diff options
-rw-r--r-- | gcc/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/config.gcc | 29 | ||||
-rw-r--r-- | gcc/config/vms/t-vmsnative | 30 | ||||
-rw-r--r-- | gcc/config/vms/vms-ar.c | 351 | ||||
-rw-r--r-- | gcc/config/vms/vms-ld.c | 968 |
5 files changed, 1372 insertions, 15 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9d0c3d6..268b43a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2011-04-19 Tristan Gingold <gingold@adacore.com> + + * config.gcc (-*-*-*vms): Added. + (alpha64-dec-*vms*,alpha*-dec-*vms*, ia64-hp-*vms*): Common + definitions moved. + * config/vms/vms-ld.c: New file. + * config/vms/vms-ar.c: New file. + * config/vms/t-vmsnative: New file. + 2011-04-18 Xinliang David Li <davidxl@google.com> * final.c (dump_basic_block_info): Use ASM_COMMENT_START. diff --git a/gcc/config.gcc b/gcc/config.gcc index 41c46e6..7c318de 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -668,6 +668,16 @@ case ${target} in *-*-solaris2*) extra_options="${extra_options} sol2.opt" ;; +*-*-*vms*) + extra_options="${extra_options} vms/vms.opt" + xmake_file=vms/x-vms + tmake_file="vms/t-vms" + if test x$gnu_ld != xyes; then + # Build wrappers for native case. + extra_programs="ld\$(exeext) ar\$(exeext)" + tmake_file="$tmake_file vms/t-vmsnative" + fi + ;; *-*-vxworks*) tmake_file=t-vxworks xm_defines=POSIX @@ -752,20 +762,12 @@ alpha*-dec-osf5.1*) alpha64-dec-*vms*) tm_file="${tm_file} alpha/vms.h alpha/vms64.h" xm_file="alpha/xm-vms.h vms/xm-vms64.h" - tmake_file="alpha/t-alpha vms/t-vms alpha/t-vms alpha/t-ieee" - xmake_file=vms/x-vms - exeext=.exe - install_headers_dir=install-headers-cp - extra_options="${extra_options} vms/vms.opt" + tmake_file="${tmake_file} alpha/t-alpha vms/t-vms64 alpha/t-vms alpha/t-ieee" ;; alpha*-dec-*vms*) tm_file="${tm_file} alpha/vms.h" xm_file="alpha/xm-vms.h" - tmake_file="alpha/t-alpha vms/t-vms alpha/t-vms alpha/t-ieee" - xmake_file=vms/x-vms - exeext=.exe - install_headers_dir=install-headers-cp - extra_options="${extra_options} vms/vms.opt" + tmake_file="${tmake_file} alpha/t-alpha alpha/t-vms alpha/t-ieee" ;; arm-wrs-vxworks) tm_file="elfos.h arm/elf.h arm/aout.h ${tm_file} vx-common.h vxworks.h arm/vxworks.h" @@ -1582,16 +1584,13 @@ ia64*-*-hpux*) ia64-hp-*vms*) tm_file="${tm_file} elfos.h ia64/sysv4.h ia64/elf.h ia64/vms.h ia64/vms64.h" xm_file="vms/xm-vms.h vms/xm-vms64.h" - tmake_file="vms/t-vms ia64/t-ia64 ia64/t-vms" - xmake_file=vms/x-vms + tmake_file="${tmake_file} vms/t-vms64 ia64/t-ia64 ia64/t-vms" target_cpu_default="0" if test x$gas = xyes then target_cpu_default="${target_cpu_default}|MASK_GNU_AS" fi - exeext=.exe - install_headers_dir=install-headers-cp - extra_options="${extra_options} vms/vms.opt ia64/vms.opt" + extra_options="${extra_options} ia64/vms.opt" ;; iq2000*-*-elf*) tm_file="elfos.h newlib-stdint.h iq2000/iq2000.h" diff --git a/gcc/config/vms/t-vmsnative b/gcc/config/vms/t-vmsnative new file mode 100644 index 0000000..a7fc031 --- /dev/null +++ b/gcc/config/vms/t-vmsnative @@ -0,0 +1,30 @@ +# Copyright (C) 2010 +# Free Software Foundation, Inc. +# +# This file is part of GCC. +# +# GCC is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GCC is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +vms-ld.o: $(srcdir)/config/vms/vms-ld.c + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) + +ld$(exeext): vms-ld.o $(LIBIBERTY) + $(CC) -o $@ vms-ld.o $(LIBIBERTY) + +vms-ar.o: $(srcdir)/config/vms/vms-ar.c + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) + +ar$(exeext): vms-ar.o $(LIBIBERTY) + $(CC) -o $@ vms-ar.o $(LIBIBERTY) diff --git a/gcc/config/vms/vms-ar.c b/gcc/config/vms/vms-ar.c new file mode 100644 index 0000000..d01a052 --- /dev/null +++ b/gcc/config/vms/vms-ar.c @@ -0,0 +1,351 @@ +/* VMS archive wrapper. + Copyright (C) 2011 Free Software Foundation, Inc. + Contributed by AdaCore. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "libiberty.h" + +#define FATAL_EXIT_CODE (44 | 0x10000000) + +/* Librarian arguments. */ +static int lib_arg_max = 0; +static const char **lib_args; +static int lib_arg_index = -1; + +/* Set for r/c/x/v command. */ +static int replace_mode = 0; +static int create_mode = 0; +static int extract_mode = 0; +static int verbose_mode = 0; + +static char modecmd[32]; +static char libname[256]; + +#define TEMP_FILE "arXXXXXX" +#define TEMP_FILE_LEN (sizeof(TEMP_FILE) - 1) +#define SUFFIX ".com" +#define SUFFIX_LEN (sizeof(SUFFIX) - 1) + +static char *to_host_file_spec (char *filespec); +static int is_regular_file (char *name); + +#ifdef VMS +static char new_host_filespec [255]; +static char filename_buff [256]; + +static int +translate_unix (char *name, int type) +{ + strcpy (filename_buff, name); + return 0; +} +#endif + +static char * +to_host_file_spec (char *filespec) +{ +#ifdef VMS + if (strchr (filespec, ']') || strchr (filespec, ':')) + return filespec; + else + { + strcpy (filename_buff, filespec); + decc$to_vms (filespec, translate_unix, 1, 1); + strcpy (new_host_filespec, filename_buff); + return new_host_filespec; + } +#else + return filespec; +#endif +} + +/* Check to see if the file named in NAME is a regular file, i.e. not a + directory. */ + +static int +is_regular_file (char *name) +{ + int ret; + struct stat statbuf; + + ret = stat (name, &statbuf); + return !ret && S_ISREG (statbuf.st_mode); +} + +/* Add the argument contained in STR to the list of arguments to pass to the + archiver. */ + +static void +addarg (const char *str) +{ + if (++lib_arg_index >= lib_arg_max) + { + lib_arg_max += 1000; + lib_args = XRESIZEVEC (const char *, lib_args, lib_arg_max); + } + + lib_args[lib_arg_index] = str; +} + +static void +usage (void) +{ + printf ("usage: ar -r [-cv] archive file...\n"); + printf (" ar -c [-rv] archive file...\n"); + printf (" ar -x [-v] archive [module...]\n"); +} + +int +main (int argc, char *argv[]) +{ + int i, nexti, iarg; + FILE *comfile; + int comfd; + int outlen, maxoutlen = 4000; + char *cwd; + char temp_filename[] = TEMP_FILE SUFFIX; + char command[256]; + int status; + + cwd = getcwd (0, 1024); + + if (argc < 2) + { + fprintf (stderr, "ar: no command or archive\n"); + exit (FATAL_EXIT_CODE); + } + + if (argv[1][0] != '-') + { + int arglen = strlen (argv[1]); + + /* Compatibility mode. */ + for (i = 0; i < arglen; i++) + { + if (argv[1][i] == 'r') + { + replace_mode = 1; + } + else if (argv[1][i] == 'c') + { + create_mode = 1; + } + else if (argv[1][i] == 'x') + { + extract_mode = 1; + } + else if (argv[1][i] == 'v') + { + verbose_mode = 1; + } + else + { + fprintf (stderr, "ar: unknown command '%c'\n", argv[1][i]); + exit (FATAL_EXIT_CODE); + } + } + nexti = 2; + } + else + { + /* Option mode. */ + nexti = 1; + for (i = 1; i < argc; i++) + { + if (argv[i][0] != '-') + { + nexti = i; + break; + } + else if (strcmp (argv[i], "-r") == 0) + { + replace_mode = 1; + } + else if (strcmp (argv[i], "-c") == 0) + { + create_mode = 1; + } + else if (strcmp (argv[i], "-x") == 0) + { + extract_mode = 1; + } + else if (strcmp (argv[i], "-v") == 0) + { + verbose_mode = 1; + } + else if (strcmp (argv[i], "--help") == 0) + { + usage (); + exit (EXIT_SUCCESS); + } + else + { + fprintf (stderr, "ar: unknown option %s\n", argv[i]); + exit (FATAL_EXIT_CODE); + } + } + } + + if (extract_mode) + { + do + { + char *lname = argv[nexti]; + int lnamelen; + + /* Next argument is the archive name. */ + if (is_regular_file (lname)) + { + addarg (xstrdup (to_host_file_spec (lname))); + break; + } + + /* If not found, try with .olb instead of .a. */ + lnamelen = strlen (lname); + + if (lnamelen > 2 + && strcmp (&lname [lnamelen - 2], ".a") == 0) + { + char *nlibname; + + nlibname = (char *)alloca (lnamelen + 3); + strcpy (nlibname, lname); + strcpy (&nlibname [lnamelen - 2], ".olb"); + if (is_regular_file (nlibname)) + { + addarg (xstrdup (to_host_file_spec (nlibname))); + break; + } + } + + fprintf (stderr, "ar: file '%s' doesn't exist\n", lname); + exit (FATAL_EXIT_CODE); + } while (0); + } + else + strcpy (libname, to_host_file_spec (argv[nexti])); + + nexti++; + + /* Build command mode. */ + if (replace_mode) + { + strcat (modecmd, "/replace"); + + if (!is_regular_file (libname) || !replace_mode) + { + /* Really create if the archive doesn't exist. */ + strcat (modecmd, "/create"); + } + } + else if (extract_mode) + { + if (nexti == argc) + { + /* Extract all. */ + strcat (modecmd, "/extract=(*"); + } + else + strcat (modecmd, "/extract=("); + } + + /* Add files. */ + for (i = nexti; i < argc; i++) + { + if (extract_mode) + { + /* Convert to module name (remove extension) and quote it. */ + char *module = argv[i]; + int module_len = strlen (module); + char *newarg = (char *)xmalloc (module_len + 3); + int l; + + newarg[0] = '"'; + memcpy (newarg + 1, module, module_len); + + l = 1 + module_len; + if (module_len > 4 + && strcmp (&module[module_len - 4], ".obj") == 0) + l -= 4; + + newarg[l] = '"'; + newarg[l + 1] = 0; + + addarg (newarg); + } + else + { + /* Add the filename. */ + addarg (xstrdup (to_host_file_spec (argv[i]))); + } + } + + if (extract_mode) + addarg (")"); + + /* Create the command file name. */ + strcpy (temp_filename, TEMP_FILE SUFFIX); + comfd = mkstemps (temp_filename, SUFFIX_LEN); + comfile = fdopen (comfd, "w"); + + /* Write the command file. + We need to split to command into severals ones if it is too long. */ + outlen = 0; + for (iarg = 0; iarg <= lib_arg_index; iarg++) + { + if (outlen == 0) + { + fprintf (comfile, "$ library %s %s -\n", modecmd, libname); + if (create_mode && iarg == 0) + strcpy (modecmd, "/replace"); + } + + fprintf (comfile, "%s", lib_args [iarg]); + outlen += strlen (lib_args [iarg]) + 2; + + if (outlen > maxoutlen || iarg == lib_arg_index) + { + /* Will write a new command. */ + fprintf (comfile, "\n"); + outlen = 0; + } + else + { + /* Continuation line. */ + fprintf (comfile, ",-\n"); + } + } + + fclose (comfile); + + sprintf (command, "@%s", temp_filename); + + status = system (command); + + remove (temp_filename); + + exit (status); +} diff --git a/gcc/config/vms/vms-ld.c b/gcc/config/vms/vms-ld.c new file mode 100644 index 0000000..18776fa --- /dev/null +++ b/gcc/config/vms/vms-ld.c @@ -0,0 +1,968 @@ +/* VMS linker wrapper. + Copyright (C) 2011 Free Software Foundation, Inc. + Contributed by AdaCore + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +/* This program is a wrapper around the VMS linker. + It translates Unix style command line options into corresponding + VMS style qualifiers and then spawns the VMS linker. + + It is possible to build this program on UNIX but only for the purpose of + checking for errors. */ + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <stdio.h> + +#include "libiberty.h" +#include <safe-ctype.h> +#include <sys/stat.h> + +/* Macro for logicals. */ +#define LNM__STRING 2 +#define LNM_C_NAMLENGTH 255 +#define PSL_C_SUPER 2 +#define PSL_C_USER 3 + +/* Local variable declarations. */ +static int ld_nocall_debug = 0; +static int ld_mkthreads = 0; +static int ld_upcalls = 0; + +/* verbose = 1 if -v passed. */ +static int verbose = 0; + +/* save_temps = 1 if -save-temps passed. */ +static int save_temps = 0; + +/* By default don't generate executable file if there are errors + in the link. Override with --noinhibit-exec. */ +static int inhibit_exec = 1; + +/* debug = 1 if -g passed. */ +static int debug = 0; + +/* By default prefer to link with static libraries. */ +static int staticp = 1; + +/* By default generate an executable, not a shareable image library. + Override with -shared. */ +static int share = 0; + +/* Linker command line. */ +static int link_cmd_maxlen = 0; +static char *link_cmd = 0; +static int link_cmd_len = 0; + +/* Keep track of filenames. */ +static char *sharebasename; +static const char *exefullfilename; +static const char *exefilename; + +/* Search dir list passed on command line (with -L). */ +static const char **search_dirs; +static int search_dirs_len; + +/* Local function declarations. */ +static void addarg (const char *); +static int is_regular_file (char *); +static char *to_host_file_spec (char *); +static char *locate_lib (char *); +static const char *expand_lib (char *); +static void preprocess_args (int, char **); +static void process_args (int, char **); +static void maybe_set_link_compat (void); +static int set_exe (const char *); +#ifdef VMS +static int translate_unix (char *, int); +#endif + + +/* Append STR to the command line to invoke the linker. + Expand the line as necessary to accommodate. */ + +static void +addarg (const char *str) +{ + int l = strlen (str); + + /* Extend the line. */ + if (link_cmd_len + l >= link_cmd_maxlen) + { + link_cmd_maxlen = link_cmd_len + l + 1024; + link_cmd = XRESIZEVEC (char, link_cmd, link_cmd_maxlen); + } + + memcpy (link_cmd + link_cmd_len, str, l); + link_cmd_len += l; +} + +/* Check to see if NAME is a regular file, i.e. not a directory. */ + +static int +is_regular_file (char *name) +{ + int ret; + struct stat statbuf; + + ret = stat (name, &statbuf); + return !ret && S_ISREG (statbuf.st_mode); +} + +#ifdef VMS +static char new_host_filespec [255]; +static char filename_buff [256]; + +/* Action routine called by decc$to_vms. NAME is a file name or + directory name. TYPE is unused. */ + +static int +translate_unix (char *name, int type ATTRIBUTE_UNUSED) +{ + strcpy (filename_buff, name); + return 0; +} +#endif + +/* Translate a Unix syntax file specification FILESPEC into VMS syntax. + If indicators of VMS syntax found, return input string. + Return a pointer to a static buffer. */ + +static char * +to_host_file_spec (char *filespec) +{ +#ifdef VMS + if (strchr (filespec, ']') || strchr (filespec, ':')) + { + /* Looks like a VMS path. */ + return filespec; + } + else + { + + strcpy (filename_buff, filespec); + decc$to_vms (filespec, translate_unix, 1, 1); + strcpy (new_host_filespec, filename_buff); + return new_host_filespec; + } +#else + return filespec; +#endif +} + +/* Locate library LIB_NAME on the library path. */ + +static char * +locate_lib (char *lib_name) +{ + int lib_len = strlen (lib_name); + const char *exts[3]; + int i; + + if (staticp) + { + /* For static links, look for shareable image libraries last. */ + exts[0] = ".a"; + exts[1] = ".olb"; + exts[2] = ".exe"; + } + else + { + exts[0] = ".exe"; + exts[1] = ".a"; + exts[2] = ".olb"; + } + + for (i = 0; i < search_dirs_len; i++) + { + char *buf; + int l; + int j; + + l = strlen (search_dirs[i]); + buf = (char *)alloca (l + 4 + lib_len + 4 + 1); + /* Put PATH/libLIB. */ + memcpy (buf, search_dirs[i], l); + memcpy (buf + l, "/lib", 4); + l += 4; + memcpy (buf + l, lib_name, lib_len); + l += lib_len; + + /* Look for files with the extensions. */ + for (j = 0; j < 3; j++) + { + strcpy (buf + l, exts[j]); + if (is_regular_file (buf)) + return xstrdup (to_host_file_spec (buf)); + } + } + + return NULL; +} + +/* Given a library name NAME, i.e. foo, Look for libfoo.lib and then + libfoo.a in the set of directories we are allowed to search in. + May return NULL if the library can be discarded. */ + +static const char * +expand_lib (char *name) +{ + char *lib_path; + + /* Discard libc. */ + if (strcmp (name, "c") == 0) + return NULL; + + /* Discard libm. No separate library for math functions. */ + if (strcmp (name, "m") == 0) + return NULL; + + /* Search on path. */ + lib_path = locate_lib (name); + if (lib_path) + return lib_path; + + fprintf (stderr, + "Couldn't locate library: lib%s.exe, lib%s.a or lib%s.olb\n", + name, name, name); + + exit (EXIT_FAILURE); +} + +/* Preprocess the number of args P_ARGC in ARGV. + Look for special flags, etc. that must be handled first. */ + +static void +preprocess_args (int argc, char **argv) +{ + int i; + + /* Scan for -shared. */ + for (i = 1; i < argc; i++) + if (strcmp (argv[i], "-shared") == 0) + { + share = 1; + break; + } + + for (i = 1; i < argc; i++) + if (strcmp (argv[i], "-o") == 0) + { + int len; + + i++; + exefilename = lbasename (argv[i]); + exefullfilename = xstrdup (to_host_file_spec (argv[i])); + + if (share) + addarg(" /share="); + else + addarg (" /exe="); + addarg (exefullfilename); + + if (share) + { + char *ptr; + + /* Extract the basename. */ + ptr = strchr (argv[i], ']'); + if (ptr == NULL) + ptr = strchr (argv[i], ':'); + if (ptr == NULL) + ptr = strchr (argv[i], '/'); + if (ptr == NULL) + sharebasename = xstrdup (argv[i]); + else + sharebasename = xstrdup (ptr + 1); + + len = strlen (sharebasename); + if (strncasecmp (&sharebasename[len-4], ".exe", 4) == 0) + sharebasename[len - 4] = 0; + + /* Convert to uppercase. */ + for (ptr = sharebasename; *ptr; ptr++) + *ptr = TOUPPER (*ptr); + } + } + + if (exefullfilename == NULL && !share) + { + exefilename = "a_out.exe"; + exefullfilename = "a_out.exe"; + addarg (xstrdup (" /exe=a_out.exe")); + } +} + +/* Preprocess the number of args ARGC in ARGV. Look for + special flags, etc. that must be handled for the VMS linker. */ + +static void +process_args (int argc, char **argv) +{ + int i; + + for (i = 1; i < argc; i++) + { + if (strncmp (argv[i], "-L", 2) == 0) + { + search_dirs = XRESIZEVEC(const char *, search_dirs, + search_dirs_len + 1); + search_dirs[search_dirs_len++] = &argv[i][2]; + } + + /* -v turns on verbose option here and is passed on to gcc. */ + else if (strcmp (argv[i], "-v") == 0) + verbose++; + else if (strcmp (argv[i], "--version") == 0) + { + fprintf (stdout, "VMS Linker\n"); + exit (EXIT_SUCCESS); + } + else if (strcmp (argv[i], "--help") == 0) + { + fprintf (stdout, "VMS Linker\n"); + exit (EXIT_SUCCESS); + } + else if (strcmp (argv[i], "-g0") == 0) + addarg ("/notraceback"); + else if (strncmp (argv[i], "-g", 2) == 0) + { + addarg ("/debug"); + debug = 1; + } + else if (strcmp (argv[i], "-static") == 0) + staticp = 1; + else if (strcmp (argv[i], "-map") == 0) + { + char *buff, *ptr; + + buff = (char *) xstrdup (exefullfilename); + ptr = strrchr (buff, '.'); + if (ptr) + *ptr = 0; + + strcat (buff, ".map"); + addarg ("/map="); + addarg (buff); + addarg (".map"); + addarg ("/full"); + + free (buff); + } + else if (strcmp (argv[i], "-save-temps") == 0) + save_temps = 1; + else if (strcmp (argv[i], "--noinhibit-exec") == 0) + inhibit_exec = 0; + } +} + +#ifdef VMS +typedef struct dsc +{ + unsigned short len, mbz; + const char *adr; +} Descriptor; + +struct lst +{ + unsigned short buflen, item_code; + const void *bufaddr; + void *retlenaddr; +}; + +static struct +{ + struct lst items [1]; + unsigned int terminator; +} item_lst1; + +static struct +{ + struct lst items [2]; + unsigned int terminator; +} item_lst2; + +/* Checks if logical names are defined for setting system library path and + linker program to enable compatibility with earlier VMS versions. */ + +static void +maybe_set_link_compat (void) +{ + char lnm_buff [LNM_C_NAMLENGTH]; + unsigned int lnm_buff_len; + int status; + Descriptor tabledsc, linkdsc; + + tabledsc.adr = "LNM$JOB"; + tabledsc.len = strlen (tabledsc.adr); + tabledsc.mbz = 0; + + linkdsc.adr = "GCC_LD_SYS$LIBRARY"; + linkdsc.len = strlen (linkdsc.adr); + linkdsc.mbz = 0; + + item_lst1.items[0].buflen = LNM_C_NAMLENGTH; + item_lst1.items[0].item_code = LNM__STRING; + item_lst1.items[0].bufaddr = lnm_buff; + item_lst1.items[0].retlenaddr = &lnm_buff_len; + item_lst1.terminator = 0; + + status = SYS$TRNLNM + (0, /* attr */ + &tabledsc, /* tabnam */ + &linkdsc, /* lognam */ + 0, /* acmode */ + &item_lst1); + + /* If GCC_LD_SYS$LIBRARY is defined, redefine SYS$LIBRARY to search + the equivalence name first for system libraries, then the default + system library directory */ + + if ((status & 1) == 1) + { + unsigned char acmode = PSL_C_USER; /* Don't retain after image exit */ + const char *syslib = "SYS$SYSROOT:[SYSLIB]"; /* Default SYS$LIBRARY */ + + /* Only visible to current and child processes */ + tabledsc.adr = "LNM$PROCESS"; + tabledsc.len = strlen (tabledsc.adr); + tabledsc.mbz = 0; + + linkdsc.adr = "SYS$LIBRARY"; + linkdsc.len = strlen (linkdsc.adr); + linkdsc.mbz = 0; + + item_lst2.items[0].buflen = lnm_buff_len; + item_lst2.items[0].item_code = LNM__STRING; + item_lst2.items[0].bufaddr = lnm_buff; + item_lst2.items[0].retlenaddr = 0; + + item_lst2.items[1].buflen = strlen (syslib); + item_lst2.items[1].item_code = LNM__STRING; + item_lst2.items[1].bufaddr = syslib; + item_lst2.items[1].retlenaddr = 0; + item_lst2.terminator = 0; + + status = SYS$CRELNM + (0, /* attr */ + &tabledsc, /* tabnam */ + &linkdsc, /* lognam */ + &acmode, /* acmode */ + &item_lst2); + + } + + tabledsc.adr = "LNM$JOB"; + tabledsc.len = strlen (tabledsc.adr); + tabledsc.mbz = 0; + + linkdsc.adr = "GCC_LD_LINK"; + linkdsc.len = strlen (linkdsc.adr); + linkdsc.mbz = 0; + + item_lst1.items[0].buflen = LNM_C_NAMLENGTH; + item_lst1.items[0].item_code = LNM__STRING; + item_lst1.items[0].bufaddr = lnm_buff; + item_lst1.items[0].retlenaddr = &lnm_buff_len; + item_lst1.terminator = 0; + + status = SYS$TRNLNM + (0, /* attr */ + &tabledsc, /* tabnam */ + &linkdsc, /* lognam */ + 0, /* acmode */ + &item_lst1); + + /* If GCC_LD_LINK is defined, redefine LINK to use the equivalence name + (sometimes the LINK program version is used by VMS to determine + compatibility). */ + + if ((status & 1) == 1) + { + unsigned char acmode = PSL_C_USER; /* Don't retain after image exit. */ + + /* Only visible to current and child processes. */ + tabledsc.adr = "LNM$PROCESS"; + tabledsc.len = strlen (tabledsc.adr); + tabledsc.mbz = 0; + + linkdsc.adr = "LINK"; + linkdsc.len = strlen (linkdsc.adr); + linkdsc.mbz = 0; + + item_lst1.items[0].buflen = lnm_buff_len; + item_lst1.items[0].item_code = LNM__STRING; + item_lst1.items[0].bufaddr = lnm_buff; + item_lst1.items[0].retlenaddr = 0; + item_lst1.terminator = 0; + + status = SYS$CRELNM + (0, /* attr */ + &tabledsc, /* tabnam */ + &linkdsc, /* lognam */ + &acmode, /* acmode */ + &item_lst1); + } +} +#else +static void +maybe_set_link_compat (void) +{ +} +#endif + +/* Set environment defined executable attributes. */ + +static int +set_exe (const char *arg) +{ + char allargs [1024]; + int res; + + snprintf (allargs, sizeof (allargs), + "$@gnu:[bin]set_exe %s %s", exefullfilename, arg); + if (verbose) + printf ("%s\n", allargs); + + res = system (allargs); + if (verbose > 1) + printf ("$!status = %d\n", res); + + if ((res & 1) != 1) + { + fprintf (stderr, "ld error: popen set_exe\n"); + return 1; + } + return 0; +} + +/* The main program. Spawn the VMS linker after fixing up the Unix-like flags + and args to be what the VMS linker wants. */ + +int +main (int argc, char **argv) +{ + /* File specification for vms-dwarf2.o. */ + char *vmsdwarf2spec = 0; + + /* File specification for vms-dwarf2eh.o. */ + char *vmsdwarf2ehspec = 0; + + int i; + char cwdev[128], *devptr; + int cwdevlen; + FILE *optfile; + char *cwd, *ptr; + char *optfilename; + int status = 0; + + /* Some linker options can be set with logicals. */ + if (getenv ("GNAT$LD_NOCALL_DEBUG")) + ld_nocall_debug = 1; + if (getenv ("GNAT$LD_MKTHREADS")) + ld_mkthreads = 1; + if (getenv ("GNAT$LD_UPCALLS")) + ld_upcalls = 1; + if (getenv ("GNAT$LD_SHARED_LIBS")) + staticp = 0; + + /* Get current dir. */ +#ifdef VMS + cwd = getcwd (0, 1024, 1); +#else + cwd = getcwd (0, 1024); + strcat (cwd, "/"); +#endif + + /* Extract device part of the path. */ + devptr = strchr (cwd, ':'); + if (devptr) + cwdevlen = (devptr - cwd) + 1; + else + cwdevlen = 0; + memcpy (cwdev, cwd, cwdevlen); + cwdev [cwdevlen] = '\0'; + + maybe_set_link_compat (); + + /* Linker command starts with the command name. */ + addarg ("$ link"); + + /* Pass to find args that have to be append first. */ + preprocess_args (argc , argv); + + /* Pass to find the rest of the args. */ + process_args (argc , argv); + + if (!verbose) + addarg ("/noinform"); + + /* Create a temp file to hold args, otherwise we can easily exceed the VMS + command line length limits. */ + optfilename = (char *) xmalloc (strlen (exefilename) + 13); + strcpy (optfilename, exefilename); + ptr = strrchr (optfilename, '.'); + if (ptr) + *ptr = 0; + strcat (optfilename, ".opt_tmpfile"); + optfile = fopen (optfilename, "w"); + + /* Write out the IDENTIFICATION argument first so that it can be overridden + by an options file. */ + for (i = 1; i < argc; i++) + { + int arg_len = strlen (argv[i]); + + if (arg_len > 6 && strncasecmp (argv[i], "IDENT=", 6) == 0) + { + /* Comes from command line. If present will always appear before + --identification=... and will override. */ + break; + } + else if (arg_len > 17 + && strncasecmp (argv[i], "--identification=", 17) == 0) + { + /* Comes from pragma Ident (). */ + fprintf (optfile, "case_sensitive=yes\n"); + fprintf (optfile, "IDENTIFICATION=\"%15.15s\"\n", &argv[i][17]); + fprintf (optfile, "case_sensitive=NO\n"); + } + } + + for (i = 1; i < argc; i++) + { + int arg_len = strlen (argv[i]); + + if (strcmp (argv[i], "-o") == 0) + { + /* Already handled. */ + i++; + } + else if (arg_len > 2 && strncmp (argv[i], "-l", 2) == 0) + { + const char *libname; + + libname = expand_lib (&argv[i][2]); + if (libname != NULL) + { + int len = strlen (libname); + const char *ext; + + if (len > 4 && strcasecmp (&libname [len-4], ".exe") == 0) + ext = "/shareable"; + else + ext = "/library"; + + if (libname[0] == '[') + fprintf (optfile, "%s%s%s\n", cwdev, libname, ext); + else + fprintf (optfile, "%s%s\n", libname, ext); + } + } + else if (strcmp (argv[i], "-v" ) == 0 + || strncmp (argv[i], "-g", 2 ) == 0 + || strcmp (argv[i], "-static" ) == 0 + || strcmp (argv[i], "-map" ) == 0 + || strcmp (argv[i], "-save-temps") == 0 + || strcmp (argv[i], "--noinhibit-exec") == 0 + || (arg_len > 2 && strncmp (argv[i], "-L", 2) == 0) + || (arg_len >= 6 && strncmp (argv[i], "-share", 6) == 0)) + { + /* Already handled. */ + } + else if (strncmp (argv[i], "--opt=", 6) == 0) + fprintf (optfile, "%s\n", argv[i] + 6); + else if (arg_len > 1 && argv[i][0] == '@') + { + /* Read response file (in fact a single line of filenames). */ + FILE *atfile; + char *ptr, *ptr1; + struct stat statbuf; + char *buff; + int len; + + if (stat (&argv[i][1], &statbuf)) + { + fprintf (stderr, "Couldn't open linker response file: %s\n", + &argv[i][1]); + exit (EXIT_FAILURE); + } + + /* Read the line. */ + buff = (char *) xmalloc (statbuf.st_size + 1); + atfile = fopen (&argv[i][1], "r"); + fgets (buff, statbuf.st_size + 1, atfile); + fclose (atfile); + + /* Remove trailing \n. */ + len = strlen (buff); + if (buff [len - 1] == '\n') + { + buff [len - 1] = 0; + len--; + } + + /* Put the filenames to the opt file. */ + ptr = buff; + do + { + ptr1 = strchr (ptr, ' '); + if (ptr1) + *ptr1 = 0; + + /* Add device name if a path is present. */ + ptr = to_host_file_spec (ptr); + if (ptr[0] == '[') + fprintf (optfile, "%s%s\n", cwdev, ptr); + else + fprintf (optfile, "%s\n", ptr); + + ptr = ptr1 + 1; + } + while (ptr1); + } + else if ((argv[i][0] == '/') && (strchr (&argv[i][1], '/') == 0)) + { + /* Unix style file specs and VMS style switches look alike, + so assume an arg consisting of one and only one slash, + and that being first, is really a switch. */ + addarg (argv[i]); + } + else if (arg_len > 4 + && strncasecmp (&argv[i][arg_len-4], ".opt", 4) == 0) + { + /* Read option file. */ + FILE *optfile1; + char buff[256]; + + /* Disable __UNIX_FOPEN redefinition in case user supplied .opt + file is not stream oriented. */ + + optfile1 = (fopen) (argv[i], "r"); + if (optfile1 == 0) + { + perror (argv[i]); + status = 1; + goto cleanup_and_exit; + } + + while (fgets (buff, sizeof (buff), optfile1)) + fputs (buff, optfile); + + fclose (optfile1); + } + else if (arg_len > 7 && strncasecmp (argv[i], "GSMATCH", 7) == 0) + fprintf (optfile, "%s\n", argv[i]); + else if (arg_len > 6 && strncasecmp (argv[i], "IDENT=", 6) == 0) + { + /* Comes from command line and will override pragma. */ + fprintf (optfile, "case_sensitive=yes\n"); + fprintf (optfile, "IDENT=\"%15.15s\"\n", &argv[i][6]); + fprintf (optfile, "case_sensitive=NO\n"); + } + else if (arg_len > 17 + && strncasecmp (argv[i], "--identification=", 17) == 0) + { + /* Already handled. */ + } + else + { + /* Assume filename arg. */ + const char *file; + const char *addswitch = NULL; + char *buff; + int buff_len; + int is_cld = 0; + + file = to_host_file_spec (argv[i]); + arg_len = strlen (file); + + /* Handle shareable image libraries. */ + if (arg_len > 4 && strcasecmp (&file[arg_len - 4], ".exe") == 0) + addswitch = "/shareable"; + else if (arg_len > 4 && strcasecmp (&file[arg_len - 4], ".cld") == 0) + { + addswitch = "/shareable"; + is_cld = 1; + } + + /* Handle object libraries. */ + else if (arg_len > 2 && strcasecmp (&file[arg_len - 2], ".a") == 0) + addswitch = "/lib"; + else if (arg_len > 4 && strcasecmp (&file[arg_len - 4], ".olb") == 0) + addswitch = "/lib"; + + /* Absolutize file location. */ + if (file[0] == '[') + { + buff = (char *) xmalloc (cwdevlen + arg_len + 1); + sprintf (buff, "%s%s", cwdev, file); + } + else if (strchr (file, ':')) + { + buff = xstrdup (file); + } + else + { + buff = (char *) xmalloc (strlen (cwd) + arg_len + 1); + sprintf (buff, "%s%s", cwd, file); + } + + buff_len = strlen (buff); + + if (buff_len >= 15 + && strcasecmp (&buff[buff_len - 14], "vms-dwarf2eh.o") == 0) + { + /* Remind of it. */ + vmsdwarf2ehspec = xstrdup (buff); + } + else if (buff_len >= 13 + && strcasecmp (&buff[buff_len - 12], "vms-dwarf2.o") == 0) + { + /* Remind of it. */ + vmsdwarf2spec = xstrdup (buff); + } + else if (is_cld) + { + /* Command line definition file. */ + addarg (buff); + addarg (addswitch); + addarg (","); + } + else + { + fprintf (optfile, "%s%s\n", + buff, addswitch != NULL ? addswitch : ""); + } + free (buff); + } + } + + if (vmsdwarf2ehspec) + { + /* Sequentialize exception handling info. */ + + fprintf (optfile, "case_sensitive=yes\n"); + fprintf (optfile, "cluster=DWARF2eh,,,%s\n", vmsdwarf2ehspec); + fprintf (optfile, "collect=DWARF2eh,eh_frame\n"); + fprintf (optfile, "case_sensitive=NO\n"); + } + + if (debug && vmsdwarf2spec) + { + /* Sequentialize the debug info. */ + + fprintf (optfile, "case_sensitive=yes\n"); + fprintf (optfile, "cluster=DWARF2debug,,,%s\n", vmsdwarf2spec); + fprintf (optfile, "collect=DWARF2debug,debug_abbrev,debug_aranges,-\n"); + fprintf (optfile, " debug_frame,debug_info,debug_line,debug_loc,-\n"); + fprintf (optfile, " debug_macinfo,debug_pubnames,debug_str,-\n"); + fprintf (optfile, " debug_zzzzzz\n"); + fprintf (optfile, "case_sensitive=NO\n"); + } + + if (debug && share && vmsdwarf2spec) + { + /* Sequentialize the shared library debug info. */ + + fprintf (optfile, "case_sensitive=yes\n"); + fprintf (optfile, "symbol_vector=(-\n"); + fprintf (optfile, + "%s$DWARF2.DEBUG_ABBREV/$dwarf2.debug_abbrev=DATA,-\n", + sharebasename); + fprintf (optfile, + "%s$DWARF2.DEBUG_ARANGES/$dwarf2.debug_aranges=DATA,-\n", + sharebasename); + fprintf (optfile, "%s$DWARF2.DEBUG_FRAME/$dwarf2.debug_frame=DATA,-\n", + sharebasename); + fprintf (optfile, "%s$DWARF2.DEBUG_INFO/$dwarf2.debug_info=DATA,-\n", + sharebasename); + fprintf (optfile, "%s$DWARF2.DEBUG_LINE/$dwarf2.debug_line=DATA,-\n", + sharebasename); + fprintf (optfile, "%s$DWARF2.DEBUG_LOC/$dwarf2.debug_loc=DATA,-\n", + sharebasename); + fprintf (optfile, + "%s$DWARF2.DEBUG_MACINFO/$dwarf2.debug_macinfo=DATA,-\n", + sharebasename); + fprintf (optfile, + "%s$DWARF2.DEBUG_PUBNAMES/$dwarf2.debug_pubnames=DATA,-\n", + sharebasename); + fprintf (optfile, "%s$DWARF2.DEBUG_STR/$dwarf2.debug_str=DATA,-\n", + sharebasename); + fprintf (optfile, "%s$DWARF2.DEBUG_ZZZZZZ/$dwarf2.debug_zzzzzz=DATA)\n", + sharebasename); + fprintf (optfile, "case_sensitive=NO\n"); + } + + fprintf (optfile, "PSECT_ATTR=LIB$INITIALIZE,GBL\n"); + fclose (optfile); + + /* Append opt file. */ + addarg (" "); + addarg (optfilename); + addarg ("/opt"); + + if (verbose) + printf ("%s\n", link_cmd); + + status = system (link_cmd); + if (verbose > 1) + printf ("$!status = %d\n", status); + + if ((status & 1) != 1) + { + status = 1; + goto cleanup_and_exit; + } + + if (debug && !share && ld_nocall_debug) + { + status = set_exe ("/flags=nocall_debug"); + if (status != 0) + goto cleanup_and_exit; + } + + if (!share && ld_mkthreads) + { + status = set_exe ("/flags=mkthreads"); + if (status != 0) + goto cleanup_and_exit; + } + + if (!share && ld_upcalls) + { + status = set_exe ("/flags=upcalls"); + if (status != 0) + goto cleanup_and_exit; + } + + status = 0; + + cleanup_and_exit: + if (!save_temps) + remove (optfilename); + + if (status == 0) + exit (EXIT_SUCCESS); + + if (exefullfilename && inhibit_exec == 1) + remove (exefullfilename); + + exit (EXIT_FAILURE); +} |