Fix for SPACK-11: Spack compiler wrapper is now in bash.
- Startup is much faster - Added test for compiler wrapper parsing. - Removed old compilation module that had to be imported by old cc. - Removed cc from python version checks now that it's bash.
This commit is contained in:
		
							
								
								
									
										420
									
								
								lib/spack/env/cc
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										420
									
								
								lib/spack/env/cc
									
									
									
									
										vendored
									
									
								
							@@ -1,140 +1,326 @@
 | 
			
		||||
#!/usr/bin/env python
 | 
			
		||||
import sys
 | 
			
		||||
if not sys.version_info[:2] >= (2,6):
 | 
			
		||||
    sys.exit("Spack requires Python 2.6.  Version was %s." % sys.version_info)
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
##############################################################################
 | 
			
		||||
# Copyright (c) 2013, Lawrence Livermore National Security, LLC.
 | 
			
		||||
# Produced at the Lawrence Livermore National Laboratory.
 | 
			
		||||
#
 | 
			
		||||
# This file is part of Spack.
 | 
			
		||||
# Written by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
 | 
			
		||||
# LLNL-CODE-647188
 | 
			
		||||
#
 | 
			
		||||
# For details, see https://scalability-llnl.github.io/spack
 | 
			
		||||
# Please also see the LICENSE file for our notice and the LGPL.
 | 
			
		||||
#
 | 
			
		||||
# This program 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) version 2.1 dated February 1999.
 | 
			
		||||
#
 | 
			
		||||
# This program 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 terms and
 | 
			
		||||
# conditions of the GNU General Public License for more details.
 | 
			
		||||
#
 | 
			
		||||
# You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
# along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 | 
			
		||||
##############################################################################
 | 
			
		||||
#
 | 
			
		||||
# Spack compiler wrapper script.
 | 
			
		||||
#
 | 
			
		||||
# Compiler commands go through this compiler wrapper in Spack builds.
 | 
			
		||||
# The compiler wrapper is a thin layer around the standard compilers.
 | 
			
		||||
# It enables several key pieces of functionality:
 | 
			
		||||
#
 | 
			
		||||
# 1. It allows Spack to swap compilers into and out of builds easily.
 | 
			
		||||
# 2. It adds several options to the compile line so that spack
 | 
			
		||||
#    packages can find their dependencies at build time and run time:
 | 
			
		||||
#      -I           arguments for dependency /include directories.
 | 
			
		||||
#      -L           arguments for dependency /lib directories.
 | 
			
		||||
#      -Wl,-rpath   arguments for dependency /lib directories.
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
import os
 | 
			
		||||
import re
 | 
			
		||||
import subprocess
 | 
			
		||||
from contextlib import closing
 | 
			
		||||
# This is the list of environment variables that need to be set before
 | 
			
		||||
# the script runs.  They are set by routines in spack.build_environment
 | 
			
		||||
# as part of spack.package.Package.do_install().
 | 
			
		||||
parameters="
 | 
			
		||||
SPACK_PREFIX
 | 
			
		||||
SPACK_ENV_PATH
 | 
			
		||||
SPACK_DEBUG_LOG_DIR
 | 
			
		||||
SPACK_COMPILER_SPEC
 | 
			
		||||
SPACK_SHORT_SPEC"
 | 
			
		||||
 | 
			
		||||
# Import spack parameters through the build environment.
 | 
			
		||||
spack_lib = os.environ.get("SPACK_LIB")
 | 
			
		||||
if not spack_lib:
 | 
			
		||||
    print "Spack compiler must be run from spack!"
 | 
			
		||||
    sys.exit(1)
 | 
			
		||||
# The compiler input variables are checked for sanity later:
 | 
			
		||||
#   SPACK_CC, SPACK_CXX, SPACK_F77, SPACK_FC
 | 
			
		||||
# Debug flag is optional; set to true for debug logging:
 | 
			
		||||
#   SPACK_DEBUG
 | 
			
		||||
# Test command is used to unit test the compiler script.
 | 
			
		||||
#   SPACK_TEST_COMMAND
 | 
			
		||||
# Dependencies can be empty for pkgs with no deps:
 | 
			
		||||
#   SPACK_DEPENDENCIES
 | 
			
		||||
 | 
			
		||||
# Grab a minimal set of spack packages
 | 
			
		||||
sys.path.append(spack_lib)
 | 
			
		||||
from spack.compilation import *
 | 
			
		||||
from external import argparse
 | 
			
		||||
import llnl.util.tty as tty
 | 
			
		||||
# die()
 | 
			
		||||
# Prints a message and exits with error 1.
 | 
			
		||||
