]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/vms/vms-ld.c
Update copyright years.
[thirdparty/gcc.git] / gcc / config / vms / vms-ld.c
CommitLineData
18a24fed 1/* VMS linker wrapper.
a945c346 2 Copyright (C) 2011-2024 Free Software Foundation, Inc.
18a24fed
TG
3 Contributed by AdaCore
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 3, or (at your option)
10any later version.
11
12GCC is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along 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. */
44static int ld_nocall_debug = 0;
45static int ld_mkthreads = 0;
46static int ld_upcalls = 0;
47
48/* verbose = 1 if -v passed. */
49static int verbose = 0;
50
51/* save_temps = 1 if -save-temps passed. */
52static 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. */
56static int inhibit_exec = 1;
57
58/* debug = 1 if -g passed. */
59static int debug = 0;
60
61/* By default prefer to link with static libraries. */
62static int staticp = 1;
63
64/* By default generate an executable, not a shareable image library.
65 Override with -shared. */
66static int share = 0;
67
68/* Linker command line. */
69static int link_cmd_maxlen = 0;
70static char *link_cmd = 0;
71static int link_cmd_len = 0;
72
73/* Keep track of filenames. */
74static char *sharebasename;
75static const char *exefullfilename;
76static const char *exefilename;
77
78/* Search dir list passed on command line (with -L). */
79static const char **search_dirs;
80static int search_dirs_len;
81
82/* Local function declarations. */
83static void addarg (const char *);
84static int is_regular_file (char *);
85static char *to_host_file_spec (char *);
86static char *locate_lib (char *);
87static const char *expand_lib (char *);
88static void preprocess_args (int, char **);
89static void process_args (int, char **);
90static void maybe_set_link_compat (void);
91static int set_exe (const char *);
92#ifdef VMS
93static int translate_unix (char *, int);
94#endif
95\f
96
c0129e2d
ML
97/* Return 1 if STR string starts with PREFIX. */
98
99static inline int
100startswith (const char *str, const char *prefix)
101{
102 return strncmp (str, prefix, strlen (prefix)) == 0;
103}
104
18a24fed
TG
105/* Append STR to the command line to invoke the linker.
106 Expand the line as necessary to accommodate. */
107
108static void
109addarg (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
126static int
127is_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
137static char new_host_filespec [255];
138static 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
143static int
144translate_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
155static char *
156to_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
179static char *
180locate_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
231static const char *
232expand_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
259static void
260preprocess_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
323static void
324process_args (int argc, char **argv)
325{
326 int i;
327
328 for (i = 1; i < argc; i++)
329 {
c0129e2d 330 if (startswith (argv[i], "-L"))
18a24fed
TG
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");
c0129e2d 352 else if (startswith (argv[i], "-g"))
18a24fed
TG
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
384typedef struct dsc
385{
386 unsigned short len, mbz;
387 const char *adr;
388} Descriptor;
389
390struct lst
391{
392 unsigned short buflen, item_code;
393 const void *bufaddr;
394 void *retlenaddr;
395};
396
397static struct
398{
399 struct lst items [1];
400 unsigned int terminator;
401} item_lst1;
402
403static 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
412static void
413maybe_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
532static void
533maybe_set_link_compat (void)
534{
535}
536#endif
537
538/* Set environment defined executable attributes. */
539
540static int
541set_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
566int
567main (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");
c2885517 651 fprintf (optfile, "IDENTIFICATION=\"%-.15s\"\n", &argv[i][17]);
18a24fed
TG
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 }
c0129e2d 665 else if (arg_len > 2 && startswith (argv[i], "-l"))
18a24fed
TG
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
c0129e2d 687 || startswith (argv[i], "-g")
18a24fed
TG
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
c0129e2d
ML
692 || (arg_len > 2 && startswith (argv[i], "-L"))
693 || (arg_len >= 6 && startswith (argv[i], "-share")))
18a24fed
TG
694 {
695 /* Already handled. */
696 }
c0129e2d 697 else if (startswith (argv[i], "--opt="))
18a24fed
TG
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}