[clean-list] htoclean sorrows

Matthew Bromberg mattcbro at earthlink.net
Tue May 30 19:16:30 MEST 2006


I got things to link and to work correctly using the little C program 
that you kindly provided that uses microsofts linker.  I made some minor 
adjustments to it, in particular the /NODEFAULTLIB:libc option was added 
and I forced it to actually print out the linker command to a logfile 
for debugging purposes.  The final step to success was to include a 
static link library for the dll as an external object file.  Including 
it as a static library in Projects options does not appear to add any 
library names to the link caller, thus forcing me to use this hack.  
Have you gotten the 64 bit version to work? (not that I need this 
trouble just yet.)

I think the old linker still has some issues though.  It does not like 
my .dll, whether or not I use the P prefix.

Regards,

P.S. Here is the modified source file

/* call_ms_linker.c : */

#include <windows.h>

#include <stdio.h>


struct line {
    struct line *next;
    char chars[0];
};

static char *string_copy (char *d,char *s)
{
    char c;
   
    while (c=*s++,c!='\0')
        *d++=c;
    *d=c;
    return d;
}

int skip_to_next_line (int c,FILE *input_file)
{
    while (c!='\n' && c!='\r' && c!=EOF)
        c=getc (input_file);
    if (c!=EOF)
        c=getc (input_file);

    return c;
}

void main (int argc,char *argv[])
{
    char *command_line,*command_line_p,*command_line_begin;
    char *input_file_name,*output_file_name;
    FILE *input_file,*error_file;
    static char application_name[257];
    int application_name_i;
    struct line *first_line,**next_line_p;
    int n,c,n_lines,n_chars_in_lines,n_arg_chars;

    input_file_name=NULL;
    output_file_name=NULL;

    if (argc>=5){
        if (!strcmp (argv[argc-4],"-I"))
            input_file_name=argv[argc-3];
        else if (!strcmp (argv[argc-2],"-I"))
            input_file_name=argv[argc-1];

        if (!strcmp (argv[argc-4],"-O"))
            output_file_name=argv[argc-3];
        else if (!strcmp (argv[argc-2],"-O"))
            output_file_name=argv[argc-1];
    }

    if (input_file_name==NULL)
        printf ("-I input_file_name missing\n");
    if (output_file_name==NULL)
        printf ("-I output_file_name missing\n");

    if (input_file_name==NULL || output_file_name==NULL)
        return;

    {
    int arg_i;
   
    n_arg_chars=0;
    for (arg_i=1; arg_i<argc-4; ++arg_i)
        n_arg_chars+=strlen (argv[arg_i]);
    }

    input_file=fopen (input_file_name,"r");
    if (input_file==NULL){
        printf ("Couldn't open %s\n",input_file_name);
        return;
    }

    error_file=fopen (output_file_name,"w");
    if (input_file==NULL){
        printf ("Couldn't create %s\n",output_file_name);
        return;
    }

    n_lines=0;
    n_chars_in_lines=0;
    next_line_p=&first_line;

    c=getc (input_file);

    while (c!=EOF){
        int i;
       
        i=0;
        while (c=="ExePath:"[i] && c!='\0'){
            c=getc (input_file);
            ++i;
        }
        if (i==sizeof ("ExePath:")-1){
            c=getc (input_file);
            break;
        }

        c=skip_to_next_line (c,input_file);
    }

    if (c==EOF){
        fprintf (error_file,"ExePath: not found in input file\n");
        fclose (error_file);
        return;
    }

    application_name_i=0;
    while (c!='\n' && c!='\r' && c!=EOF){
        if (application_name_i==256){
            fprintf (error_file,"application name too long");
            fclose (error_file);
            return;
        }
        application_name[application_name_i++]=c;
        c=getc (input_file);
    }

    application_name[application_name_i]='\0';

    while (c!=EOF){
        int i;
       
        i=0;
        while (c=="ObjectPaths"[i] && c!='\0'){
            c=getc (input_file);
            ++i;
        }
        if (i==sizeof ("ObjectPaths")-1){
            c=getc (input_file);
            break;
        }

        c=skip_to_next_line (c,input_file);
    }

    while (c!=EOF){
        static char line[257];
        int i,line_i;
       
        i=0;
        while (c=="\tPath:\t"[i] && c!='\0'){
            c=getc (input_file);
            ++i;
        }
        if (i!=sizeof ("\tPath:\t")-1)
            break;

        line_i=0;
        while (c!='\n' && c!='\r' && c!=EOF){
            if (line_i==256){
                fprintf (error_file,"file name too long");
                fclose (error_file);
                return;
            }
            line[line_i++]=c;
            c=getc (input_file);
        }
        line[line_i]='\0';
        if (line_i>0){
            struct line *next_line;
           
            next_line=malloc (sizeof (struct line)+line_i+1);
            if (next_line==NULL){
                fprintf (error_file,"not enough memory");
                fclose (error_file);
                return;           
            }
           
            strcpy (next_line->chars,line);
           
            ++n_lines;
            n_chars_in_lines+=line_i;
            *next_line_p=next_line;
            next_line_p=&next_line->next;
        }
        if (c!=EOF){
            c=getc (input_file);
        }
    }

    *next_line_p=NULL;

    fclose (input_file);

#if 1
    command_line_begin = "link.exe /nologo /release 
/entry:mainCRTStartup /subsystem:console"
                         "  /NODEFAULTLIB:libc"
                         " kernel32.lib";
#else
    command_line_begin = "link.exe /nologo /release /debug /machine:AMD64";
#endif

    command_line=malloc (strlen 
(command_line_begin)+8+n_arg_chars+(argc-5)+application_name_i+2+n_lines*3+n_chars_in_lines+1);
   
    command_line_p=command_line;
    command_line_p=string_copy (command_line_p,command_line_begin);

    {
    int arg_i;
   
    for (arg_i=1; arg_i<argc-4; ++arg_i){
        *command_line_p++=' ';
        command_line_p=string_copy (command_line_p,argv[arg_i]);
    }
    }

    command_line_p=string_copy (command_line_p," \"/out:");

    command_line_p=string_copy (command_line_p,application_name);
    *command_line_p++='\"';
    *command_line_p++=' ';

    {
        struct line *line_p;
        FILE *fd ;
        char *logfile = "linklog.txt" ;
        fd = fopen(logfile, "w") ;
       
        for (line_p=first_line; line_p!=NULL; line_p=line_p->next){
            *command_line_p++=' ';
            *command_line_p++='\"';
            command_line_p=string_copy (command_line_p,line_p->chars);
            *command_line_p++='\"';
        }

        *command_line_p='\0';
        fprintf(fd, command_line) ;
        fprintf(fd, "\n") ;
        fclose(fd) ;
    }

    fclose (error_file);

    {
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    SECURITY_ATTRIBUTES sa;

    sa.nLength = sizeof (SECURITY_ATTRIBUTES);
    sa.bInheritHandle = TRUE;
    sa.lpSecurityDescriptor = NULL;

    ZeroMemory (&si,sizeof(si));
    si.cb = sizeof(si);
    si.hStdOutput =
        CreateFile 
(output_file_name,GENERIC_WRITE,0,&sa,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);

    si.hStdInput=GetStdHandle (STD_INPUT_HANDLE);
    si.hStdError=GetStdHandle (STD_ERROR_HANDLE);
    if (si.hStdOutput==INVALID_HANDLE_VALUE)
        si.hStdOutput=GetStdHandle (STD_OUTPUT_HANDLE);
    si.dwFlags=STARTF_USESTDHANDLES;

    ZeroMemory (&pi,sizeof(pi));

    if (! CreateProcess 
(NULL,command_line,NULL,NULL,TRUE,0,NULL,NULL,&si,&pi))
    {
        fprintf (error_file,"CreateProcess failed\n");
        fclose (error_file);
          return;
    }

    WaitForSingleObject (pi.hProcess,INFINITE);

    CloseHandle (pi.hProcess);
    CloseHandle (pi.hThread);
    }
}



