This commit was generated by cvs2svn to track changes on a CVS vendor
[external/binutils.git] / binutils / dllwrap.c
1 /* dllwrap.c -- wrapper for DLLTOOL and GCC to generate PE style DLLs
2    Copyright (C) 1998 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
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33
34 #include <stdio.h>
35 #include <errno.h>
36 #include <string.h>
37 #ifdef HAVE_STDLIB_H
38 #include <stdlib.h>
39 #endif
40 #ifdef HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif
43
44 #include "getopt.h"
45 #include "libiberty.h"
46 #include "dyn-string.h"
47
48 #include <ctype.h>
49 #include <time.h>
50
51 #ifdef HAVE_SYS_WAIT_H
52 #include <sys/wait.h>
53 #else /* ! HAVE_SYS_WAIT_H */
54 #if ! defined (_WIN32) || defined (__CYGWIN32__)
55 #ifndef WIFEXITED
56 #define WIFEXITED(w)    (((w)&0377) == 0)
57 #endif
58 #ifndef WIFSIGNALED
59 #define WIFSIGNALED(w)  (((w)&0377) != 0177 && ((w)&~0377) == 0)
60 #endif
61 #ifndef WTERMSIG
62 #define WTERMSIG(w)     ((w) & 0177)
63 #endif
64 #ifndef WEXITSTATUS
65 #define WEXITSTATUS(w)  (((w) >> 8) & 0377)
66 #endif
67 #else /* defined (_WIN32) && ! defined (__CYGWIN32__) */
68 #ifndef WIFEXITED
69 #define WIFEXITED(w)    (((w) & 0xff) == 0)
70 #endif
71 #ifndef WIFSIGNALED
72 #define WIFSIGNALED(w)  (((w) & 0xff) != 0 && ((w) & 0xff) != 0x7f)
73 #endif
74 #ifndef WTERMSIG
75 #define WTERMSIG(w)     ((w) & 0x7f)
76 #endif
77 #ifndef WEXITSTATUS
78 #define WEXITSTATUS(w)  (((w) & 0xff00) >> 8)
79 #endif
80 #endif /* defined (_WIN32) && ! defined (__CYGWIN32__) */
81 #endif /* ! HAVE_SYS_WAIT_H */
82
83 static char *program_version = "0.2.4";
84 static char *driver_name = "gcc";
85 static char *cygwin32_driver_flags = 
86   "-Wl,--dll -nostartfiles";
87 static char *mingw32_driver_flags = "-mdll";
88 static char *generic_driver_flags = "-Wl,--dll";
89
90 static char *entry_point;
91
92 static char *dlltool_name = "dlltool";
93
94 static char *target = TARGET;
95
96 typedef enum {
97   UNKNOWN_TARGET, 
98   CYGWIN32_TARGET, 
99   MINGW32_TARGET
100
101 target_type;
102
103 static target_type which_target = UNKNOWN_TARGET;
104
105 static int dontdeltemps = 0;
106 static int dry_run = 0;
107
108 static char *program_name;
109
110 static int verbose = 0;
111
112 static char *dll_file_name;
113 static char *dll_name;
114 static char *base_file_name;
115 static char *exp_file_name;
116 static char *def_file_name;
117 static int delete_base_file = 1;
118 static int delete_exp_file = 1;
119 static int delete_def_file = 1;
120
121 static int run PARAMS ((const char *, char *));
122 static void usage PARAMS ((FILE *, int));
123 static void delete_temp_files PARAMS ((void));
124 static void cleanup_and_exit PARAMS ((int status));
125
126 /**********************************************************************/
127
128 static void
129 delete_temp_files ()
130 {
131   if (delete_base_file && base_file_name)
132     {
133       if (verbose)
134         fprintf (stderr, "%s temporary base file %s\n",
135                  dontdeltemps ? "Keeping" : "Deleting",
136                  base_file_name);
137       if (! dontdeltemps)
138         {
139           unlink (base_file_name);
140           free (base_file_name);
141         }
142     }
143   
144   if (delete_exp_file && exp_file_name)
145     {
146       if (verbose)
147         fprintf (stderr, "%s temporary exp file %s\n",
148                  dontdeltemps ? "Keeping" : "Deleting",
149                  exp_file_name);
150       if (! dontdeltemps)
151         {
152           unlink (exp_file_name);
153           free (exp_file_name);
154         }
155     }
156   if (delete_def_file && def_file_name)
157     {
158       if (verbose)
159         fprintf (stderr, "%s temporary def file %s\n",
160                  dontdeltemps ? "Keeping" : "Deleting",
161                  def_file_name);
162       if (! dontdeltemps)
163         {
164           unlink (def_file_name);
165           free (def_file_name);
166         }
167     }
168 }
169
170 static void 
171 cleanup_and_exit (int status)
172 {
173   delete_temp_files ();
174   exit (status);
175 }
176   
177 static int
178 run (what, args)
179      const char *what;
180      char *args;
181 {
182   char *s;
183   int pid, wait_status, retcode;
184   int i;
185   const char **argv;
186   char *errmsg_fmt, *errmsg_arg;
187   char *temp_base = choose_temp_base ();
188   int in_quote;
189   char sep;
190
191   if (verbose || dry_run)
192     fprintf (stderr, "%s %s\n", what, args);
193
194   /* Count the args */
195   i = 0;
196   for (s = args; *s; s++)
197     if (*s == ' ')
198       i++;
199   i++;
200   argv = alloca (sizeof (char *) * (i + 3));
201   i = 0;
202   argv[i++] = what;
203   s = args;
204   while (1)
205     {
206       while (*s == ' ' && *s != 0)
207         s++;
208       if (*s == 0)
209         break;
210       in_quote = (*s == '\'' || *s == '"');
211       sep = (in_quote) ? *s++ : ' ';
212       argv[i++] = s;
213       while (*s != sep && *s != 0)
214         s++;
215       if (*s == 0)
216         break;
217       *s++ = 0;
218       if (in_quote)
219         s++;
220     }
221   argv[i++] = NULL;
222
223   if (dry_run)
224     return 0;
225
226   pid = pexecute (argv[0], (char * const *) argv, program_name, temp_base,
227                   &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
228
229   if (pid == -1)
230     {
231       int errno_val = errno;
232
233       fprintf (stderr, "%s: ", program_name);
234       fprintf (stderr, errmsg_fmt, errmsg_arg);
235       fprintf (stderr, ": %s\n", strerror (errno_val));
236       return 1;
237     }
238
239   retcode = 0;
240   pid = pwait (pid, &wait_status, 0);
241   if (pid == -1)
242     {
243       fprintf (stderr, "%s: wait: %s\n", program_name, strerror (errno));
244       retcode = 1;
245     }
246   else if (WIFSIGNALED (wait_status))
247     {
248       fprintf (stderr, "%s: subprocess got fatal signal %d\n",
249                program_name, WTERMSIG (wait_status));
250       retcode = 1;
251     }
252   else if (WIFEXITED (wait_status))
253     {
254       if (WEXITSTATUS (wait_status) != 0)
255         {
256           fprintf (stderr, "%s: %s exited with status %d\n",
257                    program_name, what, WEXITSTATUS (wait_status));
258           retcode = 1;
259         }
260     }
261   else
262     retcode = 1;
263   
264   return retcode;
265 }
266
267 static char *
268 mybasename (name)
269      const char *name;
270 {
271   const char *base = name;
272
273   while (*name)
274     {
275       if (*name == '/' || *name == '\\')
276         {
277           base = name + 1;
278         }
279       ++name;
280     }
281   return (char *) base;
282 }
283
284 static int 
285 strhash (const char *str)
286 {
287   const unsigned char *s;
288   unsigned long hash;
289   unsigned int c;
290   unsigned int len;
291
292   hash = 0;
293   len = 0;
294   s = (const unsigned char *) str;
295   while ((c = *s++) != '\0')
296     {
297       hash += c + (c << 17);
298       hash ^= hash >> 2;
299       ++len;
300     }
301   hash += len + (len << 17);
302   hash ^= hash >> 2;
303
304   return hash;
305 }
306
307 /**********************************************************************/
308
309 void
310 print_version (name)
311      const char *name;
312 {
313   /* This output is intended to follow the GNU standards document.  */
314   /* xgettext:c-format */
315   printf ("GNU %s %s\n", name, program_version);
316   printf ("Copyright 1998 Free Software Foundation, Inc.\n");
317   printf ("\
318 This program is free software; you may redistribute it under the terms of\n\
319 the GNU General Public License.  This program has absolutely no warranty.\n");
320   exit (0);
321 }
322
323 static void
324 usage (file, status)
325      FILE *file;
326      int status;
327 {
328   fprintf (file, "Usage %s <options> <object-files>\n", program_name);
329   fprintf (file, "  Generic options:\n");
330   fprintf (file, "   --quiet, -q            Work quietly\n");
331   fprintf (file, "   --verbose, -v          Verbose\n");
332   fprintf (file, "   --version              Print dllwrap version\n");
333   fprintf (file, "   --implib <outname>     Synonym for --output-lib\n");
334   fprintf (file, "  Options for %s:\n", program_name);
335   fprintf (file, "   --driver-name <driver> Defaults to \"gcc\"\n");
336   fprintf (file, "   --driver-flags <flags> Override default ld flags\n");
337   fprintf (file, "   --dlltool-name <dlltool> Defaults to \"dlltool\"\n");
338   fprintf (file, "   --entry <entry>        Specify alternate DLL entry point\n");
339   fprintf (file, "   --image-base <base>    Specify image base address\n");
340   fprintf (file, "   --target <machine>     i386-cygwin32 or i386-mingw32\n");
341   fprintf (file, "   --dry-run              Show what needs to be run\n");
342   fprintf (file, "  Options passed to DLLTOOL:\n");
343   fprintf (file, "   --machine <machine>\n");
344   fprintf (file, "   --output-exp <outname> Generate export file.\n");
345   fprintf (file, "   --output-lib <outname> Generate input library.\n");
346   fprintf (file, "   --add-indirect         Add dll indirects to export file.\n");
347   fprintf (file, "   --dllname <name>       Name of input dll to put into output lib.\n");
348   fprintf (file, "   --def <deffile>        Name input .def file\n");
349   fprintf (file, "   --output-def <deffile> Name output .def file\n");
350   fprintf (file, "   --export-all-symbols     Export all symbols to .def\n");
351   fprintf (file, "   --no-export-all-symbols  Only export .drectve symbols\n");
352   fprintf (file, "   --exclude-symbols <list> Exclude <list> from .def\n");
353   fprintf (file, "   --no-default-excludes    Zap default exclude symbols\n");
354   fprintf (file, "   --base-file <basefile> Read linker generated base file\n");
355   fprintf (file, "   --no-idata4           Don't generate idata$4 section\n");
356   fprintf (file, "   --no-idata5           Don't generate idata$5 section\n");
357   fprintf (file, "   -U                     Add underscores to .lib\n");
358   fprintf (file, "   -k                     Kill @<n> from exported names\n");
359   fprintf (file, "   --add-stdcall-alias    Add aliases without @<n>\n");
360   fprintf (file, "   --as <name>            Use <name> for assembler\n");
361   fprintf (file, "   --nodelete             Keep temp files.\n");
362   fprintf (file, "  Rest are passed unmodified to the language driver\n");
363   fprintf (file, "\n\n");
364   exit (status);
365 }
366
367 #define OPTION_START            149
368
369 /* GENERIC options. */
370 #define OPTION_QUIET            (OPTION_START + 1)
371 #define OPTION_VERBOSE          (OPTION_QUIET + 1)
372 #define OPTION_VERSION          (OPTION_VERBOSE + 1)
373
374 /* DLLWRAP options. */
375 #define OPTION_DRY_RUN          (OPTION_VERSION + 1)
376 #define OPTION_DRIVER_NAME      (OPTION_DRY_RUN + 1)
377 #define OPTION_DRIVER_FLAGS     (OPTION_DRIVER_NAME + 1)
378 #define OPTION_DLLTOOL_NAME     (OPTION_DRIVER_FLAGS + 1)
379 #define OPTION_ENTRY            (OPTION_DLLTOOL_NAME + 1)
380 #define OPTION_IMAGE_BASE       (OPTION_ENTRY + 1)
381 #define OPTION_TARGET           (OPTION_IMAGE_BASE + 1)
382
383 /* DLLTOOL options. */
384 #define OPTION_NODELETE         (OPTION_TARGET + 1)
385 #define OPTION_DLLNAME          (OPTION_NODELETE + 1)
386 #define OPTION_NO_IDATA4        (OPTION_DLLNAME + 1)
387 #define OPTION_NO_IDATA5        (OPTION_NO_IDATA4 + 1)
388 #define OPTION_OUTPUT_EXP       (OPTION_NO_IDATA5 + 1)
389 #define OPTION_OUTPUT_DEF       (OPTION_OUTPUT_EXP + 1)
390 #define OPTION_EXPORT_ALL_SYMS  (OPTION_OUTPUT_DEF + 1)
391 #define OPTION_NO_EXPORT_ALL_SYMS (OPTION_EXPORT_ALL_SYMS + 1)
392 #define OPTION_EXCLUDE_SYMS     (OPTION_NO_EXPORT_ALL_SYMS + 1)
393 #define OPTION_NO_DEFAULT_EXCLUDES (OPTION_EXCLUDE_SYMS + 1)
394 #define OPTION_OUTPUT_LIB       (OPTION_NO_DEFAULT_EXCLUDES + 1)
395 #define OPTION_DEF              (OPTION_OUTPUT_LIB + 1)
396 #define OPTION_ADD_UNDERSCORE   (OPTION_DEF + 1)
397 #define OPTION_KILLAT           (OPTION_ADD_UNDERSCORE + 1)
398 #define OPTION_HELP             (OPTION_KILLAT + 1)
399 #define OPTION_MACHINE          (OPTION_HELP + 1)
400 #define OPTION_ADD_INDIRECT     (OPTION_MACHINE + 1)
401 #define OPTION_BASE_FILE        (OPTION_ADD_INDIRECT + 1)
402 #define OPTION_AS               (OPTION_BASE_FILE + 1)
403
404 static const struct option long_options[] =
405 {
406   /* generic options. */
407   {"quiet", no_argument, NULL, 'q'},
408   {"verbose", no_argument, NULL, 'v'},
409   {"version", no_argument, NULL, OPTION_VERSION},
410   {"implib", required_argument, NULL, OPTION_OUTPUT_LIB},
411
412   /* dllwrap options. */
413   {"dry-run", no_argument, NULL, OPTION_DRY_RUN},
414   {"driver-name", required_argument, NULL, OPTION_DRIVER_NAME},
415   {"driver-flags", required_argument, NULL, OPTION_DRIVER_FLAGS},
416   {"dlltool-name", required_argument, NULL, OPTION_DLLTOOL_NAME},
417   {"entry", required_argument, NULL, 'e'},
418   {"image-base", required_argument, NULL, OPTION_IMAGE_BASE},
419   {"target", required_argument, NULL, OPTION_TARGET},
420
421   /* dlltool options. */
422   {"no-delete", no_argument, NULL, 'n'},
423   {"dllname", required_argument, NULL, OPTION_DLLNAME},
424   {"no-idata4", no_argument, NULL, OPTION_NO_IDATA4},
425   {"no-idata5", no_argument, NULL, OPTION_NO_IDATA5},
426   {"output-exp", required_argument, NULL, OPTION_OUTPUT_EXP},
427   {"output-def", required_argument, NULL, OPTION_OUTPUT_DEF},
428   {"export-all-symbols", no_argument, NULL, OPTION_EXPORT_ALL_SYMS},
429   {"no-export-all-symbols", no_argument, NULL, OPTION_NO_EXPORT_ALL_SYMS},
430   {"exclude-symbols", required_argument, NULL, OPTION_EXCLUDE_SYMS},
431   {"no-default-excludes", no_argument, NULL, OPTION_NO_DEFAULT_EXCLUDES},
432   {"output-lib", required_argument, NULL, OPTION_OUTPUT_LIB},
433   {"def", required_argument, NULL, OPTION_DEF},
434   {"add-underscore", no_argument, NULL, 'U'},
435   {"killat", no_argument, NULL, 'k'},
436   {"add-stdcall-alias", no_argument, NULL, 'A'},
437   {"help", no_argument, NULL, 'h'},
438   {"machine", required_argument, NULL, OPTION_MACHINE},
439   {"add-indirect", no_argument, NULL, OPTION_ADD_INDIRECT},
440   {"base-file", required_argument, NULL, OPTION_BASE_FILE},
441   {"as", required_argument, NULL, OPTION_AS},
442   {0}
443 };
444
445 int
446 main (argc, argv)
447      int argc;
448      char **argv;
449 {
450   int c;
451   int i;
452
453   char **saved_argv = 0;
454   int cmdline_len = 0;
455
456   int export_all = 0;
457
458   int *dlltool_arg_indices;
459   int *driver_arg_indices;
460
461   char *driver_flags = 0;
462   char *output_lib_file_name = 0;
463
464   dyn_string_t dlltool_cmdline;
465   dyn_string_t driver_cmdline;
466
467   int def_file_seen = 0;
468
469   char *image_base_str = 0;
470
471   program_name = argv[0];
472
473   saved_argv = (char **) xmalloc (argc * sizeof (char*));
474   dlltool_arg_indices = (int *) xmalloc (argc * sizeof (int));
475   driver_arg_indices = (int *) xmalloc (argc * sizeof (int));
476   for (i = 0; i < argc; ++i) 
477     {
478       size_t len = strlen (argv[i]);
479       char *arg = (char *) xmalloc (len + 1);
480       strcpy (arg, argv[i]);
481       cmdline_len += len;
482       saved_argv[i] = arg;
483       dlltool_arg_indices[i] = 0;
484       driver_arg_indices[i] = 1;
485     }
486   cmdline_len++;
487
488   /* We recognize dllwrap and dlltool options, and everything else is
489      passed onto the language driver (eg., to GCC). We collect options
490      to dlltool and driver in dlltool_args and driver_args. */
491    
492   opterr = 0;
493   while ((c = getopt_long_only (argc, argv, "nkAqve:Uho:l:L:I:", 
494                                 long_options, (int *) 0)) != EOF)
495     {
496       int dlltool_arg;
497       int driver_arg;
498       int single_word_option_value_pair;
499
500       dlltool_arg = 0;
501       driver_arg = 1;
502       single_word_option_value_pair = 0;
503
504       if (c != '?')
505         {
506           /* We recognize this option, so it has to be either dllwrap or
507              dlltool option. Do not pass to driver unless it's one of the
508              generic options that are passed to all the tools (such as -v)
509              which are dealt with later. */
510           driver_arg = 0;
511         }
512
513       /* deal with generic and dllwrap options first. */
514       switch (c)
515         {
516         case 'h':
517           usage (stdout, 0);
518           break;
519         case 'q':
520           verbose = 0;
521           break;
522         case 'v':
523           verbose = 1;
524           break;
525         case OPTION_VERSION:
526           print_version (program_name);
527           break;
528         case 'e':
529           entry_point = optarg;
530           break;
531         case OPTION_IMAGE_BASE:
532           image_base_str = optarg;
533           break;
534         case OPTION_DEF:
535           def_file_name = optarg;
536           def_file_seen = 1;
537           delete_def_file = 0;
538           break;
539         case 'n':
540           dontdeltemps = 1;
541           dlltool_arg = 1;
542           break;
543         case 'o':
544           dll_file_name = optarg;
545           break;
546         case 'I':
547         case 'l':
548         case 'L':
549           driver_arg = 1;
550           break;
551         case OPTION_DLLNAME:
552           dll_name = optarg;
553           break;
554         case OPTION_DRY_RUN:
555           dry_run = 1;
556           break;
557         case OPTION_DRIVER_NAME:
558           driver_name = optarg;
559           break;
560         case OPTION_DRIVER_FLAGS:
561           driver_flags = optarg;
562           break;
563         case OPTION_DLLTOOL_NAME:
564           dlltool_name = optarg;
565           break;
566         case OPTION_TARGET:
567           target = optarg;
568           break;
569         case OPTION_BASE_FILE:
570           base_file_name = optarg;
571           delete_base_file = 0;
572           break;
573         case OPTION_OUTPUT_EXP:
574           exp_file_name = optarg;
575           delete_exp_file = 0;
576           break;
577         case OPTION_EXPORT_ALL_SYMS:
578           export_all = 1;
579           break;
580         case OPTION_OUTPUT_LIB:
581           output_lib_file_name = optarg;
582           break;
583         case '?':
584           break;
585         default:
586           dlltool_arg = 1;
587           break;
588         }
589       
590       /* Handle passing through --option=value case. */
591       if (optarg 
592           && saved_argv[optind-1][0] == '-' 
593           && saved_argv[optind-1][1] == '-' 
594           && strchr (saved_argv[optind-1], '='))
595         single_word_option_value_pair = 1;
596
597       if (dlltool_arg)
598         {
599           dlltool_arg_indices[optind-1] = 1;
600           if (optarg && ! single_word_option_value_pair)
601             {
602               dlltool_arg_indices[optind-2] = 1;
603             } 
604         }
605
606       if (! driver_arg)
607         {
608           driver_arg_indices[optind-1] = 0;
609           if (optarg && ! single_word_option_value_pair)
610             {
611               driver_arg_indices[optind-2] = 0;
612             } 
613         }
614     }
615   
616   /* sanity checks. */
617   if (! dll_name && ! dll_file_name)
618     {
619       fprintf (stderr,
620                "%s: Must provide at least one of -o or --dllname options\n",
621                program_name);
622       exit (1);
623     }
624   else if (! dll_name)
625     {
626       dll_name = xstrdup (mybasename (dll_file_name));
627     }
628   else if (! dll_file_name)
629     {
630       dll_file_name = xstrdup (dll_name);
631     }
632   
633   if (! def_file_seen)
634     {
635       char *fileprefix = choose_temp_base ();
636       def_file_name = (char *) xmalloc (strlen (fileprefix) + 5);
637       sprintf (def_file_name, "%s.def", 
638                (dontdeltemps) ? mybasename (fileprefix) : fileprefix);
639       delete_def_file = 1;
640       free (fileprefix);
641       delete_def_file = 1;
642       fprintf (stderr, "Warning: no export definition file provided\n");
643       fprintf (stderr, 
644                "dllwrap will create one, but may not be what you want\n");
645     }
646   
647   /* set the target platform. */
648   if (strstr (target, "cygwin32"))
649     which_target = CYGWIN32_TARGET;
650   else if (strstr (target, "mingw32"))
651     which_target = MINGW32_TARGET;
652   else 
653     which_target = UNKNOWN_TARGET;
654
655   /* re-create the command lines as a string, taking care to quote stuff. */
656   dlltool_cmdline = dyn_string_new (cmdline_len);
657   if (verbose)
658     {
659       dyn_string_append (dlltool_cmdline, " -v");
660     }
661   dyn_string_append (dlltool_cmdline, " --dllname ");
662   dyn_string_append (dlltool_cmdline, dll_name);
663
664   for (i = 1; i < argc; ++i)
665     {
666       if (dlltool_arg_indices[i])
667         {
668           char *arg = saved_argv[i];
669           int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
670           dyn_string_append (dlltool_cmdline, 
671                              (quote) ? " \"" : " ");
672           dyn_string_append (dlltool_cmdline, arg);
673           dyn_string_append (dlltool_cmdline, 
674                              (quote) ? "\"" : "");
675         }
676     }
677
678   driver_cmdline = dyn_string_new (cmdline_len);
679   if (! driver_flags || strlen (driver_flags) == 0)
680     {
681       switch (which_target)
682         {
683         case CYGWIN32_TARGET:
684           driver_flags = cygwin32_driver_flags;
685           break;
686         
687         case MINGW32_TARGET:
688           driver_flags = mingw32_driver_flags;
689           break;
690         
691         default:
692           driver_flags = generic_driver_flags;
693           break;
694         }
695     }
696   dyn_string_append (driver_cmdline, driver_flags);
697   dyn_string_append (driver_cmdline, " -o ");
698   dyn_string_append (driver_cmdline, dll_file_name);
699
700   if (! entry_point || strlen (entry_point) == 0)
701     {
702       switch (which_target)
703         {
704         case CYGWIN32_TARGET:
705           entry_point = "__cygwin32_dll_entry@12";
706           break;
707         
708         case MINGW32_TARGET:
709           entry_point = "_DllMainCRTStartup@12";
710           break;
711         
712         default:
713           entry_point = "_DllMain@12";
714           break;
715         }
716     }
717   dyn_string_append (driver_cmdline, " -Wl,-e,");
718   dyn_string_append (driver_cmdline, entry_point);
719   dyn_string_append (dlltool_cmdline, " --exclude-symbol=");
720   dyn_string_append (dlltool_cmdline, 
721                      (entry_point[0] == '_') ? entry_point+1 : entry_point);
722
723   if (! image_base_str || strlen (image_base_str) == 0)
724     {
725       char *tmpbuf = (char *) xmalloc (sizeof ("0x12345678") + 1);
726       unsigned long hash = strhash (dll_file_name);
727       sprintf (tmpbuf, "0x%.8X", 0x60000000|((hash<<16)&0xFFC0000));
728       image_base_str = tmpbuf;
729     }
730
731   dyn_string_append (driver_cmdline, " -Wl,--image-base,");
732   dyn_string_append (driver_cmdline, image_base_str);
733
734   if (verbose)
735     {
736       dyn_string_append (driver_cmdline, " -v");
737     }
738
739   for (i = 1; i < argc; ++i)
740     {
741       if (driver_arg_indices[i])
742         {
743           char *arg = saved_argv[i];
744           int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
745           dyn_string_append (driver_cmdline, 
746                              (quote) ? " \"" : " ");
747           dyn_string_append (driver_cmdline, arg);
748           dyn_string_append (driver_cmdline, 
749                              (quote) ? "\"" : "");
750         }
751     }
752   
753   /*
754    * Step pre-1. If no --def <EXPORT_DEF> is specified, then create it
755    * and then pass it on.
756    */
757   
758   if (! def_file_seen) 
759     {
760       int i;
761       dyn_string_t step_pre1;
762
763       step_pre1 = dyn_string_new (1024);
764
765       dyn_string_append (step_pre1, dlltool_cmdline->s);
766       if (export_all)
767         {
768           dyn_string_append (step_pre1, " --export-all --exclude-symbol=");
769           dyn_string_append (step_pre1, 
770           "_cygwin32_dll_entry@12,DllMainCRTStartup@12,DllMain@12,DllEntryPoint@12");
771         }
772       dyn_string_append (step_pre1, " --output-def ");
773       dyn_string_append (step_pre1, def_file_name);
774
775       for (i = 1; i < argc; ++i)
776         {
777           if (driver_arg_indices[i])
778             {
779               char *arg = saved_argv[i];
780               size_t len = strlen (arg);
781               if (len >= 2 && arg[len-2] == '.' 
782                   && (arg[len-1] == 'o' || arg[len-1] == 'a'))
783                 {
784                   int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
785                   dyn_string_append (step_pre1,
786                                      (quote) ? " \"" : " ");
787                   dyn_string_append (step_pre1, arg);
788                   dyn_string_append (step_pre1,
789                                      (quote) ? "\"" : "");
790                 }
791             }
792         }
793
794       if (run (dlltool_name, step_pre1->s))
795         cleanup_and_exit (1);
796       
797       dyn_string_delete (step_pre1);
798     }
799
800   dyn_string_append (dlltool_cmdline, " --def ");
801   dyn_string_append (dlltool_cmdline, def_file_name);
802
803   if (verbose)
804     {
805       fprintf (stderr, "DLLTOOL name    : %s\n", dlltool_name);
806       fprintf (stderr, "DLLTOOL options : %s\n", dlltool_cmdline->s);
807       fprintf (stderr, "DRIVER name     : %s\n", driver_name);
808       fprintf (stderr, "DRIVER options  : %s\n", driver_cmdline->s);
809     }
810  
811   /*
812    * Step 1. Call GCC/LD to create base relocation file. If using GCC, the
813    * driver command line will look like the following:
814    *    
815    *    % gcc -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
816    *
817    * If the user does not specify a base name, create temporary one that
818    * is deleted at exit.
819    *
820    */
821   
822   if (! base_file_name)
823     {
824       char *fileprefix = choose_temp_base ();
825       base_file_name = (char *) xmalloc (strlen (fileprefix) + 6);
826       sprintf (base_file_name, "%s.base", 
827                (dontdeltemps) ? mybasename (fileprefix) : fileprefix);
828       delete_base_file = 1;
829       free (fileprefix);
830     }
831   
832   {
833     int quote;
834
835     dyn_string_t step1 = dyn_string_new (driver_cmdline->length 
836                                          + strlen (base_file_name)
837                                          + 20);
838     dyn_string_append (step1, "-Wl,--base-file,");
839     quote = (strchr (base_file_name, ' ') 
840              || strchr (base_file_name, '\t'));
841     dyn_string_append (step1, 
842                        (quote) ? "\"" : "");
843     dyn_string_append (step1, base_file_name);
844     dyn_string_append (step1, 
845                        (quote) ? "\"" : "");
846     if (driver_cmdline->length)
847       {
848         dyn_string_append (step1, " ");
849         dyn_string_append (step1, driver_cmdline->s);
850       }
851
852     if (run (driver_name, step1->s))
853       cleanup_and_exit (1);
854     
855     dyn_string_delete (step1);
856   }
857
858
859
860   /*
861    * Step 2. generate the exp file by running dlltool. 
862    * dlltool command line will look like the following:
863    *    
864    *    % dlltool -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
865    *
866    * If the user does not specify a base name, create temporary one that
867    * is deleted at exit.
868    *
869    */
870   
871   if (! exp_file_name)
872     {
873       char *p = strrchr (dll_name, '.');
874       size_t prefix_len = (p) ? p - dll_name : strlen (dll_name);
875       exp_file_name = (char *) xmalloc (prefix_len + 4 + 1);
876       strncpy (exp_file_name, dll_name, prefix_len);
877       exp_file_name[prefix_len] = '\0';
878       strcat (exp_file_name, ".exp");
879       delete_exp_file = 1;
880     }
881   
882   {
883     int quote;
884     dyn_string_t step2 = dyn_string_new (dlltool_cmdline->length 
885                                          + strlen (base_file_name)
886                                          + strlen (exp_file_name)
887                                          + 20);
888
889     dyn_string_append (step2, "--base-file ");
890     quote = (strchr (base_file_name, ' ') 
891              || strchr (base_file_name, '\t'));
892     dyn_string_append (step2, 
893                        (quote) ? "\"" : "");
894     dyn_string_append (step2, base_file_name);
895     dyn_string_append (step2, 
896                        (quote) ? "\" " : " ");
897
898     dyn_string_append (step2, "--output-exp ");
899     quote = (strchr (exp_file_name, ' ') 
900              || strchr (exp_file_name, '\t'));
901     dyn_string_append (step2, 
902                        (quote) ? "\"" : "");
903     dyn_string_append (step2, exp_file_name);
904     dyn_string_append (step2, 
905                        (quote) ? "\"" : "");
906
907     if (dlltool_cmdline->length)
908       {
909         dyn_string_append (step2, " ");
910         dyn_string_append (step2, dlltool_cmdline->s);
911       }
912
913     if (run (dlltool_name, step2->s))
914       cleanup_and_exit (1);
915     
916     dyn_string_delete (step2);
917   }
918
919   /*
920    * Step 3. Call GCC/LD to again, adding the exp file this time.
921    * driver command line will look like the following:
922    *    
923    *    % gcc -Wl,--dll --Wl,--base-file,foo.base foo.exp [rest ...]
924    */
925
926   {
927     int quote;
928
929     dyn_string_t step3 = dyn_string_new (driver_cmdline->length 
930                                          + strlen (exp_file_name)
931                                          + strlen (base_file_name)
932                                          + 20);
933     dyn_string_append (step3, "-Wl,--base-file,");
934     quote = (strchr (base_file_name, ' ') 
935              || strchr (base_file_name, '\t'));
936     dyn_string_append (step3, 
937                        (quote) ? "\"" : "");
938     dyn_string_append (step3, base_file_name);
939     dyn_string_append (step3, 
940                        (quote) ? "\" " : " ");
941
942     quote = (strchr (exp_file_name, ' ') 
943              || strchr (exp_file_name, '\t'));
944     dyn_string_append (step3, 
945                        (quote) ? "\"" : "");
946     dyn_string_append (step3, exp_file_name);
947     dyn_string_append (step3, 
948                        (quote) ? "\"" : "");
949
950     if (driver_cmdline->length)
951       {
952         dyn_string_append (step3, " ");
953         dyn_string_append (step3, driver_cmdline->s);
954       }
955
956     if (run (driver_name, step3->s))
957       cleanup_and_exit (1);
958     
959     dyn_string_delete (step3);
960   }
961
962
963   /*
964    * Step 4. Run DLLTOOL again using the same command line.
965    */
966
967   {
968     int quote;
969     dyn_string_t step4 = dyn_string_new (dlltool_cmdline->length 
970                                          + strlen (base_file_name)
971                                          + strlen (exp_file_name)
972                                          + 20);
973
974     dyn_string_append (step4, "--base-file ");
975     quote = (strchr (base_file_name, ' ') 
976              || strchr (base_file_name, '\t'));
977     dyn_string_append (step4, 
978                        (quote) ? "\"" : "");
979     dyn_string_append (step4, base_file_name);
980     dyn_string_append (step4, 
981                        (quote) ? "\" " : " ");
982
983     dyn_string_append (step4, "--output-exp ");
984     quote = (strchr (exp_file_name, ' ') 
985              || strchr (exp_file_name, '\t'));
986     dyn_string_append (step4, 
987                        (quote) ? "\"" : "");
988     dyn_string_append (step4, exp_file_name);
989     dyn_string_append (step4, 
990                        (quote) ? "\"" : "");
991
992     if (dlltool_cmdline->length)
993       {
994         dyn_string_append (step4, " ");
995         dyn_string_append (step4, dlltool_cmdline->s);
996       }
997
998     if (output_lib_file_name)
999       {
1000         dyn_string_append (step4, " --output-lib ");
1001         dyn_string_append (step4, output_lib_file_name);
1002       }
1003
1004     if (run (dlltool_name, step4->s))
1005       cleanup_and_exit (1);
1006     
1007     dyn_string_delete (step4);
1008   }
1009   
1010
1011   /*
1012    * Step 5. Link it all together and be done with it.
1013    * driver command line will look like the following:
1014    *    
1015    *    % gcc -Wl,--dll foo.exp [rest ...]
1016    *
1017    */
1018
1019   {
1020     int quote;
1021
1022     dyn_string_t step5 = dyn_string_new (driver_cmdline->length 
1023                                          + strlen (exp_file_name)
1024                                          + 20);
1025     quote = (strchr (exp_file_name, ' ') 
1026              || strchr (exp_file_name, '\t'));
1027     dyn_string_append (step5, 
1028                        (quote) ? "\"" : "");
1029     dyn_string_append (step5, exp_file_name);
1030     dyn_string_append (step5, 
1031                        (quote) ? "\"" : "");
1032
1033     if (driver_cmdline->length)
1034       {
1035         dyn_string_append (step5, " ");
1036         dyn_string_append (step5, driver_cmdline->s);
1037       }
1038
1039     if (run (driver_name, step5->s))
1040       cleanup_and_exit (1);
1041     
1042     dyn_string_delete (step5);
1043   }
1044
1045   cleanup_and_exit (0);
1046
1047   return 0;
1048 }