diff options
author | Todd Gamblin <tgamblin@llnl.gov> | 2014-11-02 23:53:45 -0800 |
---|---|---|
committer | Todd Gamblin <tgamblin@llnl.gov> | 2014-11-03 14:12:16 -0800 |
commit | 0f3b80cddbfd775c10f68423444aca792525f856 (patch) | |
tree | 2c0d62d062de4b0ed1f79bba8d43bf60ccac8cee /lib | |
parent | 1656f62a125232b30235da01e816a3ade4481b8a (diff) | |
download | spack-0f3b80cddbfd775c10f68423444aca792525f856.tar.gz spack-0f3b80cddbfd775c10f68423444aca792525f856.tar.bz2 spack-0f3b80cddbfd775c10f68423444aca792525f856.tar.xz spack-0f3b80cddbfd775c10f68423444aca792525f856.zip |
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.
Diffstat (limited to 'lib')
-rwxr-xr-x | lib/spack/env/cc | 466 | ||||
-rw-r--r-- | lib/spack/spack/build_environment.py | 8 | ||||
-rw-r--r-- | lib/spack/spack/cmd/compiler.py | 2 | ||||
-rw-r--r-- | lib/spack/spack/compilation.py | 117 | ||||
-rw-r--r-- | lib/spack/spack/compiler.py | 2 | ||||
-rw-r--r-- | lib/spack/spack/compilers/__init__.py | 2 | ||||
-rw-r--r-- | lib/spack/spack/test/__init__.py | 3 | ||||
-rw-r--r-- | lib/spack/spack/test/cc.py | 130 | ||||
-rw-r--r-- | lib/spack/spack/test/python_version.py | 1 | ||||
-rw-r--r-- | lib/spack/spack/util/environment.py | 9 |
10 files changed, 472 insertions, 268 deletions
diff --git a/lib/spack/env/cc b/lib/spack/env/cc index 266e41cb48..f68cb0b2cd 100755 --- a/lib/spack/env/cc +++ b/lib/spack/env/cc @@ -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) - -import os -import re -import subprocess -from contextlib import closing - -# 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) - -# 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 - -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") - -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 what type of operation we're doing -command = os.path.basename(sys.argv[0]) - -cpp, cc, ccld, ld, version_check = range(5) - -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 - - -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) - -if command is None: - print "ERROR: Compiler '%s' does not support compiling %s programs." % ( - compiler_spec, language) - sys.exit(1) - -version_args = ['-V', '-v', '--version', '-dumpversion'] -if any(arg in sys.argv for arg in version_args): - mode = version_check - -# 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') - -options, other_args = parser.parse_known_args() -rpaths, other_args = parse_rpaths(other_args) - -# 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) - -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")) - -# 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] - -# 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] - -# 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) - -# 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) - -full_command = [command] + arguments - -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)) - -rcode = subprocess.call(full_command) -sys.exit(rcode) +#!/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. +# + +# 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" + +# 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 + +# die() +# Prints a message and exits with error 1. +function die { + echo "$@" + exit 1 +} + +for param in $parameters; do + if [ -z "${!param}" ]; then + die "Spack compiler must be run from spack! Input $param was missing!" + fi +done + +# +# 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 + +# 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 + +# Dump the version and exist if we're in testing mode. +if [ "$SPACK_TEST_COMMAND" = "dump-mode" ]; then + echo "$mode" + exit +fi + +# 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="$@" + +# +# 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=() + +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 + +# 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 + +# 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 + + if [ -d "$dep/lib" ]; then + libraries+=("$dep/lib") + rpaths+=("$dep/lib") + fi + + if [ -d "$dep/lib64" ]; then + libraries+=("$dep/lib64") + rpaths+=("$dep/lib64") + fi +done + +# 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") + +# 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 + +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 pesky environment variables that could affect build sanity. +# +unset LD_LIBRARY_PATH +unset LD_RUN_PATH +unset DYLD_LIBRARY_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") +full_command+=("${args[@]}") + +# +# 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 + +exec "${full_command[@]}" diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py index b71c543e5d..a2fcff1f10 100644 --- a/lib/spack/spack/build_environment.py +++ b/lib/spack/spack/build_environment.py @@ -48,12 +48,11 @@ SPACK_NO_PARALLEL_MAKE = 'SPACK_NO_PARALLEL_MAKE' # 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 diff --git a/lib/spack/spack/cmd/compiler.py b/lib/spack/spack/cmd/compiler.py index ac9c844a4c..5c46a3536d 100644 --- a/lib/spack/spack/cmd/compiler.py +++ b/lib/spack/spack/cmd/compiler.py @@ -31,7 +31,7 @@ from llnl.util.lang import index_by 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" diff --git a/lib/spack/spack/compilation.py b/lib/spack/spack/compilation.py deleted file mode 100644 index 3a469376a8..0000000000 --- a/lib/spack/spack/compilation.py +++ /dev/null @@ -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 diff --git a/lib/spack/spack/compiler.py b/lib/spack/spack/compiler.py index 8debf518c7..646050d267 100644 --- a/lib/spack/spack/compiler.py +++ b/lib/spack/spack/compiler.py @@ -35,8 +35,8 @@ import spack.error 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'] diff --git a/lib/spack/spack/compilers/__init__.py b/lib/spack/spack/compilers/__init__.py index 467472cced..e572cd89b6 100644 --- a/lib/spack/spack/compilers/__init__.py +++ b/lib/spack/spack/compilers/__init__.py @@ -40,7 +40,7 @@ from spack.util.multiproc import parmap 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'] diff --git a/lib/spack/spack/test/__init__.py b/lib/spack/spack/test/__init__.py index 9eae3261c2..c6a371fd0d 100644 --- a/lib/spack/spack/test/__init__.py +++ b/lib/spack/spack/test/__init__.py @@ -53,7 +53,8 @@ test_names = ['versions', 'svn_fetch', 'hg_fetch', 'mirror', - 'url_extrapolate'] + 'url_extrapolate', + 'cc'] def list_tests(): diff --git a/lib/spack/spack/test/cc.py b/lib/spack/spack/test/cc.py new file mode 100644 index 0000000000..aa16f9b351 --- /dev/null +++ b/lib/spack/spack/test/cc.py @@ -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"])) diff --git a/lib/spack/spack/test/python_version.py b/lib/spack/spack/test/python_version.py index 04b4eadf34..f814df3226 100644 --- a/lib/spack/spack/test/python_version.py +++ b/lib/spack/spack/test/python_version.py @@ -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] diff --git a/lib/spack/spack/util/environment.py b/lib/spack/spack/util/environment.py index 435d912185..afdf51c707 100644 --- a/lib/spack/spack/util/environment.py +++ b/lib/spack/spack/util/environment.py @@ -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" |