John van Groningen wrote:
> Matthew Bromberg wrote:
>   
>> Sigh,
>> I attempted this technique with no success.  I got the C code to compile (after it introduced some bugs in the cut and paste process!).
>> I replaced the StaticLinker.exe file with the new executable.  I then created a .bat file that called vcvars32.bat and then the clean IDE.
>>
>> When I compiled my little toy example I got the following errors:
>> LIBC.lib(crt0.obj) : error LNK2005: _mainCRTStartup already defined in _startup0.o
>> matrix.o : error LNK2001: unresolved external symbol _cblas_daxpy
>> LIBC.lib(crt0.obj) : error LNK2019: unresolved external symbol _main referenced in function _mainCRTStartup
>>     
>
> The linker is trying to link against the C library. You probably don't
> want to do this, try passing /NODEFAULTLIB to the linker to prevent this.
> Or if you want to link against the C library, remove _startup0.0 from
> the list of object files, and add a main function in c with a call
> to clean_main().
>
>   
>> I also tried this using an MS VC static link library that provides a ccall stub into the DLL.  Same results.  I wonder if the inability to link against
>> the library isn't a path issue?  As far as the startup*.o symbol issues I have no idea.  I'm using the Microsoft Visual C++ 2003 Toolkit., which can be
>> a little weird whenever certain libraries such as debug libraries are linked in.  I also tried collecting all the relevant .o libraries that you mentioned into a
>> single file and tried to link them directly using link.exe.   However they don't seem to be in the right format.  (Is it supposed to be COFF?)  I get this error:
>>
>> ....\Clean System Files>link /out:matrix.exe _startup.o _startup1.o _startup2.o _system.o matrix.o atlas.lib
>> Microsoft (R) Incremental Linker Version 7.10.3077
>> Copyright (C) Microsoft Corporation.  All rights reserved.
>>
>> _startup.o : fatal error LNK1136: invalid or corrupt file
>>     
>
> The _startup.o file is not used on windows, use _startup0.o, _startup1.o
> and _startup2.o instead. If there is a _startup.o file in the windows
> version of Clean it is probably not a windows COFF object file.
>
>   
>> Should I try this with MS VC++ 6.0?
>>     
>
> Maybe, with the linker from VC 6.0 I can link a Clean program.
>
> Kind regards,
>
> John van Groningen
>
>   


More information about the clean-list mailing list