xref: /openbsd-src/gnu/usr.bin/binutils-2.17/binutils/dllwrap.c (revision d2386abe6d72afba906e28bc7357d44f31adee3f)
13d8817e4Smiod /* dllwrap.c -- wrapper for DLLTOOL and GCC to generate PE style DLLs
23d8817e4Smiod    Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
33d8817e4Smiod    Contributed by Mumit Khan (khan@xraylith.wisc.edu).
43d8817e4Smiod 
53d8817e4Smiod    This file is part of GNU Binutils.
63d8817e4Smiod 
73d8817e4Smiod    This program is free software; you can redistribute it and/or modify
83d8817e4Smiod    it under the terms of the GNU General Public License as published by
93d8817e4Smiod    the Free Software Foundation; either version 2 of the License, or
103d8817e4Smiod    (at your option) any later version.
113d8817e4Smiod 
123d8817e4Smiod    This program is distributed in the hope that it will be useful,
133d8817e4Smiod    but WITHOUT ANY WARRANTY; without even the implied warranty of
143d8817e4Smiod    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
153d8817e4Smiod    GNU General Public License for more details.
163d8817e4Smiod 
173d8817e4Smiod    You should have received a copy of the GNU General Public License
183d8817e4Smiod    along with this program; if not, write to the Free Software
193d8817e4Smiod    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
203d8817e4Smiod    02110-1301, USA.  */
213d8817e4Smiod 
223d8817e4Smiod /* AIX requires this to be the first thing in the file.  */
233d8817e4Smiod #ifndef __GNUC__
243d8817e4Smiod # ifdef _AIX
253d8817e4Smiod  #pragma alloca
263d8817e4Smiod #endif
273d8817e4Smiod #endif
283d8817e4Smiod 
293d8817e4Smiod #ifdef HAVE_CONFIG_H
303d8817e4Smiod #include "config.h"
313d8817e4Smiod #endif
323d8817e4Smiod 
333d8817e4Smiod #include "bfd.h"
343d8817e4Smiod #include "libiberty.h"
353d8817e4Smiod #include "bucomm.h"
363d8817e4Smiod #include "getopt.h"
373d8817e4Smiod #include "dyn-string.h"
383d8817e4Smiod 
393d8817e4Smiod #include <time.h>
403d8817e4Smiod #include <sys/stat.h>
413d8817e4Smiod #include <stdarg.h>
423d8817e4Smiod 
433d8817e4Smiod #ifdef HAVE_SYS_WAIT_H
443d8817e4Smiod #include <sys/wait.h>
453d8817e4Smiod #else /* ! HAVE_SYS_WAIT_H */
463d8817e4Smiod #if ! defined (_WIN32) || defined (__CYGWIN32__)
473d8817e4Smiod #ifndef WIFEXITED
483d8817e4Smiod #define WIFEXITED(w)	(((w)&0377) == 0)
493d8817e4Smiod #endif
503d8817e4Smiod #ifndef WIFSIGNALED
513d8817e4Smiod #define WIFSIGNALED(w)	(((w)&0377) != 0177 && ((w)&~0377) == 0)
523d8817e4Smiod #endif
533d8817e4Smiod #ifndef WTERMSIG
543d8817e4Smiod #define WTERMSIG(w)	((w) & 0177)
553d8817e4Smiod #endif
563d8817e4Smiod #ifndef WEXITSTATUS
573d8817e4Smiod #define WEXITSTATUS(w)	(((w) >> 8) & 0377)
583d8817e4Smiod #endif
593d8817e4Smiod #else /* defined (_WIN32) && ! defined (__CYGWIN32__) */
603d8817e4Smiod #ifndef WIFEXITED
613d8817e4Smiod #define WIFEXITED(w)	(((w) & 0xff) == 0)
623d8817e4Smiod #endif
633d8817e4Smiod #ifndef WIFSIGNALED
643d8817e4Smiod #define WIFSIGNALED(w)	(((w) & 0xff) != 0 && ((w) & 0xff) != 0x7f)
653d8817e4Smiod #endif
663d8817e4Smiod #ifndef WTERMSIG
673d8817e4Smiod #define WTERMSIG(w)	((w) & 0x7f)
683d8817e4Smiod #endif
693d8817e4Smiod #ifndef WEXITSTATUS
703d8817e4Smiod #define WEXITSTATUS(w)	(((w) & 0xff00) >> 8)
713d8817e4Smiod #endif
723d8817e4Smiod #endif /* defined (_WIN32) && ! defined (__CYGWIN32__) */
733d8817e4Smiod #endif /* ! HAVE_SYS_WAIT_H */
743d8817e4Smiod 
753d8817e4Smiod static char *driver_name = NULL;
763d8817e4Smiod static char *cygwin_driver_flags =
773d8817e4Smiod   "-Wl,--dll -nostartfiles";
783d8817e4Smiod static char *mingw32_driver_flags = "-mdll";
793d8817e4Smiod static char *generic_driver_flags = "-Wl,--dll";
803d8817e4Smiod 
813d8817e4Smiod static char *entry_point;
823d8817e4Smiod 
833d8817e4Smiod static char *dlltool_name = NULL;
843d8817e4Smiod 
853d8817e4Smiod static char *target = TARGET;
863d8817e4Smiod 
873d8817e4Smiod typedef enum {
883d8817e4Smiod   UNKNOWN_TARGET,
893d8817e4Smiod   CYGWIN_TARGET,
903d8817e4Smiod   MINGW_TARGET
913d8817e4Smiod }
923d8817e4Smiod target_type;
933d8817e4Smiod 
943d8817e4Smiod static target_type which_target = UNKNOWN_TARGET;
953d8817e4Smiod 
963d8817e4Smiod static int dontdeltemps = 0;
973d8817e4Smiod static int dry_run = 0;
983d8817e4Smiod 
993d8817e4Smiod static char *prog_name;
1003d8817e4Smiod 
1013d8817e4Smiod static int verbose = 0;
1023d8817e4Smiod 
1033d8817e4Smiod static char *dll_file_name;
1043d8817e4Smiod static char *dll_name;
1053d8817e4Smiod static char *base_file_name;
1063d8817e4Smiod static char *exp_file_name;
1073d8817e4Smiod static char *def_file_name;
1083d8817e4Smiod static int delete_base_file = 1;
1093d8817e4Smiod static int delete_exp_file = 1;
1103d8817e4Smiod static int delete_def_file = 1;
1113d8817e4Smiod 
1123d8817e4Smiod static int run (const char *, char *);
1133d8817e4Smiod static char *mybasename (const char *);
1143d8817e4Smiod static int strhash (const char *);
1153d8817e4Smiod static void usage (FILE *, int);
1163d8817e4Smiod static void display (const char *, va_list) ATTRIBUTE_PRINTF(1,0);
1173d8817e4Smiod static void inform (const char *, ...) ATTRIBUTE_PRINTF_1;
1183d8817e4Smiod static void warn (const char *, ...) ATTRIBUTE_PRINTF_1;
1193d8817e4Smiod static char *look_for_prog (const char *, const char *, int);
1203d8817e4Smiod static char *deduce_name (const char *);
1213d8817e4Smiod static void delete_temp_files (void);
1223d8817e4Smiod static void cleanup_and_exit (int);
1233d8817e4Smiod 
1243d8817e4Smiod /**********************************************************************/
1253d8817e4Smiod 
1263d8817e4Smiod /* Please keep the following 4 routines in sync with dlltool.c:
1273d8817e4Smiod      display ()
1283d8817e4Smiod      inform ()
1293d8817e4Smiod      look_for_prog ()
1303d8817e4Smiod      deduce_name ()
1313d8817e4Smiod    It's not worth the hassle to break these out since dllwrap will
1323d8817e4Smiod    (hopefully) soon be retired in favor of `ld --shared.  */
1333d8817e4Smiod 
1343d8817e4Smiod static void
display(const char * message,va_list args)1353d8817e4Smiod display (const char * message, va_list args)
1363d8817e4Smiod {
1373d8817e4Smiod   if (prog_name != NULL)
1383d8817e4Smiod     fprintf (stderr, "%s: ", prog_name);
1393d8817e4Smiod 
1403d8817e4Smiod   vfprintf (stderr, message, args);
1413d8817e4Smiod   fputc ('\n', stderr);
1423d8817e4Smiod }
1433d8817e4Smiod 
1443d8817e4Smiod 
1453d8817e4Smiod static void
inform(const char * message,...)1463d8817e4Smiod inform VPARAMS ((const char *message, ...))
1473d8817e4Smiod {
1483d8817e4Smiod   VA_OPEN (args, message);
1493d8817e4Smiod   VA_FIXEDARG (args, const char *, message);
1503d8817e4Smiod 
1513d8817e4Smiod   if (!verbose)
1523d8817e4Smiod     return;
1533d8817e4Smiod 
1543d8817e4Smiod   display (message, args);
1553d8817e4Smiod 
1563d8817e4Smiod   VA_CLOSE (args);
1573d8817e4Smiod }
1583d8817e4Smiod 
1593d8817e4Smiod static void
warn(const char * format,...)1603d8817e4Smiod warn VPARAMS ((const char *format, ...))
1613d8817e4Smiod {
1623d8817e4Smiod   VA_OPEN (args, format);
1633d8817e4Smiod   VA_FIXEDARG (args, const char *, format);
1643d8817e4Smiod 
1653d8817e4Smiod   display (format, args);
1663d8817e4Smiod 
1673d8817e4Smiod   VA_CLOSE (args);
1683d8817e4Smiod }
1693d8817e4Smiod 
1703d8817e4Smiod /* Look for the program formed by concatenating PROG_NAME and the
1713d8817e4Smiod    string running from PREFIX to END_PREFIX.  If the concatenated
1723d8817e4Smiod    string contains a '/', try appending EXECUTABLE_SUFFIX if it is
1733d8817e4Smiod    appropriate.  */
1743d8817e4Smiod 
1753d8817e4Smiod static char *
look_for_prog(const char * prog_name,const char * prefix,int end_prefix)1763d8817e4Smiod look_for_prog (const char *prog_name, const char *prefix, int end_prefix)
1773d8817e4Smiod {
1783d8817e4Smiod   struct stat s;
1793d8817e4Smiod   char *cmd;
1803d8817e4Smiod 
1813d8817e4Smiod   cmd = xmalloc (strlen (prefix)
1823d8817e4Smiod 		 + strlen (prog_name)
1833d8817e4Smiod #ifdef HAVE_EXECUTABLE_SUFFIX
1843d8817e4Smiod 		 + strlen (EXECUTABLE_SUFFIX)
1853d8817e4Smiod #endif
1863d8817e4Smiod 		 + 10);
1873d8817e4Smiod   strcpy (cmd, prefix);
1883d8817e4Smiod 
1893d8817e4Smiod   sprintf (cmd + end_prefix, "%s", prog_name);
1903d8817e4Smiod 
1913d8817e4Smiod   if (strchr (cmd, '/') != NULL)
1923d8817e4Smiod     {
1933d8817e4Smiod       int found;
1943d8817e4Smiod 
1953d8817e4Smiod       found = (stat (cmd, &s) == 0
1963d8817e4Smiod #ifdef HAVE_EXECUTABLE_SUFFIX
1973d8817e4Smiod 	       || stat (strcat (cmd, EXECUTABLE_SUFFIX), &s) == 0
1983d8817e4Smiod #endif
1993d8817e4Smiod 	       );
2003d8817e4Smiod 
2013d8817e4Smiod       if (! found)
2023d8817e4Smiod 	{
2033d8817e4Smiod 	  /* xgettext:c-format */
2043d8817e4Smiod 	  inform (_("Tried file: %s"), cmd);
2053d8817e4Smiod 	  free (cmd);
2063d8817e4Smiod 	  return NULL;
2073d8817e4Smiod 	}
2083d8817e4Smiod     }
2093d8817e4Smiod 
2103d8817e4Smiod   /* xgettext:c-format */
2113d8817e4Smiod   inform (_("Using file: %s"), cmd);
2123d8817e4Smiod 
2133d8817e4Smiod   return cmd;
2143d8817e4Smiod }
2153d8817e4Smiod 
2163d8817e4Smiod /* Deduce the name of the program we are want to invoke.
2173d8817e4Smiod    PROG_NAME is the basic name of the program we want to run,
2183d8817e4Smiod    eg "as" or "ld".  The catch is that we might want actually
2193d8817e4Smiod    run "i386-pe-as" or "ppc-pe-ld".
2203d8817e4Smiod 
2213d8817e4Smiod    If argv[0] contains the full path, then try to find the program
2223d8817e4Smiod    in the same place, with and then without a target-like prefix.
2233d8817e4Smiod 
2243d8817e4Smiod    Given, argv[0] = /usr/local/bin/i586-cygwin32-dlltool,
2253d8817e4Smiod    deduce_name("as") uses the following search order:
2263d8817e4Smiod 
2273d8817e4Smiod      /usr/local/bin/i586-cygwin32-as
2283d8817e4Smiod      /usr/local/bin/as
2293d8817e4Smiod      as
2303d8817e4Smiod 
2313d8817e4Smiod    If there's an EXECUTABLE_SUFFIX, it'll use that as well; for each
2323d8817e4Smiod    name, it'll try without and then with EXECUTABLE_SUFFIX.
2333d8817e4Smiod 
2343d8817e4Smiod    Given, argv[0] = i586-cygwin32-dlltool, it will not even try "as"
2353d8817e4Smiod    as the fallback, but rather return i586-cygwin32-as.
2363d8817e4Smiod 
2373d8817e4Smiod    Oh, and given, argv[0] = dlltool, it'll return "as".
2383d8817e4Smiod 
2393d8817e4Smiod    Returns a dynamically allocated string.  */
2403d8817e4Smiod 
2413d8817e4Smiod static char *
deduce_name(const char * name)2423d8817e4Smiod deduce_name (const char * name)
2433d8817e4Smiod {
2443d8817e4Smiod   char *cmd;
2453d8817e4Smiod   const char *dash;
2463d8817e4Smiod   const char *slash;
2473d8817e4Smiod   const char *cp;
2483d8817e4Smiod 
2493d8817e4Smiod   dash = NULL;
2503d8817e4Smiod   slash = NULL;
2513d8817e4Smiod   for (cp = prog_name; *cp != '\0'; ++cp)
2523d8817e4Smiod     {
2533d8817e4Smiod       if (*cp == '-')
2543d8817e4Smiod 	dash = cp;
2553d8817e4Smiod 
2563d8817e4Smiod       if (
2573d8817e4Smiod #if defined(__DJGPP__) || defined (__CYGWIN__) || defined(__WIN32__)
2583d8817e4Smiod 	  *cp == ':' || *cp == '\\' ||
2593d8817e4Smiod #endif
2603d8817e4Smiod 	  *cp == '/')
2613d8817e4Smiod 	{
2623d8817e4Smiod 	  slash = cp;
2633d8817e4Smiod 	  dash = NULL;
2643d8817e4Smiod 	}
2653d8817e4Smiod     }
2663d8817e4Smiod 
2673d8817e4Smiod   cmd = NULL;
2683d8817e4Smiod 
2693d8817e4Smiod   if (dash != NULL)
2703d8817e4Smiod     /* First, try looking for a prefixed NAME in the
2713d8817e4Smiod        PROG_NAME directory, with the same prefix as PROG_NAME.  */
2723d8817e4Smiod     cmd = look_for_prog (name, prog_name, dash - prog_name + 1);
2733d8817e4Smiod 
2743d8817e4Smiod   if (slash != NULL && cmd == NULL)
2753d8817e4Smiod     /* Next, try looking for a NAME in the same directory as
2763d8817e4Smiod        that of this program.  */
2773d8817e4Smiod     cmd = look_for_prog (name, prog_name, slash - prog_name + 1);
2783d8817e4Smiod 
2793d8817e4Smiod   if (cmd == NULL)
2803d8817e4Smiod     /* Just return NAME as is.  */
2813d8817e4Smiod     cmd = xstrdup (name);
2823d8817e4Smiod 
2833d8817e4Smiod   return cmd;
2843d8817e4Smiod }
2853d8817e4Smiod 
2863d8817e4Smiod static void
delete_temp_files(void)2873d8817e4Smiod delete_temp_files (void)
2883d8817e4Smiod {
2893d8817e4Smiod   if (delete_base_file && base_file_name)
2903d8817e4Smiod     {
2913d8817e4Smiod       if (verbose)
2923d8817e4Smiod 	{
2933d8817e4Smiod 	  if (dontdeltemps)
2943d8817e4Smiod 	    warn (_("Keeping temporary base file %s"), base_file_name);
2953d8817e4Smiod 	  else
2963d8817e4Smiod 	    warn (_("Deleting temporary base file %s"), base_file_name);
2973d8817e4Smiod 	}
2983d8817e4Smiod       if (! dontdeltemps)
2993d8817e4Smiod 	{
3003d8817e4Smiod 	  unlink (base_file_name);
3013d8817e4Smiod 	  free (base_file_name);
3023d8817e4Smiod 	}
3033d8817e4Smiod     }
3043d8817e4Smiod 
3053d8817e4Smiod   if (delete_exp_file && exp_file_name)
3063d8817e4Smiod     {
3073d8817e4Smiod       if (verbose)
3083d8817e4Smiod 	{
3093d8817e4Smiod 	  if (dontdeltemps)
3103d8817e4Smiod 	    warn (_("Keeping temporary exp file %s"), exp_file_name);
3113d8817e4Smiod 	  else
3123d8817e4Smiod 	    warn (_("Deleting temporary exp file %s"), exp_file_name);
3133d8817e4Smiod 	}
3143d8817e4Smiod       if (! dontdeltemps)
3153d8817e4Smiod 	{
3163d8817e4Smiod 	  unlink (exp_file_name);
3173d8817e4Smiod 	  free (exp_file_name);
3183d8817e4Smiod 	}
3193d8817e4Smiod     }
3203d8817e4Smiod   if (delete_def_file && def_file_name)
3213d8817e4Smiod     {
3223d8817e4Smiod       if (verbose)
3233d8817e4Smiod 	{
3243d8817e4Smiod 	  if (dontdeltemps)
3253d8817e4Smiod 	    warn (_("Keeping temporary def file %s"), def_file_name);
3263d8817e4Smiod 	  else
3273d8817e4Smiod 	    warn (_("Deleting temporary def file %s"), def_file_name);
3283d8817e4Smiod 	}
3293d8817e4Smiod       if (! dontdeltemps)
3303d8817e4Smiod 	{
3313d8817e4Smiod 	  unlink (def_file_name);
3323d8817e4Smiod 	  free (def_file_name);
3333d8817e4Smiod 	}
3343d8817e4Smiod     }
3353d8817e4Smiod }
3363d8817e4Smiod 
3373d8817e4Smiod static void
cleanup_and_exit(int status)3383d8817e4Smiod cleanup_and_exit (int status)
3393d8817e4Smiod {
3403d8817e4Smiod   delete_temp_files ();
3413d8817e4Smiod   exit (status);
3423d8817e4Smiod }
3433d8817e4Smiod 
3443d8817e4Smiod static int
run(const char * what,char * args)3453d8817e4Smiod run (const char *what, char *args)
3463d8817e4Smiod {
3473d8817e4Smiod   char *s;
3483d8817e4Smiod   int pid, wait_status, retcode;
3493d8817e4Smiod   int i;
3503d8817e4Smiod   const char **argv;
3513d8817e4Smiod   char *errmsg_fmt, *errmsg_arg;
352*d2386abeSmiod #if defined(__MSDOS__) && !defined(__GO32__)
3533d8817e4Smiod   char *temp_base = choose_temp_base ();
354*d2386abeSmiod #else
355*d2386abeSmiod   char *temp_base = NULL;
356*d2386abeSmiod #endif
3573d8817e4Smiod   int in_quote;
3583d8817e4Smiod   char sep;
3593d8817e4Smiod 
3603d8817e4Smiod   if (verbose || dry_run)
3613d8817e4Smiod     fprintf (stderr, "%s %s\n", what, args);
3623d8817e4Smiod 
3633d8817e4Smiod   /* Count the args */
3643d8817e4Smiod   i = 0;
3653d8817e4Smiod   for (s = args; *s; s++)
3663d8817e4Smiod     if (*s == ' ')
3673d8817e4Smiod       i++;
3683d8817e4Smiod   i++;
3693d8817e4Smiod   argv = alloca (sizeof (char *) * (i + 3));
3703d8817e4Smiod   i = 0;
3713d8817e4Smiod   argv[i++] = what;
3723d8817e4Smiod   s = args;
3733d8817e4Smiod   while (1)
3743d8817e4Smiod     {
3753d8817e4Smiod       while (*s == ' ' && *s != 0)
3763d8817e4Smiod 	s++;
3773d8817e4Smiod       if (*s == 0)
3783d8817e4Smiod 	break;
3793d8817e4Smiod       in_quote = (*s == '\'' || *s == '"');
3803d8817e4Smiod       sep = (in_quote) ? *s++ : ' ';
3813d8817e4Smiod       argv[i++] = s;
3823d8817e4Smiod       while (*s != sep && *s != 0)
3833d8817e4Smiod 	s++;
3843d8817e4Smiod       if (*s == 0)
3853d8817e4Smiod 	break;
3863d8817e4Smiod       *s++ = 0;
3873d8817e4Smiod       if (in_quote)
3883d8817e4Smiod 	s++;
3893d8817e4Smiod     }
3903d8817e4Smiod   argv[i++] = NULL;
3913d8817e4Smiod 
3923d8817e4Smiod   if (dry_run)
3933d8817e4Smiod     return 0;
3943d8817e4Smiod 
3953d8817e4Smiod   pid = pexecute (argv[0], (char * const *) argv, prog_name, temp_base,
3963d8817e4Smiod 		  &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
3973d8817e4Smiod 
3983d8817e4Smiod   if (pid == -1)
3993d8817e4Smiod     {
4003d8817e4Smiod       int errno_val = errno;
4013d8817e4Smiod 
4023d8817e4Smiod       fprintf (stderr, "%s: ", prog_name);
4033d8817e4Smiod       fprintf (stderr, errmsg_fmt, errmsg_arg);
4043d8817e4Smiod       fprintf (stderr, ": %s\n", strerror (errno_val));
4053d8817e4Smiod       return 1;
4063d8817e4Smiod     }
4073d8817e4Smiod 
4083d8817e4Smiod   retcode = 0;
4093d8817e4Smiod   pid = pwait (pid, &wait_status, 0);
4103d8817e4Smiod   if (pid == -1)
4113d8817e4Smiod     {
4123d8817e4Smiod       warn ("wait: %s", strerror (errno));
4133d8817e4Smiod       retcode = 1;
4143d8817e4Smiod     }
4153d8817e4Smiod   else if (WIFSIGNALED (wait_status))
4163d8817e4Smiod     {
4173d8817e4Smiod       warn (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
4183d8817e4Smiod       retcode = 1;
4193d8817e4Smiod     }
4203d8817e4Smiod   else if (WIFEXITED (wait_status))
4213d8817e4Smiod     {
4223d8817e4Smiod       if (WEXITSTATUS (wait_status) != 0)
4233d8817e4Smiod 	{
4243d8817e4Smiod 	  warn (_("%s exited with status %d"), what, WEXITSTATUS (wait_status));
4253d8817e4Smiod 	  retcode = 1;
4263d8817e4Smiod 	}
4273d8817e4Smiod     }
4283d8817e4Smiod   else
4293d8817e4Smiod     retcode = 1;
4303d8817e4Smiod 
4313d8817e4Smiod   return retcode;
4323d8817e4Smiod }
4333d8817e4Smiod 
4343d8817e4Smiod static char *
mybasename(const char * name)4353d8817e4Smiod mybasename (const char *name)
4363d8817e4Smiod {
4373d8817e4Smiod   const char *base = name;
4383d8817e4Smiod 
4393d8817e4Smiod   while (*name)
4403d8817e4Smiod     {
4413d8817e4Smiod       if (*name == '/' || *name == '\\')
4423d8817e4Smiod 	{
4433d8817e4Smiod 	  base = name + 1;
4443d8817e4Smiod 	}
4453d8817e4Smiod       ++name;
4463d8817e4Smiod     }
4473d8817e4Smiod   return (char *) base;
4483d8817e4Smiod }
4493d8817e4Smiod 
4503d8817e4Smiod static int
strhash(const char * str)4513d8817e4Smiod strhash (const char *str)
4523d8817e4Smiod {
4533d8817e4Smiod   const unsigned char *s;
4543d8817e4Smiod   unsigned long hash;
4553d8817e4Smiod   unsigned int c;
4563d8817e4Smiod   unsigned int len;
4573d8817e4Smiod 
4583d8817e4Smiod   hash = 0;
4593d8817e4Smiod   len = 0;
4603d8817e4Smiod   s = (const unsigned char *) str;
4613d8817e4Smiod   while ((c = *s++) != '\0')
4623d8817e4Smiod     {
4633d8817e4Smiod       hash += c + (c << 17);
4643d8817e4Smiod       hash ^= hash >> 2;
4653d8817e4Smiod       ++len;
4663d8817e4Smiod     }
4673d8817e4Smiod   hash += len + (len << 17);
4683d8817e4Smiod   hash ^= hash >> 2;
4693d8817e4Smiod 
4703d8817e4Smiod   return hash;
4713d8817e4Smiod }
4723d8817e4Smiod 
4733d8817e4Smiod /**********************************************************************/
4743d8817e4Smiod 
4753d8817e4Smiod static void
usage(FILE * file,int status)4763d8817e4Smiod usage (FILE *file, int status)
4773d8817e4Smiod {
4783d8817e4Smiod   fprintf (file, _("Usage %s <option(s)> <object-file(s)>\n"), prog_name);
4793d8817e4Smiod   fprintf (file, _("  Generic options:\n"));
4803d8817e4Smiod   fprintf (file, _("   @<file>                Read options from <file>\n"));
4813d8817e4Smiod   fprintf (file, _("   --quiet, -q            Work quietly\n"));
4823d8817e4Smiod   fprintf (file, _("   --verbose, -v          Verbose\n"));
4833d8817e4Smiod   fprintf (file, _("   --version              Print dllwrap version\n"));
4843d8817e4Smiod   fprintf (file, _("   --implib <outname>     Synonym for --output-lib\n"));
4853d8817e4Smiod   fprintf (file, _("  Options for %s:\n"), prog_name);
4863d8817e4Smiod   fprintf (file, _("   --driver-name <driver> Defaults to \"gcc\"\n"));
4873d8817e4Smiod   fprintf (file, _("   --driver-flags <flags> Override default ld flags\n"));
4883d8817e4Smiod   fprintf (file, _("   --dlltool-name <dlltool> Defaults to \"dlltool\"\n"));
4893d8817e4Smiod   fprintf (file, _("   --entry <entry>        Specify alternate DLL entry point\n"));
4903d8817e4Smiod   fprintf (file, _("   --image-base <base>    Specify image base address\n"));
4913d8817e4Smiod   fprintf (file, _("   --target <machine>     i386-cygwin32 or i386-mingw32\n"));
4923d8817e4Smiod   fprintf (file, _("   --dry-run              Show what needs to be run\n"));
4933d8817e4Smiod   fprintf (file, _("   --mno-cygwin           Create Mingw DLL\n"));
4943d8817e4Smiod   fprintf (file, _("  Options passed to DLLTOOL:\n"));
4953d8817e4Smiod   fprintf (file, _("   --machine <machine>\n"));
4963d8817e4Smiod   fprintf (file, _("   --output-exp <outname> Generate export file.\n"));
4973d8817e4Smiod   fprintf (file, _("   --output-lib <outname> Generate input library.\n"));
4983d8817e4Smiod   fprintf (file, _("   --add-indirect         Add dll indirects to export file.\n"));
4993d8817e4Smiod   fprintf (file, _("   --dllname <name>       Name of input dll to put into output lib.\n"));
5003d8817e4Smiod   fprintf (file, _("   --def <deffile>        Name input .def file\n"));
5013d8817e4Smiod   fprintf (file, _("   --output-def <deffile> Name output .def file\n"));
5023d8817e4Smiod   fprintf (file, _("   --export-all-symbols     Export all symbols to .def\n"));
5033d8817e4Smiod   fprintf (file, _("   --no-export-all-symbols  Only export .drectve symbols\n"));
5043d8817e4Smiod   fprintf (file, _("   --exclude-symbols <list> Exclude <list> from .def\n"));
5053d8817e4Smiod   fprintf (file, _("   --no-default-excludes    Zap default exclude symbols\n"));
5063d8817e4Smiod   fprintf (file, _("   --base-file <basefile> Read linker generated base file\n"));
5073d8817e4Smiod   fprintf (file, _("   --no-idata4           Don't generate idata$4 section\n"));
5083d8817e4Smiod   fprintf (file, _("   --no-idata5           Don't generate idata$5 section\n"));
5093d8817e4Smiod   fprintf (file, _("   -U                     Add underscores to .lib\n"));
5103d8817e4Smiod   fprintf (file, _("   -k                     Kill @<n> from exported names\n"));
5113d8817e4Smiod   fprintf (file, _("   --add-stdcall-alias    Add aliases without @<n>\n"));
5123d8817e4Smiod   fprintf (file, _("   --as <name>            Use <name> for assembler\n"));
5133d8817e4Smiod   fprintf (file, _("   --nodelete             Keep temp files.\n"));
5143d8817e4Smiod   fprintf (file, _("  Rest are passed unmodified to the language driver\n"));
5153d8817e4Smiod   fprintf (file, "\n\n");
5163d8817e4Smiod   exit (status);
5173d8817e4Smiod }
5183d8817e4Smiod 
5193d8817e4Smiod #define OPTION_START		149
5203d8817e4Smiod 
5213d8817e4Smiod /* GENERIC options.  */
5223d8817e4Smiod #define OPTION_QUIET		(OPTION_START + 1)
5233d8817e4Smiod #define OPTION_VERBOSE		(OPTION_QUIET + 1)
5243d8817e4Smiod #define OPTION_VERSION		(OPTION_VERBOSE + 1)
5253d8817e4Smiod 
5263d8817e4Smiod /* DLLWRAP options.  */
5273d8817e4Smiod #define OPTION_DRY_RUN		(OPTION_VERSION + 1)
5283d8817e4Smiod #define OPTION_DRIVER_NAME	(OPTION_DRY_RUN + 1)
5293d8817e4Smiod #define OPTION_DRIVER_FLAGS	(OPTION_DRIVER_NAME + 1)
5303d8817e4Smiod #define OPTION_DLLTOOL_NAME	(OPTION_DRIVER_FLAGS + 1)
5313d8817e4Smiod #define OPTION_ENTRY		(OPTION_DLLTOOL_NAME + 1)
5323d8817e4Smiod #define OPTION_IMAGE_BASE	(OPTION_ENTRY + 1)
5333d8817e4Smiod #define OPTION_TARGET		(OPTION_IMAGE_BASE + 1)
5343d8817e4Smiod #define OPTION_MNO_CYGWIN	(OPTION_TARGET + 1)
5353d8817e4Smiod 
5363d8817e4Smiod /* DLLTOOL options.  */
5373d8817e4Smiod #define OPTION_NODELETE		(OPTION_MNO_CYGWIN + 1)
5383d8817e4Smiod #define OPTION_DLLNAME		(OPTION_NODELETE + 1)
5393d8817e4Smiod #define OPTION_NO_IDATA4	(OPTION_DLLNAME + 1)
5403d8817e4Smiod #define OPTION_NO_IDATA5	(OPTION_NO_IDATA4 + 1)
5413d8817e4Smiod #define OPTION_OUTPUT_EXP	(OPTION_NO_IDATA5 + 1)
5423d8817e4Smiod #define OPTION_OUTPUT_DEF	(OPTION_OUTPUT_EXP + 1)
5433d8817e4Smiod #define OPTION_EXPORT_ALL_SYMS	(OPTION_OUTPUT_DEF + 1)
5443d8817e4Smiod #define OPTION_NO_EXPORT_ALL_SYMS (OPTION_EXPORT_ALL_SYMS + 1)
5453d8817e4Smiod #define OPTION_EXCLUDE_SYMS	(OPTION_NO_EXPORT_ALL_SYMS + 1)
5463d8817e4Smiod #define OPTION_NO_DEFAULT_EXCLUDES (OPTION_EXCLUDE_SYMS + 1)
5473d8817e4Smiod #define OPTION_OUTPUT_LIB	(OPTION_NO_DEFAULT_EXCLUDES + 1)
5483d8817e4Smiod #define OPTION_DEF		(OPTION_OUTPUT_LIB + 1)
5493d8817e4Smiod #define OPTION_ADD_UNDERSCORE	(OPTION_DEF + 1)
5503d8817e4Smiod #define OPTION_KILLAT		(OPTION_ADD_UNDERSCORE + 1)
5513d8817e4Smiod #define OPTION_HELP		(OPTION_KILLAT + 1)
5523d8817e4Smiod #define OPTION_MACHINE		(OPTION_HELP + 1)
5533d8817e4Smiod #define OPTION_ADD_INDIRECT	(OPTION_MACHINE + 1)
5543d8817e4Smiod #define OPTION_BASE_FILE	(OPTION_ADD_INDIRECT + 1)
5553d8817e4Smiod #define OPTION_AS		(OPTION_BASE_FILE + 1)
5563d8817e4Smiod 
5573d8817e4Smiod static const struct option long_options[] =
5583d8817e4Smiod {
5593d8817e4Smiod   /* generic options.  */
5603d8817e4Smiod   {"quiet", no_argument, NULL, 'q'},
5613d8817e4Smiod   {"verbose", no_argument, NULL, 'v'},
5623d8817e4Smiod   {"version", no_argument, NULL, OPTION_VERSION},
5633d8817e4Smiod   {"implib", required_argument, NULL, OPTION_OUTPUT_LIB},
5643d8817e4Smiod 
5653d8817e4Smiod   /* dllwrap options.  */
5663d8817e4Smiod   {"dry-run", no_argument, NULL, OPTION_DRY_RUN},
5673d8817e4Smiod   {"driver-name", required_argument, NULL, OPTION_DRIVER_NAME},
5683d8817e4Smiod   {"driver-flags", required_argument, NULL, OPTION_DRIVER_FLAGS},
5693d8817e4Smiod   {"dlltool-name", required_argument, NULL, OPTION_DLLTOOL_NAME},
5703d8817e4Smiod   {"entry", required_argument, NULL, 'e'},
5713d8817e4Smiod   {"image-base", required_argument, NULL, OPTION_IMAGE_BASE},
5723d8817e4Smiod   {"target", required_argument, NULL, OPTION_TARGET},
5733d8817e4Smiod 
5743d8817e4Smiod   /* dlltool options.  */
5753d8817e4Smiod   {"no-delete", no_argument, NULL, 'n'},
5763d8817e4Smiod   {"dllname", required_argument, NULL, OPTION_DLLNAME},
5773d8817e4Smiod   {"no-idata4", no_argument, NULL, OPTION_NO_IDATA4},
5783d8817e4Smiod   {"no-idata5", no_argument, NULL, OPTION_NO_IDATA5},
5793d8817e4Smiod   {"output-exp", required_argument, NULL, OPTION_OUTPUT_EXP},
5803d8817e4Smiod   {"output-def", required_argument, NULL, OPTION_OUTPUT_DEF},
5813d8817e4Smiod   {"export-all-symbols", no_argument, NULL, OPTION_EXPORT_ALL_SYMS},
5823d8817e4Smiod   {"no-export-all-symbols", no_argument, NULL, OPTION_NO_EXPORT_ALL_SYMS},
5833d8817e4Smiod   {"exclude-symbols", required_argument, NULL, OPTION_EXCLUDE_SYMS},
5843d8817e4Smiod   {"no-default-excludes", no_argument, NULL, OPTION_NO_DEFAULT_EXCLUDES},
5853d8817e4Smiod   {"output-lib", required_argument, NULL, OPTION_OUTPUT_LIB},
5863d8817e4Smiod   {"def", required_argument, NULL, OPTION_DEF},
5873d8817e4Smiod   {"add-underscore", no_argument, NULL, 'U'},
5883d8817e4Smiod   {"killat", no_argument, NULL, 'k'},
5893d8817e4Smiod   {"add-stdcall-alias", no_argument, NULL, 'A'},
5903d8817e4Smiod   {"help", no_argument, NULL, 'h'},
5913d8817e4Smiod   {"machine", required_argument, NULL, OPTION_MACHINE},
5923d8817e4Smiod   {"add-indirect", no_argument, NULL, OPTION_ADD_INDIRECT},
5933d8817e4Smiod   {"base-file", required_argument, NULL, OPTION_BASE_FILE},
5943d8817e4Smiod   {"as", required_argument, NULL, OPTION_AS},
5953d8817e4Smiod   {0, 0, 0, 0}
5963d8817e4Smiod };
5973d8817e4Smiod 
5983d8817e4Smiod int main (int, char **);
5993d8817e4Smiod 
6003d8817e4Smiod int
main(int argc,char ** argv)6013d8817e4Smiod main (int argc, char **argv)
6023d8817e4Smiod {
6033d8817e4Smiod   int c;
6043d8817e4Smiod   int i;
6053d8817e4Smiod 
6063d8817e4Smiod   char **saved_argv = 0;
6073d8817e4Smiod   int cmdline_len = 0;
6083d8817e4Smiod 
6093d8817e4Smiod   int export_all = 0;
6103d8817e4Smiod 
6113d8817e4Smiod   int *dlltool_arg_indices;
6123d8817e4Smiod   int *driver_arg_indices;
6133d8817e4Smiod 
6143d8817e4Smiod   char *driver_flags = 0;
6153d8817e4Smiod   char *output_lib_file_name = 0;
6163d8817e4Smiod 
6173d8817e4Smiod   dyn_string_t dlltool_cmdline;
6183d8817e4Smiod   dyn_string_t driver_cmdline;
6193d8817e4Smiod 
6203d8817e4Smiod   int def_file_seen = 0;
6213d8817e4Smiod 
6223d8817e4Smiod   char *image_base_str = 0;
6233d8817e4Smiod 
6243d8817e4Smiod   prog_name = argv[0];
6253d8817e4Smiod 
6263d8817e4Smiod #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
6273d8817e4Smiod   setlocale (LC_MESSAGES, "");
6283d8817e4Smiod #endif
6293d8817e4Smiod #if defined (HAVE_SETLOCALE)
6303d8817e4Smiod   setlocale (LC_CTYPE, "");
6313d8817e4Smiod #endif
6323d8817e4Smiod   bindtextdomain (PACKAGE, LOCALEDIR);
6333d8817e4Smiod   textdomain (PACKAGE);
6343d8817e4Smiod 
6353d8817e4Smiod   expandargv (&argc, &argv);
6363d8817e4Smiod 
6373d8817e4Smiod   saved_argv = (char **) xmalloc (argc * sizeof (char*));
6383d8817e4Smiod   dlltool_arg_indices = (int *) xmalloc (argc * sizeof (int));
6393d8817e4Smiod   driver_arg_indices = (int *) xmalloc (argc * sizeof (int));
6403d8817e4Smiod   for (i = 0; i < argc; ++i)
6413d8817e4Smiod     {
6423d8817e4Smiod       size_t len = strlen (argv[i]);
6433d8817e4Smiod       char *arg = (char *) xmalloc (len + 1);
6443d8817e4Smiod       strcpy (arg, argv[i]);
6453d8817e4Smiod       cmdline_len += len;
6463d8817e4Smiod       saved_argv[i] = arg;
6473d8817e4Smiod       dlltool_arg_indices[i] = 0;
6483d8817e4Smiod       driver_arg_indices[i] = 1;
6493d8817e4Smiod     }
6503d8817e4Smiod   cmdline_len++;
6513d8817e4Smiod 
6523d8817e4Smiod   /* We recognize dllwrap and dlltool options, and everything else is
6533d8817e4Smiod      passed onto the language driver (eg., to GCC). We collect options
6543d8817e4Smiod      to dlltool and driver in dlltool_args and driver_args.  */
6553d8817e4Smiod 
6563d8817e4Smiod   opterr = 0;
6573d8817e4Smiod   while ((c = getopt_long_only (argc, argv, "nkAqve:Uho:l:L:I:",
6583d8817e4Smiod 				long_options, (int *) 0)) != EOF)
6593d8817e4Smiod     {
6603d8817e4Smiod       int dlltool_arg;
6613d8817e4Smiod       int driver_arg;
6623d8817e4Smiod       int single_word_option_value_pair;
6633d8817e4Smiod 
6643d8817e4Smiod       dlltool_arg = 0;
6653d8817e4Smiod       driver_arg = 1;
6663d8817e4Smiod       single_word_option_value_pair = 0;
6673d8817e4Smiod 
6683d8817e4Smiod       if (c != '?')
6693d8817e4Smiod 	{
6703d8817e4Smiod 	  /* We recognize this option, so it has to be either dllwrap or
6713d8817e4Smiod 	     dlltool option. Do not pass to driver unless it's one of the
6723d8817e4Smiod 	     generic options that are passed to all the tools (such as -v)
6733d8817e4Smiod 	     which are dealt with later.  */
6743d8817e4Smiod 	  driver_arg = 0;
6753d8817e4Smiod 	}
6763d8817e4Smiod 
6773d8817e4Smiod       /* deal with generic and dllwrap options first.  */
6783d8817e4Smiod       switch (c)
6793d8817e4Smiod 	{
6803d8817e4Smiod 	case 'h':
6813d8817e4Smiod 	  usage (stdout, 0);
6823d8817e4Smiod 	  break;
6833d8817e4Smiod 	case 'q':
6843d8817e4Smiod 	  verbose = 0;
6853d8817e4Smiod 	  break;
6863d8817e4Smiod 	case 'v':
6873d8817e4Smiod 	  verbose = 1;
6883d8817e4Smiod 	  break;
6893d8817e4Smiod 	case OPTION_VERSION:
6903d8817e4Smiod 	  print_version (prog_name);
6913d8817e4Smiod 	  break;
6923d8817e4Smiod 	case 'e':
6933d8817e4Smiod 	  entry_point = optarg;
6943d8817e4Smiod 	  break;
6953d8817e4Smiod 	case OPTION_IMAGE_BASE:
6963d8817e4Smiod 	  image_base_str = optarg;
6973d8817e4Smiod 	  break;
6983d8817e4Smiod 	case OPTION_DEF:
6993d8817e4Smiod 	  def_file_name = optarg;
7003d8817e4Smiod 	  def_file_seen = 1;
7013d8817e4Smiod 	  delete_def_file = 0;
7023d8817e4Smiod 	  break;
7033d8817e4Smiod 	case 'n':
7043d8817e4Smiod 	  dontdeltemps = 1;
7053d8817e4Smiod 	  dlltool_arg = 1;
7063d8817e4Smiod 	  break;
7073d8817e4Smiod 	case 'o':
7083d8817e4Smiod 	  dll_file_name = optarg;
7093d8817e4Smiod 	  break;
7103d8817e4Smiod 	case 'I':
7113d8817e4Smiod 	case 'l':
7123d8817e4Smiod 	case 'L':
7133d8817e4Smiod 	  driver_arg = 1;
7143d8817e4Smiod 	  break;
7153d8817e4Smiod 	case OPTION_DLLNAME:
7163d8817e4Smiod 	  dll_name = optarg;
7173d8817e4Smiod 	  break;
7183d8817e4Smiod 	case OPTION_DRY_RUN:
7193d8817e4Smiod 	  dry_run = 1;
7203d8817e4Smiod 	  break;
7213d8817e4Smiod 	case OPTION_DRIVER_NAME:
7223d8817e4Smiod 	  driver_name = optarg;
7233d8817e4Smiod 	  break;
7243d8817e4Smiod 	case OPTION_DRIVER_FLAGS:
7253d8817e4Smiod 	  driver_flags = optarg;
7263d8817e4Smiod 	  break;
7273d8817e4Smiod 	case OPTION_DLLTOOL_NAME:
7283d8817e4Smiod 	  dlltool_name = optarg;
7293d8817e4Smiod 	  break;
7303d8817e4Smiod 	case OPTION_TARGET:
7313d8817e4Smiod 	  target = optarg;
7323d8817e4Smiod 	  break;
7333d8817e4Smiod 	case OPTION_MNO_CYGWIN:
7343d8817e4Smiod 	  target = "i386-mingw32";
7353d8817e4Smiod 	  break;
7363d8817e4Smiod 	case OPTION_BASE_FILE:
7373d8817e4Smiod 	  base_file_name = optarg;
7383d8817e4Smiod 	  delete_base_file = 0;
7393d8817e4Smiod 	  break;
7403d8817e4Smiod 	case OPTION_OUTPUT_EXP:
7413d8817e4Smiod 	  exp_file_name = optarg;
7423d8817e4Smiod 	  delete_exp_file = 0;
7433d8817e4Smiod 	  break;
7443d8817e4Smiod 	case OPTION_EXPORT_ALL_SYMS:
7453d8817e4Smiod 	  export_all = 1;
7463d8817e4Smiod 	  break;
7473d8817e4Smiod 	case OPTION_OUTPUT_LIB:
7483d8817e4Smiod 	  output_lib_file_name = optarg;
7493d8817e4Smiod 	  break;
7503d8817e4Smiod 	case '?':
7513d8817e4Smiod 	  break;
7523d8817e4Smiod 	default:
7533d8817e4Smiod 	  dlltool_arg = 1;
7543d8817e4Smiod 	  break;
7553d8817e4Smiod 	}
7563d8817e4Smiod 
7573d8817e4Smiod       /* Handle passing through --option=value case.  */
7583d8817e4Smiod       if (optarg
7593d8817e4Smiod 	  && saved_argv[optind-1][0] == '-'
7603d8817e4Smiod 	  && saved_argv[optind-1][1] == '-'
7613d8817e4Smiod 	  && strchr (saved_argv[optind-1], '='))
7623d8817e4Smiod 	single_word_option_value_pair = 1;
7633d8817e4Smiod 
7643d8817e4Smiod       if (dlltool_arg)
7653d8817e4Smiod 	{
7663d8817e4Smiod 	  dlltool_arg_indices[optind-1] = 1;
7673d8817e4Smiod 	  if (optarg && ! single_word_option_value_pair)
7683d8817e4Smiod 	    {
7693d8817e4Smiod 	      dlltool_arg_indices[optind-2] = 1;
7703d8817e4Smiod 	    }
7713d8817e4Smiod 	}
7723d8817e4Smiod 
7733d8817e4Smiod       if (! driver_arg)
7743d8817e4Smiod 	{
7753d8817e4Smiod 	  driver_arg_indices[optind-1] = 0;
7763d8817e4Smiod 	  if (optarg && ! single_word_option_value_pair)
7773d8817e4Smiod 	    {
7783d8817e4Smiod 	      driver_arg_indices[optind-2] = 0;
7793d8817e4Smiod 	    }
7803d8817e4Smiod 	}
7813d8817e4Smiod     }
7823d8817e4Smiod 
7833d8817e4Smiod   /* Sanity checks.  */
7843d8817e4Smiod   if (! dll_name && ! dll_file_name)
7853d8817e4Smiod     {
7863d8817e4Smiod       warn (_("Must provide at least one of -o or --dllname options"));
7873d8817e4Smiod       exit (1);
7883d8817e4Smiod     }
7893d8817e4Smiod   else if (! dll_name)
7903d8817e4Smiod     {
7913d8817e4Smiod       dll_name = xstrdup (mybasename (dll_file_name));
7923d8817e4Smiod     }
7933d8817e4Smiod   else if (! dll_file_name)
7943d8817e4Smiod     {
7953d8817e4Smiod       dll_file_name = xstrdup (dll_name);
7963d8817e4Smiod     }
7973d8817e4Smiod 
7983d8817e4Smiod   /* Deduce driver-name and dlltool-name from our own.  */
7993d8817e4Smiod   if (driver_name == NULL)
8003d8817e4Smiod     driver_name = deduce_name ("gcc");
8013d8817e4Smiod 
8023d8817e4Smiod   if (dlltool_name == NULL)
8033d8817e4Smiod     dlltool_name = deduce_name ("dlltool");
8043d8817e4Smiod 
8053d8817e4Smiod   if (! def_file_seen)
8063d8817e4Smiod     {
807*d2386abeSmiod       def_file_name = make_temp_file (".def");
808*d2386abeSmiod       if (dontdeltemps)
809*d2386abeSmiod 	def_file_name = mybasename (def_file_name);
8103d8817e4Smiod       free (fileprefix);
8113d8817e4Smiod       delete_def_file = 1;
8123d8817e4Smiod       warn (_("no export definition file provided.\n\
8133d8817e4Smiod Creating one, but that may not be what you want"));
8143d8817e4Smiod     }
8153d8817e4Smiod 
8163d8817e4Smiod   /* Set the target platform.  */
8173d8817e4Smiod   if (strstr (target, "cygwin"))
8183d8817e4Smiod     which_target = CYGWIN_TARGET;
8193d8817e4Smiod   else if (strstr (target, "mingw"))
8203d8817e4Smiod     which_target = MINGW_TARGET;
8213d8817e4Smiod   else
8223d8817e4Smiod     which_target = UNKNOWN_TARGET;
8233d8817e4Smiod 
8243d8817e4Smiod   /* Re-create the command lines as a string, taking care to quote stuff.  */
8253d8817e4Smiod   dlltool_cmdline = dyn_string_new (cmdline_len);
8263d8817e4Smiod   if (verbose)
8273d8817e4Smiod     dyn_string_append_cstr (dlltool_cmdline, " -v");
8283d8817e4Smiod 
8293d8817e4Smiod   dyn_string_append_cstr (dlltool_cmdline, " --dllname ");
8303d8817e4Smiod   dyn_string_append_cstr (dlltool_cmdline, dll_name);
8313d8817e4Smiod 
8323d8817e4Smiod   for (i = 1; i < argc; ++i)
8333d8817e4Smiod     {
8343d8817e4Smiod       if (dlltool_arg_indices[i])
8353d8817e4Smiod 	{
8363d8817e4Smiod 	  char *arg = saved_argv[i];
8373d8817e4Smiod 	  int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
8383d8817e4Smiod 	  dyn_string_append_cstr (dlltool_cmdline,
8393d8817e4Smiod 	                     (quote) ? " \"" : " ");
8403d8817e4Smiod 	  dyn_string_append_cstr (dlltool_cmdline, arg);
8413d8817e4Smiod 	  dyn_string_append_cstr (dlltool_cmdline,
8423d8817e4Smiod 	                     (quote) ? "\"" : "");
8433d8817e4Smiod 	}
8443d8817e4Smiod     }
8453d8817e4Smiod 
8463d8817e4Smiod   driver_cmdline = dyn_string_new (cmdline_len);
8473d8817e4Smiod   if (! driver_flags || strlen (driver_flags) == 0)
8483d8817e4Smiod     {
8493d8817e4Smiod       switch (which_target)
8503d8817e4Smiod 	{
8513d8817e4Smiod 	case CYGWIN_TARGET:
8523d8817e4Smiod 	  driver_flags = cygwin_driver_flags;
8533d8817e4Smiod 	  break;
8543d8817e4Smiod 
8553d8817e4Smiod 	case MINGW_TARGET:
8563d8817e4Smiod 	  driver_flags = mingw32_driver_flags;
8573d8817e4Smiod 	  break;
8583d8817e4Smiod 
8593d8817e4Smiod 	default:
8603d8817e4Smiod 	  driver_flags = generic_driver_flags;
8613d8817e4Smiod 	  break;
8623d8817e4Smiod 	}
8633d8817e4Smiod     }
8643d8817e4Smiod   dyn_string_append_cstr (driver_cmdline, driver_flags);
8653d8817e4Smiod   dyn_string_append_cstr (driver_cmdline, " -o ");
8663d8817e4Smiod   dyn_string_append_cstr (driver_cmdline, dll_file_name);
8673d8817e4Smiod 
8683d8817e4Smiod   if (! entry_point || strlen (entry_point) == 0)
8693d8817e4Smiod     {
8703d8817e4Smiod       switch (which_target)
8713d8817e4Smiod 	{
8723d8817e4Smiod 	case CYGWIN_TARGET:
8733d8817e4Smiod 	  entry_point = "__cygwin_dll_entry@12";
8743d8817e4Smiod 	  break;
8753d8817e4Smiod 
8763d8817e4Smiod 	case MINGW_TARGET:
8773d8817e4Smiod 	  entry_point = "_DllMainCRTStartup@12";
8783d8817e4Smiod 	  break;
8793d8817e4Smiod 
8803d8817e4Smiod 	default:
8813d8817e4Smiod 	  entry_point = "_DllMain@12";
8823d8817e4Smiod 	  break;
8833d8817e4Smiod 	}
8843d8817e4Smiod     }
8853d8817e4Smiod   dyn_string_append_cstr (driver_cmdline, " -Wl,-e,");
8863d8817e4Smiod   dyn_string_append_cstr (driver_cmdline, entry_point);
8873d8817e4Smiod   dyn_string_append_cstr (dlltool_cmdline, " --exclude-symbol=");
8883d8817e4Smiod   dyn_string_append_cstr (dlltool_cmdline,
8893d8817e4Smiod                     (entry_point[0] == '_') ? entry_point+1 : entry_point);
8903d8817e4Smiod 
8913d8817e4Smiod   if (! image_base_str || strlen (image_base_str) == 0)
8923d8817e4Smiod     {
8933d8817e4Smiod       char *tmpbuf = (char *) xmalloc (sizeof ("0x12345678") + 1);
8943d8817e4Smiod       unsigned long hash = strhash (dll_file_name);
8953d8817e4Smiod       sprintf (tmpbuf, "0x%.8lX", 0x60000000|((hash<<16)&0xFFC0000));
8963d8817e4Smiod       image_base_str = tmpbuf;
8973d8817e4Smiod     }
8983d8817e4Smiod 
8993d8817e4Smiod   dyn_string_append_cstr (driver_cmdline, " -Wl,--image-base,");
9003d8817e4Smiod   dyn_string_append_cstr (driver_cmdline, image_base_str);
9013d8817e4Smiod 
9023d8817e4Smiod   if (verbose)
9033d8817e4Smiod     {
9043d8817e4Smiod       dyn_string_append_cstr (driver_cmdline, " -v");
9053d8817e4Smiod     }
9063d8817e4Smiod 
9073d8817e4Smiod   for (i = 1; i < argc; ++i)
9083d8817e4Smiod     {
9093d8817e4Smiod       if (driver_arg_indices[i])
9103d8817e4Smiod 	{
9113d8817e4Smiod 	  char *arg = saved_argv[i];
9123d8817e4Smiod 	  int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
9133d8817e4Smiod 	  dyn_string_append_cstr (driver_cmdline,
9143d8817e4Smiod 	                     (quote) ? " \"" : " ");
9153d8817e4Smiod 	  dyn_string_append_cstr (driver_cmdline, arg);
9163d8817e4Smiod 	  dyn_string_append_cstr (driver_cmdline,
9173d8817e4Smiod 	                     (quote) ? "\"" : "");
9183d8817e4Smiod 	}
9193d8817e4Smiod     }
9203d8817e4Smiod 
9213d8817e4Smiod   /* Step pre-1. If no --def <EXPORT_DEF> is specified,
9223d8817e4Smiod      then create it and then pass it on.  */
9233d8817e4Smiod 
9243d8817e4Smiod   if (! def_file_seen)
9253d8817e4Smiod     {
9263d8817e4Smiod       int i;
9273d8817e4Smiod       dyn_string_t step_pre1;
9283d8817e4Smiod 
9293d8817e4Smiod       step_pre1 = dyn_string_new (1024);
9303d8817e4Smiod 
9313d8817e4Smiod       dyn_string_append_cstr (step_pre1, dlltool_cmdline->s);
9323d8817e4Smiod       if (export_all)
9333d8817e4Smiod 	{
9343d8817e4Smiod 	  dyn_string_append_cstr (step_pre1, " --export-all --exclude-symbol=");
9353d8817e4Smiod 	  dyn_string_append_cstr (step_pre1,
9363d8817e4Smiod 	  "_cygwin_dll_entry@12,DllMainCRTStartup@12,DllMain@12,DllEntryPoint@12");
9373d8817e4Smiod 	}
9383d8817e4Smiod       dyn_string_append_cstr (step_pre1, " --output-def ");
9393d8817e4Smiod       dyn_string_append_cstr (step_pre1, def_file_name);
9403d8817e4Smiod 
9413d8817e4Smiod       for (i = 1; i < argc; ++i)
9423d8817e4Smiod 	{
9433d8817e4Smiod 	  if (driver_arg_indices[i])
9443d8817e4Smiod 	    {
9453d8817e4Smiod 	      char *arg = saved_argv[i];
9463d8817e4Smiod 	      size_t len = strlen (arg);
9473d8817e4Smiod 	      if (len >= 2 && arg[len-2] == '.'
9483d8817e4Smiod 	          && (arg[len-1] == 'o' || arg[len-1] == 'a'))
9493d8817e4Smiod 		{
9503d8817e4Smiod 		  int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
9513d8817e4Smiod 		  dyn_string_append_cstr (step_pre1,
9523d8817e4Smiod 				     (quote) ? " \"" : " ");
9533d8817e4Smiod 		  dyn_string_append_cstr (step_pre1, arg);
9543d8817e4Smiod 		  dyn_string_append_cstr (step_pre1,
9553d8817e4Smiod 				     (quote) ? "\"" : "");
9563d8817e4Smiod 		}
9573d8817e4Smiod 	    }
9583d8817e4Smiod 	}
9593d8817e4Smiod 
9603d8817e4Smiod       if (run (dlltool_name, step_pre1->s))
9613d8817e4Smiod 	cleanup_and_exit (1);
9623d8817e4Smiod 
9633d8817e4Smiod       dyn_string_delete (step_pre1);
9643d8817e4Smiod     }
9653d8817e4Smiod 
9663d8817e4Smiod   dyn_string_append_cstr (dlltool_cmdline, " --def ");
9673d8817e4Smiod   dyn_string_append_cstr (dlltool_cmdline, def_file_name);
9683d8817e4Smiod 
9693d8817e4Smiod   if (verbose)
9703d8817e4Smiod     {
9713d8817e4Smiod       fprintf (stderr, _("DLLTOOL name    : %s\n"), dlltool_name);
9723d8817e4Smiod       fprintf (stderr, _("DLLTOOL options : %s\n"), dlltool_cmdline->s);
9733d8817e4Smiod       fprintf (stderr, _("DRIVER name     : %s\n"), driver_name);
9743d8817e4Smiod       fprintf (stderr, _("DRIVER options  : %s\n"), driver_cmdline->s);
9753d8817e4Smiod     }
9763d8817e4Smiod 
9773d8817e4Smiod   /* Step 1. Call GCC/LD to create base relocation file. If using GCC, the
9783d8817e4Smiod      driver command line will look like the following:
9793d8817e4Smiod 
9803d8817e4Smiod         % gcc -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
9813d8817e4Smiod 
9823d8817e4Smiod      If the user does not specify a base name, create temporary one that
9833d8817e4Smiod      is deleted at exit.  */
9843d8817e4Smiod 
9853d8817e4Smiod   if (! base_file_name)
9863d8817e4Smiod     {
987*d2386abeSmiod       base_file_name = make_temp_file (".base");
988*d2386abeSmiod       if (dontdeltemps)
989*d2386abeSmiod 	base_file_name = mybasename (base_file_name);
9903d8817e4Smiod       delete_base_file = 1;
9913d8817e4Smiod     }
9923d8817e4Smiod 
9933d8817e4Smiod   {
9943d8817e4Smiod     int quote;
9953d8817e4Smiod 
9963d8817e4Smiod     dyn_string_t step1 = dyn_string_new (driver_cmdline->length
9973d8817e4Smiod 					 + strlen (base_file_name)
9983d8817e4Smiod 					 + 20);
9993d8817e4Smiod     dyn_string_append_cstr (step1, "-Wl,--base-file,");
10003d8817e4Smiod     quote = (strchr (base_file_name, ' ')
10013d8817e4Smiod 	     || strchr (base_file_name, '\t'));
10023d8817e4Smiod     dyn_string_append_cstr (step1,
10033d8817e4Smiod 	               (quote) ? "\"" : "");
10043d8817e4Smiod     dyn_string_append_cstr (step1, base_file_name);
10053d8817e4Smiod     dyn_string_append_cstr (step1,
10063d8817e4Smiod 	               (quote) ? "\"" : "");
10073d8817e4Smiod     if (driver_cmdline->length)
10083d8817e4Smiod       {
10093d8817e4Smiod 	dyn_string_append_cstr (step1, " ");
10103d8817e4Smiod 	dyn_string_append_cstr (step1, driver_cmdline->s);
10113d8817e4Smiod       }
10123d8817e4Smiod 
10133d8817e4Smiod     if (run (driver_name, step1->s))
10143d8817e4Smiod       cleanup_and_exit (1);
10153d8817e4Smiod 
10163d8817e4Smiod     dyn_string_delete (step1);
10173d8817e4Smiod   }
10183d8817e4Smiod 
10193d8817e4Smiod   /* Step 2. generate the exp file by running dlltool.
10203d8817e4Smiod      dlltool command line will look like the following:
10213d8817e4Smiod 
10223d8817e4Smiod         % dlltool -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
10233d8817e4Smiod 
10243d8817e4Smiod      If the user does not specify a base name, create temporary one that
10253d8817e4Smiod      is deleted at exit.  */
10263d8817e4Smiod 
10273d8817e4Smiod   if (! exp_file_name)
10283d8817e4Smiod     {
10293d8817e4Smiod       char *p = strrchr (dll_name, '.');
10303d8817e4Smiod       size_t prefix_len = (p) ? (size_t) (p - dll_name) : strlen (dll_name);
10313d8817e4Smiod 
10323d8817e4Smiod       exp_file_name = (char *) xmalloc (prefix_len + 4 + 1);
10333d8817e4Smiod       strncpy (exp_file_name, dll_name, prefix_len);
10343d8817e4Smiod       exp_file_name[prefix_len] = '\0';
10353d8817e4Smiod       strcat (exp_file_name, ".exp");
10363d8817e4Smiod       delete_exp_file = 1;
10373d8817e4Smiod     }
10383d8817e4Smiod 
10393d8817e4Smiod   {
10403d8817e4Smiod     int quote;
10413d8817e4Smiod 
10423d8817e4Smiod     dyn_string_t step2 = dyn_string_new (dlltool_cmdline->length
10433d8817e4Smiod 					 + strlen (base_file_name)
10443d8817e4Smiod 					 + strlen (exp_file_name)
10453d8817e4Smiod 				         + 20);
10463d8817e4Smiod 
10473d8817e4Smiod     dyn_string_append_cstr (step2, "--base-file ");
10483d8817e4Smiod     quote = (strchr (base_file_name, ' ')
10493d8817e4Smiod 	     || strchr (base_file_name, '\t'));
10503d8817e4Smiod     dyn_string_append_cstr (step2,
10513d8817e4Smiod 	               (quote) ? "\"" : "");
10523d8817e4Smiod     dyn_string_append_cstr (step2, base_file_name);
10533d8817e4Smiod     dyn_string_append_cstr (step2,
10543d8817e4Smiod 	               (quote) ? "\" " : " ");
10553d8817e4Smiod 
10563d8817e4Smiod     dyn_string_append_cstr (step2, "--output-exp ");
10573d8817e4Smiod     quote = (strchr (exp_file_name, ' ')
10583d8817e4Smiod 	     || strchr (exp_file_name, '\t'));
10593d8817e4Smiod     dyn_string_append_cstr (step2,
10603d8817e4Smiod 	               (quote) ? "\"" : "");
10613d8817e4Smiod     dyn_string_append_cstr (step2, exp_file_name);
10623d8817e4Smiod     dyn_string_append_cstr (step2,
10633d8817e4Smiod 	               (quote) ? "\"" : "");
10643d8817e4Smiod 
10653d8817e4Smiod     if (dlltool_cmdline->length)
10663d8817e4Smiod       {
10673d8817e4Smiod 	dyn_string_append_cstr (step2, " ");
10683d8817e4Smiod 	dyn_string_append_cstr (step2, dlltool_cmdline->s);
10693d8817e4Smiod       }
10703d8817e4Smiod 
10713d8817e4Smiod     if (run (dlltool_name, step2->s))
10723d8817e4Smiod       cleanup_and_exit (1);
10733d8817e4Smiod 
10743d8817e4Smiod     dyn_string_delete (step2);
10753d8817e4Smiod   }
10763d8817e4Smiod 
10773d8817e4Smiod   /*
10783d8817e4Smiod    * Step 3. Call GCC/LD to again, adding the exp file this time.
10793d8817e4Smiod    * driver command line will look like the following:
10803d8817e4Smiod    *
10813d8817e4Smiod    *    % gcc -Wl,--dll --Wl,--base-file,foo.base foo.exp [rest ...]
10823d8817e4Smiod    */
10833d8817e4Smiod 
10843d8817e4Smiod   {
10853d8817e4Smiod     int quote;
10863d8817e4Smiod 
10873d8817e4Smiod     dyn_string_t step3 = dyn_string_new (driver_cmdline->length
10883d8817e4Smiod 					 + strlen (exp_file_name)
10893d8817e4Smiod 					 + strlen (base_file_name)
10903d8817e4Smiod 				         + 20);
10913d8817e4Smiod     dyn_string_append_cstr (step3, "-Wl,--base-file,");
10923d8817e4Smiod     quote = (strchr (base_file_name, ' ')
10933d8817e4Smiod 	     || strchr (base_file_name, '\t'));
10943d8817e4Smiod     dyn_string_append_cstr (step3,
10953d8817e4Smiod 	               (quote) ? "\"" : "");
10963d8817e4Smiod     dyn_string_append_cstr (step3, base_file_name);
10973d8817e4Smiod     dyn_string_append_cstr (step3,
10983d8817e4Smiod 	               (quote) ? "\" " : " ");
10993d8817e4Smiod 
11003d8817e4Smiod     quote = (strchr (exp_file_name, ' ')
11013d8817e4Smiod 	     || strchr (exp_file_name, '\t'));
11023d8817e4Smiod     dyn_string_append_cstr (step3,
11033d8817e4Smiod 	               (quote) ? "\"" : "");
11043d8817e4Smiod     dyn_string_append_cstr (step3, exp_file_name);
11053d8817e4Smiod     dyn_string_append_cstr (step3,
11063d8817e4Smiod 	               (quote) ? "\"" : "");
11073d8817e4Smiod 
11083d8817e4Smiod     if (driver_cmdline->length)
11093d8817e4Smiod       {
11103d8817e4Smiod 	dyn_string_append_cstr (step3, " ");
11113d8817e4Smiod 	dyn_string_append_cstr (step3, driver_cmdline->s);
11123d8817e4Smiod       }
11133d8817e4Smiod 
11143d8817e4Smiod     if (run (driver_name, step3->s))
11153d8817e4Smiod       cleanup_and_exit (1);
11163d8817e4Smiod 
11173d8817e4Smiod     dyn_string_delete (step3);
11183d8817e4Smiod   }
11193d8817e4Smiod 
11203d8817e4Smiod 
11213d8817e4Smiod   /*
11223d8817e4Smiod    * Step 4. Run DLLTOOL again using the same command line.
11233d8817e4Smiod    */
11243d8817e4Smiod 
11253d8817e4Smiod   {
11263d8817e4Smiod     int quote;
11273d8817e4Smiod     dyn_string_t step4 = dyn_string_new (dlltool_cmdline->length
11283d8817e4Smiod 					 + strlen (base_file_name)
11293d8817e4Smiod 					 + strlen (exp_file_name)
11303d8817e4Smiod 				         + 20);
11313d8817e4Smiod 
11323d8817e4Smiod     dyn_string_append_cstr (step4, "--base-file ");
11333d8817e4Smiod     quote = (strchr (base_file_name, ' ')
11343d8817e4Smiod 	     || strchr (base_file_name, '\t'));
11353d8817e4Smiod     dyn_string_append_cstr (step4,
11363d8817e4Smiod 	               (quote) ? "\"" : "");
11373d8817e4Smiod     dyn_string_append_cstr (step4, base_file_name);
11383d8817e4Smiod     dyn_string_append_cstr (step4,
11393d8817e4Smiod 	               (quote) ? "\" " : " ");
11403d8817e4Smiod 
11413d8817e4Smiod     dyn_string_append_cstr (step4, "--output-exp ");
11423d8817e4Smiod     quote = (strchr (exp_file_name, ' ')
11433d8817e4Smiod 	     || strchr (exp_file_name, '\t'));
11443d8817e4Smiod     dyn_string_append_cstr (step4,
11453d8817e4Smiod 	               (quote) ? "\"" : "");
11463d8817e4Smiod     dyn_string_append_cstr (step4, exp_file_name);
11473d8817e4Smiod     dyn_string_append_cstr (step4,
11483d8817e4Smiod 	               (quote) ? "\"" : "");
11493d8817e4Smiod 
11503d8817e4Smiod     if (dlltool_cmdline->length)
11513d8817e4Smiod       {
11523d8817e4Smiod 	dyn_string_append_cstr (step4, " ");
11533d8817e4Smiod 	dyn_string_append_cstr (step4, dlltool_cmdline->s);
11543d8817e4Smiod       }
11553d8817e4Smiod 
11563d8817e4Smiod     if (output_lib_file_name)
11573d8817e4Smiod       {
11583d8817e4Smiod 	dyn_string_append_cstr (step4, " --output-lib ");
11593d8817e4Smiod 	dyn_string_append_cstr (step4, output_lib_file_name);
11603d8817e4Smiod       }
11613d8817e4Smiod 
11623d8817e4Smiod     if (run (dlltool_name, step4->s))
11633d8817e4Smiod       cleanup_and_exit (1);
11643d8817e4Smiod 
11653d8817e4Smiod     dyn_string_delete (step4);
11663d8817e4Smiod   }
11673d8817e4Smiod 
11683d8817e4Smiod 
11693d8817e4Smiod   /*
11703d8817e4Smiod    * Step 5. Link it all together and be done with it.
11713d8817e4Smiod    * driver command line will look like the following:
11723d8817e4Smiod    *
11733d8817e4Smiod    *    % gcc -Wl,--dll foo.exp [rest ...]
11743d8817e4Smiod    *
11753d8817e4Smiod    */
11763d8817e4Smiod 
11773d8817e4Smiod   {
11783d8817e4Smiod     int quote;
11793d8817e4Smiod 
11803d8817e4Smiod     dyn_string_t step5 = dyn_string_new (driver_cmdline->length
11813d8817e4Smiod 					 + strlen (exp_file_name)
11823d8817e4Smiod 				         + 20);
11833d8817e4Smiod     quote = (strchr (exp_file_name, ' ')
11843d8817e4Smiod 	     || strchr (exp_file_name, '\t'));
11853d8817e4Smiod     dyn_string_append_cstr (step5,
11863d8817e4Smiod 	               (quote) ? "\"" : "");
11873d8817e4Smiod     dyn_string_append_cstr (step5, exp_file_name);
11883d8817e4Smiod     dyn_string_append_cstr (step5,
11893d8817e4Smiod 	               (quote) ? "\"" : "");
11903d8817e4Smiod 
11913d8817e4Smiod     if (driver_cmdline->length)
11923d8817e4Smiod       {
11933d8817e4Smiod 	dyn_string_append_cstr (step5, " ");
11943d8817e4Smiod 	dyn_string_append_cstr (step5, driver_cmdline->s);
11953d8817e4Smiod       }
11963d8817e4Smiod 
11973d8817e4Smiod     if (run (driver_name, step5->s))
11983d8817e4Smiod       cleanup_and_exit (1);
11993d8817e4Smiod 
12003d8817e4Smiod     dyn_string_delete (step5);
12013d8817e4Smiod   }
12023d8817e4Smiod 
12033d8817e4Smiod   cleanup_and_exit (0);
12043d8817e4Smiod 
12053d8817e4Smiod   return 0;
12063d8817e4Smiod }
1207