diff --git a/var/spack/repos/builtin/packages/acfl/package.py b/var/spack/repos/builtin/packages/acfl/package.py index 84f7d7d3767..556f0d781cf 100644 --- a/var/spack/repos/builtin/packages/acfl/package.py +++ b/var/spack/repos/builtin/packages/acfl/package.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) import os +import os.path import spack.platforms from spack.package import * @@ -356,6 +357,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") + depends_on("gmake", type="build") # Licensing - Not required from 22.0.1 on. @@ -377,6 +383,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]" @@ -464,6 +487,9 @@ def setup_run_environment(self, env): env.prepend_path("LIBRARY_PATH", join_path(arm_dir, "lib")) env.prepend_path("MANPATH", join_path(arm_dir, "share", "man")) + def archspec_name(self): + return "arm" + @run_after("install") def check_install(self): arm_dir = get_acfl_prefix(self.spec) diff --git a/var/spack/repos/builtin/packages/aocc/package.py b/var/spack/repos/builtin/packages/aocc/package.py index 242895a3cad..542cc723494 100644 --- a/var/spack/repos/builtin/packages/aocc/package.py +++ b/var/spack/repos/builtin/packages/aocc/package.py @@ -1,7 +1,7 @@ # Copyright Spack Project Developers. See 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 @@ -60,6 +60,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" @@ -114,3 +117,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 a4636a9ee0e..17293d6672b 100644 --- a/var/spack/repos/builtin/packages/apple-clang/package.py +++ b/var/spack/repos/builtin/packages/apple-clang/package.py @@ -1,6 +1,8 @@ # Copyright Spack Project Developers. See COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import os + from spack.package import * from spack.pkg.builtin.llvm import LlvmDetection @@ -16,6 +18,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") + requires("platform=darwin") @classmethod @@ -38,3 +48,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 b758f0dbb58..77cf566d72a 100644 --- a/var/spack/repos/builtin/packages/armpl-gcc/package.py +++ b/var/spack/repos/builtin/packages/armpl-gcc/package.py @@ -4,7 +4,6 @@ import os -import spack.error import spack.platforms from spack.package import * @@ -406,6 +405,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") + depends_on("gmake", type="build") # Run the installer with the desired install directory @@ -431,8 +434,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 358ae60f7cc..ce2a66a0ed9 100644 --- a/var/spack/repos/builtin/packages/blt/package.py +++ b/var/spack/repos/builtin/packages/blt/package.py @@ -22,7 +22,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 @@ -37,7 +37,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 23323803005..86105b8ce95 100644 --- a/var/spack/repos/builtin/packages/cce/package.py +++ b/var/spack/repos/builtin/packages/cce/package.py @@ -1,6 +1,8 @@ # Copyright Spack Project Developers. See COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import os.path + from spack.package import * @@ -20,10 +22,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 32b3933fb41..de167f08539 100644 --- a/var/spack/repos/builtin/packages/claw/package.py +++ b/var/spack/repos/builtin/packages/claw/package.py @@ -1,11 +1,6 @@ # Copyright Spack Project Developers. See COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - -import os - -import spack.compilers -import spack.spec from spack.package import * @@ -87,8 +82,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) @@ -105,25 +98,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 4c448043099..3b1ac8c8a4c 100644 --- a/var/spack/repos/builtin/packages/clingo/package.py +++ b/var/spack/repos/builtin/packages/clingo/package.py @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) -from spack.compiler import UnsupportedCompilerFlag +from spack.compilers.error import UnsupportedCompilerFlag from spack.package import * @@ -38,8 +38,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") @@ -100,7 +100,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 a2b70d4eec3..6fc0ce5765f 100644 --- a/var/spack/repos/builtin/packages/cmake/package.py +++ b/var/spack/repos/builtin/packages/cmake/package.py @@ -243,16 +243,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/cray-mpich/package.py b/var/spack/repos/builtin/packages/cray-mpich/package.py index 485ca4da6eb..af45cde0402 100644 --- a/var/spack/repos/builtin/packages/cray-mpich/package.py +++ b/var/spack/repos/builtin/packages/cray-mpich/package.py @@ -79,10 +79,15 @@ def setup_run_environment(self, env): self.setup_mpi_wrapper_variables(env) return - env.set("MPICC", self.compiler.cc) - env.set("MPICXX", self.compiler.cxx) - env.set("MPIFC", self.compiler.fc) - env.set("MPIF77", self.compiler.f77) + if self.spec.dependencies(virtuals=("c",)): + env.set("MPICC", self.spec["c"].package.cc) + + if self.spec.dependencies(virtuals=("cxx",)): + env.set("MPICXX", self.spec["cxx"].package.cxx) + + if self.spec.dependencies(virtuals=("fortran",)): + env.set("MPIFC", self.spec["fortran"].package.fc) + env.set("MPIF77", self.spec["fortran"].package.fc) def setup_dependent_package(self, module, dependent_spec): spec = self.spec diff --git a/var/spack/repos/builtin/packages/cray-mvapich2/package.py b/var/spack/repos/builtin/packages/cray-mvapich2/package.py index f362b89503c..5c2da4c7b7e 100644 --- a/var/spack/repos/builtin/packages/cray-mvapich2/package.py +++ b/var/spack/repos/builtin/packages/cray-mvapich2/package.py @@ -29,10 +29,15 @@ class CrayMvapich2(MpichEnvironmentModifications, Package): requires("platform=linux", msg="Cray MVAPICH2 is only available on Cray") def setup_run_environment(self, env): - env.set("MPICC", self.compiler.cc) - env.set("MPICXX", self.compiler.cxx) - env.set("MPIFC", self.compiler.fc) - env.set("MPIF77", self.compiler.f77) + if self.spec.dependencies(virtuals=("c",)): + env.set("MPICC", self.spec["c"].package.cc) + + if self.spec.dependencies(virtuals=("cxx",)): + env.set("MPICXX", self.spec["cxx"].package.cxx) + + if self.spec.dependencies(virtuals=("fortran",)): + env.set("MPIFC", self.spec["fortran"].package.fc) + env.set("MPIF77", self.spec["fortran"].package.fc) def install(self, spec, prefix): raise InstallError( diff --git a/var/spack/repos/builtin/packages/cuda/package.py b/var/spack/repos/builtin/packages/cuda/package.py index 72dd1cc5604..1743adcd82f 100644 --- a/var/spack/repos/builtin/packages/cuda/package.py +++ b/var/spack/repos/builtin/packages/cuda/package.py @@ -727,7 +727,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 000d345ceec..daf88e61041 100644 --- a/var/spack/repos/builtin/packages/cxx/package.py +++ b/var/spack/repos/builtin/packages/cxx/package.py @@ -4,8 +4,6 @@ import os -import spack.compilers -import spack.spec from spack.package import * @@ -17,25 +15,14 @@ class Cxx(Package): def test_cxx(self): """Compile and run 'Hello World'""" - cxx = which(os.environ["CXX"]) expected = ["Hello world", "YES!"] - + cxx = Executable(self.cxx) test_source = self.test_suite.current_test_data_dir for test in os.listdir(test_source): exe_name = f"{test}.exe" - filepath = test_source.join(test) 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 - 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) - compiler = c_cls(c_spec, None, None, ["fakecc", "fakecxx"]) - cxx_opts = [compiler.cxx11_flag] if "c++11" in test else [] - cxx_opts += ["-o", exe_name, filepath] - - cxx(*cxx_opts) + filepath = join_path(test_source, test) + cxx("-o", exe_name, filepath) exe = which(exe_name) out = exe(output=str.split, error=str.split) check_outputs(expected, out) diff --git a/var/spack/repos/builtin/packages/dealii/package.py b/var/spack/repos/builtin/packages/dealii/package.py index c75ccfe3de0..1f55d7e87e6 100644 --- a/var/spack/repos/builtin/packages/dealii/package.py +++ b/var/spack/repos/builtin/packages/dealii/package.py @@ -54,9 +54,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( @@ -685,7 +685,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 0b4da2bcaed..ea4257c94d5 100644 --- a/var/spack/repos/builtin/packages/esmf/package.py +++ b/var/spack/repos/builtin/packages/esmf/package.py @@ -7,7 +7,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,29 +258,16 @@ 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"]: - if "flang" in self.pkg.compiler.fc: - env.set("ESMF_COMPILER", "llvm") - elif "gfortran" in self.pkg.compiler.fc: - 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] - ) - else: - raise InstallError("Unsupported C/C++/Fortran compiler combination") + 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") + elif spec["fortran"].name == "llvm": + env.set("ESMF_COMPILER", "llvm") 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 3f0898330f0..56b874e7112 100644 --- a/var/spack/repos/builtin/packages/fj/package.py +++ b/var/spack/repos/builtin/packages/fj/package.py @@ -1,6 +1,8 @@ # Copyright Spack Project Developers. See COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import os.path + from spack.package import * @@ -14,6 +16,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 " @@ -26,3 +31,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 95680003b7a..8edc4ae35e4 100644 --- a/var/spack/repos/builtin/packages/gcc-runtime/package.py +++ b/var/spack/repos/builtin/packages/gcc-runtime/package.py @@ -27,8 +27,6 @@ class GccRuntime(Package): license("GPL-3.0-or-later WITH GCC-exception-3.1") - requires("%gcc") - LIBRARIES = [ "asan", "atomic", @@ -47,15 +45,18 @@ class GccRuntime(Package): # libgfortran ABI provides("fortran-rt", "libgfortran") - provides("libgfortran@3", when="%gcc@:6") - provides("libgfortran@4", when="%gcc@7") - provides("libgfortran@5", when="%gcc@8:") + provides("libgfortran@3", when="@:6") + provides("libgfortran@4", when="@7") + provides("libgfortran@5", when="@8:") depends_on("libc", type="link", when="platform=linux") + depends_on("gcc", type="build") + def install(self, spec, prefix): + gcc_pkg = self["gcc"] 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: @@ -75,7 +76,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 f220d8f5f3d..dfb929d8723 100644 --- a/var/spack/repos/builtin/packages/gcc/package.py +++ b/var/spack/repos/builtin/packages/gcc/package.py @@ -9,7 +9,7 @@ from llnl.util.symlink import readlink -import spack.compiler +import spack.build_systems.compiler import spack.platforms import spack.repo import spack.util.libc @@ -32,9 +32,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") @@ -594,7 +594,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++"] @@ -605,6 +610,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. @@ -612,7 +651,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: @@ -1157,7 +1198,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)}:", @@ -1172,18 +1213,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/glibc/package.py b/var/spack/repos/builtin/packages/glibc/package.py index 3e2130a217e..46d851c5d5f 100644 --- a/var/spack/repos/builtin/packages/glibc/package.py +++ b/var/spack/repos/builtin/packages/glibc/package.py @@ -111,6 +111,8 @@ class Glibc(AutotoolsPackage, GNUMirrorPackage): # include_next not working patch("67fbfa5.patch", when="@:2.7") + conflicts("musl") + def setup_build_environment(self, env): if self.spec.satisfies("@:2.21"): env.append_flags("LDFLAGS", "-no-pie") diff --git a/var/spack/repos/builtin/packages/go/package.py b/var/spack/repos/builtin/packages/go/package.py index db4f7ca2482..3d3a2bf64ac 100644 --- a/var/spack/repos/builtin/packages/go/package.py +++ b/var/spack/repos/builtin/packages/go/package.py @@ -83,6 +83,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" @@ -95,8 +98,8 @@ def determine_version(cls, exe): def setup_build_environment(self, env): # 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 f6dcbec83ec..60727f3ace4 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 @@ -108,3 +108,30 @@ 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) + return str(self.prefix.bin.icc) + + @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.prefix.bin.icpc) + + @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.prefix.bin.ifort) + + def archspec_name(self): + return "intel" 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 4e7dfdf634e..e55a39afa32 100644 --- a/var/spack/repos/builtin/packages/intel-oneapi-compilers/package.py +++ b/var/spack/repos/builtin/packages/intel-oneapi-compilers/package.py @@ -1,9 +1,11 @@ # Copyright Spack Project Developers. See 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 * @@ -329,6 +331,47 @@ 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") + provides("cxx") + provides("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 @@ -337,10 +380,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"]) @@ -419,6 +460,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) @@ -514,9 +580,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). @@ -551,6 +617,24 @@ def _ld_library_path(self): if find(p, "*." + dso_suffix, recursive=False): yield p + def archspec_name(self): + return "oneapi" + + @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( @@ -561,7 +645,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)}:", @@ -570,11 +654,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-mpi/package.py b/var/spack/repos/builtin/packages/intel-oneapi-mpi/package.py index 609ba05c167..29c1d0ce303 100644 --- a/var/spack/repos/builtin/packages/intel-oneapi-mpi/package.py +++ b/var/spack/repos/builtin/packages/intel-oneapi-mpi/package.py @@ -200,11 +200,17 @@ def setup_dependent_package(self, module, dep_spec): def setup_dependent_build_environment(self, env, dependent_spec): dependent_module = dependent_spec.package.module - env.set("I_MPI_CC", dependent_module.spack_cc) - env.set("I_MPI_CXX", dependent_module.spack_cxx) - env.set("I_MPI_F77", dependent_module.spack_f77) - env.set("I_MPI_F90", dependent_module.spack_fc) - env.set("I_MPI_FC", dependent_module.spack_fc) + for var_name, attr_name in ( + ("I_MPI_CC", "spack_cc"), + ("I_MPI_CXX", "spack_cxx"), + ("I_MPI_FC", "spack_fc"), + ("I_MPI_F90", "spack_fc"), + ("I_MPI_F77", "spack_f77"), + ): + if not hasattr(dependent_module, attr_name): + continue + + env.set(var_name, getattr(dependent_module, attr_name)) # Set compiler wrappers for dependent build stage wrappers = self.wrapper_paths() 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 2ff2e5b1889..d4548efc48e 100644 --- a/var/spack/repos/builtin/packages/intel-oneapi-runtime/package.py +++ b/var/spack/repos/builtin/packages/intel-oneapi-runtime/package.py @@ -19,8 +19,7 @@ class IntelOneapiRuntime(Package): tags = ["runtime"] - requires("%oneapi") - + depends_on("intel-oneapi-compilers", type="build") depends_on("gcc-runtime", type="link") LIBRARIES = [ @@ -46,7 +45,8 @@ class IntelOneapiRuntime(Package): depends_on("libc", type="link", when="platform=linux") 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 5e4159d8f99..67c3dddfaf2 100644 --- a/var/spack/repos/builtin/packages/intel/package.py +++ b/var/spack/repos/builtin/packages/intel/package.py @@ -3,7 +3,9 @@ # SPDX-License-Identifier: (Apache-2.0 OR MIT) import re -import spack.compiler +import llnl.util.tty as tty + +import spack.build_systems.compiler from spack.package import * @@ -234,7 +236,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 baf0672cd80..724236b2705 100644 --- a/var/spack/repos/builtin/packages/libxml2/package.py +++ b/var/spack/repos/builtin/packages/libxml2/package.py @@ -110,7 +110,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 1b887702295..c93ba1890c2 100644 --- a/var/spack/repos/builtin/packages/llvm-amdgpu/package.py +++ b/var/spack/repos/builtin/packages/llvm-amdgpu/package.py @@ -6,17 +6,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") @@ -215,6 +221,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"] @@ -338,3 +353,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 ba6606d9d1c..5f81c4d0525 100644 --- a/var/spack/repos/builtin/packages/llvm/package.py +++ b/var/spack/repos/builtin/packages/llvm/package.py @@ -7,7 +7,6 @@ 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 * @@ -394,6 +393,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 @@ -495,9 +497,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 @@ -875,6 +877,55 @@ 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" + ) + + def archspec_name(self): + return "clang" + @property def libs(self): return LibraryList(self.llvm_config("--libfiles", "all", result="list")) diff --git a/var/spack/repos/builtin/packages/mapl/package.py b/var/spack/repos/builtin/packages/mapl/package.py index bfe8e3f1eb6..8393aad514c 100644 --- a/var/spack/repos/builtin/packages/mapl/package.py +++ b/var/spack/repos/builtin/packages/mapl/package.py @@ -4,7 +4,6 @@ import subprocess -import spack.compiler from spack.package import * @@ -256,9 +255,7 @@ class Mapl(CMakePackage): # MAPL can use ifx only from MAPL 2.51 onwards and only supports # ifx 2025.0 and newer due to bugs in ifx. conflicts("%oneapi@2025:", when="@:2.50") - # NOTE there is a further check on oneapi in the cmake_args below - # that is hard to conflict since we don't know the fortran compiler - # at this point + conflicts("^[virtuals=fortran] intel-oneapi-compilers") variant("flap", default=False, description="Build with FLAP support", when="@:2.39") variant("pflogger", default=True, description="Build with pFlogger support") @@ -381,33 +378,14 @@ 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") if fflags: args.append(self.define("CMAKE_Fortran_FLAGS", " ".join(fflags))) - # If oneapi@:2024 is used and it gets past the conflict above, we might be - # using ifx or ifort. If we are using ifx and the MAPL version is 2.50 or older - # we need to raise an error - - if self.spec.satisfies("@:2.50 %oneapi@:2024"): - # We now need to get which Fortran compiler is used here but there - # isn't an easy way like: - # if self.spec["fortran"].name == "ifx": - # yet (see https://github.com/spack/spack/pull/45189) - # So we need to parse the output of $FC --version - output = spack.compiler.get_compiler_version_output( - self.compiler.fc, "-diag-disable=10448 --version", ignore_errors=True - ) - if "ifx" in output: - raise InstallError("MAPL versions 2.50 and older do not support ifx") - # Scripts often need to know the MPI stack used to setup the environment. # Normally, we can autodetect this, but building with Spack does not # seem to work. We need to pass in the MPI stack used to CMake diff --git a/var/spack/repos/builtin/packages/mpich/package.py b/var/spack/repos/builtin/packages/mpich/package.py index 817d6fb6267..baac23c1616 100644 --- a/var/spack/repos/builtin/packages/mpich/package.py +++ b/var/spack/repos/builtin/packages/mpich/package.py @@ -6,7 +6,7 @@ import re import sys -import spack.compilers +import spack.compilers.config import spack.package_base from spack.package import * @@ -383,7 +383,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: @@ -509,25 +509,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 = [ diff --git a/var/spack/repos/builtin/packages/msvc/package.py b/var/spack/repos/builtin/packages/msvc/package.py index ec365721b1e..f6677829627 100644 --- a/var/spack/repos/builtin/packages/msvc/package.py +++ b/var/spack/repos/builtin/packages/msvc/package.py @@ -1,9 +1,15 @@ # Copyright Spack Project Developers. See 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 * @@ -26,13 +32,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) @@ -58,9 +77,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/musl/package.py b/var/spack/repos/builtin/packages/musl/package.py index 516f538b16e..9ec77c895b0 100644 --- a/var/spack/repos/builtin/packages/musl/package.py +++ b/var/spack/repos/builtin/packages/musl/package.py @@ -48,6 +48,8 @@ class Musl(MakefilePackage): depends_on("c", type="build") # generated + conflicts("glibc") + def patch(self): config = FileFilter("configure") if self.compiler.name == "gcc": diff --git a/var/spack/repos/builtin/packages/mvapich2/package.py b/var/spack/repos/builtin/packages/mvapich2/package.py index f4f242965b3..2c704891966 100644 --- a/var/spack/repos/builtin/packages/mvapich2/package.py +++ b/var/spack/repos/builtin/packages/mvapich2/package.py @@ -6,7 +6,7 @@ import re import sys -import spack.compilers +import spack.compilers.config from spack.package import * from spack.pkg.builtin.mpich import MpichEnvironmentModifications @@ -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 74482793320..cca7669e363 100644 --- a/var/spack/repos/builtin/packages/nag/package.py +++ b/var/spack/repos/builtin/packages/nag/package.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) import os +import os.path from spack.package import * @@ -72,6 +73,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 6a800f41f6b..451d1cc73fc 100644 --- a/var/spack/repos/builtin/packages/ncurses/package.py +++ b/var/spack/repos/builtin/packages/ncurses/package.py @@ -106,9 +106,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:"): @@ -118,7 +118,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/nvhpc/package.py b/var/spack/repos/builtin/packages/nvhpc/package.py index fe530a289ae..e7b53da0b6e 100644 --- a/var/spack/repos/builtin/packages/nvhpc/package.py +++ b/var/spack/repos/builtin/packages/nvhpc/package.py @@ -3,7 +3,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 * @@ -446,9 +446,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( @@ -469,7 +467,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 @@ -480,6 +479,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 @@ -509,11 +530,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/openfoam/package.py b/var/spack/repos/builtin/packages/openfoam/package.py index 90cb3c784ff..2eb1770cdd5 100644 --- a/var/spack/repos/builtin/packages/openfoam/package.py +++ b/var/spack/repos/builtin/packages/openfoam/package.py @@ -918,7 +918,12 @@ class OpenfoamArch: #: Map spack compiler names to OpenFOAM compiler names # By default, simply capitalize the first letter - compiler_mapping = {"aocc": "Amd", "fj": "Fujitsu", "intel": "Icc", "oneapi": "Icx"} + compiler_mapping = { + "aocc": "Amd", + "fj": "Fujitsu", + "intel": "Icc", + "intel-oneapi-compilers": "Icx", + } def __init__(self, spec, **kwargs): # Some user settings, to be adjusted manually or via variants diff --git a/var/spack/repos/builtin/packages/openmpi/package.py b/var/spack/repos/builtin/packages/openmpi/package.py index 6591f04bae5..14836bd1fb6 100644 --- a/var/spack/repos/builtin/packages/openmpi/package.py +++ b/var/spack/repos/builtin/packages/openmpi/package.py @@ -7,7 +7,9 @@ import re import sys -import spack.compilers +import llnl.util.tty as tty + +import spack.compilers.config from spack.package import * @@ -898,10 +900,16 @@ def setup_run_environment(self, env): def setup_dependent_build_environment(self, env, dependent_spec): # Use the spack compiler wrappers under MPI dependent_module = dependent_spec.package.module - env.set("OMPI_CC", dependent_module.spack_cc) - env.set("OMPI_CXX", dependent_module.spack_cxx) - env.set("OMPI_FC", dependent_module.spack_fc) - env.set("OMPI_F77", dependent_module.spack_f77) + for var_name, attr_name in ( + ("OMPI_CC", "spack_cc"), + ("OMPI_CXX", "spack_cxx"), + ("OMPI_FC", "spack_fc"), + ("OMPI_F77", "spack_f77"), + ): + if not hasattr(dependent_module, attr_name): + continue + + env.set(var_name, getattr(dependent_module, attr_name)) # See https://www.open-mpi.org/faq/?category=building#installdirs for suffix in [ @@ -1351,7 +1359,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 27cddb8d36f..f08ebbadb0e 100644 --- a/var/spack/repos/builtin/packages/openssl/package.py +++ b/var/spack/repos/builtin/packages/openssl/package.py @@ -154,7 +154,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 3f8e1605826..835b5ae89bd 100644 --- a/var/spack/repos/builtin/packages/perl/package.py +++ b/var/spack/repos/builtin/packages/perl/package.py @@ -337,7 +337,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("/", "\\"))) @@ -384,7 +384,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") @@ -546,9 +546,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 @@ -557,11 +558,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 c380f24b57a..143b094f7bc 100644 --- a/var/spack/repos/builtin/packages/python/package.py +++ b/var/spack/repos/builtin/packages/python/package.py @@ -692,7 +692,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)) @@ -810,9 +810,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): @@ -1288,7 +1288,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] @@ -1296,8 +1302,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/spectrum-mpi/package.py b/var/spack/repos/builtin/packages/spectrum-mpi/package.py index 13a4be26c6b..a5b0871684f 100644 --- a/var/spack/repos/builtin/packages/spectrum-mpi/package.py +++ b/var/spack/repos/builtin/packages/spectrum-mpi/package.py @@ -4,7 +4,7 @@ import os import re -import spack.compilers +import spack.compilers.config from spack.package import * @@ -48,7 +48,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 44e76d98587..331cc2dcc2d 100644 --- a/var/spack/repos/builtin/packages/taskflow/package.py +++ b/var/spack/repos/builtin/packages/taskflow/package.py @@ -2,7 +2,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/vasp/package.py b/var/spack/repos/builtin/packages/vasp/package.py index 8744f076066..d682a02ede1 100644 --- a/var/spack/repos/builtin/packages/vasp/package.py +++ b/var/spack/repos/builtin/packages/vasp/package.py @@ -86,7 +86,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 29624b31693..0f66363b6e8 100644 --- a/var/spack/repos/builtin/packages/win-file/package.py +++ b/var/spack/repos/builtin/packages/win-file/package.py @@ -22,6 +22,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 501668703fc..8c0876f8e79 100644 --- a/var/spack/repos/builtin/packages/win-gpg/package.py +++ b/var/spack/repos/builtin/packages/win-gpg/package.py @@ -23,6 +23,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 438ac4c214d..c63bcd54fdb 100644 --- a/var/spack/repos/builtin/packages/xl/package.py +++ b/var/spack/repos/builtin/packages/xl/package.py @@ -1,6 +1,8 @@ # Copyright Spack Project Developers. See COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import os.path + from spack.package import * @@ -14,6 +16,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 " @@ -27,6 +32,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 f1e4f699fee..ac2975d168a 100644 --- a/var/spack/repos/builtin/packages/yafyaml/package.py +++ b/var/spack/repos/builtin/packages/yafyaml/package.py @@ -3,9 +3,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 f0618245160..ffd10edb706 100644 --- a/var/spack/repos/builtin/packages/zlib-ng/package.py +++ b/var/spack/repos/builtin/packages/zlib-ng/package.py @@ -71,7 +71,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)