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
display(const char * message,va_list args)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
inform(const char * message,...)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
warn(const char * format,...)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 *
look_for_prog(const char * prog_name,const char * prefix,int end_prefix)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 *
deduce_name(const char * prog_name)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
delete_temp_files(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
cleanup_and_exit(int status)346 cleanup_and_exit (int status)
347 {
348   delete_temp_files ();
349   exit (status);
350 }
351 
352 static int
run(const char * what,char * args)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 *
mybasename(const char * name)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
strhash(const char * str)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
usage(FILE * file,int status)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
main(int argc,char ** argv)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 }
1221