dllwrap.c revision 77298
160484Sobrien/* dllwrap.c -- wrapper for DLLTOOL and GCC to generate PE style DLLs
260484Sobrien   Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
360484Sobrien   Contributed by Mumit Khan (khan@xraylith.wisc.edu).
460484Sobrien
560484Sobrien   This file is part of GNU Binutils.
660484Sobrien
760484Sobrien   This program is free software; you can redistribute it and/or modify
860484Sobrien   it under the terms of the GNU General Public License as published by
960484Sobrien   the Free Software Foundation; either version 2 of the License, or
1060484Sobrien   (at your option) any later version.
1160484Sobrien
1260484Sobrien   This program is distributed in the hope that it will be useful,
1360484Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
1460484Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1560484Sobrien   GNU General Public License for more details.
1660484Sobrien
1760484Sobrien   You should have received a copy of the GNU General Public License
1860484Sobrien   along with this program; if not, write to the Free Software
1960484Sobrien   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
2060484Sobrien   02111-1307, USA.  */
2160484Sobrien
2260484Sobrien/* AIX requires this to be the first thing in the file.  */
2360484Sobrien#ifndef __GNUC__
2460484Sobrien# ifdef _AIX
2560484Sobrien #pragma alloca
2660484Sobrien#endif
2760484Sobrien#endif
2860484Sobrien
2960484Sobrien#ifdef HAVE_CONFIG_H
3060484Sobrien#include "config.h"
3160484Sobrien#endif
3260484Sobrien
3360484Sobrien#include "bfd.h"
3460484Sobrien#include "libiberty.h"
3560484Sobrien#include "bucomm.h"
3660484Sobrien#include "getopt.h"
3760484Sobrien#include "dyn-string.h"
3860484Sobrien
3960484Sobrien#include <ctype.h>
4060484Sobrien#include <time.h>
4160484Sobrien#include <sys/stat.h>
4260484Sobrien
4360484Sobrien#ifdef ANSI_PROTOTYPES
4460484Sobrien#include <stdarg.h>
4560484Sobrien#else
4660484Sobrien#include <varargs.h>
4760484Sobrien#endif
4860484Sobrien
4960484Sobrien#ifdef HAVE_SYS_WAIT_H
5060484Sobrien#include <sys/wait.h>
5160484Sobrien#else /* ! HAVE_SYS_WAIT_H */
5260484Sobrien#if ! defined (_WIN32) || defined (__CYGWIN32__)
5360484Sobrien#ifndef WIFEXITED
5460484Sobrien#define WIFEXITED(w)	(((w)&0377) == 0)
5560484Sobrien#endif
5660484Sobrien#ifndef WIFSIGNALED
5760484Sobrien#define WIFSIGNALED(w)	(((w)&0377) != 0177 && ((w)&~0377) == 0)
5860484Sobrien#endif
5960484Sobrien#ifndef WTERMSIG
6060484Sobrien#define WTERMSIG(w)	((w) & 0177)
6160484Sobrien#endif
6260484Sobrien#ifndef WEXITSTATUS
6360484Sobrien#define WEXITSTATUS(w)	(((w) >> 8) & 0377)
6460484Sobrien#endif
6560484Sobrien#else /* defined (_WIN32) && ! defined (__CYGWIN32__) */
6660484Sobrien#ifndef WIFEXITED
6760484Sobrien#define WIFEXITED(w)	(((w) & 0xff) == 0)
6860484Sobrien#endif
6960484Sobrien#ifndef WIFSIGNALED
7060484Sobrien#define WIFSIGNALED(w)	(((w) & 0xff) != 0 && ((w) & 0xff) != 0x7f)
7160484Sobrien#endif
7260484Sobrien#ifndef WTERMSIG
7360484Sobrien#define WTERMSIG(w)	((w) & 0x7f)
7460484Sobrien#endif
7560484Sobrien#ifndef WEXITSTATUS
7660484Sobrien#define WEXITSTATUS(w)	(((w) & 0xff00) >> 8)
7760484Sobrien#endif
7860484Sobrien#endif /* defined (_WIN32) && ! defined (__CYGWIN32__) */
7960484Sobrien#endif /* ! HAVE_SYS_WAIT_H */
8060484Sobrien
8160484Sobrienstatic char *driver_name = NULL;
8260484Sobrienstatic char *cygwin_driver_flags =
8360484Sobrien  "-Wl,--dll -nostartfiles";
8460484Sobrienstatic char *mingw32_driver_flags = "-mdll";
8560484Sobrienstatic char *generic_driver_flags = "-Wl,--dll";
8660484Sobrien
8760484Sobrienstatic char *entry_point;
8860484Sobrien
8960484Sobrienstatic char *dlltool_name = NULL;
9060484Sobrien
9160484Sobrienstatic char *target = TARGET;
9260484Sobrien
9360484Sobrientypedef enum {
9460484Sobrien  UNKNOWN_TARGET,
9560484Sobrien  CYGWIN_TARGET,
9660484Sobrien  MINGW_TARGET
9760484Sobrien}
9860484Sobrientarget_type;
9960484Sobrien
10060484Sobrienstatic target_type which_target = UNKNOWN_TARGET;
10160484Sobrien
10260484Sobrienstatic int dontdeltemps = 0;
10360484Sobrienstatic int dry_run = 0;
10460484Sobrien
10560484Sobrienstatic char *program_name;
10660484Sobrien
10760484Sobrienstatic int verbose = 0;
10860484Sobrien
10960484Sobrienstatic char *dll_file_name;
11060484Sobrienstatic char *dll_name;
11160484Sobrienstatic char *base_file_name;
11260484Sobrienstatic char *exp_file_name;
11360484Sobrienstatic char *def_file_name;
11460484Sobrienstatic int delete_base_file = 1;
11560484Sobrienstatic int delete_exp_file = 1;
11660484Sobrienstatic int delete_def_file = 1;
11760484Sobrien
11860484Sobrienstatic int run PARAMS ((const char *, char *));
11960484Sobrienstatic void usage PARAMS ((FILE *, int));
12060484Sobrienstatic void display PARAMS ((const char *, va_list));
12160484Sobrienstatic void inform PARAMS ((const char *, ...));
12260484Sobrienstatic void warn PARAMS ((const char *format, ...));
12360484Sobrienstatic char *look_for_prog PARAMS ((const char *, const char *, int));
12460484Sobrienstatic char *deduce_name PARAMS ((const char *));
12560484Sobrienstatic void delete_temp_files PARAMS ((void));
12660484Sobrienstatic void cleanup_and_exit PARAMS ((int status));
12760484Sobrien
12860484Sobrien/**********************************************************************/
12960484Sobrien
13060484Sobrien/* Please keep the following 4 routines in sync with dlltool.c:
13160484Sobrien     display ()
13260484Sobrien     inform ()
13360484Sobrien     look_for_prog ()
13460484Sobrien     deduce_name ()
13560484Sobrien   It's not worth the hassle to break these out since dllwrap will
13660484Sobrien   (hopefully) soon be retired in favor of `ld --shared.  */
13760484Sobrien
13860484Sobrienstatic void
13960484Sobriendisplay (message, args)
14060484Sobrien     const char * message;
14160484Sobrien     va_list      args;
14260484Sobrien{
14360484Sobrien  if (program_name != NULL)
14460484Sobrien    fprintf (stderr, "%s: ", program_name);
14560484Sobrien
14660484Sobrien  vfprintf (stderr, message, args);
14760484Sobrien  fputc ('\n', stderr);
14860484Sobrien}
14960484Sobrien
15060484Sobrien
15160484Sobrien#ifdef __STDC__
15260484Sobrienstatic void
15360484Sobrieninform (const char * message, ...)
15460484Sobrien{
15560484Sobrien  va_list args;
15660484Sobrien
15760484Sobrien  if (!verbose)
15860484Sobrien    return;
15960484Sobrien
16060484Sobrien  va_start (args, message);
16160484Sobrien  display (message, args);
16260484Sobrien  va_end (args);
16360484Sobrien}
16460484Sobrien
16560484Sobrienstatic void
16660484Sobrienwarn (const char *format, ...)
16760484Sobrien{
16860484Sobrien  va_list args;
16960484Sobrien
17060484Sobrien  va_start (args, format);
17160484Sobrien  display (format, args);
17260484Sobrien  va_end (args);
17360484Sobrien}
17460484Sobrien#else
17560484Sobrien
17660484Sobrienstatic void
17760484Sobrieninform (message, va_alist)
17860484Sobrien     const char * message;
17960484Sobrien     va_dcl
18060484Sobrien{
18160484Sobrien  va_list args;
18260484Sobrien
18360484Sobrien  if (!verbose)
18460484Sobrien    return;
18560484Sobrien
18660484Sobrien  va_start (args);
18760484Sobrien  display (message, args);
18860484Sobrien  va_end (args);
18960484Sobrien}
19060484Sobrien
19160484Sobrienstatic void
19260484Sobrienwarn (format, va_alist)
19360484Sobrien     const char *format;
19460484Sobrien     va_dcl
19560484Sobrien{
19660484Sobrien  va_list args;
19760484Sobrien
19860484Sobrien  va_start (args);
19960484Sobrien  display (format, args);
20060484Sobrien  va_end (args);
20160484Sobrien}
20260484Sobrien#endif
20360484Sobrien
20460484Sobrien/* Look for the program formed by concatenating PROG_NAME and the
20560484Sobrien   string running from PREFIX to END_PREFIX.  If the concatenated
20660484Sobrien   string contains a '/', try appending EXECUTABLE_SUFFIX if it is
20760484Sobrien   appropriate.  */
20860484Sobrien
20960484Sobrienstatic char *
21060484Sobrienlook_for_prog (prog_name, prefix, end_prefix)
21160484Sobrien     const char *prog_name;
21260484Sobrien     const char *prefix;
21360484Sobrien     int end_prefix;
21460484Sobrien{
21560484Sobrien  struct stat s;
21660484Sobrien  char *cmd;
21760484Sobrien
21860484Sobrien  cmd = xmalloc (strlen (prefix)
21960484Sobrien                 + strlen (prog_name)
22060484Sobrien#ifdef HAVE_EXECUTABLE_SUFFIX
22160484Sobrien                 + strlen (EXECUTABLE_SUFFIX)
22260484Sobrien#endif
22360484Sobrien		 + 10);
22460484Sobrien  strcpy (cmd, prefix);
22560484Sobrien
22660484Sobrien  sprintf (cmd + end_prefix, "%s", prog_name);
22760484Sobrien
22860484Sobrien  if (strchr (cmd, '/') != NULL)
22960484Sobrien    {
23060484Sobrien      int found;
23160484Sobrien
23260484Sobrien      found = (stat (cmd, &s) == 0
23360484Sobrien#ifdef HAVE_EXECUTABLE_SUFFIX
23460484Sobrien               || stat (strcat (cmd, EXECUTABLE_SUFFIX), &s) == 0
23560484Sobrien#endif
23660484Sobrien	       );
23760484Sobrien
23860484Sobrien      if (! found)
23960484Sobrien        {
24060484Sobrien	  /* xgettext:c-format */
24160484Sobrien	  inform (_("Tried file: %s"), cmd);
24260484Sobrien	  free (cmd);
24360484Sobrien	  return NULL;
24460484Sobrien	}
24560484Sobrien    }
24660484Sobrien
24760484Sobrien  /* xgettext:c-format */
24860484Sobrien  inform (_("Using file: %s"), cmd);
24960484Sobrien
25060484Sobrien  return cmd;
25160484Sobrien}
25260484Sobrien
25360484Sobrien/* Deduce the name of the program we are want to invoke.
25460484Sobrien   PROG_NAME is the basic name of the program we want to run,
25560484Sobrien   eg "as" or "ld".  The catch is that we might want actually
25660484Sobrien   run "i386-pe-as" or "ppc-pe-ld".
25760484Sobrien
25860484Sobrien   If argv[0] contains the full path, then try to find the program
25960484Sobrien   in the same place, with and then without a target-like prefix.
26060484Sobrien
26160484Sobrien   Given, argv[0] = /usr/local/bin/i586-cygwin32-dlltool,
26260484Sobrien   deduce_name("as") uses the following search order:
26360484Sobrien
26460484Sobrien     /usr/local/bin/i586-cygwin32-as
26560484Sobrien     /usr/local/bin/as
26660484Sobrien     as
26760484Sobrien
26860484Sobrien   If there's an EXECUTABLE_SUFFIX, it'll use that as well; for each
26960484Sobrien   name, it'll try without and then with EXECUTABLE_SUFFIX.
27060484Sobrien
27160484Sobrien   Given, argv[0] = i586-cygwin32-dlltool, it will not even try "as"
27260484Sobrien   as the fallback, but rather return i586-cygwin32-as.
27360484Sobrien
27460484Sobrien   Oh, and given, argv[0] = dlltool, it'll return "as".
27560484Sobrien
27660484Sobrien   Returns a dynamically allocated string.  */
27760484Sobrien
27860484Sobrienstatic char *
27960484Sobriendeduce_name (prog_name)
28060484Sobrien     const char *prog_name;
28160484Sobrien{
28260484Sobrien  char *cmd;
28360484Sobrien  char *dash, *slash, *cp;
28460484Sobrien
28560484Sobrien  dash = NULL;
28660484Sobrien  slash = NULL;
28760484Sobrien  for (cp = program_name; *cp != '\0'; ++cp)
28860484Sobrien    {
28960484Sobrien      if (*cp == '-')
29060484Sobrien	dash = cp;
29160484Sobrien      if (
29260484Sobrien#if defined(__DJGPP__) || defined (__CYGWIN__) || defined(__WIN32__)
29360484Sobrien	  *cp == ':' || *cp == '\\' ||
29460484Sobrien#endif
29560484Sobrien	  *cp == '/')
29660484Sobrien	{
29760484Sobrien	  slash = cp;
29860484Sobrien	  dash = NULL;
29960484Sobrien	}
30060484Sobrien    }
30160484Sobrien
30260484Sobrien  cmd = NULL;
30360484Sobrien
30460484Sobrien  if (dash != NULL)
30560484Sobrien    {
30660484Sobrien      /* First, try looking for a prefixed PROG_NAME in the
30760484Sobrien         PROGRAM_NAME directory, with the same prefix as PROGRAM_NAME.  */
30860484Sobrien      cmd = look_for_prog (prog_name, program_name, dash - program_name + 1);
30960484Sobrien    }
31060484Sobrien
31160484Sobrien  if (slash != NULL && cmd == NULL)
31260484Sobrien    {
31360484Sobrien      /* Next, try looking for a PROG_NAME in the same directory as
31460484Sobrien         that of this program.  */
31560484Sobrien      cmd = look_for_prog (prog_name, program_name, slash - program_name + 1);
31660484Sobrien    }
31760484Sobrien
31860484Sobrien  if (cmd == NULL)
31960484Sobrien    {
32060484Sobrien      /* Just return PROG_NAME as is.  */
32160484Sobrien      cmd = xstrdup (prog_name);
32260484Sobrien    }
32360484Sobrien
32460484Sobrien  return cmd;
32560484Sobrien}
32660484Sobrien
32760484Sobrienstatic void
32860484Sobriendelete_temp_files ()
32960484Sobrien{
33060484Sobrien  if (delete_base_file && base_file_name)
33160484Sobrien    {
33260484Sobrien      if (verbose)
33360484Sobrien	{
33460484Sobrien	  if (dontdeltemps)
33560484Sobrien	    warn (_("Keeping temporary base file %s"), base_file_name);
33660484Sobrien	  else
33760484Sobrien	    warn (_("Deleting temporary base file %s"), base_file_name);
33860484Sobrien	}
33960484Sobrien      if (! dontdeltemps)
34060484Sobrien        {
34160484Sobrien          unlink (base_file_name);
34260484Sobrien	  free (base_file_name);
34360484Sobrien	}
34460484Sobrien    }
34560484Sobrien
34660484Sobrien  if (delete_exp_file && exp_file_name)
34760484Sobrien    {
34860484Sobrien      if (verbose)
34960484Sobrien	{
35060484Sobrien	  if (dontdeltemps)
35160484Sobrien	    warn (_("Keeping temporary exp file %s"), exp_file_name);
35260484Sobrien	  else
35360484Sobrien	    warn (_("Deleting temporary exp file %s"), exp_file_name);
35460484Sobrien	}
35560484Sobrien      if (! dontdeltemps)
35660484Sobrien        {
35760484Sobrien          unlink (exp_file_name);
35860484Sobrien          free (exp_file_name);
35960484Sobrien	}
36060484Sobrien    }
36160484Sobrien  if (delete_def_file && def_file_name)
36260484Sobrien    {
36360484Sobrien      if (verbose)
36460484Sobrien	{
36560484Sobrien	  if (dontdeltemps)
36660484Sobrien	    warn (_("Keeping temporary def file %s"), def_file_name);
36760484Sobrien	  else
36860484Sobrien	    warn (_("Deleting temporary def file %s"), def_file_name);
36960484Sobrien	}
37060484Sobrien      if (! dontdeltemps)
37160484Sobrien        {
37260484Sobrien          unlink (def_file_name);
37360484Sobrien          free (def_file_name);
37460484Sobrien	}
37560484Sobrien    }
37660484Sobrien}
37760484Sobrien
37860484Sobrienstatic void
37960484Sobriencleanup_and_exit (int status)
38060484Sobrien{
38160484Sobrien  delete_temp_files ();
38260484Sobrien  exit (status);
38360484Sobrien}
38460484Sobrien
38560484Sobrienstatic int
38660484Sobrienrun (what, args)
38760484Sobrien     const char *what;
38860484Sobrien     char *args;
38960484Sobrien{
39060484Sobrien  char *s;
39160484Sobrien  int pid, wait_status, retcode;
39260484Sobrien  int i;
39360484Sobrien  const char **argv;
39460484Sobrien  char *errmsg_fmt, *errmsg_arg;
39560484Sobrien  char *temp_base = choose_temp_base ();
39660484Sobrien  int in_quote;
39760484Sobrien  char sep;
39860484Sobrien
39960484Sobrien  if (verbose || dry_run)
40060484Sobrien    fprintf (stderr, "%s %s\n", what, args);
40160484Sobrien
40260484Sobrien  /* Count the args */
40360484Sobrien  i = 0;
40460484Sobrien  for (s = args; *s; s++)
40560484Sobrien    if (*s == ' ')
40660484Sobrien      i++;
40760484Sobrien  i++;
40860484Sobrien  argv = alloca (sizeof (char *) * (i + 3));
40960484Sobrien  i = 0;
41060484Sobrien  argv[i++] = what;
41160484Sobrien  s = args;
41260484Sobrien  while (1)
41360484Sobrien    {
41460484Sobrien      while (*s == ' ' && *s != 0)
41560484Sobrien	s++;
41660484Sobrien      if (*s == 0)
41760484Sobrien	break;
41860484Sobrien      in_quote = (*s == '\'' || *s == '"');
41960484Sobrien      sep = (in_quote) ? *s++ : ' ';
42060484Sobrien      argv[i++] = s;
42160484Sobrien      while (*s != sep && *s != 0)
42260484Sobrien	s++;
42360484Sobrien      if (*s == 0)
42460484Sobrien	break;
42560484Sobrien      *s++ = 0;
42660484Sobrien      if (in_quote)
42760484Sobrien        s++;
42860484Sobrien    }
42960484Sobrien  argv[i++] = NULL;
43060484Sobrien
43160484Sobrien  if (dry_run)
43260484Sobrien    return 0;
43360484Sobrien
43460484Sobrien  pid = pexecute (argv[0], (char * const *) argv, program_name, temp_base,
43560484Sobrien		  &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
43660484Sobrien
43760484Sobrien  if (pid == -1)
43860484Sobrien    {
43960484Sobrien      int errno_val = errno;
44060484Sobrien
44160484Sobrien      fprintf (stderr, "%s: ", program_name);
44260484Sobrien      fprintf (stderr, errmsg_fmt, errmsg_arg);
44360484Sobrien      fprintf (stderr, ": %s\n", strerror (errno_val));
44460484Sobrien      return 1;
44560484Sobrien    }
44660484Sobrien
44760484Sobrien  retcode = 0;
44860484Sobrien  pid = pwait (pid, &wait_status, 0);
44960484Sobrien  if (pid == -1)
45060484Sobrien    {
45160484Sobrien      warn ("wait: %s", strerror (errno));
45260484Sobrien      retcode = 1;
45360484Sobrien    }
45460484Sobrien  else if (WIFSIGNALED (wait_status))
45560484Sobrien    {
45660484Sobrien      warn (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
45760484Sobrien      retcode = 1;
45860484Sobrien    }
45960484Sobrien  else if (WIFEXITED (wait_status))
46060484Sobrien    {
46160484Sobrien      if (WEXITSTATUS (wait_status) != 0)
46260484Sobrien	{
46360484Sobrien	  warn (_("%s exited with status %d"), what, WEXITSTATUS (wait_status));
46460484Sobrien	  retcode = 1;
46560484Sobrien	}
46660484Sobrien    }
46760484Sobrien  else
46860484Sobrien    retcode = 1;
46960484Sobrien
47060484Sobrien  return retcode;
47160484Sobrien}
47260484Sobrien
47360484Sobrienstatic char *
47460484Sobrienmybasename (name)
47560484Sobrien     const char *name;
47660484Sobrien{
47760484Sobrien  const char *base = name;
47860484Sobrien
47960484Sobrien  while (*name)
48060484Sobrien    {
48160484Sobrien      if (*name == '/' || *name == '\\')
48260484Sobrien	{
48360484Sobrien	  base = name + 1;
48460484Sobrien	}
48560484Sobrien      ++name;
48660484Sobrien    }
48760484Sobrien  return (char *) base;
48860484Sobrien}
48960484Sobrien
49060484Sobrienstatic int
49160484Sobrienstrhash (const char *str)
49260484Sobrien{
49360484Sobrien  const unsigned char *s;
49460484Sobrien  unsigned long hash;
49560484Sobrien  unsigned int c;
49660484Sobrien  unsigned int len;
49760484Sobrien
49860484Sobrien  hash = 0;
49960484Sobrien  len = 0;
50060484Sobrien  s = (const unsigned char *) str;
50160484Sobrien  while ((c = *s++) != '\0')
50260484Sobrien    {
50360484Sobrien      hash += c + (c << 17);
50460484Sobrien      hash ^= hash >> 2;
50560484Sobrien      ++len;
50660484Sobrien    }
50760484Sobrien  hash += len + (len << 17);
50860484Sobrien  hash ^= hash >> 2;
50960484Sobrien
51060484Sobrien  return hash;
51160484Sobrien}
51260484Sobrien
51360484Sobrien/**********************************************************************/
51460484Sobrien
51560484Sobrienstatic void
51660484Sobrienusage (file, status)
51760484Sobrien     FILE *file;
51860484Sobrien     int status;
51960484Sobrien{
52060484Sobrien  fprintf (file, _("Usage %s <options> <object-files>\n"), program_name);
52160484Sobrien  fprintf (file, _("  Generic options:\n"));
52260484Sobrien  fprintf (file, _("   --quiet, -q            Work quietly\n"));
52360484Sobrien  fprintf (file, _("   --verbose, -v          Verbose\n"));
52460484Sobrien  fprintf (file, _("   --version              Print dllwrap version\n"));
52560484Sobrien  fprintf (file, _("   --implib <outname>     Synonym for --output-lib\n"));
52660484Sobrien  fprintf (file, _("  Options for %s:\n"), program_name);
52760484Sobrien  fprintf (file, _("   --driver-name <driver> Defaults to \"gcc\"\n"));
52860484Sobrien  fprintf (file, _("   --driver-flags <flags> Override default ld flags\n"));
52960484Sobrien  fprintf (file, _("   --dlltool-name <dlltool> Defaults to \"dlltool\"\n"));
53060484Sobrien  fprintf (file, _("   --entry <entry>        Specify alternate DLL entry point\n"));
53160484Sobrien  fprintf (file, _("   --image-base <base>    Specify image base address\n"));
53260484Sobrien  fprintf (file, _("   --target <machine>     i386-cygwin32 or i386-mingw32\n"));
53360484Sobrien  fprintf (file, _("   --dry-run              Show what needs to be run\n"));
53460484Sobrien  fprintf (file, _("   --mno-cygwin           Create Mingw DLL\n"));
53560484Sobrien  fprintf (file, _("  Options passed to DLLTOOL:\n"));
53660484Sobrien  fprintf (file, _("   --machine <machine>\n"));
53760484Sobrien  fprintf (file, _("   --output-exp <outname> Generate export file.\n"));
53860484Sobrien  fprintf (file, _("   --output-lib <outname> Generate input library.\n"));
53960484Sobrien  fprintf (file, _("   --add-indirect         Add dll indirects to export file.\n"));
54060484Sobrien  fprintf (file, _("   --dllname <name>       Name of input dll to put into output lib.\n"));
54160484Sobrien  fprintf (file, _("   --def <deffile>        Name input .def file\n"));
54260484Sobrien  fprintf (file, _("   --output-def <deffile> Name output .def file\n"));
54360484Sobrien  fprintf (file, _("   --export-all-symbols     Export all symbols to .def\n"));
54460484Sobrien  fprintf (file, _("   --no-export-all-symbols  Only export .drectve symbols\n"));
54560484Sobrien  fprintf (file, _("   --exclude-symbols <list> Exclude <list> from .def\n"));
54660484Sobrien  fprintf (file, _("   --no-default-excludes    Zap default exclude symbols\n"));
54760484Sobrien  fprintf (file, _("   --base-file <basefile> Read linker generated base file\n"));
54860484Sobrien  fprintf (file, _("   --no-idata4           Don't generate idata$4 section\n"));
54960484Sobrien  fprintf (file, _("   --no-idata5           Don't generate idata$5 section\n"));
55060484Sobrien  fprintf (file, _("   -U                     Add underscores to .lib\n"));
55160484Sobrien  fprintf (file, _("   -k                     Kill @<n> from exported names\n"));
55260484Sobrien  fprintf (file, _("   --add-stdcall-alias    Add aliases without @<n>\n"));
55360484Sobrien  fprintf (file, _("   --as <name>            Use <name> for assembler\n"));
55460484Sobrien  fprintf (file, _("   --nodelete             Keep temp files.\n"));
55560484Sobrien  fprintf (file, _("  Rest are passed unmodified to the language driver\n"));
55660484Sobrien  fprintf (file, "\n\n");
55760484Sobrien  exit (status);
55860484Sobrien}
55960484Sobrien
56060484Sobrien#define OPTION_START		149
56160484Sobrien
56260484Sobrien/* GENERIC options. */
56360484Sobrien#define OPTION_QUIET		(OPTION_START + 1)
56460484Sobrien#define OPTION_VERBOSE		(OPTION_QUIET + 1)
56560484Sobrien#define OPTION_VERSION		(OPTION_VERBOSE + 1)
56660484Sobrien
56760484Sobrien/* DLLWRAP options. */
56860484Sobrien#define OPTION_DRY_RUN		(OPTION_VERSION + 1)
56960484Sobrien#define OPTION_DRIVER_NAME	(OPTION_DRY_RUN + 1)
57060484Sobrien#define OPTION_DRIVER_FLAGS	(OPTION_DRIVER_NAME + 1)
57160484Sobrien#define OPTION_DLLTOOL_NAME	(OPTION_DRIVER_FLAGS + 1)
57260484Sobrien#define OPTION_ENTRY		(OPTION_DLLTOOL_NAME + 1)
57360484Sobrien#define OPTION_IMAGE_BASE	(OPTION_ENTRY + 1)
57460484Sobrien#define OPTION_TARGET		(OPTION_IMAGE_BASE + 1)
57560484Sobrien#define OPTION_MNO_CYGWIN	(OPTION_TARGET + 1)
57660484Sobrien
57760484Sobrien/* DLLTOOL options. */
57860484Sobrien#define OPTION_NODELETE		(OPTION_MNO_CYGWIN + 1)
57960484Sobrien#define OPTION_DLLNAME		(OPTION_NODELETE + 1)
58060484Sobrien#define OPTION_NO_IDATA4 	(OPTION_DLLNAME + 1)
58160484Sobrien#define OPTION_NO_IDATA5	(OPTION_NO_IDATA4 + 1)
58260484Sobrien#define OPTION_OUTPUT_EXP	(OPTION_NO_IDATA5 + 1)
58360484Sobrien#define OPTION_OUTPUT_DEF	(OPTION_OUTPUT_EXP + 1)
58460484Sobrien#define OPTION_EXPORT_ALL_SYMS	(OPTION_OUTPUT_DEF + 1)
58560484Sobrien#define OPTION_NO_EXPORT_ALL_SYMS (OPTION_EXPORT_ALL_SYMS + 1)
58660484Sobrien#define OPTION_EXCLUDE_SYMS	(OPTION_NO_EXPORT_ALL_SYMS + 1)
58760484Sobrien#define OPTION_NO_DEFAULT_EXCLUDES (OPTION_EXCLUDE_SYMS + 1)
58860484Sobrien#define OPTION_OUTPUT_LIB	(OPTION_NO_DEFAULT_EXCLUDES + 1)
58960484Sobrien#define OPTION_DEF		(OPTION_OUTPUT_LIB + 1)
59060484Sobrien#define OPTION_ADD_UNDERSCORE	(OPTION_DEF + 1)
59160484Sobrien#define OPTION_KILLAT		(OPTION_ADD_UNDERSCORE + 1)
59260484Sobrien#define OPTION_HELP		(OPTION_KILLAT + 1)
59360484Sobrien#define OPTION_MACHINE		(OPTION_HELP + 1)
59460484Sobrien#define OPTION_ADD_INDIRECT	(OPTION_MACHINE + 1)
59560484Sobrien#define OPTION_BASE_FILE	(OPTION_ADD_INDIRECT + 1)
59660484Sobrien#define OPTION_AS		(OPTION_BASE_FILE + 1)
59760484Sobrien
59860484Sobrienstatic const struct option long_options[] =
59960484Sobrien{
60060484Sobrien  /* generic options. */
60160484Sobrien  {"quiet", no_argument, NULL, 'q'},
60260484Sobrien  {"verbose", no_argument, NULL, 'v'},
60360484Sobrien  {"version", no_argument, NULL, OPTION_VERSION},
60460484Sobrien  {"implib", required_argument, NULL, OPTION_OUTPUT_LIB},
60560484Sobrien
60660484Sobrien  /* dllwrap options. */
60760484Sobrien  {"dry-run", no_argument, NULL, OPTION_DRY_RUN},
60860484Sobrien  {"driver-name", required_argument, NULL, OPTION_DRIVER_NAME},
60960484Sobrien  {"driver-flags", required_argument, NULL, OPTION_DRIVER_FLAGS},
61060484Sobrien  {"dlltool-name", required_argument, NULL, OPTION_DLLTOOL_NAME},
61160484Sobrien  {"entry", required_argument, NULL, 'e'},
61260484Sobrien  {"image-base", required_argument, NULL, OPTION_IMAGE_BASE},
61360484Sobrien  {"target", required_argument, NULL, OPTION_TARGET},
61460484Sobrien
61560484Sobrien  /* dlltool options. */
61660484Sobrien  {"no-delete", no_argument, NULL, 'n'},
61760484Sobrien  {"dllname", required_argument, NULL, OPTION_DLLNAME},
61860484Sobrien  {"no-idata4", no_argument, NULL, OPTION_NO_IDATA4},
61960484Sobrien  {"no-idata5", no_argument, NULL, OPTION_NO_IDATA5},
62060484Sobrien  {"output-exp", required_argument, NULL, OPTION_OUTPUT_EXP},
62160484Sobrien  {"output-def", required_argument, NULL, OPTION_OUTPUT_DEF},
62260484Sobrien  {"export-all-symbols", no_argument, NULL, OPTION_EXPORT_ALL_SYMS},
62360484Sobrien  {"no-export-all-symbols", no_argument, NULL, OPTION_NO_EXPORT_ALL_SYMS},
62460484Sobrien  {"exclude-symbols", required_argument, NULL, OPTION_EXCLUDE_SYMS},
62560484Sobrien  {"no-default-excludes", no_argument, NULL, OPTION_NO_DEFAULT_EXCLUDES},
62660484Sobrien  {"output-lib", required_argument, NULL, OPTION_OUTPUT_LIB},
62760484Sobrien  {"def", required_argument, NULL, OPTION_DEF},
62860484Sobrien  {"add-underscore", no_argument, NULL, 'U'},
62960484Sobrien  {"killat", no_argument, NULL, 'k'},
63060484Sobrien  {"add-stdcall-alias", no_argument, NULL, 'A'},
63160484Sobrien  {"help", no_argument, NULL, 'h'},
63260484Sobrien  {"machine", required_argument, NULL, OPTION_MACHINE},
63360484Sobrien  {"add-indirect", no_argument, NULL, OPTION_ADD_INDIRECT},
63460484Sobrien  {"base-file", required_argument, NULL, OPTION_BASE_FILE},
63560484Sobrien  {"as", required_argument, NULL, OPTION_AS},
63660484Sobrien  {0, 0, 0, 0}
63760484Sobrien};
63860484Sobrien
63960484Sobrienint
64060484Sobrienmain (argc, argv)
64160484Sobrien     int argc;
64260484Sobrien     char **argv;
64360484Sobrien{
64460484Sobrien  int c;
64560484Sobrien  int i;
64660484Sobrien
64760484Sobrien  char **saved_argv = 0;
64860484Sobrien  int cmdline_len = 0;
64960484Sobrien
65060484Sobrien  int export_all = 0;
65160484Sobrien
65260484Sobrien  int *dlltool_arg_indices;
65360484Sobrien  int *driver_arg_indices;
65460484Sobrien
65560484Sobrien  char *driver_flags = 0;
65660484Sobrien  char *output_lib_file_name = 0;
65760484Sobrien
65860484Sobrien  dyn_string_t dlltool_cmdline;
65960484Sobrien  dyn_string_t driver_cmdline;
66060484Sobrien
66160484Sobrien  int def_file_seen = 0;
66260484Sobrien
66360484Sobrien  char *image_base_str = 0;
66460484Sobrien
66560484Sobrien  program_name = argv[0];
66660484Sobrien
66760484Sobrien  saved_argv = (char **) xmalloc (argc * sizeof (char*));
66860484Sobrien  dlltool_arg_indices = (int *) xmalloc (argc * sizeof (int));
66960484Sobrien  driver_arg_indices = (int *) xmalloc (argc * sizeof (int));
67060484Sobrien  for (i = 0; i < argc; ++i)
67160484Sobrien    {
67260484Sobrien      size_t len = strlen (argv[i]);
67360484Sobrien      char *arg = (char *) xmalloc (len + 1);
67460484Sobrien      strcpy (arg, argv[i]);
67560484Sobrien      cmdline_len += len;
67660484Sobrien      saved_argv[i] = arg;
67760484Sobrien      dlltool_arg_indices[i] = 0;
67860484Sobrien      driver_arg_indices[i] = 1;
67960484Sobrien    }
68060484Sobrien  cmdline_len++;
68160484Sobrien
68260484Sobrien  /* We recognize dllwrap and dlltool options, and everything else is
68360484Sobrien     passed onto the language driver (eg., to GCC). We collect options
68460484Sobrien     to dlltool and driver in dlltool_args and driver_args. */
68560484Sobrien
68660484Sobrien  opterr = 0;
68760484Sobrien  while ((c = getopt_long_only (argc, argv, "nkAqve:Uho:l:L:I:",
68860484Sobrien                                long_options, (int *) 0)) != EOF)
68960484Sobrien    {
69060484Sobrien      int dlltool_arg;
69160484Sobrien      int driver_arg;
69260484Sobrien      int single_word_option_value_pair;
69360484Sobrien
69460484Sobrien      dlltool_arg = 0;
69560484Sobrien      driver_arg = 1;
69660484Sobrien      single_word_option_value_pair = 0;
69760484Sobrien
69860484Sobrien      if (c != '?')
69960484Sobrien        {
70060484Sobrien	  /* We recognize this option, so it has to be either dllwrap or
70160484Sobrien	     dlltool option. Do not pass to driver unless it's one of the
70260484Sobrien	     generic options that are passed to all the tools (such as -v)
70360484Sobrien	     which are dealt with later. */
70460484Sobrien	  driver_arg = 0;
70560484Sobrien	}
70660484Sobrien
70760484Sobrien      /* deal with generic and dllwrap options first. */
70860484Sobrien      switch (c)
70960484Sobrien	{
71060484Sobrien	case 'h':
71160484Sobrien	  usage (stdout, 0);
71260484Sobrien	  break;
71360484Sobrien	case 'q':
71460484Sobrien	  verbose = 0;
71560484Sobrien	  break;
71660484Sobrien	case 'v':
71760484Sobrien	  verbose = 1;
71860484Sobrien	  break;
71960484Sobrien	case OPTION_VERSION:
72060484Sobrien	  print_version (program_name);
72160484Sobrien	  break;
72260484Sobrien	case 'e':
72360484Sobrien	  entry_point = optarg;
72460484Sobrien	  break;
72560484Sobrien	case OPTION_IMAGE_BASE:
72660484Sobrien	  image_base_str = optarg;
72760484Sobrien	  break;
72860484Sobrien	case OPTION_DEF:
72960484Sobrien	  def_file_name = optarg;
73060484Sobrien	  def_file_seen = 1;
73160484Sobrien	  delete_def_file = 0;
73260484Sobrien	  break;
73360484Sobrien	case 'n':
73460484Sobrien	  dontdeltemps = 1;
73560484Sobrien	  dlltool_arg = 1;
73660484Sobrien	  break;
73760484Sobrien	case 'o':
73860484Sobrien	  dll_file_name = optarg;
73960484Sobrien	  break;
74060484Sobrien	case 'I':
74160484Sobrien	case 'l':
74260484Sobrien	case 'L':
74360484Sobrien	  driver_arg = 1;
74460484Sobrien	  break;
74560484Sobrien	case OPTION_DLLNAME:
74660484Sobrien	  dll_name = optarg;
74760484Sobrien	  break;
74860484Sobrien	case OPTION_DRY_RUN:
74960484Sobrien	  dry_run = 1;
75060484Sobrien	  break;
75160484Sobrien	case OPTION_DRIVER_NAME:
75260484Sobrien	  driver_name = optarg;
75360484Sobrien	  break;
75460484Sobrien	case OPTION_DRIVER_FLAGS:
75560484Sobrien	  driver_flags = optarg;
75660484Sobrien	  break;
75760484Sobrien	case OPTION_DLLTOOL_NAME:
75860484Sobrien	  dlltool_name = optarg;
75960484Sobrien	  break;
76060484Sobrien	case OPTION_TARGET:
76160484Sobrien	  target = optarg;
76260484Sobrien	  break;
76360484Sobrien	case OPTION_MNO_CYGWIN:
76460484Sobrien	  target = "i386-mingw32";
76560484Sobrien	  break;
76660484Sobrien	case OPTION_BASE_FILE:
76760484Sobrien	  base_file_name = optarg;
76860484Sobrien	  delete_base_file = 0;
76960484Sobrien	  break;
77060484Sobrien	case OPTION_OUTPUT_EXP:
77160484Sobrien	  exp_file_name = optarg;
77260484Sobrien	  delete_exp_file = 0;
77360484Sobrien	  break;
77460484Sobrien	case OPTION_EXPORT_ALL_SYMS:
77560484Sobrien	  export_all = 1;
77660484Sobrien	  break;
77760484Sobrien	case OPTION_OUTPUT_LIB:
77860484Sobrien	  output_lib_file_name = optarg;
77960484Sobrien	  break;
78060484Sobrien	case '?':
78160484Sobrien	  break;
78260484Sobrien	default:
78360484Sobrien	  dlltool_arg = 1;
78460484Sobrien	  break;
78560484Sobrien	}
78660484Sobrien
78760484Sobrien      /* Handle passing through --option=value case. */
78860484Sobrien      if (optarg
78960484Sobrien          && saved_argv[optind-1][0] == '-'
79060484Sobrien          && saved_argv[optind-1][1] == '-'
79160484Sobrien	  && strchr (saved_argv[optind-1], '='))
79260484Sobrien	single_word_option_value_pair = 1;
79360484Sobrien
79460484Sobrien      if (dlltool_arg)
79560484Sobrien        {
79660484Sobrien	  dlltool_arg_indices[optind-1] = 1;
79760484Sobrien	  if (optarg && ! single_word_option_value_pair)
79860484Sobrien	    {
79960484Sobrien	      dlltool_arg_indices[optind-2] = 1;
80060484Sobrien	    }
80160484Sobrien	}
80260484Sobrien
80360484Sobrien      if (! driver_arg)
80460484Sobrien        {
80560484Sobrien	  driver_arg_indices[optind-1] = 0;
80660484Sobrien	  if (optarg && ! single_word_option_value_pair)
80760484Sobrien	    {
80860484Sobrien	      driver_arg_indices[optind-2] = 0;
80960484Sobrien	    }
81060484Sobrien	}
81160484Sobrien    }
81260484Sobrien
81360484Sobrien  /* sanity checks. */
81460484Sobrien  if (! dll_name && ! dll_file_name)
81560484Sobrien    {
81660484Sobrien      warn (_("Must provide at least one of -o or --dllname options"));
81760484Sobrien      exit (1);
81860484Sobrien    }
81960484Sobrien  else if (! dll_name)
82060484Sobrien    {
82160484Sobrien      dll_name = xstrdup (mybasename (dll_file_name));
82260484Sobrien    }
82360484Sobrien  else if (! dll_file_name)
82460484Sobrien    {
82560484Sobrien      dll_file_name = xstrdup (dll_name);
82660484Sobrien    }
82760484Sobrien
82860484Sobrien  /* Deduce driver-name and dlltool-name from our own. */
82960484Sobrien  if (driver_name == NULL)
83060484Sobrien    driver_name = deduce_name ("gcc");
83160484Sobrien
83260484Sobrien  if (dlltool_name == NULL)
83360484Sobrien    dlltool_name = deduce_name ("dlltool");
83460484Sobrien
83560484Sobrien  if (! def_file_seen)
83660484Sobrien    {
83760484Sobrien      char *fileprefix = choose_temp_base ();
83860484Sobrien      def_file_name = (char *) xmalloc (strlen (fileprefix) + 5);
83960484Sobrien      sprintf (def_file_name, "%s.def",
84060484Sobrien               (dontdeltemps) ? mybasename (fileprefix) : fileprefix);
84160484Sobrien      delete_def_file = 1;
84260484Sobrien      free (fileprefix);
84360484Sobrien      delete_def_file = 1;
84460484Sobrien      warn (_("no export definition file provided"));
84560484Sobrien      warn (_("creating one, but that may not be what you want"));
84660484Sobrien    }
84760484Sobrien
84860484Sobrien  /* set the target platform. */
84960484Sobrien  if (strstr (target, "cygwin"))
85060484Sobrien    which_target = CYGWIN_TARGET;
85160484Sobrien  else if (strstr (target, "mingw"))
85260484Sobrien    which_target = MINGW_TARGET;
85360484Sobrien  else
85460484Sobrien    which_target = UNKNOWN_TARGET;
85560484Sobrien
85660484Sobrien  /* re-create the command lines as a string, taking care to quote stuff. */
85760484Sobrien  dlltool_cmdline = dyn_string_new (cmdline_len);
85860484Sobrien  if (verbose)
85960484Sobrien    {
86077298Sobrien      dyn_string_append_cstr (dlltool_cmdline, " -v");
86160484Sobrien    }
86277298Sobrien  dyn_string_append_cstr (dlltool_cmdline, " --dllname ");
86377298Sobrien  dyn_string_append_cstr (dlltool_cmdline, dll_name);
86460484Sobrien
86560484Sobrien  for (i = 1; i < argc; ++i)
86660484Sobrien    {
86760484Sobrien      if (dlltool_arg_indices[i])
86860484Sobrien        {
86960484Sobrien	  char *arg = saved_argv[i];
87060484Sobrien          int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
87177298Sobrien	  dyn_string_append_cstr (dlltool_cmdline,
87260484Sobrien	                     (quote) ? " \"" : " ");
87377298Sobrien	  dyn_string_append_cstr (dlltool_cmdline, arg);
87477298Sobrien	  dyn_string_append_cstr (dlltool_cmdline,
87560484Sobrien	                     (quote) ? "\"" : "");
87660484Sobrien	}
87760484Sobrien    }
87860484Sobrien
87960484Sobrien  driver_cmdline = dyn_string_new (cmdline_len);
88060484Sobrien  if (! driver_flags || strlen (driver_flags) == 0)
88160484Sobrien    {
88260484Sobrien      switch (which_target)
88360484Sobrien        {
88460484Sobrien	case CYGWIN_TARGET:
88560484Sobrien          driver_flags = cygwin_driver_flags;
88660484Sobrien	  break;
88760484Sobrien
88860484Sobrien	case MINGW_TARGET:
88960484Sobrien          driver_flags = mingw32_driver_flags;
89060484Sobrien	  break;
89160484Sobrien
89260484Sobrien	default:
89360484Sobrien          driver_flags = generic_driver_flags;
89460484Sobrien	  break;
89560484Sobrien	}
89660484Sobrien    }
89777298Sobrien  dyn_string_append_cstr (driver_cmdline, driver_flags);
89877298Sobrien  dyn_string_append_cstr (driver_cmdline, " -o ");
89977298Sobrien  dyn_string_append_cstr (driver_cmdline, dll_file_name);
90060484Sobrien
90160484Sobrien  if (! entry_point || strlen (entry_point) == 0)
90260484Sobrien    {
90360484Sobrien      switch (which_target)
90460484Sobrien        {
90560484Sobrien	case CYGWIN_TARGET:
90660484Sobrien	  entry_point = "__cygwin_dll_entry@12";
90760484Sobrien	  break;
90860484Sobrien
90960484Sobrien	case MINGW_TARGET:
91060484Sobrien	  entry_point = "_DllMainCRTStartup@12";
91160484Sobrien	  break;
91260484Sobrien
91360484Sobrien	default:
91460484Sobrien          entry_point = "_DllMain@12";
91560484Sobrien	  break;
91660484Sobrien	}
91760484Sobrien    }
91877298Sobrien  dyn_string_append_cstr (driver_cmdline, " -Wl,-e,");
91977298Sobrien  dyn_string_append_cstr (driver_cmdline, entry_point);
92077298Sobrien  dyn_string_append_cstr (dlltool_cmdline, " --exclude-symbol=");
92177298Sobrien  dyn_string_append_cstr (dlltool_cmdline,
92260484Sobrien                     (entry_point[0] == '_') ? entry_point+1 : entry_point);
92360484Sobrien
92460484Sobrien  if (! image_base_str || strlen (image_base_str) == 0)
92560484Sobrien    {
92660484Sobrien      char *tmpbuf = (char *) xmalloc (sizeof ("0x12345678") + 1);
92760484Sobrien      unsigned long hash = strhash (dll_file_name);
92860484Sobrien      sprintf (tmpbuf, "0x%.8lX", 0x60000000|((hash<<16)&0xFFC0000));
92960484Sobrien      image_base_str = tmpbuf;
93060484Sobrien    }
93160484Sobrien
93277298Sobrien  dyn_string_append_cstr (driver_cmdline, " -Wl,--image-base,");
93377298Sobrien  dyn_string_append_cstr (driver_cmdline, image_base_str);
93460484Sobrien
93560484Sobrien  if (verbose)
93660484Sobrien    {
93777298Sobrien      dyn_string_append_cstr (driver_cmdline, " -v");
93860484Sobrien    }
93960484Sobrien
94060484Sobrien  for (i = 1; i < argc; ++i)
94160484Sobrien    {
94260484Sobrien      if (driver_arg_indices[i])
94360484Sobrien        {
94460484Sobrien	  char *arg = saved_argv[i];
94560484Sobrien          int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
94677298Sobrien	  dyn_string_append_cstr (driver_cmdline,
94760484Sobrien	                     (quote) ? " \"" : " ");
94877298Sobrien	  dyn_string_append_cstr (driver_cmdline, arg);
94977298Sobrien	  dyn_string_append_cstr (driver_cmdline,
95060484Sobrien	                     (quote) ? "\"" : "");
95160484Sobrien	}
95260484Sobrien    }
95360484Sobrien
95460484Sobrien  /*
95560484Sobrien   * Step pre-1. If no --def <EXPORT_DEF> is specified, then create it
95660484Sobrien   * and then pass it on.
95760484Sobrien   */
95860484Sobrien
95960484Sobrien  if (! def_file_seen)
96060484Sobrien    {
96160484Sobrien      int i;
96260484Sobrien      dyn_string_t step_pre1;
96360484Sobrien
96460484Sobrien      step_pre1 = dyn_string_new (1024);
96560484Sobrien
96677298Sobrien      dyn_string_append_cstr (step_pre1, dlltool_cmdline->s);
96760484Sobrien      if (export_all)
96860484Sobrien	{
96977298Sobrien          dyn_string_append_cstr (step_pre1, " --export-all --exclude-symbol=");
97077298Sobrien          dyn_string_append_cstr (step_pre1,
97160484Sobrien	  "_cygwin_dll_entry@12,DllMainCRTStartup@12,DllMain@12,DllEntryPoint@12");
97260484Sobrien	}
97377298Sobrien      dyn_string_append_cstr (step_pre1, " --output-def ");
97477298Sobrien      dyn_string_append_cstr (step_pre1, def_file_name);
97560484Sobrien
97660484Sobrien      for (i = 1; i < argc; ++i)
97760484Sobrien	{
97860484Sobrien	  if (driver_arg_indices[i])
97960484Sobrien	    {
98060484Sobrien	      char *arg = saved_argv[i];
98160484Sobrien	      size_t len = strlen (arg);
98260484Sobrien	      if (len >= 2 && arg[len-2] == '.'
98360484Sobrien	          && (arg[len-1] == 'o' || arg[len-1] == 'a'))
98460484Sobrien		{
98560484Sobrien		  int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
98677298Sobrien		  dyn_string_append_cstr (step_pre1,
98760484Sobrien				     (quote) ? " \"" : " ");
98877298Sobrien		  dyn_string_append_cstr (step_pre1, arg);
98977298Sobrien		  dyn_string_append_cstr (step_pre1,
99060484Sobrien				     (quote) ? "\"" : "");
99160484Sobrien		}
99260484Sobrien	    }
99360484Sobrien	}
99460484Sobrien
99560484Sobrien      if (run (dlltool_name, step_pre1->s))
99660484Sobrien	cleanup_and_exit (1);
99760484Sobrien
99860484Sobrien      dyn_string_delete (step_pre1);
99960484Sobrien    }
100060484Sobrien
100177298Sobrien  dyn_string_append_cstr (dlltool_cmdline, " --def ");
100277298Sobrien  dyn_string_append_cstr (dlltool_cmdline, def_file_name);
100360484Sobrien
100460484Sobrien  if (verbose)
100560484Sobrien    {
100660484Sobrien      fprintf (stderr, _("DLLTOOL name    : %s\n"), dlltool_name);
100760484Sobrien      fprintf (stderr, _("DLLTOOL options : %s\n"), dlltool_cmdline->s);
100860484Sobrien      fprintf (stderr, _("DRIVER name     : %s\n"), driver_name);
100960484Sobrien      fprintf (stderr, _("DRIVER options  : %s\n"), driver_cmdline->s);
101060484Sobrien    }
101160484Sobrien
101260484Sobrien  /*
101360484Sobrien   * Step 1. Call GCC/LD to create base relocation file. If using GCC, the
101460484Sobrien   * driver command line will look like the following:
101560484Sobrien   *
101660484Sobrien   *    % gcc -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
101760484Sobrien   *
101860484Sobrien   * If the user does not specify a base name, create temporary one that
101960484Sobrien   * is deleted at exit.
102060484Sobrien   *
102160484Sobrien   */
102260484Sobrien
102360484Sobrien  if (! base_file_name)
102460484Sobrien    {
102560484Sobrien      char *fileprefix = choose_temp_base ();
102660484Sobrien      base_file_name = (char *) xmalloc (strlen (fileprefix) + 6);
102760484Sobrien      sprintf (base_file_name, "%s.base",
102860484Sobrien               (dontdeltemps) ? mybasename (fileprefix) : fileprefix);
102960484Sobrien      delete_base_file = 1;
103060484Sobrien      free (fileprefix);
103160484Sobrien    }
103260484Sobrien
103360484Sobrien  {
103460484Sobrien    int quote;
103560484Sobrien
103660484Sobrien    dyn_string_t step1 = dyn_string_new (driver_cmdline->length
103760484Sobrien                                         + strlen (base_file_name)
103860484Sobrien				         + 20);
103977298Sobrien    dyn_string_append_cstr (step1, "-Wl,--base-file,");
104060484Sobrien    quote = (strchr (base_file_name, ' ')
104160484Sobrien             || strchr (base_file_name, '\t'));
104277298Sobrien    dyn_string_append_cstr (step1,
104360484Sobrien	               (quote) ? "\"" : "");
104477298Sobrien    dyn_string_append_cstr (step1, base_file_name);
104577298Sobrien    dyn_string_append_cstr (step1,
104660484Sobrien	               (quote) ? "\"" : "");
104760484Sobrien    if (driver_cmdline->length)
104860484Sobrien      {
104977298Sobrien        dyn_string_append_cstr (step1, " ");
105077298Sobrien        dyn_string_append_cstr (step1, driver_cmdline->s);
105160484Sobrien      }
105260484Sobrien
105360484Sobrien    if (run (driver_name, step1->s))
105460484Sobrien      cleanup_and_exit (1);
105560484Sobrien
105660484Sobrien    dyn_string_delete (step1);
105760484Sobrien  }
105860484Sobrien
105960484Sobrien
106060484Sobrien
106160484Sobrien  /*
106260484Sobrien   * Step 2. generate the exp file by running dlltool.
106360484Sobrien   * dlltool command line will look like the following:
106460484Sobrien   *
106560484Sobrien   *    % dlltool -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
106660484Sobrien   *
106760484Sobrien   * If the user does not specify a base name, create temporary one that
106860484Sobrien   * is deleted at exit.
106960484Sobrien   *
107060484Sobrien   */
107160484Sobrien
107260484Sobrien  if (! exp_file_name)
107360484Sobrien    {
107460484Sobrien      char *p = strrchr (dll_name, '.');
107560484Sobrien      size_t prefix_len = (p) ? p - dll_name : strlen (dll_name);
107660484Sobrien      exp_file_name = (char *) xmalloc (prefix_len + 4 + 1);
107760484Sobrien      strncpy (exp_file_name, dll_name, prefix_len);
107860484Sobrien      exp_file_name[prefix_len] = '\0';
107960484Sobrien      strcat (exp_file_name, ".exp");
108060484Sobrien      delete_exp_file = 1;
108160484Sobrien    }
108260484Sobrien
108360484Sobrien  {
108460484Sobrien    int quote;
108560484Sobrien    dyn_string_t step2 = dyn_string_new (dlltool_cmdline->length
108660484Sobrien                                         + strlen (base_file_name)
108760484Sobrien                                         + strlen (exp_file_name)
108860484Sobrien				         + 20);
108960484Sobrien
109077298Sobrien    dyn_string_append_cstr (step2, "--base-file ");
109160484Sobrien    quote = (strchr (base_file_name, ' ')
109260484Sobrien             || strchr (base_file_name, '\t'));
109377298Sobrien    dyn_string_append_cstr (step2,
109460484Sobrien	               (quote) ? "\"" : "");
109577298Sobrien    dyn_string_append_cstr (step2, base_file_name);
109677298Sobrien    dyn_string_append_cstr (step2,
109760484Sobrien	               (quote) ? "\" " : " ");
109860484Sobrien
109977298Sobrien    dyn_string_append_cstr (step2, "--output-exp ");
110060484Sobrien    quote = (strchr (exp_file_name, ' ')
110160484Sobrien             || strchr (exp_file_name, '\t'));
110277298Sobrien    dyn_string_append_cstr (step2,
110360484Sobrien	               (quote) ? "\"" : "");
110477298Sobrien    dyn_string_append_cstr (step2, exp_file_name);
110577298Sobrien    dyn_string_append_cstr (step2,
110660484Sobrien	               (quote) ? "\"" : "");
110760484Sobrien
110860484Sobrien    if (dlltool_cmdline->length)
110960484Sobrien      {
111077298Sobrien        dyn_string_append_cstr (step2, " ");
111177298Sobrien        dyn_string_append_cstr (step2, dlltool_cmdline->s);
111260484Sobrien      }
111360484Sobrien
111460484Sobrien    if (run (dlltool_name, step2->s))
111560484Sobrien      cleanup_and_exit (1);
111660484Sobrien
111760484Sobrien    dyn_string_delete (step2);
111860484Sobrien  }
111960484Sobrien
112060484Sobrien  /*
112160484Sobrien   * Step 3. Call GCC/LD to again, adding the exp file this time.
112260484Sobrien   * driver command line will look like the following:
112360484Sobrien   *
112460484Sobrien   *    % gcc -Wl,--dll --Wl,--base-file,foo.base foo.exp [rest ...]
112560484Sobrien   */
112660484Sobrien
112760484Sobrien  {
112860484Sobrien    int quote;
112960484Sobrien
113060484Sobrien    dyn_string_t step3 = dyn_string_new (driver_cmdline->length
113160484Sobrien                                         + strlen (exp_file_name)
113260484Sobrien                                         + strlen (base_file_name)
113360484Sobrien				         + 20);
113477298Sobrien    dyn_string_append_cstr (step3, "-Wl,--base-file,");
113560484Sobrien    quote = (strchr (base_file_name, ' ')
113660484Sobrien             || strchr (base_file_name, '\t'));
113777298Sobrien    dyn_string_append_cstr (step3,
113860484Sobrien	               (quote) ? "\"" : "");
113977298Sobrien    dyn_string_append_cstr (step3, base_file_name);
114077298Sobrien    dyn_string_append_cstr (step3,
114160484Sobrien	               (quote) ? "\" " : " ");
114260484Sobrien
114360484Sobrien    quote = (strchr (exp_file_name, ' ')
114460484Sobrien             || strchr (exp_file_name, '\t'));
114577298Sobrien    dyn_string_append_cstr (step3,
114660484Sobrien	               (quote) ? "\"" : "");
114777298Sobrien    dyn_string_append_cstr (step3, exp_file_name);
114877298Sobrien    dyn_string_append_cstr (step3,
114960484Sobrien	               (quote) ? "\"" : "");
115060484Sobrien
115160484Sobrien    if (driver_cmdline->length)
115260484Sobrien      {
115377298Sobrien        dyn_string_append_cstr (step3, " ");
115477298Sobrien        dyn_string_append_cstr (step3, driver_cmdline->s);
115560484Sobrien      }
115660484Sobrien
115760484Sobrien    if (run (driver_name, step3->s))
115860484Sobrien      cleanup_and_exit (1);
115960484Sobrien
116060484Sobrien    dyn_string_delete (step3);
116160484Sobrien  }
116260484Sobrien
116360484Sobrien
116460484Sobrien  /*
116560484Sobrien   * Step 4. Run DLLTOOL again using the same command line.
116660484Sobrien   */
116760484Sobrien
116860484Sobrien  {
116960484Sobrien    int quote;
117060484Sobrien    dyn_string_t step4 = dyn_string_new (dlltool_cmdline->length
117160484Sobrien                                         + strlen (base_file_name)
117260484Sobrien                                         + strlen (exp_file_name)
117360484Sobrien				         + 20);
117460484Sobrien
117577298Sobrien    dyn_string_append_cstr (step4, "--base-file ");
117660484Sobrien    quote = (strchr (base_file_name, ' ')
117760484Sobrien             || strchr (base_file_name, '\t'));
117877298Sobrien    dyn_string_append_cstr (step4,
117960484Sobrien	               (quote) ? "\"" : "");
118077298Sobrien    dyn_string_append_cstr (step4, base_file_name);
118177298Sobrien    dyn_string_append_cstr (step4,
118260484Sobrien	               (quote) ? "\" " : " ");
118360484Sobrien
118477298Sobrien    dyn_string_append_cstr (step4, "--output-exp ");
118560484Sobrien    quote = (strchr (exp_file_name, ' ')
118660484Sobrien             || strchr (exp_file_name, '\t'));
118777298Sobrien    dyn_string_append_cstr (step4,
118860484Sobrien	               (quote) ? "\"" : "");
118977298Sobrien    dyn_string_append_cstr (step4, exp_file_name);
119077298Sobrien    dyn_string_append_cstr (step4,
119160484Sobrien	               (quote) ? "\"" : "");
119260484Sobrien
119360484Sobrien    if (dlltool_cmdline->length)
119460484Sobrien      {
119577298Sobrien        dyn_string_append_cstr (step4, " ");
119677298Sobrien        dyn_string_append_cstr (step4, dlltool_cmdline->s);
119760484Sobrien      }
119860484Sobrien
119960484Sobrien    if (output_lib_file_name)
120060484Sobrien      {
120177298Sobrien        dyn_string_append_cstr (step4, " --output-lib ");
120277298Sobrien        dyn_string_append_cstr (step4, output_lib_file_name);
120360484Sobrien      }
120460484Sobrien
120560484Sobrien    if (run (dlltool_name, step4->s))
120660484Sobrien      cleanup_and_exit (1);
120760484Sobrien
120860484Sobrien    dyn_string_delete (step4);
120960484Sobrien  }
121060484Sobrien
121160484Sobrien
121260484Sobrien  /*
121360484Sobrien   * Step 5. Link it all together and be done with it.
121460484Sobrien   * driver command line will look like the following:
121560484Sobrien   *
121660484Sobrien   *    % gcc -Wl,--dll foo.exp [rest ...]
121760484Sobrien   *
121860484Sobrien   */
121960484Sobrien
122060484Sobrien  {
122160484Sobrien    int quote;
122260484Sobrien
122360484Sobrien    dyn_string_t step5 = dyn_string_new (driver_cmdline->length
122460484Sobrien                                         + strlen (exp_file_name)
122560484Sobrien				         + 20);
122660484Sobrien    quote = (strchr (exp_file_name, ' ')
122760484Sobrien             || strchr (exp_file_name, '\t'));
122877298Sobrien    dyn_string_append_cstr (step5,
122960484Sobrien	               (quote) ? "\"" : "");
123077298Sobrien    dyn_string_append_cstr (step5, exp_file_name);
123177298Sobrien    dyn_string_append_cstr (step5,
123260484Sobrien	               (quote) ? "\"" : "");
123360484Sobrien
123460484Sobrien    if (driver_cmdline->length)
123560484Sobrien      {
123677298Sobrien        dyn_string_append_cstr (step5, " ");
123777298Sobrien        dyn_string_append_cstr (step5, driver_cmdline->s);
123860484Sobrien      }
123960484Sobrien
124060484Sobrien    if (run (driver_name, step5->s))
124160484Sobrien      cleanup_and_exit (1);
124260484Sobrien
124360484Sobrien    dyn_string_delete (step5);
124460484Sobrien  }
124560484Sobrien
124660484Sobrien  cleanup_and_exit (0);
124760484Sobrien
124860484Sobrien  return 0;
124960484Sobrien}
1250