function die {
 | 
			
		||||
    echo "$@"
 | 
			
		||||
    exit 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
spack_prefix        = get_env_var("SPACK_PREFIX")
 | 
			
		||||
spack_debug         = get_env_flag("SPACK_DEBUG")
 | 
			
		||||
spack_deps          = get_path("SPACK_DEPENDENCIES")
 | 
			
		||||
spack_env_path      = get_path("SPACK_ENV_PATH")
 | 
			
		||||
spack_debug_log_dir = get_env_var("SPACK_DEBUG_LOG_DIR")
 | 
			
		||||
spack_spec          = get_env_var("SPACK_SPEC")
 | 
			
		||||
for param in $parameters; do
 | 
			
		||||
    if [ -z "${!param}" ]; then
 | 
			
		||||
        die "Spack compiler must be run from spack!  Input $param was missing!"
 | 
			
		||||
    fi
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
compiler_spec = get_env_var("SPACK_COMPILER_SPEC")
 | 
			
		||||
spack_cc  = get_env_var("SPACK_CC",  required=False)
 | 
			
		||||
spack_cxx = get_env_var("SPACK_CXX", required=False)
 | 
			
		||||
spack_f77 = get_env_var("SPACK_F77", required=False)
 | 
			
		||||
spack_fc  = get_env_var("SPACK_FC",  required=False)
 | 
			
		||||
#
 | 
			
		||||
# Figure out the type of compiler, the language, and the mode so that
 | 
			
		||||
# the compiler script knows what to do.
 | 
			
		||||
#
 | 
			
		||||
# Possible languages are C, C++, Fortran 77, and Fortran 90.
 | 
			
		||||
# 'command' is set based on the input command to $SPACK_[CC|CXX|F77|F90]
 | 
			
		||||
#
 | 
			
		||||
# 'mode' is set to one of:
 | 
			
		||||
#    cc      compile
 | 
			
		||||
#    ld      link
 | 
			
		||||
#    ccld    compile & link
 | 
			
		||||
#    cpp     preprocessor
 | 
			
		||||
#    vcheck  version check
 | 
			
		||||
#
 | 
			
		||||
command=$(basename "$0")
 | 
			
		||||
case "$command" in
 | 
			
		||||
    cc|gcc|c89|c99|clang)
 | 
			
		||||
        command="$SPACK_CC"
 | 
			
		||||
        language="C"
 | 
			
		||||
        ;;
 | 
			
		||||
    c++|CC|g++|clang++)
 | 
			
		||||
        command="$SPACK_CXX"
 | 
			
		||||
        language="C++"
 | 
			
		||||
        ;;
 | 
			
		||||
    f77)
 | 
			
		||||
        command="$SPACK_F77"
 | 
			
		||||
        language="Fortran 77"
 | 
			
		||||
        ;;
 | 
			
		||||
    fc|f90|f95)
 | 
			
		||||
        command="$SPACK_FC"
 | 
			
		||||
        language="Fortran 90"
 | 
			
		||||
        ;;
 | 
			
		||||
    cpp)
 | 
			
		||||
        mode=cpp
 | 
			
		||||
        ;;
 | 
			
		||||
    ld)
 | 
			
		||||
        mode=ld
 | 
			
		||||
        ;;
 | 
			
		||||
    *)
 | 
			
		||||
        die "Unkown compiler: $command"
 | 
			
		||||
        ;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
# Figure out what type of operation we're doing
 | 
			
		||||
command = os.path.basename(sys.argv[0])
 | 
			
		||||
# Finish setting up the mode.
 | 
			
		||||
if [ -z "$mode" ]; then
 | 
			
		||||
    mode=ccld
 | 
			
		||||
    for arg in "$@"; do
 | 
			
		||||
        if [ "$arg" = -v -o "$arg" = -V -o "$arg" = --version -o "$arg" = -dumpversion ]; then
 | 
			
		||||
            mode=vcheck
 | 
			
		||||
            break
 | 
			
		||||
        elif [ "$arg" = -E ]; then
 | 
			
		||||
            mode=cpp
 | 
			
		||||
            break
 | 
			
		||||
        elif [ "$arg" = -c ]; then
 | 
			
		||||
            mode=cc
 | 
			
		||||
            break
 | 
			
		||||
        fi
 | 
			
		||||
    done
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
cpp, cc, ccld, ld, version_check = range(5)
 | 
			
		||||
# Dump the version and exist if we're in testing mode.
 | 
			
		||||
if [ "$SPACK_TEST_COMMAND" = "dump-mode" ]; then
 | 
			
		||||
    echo "$mode"
 | 
			
		||||
    exit
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if command == 'cpp':
 | 
			
		||||
    mode = cpp
 | 
			
		||||
elif command == 'ld':
 | 
			
		||||
    mode = ld
 | 
			
		||||
elif '-E' in sys.argv:
 | 
			
		||||
    mode = cpp
 | 
			
		||||
elif '-c' in sys.argv:
 | 
			
		||||
    mode = cc
 | 
			
		||||
else:
 | 
			
		||||
    mode = ccld
 | 
			
		||||
# Check that at least one of the real commands was actually selected,
 | 
			
		||||
# otherwise we don't know what to execute.
 | 
			
		||||
if [ -z "$command" ]; then
 | 
			
		||||
    die "ERROR: Compiler '$SPACK_COMPILER_SPEC' does not support compiling $language programs."
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Save original command for debug logging
 | 
			
		||||
input_command="$@"
 | 
			
		||||
 | 
			
		||||
if command in ('cc', 'gcc', 'c89', 'c99', 'clang'):
 | 
			
		||||
    command = spack_cc
 | 
			
		||||
    language = "C"
 | 
			
		||||
elif command in ('c++', 'CC', 'g++', 'clang++'):
 | 
			
		||||
    command = spack_cxx
 | 
			
		||||
    language = "C++"
 | 
			
		||||
elif command in ('f77'):
 | 
			
		||||
    command = spack_f77
 | 
			
		||||
    language = "Fortran 77"
 | 
			
		||||
elif command in ('fc', 'f90', 'f95'):
 | 
			
		||||
    command = spack_fc
 | 
			
		||||
    language = "Fortran 90"
 | 
			
		||||
