From 2e9d0e146eb71eff256aa250bd29c06840b27760 Mon Sep 17 00:00:00 2001 From: "John W. Parent" <45471568+johnwparent@users.noreply.github.com> Date: Tue, 21 Mar 2023 13:15:50 -0400 Subject: netcdf-c[xx]: CMake/Windows build (#34935) netcdf-cxx and netcdf-c now build with CMake rather than Autotools. netcdf-c can still optionally build with Autotools (but defaults to CMake). With some additional patches to the CMake files, netcdf-c can use CMake to build on Windows. --- .../netcdf-c/4.8.1-win-hdf5-with-zlib.patch | 13 ++ .../netcdf-c/netcdfc-mpi-win-support.patch | 59 ++++++++ .../repos/builtin/packages/netcdf-c/package.py | 157 +++++++++++++-------- 3 files changed, 169 insertions(+), 60 deletions(-) create mode 100644 var/spack/repos/builtin/packages/netcdf-c/4.8.1-win-hdf5-with-zlib.patch create mode 100644 var/spack/repos/builtin/packages/netcdf-c/netcdfc-mpi-win-support.patch diff --git a/var/spack/repos/builtin/packages/netcdf-c/4.8.1-win-hdf5-with-zlib.patch b/var/spack/repos/builtin/packages/netcdf-c/4.8.1-win-hdf5-with-zlib.patch new file mode 100644 index 0000000000..6023e6d4ef --- /dev/null +++ b/var/spack/repos/builtin/packages/netcdf-c/4.8.1-win-hdf5-with-zlib.patch @@ -0,0 +1,13 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index ba66a6d4..217aa712 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -856,7 +856,7 @@ IF(USE_HDF5) + # This needs to be near the beginning since we + # need to know whether to add "-lz" to the symbol + # tests below. +- CHECK_C_SOURCE_COMPILES("#include ++ CHECK_C_SOURCE_COMPILES("#include + #if !H5_HAVE_ZLIB_H + #error + #endif diff --git a/var/spack/repos/builtin/packages/netcdf-c/netcdfc-mpi-win-support.patch b/var/spack/repos/builtin/packages/netcdf-c/netcdfc-mpi-win-support.patch new file mode 100644 index 0000000000..c873af1daa --- /dev/null +++ b/var/spack/repos/builtin/packages/netcdf-c/netcdfc-mpi-win-support.patch @@ -0,0 +1,59 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 9b057311..37e96a96 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -1471,6 +1471,7 @@ ENDIF() + + # Enable Parallel IO with netCDF-4/HDF5 files using HDF5 parallel I/O. + SET(STATUS_PARALLEL "OFF") ++set(IMPORT_MPI "") + OPTION(ENABLE_PARALLEL4 "Build netCDF-4 with parallel IO" "${HDF5_PARALLEL}") + IF(ENABLE_PARALLEL4 AND ENABLE_HDF5) + IF(NOT HDF5_PARALLEL) +@@ -1492,6 +1493,7 @@ IF(ENABLE_PARALLEL4 AND ENABLE_HDF5) + FILE(COPY "${netCDF_BINARY_DIR}/tmp/run_par_tests.sh" + DESTINATION ${netCDF_BINARY_DIR}/h5_test + FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) ++ set(IMPORT_MPI "include(CMakeFindDependencyMacro)\nfind_dependency(mpi COMPONENTS C)") + ENDIF() + ENDIF() + +diff --git a/liblib/CMakeLists.txt b/liblib/CMakeLists.txt +index e3eddc0f..0493cb9d 100644 +--- a/liblib/CMakeLists.txt ++++ b/liblib/CMakeLists.txt +@@ -50,6 +50,7 @@ ADD_LIBRARY(netcdf nc_initialize.c ${LARGS} ) + + IF(MPI_C_INCLUDE_PATH) + target_include_directories(netcdf PUBLIC ${MPI_C_INCLUDE_PATH}) ++ target_link_libraries(netcdf PUBLIC MPI::MPI_C) + ENDIF(MPI_C_INCLUDE_PATH) + + IF(MOD_NETCDF_NAME) +diff --git a/netCDFConfig.cmake.in b/netCDFConfig.cmake.in +index 9d68eec5..dae2429e 100644 +--- a/netCDFConfig.cmake.in ++++ b/netCDFConfig.cmake.in +@@ -14,6 +14,8 @@ set(netCDF_LIBRARIES netCDF::netcdf) + # include target information + include("${CMAKE_CURRENT_LIST_DIR}/netCDFTargets.cmake") + ++@IMPORT_MPI@ ++ + # Compiling Options + # + set(netCDF_C_COMPILER "@CC_VERSION@") +diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt +index 65891d82..15567c8f 100644 +--- a/plugins/CMakeLists.txt ++++ b/plugins/CMakeLists.txt +@@ -62,6 +62,9 @@ MACRO(buildplugin TARGET TARGETLIB) + set_target_properties(${TARGET} PROPERTIES LINK_FLAGS "/INCREMENTAL:NO /DEBUG /OPT:REF /OPT:ICF") + # Set file name & location + set_target_properties(${TARGET} PROPERTIES COMPILE_PDB_NAME ${TARGET} COMPILE_PDB_OUTPUT_DIR ${CMAKE_BINARY_DIR}) ++ IF(MPI_C_INCLUDE_PATH) ++ target_include_directories(${TARGET} PRIVATE ${MPI_C_INCLUDE_PATH}) ++ ENDIF(MPI_C_INCLUDE_PATH) + ENDIF() + ENDMACRO() + diff --git a/var/spack/repos/builtin/packages/netcdf-c/package.py b/var/spack/repos/builtin/packages/netcdf-c/package.py index dd106fbc62..f7024353d0 100644 --- a/var/spack/repos/builtin/packages/netcdf-c/package.py +++ b/var/spack/repos/builtin/packages/netcdf-c/package.py @@ -4,11 +4,14 @@ # SPDX-License-Identifier: (Apache-2.0 OR MIT) import os +import sys +from spack.build_systems.autotools import AutotoolsBuilder +from spack.build_systems.cmake import CMakeBuilder from spack.package import * -class NetcdfC(AutotoolsPackage): +class NetcdfC(CMakePackage, AutotoolsPackage): """NetCDF (network Common Data Form) is a set of software libraries and machine-independent data formats that support the creation, access, and sharing of array-oriented scientific data. This is the C distribution.""" @@ -62,6 +65,9 @@ class NetcdfC(AutotoolsPackage): when="@4.7.2", ) + patch("4.8.1-win-hdf5-with-zlib.patch", when="@4.8.1: platform=windows") + + patch("netcdfc-mpi-win-support.patch", when="platform=windows") # See https://github.com/Unidata/netcdf-c/pull/1752 patch("4.7.3-spectrum-mpi-pnetcdf-detect.patch", when="@4.7.3:4.7.4 +parallel-netcdf") @@ -89,11 +95,13 @@ class NetcdfC(AutotoolsPackage): # description='Enable CDM Remote support') # The patch for 4.7.0 touches configure.ac. See force_autoreconf below. - depends_on("autoconf", type="build", when="@4.7.0,main") - depends_on("automake", type="build", when="@4.7.0,main") - depends_on("libtool", type="build", when="@4.7.0,main") + with when("build_system=autotools"): + depends_on("autoconf", type="build", when="@4.7.0,main") + depends_on("automake", type="build", when="@4.7.0,main") + depends_on("libtool", type="build", when="@4.7.0,main") + # CMake system can use m4, but Windows does not yet support + depends_on("m4", type="build", when=sys.platform != "win32") - depends_on("m4", type="build") depends_on("hdf~netcdf", when="+hdf4") # curl 7.18.0 or later is required: @@ -145,13 +153,72 @@ class NetcdfC(AutotoolsPackage): filter_compiler_wrappers("nc-config", relative_root="bin") + default_build_system = "cmake" if sys.platform == "win32" else "autotools" + + build_system("cmake", "autotools", default=default_build_system) + + def setup_run_environment(self, env): + if "+zstd" in self.spec: + env.append_path("HDF5_PLUGIN_PATH", self.prefix.plugins) + + @property + def libs(self): + shared = "+shared" in self.spec + return find_libraries("libnetcdf", root=self.prefix, shared=shared, recursive=True) + + +class Setup: + def setup_dependent_build_environment(self, env, dependent_spec): + self.pkg.setup_run_environment(env) + # Some packages, e.g. ncview, refuse to build if the compiler path returned by nc-config + # differs from the path to the compiler that the package should be built with. Therefore, + # we have to shadow nc-config from self.prefix.bin, which references the real compiler, + # with a backed up version, which references Spack compiler wrapper. + if os.path.exists(self._nc_config_backup_dir): + env.prepend_path("PATH", self._nc_config_backup_dir) + + +class BackupStep: + @property + def _nc_config_backup_dir(self): + return join_path(self.pkg.metadata_dir, "spack-nc-config") + + @run_after("install") + def backup_nc_config(self): + # We expect this to be run before filter_compiler_wrappers: + nc_config_file = self.prefix.bin.join("nc-config") + if os.path.exists(nc_config_file): + mkdirp(self._nc_config_backup_dir) + install(nc_config_file, self._nc_config_backup_dir) + + +class CMakeBuilder(CMakeBuilder, BackupStep, Setup): + def cmake_args(self): + base_cmake_args = [ + self.define_from_variant("BUILD_SHARED_LIBS", "shared"), + self.define("BUILD_UTILITIES", True), + self.define("ENABLE_NETCDF_4", True), + self.define_from_variant("ENABLE_DAP", "dap"), + self.define("CMAKE_INSTALL_PREFIX", self.prefix), + self.define_from_variant("ENABLE_HDF4", "hdf4"), + self.define("ENABLE_PARALLEL_TESTS", False), + self.define_from_variant("ENABLE_FSYNC", "fsync"), + self.define("ENABLE_LARGE_FILE_SUPPORT", True), + ] + if "+parallel-netcdf" in self.pkg.spec: + base_cmake_args.append(self.define("ENABLE_PNETCDF", True)) + if self.pkg.spec.satisfies("@4.3.1:"): + base_cmake_args.append(self.define("ENABLE_DYNAMIC_LOADING", True)) + return base_cmake_args + + +class AutotoolsBuilder(AutotoolsBuilder, BackupStep, Setup): @property def force_autoreconf(self): # The patch for 4.7.0 touches configure.ac. - return self.spec.satisfies("@4.7.0") + return self.pkg.spec.satisfies("@4.7.0") - @when("@4.6.3:") - def autoreconf(self, spec, prefix): + def autoreconf(self, pkg, spec, prefix): if not os.path.exists(self.configure_abs_path): Executable("./bootstrap")() @@ -169,57 +236,57 @@ class NetcdfC(AutotoolsPackage): "--enable-netcdf-4", ] - if "+optimize" in self.spec: + if "+optimize" in self.pkg.spec: cflags.append("-O2") config_args.extend(self.enable_or_disable("fsync")) # The flag was introduced in version 4.3.1 - if self.spec.satisfies("@4.3.1:"): + if self.pkg.spec.satisfies("@4.3.1:"): config_args.append("--enable-dynamic-loading") config_args += self.enable_or_disable("shared") - if "+pic" in self.spec: - cflags.append(self.compiler.cc_pic_flag) + if "+pic" in self.pkg.spec: + cflags.append(self.pkg.compiler.cc_pic_flag) config_args += self.enable_or_disable("dap") # config_args += self.enable_or_disable('cdmremote') - # if '+dap' in self.spec or '+cdmremote' in self.spec: - if "+dap" in self.spec: + # if '+dap' in self.pkg.spec or '+cdmremote' in self.pkg.spec: + if "+dap" in self.pkg.spec: # Make sure Netcdf links against Spack's curl, otherwise it may # pick up system's curl, which can give link errors, e.g.: # undefined reference to `SSL_CTX_use_certificate_chain_file - curl = self.spec["curl"] + curl = self.pkg.spec["curl"] curl_libs = curl.libs libs.append(curl_libs.link_flags) ldflags.append(curl_libs.search_flags) # TODO: figure out how to get correct flags via headers.cpp_flags cppflags.append("-I" + curl.prefix.include) - elif self.spec.satisfies("@4.8.0:"): + elif self.pkg.spec.satisfies("@4.8.0:"): # Prevent overlinking to a system installation of libcurl: config_args.append("ac_cv_lib_curl_curl_easy_setopt=no") - if self.spec.satisfies("@4.4:"): - if "+mpi" in self.spec: + if self.pkg.spec.satisfies("@4.4:"): + if "+mpi" in self.pkg.spec: config_args.append("--enable-parallel4") else: config_args.append("--disable-parallel4") - if self.spec.satisfies("@4.3.2:"): + if self.pkg.spec.satisfies("@4.3.2:"): config_args += self.enable_or_disable("jna") # Starting version 4.1.3, --with-hdf5= and other such configure options # are removed. Variables CPPFLAGS, LDFLAGS, and LD_LIBRARY_PATH must be # used instead. - hdf5_hl = self.spec["hdf5:hl"] + hdf5_hl = self.pkg.spec["hdf5:hl"] cppflags.append(hdf5_hl.headers.cpp_flags) ldflags.append(hdf5_hl.libs.search_flags) - if "+parallel-netcdf" in self.spec: + if "+parallel-netcdf" in self.pkg.spec: config_args.append("--enable-pnetcdf") - pnetcdf = self.spec["parallel-netcdf"] + pnetcdf = self.pkg.spec["parallel-netcdf"] cppflags.append(pnetcdf.headers.cpp_flags) # TODO: change to pnetcdf.libs.search_flags once 'parallel-netcdf' # package gets custom implementation of 'libs' @@ -227,17 +294,17 @@ class NetcdfC(AutotoolsPackage): else: config_args.append("--disable-pnetcdf") - if "+mpi" in self.spec or "+parallel-netcdf" in self.spec: - config_args.append("CC=%s" % self.spec["mpi"].mpicc) + if "+mpi" in self.pkg.spec or "+parallel-netcdf" in self.pkg.spec: + config_args.append("CC=%s" % self.pkg.spec["mpi"].mpicc) config_args += self.enable_or_disable("hdf4") - if "+hdf4" in self.spec: - hdf4 = self.spec["hdf"] + if "+hdf4" in self.pkg.spec: + hdf4 = self.pkg.spec["hdf"] cppflags.append(hdf4.headers.cpp_flags) # TODO: change to hdf4.libs.search_flags once 'hdf' # package gets custom implementation of 'libs' property. ldflags.append("-L" + hdf4.prefix.lib) - # TODO: change to self.spec['jpeg'].libs.link_flags once the + # TODO: change to self.pkg.spec['jpeg'].libs.link_flags once the # implementations of 'jpeg' virtual package get 'jpeg_libs' # property. libs.append("-ljpeg") @@ -247,12 +314,12 @@ class NetcdfC(AutotoolsPackage): if "+external-xdr" in hdf4 and hdf4["rpc"].name != "libc": libs.append(hdf4["rpc"].libs.link_flags) - if "+zstd" in self.spec: - zstd = self.spec["zstd"] + if "+zstd" in self.pkg.spec: + zstd = self.pkg.spec["zstd"] cppflags.append(zstd.headers.cpp_flags) ldflags.append(zstd.libs.search_flags) config_args.append("--with-plugin-dir={}".format(self.prefix.plugins)) - elif "~zstd" in self.spec: + elif "~zstd" in self.pkg.spec: # Prevent linking to system zstd. # There is no explicit option to disable zstd. config_args.append("ac_cv_lib_zstd_ZSTD_compress=no") @@ -268,36 +335,6 @@ class NetcdfC(AutotoolsPackage): return config_args - def setup_run_environment(self, env): - if "+zstd" in self.spec: - env.append_path("HDF5_PLUGIN_PATH", self.prefix.plugins) - - def setup_dependent_build_environment(self, env, dependent_spec): - self.setup_run_environment(env) - # Some packages, e.g. ncview, refuse to build if the compiler path returned by nc-config - # differs from the path to the compiler that the package should be built with. Therefore, - # we have to shadow nc-config from self.prefix.bin, which references the real compiler, - # with a backed up version, which references Spack compiler wrapper. - if os.path.exists(self._nc_config_backup_dir): - env.prepend_path("PATH", self._nc_config_backup_dir) - - @run_after("install") - def backup_nc_config(self): - # We expect this to be run before filter_compiler_wrappers: - nc_config_file = self.prefix.bin.join("nc-config") - if os.path.exists(nc_config_file): - mkdirp(self._nc_config_backup_dir) - install(nc_config_file, self._nc_config_backup_dir) - def check(self): # h5_test fails when run in parallel make("check", parallel=False) - - @property - def libs(self): - shared = "+shared" in self.spec - return find_libraries("libnetcdf", root=self.prefix, shared=shared, recursive=True) - - @property - def _nc_config_backup_dir(self): - return join_path(self.metadata_dir, "spack-nc-config") -- cgit v1.2.3-60-g2f50