* oasys.c: Add missing prototypes.
[binutils.git] / binutils / dllwrap.c
blob8f83dda6df0ebedd2658107d8bb57ed58220aa12
1 /* dllwrap.c -- wrapper for DLLTOOL and GCC to generate PE style DLLs
2 Copyright 1998, 1999, 2000 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 <ctype.h>
40 #include <time.h>
41 #include <sys/stat.h>
43 #ifdef ANSI_PROTOTYPES
44 #include <stdarg.h>
45 #else
46 #include <varargs.h>
47 #endif
49 #ifdef HAVE_SYS_WAIT_H
50 #include <sys/wait.h>
51 #else /* ! HAVE_SYS_WAIT_H */
52 #if ! defined (_WIN32) || defined (__CYGWIN32__)
53 #ifndef WIFEXITED
54 #define WIFEXITED(w) (((w)&0377) == 0)
55 #endif
56 #ifndef WIFSIGNALED
57 #define WIFSIGNALED(w) (((w)&0377) != 0177 && ((w)&~0377) == 0)
58 #endif
59 #ifndef WTERMSIG
60 #define WTERMSIG(w) ((w) & 0177)
61 #endif
62 #ifndef WEXITSTATUS
63 #define WEXITSTATUS(w) (((w) >> 8) & 0377)
64 #endif
65 #else /* defined (_WIN32) && ! defined (__CYGWIN32__) */
66 #ifndef WIFEXITED
67 #define WIFEXITED(w) (((w) & 0xff) == 0)
68 #endif
69 #ifndef WIFSIGNALED
70 #define WIFSIGNALED(w) (((w) & 0xff) != 0 && ((w) & 0xff) != 0x7f)
71 #endif
72 #ifndef WTERMSIG
73 #define WTERMSIG(w) ((w) & 0x7f)
74 #endif
75 #ifndef WEXITSTATUS
76 #define WEXITSTATUS(w) (((w) & 0xff00) >> 8)
77 #endif
78 #endif /* defined (_WIN32) && ! defined (__CYGWIN32__) */
79 #endif /* ! HAVE_SYS_WAIT_H */
81 static char *driver_name = NULL;
82 static char *cygwin_driver_flags =
83 "-Wl,--dll -nostartfiles";
84 static char *mingw32_driver_flags = "-mdll";
85 static char *generic_driver_flags = "-Wl,--dll";
87 static char *entry_point;
89 static char *dlltool_name = NULL;
91 static char *target = TARGET;
93 typedef enum {
94 UNKNOWN_TARGET,
95 CYGWIN_TARGET,
96 MINGW_TARGET
98 target_type;
100 static target_type which_target = UNKNOWN_TARGET;
102 static int dontdeltemps = 0;
103 static int dry_run = 0;
105 static char *program_name;
107 static int verbose = 0;
109 static char *dll_file_name;
110 static char *dll_name;
111 static char *base_file_name;
112 static char *exp_file_name;
113 static char *def_file_name;
114 static int delete_base_file = 1;
115 static int delete_exp_file = 1;
116 static int delete_def_file = 1;
118 static int run PARAMS ((const char *, char *));
119 static void usage PARAMS ((FILE *, int));
120 static void display PARAMS ((const char *, va_list));
121 static void inform PARAMS ((const char *, ...));
122 static void warn PARAMS ((const char *format, ...));
123 static char *look_for_prog PARAMS ((const char *, const char *, int));
124 static char *deduce_name PARAMS ((const char *));
125 static void delete_temp_files PARAMS ((void));
126 static void cleanup_and_exit PARAMS ((int status));
128 /**********************************************************************/
130 /* Please keep the following 4 routines in sync with dlltool.c:
131 display ()
132 inform ()
133 look_for_prog ()
134 deduce_name ()
135 It's not worth the hassle to break these out since dllwrap will
136 (hopefully) soon be retired in favor of `ld --shared. */
138 static void
139 display (message, args)
140 const char * message;
141 va_list args;
143 if (program_name != NULL)
144 fprintf (stderr, "%s: ", program_name);
146 vfprintf (stderr, message, args);
147 fputc ('\n', stderr);
151 #ifdef __STDC__
152 static void
153 inform (const char * message, ...)
155 va_list args;
157 if (!verbose)
158 return;
160 va_start (args, message);
161 display (message, args);
162 va_end (args);
165 static void
166 warn (const char *format, ...)
168 va_list args;
170 va_start (args, format);
171 display (format, args);
172 va_end (args);
174 #else
176 static void
177 inform (message, va_alist)
178 const char * message;
179 va_dcl
181 va_list args;
183 if (!verbose)
184 return;
186 va_start (args);
187 display (message, args);
188 va_end (args);
191 static void
192 warn (format, va_alist)
193 const char *format;
194 va_dcl
196 va_list args;
198 va_start (args);
199 display (format, args);
200 va_end (args);
202 #endif
204 /* Look for the program formed by concatenating PROG_NAME and the
205 string running from PREFIX to END_PREFIX. If the concatenated
206 string contains a '/', try appending EXECUTABLE_SUFFIX if it is
207 appropriate. */
209 static char *
210 look_for_prog (prog_name, prefix, end_prefix)
211 const char *prog_name;
212 const char *prefix;
213 int end_prefix;
215 struct stat s;
216 char *cmd;
218 cmd = xmalloc (strlen (prefix)
219 + strlen (prog_name)
220 #ifdef HAVE_EXECUTABLE_SUFFIX
221 + strlen (EXECUTABLE_SUFFIX)
222 #endif
223 + 10);
224 strcpy (cmd, prefix);
226 sprintf (cmd + end_prefix, "%s", prog_name);
228 if (strchr (cmd, '/') != NULL)
230 int found;
232 found = (stat (cmd, &s) == 0
233 #ifdef HAVE_EXECUTABLE_SUFFIX
234 || stat (strcat (cmd, EXECUTABLE_SUFFIX), &s) == 0
235 #endif
238 if (! found)
240 /* xgettext:c-format */
241 inform (_("Tried file: %s"), cmd);
242 free (cmd);
243 return NULL;
247 /* xgettext:c-format */
248 inform (_("Using file: %s"), cmd);
250 return cmd;
253 /* Deduce the name of the program we are want to invoke.
254 PROG_NAME is the basic name of the program we want to run,
255 eg "as" or "ld". The catch is that we might want actually
256 run "i386-pe-as" or "ppc-pe-ld".
258 If argv[0] contains the full path, then try to find the program
259 in the same place, with and then without a target-like prefix.
261 Given, argv[0] = /usr/local/bin/i586-cygwin32-dlltool,
262 deduce_name("as") uses the following search order:
264 /usr/local/bin/i586-cygwin32-as
265 /usr/local/bin/as
268 If there's an EXECUTABLE_SUFFIX, it'll use that as well; for each
269 name, it'll try without and then with EXECUTABLE_SUFFIX.
271 Given, argv[0] = i586-cygwin32-dlltool, it will not even try "as"
272 as the fallback, but rather return i586-cygwin32-as.
274 Oh, and given, argv[0] = dlltool, it'll return "as".
276 Returns a dynamically allocated string. */
278 static char *
279 deduce_name (prog_name)
280 const char *prog_name;
282 char *cmd;
283 char *dash, *slash, *cp;
285 dash = NULL;
286 slash = NULL;
287 for (cp = program_name; *cp != '\0'; ++cp)
289 if (*cp == '-')
290 dash = cp;
291 if (
292 #if defined(__DJGPP__) || defined (__CYGWIN__) || defined(__WIN32__)
293 *cp == ':' || *cp == '\\' ||
294 #endif
295 *cp == '/')
297 slash = cp;
298 dash = NULL;
302 cmd = NULL;
304 if (dash != NULL)
306 /* First, try looking for a prefixed PROG_NAME in the
307 PROGRAM_NAME directory, with the same prefix as PROGRAM_NAME. */
308 cmd = look_for_prog (prog_name, program_name, dash - program_name + 1);
311 if (slash != NULL && cmd == NULL)
313 /* Next, try looking for a PROG_NAME in the same directory as
314 that of this program. */
315 cmd = look_for_prog (prog_name, program_name, slash - program_name + 1);
318 if (cmd == NULL)
320 /* Just return PROG_NAME as is. */
321 cmd = xstrdup (prog_name);
324 return cmd;
327 static void
328 delete_temp_files ()
330 if (delete_base_file && base_file_name)
332 if (verbose)
334 if (dontdeltemps)
335 warn (_("Keeping temporary base file %s"), base_file_name);
336 else
337 warn (_("Deleting temporary base file %s"), base_file_name);
339 if (! dontdeltemps)
341 unlink (base_file_name);
342 free (base_file_name);
346 if (delete_exp_file && exp_file_name)
348 if (verbose)
350 if (dontdeltemps)
351 warn (_("Keeping temporary exp file %s"), exp_file_name);
352 else
353 warn (_("Deleting temporary exp file %s"), exp_file_name);
355 if (! dontdeltemps)
357 unlink (exp_file_name);
358 free (exp_file_name);
361 if (delete_def_file && def_file_name)
363 if (verbose)
365 if (dontdeltemps)
366 warn (_("Keeping temporary def file %s"), def_file_name);
367 else
368 warn (_("Deleting temporary def file %s"), def_file_name);
370 if (! dontdeltemps)
372 unlink (def_file_name);
373 free (def_file_name);
378 static void
379 cleanup_and_exit (int status)
381 delete_temp_files ();
382 exit (status);
385 static int
386 run (what, args)
387 const char *what;
388 char *args;
390 char *s;
391 int pid, wait_status, retcode;
392 int i;
393 const char **argv;
394 char *errmsg_fmt, *errmsg_arg;
395 char *temp_base = choose_temp_base ();
396 int in_quote;
397 char sep;
399 if (verbose || dry_run)
400 fprintf (stderr, "%s %s\n", what, args);
402 /* Count the args */
403 i = 0;
404 for (s = args; *s; s++)
405 if (*s == ' ')
406 i++;
407 i++;
408 argv = alloca (sizeof (char *) * (i + 3));
409 i = 0;
410 argv[i++] = what;
411 s = args;
412 while (1)
414 while (*s == ' ' && *s != 0)
415 s++;
416 if (*s == 0)
417 break;
418 in_quote = (*s == '\'' || *s == '"');
419 sep = (in_quote) ? *s++ : ' ';
420 argv[i++] = s;
421 while (*s != sep && *s != 0)
422 s++;
423 if (*s == 0)
424 break;
425 *s++ = 0;
426 if (in_quote)
427 s++;
429 argv[i++] = NULL;
431 if (dry_run)
432 return 0;
434 pid = pexecute (argv[0], (char * const *) argv, program_name, temp_base,
435 &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
437 if (pid == -1)
439 int errno_val = errno;
441 fprintf (stderr, "%s: ", program_name);
442 fprintf (stderr, errmsg_fmt, errmsg_arg);
443 fprintf (stderr, ": %s\n", strerror (errno_val));
444 return 1;
447 retcode = 0;
448 pid = pwait (pid, &wait_status, 0);
449 if (pid == -1)
451 warn ("wait: %s", strerror (errno));
452 retcode = 1;
454 else if (WIFSIGNALED (wait_status))
456 warn (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
457 retcode = 1;
459 else if (WIFEXITED (wait_status))
461 if (WEXITSTATUS (wait_status) != 0)
463 warn (_("%s exited with status %d"), what, WEXITSTATUS (wait_status));
464 retcode = 1;
467 else
468 retcode = 1;
470 return retcode;
473 static char *
474 mybasename (name)
475 const char *name;
477 const char *base = name;
479 while (*name)
481 if (*name == '/' || *name == '\\')
483 base = name + 1;
485 ++name;
487 return (char *) base;
490 static int
491 strhash (const char *str)
493 const unsigned char *s;
494 unsigned long hash;
495 unsigned int c;
496 unsigned int len;
498 hash = 0;
499 len = 0;
500 s = (const unsigned char *) str;
501 while ((c = *s++) != '\0')
503 hash += c + (c << 17);
504 hash ^= hash >> 2;
505 ++len;
507 hash += len + (len << 17);
508 hash ^= hash >> 2;
510 return hash;
513 /**********************************************************************/
515 static void
516 usage (file, status)
517 FILE *file;
518 int status;
520 fprintf (file, _("Usage %s <options> <object-files>\n"), program_name);
521 fprintf (file, _(" Generic options:\n"));
522 fprintf (file, _(" --quiet, -q Work quietly\n"));
523 fprintf (file, _(" --verbose, -v Verbose\n"));
524 fprintf (file, _(" --version Print dllwrap version\n"));
525 fprintf (file, _(" --implib <outname> Synonym for --output-lib\n"));
526 fprintf (file, _(" Options for %s:\n"), program_name);
527 fprintf (file, _(" --driver-name <driver> Defaults to \"gcc\"\n"));
528 fprintf (file, _(" --driver-flags <flags> Override default ld flags\n"));
529 fprintf (file, _(" --dlltool-name <dlltool> Defaults to \"dlltool\"\n"));
530 fprintf (file, _(" --entry <entry> Specify alternate DLL entry point\n"));
531 fprintf (file, _(" --image-base <base> Specify image base address\n"));
532 fprintf (file, _(" --target <machine> i386-cygwin32 or i386-mingw32\n"));
533 fprintf (file, _(" --dry-run Show what needs to be run\n"));
534 fprintf (file, _(" --mno-cygwin Create Mingw DLL\n"));
535 fprintf (file, _(" Options passed to DLLTOOL:\n"));
536 fprintf (file, _(" --machine <machine>\n"));
537 fprintf (file, _(" --output-exp <outname> Generate export file.\n"));
538 fprintf (file, _(" --output-lib <outname> Generate input library.\n"));
539 fprintf (file, _(" --add-indirect Add dll indirects to export file.\n"));
540 fprintf (file, _(" --dllname <name> Name of input dll to put into output lib.\n"));
541 fprintf (file, _(" --def <deffile> Name input .def file\n"));
542 fprintf (file, _(" --output-def <deffile> Name output .def file\n"));
543 fprintf (file, _(" --export-all-symbols Export all symbols to .def\n"));
544 fprintf (file, _(" --no-export-all-symbols Only export .drectve symbols\n"));
545 fprintf (file, _(" --exclude-symbols <list> Exclude <list> from .def\n"));
546 fprintf (file, _(" --no-default-excludes Zap default exclude symbols\n"));
547 fprintf (file, _(" --base-file <basefile> Read linker generated base file\n"));
548 fprintf (file, _(" --no-idata4 Don't generate idata$4 section\n"));
549 fprintf (file, _(" --no-idata5 Don't generate idata$5 section\n"));
550 fprintf (file, _(" -U Add underscores to .lib\n"));
551 fprintf (file, _(" -k Kill @<n> from exported names\n"));
552 fprintf (file, _(" --add-stdcall-alias Add aliases without @<n>\n"));
553 fprintf (file, _(" --as <name> Use <name> for assembler\n"));
554 fprintf (file, _(" --nodelete Keep temp files.\n"));
555 fprintf (file, _(" Rest are passed unmodified to the language driver\n"));
556 fprintf (file, "\n\n");
557 exit (status);
560 #define OPTION_START 149
562 /* GENERIC options. */
563 #define OPTION_QUIET (OPTION_START + 1)
564 #define OPTION_VERBOSE (OPTION_QUIET + 1)
565 #define OPTION_VERSION (OPTION_VERBOSE + 1)
567 /* DLLWRAP options. */
568 #define OPTION_DRY_RUN (OPTION_VERSION + 1)
569 #define OPTION_DRIVER_NAME (OPTION_DRY_RUN + 1)
570 #define OPTION_DRIVER_FLAGS (OPTION_DRIVER_NAME + 1)
571 #define OPTION_DLLTOOL_NAME (OPTION_DRIVER_FLAGS + 1)
572 #define OPTION_ENTRY (OPTION_DLLTOOL_NAME + 1)
573 #define OPTION_IMAGE_BASE (OPTION_ENTRY + 1)
574 #define OPTION_TARGET (OPTION_IMAGE_BASE + 1)
575 #define OPTION_MNO_CYGWIN (OPTION_TARGET + 1)
577 /* DLLTOOL options. */
578 #define OPTION_NODELETE (OPTION_MNO_CYGWIN + 1)
579 #define OPTION_DLLNAME (OPTION_NODELETE + 1)
580 #define OPTION_NO_IDATA4 (OPTION_DLLNAME + 1)
581 #define OPTION_NO_IDATA5 (OPTION_NO_IDATA4 + 1)
582 #define OPTION_OUTPUT_EXP (OPTION_NO_IDATA5 + 1)
583 #define OPTION_OUTPUT_DEF (OPTION_OUTPUT_EXP + 1)
584 #define OPTION_EXPORT_ALL_SYMS (OPTION_OUTPUT_DEF + 1)
585 #define OPTION_NO_EXPORT_ALL_SYMS (OPTION_EXPORT_ALL_SYMS + 1)
586 #define OPTION_EXCLUDE_SYMS (OPTION_NO_EXPORT_ALL_SYMS + 1)
587 #define OPTION_NO_DEFAULT_EXCLUDES (OPTION_EXCLUDE_SYMS + 1)
588 #define OPTION_OUTPUT_LIB (OPTION_NO_DEFAULT_EXCLUDES + 1)
589 #define OPTION_DEF (OPTION_OUTPUT_LIB + 1)
590 #define OPTION_ADD_UNDERSCORE (OPTION_DEF + 1)
591 #define OPTION_KILLAT (OPTION_ADD_UNDERSCORE + 1)
592 #define OPTION_HELP (OPTION_KILLAT + 1)
593 #define OPTION_MACHINE (OPTION_HELP + 1)
594 #define OPTION_ADD_INDIRECT (OPTION_MACHINE + 1)
595 #define OPTION_BASE_FILE (OPTION_ADD_INDIRECT + 1)
596 #define OPTION_AS (OPTION_BASE_FILE + 1)
598 static const struct option long_options[] =
600 /* generic options. */
601 {"quiet", no_argument, NULL, 'q'},
602 {"verbose", no_argument, NULL, 'v'},
603 {"version", no_argument, NULL, OPTION_VERSION},
604 {"implib", required_argument, NULL, OPTION_OUTPUT_LIB},
606 /* dllwrap options. */
607 {"dry-run", no_argument, NULL, OPTION_DRY_RUN},
608 {"driver-name", required_argument, NULL, OPTION_DRIVER_NAME},
609 {"driver-flags", required_argument, NULL, OPTION_DRIVER_FLAGS},
610 {"dlltool-name", required_argument, NULL, OPTION_DLLTOOL_NAME},
611 {"entry", required_argument, NULL, 'e'},
612 {"image-base", required_argument, NULL, OPTION_IMAGE_BASE},
613 {"target", required_argument, NULL, OPTION_TARGET},
615 /* dlltool options. */
616 {"no-delete", no_argument, NULL, 'n'},
617 {"dllname", required_argument, NULL, OPTION_DLLNAME},
618 {"no-idata4", no_argument, NULL, OPTION_NO_IDATA4},
619 {"no-idata5", no_argument, NULL, OPTION_NO_IDATA5},
620 {"output-exp", required_argument, NULL, OPTION_OUTPUT_EXP},
621 {"output-def", required_argument, NULL, OPTION_OUTPUT_DEF},
622 {"export-all-symbols", no_argument, NULL, OPTION_EXPORT_ALL_SYMS},
623 {"no-export-all-symbols", no_argument, NULL, OPTION_NO_EXPORT_ALL_SYMS},
624 {"exclude-symbols", required_argument, NULL, OPTION_EXCLUDE_SYMS},
625 {"no-default-excludes", no_argument, NULL, OPTION_NO_DEFAULT_EXCLUDES},
626 {"output-lib", required_argument, NULL, OPTION_OUTPUT_LIB},
627 {"def", required_argument, NULL, OPTION_DEF},
628 {"add-underscore", no_argument, NULL, 'U'},
629 {"killat", no_argument, NULL, 'k'},
630 {"add-stdcall-alias", no_argument, NULL, 'A'},
631 {"help", no_argument, NULL, 'h'},
632 {"machine", required_argument, NULL, OPTION_MACHINE},
633 {"add-indirect", no_argument, NULL, OPTION_ADD_INDIRECT},
634 {"base-file", required_argument, NULL, OPTION_BASE_FILE},
635 {"as", required_argument, NULL, OPTION_AS},
636 {0, 0, 0, 0}
640 main (argc, argv)
641 int argc;
642 char **argv;
644 int c;
645 int i;
647 char **saved_argv = 0;
648 int cmdline_len = 0;
650 int export_all = 0;
652 int *dlltool_arg_indices;
653 int *driver_arg_indices;
655 char *driver_flags = 0;
656 char *output_lib_file_name = 0;
658 dyn_string_t dlltool_cmdline;
659 dyn_string_t driver_cmdline;
661 int def_file_seen = 0;
663 char *image_base_str = 0;
665 program_name = argv[0];
667 saved_argv = (char **) xmalloc (argc * sizeof (char*));
668 dlltool_arg_indices = (int *) xmalloc (argc * sizeof (int));
669 driver_arg_indices = (int *) xmalloc (argc * sizeof (int));
670 for (i = 0; i < argc; ++i)
672 size_t len = strlen (argv[i]);
673 char *arg = (char *) xmalloc (len + 1);
674 strcpy (arg, argv[i]);
675 cmdline_len += len;
676 saved_argv[i] = arg;
677 dlltool_arg_indices[i] = 0;
678 driver_arg_indices[i] = 1;
680 cmdline_len++;
682 /* We recognize dllwrap and dlltool options, and everything else is
683 passed onto the language driver (eg., to GCC). We collect options
684 to dlltool and driver in dlltool_args and driver_args. */
686 opterr = 0;
687 while ((c = getopt_long_only (argc, argv, "nkAqve:Uho:l:L:I:",
688 long_options, (int *) 0)) != EOF)
690 int dlltool_arg;
691 int driver_arg;
692 int single_word_option_value_pair;
694 dlltool_arg = 0;
695 driver_arg = 1;
696 single_word_option_value_pair = 0;
698 if (c != '?')
700 /* We recognize this option, so it has to be either dllwrap or
701 dlltool option. Do not pass to driver unless it's one of the
702 generic options that are passed to all the tools (such as -v)
703 which are dealt with later. */
704 driver_arg = 0;
707 /* deal with generic and dllwrap options first. */
708 switch (c)
710 case 'h':
711 usage (stdout, 0);
712 break;
713 case 'q':
714 verbose = 0;
715 break;
716 case 'v':
717 verbose = 1;
718 break;
719 case OPTION_VERSION:
720 print_version (program_name);
721 break;
722 case 'e':
723 entry_point = optarg;
724 break;
725 case OPTION_IMAGE_BASE:
726 image_base_str = optarg;
727 break;
728 case OPTION_DEF:
729 def_file_name = optarg;
730 def_file_seen = 1;
731 delete_def_file = 0;
732 break;
733 case 'n':
734 dontdeltemps = 1;
735 dlltool_arg = 1;
736 break;
737 case 'o':
738 dll_file_name = optarg;
739 break;
740 case 'I':
741 case 'l':
742 case 'L':
743 driver_arg = 1;
744 break;
745 case OPTION_DLLNAME:
746 dll_name = optarg;
747 break;
748 case OPTION_DRY_RUN:
749 dry_run = 1;
750 break;
751 case OPTION_DRIVER_NAME:
752 driver_name = optarg;
753 break;
754 case OPTION_DRIVER_FLAGS:
755 driver_flags = optarg;
756 break;
757 case OPTION_DLLTOOL_NAME:
758 dlltool_name = optarg;
759 break;
760 case OPTION_TARGET:
761 target = optarg;
762 break;
763 case OPTION_MNO_CYGWIN:
764 target = "i386-mingw32";
765 break;
766 case OPTION_BASE_FILE:
767 base_file_name = optarg;
768 delete_base_file = 0;
769 break;
770 case OPTION_OUTPUT_EXP:
771 exp_file_name = optarg;
772 delete_exp_file = 0;
773 break;
774 case OPTION_EXPORT_ALL_SYMS:
775 export_all = 1;
776 break;
777 case OPTION_OUTPUT_LIB:
778 output_lib_file_name = optarg;
779 break;
780 case '?':
781 break;
782 default:
783 dlltool_arg = 1;
784 break;
787 /* Handle passing through --option=value case. */
788 if (optarg
789 && saved_argv[optind-1][0] == '-'
790 && saved_argv[optind-1][1] == '-'
791 && strchr (saved_argv[optind-1], '='))
792 single_word_option_value_pair = 1;
794 if (dlltool_arg)
796 dlltool_arg_indices[optind-1] = 1;
797 if (optarg && ! single_word_option_value_pair)
799 dlltool_arg_indices[optind-2] = 1;
803 if (! driver_arg)
805 driver_arg_indices[optind-1] = 0;
806 if (optarg && ! single_word_option_value_pair)
808 driver_arg_indices[optind-2] = 0;
813 /* sanity checks. */
814 if (! dll_name && ! dll_file_name)
816 warn (_("Must provide at least one of -o or --dllname options"));
817 exit (1);
819 else if (! dll_name)
821 dll_name = xstrdup (mybasename (dll_file_name));
823 else if (! dll_file_name)
825 dll_file_name = xstrdup (dll_name);
828 /* Deduce driver-name and dlltool-name from our own. */
829 if (driver_name == NULL)
830 driver_name = deduce_name ("gcc");
832 if (dlltool_name == NULL)
833 dlltool_name = deduce_name ("dlltool");
835 if (! def_file_seen)
837 char *fileprefix = choose_temp_base ();
838 def_file_name = (char *) xmalloc (strlen (fileprefix) + 5);
839 sprintf (def_file_name, "%s.def",
840 (dontdeltemps) ? mybasename (fileprefix) : fileprefix);
841 delete_def_file = 1;
842 free (fileprefix);
843 delete_def_file = 1;
844 warn (_("no export definition file provided"));
845 warn (_("creating one, but that may not be what you want"));
848 /* set the target platform. */
849 if (strstr (target, "cygwin"))
850 which_target = CYGWIN_TARGET;
851 else if (strstr (target, "mingw"))
852 which_target = MINGW_TARGET;
853 else
854 which_target = UNKNOWN_TARGET;
856 /* re-create the command lines as a string, taking care to quote stuff. */
857 dlltool_cmdline = dyn_string_new (cmdline_len);
858 if (verbose)
860 dyn_string_append_cstr (dlltool_cmdline, " -v");
862 dyn_string_append_cstr (dlltool_cmdline, " --dllname ");
863 dyn_string_append_cstr (dlltool_cmdline, dll_name);
865 for (i = 1; i < argc; ++i)
867 if (dlltool_arg_indices[i])
869 char *arg = saved_argv[i];
870 int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
871 dyn_string_append_cstr (dlltool_cmdline,
872 (quote) ? " \"" : " ");
873 dyn_string_append_cstr (dlltool_cmdline, arg);
874 dyn_string_append_cstr (dlltool_cmdline,
875 (quote) ? "\"" : "");
879 driver_cmdline = dyn_string_new (cmdline_len);
880 if (! driver_flags || strlen (driver_flags) == 0)
882 switch (which_target)
884 case CYGWIN_TARGET:
885 driver_flags = cygwin_driver_flags;
886 break;
888 case MINGW_TARGET:
889 driver_flags = mingw32_driver_flags;
890 break;
892 default:
893 driver_flags = generic_driver_flags;
894 break;
897 dyn_string_append_cstr (driver_cmdline, driver_flags);
898 dyn_string_append_cstr (driver_cmdline, " -o ");
899 dyn_string_append_cstr (driver_cmdline, dll_file_name);
901 if (! entry_point || strlen (entry_point) == 0)
903 switch (which_target)
905 case CYGWIN_TARGET:
906 entry_point = "__cygwin_dll_entry@12";
907 break;
909 case MINGW_TARGET:
910 entry_point = "_DllMainCRTStartup@12";
911 break;
913 default:
914 entry_point = "_DllMain@12";
915 break;
918 dyn_string_append_cstr (driver_cmdline, " -Wl,-e,");
919 dyn_string_append_cstr (driver_cmdline, entry_point);
920 dyn_string_append_cstr (dlltool_cmdline, " --exclude-symbol=");
921 dyn_string_append_cstr (dlltool_cmdline,
922 (entry_point[0] == '_') ? entry_point+1 : entry_point);
924 if (! image_base_str || strlen (image_base_str) == 0)
926 char *tmpbuf = (char *) xmalloc (sizeof ("0x12345678") + 1);
927 unsigned long hash = strhash (dll_file_name);
928 sprintf (tmpbuf, "0x%.8lX", 0x60000000|((hash<<16)&0xFFC0000));
929 image_base_str = tmpbuf;
932 dyn_string_append_cstr (driver_cmdline, " -Wl,--image-base,");
933 dyn_string_append_cstr (driver_cmdline, image_base_str);
935 if (verbose)
937 dyn_string_append_cstr (driver_cmdline, " -v");
940 for (i = 1; i < argc; ++i)
942 if (driver_arg_indices[i])
944 char *arg = saved_argv[i];
945 int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
946 dyn_string_append_cstr (driver_cmdline,
947 (quote) ? " \"" : " ");
948 dyn_string_append_cstr (driver_cmdline, arg);
949 dyn_string_append_cstr (driver_cmdline,
950 (quote) ? "\"" : "");
955 * Step pre-1. If no --def <EXPORT_DEF> is specified, then create it
956 * and then pass it on.
959 if (! def_file_seen)
961 int i;
962 dyn_string_t step_pre1;
964 step_pre1 = dyn_string_new (1024);
966 dyn_string_append_cstr (step_pre1, dlltool_cmdline->s);
967 if (export_all)
969 dyn_string_append_cstr (step_pre1, " --export-all --exclude-symbol=");
970 dyn_string_append_cstr (step_pre1,
971 "_cygwin_dll_entry@12,DllMainCRTStartup@12,DllMain@12,DllEntryPoint@12");
973 dyn_string_append_cstr (step_pre1, " --output-def ");
974 dyn_string_append_cstr (step_pre1, def_file_name);
976 for (i = 1; i < argc; ++i)
978 if (driver_arg_indices[i])
980 char *arg = saved_argv[i];
981 size_t len = strlen (arg);
982 if (len >= 2 && arg[len-2] == '.'
983 && (arg[len-1] == 'o' || arg[len-1] == 'a'))
985 int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
986 dyn_string_append_cstr (step_pre1,
987 (quote) ? " \"" : " ");
988 dyn_string_append_cstr (step_pre1, arg);
989 dyn_string_append_cstr (step_pre1,
990 (quote) ? "\"" : "");
995 if (run (dlltool_name, step_pre1->s))
996 cleanup_and_exit (1);
998 dyn_string_delete (step_pre1);
1001 dyn_string_append_cstr (dlltool_cmdline, " --def ");
1002 dyn_string_append_cstr (dlltool_cmdline, def_file_name);
1004 if (verbose)
1006 fprintf (stderr, _("DLLTOOL name : %s\n"), dlltool_name);
1007 fprintf (stderr, _("DLLTOOL options : %s\n"), dlltool_cmdline->s);
1008 fprintf (stderr, _("DRIVER name : %s\n"), driver_name);
1009 fprintf (stderr, _("DRIVER options : %s\n"), driver_cmdline->s);
1013 * Step 1. Call GCC/LD to create base relocation file. If using GCC, the
1014 * driver command line will look like the following:
1016 * % gcc -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
1018 * If the user does not specify a base name, create temporary one that
1019 * is deleted at exit.
1023 if (! base_file_name)
1025 char *fileprefix = choose_temp_base ();
1026 base_file_name = (char *) xmalloc (strlen (fileprefix) + 6);
1027 sprintf (base_file_name, "%s.base",
1028 (dontdeltemps) ? mybasename (fileprefix) : fileprefix);
1029 delete_base_file = 1;
1030 free (fileprefix);
1034 int quote;
1036 dyn_string_t step1 = dyn_string_new (driver_cmdline->length
1037 + strlen (base_file_name)
1038 + 20);
1039 dyn_string_append_cstr (step1, "-Wl,--base-file,");
1040 quote = (strchr (base_file_name, ' ')
1041 || strchr (base_file_name, '\t'));
1042 dyn_string_append_cstr (step1,
1043 (quote) ? "\"" : "");
1044 dyn_string_append_cstr (step1, base_file_name);
1045 dyn_string_append_cstr (step1,
1046 (quote) ? "\"" : "");
1047 if (driver_cmdline->length)
1049 dyn_string_append_cstr (step1, " ");
1050 dyn_string_append_cstr (step1, driver_cmdline->s);
1053 if (run (driver_name, step1->s))
1054 cleanup_and_exit (1);
1056 dyn_string_delete (step1);
1062 * Step 2. generate the exp file by running dlltool.
1063 * dlltool command line will look like the following:
1065 * % dlltool -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
1067 * If the user does not specify a base name, create temporary one that
1068 * is deleted at exit.
1072 if (! exp_file_name)
1074 char *p = strrchr (dll_name, '.');
1075 size_t prefix_len = (p) ? p - dll_name : strlen (dll_name);
1076 exp_file_name = (char *) xmalloc (prefix_len + 4 + 1);
1077 strncpy (exp_file_name, dll_name, prefix_len);
1078 exp_file_name[prefix_len] = '\0';
1079 strcat (exp_file_name, ".exp");
1080 delete_exp_file = 1;
1084 int quote;
1085 dyn_string_t step2 = dyn_string_new (dlltool_cmdline->length
1086 + strlen (base_file_name)
1087 + strlen (exp_file_name)
1088 + 20);
1090 dyn_string_append_cstr (step2, "--base-file ");
1091 quote = (strchr (base_file_name, ' ')
1092 || strchr (base_file_name, '\t'));
1093 dyn_string_append_cstr (step2,
1094 (quote) ? "\"" : "");
1095 dyn_string_append_cstr (step2, base_file_name);
1096 dyn_string_append_cstr (step2,
1097 (quote) ? "\" " : " ");
1099 dyn_string_append_cstr (step2, "--output-exp ");
1100 quote = (strchr (exp_file_name, ' ')
1101 || strchr (exp_file_name, '\t'));
1102 dyn_string_append_cstr (step2,
1103 (quote) ? "\"" : "");
1104 dyn_string_append_cstr (step2, exp_file_name);
1105 dyn_string_append_cstr (step2,
1106 (quote) ? "\"" : "");
1108 if (dlltool_cmdline->length)
1110 dyn_string_append_cstr (step2, " ");
1111 dyn_string_append_cstr (step2, dlltool_cmdline->s);
1114 if (run (dlltool_name, step2->s))
1115 cleanup_and_exit (1);
1117 dyn_string_delete (step2);
1121 * Step 3. Call GCC/LD to again, adding the exp file this time.
1122 * driver command line will look like the following:
1124 * % gcc -Wl,--dll --Wl,--base-file,foo.base foo.exp [rest ...]
1128 int quote;
1130 dyn_string_t step3 = dyn_string_new (driver_cmdline->length
1131 + strlen (exp_file_name)
1132 + strlen (base_file_name)
1133 + 20);
1134 dyn_string_append_cstr (step3, "-Wl,--base-file,");
1135 quote = (strchr (base_file_name, ' ')
1136 || strchr (base_file_name, '\t'));
1137 dyn_string_append_cstr (step3,
1138 (quote) ? "\"" : "");
1139 dyn_string_append_cstr (step3, base_file_name);
1140 dyn_string_append_cstr (step3,
1141 (quote) ? "\" " : " ");
1143 quote = (strchr (exp_file_name, ' ')
1144 || strchr (exp_file_name, '\t'));
1145 dyn_string_append_cstr (step3,
1146 (quote) ? "\"" : "");
1147 dyn_string_append_cstr (step3, exp_file_name);
1148 dyn_string_append_cstr (step3,
1149 (quote) ? "\"" : "");
1151 if (driver_cmdline->length)
1153 dyn_string_append_cstr (step3, " ");
1154 dyn_string_append_cstr (step3, driver_cmdline->s);
1157 if (run (driver_name, step3->s))
1158 cleanup_and_exit (1);
1160 dyn_string_delete (step3);
1165 * Step 4. Run DLLTOOL again using the same command line.
1169 int quote;
1170 dyn_string_t step4 = dyn_string_new (dlltool_cmdline->length
1171 + strlen (base_file_name)
1172 + strlen (exp_file_name)
1173 + 20);
1175 dyn_string_append_cstr (step4, "--base-file ");
1176 quote = (strchr (base_file_name, ' ')
1177 || strchr (base_file_name, '\t'));
1178 dyn_string_append_cstr (step4,
1179 (quote) ? "\"" : "");
1180 dyn_string_append_cstr (step4, base_file_name);
1181 dyn_string_append_cstr (step4,
1182 (quote) ? "\" " : " ");
1184 dyn_string_append_cstr (step4, "--output-exp ");
1185 quote = (strchr (exp_file_name, ' ')
1186 || strchr (exp_file_name, '\t'));
1187 dyn_string_append_cstr (step4,
1188 (quote) ? "\"" : "");
1189 dyn_string_append_cstr (step4, exp_file_name);
1190 dyn_string_append_cstr (step4,
1191 (quote) ? "\"" : "");
1193 if (dlltool_cmdline->length)
1195 dyn_string_append_cstr (step4, " ");
1196 dyn_string_append_cstr (step4, dlltool_cmdline->s);
1199 if (output_lib_file_name)
1201 dyn_string_append_cstr (step4, " --output-lib ");
1202 dyn_string_append_cstr (step4, output_lib_file_name);
1205 if (run (dlltool_name, step4->s))
1206 cleanup_and_exit (1);
1208 dyn_string_delete (step4);
1213 * Step 5. Link it all together and be done with it.
1214 * driver command line will look like the following:
1216 * % gcc -Wl,--dll foo.exp [rest ...]
1221 int quote;
1223 dyn_string_t step5 = dyn_string_new (driver_cmdline->length
1224 + strlen (exp_file_name)
1225 + 20);
1226 quote = (strchr (exp_file_name, ' ')
1227 || strchr (exp_file_name, '\t'));
1228 dyn_string_append_cstr (step5,
1229 (quote) ? "\"" : "");
1230 dyn_string_append_cstr (step5, exp_file_name);
1231 dyn_string_append_cstr (step5,
1232 (quote) ? "\"" : "");
1234 if (driver_cmdline->length)
1236 dyn_string_append_cstr (step5, " ");
1237 dyn_string_append_cstr (step5, driver_cmdline->s);
1240 if (run (driver_name, step5->s))
1241 cleanup_and_exit (1);
1243 dyn_string_delete (step5);
1246 cleanup_and_exit (0);
1248 return 0;