elif command in ('ld', 'cpp'):
 | 
			
		||||
    pass # leave it the same.  TODO: what's the right thing?
 | 
			
		||||
else:
 | 
			
		||||
    raise Exception("Unknown compiler: %s" % command)
 | 
			
		||||
#
 | 
			
		||||
# Now do real parsing of the command line args, trying hard to keep
 | 
			
		||||
# non-rpath linker arguments in the proper order w.r.t. other command
 | 
			
		||||
# line arguments.  This is important for things like groups.
 | 
			
		||||
#
 | 
			
		||||
includes=()
 | 
			
		||||
libraries=()
 | 
			
		||||
libs=()
 | 
			
		||||
rpaths=()
 | 
			
		||||
other_args=()
 | 
			
		||||
 | 
			
		||||
if command is None:
 | 
			
		||||
    print "ERROR: Compiler '%s' does not support compiling %s programs." % (
 | 
			
		||||
        compiler_spec, language)
 | 
			
		||||
    sys.exit(1)
 | 
			
		||||
while [ -n "$1" ]; do
 | 
			
		||||
    case "$1" in
 | 
			
		||||
        -I*)
 | 
			
		||||
            arg="${1#-I}"
 | 
			
		||||
            if [ -z "$arg" ]; then shift; arg="$1"; fi
 | 
			
		||||
            includes+=("$arg")
 | 
			
		||||
            ;;
 | 
			
		||||
        -L*)
 | 
			
		||||
            arg="${1#-L}"
 | 
			
		||||
            if [ -z "$arg" ]; then shift; arg="$1"; fi
 | 
			
		||||
            libraries+=("$arg")
 | 
			
		||||
            ;;
 | 
			
		||||
        -l*)
 | 
			
		||||
            arg="${1#-l}"
 | 
			
		||||
            if [ -z "$arg" ]; then shift; arg="$1"; fi
 | 
			
		||||
            libs+=("$arg")
 | 
			
		||||
            ;;
 | 
			
		||||
        -Wl,*)
 | 
			
		||||
            arg="${1#-Wl,}"
 | 
			
		||||
            if [ -z "$arg" ]; then shift; arg="$1"; fi
 | 
			
		||||
            if [[ "$arg" = -rpath=* ]]; then
 | 
			
		||||
                rpaths+=("${arg#-rpath=}")
 | 
			
		||||
            elif [[ "$arg" = -rpath ]]; then
 | 
			
		||||
                shift; arg="$1"
 | 
			
		||||
                if [[ "$arg" != -Wl,* ]]; then
 | 
			
		||||
                    die "-Wl,-rpath was not followed by -Wl,*"
 | 
			
		||||
                fi
 | 
			
		||||
                rpaths+=("${arg#-Wl,}")
 | 
			
		||||
            else
 | 
			
		||||
                other_args+=("-Wl,$arg")
 | 
			
		||||
            fi
 | 
			
		||||
            ;;
 | 
			
		||||
        -Xlinker,*)
 | 
			
		||||
            arg="${1#-Xlinker,}"
 | 
			
		||||
            if [ -z "$arg" ]; then shift; arg="$1"; fi
 | 
			
		||||
            if [[ "$arg" = -rpath=* ]]; then
 | 
			
		||||
                rpaths+=("${arg#-rpath=}")
 | 
			
		||||
            elif [[ "$arg" = -rpath ]]; then
 | 
			
		||||
                shift; arg="$1"
 | 
			
		||||
                if [[ "$arg" != -Xlinker,* ]]; then
 | 
			
		||||
                    die "-Xlinker,-rpath was not followed by -Xlinker,*"
 | 
			
		||||
                fi
 | 
			
		||||
                rpaths+=("${arg#-Xlinker,}")
 | 
			
		||||
            else
 | 
			
		||||
                other_args+=("-Xlinker,$arg")
 | 
			
		||||
            fi
 | 
			
		||||
            ;;
 | 
			
		||||
        *)
 | 
			
		||||
            other_args+=("$1")
 | 
			
		||||
            ;;
 | 
			
		||||
    esac
 | 
			
		||||
    shift
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
version_args = ['-V', '-v', '--version', '-dumpversion']
 | 
			
		||||
if any(arg in sys.argv for arg in version_args):
 | 
			
		||||
    mode = version_check
 | 
			
		||||
# Dump parsed values for unit testing if asked for
 | 
			
		||||
if [ -n "$SPACK_TEST_COMMAND" ]; then
 | 
			
		||||
    IFS=$'\n'
 | 
			
		||||
    case "$SPACK_TEST_COMMAND" in
 | 
			
		||||
        dump-includes)   echo "${includes[*]}";;
 | 
			
		||||
        dump-libraries)  echo "${libraries[*]}";;
 | 
			
		||||
        dump-libs)       echo "${libs[*]}";;
 | 
			
		||||
        dump-rpaths)     echo "${rpaths[*]}";;
 | 
			
		||||
        dump-other-args) echo "${other_args[*]}";;
 | 
			
		||||
        dump-all)
 | 
			
		||||
            echo "INCLUDES:"
 | 
			
		||||
            echo "${includes[*]}"
 | 
			
		||||
            echo
 | 
			
		||||
            echo "LIBRARIES:"
 | 
			
		||||
            echo "${libraries[*]}"
 | 
			
		||||
            echo
 | 
			
		||||
            echo "LIBS:"
 | 
			
		||||
            echo "${libs[*]}"
 | 
			
		||||
            echo
 | 
			
		||||
            echo "RPATHS:"
 | 
			
		||||
            echo "${rpaths[*]}"
 | 
			
		||||
            echo
 | 
			
		||||
            echo "ARGS:"
 | 
			
		||||
            echo "${other_args[*]}"
 | 
			
		||||
            ;;
 | 
			
		||||
        *)
 | 
			
		||||
            echo "ERROR: Unknown test command"
 | 
			
		||||
            exit 1 ;;
 | 
			
		||||
    esac
 | 
			
		||||
    exit
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Parse out the includes, libs, etc. so we can adjust them if need be.
 | 
			
		||||
