diff --git a/lib/spack/env/cc b/lib/spack/env/cc index 35d92b4d41af1d..ccfc14bb89dc53 100755 --- a/lib/spack/env/cc +++ b/lib/spack/env/cc @@ -174,6 +174,46 @@ preextend() { unset IFS } +execute() { + # dump the full command if the caller supplies SPACK_TEST_COMMAND=dump-args + if [ -n "${SPACK_TEST_COMMAND=}" ]; then + case "$SPACK_TEST_COMMAND" in + dump-args) + IFS="$lsep" + for arg in $full_command_list; do + echo "$arg" + done + unset IFS + exit + ;; + dump-env-*) + var=${SPACK_TEST_COMMAND#dump-env-} + eval "printf '%s\n' \"\$0: \$var: \$$var\"" + ;; + *) + die "Unknown test command: '$SPACK_TEST_COMMAND'" + ;; + esac + fi + + # + # 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_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" + IFS="$lsep" + echo "[$mode] "$full_command_list >> "$output_log" + unset IFS + fi + + # Execute the full command, preserving spaces with IFS set + # to the alarm bell separator. + IFS="$lsep"; exec $full_command_list + exit +} + # Fail with a clear message if the input contains any bell characters. if eval "[ \"\${*#*${lsep}}\" != \"\$*\" ]"; then die "Compiler command line contains our separator ('${lsep}'). Cannot parse." @@ -231,6 +271,9 @@ fi # ld link # ccld compile & link +# Note. SPACK_ALWAYS_XFLAGS are applied for all compiler invocations, +# including version checks (SPACK_XFLAGS variants are not applied +# for version checks). command="${0##*/}" comp="CC" vcheck_flags="" @@ -238,51 +281,31 @@ case "$command" in cpp) mode=cpp debug_flags="-g" + vcheck_flags="${SPACK_ALWAYS_CPPFLAGS}" ;; cc|c89|c99|gcc|clang|armclang|icc|icx|pgcc|nvc|xlc|xlc_r|fcc|amdclang|cl.exe|craycc) - # Edge case for Intel's oneAPI compilers when using the legacy classic compilers: - # Pass flags to disable deprecation warnings to vcheck mode, since the warnings - # to stderr confuse tools that parse the output of compiler version checks. - case ${SPACK_CFLAGS} in - *"-diag-disable=10441"* ) - vcheck_flags="-diag-disable=10441" - ;; - esac command="$SPACK_CC" language="C" comp="CC" lang_flags=C debug_flags="-g" + vcheck_flags="${SPACK_ALWAYS_CFLAGS}" ;; c++|CC|g++|clang++|armclang++|icpc|icpx|pgc++|nvc++|xlc++|xlc++_r|FCC|amdclang++|crayCC) - # Edge case for Intel's oneAPI compilers when using the legacy classic compilers: - # Pass flags to disable deprecation warnings to vcheck mode, since the warnings - # to stderr confuse tools that parse the output of compiler version checks. - case ${SPACK_CXXFLAGS} in - *"-diag-disable=10441"* ) - vcheck_flags="-diag-disable=10441" - ;; - esac command="$SPACK_CXX" language="C++" comp="CXX" lang_flags=CXX debug_flags="-g" + vcheck_flags="${SPACK_ALWAYS_CXXFLAGS}" ;; ftn|f90|fc|f95|gfortran|flang|armflang|ifort|ifx|pgfortran|nvfortran|xlf90|xlf90_r|nagfor|frt|amdflang|crayftn) - # Edge case for Intel's oneAPI compilers when using the legacy classic compilers: - # Pass flags to disable deprecation warnings to vcheck mode, since the warnings - # to stderr confuse tools that parse the output of compiler version checks. - case ${SPACK_FFLAGS} in - *"-diag-disable=10448"* ) - vcheck_flags="-diag-disable=10448" - ;; - esac command="$SPACK_FC" language="Fortran 90" comp="FC" lang_flags=F debug_flags="-g" + vcheck_flags="${SPACK_ALWAYS_FFLAGS}" ;; f77|xlf|xlf_r|pgf77) command="$SPACK_F77" @@ -290,6 +313,7 @@ case "$command" in comp="F77" lang_flags=F debug_flags="-g" + vcheck_flags="${SPACK_ALWAYS_FFLAGS}" ;; ld|ld.gold|ld.lld) mode=ld @@ -390,7 +414,11 @@ unset IFS export PATH="$new_dirs" if [ "$mode" = vcheck ]; then - exec "${command}" ${vcheck_flags} "$@" + full_command_list="$command" + args="$@" + extend full_command_list vcheck_flags + extend full_command_list args + execute fi # Darwin's linker has a -r argument that merges object files together. @@ -747,6 +775,7 @@ case "$mode" in cc|ccld) case $lang_flags in F) + extend spack_flags_list SPACK_ALWAYS_FFLAGS extend spack_flags_list SPACK_FFLAGS ;; esac @@ -756,6 +785,7 @@ esac # C preprocessor flags come before any C/CXX flags case "$mode" in cpp|as|cc|ccld) + extend spack_flags_list SPACK_ALWAYS_CPPFLAGS extend spack_flags_list SPACK_CPPFLAGS ;; esac @@ -766,9 +796,11 @@ case "$mode" in cc|ccld) case $lang_flags in C) + extend spack_flags_list SPACK_ALWAYS_CFLAGS extend spack_flags_list SPACK_CFLAGS ;; CXX) + extend spack_flags_list SPACK_ALWAYS_CXXFLAGS extend spack_flags_list SPACK_CXXFLAGS ;; esac @@ -958,39 +990,4 @@ if [ -n "$SPACK_CCACHE_BINARY" ]; then esac fi -# dump the full command if the caller supplies SPACK_TEST_COMMAND=dump-args -if [ -n "${SPACK_TEST_COMMAND=}" ]; then - case "$SPACK_TEST_COMMAND" in - dump-args) - IFS="$lsep" - for arg in $full_command_list; do - echo "$arg" - done - unset IFS - exit - ;; - dump-env-*) - var=${SPACK_TEST_COMMAND#dump-env-} - eval "printf '%s\n' \"\$0: \$var: \$$var\"" - ;; - *) - die "Unknown test command: '$SPACK_TEST_COMMAND'" - ;; - esac -fi - -# -# 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_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" - IFS="$lsep" - echo "[$mode] "$full_command_list >> "$output_log" - unset IFS -fi - -# Execute the full command, preserving spaces with IFS set -# to the alarm bell separator. -IFS="$lsep"; exec $full_command_list +execute diff --git a/lib/spack/spack/compilers/intel.py b/lib/spack/spack/compilers/intel.py index c7b0d8033c6eaa..023248b86e57e5 100644 --- a/lib/spack/spack/compilers/intel.py +++ b/lib/spack/spack/compilers/intel.py @@ -126,3 +126,14 @@ def fc_pic_flag(self): @property def stdcxx_libs(self): return ("-cxxlib",) + + def setup_custom_environment(self, pkg, env): + # Edge cases for Intel's oneAPI compilers when using the legacy classic compilers: + # Always pass flags to disable deprecation warnings, since these warnings can + # confuse tools that parse the output of compiler commands (e.g. version checks). + if self.cc and self.cc.endswith("icc") and self.real_version >= Version("2021"): + env.append_flags("SPACK_ALWAYS_CFLAGS", "-diag-disable=10441") + if self.cxx and self.cxx.endswith("icpc") and self.real_version >= Version("2021"): + env.append_flags("SPACK_ALWAYS_CXXFLAGS", "-diag-disable=10441") + if self.fc and self.fc.endswith("ifort") and self.real_version >= Version("2021"): + env.append_flags("SPACK_ALWAYS_FFLAGS", "-diag-disable=10448") diff --git a/lib/spack/spack/compilers/oneapi.py b/lib/spack/spack/compilers/oneapi.py index ecba99081a4b95..fd8908be13bca8 100644 --- a/lib/spack/spack/compilers/oneapi.py +++ b/lib/spack/spack/compilers/oneapi.py @@ -9,6 +9,7 @@ from llnl.util import tty from spack.compiler import Compiler +from spack.version import Version class Oneapi(Compiler): @@ -138,6 +139,16 @@ def setup_custom_environment(self, pkg, env): if self.cxx: env.prepend_path("PATH", dirname(self.cxx)) + # Edge cases for Intel's oneAPI compilers when using the legacy classic compilers: + # Always pass flags to disable deprecation warnings, since these warnings can + # confuse tools that parse the output of compiler commands (e.g. version checks). + if self.cc and self.cc.endswith("icc") and self.real_version >= Version("2021"): + env.append_flags("SPACK_ALWAYS_CFLAGS", "-diag-disable=10441") + if self.cxx and self.cxx.endswith("icpc") and self.real_version >= Version("2021"): + env.append_flags("SPACK_ALWAYS_CXXFLAGS", "-diag-disable=10441") + if self.fc and self.fc.endswith("ifort") and self.real_version >= Version("2021"): + env.append_flags("SPACK_ALWAYS_FFLAGS", "-diag-disable=10448") + # 2024 release bumped the libsycl version because of an ABI # change, 2024 compilers are required. You will see this # error: diff --git a/lib/spack/spack/test/build_environment.py b/lib/spack/spack/test/build_environment.py index cb47ee5977ca1e..d06bda58fdbc48 100644 --- a/lib/spack/spack/test/build_environment.py +++ b/lib/spack/spack/test/build_environment.py @@ -6,6 +6,7 @@ import os import platform import posixpath +import sys import pytest @@ -286,6 +287,25 @@ def platform_pathsep(pathlist): assert name not in os.environ +def test_compiler_custom_env(config, mock_packages, monkeypatch, working_env): + if sys.platform == "win32": + test_path = r"C:\test\path\element\custom-env" + "\\" + else: + test_path = r"/test/path/element/custom-env/" + + def custom_env(pkg, env): + env.prepend_path("PATH", test_path) + env.append_flags("ENV_CUSTOM_CC_FLAGS", "--custom-env-flag1") + + pkg = spack.spec.Spec("cmake").concretized().package + monkeypatch.setattr(pkg.compiler, "setup_custom_environment", custom_env) + spack.build_environment.setup_package(pkg, False) + + # Note: trailing slash may be stripped by internal logic + assert test_path[:-1] in os.environ["PATH"] + assert "--custom-env-flag1" in os.environ["ENV_CUSTOM_CC_FLAGS"] + + def test_external_config_env(mock_packages, mutable_config, working_env): cmake_config = { "externals": [ diff --git a/lib/spack/spack/test/cc.py b/lib/spack/spack/test/cc.py index dfff73811ab9ce..bf119d2d509add 100644 --- a/lib/spack/spack/test/cc.py +++ b/lib/spack/spack/test/cc.py @@ -355,6 +355,15 @@ def test_fc_flags(wrapper_environment, wrapper_flags): ) +def test_always_cflags(wrapper_environment, wrapper_flags): + with set_env(SPACK_ALWAYS_CFLAGS="-always1 -always2"): + check_args( + cc, + ["-v", "--cmd-line-v-opt"], + [real_cc] + ["-always1", "-always2"] + ["-v", "--cmd-line-v-opt"], + ) + + def test_Wl_parsing(wrapper_environment): check_args( cc,