| /* | |
| * Main function | |
| * | |
| * Copyright 1993 Robert J. Amstadt | |
| * Copyright 1995 Martin von Loewis | |
| * Copyright 1995, 1996, 1997 Alexandre Julliard | |
| * Copyright 1997 Eric Youngdale | |
| * Copyright 1999 Ulrich Weigand | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| */ | |
| #include "config.h" | |
| #include "wine/port.h" | |
| #include <assert.h> | |
| #include <stdio.h> | |
| #include <errno.h> | |
| #include <string.h> | |
| #include <ctype.h> | |
| #include "build.h" | |
| ORDDEF *EntryPoints[MAX_ORDINALS]; | |
| ORDDEF *Ordinals[MAX_ORDINALS]; | |
| ORDDEF *Names[MAX_ORDINALS]; | |
| SPEC_MODE SpecMode = SPEC_MODE_DLL; | |
| int Base = MAX_ORDINALS; | |
| int Limit = 0; | |
| int DLLHeapSize = 0; | |
| int UsePIC = 0; | |
| int stack_size = 0; | |
| int nb_entry_points = 0; | |
| int nb_names = 0; | |
| int nb_debug_channels = 0; | |
| int nb_lib_paths = 0; | |
| int display_warnings = 0; | |
| /* we only support relay debugging on i386 */ | |
| #if defined(__i386__) && !defined(NO_TRACE_MSGS) | |
| int debugging = 1; | |
| #else | |
| int debugging = 0; | |
| #endif | |
| char DLLName[80]; | |
| char DLLFileName[80]; | |
| char owner_name[80]; | |
| char *init_func = NULL; | |
| char **debug_channels = NULL; | |
| char **lib_path = NULL; | |
| char *input_file_name = NULL; | |
| const char *output_file_name = NULL; | |
| static FILE *input_file; | |
| static FILE *output_file; | |
| static const char *current_src_dir; | |
| /* execution mode */ | |
| static enum | |
| { | |
| MODE_NONE, | |
| MODE_SPEC, | |
| MODE_EXE, | |
| MODE_GLUE, | |
| MODE_DEF, | |
| MODE_DEBUG, | |
| MODE_RELAY16, | |
| MODE_RELAY32 | |
| } exec_mode = MODE_NONE; | |
| /* set the dll file name from the input file name */ | |
| static void set_dll_file_name( const char *name ) | |
| { | |
| char *p; | |
| if ((p = strrchr( name, '\\' ))) name = p + 1; | |
| if ((p = strrchr( name, '/' ))) name = p + 1; | |
| strcpy( DLLFileName, name ); | |
| if ((p = strrchr( DLLFileName, '.' )) && !strcmp( p, ".spec" )) *p = 0; | |
| if (!strchr( DLLFileName, '.' )) strcat( DLLFileName, ".dll" ); | |
| } | |
| /* cleanup on program exit */ | |
| static void cleanup(void) | |
| { | |
| if (output_file_name) unlink( output_file_name ); | |
| } | |
| /******************************************************************* | |
| * command-line option handling | |
| */ | |
| struct option_descr | |
| { | |
| const char *name; | |
| int has_arg; | |
| void (*func)(); | |
| const char *usage; | |
| }; | |
| static void do_output( const char *arg ); | |
| static void do_usage(void); | |
| static void do_warnings(void); | |
| static void do_f_flags( const char *arg ); | |
| static void do_define( const char *arg ); | |
| static void do_include( const char *arg ); | |
| static void do_k_flags( const char *arg ); | |
| static void do_exe_mode( const char *arg ); | |
| static void do_module( const char *arg ); | |
| static void do_heap( const char *arg ); | |
| static void do_name( const char *arg ); | |
| static void do_spec( const char *arg ); | |
| static void do_def( const char *arg ); | |
| static void do_exe( const char *arg ); | |
| static void do_glue(void); | |
| static void do_relay16(void); | |
| static void do_relay32(void); | |
| static void do_debug(void); | |
| static void do_sym(void); | |
| static void do_chdir( const char *arg ); | |
| static void do_lib( const char *arg ); | |
| static void do_import( const char *arg ); | |
| static void do_dimport( const char *arg ); | |
| static void do_rsrc( const char *arg ); | |
| static const struct option_descr option_table[] = | |
| { | |
| { "-h", 0, do_usage, "-h Display this help message" }, | |
| { "-w", 0, do_warnings,"-w Turn on warnings" }, | |
| { "-C", 1, do_chdir, "-C dir Change directory to <dir> before opening source files" }, | |
| { "-f", 1, do_f_flags, "-f flags Compiler flags (only -fPIC is supported)" }, | |
| { "-D", 1, do_define, "-D sym Ignored for C flags compatibility" }, | |
| { "-I", 1, do_include, "-I dir Ignored for C flags compatibility" }, | |
| { "-K", 1, do_k_flags, "-K flags Compiler flags (only -KPIC is supported)" }, | |
| { "-m", 1, do_exe_mode,"-m mode Set the executable mode (cui|gui|cuiw|guiw)" }, | |
| { "-M", 1, do_module, "-M module Set the name of the main (Win32) module for a Win16 dll" }, | |
| { "-L", 1, do_lib, "-L directory Look for imports libraries in 'directory'" }, | |
| { "-l", 1, do_import, "-l lib.dll Import the specified library" }, | |
| { "-dl", 1, do_dimport, "-dl lib.dll Delay-import the specified library" }, | |
| { "-H", 1, do_heap, "-H size Set the heap size for a Win16 dll" }, | |
| { "-N", 1, do_name, "-N dllname Set the DLL name (default: set from input file name)" }, | |
| { "-res", 1, do_rsrc, "-res rsrc.res Load resources from rsrc.res" }, | |
| { "-o", 1, do_output, "-o name Set the output file name (default: stdout)\n" }, | |
| { "-sym", 0, do_sym, NULL }, /* ignored for backwards compatibility */ | |
| { "-spec", 1, do_spec, "-spec file.spec Build a .c file from a spec file" }, | |
| { "-def", 1, do_def, "-def file.spec Build a .def file from a spec file" }, | |
| { "-exe", 1, do_exe, "-exe name Build a .c file for the named executable" }, | |
| { "-debug", 0, do_debug, "-debug [files] Build a .c file containing debug channels declarations" }, | |
| { "-glue", 0, do_glue, "-glue [files] Build the 16-bit glue for the source files" }, | |
| { "-relay16", 0, do_relay16, "-relay16 Build the 16-bit relay assembly routines" }, | |
| { "-relay32", 0, do_relay32, "-relay32 Build the 32-bit relay assembly routines" }, | |
| { NULL, 0, NULL, NULL } | |
| }; | |
| static void do_output( const char *arg ) | |
| { | |
| if ( ( unlink ( arg ) ) == -1 && ( errno != ENOENT ) ) | |
| { | |
| fprintf ( stderr, "Unable to create output file '%s'\n", arg ); | |
| exit (1); | |
| } | |
| if (!(output_file = fopen( arg, "w" ))) | |
| { | |
| fprintf( stderr, "Unable to create output file '%s'\n", arg ); | |
| exit(1); | |
| } | |
| output_file_name = arg; | |
| atexit( cleanup ); /* make sure we remove the output file on exit */ | |
| } | |
| static void do_usage(void) | |
| { | |
| const struct option_descr *opt; | |
| fprintf( stderr, "Usage: winebuild [options]\n\n" ); | |
| fprintf( stderr, "Options:\n" ); | |
| for (opt = option_table; opt->name; opt++) | |
| if (opt->usage) fprintf( stderr, " %s\n", opt->usage ); | |
| fprintf( stderr, "\nExactly one of -spec, -def, -exe, -debug, -glue, -relay16 or -relay32 must be specified.\n\n" ); | |
| exit(1); | |
| } | |
| static void do_warnings(void) | |
| { | |
| display_warnings = 1; | |
| } | |
| static void do_f_flags( const char *arg ) | |
| { | |
| if (!strcmp( arg, "PIC" )) UsePIC = 1; | |
| /* ignore all other flags */ | |
| } | |
| static void do_define( const char *arg ) | |
| { | |
| /* nothing */ | |
| } | |
| static void do_include( const char *arg ) | |
| { | |
| /* nothing */ | |
| } | |
| static void do_k_flags( const char *arg ) | |
| { | |
| /* Ignored, because cc generates correct code. */ | |
| /* if (!strcmp( arg, "PIC" )) UsePIC = 1; */ | |
| /* ignore all other flags */ | |
| } | |
| static void do_heap( const char *arg ) | |
| { | |
| if (!isdigit(arg[0])) | |
| fatal_error( "Expected number argument with -H option instead of '%s'\n", arg ); | |
| DLLHeapSize = atoi(arg); | |
| if (DLLHeapSize > 65535) fatal_error( "Invalid heap size %d, maximum is 65535\n", DLLHeapSize ); | |
| } | |
| static void do_name( const char *arg ) | |
| { | |
| strncpy( DLLName, arg, sizeof(DLLName) ); | |
| DLLName[sizeof(DLLName) - 1] = 0; | |
| } | |
| static void do_spec( const char *arg ) | |
| { | |
| if (exec_mode != MODE_NONE || !arg[0]) do_usage(); | |
| exec_mode = MODE_SPEC; | |
| input_file = open_input_file( NULL, arg ); | |
| set_dll_file_name( arg ); | |
| } | |
| static void do_def( const char *arg ) | |
| { | |
| if (exec_mode != MODE_NONE || !arg[0]) do_usage(); | |
| exec_mode = MODE_DEF; | |
| input_file = open_input_file( NULL, arg ); | |
| set_dll_file_name( arg ); | |
| } | |
| static void do_exe( const char *arg ) | |
| { | |
| const char *p; | |
| if (exec_mode != MODE_NONE || !arg[0]) do_usage(); | |
| exec_mode = MODE_EXE; | |
| if ((p = strrchr( arg, '/' ))) p++; | |
| else p = arg; | |
| strcpy( DLLFileName, p ); | |
| if (!strchr( DLLFileName, '.' )) strcat( DLLFileName, ".exe" ); | |
| if (SpecMode == SPEC_MODE_DLL) SpecMode = SPEC_MODE_GUIEXE; | |
| } | |
| static void do_exe_mode( const char *arg ) | |
| { | |
| if (!strcmp( arg, "gui" )) SpecMode = SPEC_MODE_GUIEXE; | |
| else if (!strcmp( arg, "cui" )) SpecMode = SPEC_MODE_CUIEXE; | |
| else if (!strcmp( arg, "guiw" )) SpecMode = SPEC_MODE_GUIEXE_UNICODE; | |
| else if (!strcmp( arg, "cuiw" )) SpecMode = SPEC_MODE_CUIEXE_UNICODE; | |
| else do_usage(); | |
| } | |
| static void do_module( const char *arg ) | |
| { | |
| strcpy( owner_name, arg ); | |
| } | |
| static void do_glue(void) | |
| { | |
| if (exec_mode != MODE_NONE) do_usage(); | |
| exec_mode = MODE_GLUE; | |
| } | |
| static void do_debug(void) | |
| { | |
| if (exec_mode != MODE_NONE) do_usage(); | |
| exec_mode = MODE_DEBUG; | |
| } | |
| static void do_chdir( const char *arg ) | |
| { | |
| current_src_dir = arg; | |
| } | |
| static void do_relay16(void) | |
| { | |
| if (exec_mode != MODE_NONE) do_usage(); | |
| exec_mode = MODE_RELAY16; | |
| } | |
| static void do_relay32(void) | |
| { | |
| if (exec_mode != MODE_NONE) do_usage(); | |
| exec_mode = MODE_RELAY32; | |
| } | |
| static void do_sym(void) | |
| { | |
| /* nothing */ | |
| } | |
| static void do_lib( const char *arg ) | |
| { | |
| lib_path = xrealloc( lib_path, (nb_lib_paths+1) * sizeof(*lib_path) ); | |
| lib_path[nb_lib_paths++] = xstrdup( arg ); | |
| } | |
| static void do_import( const char *arg ) | |
| { | |
| add_import_dll( arg, 0 ); | |
| } | |
| static void do_dimport( const char *arg ) | |
| { | |
| add_import_dll( arg, 1 ); | |
| } | |
| static void do_rsrc( const char *arg ) | |
| { | |
| load_res32_file( arg ); | |
| } | |
| /* parse options from the argv array and remove all the recognized ones */ | |
| static void parse_options( char *argv[] ) | |
| { | |
| const struct option_descr *opt; | |
| char **ptr, **last; | |
| const char* arg=NULL; | |
| for (ptr = last = argv + 1; *ptr; ptr++) | |
| { | |
| for (opt = option_table; opt->name; opt++) | |
| { | |
| if (opt->has_arg && !strncmp( *ptr, opt->name, strlen(opt->name) )) | |
| { | |
| arg=*ptr+strlen(opt->name); | |
| if (*arg=='\0') | |
| { | |
| ptr++; | |
| arg=*ptr; | |
| } | |
| break; | |
| } | |
| if (!strcmp( *ptr, opt->name )) | |
| { | |
| arg=NULL; | |
| break; | |
| } | |
| } | |
| if (opt->name) | |
| { | |
| if (opt->has_arg && arg != NULL) opt->func( arg ); | |
| else opt->func( "" ); | |
| } | |
| else /* keep this argument */ | |
| { | |
| if (last != ptr) *last = *ptr; | |
| last++; | |
| } | |
| } | |
| *last = NULL; | |
| } | |
| /******************************************************************* | |
| * main | |
| */ | |
| int main(int argc, char **argv) | |
| { | |
| output_file = stdout; | |
| parse_options( argv ); | |
| switch(exec_mode) | |
| { | |
| case MODE_SPEC: | |
| switch (ParseTopLevel( input_file, 0 )) | |
| { | |
| case SPEC_WIN16: | |
| if (argv[1]) | |
| fatal_error( "file argument '%s' not allowed in this mode\n", argv[1] ); | |
| BuildSpec16File( output_file ); | |
| break; | |
| case SPEC_WIN32: | |
| read_undef_symbols( argv + 1 ); | |
| BuildSpec32File( output_file ); | |
| break; | |
| default: assert(0); | |
| } | |
| break; | |
| case MODE_EXE: | |
| read_undef_symbols( argv + 1 ); | |
| BuildSpec32File( output_file ); | |
| break; | |
| case MODE_DEF: | |
| if (argv[1]) fatal_error( "file argument '%s' not allowed in this mode\n", argv[1] ); | |
| switch (ParseTopLevel( input_file, 1 )) | |
| { | |
| case SPEC_WIN16: | |
| fatal_error( "Cannot yet build .def file for 16-bit dlls\n" ); | |
| break; | |
| case SPEC_WIN32: | |
| BuildDef32File( output_file ); | |
| break; | |
| default: assert(0); | |
| } | |
| break; | |
| case MODE_DEBUG: | |
| BuildDebugFile( output_file, current_src_dir, argv + 1 ); | |
| break; | |
| case MODE_GLUE: | |
| BuildGlue( output_file, current_src_dir, argv + 1 ); | |
| break; | |
| case MODE_RELAY16: | |
| if (argv[1]) fatal_error( "file argument '%s' not allowed in this mode\n", argv[1] ); | |
| BuildRelays16( output_file ); | |
| break; | |
| case MODE_RELAY32: | |
| if (argv[1]) fatal_error( "file argument '%s' not allowed in this mode\n", argv[1] ); | |
| BuildRelays32( output_file ); | |
| break; | |
| default: | |
| do_usage(); | |
| break; | |
| } | |
| if (output_file_name) | |
| { | |
| fclose( output_file ); | |
| output_file_name = NULL; | |
| } | |
| return 0; | |
| } |