diff --git a/var/spack/repos/builtin/packages/sgpp/package.py b/var/spack/repos/builtin/packages/sgpp/package.py index 5d9fc6f941a..d829f49153e 100644 --- a/var/spack/repos/builtin/packages/sgpp/package.py +++ b/var/spack/repos/builtin/packages/sgpp/package.py @@ -2,6 +2,8 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import sys + from spack.build_systems.python import PythonPipBuilder from spack.package import * from spack.pkg.builtin.boost import Boost @@ -51,10 +53,22 @@ class Sgpp(SConsPackage): # to complain about missing headers (due to a path check not working anymore) # See issue https://github.com/SGpp/SGpp/issues/263 and https://github.com/SGpp/SGpp/pull/266 patch("disable_disutils_deprecation_warning.patch", when="@:3.4.0 ^python@3.10:3.11") - # SGpp does not contain aarch64 support as of yet. To make it work still, this patch adds + # SGpp does not contain aarch64 support as of 3.4.0. To make it work still, this patch adds # simple build system support for it. - patch("for_aarch64.patch", when="target=aarch64:") + patch("for_aarch64.patch", when="@:3.4.0 target=aarch64:") + # SGpp will default to the system paths when linking boost without the patch + # This may work (depending on the boost versions in question) but we should use the boost + # from spack. This patch allows to correctly pass the spack's boost path to SGpp + # Fixed in SGpp PR https://github.com/SGpp/SGpp/pull/273 + patch("set_boost_lib_path_internally.patch", when="@3.3.0:3.4.0") + variant("debug", default=False, description="Build debug version instead of release version") + variant( + "doc", + default=False, + description="Build sgpp documentation (doxygen / pydoc)", + when="@3.4.0:", + ) variant("python", default=True, description="Provide Python bindings for SGpp") variant("optimization", default=True, description="Builds the optimization module of SGpp") variant("pde", default=True, description="Builds the datadriven module of SGpp") @@ -67,24 +81,37 @@ class Sgpp(SConsPackage): "opencl", default=False, description="Enables support for OpenCL accelerated operations" ) variant("mpi", default=False, description="Enables support for MPI-distributed operations") + variant( + "eigen", default=False, description="Enables Eigen support", when="@3.4.0: +optimization" + ) + variant( + "dakota", default=False, description="Enables Dakota support", when="@3.4.0: +combigrid" + ) + variant( + "visualization", + default=False, + description="Build with visualization support", + when="+python", + ) # Mandatory dependencies depends_on("cxx", type="build") # generated depends_on("scons@3:", type="build") depends_on("zlib-api", type="link") + depends_on("doxygen+graphviz", when="+doc", type="build") + depends_on("eigen", when="+eigen", type=("build", "run")) + depends_on("dakota", when="+dakota", type=("build", "run")) # Python dependencies extends("python", when="+python") depends_on("py-pip", when="+python", type="build") depends_on("py-wheel", when="+python", type="build") depends_on("py-setuptools", type="build") - # Older SGpp releases (:3.4.0) do not support python 3.12 due to them using distutils - depends_on("python@3.7:3.11", type=("build", "run"), when="@:3.4.0") - # SGpp@master works with newer python versions (3.12:) as well depends_on("python@3.7:", type=("build", "run")) - # Newest swig version 4.1 seems to cause problem -> limit to 3:4.0 for now - depends_on("swig@3:4.0", when="+python", type="build") + depends_on("swig@3:", when="+python", type="build") depends_on("py-numpy@1.17:", when="+python", type=("build", "run")) - depends_on("py-scipy@1.3:", when="+python", type=("build", "run")) + depends_on("py-pandas@1.1:", when="+python+visualization", type=("build", "run")) + depends_on("py-matplotlib@3:", when="+python+visualization", type=("build", "run")) + depends_on("py-scipy@1.5:", when="+python", type=("build", "run")) # OpenCL dependency depends_on("opencl@1.1:", when="+opencl", type=("build", "run")) # MPI dependency @@ -93,7 +120,7 @@ class Sgpp(SConsPackage): # TODO: replace this with an explicit list of components of Boost, # for instance depends_on('boost +filesystem') # See https://github.com/spack/spack/pull/22303 for reference - depends_on(Boost.with_default_variants, type="test") + depends_on(Boost.with_default_variants, type=("build", "run", "test")) # Compiler with C++11 support is required conflicts("%gcc@:4.8.4", msg="Compiler with c++11 support is required!") @@ -119,24 +146,50 @@ class Sgpp(SConsPackage): conflicts("+combigrid", when="@1.0.0:3.2.0~pde") conflicts("+combigrid", when="@1.0.0:3.2.0~solver") conflicts("+combigrid", when="@1.0.0:3.2.0~quadrature") + # Conflicts due the changes in the respective frameworks + # Fixed in newer SGpp versions, but 3.4.0 or older versions do not work + conflicts("^python@3.12:", when="@:3.4.0+python") + conflicts("^py-numpy@2:", when="@:3.4.0+python") + conflicts("^py-pandas@1.4:", when="@:3.4.0+python") + conflicts("^py-matplotlib@3.6:", when="@:3.4.0+python") + conflicts("^swig@4.1:", when="@:3.4.0+python") def build_args(self, spec, prefix): # Testing parameters if self.run_tests: - self.args = ["COMPILE_BOOST_TESTS=1", "RUN_BOOST_TESTS=1"] + self.args = [ + "COMPILE_BOOST_TESTS=1", + "RUN_BOOST_TESTS=1", + "COMPILE_BOOST_PERFORMANCE_TESTS=1", + "RUN_BOOST_PERFORMANCE_TESTS=1", + ] if "+python" in spec: self.args.append("RUN_PYTHON_TESTS=1") - if spec.satisfies("@1.0.0:3.2.0"): + if spec.satisfies("@3.3.0:"): + self.args.append("RUN_PYTHON_EXAMPLES=1") + if spec.satisfies("@1.0.0:3.2.0"): # argument was renamed after 3.2.0 self.args.append("RUN_CPPLINT=1") - else: # argument was renamed after 3.2.0 + else: + self.args.append("RUN_CPP_EXAMPLES=1") self.args.append("CHECK_STYLE=1") else: - self.args = ["COMPILE_BOOST_TESTS=0", "RUN_BOOST_TESTS=0", "RUN_PYTHON_TESTS=0"] - if spec.satisfies("@1.0.0:3.2.0"): + self.args = [ + "COMPILE_BOOST_TESTS=0", + "RUN_BOOST_TESTS=0", + "COMPILE_BOOST_PERFORMANCE_TESTS=0", + "RUN_BOOST_PERFORMANCE_TESTS=0", + "RUN_PYTHON_TESTS=0", + ] + if spec.satisfies("@1.0.0:3.2.0"): # argument was renamed after 3.2.0 self.args.append("RUN_CPPLINT=0") - else: # argument was renamed after 3.2.0 + else: + self.args.append("RUN_PYTHON_EXAMPLES=0") + self.args.append("RUN_CPP_EXAMPLES=0") self.args.append("CHECK_STYLE=0") + # Debug build or not + self.args.append("OPT={0}".format("0" if "+debug" in spec else "1")) + # Install direction self.args.append("PREFIX={0}".format(prefix)) @@ -168,6 +221,8 @@ def build_args(self, spec, prefix): self.args.append("ARCH=sse42") elif "sse3" in self.spec.target: self.args.append("ARCH=sse3") + elif "target=aarch64:" in spec: + self.args.append("ARCH=aarch64") # OpenCL Flags self.args.append("USE_OCL={0}".format("1" if "+opencl" in spec else "0")) @@ -179,10 +234,54 @@ def build_args(self, spec, prefix): else: self.args.append("CXX={0}".format(self.compiler.cxx)) + # Include PYDOC when building the documentation + self.args.append("PYDOC={0}".format("1" if "+doc +python" in spec else "0")) + + # For some libraries, SGpp expects the path to be explicitly passed to scons (either using + # CPPPATH and LIBPATH or using depency-specific variables (BOOST_LIBRARY_PATH). + # Here, we set those paths and associated flags the dependencies where SGpp expects them + # to be passed manually via CPPPATH/LIBPATH (Eigen, Dakota, ...): + custom_cpppath = "" + custom_libpath = "" + path_separator = ";" if sys.platform == "win32" else ":" + if "+eigen" in spec: + self.args.append("USE_EIGEN=1") + custom_cpppath += "{0}{1}".format(self.spec["eigen"].prefix.include, path_separator) + if "+dakota" in spec: + self.args.append("USE_DAKOTA=1") + custom_cpppath += "{0}{1}".format(self.spec["dakota"].prefix.include, path_separator) + # Simply using spec["dakota"].libs.directories[0] does not work because spack will look + # for a libdakota library file which does not exist. However, we can use find_libraries + # and manually specify an existing library + # name within dakota to find the correct lib directory: + custom_libpath += "{0}{1}".format( + find_libraries( + "libdakota_src", root=self.spec["dakota"].prefix, shared=True, recursive=True + ).directories[0], + path_separator, + ) + # Add combined paths to CPPPATH/LIBPATH + if custom_cpppath: + self.args.append("CPPPATH={0}".format(custom_cpppath)) + if custom_libpath: + self.args.append("LIBPATH={0}".format(custom_libpath)) + # Manually set Boost location to the spack one (otherwise SGpp will try to look for + # Boost within the System install directory first) + self.args.append("BOOST_INCLUDE_PATH={0}".format(self.spec["boost"].prefix.include)) + self.args.append("BOOST_LIBRARY_PATH={0}".format(self.spec["boost"].libs.directories[0])) + # Parallel builds do not seem to work without this: self.args.append("-j{0}".format(make_jobs)) + return self.args + @run_after("build") + def build_docs(self): + # Run Doxygen Step after build but before install + if "+doc" in self.spec: + args = self.args + scons("doxygen", *args) + def install_args(self, spec, prefix): # SGpp expects the same args for the install and build commands return self.args @@ -191,3 +290,6 @@ def install_args(self, spec, prefix): def python_install(self): if "+python" in self.spec: pip(*PythonPipBuilder.std_args(self), f"--prefix={self.prefix}", ".") + # Install docs + if "+doc" in self.spec: + install_tree("doc", self.prefix.doc) diff --git a/var/spack/repos/builtin/packages/sgpp/set_boost_lib_path_internally.patch b/var/spack/repos/builtin/packages/sgpp/set_boost_lib_path_internally.patch new file mode 100644 index 00000000000..9b871fc7740 --- /dev/null +++ b/var/spack/repos/builtin/packages/sgpp/set_boost_lib_path_internally.patch @@ -0,0 +1,33 @@ +diff --git a/SConstruct b/SConstruct +index d7c85bd72..9d9fd494d 100644 +--- a/SConstruct ++++ b/SConstruct +@@ -443,6 +443,10 @@ if env["RUN_PYTHON_TESTS"]: + Helper.printWarning("Python tests disabled because SG_PYTHON is disabled.") + + if env["COMPILE_BOOST_TESTS"]: ++ # also add the Boost library path to the PATH ++ # so that the Boost test lib can be found when running the tests ++ env["ENV"]["LD_LIBRARY_PATH"] = os.pathsep.join([env["BOOST_LIBRARY_PATH"], ++ env["ENV"].get("LD_LIBRARY_PATH", "")]) + builder = Builder(action="./$SOURCE --log_level=test_suite") + env.Append(BUILDERS={"BoostTest" : builder}) + +diff --git a/datadriven/SConscript b/datadriven/SConscript +index 031f641cd..6380cd43f 100755 +--- a/datadriven/SConscript ++++ b/datadriven/SConscript +@@ -83,7 +83,11 @@ if env["USE_HPX"]: + module.runPythonTests() + module.buildBoostTests() + module.runBoostTests() ++# Build performance tests... + module.buildBoostTests("performanceTests", compileFlag=performanceTestFlag) +-module.runBoostTests("performanceTests", compileFlag=performanceTestFlag, +- runFlag=performanceTestRunFlag) ++# ... however, without OCL they are empty (via ifdefs) and boost would does ++# throw an error. Only run them when OCL is used ++if env["USE_OCL"]: ++ module.runBoostTests("performanceTests", compileFlag=performanceTestFlag, ++ runFlag=performanceTestRunFlag) + module.checkStyle()