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