Added support in winebuild for resolving function imports (-sym option).
[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
11 #include <assert.h>
12 #include <stdio.h>
13 #include <unistd.h>
14 #include <errno.h>
15
16 #include "config.h"
17 #include "winnt.h"
18 #include "build.h"
19
20 ORDDEF EntryPoints[MAX_ORDINALS];
21 ORDDEF *Ordinals[MAX_ORDINALS];
22 ORDDEF *Names[MAX_ORDINALS];
23
24 SPEC_MODE SpecMode = SPEC_MODE_DLL;
25 int Base = MAX_ORDINALS;
26 int Limit = 0;
27 int DLLHeapSize = 0;
28 int UsePIC = 0;
29 int nb_entry_points = 0;
30 int nb_names = 0;
31 int debugging = 1;
32 int nb_debug_channels = 0;
33 int nb_lib_paths = 0;
34
35 char DLLName[80];
36 char DLLFileName[80];
37 char DLLInitFunc[80];
38 char owner_name[80];
39 char **debug_channels = NULL;
40 char **lib_path = NULL;
41
42 const char *input_file_name;
43 const char *output_file_name;
44
45 static FILE *input_file;
46 static FILE *output_file;
47
48 /* execution mode */
49 static enum { MODE_NONE, MODE_SPEC, MODE_GLUE, MODE_RELAY } exec_mode = MODE_NONE;
50
51 /* open the input file */
52 static void open_input( const char *name )
53 {
54     input_file_name = name;
55     if (!(input_file = fopen( name, "r" )))
56     {
57         fprintf( stderr, "Cannot open input file '%s'\n", name );
58         exit(1);
59     }
60 }
61
62 /* cleanup on program exit */
63 static void cleanup(void)
64 {
65     if (output_file_name) unlink( output_file_name );
66 }
67
68
69 /*******************************************************************
70  *         command-line option handling
71  */
72
73 struct option
74 {
75     const char *name;
76     int         has_arg;
77     void      (*func)();
78     const char *usage;
79 };
80
81 static void do_pic(void);
82 static void do_output( const char *arg );
83 static void do_usage(void);
84 static void do_spec( const char *arg );
85 static void do_glue( const char *arg );
86 static void do_relay(void);
87 static void do_sym( const char *arg );
88 static void do_lib( const char *arg );
89
90 static const struct option option_table[] =
91 {
92     { "-fPIC",  0, do_pic,    "-fPIC            Generate PIC code" },
93     { "-h",     0, do_usage,  "-h               Display this help message" },
94     { "-L",     1, do_lib,    "-L directory     Look for imports libraries in 'directory'" },
95     { "-o",     1, do_output, "-o name          Set the output file name (default: stdout)" },
96     { "-sym",   1, do_sym,    "-sym file.o      Read the list of undefined symbols from 'file.o'" },
97     { "-spec",  1, do_spec,   "-spec file.spec  Build a .c file from a spec file" },
98     { "-glue",  1, do_glue,   "-glue file.c     Build the 16-bit glue for a .c file" },
99     { "-relay", 0, do_relay,  "-relay           Build the relay assembly routines" },
100     { NULL,     0, NULL,      NULL }
101 };
102
103 static void do_pic(void)
104 {
105     UsePIC = 1;
106 }
107
108 static void do_output( const char *arg )
109 {
110     if ( ( unlink ( arg ) ) == -1 && ( errno != ENOENT ) ) 
111     {
112         fprintf ( stderr, "Unable to create output file '%s'\n", arg );
113         exit (1);
114     }
115     if (!(output_file = fopen( arg, "w" )))
116     {
117         fprintf( stderr, "Unable to create output file '%s'\n", arg );
118         exit(1);
119     }
120     output_file_name = arg;
121     atexit( cleanup );  /* make sure we remove the output file on exit */
122 }
123
124 static void do_usage(void)
125 {
126     const struct option *opt;
127     fprintf( stderr, "Usage: winebuild [options]\n\n" );
128     fprintf( stderr, "Options:\n" );
129     for (opt = option_table; opt->name; opt++) fprintf( stderr, "   %s\n", opt->usage );
130     fprintf( stderr, "\nExactly one of -spec, -glue or -relay must be specified.\n\n" );
131     exit(1);
132 }
133
134 static void do_spec( const char *arg )
135 {
136     if (exec_mode != MODE_NONE || !arg[0]) do_usage();
137     exec_mode = MODE_SPEC;
138     open_input( arg );
139 }
140
141 static void do_glue( const char *arg )
142 {
143     if (exec_mode != MODE_NONE || !arg[0]) do_usage();
144     exec_mode = MODE_GLUE;
145     open_input( arg );
146 }
147
148 static void do_relay(void)
149 {
150     if (exec_mode != MODE_NONE) do_usage();
151     exec_mode = MODE_RELAY;
152 }
153
154 static void do_sym( const char *arg )
155 {
156     extern void read_undef_symbols( const char *name );
157     read_undef_symbols( arg );
158 }
159
160 static void do_lib( const char *arg )
161 {
162     lib_path = xrealloc( lib_path, (nb_lib_paths+1) * sizeof(*lib_path) );
163     lib_path[nb_lib_paths++] = xstrdup( arg );
164 }
165
166 /* parse options from the argv array and remove all the recognized ones */
167 static void parse_options( char *argv[] )
168 {
169     const struct option *opt;
170     int i;
171
172     for (i = 1; argv[i]; i++)
173     {
174         for (opt = option_table; opt->name; opt++)
175             if (!strcmp( argv[i], opt->name )) break;
176
177         if (!opt->name)
178         {
179             fprintf( stderr, "Unrecognized option '%s'\n", argv[i] );
180             do_usage();
181         }
182
183         if (opt->has_arg && argv[i+1]) opt->func( argv[++i] );
184         else opt->func( "" );
185     }
186 }
187
188
189 /*******************************************************************
190  *         main
191  */
192 int main(int argc, char **argv)
193 {
194     output_file = stdout;
195     parse_options( argv );
196
197     switch(exec_mode)
198     {
199     case MODE_SPEC:
200         switch (ParseTopLevel( input_file ))
201         {
202             case SPEC_WIN16:
203                 BuildSpec16File( output_file );
204                 break;
205             case SPEC_WIN32:
206                 BuildSpec32File( output_file, !resolve_imports( output_file ) );
207                 break;
208             default: assert(0);
209         }
210         break;
211     case MODE_GLUE:
212         BuildGlue( output_file, input_file );
213         break;
214     case MODE_RELAY:
215         BuildRelays( output_file );
216         break;
217     default:
218         do_usage();
219         break;
220     }
221     fclose( output_file );
222     output_file_name = NULL;
223     return 0;
224 }