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