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