match reality
[binutils.git] / binutils / dllwrap.c
blobf8449a8a780a2a78269b6422cec39b5e1c951921
1 /* dllwrap.c -- wrapper for DLLTOOL and GCC to generate PE style DLLs
2 Copyright 1998, 1999, 2000, 2001, 2002 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 PARAMS ((const char *, char *));
118 static void usage PARAMS ((FILE *, int));
119 static void display PARAMS ((const char *, va_list));
120 static void inform PARAMS ((const char *, ...));
121 static void warn PARAMS ((const char *format, ...));
122 static char *look_for_prog PARAMS ((const char *, const char *, int));
123 static char *deduce_name PARAMS ((const char *));
124 static void delete_temp_files PARAMS ((void));
125 static void cleanup_and_exit PARAMS ((int status));
127 /**********************************************************************/
129 /* Please keep the following 4 routines in sync with dlltool.c:
130 display ()
131 inform ()
132 look_for_prog ()
133 deduce_name ()
134 It's not worth the hassle to break these out since dllwrap will
135 (hopefully) soon be retired in favor of `ld --shared. */
137 static void
138 display (message, args)
139 const char * message;
140 va_list args;
142 if (program_name != NULL)
143 fprintf (stderr, "%s: ", program_name);
145 vfprintf (stderr, message, args);
146 fputc ('\n', stderr);
150 #ifdef __STDC__
151 static void
152 inform (const char * message, ...)
154 va_list args;
156 if (!verbose)
157 return;
159 va_start (args, message);
160 display (message, args);
161 va_end (args);
164 static void
165 warn (const char *format, ...)
167 va_list args;
169 va_start (args, format);
170 display (format, args);
171 va_end (args);
173 #else
175 static void
176 inform (message, va_alist)
177 const char * message;
178 va_dcl
180 va_list args;
182 if (!verbose)
183 return;
185 va_start (args);
186 display (message, args);
187 va_end (args);
190 static void
191 warn (format, va_alist)
192 const char *format;
193 va_dcl
195 va_list args;
197 va_start (args);
198 display (format, args);
199 va_end (args);
201 #endif
203 /* Look for the program formed by concatenating PROG_NAME and the
204 string running from PREFIX to END_PREFIX. If the concatenated
205 string contains a '/', try appending EXECUTABLE_SUFFIX if it is
206 appropriate. */
208 static char *
209 look_for_prog (prog_name, prefix, end_prefix)
210 const char *prog_name;
211 const char *prefix;
212 int end_prefix;
214 struct stat s;
215 char *cmd;
217 cmd = xmalloc (strlen (prefix)
218 + strlen (prog_name)
219 #ifdef HAVE_EXECUTABLE_SUFFIX
220 + strlen (EXECUTABLE_SUFFIX)
221 #endif
222 + 10);
223 strcpy (cmd, prefix);
225 sprintf (cmd + end_prefix, "%s", prog_name);
227 if (strchr (cmd, '/') != NULL)
229 int found;
231 found = (stat (cmd, &s) == 0
232 #ifdef HAVE_EXECUTABLE_SUFFIX
233 || stat (strcat (cmd, EXECUTABLE_SUFFIX), &s) == 0
234 #endif
237 if (! found)
239 /* xgettext:c-format */
240 inform (_("Tried file: %s"), cmd);
241 free (cmd);
242 return NULL;
246 /* xgettext:c-format */
247 inform (_("Using file: %s"), cmd);
249 return cmd;
252 /* Deduce the name of the program we are want to invoke.
253 PROG_NAME is the basic name of the program we want to run,
254 eg "as" or "ld". The catch is that we might want actually
255 run "i386-pe-as" or "ppc-pe-ld".
257 If argv[0] contains the full path, then try to find the program
258 in the same place, with and then without a target-like prefix.
260 Given, argv[0] = /usr/local/bin/i586-cygwin32-dlltool,
261 deduce_name("as") uses the following search order:
263 /usr/local/bin/i586-cygwin32-as
264 /usr/local/bin/as
267 If there's an EXECUTABLE_SUFFIX, it'll use that as well; for each
268 name, it'll try without and then with EXECUTABLE_SUFFIX.
270 Given, argv[0] = i586-cygwin32-dlltool, it will not even try "as"
271 as the fallback, but rather return i586-cygwin32-as.
273 Oh, and given, argv[0] = dlltool, it'll return "as".
275 Returns a dynamically allocated string. */
277 static char *
278 deduce_name (prog_name)
279 const char *prog_name;
281 char *cmd;
282 char *dash, *slash, *cp;
284 dash = NULL;
285 slash = NULL;
286 for (cp = program_name; *cp != '\0'; ++cp)
288 if (*cp == '-')
289 dash = cp;
290 if (
291 #if defined(__DJGPP__) || defined (__CYGWIN__) || defined(__WIN32__)
292 *cp == ':' || *cp == '\\' ||
293 #endif
294 *cp == '/')
296 slash = cp;
297 dash = NULL;
301 cmd = NULL;
303 if (dash != NULL)
305 /* First, try looking for a prefixed PROG_NAME in the
306 PROGRAM_NAME directory, with the same prefix as PROGRAM_NAME. */
307 cmd = look_for_prog (prog_name, program_name, dash - program_name + 1);
310 if (slash != NULL && cmd == NULL)
312 /* Next, try looking for a PROG_NAME in the same directory as
313 that of this program. */
314 cmd = look_for_prog (prog_name, program_name, slash - program_name + 1);
317 if (cmd == NULL)
319 /* Just return PROG_NAME as is. */
320 cmd = xstrdup (prog_name);
323 return cmd;
326 static void
327 delete_temp_files ()
329 if (delete_base_file && base_file_name)
331 if (verbose)
333 if (dontdeltemps)
334 warn (_("Keeping temporary base file %s"), base_file_name);
335 else
336 warn (_("Deleting temporary base file %s"), base_file_name);
338 if (! dontdeltemps)
340 unlink (base_file_name);
341 free (base_file_name);
345 if (delete_exp_file && exp_file_name)
347 if (verbose)
349 if (dontdeltemps)
350 warn (_("Keeping temporary exp file %s"), exp_file_name);
351 else
352 warn (_("Deleting temporary exp file %s"), exp_file_name);
354 if (! dontdeltemps)
356 unlink (exp_file_name);
357 free (exp_file_name);
360 if (delete_def_file && def_file_name)
362 if (verbose)
364 if (dontdeltemps)
365 warn (_("Keeping temporary def file %s"), def_file_name);
366 else
367 warn (_("Deleting temporary def file %s"), def_file_name);
369 if (! dontdeltemps)
371 unlink (def_file_name);
372 free (def_file_name);
377 static void
378 cleanup_and_exit (int status)
380 delete_temp_files ();
381 exit (status);
384 static int
385 run (what, args)
386 const char *what;
387 char *args;
389 char *s;
390 int pid, wait_status, retcode;
391 int i;
392 const char **argv;
393 char *errmsg_fmt, *errmsg_arg;
394 char *temp_base = choose_temp_base ();
395 int in_quote;
396 char sep;
398 if (verbose || dry_run)
399 fprintf (stderr, "%s %s\n", what, args);
401 /* Count the args */
402 i = 0;
403 for (s = args; *s; s++)
404 if (*s == ' ')
405 i++;
406 i++;
407 argv = alloca (sizeof (char *) * (i + 3));
408 i = 0;
409 argv[i++] = what;
410 s = args;
411 while (1)
413 while (*s == ' ' && *s != 0)
414 s++;
415 if (*s == 0)
416 break;
417 in_quote = (*s == '\'' || *s == '"');
418 sep = (in_quote) ? *s++ : ' ';
419 argv[i++] = s;
420 while (*s != sep && *s != 0)
421 s++;
422 if (*s == 0)
423 break;
424 *s++ = 0;
425 if (in_quote)
426 s++;
428 argv[i++] = NULL;
430 if (dry_run)
431 return 0;
433 pid = pexecute (argv[0], (char * const *) argv, program_name, temp_base,
434 &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
436 if (pid == -1)
438 int errno_val = errno;
440 fprintf (stderr, "%s: ", program_name);
441 fprintf (stderr, errmsg_fmt, errmsg_arg);
442 fprintf (stderr, ": %s\n", strerror (errno_val));
443 return 1;
446 retcode = 0;
447 pid = pwait (pid, &wait_status, 0);
448 if (pid == -1)
450 warn ("wait: %s", strerror (errno));
451 retcode = 1;
453 else if (WIFSIGNALED (wait_status))
455 warn (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
456 retcode = 1;
458 else if (WIFEXITED (wait_status))
460 if (WEXITSTATUS (wait_status) != 0)
462 warn (_("%s exited with status %d"), what, WEXITSTATUS (wait_status));
463 retcode = 1;
466 else
467 retcode = 1;
469 return retcode;
472 static char *
473 mybasename (name)
474 const char *name;
476 const char *base = name;
478 while (*name)
480 if (*name == '/' || *name == '\\')
482 base = name + 1;
484 ++name;
486 return (char *) base;
489 static int
490 strhash (const char *str)
492 const unsigned char *s;
493 unsigned long hash;
494 unsigned int c;
495 unsigned int len;
497 hash = 0;
498 len = 0;
499 s = (const unsigned char *) str;
500 while ((c = *s++) != '\0')
502 hash += c + (c << 17);
503 hash ^= hash >> 2;
504 ++len;
506 hash += len + (len << 17);
507 hash ^= hash >> 2;
509 return hash;
512 /**********************************************************************/
514 static void
515 usage (file, status)
516 FILE *file;
517 int status;
519 fprintf (file, _("Usage %s <option(s)> <object-file(s)>\n"), program_name);
520 fprintf (file, _(" Generic options:\n"));
521 fprintf (file, _(" --quiet, -q Work quietly\n"));
522 fprintf (file, _(" --verbose, -v Verbose\n"));
523 fprintf (file, _(" --version Print dllwrap version\n"));
524 fprintf (file, _(" --implib <outname> Synonym for --output-lib\n"));
525 fprintf (file, _(" Options for %s:\n"), program_name);
526 fprintf (file, _(" --driver-name <driver> Defaults to \"gcc\"\n"));
527 fprintf (file, _(" --driver-flags <flags> Override default ld flags\n"));
528 fprintf (file, _(" --dlltool-name <dlltool> Defaults to \"dlltool\"\n"));
529 fprintf (file, _(" --entry <entry> Specify alternate DLL entry point\n"));
530 fprintf (file, _(" --image-base <base> Specify image base address\n"));
531 fprintf (file, _(" --target <machine> i386-cygwin32 or i386-mingw32\n"));
532 fprintf (file, _(" --dry-run Show what needs to be run\n"));
533 fprintf (file, _(" --mno-cygwin Create Mingw DLL\n"));
534 fprintf (file, _(" Options passed to DLLTOOL:\n"));
535 fprintf (file, _(" --machine <machine>\n"));
536 fprintf (file, _(" --output-exp <outname> Generate export file.\n"));
537 fprintf (file, _(" --output-lib <outname> Generate input library.\n"));
538 fprintf (file, _(" --add-indirect Add dll indirects to export file.\n"));
539 fprintf (file, _(" --dllname <name> Name of input dll to put into output lib.\n"));
540 fprintf (file, _(" --def <deffile> Name input .def file\n"));
541 fprintf (file, _(" --output-def <deffile> Name output .def file\n"));
542 fprintf (file, _(" --export-all-symbols Export all symbols to .def\n"));
543 fprintf (file, _(" --no-export-all-symbols Only export .drectve symbols\n"));
544 fprintf (file, _(" --exclude-symbols <list> Exclude <list> from .def\n"));
545 fprintf (file, _(" --no-default-excludes Zap default exclude symbols\n"));
546 fprintf (file, _(" --base-file <basefile> Read linker generated base file\n"));
547 fprintf (file, _(" --no-idata4 Don't generate idata$4 section\n"));
548 fprintf (file, _(" --no-idata5 Don't generate idata$5 section\n"));
549 fprintf (file, _(" -U Add underscores to .lib\n"));
550 fprintf (file, _(" -k Kill @<n> from exported names\n"));
551 fprintf (file, _(" --add-stdcall-alias Add aliases without @<n>\n"));
552 fprintf (file, _(" --as <name> Use <name> for assembler\n"));
553 fprintf (file, _(" --nodelete Keep temp files.\n"));
554 fprintf (file, _(" Rest are passed unmodified to the language driver\n"));
555 fprintf (file, "\n\n");
556 exit (status);
559 #define OPTION_START 149
561 /* GENERIC options. */
562 #define OPTION_QUIET (OPTION_START + 1)
563 #define OPTION_VERBOSE (OPTION_QUIET + 1)
564 #define OPTION_VERSION (OPTION_VERBOSE + 1)
566 /* DLLWRAP options. */
567 #define OPTION_DRY_RUN (OPTION_VERSION + 1)
568 #define OPTION_DRIVER_NAME (OPTION_DRY_RUN + 1)
569 #define OPTION_DRIVER_FLAGS (OPTION_DRIVER_NAME + 1)
570 #define OPTION_DLLTOOL_NAME (OPTION_DRIVER_FLAGS + 1)
571 #define OPTION_ENTRY (OPTION_DLLTOOL_NAME + 1)
572 #define OPTION_IMAGE_BASE (OPTION_ENTRY + 1)
573 #define OPTION_TARGET (OPTION_IMAGE_BASE + 1)
574 #define OPTION_MNO_CYGWIN (OPTION_TARGET + 1)
576 /* DLLTOOL options. */
577 #define OPTION_NODELETE (OPTION_MNO_CYGWIN + 1)
578 #define OPTION_DLLNAME (OPTION_NODELETE + 1)
579 #define OPTION_NO_IDATA4 (OPTION_DLLNAME + 1)
580 #define OPTION_NO_IDATA5 (OPTION_NO_IDATA4 + 1)
581 #define OPTION_OUTPUT_EXP (OPTION_NO_IDATA5 + 1)
582 #define OPTION_OUTPUT_DEF (OPTION_OUTPUT_EXP + 1)
583 #define OPTION_EXPORT_ALL_SYMS (OPTION_OUTPUT_DEF + 1)
584 #define OPTION_NO_EXPORT_ALL_SYMS (OPTION_EXPORT_ALL_SYMS + 1)
585 #define OPTION_EXCLUDE_SYMS (OPTION_NO_EXPORT_ALL_SYMS + 1)
586 #define OPTION_NO_DEFAULT_EXCLUDES (OPTION_EXCLUDE_SYMS + 1)
587 #define OPTION_OUTPUT_LIB (OPTION_NO_DEFAULT_EXCLUDES + 1)
588 #define OPTION_DEF (OPTION_OUTPUT_LIB + 1)
589 #define OPTION_ADD_UNDERSCORE (OPTION_DEF + 1)
590 #define OPTION_KILLAT (OPTION_ADD_UNDERSCORE + 1)
591 #define OPTION_HELP (OPTION_KILLAT + 1)
592 #define OPTION_MACHINE (OPTION_HELP + 1)
593 #define OPTION_ADD_INDIRECT (OPTION_MACHINE + 1)
594 #define OPTION_BASE_FILE (OPTION_ADD_INDIRECT + 1)
595 #define OPTION_AS (OPTION_BASE_FILE + 1)
597 static const struct option long_options[] =
599 /* generic options. */
600 {"quiet", no_argument, NULL, 'q'},
601 {"verbose", no_argument, NULL, 'v'},
602 {"version", no_argument, NULL, OPTION_VERSION},
603 {"implib", required_argument, NULL, OPTION_OUTPUT_LIB},
605 /* dllwrap options. */
606 {"dry-run", no_argument, NULL, OPTION_DRY_RUN},
607 {"driver-name", required_argument, NULL, OPTION_DRIVER_NAME},
608 {"driver-flags", required_argument, NULL, OPTION_DRIVER_FLAGS},
609 {"dlltool-name", required_argument, NULL, OPTION_DLLTOOL_NAME},
610 {"entry", required_argument, NULL, 'e'},
611 {"image-base", required_argument, NULL, OPTION_IMAGE_BASE},
612 {"target", required_argument, NULL, OPTION_TARGET},
614 /* dlltool options. */
615 {"no-delete", no_argument, NULL, 'n'},
616 {"dllname", required_argument, NULL, OPTION_DLLNAME},
617 {"no-idata4", no_argument, NULL, OPTION_NO_IDATA4},
618 {"no-idata5", no_argument, NULL, OPTION_NO_IDATA5},
619 {"output-exp", required_argument, NULL, OPTION_OUTPUT_EXP},
620 {"output-def", required_argument, NULL, OPTION_OUTPUT_DEF},
621 {"export-all-symbols", no_argument, NULL, OPTION_EXPORT_ALL_SYMS},
622 {"no-export-all-symbols", no_argument, NULL, OPTION_NO_EXPORT_ALL_SYMS},
623 {"exclude-symbols", required_argument, NULL, OPTION_EXCLUDE_SYMS},
624 {"no-default-excludes", no_argument, NULL, OPTION_NO_DEFAULT_EXCLUDES},
625 {"output-lib", required_argument, NULL, OPTION_OUTPUT_LIB},
626 {"def", required_argument, NULL, OPTION_DEF},
627 {"add-underscore", no_argument, NULL, 'U'},
628 {"killat", no_argument, NULL, 'k'},
629 {"add-stdcall-alias", no_argument, NULL, 'A'},
630 {"help", no_argument, NULL, 'h'},
631 {"machine", required_argument, NULL, OPTION_MACHINE},
632 {"add-indirect", no_argument, NULL, OPTION_ADD_INDIRECT},
633 {"base-file", required_argument, NULL, OPTION_BASE_FILE},
634 {"as", required_argument, NULL, OPTION_AS},
635 {0, 0, 0, 0}
639 main (argc, argv)
640 int argc;
641 char **argv;
643 int c;
644 int i;
646 char **saved_argv = 0;
647 int cmdline_len = 0;
649 int export_all = 0;
651 int *dlltool_arg_indices;
652 int *driver_arg_indices;
654 char *driver_flags = 0;
655 char *output_lib_file_name = 0;
657 dyn_string_t dlltool_cmdline;
658 dyn_string_t driver_cmdline;
660 int def_file_seen = 0;
662 char *image_base_str = 0;
664 program_name = argv[0];
666 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
667 setlocale (LC_MESSAGES, "");
668 #endif
669 #if defined (HAVE_SETLOCALE)
670 setlocale (LC_CTYPE, "");
671 #endif
672 bindtextdomain (PACKAGE, LOCALEDIR);
673 textdomain (PACKAGE);
675 saved_argv = (char **) xmalloc (argc * sizeof (char*));
676 dlltool_arg_indices = (int *) xmalloc (argc * sizeof (int));
677 driver_arg_indices = (int *) xmalloc (argc * sizeof (int));
678 for (i = 0; i < argc; ++i)
680 size_t len = strlen (argv[i]);
681 char *arg = (char *) xmalloc (len + 1);
682 strcpy (arg, argv[i]);
683 cmdline_len += len;
684 saved_argv[i] = arg;
685 dlltool_arg_indices[i] = 0;
686 driver_arg_indices[i] = 1;
688 cmdline_len++;
690 /* We recognize dllwrap and dlltool options, and everything else is
691 passed onto the language driver (eg., to GCC). We collect options
692 to dlltool and driver in dlltool_args and driver_args. */
694 opterr = 0;
695 while ((c = getopt_long_only (argc, argv, "nkAqve:Uho:l:L:I:",
696 long_options, (int *) 0)) != EOF)
698 int dlltool_arg;
699 int driver_arg;
700 int single_word_option_value_pair;
702 dlltool_arg = 0;
703 driver_arg = 1;
704 single_word_option_value_pair = 0;
706 if (c != '?')
708 /* We recognize this option, so it has to be either dllwrap or
709 dlltool option. Do not pass to driver unless it's one of the
710 generic options that are passed to all the tools (such as -v)
711 which are dealt with later. */
712 driver_arg = 0;
715 /* deal with generic and dllwrap options first. */
716 switch (c)
718 case 'h':
719 usage (stdout, 0);
720 break;
721 case 'q':
722 verbose = 0;
723 break;
724 case 'v':
725 verbose = 1;
726 break;
727 case OPTION_VERSION:
728 print_version (program_name);
729 break;
730 case 'e':
731 entry_point = optarg;
732 break;
733 case OPTION_IMAGE_BASE:
734 image_base_str = optarg;
735 break;
736 case OPTION_DEF:
737 def_file_name = optarg;
738 def_file_seen = 1;
739 delete_def_file = 0;
740 break;
741 case 'n':
742 dontdeltemps = 1;
743 dlltool_arg = 1;
744 break;
745 case 'o':
746 dll_file_name = optarg;
747 break;
748 case 'I':
749 case 'l':
750 case 'L':
751 driver_arg = 1;
752 break;
753 case OPTION_DLLNAME:
754 dll_name = optarg;
755 break;
756 case OPTION_DRY_RUN:
757 dry_run = 1;
758 break;
759 case OPTION_DRIVER_NAME:
760 driver_name = optarg;
761 break;
762 case OPTION_DRIVER_FLAGS:
763 driver_flags = optarg;
764 break;
765 case OPTION_DLLTOOL_NAME:
766 dlltool_name = optarg;
767 break;
768 case OPTION_TARGET:
769 target = optarg;
770 break;
771 case OPTION_MNO_CYGWIN:
772 target = "i386-mingw32";
773 break;
774 case OPTION_BASE_FILE:
775 base_file_name = optarg;
776 delete_base_file = 0;
777 break;
778 case OPTION_OUTPUT_EXP:
779 exp_file_name = optarg;
780 delete_exp_file = 0;
781 break;
782 case OPTION_EXPORT_ALL_SYMS:
783 export_all = 1;
784 break;
785 case OPTION_OUTPUT_LIB:
786 output_lib_file_name = optarg;
787 break;
788 case '?':
789 break;
790 default:
791 dlltool_arg = 1;
792 break;
795 /* Handle passing through --option=value case. */
796 if (optarg
797 && saved_argv[optind-1][0] == '-'
798 && saved_argv[optind-1][1] == '-'
799 && strchr (saved_argv[optind-1], '='))
800 single_word_option_value_pair = 1;
802 if (dlltool_arg)
804 dlltool_arg_indices[optind-1] = 1;
805 if (optarg && ! single_word_option_value_pair)
807 dlltool_arg_indices[optind-2] = 1;
811 if (! driver_arg)
813 driver_arg_indices[optind-1] = 0;
814 if (optarg && ! single_word_option_value_pair)
816 driver_arg_indices[optind-2] = 0;
821 /* sanity checks. */
822 if (! dll_name && ! dll_file_name)
824 warn (_("Must provide at least one of -o or --dllname options"));
825 exit (1);
827 else if (! dll_name)
829 dll_name = xstrdup (mybasename (dll_file_name));
831 else if (! dll_file_name)
833 dll_file_name = xstrdup (dll_name);
836 /* Deduce driver-name and dlltool-name from our own. */
837 if (driver_name == NULL)
838 driver_name = deduce_name ("gcc");
840 if (dlltool_name == NULL)
841 dlltool_name = deduce_name ("dlltool");
843 if (! def_file_seen)
845 char *fileprefix = choose_temp_base ();
846 def_file_name = (char *) xmalloc (strlen (fileprefix) + 5);
847 sprintf (def_file_name, "%s.def",
848 (dontdeltemps) ? mybasename (fileprefix) : fileprefix);
849 delete_def_file = 1;
850 free (fileprefix);
851 delete_def_file = 1;
852 warn (_("no export definition file provided.\n\
853 Creating one, but that may not be what you want"));
856 /* set the target platform. */
857 if (strstr (target, "cygwin"))
858 which_target = CYGWIN_TARGET;
859 else if (strstr (target, "mingw"))
860 which_target = MINGW_TARGET;
861 else
862 which_target = UNKNOWN_TARGET;
864 /* re-create the command lines as a string, taking care to quote stuff. */
865 dlltool_cmdline = dyn_string_new (cmdline_len);
866 if (verbose)
868 dyn_string_append_cstr (dlltool_cmdline, " -v");
870 dyn_string_append_cstr (dlltool_cmdline, " --dllname ");
871 dyn_string_append_cstr (dlltool_cmdline, dll_name);
873 for (i = 1; i < argc; ++i)
875 if (dlltool_arg_indices[i])
877 char *arg = saved_argv[i];
878 int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
879 dyn_string_append_cstr (dlltool_cmdline,
880 (quote) ? " \"" : " ");
881 dyn_string_append_cstr (dlltool_cmdline, arg);
882 dyn_string_append_cstr (dlltool_cmdline,
883 (quote) ? "\"" : "");
887 driver_cmdline = dyn_string_new (cmdline_len);
888 if (! driver_flags || strlen (driver_flags) == 0)
890 switch (which_target)
892 case CYGWIN_TARGET:
893 driver_flags = cygwin_driver_flags;
894 break;
896 case MINGW_TARGET:
897 driver_flags = mingw32_driver_flags;
898 break;
900 default:
901 driver_flags = generic_driver_flags;
902 break;
905 dyn_string_append_cstr (driver_cmdline, driver_flags);
906 dyn_string_append_cstr (driver_cmdline, " -o ");
907 dyn_string_append_cstr (driver_cmdline, dll_file_name);
909 if (! entry_point || strlen (entry_point) == 0)
911 switch (which_target)
913 case CYGWIN_TARGET:
914 entry_point = "__cygwin_dll_entry@12";
915 break;
917 case MINGW_TARGET:
918 entry_point = "_DllMainCRTStartup@12";
919 break;
921 default:
922 entry_point = "_DllMain@12";
923 break;
926 dyn_string_append_cstr (driver_cmdline, " -Wl,-e,");
927 dyn_string_append_cstr (driver_cmdline, entry_point);
928 dyn_string_append_cstr (dlltool_cmdline, " --exclude-symbol=");
929 dyn_string_append_cstr (dlltool_cmdline,
930 (entry_point[0] == '_') ? entry_point+1 : entry_point);
932 if (! image_base_str || strlen (image_base_str) == 0)
934 char *tmpbuf = (char *) xmalloc (sizeof ("0x12345678") + 1);
935 unsigned long hash = strhash (dll_file_name);
936 sprintf (tmpbuf, "0x%.8lX", 0x60000000|((hash<<16)&0xFFC0000));
937 image_base_str = tmpbuf;
940 dyn_string_append_cstr (driver_cmdline, " -Wl,--image-base,");
941 dyn_string_append_cstr (driver_cmdline, image_base_str);
943 if (verbose)
945 dyn_string_append_cstr (driver_cmdline, " -v");
948 for (i = 1; i < argc; ++i)
950 if (driver_arg_indices[i])
952 char *arg = saved_argv[i];
953 int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
954 dyn_string_append_cstr (driver_cmdline,
955 (quote) ? " \"" : " ");
956 dyn_string_append_cstr (driver_cmdline, arg);
957 dyn_string_append_cstr (driver_cmdline,
958 (quote) ? "\"" : "");
963 * Step pre-1. If no --def <EXPORT_DEF> is specified, then create it
964 * and then pass it on.
967 if (! def_file_seen)
969 int i;
970 dyn_string_t step_pre1;
972 step_pre1 = dyn_string_new (1024);
974 dyn_string_append_cstr (step_pre1, dlltool_cmdline->s);
975 if (export_all)
977 dyn_string_append_cstr (step_pre1, " --export-all --exclude-symbol=");
978 dyn_string_append_cstr (step_pre1,
979 "_cygwin_dll_entry@12,DllMainCRTStartup@12,DllMain@12,DllEntryPoint@12");
981 dyn_string_append_cstr (step_pre1, " --output-def ");
982 dyn_string_append_cstr (step_pre1, def_file_name);
984 for (i = 1; i < argc; ++i)
986 if (driver_arg_indices[i])
988 char *arg = saved_argv[i];
989 size_t len = strlen (arg);
990 if (len >= 2 && arg[len-2] == '.'
991 && (arg[len-1] == 'o' || arg[len-1] == 'a'))
993 int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
994 dyn_string_append_cstr (step_pre1,
995 (quote) ? " \"" : " ");
996 dyn_string_append_cstr (step_pre1, arg);
997 dyn_string_append_cstr (step_pre1,
998 (quote) ? "\"" : "");
1003 if (run (dlltool_name, step_pre1->s))
1004 cleanup_and_exit (1);
1006 dyn_string_delete (step_pre1);
1009 dyn_string_append_cstr (dlltool_cmdline, " --def ");
1010 dyn_string_append_cstr (dlltool_cmdline, def_file_name);
1012 if (verbose)
1014 fprintf (stderr, _("DLLTOOL name : %s\n"), dlltool_name);
1015 fprintf (stderr, _("DLLTOOL options : %s\n"), dlltool_cmdline->s);
1016 fprintf (stderr, _("DRIVER name : %s\n"), driver_name);
1017 fprintf (stderr, _("DRIVER options : %s\n"), driver_cmdline->s);
1021 * Step 1. Call GCC/LD to create base relocation file. If using GCC, the
1022 * driver command line will look like the following:
1024 * % gcc -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
1026 * If the user does not specify a base name, create temporary one that
1027 * is deleted at exit.
1031 if (! base_file_name)
1033 char *fileprefix = choose_temp_base ();
1034 base_file_name = (char *) xmalloc (strlen (fileprefix) + 6);
1035 sprintf (base_file_name, "%s.base",
1036 (dontdeltemps) ? mybasename (fileprefix) : fileprefix);
1037 delete_base_file = 1;
1038 free (fileprefix);
1042 int quote;
1044 dyn_string_t step1 = dyn_string_new (driver_cmdline->length
1045 + strlen (base_file_name)
1046 + 20);
1047 dyn_string_append_cstr (step1, "-Wl,--base-file,");
1048 quote = (strchr (base_file_name, ' ')
1049 || strchr (base_file_name, '\t'));
1050 dyn_string_append_cstr (step1,
1051 (quote) ? "\"" : "");
1052 dyn_string_append_cstr (step1, base_file_name);
1053 dyn_string_append_cstr (step1,
1054 (quote) ? "\"" : "");
1055 if (driver_cmdline->length)
1057 dyn_string_append_cstr (step1, " ");
1058 dyn_string_append_cstr (step1, driver_cmdline->s);
1061 if (run (driver_name, step1->s))
1062 cleanup_and_exit (1);
1064 dyn_string_delete (step1);
1070 * Step 2. generate the exp file by running dlltool.
1071 * dlltool command line will look like the following:
1073 * % dlltool -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
1075 * If the user does not specify a base name, create temporary one that
1076 * is deleted at exit.
1080 if (! exp_file_name)
1082 char *p = strrchr (dll_name, '.');
1083 size_t prefix_len = (p) ? p - dll_name : strlen (dll_name);
1084 exp_file_name = (char *) xmalloc (prefix_len + 4 + 1);
1085 strncpy (exp_file_name, dll_name, prefix_len);
1086 exp_file_name[prefix_len] = '\0';
1087 strcat (exp_file_name, ".exp");
1088 delete_exp_file = 1;
1092 int quote;
1093 dyn_string_t step2 = dyn_string_new (dlltool_cmdline->length
1094 + strlen (base_file_name)
1095 + strlen (exp_file_name)
1096 + 20);
1098 dyn_string_append_cstr (step2, "--base-file ");
1099 quote = (strchr (base_file_name, ' ')
1100 || strchr (base_file_name, '\t'));
1101 dyn_string_append_cstr (step2,
1102 (quote) ? "\"" : "");
1103 dyn_string_append_cstr (step2, base_file_name);
1104 dyn_string_append_cstr (step2,
1105 (quote) ? "\" " : " ");
1107 dyn_string_append_cstr (step2, "--output-exp ");
1108 quote = (strchr (exp_file_name, ' ')
1109 || strchr (exp_file_name, '\t'));
1110 dyn_string_append_cstr (step2,
1111 (quote) ? "\"" : "");
1112 dyn_string_append_cstr (step2, exp_file_name);
1113 dyn_string_append_cstr (step2,
1114 (quote) ? "\"" : "");
1116 if (dlltool_cmdline->length)
1118 dyn_string_append_cstr (step2, " ");
1119 dyn_string_append_cstr (step2, dlltool_cmdline->s);
1122 if (run (dlltool_name, step2->s))
1123 cleanup_and_exit (1);
1125 dyn_string_delete (step2);
1129 * Step 3. Call GCC/LD to again, adding the exp file this time.
1130 * driver command line will look like the following:
1132 * % gcc -Wl,--dll --Wl,--base-file,foo.base foo.exp [rest ...]
1136 int quote;
1138 dyn_string_t step3 = dyn_string_new (driver_cmdline->length
1139 + strlen (exp_file_name)
1140 + strlen (base_file_name)
1141 + 20);
1142 dyn_string_append_cstr (step3, "-Wl,--base-file,");
1143 quote = (strchr (base_file_name, ' ')
1144 || strchr (base_file_name, '\t'));
1145 dyn_string_append_cstr (step3,
1146 (quote) ? "\"" : "");
1147 dyn_string_append_cstr (step3, base_file_name);
1148 dyn_string_append_cstr (step3,
1149 (quote) ? "\" " : " ");
1151 quote = (strchr (exp_file_name, ' ')
1152 || strchr (exp_file_name, '\t'));
1153 dyn_string_append_cstr (step3,
1154 (quote) ? "\"" : "");
1155 dyn_string_append_cstr (step3, exp_file_name);
1156 dyn_string_append_cstr (step3,
1157 (quote) ? "\"" : "");
1159 if (driver_cmdline->length)
1161 dyn_string_append_cstr (step3, " ");
1162 dyn_string_append_cstr (step3, driver_cmdline->s);
1165 if (run (driver_name, step3->s))
1166 cleanup_and_exit (1);
1168 dyn_string_delete (step3);
1173 * Step 4. Run DLLTOOL again using the same command line.
1177 int quote;
1178 dyn_string_t step4 = dyn_string_new (dlltool_cmdline->length
1179 + strlen (base_file_name)
1180 + strlen (exp_file_name)
1181 + 20);
1183 dyn_string_append_cstr (step4, "--base-file ");
1184 quote = (strchr (base_file_name, ' ')
1185 || strchr (base_file_name, '\t'));
1186 dyn_string_append_cstr (step4,
1187 (quote) ? "\"" : "");
1188 dyn_string_append_cstr (step4, base_file_name);
1189 dyn_string_append_cstr (step4,
1190 (quote) ? "\" " : " ");
1192 dyn_string_append_cstr (step4, "--output-exp ");
1193 quote = (strchr (exp_file_name, ' ')
1194 || strchr (exp_file_name, '\t'));
1195 dyn_string_append_cstr (step4,
1196 (quote) ? "\"" : "");
1197 dyn_string_append_cstr (step4, exp_file_name);
1198 dyn_string_append_cstr (step4,
1199 (quote) ? "\"" : "");
1201 if (dlltool_cmdline->length)
1203 dyn_string_append_cstr (step4, " ");
1204 dyn_string_append_cstr (step4, dlltool_cmdline->s);
1207 if (output_lib_file_name)
1209 dyn_string_append_cstr (step4, " --output-lib ");
1210 dyn_string_append_cstr (step4, output_lib_file_name);
1213 if (run (dlltool_name, step4->s))
1214 cleanup_and_exit (1);
1216 dyn_string_delete (step4);
1221 * Step 5. Link it all together and be done with it.
1222 * driver command line will look like the following:
1224 * % gcc -Wl,--dll foo.exp [rest ...]
1229 int quote;
1231 dyn_string_t step5 = dyn_string_new (driver_cmdline->length
1232 + strlen (exp_file_name)
1233 + 20);
1234 quote = (strchr (exp_file_name, ' ')
1235 || strchr (exp_file_name, '\t'));
1236 dyn_string_append_cstr (step5,
1237 (quote) ? "\"" : "");
1238 dyn_string_append_cstr (step5, exp_file_name);
1239 dyn_string_append_cstr (step5,
1240 (quote) ? "\"" : "");
1242 if (driver_cmdline->length)
1244 dyn_string_append_cstr (step5, " ");
1245 dyn_string_append_cstr (step5, driver_cmdline->s);
1248 if (run (driver_name, step5->s))
1249 cleanup_and_exit (1);
1251 dyn_string_delete (step5);
1254 cleanup_and_exit (0);
1256 return 0;