From e19274973c615920bfa301ad26cdef3b634b804a Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Mon, 11 Nov 2024 12:24:22 +0100 Subject: [PATCH] builtin: changes to packages --- .../repos/builtin/packages/acfl/package.py | 23 +++ .../repos/builtin/packages/aocc/package.py | 32 +++ .../builtin/packages/apple-clang/package.py | 35 ++++ .../builtin/packages/armpl-gcc/package.py | 7 +- .../repos/builtin/packages/blt/package.py | 4 +- .../repos/builtin/packages/cce/package.py | 23 ++- .../repos/builtin/packages/claw/package.py | 29 --- .../repos/builtin/packages/clingo/package.py | 8 +- .../repos/builtin/packages/cmake/package.py | 10 - .../repos/builtin/packages/cuda/package.py | 3 +- .../repos/builtin/packages/cxx/package.py | 2 +- .../repos/builtin/packages/dealii/package.py | 8 +- .../repos/builtin/packages/esmf/package.py | 19 +- .../repos/builtin/packages/fj/package.py | 31 +++ .../builtin/packages/gcc-runtime/package.py | 9 +- .../repos/builtin/packages/gcc/package.py | 66 +++++- .../repos/builtin/packages/go/package.py | 7 +- .../intel-oneapi-compilers-classic/package.py | 24 +++ .../intel-oneapi-compilers/package.py | 135 +++++++++++-- .../packages/intel-oneapi-runtime/package.py | 4 +- .../repos/builtin/packages/intel/package.py | 6 +- .../repos/builtin/packages/libxml2/package.py | 2 +- .../builtin/packages/llvm-amdgpu/package.py | 43 +++- .../repos/builtin/packages/llvm/package.py | 58 +++++- .../builtin/packages/lua-lpeg/package.py | 5 + .../packages/lua-luajit-openresty/package.py | 3 +- .../repos/builtin/packages/mapl/package.py | 8 +- .../repos/builtin/packages/mpich/package.py | 26 +-- .../repos/builtin/packages/msvc/package.py | 188 +++++++++++++++++- .../builtin/packages/mvapich2/package.py | 4 +- .../repos/builtin/packages/nag/package.py | 43 ++++ .../repos/builtin/packages/ncurses/package.py | 6 +- .../repos/builtin/packages/neovim/package.py | 6 +- .../repos/builtin/packages/nvhpc/package.py | 37 +++- .../repos/builtin/packages/openmpi/package.py | 12 +- .../repos/builtin/packages/openssl/package.py | 2 +- .../repos/builtin/packages/perl/package.py | 11 +- .../repos/builtin/packages/python/package.py | 19 +- .../repos/builtin/packages/snappy/package.py | 3 +- .../builtin/packages/spectrum-mpi/package.py | 4 +- .../builtin/packages/taskflow/package.py | 2 +- .../repos/builtin/packages/tree/package.py | 2 + .../repos/builtin/packages/vasp/package.py | 2 +- .../builtin/packages/win-file/package.py | 2 + .../repos/builtin/packages/win-gpg/package.py | 2 + .../repos/builtin/packages/xl/package.py | 47 +++++ .../repos/builtin/packages/yafyaml/package.py | 29 --- .../repos/builtin/packages/zlib-ng/package.py | 2 +- 48 files changed, 838 insertions(+), 215 deletions(-) diff --git a/var/spack/repos/builtin/packages/acfl/package.py b/var/spack/repos/builtin/packages/acfl/package.py index 6e1d9fa618c..9d23a5280dd 100644 --- a/var/spack/repos/builtin/packages/acfl/package.py +++ b/var/spack/repos/builtin/packages/acfl/package.py @@ -3,6 +3,7 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) import os +import os.path import spack.platforms from spack.package import * @@ -357,6 +358,11 @@ class Acfl(Package, CompilerPackage): provides("lapack") provides("fftw-api@3") + provides("c", "cxx") + provides("fortran") + + requires("platform=linux", msg="acfl is only available for linux") + # Licensing - Not required from 22.0.1 on. # Run the installer with the desired install directory @@ -376,6 +382,23 @@ def install(self, spec, prefix): r"Arm C\/C\+\+\/Fortran Compiler version ([\d\.]+) \(build number \d+\) " ) + opt_flags = ["-O", "-O0", "-O1", "-O2", "-O3", "-Ofast"] + + link_paths = { + "c": os.path.join("arm", "armclang"), + "cxx": os.path.join("arm", "armclang++"), + "fortran": os.path.join("arm", "armflang"), + } + + required_libs = ["libclang", "libflang"] + + def _standard_flag(self, *, language, standard): + flags = { + "cxx": {"11": "-std=c++11", "14": "-std=c++14", "17": "-std=c++1z"}, + "c": {"99": "-std=c99", "11": "-std=c11"}, + } + return flags[language][standard] + @property def cc(self): msg = "cannot retrieve C compiler [spec is not concrete]" diff --git a/var/spack/repos/builtin/packages/aocc/package.py b/var/spack/repos/builtin/packages/aocc/package.py index 0366bbe971c..686d11a39a9 100644 --- a/var/spack/repos/builtin/packages/aocc/package.py +++ b/var/spack/repos/builtin/packages/aocc/package.py @@ -2,6 +2,7 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import os.path from llnl.util import tty @@ -62,6 +63,9 @@ class Aocc(Package, LlvmDetection, CompilerPackage): depends_on("c", type="build") # generated + provides("c", "cxx") + provides("fortran") + # Licensing license_url = "https://www.amd.com/en/developer/aocc/aocc-compiler/eula.html" @@ -116,3 +120,31 @@ def cfg_files(self): compiler_version_regex = r"AOCC_(\d+[._]\d+[._]\d+)" fortran_names = ["flang"] + + debug_flags = [ + "-gcodeview", + "-gdwarf-2", + "-gdwarf-3", + "-gdwarf-4", + "-gdwarf-5", + "-gline-tables-only", + "-gmodules", + "-g", + ] + + opt_flags = ["-O0", "-O1", "-O2", "-O3", "-Ofast", "-Os", "-Oz", "-Og", "-O", "-O4"] + + link_paths = { + "c": os.path.join("aocc", "clang"), + "cxx": os.path.join("aocc", "clang++"), + "fortran": os.path.join("aocc", "flang"), + } + + required_libs = ["libclang"] + + def _standard_flag(self, *, language: str, standard: str) -> str: + flags = { + "cxx": {"11": "-std=c++11", "14": "-std=c++14", "17": "-std=c++17"}, + "c": {"99": "-std=c99", "11": "-std=c11"}, + } + return flags[language][standard] diff --git a/var/spack/repos/builtin/packages/apple-clang/package.py b/var/spack/repos/builtin/packages/apple-clang/package.py index ba87604cd2e..8fc305ed814 100644 --- a/var/spack/repos/builtin/packages/apple-clang/package.py +++ b/var/spack/repos/builtin/packages/apple-clang/package.py @@ -2,6 +2,8 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import os.path + from spack.package import * from spack.pkg.builtin.llvm import LlvmDetection @@ -17,6 +19,14 @@ class AppleClang(BundlePackage, LlvmDetection, CompilerPackage): compiler_languages = ["c", "cxx"] compiler_version_regex = r"^Apple (?:LLVM|clang) version ([^ )]+)" + openmp_flag = "-Xpreprocessor -fopenmp" + + link_paths = {"c": os.path.join("clang", "clang"), "cxx": os.path.join("clang", "clang++")} + + required_libs = ["libclang"] + + provides("c", "cxx") + @classmethod def validate_detected_spec(cls, spec, extra_attributes): msg = f'the extra attribute "compilers" must be set for the detected spec "{spec}"' @@ -37,3 +47,28 @@ def cxx(self): msg = "apple-clang is expected to be an external spec" assert self.spec.concrete and self.spec.external, msg return self.spec.extra_attributes["compilers"].get("cxx", None) + + def _standard_flag(self, *, language, standard): + flags = { + "cxx": { + "11": [("@4.0:", "-std=c++11")], + "14": [("@6.1:", "-std=c++14")], + "17": [("@6.1:10.0", "-std=c++1z"), ("10.1:", "-std=c++17")], + "20": [("@10.0:13.0", "-std=c++2a"), ("13.1:", "-std=c++20")], + "23": [("13.0:", "-std=c++2b")], + }, + "c": { + "99": [("@4.0:", "-std=c99")], + "11": [("@4.0:", "-std=c11")], + "17": [("@11.1:", "-std=c17")], + "23": [("@11.1:", "-std=c2x")], + }, + } + for condition, flag in flags[language][standard]: + if self.spec.satisfies(condition): + return flag + else: + raise RuntimeError( + f"{self.spec} does not support the '{standard}' standard " + f"for the '{language}' language" + ) diff --git a/var/spack/repos/builtin/packages/armpl-gcc/package.py b/var/spack/repos/builtin/packages/armpl-gcc/package.py index 3da17ef3e42..b9a6e4ff21d 100644 --- a/var/spack/repos/builtin/packages/armpl-gcc/package.py +++ b/var/spack/repos/builtin/packages/armpl-gcc/package.py @@ -5,7 +5,6 @@ import os -import spack.error import spack.platforms from spack.package import * @@ -407,6 +406,10 @@ class ArmplGcc(Package): provides("lapack") provides("fftw-api@3") + depends_on("c", type="build") + depends_on("fortran", type="build") + requires("^[virtuals=c,fortran] gcc", msg="armpl-gcc is only compatible with the GCC compiler") + # Run the installer with the desired install directory def install(self, spec, prefix): if spec.platform == "darwin": @@ -430,8 +433,6 @@ def install(self, spec, prefix): # Unmount image hdiutil("detach", mountpoint) return - if self.compiler.name != "gcc": - raise spack.error.SpackError(("Only compatible with GCC.\n")) with when("@:22"): armpl_version = spec.version.up_to(3).string.split("_")[0] diff --git a/var/spack/repos/builtin/packages/blt/package.py b/var/spack/repos/builtin/packages/blt/package.py index 4202ca559c9..2ff041d5b67 100644 --- a/var/spack/repos/builtin/packages/blt/package.py +++ b/var/spack/repos/builtin/packages/blt/package.py @@ -23,7 +23,7 @@ def spec_uses_gccname(spec): def llnl_link_helpers(options, spec, compiler): # From local package: - if compiler.fc: + if "fortran" in spec: fortran_compilers = ["gfortran", "xlf"] if any(f_comp in compiler.fc for f_comp in fortran_compilers) and ( "clang" in compiler.cxx @@ -38,7 +38,7 @@ def llnl_link_helpers(options, spec, compiler): if flags: options.append(cmake_cache_string("BLT_EXE_LINKER_FLAGS", flags, description)) - if "cce" in compiler.cxx: + if "cxx" in spec and spec["cxx"].name == "cce": description = "Adds a missing rpath for libraries " "associated with the fortran compiler" # Here is where to find libs that work for fortran libdir = "/opt/cray/pe/cce/{0}/cce-clang/x86_64/lib".format(compiler.version) diff --git a/var/spack/repos/builtin/packages/cce/package.py b/var/spack/repos/builtin/packages/cce/package.py index 0772be6ab1d..ce6dd5f1f17 100644 --- a/var/spack/repos/builtin/packages/cce/package.py +++ b/var/spack/repos/builtin/packages/cce/package.py @@ -2,6 +2,8 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import os.path + from spack.package import * @@ -21,10 +23,29 @@ class Cce(Package, CompilerPackage): r"[Cc]ray (?:clang|C :|C\+\+ :|Fortran :) [Vv]ersion.*?(\d+(?:\.\d+)+)" ) - # notify when the package is updated. + debug_flags = ["-g", "-G0", "-G1", "-G2", "-Gfast"] + + liink_paths = { + "c": os.path.join("cce", "craycc"), + "cxx": os.path.join("cce", "case-insensitive", "crayCC"), + "fortran": os.path.join("cce", "crayftn"), + } + maintainers("becker33") version("16.0.0") + provides("c", "cxx") + provides("fortran") + + requires("platform=linux") + + def _standard_flag(self, *, language, standard): + flags = { + "cxx": {"11": "-std=c++11", "14": "-std=c++14", "17": "-std=c++17"}, + "c": {"99": "-std=c99", "11": "-std=c11"}, + } + return flags[language][standard] + def install(self, spec, prefix): raise NotImplementedError("cray compiler must be configured as external") diff --git a/var/spack/repos/builtin/packages/claw/package.py b/var/spack/repos/builtin/packages/claw/package.py index 481745cb907..3bc5c41fc06 100644 --- a/var/spack/repos/builtin/packages/claw/package.py +++ b/var/spack/repos/builtin/packages/claw/package.py @@ -2,11 +2,6 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - -import os - -import spack.compilers -import spack.spec from spack.package import * @@ -88,8 +83,6 @@ class Claw(CMakePackage): def flag_handler(self, name, flags): if name == "cflags": compiler_spec = self.spec.compiler - if spack.compilers.is_mixed_toolchain(self.compiler): - compiler_spec = self._get_real_compiler_spec("cc") or compiler_spec if any( [ compiler_spec.satisfies(s) @@ -106,25 +99,3 @@ def cmake_args(self): args = ["-DOMNI_CONF_OPTION=--with-libxml2=%s" % self.spec["libxml2"].prefix] return args - - def _get_real_compiler_spec(self, language): - lang_compiler = getattr(self.compiler, language) - - if not lang_compiler: - return None - - for compiler_name in spack.compilers.supported_compilers(): - compiler_cls = spack.compilers.class_for_compiler_name(compiler_name) - lang_version_fn = getattr(compiler_cls, "{0}_version".format(language)) - for regexp in compiler_cls.search_regexps(language): - if regexp.match(os.path.basename(lang_compiler)): - try: - detected_version = lang_version_fn(lang_compiler) - if detected_version: - compiler_version = Version(detected_version) - if compiler_version != Version("unknown"): - return spack.spec.CompilerSpec(compiler_name, compiler_version) - except Exception: - continue - - return None diff --git a/var/spack/repos/builtin/packages/clingo/package.py b/var/spack/repos/builtin/packages/clingo/package.py index 73ff2b17696..53fb0b998a5 100644 --- a/var/spack/repos/builtin/packages/clingo/package.py +++ b/var/spack/repos/builtin/packages/clingo/package.py @@ -3,7 +3,7 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) -from spack.compiler import UnsupportedCompilerFlag +from spack.compilers.error import UnsupportedCompilerFlag from spack.package import * @@ -39,8 +39,8 @@ class Clingo(CMakePackage): version("5.3.0", sha256="b0d406d2809352caef7fccf69e8864d55e81ee84f4888b0744894977f703f976") version("5.2.2", sha256="da1ef8142e75c5a6f23c9403b90d4f40b9f862969ba71e2aaee9a257d058bfcf") - depends_on("c", type="build") # generated - depends_on("cxx", type="build") # generated + depends_on("c", type="build") + depends_on("cxx", type="build") variant("docs", default=False, description="build documentation with Doxygen") variant("python", default=True, description="build with python bindings") @@ -101,7 +101,7 @@ def cmake_py_shared(self): def cmake_args(self): try: - self.compiler.cxx14_flag + self.spec["cxx"].package.standard_flag(language="cxx", standard="14") except UnsupportedCompilerFlag: InstallError("clingo requires a C++14-compliant C++ compiler") diff --git a/var/spack/repos/builtin/packages/cmake/package.py b/var/spack/repos/builtin/packages/cmake/package.py index ba0b028bc13..429d19b368d 100644 --- a/var/spack/repos/builtin/packages/cmake/package.py +++ b/var/spack/repos/builtin/packages/cmake/package.py @@ -276,16 +276,6 @@ def determine_version(cls, exe): match = re.search(r"cmake.*version\s+(\S+)", output) return match.group(1) if match else None - def flag_handler(self, name, flags): - if name == "cxxflags" and self.compiler.name == "fj": - cxx11plus_flags = (self.compiler.cxx11_flag, self.compiler.cxx14_flag) - cxxpre11_flags = self.compiler.cxx98_flag - if any(f in flags for f in cxxpre11_flags): - raise ValueError("cannot build cmake pre-c++11 standard") - elif not any(f in flags for f in cxx11plus_flags): - flags.append(self.compiler.cxx11_flag) - return (flags, None, None) - def bootstrap_args(self): spec = self.spec args = [] diff --git a/var/spack/repos/builtin/packages/cuda/package.py b/var/spack/repos/builtin/packages/cuda/package.py index ea7b314418d..d816213b390 100644 --- a/var/spack/repos/builtin/packages/cuda/package.py +++ b/var/spack/repos/builtin/packages/cuda/package.py @@ -720,7 +720,8 @@ def setup_build_environment(self, env): env.append_path("LD_LIBRARY_PATH", libxml2_home.lib) def setup_dependent_build_environment(self, env, dependent_spec): - env.set("CUDAHOSTCXX", dependent_spec.package.compiler.cxx) + if "cxx" in dependent_spec: + env.set("CUDAHOSTCXX", dependent_spec["cxx"].package.cxx) env.set("CUDA_HOME", self.prefix) env.set("NVHPC_CUDA_HOME", self.prefix) diff --git a/var/spack/repos/builtin/packages/cxx/package.py b/var/spack/repos/builtin/packages/cxx/package.py index ac5c5cc5a6b..86e25b10282 100644 --- a/var/spack/repos/builtin/packages/cxx/package.py +++ b/var/spack/repos/builtin/packages/cxx/package.py @@ -28,7 +28,7 @@ def test_cxx(self): with test_part(self, f"test_cxx_{test}", f"build and run {exe_name}"): # standard options # Hack to get compiler attributes - # TODO: remove this when compilers are dependencies + # FIXME (compiler as nodes): remove this when compilers are dependencies c_name = clang if self.spec.satisfies("llvm+clang") else self.name c_spec = spack.spec.CompilerSpec(c_name, self.spec.version) c_cls = spack.compilers.class_for_compiler_name(c_name) diff --git a/var/spack/repos/builtin/packages/dealii/package.py b/var/spack/repos/builtin/packages/dealii/package.py index e9ed50ac7aa..e2dfe8ef6cd 100644 --- a/var/spack/repos/builtin/packages/dealii/package.py +++ b/var/spack/repos/builtin/packages/dealii/package.py @@ -53,9 +53,9 @@ class Dealii(CMakePackage, CudaPackage): version("8.2.1", sha256="d75674e45fe63cd9fa294460fe45228904d51a68f744dbb99cd7b60720f3b2a0") version("8.1.0", sha256="d666bbda2a17b41b80221d7029468246f2658051b8c00d9c5907cd6434c4df99") - depends_on("c", type="build") # generated - depends_on("cxx", type="build") # generated - depends_on("fortran", type="build") # generated + depends_on("c", type="build") + depends_on("cxx", type="build") + depends_on("fortran", type="build") # Configuration variants variant( @@ -684,7 +684,7 @@ def cmake_args(self): # Add flags for machine vectorization, used when tutorials # and user code is built. # See https://github.com/dealii/dealii/issues/9164 - options.append(self.define("DEAL_II_CXX_FLAGS", os.environ["SPACK_TARGET_ARGS"])) + options.append(self.define("DEAL_II_CXX_FLAGS", os.environ["SPACK_TARGET_ARGS_CXX"])) # platform introspection - needs to be disabled in some environments if spec.satisfies("+platform-introspection"): diff --git a/var/spack/repos/builtin/packages/esmf/package.py b/var/spack/repos/builtin/packages/esmf/package.py index 20a7223e630..724b81ec4db 100644 --- a/var/spack/repos/builtin/packages/esmf/package.py +++ b/var/spack/repos/builtin/packages/esmf/package.py @@ -8,7 +8,6 @@ import spack.build_systems.makefile import spack.build_systems.python -import spack.compiler from spack.build_environment import dso_suffix, stat_suffix from spack.package import * @@ -259,24 +258,14 @@ def setup_build_environment(self, env): # ESMF_COMPILER must be set to select which Fortran and # C++ compilers are being used to build the ESMF library. - if self.pkg.compiler.name == "gcc": + if spec["fortran"].name == "gcc" and spec["c"].name == "gcc": + gfortran_major_version = int(spec["fortran"].version[0]) env.set("ESMF_COMPILER", "gfortran") - with self.pkg.compiler.compiler_environment(): - gfortran_major_version = int( - spack.compiler.get_compiler_version_output( - self.pkg.compiler.fc, "-dumpversion" - ).split(".")[0] - ) elif self.pkg.compiler.name == "intel" or self.pkg.compiler.name == "oneapi": env.set("ESMF_COMPILER", "intel") - elif self.pkg.compiler.name in ["clang", "apple-clang"]: + elif spec["fortran"].name == "gcc" and spec["c"].name in ["clang", "apple-clang"]: + gfortran_major_version = int(spec["fortran"].version[0]) env.set("ESMF_COMPILER", "gfortranclang") - with self.pkg.compiler.compiler_environment(): - gfortran_major_version = int( - spack.compiler.get_compiler_version_output( - self.pkg.compiler.fc, "-dumpversion" - ).split(".")[0] - ) elif self.pkg.compiler.name == "nag": env.set("ESMF_COMPILER", "nag") elif self.pkg.compiler.name == "nvhpc": diff --git a/var/spack/repos/builtin/packages/fj/package.py b/var/spack/repos/builtin/packages/fj/package.py index 9ebcecab2ef..90a5ee24b80 100644 --- a/var/spack/repos/builtin/packages/fj/package.py +++ b/var/spack/repos/builtin/packages/fj/package.py @@ -2,6 +2,8 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import os.path + from spack.package import * @@ -15,6 +17,9 @@ class Fj(Package, CompilerPackage): maintainers("t-karatsu") + provides("c", "cxx") + provides("fortran") + def install(self, spec, prefix): raise InstallError( "Fujitsu compilers are not installable yet, but can be " @@ -27,3 +32,29 @@ def install(self, spec, prefix): fortran_names = ["frt"] compiler_version_regex = r"\((?:FCC|FRT)\) ([a-z\d.]+)" compiler_version_argument = "--version" + + debug_flags = ["-g"] + opt_flags = ["-O0", "-O1", "-O2", "-O3", "-Ofast"] + + pic_flag = "-KPIC" + openmp_flag = "-Kopenmp" + + link_paths = { + "c": os.path.join("fj", "fcc"), + "cxx": os.path.join("fj", "case-insensitive", "FCC"), + "fortran": os.path.join("fj", "frt"), + } + + required_libs = ["libfj90i", "libfj90f", "libfjsrcinfo"] + + def _standard_flag(self, *, language, standard): + flags = { + "cxx": { + "98": "-std=c++98", + "11": "-std=c++11", + "14": "-std=c++14", + "17": "-std=c++17", + }, + "c": {"99": "-std=c99", "11": "-std=c11"}, + } + return flags[language][standard] diff --git a/var/spack/repos/builtin/packages/gcc-runtime/package.py b/var/spack/repos/builtin/packages/gcc-runtime/package.py index 551aaa57cbc..494942413ae 100644 --- a/var/spack/repos/builtin/packages/gcc-runtime/package.py +++ b/var/spack/repos/builtin/packages/gcc-runtime/package.py @@ -30,8 +30,6 @@ class GccRuntime(Package): license("GPL-3.0-or-later WITH GCC-exception-3.1") - requires("%gcc") - LIBRARIES = [ "asan", "atomic", @@ -56,9 +54,12 @@ class GccRuntime(Package): depends_on("libc", type="link", when="platform=linux") + depends_on("gcc", type="build") + def install(self, spec, prefix): + gcc_pkg = self.spec["gcc"].package if spec.platform in ["linux", "freebsd"]: - libraries = get_elf_libraries(compiler=self.compiler, libraries=self.LIBRARIES) + libraries = get_elf_libraries(compiler=gcc_pkg, libraries=self.LIBRARIES) elif spec.platform == "darwin": libraries = self._get_libraries_macho() else: @@ -78,7 +79,7 @@ def install(self, spec, prefix): def _get_libraries_macho(self): """Same as _get_libraries_elf but for Mach-O binaries""" - cc = Executable(self.compiler.cc) + cc = Executable(self.spec["gcc"].package.cc) path_and_install_name = [] for name in self.LIBRARIES: diff --git a/var/spack/repos/builtin/packages/gcc/package.py b/var/spack/repos/builtin/packages/gcc/package.py index 8972fc46ced..4d6f4ba536b 100644 --- a/var/spack/repos/builtin/packages/gcc/package.py +++ b/var/spack/repos/builtin/packages/gcc/package.py @@ -11,7 +11,7 @@ import llnl.util.tty as tty from llnl.util.symlink import readlink -import spack.compiler +import spack.build_systems.compiler import spack.platforms import spack.util.libc from spack.operating_systems.mac_os import macos_sdk_path, macos_version @@ -33,9 +33,9 @@ class Gcc(AutotoolsPackage, GNUMirrorPackage, CompilerPackage): license("GPL-2.0-or-later AND LGPL-2.1-or-later") - provides("c") - provides("cxx") - provides("fortran") + provides("c", when="languages=c") + provides("cxx", when="languages=c++") + provides("fortran", when="languages=fortran") version("master", branch="master") @@ -559,7 +559,12 @@ def supported_languages(self): # This weirdness is because it could be called on an abstract spec if "languages" not in self.spec.variants: return self.compiler_languages - return [x for x in self.compiler_languages if x in self.spec.variants["languages"].value] + variant_value = {"cxx": "c++"} + return [ + x + for x in self.compiler_languages + if self.spec.satisfies(f"languages={variant_value.get(x, x)}") + ] c_names = ["gcc"] cxx_names = ["g++"] @@ -570,6 +575,40 @@ def supported_languages(self): compiler_version_regex = r"([0-9.]+)" compiler_version_argument = ("-dumpfullversion", "-dumpversion") + link_paths = { + "c": os.path.join("gcc", "gcc"), + "cxx": os.path.join("gcc", "g++"), + "fortran": os.path.join("gcc", "gfortran"), + } + + debug_flags = ["-g", "-gstabs+", "-gstabs", "-gxcoff+", "-gxcoff", "-gvms"] + opt_flags = ["-O", "-O0", "-O1", "-O2", "-O3", "-Os", "-Ofast", "-Og"] + + required_libs = ["libgcc", "libgfortran"] + stdcxx_libs = "-lstdc++" + + def _standard_flag(self, *, language, standard): + flags = { + "cxx": { + "98": [("@6:", "-std=c++98"), ("@:5", "")], + "11": [("@4.3:4.6", "-std=c++0x"), ("@4.7:", "-std=c++11")], + "14": [("@4.8", "-std=c++1y"), ("@4.9:", "-std=c++14")], + "17": [("@5", "-std=c++1z"), ("@6:", "-std=c++17")], + "20": [("@8:10", "-std=c++2a"), ("@11:", "-std=c++20")], + "23": [("@11:13", "-std=c++2b"), ("@14:", "-std=c++23")], + }, + "c": {"99": [("@4.5:", "-std=c99")], "11": [("@4.7:", "-std=c11")]}, + } + for condition, flag in flags[language][standard]: + if self.spec.satisfies(condition): + return flag + + else: + raise RuntimeError( + f"{self.spec} does not support the '{standard}' standard " + f"for the '{language}' language" + ) + @classmethod def filter_detected_exes(cls, prefix, exes_in_prefix): # Apple's gcc is actually apple clang, so skip it. @@ -577,7 +616,9 @@ def filter_detected_exes(cls, prefix, exes_in_prefix): not_apple_clang = [] for exe in exes_in_prefix: try: - output = spack.compiler.get_compiler_version_output(exe, "--version") + output = spack.build_systems.compiler.compiler_output( + exe, version_argument="--version" + ) except Exception: output = "" if "clang version" in output: @@ -1127,7 +1168,7 @@ def runtime_constraints(cls, *, spec, pkg): ) pkg("*").depends_on( f"gcc-runtime@{str(spec.version)}:", - when=f"%{str(spec)}", + when=f"^[deptypes=build] {spec.name}@{spec.versions}", type="link", description=f"If any package uses %{str(spec)}, " f"it depends on gcc-runtime@{str(spec.version)}:", @@ -1142,18 +1183,21 @@ def runtime_constraints(cls, *, spec, pkg): for fortran_virtual in ("fortran-rt", gfortran_str): pkg("*").depends_on( fortran_virtual, - when=f"%{str(spec)}", - languages=["fortran"], + when=f"^[virtuals=fortran deptypes=build] {spec.name}@{spec.versions}", type="link", description=f"Add a dependency on '{gfortran_str}' for nodes compiled with " f"{str(spec)} and using the 'fortran' language", ) # The version of gcc-runtime is the same as the %gcc used to "compile" it - pkg("gcc-runtime").requires(f"@={str(spec.version)}", when=f"%{str(spec)}") + pkg("gcc-runtime").requires( + f"@{str(spec.versions)}", when=f"^[deptypes=build] {spec.name}@{spec.versions}" + ) # If a node used %gcc@X.Y its dependencies must use gcc-runtime@:X.Y # (technically @:X is broader than ... <= @=X but this should work in practice) - pkg("*").propagate(f"%gcc@:{str(spec.version)}", when=f"%{str(spec)}") + pkg("*").propagate( + f"gcc@:{str(spec.version)}", when=f"^[deptypes=build] {spec.name}@{spec.versions}" + ) def _post_buildcache_install_hook(self): if not self.spec.satisfies("platform=linux"): diff --git a/var/spack/repos/builtin/packages/go/package.py b/var/spack/repos/builtin/packages/go/package.py index 753c26c4ae8..1ce16b226b6 100644 --- a/var/spack/repos/builtin/packages/go/package.py +++ b/var/spack/repos/builtin/packages/go/package.py @@ -88,6 +88,9 @@ class Go(Package): phases = ["build", "install"] + depends_on("c", type="build") + depends_on("cxx", type="build") + def url_for_version(self, version): return f"https://go.dev/dl/go{version}.src.tar.gz" @@ -101,8 +104,8 @@ def setup_build_environment(self, env): env.set("GOROOT_FINAL", self.spec.prefix.go) # We need to set CC/CXX_FOR_TARGET, otherwise cgo will use the # internal Spack wrappers and fail. - env.set("CC_FOR_TARGET", self.compiler.cc) - env.set("CXX_FOR_TARGET", self.compiler.cxx) + env.set("CC_FOR_TARGET", self.spec["c"].package.cc) + env.set("CXX_FOR_TARGET", self.spec["cxx"].package.cxx) env.set("GOMAXPROCS", make_jobs) def build(self, spec, prefix): diff --git a/var/spack/repos/builtin/packages/intel-oneapi-compilers-classic/package.py b/var/spack/repos/builtin/packages/intel-oneapi-compilers-classic/package.py index 71de26ed340..1e4117ef9bb 100644 --- a/var/spack/repos/builtin/packages/intel-oneapi-compilers-classic/package.py +++ b/var/spack/repos/builtin/packages/intel-oneapi-compilers-classic/package.py @@ -109,3 +109,27 @@ def symlink_dir(self, src, dest): link_tree.merge(dest_path) else: os.symlink(src_path, dest_path) + + @property + def cc(self): + msg = "cannot retrieve C compiler [spec is not concrete]" + assert self.spec.concrete, msg + if self.spec.external: + return self.spec.extra_attributes["compilers"].get("c", None) + raise NotImplementedError("FIXME (compiler as nodes): missing spack installed package") + + @property + def cxx(self): + msg = "cannot retrieve C++ compiler [spec is not concrete]" + assert self.spec.concrete, msg + if self.spec.external: + return self.spec.extra_attributes["compilers"].get("cxx", None) + raise NotImplementedError("FIXME (compiler as nodes): missing spack installed package") + + @property + def fortran(self): + msg = "cannot retrieve Fortran compiler [spec is not concrete]" + assert self.spec.concrete, msg + if self.spec.external: + return self.spec.extra_attributes["compilers"].get("fortran", None) + raise NotImplementedError("FIXME (compiler as nodes): missing spack installed package") diff --git a/var/spack/repos/builtin/packages/intel-oneapi-compilers/package.py b/var/spack/repos/builtin/packages/intel-oneapi-compilers/package.py index e3ec31d4b01..3fdce18bcf0 100644 --- a/var/spack/repos/builtin/packages/intel-oneapi-compilers/package.py +++ b/var/spack/repos/builtin/packages/intel-oneapi-compilers/package.py @@ -2,9 +2,11 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - import os +import os.path +import pathlib import platform +import warnings from spack.build_environment import dso_suffix from spack.package import * @@ -319,6 +321,45 @@ class IntelOneapiCompilers(IntelOneApiPackage, CompilerPackage): r"(?:(?:oneAPI DPC\+\+(?:\/C\+\+)? Compiler)|(?:\(IFORT\))|(?:\(IFX\))) (\S+)" ) + debug_flags = ["-debug", "-g", "-g0", "-g1", "-g2", "-g3"] + opt_flags = ["-O", "-O0", "-O1", "-O2", "-O3", "-Ofast", "-Os"] + + openmp_flag = "-fiopenmp" + + link_paths = { + "c": os.path.join("oneapi", "icx"), + "cxx": os.path.join("oneapi", "icpx"), + "fortran": os.path.join("oneapi", "ifx"), + } + + required_libs = [ + "libirc", + "libifcore", + "libifcoremt", + "libirng", + "libsvml", + "libintlc", + "libimf", + "libsycl", + "libOpenCL", + ] + + stdcxx_libs = ("-cxxlib",) + + provides("c", "cxx", "fortran") + + def _standard_flag(self, *, language, standard): + flags = { + "cxx": { + "11": "-std=c++11", + "14": "-std=c++14", + "17": "-std=c++17", + "20": "-std=c++20", + }, + "c": {"99": "-std=c99", "11": "-std=c1x"}, + } + return flags[language][standard] + # See https://github.com/spack/spack/issues/39252 depends_on("patchelf@:0.17", type="build", when="@:2024.1") # Add the nvidia variant @@ -327,10 +368,8 @@ class IntelOneapiCompilers(IntelOneApiPackage, CompilerPackage): # Add the amd variant variant("amd", default=False, description="Install AMD plugin for OneAPI") conflicts("@:2022.2.1", when="+amd", msg="Codeplay AMD plugin requires newer release") - # TODO: effectively gcc is a direct dependency of intel-oneapi-compilers, but we - # cannot express that properly. For now, add conflicts for non-gcc compilers - # instead. - requires("%gcc", msg="intel-oneapi-compilers must be installed with %gcc") + + depends_on("gcc languages=c,c++", type="run") for v in versions: version(v["version"], expand=False, **v["cpp"]) @@ -401,6 +440,31 @@ def setup_run_environment(self, env): env.set("F77", self._llvm_bin.ifx) env.set("FC", self._llvm_bin.ifx) + def setup_dependent_build_environment(self, env, dependent_spec): + super().setup_dependent_build_environment(env, dependent_spec) + # workaround bug in icpx driver where it requires sycl-post-link is on the PATH + # It is located in the same directory as the driver. Error message: + # clang++: error: unable to execute command: + # Executable "sycl-post-link" doesn't exist! + # also ensures that shared objects and libraries required by the compiler, + # e.g. libonnx, can be found succesfully + # due to a fix, this is no longer required for OneAPI versions >= 2024.2 + bin_dir = os.path.dirname(self.cxx) + lib_dir = os.path.join(os.path.dirname(bin_dir), "lib") + if self.cxx and self.spec.satisfies("%oneapi@:2024.1"): + env.prepend_path("PATH", bin_dir) + env.prepend_path("LD_LIBRARY_PATH", lib_dir) + + # 2024 release bumped the libsycl version because of an ABI + # change, 2024 compilers are required. You will see this + # error: + # + # /usr/bin/ld: warning: libsycl.so.7, needed by ...., not found + if self.spec.satisfies("%oneapi@:2023"): + for c in ["dnn"]: + if self.spec.satisfies(f"^intel-oneapi-{c}@2024:"): + warnings.warn(f"intel-oneapi-{c}@2024 SYCL APIs requires %oneapi@2024:") + def install(self, spec, prefix): # Copy instead of install to speed up debugging # install_tree("/opt/intel/oneapi/compiler", self.prefix) @@ -496,9 +560,9 @@ def extend_config_flags(self): common_flags = ["-Wl,-rpath,{}".format(d) for d in self._ld_library_path()] # Make sure that underlying clang gets the right GCC toolchain by default - llvm_flags = ["--gcc-toolchain={}".format(self.compiler.prefix)] - classic_flags = ["-gcc-name={}".format(self.compiler.cc)] - classic_flags.append("-gxx-name={}".format(self.compiler.cxx)) + gcc = self.spec["gcc"].package + llvm_flags = [f"--gcc-toolchain={gcc.prefix}"] + classic_flags = [f"-gcc-name={gcc.cc}", f"-gxx-name={gcc.cxx}"] # Older versions trigger -Wunused-command-line-argument warnings whenever # linker flags are passed in preprocessor (-E) or compilation mode (-c). @@ -533,6 +597,21 @@ def _ld_library_path(self): if find(p, "*." + dso_suffix, recursive=False): yield p + @classmethod + def determine_variants(cls, exes, version_str): + variant, extra_attributes = super().determine_variants(exes, version_str) + + bin_dirs = {pathlib.Path(x).parent for x in exes} + if len(bin_dirs) != 1: + dirs = ", ".join([str(x) for x in sorted(bin_dirs)]) + raise RuntimeError(f"executables found in multiple dirs: {dirs}") + bin_dir = bin_dirs.pop() + prefix_parts = bin_dir.parts[: bin_dir.parts.index("compiler")] + computed_prefix = pathlib.Path(*prefix_parts) + extra_attributes["prefix"] = str(computed_prefix) + + return variant, extra_attributes + @classmethod def runtime_constraints(cls, *, spec, pkg): pkg("*").depends_on( @@ -543,7 +622,7 @@ def runtime_constraints(cls, *, spec, pkg): ) pkg("*").depends_on( f"intel-oneapi-runtime@{str(spec.version)}:", - when=f"%{str(spec)}", + when=f"^[deptypes=build] {spec.name}@{spec.versions}", type="link", description=f"If any package uses %{str(spec)}, " f"it depends on intel-oneapi-runtime@{str(spec.version)}:", @@ -552,11 +631,43 @@ def runtime_constraints(cls, *, spec, pkg): for fortran_virtual in ("fortran-rt", "libifcore@5"): pkg("*").depends_on( fortran_virtual, - when=f"%{str(spec)}", - languages=["fortran"], + when=f"^[virtuals=fortran deptypes=build] {spec.name}@{spec.versions}", type="link", description=f"Add a dependency on 'libifcore' for nodes compiled with " f"{str(spec)} and using the 'fortran' language", ) # The version of intel-oneapi-runtime is the same as the %oneapi used to "compile" it - pkg("intel-oneapi-runtime").requires(f"@={str(spec.version)}", when=f"%{str(spec)}") + pkg("intel-oneapi-runtime").requires( + f"@{str(spec.versions)}", when=f"^[deptypes=build] {spec.name}@{spec.versions}" + ) + + # If a node used %intel-oneapi=runtime@X.Y its dependencies must use @:X.Y + # (technically @:X is broader than ... <= @=X but this should work in practice) + pkg("*").propagate( + f"intel-oneapi-compilers@:{str(spec.version)}", + when=f"^[deptypes=build] {spec.name}@{spec.versions}", + ) + + @property + def cc(self): + msg = "cannot retrieve C compiler [spec is not concrete]" + assert self.spec.concrete, msg + if self.spec.external: + return self.spec.extra_attributes["compilers"].get("c", None) + return str(self._llvm_bin.icx) + + @property + def cxx(self): + msg = "cannot retrieve C++ compiler [spec is not concrete]" + assert self.spec.concrete, msg + if self.spec.external: + return self.spec.extra_attributes["compilers"].get("cxx", None) + return str(self._llvm_bin.icpx) + + @property + def fortran(self): + msg = "cannot retrieve Fortran compiler [spec is not concrete]" + assert self.spec.concrete, msg + if self.spec.external: + return self.spec.extra_attributes["compilers"].get("fortran", None) + return str(self._llvm_bin.ifx) diff --git a/var/spack/repos/builtin/packages/intel-oneapi-runtime/package.py b/var/spack/repos/builtin/packages/intel-oneapi-runtime/package.py index 961a8e301cf..b7a9dae1c68 100644 --- a/var/spack/repos/builtin/packages/intel-oneapi-runtime/package.py +++ b/var/spack/repos/builtin/packages/intel-oneapi-runtime/package.py @@ -47,9 +47,11 @@ class IntelOneapiRuntime(Package): conflicts("platform=darwin", msg="IntelOneAPI can only be installed on Linux, and FreeBSD") depends_on("libc", type="link", when="platform=linux") + depends_on("intel-oneapi-compilers", type="build") def install(self, spec, prefix): - libraries = get_elf_libraries(compiler=self.compiler, libraries=self.LIBRARIES) + oneapi_pkg = self.spec["intel-oneapi-compilers"].package + libraries = get_elf_libraries(compiler=oneapi_pkg, libraries=self.LIBRARIES) mkdir(prefix.lib) if not libraries: diff --git a/var/spack/repos/builtin/packages/intel/package.py b/var/spack/repos/builtin/packages/intel/package.py index 51bae70edb1..3399ffb6124 100644 --- a/var/spack/repos/builtin/packages/intel/package.py +++ b/var/spack/repos/builtin/packages/intel/package.py @@ -6,7 +6,7 @@ import llnl.util.tty as tty -import spack.compiler +import spack.build_systems.compiler from spack.package import * @@ -237,7 +237,9 @@ class Intel(IntelPackage): def determine_version(cls, exe): version_regex = re.compile(r"\((?:IFORT|ICC)\) ([^ ]+)") try: - output = spack.compiler.get_compiler_version_output(exe, "--version") + output = spack.build_systems.compiler.compiler_output( + exe, version_argument="--version" + ) match = version_regex.search(output) if match: return match.group(1) diff --git a/var/spack/repos/builtin/packages/libxml2/package.py b/var/spack/repos/builtin/packages/libxml2/package.py index a07f0c1b6a7..0043aea7484 100644 --- a/var/spack/repos/builtin/packages/libxml2/package.py +++ b/var/spack/repos/builtin/packages/libxml2/package.py @@ -109,7 +109,7 @@ def url_for_version(self, version): def flag_handler(self, name, flags): if name == "cflags" and self.spec.satisfies("+pic"): - flags.append(self.compiler.cc_pic_flag) + flags.append(self.spec["c"].package.pic_flag) flags.append("-DPIC") return (flags, None, None) diff --git a/var/spack/repos/builtin/packages/llvm-amdgpu/package.py b/var/spack/repos/builtin/packages/llvm-amdgpu/package.py index ee9d5699ecc..84dcbb021ef 100644 --- a/var/spack/repos/builtin/packages/llvm-amdgpu/package.py +++ b/var/spack/repos/builtin/packages/llvm-amdgpu/package.py @@ -7,17 +7,23 @@ import shutil from spack.package import * +from spack.pkg.builtin.llvm import LlvmDetection -class LlvmAmdgpu(CMakePackage, CompilerPackage): +class LlvmAmdgpu(CMakePackage, LlvmDetection, CompilerPackage): """Toolkit for the construction of highly optimized compilers, optimizers, and run-time environments.""" homepage = "https://github.com/ROCm/llvm-project" git = "https://github.com/ROCm/llvm-project.git" url = "https://github.com/ROCm/llvm-project/archive/rocm-6.2.4.tar.gz" - tags = ["rocm"] + tags = ["rocm", "compiler"] executables = [r"amdclang", r"amdclang\+\+", r"amdflang", r"clang.*", r"flang.*", "llvm-.*"] + + link_paths = {"c": "rocmcc/amdclang", "cxx": "rocmcc/amdclang++", "fortran": "rocmcc/amdflang"} + + stdcxx_libs = ("-lstdc++",) + generator("ninja") maintainers("srekolam", "renjithravindrankannath", "haampie", "afzpatel") @@ -210,6 +216,15 @@ class LlvmAmdgpu(CMakePackage, CompilerPackage): when="@master", ) + stdcxx_libs = ("-lstdc++",) + + def _standard_flag(self, *, language, standard): + flags = { + "cxx": {"11": "-std=c++11", "14": "-std=c++14", "17": "-std=c++17"}, + "c": {"99": "-std=c99", "11": "-std=c1x"}, + } + return flags[language][standard] + def cmake_args(self): llvm_projects = ["clang", "lld", "clang-tools-extra", "compiler-rt"] llvm_runtimes = ["libcxx", "libcxxabi"] @@ -328,3 +343,27 @@ def setup_dependent_build_environment(self, env, dependent_spec): if "libclang_rt.asan-x86_64.so" in files: env.prepend_path("LD_LIBRARY_PATH", root) env.prune_duplicate_paths("LD_LIBRARY_PATH") + + @property + def cc(self): + msg = "cannot retrieve C compiler [spec is not concrete]" + assert self.spec.concrete, msg + if self.spec.external: + return self.spec.extra_attributes["compilers"].get("c", None) + return os.path.join(self.spec.prefix.bin, "amdclang") + + @property + def cxx(self): + msg = "cannot retrieve C++ compiler [spec is not concrete]" + assert self.spec.concrete, msg + if self.spec.external: + return self.spec.extra_attributes["compilers"].get("cxx", None) + return os.path.join(self.spec.prefix.bin, "amdclang++") + + @property + def fc(self): + msg = "cannot retrieve Fortran compiler [spec is not concrete]" + assert self.spec.concrete, msg + if self.spec.external: + return self.spec.extra_attributes["compilers"].get("fc", None) + return os.path.join(self.spec.prefix.bin, "amdflang") diff --git a/var/spack/repos/builtin/packages/llvm/package.py b/var/spack/repos/builtin/packages/llvm/package.py index d5abd0cb6fe..294a4b768f4 100644 --- a/var/spack/repos/builtin/packages/llvm/package.py +++ b/var/spack/repos/builtin/packages/llvm/package.py @@ -10,7 +10,6 @@ import llnl.util.tty as tty from llnl.util.lang import classproperty -import spack.compilers from spack.build_systems.cmake import get_cmake_prefix_path from spack.operating_systems.mac_os import macos_sdk_path from spack.package import * @@ -31,7 +30,7 @@ def filter_detected_exes(cls, prefix, exes_in_prefix): reject = re.compile( r"-(vscode|cpp|cl|ocl|gpu|tidy|rename|scan-deps|format|refactor|offload|" r"check|query|doc|move|extdef|apply|reorder|change-namespace|" - r"include-fixer|import-test|dap|server)" + r"include-fixer|import-test|dap|server|PerfectShuffle)" ) return [x for x in exes_in_prefix if not reject.search(x)] @@ -311,6 +310,9 @@ class Llvm(CMakePackage, CudaPackage, LlvmDetection, CompilerPackage): provides("libllvm@4", when="@4.0.0:4") provides("libllvm@3", when="@3.0.0:3") + provides("c", "cxx", when="+clang") + provides("fortran", when="+flang") + extends("python", when="+python") # Build dependency @@ -412,9 +414,9 @@ class Llvm(CMakePackage, CudaPackage, LlvmDetection, CompilerPackage): }, }.items(): with when(v): - for comp in spack.compilers.supported_compilers(): - conflicts("%{0}{1}".format(comp, compiler_conflicts.get(comp, ""))) - del v, compiler_conflicts, comp + for _name, _constraint in compiler_conflicts.items(): + conflicts(f"%{_name}{_constraint}") + del v, compiler_conflicts, _name, _constraint # libomptarget conflicts("+cuda", when="@15:") # +cuda variant is obselete since LLVM 15 @@ -777,6 +779,52 @@ def f77(self): result = os.path.join(self.spec.prefix.bin, "flang") return result + debug_flags = [ + "-gcodeview", + "-gdwarf-2", + "-gdwarf-3", + "-gdwarf-4", + "-gdwarf-5", + "-gline-tables-only", + "-gmodules", + "-g", + ] + + opt_flags = ["-O0", "-O1", "-O2", "-O3", "-Ofast", "-Os", "-Oz", "-Og", "-O", "-O4"] + + link_paths = { + "c": os.path.join("clang", "clang"), + "cxx": os.path.join("clang", "clang++"), + "fortran": os.path.join("clang", "flang"), + } + + required_libs = ["libclang"] + + def _standard_flag(self, *, language, standard): + flags = { + "cxx": { + "11": [("@3.3:", "-std=c++11")], + "14": [("@3.5:", "-std=c++14")], + "17": [("@3.5:4", "-std=c++1z"), ("@5:", "-std=c++17")], + "20": [("@5:10", "-std=c++2a"), ("@11:", "-std=c++20")], + "23": [("@12:16", "-std=c++2b"), ("@17:", "-std=c++23")], + }, + "c": { + "99": [("@:", "-std=c99")], + "11": [("@3.1:", "-std=c11")], + "17": [("@6:", "-std=c17")], + "23": [("@9:17", "-std=c2x"), ("@18:", "-std=c23")], + }, + } + for condition, flag in flags[language][standard]: + if self.spec.satisfies(condition): + return flag + else: + raise RuntimeError( + f"{self.spec} does not support the '{standard}' standard " + f"for the '{language}' language" + ) + @property def libs(self): return LibraryList(self.llvm_config("--libfiles", "all", result="list")) diff --git a/var/spack/repos/builtin/packages/lua-lpeg/package.py b/var/spack/repos/builtin/packages/lua-lpeg/package.py index 2615c4a9c8b..74816cd275e 100644 --- a/var/spack/repos/builtin/packages/lua-lpeg/package.py +++ b/var/spack/repos/builtin/packages/lua-lpeg/package.py @@ -36,6 +36,11 @@ class LuaLpeg(LuaPackage): depends_on("lua-lang@:5.1.9", when="@:0.12.1 ^[virtuals=lua-lang] lua") + @property + def libs(self): + libraries = [f"**/lua/{self.spec['lua-lang'].version.up_to(2)}/lpeg"] + return find_libraries(libraries, root=self.prefix) + class LuaBuilder(spack.build_systems.lua.LuaBuilder): # without this, the resulting library cannot be linked by a normal link phase, the diff --git a/var/spack/repos/builtin/packages/lua-luajit-openresty/package.py b/var/spack/repos/builtin/packages/lua-luajit-openresty/package.py index 1f8356270f2..fdeaaf22c54 100644 --- a/var/spack/repos/builtin/packages/lua-luajit-openresty/package.py +++ b/var/spack/repos/builtin/packages/lua-luajit-openresty/package.py @@ -36,7 +36,8 @@ class LuaLuajitOpenresty(LuaImplPackage): description="add symlinks to make lua-luajit a drop-in lua replacement", ) - provides("luajit", "lua-lang@5.1", when="+lualinks") + provides("luajit", "lua-lang", when="+lualinks") + provides("lua-lang@5.1", when="+lualinks") lua_version_override = "5.1" @run_after("install") diff --git a/var/spack/repos/builtin/packages/mapl/package.py b/var/spack/repos/builtin/packages/mapl/package.py index 831fcb67500..bbc4eaef8ae 100644 --- a/var/spack/repos/builtin/packages/mapl/package.py +++ b/var/spack/repos/builtin/packages/mapl/package.py @@ -5,7 +5,6 @@ import subprocess -import spack.compiler from spack.package import * @@ -360,11 +359,8 @@ def cmake_args(self): fflags = [] if self.compiler.name in ["gcc", "clang", "apple-clang"]: fflags.append("-ffree-line-length-none") - gfortran_major_ver = int( - spack.compiler.get_compiler_version_output(self.compiler.fc, "-dumpversion").split( - "." - )[0] - ) + + gfortran_major_ver = int(self.spec["fortran"].version[0]) if gfortran_major_ver >= 10: fflags.append("-fallow-invalid-boz") fflags.append("-fallow-argument-mismatch") diff --git a/var/spack/repos/builtin/packages/mpich/package.py b/var/spack/repos/builtin/packages/mpich/package.py index a1816d401af..e2fbf3392cd 100644 --- a/var/spack/repos/builtin/packages/mpich/package.py +++ b/var/spack/repos/builtin/packages/mpich/package.py @@ -7,7 +7,7 @@ import re import sys -import spack.compilers +import spack.compilers.config from spack.build_environment import dso_suffix from spack.package import * @@ -334,7 +334,7 @@ def determine_version(cls, exe): @classmethod def determine_variants(cls, exes, version): def get_spack_compiler_spec(compiler): - spack_compilers = spack.compilers.find_compilers([os.path.dirname(compiler)]) + spack_compilers = spack.compilers.config.find_compilers([os.path.dirname(compiler)]) actual_compiler = None # check if the compiler actually matches the one we want for spack_compiler in spack_compilers: @@ -493,25 +493,6 @@ def autoreconf(self, spec, prefix): bash = which("bash") bash("./autogen.sh") - @run_before("autoreconf") - def die_without_fortran(self): - # Until we can pass variants such as +fortran through virtual - # dependencies depends_on('mpi'), require Fortran compiler to - # avoid delayed build errors in dependents. - # The user can work around this by disabling Fortran explicitly - # with ~fortran - - f77 = self.compiler.f77 - fc = self.compiler.fc - - fortran_missing = f77 is None or fc is None - - if "+fortran" in self.spec and fortran_missing: - raise InstallError( - "mpich +fortran requires Fortran compilers. Configure " - "Fortran compiler or disable Fortran support with ~fortran" - ) - def configure_args(self): spec = self.spec config_args = [ @@ -541,8 +522,7 @@ def configure_args(self): ) ) - if "~fortran" in spec: - config_args.append("--disable-fortran") + config_args.extend(self.enable_or_disable("fortran")) if "+slurm" in spec: config_args.append("--with-slurm=yes") diff --git a/var/spack/repos/builtin/packages/msvc/package.py b/var/spack/repos/builtin/packages/msvc/package.py index 4d25b87118d..49b448b6828 100644 --- a/var/spack/repos/builtin/packages/msvc/package.py +++ b/var/spack/repos/builtin/packages/msvc/package.py @@ -2,9 +2,15 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import os.path import re +import subprocess -import spack.compiler +import archspec.cpu + +import spack.build_systems.compiler +import spack.platforms +import spack.version from spack.package import * @@ -27,13 +33,26 @@ def install(self, spec, prefix): compiler_version_argument = "" compiler_version_regex = r"([1-9][0-9]*\.[0-9]*\.[0-9]*)" + # Named wrapper links within build_env_path + # Due to the challenges of supporting compiler wrappers + # in Windows, we leave these blank, and dynamically compute + # based on proper versions of MSVC from there + # pending acceptance of #28117 for full support using + # compiler wrappers + link_paths = {"c": "", "cxx": "", "fortran": ""} + + provides("c", "cxx") + requires("platform=windows", msg="MSVC is only supported on Windows") + @classmethod def determine_version(cls, exe): # MSVC compiler does not have a proper version argument # Errors out and prints version info with no args match = re.search( cls.compiler_version_regex, - spack.compiler.get_compiler_version_output(exe, version_arg=None, ignore_errors=True), + spack.build_systems.compiler.compiler_output( + exe, version_argument=None, ignore_errors=1 + ), ) if match: return match.group(1) @@ -59,9 +78,164 @@ def cxx(self): msg = "cannot retrieve C++ compiler [spec is not concrete]" assert self.spec.concrete, msg + def setup_dependent_build_environment(self, env, dependent_spec): + self.init_msvc() + # Set the build environment variables for spack. Just using + # subprocess.call() doesn't work since that operates in its own + # environment which is destroyed (along with the adjusted variables) + # once the process terminates. So go the long way around: examine + # output, sort into dictionary, use that to make the build + # environment. + + # vcvars can target specific sdk versions, force it to pick up concretized sdk + # version, if needed by spec + if dependent_spec.name != "win-sdk" and "win-sdk" in dependent_spec: + self.vcvars_call.sdk_ver = dependent_spec["win-sdk"].version.string + + out = self.msvc_compiler_environment() + int_env = dict( + (key, value) + for key, _, value in (line.partition("=") for line in out.splitlines()) + if key and value + ) + + for env_var in int_env: + if os.pathsep not in int_env[env_var]: + env.set(env_var, int_env[env_var]) + else: + env.set_path(env_var, int_env[env_var].split(os.pathsep)) + + env.set("CC", self.cc) + env.set("CXX", self.cxx) + + def init_msvc(self): + # To use the MSVC compilers, VCVARS must be invoked + # VCVARS is located at a fixed location, referencable + # idiomatically by the following relative path from the + # compiler. + # Spack first finds the compilers via VSWHERE + # and stores their path, but their respective VCVARS + # file must be invoked before useage. + env_cmds = [] + compiler_root = os.path.join(os.path.dirname(self.cc), "../../../../../..") + vcvars_script_path = os.path.join(compiler_root, "Auxiliary", "Build", "vcvars64.bat") + # get current platform architecture and format for vcvars argument + arch = spack.platforms.real_host().default.lower() + arch = arch.replace("-", "_") + if str(archspec.cpu.host().family) == "x86_64": + arch = "amd64" + + msvc_version = spack.version.Version( + re.search(Msvc.compiler_version_regex, self.cc).group(1) + ) + self.vcvars_call = VCVarsInvocation(vcvars_script_path, arch, msvc_version) + env_cmds.append(self.vcvars_call) + self.msvc_compiler_environment = CmdCall(*env_cmds) + + def _standard_flag(self, *, language: str, standard: str) -> str: + flags = { + "cxx": { + "11": "/std:c++11", + "14": "/std:c++14", + "17": "/std:c++17", + "20": "/std:c++20", + }, + "c": {"11": "/std:c11", "17": "/std:c17"}, + } + return flags[language][standard] + + +class CmdCall: + """Compose a call to `cmd` for an ordered series of cmd commands/scripts""" + + def __init__(self, *cmds): + if not cmds: + raise RuntimeError( + """Attempting to run commands from CMD without specifying commands. + Please add commands to be run.""" + ) + self._cmds = cmds + + def __call__(self): + out = subprocess.check_output(self.cmd_line, stderr=subprocess.STDOUT) # novermin + return out.decode("utf-16le", errors="replace") # novermin + @property - def fortran(self): - if self.spec.external: - return self.spec.extra_attributes["compilers"]["fortran"] - msg = "cannot retrieve Fortran compiler [spec is not concrete]" - assert self.spec.concrete, msg + def cmd_line(self): + base_call = "cmd /u /c " + commands = " && ".join([x.command_str() for x in self._cmds]) + # If multiple commands are being invoked by a single subshell + # they must be encapsulated by a double quote. Always double + # quote to be sure of proper handling + # cmd will properly resolve nested double quotes as needed + # + # `set`` writes out the active env to the subshell stdout, + # and in this context we are always trying to obtain env + # state so it should always be appended + return base_call + f'"{commands} && set"' + + +class VarsInvocation: + def __init__(self, script): + self._script = script + + def command_str(self): + return f'"{self._script}"' + + @property + def script(self): + return self._script + + +class VCVarsInvocation(VarsInvocation): + def __init__(self, script, arch, msvc_version): + super(VCVarsInvocation, self).__init__(script) + self._arch = arch + self._msvc_version = msvc_version + + @property + def sdk_ver(self): + """Accessor for Windows SDK version property + + Note: This property may not be set by + the calling context and as such this property will + return an empty string + + This property will ONLY be set if the SDK package + is a dependency somewhere in the Spack DAG of the package + for which we are constructing an MSVC compiler env. + Otherwise this property should be unset to allow the VCVARS + script to use its internal heuristics to determine appropriate + SDK version + """ + if getattr(self, "_sdk_ver", None): + return self._sdk_ver + ".0" + return "" + + @sdk_ver.setter + def sdk_ver(self, val): + self._sdk_ver = val + + @property + def arch(self): + return self._arch + + @property + def vcvars_ver(self): + return f"-vcvars_ver={self._msvc_version}" + + def command_str(self): + script = super(VCVarsInvocation, self).command_str() + return f"{script} {self.arch} {self.sdk_ver} {self.vcvars_ver}" + + +FC_PATH = {} + + +def get_valid_fortran_pth(): + """Assign maximum available fortran compiler version""" + # TODO (johnwparent): validate compatibility w/ try compiler + # functionality when added + sort_fn = lambda fc_ver: spack.version.Version(fc_ver) + sort_fc_ver = sorted(list(FC_PATH.keys()), key=sort_fn) + return FC_PATH[sort_fc_ver[-1]] if sort_fc_ver else None diff --git a/var/spack/repos/builtin/packages/mvapich2/package.py b/var/spack/repos/builtin/packages/mvapich2/package.py index c0ff3bb07fa..648045e2b5b 100644 --- a/var/spack/repos/builtin/packages/mvapich2/package.py +++ b/var/spack/repos/builtin/packages/mvapich2/package.py @@ -7,7 +7,7 @@ import re import sys -import spack.compilers +import spack.compilers.config from spack.package import * @@ -172,7 +172,7 @@ def determine_version(cls, exe): @classmethod def determine_variants(cls, exes, version): def get_spack_compiler_spec(path): - spack_compilers = spack.compilers.find_compilers([path]) + spack_compilers = spack.compilers.config.find_compilers([path]) for spack_compiler in spack_compilers: if os.path.dirname(spack_compiler.cc) == path: return spack_compiler.spec diff --git a/var/spack/repos/builtin/packages/nag/package.py b/var/spack/repos/builtin/packages/nag/package.py index 2fc265268a5..88bc9f1b1a6 100644 --- a/var/spack/repos/builtin/packages/nag/package.py +++ b/var/spack/repos/builtin/packages/nag/package.py @@ -3,6 +3,7 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) import os +import os.path from spack.package import * @@ -73,6 +74,48 @@ def setup_run_environment(self, env): compiler_version_regex = r"NAG Fortran Compiler Release (\d+).(\d+)\(.*\) Build (\d+)" compiler_version_argument = "-V" + # Unlike other compilers, the NAG compiler passes options to GCC, which + # then passes them to the linker. Therefore, we need to doubly wrap the + # options with '-Wl,-Wl,,' + rpath_arg = "-Wl,-Wl,,-rpath,," + linker_arg = "-Wl,-Wl,," + disable_new_dtags = "" + enable_new_dtags = "" + debug_flags = ["-g", "-gline", "-g90"] + opt_flags = ["-O", "-O0", "-O1", "-O2", "-O3", "-O4"] + + link_paths = {"fortran": os.path.join("nag", "nagfor")} + + # NAG does not support a flag that would enable verbose output and + # compilation/linking at the same time (with either '-#' or '-dryrun' + # the compiler only prints the commands but does not run them). + # Therefore, the only thing we can do is to pass the '-v' argument to + # the underlying GCC. In order to get verbose output from the latter + # at both compile and linking stages, we need to call NAG with two + # additional flags: '-Wc,-v' and '-Wl,-v'. However, we return only + # '-Wl,-v' for the following reasons: + # 1) the interface of this method does not support multiple flags in + # the return value and, at least currently, verbose output at the + # linking stage has a higher priority for us; + # 2) NAG is usually mixed with GCC compiler, which also accepts + # '-Wl,-v' and produces meaningful result with it: '-v' is passed + # to the linker and the latter produces verbose output for the + # linking stage ('-Wc,-v', however, would break the compilation + # with a message from GCC that the flag is not recognized). + # + # This way, we at least enable the implicit rpath detection, which is + # based on compilation of a C file (see method + # spack.compiler._compile_dummy_c_source): in the case of a mixed + # NAG/GCC toolchain, the flag will be passed to g++ (e.g. + # 'g++ -Wl,-v ./main.c'), otherwise, the flag will be passed to nagfor + # (e.g. 'nagfor -Wl,-v ./main.c' - note that nagfor recognizes '.c' + # extension and treats the file accordingly). The list of detected + # rpaths will contain only GCC-related directories and rpaths to + # NAG-related directories are injected by nagfor anyway. + verbose_flag = "-Wl,-v" + + openmp_flag = "-openmp" + @property def fortran(self): msg = "cannot retrieve Fortran compiler [spec is not concrete]" diff --git a/var/spack/repos/builtin/packages/ncurses/package.py b/var/spack/repos/builtin/packages/ncurses/package.py index 6f3b424ae36..42f4c1d8a41 100644 --- a/var/spack/repos/builtin/packages/ncurses/package.py +++ b/var/spack/repos/builtin/packages/ncurses/package.py @@ -107,9 +107,9 @@ def setup_build_environment(self, env): def flag_handler(self, name, flags): if name == "cflags": - flags.append(self.compiler.cc_pic_flag) + flags.append(self.spec["c"].package.pic_flag) elif name == "cxxflags": - flags.append(self.compiler.cxx_pic_flag) + flags.append(self.spec["cxx"].package.pic_flag) # ncurses@:6.0 fails in definition of macro 'mouse_trafo' without -P if self.spec.satisfies("@:6.0 %gcc@5.0:"): @@ -119,7 +119,7 @@ def flag_handler(self, name, flags): # ncurses@:6.0 uses dynamic exception specifications not allowed in c++17 if self.spec.satisfies("@:5"): if name == "cxxflags": - flags.append(self.compiler.cxx14_flag) + flags.append(self.spec["cxx"].package.standard_flag(language="cxx", standard="14")) return (flags, None, None) diff --git a/var/spack/repos/builtin/packages/neovim/package.py b/var/spack/repos/builtin/packages/neovim/package.py index 5b7753876a9..70e8a08eb37 100644 --- a/var/spack/repos/builtin/packages/neovim/package.py +++ b/var/spack/repos/builtin/packages/neovim/package.py @@ -89,6 +89,7 @@ class Neovim(CMakePackage): ) # depend on virtual, lua-luajit-openresty preferred + depends_on("lua-lang") depends_on("luajit", when="~no_luajit") depends_on("lua-lang@5.1", when="+no_luajit") @@ -154,4 +155,7 @@ class Neovim(CMakePackage): @when("^lua") def cmake_args(self): - return [self.define("PREFER_LUA", True)] + return [ + self.define("PREFER_LUA", True), + self.define("LPEG_LIBRARY", self.spec["lua-lpeg"].libs), + ] diff --git a/var/spack/repos/builtin/packages/nvhpc/package.py b/var/spack/repos/builtin/packages/nvhpc/package.py index 4f03fe96af8..13b0d92a7e1 100644 --- a/var/spack/repos/builtin/packages/nvhpc/package.py +++ b/var/spack/repos/builtin/packages/nvhpc/package.py @@ -4,7 +4,7 @@ # SPDX-License-Identifier: (Apache-2.0 OR MIT) # # Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. - +import os.path import platform from spack.package import * @@ -438,9 +438,7 @@ class Nvhpc(Package, CompilerPackage): if pkg: version(ver, sha256=pkg[0], url=pkg[1]) - depends_on("c", type="build") # generated - depends_on("cxx", type="build") # generated - depends_on("fortran", type="build") # generated + depends_on("gcc languages=c,c++,fortran", type="run") variant("blas", default=True, description="Enable BLAS") variant( @@ -461,7 +459,8 @@ class Nvhpc(Package, CompilerPackage): provides("lapack", when="+lapack") provides("mpi", when="+mpi") - requires("%gcc", msg="nvhpc must be installed with %gcc") + provides("c", "cxx") + provides("fortran") # For now we only detect compiler components # It will require additional work to detect mpi/lapack/blas components @@ -472,6 +471,28 @@ class Nvhpc(Package, CompilerPackage): compiler_version_argument = "--version" compiler_version_regex = r"nv[^ ]* (?:[^ ]+ Dev-r)?([0-9.]+)(?:-[0-9]+)?" + debug_flags = ["-g", "-gopt"] + opt_flags = ["-O", "-O0", "-O1", "-O2", "-O3", "-O4"] + + pic_flag = "-fpic" + openmp_flag = "-mp" + + link_paths = { + "c": os.path.join("nvhpc", "nvc"), + "cxx": os.path.join("nvhpc", "nvc++"), + "fortran": os.path.join("nvhpc", "nvfortran"), + } + + required_libs = ["libnvc", "libnvf"] + stdcxx_libs = ("-c++libs",) + + def _standard_flag(self, *, language, standard): + flags = { + "cxx": {"11": "--c++11", "14": "--c++14", "17": "--c++17"}, + "c": {"99": "-c99", "11": "-c11"}, + } + return flags[language][standard] + @classmethod def determine_variants(cls, exes, version_str): # TODO: use other exes to determine default_cuda/install_type/blas/lapack/mpi variants @@ -501,11 +522,11 @@ def install(self, spec, prefix): makelocalrc_args = [ "-gcc", - self.compiler.cc, + spec["gcc"].package.cc, "-gpp", - self.compiler.cxx, + spec["gcc"].package.cxx, "-g77", - self.compiler.f77, + spec["gcc"].package.fortran, "-x", compilers_bin, ] diff --git a/var/spack/repos/builtin/packages/openmpi/package.py b/var/spack/repos/builtin/packages/openmpi/package.py index 889d9034354..99e403e3f27 100644 --- a/var/spack/repos/builtin/packages/openmpi/package.py +++ b/var/spack/repos/builtin/packages/openmpi/package.py @@ -11,7 +11,7 @@ import llnl.util.tty as tty -import spack.compilers +import spack.compilers.config import spack.version from spack.package import * @@ -399,9 +399,9 @@ class Openmpi(AutotoolsPackage, CudaPackage): "1.0", sha256="cf75e56852caebe90231d295806ac3441f37dc6d9ad17b1381791ebb78e21564" ) # libmpi.so.0.0.0 - depends_on("c", type="build") # generated - depends_on("cxx", type="build") # generated - depends_on("fortran", type="build") # generated + depends_on("c", type="build") + depends_on("cxx", type="build") + depends_on("fortran", type="build") patch("ad_lustre_rwcontig_open_source.patch", when="@1.6.5") patch("llnl-platforms.patch", when="@1.6.5") @@ -1285,7 +1285,7 @@ def filter_pc_files(self): # NAG compiler is usually mixed with GCC, which has a different # prefix for linker arguments. - if self.compiler.name == "nag": + if self.spec["fortran"].name == "nag": x.filter("-Wl,--enable-new-dtags", "", string=True, backup=False) # For v4 and lower @@ -1418,7 +1418,7 @@ def test_example(self): def get_spack_compiler_spec(compiler): - spack_compilers = spack.compilers.find_compilers([os.path.dirname(compiler)]) + spack_compilers = spack.compilers.config.find_compilers([os.path.dirname(compiler)]) actual_compiler = None # check if the compiler actually matches the one we want for spack_compiler in spack_compilers: diff --git a/var/spack/repos/builtin/packages/openssl/package.py b/var/spack/repos/builtin/packages/openssl/package.py index cf0e5544fb1..abf4414346a 100644 --- a/var/spack/repos/builtin/packages/openssl/package.py +++ b/var/spack/repos/builtin/packages/openssl/package.py @@ -157,7 +157,7 @@ def install(self, spec, prefix): if spec.satisfies("@1.0"): options.append("no-krb5") # clang does not support the .arch directive in assembly files. - if "clang" in self.compiler.cc and spec.target.family == "aarch64": + if "clang" in self.spec["c"].package.cc and spec.target.family == "aarch64": options.append("no-asm") elif "%nvhpc" in spec: # Last tested on nvidia@22.3 for x86_64: diff --git a/var/spack/repos/builtin/packages/perl/package.py b/var/spack/repos/builtin/packages/perl/package.py index 8b608e04d21..e17940558c4 100644 --- a/var/spack/repos/builtin/packages/perl/package.py +++ b/var/spack/repos/builtin/packages/perl/package.py @@ -335,7 +335,7 @@ def do_stage(self, mirror_only=False): def nmake_arguments(self): args = [] if self.spec.satisfies("%msvc"): - args.append("CCTYPE=%s" % self.compiler.short_msvc_version) + args.append("CCTYPE=%s" % self.spec["msvc"].package.short_msvc_version) else: raise RuntimeError("Perl unsupported for non MSVC compilers on Windows") args.append("INST_TOP=%s" % windows_sfn(self.prefix.replace("/", "\\"))) @@ -382,7 +382,7 @@ def configure_args(self): # https://github.com/spack/spack/pull/3081 and # https://github.com/spack/spack/pull/4416 if spec.satisfies("%intel"): - config_args.append("-Accflags={0}".format(self.compiler.cc_pic_flag)) + config_args.append("-Accflags={0}".format(self.spec["cc"].package.pic_flag)) if "+shared" in spec: config_args.append("-Duseshrplib") @@ -544,9 +544,10 @@ def filter_config_dot_pm(self): "-MModule::Loaded", "-MConfig", "-e", "print is_loaded(Config)", output=str ) + c_compiler = self.spec["c"].package.cc with self.make_briefly_writable(config_dot_pm): match = "cc *=>.*" - substitute = "cc => '{cc}',".format(cc=self.compiler.cc) + substitute = "cc => '{cc}',".format(cc=c_compiler) filter_file(match, substitute, config_dot_pm, **kwargs) # And the path Config_heavy.pl @@ -555,11 +556,11 @@ def filter_config_dot_pm(self): with self.make_briefly_writable(config_heavy): match = "^cc=.*" - substitute = "cc='{cc}'".format(cc=self.compiler.cc) + substitute = "cc='{cc}'".format(cc=c_compiler) filter_file(match, substitute, config_heavy, **kwargs) match = "^ld=.*" - substitute = "ld='{ld}'".format(ld=self.compiler.cc) + substitute = "ld='{ld}'".format(ld=c_compiler) filter_file(match, substitute, config_heavy, **kwargs) match = "^ccflags='" diff --git a/var/spack/repos/builtin/packages/python/package.py b/var/spack/repos/builtin/packages/python/package.py index 841b94b54c0..96c0c45cda0 100644 --- a/var/spack/repos/builtin/packages/python/package.py +++ b/var/spack/repos/builtin/packages/python/package.py @@ -566,7 +566,7 @@ def configure_args(self): config_args.append("--without-ensurepip") if "+pic" in spec: - cflags.append(self.compiler.cc_pic_flag) + cflags.append(self.spec["c"].package.pic_flag) if "+ssl" in spec: config_args.append("--with-openssl={0}".format(spec["openssl"].prefix)) @@ -684,9 +684,9 @@ def filter_compilers(self): filenames = [self.get_sysconfigdata_name(), self.config_vars["makefile_filename"]] - filter_file(spack_cc, self.compiler.cc, *filenames, **kwargs) - if spack_cxx and self.compiler.cxx: - filter_file(spack_cxx, self.compiler.cxx, *filenames, **kwargs) + filter_file(spack_cc, self.spec["c"].package.cc, *filenames, **kwargs) + if spack_cxx: + filter_file(spack_cxx, self.spec["cxx"].package.cxx, *filenames, **kwargs) @run_after("install") def symlink(self): @@ -1162,7 +1162,13 @@ def setup_dependent_build_environment(self, env, dependent_spec): # try to modify LDSHARED (LDCXXSHARED), the second variable, which is # used for linking, in a consistent manner. - for compile_var, link_var in [("CC", "LDSHARED"), ("CXX", "LDCXXSHARED")]: + for language, compile_var, link_var in [ + ("c", "CC", "LDSHARED"), + ("cxx", "CXX", "LDCXXSHARED"), + ]: + if not dependent_spec.dependencies(virtuals=(language,)): + continue + # First, we get the values from the sysconfigdata: config_compile = self.config_vars[compile_var] config_link = self.config_vars[link_var] @@ -1170,8 +1176,7 @@ def setup_dependent_build_environment(self, env, dependent_spec): # The dependent environment will have the compilation command set to # the following: new_compile = join_path( - spack.paths.build_env_path, - dependent_spec.package.compiler.link_paths[compile_var.lower()], + spack.paths.build_env_path, dependent_spec[language].package.link_paths[language] ) # Normally, the link command starts with the compilation command: diff --git a/var/spack/repos/builtin/packages/snappy/package.py b/var/spack/repos/builtin/packages/snappy/package.py index be67125417f..291f8985804 100644 --- a/var/spack/repos/builtin/packages/snappy/package.py +++ b/var/spack/repos/builtin/packages/snappy/package.py @@ -20,7 +20,8 @@ class Snappy(CMakePackage): version("1.1.8", sha256="16b677f07832a612b0836178db7f374e414f94657c138e6993cbfc5dcc58651f") version("1.1.7", sha256="3dfa02e873ff51a11ee02b9ca391807f0c8ea0529a4924afa645fbf97163f9d4") - depends_on("cxx", type="build") # generated + depends_on("c", type="build") + depends_on("cxx", type="build") variant("shared", default=True, description="Build shared libraries") variant("pic", default=True, description="Build position independent code") diff --git a/var/spack/repos/builtin/packages/spectrum-mpi/package.py b/var/spack/repos/builtin/packages/spectrum-mpi/package.py index e36be9826c7..ed4f4a28e29 100644 --- a/var/spack/repos/builtin/packages/spectrum-mpi/package.py +++ b/var/spack/repos/builtin/packages/spectrum-mpi/package.py @@ -5,7 +5,7 @@ import os import re -import spack.compilers +import spack.compilers.config from spack.package import * @@ -49,7 +49,7 @@ def get_host_compiler(exe): def get_spack_compiler_spec(compilers_found): # check using cc for now, as everyone should have that defined. path = os.path.dirname(compilers_found["cc"]) - spack_compilers = spack.compilers.find_compilers([path]) + spack_compilers = spack.compilers.config.find_compilers([path]) actual_compiler = None # check if the compiler actually matches the one we want for spack_compiler in spack_compilers: diff --git a/var/spack/repos/builtin/packages/taskflow/package.py b/var/spack/repos/builtin/packages/taskflow/package.py index 510509e5b5e..71d6cb2bb48 100644 --- a/var/spack/repos/builtin/packages/taskflow/package.py +++ b/var/spack/repos/builtin/packages/taskflow/package.py @@ -3,7 +3,7 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) -from spack.compiler import UnsupportedCompilerFlag +from spack.compilers.error import UnsupportedCompilerFlag from spack.package import * diff --git a/var/spack/repos/builtin/packages/tree/package.py b/var/spack/repos/builtin/packages/tree/package.py index e99c3437782..48efe590828 100644 --- a/var/spack/repos/builtin/packages/tree/package.py +++ b/var/spack/repos/builtin/packages/tree/package.py @@ -27,6 +27,8 @@ class Tree(Package): version("1.8.0", sha256="715d5d4b434321ce74706d0dd067505bb60c5ea83b5f0b3655dae40aa6f9b7c2") version("1.7.0", sha256="6957c20e82561ac4231638996e74f4cfa4e6faabc5a2f511f0b4e3940e8f7b12") + depends_on("c", type="build") + @when("@2:") def install(self, spec, prefix): make( diff --git a/var/spack/repos/builtin/packages/vasp/package.py b/var/spack/repos/builtin/packages/vasp/package.py index aa937bc4ab4..71fa53b16b3 100644 --- a/var/spack/repos/builtin/packages/vasp/package.py +++ b/var/spack/repos/builtin/packages/vasp/package.py @@ -87,7 +87,7 @@ class Vasp(MakefilePackage, CudaPackage): depends_on("nccl", when="@6.3: +cuda") depends_on("hdf5+fortran+mpi", when="+hdf5") # at the very least the nvhpc mpi seems required - depends_on("nvhpc+mpi+lapack+blas", when="%nvhpc") + requires("^nvhpc+mpi+lapack+blas", when="%nvhpc") conflicts( "%gcc@:8", msg="GFortran before 9.x does not support all features needed to build VASP" diff --git a/var/spack/repos/builtin/packages/win-file/package.py b/var/spack/repos/builtin/packages/win-file/package.py index 2196be842d5..10b8170cd21 100644 --- a/var/spack/repos/builtin/packages/win-file/package.py +++ b/var/spack/repos/builtin/packages/win-file/package.py @@ -23,6 +23,8 @@ class WinFile(Package): version("5.45", sha256="11b8f3abf647c711bc50ef8451c8d6e955f11c4afd8b0a98f2ac65e9b6e10d5e") + depends_on("c", type="build") + @classmethod def determine_version(cls, exe): output = Executable(exe)("--version", output=str, error=str) diff --git a/var/spack/repos/builtin/packages/win-gpg/package.py b/var/spack/repos/builtin/packages/win-gpg/package.py index f2fef7ff6dd..e6cfdc3f96f 100644 --- a/var/spack/repos/builtin/packages/win-gpg/package.py +++ b/var/spack/repos/builtin/packages/win-gpg/package.py @@ -24,6 +24,8 @@ class WinGpg(Package): version("2.4.5", sha256="249ab87bd06abea3140054089bad44d9a5d1531413590576da609142db2673ec") + depends_on("c", type="build") + @classmethod def determine_version(cls, exe): output = Executable(exe)("--version", output=str, error=str) diff --git a/var/spack/repos/builtin/packages/xl/package.py b/var/spack/repos/builtin/packages/xl/package.py index 379c35810be..98eb54912e0 100644 --- a/var/spack/repos/builtin/packages/xl/package.py +++ b/var/spack/repos/builtin/packages/xl/package.py @@ -2,6 +2,8 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import os.path + from spack.package import * @@ -15,6 +17,9 @@ class Xl(Package, CompilerPackage): variant("r", default=True, description="The _r version of compilers") + provides("c", "cxx") + provides("fortran") + def install(self, spec, prefix): raise InstallError( "XL compilers are not installable yet, but can be " @@ -28,6 +33,48 @@ def install(self, spec, prefix): compiler_version_argument = "-qversion" compiler_version_regex = r"([0-9]?[0-9]\.[0-9])" + pic_flag = "-qpic" + openmp_flag = "-qsmp=omp" + + debug_flags = ["-g", "-g0", "-g1", "-g2", "-g8", "-g9"] + opt_flags = ["-O", "-O0", "-O1", "-O2", "-O3", "-O4", "-O5", "-Ofast"] + verbose_flag = "-V" + + @property + def link_paths(self): + if self.spec.satisfies("~r"): + return { + "c": os.path.join("xl", "xlc"), + "cxx": os.path.join("xl", "xlc++"), + "fortran": os.path.join("xl", "xlf"), + } + + return { + "c": os.path.join("xl", "xlc_r"), + "cxx": os.path.join("xl", "xlc++_r"), + "fortran": os.path.join("xl", "xlf_r"), + } + + def _standard_flag(self, *, language, standard): + flags = { + "cxx": { + "11": [("@13.1:", "-qlanglvl=extended0x")], + "14": [("@16.1.1.8:", "-std=c++14")], + }, + "c": { + "99": [("@10.1:13.0", "-qlanglvl=extc99"), ("@13.1:", "-std=gnu99")], + "11": [("@12.1:13.1.1", "-qlanglvl=extc1x"), ("@13.1.2:", "-std=gnu11")], + }, + } + for condition, flag in flags[language][standard]: + if self.spec.satisfies(condition): + return flag + else: + raise RuntimeError( + f"{self.spec} does not support the '{standard}' standard " + f"for the '{language}' language" + ) + @classmethod def determine_variants(cls, exes, version_str): _r_exes = [e for e in exes if e.endswith("_r")] diff --git a/var/spack/repos/builtin/packages/yafyaml/package.py b/var/spack/repos/builtin/packages/yafyaml/package.py index 379fff05abe..447e77722b0 100644 --- a/var/spack/repos/builtin/packages/yafyaml/package.py +++ b/var/spack/repos/builtin/packages/yafyaml/package.py @@ -4,9 +4,7 @@ # SPDX-License-Identifier: (Apache-2.0 OR MIT) import os -import re -import spack.compiler from spack.package import * @@ -65,35 +63,8 @@ class Yafyaml(CMakePackage): msg="yaFyaml only works with the Fujitsu compiler from 1.3.0 onwards", ) - # GCC 13.3 and higher only work with yafyaml 1.4.0 onwards - # First we can check if the spec is gcc@13.3... conflicts("%gcc@13.3:", when="@:1.3.0", msg="GCC 13.3+ only works with yafyaml 1.4.0 onwards") - # ...but if it is not (say apple-clang with gfortran as a fc), there is - # no easy way to check this. So we hijack flag_handler to raise an - # exception if we detect gfortran 13.3 or 14. - # NOTE: This will only error out at install time, so `spack spec` will - # not catch this. - def flag_handler(self, name, flags): - # We need to match any compiler that has a name of gfortran or gfortran-* - pattern = re.compile(r"gfortran(-\d+)?$") - - if pattern.search(self.compiler.fc): - gfortran_version = spack.compiler.get_compiler_version_output( - self.compiler.fc, "-dumpfullversion" - ).strip() - - # gfortran_version is now a string like "13.3.0". We now need to just capture - # the major and minor version numbers - gfortran_version = ".".join(gfortran_version.split(".")[:2]) - - if self.spec.satisfies("@:1.3.0") and (float(gfortran_version) >= 13.3): - raise InstallError( - f"Your gfortran version {gfortran_version} is not compatible with " - f"yafyaml 1.3.0 and below. Use yafyaml 1.4.0 or higher." - ) - return None, None, None - variant( "build_type", default="Release", diff --git a/var/spack/repos/builtin/packages/zlib-ng/package.py b/var/spack/repos/builtin/packages/zlib-ng/package.py index 40de58f4e0b..561a0d977db 100644 --- a/var/spack/repos/builtin/packages/zlib-ng/package.py +++ b/var/spack/repos/builtin/packages/zlib-ng/package.py @@ -70,7 +70,7 @@ def libs(self): def flag_handler(self, name, flags): if name == "cflags" and self.spec.satisfies("+pic build_system=autotools"): - flags.append(self.compiler.cc_pic_flag) + flags.append(self.spec["c"].package.pic_flag) return (flags, None, None)