Avoid excessive heap memory reallocation when generating EMF
[wine] / tools / winegcc / winegcc.c
1 /*
2  * MinGW wrapper: makes gcc behave like MinGW.
3  *
4  * Copyright 2000 Manuel Novoa III
5  * Copyright 2002 Dimitrie O. Paun
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <stdarg.h>
28 #include <string.h>
29 #include <errno.h>
30
31 #include "utils.h"
32
33 static int keep_generated = 0;
34 static strarray *tmp_files;
35
36 static int strendswith(const char *str, const char *end)
37 {
38     int l = strlen(str);
39     int m = strlen(end);
40    
41     return l >= m && strcmp(str + l - m, end) == 0; 
42 }
43
44 static void clean_temp_files()
45 {
46     if (!keep_generated)
47     {
48         int i;
49         for (i = 0; i < tmp_files->size; i++)
50             unlink(tmp_files->base[i]);
51     }
52     strarray_free(tmp_files);
53 }
54
55 static char *get_temp_file(const char *suffix)
56 {
57     char *tmp = strmake("wgcc.XXXXXX%s", suffix);
58     int fd = mkstemps( tmp, strlen(suffix) );
59     if (fd == -1)
60     {
61         /* could not create it in current directory, try in /tmp */
62         free(tmp);
63         tmp = strmake("/tmp/wgcc.XXXXXX%s", suffix);
64         fd = mkstemps( tmp, strlen(suffix) );
65         if (fd == -1) error( "could not create temp file" );
66     }
67     close( fd );
68     strarray_add(tmp_files, tmp);
69
70     return tmp;
71 }
72
73 static char *get_obj_file(char **argv, int n)
74 {
75     char *tmpobj;
76     strarray* compargv;
77     int j;
78
79     if (strendswith(argv[n], ".o")) return argv[n];
80     if (strendswith(argv[n], ".a")) return argv[n];
81     if (strendswith(argv[n], ".res")) return argv[n];
82     
83     tmpobj = get_temp_file(".o");
84
85     compargv = strarray_alloc();
86     strarray_add(compargv,"winegcc");
87     strarray_add(compargv, "-c");
88     strarray_add(compargv, "-o");
89     strarray_add(compargv, tmpobj);
90     for (j = 1; j <= n; j++)
91         if (argv[j]) strarray_add(compargv, argv[j]);
92     strarray_add(compargv, NULL);
93     
94     spawn(compargv);
95     strarray_free(compargv);
96
97     return tmpobj;
98 }
99
100
101 int main(int argc, char **argv)
102 {
103     strarray *gcc_argv;
104     int i, j;
105     int linking = 1, cpp = 0, preprocessor = 0, use_static_linking = 0;
106     int use_stdinc = 1, use_stdlib = 1, use_msvcrt = 0, gui_app = 0;
107
108     tmp_files = strarray_alloc();
109     atexit(clean_temp_files);
110     
111     if (strendswith(argv[0], "winecpp")) preprocessor = 1;
112     else if (strendswith(argv[0], "++")) cpp = 1;
113     
114     for ( i = 1 ; i < argc ; i++ ) 
115     {
116         if (argv[i][0] == '-')  /* option */
117         {
118             switch (argv[i][1]) 
119             {
120                 case 'c':        /* compile or assemble */
121                 case 'S':        /* generate assembler code */
122                 case 'E':        /* preprocess only */
123                     if (argv[i][2] == 0) linking = 0;
124                     break;
125                 case 'M':        /* map file generation */
126                     linking = 0;
127                     break;
128                 case 'm':
129                     if (strcmp("-mno-cygwin", argv[i]) == 0)
130                         use_msvcrt = 1;
131                     else if (strcmp("-mwindows", argv[i]) == 0)
132                         gui_app = 1;
133                     else if (strcmp("-mconsole", argv[i]) == 0)
134                         gui_app = 0;
135                     break;
136                 case 'n':
137                     if (strcmp("-nostdinc", argv[i]) == 0)
138                         use_stdinc = 0;
139                     else if (strcmp("-nodefaultlibs", argv[i]) == 0)
140                         use_stdlib = 0;
141                     else if (strcmp("-nostdlib", argv[i]) == 0)
142                         use_stdlib = 0;
143                     break;
144                 case 's':
145                     if (strcmp("-static", argv[i]) == 0) use_static_linking = 1;
146                     break;
147                 case 'v':        /* verbose */
148                     if (argv[i][2] == 0) verbose = 1;
149                     break;
150                 case 'W':
151                     if (strncmp("-Wl,", argv[i], 4) == 0)
152                     {
153                         if (strstr(argv[i], "-static"))
154                             use_static_linking = 1;
155                     }
156                     break;
157                 case '-':
158                     if (strcmp("-static", argv[i]+1) == 0)
159                         use_static_linking = 1;
160                     break;
161             }
162         } 
163     }
164
165     if (preprocessor) linking = 0;
166     if (use_static_linking) error("Static linking is not supported.");
167
168     gcc_argv = strarray_alloc();
169
170     if (linking)
171     {
172         int has_input_files = 0;
173
174         strarray *copy_argv;
175
176         /* we need a copy in case we decide to pass args straight to gcc
177          * and we erase some of the original parameters as we go along
178          */
179         copy_argv = strarray_alloc();
180         strarray_add(copy_argv, cpp ? "g++" : "gcc");
181         for( j = 1; j < argc ; j++ )
182             strarray_add(copy_argv, argv[j]);
183
184         strarray_add(gcc_argv, "winewrap");
185         if (gui_app) strarray_add(gcc_argv, "-mgui");
186
187         if (cpp) strarray_add(gcc_argv, "-C");
188
189         for ( j = 1 ; j < argc ; j++ ) 
190         {
191             if ( argv[j][0] == '-' )
192             {
193                 switch (argv[j][1])
194                 {
195                 case 'L':
196                 case 'o':
197                     strarray_add(gcc_argv, argv[j]);
198                     if (!argv[j][2] && j + 1 < argc)
199                     {
200                         argv[j] = 0;
201                         strarray_add(gcc_argv, argv[++j]);
202                     }
203                     argv[j] = 0;
204                     break;
205                 case 'l':
206                     strarray_add(gcc_argv, strcmp(argv[j], "-luuid") ? argv[j] : "-lwine_uuid"); 
207                     argv[j] = 0;
208                     break;
209                 default:
210                     ; /* ignore the rest */
211                 }
212             }
213             else
214             {
215                 strarray_add(gcc_argv, get_obj_file(argv, j));
216                 argv[j] = 0;
217                 has_input_files = 1;
218             }
219         }
220
221         if (has_input_files)
222         {
223             if (use_stdlib && use_msvcrt) strarray_add(gcc_argv, "-lmsvcrt");
224             if (gui_app) strarray_add(gcc_argv, "-lcomdlg32");
225             strarray_add(gcc_argv, "-ladvapi32");
226             strarray_add(gcc_argv, "-lshell32");
227         }
228         else
229         {
230             /* if we have nothing to process, just forward stuff to gcc */
231             strarray_free(gcc_argv);
232             gcc_argv = copy_argv;
233         }
234     }
235     else
236     {
237         strarray_add(gcc_argv, preprocessor ? "cpp" : cpp ? "g++" : "gcc");
238
239         if (!preprocessor)
240         {
241             strarray_add(gcc_argv, "-fshort-wchar");
242             strarray_add(gcc_argv, "-fPIC");
243         }
244         if (use_stdinc)
245         {
246             if (use_msvcrt)
247             {
248                 strarray_add(gcc_argv, "-I" INCLUDEDIR "/msvcrt");
249                 strarray_add(gcc_argv, "-D__MSVCRT__");
250             }
251             strarray_add(gcc_argv, "-I" INCLUDEDIR "/windows");
252         }
253         strarray_add(gcc_argv, "-DWIN32");
254         strarray_add(gcc_argv, "-D_WIN32");
255         strarray_add(gcc_argv, "-D__WIN32");
256         strarray_add(gcc_argv, "-D__WIN32__");
257         strarray_add(gcc_argv, "-D__WINNT");
258         strarray_add(gcc_argv, "-D__WINNT__");
259
260         strarray_add(gcc_argv, "-D__stdcall=__attribute__((__stdcall__))");
261         strarray_add(gcc_argv, "-D__cdecl=__attribute__((__cdecl__))");
262         strarray_add(gcc_argv, "-D__fastcall=__attribute__((__fastcall__))");
263         strarray_add(gcc_argv, "-D_stdcall=__attribute__((__stdcall__))");
264         strarray_add(gcc_argv, "-D_cdecl=__attribute__((__cdecl__))");
265         strarray_add(gcc_argv, "-D_fastcall=__attribute__((__fastcall__))");
266         strarray_add(gcc_argv, "-D__declspec(x)=__declspec_##x");
267         strarray_add(gcc_argv, "-D__declspec_align(x)=__attribute__((aligned(x)))");
268         strarray_add(gcc_argv, "-D__declspec_allocate(x)=__attribute__((section(x)))");
269         strarray_add(gcc_argv, "-D__declspec_deprecated=__attribute__((deprecated))");
270         strarray_add(gcc_argv, "-D__declspec_dllimport=__attribute__((dllimport))");
271         strarray_add(gcc_argv, "-D__declspec_dllexport=__attribute__((dllexport))");
272         strarray_add(gcc_argv, "-D__declspec_naked=__attribute__((naked))");
273         strarray_add(gcc_argv, "-D__declspec_noinline=__attribute__((noinline))");
274         strarray_add(gcc_argv, "-D__declspec_noreturn=__attribute__((noreturn))");
275         strarray_add(gcc_argv, "-D__declspec_nothrow=__attribute__((nothrow))");
276         strarray_add(gcc_argv, "-D__declspec_novtable=__attribute__(())"); /* ignore it */
277         strarray_add(gcc_argv, "-D__declspec_selectany=__attribute__((weak))");
278         strarray_add(gcc_argv, "-D__declspec_thread=__thread");
279
280         /* Wine specific defines */
281         strarray_add(gcc_argv, "-D__WINE__");
282         strarray_add(gcc_argv, "-DWINE_UNICODE_NATIVE");
283         strarray_add(gcc_argv, "-D__int8=char");
284         strarray_add(gcc_argv, "-D__int16=short");
285         strarray_add(gcc_argv, "-D__int32=int");
286         strarray_add(gcc_argv, "-D__int64=long long");
287
288         for ( j = 1 ; j < argc ; j++ ) 
289         {
290             if (strcmp("-mno-cygwin", argv[j]) == 0)
291                 ; /* ignore this option */
292             else if (strcmp("-mwindows", argv[j]) == 0)
293                 ; /* ignore this option */
294             else if (strcmp("-mconsole", argv[j]) == 0)
295                 ; /* ignore this option */
296             else if (strcmp("-mthreads", argv[j]) == 0)
297                 ; /* ignore this option */
298             else if (strncmp("-Wl,", argv[j], 4) == 0)
299                 ; /* do not pass linking options to compiler */
300             else if (strcmp("-s", argv[j]) == 0)
301                 ; /* ignore this option */
302             else
303                 strarray_add(gcc_argv, argv[j]);
304         }
305     }
306
307     strarray_add(gcc_argv, NULL);
308
309     spawn(gcc_argv);
310
311     strarray_free(gcc_argv);
312
313     return 0;
314 }