parser = argparse.ArgumentParser(add_help=False)
 | 
			
		||||
parser.add_argument("-I", action='append', default=[], dest='include_path')
 | 
			
		||||
parser.add_argument("-L", action='append', default=[], dest='lib_path')
 | 
			
		||||
parser.add_argument("-l", action='append', default=[], dest='libs')
 | 
			
		||||
# Read spack dependencies from the path environment variable
 | 
			
		||||
IFS=':' read -ra deps <<< "$SPACK_DEPENDENCIES"
 | 
			
		||||
for dep in "${deps[@]}"; do
 | 
			
		||||
    if [ -d "$dep/include" ]; then
 | 
			
		||||
        includes+=("$dep/include")
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
options, other_args = parser.parse_known_args()
 | 
			
		||||
rpaths, other_args = parse_rpaths(other_args)
 | 
			
		||||
    if [ -d "$dep/lib" ]; then
 | 
			
		||||
        libraries+=("$dep/lib")
 | 
			
		||||
        rpaths+=("$dep/lib")
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
# Add dependencies' include and lib paths to our compiler flags.
 | 
			
		||||
def add_if_dir(path_list, directory, index=None):
 | 
			
		||||
    if os.path.isdir(directory):
 | 
			
		||||
        if index is None:
 | 
			
		||||
            path_list.append(directory)
 | 
			
		||||
        else:
 | 
			
		||||
            path_list.insert(index, directory)
 | 
			
		||||
    if [ -d "$dep/lib64" ]; then
 | 
			
		||||
        libraries+=("$dep/lib64")
 | 
			
		||||
        rpaths+=("$dep/lib64")
 | 
			
		||||
    fi
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
for dep_dir in spack_deps:
 | 
			
		||||
    add_if_dir(options.include_path, os.path.join(dep_dir, "include"))
 | 
			
		||||
    add_if_dir(options.lib_path,     os.path.join(dep_dir, "lib"))
 | 
			
		||||
    add_if_dir(options.lib_path,     os.path.join(dep_dir, "lib64"))
 | 
			
		||||
# Include all -L's and prefix/whatever dirs in rpath
 | 
			
		||||
for dir in "${libraries[@]}"; do
 | 
			
		||||
    [ "$dir" != "." ] && rpaths+=("$dir")
 | 
			
		||||
done
 | 
			
		||||
rpaths+=("$SPACK_PREFIX/lib")
 | 
			
		||||
rpaths+=("$SPACK_PREFIX/lib64")
 | 
			
		||||
 | 
			
		||||
# Add our modified arguments to it.
 | 
			
		||||
arguments  = ['-I%s' % path for path in options.include_path]
 | 
			
		||||
arguments += other_args
 | 
			
		||||
arguments += ['-L%s' % path for path in options.lib_path]
 | 
			
		||||
arguments += ['-l%s' % path for path in options.libs]
 | 
			
		||||
# Put the arguments together
 | 
			
		||||
args=()
 | 
			
		||||
for dir in "${includes[@]}";  do args+=("-I$dir"); done
 | 
			
		||||
args+=("${other_args[@]}")
 | 
			
		||||
for dir in "${libraries[@]}"; do args+=("-L$dir"); done
 | 
			
		||||
for lib in "${libs[@]}";      do args+=("-l$lib"); done
 | 
			
		||||
 | 
			
		||||
# Add rpaths to install dir and its dependencies.  We add both lib and lib64
 | 
			
		||||
# here because we don't know which will be created.
 | 
			
		||||
rpaths.extend(options.lib_path)
 | 
			
		||||
rpaths.append('%s/lib'   % spack_prefix)
 | 
			
		||||
rpaths.append('%s/lib64' % spack_prefix)
 | 
			
		||||
if mode == ccld:
 | 
			
		||||
    arguments += ['-Wl,-rpath,%s' % p for p in rpaths]
 | 
			
		||||
elif mode == ld:
 | 
			
		||||
    pairs = [('-rpath', '%s' % p) for p in rpaths]
 | 
			
		||||
    arguments += [item for sublist in pairs for item in sublist]
 | 
			
		||||
if [ "$mode" = ccld ]; then
 | 
			
		||||
    for dir in "${rpaths[@]}"; do args+=("-Wl,-rpath=$dir"); done
 | 
			
		||||
elif [ "$mode" = ld ]; then
 | 
			
		||||
    for dir in "${rpaths[@]}"; do args+=("-rpath=$dir"); done
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Unset some pesky environment variables
 | 
			
		||||
for var in ["LD_LIBRARY_PATH", "LD_RUN_PATH", "DYLD_LIBRARY_PATH"]:
 | 
			
		||||
    if var in os.environ:
 | 
			
		||||
        os.environ.pop(var)
 | 
			
		||||
