summaryrefslogtreecommitdiff
path: root/lib/spack/env/cc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/spack/env/cc')
-rwxr-xr-xlib/spack/env/cc424
1 files changed, 291 insertions, 133 deletions
diff --git a/lib/spack/env/cc b/lib/spack/env/cc
index b06c6fd6fc..3b83291cc2 100755
--- a/lib/spack/env/cc
+++ b/lib/spack/env/cc
@@ -1,28 +1,10 @@
#!/bin/bash
-##############################################################################
-# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
-# Produced at the Lawrence Livermore National Laboratory.
#
-# This file is part of Spack.
-# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
-# LLNL-CODE-647188
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
-# For details, see https://github.com/spack/spack
-# Please also see the NOTICE and LICENSE files 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 Lesser General Public License (as
-# published by the Free Software Foundation) version 2.1, 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 Lesser 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
-##############################################################################
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
#
# Spack compiler wrapper script.
#
@@ -52,6 +34,7 @@ parameters=(
SPACK_F77_RPATH_ARG
SPACK_FC_RPATH_ARG
SPACK_SHORT_SPEC
+ SPACK_SYSTEM_DIRS
)
# The compiler input variables are checked for sanity later:
@@ -73,7 +56,31 @@ function die {
exit 1
}
-for param in ${parameters[@]}; do
+# read input parameters into proper bash arrays.
+# SYSTEM_DIRS is delimited by :
+IFS=':' read -ra SPACK_SYSTEM_DIRS <<< "${SPACK_SYSTEM_DIRS}"
+
+# SPACK_<LANG>FLAGS and SPACK_LDLIBS are split by ' '
+IFS=' ' read -ra SPACK_FFLAGS <<< "$SPACK_FFLAGS"
+IFS=' ' read -ra SPACK_CPPFLAGS <<< "$SPACK_CPPFLAGS"
+IFS=' ' read -ra SPACK_CFLAGS <<< "$SPACK_CFLAGS"
+IFS=' ' read -ra SPACK_CXXFLAGS <<< "$SPACK_CXXFLAGS"
+IFS=' ' read -ra SPACK_LDFLAGS <<< "$SPACK_LDFLAGS"
+IFS=' ' read -ra SPACK_LDLIBS <<< "$SPACK_LDLIBS"
+
+# test whether a path is a system directory
+function system_dir {
+ path="$1"
+ for sd in "${SPACK_SYSTEM_DIRS[@]}"; do
+ if [ "${path}" == "${sd}" ] || [ "${path}" == "${sd}/" ]; then
+ # success if path starts with a system prefix
+ return 0
+ fi
+ done
+ return 1 # fail if path starts no system prefix
+}
+
+for param in "${parameters[@]}"; do
if [[ -z ${!param} ]]; then
die "Spack compiler must be run from Spack! Input '$param' is missing."
fi
@@ -117,7 +124,7 @@ case "$command" in
comp="FC"
lang_flags=F
;;
- f77|gfortran|flang|ifort|pgfortran|xlf|xlf_r|nagfor|ftn)
+ f77|xlf|xlf_r|pgf77)
command="$SPACK_F77"
language="Fortran 77"
comp="F77"
@@ -136,10 +143,12 @@ esac
# libraries.
if [[ -z $mode ]] || [[ $mode == ld ]]; then
for arg in "$@"; do
- if [[ $arg == -v || $arg == -V || $arg == --version || $arg == -dumpversion ]]; then
- mode=vcheck
- break
- fi
+ case $arg in
+ -v|-V|--version|-dumpversion)
+ mode=vcheck
+ break
+ ;;
+ esac
done
fi
@@ -163,7 +172,7 @@ fi
# Set up rpath variable according to language.
eval rpath=\$SPACK_${comp}_RPATH_ARG
-# Dump the version and exit if we're in testing mode.
+# Dump the mode and exit if the command is dump-mode.
if [[ $SPACK_TEST_COMMAND == dump-mode ]]; then
echo "$mode"
exit
@@ -176,50 +185,40 @@ if [[ -z $command ]]; then
fi
#
-# Set paths as defined in the 'environment' section of the compiler config
-# names are stored in SPACK_ENV_TO_SET
-# values are stored in SPACK_ENV_SET_<varname>
-#
-IFS=':' read -ra env_set_varnames <<< "$SPACK_ENV_TO_SET"
-for varname in "${env_set_varnames[@]}"; do
- spack_varname="SPACK_ENV_SET_$varname"
- export $varname=${!spack_varname}
- unset $spack_varname
-done
-
-#
# 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=""
+export PATH=""
for dir in "${env_path[@]}"; do
addpath=true
for env_dir in "${spack_env_dirs[@]}"; do
- if [[ $dir == $env_dir ]]; then
+ if [[ "$dir" == "$env_dir" ]]; then
addpath=false
break
fi
done
if $addpath; then
- PATH="${PATH:+$PATH:}$dir"
+ export PATH="${PATH:+$PATH:}$dir"
fi
done
-export PATH
if [[ $mode == vcheck ]]; then
- exec ${command} "$@"
+ exec "${command}" "$@"
fi
# Darwin's linker has a -r argument that merges object files together.
# It doesn't work with -rpath.
# This variable controls whether they are added.
add_rpaths=true
-if [[ ($mode == ld || $mode == ccld) && "$SPACK_SHORT_SPEC" =~ "darwin" ]]; then
+if [[ ($mode == ld || $mode == ccld) && "$SPACK_SHORT_SPEC" =~ "darwin" ]];
+then
for arg in "$@"; do
- if [[ ($arg == -r && $mode == ld) || ($arg == -r && $mode == ccld) || ($arg == -Wl,-r && $mode == ccld) ]]; then
+ if [[ ($arg == -r && $mode == ld) ||
+ ($arg == -r && $mode == ccld) ||
+ ($arg == -Wl,-r && $mode == ccld) ]]; then
add_rpaths=false
break
fi
@@ -227,126 +226,285 @@ if [[ ($mode == ld || $mode == ccld) && "$SPACK_SHORT_SPEC" =~ "darwin" ]]; then
fi
# Save original command for debug logging
-input_command="$@"
-args=("$@")
+input_command="$*"
+
+#
+# Parse the command line arguments.
+#
+# We extract -L, -I, and -Wl,-rpath arguments from the command line and
+# recombine them with Spack arguments later. We parse these out so that
+# we can make sure that system paths come last, that package arguments
+# come first, and that Spack arguments are injected properly.
+#
+# All other arguments, including -l arguments, are treated as
+# 'other_args' and left in their original order. This ensures that
+# --start-group, --end-group, and other order-sensitive flags continue to
+# work as the caller expects.
+#
+# The libs variable is initialized here for completeness, and it is also
+# used later to inject flags supplied via `ldlibs` on the command
+# line. These come into the wrappers via SPACK_LDLIBS.
+#
+includes=()
+libdirs=()
+rpaths=()
+system_includes=()
+system_libdirs=()
+system_rpaths=()
+libs=()
+other_args=()
-# Prepend cppflags, cflags, cxxflags, fcflags, fflags, and ldflags
+while [ -n "$1" ]; do
+ # an RPATH to be added after the case statement.
+ rp=""
-# Add ldflags
+ case "$1" in
+ -I*)
+ arg="${1#-I}"
+ if [ -z "$arg" ]; then shift; arg="$1"; fi
+ if system_dir "$arg"; then
+ system_includes+=("$arg")
+ else
+ includes+=("$arg")
+ fi
+ ;;
+ -L*)
+ arg="${1#-L}"
+ if [ -z "$arg" ]; then shift; arg="$1"; fi
+ if system_dir "$arg"; then
+ system_libdirs+=("$arg")
+ else
+ libdirs+=("$arg")
+ fi
+ ;;
+ -l*)
+ arg="${1#-l}"
+ if [ -z "$arg" ]; then shift; arg="$1"; fi
+ other_args+=("-l$arg")
+ ;;
+ -Wl,*)
+ arg="${1#-Wl,}"
+ if [ -z "$arg" ]; then shift; arg="$1"; fi
+ if [[ "$arg" = -rpath=* ]]; then
+ rp="${arg#-rpath=}"
+ elif [[ "$arg" = -rpath,* ]]; then
+ rp="${arg#-rpath,}"
+ elif [[ "$arg" = -rpath ]]; then
+ shift; arg="$1"
+ if [[ "$arg" != -Wl,* ]]; then
+ die "-Wl,-rpath was not followed by -Wl,*"
+ fi
+ rp="${arg#-Wl,}"
+ else
+ other_args+=("-Wl,$arg")
+ fi
+ ;;
+ -Xlinker,*)
+ arg="${1#-Xlinker,}"
+ if [ -z "$arg" ]; then shift; arg="$1"; fi
+ if [[ "$arg" = -rpath=* ]]; then
+ rp="${arg#-rpath=}"
+ elif [[ "$arg" = -rpath ]]; then
+ shift; arg="$1"
+ if [[ "$arg" != -Xlinker,* ]]; then
+ die "-Xlinker,-rpath was not followed by -Xlinker,*"
+ fi
+ rp="${arg#-Xlinker,}"
+ else
+ other_args+=("-Xlinker,$arg")
+ fi
+ ;;
+ -Xlinker)
+ if [[ "$2" == "-rpath" ]]; then
+ if [[ "$3" != "-Xlinker" ]]; then
+ die "-Xlinker,-rpath was not followed by -Xlinker,*"
+ fi
+ shift 3;
+ rp="$1"
+ else
+ other_args+=("$1")
+ fi
+ ;;
+ *)
+ other_args+=("$1")
+ ;;
+ esac
+
+ # test rpaths against system directories in one place.
+ if [ -n "$rp" ]; then
+ if system_dir "$rp"; then
+ system_rpaths+=("$rp")
+ else
+ rpaths+=("$rp")
+ fi
+ fi
+ shift
+done
+
+#
+# Add flags from Spack's cppflags, cflags, cxxflags, fcflags, fflags, and
+# ldflags. We stick to the order that gmake puts the flags in by default.
+#
+# See the gmake manual on implicit rules for details:
+# https://www.gnu.org/software/make/manual/html_node/Implicit-Variables.html
+#
+flags=()
+
+# Fortran flags come before CPPFLAGS
case "$mode" in
- ld|ccld)
- args=(${SPACK_LDFLAGS[@]} "${args[@]}") ;;
+ cc|ccld)
+ case $lang_flags in
+ F)
+ flags=("${flags[@]}" "${SPACK_FFLAGS[@]}") ;;
+ esac
+ ;;
+esac
+
+# C preprocessor flags come before any C/CXX flags
+case "$mode" in
+ cpp|as|cc|ccld)
+ flags=("${flags[@]}" "${SPACK_CPPFLAGS[@]}") ;;
esac
-# Add compiler flags.
+
+# Add C and C++ flags
case "$mode" in
cc|ccld)
- # Add c, cxx, fc, and f flags
case $lang_flags in
C)
- args=(${SPACK_CFLAGS[@]} "${args[@]}") ;;
+ flags=("${flags[@]}" "${SPACK_CFLAGS[@]}") ;;
CXX)
- args=(${SPACK_CXXFLAGS[@]} "${args[@]}") ;;
+ flags=("${flags[@]}" "${SPACK_CXXFLAGS[@]}") ;;
esac
;;
esac
-# Add cppflags
+# Linker flags
case "$mode" in
- cpp|as|cc|ccld)
- args=(${SPACK_CPPFLAGS[@]} "${args[@]}") ;;
+ ld|ccld)
+ flags=("${flags[@]}" "${SPACK_LDFLAGS[@]}") ;;
esac
-case "$mode" in cc|ccld)
- # Add fortran flags
- case $lang_flags in
- F)
- args=(${SPACK_FFLAGS[@]} "${args[@]}") ;;
- esac
+
+# Include the package's prefix/lib[64] dirs in rpath. We don't know until
+# *after* installation which one's correct, so we include both lib and
+# lib64, assuming that only one will be present.
+case "$mode" in
+ ld|ccld)
+ $add_rpaths && rpaths+=("$SPACK_PREFIX/lib")
+ $add_rpaths && rpaths+=("$SPACK_PREFIX/lib64")
;;
esac
-# Read spack dependencies from the path environment variable
+# Read spack dependencies from the environment. This is a list of prefixes.
IFS=':' read -ra deps <<< "$SPACK_DEPENDENCIES"
for dep in "${deps[@]}"; do
- # Prepend include directories
- if [[ -d $dep/include ]]; then
- if [[ $mode == cpp || $mode == cc || $mode == as || $mode == ccld ]]; then
- args=("-I$dep/include" "${args[@]}")
- fi
- fi
-
- # Prepend lib and RPATH directories
- if [[ -d $dep/lib ]]; then
- if [[ $mode == ccld ]]; then
- if [[ $SPACK_RPATH_DEPS == *$dep* ]]; then
- $add_rpaths && args=("$rpath$dep/lib" "${args[@]}")
- fi
- if [[ $SPACK_LINK_DEPS == *$dep* ]]; then
- args=("-L$dep/lib" "${args[@]}")
- fi
- elif [[ $mode == ld ]]; then
- if [[ $SPACK_RPATH_DEPS == *$dep* ]]; then
- $add_rpaths && args=("-rpath" "$dep/lib" "${args[@]}")
+ # Append include directories in any compilation mode
+ case "$mode" in
+ cpp|cc|as|ccld)
+ if [[ -d $dep/include ]]; then
+ includes=("${includes[@]}" "$dep/include")
fi
- if [[ $SPACK_LINK_DEPS == *$dep* ]]; then
- args=("-L$dep/lib" "${args[@]}")
- fi
- fi
- fi
+ ;;
+ esac
- # Prepend lib64 and RPATH directories
- if [[ -d $dep/lib64 ]]; then
- if [[ $mode == ccld ]]; then
- if [[ $SPACK_RPATH_DEPS == *$dep* ]]; then
- $add_rpaths && args=("$rpath$dep/lib64" "${args[@]}")
+ # Append lib/lib64 and RPATH directories, but only if we're linking
+ case "$mode" in
+ ld|ccld)
+ if [[ -d $dep/lib ]]; then
+ if [[ $SPACK_RPATH_DEPS == *$dep* ]]; then
+ $add_rpaths && rpaths=("${rpaths[@]}" "$dep/lib")
+ fi
+ if [[ $SPACK_LINK_DEPS == *$dep* ]]; then
+ libdirs=("${libdirs[@]}" "$dep/lib")
+ fi
fi
- if [[ $SPACK_LINK_DEPS == *$dep* ]]; then
- args=("-L$dep/lib64" "${args[@]}")
- fi
- elif [[ $mode == ld ]]; then
- if [[ $SPACK_RPATH_DEPS == *$dep* ]]; then
- $add_rpaths && args=("-rpath" "$dep/lib64" "${args[@]}")
- fi
- if [[ $SPACK_LINK_DEPS == *$dep* ]]; then
- args=("-L$dep/lib64" "${args[@]}")
+
+ if [[ -d $dep/lib64 ]]; then
+ if [[ $SPACK_RPATH_DEPS == *$dep* ]]; then
+ $add_rpaths && rpaths+=("$dep/lib64")
+ fi
+ if [[ $SPACK_LINK_DEPS == *$dep* ]]; then
+ libdirs+=("$dep/lib64")
+ fi
fi
- fi
- fi
+ ;;
+ esac
done
-# Include all -L's and prefix/whatever dirs in rpath
-if [[ $mode == ccld ]]; then
- $add_rpaths && args=("$rpath$SPACK_PREFIX/lib64" "${args[@]}")
- $add_rpaths && args=("$rpath$SPACK_PREFIX/lib" "${args[@]}")
-elif [[ $mode == ld ]]; then
- $add_rpaths && args=("-rpath" "$SPACK_PREFIX/lib64" "${args[@]}")
- $add_rpaths && args=("-rpath" "$SPACK_PREFIX/lib" "${args[@]}")
-fi
+# add RPATHs if we're in in any linking mode
+case "$mode" in
+ ld|ccld)
+ # Set extra RPATHs
+ IFS=':' read -ra extra_rpaths <<< "$SPACK_COMPILER_EXTRA_RPATHS"
+ for extra_rpath in "${extra_rpaths[@]}"; do
+ $add_rpaths && rpaths+=("$extra_rpath")
+ libdirs+=("$extra_rpath")
+ done
-# Set extra RPATHs
-IFS=':' read -ra extra_rpaths <<< "$SPACK_COMPILER_EXTRA_RPATHS"
-for extra_rpath in "${extra_rpaths[@]}"; do
- if [[ $mode == ccld ]]; then
- $add_rpaths && args=("$rpath$extra_rpath" "${args[@]}")
- args=("-L$extra_rpath" "${args[@]}")
- elif [[ $mode == ld ]]; then
- $add_rpaths && args=("-rpath" "$extra_rpath" "${args[@]}")
- args=("-L$extra_rpath" "${args[@]}")
- fi
-done
+ # Add SPACK_LDLIBS to args
+ for lib in "${SPACK_LDLIBS[@]}"; do
+ libs+=("${lib#-l}")
+ done
+ ;;
+esac
+
+#
+# Finally, reassemble the command line.
+#
+
+# Includes and system includes first
+args=()
+
+# flags assembled earlier
+args+=("${flags[@]}")
-# Add SPACK_LDLIBS to args
+# include directory search paths
+for dir in "${includes[@]}"; do args+=("-I$dir"); done
+for dir in "${system_includes[@]}"; do args+=("-I$dir"); done
+
+# Library search paths
+for dir in "${libdirs[@]}"; do args+=("-L$dir"); done
+for dir in "${system_libdirs[@]}"; do args+=("-L$dir"); done
+
+# RPATHs arguments
case "$mode" in
- ld|ccld)
- args=("${args[@]}" ${SPACK_LDLIBS[@]}) ;;
+ ccld)
+ for dir in "${rpaths[@]}"; do args+=("$rpath$dir"); done
+ for dir in "${system_rpaths[@]}"; do args+=("$rpath$dir"); done
+ ;;
+ ld)
+ for dir in "${rpaths[@]}"; do args+=("-rpath" "$dir"); done
+ for dir in "${system_rpaths[@]}"; do args+=("-rpath" "$dir"); done
+ ;;
esac
+# Other arguments from the input command
+args+=("${other_args[@]}")
+
+# Inject SPACK_LDLIBS, if supplied
+for lib in "${libs[@]}"; do
+ args+=("-l$lib");
+done
+
full_command=("$command" "${args[@]}")
-# In test command mode, write out full command for Spack tests.
+# prepend the ccache binary if we're using ccache
+if [ -n "$SPACK_CCACHE_BINARY" ]; then
+ case "$lang_flags" in
+ C|CXX) # ccache only supports C languages
+ full_command=("${SPACK_CCACHE_BINARY}" "${full_command[@]}")
+ # workaround for stage being a temp folder
+ # see #3761#issuecomment-294352232
+ export CCACHE_NOHASHDIR=yes
+ ;;
+ esac
+fi
+
+# dump the full command if the caller supplies SPACK_TEST_COMMAND=dump-args
if [[ $SPACK_TEST_COMMAND == dump-args ]]; then
- echo "${full_command[@]}"
+ IFS="
+" && echo "${full_command[*]}"
exit
elif [[ -n $SPACK_TEST_COMMAND ]]; then
die "ERROR: Unknown test command"
@@ -359,7 +517,7 @@ if [[ $SPACK_DEBUG == TRUE ]]; then
input_log="$SPACK_DEBUG_LOG_DIR/spack-cc-$SPACK_DEBUG_LOG_ID.in.log"
output_log="$SPACK_DEBUG_LOG_DIR/spack-cc-$SPACK_DEBUG_LOG_ID.out.log"
echo "[$mode] $command $input_command" >> "$input_log"
- echo "[$mode] ${full_command[@]}" >> "$output_log"
+ echo "[$mode] ${full_command[*]}" >> "$output_log"
fi
exec "${full_command[@]}"