1 /* dllwrap.c -- wrapper for DLLTOOL and GCC to generate PE style DLLs
2 Copyright 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
3 Contributed by Mumit Khan (khan@xraylith.wisc.edu).
5 This file is part of GNU Binutils.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
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 *program_name
;
106 static int verbose
= 0;
108 static char *dll_file_name
;
109 static char *dll_name
;
110 static char *base_file_name
;
111 static char *exp_file_name
;
112 static char *def_file_name
;
113 static int delete_base_file
= 1;
114 static int delete_exp_file
= 1;
115 static int delete_def_file
= 1;
117 static int run (const char *, char *);
118 static char *mybasename (const char *);
119 static int strhash (const char *);
120 static void usage (FILE *, int);
121 static void display (const char *, va_list);
122 static void inform (const char *, ...);
123 static void warn (const char *, ...);
124 static char *look_for_prog (const char *, const char *, int);
125 static char *deduce_name (const char *);
126 static void delete_temp_files (void);
127 static void cleanup_and_exit (int);
129 /**********************************************************************/
131 /* Please keep the following 4 routines in sync with dlltool.c:
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 (program_name
!= NULL
)
143 fprintf (stderr
, "%s: ", program_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 *prog_name
)
250 char *dash
, *slash
, *cp
;
254 for (cp
= program_name
; *cp
!= '\0'; ++cp
)
259 #if defined(__DJGPP__) || defined (__CYGWIN__) || defined(__WIN32__)
260 *cp
== ':' || *cp
== '\\' ||
273 /* First, try looking for a prefixed PROG_NAME in the
274 PROGRAM_NAME directory, with the same prefix as PROGRAM_NAME. */
275 cmd
= look_for_prog (prog_name
, program_name
, dash
- program_name
+ 1);
278 if (slash
!= NULL
&& cmd
== NULL
)
280 /* Next, try looking for a PROG_NAME in the same directory as
281 that of this program. */
282 cmd
= look_for_prog (prog_name
, program_name
, slash
- program_name
+ 1);
287 /* Just return PROG_NAME as is. */
288 cmd
= xstrdup (prog_name
);
295 delete_temp_files (void)
297 if (delete_base_file
&& base_file_name
)
302 warn (_("Keeping temporary base file %s"), base_file_name
);
304 warn (_("Deleting temporary base file %s"), base_file_name
);
308 unlink (base_file_name
);
309 free (base_file_name
);
313 if (delete_exp_file
&& exp_file_name
)
318 warn (_("Keeping temporary exp file %s"), exp_file_name
);
320 warn (_("Deleting temporary exp file %s"), exp_file_name
);
324 unlink (exp_file_name
);
325 free (exp_file_name
);
328 if (delete_def_file
&& def_file_name
)
333 warn (_("Keeping temporary def file %s"), def_file_name
);
335 warn (_("Deleting temporary def file %s"), def_file_name
);
339 unlink (def_file_name
);
340 free (def_file_name
);
346 cleanup_and_exit (int status
)
348 delete_temp_files ();
353 run (const char *what
, char *args
)
356 int pid
, wait_status
, retcode
;
359 char *errmsg_fmt
, *errmsg_arg
;
360 char *temp_base
= choose_temp_base ();
364 if (verbose
|| dry_run
)
365 fprintf (stderr
, "%s %s\n", what
, args
);
369 for (s
= args
; *s
; s
++)
373 argv
= alloca (sizeof (char *) * (i
+ 3));
379 while (*s
== ' ' && *s
!= 0)
383 in_quote
= (*s
== '\'' || *s
== '"');
384 sep
= (in_quote
) ? *s
++ : ' ';
386 while (*s
!= sep
&& *s
!= 0)
399 pid
= pexecute (argv
[0], (char * const *) argv
, program_name
, temp_base
,
400 &errmsg_fmt
, &errmsg_arg
, PEXECUTE_ONE
| PEXECUTE_SEARCH
);
404 int errno_val
= errno
;
406 fprintf (stderr
, "%s: ", program_name
);
407 fprintf (stderr
, errmsg_fmt
, errmsg_arg
);
408 fprintf (stderr
, ": %s\n", strerror (errno_val
));
413 pid
= pwait (pid
, &wait_status
, 0);
416 warn ("wait: %s", strerror (errno
));
419 else if (WIFSIGNALED (wait_status
))
421 warn (_("subprocess got fatal signal %d"), WTERMSIG (wait_status
));
424 else if (WIFEXITED (wait_status
))
426 if (WEXITSTATUS (wait_status
) != 0)
428 warn (_("%s exited with status %d"), what
, WEXITSTATUS (wait_status
));
439 mybasename (const char *name
)
441 const char *base
= name
;
445 if (*name
== '/' || *name
== '\\')
451 return (char *) base
;
455 strhash (const char *str
)
457 const unsigned char *s
;
464 s
= (const unsigned char *) str
;
465 while ((c
= *s
++) != '\0')
467 hash
+= c
+ (c
<< 17);
471 hash
+= len
+ (len
<< 17);
477 /**********************************************************************/
480 usage (FILE *file
, int status
)
482 fprintf (file
, _("Usage %s <option(s)> <object-file(s)>\n"), program_name
);
483 fprintf (file
, _(" Generic options:\n"));
484 fprintf (file
, _(" --quiet, -q Work quietly\n"));
485 fprintf (file
, _(" --verbose, -v Verbose\n"));
486 fprintf (file
, _(" --version Print dllwrap version\n"));
487 fprintf (file
, _(" --implib <outname> Synonym for --output-lib\n"));
488 fprintf (file
, _(" Options for %s:\n"), program_name
);
489 fprintf (file
, _(" --driver-name <driver> Defaults to \"gcc\"\n"));
490 fprintf (file
, _(" --driver-flags <flags> Override default ld flags\n"));
491 fprintf (file
, _(" --dlltool-name <dlltool> Defaults to \"dlltool\"\n"));
492 fprintf (file
, _(" --entry <entry> Specify alternate DLL entry point\n"));
493 fprintf (file
, _(" --image-base <base> Specify image base address\n"));
494 fprintf (file
, _(" --target <machine> i386-cygwin32 or i386-mingw32\n"));
495 fprintf (file
, _(" --dry-run Show what needs to be run\n"));
496 fprintf (file
, _(" --mno-cygwin Create Mingw DLL\n"));
497 fprintf (file
, _(" Options passed to DLLTOOL:\n"));
498 fprintf (file
, _(" --machine <machine>\n"));
499 fprintf (file
, _(" --output-exp <outname> Generate export file.\n"));
500 fprintf (file
, _(" --output-lib <outname> Generate input library.\n"));
501 fprintf (file
, _(" --add-indirect Add dll indirects to export file.\n"));
502 fprintf (file
, _(" --dllname <name> Name of input dll to put into output lib.\n"));
503 fprintf (file
, _(" --def <deffile> Name input .def file\n"));
504 fprintf (file
, _(" --output-def <deffile> Name output .def file\n"));
505 fprintf (file
, _(" --export-all-symbols Export all symbols to .def\n"));
506 fprintf (file
, _(" --no-export-all-symbols Only export .drectve symbols\n"));
507 fprintf (file
, _(" --exclude-symbols <list> Exclude <list> from .def\n"));
508 fprintf (file
, _(" --no-default-excludes Zap default exclude symbols\n"));
509 fprintf (file
, _(" --base-file <basefile> Read linker generated base file\n"));
510 fprintf (file
, _(" --no-idata4 Don't generate idata$4 section\n"));
511 fprintf (file
, _(" --no-idata5 Don't generate idata$5 section\n"));
512 fprintf (file
, _(" -U Add underscores to .lib\n"));
513 fprintf (file
, _(" -k Kill @<n> from exported names\n"));
514 fprintf (file
, _(" --add-stdcall-alias Add aliases without @<n>\n"));
515 fprintf (file
, _(" --as <name> Use <name> for assembler\n"));
516 fprintf (file
, _(" --nodelete Keep temp files.\n"));
517 fprintf (file
, _(" Rest are passed unmodified to the language driver\n"));
518 fprintf (file
, "\n\n");
522 #define OPTION_START 149
524 /* GENERIC options. */
525 #define OPTION_QUIET (OPTION_START + 1)
526 #define OPTION_VERBOSE (OPTION_QUIET + 1)
527 #define OPTION_VERSION (OPTION_VERBOSE + 1)
529 /* DLLWRAP options. */
530 #define OPTION_DRY_RUN (OPTION_VERSION + 1)
531 #define OPTION_DRIVER_NAME (OPTION_DRY_RUN + 1)
532 #define OPTION_DRIVER_FLAGS (OPTION_DRIVER_NAME + 1)
533 #define OPTION_DLLTOOL_NAME (OPTION_DRIVER_FLAGS + 1)
534 #define OPTION_ENTRY (OPTION_DLLTOOL_NAME + 1)
535 #define OPTION_IMAGE_BASE (OPTION_ENTRY + 1)
536 #define OPTION_TARGET (OPTION_IMAGE_BASE + 1)
537 #define OPTION_MNO_CYGWIN (OPTION_TARGET + 1)
539 /* DLLTOOL options. */
540 #define OPTION_NODELETE (OPTION_MNO_CYGWIN + 1)
541 #define OPTION_DLLNAME (OPTION_NODELETE + 1)
542 #define OPTION_NO_IDATA4 (OPTION_DLLNAME + 1)
543 #define OPTION_NO_IDATA5 (OPTION_NO_IDATA4 + 1)
544 #define OPTION_OUTPUT_EXP (OPTION_NO_IDATA5 + 1)
545 #define OPTION_OUTPUT_DEF (OPTION_OUTPUT_EXP + 1)
546 #define OPTION_EXPORT_ALL_SYMS (OPTION_OUTPUT_DEF + 1)
547 #define OPTION_NO_EXPORT_ALL_SYMS (OPTION_EXPORT_ALL_SYMS + 1)
548 #define OPTION_EXCLUDE_SYMS (OPTION_NO_EXPORT_ALL_SYMS + 1)
549 #define OPTION_NO_DEFAULT_EXCLUDES (OPTION_EXCLUDE_SYMS + 1)
550 #define OPTION_OUTPUT_LIB (OPTION_NO_DEFAULT_EXCLUDES + 1)
551 #define OPTION_DEF (OPTION_OUTPUT_LIB + 1)
552 #define OPTION_ADD_UNDERSCORE (OPTION_DEF + 1)
553 #define OPTION_KILLAT (OPTION_ADD_UNDERSCORE + 1)
554 #define OPTION_HELP (OPTION_KILLAT + 1)
555 #define OPTION_MACHINE (OPTION_HELP + 1)
556 #define OPTION_ADD_INDIRECT (OPTION_MACHINE + 1)
557 #define OPTION_BASE_FILE (OPTION_ADD_INDIRECT + 1)
558 #define OPTION_AS (OPTION_BASE_FILE + 1)
560 static const struct option long_options
[] =
562 /* generic options. */
563 {"quiet", no_argument
, NULL
, 'q'},
564 {"verbose", no_argument
, NULL
, 'v'},
565 {"version", no_argument
, NULL
, OPTION_VERSION
},
566 {"implib", required_argument
, NULL
, OPTION_OUTPUT_LIB
},
568 /* dllwrap options. */
569 {"dry-run", no_argument
, NULL
, OPTION_DRY_RUN
},
570 {"driver-name", required_argument
, NULL
, OPTION_DRIVER_NAME
},
571 {"driver-flags", required_argument
, NULL
, OPTION_DRIVER_FLAGS
},
572 {"dlltool-name", required_argument
, NULL
, OPTION_DLLTOOL_NAME
},
573 {"entry", required_argument
, NULL
, 'e'},
574 {"image-base", required_argument
, NULL
, OPTION_IMAGE_BASE
},
575 {"target", required_argument
, NULL
, OPTION_TARGET
},
577 /* dlltool options. */
578 {"no-delete", no_argument
, NULL
, 'n'},
579 {"dllname", required_argument
, NULL
, OPTION_DLLNAME
},
580 {"no-idata4", no_argument
, NULL
, OPTION_NO_IDATA4
},
581 {"no-idata5", no_argument
, NULL
, OPTION_NO_IDATA5
},
582 {"output-exp", required_argument
, NULL
, OPTION_OUTPUT_EXP
},
583 {"output-def", required_argument
, NULL
, OPTION_OUTPUT_DEF
},
584 {"export-all-symbols", no_argument
, NULL
, OPTION_EXPORT_ALL_SYMS
},
585 {"no-export-all-symbols", no_argument
, NULL
, OPTION_NO_EXPORT_ALL_SYMS
},
586 {"exclude-symbols", required_argument
, NULL
, OPTION_EXCLUDE_SYMS
},
587 {"no-default-excludes", no_argument
, NULL
, OPTION_NO_DEFAULT_EXCLUDES
},
588 {"output-lib", required_argument
, NULL
, OPTION_OUTPUT_LIB
},
589 {"def", required_argument
, NULL
, OPTION_DEF
},
590 {"add-underscore", no_argument
, NULL
, 'U'},
591 {"killat", no_argument
, NULL
, 'k'},
592 {"add-stdcall-alias", no_argument
, NULL
, 'A'},
593 {"help", no_argument
, NULL
, 'h'},
594 {"machine", required_argument
, NULL
, OPTION_MACHINE
},
595 {"add-indirect", no_argument
, NULL
, OPTION_ADD_INDIRECT
},
596 {"base-file", required_argument
, NULL
, OPTION_BASE_FILE
},
597 {"as", required_argument
, NULL
, OPTION_AS
},
601 int main (int, char **);
604 main (int argc
, char **argv
)
609 char **saved_argv
= 0;
614 int *dlltool_arg_indices
;
615 int *driver_arg_indices
;
617 char *driver_flags
= 0;
618 char *output_lib_file_name
= 0;
620 dyn_string_t dlltool_cmdline
;
621 dyn_string_t driver_cmdline
;
623 int def_file_seen
= 0;
625 char *image_base_str
= 0;
627 program_name
= argv
[0];
629 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
630 setlocale (LC_MESSAGES
, "");
632 #if defined (HAVE_SETLOCALE)
633 setlocale (LC_CTYPE
, "");
635 bindtextdomain (PACKAGE
, LOCALEDIR
);
636 textdomain (PACKAGE
);
638 saved_argv
= (char **) xmalloc (argc
* sizeof (char*));
639 dlltool_arg_indices
= (int *) xmalloc (argc
* sizeof (int));
640 driver_arg_indices
= (int *) xmalloc (argc
* sizeof (int));
641 for (i
= 0; i
< argc
; ++i
)
643 size_t len
= strlen (argv
[i
]);
644 char *arg
= (char *) xmalloc (len
+ 1);
645 strcpy (arg
, argv
[i
]);
648 dlltool_arg_indices
[i
] = 0;
649 driver_arg_indices
[i
] = 1;
653 /* We recognize dllwrap and dlltool options, and everything else is
654 passed onto the language driver (eg., to GCC). We collect options
655 to dlltool and driver in dlltool_args and driver_args. */
658 while ((c
= getopt_long_only (argc
, argv
, "nkAqve:Uho:l:L:I:",
659 long_options
, (int *) 0)) != EOF
)
663 int single_word_option_value_pair
;
667 single_word_option_value_pair
= 0;
671 /* We recognize this option, so it has to be either dllwrap or
672 dlltool option. Do not pass to driver unless it's one of the
673 generic options that are passed to all the tools (such as -v)
674 which are dealt with later. */
678 /* deal with generic and dllwrap options first. */
691 print_version (program_name
);
694 entry_point
= optarg
;
696 case OPTION_IMAGE_BASE
:
697 image_base_str
= optarg
;
700 def_file_name
= optarg
;
709 dll_file_name
= optarg
;
722 case OPTION_DRIVER_NAME
:
723 driver_name
= optarg
;
725 case OPTION_DRIVER_FLAGS
:
726 driver_flags
= optarg
;
728 case OPTION_DLLTOOL_NAME
:
729 dlltool_name
= optarg
;
734 case OPTION_MNO_CYGWIN
:
735 target
= "i386-mingw32";
737 case OPTION_BASE_FILE
:
738 base_file_name
= optarg
;
739 delete_base_file
= 0;
741 case OPTION_OUTPUT_EXP
:
742 exp_file_name
= optarg
;
745 case OPTION_EXPORT_ALL_SYMS
:
748 case OPTION_OUTPUT_LIB
:
749 output_lib_file_name
= optarg
;
758 /* Handle passing through --option=value case. */
760 && saved_argv
[optind
-1][0] == '-'
761 && saved_argv
[optind
-1][1] == '-'
762 && strchr (saved_argv
[optind
-1], '='))
763 single_word_option_value_pair
= 1;
767 dlltool_arg_indices
[optind
-1] = 1;
768 if (optarg
&& ! single_word_option_value_pair
)
770 dlltool_arg_indices
[optind
-2] = 1;
776 driver_arg_indices
[optind
-1] = 0;
777 if (optarg
&& ! single_word_option_value_pair
)
779 driver_arg_indices
[optind
-2] = 0;
785 if (! dll_name
&& ! dll_file_name
)
787 warn (_("Must provide at least one of -o or --dllname options"));
792 dll_name
= xstrdup (mybasename (dll_file_name
));
794 else if (! dll_file_name
)
796 dll_file_name
= xstrdup (dll_name
);
799 /* Deduce driver-name and dlltool-name from our own. */
800 if (driver_name
== NULL
)
801 driver_name
= deduce_name ("gcc");
803 if (dlltool_name
== NULL
)
804 dlltool_name
= deduce_name ("dlltool");
808 char *fileprefix
= choose_temp_base ();
809 def_file_name
= (char *) xmalloc (strlen (fileprefix
) + 5);
810 sprintf (def_file_name
, "%s.def",
811 (dontdeltemps
) ? mybasename (fileprefix
) : fileprefix
);
815 warn (_("no export definition file provided.\n\
816 Creating one, but that may not be what you want"));
819 /* set the target platform. */
820 if (strstr (target
, "cygwin"))
821 which_target
= CYGWIN_TARGET
;
822 else if (strstr (target
, "mingw"))
823 which_target
= MINGW_TARGET
;
825 which_target
= UNKNOWN_TARGET
;
827 /* re-create the command lines as a string, taking care to quote stuff. */
828 dlltool_cmdline
= dyn_string_new (cmdline_len
);
831 dyn_string_append_cstr (dlltool_cmdline
, " -v");
833 dyn_string_append_cstr (dlltool_cmdline
, " --dllname ");
834 dyn_string_append_cstr (dlltool_cmdline
, dll_name
);
836 for (i
= 1; i
< argc
; ++i
)
838 if (dlltool_arg_indices
[i
])
840 char *arg
= saved_argv
[i
];
841 int quote
= (strchr (arg
, ' ') || strchr (arg
, '\t'));
842 dyn_string_append_cstr (dlltool_cmdline
,
843 (quote
) ? " \"" : " ");
844 dyn_string_append_cstr (dlltool_cmdline
, arg
);
845 dyn_string_append_cstr (dlltool_cmdline
,
846 (quote
) ? "\"" : "");
850 driver_cmdline
= dyn_string_new (cmdline_len
);
851 if (! driver_flags
|| strlen (driver_flags
) == 0)
853 switch (which_target
)
856 driver_flags
= cygwin_driver_flags
;
860 driver_flags
= mingw32_driver_flags
;
864 driver_flags
= generic_driver_flags
;
868 dyn_string_append_cstr (driver_cmdline
, driver_flags
);
869 dyn_string_append_cstr (driver_cmdline
, " -o ");
870 dyn_string_append_cstr (driver_cmdline
, dll_file_name
);
872 if (! entry_point
|| strlen (entry_point
) == 0)
874 switch (which_target
)
877 entry_point
= "__cygwin_dll_entry@12";
881 entry_point
= "_DllMainCRTStartup@12";
885 entry_point
= "_DllMain@12";
889 dyn_string_append_cstr (driver_cmdline
, " -Wl,-e,");
890 dyn_string_append_cstr (driver_cmdline
, entry_point
);
891 dyn_string_append_cstr (dlltool_cmdline
, " --exclude-symbol=");
892 dyn_string_append_cstr (dlltool_cmdline
,
893 (entry_point
[0] == '_') ? entry_point
+1 : entry_point
);
895 if (! image_base_str
|| strlen (image_base_str
) == 0)
897 char *tmpbuf
= (char *) xmalloc (sizeof ("0x12345678") + 1);
898 unsigned long hash
= strhash (dll_file_name
);
899 sprintf (tmpbuf
, "0x%.8lX", 0x60000000|((hash
<<16)&0xFFC0000));
900 image_base_str
= tmpbuf
;
903 dyn_string_append_cstr (driver_cmdline
, " -Wl,--image-base,");
904 dyn_string_append_cstr (driver_cmdline
, image_base_str
);
908 dyn_string_append_cstr (driver_cmdline
, " -v");
911 for (i
= 1; i
< argc
; ++i
)
913 if (driver_arg_indices
[i
])
915 char *arg
= saved_argv
[i
];
916 int quote
= (strchr (arg
, ' ') || strchr (arg
, '\t'));
917 dyn_string_append_cstr (driver_cmdline
,
918 (quote
) ? " \"" : " ");
919 dyn_string_append_cstr (driver_cmdline
, arg
);
920 dyn_string_append_cstr (driver_cmdline
,
921 (quote
) ? "\"" : "");
926 * Step pre-1. If no --def <EXPORT_DEF> is specified, then create it
927 * and then pass it on.
933 dyn_string_t step_pre1
;
935 step_pre1
= dyn_string_new (1024);
937 dyn_string_append_cstr (step_pre1
, dlltool_cmdline
->s
);
940 dyn_string_append_cstr (step_pre1
, " --export-all --exclude-symbol=");
941 dyn_string_append_cstr (step_pre1
,
942 "_cygwin_dll_entry@12,DllMainCRTStartup@12,DllMain@12,DllEntryPoint@12");
944 dyn_string_append_cstr (step_pre1
, " --output-def ");
945 dyn_string_append_cstr (step_pre1
, def_file_name
);
947 for (i
= 1; i
< argc
; ++i
)
949 if (driver_arg_indices
[i
])
951 char *arg
= saved_argv
[i
];
952 size_t len
= strlen (arg
);
953 if (len
>= 2 && arg
[len
-2] == '.'
954 && (arg
[len
-1] == 'o' || arg
[len
-1] == 'a'))
956 int quote
= (strchr (arg
, ' ') || strchr (arg
, '\t'));
957 dyn_string_append_cstr (step_pre1
,
958 (quote
) ? " \"" : " ");
959 dyn_string_append_cstr (step_pre1
, arg
);
960 dyn_string_append_cstr (step_pre1
,
961 (quote
) ? "\"" : "");
966 if (run (dlltool_name
, step_pre1
->s
))
967 cleanup_and_exit (1);
969 dyn_string_delete (step_pre1
);
972 dyn_string_append_cstr (dlltool_cmdline
, " --def ");
973 dyn_string_append_cstr (dlltool_cmdline
, def_file_name
);
977 fprintf (stderr
, _("DLLTOOL name : %s\n"), dlltool_name
);
978 fprintf (stderr
, _("DLLTOOL options : %s\n"), dlltool_cmdline
->s
);
979 fprintf (stderr
, _("DRIVER name : %s\n"), driver_name
);
980 fprintf (stderr
, _("DRIVER options : %s\n"), driver_cmdline
->s
);
984 * Step 1. Call GCC/LD to create base relocation file. If using GCC, the
985 * driver command line will look like the following:
987 * % gcc -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
989 * If the user does not specify a base name, create temporary one that
990 * is deleted at exit.
994 if (! base_file_name
)
996 char *fileprefix
= choose_temp_base ();
997 base_file_name
= (char *) xmalloc (strlen (fileprefix
) + 6);
998 sprintf (base_file_name
, "%s.base",
999 (dontdeltemps
) ? mybasename (fileprefix
) : fileprefix
);
1000 delete_base_file
= 1;
1007 dyn_string_t step1
= dyn_string_new (driver_cmdline
->length
1008 + strlen (base_file_name
)
1010 dyn_string_append_cstr (step1
, "-Wl,--base-file,");
1011 quote
= (strchr (base_file_name
, ' ')
1012 || strchr (base_file_name
, '\t'));
1013 dyn_string_append_cstr (step1
,
1014 (quote
) ? "\"" : "");
1015 dyn_string_append_cstr (step1
, base_file_name
);
1016 dyn_string_append_cstr (step1
,
1017 (quote
) ? "\"" : "");
1018 if (driver_cmdline
->length
)
1020 dyn_string_append_cstr (step1
, " ");
1021 dyn_string_append_cstr (step1
, driver_cmdline
->s
);
1024 if (run (driver_name
, step1
->s
))
1025 cleanup_and_exit (1);
1027 dyn_string_delete (step1
);
1033 * Step 2. generate the exp file by running dlltool.
1034 * dlltool command line will look like the following:
1036 * % dlltool -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
1038 * If the user does not specify a base name, create temporary one that
1039 * is deleted at exit.
1043 if (! exp_file_name
)
1045 char *p
= strrchr (dll_name
, '.');
1046 size_t prefix_len
= (p
) ? p
- dll_name
: strlen (dll_name
);
1047 exp_file_name
= (char *) xmalloc (prefix_len
+ 4 + 1);
1048 strncpy (exp_file_name
, dll_name
, prefix_len
);
1049 exp_file_name
[prefix_len
] = '\0';
1050 strcat (exp_file_name
, ".exp");
1051 delete_exp_file
= 1;
1056 dyn_string_t step2
= dyn_string_new (dlltool_cmdline
->length
1057 + strlen (base_file_name
)
1058 + strlen (exp_file_name
)
1061 dyn_string_append_cstr (step2
, "--base-file ");
1062 quote
= (strchr (base_file_name
, ' ')
1063 || strchr (base_file_name
, '\t'));
1064 dyn_string_append_cstr (step2
,
1065 (quote
) ? "\"" : "");
1066 dyn_string_append_cstr (step2
, base_file_name
);
1067 dyn_string_append_cstr (step2
,
1068 (quote
) ? "\" " : " ");
1070 dyn_string_append_cstr (step2
, "--output-exp ");
1071 quote
= (strchr (exp_file_name
, ' ')
1072 || strchr (exp_file_name
, '\t'));
1073 dyn_string_append_cstr (step2
,
1074 (quote
) ? "\"" : "");
1075 dyn_string_append_cstr (step2
, exp_file_name
);
1076 dyn_string_append_cstr (step2
,
1077 (quote
) ? "\"" : "");
1079 if (dlltool_cmdline
->length
)
1081 dyn_string_append_cstr (step2
, " ");
1082 dyn_string_append_cstr (step2
, dlltool_cmdline
->s
);
1085 if (run (dlltool_name
, step2
->s
))
1086 cleanup_and_exit (1);
1088 dyn_string_delete (step2
);
1092 * Step 3. Call GCC/LD to again, adding the exp file this time.
1093 * driver command line will look like the following:
1095 * % gcc -Wl,--dll --Wl,--base-file,foo.base foo.exp [rest ...]
1101 dyn_string_t step3
= dyn_string_new (driver_cmdline
->length
1102 + strlen (exp_file_name
)
1103 + strlen (base_file_name
)
1105 dyn_string_append_cstr (step3
, "-Wl,--base-file,");
1106 quote
= (strchr (base_file_name
, ' ')
1107 || strchr (base_file_name
, '\t'));
1108 dyn_string_append_cstr (step3
,
1109 (quote
) ? "\"" : "");
1110 dyn_string_append_cstr (step3
, base_file_name
);
1111 dyn_string_append_cstr (step3
,
1112 (quote
) ? "\" " : " ");
1114 quote
= (strchr (exp_file_name
, ' ')
1115 || strchr (exp_file_name
, '\t'));
1116 dyn_string_append_cstr (step3
,
1117 (quote
) ? "\"" : "");
1118 dyn_string_append_cstr (step3
, exp_file_name
);
1119 dyn_string_append_cstr (step3
,
1120 (quote
) ? "\"" : "");
1122 if (driver_cmdline
->length
)
1124 dyn_string_append_cstr (step3
, " ");
1125 dyn_string_append_cstr (step3
, driver_cmdline
->s
);
1128 if (run (driver_name
, step3
->s
))
1129 cleanup_and_exit (1);
1131 dyn_string_delete (step3
);
1136 * Step 4. Run DLLTOOL again using the same command line.
1141 dyn_string_t step4
= dyn_string_new (dlltool_cmdline
->length
1142 + strlen (base_file_name
)
1143 + strlen (exp_file_name
)
1146 dyn_string_append_cstr (step4
, "--base-file ");
1147 quote
= (strchr (base_file_name
, ' ')
1148 || strchr (base_file_name
, '\t'));
1149 dyn_string_append_cstr (step4
,
1150 (quote
) ? "\"" : "");
1151 dyn_string_append_cstr (step4
, base_file_name
);
1152 dyn_string_append_cstr (step4
,
1153 (quote
) ? "\" " : " ");
1155 dyn_string_append_cstr (step4
, "--output-exp ");
1156 quote
= (strchr (exp_file_name
, ' ')
1157 || strchr (exp_file_name
, '\t'));
1158 dyn_string_append_cstr (step4
,
1159 (quote
) ? "\"" : "");
1160 dyn_string_append_cstr (step4
, exp_file_name
);
1161 dyn_string_append_cstr (step4
,
1162 (quote
) ? "\"" : "");
1164 if (dlltool_cmdline
->length
)
1166 dyn_string_append_cstr (step4
, " ");
1167 dyn_string_append_cstr (step4
, dlltool_cmdline
->s
);
1170 if (output_lib_file_name
)
1172 dyn_string_append_cstr (step4
, " --output-lib ");
1173 dyn_string_append_cstr (step4
, output_lib_file_name
);
1176 if (run (dlltool_name
, step4
->s
))
1177 cleanup_and_exit (1);
1179 dyn_string_delete (step4
);
1184 * Step 5. Link it all together and be done with it.
1185 * driver command line will look like the following:
1187 * % gcc -Wl,--dll foo.exp [rest ...]
1194 dyn_string_t step5
= dyn_string_new (driver_cmdline
->length
1195 + strlen (exp_file_name
)
1197 quote
= (strchr (exp_file_name
, ' ')
1198 || strchr (exp_file_name
, '\t'));
1199 dyn_string_append_cstr (step5
,
1200 (quote
) ? "\"" : "");
1201 dyn_string_append_cstr (step5
, exp_file_name
);
1202 dyn_string_append_cstr (step5
,
1203 (quote
) ? "\"" : "");
1205 if (driver_cmdline
->length
)
1207 dyn_string_append_cstr (step5
, " ");
1208 dyn_string_append_cstr (step5
, driver_cmdline
->s
);
1211 if (run (driver_name
, step5
->s
))
1212 cleanup_and_exit (1);
1214 dyn_string_delete (step5
);
1217 cleanup_and_exit (0);