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