OSDN Git Service

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