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