diff --git a/tools/winebuild/build.h b/tools/winebuild/build.h index 9a25856480a..62193a4fc55 100644 --- a/tools/winebuild/build.h +++ b/tools/winebuild/build.h @@ -177,6 +177,7 @@ extern void close_input_file( FILE *file ); extern void dump_bytes( FILE *outfile, const unsigned char *data, int len, const char *label, int constant ); extern int remove_stdcall_decoration( char *name ); +extern void assemble_file( const char *src_file, const char *obj_file ); extern DLLSPEC *alloc_dll_spec(void); extern void free_dll_spec( DLLSPEC *spec ); extern int has_stubs( const DLLSPEC *spec ); @@ -233,6 +234,8 @@ extern int nb_lib_paths; extern int nb_errors; extern int display_warnings; extern int kill_at; +extern int verbose; +extern int save_temps; extern char *input_file_name; extern char *spec_file_name; diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c index dbab35f611e..07567d5f750 100644 --- a/tools/winebuild/import.c +++ b/tools/winebuild/import.c @@ -505,12 +505,9 @@ static void check_undefined_exports( DLLSPEC *spec ) /* create a .o file that references all the undefined symbols we want to resolve */ static char *create_undef_symbols_file( DLLSPEC *spec ) { - char *cmd, *as_file, *obj_file; + char *as_file, *obj_file; unsigned int i; FILE *f; - int err; - - if (!as_command) as_command = xstrdup("as"); as_file = get_temp_file_name( output_file_name, ".s" ); if (!(f = fopen( as_file, "w" ))) fatal_error( "Cannot create %s\n", as_file ); @@ -528,11 +525,7 @@ static char *create_undef_symbols_file( DLLSPEC *spec ) fclose( f ); obj_file = get_temp_file_name( output_file_name, ".o" ); - cmd = xmalloc( strlen(as_command) + strlen(obj_file) + strlen(as_file) + 6 ); - sprintf( cmd, "%s -o %s %s", as_command, obj_file, as_file ); - err = system( cmd ); - if (err) fatal_error( "%s failed with status %d\n", as_command, err ); - free( cmd ); + assemble_file( as_file, obj_file ); return obj_file; } @@ -553,6 +546,7 @@ static const char *ldcombine_files( DLLSPEC *spec, char **argv ) p += sprintf( cmd, "%s -r -o %s %s", ld_command, ld_tmp_file, undef_file ); for (i = 0; argv[i]; i++) p += sprintf( p, " %s", argv[i] ); + if (verbose) fprintf( stderr, "%s\n", cmd ); err = system( cmd ); if (err) fatal_error( "%s -r failed with status %d\n", ld_command, err ); free( cmd ); diff --git a/tools/winebuild/main.c b/tools/winebuild/main.c index 63d89798969..9c75b51f0bb 100644 --- a/tools/winebuild/main.c +++ b/tools/winebuild/main.c @@ -46,6 +46,8 @@ int nb_lib_paths = 0; int nb_errors = 0; int display_warnings = 0; int kill_at = 0; +int verbose = 0; +int save_temps = 0; #ifdef __i386__ enum target_cpu target_cpu = CPU_x86; @@ -77,6 +79,7 @@ char **lib_path = NULL; char *input_file_name = NULL; char *spec_file_name = NULL; const char *output_file_name = NULL; +static const char *output_file_source_name; char *as_command = NULL; char *ld_command = NULL; @@ -266,9 +269,11 @@ static const char usage_str[] = " -N, --dll-name=DLLNAME Set the DLL name (default: from input file name)\n" " -o, --output=NAME Set the output file name (default: stdout)\n" " -r, --res=RSRC.RES Load resources from RSRC.RES\n" +" --save-temps Do not delete the generated intermediate files\n" " --subsystem=SUBSYS Set the subsystem (one of native, windows, console)\n" " --target=TARGET Specify target CPU and platform for cross-compiling\n" " -u, --undefined=SYMBOL Add an undefined reference to SYMBOL when linking\n" +" -v, --verbose Display the programs invoked\n" " --version Print the version and exit\n" " -w, --warnings Turn on warnings\n" "\nMode options:\n" @@ -291,12 +296,13 @@ enum long_options_values LONG_OPT_NMCMD, LONG_OPT_RELAY16, LONG_OPT_RELAY32, + LONG_OPT_SAVE_TEMPS, LONG_OPT_SUBSYSTEM, LONG_OPT_TARGET, LONG_OPT_VERSION }; -static const char short_options[] = "C:D:E:F:H:I:K:L:M:N:d:e:f:hi:kl:m:o:r:u:w"; +static const char short_options[] = "C:D:E:F:H:I:K:L:M:N:d:e:f:hi:kl:m:o:r:u:vw"; static const struct option long_options[] = { @@ -309,6 +315,7 @@ static const struct option long_options[] = { "nm-cmd", 1, 0, LONG_OPT_NMCMD }, { "relay16", 0, 0, LONG_OPT_RELAY16 }, { "relay32", 0, 0, LONG_OPT_RELAY32 }, + { "save-temps",0, 0, LONG_OPT_SAVE_TEMPS }, { "subsystem",1, 0, LONG_OPT_SUBSYSTEM }, { "target", 1, 0, LONG_OPT_TARGET }, { "version", 0, 0, LONG_OPT_VERSION }, @@ -329,6 +336,7 @@ static const struct option long_options[] = { "output", 1, 0, 'o' }, { "res", 1, 0, 'r' }, { "undefined", 1, 0, 'u' }, + { "verbose", 0, 0, 'v' }, { "warnings", 0, 0, 'w' }, { NULL, 0, 0, 0 } }; @@ -424,12 +432,25 @@ static char **parse_options( int argc, char **argv, DLLSPEC *spec ) add_import_dll( optarg, NULL ); break; case 'o': - if (unlink( optarg ) == -1 && errno != ENOENT) - fatal_error( "Unable to create output file '%s'\n", optarg ); - if (!(output_file = fopen( optarg, "w" ))) - fatal_error( "Unable to create output file '%s'\n", optarg ); - output_file_name = xstrdup(optarg); - atexit( cleanup ); /* make sure we remove the output file on exit */ + { + char *ext = strrchr( optarg, '.' ); + + if (unlink( optarg ) == -1 && errno != ENOENT) + fatal_error( "Unable to create output file '%s'\n", optarg ); + if (ext && !strcmp( ext, ".o" )) + { + output_file_source_name = get_temp_file_name( optarg, ".s" ); + if (!(output_file = fopen( output_file_source_name, "w" ))) + fatal_error( "Unable to create output file '%s'\n", optarg ); + } + else + { + if (!(output_file = fopen( optarg, "w" ))) + fatal_error( "Unable to create output file '%s'\n", optarg ); + } + output_file_name = xstrdup(optarg); + atexit( cleanup ); /* make sure we remove the output file on exit */ + } break; case 'r': res_files = xrealloc( res_files, (nb_res_files+1) * sizeof(*res_files) ); @@ -438,6 +459,9 @@ static char **parse_options( int argc, char **argv, DLLSPEC *spec ) case 'u': add_extra_ld_symbol( optarg ); break; + case 'v': + verbose++; + break; case 'w': display_warnings = 1; break; @@ -469,6 +493,9 @@ static char **parse_options( int argc, char **argv, DLLSPEC *spec ) case LONG_OPT_RELAY32: set_exec_mode( MODE_RELAY32 ); break; + case LONG_OPT_SAVE_TEMPS: + save_temps = 1; + break; case LONG_OPT_SUBSYSTEM: set_subsystem( optarg, spec ); break; @@ -624,6 +651,7 @@ int main(int argc, char **argv) if (output_file_name) { fclose( output_file ); + if (output_file_source_name) assemble_file( output_file_source_name, output_file_name ); output_file_name = NULL; } return 0; diff --git a/tools/winebuild/utils.c b/tools/winebuild/utils.c index ae4ac2916f5..810491f28dc 100644 --- a/tools/winebuild/utils.c +++ b/tools/winebuild/utils.c @@ -166,22 +166,27 @@ void warning( const char *msg, ... ) char *get_temp_file_name( const char *prefix, const char *suffix ) { char *name; + const char *ext; int fd; assert( nb_tmp_files < MAX_TMP_FILES ); - if (!nb_tmp_files) atexit( cleanup_tmp_files ); + if (!nb_tmp_files && !save_temps) atexit( cleanup_tmp_files ); - if (!prefix || !prefix[0]) prefix = "winebuild.tmp"; + if (!prefix || !prefix[0]) prefix = "winebuild"; if (!suffix) suffix = ""; - name = xmalloc( strlen(prefix) + strlen(suffix) + sizeof("/tmp/.XXXXXX") ); - sprintf( name, "%s.XXXXXX%s", prefix, suffix ); + if (!(ext = strchr( prefix, '.' ))) ext = prefix + strlen(prefix); + name = xmalloc( sizeof("/tmp/") + (ext - prefix) + sizeof(".XXXXXX") + strlen(suffix) ); + strcpy( name, "/tmp/" ); + memcpy( name + 5, prefix, ext - prefix ); + strcpy( name + 5 + (ext - prefix), ".XXXXXX" ); + strcat( name, suffix ); + + /* first try without the /tmp/ prefix */ + if ((fd = mkstemps( name + 5, strlen(suffix) )) != -1) + name += 5; + else if ((fd = mkstemps( name, strlen(suffix) )) == -1) + fatal_error( "could not generate a temp file\n" ); - if ((fd = mkstemps( name, strlen(suffix) ) == -1)) - { - sprintf( name, "/tmp/%s.XXXXXX%s", prefix, suffix ); - if ((fd = mkstemps( name, strlen(suffix) ) == -1)) - fatal_error( "could not generate a temp file\n" ); - } close( fd ); tmp_files[nb_tmp_files++] = name; return name; @@ -275,6 +280,26 @@ int remove_stdcall_decoration( char *name ) } +/******************************************************************* + * assemble_file + * + * Run a file through the assembler. + */ +void assemble_file( const char *src_file, const char *obj_file ) +{ + char *cmd; + int err; + + if (!as_command) as_command = xstrdup("as"); + cmd = xmalloc( strlen(as_command) + strlen(obj_file) + strlen(src_file) + 6 ); + sprintf( cmd, "%s -o %s %s", as_command, obj_file, src_file ); + if (verbose) fprintf( stderr, "%s\n", cmd ); + err = system( cmd ); + if (err) fatal_error( "%s failed with status %d\n", as_command, err ); + free( cmd ); +} + + /******************************************************************* * alloc_dll_spec * diff --git a/tools/winebuild/winebuild.man.in b/tools/winebuild/winebuild.man.in index 251deb3b605..5bd6b8248ea 100644 --- a/tools/winebuild/winebuild.man.in +++ b/tools/winebuild/winebuild.man.in @@ -1,5 +1,5 @@ .\" -*- nroff -*- -.TH WINEBUILD 1 "March 2003" "@PACKAGE_STRING@" "Wine dll builder" +.TH WINEBUILD 1 "September 2005" "@PACKAGE_STRING@" "Wine dll builder" .SH NAME winebuild \- Wine dll builder .SH SYNOPSIS @@ -20,11 +20,11 @@ You have to specify exactly one of the following options, depending on what you want winebuild to generate. .TP .BI \--dll -Build a C file from a .spec file (see \fBSPEC FILE SYNTAX\fR for -details), or from a standard Windows .def file. The .spec/.def file -is specified via the -E option. The resulting C file must be compiled -and linked to the other object files to build a working Wine dll. -In this mode, the +Build an assembly file from a .spec file (see \fBSPEC FILE SYNTAX\fR +for details), or from a standard Windows .def file. The +.spec/.def file is specified via the -E option. The resulting file +must be assembled and linked to the other object files to build a +working Wine dll. In this mode, the .I input files should be the list of all object files that will be linked into the final dll, to allow @@ -33,13 +33,13 @@ to get the list of all undefined symbols that need to be imported from other dlls. .TP .BI \--exe -Build a C file for an executable. This is basically the same as +Build an assembly file for an executable. This is basically the same as the --dll mode except that it doesn't require a .spec/.def file as input, since an executable need not export functions. Some executables however do export functions, and for those a .spec/.def file can be specified via the -E option. The executable is named from the .spec/.def file name if -present, or explicitly through the -F option. The resulting C file must be -compiled and linked to the other object files to build a working Wine +present, or explicitly through the -F option. The resulting file must be +assembled and linked to the other object files to build a working Wine executable, and all the other object files must be listed as .I input files. .TP @@ -160,11 +160,14 @@ Specify the command to use to get the list of undefined symbols; the default is \fBnm\fR. .TP .BI \-o,\ --output= file -Set the name of the output file (default is standard output). +Set the name of the output file (default is standard output). If the +output file name end in \fB.o\fR, the text output is sent to a +temporary file that is then assembled to produce the specified .o +file. .TP .BI \-r,\ --res= rsrc.res Load resources from the specified binary resource file. The -\fIrsrc.res\fR can be produced from a source resource file with +\fIrsrc.res\fR file can be produced from a source resource file with .BR wrc(1) (or with a Windows resource compiler). .br @@ -175,6 +178,9 @@ and will automatically be handled correctly (though the .B \-r option will also work for Win32 files). .TP +.B --save-temps +Do not delete the various temporary files that \fBwinebuild\fR generates. +.TP .BI --subsystem= subsystem[:major[.minor]] Set the subsystem of the executable, which can be one of the following: .br @@ -205,6 +211,10 @@ Add \fIsymbol\fR to the list of undefined symbols when invoking the linker. This makes it possible to force a specific module of a static library to be included when resolving imports. .TP +.B \-v, --verbose +Display the various subcommands being invoked by +.B winebuild. +.TP .B \--version Display the program version and exit. .TP