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