From 0902910784dbe755d1ee1e0e76b9c263c6124bbc Mon Sep 17 00:00:00 2001 From: Dom Heinzeller Date: Thu, 8 Aug 2024 00:40:36 -0600 Subject: [PATCH] Compiler wrapper: add env var to pass vcheck flags (#44588) Fixes #43494 Add a set of environment variables SPACK_ALWAYS_CFLAGS (etc.) that are always applied by the compiler wrapper. Unlike SPACK_CFLAGS, for example, these will also be applied to version checks (both SPACK_CFLAGS and SPACK_ALWAYS_CFLAGS will be applied to the other invocation modes like ccld etc.). Using this new functionality, the classic Intel and oneAPI compilers are updated to pass compiler flags that disable warning messages when newer versions are invoked via their older binary names (these warnings were also generated for version checks, hence the need for a new wrapper variable). --------- Co-authored-by: Peter Josef Scheibel --- lib/spack/env/cc | 96 ++++++++++++++--------- lib/spack/spack/compilers/intel.py | 11 +++ lib/spack/spack/compilers/oneapi.py | 11 +++ lib/spack/spack/test/build_environment.py | 20 +++++ lib/spack/spack/test/cc.py | 9 +++ 5 files changed, 110 insertions(+), 37 deletions(-) diff --git a/lib/spack/env/cc b/lib/spack/env/cc index ffaa9944df2..ccfc14bb89d 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,12 +271,17 @@ 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="" 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) command="$SPACK_CC" @@ -244,6 +289,7 @@ case "$command" in 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) command="$SPACK_CXX" @@ -251,6 +297,7 @@ case "$command" in 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) command="$SPACK_FC" @@ -258,6 +305,7 @@ case "$command" in comp="FC" lang_flags=F debug_flags="-g" + vcheck_flags="${SPACK_ALWAYS_FFLAGS}" ;; f77|xlf|xlf_r|pgf77) command="$SPACK_F77" @@ -265,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 @@ -365,7 +414,11 @@ unset IFS export PATH="$new_dirs" if [ "$mode" = vcheck ]; then - exec "${command}" "$@" + 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. @@ -722,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 @@ -731,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 @@ -741,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 @@ -933,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 c7b0d8033c6..023248b86e5 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 1baac838268..fbcf7876c74 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): @@ -142,6 +143,16 @@ def setup_custom_environment(self, pkg, env): env.prepend_path("PATH", dirname(self.cxx)) env.prepend_path("LD_LIBRARY_PATH", join(dirname(dirname(self.cxx)), "lib")) + # 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 a47fb288112..3c381f368ce 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 @@ -287,6 +288,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 b547641b06f..27d05fb7861 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,