1 /* $MirOS: src/gnu/usr.bin/binutils/binutils/dllwrap.c,v 1.3 2005/06/05 21:24:04 tg Exp $ */
2
3 /* dllwrap.c -- wrapper for DLLTOOL and GCC to generate PE style DLLs
4 Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
5 Contributed by Mumit Khan (khan@xraylith.wisc.edu).
6
7 This file is part of GNU Binutils.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
22 02110-1301, USA. */
23
24 /* AIX requires this to be the first thing in the file. */
25 #ifndef __GNUC__
26 # ifdef _AIX
27 #pragma alloca
28 #endif
29 #endif
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #include "bfd.h"
36 #include "libiberty.h"
37 #include "bucomm.h"
38 #include "getopt.h"
39 #include "dyn-string.h"
40
41 #include <time.h>
42 #include <sys/stat.h>
43
44 #ifdef ANSI_PROTOTYPES
45 #include <stdarg.h>
46 #else
47 #include <varargs.h>
48 #endif
49
50 __RCSID("$MirOS: src/gnu/usr.bin/binutils/binutils/dllwrap.c,v 1.3 2005/06/05 21:24:04 tg Exp $");
51
52 #ifdef HAVE_SYS_WAIT_H
53 #include <sys/wait.h>
54 #else /* ! HAVE_SYS_WAIT_H */
55 #if ! defined (_WIN32) || defined (__CYGWIN32__)
56 #ifndef WIFEXITED
57 #define WIFEXITED(w) (((w)&0377) == 0)
58 #endif
59 #ifndef WIFSIGNALED
60 #define WIFSIGNALED(w) (((w)&0377) != 0177 && ((w)&~0377) == 0)
61 #endif
62 #ifndef WTERMSIG
63 #define WTERMSIG(w) ((w) & 0177)
64 #endif
65 #ifndef WEXITSTATUS
66 #define WEXITSTATUS(w) (((w) >> 8) & 0377)
67 #endif
68 #else /* defined (_WIN32) && ! defined (__CYGWIN32__) */
69 #ifndef WIFEXITED
70 #define WIFEXITED(w) (((w) & 0xff) == 0)
71 #endif
72 #ifndef WIFSIGNALED
73 #define WIFSIGNALED(w) (((w) & 0xff) != 0 && ((w) & 0xff) != 0x7f)
74 #endif
75 #ifndef WTERMSIG
76 #define WTERMSIG(w) ((w) & 0x7f)
77 #endif
78 #ifndef WEXITSTATUS
79 #define WEXITSTATUS(w) (((w) & 0xff00) >> 8)
80 #endif
81 #endif /* defined (_WIN32) && ! defined (__CYGWIN32__) */
82 #endif /* ! HAVE_SYS_WAIT_H */
83
84 static char *driver_name = NULL;
85 static char *cygwin_driver_flags =
86 "-Wl,--dll -nostartfiles";
87 static char *mingw32_driver_flags = "-mdll";
88 static char *generic_driver_flags = "-Wl,--dll";
89
90 static char *entry_point;
91
92 static char *dlltool_name = NULL;
93
94 static char *target = TARGET;
95
96 typedef enum {
97 UNKNOWN_TARGET,
98 CYGWIN_TARGET,
99 MINGW_TARGET
100 }
101 target_type;
102
103 static target_type which_target = UNKNOWN_TARGET;
104
105 static int dontdeltemps = 0;
106 static int dry_run = 0;
107
108 static char *prog_name;
109
110 static int verbose = 0;
111
112 static char *dll_file_name;
113 static char *dll_name;
114 static char *base_file_name;
115 static char *exp_file_name;
116 static char *def_file_name;
117 static int delete_base_file = 1;
118 static int delete_exp_file = 1;
119 static int delete_def_file = 1;
120
121 static int run (const char *, char *);
122 static char *mybasename (const char *);
123 static int strhash (const char *);
124 static void usage (FILE *, int);
125 static void display (const char *, va_list);
126 static void inform (const char *, ...);
127 static void warn (const char *, ...);
128 static char *look_for_prog (const char *, const char *, int);
129 static char *deduce_name (const char *);
130 static void delete_temp_files (void);
131 static void cleanup_and_exit (int);
132
133 /**********************************************************************/
134
135 /* Please keep the following 4 routines in sync with dlltool.c:
136 display ()
137 inform ()
138 look_for_prog ()
139 deduce_name ()
140 It's not worth the hassle to break these out since dllwrap will
141 (hopefully) soon be retired in favor of `ld --shared. */
142
143 static void
display(const char * message,va_list args)144 display (const char * message, va_list args)
145 {
146 if (prog_name != NULL)
147 fprintf (stderr, "%s: ", prog_name);
148
149 vfprintf (stderr, message, args);
150 fputc ('\n', stderr);
151 }
152
153
154 static void
inform(const char * message,...)155 inform VPARAMS ((const char *message, ...))
156 {
157 VA_OPEN (args, message);
158 VA_FIXEDARG (args, const char *, message);
159
160 if (!verbose)
161 return;
162
163 display (message, args);
164
165 VA_CLOSE (args);
166 }
167
168 static void
warn(const char * format,...)169 warn VPARAMS ((const char *format, ...))
170 {
171 VA_OPEN (args, format);
172 VA_FIXEDARG (args, const char *, format);
173
174 display (format, args);
175
176 VA_CLOSE (args);
177 }
178
179 /* Look for the program formed by concatenating PROG_NAME and the
180 string running from PREFIX to END_PREFIX. If the concatenated
181 string contains a '/', try appending EXECUTABLE_SUFFIX if it is
182 appropriate. */
183
184 static char *
look_for_prog(const char * prog_name,const char * prefix,int end_prefix)185 look_for_prog (const char *prog_name, const char *prefix, int end_prefix)
186 {
187 struct stat s;
188 char *cmd;
189
190 cmd = xmalloc (strlen (prefix)
191 + strlen (prog_name)
192 #ifdef HAVE_EXECUTABLE_SUFFIX
193 + strlen (EXECUTABLE_SUFFIX)
194 #endif
195 + 10);
196 strcpy (cmd, prefix);
197
198 sprintf (cmd + end_prefix, "%s", prog_name);
199
200 if (strchr (cmd, '/') != NULL)
201 {
202 int found;
203
204 found = (stat (cmd, &s) == 0
205 #ifdef HAVE_EXECUTABLE_SUFFIX
206 || stat (strcat (cmd, EXECUTABLE_SUFFIX), &s) == 0
207 #endif
208 );
209
210 if (! found)
211 {
212 /* xgettext:c-format */
213 inform (_("Tried file: %s"), cmd);
214 free (cmd);
215 return NULL;
216 }
217 }
218
219 /* xgettext:c-format */
220 inform (_("Using file: %s"), cmd);
221
222 return cmd;
223 }
224
225 /* Deduce the name of the program we are want to invoke.
226 PROG_NAME is the basic name of the program we want to run,
227 eg "as" or "ld". The catch is that we might want actually
228 run "i386-pe-as" or "ppc-pe-ld".
229
230 If argv[0] contains the full path, then try to find the program
231 in the same place, with and then without a target-like prefix.
232
233 Given, argv[0] = /usr/local/bin/i586-cygwin32-dlltool,
234 deduce_name("as") uses the following search order:
235
236 /usr/local/bin/i586-cygwin32-as
237 /usr/local/bin/as
238 as
239
240 If there's an EXECUTABLE_SUFFIX, it'll use that as well; for each
241 name, it'll try without and then with EXECUTABLE_SUFFIX.
242
243 Given, argv[0] = i586-cygwin32-dlltool, it will not even try "as"
244 as the fallback, but rather return i586-cygwin32-as.
245
246 Oh, and given, argv[0] = dlltool, it'll return "as".
247
248 Returns a dynamically allocated string. */
249
250 static char *
deduce_name(const char * name)251 deduce_name (const char * name)
252 {
253 char *cmd;
254 const char *dash;
255 const char *slash;
256 const char *cp;
257
258 dash = NULL;
259 slash = NULL;
260 for (cp = prog_name; *cp != '\0'; ++cp)
261 {
262 if (*cp == '-')
263 dash = cp;
264
265 if (
266 #if defined(__DJGPP__) || defined (__CYGWIN__) || defined(__WIN32__)
267 *cp == ':' || *cp == '\\' ||
268 #endif
269 *cp == '/')
270 {
271 slash = cp;
272 dash = NULL;
273 }
274 }
275
276 cmd = NULL;
277
278 if (dash != NULL)
279 /* First, try looking for a prefixed NAME in the
280 PROG_NAME directory, with the same prefix as PROG_NAME. */
281 cmd = look_for_prog (name, prog_name, dash - prog_name + 1);
282
283 if (slash != NULL && cmd == NULL)
284 /* Next, try looking for a NAME in the same directory as
285 that of this program. */
286 cmd = look_for_prog (name, prog_name, slash - prog_name + 1);
287
288 if (cmd == NULL)
289 /* Just return NAME as is. */
290 cmd = xstrdup (name);
291
292 return cmd;
293 }
294
295 static void
delete_temp_files(void)296 delete_temp_files (void)
297 {
298 if (delete_base_file && base_file_name)
299 {
300 if (verbose)
301 {
302 if (dontdeltemps)
303 warn (_("Keeping temporary base file %s"), base_file_name);
304 else
305 warn (_("Deleting temporary base file %s"), base_file_name);
306 }
307 if (! dontdeltemps)
308 {
309 unlink (base_file_name);
310 free (base_file_name);
311 }
312 }
313
314 if (delete_exp_file && exp_file_name)
315 {
316 if (verbose)
317 {
318 if (dontdeltemps)
319 warn (_("Keeping temporary exp file %s"), exp_file_name);
320 else
321 warn (_("Deleting temporary exp file %s"), exp_file_name);
322 }
323 if (! dontdeltemps)
324 {
325 unlink (exp_file_name);
326 free (exp_file_name);
327 }
328 }
329 if (delete_def_file && def_file_name)
330 {
331 if (verbose)
332 {
333 if (dontdeltemps)
334 warn (_("Keeping temporary def file %s"), def_file_name);
335 else
336 warn (_("Deleting temporary def file %s"), def_file_name);
337 }
338 if (! dontdeltemps)
339 {
340 unlink (def_file_name);
341 free (def_file_name);
342 }
343 }
344 }
345
346 static void
cleanup_and_exit(int status)347 cleanup_and_exit (int status)
348 {
349 delete_temp_files ();
350 exit (status);
351 }
352
353 static int
run(const char * what,char * args)354 run (const char *what, char *args)
355 {
356 char *s;
357 int pid, wait_status, retcode;
358 int i;
359 const char **argv;
360 char *errmsg_fmt, *errmsg_arg;
361 #if defined(__MSDOS__) && !defined(__GO32__)
362 char *temp_base = choose_temp_base ();
363 #else
364 char *temp_base = NULL;
365 #endif
366 int in_quote;
367 char sep;
368
369 if (verbose || dry_run)
370 fprintf (stderr, "%s %s\n", what, args);
371
372 /* Count the args */
373 i = 0;
374 for (s = args; *s; s++)
375 if (*s == ' ')
376 i++;
377 i++;
378 argv = alloca (sizeof (char *) * (i + 3));
379 i = 0;
380 argv[i++] = what;
381 s = args;
382 while (1)
383 {
384 while (*s == ' ' && *s != 0)
385 s++;
386 if (*s == 0)
387 break;
388 in_quote = (*s == '\'' || *s == '"');
389 sep = (in_quote) ? *s++ : ' ';
390 argv[i++] = s;
391 while (*s != sep && *s != 0)
392 s++;
393 if (*s == 0)
394 break;
395 *s++ = 0;
396 if (in_quote)
397 s++;
398 }
399 argv[i++] = NULL;
400
401 if (dry_run)
402 return 0;
403
404 pid = pexecute (argv[0], (char * const *) argv, prog_name, temp_base,
405 &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
406
407 if (pid == -1)
408 {
409 int errno_val = errno;
410
411 fprintf (stderr, "%s: ", prog_name);
412 fprintf (stderr, errmsg_fmt, errmsg_arg);
413 fprintf (stderr, ": %s\n", strerror (errno_val));
414 return 1;
415 }
416
417 retcode = 0;
418 pid = pwait (pid, &wait_status, 0);
419 if (pid == -1)
420 {
421 warn ("wait: %s", strerror (errno));
422 retcode = 1;
423 }
424 else if (WIFSIGNALED (wait_status))
425 {
426 warn (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
427 retcode = 1;
428 }
429 else if (WIFEXITED (wait_status))
430 {
431 if (WEXITSTATUS (wait_status) != 0)
432 {
433 warn (_("%s exited with status %d"), what, WEXITSTATUS (wait_status));
434 retcode = 1;
435 }
436 }
437 else
438 retcode = 1;
439
440 return retcode;
441 }
442
443 static char *
mybasename(const char * name)444 mybasename (const char *name)
445 {
446 const char *base = name;
447
448 while (*name)
449 {
450 if (*name == '/' || *name == '\\')
451 {
452 base = name + 1;
453 }
454 ++name;
455 }
456 return (char *) base;
457 }
458
459 static int
strhash(const char * str)460 strhash (const char *str)
461 {
462 const unsigned char *s;
463 unsigned long hash;
464 unsigned int c;
465 unsigned int len;
466
467 hash = 0;
468 len = 0;
469 s = (const unsigned char *) str;
470 while ((c = *s++) != '\0')
471 {
472 hash += c + (c << 17);
473 hash ^= hash >> 2;
474 ++len;
475 }
476 hash += len + (len << 17);
477 hash ^= hash >> 2;
478
479 return hash;
480 }
481
482 /**********************************************************************/
483
484 static void
usage(FILE * file,int status)485 usage (FILE *file, int status)
486 {
487 fprintf (file, _("Usage %s <option(s)> <object-file(s)>\n"), prog_name);
488 fprintf (file, _(" Generic options:\n"));
489 fprintf (file, _(" --quiet, -q Work quietly\n"));
490 fprintf (file, _(" --verbose, -v Verbose\n"));
491 fprintf (file, _(" --version Print dllwrap version\n"));
492 fprintf (file, _(" --implib <outname> Synonym for --output-lib\n"));
493 fprintf (file, _(" Options for %s:\n"), prog_name);
494 fprintf (file, _(" --driver-name <driver> Defaults to \"gcc\"\n"));
495 fprintf (file, _(" --driver-flags <flags> Override default ld flags\n"));
496 fprintf (file, _(" --dlltool-name <dlltool> Defaults to \"dlltool\"\n"));
497 fprintf (file, _(" --entry <entry> Specify alternate DLL entry point\n"));
498 fprintf (file, _(" --image-base <base> Specify image base address\n"));
499 fprintf (file, _(" --target <machine> i386-cygwin32 or i386-mingw32\n"));
500 fprintf (file, _(" --dry-run Show what needs to be run\n"));
501 fprintf (file, _(" --mno-cygwin Create Mingw DLL\n"));
502 fprintf (file, _(" Options passed to DLLTOOL:\n"));
503 fprintf (file, _(" --machine <machine>\n"));
504 fprintf (file, _(" --output-exp <outname> Generate export file.\n"));
505 fprintf (file, _(" --output-lib <outname> Generate input library.\n"));
506 fprintf (file, _(" --add-indirect Add dll indirects to export file.\n"));
507 fprintf (file, _(" --dllname <name> Name of input dll to put into output lib.\n"));
508 fprintf (file, _(" --def <deffile> Name input .def file\n"));
509 fprintf (file, _(" --output-def <deffile> Name output .def file\n"));
510 fprintf (file, _(" --export-all-symbols Export all symbols to .def\n"));
511 fprintf (file, _(" --no-export-all-symbols Only export .drectve symbols\n"));
512 fprintf (file, _(" --exclude-symbols <list> Exclude <list> from .def\n"));
513 fprintf (file, _(" --no-default-excludes Zap default exclude symbols\n"));
514 fprintf (file, _(" --base-file <basefile> Read linker generated base file\n"));
515 fprintf (file, _(" --no-idata4 Don't generate idata$4 section\n"));
516 fprintf (file, _(" --no-idata5 Don't generate idata$5 section\n"));
517 fprintf (file, _(" -U Add underscores to .lib\n"));
518 fprintf (file, _(" -k Kill @<n> from exported names\n"));
519 fprintf (file, _(" --add-stdcall-alias Add aliases without @<n>\n"));
520 fprintf (file, _(" --as <name> Use <name> for assembler\n"));
521 fprintf (file, _(" --nodelete Keep temp files.\n"));
522 fprintf (file, _(" Rest are passed unmodified to the language driver\n"));
523 fprintf (file, "\n\n");
524 exit (status);
525 }
526
527 #define OPTION_START 149
528
529 /* GENERIC options. */
530 #define OPTION_QUIET (OPTION_START + 1)
531 #define OPTION_VERBOSE (OPTION_QUIET + 1)
532 #define OPTION_VERSION (OPTION_VERBOSE + 1)
533
534 /* DLLWRAP options. */
535 #define OPTION_DRY_RUN (OPTION_VERSION + 1)
536 #define OPTION_DRIVER_NAME (OPTION_DRY_RUN + 1)
537 #define OPTION_DRIVER_FLAGS (OPTION_DRIVER_NAME + 1)
538 #define OPTION_DLLTOOL_NAME (OPTION_DRIVER_FLAGS + 1)
539 #define OPTION_ENTRY (OPTION_DLLTOOL_NAME + 1)
540 #define OPTION_IMAGE_BASE (OPTION_ENTRY + 1)
541 #define OPTION_TARGET (OPTION_IMAGE_BASE + 1)
542 #define OPTION_MNO_CYGWIN (OPTION_TARGET + 1)
543
544 /* DLLTOOL options. */
545 #define OPTION_NODELETE (OPTION_MNO_CYGWIN + 1)
546 #define OPTION_DLLNAME (OPTION_NODELETE + 1)
547 #define OPTION_NO_IDATA4 (OPTION_DLLNAME + 1)
548 #define OPTION_NO_IDATA5 (OPTION_NO_IDATA4 + 1)
549 #define OPTION_OUTPUT_EXP (OPTION_NO_IDATA5 + 1)
550 #define OPTION_OUTPUT_DEF (OPTION_OUTPUT_EXP + 1)
551 #define OPTION_EXPORT_ALL_SYMS (OPTION_OUTPUT_DEF + 1)
552 #define OPTION_NO_EXPORT_ALL_SYMS (OPTION_EXPORT_ALL_SYMS + 1)
553 #define OPTION_EXCLUDE_SYMS (OPTION_NO_EXPORT_ALL_SYMS + 1)
554 #define OPTION_NO_DEFAULT_EXCLUDES (OPTION_EXCLUDE_SYMS + 1)
555 #define OPTION_OUTPUT_LIB (OPTION_NO_DEFAULT_EXCLUDES + 1)
556 #define OPTION_DEF (OPTION_OUTPUT_LIB + 1)
557 #define OPTION_ADD_UNDERSCORE (OPTION_DEF + 1)
558 #define OPTION_KILLAT (OPTION_ADD_UNDERSCORE + 1)
559 #define OPTION_HELP (OPTION_KILLAT + 1)
560 #define OPTION_MACHINE (OPTION_HELP + 1)
561 #define OPTION_ADD_INDIRECT (OPTION_MACHINE + 1)
562 #define OPTION_BASE_FILE (OPTION_ADD_INDIRECT + 1)
563 #define OPTION_AS (OPTION_BASE_FILE + 1)
564
565 static const struct option long_options[] =
566 {
567 /* generic options. */
568 {"quiet", no_argument, NULL, 'q'},
569 {"verbose", no_argument, NULL, 'v'},
570 {"version", no_argument, NULL, OPTION_VERSION},
571 {"implib", required_argument, NULL, OPTION_OUTPUT_LIB},
572
573 /* dllwrap options. */
574 {"dry-run", no_argument, NULL, OPTION_DRY_RUN},
575 {"driver-name", required_argument, NULL, OPTION_DRIVER_NAME},
576 {"driver-flags", required_argument, NULL, OPTION_DRIVER_FLAGS},
577 {"dlltool-name", required_argument, NULL, OPTION_DLLTOOL_NAME},
578 {"entry", required_argument, NULL, 'e'},
579 {"image-base", required_argument, NULL, OPTION_IMAGE_BASE},
580 {"target", required_argument, NULL, OPTION_TARGET},
581
582 /* dlltool options. */
583 {"no-delete", no_argument, NULL, 'n'},
584 {"dllname", required_argument, NULL, OPTION_DLLNAME},
585 {"no-idata4", no_argument, NULL, OPTION_NO_IDATA4},
586 {"no-idata5", no_argument, NULL, OPTION_NO_IDATA5},
587 {"output-exp", required_argument, NULL, OPTION_OUTPUT_EXP},
588 {"output-def", required_argument, NULL, OPTION_OUTPUT_DEF},
589 {"export-all-symbols", no_argument, NULL, OPTION_EXPORT_ALL_SYMS},
590 {"no-export-all-symbols", no_argument, NULL, OPTION_NO_EXPORT_ALL_SYMS},
591 {"exclude-symbols", required_argument, NULL, OPTION_EXCLUDE_SYMS},
592 {"no-default-excludes", no_argument, NULL, OPTION_NO_DEFAULT_EXCLUDES},
593 {"output-lib", required_argument, NULL, OPTION_OUTPUT_LIB},
594 {"def", required_argument, NULL, OPTION_DEF},
595 {"add-underscore", no_argument, NULL, 'U'},
596 {"killat", no_argument, NULL, 'k'},
597 {"add-stdcall-alias", no_argument, NULL, 'A'},
598 {"help", no_argument, NULL, 'h'},
599 {"machine", required_argument, NULL, OPTION_MACHINE},
600 {"add-indirect", no_argument, NULL, OPTION_ADD_INDIRECT},
601 {"base-file", required_argument, NULL, OPTION_BASE_FILE},
602 {"as", required_argument, NULL, OPTION_AS},
603 {0, 0, 0, 0}
604 };
605
606 int main (int, char **);
607
608 int
main(int argc,char ** argv)609 main (int argc, char **argv)
610 {
611 int c;
612 int i;
613
614 char **saved_argv = 0;
615 int cmdline_len = 0;
616
617 int export_all = 0;
618
619 int *dlltool_arg_indices;
620 int *driver_arg_indices;
621
622 char *driver_flags = 0;
623 char *output_lib_file_name = 0;
624
625 dyn_string_t dlltool_cmdline;
626 dyn_string_t driver_cmdline;
627
628 int def_file_seen = 0;
629
630 char *image_base_str = 0;
631
632 prog_name = argv[0];
633
634 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
635 setlocale (LC_MESSAGES, "");
636 #endif
637 #if defined (HAVE_SETLOCALE)
638 setlocale (LC_CTYPE, "");
639 #endif
640 bindtextdomain (PACKAGE, LOCALEDIR);
641 textdomain (PACKAGE);
642
643 saved_argv = (char **) xmalloc (argc * sizeof (char*));
644 dlltool_arg_indices = (int *) xmalloc (argc * sizeof (int));
645 driver_arg_indices = (int *) xmalloc (argc * sizeof (int));
646 for (i = 0; i < argc; ++i)
647 {
648 size_t len = strlen (argv[i]);
649 char *arg = (char *) xmalloc (len + 1);
650 strcpy (arg, argv[i]);
651 cmdline_len += len;
652 saved_argv[i] = arg;
653 dlltool_arg_indices[i] = 0;
654 driver_arg_indices[i] = 1;
655 }
656 cmdline_len++;
657
658 /* We recognize dllwrap and dlltool options, and everything else is
659 passed onto the language driver (eg., to GCC). We collect options
660 to dlltool and driver in dlltool_args and driver_args. */
661
662 opterr = 0;
663 while ((c = getopt_long_only (argc, argv, "nkAqve:Uho:l:L:I:",
664 long_options, (int *) 0)) != EOF)
665 {
666 int dlltool_arg;
667 int driver_arg;
668 int single_word_option_value_pair;
669
670 dlltool_arg = 0;
671 driver_arg = 1;
672 single_word_option_value_pair = 0;
673
674 if (c != '?')
675 {
676 /* We recognize this option, so it has to be either dllwrap or
677 dlltool option. Do not pass to driver unless it's one of the
678 generic options that are passed to all the tools (such as -v)
679 which are dealt with later. */
680 driver_arg = 0;
681 }
682
683 /* deal with generic and dllwrap options first. */
684 switch (c)
685 {
686 case 'h':
687 usage (stdout, 0);
688 break;
689 case 'q':
690 verbose = 0;
691 break;
692 case 'v':
693 verbose = 1;
694 break;
695 case OPTION_VERSION:
696 print_version (prog_name);
697 break;
698 case 'e':
699 entry_point = optarg;
700 break;
701 case OPTION_IMAGE_BASE:
702 image_base_str = optarg;
703 break;
704 case OPTION_DEF:
705 def_file_name = optarg;
706 def_file_seen = 1;
707 delete_def_file = 0;
708 break;
709 case 'n':
710 dontdeltemps = 1;
711 dlltool_arg = 1;
712 break;
713 case 'o':
714 dll_file_name = optarg;
715 break;
716 case 'I':
717 case 'l':
718 case 'L':
719 driver_arg = 1;
720 break;
721 case OPTION_DLLNAME:
722 dll_name = optarg;
723 break;
724 case OPTION_DRY_RUN:
725 dry_run = 1;
726 break;
727 case OPTION_DRIVER_NAME:
728 driver_name = optarg;
729 break;
730 case OPTION_DRIVER_FLAGS:
731 driver_flags = optarg;
732 break;
733 case OPTION_DLLTOOL_NAME:
734 dlltool_name = optarg;
735 break;
736 case OPTION_TARGET:
737 target = optarg;
738 break;
739 case OPTION_MNO_CYGWIN:
740 target = "i386-mingw32";
741 break;
742 case OPTION_BASE_FILE:
743 base_file_name = optarg;
744 delete_base_file = 0;
745 break;
746 case OPTION_OUTPUT_EXP:
747 exp_file_name = optarg;
748 delete_exp_file = 0;
749 break;
750 case OPTION_EXPORT_ALL_SYMS:
751 export_all = 1;
752 break;
753 case OPTION_OUTPUT_LIB:
754 output_lib_file_name = optarg;
755 break;
756 case '?':
757 break;
758 default:
759 dlltool_arg = 1;
760 break;
761 }
762
763 /* Handle passing through --option=value case. */
764 if (optarg
765 && saved_argv[optind-1][0] == '-'
766 && saved_argv[optind-1][1] == '-'
767 && strchr (saved_argv[optind-1], '='))
768 single_word_option_value_pair = 1;
769
770 if (dlltool_arg)
771 {
772 dlltool_arg_indices[optind-1] = 1;
773 if (optarg && ! single_word_option_value_pair)
774 {
775 dlltool_arg_indices[optind-2] = 1;
776 }
777 }
778
779 if (! driver_arg)
780 {
781 driver_arg_indices[optind-1] = 0;
782 if (optarg && ! single_word_option_value_pair)
783 {
784 driver_arg_indices[optind-2] = 0;
785 }
786 }
787 }
788
789 /* Sanity checks. */
790 if (! dll_name && ! dll_file_name)
791 {
792 warn (_("Must provide at least one of -o or --dllname options"));
793 exit (1);
794 }
795 else if (! dll_name)
796 {
797 dll_name = xstrdup (mybasename (dll_file_name));
798 }
799 else if (! dll_file_name)
800 {
801 dll_file_name = xstrdup (dll_name);
802 }
803
804 /* Deduce driver-name and dlltool-name from our own. */
805 if (driver_name == NULL)
806 driver_name = deduce_name ("gcc");
807
808 if (dlltool_name == NULL)
809 dlltool_name = deduce_name ("dlltool");
810
811 if (! def_file_seen)
812 {
813 def_file_name = make_temp_file (".def");
814 if (dontdeltemps)
815 def_file_name = mybasename (def_file_name);
816 delete_def_file = 1;
817 warn (_("no export definition file provided.\n\
818 Creating one, but that may not be what you want"));
819 }
820
821 /* Set the target platform. */
822 if (strstr (target, "cygwin"))
823 which_target = CYGWIN_TARGET;
824 else if (strstr (target, "mingw"))
825 which_target = MINGW_TARGET;
826 else
827 which_target = UNKNOWN_TARGET;
828
829 /* Re-create the command lines as a string, taking care to quote stuff. */
830 dlltool_cmdline = dyn_string_new (cmdline_len);
831 if (verbose)
832 dyn_string_append_cstr (dlltool_cmdline, " -v");
833
834 dyn_string_append_cstr (dlltool_cmdline, " --dllname ");
835 dyn_string_append_cstr (dlltool_cmdline, dll_name);
836
837 for (i = 1; i < argc; ++i)
838 {
839 if (dlltool_arg_indices[i])
840 {
841 char *arg = saved_argv[i];
842 int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
843 dyn_string_append_cstr (dlltool_cmdline,
844 (quote) ? " \"" : " ");
845 dyn_string_append_cstr (dlltool_cmdline, arg);
846 dyn_string_append_cstr (dlltool_cmdline,
847 (quote) ? "\"" : "");
848 }
849 }
850
851 driver_cmdline = dyn_string_new (cmdline_len);
852 if (! driver_flags || strlen (driver_flags) == 0)
853 {
854 switch (which_target)
855 {
856 case CYGWIN_TARGET:
857 driver_flags = cygwin_driver_flags;
858 break;
859
860 case MINGW_TARGET:
861 driver_flags = mingw32_driver_flags;
862 break;
863
864 default:
865 driver_flags = generic_driver_flags;
866 break;
867 }
868 }
869 dyn_string_append_cstr (driver_cmdline, driver_flags);
870 dyn_string_append_cstr (driver_cmdline, " -o ");
871 dyn_string_append_cstr (driver_cmdline, dll_file_name);
872
873 if (! entry_point || strlen (entry_point) == 0)
874 {
875 switch (which_target)
876 {
877 case CYGWIN_TARGET:
878 entry_point = "__cygwin_dll_entry@12";
879 break;
880
881 case MINGW_TARGET:
882 entry_point = "_DllMainCRTStartup@12";
883 break;
884
885 default:
886 entry_point = "_DllMain@12";
887 break;
888 }
889 }
890 dyn_string_append_cstr (driver_cmdline, " -Wl,-e,");
891 dyn_string_append_cstr (driver_cmdline, entry_point);
892 dyn_string_append_cstr (dlltool_cmdline, " --exclude-symbol=");
893 dyn_string_append_cstr (dlltool_cmdline,
894 (entry_point[0] == '_') ? entry_point+1 : entry_point);
895
896 if (! image_base_str || strlen (image_base_str) == 0)
897 {
898 char *tmpbuf = (char *) xmalloc (sizeof ("0x12345678") + 1);
899 unsigned long hash = strhash (dll_file_name);
900 sprintf (tmpbuf, "0x%.8lX", 0x60000000|((hash<<16)&0xFFC0000));
901 image_base_str = tmpbuf;
902 }
903
904 dyn_string_append_cstr (driver_cmdline, " -Wl,--image-base,");
905 dyn_string_append_cstr (driver_cmdline, image_base_str);
906
907 if (verbose)
908 {
909 dyn_string_append_cstr (driver_cmdline, " -v");
910 }
911
912 for (i = 1; i < argc; ++i)
913 {
914 if (driver_arg_indices[i])
915 {
916 char *arg = saved_argv[i];
917 int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
918 dyn_string_append_cstr (driver_cmdline,
919 (quote) ? " \"" : " ");
920 dyn_string_append_cstr (driver_cmdline, arg);
921 dyn_string_append_cstr (driver_cmdline,
922 (quote) ? "\"" : "");
923 }
924 }
925
926 /* Step pre-1. If no --def <EXPORT_DEF> is specified,
927 then create it and then pass it on. */
928
929 if (! def_file_seen)
930 {
931 int i;
932 dyn_string_t step_pre1;
933
934 step_pre1 = dyn_string_new (1024);
935
936 dyn_string_append_cstr (step_pre1, dlltool_cmdline->s);
937 if (export_all)
938 {
939 dyn_string_append_cstr (step_pre1, " --export-all --exclude-symbol=");
940 dyn_string_append_cstr (step_pre1,
941 "_cygwin_dll_entry@12,DllMainCRTStartup@12,DllMain@12,DllEntryPoint@12");
942 }
943 dyn_string_append_cstr (step_pre1, " --output-def ");
944 dyn_string_append_cstr (step_pre1, def_file_name);
945
946 for (i = 1; i < argc; ++i)
947 {
948 if (driver_arg_indices[i])
949 {
950 char *arg = saved_argv[i];
951 size_t len = strlen (arg);
952 if (len >= 2 && arg[len-2] == '.'
953 && (arg[len-1] == 'o' || arg[len-1] == 'a'))
954 {
955 int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
956 dyn_string_append_cstr (step_pre1,
957 (quote) ? " \"" : " ");
958 dyn_string_append_cstr (step_pre1, arg);
959 dyn_string_append_cstr (step_pre1,
960 (quote) ? "\"" : "");
961 }
962 }
963 }
964
965 if (run (dlltool_name, step_pre1->s))
966 cleanup_and_exit (1);
967
968 dyn_string_delete (step_pre1);
969 }
970
971 dyn_string_append_cstr (dlltool_cmdline, " --def ");
972 dyn_string_append_cstr (dlltool_cmdline, def_file_name);
973
974 if (verbose)
975 {
976 fprintf (stderr, _("DLLTOOL name : %s\n"), dlltool_name);
977 fprintf (stderr, _("DLLTOOL options : %s\n"), dlltool_cmdline->s);
978 fprintf (stderr, _("DRIVER name : %s\n"), driver_name);
979 fprintf (stderr, _("DRIVER options : %s\n"), driver_cmdline->s);
980 }
981
982 /* Step 1. Call GCC/LD to create base relocation file. If using GCC, the
983 driver command line will look like the following:
984
985 % gcc -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
986
987 If the user does not specify a base name, create temporary one that
988 is deleted at exit. */
989
990 if (! base_file_name)
991 {
992 base_file_name = make_temp_file (".base");
993 if (dontdeltemps)
994 base_file_name = mybasename (base_file_name);
995 delete_base_file = 1;
996 }
997
998 {
999 int quote;
1000
1001 dyn_string_t step1 = dyn_string_new (driver_cmdline->length
1002 + strlen (base_file_name)
1003 + 20);
1004 dyn_string_append_cstr (step1, "-Wl,--base-file,");
1005 quote = (strchr (base_file_name, ' ')
1006 || strchr (base_file_name, '\t'));
1007 dyn_string_append_cstr (step1,
1008 (quote) ? "\"" : "");
1009 dyn_string_append_cstr (step1, base_file_name);
1010 dyn_string_append_cstr (step1,
1011 (quote) ? "\"" : "");
1012 if (driver_cmdline->length)
1013 {
1014 dyn_string_append_cstr (step1, " ");
1015 dyn_string_append_cstr (step1, driver_cmdline->s);
1016 }
1017
1018 if (run (driver_name, step1->s))
1019 cleanup_and_exit (1);
1020
1021 dyn_string_delete (step1);
1022 }
1023
1024 /* Step 2. generate the exp file by running dlltool.
1025 dlltool command line will look like the following:
1026
1027 % dlltool -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
1028
1029 If the user does not specify a base name, create temporary one that
1030 is deleted at exit. */
1031
1032 if (! exp_file_name)
1033 {
1034 char *p = strrchr (dll_name, '.');
1035 size_t prefix_len = (p) ? (size_t) (p - dll_name) : strlen (dll_name);
1036
1037 exp_file_name = (char *) xmalloc (prefix_len + 4 + 1);
1038 strncpy (exp_file_name, dll_name, prefix_len);
1039 exp_file_name[prefix_len] = '\0';
1040 strcat (exp_file_name, ".exp");
1041 delete_exp_file = 1;
1042 }
1043
1044 {
1045 int quote;
1046
1047 dyn_string_t step2 = dyn_string_new (dlltool_cmdline->length
1048 + strlen (base_file_name)
1049 + strlen (exp_file_name)
1050 + 20);
1051
1052 dyn_string_append_cstr (step2, "--base-file ");
1053 quote = (strchr (base_file_name, ' ')
1054 || strchr (base_file_name, '\t'));
1055 dyn_string_append_cstr (step2,
1056 (quote) ? "\"" : "");
1057 dyn_string_append_cstr (step2, base_file_name);
1058 dyn_string_append_cstr (step2,
1059 (quote) ? "\" " : " ");
1060
1061 dyn_string_append_cstr (step2, "--output-exp ");
1062 quote = (strchr (exp_file_name, ' ')
1063 || strchr (exp_file_name, '\t'));
1064 dyn_string_append_cstr (step2,
1065 (quote) ? "\"" : "");
1066 dyn_string_append_cstr (step2, exp_file_name);
1067 dyn_string_append_cstr (step2,
1068 (quote) ? "\"" : "");
1069
1070 if (dlltool_cmdline->length)
1071 {
1072 dyn_string_append_cstr (step2, " ");
1073 dyn_string_append_cstr (step2, dlltool_cmdline->s);
1074 }
1075
1076 if (run (dlltool_name, step2->s))
1077 cleanup_and_exit (1);
1078
1079 dyn_string_delete (step2);
1080 }
1081
1082 /*
1083 * Step 3. Call GCC/LD to again, adding the exp file this time.
1084 * driver command line will look like the following:
1085 *
1086 * % gcc -Wl,--dll --Wl,--base-file,foo.base foo.exp [rest ...]
1087 */
1088
1089 {
1090 int quote;
1091
1092 dyn_string_t step3 = dyn_string_new (driver_cmdline->length
1093 + strlen (exp_file_name)
1094 + strlen (base_file_name)
1095 + 20);
1096 dyn_string_append_cstr (step3, "-Wl,--base-file,");
1097 quote = (strchr (base_file_name, ' ')
1098 || strchr (base_file_name, '\t'));
1099 dyn_string_append_cstr (step3,
1100 (quote) ? "\"" : "");
1101 dyn_string_append_cstr (step3, base_file_name);
1102 dyn_string_append_cstr (step3,
1103 (quote) ? "\" " : " ");
1104
1105 quote = (strchr (exp_file_name, ' ')
1106 || strchr (exp_file_name, '\t'));
1107 dyn_string_append_cstr (step3,
1108 (quote) ? "\"" : "");
1109 dyn_string_append_cstr (step3, exp_file_name);
1110 dyn_string_append_cstr (step3,
1111 (quote) ? "\"" : "");
1112
1113 if (driver_cmdline->length)
1114 {
1115 dyn_string_append_cstr (step3, " ");
1116 dyn_string_append_cstr (step3, driver_cmdline->s);
1117 }
1118
1119 if (run (driver_name, step3->s))
1120 cleanup_and_exit (1);
1121
1122 dyn_string_delete (step3);
1123 }
1124
1125
1126 /*
1127 * Step 4. Run DLLTOOL again using the same command line.
1128 */
1129
1130 {
1131 int quote;
1132 dyn_string_t step4 = dyn_string_new (dlltool_cmdline->length
1133 + strlen (base_file_name)
1134 + strlen (exp_file_name)
1135 + 20);
1136
1137 dyn_string_append_cstr (step4, "--base-file ");
1138 quote = (strchr (base_file_name, ' ')
1139 || strchr (base_file_name, '\t'));
1140 dyn_string_append_cstr (step4,
1141 (quote) ? "\"" : "");
1142 dyn_string_append_cstr (step4, base_file_name);
1143 dyn_string_append_cstr (step4,
1144 (quote) ? "\" " : " ");
1145
1146 dyn_string_append_cstr (step4, "--output-exp ");
1147 quote = (strchr (exp_file_name, ' ')
1148 || strchr (exp_file_name, '\t'));
1149 dyn_string_append_cstr (step4,
1150 (quote) ? "\"" : "");
1151 dyn_string_append_cstr (step4, exp_file_name);
1152 dyn_string_append_cstr (step4,
1153 (quote) ? "\"" : "");
1154
1155 if (dlltool_cmdline->length)
1156 {
1157 dyn_string_append_cstr (step4, " ");
1158 dyn_string_append_cstr (step4, dlltool_cmdline->s);
1159 }
1160
1161 if (output_lib_file_name)
1162 {
1163 dyn_string_append_cstr (step4, " --output-lib ");
1164 dyn_string_append_cstr (step4, output_lib_file_name);
1165 }
1166
1167 if (run (dlltool_name, step4->s))
1168 cleanup_and_exit (1);
1169
1170 dyn_string_delete (step4);
1171 }
1172
1173
1174 /*
1175 * Step 5. Link it all together and be done with it.
1176 * driver command line will look like the following:
1177 *
1178 * % gcc -Wl,--dll foo.exp [rest ...]
1179 *
1180 */
1181
1182 {
1183 int quote;
1184
1185 dyn_string_t step5 = dyn_string_new (driver_cmdline->length
1186 + strlen (exp_file_name)
1187 + 20);
1188 quote = (strchr (exp_file_name, ' ')
1189 || strchr (exp_file_name, '\t'));
1190 dyn_string_append_cstr (step5,
1191 (quote) ? "\"" : "");
1192 dyn_string_append_cstr (step5, exp_file_name);
1193 dyn_string_append_cstr (step5,
1194 (quote) ? "\"" : "");
1195
1196 if (driver_cmdline->length)
1197 {
1198 dyn_string_append_cstr (step5, " ");
1199 dyn_string_append_cstr (step5, driver_cmdline->s);
1200 }
1201
1202 if (run (driver_name, step5->s))
1203 cleanup_and_exit (1);
1204
1205 dyn_string_delete (step5);
1206 }
1207
1208 cleanup_and_exit (0);
1209
1210 return 0;
1211 }
1212