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