1 /* VMS linker wrapper. 2 Copyright (C) 2011-2024 Free Software Foundation, Inc. 3 Contributed by AdaCore 4 5 This file is part of GCC. 6 7 GCC 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 3, or (at your option) 10 any later version. 11 12 GCC 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 GCC; see the file COPYING3. If not see 19 <http://www.gnu.org/licenses/>. */ 20 21 /* This program is a wrapper around the VMS linker. 22 It translates Unix style command line options into corresponding 23 VMS style qualifiers and then spawns the VMS linker. 24 25 It is possible to build this program on UNIX but only for the purpose of 26 checking for errors. */ 27 28 #include <stdlib.h> 29 #include <string.h> 30 #include <unistd.h> 31 #include <stdio.h> 32 33 #include "libiberty.h" 34 #include <safe-ctype.h> 35 #include <sys/stat.h> 36 37 /* Macro for logicals. */ 38 #define LNM__STRING 2 39 #define LNM_C_NAMLENGTH 255 40 #define PSL_C_SUPER 2 41 #define PSL_C_USER 3 42 43 /* Local variable declarations. */ 44 static int ld_nocall_debug = 0; 45 static int ld_mkthreads = 0; 46 static int ld_upcalls = 0; 47 48 /* verbose = 1 if -v passed. */ 49 static int verbose = 0; 50 51 /* save_temps = 1 if -save-temps passed. */ 52 static int save_temps = 0; 53 54 /* By default don't generate executable file if there are errors 55 in the link. Override with --noinhibit-exec. */ 56 static int inhibit_exec = 1; 57 58 /* debug = 1 if -g passed. */ 59 static int debug = 0; 60 61 /* By default prefer to link with static libraries. */ 62 static int staticp = 1; 63 64 /* By default generate an executable, not a shareable image library. 65 Override with -shared. */ 66 static int share = 0; 67 68 /* Linker command line. */ 69 static int link_cmd_maxlen = 0; 70 static char *link_cmd = 0; 71 static int link_cmd_len = 0; 72 73 /* Keep track of filenames. */ 74 static char *sharebasename; 75 static const char *exefullfilename; 76 static const char *exefilename; 77 78 /* Search dir list passed on command line (with -L). */ 79 static const char **search_dirs; 80 static int search_dirs_len; 81 82 /* Local function declarations. */ 83 static void addarg (const char *); 84 static int is_regular_file (char *); 85 static char *to_host_file_spec (char *); 86 static char *locate_lib (char *); 87 static const char *expand_lib (char *); 88 static void preprocess_args (int, char **); 89 static void process_args (int, char **); 90 static void maybe_set_link_compat (void); 91 static int set_exe (const char *); 92 #ifdef VMS 93 static int translate_unix (char *, int); 94 #endif 95 96 98 /* Return 1 if STR string starts with PREFIX. */ 99 100 static inline int 101 startswith (const char *str, const char *prefix) 102 { 103 return strncmp (str, prefix, strlen (prefix)) == 0; 104 } 105 106 /* Append STR to the command line to invoke the linker. 107 Expand the line as necessary to accommodate. */ 108 109 static void 110 addarg (const char *str) 111 { 112 int l = strlen (str); 113 114 /* Extend the line. */ 115 if (link_cmd_len + l >= link_cmd_maxlen) 116 { 117 link_cmd_maxlen = link_cmd_len + l + 1024; 118 link_cmd = XRESIZEVEC (char, link_cmd, link_cmd_maxlen); 119 } 120 121 memcpy (link_cmd + link_cmd_len, str, l); 122 link_cmd_len += l; 123 } 124 125 /* Check to see if NAME is a regular file, i.e. not a directory. */ 126 127 static int 128 is_regular_file (char *name) 129 { 130 int ret; 131 struct stat statbuf; 132 133 ret = stat (name, &statbuf); 134 return !ret && S_ISREG (statbuf.st_mode); 135 } 136 137 #ifdef VMS 138 static char new_host_filespec [255]; 139 static char filename_buff [256]; 140 141 /* Action routine called by decc$to_vms. NAME is a file name or 142 directory name. TYPE is unused. */ 143 144 static int 145 translate_unix (char *name, int type ATTRIBUTE_UNUSED) 146 { 147 strcpy (filename_buff, name); 148 return 0; 149 } 150 #endif 151 152 /* Translate a Unix syntax file specification FILESPEC into VMS syntax. 153 If indicators of VMS syntax found, return input string. 154 Return a pointer to a static buffer. */ 155 156 static char * 157 to_host_file_spec (char *filespec) 158 { 159 #ifdef VMS 160 if (strchr (filespec, ']') || strchr (filespec, ':')) 161 { 162 /* Looks like a VMS path. */ 163 return filespec; 164 } 165 else 166 { 167 168 strcpy (filename_buff, filespec); 169 decc$to_vms (filespec, translate_unix, 1, 1); 170 strcpy (new_host_filespec, filename_buff); 171 return new_host_filespec; 172 } 173 #else 174 return filespec; 175 #endif 176 } 177 178 /* Locate library LIB_NAME on the library path. */ 179 180 static char * 181 locate_lib (char *lib_name) 182 { 183 int lib_len = strlen (lib_name); 184 const char *exts[3]; 185 int i; 186 187 if (staticp) 188 { 189 /* For static links, look for shareable image libraries last. */ 190 exts[0] = ".a"; 191 exts[1] = ".olb"; 192 exts[2] = ".exe"; 193 } 194 else 195 { 196 exts[0] = ".exe"; 197 exts[1] = ".a"; 198 exts[2] = ".olb"; 199 } 200 201 for (i = 0; i < search_dirs_len; i++) 202 { 203 char *buf; 204 int l; 205 int j; 206 207 l = strlen (search_dirs[i]); 208 buf = (char *)alloca (l + 4 + lib_len + 4 + 1); 209 /* Put PATH/libLIB. */ 210 memcpy (buf, search_dirs[i], l); 211 memcpy (buf + l, "/lib", 4); 212 l += 4; 213 memcpy (buf + l, lib_name, lib_len); 214 l += lib_len; 215 216 /* Look for files with the extensions. */ 217 for (j = 0; j < 3; j++) 218 { 219 strcpy (buf + l, exts[j]); 220 if (is_regular_file (buf)) 221 return xstrdup (to_host_file_spec (buf)); 222 } 223 } 224 225 return NULL; 226 } 227 228 /* Given a library name NAME, i.e. foo, Look for libfoo.lib and then 229 libfoo.a in the set of directories we are allowed to search in. 230 May return NULL if the library can be discarded. */ 231 232 static const char * 233 expand_lib (char *name) 234 { 235 char *lib_path; 236 237 /* Discard libc. */ 238 if (strcmp (name, "c") == 0) 239 return NULL; 240 241 /* Discard libm. No separate library for math functions. */ 242 if (strcmp (name, "m") == 0) 243 return NULL; 244 245 /* Search on path. */ 246 lib_path = locate_lib (name); 247 if (lib_path) 248 return lib_path; 249 250 fprintf (stderr, 251 "Couldn't locate library: lib%s.exe, lib%s.a or lib%s.olb\n", 252 name, name, name); 253 254 exit (EXIT_FAILURE); 255 } 256 257 /* Preprocess the number of args P_ARGC in ARGV. 258 Look for special flags, etc. that must be handled first. */ 259 260 static void 261 preprocess_args (int argc, char **argv) 262 { 263 int i; 264 265 /* Scan for -shared. */ 266 for (i = 1; i < argc; i++) 267 if (strcmp (argv[i], "-shared") == 0) 268 { 269 share = 1; 270 break; 271 } 272 273 for (i = 1; i < argc; i++) 274 if (strcmp (argv[i], "-o") == 0) 275 { 276 int len; 277 278 i++; 279 exefilename = lbasename (argv[i]); 280 exefullfilename = xstrdup (to_host_file_spec (argv[i])); 281 282 if (share) 283 addarg(" /share="); 284 else 285 addarg (" /exe="); 286 addarg (exefullfilename); 287 288 if (share) 289 { 290 char *ptr; 291 292 /* Extract the basename. */ 293 ptr = strchr (argv[i], ']'); 294 if (ptr == NULL) 295 ptr = strchr (argv[i], ':'); 296 if (ptr == NULL) 297 ptr = strchr (argv[i], '/'); 298 if (ptr == NULL) 299 sharebasename = xstrdup (argv[i]); 300 else 301 sharebasename = xstrdup (ptr + 1); 302 303 len = strlen (sharebasename); 304 if (strncasecmp (&sharebasename[len-4], ".exe", 4) == 0) 305 sharebasename[len - 4] = 0; 306 307 /* Convert to uppercase. */ 308 for (ptr = sharebasename; *ptr; ptr++) 309 *ptr = TOUPPER (*ptr); 310 } 311 } 312 313 if (exefullfilename == NULL && !share) 314 { 315 exefilename = "a_out.exe"; 316 exefullfilename = "a_out.exe"; 317 addarg (xstrdup (" /exe=a_out.exe")); 318 } 319 } 320 321 /* Preprocess the number of args ARGC in ARGV. Look for 322 special flags, etc. that must be handled for the VMS linker. */ 323 324 static void 325 process_args (int argc, char **argv) 326 { 327 int i; 328 329 for (i = 1; i < argc; i++) 330 { 331 if (startswith (argv[i], "-L")) 332 { 333 search_dirs = XRESIZEVEC(const char *, search_dirs, 334 search_dirs_len + 1); 335 search_dirs[search_dirs_len++] = &argv[i][2]; 336 } 337 338 /* -v turns on verbose option here and is passed on to gcc. */ 339 else if (strcmp (argv[i], "-v") == 0) 340 verbose++; 341 else if (strcmp (argv[i], "--version") == 0) 342 { 343 fprintf (stdout, "VMS Linker\n"); 344 exit (EXIT_SUCCESS); 345 } 346 else if (strcmp (argv[i], "--help") == 0) 347 { 348 fprintf (stdout, "VMS Linker\n"); 349 exit (EXIT_SUCCESS); 350 } 351 else if (strcmp (argv[i], "-g0") == 0) 352 addarg ("/notraceback"); 353 else if (startswith (argv[i], "-g")) 354 { 355 addarg ("/debug"); 356 debug = 1; 357 } 358 else if (strcmp (argv[i], "-static") == 0) 359 staticp = 1; 360 else if (strcmp (argv[i], "-map") == 0) 361 { 362 char *buff, *ptr; 363 364 buff = (char *) xstrdup (exefullfilename); 365 ptr = strrchr (buff, '.'); 366 if (ptr) 367 *ptr = 0; 368 369 strcat (buff, ".map"); 370 addarg ("/map="); 371 addarg (buff); 372 addarg (".map"); 373 addarg ("/full"); 374 375 free (buff); 376 } 377 else if (strcmp (argv[i], "-save-temps") == 0) 378 save_temps = 1; 379 else if (strcmp (argv[i], "--noinhibit-exec") == 0) 380 inhibit_exec = 0; 381 } 382 } 383 384 #ifdef VMS 385 typedef struct dsc 386 { 387 unsigned short len, mbz; 388 const char *adr; 389 } Descriptor; 390 391 struct lst 392 { 393 unsigned short buflen, item_code; 394 const void *bufaddr; 395 void *retlenaddr; 396 }; 397 398 static struct 399 { 400 struct lst items [1]; 401 unsigned int terminator; 402 } item_lst1; 403 404 static struct 405 { 406 struct lst items [2]; 407 unsigned int terminator; 408 } item_lst2; 409 410 /* Checks if logical names are defined for setting system library path and 411 linker program to enable compatibility with earlier VMS versions. */ 412 413 static void 414 maybe_set_link_compat (void) 415 { 416 char lnm_buff [LNM_C_NAMLENGTH]; 417 unsigned int lnm_buff_len; 418 int status; 419 Descriptor tabledsc, linkdsc; 420 421 tabledsc.adr = "LNM$JOB"; 422 tabledsc.len = strlen (tabledsc.adr); 423 tabledsc.mbz = 0; 424 425 linkdsc.adr = "GCC_LD_SYS$LIBRARY"; 426 linkdsc.len = strlen (linkdsc.adr); 427 linkdsc.mbz = 0; 428 429 item_lst1.items[0].buflen = LNM_C_NAMLENGTH; 430 item_lst1.items[0].item_code = LNM__STRING; 431 item_lst1.items[0].bufaddr = lnm_buff; 432 item_lst1.items[0].retlenaddr = &lnm_buff_len; 433 item_lst1.terminator = 0; 434 435 status = SYS$TRNLNM 436 (0, /* attr */ 437 &tabledsc, /* tabnam */ 438 &linkdsc, /* lognam */ 439 0, /* acmode */ 440 &item_lst1); 441 442 /* If GCC_LD_SYS$LIBRARY is defined, redefine SYS$LIBRARY to search 443 the equivalence name first for system libraries, then the default 444 system library directory */ 445 446 if ((status & 1) == 1) 447 { 448 unsigned char acmode = PSL_C_USER; /* Don't retain after image exit */ 449 const char *syslib = "SYS$SYSROOT:[SYSLIB]"; /* Default SYS$LIBRARY */ 450 451 /* Only visible to current and child processes */ 452 tabledsc.adr = "LNM$PROCESS"; 453 tabledsc.len = strlen (tabledsc.adr); 454 tabledsc.mbz = 0; 455 456 linkdsc.adr = "SYS$LIBRARY"; 457 linkdsc.len = strlen (linkdsc.adr); 458 linkdsc.mbz = 0; 459 460 item_lst2.items[0].buflen = lnm_buff_len; 461 item_lst2.items[0].item_code = LNM__STRING; 462 item_lst2.items[0].bufaddr = lnm_buff; 463 item_lst2.items[0].retlenaddr = 0; 464 465 item_lst2.items[1].buflen = strlen (syslib); 466 item_lst2.items[1].item_code = LNM__STRING; 467 item_lst2.items[1].bufaddr = syslib; 468 item_lst2.items[1].retlenaddr = 0; 469 item_lst2.terminator = 0; 470 471 status = SYS$CRELNM 472 (0, /* attr */ 473 &tabledsc, /* tabnam */ 474 &linkdsc, /* lognam */ 475 &acmode, /* acmode */ 476 &item_lst2); 477 478 } 479 480 tabledsc.adr = "LNM$JOB"; 481 tabledsc.len = strlen (tabledsc.adr); 482 tabledsc.mbz = 0; 483 484 linkdsc.adr = "GCC_LD_LINK"; 485 linkdsc.len = strlen (linkdsc.adr); 486 linkdsc.mbz = 0; 487 488 item_lst1.items[0].buflen = LNM_C_NAMLENGTH; 489 item_lst1.items[0].item_code = LNM__STRING; 490 item_lst1.items[0].bufaddr = lnm_buff; 491 item_lst1.items[0].retlenaddr = &lnm_buff_len; 492 item_lst1.terminator = 0; 493 494 status = SYS$TRNLNM 495 (0, /* attr */ 496 &tabledsc, /* tabnam */ 497 &linkdsc, /* lognam */ 498 0, /* acmode */ 499 &item_lst1); 500 501 /* If GCC_LD_LINK is defined, redefine LINK to use the equivalence name 502 (sometimes the LINK program version is used by VMS to determine 503 compatibility). */ 504 505 if ((status & 1) == 1) 506 { 507 unsigned char acmode = PSL_C_USER; /* Don't retain after image exit. */ 508 509 /* Only visible to current and child processes. */ 510 tabledsc.adr = "LNM$PROCESS"; 511 tabledsc.len = strlen (tabledsc.adr); 512 tabledsc.mbz = 0; 513 514 linkdsc.adr = "LINK"; 515 linkdsc.len = strlen (linkdsc.adr); 516 linkdsc.mbz = 0; 517 518 item_lst1.items[0].buflen = lnm_buff_len; 519 item_lst1.items[0].item_code = LNM__STRING; 520 item_lst1.items[0].bufaddr = lnm_buff; 521 item_lst1.items[0].retlenaddr = 0; 522 item_lst1.terminator = 0; 523 524 status = SYS$CRELNM 525 (0, /* attr */ 526 &tabledsc, /* tabnam */ 527 &linkdsc, /* lognam */ 528 &acmode, /* acmode */ 529 &item_lst1); 530 } 531 } 532 #else 533 static void 534 maybe_set_link_compat (void) 535 { 536 } 537 #endif 538 539 /* Set environment defined executable attributes. */ 540 541 static int 542 set_exe (const char *arg) 543 { 544 char allargs [1024]; 545 int res; 546 547 snprintf (allargs, sizeof (allargs), 548 "$@gnu:[bin]set_exe %s %s", exefullfilename, arg); 549 if (verbose) 550 printf ("%s\n", allargs); 551 552 res = system (allargs); 553 if (verbose > 1) 554 printf ("$!status = %d\n", res); 555 556 if ((res & 1) != 1) 557 { 558 fprintf (stderr, "ld error: popen set_exe\n"); 559 return 1; 560 } 561 return 0; 562 } 563 564 /* The main program. Spawn the VMS linker after fixing up the Unix-like flags 565 and args to be what the VMS linker wants. */ 566 567 int 568 main (int argc, char **argv) 569 { 570 /* File specification for vms-dwarf2.o. */ 571 char *vmsdwarf2spec = 0; 572 573 /* File specification for vms-dwarf2eh.o. */ 574 char *vmsdwarf2ehspec = 0; 575 576 int i; 577 char cwdev[128], *devptr; 578 int cwdevlen; 579 FILE *optfile; 580 char *cwd, *ptr; 581 char *optfilename; 582 int status = 0; 583 584 /* Some linker options can be set with logicals. */ 585 if (getenv ("GNAT$LD_NOCALL_DEBUG")) 586 ld_nocall_debug = 1; 587 if (getenv ("GNAT$LD_MKTHREADS")) 588 ld_mkthreads = 1; 589 if (getenv ("GNAT$LD_UPCALLS")) 590 ld_upcalls = 1; 591 if (getenv ("GNAT$LD_SHARED_LIBS")) 592 staticp = 0; 593 594 /* Get current dir. */ 595 #ifdef VMS 596 cwd = getcwd (0, 1024, 1); 597 #else 598 cwd = getcwd (0, 1024); 599 strcat (cwd, "/"); 600 #endif 601 602 /* Extract device part of the path. */ 603 devptr = strchr (cwd, ':'); 604 if (devptr) 605 cwdevlen = (devptr - cwd) + 1; 606 else 607 cwdevlen = 0; 608 memcpy (cwdev, cwd, cwdevlen); 609 cwdev [cwdevlen] = '\0'; 610 611 maybe_set_link_compat (); 612 613 /* Linker command starts with the command name. */ 614 addarg ("$ link"); 615 616 /* Pass to find args that have to be append first. */ 617 preprocess_args (argc , argv); 618 619 /* Pass to find the rest of the args. */ 620 process_args (argc , argv); 621 622 if (!verbose) 623 addarg ("/noinform"); 624 625 /* Create a temp file to hold args, otherwise we can easily exceed the VMS 626 command line length limits. */ 627 optfilename = (char *) xmalloc (strlen (exefilename) + 13); 628 strcpy (optfilename, exefilename); 629 ptr = strrchr (optfilename, '.'); 630 if (ptr) 631 *ptr = 0; 632 strcat (optfilename, ".opt_tmpfile"); 633 optfile = fopen (optfilename, "w"); 634 635 /* Write out the IDENTIFICATION argument first so that it can be overridden 636 by an options file. */ 637 for (i = 1; i < argc; i++) 638 { 639 int arg_len = strlen (argv[i]); 640 641 if (arg_len > 6 && strncasecmp (argv[i], "IDENT=", 6) == 0) 642 { 643 /* Comes from command line. If present will always appear before 644 --identification=... and will override. */ 645 break; 646 } 647 else if (arg_len > 17 648 && strncasecmp (argv[i], "--identification=", 17) == 0) 649 { 650 /* Comes from pragma Ident (). */ 651 fprintf (optfile, "case_sensitive=yes\n"); 652 fprintf (optfile, "IDENTIFICATION=\"%-.15s\"\n", &argv[i][17]); 653 fprintf (optfile, "case_sensitive=NO\n"); 654 } 655 } 656 657 for (i = 1; i < argc; i++) 658 { 659 int arg_len = strlen (argv[i]); 660 661 if (strcmp (argv[i], "-o") == 0) 662 { 663 /* Already handled. */ 664 i++; 665 } 666 else if (arg_len > 2 && startswith (argv[i], "-l")) 667 { 668 const char *libname; 669 670 libname = expand_lib (&argv[i][2]); 671 if (libname != NULL) 672 { 673 int len = strlen (libname); 674 const char *ext; 675 676 if (len > 4 && strcasecmp (&libname [len-4], ".exe") == 0) 677 ext = "/shareable"; 678 else 679 ext = "/library"; 680 681 if (libname[0] == '[') 682 fprintf (optfile, "%s%s%s\n", cwdev, libname, ext); 683 else 684 fprintf (optfile, "%s%s\n", libname, ext); 685 } 686 } 687 else if (strcmp (argv[i], "-v" ) == 0 688 || startswith (argv[i], "-g") 689 || strcmp (argv[i], "-static" ) == 0 690 || strcmp (argv[i], "-map" ) == 0 691 || strcmp (argv[i], "-save-temps") == 0 692 || strcmp (argv[i], "--noinhibit-exec") == 0 693 || (arg_len > 2 && startswith (argv[i], "-L")) 694 || (arg_len >= 6 && startswith (argv[i], "-share"))) 695 { 696 /* Already handled. */ 697 } 698 else if (startswith (argv[i], "--opt=")) 699 fprintf (optfile, "%s\n", argv[i] + 6); 700 else if (arg_len > 1 && argv[i][0] == '@') 701 { 702 /* Read response file (in fact a single line of filenames). */ 703 FILE *atfile; 704 char *ptr, *ptr1; 705 struct stat statbuf; 706 char *buff; 707 int len; 708 709 if (stat (&argv[i][1], &statbuf)) 710 { 711 fprintf (stderr, "Couldn't open linker response file: %s\n", 712 &argv[i][1]); 713 exit (EXIT_FAILURE); 714 } 715 716 /* Read the line. */ 717 buff = (char *) xmalloc (statbuf.st_size + 1); 718 atfile = fopen (&argv[i][1], "r"); 719 fgets (buff, statbuf.st_size + 1, atfile); 720 fclose (atfile); 721 722 /* Remove trailing \n. */ 723 len = strlen (buff); 724 if (buff [len - 1] == '\n') 725 { 726 buff [len - 1] = 0; 727 len--; 728 } 729 730 /* Put the filenames to the opt file. */ 731 ptr = buff; 732 do 733 { 734 ptr1 = strchr (ptr, ' '); 735 if (ptr1) 736 *ptr1 = 0; 737 738 /* Add device name if a path is present. */ 739 ptr = to_host_file_spec (ptr); 740 if (ptr[0] == '[') 741 fprintf (optfile, "%s%s\n", cwdev, ptr); 742 else 743 fprintf (optfile, "%s\n", ptr); 744 745 ptr = ptr1 + 1; 746 } 747 while (ptr1); 748 } 749 else if ((argv[i][0] == '/') && (strchr (&argv[i][1], '/') == 0)) 750 { 751 /* Unix style file specs and VMS style switches look alike, 752 so assume an arg consisting of one and only one slash, 753 and that being first, is really a switch. */ 754 addarg (argv[i]); 755 } 756 else if (arg_len > 4 757 && strncasecmp (&argv[i][arg_len-4], ".opt", 4) == 0) 758 { 759 /* Read option file. */ 760 FILE *optfile1; 761 char buff[256]; 762 763 /* Disable __UNIX_FOPEN redefinition in case user supplied .opt 764 file is not stream oriented. */ 765 766 optfile1 = (fopen) (argv[i], "r"); 767 if (optfile1 == 0) 768 { 769 perror (argv[i]); 770 status = 1; 771 goto cleanup_and_exit; 772 } 773 774 while (fgets (buff, sizeof (buff), optfile1)) 775 fputs (buff, optfile); 776 777 fclose (optfile1); 778 } 779 else if (arg_len > 7 && strncasecmp (argv[i], "GSMATCH", 7) == 0) 780 fprintf (optfile, "%s\n", argv[i]); 781 else if (arg_len > 6 && strncasecmp (argv[i], "IDENT=", 6) == 0) 782 { 783 /* Comes from command line and will override pragma. */ 784 fprintf (optfile, "case_sensitive=yes\n"); 785 fprintf (optfile, "IDENT=\"%15.15s\"\n", &argv[i][6]); 786 fprintf (optfile, "case_sensitive=NO\n"); 787 } 788 else if (arg_len > 17 789 && strncasecmp (argv[i], "--identification=", 17) == 0) 790 { 791 /* Already handled. */ 792 } 793 else 794 { 795 /* Assume filename arg. */ 796 const char *file; 797 const char *addswitch = NULL; 798 char *buff; 799 int buff_len; 800 int is_cld = 0; 801 802 file = to_host_file_spec (argv[i]); 803 arg_len = strlen (file); 804 805 /* Handle shareable image libraries. */ 806 if (arg_len > 4 && strcasecmp (&file[arg_len - 4], ".exe") == 0) 807 addswitch = "/shareable"; 808 else if (arg_len > 4 && strcasecmp (&file[arg_len - 4], ".cld") == 0) 809 { 810 addswitch = "/shareable"; 811 is_cld = 1; 812 } 813 814 /* Handle object libraries. */ 815 else if (arg_len > 2 && strcasecmp (&file[arg_len - 2], ".a") == 0) 816 addswitch = "/lib"; 817 else if (arg_len > 4 && strcasecmp (&file[arg_len - 4], ".olb") == 0) 818 addswitch = "/lib"; 819 820 /* Absolutize file location. */ 821 if (file[0] == '[') 822 { 823 buff = (char *) xmalloc (cwdevlen + arg_len + 1); 824 sprintf (buff, "%s%s", cwdev, file); 825 } 826 else if (strchr (file, ':')) 827 { 828 buff = xstrdup (file); 829 } 830 else 831 { 832 buff = (char *) xmalloc (strlen (cwd) + arg_len + 1); 833 sprintf (buff, "%s%s", cwd, file); 834 } 835 836 buff_len = strlen (buff); 837 838 if (buff_len >= 15 839 && strcasecmp (&buff[buff_len - 14], "vms-dwarf2eh.o") == 0) 840 { 841 /* Remind of it. */ 842 vmsdwarf2ehspec = xstrdup (buff); 843 } 844 else if (buff_len >= 13 845 && strcasecmp (&buff[buff_len - 12], "vms-dwarf2.o") == 0) 846 { 847 /* Remind of it. */ 848 vmsdwarf2spec = xstrdup (buff); 849 } 850 else if (is_cld) 851 { 852 /* Command line definition file. */ 853 addarg (buff); 854 addarg (addswitch); 855 addarg (","); 856 } 857 else 858 { 859 fprintf (optfile, "%s%s\n", 860 buff, addswitch != NULL ? addswitch : ""); 861 } 862 free (buff); 863 } 864 } 865 866 if (vmsdwarf2ehspec) 867 { 868 /* Sequentialize exception handling info. */ 869 870 fprintf (optfile, "case_sensitive=yes\n"); 871 fprintf (optfile, "cluster=DWARF2eh,,,%s\n", vmsdwarf2ehspec); 872 fprintf (optfile, "collect=DWARF2eh,eh_frame\n"); 873 fprintf (optfile, "case_sensitive=NO\n"); 874 } 875 876 if (debug && vmsdwarf2spec) 877 { 878 /* Sequentialize the debug info. */ 879 880 fprintf (optfile, "case_sensitive=yes\n"); 881 fprintf (optfile, "cluster=DWARF2debug,,,%s\n", vmsdwarf2spec); 882 fprintf (optfile, "collect=DWARF2debug,debug_abbrev,debug_aranges,-\n"); 883 fprintf (optfile, " debug_frame,debug_info,debug_line,debug_loc,-\n"); 884 fprintf (optfile, " debug_macinfo,debug_pubnames,debug_str,-\n"); 885 fprintf (optfile, " debug_zzzzzz\n"); 886 fprintf (optfile, "case_sensitive=NO\n"); 887 } 888 889 if (debug && share && vmsdwarf2spec) 890 { 891 /* Sequentialize the shared library debug info. */ 892 893 fprintf (optfile, "case_sensitive=yes\n"); 894 fprintf (optfile, "symbol_vector=(-\n"); 895 fprintf (optfile, 896 "%s$DWARF2.DEBUG_ABBREV/$dwarf2.debug_abbrev=DATA,-\n", 897 sharebasename); 898 fprintf (optfile, 899 "%s$DWARF2.DEBUG_ARANGES/$dwarf2.debug_aranges=DATA,-\n", 900 sharebasename); 901 fprintf (optfile, "%s$DWARF2.DEBUG_FRAME/$dwarf2.debug_frame=DATA,-\n", 902 sharebasename); 903 fprintf (optfile, "%s$DWARF2.DEBUG_INFO/$dwarf2.debug_info=DATA,-\n", 904 sharebasename); 905 fprintf (optfile, "%s$DWARF2.DEBUG_LINE/$dwarf2.debug_line=DATA,-\n", 906 sharebasename); 907 fprintf (optfile, "%s$DWARF2.DEBUG_LOC/$dwarf2.debug_loc=DATA,-\n", 908 sharebasename); 909 fprintf (optfile, 910 "%s$DWARF2.DEBUG_MACINFO/$dwarf2.debug_macinfo=DATA,-\n", 911 sharebasename); 912 fprintf (optfile, 913 "%s$DWARF2.DEBUG_PUBNAMES/$dwarf2.debug_pubnames=DATA,-\n", 914 sharebasename); 915 fprintf (optfile, "%s$DWARF2.DEBUG_STR/$dwarf2.debug_str=DATA,-\n", 916 sharebasename); 917 fprintf (optfile, "%s$DWARF2.DEBUG_ZZZZZZ/$dwarf2.debug_zzzzzz=DATA)\n", 918 sharebasename); 919 fprintf (optfile, "case_sensitive=NO\n"); 920 } 921 922 fprintf (optfile, "PSECT_ATTR=LIB$INITIALIZE,GBL\n"); 923 fclose (optfile); 924 925 /* Append opt file. */ 926 addarg (" "); 927 addarg (optfilename); 928 addarg ("/opt"); 929 930 if (verbose) 931 printf ("%s\n", link_cmd); 932 933 status = system (link_cmd); 934 if (verbose > 1) 935 printf ("$!status = %d\n", status); 936 937 if ((status & 1) != 1) 938 { 939 status = 1; 940 goto cleanup_and_exit; 941 } 942 943 if (debug && !share && ld_nocall_debug) 944 { 945 status = set_exe ("/flags=nocall_debug"); 946 if (status != 0) 947 goto cleanup_and_exit; 948 } 949 950 if (!share && ld_mkthreads) 951 { 952 status = set_exe ("/flags=mkthreads"); 953 if (status != 0) 954 goto cleanup_and_exit; 955 } 956 957 if (!share && ld_upcalls) 958 { 959 status = set_exe ("/flags=upcalls"); 960 if (status != 0) 961 goto cleanup_and_exit; 962 } 963 964 status = 0; 965 966 cleanup_and_exit: 967 if (!save_temps) 968 remove (optfilename); 969 970 if (status == 0) 971 exit (EXIT_SUCCESS); 972 973 if (exefullfilename && inhibit_exec == 1) 974 remove (exefullfilename); 975 976 exit (EXIT_FAILURE); 977 } 978