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