2 Copyright (C) 2011-2023 Free Software Foundation, Inc.
5 This file is part of GCC.
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)
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.
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/>. */
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.
25 It is possible to build this program on UNIX but only for the purpose of
26 checking for errors. */
33 #include "libiberty.h"
34 #include <safe-ctype.h>
37 /* Macro for logicals. */
39 #define LNM_C_NAMLENGTH 255
43 /* Local variable declarations. */
44 static int ld_nocall_debug
= 0;
45 static int ld_mkthreads
= 0;
46 static int ld_upcalls
= 0;
48 /* verbose = 1 if -v passed. */
49 static int verbose
= 0;
51 /* save_temps = 1 if -save-temps passed. */
52 static int save_temps
= 0;
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;
58 /* debug = 1 if -g passed. */
61 /* By default prefer to link with static libraries. */
62 static int staticp
= 1;
64 /* By default generate an executable, not a shareable image library.
65 Override with -shared. */
68 /* Linker command line. */
69 static int link_cmd_maxlen
= 0;
70 static char *link_cmd
= 0;
71 static int link_cmd_len
= 0;
73 /* Keep track of filenames. */
74 static char *sharebasename
;
75 static const char *exefullfilename
;
76 static const char *exefilename
;
78 /* Search dir list passed on command line (with -L). */
79 static const char **search_dirs
;
80 static int search_dirs_len
;
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 *);
93 static int translate_unix (char *, int);
97 /* Return 1 if STR string starts with PREFIX. */
100 startswith (const char *str
, const char *prefix
)
102 return strncmp (str
, prefix
, strlen (prefix
)) == 0;
105 /* Append STR to the command line to invoke the linker.
106 Expand the line as necessary to accommodate. */
109 addarg (const char *str
)
111 int l
= strlen (str
);
113 /* Extend the line. */
114 if (link_cmd_len
+ l
>= link_cmd_maxlen
)
116 link_cmd_maxlen
= link_cmd_len
+ l
+ 1024;
117 link_cmd
= XRESIZEVEC (char, link_cmd
, link_cmd_maxlen
);
120 memcpy (link_cmd
+ link_cmd_len
, str
, l
);
124 /* Check to see if NAME is a regular file, i.e. not a directory. */
127 is_regular_file (char *name
)
132 ret
= stat (name
, &statbuf
);
133 return !ret
&& S_ISREG (statbuf
.st_mode
);
137 static char new_host_filespec
[255];
138 static char filename_buff
[256];
140 /* Action routine called by decc$to_vms. NAME is a file name or
141 directory name. TYPE is unused. */
144 translate_unix (char *name
, int type ATTRIBUTE_UNUSED
)
146 strcpy (filename_buff
, name
);
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. */
156 to_host_file_spec (char *filespec
)
159 if (strchr (filespec
, ']') || strchr (filespec
, ':'))
161 /* Looks like a VMS path. */
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
;
177 /* Locate library LIB_NAME on the library path. */
180 locate_lib (char *lib_name
)
182 int lib_len
= strlen (lib_name
);
188 /* For static links, look for shareable image libraries last. */
200 for (i
= 0; i
< search_dirs_len
; i
++)
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);
212 memcpy (buf
+ l
, lib_name
, lib_len
);
215 /* Look for files with the extensions. */
216 for (j
= 0; j
< 3; j
++)
218 strcpy (buf
+ l
, exts
[j
]);
219 if (is_regular_file (buf
))
220 return xstrdup (to_host_file_spec (buf
));
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. */
232 expand_lib (char *name
)
237 if (strcmp (name
, "c") == 0)
240 /* Discard libm. No separate library for math functions. */
241 if (strcmp (name
, "m") == 0)
244 /* Search on path. */
245 lib_path
= locate_lib (name
);
250 "Couldn't locate library: lib%s.exe, lib%s.a or lib%s.olb\n",
256 /* Preprocess the number of args P_ARGC in ARGV.
257 Look for special flags, etc. that must be handled first. */
260 preprocess_args (int argc
, char **argv
)
264 /* Scan for -shared. */
265 for (i
= 1; i
< argc
; i
++)
266 if (strcmp (argv
[i
], "-shared") == 0)
272 for (i
= 1; i
< argc
; i
++)
273 if (strcmp (argv
[i
], "-o") == 0)
278 exefilename
= lbasename (argv
[i
]);
279 exefullfilename
= xstrdup (to_host_file_spec (argv
[i
]));
285 addarg (exefullfilename
);
291 /* Extract the basename. */
292 ptr
= strchr (argv
[i
], ']');
294 ptr
= strchr (argv
[i
], ':');
296 ptr
= strchr (argv
[i
], '/');
298 sharebasename
= xstrdup (argv
[i
]);
300 sharebasename
= xstrdup (ptr
+ 1);
302 len
= strlen (sharebasename
);
303 if (strncasecmp (&sharebasename
[len
-4], ".exe", 4) == 0)
304 sharebasename
[len
- 4] = 0;
306 /* Convert to uppercase. */
307 for (ptr
= sharebasename
; *ptr
; ptr
++)
308 *ptr
= TOUPPER (*ptr
);
312 if (exefullfilename
== NULL
&& !share
)
314 exefilename
= "a_out.exe";
315 exefullfilename
= "a_out.exe";
316 addarg (xstrdup (" /exe=a_out.exe"));
320 /* Preprocess the number of args ARGC in ARGV. Look for
321 special flags, etc. that must be handled for the VMS linker. */
324 process_args (int argc
, char **argv
)
328 for (i
= 1; i
< argc
; i
++)
330 if (startswith (argv
[i
], "-L"))
332 search_dirs
= XRESIZEVEC(const char *, search_dirs
,
333 search_dirs_len
+ 1);
334 search_dirs
[search_dirs_len
++] = &argv
[i
][2];
337 /* -v turns on verbose option here and is passed on to gcc. */
338 else if (strcmp (argv
[i
], "-v") == 0)
340 else if (strcmp (argv
[i
], "--version") == 0)
342 fprintf (stdout
, "VMS Linker\n");
345 else if (strcmp (argv
[i
], "--help") == 0)
347 fprintf (stdout
, "VMS Linker\n");
350 else if (strcmp (argv
[i
], "-g0") == 0)
351 addarg ("/notraceback");
352 else if (startswith (argv
[i
], "-g"))
357 else if (strcmp (argv
[i
], "-static") == 0)
359 else if (strcmp (argv
[i
], "-map") == 0)
363 buff
= (char *) xstrdup (exefullfilename
);
364 ptr
= strrchr (buff
, '.');
368 strcat (buff
, ".map");
376 else if (strcmp (argv
[i
], "-save-temps") == 0)
378 else if (strcmp (argv
[i
], "--noinhibit-exec") == 0)
386 unsigned short len
, mbz
;
392 unsigned short buflen
, item_code
;
399 struct lst items
[1];
400 unsigned int terminator
;
405 struct lst items
[2];
406 unsigned int terminator
;
409 /* Checks if logical names are defined for setting system library path and
410 linker program to enable compatibility with earlier VMS versions. */
413 maybe_set_link_compat (void)
415 char lnm_buff
[LNM_C_NAMLENGTH
];
416 unsigned int lnm_buff_len
;
418 Descriptor tabledsc
, linkdsc
;
420 tabledsc
.adr
= "LNM$JOB";
421 tabledsc
.len
= strlen (tabledsc
.adr
);
424 linkdsc
.adr
= "GCC_LD_SYS$LIBRARY";
425 linkdsc
.len
= strlen (linkdsc
.adr
);
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;
436 &tabledsc
, /* tabnam */
437 &linkdsc
, /* lognam */
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 */
445 if ((status
& 1) == 1)
447 unsigned char acmode
= PSL_C_USER
; /* Don't retain after image exit */
448 const char *syslib
= "SYS$SYSROOT:[SYSLIB]"; /* Default SYS$LIBRARY */
450 /* Only visible to current and child processes */
451 tabledsc
.adr
= "LNM$PROCESS";
452 tabledsc
.len
= strlen (tabledsc
.adr
);
455 linkdsc
.adr
= "SYS$LIBRARY";
456 linkdsc
.len
= strlen (linkdsc
.adr
);
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;
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;
472 &tabledsc
, /* tabnam */
473 &linkdsc
, /* lognam */
474 &acmode
, /* acmode */
479 tabledsc
.adr
= "LNM$JOB";
480 tabledsc
.len
= strlen (tabledsc
.adr
);
483 linkdsc
.adr
= "GCC_LD_LINK";
484 linkdsc
.len
= strlen (linkdsc
.adr
);
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;
495 &tabledsc
, /* tabnam */
496 &linkdsc
, /* lognam */
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
504 if ((status
& 1) == 1)
506 unsigned char acmode
= PSL_C_USER
; /* Don't retain after image exit. */
508 /* Only visible to current and child processes. */
509 tabledsc
.adr
= "LNM$PROCESS";
510 tabledsc
.len
= strlen (tabledsc
.adr
);
513 linkdsc
.adr
= "LINK";
514 linkdsc
.len
= strlen (linkdsc
.adr
);
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;
525 &tabledsc
, /* tabnam */
526 &linkdsc
, /* lognam */
527 &acmode
, /* acmode */
533 maybe_set_link_compat (void)
538 /* Set environment defined executable attributes. */
541 set_exe (const char *arg
)
546 snprintf (allargs
, sizeof (allargs
),
547 "$@gnu:[bin]set_exe %s %s", exefullfilename
, arg
);
549 printf ("%s\n", allargs
);
551 res
= system (allargs
);
553 printf ("$!status = %d\n", res
);
557 fprintf (stderr
, "ld error: popen set_exe\n");
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. */
567 main (int argc
, char **argv
)
569 /* File specification for vms-dwarf2.o. */
570 char *vmsdwarf2spec
= 0;
572 /* File specification for vms-dwarf2eh.o. */
573 char *vmsdwarf2ehspec
= 0;
576 char cwdev
[128], *devptr
;
583 /* Some linker options can be set with logicals. */
584 if (getenv ("GNAT$LD_NOCALL_DEBUG"))
586 if (getenv ("GNAT$LD_MKTHREADS"))
588 if (getenv ("GNAT$LD_UPCALLS"))
590 if (getenv ("GNAT$LD_SHARED_LIBS"))
593 /* Get current dir. */
595 cwd
= getcwd (0, 1024, 1);
597 cwd
= getcwd (0, 1024);
601 /* Extract device part of the path. */
602 devptr
= strchr (cwd
, ':');
604 cwdevlen
= (devptr
- cwd
) + 1;
607 memcpy (cwdev
, cwd
, cwdevlen
);
608 cwdev
[cwdevlen
] = '\0';
610 maybe_set_link_compat ();
612 /* Linker command starts with the command name. */
615 /* Pass to find args that have to be append first. */
616 preprocess_args (argc
, argv
);
618 /* Pass to find the rest of the args. */
619 process_args (argc
, argv
);
622 addarg ("/noinform");
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
, '.');
631 strcat (optfilename
, ".opt_tmpfile");
632 optfile
= fopen (optfilename
, "w");
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
++)
638 int arg_len
= strlen (argv
[i
]);
640 if (arg_len
> 6 && strncasecmp (argv
[i
], "IDENT=", 6) == 0)
642 /* Comes from command line. If present will always appear before
643 --identification=... and will override. */
646 else if (arg_len
> 17
647 && strncasecmp (argv
[i
], "--identification=", 17) == 0)
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");
656 for (i
= 1; i
< argc
; i
++)
658 int arg_len
= strlen (argv
[i
]);
660 if (strcmp (argv
[i
], "-o") == 0)
662 /* Already handled. */
665 else if (arg_len
> 2 && startswith (argv
[i
], "-l"))
669 libname
= expand_lib (&argv
[i
][2]);
672 int len
= strlen (libname
);
675 if (len
> 4 && strcasecmp (&libname
[len
-4], ".exe") == 0)
680 if (libname
[0] == '[')
681 fprintf (optfile
, "%s%s%s\n", cwdev
, libname
, ext
);
683 fprintf (optfile
, "%s%s\n", libname
, ext
);
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")))
695 /* Already handled. */
697 else if (startswith (argv
[i
], "--opt="))
698 fprintf (optfile
, "%s\n", argv
[i
] + 6);
699 else if (arg_len
> 1 && argv
[i
][0] == '@')
701 /* Read response file (in fact a single line of filenames). */
708 if (stat (&argv
[i
][1], &statbuf
))
710 fprintf (stderr
, "Couldn't open linker response file: %s\n",
716 buff
= (char *) xmalloc (statbuf
.st_size
+ 1);
717 atfile
= fopen (&argv
[i
][1], "r");
718 fgets (buff
, statbuf
.st_size
+ 1, atfile
);
721 /* Remove trailing \n. */
723 if (buff
[len
- 1] == '\n')
729 /* Put the filenames to the opt file. */
733 ptr1
= strchr (ptr
, ' ');
737 /* Add device name if a path is present. */
738 ptr
= to_host_file_spec (ptr
);
740 fprintf (optfile
, "%s%s\n", cwdev
, ptr
);
742 fprintf (optfile
, "%s\n", ptr
);
748 else if ((argv
[i
][0] == '/') && (strchr (&argv
[i
][1], '/') == 0))
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. */
756 && strncasecmp (&argv
[i
][arg_len
-4], ".opt", 4) == 0)
758 /* Read option file. */
762 /* Disable __UNIX_FOPEN redefinition in case user supplied .opt
763 file is not stream oriented. */
765 optfile1
= (fopen
) (argv
[i
], "r");
770 goto cleanup_and_exit
;
773 while (fgets (buff
, sizeof (buff
), optfile1
))
774 fputs (buff
, optfile
);
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)
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");
787 else if (arg_len
> 17
788 && strncasecmp (argv
[i
], "--identification=", 17) == 0)
790 /* Already handled. */
794 /* Assume filename arg. */
796 const char *addswitch
= NULL
;
801 file
= to_host_file_spec (argv
[i
]);
802 arg_len
= strlen (file
);
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)
809 addswitch
= "/shareable";
813 /* Handle object libraries. */
814 else if (arg_len
> 2 && strcasecmp (&file
[arg_len
- 2], ".a") == 0)
816 else if (arg_len
> 4 && strcasecmp (&file
[arg_len
- 4], ".olb") == 0)
819 /* Absolutize file location. */
822 buff
= (char *) xmalloc (cwdevlen
+ arg_len
+ 1);
823 sprintf (buff
, "%s%s", cwdev
, file
);
825 else if (strchr (file
, ':'))
827 buff
= xstrdup (file
);
831 buff
= (char *) xmalloc (strlen (cwd
) + arg_len
+ 1);
832 sprintf (buff
, "%s%s", cwd
, file
);
835 buff_len
= strlen (buff
);
838 && strcasecmp (&buff
[buff_len
- 14], "vms-dwarf2eh.o") == 0)
841 vmsdwarf2ehspec
= xstrdup (buff
);
843 else if (buff_len
>= 13
844 && strcasecmp (&buff
[buff_len
- 12], "vms-dwarf2.o") == 0)
847 vmsdwarf2spec
= xstrdup (buff
);
851 /* Command line definition file. */
858 fprintf (optfile
, "%s%s\n",
859 buff
, addswitch
!= NULL
? addswitch
: "");
867 /* Sequentialize exception handling info. */
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");
875 if (debug
&& vmsdwarf2spec
)
877 /* Sequentialize the debug info. */
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");
888 if (debug
&& share
&& vmsdwarf2spec
)
890 /* Sequentialize the shared library debug info. */
892 fprintf (optfile
, "case_sensitive=yes\n");
893 fprintf (optfile
, "symbol_vector=(-\n");
895 "%s$DWARF2.DEBUG_ABBREV/$dwarf2.debug_abbrev=DATA,-\n",
898 "%s$DWARF2.DEBUG_ARANGES/$dwarf2.debug_aranges=DATA,-\n",
900 fprintf (optfile
, "%s$DWARF2.DEBUG_FRAME/$dwarf2.debug_frame=DATA,-\n",
902 fprintf (optfile
, "%s$DWARF2.DEBUG_INFO/$dwarf2.debug_info=DATA,-\n",
904 fprintf (optfile
, "%s$DWARF2.DEBUG_LINE/$dwarf2.debug_line=DATA,-\n",
906 fprintf (optfile
, "%s$DWARF2.DEBUG_LOC/$dwarf2.debug_loc=DATA,-\n",
909 "%s$DWARF2.DEBUG_MACINFO/$dwarf2.debug_macinfo=DATA,-\n",
912 "%s$DWARF2.DEBUG_PUBNAMES/$dwarf2.debug_pubnames=DATA,-\n",
914 fprintf (optfile
, "%s$DWARF2.DEBUG_STR/$dwarf2.debug_str=DATA,-\n",
916 fprintf (optfile
, "%s$DWARF2.DEBUG_ZZZZZZ/$dwarf2.debug_zzzzzz=DATA)\n",
918 fprintf (optfile
, "case_sensitive=NO\n");
921 fprintf (optfile
, "PSECT_ATTR=LIB$INITIALIZE,GBL\n");
924 /* Append opt file. */
926 addarg (optfilename
);
930 printf ("%s\n", link_cmd
);
932 status
= system (link_cmd
);
934 printf ("$!status = %d\n", status
);
936 if ((status
& 1) != 1)
939 goto cleanup_and_exit
;
942 if (debug
&& !share
&& ld_nocall_debug
)
944 status
= set_exe ("/flags=nocall_debug");
946 goto cleanup_and_exit
;
949 if (!share
&& ld_mkthreads
)
951 status
= set_exe ("/flags=mkthreads");
953 goto cleanup_and_exit
;
956 if (!share
&& ld_upcalls
)
958 status
= set_exe ("/flags=upcalls");
960 goto cleanup_and_exit
;
967 remove (optfilename
);
972 if (exefullfilename
&& inhibit_exec
== 1)
973 remove (exefullfilename
);