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