From patchwork Tue Apr 19 08:08:30 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tristan Gingold X-Patchwork-Id: 91930 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id C4F38B6FF0 for ; Tue, 19 Apr 2011 18:09:03 +1000 (EST) Received: (qmail 1089 invoked by alias); 19 Apr 2011 08:09:00 -0000 Received: (qmail 1076 invoked by uid 22791); 19 Apr 2011 08:08:54 -0000 X-SWARE-Spam-Status: No, hits=-0.6 required=5.0 tests=AWL, BAYES_20, FILL_THIS_FORM_FRAUD_PHISH, MIME_QP_LONG_LINE, TW_CP, TW_EV, TW_VP, T_FILL_THIS_FORM_SHORT X-Spam-Check-By: sourceware.org Received: from mel.act-europe.fr (HELO mel.act-europe.fr) (194.98.77.210) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 19 Apr 2011 08:08:35 +0000 Received: from localhost (localhost [127.0.0.1]) by filtered-smtp.eu.adacore.com (Postfix) with ESMTP id 13B61CB0214 for ; Tue, 19 Apr 2011 10:08:34 +0200 (CEST) Received: from mel.act-europe.fr ([127.0.0.1]) by localhost (smtp.eu.adacore.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id rs2K3FIpp8bk for ; Tue, 19 Apr 2011 10:08:31 +0200 (CEST) Received: from ulanbator.act-europe.fr (ulanbator.act-europe.fr [10.10.1.67]) (using TLSv1 with cipher AES128-SHA (128/128 bits)) (No client certificate requested) by mel.act-europe.fr (Postfix) with ESMTP id 84728CB0322 for ; Tue, 19 Apr 2011 10:08:30 +0200 (CEST) From: Tristan Gingold Subject: [vms] committed: add wrappers for ld and ar Date: Tue, 19 Apr 2011 10:08:30 +0200 Message-Id: To: "gcc-patches@gcc.gnu.org Patches" Mime-Version: 1.0 (Apple Message framework v1084) X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Hi, as the native vms linker ('link') doesn't follow at all the unix convention, we need to convert and massage the command line before invoking the native linker. The easiest and least intrusive way is the use of a wrapper. It deals with command line length limitation, filename, extension, library search, misc options and support of dwarf on alpha vms. Alongside, we also have a wrapper for ar (librarian on vms). They are automatically built unless gcc is configured with --with-gnu-ld. They can also be compiled on unix to unix to check for errors, also the binary is useless. I have also slightly cleaned up config.gcc to group common VMS definitions. Tested by doing cross-builds for both alpha and ia64 vms. Committed on trunk. Tristan. gcc/ 2011-04-19 Tristan Gingold * 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. Index: gcc/config.gcc =================================================================== --- gcc/config.gcc (revision 172694) +++ gcc/config.gcc (working copy) @@ -668,6 +668,16 @@ *-*-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 @@ 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-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" Index: gcc/config/vms/vms-ld.c =================================================================== --- gcc/config/vms/vms-ld.c (revision 0) +++ gcc/config/vms/vms-ld.c (revision 0) @@ -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 +. */ + +/* 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 +#include +#include +#include + +#include "libiberty.h" +#include +#include + +/* 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); +} Index: gcc/config/vms/vms-ar.c =================================================================== --- gcc/config/vms/vms-ar.c (revision 0) +++ gcc/config/vms/vms-ar.c (revision 0) @@ -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 +. */ + +#include +#include +#include +#include +#include +#include +#include + +#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); +} Index: gcc/config/vms/t-vmsnative =================================================================== --- gcc/config/vms/t-vmsnative (revision 0) +++ gcc/config/vms/t-vmsnative (revision 0) @@ -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 +# . + +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)