spack/lib/spack/env/cc

568 lines
16 KiB
Plaintext
Raw Normal View History

#!/bin/bash
#
# Copyright 2013-2020 Lawrence Livermore National Security, LLC and other
# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
#
# 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 and/or -isystem arguments for dependency /include directories.
# -L arguments for dependency /lib directories.
# -Wl,-rpath arguments for dependency /lib directories.
#
# This is an array of environment variables that need to be set before
2016-04-05 04:00:09 +08:00
# the script runs. They are set by routines in spack.build_environment
# as part of spack.package.Package.do_install().
parameters=(
SPACK_ENV_PATH
SPACK_DEBUG_LOG_DIR
SPACK_DEBUG_LOG_ID
SPACK_COMPILER_SPEC
SPACK_CC_RPATH_ARG
SPACK_CXX_RPATH_ARG
SPACK_F77_RPATH_ARG
SPACK_FC_RPATH_ARG
SPACK_TARGET_ARGS
SPACK_DTAGS_TO_ADD
SPACK_DTAGS_TO_STRIP
SPACK_LINKER_ARG
SPACK_SHORT_SPEC
Restore cc: package search paths come before dependency paths (#4692) Spack currently prepends include paths, library paths, and rpaths to the compile line. This causes problems when a header or library in the package has the same name as one exported by one of its dependencies. The *dependency's* header will be preferred over the package's, which is not what most builds expect. This also breaks some of our production codes. This restores the original cc behavior (from *very* early Spack) of parsing compiler arguments out by type (`-L`, `-I`, `-Wl,-rpath`) and reconstituting the full command at the end. `<includes> <other_args> <library dirs> <rpaths>` This differs from the original behavior in one significant way, though: it *appends* the library arguments so that dependency libraries do not shadow those in the build. This is safe because semantics aren't affected by *interleaving* `-I`, `-L`, and `-Wl,-rpath` arguments with others, only with each other (so the order of two `-L` args affects the search path, but we search for all libraries on the command line using the same search path). We preserve the following: 1. Any system directory in the paths will be listed last. 2. The root package's include/library/RPATH flags come before flags of the same type for any dependency. 3. Order will be preserved within flags passed by the build (except system paths, which are moved to be last) 4. Flags for dependencies will appear between the root flags and the system flags, and the flags for any dependency will come before those for *its* dependencies (this is for completeness -- we already guarantee this in `build_environment.py`)
2018-08-05 12:30:17 +08:00
SPACK_SYSTEM_DIRS
)
# The compiler input variables are checked for sanity later:
# SPACK_CC, SPACK_CXX, SPACK_F77, SPACK_FC
# The default compiler flags are passed from these variables:
# SPACK_CFLAGS, SPACK_CXXFLAGS, SPACK_FFLAGS,
# SPACK_LDFLAGS, SPACK_LDLIBS
# Debug env var is optional; set to "TRUE" for debug logging:
# SPACK_DEBUG
# Test command is used to unit test the compiler script.
# SPACK_TEST_COMMAND
# die()
# Prints a message and exits with error 1.
function die {
echo "$@"
exit 1
}
# 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+x} ]]; then
2016-04-05 19:42:23 +08:00
die "Spack compiler must be run from Spack! Input '$param' is 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:
2016-04-05 04:00:09 +08:00
# vcheck version check
2016-03-18 09:53:13 +08:00
# cpp preprocess
# cc compile
2016-03-18 09:53:13 +08:00
# as assemble
# ld link
# ccld compile & link
command=$(basename "$0")
comp="CC"
case "$command" in
2016-04-05 02:33:48 +08:00
cpp)
mode=cpp
;;
cc|c89|c99|gcc|clang|armclang|icc|pgcc|xlc|xlc_r|fcc)
command="$SPACK_CC"
language="C"
comp="CC"
lang_flags=C
;;
c++|CC|g++|clang++|armclang++|icpc|pgc++|xlc++|xlc++_r|FCC)
command="$SPACK_CXX"
language="C++"
comp="CXX"
lang_flags=CXX
;;
ftn|f90|fc|f95|gfortran|flang|armflang|ifort|pgfortran|xlf90|xlf90_r|nagfor|frt)
command="$SPACK_FC"
language="Fortran 90"
comp="FC"
lang_flags=F
;;
f77|xlf|xlf_r|pgf77|frt)
command="$SPACK_F77"
language="Fortran 77"
comp="F77"
lang_flags=F
;;
ld)
mode=ld
;;
*)
2019-04-10 07:36:45 +08:00
die "Unknown compiler: $command"
;;
esac
2016-04-05 04:00:09 +08:00
# If any of the arguments below are present, then the mode is vcheck.
# In vcheck mode, nothing is added in terms of extra search paths or
2016-04-05 02:33:48 +08:00
# libraries.
if [[ -z $mode ]] || [[ $mode == ld ]]; then
for arg in "$@"; do
case $arg in
-v|-V|--version|-dumpversion)
mode=vcheck
break
;;
esac
done
fi
# Finish setting up the mode.
2016-04-05 02:33:48 +08:00
if [[ -z $mode ]]; then
mode=ccld
for arg in "$@"; do
2016-04-05 03:38:21 +08:00
if [[ $arg == -E ]]; then
mode=cpp
break
2016-04-05 03:38:21 +08:00
elif [[ $arg == -S ]]; then
2016-03-18 09:53:13 +08:00
mode=as
break
2016-04-05 03:38:21 +08:00
elif [[ $arg == -c ]]; then
mode=cc
break
fi
done
fi
# This is needed to ensure we set RPATH instead of RUNPATH
# (or the opposite, depending on the configuration in config.yaml)
#
# Documentation on this mechanism is lacking at best. A few sources
# of information are (note that some of them take explicitly the
# opposite stance that Spack does):
#
# http://blog.qt.io/blog/2011/10/28/rpath-and-runpath/
# https://wiki.debian.org/RpathIssue
#
# The only discussion I could find on enabling new dynamic tags by
# default on ld is the following:
#
# https://sourceware.org/ml/binutils/2013-01/msg00307.html
#
dtags_to_add="${SPACK_DTAGS_TO_ADD}"
dtags_to_strip="${SPACK_DTAGS_TO_STRIP}"
linker_arg="${SPACK_LINKER_ARG}"
# Set up rpath variable according to language.
eval rpath=\$SPACK_${comp}_RPATH_ARG
# Dump the mode and exit if the command is dump-mode.
2016-04-05 03:38:21 +08:00
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.
2016-03-18 09:53:13 +08:00
if [[ -z $command ]]; then
die "ERROR: Compiler '$SPACK_COMPILER_SPEC' does not support compiling $language programs."
fi
2016-05-19 07:50:50 +08:00
#
# 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+=("" ".")
export PATH=""
2016-05-19 07:50:50 +08:00
for dir in "${env_path[@]}"; do
addpath=true
for env_dir in "${spack_env_dirs[@]}"; do
if [[ "$dir" == "$env_dir" ]]; then
2016-05-19 07:50:50 +08:00
addpath=false
break
fi
done
if $addpath; then
export PATH="${PATH:+$PATH:}$dir"
2016-05-19 07:50:50 +08:00
fi
done
2016-04-05 02:33:48 +08:00
if [[ $mode == vcheck ]]; then
exec "${command}" "$@"
2016-03-18 09:53:13 +08:00
fi
2016-04-05 02:33:48 +08:00
# 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
2016-04-05 02:33:48 +08:00
for arg in "$@"; do
if [[ ($arg == -r && $mode == ld) ||
($arg == -r && $mode == ccld) ||
($arg == -Wl,-r && $mode == ccld) ]]; then
2016-04-05 02:33:48 +08:00
add_rpaths=false
break
2016-04-05 03:38:21 +08:00
fi
2016-04-05 02:33:48 +08:00
done
fi
# Save original command for debug logging
input_command="$*"
Restore cc: package search paths come before dependency paths (#4692) Spack currently prepends include paths, library paths, and rpaths to the compile line. This causes problems when a header or library in the package has the same name as one exported by one of its dependencies. The *dependency's* header will be preferred over the package's, which is not what most builds expect. This also breaks some of our production codes. This restores the original cc behavior (from *very* early Spack) of parsing compiler arguments out by type (`-L`, `-I`, `-Wl,-rpath`) and reconstituting the full command at the end. `<includes> <other_args> <library dirs> <rpaths>` This differs from the original behavior in one significant way, though: it *appends* the library arguments so that dependency libraries do not shadow those in the build. This is safe because semantics aren't affected by *interleaving* `-I`, `-L`, and `-Wl,-rpath` arguments with others, only with each other (so the order of two `-L` args affects the search path, but we search for all libraries on the command line using the same search path). We preserve the following: 1. Any system directory in the paths will be listed last. 2. The root package's include/library/RPATH flags come before flags of the same type for any dependency. 3. Order will be preserved within flags passed by the build (except system paths, which are moved to be last) 4. Flags for dependencies will appear between the root flags and the system flags, and the flags for any dependency will come before those for *its* dependencies (this is for completeness -- we already guarantee this in `build_environment.py`)
2018-08-05 12:30:17 +08:00
#
# Parse the command line arguments.
#
# We extract -L, -I, -isystem 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.
Restore cc: package search paths come before dependency paths (#4692) Spack currently prepends include paths, library paths, and rpaths to the compile line. This causes problems when a header or library in the package has the same name as one exported by one of its dependencies. The *dependency's* header will be preferred over the package's, which is not what most builds expect. This also breaks some of our production codes. This restores the original cc behavior (from *very* early Spack) of parsing compiler arguments out by type (`-L`, `-I`, `-Wl,-rpath`) and reconstituting the full command at the end. `<includes> <other_args> <library dirs> <rpaths>` This differs from the original behavior in one significant way, though: it *appends* the library arguments so that dependency libraries do not shadow those in the build. This is safe because semantics aren't affected by *interleaving* `-I`, `-L`, and `-Wl,-rpath` arguments with others, only with each other (so the order of two `-L` args affects the search path, but we search for all libraries on the command line using the same search path). We preserve the following: 1. Any system directory in the paths will be listed last. 2. The root package's include/library/RPATH flags come before flags of the same type for any dependency. 3. Order will be preserved within flags passed by the build (except system paths, which are moved to be last) 4. Flags for dependencies will appear between the root flags and the system flags, and the flags for any dependency will come before those for *its* dependencies (this is for completeness -- we already guarantee this in `build_environment.py`)
2018-08-05 12:30:17 +08:00
#
# 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.
Restore cc: package search paths come before dependency paths (#4692) Spack currently prepends include paths, library paths, and rpaths to the compile line. This causes problems when a header or library in the package has the same name as one exported by one of its dependencies. The *dependency's* header will be preferred over the package's, which is not what most builds expect. This also breaks some of our production codes. This restores the original cc behavior (from *very* early Spack) of parsing compiler arguments out by type (`-L`, `-I`, `-Wl,-rpath`) and reconstituting the full command at the end. `<includes> <other_args> <library dirs> <rpaths>` This differs from the original behavior in one significant way, though: it *appends* the library arguments so that dependency libraries do not shadow those in the build. This is safe because semantics aren't affected by *interleaving* `-I`, `-L`, and `-Wl,-rpath` arguments with others, only with each other (so the order of two `-L` args affects the search path, but we search for all libraries on the command line using the same search path). We preserve the following: 1. Any system directory in the paths will be listed last. 2. The root package's include/library/RPATH flags come before flags of the same type for any dependency. 3. Order will be preserved within flags passed by the build (except system paths, which are moved to be last) 4. Flags for dependencies will appear between the root flags and the system flags, and the flags for any dependency will come before those for *its* dependencies (this is for completeness -- we already guarantee this in `build_environment.py`)
2018-08-05 12:30:17 +08:00
#
# 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.
Restore cc: package search paths come before dependency paths (#4692) Spack currently prepends include paths, library paths, and rpaths to the compile line. This causes problems when a header or library in the package has the same name as one exported by one of its dependencies. The *dependency's* header will be preferred over the package's, which is not what most builds expect. This also breaks some of our production codes. This restores the original cc behavior (from *very* early Spack) of parsing compiler arguments out by type (`-L`, `-I`, `-Wl,-rpath`) and reconstituting the full command at the end. `<includes> <other_args> <library dirs> <rpaths>` This differs from the original behavior in one significant way, though: it *appends* the library arguments so that dependency libraries do not shadow those in the build. This is safe because semantics aren't affected by *interleaving* `-I`, `-L`, and `-Wl,-rpath` arguments with others, only with each other (so the order of two `-L` args affects the search path, but we search for all libraries on the command line using the same search path). We preserve the following: 1. Any system directory in the paths will be listed last. 2. The root package's include/library/RPATH flags come before flags of the same type for any dependency. 3. Order will be preserved within flags passed by the build (except system paths, which are moved to be last) 4. Flags for dependencies will appear between the root flags and the system flags, and the flags for any dependency will come before those for *its* dependencies (this is for completeness -- we already guarantee this in `build_environment.py`)
2018-08-05 12:30:17 +08:00
#
includes=()
libdirs=()
rpaths=()
system_includes=()
system_libdirs=()
system_rpaths=()
libs=()
Restore cc: package search paths come before dependency paths (#4692) Spack currently prepends include paths, library paths, and rpaths to the compile line. This causes problems when a header or library in the package has the same name as one exported by one of its dependencies. The *dependency's* header will be preferred over the package's, which is not what most builds expect. This also breaks some of our production codes. This restores the original cc behavior (from *very* early Spack) of parsing compiler arguments out by type (`-L`, `-I`, `-Wl,-rpath`) and reconstituting the full command at the end. `<includes> <other_args> <library dirs> <rpaths>` This differs from the original behavior in one significant way, though: it *appends* the library arguments so that dependency libraries do not shadow those in the build. This is safe because semantics aren't affected by *interleaving* `-I`, `-L`, and `-Wl,-rpath` arguments with others, only with each other (so the order of two `-L` args affects the search path, but we search for all libraries on the command line using the same search path). We preserve the following: 1. Any system directory in the paths will be listed last. 2. The root package's include/library/RPATH flags come before flags of the same type for any dependency. 3. Order will be preserved within flags passed by the build (except system paths, which are moved to be last) 4. Flags for dependencies will appear between the root flags and the system flags, and the flags for any dependency will come before those for *its* dependencies (this is for completeness -- we already guarantee this in `build_environment.py`)
2018-08-05 12:30:17 +08:00
other_args=()
isystem_system_includes=()
isystem_includes=()
Restore cc: package search paths come before dependency paths (#4692) Spack currently prepends include paths, library paths, and rpaths to the compile line. This causes problems when a header or library in the package has the same name as one exported by one of its dependencies. The *dependency's* header will be preferred over the package's, which is not what most builds expect. This also breaks some of our production codes. This restores the original cc behavior (from *very* early Spack) of parsing compiler arguments out by type (`-L`, `-I`, `-Wl,-rpath`) and reconstituting the full command at the end. `<includes> <other_args> <library dirs> <rpaths>` This differs from the original behavior in one significant way, though: it *appends* the library arguments so that dependency libraries do not shadow those in the build. This is safe because semantics aren't affected by *interleaving* `-I`, `-L`, and `-Wl,-rpath` arguments with others, only with each other (so the order of two `-L` args affects the search path, but we search for all libraries on the command line using the same search path). We preserve the following: 1. Any system directory in the paths will be listed last. 2. The root package's include/library/RPATH flags come before flags of the same type for any dependency. 3. Order will be preserved within flags passed by the build (except system paths, which are moved to be last) 4. Flags for dependencies will appear between the root flags and the system flags, and the flags for any dependency will come before those for *its* dependencies (this is for completeness -- we already guarantee this in `build_environment.py`)
2018-08-05 12:30:17 +08:00
while [ -n "$1" ]; do
# an RPATH to be added after the case statement.
rp=""
Restore cc: package search paths come before dependency paths (#4692) Spack currently prepends include paths, library paths, and rpaths to the compile line. This causes problems when a header or library in the package has the same name as one exported by one of its dependencies. The *dependency's* header will be preferred over the package's, which is not what most builds expect. This also breaks some of our production codes. This restores the original cc behavior (from *very* early Spack) of parsing compiler arguments out by type (`-L`, `-I`, `-Wl,-rpath`) and reconstituting the full command at the end. `<includes> <other_args> <library dirs> <rpaths>` This differs from the original behavior in one significant way, though: it *appends* the library arguments so that dependency libraries do not shadow those in the build. This is safe because semantics aren't affected by *interleaving* `-I`, `-L`, and `-Wl,-rpath` arguments with others, only with each other (so the order of two `-L` args affects the search path, but we search for all libraries on the command line using the same search path). We preserve the following: 1. Any system directory in the paths will be listed last. 2. The root package's include/library/RPATH flags come before flags of the same type for any dependency. 3. Order will be preserved within flags passed by the build (except system paths, which are moved to be last) 4. Flags for dependencies will appear between the root flags and the system flags, and the flags for any dependency will come before those for *its* dependencies (this is for completeness -- we already guarantee this in `build_environment.py`)
2018-08-05 12:30:17 +08:00
case "$1" in
-isystem*)
arg="${1#-isystem}"
isystem_was_used=true
if [ -z "$arg" ]; then shift; arg="$1"; fi
if system_dir "$arg"; then
isystem_system_includes+=("$arg")
else
isystem_includes+=("$arg")
fi
;;
Restore cc: package search paths come before dependency paths (#4692) Spack currently prepends include paths, library paths, and rpaths to the compile line. This causes problems when a header or library in the package has the same name as one exported by one of its dependencies. The *dependency's* header will be preferred over the package's, which is not what most builds expect. This also breaks some of our production codes. This restores the original cc behavior (from *very* early Spack) of parsing compiler arguments out by type (`-L`, `-I`, `-Wl,-rpath`) and reconstituting the full command at the end. `<includes> <other_args> <library dirs> <rpaths>` This differs from the original behavior in one significant way, though: it *appends* the library arguments so that dependency libraries do not shadow those in the build. This is safe because semantics aren't affected by *interleaving* `-I`, `-L`, and `-Wl,-rpath` arguments with others, only with each other (so the order of two `-L` args affects the search path, but we search for all libraries on the command line using the same search path). We preserve the following: 1. Any system directory in the paths will be listed last. 2. The root package's include/library/RPATH flags come before flags of the same type for any dependency. 3. Order will be preserved within flags passed by the build (except system paths, which are moved to be last) 4. Flags for dependencies will appear between the root flags and the system flags, and the flags for any dependency will come before those for *its* dependencies (this is for completeness -- we already guarantee this in `build_environment.py`)
2018-08-05 12:30:17 +08:00
-I*)
arg="${1#-I}"
if [ -z "$arg" ]; then shift; arg="$1"; fi
if system_dir "$arg"; then
system_includes+=("$arg")
else
includes+=("$arg")
fi
Restore cc: package search paths come before dependency paths (#4692) Spack currently prepends include paths, library paths, and rpaths to the compile line. This causes problems when a header or library in the package has the same name as one exported by one of its dependencies. The *dependency's* header will be preferred over the package's, which is not what most builds expect. This also breaks some of our production codes. This restores the original cc behavior (from *very* early Spack) of parsing compiler arguments out by type (`-L`, `-I`, `-Wl,-rpath`) and reconstituting the full command at the end. `<includes> <other_args> <library dirs> <rpaths>` This differs from the original behavior in one significant way, though: it *appends* the library arguments so that dependency libraries do not shadow those in the build. This is safe because semantics aren't affected by *interleaving* `-I`, `-L`, and `-Wl,-rpath` arguments with others, only with each other (so the order of two `-L` args affects the search path, but we search for all libraries on the command line using the same search path). We preserve the following: 1. Any system directory in the paths will be listed last. 2. The root package's include/library/RPATH flags come before flags of the same type for any dependency. 3. Order will be preserved within flags passed by the build (except system paths, which are moved to be last) 4. Flags for dependencies will appear between the root flags and the system flags, and the flags for any dependency will come before those for *its* dependencies (this is for completeness -- we already guarantee this in `build_environment.py`)
2018-08-05 12:30:17 +08:00
;;
-L*)
arg="${1#-L}"
if [ -z "$arg" ]; then shift; arg="$1"; fi
if system_dir "$arg"; then
system_libdirs+=("$arg")
else
libdirs+=("$arg")
fi
Restore cc: package search paths come before dependency paths (#4692) Spack currently prepends include paths, library paths, and rpaths to the compile line. This causes problems when a header or library in the package has the same name as one exported by one of its dependencies. The *dependency's* header will be preferred over the package's, which is not what most builds expect. This also breaks some of our production codes. This restores the original cc behavior (from *very* early Spack) of parsing compiler arguments out by type (`-L`, `-I`, `-Wl,-rpath`) and reconstituting the full command at the end. `<includes> <other_args> <library dirs> <rpaths>` This differs from the original behavior in one significant way, though: it *appends* the library arguments so that dependency libraries do not shadow those in the build. This is safe because semantics aren't affected by *interleaving* `-I`, `-L`, and `-Wl,-rpath` arguments with others, only with each other (so the order of two `-L` args affects the search path, but we search for all libraries on the command line using the same search path). We preserve the following: 1. Any system directory in the paths will be listed last. 2. The root package's include/library/RPATH flags come before flags of the same type for any dependency. 3. Order will be preserved within flags passed by the build (except system paths, which are moved to be last) 4. Flags for dependencies will appear between the root flags and the system flags, and the flags for any dependency will come before those for *its* dependencies (this is for completeness -- we already guarantee this in `build_environment.py`)
2018-08-05 12:30:17 +08:00
;;
-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,}"
Restore cc: package search paths come before dependency paths (#4692) Spack currently prepends include paths, library paths, and rpaths to the compile line. This causes problems when a header or library in the package has the same name as one exported by one of its dependencies. The *dependency's* header will be preferred over the package's, which is not what most builds expect. This also breaks some of our production codes. This restores the original cc behavior (from *very* early Spack) of parsing compiler arguments out by type (`-L`, `-I`, `-Wl,-rpath`) and reconstituting the full command at the end. `<includes> <other_args> <library dirs> <rpaths>` This differs from the original behavior in one significant way, though: it *appends* the library arguments so that dependency libraries do not shadow those in the build. This is safe because semantics aren't affected by *interleaving* `-I`, `-L`, and `-Wl,-rpath` arguments with others, only with each other (so the order of two `-L` args affects the search path, but we search for all libraries on the command line using the same search path). We preserve the following: 1. Any system directory in the paths will be listed last. 2. The root package's include/library/RPATH flags come before flags of the same type for any dependency. 3. Order will be preserved within flags passed by the build (except system paths, which are moved to be last) 4. Flags for dependencies will appear between the root flags and the system flags, and the flags for any dependency will come before those for *its* dependencies (this is for completeness -- we already guarantee this in `build_environment.py`)
2018-08-05 12:30:17 +08:00
elif [[ "$arg" = -rpath ]]; then
shift; arg="$1"
if [[ "$arg" != -Wl,* ]]; then
die "-Wl,-rpath was not followed by -Wl,*"
fi
rp="${arg#-Wl,}"
elif [[ "$arg" = "$dtags_to_strip" ]] ; then
: # We want to remove explicitly this flag
Restore cc: package search paths come before dependency paths (#4692) Spack currently prepends include paths, library paths, and rpaths to the compile line. This causes problems when a header or library in the package has the same name as one exported by one of its dependencies. The *dependency's* header will be preferred over the package's, which is not what most builds expect. This also breaks some of our production codes. This restores the original cc behavior (from *very* early Spack) of parsing compiler arguments out by type (`-L`, `-I`, `-Wl,-rpath`) and reconstituting the full command at the end. `<includes> <other_args> <library dirs> <rpaths>` This differs from the original behavior in one significant way, though: it *appends* the library arguments so that dependency libraries do not shadow those in the build. This is safe because semantics aren't affected by *interleaving* `-I`, `-L`, and `-Wl,-rpath` arguments with others, only with each other (so the order of two `-L` args affects the search path, but we search for all libraries on the command line using the same search path). We preserve the following: 1. Any system directory in the paths will be listed last. 2. The root package's include/library/RPATH flags come before flags of the same type for any dependency. 3. Order will be preserved within flags passed by the build (except system paths, which are moved to be last) 4. Flags for dependencies will appear between the root flags and the system flags, and the flags for any dependency will come before those for *its* dependencies (this is for completeness -- we already guarantee this in `build_environment.py`)
2018-08-05 12:30:17 +08:00
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=}"
Restore cc: package search paths come before dependency paths (#4692) Spack currently prepends include paths, library paths, and rpaths to the compile line. This causes problems when a header or library in the package has the same name as one exported by one of its dependencies. The *dependency's* header will be preferred over the package's, which is not what most builds expect. This also breaks some of our production codes. This restores the original cc behavior (from *very* early Spack) of parsing compiler arguments out by type (`-L`, `-I`, `-Wl,-rpath`) and reconstituting the full command at the end. `<includes> <other_args> <library dirs> <rpaths>` This differs from the original behavior in one significant way, though: it *appends* the library arguments so that dependency libraries do not shadow those in the build. This is safe because semantics aren't affected by *interleaving* `-I`, `-L`, and `-Wl,-rpath` arguments with others, only with each other (so the order of two `-L` args affects the search path, but we search for all libraries on the command line using the same search path). We preserve the following: 1. Any system directory in the paths will be listed last. 2. The root package's include/library/RPATH flags come before flags of the same type for any dependency. 3. Order will be preserved within flags passed by the build (except system paths, which are moved to be last) 4. Flags for dependencies will appear between the root flags and the system flags, and the flags for any dependency will come before those for *its* dependencies (this is for completeness -- we already guarantee this in `build_environment.py`)
2018-08-05 12:30:17 +08:00
elif [[ "$arg" = -rpath ]]; then
shift; arg="$1"
if [[ "$arg" != -Xlinker,* ]]; then
die "-Xlinker,-rpath was not followed by -Xlinker,*"
fi
rp="${arg#-Xlinker,}"
Restore cc: package search paths come before dependency paths (#4692) Spack currently prepends include paths, library paths, and rpaths to the compile line. This causes problems when a header or library in the package has the same name as one exported by one of its dependencies. The *dependency's* header will be preferred over the package's, which is not what most builds expect. This also breaks some of our production codes. This restores the original cc behavior (from *very* early Spack) of parsing compiler arguments out by type (`-L`, `-I`, `-Wl,-rpath`) and reconstituting the full command at the end. `<includes> <other_args> <library dirs> <rpaths>` This differs from the original behavior in one significant way, though: it *appends* the library arguments so that dependency libraries do not shadow those in the build. This is safe because semantics aren't affected by *interleaving* `-I`, `-L`, and `-Wl,-rpath` arguments with others, only with each other (so the order of two `-L` args affects the search path, but we search for all libraries on the command line using the same search path). We preserve the following: 1. Any system directory in the paths will be listed last. 2. The root package's include/library/RPATH flags come before flags of the same type for any dependency. 3. Order will be preserved within flags passed by the build (except system paths, which are moved to be last) 4. Flags for dependencies will appear between the root flags and the system flags, and the flags for any dependency will come before those for *its* dependencies (this is for completeness -- we already guarantee this in `build_environment.py`)
2018-08-05 12:30:17 +08:00
else
other_args+=("-Xlinker,$arg")
fi
;;
-Xlinker)
if [[ "$2" == "-rpath" ]]; then
if [[ "$3" != "-Xlinker" ]]; then
Restore cc: package search paths come before dependency paths (#4692) Spack currently prepends include paths, library paths, and rpaths to the compile line. This causes problems when a header or library in the package has the same name as one exported by one of its dependencies. The *dependency's* header will be preferred over the package's, which is not what most builds expect. This also breaks some of our production codes. This restores the original cc behavior (from *very* early Spack) of parsing compiler arguments out by type (`-L`, `-I`, `-Wl,-rpath`) and reconstituting the full command at the end. `<includes> <other_args> <library dirs> <rpaths>` This differs from the original behavior in one significant way, though: it *appends* the library arguments so that dependency libraries do not shadow those in the build. This is safe because semantics aren't affected by *interleaving* `-I`, `-L`, and `-Wl,-rpath` arguments with others, only with each other (so the order of two `-L` args affects the search path, but we search for all libraries on the command line using the same search path). We preserve the following: 1. Any system directory in the paths will be listed last. 2. The root package's include/library/RPATH flags come before flags of the same type for any dependency. 3. Order will be preserved within flags passed by the build (except system paths, which are moved to be last) 4. Flags for dependencies will appear between the root flags and the system flags, and the flags for any dependency will come before those for *its* dependencies (this is for completeness -- we already guarantee this in `build_environment.py`)
2018-08-05 12:30:17 +08:00
die "-Xlinker,-rpath was not followed by -Xlinker,*"
fi
shift 3;
rp="$1"
elif [[ "$2" = "$dtags_to_strip" ]] ; then
shift # We want to remove explicitly this flag
Restore cc: package search paths come before dependency paths (#4692) Spack currently prepends include paths, library paths, and rpaths to the compile line. This causes problems when a header or library in the package has the same name as one exported by one of its dependencies. The *dependency's* header will be preferred over the package's, which is not what most builds expect. This also breaks some of our production codes. This restores the original cc behavior (from *very* early Spack) of parsing compiler arguments out by type (`-L`, `-I`, `-Wl,-rpath`) and reconstituting the full command at the end. `<includes> <other_args> <library dirs> <rpaths>` This differs from the original behavior in one significant way, though: it *appends* the library arguments so that dependency libraries do not shadow those in the build. This is safe because semantics aren't affected by *interleaving* `-I`, `-L`, and `-Wl,-rpath` arguments with others, only with each other (so the order of two `-L` args affects the search path, but we search for all libraries on the command line using the same search path). We preserve the following: 1. Any system directory in the paths will be listed last. 2. The root package's include/library/RPATH flags come before flags of the same type for any dependency. 3. Order will be preserved within flags passed by the build (except system paths, which are moved to be last) 4. Flags for dependencies will appear between the root flags and the system flags, and the flags for any dependency will come before those for *its* dependencies (this is for completeness -- we already guarantee this in `build_environment.py`)
2018-08-05 12:30:17 +08:00
else
other_args+=("$1")
fi
;;
*)
if [[ "$1" = "$dtags_to_strip" ]] ; then
: # We want to remove explicitly this flag
else
other_args+=("$1")
fi
Restore cc: package search paths come before dependency paths (#4692) Spack currently prepends include paths, library paths, and rpaths to the compile line. This causes problems when a header or library in the package has the same name as one exported by one of its dependencies. The *dependency's* header will be preferred over the package's, which is not what most builds expect. This also breaks some of our production codes. This restores the original cc behavior (from *very* early Spack) of parsing compiler arguments out by type (`-L`, `-I`, `-Wl,-rpath`) and reconstituting the full command at the end. `<includes> <other_args> <library dirs> <rpaths>` This differs from the original behavior in one significant way, though: it *appends* the library arguments so that dependency libraries do not shadow those in the build. This is safe because semantics aren't affected by *interleaving* `-I`, `-L`, and `-Wl,-rpath` arguments with others, only with each other (so the order of two `-L` args affects the search path, but we search for all libraries on the command line using the same search path). We preserve the following: 1. Any system directory in the paths will be listed last. 2. The root package's include/library/RPATH flags come before flags of the same type for any dependency. 3. Order will be preserved within flags passed by the build (except system paths, which are moved to be last) 4. Flags for dependencies will appear between the root flags and the system flags, and the flags for any dependency will come before those for *its* dependencies (this is for completeness -- we already guarantee this in `build_environment.py`)
2018-08-05 12:30:17 +08:00
;;
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
Restore cc: package search paths come before dependency paths (#4692) Spack currently prepends include paths, library paths, and rpaths to the compile line. This causes problems when a header or library in the package has the same name as one exported by one of its dependencies. The *dependency's* header will be preferred over the package's, which is not what most builds expect. This also breaks some of our production codes. This restores the original cc behavior (from *very* early Spack) of parsing compiler arguments out by type (`-L`, `-I`, `-Wl,-rpath`) and reconstituting the full command at the end. `<includes> <other_args> <library dirs> <rpaths>` This differs from the original behavior in one significant way, though: it *appends* the library arguments so that dependency libraries do not shadow those in the build. This is safe because semantics aren't affected by *interleaving* `-I`, `-L`, and `-Wl,-rpath` arguments with others, only with each other (so the order of two `-L` args affects the search path, but we search for all libraries on the command line using the same search path). We preserve the following: 1. Any system directory in the paths will be listed last. 2. The root package's include/library/RPATH flags come before flags of the same type for any dependency. 3. Order will be preserved within flags passed by the build (except system paths, which are moved to be last) 4. Flags for dependencies will appear between the root flags and the system flags, and the flags for any dependency will come before those for *its* dependencies (this is for completeness -- we already guarantee this in `build_environment.py`)
2018-08-05 12:30:17 +08:00
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
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 C and C++ flags
case "$mode" in
cc|ccld)
case $lang_flags in
C)
flags=("${flags[@]}" "${SPACK_CFLAGS[@]}") ;;
CXX)
flags=("${flags[@]}" "${SPACK_CXXFLAGS[@]}") ;;
esac
targets: Spack targets can now be fine-grained microarchitectures Spack can now: - label ppc64, ppc64le, x86_64, etc. builds with specific microarchitecture-specific names, like 'haswell', 'skylake' or 'icelake'. - detect the host architecture of a machine from /proc/cpuinfo or similar tools. - Understand which microarchitectures are compatible with which (for binary reuse) - Understand which compiler flags are needed (for GCC, so far) to build binaries for particular microarchitectures. All of this is managed through a JSON file (microarchitectures.json) that contains detailed auto-detection, compiler flag, and compatibility information for specific microarchitecture targets. The `llnl.util.cpu` module implements a library that allows detection and comparison of microarchitectures based on the data in this file. The `target` part of Spack specs is now essentially a Microarchitecture object, and Specs' targets can be compared for compatibility as well. This allows us to label optimized binary packages at a granularity that enables them to be reused on compatible machines. Previously, we only knew that a package was built for x86_64, NOT which x86_64 machines it was usable on. Currently this feature supports Intel, Power, and AMD chips. Support for ARM is forthcoming. Specifics: - Add microarchitectures.json with descriptions of architectures - Relaxed semantic of compiler's "target" attribute. Before this change the semantic to check if a compiler could be viable for a given target was exact match. This made sense as the finest granularity of targets was architecture families. As now we can target micro-architectures, this commit changes the semantic by interpreting as the architecture family what is stored in the compiler's "target" attribute. A compiler is then a viable choice if the target being concretized belongs to the same family. Similarly when a new compiler is detected the architecture family is stored in the "target" attribute. - Make Spack's `cc` compiler wrapper inject target-specific flags on the command line - Architecture concretization updated to use the same algorithm as compiler concretization - Micro-architecture features, vendor, generation etc. are included in the package hash. Generic architectures, such as x86_64 or ppc64, are still dumped using the name only. - If the compiler for a target is not supported exit with an intelligible error message. If the compiler support is unknown don't try to use optimization flags. - Support and define feature aliases (e.g., sse3 -> ssse3) in microarchitectures.json and on Microarchitecture objects. Feature aliases are defined in targets.json and map a name (the "alias") to a list of rules that must be met for the test to be successful. The rules that are available can be extended later using a decorator. - Implement subset semantics for comparing microarchitectures (treat microarchitectures as a partial order, i.e. (a < b), (a == b) and (b < a) can all be false. - Implement logic to automatically demote the default target if the compiler being used is too old to optimize for it. Updated docs to make this behavior explicit. This avoids surprising the user if the default compiler is older than the host architecture. This commit adds unit tests to verify the semantics of target ranges and target lists in constraints. The implementation to allow target ranges and lists is minimal and doesn't add any new type. A more careful refactor that takes into account the type system might be due later. Co-authored-by: Gregory Becker <becker33.llnl.gov>
2019-06-19 21:47:07 +08:00
flags=(${SPACK_TARGET_ARGS[@]} "${flags[@]}")
;;
esac
# Linker flags
case "$mode" in
ld|ccld)
flags=("${flags[@]}" "${SPACK_LDFLAGS[@]}") ;;
esac
# On macOS insert headerpad_max_install_names linker flag
if [[ ($mode == ld || $mode == ccld) && "$SPACK_SHORT_SPEC" =~ "darwin" ]];
then
case "$mode" in
ld)
flags=("${flags[@]}" -headerpad_max_install_names) ;;
ccld)
flags=("${flags[@]}" -Wl,-headerpad_max_install_names) ;;
esac
fi
IFS=':' read -ra rpath_dirs <<< "$SPACK_RPATH_DIRS"
if [[ $mode == ccld || $mode == ld ]]; then
if [[ "$add_rpaths" != "false" ]] ; then
# Append RPATH directories. Note that in the case of the
# top-level package these directories may not exist yet. For dependencies
# it is assumed that paths have already been confirmed.
rpaths=("${rpaths[@]}" "${rpath_dirs[@]}")
fi
fi
IFS=':' read -ra link_dirs <<< "$SPACK_LINK_DIRS"
if [[ $mode == ccld || $mode == ld ]]; then
libdirs=("${libdirs[@]}" "${link_dirs[@]}")
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"
libdirs+=("${extra_rpaths[@]}")
if [[ "$add_rpaths" != "false" ]] ; then
rpaths+=("${extra_rpaths[@]}")
fi
# Set implicit RPATHs
IFS=':' read -ra implicit_rpaths <<< "$SPACK_COMPILER_IMPLICIT_RPATHS"
if [[ "$add_rpaths" != "false" ]] ; then
rpaths+=("${implicit_rpaths[@]}")
fi
# 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[@]}")
# Insert include directories just prior to any system include directories
for dir in "${includes[@]}"; do args+=("-I$dir"); done
for dir in "${isystem_includes[@]}"; do args+=("-isystem$dir"); done
IFS=':' read -ra spack_include_dirs <<< "$SPACK_INCLUDE_DIRS"
if [[ $mode == cpp || $mode == cc || $mode == as || $mode == ccld ]]; then
if [[ "$isystem_was_used" == "true" ]] ; then
for dir in "${spack_include_dirs[@]}"; do args+=("-isystem$dir"); done
else
for dir in "${spack_include_dirs[@]}"; do args+=("-I$dir"); done
fi
fi
for dir in "${system_includes[@]}"; do args+=("-I$dir"); done
for dir in "${isystem_system_includes[@]}"; do args+=("-isystem$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
ccld)
if [ ! -z "$dtags_to_add" ] ; then args+=("$linker_arg$dtags_to_add") ; fi
for dir in "${rpaths[@]}"; do args+=("$rpath$dir"); done
for dir in "${system_rpaths[@]}"; do args+=("$rpath$dir"); done
;;
ld)
if [ ! -z "$dtags_to_add" ] ; then args+=("$dtags_to_add") ; fi
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[@]}")
# 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
Restore cc: package search paths come before dependency paths (#4692) Spack currently prepends include paths, library paths, and rpaths to the compile line. This causes problems when a header or library in the package has the same name as one exported by one of its dependencies. The *dependency's* header will be preferred over the package's, which is not what most builds expect. This also breaks some of our production codes. This restores the original cc behavior (from *very* early Spack) of parsing compiler arguments out by type (`-L`, `-I`, `-Wl,-rpath`) and reconstituting the full command at the end. `<includes> <other_args> <library dirs> <rpaths>` This differs from the original behavior in one significant way, though: it *appends* the library arguments so that dependency libraries do not shadow those in the build. This is safe because semantics aren't affected by *interleaving* `-I`, `-L`, and `-Wl,-rpath` arguments with others, only with each other (so the order of two `-L` args affects the search path, but we search for all libraries on the command line using the same search path). We preserve the following: 1. Any system directory in the paths will be listed last. 2. The root package's include/library/RPATH flags come before flags of the same type for any dependency. 3. Order will be preserved within flags passed by the build (except system paths, which are moved to be last) 4. Flags for dependencies will appear between the root flags and the system flags, and the flags for any dependency will come before those for *its* dependencies (this is for completeness -- we already guarantee this in `build_environment.py`)
2018-08-05 12:30:17 +08:00
# dump the full command if the caller supplies SPACK_TEST_COMMAND=dump-args
2016-04-05 03:38:21 +08:00
if [[ $SPACK_TEST_COMMAND == dump-args ]]; then
IFS="
" && echo "${full_command[*]}"
exit
elif [[ -n $SPACK_TEST_COMMAND ]]; then
die "ERROR: Unknown test command"
fi
#
# Write the input and output commands to debug logs if it's asked for.
#
2016-04-05 03:38:21 +08:00
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"
fi
exec "${full_command[@]}"