From 381bedf3693bbd228915c28fc47d73dbd60af1cd Mon Sep 17 00:00:00 2001 From: Jared Popelar Date: Thu, 17 Nov 2022 11:40:53 -0700 Subject: Hdf5 package: build on Windows (#31141) * Enable hdf5 build (including +mpi) on Windows * This includes updates to hdf5 dependencies openssl (minor edit) and bzip2 (more-extensive edits) * Add binary-based installation of msmpi (this is currently the only supported MPI implementation in Spack for Windows). Note that this does not install to the Spack-specified prefix. This implementation will be replaced with a source-based implementation Co-authored-by: John Parent --- lib/spack/docs/getting_started.rst | 2 + lib/spack/spack/spec.py | 2 +- var/spack/repos/builtin/packages/bzip2/package.py | 55 +++++++++++++++++----- var/spack/repos/builtin/packages/hdf5/package.py | 9 ++-- var/spack/repos/builtin/packages/msmpi/package.py | 42 +++++++++++++++++ .../repos/builtin/packages/openssl/package.py | 5 -- 6 files changed, 94 insertions(+), 21 deletions(-) create mode 100644 var/spack/repos/builtin/packages/msmpi/package.py diff --git a/lib/spack/docs/getting_started.rst b/lib/spack/docs/getting_started.rst index 1bf99e09b3..0c30c9a694 100644 --- a/lib/spack/docs/getting_started.rst +++ b/lib/spack/docs/getting_started.rst @@ -1704,9 +1704,11 @@ dependencies or incompatible build tools like autoconf. Here are several packages known to work on Windows: * abseil-cpp +* bzip2 * clingo * cpuinfo * cmake +* hdf5 * glm * nasm * netlib-lapack (requires Intel Fortran) diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py index 401be97858..5c688d916f 100644 --- a/lib/spack/spack/spec.py +++ b/lib/spack/spack/spec.py @@ -1089,7 +1089,7 @@ def _libs_default_handler(descriptor, spec, cls): home = getattr(spec.package, "home") # Avoid double 'lib' for packages whose names already start with lib - if not name.startswith("lib"): + if not name.startswith("lib") and not spec.satisfies("platform=windows"): name = "lib" + name # If '+shared' search only for shared library; if '~shared' search only for diff --git a/var/spack/repos/builtin/packages/bzip2/package.py b/var/spack/repos/builtin/packages/bzip2/package.py index c4d497e6a8..ea1b883068 100644 --- a/var/spack/repos/builtin/packages/bzip2/package.py +++ b/var/spack/repos/builtin/packages/bzip2/package.py @@ -4,6 +4,7 @@ # SPDX-License-Identifier: (Apache-2.0 OR MIT) import re +import sys from spack.package import * @@ -24,11 +25,23 @@ class Bzip2(Package, SourcewarePackage): version("1.0.7", sha256="e768a87c5b1a79511499beb41500bcc4caf203726fff46a6f5f9ad27fe08ab2b") version("1.0.6", sha256="a2848f34fcd5d6cf47def00461fcb528a0484d8edef8208d6d2e2909dc61d9cd") - variant("shared", default=True, description="Enables the build of shared libraries.") + variant( + "shared", + default=(sys.platform != "win32"), + description="Enables the build of shared libraries.", + ) variant("pic", default=False, description="Build static libraries with PIC") variant("debug", default=False, description="Enable debug symbols and disable optimization") - depends_on("diffutils", type="build") + # makefile.msc doesn't provide a shared recipe + conflicts( + "+shared", + when="platform=windows", + msg="Windows makefile has no recipe for shared builds, use ~shared.", + ) + + if sys.platform != "win32": + depends_on("diffutils", type="build") @classmethod def determine_version(cls, exe): @@ -52,9 +65,10 @@ class Bzip2(Package, SourcewarePackage): def patch(self): if self.spec.satisfies("+debug"): - for makefile in ["Makefile", "Makefile-libbz2_so"]: + for makefile in ["Makefile", "Makefile-libbz2_so", "makefile.msc"]: filter_file(r"-O ", "-O0 ", makefile) filter_file(r"-O2 ", "-O0 ", makefile) + filter_file(r"-Ox ", "-O0 ", makefile) # bzip2 comes with two separate Makefiles for static and dynamic builds # Tell both to use Spack's compiler wrapper instead of GCC @@ -82,13 +96,13 @@ class Bzip2(Package, SourcewarePackage): "$(CC) -dynamiclib -Wl,-install_name -Wl,@rpath/libbz2.{0}.dylib " "-current_version {1} -compatibility_version {2} -o libbz2.{3}.dylib $(OBJS)" ).format(v1, v2, v3, v3), - **kwargs + **kwargs, ) mf.filter( "$(CC) $(CFLAGS) -o bzip2-shared bzip2.c libbz2.so.{0}".format(v3), "$(CC) $(CFLAGS) -o bzip2-shared bzip2.c libbz2.{0}.dylib".format(v3), - **kwargs + **kwargs, ) mf.filter( "rm -f libbz2.so.{0}".format(v2), "rm -f libbz2.{0}.dylib".format(v2), **kwargs @@ -96,7 +110,7 @@ class Bzip2(Package, SourcewarePackage): mf.filter( "ln -s libbz2.so.{0} libbz2.so.{1}".format(v3, v2), "ln -s libbz2.{0}.dylib libbz2.{1}.dylib".format(v3, v2), - **kwargs + **kwargs, ) def install(self, spec, prefix): @@ -105,8 +119,23 @@ class Bzip2(Package, SourcewarePackage): make("-f", "Makefile-libbz2_so") # Build the static library and everything else - make() - make("install", "PREFIX={0}".format(prefix)) + if self.spec.satisfies("platform=windows"): + # Build step + nmake = Executable("nmake.exe") + nmake("-f", "makefile.msc") + # Install step + mkdirp(self.prefix.include) + mkdirp(self.prefix.lib) + mkdirp(self.prefix.bin) + mkdirp(self.prefix.man) + mkdirp(self.prefix.man.man1) + install("*.h", self.prefix.include) + install("*.lib", self.prefix.lib) + install("*.exe", self.prefix.bin) + install("*.1", self.prefix.man.man1) + else: + make() + make("install", "PREFIX={0}".format(prefix)) if "+shared" in spec: install("bzip2-shared", join_path(prefix.bin, "bzip2")) @@ -124,7 +153,9 @@ class Bzip2(Package, SourcewarePackage): for libname in (lib, lib1, lib2): symlink(lib3, libname) - with working_dir(prefix.bin): - force_remove("bunzip2", "bzcat") - symlink("bzip2", "bunzip2") - symlink("bzip2", "bzcat") + # These files won't be in a Windows installation + if not self.spec.satisfies("platform=windows"): + with working_dir(prefix.bin): + force_remove("bunzip2", "bzcat") + symlink("bzip2", "bunzip2") + symlink("bzip2", "bzcat") diff --git a/var/spack/repos/builtin/packages/hdf5/package.py b/var/spack/repos/builtin/packages/hdf5/package.py index dd47e2bd4d..c716e2b90b 100644 --- a/var/spack/repos/builtin/packages/hdf5/package.py +++ b/var/spack/repos/builtin/packages/hdf5/package.py @@ -196,13 +196,16 @@ class Hdf5(CMakePackage): depends_on("cmake@3.12:", type="build") + depends_on("msmpi", when="+mpi platform=windows") depends_on("mpi", when="+mpi") depends_on("java", type=("build", "run"), when="+java") depends_on("szip", when="+szip") depends_on("zlib@1.1.2:") # The compiler wrappers (h5cc, h5fc, etc.) run 'pkg-config'. - depends_on("pkgconfig", type="run") + # Skip this on Windows since pkgconfig is autotools + for plat in ["cray", "darwin", "linux"]: + depends_on("pkgconfig", when="platform=%s" % plat, type="run") conflicts("api=v114", when="@1.6:1.12", msg="v114 is not compatible with this release") conflicts("api=v112", when="@1.6:1.10", msg="v112 is not compatible with this release") @@ -498,7 +501,7 @@ class Hdf5(CMakePackage): if api != "default": args.append(self.define("DEFAULT_API_VERSION", api)) - if "+mpi" in spec: + if "+mpi" in spec and "platform=windows" not in spec: args.append(self.define("CMAKE_C_COMPILER", spec["mpi"].mpicc)) if "+cxx" in self.spec: @@ -567,7 +570,7 @@ class Hdf5(CMakePackage): r"(Requires(?:\.private)?:.*)(hdf5[^\s,]*)(?:-[^\s,]*)(.*)", r"\1\2\3", *pc_files, - backup=False + backup=False, ) # Create non-versioned symlinks to the versioned pkg-config files: diff --git a/var/spack/repos/builtin/packages/msmpi/package.py b/var/spack/repos/builtin/packages/msmpi/package.py new file mode 100644 index 0000000000..0e5584cf29 --- /dev/null +++ b/var/spack/repos/builtin/packages/msmpi/package.py @@ -0,0 +1,42 @@ +# Copyright 2013-2022 Lawrence Livermore National Security, LLC and other +# Spack Project Developers. See the top-level COPYRIGHT file for details. +# +# SPDX-License-Identifier: (Apache-2.0 OR MIT) + +from spack.package import * + + +class Msmpi(Package): + """A Windows-specced build of MPICH provided directly by + Microsoft Support Team + """ + + homepage = "https://www.microsoft.com/en-us/download/default.aspx" + maintainers = ["jpopelar"] + + executable = ["mpiexec.exe"] + + version( + "10.0", + sha256="7dae13797627726f67fab9c1d251aec2df9ecd25939984645ec05748bdffd396", + extension="exe", + expand=False, + ) + + provides("mpi") + + conflicts("platform=linux") + conflicts("platform=darwin") + conflicts("platform=cray") + + def url_for_version(self, version): + return "https://download.microsoft.com/download/A/E/0/AE002626-9D9D-448D-8197-1EA510E297CE/msmpisetup.exe" + + def determine_version(self, exe): + output = Executable("mpiexec.exe") + ver_str = re.search("[Version ([0-9.]+)]", output) + return Version(ver_str.group(0)) if ver_str else None + + def install(self, spec, prefix): + installer = Executable("msmpisetup.exe") + installer("-unattend") diff --git a/var/spack/repos/builtin/packages/openssl/package.py b/var/spack/repos/builtin/packages/openssl/package.py index 862ccd1788..62fdecbdc4 100644 --- a/var/spack/repos/builtin/packages/openssl/package.py +++ b/var/spack/repos/builtin/packages/openssl/package.py @@ -420,11 +420,6 @@ class Openssl(Package): # Uses Fake Autotools, should subclass Package # (e.g. gcc) will not accept them. filter_file(r"-arch x86_64", "", "Makefile") - if spec.satisfies("+dynamic"): - # This variant only makes sense for Windows - if spec.satisfies("platform=windows"): - filter_file(r"MT", "MD", "makefile") - if spec.satisfies("platform=windows"): host_make = nmake else: -- cgit v1.2.3-70-g09d2