* bfd.c (struct bfd_preserve): New.
[binutils.git] / binutils / dllwrap.c
blob4ca59366a0291332f29ab60bff66aa8024b005b5
1 /* dllwrap.c -- wrapper for DLLTOOL and GCC to generate PE style DLLs
2 Copyright 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
3 Contributed by Mumit Khan (khan@xraylith.wisc.edu).
5 This file is part of GNU Binutils.
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.
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.
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., 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA. */
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
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
33 #include "bfd.h"
34 #include "libiberty.h"
35 #include "bucomm.h"
36 #include "getopt.h"
37 #include "dyn-string.h"
39 #include <time.h>
40 #include <sys/stat.h>
42 #ifdef ANSI_PROTOTYPES
43 #include <stdarg.h>
44 #else
45 #include <varargs.h>
46 #endif
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 */
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";
86 static char *entry_point;
88 static char *dlltool_name = NULL;
90 static char *target = TARGET;
92 typedef enum {
93 UNKNOWN_TARGET,
94 CYGWIN_TARGET,
95 MINGW_TARGET
97 target_type;
99 static target_type which_target = UNKNOWN_TARGET;
101 static int dontdeltemps = 0;
102 static int dry_run = 0;
104 static char *program_name;
106 static int verbose = 0;
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;
117 static int run PARAMS ((const char *, char *));
118 static char *mybasename PARAMS ((const char *));
119 static int strhash PARAMS ((const char *));
120 static void usage PARAMS ((FILE *, int));
121 static void display PARAMS ((const char *, va_list));
122 static void inform PARAMS ((const char *, ...));
123 static void warn PARAMS ((const char *, ...));
124 static char *look_for_prog PARAMS ((const char *, const char *, int));
125 static char *deduce_name PARAMS ((const char *));
126 static void delete_temp_files PARAMS ((void));
127 static void cleanup_and_exit PARAMS ((int));
129 /**********************************************************************/
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. */
139 static void
140 display (message, args)
141 const char * message;
142 va_list args;
144 if (program_name != NULL)
145 fprintf (stderr, "%s: ", program_name);
147 vfprintf (stderr, message, args);
148 fputc ('\n', stderr);
152 static void
153 inform VPARAMS ((const char *message, ...))
155 VA_OPEN (args, message);
156 VA_FIXEDARG (args, const char *, message);
158 if (!verbose)
159 return;
161 display (message, args);
163 VA_CLOSE (args);
166 static void
167 warn VPARAMS ((const char *format, ...))
169 VA_OPEN (args, format);
170 VA_FIXEDARG (args, const char *, format);
172 display (format, args);
174 VA_CLOSE (args);
177 /* Look for the program formed by concatenating PROG_NAME and the
178 string running from PREFIX to END_PREFIX. If the concatenated
179 string contains a '/', try appending EXECUTABLE_SUFFIX if it is
180 appropriate. */
182 static char *
183 look_for_prog (prog_name, prefix, end_prefix)
184 const char *prog_name;
185 const char *prefix;
186 int end_prefix;
188 struct stat s;
189 char *cmd;
191 cmd = xmalloc (strlen (prefix)
192 + strlen (prog_name)
193 #ifdef HAVE_EXECUTABLE_SUFFIX
194 + strlen (EXECUTABLE_SUFFIX)
195 #endif
196 + 10);
197 strcpy (cmd, prefix);
199 sprintf (cmd + end_prefix, "%s", prog_name);
201 if (strchr (cmd, '/') != NULL)
203 int found;
205 found = (stat (cmd, &s) == 0
206 #ifdef HAVE_EXECUTABLE_SUFFIX
207 || stat (strcat (cmd, EXECUTABLE_SUFFIX), &s) == 0
208 #endif
211 if (! found)
213 /* xgettext:c-format */
214 inform (_("Tried file: %s"), cmd);
215 free (cmd);
216 return NULL;
220 /* xgettext:c-format */
221 inform (_("Using file: %s"), cmd);
223 return cmd;
226 /* Deduce the name of the program we are want to invoke.
227 PROG_NAME is the basic name of the program we want to run,
228 eg "as" or "ld". The catch is that we might want actually
229 run "i386-pe-as" or "ppc-pe-ld".
231 If argv[0] contains the full path, then try to find the program
232 in the same place, with and then without a target-like prefix.
234 Given, argv[0] = /usr/local/bin/i586-cygwin32-dlltool,
235 deduce_name("as") uses the following search order:
237 /usr/local/bin/i586-cygwin32-as
238 /usr/local/bin/as
241 If there's an EXECUTABLE_SUFFIX, it'll use that as well; for each
242 name, it'll try without and then with EXECUTABLE_SUFFIX.
244 Given, argv[0] = i586-cygwin32-dlltool, it will not even try "as"
245 as the fallback, but rather return i586-cygwin32-as.
247 Oh, and given, argv[0] = dlltool, it'll return "as".
249 Returns a dynamically allocated string. */
251 static char *
252 deduce_name (prog_name)
253 const char *prog_name;
255 char *cmd;
256 char *dash, *slash, *cp;
258 dash = NULL;
259 slash = NULL;
260 for (cp = program_name; *cp != '\0'; ++cp)
262 if (*cp == '-')
263 dash = cp;
264 if (
265 #if defined(__DJGPP__) || defined (__CYGWIN__) || defined(__WIN32__)
266 *cp == ':' || *cp == '\\' ||
267 #endif
268 *cp == '/')
270 slash = cp;
271 dash = NULL;
275 cmd = NULL;
277 if (dash != NULL)
279 /* First, try looking for a prefixed PROG_NAME in the
280 PROGRAM_NAME directory, with the same prefix as PROGRAM_NAME. */
281 cmd = look_for_prog (prog_name, program_name, dash - program_name + 1);
284 if (slash != NULL && cmd == NULL)
286 /* Next, try looking for a PROG_NAME in the same directory as
287 that of this program. */
288 cmd = look_for_prog (prog_name, program_name, slash - program_name + 1);
291 if (cmd == NULL)
293 /* Just return PROG_NAME as is. */
294 cmd = xstrdup (prog_name);
297 return cmd;
300 static void
301 delete_temp_files ()
303 if (delete_base_file && base_file_name)
305 if (verbose)
307 if (dontdeltemps)
308 warn (_("Keeping temporary base file %s"), base_file_name);
309 else
310 warn (_("Deleting temporary base file %s"), base_file_name);
312 if (! dontdeltemps)
314 unlink (base_file_name);
315 free (base_file_name);
319 if (delete_exp_file && exp_file_name)
321 if (verbose)
323 if (dontdeltemps)
324 warn (_("Keeping temporary exp file %s"), exp_file_name);
325 else
326 warn (_("Deleting temporary exp file %s"), exp_file_name);
328 if (! dontdeltemps)
330 unlink (exp_file_name);
331 free (exp_file_name);
334 if (delete_def_file && def_file_name)
336 if (verbose)
338 if (dontdeltemps)
339 warn (_("Keeping temporary def file %s"), def_file_name);
340 else
341 warn (_("Deleting temporary def file %s"), def_file_name);
343 if (! dontdeltemps)
345 unlink (def_file_name);
346 free (def_file_name);
351 static void
352 cleanup_and_exit (status)
353 int status;
355 delete_temp_files ();
356 exit (status);
359 static int
360 run (what, args)
361 const char *what;
362 char *args;
364 char *s;
365 int pid, wait_status, retcode;
366 int i;
367 const char **argv;
368 char *errmsg_fmt, *errmsg_arg;
369 char *temp_base = choose_temp_base ();
370 int in_quote;
371 char sep;
373 if (verbose || dry_run)
374 fprintf (stderr, "%s %s\n", what, args);
376 /* Count the args */
377 i = 0;
378 for (s = args; *s; s++)
379 if (*s == ' ')
380 i++;
381 i++;
382 argv = alloca (sizeof (char *) * (i + 3));
383 i = 0;
384 argv[i++] = what;
385 s = args;
386 while (1)
388 while (*s == ' ' && *s != 0)
389 s++;
390 if (*s == 0)
391 break;
392 in_quote = (*s == '\'' || *s == '"');
393 sep = (in_quote) ? *s++ : ' ';
394 argv[i++] = s;
395 while (*s != sep && *s != 0)
396 s++;
397 if (*s == 0)
398 break;
399 *s++ = 0;
400 if (in_quote)
401 s++;
403 argv[i++] = NULL;
405 if (dry_run)
406 return 0;
408 pid = pexecute (argv[0], (char * const *) argv, program_name, temp_base,
409 &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
411 if (pid == -1)
413 int errno_val = errno;
415 fprintf (stderr, "%s: ", program_name);
416 fprintf (stderr, errmsg_fmt, errmsg_arg);
417 fprintf (stderr, ": %s\n", strerror (errno_val));
418 return 1;
421 retcode = 0;
422 pid = pwait (pid, &wait_status, 0);
423 if (pid == -1)
425 warn ("wait: %s", strerror (errno));
426 retcode = 1;
428 else if (WIFSIGNALED (wait_status))
430 warn (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
431 retcode = 1;
433 else if (WIFEXITED (wait_status))
435 if (WEXITSTATUS (wait_status) != 0)
437 warn (_("%s exited with status %d"), what, WEXITSTATUS (wait_status));
438 retcode = 1;
441 else
442 retcode = 1;
444 return retcode;
447 static char *
448 mybasename (name)
449 const char *name;
451 const char *base = name;
453 while (*name)
455 if (*name == '/' || *name == '\\')
457 base = name + 1;
459 ++name;
461 return (char *) base;
464 static int
465 strhash (str)
466 const char *str;
468 const unsigned char *s;
469 unsigned long hash;
470 unsigned int c;
471 unsigned int len;
473 hash = 0;
474 len = 0;
475 s = (const unsigned char *) str;
476 while ((c = *s++) != '\0')
478 hash += c + (c << 17);
479 hash ^= hash >> 2;
480 ++len;
482 hash += len + (len << 17);
483 hash ^= hash >> 2;
485 return hash;
488 /**********************************************************************/
490 static void
491 usage (file, status)
492 FILE *file;
493 int status;
495 fprintf (file, _("Usage %s <option(s)> <object-file(s)>\n"), program_name);
496 fprintf (file, _(" Generic options:\n"));
497 fprintf (file, _(" --quiet, -q Work quietly\n"));
498 fprintf (file, _(" --verbose, -v Verbose\n"));
499 fprintf (file, _(" --version Print dllwrap version\n"));
500 fprintf (file, _(" --implib <outname> Synonym for --output-lib\n"));
501 fprintf (file, _(" Options for %s:\n"), program_name);
502 fprintf (file, _(" --driver-name <driver> Defaults to \"gcc\"\n"));
503 fprintf (file, _(" --driver-flags <flags> Override default ld flags\n"));
504 fprintf (file, _(" --dlltool-name <dlltool> Defaults to \"dlltool\"\n"));
505 fprintf (file, _(" --entry <entry> Specify alternate DLL entry point\n"));
506 fprintf (file, _(" --image-base <base> Specify image base address\n"));
507 fprintf (file, _(" --target <machine> i386-cygwin32 or i386-mingw32\n"));
508 fprintf (file, _(" --dry-run Show what needs to be run\n"));
509 fprintf (file, _(" --mno-cygwin Create Mingw DLL\n"));
510 fprintf (file, _(" Options passed to DLLTOOL:\n"));
511 fprintf (file, _(" --machine <machine>\n"));
512 fprintf (file, _(" --output-exp <outname> Generate export file.\n"));
513 fprintf (file, _(" --output-lib <outname> Generate input library.\n"));
514 fprintf (file, _(" --add-indirect Add dll indirects to export file.\n"));
515 fprintf (file, _(" --dllname <name> Name of input dll to put into output lib.\n"));
516 fprintf (file, _(" --def <deffile> Name input .def file\n"));
517 fprintf (file, _(" --output-def <deffile> Name output .def file\n"));
518 fprintf (file, _(" --export-all-symbols Export all symbols to .def\n"));
519 fprintf (file, _(" --no-export-all-symbols Only export .drectve symbols\n"));
520 fprintf (file, _(" --exclude-symbols <list> Exclude <list> from .def\n"));
521 fprintf (file, _(" --no-default-excludes Zap default exclude symbols\n"));
522 fprintf (file, _(" --base-file <basefile> Read linker generated base file\n"));
523 fprintf (file, _(" --no-idata4 Don't generate idata$4 section\n"));
524 fprintf (file, _(" --no-idata5 Don't generate idata$5 section\n"));
525 fprintf (file, _(" -U Add underscores to .lib\n"));
526 fprintf (file, _(" -k Kill @<n> from exported names\n"));
527 fprintf (file, _(" --add-stdcall-alias Add aliases without @<n>\n"));
528 fprintf (file, _(" --as <name> Use <name> for assembler\n"));
529 fprintf (file, _(" --nodelete Keep temp files.\n"));
530 fprintf (file, _(" Rest are passed unmodified to the language driver\n"));
531 fprintf (file, "\n\n");
532 exit (status);
535 #define OPTION_START 149
537 /* GENERIC options. */
538 #define OPTION_QUIET (OPTION_START + 1)
539 #define OPTION_VERBOSE (OPTION_QUIET + 1)
540 #define OPTION_VERSION (OPTION_VERBOSE + 1)
542 /* DLLWRAP options. */
543 #define OPTION_DRY_RUN (OPTION_VERSION + 1)
544 #define OPTION_DRIVER_NAME (OPTION_DRY_RUN + 1)
545 #define OPTION_DRIVER_FLAGS (OPTION_DRIVER_NAME + 1)
546 #define OPTION_DLLTOOL_NAME (OPTION_DRIVER_FLAGS + 1)
547 #define OPTION_ENTRY (OPTION_DLLTOOL_NAME + 1)
548 #define OPTION_IMAGE_BASE (OPTION_ENTRY + 1)
549 #define OPTION_TARGET (OPTION_IMAGE_BASE + 1)
550 #define OPTION_MNO_CYGWIN (OPTION_TARGET + 1)
552 /* DLLTOOL options. */
553 #define OPTION_NODELETE (OPTION_MNO_CYGWIN + 1)
554 #define OPTION_DLLNAME (OPTION_NODELETE + 1)
555 #define OPTION_NO_IDATA4 (OPTION_DLLNAME + 1)
556 #define OPTION_NO_IDATA5 (OPTION_NO_IDATA4 + 1)
557 #define OPTION_OUTPUT_EXP (OPTION_NO_IDATA5 + 1)
558 #define OPTION_OUTPUT_DEF (OPTION_OUTPUT_EXP + 1)
559 #define OPTION_EXPORT_ALL_SYMS (OPTION_OUTPUT_DEF + 1)
560 #define OPTION_NO_EXPORT_ALL_SYMS (OPTION_EXPORT_ALL_SYMS + 1)
561 #define OPTION_EXCLUDE_SYMS (OPTION_NO_EXPORT_ALL_SYMS + 1)
562 #define OPTION_NO_DEFAULT_EXCLUDES (OPTION_EXCLUDE_SYMS + 1)
563 #define OPTION_OUTPUT_LIB (OPTION_NO_DEFAULT_EXCLUDES + 1)
564 #define OPTION_DEF (OPTION_OUTPUT_LIB + 1)
565 #define OPTION_ADD_UNDERSCORE (OPTION_DEF + 1)
566 #define OPTION_KILLAT (OPTION_ADD_UNDERSCORE + 1)
567 #define OPTION_HELP (OPTION_KILLAT + 1)
568 #define OPTION_MACHINE (OPTION_HELP + 1)
569 #define OPTION_ADD_INDIRECT (OPTION_MACHINE + 1)
570 #define OPTION_BASE_FILE (OPTION_ADD_INDIRECT + 1)
571 #define OPTION_AS (OPTION_BASE_FILE + 1)
573 static const struct option long_options[] =
575 /* generic options. */
576 {"quiet", no_argument, NULL, 'q'},
577 {"verbose", no_argument, NULL, 'v'},
578 {"version", no_argument, NULL, OPTION_VERSION},
579 {"implib", required_argument, NULL, OPTION_OUTPUT_LIB},
581 /* dllwrap options. */
582 {"dry-run", no_argument, NULL, OPTION_DRY_RUN},
583 {"driver-name", required_argument, NULL, OPTION_DRIVER_NAME},
584 {"driver-flags", required_argument, NULL, OPTION_DRIVER_FLAGS},
585 {"dlltool-name", required_argument, NULL, OPTION_DLLTOOL_NAME},
586 {"entry", required_argument, NULL, 'e'},
587 {"image-base", required_argument, NULL, OPTION_IMAGE_BASE},
588 {"target", required_argument, NULL, OPTION_TARGET},
590 /* dlltool options. */
591 {"no-delete", no_argument, NULL, 'n'},
592 {"dllname", required_argument, NULL, OPTION_DLLNAME},
593 {"no-idata4", no_argument, NULL, OPTION_NO_IDATA4},
594 {"no-idata5", no_argument, NULL, OPTION_NO_IDATA5},
595 {"output-exp", required_argument, NULL, OPTION_OUTPUT_EXP},
596 {"output-def", required_argument, NULL, OPTION_OUTPUT_DEF},
597 {"export-all-symbols", no_argument, NULL, OPTION_EXPORT_ALL_SYMS},
598 {"no-export-all-symbols", no_argument, NULL, OPTION_NO_EXPORT_ALL_SYMS},
599 {"exclude-symbols", required_argument, NULL, OPTION_EXCLUDE_SYMS},
600 {"no-default-excludes", no_argument, NULL, OPTION_NO_DEFAULT_EXCLUDES},
601 {"output-lib", required_argument, NULL, OPTION_OUTPUT_LIB},
602 {"def", required_argument, NULL, OPTION_DEF},
603 {"add-underscore", no_argument, NULL, 'U'},
604 {"killat", no_argument, NULL, 'k'},
605 {"add-stdcall-alias", no_argument, NULL, 'A'},
606 {"help", no_argument, NULL, 'h'},
607 {"machine", required_argument, NULL, OPTION_MACHINE},
608 {"add-indirect", no_argument, NULL, OPTION_ADD_INDIRECT},
609 {"base-file", required_argument, NULL, OPTION_BASE_FILE},
610 {"as", required_argument, NULL, OPTION_AS},
611 {0, 0, 0, 0}
614 int main PARAMS ((int, char **));
617 main (argc, argv)
618 int argc;
619 char **argv;
621 int c;
622 int i;
624 char **saved_argv = 0;
625 int cmdline_len = 0;
627 int export_all = 0;
629 int *dlltool_arg_indices;
630 int *driver_arg_indices;
632 char *driver_flags = 0;
633 char *output_lib_file_name = 0;
635 dyn_string_t dlltool_cmdline;
636 dyn_string_t driver_cmdline;
638 int def_file_seen = 0;
640 char *image_base_str = 0;
642 program_name = argv[0];
644 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
645 setlocale (LC_MESSAGES, "");
646 #endif
647 #if defined (HAVE_SETLOCALE)
648 setlocale (LC_CTYPE, "");
649 #endif
650 bindtextdomain (PACKAGE, LOCALEDIR);
651 textdomain (PACKAGE);
653 saved_argv = (char **) xmalloc (argc * sizeof (char*));
654 dlltool_arg_indices = (int *) xmalloc (argc * sizeof (int));
655 driver_arg_indices = (int *) xmalloc (argc * sizeof (int));
656 for (i = 0; i < argc; ++i)
658 size_t len = strlen (argv[i]);
659 char *arg = (char *) xmalloc (len + 1);
660 strcpy (arg, argv[i]);
661 cmdline_len += len;
662 saved_argv[i] = arg;
663 dlltool_arg_indices[i] = 0;
664 driver_arg_indices[i] = 1;
666 cmdline_len++;
668 /* We recognize dllwrap and dlltool options, and everything else is
669 passed onto the language driver (eg., to GCC). We collect options
670 to dlltool and driver in dlltool_args and driver_args. */
672 opterr = 0;
673 while ((c = getopt_long_only (argc, argv, "nkAqve:Uho:l:L:I:",
674 long_options, (int *) 0)) != EOF)
676 int dlltool_arg;
677 int driver_arg;
678 int single_word_option_value_pair;
680 dlltool_arg = 0;
681 driver_arg = 1;
682 single_word_option_value_pair = 0;
684 if (c != '?')
686 /* We recognize this option, so it has to be either dllwrap or
687 dlltool option. Do not pass to driver unless it's one of the
688 generic options that are passed to all the tools (such as -v)
689 which are dealt with later. */
690 driver_arg = 0;
693 /* deal with generic and dllwrap options first. */
694 switch (c)
696 case 'h':
697 usage (stdout, 0);
698 break;
699 case 'q':
700 verbose = 0;
701 break;
702 case 'v':
703 verbose = 1;
704 break;
705 case OPTION_VERSION:
706 print_version (program_name);
707 break;
708 case 'e':
709 entry_point = optarg;
710 break;
711 case OPTION_IMAGE_BASE:
712 image_base_str = optarg;
713 break;
714 case OPTION_DEF:
715 def_file_name = optarg;
716 def_file_seen = 1;
717 delete_def_file = 0;
718 break;
719 case 'n':
720 dontdeltemps = 1;
721 dlltool_arg = 1;
722 break;
723 case 'o':
724 dll_file_name = optarg;
725 break;
726 case 'I':
727 case 'l':
728 case 'L':
729 driver_arg = 1;
730 break;
731 case OPTION_DLLNAME:
732 dll_name = optarg;
733 break;
734 case OPTION_DRY_RUN:
735 dry_run = 1;
736 break;
737 case OPTION_DRIVER_NAME:
738 driver_name = optarg;
739 break;
740 case OPTION_DRIVER_FLAGS:
741 driver_flags = optarg;
742 break;
743 case OPTION_DLLTOOL_NAME:
744 dlltool_name = optarg;
745 break;
746 case OPTION_TARGET:
747 target = optarg;
748 break;
749 case OPTION_MNO_CYGWIN:
750 target = "i386-mingw32";
751 break;
752 case OPTION_BASE_FILE:
753 base_file_name = optarg;
754 delete_base_file = 0;
755 break;
756 case OPTION_OUTPUT_EXP:
757 exp_file_name = optarg;
758 delete_exp_file = 0;
759 break;
760 case OPTION_EXPORT_ALL_SYMS:
761 export_all = 1;
762 break;
763 case OPTION_OUTPUT_LIB:
764 output_lib_file_name = optarg;
765 break;
766 case '?':
767 break;
768 default:
769 dlltool_arg = 1;
770 break;
773 /* Handle passing through --option=value case. */
774 if (optarg
775 && saved_argv[optind-1][0] == '-'
776 && saved_argv[optind-1][1] == '-'
777 && strchr (saved_argv[optind-1], '='))
778 single_word_option_value_pair = 1;
780 if (dlltool_arg)
782 dlltool_arg_indices[optind-1] = 1;
783 if (optarg && ! single_word_option_value_pair)
785 dlltool_arg_indices[optind-2] = 1;
789 if (! driver_arg)
791 driver_arg_indices[optind-1] = 0;
792 if (optarg && ! single_word_option_value_pair)
794 driver_arg_indices[optind-2] = 0;
799 /* sanity checks. */
800 if (! dll_name && ! dll_file_name)
802 warn (_("Must provide at least one of -o or --dllname options"));
803 exit (1);
805 else if (! dll_name)
807 dll_name = xstrdup (mybasename (dll_file_name));
809 else if (! dll_file_name)
811 dll_file_name = xstrdup (dll_name);
814 /* Deduce driver-name and dlltool-name from our own. */
815 if (driver_name == NULL)
816 driver_name = deduce_name ("gcc");
818 if (dlltool_name == NULL)
819 dlltool_name = deduce_name ("dlltool");
821 if (! def_file_seen)
823 char *fileprefix = choose_temp_base ();
824 def_file_name = (char *) xmalloc (strlen (fileprefix) + 5);
825 sprintf (def_file_name, "%s.def",
826 (dontdeltemps) ? mybasename (fileprefix) : fileprefix);
827 delete_def_file = 1;
828 free (fileprefix);
829 delete_def_file = 1;
830 warn (_("no export definition file provided.\n\
831 Creating one, but that may not be what you want"));
834 /* set the target platform. */
835 if (strstr (target, "cygwin"))
836 which_target = CYGWIN_TARGET;
837 else if (strstr (target, "mingw"))
838 which_target = MINGW_TARGET;
839 else
840 which_target = UNKNOWN_TARGET;
842 /* re-create the command lines as a string, taking care to quote stuff. */
843 dlltool_cmdline = dyn_string_new (cmdline_len);
844 if (verbose)
846 dyn_string_append_cstr (dlltool_cmdline, " -v");
848 dyn_string_append_cstr (dlltool_cmdline, " --dllname ");
849 dyn_string_append_cstr (dlltool_cmdline, dll_name);
851 for (i = 1; i < argc; ++i)
853 if (dlltool_arg_indices[i])
855 char *arg = saved_argv[i];
856 int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
857 dyn_string_append_cstr (dlltool_cmdline,
858 (quote) ? " \"" : " ");
859 dyn_string_append_cstr (dlltool_cmdline, arg);
860 dyn_string_append_cstr (dlltool_cmdline,
861 (quote) ? "\"" : "");
865 driver_cmdline = dyn_string_new (cmdline_len);
866 if (! driver_flags || strlen (driver_flags) == 0)
868 switch (which_target)
870 case CYGWIN_TARGET:
871 driver_flags = cygwin_driver_flags;
872 break;
874 case MINGW_TARGET:
875 driver_flags = mingw32_driver_flags;
876 break;
878 default:
879 driver_flags = generic_driver_flags;
880 break;
883 dyn_string_append_cstr (driver_cmdline, driver_flags);
884 dyn_string_append_cstr (driver_cmdline, " -o ");
885 dyn_string_append_cstr (driver_cmdline, dll_file_name);
887 if (! entry_point || strlen (entry_point) == 0)
889 switch (which_target)
891 case CYGWIN_TARGET:
892 entry_point = "__cygwin_dll_entry@12";
893 break;
895 case MINGW_TARGET:
896 entry_point = "_DllMainCRTStartup@12";
897 break;
899 default:
900 entry_point = "_DllMain@12";
901 break;
904 dyn_string_append_cstr (driver_cmdline, " -Wl,-e,");
905 dyn_string_append_cstr (driver_cmdline, entry_point);
906 dyn_string_append_cstr (dlltool_cmdline, " --exclude-symbol=");
907 dyn_string_append_cstr (dlltool_cmdline,
908 (entry_point[0] == '_') ? entry_point+1 : entry_point);
910 if (! image_base_str || strlen (image_base_str) == 0)
912 char *tmpbuf = (char *) xmalloc (sizeof ("0x12345678") + 1);
913 unsigned long hash = strhash (dll_file_name);
914 sprintf (tmpbuf, "0x%.8lX", 0x60000000|((hash<<16)&0xFFC0000));
915 image_base_str = tmpbuf;
918 dyn_string_append_cstr (driver_cmdline, " -Wl,--image-base,");
919 dyn_string_append_cstr (driver_cmdline, image_base_str);
921 if (verbose)
923 dyn_string_append_cstr (driver_cmdline, " -v");
926 for (i = 1; i < argc; ++i)
928 if (driver_arg_indices[i])
930 char *arg = saved_argv[i];
931 int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
932 dyn_string_append_cstr (driver_cmdline,
933 (quote) ? " \"" : " ");
934 dyn_string_append_cstr (driver_cmdline, arg);
935 dyn_string_append_cstr (driver_cmdline,
936 (quote) ? "\"" : "");
941 * Step pre-1. If no --def <EXPORT_DEF> is specified, then create it
942 * and then pass it on.
945 if (! def_file_seen)
947 int i;
948 dyn_string_t step_pre1;
950 step_pre1 = dyn_string_new (1024);
952 dyn_string_append_cstr (step_pre1, dlltool_cmdline->s);
953 if (export_all)
955 dyn_string_append_cstr (step_pre1, " --export-all --exclude-symbol=");
956 dyn_string_append_cstr (step_pre1,
957 "_cygwin_dll_entry@12,DllMainCRTStartup@12,DllMain@12,DllEntryPoint@12");
959 dyn_string_append_cstr (step_pre1, " --output-def ");
960 dyn_string_append_cstr (step_pre1, def_file_name);
962 for (i = 1; i < argc; ++i)
964 if (driver_arg_indices[i])
966 char *arg = saved_argv[i];
967 size_t len = strlen (arg);
968 if (len >= 2 && arg[len-2] == '.'
969 && (arg[len-1] == 'o' || arg[len-1] == 'a'))
971 int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
972 dyn_string_append_cstr (step_pre1,
973 (quote) ? " \"" : " ");
974 dyn_string_append_cstr (step_pre1, arg);
975 dyn_string_append_cstr (step_pre1,
976 (quote) ? "\"" : "");
981 if (run (dlltool_name, step_pre1->s))
982 cleanup_and_exit (1);
984 dyn_string_delete (step_pre1);
987 dyn_string_append_cstr (dlltool_cmdline, " --def ");
988 dyn_string_append_cstr (dlltool_cmdline, def_file_name);
990 if (verbose)
992 fprintf (stderr, _("DLLTOOL name : %s\n"), dlltool_name);
993 fprintf (stderr, _("DLLTOOL options : %s\n"), dlltool_cmdline->s);
994 fprintf (stderr, _("DRIVER name : %s\n"), driver_name);
995 fprintf (stderr, _("DRIVER options : %s\n"), driver_cmdline->s);
999 * Step 1. Call GCC/LD to create base relocation file. If using GCC, the
1000 * driver command line will look like the following:
1002 * % gcc -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
1004 * If the user does not specify a base name, create temporary one that
1005 * is deleted at exit.
1009 if (! base_file_name)
1011 char *fileprefix = choose_temp_base ();
1012 base_file_name = (char *) xmalloc (strlen (fileprefix) + 6);
1013 sprintf (base_file_name, "%s.base",
1014 (dontdeltemps) ? mybasename (fileprefix) : fileprefix);
1015 delete_base_file = 1;
1016 free (fileprefix);
1020 int quote;
1022 dyn_string_t step1 = dyn_string_new (driver_cmdline->length
1023 + strlen (base_file_name)
1024 + 20);
1025 dyn_string_append_cstr (step1, "-Wl,--base-file,");
1026 quote = (strchr (base_file_name, ' ')
1027 || strchr (base_file_name, '\t'));
1028 dyn_string_append_cstr (step1,
1029 (quote) ? "\"" : "");
1030 dyn_string_append_cstr (step1, base_file_name);
1031 dyn_string_append_cstr (step1,
1032 (quote) ? "\"" : "");
1033 if (driver_cmdline->length)
1035 dyn_string_append_cstr (step1, " ");
1036 dyn_string_append_cstr (step1, driver_cmdline->s);
1039 if (run (driver_name, step1->s))
1040 cleanup_and_exit (1);
1042 dyn_string_delete (step1);
1048 * Step 2. generate the exp file by running dlltool.
1049 * dlltool command line will look like the following:
1051 * % dlltool -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
1053 * If the user does not specify a base name, create temporary one that
1054 * is deleted at exit.
1058 if (! exp_file_name)
1060 char *p = strrchr (dll_name, '.');
1061 size_t prefix_len = (p) ? p - dll_name : strlen (dll_name);
1062 exp_file_name = (char *) xmalloc (prefix_len + 4 + 1);
1063 strncpy (exp_file_name, dll_name, prefix_len);
1064 exp_file_name[prefix_len] = '\0';
1065 strcat (exp_file_name, ".exp");
1066 delete_exp_file = 1;
1070 int quote;
1071 dyn_string_t step2 = dyn_string_new (dlltool_cmdline->length
1072 + strlen (base_file_name)
1073 + strlen (exp_file_name)
1074 + 20);
1076 dyn_string_append_cstr (step2, "--base-file ");
1077 quote = (strchr (base_file_name, ' ')
1078 || strchr (base_file_name, '\t'));
1079 dyn_string_append_cstr (step2,
1080 (quote) ? "\"" : "");
1081 dyn_string_append_cstr (step2, base_file_name);
1082 dyn_string_append_cstr (step2,
1083 (quote) ? "\" " : " ");
1085 dyn_string_append_cstr (step2, "--output-exp ");
1086 quote = (strchr (exp_file_name, ' ')
1087 || strchr (exp_file_name, '\t'));
1088 dyn_string_append_cstr (step2,
1089 (quote) ? "\"" : "");
1090 dyn_string_append_cstr (step2, exp_file_name);
1091 dyn_string_append_cstr (step2,
1092 (quote) ? "\"" : "");
1094 if (dlltool_cmdline->length)
1096 dyn_string_append_cstr (step2, " ");
1097 dyn_string_append_cstr (step2, dlltool_cmdline->s);
1100 if (run (dlltool_name, step2->s))
1101 cleanup_and_exit (1);
1103 dyn_string_delete (step2);
1107 * Step 3. Call GCC/LD to again, adding the exp file this time.
1108 * driver command line will look like the following:
1110 * % gcc -Wl,--dll --Wl,--base-file,foo.base foo.exp [rest ...]
1114 int quote;
1116 dyn_string_t step3 = dyn_string_new (driver_cmdline->length
1117 + strlen (exp_file_name)
1118 + strlen (base_file_name)
1119 + 20);
1120 dyn_string_append_cstr (step3, "-Wl,--base-file,");
1121 quote = (strchr (base_file_name, ' ')
1122 || strchr (base_file_name, '\t'));
1123 dyn_string_append_cstr (step3,
1124 (quote) ? "\"" : "");
1125 dyn_string_append_cstr (step3, base_file_name);
1126 dyn_string_append_cstr (step3,
1127 (quote) ? "\" " : " ");
1129 quote = (strchr (exp_file_name, ' ')
1130 || strchr (exp_file_name, '\t'));
1131 dyn_string_append_cstr (step3,
1132 (quote) ? "\"" : "");
1133 dyn_string_append_cstr (step3, exp_file_name);
1134 dyn_string_append_cstr (step3,
1135 (quote) ? "\"" : "");
1137 if (driver_cmdline->length)
1139 dyn_string_append_cstr (step3, " ");
1140 dyn_string_append_cstr (step3, driver_cmdline->s);
1143 if (run (driver_name, step3->s))
1144 cleanup_and_exit (1);
1146 dyn_string_delete (step3);
1151 * Step 4. Run DLLTOOL again using the same command line.
1155 int quote;
1156 dyn_string_t step4 = dyn_string_new (dlltool_cmdline->length
1157 + strlen (base_file_name)
1158 + strlen (exp_file_name)
1159 + 20);
1161 dyn_string_append_cstr (step4, "--base-file ");
1162 quote = (strchr (base_file_name, ' ')
1163 || strchr (base_file_name, '\t'));
1164 dyn_string_append_cstr (step4,
1165 (quote) ? "\"" : "");
1166 dyn_string_append_cstr (step4, base_file_name);
1167 dyn_string_append_cstr (step4,
1168 (quote) ? "\" " : " ");
1170 dyn_string_append_cstr (step4, "--output-exp ");
1171 quote = (strchr (exp_file_name, ' ')
1172 || strchr (exp_file_name, '\t'));
1173 dyn_string_append_cstr (step4,
1174 (quote) ? "\"" : "");
1175 dyn_string_append_cstr (step4, exp_file_name);
1176 dyn_string_append_cstr (step4,
1177 (quote) ? "\"" : "");
1179 if (dlltool_cmdline->length)
1181 dyn_string_append_cstr (step4, " ");
1182 dyn_string_append_cstr (step4, dlltool_cmdline->s);
1185 if (output_lib_file_name)
1187 dyn_string_append_cstr (step4, " --output-lib ");
1188 dyn_string_append_cstr (step4, output_lib_file_name);
1191 if (run (dlltool_name, step4->s))
1192 cleanup_and_exit (1);
1194 dyn_string_delete (step4);
1199 * Step 5. Link it all together and be done with it.
1200 * driver command line will look like the following:
1202 * % gcc -Wl,--dll foo.exp [rest ...]
1207 int quote;
1209 dyn_string_t step5 = dyn_string_new (driver_cmdline->length
1210 + strlen (exp_file_name)
1211 + 20);
1212 quote = (strchr (exp_file_name, ' ')
1213 || strchr (exp_file_name, '\t'));
1214 dyn_string_append_cstr (step5,
1215 (quote) ? "\"" : "");
1216 dyn_string_append_cstr (step5, exp_file_name);
1217 dyn_string_append_cstr (step5,
1218 (quote) ? "\"" : "");
1220 if (driver_cmdline->length)
1222 dyn_string_append_cstr (step5, " ");
1223 dyn_string_append_cstr (step5, driver_cmdline->s);
1226 if (run (driver_name, step5->s))
1227 cleanup_and_exit (1);
1229 dyn_string_delete (step5);
1232 cleanup_and_exit (0);
1234 return 0;