1 /* dllwrap.c -- wrapper for DLLTOOL and GCC to generate PE style DLLs
2 Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
3 Contributed by Mumit Khan (khan@xraylith.wisc.edu).
5 This file is part of GNU Binutils.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
22 /* AIX requires this to be the first thing in the file. */
34 #include "libiberty.h"
37 #include "dyn-string.h"
42 #ifdef ANSI_PROTOTYPES
48 #ifdef HAVE_SYS_WAIT_H
50 #else /* ! HAVE_SYS_WAIT_H */
51 #if ! defined (_WIN32) || defined (__CYGWIN32__)
53 #define WIFEXITED(w) (((w)&0377) == 0)
56 #define WIFSIGNALED(w) (((w)&0377) != 0177 && ((w)&~0377) == 0)
59 #define WTERMSIG(w) ((w) & 0177)
62 #define WEXITSTATUS(w) (((w) >> 8) & 0377)
64 #else /* defined (_WIN32) && ! defined (__CYGWIN32__) */
66 #define WIFEXITED(w) (((w) & 0xff) == 0)
69 #define WIFSIGNALED(w) (((w) & 0xff) != 0 && ((w) & 0xff) != 0x7f)
72 #define WTERMSIG(w) ((w) & 0x7f)
75 #define WEXITSTATUS(w) (((w) & 0xff00) >> 8)
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
;
99 static target_type which_target
= UNKNOWN_TARGET
;
101 static int dontdeltemps
= 0;
102 static int dry_run
= 0;
104 static char *prog_name
;
106 static int verbose
= 0;
108 static char *dll_file_name
;
109 static char *dll_name
;
110 static char *base_file_name
;
111 static char *exp_file_name
;
112 static char *def_file_name
;
113 static int delete_base_file
= 1;
114 static int delete_exp_file
= 1;
115 static int delete_def_file
= 1;
117 static int run (const char *, char *);
118 static char *mybasename (const char *);
119 static int strhash (const char *);
120 static void usage (FILE *, int);
121 static void display (const char *, va_list);
122 static void inform (const char *, ...);
123 static void warn (const char *, ...);
124 static char *look_for_prog (const char *, const char *, int);
125 static char *deduce_name (const char *);
126 static void delete_temp_files (void);
127 static void cleanup_and_exit (int);
129 /**********************************************************************/
131 /* Please keep the following 4 routines in sync with dlltool.c:
136 It's not worth the hassle to break these out since dllwrap will
137 (hopefully) soon be retired in favor of `ld --shared. */
140 display (const char * message
, va_list args
)
142 if (prog_name
!= NULL
)
143 fprintf (stderr
, "%s: ", prog_name
);
145 vfprintf (stderr
, message
, args
);
146 fputc ('\n', stderr
);
151 inform
VPARAMS ((const char *message
, ...))
153 VA_OPEN (args
, message
);
154 VA_FIXEDARG (args
, const char *, message
);
159 display (message
, args
);
165 warn
VPARAMS ((const char *format
, ...))
167 VA_OPEN (args
, format
);
168 VA_FIXEDARG (args
, const char *, format
);
170 display (format
, 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
181 look_for_prog (const char *prog_name
, const char *prefix
, int end_prefix
)
186 cmd
= xmalloc (strlen (prefix
)
188 #ifdef HAVE_EXECUTABLE_SUFFIX
189 + strlen (EXECUTABLE_SUFFIX
)
192 strcpy (cmd
, prefix
);
194 sprintf (cmd
+ end_prefix
, "%s", prog_name
);
196 if (strchr (cmd
, '/') != NULL
)
200 found
= (stat (cmd
, &s
) == 0
201 #ifdef HAVE_EXECUTABLE_SUFFIX
202 || stat (strcat (cmd
, EXECUTABLE_SUFFIX
), &s
) == 0
208 /* xgettext:c-format */
209 inform (_("Tried file: %s"), cmd
);
215 /* xgettext:c-format */
216 inform (_("Using file: %s"), 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
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. */
247 deduce_name (const char * name
)
256 for (cp
= prog_name
; *cp
!= '\0'; ++cp
)
262 #if defined(__DJGPP__) || defined (__CYGWIN__) || defined(__WIN32__)
263 *cp
== ':' || *cp
== '\\' ||
275 /* First, try looking for a prefixed NAME in the
276 PROG_NAME directory, with the same prefix as PROG_NAME. */
277 cmd
= look_for_prog (name
, prog_name
, dash
- prog_name
+ 1);
279 if (slash
!= NULL
&& cmd
== NULL
)
280 /* Next, try looking for a NAME in the same directory as
281 that of this program. */
282 cmd
= look_for_prog (name
, prog_name
, slash
- prog_name
+ 1);
285 /* Just return NAME as is. */
286 cmd
= xstrdup (name
);
292 delete_temp_files (void)
294 if (delete_base_file
&& base_file_name
)
299 warn (_("Keeping temporary base file %s"), base_file_name
);
301 warn (_("Deleting temporary base file %s"), base_file_name
);
305 unlink (base_file_name
);
306 free (base_file_name
);
310 if (delete_exp_file
&& exp_file_name
)
315 warn (_("Keeping temporary exp file %s"), exp_file_name
);
317 warn (_("Deleting temporary exp file %s"), exp_file_name
);
321 unlink (exp_file_name
);
322 free (exp_file_name
);
325 if (delete_def_file
&& def_file_name
)
330 warn (_("Keeping temporary def file %s"), def_file_name
);
332 warn (_("Deleting temporary def file %s"), def_file_name
);
336 unlink (def_file_name
);
337 free (def_file_name
);
343 cleanup_and_exit (int status
)
345 delete_temp_files ();
350 run (const char *what
, char *args
)
353 int pid
, wait_status
, retcode
;
356 char *errmsg_fmt
, *errmsg_arg
;
357 char *temp_base
= choose_temp_base ();
361 if (verbose
|| dry_run
)
362 fprintf (stderr
, "%s %s\n", what
, args
);
366 for (s
= args
; *s
; s
++)
370 argv
= alloca (sizeof (char *) * (i
+ 3));
376 while (*s
== ' ' && *s
!= 0)
380 in_quote
= (*s
== '\'' || *s
== '"');
381 sep
= (in_quote
) ? *s
++ : ' ';
383 while (*s
!= sep
&& *s
!= 0)
396 pid
= pexecute (argv
[0], (char * const *) argv
, prog_name
, temp_base
,
397 &errmsg_fmt
, &errmsg_arg
, PEXECUTE_ONE
| PEXECUTE_SEARCH
);
401 int errno_val
= errno
;
403 fprintf (stderr
, "%s: ", prog_name
);
404 fprintf (stderr
, errmsg_fmt
, errmsg_arg
);
405 fprintf (stderr
, ": %s\n", strerror (errno_val
));
410 pid
= pwait (pid
, &wait_status
, 0);
413 warn ("wait: %s", strerror (errno
));
416 else if (WIFSIGNALED (wait_status
))
418 warn (_("subprocess got fatal signal %d"), WTERMSIG (wait_status
));
421 else if (WIFEXITED (wait_status
))
423 if (WEXITSTATUS (wait_status
) != 0)
425 warn (_("%s exited with status %d"), what
, WEXITSTATUS (wait_status
));
436 mybasename (const char *name
)
438 const char *base
= name
;
442 if (*name
== '/' || *name
== '\\')
448 return (char *) base
;
452 strhash (const char *str
)
454 const unsigned char *s
;
461 s
= (const unsigned char *) str
;
462 while ((c
= *s
++) != '\0')
464 hash
+= c
+ (c
<< 17);
468 hash
+= len
+ (len
<< 17);
474 /**********************************************************************/
477 usage (FILE *file
, int status
)
479 fprintf (file
, _("Usage %s <option(s)> <object-file(s)>\n"), prog_name
);
480 fprintf (file
, _(" Generic options:\n"));
481 fprintf (file
, _(" --quiet, -q Work quietly\n"));
482 fprintf (file
, _(" --verbose, -v Verbose\n"));
483 fprintf (file
, _(" --version Print dllwrap version\n"));
484 fprintf (file
, _(" --implib <outname> Synonym for --output-lib\n"));
485 fprintf (file
, _(" Options for %s:\n"), prog_name
);
486 fprintf (file
, _(" --driver-name <driver> Defaults to \"gcc\"\n"));
487 fprintf (file
, _(" --driver-flags <flags> Override default ld flags\n"));
488 fprintf (file
, _(" --dlltool-name <dlltool> Defaults to \"dlltool\"\n"));
489 fprintf (file
, _(" --entry <entry> Specify alternate DLL entry point\n"));
490 fprintf (file
, _(" --image-base <base> Specify image base address\n"));
491 fprintf (file
, _(" --target <machine> i386-cygwin32 or i386-mingw32\n"));
492 fprintf (file
, _(" --dry-run Show what needs to be run\n"));
493 fprintf (file
, _(" --mno-cygwin Create Mingw DLL\n"));
494 fprintf (file
, _(" Options passed to DLLTOOL:\n"));
495 fprintf (file
, _(" --machine <machine>\n"));
496 fprintf (file
, _(" --output-exp <outname> Generate export file.\n"));
497 fprintf (file
, _(" --output-lib <outname> Generate input library.\n"));
498 fprintf (file
, _(" --add-indirect Add dll indirects to export file.\n"));
499 fprintf (file
, _(" --dllname <name> Name of input dll to put into output lib.\n"));
500 fprintf (file
, _(" --def <deffile> Name input .def file\n"));
501 fprintf (file
, _(" --output-def <deffile> Name output .def file\n"));
502 fprintf (file
, _(" --export-all-symbols Export all symbols to .def\n"));
503 fprintf (file
, _(" --no-export-all-symbols Only export .drectve symbols\n"));
504 fprintf (file
, _(" --exclude-symbols <list> Exclude <list> from .def\n"));
505 fprintf (file
, _(" --no-default-excludes Zap default exclude symbols\n"));
506 fprintf (file
, _(" --base-file <basefile> Read linker generated base file\n"));
507 fprintf (file
, _(" --no-idata4 Don't generate idata$4 section\n"));
508 fprintf (file
, _(" --no-idata5 Don't generate idata$5 section\n"));
509 fprintf (file
, _(" -U Add underscores to .lib\n"));
510 fprintf (file
, _(" -k Kill @<n> from exported names\n"));
511 fprintf (file
, _(" --add-stdcall-alias Add aliases without @<n>\n"));
512 fprintf (file
, _(" --as <name> Use <name> for assembler\n"));
513 fprintf (file
, _(" --nodelete Keep temp files.\n"));
514 fprintf (file
, _(" Rest are passed unmodified to the language driver\n"));
515 fprintf (file
, "\n\n");
519 #define OPTION_START 149
521 /* GENERIC options. */
522 #define OPTION_QUIET (OPTION_START + 1)
523 #define OPTION_VERBOSE (OPTION_QUIET + 1)
524 #define OPTION_VERSION (OPTION_VERBOSE + 1)
526 /* DLLWRAP options. */
527 #define OPTION_DRY_RUN (OPTION_VERSION + 1)
528 #define OPTION_DRIVER_NAME (OPTION_DRY_RUN + 1)
529 #define OPTION_DRIVER_FLAGS (OPTION_DRIVER_NAME + 1)
530 #define OPTION_DLLTOOL_NAME (OPTION_DRIVER_FLAGS + 1)
531 #define OPTION_ENTRY (OPTION_DLLTOOL_NAME + 1)
532 #define OPTION_IMAGE_BASE (OPTION_ENTRY + 1)
533 #define OPTION_TARGET (OPTION_IMAGE_BASE + 1)
534 #define OPTION_MNO_CYGWIN (OPTION_TARGET + 1)
536 /* DLLTOOL options. */
537 #define OPTION_NODELETE (OPTION_MNO_CYGWIN + 1)
538 #define OPTION_DLLNAME (OPTION_NODELETE + 1)
539 #define OPTION_NO_IDATA4 (OPTION_DLLNAME + 1)
540 #define OPTION_NO_IDATA5 (OPTION_NO_IDATA4 + 1)
541 #define OPTION_OUTPUT_EXP (OPTION_NO_IDATA5 + 1)
542 #define OPTION_OUTPUT_DEF (OPTION_OUTPUT_EXP + 1)
543 #define OPTION_EXPORT_ALL_SYMS (OPTION_OUTPUT_DEF + 1)
544 #define OPTION_NO_EXPORT_ALL_SYMS (OPTION_EXPORT_ALL_SYMS + 1)
545 #define OPTION_EXCLUDE_SYMS (OPTION_NO_EXPORT_ALL_SYMS + 1)
546 #define OPTION_NO_DEFAULT_EXCLUDES (OPTION_EXCLUDE_SYMS + 1)
547 #define OPTION_OUTPUT_LIB (OPTION_NO_DEFAULT_EXCLUDES + 1)
548 #define OPTION_DEF (OPTION_OUTPUT_LIB + 1)
549 #define OPTION_ADD_UNDERSCORE (OPTION_DEF + 1)
550 #define OPTION_KILLAT (OPTION_ADD_UNDERSCORE + 1)
551 #define OPTION_HELP (OPTION_KILLAT + 1)
552 #define OPTION_MACHINE (OPTION_HELP + 1)
553 #define OPTION_ADD_INDIRECT (OPTION_MACHINE + 1)
554 #define OPTION_BASE_FILE (OPTION_ADD_INDIRECT + 1)
555 #define OPTION_AS (OPTION_BASE_FILE + 1)
557 static const struct option long_options
[] =
559 /* generic options. */
560 {"quiet", no_argument
, NULL
, 'q'},
561 {"verbose", no_argument
, NULL
, 'v'},
562 {"version", no_argument
, NULL
, OPTION_VERSION
},
563 {"implib", required_argument
, NULL
, OPTION_OUTPUT_LIB
},
565 /* dllwrap options. */
566 {"dry-run", no_argument
, NULL
, OPTION_DRY_RUN
},
567 {"driver-name", required_argument
, NULL
, OPTION_DRIVER_NAME
},
568 {"driver-flags", required_argument
, NULL
, OPTION_DRIVER_FLAGS
},
569 {"dlltool-name", required_argument
, NULL
, OPTION_DLLTOOL_NAME
},
570 {"entry", required_argument
, NULL
, 'e'},
571 {"image-base", required_argument
, NULL
, OPTION_IMAGE_BASE
},
572 {"target", required_argument
, NULL
, OPTION_TARGET
},
574 /* dlltool options. */
575 {"no-delete", no_argument
, NULL
, 'n'},
576 {"dllname", required_argument
, NULL
, OPTION_DLLNAME
},
577 {"no-idata4", no_argument
, NULL
, OPTION_NO_IDATA4
},
578 {"no-idata5", no_argument
, NULL
, OPTION_NO_IDATA5
},
579 {"output-exp", required_argument
, NULL
, OPTION_OUTPUT_EXP
},
580 {"output-def", required_argument
, NULL
, OPTION_OUTPUT_DEF
},
581 {"export-all-symbols", no_argument
, NULL
, OPTION_EXPORT_ALL_SYMS
},
582 {"no-export-all-symbols", no_argument
, NULL
, OPTION_NO_EXPORT_ALL_SYMS
},
583 {"exclude-symbols", required_argument
, NULL
, OPTION_EXCLUDE_SYMS
},
584 {"no-default-excludes", no_argument
, NULL
, OPTION_NO_DEFAULT_EXCLUDES
},
585 {"output-lib", required_argument
, NULL
, OPTION_OUTPUT_LIB
},
586 {"def", required_argument
, NULL
, OPTION_DEF
},
587 {"add-underscore", no_argument
, NULL
, 'U'},
588 {"killat", no_argument
, NULL
, 'k'},
589 {"add-stdcall-alias", no_argument
, NULL
, 'A'},
590 {"help", no_argument
, NULL
, 'h'},
591 {"machine", required_argument
, NULL
, OPTION_MACHINE
},
592 {"add-indirect", no_argument
, NULL
, OPTION_ADD_INDIRECT
},
593 {"base-file", required_argument
, NULL
, OPTION_BASE_FILE
},
594 {"as", required_argument
, NULL
, OPTION_AS
},
598 int main (int, char **);
601 main (int argc
, char **argv
)
606 char **saved_argv
= 0;
611 int *dlltool_arg_indices
;
612 int *driver_arg_indices
;
614 char *driver_flags
= 0;
615 char *output_lib_file_name
= 0;
617 dyn_string_t dlltool_cmdline
;
618 dyn_string_t driver_cmdline
;
620 int def_file_seen
= 0;
622 char *image_base_str
= 0;
626 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
627 setlocale (LC_MESSAGES
, "");
629 #if defined (HAVE_SETLOCALE)
630 setlocale (LC_CTYPE
, "");
632 bindtextdomain (PACKAGE
, LOCALEDIR
);
633 textdomain (PACKAGE
);
635 saved_argv
= (char **) xmalloc (argc
* sizeof (char*));
636 dlltool_arg_indices
= (int *) xmalloc (argc
* sizeof (int));
637 driver_arg_indices
= (int *) xmalloc (argc
* sizeof (int));
638 for (i
= 0; i
< argc
; ++i
)
640 size_t len
= strlen (argv
[i
]);
641 char *arg
= (char *) xmalloc (len
+ 1);
642 strcpy (arg
, argv
[i
]);
645 dlltool_arg_indices
[i
] = 0;
646 driver_arg_indices
[i
] = 1;
650 /* We recognize dllwrap and dlltool options, and everything else is
651 passed onto the language driver (eg., to GCC). We collect options
652 to dlltool and driver in dlltool_args and driver_args. */
655 while ((c
= getopt_long_only (argc
, argv
, "nkAqve:Uho:l:L:I:",
656 long_options
, (int *) 0)) != EOF
)
660 int single_word_option_value_pair
;
664 single_word_option_value_pair
= 0;
668 /* We recognize this option, so it has to be either dllwrap or
669 dlltool option. Do not pass to driver unless it's one of the
670 generic options that are passed to all the tools (such as -v)
671 which are dealt with later. */
675 /* deal with generic and dllwrap options first. */
688 print_version (prog_name
);
691 entry_point
= optarg
;
693 case OPTION_IMAGE_BASE
:
694 image_base_str
= optarg
;
697 def_file_name
= optarg
;
706 dll_file_name
= optarg
;
719 case OPTION_DRIVER_NAME
:
720 driver_name
= optarg
;
722 case OPTION_DRIVER_FLAGS
:
723 driver_flags
= optarg
;
725 case OPTION_DLLTOOL_NAME
:
726 dlltool_name
= optarg
;
731 case OPTION_MNO_CYGWIN
:
732 target
= "i386-mingw32";
734 case OPTION_BASE_FILE
:
735 base_file_name
= optarg
;
736 delete_base_file
= 0;
738 case OPTION_OUTPUT_EXP
:
739 exp_file_name
= optarg
;
742 case OPTION_EXPORT_ALL_SYMS
:
745 case OPTION_OUTPUT_LIB
:
746 output_lib_file_name
= optarg
;
755 /* Handle passing through --option=value case. */
757 && saved_argv
[optind
-1][0] == '-'
758 && saved_argv
[optind
-1][1] == '-'
759 && strchr (saved_argv
[optind
-1], '='))
760 single_word_option_value_pair
= 1;
764 dlltool_arg_indices
[optind
-1] = 1;
765 if (optarg
&& ! single_word_option_value_pair
)
767 dlltool_arg_indices
[optind
-2] = 1;
773 driver_arg_indices
[optind
-1] = 0;
774 if (optarg
&& ! single_word_option_value_pair
)
776 driver_arg_indices
[optind
-2] = 0;
782 if (! dll_name
&& ! dll_file_name
)
784 warn (_("Must provide at least one of -o or --dllname options"));
789 dll_name
= xstrdup (mybasename (dll_file_name
));
791 else if (! dll_file_name
)
793 dll_file_name
= xstrdup (dll_name
);
796 /* Deduce driver-name and dlltool-name from our own. */
797 if (driver_name
== NULL
)
798 driver_name
= deduce_name ("gcc");
800 if (dlltool_name
== NULL
)
801 dlltool_name
= deduce_name ("dlltool");
805 char *fileprefix
= choose_temp_base ();
807 def_file_name
= (char *) xmalloc (strlen (fileprefix
) + 5);
808 sprintf (def_file_name
, "%s.def",
809 (dontdeltemps
) ? mybasename (fileprefix
) : fileprefix
);
813 warn (_("no export definition file provided.\n\
814 Creating one, but that may not be what you want"));
817 /* Set the target platform. */
818 if (strstr (target
, "cygwin"))
819 which_target
= CYGWIN_TARGET
;
820 else if (strstr (target
, "mingw"))
821 which_target
= MINGW_TARGET
;
823 which_target
= UNKNOWN_TARGET
;
825 /* Re-create the command lines as a string, taking care to quote stuff. */
826 dlltool_cmdline
= dyn_string_new (cmdline_len
);
828 dyn_string_append_cstr (dlltool_cmdline
, " -v");
830 dyn_string_append_cstr (dlltool_cmdline
, " --dllname ");
831 dyn_string_append_cstr (dlltool_cmdline
, dll_name
);
833 for (i
= 1; i
< argc
; ++i
)
835 if (dlltool_arg_indices
[i
])
837 char *arg
= saved_argv
[i
];
838 int quote
= (strchr (arg
, ' ') || strchr (arg
, '\t'));
839 dyn_string_append_cstr (dlltool_cmdline
,
840 (quote
) ? " \"" : " ");
841 dyn_string_append_cstr (dlltool_cmdline
, arg
);
842 dyn_string_append_cstr (dlltool_cmdline
,
843 (quote
) ? "\"" : "");
847 driver_cmdline
= dyn_string_new (cmdline_len
);
848 if (! driver_flags
|| strlen (driver_flags
) == 0)
850 switch (which_target
)
853 driver_flags
= cygwin_driver_flags
;
857 driver_flags
= mingw32_driver_flags
;
861 driver_flags
= generic_driver_flags
;
865 dyn_string_append_cstr (driver_cmdline
, driver_flags
);
866 dyn_string_append_cstr (driver_cmdline
, " -o ");
867 dyn_string_append_cstr (driver_cmdline
, dll_file_name
);
869 if (! entry_point
|| strlen (entry_point
) == 0)
871 switch (which_target
)
874 entry_point
= "__cygwin_dll_entry@12";
878 entry_point
= "_DllMainCRTStartup@12";
882 entry_point
= "_DllMain@12";
886 dyn_string_append_cstr (driver_cmdline
, " -Wl,-e,");
887 dyn_string_append_cstr (driver_cmdline
, entry_point
);
888 dyn_string_append_cstr (dlltool_cmdline
, " --exclude-symbol=");
889 dyn_string_append_cstr (dlltool_cmdline
,
890 (entry_point
[0] == '_') ? entry_point
+1 : entry_point
);
892 if (! image_base_str
|| strlen (image_base_str
) == 0)
894 char *tmpbuf
= (char *) xmalloc (sizeof ("0x12345678") + 1);
895 unsigned long hash
= strhash (dll_file_name
);
896 sprintf (tmpbuf
, "0x%.8lX", 0x60000000|((hash
<<16)&0xFFC0000));
897 image_base_str
= tmpbuf
;
900 dyn_string_append_cstr (driver_cmdline
, " -Wl,--image-base,");
901 dyn_string_append_cstr (driver_cmdline
, image_base_str
);
905 dyn_string_append_cstr (driver_cmdline
, " -v");
908 for (i
= 1; i
< argc
; ++i
)
910 if (driver_arg_indices
[i
])
912 char *arg
= saved_argv
[i
];
913 int quote
= (strchr (arg
, ' ') || strchr (arg
, '\t'));
914 dyn_string_append_cstr (driver_cmdline
,
915 (quote
) ? " \"" : " ");
916 dyn_string_append_cstr (driver_cmdline
, arg
);
917 dyn_string_append_cstr (driver_cmdline
,
918 (quote
) ? "\"" : "");
922 /* Step pre-1. If no --def <EXPORT_DEF> is specified,
923 then create it and then pass it on. */
928 dyn_string_t step_pre1
;
930 step_pre1
= dyn_string_new (1024);
932 dyn_string_append_cstr (step_pre1
, dlltool_cmdline
->s
);
935 dyn_string_append_cstr (step_pre1
, " --export-all --exclude-symbol=");
936 dyn_string_append_cstr (step_pre1
,
937 "_cygwin_dll_entry@12,DllMainCRTStartup@12,DllMain@12,DllEntryPoint@12");
939 dyn_string_append_cstr (step_pre1
, " --output-def ");
940 dyn_string_append_cstr (step_pre1
, def_file_name
);
942 for (i
= 1; i
< argc
; ++i
)
944 if (driver_arg_indices
[i
])
946 char *arg
= saved_argv
[i
];
947 size_t len
= strlen (arg
);
948 if (len
>= 2 && arg
[len
-2] == '.'
949 && (arg
[len
-1] == 'o' || arg
[len
-1] == 'a'))
951 int quote
= (strchr (arg
, ' ') || strchr (arg
, '\t'));
952 dyn_string_append_cstr (step_pre1
,
953 (quote
) ? " \"" : " ");
954 dyn_string_append_cstr (step_pre1
, arg
);
955 dyn_string_append_cstr (step_pre1
,
956 (quote
) ? "\"" : "");
961 if (run (dlltool_name
, step_pre1
->s
))
962 cleanup_and_exit (1);
964 dyn_string_delete (step_pre1
);
967 dyn_string_append_cstr (dlltool_cmdline
, " --def ");
968 dyn_string_append_cstr (dlltool_cmdline
, def_file_name
);
972 fprintf (stderr
, _("DLLTOOL name : %s\n"), dlltool_name
);
973 fprintf (stderr
, _("DLLTOOL options : %s\n"), dlltool_cmdline
->s
);
974 fprintf (stderr
, _("DRIVER name : %s\n"), driver_name
);
975 fprintf (stderr
, _("DRIVER options : %s\n"), driver_cmdline
->s
);
978 /* Step 1. Call GCC/LD to create base relocation file. If using GCC, the
979 driver command line will look like the following:
981 % gcc -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
983 If the user does not specify a base name, create temporary one that
984 is deleted at exit. */
986 if (! base_file_name
)
988 char *fileprefix
= choose_temp_base ();
989 base_file_name
= (char *) xmalloc (strlen (fileprefix
) + 6);
990 sprintf (base_file_name
, "%s.base",
991 (dontdeltemps
) ? mybasename (fileprefix
) : fileprefix
);
992 delete_base_file
= 1;
999 dyn_string_t step1
= dyn_string_new (driver_cmdline
->length
1000 + strlen (base_file_name
)
1002 dyn_string_append_cstr (step1
, "-Wl,--base-file,");
1003 quote
= (strchr (base_file_name
, ' ')
1004 || strchr (base_file_name
, '\t'));
1005 dyn_string_append_cstr (step1
,
1006 (quote
) ? "\"" : "");
1007 dyn_string_append_cstr (step1
, base_file_name
);
1008 dyn_string_append_cstr (step1
,
1009 (quote
) ? "\"" : "");
1010 if (driver_cmdline
->length
)
1012 dyn_string_append_cstr (step1
, " ");
1013 dyn_string_append_cstr (step1
, driver_cmdline
->s
);
1016 if (run (driver_name
, step1
->s
))
1017 cleanup_and_exit (1);
1019 dyn_string_delete (step1
);
1022 /* Step 2. generate the exp file by running dlltool.
1023 dlltool command line will look like the following:
1025 % dlltool -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
1027 If the user does not specify a base name, create temporary one that
1028 is deleted at exit. */
1030 if (! exp_file_name
)
1032 char *p
= strrchr (dll_name
, '.');
1033 size_t prefix_len
= (p
) ? (size_t) (p
- dll_name
) : strlen (dll_name
);
1035 exp_file_name
= (char *) xmalloc (prefix_len
+ 4 + 1);
1036 strncpy (exp_file_name
, dll_name
, prefix_len
);
1037 exp_file_name
[prefix_len
] = '\0';
1038 strcat (exp_file_name
, ".exp");
1039 delete_exp_file
= 1;
1045 dyn_string_t step2
= dyn_string_new (dlltool_cmdline
->length
1046 + strlen (base_file_name
)
1047 + strlen (exp_file_name
)
1050 dyn_string_append_cstr (step2
, "--base-file ");
1051 quote
= (strchr (base_file_name
, ' ')
1052 || strchr (base_file_name
, '\t'));
1053 dyn_string_append_cstr (step2
,
1054 (quote
) ? "\"" : "");
1055 dyn_string_append_cstr (step2
, base_file_name
);
1056 dyn_string_append_cstr (step2
,
1057 (quote
) ? "\" " : " ");
1059 dyn_string_append_cstr (step2
, "--output-exp ");
1060 quote
= (strchr (exp_file_name
, ' ')
1061 || strchr (exp_file_name
, '\t'));
1062 dyn_string_append_cstr (step2
,
1063 (quote
) ? "\"" : "");
1064 dyn_string_append_cstr (step2
, exp_file_name
);
1065 dyn_string_append_cstr (step2
,
1066 (quote
) ? "\"" : "");
1068 if (dlltool_cmdline
->length
)
1070 dyn_string_append_cstr (step2
, " ");
1071 dyn_string_append_cstr (step2
, dlltool_cmdline
->s
);
1074 if (run (dlltool_name
, step2
->s
))
1075 cleanup_and_exit (1);
1077 dyn_string_delete (step2
);
1081 * Step 3. Call GCC/LD to again, adding the exp file this time.
1082 * driver command line will look like the following:
1084 * % gcc -Wl,--dll --Wl,--base-file,foo.base foo.exp [rest ...]
1090 dyn_string_t step3
= dyn_string_new (driver_cmdline
->length
1091 + strlen (exp_file_name
)
1092 + strlen (base_file_name
)
1094 dyn_string_append_cstr (step3
, "-Wl,--base-file,");
1095 quote
= (strchr (base_file_name
, ' ')
1096 || strchr (base_file_name
, '\t'));
1097 dyn_string_append_cstr (step3
,
1098 (quote
) ? "\"" : "");
1099 dyn_string_append_cstr (step3
, base_file_name
);
1100 dyn_string_append_cstr (step3
,
1101 (quote
) ? "\" " : " ");
1103 quote
= (strchr (exp_file_name
, ' ')
1104 || strchr (exp_file_name
, '\t'));
1105 dyn_string_append_cstr (step3
,
1106 (quote
) ? "\"" : "");
1107 dyn_string_append_cstr (step3
, exp_file_name
);
1108 dyn_string_append_cstr (step3
,
1109 (quote
) ? "\"" : "");
1111 if (driver_cmdline
->length
)
1113 dyn_string_append_cstr (step3
, " ");
1114 dyn_string_append_cstr (step3
, driver_cmdline
->s
);
1117 if (run (driver_name
, step3
->s
))
1118 cleanup_and_exit (1);
1120 dyn_string_delete (step3
);
1125 * Step 4. Run DLLTOOL again using the same command line.
1130 dyn_string_t step4
= dyn_string_new (dlltool_cmdline
->length
1131 + strlen (base_file_name
)
1132 + strlen (exp_file_name
)
1135 dyn_string_append_cstr (step4
, "--base-file ");
1136 quote
= (strchr (base_file_name
, ' ')
1137 || strchr (base_file_name
, '\t'));
1138 dyn_string_append_cstr (step4
,
1139 (quote
) ? "\"" : "");
1140 dyn_string_append_cstr (step4
, base_file_name
);
1141 dyn_string_append_cstr (step4
,
1142 (quote
) ? "\" " : " ");
1144 dyn_string_append_cstr (step4
, "--output-exp ");
1145 quote
= (strchr (exp_file_name
, ' ')
1146 || strchr (exp_file_name
, '\t'));
1147 dyn_string_append_cstr (step4
,
1148 (quote
) ? "\"" : "");
1149 dyn_string_append_cstr (step4
, exp_file_name
);
1150 dyn_string_append_cstr (step4
,
1151 (quote
) ? "\"" : "");
1153 if (dlltool_cmdline
->length
)
1155 dyn_string_append_cstr (step4
, " ");
1156 dyn_string_append_cstr (step4
, dlltool_cmdline
->s
);
1159 if (output_lib_file_name
)
1161 dyn_string_append_cstr (step4
, " --output-lib ");
1162 dyn_string_append_cstr (step4
, output_lib_file_name
);
1165 if (run (dlltool_name
, step4
->s
))
1166 cleanup_and_exit (1);
1168 dyn_string_delete (step4
);
1173 * Step 5. Link it all together and be done with it.
1174 * driver command line will look like the following:
1176 * % gcc -Wl,--dll foo.exp [rest ...]
1183 dyn_string_t step5
= dyn_string_new (driver_cmdline
->length
1184 + strlen (exp_file_name
)
1186 quote
= (strchr (exp_file_name
, ' ')
1187 || strchr (exp_file_name
, '\t'));
1188 dyn_string_append_cstr (step5
,
1189 (quote
) ? "\"" : "");
1190 dyn_string_append_cstr (step5
, exp_file_name
);
1191 dyn_string_append_cstr (step5
,
1192 (quote
) ? "\"" : "");
1194 if (driver_cmdline
->length
)
1196 dyn_string_append_cstr (step5
, " ");
1197 dyn_string_append_cstr (step5
, driver_cmdline
->s
);
1200 if (run (driver_name
, step5
->s
))
1201 cleanup_and_exit (1);
1203 dyn_string_delete (step5
);
1206 cleanup_and_exit (0);