Added support in winebuild for specifying import libraries directly on
[wine] / tools / winebuild / main.c
1 /*
2  * Main function
3  *
4  * Copyright 1993 Robert J. Amstadt
5  * Copyright 1995 Martin von Loewis
6  * Copyright 1995, 1996, 1997 Alexandre Julliard
7  * Copyright 1997 Eric Youngdale
8  * Copyright 1999 Ulrich Weigand
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  */
24
25 #include "config.h"
26 #include "wine/port.h"
27
28 #include <assert.h>
29 #include <stdio.h>
30 #include <signal.h>
31 #include <errno.h>
32 #include <string.h>
33 #include <stdarg.h>
34 #include <ctype.h>
35 #ifdef HAVE_GETOPT_H
36 # include <getopt.h>
37 #endif
38
39 #include "windef.h"
40 #include "winbase.h"
41 #include "build.h"
42
43 int UsePIC = 0;
44 int nb_debug_channels = 0;
45 int nb_lib_paths = 0;
46 int nb_errors = 0;
47 int display_warnings = 0;
48 int kill_at = 0;
49
50 /* we only support relay debugging on i386 */
51 #ifdef __i386__
52 int debugging = 1;
53 #else
54 int debugging = 0;
55 #endif
56
57 char **debug_channels = NULL;
58 char **lib_path = NULL;
59
60 char *input_file_name = NULL;
61 char *spec_file_name = NULL;
62 const char *output_file_name = NULL;
63
64 char *ld_command = "ld";
65 char *nm_command = "nm";
66
67 static FILE *output_file;
68 static const char *current_src_dir;
69 static int nb_res_files;
70 static char **res_files;
71
72 /* execution mode */
73 enum exec_mode_values
74 {
75     MODE_NONE,
76     MODE_DLL,
77     MODE_EXE,
78     MODE_DEF,
79     MODE_DEBUG,
80     MODE_RELAY16,
81     MODE_RELAY32
82 };
83
84 static enum exec_mode_values exec_mode = MODE_NONE;
85
86 /* set the dll file name from the input file name */
87 static void set_dll_file_name( const char *name, DLLSPEC *spec )
88 {
89     char *p;
90
91     if (spec->file_name) return;
92
93     if ((p = strrchr( name, '\\' ))) name = p + 1;
94     if ((p = strrchr( name, '/' ))) name = p + 1;
95     spec->file_name = xmalloc( strlen(name) + 5 );
96     strcpy( spec->file_name, name );
97     if ((p = strrchr( spec->file_name, '.' )))
98     {
99         if (!strcmp( p, ".spec" ) || !strcmp( p, ".def" )) *p = 0;
100     }
101 }
102
103 /* set the dll subsystem */
104 static void set_subsystem( const char *subsystem, DLLSPEC *spec )
105 {
106     char *major, *minor, *str = xstrdup( subsystem );
107
108     if ((major = strchr( str, ':' ))) *major++ = 0;
109     if (!strcmp( str, "native" )) spec->subsystem = IMAGE_SUBSYSTEM_NATIVE;
110     else if (!strcmp( str, "windows" )) spec->subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI;
111     else if (!strcmp( str, "console" )) spec->subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
112     else fatal_error( "Invalid subsystem name '%s'\n", subsystem );
113     if (major)
114     {
115         if ((minor = strchr( major, '.' )))
116         {
117             *minor++ = 0;
118             spec->subsystem_minor = atoi( minor );
119         }
120         spec->subsystem_major = atoi( major );
121     }
122     free( str );
123 }
124
125 /* cleanup on program exit */
126 static void cleanup(void)
127 {
128     if (output_file_name) unlink( output_file_name );
129 }
130
131 /* clean things up when aborting on a signal */
132 static void exit_on_signal( int sig )
133 {
134     exit(1);  /* this will call atexit functions */
135 }
136
137 /*******************************************************************
138  *         command-line option handling
139  */
140 static const char usage_str[] =
141 "Usage: winebuild [OPTIONS] [FILES]\n\n"
142 "Options:\n"
143 "    -C --source-dir=DIR     Look for source files in DIR\n"
144 "    -d --delay-lib=LIB      Import the specified library in delayed mode\n"
145 "    -D SYM                  Ignored for C flags compatibility\n"
146 "    -E --export=FILE        Export the symbols defined in the .spec or .def file\n"
147 "    -e --entry=FUNC         Set the DLL entry point function (default: DllMain)\n"
148 "    -f FLAGS                Compiler flags (only -fPIC is supported)\n"
149 "    -F --filename=DLLFILE   Set the DLL filename (default: from input file name)\n"
150 "    -h --help               Display this help message\n"
151 "    -H --heap=SIZE          Set the heap size for a Win16 dll\n"
152 "    -i --ignore=SYM[,SYM]   Ignore specified symbols when resolving imports\n"
153 "    -I DIR                  Ignored for C flags compatibility\n"
154 "    -k --kill-at            Kill stdcall decorations in generated .def files\n"
155 "    -K FLAGS                Compiler flags (only -KPIC is supported)\n"
156 "       --ld-cmd=LD          Command to use for linking (default: ld)\n"
157 "    -l --library=LIB        Import the specified library\n"
158 "    -L --library-path=DIR   Look for imports libraries in DIR\n"
159 "    -M --main-module=MODULE Set the name of the main module for a Win16 dll\n"
160 "       --nm-cmd=NM          Command to use to get undefined symbols (default: nm)\n"
161 "    -N --dll-name=DLLNAME   Set the DLL name (default: from input file name)\n"
162 "    -o --output=NAME        Set the output file name (default: stdout)\n"
163 "    -r --res=RSRC.RES       Load resources from RSRC.RES\n"
164 "       --subsystem=SUBSYS   Set the subsystem (one of native, windows, console)\n"
165 "       --version            Print the version and exit\n"
166 "    -w --warnings           Turn on warnings\n"
167 "\nMode options:\n"
168 "       --dll                Build a .c file from a .spec or .def file\n"
169 "       --def                Build a .def file from a .spec file\n"
170 "       --exe                Build a .c file for an executable\n"
171 "       --debug [FILES]      Build a .c file with the debug channels declarations\n"
172 "       --relay16            Build the 16-bit relay assembly routines\n"
173 "       --relay32            Build the 32-bit relay assembly routines\n\n"
174 "The mode options are mutually exclusive; you must specify one and only one.\n\n";
175
176 enum long_options_values
177 {
178     LONG_OPT_DLL = 1,
179     LONG_OPT_DEF,
180     LONG_OPT_EXE,
181     LONG_OPT_DEBUG,
182     LONG_OPT_LDCMD,
183     LONG_OPT_NMCMD,
184     LONG_OPT_RELAY16,
185     LONG_OPT_RELAY32,
186     LONG_OPT_SUBSYSTEM,
187     LONG_OPT_VERSION
188 };
189
190 static const char short_options[] = "C:D:E:F:H:I:K:L:M:N:d:e:f:hi:kl:m:o:r:w";
191
192 static const struct option long_options[] =
193 {
194     { "dll",      0, 0, LONG_OPT_DLL },
195     { "def",      0, 0, LONG_OPT_DEF },
196     { "exe",      0, 0, LONG_OPT_EXE },
197     { "debug",    0, 0, LONG_OPT_DEBUG },
198     { "ld-cmd",   1, 0, LONG_OPT_LDCMD },
199     { "nm-cmd",   1, 0, LONG_OPT_NMCMD },
200     { "relay16",  0, 0, LONG_OPT_RELAY16 },
201     { "relay32",  0, 0, LONG_OPT_RELAY32 },
202     { "subsystem",1, 0, LONG_OPT_SUBSYSTEM },
203     { "version",  0, 0, LONG_OPT_VERSION },
204     /* aliases for short options */
205     { "source-dir",    1, 0, 'C' },
206     { "delay-lib",     1, 0, 'd' },
207     { "export",        1, 0, 'E' },
208     { "entry",         1, 0, 'e' },
209     { "filename",      1, 0, 'F' },
210     { "help",          0, 0, 'h' },
211     { "heap",          1, 0, 'H' },
212     { "ignore",        1, 0, 'i' },
213     { "kill-at",       0, 0, 'k' },
214     { "library",       1, 0, 'l' },
215     { "library-path",  1, 0, 'L' },
216     { "main-module",   1, 0, 'M' },
217     { "dll-name",      1, 0, 'N' },
218     { "output",        1, 0, 'o' },
219     { "res",           1, 0, 'r' },
220     { "warnings",      0, 0, 'w' },
221     { NULL,            0, 0, 0 }
222 };
223
224 static void usage( int exit_code )
225 {
226     fprintf( stderr, "%s", usage_str );
227     exit( exit_code );
228 }
229
230 static void set_exec_mode( enum exec_mode_values mode )
231 {
232     if (exec_mode != MODE_NONE) usage(1);
233     exec_mode = mode;
234 }
235
236 /* parse options from the argv array and remove all the recognized ones */
237 static char **parse_options( int argc, char **argv, DLLSPEC *spec )
238 {
239     char *p;
240     int optc;
241
242     while ((optc = getopt_long( argc, argv, short_options, long_options, NULL )) != -1)
243     {
244         switch(optc)
245         {
246         case 'C':
247             current_src_dir = optarg;
248             break;
249         case 'D':
250             /* ignored */
251             break;
252         case 'E':
253             spec_file_name = xstrdup( optarg );
254             set_dll_file_name( optarg, spec );
255             break;
256         case 'F':
257             spec->file_name = xstrdup( optarg );
258             break;
259         case 'H':
260             if (!isdigit(optarg[0]))
261                 fatal_error( "Expected number argument with -H option instead of '%s'\n", optarg );
262             spec->heap_size = atoi(optarg);
263             if (spec->heap_size > 65535)
264                 fatal_error( "Invalid heap size %d, maximum is 65535\n", spec->heap_size );
265             break;
266         case 'I':
267             /* ignored */
268             break;
269         case 'K':
270             /* ignored, because cc generates correct code. */
271             break;
272         case 'L':
273             lib_path = xrealloc( lib_path, (nb_lib_paths+1) * sizeof(*lib_path) );
274             lib_path[nb_lib_paths++] = xstrdup( optarg );
275             break;
276         case 'M':
277             spec->owner_name = xstrdup( optarg );
278             spec->type = SPEC_WIN16;
279             break;
280         case 'N':
281             spec->dll_name = xstrdup( optarg );
282             break;
283         case 'd':
284             add_delayed_import( optarg );
285             break;
286         case 'e':
287             spec->init_func = xstrdup( optarg );
288             if ((p = strchr( spec->init_func, '@' ))) *p = 0;  /* kill stdcall decoration */
289             break;
290         case 'f':
291             if (!strcmp( optarg, "PIC") || !strcmp( optarg, "pic")) UsePIC = 1;
292             /* ignore all other flags */
293             break;
294         case 'h':
295             usage(0);
296             break;
297         case 'i':
298             {
299                 char *str = xstrdup( optarg );
300                 char *token = strtok( str, "," );
301                 while (token)
302                 {
303                     add_ignore_symbol( token );
304                     token = strtok( NULL, "," );
305                 }
306                 free( str );
307             }
308             break;
309         case 'k':
310             kill_at = 1;
311             break;
312         case 'l':
313             add_import_dll( optarg, NULL );
314             break;
315         case 'o':
316             if (unlink( optarg ) == -1 && errno != ENOENT)
317                 fatal_error( "Unable to create output file '%s'\n", optarg );
318             if (!(output_file = fopen( optarg, "w" )))
319                 fatal_error( "Unable to create output file '%s'\n", optarg );
320             output_file_name = xstrdup(optarg);
321             atexit( cleanup );  /* make sure we remove the output file on exit */
322             break;
323         case 'r':
324             res_files = xrealloc( res_files, (nb_res_files+1) * sizeof(*res_files) );
325             res_files[nb_res_files++] = xstrdup( optarg );
326             break;
327         case 'w':
328             display_warnings = 1;
329             break;
330         case LONG_OPT_DLL:
331             set_exec_mode( MODE_DLL );
332             break;
333         case LONG_OPT_DEF:
334             set_exec_mode( MODE_DEF );
335             break;
336         case LONG_OPT_EXE:
337             set_exec_mode( MODE_EXE );
338             if (!spec->subsystem) spec->subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI;
339             break;
340         case LONG_OPT_DEBUG:
341             set_exec_mode( MODE_DEBUG );
342             break;
343         case LONG_OPT_LDCMD:
344             ld_command = xstrdup( optarg );
345             break;
346         case LONG_OPT_NMCMD:
347             nm_command = xstrdup( optarg );
348             break;
349         case LONG_OPT_RELAY16:
350             set_exec_mode( MODE_RELAY16 );
351             break;
352         case LONG_OPT_RELAY32:
353             set_exec_mode( MODE_RELAY32 );
354             break;
355         case LONG_OPT_SUBSYSTEM:
356             set_subsystem( optarg, spec );
357             break;
358         case LONG_OPT_VERSION:
359             printf( "winebuild version " PACKAGE_VERSION "\n" );
360             exit(0);
361         case '?':
362             usage(1);
363             break;
364         }
365     }
366
367     if (spec->file_name && !strchr( spec->file_name, '.' ))
368         strcat( spec->file_name, exec_mode == MODE_EXE ? ".exe" : ".dll" );
369
370     return &argv[optind];
371 }
372
373
374 /* load all specified resource files */
375 static void load_resources( char *argv[], DLLSPEC *spec )
376 {
377     int i;
378     char **ptr, **last;
379
380     switch (spec->type)
381     {
382     case SPEC_WIN16:
383         for (i = 0; i < nb_res_files; i++) load_res16_file( res_files[i], spec );
384         break;
385
386     case SPEC_WIN32:
387         for (i = 0; i < nb_res_files; i++)
388         {
389             if (!load_res32_file( res_files[i], spec ))
390                 fatal_error( "%s is not a valid Win32 resource file\n", res_files[i] );
391         }
392
393         /* load any resource file found in the remaining arguments */
394         for (ptr = last = argv; *ptr; ptr++)
395         {
396             if (!load_res32_file( *ptr, spec ))
397                 *last++ = *ptr; /* not a resource file, keep it in the list */
398         }
399         *last = NULL;
400         break;
401     }
402 }
403
404 /* add input files that look like import libs to the import list */
405 static void load_import_libs( char *argv[] )
406 {
407     char **ptr, **last;
408
409     for (ptr = last = argv; *ptr; ptr++)
410     {
411         if (strendswith( *ptr, ".def" ))
412             add_import_dll( NULL, *ptr );
413         else
414             *last++ = *ptr; /* not an import dll, keep it in the list */
415     }
416     *last = NULL;
417 }
418
419 static int parse_input_file( DLLSPEC *spec )
420 {
421     FILE *input_file = open_input_file( NULL, spec_file_name );
422     char *extension = strrchr( spec_file_name, '.' );
423     int result;
424
425     if (extension && !strcmp( extension, ".def" ))
426         result = parse_def_file( input_file, spec );
427     else
428         result = parse_spec_file( input_file, spec );
429     close_input_file( input_file );
430     return result;
431 }
432
433
434 /*******************************************************************
435  *         main
436  */
437 int main(int argc, char **argv)
438 {
439     DLLSPEC *spec = alloc_dll_spec();
440
441 #ifdef SIGHUP
442     signal( SIGHUP, exit_on_signal );
443 #endif
444     signal( SIGTERM, exit_on_signal );
445     signal( SIGINT, exit_on_signal );
446
447     output_file = stdout;
448     argv = parse_options( argc, argv, spec );
449
450     switch(exec_mode)
451     {
452     case MODE_DLL:
453         spec->characteristics |= IMAGE_FILE_DLL;
454         load_resources( argv, spec );
455         load_import_libs( argv );
456         if (!spec_file_name) fatal_error( "missing .spec file\n" );
457         if (!parse_input_file( spec )) break;
458         switch (spec->type)
459         {
460             case SPEC_WIN16:
461                 if (argv[0])
462                     fatal_error( "file argument '%s' not allowed in this mode\n", argv[0] );
463                 BuildSpec16File( output_file, spec );
464                 break;
465             case SPEC_WIN32:
466                 read_undef_symbols( argv );
467                 BuildSpec32File( output_file, spec );
468                 break;
469             default: assert(0);
470         }
471         break;
472     case MODE_EXE:
473         if (spec->type == SPEC_WIN16) fatal_error( "Cannot build 16-bit exe files\n" );
474         if (!spec->file_name) fatal_error( "executable must be named via the -F option\n" );
475         load_resources( argv, spec );
476         load_import_libs( argv );
477         if (spec_file_name && !parse_input_file( spec )) break;
478         read_undef_symbols( argv );
479         BuildSpec32File( output_file, spec );
480         break;
481     case MODE_DEF:
482         if (argv[0]) fatal_error( "file argument '%s' not allowed in this mode\n", argv[0] );
483         if (spec->type == SPEC_WIN16) fatal_error( "Cannot yet build .def file for 16-bit dlls\n" );
484         if (!spec_file_name) fatal_error( "missing .spec file\n" );
485         if (!parse_input_file( spec )) break;
486         BuildDef32File( output_file, spec );
487         break;
488     case MODE_DEBUG:
489         BuildDebugFile( output_file, current_src_dir, argv );
490         break;
491     case MODE_RELAY16:
492         if (argv[0]) fatal_error( "file argument '%s' not allowed in this mode\n", argv[0] );
493         BuildRelays16( output_file );
494         break;
495     case MODE_RELAY32:
496         if (argv[0]) fatal_error( "file argument '%s' not allowed in this mode\n", argv[0] );
497         BuildRelays32( output_file );
498         break;
499     default:
500         usage(1);
501         break;
502     }
503     if (nb_errors) exit(1);
504     if (output_file_name)
505     {
506         fclose( output_file );
507         output_file_name = NULL;
508     }
509     return 0;
510 }