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