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