Home | History | Annotate | Line # | Download | only in vms
      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