#
 | 
			
		||||
# Unset pesky environment variables that could affect build sanity.
 | 
			
		||||
#
 | 
			
		||||
unset LD_LIBRARY_PATH
 | 
			
		||||
unset LD_RUN_PATH
 | 
			
		||||
unset DYLD_LIBRARY_PATH
 | 
			
		||||
 | 
			
		||||
# Ensure that the delegated command doesn't just call this script again.
 | 
			
		||||
remove_paths = ['.'] + spack_env_path
 | 
			
		||||
path = [p for p in get_path("PATH") if p not in remove_paths]
 | 
			
		||||
os.environ["PATH"] = ":".join(path)
 | 
			
		||||
#
 | 
			
		||||
# Filter '.' and Spack environment directories out of PATH so that
 | 
			
		||||
# this script doesn't just call itself
 | 
			
		||||
#
 | 
			
		||||
IFS=':' read -ra env_path <<< "$PATH"
 | 
			
		||||
IFS=':' read -ra spack_env_dirs <<< "$SPACK_ENV_PATH"
 | 
			
		||||
spack_env_dirs+=(".")
 | 
			
		||||
PATH=""
 | 
			
		||||
for dir in "${env_path[@]}"; do
 | 
			
		||||
    remove=""
 | 
			
		||||
    for rm_dir in "${spack_env_dirs[@]}"; do
 | 
			
		||||
        if [ "$dir" = "$rm_dir" ]; then remove=True; fi
 | 
			
		||||
    done
 | 
			
		||||
    if [ -z "$remove" ]; then
 | 
			
		||||
        if [ -z "$PATH" ]; then
 | 
			
		||||
            PATH="$dir"
 | 
			
		||||
        else
 | 
			
		||||
            PATH="$PATH:$dir"
 | 
			
		||||
        fi
 | 
			
		||||
    fi
 | 
			
		||||
done
 | 
			
		||||
export PATH
 | 
			
		||||
 | 
			
		||||
full_command = [command] + arguments
 | 
			
		||||
full_command=("$command")
 | 
			
		||||
full_command+=("${args[@]}")
 | 
			
		||||
 | 
			
		||||
if spack_debug:
 | 
			
		||||
    input_log = os.path.join(spack_debug_log_dir,  'spack-cc-%s.in.log' % spack_spec)
 | 
			
		||||
    output_log = os.path.join(spack_debug_log_dir, 'spack-cc-%s.out.log' % spack_spec)
 | 
			
		||||
    with closing(open(input_log, 'a')) as log:
 | 
			
		||||
        args = [os.path.basename(sys.argv[0])] + sys.argv[1:]
 | 
			
		||||
        log.write("%s\n" % " ".join(arg.replace(' ', r'\ ') for arg in args))
 | 
			
		||||
    with closing(open(output_log, 'a')) as log:
 | 
			
		||||
        log.write("%s\n" % " ".join(full_command))
 | 
			
		||||
#
 | 
			
		||||
# Write the input and output commands to debug logs if it's asked for.
 | 
			
		||||
#
 | 
			
		||||
if [ "$SPACK_DEBUG" = "TRUE" ]; then
 | 
			
		||||
    input_log="$SPACK_DEBUG_LOG_DIR/spack-cc-$SPACK_SHORT_SPEC.in.log"
 | 
			
		||||
    output_log="$SPACK_DEBUG_LOG_DIR/spack-cc-$SPACK_SHORT_SPEC.out.log"
 | 
			
		||||
    echo "$input_command"     >> $input_log
 | 
			
		||||
    echo "$mode       ${full_command[@]}" >> $output_log
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
rcode = subprocess.call(full_command)
 | 
			
		||||
sys.exit(rcode)
 | 
			
		||||
exec "${full_command[@]}"
 | 
			
		||||
 
 | 
			
		||||
@@ -48,12 +48,11 @@
 | 
			
		||||
# set_build_environment_variables and used to pass parameters to
 | 
			
		||||
# Spack's compiler wrappers.
 | 
			
		||||
#
 | 
			
		||||
SPACK_LIB              = 'SPACK_LIB'
 | 
			
		||||
SPACK_ENV_PATH         = 'SPACK_ENV_PATH'
 | 
			
		||||
SPACK_DEPENDENCIES     = 'SPACK_DEPENDENCIES'
 | 
			
		||||
SPACK_PREFIX           = 'SPACK_PREFIX'
 | 
			
		||||
SPACK_DEBUG            = 'SPACK_DEBUG'
 | 
			
		||||
SPACK_SPEC             = 'SPACK_SPEC'
 | 
			
		||||
SPACK_SHORT_SPEC       = 'SPACK_SHORT_SPEC'
 | 
			
		||||
SPACK_DEBUG_LOG_DIR    = 'SPACK_DEBUG_LOG_DIR'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -108,9 +107,6 @@ def set_compiler_environment_variables(pkg):
 | 
			
		||||
def set_build_environment_variables(pkg):
 | 
			
		||||
    """This ensures a clean install environment when we build packages.
 | 
			
		||||
    """
 | 
			
		||||
    # This tells the compiler script where to find the Spack installation.
 | 
			
		||||
    os.environ[SPACK_LIB] = spack.lib_path
 | 
			
		||||
 | 
			
		||||
    # Add spack build environment path with compiler wrappers first in
 | 
			
		||||
    # the path.  We handle case sensitivity conflicts like "CC" and
 | 
			
		||||
    # "cc" by putting one in the <build_env_path>/case-insensitive
 | 
			
		||||
