remove VA_* from binutils
[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, 2014 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 (const char *message, ...)
148 {
149   va_list args;
150
151   va_start (args, message);
152
153   if (!verbose)
154     return;
155
156   display (message, args);
157
158   va_end (args);
159 }
160
161 static void
162 warn (const char *format, ...)
163 {
164   va_list args;
165
166   va_start (args, format);
167
168   display (format, args);
169
170   va_end (args);
171 }
172
173 /* Look for the program formed by concatenating PROG_NAME and the
174    string running from PREFIX to END_PREFIX.  If the concatenated
175    string contains a '/', try appending EXECUTABLE_SUFFIX if it is
176    appropriate.  */
177
178 static char *
179 look_for_prog (const char *progname, const char *prefix, int end_prefix)
180 {
181   struct stat s;
182   char *cmd;
183
184   cmd = xmalloc (strlen (prefix)
185                  + strlen (progname)
186 #ifdef HAVE_EXECUTABLE_SUFFIX
187                  + strlen (EXECUTABLE_SUFFIX)
188 #endif
189                  + 10);
190   strcpy (cmd, prefix);
191
192   sprintf (cmd + end_prefix, "%s", progname);
193
194   if (strchr (cmd, '/') != NULL)
195     {
196       int found;
197
198       found = (stat (cmd, &s) == 0
199 #ifdef HAVE_EXECUTABLE_SUFFIX
200                || stat (strcat (cmd, EXECUTABLE_SUFFIX), &s) == 0
201 #endif
202                );
203
204       if (! found)
205         {
206           /* xgettext:c-format */
207           inform (_("Tried file: %s"), cmd);
208           free (cmd);
209           return NULL;
210         }
211     }
212
213   /* xgettext:c-format */
214   inform (_("Using file: %s"), cmd);
215
216   return cmd;
217 }
218
219 /* Deduce the name of the program we are want to invoke.
220    PROG_NAME is the basic name of the program we want to run,
221    eg "as" or "ld".  The catch is that we might want actually
222    run "i386-pe-as" or "ppc-pe-ld".
223
224    If argv[0] contains the full path, then try to find the program
225    in the same place, with and then without a target-like prefix.
226
227    Given, argv[0] = /usr/local/bin/i586-cygwin32-dlltool,
228    deduce_name("as") uses the following search order:
229
230      /usr/local/bin/i586-cygwin32-as
231      /usr/local/bin/as
232      as
233
234    If there's an EXECUTABLE_SUFFIX, it'll use that as well; for each
235    name, it'll try without and then with EXECUTABLE_SUFFIX.
236
237    Given, argv[0] = i586-cygwin32-dlltool, it will not even try "as"
238    as the fallback, but rather return i586-cygwin32-as.
239
240    Oh, and given, argv[0] = dlltool, it'll return "as".
241
242    Returns a dynamically allocated string.  */
243
244 static char *
245 deduce_name (const char * name)
246 {
247   char *cmd;
248   const char *dash;
249   const char *slash;
250   const char *cp;
251
252   dash = NULL;
253   slash = NULL;
254   for (cp = prog_name; *cp != '\0'; ++cp)
255     {
256       if (*cp == '-')
257         dash = cp;
258
259       if (
260 #if defined(__DJGPP__) || defined (__CYGWIN__) || defined(__WIN32__)
261           *cp == ':' || *cp == '\\' ||
262 #endif
263           *cp == '/')
264         {
265           slash = cp;
266           dash = NULL;
267         }
268     }
269
270   cmd = NULL;
271
272   if (dash != NULL)
273     /* First, try looking for a prefixed NAME in the
274        PROG_NAME directory, with the same prefix as PROG_NAME.  */
275     cmd = look_for_prog (name, prog_name, dash - prog_name + 1);
276
277   if (slash != NULL && cmd == NULL)
278     /* Next, try looking for a NAME in the same directory as
279        that of this program.  */
280     cmd = look_for_prog (name, prog_name, slash - prog_name + 1);
281
282   if (cmd == NULL)
283     /* Just return NAME as is.  */
284     cmd = xstrdup (name);
285
286   return cmd;
287 }
288
289 static void
290 delete_temp_files (void)
291 {
292   if (delete_base_file && base_file_name)
293     {
294       if (verbose)
295         {
296           if (dontdeltemps)
297             warn (_("Keeping temporary base file %s"), base_file_name);
298           else
299             warn (_("Deleting temporary base file %s"), base_file_name);
300         }
301       if (! dontdeltemps)
302         {
303           unlink (base_file_name);
304           free (base_file_name);
305         }
306     }
307
308   if (delete_exp_file && exp_file_name)
309     {
310       if (verbose)
311         {
312           if (dontdeltemps)
313             warn (_("Keeping temporary exp file %s"), exp_file_name);
314           else
315             warn (_("Deleting temporary exp file %s"), exp_file_name);
316         }
317       if (! dontdeltemps)
318         {
319           unlink (exp_file_name);
320           free (exp_file_name);
321         }
322     }
323   if (delete_def_file && def_file_name)
324     {
325       if (verbose)
326         {
327           if (dontdeltemps)
328             warn (_("Keeping temporary def file %s"), def_file_name);
329           else
330             warn (_("Deleting temporary def file %s"), def_file_name);
331         }
332       if (! dontdeltemps)
333         {
334           unlink (def_file_name);
335           free (def_file_name);
336         }
337     }
338 }
339
340 static void
341 cleanup_and_exit (int status)
342 {
343   delete_temp_files ();
344   exit (status);
345 }
346
347 static int
348 run (const char *what, char *args)
349 {
350   char *s;
351   int pid, wait_status, retcode;
352   int i;
353   const char **argv;
354   char *errmsg_fmt, *errmsg_arg;
355   char *temp_base = choose_temp_base ();
356   int in_quote;
357   char sep;
358
359   if (verbose || dry_run)
360     fprintf (stderr, "%s %s\n", what, args);
361
362   /* Count the args */
363   i = 0;
364   for (s = args; *s; s++)
365     if (*s == ' ')
366       i++;
367   i++;
368   argv = alloca (sizeof (char *) * (i + 3));
369   i = 0;
370   argv[i++] = what;
371   s = args;
372   while (1)
373     {
374       while (*s == ' ' && *s != 0)
375         s++;
376       if (*s == 0)
377         break;
378       in_quote = (*s == '\'' || *s == '"');
379       sep = (in_quote) ? *s++ : ' ';
380       argv[i++] = s;
381       while (*s != sep && *s != 0)
382         s++;
383       if (*s == 0)
384         break;
385       *s++ = 0;
386       if (in_quote)
387         s++;
388     }
389   argv[i++] = NULL;
390
391   if (dry_run)
392     return 0;
393
394   pid = pexecute (argv[0], (char * const *) argv, prog_name, temp_base,
395                   &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
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 }