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