opcodes/
[binutils.git] / binutils / dllwrap.c
blobe4db7bae53878ab22cdefd5640fe86afbc790bdf
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).
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 *program_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 (program_name != NULL)
143 fprintf (stderr, "%s: ", program_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 *prog_name)
249 char *cmd;
250 char *dash, *slash, *cp;
252 dash = NULL;
253 slash = NULL;
254 for (cp = program_name; *cp != '\0'; ++cp)
256 if (*cp == '-')
257 dash = cp;
258 if (
259 #if defined(__DJGPP__) || defined (__CYGWIN__) || defined(__WIN32__)
260 *cp == ':' || *cp == '\\' ||
261 #endif
262 *cp == '/')
264 slash = cp;
265 dash = NULL;
269 cmd = NULL;
271 if (dash != NULL)
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);
278 if (slash != NULL && cmd == NULL)
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);
285 if (cmd == NULL)
287 /* Just return PROG_NAME as is. */
288 cmd = xstrdup (prog_name);
291 return cmd;
294 static void
295 delete_temp_files (void)
297 if (delete_base_file && base_file_name)
299 if (verbose)
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);
306 if (! dontdeltemps)
308 unlink (base_file_name);
309 free (base_file_name);
313 if (delete_exp_file && exp_file_name)
315 if (verbose)
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);
322 if (! dontdeltemps)
324 unlink (exp_file_name);
325 free (exp_file_name);
328 if (delete_def_file && def_file_name)
330 if (verbose)
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);
337 if (! dontdeltemps)
339 unlink (def_file_name);
340 free (def_file_name);
345 static void
346 cleanup_and_exit (int status)
348 delete_temp_files ();
349 exit (status);
352 static int
353 run (const char *what, char *args)
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;
364 if (verbose || dry_run)
365 fprintf (stderr, "%s %s\n", what, args);
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)
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++;
394 argv[i++] = NULL;
396 if (dry_run)
397 return 0;
399 pid = pexecute (argv[0], (char * const *) argv, program_name, temp_base,
400 &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
402 if (pid == -1)
404 int errno_val = errno;
406 fprintf (stderr, "%s: ", program_name);
407 fprintf (stderr, errmsg_fmt, errmsg_arg);
408 fprintf (stderr, ": %s\n", strerror (errno_val));
409 return 1;
412 retcode = 0;
413 pid = pwait (pid, &wait_status, 0);
414 if (pid == -1)
416 warn ("wait: %s", strerror (errno));
417 retcode = 1;
419 else if (WIFSIGNALED (wait_status))
421 warn (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
422 retcode = 1;
424 else if (WIFEXITED (wait_status))
426 if (WEXITSTATUS (wait_status) != 0)
428 warn (_("%s exited with status %d"), what, WEXITSTATUS (wait_status));
429 retcode = 1;
432 else
433 retcode = 1;
435 return retcode;
438 static char *
439 mybasename (const char *name)
441 const char *base = name;
443 while (*name)
445 if (*name == '/' || *name == '\\')
447 base = name + 1;
449 ++name;
451 return (char *) base;
454 static int
455 strhash (const char *str)
457 const unsigned char *s;
458 unsigned long hash;
459 unsigned int c;
460 unsigned int len;
462 hash = 0;
463 len = 0;
464 s = (const unsigned char *) str;
465 while ((c = *s++) != '\0')
467 hash += c + (c << 17);
468 hash ^= hash >> 2;
469 ++len;
471 hash += len + (len << 17);
472 hash ^= hash >> 2;
474 return hash;
477 /**********************************************************************/
479 static void
480 usage (FILE *file, int status)
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);
522 #define OPTION_START 149
524 /* GENERIC options. */
525 #define OPTION_QUIET (OPTION_START + 1)
526 #define OPTION_VERBOSE (OPTION_QUIET + 1)
527 #define OPTION_VERSION (OPTION_VERBOSE + 1)
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)
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)
560 static const struct option long_options[] =
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},
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},
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}
601 int main (int, char **);
604 main (int argc, char **argv)
606 int c;
607 int i;
609 char **saved_argv = 0;
610 int cmdline_len = 0;
612 int export_all = 0;
614 int *dlltool_arg_indices;
615 int *driver_arg_indices;
617 char *driver_flags = 0;
618 char *output_lib_file_name = 0;
620 dyn_string_t dlltool_cmdline;
621 dyn_string_t driver_cmdline;
623 int def_file_seen = 0;
625 char *image_base_str = 0;
627 program_name = argv[0];
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);
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)
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;
651 cmdline_len++;
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. */
657 opterr = 0;
658 while ((c = getopt_long_only (argc, argv, "nkAqve:Uho:l:L:I:",
659 long_options, (int *) 0)) != EOF)
661 int dlltool_arg;
662 int driver_arg;
663 int single_word_option_value_pair;
665 dlltool_arg = 0;
666 driver_arg = 1;
667 single_word_option_value_pair = 0;
669 if (c != '?')
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;
678 /* deal with generic and dllwrap options first. */
679 switch (c)
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;
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;
765 if (dlltool_arg)
767 dlltool_arg_indices[optind-1] = 1;
768 if (optarg && ! single_word_option_value_pair)
770 dlltool_arg_indices[optind-2] = 1;
774 if (! driver_arg)
776 driver_arg_indices[optind-1] = 0;
777 if (optarg && ! single_word_option_value_pair)
779 driver_arg_indices[optind-2] = 0;
784 /* sanity checks. */
785 if (! dll_name && ! dll_file_name)
787 warn (_("Must provide at least one of -o or --dllname options"));
788 exit (1);
790 else if (! dll_name)
792 dll_name = xstrdup (mybasename (dll_file_name));
794 else if (! dll_file_name)
796 dll_file_name = xstrdup (dll_name);
799 /* Deduce driver-name and dlltool-name from our own. */
800 if (driver_name == NULL)
801 driver_name = deduce_name ("gcc");
803 if (dlltool_name == NULL)
804 dlltool_name = deduce_name ("dlltool");
806 if (! def_file_seen)
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"));
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;
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)
831 dyn_string_append_cstr (dlltool_cmdline, " -v");
833 dyn_string_append_cstr (dlltool_cmdline, " --dllname ");
834 dyn_string_append_cstr (dlltool_cmdline, dll_name);
836 for (i = 1; i < argc; ++i)
838 if (dlltool_arg_indices[i])
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) ? "\"" : "");
850 driver_cmdline = dyn_string_new (cmdline_len);
851 if (! driver_flags || strlen (driver_flags) == 0)
853 switch (which_target)
855 case CYGWIN_TARGET:
856 driver_flags = cygwin_driver_flags;
857 break;
859 case MINGW_TARGET:
860 driver_flags = mingw32_driver_flags;
861 break;
863 default:
864 driver_flags = generic_driver_flags;
865 break;
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);
872 if (! entry_point || strlen (entry_point) == 0)
874 switch (which_target)
876 case CYGWIN_TARGET:
877 entry_point = "__cygwin_dll_entry@12";
878 break;
880 case MINGW_TARGET:
881 entry_point = "_DllMainCRTStartup@12";
882 break;
884 default:
885 entry_point = "_DllMain@12";
886 break;
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);
895 if (! image_base_str || strlen (image_base_str) == 0)
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;
903 dyn_string_append_cstr (driver_cmdline, " -Wl,--image-base,");
904 dyn_string_append_cstr (driver_cmdline, image_base_str);
906 if (verbose)
908 dyn_string_append_cstr (driver_cmdline, " -v");
911 for (i = 1; i < argc; ++i)
913 if (driver_arg_indices[i])
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) ? "\"" : "");
926 * Step pre-1. If no --def <EXPORT_DEF> is specified, then create it
927 * and then pass it on.
930 if (! def_file_seen)
932 int i;
933 dyn_string_t step_pre1;
935 step_pre1 = dyn_string_new (1024);
937 dyn_string_append_cstr (step_pre1, dlltool_cmdline->s);
938 if (export_all)
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");
944 dyn_string_append_cstr (step_pre1, " --output-def ");
945 dyn_string_append_cstr (step_pre1, def_file_name);
947 for (i = 1; i < argc; ++i)
949 if (driver_arg_indices[i])
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'))
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) ? "\"" : "");
966 if (run (dlltool_name, step_pre1->s))
967 cleanup_and_exit (1);
969 dyn_string_delete (step_pre1);
972 dyn_string_append_cstr (dlltool_cmdline, " --def ");
973 dyn_string_append_cstr (dlltool_cmdline, def_file_name);
975 if (verbose)
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);
984 * Step 1. Call GCC/LD to create base relocation file. If using GCC, the
985 * driver command line will look like the following:
987 * % gcc -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
989 * If the user does not specify a base name, create temporary one that
990 * is deleted at exit.
994 if (! base_file_name)
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);
1005 int quote;
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)
1020 dyn_string_append_cstr (step1, " ");
1021 dyn_string_append_cstr (step1, driver_cmdline->s);
1024 if (run (driver_name, step1->s))
1025 cleanup_and_exit (1);
1027 dyn_string_delete (step1);
1033 * Step 2. generate the exp file by running dlltool.
1034 * dlltool command line will look like the following:
1036 * % dlltool -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
1038 * If the user does not specify a base name, create temporary one that
1039 * is deleted at exit.
1043 if (! exp_file_name)
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;
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);
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) ? "\" " : " ");
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) ? "\"" : "");
1079 if (dlltool_cmdline->length)
1081 dyn_string_append_cstr (step2, " ");
1082 dyn_string_append_cstr (step2, dlltool_cmdline->s);
1085 if (run (dlltool_name, step2->s))
1086 cleanup_and_exit (1);
1088 dyn_string_delete (step2);
1092 * Step 3. Call GCC/LD to again, adding the exp file this time.
1093 * driver command line will look like the following:
1095 * % gcc -Wl,--dll --Wl,--base-file,foo.base foo.exp [rest ...]
1099 int quote;
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) ? "\" " : " ");
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) ? "\"" : "");
1122 if (driver_cmdline->length)
1124 dyn_string_append_cstr (step3, " ");
1125 dyn_string_append_cstr (step3, driver_cmdline->s);
1128 if (run (driver_name, step3->s))
1129 cleanup_and_exit (1);
1131 dyn_string_delete (step3);
1136 * Step 4. Run DLLTOOL again using the same command line.
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);
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) ? "\" " : " ");
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) ? "\"" : "");
1164 if (dlltool_cmdline->length)
1166 dyn_string_append_cstr (step4, " ");
1167 dyn_string_append_cstr (step4, dlltool_cmdline->s);
1170 if (output_lib_file_name)
1172 dyn_string_append_cstr (step4, " --output-lib ");
1173 dyn_string_append_cstr (step4, output_lib_file_name);
1176 if (run (dlltool_name, step4->s))
1177 cleanup_and_exit (1);
1179 dyn_string_delete (step4);
1184 * Step 5. Link it all together and be done with it.
1185 * driver command line will look like the following:
1187 * % gcc -Wl,--dll foo.exp [rest ...]
1192 int quote;
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) ? "\"" : "");
1205 if (driver_cmdline->length)
1207 dyn_string_append_cstr (step5, " ");
1208 dyn_string_append_cstr (step5, driver_cmdline->s);
1211 if (run (driver_name, step5->s))
1212 cleanup_and_exit (1);
1214 dyn_string_delete (step5);
1217 cleanup_and_exit (0);
1219 return 0;