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