@@ -140,7 +136,7 @@ def set_build_environment_variables(pkg):
 | 
			
		||||
    # Working directory for the spack command itself, for debug logs.
 | 
			
		||||
    if spack.debug:
 | 
			
		||||
        os.environ[SPACK_DEBUG] = "TRUE"
 | 
			
		||||
    os.environ[SPACK_SPEC] = str(pkg.spec)
 | 
			
		||||
    os.environ[SPACK_SHORT_SPEC] = pkg.spec.short_spec
 | 
			
		||||
    os.environ[SPACK_DEBUG_LOG_DIR] = spack.spack_working_dir
 | 
			
		||||
 | 
			
		||||
    # Add dependencies to CMAKE_PREFIX_PATH
 | 
			
		||||
 
 | 
			
		||||
@@ -31,7 +31,7 @@
 | 
			
		||||
import spack.compilers
 | 
			
		||||
import spack.spec
 | 
			
		||||
import spack.config
 | 
			
		||||
from spack.compilation import get_path
 | 
			
		||||
from spack.util.environment import get_path
 | 
			
		||||
from spack.spec import CompilerSpec
 | 
			
		||||
 | 
			
		||||
description = "Manage compilers"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,117 +0,0 @@
 | 
			
		||||
##############################################################################
 | 
			
		||||
# Copyright (c) 2013, Lawrence Livermore National Security, LLC.
 | 
			
		||||
# Produced at the Lawrence Livermore National Laboratory.
 | 
			
		||||
#
 | 
			
		||||
# This file is part of Spack.
 | 
			
		||||
# Written by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
 | 
			
		||||
# LLNL-CODE-647188
 | 
			
		||||
#
 | 
			
		||||
# For details, see https://scalability-llnl.github.io/spack
 | 
			
		||||
# Please also see the LICENSE file for our notice and the LGPL.
 | 
			
		||||
#
 | 
			
		||||
# This program 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) version 2.1 dated February 1999.
 | 
			
		||||
#
 | 
			
		||||
# This program 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 terms and
 | 
			
		||||
# conditions of the GNU General Public License for more details.
 | 
			
		||||
#
 | 
			
		||||
# You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
# along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 | 
			
		||||
##############################################################################
 | 
			
		||||
"""\
 | 
			
		||||
The ``compilation`` module contains utility functions used by the compiler
 | 
			
		||||
wrapper script.
 | 
			
		||||
 | 
			
		||||
.. todo::
 | 
			
		||||
 | 
			
		||||
   Think about moving this into the script to increase compilation
 | 
			
		||||
   speed.
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
import os
 | 
			
		||||
import sys
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_env_var(name, required=True):
 | 
			
		||||
    value = os.environ.get(name)
 | 
			
		||||
    if required and value is None:
 | 
			
		||||
        print "%s must be run from spack." % os.path.abspath(sys.argv[0])
 | 
			
		||||
        sys.exit(1)
 | 
			
		||||
    return value
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_env_flag(name, required=False):
 | 
			
		||||
    value = get_env_var(name, required)
 | 
			
		||||
    if value:
 | 
			
		||||
        return value.lower() == "true"
 | 
			
		||||
    return False
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_path(name):
 | 
			
		||||
    path = os.environ.get(name, "").strip()
 | 
			
		||||
    if path:
 | 
			
		||||
        return path.split(":")
 | 
			
		||||
    else:
 | 
			
		||||
        return []
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def parse_rpaths(arguments):
 | 
			
		||||
    """argparse, for all its features, cannot understand most compilers'
 | 
			
		||||
       rpath arguments.  This handles '-Wl,', '-Xlinker', and '-R'"""
 | 
			
		||||
    def get_next(arg, args):
 | 
			
		||||
        """Get an expected next value of an iterator, or die if it's not there"""
 | 
			
		||||
        try:
 | 
			
		||||
            return next(args)
 | 
			
		||||
        except StopIteration:
 | 
			
		||||
            # quietly ignore -rpath and -Xlinker without args.
 | 
			
		||||
            return None
 | 
			
		||||
 | 
			
		||||
    other_args = []
 | 
			
		||||
    def linker_args():
 | 
			
		||||
        """This generator function allows us to parse the linker args separately
 | 
			
		||||
           from the compiler args, so that we can handle them more naturally.
 | 
			
		||||
        """
 | 
			
		||||
        args = iter(arguments)
 | 
			
		||||
        for arg in args:
 | 
			
		||||
            if arg.startswith('-Wl,'):
 | 
			
		||||
                sub_args = [sub for sub in arg.replace('-Wl,', '', 1).split(',')]
 | 
			
		||||
                for arg in sub_args:
 | 
			
		||||
                    yield arg
 | 
			
		||||
            elif arg == '-Xlinker':
 | 
			
		||||
                target = get_next(arg, args)
 | 
			
		||||
                if target is not None:
 | 
			
		||||
                    yield target
 | 
			
		||||
            else:
 | 
			
		||||
                other_args.append(arg)
 | 
			
		||||
 | 
			
		||||
    # Extract all the possible ways rpath can appear in linker args, then
 | 
			
		||||
    # append non-rpaths to other_args.  This happens in-line as the linker
 | 
			
		||||
    # args are extracted, so we preserve the original order of arguments.
 | 
			
		||||
    # This is important for args like --whole-archive, --no-whole-archive,
 | 
			
		||||
    # and others that tell the linker how to handle the next few libraries
 | 
			
		||||
    # it encounters on the command line.
 | 
			
		||||
    rpaths = []
 | 
			
		||||
    largs = linker_args()
 | 
			
		||||
    for arg in largs:
 | 
			
		||||
        if arg == '-rpath':
 | 
			
		||||
            target = get_next(arg, largs)
 | 
			
		||||
            if target is not None:
 | 
			
		||||
                rpaths.append(target)
 | 
			
		||||
 | 
			
		||||
        elif arg.startswith('-R'):
 | 
			
		||||
            target = arg.replace('-R', '', 1)
 | 
			
		||||
            if not target:
 | 
			
		||||
                target = get_next(arg, largs)
 | 
			
		||||
                if target is None: break
 | 
			
		||||
 | 
			
		||||
            if os.path.isdir(target):
 | 
			
		||||
                rpaths.append(target)
 | 
			
		||||
            else:
 | 
			
		||||
                other_args.extend(['-Wl,' + arg, '-Wl,' + target])
 | 
			
		||||
        else:
 | 
			
		||||
            other_args.append('-Wl,' + arg)
 | 
			
		||||
    return rpaths, other_args
 | 
			
		||||
