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