dllwrap.c revision 1.10 1 1.1 christos /* dllwrap.c -- wrapper for DLLTOOL and GCC to generate PE style DLLs
2 1.10 christos Copyright (C) 1998-2025 Free Software Foundation, Inc.
3 1.1 christos Contributed by Mumit Khan (khan (at) xraylith.wisc.edu).
4 1.1 christos
5 1.1 christos This file is part of GNU Binutils.
6 1.1 christos
7 1.1 christos This program is free software; you can redistribute it and/or modify
8 1.1 christos it under the terms of the GNU General Public License as published by
9 1.1 christos the Free Software Foundation; either version 3 of the License, or
10 1.1 christos (at your option) any later version.
11 1.1 christos
12 1.1 christos This program is distributed in the hope that it will be useful,
13 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
14 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 1.1 christos GNU General Public License for more details.
16 1.1 christos
17 1.1 christos You should have received a copy of the GNU General Public License
18 1.1 christos along with this program; if not, write to the Free Software
19 1.1 christos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
20 1.1 christos 02110-1301, USA. */
21 1.1 christos
22 1.1 christos #include "sysdep.h"
23 1.1 christos #include "bfd.h"
24 1.1 christos #include "libiberty.h"
25 1.1 christos #include "getopt.h"
26 1.1 christos #include "dyn-string.h"
27 1.1 christos #include "bucomm.h"
28 1.1 christos
29 1.1 christos #include <time.h>
30 1.1 christos
31 1.1 christos #ifdef HAVE_SYS_WAIT_H
32 1.1 christos #include <sys/wait.h>
33 1.1 christos #else /* ! HAVE_SYS_WAIT_H */
34 1.1 christos #if ! defined (_WIN32) || defined (__CYGWIN32__)
35 1.1 christos #ifndef WIFEXITED
36 1.1 christos #define WIFEXITED(w) (((w)&0377) == 0)
37 1.1 christos #endif
38 1.1 christos #ifndef WIFSIGNALED
39 1.1 christos #define WIFSIGNALED(w) (((w)&0377) != 0177 && ((w)&~0377) == 0)
40 1.1 christos #endif
41 1.1 christos #ifndef WTERMSIG
42 1.1 christos #define WTERMSIG(w) ((w) & 0177)
43 1.1 christos #endif
44 1.1 christos #ifndef WEXITSTATUS
45 1.1 christos #define WEXITSTATUS(w) (((w) >> 8) & 0377)
46 1.1 christos #endif
47 1.1 christos #else /* defined (_WIN32) && ! defined (__CYGWIN32__) */
48 1.1 christos #ifndef WIFEXITED
49 1.1 christos #define WIFEXITED(w) (((w) & 0xff) == 0)
50 1.1 christos #endif
51 1.1 christos #ifndef WIFSIGNALED
52 1.1 christos #define WIFSIGNALED(w) (((w) & 0xff) != 0 && ((w) & 0xff) != 0x7f)
53 1.1 christos #endif
54 1.1 christos #ifndef WTERMSIG
55 1.1 christos #define WTERMSIG(w) ((w) & 0x7f)
56 1.1 christos #endif
57 1.1 christos #ifndef WEXITSTATUS
58 1.1 christos #define WEXITSTATUS(w) (((w) & 0xff00) >> 8)
59 1.1 christos #endif
60 1.1 christos #endif /* defined (_WIN32) && ! defined (__CYGWIN32__) */
61 1.1 christos #endif /* ! HAVE_SYS_WAIT_H */
62 1.1 christos
63 1.1 christos static char *driver_name = NULL;
64 1.1 christos static char *cygwin_driver_flags =
65 1.1 christos "-Wl,--dll -nostartfiles";
66 1.1 christos static char *mingw32_driver_flags = "-mdll";
67 1.1 christos static char *generic_driver_flags = "-Wl,--dll";
68 1.1 christos
69 1.1 christos static char *entry_point;
70 1.1 christos
71 1.1 christos static char *dlltool_name = NULL;
72 1.1 christos
73 1.1 christos static char *target = TARGET;
74 1.1 christos
75 1.1 christos /* -1: use default, 0: no underscoring, 1: underscore. */
76 1.1 christos static int is_leading_underscore = -1;
77 1.1 christos
78 1.1 christos typedef enum {
79 1.1 christos UNKNOWN_TARGET,
80 1.1 christos CYGWIN_TARGET,
81 1.1 christos MINGW_TARGET
82 1.1 christos }
83 1.1 christos target_type;
84 1.1 christos
85 1.1 christos typedef enum {
86 1.1 christos UNKNOWN_CPU,
87 1.1 christos X86_CPU,
88 1.1 christos X64_CPU,
89 1.1 christos ARM_CPU
90 1.1 christos }
91 1.1 christos target_cpu;
92 1.1 christos
93 1.1 christos static target_type which_target = UNKNOWN_TARGET;
94 1.1 christos static target_cpu which_cpu = UNKNOWN_CPU;
95 1.1 christos
96 1.1 christos static int dontdeltemps = 0;
97 1.1 christos static int dry_run = 0;
98 1.1 christos
99 1.1 christos static char *prog_name;
100 1.1 christos
101 1.1 christos static int verbose = 0;
102 1.1 christos
103 1.1 christos static char *dll_file_name;
104 1.1 christos static char *dll_name;
105 1.1 christos static char *base_file_name;
106 1.1 christos static char *exp_file_name;
107 1.1 christos static char *def_file_name;
108 1.1 christos static int delete_base_file = 1;
109 1.1 christos static int delete_exp_file = 1;
110 1.1 christos static int delete_def_file = 1;
111 1.1 christos
112 1.1 christos static int run (const char *, char *);
113 1.1 christos static char *mybasename (const char *);
114 1.1 christos static int strhash (const char *);
115 1.1 christos static void usage (FILE *, int);
116 1.1 christos static void display (const char *, va_list) ATTRIBUTE_PRINTF(1,0);
117 1.1 christos static void inform (const char *, ...) ATTRIBUTE_PRINTF_1;
118 1.1 christos static void warn (const char *, ...) ATTRIBUTE_PRINTF_1;
119 1.1 christos static char *look_for_prog (const char *, const char *, int);
120 1.1 christos static char *deduce_name (const char *);
121 1.1 christos static void delete_temp_files (void);
122 1.1 christos static void cleanup_and_exit (int);
123 1.1 christos
124 1.1 christos /**********************************************************************/
125 1.1 christos
126 1.1 christos /* Please keep the following 4 routines in sync with dlltool.c:
127 1.1 christos display ()
128 1.1 christos inform ()
129 1.1 christos look_for_prog ()
130 1.1 christos deduce_name ()
131 1.1 christos It's not worth the hassle to break these out since dllwrap will
132 1.1 christos (hopefully) soon be retired in favor of `ld --shared. */
133 1.1 christos
134 1.1 christos static void
135 1.1 christos display (const char * message, va_list args)
136 1.1 christos {
137 1.1 christos if (prog_name != NULL)
138 1.1 christos fprintf (stderr, "%s: ", prog_name);
139 1.1 christos
140 1.1 christos vfprintf (stderr, message, args);
141 1.1 christos fputc ('\n', stderr);
142 1.1 christos }
143 1.1 christos
144 1.1 christos
145 1.1 christos static void
146 1.3 christos inform (const char *message, ...)
147 1.1 christos {
148 1.3 christos va_list args;
149 1.3 christos
150 1.3 christos va_start (args, message);
151 1.1 christos
152 1.1 christos if (!verbose)
153 1.1 christos return;
154 1.1 christos
155 1.1 christos display (message, args);
156 1.1 christos
157 1.3 christos va_end (args);
158 1.1 christos }
159 1.1 christos
160 1.1 christos static void
161 1.3 christos warn (const char *format, ...)
162 1.1 christos {
163 1.3 christos va_list args;
164 1.3 christos
165 1.3 christos va_start (args, format);
166 1.1 christos
167 1.1 christos display (format, args);
168 1.1 christos
169 1.3 christos va_end (args);
170 1.1 christos }
171 1.1 christos
172 1.1 christos /* Look for the program formed by concatenating PROG_NAME and the
173 1.1 christos string running from PREFIX to END_PREFIX. If the concatenated
174 1.1 christos string contains a '/', try appending EXECUTABLE_SUFFIX if it is
175 1.1 christos appropriate. */
176 1.1 christos
177 1.1 christos static char *
178 1.1 christos look_for_prog (const char *progname, const char *prefix, int end_prefix)
179 1.1 christos {
180 1.1 christos struct stat s;
181 1.1 christos char *cmd;
182 1.1 christos
183 1.1 christos cmd = xmalloc (strlen (prefix)
184 1.1 christos + strlen (progname)
185 1.1 christos #ifdef HAVE_EXECUTABLE_SUFFIX
186 1.1 christos + strlen (EXECUTABLE_SUFFIX)
187 1.1 christos #endif
188 1.1 christos + 10);
189 1.9 christos memcpy (cmd, prefix, end_prefix);
190 1.1 christos
191 1.9 christos strcpy (cmd + end_prefix, progname);
192 1.1 christos
193 1.1 christos if (strchr (cmd, '/') != NULL)
194 1.1 christos {
195 1.1 christos int found;
196 1.1 christos
197 1.1 christos found = (stat (cmd, &s) == 0
198 1.1 christos #ifdef HAVE_EXECUTABLE_SUFFIX
199 1.1 christos || stat (strcat (cmd, EXECUTABLE_SUFFIX), &s) == 0
200 1.1 christos #endif
201 1.1 christos );
202 1.1 christos
203 1.1 christos if (! found)
204 1.1 christos {
205 1.1 christos /* xgettext:c-format */
206 1.1 christos inform (_("Tried file: %s"), cmd);
207 1.1 christos free (cmd);
208 1.1 christos return NULL;
209 1.1 christos }
210 1.1 christos }
211 1.1 christos
212 1.1 christos /* xgettext:c-format */
213 1.1 christos inform (_("Using file: %s"), cmd);
214 1.1 christos
215 1.1 christos return cmd;
216 1.1 christos }
217 1.1 christos
218 1.1 christos /* Deduce the name of the program we are want to invoke.
219 1.1 christos PROG_NAME is the basic name of the program we want to run,
220 1.1 christos eg "as" or "ld". The catch is that we might want actually
221 1.1 christos run "i386-pe-as" or "ppc-pe-ld".
222 1.1 christos
223 1.1 christos If argv[0] contains the full path, then try to find the program
224 1.1 christos in the same place, with and then without a target-like prefix.
225 1.1 christos
226 1.1 christos Given, argv[0] = /usr/local/bin/i586-cygwin32-dlltool,
227 1.1 christos deduce_name("as") uses the following search order:
228 1.1 christos
229 1.1 christos /usr/local/bin/i586-cygwin32-as
230 1.1 christos /usr/local/bin/as
231 1.1 christos as
232 1.1 christos
233 1.1 christos If there's an EXECUTABLE_SUFFIX, it'll use that as well; for each
234 1.1 christos name, it'll try without and then with EXECUTABLE_SUFFIX.
235 1.1 christos
236 1.1 christos Given, argv[0] = i586-cygwin32-dlltool, it will not even try "as"
237 1.1 christos as the fallback, but rather return i586-cygwin32-as.
238 1.1 christos
239 1.1 christos Oh, and given, argv[0] = dlltool, it'll return "as".
240 1.1 christos
241 1.1 christos Returns a dynamically allocated string. */
242 1.1 christos
243 1.1 christos static char *
244 1.1 christos deduce_name (const char * name)
245 1.1 christos {
246 1.1 christos char *cmd;
247 1.1 christos const char *dash;
248 1.1 christos const char *slash;
249 1.1 christos const char *cp;
250 1.1 christos
251 1.1 christos dash = NULL;
252 1.1 christos slash = NULL;
253 1.1 christos for (cp = prog_name; *cp != '\0'; ++cp)
254 1.1 christos {
255 1.1 christos if (*cp == '-')
256 1.1 christos dash = cp;
257 1.1 christos
258 1.1 christos if (
259 1.1 christos #if defined(__DJGPP__) || defined (__CYGWIN__) || defined(__WIN32__)
260 1.1 christos *cp == ':' || *cp == '\\' ||
261 1.1 christos #endif
262 1.1 christos *cp == '/')
263 1.1 christos {
264 1.1 christos slash = cp;
265 1.1 christos dash = NULL;
266 1.1 christos }
267 1.1 christos }
268 1.1 christos
269 1.1 christos cmd = NULL;
270 1.1 christos
271 1.1 christos if (dash != NULL)
272 1.1 christos /* First, try looking for a prefixed NAME in the
273 1.1 christos PROG_NAME directory, with the same prefix as PROG_NAME. */
274 1.1 christos cmd = look_for_prog (name, prog_name, dash - prog_name + 1);
275 1.1 christos
276 1.1 christos if (slash != NULL && cmd == NULL)
277 1.1 christos /* Next, try looking for a NAME in the same directory as
278 1.1 christos that of this program. */
279 1.1 christos cmd = look_for_prog (name, prog_name, slash - prog_name + 1);
280 1.1 christos
281 1.1 christos if (cmd == NULL)
282 1.1 christos /* Just return NAME as is. */
283 1.1 christos cmd = xstrdup (name);
284 1.1 christos
285 1.1 christos return cmd;
286 1.1 christos }
287 1.1 christos
288 1.1 christos static void
289 1.1 christos delete_temp_files (void)
290 1.1 christos {
291 1.1 christos if (delete_base_file && base_file_name)
292 1.1 christos {
293 1.1 christos if (verbose)
294 1.1 christos {
295 1.1 christos if (dontdeltemps)
296 1.1 christos warn (_("Keeping temporary base file %s"), base_file_name);
297 1.1 christos else
298 1.1 christos warn (_("Deleting temporary base file %s"), base_file_name);
299 1.1 christos }
300 1.1 christos if (! dontdeltemps)
301 1.1 christos {
302 1.1 christos unlink (base_file_name);
303 1.1 christos free (base_file_name);
304 1.1 christos }
305 1.1 christos }
306 1.1 christos
307 1.1 christos if (delete_exp_file && exp_file_name)
308 1.1 christos {
309 1.1 christos if (verbose)
310 1.1 christos {
311 1.1 christos if (dontdeltemps)
312 1.1 christos warn (_("Keeping temporary exp file %s"), exp_file_name);
313 1.1 christos else
314 1.1 christos warn (_("Deleting temporary exp file %s"), exp_file_name);
315 1.1 christos }
316 1.1 christos if (! dontdeltemps)
317 1.1 christos {
318 1.1 christos unlink (exp_file_name);
319 1.1 christos free (exp_file_name);
320 1.1 christos }
321 1.1 christos }
322 1.1 christos if (delete_def_file && def_file_name)
323 1.1 christos {
324 1.1 christos if (verbose)
325 1.1 christos {
326 1.1 christos if (dontdeltemps)
327 1.1 christos warn (_("Keeping temporary def file %s"), def_file_name);
328 1.1 christos else
329 1.1 christos warn (_("Deleting temporary def file %s"), def_file_name);
330 1.1 christos }
331 1.1 christos if (! dontdeltemps)
332 1.1 christos {
333 1.1 christos unlink (def_file_name);
334 1.1 christos free (def_file_name);
335 1.1 christos }
336 1.1 christos }
337 1.1 christos }
338 1.1 christos
339 1.1 christos static void
340 1.1 christos cleanup_and_exit (int status)
341 1.1 christos {
342 1.1 christos delete_temp_files ();
343 1.1 christos exit (status);
344 1.1 christos }
345 1.1 christos
346 1.1 christos static int
347 1.1 christos run (const char *what, char *args)
348 1.1 christos {
349 1.1 christos char *s;
350 1.1 christos int pid, wait_status, retcode;
351 1.1 christos int i;
352 1.1 christos const char **argv;
353 1.8 christos char *errmsg_fmt = NULL, *errmsg_arg = NULL;
354 1.9 christos char *temp_base = make_temp_file (NULL);
355 1.1 christos int in_quote;
356 1.1 christos char sep;
357 1.1 christos
358 1.1 christos if (verbose || dry_run)
359 1.1 christos fprintf (stderr, "%s %s\n", what, args);
360 1.1 christos
361 1.1 christos /* Count the args */
362 1.1 christos i = 0;
363 1.1 christos for (s = args; *s; s++)
364 1.1 christos if (*s == ' ')
365 1.1 christos i++;
366 1.1 christos i++;
367 1.5 christos argv = xmalloc (sizeof (char *) * (i + 3));
368 1.1 christos i = 0;
369 1.1 christos argv[i++] = what;
370 1.1 christos s = args;
371 1.1 christos while (1)
372 1.1 christos {
373 1.1 christos while (*s == ' ' && *s != 0)
374 1.1 christos s++;
375 1.1 christos if (*s == 0)
376 1.1 christos break;
377 1.1 christos in_quote = (*s == '\'' || *s == '"');
378 1.1 christos sep = (in_quote) ? *s++ : ' ';
379 1.1 christos argv[i++] = s;
380 1.1 christos while (*s != sep && *s != 0)
381 1.1 christos s++;
382 1.1 christos if (*s == 0)
383 1.1 christos break;
384 1.1 christos *s++ = 0;
385 1.1 christos if (in_quote)
386 1.1 christos s++;
387 1.1 christos }
388 1.1 christos argv[i++] = NULL;
389 1.1 christos
390 1.1 christos if (dry_run)
391 1.1 christos return 0;
392 1.1 christos
393 1.1 christos pid = pexecute (argv[0], (char * const *) argv, prog_name, temp_base,
394 1.1 christos &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
395 1.5 christos free (argv);
396 1.1 christos
397 1.1 christos if (pid == -1)
398 1.1 christos {
399 1.1 christos int errno_val = errno;
400 1.1 christos
401 1.1 christos fprintf (stderr, "%s: ", prog_name);
402 1.1 christos fprintf (stderr, errmsg_fmt, errmsg_arg);
403 1.1 christos fprintf (stderr, ": %s\n", strerror (errno_val));
404 1.1 christos return 1;
405 1.1 christos }
406 1.1 christos
407 1.1 christos retcode = 0;
408 1.1 christos pid = pwait (pid, &wait_status, 0);
409 1.1 christos if (pid == -1)
410 1.1 christos {
411 1.1 christos warn (_("pwait returns: %s"), strerror (errno));
412 1.1 christos retcode = 1;
413 1.1 christos }
414 1.1 christos else if (WIFSIGNALED (wait_status))
415 1.1 christos {
416 1.1 christos warn (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
417 1.1 christos retcode = 1;
418 1.1 christos }
419 1.1 christos else if (WIFEXITED (wait_status))
420 1.1 christos {
421 1.1 christos if (WEXITSTATUS (wait_status) != 0)
422 1.1 christos {
423 1.1 christos warn (_("%s exited with status %d"), what, WEXITSTATUS (wait_status));
424 1.1 christos retcode = 1;
425 1.1 christos }
426 1.1 christos }
427 1.1 christos else
428 1.1 christos retcode = 1;
429 1.1 christos
430 1.1 christos return retcode;
431 1.1 christos }
432 1.1 christos
433 1.1 christos static char *
434 1.1 christos mybasename (const char *name)
435 1.1 christos {
436 1.1 christos const char *base = name;
437 1.1 christos
438 1.1 christos while (*name)
439 1.1 christos {
440 1.1 christos if (*name == '/' || *name == '\\')
441 1.1 christos {
442 1.1 christos base = name + 1;
443 1.1 christos }
444 1.1 christos ++name;
445 1.1 christos }
446 1.1 christos return (char *) base;
447 1.1 christos }
448 1.1 christos
449 1.1 christos static int
450 1.1 christos strhash (const char *str)
451 1.1 christos {
452 1.1 christos const unsigned char *s;
453 1.1 christos unsigned long hash;
454 1.1 christos unsigned int c;
455 1.1 christos unsigned int len;
456 1.1 christos
457 1.1 christos hash = 0;
458 1.1 christos len = 0;
459 1.1 christos s = (const unsigned char *) str;
460 1.1 christos while ((c = *s++) != '\0')
461 1.1 christos {
462 1.1 christos hash += c + (c << 17);
463 1.1 christos hash ^= hash >> 2;
464 1.1 christos ++len;
465 1.1 christos }
466 1.1 christos hash += len + (len << 17);
467 1.1 christos hash ^= hash >> 2;
468 1.1 christos
469 1.1 christos return hash;
470 1.1 christos }
471 1.1 christos
472 1.1 christos /**********************************************************************/
473 1.1 christos
474 1.1 christos static void
475 1.1 christos usage (FILE *file, int status)
476 1.1 christos {
477 1.1 christos fprintf (file, _("Usage %s <option(s)> <object-file(s)>\n"), prog_name);
478 1.1 christos fprintf (file, _(" Generic options:\n"));
479 1.3 christos fprintf (file, _(" @<file> Read options from <file>\n"));
480 1.1 christos fprintf (file, _(" --quiet, -q Work quietly\n"));
481 1.1 christos fprintf (file, _(" --verbose, -v Verbose\n"));
482 1.1 christos fprintf (file, _(" --version Print dllwrap version\n"));
483 1.1 christos fprintf (file, _(" --implib <outname> Synonym for --output-lib\n"));
484 1.1 christos fprintf (file, _(" Options for %s:\n"), prog_name);
485 1.1 christos fprintf (file, _(" --driver-name <driver> Defaults to \"gcc\"\n"));
486 1.1 christos fprintf (file, _(" --driver-flags <flags> Override default ld flags\n"));
487 1.1 christos fprintf (file, _(" --dlltool-name <dlltool> Defaults to \"dlltool\"\n"));
488 1.1 christos fprintf (file, _(" --entry <entry> Specify alternate DLL entry point\n"));
489 1.1 christos fprintf (file, _(" --image-base <base> Specify image base address\n"));
490 1.1 christos fprintf (file, _(" --target <machine> i386-cygwin32 or i386-mingw32\n"));
491 1.1 christos fprintf (file, _(" --dry-run Show what needs to be run\n"));
492 1.1 christos fprintf (file, _(" --mno-cygwin Create Mingw DLL\n"));
493 1.1 christos fprintf (file, _(" Options passed to DLLTOOL:\n"));
494 1.1 christos fprintf (file, _(" --machine <machine>\n"));
495 1.1 christos fprintf (file, _(" --output-exp <outname> Generate export file.\n"));
496 1.1 christos fprintf (file, _(" --output-lib <outname> Generate input library.\n"));
497 1.1 christos fprintf (file, _(" --add-indirect Add dll indirects to export file.\n"));
498 1.1 christos fprintf (file, _(" --dllname <name> Name of input dll to put into output lib.\n"));
499 1.1 christos fprintf (file, _(" --def <deffile> Name input .def file\n"));
500 1.1 christos fprintf (file, _(" --output-def <deffile> Name output .def file\n"));
501 1.1 christos fprintf (file, _(" --export-all-symbols Export all symbols to .def\n"));
502 1.1 christos fprintf (file, _(" --no-export-all-symbols Only export .drectve symbols\n"));
503 1.1 christos fprintf (file, _(" --exclude-symbols <list> Exclude <list> from .def\n"));
504 1.1 christos fprintf (file, _(" --no-default-excludes Zap default exclude symbols\n"));
505 1.1 christos fprintf (file, _(" --base-file <basefile> Read linker generated base file\n"));
506 1.1 christos fprintf (file, _(" --no-idata4 Don't generate idata$4 section\n"));
507 1.1 christos fprintf (file, _(" --no-idata5 Don't generate idata$5 section\n"));
508 1.1 christos fprintf (file, _(" -U Add underscores to .lib\n"));
509 1.1 christos fprintf (file, _(" -k Kill @<n> from exported names\n"));
510 1.1 christos fprintf (file, _(" --add-stdcall-alias Add aliases without @<n>\n"));
511 1.1 christos fprintf (file, _(" --as <name> Use <name> for assembler\n"));
512 1.1 christos fprintf (file, _(" --nodelete Keep temp files.\n"));
513 1.1 christos fprintf (file, _(" --no-leading-underscore Entrypoint without underscore\n"));
514 1.1 christos fprintf (file, _(" --leading-underscore Entrypoint with underscore.\n"));
515 1.1 christos fprintf (file, _(" Rest are passed unmodified to the language driver\n"));
516 1.1 christos fprintf (file, "\n\n");
517 1.1 christos if (REPORT_BUGS_TO[0] && status == 0)
518 1.1 christos fprintf (file, _("Report bugs to %s\n"), REPORT_BUGS_TO);
519 1.1 christos exit (status);
520 1.1 christos }
521 1.1 christos
522 1.1 christos #define OPTION_START 149
523 1.1 christos
524 1.1 christos /* GENERIC options. */
525 1.1 christos #define OPTION_QUIET (OPTION_START + 1)
526 1.1 christos #define OPTION_VERBOSE (OPTION_QUIET + 1)
527 1.1 christos #define OPTION_VERSION (OPTION_VERBOSE + 1)
528 1.1 christos
529 1.1 christos /* DLLWRAP options. */
530 1.1 christos #define OPTION_DRY_RUN (OPTION_VERSION + 1)
531 1.1 christos #define OPTION_DRIVER_NAME (OPTION_DRY_RUN + 1)
532 1.1 christos #define OPTION_DRIVER_FLAGS (OPTION_DRIVER_NAME + 1)
533 1.1 christos #define OPTION_DLLTOOL_NAME (OPTION_DRIVER_FLAGS + 1)
534 1.1 christos #define OPTION_ENTRY (OPTION_DLLTOOL_NAME + 1)
535 1.1 christos #define OPTION_IMAGE_BASE (OPTION_ENTRY + 1)
536 1.1 christos #define OPTION_TARGET (OPTION_IMAGE_BASE + 1)
537 1.1 christos #define OPTION_MNO_CYGWIN (OPTION_TARGET + 1)
538 1.1 christos #define OPTION_NO_LEADING_UNDERSCORE (OPTION_MNO_CYGWIN + 1)
539 1.1 christos #define OPTION_LEADING_UNDERSCORE (OPTION_NO_LEADING_UNDERSCORE + 1)
540 1.1 christos
541 1.1 christos /* DLLTOOL options. */
542 1.1 christos #define OPTION_NODELETE (OPTION_LEADING_UNDERSCORE + 1)
543 1.1 christos #define OPTION_DLLNAME (OPTION_NODELETE + 1)
544 1.1 christos #define OPTION_NO_IDATA4 (OPTION_DLLNAME + 1)
545 1.1 christos #define OPTION_NO_IDATA5 (OPTION_NO_IDATA4 + 1)
546 1.1 christos #define OPTION_OUTPUT_EXP (OPTION_NO_IDATA5 + 1)
547 1.1 christos #define OPTION_OUTPUT_DEF (OPTION_OUTPUT_EXP + 1)
548 1.1 christos #define OPTION_EXPORT_ALL_SYMS (OPTION_OUTPUT_DEF + 1)
549 1.1 christos #define OPTION_NO_EXPORT_ALL_SYMS (OPTION_EXPORT_ALL_SYMS + 1)
550 1.1 christos #define OPTION_EXCLUDE_SYMS (OPTION_NO_EXPORT_ALL_SYMS + 1)
551 1.1 christos #define OPTION_NO_DEFAULT_EXCLUDES (OPTION_EXCLUDE_SYMS + 1)
552 1.1 christos #define OPTION_OUTPUT_LIB (OPTION_NO_DEFAULT_EXCLUDES + 1)
553 1.1 christos #define OPTION_DEF (OPTION_OUTPUT_LIB + 1)
554 1.1 christos #define OPTION_ADD_UNDERSCORE (OPTION_DEF + 1)
555 1.1 christos #define OPTION_KILLAT (OPTION_ADD_UNDERSCORE + 1)
556 1.1 christos #define OPTION_HELP (OPTION_KILLAT + 1)
557 1.1 christos #define OPTION_MACHINE (OPTION_HELP + 1)
558 1.1 christos #define OPTION_ADD_INDIRECT (OPTION_MACHINE + 1)
559 1.1 christos #define OPTION_BASE_FILE (OPTION_ADD_INDIRECT + 1)
560 1.1 christos #define OPTION_AS (OPTION_BASE_FILE + 1)
561 1.1 christos
562 1.1 christos static const struct option long_options[] =
563 1.1 christos {
564 1.1 christos /* generic options. */
565 1.1 christos {"quiet", no_argument, NULL, 'q'},
566 1.1 christos {"verbose", no_argument, NULL, 'v'},
567 1.1 christos {"version", no_argument, NULL, OPTION_VERSION},
568 1.1 christos {"implib", required_argument, NULL, OPTION_OUTPUT_LIB},
569 1.1 christos
570 1.1 christos /* dllwrap options. */
571 1.1 christos {"dry-run", no_argument, NULL, OPTION_DRY_RUN},
572 1.1 christos {"driver-name", required_argument, NULL, OPTION_DRIVER_NAME},
573 1.1 christos {"driver-flags", required_argument, NULL, OPTION_DRIVER_FLAGS},
574 1.1 christos {"dlltool-name", required_argument, NULL, OPTION_DLLTOOL_NAME},
575 1.1 christos {"entry", required_argument, NULL, 'e'},
576 1.1 christos {"image-base", required_argument, NULL, OPTION_IMAGE_BASE},
577 1.1 christos {"target", required_argument, NULL, OPTION_TARGET},
578 1.1 christos {"no-leading-underscore", no_argument, NULL, OPTION_NO_LEADING_UNDERSCORE},
579 1.1 christos {"leading-underscore", no_argument, NULL, OPTION_NO_LEADING_UNDERSCORE},
580 1.1 christos
581 1.1 christos /* dlltool options. */
582 1.1 christos {"no-delete", no_argument, NULL, 'n'},
583 1.1 christos {"dllname", required_argument, NULL, OPTION_DLLNAME},
584 1.1 christos {"no-idata4", no_argument, NULL, OPTION_NO_IDATA4},
585 1.1 christos {"no-idata5", no_argument, NULL, OPTION_NO_IDATA5},
586 1.1 christos {"output-exp", required_argument, NULL, OPTION_OUTPUT_EXP},
587 1.1 christos {"output-def", required_argument, NULL, OPTION_OUTPUT_DEF},
588 1.1 christos {"export-all-symbols", no_argument, NULL, OPTION_EXPORT_ALL_SYMS},
589 1.1 christos {"no-export-all-symbols", no_argument, NULL, OPTION_NO_EXPORT_ALL_SYMS},
590 1.1 christos {"exclude-symbols", required_argument, NULL, OPTION_EXCLUDE_SYMS},
591 1.1 christos {"no-default-excludes", no_argument, NULL, OPTION_NO_DEFAULT_EXCLUDES},
592 1.1 christos {"output-lib", required_argument, NULL, OPTION_OUTPUT_LIB},
593 1.1 christos {"def", required_argument, NULL, OPTION_DEF},
594 1.1 christos {"add-underscore", no_argument, NULL, 'U'},
595 1.1 christos {"killat", no_argument, NULL, 'k'},
596 1.1 christos {"add-stdcall-alias", no_argument, NULL, 'A'},
597 1.1 christos {"help", no_argument, NULL, 'h'},
598 1.1 christos {"machine", required_argument, NULL, OPTION_MACHINE},
599 1.1 christos {"add-indirect", no_argument, NULL, OPTION_ADD_INDIRECT},
600 1.1 christos {"base-file", required_argument, NULL, OPTION_BASE_FILE},
601 1.1 christos {"as", required_argument, NULL, OPTION_AS},
602 1.1 christos {0, 0, 0, 0}
603 1.1 christos };
604 1.1 christos
605 1.1 christos int main (int, char **);
606 1.1 christos
607 1.1 christos int
608 1.1 christos main (int argc, char **argv)
609 1.1 christos {
610 1.1 christos int c;
611 1.1 christos int i;
612 1.1 christos
613 1.1 christos char **saved_argv = 0;
614 1.1 christos int cmdline_len = 0;
615 1.1 christos
616 1.1 christos int export_all = 0;
617 1.1 christos
618 1.1 christos int *dlltool_arg_indices;
619 1.1 christos int *driver_arg_indices;
620 1.1 christos
621 1.1 christos char *driver_flags = 0;
622 1.1 christos char *output_lib_file_name = 0;
623 1.1 christos
624 1.1 christos dyn_string_t dlltool_cmdline;
625 1.1 christos dyn_string_t driver_cmdline;
626 1.1 christos
627 1.1 christos int def_file_seen = 0;
628 1.1 christos
629 1.1 christos char *image_base_str = 0;
630 1.1 christos
631 1.1 christos prog_name = argv[0];
632 1.1 christos
633 1.8 christos #ifdef HAVE_LC_MESSAGES
634 1.1 christos setlocale (LC_MESSAGES, "");
635 1.1 christos #endif
636 1.1 christos setlocale (LC_CTYPE, "");
637 1.1 christos bindtextdomain (PACKAGE, LOCALEDIR);
638 1.1 christos textdomain (PACKAGE);
639 1.1 christos
640 1.8 christos warn (_("WARNING: %s is deprecated, use gcc -shared or ld -shared instead\n"),
641 1.8 christos prog_name);
642 1.8 christos
643 1.1 christos expandargv (&argc, &argv);
644 1.1 christos
645 1.1 christos saved_argv = (char **) xmalloc (argc * sizeof (char*));
646 1.1 christos dlltool_arg_indices = (int *) xmalloc (argc * sizeof (int));
647 1.1 christos driver_arg_indices = (int *) xmalloc (argc * sizeof (int));
648 1.1 christos for (i = 0; i < argc; ++i)
649 1.1 christos {
650 1.1 christos size_t len = strlen (argv[i]);
651 1.1 christos char *arg = (char *) xmalloc (len + 1);
652 1.1 christos strcpy (arg, argv[i]);
653 1.1 christos cmdline_len += len;
654 1.1 christos saved_argv[i] = arg;
655 1.1 christos dlltool_arg_indices[i] = 0;
656 1.1 christos driver_arg_indices[i] = 1;
657 1.1 christos }
658 1.1 christos cmdline_len++;
659 1.1 christos
660 1.1 christos /* We recognize dllwrap and dlltool options, and everything else is
661 1.1 christos passed onto the language driver (eg., to GCC). We collect options
662 1.1 christos to dlltool and driver in dlltool_args and driver_args. */
663 1.1 christos
664 1.1 christos opterr = 0;
665 1.1 christos while ((c = getopt_long_only (argc, argv, "nkAqve:Uho:l:L:I:",
666 1.1 christos long_options, (int *) 0)) != EOF)
667 1.1 christos {
668 1.1 christos int dlltool_arg;
669 1.1 christos int driver_arg;
670 1.1 christos int single_word_option_value_pair;
671 1.1 christos
672 1.1 christos dlltool_arg = 0;
673 1.1 christos driver_arg = 1;
674 1.1 christos single_word_option_value_pair = 0;
675 1.1 christos
676 1.1 christos if (c != '?')
677 1.1 christos {
678 1.1 christos /* We recognize this option, so it has to be either dllwrap or
679 1.1 christos dlltool option. Do not pass to driver unless it's one of the
680 1.1 christos generic options that are passed to all the tools (such as -v)
681 1.1 christos which are dealt with later. */
682 1.1 christos driver_arg = 0;
683 1.1 christos }
684 1.1 christos
685 1.1 christos /* deal with generic and dllwrap options first. */
686 1.1 christos switch (c)
687 1.1 christos {
688 1.1 christos case 'h':
689 1.1 christos usage (stdout, 0);
690 1.1 christos break;
691 1.1 christos case 'q':
692 1.1 christos verbose = 0;
693 1.1 christos break;
694 1.1 christos case 'v':
695 1.1 christos verbose = 1;
696 1.1 christos break;
697 1.1 christos case OPTION_VERSION:
698 1.1 christos print_version (prog_name);
699 1.1 christos break;
700 1.1 christos case 'e':
701 1.1 christos entry_point = optarg;
702 1.1 christos break;
703 1.1 christos case OPTION_IMAGE_BASE:
704 1.1 christos image_base_str = optarg;
705 1.1 christos break;
706 1.1 christos case OPTION_DEF:
707 1.1 christos def_file_name = optarg;
708 1.1 christos def_file_seen = 1;
709 1.1 christos delete_def_file = 0;
710 1.1 christos break;
711 1.1 christos case 'n':
712 1.1 christos dontdeltemps = 1;
713 1.1 christos dlltool_arg = 1;
714 1.1 christos break;
715 1.1 christos case 'o':
716 1.1 christos dll_file_name = optarg;
717 1.1 christos break;
718 1.1 christos case 'I':
719 1.1 christos case 'l':
720 1.1 christos case 'L':
721 1.1 christos driver_arg = 1;
722 1.1 christos break;
723 1.1 christos case OPTION_DLLNAME:
724 1.1 christos dll_name = optarg;
725 1.1 christos break;
726 1.1 christos case OPTION_DRY_RUN:
727 1.1 christos dry_run = 1;
728 1.1 christos break;
729 1.1 christos case OPTION_DRIVER_NAME:
730 1.1 christos driver_name = optarg;
731 1.1 christos break;
732 1.1 christos case OPTION_DRIVER_FLAGS:
733 1.1 christos driver_flags = optarg;
734 1.1 christos break;
735 1.1 christos case OPTION_DLLTOOL_NAME:
736 1.1 christos dlltool_name = optarg;
737 1.1 christos break;
738 1.1 christos case OPTION_TARGET:
739 1.1 christos target = optarg;
740 1.1 christos break;
741 1.1 christos case OPTION_MNO_CYGWIN:
742 1.1 christos target = "i386-mingw32";
743 1.1 christos break;
744 1.1 christos case OPTION_NO_LEADING_UNDERSCORE:
745 1.1 christos is_leading_underscore = 0;
746 1.1 christos break;
747 1.1 christos case OPTION_LEADING_UNDERSCORE:
748 1.1 christos is_leading_underscore = 1;
749 1.1 christos break;
750 1.1 christos case OPTION_BASE_FILE:
751 1.1 christos base_file_name = optarg;
752 1.1 christos delete_base_file = 0;
753 1.1 christos break;
754 1.1 christos case OPTION_OUTPUT_EXP:
755 1.1 christos exp_file_name = optarg;
756 1.1 christos delete_exp_file = 0;
757 1.1 christos break;
758 1.1 christos case OPTION_EXPORT_ALL_SYMS:
759 1.1 christos export_all = 1;
760 1.1 christos break;
761 1.1 christos case OPTION_OUTPUT_LIB:
762 1.1 christos output_lib_file_name = optarg;
763 1.1 christos break;
764 1.1 christos case '?':
765 1.1 christos break;
766 1.1 christos default:
767 1.1 christos dlltool_arg = 1;
768 1.1 christos break;
769 1.1 christos }
770 1.1 christos
771 1.1 christos /* Handle passing through --option=value case. */
772 1.1 christos if (optarg
773 1.1 christos && saved_argv[optind-1][0] == '-'
774 1.1 christos && saved_argv[optind-1][1] == '-'
775 1.1 christos && strchr (saved_argv[optind-1], '='))
776 1.1 christos single_word_option_value_pair = 1;
777 1.1 christos
778 1.1 christos if (dlltool_arg)
779 1.1 christos {
780 1.1 christos dlltool_arg_indices[optind-1] = 1;
781 1.1 christos if (optarg && ! single_word_option_value_pair)
782 1.1 christos {
783 1.1 christos dlltool_arg_indices[optind-2] = 1;
784 1.1 christos }
785 1.1 christos }
786 1.1 christos
787 1.1 christos if (! driver_arg)
788 1.1 christos {
789 1.1 christos driver_arg_indices[optind-1] = 0;
790 1.1 christos if (optarg && ! single_word_option_value_pair)
791 1.1 christos {
792 1.1 christos driver_arg_indices[optind-2] = 0;
793 1.1 christos }
794 1.1 christos }
795 1.1 christos }
796 1.1 christos
797 1.1 christos /* Sanity checks. */
798 1.1 christos if (! dll_name && ! dll_file_name)
799 1.1 christos {
800 1.1 christos warn (_("Must provide at least one of -o or --dllname options"));
801 1.1 christos exit (1);
802 1.1 christos }
803 1.1 christos else if (! dll_name)
804 1.1 christos {
805 1.1 christos dll_name = xstrdup (mybasename (dll_file_name));
806 1.1 christos }
807 1.1 christos else if (! dll_file_name)
808 1.1 christos {
809 1.1 christos dll_file_name = xstrdup (dll_name);
810 1.1 christos }
811 1.1 christos
812 1.1 christos /* Deduce driver-name and dlltool-name from our own. */
813 1.1 christos if (driver_name == NULL)
814 1.1 christos driver_name = deduce_name ("gcc");
815 1.1 christos
816 1.1 christos if (dlltool_name == NULL)
817 1.1 christos dlltool_name = deduce_name ("dlltool");
818 1.1 christos
819 1.1 christos if (! def_file_seen)
820 1.1 christos {
821 1.9 christos char *fileprefix = make_temp_file (NULL);
822 1.1 christos
823 1.1 christos def_file_name = (char *) xmalloc (strlen (fileprefix) + 5);
824 1.1 christos sprintf (def_file_name, "%s.def",
825 1.1 christos (dontdeltemps) ? mybasename (fileprefix) : fileprefix);
826 1.1 christos delete_def_file = 1;
827 1.1 christos free (fileprefix);
828 1.1 christos delete_def_file = 1;
829 1.1 christos warn (_("no export definition file provided.\n\
830 1.1 christos Creating one, but that may not be what you want"));
831 1.1 christos }
832 1.1 christos
833 1.1 christos /* Set the target platform. */
834 1.1 christos if (strstr (target, "cygwin"))
835 1.1 christos which_target = CYGWIN_TARGET;
836 1.1 christos else if (strstr (target, "mingw"))
837 1.1 christos which_target = MINGW_TARGET;
838 1.1 christos else
839 1.1 christos which_target = UNKNOWN_TARGET;
840 1.1 christos
841 1.8 christos if (startswith (target, "arm"))
842 1.1 christos which_cpu = ARM_CPU;
843 1.8 christos else if (startswith (target, "x86_64")
844 1.8 christos || startswith (target, "athlon64")
845 1.8 christos || startswith (target, "amd64"))
846 1.1 christos which_cpu = X64_CPU;
847 1.1 christos else if (target[0] == 'i' && (target[1] >= '3' && target[1] <= '6')
848 1.1 christos && target[2] == '8' && target[3] == '6')
849 1.1 christos which_cpu = X86_CPU;
850 1.1 christos else
851 1.1 christos which_cpu = UNKNOWN_CPU;
852 1.1 christos
853 1.1 christos if (is_leading_underscore == -1)
854 1.1 christos is_leading_underscore = (which_cpu != X64_CPU && which_cpu != ARM_CPU);
855 1.1 christos
856 1.1 christos /* Re-create the command lines as a string, taking care to quote stuff. */
857 1.1 christos dlltool_cmdline = dyn_string_new (cmdline_len);
858 1.1 christos if (verbose)
859 1.1 christos dyn_string_append_cstr (dlltool_cmdline, " -v");
860 1.1 christos
861 1.1 christos dyn_string_append_cstr (dlltool_cmdline, " --dllname ");
862 1.1 christos dyn_string_append_cstr (dlltool_cmdline, dll_name);
863 1.1 christos
864 1.1 christos for (i = 1; i < argc; ++i)
865 1.1 christos {
866 1.1 christos if (dlltool_arg_indices[i])
867 1.1 christos {
868 1.1 christos char *arg = saved_argv[i];
869 1.1 christos int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
870 1.1 christos dyn_string_append_cstr (dlltool_cmdline,
871 1.1 christos (quote) ? " \"" : " ");
872 1.1 christos dyn_string_append_cstr (dlltool_cmdline, arg);
873 1.1 christos dyn_string_append_cstr (dlltool_cmdline,
874 1.1 christos (quote) ? "\"" : "");
875 1.1 christos }
876 1.1 christos }
877 1.1 christos
878 1.1 christos driver_cmdline = dyn_string_new (cmdline_len);
879 1.1 christos if (! driver_flags || strlen (driver_flags) == 0)
880 1.1 christos {
881 1.1 christos switch (which_target)
882 1.1 christos {
883 1.1 christos case CYGWIN_TARGET:
884 1.1 christos driver_flags = cygwin_driver_flags;
885 1.1 christos break;
886 1.1 christos
887 1.1 christos case MINGW_TARGET:
888 1.1 christos driver_flags = mingw32_driver_flags;
889 1.1 christos break;
890 1.1 christos
891 1.1 christos default:
892 1.1 christos driver_flags = generic_driver_flags;
893 1.1 christos break;
894 1.1 christos }
895 1.1 christos }
896 1.1 christos dyn_string_append_cstr (driver_cmdline, driver_flags);
897 1.1 christos dyn_string_append_cstr (driver_cmdline, " -o ");
898 1.1 christos dyn_string_append_cstr (driver_cmdline, dll_file_name);
899 1.1 christos
900 1.1 christos if (is_leading_underscore == 0)
901 1.1 christos dyn_string_append_cstr (driver_cmdline, " --no-leading-underscore");
902 1.1 christos else if (is_leading_underscore == 1)
903 1.1 christos dyn_string_append_cstr (driver_cmdline, " --leading-underscore");
904 1.1 christos
905 1.1 christos if (! entry_point || strlen (entry_point) == 0)
906 1.1 christos {
907 1.1 christos const char *prefix = (is_leading_underscore != 0 ? "_" : "");
908 1.1 christos const char *postfix = "";
909 1.1 christos const char *name_entry;
910 1.1 christos
911 1.1 christos if (which_cpu == X86_CPU || which_cpu == UNKNOWN_CPU)
912 1.1 christos postfix = "@12";
913 1.1 christos
914 1.1 christos switch (which_target)
915 1.1 christos {
916 1.1 christos case CYGWIN_TARGET:
917 1.1 christos name_entry = "_cygwin_dll_entry";
918 1.1 christos break;
919 1.1 christos
920 1.1 christos case MINGW_TARGET:
921 1.1 christos name_entry = "DllMainCRTStartup";
922 1.1 christos break;
923 1.1 christos
924 1.1 christos default:
925 1.1 christos name_entry = "DllMain";
926 1.1 christos break;
927 1.1 christos }
928 1.1 christos entry_point =
929 1.1 christos (char *) malloc (strlen (name_entry) + strlen (prefix)
930 1.1 christos + strlen (postfix) + 1);
931 1.1 christos sprintf (entry_point, "%s%s%s", prefix, name_entry, postfix);
932 1.1 christos }
933 1.1 christos dyn_string_append_cstr (driver_cmdline, " -Wl,-e,");
934 1.1 christos dyn_string_append_cstr (driver_cmdline, entry_point);
935 1.1 christos dyn_string_append_cstr (dlltool_cmdline, " --exclude-symbol=");
936 1.1 christos dyn_string_append_cstr (dlltool_cmdline,
937 1.1 christos (entry_point[0] == '_') ? entry_point+1 : entry_point);
938 1.1 christos
939 1.1 christos if (! image_base_str || strlen (image_base_str) == 0)
940 1.1 christos {
941 1.1 christos char *tmpbuf = (char *) xmalloc (sizeof ("0x12345678") + 1);
942 1.1 christos unsigned long hash = strhash (dll_file_name);
943 1.1 christos sprintf (tmpbuf, "0x%.8lX", 0x60000000|((hash<<16)&0xFFC0000));
944 1.1 christos image_base_str = tmpbuf;
945 1.1 christos }
946 1.1 christos
947 1.1 christos dyn_string_append_cstr (driver_cmdline, " -Wl,--image-base,");
948 1.1 christos dyn_string_append_cstr (driver_cmdline, image_base_str);
949 1.1 christos
950 1.1 christos if (verbose)
951 1.1 christos {
952 1.1 christos dyn_string_append_cstr (driver_cmdline, " -v");
953 1.1 christos }
954 1.1 christos
955 1.1 christos for (i = 1; i < argc; ++i)
956 1.1 christos {
957 1.1 christos if (driver_arg_indices[i])
958 1.1 christos {
959 1.1 christos char *arg = saved_argv[i];
960 1.1 christos int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
961 1.1 christos dyn_string_append_cstr (driver_cmdline,
962 1.1 christos (quote) ? " \"" : " ");
963 1.1 christos dyn_string_append_cstr (driver_cmdline, arg);
964 1.1 christos dyn_string_append_cstr (driver_cmdline,
965 1.1 christos (quote) ? "\"" : "");
966 1.1 christos }
967 1.1 christos }
968 1.1 christos
969 1.1 christos /* Step pre-1. If no --def <EXPORT_DEF> is specified,
970 1.1 christos then create it and then pass it on. */
971 1.1 christos
972 1.1 christos if (! def_file_seen)
973 1.1 christos {
974 1.1 christos dyn_string_t step_pre1;
975 1.1 christos
976 1.1 christos step_pre1 = dyn_string_new (1024);
977 1.1 christos
978 1.1 christos dyn_string_append_cstr (step_pre1, dlltool_cmdline->s);
979 1.1 christos if (export_all)
980 1.1 christos {
981 1.1 christos dyn_string_append_cstr (step_pre1, " --export-all --exclude-symbol=");
982 1.1 christos dyn_string_append_cstr (step_pre1,
983 1.1 christos "_cygwin_dll_entry@12,DllMainCRTStartup@12,DllMain@12,DllEntryPoint@12");
984 1.1 christos }
985 1.1 christos dyn_string_append_cstr (step_pre1, " --output-def ");
986 1.1 christos dyn_string_append_cstr (step_pre1, def_file_name);
987 1.1 christos
988 1.1 christos for (i = 1; i < argc; ++i)
989 1.1 christos {
990 1.1 christos if (driver_arg_indices[i])
991 1.1 christos {
992 1.1 christos char *arg = saved_argv[i];
993 1.1 christos size_t len = strlen (arg);
994 1.1 christos if (len >= 2 && arg[len-2] == '.'
995 1.1 christos && (arg[len-1] == 'o' || arg[len-1] == 'a'))
996 1.1 christos {
997 1.1 christos int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
998 1.1 christos dyn_string_append_cstr (step_pre1,
999 1.1 christos (quote) ? " \"" : " ");
1000 1.1 christos dyn_string_append_cstr (step_pre1, arg);
1001 1.1 christos dyn_string_append_cstr (step_pre1,
1002 1.1 christos (quote) ? "\"" : "");
1003 1.1 christos }
1004 1.1 christos }
1005 1.1 christos }
1006 1.1 christos
1007 1.1 christos if (run (dlltool_name, step_pre1->s))
1008 1.1 christos cleanup_and_exit (1);
1009 1.1 christos
1010 1.1 christos dyn_string_delete (step_pre1);
1011 1.1 christos }
1012 1.1 christos
1013 1.1 christos dyn_string_append_cstr (dlltool_cmdline, " --def ");
1014 1.1 christos dyn_string_append_cstr (dlltool_cmdline, def_file_name);
1015 1.1 christos
1016 1.1 christos if (verbose)
1017 1.1 christos {
1018 1.1 christos fprintf (stderr, _("DLLTOOL name : %s\n"), dlltool_name);
1019 1.1 christos fprintf (stderr, _("DLLTOOL options : %s\n"), dlltool_cmdline->s);
1020 1.1 christos fprintf (stderr, _("DRIVER name : %s\n"), driver_name);
1021 1.1 christos fprintf (stderr, _("DRIVER options : %s\n"), driver_cmdline->s);
1022 1.1 christos }
1023 1.1 christos
1024 1.1 christos /* Step 1. Call GCC/LD to create base relocation file. If using GCC, the
1025 1.1 christos driver command line will look like the following:
1026 1.3 christos
1027 1.1 christos % gcc -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
1028 1.3 christos
1029 1.1 christos If the user does not specify a base name, create temporary one that
1030 1.1 christos is deleted at exit. */
1031 1.1 christos
1032 1.1 christos if (! base_file_name)
1033 1.1 christos {
1034 1.9 christos char *fileprefix = make_temp_file (NULL);
1035 1.1 christos base_file_name = (char *) xmalloc (strlen (fileprefix) + 6);
1036 1.1 christos sprintf (base_file_name, "%s.base",
1037 1.1 christos (dontdeltemps) ? mybasename (fileprefix) : fileprefix);
1038 1.1 christos delete_base_file = 1;
1039 1.1 christos free (fileprefix);
1040 1.1 christos }
1041 1.1 christos
1042 1.1 christos {
1043 1.1 christos int quote;
1044 1.1 christos
1045 1.1 christos dyn_string_t step1 = dyn_string_new (driver_cmdline->length
1046 1.1 christos + strlen (base_file_name)
1047 1.1 christos + 20);
1048 1.1 christos dyn_string_append_cstr (step1, "-Wl,--base-file,");
1049 1.1 christos quote = (strchr (base_file_name, ' ')
1050 1.1 christos || strchr (base_file_name, '\t'));
1051 1.1 christos dyn_string_append_cstr (step1,
1052 1.1 christos (quote) ? "\"" : "");
1053 1.1 christos dyn_string_append_cstr (step1, base_file_name);
1054 1.1 christos dyn_string_append_cstr (step1,
1055 1.1 christos (quote) ? "\"" : "");
1056 1.1 christos if (driver_cmdline->length)
1057 1.1 christos {
1058 1.1 christos dyn_string_append_cstr (step1, " ");
1059 1.1 christos dyn_string_append_cstr (step1, driver_cmdline->s);
1060 1.1 christos }
1061 1.1 christos
1062 1.1 christos if (run (driver_name, step1->s))
1063 1.1 christos cleanup_and_exit (1);
1064 1.1 christos
1065 1.1 christos dyn_string_delete (step1);
1066 1.1 christos }
1067 1.1 christos
1068 1.1 christos /* Step 2. generate the exp file by running dlltool.
1069 1.1 christos dlltool command line will look like the following:
1070 1.3 christos
1071 1.1 christos % dlltool -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
1072 1.3 christos
1073 1.1 christos If the user does not specify a base name, create temporary one that
1074 1.1 christos is deleted at exit. */
1075 1.1 christos
1076 1.1 christos if (! exp_file_name)
1077 1.1 christos {
1078 1.1 christos char *p = strrchr (dll_name, '.');
1079 1.1 christos size_t prefix_len = (p) ? (size_t) (p - dll_name) : strlen (dll_name);
1080 1.1 christos
1081 1.1 christos exp_file_name = (char *) xmalloc (prefix_len + 4 + 1);
1082 1.1 christos strncpy (exp_file_name, dll_name, prefix_len);
1083 1.1 christos exp_file_name[prefix_len] = '\0';
1084 1.1 christos strcat (exp_file_name, ".exp");
1085 1.1 christos delete_exp_file = 1;
1086 1.1 christos }
1087 1.1 christos
1088 1.1 christos {
1089 1.1 christos int quote;
1090 1.1 christos
1091 1.1 christos dyn_string_t step2 = dyn_string_new (dlltool_cmdline->length
1092 1.1 christos + strlen (base_file_name)
1093 1.1 christos + strlen (exp_file_name)
1094 1.1 christos + 20);
1095 1.1 christos
1096 1.1 christos dyn_string_append_cstr (step2, "--base-file ");
1097 1.1 christos quote = (strchr (base_file_name, ' ')
1098 1.1 christos || strchr (base_file_name, '\t'));
1099 1.1 christos dyn_string_append_cstr (step2,
1100 1.1 christos (quote) ? "\"" : "");
1101 1.1 christos dyn_string_append_cstr (step2, base_file_name);
1102 1.1 christos dyn_string_append_cstr (step2,
1103 1.1 christos (quote) ? "\" " : " ");
1104 1.1 christos
1105 1.1 christos dyn_string_append_cstr (step2, "--output-exp ");
1106 1.1 christos quote = (strchr (exp_file_name, ' ')
1107 1.1 christos || strchr (exp_file_name, '\t'));
1108 1.1 christos dyn_string_append_cstr (step2,
1109 1.1 christos (quote) ? "\"" : "");
1110 1.1 christos dyn_string_append_cstr (step2, exp_file_name);
1111 1.1 christos dyn_string_append_cstr (step2,
1112 1.1 christos (quote) ? "\"" : "");
1113 1.1 christos
1114 1.1 christos if (dlltool_cmdline->length)
1115 1.1 christos {
1116 1.1 christos dyn_string_append_cstr (step2, " ");
1117 1.1 christos dyn_string_append_cstr (step2, dlltool_cmdline->s);
1118 1.1 christos }
1119 1.1 christos
1120 1.1 christos if (run (dlltool_name, step2->s))
1121 1.1 christos cleanup_and_exit (1);
1122 1.1 christos
1123 1.1 christos dyn_string_delete (step2);
1124 1.1 christos }
1125 1.1 christos
1126 1.1 christos /*
1127 1.1 christos * Step 3. Call GCC/LD to again, adding the exp file this time.
1128 1.1 christos * driver command line will look like the following:
1129 1.1 christos *
1130 1.1 christos * % gcc -Wl,--dll --Wl,--base-file,foo.base foo.exp [rest ...]
1131 1.1 christos */
1132 1.1 christos
1133 1.1 christos {
1134 1.1 christos int quote;
1135 1.1 christos
1136 1.1 christos dyn_string_t step3 = dyn_string_new (driver_cmdline->length
1137 1.1 christos + strlen (exp_file_name)
1138 1.1 christos + strlen (base_file_name)
1139 1.1 christos + 20);
1140 1.1 christos dyn_string_append_cstr (step3, "-Wl,--base-file,");
1141 1.1 christos quote = (strchr (base_file_name, ' ')
1142 1.1 christos || strchr (base_file_name, '\t'));
1143 1.1 christos dyn_string_append_cstr (step3,
1144 1.1 christos (quote) ? "\"" : "");
1145 1.1 christos dyn_string_append_cstr (step3, base_file_name);
1146 1.1 christos dyn_string_append_cstr (step3,
1147 1.1 christos (quote) ? "\" " : " ");
1148 1.1 christos
1149 1.1 christos quote = (strchr (exp_file_name, ' ')
1150 1.1 christos || strchr (exp_file_name, '\t'));
1151 1.1 christos dyn_string_append_cstr (step3,
1152 1.1 christos (quote) ? "\"" : "");
1153 1.1 christos dyn_string_append_cstr (step3, exp_file_name);
1154 1.1 christos dyn_string_append_cstr (step3,
1155 1.1 christos (quote) ? "\"" : "");
1156 1.1 christos
1157 1.1 christos if (driver_cmdline->length)
1158 1.1 christos {
1159 1.1 christos dyn_string_append_cstr (step3, " ");
1160 1.1 christos dyn_string_append_cstr (step3, driver_cmdline->s);
1161 1.1 christos }
1162 1.1 christos
1163 1.1 christos if (run (driver_name, step3->s))
1164 1.1 christos cleanup_and_exit (1);
1165 1.1 christos
1166 1.1 christos dyn_string_delete (step3);
1167 1.1 christos }
1168 1.1 christos
1169 1.1 christos
1170 1.1 christos /*
1171 1.1 christos * Step 4. Run DLLTOOL again using the same command line.
1172 1.1 christos */
1173 1.1 christos
1174 1.1 christos {
1175 1.1 christos int quote;
1176 1.1 christos dyn_string_t step4 = dyn_string_new (dlltool_cmdline->length
1177 1.1 christos + strlen (base_file_name)
1178 1.1 christos + strlen (exp_file_name)
1179 1.1 christos + 20);
1180 1.1 christos
1181 1.1 christos dyn_string_append_cstr (step4, "--base-file ");
1182 1.1 christos quote = (strchr (base_file_name, ' ')
1183 1.1 christos || strchr (base_file_name, '\t'));
1184 1.1 christos dyn_string_append_cstr (step4,
1185 1.1 christos (quote) ? "\"" : "");
1186 1.1 christos dyn_string_append_cstr (step4, base_file_name);
1187 1.1 christos dyn_string_append_cstr (step4,
1188 1.1 christos (quote) ? "\" " : " ");
1189 1.1 christos
1190 1.1 christos dyn_string_append_cstr (step4, "--output-exp ");
1191 1.1 christos quote = (strchr (exp_file_name, ' ')
1192 1.1 christos || strchr (exp_file_name, '\t'));
1193 1.1 christos dyn_string_append_cstr (step4,
1194 1.1 christos (quote) ? "\"" : "");
1195 1.1 christos dyn_string_append_cstr (step4, exp_file_name);
1196 1.1 christos dyn_string_append_cstr (step4,
1197 1.1 christos (quote) ? "\"" : "");
1198 1.1 christos
1199 1.1 christos if (dlltool_cmdline->length)
1200 1.1 christos {
1201 1.1 christos dyn_string_append_cstr (step4, " ");
1202 1.1 christos dyn_string_append_cstr (step4, dlltool_cmdline->s);
1203 1.1 christos }
1204 1.1 christos
1205 1.1 christos if (output_lib_file_name)
1206 1.1 christos {
1207 1.1 christos dyn_string_append_cstr (step4, " --output-lib ");
1208 1.1 christos dyn_string_append_cstr (step4, output_lib_file_name);
1209 1.1 christos }
1210 1.1 christos
1211 1.1 christos if (run (dlltool_name, step4->s))
1212 1.1 christos cleanup_and_exit (1);
1213 1.1 christos
1214 1.1 christos dyn_string_delete (step4);
1215 1.1 christos }
1216 1.1 christos
1217 1.1 christos
1218 1.1 christos /*
1219 1.1 christos * Step 5. Link it all together and be done with it.
1220 1.1 christos * driver command line will look like the following:
1221 1.1 christos *
1222 1.1 christos * % gcc -Wl,--dll foo.exp [rest ...]
1223 1.1 christos *
1224 1.1 christos */
1225 1.1 christos
1226 1.1 christos {
1227 1.1 christos int quote;
1228 1.1 christos
1229 1.1 christos dyn_string_t step5 = dyn_string_new (driver_cmdline->length
1230 1.1 christos + strlen (exp_file_name)
1231 1.1 christos + 20);
1232 1.1 christos quote = (strchr (exp_file_name, ' ')
1233 1.1 christos || strchr (exp_file_name, '\t'));
1234 1.1 christos dyn_string_append_cstr (step5,
1235 1.1 christos (quote) ? "\"" : "");
1236 1.1 christos dyn_string_append_cstr (step5, exp_file_name);
1237 1.1 christos dyn_string_append_cstr (step5,
1238 1.1 christos (quote) ? "\"" : "");
1239 1.1 christos
1240 1.1 christos if (driver_cmdline->length)
1241 1.1 christos {
1242 1.1 christos dyn_string_append_cstr (step5, " ");
1243 1.1 christos dyn_string_append_cstr (step5, driver_cmdline->s);
1244 1.1 christos }
1245 1.1 christos
1246 1.1 christos if (run (driver_name, step5->s))
1247 1.1 christos cleanup_and_exit (1);
1248 1.1 christos
1249 1.1 christos dyn_string_delete (step5);
1250 1.1 christos }
1251 1.1 christos
1252 1.1 christos cleanup_and_exit (0);
1253 1.1 christos
1254 1.1 christos return 0;
1255 1.1 christos }
1256