@@ -35,8 +35,8 @@
 | 
			
		||||
import spack.spec
 | 
			
		||||
from spack.util.multiproc import parmap
 | 
			
		||||
from spack.util.executable import *
 | 
			
		||||
from spack.util.environment import get_path
 | 
			
		||||
from spack.version import Version
 | 
			
		||||
from spack.compilation import get_path
 | 
			
		||||
 | 
			
		||||
__all__ = ['Compiler', 'get_compiler_version']
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -40,7 +40,7 @@
 | 
			
		||||
from spack.compiler import Compiler
 | 
			
		||||
from spack.util.executable import which
 | 
			
		||||
from spack.util.naming import mod_to_class
 | 
			
		||||
from spack.compilation import get_path
 | 
			
		||||
from spack.util.environment import get_path
 | 
			
		||||
 | 
			
		||||
_imported_compilers_module = 'spack.compilers'
 | 
			
		||||
_required_instance_vars = ['cc', 'cxx', 'f77', 'fc']
 | 
			
		||||
 
 | 
			
		||||
@@ -53,7 +53,8 @@
 | 
			
		||||
              'svn_fetch',
 | 
			
		||||
              'hg_fetch',
 | 
			
		||||
              'mirror',
 | 
			
		||||
              'url_extrapolate']
 | 
			
		||||
              'url_extrapolate',
 | 
			
		||||
              'cc']
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def list_tests():
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										130
									
								
								lib/spack/spack/test/cc.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								lib/spack/spack/test/cc.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,130 @@
 | 
			
		||||
##############################################################################
 | 
			
		||||
# Copyright (c) 2013, Lawrence Livermore National Security, LLC.
 | 
			
		||||
# Produced at the Lawrence Livermore National Laboratory.
 | 
			
		||||
#
 | 
			
		||||
# This file is part of Spack.
 | 
			
		||||
# Written by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
 | 
			
		||||
# LLNL-CODE-647188
 | 
			
		||||
#
 | 
			
		||||
# For details, see https://scalability-llnl.github.io/spack
 | 
			
		||||
# Please also see the LICENSE file for our notice and the LGPL.
 | 
			
		||||
#
 | 
			
		||||
# This program 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) version 2.1 dated February 1999.
 | 
			
		||||
#
 | 
			
		||||
# This program 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 terms and
 | 
			
		||||
# conditions of the GNU General Public License for more details.
 | 
			
		||||
#
 | 
			
		||||
# You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
# along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 | 
			
		||||
##############################################################################
 | 
			
		||||
"""
 | 
			
		||||
This test checks that the Spack cc compiler wrapper is parsing
 | 
			
		||||
arguments correctly.
 | 
			
		||||
"""
 | 
			
		||||
import os
 | 
			
		||||
import unittest
 | 
			
		||||
 | 
			
		||||
from llnl.util.filesystem import *
 | 
			
		||||
import spack
 | 
			
		||||
from spack.util.executable import *
 | 
			
		||||
 | 
			
		||||
# Complicated compiler test command
 | 
			
		||||
