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