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