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