Warn unsupported compress type and corrupted compressed section
[external/binutils.git] / binutils / dllwrap.c
1 /* dllwrap.c -- wrapper for DLLTOOL and GCC to generate PE style DLLs
2    Copyright (C) 1998-2015 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 = alloca (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
396   if (pid == -1)
397     {
398       int errno_val = errno;
399
400       fprintf (stderr, "%s: ", prog_name);
401       fprintf (stderr, errmsg_fmt, errmsg_arg);
402       fprintf (stderr, ": %s\n", strerror (errno_val));
403       return 1;
404     }
405
406   retcode = 0;
407   pid = pwait (pid, &wait_status, 0);
408   if (pid == -1)
409     {
410       warn (_("pwait returns: %s"), strerror (errno));
411       retcode = 1;
412     }
413   else if (WIFSIGNALED (wait_status))
414     {
415       warn (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
416       retcode = 1;
417     }
418   else if (WIFEXITED (wait_status))
419     {
420       if (WEXITSTATUS (wait_status) != 0)
421         {
422           warn (_("%s exited with status %d"), what, WEXITSTATUS (wait_status));
423           retcode = 1;
424         }
425     }
426   else
427     retcode = 1;
428
429   return retcode;
430 }
431
432 static char *
433 mybasename (const char *name)
434 {
435   const char *base = name;
436
437   while (*name)
438     {
439       if (*name == '/' || *name == '\\')
440         {
441           base = name + 1;
442         }
443       ++name;
444     }
445   return (char *) base;
446 }
447
448 static int
449 strhash (const char *str)
450 {
451   const unsigned char *s;
452   unsigned long hash;
453   unsigned int c;
454   unsigned int len;
455
456   hash = 0;
457   len = 0;
458   s = (const unsigned char *) str;
459   while ((c = *s++) != '\0')
460     {
461       hash += c + (c << 17);
462       hash ^= hash >> 2;
463       ++len;
464     }
465   hash += len + (len << 17);
466   hash ^= hash >> 2;
467
468   return hash;
469 }
470
471 /**********************************************************************/
472
473 static void
474 usage (FILE *file, int status)
475 {
476   fprintf (file, _("Usage %s <option(s)> <object-file(s)>\n"), prog_name);
477   fprintf (file, _("  Generic options:\n"));
478   fprintf (file, _("   @<file>                Read options from <file>\n"));    
479   fprintf (file, _("   --quiet, -q            Work quietly\n"));
480   fprintf (file, _("   --verbose, -v          Verbose\n"));
481   fprintf (file, _("   --version              Print dllwrap version\n"));
482   fprintf (file, _("   --implib <outname>     Synonym for --output-lib\n"));
483   fprintf (file, _("  Options for %s:\n"), prog_name);
484   fprintf (file, _("   --driver-name <driver> Defaults to \"gcc\"\n"));
485   fprintf (file, _("   --driver-flags <flags> Override default ld flags\n"));
486   fprintf (file, _("   --dlltool-name <dlltool> Defaults to \"dlltool\"\n"));
487   fprintf (file, _("   --entry <entry>        Specify alternate DLL entry point\n"));
488   fprintf (file, _("   --image-base <base>    Specify image base address\n"));
489   fprintf (file, _("   --target <machine>     i386-cygwin32 or i386-mingw32\n"));
490   fprintf (file, _("   --dry-run              Show what needs to be run\n"));
491   fprintf (file, _("   --mno-cygwin           Create Mingw DLL\n"));
492   fprintf (file, _("  Options passed to DLLTOOL:\n"));
493   fprintf (file, _("   --machine <machine>\n"));
494   fprintf (file, _("   --output-exp <outname> Generate export file.\n"));
495   fprintf (file, _("   --output-lib <outname> Generate input library.\n"));
496   fprintf (file, _("   --add-indirect         Add dll indirects to export file.\n"));
497   fprintf (file, _("   --dllname <name>       Name of input dll to put into output lib.\n"));
498   fprintf (file, _("   --def <deffile>        Name input .def file\n"));
499   fprintf (file, _("   --output-def <deffile> Name output .def file\n"));
500   fprintf (file, _("   --export-all-symbols     Export all symbols to .def\n"));
501   fprintf (file, _("   --no-export-all-symbols  Only export .drectve symbols\n"));
502   fprintf (file, _("   --exclude-symbols <list> Exclude <list> from .def\n"));
503   fprintf (file, _("   --no-default-excludes    Zap default exclude symbols\n"));
504   fprintf (file, _("   --base-file <basefile> Read linker generated base file\n"));
505   fprintf (file, _("   --no-idata4           Don't generate idata$4 section\n"));
506   fprintf (file, _("   --no-idata5           Don't generate idata$5 section\n"));
507   fprintf (file, _("   -U                     Add underscores to .lib\n"));
508   fprintf (file, _("   -k                     Kill @<n> from exported names\n"));
509   fprintf (file, _("   --add-stdcall-alias    Add aliases without @<n>\n"));
510   fprintf (file, _("   --as <name>            Use <name> for assembler\n"));
511   fprintf (file, _("   --nodelete             Keep temp files.\n"));
512   fprintf (file, _("   --no-leading-underscore  Entrypoint without underscore\n"));
513   fprintf (file, _("   --leading-underscore     Entrypoint with underscore.\n"));
514   fprintf (file, _("  Rest are passed unmodified to the language driver\n"));
515   fprintf (file, "\n\n");
516   if (REPORT_BUGS_TO[0] && status == 0)
517     fprintf (file, _("Report bugs to %s\n"), REPORT_BUGS_TO);
518   exit (status);
519 }
520
521 #define OPTION_START            149
522
523 /* GENERIC options.  */
524 #define OPTION_QUIET            (OPTION_START + 1)
525 #define OPTION_VERBOSE          (OPTION_QUIET + 1)
526 #define OPTION_VERSION          (OPTION_VERBOSE + 1)
527
528 /* DLLWRAP options.  */
529 #define OPTION_DRY_RUN          (OPTION_VERSION + 1)
530 #define OPTION_DRIVER_NAME      (OPTION_DRY_RUN + 1)
531 #define OPTION_DRIVER_FLAGS     (OPTION_DRIVER_NAME + 1)
532 #define OPTION_DLLTOOL_NAME     (OPTION_DRIVER_FLAGS + 1)
533 #define OPTION_ENTRY            (OPTION_DLLTOOL_NAME + 1)
534 #define OPTION_IMAGE_BASE       (OPTION_ENTRY + 1)
535 #define OPTION_TARGET           (OPTION_IMAGE_BASE + 1)
536 #define OPTION_MNO_CYGWIN       (OPTION_TARGET + 1)
537 #define OPTION_NO_LEADING_UNDERSCORE (OPTION_MNO_CYGWIN + 1)
538 #define OPTION_LEADING_UNDERSCORE (OPTION_NO_LEADING_UNDERSCORE + 1)
539
540 /* DLLTOOL options.  */
541 #define OPTION_NODELETE         (OPTION_LEADING_UNDERSCORE + 1)
542 #define OPTION_DLLNAME          (OPTION_NODELETE + 1)
543 #define OPTION_NO_IDATA4        (OPTION_DLLNAME + 1)
544 #define OPTION_NO_IDATA5        (OPTION_NO_IDATA4 + 1)
545 #define OPTION_OUTPUT_EXP       (OPTION_NO_IDATA5 + 1)
546 #define OPTION_OUTPUT_DEF       (OPTION_OUTPUT_EXP + 1)
547 #define OPTION_EXPORT_ALL_SYMS  (OPTION_OUTPUT_DEF + 1)
548 #define OPTION_NO_EXPORT_ALL_SYMS (OPTION_EXPORT_ALL_SYMS + 1)
549 #define OPTION_EXCLUDE_SYMS     (OPTION_NO_EXPORT_ALL_SYMS + 1)
550 #define OPTION_NO_DEFAULT_EXCLUDES (OPTION_EXCLUDE_SYMS + 1)
551 #define OPTION_OUTPUT_LIB       (OPTION_NO_DEFAULT_EXCLUDES + 1)
552 #define OPTION_DEF              (OPTION_OUTPUT_LIB + 1)
553 #define OPTION_ADD_UNDERSCORE   (OPTION_DEF + 1)
554 #define OPTION_KILLAT           (OPTION_ADD_UNDERSCORE + 1)
555 #define OPTION_HELP             (OPTION_KILLAT + 1)
556 #define OPTION_MACHINE          (OPTION_HELP + 1)
557 #define OPTION_ADD_INDIRECT     (OPTION_MACHINE + 1)
558 #define OPTION_BASE_FILE        (OPTION_ADD_INDIRECT + 1)
559 #define OPTION_AS               (OPTION_BASE_FILE + 1)
560
561 static const struct option long_options[] =
562 {
563   /* generic options.  */
564   {"quiet", no_argument, NULL, 'q'},
565   {"verbose", no_argument, NULL, 'v'},
566   {"version", no_argument, NULL, OPTION_VERSION},
567   {"implib", required_argument, NULL, OPTION_OUTPUT_LIB},
568
569   /* dllwrap options.  */
570   {"dry-run", no_argument, NULL, OPTION_DRY_RUN},
571   {"driver-name", required_argument, NULL, OPTION_DRIVER_NAME},
572   {"driver-flags", required_argument, NULL, OPTION_DRIVER_FLAGS},
573   {"dlltool-name", required_argument, NULL, OPTION_DLLTOOL_NAME},
574   {"entry", required_argument, NULL, 'e'},
575   {"image-base", required_argument, NULL, OPTION_IMAGE_BASE},
576   {"target", required_argument, NULL, OPTION_TARGET},
577   {"no-leading-underscore", no_argument, NULL, OPTION_NO_LEADING_UNDERSCORE},
578   {"leading-underscore", no_argument, NULL, OPTION_NO_LEADING_UNDERSCORE},
579
580   /* dlltool options.  */
581   {"no-delete", no_argument, NULL, 'n'},
582   {"dllname", required_argument, NULL, OPTION_DLLNAME},
583   {"no-idata4", no_argument, NULL, OPTION_NO_IDATA4},
584   {"no-idata5", no_argument, NULL, OPTION_NO_IDATA5},
585   {"output-exp", required_argument, NULL, OPTION_OUTPUT_EXP},
586   {"output-def", required_argument, NULL, OPTION_OUTPUT_DEF},
587   {"export-all-symbols", no_argument, NULL, OPTION_EXPORT_ALL_SYMS},
588   {"no-export-all-symbols", no_argument, NULL, OPTION_NO_EXPORT_ALL_SYMS},
589   {"exclude-symbols", required_argument, NULL, OPTION_EXCLUDE_SYMS},
590   {"no-default-excludes", no_argument, NULL, OPTION_NO_DEFAULT_EXCLUDES},
591   {"output-lib", required_argument, NULL, OPTION_OUTPUT_LIB},
592   {"def", required_argument, NULL, OPTION_DEF},
593   {"add-underscore", no_argument, NULL, 'U'},
594   {"killat", no_argument, NULL, 'k'},
595   {"add-stdcall-alias", no_argument, NULL, 'A'},
596   {"help", no_argument, NULL, 'h'},
597   {"machine", required_argument, NULL, OPTION_MACHINE},
598   {"add-indirect", no_argument, NULL, OPTION_ADD_INDIRECT},
599   {"base-file", required_argument, NULL, OPTION_BASE_FILE},
600   {"as", required_argument, NULL, OPTION_AS},
601   {0, 0, 0, 0}
602 };
603
604 int main (int, char **);
605
606 int
607 main (int argc, char **argv)
608 {
609   int c;
610   int i;
611
612   char **saved_argv = 0;
613   int cmdline_len = 0;
614
615   int export_all = 0;
616
617   int *dlltool_arg_indices;
618   int *driver_arg_indices;
619
620   char *driver_flags = 0;
621   char *output_lib_file_name = 0;
622
623   dyn_string_t dlltool_cmdline;
624   dyn_string_t driver_cmdline;
625
626   int def_file_seen = 0;
627
628   char *image_base_str = 0;
629
630   prog_name = argv[0];
631
632 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
633   setlocale (LC_MESSAGES, "");
634 #endif
635 #if defined (HAVE_SETLOCALE)
636   setlocale (LC_CTYPE, "");
637 #endif
638   bindtextdomain (PACKAGE, LOCALEDIR);
639   textdomain (PACKAGE);
640
641   expandargv (&argc, &argv);
642
643   saved_argv = (char **) xmalloc (argc * sizeof (char*));
644   dlltool_arg_indices = (int *) xmalloc (argc * sizeof (int));
645   driver_arg_indices = (int *) xmalloc (argc * sizeof (int));
646   for (i = 0; i < argc; ++i)
647     {
648       size_t len = strlen (argv[i]);
649       char *arg = (char *) xmalloc (len + 1);
650       strcpy (arg, argv[i]);
651       cmdline_len += len;
652       saved_argv[i] = arg;
653       dlltool_arg_indices[i] = 0;
654       driver_arg_indices[i] = 1;
655     }
656   cmdline_len++;
657
658   /* We recognize dllwrap and dlltool options, and everything else is
659      passed onto the language driver (eg., to GCC). We collect options
660      to dlltool and driver in dlltool_args and driver_args.  */
661
662   opterr = 0;
663   while ((c = getopt_long_only (argc, argv, "nkAqve:Uho:l:L:I:",
664                                 long_options, (int *) 0)) != EOF)
665     {
666       int dlltool_arg;
667       int driver_arg;
668       int single_word_option_value_pair;
669
670       dlltool_arg = 0;
671       driver_arg = 1;
672       single_word_option_value_pair = 0;
673
674       if (c != '?')
675         {
676           /* We recognize this option, so it has to be either dllwrap or
677              dlltool option. Do not pass to driver unless it's one of the
678              generic options that are passed to all the tools (such as -v)
679              which are dealt with later.  */
680           driver_arg = 0;
681         }
682
683       /* deal with generic and dllwrap options first.  */
684       switch (c)
685         {
686         case 'h':
687           usage (stdout, 0);
688           break;
689         case 'q':
690           verbose = 0;
691           break;
692         case 'v':
693           verbose = 1;
694           break;
695         case OPTION_VERSION:
696           print_version (prog_name);
697           break;
698         case 'e':
699           entry_point = optarg;
700           break;
701         case OPTION_IMAGE_BASE:
702           image_base_str = optarg;
703           break;
704         case OPTION_DEF:
705           def_file_name = optarg;
706           def_file_seen = 1;
707           delete_def_file = 0;
708           break;
709         case 'n':
710           dontdeltemps = 1;
711           dlltool_arg = 1;
712           break;
713         case 'o':
714           dll_file_name = optarg;
715           break;
716         case 'I':
717         case 'l':
718         case 'L':
719           driver_arg = 1;
720           break;
721         case OPTION_DLLNAME:
722           dll_name = optarg;
723           break;
724         case OPTION_DRY_RUN:
725           dry_run = 1;
726           break;
727         case OPTION_DRIVER_NAME:
728           driver_name = optarg;
729           break;
730         case OPTION_DRIVER_FLAGS:
731           driver_flags = optarg;
732           break;
733         case OPTION_DLLTOOL_NAME:
734           dlltool_name = optarg;
735           break;
736         case OPTION_TARGET:
737           target = optarg;
738           break;
739         case OPTION_MNO_CYGWIN:
740           target = "i386-mingw32";
741           break;
742         case OPTION_NO_LEADING_UNDERSCORE:
743           is_leading_underscore = 0;
744           break;
745         case OPTION_LEADING_UNDERSCORE:
746           is_leading_underscore = 1;
747           break;
748         case OPTION_BASE_FILE:
749           base_file_name = optarg;
750           delete_base_file = 0;
751           break;
752         case OPTION_OUTPUT_EXP:
753           exp_file_name = optarg;
754           delete_exp_file = 0;
755           break;
756         case OPTION_EXPORT_ALL_SYMS:
757           export_all = 1;
758           break;
759         case OPTION_OUTPUT_LIB:
760           output_lib_file_name = optarg;
761           break;
762         case '?':
763           break;
764         default:
765           dlltool_arg = 1;
766           break;
767         }
768
769       /* Handle passing through --option=value case.  */
770       if (optarg
771           && saved_argv[optind-1][0] == '-'
772           && saved_argv[optind-1][1] == '-'
773           && strchr (saved_argv[optind-1], '='))
774         single_word_option_value_pair = 1;
775
776       if (dlltool_arg)
777         {
778           dlltool_arg_indices[optind-1] = 1;
779           if (optarg && ! single_word_option_value_pair)
780             {
781               dlltool_arg_indices[optind-2] = 1;
782             }
783         }
784
785       if (! driver_arg)
786         {
787           driver_arg_indices[optind-1] = 0;
788           if (optarg && ! single_word_option_value_pair)
789             {
790               driver_arg_indices[optind-2] = 0;
791             }
792         }
793     }
794
795   /* Sanity checks.  */
796   if (! dll_name && ! dll_file_name)
797     {
798       warn (_("Must provide at least one of -o or --dllname options"));
799       exit (1);
800     }
801   else if (! dll_name)
802     {
803       dll_name = xstrdup (mybasename (dll_file_name));
804     }
805   else if (! dll_file_name)
806     {
807       dll_file_name = xstrdup (dll_name);
808     }
809
810   /* Deduce driver-name and dlltool-name from our own.  */
811   if (driver_name == NULL)
812     driver_name = deduce_name ("gcc");
813
814   if (dlltool_name == NULL)
815     dlltool_name = deduce_name ("dlltool");
816
817   if (! def_file_seen)
818     {
819       char *fileprefix = choose_temp_base ();
820
821       def_file_name = (char *) xmalloc (strlen (fileprefix) + 5);
822       sprintf (def_file_name, "%s.def",
823                (dontdeltemps) ? mybasename (fileprefix) : fileprefix);
824       delete_def_file = 1;
825       free (fileprefix);
826       delete_def_file = 1;
827       warn (_("no export definition file provided.\n\
828 Creating one, but that may not be what you want"));
829     }
830
831   /* Set the target platform.  */
832   if (strstr (target, "cygwin"))
833     which_target = CYGWIN_TARGET;
834   else if (strstr (target, "mingw"))
835     which_target = MINGW_TARGET;
836   else
837     which_target = UNKNOWN_TARGET;
838
839   if (! strncmp (target, "arm", 3))
840     which_cpu = ARM_CPU;
841   else if (!strncmp (target, "x86_64", 6)
842            || !strncmp (target, "athlon64", 8)
843            || !strncmp (target, "amd64", 5))
844     which_cpu = X64_CPU;
845   else if (target[0] == 'i' && (target[1] >= '3' && target[1] <= '6')
846            && target[2] == '8' && target[3] == '6')
847     which_cpu = X86_CPU;
848   else
849     which_cpu = UNKNOWN_CPU;
850
851   if (is_leading_underscore == -1)
852     is_leading_underscore = (which_cpu != X64_CPU && which_cpu != ARM_CPU);
853
854   /* Re-create the command lines as a string, taking care to quote stuff.  */
855   dlltool_cmdline = dyn_string_new (cmdline_len);
856   if (verbose)
857     dyn_string_append_cstr (dlltool_cmdline, " -v");
858
859   dyn_string_append_cstr (dlltool_cmdline, " --dllname ");
860   dyn_string_append_cstr (dlltool_cmdline, dll_name);
861
862   for (i = 1; i < argc; ++i)
863     {
864       if (dlltool_arg_indices[i])
865         {
866           char *arg = saved_argv[i];
867           int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
868           dyn_string_append_cstr (dlltool_cmdline,
869                              (quote) ? " \"" : " ");
870           dyn_string_append_cstr (dlltool_cmdline, arg);
871           dyn_string_append_cstr (dlltool_cmdline,
872                              (quote) ? "\"" : "");
873         }
874     }
875
876   driver_cmdline = dyn_string_new (cmdline_len);
877   if (! driver_flags || strlen (driver_flags) == 0)
878     {
879       switch (which_target)
880         {
881         case CYGWIN_TARGET:
882           driver_flags = cygwin_driver_flags;
883           break;
884
885         case MINGW_TARGET:
886           driver_flags = mingw32_driver_flags;
887           break;
888
889         default:
890           driver_flags = generic_driver_flags;
891           break;
892         }
893     }
894   dyn_string_append_cstr (driver_cmdline, driver_flags);
895   dyn_string_append_cstr (driver_cmdline, " -o ");
896   dyn_string_append_cstr (driver_cmdline, dll_file_name);
897
898   if (is_leading_underscore == 0)
899     dyn_string_append_cstr (driver_cmdline, " --no-leading-underscore");
900   else if (is_leading_underscore == 1)
901     dyn_string_append_cstr (driver_cmdline, " --leading-underscore");
902
903   if (! entry_point || strlen (entry_point) == 0)
904     {
905       const char *prefix = (is_leading_underscore != 0 ? "_" : "");
906       const char *postfix = "";
907       const char *name_entry;
908
909       if (which_cpu == X86_CPU || which_cpu == UNKNOWN_CPU)
910         postfix = "@12";
911
912       switch (which_target)
913         {
914         case CYGWIN_TARGET:
915           name_entry = "_cygwin_dll_entry";
916           break;
917
918         case MINGW_TARGET:
919           name_entry = "DllMainCRTStartup";
920           break;
921
922         default:
923           name_entry = "DllMain";
924           break;
925         }
926       entry_point =
927         (char *) malloc (strlen (name_entry) + strlen (prefix)
928                          + strlen (postfix) + 1);
929       sprintf (entry_point, "%s%s%s", prefix, name_entry, postfix);
930     }
931   dyn_string_append_cstr (driver_cmdline, " -Wl,-e,");
932   dyn_string_append_cstr (driver_cmdline, entry_point);
933   dyn_string_append_cstr (dlltool_cmdline, " --exclude-symbol=");
934   dyn_string_append_cstr (dlltool_cmdline,
935                     (entry_point[0] == '_') ? entry_point+1 : entry_point);
936
937   if (! image_base_str || strlen (image_base_str) == 0)
938     {
939       char *tmpbuf = (char *) xmalloc (sizeof ("0x12345678") + 1);
940       unsigned long hash = strhash (dll_file_name);
941       sprintf (tmpbuf, "0x%.8lX", 0x60000000|((hash<<16)&0xFFC0000));
942       image_base_str = tmpbuf;
943     }
944
945   dyn_string_append_cstr (driver_cmdline, " -Wl,--image-base,");
946   dyn_string_append_cstr (driver_cmdline, image_base_str);
947
948   if (verbose)
949     {
950       dyn_string_append_cstr (driver_cmdline, " -v");
951     }
952
953   for (i = 1; i < argc; ++i)
954     {
955       if (driver_arg_indices[i])
956         {
957           char *arg = saved_argv[i];
958           int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
959           dyn_string_append_cstr (driver_cmdline,
960                              (quote) ? " \"" : " ");
961           dyn_string_append_cstr (driver_cmdline, arg);
962           dyn_string_append_cstr (driver_cmdline,
963                              (quote) ? "\"" : "");
964         }
965     }
966
967   /* Step pre-1. If no --def <EXPORT_DEF> is specified,
968      then create it and then pass it on.  */
969
970   if (! def_file_seen)
971     {
972       dyn_string_t step_pre1;
973
974       step_pre1 = dyn_string_new (1024);
975
976       dyn_string_append_cstr (step_pre1, dlltool_cmdline->s);
977       if (export_all)
978         {
979           dyn_string_append_cstr (step_pre1, " --export-all --exclude-symbol=");
980           dyn_string_append_cstr (step_pre1,
981           "_cygwin_dll_entry@12,DllMainCRTStartup@12,DllMain@12,DllEntryPoint@12");
982         }
983       dyn_string_append_cstr (step_pre1, " --output-def ");
984       dyn_string_append_cstr (step_pre1, def_file_name);
985
986       for (i = 1; i < argc; ++i)
987         {
988           if (driver_arg_indices[i])
989             {
990               char *arg = saved_argv[i];
991               size_t len = strlen (arg);
992               if (len >= 2 && arg[len-2] == '.'
993                   && (arg[len-1] == 'o' || arg[len-1] == 'a'))
994                 {
995                   int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
996                   dyn_string_append_cstr (step_pre1,
997                                      (quote) ? " \"" : " ");
998                   dyn_string_append_cstr (step_pre1, arg);
999                   dyn_string_append_cstr (step_pre1,
1000                                      (quote) ? "\"" : "");
1001                 }
1002             }
1003         }
1004
1005       if (run (dlltool_name, step_pre1->s))
1006         cleanup_and_exit (1);
1007
1008       dyn_string_delete (step_pre1);
1009     }
1010
1011   dyn_string_append_cstr (dlltool_cmdline, " --def ");
1012   dyn_string_append_cstr (dlltool_cmdline, def_file_name);
1013
1014   if (verbose)
1015     {
1016       fprintf (stderr, _("DLLTOOL name    : %s\n"), dlltool_name);
1017       fprintf (stderr, _("DLLTOOL options : %s\n"), dlltool_cmdline->s);
1018       fprintf (stderr, _("DRIVER name     : %s\n"), driver_name);
1019       fprintf (stderr, _("DRIVER options  : %s\n"), driver_cmdline->s);
1020     }
1021
1022   /* Step 1. Call GCC/LD to create base relocation file. If using GCC, the
1023      driver command line will look like the following:
1024     
1025         % gcc -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
1026     
1027      If the user does not specify a base name, create temporary one that
1028      is deleted at exit.  */
1029
1030   if (! base_file_name)
1031     {
1032       char *fileprefix = choose_temp_base ();
1033       base_file_name = (char *) xmalloc (strlen (fileprefix) + 6);
1034       sprintf (base_file_name, "%s.base",
1035                (dontdeltemps) ? mybasename (fileprefix) : fileprefix);
1036       delete_base_file = 1;
1037       free (fileprefix);
1038     }
1039
1040   {
1041     int quote;
1042
1043     dyn_string_t step1 = dyn_string_new (driver_cmdline->length
1044                                          + strlen (base_file_name)
1045                                          + 20);
1046     dyn_string_append_cstr (step1, "-Wl,--base-file,");
1047     quote = (strchr (base_file_name, ' ')
1048              || strchr (base_file_name, '\t'));
1049     dyn_string_append_cstr (step1,
1050                        (quote) ? "\"" : "");
1051     dyn_string_append_cstr (step1, base_file_name);
1052     dyn_string_append_cstr (step1,
1053                        (quote) ? "\"" : "");
1054     if (driver_cmdline->length)
1055       {
1056         dyn_string_append_cstr (step1, " ");
1057         dyn_string_append_cstr (step1, driver_cmdline->s);
1058       }
1059
1060     if (run (driver_name, step1->s))
1061       cleanup_and_exit (1);
1062
1063     dyn_string_delete (step1);
1064   }
1065
1066   /* Step 2. generate the exp file by running dlltool.
1067      dlltool command line will look like the following:
1068     
1069         % dlltool -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
1070     
1071      If the user does not specify a base name, create temporary one that
1072      is deleted at exit.  */
1073
1074   if (! exp_file_name)
1075     {
1076       char *p = strrchr (dll_name, '.');
1077       size_t prefix_len = (p) ? (size_t) (p - dll_name) : strlen (dll_name);
1078
1079       exp_file_name = (char *) xmalloc (prefix_len + 4 + 1);
1080       strncpy (exp_file_name, dll_name, prefix_len);
1081       exp_file_name[prefix_len] = '\0';
1082       strcat (exp_file_name, ".exp");
1083       delete_exp_file = 1;
1084     }
1085
1086   {
1087     int quote;
1088
1089     dyn_string_t step2 = dyn_string_new (dlltool_cmdline->length
1090                                          + strlen (base_file_name)
1091                                          + strlen (exp_file_name)
1092                                          + 20);
1093
1094     dyn_string_append_cstr (step2, "--base-file ");
1095     quote = (strchr (base_file_name, ' ')
1096              || strchr (base_file_name, '\t'));
1097     dyn_string_append_cstr (step2,
1098                        (quote) ? "\"" : "");
1099     dyn_string_append_cstr (step2, base_file_name);
1100     dyn_string_append_cstr (step2,
1101                        (quote) ? "\" " : " ");
1102
1103     dyn_string_append_cstr (step2, "--output-exp ");
1104     quote = (strchr (exp_file_name, ' ')
1105              || strchr (exp_file_name, '\t'));
1106     dyn_string_append_cstr (step2,
1107                        (quote) ? "\"" : "");
1108     dyn_string_append_cstr (step2, exp_file_name);
1109     dyn_string_append_cstr (step2,
1110                        (quote) ? "\"" : "");
1111
1112     if (dlltool_cmdline->length)
1113       {
1114         dyn_string_append_cstr (step2, " ");
1115         dyn_string_append_cstr (step2, dlltool_cmdline->s);
1116       }
1117
1118     if (run (dlltool_name, step2->s))
1119       cleanup_and_exit (1);
1120
1121     dyn_string_delete (step2);
1122   }
1123
1124   /*
1125    * Step 3. Call GCC/LD to again, adding the exp file this time.
1126    * driver command line will look like the following:
1127    *
1128    *    % gcc -Wl,--dll --Wl,--base-file,foo.base foo.exp [rest ...]
1129    */
1130
1131   {
1132     int quote;
1133
1134     dyn_string_t step3 = dyn_string_new (driver_cmdline->length
1135                                          + strlen (exp_file_name)
1136                                          + strlen (base_file_name)
1137                                          + 20);
1138     dyn_string_append_cstr (step3, "-Wl,--base-file,");
1139     quote = (strchr (base_file_name, ' ')
1140              || strchr (base_file_name, '\t'));
1141     dyn_string_append_cstr (step3,
1142                        (quote) ? "\"" : "");
1143     dyn_string_append_cstr (step3, base_file_name);
1144     dyn_string_append_cstr (step3,
1145                        (quote) ? "\" " : " ");
1146
1147     quote = (strchr (exp_file_name, ' ')
1148              || strchr (exp_file_name, '\t'));
1149     dyn_string_append_cstr (step3,
1150                        (quote) ? "\"" : "");
1151     dyn_string_append_cstr (step3, exp_file_name);
1152     dyn_string_append_cstr (step3,
1153                        (quote) ? "\"" : "");
1154
1155     if (driver_cmdline->length)
1156       {
1157         dyn_string_append_cstr (step3, " ");
1158         dyn_string_append_cstr (step3, driver_cmdline->s);
1159       }
1160
1161     if (run (driver_name, step3->s))
1162       cleanup_and_exit (1);
1163
1164     dyn_string_delete (step3);
1165   }
1166
1167
1168   /*
1169    * Step 4. Run DLLTOOL again using the same command line.
1170    */
1171
1172   {
1173     int quote;
1174     dyn_string_t step4 = dyn_string_new (dlltool_cmdline->length
1175                                          + strlen (base_file_name)
1176                                          + strlen (exp_file_name)
1177                                          + 20);
1178
1179     dyn_string_append_cstr (step4, "--base-file ");
1180     quote = (strchr (base_file_name, ' ')
1181              || strchr (base_file_name, '\t'));
1182     dyn_string_append_cstr (step4,
1183                        (quote) ? "\"" : "");
1184     dyn_string_append_cstr (step4, base_file_name);
1185     dyn_string_append_cstr (step4,
1186                        (quote) ? "\" " : " ");
1187
1188     dyn_string_append_cstr (step4, "--output-exp ");
1189     quote = (strchr (exp_file_name, ' ')
1190              || strchr (exp_file_name, '\t'));
1191     dyn_string_append_cstr (step4,
1192                        (quote) ? "\"" : "");
1193     dyn_string_append_cstr (step4, exp_file_name);
1194     dyn_string_append_cstr (step4,
1195                        (quote) ? "\"" : "");
1196
1197     if (dlltool_cmdline->length)
1198       {
1199         dyn_string_append_cstr (step4, " ");
1200         dyn_string_append_cstr (step4, dlltool_cmdline->s);
1201       }
1202
1203     if (output_lib_file_name)
1204       {
1205         dyn_string_append_cstr (step4, " --output-lib ");
1206         dyn_string_append_cstr (step4, output_lib_file_name);
1207       }
1208
1209     if (run (dlltool_name, step4->s))
1210       cleanup_and_exit (1);
1211
1212     dyn_string_delete (step4);
1213   }
1214
1215
1216   /*
1217    * Step 5. Link it all together and be done with it.
1218    * driver command line will look like the following:
1219    *
1220    *    % gcc -Wl,--dll foo.exp [rest ...]
1221    *
1222    */
1223
1224   {
1225     int quote;
1226
1227     dyn_string_t step5 = dyn_string_new (driver_cmdline->length
1228                                          + strlen (exp_file_name)
1229                                          + 20);
1230     quote = (strchr (exp_file_name, ' ')
1231              || strchr (exp_file_name, '\t'));
1232     dyn_string_append_cstr (step5,
1233                        (quote) ? "\"" : "");
1234     dyn_string_append_cstr (step5, exp_file_name);
1235     dyn_string_append_cstr (step5,
1236                        (quote) ? "\"" : "");
1237
1238     if (driver_cmdline->length)
1239       {
1240         dyn_string_append_cstr (step5, " ");
1241         dyn_string_append_cstr (step5, driver_cmdline->s);
1242       }
1243
1244     if (run (driver_name, step5->s))
1245       cleanup_and_exit (1);
1246
1247     dyn_string_delete (step5);
1248   }
1249
1250   cleanup_and_exit (0);
1251
1252   return 0;
1253 }