160484Sobrien/* dllwrap.c -- wrapper for DLLTOOL and GCC to generate PE style DLLs
2218822Sdim   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007
3218822Sdim   Free Software Foundation, Inc.
460484Sobrien   Contributed by Mumit Khan (khan@xraylith.wisc.edu).
560484Sobrien
660484Sobrien   This file is part of GNU Binutils.
760484Sobrien
860484Sobrien   This program is free software; you can redistribute it and/or modify
960484Sobrien   it under the terms of the GNU General Public License as published by
1060484Sobrien   the Free Software Foundation; either version 2 of the License, or
1160484Sobrien   (at your option) any later version.
1260484Sobrien
1360484Sobrien   This program is distributed in the hope that it will be useful,
1460484Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
1560484Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1660484Sobrien   GNU General Public License for more details.
1760484Sobrien
1860484Sobrien   You should have received a copy of the GNU General Public License
1960484Sobrien   along with this program; if not, write to the Free Software
20218822Sdim   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
21218822Sdim   02110-1301, USA.  */
2260484Sobrien
2360484Sobrien/* AIX requires this to be the first thing in the file.  */
2460484Sobrien#ifndef __GNUC__
2560484Sobrien# ifdef _AIX
2660484Sobrien #pragma alloca
2760484Sobrien#endif
2860484Sobrien#endif
2960484Sobrien
30218822Sdim#include "sysdep.h"
3160484Sobrien#include "bfd.h"
3260484Sobrien#include "libiberty.h"
3360484Sobrien#include "getopt.h"
3460484Sobrien#include "dyn-string.h"
35218822Sdim#include "bucomm.h"
3660484Sobrien
3760484Sobrien#include <time.h>
3860484Sobrien#include <sys/stat.h>
3960484Sobrien
4060484Sobrien#ifdef HAVE_SYS_WAIT_H
4160484Sobrien#include <sys/wait.h>
4260484Sobrien#else /* ! HAVE_SYS_WAIT_H */
4360484Sobrien#if ! defined (_WIN32) || defined (__CYGWIN32__)
4460484Sobrien#ifndef WIFEXITED
4560484Sobrien#define WIFEXITED(w)	(((w)&0377) == 0)
4660484Sobrien#endif
4760484Sobrien#ifndef WIFSIGNALED
4860484Sobrien#define WIFSIGNALED(w)	(((w)&0377) != 0177 && ((w)&~0377) == 0)
4960484Sobrien#endif
5060484Sobrien#ifndef WTERMSIG
5160484Sobrien#define WTERMSIG(w)	((w) & 0177)
5260484Sobrien#endif
5360484Sobrien#ifndef WEXITSTATUS
5460484Sobrien#define WEXITSTATUS(w)	(((w) >> 8) & 0377)
5560484Sobrien#endif
5660484Sobrien#else /* defined (_WIN32) && ! defined (__CYGWIN32__) */
5760484Sobrien#ifndef WIFEXITED
5860484Sobrien#define WIFEXITED(w)	(((w) & 0xff) == 0)
5960484Sobrien#endif
6060484Sobrien#ifndef WIFSIGNALED
6160484Sobrien#define WIFSIGNALED(w)	(((w) & 0xff) != 0 && ((w) & 0xff) != 0x7f)
6260484Sobrien#endif
6360484Sobrien#ifndef WTERMSIG
6460484Sobrien#define WTERMSIG(w)	((w) & 0x7f)
6560484Sobrien#endif
6660484Sobrien#ifndef WEXITSTATUS
6760484Sobrien#define WEXITSTATUS(w)	(((w) & 0xff00) >> 8)
6860484Sobrien#endif
6960484Sobrien#endif /* defined (_WIN32) && ! defined (__CYGWIN32__) */
7060484Sobrien#endif /* ! HAVE_SYS_WAIT_H */
7160484Sobrien
7260484Sobrienstatic char *driver_name = NULL;
73104834Sobrienstatic char *cygwin_driver_flags =
7460484Sobrien  "-Wl,--dll -nostartfiles";
7560484Sobrienstatic char *mingw32_driver_flags = "-mdll";
7660484Sobrienstatic char *generic_driver_flags = "-Wl,--dll";
7760484Sobrien
7860484Sobrienstatic char *entry_point;
7960484Sobrien
8060484Sobrienstatic char *dlltool_name = NULL;
8160484Sobrien
8260484Sobrienstatic char *target = TARGET;
8360484Sobrien
8460484Sobrientypedef enum {
85104834Sobrien  UNKNOWN_TARGET,
86104834Sobrien  CYGWIN_TARGET,
8760484Sobrien  MINGW_TARGET
88104834Sobrien}
8960484Sobrientarget_type;
9060484Sobrien
9160484Sobrienstatic target_type which_target = UNKNOWN_TARGET;
9260484Sobrien
9360484Sobrienstatic int dontdeltemps = 0;
9460484Sobrienstatic int dry_run = 0;
9560484Sobrien
96218822Sdimstatic char *prog_name;
9760484Sobrien
9860484Sobrienstatic int verbose = 0;
9960484Sobrien
10060484Sobrienstatic char *dll_file_name;
10160484Sobrienstatic char *dll_name;
10260484Sobrienstatic char *base_file_name;
10360484Sobrienstatic char *exp_file_name;
10460484Sobrienstatic char *def_file_name;
10560484Sobrienstatic int delete_base_file = 1;
10660484Sobrienstatic int delete_exp_file = 1;
10760484Sobrienstatic int delete_def_file = 1;
10860484Sobrien
109130561Sobrienstatic int run (const char *, char *);
110130561Sobrienstatic char *mybasename (const char *);
111130561Sobrienstatic int strhash (const char *);
112130561Sobrienstatic void usage (FILE *, int);
113218822Sdimstatic void display (const char *, va_list) ATTRIBUTE_PRINTF(1,0);
114218822Sdimstatic void inform (const char *, ...) ATTRIBUTE_PRINTF_1;
115218822Sdimstatic void warn (const char *, ...) ATTRIBUTE_PRINTF_1;
116130561Sobrienstatic char *look_for_prog (const char *, const char *, int);
117130561Sobrienstatic char *deduce_name (const char *);
118130561Sobrienstatic void delete_temp_files (void);
119130561Sobrienstatic void cleanup_and_exit (int);
12060484Sobrien
12160484Sobrien/**********************************************************************/
12260484Sobrien
12360484Sobrien/* Please keep the following 4 routines in sync with dlltool.c:
12460484Sobrien     display ()
12560484Sobrien     inform ()
12660484Sobrien     look_for_prog ()
12760484Sobrien     deduce_name ()
12860484Sobrien   It's not worth the hassle to break these out since dllwrap will
12960484Sobrien   (hopefully) soon be retired in favor of `ld --shared.  */
13060484Sobrien
13160484Sobrienstatic void
132130561Sobriendisplay (const char * message, va_list args)
13360484Sobrien{
134218822Sdim  if (prog_name != NULL)
135218822Sdim    fprintf (stderr, "%s: ", prog_name);
13660484Sobrien
13760484Sobrien  vfprintf (stderr, message, args);
13860484Sobrien  fputc ('\n', stderr);
13960484Sobrien}
14060484Sobrien
14160484Sobrien
14260484Sobrienstatic void
14399461Sobrieninform VPARAMS ((const char *message, ...))
14460484Sobrien{
14599461Sobrien  VA_OPEN (args, message);
14699461Sobrien  VA_FIXEDARG (args, const char *, message);
14760484Sobrien
14860484Sobrien  if (!verbose)
14960484Sobrien    return;
15060484Sobrien
15160484Sobrien  display (message, args);
15299461Sobrien
15399461Sobrien  VA_CLOSE (args);
15460484Sobrien}
15560484Sobrien
15660484Sobrienstatic void
15799461Sobrienwarn VPARAMS ((const char *format, ...))
15860484Sobrien{
15999461Sobrien  VA_OPEN (args, format);
16099461Sobrien  VA_FIXEDARG (args, const char *, format);
16160484Sobrien
16260484Sobrien  display (format, args);
16360484Sobrien
16499461Sobrien  VA_CLOSE (args);
16560484Sobrien}
16660484Sobrien
16760484Sobrien/* Look for the program formed by concatenating PROG_NAME and the
16860484Sobrien   string running from PREFIX to END_PREFIX.  If the concatenated
16960484Sobrien   string contains a '/', try appending EXECUTABLE_SUFFIX if it is
17060484Sobrien   appropriate.  */
17160484Sobrien
17260484Sobrienstatic char *
173130561Sobrienlook_for_prog (const char *prog_name, const char *prefix, int end_prefix)
17460484Sobrien{
17560484Sobrien  struct stat s;
17660484Sobrien  char *cmd;
17760484Sobrien
178104834Sobrien  cmd = xmalloc (strlen (prefix)
179104834Sobrien		 + strlen (prog_name)
18060484Sobrien#ifdef HAVE_EXECUTABLE_SUFFIX
181104834Sobrien		 + strlen (EXECUTABLE_SUFFIX)
18260484Sobrien#endif
18360484Sobrien		 + 10);
18460484Sobrien  strcpy (cmd, prefix);
18560484Sobrien
18660484Sobrien  sprintf (cmd + end_prefix, "%s", prog_name);
18760484Sobrien
18860484Sobrien  if (strchr (cmd, '/') != NULL)
18960484Sobrien    {
19060484Sobrien      int found;
19160484Sobrien
19260484Sobrien      found = (stat (cmd, &s) == 0
19360484Sobrien#ifdef HAVE_EXECUTABLE_SUFFIX
194104834Sobrien	       || stat (strcat (cmd, EXECUTABLE_SUFFIX), &s) == 0
19560484Sobrien#endif
19660484Sobrien	       );
19760484Sobrien
19860484Sobrien      if (! found)
199104834Sobrien	{
20060484Sobrien	  /* xgettext:c-format */
20160484Sobrien	  inform (_("Tried file: %s"), cmd);
20260484Sobrien	  free (cmd);
20360484Sobrien	  return NULL;
20460484Sobrien	}
20560484Sobrien    }
20660484Sobrien
20760484Sobrien  /* xgettext:c-format */
20860484Sobrien  inform (_("Using file: %s"), cmd);
20960484Sobrien
21060484Sobrien  return cmd;
21160484Sobrien}
21260484Sobrien
21360484Sobrien/* Deduce the name of the program we are want to invoke.
21460484Sobrien   PROG_NAME is the basic name of the program we want to run,
21560484Sobrien   eg "as" or "ld".  The catch is that we might want actually
216104834Sobrien   run "i386-pe-as" or "ppc-pe-ld".
21760484Sobrien
21860484Sobrien   If argv[0] contains the full path, then try to find the program
21960484Sobrien   in the same place, with and then without a target-like prefix.
22060484Sobrien
22160484Sobrien   Given, argv[0] = /usr/local/bin/i586-cygwin32-dlltool,
222104834Sobrien   deduce_name("as") uses the following search order:
22360484Sobrien
22460484Sobrien     /usr/local/bin/i586-cygwin32-as
22560484Sobrien     /usr/local/bin/as
22660484Sobrien     as
227104834Sobrien
22860484Sobrien   If there's an EXECUTABLE_SUFFIX, it'll use that as well; for each
22960484Sobrien   name, it'll try without and then with EXECUTABLE_SUFFIX.
23060484Sobrien
23160484Sobrien   Given, argv[0] = i586-cygwin32-dlltool, it will not even try "as"
23260484Sobrien   as the fallback, but rather return i586-cygwin32-as.
233104834Sobrien
23460484Sobrien   Oh, and given, argv[0] = dlltool, it'll return "as".
23560484Sobrien
23660484Sobrien   Returns a dynamically allocated string.  */
23760484Sobrien
23860484Sobrienstatic char *
239218822Sdimdeduce_name (const char * name)
24060484Sobrien{
24160484Sobrien  char *cmd;
242218822Sdim  const char *dash;
243218822Sdim  const char *slash;
244218822Sdim  const char *cp;
24560484Sobrien
24660484Sobrien  dash = NULL;
24760484Sobrien  slash = NULL;
248218822Sdim  for (cp = prog_name; *cp != '\0'; ++cp)
24960484Sobrien    {
25060484Sobrien      if (*cp == '-')
25160484Sobrien	dash = cp;
252218822Sdim
25360484Sobrien      if (
25460484Sobrien#if defined(__DJGPP__) || defined (__CYGWIN__) || defined(__WIN32__)
25560484Sobrien	  *cp == ':' || *cp == '\\' ||
25660484Sobrien#endif
25760484Sobrien	  *cp == '/')
25860484Sobrien	{
25960484Sobrien	  slash = cp;
26060484Sobrien	  dash = NULL;
26160484Sobrien	}
26260484Sobrien    }
26360484Sobrien
26460484Sobrien  cmd = NULL;
26560484Sobrien
26660484Sobrien  if (dash != NULL)
267218822Sdim    /* First, try looking for a prefixed NAME in the
268218822Sdim       PROG_NAME directory, with the same prefix as PROG_NAME.  */
269218822Sdim    cmd = look_for_prog (name, prog_name, dash - prog_name + 1);
27060484Sobrien
27160484Sobrien  if (slash != NULL && cmd == NULL)
272218822Sdim    /* Next, try looking for a NAME in the same directory as
273218822Sdim       that of this program.  */
274218822Sdim    cmd = look_for_prog (name, prog_name, slash - prog_name + 1);
27560484Sobrien
27660484Sobrien  if (cmd == NULL)
277218822Sdim    /* Just return NAME as is.  */
278218822Sdim    cmd = xstrdup (name);
27960484Sobrien
28060484Sobrien  return cmd;
28160484Sobrien}
28260484Sobrien
28360484Sobrienstatic void
284130561Sobriendelete_temp_files (void)
28560484Sobrien{
28660484Sobrien  if (delete_base_file && base_file_name)
28760484Sobrien    {
28860484Sobrien      if (verbose)
28960484Sobrien	{
29060484Sobrien	  if (dontdeltemps)
29160484Sobrien	    warn (_("Keeping temporary base file %s"), base_file_name);
29260484Sobrien	  else
29360484Sobrien	    warn (_("Deleting temporary base file %s"), base_file_name);
29460484Sobrien	}
29560484Sobrien      if (! dontdeltemps)
296104834Sobrien	{
297104834Sobrien	  unlink (base_file_name);
29860484Sobrien	  free (base_file_name);
29960484Sobrien	}
30060484Sobrien    }
301104834Sobrien
30260484Sobrien  if (delete_exp_file && exp_file_name)
30360484Sobrien    {
30460484Sobrien      if (verbose)
30560484Sobrien	{
30660484Sobrien	  if (dontdeltemps)
30760484Sobrien	    warn (_("Keeping temporary exp file %s"), exp_file_name);
30860484Sobrien	  else
30960484Sobrien	    warn (_("Deleting temporary exp file %s"), exp_file_name);
31060484Sobrien	}
31160484Sobrien      if (! dontdeltemps)
312104834Sobrien	{
313104834Sobrien	  unlink (exp_file_name);
314104834Sobrien	  free (exp_file_name);
31560484Sobrien	}
31660484Sobrien    }
31760484Sobrien  if (delete_def_file && def_file_name)
31860484Sobrien    {
31960484Sobrien      if (verbose)
32060484Sobrien	{
32160484Sobrien	  if (dontdeltemps)
32260484Sobrien	    warn (_("Keeping temporary def file %s"), def_file_name);
32360484Sobrien	  else
32460484Sobrien	    warn (_("Deleting temporary def file %s"), def_file_name);
32560484Sobrien	}
32660484Sobrien      if (! dontdeltemps)
327104834Sobrien	{
328104834Sobrien	  unlink (def_file_name);
329104834Sobrien	  free (def_file_name);
33060484Sobrien	}
33160484Sobrien    }
33260484Sobrien}
33360484Sobrien
334104834Sobrienstatic void
335130561Sobriencleanup_and_exit (int status)
33660484Sobrien{
33760484Sobrien  delete_temp_files ();
33860484Sobrien  exit (status);
33960484Sobrien}
340104834Sobrien
34160484Sobrienstatic int
342130561Sobrienrun (const char *what, char *args)
34360484Sobrien{
34460484Sobrien  char *s;
34560484Sobrien  int pid, wait_status, retcode;
34660484Sobrien  int i;
34760484Sobrien  const char **argv;
34860484Sobrien  char *errmsg_fmt, *errmsg_arg;
34960484Sobrien  char *temp_base = choose_temp_base ();
35060484Sobrien  int in_quote;
35160484Sobrien  char sep;
35260484Sobrien
35360484Sobrien  if (verbose || dry_run)
35460484Sobrien    fprintf (stderr, "%s %s\n", what, args);
35560484Sobrien
35660484Sobrien  /* Count the args */
35760484Sobrien  i = 0;
35860484Sobrien  for (s = args; *s; s++)
35960484Sobrien    if (*s == ' ')
36060484Sobrien      i++;
36160484Sobrien  i++;
36260484Sobrien  argv = alloca (sizeof (char *) * (i + 3));
36360484Sobrien  i = 0;
36460484Sobrien  argv[i++] = what;
36560484Sobrien  s = args;
36660484Sobrien  while (1)
36760484Sobrien    {
36860484Sobrien      while (*s == ' ' && *s != 0)
36960484Sobrien	s++;
37060484Sobrien      if (*s == 0)
37160484Sobrien	break;
37260484Sobrien      in_quote = (*s == '\'' || *s == '"');
37360484Sobrien      sep = (in_quote) ? *s++ : ' ';
37460484Sobrien      argv[i++] = s;
37560484Sobrien      while (*s != sep && *s != 0)
37660484Sobrien	s++;
37760484Sobrien      if (*s == 0)
37860484Sobrien	break;
37960484Sobrien      *s++ = 0;
38060484Sobrien      if (in_quote)
381104834Sobrien	s++;
38260484Sobrien    }
38360484Sobrien  argv[i++] = NULL;
38460484Sobrien
38560484Sobrien  if (dry_run)
38660484Sobrien    return 0;
38760484Sobrien
388218822Sdim  pid = pexecute (argv[0], (char * const *) argv, prog_name, temp_base,
38960484Sobrien		  &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
39060484Sobrien
39160484Sobrien  if (pid == -1)
39260484Sobrien    {
39360484Sobrien      int errno_val = errno;
39460484Sobrien
395218822Sdim      fprintf (stderr, "%s: ", prog_name);
39660484Sobrien      fprintf (stderr, errmsg_fmt, errmsg_arg);
39760484Sobrien      fprintf (stderr, ": %s\n", strerror (errno_val));
39860484Sobrien      return 1;
39960484Sobrien    }
40060484Sobrien
40160484Sobrien  retcode = 0;
40260484Sobrien  pid = pwait (pid, &wait_status, 0);
40360484Sobrien  if (pid == -1)
40460484Sobrien    {
40560484Sobrien      warn ("wait: %s", strerror (errno));
40660484Sobrien      retcode = 1;
40760484Sobrien    }
40860484Sobrien  else if (WIFSIGNALED (wait_status))
40960484Sobrien    {
41060484Sobrien      warn (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
41160484Sobrien      retcode = 1;
41260484Sobrien    }
41360484Sobrien  else if (WIFEXITED (wait_status))
41460484Sobrien    {
41560484Sobrien      if (WEXITSTATUS (wait_status) != 0)
41660484Sobrien	{
41760484Sobrien	  warn (_("%s exited with status %d"), what, WEXITSTATUS (wait_status));
41860484Sobrien	  retcode = 1;
41960484Sobrien	}
42060484Sobrien    }
42160484Sobrien  else
42260484Sobrien    retcode = 1;
423104834Sobrien
42460484Sobrien  return retcode;
42560484Sobrien}
42660484Sobrien
42760484Sobrienstatic char *
428130561Sobrienmybasename (const char *name)
42960484Sobrien{
43060484Sobrien  const char *base = name;
43160484Sobrien
43260484Sobrien  while (*name)
43360484Sobrien    {
43460484Sobrien      if (*name == '/' || *name == '\\')
43560484Sobrien	{
43660484Sobrien	  base = name + 1;
43760484Sobrien	}
43860484Sobrien      ++name;
43960484Sobrien    }
44060484Sobrien  return (char *) base;
44160484Sobrien}
44260484Sobrien
443104834Sobrienstatic int
444130561Sobrienstrhash (const char *str)
44560484Sobrien{
44660484Sobrien  const unsigned char *s;
44760484Sobrien  unsigned long hash;
44860484Sobrien  unsigned int c;
44960484Sobrien  unsigned int len;
45060484Sobrien
45160484Sobrien  hash = 0;
45260484Sobrien  len = 0;
45360484Sobrien  s = (const unsigned char *) str;
45460484Sobrien  while ((c = *s++) != '\0')
45560484Sobrien    {
45660484Sobrien      hash += c + (c << 17);
45760484Sobrien      hash ^= hash >> 2;
45860484Sobrien      ++len;
45960484Sobrien    }
46060484Sobrien  hash += len + (len << 17);
46160484Sobrien  hash ^= hash >> 2;
46260484Sobrien
46360484Sobrien  return hash;
46460484Sobrien}
46560484Sobrien
46660484Sobrien/**********************************************************************/
46760484Sobrien
46860484Sobrienstatic void
469130561Sobrienusage (FILE *file, int status)
47060484Sobrien{
471218822Sdim  fprintf (file, _("Usage %s <option(s)> <object-file(s)>\n"), prog_name);
47260484Sobrien  fprintf (file, _("  Generic options:\n"));
473218822Sdim  fprintf (file, _("   @<file>                Read options from <file>\n"));
47460484Sobrien  fprintf (file, _("   --quiet, -q            Work quietly\n"));
47560484Sobrien  fprintf (file, _("   --verbose, -v          Verbose\n"));
47660484Sobrien  fprintf (file, _("   --version              Print dllwrap version\n"));
47760484Sobrien  fprintf (file, _("   --implib <outname>     Synonym for --output-lib\n"));
478218822Sdim  fprintf (file, _("  Options for %s:\n"), prog_name);
47960484Sobrien  fprintf (file, _("   --driver-name <driver> Defaults to \"gcc\"\n"));
48060484Sobrien  fprintf (file, _("   --driver-flags <flags> Override default ld flags\n"));
48160484Sobrien  fprintf (file, _("   --dlltool-name <dlltool> Defaults to \"dlltool\"\n"));
48260484Sobrien  fprintf (file, _("   --entry <entry>        Specify alternate DLL entry point\n"));
48360484Sobrien  fprintf (file, _("   --image-base <base>    Specify image base address\n"));
48460484Sobrien  fprintf (file, _("   --target <machine>     i386-cygwin32 or i386-mingw32\n"));
48560484Sobrien  fprintf (file, _("   --dry-run              Show what needs to be run\n"));
48660484Sobrien  fprintf (file, _("   --mno-cygwin           Create Mingw DLL\n"));
48760484Sobrien  fprintf (file, _("  Options passed to DLLTOOL:\n"));
48860484Sobrien  fprintf (file, _("   --machine <machine>\n"));
48960484Sobrien  fprintf (file, _("   --output-exp <outname> Generate export file.\n"));
49060484Sobrien  fprintf (file, _("   --output-lib <outname> Generate input library.\n"));
49160484Sobrien  fprintf (file, _("   --add-indirect         Add dll indirects to export file.\n"));
49260484Sobrien  fprintf (file, _("   --dllname <name>       Name of input dll to put into output lib.\n"));
49360484Sobrien  fprintf (file, _("   --def <deffile>        Name input .def file\n"));
49460484Sobrien  fprintf (file, _("   --output-def <deffile> Name output .def file\n"));
49560484Sobrien  fprintf (file, _("   --export-all-symbols     Export all symbols to .def\n"));
49660484Sobrien  fprintf (file, _("   --no-export-all-symbols  Only export .drectve symbols\n"));
49760484Sobrien  fprintf (file, _("   --exclude-symbols <list> Exclude <list> from .def\n"));
49860484Sobrien  fprintf (file, _("   --no-default-excludes    Zap default exclude symbols\n"));
49960484Sobrien  fprintf (file, _("   --base-file <basefile> Read linker generated base file\n"));
50060484Sobrien  fprintf (file, _("   --no-idata4           Don't generate idata$4 section\n"));
50160484Sobrien  fprintf (file, _("   --no-idata5           Don't generate idata$5 section\n"));
50260484Sobrien  fprintf (file, _("   -U                     Add underscores to .lib\n"));
50360484Sobrien  fprintf (file, _("   -k                     Kill @<n> from exported names\n"));
50460484Sobrien  fprintf (file, _("   --add-stdcall-alias    Add aliases without @<n>\n"));
50560484Sobrien  fprintf (file, _("   --as <name>            Use <name> for assembler\n"));
50660484Sobrien  fprintf (file, _("   --nodelete             Keep temp files.\n"));
50760484Sobrien  fprintf (file, _("  Rest are passed unmodified to the language driver\n"));
50860484Sobrien  fprintf (file, "\n\n");
509218822Sdim  if (REPORT_BUGS_TO[0] && status == 0)
510218822Sdim    fprintf (file, _("Report bugs to %s\n"), REPORT_BUGS_TO);
51160484Sobrien  exit (status);
51260484Sobrien}
51360484Sobrien
51460484Sobrien#define OPTION_START		149
51560484Sobrien
516104834Sobrien/* GENERIC options.  */
51760484Sobrien#define OPTION_QUIET		(OPTION_START + 1)
51860484Sobrien#define OPTION_VERBOSE		(OPTION_QUIET + 1)
51960484Sobrien#define OPTION_VERSION		(OPTION_VERBOSE + 1)
52060484Sobrien
521104834Sobrien/* DLLWRAP options.  */
52260484Sobrien#define OPTION_DRY_RUN		(OPTION_VERSION + 1)
52360484Sobrien#define OPTION_DRIVER_NAME	(OPTION_DRY_RUN + 1)
52460484Sobrien#define OPTION_DRIVER_FLAGS	(OPTION_DRIVER_NAME + 1)
52560484Sobrien#define OPTION_DLLTOOL_NAME	(OPTION_DRIVER_FLAGS + 1)
52660484Sobrien#define OPTION_ENTRY		(OPTION_DLLTOOL_NAME + 1)
52760484Sobrien#define OPTION_IMAGE_BASE	(OPTION_ENTRY + 1)
52860484Sobrien#define OPTION_TARGET		(OPTION_IMAGE_BASE + 1)
52960484Sobrien#define OPTION_MNO_CYGWIN	(OPTION_TARGET + 1)
53060484Sobrien
531104834Sobrien/* DLLTOOL options.  */
53260484Sobrien#define OPTION_NODELETE		(OPTION_MNO_CYGWIN + 1)
53360484Sobrien#define OPTION_DLLNAME		(OPTION_NODELETE + 1)
534130561Sobrien#define OPTION_NO_IDATA4	(OPTION_DLLNAME + 1)
53560484Sobrien#define OPTION_NO_IDATA5	(OPTION_NO_IDATA4 + 1)
53660484Sobrien#define OPTION_OUTPUT_EXP	(OPTION_NO_IDATA5 + 1)
53760484Sobrien#define OPTION_OUTPUT_DEF	(OPTION_OUTPUT_EXP + 1)
53860484Sobrien#define OPTION_EXPORT_ALL_SYMS	(OPTION_OUTPUT_DEF + 1)
53960484Sobrien#define OPTION_NO_EXPORT_ALL_SYMS (OPTION_EXPORT_ALL_SYMS + 1)
54060484Sobrien#define OPTION_EXCLUDE_SYMS	(OPTION_NO_EXPORT_ALL_SYMS + 1)
54160484Sobrien#define OPTION_NO_DEFAULT_EXCLUDES (OPTION_EXCLUDE_SYMS + 1)
54260484Sobrien#define OPTION_OUTPUT_LIB	(OPTION_NO_DEFAULT_EXCLUDES + 1)
54360484Sobrien#define OPTION_DEF		(OPTION_OUTPUT_LIB + 1)
54460484Sobrien#define OPTION_ADD_UNDERSCORE	(OPTION_DEF + 1)
54560484Sobrien#define OPTION_KILLAT		(OPTION_ADD_UNDERSCORE + 1)
54660484Sobrien#define OPTION_HELP		(OPTION_KILLAT + 1)
54760484Sobrien#define OPTION_MACHINE		(OPTION_HELP + 1)
54860484Sobrien#define OPTION_ADD_INDIRECT	(OPTION_MACHINE + 1)
54960484Sobrien#define OPTION_BASE_FILE	(OPTION_ADD_INDIRECT + 1)
55060484Sobrien#define OPTION_AS		(OPTION_BASE_FILE + 1)
55160484Sobrien
55260484Sobrienstatic const struct option long_options[] =
55360484Sobrien{
554104834Sobrien  /* generic options.  */
55560484Sobrien  {"quiet", no_argument, NULL, 'q'},
55660484Sobrien  {"verbose", no_argument, NULL, 'v'},
55760484Sobrien  {"version", no_argument, NULL, OPTION_VERSION},
55860484Sobrien  {"implib", required_argument, NULL, OPTION_OUTPUT_LIB},
55960484Sobrien
560104834Sobrien  /* dllwrap options.  */
56160484Sobrien  {"dry-run", no_argument, NULL, OPTION_DRY_RUN},
56260484Sobrien  {"driver-name", required_argument, NULL, OPTION_DRIVER_NAME},
56360484Sobrien  {"driver-flags", required_argument, NULL, OPTION_DRIVER_FLAGS},
56460484Sobrien  {"dlltool-name", required_argument, NULL, OPTION_DLLTOOL_NAME},
56560484Sobrien  {"entry", required_argument, NULL, 'e'},
56660484Sobrien  {"image-base", required_argument, NULL, OPTION_IMAGE_BASE},
56760484Sobrien  {"target", required_argument, NULL, OPTION_TARGET},
56860484Sobrien
569104834Sobrien  /* dlltool options.  */
57060484Sobrien  {"no-delete", no_argument, NULL, 'n'},
57160484Sobrien  {"dllname", required_argument, NULL, OPTION_DLLNAME},
57260484Sobrien  {"no-idata4", no_argument, NULL, OPTION_NO_IDATA4},
57360484Sobrien  {"no-idata5", no_argument, NULL, OPTION_NO_IDATA5},
57460484Sobrien  {"output-exp", required_argument, NULL, OPTION_OUTPUT_EXP},
57560484Sobrien  {"output-def", required_argument, NULL, OPTION_OUTPUT_DEF},
57660484Sobrien  {"export-all-symbols", no_argument, NULL, OPTION_EXPORT_ALL_SYMS},
57760484Sobrien  {"no-export-all-symbols", no_argument, NULL, OPTION_NO_EXPORT_ALL_SYMS},
57860484Sobrien  {"exclude-symbols", required_argument, NULL, OPTION_EXCLUDE_SYMS},
57960484Sobrien  {"no-default-excludes", no_argument, NULL, OPTION_NO_DEFAULT_EXCLUDES},
58060484Sobrien  {"output-lib", required_argument, NULL, OPTION_OUTPUT_LIB},
58160484Sobrien  {"def", required_argument, NULL, OPTION_DEF},
58260484Sobrien  {"add-underscore", no_argument, NULL, 'U'},
58360484Sobrien  {"killat", no_argument, NULL, 'k'},
58460484Sobrien  {"add-stdcall-alias", no_argument, NULL, 'A'},
58560484Sobrien  {"help", no_argument, NULL, 'h'},
58660484Sobrien  {"machine", required_argument, NULL, OPTION_MACHINE},
58760484Sobrien  {"add-indirect", no_argument, NULL, OPTION_ADD_INDIRECT},
58860484Sobrien  {"base-file", required_argument, NULL, OPTION_BASE_FILE},
58960484Sobrien  {"as", required_argument, NULL, OPTION_AS},
59060484Sobrien  {0, 0, 0, 0}
59160484Sobrien};
59260484Sobrien
593130561Sobrienint main (int, char **);
59499461Sobrien
59560484Sobrienint
596130561Sobrienmain (int argc, char **argv)
59760484Sobrien{
59860484Sobrien  int c;
59960484Sobrien  int i;
60060484Sobrien
60160484Sobrien  char **saved_argv = 0;
60260484Sobrien  int cmdline_len = 0;
60360484Sobrien
60460484Sobrien  int export_all = 0;
60560484Sobrien
60660484Sobrien  int *dlltool_arg_indices;
60760484Sobrien  int *driver_arg_indices;
60860484Sobrien
60960484Sobrien  char *driver_flags = 0;
61060484Sobrien  char *output_lib_file_name = 0;
61160484Sobrien
61260484Sobrien  dyn_string_t dlltool_cmdline;
61360484Sobrien  dyn_string_t driver_cmdline;
61460484Sobrien
61560484Sobrien  int def_file_seen = 0;
61660484Sobrien
61760484Sobrien  char *image_base_str = 0;
61860484Sobrien
619218822Sdim  prog_name = argv[0];
62060484Sobrien
62189857Sobrien#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
62289857Sobrien  setlocale (LC_MESSAGES, "");
62389857Sobrien#endif
62489857Sobrien#if defined (HAVE_SETLOCALE)
62589857Sobrien  setlocale (LC_CTYPE, "");
62689857Sobrien#endif
62789857Sobrien  bindtextdomain (PACKAGE, LOCALEDIR);
62889857Sobrien  textdomain (PACKAGE);
62989857Sobrien
630218822Sdim  expandargv (&argc, &argv);
631218822Sdim
63260484Sobrien  saved_argv = (char **) xmalloc (argc * sizeof (char*));
63360484Sobrien  dlltool_arg_indices = (int *) xmalloc (argc * sizeof (int));
63460484Sobrien  driver_arg_indices = (int *) xmalloc (argc * sizeof (int));
635104834Sobrien  for (i = 0; i < argc; ++i)
63660484Sobrien    {
63760484Sobrien      size_t len = strlen (argv[i]);
63860484Sobrien      char *arg = (char *) xmalloc (len + 1);
63960484Sobrien      strcpy (arg, argv[i]);
64060484Sobrien      cmdline_len += len;
64160484Sobrien      saved_argv[i] = arg;
64260484Sobrien      dlltool_arg_indices[i] = 0;
64360484Sobrien      driver_arg_indices[i] = 1;
64460484Sobrien    }
64560484Sobrien  cmdline_len++;
64660484Sobrien
64760484Sobrien  /* We recognize dllwrap and dlltool options, and everything else is
64860484Sobrien     passed onto the language driver (eg., to GCC). We collect options
649104834Sobrien     to dlltool and driver in dlltool_args and driver_args.  */
650104834Sobrien
65160484Sobrien  opterr = 0;
652104834Sobrien  while ((c = getopt_long_only (argc, argv, "nkAqve:Uho:l:L:I:",
653104834Sobrien				long_options, (int *) 0)) != EOF)
65460484Sobrien    {
65560484Sobrien      int dlltool_arg;
65660484Sobrien      int driver_arg;
65760484Sobrien      int single_word_option_value_pair;
65860484Sobrien
65960484Sobrien      dlltool_arg = 0;
66060484Sobrien      driver_arg = 1;
66160484Sobrien      single_word_option_value_pair = 0;
66260484Sobrien
66360484Sobrien      if (c != '?')
664104834Sobrien	{
66560484Sobrien	  /* We recognize this option, so it has to be either dllwrap or
66660484Sobrien	     dlltool option. Do not pass to driver unless it's one of the
66760484Sobrien	     generic options that are passed to all the tools (such as -v)
668104834Sobrien	     which are dealt with later.  */
66960484Sobrien	  driver_arg = 0;
67060484Sobrien	}
67160484Sobrien
672104834Sobrien      /* deal with generic and dllwrap options first.  */
67360484Sobrien      switch (c)
67460484Sobrien	{
67560484Sobrien	case 'h':
67660484Sobrien	  usage (stdout, 0);
67760484Sobrien	  break;
67860484Sobrien	case 'q':
67960484Sobrien	  verbose = 0;
68060484Sobrien	  break;
68160484Sobrien	case 'v':
68260484Sobrien	  verbose = 1;
68360484Sobrien	  break;
68460484Sobrien	case OPTION_VERSION:
685218822Sdim	  print_version (prog_name);
68660484Sobrien	  break;
68760484Sobrien	case 'e':
68860484Sobrien	  entry_point = optarg;
68960484Sobrien	  break;
69060484Sobrien	case OPTION_IMAGE_BASE:
69160484Sobrien	  image_base_str = optarg;
69260484Sobrien	  break;
69360484Sobrien	case OPTION_DEF:
69460484Sobrien	  def_file_name = optarg;
69560484Sobrien	  def_file_seen = 1;
69660484Sobrien	  delete_def_file = 0;
69760484Sobrien	  break;
69860484Sobrien	case 'n':
69960484Sobrien	  dontdeltemps = 1;
70060484Sobrien	  dlltool_arg = 1;
70160484Sobrien	  break;
70260484Sobrien	case 'o':
70360484Sobrien	  dll_file_name = optarg;
70460484Sobrien	  break;
70560484Sobrien	case 'I':
70660484Sobrien	case 'l':
70760484Sobrien	case 'L':
70860484Sobrien	  driver_arg = 1;
70960484Sobrien	  break;
71060484Sobrien	case OPTION_DLLNAME:
71160484Sobrien	  dll_name = optarg;
71260484Sobrien	  break;
71360484Sobrien	case OPTION_DRY_RUN:
71460484Sobrien	  dry_run = 1;
71560484Sobrien	  break;
71660484Sobrien	case OPTION_DRIVER_NAME:
71760484Sobrien	  driver_name = optarg;
71860484Sobrien	  break;
71960484Sobrien	case OPTION_DRIVER_FLAGS:
72060484Sobrien	  driver_flags = optarg;
72160484Sobrien	  break;
72260484Sobrien	case OPTION_DLLTOOL_NAME:
72360484Sobrien	  dlltool_name = optarg;
72460484Sobrien	  break;
72560484Sobrien	case OPTION_TARGET:
72660484Sobrien	  target = optarg;
72760484Sobrien	  break;
72860484Sobrien	case OPTION_MNO_CYGWIN:
72960484Sobrien	  target = "i386-mingw32";
73060484Sobrien	  break;
73160484Sobrien	case OPTION_BASE_FILE:
73260484Sobrien	  base_file_name = optarg;
73360484Sobrien	  delete_base_file = 0;
73460484Sobrien	  break;
73560484Sobrien	case OPTION_OUTPUT_EXP:
73660484Sobrien	  exp_file_name = optarg;
73760484Sobrien	  delete_exp_file = 0;
73860484Sobrien	  break;
73960484Sobrien	case OPTION_EXPORT_ALL_SYMS:
74060484Sobrien	  export_all = 1;
74160484Sobrien	  break;
74260484Sobrien	case OPTION_OUTPUT_LIB:
74360484Sobrien	  output_lib_file_name = optarg;
74460484Sobrien	  break;
74560484Sobrien	case '?':
74660484Sobrien	  break;
74760484Sobrien	default:
74860484Sobrien	  dlltool_arg = 1;
74960484Sobrien	  break;
75060484Sobrien	}
751104834Sobrien
752104834Sobrien      /* Handle passing through --option=value case.  */
753104834Sobrien      if (optarg
754104834Sobrien	  && saved_argv[optind-1][0] == '-'
755104834Sobrien	  && saved_argv[optind-1][1] == '-'
75660484Sobrien	  && strchr (saved_argv[optind-1], '='))
75760484Sobrien	single_word_option_value_pair = 1;
75860484Sobrien
75960484Sobrien      if (dlltool_arg)
760104834Sobrien	{
76160484Sobrien	  dlltool_arg_indices[optind-1] = 1;
76260484Sobrien	  if (optarg && ! single_word_option_value_pair)
76360484Sobrien	    {
76460484Sobrien	      dlltool_arg_indices[optind-2] = 1;
765104834Sobrien	    }
76660484Sobrien	}
76760484Sobrien
76860484Sobrien      if (! driver_arg)
769104834Sobrien	{
77060484Sobrien	  driver_arg_indices[optind-1] = 0;
77160484Sobrien	  if (optarg && ! single_word_option_value_pair)
77260484Sobrien	    {
77360484Sobrien	      driver_arg_indices[optind-2] = 0;
774104834Sobrien	    }
77560484Sobrien	}
77660484Sobrien    }
77760484Sobrien
778218822Sdim  /* Sanity checks.  */
77960484Sobrien  if (! dll_name && ! dll_file_name)
78060484Sobrien    {
78160484Sobrien      warn (_("Must provide at least one of -o or --dllname options"));
78260484Sobrien      exit (1);
78360484Sobrien    }
78460484Sobrien  else if (! dll_name)
78560484Sobrien    {
78660484Sobrien      dll_name = xstrdup (mybasename (dll_file_name));
78760484Sobrien    }
78860484Sobrien  else if (! dll_file_name)
78960484Sobrien    {
79060484Sobrien      dll_file_name = xstrdup (dll_name);
79160484Sobrien    }
79260484Sobrien
793104834Sobrien  /* Deduce driver-name and dlltool-name from our own.  */
79460484Sobrien  if (driver_name == NULL)
79560484Sobrien    driver_name = deduce_name ("gcc");
79660484Sobrien
79760484Sobrien  if (dlltool_name == NULL)
79860484Sobrien    dlltool_name = deduce_name ("dlltool");
79960484Sobrien
80060484Sobrien  if (! def_file_seen)
80160484Sobrien    {
80260484Sobrien      char *fileprefix = choose_temp_base ();
803218822Sdim
80460484Sobrien      def_file_name = (char *) xmalloc (strlen (fileprefix) + 5);
805104834Sobrien      sprintf (def_file_name, "%s.def",
806104834Sobrien	       (dontdeltemps) ? mybasename (fileprefix) : fileprefix);
80760484Sobrien      delete_def_file = 1;
80860484Sobrien      free (fileprefix);
80960484Sobrien      delete_def_file = 1;
81089857Sobrien      warn (_("no export definition file provided.\n\
81189857SobrienCreating one, but that may not be what you want"));
81260484Sobrien    }
813104834Sobrien
814218822Sdim  /* Set the target platform.  */
81560484Sobrien  if (strstr (target, "cygwin"))
81660484Sobrien    which_target = CYGWIN_TARGET;
81760484Sobrien  else if (strstr (target, "mingw"))
81860484Sobrien    which_target = MINGW_TARGET;
819104834Sobrien  else
82060484Sobrien    which_target = UNKNOWN_TARGET;
82160484Sobrien
822218822Sdim  /* Re-create the command lines as a string, taking care to quote stuff.  */
82360484Sobrien  dlltool_cmdline = dyn_string_new (cmdline_len);
82460484Sobrien  if (verbose)
825218822Sdim    dyn_string_append_cstr (dlltool_cmdline, " -v");
826218822Sdim
82777298Sobrien  dyn_string_append_cstr (dlltool_cmdline, " --dllname ");
82877298Sobrien  dyn_string_append_cstr (dlltool_cmdline, dll_name);
82960484Sobrien
83060484Sobrien  for (i = 1; i < argc; ++i)
83160484Sobrien    {
83260484Sobrien      if (dlltool_arg_indices[i])
833104834Sobrien	{
83460484Sobrien	  char *arg = saved_argv[i];
835104834Sobrien	  int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
836104834Sobrien	  dyn_string_append_cstr (dlltool_cmdline,
83760484Sobrien	                     (quote) ? " \"" : " ");
83877298Sobrien	  dyn_string_append_cstr (dlltool_cmdline, arg);
839104834Sobrien	  dyn_string_append_cstr (dlltool_cmdline,
84060484Sobrien	                     (quote) ? "\"" : "");
84160484Sobrien	}
84260484Sobrien    }
84360484Sobrien
84460484Sobrien  driver_cmdline = dyn_string_new (cmdline_len);
84560484Sobrien  if (! driver_flags || strlen (driver_flags) == 0)
84660484Sobrien    {
84760484Sobrien      switch (which_target)
848104834Sobrien	{
84960484Sobrien	case CYGWIN_TARGET:
850104834Sobrien	  driver_flags = cygwin_driver_flags;
85160484Sobrien	  break;
852104834Sobrien
85360484Sobrien	case MINGW_TARGET:
854104834Sobrien	  driver_flags = mingw32_driver_flags;
85560484Sobrien	  break;
856104834Sobrien
85760484Sobrien	default:
858104834Sobrien	  driver_flags = generic_driver_flags;
85960484Sobrien	  break;
86060484Sobrien	}
86160484Sobrien    }
86277298Sobrien  dyn_string_append_cstr (driver_cmdline, driver_flags);
86377298Sobrien  dyn_string_append_cstr (driver_cmdline, " -o ");
86477298Sobrien  dyn_string_append_cstr (driver_cmdline, dll_file_name);
86560484Sobrien
86660484Sobrien  if (! entry_point || strlen (entry_point) == 0)
86760484Sobrien    {
86860484Sobrien      switch (which_target)
869104834Sobrien	{
87060484Sobrien	case CYGWIN_TARGET:
87160484Sobrien	  entry_point = "__cygwin_dll_entry@12";
87260484Sobrien	  break;
873104834Sobrien
87460484Sobrien	case MINGW_TARGET:
87560484Sobrien	  entry_point = "_DllMainCRTStartup@12";
87660484Sobrien	  break;
877104834Sobrien
87860484Sobrien	default:
879104834Sobrien	  entry_point = "_DllMain@12";
88060484Sobrien	  break;
88160484Sobrien	}
88260484Sobrien    }
88377298Sobrien  dyn_string_append_cstr (driver_cmdline, " -Wl,-e,");
88477298Sobrien  dyn_string_append_cstr (driver_cmdline, entry_point);
88577298Sobrien  dyn_string_append_cstr (dlltool_cmdline, " --exclude-symbol=");
886104834Sobrien  dyn_string_append_cstr (dlltool_cmdline,
887104834Sobrien                    (entry_point[0] == '_') ? entry_point+1 : entry_point);
88860484Sobrien
88960484Sobrien  if (! image_base_str || strlen (image_base_str) == 0)
89060484Sobrien    {
89160484Sobrien      char *tmpbuf = (char *) xmalloc (sizeof ("0x12345678") + 1);
89260484Sobrien      unsigned long hash = strhash (dll_file_name);
89360484Sobrien      sprintf (tmpbuf, "0x%.8lX", 0x60000000|((hash<<16)&0xFFC0000));
89460484Sobrien      image_base_str = tmpbuf;
89560484Sobrien    }
89660484Sobrien
89777298Sobrien  dyn_string_append_cstr (driver_cmdline, " -Wl,--image-base,");
89877298Sobrien  dyn_string_append_cstr (driver_cmdline, image_base_str);
89960484Sobrien
90060484Sobrien  if (verbose)
90160484Sobrien    {
90277298Sobrien      dyn_string_append_cstr (driver_cmdline, " -v");
90360484Sobrien    }
90460484Sobrien
90560484Sobrien  for (i = 1; i < argc; ++i)
90660484Sobrien    {
90760484Sobrien      if (driver_arg_indices[i])
908104834Sobrien	{
90960484Sobrien	  char *arg = saved_argv[i];
910104834Sobrien	  int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
911104834Sobrien	  dyn_string_append_cstr (driver_cmdline,
91260484Sobrien	                     (quote) ? " \"" : " ");
91377298Sobrien	  dyn_string_append_cstr (driver_cmdline, arg);
914104834Sobrien	  dyn_string_append_cstr (driver_cmdline,
91560484Sobrien	                     (quote) ? "\"" : "");
91660484Sobrien	}
91760484Sobrien    }
918104834Sobrien
919218822Sdim  /* Step pre-1. If no --def <EXPORT_DEF> is specified,
920218822Sdim     then create it and then pass it on.  */
921104834Sobrien
922104834Sobrien  if (! def_file_seen)
92360484Sobrien    {
92460484Sobrien      int i;
92560484Sobrien      dyn_string_t step_pre1;
92660484Sobrien
92760484Sobrien      step_pre1 = dyn_string_new (1024);
92860484Sobrien
92977298Sobrien      dyn_string_append_cstr (step_pre1, dlltool_cmdline->s);
93060484Sobrien      if (export_all)
93160484Sobrien	{
932104834Sobrien	  dyn_string_append_cstr (step_pre1, " --export-all --exclude-symbol=");
933104834Sobrien	  dyn_string_append_cstr (step_pre1,
93460484Sobrien	  "_cygwin_dll_entry@12,DllMainCRTStartup@12,DllMain@12,DllEntryPoint@12");
93560484Sobrien	}
93677298Sobrien      dyn_string_append_cstr (step_pre1, " --output-def ");
93777298Sobrien      dyn_string_append_cstr (step_pre1, def_file_name);
93860484Sobrien
93960484Sobrien      for (i = 1; i < argc; ++i)
94060484Sobrien	{
94160484Sobrien	  if (driver_arg_indices[i])
94260484Sobrien	    {
94360484Sobrien	      char *arg = saved_argv[i];
94460484Sobrien	      size_t len = strlen (arg);
945104834Sobrien	      if (len >= 2 && arg[len-2] == '.'
94660484Sobrien	          && (arg[len-1] == 'o' || arg[len-1] == 'a'))
94760484Sobrien		{
94860484Sobrien		  int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
94977298Sobrien		  dyn_string_append_cstr (step_pre1,
95060484Sobrien				     (quote) ? " \"" : " ");
95177298Sobrien		  dyn_string_append_cstr (step_pre1, arg);
95277298Sobrien		  dyn_string_append_cstr (step_pre1,
95360484Sobrien				     (quote) ? "\"" : "");
95460484Sobrien		}
95560484Sobrien	    }
95660484Sobrien	}
95760484Sobrien
95860484Sobrien      if (run (dlltool_name, step_pre1->s))
95960484Sobrien	cleanup_and_exit (1);
960104834Sobrien
96160484Sobrien      dyn_string_delete (step_pre1);
96260484Sobrien    }
96360484Sobrien
96477298Sobrien  dyn_string_append_cstr (dlltool_cmdline, " --def ");
96577298Sobrien  dyn_string_append_cstr (dlltool_cmdline, def_file_name);
96660484Sobrien
96760484Sobrien  if (verbose)
96860484Sobrien    {
96960484Sobrien      fprintf (stderr, _("DLLTOOL name    : %s\n"), dlltool_name);
97060484Sobrien      fprintf (stderr, _("DLLTOOL options : %s\n"), dlltool_cmdline->s);
97160484Sobrien      fprintf (stderr, _("DRIVER name     : %s\n"), driver_name);
97260484Sobrien      fprintf (stderr, _("DRIVER options  : %s\n"), driver_cmdline->s);
97360484Sobrien    }
974104834Sobrien
975218822Sdim  /* Step 1. Call GCC/LD to create base relocation file. If using GCC, the
976218822Sdim     driver command line will look like the following:
977218822Sdim
978218822Sdim        % gcc -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
979218822Sdim
980218822Sdim     If the user does not specify a base name, create temporary one that
981218822Sdim     is deleted at exit.  */
982104834Sobrien
98360484Sobrien  if (! base_file_name)
98460484Sobrien    {
98560484Sobrien      char *fileprefix = choose_temp_base ();
98660484Sobrien      base_file_name = (char *) xmalloc (strlen (fileprefix) + 6);
987104834Sobrien      sprintf (base_file_name, "%s.base",
988104834Sobrien	       (dontdeltemps) ? mybasename (fileprefix) : fileprefix);
98960484Sobrien      delete_base_file = 1;
99060484Sobrien      free (fileprefix);
99160484Sobrien    }
992104834Sobrien
99360484Sobrien  {
99460484Sobrien    int quote;
99560484Sobrien
996104834Sobrien    dyn_string_t step1 = dyn_string_new (driver_cmdline->length
997104834Sobrien					 + strlen (base_file_name)
998104834Sobrien					 + 20);
99977298Sobrien    dyn_string_append_cstr (step1, "-Wl,--base-file,");
1000104834Sobrien    quote = (strchr (base_file_name, ' ')
1001104834Sobrien	     || strchr (base_file_name, '\t'));
1002104834Sobrien    dyn_string_append_cstr (step1,
100360484Sobrien	               (quote) ? "\"" : "");
100477298Sobrien    dyn_string_append_cstr (step1, base_file_name);
1005104834Sobrien    dyn_string_append_cstr (step1,
100660484Sobrien	               (quote) ? "\"" : "");
100760484Sobrien    if (driver_cmdline->length)
100860484Sobrien      {
1009104834Sobrien	dyn_string_append_cstr (step1, " ");
1010104834Sobrien	dyn_string_append_cstr (step1, driver_cmdline->s);
101160484Sobrien      }
101260484Sobrien
101360484Sobrien    if (run (driver_name, step1->s))
101460484Sobrien      cleanup_and_exit (1);
1015104834Sobrien
101660484Sobrien    dyn_string_delete (step1);
101760484Sobrien  }
101860484Sobrien
1019218822Sdim  /* Step 2. generate the exp file by running dlltool.
1020218822Sdim     dlltool command line will look like the following:
1021218822Sdim
1022218822Sdim        % dlltool -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
1023218822Sdim
1024218822Sdim     If the user does not specify a base name, create temporary one that
1025218822Sdim     is deleted at exit.  */
102660484Sobrien
102760484Sobrien  if (! exp_file_name)
102860484Sobrien    {
102960484Sobrien      char *p = strrchr (dll_name, '.');
1030218822Sdim      size_t prefix_len = (p) ? (size_t) (p - dll_name) : strlen (dll_name);
1031218822Sdim
103260484Sobrien      exp_file_name = (char *) xmalloc (prefix_len + 4 + 1);
103360484Sobrien      strncpy (exp_file_name, dll_name, prefix_len);
103460484Sobrien      exp_file_name[prefix_len] = '\0';
103560484Sobrien      strcat (exp_file_name, ".exp");
103660484Sobrien      delete_exp_file = 1;
103760484Sobrien    }
1038104834Sobrien
103960484Sobrien  {
104060484Sobrien    int quote;
1041218822Sdim
1042104834Sobrien    dyn_string_t step2 = dyn_string_new (dlltool_cmdline->length
1043104834Sobrien					 + strlen (base_file_name)
1044104834Sobrien					 + strlen (exp_file_name)
104560484Sobrien				         + 20);
104660484Sobrien
104777298Sobrien    dyn_string_append_cstr (step2, "--base-file ");
1048104834Sobrien    quote = (strchr (base_file_name, ' ')
1049104834Sobrien	     || strchr (base_file_name, '\t'));
1050104834Sobrien    dyn_string_append_cstr (step2,
105160484Sobrien	               (quote) ? "\"" : "");
105277298Sobrien    dyn_string_append_cstr (step2, base_file_name);
1053104834Sobrien    dyn_string_append_cstr (step2,
105460484Sobrien	               (quote) ? "\" " : " ");
105560484Sobrien
105677298Sobrien    dyn_string_append_cstr (step2, "--output-exp ");
1057104834Sobrien    quote = (strchr (exp_file_name, ' ')
1058104834Sobrien	     || strchr (exp_file_name, '\t'));
1059104834Sobrien    dyn_string_append_cstr (step2,
106060484Sobrien	               (quote) ? "\"" : "");
106177298Sobrien    dyn_string_append_cstr (step2, exp_file_name);
1062104834Sobrien    dyn_string_append_cstr (step2,
106360484Sobrien	               (quote) ? "\"" : "");
106460484Sobrien
106560484Sobrien    if (dlltool_cmdline->length)
106660484Sobrien      {
1067104834Sobrien	dyn_string_append_cstr (step2, " ");
1068104834Sobrien	dyn_string_append_cstr (step2, dlltool_cmdline->s);
106960484Sobrien      }
107060484Sobrien
107160484Sobrien    if (run (dlltool_name, step2->s))
107260484Sobrien      cleanup_and_exit (1);
1073104834Sobrien
107460484Sobrien    dyn_string_delete (step2);
107560484Sobrien  }
107660484Sobrien
107760484Sobrien  /*
107860484Sobrien   * Step 3. Call GCC/LD to again, adding the exp file this time.
107960484Sobrien   * driver command line will look like the following:
1080104834Sobrien   *
108160484Sobrien   *    % gcc -Wl,--dll --Wl,--base-file,foo.base foo.exp [rest ...]
108260484Sobrien   */
108360484Sobrien
108460484Sobrien  {
108560484Sobrien    int quote;
108660484Sobrien
1087104834Sobrien    dyn_string_t step3 = dyn_string_new (driver_cmdline->length
1088104834Sobrien					 + strlen (exp_file_name)
1089104834Sobrien					 + strlen (base_file_name)
109060484Sobrien				         + 20);
109177298Sobrien    dyn_string_append_cstr (step3, "-Wl,--base-file,");
1092104834Sobrien    quote = (strchr (base_file_name, ' ')
1093104834Sobrien	     || strchr (base_file_name, '\t'));
1094104834Sobrien    dyn_string_append_cstr (step3,
109560484Sobrien	               (quote) ? "\"" : "");
109677298Sobrien    dyn_string_append_cstr (step3, base_file_name);
1097104834Sobrien    dyn_string_append_cstr (step3,
109860484Sobrien	               (quote) ? "\" " : " ");
109960484Sobrien
1100104834Sobrien    quote = (strchr (exp_file_name, ' ')
1101104834Sobrien	     || strchr (exp_file_name, '\t'));
1102104834Sobrien    dyn_string_append_cstr (step3,
110360484Sobrien	               (quote) ? "\"" : "");
110477298Sobrien    dyn_string_append_cstr (step3, exp_file_name);
1105104834Sobrien    dyn_string_append_cstr (step3,
110660484Sobrien	               (quote) ? "\"" : "");
110760484Sobrien
110860484Sobrien    if (driver_cmdline->length)
110960484Sobrien      {
1110104834Sobrien	dyn_string_append_cstr (step3, " ");
1111104834Sobrien	dyn_string_append_cstr (step3, driver_cmdline->s);
111260484Sobrien      }
111360484Sobrien
111460484Sobrien    if (run (driver_name, step3->s))
111560484Sobrien      cleanup_and_exit (1);
1116104834Sobrien
111760484Sobrien    dyn_string_delete (step3);
111860484Sobrien  }
111960484Sobrien
112060484Sobrien
112160484Sobrien  /*
112260484Sobrien   * Step 4. Run DLLTOOL again using the same command line.
112360484Sobrien   */
112460484Sobrien
112560484Sobrien  {
112660484Sobrien    int quote;
1127104834Sobrien    dyn_string_t step4 = dyn_string_new (dlltool_cmdline->length
1128104834Sobrien					 + strlen (base_file_name)
1129104834Sobrien					 + strlen (exp_file_name)
113060484Sobrien				         + 20);
113160484Sobrien
113277298Sobrien    dyn_string_append_cstr (step4, "--base-file ");
1133104834Sobrien    quote = (strchr (base_file_name, ' ')
1134104834Sobrien	     || strchr (base_file_name, '\t'));
1135104834Sobrien    dyn_string_append_cstr (step4,
113660484Sobrien	               (quote) ? "\"" : "");
113777298Sobrien    dyn_string_append_cstr (step4, base_file_name);
1138104834Sobrien    dyn_string_append_cstr (step4,
113960484Sobrien	               (quote) ? "\" " : " ");
114060484Sobrien
114177298Sobrien    dyn_string_append_cstr (step4, "--output-exp ");
1142104834Sobrien    quote = (strchr (exp_file_name, ' ')
1143104834Sobrien	     || strchr (exp_file_name, '\t'));
1144104834Sobrien    dyn_string_append_cstr (step4,
114560484Sobrien	               (quote) ? "\"" : "");
114677298Sobrien    dyn_string_append_cstr (step4, exp_file_name);
1147104834Sobrien    dyn_string_append_cstr (step4,
114860484Sobrien	               (quote) ? "\"" : "");
114960484Sobrien
115060484Sobrien    if (dlltool_cmdline->length)
115160484Sobrien      {
1152104834Sobrien	dyn_string_append_cstr (step4, " ");
1153104834Sobrien	dyn_string_append_cstr (step4, dlltool_cmdline->s);
115460484Sobrien      }
115560484Sobrien
115660484Sobrien    if (output_lib_file_name)
115760484Sobrien      {
1158104834Sobrien	dyn_string_append_cstr (step4, " --output-lib ");
1159104834Sobrien	dyn_string_append_cstr (step4, output_lib_file_name);
116060484Sobrien      }
116160484Sobrien
116260484Sobrien    if (run (dlltool_name, step4->s))
116360484Sobrien      cleanup_and_exit (1);
1164104834Sobrien
116560484Sobrien    dyn_string_delete (step4);
116660484Sobrien  }
116760484Sobrien
1168104834Sobrien
116960484Sobrien  /*
117060484Sobrien   * Step 5. Link it all together and be done with it.
117160484Sobrien   * driver command line will look like the following:
1172104834Sobrien   *
117360484Sobrien   *    % gcc -Wl,--dll foo.exp [rest ...]
117460484Sobrien   *
117560484Sobrien   */
117660484Sobrien
117760484Sobrien  {
117860484Sobrien    int quote;
117960484Sobrien
1180104834Sobrien    dyn_string_t step5 = dyn_string_new (driver_cmdline->length
1181104834Sobrien					 + strlen (exp_file_name)
118260484Sobrien				         + 20);
1183104834Sobrien    quote = (strchr (exp_file_name, ' ')
1184104834Sobrien	     || strchr (exp_file_name, '\t'));
1185104834Sobrien    dyn_string_append_cstr (step5,
118660484Sobrien	               (quote) ? "\"" : "");
118777298Sobrien    dyn_string_append_cstr (step5, exp_file_name);
1188104834Sobrien    dyn_string_append_cstr (step5,
118960484Sobrien	               (quote) ? "\"" : "");
119060484Sobrien
119160484Sobrien    if (driver_cmdline->length)
119260484Sobrien      {
1193104834Sobrien	dyn_string_append_cstr (step5, " ");
1194104834Sobrien	dyn_string_append_cstr (step5, driver_cmdline->s);
119560484Sobrien      }
119660484Sobrien
119760484Sobrien    if (run (driver_name, step5->s))
119860484Sobrien      cleanup_and_exit (1);
1199104834Sobrien
120060484Sobrien    dyn_string_delete (step5);
120160484Sobrien  }
120260484Sobrien
120360484Sobrien  cleanup_and_exit (0);
120460484Sobrien
120560484Sobrien  return 0;
120660484Sobrien}
1207