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
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
PARAMS ((const char *, char *));
118 static char *mybasename
PARAMS ((const char *));
119 static int strhash
PARAMS ((const char *));
120 static void usage
PARAMS ((FILE *, int));
121 static void display
PARAMS ((const char *, va_list));
122 static void inform
PARAMS ((const char *, ...));
123 static void warn
PARAMS ((const char *, ...));
124 static char *look_for_prog
PARAMS ((const char *, const char *, int));
125 static char *deduce_name
PARAMS ((const char *));
126 static void delete_temp_files
PARAMS ((void));
127 static void cleanup_and_exit
PARAMS ((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 (message
, args
)
141 const char * message
;
144 if (program_name
!= NULL
)
145 fprintf (stderr
, "%s: ", program_name
);
147 vfprintf (stderr
, message
, args
);
148 fputc ('\n', stderr
);
153 inform
VPARAMS ((const char *message
, ...))
155 VA_OPEN (args
, message
);
156 VA_FIXEDARG (args
, const char *, message
);
161 display (message
, args
);
167 warn
VPARAMS ((const char *format
, ...))
169 VA_OPEN (args
, format
);
170 VA_FIXEDARG (args
, const char *, format
);
172 display (format
, args
);
177 /* Look for the program formed by concatenating PROG_NAME and the
178 string running from PREFIX to END_PREFIX. If the concatenated
179 string contains a '/', try appending EXECUTABLE_SUFFIX if it is
183 look_for_prog (prog_name
, prefix
, end_prefix
)
184 const char *prog_name
;
191 cmd
= xmalloc (strlen (prefix
)
193 #ifdef HAVE_EXECUTABLE_SUFFIX
194 + strlen (EXECUTABLE_SUFFIX
)
197 strcpy (cmd
, prefix
);
199 sprintf (cmd
+ end_prefix
, "%s", prog_name
);
201 if (strchr (cmd
, '/') != NULL
)
205 found
= (stat (cmd
, &s
) == 0
206 #ifdef HAVE_EXECUTABLE_SUFFIX
207 || stat (strcat (cmd
, EXECUTABLE_SUFFIX
), &s
) == 0
213 /* xgettext:c-format */
214 inform (_("Tried file: %s"), cmd
);
220 /* xgettext:c-format */
221 inform (_("Using file: %s"), cmd
);
226 /* Deduce the name of the program we are want to invoke.
227 PROG_NAME is the basic name of the program we want to run,
228 eg "as" or "ld". The catch is that we might want actually
229 run "i386-pe-as" or "ppc-pe-ld".
231 If argv[0] contains the full path, then try to find the program
232 in the same place, with and then without a target-like prefix.
234 Given, argv[0] = /usr/local/bin/i586-cygwin32-dlltool,
235 deduce_name("as") uses the following search order:
237 /usr/local/bin/i586-cygwin32-as
241 If there's an EXECUTABLE_SUFFIX, it'll use that as well; for each
242 name, it'll try without and then with EXECUTABLE_SUFFIX.
244 Given, argv[0] = i586-cygwin32-dlltool, it will not even try "as"
245 as the fallback, but rather return i586-cygwin32-as.
247 Oh, and given, argv[0] = dlltool, it'll return "as".
249 Returns a dynamically allocated string. */
252 deduce_name (prog_name
)
253 const char *prog_name
;
256 char *dash
, *slash
, *cp
;
260 for (cp
= program_name
; *cp
!= '\0'; ++cp
)
265 #if defined(__DJGPP__) || defined (__CYGWIN__) || defined(__WIN32__)
266 *cp
== ':' || *cp
== '\\' ||
279 /* First, try looking for a prefixed PROG_NAME in the
280 PROGRAM_NAME directory, with the same prefix as PROGRAM_NAME. */
281 cmd
= look_for_prog (prog_name
, program_name
, dash
- program_name
+ 1);
284 if (slash
!= NULL
&& cmd
== NULL
)
286 /* Next, try looking for a PROG_NAME in the same directory as
287 that of this program. */
288 cmd
= look_for_prog (prog_name
, program_name
, slash
- program_name
+ 1);
293 /* Just return PROG_NAME as is. */
294 cmd
= xstrdup (prog_name
);
303 if (delete_base_file
&& base_file_name
)
308 warn (_("Keeping temporary base file %s"), base_file_name
);
310 warn (_("Deleting temporary base file %s"), base_file_name
);
314 unlink (base_file_name
);
315 free (base_file_name
);
319 if (delete_exp_file
&& exp_file_name
)
324 warn (_("Keeping temporary exp file %s"), exp_file_name
);
326 warn (_("Deleting temporary exp file %s"), exp_file_name
);
330 unlink (exp_file_name
);
331 free (exp_file_name
);
334 if (delete_def_file
&& def_file_name
)
339 warn (_("Keeping temporary def file %s"), def_file_name
);
341 warn (_("Deleting temporary def file %s"), def_file_name
);
345 unlink (def_file_name
);
346 free (def_file_name
);
352 cleanup_and_exit (status
)
355 delete_temp_files ();
365 int pid
, wait_status
, retcode
;
368 char *errmsg_fmt
, *errmsg_arg
;
369 char *temp_base
= choose_temp_base ();
373 if (verbose
|| dry_run
)
374 fprintf (stderr
, "%s %s\n", what
, args
);
378 for (s
= args
; *s
; s
++)
382 argv
= alloca (sizeof (char *) * (i
+ 3));
388 while (*s
== ' ' && *s
!= 0)
392 in_quote
= (*s
== '\'' || *s
== '"');
393 sep
= (in_quote
) ? *s
++ : ' ';
395 while (*s
!= sep
&& *s
!= 0)
408 pid
= pexecute (argv
[0], (char * const *) argv
, program_name
, temp_base
,
409 &errmsg_fmt
, &errmsg_arg
, PEXECUTE_ONE
| PEXECUTE_SEARCH
);
413 int errno_val
= errno
;
415 fprintf (stderr
, "%s: ", program_name
);
416 fprintf (stderr
, errmsg_fmt
, errmsg_arg
);
417 fprintf (stderr
, ": %s\n", strerror (errno_val
));
422 pid
= pwait (pid
, &wait_status
, 0);
425 warn ("wait: %s", strerror (errno
));
428 else if (WIFSIGNALED (wait_status
))
430 warn (_("subprocess got fatal signal %d"), WTERMSIG (wait_status
));
433 else if (WIFEXITED (wait_status
))
435 if (WEXITSTATUS (wait_status
) != 0)
437 warn (_("%s exited with status %d"), what
, WEXITSTATUS (wait_status
));
451 const char *base
= name
;
455 if (*name
== '/' || *name
== '\\')
461 return (char *) base
;
468 const unsigned char *s
;
475 s
= (const unsigned char *) str
;
476 while ((c
= *s
++) != '\0')
478 hash
+= c
+ (c
<< 17);
482 hash
+= len
+ (len
<< 17);
488 /**********************************************************************/
495 fprintf (file
, _("Usage %s <option(s)> <object-file(s)>\n"), program_name
);
496 fprintf (file
, _(" Generic options:\n"));
497 fprintf (file
, _(" --quiet, -q Work quietly\n"));
498 fprintf (file
, _(" --verbose, -v Verbose\n"));
499 fprintf (file
, _(" --version Print dllwrap version\n"));
500 fprintf (file
, _(" --implib <outname> Synonym for --output-lib\n"));
501 fprintf (file
, _(" Options for %s:\n"), program_name
);
502 fprintf (file
, _(" --driver-name <driver> Defaults to \"gcc\"\n"));
503 fprintf (file
, _(" --driver-flags <flags> Override default ld flags\n"));
504 fprintf (file
, _(" --dlltool-name <dlltool> Defaults to \"dlltool\"\n"));
505 fprintf (file
, _(" --entry <entry> Specify alternate DLL entry point\n"));
506 fprintf (file
, _(" --image-base <base> Specify image base address\n"));
507 fprintf (file
, _(" --target <machine> i386-cygwin32 or i386-mingw32\n"));
508 fprintf (file
, _(" --dry-run Show what needs to be run\n"));
509 fprintf (file
, _(" --mno-cygwin Create Mingw DLL\n"));
510 fprintf (file
, _(" Options passed to DLLTOOL:\n"));
511 fprintf (file
, _(" --machine <machine>\n"));
512 fprintf (file
, _(" --output-exp <outname> Generate export file.\n"));
513 fprintf (file
, _(" --output-lib <outname> Generate input library.\n"));
514 fprintf (file
, _(" --add-indirect Add dll indirects to export file.\n"));
515 fprintf (file
, _(" --dllname <name> Name of input dll to put into output lib.\n"));
516 fprintf (file
, _(" --def <deffile> Name input .def file\n"));
517 fprintf (file
, _(" --output-def <deffile> Name output .def file\n"));
518 fprintf (file
, _(" --export-all-symbols Export all symbols to .def\n"));
519 fprintf (file
, _(" --no-export-all-symbols Only export .drectve symbols\n"));
520 fprintf (file
, _(" --exclude-symbols <list> Exclude <list> from .def\n"));
521 fprintf (file
, _(" --no-default-excludes Zap default exclude symbols\n"));
522 fprintf (file
, _(" --base-file <basefile> Read linker generated base file\n"));
523 fprintf (file
, _(" --no-idata4 Don't generate idata$4 section\n"));
524 fprintf (file
, _(" --no-idata5 Don't generate idata$5 section\n"));
525 fprintf (file
, _(" -U Add underscores to .lib\n"));
526 fprintf (file
, _(" -k Kill @<n> from exported names\n"));
527 fprintf (file
, _(" --add-stdcall-alias Add aliases without @<n>\n"));
528 fprintf (file
, _(" --as <name> Use <name> for assembler\n"));
529 fprintf (file
, _(" --nodelete Keep temp files.\n"));
530 fprintf (file
, _(" Rest are passed unmodified to the language driver\n"));
531 fprintf (file
, "\n\n");
535 #define OPTION_START 149
537 /* GENERIC options. */
538 #define OPTION_QUIET (OPTION_START + 1)
539 #define OPTION_VERBOSE (OPTION_QUIET + 1)
540 #define OPTION_VERSION (OPTION_VERBOSE + 1)
542 /* DLLWRAP options. */
543 #define OPTION_DRY_RUN (OPTION_VERSION + 1)
544 #define OPTION_DRIVER_NAME (OPTION_DRY_RUN + 1)
545 #define OPTION_DRIVER_FLAGS (OPTION_DRIVER_NAME + 1)
546 #define OPTION_DLLTOOL_NAME (OPTION_DRIVER_FLAGS + 1)
547 #define OPTION_ENTRY (OPTION_DLLTOOL_NAME + 1)
548 #define OPTION_IMAGE_BASE (OPTION_ENTRY + 1)
549 #define OPTION_TARGET (OPTION_IMAGE_BASE + 1)
550 #define OPTION_MNO_CYGWIN (OPTION_TARGET + 1)
552 /* DLLTOOL options. */
553 #define OPTION_NODELETE (OPTION_MNO_CYGWIN + 1)
554 #define OPTION_DLLNAME (OPTION_NODELETE + 1)
555 #define OPTION_NO_IDATA4 (OPTION_DLLNAME + 1)
556 #define OPTION_NO_IDATA5 (OPTION_NO_IDATA4 + 1)
557 #define OPTION_OUTPUT_EXP (OPTION_NO_IDATA5 + 1)
558 #define OPTION_OUTPUT_DEF (OPTION_OUTPUT_EXP + 1)
559 #define OPTION_EXPORT_ALL_SYMS (OPTION_OUTPUT_DEF + 1)
560 #define OPTION_NO_EXPORT_ALL_SYMS (OPTION_EXPORT_ALL_SYMS + 1)
561 #define OPTION_EXCLUDE_SYMS (OPTION_NO_EXPORT_ALL_SYMS + 1)
562 #define OPTION_NO_DEFAULT_EXCLUDES (OPTION_EXCLUDE_SYMS + 1)
563 #define OPTION_OUTPUT_LIB (OPTION_NO_DEFAULT_EXCLUDES + 1)
564 #define OPTION_DEF (OPTION_OUTPUT_LIB + 1)
565 #define OPTION_ADD_UNDERSCORE (OPTION_DEF + 1)
566 #define OPTION_KILLAT (OPTION_ADD_UNDERSCORE + 1)
567 #define OPTION_HELP (OPTION_KILLAT + 1)
568 #define OPTION_MACHINE (OPTION_HELP + 1)
569 #define OPTION_ADD_INDIRECT (OPTION_MACHINE + 1)
570 #define OPTION_BASE_FILE (OPTION_ADD_INDIRECT + 1)
571 #define OPTION_AS (OPTION_BASE_FILE + 1)
573 static const struct option long_options
[] =
575 /* generic options. */
576 {"quiet", no_argument
, NULL
, 'q'},
577 {"verbose", no_argument
, NULL
, 'v'},
578 {"version", no_argument
, NULL
, OPTION_VERSION
},
579 {"implib", required_argument
, NULL
, OPTION_OUTPUT_LIB
},
581 /* dllwrap options. */
582 {"dry-run", no_argument
, NULL
, OPTION_DRY_RUN
},
583 {"driver-name", required_argument
, NULL
, OPTION_DRIVER_NAME
},
584 {"driver-flags", required_argument
, NULL
, OPTION_DRIVER_FLAGS
},
585 {"dlltool-name", required_argument
, NULL
, OPTION_DLLTOOL_NAME
},
586 {"entry", required_argument
, NULL
, 'e'},
587 {"image-base", required_argument
, NULL
, OPTION_IMAGE_BASE
},
588 {"target", required_argument
, NULL
, OPTION_TARGET
},
590 /* dlltool options. */
591 {"no-delete", no_argument
, NULL
, 'n'},
592 {"dllname", required_argument
, NULL
, OPTION_DLLNAME
},
593 {"no-idata4", no_argument
, NULL
, OPTION_NO_IDATA4
},
594 {"no-idata5", no_argument
, NULL
, OPTION_NO_IDATA5
},
595 {"output-exp", required_argument
, NULL
, OPTION_OUTPUT_EXP
},
596 {"output-def", required_argument
, NULL
, OPTION_OUTPUT_DEF
},
597 {"export-all-symbols", no_argument
, NULL
, OPTION_EXPORT_ALL_SYMS
},
598 {"no-export-all-symbols", no_argument
, NULL
, OPTION_NO_EXPORT_ALL_SYMS
},
599 {"exclude-symbols", required_argument
, NULL
, OPTION_EXCLUDE_SYMS
},
600 {"no-default-excludes", no_argument
, NULL
, OPTION_NO_DEFAULT_EXCLUDES
},
601 {"output-lib", required_argument
, NULL
, OPTION_OUTPUT_LIB
},
602 {"def", required_argument
, NULL
, OPTION_DEF
},
603 {"add-underscore", no_argument
, NULL
, 'U'},
604 {"killat", no_argument
, NULL
, 'k'},
605 {"add-stdcall-alias", no_argument
, NULL
, 'A'},
606 {"help", no_argument
, NULL
, 'h'},
607 {"machine", required_argument
, NULL
, OPTION_MACHINE
},
608 {"add-indirect", no_argument
, NULL
, OPTION_ADD_INDIRECT
},
609 {"base-file", required_argument
, NULL
, OPTION_BASE_FILE
},
610 {"as", required_argument
, NULL
, OPTION_AS
},
614 int main
PARAMS ((int, char **));
624 char **saved_argv
= 0;
629 int *dlltool_arg_indices
;
630 int *driver_arg_indices
;
632 char *driver_flags
= 0;
633 char *output_lib_file_name
= 0;
635 dyn_string_t dlltool_cmdline
;
636 dyn_string_t driver_cmdline
;
638 int def_file_seen
= 0;
640 char *image_base_str
= 0;
642 program_name
= argv
[0];
644 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
645 setlocale (LC_MESSAGES
, "");
647 #if defined (HAVE_SETLOCALE)
648 setlocale (LC_CTYPE
, "");
650 bindtextdomain (PACKAGE
, LOCALEDIR
);
651 textdomain (PACKAGE
);
653 saved_argv
= (char **) xmalloc (argc
* sizeof (char*));
654 dlltool_arg_indices
= (int *) xmalloc (argc
* sizeof (int));
655 driver_arg_indices
= (int *) xmalloc (argc
* sizeof (int));
656 for (i
= 0; i
< argc
; ++i
)
658 size_t len
= strlen (argv
[i
]);
659 char *arg
= (char *) xmalloc (len
+ 1);
660 strcpy (arg
, argv
[i
]);
663 dlltool_arg_indices
[i
] = 0;
664 driver_arg_indices
[i
] = 1;
668 /* We recognize dllwrap and dlltool options, and everything else is
669 passed onto the language driver (eg., to GCC). We collect options
670 to dlltool and driver in dlltool_args and driver_args. */
673 while ((c
= getopt_long_only (argc
, argv
, "nkAqve:Uho:l:L:I:",
674 long_options
, (int *) 0)) != EOF
)
678 int single_word_option_value_pair
;
682 single_word_option_value_pair
= 0;
686 /* We recognize this option, so it has to be either dllwrap or
687 dlltool option. Do not pass to driver unless it's one of the
688 generic options that are passed to all the tools (such as -v)
689 which are dealt with later. */
693 /* deal with generic and dllwrap options first. */
706 print_version (program_name
);
709 entry_point
= optarg
;
711 case OPTION_IMAGE_BASE
:
712 image_base_str
= optarg
;
715 def_file_name
= optarg
;
724 dll_file_name
= optarg
;
737 case OPTION_DRIVER_NAME
:
738 driver_name
= optarg
;
740 case OPTION_DRIVER_FLAGS
:
741 driver_flags
= optarg
;
743 case OPTION_DLLTOOL_NAME
:
744 dlltool_name
= optarg
;
749 case OPTION_MNO_CYGWIN
:
750 target
= "i386-mingw32";
752 case OPTION_BASE_FILE
:
753 base_file_name
= optarg
;
754 delete_base_file
= 0;
756 case OPTION_OUTPUT_EXP
:
757 exp_file_name
= optarg
;
760 case OPTION_EXPORT_ALL_SYMS
:
763 case OPTION_OUTPUT_LIB
:
764 output_lib_file_name
= optarg
;
773 /* Handle passing through --option=value case. */
775 && saved_argv
[optind
-1][0] == '-'
776 && saved_argv
[optind
-1][1] == '-'
777 && strchr (saved_argv
[optind
-1], '='))
778 single_word_option_value_pair
= 1;
782 dlltool_arg_indices
[optind
-1] = 1;
783 if (optarg
&& ! single_word_option_value_pair
)
785 dlltool_arg_indices
[optind
-2] = 1;
791 driver_arg_indices
[optind
-1] = 0;
792 if (optarg
&& ! single_word_option_value_pair
)
794 driver_arg_indices
[optind
-2] = 0;
800 if (! dll_name
&& ! dll_file_name
)
802 warn (_("Must provide at least one of -o or --dllname options"));
807 dll_name
= xstrdup (mybasename (dll_file_name
));
809 else if (! dll_file_name
)
811 dll_file_name
= xstrdup (dll_name
);
814 /* Deduce driver-name and dlltool-name from our own. */
815 if (driver_name
== NULL
)
816 driver_name
= deduce_name ("gcc");
818 if (dlltool_name
== NULL
)
819 dlltool_name
= deduce_name ("dlltool");
823 char *fileprefix
= choose_temp_base ();
824 def_file_name
= (char *) xmalloc (strlen (fileprefix
) + 5);
825 sprintf (def_file_name
, "%s.def",
826 (dontdeltemps
) ? mybasename (fileprefix
) : fileprefix
);
830 warn (_("no export definition file provided.\n\
831 Creating one, but that may not be what you want"));
834 /* set the target platform. */
835 if (strstr (target
, "cygwin"))
836 which_target
= CYGWIN_TARGET
;
837 else if (strstr (target
, "mingw"))
838 which_target
= MINGW_TARGET
;
840 which_target
= UNKNOWN_TARGET
;
842 /* re-create the command lines as a string, taking care to quote stuff. */
843 dlltool_cmdline
= dyn_string_new (cmdline_len
);
846 dyn_string_append_cstr (dlltool_cmdline
, " -v");
848 dyn_string_append_cstr (dlltool_cmdline
, " --dllname ");
849 dyn_string_append_cstr (dlltool_cmdline
, dll_name
);
851 for (i
= 1; i
< argc
; ++i
)
853 if (dlltool_arg_indices
[i
])
855 char *arg
= saved_argv
[i
];
856 int quote
= (strchr (arg
, ' ') || strchr (arg
, '\t'));
857 dyn_string_append_cstr (dlltool_cmdline
,
858 (quote
) ? " \"" : " ");
859 dyn_string_append_cstr (dlltool_cmdline
, arg
);
860 dyn_string_append_cstr (dlltool_cmdline
,
861 (quote
) ? "\"" : "");
865 driver_cmdline
= dyn_string_new (cmdline_len
);
866 if (! driver_flags
|| strlen (driver_flags
) == 0)
868 switch (which_target
)
871 driver_flags
= cygwin_driver_flags
;
875 driver_flags
= mingw32_driver_flags
;
879 driver_flags
= generic_driver_flags
;
883 dyn_string_append_cstr (driver_cmdline
, driver_flags
);
884 dyn_string_append_cstr (driver_cmdline
, " -o ");
885 dyn_string_append_cstr (driver_cmdline
, dll_file_name
);
887 if (! entry_point
|| strlen (entry_point
) == 0)
889 switch (which_target
)
892 entry_point
= "__cygwin_dll_entry@12";
896 entry_point
= "_DllMainCRTStartup@12";
900 entry_point
= "_DllMain@12";
904 dyn_string_append_cstr (driver_cmdline
, " -Wl,-e,");
905 dyn_string_append_cstr (driver_cmdline
, entry_point
);
906 dyn_string_append_cstr (dlltool_cmdline
, " --exclude-symbol=");
907 dyn_string_append_cstr (dlltool_cmdline
,
908 (entry_point
[0] == '_') ? entry_point
+1 : entry_point
);
910 if (! image_base_str
|| strlen (image_base_str
) == 0)
912 char *tmpbuf
= (char *) xmalloc (sizeof ("0x12345678") + 1);
913 unsigned long hash
= strhash (dll_file_name
);
914 sprintf (tmpbuf
, "0x%.8lX", 0x60000000|((hash
<<16)&0xFFC0000));
915 image_base_str
= tmpbuf
;
918 dyn_string_append_cstr (driver_cmdline
, " -Wl,--image-base,");
919 dyn_string_append_cstr (driver_cmdline
, image_base_str
);
923 dyn_string_append_cstr (driver_cmdline
, " -v");
926 for (i
= 1; i
< argc
; ++i
)
928 if (driver_arg_indices
[i
])
930 char *arg
= saved_argv
[i
];
931 int quote
= (strchr (arg
, ' ') || strchr (arg
, '\t'));
932 dyn_string_append_cstr (driver_cmdline
,
933 (quote
) ? " \"" : " ");
934 dyn_string_append_cstr (driver_cmdline
, arg
);
935 dyn_string_append_cstr (driver_cmdline
,
936 (quote
) ? "\"" : "");
941 * Step pre-1. If no --def <EXPORT_DEF> is specified, then create it
942 * and then pass it on.
948 dyn_string_t step_pre1
;
950 step_pre1
= dyn_string_new (1024);
952 dyn_string_append_cstr (step_pre1
, dlltool_cmdline
->s
);
955 dyn_string_append_cstr (step_pre1
, " --export-all --exclude-symbol=");
956 dyn_string_append_cstr (step_pre1
,
957 "_cygwin_dll_entry@12,DllMainCRTStartup@12,DllMain@12,DllEntryPoint@12");
959 dyn_string_append_cstr (step_pre1
, " --output-def ");
960 dyn_string_append_cstr (step_pre1
, def_file_name
);
962 for (i
= 1; i
< argc
; ++i
)
964 if (driver_arg_indices
[i
])
966 char *arg
= saved_argv
[i
];
967 size_t len
= strlen (arg
);
968 if (len
>= 2 && arg
[len
-2] == '.'
969 && (arg
[len
-1] == 'o' || arg
[len
-1] == 'a'))
971 int quote
= (strchr (arg
, ' ') || strchr (arg
, '\t'));
972 dyn_string_append_cstr (step_pre1
,
973 (quote
) ? " \"" : " ");
974 dyn_string_append_cstr (step_pre1
, arg
);
975 dyn_string_append_cstr (step_pre1
,
976 (quote
) ? "\"" : "");
981 if (run (dlltool_name
, step_pre1
->s
))
982 cleanup_and_exit (1);
984 dyn_string_delete (step_pre1
);
987 dyn_string_append_cstr (dlltool_cmdline
, " --def ");
988 dyn_string_append_cstr (dlltool_cmdline
, def_file_name
);
992 fprintf (stderr
, _("DLLTOOL name : %s\n"), dlltool_name
);
993 fprintf (stderr
, _("DLLTOOL options : %s\n"), dlltool_cmdline
->s
);
994 fprintf (stderr
, _("DRIVER name : %s\n"), driver_name
);
995 fprintf (stderr
, _("DRIVER options : %s\n"), driver_cmdline
->s
);
999 * Step 1. Call GCC/LD to create base relocation file. If using GCC, the
1000 * driver command line will look like the following:
1002 * % gcc -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
1004 * If the user does not specify a base name, create temporary one that
1005 * is deleted at exit.
1009 if (! base_file_name
)
1011 char *fileprefix
= choose_temp_base ();
1012 base_file_name
= (char *) xmalloc (strlen (fileprefix
) + 6);
1013 sprintf (base_file_name
, "%s.base",
1014 (dontdeltemps
) ? mybasename (fileprefix
) : fileprefix
);
1015 delete_base_file
= 1;
1022 dyn_string_t step1
= dyn_string_new (driver_cmdline
->length
1023 + strlen (base_file_name
)
1025 dyn_string_append_cstr (step1
, "-Wl,--base-file,");
1026 quote
= (strchr (base_file_name
, ' ')
1027 || strchr (base_file_name
, '\t'));
1028 dyn_string_append_cstr (step1
,
1029 (quote
) ? "\"" : "");
1030 dyn_string_append_cstr (step1
, base_file_name
);
1031 dyn_string_append_cstr (step1
,
1032 (quote
) ? "\"" : "");
1033 if (driver_cmdline
->length
)
1035 dyn_string_append_cstr (step1
, " ");
1036 dyn_string_append_cstr (step1
, driver_cmdline
->s
);
1039 if (run (driver_name
, step1
->s
))
1040 cleanup_and_exit (1);
1042 dyn_string_delete (step1
);
1048 * Step 2. generate the exp file by running dlltool.
1049 * dlltool command line will look like the following:
1051 * % dlltool -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
1053 * If the user does not specify a base name, create temporary one that
1054 * is deleted at exit.
1058 if (! exp_file_name
)
1060 char *p
= strrchr (dll_name
, '.');
1061 size_t prefix_len
= (p
) ? p
- dll_name
: strlen (dll_name
);
1062 exp_file_name
= (char *) xmalloc (prefix_len
+ 4 + 1);
1063 strncpy (exp_file_name
, dll_name
, prefix_len
);
1064 exp_file_name
[prefix_len
] = '\0';
1065 strcat (exp_file_name
, ".exp");
1066 delete_exp_file
= 1;
1071 dyn_string_t step2
= dyn_string_new (dlltool_cmdline
->length
1072 + strlen (base_file_name
)
1073 + strlen (exp_file_name
)
1076 dyn_string_append_cstr (step2
, "--base-file ");
1077 quote
= (strchr (base_file_name
, ' ')
1078 || strchr (base_file_name
, '\t'));
1079 dyn_string_append_cstr (step2
,
1080 (quote
) ? "\"" : "");
1081 dyn_string_append_cstr (step2
, base_file_name
);
1082 dyn_string_append_cstr (step2
,
1083 (quote
) ? "\" " : " ");
1085 dyn_string_append_cstr (step2
, "--output-exp ");
1086 quote
= (strchr (exp_file_name
, ' ')
1087 || strchr (exp_file_name
, '\t'));
1088 dyn_string_append_cstr (step2
,
1089 (quote
) ? "\"" : "");
1090 dyn_string_append_cstr (step2
, exp_file_name
);
1091 dyn_string_append_cstr (step2
,
1092 (quote
) ? "\"" : "");
1094 if (dlltool_cmdline
->length
)
1096 dyn_string_append_cstr (step2
, " ");
1097 dyn_string_append_cstr (step2
, dlltool_cmdline
->s
);
1100 if (run (dlltool_name
, step2
->s
))
1101 cleanup_and_exit (1);
1103 dyn_string_delete (step2
);
1107 * Step 3. Call GCC/LD to again, adding the exp file this time.
1108 * driver command line will look like the following:
1110 * % gcc -Wl,--dll --Wl,--base-file,foo.base foo.exp [rest ...]
1116 dyn_string_t step3
= dyn_string_new (driver_cmdline
->length
1117 + strlen (exp_file_name
)
1118 + strlen (base_file_name
)
1120 dyn_string_append_cstr (step3
, "-Wl,--base-file,");
1121 quote
= (strchr (base_file_name
, ' ')
1122 || strchr (base_file_name
, '\t'));
1123 dyn_string_append_cstr (step3
,
1124 (quote
) ? "\"" : "");
1125 dyn_string_append_cstr (step3
, base_file_name
);
1126 dyn_string_append_cstr (step3
,
1127 (quote
) ? "\" " : " ");
1129 quote
= (strchr (exp_file_name
, ' ')
1130 || strchr (exp_file_name
, '\t'));
1131 dyn_string_append_cstr (step3
,
1132 (quote
) ? "\"" : "");
1133 dyn_string_append_cstr (step3
, exp_file_name
);
1134 dyn_string_append_cstr (step3
,
1135 (quote
) ? "\"" : "");
1137 if (driver_cmdline
->length
)
1139 dyn_string_append_cstr (step3
, " ");
1140 dyn_string_append_cstr (step3
, driver_cmdline
->s
);
1143 if (run (driver_name
, step3
->s
))
1144 cleanup_and_exit (1);
1146 dyn_string_delete (step3
);
1151 * Step 4. Run DLLTOOL again using the same command line.
1156 dyn_string_t step4
= dyn_string_new (dlltool_cmdline
->length
1157 + strlen (base_file_name
)
1158 + strlen (exp_file_name
)
1161 dyn_string_append_cstr (step4
, "--base-file ");
1162 quote
= (strchr (base_file_name
, ' ')
1163 || strchr (base_file_name
, '\t'));
1164 dyn_string_append_cstr (step4
,
1165 (quote
) ? "\"" : "");
1166 dyn_string_append_cstr (step4
, base_file_name
);
1167 dyn_string_append_cstr (step4
,
1168 (quote
) ? "\" " : " ");
1170 dyn_string_append_cstr (step4
, "--output-exp ");
1171 quote
= (strchr (exp_file_name
, ' ')
1172 || strchr (exp_file_name
, '\t'));
1173 dyn_string_append_cstr (step4
,
1174 (quote
) ? "\"" : "");
1175 dyn_string_append_cstr (step4
, exp_file_name
);
1176 dyn_string_append_cstr (step4
,
1177 (quote
) ? "\"" : "");
1179 if (dlltool_cmdline
->length
)
1181 dyn_string_append_cstr (step4
, " ");
1182 dyn_string_append_cstr (step4
, dlltool_cmdline
->s
);
1185 if (output_lib_file_name
)
1187 dyn_string_append_cstr (step4
, " --output-lib ");
1188 dyn_string_append_cstr (step4
, output_lib_file_name
);
1191 if (run (dlltool_name
, step4
->s
))
1192 cleanup_and_exit (1);
1194 dyn_string_delete (step4
);
1199 * Step 5. Link it all together and be done with it.
1200 * driver command line will look like the following:
1202 * % gcc -Wl,--dll foo.exp [rest ...]
1209 dyn_string_t step5
= dyn_string_new (driver_cmdline
->length
1210 + strlen (exp_file_name
)
1212 quote
= (strchr (exp_file_name
, ' ')
1213 || strchr (exp_file_name
, '\t'));
1214 dyn_string_append_cstr (step5
,
1215 (quote
) ? "\"" : "");
1216 dyn_string_append_cstr (step5
, exp_file_name
);
1217 dyn_string_append_cstr (step5
,
1218 (quote
) ? "\"" : "");
1220 if (driver_cmdline
->length
)
1222 dyn_string_append_cstr (step5
, " ");
1223 dyn_string_append_cstr (step5
, driver_cmdline
->s
);
1226 if (run (driver_name
, step5
->s
))
1227 cleanup_and_exit (1);
1229 dyn_string_delete (step5
);
1232 cleanup_and_exit (0);