diff --git a/.ci/env b/.ci/env index e9328370248..5c0b654b90a 100644 --- a/.ci/env +++ b/.ci/env @@ -1,2 +1,2 @@ -SPACK_CHECKOUT_VERSION=84cb7ff86b42e7fa45476750b6729144c58f70dc +SPACK_CHECKOUT_VERSION=df98ad4289a7234bd9a443151d70c3f75668fdcf SPACK_CHECKOUT_REPO=spack/spack diff --git a/.ci/gitlab/.gitlab-ci.yml b/.ci/gitlab/.gitlab-ci.yml index 748612ea3b5..67de4ae21f8 100644 --- a/.ci/gitlab/.gitlab-ci.yml +++ b/.ci/gitlab/.gitlab-ci.yml @@ -116,6 +116,7 @@ default: - mkdir "${CI_PROJECT_DIR}/jobs_scratch_dir/${SPACK_CI_STACK_NAME}" - spack config blame > "${CI_PROJECT_DIR}/jobs_scratch_dir/${SPACK_CI_STACK_NAME}/spack.yaml.blame" + # - spack solve --show all > "${CI_PROJECT_DIR}/jobs_scratch_dir/${SPACK_CI_STACK_NAME}/solve.out" - spack -v --color=always ci generate --check-index-only -j ${SPACK_CONCRETIZE_JOBS} --forward-variable SPACK_CHECKOUT_VERSION diff --git a/repos/spack_repo/builtin/packages/compiler_wrapper/package.py b/repos/spack_repo/builtin/packages/compiler_wrapper/package.py index eef1d7e1ad5..151673ba724 100644 --- a/repos/spack_repo/builtin/packages/compiler_wrapper/package.py +++ b/repos/spack_repo/builtin/packages/compiler_wrapper/package.py @@ -6,11 +6,14 @@ import sys from spack_repo.builtin.build_systems.generic import Package +from spack_repo.builtin.build_systems.nmake import NMakeBuilder, NMakePackage from spack.package import * +IS_WINDOWS = sys.platform == "win32" -class CompilerWrapper(Package): + +class CompilerWrapper(Package, NMakePackage): """Spack compiler wrapper script. Compiler commands go through this compiler wrapper in Spack builds. @@ -26,125 +29,75 @@ class CompilerWrapper(Package): 3. It provides a mechanism to inject flags from specs """ - homepage = "https://github.com/spack/spack" - url = "https://github.com/spack/compiler-wrapper/releases/download/v1.0/compiler-wrapper-1.0.tar.gz" + homepage_nix = "https://github.com/spack/spack" + url_nix = "https://github.com/spack/compiler-wrapper/releases/download/v1.0/compiler-wrapper-1.0.tar.gz" + + homepage_win = "https://github.com/spack/msvc-wrapper" + url_win = "https://github.com/spack/msvc-wrapper/archive/refs/tags/v0.1.0.tar.gz" + git_win = "https://github.com/spack/msvc-wrapper.git" + + homepage = homepage_win if IS_WINDOWS else homepage_nix + url = url_win if IS_WINDOWS else url_nix + if IS_WINDOWS: + git = git_win # FIXME (compiler as nodes): use a different tag, since this is only to exclude # this node from auto-generated rules tags = ["runtime"] - maintainers("haampie") + maintainers("haampie", "johnwparent") license("Apache-2.0 OR MIT") - if sys.platform != "win32": + default_builder = "nmake" if IS_WINDOWS else "generic" + build_system("generic", conditional("nmake", when="platform=windows"), default=default_builder) + + if not IS_WINDOWS: version("1.1.0", sha256="a07b35081d14b0729090bc1e5790a5dda2d5b997e064c62da39a1224ee249b2a") version("1.0", sha256="ac876f7600fa6cb0c74ae172ef1c61661aacff03a6befbc7d87e092e2f2233f9") else: - version("1.0") - has_code = False + # version("develop", branch="main") + version("1.0", commit="51358dd5c37a77b9a5816b6f9c8e3e4f6e07fb78") + + depends_on("msvc", when="platform=windows", type=("build", "run")) def bin_dir(self) -> pathlib.Path: # This adds an extra "spack" subdir, so that the script and symlinks don't get # their way to the default view return pathlib.Path(str(self.prefix)) / "libexec" / "spack" - def install(self, spec, prefix): - if sys.platform == "win32": - placeholder = self.bin_dir() / "placeholder-wrapper" - placeholder.parent.mkdir(parents=True) - placeholder.write_text( - "This file is a placeholder for the compiler wrapper on Windows." - ) - return + def setup_dependent_package(self, module, dependent_spec): + def _spack_compiler_attribute(*, language: str) -> str: + compiler_pkg = dependent_spec[language].package + return str(self.bin_dir() / compiler_pkg.compiler_wrapper_link_paths[language]) - cc_script = pathlib.Path(self.stage.source_path) / "cc.sh" - bin_dir = self.bin_dir() + if dependent_spec.has_virtual_dependency("c"): + setattr(module, "spack_cc", _spack_compiler_attribute(language="c")) - # Copy the script - bin_dir.mkdir(parents=True) - installed_script = bin_dir / "cc" - shutil.copy(cc_script, str(installed_script)) - set_executable(installed_script) + if dependent_spec.has_virtual_dependency("cxx"): + setattr(module, "spack_cxx", _spack_compiler_attribute(language="cxx")) - # Create links to use the script under different names - for name in ( - "ld.lld", - "ld.gold", - "ld", - "ftn", - "fc", - "f95", - "f90", - "f77", - "cpp", - "c99", - "c89", - "c++", - ): - (bin_dir / name).symlink_to(installed_script) + if dependent_spec.has_virtual_dependency("fortran"): + setattr(module, "spack_fc", _spack_compiler_attribute(language="fortran")) + setattr(module, "spack_f77", _spack_compiler_attribute(language="fortran")) - for subdir, name in ( - ("aocc", "clang"), - ("aocc", "clang++"), - ("aocc", "flang"), - ("arm", "armclang"), - ("arm", "armclang++"), - ("arm", "armflang"), - ("case-insensitive", "CC"), - ("cce", "cc"), - ("cce", "craycc"), - ("cce", "crayftn"), - ("cce", "ftn"), - ("clang", "clang"), - ("clang", "clang++"), - ("clang", "flang"), - ("fj", "fcc"), - ("fj", "frt"), - ("gcc", "gcc"), - ("gcc", "g++"), - ("gcc", "gfortran"), - ("intel", "icc"), - ("intel", "icpc"), - ("intel", "ifort"), - ("nag", "nagfor"), - ("nvhpc", "nvc"), - ("nvhpc", "nvc++"), - ("nvhpc", "nvfortran"), - ("oneapi", "icx"), - ("oneapi", "icpx"), - ("oneapi", "ifx"), - ("rocmcc", "amdclang"), - ("rocmcc", "amdclang++"), - ("rocmcc", "amdflang"), - ("xl", "xlc"), - ("xl", "xlc++"), - ("xl", "xlf"), - ("xl", "xlf90"), - ("xl_r", "xlc_r"), - ("xl_r", "xlc++_r"), - ("xl_r", "xlf_r"), - ("xl_r", "xlf90_r"), - ): - (bin_dir / subdir).mkdir(exist_ok=True) - (bin_dir / subdir / name).symlink_to(installed_script) + @property + def disable_new_dtags(self) -> str: + if self.spec.satisfies("platform=darwin"): + return "" + return "--disable-new-dtags" - # Extra symlinks for Cray - cray_dir = bin_dir / "cce" / "case-insensitive" - cray_dir.mkdir(exist_ok=True) - (cray_dir / "crayCC").symlink_to(installed_script) - (cray_dir / "CC").symlink_to(installed_script) + @property + def enable_new_dtags(self) -> str: + if self.spec.satisfies("platform=darwin"): + return "" + return "--enable-new-dtags" - # Extra symlink for Fujitsu - fj_dir = bin_dir / "fj" / "case-insensitive" - fj_dir.mkdir(exist_ok=True) - (fj_dir / "FCC").symlink_to(installed_script) +class EnvironmentSetup: def setup_dependent_build_environment( self, env: EnvironmentModifications, dependent_spec: Spec ) -> None: - if sys.platform == "win32": - return _var_list = [] if dependent_spec.has_virtual_dependency("c"): @@ -156,12 +109,11 @@ def setup_dependent_build_environment( if dependent_spec.has_virtual_dependency("fortran"): _var_list.append(("fortran", "fortran", "F77", "SPACK_F77")) _var_list.append(("fortran", "fortran", "FC", "SPACK_FC")) - # The package is not used as a compiler, so skip this setup if not _var_list: return - bin_dir = self.bin_dir() + bin_dir = self.pkg.bin_dir() implicit_rpaths, env_paths = [], [] extra_rpaths = [] for language, attr_name, wrapper_var_name, spack_var_name in _var_list: @@ -172,6 +124,9 @@ def setup_dependent_build_environment( compiler = getattr(compiler_pkg, attr_name) env.set(spack_var_name, compiler) + if hasattr(compiler_pkg, "ld"): + env.set("SPACK_LD", compiler_pkg.ld) + # -frandom-seed= is needed for deterministic builds with GCC if compiler_pkg.name == "gcc" and self.spec.satisfies("@1.1:"): env.set(f"SPACK_{wrapper_var_name}_HAS_FRANDOM_SEED", "1") @@ -229,45 +184,122 @@ def setup_dependent_build_environment( extra_rpaths = dedupe(extra_rpaths) env.set("SPACK_COMPILER_EXTRA_RPATHS", ":".join(extra_rpaths)) - env.set("SPACK_ENABLE_NEW_DTAGS", self.enable_new_dtags) - env.set("SPACK_DISABLE_NEW_DTAGS", self.disable_new_dtags) + env.set("SPACK_ENABLE_NEW_DTAGS", self.pkg.enable_new_dtags) + env.set("SPACK_DISABLE_NEW_DTAGS", self.pkg.disable_new_dtags) for item in env_paths: env.prepend_path("SPACK_COMPILER_WRAPPER_PATH", item) - def setup_dependent_package(self, module, dependent_spec): - def _spack_compiler_attribute(*, language: str) -> str: - compiler_pkg = dependent_spec[language].package - if sys.platform != "win32": - # On non-Windows we return the appropriate path to the compiler wrapper - return str(self.bin_dir() / compiler_pkg.compiler_wrapper_link_paths[language]) - - # On Windows we return the real compiler - if language == "c": - return compiler_pkg.cc - elif language == "cxx": - return compiler_pkg.cxx - elif language == "fortran": - return compiler_pkg.fortran + env.set("SPACK_CONTEXT_ROOT", dependent_spec.package.stage.source_path) + if IS_WINDOWS: + env.set("SPACK_DEBUG_WRAPPER", "ON") - if dependent_spec.has_virtual_dependency("c"): - setattr(module, "spack_cc", _spack_compiler_attribute(language="c")) - if dependent_spec.has_virtual_dependency("cxx"): - setattr(module, "spack_cxx", _spack_compiler_attribute(language="cxx")) +class GenericBuilder(GenericBuilder, EnvironmentSetup): + def install(self, pkg, spec, prefix): + cc_script = pathlib.Path(self.stage.source_path) / "cc.sh" + bin_dir = pkg.bin_dir() - if dependent_spec.has_virtual_dependency("fortran"): - setattr(module, "spack_fc", _spack_compiler_attribute(language="fortran")) - setattr(module, "spack_f77", _spack_compiler_attribute(language="fortran")) + # Copy the script + bin_dir.mkdir(parents=True) + installed_script = bin_dir / "cc" + shutil.copy(cc_script, str(installed_script)) + set_executable(installed_script) - @property - def disable_new_dtags(self) -> str: - if self.spec.satisfies("platform=darwin"): - return "" - return "--disable-new-dtags" + # Create links to use the script under different names + for name in ( + "ld.lld", + "ld.gold", + "ld", + "ftn", + "fc", + "f95", + "f90", + "f77", + "cpp", + "c99", + "c89", + "c++", + ): + (bin_dir / name).symlink_to(installed_script) - @property - def enable_new_dtags(self) -> str: - if self.spec.satisfies("platform=darwin"): - return "" - return "--enable-new-dtags" + for subdir, name in ( + ("aocc", "clang"), + ("aocc", "clang++"), + ("aocc", "flang"), + ("arm", "armclang"), + ("arm", "armclang++"), + ("arm", "armflang"), + ("case-insensitive", "CC"), + ("cce", "cc"), + ("cce", "craycc"), + ("cce", "crayftn"), + ("cce", "ftn"), + ("clang", "clang"), + ("clang", "clang++"), + ("clang", "flang"), + ("fj", "fcc"), + ("fj", "frt"), + ("gcc", "gcc"), + ("gcc", "g++"), + ("gcc", "gfortran"), + ("intel", "icc"), + ("intel", "icpc"), + ("intel", "ifort"), + ("nag", "nagfor"), + ("nvhpc", "nvc"), + ("nvhpc", "nvc++"), + ("nvhpc", "nvfortran"), + ("oneapi", "icx"), + ("oneapi", "icpx"), + ("oneapi", "ifx"), + ("rocmcc", "amdclang"), + ("rocmcc", "amdclang++"), + ("rocmcc", "amdflang"), + ("xl", "xlc"), + ("xl", "xlc++"), + ("xl", "xlf"), + ("xl", "xlf90"), + ("xl_r", "xlc_r"), + ("xl_r", "xlc++_r"), + ("xl_r", "xlf_r"), + ("xl_r", "xlf90_r"), + ): + (bin_dir / subdir).mkdir(exist_ok=True) + (bin_dir / subdir / name).symlink_to(installed_script) + + # Extra symlinks for Cray + cray_dir = bin_dir / "cce" / "case-insensitive" + cray_dir.mkdir(exist_ok=True) + (cray_dir / "crayCC").symlink_to(installed_script) + (cray_dir / "CC").symlink_to(installed_script) + + # Extra symlink for Fujitsu + fj_dir = bin_dir / "fj" / "case-insensitive" + fj_dir.mkdir(exist_ok=True) + (fj_dir / "FCC").symlink_to(installed_script) + + +class NMakeBuilder(NMakeBuilder, EnvironmentSetup): + install_targets = ["install"] + build_targets = ["cl.exe"] + + def install(self, pkg, spec, prefix): + bin_dir = pkg.bin_dir() + opts = self.std_nmake_args + opts.append(self.define("PREFIX", str(bin_dir))) + with working_dir(self.build_directory): + nmake(*opts, *self.install_targets, ignore_quotes=self.ignore_quotes) + + # Create links to use the script under different names + for name in ("link", "ftn", "fc", "f95", "f90", "f77", "cpp", "c99", "c89", "c++"): + (bin_dir / name).symlink_to(bin_dir / "cl.exe") + + for subdir, name in ( + ("case-insensitive", "CC.exe"), + ("intel", "ifort.exe"), + ("oneapi", "ifx.exe"), + ("msvc", "cl.exe"), + ): + (bin_dir / subdir).mkdir(exist_ok=True) + (bin_dir / subdir / name).symlink_to(bin_dir / "cl.exe") diff --git a/repos/spack_repo/builtin/packages/msmpi/ifort_nd_compat.patch b/repos/spack_repo/builtin/packages/msmpi/ifort_nd_compat.patch index a75c0841b4b..3ef6f842ef9 100644 --- a/repos/spack_repo/builtin/packages/msmpi/ifort_nd_compat.patch +++ b/repos/spack_repo/builtin/packages/msmpi/ifort_nd_compat.patch @@ -37,7 +37,7 @@ index 24bd29d..319153d 100644 + /D _WIN64=1 /D _AMD64_=1 /D AMD64=1 - -+ ++ diff --git a/repos/spack_repo/builtin/packages/msvc/package.py b/repos/spack_repo/builtin/packages/msvc/package.py index 3f1fe49d72e..c0e7c211f70 100644 --- a/repos/spack_repo/builtin/packages/msvc/package.py +++ b/repos/spack_repo/builtin/packages/msvc/package.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) import os.path +import pathlib import re import subprocess @@ -46,12 +47,15 @@ def install(self, spec, prefix): compiler_version_argument = "" compiler_version_regex = r"([1-9][0-9]*\.[0-9]*\.[0-9]*)" - # 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 - compiler_wrapper_link_paths = {"c": "", "cxx": "", "fortran": ""} + compiler_wrapper_link_paths = { + "c": "msvc\\cl.exe", + "cxx": "msvc\\cl.exe", + "fortran": "oneapi\\ifx.exe", + } + + version("19.39.33523") + version("19.16.27054") + version("19.16.27051") provides("c", "cxx", "fortran") requires("platform=windows", msg="MSVC is only supported on Windows") @@ -75,6 +79,17 @@ def determine_variants(cls, exes, version_str): # MSVC uses same executable for both languages spec, extras = super().determine_variants(exes, version_str) extras["compilers"]["c"] = extras["compilers"]["cxx"] + + # Spack's msvc compiler wrapper also wraps the linker + # to inject rpath-analogous behavior into Windows + # binaries. We define the linker so we can + # expose it to the run environmnet of the wrapper + # similar to how we do CC vs SPACK_CC + # the linker is always in the same directory as the compiler + extras["compilers"]["ld"] = str( + pathlib.Path(extras["compilers"]["cxx"]).parent / "link.exe" + ) + # This depends on oneapi being processed before msvc # which is guarunteed from detection behavior. # Processing oneAPI tracks oneAPI installations within @@ -125,13 +140,10 @@ def setup_dependent_build_environment( else: env.set_path(env_var, int_env[env_var].split(os.pathsep)) - if self.cc: - env.set("CC", self.cc) - if self.cxx: - env.set("CXX", self.cxx) - if self.fortran: - env.set("FC", self.fortran) - env.set("F77", self.fortran) + def setup_dependent_run_environment( + self, env: EnvironmentModifications, dependent_spec: Spec + ) -> None: + self.setup_dependent_build_environment(env=env, dependent_spec=dependent_spec) def init_msvc(self): # To use the MSVC compilers, VCVARS must be invoked @@ -264,6 +276,17 @@ def platform_toolset_ver(self): vs22_toolset = Version(toolset_ver) > Version("142") return toolset_ver if not vs22_toolset else "143" + @property + def ld(self): + assert self.spec.concrete, "cannot retrieve C++ linker, spec is not concrete" + assert self.spec.external, ( + "MSVC is external only, please report this bug to the Spack maintainers" + ) + ld = self.spec.extra_attributes.get("compilers", {}).get("ld", None) + if not ld: + ld = os.path.join(os.path.dirname(self.cc), "link.exe") + return ld + class CmdCall: """Compose a call to `cmd` for an ordered series of cmd commands/scripts""" diff --git a/repos/spack_repo/builtin/packages/win_gpg/package.py b/repos/spack_repo/builtin/packages/win_gpg/package.py index e0aa633ade2..168432988e4 100644 --- a/repos/spack_repo/builtin/packages/win_gpg/package.py +++ b/repos/spack_repo/builtin/packages/win_gpg/package.py @@ -25,8 +25,6 @@ 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)