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