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