test_command = [
 | 
			
		||||
    '-I/test/include', '-L/test/lib', '-L/other/lib', '-I/other/include',
 | 
			
		||||
    'arg1',
 | 
			
		||||
    '-Wl,--start-group',
 | 
			
		||||
    'arg2',
 | 
			
		||||
    '-Wl,-rpath=/first/rpath', 'arg3', '-Wl,-rpath', '-Wl,/second/rpath',
 | 
			
		||||
    '-llib1', '-llib2',
 | 
			
		||||
    'arg4',
 | 
			
		||||
    '-Wl,--end-group',
 | 
			
		||||
    '-Xlinker,-rpath', '-Xlinker,/third/rpath', '-Xlinker,-rpath=/fourth/rpath',
 | 
			
		||||
    '-llib3', '-llib4',
 | 
			
		||||
    'arg5', 'arg6']
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CompilerTest(unittest.TestCase):
 | 
			
		||||
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        self.cc = Executable(join_path(spack.build_env_path, "cc"))
 | 
			
		||||
        self.ld = Executable(join_path(spack.build_env_path, "ld"))
 | 
			
		||||
        self.cpp = Executable(join_path(spack.build_env_path, "cpp"))
 | 
			
		||||
 | 
			
		||||
        os.environ['SPACK_CC'] = "/bin/mycc"
 | 
			
		||||
        os.environ['SPACK_PREFIX'] = "/usr"
 | 
			
		||||
        os.environ['SPACK_ENV_PATH']="test"
 | 
			
		||||
        os.environ['SPACK_DEBUG_LOG_DIR'] = "."
 | 
			
		||||
        os.environ['SPACK_COMPILER_SPEC'] = "gcc@4.4.7"
 | 
			
		||||
        os.environ['SPACK_SHORT_SPEC'] = "foo@1.2"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def check_cc(self, command, args, expected):
 | 
			
		||||
        os.environ['SPACK_TEST_COMMAND'] = command
 | 
			
		||||
        self.assertEqual(self.cc(*args, return_output=True).strip(), expected)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def check_ld(self, command, args, expected):
 | 
			
		||||
        os.environ['SPACK_TEST_COMMAND'] = command
 | 
			
		||||
        self.assertEqual(self.ld(*args, return_output=True).strip(), expected)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def check_cpp(self, command, args, expected):
 | 
			
		||||
        os.environ['SPACK_TEST_COMMAND'] = command
 | 
			
		||||
        self.assertEqual(self.cpp(*args, return_output=True).strip(), expected)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def test_vcheck_mode(self):
 | 
			
		||||
        self.check_cc('dump-mode', ['-I/include', '--version'], "vcheck")
 | 
			
		||||
        self.check_cc('dump-mode', ['-I/include', '-V'], "vcheck")
 | 
			
		||||
        self.check_cc('dump-mode', ['-I/include', '-v'], "vcheck")
 | 
			
		||||
        self.check_cc('dump-mode', ['-I/include', '-dumpversion'], "vcheck")
 | 
			
		||||
        self.check_cc('dump-mode', ['-I/include', '--version', '-c'], "vcheck")
 | 
			
		||||
        self.check_cc('dump-mode', ['-I/include', '-V', '-o', 'output'], "vcheck")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def test_cpp_mode(self):
 | 
			
		||||
        self.check_cc('dump-mode', ['-E'], "cpp")
 | 
			
		||||
        self.check_cpp('dump-mode', [], "cpp")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def test_ccld_mode(self):
 | 
			
		||||
        self.check_cc('dump-mode', [], "ccld")
 | 
			
		||||
        self.check_cc('dump-mode', ['foo.c', '-o', 'foo'], "ccld")
 | 
			
		||||
        self.check_cc('dump-mode', ['foo.c', '-o', 'foo', '-Wl,-rpath=foo'], "ccld")
 | 
			
		||||
        self.check_cc('dump-mode', ['foo.o', 'bar.o', 'baz.o', '-o', 'foo', '-Wl,-rpath=foo'], "ccld")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def test_ld_mode(self):
 | 
			
		||||
        self.check_ld('dump-mode', [], "ld")
 | 
			
		||||
        self.check_ld('dump-mode', ['foo.o', 'bar.o', 'baz.o', '-o', 'foo', '-Wl,-rpath=foo'], "ld")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def test_includes(self):
 | 
			
		||||
        self.check_cc('dump-includes', test_command,
 | 
			
		||||
                      "\n".join(["/test/include", "/other/include"]))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def test_libraries(self):
 | 
			
		||||
        self.check_cc('dump-libraries', test_command,
 | 
			
		||||
                      "\n".join(["/test/lib", "/other/lib"]))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def test_libs(self):
 | 
			
		||||
        self.check_cc('dump-libs', test_command,
 | 
			
		||||
                      "\n".join(["lib1", "lib2", "lib3", "lib4"]))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def test_rpaths(self):
 | 
			
		||||
        self.check_cc('dump-rpaths', test_command,
 | 
			
		||||
                      "\n".join(["/first/rpath", "/second/rpath", "/third/rpath", "/fourth/rpath"]))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def test_other_args(self):
 | 
			
		||||
        self.check_cc('dump-other-args', test_command,
 | 
			
		||||
                      "\n".join(["arg1", "-Wl,--start-group", "arg2", "arg3", "arg4",
 | 
			
		||||
                                 "-Wl,--end-group", "arg5", "arg6"]))
 | 
			
		||||
@@ -45,7 +45,6 @@ class PythonVersionTest(unittest.TestCase):
 | 
			
		||||
    def spack_python_files(self):
 | 
			
		||||
        # first file is the spack script.
 | 
			
		||||
        yield spack.spack_file
 | 
			
		||||
        yield os.path.join(spack.build_env_path, 'cc')
 | 
			
		||||
 | 
			
		||||
        # Next files are all the source files and package files.
 | 
			
		||||
        search_paths = [spack.lib_path, spack.var_path]
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,15 @@
 | 
			
		||||
##############################################################################
 | 
			
		||||
import os
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_path(name):
 | 
			
		||||
    path = os.environ.get(name, "").strip()
 | 
			
		||||
    if path:
 | 
			
		||||
        return path.split(":")
 | 
			
		||||
    else:
 | 
			
		||||
        return []
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def env_flag(name):
 | 
			
		||||
    if name in os.environ:
 | 
			
		||||
        return os.environ[name].lower() == "true"
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user