2005-01-03 Paolo Bonzini <bonzini@gnu.org>
[binutils.git] / binutils / dllwrap.c
blob577772f1cdfbeffa05c919b613e361d9e32dee75
1 /* dllwrap.c -- wrapper for DLLTOOL and GCC to generate PE style DLLs
2 Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
3 Contributed by Mumit Khan (khan@xraylith.wisc.edu).
5 This file is part of GNU Binutils.
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.
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.
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. */
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
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
33 #include "bfd.h"
34 #include "libiberty.h"
35 #include "bucomm.h"
36 #include "getopt.h"
37 #include "dyn-string.h"
39 #include <time.h>
40 #include <sys/stat.h>
42 #ifdef ANSI_PROTOTYPES
43 #include <stdarg.h>
44 #else
45 #include <varargs.h>
46 #endif
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 */
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";
86 static char *entry_point;
88 static char *dlltool_name = NULL;
90 static char *target = TARGET;
92 typedef enum {
93 UNKNOWN_TARGET,
94 CYGWIN_TARGET,
95 MINGW_TARGET
97 target_type;
99 static target_type which_target = UNKNOWN_TARGET;
101 static int dontdeltemps = 0;
102 static int dry_run = 0;
104 static char *prog_name;
106 static int verbose = 0;
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;
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);
129 /**********************************************************************/
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. */
139 static void
140 display (const char * message, va_list args)
142 if (prog_name != NULL)
143 fprintf (stderr, "%s: ", prog_name);
145 vfprintf (stderr, message, args);
146 fputc ('\n', stderr);
150 static void
151 inform VPARAMS ((const char *message, ...))
153 VA_OPEN (args, message);
154 VA_FIXEDARG (args, const char *, message);
156 if (!verbose)
157 return;
159 display (message, args);
161 VA_CLOSE (args);
164 static void
165 warn VPARAMS ((const char *format, ...))
167 VA_OPEN (args, format);
168 VA_FIXEDARG (args, const char *, format);
170 display (format, args);
172 VA_CLOSE (args);
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. */
180 static char *
181 look_for_prog (const char *prog_name, const char *prefix, int end_prefix)
183 struct stat s;
184 char *cmd;
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);
194 sprintf (cmd + end_prefix, "%s", prog_name);
196 if (strchr (cmd, '/') != NULL)
198 int found;
200 found = (stat (cmd, &s) == 0
201 #ifdef HAVE_EXECUTABLE_SUFFIX
202 || stat (strcat (cmd, EXECUTABLE_SUFFIX), &s) == 0
203 #endif
206 if (! found)
208 /* xgettext:c-format */
209 inform (_("Tried file: %s"), cmd);
210 free (cmd);
211 return NULL;
215 /* xgettext:c-format */
216 inform (_("Using file: %s"), cmd);
218 return cmd;
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".
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.
229 Given, argv[0] = /usr/local/bin/i586-cygwin32-dlltool,
230 deduce_name("as") uses the following search order:
232 /usr/local/bin/i586-cygwin32-as
233 /usr/local/bin/as
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.
239 Given, argv[0] = i586-cygwin32-dlltool, it will not even try "as"
240 as the fallback, but rather return i586-cygwin32-as.
242 Oh, and given, argv[0] = dlltool, it'll return "as".
244 Returns a dynamically allocated string. */
246 static char *
247 deduce_name (const char * name)
249 char *cmd;
250 const char *dash;
251 const char *slash;
252 const char *cp;
254 dash = NULL;
255 slash = NULL;
256 for (cp = prog_name; *cp != '\0'; ++cp)
258 if (*cp == '-')
259 dash = cp;
261 if (
262 #if defined(__DJGPP__) || defined (__CYGWIN__) || defined(__WIN32__)
263 *cp == ':' || *cp == '\\' ||
264 #endif
265 *cp == '/')
267 slash = cp;
268 dash = NULL;
272 cmd = NULL;
274 if (dash != NULL)
275 /* First, try looking for a prefixed NAME in the
276 PROG_NAME directory, with the same prefix as PROG_NAME. */
277 cmd = look_for_prog (name, prog_name, dash - prog_name + 1);
279 if (slash != NULL && cmd == NULL)
280 /* Next, try looking for a NAME in the same directory as
281 that of this program. */
282 cmd = look_for_prog (name, prog_name, slash - prog_name + 1);
284 if (cmd == NULL)
285 /* Just return NAME as is. */
286 cmd = xstrdup (name);
288 return cmd;
291 static void
292 delete_temp_files (void)
294 if (delete_base_file && base_file_name)
296 if (verbose)
298 if (dontdeltemps)
299 warn (_("Keeping temporary base file %s"), base_file_name);
300 else
301 warn (_("Deleting temporary base file %s"), base_file_name);
303 if (! dontdeltemps)
305 unlink (base_file_name);
306 free (base_file_name);
310 if (delete_exp_file && exp_file_name)
312 if (verbose)
314 if (dontdeltemps)
315 warn (_("Keeping temporary exp file %s"), exp_file_name);
316 else
317 warn (_("Deleting temporary exp file %s"), exp_file_name);
319 if (! dontdeltemps)
321 unlink (exp_file_name);
322 free (exp_file_name);
325 if (delete_def_file && def_file_name)
327 if (verbose)
329 if (dontdeltemps)
330 warn (_("Keeping temporary def file %s"), def_file_name);
331 else
332 warn (_("Deleting temporary def file %s"), def_file_name);
334 if (! dontdeltemps)
336 unlink (def_file_name);
337 free (def_file_name);
342 static void
343 cleanup_and_exit (int status)
345 delete_temp_files ();
346 exit (status);
349 static int
350 run (const char *what, char *args)
352 char *s;
353 int pid, wait_status, retcode;
354 int i;
355 const char **argv;
356 char *errmsg_fmt, *errmsg_arg;
357 char *temp_base = choose_temp_base ();
358 int in_quote;
359 char sep;
361 if (verbose || dry_run)
362 fprintf (stderr, "%s %s\n", what, args);
364 /* Count the args */
365 i = 0;
366 for (s = args; *s; s++)
367 if (*s == ' ')
368 i++;
369 i++;
370 argv = alloca (sizeof (char *) * (i + 3));
371 i = 0;
372 argv[i++] = what;
373 s = args;
374 while (1)
376 while (*s == ' ' && *s != 0)
377 s++;
378 if (*s == 0)
379 break;
380 in_quote = (*s == '\'' || *s == '"');
381 sep = (in_quote) ? *s++ : ' ';
382 argv[i++] = s;
383 while (*s != sep && *s != 0)
384 s++;
385 if (*s == 0)
386 break;
387 *s++ = 0;
388 if (in_quote)
389 s++;
391 argv[i++] = NULL;
393 if (dry_run)
394 return 0;
396 pid = pexecute (argv[0], (char * const *) argv, prog_name, temp_base,
397 &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
399 if (pid == -1)
401 int errno_val = errno;
403 fprintf (stderr, "%s: ", prog_name);
404 fprintf (stderr, errmsg_fmt, errmsg_arg);
405 fprintf (stderr, ": %s\n", strerror (errno_val));
406 return 1;
409 retcode = 0;
410 pid = pwait (pid, &wait_status, 0);
411 if (pid == -1)
413 warn ("wait: %s", strerror (errno));
414 retcode = 1;
416 else if (WIFSIGNALED (wait_status))
418 warn (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
419 retcode = 1;
421 else if (WIFEXITED (wait_status))
423 if (WEXITSTATUS (wait_status) != 0)
425 warn (_("%s exited with status %d"), what, WEXITSTATUS (wait_status));
426 retcode = 1;
429 else
430 retcode = 1;
432 return retcode;
435 static char *
436 mybasename (const char *name)
438 const char *base = name;
440 while (*name)
442 if (*name == '/' || *name == '\\')
444 base = name + 1;
446 ++name;
448 return (char *) base;
451 static int
452 strhash (const char *str)
454 const unsigned char *s;
455 unsigned long hash;
456 unsigned int c;
457 unsigned int len;
459 hash = 0;
460 len = 0;
461 s = (const unsigned char *) str;
462 while ((c = *s++) != '\0')
464 hash += c + (c << 17);
465 hash ^= hash >> 2;
466 ++len;
468 hash += len + (len << 17);
469 hash ^= hash >> 2;
471 return hash;
474 /**********************************************************************/
476 static void
477 usage (FILE *file, int status)
479 fprintf (file, _("Usage %s <option(s)> <object-file(s)>\n"), prog_name);
480 fprintf (file, _(" Generic options:\n"));
481 fprintf (file, _(" --quiet, -q Work quietly\n"));
482 fprintf (file, _(" --verbose, -v Verbose\n"));
483 fprintf (file, _(" --version Print dllwrap version\n"));
484 fprintf (file, _(" --implib <outname> Synonym for --output-lib\n"));
485 fprintf (file, _(" Options for %s:\n"), prog_name);
486 fprintf (file, _(" --driver-name <driver> Defaults to \"gcc\"\n"));
487 fprintf (file, _(" --driver-flags <flags> Override default ld flags\n"));
488 fprintf (file, _(" --dlltool-name <dlltool> Defaults to \"dlltool\"\n"));
489 fprintf (file, _(" --entry <entry> Specify alternate DLL entry point\n"));
490 fprintf (file, _(" --image-base <base> Specify image base address\n"));
491 fprintf (file, _(" --target <machine> i386-cygwin32 or i386-mingw32\n"));
492 fprintf (file, _(" --dry-run Show what needs to be run\n"));
493 fprintf (file, _(" --mno-cygwin Create Mingw DLL\n"));
494 fprintf (file, _(" Options passed to DLLTOOL:\n"));
495 fprintf (file, _(" --machine <machine>\n"));
496 fprintf (file, _(" --output-exp <outname> Generate export file.\n"));
497 fprintf (file, _(" --output-lib <outname> Generate input library.\n"));
498 fprintf (file, _(" --add-indirect Add dll indirects to export file.\n"));
499 fprintf (file, _(" --dllname <name> Name of input dll to put into output lib.\n"));
500 fprintf (file, _(" --def <deffile> Name input .def file\n"));
501 fprintf (file, _(" --output-def <deffile> Name output .def file\n"));
502 fprintf (file, _(" --export-all-symbols Export all symbols to .def\n"));
503 fprintf (file, _(" --no-export-all-symbols Only export .drectve symbols\n"));
504 fprintf (file, _(" --exclude-symbols <list> Exclude <list> from .def\n"));
505 fprintf (file, _(" --no-default-excludes Zap default exclude symbols\n"));
506 fprintf (file, _(" --base-file <basefile> Read linker generated base file\n"));
507 fprintf (file, _(" --no-idata4 Don't generate idata$4 section\n"));
508 fprintf (file, _(" --no-idata5 Don't generate idata$5 section\n"));
509 fprintf (file, _(" -U Add underscores to .lib\n"));
510 fprintf (file, _(" -k Kill @<n> from exported names\n"));
511 fprintf (file, _(" --add-stdcall-alias Add aliases without @<n>\n"));
512 fprintf (file, _(" --as <name> Use <name> for assembler\n"));
513 fprintf (file, _(" --nodelete Keep temp files.\n"));
514 fprintf (file, _(" Rest are passed unmodified to the language driver\n"));
515 fprintf (file, "\n\n");
516 exit (status);
519 #define OPTION_START 149
521 /* GENERIC options. */
522 #define OPTION_QUIET (OPTION_START + 1)
523 #define OPTION_VERBOSE (OPTION_QUIET + 1)
524 #define OPTION_VERSION (OPTION_VERBOSE + 1)
526 /* DLLWRAP options. */
527 #define OPTION_DRY_RUN (OPTION_VERSION + 1)
528 #define OPTION_DRIVER_NAME (OPTION_DRY_RUN + 1)
529 #define OPTION_DRIVER_FLAGS (OPTION_DRIVER_NAME + 1)
530 #define OPTION_DLLTOOL_NAME (OPTION_DRIVER_FLAGS + 1)
531 #define OPTION_ENTRY (OPTION_DLLTOOL_NAME + 1)
532 #define OPTION_IMAGE_BASE (OPTION_ENTRY + 1)
533 #define OPTION_TARGET (OPTION_IMAGE_BASE + 1)
534 #define OPTION_MNO_CYGWIN (OPTION_TARGET + 1)
536 /* DLLTOOL options. */
537 #define OPTION_NODELETE (OPTION_MNO_CYGWIN + 1)
538 #define OPTION_DLLNAME (OPTION_NODELETE + 1)
539 #define OPTION_NO_IDATA4 (OPTION_DLLNAME + 1)
540 #define OPTION_NO_IDATA5 (OPTION_NO_IDATA4 + 1)
541 #define OPTION_OUTPUT_EXP (OPTION_NO_IDATA5 + 1)
542 #define OPTION_OUTPUT_DEF (OPTION_OUTPUT_EXP + 1)
543 #define OPTION_EXPORT_ALL_SYMS (OPTION_OUTPUT_DEF + 1)
544 #define OPTION_NO_EXPORT_ALL_SYMS (OPTION_EXPORT_ALL_SYMS + 1)
545 #define OPTION_EXCLUDE_SYMS (OPTION_NO_EXPORT_ALL_SYMS + 1)
546 #define OPTION_NO_DEFAULT_EXCLUDES (OPTION_EXCLUDE_SYMS + 1)
547 #define OPTION_OUTPUT_LIB (OPTION_NO_DEFAULT_EXCLUDES + 1)
548 #define OPTION_DEF (OPTION_OUTPUT_LIB + 1)
549 #define OPTION_ADD_UNDERSCORE (OPTION_DEF + 1)
550 #define OPTION_KILLAT (OPTION_ADD_UNDERSCORE + 1)
551 #define OPTION_HELP (OPTION_KILLAT + 1)
552 #define OPTION_MACHINE (OPTION_HELP + 1)
553 #define OPTION_ADD_INDIRECT (OPTION_MACHINE + 1)
554 #define OPTION_BASE_FILE (OPTION_ADD_INDIRECT + 1)
555 #define OPTION_AS (OPTION_BASE_FILE + 1)
557 static const struct option long_options[] =
559 /* generic options. */
560 {"quiet", no_argument, NULL, 'q'},
561 {"verbose", no_argument, NULL, 'v'},
562 {"version", no_argument, NULL, OPTION_VERSION},
563 {"implib", required_argument, NULL, OPTION_OUTPUT_LIB},
565 /* dllwrap options. */
566 {"dry-run", no_argument, NULL, OPTION_DRY_RUN},
567 {"driver-name", required_argument, NULL, OPTION_DRIVER_NAME},
568 {"driver-flags", required_argument, NULL, OPTION_DRIVER_FLAGS},
569 {"dlltool-name", required_argument, NULL, OPTION_DLLTOOL_NAME},
570 {"entry", required_argument, NULL, 'e'},
571 {"image-base", required_argument, NULL, OPTION_IMAGE_BASE},
572 {"target", required_argument, NULL, OPTION_TARGET},
574 /* dlltool options. */
575 {"no-delete", no_argument, NULL, 'n'},
576 {"dllname", required_argument, NULL, OPTION_DLLNAME},
577 {"no-idata4", no_argument, NULL, OPTION_NO_IDATA4},
578 {"no-idata5", no_argument, NULL, OPTION_NO_IDATA5},
579 {"output-exp", required_argument, NULL, OPTION_OUTPUT_EXP},
580 {"output-def", required_argument, NULL, OPTION_OUTPUT_DEF},
581 {"export-all-symbols", no_argument, NULL, OPTION_EXPORT_ALL_SYMS},
582 {"no-export-all-symbols", no_argument, NULL, OPTION_NO_EXPORT_ALL_SYMS},
583 {"exclude-symbols", required_argument, NULL, OPTION_EXCLUDE_SYMS},
584 {"no-default-excludes", no_argument, NULL, OPTION_NO_DEFAULT_EXCLUDES},
585 {"output-lib", required_argument, NULL, OPTION_OUTPUT_LIB},
586 {"def", required_argument, NULL, OPTION_DEF},
587 {"add-underscore", no_argument, NULL, 'U'},
588 {"killat", no_argument, NULL, 'k'},
589 {"add-stdcall-alias", no_argument, NULL, 'A'},
590 {"help", no_argument, NULL, 'h'},
591 {"machine", required_argument, NULL, OPTION_MACHINE},
592 {"add-indirect", no_argument, NULL, OPTION_ADD_INDIRECT},
593 {"base-file", required_argument, NULL, OPTION_BASE_FILE},
594 {"as", required_argument, NULL, OPTION_AS},
595 {0, 0, 0, 0}
598 int main (int, char **);
601 main (int argc, char **argv)
603 int c;
604 int i;
606 char **saved_argv = 0;
607 int cmdline_len = 0;
609 int export_all = 0;
611 int *dlltool_arg_indices;
612 int *driver_arg_indices;
614 char *driver_flags = 0;
615 char *output_lib_file_name = 0;
617 dyn_string_t dlltool_cmdline;
618 dyn_string_t driver_cmdline;
620 int def_file_seen = 0;
622 char *image_base_str = 0;
624 prog_name = argv[0];
626 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
627 setlocale (LC_MESSAGES, "");
628 #endif
629 #if defined (HAVE_SETLOCALE)
630 setlocale (LC_CTYPE, "");
631 #endif
632 bindtextdomain (PACKAGE, LOCALEDIR);
633 textdomain (PACKAGE);
635 saved_argv = (char **) xmalloc (argc * sizeof (char*));
636 dlltool_arg_indices = (int *) xmalloc (argc * sizeof (int));
637 driver_arg_indices = (int *) xmalloc (argc * sizeof (int));
638 for (i = 0; i < argc; ++i)
640 size_t len = strlen (argv[i]);
641 char *arg = (char *) xmalloc (len + 1);
642 strcpy (arg, argv[i]);
643 cmdline_len += len;
644 saved_argv[i] = arg;
645 dlltool_arg_indices[i] = 0;
646 driver_arg_indices[i] = 1;
648 cmdline_len++;
650 /* We recognize dllwrap and dlltool options, and everything else is
651 passed onto the language driver (eg., to GCC). We collect options
652 to dlltool and driver in dlltool_args and driver_args. */
654 opterr = 0;
655 while ((c = getopt_long_only (argc, argv, "nkAqve:Uho:l:L:I:",
656 long_options, (int *) 0)) != EOF)
658 int dlltool_arg;
659 int driver_arg;
660 int single_word_option_value_pair;
662 dlltool_arg = 0;
663 driver_arg = 1;
664 single_word_option_value_pair = 0;
666 if (c != '?')
668 /* We recognize this option, so it has to be either dllwrap or
669 dlltool option. Do not pass to driver unless it's one of the
670 generic options that are passed to all the tools (such as -v)
671 which are dealt with later. */
672 driver_arg = 0;
675 /* deal with generic and dllwrap options first. */
676 switch (c)
678 case 'h':
679 usage (stdout, 0);
680 break;
681 case 'q':
682 verbose = 0;
683 break;
684 case 'v':
685 verbose = 1;
686 break;
687 case OPTION_VERSION:
688 print_version (prog_name);
689 break;
690 case 'e':
691 entry_point = optarg;
692 break;
693 case OPTION_IMAGE_BASE:
694 image_base_str = optarg;
695 break;
696 case OPTION_DEF:
697 def_file_name = optarg;
698 def_file_seen = 1;
699 delete_def_file = 0;
700 break;
701 case 'n':
702 dontdeltemps = 1;
703 dlltool_arg = 1;
704 break;
705 case 'o':
706 dll_file_name = optarg;
707 break;
708 case 'I':
709 case 'l':
710 case 'L':
711 driver_arg = 1;
712 break;
713 case OPTION_DLLNAME:
714 dll_name = optarg;
715 break;
716 case OPTION_DRY_RUN:
717 dry_run = 1;
718 break;
719 case OPTION_DRIVER_NAME:
720 driver_name = optarg;
721 break;
722 case OPTION_DRIVER_FLAGS:
723 driver_flags = optarg;
724 break;
725 case OPTION_DLLTOOL_NAME:
726 dlltool_name = optarg;
727 break;
728 case OPTION_TARGET:
729 target = optarg;
730 break;
731 case OPTION_MNO_CYGWIN:
732 target = "i386-mingw32";
733 break;
734 case OPTION_BASE_FILE:
735 base_file_name = optarg;
736 delete_base_file = 0;
737 break;
738 case OPTION_OUTPUT_EXP:
739 exp_file_name = optarg;
740 delete_exp_file = 0;
741 break;
742 case OPTION_EXPORT_ALL_SYMS:
743 export_all = 1;
744 break;
745 case OPTION_OUTPUT_LIB:
746 output_lib_file_name = optarg;
747 break;
748 case '?':
749 break;
750 default:
751 dlltool_arg = 1;
752 break;
755 /* Handle passing through --option=value case. */
756 if (optarg
757 && saved_argv[optind-1][0] == '-'
758 && saved_argv[optind-1][1] == '-'
759 && strchr (saved_argv[optind-1], '='))
760 single_word_option_value_pair = 1;
762 if (dlltool_arg)
764 dlltool_arg_indices[optind-1] = 1;
765 if (optarg && ! single_word_option_value_pair)
767 dlltool_arg_indices[optind-2] = 1;
771 if (! driver_arg)
773 driver_arg_indices[optind-1] = 0;
774 if (optarg && ! single_word_option_value_pair)
776 driver_arg_indices[optind-2] = 0;
781 /* Sanity checks. */
782 if (! dll_name && ! dll_file_name)
784 warn (_("Must provide at least one of -o or --dllname options"));
785 exit (1);
787 else if (! dll_name)
789 dll_name = xstrdup (mybasename (dll_file_name));
791 else if (! dll_file_name)
793 dll_file_name = xstrdup (dll_name);
796 /* Deduce driver-name and dlltool-name from our own. */
797 if (driver_name == NULL)
798 driver_name = deduce_name ("gcc");
800 if (dlltool_name == NULL)
801 dlltool_name = deduce_name ("dlltool");
803 if (! def_file_seen)
805 char *fileprefix = choose_temp_base ();
807 def_file_name = (char *) xmalloc (strlen (fileprefix) + 5);
808 sprintf (def_file_name, "%s.def",
809 (dontdeltemps) ? mybasename (fileprefix) : fileprefix);
810 delete_def_file = 1;
811 free (fileprefix);
812 delete_def_file = 1;
813 warn (_("no export definition file provided.\n\
814 Creating one, but that may not be what you want"));
817 /* Set the target platform. */
818 if (strstr (target, "cygwin"))
819 which_target = CYGWIN_TARGET;
820 else if (strstr (target, "mingw"))
821 which_target = MINGW_TARGET;
822 else
823 which_target = UNKNOWN_TARGET;
825 /* Re-create the command lines as a string, taking care to quote stuff. */
826 dlltool_cmdline = dyn_string_new (cmdline_len);
827 if (verbose)
828 dyn_string_append_cstr (dlltool_cmdline, " -v");
830 dyn_string_append_cstr (dlltool_cmdline, " --dllname ");
831 dyn_string_append_cstr (dlltool_cmdline, dll_name);
833 for (i = 1; i < argc; ++i)
835 if (dlltool_arg_indices[i])
837 char *arg = saved_argv[i];
838 int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
839 dyn_string_append_cstr (dlltool_cmdline,
840 (quote) ? " \"" : " ");
841 dyn_string_append_cstr (dlltool_cmdline, arg);
842 dyn_string_append_cstr (dlltool_cmdline,
843 (quote) ? "\"" : "");
847 driver_cmdline = dyn_string_new (cmdline_len);
848 if (! driver_flags || strlen (driver_flags) == 0)
850 switch (which_target)
852 case CYGWIN_TARGET:
853 driver_flags = cygwin_driver_flags;
854 break;
856 case MINGW_TARGET:
857 driver_flags = mingw32_driver_flags;
858 break;
860 default:
861 driver_flags = generic_driver_flags;
862 break;
865 dyn_string_append_cstr (driver_cmdline, driver_flags);
866 dyn_string_append_cstr (driver_cmdline, " -o ");
867 dyn_string_append_cstr (driver_cmdline, dll_file_name);
869 if (! entry_point || strlen (entry_point) == 0)
871 switch (which_target)
873 case CYGWIN_TARGET:
874 entry_point = "__cygwin_dll_entry@12";
875 break;
877 case MINGW_TARGET:
878 entry_point = "_DllMainCRTStartup@12";
879 break;
881 default:
882 entry_point = "_DllMain@12";
883 break;
886 dyn_string_append_cstr (driver_cmdline, " -Wl,-e,");
887 dyn_string_append_cstr (driver_cmdline, entry_point);
888 dyn_string_append_cstr (dlltool_cmdline, " --exclude-symbol=");
889 dyn_string_append_cstr (dlltool_cmdline,
890 (entry_point[0] == '_') ? entry_point+1 : entry_point);
892 if (! image_base_str || strlen (image_base_str) == 0)
894 char *tmpbuf = (char *) xmalloc (sizeof ("0x12345678") + 1);
895 unsigned long hash = strhash (dll_file_name);
896 sprintf (tmpbuf, "0x%.8lX", 0x60000000|((hash<<16)&0xFFC0000));
897 image_base_str = tmpbuf;
900 dyn_string_append_cstr (driver_cmdline, " -Wl,--image-base,");
901 dyn_string_append_cstr (driver_cmdline, image_base_str);
903 if (verbose)
905 dyn_string_append_cstr (driver_cmdline, " -v");
908 for (i = 1; i < argc; ++i)
910 if (driver_arg_indices[i])
912 char *arg = saved_argv[i];
913 int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
914 dyn_string_append_cstr (driver_cmdline,
915 (quote) ? " \"" : " ");
916 dyn_string_append_cstr (driver_cmdline, arg);
917 dyn_string_append_cstr (driver_cmdline,
918 (quote) ? "\"" : "");
922 /* Step pre-1. If no --def <EXPORT_DEF> is specified,
923 then create it and then pass it on. */
925 if (! def_file_seen)
927 int i;
928 dyn_string_t step_pre1;
930 step_pre1 = dyn_string_new (1024);
932 dyn_string_append_cstr (step_pre1, dlltool_cmdline->s);
933 if (export_all)
935 dyn_string_append_cstr (step_pre1, " --export-all --exclude-symbol=");
936 dyn_string_append_cstr (step_pre1,
937 "_cygwin_dll_entry@12,DllMainCRTStartup@12,DllMain@12,DllEntryPoint@12");
939 dyn_string_append_cstr (step_pre1, " --output-def ");
940 dyn_string_append_cstr (step_pre1, def_file_name);
942 for (i = 1; i < argc; ++i)
944 if (driver_arg_indices[i])
946 char *arg = saved_argv[i];
947 size_t len = strlen (arg);
948 if (len >= 2 && arg[len-2] == '.'
949 && (arg[len-1] == 'o' || arg[len-1] == 'a'))
951 int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
952 dyn_string_append_cstr (step_pre1,
953 (quote) ? " \"" : " ");
954 dyn_string_append_cstr (step_pre1, arg);
955 dyn_string_append_cstr (step_pre1,
956 (quote) ? "\"" : "");
961 if (run (dlltool_name, step_pre1->s))
962 cleanup_and_exit (1);
964 dyn_string_delete (step_pre1);
967 dyn_string_append_cstr (dlltool_cmdline, " --def ");
968 dyn_string_append_cstr (dlltool_cmdline, def_file_name);
970 if (verbose)
972 fprintf (stderr, _("DLLTOOL name : %s\n"), dlltool_name);
973 fprintf (stderr, _("DLLTOOL options : %s\n"), dlltool_cmdline->s);
974 fprintf (stderr, _("DRIVER name : %s\n"), driver_name);
975 fprintf (stderr, _("DRIVER options : %s\n"), driver_cmdline->s);
978 /* Step 1. Call GCC/LD to create base relocation file. If using GCC, the
979 driver command line will look like the following:
981 % gcc -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
983 If the user does not specify a base name, create temporary one that
984 is deleted at exit. */
986 if (! base_file_name)
988 char *fileprefix = choose_temp_base ();
989 base_file_name = (char *) xmalloc (strlen (fileprefix) + 6);
990 sprintf (base_file_name, "%s.base",
991 (dontdeltemps) ? mybasename (fileprefix) : fileprefix);
992 delete_base_file = 1;
993 free (fileprefix);
997 int quote;
999 dyn_string_t step1 = dyn_string_new (driver_cmdline->length
1000 + strlen (base_file_name)
1001 + 20);
1002 dyn_string_append_cstr (step1, "-Wl,--base-file,");
1003 quote = (strchr (base_file_name, ' ')
1004 || strchr (base_file_name, '\t'));
1005 dyn_string_append_cstr (step1,
1006 (quote) ? "\"" : "");
1007 dyn_string_append_cstr (step1, base_file_name);
1008 dyn_string_append_cstr (step1,
1009 (quote) ? "\"" : "");
1010 if (driver_cmdline->length)
1012 dyn_string_append_cstr (step1, " ");
1013 dyn_string_append_cstr (step1, driver_cmdline->s);
1016 if (run (driver_name, step1->s))
1017 cleanup_and_exit (1);
1019 dyn_string_delete (step1);
1022 /* Step 2. generate the exp file by running dlltool.
1023 dlltool command line will look like the following:
1025 % dlltool -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
1027 If the user does not specify a base name, create temporary one that
1028 is deleted at exit. */
1030 if (! exp_file_name)
1032 char *p = strrchr (dll_name, '.');
1033 size_t prefix_len = (p) ? (size_t) (p - dll_name) : strlen (dll_name);
1035 exp_file_name = (char *) xmalloc (prefix_len + 4 + 1);
1036 strncpy (exp_file_name, dll_name, prefix_len);
1037 exp_file_name[prefix_len] = '\0';
1038 strcat (exp_file_name, ".exp");
1039 delete_exp_file = 1;
1043 int quote;
1045 dyn_string_t step2 = dyn_string_new (dlltool_cmdline->length
1046 + strlen (base_file_name)
1047 + strlen (exp_file_name)
1048 + 20);
1050 dyn_string_append_cstr (step2, "--base-file ");
1051 quote = (strchr (base_file_name, ' ')
1052 || strchr (base_file_name, '\t'));
1053 dyn_string_append_cstr (step2,
1054 (quote) ? "\"" : "");
1055 dyn_string_append_cstr (step2, base_file_name);
1056 dyn_string_append_cstr (step2,
1057 (quote) ? "\" " : " ");
1059 dyn_string_append_cstr (step2, "--output-exp ");
1060 quote = (strchr (exp_file_name, ' ')
1061 || strchr (exp_file_name, '\t'));
1062 dyn_string_append_cstr (step2,
1063 (quote) ? "\"" : "");
1064 dyn_string_append_cstr (step2, exp_file_name);
1065 dyn_string_append_cstr (step2,
1066 (quote) ? "\"" : "");
1068 if (dlltool_cmdline->length)
1070 dyn_string_append_cstr (step2, " ");
1071 dyn_string_append_cstr (step2, dlltool_cmdline->s);
1074 if (run (dlltool_name, step2->s))
1075 cleanup_and_exit (1);
1077 dyn_string_delete (step2);
1081 * Step 3. Call GCC/LD to again, adding the exp file this time.
1082 * driver command line will look like the following:
1084 * % gcc -Wl,--dll --Wl,--base-file,foo.base foo.exp [rest ...]
1088 int quote;
1090 dyn_string_t step3 = dyn_string_new (driver_cmdline->length
1091 + strlen (exp_file_name)
1092 + strlen (base_file_name)
1093 + 20);
1094 dyn_string_append_cstr (step3, "-Wl,--base-file,");
1095 quote = (strchr (base_file_name, ' ')
1096 || strchr (base_file_name, '\t'));
1097 dyn_string_append_cstr (step3,
1098 (quote) ? "\"" : "");
1099 dyn_string_append_cstr (step3, base_file_name);
1100 dyn_string_append_cstr (step3,
1101 (quote) ? "\" " : " ");
1103 quote = (strchr (exp_file_name, ' ')
1104 || strchr (exp_file_name, '\t'));
1105 dyn_string_append_cstr (step3,
1106 (quote) ? "\"" : "");
1107 dyn_string_append_cstr (step3, exp_file_name);
1108 dyn_string_append_cstr (step3,
1109 (quote) ? "\"" : "");
1111 if (driver_cmdline->length)
1113 dyn_string_append_cstr (step3, " ");
1114 dyn_string_append_cstr (step3, driver_cmdline->s);
1117 if (run (driver_name, step3->s))
1118 cleanup_and_exit (1);
1120 dyn_string_delete (step3);
1125 * Step 4. Run DLLTOOL again using the same command line.
1129 int quote;
1130 dyn_string_t step4 = dyn_string_new (dlltool_cmdline->length
1131 + strlen (base_file_name)
1132 + strlen (exp_file_name)
1133 + 20);
1135 dyn_string_append_cstr (step4, "--base-file ");
1136 quote = (strchr (base_file_name, ' ')
1137 || strchr (base_file_name, '\t'));
1138 dyn_string_append_cstr (step4,
1139 (quote) ? "\"" : "");
1140 dyn_string_append_cstr (step4, base_file_name);
1141 dyn_string_append_cstr (step4,
1142 (quote) ? "\" " : " ");
1144 dyn_string_append_cstr (step4, "--output-exp ");
1145 quote = (strchr (exp_file_name, ' ')
1146 || strchr (exp_file_name, '\t'));
1147 dyn_string_append_cstr (step4,
1148 (quote) ? "\"" : "");
1149 dyn_string_append_cstr (step4, exp_file_name);
1150 dyn_string_append_cstr (step4,
1151 (quote) ? "\"" : "");
1153 if (dlltool_cmdline->length)
1155 dyn_string_append_cstr (step4, " ");
1156 dyn_string_append_cstr (step4, dlltool_cmdline->s);
1159 if (output_lib_file_name)
1161 dyn_string_append_cstr (step4, " --output-lib ");
1162 dyn_string_append_cstr (step4, output_lib_file_name);
1165 if (run (dlltool_name, step4->s))
1166 cleanup_and_exit (1);
1168 dyn_string_delete (step4);
1173 * Step 5. Link it all together and be done with it.
1174 * driver command line will look like the following:
1176 * % gcc -Wl,--dll foo.exp [rest ...]
1181 int quote;
1183 dyn_string_t step5 = dyn_string_new (driver_cmdline->length
1184 + strlen (exp_file_name)
1185 + 20);
1186 quote = (strchr (exp_file_name, ' ')
1187 || strchr (exp_file_name, '\t'));
1188 dyn_string_append_cstr (step5,
1189 (quote) ? "\"" : "");
1190 dyn_string_append_cstr (step5, exp_file_name);
1191 dyn_string_append_cstr (step5,
1192 (quote) ? "\"" : "");
1194 if (driver_cmdline->length)
1196 dyn_string_append_cstr (step5, " ");
1197 dyn_string_append_cstr (step5, driver_cmdline->s);
1200 if (run (driver_name, step5->s))
1201 cleanup_and_exit (1);
1203 dyn_string_delete (step5);
1206 cleanup_and_exit (0);
1208 return 0;