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