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