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