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