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