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