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