Back to index

cell-binutils  2.17cvs20070401
dllwrap.c
Go to the documentation of this file.
00001 /* dllwrap.c -- wrapper for DLLTOOL and GCC to generate PE style DLLs
00002    Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007
00003    Free Software Foundation, Inc.
00004    Contributed by Mumit Khan (khan@xraylith.wisc.edu).
00005 
00006    This file is part of GNU Binutils.
00007 
00008    This program is free software; you can redistribute it and/or modify
00009    it under the terms of the GNU General Public License as published by
00010    the Free Software Foundation; either version 2 of the License, or
00011    (at your option) any later version.
00012 
00013    This program is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016    GNU General Public License for more details.
00017 
00018    You should have received a copy of the GNU General Public License
00019    along with this program; if not, write to the Free Software
00020    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
00021    02110-1301, USA.  */
00022 
00023 /* AIX requires this to be the first thing in the file.  */
00024 #ifndef __GNUC__
00025 # ifdef _AIX
00026  #pragma alloca
00027 #endif
00028 #endif
00029 
00030 #ifdef HAVE_CONFIG_H
00031 #include "config.h"
00032 #endif
00033 
00034 #include "bfd.h"
00035 #include "libiberty.h"
00036 #include "bucomm.h"
00037 #include "getopt.h"
00038 #include "dyn-string.h"
00039 
00040 #include <time.h>
00041 #include <sys/stat.h>
00042 #include <stdarg.h>
00043 
00044 #ifdef HAVE_SYS_WAIT_H
00045 #include <sys/wait.h>
00046 #else /* ! HAVE_SYS_WAIT_H */
00047 #if ! defined (_WIN32) || defined (__CYGWIN32__)
00048 #ifndef WIFEXITED
00049 #define WIFEXITED(w) (((w)&0377) == 0)
00050 #endif
00051 #ifndef WIFSIGNALED
00052 #define WIFSIGNALED(w)      (((w)&0377) != 0177 && ((w)&~0377) == 0)
00053 #endif
00054 #ifndef WTERMSIG
00055 #define WTERMSIG(w)  ((w) & 0177)
00056 #endif
00057 #ifndef WEXITSTATUS
00058 #define WEXITSTATUS(w)      (((w) >> 8) & 0377)
00059 #endif
00060 #else /* defined (_WIN32) && ! defined (__CYGWIN32__) */
00061 #ifndef WIFEXITED
00062 #define WIFEXITED(w) (((w) & 0xff) == 0)
00063 #endif
00064 #ifndef WIFSIGNALED
00065 #define WIFSIGNALED(w)      (((w) & 0xff) != 0 && ((w) & 0xff) != 0x7f)
00066 #endif
00067 #ifndef WTERMSIG
00068 #define WTERMSIG(w)  ((w) & 0x7f)
00069 #endif
00070 #ifndef WEXITSTATUS
00071 #define WEXITSTATUS(w)      (((w) & 0xff00) >> 8)
00072 #endif
00073 #endif /* defined (_WIN32) && ! defined (__CYGWIN32__) */
00074 #endif /* ! HAVE_SYS_WAIT_H */
00075 
00076 static char *driver_name = NULL;
00077 static char *cygwin_driver_flags =
00078   "-Wl,--dll -nostartfiles";
00079 static char *mingw32_driver_flags = "-mdll";
00080 static char *generic_driver_flags = "-Wl,--dll";
00081 
00082 static char *entry_point;
00083 
00084 static char *dlltool_name = NULL;
00085 
00086 static char *target = TARGET;
00087 
00088 typedef enum {
00089   UNKNOWN_TARGET,
00090   CYGWIN_TARGET,
00091   MINGW_TARGET
00092 }
00093 target_type;
00094 
00095 static target_type which_target = UNKNOWN_TARGET;
00096 
00097 static int dontdeltemps = 0;
00098 static int dry_run = 0;
00099 
00100 static char *prog_name;
00101 
00102 static int verbose = 0;
00103 
00104 static char *dll_file_name;
00105 static char *dll_name;
00106 static char *base_file_name;
00107 static char *exp_file_name;
00108 static char *def_file_name;
00109 static int delete_base_file = 1;
00110 static int delete_exp_file = 1;
00111 static int delete_def_file = 1;
00112 
00113 static int run (const char *, char *);
00114 static char *mybasename (const char *);
00115 static int strhash (const char *);
00116 static void usage (FILE *, int);
00117 static void display (const char *, va_list) ATTRIBUTE_PRINTF(1,0);
00118 static void inform (const char *, ...) ATTRIBUTE_PRINTF_1;
00119 static void warn (const char *, ...) ATTRIBUTE_PRINTF_1;
00120 static char *look_for_prog (const char *, const char *, int);
00121 static char *deduce_name (const char *);
00122 static void delete_temp_files (void);
00123 static void cleanup_and_exit (int);
00124 
00125 /**********************************************************************/
00126 
00127 /* Please keep the following 4 routines in sync with dlltool.c:
00128      display ()
00129      inform ()
00130      look_for_prog ()
00131      deduce_name ()
00132    It's not worth the hassle to break these out since dllwrap will
00133    (hopefully) soon be retired in favor of `ld --shared.  */
00134 
00135 static void
00136 display (const char * message, va_list args)
00137 {
00138   if (prog_name != NULL)
00139     fprintf (stderr, "%s: ", prog_name);
00140 
00141   vfprintf (stderr, message, args);
00142   fputc ('\n', stderr);
00143 }
00144 
00145 
00146 static void
00147 inform VPARAMS ((const char *message, ...))
00148 {
00149   VA_OPEN (args, message);
00150   VA_FIXEDARG (args, const char *, message);
00151 
00152   if (!verbose)
00153     return;
00154 
00155   display (message, args);
00156 
00157   VA_CLOSE (args);
00158 }
00159 
00160 static void
00161 warn VPARAMS ((const char *format, ...))
00162 {
00163   VA_OPEN (args, format);
00164   VA_FIXEDARG (args, const char *, format);
00165 
00166   display (format, args);
00167 
00168   VA_CLOSE (args);
00169 }
00170 
00171 /* Look for the program formed by concatenating PROG_NAME and the
00172    string running from PREFIX to END_PREFIX.  If the concatenated
00173    string contains a '/', try appending EXECUTABLE_SUFFIX if it is
00174    appropriate.  */
00175 
00176 static char *
00177 look_for_prog (const char *prog_name, const char *prefix, int end_prefix)
00178 {
00179   struct stat s;
00180   char *cmd;
00181 
00182   cmd = xmalloc (strlen (prefix)
00183                + strlen (prog_name)
00184 #ifdef HAVE_EXECUTABLE_SUFFIX
00185                + strlen (EXECUTABLE_SUFFIX)
00186 #endif
00187                + 10);
00188   strcpy (cmd, prefix);
00189 
00190   sprintf (cmd + end_prefix, "%s", prog_name);
00191 
00192   if (strchr (cmd, '/') != NULL)
00193     {
00194       int found;
00195 
00196       found = (stat (cmd, &s) == 0
00197 #ifdef HAVE_EXECUTABLE_SUFFIX
00198               || stat (strcat (cmd, EXECUTABLE_SUFFIX), &s) == 0
00199 #endif
00200               );
00201 
00202       if (! found)
00203        {
00204          /* xgettext:c-format */
00205          inform (_("Tried file: %s"), cmd);
00206          free (cmd);
00207          return NULL;
00208        }
00209     }
00210 
00211   /* xgettext:c-format */
00212   inform (_("Using file: %s"), cmd);
00213 
00214   return cmd;
00215 }
00216 
00217 /* Deduce the name of the program we are want to invoke.
00218    PROG_NAME is the basic name of the program we want to run,
00219    eg "as" or "ld".  The catch is that we might want actually
00220    run "i386-pe-as" or "ppc-pe-ld".
00221 
00222    If argv[0] contains the full path, then try to find the program
00223    in the same place, with and then without a target-like prefix.
00224 
00225    Given, argv[0] = /usr/local/bin/i586-cygwin32-dlltool,
00226    deduce_name("as") uses the following search order:
00227 
00228      /usr/local/bin/i586-cygwin32-as
00229      /usr/local/bin/as
00230      as
00231 
00232    If there's an EXECUTABLE_SUFFIX, it'll use that as well; for each
00233    name, it'll try without and then with EXECUTABLE_SUFFIX.
00234 
00235    Given, argv[0] = i586-cygwin32-dlltool, it will not even try "as"
00236    as the fallback, but rather return i586-cygwin32-as.
00237 
00238    Oh, and given, argv[0] = dlltool, it'll return "as".
00239 
00240    Returns a dynamically allocated string.  */
00241 
00242 static char *
00243 deduce_name (const char * name)
00244 {
00245   char *cmd;
00246   const char *dash;
00247   const char *slash;
00248   const char *cp;
00249 
00250   dash = NULL;
00251   slash = NULL;
00252   for (cp = prog_name; *cp != '\0'; ++cp)
00253     {
00254       if (*cp == '-')
00255        dash = cp;
00256 
00257       if (
00258 #if defined(__DJGPP__) || defined (__CYGWIN__) || defined(__WIN32__)
00259          *cp == ':' || *cp == '\\' ||
00260 #endif
00261          *cp == '/')
00262        {
00263          slash = cp;
00264          dash = NULL;
00265        }
00266     }
00267 
00268   cmd = NULL;
00269 
00270   if (dash != NULL)
00271     /* First, try looking for a prefixed NAME in the
00272        PROG_NAME directory, with the same prefix as PROG_NAME.  */
00273     cmd = look_for_prog (name, prog_name, dash - prog_name + 1);
00274 
00275   if (slash != NULL && cmd == NULL)
00276     /* Next, try looking for a NAME in the same directory as
00277        that of this program.  */
00278     cmd = look_for_prog (name, prog_name, slash - prog_name + 1);
00279 
00280   if (cmd == NULL)
00281     /* Just return NAME as is.  */
00282     cmd = xstrdup (name);
00283 
00284   return cmd;
00285 }
00286 
00287 static void
00288 delete_temp_files (void)
00289 {
00290   if (delete_base_file && base_file_name)
00291     {
00292       if (verbose)
00293        {
00294          if (dontdeltemps)
00295            warn (_("Keeping temporary base file %s"), base_file_name);
00296          else
00297            warn (_("Deleting temporary base file %s"), base_file_name);
00298        }
00299       if (! dontdeltemps)
00300        {
00301          unlink (base_file_name);
00302          free (base_file_name);
00303        }
00304     }
00305 
00306   if (delete_exp_file && exp_file_name)
00307     {
00308       if (verbose)
00309        {
00310          if (dontdeltemps)
00311            warn (_("Keeping temporary exp file %s"), exp_file_name);
00312          else
00313            warn (_("Deleting temporary exp file %s"), exp_file_name);
00314        }
00315       if (! dontdeltemps)
00316        {
00317          unlink (exp_file_name);
00318          free (exp_file_name);
00319        }
00320     }
00321   if (delete_def_file && def_file_name)
00322     {
00323       if (verbose)
00324        {
00325          if (dontdeltemps)
00326            warn (_("Keeping temporary def file %s"), def_file_name);
00327          else
00328            warn (_("Deleting temporary def file %s"), def_file_name);
00329        }
00330       if (! dontdeltemps)
00331        {
00332          unlink (def_file_name);
00333          free (def_file_name);
00334        }
00335     }
00336 }
00337 
00338 static void
00339 cleanup_and_exit (int status)
00340 {
00341   delete_temp_files ();
00342   exit (status);
00343 }
00344 
00345 static int
00346 run (const char *what, char *args)
00347 {
00348   char *s;
00349   int pid, wait_status, retcode;
00350   int i;
00351   const char **argv;
00352   char *errmsg_fmt, *errmsg_arg;
00353   char *temp_base = choose_temp_base ();
00354   int in_quote;
00355   char sep;
00356 
00357   if (verbose || dry_run)
00358     fprintf (stderr, "%s %s\n", what, args);
00359 
00360   /* Count the args */
00361   i = 0;
00362   for (s = args; *s; s++)
00363     if (*s == ' ')
00364       i++;
00365   i++;
00366   argv = alloca (sizeof (char *) * (i + 3));
00367   i = 0;
00368   argv[i++] = what;
00369   s = args;
00370   while (1)
00371     {
00372       while (*s == ' ' && *s != 0)
00373        s++;
00374       if (*s == 0)
00375        break;
00376       in_quote = (*s == '\'' || *s == '"');
00377       sep = (in_quote) ? *s++ : ' ';
00378       argv[i++] = s;
00379       while (*s != sep && *s != 0)
00380        s++;
00381       if (*s == 0)
00382        break;
00383       *s++ = 0;
00384       if (in_quote)
00385        s++;
00386     }
00387   argv[i++] = NULL;
00388 
00389   if (dry_run)
00390     return 0;
00391 
00392   pid = pexecute (argv[0], (char * const *) argv, prog_name, temp_base,
00393                 &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
00394 
00395   if (pid == -1)
00396     {
00397       int errno_val = errno;
00398 
00399       fprintf (stderr, "%s: ", prog_name);
00400       fprintf (stderr, errmsg_fmt, errmsg_arg);
00401       fprintf (stderr, ": %s\n", strerror (errno_val));
00402       return 1;
00403     }
00404 
00405   retcode = 0;
00406   pid = pwait (pid, &wait_status, 0);
00407   if (pid == -1)
00408     {
00409       warn ("wait: %s", strerror (errno));
00410       retcode = 1;
00411     }
00412   else if (WIFSIGNALED (wait_status))
00413     {
00414       warn (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
00415       retcode = 1;
00416     }
00417   else if (WIFEXITED (wait_status))
00418     {
00419       if (WEXITSTATUS (wait_status) != 0)
00420        {
00421          warn (_("%s exited with status %d"), what, WEXITSTATUS (wait_status));
00422          retcode = 1;
00423        }
00424     }
00425   else
00426     retcode = 1;
00427 
00428   return retcode;
00429 }
00430 
00431 static char *
00432 mybasename (const char *name)
00433 {
00434   const char *base = name;
00435 
00436   while (*name)
00437     {
00438       if (*name == '/' || *name == '\\')
00439        {
00440          base = name + 1;
00441        }
00442       ++name;
00443     }
00444   return (char *) base;
00445 }
00446 
00447 static int
00448 strhash (const char *str)
00449 {
00450   const unsigned char *s;
00451   unsigned long hash;
00452   unsigned int c;
00453   unsigned int len;
00454 
00455   hash = 0;
00456   len = 0;
00457   s = (const unsigned char *) str;
00458   while ((c = *s++) != '\0')
00459     {
00460       hash += c + (c << 17);
00461       hash ^= hash >> 2;
00462       ++len;
00463     }
00464   hash += len + (len << 17);
00465   hash ^= hash >> 2;
00466 
00467   return hash;
00468 }
00469 
00470 /**********************************************************************/
00471 
00472 static void
00473 usage (FILE *file, int status)
00474 {
00475   fprintf (file, _("Usage %s <option(s)> <object-file(s)>\n"), prog_name);
00476   fprintf (file, _("  Generic options:\n"));
00477   fprintf (file, _("   @<file>                Read options from <file>\n"));    
00478   fprintf (file, _("   --quiet, -q            Work quietly\n"));
00479   fprintf (file, _("   --verbose, -v          Verbose\n"));
00480   fprintf (file, _("   --version              Print dllwrap version\n"));
00481   fprintf (file, _("   --implib <outname>     Synonym for --output-lib\n"));
00482   fprintf (file, _("  Options for %s:\n"), prog_name);
00483   fprintf (file, _("   --driver-name <driver> Defaults to \"gcc\"\n"));
00484   fprintf (file, _("   --driver-flags <flags> Override default ld flags\n"));
00485   fprintf (file, _("   --dlltool-name <dlltool> Defaults to \"dlltool\"\n"));
00486   fprintf (file, _("   --entry <entry>        Specify alternate DLL entry point\n"));
00487   fprintf (file, _("   --image-base <base>    Specify image base address\n"));
00488   fprintf (file, _("   --target <machine>     i386-cygwin32 or i386-mingw32\n"));
00489   fprintf (file, _("   --dry-run              Show what needs to be run\n"));
00490   fprintf (file, _("   --mno-cygwin           Create Mingw DLL\n"));
00491   fprintf (file, _("  Options passed to DLLTOOL:\n"));
00492   fprintf (file, _("   --machine <machine>\n"));
00493   fprintf (file, _("   --output-exp <outname> Generate export file.\n"));
00494   fprintf (file, _("   --output-lib <outname> Generate input library.\n"));
00495   fprintf (file, _("   --add-indirect         Add dll indirects to export file.\n"));
00496   fprintf (file, _("   --dllname <name>       Name of input dll to put into output lib.\n"));
00497   fprintf (file, _("   --def <deffile>        Name input .def file\n"));
00498   fprintf (file, _("   --output-def <deffile> Name output .def file\n"));
00499   fprintf (file, _("   --export-all-symbols     Export all symbols to .def\n"));
00500   fprintf (file, _("   --no-export-all-symbols  Only export .drectve symbols\n"));
00501   fprintf (file, _("   --exclude-symbols <list> Exclude <list> from .def\n"));
00502   fprintf (file, _("   --no-default-excludes    Zap default exclude symbols\n"));
00503   fprintf (file, _("   --base-file <basefile> Read linker generated base file\n"));
00504   fprintf (file, _("   --no-idata4           Don't generate idata$4 section\n"));
00505   fprintf (file, _("   --no-idata5           Don't generate idata$5 section\n"));
00506   fprintf (file, _("   -U                     Add underscores to .lib\n"));
00507   fprintf (file, _("   -k                     Kill @<n> from exported names\n"));
00508   fprintf (file, _("   --add-stdcall-alias    Add aliases without @<n>\n"));
00509   fprintf (file, _("   --as <name>            Use <name> for assembler\n"));
00510   fprintf (file, _("   --nodelete             Keep temp files.\n"));
00511   fprintf (file, _("  Rest are passed unmodified to the language driver\n"));
00512   fprintf (file, "\n\n");
00513   if (REPORT_BUGS_TO[0] && status == 0)
00514     fprintf (file, _("Report bugs to %s\n"), REPORT_BUGS_TO);
00515   exit (status);
00516 }
00517 
00518 #define OPTION_START        149
00519 
00520 /* GENERIC options.  */
00521 #define OPTION_QUIET        (OPTION_START + 1)
00522 #define OPTION_VERBOSE             (OPTION_QUIET + 1)
00523 #define OPTION_VERSION             (OPTION_VERBOSE + 1)
00524 
00525 /* DLLWRAP options.  */
00526 #define OPTION_DRY_RUN             (OPTION_VERSION + 1)
00527 #define OPTION_DRIVER_NAME  (OPTION_DRY_RUN + 1)
00528 #define OPTION_DRIVER_FLAGS (OPTION_DRIVER_NAME + 1)
00529 #define OPTION_DLLTOOL_NAME (OPTION_DRIVER_FLAGS + 1)
00530 #define OPTION_ENTRY        (OPTION_DLLTOOL_NAME + 1)
00531 #define OPTION_IMAGE_BASE   (OPTION_ENTRY + 1)
00532 #define OPTION_TARGET              (OPTION_IMAGE_BASE + 1)
00533 #define OPTION_MNO_CYGWIN   (OPTION_TARGET + 1)
00534 
00535 /* DLLTOOL options.  */
00536 #define OPTION_NODELETE            (OPTION_MNO_CYGWIN + 1)
00537 #define OPTION_DLLNAME             (OPTION_NODELETE + 1)
00538 #define OPTION_NO_IDATA4    (OPTION_DLLNAME + 1)
00539 #define OPTION_NO_IDATA5    (OPTION_NO_IDATA4 + 1)
00540 #define OPTION_OUTPUT_EXP   (OPTION_NO_IDATA5 + 1)
00541 #define OPTION_OUTPUT_DEF   (OPTION_OUTPUT_EXP + 1)
00542 #define OPTION_EXPORT_ALL_SYMS     (OPTION_OUTPUT_DEF + 1)
00543 #define OPTION_NO_EXPORT_ALL_SYMS (OPTION_EXPORT_ALL_SYMS + 1)
00544 #define OPTION_EXCLUDE_SYMS (OPTION_NO_EXPORT_ALL_SYMS + 1)
00545 #define OPTION_NO_DEFAULT_EXCLUDES (OPTION_EXCLUDE_SYMS + 1)
00546 #define OPTION_OUTPUT_LIB   (OPTION_NO_DEFAULT_EXCLUDES + 1)
00547 #define OPTION_DEF          (OPTION_OUTPUT_LIB + 1)
00548 #define OPTION_ADD_UNDERSCORE      (OPTION_DEF + 1)
00549 #define OPTION_KILLAT              (OPTION_ADD_UNDERSCORE + 1)
00550 #define OPTION_HELP         (OPTION_KILLAT + 1)
00551 #define OPTION_MACHINE             (OPTION_HELP + 1)
00552 #define OPTION_ADD_INDIRECT (OPTION_MACHINE + 1)
00553 #define OPTION_BASE_FILE    (OPTION_ADD_INDIRECT + 1)
00554 #define OPTION_AS           (OPTION_BASE_FILE + 1)
00555 
00556 static const struct option long_options[] =
00557 {
00558   /* generic options.  */
00559   {"quiet", no_argument, NULL, 'q'},
00560   {"verbose", no_argument, NULL, 'v'},
00561   {"version", no_argument, NULL, OPTION_VERSION},
00562   {"implib", required_argument, NULL, OPTION_OUTPUT_LIB},
00563 
00564   /* dllwrap options.  */
00565   {"dry-run", no_argument, NULL, OPTION_DRY_RUN},
00566   {"driver-name", required_argument, NULL, OPTION_DRIVER_NAME},
00567   {"driver-flags", required_argument, NULL, OPTION_DRIVER_FLAGS},
00568   {"dlltool-name", required_argument, NULL, OPTION_DLLTOOL_NAME},
00569   {"entry", required_argument, NULL, 'e'},
00570   {"image-base", required_argument, NULL, OPTION_IMAGE_BASE},
00571   {"target", required_argument, NULL, OPTION_TARGET},
00572 
00573   /* dlltool options.  */
00574   {"no-delete", no_argument, NULL, 'n'},
00575   {"dllname", required_argument, NULL, OPTION_DLLNAME},
00576   {"no-idata4", no_argument, NULL, OPTION_NO_IDATA4},
00577   {"no-idata5", no_argument, NULL, OPTION_NO_IDATA5},
00578   {"output-exp", required_argument, NULL, OPTION_OUTPUT_EXP},
00579   {"output-def", required_argument, NULL, OPTION_OUTPUT_DEF},
00580   {"export-all-symbols", no_argument, NULL, OPTION_EXPORT_ALL_SYMS},
00581   {"no-export-all-symbols", no_argument, NULL, OPTION_NO_EXPORT_ALL_SYMS},
00582   {"exclude-symbols", required_argument, NULL, OPTION_EXCLUDE_SYMS},
00583   {"no-default-excludes", no_argument, NULL, OPTION_NO_DEFAULT_EXCLUDES},
00584   {"output-lib", required_argument, NULL, OPTION_OUTPUT_LIB},
00585   {"def", required_argument, NULL, OPTION_DEF},
00586   {"add-underscore", no_argument, NULL, 'U'},
00587   {"killat", no_argument, NULL, 'k'},
00588   {"add-stdcall-alias", no_argument, NULL, 'A'},
00589   {"help", no_argument, NULL, 'h'},
00590   {"machine", required_argument, NULL, OPTION_MACHINE},
00591   {"add-indirect", no_argument, NULL, OPTION_ADD_INDIRECT},
00592   {"base-file", required_argument, NULL, OPTION_BASE_FILE},
00593   {"as", required_argument, NULL, OPTION_AS},
00594   {0, 0, 0, 0}
00595 };
00596 
00597 int main (int, char **);
00598 
00599 int
00600 main (int argc, char **argv)
00601 {
00602   int c;
00603   int i;
00604 
00605   char **saved_argv = 0;
00606   int cmdline_len = 0;
00607 
00608   int export_all = 0;
00609 
00610   int *dlltool_arg_indices;
00611   int *driver_arg_indices;
00612 
00613   char *driver_flags = 0;
00614   char *output_lib_file_name = 0;
00615 
00616   dyn_string_t dlltool_cmdline;
00617   dyn_string_t driver_cmdline;
00618 
00619   int def_file_seen = 0;
00620 
00621   char *image_base_str = 0;
00622 
00623   prog_name = argv[0];
00624 
00625 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
00626   setlocale (LC_MESSAGES, "");
00627 #endif
00628 #if defined (HAVE_SETLOCALE)
00629   setlocale (LC_CTYPE, "");
00630 #endif
00631   bindtextdomain (PACKAGE, LOCALEDIR);
00632   textdomain (PACKAGE);
00633 
00634   expandargv (&argc, &argv);
00635 
00636   saved_argv = (char **) xmalloc (argc * sizeof (char*));
00637   dlltool_arg_indices = (int *) xmalloc (argc * sizeof (int));
00638   driver_arg_indices = (int *) xmalloc (argc * sizeof (int));
00639   for (i = 0; i < argc; ++i)
00640     {
00641       size_t len = strlen (argv[i]);
00642       char *arg = (char *) xmalloc (len + 1);
00643       strcpy (arg, argv[i]);
00644       cmdline_len += len;
00645       saved_argv[i] = arg;
00646       dlltool_arg_indices[i] = 0;
00647       driver_arg_indices[i] = 1;
00648     }
00649   cmdline_len++;
00650 
00651   /* We recognize dllwrap and dlltool options, and everything else is
00652      passed onto the language driver (eg., to GCC). We collect options
00653      to dlltool and driver in dlltool_args and driver_args.  */
00654 
00655   opterr = 0;
00656   while ((c = getopt_long_only (argc, argv, "nkAqve:Uho:l:L:I:",
00657                             long_options, (int *) 0)) != EOF)
00658     {
00659       int dlltool_arg;
00660       int driver_arg;
00661       int single_word_option_value_pair;
00662 
00663       dlltool_arg = 0;
00664       driver_arg = 1;
00665       single_word_option_value_pair = 0;
00666 
00667       if (c != '?')
00668        {
00669          /* We recognize this option, so it has to be either dllwrap or
00670             dlltool option. Do not pass to driver unless it's one of the
00671             generic options that are passed to all the tools (such as -v)
00672             which are dealt with later.  */
00673          driver_arg = 0;
00674        }
00675 
00676       /* deal with generic and dllwrap options first.  */
00677       switch (c)
00678        {
00679        case 'h':
00680          usage (stdout, 0);
00681          break;
00682        case 'q':
00683          verbose = 0;
00684          break;
00685        case 'v':
00686          verbose = 1;
00687          break;
00688        case OPTION_VERSION:
00689          print_version (prog_name);
00690          break;
00691        case 'e':
00692          entry_point = optarg;
00693          break;
00694        case OPTION_IMAGE_BASE:
00695          image_base_str = optarg;
00696          break;
00697        case OPTION_DEF:
00698          def_file_name = optarg;
00699          def_file_seen = 1;
00700          delete_def_file = 0;
00701          break;
00702        case 'n':
00703          dontdeltemps = 1;
00704          dlltool_arg = 1;
00705          break;
00706        case 'o':
00707          dll_file_name = optarg;
00708          break;
00709        case 'I':
00710        case 'l':
00711        case 'L':
00712          driver_arg = 1;
00713          break;
00714        case OPTION_DLLNAME:
00715          dll_name = optarg;
00716          break;
00717        case OPTION_DRY_RUN:
00718          dry_run = 1;
00719          break;
00720        case OPTION_DRIVER_NAME:
00721          driver_name = optarg;
00722          break;
00723        case OPTION_DRIVER_FLAGS:
00724          driver_flags = optarg;
00725          break;
00726        case OPTION_DLLTOOL_NAME:
00727          dlltool_name = optarg;
00728          break;
00729        case OPTION_TARGET:
00730          target = optarg;
00731          break;
00732        case OPTION_MNO_CYGWIN:
00733          target = "i386-mingw32";
00734          break;
00735        case OPTION_BASE_FILE:
00736          base_file_name = optarg;
00737          delete_base_file = 0;
00738          break;
00739        case OPTION_OUTPUT_EXP:
00740          exp_file_name = optarg;
00741          delete_exp_file = 0;
00742          break;
00743        case OPTION_EXPORT_ALL_SYMS:
00744          export_all = 1;
00745          break;
00746        case OPTION_OUTPUT_LIB:
00747          output_lib_file_name = optarg;
00748          break;
00749        case '?':
00750          break;
00751        default:
00752          dlltool_arg = 1;
00753          break;
00754        }
00755 
00756       /* Handle passing through --option=value case.  */
00757       if (optarg
00758          && saved_argv[optind-1][0] == '-'
00759          && saved_argv[optind-1][1] == '-'
00760          && strchr (saved_argv[optind-1], '='))
00761        single_word_option_value_pair = 1;
00762 
00763       if (dlltool_arg)
00764        {
00765          dlltool_arg_indices[optind-1] = 1;
00766          if (optarg && ! single_word_option_value_pair)
00767            {
00768              dlltool_arg_indices[optind-2] = 1;
00769            }
00770        }
00771 
00772       if (! driver_arg)
00773        {
00774          driver_arg_indices[optind-1] = 0;
00775          if (optarg && ! single_word_option_value_pair)
00776            {
00777              driver_arg_indices[optind-2] = 0;
00778            }
00779        }
00780     }
00781 
00782   /* Sanity checks.  */
00783   if (! dll_name && ! dll_file_name)
00784     {
00785       warn (_("Must provide at least one of -o or --dllname options"));
00786       exit (1);
00787     }
00788   else if (! dll_name)
00789     {
00790       dll_name = xstrdup (mybasename (dll_file_name));
00791     }
00792   else if (! dll_file_name)
00793     {
00794       dll_file_name = xstrdup (dll_name);
00795     }
00796 
00797   /* Deduce driver-name and dlltool-name from our own.  */
00798   if (driver_name == NULL)
00799     driver_name = deduce_name ("gcc");
00800 
00801   if (dlltool_name == NULL)
00802     dlltool_name = deduce_name ("dlltool");
00803 
00804   if (! def_file_seen)
00805     {
00806       char *fileprefix = choose_temp_base ();
00807 
00808       def_file_name = (char *) xmalloc (strlen (fileprefix) + 5);
00809       sprintf (def_file_name, "%s.def",
00810               (dontdeltemps) ? mybasename (fileprefix) : fileprefix);
00811       delete_def_file = 1;
00812       free (fileprefix);
00813       delete_def_file = 1;
00814       warn (_("no export definition file provided.\n\
00815 Creating one, but that may not be what you want"));
00816     }
00817 
00818   /* Set the target platform.  */
00819   if (strstr (target, "cygwin"))
00820     which_target = CYGWIN_TARGET;
00821   else if (strstr (target, "mingw"))
00822     which_target = MINGW_TARGET;
00823   else
00824     which_target = UNKNOWN_TARGET;
00825 
00826   /* Re-create the command lines as a string, taking care to quote stuff.  */
00827   dlltool_cmdline = dyn_string_new (cmdline_len);
00828   if (verbose)
00829     dyn_string_append_cstr (dlltool_cmdline, " -v");
00830 
00831   dyn_string_append_cstr (dlltool_cmdline, " --dllname ");
00832   dyn_string_append_cstr (dlltool_cmdline, dll_name);
00833 
00834   for (i = 1; i < argc; ++i)
00835     {
00836       if (dlltool_arg_indices[i])
00837        {
00838          char *arg = saved_argv[i];
00839          int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
00840          dyn_string_append_cstr (dlltool_cmdline,
00841                             (quote) ? " \"" : " ");
00842          dyn_string_append_cstr (dlltool_cmdline, arg);
00843          dyn_string_append_cstr (dlltool_cmdline,
00844                             (quote) ? "\"" : "");
00845        }
00846     }
00847 
00848   driver_cmdline = dyn_string_new (cmdline_len);
00849   if (! driver_flags || strlen (driver_flags) == 0)
00850     {
00851       switch (which_target)
00852        {
00853        case CYGWIN_TARGET:
00854          driver_flags = cygwin_driver_flags;
00855          break;
00856 
00857        case MINGW_TARGET:
00858          driver_flags = mingw32_driver_flags;
00859          break;
00860 
00861        default:
00862          driver_flags = generic_driver_flags;
00863          break;
00864        }
00865     }
00866   dyn_string_append_cstr (driver_cmdline, driver_flags);
00867   dyn_string_append_cstr (driver_cmdline, " -o ");
00868   dyn_string_append_cstr (driver_cmdline, dll_file_name);
00869 
00870   if (! entry_point || strlen (entry_point) == 0)
00871     {
00872       switch (which_target)
00873        {
00874        case CYGWIN_TARGET:
00875          entry_point = "__cygwin_dll_entry@12";
00876          break;
00877 
00878        case MINGW_TARGET:
00879          entry_point = "_DllMainCRTStartup@12";
00880          break;
00881 
00882        default:
00883          entry_point = "_DllMain@12";
00884          break;
00885        }
00886     }
00887   dyn_string_append_cstr (driver_cmdline, " -Wl,-e,");
00888   dyn_string_append_cstr (driver_cmdline, entry_point);
00889   dyn_string_append_cstr (dlltool_cmdline, " --exclude-symbol=");
00890   dyn_string_append_cstr (dlltool_cmdline,
00891                     (entry_point[0] == '_') ? entry_point+1 : entry_point);
00892 
00893   if (! image_base_str || strlen (image_base_str) == 0)
00894     {
00895       char *tmpbuf = (char *) xmalloc (sizeof ("0x12345678") + 1);
00896       unsigned long hash = strhash (dll_file_name);
00897       sprintf (tmpbuf, "0x%.8lX", 0x60000000|((hash<<16)&0xFFC0000));
00898       image_base_str = tmpbuf;
00899     }
00900 
00901   dyn_string_append_cstr (driver_cmdline, " -Wl,--image-base,");
00902   dyn_string_append_cstr (driver_cmdline, image_base_str);
00903 
00904   if (verbose)
00905     {
00906       dyn_string_append_cstr (driver_cmdline, " -v");
00907     }
00908 
00909   for (i = 1; i < argc; ++i)
00910     {
00911       if (driver_arg_indices[i])
00912        {
00913          char *arg = saved_argv[i];
00914          int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
00915          dyn_string_append_cstr (driver_cmdline,
00916                             (quote) ? " \"" : " ");
00917          dyn_string_append_cstr (driver_cmdline, arg);
00918          dyn_string_append_cstr (driver_cmdline,
00919                             (quote) ? "\"" : "");
00920        }
00921     }
00922 
00923   /* Step pre-1. If no --def <EXPORT_DEF> is specified,
00924      then create it and then pass it on.  */
00925 
00926   if (! def_file_seen)
00927     {
00928       int i;
00929       dyn_string_t step_pre1;
00930 
00931       step_pre1 = dyn_string_new (1024);
00932 
00933       dyn_string_append_cstr (step_pre1, dlltool_cmdline->s);
00934       if (export_all)
00935        {
00936          dyn_string_append_cstr (step_pre1, " --export-all --exclude-symbol=");
00937          dyn_string_append_cstr (step_pre1,
00938          "_cygwin_dll_entry@12,DllMainCRTStartup@12,DllMain@12,DllEntryPoint@12");
00939        }
00940       dyn_string_append_cstr (step_pre1, " --output-def ");
00941       dyn_string_append_cstr (step_pre1, def_file_name);
00942 
00943       for (i = 1; i < argc; ++i)
00944        {
00945          if (driver_arg_indices[i])
00946            {
00947              char *arg = saved_argv[i];
00948              size_t len = strlen (arg);
00949              if (len >= 2 && arg[len-2] == '.'
00950                  && (arg[len-1] == 'o' || arg[len-1] == 'a'))
00951               {
00952                 int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
00953                 dyn_string_append_cstr (step_pre1,
00954                                  (quote) ? " \"" : " ");
00955                 dyn_string_append_cstr (step_pre1, arg);
00956                 dyn_string_append_cstr (step_pre1,
00957                                  (quote) ? "\"" : "");
00958               }
00959            }
00960        }
00961 
00962       if (run (dlltool_name, step_pre1->s))
00963        cleanup_and_exit (1);
00964 
00965       dyn_string_delete (step_pre1);
00966     }
00967 
00968   dyn_string_append_cstr (dlltool_cmdline, " --def ");
00969   dyn_string_append_cstr (dlltool_cmdline, def_file_name);
00970 
00971   if (verbose)
00972     {
00973       fprintf (stderr, _("DLLTOOL name    : %s\n"), dlltool_name);
00974       fprintf (stderr, _("DLLTOOL options : %s\n"), dlltool_cmdline->s);
00975       fprintf (stderr, _("DRIVER name     : %s\n"), driver_name);
00976       fprintf (stderr, _("DRIVER options  : %s\n"), driver_cmdline->s);
00977     }
00978 
00979   /* Step 1. Call GCC/LD to create base relocation file. If using GCC, the
00980      driver command line will look like the following:
00981     
00982         % gcc -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
00983     
00984      If the user does not specify a base name, create temporary one that
00985      is deleted at exit.  */
00986 
00987   if (! base_file_name)
00988     {
00989       char *fileprefix = choose_temp_base ();
00990       base_file_name = (char *) xmalloc (strlen (fileprefix) + 6);
00991       sprintf (base_file_name, "%s.base",
00992               (dontdeltemps) ? mybasename (fileprefix) : fileprefix);
00993       delete_base_file = 1;
00994       free (fileprefix);
00995     }
00996 
00997   {
00998     int quote;
00999 
01000     dyn_string_t step1 = dyn_string_new (driver_cmdline->length
01001                                     + strlen (base_file_name)
01002                                     + 20);
01003     dyn_string_append_cstr (step1, "-Wl,--base-file,");
01004     quote = (strchr (base_file_name, ' ')
01005             || strchr (base_file_name, '\t'));
01006     dyn_string_append_cstr (step1,
01007                       (quote) ? "\"" : "");
01008     dyn_string_append_cstr (step1, base_file_name);
01009     dyn_string_append_cstr (step1,
01010                       (quote) ? "\"" : "");
01011     if (driver_cmdline->length)
01012       {
01013        dyn_string_append_cstr (step1, " ");
01014        dyn_string_append_cstr (step1, driver_cmdline->s);
01015       }
01016 
01017     if (run (driver_name, step1->s))
01018       cleanup_and_exit (1);
01019 
01020     dyn_string_delete (step1);
01021   }
01022 
01023   /* Step 2. generate the exp file by running dlltool.
01024      dlltool command line will look like the following:
01025     
01026         % dlltool -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
01027     
01028      If the user does not specify a base name, create temporary one that
01029      is deleted at exit.  */
01030 
01031   if (! exp_file_name)
01032     {
01033       char *p = strrchr (dll_name, '.');
01034       size_t prefix_len = (p) ? (size_t) (p - dll_name) : strlen (dll_name);
01035 
01036       exp_file_name = (char *) xmalloc (prefix_len + 4 + 1);
01037       strncpy (exp_file_name, dll_name, prefix_len);
01038       exp_file_name[prefix_len] = '\0';
01039       strcat (exp_file_name, ".exp");
01040       delete_exp_file = 1;
01041     }
01042 
01043   {
01044     int quote;
01045 
01046     dyn_string_t step2 = dyn_string_new (dlltool_cmdline->length
01047                                     + strlen (base_file_name)
01048                                     + strlen (exp_file_name)
01049                                      + 20);
01050 
01051     dyn_string_append_cstr (step2, "--base-file ");
01052     quote = (strchr (base_file_name, ' ')
01053             || strchr (base_file_name, '\t'));
01054     dyn_string_append_cstr (step2,
01055                       (quote) ? "\"" : "");
01056     dyn_string_append_cstr (step2, base_file_name);
01057     dyn_string_append_cstr (step2,
01058                       (quote) ? "\" " : " ");
01059 
01060     dyn_string_append_cstr (step2, "--output-exp ");
01061     quote = (strchr (exp_file_name, ' ')
01062             || strchr (exp_file_name, '\t'));
01063     dyn_string_append_cstr (step2,
01064                       (quote) ? "\"" : "");
01065     dyn_string_append_cstr (step2, exp_file_name);
01066     dyn_string_append_cstr (step2,
01067                       (quote) ? "\"" : "");
01068 
01069     if (dlltool_cmdline->length)
01070       {
01071        dyn_string_append_cstr (step2, " ");
01072        dyn_string_append_cstr (step2, dlltool_cmdline->s);
01073       }
01074 
01075     if (run (dlltool_name, step2->s))
01076       cleanup_and_exit (1);
01077 
01078     dyn_string_delete (step2);
01079   }
01080 
01081   /*
01082    * Step 3. Call GCC/LD to again, adding the exp file this time.
01083    * driver command line will look like the following:
01084    *
01085    *    % gcc -Wl,--dll --Wl,--base-file,foo.base foo.exp [rest ...]
01086    */
01087 
01088   {
01089     int quote;
01090 
01091     dyn_string_t step3 = dyn_string_new (driver_cmdline->length
01092                                     + strlen (exp_file_name)
01093                                     + strlen (base_file_name)
01094                                      + 20);
01095     dyn_string_append_cstr (step3, "-Wl,--base-file,");
01096     quote = (strchr (base_file_name, ' ')
01097             || strchr (base_file_name, '\t'));
01098     dyn_string_append_cstr (step3,
01099                       (quote) ? "\"" : "");
01100     dyn_string_append_cstr (step3, base_file_name);
01101     dyn_string_append_cstr (step3,
01102                       (quote) ? "\" " : " ");
01103 
01104     quote = (strchr (exp_file_name, ' ')
01105             || strchr (exp_file_name, '\t'));
01106     dyn_string_append_cstr (step3,
01107                       (quote) ? "\"" : "");
01108     dyn_string_append_cstr (step3, exp_file_name);
01109     dyn_string_append_cstr (step3,
01110                       (quote) ? "\"" : "");
01111 
01112     if (driver_cmdline->length)
01113       {
01114        dyn_string_append_cstr (step3, " ");
01115        dyn_string_append_cstr (step3, driver_cmdline->s);
01116       }
01117 
01118     if (run (driver_name, step3->s))
01119       cleanup_and_exit (1);
01120 
01121     dyn_string_delete (step3);
01122   }
01123 
01124 
01125   /*
01126    * Step 4. Run DLLTOOL again using the same command line.
01127    */
01128 
01129   {
01130     int quote;
01131     dyn_string_t step4 = dyn_string_new (dlltool_cmdline->length
01132                                     + strlen (base_file_name)
01133                                     + strlen (exp_file_name)
01134                                      + 20);
01135 
01136     dyn_string_append_cstr (step4, "--base-file ");
01137     quote = (strchr (base_file_name, ' ')
01138             || strchr (base_file_name, '\t'));
01139     dyn_string_append_cstr (step4,
01140                       (quote) ? "\"" : "");
01141     dyn_string_append_cstr (step4, base_file_name);
01142     dyn_string_append_cstr (step4,
01143                       (quote) ? "\" " : " ");
01144 
01145     dyn_string_append_cstr (step4, "--output-exp ");
01146     quote = (strchr (exp_file_name, ' ')
01147             || strchr (exp_file_name, '\t'));
01148     dyn_string_append_cstr (step4,
01149                       (quote) ? "\"" : "");
01150     dyn_string_append_cstr (step4, exp_file_name);
01151     dyn_string_append_cstr (step4,
01152                       (quote) ? "\"" : "");
01153 
01154     if (dlltool_cmdline->length)
01155       {
01156        dyn_string_append_cstr (step4, " ");
01157        dyn_string_append_cstr (step4, dlltool_cmdline->s);
01158       }
01159 
01160     if (output_lib_file_name)
01161       {
01162        dyn_string_append_cstr (step4, " --output-lib ");
01163        dyn_string_append_cstr (step4, output_lib_file_name);
01164       }
01165 
01166     if (run (dlltool_name, step4->s))
01167       cleanup_and_exit (1);
01168 
01169     dyn_string_delete (step4);
01170   }
01171 
01172 
01173   /*
01174    * Step 5. Link it all together and be done with it.
01175    * driver command line will look like the following:
01176    *
01177    *    % gcc -Wl,--dll foo.exp [rest ...]
01178    *
01179    */
01180 
01181   {
01182     int quote;
01183 
01184     dyn_string_t step5 = dyn_string_new (driver_cmdline->length
01185                                     + strlen (exp_file_name)
01186                                      + 20);
01187     quote = (strchr (exp_file_name, ' ')
01188             || strchr (exp_file_name, '\t'));
01189     dyn_string_append_cstr (step5,
01190                       (quote) ? "\"" : "");
01191     dyn_string_append_cstr (step5, exp_file_name);
01192     dyn_string_append_cstr (step5,
01193                       (quote) ? "\"" : "");
01194 
01195     if (driver_cmdline->length)
01196       {
01197        dyn_string_append_cstr (step5, " ");
01198        dyn_string_append_cstr (step5, driver_cmdline->s);
01199       }
01200 
01201     if (run (driver_name, step5->s))
01202       cleanup_and_exit (1);
01203 
01204     dyn_string_delete (step5);
01205   }
01206 
01207   cleanup_and_exit (0);
01208 
01209   return 0;
01210 }