From a227fec4b99b52300277d1c2355e8f2a5e09a69c Mon Sep 17 00:00:00 2001 From: G-Ragghianti <33492707+G-Ragghianti@users.noreply.github.com> Date: Wed, 12 Oct 2022 11:34:48 -0400 Subject: [PATCH 001/442] Package slate: Added deps for +rocm smoke test (#33218) * Added deps for slate+rocm smoke test * Style change --- var/spack/repos/builtin/packages/slate/package.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/var/spack/repos/builtin/packages/slate/package.py b/var/spack/repos/builtin/packages/slate/package.py index 7afb4f59fff..798acc987a5 100644 --- a/var/spack/repos/builtin/packages/slate/package.py +++ b/var/spack/repos/builtin/packages/slate/package.py @@ -117,13 +117,10 @@ def test(self): test_dir = join_path(self.test_suite.current_test_cache_dir, "examples", "build") with working_dir(test_dir, create=True): cmake_bin = join_path(self.spec["cmake"].prefix.bin, "cmake") - prefixes = ";".join( - [ - self.spec["blaspp"].prefix, - self.spec["lapackpp"].prefix, - self.spec["mpi"].prefix, - ] - ) + deps = "blaspp lapackpp mpi" + if self.spec.satisfies("+rocm"): + deps += " rocblas hip llvm-amdgpu comgr hsa-rocr-dev rocsolver" + prefixes = ";".join([self.spec[x].prefix for x in deps.split()]) self.run_test(cmake_bin, ["-DCMAKE_PREFIX_PATH=" + prefixes, ".."]) make() test_args = ["-n", "4", "./ex05_blas"] From d52eef5b16bbcbc3a37f94d277f405c842fa2fd9 Mon Sep 17 00:00:00 2001 From: iarspider Date: Wed, 12 Oct 2022 18:22:12 +0200 Subject: [PATCH 002/442] Add checksum for py-requests-oauthlib 1.3.1 (#33199) --- var/spack/repos/builtin/packages/py-requests-oauthlib/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/py-requests-oauthlib/package.py b/var/spack/repos/builtin/packages/py-requests-oauthlib/package.py index 1bb3dcc6b3f..f96fefb9ea9 100644 --- a/var/spack/repos/builtin/packages/py-requests-oauthlib/package.py +++ b/var/spack/repos/builtin/packages/py-requests-oauthlib/package.py @@ -12,6 +12,7 @@ class PyRequestsOauthlib(PythonPackage): homepage = "https://github.com/requests/requests-oauthlib" pypi = "requests-oauthlib/requests-oauthlib-1.2.0.tar.gz" + version("1.3.1", sha256="75beac4a47881eeb94d5ea5d6ad31ef88856affe2332b9aafb52c6452ccf0d7a") version("1.3.0", sha256="b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a") version("1.2.0", sha256="bd6533330e8748e94bf0b214775fed487d309b8b8fe823dc45641ebcd9a32f57") version("0.3.3", sha256="37557b4de3eef50d2a4c65dc9382148b8331f04b1c637c414b3355feb0f007e9") From 4765309b975d6b05e9a55d6d71f031c93e2ec76d Mon Sep 17 00:00:00 2001 From: Auriane R <48684432+aurianer@users.noreply.github.com> Date: Wed, 12 Oct 2022 19:10:03 +0200 Subject: [PATCH 003/442] Limit whip dependencies for pika (#33244) --- var/spack/repos/builtin/packages/pika/package.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/pika/package.py b/var/spack/repos/builtin/packages/pika/package.py index 37ae086d828..c5a1aa555fe 100644 --- a/var/spack/repos/builtin/packages/pika/package.py +++ b/var/spack/repos/builtin/packages/pika/package.py @@ -98,7 +98,8 @@ class Pika(CMakePackage, CudaPackage, ROCmPackage): depends_on("rocblas", when="+rocm") depends_on("rocsolver", when="@0.5: +rocm") depends_on("tracy-client", when="+tracy") - depends_on("whip", when="@0.9:") + depends_on("whip+rocm", when="@0.9: +rocm") + depends_on("whip+cuda", when="@0.9: +cuda") for cxxstd in cxxstds: depends_on("boost cxxstd={0}".format(map_cxxstd(cxxstd)), when="cxxstd={0}".format(cxxstd)) From 48da17d18e965030139ba8b82fc5dfb21a6471b6 Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Wed, 12 Oct 2022 21:09:52 +0200 Subject: [PATCH 004/442] py-pythran: customize headers attribute (#33242) --- var/spack/repos/builtin/packages/py-pythran/package.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/var/spack/repos/builtin/packages/py-pythran/package.py b/var/spack/repos/builtin/packages/py-pythran/package.py index 8a05c43e065..eba40ccaf38 100644 --- a/var/spack/repos/builtin/packages/py-pythran/package.py +++ b/var/spack/repos/builtin/packages/py-pythran/package.py @@ -5,6 +5,8 @@ import sys +import llnl.util.filesystem as fs + from spack.package import * @@ -54,6 +56,13 @@ class PyPythran(PythonPackage): # https://github.com/serge-sans-paille/pythran/issues/1937 conflicts("%apple-clang@13:", when="@:0.10") + @property + def headers(self): + # Pythran is mainly meant to be used as a compiler, so return no headers to + # avoid issue https://github.com/spack/spack/issues/33237 This can be refined + # later to allow using pythran also as a library. + return fs.HeaderList([]) + def patch(self): # Compiler is used at run-time to determine name of OpenMP library to search for cfg_file = join_path("pythran", "pythran-{0}.cfg".format(sys.platform)) From 042fcc35756b9909f4549d1ae1413fc9f5ae775d Mon Sep 17 00:00:00 2001 From: Glenn Johnson Date: Wed, 12 Oct 2022 16:04:20 -0500 Subject: [PATCH 005/442] update Bioconductor R packages (#33224) * Add bioc attribute to r-do-db * add version 1.38.1 to bioconductor package r-annotationforge * add version 1.30.4 to bioconductor package r-biocparallel * add version 2.64.1 to bioconductor package r-biostrings * add version 4.4.4 to bioconductor package r-clusterprofiler * add version 2.12.1 to bioconductor package r-complexheatmap * add version 1.18.1 to bioconductor package r-delayedmatrixstats * add version 3.22.1 to bioconductor package r-dose * add version 3.38.4 to bioconductor package r-edger * add version 1.16.2 to bioconductor package r-enrichplot * add version 2.20.2 to bioconductor package r-ensembldb * add version 1.32.4 to bioconductor package r-genomeinfodb * add version 1.32.1 to bioconductor package r-genomicalignments * add version 1.48.4 to bioconductor package r-genomicfeatures * add version 1.44.1 to bioconductor package r-ggbio * add version 3.4.4 to bioconductor package r-ggtree * add version 1.24.2 to bioconductor package r-hdf5array * add version 2.30.1 to bioconductor package r-iranges * add version 1.36.3 to bioconductor package r-keggrest * add version 3.52.4 to bioconductor package r-limma * add version 1.8.1 to bioconductor package r-matrixgenerics * update r-org-hs-eg-db * add version 1.38.1 to bioconductor package r-organismdbi * add version 1.36.1 to bioconductor package r-pathview * add version 1.56.1 to bioconductor package r-rtracklayer * add version 1.4.1 to bioconductor package r-scaledmatrix * add version 1.24.1 to bioconductor package r-scran * add version 1.6.3 to bioconductor package r-scuttle * add version 1.18.1 to bioconductor package r-singlecellexperiment * add version 1.20.2 to bioconductor package r-treeio * Revert "Add bioc attribute to r-do-db" This reverts commit 36be5c6072c98ec70bb16f9d613a6fe24407fee1. * Fix quotes on versions Co-authored-by: Massimiliano Culpo Co-authored-by: Tamara Dahlgren <35777542+tldahlgren@users.noreply.github.com> --- .../repos/builtin/packages/r-annotationforge/package.py | 1 + var/spack/repos/builtin/packages/r-biocparallel/package.py | 2 ++ var/spack/repos/builtin/packages/r-biostrings/package.py | 2 ++ .../repos/builtin/packages/r-clusterprofiler/package.py | 1 + .../repos/builtin/packages/r-complexheatmap/package.py | 1 + .../repos/builtin/packages/r-delayedmatrixstats/package.py | 2 ++ var/spack/repos/builtin/packages/r-dose/package.py | 1 + var/spack/repos/builtin/packages/r-edger/package.py | 1 + var/spack/repos/builtin/packages/r-enrichplot/package.py | 3 ++- var/spack/repos/builtin/packages/r-ensembldb/package.py | 1 + var/spack/repos/builtin/packages/r-genomeinfodb/package.py | 1 + .../repos/builtin/packages/r-genomicalignments/package.py | 1 + .../repos/builtin/packages/r-genomicfeatures/package.py | 1 + var/spack/repos/builtin/packages/r-ggbio/package.py | 1 + var/spack/repos/builtin/packages/r-ggtree/package.py | 1 + var/spack/repos/builtin/packages/r-hdf5array/package.py | 1 + var/spack/repos/builtin/packages/r-iranges/package.py | 1 + var/spack/repos/builtin/packages/r-keggrest/package.py | 1 + var/spack/repos/builtin/packages/r-limma/package.py | 1 + .../repos/builtin/packages/r-matrixgenerics/package.py | 1 + var/spack/repos/builtin/packages/r-org-hs-eg-db/package.py | 6 ++++++ var/spack/repos/builtin/packages/r-organismdbi/package.py | 1 + var/spack/repos/builtin/packages/r-pathview/package.py | 1 + var/spack/repos/builtin/packages/r-rtracklayer/package.py | 1 + var/spack/repos/builtin/packages/r-scaledmatrix/package.py | 1 + var/spack/repos/builtin/packages/r-scran/package.py | 1 + var/spack/repos/builtin/packages/r-scuttle/package.py | 1 + .../builtin/packages/r-singlecellexperiment/package.py | 1 + var/spack/repos/builtin/packages/r-treeio/package.py | 1 + 29 files changed, 38 insertions(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/r-annotationforge/package.py b/var/spack/repos/builtin/packages/r-annotationforge/package.py index ab4b8d0db6b..cab41691450 100644 --- a/var/spack/repos/builtin/packages/r-annotationforge/package.py +++ b/var/spack/repos/builtin/packages/r-annotationforge/package.py @@ -14,6 +14,7 @@ class RAnnotationforge(RPackage): bioc = "AnnotationForge" + version("1.38.1", commit="2dcedf353bc57bf80818e6adb1f7129c21886f6b") version("1.38.0", commit="1f77750562ea3a01f0f1a46c299184fc31196ffd") version("1.36.0", commit="523b5f0c3ffb77e59e1568e5f36a5a470bfeeae5") version("1.32.0", commit="3d17c2a945951c02fe152e5a8a8e9c6cb41e30f7") diff --git a/var/spack/repos/builtin/packages/r-biocparallel/package.py b/var/spack/repos/builtin/packages/r-biocparallel/package.py index f1a13d964f5..0a315307a97 100644 --- a/var/spack/repos/builtin/packages/r-biocparallel/package.py +++ b/var/spack/repos/builtin/packages/r-biocparallel/package.py @@ -15,6 +15,7 @@ class RBiocparallel(RPackage): bioc = "BiocParallel" + version("1.30.4", commit="1229ebe9f6d8305f9f61e562464f83f9ba86e699") version("1.30.2", commit="e7e109f7a94dbfbc50f926be030c7ad8c1a053db") version("1.28.3", commit="2f9d88ad83659939e7911d49c2d24d2cd599c7cc") version("1.24.1", commit="f713caa4314ec0ddeba7fe0eb599ad417efb413f") @@ -27,4 +28,5 @@ class RBiocparallel(RPackage): depends_on("r@3.5.0:", type=("build", "run"), when="@1.28.3:") depends_on("r-futile-logger", type=("build", "run")) depends_on("r-snow", type=("build", "run")) + depends_on("r-codetools", type=("build", "run"), when="@1.30.4:") depends_on("r-bh", type=("build", "run"), when="@1.12.0:") diff --git a/var/spack/repos/builtin/packages/r-biostrings/package.py b/var/spack/repos/builtin/packages/r-biostrings/package.py index b2279c62bcc..b4fa9866a0a 100644 --- a/var/spack/repos/builtin/packages/r-biostrings/package.py +++ b/var/spack/repos/builtin/packages/r-biostrings/package.py @@ -15,6 +15,7 @@ class RBiostrings(RPackage): bioc = "Biostrings" + version("2.64.1", commit="ffe263e958463bd1edb5d5d9316cfd89905be53c") version("2.64.0", commit="c7ad3c7af607bc8fe4a5e1c37f09e6c9bf70b4f6") version("2.62.0", commit="53ed287e03d16fa523789af3131c60375ccf587f") version("2.58.0", commit="0ec1a5455d5e9eebd14b26228906bb04e2abb197") @@ -39,6 +40,7 @@ class RBiostrings(RPackage): depends_on("r-iranges@2.9.18:", type=("build", "run"), when="@2.44.2:") depends_on("r-iranges@2.13.24:", type=("build", "run"), when="@2.48.0:") depends_on("r-iranges@2.23.9:", type=("build", "run"), when="@2.58.0:") + depends_on("r-iranges@2.30.1:", type=("build", "run"), when="@2.64.1:") depends_on("r-xvector@0.11.6:", type=("build", "run")) depends_on("r-xvector@0.19.8:", type=("build", "run"), when="@2.48.0:") depends_on("r-xvector@0.21.4:", type=("build", "run"), when="@2.50.2:") diff --git a/var/spack/repos/builtin/packages/r-clusterprofiler/package.py b/var/spack/repos/builtin/packages/r-clusterprofiler/package.py index a39b6e81422..3f3d83bb60e 100644 --- a/var/spack/repos/builtin/packages/r-clusterprofiler/package.py +++ b/var/spack/repos/builtin/packages/r-clusterprofiler/package.py @@ -15,6 +15,7 @@ class RClusterprofiler(RPackage): bioc = "clusterProfiler" + version("4.4.4", commit="9fca9a45ca1793884d8dcfd0f077353dbf75df29") version("4.4.1", commit="daad11fb80be2dd9b825e0b484815a0a2b1592a4") version("4.2.2", commit="4ebb9de8e03eedc971f54a57cf5bf1b250ed43d5") version("3.18.0", commit="064a6e612ce27e260e33af78b907bee4065ff821") diff --git a/var/spack/repos/builtin/packages/r-complexheatmap/package.py b/var/spack/repos/builtin/packages/r-complexheatmap/package.py index 2efd9ab0076..6cf4964280d 100644 --- a/var/spack/repos/builtin/packages/r-complexheatmap/package.py +++ b/var/spack/repos/builtin/packages/r-complexheatmap/package.py @@ -16,6 +16,7 @@ class RComplexheatmap(RPackage): bioc = "ComplexHeatmap" + version("2.12.1", commit="2c5fe70724219008174d4e6f83189cddbd895ec6") version("2.12.0", commit="8a5f060b06646f9d6a5032832ea72e3f183ca5d7") version("2.10.0", commit="170df82a1568e879e4019e0ff6feb0047851684f") version("2.6.2", commit="0383bada2c76dc3dde71cf6a625016b619aec4d3") diff --git a/var/spack/repos/builtin/packages/r-delayedmatrixstats/package.py b/var/spack/repos/builtin/packages/r-delayedmatrixstats/package.py index 15f852038d5..df0e57aa984 100644 --- a/var/spack/repos/builtin/packages/r-delayedmatrixstats/package.py +++ b/var/spack/repos/builtin/packages/r-delayedmatrixstats/package.py @@ -18,6 +18,7 @@ class RDelayedmatrixstats(RPackage): bioc = "DelayedMatrixStats" + version("1.18.1", commit="9c4658d11fc20b7d88e05b9c52140c2ca8a65768") version("1.18.0", commit="50c9aab259b6e8f68abf44b78122662a41c8bf47") version("1.16.0", commit="d44a3d765769cb022193428a77af25bf19916be7") version("1.12.3", commit="2b3091dfa9b3bab914e3a4157182063714ba86ae") @@ -40,6 +41,7 @@ class RDelayedmatrixstats(RPackage): depends_on("r-matrixstats@0.60.0:", type=("build", "run"), when="@1.16.0:") depends_on("r-sparsematrixstats", type=("build", "run"), when="@1.12.2:") depends_on("r-matrix", type=("build", "run")) + depends_on("r-matrix@1.5.0:", type=("build", "run"), when="@1.18.1:") depends_on("r-s4vectors", type=("build", "run")) depends_on("r-s4vectors@0.17.5:", type=("build", "run"), when="@1.2.0:") depends_on("r-iranges", type=("build", "run")) diff --git a/var/spack/repos/builtin/packages/r-dose/package.py b/var/spack/repos/builtin/packages/r-dose/package.py index 3b1716da587..99c36609ab0 100644 --- a/var/spack/repos/builtin/packages/r-dose/package.py +++ b/var/spack/repos/builtin/packages/r-dose/package.py @@ -18,6 +18,7 @@ class RDose(RPackage): bioc = "DOSE" + version("3.22.1", commit="6b711a0f076a9fefcb00ddef66e8f198039e6dfa") version("3.22.0", commit="242ac1b746c44fbbf281fbe6e5e4424a8dc74375") version("3.20.1", commit="bf434f24d035217822cb1b0ab08a486b9a53edb4") version("3.16.0", commit="a534a4f2ef1e54e8b92079cf1bbedb5042fd90cd") diff --git a/var/spack/repos/builtin/packages/r-edger/package.py b/var/spack/repos/builtin/packages/r-edger/package.py index ab3610f4734..2dc5026083d 100644 --- a/var/spack/repos/builtin/packages/r-edger/package.py +++ b/var/spack/repos/builtin/packages/r-edger/package.py @@ -19,6 +19,7 @@ class REdger(RPackage): bioc = "edgeR" + version("3.38.4", commit="f5a3bb568a23b34146ac66329a95ee4785093536") version("3.38.1", commit="e58bf52f34ec451096f593126922ad7e5d517f7e") version("3.36.0", commit="c7db03addfc42138a1901834409c02da9d873026") version("3.32.1", commit="b881d801d60e5b38413d27f149384c218621c55a") diff --git a/var/spack/repos/builtin/packages/r-enrichplot/package.py b/var/spack/repos/builtin/packages/r-enrichplot/package.py index dc7597b6ea4..24f204a5eaa 100644 --- a/var/spack/repos/builtin/packages/r-enrichplot/package.py +++ b/var/spack/repos/builtin/packages/r-enrichplot/package.py @@ -16,6 +16,7 @@ class REnrichplot(RPackage): bioc = "enrichplot" + version("1.16.2", commit="eeb21345288d96c116ac308649fa772d03760259") version("1.16.1", commit="cff77b622b2312be546714ec437aa4bc585bac87") version("1.14.1", commit="ccf3a6d9b7cd9cffd8de6d6263efdffe59d2ec36") version("1.10.2", commit="77ee04f60a07cc31151f8f47f8ee64f3a43c9760") @@ -49,5 +50,5 @@ class REnrichplot(RPackage): depends_on("r-europepmc", type=("build", "run"), when="@1.2.0:1.4.0") depends_on("r-ggplotify", type=("build", "run"), when="@1.2.0:1.4.0") depends_on("r-gridextra", type=("build", "run"), when="@1.2.0:1.4.0") - depends_on("r-cowplot", type=("build", "run")) + depends_on("r-cowplot", when="@:1.16.1") diff --git a/var/spack/repos/builtin/packages/r-ensembldb/package.py b/var/spack/repos/builtin/packages/r-ensembldb/package.py index 8e2403c6bf8..da2dc2dfe28 100644 --- a/var/spack/repos/builtin/packages/r-ensembldb/package.py +++ b/var/spack/repos/builtin/packages/r-ensembldb/package.py @@ -24,6 +24,7 @@ class REnsembldb(RPackage): bioc = "ensembldb" + version("2.20.2", commit="ac1fb8389efd88099600af298d6bb3384206f9ed") version("2.20.1", commit="e547d184730cfe5e65f59e4f3512395fb1cdba1a") version("2.18.3", commit="e2fcfc0c7700110df070a171d2d542b37ec098f3") version("2.14.0", commit="c7150519ed4ef38e5eac1043209863dbc7be43a1") diff --git a/var/spack/repos/builtin/packages/r-genomeinfodb/package.py b/var/spack/repos/builtin/packages/r-genomeinfodb/package.py index de08108955d..e9218f10e0b 100644 --- a/var/spack/repos/builtin/packages/r-genomeinfodb/package.py +++ b/var/spack/repos/builtin/packages/r-genomeinfodb/package.py @@ -17,6 +17,7 @@ class RGenomeinfodb(RPackage): bioc = "GenomeInfoDb" + version("1.32.4", commit="69df6a5a10027fecf6a6d1c8298f3f686b990d8f") version("1.32.2", commit="2e40af38f00ee86d2c83d140e234c1349baa27de") version("1.30.1", commit="bf8b385a2ffcecf9b41e581794056f267895863d") version("1.26.2", commit="96dd27a7e3ef476790b1475aab50dbbed7df67a2") diff --git a/var/spack/repos/builtin/packages/r-genomicalignments/package.py b/var/spack/repos/builtin/packages/r-genomicalignments/package.py index 3a2cb8c2deb..20f659508c4 100644 --- a/var/spack/repos/builtin/packages/r-genomicalignments/package.py +++ b/var/spack/repos/builtin/packages/r-genomicalignments/package.py @@ -16,6 +16,7 @@ class RGenomicalignments(RPackage): bioc = "GenomicAlignments" + version("1.32.1", commit="2553580d0b8a8a5fd7835c1446616b39f707b8a9") version("1.32.0", commit="7a660a914a04e2eb0758082b6f64c4124a887ef3") version("1.30.0", commit="2d2c5fce3529c2962fdcefd736d8b7f7c0ec2d54") version("1.26.0", commit="6c74c74ee53efcd880171126366fee4bd72357bc") diff --git a/var/spack/repos/builtin/packages/r-genomicfeatures/package.py b/var/spack/repos/builtin/packages/r-genomicfeatures/package.py index 491b8632bc1..2da07056944 100644 --- a/var/spack/repos/builtin/packages/r-genomicfeatures/package.py +++ b/var/spack/repos/builtin/packages/r-genomicfeatures/package.py @@ -20,6 +20,7 @@ class RGenomicfeatures(RPackage): bioc = "GenomicFeatures" + version("1.48.4", commit="06e37dc1847d49d91391264caec877ed33abf359") version("1.48.3", commit="b0ddea0e101e3861928f3ad353348df047d90382") version("1.46.4", commit="d3ab6fd069624904ce7fcdf75dad884473f97975") version("1.42.1", commit="2e82891974138b0e976799d64a8938f0be61284d") diff --git a/var/spack/repos/builtin/packages/r-ggbio/package.py b/var/spack/repos/builtin/packages/r-ggbio/package.py index b310a41ee4c..1ea9655c07e 100644 --- a/var/spack/repos/builtin/packages/r-ggbio/package.py +++ b/var/spack/repos/builtin/packages/r-ggbio/package.py @@ -21,6 +21,7 @@ class RGgbio(RPackage): bioc = "ggbio" + version("1.44.1", commit="0301d9464e304a8113ea4479185cd358855ca365") version("1.44.0", commit="cb21284a9803917fa76e116adfc456525c95f660") version("1.42.0", commit="3540047ef018957d59fba8af7d3c58e4659f8e26") version("1.38.0", commit="c39c51993f419cfc2f094e664477f25f5212a242") diff --git a/var/spack/repos/builtin/packages/r-ggtree/package.py b/var/spack/repos/builtin/packages/r-ggtree/package.py index bc3e5eddfd7..9128cffcf83 100644 --- a/var/spack/repos/builtin/packages/r-ggtree/package.py +++ b/var/spack/repos/builtin/packages/r-ggtree/package.py @@ -16,6 +16,7 @@ class RGgtree(RPackage): bioc = "ggtree" + version("3.4.4", commit="8e48d3e2ea445b6c2213f0471462108a7a72b333") version("3.4.0", commit="23f08a3da1829d1bbb6827ed1c4cf878daa4b539") version("3.2.1", commit="d3747e636fe1a6a9e09b56a3a3899208ebd05547") diff --git a/var/spack/repos/builtin/packages/r-hdf5array/package.py b/var/spack/repos/builtin/packages/r-hdf5array/package.py index 024eee78fed..ca60baa1e13 100644 --- a/var/spack/repos/builtin/packages/r-hdf5array/package.py +++ b/var/spack/repos/builtin/packages/r-hdf5array/package.py @@ -20,6 +20,7 @@ class RHdf5array(RPackage): bioc = "HDF5Array" + version("1.24.2", commit="fb213ba36631b04dfe754705f701f3a015c4fc82") version("1.24.1", commit="d002fe70c84baaadb62058ce467d6c1ea032d8f5") version("1.22.1", commit="b3f091fbc159609e8e0792d2bf9fbef52c6ceede") version("1.18.0", commit="d5bd55d170cb384fdebdf60751e1e28483782caa") diff --git a/var/spack/repos/builtin/packages/r-iranges/package.py b/var/spack/repos/builtin/packages/r-iranges/package.py index 80e44d5d7e5..4cf880670ae 100644 --- a/var/spack/repos/builtin/packages/r-iranges/package.py +++ b/var/spack/repos/builtin/packages/r-iranges/package.py @@ -18,6 +18,7 @@ class RIranges(RPackage): bioc = "IRanges" + version("2.30.1", commit="ead506a14d6cc89ac2f14b55a4b04496755e4e50") version("2.30.0", commit="9b5f3ca12812fb76c23b1550aa3a794384384d9b") version("2.28.0", commit="d85ee908a379e12d1e32599e999c71ab37c25e57") version("2.24.1", commit="6c61fddf4c5830f69a0f7f108888c67cd0a12b19") diff --git a/var/spack/repos/builtin/packages/r-keggrest/package.py b/var/spack/repos/builtin/packages/r-keggrest/package.py index 4a081d71326..20bf8b0e315 100644 --- a/var/spack/repos/builtin/packages/r-keggrest/package.py +++ b/var/spack/repos/builtin/packages/r-keggrest/package.py @@ -15,6 +15,7 @@ class RKeggrest(RPackage): bioc = "KEGGREST" + version("1.36.3", commit="1827cde76863aa80c83264a0dd95514654358df3") version("1.36.0", commit="591818bbc9195bfd0657cf4f5c7c771ea7f86830") version("1.34.0", commit="2056750dc202fa04a34b84c6c712e884c7cad2bd") version("1.30.1", commit="fd9970ea9df117d625257b8c6351cf85098cfbc1") diff --git a/var/spack/repos/builtin/packages/r-limma/package.py b/var/spack/repos/builtin/packages/r-limma/package.py index 6bc580bb2f4..8d92ec55058 100644 --- a/var/spack/repos/builtin/packages/r-limma/package.py +++ b/var/spack/repos/builtin/packages/r-limma/package.py @@ -14,6 +14,7 @@ class RLimma(RPackage): bioc = "limma" + version("3.52.4", commit="3226c29ad8c18aa7e6722f4a2c95ff8ac900437e") version("3.52.1", commit="c81c539a217ac1cf46e850f8a20266cecfafed50") version("3.50.0", commit="657b19bbc33c5c941af79aeb68967bf42ea40e23") version("3.46.0", commit="ff03542231827f39ebde6464cdbba0110e24364e") diff --git a/var/spack/repos/builtin/packages/r-matrixgenerics/package.py b/var/spack/repos/builtin/packages/r-matrixgenerics/package.py index bfada6c30de..289f23d36af 100644 --- a/var/spack/repos/builtin/packages/r-matrixgenerics/package.py +++ b/var/spack/repos/builtin/packages/r-matrixgenerics/package.py @@ -19,6 +19,7 @@ class RMatrixgenerics(RPackage): bioc = "MatrixGenerics" + version("1.8.1", commit="a4a21089e9f78275dd4a6f0df0c4b6b45c4650c7") version("1.8.0", commit="e4cc34d53bcfb9a5914afd79fda31ecd5037a47a") version("1.6.0", commit="4588a60e5cc691424c17faa281bdd7d99d83ec34") version("1.2.1", commit="abcc9ca0504e0b915cd7933a3169a8e9e5bd2fe9") diff --git a/var/spack/repos/builtin/packages/r-org-hs-eg-db/package.py b/var/spack/repos/builtin/packages/r-org-hs-eg-db/package.py index d8edda67ff8..2892bc3480f 100644 --- a/var/spack/repos/builtin/packages/r-org-hs-eg-db/package.py +++ b/var/spack/repos/builtin/packages/r-org-hs-eg-db/package.py @@ -15,6 +15,11 @@ class ROrgHsEgDb(RPackage): bioc = "org.Hs.eg.db" url = "https://www.bioconductor.org/packages/3.5/data/annotation/src/contrib/org.Hs.eg.db_3.4.1.tar.gz" + version( + "3.15.0", + sha256="1dc9bb6019e0f0a222b9ec84a1c5870cdbca480f45d9ad08e35f77278baa3c5f", + url="https://www.bioconductor.org/packages/3.15/data/annotation/src/contrib/org.Hs.eg.db_3.15.0.tar.gz", + ) version( "3.14.0", sha256="0f87b3f1925a1d7007e5ad9200bdf511788bd1d7cb76f1121feeb109889c2b00", @@ -41,3 +46,4 @@ class ROrgHsEgDb(RPackage): depends_on("r-annotationdbi@1.43.1:", type=("build", "run"), when="@3.8.2:") depends_on("r-annotationdbi@1.51.3:", type=("build", "run"), when="@3.12.0:") depends_on("r-annotationdbi@1.55.1:", type=("build", "run"), when="@3.14.0:") + depends_on("r-annotationdbi@1.57.1:", type=("build", "run"), when="@3.15.0:") diff --git a/var/spack/repos/builtin/packages/r-organismdbi/package.py b/var/spack/repos/builtin/packages/r-organismdbi/package.py index bd289585864..5ae90de6299 100644 --- a/var/spack/repos/builtin/packages/r-organismdbi/package.py +++ b/var/spack/repos/builtin/packages/r-organismdbi/package.py @@ -16,6 +16,7 @@ class ROrganismdbi(RPackage): bioc = "OrganismDbi" + version("1.38.1", commit="fa8da4dd42ab15e1d21fd9f8286440596d50b1ec") version("1.38.0", commit="2ca01830a6ffcd0c0018d2bdbd3de8b4df716771") version("1.36.0", commit="3e7a90d248ff09f05ccd381ff921e12373a4b330") version("1.32.0", commit="c8100c4fea17bf1b10d4efacc73a7e2866d649e3") diff --git a/var/spack/repos/builtin/packages/r-pathview/package.py b/var/spack/repos/builtin/packages/r-pathview/package.py index 01a8f0f8709..92b017f1581 100644 --- a/var/spack/repos/builtin/packages/r-pathview/package.py +++ b/var/spack/repos/builtin/packages/r-pathview/package.py @@ -20,6 +20,7 @@ class RPathview(RPackage): bioc = "pathview" + version("1.36.1", commit="f2e86b106c1cd91aac703337f968b7593a61c68d") version("1.36.0", commit="4f6be090a4089b5259d8e796d62f9830e2d63943") version("1.34.0", commit="a8788902a3bb047f8ee785966e57f84596076bbd") version("1.30.1", commit="a6a32395db408798cb076894678e90148bae6bf4") diff --git a/var/spack/repos/builtin/packages/r-rtracklayer/package.py b/var/spack/repos/builtin/packages/r-rtracklayer/package.py index e095dd3251c..a52013b3290 100644 --- a/var/spack/repos/builtin/packages/r-rtracklayer/package.py +++ b/var/spack/repos/builtin/packages/r-rtracklayer/package.py @@ -18,6 +18,7 @@ class RRtracklayer(RPackage): bioc = "rtracklayer" + version("1.56.1", commit="4c6d2201fcb102d471bd88f4f51cc34317669955") version("1.56.0", commit="1d70f7dc464ad87a1fde61588cd9ae0cb86b6e86") version("1.54.0", commit="04cdd75521a8364e67a49d7352500dd4a3e83c55") version("1.50.0", commit="d2e61f72ff5d5a94c2c487ba108a37f23bfcc1e6") diff --git a/var/spack/repos/builtin/packages/r-scaledmatrix/package.py b/var/spack/repos/builtin/packages/r-scaledmatrix/package.py index e99dc8dac29..b49f1235d52 100644 --- a/var/spack/repos/builtin/packages/r-scaledmatrix/package.py +++ b/var/spack/repos/builtin/packages/r-scaledmatrix/package.py @@ -16,6 +16,7 @@ class RScaledmatrix(RPackage): bioc = "ScaledMatrix" + version("1.4.1", commit="15e2efcb6b11e26c31ef2d44968355f71cc1f4fc") version("1.4.0", commit="32e6e918bc7bb64bbf75613d353ca268c7d04292") version("1.2.0", commit="d0573e14ca537b40ade7dd1c9cf0cadae60d4349") diff --git a/var/spack/repos/builtin/packages/r-scran/package.py b/var/spack/repos/builtin/packages/r-scran/package.py index fcf4f46534a..cac48a6e176 100644 --- a/var/spack/repos/builtin/packages/r-scran/package.py +++ b/var/spack/repos/builtin/packages/r-scran/package.py @@ -17,6 +17,7 @@ class RScran(RPackage): bioc = "scran" + version("1.24.1", commit="1a83eb7c948b1dc49253080c23b26cefb3a0f3b9") version("1.24.0", commit="c3f9e169c4538ce827d4f14a4141571c2366cd31") depends_on("r-singlecellexperiment", type=("build", "run")) diff --git a/var/spack/repos/builtin/packages/r-scuttle/package.py b/var/spack/repos/builtin/packages/r-scuttle/package.py index 6862bf38068..2ed9145d158 100644 --- a/var/spack/repos/builtin/packages/r-scuttle/package.py +++ b/var/spack/repos/builtin/packages/r-scuttle/package.py @@ -16,6 +16,7 @@ class RScuttle(RPackage): bioc = "scuttle" + version("1.6.3", commit="df23680da9fa4d685df77e4561467f491c850b50") version("1.6.2", commit="afdfc555151d84cc332757b4ec0b97cb7f39d2d5") version("1.4.0", commit="b335263dd56bb859b5dd3ea27ee00dffa0215313") version("1.0.4", commit="a827e2759d80e6c3510e2f8fd4bd680274206d9f") diff --git a/var/spack/repos/builtin/packages/r-singlecellexperiment/package.py b/var/spack/repos/builtin/packages/r-singlecellexperiment/package.py index d024ae131a8..47719faeb76 100644 --- a/var/spack/repos/builtin/packages/r-singlecellexperiment/package.py +++ b/var/spack/repos/builtin/packages/r-singlecellexperiment/package.py @@ -16,6 +16,7 @@ class RSinglecellexperiment(RPackage): bioc = "SingleCellExperiment" + version("1.18.1", commit="db7768a7cb5eca724bcf7e4cea3234992ac714a1") version("1.18.0", commit="3a72dcd97e628055b2d02294eaecca9a41aba604") version("1.16.0", commit="bb27609ba08052607fc08529ffbbbcf1eab265cb") version("1.12.0", commit="66063b74c8b0bd0fd1277c7ad425ad11823ab356") diff --git a/var/spack/repos/builtin/packages/r-treeio/package.py b/var/spack/repos/builtin/packages/r-treeio/package.py index 64b8dce4203..17cf92167da 100644 --- a/var/spack/repos/builtin/packages/r-treeio/package.py +++ b/var/spack/repos/builtin/packages/r-treeio/package.py @@ -18,6 +18,7 @@ class RTreeio(RPackage): bioc = "treeio" + version("1.20.2", commit="ed457d6fd85a50e0993c8c9acbd9b701be01a348") version("1.20.0", commit="5f7c3704fc8202c52451d092148fdcfe683f026a") version("1.18.1", commit="a06b6b3d2a64f1b22c6c8c5f97c08f5863349c83") From 8dbdfbd1eb326c7eb14e0c0b6ca7280642a8e74a Mon Sep 17 00:00:00 2001 From: Filippo Spiga Date: Wed, 12 Oct 2022 22:17:53 +0100 Subject: [PATCH 006/442] NVIDIA HPC SDK: add v22.9 (#33258) --- var/spack/repos/builtin/packages/nvhpc/package.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/var/spack/repos/builtin/packages/nvhpc/package.py b/var/spack/repos/builtin/packages/nvhpc/package.py index 1a8751559cc..b7e625b97c5 100644 --- a/var/spack/repos/builtin/packages/nvhpc/package.py +++ b/var/spack/repos/builtin/packages/nvhpc/package.py @@ -21,6 +21,20 @@ # - package key must be in the form '{os}-{arch}' where 'os' is in the # format returned by platform.system() and 'arch' by platform.machine() _versions = { + "22.9": { + "Linux-aarch64": ( + "bc4473f04b49bc9a26f08c17a72360650ddf48a3b6eefacdc525d79c8d730f30", + "https://developer.download.nvidia.com/hpc-sdk/22.9/nvhpc_2022_229_Linux_aarch64_cuda_multi.tar.gz", + ), + "Linux-ppc64le": ( + "9aac31d36bb09f6653544978021f5b78c272112e7748871566f7e930f5e7475b", + "https://developer.download.nvidia.com/hpc-sdk/22.9/nvhpc_2022_229_Linux_ppc64le_cuda_multi.tar.gz", + ), + "Linux-x86_64": ( + "aebfeb826ace3dabf9699f72390ca0340f8789a8ef6fe4032e3c7b794f073ea3", + "https://developer.download.nvidia.com/hpc-sdk/22.9/nvhpc_2022_229_Linux_x86_64_cuda_multi.tar.gz", + ), + }, "22.7": { "Linux-aarch64": ( "2aae3fbfd2d0d2d09448a36166c42311368f5600c7c346f159c280b412fe924a", From 5009e3d94a2182c976c4f240caeacf21978300ed Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Wed, 12 Oct 2022 23:30:00 +0200 Subject: [PATCH 007/442] env depfile: allow deps only install (#33245) * env depfile: allow deps only install - Refactor `spack env depfile` to use a Jinja template, making it a bit easier to follow as a human being. - Add a layer of indirection in the generated Makefile through an `/.install-deps/` target, which allows one to specify different options when installing dependencies. For example, only verbose/debug mode on when installing some particular spec: ``` $ spack -e my_env env depfile -o Makefile --make-target-prefix example $ make example/.install-deps/ -j16 $ make example/.install/ SPACK="spack -d" SPACK_INSTALL_FLAGS=--verbose -j16 ``` This could be used to speed up `spack ci rebuild`: - Parallel install of dependencies from buildcache - Better readability of logs, e.g. reducing verbosity when installing dependencies, and splitting logs into deps.log and current_spec.log * Silence please! --- lib/spack/spack/cmd/env.py | 90 ++++++++------------------ lib/spack/spack/tengine.py | 1 + share/spack/templates/depfile/Makefile | 37 +++++++++++ 3 files changed, 66 insertions(+), 62 deletions(-) create mode 100644 share/spack/templates/depfile/Makefile diff --git a/lib/spack/spack/cmd/env.py b/lib/spack/spack/cmd/env.py index 86953a7bccd..e421e300e1e 100644 --- a/lib/spack/spack/cmd/env.py +++ b/lib/spack/spack/cmd/env.py @@ -24,6 +24,7 @@ import spack.environment as ev import spack.environment.shell import spack.schema.env +import spack.tengine import spack.util.string as string from spack.util.environment import EnvironmentModifications @@ -641,6 +642,9 @@ def get_target(name): def get_install_target(name): return os.path.join(target_prefix, ".install", name) + def get_install_deps_target(name): + return os.path.join(target_prefix, ".install-deps", name) + for _, spec in env.concretized_specs(): for s in spec.traverse(root=True): hash_to_spec[s.dag_hash()] = s @@ -655,76 +659,38 @@ def get_install_target(name): # All package install targets, not just roots. all_install_targets = [get_install_target(h) for h in hash_to_spec.keys()] + all_install_deps_targets = [get_install_deps_target(h) for h, _ in hash_to_prereqs.items()] buf = six.StringIO() - buf.write( - """SPACK ?= spack + template = spack.tengine.make_environment().get_template(os.path.join("depfile", "Makefile")) -.PHONY: {} {} - -{}: {} - -{}: {} -\t@touch $@ - -{}: -\t@mkdir -p {} - -{}: | {} -\t$(info Installing $(SPEC)) -\t{}$(SPACK) -e '{}' install $(SPACK_INSTALL_FLAGS) --only-concrete --only=package \ ---no-add /$(notdir $@) && touch $@ - -""".format( - get_target("all"), - get_target("clean"), - get_target("all"), - get_target("env"), - get_target("env"), - " ".join(root_install_targets), - get_target("dirs"), - get_target(".install"), - get_target(".install/%"), - get_target("dirs"), - "+" if args.jobserver else "", - env.path, - ) - ) - - # Targets are of the form /: [/]..., - # The prefix can be an empty string, in that case we don't add the `/`. - # The name is currently the dag hash of the spec. In principle it - # could be the package name in case of `concretization: together` so - # it can be more easily referred to, but for now we don't special case - # this. fmt = "{name}{@version}{%compiler}{variants}{arch=architecture}" + hash_with_name = [(h, hash_to_spec[h].format(fmt)) for h in hash_to_prereqs.keys()] + targets_to_prereqs = [ + (get_install_deps_target(h), " ".join(prereqs)) for h, prereqs in hash_to_prereqs.items() + ] - # Set SPEC for each hash - buf.write("# Set the human-readable spec for each target\n") - for dag_hash in hash_to_prereqs.keys(): - formatted_spec = hash_to_spec[dag_hash].format(fmt) - buf.write("{}: SPEC = {}\n".format(get_target("%/" + dag_hash), formatted_spec)) - buf.write("\n") - - # Set install dependencies - buf.write("# Install dependencies\n") - for parent, children in hash_to_prereqs.items(): - if not children: - continue - buf.write("{}: {}\n".format(get_install_target(parent), " ".join(children))) - buf.write("\n") - - # Clean target: remove target files but not their folders, cause - # --make-target-prefix can be any existing directory we do not control, - # including empty string (which means deleting the containing folder - # would delete the folder with the Makefile) - buf.write( - "{}:\n\trm -f -- {} {}\n".format( - get_target("clean"), get_target("env"), " ".join(all_install_targets) - ) + rendered = template.render( + { + "all_target": get_target("all"), + "env_target": get_target("env"), + "clean_target": get_target("clean"), + "all_install_targets": " ".join(all_install_targets), + "all_install_deps_targets": " ".join(all_install_deps_targets), + "root_install_targets": " ".join(root_install_targets), + "dirs_target": get_target("dirs"), + "environment": env.path, + "install_target": get_target(".install"), + "install_deps_target": get_target(".install-deps"), + "any_hash_target": get_target("%"), + "hash_with_name": hash_with_name, + "jobserver_support": "+" if args.jobserver else "", + "targets_to_prereqs": targets_to_prereqs, + } ) + buf.write(rendered) makefile = buf.getvalue() # Finally write to stdout/file. diff --git a/lib/spack/spack/tengine.py b/lib/spack/spack/tengine.py index 34db15d832a..75dae5c9c1c 100644 --- a/lib/spack/spack/tengine.py +++ b/lib/spack/spack/tengine.py @@ -11,6 +11,7 @@ import llnl.util.lang import spack.config +import spack.extensions from spack.util.path import canonicalize_path diff --git a/share/spack/templates/depfile/Makefile b/share/spack/templates/depfile/Makefile new file mode 100644 index 00000000000..a149951d9f2 --- /dev/null +++ b/share/spack/templates/depfile/Makefile @@ -0,0 +1,37 @@ +SPACK ?= spack + +.PHONY: {{ all_target }} {{ clean_target }} + +{{ all_target }}: {{ env_target }} + +{{ env_target }}: {{ root_install_targets }} + @touch $@ + +{{ dirs_target }}: + @mkdir -p {{ install_target }} {{ install_deps_target }} + +# The spack install commands are of the form: +# spack -e my_env --no-add --only=package --only=concrete /hash +# This is an involved way of expressing that Spack should only install +# an individual concrete spec from the environment without deps. +{{ install_target }}/%: {{ install_deps_target }}/% | {{ dirs_target }} + $(info Installing $(SPEC)) + {{ jobserver_support }}$(SPACK) -e '{{ environment }}' install $(SPACK_INSTALL_FLAGS) --only-concrete --only=package --no-add /$(notdir $@) + @touch $@ + +# Targets of the form {{ install_deps_target }}/ install dependencies only +{{ install_deps_target }}/%: | {{ dirs_target }} + @touch $@ + +# Set a human-readable SPEC variable for each target that has a hash +{% for (hash, name) in hash_with_name -%} +{{ any_hash_target }}/{{ hash }}: SPEC = {{ name }} +{% endfor %} + +# The Spack DAG expressed in targets: +{% for (target, prereqs) in targets_to_prereqs -%} +{{ target }}: {{prereqs}} +{% endfor %} + +{{ clean_target }}: + rm -rf {{ env_target }} {{ all_install_targets }} {{ all_install_deps_targets }} From f24c135383399c5ea4a78744470b66dd729a1601 Mon Sep 17 00:00:00 2001 From: Brian Van Essen Date: Wed, 12 Oct 2022 14:35:45 -0700 Subject: [PATCH 008/442] Added hash for version 2.7.0-6 (#33263) --- var/spack/repos/builtin/packages/nvshmem/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/nvshmem/package.py b/var/spack/repos/builtin/packages/nvshmem/package.py index d007c6c6115..bf91fb75dd7 100644 --- a/var/spack/repos/builtin/packages/nvshmem/package.py +++ b/var/spack/repos/builtin/packages/nvshmem/package.py @@ -18,6 +18,7 @@ class Nvshmem(MakefilePackage, CudaPackage): maintainers = ["bvanessen"] + version("2.7.0-6", sha256="23ed9b0187104dc87d5d2bc1394b6f5ff29e8c19138dc019d940b109ede699df") version("2.6.0-1", sha256="fc0e8de61b034f3a079dc231b1d0955e665a9f57b5013ee98b6743647bd60417") version("2.5.0-19", sha256="dd800b40f1d296e1d3ed2a9885adcfe745c3e57582bc809860e87bd32abcdc60") version("2.4.1-3", sha256="8b6c0eab321b6352911e470f9e81a777a49e58148ec3728453b9522446dba178") From a2dee76310ebd04bfe9cdfdbdeb2eda4a77dc1b9 Mon Sep 17 00:00:00 2001 From: Max Zeyen Date: Thu, 13 Oct 2022 00:23:19 +0200 Subject: [PATCH 009/442] gpi-space: add new version (#33184) * gpi-space: add new version * gpi-space: fix flake8 formatting issues * gpi-space: fix more flake8 issues --- .../builtin/packages/gpi-space/package.py | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/var/spack/repos/builtin/packages/gpi-space/package.py b/var/spack/repos/builtin/packages/gpi-space/package.py index 97dc85159f1..b5066e7e496 100644 --- a/var/spack/repos/builtin/packages/gpi-space/package.py +++ b/var/spack/repos/builtin/packages/gpi-space/package.py @@ -24,24 +24,33 @@ class GpiSpace(CMakePackage): maintainers = ["mzeyen1985", "tiberot", "rumach", "mrahn", "acastanedam"] version("latest", branch="main") + version("22.09", sha256="f938847205181081ed24896bba16302ac35bbf478b4ceecae5bb21d5a38c8556") version("22.06", sha256="d89d8a7b574430c4f151a3768073fa44d32e5cc7606fbe0f58aeedf6f5fefc0b") version("22.03", sha256="b01500b9480452aee865a0ef98cf40864f847b7e22ea572f9a6f0f5ac2ae9a1a") version("21.12.1", sha256="6c49aca95a32e66fa1e34bef542c2f380e91f86c9c2b3b0d98921901bab7abce") version("21.12", sha256="51794e2b593b8d1dc7d6310e17744842919bf44205b2cb7a79de2f2bbac3352a") version("21.09", sha256="7f3861c2bfec15a4da46378ea38b304e1462ed315cd315b81ab2c2a8ba50dd3e") + variant( + "monitor", + default=True, + description=""" + Enables the gspc-monitor application for execution monitoring. + """, + ) + variant( + "iml", + default=True, + description=""" + Enables IML support + """, + ) variant( "network", default="ethernet", values=("infiniband", "ethernet"), description="GPI-2 fabric to enable", - ) - variant( - "monitor", - default=True, - description=""" - Enables the gspc-monitor application for execution monitoring. - """, + when="+iml", ) variant( "build_type", @@ -61,8 +70,9 @@ class GpiSpace(CMakePackage): depends_on("hwloc@1.10: +libudev ~libxml2 libs=static") depends_on("libssh2@1.7:") depends_on("openssl@0.9:") - depends_on("gpi-2@1.3.2:1.3.3 fabrics=infiniband", when="network=infiniband") - depends_on("gpi-2@1.3.2:1.3.3 fabrics=ethernet", when="network=ethernet") + with when("+iml"): + depends_on("gpi-2@1.3.2:1.3.3 fabrics=infiniband", when="network=infiniband") + depends_on("gpi-2@1.3.2:1.3.3 fabrics=ethernet", when="network=ethernet") depends_on("qt@5.9:5.15", when="+monitor") def cmake_args(self): @@ -71,6 +81,7 @@ def cmake_args(self): self.define("INSTALL_DO_NOT_BUNDLE", True), self.define("BUILD_TESTING", False), self.define_from_variant("GSPC_WITH_MONITOR_APP", "monitor"), + self.define_from_variant("GSPC_WITH_IML", "iml"), ] return args From 40c400441a75d80f6a901554aeebb5f1100ea3c5 Mon Sep 17 00:00:00 2001 From: William R Tobin <4522899+wrtobin@users.noreply.github.com> Date: Wed, 12 Oct 2022 15:28:35 -0700 Subject: [PATCH 010/442] exodusii: add fortran variant (#33074) * add fortran variant, pass cmake options to build with fortran + specified compiler/mpi compiler wrapper (following existing style in the package), activate exodus fortran wrapper library compilation * change variant description, fix style --- var/spack/repos/builtin/packages/exodusii/package.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/var/spack/repos/builtin/packages/exodusii/package.py b/var/spack/repos/builtin/packages/exodusii/package.py index c9cd90eedcd..72963398d94 100644 --- a/var/spack/repos/builtin/packages/exodusii/package.py +++ b/var/spack/repos/builtin/packages/exodusii/package.py @@ -56,6 +56,7 @@ class Exodusii(CMakePackage): version("master", branch="master") variant("mpi", default=True, description="Enables MPI parallelism.") + variant("fortran", default=False, description="Build Fortran wrapper libraries.") depends_on("cmake@2.8.11:", type="build") depends_on("mpi", when="+mpi") @@ -88,6 +89,16 @@ def cmake_args(self): "-DCMAKE_C_COMPILER={0}".format(cc_path), "-DCMAKE_CXX_COMPILER={0}".format(cxx_path), ] + if "+fortran" in spec: + fc_path = spec["mpi"].mpifc if "+mpi" in spec else self.compiler.f90 + options.extend( + [ + "-DSEACASProj_ENABLE_Fortran:BOOL=ON", + "-DCMAKE_Fortran_COMPILER={0}".format(fc_path), + "-DSEACASProj_ENABLE_SEACASExodus_for:BOOL=ON", + "-DSEACASProj_ENABLE_SEACASExoIIv2for32:BOOL=ON", + ] + ) # Python # # Handle v2016 separately because of older tribits if spec.satisfies("@:2016-08-09"): From 601c727491089d29e36e3cae8d86a507e94764f8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Oct 2022 09:48:55 +0200 Subject: [PATCH 011/442] Bump docker/setup-buildx-action from 2.0.0 to 2.1.0 (#33267) Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 2.0.0 to 2.1.0. - [Release notes](https://github.com/docker/setup-buildx-action/releases) - [Commits](https://github.com/docker/setup-buildx-action/compare/dc7b9719a96d48369863986a06765841d7ea23f6...95cb08cb2672c73d4ffd2f422e6d11953d2a9c70) --- updated-dependencies: - dependency-name: docker/setup-buildx-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-containers.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-containers.yml b/.github/workflows/build-containers.yml index 9e395974d34..c5b7567dbda 100644 --- a/.github/workflows/build-containers.yml +++ b/.github/workflows/build-containers.yml @@ -89,7 +89,7 @@ jobs: uses: docker/setup-qemu-action@8b122486cedac8393e77aa9734c3528886e4a1a8 # @v1 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@dc7b9719a96d48369863986a06765841d7ea23f6 # @v1 + uses: docker/setup-buildx-action@95cb08cb2672c73d4ffd2f422e6d11953d2a9c70 # @v1 - name: Log in to GitHub Container Registry uses: docker/login-action@49ed152c8eca782a232dede0303416e8f356c37b # @v1 From a8b1314d188149e696eb8e7ba3e4d0de548f1894 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Oct 2022 09:49:26 +0200 Subject: [PATCH 012/442] Bump docker/login-action from 2.0.0 to 2.1.0 (#33268) Bumps [docker/login-action](https://github.com/docker/login-action) from 2.0.0 to 2.1.0. - [Release notes](https://github.com/docker/login-action/releases) - [Commits](https://github.com/docker/login-action/compare/49ed152c8eca782a232dede0303416e8f356c37b...f4ef78c080cd8ba55a85445d5b36e214a81df20a) --- updated-dependencies: - dependency-name: docker/login-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-containers.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-containers.yml b/.github/workflows/build-containers.yml index c5b7567dbda..0662ad75c5c 100644 --- a/.github/workflows/build-containers.yml +++ b/.github/workflows/build-containers.yml @@ -92,7 +92,7 @@ jobs: uses: docker/setup-buildx-action@95cb08cb2672c73d4ffd2f422e6d11953d2a9c70 # @v1 - name: Log in to GitHub Container Registry - uses: docker/login-action@49ed152c8eca782a232dede0303416e8f356c37b # @v1 + uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a # @v1 with: registry: ghcr.io username: ${{ github.actor }} @@ -100,7 +100,7 @@ jobs: - name: Log in to DockerHub if: github.event_name != 'pull_request' - uses: docker/login-action@49ed152c8eca782a232dede0303416e8f356c37b # @v1 + uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a # @v1 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} From f5704fff69547e581f8234e40529c3a87fced255 Mon Sep 17 00:00:00 2001 From: iarspider Date: Thu, 13 Oct 2022 18:22:37 +0200 Subject: [PATCH 013/442] Add checksum for py-async-lru 1.0.3 (#33196) * Add checksum for py-async-lru 1.0.3 * [@spackbot] updating style on behalf of iarspider * Update var/spack/repos/builtin/packages/py-async-lru/package.py Co-authored-by: Adam J. Stewart * Update package.py Co-authored-by: iarspider Co-authored-by: Adam J. Stewart --- .../repos/builtin/packages/py-async-lru/package.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/py-async-lru/package.py b/var/spack/repos/builtin/packages/py-async-lru/package.py index 54ad4c173b9..37f99ce2cc6 100644 --- a/var/spack/repos/builtin/packages/py-async-lru/package.py +++ b/var/spack/repos/builtin/packages/py-async-lru/package.py @@ -10,11 +10,20 @@ class PyAsyncLru(PythonPackage): """Simple lru_cache for asyncio""" homepage = "https://github.com/wikibusiness/async_lru" - pypi = "async_lru/async_lru-1.0.2.tar.gz" + pypi = "async-lru/async-lru-1.0.2.tar.gz" maintainers = ["iarspider"] + version("1.0.3", sha256="c2cb9b2915eb14e6cf3e717154b40f715bf90e596d73623677affd0d1fbcd32a") version("1.0.2", sha256="baa898027619f5cc31b7966f96f00e4fc0df43ba206a8940a5d1af5336a477cb") depends_on("python@3.6:", type=("build", "run")) depends_on("py-setuptools", type="build") + + def url_for_version(self, version): + url = "https://files.pythonhosted.org/packages/source/a/{0}/{0}-{1}.tar.gz" + if version >= Version("1.0.3"): + name = "async-lru" + else: + name = "async_lru" + return url.format(name, version) From 4ddf011c565dfca65ab1bf82146fb2027ad75b9a Mon Sep 17 00:00:00 2001 From: iarspider Date: Thu, 13 Oct 2022 18:23:07 +0200 Subject: [PATCH 014/442] Add checksum for py-regex 2022.8.17 (#33209) * Add checksum for py-regex 2022.8.17 * Update var/spack/repos/builtin/packages/py-regex/package.py Co-authored-by: Adam J. Stewart Co-authored-by: Adam J. Stewart --- var/spack/repos/builtin/packages/py-regex/package.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/py-regex/package.py b/var/spack/repos/builtin/packages/py-regex/package.py index 494af423ab4..85c3a06b4cc 100644 --- a/var/spack/repos/builtin/packages/py-regex/package.py +++ b/var/spack/repos/builtin/packages/py-regex/package.py @@ -9,8 +9,10 @@ class PyRegex(PythonPackage): """Alternative regular expression module, to replace re.""" + homepage = "https://github.com/mrabarnett/mrab-regex" pypi = "regex/regex-2020.11.13.tar.gz" + version("2022.8.17", sha256="5c77eab46f3a2b2cd8bbe06467df783543bf7396df431eb4a144cc4b89e9fb3c") version( "2020.11.13", sha256="83d6b356e116ca119db8e7c6fc2983289d87b27b3fac238cfe5dca529d884562" ) @@ -25,4 +27,5 @@ class PyRegex(PythonPackage): "2017.07.11", sha256="dbda8bdc31a1c85445f1a1b29d04abda46e5c690f8f933a9cc3a85a358969616" ) - depends_on("py-setuptools", type="build", when="@:2018,2020:") + depends_on("py-setuptools", type="build") + depends_on("python@3.6:", when="@2022.8.17:", type=("build", "run")) From 5eeb81c253e5fc86ba897930573b5cb540915be7 Mon Sep 17 00:00:00 2001 From: iarspider Date: Thu, 13 Oct 2022 18:23:38 +0200 Subject: [PATCH 015/442] Add checksum for py-jupyter-server-mathjax 0.2.6 (#33203) * Add checksum for py-jupyter-server-mathjax 0.2.6 * Update package.py * Update package.py --- .../builtin/packages/py-jupyter-server-mathjax/package.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/var/spack/repos/builtin/packages/py-jupyter-server-mathjax/package.py b/var/spack/repos/builtin/packages/py-jupyter-server-mathjax/package.py index 10b9e7fc05e..1c768476c4b 100644 --- a/var/spack/repos/builtin/packages/py-jupyter-server-mathjax/package.py +++ b/var/spack/repos/builtin/packages/py-jupyter-server-mathjax/package.py @@ -12,10 +12,12 @@ class PyJupyterServerMathjax(PythonPackage): homepage = "http://jupyter.org/" pypi = "jupyter_server_mathjax/jupyter_server_mathjax-0.2.3.tar.gz" + version("0.2.6", sha256="bb1e6b6dc0686c1fe386a22b5886163db548893a99c2810c36399e9c4ca23943") version("0.2.3", sha256="564e8d1272019c6771208f577b5f9f2b3afb02b9e2bff3b34c042cef8ed84451") depends_on("python@3.6:", type=("build", "run")) depends_on("py-setuptools", type="build") - depends_on("py-wheel", type="build") depends_on("py-jupyter-packaging", type="build") - depends_on("py-jupyter-server@1.1:1", type=("build", "run")) + depends_on("py-jupyter-packaging11@:1", when="@0.2.6:", type="build") + depends_on("py-jupyter-server@1.1:1", when="@0.2.3", type=("build", "run")) + depends_on("py-jupyter-server@1.1:", when="@0.2.6:", type=("build", "run")) From f76a3a1a732182b0144fbb0d098f5ee3fc310f32 Mon Sep 17 00:00:00 2001 From: iarspider Date: Thu, 13 Oct 2022 18:24:05 +0200 Subject: [PATCH 016/442] Add checksum for py-setuptools-rust 1.5.1 (#33188) * Add checksum for py-setuptools-rust 1.5.1 * Update package.py --- .../repos/builtin/packages/py-setuptools-rust/package.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/var/spack/repos/builtin/packages/py-setuptools-rust/package.py b/var/spack/repos/builtin/packages/py-setuptools-rust/package.py index fed852868a0..cab58b302c9 100644 --- a/var/spack/repos/builtin/packages/py-setuptools-rust/package.py +++ b/var/spack/repos/builtin/packages/py-setuptools-rust/package.py @@ -12,6 +12,7 @@ class PySetuptoolsRust(PythonPackage): homepage = "https://github.com/PyO3/setuptools-rust" pypi = "setuptools-rust/setuptools-rust-0.12.1.tar.gz" + version("1.5.1", sha256="0e05e456645d59429cb1021370aede73c0760e9360bbfdaaefb5bced530eb9d7") version("1.4.1", sha256="18ff850831f58ee21d5783825c99fad632da21e47645e9427fd7dec048029e76") version("1.2.0", sha256="0a4ada479e8c7e3d8bd7cb56e1a29acc2b2bb98c2325051b0cdcb57d7f056de8") version("0.12.1", sha256="647009e924f0ae439c7f3e0141a184a69ad247ecb9044c511dabde232d3d570e") @@ -29,8 +30,8 @@ class PySetuptoolsRust(PythonPackage): depends_on("py-setuptools@62.4:", when="@1.4.0:", type=("build", "run")) depends_on("py-setuptools@46.1:", when="@0.11.6:", type=("build", "run")) depends_on("py-setuptools", type=("build", "run")) - depends_on("py-setuptools-scm+toml@6.3.2:", when="@1.2.0:", type="build") - depends_on("py-setuptools-scm+toml@3.4.3:", when="@0.11:", type="build") + depends_on("py-setuptools-scm+toml@6.3.2:", when="@1.2.0:1.4.1", type="build") + depends_on("py-setuptools-scm+toml@3.4.3:", when="@0.11:1.1", type="build") depends_on("py-semantic-version@2.8.2:2", when="@1.2.0:", type=("build", "run")) depends_on("py-semantic-version@2.6.0:", type=("build", "run")) depends_on("py-typing-extensions@3.7.4.3:", when="@1.2.0:", type=("build", "run")) From bd263b71dade1a53a9846d117a408a9bbd59632a Mon Sep 17 00:00:00 2001 From: iarspider Date: Thu, 13 Oct 2022 18:24:35 +0200 Subject: [PATCH 017/442] Add checksum for py-keyring 23.9.1 (#33185) * Add checksum for py-keyring 23.9.1 * Update package.py --- var/spack/repos/builtin/packages/py-keyring/package.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/var/spack/repos/builtin/packages/py-keyring/package.py b/var/spack/repos/builtin/packages/py-keyring/package.py index 9503f7d29b5..8c29d85bc00 100644 --- a/var/spack/repos/builtin/packages/py-keyring/package.py +++ b/var/spack/repos/builtin/packages/py-keyring/package.py @@ -14,6 +14,7 @@ class PyKeyring(PythonPackage): homepage = "https://github.com/jaraco/keyring" pypi = "keyring/keyring-23.0.1.tar.gz" + version("23.9.1", sha256="39e4f6572238d2615a82fcaa485e608b84b503cf080dc924c43bbbacb11c1c18") version("23.5.0", sha256="9012508e141a80bd1c0b6778d5c610dd9f8c464d75ac6774248500503f972fb9") version("23.2.1", sha256="6334aee6073db2fb1f30892697b1730105b5e9a77ce7e61fca6b435225493efe") version("23.2.0", sha256="1e1970dcecde00c59ff6033d69cee3b283cd0d7cbad78b0dc4cdd15c8a28bcf8") @@ -39,8 +40,9 @@ class PyKeyring(PythonPackage): ) depends_on("py-secretstorage", when="platform=linux", type=("build", "run")) depends_on("py-jeepney@0.4.2:", when="@21: platform=linux", type=("build", "run")) - depends_on("py-importlib-metadata@3.6:", when="@23:", type=("build", "run")) - depends_on("py-importlib-metadata@1:", when="@21:", type=("build", "run")) + depends_on("py-importlib-metadata@3.6:", when="@23: ^python@:3.9", type=("build", "run")) + depends_on("py-importlib-metadata@1:", when="@21:22", type=("build", "run")) depends_on("py-importlib-metadata", when="@20:", type=("build", "run")) + depends_on("py-jaraco-classes", when="@23.9.1:", type=("build", "run")) # TODO: additional dependency on pywin32-ctypes required for Windows From 268a43762c1ea96f55ca803b9e9ef74631cc0738 Mon Sep 17 00:00:00 2001 From: iarspider Date: Thu, 13 Oct 2022 18:25:43 +0200 Subject: [PATCH 018/442] Add checksum for py-pymongo 4.2.0 (#33234) --- var/spack/repos/builtin/packages/py-pymongo/package.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/var/spack/repos/builtin/packages/py-pymongo/package.py b/var/spack/repos/builtin/packages/py-pymongo/package.py index 4505acb9035..501484d1e38 100644 --- a/var/spack/repos/builtin/packages/py-pymongo/package.py +++ b/var/spack/repos/builtin/packages/py-pymongo/package.py @@ -17,10 +17,12 @@ class PyPymongo(PythonPackage): pypi = "pymongo/pymongo-3.9.0.tar.gz" + version("4.2.0", sha256="72f338f6aabd37d343bd9d1fdd3de921104d395766bcc5cdc4039e4c2dd97766") version("3.12.1", sha256="704879b6a54c45ad76cea7c6789c1ae7185050acea7afd15b58318fa1932ed45") version("3.9.0", sha256="4249c6ba45587b959292a727532826c5032d59171f923f7f823788f413c2a5a3") version("3.6.0", sha256="c6de26d1e171cdc449745b82f1addbc873d105b8e7335097da991c0fc664a4a8") version("3.3.0", sha256="3d45302fc2622fabf34356ba274c69df41285bac71bbd229f1587283b851b91e") depends_on("python@2.7:2.8,3.4:", type=("build", "run")) + depends_on("python@3.7:", when="@4.2.0:", type=("build", "run")) depends_on("py-setuptools", type="build") From 828fddacf1a0b74e223626ca1d5efbec6d06f529 Mon Sep 17 00:00:00 2001 From: iarspider Date: Thu, 13 Oct 2022 18:28:15 +0200 Subject: [PATCH 019/442] Add checksum for py-bottle 0.12.23 (#33241) --- var/spack/repos/builtin/packages/py-bottle/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/py-bottle/package.py b/var/spack/repos/builtin/packages/py-bottle/package.py index ff79fc62e51..90cd50a7d54 100644 --- a/var/spack/repos/builtin/packages/py-bottle/package.py +++ b/var/spack/repos/builtin/packages/py-bottle/package.py @@ -13,6 +13,7 @@ class PyBottle(PythonPackage): homepage = "https://github.com/bottlepy/bottle" url = "https://github.com/bottlepy/bottle/archive/0.12.18.tar.gz" + version("0.12.23", sha256="f38c26395736ae4653cbeb94087d3bd1d2e1ad0c29b1d3e5384f5db20b63bc98") version("0.12.19", sha256="b97277f8e87d452a0aa5fbcd16cd604a189e2cc17fdb2d4eaf6baa732f8d111b") version("0.12.18", sha256="176721f1e26082c66fd4df76f31800933e4bb36de6814b0fda3851cb409a95e6") version("0.12.17", sha256="7df26ca1789aa0693277c4a86d564524bff03e5d3132d9405946c58739190928") From 0af5838581a89ab6d376eee16c4c285bc482a1d5 Mon Sep 17 00:00:00 2001 From: iarspider Date: Thu, 13 Oct 2022 18:28:52 +0200 Subject: [PATCH 020/442] Add checksum for py-cloudpickle 2.2.0 (#33240) --- var/spack/repos/builtin/packages/py-cloudpickle/package.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/var/spack/repos/builtin/packages/py-cloudpickle/package.py b/var/spack/repos/builtin/packages/py-cloudpickle/package.py index 490a532d667..b4bbc9ad190 100644 --- a/var/spack/repos/builtin/packages/py-cloudpickle/package.py +++ b/var/spack/repos/builtin/packages/py-cloudpickle/package.py @@ -12,10 +12,12 @@ class PyCloudpickle(PythonPackage): homepage = "https://github.com/cloudpipe/cloudpickle" pypi = "cloudpickle/cloudpickle-0.5.2.tar.gz" + version("2.2.0", sha256="3f4219469c55453cfe4737e564b67c2a149109dabf7f242478948b895f61106f") version("1.6.0", sha256="9bc994f9e9447593bd0a45371f0e7ac7333710fcf64a4eb9834bf149f4ef2f32") version("1.2.1", sha256="603244e0f552b72a267d47a7d9b347b27a3430f58a0536037a290e7e0e212ecf") version("1.1.1", sha256="7d43c4d0c7e9735ee8a352c96f84031dabd6676170c4e5e0585a469cc4769f22") version("0.5.2", sha256="b0e63dd89ed5285171a570186751bc9b84493675e99e12789e9a5dc5490ef554") depends_on("python@3.5:", type=("build", "run"), when="@1.6.0:") + depends_on("python@3.6:", type=("build", "run"), when="@2.2.0:") depends_on("py-setuptools", type="build") From 4c151e0387bb0efdc9cdc9e37827565443a65168 Mon Sep 17 00:00:00 2001 From: iarspider Date: Thu, 13 Oct 2022 18:29:48 +0200 Subject: [PATCH 021/442] Add checksum for py-mpld3 0.5.8 (#33239) --- var/spack/repos/builtin/packages/py-mpld3/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/py-mpld3/package.py b/var/spack/repos/builtin/packages/py-mpld3/package.py index e4057cfd3cb..1c75fcbaf0d 100644 --- a/var/spack/repos/builtin/packages/py-mpld3/package.py +++ b/var/spack/repos/builtin/packages/py-mpld3/package.py @@ -13,6 +13,7 @@ class PyMpld3(PythonPackage): homepage = "https://mpld3.github.io/" pypi = "mpld3/mpld3-0.3.tar.gz" + version("0.5.8", sha256="1a167dbef836dd7c66d8aa71c06a32d50bffa18725f304d93cb74fdb3545043b") version("0.5.5", sha256="b080f3535238a71024c0158280ab4f6091717c45347c41c907012f8dd6da1bd5") version("0.3", sha256="4d455884a211bf99b37ecc760759435c7bb6a5955de47d8daf4967e301878ab7") From 93be19d0e38fbf324ff440563e0bc5b5ca8780ad Mon Sep 17 00:00:00 2001 From: iarspider Date: Thu, 13 Oct 2022 18:31:42 +0200 Subject: [PATCH 022/442] Add checksum for py-bokeh 2.4.3 (#33236) * Add checksum for py-bokeh 2.4.3 * [@spackbot] updating style on behalf of iarspider Co-authored-by: iarspider --- .../repos/builtin/packages/py-bokeh/package.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/var/spack/repos/builtin/packages/py-bokeh/package.py b/var/spack/repos/builtin/packages/py-bokeh/package.py index bd6f2d8b4fb..aa2a793558e 100644 --- a/var/spack/repos/builtin/packages/py-bokeh/package.py +++ b/var/spack/repos/builtin/packages/py-bokeh/package.py @@ -12,6 +12,7 @@ class PyBokeh(PythonPackage): homepage = "https://github.com/bokeh/bokeh" pypi = "bokeh/bokeh-0.12.2.tar.gz" + version("2.4.3", sha256="ef33801161af379665ab7a34684f2209861e3aefd5c803a21fbbb99d94874b03") version("2.4.1", sha256="d0410717d743a0ac251e62480e2ea860a7341bdcd1dbe01499a904f233c90512") version("2.4.0", sha256="6fa00ed8baab5cca33f4175792c309fa2536eaae7e90abee884501ba8c90fddb") version("2.3.3", sha256="a5fdcc181835561447fcc5a371300973fce4114692d5853addec284d1cdeb677") @@ -26,22 +27,23 @@ class PyBokeh(PythonPackage): depends_on("python@3.7:", type=("build", "run"), when="@2.4.0:") depends_on("py-requests@1.2.3:", type=("build", "run"), when="@0.12.2") - - depends_on("py-packaging@16.8:", type=("build", "run"), when="@1.3.4:") depends_on("py-six@1.5.2:", type=("build", "run"), when="@:1.3.4") - depends_on("py-pyyaml@3.10:", type=("build", "run")) depends_on("py-python-dateutil@2.1:", type=("build", "run"), when="@:2.3.3") depends_on("py-futures@3.0.3:", type=("build", "run"), when="@:1.3.4 ^python@2.7:2.8") - depends_on("pil@4.0:", type=("build", "run"), when="@1.3.4:") - depends_on("pil@7.1.0:", type=("build", "run"), when="@2.3.3:") - depends_on("py-jinja2@2.7:", type=("build", "run")) depends_on("py-jinja2@2.9:", type=("build", "run"), when="@2.3.3:") depends_on("py-numpy@1.7.1:", type=("build", "run")) depends_on("py-numpy@1.11.3:", type=("build", "run"), when="@2.3.3:") + depends_on("py-packaging@16.8:", type=("build", "run"), when="@1.3.4:") + + depends_on("pil@4.0:", type=("build", "run"), when="@1.3.4:") + depends_on("pil@7.1.0:", type=("build", "run"), when="@2.3.3:") + + depends_on("py-pyyaml@3.10:", type=("build", "run")) + depends_on("py-tornado@4.3:", type=("build", "run")) depends_on("py-tornado@5.1:", type=("build", "run"), when="@2.3.3:") From 0c4ad440c63812a83226e5176dbc8326a09b03df Mon Sep 17 00:00:00 2001 From: Laurent Aphecetche Date: Thu, 13 Oct 2022 18:32:11 +0200 Subject: [PATCH 023/442] py-pyopenssl: add version 22.1.0 (#33189) * py-pyopenssl: add version 22.1.0 * Update var/spack/repos/builtin/packages/py-pyopenssl/package.py Co-authored-by: Adam J. Stewart Co-authored-by: Adam J. Stewart --- var/spack/repos/builtin/packages/py-pyopenssl/package.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/py-pyopenssl/package.py b/var/spack/repos/builtin/packages/py-pyopenssl/package.py index 6a049cb80fe..df5d0257594 100644 --- a/var/spack/repos/builtin/packages/py-pyopenssl/package.py +++ b/var/spack/repos/builtin/packages/py-pyopenssl/package.py @@ -17,8 +17,11 @@ class PyPyopenssl(PythonPackage): homepage = "https://pyopenssl.org/" pypi = "pyOpenSSL/pyOpenSSL-19.0.0.tar.gz" + version("22.1.0", sha256="7a83b7b272dd595222d672f5ce29aa030f1fb837630ef229f62e72e395ce8968") version("19.0.0", sha256="aeca66338f6de19d1aa46ed634c3b9ae519a64b458f8468aec688e7e3c20f200") depends_on("py-setuptools", type="build") depends_on("py-cryptography@2.3:", type=("build", "run")) - depends_on("py-six@1.5.2:", type=("build", "run")) + depends_on("py-cryptography@38", when="@22:", type=("build", "run")) + depends_on("python@3.6:", when="@22:", type=("build", "run")) + depends_on("py-six@1.5.2:", when="@:19", type=("build", "run")) From e20d45f3bc0c83d4731fc5b507fcf2110be37b33 Mon Sep 17 00:00:00 2001 From: Cameron Rutherford Date: Thu, 13 Oct 2022 12:41:18 -0400 Subject: [PATCH 024/442] Fix ROCm constraints for ginkgo@glu_experimental in HiOp (#32499) * Remove ROCm constraints for ginkgo@glu_experimental. * Fix style. * Apply @tcojean suggestion. * Fix hip_repair_options in camp package. * Remvoe old ROCm logic. * Remove added whitespace. * Fix style issue. * Revert camp changes. * Revert camp whitespace change. * Set Ginkgo preferred version to 1.4.0 --- var/spack/repos/builtin/packages/ginkgo/package.py | 6 +++--- var/spack/repos/builtin/packages/hiop/package.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/var/spack/repos/builtin/packages/ginkgo/package.py b/var/spack/repos/builtin/packages/ginkgo/package.py index 8899964a544..e2ebbe13773 100644 --- a/var/spack/repos/builtin/packages/ginkgo/package.py +++ b/var/spack/repos/builtin/packages/ginkgo/package.py @@ -22,9 +22,9 @@ class Ginkgo(CMakePackage, CudaPackage, ROCmPackage): version("develop", branch="develop") version("master", branch="master") - version("glu", branch="glu") - version("glu_experimental", branch="glu_experimental") - version("1.4.0", commit="f811917c1def4d0fcd8db3fe5c948ce13409e28e") # v1.4.0 + version("1.5.0.glu", branch="glu") + version("1.5.0.glu_experimental", branch="glu_experimental") + version("1.4.0", commit="f811917c1def4d0fcd8db3fe5c948ce13409e28e", preferred=True) # v1.4.0 version("1.3.0", commit="4678668c66f634169def81620a85c9a20b7cec78") # v1.3.0 version("1.2.0", commit="b4be2be961fd5db45c3d02b5e004d73550722e31") # v1.2.0 version("1.1.1", commit="08d2c5200d3c78015ac8a4fd488bafe1e4240cf5") # v1.1.1 diff --git a/var/spack/repos/builtin/packages/hiop/package.py b/var/spack/repos/builtin/packages/hiop/package.py index b770a786183..7b7e08c41b4 100644 --- a/var/spack/repos/builtin/packages/hiop/package.py +++ b/var/spack/repos/builtin/packages/hiop/package.py @@ -113,7 +113,7 @@ class Hiop(CMakePackage, CudaPackage, ROCmPackage): depends_on("coinhsl+blas", when="+sparse") depends_on("metis", when="+sparse") - depends_on("ginkgo@glu_experimental", when="+ginkgo") + depends_on("ginkgo@1.5.0.glu_experimental", when="+ginkgo") conflicts( "+shared", From 9c6c2964744a71c58715f555c3f78a2bca96b848 Mon Sep 17 00:00:00 2001 From: iarspider Date: Thu, 13 Oct 2022 18:42:19 +0200 Subject: [PATCH 025/442] Add checksum for py-asn1crypto 1.5.1 (#33283) --- var/spack/repos/builtin/packages/py-asn1crypto/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/py-asn1crypto/package.py b/var/spack/repos/builtin/packages/py-asn1crypto/package.py index 5d5576cab41..0fbd15dadba 100644 --- a/var/spack/repos/builtin/packages/py-asn1crypto/package.py +++ b/var/spack/repos/builtin/packages/py-asn1crypto/package.py @@ -13,6 +13,7 @@ class PyAsn1crypto(PythonPackage): homepage = "https://github.com/wbond/asn1crypto" pypi = "asn1crypto/asn1crypto-0.22.0.tar.gz" + version("1.5.1", sha256="13ae38502be632115abf8a24cbe5f4da52e3b5231990aff31123c805306ccb9c") version("1.4.0", sha256="f4f6e119474e58e04a2b1af817eb585b4fd72bdd89b998624712b5c99be7641c") version("0.24.0", sha256="9d5c20441baf0cb60a4ac34cc447c6c189024b6b4c6cd7877034f4965c464e49") version("0.22.0", sha256="cbbadd640d3165ab24b06ef25d1dca09a3441611ac15f6a6b452474fdf0aed1a") From be93b27ffce3e23ff04318bb29d2c36a525db44f Mon Sep 17 00:00:00 2001 From: iarspider Date: Thu, 13 Oct 2022 18:42:58 +0200 Subject: [PATCH 026/442] Add checksum for py-atomicwrites 1.4.1 (#33284) --- var/spack/repos/builtin/packages/py-atomicwrites/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/py-atomicwrites/package.py b/var/spack/repos/builtin/packages/py-atomicwrites/package.py index 65321fb2faf..7057832fd66 100644 --- a/var/spack/repos/builtin/packages/py-atomicwrites/package.py +++ b/var/spack/repos/builtin/packages/py-atomicwrites/package.py @@ -12,6 +12,7 @@ class PyAtomicwrites(PythonPackage): homepage = "https://github.com/untitaker/python-atomicwrites" pypi = "atomicwrites/atomicwrites-1.3.0.tar.gz" + version("1.4.1", sha256="81b2c9071a49367a7f770170e5eec8cb66567cfbbc8c73d20ce5ca4a8d71cf11") version("1.4.0", sha256="ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a") version("1.3.0", sha256="75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6") version("1.1.5", sha256="240831ea22da9ab882b551b31d4225591e5e447a68c5e188db5b89ca1d487585") From 6ac1f445eceb65e7d24a7bcc728385bde9c1b117 Mon Sep 17 00:00:00 2001 From: "Adam J. Stewart" Date: Thu, 13 Oct 2022 11:52:20 -0500 Subject: [PATCH 027/442] py-shapely: add v1.8.5 (#33259) --- var/spack/repos/builtin/packages/py-shapely/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/py-shapely/package.py b/var/spack/repos/builtin/packages/py-shapely/package.py index 8c2aad9eb16..9c39acbe0bc 100644 --- a/var/spack/repos/builtin/packages/py-shapely/package.py +++ b/var/spack/repos/builtin/packages/py-shapely/package.py @@ -20,6 +20,7 @@ class PyShapely(PythonPackage): version("main", branch="main") version("master", branch="main", deprecated=True) + version("1.8.5", sha256="e82b6d60ecfb124120c88fe106a478596bbeab142116d7e7f64a364dac902a92") version("1.8.4", sha256="a195e51caafa218291f2cbaa3fef69fd3353c93ec4b65b2a4722c4cf40c3198c") version("1.8.3", sha256="1ce9da186d48efc50130af96d62ffb4d2e175235143d804ef395aad156d45bb3") version("1.8.2", sha256="572af9d5006fd5e3213e37ee548912b0341fb26724d6dc8a4e3950c10197ebb6") From 3014caa586aeb71c83ee2f45163728da65080dc7 Mon Sep 17 00:00:00 2001 From: "Adam J. Stewart" Date: Thu, 13 Oct 2022 12:42:27 -0500 Subject: [PATCH 028/442] py-kornia: add v0.6.8 (#33287) --- var/spack/repos/builtin/packages/py-kornia/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/py-kornia/package.py b/var/spack/repos/builtin/packages/py-kornia/package.py index 0834cef0825..3abc0a1aac3 100644 --- a/var/spack/repos/builtin/packages/py-kornia/package.py +++ b/var/spack/repos/builtin/packages/py-kornia/package.py @@ -12,6 +12,7 @@ class PyKornia(PythonPackage): homepage = "https://www.kornia.org/" pypi = "kornia/kornia-0.5.10.tar.gz" + version("0.6.8", sha256="0985e02453c0ab4f030e8d22a3a7554dab312ffa8f8a54ec872190e6f0b58c56") version("0.6.7", sha256="7ff57c931551a1a1465aaac1fa6842a2aad650f51a0f9bf6cf0b0f7d6e5fb59c") version("0.6.6", sha256="e29f0f994e3bafec016b101a9a3e89c3751b4fe99ada3ac21d3febb47904faa4") version("0.6.5", sha256="14cbd8b4064b3d0fb5a8198d1b5fd9231bcd62b9039351641fca6b294b5069f0") From 5167eed558d4e97a5ec19e8fe68fed3e294c1314 Mon Sep 17 00:00:00 2001 From: Chris White Date: Thu, 13 Oct 2022 10:51:07 -0700 Subject: [PATCH 029/442] Lua: Add versions and minor clean up (#33037) * add new lua releases * split install phase and move it into a build phase, remove hardcoded standard flag * revert back to the original hardcoded std flag, guard patch against versions above 5.4 --- .../repos/builtin/packages/lua/package.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/var/spack/repos/builtin/packages/lua/package.py b/var/spack/repos/builtin/packages/lua/package.py index 7753bf1e092..cd314f3df5b 100644 --- a/var/spack/repos/builtin/packages/lua/package.py +++ b/var/spack/repos/builtin/packages/lua/package.py @@ -209,6 +209,12 @@ class Lua(LuaImplPackage): homepage = "https://www.lua.org" url = "https://www.lua.org/ftp/lua-5.3.4.tar.gz" + version("5.4.4", sha256="164c7849653b80ae67bec4b7473b884bf5cc8d2dca05653475ec2ed27b9ebf61") + version("5.4.3", sha256="f8612276169e3bfcbcfb8f226195bfc6e466fe13042f1076cbde92b7ec96bbfb") + version("5.4.2", sha256="11570d97e9d7303c0a59567ed1ac7c648340cd0db10d5fd594c09223ef2f524f") + version("5.4.1", sha256="4ba786c3705eb9db6567af29c91a01b81f1c0ac3124fdbf6cd94bdd9e53cca7d") + version("5.4.0", sha256="eac0836eb7219e421a96b7ee3692b93f0629e4cdb0c788432e3d10ce9ed47e28") + version("5.3.6", sha256="fc5fd69bb8736323f026672b1b7235da613d7177e72558893a0bdcd320466d60") version("5.3.5", sha256="0c2eed3f960446e1a3e4b9a1ca2f3ff893b6ce41942cf54d5dd59ab4b3b058ac") version("5.3.4", sha256="f681aa518233bc407e23acf0f5887c884f17436f000d453b2491a9f11a52400c") version("5.3.2", sha256="c740c7bb23a936944e1cc63b7c3c5351a8976d7867c5252c8854f7b2af9da68f") @@ -229,6 +235,7 @@ class Lua(LuaImplPackage): provides("lua-lang@5.1", when="@5.1:5.1.99") provides("lua-lang@5.2", when="@5.2:5.2.99") provides("lua-lang@5.3", when="@5.3:5.3.99") + provides("lua-lang@5.4", when="@5.4:5.4.99") depends_on("ncurses+termlib") depends_on("readline") @@ -236,22 +243,23 @@ class Lua(LuaImplPackage): patch( "http://lua.2524044.n2.nabble.com/attachment/7666421/0/pkg-config.patch", sha256="208316c2564bdd5343fa522f3b230d84bd164058957059838df7df56876cb4ae", - when="+pcfile", + when="+pcfile @:5.3.9999", ) - def install(self, spec, prefix): + def build(self, spec, prefix): if spec.satisfies("platform=darwin"): target = "macosx" else: target = "linux" make( - "INSTALL_TOP=%s" % prefix, "MYLDFLAGS=" + " ".join((spec["readline"].libs.search_flags, spec["ncurses"].libs.search_flags)), "MYLIBS=%s" % spec["ncurses"].libs.link_flags, - "CC=%s -std=gnu99 %s" % (spack_cc, self.compiler.cc_pic_flag), + "CC={0} -std=gnu99 {1}".format(spack_cc, self.compiler.cc_pic_flag), target, ) + + def install(self, spec, prefix): make("INSTALL_TOP=%s" % prefix, "install") if "+shared" in spec: @@ -286,7 +294,8 @@ def install(self, spec, prefix): @run_after("install") def link_pkg_config(self): if "+pcfile" in self.spec: + versioned_pc_file_name = "lua{0}.pc".format(self.version.up_to(2)) symlink( - join_path(self.prefix.lib, "pkgconfig", "lua5.3.pc"), + join_path(self.prefix.lib, "pkgconfig", versioned_pc_file_name), join_path(self.prefix.lib, "pkgconfig", "lua.pc"), ) From 7f24ab9b0a9de3673688e3b54e681d6a66663894 Mon Sep 17 00:00:00 2001 From: Luke Diorio-Toth Date: Thu, 13 Oct 2022 13:22:03 -0500 Subject: [PATCH 030/442] py-alive-progress, py-about-time, py-graphme: new packages (#33252) * new package + deps * Update var/spack/repos/builtin/packages/py-about-time/package.py Co-authored-by: Adam J. Stewart * Update var/spack/repos/builtin/packages/py-alive-progress/package.py Co-authored-by: Adam J. Stewart * removed unnecessary python version dep Co-authored-by: Adam J. Stewart --- .../builtin/packages/py-about-time/package.py | 21 ++++++++++++++++ .../packages/py-alive-progress/package.py | 25 +++++++++++++++++++ .../builtin/packages/py-grapheme/package.py | 21 ++++++++++++++++ 3 files changed, 67 insertions(+) create mode 100644 var/spack/repos/builtin/packages/py-about-time/package.py create mode 100644 var/spack/repos/builtin/packages/py-alive-progress/package.py create mode 100644 var/spack/repos/builtin/packages/py-grapheme/package.py diff --git a/var/spack/repos/builtin/packages/py-about-time/package.py b/var/spack/repos/builtin/packages/py-about-time/package.py new file mode 100644 index 00000000000..ba49abb99da --- /dev/null +++ b/var/spack/repos/builtin/packages/py-about-time/package.py @@ -0,0 +1,21 @@ +# 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 PyAboutTime(PythonPackage): + """A cool helper for tracking time and throughput of + code blocks, with beautiful human friendly renditions.""" + + homepage = "https://github.com/rsalmei/about-time" + pypi = "about-time/about-time-4.1.0.tar.gz" + + version("4.1.0", sha256="963b1f3739b0c9732eb205031762b76f1291d89b5d0c8220a8d5b154e32ce650") + version("3.1.1", sha256="586b329450c9387d1ae8c42d2db4f5b4c57a54508d0f1b7bb00322ffd5ce9f9b") + + depends_on("python@3.7:3", type=("build", "run"), when="@4:") + depends_on("py-setuptools", type="build") diff --git a/var/spack/repos/builtin/packages/py-alive-progress/package.py b/var/spack/repos/builtin/packages/py-alive-progress/package.py new file mode 100644 index 00000000000..95f4f871690 --- /dev/null +++ b/var/spack/repos/builtin/packages/py-alive-progress/package.py @@ -0,0 +1,25 @@ +# 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 PyAliveProgress(PythonPackage): + """A new kind of Progress Bar, with real-time + throughput, ETA, and very cool animations!""" + + homepage = "https://github.com/rsalmei/alive-progress" + pypi = "alive-progress/alive-progress-2.4.1.tar.gz" + + version("2.4.1", sha256="089757c8197f27ad972ba27e1060f6db92368d83c736884e159034fd74865323") + version("1.6.2", sha256="642e1ce98becf226c8c36bf24e10221085998c5465a357a66fb83b7dc618b43e") + + depends_on("python@2.7:3.8", type=("build", "run")) + depends_on("python@3.6:3", type=("build", "run"), when="@2:") + depends_on("python@3.7:3", type=("build", "run"), when="@2.2:") + depends_on("py-setuptools", type="build") + depends_on("py-about-time@3.1.1", type=("build", "run"), when="@2.4.1:") + depends_on("py-grapheme@0.6.0", type=("build", "run"), when="@2.4.1:") diff --git a/var/spack/repos/builtin/packages/py-grapheme/package.py b/var/spack/repos/builtin/packages/py-grapheme/package.py new file mode 100644 index 00000000000..d6fd724cccb --- /dev/null +++ b/var/spack/repos/builtin/packages/py-grapheme/package.py @@ -0,0 +1,21 @@ +# 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 PyGrapheme(PythonPackage): + """A Python package for working with user perceived characters. More + specifically, string manipulation and calculation functions for working + with grapheme cluster groups (graphemes) as defined by the + Unicode Standard Annex #29.""" + + homepage = "https://github.com/alvinlindstam/grapheme" + pypi = "grapheme/grapheme-0.6.0.tar.gz" + + version("0.6.0", sha256="44c2b9f21bbe77cfb05835fec230bd435954275267fea1858013b102f8603cca") + + depends_on("py-setuptools", type="build") From 8ce1574e0cd88cfa14391cf3c9362813109e9363 Mon Sep 17 00:00:00 2001 From: "Adam J. Stewart" Date: Thu, 13 Oct 2022 13:22:09 -0500 Subject: [PATCH 031/442] py-meson: remove package (#33295) --- .../packages/py-meson-python/package.py | 2 +- .../builtin/packages/py-meson/package.py | 26 ------------------- 2 files changed, 1 insertion(+), 27 deletions(-) delete mode 100644 var/spack/repos/builtin/packages/py-meson/package.py diff --git a/var/spack/repos/builtin/packages/py-meson-python/package.py b/var/spack/repos/builtin/packages/py-meson-python/package.py index eba4d613f93..323a997074b 100644 --- a/var/spack/repos/builtin/packages/py-meson-python/package.py +++ b/var/spack/repos/builtin/packages/py-meson-python/package.py @@ -17,7 +17,7 @@ class PyMesonPython(PythonPackage): version("0.7.0", sha256="9fcfa350f44ca80dd4f5f9c3d251725434acf9a07d9618f382e6cc4629dcbe84") depends_on("python@3.7:", type=("build", "run")) - depends_on("py-meson@0.62:", type=("build", "run")) + depends_on("meson@0.62:", type=("build", "run")) depends_on("py-ninja", type=("build", "run")) depends_on("py-pyproject-metadata@0.5:", type=("build", "run")) depends_on("py-tomli@1:", type=("build", "run")) diff --git a/var/spack/repos/builtin/packages/py-meson/package.py b/var/spack/repos/builtin/packages/py-meson/package.py deleted file mode 100644 index 0c71dc6887c..00000000000 --- a/var/spack/repos/builtin/packages/py-meson/package.py +++ /dev/null @@ -1,26 +0,0 @@ -# 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 PyMeson(PythonPackage): - """A high performance build system. - - Meson is a cross-platform build system designed to be both as fast and as user - friendly as possible. It supports many languages and compilers, including GCC, - Clang, PGI, Intel, and Visual Studio. Its build definitions are written in a simple - non-Turing complete DSL. - """ - - homepage = "https://mesonbuild.com/" - pypi = "meson/meson-0.62.2.tar.gz" - - maintainers = ["eli-schwartz", "adamjstewart"] - - version("0.62.2", sha256="a7669e4c4110b06b743d57cc5d6432591a6677ef2402139fe4f3d42ac13380b0") - - depends_on("python@3.7:", type=("build", "run")) - depends_on("py-setuptools@42:", type="build") From feb1f3aadb160fc64fc86fa4dd58a698468f77e3 Mon Sep 17 00:00:00 2001 From: Gregory Lee Date: Thu, 13 Oct 2022 11:51:28 -0700 Subject: [PATCH 032/442] libcroco does not respect gtk-doc configure flag, so removing variant (#32890) * libcroco does not respect gtk-doc configure flag, so removing variant --- var/spack/repos/builtin/packages/libcroco/package.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/var/spack/repos/builtin/packages/libcroco/package.py b/var/spack/repos/builtin/packages/libcroco/package.py index 2f1a5f07c23..56230050aa7 100644 --- a/var/spack/repos/builtin/packages/libcroco/package.py +++ b/var/spack/repos/builtin/packages/libcroco/package.py @@ -15,16 +15,18 @@ class Libcroco(AutotoolsPackage): version("0.6.13", sha256="767ec234ae7aa684695b3a735548224888132e063f92db585759b422570621d4") version("0.6.12", sha256="ddc4b5546c9fb4280a5017e2707fbd4839034ed1aba5b7d4372212f34f84f860") - variant("doc", default=False, description="Build documentation with gtk-doc") + # libcroco has a --enable-gtk-doc configure flag that appears to be + # ignored as of version 0.6.13. Until that flag is honored, the +doc + # variant is a no-op + # variant("doc", default=False, + # description="Build documentation with gtk-doc") depends_on("glib") depends_on("libxml2") - depends_on("gtk-doc", type="build", when="+doc") + depends_on("gtk-doc", type="build") depends_on("pkgconfig", type="build") def configure_args(self): - args = ["--enable-gtk-doc=" + ("yes" if self.spec.variants["doc"].value else "no")] # macOS ld does not support this flag # https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/libcroco.rb - args.append("--disable-Bsymbolic") - return args + return ["--disable-Bsymbolic"] From 599480ae9a93835401212f61ca96a323f62d12d8 Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Thu, 13 Oct 2022 20:54:20 +0200 Subject: [PATCH 033/442] Add missing upperbound to docs/spack.yaml (#33280) --- lib/spack/docs/spack.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/spack/docs/spack.yaml b/lib/spack/docs/spack.yaml index 2dd932b5658..778f0a3c753 100644 --- a/lib/spack/docs/spack.yaml +++ b/lib/spack/docs/spack.yaml @@ -20,6 +20,8 @@ spack: - py-docutils@:0.16 - py-sphinx-design - py-sphinx-rtd-theme + - py-pygments@:2.12 + # VCS - git - mercurial From f74742b834c236fba218fb359e032147acd7f9b6 Mon Sep 17 00:00:00 2001 From: Luke Diorio-Toth Date: Thu, 13 Oct 2022 15:01:16 -0500 Subject: [PATCH 034/442] new package (#33262) --- .../packages/py-deepsig-biocomp/package.py | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 var/spack/repos/builtin/packages/py-deepsig-biocomp/package.py diff --git a/var/spack/repos/builtin/packages/py-deepsig-biocomp/package.py b/var/spack/repos/builtin/packages/py-deepsig-biocomp/package.py new file mode 100644 index 00000000000..200812735e8 --- /dev/null +++ b/var/spack/repos/builtin/packages/py-deepsig-biocomp/package.py @@ -0,0 +1,36 @@ +# 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 PyDeepsigBiocomp(PythonPackage): + """DeepSig - Predictor of signal peptides + in proteins based on deep learning""" + + homepage = "https://deepsig.biocomp.unibo.it" + + url = "https://github.com/BolognaBiocomp/deepsig/archive/refs/tags/v1.2.5.tar.gz" + + version("1.2.5", sha256="e954b815d63c221c564c7d3fe27123d7cd2c39b191d6107369ab095d506496e0") + + depends_on("python@3.8", type=("build", "run")) + depends_on("py-setuptools", type="build") + depends_on("py-biopython@1.78:", type=("build", "run")) + depends_on("py-keras@2.4.3", type=("build", "run")) + depends_on("py-tensorflow@2.2.0", type=("build", "run")) + depends_on("py-tensorboard", type=("build", "run")) + + @run_after("install") + def create_share_folder(self): + share_dir = join_path(self.prefix, "share", "deepsig") + mkdirp(share_dir) + mv = which("mv") + for d in ("models", "tools"): + mv(d, share_dir) + + def setup_run_environment(self, env): + env.set("DEEPSIG_ROOT", self.prefix.share.deepsig) From 75f71d3f818e08c4b0b0961d98ec3c8a067ca756 Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Thu, 13 Oct 2022 22:22:08 +0200 Subject: [PATCH 035/442] py-execnet: 1.9.0 (#33282) * py-execnet: 1.9.0 * bounds --- var/spack/repos/builtin/packages/py-execnet/package.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/py-execnet/package.py b/var/spack/repos/builtin/packages/py-execnet/package.py index d64b3131e4b..2e32631d711 100644 --- a/var/spack/repos/builtin/packages/py-execnet/package.py +++ b/var/spack/repos/builtin/packages/py-execnet/package.py @@ -14,10 +14,12 @@ class PyExecnet(PythonPackage): homepage = "https://codespeak.net/execnet" pypi = "execnet/execnet-1.7.1.tar.gz" + version("1.9.0", sha256="8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5") version("1.7.1", sha256="cacb9df31c9680ec5f95553976c4da484d407e85e41c83cb812aa014f0eddc50") version("1.4.1", sha256="f66dd4a7519725a1b7e14ad9ae7d3df8e09b2da88062386e08e941cafc0ef3e6") depends_on("python@2.7:2.8,3.4:", type=("build", "run")) + depends_on("python@2.7:2.8,3.5:", type=("build", "run"), when="@1.9:") depends_on("py-setuptools", type="build") depends_on("py-setuptools-scm", type="build") - depends_on("py-apipkg@1.4:", type=("build", "run")) + depends_on("py-apipkg@1.4:", type=("build", "run"), when="@:1.7") From 00ea25061f2ae8635fb500c9907b69068be559c4 Mon Sep 17 00:00:00 2001 From: Jim Edwards Date: Thu, 13 Oct 2022 14:51:50 -0600 Subject: [PATCH 036/442] add version 1.12.3 of parallel-netcdf (#33286) --- var/spack/repos/builtin/packages/parallel-netcdf/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/parallel-netcdf/package.py b/var/spack/repos/builtin/packages/parallel-netcdf/package.py index 965e6a365eb..44f71946408 100644 --- a/var/spack/repos/builtin/packages/parallel-netcdf/package.py +++ b/var/spack/repos/builtin/packages/parallel-netcdf/package.py @@ -34,6 +34,7 @@ def url_for_version(self, version): return url.format(version.dotted) version("master", branch="master") + version("1.12.3", sha256="439e359d09bb93d0e58a6e3f928f39c2eae965b6c97f64e67cd42220d6034f77") version("1.12.2", sha256="3ef1411875b07955f519a5b03278c31e566976357ddfc74c2493a1076e7d7c74") version("1.12.1", sha256="56f5afaa0ddc256791c405719b6436a83b92dcd5be37fe860dea103aee8250a2") version("1.11.2", sha256="d2c18601b364c35b5acb0a0b46cd6e14cae456e0eb854e5c789cf65f3cd6a2a7") From 43dd34b651277c71758b3d60d1d19e260e6235fe Mon Sep 17 00:00:00 2001 From: iarspider Date: Thu, 13 Oct 2022 23:06:06 +0200 Subject: [PATCH 037/442] Add checksum for py-psutil 5.9.2 (#33139) --- var/spack/repos/builtin/packages/py-psutil/package.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/var/spack/repos/builtin/packages/py-psutil/package.py b/var/spack/repos/builtin/packages/py-psutil/package.py index 8b401532326..c839f4354e3 100644 --- a/var/spack/repos/builtin/packages/py-psutil/package.py +++ b/var/spack/repos/builtin/packages/py-psutil/package.py @@ -11,8 +11,10 @@ class PyPsutil(PythonPackage): running processes and system utilization (CPU, memory, disks, network) in Python.""" + homepage = "https://github.com/giampaolo/psutil" pypi = "psutil/psutil-5.6.3.tar.gz" + version("5.9.2", sha256="feb861a10b6c3bb00701063b37e4afc754f8217f0f09c42280586bd6ac712b5c") version("5.8.0", sha256="0c9ccb99ab76025f2f0bbecf341d4656e9c1351db8cc8a03ccd62e318ab4b5c6") version("5.7.2", sha256="90990af1c3c67195c44c9a889184f84f5b2320dce3ee3acbd054e3ba0b4a7beb") version("5.6.3", sha256="863a85c1c0a5103a12c05a35e59d336e1d665747e531256e061213e2e90f63f3") @@ -22,4 +24,5 @@ class PyPsutil(PythonPackage): version("5.0.1", sha256="9d8b7f8353a2b2eb6eb7271d42ec99d0d264a9338a37be46424d56b4e473b39e") depends_on("python@2.6:2.8,3.4:", type=("build", "run")) + depends_on("python@2.7:2.8,3.4:", when="@5.9.2:", type=("build", "run")) depends_on("py-setuptools", type="build") From 7da303334ebeb86144a241c09d82c0eb1ec27da0 Mon Sep 17 00:00:00 2001 From: Scott Wittenburg Date: Thu, 13 Oct 2022 16:35:07 -0600 Subject: [PATCH 038/442] gitlab ci: Print better information about broken specs (#33124) When a pipeline generation job is automatically failed because it generated jobs for specs known to be broken on develop, print better information about the broken specs that were encountered. Include at a minimum the hash and the url of the job whose failure caused it to be put on the broken specs list in the first place. --- lib/spack/spack/ci.py | 85 ++++++++++++++++++++++++++++++---- lib/spack/spack/cmd/ci.py | 39 ++++------------ lib/spack/spack/test/cmd/ci.py | 23 +++++---- 3 files changed, 98 insertions(+), 49 deletions(-) diff --git a/lib/spack/spack/ci.py b/lib/spack/spack/ci.py index 198e787dea5..33724e7ac8d 100644 --- a/lib/spack/spack/ci.py +++ b/lib/spack/spack/ci.py @@ -4,6 +4,7 @@ # SPDX-License-Identifier: (Apache-2.0 OR MIT) import base64 +import codecs import copy import json import os @@ -1021,9 +1022,7 @@ def generate_gitlab_ci_yaml( continue if broken_spec_urls is not None and release_spec_dag_hash in broken_spec_urls: - known_broken_specs_encountered.append( - "{0} ({1})".format(release_spec, release_spec_dag_hash) - ) + known_broken_specs_encountered.append(release_spec_dag_hash) # Only keep track of these if we are copying rebuilt cache entries if spack_buildcache_copy: @@ -1286,6 +1285,7 @@ def generate_gitlab_ci_yaml( "SPACK_JOB_TEST_DIR": rel_job_test_dir, "SPACK_LOCAL_MIRROR_DIR": rel_local_mirror_dir, "SPACK_PIPELINE_TYPE": str(spack_pipeline_type), + "SPACK_CI_STACK_NAME": os.environ.get("SPACK_CI_STACK_NAME", "None"), } if remote_mirror_override: @@ -1343,13 +1343,9 @@ def generate_gitlab_ci_yaml( sorted_output = {"no-specs-to-rebuild": noop_job} if known_broken_specs_encountered: - error_msg = ( - "Pipeline generation failed due to the presence of the " - "following specs that are known to be broken in develop:\n" - ) - for broken_spec in known_broken_specs_encountered: - error_msg += "* {0}\n".format(broken_spec) - tty.die(error_msg) + tty.error("This pipeline generated hashes known to be broken on develop:") + display_broken_spec_messages(broken_specs_url, known_broken_specs_encountered) + tty.die() with open(output_file, "w") as outf: outf.write(syaml.dump_config(sorted_output, default_flow_style=True)) @@ -2060,6 +2056,75 @@ def create_buildcache(**kwargs): push_mirror_contents(env, json_path, pipeline_mirror_url, sign_binaries) +def write_broken_spec(url, pkg_name, stack_name, job_url, pipeline_url, spec_dict): + """Given a url to write to and the details of the failed job, write an entry + in the broken specs list. + """ + tmpdir = tempfile.mkdtemp() + file_path = os.path.join(tmpdir, "broken.txt") + + broken_spec_details = { + "broken-spec": { + "job-name": pkg_name, + "job-stack": stack_name, + "job-url": job_url, + "pipeline-url": pipeline_url, + "concrete-spec-dict": spec_dict, + } + } + + try: + with open(file_path, "w") as fd: + fd.write(syaml.dump(broken_spec_details)) + web_util.push_to_url( + file_path, + url, + keep_original=False, + extra_args={"ContentType": "text/plain"}, + ) + except Exception as err: + # If there is an S3 error (e.g., access denied or connection + # error), the first non boto-specific class in the exception + # hierarchy is Exception. Just print a warning and return + msg = "Error writing to broken specs list {0}: {1}".format(url, err) + tty.warn(msg) + finally: + shutil.rmtree(tmpdir) + + +def read_broken_spec(broken_spec_url): + """Read data from broken specs file located at the url, return as a yaml + object. + """ + try: + _, _, fs = web_util.read_from_url(broken_spec_url) + except (URLError, web_util.SpackWebError, HTTPError): + tty.warn("Unable to read broken spec from {0}".format(broken_spec_url)) + return None + + broken_spec_contents = codecs.getreader("utf-8")(fs).read() + return syaml.load(broken_spec_contents) + + +def display_broken_spec_messages(base_url, hashes): + """Fetch the broken spec file for each of the hashes under the base_url and + print a message with some details about each one. + """ + broken_specs = [(h, read_broken_spec(url_util.join(base_url, h))) for h in hashes] + for spec_hash, broken_spec in [tup for tup in broken_specs if tup[1]]: + details = broken_spec["broken-spec"] + if "job-name" in details: + item_name = "{0}/{1}".format(details["job-name"], spec_hash[:7]) + else: + item_name = spec_hash + + if "job-stack" in details: + item_name = "{0} (in stack {1})".format(item_name, details["job-stack"]) + + msg = " {0} was reported broken here: {1}".format(item_name, details["job-url"]) + tty.msg(msg) + + def run_standalone_tests(**kwargs): """Run stand-alone tests on the current spec. diff --git a/lib/spack/spack/cmd/ci.py b/lib/spack/spack/cmd/ci.py index 7bb0497c811..cd7a0bb767f 100644 --- a/lib/spack/spack/cmd/ci.py +++ b/lib/spack/spack/cmd/ci.py @@ -7,7 +7,6 @@ import os import shutil import sys -import tempfile import llnl.util.filesystem as fs import llnl.util.tty as tty @@ -19,7 +18,6 @@ import spack.environment as ev import spack.hash_types as ht import spack.mirror -import spack.util.spack_yaml as syaml import spack.util.url as url_util import spack.util.web as web_util @@ -285,6 +283,7 @@ def ci_rebuild(args): spack_pipeline_type = get_env_var("SPACK_PIPELINE_TYPE") remote_mirror_override = get_env_var("SPACK_REMOTE_MIRROR_OVERRIDE") remote_mirror_url = get_env_var("SPACK_REMOTE_MIRROR_URL") + spack_ci_stack_name = get_env_var("SPACK_CI_STACK_NAME") # Construct absolute paths relative to current $CI_PROJECT_DIR ci_project_dir = get_env_var("CI_PROJECT_DIR") @@ -547,34 +546,14 @@ def ci_rebuild(args): dev_fail_hash = job_spec.dag_hash() broken_spec_path = url_util.join(broken_specs_url, dev_fail_hash) tty.msg("Reporting broken develop build as: {0}".format(broken_spec_path)) - tmpdir = tempfile.mkdtemp() - empty_file_path = os.path.join(tmpdir, "empty.txt") - - broken_spec_details = { - "broken-spec": { - "job-url": get_env_var("CI_JOB_URL"), - "pipeline-url": get_env_var("CI_PIPELINE_URL"), - "concrete-spec-dict": job_spec.to_dict(hash=ht.dag_hash), - } - } - - try: - with open(empty_file_path, "w") as efd: - efd.write(syaml.dump(broken_spec_details)) - web_util.push_to_url( - empty_file_path, - broken_spec_path, - keep_original=False, - extra_args={"ContentType": "text/plain"}, - ) - except Exception as err: - # If there is an S3 error (e.g., access denied or connection - # error), the first non boto-specific class in the exception - # hierarchy is Exception. Just print a warning and return - msg = "Error writing to broken specs list {0}: {1}".format(broken_spec_path, err) - tty.warn(msg) - finally: - shutil.rmtree(tmpdir) + spack_ci.write_broken_spec( + broken_spec_path, + job_spec_pkg_name, + spack_ci_stack_name, + get_env_var("CI_JOB_URL"), + get_env_var("CI_PIPELINE_URL"), + job_spec.to_dict(hash=ht.dag_hash), + ) # We generated the "spack install ..." command to "--keep-stage", copy # any logs from the staging directory to artifacts now diff --git a/lib/spack/spack/test/cmd/ci.py b/lib/spack/spack/test/cmd/ci.py index a8eaa2c631d..37189af73ef 100644 --- a/lib/spack/spack/test/cmd/ci.py +++ b/lib/spack/spack/test/cmd/ci.py @@ -1959,13 +1959,16 @@ def test_ci_generate_read_broken_specs_url( spec_flattendeps.concretize() flattendeps_dag_hash = spec_flattendeps.dag_hash() - # Mark 'a' as broken (but not 'flatten-deps') - broken_spec_a_path = str(tmpdir.join(a_dag_hash)) - with open(broken_spec_a_path, "w") as bsf: - bsf.write("") - broken_specs_url = "file://{0}".format(tmpdir.strpath) + # Mark 'a' as broken (but not 'flatten-deps') + broken_spec_a_url = "{0}/{1}".format(broken_specs_url, a_dag_hash) + job_stack = "job_stack" + a_job_url = "a_job_url" + ci.write_broken_spec( + broken_spec_a_url, spec_a.name, job_stack, a_job_url, "pipeline_url", spec_a.to_dict() + ) + # Test that `spack ci generate` notices this broken spec and fails. filename = str(tmpdir.join("spack.yaml")) with open(filename, "w") as f: @@ -2001,11 +2004,13 @@ def test_ci_generate_read_broken_specs_url( output = ci_cmd("generate", output=str, fail_on_error=False) assert "known to be broken" in output - ex = "({0})".format(a_dag_hash) - assert ex in output + expected = "{0}/{1} (in stack {2}) was reported broken here: {3}".format( + spec_a.name, a_dag_hash[:7], job_stack, a_job_url + ) + assert expected in output - ex = "({0})".format(flattendeps_dag_hash) - assert ex not in output + not_expected = "flatten-deps/{0} (in stack".format(flattendeps_dag_hash[:7]) + assert not_expected not in output def test_ci_generate_external_signing_job( From d5ebb553388d7fbad4221c8f67807ae1e2cebc9b Mon Sep 17 00:00:00 2001 From: "Adam J. Stewart" Date: Thu, 13 Oct 2022 20:26:51 -0500 Subject: [PATCH 039/442] meson: remove slash in path (#33292) --- lib/spack/spack/build_systems/meson.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/spack/spack/build_systems/meson.py b/lib/spack/spack/build_systems/meson.py index 6f5f2d6cbb8..cafd613808f 100644 --- a/lib/spack/spack/build_systems/meson.py +++ b/lib/spack/spack/build_systems/meson.py @@ -75,7 +75,7 @@ class MesonPackage(PackageBase): @property def archive_files(self): """Files to archive for packages based on Meson""" - return [os.path.join(self.build_directory, "meson-logs/meson-log.txt")] + return [os.path.join(self.build_directory, "meson-logs", "meson-log.txt")] @property def root_mesonlists_dir(self): From c13381fab382db52dcb0de47f5be6e6728b19ec9 Mon Sep 17 00:00:00 2001 From: iarspider Date: Fri, 14 Oct 2022 03:27:39 +0200 Subject: [PATCH 040/442] Add checksum for py-gitpython 3.1.27 (#33285) * Add checksum for py-gitpython 3.1.27 * Update package.py * Update var/spack/repos/builtin/packages/py-gitpython/package.py Co-authored-by: Adam J. Stewart Co-authored-by: Adam J. Stewart --- var/spack/repos/builtin/packages/py-gitpython/package.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/py-gitpython/package.py b/var/spack/repos/builtin/packages/py-gitpython/package.py index 6903749062a..742c9ba5c3a 100644 --- a/var/spack/repos/builtin/packages/py-gitpython/package.py +++ b/var/spack/repos/builtin/packages/py-gitpython/package.py @@ -12,6 +12,7 @@ class PyGitpython(PythonPackage): homepage = "https://gitpython.readthedocs.org" pypi = "GitPython/GitPython-3.1.12.tar.gz" + version("3.1.27", sha256="1c885ce809e8ba2d88a29befeb385fcea06338d3640712b59ca623c220bb5704") version("3.1.24", sha256="df83fdf5e684fef7c6ee2c02fc68a5ceb7e7e759d08b694088d0cacb4eba59e5") version("3.1.23", sha256="aaae7a3bfdf0a6db30dc1f3aeae47b71cd326d86b936fe2e158aa925fdf1471c") version("3.1.22", sha256="e1589f27c3cd1f33b22db1df194201b5abca6b4cc5450f13f9c371e099c1b24f") @@ -49,5 +50,8 @@ class PyGitpython(PythonPackage): "py-typing-extensions@3.7.4.0:", type=("build", "run"), when="@3.1.16: ^python@:3.7" ) depends_on( - "py-typing-extensions@3.7.4.3:", type=("build", "run"), when="@3.1.19: ^python@:3.10" + "py-typing-extensions@3.7.4.3:", type=("build", "run"), when="@3.1.19:3.1.26 ^python@:3.10" + ) + depends_on( + "py-typing-extensions@3.7.4.3:", type=("build", "run"), when="@3.1.27: ^python@:3.7" ) From 0de1f98920c291f9df9f16238d2802cb67442290 Mon Sep 17 00:00:00 2001 From: Dan Bonachea Date: Thu, 13 Oct 2022 21:50:27 -0400 Subject: [PATCH 041/442] UPC++/GASNet-EX 2022.9.0 update (#33277) * gasnet: Add new release hash * upcxx: Add new release hash * gasnet: misc updates * upcxx: misc updates --- var/spack/repos/builtin/packages/gasnet/package.py | 6 ++++-- var/spack/repos/builtin/packages/upcxx/package.py | 8 ++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/var/spack/repos/builtin/packages/gasnet/package.py b/var/spack/repos/builtin/packages/gasnet/package.py index efcb23828d1..baec00cd59e 100644 --- a/var/spack/repos/builtin/packages/gasnet/package.py +++ b/var/spack/repos/builtin/packages/gasnet/package.py @@ -31,12 +31,13 @@ class Gasnet(Package, CudaPackage, ROCmPackage): maintainers = ["PHHargrove", "bonachea"] - tags = ["e4s"] + tags = ["e4s", "ecp"] version("develop", branch="develop") version("main", branch="stable") version("master", branch="master") + version("2022.9.0", sha256="6873ff4ad8ebee49da4378f2d78095a6ccc31333d6ae4cd739b9f772af11f936") version("2022.3.0", sha256="91b59aa84c0680c807e00d3d1d8fa7c33c1aed50b86d1616f93e499620a9ba09") version("2021.9.0", sha256="1b6ff6cdad5ecf76b92032ef9507e8a0876c9fc3ee0ab008de847c1fad0359ee") version("2021.3.0", sha256="8a40fb3fa8bacc3922cd4d45217816fcb60100357ab97fb622a245567ea31747") @@ -53,9 +54,9 @@ class Gasnet(Package, CudaPackage, ROCmPackage): description="The hardware-dependent network backends to enable.\n" + "(smp) = SMP conduit for single-node operation ;\n" + "(ibv) = Native InfiniBand verbs conduit ;\n" + + "(ofi) = OFI conduit over libfabric, for HPE Cray Slingshot and Intel Omni-Path ;\n" + "(udp) = Portable UDP conduit, for Ethernet networks ;\n" + "(mpi) = Low-performance/portable MPI conduit ;\n" - + "(ofi) = EXPERIMENTAL Portable OFI conduit over libfabric ;\n" + "(ucx) = EXPERIMENTAL UCX conduit for Mellanox IB/RoCE ConnectX-5+ ;\n" + "For detailed recommendations, consult https://gasnet.lbl.gov", ) @@ -164,6 +165,7 @@ def test(self): } os.environ["GASNET_VERBOSEENV"] = "1" # include diagnostic info + os.environ["GASNET_SPAWN_VERBOSE"] = "1" # include spawning diagnostics if "GASNET_SSH_SERVERS" not in os.environ: os.environ["GASNET_SSH_SERVERS"] = "localhost " * 4 diff --git a/var/spack/repos/builtin/packages/upcxx/package.py b/var/spack/repos/builtin/packages/upcxx/package.py index ce6081a1ae9..04841436212 100644 --- a/var/spack/repos/builtin/packages/upcxx/package.py +++ b/var/spack/repos/builtin/packages/upcxx/package.py @@ -42,11 +42,12 @@ class Upcxx(Package, CudaPackage, ROCmPackage): url = "https://bitbucket.org/berkeleylab/upcxx/downloads/upcxx-2021.3.0.tar.gz" git = "https://bitbucket.org/berkeleylab/upcxx.git" - tags = ["e4s"] + tags = ["e4s", "ecp"] version("develop", branch="develop") version("master", branch="master") + version("2022.9.0", sha256="dbf15fd9ba38bfe2491f556b55640343d6303048a117c4e84877ceddb64e4c7c") version("2022.3.0", sha256="72bccfc9dfab5c2351ee964232b3754957ecfdbe6b4de640e1b1387d45019496") version("2021.9.0", sha256="9299e17602bcc8c05542cdc339897a9c2dba5b5c3838d6ef2df7a02250f42177") version("2021.3.0", sha256="3433714cd4162ffd8aad9a727c12dbf1c207b7d6664879fc41259a4b351595b7") @@ -89,7 +90,8 @@ class Upcxx(Package, CudaPackage, ROCmPackage): # UPC++ always relies on GASNet-EX. # The default (and recommendation) is to use the implicit, embedded version. - # This variant allows overriding with a particular version of GASNet-EX sources. + # This variant allows overriding with a particular version of GASNet-EX sources, + # although this is not officially supported and some combinations might be rejected. variant("gasnet", default=False, description="Override embedded GASNet-EX version") depends_on("gasnet conduits=none", when="+gasnet") @@ -148,6 +150,7 @@ def install(self, spec, prefix): real_cc = join_path(env["CRAYPE_DIR"], "bin", "cc") real_cxx = join_path(env["CRAYPE_DIR"], "bin", "CC") # workaround a bug in the UPC++ installer: (issue #346) + # this can be removed once the floor version reaches 2020.10.0 env["GASNET_CONFIGURE_ARGS"] += " --with-cc=" + real_cc + " --with-cxx=" + real_cxx if "+mpi" in spec: env["GASNET_CONFIGURE_ARGS"] += " --with-mpicc=" + real_cc @@ -169,6 +172,7 @@ def install(self, spec, prefix): provider = "verbs;ofi_rxm" # Append the recommended options for Cray Shasta + # This list can be pruned once the floor version reaches 2022.9.0 options.append("--with-pmi-version=cray") options.append("--with-pmi-runcmd='srun -n %N -- %C'") options.append("--disable-ibv") From 67bc90acb764971e7bb07383c8ae469918886f6c Mon Sep 17 00:00:00 2001 From: Auriane R <48684432+aurianer@users.noreply.github.com> Date: Fri, 14 Oct 2022 15:13:57 +0200 Subject: [PATCH 042/442] Fix pika@0.9.0 sha (#33307) --- var/spack/repos/builtin/packages/pika/package.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/pika/package.py b/var/spack/repos/builtin/packages/pika/package.py index c5a1aa555fe..0eee028dd69 100644 --- a/var/spack/repos/builtin/packages/pika/package.py +++ b/var/spack/repos/builtin/packages/pika/package.py @@ -17,7 +17,7 @@ class Pika(CMakePackage, CudaPackage, ROCmPackage): git = "https://github.com/pika-org/pika.git" maintainers = ["msimberg", "albestro", "teonnik", "aurianer"] - version("0.9.0", branch="c349b2a96476d6974d2421288ca4d2e14ef9e5897d44cd7d5343165faa2d1299") + version("0.9.0", sha256="c349b2a96476d6974d2421288ca4d2e14ef9e5897d44cd7d5343165faa2d1299") version("0.8.0", sha256="058e82d7c8f95badabe52bbb4682d55aadf340d67ced1226c0673b4529adc182") version("0.7.0", sha256="e1bf978c88515f7af28ee47f98b795ffee521c15b39877ea4cfb405f31d507ed") version("0.6.0", sha256="cb4ebd7b92da39ec4df7b0d05923b94299d6ee2f2f49752923ffa2266ca76568") From c44934a44dc3b36f30b744357fa7e2d42feb9ebb Mon Sep 17 00:00:00 2001 From: eugeneswalker <38933153+eugeneswalker@users.noreply.github.com> Date: Fri, 14 Oct 2022 08:12:07 -0700 Subject: [PATCH 043/442] hip@5.2.0 onwards: set prefix properly (#33257) * hip-set-prefix-rocm5.2.0-onwards * Update var/spack/repos/builtin/packages/hip/package.py Update description Co-authored-by: Satish Balay --- var/spack/repos/builtin/packages/hip/package.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/var/spack/repos/builtin/packages/hip/package.py b/var/spack/repos/builtin/packages/hip/package.py index 8b9b39f9a76..41c2d2d29fe 100644 --- a/var/spack/repos/builtin/packages/hip/package.py +++ b/var/spack/repos/builtin/packages/hip/package.py @@ -288,10 +288,12 @@ def get_paths(self): if self.spec.external: # For external packages we only assume the `hip` prefix is known, # because spack does not set prefixes of dependencies of externals. - # We assume self.spec.prefix is /opt/rocm-x.y.z/hip and rocm has a - # default installation with everything installed under - # /opt/rocm-x.y.z - rocm_prefix = Prefix(os.path.dirname(self.spec.prefix)) + # We assume self.spec.prefix is /opt/rocm-x.y.z for rocm-5.2.0 and newer + # and /opt/rocm-x.y.z/hip for older versions + if self.spec.satisfies("@5.2.0:"): + rocm_prefix = Prefix(self.spec.prefix) + else: + rocm_prefix = Prefix(os.path.dirname(self.spec.prefix)) if not os.path.isdir(rocm_prefix): msg = "Could not determine prefix for other rocm components\n" From 6983d520fa64d8c7343dcc627197b0e6c621d1a6 Mon Sep 17 00:00:00 2001 From: Satish Balay Date: Fri, 14 Oct 2022 10:12:16 -0500 Subject: [PATCH 044/442] petsc,py-petsc4py,slepc,py-slepc4py: add version 3.18.0 (#32938) * petsc,py-petsc4py,slepc,py-slepc4py: add version 3.18.0 * workaround for dealii build failure [with petsc version check] * pism: add compatibility fix to for petsc@3.18 * add in hipsolver dependency --- .../repos/builtin/packages/petsc/package.py | 6 +- .../revert-3.18.0-ver-format-for-dealii.patch | 57 +++++++++++++++++++ .../repos/builtin/packages/pism/package.py | 2 + .../packages/pism/pism-petsc-3.18.diff | 22 +++++++ .../builtin/packages/py-petsc4py/package.py | 3 + .../builtin/packages/py-slepc4py/package.py | 3 + .../repos/builtin/packages/slepc/package.py | 2 + 7 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 var/spack/repos/builtin/packages/petsc/revert-3.18.0-ver-format-for-dealii.patch create mode 100644 var/spack/repos/builtin/packages/pism/pism-petsc-3.18.diff diff --git a/var/spack/repos/builtin/packages/petsc/package.py b/var/spack/repos/builtin/packages/petsc/package.py index 05799ec6bea..75d041fc1de 100644 --- a/var/spack/repos/builtin/packages/petsc/package.py +++ b/var/spack/repos/builtin/packages/petsc/package.py @@ -22,6 +22,8 @@ class Petsc(Package, CudaPackage, ROCmPackage): version("main", branch="main") + version("3.18.0", sha256="9da802e703ad79fb7ef0007d17f68916573011073ee9712dcd1673537f6a5f68") + version("3.17.5", sha256="a1193e6c50a1676c3972a1edf0a06eec9fac8ecc2f3771f2689a8997423e4c71") version("3.17.4", sha256="99c127486722a3ffd95a268b4ceb0976cbf217926c681a9631bd7246eab8cb2a") version("3.17.3", sha256="5c24ade5e4b32cc04935ba0db1dafe48d633bebaaa30a3033f1e58788d37875f") version("3.17.2", sha256="2313dd1ca41bf0ace68671ea6f8d4abf90011ed899f5e1e08658d3f18478359d") @@ -201,6 +203,7 @@ def check_fortran_compiler(self): patch("xcode_stub_out_of_sync.patch", when="@:3.10.4") patch("xlf_fix-dup-petscfecreate.patch", when="@3.11.0") patch("disable-DEPRECATED_ENUM.diff", when="@3.14.1 +cuda") + patch("revert-3.18.0-ver-format-for-dealii.patch", when="@3.18.0") depends_on("diffutils", type="build") @@ -217,6 +220,7 @@ def check_fortran_compiler(self): depends_on("hip", when="+rocm") depends_on("hipblas", when="+rocm") depends_on("hipsparse", when="+rocm") + depends_on("hipsolver", when="+rocm") depends_on("rocsparse", when="+rocm") depends_on("rocsolver", when="+rocm") depends_on("rocblas", when="+rocm") @@ -543,7 +547,7 @@ def configure_options(self): if not spec.satisfies("amdgpu_target=none"): hip_arch = spec.variants["amdgpu_target"].value options.append("--with-hip-arch={0}".format(hip_arch[0])) - hip_pkgs = ["hipsparse", "hipblas", "rocsparse", "rocsolver", "rocblas"] + hip_pkgs = ["hipsparse", "hipblas", "hipsolver", "rocsparse", "rocsolver", "rocblas"] hip_ipkgs = hip_pkgs + ["rocthrust", "rocprim"] hip_lpkgs = hip_pkgs if spec.satisfies("^rocrand@5.1:"): diff --git a/var/spack/repos/builtin/packages/petsc/revert-3.18.0-ver-format-for-dealii.patch b/var/spack/repos/builtin/packages/petsc/revert-3.18.0-ver-format-for-dealii.patch new file mode 100644 index 00000000000..6c6d96c2693 --- /dev/null +++ b/var/spack/repos/builtin/packages/petsc/revert-3.18.0-ver-format-for-dealii.patch @@ -0,0 +1,57 @@ +--- a/include/petscversion.h 2022-10-01 13:55:26.000000000 -0500 ++++ b/include/petscversion.h 2022-10-10 18:03:11.525297321 -0500 +@@ -2,11 +2,11 @@ + #define PETSCVERSION_H + #include + +-#define PETSC_VERSION_RELEASE 1 +-#define PETSC_VERSION_MAJOR 3 +-#define PETSC_VERSION_MINOR 18 +-#define PETSC_VERSION_SUBMINOR 0 +-#define PETSC_RELEASE_DATE "Sep 30, 2022" ++#define PETSC_VERSION_RELEASE 1 ++#define PETSC_VERSION_MAJOR 3 ++#define PETSC_VERSION_MINOR 18 ++#define PETSC_VERSION_SUBMINOR 0 ++#define PETSC_RELEASE_DATE "Sep 30, 2022" + #define PETSC_VERSION_DATE "Sep 30, 2022" + + #if !defined(PETSC_VERSION_GIT) +@@ -17,17 +17,30 @@ + #define PETSC_VERSION_DATE_GIT "2022-09-30 20:39:36 -0500" + #endif + +-#define PETSC_VERSION_EQ(MAJOR, MINOR, SUBMINOR) ((PETSC_VERSION_MAJOR == (MAJOR)) && (PETSC_VERSION_MINOR == (MINOR)) && (PETSC_VERSION_SUBMINOR == (SUBMINOR)) && (PETSC_VERSION_RELEASE == 1)) ++#define PETSC_VERSION_EQ(MAJOR,MINOR,SUBMINOR) \ ++ ((PETSC_VERSION_MAJOR == (MAJOR)) && \ ++ (PETSC_VERSION_MINOR == (MINOR)) && \ ++ (PETSC_VERSION_SUBMINOR == (SUBMINOR)) && \ ++ (PETSC_VERSION_RELEASE == 1)) + + #define PETSC_VERSION_ PETSC_VERSION_EQ + +-#define PETSC_VERSION_LT(MAJOR, MINOR, SUBMINOR) \ +- (PETSC_VERSION_RELEASE == 1 && (PETSC_VERSION_MAJOR < (MAJOR) || (PETSC_VERSION_MAJOR == (MAJOR) && (PETSC_VERSION_MINOR < (MINOR) || (PETSC_VERSION_MINOR == (MINOR) && (PETSC_VERSION_SUBMINOR < (SUBMINOR))))))) ++#define PETSC_VERSION_LT(MAJOR,MINOR,SUBMINOR) \ ++ (PETSC_VERSION_RELEASE == 1 && \ ++ (PETSC_VERSION_MAJOR < (MAJOR) || \ ++ (PETSC_VERSION_MAJOR == (MAJOR) && \ ++ (PETSC_VERSION_MINOR < (MINOR) || \ ++ (PETSC_VERSION_MINOR == (MINOR) && \ ++ (PETSC_VERSION_SUBMINOR < (SUBMINOR))))))) ++ ++#define PETSC_VERSION_LE(MAJOR,MINOR,SUBMINOR) \ ++ (PETSC_VERSION_LT(MAJOR,MINOR,SUBMINOR) || \ ++ PETSC_VERSION_EQ(MAJOR,MINOR,SUBMINOR)) + +-#define PETSC_VERSION_LE(MAJOR, MINOR, SUBMINOR) (PETSC_VERSION_LT(MAJOR, MINOR, SUBMINOR) || PETSC_VERSION_EQ(MAJOR, MINOR, SUBMINOR)) ++#define PETSC_VERSION_GT(MAJOR,MINOR,SUBMINOR) \ ++ (0 == PETSC_VERSION_LE(MAJOR,MINOR,SUBMINOR)) + +-#define PETSC_VERSION_GT(MAJOR, MINOR, SUBMINOR) (0 == PETSC_VERSION_LE(MAJOR, MINOR, SUBMINOR)) +- +-#define PETSC_VERSION_GE(MAJOR, MINOR, SUBMINOR) (0 == PETSC_VERSION_LT(MAJOR, MINOR, SUBMINOR)) ++#define PETSC_VERSION_GE(MAJOR,MINOR,SUBMINOR) \ ++ (0 == PETSC_VERSION_LT(MAJOR,MINOR,SUBMINOR)) + + #endif diff --git a/var/spack/repos/builtin/packages/pism/package.py b/var/spack/repos/builtin/packages/pism/package.py index 912752792ac..edfb3ebd3e6 100644 --- a/var/spack/repos/builtin/packages/pism/package.py +++ b/var/spack/repos/builtin/packages/pism/package.py @@ -47,6 +47,8 @@ class Pism(CMakePackage): description = "Report errors through Everytrace (requires Everytrace)" variant("everytrace", default=False, description=description) + patch("pism-petsc-3.18.diff", when="@1.1.4 ^petsc@3.18:") + # CMake build options not transferred to Spack variants # (except from CMakeLists.txt) # diff --git a/var/spack/repos/builtin/packages/pism/pism-petsc-3.18.diff b/var/spack/repos/builtin/packages/pism/pism-petsc-3.18.diff new file mode 100644 index 00000000000..68d47427edd --- /dev/null +++ b/var/spack/repos/builtin/packages/pism/pism-petsc-3.18.diff @@ -0,0 +1,22 @@ +--- spack-src/src/util/options.cc~ 2019-06-17 13:14:35.000000000 -0500 ++++ spack-src/src/util/options.cc 2022-10-10 19:50:05.309762538 -0500 +@@ -59,8 +59,7 @@ + memset(tmp, 0, TEMPORARY_STRING_LENGTH); + + PetscErrorCode ierr; +- ierr = PetscOptionsBegin(MPI_COMM_SELF, "", "", ""); +- PISM_CHK(ierr, "PetscOptionsBegin"); ++ PetscOptionsBegin(MPI_COMM_SELF, "", "", ""); + + ierr = PetscOptionsString(option.c_str(), + description.c_str(), +@@ -71,8 +70,7 @@ + &flag); // PETSC_TRUE if found, else PETSC_FALSE + PISM_CHK(ierr, "PetscOptionsString"); + +- ierr = PetscOptionsEnd(); +- PISM_CHK(ierr, "PetscOptionsEnd"); ++ PetscOptionsEnd(); + + std::string result = tmp; + diff --git a/var/spack/repos/builtin/packages/py-petsc4py/package.py b/var/spack/repos/builtin/packages/py-petsc4py/package.py index 555c26e4986..ded5146c6cf 100644 --- a/var/spack/repos/builtin/packages/py-petsc4py/package.py +++ b/var/spack/repos/builtin/packages/py-petsc4py/package.py @@ -16,6 +16,8 @@ class PyPetsc4py(PythonPackage): maintainers = ["balay"] version("main", branch="main") + version("3.18.0", sha256="76bad2d35f380f698f5649c3f38eabd153b9b19b1fe3ce3a1d3de9aa5824a4d2") + version("3.17.5", sha256="e435d927bf22950c71c30bda538e1ae75f48f6931a63205c6fbeff6cf4393f09") version("3.17.4", sha256="216c3da074557946615d37d0826bc89f1f2e599323e2dacbdc45326d78bd50c6") version("3.17.3", sha256="c588ab4a17deebe7f0a57f966b3368d88f01d1a1c09f220f63fe8e3b37a32899") version("3.17.2", sha256="7e256e13013ce12c8e52edee35920e3d2c1deaae1b71597a3064201eba7abc1c") @@ -61,6 +63,7 @@ class PyPetsc4py(PythonPackage): depends_on("petsc+mpi", when="+mpi") depends_on("petsc~mpi", when="~mpi") depends_on("petsc@main", when="@main") + depends_on("petsc@3.18.0:3.18", when="@3.18.0:3.18") depends_on("petsc@3.17.0:3.17", when="@3.17.0:3.17") depends_on("petsc@3.16.0:3.16", when="@3.16.0:3.16") depends_on("petsc@3.15.0:3.15", when="@3.15.0:3.15") diff --git a/var/spack/repos/builtin/packages/py-slepc4py/package.py b/var/spack/repos/builtin/packages/py-slepc4py/package.py index 2525fe46dd2..3d8f8d2b2e6 100644 --- a/var/spack/repos/builtin/packages/py-slepc4py/package.py +++ b/var/spack/repos/builtin/packages/py-slepc4py/package.py @@ -16,6 +16,7 @@ class PySlepc4py(PythonPackage): maintainers = ["joseeroman", "balay"] version("main", branch="main") + version("3.18.0", sha256="aa83f46f942aca05ffcbc8be29b496f56837f564e0396f5b39cec4946654ee78") version("3.17.2", sha256="e5b235486b6901cd4ff0d94083f0e5eeacaef3a2893e1714769717ad488a3885") version("3.17.1", sha256="967d5d045526088ff5b7b2cde76f8b4d1fee3a2a68481f85224b0795e6613eb9") version("3.17.0", sha256="cab298eb794739579167fd60ff900db90476c4c93b4ae4e0204e989a6eeb3767") @@ -41,6 +42,7 @@ class PySlepc4py(PythonPackage): depends_on("py-setuptools", type="build") depends_on("py-petsc4py", type=("build", "run")) + depends_on("py-petsc4py@3.18.0:3.18", when="@3.18.0:3.18", type=("build", "run")) depends_on("py-petsc4py@3.17.0:3.17", when="@3.17.0:3.17", type=("build", "run")) depends_on("py-petsc4py@3.16.0:3.16", when="@3.16.0:3.16", type=("build", "run")) depends_on("py-petsc4py@3.15.0:3.15", when="@3.15.0:3.15", type=("build", "run")) @@ -53,6 +55,7 @@ class PySlepc4py(PythonPackage): depends_on("py-petsc4py@3.7.0:3.7", when="@3.7.0:3.7", type=("build", "run")) depends_on("slepc") + depends_on("slepc@3.18.0:3.18", when="@3.18.0:3.18") depends_on("slepc@3.17.0:3.17", when="@3.17.0:3.17") depends_on("slepc@3.16.0:3.16", when="@3.16.0:3.16") depends_on("slepc@3.15.0:3.15", when="@3.15.0:3.15") diff --git a/var/spack/repos/builtin/packages/slepc/package.py b/var/spack/repos/builtin/packages/slepc/package.py index 0a19e0025f3..3fc5a5c170c 100644 --- a/var/spack/repos/builtin/packages/slepc/package.py +++ b/var/spack/repos/builtin/packages/slepc/package.py @@ -22,6 +22,7 @@ class Slepc(Package, CudaPackage, ROCmPackage): test_requires_compiler = True version("main", branch="main") + version("3.18.0", sha256="18af535d979a646363df01f407c75f0e3b0dd97b3fdeb20dca25b30cd89239ee") version("3.17.2", sha256="f784cca83a14156631d6e0f5726ca0778e259e1fe40c927607d5fb12d958d705") version("3.17.1", sha256="11386cd3f4c0f9727af3c1c59141cc4bf5f83bdf7c50251de0845e406816f575") version("3.17.0", sha256="d4685fed01b2351c66706cbd6d08e4083a4645df398ef5ccd68fdfeb2f86ea97") @@ -69,6 +70,7 @@ class Slepc(Package, CudaPackage, ROCmPackage): # Cannot mix release and development versions of SLEPc and PETSc: depends_on("petsc@main", when="@main") + depends_on("petsc@3.18.0:3.18", when="@3.18.0:3.18") depends_on("petsc@3.17.0:3.17", when="@3.17.0:3.17") depends_on("petsc@3.16.0:3.16", when="@3.16.0:3.16") depends_on("petsc@3.15.0:3.15", when="@3.15.0:3.15") From 89b3e6c6d01d674977c3a6d6827e180fb04e419c Mon Sep 17 00:00:00 2001 From: John-Luke Navarro <33131245+jlnav@users.noreply.github.com> Date: Fri, 14 Oct 2022 11:01:57 -0500 Subject: [PATCH 045/442] py-libensemble: updating package for v0.9.3 (#33298) * commit updating py-libensemble package for 0.9.3 * removed commented-out lines --- .../repos/builtin/packages/py-libensemble/package.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/var/spack/repos/builtin/packages/py-libensemble/package.py b/var/spack/repos/builtin/packages/py-libensemble/package.py index 6d5bfbc35b5..13b511811e5 100644 --- a/var/spack/repos/builtin/packages/py-libensemble/package.py +++ b/var/spack/repos/builtin/packages/py-libensemble/package.py @@ -12,13 +12,14 @@ class PyLibensemble(PythonPackage): """Library for managing ensemble-like collections of computations.""" homepage = "https://libensemble.readthedocs.io" - pypi = "libensemble/libensemble-0.9.2.tar.gz" + pypi = "libensemble/libensemble-0.9.3.tar.gz" git = "https://github.com/Libensemble/libensemble.git" - maintainers = ["shuds13"] + maintainers = ["shuds13", "jlnav"] tags = ["e4s"] version("develop", branch="develop") + version("0.9.3", sha256="00e5a65d6891feee6a686c048d8de72097b8bff164431f163be96ec130a9c390") version("0.9.2", sha256="e46598e5696f770cbff4cb90507b52867faad5654f1b80de35405a95228c909f") version("0.9.1", sha256="684e52b0ea64f5ec610e7868b7e4c9fa5fd2316a370a726870aa5fd5fb1b0ede") version("0.9.0", sha256="34976e775f0d2ba5955744560104eab214fd22cb47173440eb5136e852a8ec38") @@ -45,9 +46,6 @@ class PyLibensemble(PythonPackage): variant("tasmanian", default=False, description="Install with tasmanian") variant("pyyaml", default=False, description="Install with pyyaml") - # depends_on('python@2.7:2.8,3.3:', when='@:0.4.1') - # depends_on('python@3.5:', when='@0.5.0:') - depends_on("python@3.5:", type=("build", "run")) depends_on("py-setuptools", type="build") depends_on("py-numpy", type=("build", "run")) depends_on("py-psutil", type=("build", "run"), when="@0.7.1:") From 9546eadd980d233f1301a6adc1e743f73da72fae Mon Sep 17 00:00:00 2001 From: iarspider Date: Fri, 14 Oct 2022 20:46:08 +0200 Subject: [PATCH 046/442] Add checksum for py-oauthlib 3.2.1 (#33201) * Add checksum for py-oauthlib 3.2.1 * Update package.py * [@spackbot] updating style on behalf of iarspider * Update package.py * Update package.py Co-authored-by: iarspider --- .../builtin/packages/py-oauthlib/package.py | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/var/spack/repos/builtin/packages/py-oauthlib/package.py b/var/spack/repos/builtin/packages/py-oauthlib/package.py index d5a7fb4ef6a..1b73e0c4b2a 100644 --- a/var/spack/repos/builtin/packages/py-oauthlib/package.py +++ b/var/spack/repos/builtin/packages/py-oauthlib/package.py @@ -15,19 +15,38 @@ class PyOauthlib(PythonPackage): homepage = "https://github.com/oauthlib/oauthlib" pypi = "oauthlib/oauthlib-3.1.0.tar.gz" + version("3.2.1", sha256="1565237372795bf6ee3e5aba5e2a85bd5a65d0e2aa5c628b9a97b7d7a0da3721") version("3.1.1", sha256="8f0215fcc533dd8dd1bee6f4c412d4f0cd7297307d43ac61666389e3bc3198a3") version("3.1.0", sha256="bee41cc35fcca6e988463cacc3bcb8a96224f470ca547e697b604cc697b2f889") version("3.0.1", sha256="0ce32c5d989a1827e3f1148f98b9085ed2370fc939bf524c9c851d8714797298") version("2.0.2", sha256="b3b9b47f2a263fe249b5b48c4e25a5bce882ff20a0ac34d553ce43cff55b53ac") - variant("extras", default=True, description="Build with pyjwt, blinker, cryptography") + variant( + "extras", + when="@:3.1.1", + default=True, + description="Build with pyjwt, blinker, cryptography", + ) + variant("rsa", when="@3.2.1:", default=False, description="Build with cryptography") + variant( + "signedtoken", + when="@3.2.1:", + default=False, + description="Build with cryptography and pyjwt", + ) + variant("signals", when="@3.2.1:", default=False, description="Build with blinker") depends_on("py-setuptools", type="build") depends_on("py-pyjwt@1.0.0:", type=("build", "run"), when="+extras") depends_on("py-pyjwt@2.0.0:2", type=("build", "run"), when="+extras @3.1.1:") + depends_on("py-pyjwt@2.0.0:2", type=("build", "run"), when="+signedtoken @3.2.1:") depends_on("py-blinker", type=("build", "run"), when="+extras") + depends_on("py-blinker", type=("build", "run"), when="+signals") depends_on("py-blinker@1.4:", type=("build", "run"), when="+extras @3.1.1:") + depends_on("py-blinker@1.4:", type=("build", "run"), when="+signals @3.2.1:") depends_on("py-cryptography", type=("build", "run"), when="+extras") - depends_on("py-cryptography@3.0.0:3", type=("build", "run"), when="+extras @3.1.1:") + depends_on("py-cryptography@3.0.0:3", type=("build", "run"), when="+extras @3.1.1") + depends_on("py-cryptography@3.0.0:", type=("build", "run"), when="+rsa @3.2.1:") + depends_on("py-cryptography@3.0.0:", type=("build", "run"), when="+signedtoken @3.2.1:") depends_on("python@2.7:2.8,3.4:", type=("build", "run")) depends_on("python@3.6:", type=("build", "run"), when="@3.1.1:") From a661193c6499ece2c580ada8e97bd6a478c5429d Mon Sep 17 00:00:00 2001 From: Erik Schnetter Date: Fri, 14 Oct 2022 16:31:42 -0400 Subject: [PATCH 047/442] ninja: New version 1.11.1 (#33215) --- var/spack/repos/builtin/packages/ninja/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/ninja/package.py b/var/spack/repos/builtin/packages/ninja/package.py index 5321d550411..e71b648f263 100644 --- a/var/spack/repos/builtin/packages/ninja/package.py +++ b/var/spack/repos/builtin/packages/ninja/package.py @@ -25,6 +25,7 @@ class Ninja(Package): version("kitware", branch="features-for-fortran", git="https://github.com/Kitware/ninja.git") version("master", branch="master") + version("1.11.1", sha256="31747ae633213f1eda3842686f83c2aa1412e0f5691d1c14dbbcc67fe7400cea") version("1.11.0", sha256="3c6ba2e66400fe3f1ae83deb4b235faf3137ec20bd5b08c29bfc368db143e4c6") version("1.10.2", sha256="ce35865411f0490368a8fc383f29071de6690cbadc27704734978221f25e2bed") version("1.10.1", sha256="a6b6f7ac360d4aabd54e299cc1d8fa7b234cd81b9401693da21221c62569a23e") From 2a166a5cc4a59cb500e4abd119b6081b53146649 Mon Sep 17 00:00:00 2001 From: Greg Sjaardema Date: Fri, 14 Oct 2022 16:49:06 -0600 Subject: [PATCH 048/442] seacas: update to latest release (#33330) Add checksum for latest tag/release --- var/spack/repos/builtin/packages/seacas/package.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/var/spack/repos/builtin/packages/seacas/package.py b/var/spack/repos/builtin/packages/seacas/package.py index 4d486f2fb21..061e89d033a 100644 --- a/var/spack/repos/builtin/packages/seacas/package.py +++ b/var/spack/repos/builtin/packages/seacas/package.py @@ -28,6 +28,9 @@ class Seacas(CMakePackage): # ###################### Versions ########################## version("master", branch="master") + version( + "2022-10-14", sha256="cde91e7561d2352045d669a25bdf46a604d85ed1ea7f3f5028004455e4ce9d56" + ) version( "2022-05-16", sha256="22ff67045d730a2c7d5394c9034e44a2033cc82a461574f93d899e9aa713d4ae" ) From 19226ecc49be26df5af4ad1c4ea950a5b5e48d4c Mon Sep 17 00:00:00 2001 From: WuK Date: Sat, 15 Oct 2022 06:54:41 +0800 Subject: [PATCH 049/442] gptl: new version 8.1.1; use the correct mpi fortran compiler (#33235) * gptl: new version 8.1.1; use the correct `mpifc` * add `F90` and `$F77` --- var/spack/repos/builtin/packages/gptl/package.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/var/spack/repos/builtin/packages/gptl/package.py b/var/spack/repos/builtin/packages/gptl/package.py index 35f2c9380e0..f4b69362879 100644 --- a/var/spack/repos/builtin/packages/gptl/package.py +++ b/var/spack/repos/builtin/packages/gptl/package.py @@ -18,6 +18,7 @@ class Gptl(AutotoolsPackage): maintainers = ["edwardhartnett", "kgerheiser", "Hang-Lei-NOAA", " jmrosinski"] + version("8.1.1", sha256="b8ee26f7aeedd2a31d565789634e7c380023fe6b65bbf59030884f4dcbce94a5") version("8.0.3", sha256="334979c6fe78d4ed1b491ec57fb61df7a910c58fd39a3658d03ad89f077a4db6") version("8.0.2", sha256="011f153084ebfb52b6bf8f190835d4bae6f6b5c0ad320331356aa47a547bf2b4") @@ -34,6 +35,10 @@ def configure_args(self): if "+pmpi" in self.spec: args.append("--enable-pmpi") args.append("CC=" + self.spec["mpi"].mpicc) + args.append("CXX=" + self.spec["mpi"].mpicxx) + args.append("FC=" + self.spec["mpi"].mpifc) + args.append("F90=" + self.spec["mpi"].mpifc) + args.append("F77=" + self.spec["mpi"].mpif77) if "+papi" in self.spec: args.append("--enable-papi") From 31cda96181c27889782ed48a091bc4c683bf1254 Mon Sep 17 00:00:00 2001 From: Michael Kuhn Date: Sat, 15 Oct 2022 05:27:08 +0200 Subject: [PATCH 050/442] glib: add 2.74.0 and 2.72.4 (#33332) --- var/spack/repos/builtin/packages/glib/package.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/var/spack/repos/builtin/packages/glib/package.py b/var/spack/repos/builtin/packages/glib/package.py index 83dfb307b20..a7d9c43ef6a 100644 --- a/var/spack/repos/builtin/packages/glib/package.py +++ b/var/spack/repos/builtin/packages/glib/package.py @@ -23,6 +23,8 @@ class Glib(Package): maintainers = ["michaelkuhn"] + version("2.74.0", sha256="3652c7f072d7b031a6b5edd623f77ebc5dcd2ae698598abcc89ff39ca75add30") + version("2.72.4", sha256="8848aba518ba2f4217d144307a1d6cb9afcc92b54e5c13ac1f8c4d4608e96f0e") version("2.72.3", sha256="4a39a2f624b8512d500d5840173eda7fa85f51c109052eae806acece85d345f0") version("2.72.2", sha256="78d599a133dba7fe2036dfa8db8fb6131ab9642783fc9578b07a20995252d2de") version("2.72.1", sha256="c07e57147b254cef92ce80a0378dc0c02a4358e7de4702e9f403069781095fe2") @@ -137,7 +139,7 @@ class Glib(Package): # glib prefers the libc version of gettext, which breaks the build if the # external version is also found. patch("meson-gettext.patch", when="@2.58:2.64") - patch("meson-gettext-2.66.patch", when="@2.66:2.68,2.72:") + patch("meson-gettext-2.66.patch", when="@2.66:2.68,2.72") patch("meson-gettext-2.70.patch", when="@2.70") def url_for_version(self, version): @@ -162,7 +164,9 @@ def libs(self): return find_libraries(["libglib*"], root=self.prefix, recursive=True) def meson_args(self): - args = ["-Dgettext=external"] + args = [] + if self.spec.satisfies("@:2.72"): + args.append("-Dgettext=external") if self.spec.satisfies("@2.63.5:"): if "+libmount" in self.spec: args.append("-Dlibmount=enabled") From 2f6a56a43b88a8c2d43e1cac199f4bd136c8bec2 Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Sat, 15 Oct 2022 06:10:05 +0200 Subject: [PATCH 051/442] depfile: update docs (#33279) --- lib/spack/docs/environments.rst | 46 ++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/lib/spack/docs/environments.rst b/lib/spack/docs/environments.rst index 2b981373149..b417e26f3e1 100644 --- a/lib/spack/docs/environments.rst +++ b/lib/spack/docs/environments.rst @@ -986,7 +986,7 @@ A typical workflow is as follows: spack env create -d . spack -e . add perl spack -e . concretize - spack -e . env depfile > Makefile + spack -e . env depfile -o Makefile make -j64 This generates a ``Makefile`` from a concretized environment in the @@ -999,7 +999,6 @@ load, even when packages are built in parallel. By default the following phony convenience targets are available: - ``make all``: installs the environment (default target); -- ``make fetch-all``: only fetch sources of all packages; - ``make clean``: cleans files used by make, but does not uninstall packages. .. tip:: @@ -1009,8 +1008,17 @@ By default the following phony convenience targets are available: printed orderly per package install. To get synchronized output with colors, use ``make -j SPACK_COLOR=always --output-sync=recurse``. -The following advanced example shows how generated targets can be used in a -``Makefile``: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Specifying dependencies on generated ``make`` targets +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +An interesting question is how to include generated ``Makefile``\s in your own +``Makefile``\s. This comes up when you want to install an environment that provides +executables required in a command for a make target of your own. + +The example below shows how to accomplish this: the ``env`` target specifies +the generated ``spack/env`` target as a prerequisite, meaning that the environment +gets installed and is available for use in the ``env`` target. .. code:: Makefile @@ -1036,11 +1044,10 @@ The following advanced example shows how generated targets can be used in a include env.mk endif -When ``make`` is invoked, it first "remakes" the missing include ``env.mk`` -from its rule, which triggers concretization. When done, the generated target -``spack/env`` is available. In the above example, the ``env`` target uses this generated -target as a prerequisite, meaning that it can make use of the installed packages in -its commands. +This works as follows: when ``make`` is invoked, it first "remakes" the missing +include ``env.mk`` as there is a target for it. This triggers concretization of +the environment and makes spack output ``env.mk``. At that point the +generated target ``spack/env`` becomes available through ``include env.mk``. As it is typically undesirable to remake ``env.mk`` as part of ``make clean``, the include is conditional. @@ -1051,3 +1058,24 @@ the include is conditional. the ``--make-target-prefix`` flag and use the non-phony target ``/env`` as prerequisite, instead of the phony target ``/all``. + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Building a subset of the environment +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The generated ``Makefile``\s contain install targets for each spec. Given the hash +of a particular spec, you can use the ``.install/`` target to install the +spec with its dependencies. There is also ``.install-deps/`` to *only* install +its dependencies. This can be useful when certain flags should only apply to +dependencies. Below we show a use case where a spec is installed with verbose +output (``spack install --verbose``) while its dependencies are installed silently: + +.. code:: console + + $ spack env depfile -o Makefile --make-target-prefix my_env + + # Install dependencies in parallel, only show a log on error. + $ make -j16 my_env/.install-deps/ SPACK_INSTALL_FLAGS=--show-log-on-error + + # Install the root spec with verbose output. + $ make -j16 my_env/.install/ SPACK_INSTALL_FLAGS=--verbose \ No newline at end of file From b2d7782b004a9827c4487fbea9f5ac5c7548f714 Mon Sep 17 00:00:00 2001 From: Michael Kuhn Date: Sat, 15 Oct 2022 06:34:17 +0200 Subject: [PATCH 052/442] rocksdb: add 7.7.3 (#33341) --- var/spack/repos/builtin/packages/rocksdb/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/rocksdb/package.py b/var/spack/repos/builtin/packages/rocksdb/package.py index b6046d28062..c005d57b602 100644 --- a/var/spack/repos/builtin/packages/rocksdb/package.py +++ b/var/spack/repos/builtin/packages/rocksdb/package.py @@ -14,6 +14,7 @@ class Rocksdb(MakefilePackage): git = "https://github.com/facebook/rocksdb.git" version("master", git=git, branch="master", submodules=True) + version("7.7.3", sha256="b8ac9784a342b2e314c821f6d701148912215666ac5e9bdbccd93cf3767cb611") version("7.2.2", sha256="c4ea6bd2e3ffe3f0f8921c699234d59108c9122d61b0ba2aa78358642a7b614e") version("6.20.3", sha256="c6502c7aae641b7e20fafa6c2b92273d935d2b7b2707135ebd9a67b092169dca") version("6.19.3", sha256="5c19ffefea2bbe4c275d0c60194220865f508f371c64f42e802b4a85f065af5b") From 898c0b45fbd8798044d21acc3d3f0462230f451f Mon Sep 17 00:00:00 2001 From: iarspider Date: Sat, 15 Oct 2022 17:34:30 +0200 Subject: [PATCH 053/442] Add checksum for py-seaborn 0.12.0 (#33145) * Add checksum for py-seaborn 0.12.0 * Update package.py * Update package.py * [@spackbot] updating style on behalf of iarspider * Update package.py Co-authored-by: iarspider --- .../builtin/packages/py-seaborn/package.py | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/var/spack/repos/builtin/packages/py-seaborn/package.py b/var/spack/repos/builtin/packages/py-seaborn/package.py index 4d96e464a04..81ff8bf858d 100644 --- a/var/spack/repos/builtin/packages/py-seaborn/package.py +++ b/var/spack/repos/builtin/packages/py-seaborn/package.py @@ -17,26 +17,40 @@ class PySeaborn(PythonPackage): homepage = "https://seaborn.pydata.org/" pypi = "seaborn/seaborn-0.7.1.tar.gz" + version("0.12.0", sha256="893f17292d8baca616c1578ddb58eb25c72d622f54fc5ee329c8207dc9b57b23") version("0.11.2", sha256="cf45e9286d40826864be0e3c066f98536982baf701a7caa386511792d61ff4f6") version("0.11.1", sha256="44e78eaed937c5a87fc7a892c329a7cc091060b67ebd1d0d306b446a74ba01ad") version("0.9.0", sha256="76c83f794ca320fb6b23a7c6192d5e185a5fcf4758966a0c0a54baee46d41e2f") version("0.7.1", sha256="fa274344b1ee72f723bab751c40a5c671801d47a29ee9b5e69fcf63a18ce5c5d") - depends_on("python@3.6:", when="@0.10:", type="build") - depends_on("py-setuptools", type="build") + variant("stats", default=False, description="Optional statistical dependencies", when="@0.12:") + depends_on("python@3.6:", when="@0.10:", type="build") + depends_on("python@3.7:", when="@0.12:", type="build") + depends_on("py-setuptools", when="@:0.11.2", type="build") + depends_on("py-flit-core@3.2:3", when="@0.12.0:", type="build") + + depends_on("py-numpy@1.17:", when="@0.12:", type=("build", "run")) depends_on("py-numpy@1.15:", when="@0.11:", type=("build", "run")) depends_on("py-numpy@1.9.3:", when="@0.9:", type=("build", "run")) depends_on("py-numpy", type=("build", "run")) - depends_on("py-scipy@1:", when="@0.11:", type=("build", "run")) - depends_on("py-scipy@1.0.1:", when="@0.10:", type=("build", "run")) - depends_on("py-scipy@0.14:", when="@0.9.0:", type=("build", "run")) - depends_on("py-scipy", type=("build", "run")) + depends_on("py-pandas@0.25:", when="@0.12:", type=("build", "run")) depends_on("py-pandas@0.23:", when="@0.11:", type=("build", "run")) depends_on("py-pandas@0.22:", when="@0.10:", type=("build", "run")) depends_on("py-pandas@0.15.2:", when="@0.9:", type=("build", "run")) depends_on("py-pandas", type=("build", "run")) + depends_on("py-matplotlib@3.1:", when="@0.12:", type=("build", "run")) depends_on("py-matplotlib@2.2:", when="@0.11:", type=("build", "run")) depends_on("py-matplotlib@2.1.2:", when="@0.10:", type=("build", "run")) depends_on("py-matplotlib@1.4.3:", when="@0.9:", type=("build", "run")) depends_on("py-matplotlib", type=("build", "run")) + + depends_on("py-scipy@1:", when="@0.12: +stats", type=("build", "run")) + depends_on("py-scipy@1:", when="@0.11", type=("build", "run")) + depends_on("py-scipy@1.0.1:", when="@0.10:0.11", type=("build", "run")) + depends_on("py-scipy@0.14:", when="@0.9.0:0.11", type=("build", "run")) + depends_on("py-scipy", when="@:0.11", type=("build", "run")) + + depends_on("py-statsmodels@0.10:", when="@0.12: +stats", type=("build", "run")) + + depends_on("py-typing-extensions", when="@0.12: ^python@:3.7", type=("build", "run")) From 10491e98a876df986ce9ee78902c440fe4a8337d Mon Sep 17 00:00:00 2001 From: Jonathon Anderson <17242663+blue42u@users.noreply.github.com> Date: Sat, 15 Oct 2022 12:29:53 -0500 Subject: [PATCH 054/442] CI: allow multiple matches to combine tags (#32290) Currently "spack ci generate" chooses the first matching entry in gitlab-ci:mappings to fill attributes for a generated build-job, requiring that the entire configuration matrix is listed out explicitly. This unfortunately causes significant problems in environments with large configuration spaces, for example the environment in #31598 (spack.yaml) supports 5 operating systems, 3 architectures and 130 packages with explicit size requirements, resulting in 1300 lines of configuration YAML. This patch adds a configuraiton option to the gitlab-ci schema called "match_behavior"; when it is set to "merge", all matching entries are applied in order to the final build-job, allowing a few entries to cover an entire matrix of configurations. The default for "match_behavior" is "first", which behaves as before this commit (only the runner attributes of the first match are used). In addition, match entries may now include a "remove-attributes" configuration, which allows matches to remove tags that have been aggregated by prior matches. This only makes sense to use with "match_behavior:merge". You can combine "runner-attributes" with "remove-attributes" to effectively override prior tags. --- lib/spack/spack/ci.py | 24 +++++++++--- lib/spack/spack/schema/gitlab_ci.py | 11 ++++++ lib/spack/spack/test/cmd/ci.py | 37 +++++++++++++++---- .../stacks/aws-ahug-aarch64/spack.yaml | 1 + .../stacks/aws-ahug/spack.yaml | 1 + .../stacks/aws-isc-aarch64/spack.yaml | 1 + .../cloud_pipelines/stacks/aws-isc/spack.yaml | 1 + .../stacks/build_systems/spack.yaml | 1 + .../stacks/data-vis-sdk/spack.yaml | 1 + .../cloud_pipelines/stacks/e4s-mac/spack.yaml | 1 + .../stacks/e4s-on-power/spack.yaml | 1 + .../stacks/e4s-oneapi/spack.yaml | 1 + .../cloud_pipelines/stacks/e4s/spack.yaml | 1 + .../cloud_pipelines/stacks/ml-cpu/spack.yaml | 1 + .../cloud_pipelines/stacks/ml-cuda/spack.yaml | 1 + .../cloud_pipelines/stacks/ml-rocm/spack.yaml | 1 + .../stacks/radiuss-aws-aarch64/spack.yaml | 1 + .../stacks/radiuss-aws/spack.yaml | 1 + .../cloud_pipelines/stacks/radiuss/spack.yaml | 1 + .../stacks/tutorial/spack.yaml | 1 + 20 files changed, 76 insertions(+), 13 deletions(-) diff --git a/lib/spack/spack/ci.py b/lib/spack/spack/ci.py index 33724e7ac8d..c54596fea6c 100644 --- a/lib/spack/spack/ci.py +++ b/lib/spack/spack/ci.py @@ -397,6 +397,14 @@ def _spec_matches(spec, match_string): return spec.satisfies(match_string) +def _remove_attributes(src_dict, dest_dict): + if "tags" in src_dict and "tags" in dest_dict: + # For 'tags', we remove any tags that are listed for removal + for tag in src_dict["tags"]: + while tag in dest_dict["tags"]: + dest_dict["tags"].remove(tag) + + def _copy_attributes(attrs_list, src_dict, dest_dict): for runner_attr in attrs_list: if runner_attr in src_dict: @@ -430,19 +438,23 @@ def _find_matching_config(spec, gitlab_ci): _copy_attributes(overridable_attrs, gitlab_ci, runner_attributes) - ci_mappings = gitlab_ci["mappings"] - for ci_mapping in ci_mappings: + matched = False + only_first = gitlab_ci.get("match_behavior", "first") == "first" + for ci_mapping in gitlab_ci["mappings"]: for match_string in ci_mapping["match"]: if _spec_matches(spec, match_string): + matched = True + if "remove-attributes" in ci_mapping: + _remove_attributes(ci_mapping["remove-attributes"], runner_attributes) if "runner-attributes" in ci_mapping: _copy_attributes( overridable_attrs, ci_mapping["runner-attributes"], runner_attributes ) - return runner_attributes - else: - return None + break + if matched and only_first: + break - return runner_attributes + return runner_attributes if matched else None def _pkg_name_from_spec_label(spec_label): diff --git a/lib/spack/spack/schema/gitlab_ci.py b/lib/spack/spack/schema/gitlab_ci.py index d9da5c6ce7f..7c0604aaeea 100644 --- a/lib/spack/spack/schema/gitlab_ci.py +++ b/lib/spack/spack/schema/gitlab_ci.py @@ -52,6 +52,15 @@ "properties": runner_attributes_schema_items, } +remove_attributes_schema = { + "type": "object", + "additionalProperties": False, + "required": ["tags"], + "properties": { + "tags": {"type": "array", "items": {"type": "string"}}, + }, +} + core_shared_properties = union_dicts( runner_attributes_schema_items, @@ -80,6 +89,7 @@ ], }, }, + "match_behavior": {"type": "string", "enum": ["first", "merge"], "default": "first"}, "mappings": { "type": "array", "items": { @@ -93,6 +103,7 @@ "type": "string", }, }, + "remove-attributes": remove_attributes_schema, "runner-attributes": runner_selector_schema, }, }, diff --git a/lib/spack/spack/test/cmd/ci.py b/lib/spack/spack/test/cmd/ci.py index 37189af73ef..dff8484199a 100644 --- a/lib/spack/spack/test/cmd/ci.py +++ b/lib/spack/spack/test/cmd/ci.py @@ -1358,8 +1358,15 @@ def failing_access(*args, **kwargs): assert expect_msg in std_out +@pytest.mark.parametrize("match_behavior", ["first", "merge"]) def test_ci_generate_override_runner_attrs( - tmpdir, mutable_mock_env_path, install_mockery, mock_packages, monkeypatch, ci_base_environment + tmpdir, + mutable_mock_env_path, + install_mockery, + mock_packages, + monkeypatch, + ci_base_environment, + match_behavior, ): """Test that we get the behavior we want with respect to the provision of runner attributes like tags, variables, and scripts, both when we @@ -1378,6 +1385,7 @@ def test_ci_generate_override_runner_attrs( gitlab-ci: tags: - toplevel + - toplevel2 variables: ONE: toplevelvarone TWO: toplevelvartwo @@ -1388,6 +1396,7 @@ def test_ci_generate_override_runner_attrs( - main step after_script: - post step one + match_behavior: {0} mappings: - match: - flatten-deps @@ -1400,10 +1409,12 @@ def test_ci_generate_override_runner_attrs( - dependency-install - match: - a + remove-attributes: + tags: + - toplevel2 runner-attributes: tags: - specific-a - - toplevel variables: ONE: specificvarone TWO: specificvartwo @@ -1413,10 +1424,17 @@ def test_ci_generate_override_runner_attrs( - custom main step after_script: - custom post step one + - match: + - a + runner-attributes: + tags: + - specific-a-2 service-job-attributes: image: donotcare tags: [donotcare] -""" +""".format( + match_behavior + ) ) with tmpdir.as_cwd(): @@ -1449,9 +1467,12 @@ def test_ci_generate_override_runner_attrs( assert the_elt["variables"]["ONE"] == "specificvarone" assert the_elt["variables"]["TWO"] == "specificvartwo" assert "THREE" not in the_elt["variables"] - assert len(the_elt["tags"]) == 2 + assert len(the_elt["tags"]) == (2 if match_behavior == "first" else 3) assert "specific-a" in the_elt["tags"] + if match_behavior == "merge": + assert "specific-a-2" in the_elt["tags"] assert "toplevel" in the_elt["tags"] + assert "toplevel2" not in the_elt["tags"] assert len(the_elt["before_script"]) == 1 assert the_elt["before_script"][0] == "custom pre step one" assert len(the_elt["script"]) == 1 @@ -1466,8 +1487,9 @@ def test_ci_generate_override_runner_attrs( assert the_elt["variables"]["ONE"] == "toplevelvarone" assert the_elt["variables"]["TWO"] == "toplevelvartwo" assert "THREE" not in the_elt["variables"] - assert len(the_elt["tags"]) == 1 - assert the_elt["tags"][0] == "toplevel" + assert len(the_elt["tags"]) == 2 + assert "toplevel" in the_elt["tags"] + assert "toplevel2" in the_elt["tags"] assert len(the_elt["before_script"]) == 2 assert the_elt["before_script"][0] == "pre step one" assert the_elt["before_script"][1] == "pre step two" @@ -1484,9 +1506,10 @@ def test_ci_generate_override_runner_attrs( assert the_elt["variables"]["ONE"] == "toplevelvarone" assert the_elt["variables"]["TWO"] == "toplevelvartwo" assert the_elt["variables"]["THREE"] == "specificvarthree" - assert len(the_elt["tags"]) == 2 + assert len(the_elt["tags"]) == 3 assert "specific-one" in the_elt["tags"] assert "toplevel" in the_elt["tags"] + assert "toplevel2" in the_elt["tags"] assert len(the_elt["before_script"]) == 2 assert the_elt["before_script"][0] == "pre step one" assert the_elt["before_script"][1] == "pre step two" diff --git a/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml index 67ac499003e..89337ece10c 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml @@ -252,6 +252,7 @@ spack: - spack -d ci rebuild > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) image: { "name": "ghcr.io/spack/e4s-amazonlinux-2:v2022-03-21", "entrypoint": [""] } + match_behavior: first mappings: - match: - llvm diff --git a/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml index f81eb0383e9..c0cdef4448d 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml @@ -253,6 +253,7 @@ spack: - spack -d ci rebuild > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) image: { "name": "ghcr.io/spack/e4s-amazonlinux-2:v2022-03-21", "entrypoint": [""] } + match_behavior: first mappings: - match: - llvm diff --git a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml index 248d49fd40c..0e575647fc5 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml @@ -159,6 +159,7 @@ spack: - spack -d ci rebuild > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) image: { "name": "ghcr.io/spack/e4s-amazonlinux-2:v2022-03-21", "entrypoint": [""] } + match_behavior: first mappings: - match: - llvm diff --git a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml index 27de37b1f59..4c209022af9 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml @@ -171,6 +171,7 @@ spack: - spack -d ci rebuild > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) image: { "name": "ghcr.io/spack/e4s-amazonlinux-2:v2022-03-21", "entrypoint": [""] } + match_behavior: first mappings: - match: - llvm diff --git a/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml index 700d32add8e..eb60dd85fe1 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml @@ -45,6 +45,7 @@ spack: name: "ghcr.io/spack/e4s-ubuntu-18.04:v2021-10-18" entrypoint: [ "" ] + match_behavior: first mappings: - match: - cmake diff --git a/share/spack/gitlab/cloud_pipelines/stacks/data-vis-sdk/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/data-vis-sdk/spack.yaml index ae9025e366d..3f5a37f8875 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/data-vis-sdk/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/data-vis-sdk/spack.yaml @@ -55,6 +55,7 @@ spack: - if [[ -r /mnt/key/intermediate_ci_signing_key.gpg ]]; then spack gpg trust /mnt/key/intermediate_ci_signing_key.gpg; fi - if [[ -r /mnt/key/spack_public_key.gpg ]]; then spack gpg trust /mnt/key/spack_public_key.gpg; fi - spack -d ci rebuild + match_behavior: first mappings: - match: - llvm diff --git a/share/spack/gitlab/cloud_pipelines/stacks/e4s-mac/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/e4s-mac/spack.yaml index 34517c1fa92..ed49d553b25 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/e4s-mac/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/e4s-mac/spack.yaml @@ -51,6 +51,7 @@ spack: - mkdir -p ${SPACK_ARTIFACTS_ROOT}/user_data - spack -d ci rebuild > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) + match_behavior: first mappings: - match: ['os=monterey'] runner-attributes: diff --git a/share/spack/gitlab/cloud_pipelines/stacks/e4s-on-power/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/e4s-on-power/spack.yaml index 24a4879277c..b1a30701df8 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/e4s-on-power/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/e4s-on-power/spack.yaml @@ -221,6 +221,7 @@ spack: - spack config add "config:install_tree:projections:${SPACK_JOB_SPEC_PKG_NAME}:'morepadding/{architecture}/{compiler.name}-{compiler.version}/{name}-{version}-{hash}'" - spack -d ci rebuild + match_behavior: first mappings: - match: - cuda diff --git a/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml index 44923801260..ce8441a5d87 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml @@ -282,6 +282,7 @@ spack: image: ecpe4s/ubuntu20.04-runner-x86_64-oneapi:2022-07-01 + match_behavior: first mappings: - match: - hipblas diff --git a/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml index 853e293e6c6..6158234a8ab 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml @@ -261,6 +261,7 @@ spack: broken-tests-packages: - gptune + match_behavior: first mappings: - match: - hipblas diff --git a/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml index e6b49b9f41c..f389a0d14f0 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml @@ -97,6 +97,7 @@ spack: - if [[ -r /mnt/key/spack_public_key.gpg ]]; then spack gpg trust /mnt/key/spack_public_key.gpg; fi - spack -d ci rebuild > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) + match_behavior: first mappings: - match: - llvm diff --git a/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml index eb37168665f..a65c68db095 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml @@ -100,6 +100,7 @@ spack: - if [[ -r /mnt/key/spack_public_key.gpg ]]; then spack gpg trust /mnt/key/spack_public_key.gpg; fi - spack -d ci rebuild > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) + match_behavior: first mappings: - match: - llvm diff --git a/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml index c437b170e4b..d369924b8bf 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml @@ -103,6 +103,7 @@ spack: - if [[ -r /mnt/key/spack_public_key.gpg ]]; then spack gpg trust /mnt/key/spack_public_key.gpg; fi - spack -d ci rebuild > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) + match_behavior: first mappings: - match: - llvm diff --git a/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws-aarch64/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws-aarch64/spack.yaml index 4d18961d4b3..0e22a2d5666 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws-aarch64/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws-aarch64/spack.yaml @@ -67,6 +67,7 @@ spack: - spack -d ci rebuild > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) image: { "name": "ghcr.io/spack/e4s-amazonlinux-2:v2022-03-21", "entrypoint": [""] } + match_behavior: first mappings: - match: - llvm diff --git a/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws/spack.yaml index c6c895bd365..9c1347ac259 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws/spack.yaml @@ -72,6 +72,7 @@ spack: - spack -d ci rebuild > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) image: { "name": "ghcr.io/spack/e4s-amazonlinux-2:v2022-03-21", "entrypoint": [""] } + match_behavior: first mappings: - match: - llvm diff --git a/share/spack/gitlab/cloud_pipelines/stacks/radiuss/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/radiuss/spack.yaml index ebb15eb7ca0..b43c4ebdcfa 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/radiuss/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/radiuss/spack.yaml @@ -72,6 +72,7 @@ spack: - if [[ -r /mnt/key/intermediate_ci_signing_key.gpg ]]; then spack gpg trust /mnt/key/intermediate_ci_signing_key.gpg; fi - if [[ -r /mnt/key/spack_public_key.gpg ]]; then spack gpg trust /mnt/key/spack_public_key.gpg; fi - spack -d ci rebuild + match_behavior: first mappings: - match: - lbann diff --git a/share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml index 504b4209d27..dc91bf32082 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml @@ -74,6 +74,7 @@ spack: - spack -d ci rebuild image: { "name": "ghcr.io/spack/tutorial-ubuntu-18.04:v2021-11-02", "entrypoint": [""] } + match_behavior: first mappings: - match: - cmake From 496f4193a6083956089d6d7f5f804c15012b3227 Mon Sep 17 00:00:00 2001 From: "Adam J. Stewart" Date: Sun, 16 Oct 2022 04:53:54 -0500 Subject: [PATCH 055/442] meson: update OneAPI compiler support patch (#33293) --- .../repos/builtin/packages/meson/oneapi.patch | 158 ++++++++++++++++++ .../repos/builtin/packages/meson/package.py | 11 +- 2 files changed, 163 insertions(+), 6 deletions(-) create mode 100644 var/spack/repos/builtin/packages/meson/oneapi.patch diff --git a/var/spack/repos/builtin/packages/meson/oneapi.patch b/var/spack/repos/builtin/packages/meson/oneapi.patch new file mode 100644 index 00000000000..e5996261db7 --- /dev/null +++ b/var/spack/repos/builtin/packages/meson/oneapi.patch @@ -0,0 +1,158 @@ +diff --git a/docs/markdown/Reference-tables.md b/docs/markdown/Reference-tables.md +index 60303dad6..421b33c07 100644 +--- a/docs/markdown/Reference-tables.md ++++ b/docs/markdown/Reference-tables.md +@@ -20,6 +20,7 @@ These are return values of the `get_id` (Compiler family) and + | gcc | The GNU Compiler Collection | gcc | + | intel | Intel compiler (Linux and Mac) | gcc | + | intel-cl | Intel compiler (Windows) | msvc | ++| intel-llvm| Intel oneAPI LLVM-based compiler | | + | lcc | Elbrus C/C++/Fortran Compiler | | + | llvm | LLVM-based compiler (Swift, D) | | + | mono | Xamarin C# compiler | | +diff --git a/docs/markdown/snippets/oneapi_compilers.md b/docs/markdown/snippets/oneapi_compilers.md +new file mode 100644 +index 000000000..a982da22a +--- /dev/null ++++ b/docs/markdown/snippets/oneapi_compilers.md +@@ -0,0 +1,8 @@ ++## Basic support for oneAPI compilers on Linux ++ ++To use: ++ ++``` ++source /opt/intel/oneapi/setvars.sh ++CC=icx CXX=icpx FC=ifx meson setup builddir ++``` +diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py +index b1b4a7c92..9490ee688 100644 +--- a/mesonbuild/compilers/c.py ++++ b/mesonbuild/compilers/c.py +@@ -406,6 +406,13 @@ class IntelCCompiler(IntelGnuLikeCompiler, CCompiler): + return args + + ++class IntelLLVMCCompiler(ClangCCompiler): ++ ++ ++ id = 'intel-llvm' ++ ++ ++ + class VisualStudioLikeCCompilerMixin(CompilerMixinBase): + + """Shared methods that apply to MSVC-like C compilers.""" +diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py +index ac65df9a1..3d728f169 100644 +--- a/mesonbuild/compilers/cpp.py ++++ b/mesonbuild/compilers/cpp.py +@@ -153,7 +153,7 @@ class CPPCompiler(CLikeCompiler, Compiler): + } + + # Currently, remapping is only supported for Clang, Elbrus and GCC +- assert self.id in frozenset(['clang', 'lcc', 'gcc', 'emscripten', 'armltdclang']) ++ assert self.id in frozenset(['clang', 'lcc', 'gcc', 'emscripten', 'armltdclang', 'intel-llvm']) + + if cpp_std not in CPP_FALLBACKS: + # 'c++03' and 'c++98' don't have fallback types +@@ -593,6 +593,13 @@ class IntelCPPCompiler(IntelGnuLikeCompiler, CPPCompiler): + return [] + + ++class IntelLLVMCPPCompiler(ClangCPPCompiler): ++ ++ ++ id = 'intel-llvm' ++ ++ ++ + class VisualStudioLikeCPPCompilerMixin(CompilerMixinBase): + + """Mixin for C++ specific method overrides in MSVC-like compilers.""" +diff --git a/mesonbuild/compilers/detect.py b/mesonbuild/compilers/detect.py +index f4afa777d..42a4b18a5 100644 +--- a/mesonbuild/compilers/detect.py ++++ b/mesonbuild/compilers/detect.py +@@ -62,6 +62,7 @@ from .c import ( + EmscriptenCCompiler, + IntelCCompiler, + IntelClCCompiler, ++ IntelLLVMCCompiler, + NvidiaHPC_CCompiler, + PGICCompiler, + CcrxCCompiler, +@@ -83,6 +84,7 @@ from .cpp import ( + EmscriptenCPPCompiler, + IntelCPPCompiler, + IntelClCPPCompiler, ++ IntelLLVMCPPCompiler, + NvidiaHPC_CPPCompiler, + PGICPPCompiler, + CcrxCPPCompiler, +@@ -106,6 +108,7 @@ from .fortran import ( + FlangFortranCompiler, + IntelFortranCompiler, + IntelClFortranCompiler, ++ IntelLLVMFortranCompiler, + NAGFortranCompiler, + Open64FortranCompiler, + PathScaleFortranCompiler, +@@ -180,11 +183,11 @@ else: + defaults['objc'] = ['clang'] + defaults['objcpp'] = ['clang++'] + else: +- defaults['c'] = ['cc', 'gcc', 'clang', 'nvc', 'pgcc', 'icc'] +- defaults['cpp'] = ['c++', 'g++', 'clang++', 'nvc++', 'pgc++', 'icpc'] ++ defaults['c'] = ['cc', 'gcc', 'clang', 'nvc', 'pgcc', 'icc', 'icx'] ++ defaults['cpp'] = ['c++', 'g++', 'clang++', 'nvc++', 'pgc++', 'icpc', 'icpx'] + defaults['objc'] = ['cc', 'gcc', 'clang'] + defaults['objcpp'] = ['c++', 'g++', 'clang++'] +- defaults['fortran'] = ['gfortran', 'flang', 'nvfortran', 'pgfortran', 'ifort', 'g95'] ++ defaults['fortran'] = ['gfortran', 'flang', 'nvfortran', 'pgfortran', 'ifort', 'ifx', 'g95'] + defaults['cs'] = ['mcs', 'csc'] + defaults['d'] = ['ldc2', 'ldc', 'gdc', 'dmd'] + defaults['java'] = ['javac'] +@@ -617,6 +620,12 @@ def _detect_c_or_cpp_compiler(env: 'Environment', lang: str, for_machine: Machin + return cls( + ccache + compiler, version, for_machine, is_cross, info, + exe_wrap, full_version=full_version, linker=l) ++ if 'Intel(R) oneAPI' in out: ++ cls = IntelLLVMCCompiler if lang == 'c' else IntelLLVMCPPCompiler ++ l = guess_nix_linker(env, compiler, cls, version, for_machine) ++ return cls( ++ ccache + compiler, version, for_machine, is_cross, info, ++ exe_wrap, full_version=full_version, linker=l) + if 'TMS320C2000 C/C++' in out or 'MSP430 C/C++' in out or 'TI ARM C/C++ Compiler' in out: + lnk: T.Union[T.Type[C2000DynamicLinker], T.Type[TIDynamicLinker]] + if 'TMS320C2000 C/C++' in out: +@@ -789,6 +798,13 @@ def detect_fortran_compiler(env: 'Environment', for_machine: MachineChoice) -> C + compiler, version, for_machine, is_cross, info, + exe_wrap, full_version=full_version, linker=linker) + ++ if 'ifx (IFORT)' in out: ++ cls = IntelLLVMFortranCompiler ++ linker = guess_nix_linker(env, compiler, cls, version, for_machine) ++ return cls( ++ compiler, version, for_machine, is_cross, info, ++ exe_wrap, full_version=full_version, linker=linker) ++ + if 'PathScale EKOPath(tm)' in err: + return PathScaleFortranCompiler( + compiler, version, for_machine, is_cross, info, +diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py +index 0a0c3ec86..e7154fe87 100644 +--- a/mesonbuild/compilers/fortran.py ++++ b/mesonbuild/compilers/fortran.py +@@ -352,6 +352,12 @@ class IntelFortranCompiler(IntelGnuLikeCompiler, FortranCompiler): + return ['-gen-dep=' + outtarget, '-gen-depformat=make'] + + ++class IntelLLVMFortranCompiler(IntelFortranCompiler): ++ ++ ++ id = 'intel-llvm' ++ ++ + class IntelClFortranCompiler(IntelVisualStudioLikeCompiler, FortranCompiler): + + file_suffixes = ('f90', 'f', 'for', 'ftn', 'fpp', ) diff --git a/var/spack/repos/builtin/packages/meson/package.py b/var/spack/repos/builtin/packages/meson/package.py index 05433d59ddf..ecec5026510 100644 --- a/var/spack/repos/builtin/packages/meson/package.py +++ b/var/spack/repos/builtin/packages/meson/package.py @@ -67,12 +67,11 @@ class Meson(PythonPackage): patch("rpath-0.54.patch", when="@0.54:0.55") patch("rpath-0.56.patch", when="@0.56:0.57") patch("rpath-0.58.patch", when="@0.58:") - # Help meson recognize Intel OneAPI compilers - patch( - "https://patch-diff.githubusercontent.com/raw/mesonbuild/meson/pull/9850.patch?full_index=1", - sha256="9c874726ce0a06922580d3e3d6adbe74e5144b3a661ef1059f32c9c1bc478b65", - when="@0.60.0:", - ) + + # Intel OneAPI compiler support + # https://github.com/mesonbuild/meson/pull/10909 + # https://github.com/mesonbuild/meson/pull/9850 + patch("oneapi.patch", when="@0.62: %oneapi") executables = ["^meson$"] From f7f11fc88117703f287134bd63a5c12bc47bff1d Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Sun, 16 Oct 2022 13:09:56 +0200 Subject: [PATCH 056/442] py-tensorflow: fix zlib (#33349) * py-tensorflow: fix zlib * [@spackbot] updating style on behalf of haampie Co-authored-by: haampie --- .../builtin/packages/py-tensorflow-metadata/package.py | 7 +++++++ .../repos/builtin/packages/py-tensorflow/package.py | 10 +++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/py-tensorflow-metadata/package.py b/var/spack/repos/builtin/packages/py-tensorflow-metadata/package.py index 363579b7a5d..07e09d4bf44 100644 --- a/var/spack/repos/builtin/packages/py-tensorflow-metadata/package.py +++ b/var/spack/repos/builtin/packages/py-tensorflow-metadata/package.py @@ -22,6 +22,13 @@ class PyTensorflowMetadata(PythonPackage): version("1.10.0", sha256="e7aa81aa01433e2a75c11425affd55125b64f384baf96b71eeb3a88dca8cf2ae") version("1.5.0", sha256="f0ec8aaf62fd772ef908efe4ee5ea3bc0d67dcbf10ae118415b7b206a1d61745") + # Fix non-existing zlib URL + patch( + "https://github.com/tensorflow/metadata/commit/8df679e782f5bf2d163d63e550d8752c3812d566.patch?full_index=1", + sha256="a6b294d5e6099979192fcdb4d5b7b0388dc30b48671944d22e51a9e6bd5e1490", + when="@1.10.0", + ) + depends_on("bazel@0.24.1:", type="build") depends_on("python@3.7:3", type=("build", "run")) depends_on("py-setuptools", type="build") diff --git a/var/spack/repos/builtin/packages/py-tensorflow/package.py b/var/spack/repos/builtin/packages/py-tensorflow/package.py index 5c6b3dc1ac2..5c2bcb759a9 100644 --- a/var/spack/repos/builtin/packages/py-tensorflow/package.py +++ b/var/spack/repos/builtin/packages/py-tensorflow/package.py @@ -440,8 +440,16 @@ class PyTensorflow(Package, CudaPackage, ROCmPackage): conflicts("~rocm", when="@2.7.4-rocm-enhanced") conflicts("+rocm", when="@:2.7.4-a,2.7.4.0:") - # TODO: why is this needed? + # zlib is vendored and downloaded directly from zlib.org (or mirrors), but + # old downloads are removed from that site immediately after a new release. + # If the tf mirrors don't work, make sure the fallback is to something existing. patch("url-zlib.patch", when="@0.10.0") + # bump to zlib 1.2.13 + patch( + "https://github.com/tensorflow/tensorflow/commit/76b9fa22857148a562f3d9b5af6843402a93c15b.patch?full_index=1", + sha256="f9e26c544da729cfd376dbd3b096030e3777d3592459add1f3c78b1b9828d493", + when="@2.9:2.10.0", + ) # TODO: why is this needed? patch("crosstool.patch", when="@0.10.0+cuda") # Avoid build error: "no such package '@io_bazel_rules_docker..." From 23fe981c41e810acb214112645faf34cda1d2238 Mon Sep 17 00:00:00 2001 From: "Adam J. Stewart" Date: Sun, 16 Oct 2022 11:00:24 -0500 Subject: [PATCH 057/442] py-meson-python: add new versions (#33294) --- .../repos/builtin/packages/py-meson-python/package.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/py-meson-python/package.py b/var/spack/repos/builtin/packages/py-meson-python/package.py index 323a997074b..ba4f5e9df77 100644 --- a/var/spack/repos/builtin/packages/py-meson-python/package.py +++ b/var/spack/repos/builtin/packages/py-meson-python/package.py @@ -14,12 +14,21 @@ class PyMesonPython(PythonPackage): maintainers = ["eli-schwartz", "adamjstewart"] + version("0.10.0", sha256="08dd122c1074dbd5c55b53993a719cca73dd8216372c91217f7a550260f9e7e1") + version("0.9.0", sha256="6aa5a09ff5cce1c5308938ebbf3eab5529413c8677055ace1ac8c83d8a07b29d") + version("0.8.1", sha256="442f1fa4cf5db50eea61170a6059c10fafd70977f5dbdf3441c106cd23b05e4c") + version("0.8.0", sha256="b5c8a2727e6f6feaffc1db513244c9bdb5d0f689b45e24f4529b649b7710daf7") version("0.7.0", sha256="9fcfa350f44ca80dd4f5f9c3d251725434acf9a07d9618f382e6cc4629dcbe84") depends_on("python@3.7:", type=("build", "run")) + depends_on("meson@0.63:", when="@0.9:", type=("build", "run")) depends_on("meson@0.62:", type=("build", "run")) - depends_on("py-ninja", type=("build", "run")) depends_on("py-pyproject-metadata@0.5:", type=("build", "run")) depends_on("py-tomli@1:", type=("build", "run")) depends_on("py-typing-extensions@3.7.4:", when="^python@:3.7", type=("build", "run")) depends_on("py-colorama", when="platform=windows", type=("build", "run")) + + # https://github.com/FFY00/meson-python/pull/111 + conflicts("platform=darwin os=ventura", when="@:0.7") + conflicts("platform=darwin os=monterey", when="@:0.7") + conflicts("platform=darwin os=bigsur", when="@:0.7") From 0c505e459b8e02f7fc229a8e60dd8e9eeb563053 Mon Sep 17 00:00:00 2001 From: Miroslav Stoyanov <30537612+mkstoyanov@users.noreply.github.com> Date: Sun, 16 Oct 2022 12:17:44 -0400 Subject: [PATCH 058/442] tasmanian: disable openmp by default (#33345) --- var/spack/repos/builtin/packages/tasmanian/package.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/var/spack/repos/builtin/packages/tasmanian/package.py b/var/spack/repos/builtin/packages/tasmanian/package.py index 6296e59a08c..e2b4ab39736 100644 --- a/var/spack/repos/builtin/packages/tasmanian/package.py +++ b/var/spack/repos/builtin/packages/tasmanian/package.py @@ -44,8 +44,7 @@ class Tasmanian(CMakePackage, CudaPackage, ROCmPackage): variant("xsdkflags", default=False, description="enable XSDK defaults for Tasmanian") - variant("openmp", default=True, description="add OpenMP support to Tasmanian") - # tested with OpenMP 3.1 (clang4) through 4.0-4.5 (gcc 5 - 8) + variant("openmp", default=False, description="add OpenMP support to Tasmanian") variant("blas", default=False, description="add BLAS support to Tasmanian") From 7547f1c414812fdbb5e5ffffbb2f6910f4f06524 Mon Sep 17 00:00:00 2001 From: Hans Fangohr Date: Sun, 16 Oct 2022 18:19:01 +0200 Subject: [PATCH 059/442] octopus: upgrade to 12.1 (#33343) --- var/spack/repos/builtin/packages/octopus/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/octopus/package.py b/var/spack/repos/builtin/packages/octopus/package.py index 5ba38a4a400..3139eac3b59 100644 --- a/var/spack/repos/builtin/packages/octopus/package.py +++ b/var/spack/repos/builtin/packages/octopus/package.py @@ -20,6 +20,7 @@ class Octopus(Package, CudaPackage): maintainers = ["fangohr", "RemiLacroix-IDRIS"] + version("12.1", sha256="e2214e958f1e9631dbe6bf020c39f1fe4d71ab0b6118ea9bd8dc38f6d7a7959a") version("12.0", sha256="70beaf08573d394a766f10346a708219b355ad725642126065d12596afbc0dcc") version("11.4", sha256="73bb872bff8165ddd8efc5b891f767cb3fe575b5a4b518416c834450a4492da7") version("11.3", sha256="0c98417071b5e38ba6cbdd409adf917837c387a010e321c0a7f94d9bd9478930") From 25e4d482278d3fac6ef51098c6c564659b011851 Mon Sep 17 00:00:00 2001 From: "Adam J. Stewart" Date: Sun, 16 Oct 2022 15:45:07 -0500 Subject: [PATCH 060/442] py-sphinx: add v5.3 and v5.2 (#33356) --- var/spack/repos/builtin/packages/py-sphinx/package.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/var/spack/repos/builtin/packages/py-sphinx/package.py b/var/spack/repos/builtin/packages/py-sphinx/package.py index a5c99d50783..86de3285a1e 100644 --- a/var/spack/repos/builtin/packages/py-sphinx/package.py +++ b/var/spack/repos/builtin/packages/py-sphinx/package.py @@ -14,6 +14,10 @@ class PySphinx(PythonPackage): maintainers = ["adamjstewart"] + version("5.3.0", sha256="51026de0a9ff9fc13c05d74913ad66047e104f56a129ff73e174eb5c3ee794b5") + version("5.2.3", sha256="5b10cb1022dac8c035f75767799c39217a05fc0fe2d6fe5597560d38e44f0363") + version("5.2.2", sha256="7225c104dc06169eb73b061582c4bc84a9594042acae6c1582564de274b7df2f") + version("5.2.1", sha256="c009bb2e9ac5db487bcf53f015504005a330ff7c631bb6ab2604e0d65bae8b54") version("5.2.0", sha256="1790c2098937dcfa7871c9d102c24eccd4a8b883b67c5c1e26892fb52d102542") version("5.1.1", sha256="ba3224a4e206e1fbdecf98a4fae4992ef9b24b85ebf7b584bb340156eaf08d89") version("5.1.0", sha256="7893d10d9d852c16673f9b1b7e9eda1606b420b7810270294d6e4b44c0accacc") From 02fb32bc1eb72ea056b56832c4b06b0624cee9e0 Mon Sep 17 00:00:00 2001 From: "Adam J. Stewart" Date: Mon, 17 Oct 2022 02:17:10 -0500 Subject: [PATCH 061/442] py-setuptools: add v65.5.0 (#33353) --- var/spack/repos/builtin/packages/py-setuptools/package.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/var/spack/repos/builtin/packages/py-setuptools/package.py b/var/spack/repos/builtin/packages/py-setuptools/package.py index 53b1bc157a4..8bf9f71863b 100644 --- a/var/spack/repos/builtin/packages/py-setuptools/package.py +++ b/var/spack/repos/builtin/packages/py-setuptools/package.py @@ -16,6 +16,11 @@ class PySetuptools(Package): maintainers = ["adamjstewart"] + version( + "65.5.0", + sha256="f62ea9da9ed6289bfe868cd6845968a2c854d1427f8548d52cae02a42b4f0356", + expand=False, + ) version( "65.0.0", sha256="fe9a97f68b064a6ddd4bacfb0b4b93a4c65a556d97ce906255540439d0c35cef", From 1338dbca56a10344f11601f9429aff7e199e982e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mos=C3=A8=20Giordano?= Date: Mon, 17 Oct 2022 08:23:51 +0100 Subject: [PATCH 062/442] libblastrampoline: Add versions 5.1.1, 5.2.0 (#33352) --- var/spack/repos/builtin/packages/libblastrampoline/package.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/var/spack/repos/builtin/packages/libblastrampoline/package.py b/var/spack/repos/builtin/packages/libblastrampoline/package.py index b8638e54b86..54a59458d98 100644 --- a/var/spack/repos/builtin/packages/libblastrampoline/package.py +++ b/var/spack/repos/builtin/packages/libblastrampoline/package.py @@ -15,6 +15,8 @@ class Libblastrampoline(MakefilePackage): maintainers = ["haampie", "giordano"] + version("5.2.0", sha256="5af9ff9cec16087f57109082a362419fc49152034fa90772ebcabd882007fd95") + version("5.1.1", sha256="cb5515512f6653538ce74653e46ccfba58c87b7dcb79b9655f7c3655e65498f0") version("5.1.0", sha256="55ac0c8f9cb91b2ed2db014be8394c9dadf3b5f26bd8af6dca9d6f20ca72b8fd") version("5.0.2", sha256="2e96fa62957719351da3e4dff8cd0949449073708f5564dae0a224a556432356") version("5.0.1", sha256="1066b4d157276e41ca66ca94f0f8c2900c221b49da2df3c410e6f8bf1ce9b488") From 574ab3e40acc5334b0cf6734a2988a452b9e87d3 Mon Sep 17 00:00:00 2001 From: Diego Alvarez Date: Mon, 17 Oct 2022 04:35:45 -0300 Subject: [PATCH 063/442] nextflow: add v20.10.0 (#33354) --- var/spack/repos/builtin/packages/nextflow/package.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/var/spack/repos/builtin/packages/nextflow/package.py b/var/spack/repos/builtin/packages/nextflow/package.py index 855cb8d3e7b..1f73765830b 100644 --- a/var/spack/repos/builtin/packages/nextflow/package.py +++ b/var/spack/repos/builtin/packages/nextflow/package.py @@ -14,6 +14,11 @@ class Nextflow(Package): maintainers = ["dialvarezs"] + version( + "22.10.0", + sha256="6acea8bd21f7f66b1363eef900cd696d9523d2b9edb53327940f093189c1535e", + expand=False, + ) version( "22.04.4", sha256="e5ebf9942af4569db9199e8528016d9a52f73010ed476049774a76b201cd4b10", From 7993d10e5477716c0813e4a4a15cd7b41c6e85fe Mon Sep 17 00:00:00 2001 From: Wouter Deconinck Date: Mon, 17 Oct 2022 02:37:34 -0500 Subject: [PATCH 064/442] sdl2: add v2.0.22 and v2.24.1 (#33351) --- var/spack/repos/builtin/packages/sdl2/package.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/var/spack/repos/builtin/packages/sdl2/package.py b/var/spack/repos/builtin/packages/sdl2/package.py index 6f191fd28d2..459fdf178fa 100644 --- a/var/spack/repos/builtin/packages/sdl2/package.py +++ b/var/spack/repos/builtin/packages/sdl2/package.py @@ -13,7 +13,11 @@ class Sdl2(CMakePackage): homepage = "https://wiki.libsdl.org/FrontPage" url = "https://libsdl.org/release/SDL2-2.0.5.tar.gz" + git = "https://github.com/libsdl-org/SDL.git" + list_url = "https://github.com/libsdl-org/SDL.git" + version("2.24.1", sha256="bc121588b1105065598ce38078026a414c28ea95e66ed2adab4c44d80b309e1b") + version("2.0.22", sha256="fe7cbf3127882e3fc7259a75a0cb585620272c51745d3852ab9dd87960697f2e") version("2.0.14", sha256="d8215b571a581be1332d2106f8036fcb03d12a70bae01e20f424976d275432bc") version("2.0.5", sha256="442038cf55965969f2ff06d976031813de643af9c9edc9e331bd761c242e8785") From f3ebe237e5a8c3a23c3b698d5b1180ff36623614 Mon Sep 17 00:00:00 2001 From: Michael Kuhn Date: Mon, 17 Oct 2022 09:53:07 +0200 Subject: [PATCH 065/442] mariadb-c-client: add 3.3.2, 3.2.7, 3.1.18, 3.0.10 (#33335) --- var/spack/repos/builtin/packages/mariadb-c-client/package.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/var/spack/repos/builtin/packages/mariadb-c-client/package.py b/var/spack/repos/builtin/packages/mariadb-c-client/package.py index 0eafda8f268..fe30923df6b 100644 --- a/var/spack/repos/builtin/packages/mariadb-c-client/package.py +++ b/var/spack/repos/builtin/packages/mariadb-c-client/package.py @@ -22,12 +22,16 @@ class MariadbCClient(CMakePackage): list_url = "https://downloads.mariadb.com/Connectors/c/" list_depth = 1 + version("3.3.2", sha256="7e0722e07d30bb906fac9fe10fb582cde1e148e05a83d9ca7b6fcc884b68fbce") + version("3.2.7", sha256="9d7196248e6697c09c73e173fe9b282045f55ec9d7ae743c1ebad08b9ea56dda") version("3.2.6", sha256="9c22fff9d18db7ebdcb63979882fb6b68d2036cf2eb62f043eac922cd36bdb91") + version("3.1.18", sha256="b01ecacf7531c2f36d90708845488e66462bf63627c58cb5986bd1c0833e4d9c") version("3.1.13", sha256="0271a5edfd64b13bca5937267474e4747d832ec62e169fc2589d2ead63746875") version("3.1.9", sha256="108d99bf2add434dcb3bd9526ba1d89a2b9a943b62dcd9d0a41fcbef8ffbf2c7") version("3.1.6", sha256="d266bb67df83c088c4fb05392713d2504c67be620894cedaf758a9561c116720") version("3.1.5", sha256="a9de5fedd1a7805c86e23be49b9ceb79a86b090ad560d51495d7ba5952a9d9d5") version("3.1.4", sha256="7a1a72fee00e4c28060f96c3efbbf38aabcbbab17903e82fce85a85002565316") + version("3.0.10", sha256="bd9aa1f137ead3dc68ed3165adc53541712076d08949800b6ccebd33da6d0ae8") version("3.0.9", sha256="7277c0caba6f50b1d07e1d682baf0b962a63e2e6af9e00e09b8dcf36a7858641") version("3.0.8", sha256="2ca368fd79e87e80497a5c9fd18922d8316af8584d87cecb35bd5897cb1efd05") version("3.0.7", sha256="f63883c9360675d111646fba5c97feb0d08e0def5873dd189d78bafbb75fa004") From 9933a9046a659a82b4bbed175ec45eafeff6d788 Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Mon, 17 Oct 2022 12:39:16 +0200 Subject: [PATCH 066/442] py-tensorflow-hub: zlib, again. (#33359) --- ...VE-use-fossils-url-which-is-more-sta.patch | 29 +++++++++++++++++++ .../packages/py-tensorflow-hub/package.py | 7 ++--- 2 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 var/spack/repos/builtin/packages/py-tensorflow-hub/0001-zlib-bump-over-CVE-use-fossils-url-which-is-more-sta.patch diff --git a/var/spack/repos/builtin/packages/py-tensorflow-hub/0001-zlib-bump-over-CVE-use-fossils-url-which-is-more-sta.patch b/var/spack/repos/builtin/packages/py-tensorflow-hub/0001-zlib-bump-over-CVE-use-fossils-url-which-is-more-sta.patch new file mode 100644 index 00000000000..c552390eaae --- /dev/null +++ b/var/spack/repos/builtin/packages/py-tensorflow-hub/0001-zlib-bump-over-CVE-use-fossils-url-which-is-more-sta.patch @@ -0,0 +1,29 @@ +From e5a889202143ccc5a6d126197e86ee138307cbc4 Mon Sep 17 00:00:00 2001 +From: Harmen Stoppels +Date: Mon, 17 Oct 2022 09:52:27 +0200 +Subject: [PATCH] zlib: bump over CVE, use fossils url which is more stable + +--- + WORKSPACE | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/WORKSPACE b/WORKSPACE +index 495ed63..36d730b 100644 +--- a/WORKSPACE ++++ b/WORKSPACE +@@ -29,9 +29,9 @@ git_repository( + http_archive( + name = "zlib", + build_file = "@com_google_protobuf//:third_party/zlib.BUILD", +- sha256 = "c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1", +- strip_prefix = "zlib-1.2.11", +- urls = ["https://zlib.net/zlib-1.2.11.tar.gz"], ++ sha256 = "b3a24de97a8fdbc835b9833169501030b8977031bcb54b3b3ac13740f846ab30", ++ strip_prefix = "zlib-1.2.13", ++ urls = ["https://zlib.net/fossils/zlib-1.2.13.tar.gz"], + ) + + # Required by protobuf 3.8.0. +-- +2.37.0 + diff --git a/var/spack/repos/builtin/packages/py-tensorflow-hub/package.py b/var/spack/repos/builtin/packages/py-tensorflow-hub/package.py index 2ec9bc65196..58cf70414c4 100644 --- a/var/spack/repos/builtin/packages/py-tensorflow-hub/package.py +++ b/var/spack/repos/builtin/packages/py-tensorflow-hub/package.py @@ -30,11 +30,8 @@ class PyTensorflowHub(Package): depends_on("py-numpy@1.12.0:", type=("build", "run")) depends_on("py-protobuf@3.8.0:", type=("build", "run")) - patch( - "https://github.com/tensorflow/hub/commit/049192a7edd3e80eebf1735b93f57c7965381bdb.patch?full_index=1", - sha256="c8b59d17511a8ebd2a58717723b9b77514a12b43bb2e6acec6d0c1062df6e457", - when="@:0.12", - ) + # Deal with vendored zlib. + patch("0001-zlib-bump-over-CVE-use-fossils-url-which-is-more-sta.patch", when="@:0.12") def install(self, spec, prefix): tmp_path = tempfile.mkdtemp(prefix="spack") From 8dc2d37447fc35fbf6a8ae3e86982f885b93ba7c Mon Sep 17 00:00:00 2001 From: iarspider Date: Mon, 17 Oct 2022 13:19:40 +0200 Subject: [PATCH 067/442] Add checksum for py-sniffio 1.3.0 (#32975) --- var/spack/repos/builtin/packages/py-sniffio/package.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/var/spack/repos/builtin/packages/py-sniffio/package.py b/var/spack/repos/builtin/packages/py-sniffio/package.py index 19aab104d24..257c2366046 100644 --- a/var/spack/repos/builtin/packages/py-sniffio/package.py +++ b/var/spack/repos/builtin/packages/py-sniffio/package.py @@ -13,9 +13,11 @@ class PySniffio(PythonPackage): homepage = "https://github.com/python-trio/sniffio" pypi = "sniffio/sniffio-1.1.0.tar.gz" + version("1.3.0", sha256="e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101") version("1.2.0", sha256="c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de") version("1.1.0", sha256="8e3810100f69fe0edd463d02ad407112542a11ffdc29f67db2bf3771afb87a21") depends_on("python@3.5:", type=("build", "run")) + depends_on("python@3.7:", when="@1.3.0:", type=("build", "run")) depends_on("py-setuptools", type="build") depends_on("py-contextvars@2.1:", when="^python@:3.6", type=("build", "run")) From 84fbccd682438e2d0032c91a24a2245c6a28648b Mon Sep 17 00:00:00 2001 From: "Adam J. Stewart" Date: Mon, 17 Oct 2022 08:23:08 -0500 Subject: [PATCH 068/442] py-numpy: add v1.23.4 (#33260) --- var/spack/repos/builtin/packages/py-numpy/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/py-numpy/package.py b/var/spack/repos/builtin/packages/py-numpy/package.py index 840e05a9d67..708272744ea 100644 --- a/var/spack/repos/builtin/packages/py-numpy/package.py +++ b/var/spack/repos/builtin/packages/py-numpy/package.py @@ -23,6 +23,7 @@ class PyNumpy(PythonPackage): maintainers = ["adamjstewart", "rgommers"] version("main", branch="main") + version("1.23.4", sha256="ed2cc92af0efad20198638c69bb0fc2870a58dabfba6eb722c933b48556c686c") version("1.23.3", sha256="51bf49c0cd1d52be0a240aa66f3458afc4b95d8993d2d04f0d91fa60c10af6cd") version("1.23.2", sha256="b78d00e48261fbbd04aa0d7427cf78d18401ee0abd89c7559bbf422e5b1c7d01") version("1.23.1", sha256="d748ef349bfef2e1194b59da37ed5a29c19ea8d7e6342019921ba2ba4fd8b624") From f3523d8655d8307fb3761434a5bbeb77754b5cea Mon Sep 17 00:00:00 2001 From: iarspider Date: Mon, 17 Oct 2022 15:42:01 +0200 Subject: [PATCH 069/442] py-jupyterlab-pygments: install from wheel to avoid cyclic dependency (#33278) * py-jupyterlab-pygments: avoid cyclic dependency * Fix style * Update package.py * Update package.py * [@spackbot] updating style on behalf of iarspider * Update package.py * Flake-8 * fix Co-authored-by: iarspider --- .../py-jupyterlab-pygments/package.py | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/var/spack/repos/builtin/packages/py-jupyterlab-pygments/package.py b/var/spack/repos/builtin/packages/py-jupyterlab-pygments/package.py index 9335e2db485..5f5973273c6 100644 --- a/var/spack/repos/builtin/packages/py-jupyterlab-pygments/package.py +++ b/var/spack/repos/builtin/packages/py-jupyterlab-pygments/package.py @@ -11,14 +11,28 @@ class PyJupyterlabPygments(PythonPackage): """Pygments theme using JupyterLab CSS variables.""" homepage = "https://jupyter.org/" - pypi = "jupyterlab-pygments/jupyterlab_pygments-0.1.1.tar.gz" + url = "https://files.pythonhosted.org/packages/py2.py3/j/jupyterlab-pygments/jupyterlab_pygments-0.2.2-py2.py3-none-any.whl" + # We use wheels because in @0.2.2: there is a cyclic dependency between + # py-nbconvert and py-jupyter-server: + # py-nbconvert -> py-jupyterlab-pygments -> py-jupyterlab -> + # -> py-jupyter-server -> py-nbconvert + # Reported here: https://github.com/jupyterlab/jupyterlab_pygments/issues/23 - version("0.2.2", sha256="7405d7fde60819d905a9fa8ce89e4cd830e318cdad22a0030f7a901da705585d") - version("0.1.2", sha256="cfcda0873626150932f438eccf0f8bf22bfa92345b814890ab360d666b254146") - version("0.1.1", sha256="19a0ccde7daddec638363cd3d60b63a4f6544c9181d65253317b2fb492a797b9") + version( + "0.2.2", + sha256="2405800db07c9f770863bcf8049a529c3dd4d3e28536638bd7c1c01d2748309f", + expand=False, + ) + version( + "0.1.2", + sha256="abfb880fd1561987efaefcb2d2ac75145d2a5d0139b1876d5be806e32f630008", + expand=False, + ) + version( + "0.1.1", + sha256="c9535e5999f29bff90bd0fa423717dcaf247b71fad505d66b17d3217e9021fc5", + expand=False, + ) depends_on("python@3.7:", when="@0.2.2:", type=("build", "run")) - depends_on("py-setuptools", when="@:0.1.2", type="build") - depends_on("py-jupyter-packaging11", when="@0.2.2:", type="build") - depends_on("py-jupyterlab@3.1:3", when="@0.2.2:", type="build") depends_on("py-pygments@2.4.1:2", type=("build", "run")) From 2c802c12a594d64b72a589af9261f9ab7fecea2c Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Mon, 17 Oct 2022 15:54:40 +0200 Subject: [PATCH 070/442] installer.py: show timers for binary install (#33305) Print a message of the form ``` Fetch mm:ss. Build: mm:ss. Total: mm:ss ``` when installing from buildcache. Previously this only happened for source builds. --- lib/spack/spack/installer.py | 80 +++++++++++++++++++++++++----------- 1 file changed, 57 insertions(+), 23 deletions(-) diff --git a/lib/spack/spack/installer.py b/lib/spack/spack/installer.py index 4150302b28e..7ec31f02677 100644 --- a/lib/spack/spack/installer.py +++ b/lib/spack/spack/installer.py @@ -262,6 +262,30 @@ def _hms(seconds): return " ".join(parts) +def _log_prefix(pkg_name): + """Prefix of the form "[pid]: [pkg name]: ..." when printing a status update during + the build.""" + pid = "{0}: ".format(os.getpid()) if tty.show_pid() else "" + return "{0}{1}:".format(pid, pkg_name) + + +def _print_installed_pkg(message): + """ + Output a message with a package icon. + + Args: + message (str): message to be output + """ + print(colorize("@*g{[+]} ") + spack.util.path.debug_padded_filter(message)) + + +def _print_timer(pre, pkg_id, fetch, build, total): + tty.msg( + "{0} Successfully installed {1}".format(pre, pkg_id), + "Fetch: {0}. Build: {1}. Total: {2}.".format(_hms(fetch), _hms(build), _hms(total)), + ) + + def _install_from_cache(pkg, cache_only, explicit, unsigned=False): """ Extract the package from binary cache @@ -278,7 +302,10 @@ def _install_from_cache(pkg, cache_only, explicit, unsigned=False): bool: ``True`` if the package was extract from binary cache, ``False`` otherwise """ - installed_from_cache = _try_install_from_binary_cache(pkg, explicit, unsigned=unsigned) + timer = Timer() + installed_from_cache = _try_install_from_binary_cache( + pkg, explicit, unsigned=unsigned, timer=timer + ) pkg_id = package_id(pkg) if not installed_from_cache: pre = "No binary for {0} found".format(pkg_id) @@ -287,23 +314,20 @@ def _install_from_cache(pkg, cache_only, explicit, unsigned=False): tty.msg("{0}: installing from source".format(pre)) return False - + timer.stop() tty.debug("Successfully extracted {0} from binary cache".format(pkg_id)) + _print_timer( + pre=_log_prefix(pkg.name), + pkg_id=pkg_id, + fetch=timer.phases.get("search", 0) + timer.phases.get("fetch", 0), + build=timer.phases.get("install", 0), + total=timer.total, + ) _print_installed_pkg(pkg.spec.prefix) spack.hooks.post_install(pkg.spec) return True -def _print_installed_pkg(message): - """ - Output a message with a package icon. - - Args: - message (str): message to be output - """ - print(colorize("@*g{[+]} ") + spack.util.path.debug_padded_filter(message)) - - def _process_external_package(pkg, explicit): """ Helper function to run post install hooks and register external packages. @@ -345,7 +369,9 @@ def _process_external_package(pkg, explicit): spack.store.db.add(spec, None, explicit=explicit) -def _process_binary_cache_tarball(pkg, binary_spec, explicit, unsigned, mirrors_for_spec=None): +def _process_binary_cache_tarball( + pkg, binary_spec, explicit, unsigned, mirrors_for_spec=None, timer=None +): """ Process the binary cache tarball. @@ -357,6 +383,7 @@ def _process_binary_cache_tarball(pkg, binary_spec, explicit, unsigned, mirrors_ otherwise, ``False`` mirrors_for_spec (list): Optional list of concrete specs and mirrors obtained by calling binary_distribution.get_mirrors_for_spec(). + timer (Timer): timer to keep track of binary install phases. Return: bool: ``True`` if the package was extracted from binary cache, @@ -365,6 +392,8 @@ def _process_binary_cache_tarball(pkg, binary_spec, explicit, unsigned, mirrors_ download_result = binary_distribution.download_tarball( binary_spec, unsigned, mirrors_for_spec=mirrors_for_spec ) + if timer: + timer.phase("fetch") # see #10063 : install from source if tarball doesn't exist if download_result is None: tty.msg("{0} exists in binary cache but with different hash".format(pkg.name)) @@ -381,10 +410,12 @@ def _process_binary_cache_tarball(pkg, binary_spec, explicit, unsigned, mirrors_ pkg.installed_from_binary_cache = True spack.store.db.add(pkg.spec, spack.store.layout, explicit=explicit) + if timer: + timer.phase("install") return True -def _try_install_from_binary_cache(pkg, explicit, unsigned=False): +def _try_install_from_binary_cache(pkg, explicit, unsigned=False, timer=None): """ Try to extract the package from binary cache. @@ -393,16 +424,20 @@ def _try_install_from_binary_cache(pkg, explicit, unsigned=False): explicit (bool): the package was explicitly requested by the user unsigned (bool): ``True`` if binary package signatures to be checked, otherwise, ``False`` + timer (Timer): """ pkg_id = package_id(pkg) tty.debug("Searching for binary cache of {0}".format(pkg_id)) matches = binary_distribution.get_mirrors_for_spec(pkg.spec) + if timer: + timer.phase("search") + if not matches: return False return _process_binary_cache_tarball( - pkg, pkg.spec, explicit, unsigned, mirrors_for_spec=matches + pkg, pkg.spec, explicit, unsigned, mirrors_for_spec=matches, timer=timer ) @@ -1841,8 +1876,7 @@ def __init__(self, pkg, install_args): self.filter_fn = spack.util.path.padding_filter if padding else None # info/debug information - pid = "{0}: ".format(os.getpid()) if tty.show_pid() else "" - self.pre = "{0}{1}:".format(pid, pkg.name) + self.pre = _log_prefix(pkg.name) self.pkg_id = package_id(pkg) def run(self): @@ -1885,12 +1919,12 @@ def run(self): # Run post install hooks before build stage is removed. spack.hooks.post_install(self.pkg.spec) - build_time = self.timer.total - self.pkg._fetch_time - tty.msg( - "{0} Successfully installed {1}".format(self.pre, self.pkg_id), - "Fetch: {0}. Build: {1}. Total: {2}.".format( - _hms(self.pkg._fetch_time), _hms(build_time), _hms(self.timer.total) - ), + _print_timer( + pre=self.pre, + pkg_id=self.pkg_id, + fetch=self.pkg._fetch_time, + build=self.timer.total - self.pkg._fetch_time, + total=self.timer.total, ) _print_installed_pkg(self.pkg.prefix) From 25e35c936b4f666f09163bbdde13ca52aea3d8f1 Mon Sep 17 00:00:00 2001 From: iarspider Date: Mon, 17 Oct 2022 16:09:52 +0200 Subject: [PATCH 071/442] Add checksum for py-astroid 2.12.7, py-astroid 2.12.10, py-setuptools 62.6.0, py-wrapt 1.14.1, py-pylint 2.15.0 (#32976) * Add checksum for py-astroid 2.12.7, py-setuptools 62.6.0 * Also add checksum for py-wrapt * Update package.py * Update package.py (#57) * Update package.py * Update package.py * Update package.py --- .../builtin/packages/py-astroid/package.py | 13 +++-- .../builtin/packages/py-pylint/package.py | 47 ++++++++++--------- .../builtin/packages/py-setuptools/package.py | 15 ++++-- .../builtin/packages/py-wrapt/package.py | 1 + 4 files changed, 46 insertions(+), 30 deletions(-) diff --git a/var/spack/repos/builtin/packages/py-astroid/package.py b/var/spack/repos/builtin/packages/py-astroid/package.py index 0d28062c256..555ff3822cd 100644 --- a/var/spack/repos/builtin/packages/py-astroid/package.py +++ b/var/spack/repos/builtin/packages/py-astroid/package.py @@ -13,6 +13,8 @@ class PyAstroid(PythonPackage): homepage = "https://github.com/PyCQA/astroid" pypi = "astroid/astroid-2.8.3.tar.gz" + version("2.12.10", sha256="81f870105d892e73bf535da77a8261aa5bde838fa4ed12bb2f435291a098c581") + version("2.12.7", sha256="cd468be9d9d03d086d4d7e6643a59bfc025762d2c895e1e22cf21feced7bb148") version("2.11.6", sha256="4f933d0bf5e408b03a6feb5d23793740c27e07340605f236496cd6ce552043d6") version("2.11.5", sha256="f4e4ec5294c4b07ac38bab9ca5ddd3914d4bf46f9006eb5c0ae755755061044e") version("2.11.4", sha256="561dc6015eecce7e696ff7e3b40434bc56831afeff783f0ea853e19c4f635c06") @@ -40,17 +42,20 @@ class PyAstroid(PythonPackage): depends_on("python@3.5:", when="@2.3.3:", type=("build", "run")) depends_on("python@3.6:", when="@2.5.6:", type=("build", "run")) depends_on("python@3.6.2:", when="@2.11.4:", type=("build", "run")) + depends_on("python@3.7.2:", when="@2.12.7:", type=("build", "run")) depends_on("py-lazy-object-proxy", type=("build", "run")) # Starting with astroid 2.3.1, astroid's dependencies were restricted # to a given minor version, c.f. commit e1b4e11. depends_on("py-lazy-object-proxy@1.4.0:1.4", when="@2.3.1:2.7.2", type=("build", "run")) depends_on("py-lazy-object-proxy@1.4.0:", when="@2.7.3:", type=("build", "run")) - depends_on("py-six", type=("build", "run"), when="@:2.7.2") + depends_on("py-six", when="@:2.7.2", type=("build", "run")) depends_on("py-six@1.12:1", when="@2.3.3:2.7.2", type=("build", "run")) depends_on("py-wrapt", when="@:2.2", type=("build", "run")) depends_on("py-wrapt@1.11:1.12", when="@2.3.3:2.8.2", type=("build", "run")) depends_on("py-wrapt@1.11:1.13", when="@2.8.3:2.10", type=("build", "run")) - depends_on("py-wrapt@1.11:1", when="@2.11:", type=("build", "run")) + depends_on("py-wrapt@1.11:1", when="@2.11", type=("build", "run")) + depends_on("py-wrapt@1.14:1", when="@2.12.7: ^python@3.11:", type=("build", "run")) + depends_on("py-wrapt@1.11:1", when="@2.12.7: ^python@:3.10", type=("build", "run")) depends_on("py-enum34@1.1.3:", when="^python@:3.3", type=("build", "run")) depends_on("py-singledispatch", when="^python@:3.3", type=("build", "run")) depends_on("py-backports-functools-lru-cache", when="^python@:3.2", type=("build", "run")) @@ -60,4 +65,6 @@ class PyAstroid(PythonPackage): depends_on("py-typing-extensions@3.7.4:", when="@2.7.3: ^python@:3.7", type=("build", "run")) depends_on("py-typing-extensions@3.10:", when="@2.8.3: ^python@:3.9", type=("build", "run")) depends_on("py-setuptools@17.1:", type=("build", "run")) - depends_on("py-setuptools@20:", type=("build", "run"), when="@2.7.3:") + depends_on("py-setuptools@20:", when="@2.7.3:", type=("build", "run")) + depends_on("py-setuptools@62.6:62", when="@2.12.7:", type=("build", "run")) + depends_on("py-wheel@0.37.1:0.37", when="@2.12.7:", type="build") diff --git a/var/spack/repos/builtin/packages/py-pylint/package.py b/var/spack/repos/builtin/packages/py-pylint/package.py index 60f3a67a535..675f292e8c8 100644 --- a/var/spack/repos/builtin/packages/py-pylint/package.py +++ b/var/spack/repos/builtin/packages/py-pylint/package.py @@ -25,6 +25,7 @@ class PyPylint(PythonPackage): "pylint.reporters.ureports", ] + version("2.15.0", sha256="4f3f7e869646b0bd63b3dfb79f3c0f28fc3d2d923ea220d52620fd625aed92b0") version("2.14.4", sha256="47705453aa9dce520e123a7d51843d5f0032cbfa06870f89f00927aa1f735a4a") version("2.13.5", sha256="dab221658368c7a05242e673c275c488670144123f4bd262b2777249c1c0de9b") version("2.11.1", sha256="2c9843fff1a88ca0ad98a256806c82c5a8f86086e7ccbdb93297d86c3f90c436") @@ -43,33 +44,35 @@ class PyPylint(PythonPackage): depends_on("python@3.6:", when="@2.8.2:", type=("build", "run")) depends_on("python@3.6.2:", when="@2.13.5:", type=("build", "run")) depends_on("python@3.7.2:", when="@2.14.0:", type=("build", "run")) + depends_on("py-setuptools-scm", when="@2.8.2", type="build") + depends_on("py-setuptools@17.1:", type="build") + depends_on("py-setuptools@62.6:62", when="@2.15.0:", type="build") + depends_on("py-wheel@0.37.1:0.37", when="@2.15.0:", type="build") + depends_on("py-dill@0.2:", when="@2.13.5:", type=("build", "run")) + depends_on("py-platformdirs@2.2.0:", when="@2.11.1:", type=("build", "run")) depends_on("py-astroid", type=("build", "run")) # note there is no working version of astroid for this - depends_on("py-astroid@1.5.1:", type=("build", "run"), when="@1.7:") - depends_on("py-astroid@1.6:1.9", type=("build", "run"), when="@1.9.4") - depends_on("py-astroid@2.0:", type=("build", "run"), when="@2.2.0:") - depends_on("py-astroid@2.2.0:2", type=("build", "run"), when="@2.3.0:2.7") - depends_on("py-astroid@2.5.6:2.6", type=("build", "run"), when="@2.8.0:2.10") - depends_on("py-astroid@2.8.0:2.8", type=("build", "run"), when="@2.11.1") - depends_on("py-astroid@2.11.2:2.11", type=("build", "run"), when="@2.13.5:") - depends_on("py-astroid@2.11.6:2.11", type=("build", "run"), when="@2.14.2:") - depends_on("py-backports-functools-lru-cache", when="^python@:2.8", type=("build", "run")) - depends_on("py-configparser", when="^python@:2.8", type=("build", "run")) - depends_on("py-dill@0.2:", when="@2.13.5:", type=("build", "run")) - depends_on("py-editdistance", type=("build", "run"), when="@:1.7") + depends_on("py-astroid@1.5.1:", when="@1.7:", type=("build", "run")) + depends_on("py-astroid@1.6:1.9", when="@1.9.4", type=("build", "run")) + depends_on("py-astroid@2.0:", when="@2.2.0:", type=("build", "run")) + depends_on("py-astroid@2.2.0:2", when="@2.3.0:2.7", type=("build", "run")) + depends_on("py-astroid@2.5.6:2.6", when="@2.8.0:2.10", type=("build", "run")) + depends_on("py-astroid@2.8.0:2.8", when="@2.11.1", type=("build", "run")) + depends_on("py-astroid@2.11.2:2.11", when="@2.13.5:2.13", type=("build", "run")) + depends_on("py-astroid@2.11.6:2.11", when="@2.14.2:2.14", type=("build", "run")) + depends_on("py-astroid@2.12.4:2.13", when="@2.15.0:", type=("build", "run")) depends_on("py-isort@4.2.5:", type=("build", "run")) depends_on("py-isort@4.2.5:5", when="@2.3.1:", type=("build", "run")) depends_on("py-mccabe", type=("build", "run")) depends_on("py-mccabe@0.6.0:0.6", when="@2.3.1:2.11", type=("build", "run")) depends_on("py-mccabe@0.6.0:0.7", when="@2.13:", type=("build", "run")) - depends_on("py-pip", type=("build")) # see https://github.com/spack/spack/issues/27075 - # depends_on('py-setuptools-scm@1.15.0:', type='build') - depends_on("py-setuptools-scm", type="build", when="@2.8.2") - depends_on("py-setuptools@17.1:", type="build") + depends_on("py-tomli@1.1.0:", when="@2.13.5: ^python@:3.10", type=("build", "run")) + depends_on("py-tomlkit@0.10.1:", when="@2.14.0:", type=("build", "run")) + depends_on("py-colorama@0.4.5:", when="platform=windows", type=("build", "run")) + depends_on("py-typing-extensions@3.10.0:", when="@2.11.1: ^python@:3.9", type=("build", "run")) + depends_on("py-backports-functools-lru-cache", when="^python@:2.8", type=("build", "run")) + depends_on("py-configparser", when="^python@:2.8", type=("build", "run")) + depends_on("py-editdistance", when="@:1.7", type=("build", "run")) depends_on("py-singledispatch", when="^python@:3.3", type=("build", "run")) - depends_on("py-six", type=("build", "run"), when="@1:2.3.1") - depends_on("py-toml@0.7.1:", type=("build", "run"), when="@2.8.2:2.12.2") - depends_on("py-tomli@1.1.0:", type=("build", "run"), when="@2.13.5: ^python@:3.10") - depends_on("py-tomlkit@0.10.1:", type=("build", "run"), when="@2.14.0:") - depends_on("py-platformdirs@2.2.0:", type=("build", "run"), when="@2.11.1:") - depends_on("py-typing-extensions@3.10.0:", type=("build", "run"), when="@2.11.1: ^python@:3.9") + depends_on("py-six", when="@1:2.3.1", type=("build", "run")) + depends_on("py-toml@0.7.1:", when="@2.8.2:2.12.2", type=("build", "run")) diff --git a/var/spack/repos/builtin/packages/py-setuptools/package.py b/var/spack/repos/builtin/packages/py-setuptools/package.py index 8bf9f71863b..6bb59b2ad6b 100644 --- a/var/spack/repos/builtin/packages/py-setuptools/package.py +++ b/var/spack/repos/builtin/packages/py-setuptools/package.py @@ -36,6 +36,11 @@ class PySetuptools(Package): sha256="045aec56a3eee5c82373a70e02db8b6da9a10f7faf61ff89a14ab66c738ed370", expand=False, ) + version( + "62.6.0", + sha256="c1848f654aea2e3526d17fc3ce6aeaa5e7e24e66e645b5be2171f3f6b4e5a178", + expand=False, + ) version( "62.4.0", sha256="5a844ad6e190dccc67d6d7411d119c5152ce01f7c76be4d8a1eaa314501bba77", @@ -173,11 +178,11 @@ class PySetuptools(Package): ) extends("python") - depends_on("python@3.7:", type=("build", "run"), when="@59.7:") - depends_on("python@3.6:", type=("build", "run"), when="@51:") - depends_on("python@3.5:", type=("build", "run"), when="@45:50") - depends_on("python@2.7:2.8,3.5:", type=("build", "run"), when="@44") - depends_on("python@2.7:2.8,3.4:", type=("build", "run"), when="@:43") + depends_on("python@3.7:", when="@59.7:", type=("build", "run")) + depends_on("python@3.6:", when="@51:", type=("build", "run")) + depends_on("python@3.5:", when="@45:50", type=("build", "run")) + depends_on("python@2.7:2.8,3.5:", when="@44", type=("build", "run")) + depends_on("python@2.7:2.8,3.4:", when="@:43", type=("build", "run")) depends_on("py-pip", type="build") def url_for_version(self, version): diff --git a/var/spack/repos/builtin/packages/py-wrapt/package.py b/var/spack/repos/builtin/packages/py-wrapt/package.py index 281f56f0b6c..a7a57fa0250 100644 --- a/var/spack/repos/builtin/packages/py-wrapt/package.py +++ b/var/spack/repos/builtin/packages/py-wrapt/package.py @@ -12,6 +12,7 @@ class PyWrapt(PythonPackage): homepage = "https://github.com/GrahamDumpleton/wrapt" pypi = "wrapt/wrapt-1.11.2.tar.gz" + version("1.14.1", sha256="380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d") version("1.13.3", sha256="1fea9cd438686e6682271d36f3481a9f3636195578bab9ca3382e2f5f01fc185") version("1.12.1", sha256="b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7") version("1.11.2", sha256="565a021fd19419476b9362b05eeaa094178de64f8361e44468f9e9d7843901e1") From 1be6506e29b57bd905145c8f08fbd7193e74bb78 Mon Sep 17 00:00:00 2001 From: Scott Wittenburg Date: Mon, 17 Oct 2022 08:29:56 -0600 Subject: [PATCH 072/442] gitlab ci: Do not force protected build jobs to run on aws runners (#33314) --- lib/spack/spack/ci.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/spack/spack/ci.py b/lib/spack/spack/ci.py index c54596fea6c..e471e042096 100644 --- a/lib/spack/spack/ci.py +++ b/lib/spack/spack/ci.py @@ -878,7 +878,7 @@ def generate_gitlab_ci_yaml( # For spack pipelines "public" and "protected" are reserved tags tags = _remove_reserved_tags(tags) if spack_pipeline_type == "spack_protected_branch": - tags.extend(["aws", "protected"]) + tags.extend(["protected"]) elif spack_pipeline_type == "spack_pull_request": tags.extend(["public"]) From e882583b013be66aeed777f19a4b2604a377f2c7 Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Mon, 17 Oct 2022 16:57:58 +0200 Subject: [PATCH 073/442] installer.py: fix/test get_deptypes (#33363) Fixing an oversight in https://github.com/spack/spack/pull/32537 `get_deptypes` should depend on new `package/dependencies_cache_only` props. --- lib/spack/spack/installer.py | 8 ++++++- lib/spack/spack/test/buildrequest.py | 33 ++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/lib/spack/spack/installer.py b/lib/spack/spack/installer.py index 7ec31f02677..1de78e392b3 100644 --- a/lib/spack/spack/installer.py +++ b/lib/spack/spack/installer.py @@ -2391,7 +2391,13 @@ def get_deptypes(self, pkg): """ deptypes = ["link", "run"] include_build_deps = self.install_args.get("include_build_deps") - if not self.install_args.get("cache_only") or include_build_deps: + + if self.pkg_id == package_id(pkg): + cache_only = self.install_args.get("package_cache_only") + else: + cache_only = self.install_args.get("dependencies_cache_only") + + if not cache_only or include_build_deps: deptypes.append("build") if self.run_tests(pkg): deptypes.append("test") diff --git a/lib/spack/spack/test/buildrequest.py b/lib/spack/spack/test/buildrequest.py index e656cfa99ef..7c986bb844a 100644 --- a/lib/spack/spack/test/buildrequest.py +++ b/lib/spack/spack/test/buildrequest.py @@ -62,3 +62,36 @@ def test_build_request_strings(install_mockery): istr = str(request) assert "package=dependent-install" in istr assert "install_args=" in istr + + +@pytest.mark.parametrize( + "package_cache_only,dependencies_cache_only,package_deptypes,dependencies_deptypes", + [ + (False, False, ["build", "link", "run"], ["build", "link", "run"]), + (True, False, ["link", "run"], ["build", "link", "run"]), + (False, True, ["build", "link", "run"], ["link", "run"]), + (True, True, ["link", "run"], ["link", "run"]), + ], +) +def test_build_request_deptypes( + install_mockery, + package_cache_only, + dependencies_cache_only, + package_deptypes, + dependencies_deptypes, +): + s = spack.spec.Spec("dependent-install").concretized() + + build_request = inst.BuildRequest( + s.package, + { + "package_cache_only": package_cache_only, + "dependencies_cache_only": dependencies_cache_only, + }, + ) + + actual_package_deptypes = build_request.get_deptypes(s.package) + actual_dependency_deptypes = build_request.get_deptypes(s["dependency-install"].package) + + assert sorted(actual_package_deptypes) == package_deptypes + assert sorted(actual_dependency_deptypes) == dependencies_deptypes From 42a27f3075c4e57f7716d698e287f0826936dee8 Mon Sep 17 00:00:00 2001 From: iarspider Date: Mon, 17 Oct 2022 17:01:22 +0200 Subject: [PATCH 074/442] Add checksum for py-grpcio-tools 1.48.1 (#33358) --- .../repos/builtin/packages/py-grpcio-tools/package.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/var/spack/repos/builtin/packages/py-grpcio-tools/package.py b/var/spack/repos/builtin/packages/py-grpcio-tools/package.py index 78c4339279f..21247b745a1 100644 --- a/var/spack/repos/builtin/packages/py-grpcio-tools/package.py +++ b/var/spack/repos/builtin/packages/py-grpcio-tools/package.py @@ -12,14 +12,17 @@ class PyGrpcioTools(PythonPackage): homepage = "https://grpc.io/" pypi = "grpcio-tools/grpcio-tools-1.42.0.tar.gz" + version("1.48.1", sha256="1178f2ea531f80cc2027ec64728df6ffc8e98cf1df61652a496eafd612127183") version("1.42.0", sha256="d0a0daa82eb2c2fb8e12b82a458d1b7c5516fe1135551da92b1a02e2cba93422") version("1.39.0", sha256="39dfe7415bc0d3860fdb8dd90607594b046b88b57dbe64284efa4820f951c805") depends_on("python@3.6:", type=("build", "run")) depends_on("py-setuptools", type="build") + depends_on("py-protobuf@3.12.0:3", when="@1.48.1:", type=("build", "run")) depends_on("py-protobuf@3.5.0.post1:3", type=("build", "run")) - depends_on("py-grpcio@1.42.0:", type=("build", "run"), when="@1.42.0:") - depends_on("py-grpcio@1.39.0:", type=("build", "run"), when="@1.39.0:1.41") + depends_on("py-grpcio@1.48.1:", when="@1.48.1:", type=("build", "run")) + depends_on("py-grpcio@1.42.0:", when="@1.42.0:", type=("build", "run")) + depends_on("py-grpcio@1.39.0:", when="@1.39.0:1.41", type=("build", "run")) depends_on("py-cython@0.23:", type="build") depends_on("openssl") depends_on("zlib") From bfe49222d58c756828d9c1b00a7f5cc118b1104c Mon Sep 17 00:00:00 2001 From: iarspider Date: Mon, 17 Oct 2022 17:02:19 +0200 Subject: [PATCH 075/442] Add checksum for py-prompt-toolkit 3.0.31 (#33362) --- var/spack/repos/builtin/packages/py-prompt-toolkit/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/py-prompt-toolkit/package.py b/var/spack/repos/builtin/packages/py-prompt-toolkit/package.py index d4e9a04c418..b15830d6d94 100644 --- a/var/spack/repos/builtin/packages/py-prompt-toolkit/package.py +++ b/var/spack/repos/builtin/packages/py-prompt-toolkit/package.py @@ -37,6 +37,7 @@ class PyPromptToolkit(PythonPackage): "prompt_toolkit.clipboard", ] + version("3.0.31", sha256="9ada952c9d1787f52ff6d5f3484d0b4df8952787c087edf6a1f7c2cb1ea88148") version("3.0.29", sha256="bd640f60e8cecd74f0dc249713d433ace2ddc62b65ee07f96d358e0b152b6ea7") version("3.0.24", sha256="1bb05628c7d87b645974a1bad3f17612be0c29fa39af9f7688030163f680bad6") version("3.0.17", sha256="9397a7162cf45449147ad6042fa37983a081b8a73363a5253dd4072666333137") From 4fe53061a8579fcf2a36ba8f81af05b3ee342a76 Mon Sep 17 00:00:00 2001 From: Rui Peng Li Date: Mon, 17 Oct 2022 08:31:28 -0700 Subject: [PATCH 076/442] hypre 2.26.0 (#33299) --- var/spack/repos/builtin/packages/hypre/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/hypre/package.py b/var/spack/repos/builtin/packages/hypre/package.py index 874b2321cbf..a05e8a17013 100644 --- a/var/spack/repos/builtin/packages/hypre/package.py +++ b/var/spack/repos/builtin/packages/hypre/package.py @@ -26,6 +26,7 @@ class Hypre(AutotoolsPackage, CudaPackage, ROCmPackage): test_requires_compiler = True version("develop", branch="master") + version("2.26.0", sha256="c214084bddc61a06f3758d82947f7f831e76d7e3edeac2c78bb82d597686e05d") version("2.25.0", sha256="f9fc8371d91239fca694284dab17175bfda3821d7b7a871fd2e8f9d5930f303c") version("2.24.0", sha256="f480e61fc25bf533fc201fdf79ec440be79bb8117650627d1f25151e8be2fdb5") version("2.23.0", sha256="8a9f9fb6f65531b77e4c319bf35bfc9d34bf529c36afe08837f56b635ac052e2") From ea80113d0f2ba9ca1a60f06c77a9bb1c88824b1f Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Mon, 17 Oct 2022 17:38:25 +0200 Subject: [PATCH 077/442] Github Discussions can be used for Q&A (#33364) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index fea23bb4086..cf4b413af8b 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,7 @@ Resources: * **Slack workspace**: [spackpm.slack.com](https://spackpm.slack.com). To get an invitation, visit [slack.spack.io](https://slack.spack.io). +* [**Github Discussions**](https://github.com/spack/spack/discussions): not just for discussions, also Q&A. * **Mailing list**: [groups.google.com/d/forum/spack](https://groups.google.com/d/forum/spack) * **Twitter**: [@spackpm](https://twitter.com/spackpm). Be sure to `@mention` us! From 29df7e9be356b1c6eb84647b556beae5f7cec933 Mon Sep 17 00:00:00 2001 From: Scott Wittenburg Date: Mon, 17 Oct 2022 09:45:09 -0600 Subject: [PATCH 078/442] Support spackbot rebuilding all specs from source (#32596) Support spackbot rebuilding all specs from source when asked (with "rebuild everything") - Allow overriding --prune-dag cli opt with env var - Use job variable to optionally prevent rebuild jobs early exit behavior - ci rebuild: Use new install argument to insist deps are always installed from binary, but package is only installed from source. - gitlab: fix bug w/ untouched pruning - ci rebuild: install from hash rather than json file - When doing a "rebuild everything" pipeline, make sure that each install job only consumes binary dependencies from the mirror being populated by the current pipeline. This avoids using, e.g. binaries from develop, when rebuilding everything on a PR. - When running a pipeline to rebuild everything, do not die because we generated a hash on the broken specs list. Instead only warn in that case. - bugfix: Replace broken no-args tty.die() with sys.exit(1) --- lib/spack/spack/ci.py | 34 +++++++++++++++++++++++---- lib/spack/spack/cmd/ci.py | 49 +++++++++++++++++++++++++++------------ 2 files changed, 64 insertions(+), 19 deletions(-) diff --git a/lib/spack/spack/ci.py b/lib/spack/spack/ci.py index e471e042096..0741485656c 100644 --- a/lib/spack/spack/ci.py +++ b/lib/spack/spack/ci.py @@ -12,6 +12,7 @@ import shutil import stat import subprocess +import sys import tempfile import time import zipfile @@ -626,11 +627,11 @@ def generate_gitlab_ci_yaml( cdash_handler = CDashHandler(yaml_root.get("cdash")) if "cdash" in yaml_root else None build_group = cdash_handler.build_group if cdash_handler else None - prune_untouched_packages = os.environ.get("SPACK_PRUNE_UNTOUCHED", None) - if prune_untouched_packages: + prune_untouched_packages = False + spack_prune_untouched = os.environ.get("SPACK_PRUNE_UNTOUCHED", None) + if spack_prune_untouched is not None and spack_prune_untouched.lower() == "true": # Requested to prune untouched packages, but assume we won't do that # unless we're actually in a git repo. - prune_untouched_packages = False rev1, rev2 = get_change_revisions() tty.debug("Got following revisions: rev1={0}, rev2={1}".format(rev1, rev2)) if rev1 and rev2: @@ -646,6 +647,14 @@ def generate_gitlab_ci_yaml( for s in affected_specs: tty.debug(" {0}".format(s.name)) + # Allow overriding --prune-dag cli opt with environment variable + prune_dag_override = os.environ.get("SPACK_PRUNE_UP_TO_DATE", None) + if prune_dag_override is not None: + prune_dag = True if prune_dag_override.lower() == "true" else False + + # If we are not doing any kind of pruning, we are rebuilding everything + rebuild_everything = not prune_dag and not prune_untouched_packages + # Downstream jobs will "need" (depend on, for both scheduling and # artifacts, which include spack.lock file) this pipeline generation # job by both name and pipeline id. If those environment variables @@ -1298,6 +1307,8 @@ def generate_gitlab_ci_yaml( "SPACK_LOCAL_MIRROR_DIR": rel_local_mirror_dir, "SPACK_PIPELINE_TYPE": str(spack_pipeline_type), "SPACK_CI_STACK_NAME": os.environ.get("SPACK_CI_STACK_NAME", "None"), + "SPACK_REBUILD_CHECK_UP_TO_DATE": str(prune_dag), + "SPACK_REBUILD_EVERYTHING": str(rebuild_everything), } if remote_mirror_override: @@ -1357,7 +1368,9 @@ def generate_gitlab_ci_yaml( if known_broken_specs_encountered: tty.error("This pipeline generated hashes known to be broken on develop:") display_broken_spec_messages(broken_specs_url, known_broken_specs_encountered) - tty.die() + + if not rebuild_everything: + sys.exit(1) with open(output_file, "w") as outf: outf.write(syaml.dump_config(sorted_output, default_flow_style=True)) @@ -1575,6 +1588,19 @@ def push_mirror_contents(env, specfile_path, mirror_url, sign_binaries): raise inst +def remove_other_mirrors(mirrors_to_keep, scope=None): + """Remove all mirrors from the given config scope, the exceptions being + any listed in in mirrors_to_keep, which is a list of mirror urls. + """ + mirrors_to_remove = [] + for name, mirror_url in spack.config.get("mirrors", scope=scope).items(): + if mirror_url not in mirrors_to_keep: + mirrors_to_remove.append(name) + + for mirror_name in mirrors_to_remove: + spack.mirror.remove(mirror_name, scope) + + def copy_files_to_artifacts(src, artifacts_dir): """ Copy file(s) to the given artifacts directory diff --git a/lib/spack/spack/cmd/ci.py b/lib/spack/spack/cmd/ci.py index cd7a0bb767f..70016a29e8a 100644 --- a/lib/spack/spack/cmd/ci.py +++ b/lib/spack/spack/cmd/ci.py @@ -284,6 +284,7 @@ def ci_rebuild(args): remote_mirror_override = get_env_var("SPACK_REMOTE_MIRROR_OVERRIDE") remote_mirror_url = get_env_var("SPACK_REMOTE_MIRROR_URL") spack_ci_stack_name = get_env_var("SPACK_CI_STACK_NAME") + rebuild_everything = get_env_var("SPACK_REBUILD_EVERYTHING") # Construct absolute paths relative to current $CI_PROJECT_DIR ci_project_dir = get_env_var("CI_PROJECT_DIR") @@ -325,6 +326,8 @@ def ci_rebuild(args): ) ) + full_rebuild = True if rebuild_everything and rebuild_everything.lower() == "true" else False + # If no override url exists, then just push binary package to the # normal remote mirror url. buildcache_mirror_url = remote_mirror_override or remote_mirror_url @@ -448,6 +451,8 @@ def ci_rebuild(args): fd.write(spack_info.encode("utf8")) fd.write(b"\n") + pipeline_mirrors = [] + # If we decided there should be a temporary storage mechanism, add that # mirror now so it's used when we check for a hash match already # built for this spec. @@ -455,22 +460,29 @@ def ci_rebuild(args): spack.mirror.add( spack_ci.TEMP_STORAGE_MIRROR_NAME, pipeline_mirror_url, cfg.default_modify_scope() ) + pipeline_mirrors.append(pipeline_mirror_url) # Check configured mirrors for a built spec with a matching hash mirrors_to_check = None - if remote_mirror_override and spack_pipeline_type == "spack_protected_branch": - # Passing "mirrors_to_check" below means we *only* look in the override - # mirror to see if we should skip building, which is what we want. - mirrors_to_check = {"override": remote_mirror_override} + if remote_mirror_override: + if spack_pipeline_type == "spack_protected_branch": + # Passing "mirrors_to_check" below means we *only* look in the override + # mirror to see if we should skip building, which is what we want. + mirrors_to_check = {"override": remote_mirror_override} - # Adding this mirror to the list of configured mirrors means dependencies - # could be installed from either the override mirror or any other configured - # mirror (e.g. remote_mirror_url which is defined in the environment or - # pipeline_mirror_url), which is also what we want. - spack.mirror.add("mirror_override", remote_mirror_override, cfg.default_modify_scope()) + # Adding this mirror to the list of configured mirrors means dependencies + # could be installed from either the override mirror or any other configured + # mirror (e.g. remote_mirror_url which is defined in the environment or + # pipeline_mirror_url), which is also what we want. + spack.mirror.add("mirror_override", remote_mirror_override, cfg.default_modify_scope()) + pipeline_mirrors.append(remote_mirror_override) - matches = bindist.get_mirrors_for_spec( - job_spec, mirrors_to_check=mirrors_to_check, index_only=False + matches = ( + None + if full_rebuild + else bindist.get_mirrors_for_spec( + job_spec, mirrors_to_check=mirrors_to_check, index_only=False + ) ) if matches: @@ -493,6 +505,13 @@ def ci_rebuild(args): # Now we are done and successful sys.exit(0) + # Before beginning the install, if this is a "rebuild everything" pipeline, we + # only want to keep the mirror being used by the current pipeline as it's binary + # package destination. This ensures that the when we rebuild everything, we only + # consume binary dependencies built in this pipeline. + if full_rebuild: + spack_ci.remove_other_mirrors(pipeline_mirrors, cfg.default_modify_scope()) + # No hash match anywhere means we need to rebuild spec # Start with spack arguments @@ -507,6 +526,8 @@ def ci_rebuild(args): "install", "--show-log-on-error", # Print full log on fails "--keep-stage", + "--use-buildcache", + "dependencies:only,package:never", ] ) @@ -525,10 +546,8 @@ def ci_rebuild(args): if compiler_action != "FIND_ANY": install_args.append("--no-add") - # TODO: once we have the concrete spec registry, use the DAG hash - # to identify the spec to install, rather than the concrete spec - # json file. - install_args.extend(["-f", job_spec_json_path]) + # Identify spec to install by hash + install_args.append("/{0}".format(job_spec.dag_hash())) tty.debug("Installing {0} from source".format(job_spec.name)) install_exit_code = spack_ci.process_command("install", install_args, repro_dir) From 32761cdb7b36477c77b2f3a157e225f0e8da067a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Bederi=C3=A1n?= Date: Mon, 17 Oct 2022 12:47:10 -0300 Subject: [PATCH 079/442] python: add 3.10.7, 3.9.14, 3.8.14, 3.7.14 (#32623) --- var/spack/repos/builtin/packages/python/package.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/var/spack/repos/builtin/packages/python/package.py b/var/spack/repos/builtin/packages/python/package.py index 48d3cae903b..32c3429c432 100644 --- a/var/spack/repos/builtin/packages/python/package.py +++ b/var/spack/repos/builtin/packages/python/package.py @@ -44,6 +44,7 @@ class Python(Package): install_targets = ["install"] build_targets = [] # type: List[str] + version("3.10.7", sha256="1b2e4e2df697c52d36731666979e648beeda5941d0f95740aafbf4163e5cc126") version("3.10.6", sha256="848cb06a5caa85da5c45bd7a9221bb821e33fc2bdcba088c127c58fad44e6343") version("3.10.5", sha256="18f57182a2de3b0be76dfc39fdcfd28156bb6dd23e5f08696f7492e9e3d0bf2d") version("3.10.4", sha256="f3bcc65b1d5f1dc78675c746c98fcee823c038168fc629c5935b044d0911ad28") @@ -52,10 +53,11 @@ class Python(Package): version("3.10.1", sha256="b76117670e7c5064344b9c138e141a377e686b9063f3a8a620ff674fa8ec90d3") version("3.10.0", sha256="c4e0cbad57c90690cb813fb4663ef670b4d0f587d8171e2c42bd4c9245bd2758") version( - "3.9.13", - sha256="829b0d26072a44689a6b0810f5b4a3933ee2a0b8a4bfc99d7c5893ffd4f97c44", + "3.9.14", + sha256="9201836e2c16361b2b7408680502393737d44f227333fe2e5729c7d5f6041675", preferred=True, ) + version("3.9.13", sha256="829b0d26072a44689a6b0810f5b4a3933ee2a0b8a4bfc99d7c5893ffd4f97c44") version("3.9.12", sha256="70e08462ebf265012bd2be88a63d2149d880c73e53f1712b7bbbe93750560ae8") version("3.9.11", sha256="3442400072f582ac2f0df30895558f08883b416c8c7877ea55d40d00d8a93112") version("3.9.10", sha256="1aa9c0702edbae8f6a2c95f70a49da8420aaa76b7889d3419c186bfc8c0e571e") @@ -69,6 +71,7 @@ class Python(Package): version("3.9.2", sha256="7899e8a6f7946748830d66739f2d8f2b30214dad956e56b9ba216b3de5581519") version("3.9.1", sha256="29cb91ba038346da0bd9ab84a0a55a845d872c341a4da6879f462e94c741f117") version("3.9.0", sha256="df796b2dc8ef085edae2597a41c1c0a63625ebd92487adaef2fed22b567873e8") + version("3.8.14", sha256="41f959c480c59211feb55d5a28851a56c7e22d02ef91035606ebb21011723c31") version("3.8.13", sha256="903b92d76354366b1d9c4434d0c81643345cef87c1600adfa36095d7b00eede4") version("3.8.12", sha256="316aa33f3b7707d041e73f246efedb297a70898c4b91f127f66dc8d80c596f1a") version("3.8.11", sha256="b77464ea80cec14581b86aeb7fb2ff02830e0abc7bcdc752b7b4bdfcd8f3e393") @@ -83,6 +86,7 @@ class Python(Package): version("3.8.2", sha256="e634a7a74776c2b89516b2e013dda1728c89c8149b9863b8cea21946daf9d561") version("3.8.1", sha256="c7cfa39a43b994621b245e029769e9126caa2a93571cee2e743b213cceac35fb") version("3.8.0", sha256="f1069ad3cae8e7ec467aa98a6565a62a48ef196cb8f1455a245a08db5e1792df") + version("3.7.14", sha256="82b2abf8978caa61a9011d166eede831b32de9cbebc0db8162900fa23437b709") version("3.7.13", sha256="e405417f50984bc5870c7e7a9f9aeb93e9d270f5ac67f667a0cd3a09439682b5") version("3.7.12", sha256="33b4daaf831be19219659466d12645f87ecec6eb21d4d9f9711018a7b66cce46") version("3.7.11", sha256="b4fba32182e16485d0a6022ba83c9251e6a1c14676ec243a9a07d3722cd4661a") From db342d872746e8f92b53c7763ccb1d6b0bbc9a07 Mon Sep 17 00:00:00 2001 From: iarspider Date: Mon, 17 Oct 2022 17:54:31 +0200 Subject: [PATCH 080/442] Add checksum for py-secretstorage 3.3.3 (#33366) --- var/spack/repos/builtin/packages/py-secretstorage/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/py-secretstorage/package.py b/var/spack/repos/builtin/packages/py-secretstorage/package.py index 3c0f935a2d0..e7f0c9f1a88 100644 --- a/var/spack/repos/builtin/packages/py-secretstorage/package.py +++ b/var/spack/repos/builtin/packages/py-secretstorage/package.py @@ -12,6 +12,7 @@ class PySecretstorage(PythonPackage): homepage = "https://github.com/mitya57/secretstorage" pypi = "SecretStorage/SecretStorage-3.1.2.tar.gz" + version("3.3.3", sha256="2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77") version("3.3.1", sha256="fd666c51a6bf200643495a04abb261f83229dcb6fd8472ec393df7ffc8b6f195") version("3.1.2", sha256="15da8a989b65498e29be338b3b279965f1b8f09b9668bd8010da183024c8bff6") version("2.3.1", sha256="3af65c87765323e6f64c83575b05393f9e003431959c9395d1791d51497f29b6") From ad430a7504c5e132d06a4d722b72e2bdd056d6c8 Mon Sep 17 00:00:00 2001 From: iarspider Date: Mon, 17 Oct 2022 17:59:21 +0200 Subject: [PATCH 081/442] Add checksum for py-ipykernel 6.15.2 (#33360) --- var/spack/repos/builtin/packages/py-ipykernel/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/py-ipykernel/package.py b/var/spack/repos/builtin/packages/py-ipykernel/package.py index 9ac69621a0e..a32c3c8331f 100644 --- a/var/spack/repos/builtin/packages/py-ipykernel/package.py +++ b/var/spack/repos/builtin/packages/py-ipykernel/package.py @@ -14,6 +14,7 @@ class PyIpykernel(PythonPackage): pypi = "ipykernel/ipykernel-5.3.4.tar.gz" version("6.16.0", sha256="7fe42c0d58435e971dc15fd42189f20d66bf35f3056bda4f6554271bc1fa3d0d") + version("6.15.2", sha256="e7481083b438609c9c8a22d6362e8e1bc6ec94ba0741b666941e634f2d61bdf3") version("6.9.1", sha256="f95070a2dfd3147f8ab19f18ee46733310813758593745e07ec18fb08b409f1d") version("6.4.1", sha256="df3355e5eec23126bc89767a676c5f0abfc7f4c3497d118c592b83b316e8c0cd") version("6.2.0", sha256="4439459f171d77f35b7f7e72dace5d7c2dd10a5c9e2c22b173ad9048fbfe7656") From 90818719663fbf96c1746694bd1b1ab11ce40cc4 Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Mon, 17 Oct 2022 18:13:52 +0200 Subject: [PATCH 082/442] GnuPG: add v2.3.8 and update stack (#33368) --- var/spack/repos/builtin/packages/gnupg/package.py | 3 +++ var/spack/repos/builtin/packages/gpgme/package.py | 1 + var/spack/repos/builtin/packages/libgcrypt/package.py | 1 + var/spack/repos/builtin/packages/libgpg-error/package.py | 6 +++++- var/spack/repos/builtin/packages/libksba/package.py | 1 + var/spack/repos/builtin/packages/pinentry/package.py | 1 + 6 files changed, 12 insertions(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/gnupg/package.py b/var/spack/repos/builtin/packages/gnupg/package.py index bcf0549472f..6d9b89b72a9 100644 --- a/var/spack/repos/builtin/packages/gnupg/package.py +++ b/var/spack/repos/builtin/packages/gnupg/package.py @@ -14,7 +14,10 @@ class Gnupg(AutotoolsPackage): maintainers = ["alalazo"] + version("2.3.8", sha256="540b7a40e57da261fb10ef521a282e0021532a80fd023e75fb71757e8a4969ed") version("2.3.7", sha256="ee163a5fb9ec99ffc1b18e65faef8d086800c5713d15a672ab57d3799da83669") + version("2.2.40", sha256="1164b29a75e8ab93ea15033300149e1872a7ef6bdda3d7c78229a735f8204c28") + # Deprecated over CVE-2022-34903 version( "2.3.4", diff --git a/var/spack/repos/builtin/packages/gpgme/package.py b/var/spack/repos/builtin/packages/gpgme/package.py index fc02415f357..a8077130f58 100644 --- a/var/spack/repos/builtin/packages/gpgme/package.py +++ b/var/spack/repos/builtin/packages/gpgme/package.py @@ -15,6 +15,7 @@ class Gpgme(AutotoolsPackage): executables = ["^gpgme-config$"] + version("1.18.0", sha256="361d4eae47ce925dba0ea569af40e7b52c645c4ae2e65e5621bf1b6cdd8b0e9e") version("1.16.0", sha256="6c8cc4aedb10d5d4c905894ba1d850544619ee765606ac43df7405865de29ed0") version("1.12.0", sha256="b4dc951c3743a60e2e120a77892e9e864fb936b2e58e7c77e8581f4d050e8cd8") diff --git a/var/spack/repos/builtin/packages/libgcrypt/package.py b/var/spack/repos/builtin/packages/libgcrypt/package.py index e7798429f6e..1b945c87c33 100644 --- a/var/spack/repos/builtin/packages/libgcrypt/package.py +++ b/var/spack/repos/builtin/packages/libgcrypt/package.py @@ -20,6 +20,7 @@ class Libgcrypt(AutotoolsPackage): version("1.9.3", sha256="97ebe4f94e2f7e35b752194ce15a0f3c66324e0ff6af26659bbfb5ff2ec328fd") version("1.9.2", sha256="b2c10d091513b271e47177274607b1ffba3d95b188bbfa8797f948aec9053c5a") version("1.9.1", sha256="c5a67a8b9b2bd370fb415ed1ee31c7172e5683076493cf4a3678a0fbdf0265d9") + version("1.8.9", sha256="2bda4790aa5f0895d3407cf7bf6bd7727fd992f25a45a63d92fef10767fa3769") version("1.8.7", sha256="03b70f028299561b7034b8966d7dd77ef16ed139c43440925fe8782561974748") version("1.8.6", sha256="0cba2700617b99fc33864a0c16b1fa7fdf9781d9ed3509f5d767178e5fd7b975") version("1.8.5", sha256="3b4a2a94cb637eff5bdebbcaf46f4d95c4f25206f459809339cdada0eb577ac3") diff --git a/var/spack/repos/builtin/packages/libgpg-error/package.py b/var/spack/repos/builtin/packages/libgpg-error/package.py index acdc73f8a71..8b6924492f9 100644 --- a/var/spack/repos/builtin/packages/libgpg-error/package.py +++ b/var/spack/repos/builtin/packages/libgpg-error/package.py @@ -14,6 +14,7 @@ class LibgpgError(AutotoolsPackage): maintainers = ["alalazo"] + version("1.46", sha256="b7e11a64246bbe5ef37748de43b245abd72cfcd53c9ae5e7fc5ca59f1c81268d") version("1.45", sha256="570f8ee4fb4bff7b7495cff920c275002aea2147e9a1d220c068213267f80a26") version("1.44", sha256="8e3d2da7a8b9a104dd8e9212ebe8e0daf86aa838cc1314ba6bc4de8f2d8a1ff9") version("1.43", sha256="a9ab83ca7acc442a5bd846a75b920285ff79bdb4e3d34aa382be88ed2c3aebaf") @@ -31,8 +32,11 @@ class LibgpgError(AutotoolsPackage): patch("awk-5.patch", when="@1.36^gawk@5:") def configure_args(self): - return [ + args = [ "--enable-static", "--enable-shared", "--enable-tests" if self.run_tests else "--disable-tests", ] + if self.spec.satisfies("@1.46:"): + args.append("--enable-install-gpg-error-config") + return args diff --git a/var/spack/repos/builtin/packages/libksba/package.py b/var/spack/repos/builtin/packages/libksba/package.py index 9cb7d40c94f..8369102f316 100644 --- a/var/spack/repos/builtin/packages/libksba/package.py +++ b/var/spack/repos/builtin/packages/libksba/package.py @@ -17,6 +17,7 @@ class Libksba(AutotoolsPackage): maintainers = ["alalazo"] + version("1.6.2", sha256="fce01ccac59812bddadffacff017dac2e4762bdb6ebc6ffe06f6ed4f6192c971") version("1.6.0", sha256="dad683e6f2d915d880aa4bed5cea9a115690b8935b78a1bbe01669189307a48b") version("1.5.1", sha256="b0f4c65e4e447d9a2349f6b8c0e77a28be9531e4548ba02c545d1f46dc7bf921") version("1.5.0", sha256="ae4af129216b2d7fdea0b5bf2a788cd458a79c983bb09a43f4d525cc87aba0ba") diff --git a/var/spack/repos/builtin/packages/pinentry/package.py b/var/spack/repos/builtin/packages/pinentry/package.py index fec657a7727..9c91a1e0ce3 100644 --- a/var/spack/repos/builtin/packages/pinentry/package.py +++ b/var/spack/repos/builtin/packages/pinentry/package.py @@ -20,6 +20,7 @@ class Pinentry(AutotoolsPackage): maintainers = ["alalazo"] + version("1.2.1", sha256="457a185e5a85238fb945a955dc6352ab962dc8b48720b62fc9fa48c7540a4067") version("1.2.0", sha256="10072045a3e043d0581f91cd5676fcac7ffee957a16636adedaa4f583a616470") version("1.1.1", sha256="cd12a064013ed18e2ee8475e669b9f58db1b225a0144debdb85a68cecddba57f") version("1.1.0", sha256="68076686fa724a290ea49cdf0d1c0c1500907d1b759a3bcbfbec0293e8f56570") From 39105a3a6f2fe49376a2068a5885fcbdb4a5acbf Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Mon, 17 Oct 2022 18:14:12 +0200 Subject: [PATCH 083/442] installer.py: traverse_dependencies has local deptype (#33367) Currently `traverse_dependencies` fixes deptypes to traverse once and for all in the recursion, but this is incorrect, since deptypes depend on the node (e.g. if it's a dependency and cache-only, don't follow build type edges, even if the parent is build from sources and needs build deps.) --- lib/spack/spack/installer.py | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/lib/spack/spack/installer.py b/lib/spack/spack/installer.py index 1de78e392b3..ca53f87691a 100644 --- a/lib/spack/spack/installer.py +++ b/lib/spack/spack/installer.py @@ -2426,21 +2426,31 @@ def spec(self): """The specification associated with the package.""" return self.pkg.spec - def traverse_dependencies(self): + def traverse_dependencies(self, spec=None, visited=None): """ Yield any dependencies of the appropriate type(s) Yields: (Spec) The next child spec in the DAG """ - get_spec = lambda s: s.spec + # notice: deptype is not constant across nodes, so we cannot use + # spec.traverse_edges(deptype=...). - deptypes = self.get_deptypes(self.pkg) - tty.debug("Processing dependencies for {0}: {1}".format(self.pkg_id, deptypes)) - for dspec in self.spec.traverse_edges( - deptype=deptypes, order="post", root=False, direction="children" - ): - yield get_spec(dspec) + if spec is None: + spec = self.spec + if visited is None: + visited = set() + deptype = self.get_deptypes(spec.package) + + for dep in spec.dependencies(deptype=deptype): + hash = dep.dag_hash() + if hash in visited: + continue + visited.add(hash) + # In Python 3: yield from self.traverse_dependencies(dep, visited) + for s in self.traverse_dependencies(dep, visited): + yield s + yield dep class InstallError(spack.error.SpackError): From 839cf483521181e82fb29086d1c1b797c4efdc9a Mon Sep 17 00:00:00 2001 From: "Adam J. Stewart" Date: Mon, 17 Oct 2022 11:14:55 -0500 Subject: [PATCH 084/442] py-horovod: add v0.26 (#33311) * py-horovod: add v0.26 * py-petastorm: add v0.12.0 --- var/spack/repos/builtin/packages/py-horovod/package.py | 5 +++++ var/spack/repos/builtin/packages/py-petastorm/package.py | 1 + 2 files changed, 6 insertions(+) diff --git a/var/spack/repos/builtin/packages/py-horovod/package.py b/var/spack/repos/builtin/packages/py-horovod/package.py index 866ba430afd..ef3c1415b2c 100644 --- a/var/spack/repos/builtin/packages/py-horovod/package.py +++ b/var/spack/repos/builtin/packages/py-horovod/package.py @@ -17,6 +17,8 @@ class PyHorovod(PythonPackage, CudaPackage): maintainers = ["adamjstewart", "aweits", "tgaddair"] version("master", branch="master", submodules=True) + version("0.26.1", tag="v0.26.1", submodules=True) + version("0.26.0", tag="v0.26.0", submodules=True) version("0.25.0", tag="v0.25.0", submodules=True) version("0.24.3", tag="v0.24.3", submodules=True) version("0.24.2", tag="v0.24.2", submodules=True) @@ -86,6 +88,7 @@ class PyHorovod(PythonPackage, CudaPackage): depends_on("py-pyyaml", type=("build", "run")) depends_on("py-six", type=("build", "run"), when="@:0.19") depends_on("py-dataclasses", type=("build", "run"), when="@0.20: ^python@:3.6") + depends_on("py-packaging", type=("build", "run"), when="@0.26:") # Framework dependencies depends_on("py-tensorflow@1.1.0:", type=("build", "link", "run"), when="frameworks=tensorflow") @@ -115,6 +118,7 @@ class PyHorovod(PythonPackage, CudaPackage): ) depends_on("py-petastorm@0.9.8:", type=("build", "run"), when="frameworks=spark @0.21.1:") depends_on("py-petastorm@0.11:", type=("build", "run"), when="frameworks=spark @0.22:") + depends_on("py-petastorm@0.12:", type=("build", "run"), when="frameworks=spark @0.26:") depends_on("py-pyarrow@0.15.0:", type=("build", "run"), when="frameworks=spark") depends_on("py-pyspark@2.3.2:", type=("build", "run"), when="frameworks=spark ^python@:3.7") depends_on("py-pyspark@3.0.0:", type=("build", "run"), when="frameworks=spark ^python@3.8:") @@ -122,6 +126,7 @@ class PyHorovod(PythonPackage, CudaPackage): depends_on("py-fsspec@2021.07:", type=("build", "run"), when="frameworks=spark @0.24.2:") depends_on("py-ray", type=("build", "run"), when="frameworks=ray") depends_on("py-aioredis@:1", type=("build", "run"), when="frameworks=ray @0.23:") + depends_on("py-google-api-core@:2.8", type=("build", "run"), when="frameworks=ray @0.26:") # Controller dependencies depends_on("mpi", when="controllers=mpi") diff --git a/var/spack/repos/builtin/packages/py-petastorm/package.py b/var/spack/repos/builtin/packages/py-petastorm/package.py index 65953b1466e..fbb7b191a33 100644 --- a/var/spack/repos/builtin/packages/py-petastorm/package.py +++ b/var/spack/repos/builtin/packages/py-petastorm/package.py @@ -16,6 +16,7 @@ class PyPetastorm(PythonPackage): maintainers = ["adamjstewart"] + version("0.12.0", sha256="79b98b87a619f34ca96a3dd42670506ce9439d321b3aab356cdf7edac8ff5c5c") version("0.11.4", sha256="7090dfc86f110e641d95798bcc75f8b1ca14cd56ed3feef491baaa6849629e51") version("0.9.8", sha256="571855224411b88b759ba5d48b288ad2ba09997ebd259292f72b9246144b8101") version("0.8.2", sha256="1bf4f26ce0b14f7334c0c29868154f1e600021a044f7565a5ad766b5ecdde911") From e7b14dd4911cee11b04c031cfc9ee096a1f5ea6f Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Mon, 17 Oct 2022 18:30:19 +0200 Subject: [PATCH 085/442] database: don't warn adding missing build deps (#33361) When installing an individual spec `spack --only=package --cache-only /xyz` from a buildcache, Spack currently issues tons of warnings about missing build deps (and their deps) in the database. This PR disables these warnings, since it's fine to have a spec without its build deps in the db (they are just "missing"). --- lib/spack/spack/database.py | 71 ++++++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 25 deletions(-) diff --git a/lib/spack/spack/database.py b/lib/spack/spack/database.py index df41459dff6..30ec4d8da0e 100644 --- a/lib/spack/spack/database.py +++ b/lib/spack/spack/database.py @@ -48,7 +48,10 @@ import spack.store import spack.util.lock as lk import spack.util.spack_json as sjson -from spack.directory_layout import DirectoryLayoutError +from spack.directory_layout import ( + DirectoryLayoutError, + InconsistentInstallDirectoryError, +) from spack.error import SpackError from spack.filesystem_view import YamlFilesystemView from spack.util.crypto import bit_length @@ -1063,7 +1066,14 @@ def _read(self): elif self.is_upstream: tty.warn("upstream not found: {0}".format(self._index_path)) - def _add(self, spec, directory_layout=None, explicit=False, installation_time=None): + def _add( + self, + spec, + directory_layout=None, + explicit=False, + installation_time=None, + allow_missing=False, + ): """Add an install record for this spec to the database. Assumes spec is installed in ``layout.path_for_spec(spec)``. @@ -1074,19 +1084,18 @@ def _add(self, spec, directory_layout=None, explicit=False, installation_time=No Args: spec: spec to be added directory_layout: layout of the spec installation - **kwargs: + explicit: + Possible values: True, False, any - explicit - Possible values: True, False, any - - A spec that was installed following a specific user - request is marked as explicit. If instead it was - pulled-in as a dependency of a user requested spec - it's considered implicit. - - installation_time - Date and time of installation + A spec that was installed following a specific user + request is marked as explicit. If instead it was + pulled-in as a dependency of a user requested spec + it's considered implicit. + installation_time: + Date and time of installation + allow_missing: if True, don't warn when installation is not found on on disk + This is useful when installing specs without build deps. """ if not spec.concrete: raise NonConcreteSpecAddError("Specs added to DB must be concrete.") @@ -1100,11 +1109,22 @@ def _add(self, spec, directory_layout=None, explicit=False, installation_time=No # Retrieve optional arguments installation_time = installation_time or _now() - for dep in spec.dependencies(deptype=_tracked_deps): - dkey = dep.dag_hash() - if dkey not in self._data: - extra_args = {"explicit": False, "installation_time": installation_time} - self._add(dep, directory_layout, **extra_args) + for edge in spec.edges_to_dependencies(deptype=_tracked_deps): + if edge.spec.dag_hash() in self._data: + continue + # allow missing build-only deps. This prevents excessive + # warnings when a spec is installed, and its build dep + # is missing a build dep; there's no need to install the + # build dep's build dep first, and there's no need to warn + # about it missing. + dep_allow_missing = allow_missing or edge.deptypes == ("build",) + self._add( + edge.spec, + directory_layout, + explicit=False, + installation_time=installation_time, + allow_missing=dep_allow_missing, + ) # Make sure the directory layout agrees whether the spec is installed if not spec.external and directory_layout: @@ -1115,13 +1135,14 @@ def _add(self, spec, directory_layout=None, explicit=False, installation_time=No installed = True self._installed_prefixes.add(path) except DirectoryLayoutError as e: - msg = ( - "{0} is being {1} in the database with prefix {2}, " - "but this directory does not contain an installation of " - "the spec, due to: {3}" - ) - action = "updated" if key in self._data else "registered" - tty.warn(msg.format(spec.short_spec, action, path, str(e))) + if not (allow_missing and isinstance(e, InconsistentInstallDirectoryError)): + msg = ( + "{0} is being {1} in the database with prefix {2}, " + "but this directory does not contain an installation of " + "the spec, due to: {3}" + ) + action = "updated" if key in self._data else "registered" + tty.warn(msg.format(spec.short_spec, action, path, str(e))) elif spec.external_path: path = spec.external_path installed = True From 2e55812417398ea2fcb2f9e8d75cf7c86b9095d2 Mon Sep 17 00:00:00 2001 From: Stephen Sachs Date: Mon, 17 Oct 2022 18:46:11 +0200 Subject: [PATCH 086/442] Classic Intel compilers do not support gcc-toolchain (#33281) * Classic Intel compilers do not support gcc-toolchain This fix removes `--gcc-toolchain=` from the ~.fcg` files for the classic Intel compilers. AFAIK this option is only supported for Clang based compilers. This lead to an issue when installing cmake. Reproducer: ``` spack install cmake@3.24.2%intel@2021.7.0~doc+ncurses+ownlibs~qt build_type=Release arch=linux-amzn2-skylake_avx512 ``` Tagging maintainer @rscohn2 * Add `-gcc-name` for icc .. and `-gxx-name` for icpc. AFAIK this is used for modern C++ support, so we can ignore `ifort`. Co-authored-by: Stephen Sachs --- .../intel-oneapi-compilers/package.py | 41 ++++++++++++------- 1 file changed, 26 insertions(+), 15 deletions(-) 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 df40c94f8a9..0ad8d3921d7 100644 --- a/var/spack/repos/builtin/packages/intel-oneapi-compilers/package.py +++ b/var/spack/repos/builtin/packages/intel-oneapi-compilers/package.py @@ -131,7 +131,7 @@ class IntelOneapiCompilers(IntelOneApiPackage): placement="fortran-installer", when="@{0}".format(v["version"]), expand=False, - **v["ftn"] + **v["ftn"], ) @property @@ -206,21 +206,32 @@ def extend_config_flags(self): if self.spec.version < Version("2022.1.0"): flags_list.append("-Wno-unused-command-line-argument") + def write_cfg(cmp_list, flags_list): + flags = " ".join(flags_list) + for cmp in cmp_list: + cfg_file = self.component_prefix.linux.bin.join(cmp + ".cfg") + with open(cfg_file, "w") as f: + f.write(flags) + set_install_permissions(cfg_file) + + # Make sure that icc gets the right GCC C+ support + write_cfg( + [ + join_path("intel64", "icc"), + ], + flags_list + ["-gcc-name={}".format(self.compiler.cc)], + ) + write_cfg( + [ + join_path("intel64", "icpc"), + ], + flags_list + ["-gxx-name={}".format(self.compiler.cxx)], + ) # Make sure that underlying clang gets the right GCC toolchain by default - flags_list.append("--gcc-toolchain={}".format(self.compiler.prefix)) - flags = " ".join(flags_list) - for cmp in [ - "icx", - "icpx", - "ifx", - join_path("intel64", "icc"), - join_path("intel64", "icpc"), - join_path("intel64", "ifort"), - ]: - cfg_file = self.component_prefix.linux.bin.join(cmp + ".cfg") - with open(cfg_file, "w") as f: - f.write(flags) - set_install_permissions(cfg_file) + write_cfg( + ["icx", "icpx", "ifx"], + flags_list + ["--gcc-toolchain={}".format(self.compiler.prefix)], + ) def _ld_library_path(self): # Returns an iterable of directories that might contain shared runtime libraries From fb090a69f4ead786c5b0e016f402bb4d782ab313 Mon Sep 17 00:00:00 2001 From: Luke Diorio-Toth Date: Mon, 17 Oct 2022 14:16:09 -0500 Subject: [PATCH 087/442] py-xopen: version bump to 1.6.0 (#33231) * version bump to 1.6.0 * added py-isal, updated URL --- .../repos/builtin/packages/py-isal/package.py | 21 +++++++++++++++++++ .../builtin/packages/py-xopen/package.py | 8 ++++++- 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 var/spack/repos/builtin/packages/py-isal/package.py diff --git a/var/spack/repos/builtin/packages/py-isal/package.py b/var/spack/repos/builtin/packages/py-isal/package.py new file mode 100644 index 00000000000..3a4efa4ef78 --- /dev/null +++ b/var/spack/repos/builtin/packages/py-isal/package.py @@ -0,0 +1,21 @@ +# 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 PyIsal(PythonPackage): + """Faster zlib and gzip compatible compression and decompression by + providing Python bindings for the ISA-L library.""" + + homepage = "https://github.com/pycompression/python-isal" + pypi = "isal/isal-1.1.0.tar.gz" + + version("1.1.0", sha256="1364f4e3255a57d51c01422ab3ae785a43c076d516ebf49f6a25adecf8232105") + version("1.0.0", sha256="a30369de6852109eef8ca1bdd46d7e4b5c4517846a25acfc707cbb19db66ac80") + + depends_on("python@3.7:", type=("build", "run")) + depends_on("py-setuptools@51:", type="build") diff --git a/var/spack/repos/builtin/packages/py-xopen/package.py b/var/spack/repos/builtin/packages/py-xopen/package.py index 801dcd5da93..22ce0369e03 100644 --- a/var/spack/repos/builtin/packages/py-xopen/package.py +++ b/var/spack/repos/builtin/packages/py-xopen/package.py @@ -12,9 +12,11 @@ class PyXopen(PythonPackage): compression formats are gzip, bzip2 and xz. They are automatically recognized by their file extensions .gz, .bz2 or .xz.""" - homepage = "https://github.com/marcelm/xopen" + homepage = "https://github.com/pycompression/xopen" pypi = "xopen/xopen-0.1.1.tar.gz" + version("1.6.0", sha256="72219a4d690e9c90ad445c45d2119ae2a6d5d38912255631e227aceac6294353") + version("1.1.0", sha256="38277eb96313b2e8822e19e793791801a1f41bf13ee5b48616a97afc65e9adb3") version("1.0.1", sha256="79d7e425fb0930b0153eb6beba9a540ca3e07ac254ca828577ad2e8fa24105dc") version("0.9.0", sha256="1e3918c8a5cd2bd128ba05b3b883ee322349219c99c305e10114638478e3162a") version("0.8.4", sha256="dcd8f5ef5da5564f514a990573a48a0c347ee1fdbb9b6374d31592819868f7ba") @@ -22,9 +24,13 @@ class PyXopen(PythonPackage): version("0.5.0", sha256="b097cd25e8afec42b6e1780c1f6315016171b5b6936100cdf307d121e2cbab9f") version("0.1.1", sha256="d1320ca46ed464a59db4c27c7a44caf5e268301e68319f0295d06bf6a9afa6f3") + depends_on("python@3.7:", type=("build", "run"), when="@1.5.0:") + depends_on("python@3.6:", type=("build", "run"), when="@1.1.0:") depends_on("python@3.5:", type=("build", "run"), when="@0.9.0:") depends_on("python@2.7,3.4:", type=("build", "run"), when="@0.5:0.8") depends_on("python@2.6:2,3.3:", type=("build", "run"), when="@0.1.1") depends_on("py-setuptools", type="build") + depends_on("py-setuptools-scm@6.2:", type="build", when="@1.2.0:") depends_on("py-setuptools-scm", type="build") + depends_on("py-isal@1.0.0:", type=("build", "run"), when="@1.6.0: target=x86_64:") depends_on("py-bz2file", type=("build", "run"), when="@0.5: ^python@:2.8") From da6aeaad44e434da5563d32f2fa9900de362b2ed Mon Sep 17 00:00:00 2001 From: Robert Underwood Date: Mon, 17 Oct 2022 15:30:54 -0400 Subject: [PATCH 088/442] Initial contribution of LibPressio ecosystem (#32630) * Add libpressio and dependencies; some of these packages are maintained as forks of the original repositories and in those cases the docstring mentions this. * Add optional dependency in adios2 on libpressio * cub package: set CUB_DIR environment variable for dependent installations * Clear R_HOME/R_ENVIRON before Spack installation (avoid sources outside of Spack from affecting the installation in Spack) * Rename dlib to dorian3d-dlib and update dependents; add new dlib implementation. Pending an official policy on how to handle packages with short names, reviewer unilaterally decided that the rename was acceptable given that the new Spack dlib package is referenced more widely (by orders of magnitude) than the original Co-authored-by: Samuel Li --- lib/spack/spack/build_environment.py | 2 + .../repos/builtin/packages/adios2/package.py | 5 + .../repos/builtin/packages/arc/package.py | 37 ++ .../builtin/packages/bitgroomingz/package.py | 30 ++ .../repos/builtin/packages/cub/package.py | 3 + .../repos/builtin/packages/cusz/package.py | 31 +- .../repos/builtin/packages/dbow2/package.py | 2 +- .../builtin/packages/digitrounding/package.py | 30 ++ .../repos/builtin/packages/dlib/package.py | 35 +- .../builtin/packages/dorian3d-dlib/package.py | 21 ++ .../repos/builtin/packages/fpzip/package.py | 19 + .../packages/libdistributed/package.py | 50 +++ .../packages/libpressio-adios2/package.py | 29 ++ .../libpressio-errorinjector/package.py | 25 ++ .../packages/libpressio-nvcomp/package.py | 30 ++ .../packages/libpressio-opt/package.py | 49 +++ .../packages/libpressio-rmetric/package.py | 43 +++ .../packages/libpressio-sperr/package.py | 25 ++ .../packages/libpressio-tools/package.py | 100 ++++++ .../packages/libpressio-tthresh/package.py | 39 +++ .../builtin/packages/libpressio/package.py | 331 ++++++++++++++++++ .../builtin/packages/libstdcompat/package.py | 98 ++++++ .../repos/builtin/packages/mgard/package.py | 45 +++ .../repos/builtin/packages/mgardx/package.py | 35 ++ .../repos/builtin/packages/ndzip/package.py | 40 +++ .../repos/builtin/packages/nvcomp/package.py | 34 ++ .../repos/builtin/packages/qcat/package.py | 24 ++ .../repos/builtin/packages/qoz/package.py | 28 ++ .../builtin/packages/r-libpressio/package.py | 36 ++ var/spack/repos/builtin/packages/r/package.py | 3 + .../repos/builtin/packages/sam2p/package.py | 25 ++ .../repos/builtin/packages/sperr/package.py | 43 +++ .../repos/builtin/packages/sz-cpp/package.py | 29 ++ .../repos/builtin/packages/sz3/package.py | 31 ++ .../repos/builtin/packages/szauto/package.py | 23 ++ 35 files changed, 1407 insertions(+), 23 deletions(-) create mode 100644 var/spack/repos/builtin/packages/arc/package.py create mode 100644 var/spack/repos/builtin/packages/bitgroomingz/package.py create mode 100644 var/spack/repos/builtin/packages/digitrounding/package.py create mode 100644 var/spack/repos/builtin/packages/dorian3d-dlib/package.py create mode 100644 var/spack/repos/builtin/packages/fpzip/package.py create mode 100644 var/spack/repos/builtin/packages/libdistributed/package.py create mode 100644 var/spack/repos/builtin/packages/libpressio-adios2/package.py create mode 100644 var/spack/repos/builtin/packages/libpressio-errorinjector/package.py create mode 100644 var/spack/repos/builtin/packages/libpressio-nvcomp/package.py create mode 100644 var/spack/repos/builtin/packages/libpressio-opt/package.py create mode 100644 var/spack/repos/builtin/packages/libpressio-rmetric/package.py create mode 100644 var/spack/repos/builtin/packages/libpressio-sperr/package.py create mode 100644 var/spack/repos/builtin/packages/libpressio-tools/package.py create mode 100644 var/spack/repos/builtin/packages/libpressio-tthresh/package.py create mode 100644 var/spack/repos/builtin/packages/libpressio/package.py create mode 100644 var/spack/repos/builtin/packages/libstdcompat/package.py create mode 100644 var/spack/repos/builtin/packages/mgard/package.py create mode 100644 var/spack/repos/builtin/packages/mgardx/package.py create mode 100644 var/spack/repos/builtin/packages/ndzip/package.py create mode 100644 var/spack/repos/builtin/packages/nvcomp/package.py create mode 100644 var/spack/repos/builtin/packages/qcat/package.py create mode 100644 var/spack/repos/builtin/packages/qoz/package.py create mode 100644 var/spack/repos/builtin/packages/r-libpressio/package.py create mode 100644 var/spack/repos/builtin/packages/sam2p/package.py create mode 100644 var/spack/repos/builtin/packages/sperr/package.py create mode 100644 var/spack/repos/builtin/packages/sz-cpp/package.py create mode 100644 var/spack/repos/builtin/packages/sz3/package.py create mode 100644 var/spack/repos/builtin/packages/szauto/package.py diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py index 63b1309a221..f8fda997d3f 100644 --- a/lib/spack/spack/build_environment.py +++ b/lib/spack/spack/build_environment.py @@ -201,6 +201,8 @@ def clean_environment(): env.unset("CMAKE_PREFIX_PATH") env.unset("PYTHONPATH") + env.unset("R_HOME") + env.unset("R_ENVIRON") # Affects GNU make, can e.g. indirectly inhibit enabling parallel build # env.unset('MAKEFLAGS') diff --git a/var/spack/repos/builtin/packages/adios2/package.py b/var/spack/repos/builtin/packages/adios2/package.py index 39568376e85..dd4708b841a 100644 --- a/var/spack/repos/builtin/packages/adios2/package.py +++ b/var/spack/repos/builtin/packages/adios2/package.py @@ -60,6 +60,9 @@ class Adios2(CMakePackage, CudaPackage): variant("mpi", default=True, description="Enable MPI") # Compression libraries + variant( + "libpressio", default=False, when="@2.8:", description="Enable LibPressio for compression" + ) variant("blosc", default=True, when="@2.4:", description="Enable Blosc compression") variant("bzip2", default=True, when="@2.4:", description="Enable BZip2 compression") variant("zfp", default=True, description="Enable ZFP compression") @@ -103,6 +106,7 @@ class Adios2(CMakePackage, CudaPackage): depends_on("hdf5~mpi", when="+hdf5~mpi") depends_on("hdf5+mpi", when="+hdf5+mpi") + depends_on("libpressio", when="+libpressio") depends_on("c-blosc", when="+blosc") depends_on("bzip2", when="+bzip2") depends_on("libpng@1.6:", when="+png") @@ -178,6 +182,7 @@ def cmake_args(self): from_variant("ADIOS2_USE_SZ", "sz"), from_variant("ADIOS2_USE_ZFP", "zfp"), from_variant("ADIOS2_USE_CUDA", "cuda"), + from_variant("ADIOS2_USE_LIBPRESSIO", "libpressio"), self.define("BUILD_TESTING", self.run_tests), self.define("ADIOS2_BUILD_EXAMPLES", False), self.define("ADIOS2_USE_Endian_Reverse", True), diff --git a/var/spack/repos/builtin/packages/arc/package.py b/var/spack/repos/builtin/packages/arc/package.py new file mode 100644 index 00000000000..5d2349ca3e9 --- /dev/null +++ b/var/spack/repos/builtin/packages/arc/package.py @@ -0,0 +1,37 @@ +# 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 Arc(CMakePackage): + """ARC is an automatic resiliency library designed to provide security + to lossy compressed data or other uint8_t data arrays + + forked from: https://github.com/FTHPC/ARC to support Spack after developer + left grad school + """ + + homepage = "https://github.com/FTHPC/ARC" + url = "https://github.com/FTHPC/ARC" + git = "https://github.com/robertu94/ARC" + + maintainers = ["robertu94"] + + version("master", branch="master") + version("2021-12-01", commit="49d4a5df53a082f15a6959aef434224fd7b9beac") + + depends_on("libpressio+sz+zfp", when="+examples") + + variant("examples", description="build examples", default=False) + variant("shared", description="build shared libraries", default=True) + + def cmake_args(self): + args = [ + self.define("BUILD_TESTING", self.run_tests), + self.define_from_variant("BUILD_SHARED_LIBS", "shared"), + self.define_from_variant("BUILD_EXAMPLES", "examples"), + ] + return args diff --git a/var/spack/repos/builtin/packages/bitgroomingz/package.py b/var/spack/repos/builtin/packages/bitgroomingz/package.py new file mode 100644 index 00000000000..c10a4f15df9 --- /dev/null +++ b/var/spack/repos/builtin/packages/bitgroomingz/package.py @@ -0,0 +1,30 @@ +# 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 Bitgroomingz(CMakePackage): + """BGZ: Bit Grooming Compressor""" + + homepage = "https://github.com/disheng222/BitGroomingZ" + git = "https://github.com/disheng222/BitGroomingZ" + + maintainers = ["robertu94"] + + version("master", branch="master") + version("2022-10-14", commit="a018b20cca9f7d6a5396ab36230e4be6ae1cb25b") + + variant("shared", default=True, description="build shared libs") + + depends_on("zlib") + + def cmake_args(self): + args = [] + if "+shared" in self.spec: + args.append("-DBUILD_SHARED_LIBS=ON") + else: + args.append("-DBUILD_SHARED_LIBS=OFF") + return args diff --git a/var/spack/repos/builtin/packages/cub/package.py b/var/spack/repos/builtin/packages/cub/package.py index c704b47319f..ad115965cbf 100644 --- a/var/spack/repos/builtin/packages/cub/package.py +++ b/var/spack/repos/builtin/packages/cub/package.py @@ -39,6 +39,9 @@ class Cub(Package): version("1.7.1", sha256="50b8777b83093fdfdab429a61fccdbfbbb991b3bbc08385118e5ad58e8f62e1d") version("1.4.1", sha256="7c3784cf59f02d4a88099d6a11e357032bac9eac2b9c78aaec947d1270e21871") + def setup_dependent_build_environment(self, env, dependent_spec): + env.set("CUB_DIR", self.prefix.include.cub.cmake) + def install(self, spec, prefix): mkdirp(prefix.include) install_tree("cub", join_path(prefix.include, "cub")) diff --git a/var/spack/repos/builtin/packages/cusz/package.py b/var/spack/repos/builtin/packages/cusz/package.py index 8a9e1358e50..2c1e78b4b06 100644 --- a/var/spack/repos/builtin/packages/cusz/package.py +++ b/var/spack/repos/builtin/packages/cusz/package.py @@ -6,19 +6,24 @@ from spack.package import * -class Cusz(MakefilePackage): - """cuSZ is a CUDA-based error-bounded lossy compressor for scientific - data (floating point and integers). - """ +class Cusz(CMakePackage, CudaPackage): + """A GPU accelerated error-bounded lossy compression for scientific data""" - homepage = "https://szcompressor.org" - url = "https://github.com/szcompressor/cuSZ/releases/download/v0.1.2/cuSZ-0.1.2.tar.gz" - git = "https://github.com/szcompressor/cuSZ" - maintainers = ["dingwentao", "jtian0"] + homepage = "https://szcompressor.org/" + git = "https://github.com/szcompressor/cusz" + url = "https://github.com/szcompressor/cuSZ/archive/refs/tags/v0.3.tar.gz" - version("master", branch="master") - version("0.1.2", sha256="c6e89a26b295724edefc8052f62653c5a315c78eaf6d5273299a8e11a5cf7363") + maintainers = ["jtian0", "dingwentao"] - def install(self, spec, prefix): - mkdir(prefix.bin) - install("bin/cusz", prefix.bin) + conflicts("~cuda") + conflicts("cuda_arch=none", when="+cuda") + + version("develop", branch="develop") + version("0.3", sha256="0feb4f7fd64879fe147624dd5ad164adf3983f79b2e0383d35724f8d185dcb11") + + depends_on("cub", when="^ cuda@:10.2.89") + + def cmake_args(self): + cuda_arch = self.spec.variants["cuda_arch"].value + args = ["-DBUILD_TESTING=OFF", ("-DCMAKE_CUDA_ARCHITECTURES=%s" % cuda_arch)] + return args diff --git a/var/spack/repos/builtin/packages/dbow2/package.py b/var/spack/repos/builtin/packages/dbow2/package.py index 90c3f9f1c16..0851eff37a1 100644 --- a/var/spack/repos/builtin/packages/dbow2/package.py +++ b/var/spack/repos/builtin/packages/dbow2/package.py @@ -24,5 +24,5 @@ class Dbow2(CMakePackage): # See https://github.com/spack/spack/pull/22303 for reference depends_on(Boost.with_default_variants) depends_on("opencv+calib3d+features2d+highgui+imgproc") - depends_on("dlib") + depends_on("dorian3d-dlib") depends_on("eigen", type="link") diff --git a/var/spack/repos/builtin/packages/digitrounding/package.py b/var/spack/repos/builtin/packages/digitrounding/package.py new file mode 100644 index 00000000000..3351bdf0f42 --- /dev/null +++ b/var/spack/repos/builtin/packages/digitrounding/package.py @@ -0,0 +1,30 @@ +# 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 Digitrounding(CMakePackage): + """Standalone version of Digit rounding compressor""" + + homepage = "https://github.com/disheng222/digitroundingZ" + git = "https://github.com/disheng222/digitroundingZ" + + maintainers = ["robertu94"] + + version("master", branch="master") + version("2020-02-27", commit="7b18679aded7a85e6f221f7f5cd4f080f322bc33") + + depends_on("zlib") + + variant("shared", default=True, description="build shared libraries") + + def cmake_args(self): + args = [] + if "+shared" in self.spec: + args.append("-DBUILD_SHARED_LIBS=ON") + else: + args.append("-DBUILD_SHARED_LIBS=OFF") + return args diff --git a/var/spack/repos/builtin/packages/dlib/package.py b/var/spack/repos/builtin/packages/dlib/package.py index d733d00ff9f..61813a7e828 100644 --- a/var/spack/repos/builtin/packages/dlib/package.py +++ b/var/spack/repos/builtin/packages/dlib/package.py @@ -2,20 +2,37 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - - from spack.package import * class Dlib(CMakePackage): - """DLib is a collection of C++ classes to solve common tasks in C++ - programs, as well as to offer additional functionality to use OpenCV - data and to solve computer vision problems.""" + """toolkit containing machine learning algorithms and tools + for creating complex software in C++ to solve real world problems""" - homepage = "https://github.com/dorian3d/DLib" - git = "https://github.com/dorian3d/DLib.git" + homepage = "http://dlib.net/" + url = "https://github.com/davisking/dlib/archive/v19.19.tar.gz" + git = "https://github.com/davisking/dlib" + + maintainer = ["robertu94"] version("master", branch="master") + version("19.22", sha256="5f44b67f762691b92f3e41dcf9c95dd0f4525b59cacb478094e511fdacb5c096") + version("19.21", sha256="116f52e58be04b47dab52057eaad4b5c4d5c3032d927fe23d55b0741fc4107a0") + version("19.20", sha256="fc3f0986350e8e53aceadf95a71d2f413f1eedc469abda99a462cb528741d411") + version("19.19", sha256="7af455bb422d3ae5ef369c51ee64e98fa68c39435b0fa23be2e5d593a3d45b87") - depends_on("cmake@3.0:", type="build") - depends_on("opencv+calib3d+features2d+highgui+imgproc+imgcodecs+flann") + variant("shared", default=True, description="build the shared libraries") + + depends_on("zlib") + depends_on("libpng") + depends_on("libjpeg") + depends_on("blas") + depends_on("lapack") + depends_on("libsm") + depends_on("libx11") + + def cmake_args(self): + args = [] + if "+shared" in self.spec: + args.append("-DBUILD_SHARED_LIBS=ON") + return args diff --git a/var/spack/repos/builtin/packages/dorian3d-dlib/package.py b/var/spack/repos/builtin/packages/dorian3d-dlib/package.py new file mode 100644 index 00000000000..c71d7d32ded --- /dev/null +++ b/var/spack/repos/builtin/packages/dorian3d-dlib/package.py @@ -0,0 +1,21 @@ +# 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 Dorian3dDlib(CMakePackage): + """DLib is a collection of C++ classes to solve common tasks in C++ + programs, as well as to offer additional functionality to use OpenCV + data and to solve computer vision problems.""" + + homepage = "https://github.com/dorian3d/DLib" + git = "https://github.com/dorian3d/DLib.git" + + version("master", branch="master") + + depends_on("cmake@3.0:", type="build") + depends_on("opencv+calib3d+features2d+highgui+imgproc+imgcodecs+flann") diff --git a/var/spack/repos/builtin/packages/fpzip/package.py b/var/spack/repos/builtin/packages/fpzip/package.py new file mode 100644 index 00000000000..46d30da2a5d --- /dev/null +++ b/var/spack/repos/builtin/packages/fpzip/package.py @@ -0,0 +1,19 @@ +# 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 Fpzip(CMakePackage): + """fpzip compressor""" + + homepage = "https://github.com/llnl/fpzip" + url = "https://github.com/LLNL/fpzip/releases/download/1.3.0/fpzip-1.3.0.tar.gz" + git = "https://github.com/llnl/fpzip" + + maintainers = ["robertu94"] + + version("master", branch="master") + version("1.3.0", sha256="248df7d84259e3feaa4c4797956b2a77c3fcd734e8f8fdc51ce171dcf4f0136c") diff --git a/var/spack/repos/builtin/packages/libdistributed/package.py b/var/spack/repos/builtin/packages/libdistributed/package.py new file mode 100644 index 00000000000..3d442b1c608 --- /dev/null +++ b/var/spack/repos/builtin/packages/libdistributed/package.py @@ -0,0 +1,50 @@ +# 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 Libdistributed(CMakePackage): + """a collection of facilities for MPI that create for higher level + facilities for programming in C++""" + + homepage = "https://github.com/robertu94/libdistributed" + url = "https://github.com/robertu94/libdistributed/archive/0.0.3.tar.gz" + git = "https://github.com/robertu94/libdistributed" + + maintainers = ["robertu94"] + + version("master", branch="master") + version("0.4.0", sha256="7895d268c4f9b5444e4378f60b5a28198720bc48633d0e5d072c39e3366b096c") + version("0.3.0", sha256="57443c72a5a9aa57d7f8760c878a77dcffca0b3b5ccf5124cdf5c1fad8a44ae8") + version("0.2.0", sha256="4540136d39f98a21c59a7e127cb0568266747bfff886edf0f0007be4959a09a3") + version("0.1.2", sha256="c22f93e6ea781ea33812481b19c7bc5e688e51f91991debc7f27a493ef2c78b3") + version("0.1.1", sha256="a5201fd754588034e2c87a21f0283dd9fda758d7820450179eabd68b3dae8cb6") + version("0.1.0", sha256="e10daa6d4a6dc371057e92d2b706ae16450b41ed7c0d386cffeb68e160f556c1") + version("0.0.10", sha256="3af4ce81b3ae016e80e401adfcfad856e15a76da4d2a81535cb4bd993c11104b") + version("0.0.8", sha256="78bc1fbc99e46ea0e03cb181623262be0f527767efd3249baa249cb24b794762") + version("0.0.7", sha256="b2c65752df7bc55fcdc9a5eb7b36c203667f2fb6382d3eaecdaf1504421d4d7b") + version("0.0.6", sha256="05ce6ae880aec19f6945ee5f3c2f4099343ca6b555ea6c8e005a48a6e09faf5b") + version("0.0.5", sha256="09c1e9a0b34371fa8e6f3d50671bcce7fcc3e4c7c26f3e19017b07b64695d199") + version("0.0.4", sha256="7813980011091822534d196d372b8cb6fdc12d35acd5acb42c6eeeaf10a44490") + version("0.0.3", sha256="c476b3efe20e1af4c976e89ff81b7eed01ddddae73ac66f005108747facbeff7") + version("0.0.2", sha256="c25309108fe17021fd5f06ba98386210708158c439e98326e68f66c42875e58a") + version("0.0.1", sha256="4c23ce0fd70a12ee5f8760ea00377ab6370d86b30ab42476e07453b19ea4ac44") + + depends_on("mpi@2:") + depends_on("libstdcompat@0.0.2:", when="@0.1.0:") + + def cmake_args(self): + args = [] + if self.run_tests: + args.append("-DBUILD_TESTING=ON") + else: + args.append("-DBUILD_TESTING=OFF") + return args + + @run_after("build") + @on_package_attributes(run_tests=True) + def test(self): + make("test") diff --git a/var/spack/repos/builtin/packages/libpressio-adios2/package.py b/var/spack/repos/builtin/packages/libpressio-adios2/package.py new file mode 100644 index 00000000000..dbd06a79738 --- /dev/null +++ b/var/spack/repos/builtin/packages/libpressio-adios2/package.py @@ -0,0 +1,29 @@ +# 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 LibpressioAdios2(CMakePackage): + """An IO plugin to read/write ADIOS2 files for LibPressio""" + + homepage = "https://github.com/robertu94/libpressio_adios2" + url = "https://github.com/robertu94/libpressio_adios2/archive/refs/tags/0.0.1.tar.gz" + + maintainers = ["robertu94"] + + version("0.0.2", sha256="8ab4b5a0dd8038d52f54aa9b5a67b83a8f7cd096db4c5a413fe0c6caf678e402") + version("0.0.1", sha256="ab9c7e26114e8d81f8ad8aca703855079cd3441f9b72e01d9b4aeb0c57ce0746") + + depends_on("libpressio@0.85.0:+mpi", when="@0.0.2") + depends_on("libpressio@0.60.0:+mpi") + depends_on("adios2@2.8.0:+mpi") + + def cmake_args(self): + args = [ + self.define("BUILD_TESTING", self.run_tests), + self.define("LIBPRESSIO_ADIOS2_WERROR", False), + ] + return args diff --git a/var/spack/repos/builtin/packages/libpressio-errorinjector/package.py b/var/spack/repos/builtin/packages/libpressio-errorinjector/package.py new file mode 100644 index 00000000000..ce75a977ac6 --- /dev/null +++ b/var/spack/repos/builtin/packages/libpressio-errorinjector/package.py @@ -0,0 +1,25 @@ +# 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 LibpressioErrorinjector(CMakePackage): + """LibPressioErrorInjector injects errors into data for sensitivity studies""" + + homepage = "https://github.com/robertu94/libpressio-errorinjector" + git = "https://github.com/robertu94/libpressio-errorinjector" + + maintainers = ["robertu94"] + + version("0.8.0", commit="0bfac9a06b1ae34a872b8b599dd4ccb46aa2db4e") + version("0.7.0", commit="0b5a5b15121be248a3e5af925f9ad88b3d43fef6") + + depends_on("libpressio@0.88.0:", when="@0.8.0:") + depends_on("libpressio@:0.87.0", when="@:0.7.0") + + def cmake_args(self): + args = ["-DBUILD_TESTING=OFF"] + return args diff --git a/var/spack/repos/builtin/packages/libpressio-nvcomp/package.py b/var/spack/repos/builtin/packages/libpressio-nvcomp/package.py new file mode 100644 index 00000000000..7688b3c5017 --- /dev/null +++ b/var/spack/repos/builtin/packages/libpressio-nvcomp/package.py @@ -0,0 +1,30 @@ +# 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 LibpressioNvcomp(CMakePackage, CudaPackage): + """LibPressio Bindings for NVCOMP""" + + homepage = "https://github.com/robertu94/libpressio-nvcomp" + url = "https://github.com/robertu94/libpressio-nvcomp/archive/refs/tags/0.0.3.tar.gz" + git = "https://github.com/robertu94/libpressio-nvcomp" + + maintainers = ["robertu94"] + + version("0.0.3", sha256="21409d34f9281bfd7b83b74f5f8fc6d34794f3161391405538c060fb59534597") + version("0.0.2", commit="38d7aa7c283681cbe5b7f17b900f72f9f25be51c") + + depends_on("nvcomp@2.2.0:", when="@0.0.3:") + depends_on("libpressio@0.88.0:", when="@:0.0.2") + + conflicts("~cuda") + conflicts("cuda_arch=none", when="+cuda") + + def cmake_args(self): + cuda_arch = self.spec.variants["cuda_arch"].value + args = [("-DCMAKE_CUDA_ARCHITECTURES=%s" % cuda_arch)] + return args diff --git a/var/spack/repos/builtin/packages/libpressio-opt/package.py b/var/spack/repos/builtin/packages/libpressio-opt/package.py new file mode 100644 index 00000000000..4c988b63723 --- /dev/null +++ b/var/spack/repos/builtin/packages/libpressio-opt/package.py @@ -0,0 +1,49 @@ +# 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 LibpressioOpt(CMakePackage): + """Metacompressor which preforms optimization of compressor settings for LibPressio""" + + homepage = "https://github.com/robertu94/libpressio_opt" + git = "git@github.com:robertu94/libpressio_opt" + url = "https://github.com/robertu94/libpressio_opt/archive/refs/tags/0.11.0.tar.gz" + + maintainers = ["robertu94"] + + version("develop", branch="develop") + version("sdr-develop", branch="develop", git="git@github.com:szcompressor/SDRFramework") + version("0.13.5", sha256="cc0e6a46335aa3552b8ab57757d39855f4fba71e661f706ec99519cb2c8a2f3c") + version("0.13.4", sha256="e9f715d11fe3558a31e1d9a939150209449ec8636ded047cb0adcd3db07569ae") + version("0.13.3", sha256="98436b7fa6a53dd9cc09a9b978dc81c299501930cb8b844713080fc42d39d173") + version("0.13.2", sha256="8a16ba23b5078b0ee3a75d8a64ba64b492ecfadc221dd28ae463f4d3f4f7d847") + version("0.13.1", sha256="a831d326871c183a7e64b2015d687da3f17cf89c2d7d1d6770e3acbc1346aa8c") + version("0.13.0", sha256="6a64116dd6727e2dc05840b0e804fcaf82debde09c69e4905197462a769e998e") + version("0.12.1", sha256="e5d0b4d8b4885dfe555148e23f34e0bc904a898871dea8d412265075f1f8c858") + version("0.12.0", sha256="5f28f37de858634cf481d911f202360f078902803f82b5f49b7eec9b59948d64") + version("0.11.0", sha256="cebbc512fcaa537d2af1a6919d6e0400cdc13595d71d9b90b74ad3eb865c9767") + + depends_on("libpressio+libdistributed+mpi") + depends_on("libpressio@0.88.0:", when="@0.13.5:") + depends_on("libpressio@0.85.0:", when="@0.13.3:") + depends_on("libpressio@0.66.1:", when="@:0.13.2") + depends_on("libdistributed@0.0.11:") + depends_on("libdistributed@0.4.0:", when="@0.13.3:") + depends_on("dlib@19.22:") + + def cmake_args(self): + args = [] + if self.run_tests: + args.append("-DBUILD_TESTING=ON") + else: + args.append("-DBUILD_TESTING=OFF") + return args + + @run_after("build") + @on_package_attributes(run_tests=True) + def test(self): + make("test") diff --git a/var/spack/repos/builtin/packages/libpressio-rmetric/package.py b/var/spack/repos/builtin/packages/libpressio-rmetric/package.py new file mode 100644 index 00000000000..4a916904e58 --- /dev/null +++ b/var/spack/repos/builtin/packages/libpressio-rmetric/package.py @@ -0,0 +1,43 @@ +# 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 LibpressioRmetric(CMakePackage): + """LibPressio metric that runs R code""" + + url = "https://github.com/robertu94/libpressio-rmetric/archive/refs/tags/0.0.2.tar.gz" + git = "https://github.com/robertu94/libpressio-rmetric" + homepage = git + + maintainers = ["robertu94"] + + version("master", branch="master") + # note versions <= 0.0.3 do not build with spack + version("0.0.6", sha256="b23a79448cd32b51a7301d6cebf4e228289712dd77dd76d86821741467e9af46") + version("0.0.5", sha256="51eb192314ef083790dd0779864cab527845bd8de699b3a33cd065c248eae24c") + version("0.0.4", sha256="166af5e84d7156c828a3f0dcc5bf531793ea4ec44bbf468184fbab96e1f0a91f") + version("0.0.3", sha256="c45948f83854c87748c7ec828ca2f06d7cf6f98a34f763b68c13a4e2deb7fd79") + + depends_on("libpressio@0.88.0:", when="@0.0.5:") + depends_on("libpressio@0.85.0:", when="@:0.0.4") + depends_on("r") + depends_on("r-rcpp") + depends_on("r-rinside") + + def cmake_args(self): + args = [] + if self.run_tests: + args.append("-DBUILD_TESTING=ON") + else: + args.append("-DBUILD_TESTING=OFF") + + return args + + @run_after("build") + @on_package_attributes(run_tests=True) + def test(self): + make("test") diff --git a/var/spack/repos/builtin/packages/libpressio-sperr/package.py b/var/spack/repos/builtin/packages/libpressio-sperr/package.py new file mode 100644 index 00000000000..36a01c7531b --- /dev/null +++ b/var/spack/repos/builtin/packages/libpressio-sperr/package.py @@ -0,0 +1,25 @@ +# 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 LibpressioSperr(CMakePackage): + """A LibPressio plugin for Sperr""" + + homepage = "https://github.com/robertu94/libpressio-sperr" + url = "https://github.com/robertu94/libpressio-sperr/archive/refs/tags/0.0.1.tar.gz" + git = homepage + + maintainers = ["robertu94"] + + depends_on("libpressio@0.88.0:", when="@0.0.3:") + depends_on("libpressio@:0.88.0", when="@:0.0.2") + depends_on("sperr") + depends_on("pkgconfig", type="build") + + version("master", branch="master") + version("0.0.2", sha256="61995d687f9e7e798e17ec7238d19d917890dc0ff5dec18293b840c4d6f8c115") + version("0.0.1", sha256="e2c164822708624b97654046b42abff704594cba6537d6d0646d485bdf2d03ca") diff --git a/var/spack/repos/builtin/packages/libpressio-tools/package.py b/var/spack/repos/builtin/packages/libpressio-tools/package.py new file mode 100644 index 00000000000..bda9019fd48 --- /dev/null +++ b/var/spack/repos/builtin/packages/libpressio-tools/package.py @@ -0,0 +1,100 @@ +# 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 LibpressioTools(CMakePackage): + """General Utilities for LibPressio""" + + homepage = "https://github.com/robertu94/pressio-tools" + url = "https://github.com/robertu94/pressio-tools/archive/refs/tags/0.0.15.tar.gz" + git = "https://github.com/robertu94/pressio-tools" + + maintainers = ["robertu94"] + + version("master", branch="master") + version("0.1.6", sha256="a67a364f46dea29ff1b3e5c52c0a5abf2d9d53412fb8d424f6bd71252bfa7792") + version("0.1.5", sha256="b35f495fae53df87dd2abf58c0c51ed17710b16aaa2d0842a543fddd3b2a8035") + version("0.1.4", sha256="39adc4b09a63548a416ee4b1dcc87ec8578b15a176a11a2845c276c6c211f2d0") + version("0.1.3", sha256="4e6c39061d6d829936dfeb569ea997854694ef1a46f112e306672ee1cc1567a0") + version("0.1.2", sha256="a3379fd7c53c2eb0b5cdbf0e7eed37ae2a415f737885310d3da4d34fa55c618e") + version("0.1.1", sha256="adec3ea9a12677c647fbc3a1f9909fde6f2dd5ed662ed0ee5cd753b26397643e") + version("0.1.0", sha256="e016b1785f2dc5c8a8565ff3d7b50980788e057e61905a91ef1d16da73297a06") + version("0.0.24", sha256="b369efcc17f339fdd5741d817f1b7908bd2b5df5686c5406c6b1123b0daa82c5") + version("0.0.23", sha256="08a141be14e63e491216a89d45737040fc3450c5b793e6a4819cd06f876b2b0b") + version("0.0.22", sha256="9fcb20a3bf24e139386e94b413f10087d65ed32d2eb93cc7be8e87d736da9766") + version("0.0.21", sha256="2ffe1018ff86eca0928ab8bbf568b2cf7ab739f0e191e2722a6f5071dac4a153") + version("0.0.20", sha256="cad3a1dff25ae1dc442821e72fe8f7495e098bd0ea52c3beeac1ceb721c60351") + version("0.0.19", sha256="cc8a4bb5259b7b8e14248a1a741067a865a0db36645c878d346da983e74c9521") + version("0.0.18", sha256="766fcf6c4bd475de66107d379c76805d6368d71ee83cade645f2b7cd27801718") + version("0.0.17", sha256="cf76e8a929aa128d09f8f953171d5cf395223245bc81d2ea4e22099849e40b94") + version("0.0.16", sha256="1299e441fb15666d1c8abfd40f3f52b1bf55b6bfda4bfcc71177eec37160a95e") + version("0.0.15", sha256="bcdf865d77969a34e2d747034ceeccf5cb766a4c11bcc856630d837f442ee33e") + + depends_on("mpi", when="+mpi") + depends_on("libpressio+libdistributed+mpi", when="+mpi") + depends_on("libpressio", when="~mpi") + depends_on("libpressio+hdf5", when="+hdf5") + + depends_on("boost") + + # 0.1.0 changed a bunch of things in the build system, make sure everything is up to date + depends_on("libpressio@0.88.0:", when="@0.1.6:") + depends_on("libpressio@0.85.0:", when="@0.1.0:0.1.5") + depends_on("libpressio-opt@0.13.3:", when="@0.1.0:+opt") + depends_on("libpressio-errorinjector@0.7.0:", when="@0.1.0:+error_injector") + depends_on("libpressio-tthresh@0.0.5:", when="@0.1.0:+tthresh") + depends_on("libpressio-rmetric@0.0.4:", when="@0.1.0:+rcpp") + depends_on("libpressio-adios2@0.0.2", when="@0.1.0:+adios2") + + depends_on("libpressio-opt", when="+opt") + depends_on("libpressio-errorinjector", when="+error_injector") + depends_on("libpressio-tthresh", when="+tthresh") + depends_on("libpressio-rmetric", when="+rcpp") + depends_on("libpressio-adios2", when="+adios2") + depends_on("libpressio-sperr", when="+sperr") + depends_on("libpressio-nvcomp", when="+nvcomp") + + variant("hdf5", default=True, description="support the hdf5 package") + variant("opt", default=False, description="support the libpressio-opt package") + variant( + "error_injector", default=False, description="support the libpressio-errorinjector package" + ) + variant("tthresh", default=False, description="depend on the GPL licensed libpressio-tthresh") + variant("rcpp", default=False, description="depend on the GPL licensed libpressio-rmetric") + variant("mpi", default=False, description="depend on MPI for distributed parallelism") + variant("adios2", default=False, description="depend on ADIOS2 for IO modules") + variant("sperr", default=False, description="depend on sperr", when="@0.1.2:") + variant("nvcomp", default=False, description="depend on nvcomp", when="@0.1.0:") + conflicts("+opt", "~mpi") + + def cmake_args(self): + args = [] + if "+mpi" in self.spec: + args.append("-DLIBPRESSIO_TOOLS_HAS_MPI=YES") + if "+opt" in self.spec: + args.append("-DLIBPRESSIO_TOOLS_HAS_OPT=YES") + if "+error_injector" in self.spec: + args.append("-DLIBPRESSIO_TOOLS_HAS_ERROR_INJECTOR=YES") + if "+tthresh" in self.spec: + args.append("-DLIBPRESSIO_TOOLS_HAS_TTHRESH=YES") + if "+rcpp" in self.spec: + args.append("-DLIBPRESSIO_TOOLS_HAS_RMETRIC=YES") + if "+sperr" in self.spec: + args.append("-DLIBPRESSIO_TOOLS_HAS_SPERR=YES") + if "+nvcomp" in self.spec: + args.append("-DLIBPRESSIO_TOOLS_HAS_NVCOMP=YES") + if self.run_tests: + args.append("-DBUILD_TESTING=ON") + else: + args.append("-DBUILD_TESTING=OFF") + + return args + + @run_after("build") + @on_package_attributes(run_tests=True) + def test(self): + make("test") diff --git a/var/spack/repos/builtin/packages/libpressio-tthresh/package.py b/var/spack/repos/builtin/packages/libpressio-tthresh/package.py new file mode 100644 index 00000000000..d94019328d3 --- /dev/null +++ b/var/spack/repos/builtin/packages/libpressio-tthresh/package.py @@ -0,0 +1,39 @@ +# 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 LibpressioTthresh(CMakePackage): + """A tthresh implementation for libpressio""" + + homepage = "https://github.com/robertu94/libpressio_tthresh" + url = "https://github.com/robertu94/libpressio_tthresh/archive/refs/tags/0.0.1.tar.gz" + git = homepage + + maintainers = ["robertu94"] + + version("main", branch="main") + version("0.0.6", sha256="e9dc4754421d892a86516c6bb892f6ff582e9ea3c242c1c052104e4f6944cbec") + version("0.0.5", sha256="af47c90e9c16825312e390a7fb30d9d128847afb69ad6c2f6608bd80f60bae23") + version("0.0.3", sha256="b0b0a4876d3362deafc2bb326be33882132e3d1666e0c5f916fd6fad74a18688") + version("0.0.1", sha256="9efcfa97a5a81e9c456f50b712adb806d9d2f2ed6039860615df0f2e9d96569e") + + depends_on("eigen") + depends_on("libpressio@0.85.0:", when="@:0.0.5") + depends_on("libpressio@0.88.0:", when="@0.0.6:") + + def cmake_args(self): + args = [] + if self.run_tests: + args.append("-DBUILD_TESTING=ON") + else: + args.append("-DBUILD_TESTING=OFF") + return args + + @run_after("build") + @on_package_attributes(run_tests=True) + def test(self): + make("test") diff --git a/var/spack/repos/builtin/packages/libpressio/package.py b/var/spack/repos/builtin/packages/libpressio/package.py new file mode 100644 index 00000000000..d30bb5edc16 --- /dev/null +++ b/var/spack/repos/builtin/packages/libpressio/package.py @@ -0,0 +1,331 @@ +# 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 Libpressio(CMakePackage, CudaPackage): + """A generic abstraction for the compression of dense tensors""" + + # codarcode gets "stable" releases ~1/yr; robertu94 contains development versions + homepage = "https://github.com/codarcode/libpressio" + url = "https://github.com/robertu94/libpressio/archive/0.31.1.tar.gz" + git = "https://github.com/robertu94/libpressio" + + version("master", branch="master") + version("develop", branch="develop") + version("0.88.0", sha256="4358441f0d10559d571327162a216617d16d09569a80e13ad286e3b7c41c5b9b") + version("0.87.0", sha256="2bea685e5ed3a1528ea68ba4a281902ff77c0bebd38ff212b6e8edbfa263b572") + version("0.86.7", sha256="2a6319640a018c39aa93aaf0f027fd496d7ea7dc5ac95509313cf1b4b6b1fb00") + version("0.86.6", sha256="31ac77137c31a524c2086e1fe4d9b1d3c1bc6d8594662cd4b67878ba8887cabb") + version("0.86.5", sha256="6e6ffe7585e298061f6f5ff79a9fe7edf722a8c124a87282bae864ed6a167246") + version("0.86.4", sha256="52a1d932b30a9390e836ea4b102225b176f8feebbac598a0ab3a81a9ac83775c") + version("0.86.3", sha256="6b010e394fc916ad2233e941a49f70555dda40521e3668f2e10502c7bfa529be") + version("0.86.2", sha256="e221cb256e1b387ce1245cab5704c10d351812c003b257655d43b156b9650a89") + version("0.86.1", sha256="89b1b652215f67635da1baac81d3f927ff00f335c473322edcf24472b5a9b5a4") + version("0.86.0", sha256="867bd6ea6b632b7f6d6a89aac073cea738b574825c81ee83318802e9d3d5fbe8") + version("0.85.0", sha256="79a600fdd5c7a418a0380425e1bbeb245d5d86e1676f251e5900b69738b72423") + version("0.84.3", sha256="7b2ca198f919c1f981c88722da33ef69b564fe123d49330ad6ba17eba80c046e") + version("0.84.2", sha256="c50b599a22ab89b7ef57dbaa717f5e97f4437d2bd4b6e572274c8c98022b05da") + version("0.84.0", sha256="b22320a54dbb9f65a66af2a6f335884e7ba48abd3effe643e51e4e7cfe793b7d") + version("0.83.4", sha256="9dd0efff1c6121e964b45371d6a52895f6a8db3d5cdabbd1e951b696a3f590e3") + version("0.83.3", sha256="59e2bb2c1eb422c03204bfc713bc76d7bbaeaeba6430e1204577495c07eef34d") + version("0.83.2", sha256="56dd63cb3924fb57f8f53929faecf2a5211985f160cdacf38b3d001e22728427") + version("0.83.1", sha256="2afdc8421b4c0f638c8547bcdd54bdb405d1717dca32b804621c5c152adbe2a6") + version("0.83.0", sha256="7c692bbf3ebdfa508a493902eb561c85b9087dd8003547dcd54baf0b2188d9bd") + version("0.82.3", sha256="97a6a0a022d8ae60f477ce21d1ff10cc47bb2f7d3891bb3b49f4a7b166f9c2e1") + version("0.82.2", sha256="ce2d566c627a5341e1fd58261b2d38567b84d963f1045e2e4aac87e67ac06d89") + version("0.82.1", sha256="f6b41ad6f56311078e67e68063f9124f32e63a9c1c9c0c0289c75addaf9fed94") + version("0.82.0", sha256="e60f843dda8312ae4269c3ee23aad67b50f29a8830c84fb6c10309c37e442410") + version("0.81.0", sha256="51ab443a42895fefb4e0ae8eb841402f01a340f3dd30dcb372f837e36ac65070") + version("0.80.1", sha256="9168789f8714d0bbce1a03ff3a41ef24c203f807fed1fbd5ca050798ebef015f") + version("0.80.0", sha256="f93292dc258224a8ef69f33299a5deecfb45e7ea530575eeaa4ceff48093d20e") + version("0.79.0", sha256="e843d8f70369e30d0135b513926ac4a5dacd3042c307c132e80a29b7349e8501") + version("0.78.0", sha256="d9292150686d2be616cd9145c24fe6fc12374df023eee14099ffdf7071e87044") + version("0.77.0", sha256="d2f362c8b48b6ea6b3a099f3dcb0ce844e3b45fd6cf0c4130fbbf48d54d1a9b3") + version("0.76.1", sha256="09b6926efefa1b10f400dfc94927c195d1f266f34ed34cddeba11707c0cc6982") + version("0.76.0", sha256="8ec0e3bcc57511a426047748f649096cf899a07767ddbcdbfad28500e1190810") + version("0.75.1", sha256="8b9beb79507196575649d32116d13833e7dc9765370c245ac5a3640a50cb106a") + version("0.75.0", sha256="83aadd5e6172b3654b955954d13f2d9346fcd008bc901746f6f8b65a978235ee") + version("0.74.1", sha256="aab7211c244a7a640e0b2d12346463c8650ef4f8d48fc58819a20d3b27ab5f81") + version("0.74.0", sha256="2fbd54bbc4d1f3ce4b107ac625ad97c6396bff8873f2ac51dd049d93aa3f2276") + version("0.73.0", sha256="059c90ab50d2e50a1fff8bf25c0c387a9274090bf8657fa49aa1c211b4690491") + version("0.72.2", sha256="1f620b8af272dd2823712c1e38a69c6375febe49eb9155a3f04667ea1931ebdb") + version("0.72.1", sha256="f8ab9559c40a6a93ad0c1a894acf71e07c9fe1994f464852c9dd6f0423a6dc51") + version("0.72.0", sha256="0e6e7327a21a0cd6cf56fa4c62ba5ec1c41381ac053602d8acaa854bdfd1cb30") + version("0.71.3", sha256="f1185acdc6143fe7e417754032336ef50fec5760b08cb291962305429adf18da") + version("0.71.2", sha256="0501f6a0a9cfad62f80834d1dd77c678b000202903168aec0d2c4928ff6e581c") + version("0.71.1", sha256="cd9daa4b28da3b5e3cb36cace11b4e580a66fb14ca04a807c5a135a9448bb5df") + version("0.71.0", sha256="9b9ba9689c53e9cfa4d9fee52653ed393d2307c437dac41daceb6f98564fbcd1") + version("0.70.8", sha256="f0600cabd0341669ef1d6e838ef3496cff5200239a3b96a4941c434d71e4517c") + version("0.70.7", sha256="82722a9e7fbec3b2d79be226ba73bbf3108d3206d006a763db46d20cc044a8b5") + version("0.70.6", sha256="e76be47b0b8bd18d7ac44d59242adc45dc721465638aefd2c8564fd778d1adbd") + version("0.70.5", sha256="c6ee62643c08a7ceca7c45eb28edff0eeb070671bf0d502563b6cc8ada4bf695") + version("0.70.4", sha256="6df62154d0a8919fa91f6fce4ffb2f77584d5ddc61c85eee34557d36de9906b2") + version("0.70.3", sha256="40cca7f6d3bd19fdcf6f6c17521acdf63dfda0fb5b173c23d4521818b16a9a46") + version("0.70.2", sha256="30929e02c0ce5db8d9ff1eeca42df92e68439c7dd5a3c1fea0bb44ead2343442") + version("0.70.1", sha256="855923ca58b1c549681d368d2112d05b96fae9e3199f2a10c2013fcb2f630036") + version("0.70.0", sha256="1e987dcea76b2bd01f7e59b404267c7614a7c99b3fbc0ae745bf8e9426f489c6") + version("0.69.0", sha256="22e47deb4791778846b9c858295b756f91e1d8c884ccf246c2df2bf9b56a04d5") + version("0.68.0", sha256="c7008e6f6b4451812070ece7e9b2fb6cc2fb04971255f95c8274375a698c6794") + version("0.66.3", sha256="7423339831525a128115d446b1dd7fb7942f2aed24e0ec3778396d2c0c379678") + version("0.66.2", sha256="89a6459b6fcf1273f8afc7317e7351c09be977aeb3bb6554941166074ee2030f") + version("0.66.1", sha256="1de2d3d911fc91f7aa9f57eda467f1aadd7060a680538b82c678a5f4e7e6c5d0") + version("0.66.0", sha256="c3063a85c8f17df6ba1722f06eaab74fe14a53f37f5a86664c23a7f35d943f3a") + version("0.65.0", sha256="beb4f7bc73b746fe68c4333fa4d4e1dba05f5f5fb386874b83cbf7f105e83c45") + version("0.64.0", sha256="1af87b410eabee7f377b047049eae486cf3161fa67546789440f1d1e56e2324d") + version("0.63.0", sha256="32d716f52073d7ea246d01fefb420bfe5b834ebc10579edd79ebce7a87dd1a81") + version("0.62.0", sha256="248eedc764312da401aa29304275e009196ebdb5b08594a1522bb165c16874aa") + version("0.61.0", sha256="7b4304b7556d8ec0742d1b8a9280f7f788307d2a6f4d2f59cc8e8358b6c69c11") + version("0.60.0", sha256="a57fce96d50a603075a8a4a583431a1a03170df4d2894ff30f84d8c5ab4caf47") + version("0.59.0", sha256="eae5933a7b37834cf4f70424b083f99799f9381ee8bb616f3a01d4ab2e5631a6") + version("0.58.0", sha256="6b092dda66e7cc1bc4842fe54ab41248c4f136307cc955081e8052222c82aff1") + version("0.57.0", sha256="4f978616c13f311170fdc992610ad1fd727884cf0d20b6849b2c985d936c482b") + version("0.56.2", sha256="1ae20415ba50a4dcfec7992e9a571f09f075f077ebdd7c1afb9a19b158f6205d") + version("0.56.1", sha256="01b7c09f1eafff819de0079baf033f75547432be62dc10cb96691d078994a4e9") + version("0.56.0", sha256="77003c9dde0590ca37fddfbe380b29b9f897fa0dadb9b9f953819f5e9d9f08f0") + version("0.55.3", sha256="f8c6ae6ae48c4d38a82691d7de219ebf0e3f9ca38ae6ba31a64181bfd8a8c50a") + version("0.55.2", sha256="47f25f27f4bff22fd32825d5a1135522e61f9505758dde3d093cfbdaff0b3255") + version("0.55.1", sha256="39f1799d965cd0fec06f0a43dec865c360cbb206e4254f4deb4f7b7f7f3c3b2f") + version("0.55.0", sha256="fb74cfe2a8f3da51f9840082fa563c2a4ce689972c164e95b1b8a1817c4224cf") + version("0.54.0", sha256="cd28ddf054446c286f9bfae563aa463e638ee03e0353c0828a9ce44be4ce2df9") + version("0.53.2", sha256="4a7b57f1fd8e3e85ecf4a481cc907b81a71c4f44cf2c4a506cb37a6513a819a4") + version("0.53.1", sha256="1425dec7ee1a7ddf1c3086b83834ef6e49de021901a62d5bff0f2ca0c75d3455") + version("0.53.0", sha256="0afb44c2dab8dd8121d174193eb6623b29da9592e5fe1bbe344cfc9cacbec0cb") + version("0.52.2", sha256="c642463da0bbdd533399e43c84ea0007b1d7da98276c26bc075c7b4778f97a01") + version("0.52.1", sha256="32f211aaf4641223bf837dc71ea064931f85aa9260b9c7f379787ca907c78c3a") + version("0.52.0", sha256="2fd4cf0cc43c363b2e51cb264a919a1b43514aad979b9b5761b746fc70490130") + version("0.51.0", sha256="878d5399c4789034b7f587a478e2baf8e852f7f1f82aa59e276ddf81d325b934") + version("0.50.4", sha256="f4ab7dada0e07ecf97f88e2dd7ca6c4755fb0f4175d8d12ed3a856c45b240bde") + version("0.50.3", sha256="cc78bfc9a5d1b061098c892e9c8ff14861aa48ea95f0e9684ca4250d30c38889") + version("0.50.2", sha256="0ef1355f905d48ed01c034a8d418e9c528113d65acb3dd31951297029c5aaed4") + version("0.50.1", sha256="1500bae01ba74c330bc205b57423688c2b1aacafe1aabcaf469b221dcda9beec") + version("0.50.0", sha256="c50fb77b5c8d535fe0c930e5d4400d039ad567a571ea9711b01d6d5bd2a26fb6") + version("0.49.2", sha256="cde90e0183024dc1a78d510e2ae3effa087c86c5761f84cba0125f10abc74254") + version("0.49.1", sha256="6d1952ada65d52d2fd5d4c60bb17e51d264c2c618f9b66dadeffa1e5f849394a") + version("0.49.0", sha256="adfe5c64a5d170197893fe5a4c9338cde6cbdd5b54e52534886425101be4458f") + version("0.48.0", sha256="087a7f944240caf2d121c1520a6877beea5d30cc598d09a55138014d7953348a") + version("0.47.0", sha256="efce0f6f32e00482b80973d951a6ddc47b20c8703bd0e63ab59acc0e339d410b") + version("0.46.3", sha256="24bc5d8532a90f07ab2a412ea28ddbfc8ff7ab27cd9b4e7bd99a92b2a0b5acfd") + version("0.46.2", sha256="3ebbafa241e54cb328966ea99eab5d837c4a889f17c3b2048cc2961166a84cc4") + version("0.46.1", sha256="be7468b30a367bcbefab09ed5ac07320cd323904c9129d6b874175b39ef65cd9") + version("0.46.0", sha256="ab944358edc7e03be604749002f1f00aaf4d55d20bac2689d40bd4e66357879d") + version("0.45.0", sha256="b3307b99f82f0300dfed7dd122447a6e74ca8ad8c012d2fc60467e6e067ac226") + version("0.44.0", sha256="cec114325167731233be294aab329d54862457cb2e1f1a87d42d100da7c53aa5") + version("0.42.2", sha256="a9289260eb0a4eaf4550c2d6ad1af7e95a669a747ce425ab9a572d4ab80e2c1f") + version("0.42.1", sha256="5f79487568ec4625b0731f0c10efb565201602a733d1b6ac1436e8934cf8b8ec") + version("0.42.0", sha256="c08e047e202271ec15eeda53670c6082815d168009f4e993debcc0d035904d6b") + version("0.41.0", sha256="b789360d70656d99cd5e0ceebfc8828bdf129f7e2bfe6451592a735be9a0809a") + version("0.40.1", sha256="73a65f17e727191b97dfdf770dd2c285900af05e6fee93aa9ced9eadb86f58ff") + version("0.40.0", sha256="80e68172eeef0fbff128ede354eaac759a9408c3ef72c5eed871bb9430b960ff") + version("0.39.0", sha256="e62fea9bcb96529507fdd83abc991036e8ed9aa858b7d36587fce3d559420036") + version("0.38.2", sha256="5f38387d92338eac8658cd70544a5d9a609bd632090f4f69bcbc9f07ec4abd7b") + version("0.38.1", sha256="99ff1ff61408e17f67ab427c51add074f66ab7375a506ae70dcb24c47a8ea636") + version("0.38.0", sha256="e95aa6e4161324fa92fa236ea2bf08a7267a883ef4ca5fbb8bbf75e70db1ce4f") + version("0.37.0", sha256="98877fa2daf91ac91c2e0e0014684131d6efc4a1f2f77917d40fdbf424d74588") + version("0.36.0", sha256="452a3973cf359786409e064ca4b63a5f81072a9d72a52d1a4084d197f21fc26b") + version("0.35.0", sha256="50e6de305e1ffdcf423cec424e919bb0bdebee6449d34ff26a40421f09392826") + version("0.34.4", sha256="5a997c6f4b8c954a98046a851d0f3b31ce7c5be6e7e615068df4f1d7b86c9630") + version("0.34.3", sha256="1f5994862c33df4588d411b49fba20a40294627d0b325bbd5234f169eb1d4842") + version("0.34.2", sha256="3b8d3f801799023c8efe5069895723ce4e742330282774dc0873c2fa3910eeb2") + version("0.34.1", sha256="791ff249a685fab1733d4c3c936db6a064aa912d47926ad4bd26b1829f6e2178") + version("0.34.0", sha256="da62a15da103e763e34dae43be3436873e4fb550630dddc55232ae644accda02") + version("0.33.0", sha256="61200855a0846ce765b686fa368496f44534e633031811803ba2cb31f94c25b1") + version("0.32.0", sha256="187e75fc6d3f84003829d2b8aec584e99d72d65f2d82835998714ae05ae008af") + version("0.31.1", sha256="32c1fd8319fbbb844a0a252d44761f81f17c6f3549daadce47e81524d84605a4") + version("0.31.0", sha256="9d4bc8b2c1a210a58f34216cebe7cd5935039d244b7e90f7e2792bda81ff7ddc") + version("0.30.1", sha256="e2249bdced68d80a413de59f8393922553a8900a14e731030e362266e82a9af8") + version("0.30.0", sha256="91de53099d9381e3744e7a1ac06d2db0f9065378c4d178328b78ac797ee3ec65") + version("0.29.1", sha256="ced1e98fbd383669e59ec06d2e0c15e27dbceda9ac5569d311c538b2fe6d3876") + version("0.29.0", sha256="a417a1d0ed75bd51131b86fba990502666d8c1388ad6282b3097aa461ccf9785") + version("0.28.0", sha256="5c4e0fe8c7c80615688f271b57b35ee9d924ac07c6d3d56d0303e610338ed332") + version("0.27.1", sha256="3f7d2401ff8b113781d93c5bf374f47ca35b2f962634c6310b73620da735e63d") + version("0.27.0", sha256="387ee5958de2d986095cda2aaf39d0bf319d02eaeeea2a565aea97e6a6f31f36") + version("0.26.0", sha256="c451591d106d1671c9ddbb5c304979dd2d083e0616b2aeede62e7a6b568f828c") + + variant("blosc", default=False, description="support the blosc lossless compressors") + variant("fpzip", default=False, description="support for the FPZIP lossy compressor") + variant("hdf5", default=False, description="support reading and writing from hdf5 files") + variant("magick", default=False, description="support the imagemagick image compressors") + variant( + "mgard", default=False, description="support for the MAGARD error bounded lossy compressor" + ) + variant("python", default=False, description="build the python wrappers") + variant("sz", default=False, description="support for the SZ error bounded lossy compressor") + variant("zfp", default=False, description="support for the ZFP error bounded lossy compressor") + variant("boost", default=False, description="support older compilers using boost") + variant("petsc", default=False, description="support IO using petsc format") + variant("mpi", default=False, description="support for launching processes using mpi") + variant("lua", default=False, description="support for composite metrics using lua") + variant( + "libdistributed", default=False, description="support for distributed multi-buffer support" + ) + variant("ftk", default=False, description="build support for the feature tracking toolkit") + variant("digitrounding", default=False, description="build support for the digit rounding") + variant("bitgrooming", default=False, description="build support for the bitgrooming") + variant("openmp", default=False, description="build plugins that use openmp") + variant("docs", default=False, description="build and install manual pages") + variant("remote", default=False, description="build the remote launch plugin") + variant("json", default=False, description="build the JSON support") + variant("szauto", default=False, description="build szauto support") + variant("unix", default=False, description="build support for unixisms like mmap and rusage") + variant("ndzip", default=False, description="build support for the NDZIP compressor") + variant("arc", default=False, description="build support for the ARC error correction tool") + variant("netcdf", default=False, description="build support for the NDFCDF data format") + variant("sz3", default=False, description="build support for the SZ3 compressor family") + variant("mgardx", default=False, description="build support for the MGARDx compressor") + variant("bzip2", default=False, description="build support for the bzip2 compressor") + variant("qoz", default=False, description="build support for the qoz compressor") + variant( + "cusz", default=False, description="build support for the cusz compressor", when="@0.86.0:" + ) + + depends_on("boost", when="@:0.51.0+boost") + + depends_on("libstdcompat+boost", when="+boost") + depends_on("libstdcompat@0.0.14:", when="@0.79.0:") + depends_on("libstdcompat@0.0.13:", when="@0.73.0:") + depends_on("libstdcompat@0.0.10:", when="@0.71.3:") + depends_on("libstdcompat@0.0.7:", when="@0.70.3:") + depends_on("libstdcompat@0.0.6:", when="@0.70.2:") + depends_on("libstdcompat@0.0.5:", when="@0.63.0:") + depends_on("libstdcompat@0.0.3:", when="@0.60.0:") + depends_on("libstdcompat", when="@0.52.0:") + + depends_on("c-blosc", when="+blosc") + depends_on("fpzip", when="+fpzip") + depends_on("hdf5", when="+hdf5") + depends_on("imagemagick", when="+magick") + depends_on("mgard", when="+mgard") + depends_on("python@3:", when="+python", type=("build", "link", "run")) + depends_on("py-numpy", when="+python", type=("build", "link", "run")) + depends_on("swig@3.12:", when="+python", type="build") + depends_on("sz@2.1.8.1:", when="@0.55.2:+sz") + depends_on("sz@2.1.11.1:", when="@0.55.3:+sz") + depends_on("sz@2.1.12:", when="@0.69.0:+sz") + depends_on("fftw", when="+sz ^sz@:2.1.10") + depends_on("zfp", when="+zfp") + depends_on("petsc", when="+petsc") + depends_on("mpi@2:", when="+mpi") + depends_on("lua-sol2", when="+lua") + depends_on("libdistributed@0.0.11:", when="+libdistributed") + depends_on("libdistributed@0.4.0:", when="@0.85.0:+libdistributed") + depends_on("pkg-config", type="build") + depends_on("ftk@master", when="+ftk") + depends_on("digitrounding", when="+digitrounding") + depends_on("bitgroomingz", when="+bitgrooming") + depends_on("cmake@3.14:", type="build") + depends_on("py-mpi4py", when="@0.54.0:+mpi+python", type=("build", "link", "run")) + depends_on("py-numcodecs", when="@0.54.0:+python", type="run") + depends_on("doxygen+graphviz", when="+docs", type="build") + depends_on("curl", when="+remote") + depends_on("nlohmann-json+multiple_headers", when="+remote") + depends_on("nlohmann-json+multiple_headers", when="+json") + depends_on("szauto", when="+szauto") + depends_on("ndzip", when="+ndzip") + depends_on("arc", when="+arc") + depends_on("netcdf-c", when="+netcdf") + depends_on("mgardx", when="+mgardx") + conflicts( + "+mgardx", when="+szauto" + ) # SZ auto and MGARDx cause symbol conflicts with each other + conflicts( + "~json", + when="@0.57.0:+remote", + msg="JSON support required for remote after version 0.57.0", + ) + depends_on("sz3", when="+sz3") + depends_on("bzip2", when="+bzip2") + depends_on("qoz", when="+qoz") + depends_on("cusz", when="+cusz") + + extends("python", when="+python") + + def cmake_args(self): + args = [] + if "+python" in self.spec: + args.append("-DLIBPRESSIO_PYTHON_SITELIB={0}".format(python_platlib)) + args.append("-DBUILD_PYTHON_WRAPPER=ON") + args.append("-DPython3_EXECUTABLE={0}".format(self.spec["python"].command)) + if "+mpi" in self.spec: + args.append("-DLIBPRESSIO_HAS_MPI4PY=ON") + if "+hdf5" in self.spec: + args.append("-DLIBPRESSIO_HAS_HDF=ON") + args.append("-DHDF5_ROOT=" + self.spec["hdf5"].prefix) + if "+sz" in self.spec: + args.append("-DLIBPRESSIO_HAS_SZ=ON") + if "+szauto" in self.spec: + args.append("-DLIBPRESSIO_HAS_SZ_AUTO=ON") + if "+zfp" in self.spec: + args.append("-DLIBPRESSIO_HAS_ZFP=ON") + if "+fpzip" in self.spec: + args.append("-DLIBPRESSIO_HAS_FPZIP=ON") + if "+blosc" in self.spec: + args.append("-DLIBPRESSIO_HAS_BLOSC=ON") + if "+magick" in self.spec: + args.append("-DLIBPRESSIO_HAS_MAGICK=ON") + if "+mgard" in self.spec: + args.append("-DLIBPRESSIO_HAS_MGARD=ON") + if "+petsc" in self.spec: + args.append("-DLIBPRESSIO_HAS_PETSC=ON") + if "+boost" in self.spec: + args.append("-DLIBPRESSIO_CXX_VERSION=11") + if "+mpi" in self.spec: + args.append("-DLIBPRESSIO_HAS_MPI=ON") + if "+lua" in self.spec: + args.append("-DLIBPRESSIO_HAS_LUA=ON") + if "+libdistributed" in self.spec: + args.append("-DLIBPRESSIO_HAS_LIBDISTRIBUTED=ON") + if "+ftk" in self.spec: + args.append("-DLIBPRESSIO_HAS_FTK=ON") + if "+bitgrooming" in self.spec: + args.append("-DLIBPRESSIO_HAS_BIT_GROOMING=ON") + if "+digitrounding" in self.spec: + args.append("-DLIBPRESSIO_HAS_DIGIT_ROUNDING=ON") + if "+openmp" in self.spec: + args.append("-DLIBPRESSIO_HAS_OPENMP=ON") + if "+docs" in self.spec: + args.append("-DBUILD_DOCS=ON") + args.append("-DLIBPRESSIO_INSTALL_DOCS=ON") + if "+remote" in self.spec: + args.append("-DLIBPRESSIO_HAS_REMOTELAUNCH=ON") + if "+json" in self.spec: + args.append("-DLIBPRESSIO_HAS_JSON=ON") + if "+unix" in self.spec: + args.append("-DLIBPRESSIO_HAS_LINUX=ON") + if "+ndzip" in self.spec: + args.append("-DLIBPRESSIO_HAS_NDZIP=ON") + if "+arc" in self.spec: + args.append("-DLIBPRESSIO_HAS_ARC=ON") + if "+netcdf" in self.spec: + args.append("-DLIBPRESSIO_HAS_NETCDF=ON") + if "+sz3" in self.spec: + args.append("-DLIBPRESSIO_HAS_SZ3=ON") + if "+cuda" in self.spec: + args.append("-DLIBPRESSIO_HAS_CUFILE=ON") + if "+mgardx" in self.spec: + args.append("-DLIBPRESSIO_HAS_MGARDx=ON") + if "+bzip2" in self.spec: + args.append("-DLIBPRESSIO_HAS_BZIP2=ON") + if "+qoz" in self.spec: + args.append("-DLIBPRESSIO_HAS_QoZ=ON") + if "+cusz" in self.spec: + args.append("-DLIBPRESSIO_HAS_CUSZ=ON") + if self.run_tests: + args.append("-DBUILD_TESTING=ON") + else: + args.append("-DBUILD_TESTING=OFF") + return args + + @run_after("build") + @on_package_attributes(run_tests=True) + def test(self): + make("test") + + @run_after("build") + def install_docs(self): + if "+docs" in self.spec: + with working_dir(self.build_directory): + make("docs") diff --git a/var/spack/repos/builtin/packages/libstdcompat/package.py b/var/spack/repos/builtin/packages/libstdcompat/package.py new file mode 100644 index 00000000000..481dbce1c86 --- /dev/null +++ b/var/spack/repos/builtin/packages/libstdcompat/package.py @@ -0,0 +1,98 @@ +# 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 Libstdcompat(CMakePackage): + """A compatibility header for C++14, 17, and 20 for C++11""" + + homepage = "https://github.com/robertu94/std_compat" + url = "https://github.com/robertu94/std_compat/archive/0.0.1.tar.gz" + git = "https://github.com/robertu94/std_compat" + + maintainers = ["robertu94"] + + version("master", branch="master") + version("0.0.15", sha256="af374a8883a32d874f6cd18cce4e4344e32f9d60754be403a5ac7114feca2a28") + version("0.0.14", sha256="9a794d43a1d79aec3350b89d8c06689b8b32cf75e2742cdfa9dc0e3f2be6f04e") + version("0.0.13", sha256="460656189e317e108a489af701fa8f33f13a93d96380788e692a1c68100e0388") + version("0.0.12", sha256="67c1d1724122a1ba7cebcd839658786680fa06a549369f4a7c36a44ad93ddd5d") + version("0.0.11", sha256="f166cd55e3cf845e4ed9eee1fb25de1f991dee5ef538c1e3ea9cbe7714863ccb") + version("0.0.10", sha256="d55ad9b7f61efa5a4bbef047f729af5ed9e44f96bb9d54f36023fa99af2bfe40") + version("0.0.9", sha256="325e816153aab0aee791e4c628e01dbc5b7aa336558d1694bd5de763f34e37e6") + version("0.0.8", sha256="3103295033fb6723dc462a8979ccfe3b571347c2a458f4cc8d8324981dedead9") + version("0.0.7", sha256="8cb4ed704aef427bbe4c86ee874a350561e6e059223e7b3d60f1e0d7300ccfe9") + version("0.0.6", sha256="cf4288422c9e9ab9e7c831c11a6a67907fe19b0da40601cc2b05e76e3be2f795") + version("0.0.5", sha256="a8599a12253b5ebdb38c6e416e7896444fd48a15167fe481985182ed17fc6883") + version("0.0.4", sha256="b2aeb4e60105635acb3f41b2c9559956e7b75d999c73b84b14be5b78daa4e6a9") + version("0.0.3", sha256="098678618a335bb2e8b25ceae8c3498f4c3056fd9e03467948bab18252afb46d") + version("0.0.2", sha256="36424399e649be38bdb21899aa45f94aebba25c66048bab2751b1b3b9fd27238") + version("0.0.1", sha256="3d63e901f4e20b9032a67086f4b4281f641ee0dea436cf15f7058faa40d8637b") + + variant( + "cpp_compat", + values=("11", "14", "17", "20", "auto"), + default="auto", + multi=False, + description="version of the c++ standard to use and depend on", + ) + variant("cpp_unstable", default=True, description="sets CXX_STANDARD_REQUIRED") + variant("boost", default=False, description="support older compilers using boost") + + depends_on("boost+thread", when="%gcc@:8.0.0") + depends_on("boost+thread", when="+boost") + depends_on("boost+thread", when="cpp_compat=11") + depends_on("boost+thread", when="cpp_compat=14") + + conflicts("~cpp_unstable", when="@0.0.7: cpp_compat=auto") + conflicts("+cpp_unstable", when="@:0.0.7") + conflicts("cpp_compat=11", when="@:0.0.7") + conflicts("cpp_compat=14", when="@:0.0.7") + conflicts("cpp_compat=17", when="@:0.0.7") + conflicts("cpp_compat=20", when="@:0.0.7") + + def max_cxx_version(self): + try: + self.compiler.cxx17_flag + return "17" + except Exception: + pass + try: + self.compiler.cxx14_flag + return "14" + except Exception: + pass + self.compiler.cxx11_flag + return "11" + + def cmake_args(self): + args = [] + cpp_compat = self.spec.variants["cpp_compat"].value + + if "cpp_unstable" in self.spec: + args.append("-DSTDCOMPAT_CXX_UNSTABLE=ON") + + if cpp_compat == "auto": + args.append("-DSTDCOMPAT_CXX_VERSION=%s" % self.max_cxx_version()) + elif cpp_compat == "11": + args.append("-DSTDCOMPAT_CXX_VERSION=11") + elif cpp_compat == "14": + args.append("-DSTDCOMPAT_CXX_VERSION=14") + elif cpp_compat == "17": + args.append("-DSTDCOMPAT_CXX_VERSION=17") + elif cpp_compat == "20": + args.append("-DSTDCOMPAT_CXX_VERSION=20") + + if self.run_tests: + args.append("-DBUILD_TESTING=ON") + else: + args.append("-DBUILD_TESTING=OFF") + return args + + @run_after("build") + @on_package_attributes(run_tests=True) + def test(self): + make("test") diff --git a/var/spack/repos/builtin/packages/mgard/package.py b/var/spack/repos/builtin/packages/mgard/package.py new file mode 100644 index 00000000000..1cc336c7a19 --- /dev/null +++ b/var/spack/repos/builtin/packages/mgard/package.py @@ -0,0 +1,45 @@ +# 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 Mgard(CMakePackage, CudaPackage): + """MGARD error bounded lossy compressor + forked from https://github.com/CODARcode/MGARD with patches to support Spack""" + + # This is a research compressor with a fast evolving API. The fork is updated + # when releases are made with minimal changes to support spack + + homepage = "https://github.com/CODARcode/MGARD" + git = "https://github.com/robertu94/MGARD" + + maintainers = ["robertu94"] + + version("2021-11-12", commit="3c05c80a45a51bb6cc5fb5fffe7b1b16787d3366") + version("2020-10-01", commit="b67a0ac963587f190e106cc3c0b30773a9455f7a") + + depends_on("zlib") + depends_on("zstd") + depends_on("libarchive", when="@2021-11-12:") + depends_on("tclap", when="@2021-11-12:") + depends_on("yaml-cpp", when="@2021-11-12:") + depends_on("cmake@3.19:") + depends_on("nvcomp@2.0.2", when="+cuda") + conflicts("cuda_arch=none", when="+cuda") + conflicts("~cuda", when="@2021-11-12") + + def cmake_args(self): + args = ["-DBUILD_TESTING=OFF"] + if "+cuda" in self.spec: + args.append("-DMGARD_ENABLE_CUDA=ON") + cuda_arch = self.spec.variants["cuda_arch"].value + args.append("-DCUDA_ARCH_STRING={}".format(";".join(cuda_arch))) + if "75" in cuda_arch: + args.append("-DMGARD_ENABLE_CUDA_OPTIMIZE_TURING=ON") + if "70" in cuda_arch: + args.append("-DMGARD_ENABLE_CUDA_OPTIMIZE_VOLTA=ON") + + return args diff --git a/var/spack/repos/builtin/packages/mgardx/package.py b/var/spack/repos/builtin/packages/mgardx/package.py new file mode 100644 index 00000000000..8872e7cfe4c --- /dev/null +++ b/var/spack/repos/builtin/packages/mgardx/package.py @@ -0,0 +1,35 @@ +# 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 Mgardx(CMakePackage): + """MGARD implementation for research purposes + forked from: https://github.com/lxAltria/MGARDx""" + + # Some of the functionality of this compressor were moved to `MGARD` proper + # effectively retiring this package. This package lives on to access some of + # this functionality. Includes minor patches to support spack. + + homepage = "https://github.com/lxAltria/MGARDx" + git = "https://github.com/robertu94/MGARDx" + + maintainers = ["robertu94"] + + variant("shared", description="build shared libraries", default=True) + + version("2022-01-27", commit="aabe9de1a331eaeb8eec41125dd45e30c1d03af4") + + depends_on("sz-cpp") + depends_on("pkgconfig") + depends_on("zstd") + + def cmake_args(self): + args = [ + self.define("BUILD_TESTING", self.run_tests), + self.define_from_variant("BUILD_SHARED_LIBS", "shared"), + ] + return args diff --git a/var/spack/repos/builtin/packages/ndzip/package.py b/var/spack/repos/builtin/packages/ndzip/package.py new file mode 100644 index 00000000000..be8f7ab0e7f --- /dev/null +++ b/var/spack/repos/builtin/packages/ndzip/package.py @@ -0,0 +1,40 @@ +# 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 Ndzip(CMakePackage, CudaPackage): + """A High-Throughput Parallel Lossless Compressor for Scientific Data + + forked from: https://github.com/fknorr/ndzip + """ + + # the upstream developer graduated and moved on to other tasks + + url = "https://github.com/celerity/ndzip" + homepage = "https://github.com/fknorr/ndzip" + git = "https://github.com/robertu94/ndzip" + + maintainers = ["robertu94"] + + version("master", branch="master") + version("2021-11-30", commit="5b3c34991005c0924a339f2ec06750729ebbf015") + + variant("cuda", description="build with cuda support", default=False) + variant("openmp", description="build with cuda support", default=False) + + def cmake_args(self): + args = [ + self.define_from_variant("NDZIP_WITH_CUDA", "cuda"), + self.define_from_variant("NDZIP_WITH_MT", "openmp"), + self.define("NDZIP_BUILD_BENCHMARK", False), + self.define("NDZIP_BUILD_TEST", self.run_tests), + self.define("NDZIP_USE_WERROR", False), + ] + if "+cuda" in self.spec and self.spec.variants["cuda_arch"].value != "none": + arch_str = ";".join(self.spec.variants["cuda_arch"].value) + args.append(self.define("CMAKE_CUDA_ARCHITECTURES", arch_str)) + return args diff --git a/var/spack/repos/builtin/packages/nvcomp/package.py b/var/spack/repos/builtin/packages/nvcomp/package.py new file mode 100644 index 00000000000..353802225d5 --- /dev/null +++ b/var/spack/repos/builtin/packages/nvcomp/package.py @@ -0,0 +1,34 @@ +# 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 Nvcomp(CMakePackage, CudaPackage): + """Last open source release of A library for fast lossless compression + /decompression on NVIDIA GPUs + + forked from: https://github.com/NVIDIA/nvcomp after NVIDIA made this closed source + """ + + homepage = "https://github.com/NVIDIA/nvcomp" + url = "https://github.com/NVIDIA/nvcomp/archive/refs/tags/v2.0.2.tar.gz" + + # pinned to the last open source release+a few minor patches + git = "https://github.com/robertu94/nvcomp" + + maintainers = ["robertu94"] + + version("2.2.0", commit="3737f6e5028ed1887b0023ad0fc033e139d57574") + version("2.0.2", commit="5d5c194f3449486d989057f632d10954b8d11d75") + + depends_on("cuda") + conflicts("~cuda") + + def cmake_args(self): + args = ["-DBUILD_EXAMPLES=OFF", "-DBUILD_BENCHMARKS=OFF"] + cuda_arch_list = self.spec.variants["cuda_arch"].value + args.append("CMAKE_CUDA_ARCHITECTURES={0}".format(";".join(cuda_arch_list))) + return args diff --git a/var/spack/repos/builtin/packages/qcat/package.py b/var/spack/repos/builtin/packages/qcat/package.py new file mode 100644 index 00000000000..d0753663e6a --- /dev/null +++ b/var/spack/repos/builtin/packages/qcat/package.py @@ -0,0 +1,24 @@ +# 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 Qcat(CMakePackage): + """Quick data compression quality analysis tool""" + + homepage = "https://github.com/szcompressor/qcat" + git = "https://github.com/szcompressor/qcat" + + maintainers = ["disheng222", "robertu94"] + + version("master", branch="master") + version("1.4", commit="f16032cf237837b1d32dde0c3daa6ad1ca4a912f") + + depends_on("zstd") + + def cmake_args(self): + args = ["-DQCAT_USE_BUNDLES=OFF"] + return args diff --git a/var/spack/repos/builtin/packages/qoz/package.py b/var/spack/repos/builtin/packages/qoz/package.py new file mode 100644 index 00000000000..81ca6bd7944 --- /dev/null +++ b/var/spack/repos/builtin/packages/qoz/package.py @@ -0,0 +1,28 @@ +# 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 Qoz(CMakePackage): + """Quality optimized version of SZ3 is the next generation of the SZ compressor framework""" + + git = "https://github.com/robertu94/QoZ" + homepage = git + + version("2022.04.26", commit="d28a7a8c9f703075441b700202b8a1ee185ded00") + + maintainers = ["disheng222"] + + depends_on("zstd") + depends_on("gsl") + depends_on("pkgconfig") + + def cmake_args(self): + args = [ + "-DQoZ_USE_BUNDLED_ZSTD=OFF", + "-DQoZ_DEBUG_TIMINGS=OFF", + ] + return args diff --git a/var/spack/repos/builtin/packages/r-libpressio/package.py b/var/spack/repos/builtin/packages/r-libpressio/package.py new file mode 100644 index 00000000000..94e90c59b95 --- /dev/null +++ b/var/spack/repos/builtin/packages/r-libpressio/package.py @@ -0,0 +1,36 @@ +# 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 RLibpressio(RPackage): + """R package for libpressio""" + + homepage = "https://github.com/robertu94/libpressio-r" + url = "https://github.com/robertu94/libpressio-r/archive/0.0.1.tar.gz" + + maintainers = ["robertu94"] + + version("1.6.0", sha256="4f8a712e5e84a201373a104e73b10282fcf98f1c7672cc1dd5a2ff07a32d54f6") + version("1.5.0", sha256="6b0e095610f190aad5dded0dbc6c0783893d4d5e773afc80328fc8c5befeff58") + version("1.4.1", sha256="fa9d47c84ddeb4edd9c5250067a87cc1bb549b9b1dd71e2501dd39ee4e171c27") + version("1.3.2", sha256="6afc907aa3663fbb9bfc7c92ca57e15d05ecbec59f94badec24e8da99ac1422f") + version("1.3", sha256="6ade53d30446de85d2bf6aff0f0a756887f970634b97456aec8b2920a96c0726") + version("1.2", sha256="e5889abf6aabd14b25b5c11e8ecc42cfe56681b1e4f7ade9c9fc28de213981b4") + version("1.1", sha256="b86a541e095b6e41b3548f6cd734c1ff50c70edda2806ed66b5205880fbfbb96") + version("0.0.1", sha256="a508cf3ec1b06c417e0de0e1e4180f3175ead2e4ec23b374425fcf2abfaa1b88") + + variant( + "third_party", description="include support for 3rd party compressor modules", default=True + ) + + depends_on("r@3.3.0:", type=("build", "run")) + depends_on("r-rcpp", type=("build", "link", "run")) + depends_on("libpressio+json", type=("build", "link", "run")) + depends_on("libpressio@0.65.0:", type=("build", "link", "run"), when="@1.2:1.5") + depends_on("libpressio@0.88.0:", type=("build", "link", "run"), when="@1.6:") + depends_on("pkgconfig", type=("build")) + depends_on("libpressio-tools@0.1.4:", type=("build", "link", "run"), when="+third_party") diff --git a/var/spack/repos/builtin/packages/r/package.py b/var/spack/repos/builtin/packages/r/package.py index 130ad46c9bd..ffae98f8ef3 100644 --- a/var/spack/repos/builtin/packages/r/package.py +++ b/var/spack/repos/builtin/packages/r/package.py @@ -214,16 +214,19 @@ def setup_dependent_build_environment(self, env, dependent_spec): # Use the number of make_jobs set in spack. The make program will # determine how many jobs can actually be started. env.set("MAKEFLAGS", "-j{0}".format(make_jobs)) + env.set("R_HOME", join_path(self.prefix, "rlib", "R")) def setup_dependent_run_environment(self, env, dependent_spec): # For run time environment set only the path for dependent_spec and # prepend it to R_LIBS + env.set("R_HOME", join_path(self.prefix, "rlib", "R")) if dependent_spec.package.extends(self.spec): env.prepend_path("R_LIBS", join_path(dependent_spec.prefix, self.r_lib_dir)) def setup_run_environment(self, env): env.prepend_path("LD_LIBRARY_PATH", join_path(self.prefix, "rlib", "R", "lib")) env.prepend_path("PKG_CONFIG_PATH", join_path(self.prefix, "rlib", "pkgconfig")) + env.set("R_HOME", join_path(self.prefix, "rlib", "R")) if "+rmath" in self.spec: env.prepend_path("LD_LIBRARY_PATH", join_path(self.prefix, "rlib")) diff --git a/var/spack/repos/builtin/packages/sam2p/package.py b/var/spack/repos/builtin/packages/sam2p/package.py new file mode 100644 index 00000000000..6c4c8e1cb01 --- /dev/null +++ b/var/spack/repos/builtin/packages/sam2p/package.py @@ -0,0 +1,25 @@ +# 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 Sam2p(Package): + """A raster to PostScript/PDF image conversion program""" + + homepage = "https://github.com/pts/sam2p" + url = "https://github.com/pts/sam2p/archive/v0.49.4.tar.gz" + git = homepage + + maintainers = ["robertu94"] + + version("master", branch="master") + version("2021-05-04", commit="f3e9cc0a2df1880a63f9f37c96e3595bca890cfa") + + def install(self, spec, prefix): + compile_sh = Executable("./compile.sh") + compile_sh() + mkdirp(prefix.bin) + install("sam2p", prefix.bin) diff --git a/var/spack/repos/builtin/packages/sperr/package.py b/var/spack/repos/builtin/packages/sperr/package.py new file mode 100644 index 00000000000..4d7482aff18 --- /dev/null +++ b/var/spack/repos/builtin/packages/sperr/package.py @@ -0,0 +1,43 @@ +# 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 Sperr(CMakePackage): + """SPERR is a lossy scientific (floating-point) data compressor that can + perform either error-bounded or size-bounded data compression""" + + homepage = "https://github.com/NCAR/SPERR" + git = homepage + + version("2022.07.18", commit="640305d049db9e9651ebdd773e6936e2c028ff3a") + version("2022.05.26", commit="7894a5fe1b5ca5a4aaa952d1779dfc31fd741243") + + depends_on("git", type="build") + depends_on("zstd", type=("build", "link"), when="+zstd") + depends_on("pkgconf", type=("build"), when="+zstd") + + variant("shared", description="build shared libaries", default=True) + variant("zstd", description="use Zstd for more compression", default=True) + variant("openmp", description="use openmp for acceleration", default=True) + + maintainers = ["shaomeng", "robertu94"] + + def cmake_args(self): + # ensure the compiler supports OpenMP if it is used + if "+openmp" in self.spec: + self.compiler.openmp_flag + + args = [ + self.define_from_variant("BUILD_SHARED_LIBS", "shared"), + self.define_from_variant("USE_ZSTD", "zstd"), + self.define_from_variant("USE_OMP", "openmp"), + "-DSPERR_PREFER_RPATH=OFF", + "-DUSE_BUNDLED_ZSTD=OFF", + "-DBUILD_CLI_UTILITIES=OFF", + "-DBUILD_UNIT_TESTS=OFF", + ] + return args diff --git a/var/spack/repos/builtin/packages/sz-cpp/package.py b/var/spack/repos/builtin/packages/sz-cpp/package.py new file mode 100644 index 00000000000..34a5365a73f --- /dev/null +++ b/var/spack/repos/builtin/packages/sz-cpp/package.py @@ -0,0 +1,29 @@ +# 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 SzCpp(CMakePackage): + """Refactorization of SZ in cpp""" + + homepage = "https://github.com/robertu94/meta_compressor/" + git = "https://github.com/robertu94/meta_compressor/" + + maintainers = ["robertu94"] + + version("2022-01-27", commit="9441b79abc89d4bcce53fe18edf0df53fd92d1d7") + + variant("shared", description="build shared libs", default=True) + + depends_on("zstd") + depends_on("pkgconfig") + + def cmake_args(self): + args = [ + self.define_from_variant("BUILD_SHARED_LIBS", "shared"), + self.define("BUILD_TESTING", self.run_tests), + ] + return args diff --git a/var/spack/repos/builtin/packages/sz3/package.py b/var/spack/repos/builtin/packages/sz3/package.py new file mode 100644 index 00000000000..80a8ff3b02b --- /dev/null +++ b/var/spack/repos/builtin/packages/sz3/package.py @@ -0,0 +1,31 @@ +# 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 Sz3(CMakePackage): + """SZ3 is the next generation of the SZ compressor framework""" + + homepage = "https://github.com/szcompressor/SZ3" + git = "https://github.com/szcompressor/SZ3" + + maintainers = ["disheng222"] + + version("master") + version("3.1.5.4", commit="08df24b566e6d2e419cb95553aebf4a4902a8015") + version("3.1.5.1", commit="5736a63b917e439dd62248b4ff6234e96726af5d") + version("3.1.3.1", commit="323cb17b412d657c4be681b52c34beaf933fe7af") + version("3.1.3", commit="695dff8dc326f3b165f6676d810f46add088a585") + + depends_on("zstd") + depends_on("gsl") + depends_on("pkgconfig") + + def cmake_args(self): + return [ + "-DSZ3_USE_BUNDLED_ZSTD=OFF", + "-DSZ3_DEBUG_TIMINGS=OFF", + ] diff --git a/var/spack/repos/builtin/packages/szauto/package.py b/var/spack/repos/builtin/packages/szauto/package.py new file mode 100644 index 00000000000..744149d6e28 --- /dev/null +++ b/var/spack/repos/builtin/packages/szauto/package.py @@ -0,0 +1,23 @@ +# 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 Szauto(CMakePackage): + """SZauto: SZ C++ Version that Supports Second-Order Prediction and Parameter Optimization""" + + homepage = "https://github.com/szcompressor/SZauto" + url = "https://github.com/szcompressor/SZauto/releases/download/1.0.0/SZauto-1.0.0.tar.gz" + git = "https://github.com/szcompressor/szauto" + + maintainers = ["disheng222", "robertu94"] + + version("master", branch="master") + version("1.2.1", sha256="55c58f58df3a874f684ef864a9247907df0501e5598c089fd2d855ae0309b03a") + version("1.0.0", commit="03f3ab0312bd1de647e9d65746add73a0e8602d2") + + depends_on("zstd") + depends_on("pkgconfig") From c0361168a5d33d3ed77c3ce9eca85eb81fc7ce27 Mon Sep 17 00:00:00 2001 From: snehring <7978778+snehring@users.noreply.github.com> Date: Mon, 17 Oct 2022 14:40:01 -0500 Subject: [PATCH 089/442] New packages: libbigwig, methyldackel (#33273) * libbigwig: adding new package libbigwig * methyldackel: adding new package methyldackel * libbigwig: tighten up curl variant --- .../builtin/packages/libbigwig/package.py | 26 ++++++++++++ .../builtin/packages/methyldackel/package.py | 40 +++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 var/spack/repos/builtin/packages/libbigwig/package.py create mode 100644 var/spack/repos/builtin/packages/methyldackel/package.py diff --git a/var/spack/repos/builtin/packages/libbigwig/package.py b/var/spack/repos/builtin/packages/libbigwig/package.py new file mode 100644 index 00000000000..9b6819b7a77 --- /dev/null +++ b/var/spack/repos/builtin/packages/libbigwig/package.py @@ -0,0 +1,26 @@ +# 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 Libbigwig(CMakePackage): + """A C library for reading/parsing local and remote bigWig and bigBed files.""" + + homepage = "https://github.com/dpryan79/libBigWig" + url = "https://github.com/dpryan79/libBigWig/archive/refs/tags/0.4.7.tar.gz" + maintainers = ["snehring"] + + version("0.4.7", sha256="8e057797011d93fa00e756600898af4fe6ca2d48959236efc9f296abe94916d9") + + variant("curl", default=True, description="Build with curl support") + + depends_on("curl", when="+curl") + + def cmake_args(self): + args = [] + if self.spec.satisfies("~curl"): + args.append("-DWITH_CURL=OFF") + return args diff --git a/var/spack/repos/builtin/packages/methyldackel/package.py b/var/spack/repos/builtin/packages/methyldackel/package.py new file mode 100644 index 00000000000..6e943c4c3d1 --- /dev/null +++ b/var/spack/repos/builtin/packages/methyldackel/package.py @@ -0,0 +1,40 @@ +# 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 Methyldackel(MakefilePackage): + """MethylDackel (formerly named PileOMeth, which was a temporary name + derived due to it using a PILEup to extract METHylation metrics) will + process a coordinate-sorted and indexed BAM or CRAM file containing + some form of BS-seq alignments and extract per-base methylation + metrics from them. + """ + + homepage = "https://github.com/dpryan79/MethylDackel" + url = "https://github.com/dpryan79/MethylDackel/archive/refs/tags/0.6.1.tar.gz" + maintainers = ["snehring"] + + version("0.6.1", sha256="eeb1da4c830bcd9f3e6663a764947d957c41337643069524a4b545812fcf4819") + + depends_on("htslib@1.11:") + depends_on("libbigwig") + depends_on("curl") + + def edit(self, spec, prefix): + filter_file(r"^prefix \?=.*$", "prefix = " + spec.prefix, "Makefile") + filter_file( + "$(LIBBIGWIG)", + join_path(spec["libbigwig"].prefix.lib64, "libBigWig.a"), + "Makefile", + string=True, + ) + filter_file( + "-IlibBigWig", + "-I" + spec["libbigwig"].prefix.include.libbigwig, + "Makefile", + string=True, + ) From 9b87b4c8cd5ea1aeeedf673a352cf28838f01412 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mos=C3=A8=20Giordano?= Date: Mon, 17 Oct 2022 21:06:15 +0100 Subject: [PATCH 090/442] grid: reference `fftw-api` instead of `fftw` (#33374) This makes it possible to compile with, e.g., `cray-fftw`, not just `fftw`. --- var/spack/repos/builtin/packages/grid/package.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/grid/package.py b/var/spack/repos/builtin/packages/grid/package.py index 1427e2f2c6f..d7f19a67398 100644 --- a/var/spack/repos/builtin/packages/grid/package.py +++ b/var/spack/repos/builtin/packages/grid/package.py @@ -77,7 +77,7 @@ def configure_args(self): args.append("--enable-mkl") else: if "+fftw" in spec: - args.append("--with-fftw={0}".format(self.spec["fftw"].prefix)) + args.append("--with-fftw={0}".format(self.spec["fftw-api"].prefix)) if "+lapack" in spec: args.append("--enable-lapack={0}".format(self.spec["lapack"].prefix)) # lapack is searched only as `-llapack`, so anything else From 47bfc60845b71830ee54a04c597419c7eedd2a42 Mon Sep 17 00:00:00 2001 From: Brian Van Essen Date: Mon, 17 Oct 2022 13:07:27 -0700 Subject: [PATCH 091/442] Bugfix HIP and aluminum rocm build (#33344) * Fixed two bugs in the HIP package recipe. The first is that the HIP_PATH was being set to the actual spec, and not the spec prefix. The second bug is that HIP is expected to be in /opt/rocm-x.y.z/hip but it's libraries can exist at both /opt/rocm-x.y.z/hip/lib and /opt/rocm-x.y.z/lib. This means that the external detection logic may find it in either and it turns out that some modules only expose one of those two locations. Logic is added to ensure that the internal HIP_PATH and associated ROCM_PATH are correctly set in both cases. * Added support for Aluminum to use the libfabric plugin with either RCCL or NCCL. --- .../builtin/packages/aluminum/package.py | 17 ++++++++++----- .../repos/builtin/packages/hip/package.py | 21 +++++++++++++++++-- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/var/spack/repos/builtin/packages/aluminum/package.py b/var/spack/repos/builtin/packages/aluminum/package.py index 235aa0b996d..3d903dfaf26 100644 --- a/var/spack/repos/builtin/packages/aluminum/package.py +++ b/var/spack/repos/builtin/packages/aluminum/package.py @@ -52,9 +52,16 @@ class Aluminum(CMakePackage, CudaPackage, ROCmPackage): ) variant("rccl", default=False, description="Builds with support for RCCL communication lib") variant( - "ofi_rccl_plugin", - default=False, - description="Builds with support for OFI libfabric enhanced RCCL communication lib", + "ofi_libfabric_plugin", + default=True, + when="+rccl platform=cray", + description="Builds with support for OFI libfabric enhanced RCCL/NCCL communication lib", + ) + variant( + "ofi_libfabric_plugin", + default=True, + when="+nccl platform=cray", + description="Builds with support for OFI libfabric enhanced RCCL/NCCL communication lib", ) depends_on("cmake@3.21.0:", type="build", when="@1.0.1:") @@ -68,12 +75,12 @@ class Aluminum(CMakePackage, CudaPackage, ROCmPackage): depends_on("hipcub", when="@:0.1,0.6.0: +rocm") depends_on("rccl", when="+rccl") - depends_on("aws-ofi-rccl", when="+ofi_rccl_plugin platform=cray") + depends_on("aws-ofi-rccl", when="+rccl +ofi_libfabric_plugin platform=cray") + depends_on("aws-ofi-nccl", when="+nccl +ofi_libfabric_plugin platform=cray") conflicts("~cuda", when="+cuda_rma", msg="CUDA RMA support requires CUDA") conflicts("+cuda", when="+rocm", msg="CUDA and ROCm support are mutually exclusive") conflicts("+nccl", when="+rccl", msg="NCCL and RCCL support are mutually exclusive") - conflicts("~rccl", when="+ofi_rccl_plugin", msg="libfabric enhancements require RCCL support") generator = "Ninja" depends_on("ninja", type="build") diff --git a/var/spack/repos/builtin/packages/hip/package.py b/var/spack/repos/builtin/packages/hip/package.py index 41c2d2d29fe..9dce2189049 100644 --- a/var/spack/repos/builtin/packages/hip/package.py +++ b/var/spack/repos/builtin/packages/hip/package.py @@ -288,12 +288,22 @@ def get_paths(self): if self.spec.external: # For external packages we only assume the `hip` prefix is known, # because spack does not set prefixes of dependencies of externals. + hip_libs_at_top = os.path.basename(self.spec.prefix) != "hip" # We assume self.spec.prefix is /opt/rocm-x.y.z for rocm-5.2.0 and newer # and /opt/rocm-x.y.z/hip for older versions if self.spec.satisfies("@5.2.0:"): rocm_prefix = Prefix(self.spec.prefix) else: - rocm_prefix = Prefix(os.path.dirname(self.spec.prefix)) + # We assume self.spec.prefix is /opt/rocm-x.y.z/hip and rocm has a + # default installation with everything installed under + # /opt/rocm-x.y.z + # Note that since the key hip library can also exist at the top of the + # /opt/rocm-x.y.z/lib tree, it is possible that the package is detected + # without the correct prefix. Work around it. + if hip_libs_at_top: + rocm_prefix = Prefix(self.spec.prefix) + else: + rocm_prefix = Prefix(os.path.dirname(self.spec.prefix)) if not os.path.isdir(rocm_prefix): msg = "Could not determine prefix for other rocm components\n" @@ -302,7 +312,13 @@ def get_paths(self): msg += "a workaround." raise RuntimeError(msg) + if hip_libs_at_top: + hip_path = "{0}/hip".format(self.spec.prefix) + else: + hip_path = self.spec.prefix + paths = { + "hip-path": hip_path, "rocm-path": rocm_prefix, "llvm-amdgpu": rocm_prefix.llvm, "hsa-rocr-dev": rocm_prefix.hsa, @@ -311,6 +327,7 @@ def get_paths(self): } else: paths = { + "hip-path": self.spec.prefix, "rocm-path": self.spec.prefix, "llvm-amdgpu": self.spec["llvm-amdgpu"].prefix, "hsa-rocr-dev": self.spec["hsa-rocr-dev"].prefix, @@ -374,7 +391,7 @@ def set_variables(self, env): env.set("HIP_DEVICE_LIB_PATH", paths["bitcode"]) # Just the prefix of hip (used in hipcc) - env.set("HIP_PATH", paths["rocm-path"]) + env.set("HIP_PATH", paths["hip-path"]) # Used in comgr and seems necessary when using the JIT compiler, e.g. # hiprtcCreateProgram: From 9d11b96e4bd9d0d7b3516224b074864d61ef6cc0 Mon Sep 17 00:00:00 2001 From: Michael Kuhn Date: Mon, 17 Oct 2022 22:42:03 +0200 Subject: [PATCH 092/442] lz4: add 1.9.4 (#33334) --- var/spack/repos/builtin/packages/lz4/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/lz4/package.py b/var/spack/repos/builtin/packages/lz4/package.py index 4c3dbfffd2d..c2b34a5d2d6 100644 --- a/var/spack/repos/builtin/packages/lz4/package.py +++ b/var/spack/repos/builtin/packages/lz4/package.py @@ -17,6 +17,7 @@ class Lz4(MakefilePackage): homepage = "https://lz4.github.io/lz4/" url = "https://github.com/lz4/lz4/archive/v1.9.2.tar.gz" + version("1.9.4", sha256="0b0e3aa07c8c063ddf40b082bdf7e37a1562bda40a0ff5272957f3e987e0e54b") version("1.9.3", sha256="030644df4611007ff7dc962d981f390361e6c97a34e5cbc393ddfbe019ffe2c1") version("1.9.2", sha256="658ba6191fa44c92280d4aa2c271b0f4fbc0e34d249578dd05e50e76d0e5efcc") version("1.9.0", sha256="f8b6d5662fa534bd61227d313535721ae41a68c9d84058b7b7d86e143572dcfb") From dd003f66a8b8590774db01dc0b858443ea065492 Mon Sep 17 00:00:00 2001 From: eugeneswalker <38933153+eugeneswalker@users.noreply.github.com> Date: Mon, 17 Oct 2022 14:04:31 -0700 Subject: [PATCH 093/442] e4s ci stack: add trilinos +rocm (#31601) --- share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml index 6158234a8ab..0204bf00d32 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml @@ -223,6 +223,11 @@ spack: - superlu-dist +rocm amdgpu_target=gfx90a - tasmanian ~openmp +rocm amdgpu_target=gfx90a - tau +mpi +rocm + - trilinos@13.4.0 +amesos +amesos2 +anasazi +aztec ~belos +boost +epetra +epetraext + +ifpack ~ifpack2 +intrepid +intrepid2 +isorropia +kokkos +ml +minitensor +muelu + +nox +piro +phalanx +rol +rythmos +sacado +stk +shards +shylu ~stokhos +stratimikos + +teko +tempus +tpetra +trilinoscouplings +zoltan +zoltan2 +superlu-dist gotype=long_long + +rocm amdgpu_target=gfx90a - upcxx +rocm amdgpu_target=gfx90a - vtk-m ~openmp +rocm amdgpu_target=gfx90a From 0b014ff9cdd71dd582eb68aacc109844438ab2cf Mon Sep 17 00:00:00 2001 From: "Adam J. Stewart" Date: Mon, 17 Oct 2022 23:33:50 -0500 Subject: [PATCH 094/442] py-fiona: add v1.8.22 (#33372) --- var/spack/repos/builtin/packages/py-fiona/package.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/py-fiona/package.py b/var/spack/repos/builtin/packages/py-fiona/package.py index 5d7dc23759f..a43daa0bb65 100644 --- a/var/spack/repos/builtin/packages/py-fiona/package.py +++ b/var/spack/repos/builtin/packages/py-fiona/package.py @@ -16,6 +16,7 @@ class PyFiona(PythonPackage): maintainers = ["adamjstewart"] version("master", branch="master") + version("1.8.22", sha256="a82a99ce9b3e7825740157c45c9fb2259d4e92f0a886aaac25f0db40ffe1eea3") version("1.8.21", sha256="3a0edca2a7a070db405d71187214a43d2333a57b4097544a3fcc282066a58bfc") version("1.8.20", sha256="a70502d2857b82f749c09cb0dea3726787747933a2a1599b5ab787d74e3c143b") version("1.8.18", sha256="b732ece0ff8886a29c439723a3e1fc382718804bb057519d537a81308854967a") @@ -28,7 +29,7 @@ class PyFiona(PythonPackage): depends_on("gdal@1.11:", type=("build", "link", "run"), when="@1.9:") depends_on("gdal@1.8:", type=("build", "link", "run")) - depends_on("py-cython", type="build", when="@master") + depends_on("py-cython@0.29.29:", type="build", when="@master") depends_on("py-attrs@17:", type=("build", "run")) depends_on("py-certifi", type=("build", "run"), when="@1.8.18:") depends_on("py-click@4:", type=("build", "run")) From fe2656f182c5707f65175481cf25b43f60b11900 Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Tue, 18 Oct 2022 07:19:25 +0200 Subject: [PATCH 095/442] intel-oneapi-compilers: fix Python 2.7 compliance (#33383) --- .../repos/builtin/packages/intel-oneapi-compilers/package.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 0ad8d3921d7..f9c832eb8d0 100644 --- a/var/spack/repos/builtin/packages/intel-oneapi-compilers/package.py +++ b/var/spack/repos/builtin/packages/intel-oneapi-compilers/package.py @@ -131,7 +131,7 @@ class IntelOneapiCompilers(IntelOneApiPackage): placement="fortran-installer", when="@{0}".format(v["version"]), expand=False, - **v["ftn"], + **v["ftn"] ) @property @@ -214,7 +214,7 @@ def write_cfg(cmp_list, flags_list): f.write(flags) set_install_permissions(cfg_file) - # Make sure that icc gets the right GCC C+ support + # Make sure that icc gets the right GCC C++ support write_cfg( [ join_path("intel64", "icc"), From b21e54dffa7b666462f063ab9d4d51109202b956 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Oct 2022 10:22:30 +0200 Subject: [PATCH 096/442] build(deps): bump docker/setup-buildx-action from 2.1.0 to 2.2.0 (#33384) Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 2.1.0 to 2.2.0. - [Release notes](https://github.com/docker/setup-buildx-action/releases) - [Commits](https://github.com/docker/setup-buildx-action/compare/95cb08cb2672c73d4ffd2f422e6d11953d2a9c70...c74574e6c82eeedc46366be1b0d287eff9085eb6) --- updated-dependencies: - dependency-name: docker/setup-buildx-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-containers.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-containers.yml b/.github/workflows/build-containers.yml index 0662ad75c5c..940e9d965fb 100644 --- a/.github/workflows/build-containers.yml +++ b/.github/workflows/build-containers.yml @@ -89,7 +89,7 @@ jobs: uses: docker/setup-qemu-action@8b122486cedac8393e77aa9734c3528886e4a1a8 # @v1 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@95cb08cb2672c73d4ffd2f422e6d11953d2a9c70 # @v1 + uses: docker/setup-buildx-action@c74574e6c82eeedc46366be1b0d287eff9085eb6 # @v1 - name: Log in to GitHub Container Registry uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a # @v1 From 8e8d6e5adbbf7cd54fa7f146863c6f380d5897e6 Mon Sep 17 00:00:00 2001 From: snehring <7978778+snehring@users.noreply.github.com> Date: Tue, 18 Oct 2022 09:54:23 -0500 Subject: [PATCH 097/442] mothur: add v1.48.0 and variants (#33326) --- .../repos/builtin/packages/mothur/package.py | 83 ++++++++++++++----- 1 file changed, 63 insertions(+), 20 deletions(-) diff --git a/var/spack/repos/builtin/packages/mothur/package.py b/var/spack/repos/builtin/packages/mothur/package.py index 2d546c79581..3e88378a5d6 100644 --- a/var/spack/repos/builtin/packages/mothur/package.py +++ b/var/spack/repos/builtin/packages/mothur/package.py @@ -4,7 +4,6 @@ # SPDX-License-Identifier: (Apache-2.0 OR MIT) from spack.package import * -from spack.pkg.builtin.boost import Boost class Mothur(MakefilePackage): @@ -15,37 +14,81 @@ class Mothur(MakefilePackage): homepage = "https://github.com/mothur/mothur" url = "https://github.com/mothur/mothur/archive/v1.39.5.tar.gz" + version("1.48.0", sha256="9494406abd8d14b821782ab9db811f045ded9424f28f01234ee6764d4e78941d") version("1.46.1", sha256="29b500b3c92d726cde34922f697f2e47f0b7127d76d9a6fb167cc2b8ba3d00fd") version("1.43.0", sha256="12ccd95a85bec3bb1564b8feabd244ea85413973740754803d01fc71ecb0a2c1") version("1.42.1", sha256="6b61591dda289ac2d8361f9c1547ffbeeba3b9fbdff877dd286bad850bbd5539") version("1.40.5", sha256="a0fbdfa68b966d7adc4560e3787506a0dad8b47b4b996c2663cd6c0b416d101a") version("1.39.5", sha256="9f1cd691e9631a2ab7647b19eb59cd21ea643f29b22cde73d7f343372dfee342") + maintainers = ["snehring"] - variant("vsearch", default=False, description="Use vsearch") + variant( + "boost", + default=True, + description="Build with boost support (allow make.contigs to read gz files).", + ) + variant("hdf5", default=False, description="Build with hdf5 support", when="@1.41.0:") + variant( + "gsl", default=False, description="Build with the gnu scientific libaries", when="@1.43.0:" + ) - # 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) + depends_on("boost+iostreams+filesystem+system", when="+boost") + depends_on("gsl", when="+gsl") + depends_on("hdf5+cxx", when="+hdf5") depends_on("readline") - depends_on("vsearch@2.13.3", when="+vsearch", type="run") + depends_on("vsearch@2.13.5:", type="run") + depends_on("usearch", type="run") + depends_on("zlib", when="+boost") def edit(self, spec, prefix): - makefile = FileFilter("Makefile") - makefile.filter( - 'BOOST_LIBRARY_DIR="\\"Enter_your_boost_library_path' '_here\\""', - "BOOST_LIBRARY_DIR=%s" % self.spec["boost"].prefix.lib, - ) - makefile.filter( - 'BOOST_INCLUDE_DIR="\\"Enter_your_boost_include_path' '_here\\""', - "BOOST_INCLUDE_DIR=%s" % self.spec["boost"].prefix.include, - ) - makefile.filter( - 'MOTHUR_FILES="\\"Enter_your_default_path_' 'here\\""', "MOTHUR_FILES=%s" % prefix - ) + filter_file(r"^.*DMOTHUR_TOOLS.*$", "", "Makefile") + filter_file(r"^.*DMOTHUR_FILES.*$", "", "Makefile") + filter_file(r"(\$\(skipUchime\))", r"\1, source/", "Makefile") + if spec.satisfies("@1.40.5"): + filter_file( + r"^(#define writer_h)", "\\1 \n#include", join_path("source", "writer.h") + ) + # this includes the public domain uchime, which needs work to + # compile on newer compilers we'll use what's in usearch + filter_file(" uchime", "", "Makefile") + if spec.satisfies("+boost"): + filter_file(r"USEBOOST \?=.*$", "USEBOOST = yes", "Makefile") + filter_file( + r"^BOOST_LIBRARY_DIR .*$", + "BOOST_LIBRARY_DIR=%s" % self.spec["boost"].prefix.lib, + "Makefile", + ) + filter_file( + r"BOOST_INCLUDE_DIR .*$", + "BOOST_INCLUDE_DIR=%s" % self.spec["boost"].prefix.include, + "Makefile", + ) + if spec.satisfies("+hdf5"): + filter_file(r"USEHDF5 \?=.*$", "USEHDF5 = yes", "Makefile") + filter_file( + r"^HDF5_LIBRARY_DIR \?=.*$", + "HDF5_LIBRARY_DIR = " + spec["hdf5"].prefix.lib, + "Makefile", + ) + filter_file( + r"^HDF5_INCLUDE_DIR \?=.*$", + "HDF5_INCLUDE_DIR = " + spec["hdf5"].prefix.include, + "Makefile", + ) + if spec.satisfies("+gsl"): + filter_file(r"^USEGSL \?=.*$", "USEGSL = yes", "Makefile") + filter_file( + r"GSL_LIBRARY_DIR \?=.*$", + "GSL_LIBRARY_DIR = " + spec["gsl"].prefix.lib, + "Makefile", + ) + filter_file( + r"GSL_INCLUDE_DIR \?=.*$", + "GSL_INCLUDE_DIR = " + spec["gsl"].prefix.include, + "Makefile", + ) def install(self, spec, prefix): mkdirp(prefix.bin) install("mothur", prefix.bin) - install("uchime", prefix.bin) install_tree("source", prefix.include) From b44c83429c78b62ff64394988e9f96d724400d07 Mon Sep 17 00:00:00 2001 From: snehring <7978778+snehring@users.noreply.github.com> Date: Tue, 18 Oct 2022 09:59:38 -0500 Subject: [PATCH 098/442] vsearch: add v2.22.1 (#33327) --- var/spack/repos/builtin/packages/vsearch/package.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/var/spack/repos/builtin/packages/vsearch/package.py b/var/spack/repos/builtin/packages/vsearch/package.py index f975bf9e5ab..18e3b9f6895 100644 --- a/var/spack/repos/builtin/packages/vsearch/package.py +++ b/var/spack/repos/builtin/packages/vsearch/package.py @@ -11,7 +11,9 @@ class Vsearch(AutotoolsPackage): homepage = "https://github.com/torognes/vsearch" url = "https://github.com/torognes/vsearch/archive/v2.4.3.tar.gz" + maintainers = ["snehring"] + version("2.22.1", sha256="c62bf69e7cc3d011a12e3b522ba8c0c91fb90deea782359e9569677d0c991778") version("2.14.1", sha256="388529a39eb0618a09047bf91e0a8ae8c9fd851a05f8d975e299331748f97741") version("2.13.3", sha256="e5f34ece28b76403d3ba4a673eca41178fe399c35a1023dbc87d0c0da5efaa52") version("2.4.3", sha256="f7ffc2aec5d76bdaf1ffe7fb733102138214cec3e3846eb225455dcc3c088141") @@ -19,4 +21,6 @@ class Vsearch(AutotoolsPackage): depends_on("m4", type="build") depends_on("autoconf", type="build") depends_on("automake", type="build") + depends_on("bzip2") depends_on("libtool", type="build") + depends_on("zlib") From d95f14084ea438185e35e9ce0cfa20dda4cff7bc Mon Sep 17 00:00:00 2001 From: Howard Pritchard Date: Tue, 18 Oct 2022 11:18:04 -0600 Subject: [PATCH 099/442] papi: fix for Intel OneAPI compiler (#33225) Without this patch one hits this error trying to compiler papi with Intel OneAPI: icx: error: Note that use of '-g' without any optimization-level option will turn off most compiler optimizations similar to use of '-O0' [-Werror,-Wdebug-disables-optimization] Signed-off-by: Howard Pritchard Signed-off-by: Howard Pritchard --- var/spack/repos/builtin/packages/papi/package.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/var/spack/repos/builtin/packages/papi/package.py b/var/spack/repos/builtin/packages/papi/package.py index f3fe762e448..35ea13fbd9c 100644 --- a/var/spack/repos/builtin/packages/papi/package.py +++ b/var/spack/repos/builtin/packages/papi/package.py @@ -105,6 +105,11 @@ def setup_build_environment(self, env): env.set("HSA_TOOLS_LIB", "unset") if "+rocm_smi" in spec: env.append_flags("CFLAGS", "-I%s/rocm_smi" % spec["rocm-smi-lib"].prefix.include) + # + # Intel OneAPI LLVM cannot compile papi unless the DBG enviroment variable is cleared + # + if spec.satisfies("%oneapi"): + env.set("DBG", "") setup_run_environment = setup_build_environment From 1ae32ff62c0827e3cc6150e1127cab91be694c91 Mon Sep 17 00:00:00 2001 From: Bernhard Kaindl <43588962+bernhardkaindl@users.noreply.github.com> Date: Tue, 18 Oct 2022 19:18:49 +0200 Subject: [PATCH 100/442] go,gcc: Support external go compilers for Go bootstrap (#27769) For ARM64, fallback to gccgo. (go-bootstrap@1.4 can't support ARM64) --- etc/spack/defaults/packages.yaml | 3 +- .../repos/builtin/packages/gcc/package.py | 20 ++++++++++++- .../builtin/packages/go-bootstrap/package.py | 29 ++++++++++++++++++- .../repos/builtin/packages/go/package.py | 13 ++++----- 4 files changed, 55 insertions(+), 10 deletions(-) diff --git a/etc/spack/defaults/packages.yaml b/etc/spack/defaults/packages.yaml index ead2d872c7d..f0596b0fe1d 100644 --- a/etc/spack/defaults/packages.yaml +++ b/etc/spack/defaults/packages.yaml @@ -27,7 +27,8 @@ packages: fuse: [libfuse] gl: [glx, osmesa] glu: [mesa-glu, openglu] - golang: [gcc] + golang: [go, gcc] + go-external-or-gccgo-bootstrap: [go-bootstrap, gcc] iconv: [libiconv] ipp: [intel-ipp] java: [openjdk, jdk, ibm-java] diff --git a/var/spack/repos/builtin/packages/gcc/package.py b/var/spack/repos/builtin/packages/gcc/package.py index 67b065a107c..f36980d8e70 100644 --- a/var/spack/repos/builtin/packages/gcc/package.py +++ b/var/spack/repos/builtin/packages/gcc/package.py @@ -206,9 +206,24 @@ class Gcc(AutotoolsPackage, GNUMirrorPackage): provides("golang@:1.4", when="@5:") provides("golang@:1.6.1", when="@6:") provides("golang@:1.8", when="@7:") + provides("golang@:1.10", when="@8:") + provides("golang@:1.12", when="@9:") + provides("golang@:1.14", when="@10:") + provides("golang@:1.16", when="@11:") + provides("golang@:1.18", when="@11:") # GCC 4.6 added support for the Go programming language. # See https://gcc.gnu.org/gcc-4.6/changes.html conflicts("@:4.5", msg="support for Go has been added in GCC 4.6") + # aarch64 machines (including Macs with Apple silicon) can't use + # go-bootstrap because it pre-dates aarch64 support in Go. When not + # using an external go bootstrap go, These machines have to rely on + # Go support in gcc (which may require compiling a version of gcc + # with Go support just to satisfy this requirement). However, + # there's also a bug in some versions of GCC's Go front-end that prevents + # these versions from properly bootstrapping Go. (See issue #47771 + # https://github.com/golang/go/issues/47771 ) On the 10.x branch, we need + # at least 10.4. On the 11.x branch, we need at least 11.3: + provides("go-external-or-gccgo-bootstrap", when="gcc@10.4.0:10,11.3.0:target=aarch64:") # Go is not supported on macOS conflicts("platform=darwin", msg="Go not supported on MacOS") @@ -442,7 +457,7 @@ class Gcc(AutotoolsPackage, GNUMirrorPackage): @classproperty def executables(cls): - names = [r"gcc", r"[^\w]?g\+\+", r"gfortran", r"gdc"] + names = [r"gcc", r"[^\w]?g\+\+", r"gfortran", r"gdc", r"gccgo"] suffixes = [r"", r"-mp-\d+\.\d", r"-\d+\.\d", r"-\d+", r"\d\d"] return [r"".join(x) for x in itertools.product(names, suffixes)] @@ -520,6 +535,9 @@ def determine_variants(cls, exes, version_str): elif "gcc" in basename: languages.add("c") compilers["c"] = exe + elif "gccgo" in basename: + languages.add("go") + compilers["go"] = exe elif "gdc" in basename: languages.add("d") compilers["d"] = exe diff --git a/var/spack/repos/builtin/packages/go-bootstrap/package.py b/var/spack/repos/builtin/packages/go-bootstrap/package.py index 7068a44c93a..a622ffd72a1 100644 --- a/var/spack/repos/builtin/packages/go-bootstrap/package.py +++ b/var/spack/repos/builtin/packages/go-bootstrap/package.py @@ -3,6 +3,8 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import re + from spack.package import * # THIS PACKAGE SHOULD NOT EXIST @@ -47,6 +49,25 @@ class GoBootstrap(Package): conflicts("os=monterey", msg="go-bootstrap won't build on new macOS") conflicts("target=aarch64:", msg="Go bootstrap doesn't support aarch64 architectures") + # This virtual package allows a fallback to gccgo for aarch64, + # where go-bootstrap cannot be built(aarch64 was added with Go 1.5) + provides("go-external-or-gccgo-bootstrap") + + # Support for aarch64 was added in Go 1.5, use an external package or gccgo instead: + conflicts("@:1.4", when="target=aarch64:") + + executables = ["^go$"] + + # When the user adds a go compiler using ``spack external find go-bootstrap``, + # this lets us get the version for packages.yaml. Then, the solver can avoid + # to build the bootstrap go compiler(for aarch64, it's only gccgo) from source: + @classmethod + def determine_version(cls, exe): + """Return the version of an externally provided go executable or ``None``""" + output = Executable(exe)("version", output=str, error=str) + match = re.search(r"go version go(\S+)", output) + return match.group(1) if match else None + def patch(self): if self.spec.satisfies("@:1.4.3"): # NOTE: Older versions of Go attempt to download external files that have @@ -72,7 +93,13 @@ def install(self, spec, prefix): install_tree(".", prefix) def setup_dependent_build_environment(self, env, dependent_spec): - env.set("GOROOT_BOOTSTRAP", self.spec.prefix) + """Set GOROOT_BOOTSTRAP: When using an external compiler, get its GOROOT env""" + if self.spec.external: + # Use the go compiler added by ``spack external find go-bootstrap``: + goroot = Executable(self.spec.prefix.bin.go)("env", "GOROOT", output=str) + else: + goroot = self.spec.prefix + env.set("GOROOT_BOOTSTRAP", goroot) def setup_build_environment(self, env): env.set("GOROOT_FINAL", self.spec.prefix) diff --git a/var/spack/repos/builtin/packages/go/package.py b/var/spack/repos/builtin/packages/go/package.py index e1425f06c86..b4f2c769595 100644 --- a/var/spack/repos/builtin/packages/go/package.py +++ b/var/spack/repos/builtin/packages/go/package.py @@ -152,14 +152,13 @@ class Go(Package): # aarch64 machines (including Macs with Apple silicon) can't use # go-bootstrap because it pre-dates aarch64 support in Go. These machines # have to rely on Go support in gcc (which may require compiling a version - # of gcc with Go support just to satisfy this requirement). However, - # there's also a bug in some versions of GCC's Go front-end that prevents - # these versions from properly bootstrapping Go. (See issue #47771 - # https://github.com/golang/go/issues/47771 ) On the 10.x branch, we need - # at least 10.4. On the 11.x branch, we need at least 11.3. + # of gcc with Go support just to satisfy this requirement) or external go: - if platform.machine() == "aarch64": - depends_on("gcc@10.4.0:10,11.3.0: languages=go", type="build") + # #27769: On M1/MacOS, platform.machine() may return arm64: + if platform.machine() in ["arm64", "aarch64"]: + # Use an external go compiler from packages.yaml/`spack external find go-bootstrap`, + # but fallback to build go-bootstrap@1.4 or to gcc with languages=go (for aarch64): + depends_on("go-external-or-gccgo-bootstrap", type="build") else: depends_on("go-bootstrap", type="build") From c6c5e56ec1adb23c7fe20a51ea721ad40a6570ba Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Tue, 18 Oct 2022 20:52:28 +0200 Subject: [PATCH 101/442] Reusable --use-buildcache with better validation (#33388) Co-authored-by: Massimiliano Culpo --- lib/spack/spack/cmd/common/arguments.py | 56 ++++++++++++++++++++ lib/spack/spack/cmd/install.py | 32 +---------- lib/spack/spack/test/cmd/common/arguments.py | 16 ++++++ lib/spack/spack/test/cmd/install.py | 3 +- 4 files changed, 76 insertions(+), 31 deletions(-) diff --git a/lib/spack/spack/cmd/common/arguments.py b/lib/spack/spack/cmd/common/arguments.py index c9f15cfa98b..7e68ac594bf 100644 --- a/lib/spack/spack/cmd/common/arguments.py +++ b/lib/spack/spack/cmd/common/arguments.py @@ -6,6 +6,8 @@ import argparse +from llnl.util.lang import stable_partition + import spack.cmd import spack.config import spack.dependency as dep @@ -437,3 +439,57 @@ def add_s3_connection_args(subparser, add_help): subparser.add_argument( "--s3-endpoint-url", help="Endpoint URL to use to connect to this S3 mirror" ) + + +def use_buildcache(cli_arg_value): + """Translate buildcache related command line arguments into a pair of strings, + representing whether the root or its dependencies can use buildcaches. + + Argument type that accepts comma-separated subargs: + + 1. auto|only|never + 2. package:auto|only|never + 3. dependencies:auto|only|never + + Args: + cli_arg_value (str): command line argument value to be translated + + Return: + Tuple of two strings + """ + valid_keys = frozenset(["package", "dependencies"]) + valid_values = frozenset(["only", "never", "auto"]) + + # Split in args, split in key/value, and trim whitespace + args = [tuple(map(lambda x: x.strip(), part.split(":"))) for part in cli_arg_value.split(",")] + + # Verify keys and values + def is_valid(arg): + if len(arg) == 1: + return arg[0] in valid_values + if len(arg) == 2: + return arg[0] in valid_keys and arg[1] in valid_values + return False + + valid, invalid = stable_partition(args, is_valid) + + # print first error + if invalid: + raise argparse.ArgumentTypeError("invalid argument `{}`".format(":".join(invalid[0]))) + + # Default values + package = "auto" + dependencies = "auto" + + # Override in order. + for arg in valid: + if len(arg) == 1: + package = dependencies = arg[0] + continue + key, val = arg + if key == "package": + package = val + else: + dependencies = val + + return package, dependencies diff --git a/lib/spack/spack/cmd/install.py b/lib/spack/spack/cmd/install.py index a6fdfd31f48..640b48a6d0f 100644 --- a/lib/spack/spack/cmd/install.py +++ b/lib/spack/spack/cmd/install.py @@ -5,7 +5,6 @@ import argparse import os -import re import shutil import sys import textwrap @@ -32,33 +31,6 @@ level = "short" -# Pass in the value string passed to use-buildcache and get back -# the package and dependencies values. -def parse_use_buildcache(opt): - bc_keys = ["package:", "dependencies:", ""] - bc_values = ["only", "never", "auto"] - kv_list = re.findall("([a-z]+:)?([a-z]+)", opt) - - # Verify keys and values - bc_map = {k: v for k, v in kv_list if k in bc_keys and v in bc_values} - if not len(kv_list) == len(bc_map): - tty.error("Unrecognized arguments passed to use-buildcache") - tty.error( - "Expected: --use-buildcache " - "[[auto|only|never],[package:[auto|only|never]],[dependencies:[auto|only|never]]]" - ) - exit(1) - - for _group in ["package:", "dependencies:"]: - if _group not in bc_map: - if "" in bc_map: - bc_map[_group] = bc_map[""] - else: - bc_map[_group] = "auto" - - return bc_map["package:"], bc_map["dependencies:"] - - # Determine value of cache flag def cache_opt(default_opt, use_buildcache): if use_buildcache == "auto": @@ -73,8 +45,7 @@ def install_kwargs_from_args(args): """Translate command line arguments into a dictionary that will be passed to the package installer. """ - - pkg_use_bc, dep_use_bc = parse_use_buildcache(args.use_buildcache) + pkg_use_bc, dep_use_bc = args.use_buildcache return { "fail_fast": args.fail_fast, @@ -169,6 +140,7 @@ def setup_parser(subparser): cache_group.add_argument( "--use-buildcache", dest="use_buildcache", + type=arguments.use_buildcache, default="package:auto,dependencies:auto", metavar="[{auto,only,never},][package:{auto,only,never},][dependencies:{auto,only,never}]", help="""select the mode of buildcache for the 'package' and 'dependencies'. diff --git a/lib/spack/spack/test/cmd/common/arguments.py b/lib/spack/spack/test/cmd/common/arguments.py index 58bf8e0ac58..772cc0297eb 100644 --- a/lib/spack/spack/test/cmd/common/arguments.py +++ b/lib/spack/spack/test/cmd/common/arguments.py @@ -129,3 +129,19 @@ def test_concretizer_arguments(mutable_config, mock_packages): spec("--fresh", "zlib") assert spack.config.get("concretizer:reuse", None) is False + + +def test_use_buildcache_type(): + assert arguments.use_buildcache("only") == ("only", "only") + assert arguments.use_buildcache("never") == ("never", "never") + assert arguments.use_buildcache("auto") == ("auto", "auto") + assert arguments.use_buildcache("package:never,dependencies:only") == ("never", "only") + assert arguments.use_buildcache("only,package:never") == ("never", "only") + assert arguments.use_buildcache("package:only,package:never") == ("never", "auto") + assert arguments.use_buildcache("auto , package: only") == ("only", "auto") + + with pytest.raises(argparse.ArgumentTypeError): + assert arguments.use_buildcache("pkg:only,deps:never") + + with pytest.raises(argparse.ArgumentTypeError): + assert arguments.use_buildcache("sometimes") diff --git a/lib/spack/spack/test/cmd/install.py b/lib/spack/spack/test/cmd/install.py index e74f01db7fd..8c37ea3e98b 100644 --- a/lib/spack/spack/test/cmd/install.py +++ b/lib/spack/spack/test/cmd/install.py @@ -17,6 +17,7 @@ import llnl.util.filesystem as fs import llnl.util.tty as tty +import spack.cmd.common.arguments import spack.cmd.install import spack.compilers as compilers import spack.config @@ -1132,7 +1133,7 @@ def install_use_buildcache(opt): "--no-check-signature", "--use-buildcache", opt, package_name, fail_on_error=True ) - pkg_opt, dep_opt = spack.cmd.install.parse_use_buildcache(opt) + pkg_opt, dep_opt = spack.cmd.common.arguments.use_buildcache(opt) validate(dep_opt, out, dependency_name) validate(pkg_opt, out, package_name) From 13356f3bfa2b5cc6d77def51416bce9413acfd02 Mon Sep 17 00:00:00 2001 From: Tamara Dahlgren <35777542+tldahlgren@users.noreply.github.com> Date: Tue, 18 Oct 2022 12:11:21 -0700 Subject: [PATCH 102/442] Docs: Spack info option updates (#33376) --- lib/spack/docs/basic_usage.rst | 2 +- .../docs/build_systems/inteloneapipackage.rst | 2 +- lib/spack/docs/packaging_guide.rst | 33 ++++++++++++++----- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/lib/spack/docs/basic_usage.rst b/lib/spack/docs/basic_usage.rst index 53bd3858e04..b8b758e6eda 100644 --- a/lib/spack/docs/basic_usage.rst +++ b/lib/spack/docs/basic_usage.rst @@ -85,7 +85,7 @@ All packages whose names or descriptions contain documentation: To get more information on a particular package from `spack list`, use `spack info`. Just supply the name of a package: -.. command-output:: spack info mpich +.. command-output:: spack info --all mpich Most of the information is self-explanatory. The *safe versions* are versions that Spack knows the checksum for, and it will use the diff --git a/lib/spack/docs/build_systems/inteloneapipackage.rst b/lib/spack/docs/build_systems/inteloneapipackage.rst index fe6aea91bbc..c16c368dd4e 100644 --- a/lib/spack/docs/build_systems/inteloneapipackage.rst +++ b/lib/spack/docs/build_systems/inteloneapipackage.rst @@ -32,7 +32,7 @@ oneAPI packages or use:: For more information on a specific package, do:: - spack info + spack info --all Intel no longer releases new versions of Parallel Studio, which can be used in Spack via the :ref:`intelpackage`. All of its components can diff --git a/lib/spack/docs/packaging_guide.rst b/lib/spack/docs/packaging_guide.rst index 5662c3c3f26..556dde31e85 100644 --- a/lib/spack/docs/packaging_guide.rst +++ b/lib/spack/docs/packaging_guide.rst @@ -3369,27 +3369,44 @@ The name and order in which the phases will be executed can be obtained either r docs at :py:mod:`~.spack.build_systems`, or using the ``spack info`` command: .. code-block:: console - :emphasize-lines: 13,14 + :emphasize-lines: 26-27 - $ spack info m4 - AutotoolsPackage: m4 - Homepage: https://www.gnu.org/software/m4/m4.html + $ spack info --phases m4 + AutotoolsPackage: m4 + + Description: + GNU M4 is an implementation of the traditional Unix macro processor. + + Homepage: https://www.gnu.org/software/m4/m4.html + + Preferred version: + 1.4.19 https://ftpmirror.gnu.org/m4/m4-1.4.19.tar.gz Safe versions: - 1.4.17 ftp://ftp.gnu.org/gnu/m4/m4-1.4.17.tar.gz + 1.4.19 https://ftpmirror.gnu.org/m4/m4-1.4.19.tar.gz + 1.4.18 https://ftpmirror.gnu.org/m4/m4-1.4.18.tar.gz + 1.4.17 https://ftpmirror.gnu.org/m4/m4-1.4.17.tar.gz + + Deprecated versions: + None Variants: - Name Default Description + Name [Default] When Allowed values Description + ============== ==== ============== =============================== - sigsegv on Build the libsigsegv dependency + sigsegv [on] -- on, off Build the libsigsegv dependency Installation Phases: autoreconf configure build install Build Dependencies: + diffutils gnuconfig libsigsegv + + Link Dependencies: libsigsegv - ... + Run Dependencies: + None Typically, phases have default implementations that fit most of the common cases: From 7bb4b58b8b06aaff7635b702093585891c966f2d Mon Sep 17 00:00:00 2001 From: Robert Cohn Date: Tue, 18 Oct 2022 18:17:50 -0400 Subject: [PATCH 103/442] intel-oneapi-compilers: do not pass -Wno-unused-command-line-argument to icc + refactor (#33389) --- .../intel-oneapi-compilers/package.py | 46 ++++++++----------- 1 file changed, 20 insertions(+), 26 deletions(-) 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 f9c832eb8d0..fa6d9f7ac11 100644 --- a/var/spack/repos/builtin/packages/intel-oneapi-compilers/package.py +++ b/var/spack/repos/builtin/packages/intel-oneapi-compilers/package.py @@ -182,6 +182,13 @@ def inject_rpaths(self): # should not be patched patchelf(file, fail_on_error=False) + def write_config_file(self, flags, path, compilers): + for compiler in compilers: + p = path.join(compiler + ".cfg") + with open(p, "w") as f: + f.write(" ".join(flags)) + set_install_permissions(p) + @run_after("install") def extend_config_flags(self): # Extends compiler config files to inject additional compiler flags. @@ -196,7 +203,12 @@ def extend_config_flags(self): # TODO: it is unclear whether we should really use all elements of # _ld_library_path because it looks like the only rpath that needs to be # injected is self.component_prefix.linux.compiler.lib.intel64_lin. - flags_list = ["-Wl,-rpath,{}".format(d) for d in self._ld_library_path()] + 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)) # Older versions trigger -Wunused-command-line-argument warnings whenever # linker flags are passed in preprocessor (-E) or compilation mode (-c). @@ -204,33 +216,15 @@ def extend_config_flags(self): # do not trigger these warnings. In some build systems these warnings can # cause feature detection to fail, so we silence them with -Wno-unused-... if self.spec.version < Version("2022.1.0"): - flags_list.append("-Wno-unused-command-line-argument") + llvm_flags.append("-Wno-unused-command-line-argument") - def write_cfg(cmp_list, flags_list): - flags = " ".join(flags_list) - for cmp in cmp_list: - cfg_file = self.component_prefix.linux.bin.join(cmp + ".cfg") - with open(cfg_file, "w") as f: - f.write(flags) - set_install_permissions(cfg_file) - - # Make sure that icc gets the right GCC C++ support - write_cfg( - [ - join_path("intel64", "icc"), - ], - flags_list + ["-gcc-name={}".format(self.compiler.cc)], + self.write_config_file( + common_flags + llvm_flags, self.component_prefix.linux.bin, ["icx", "icpx", "ifx"] ) - write_cfg( - [ - join_path("intel64", "icpc"), - ], - flags_list + ["-gxx-name={}".format(self.compiler.cxx)], - ) - # Make sure that underlying clang gets the right GCC toolchain by default - write_cfg( - ["icx", "icpx", "ifx"], - flags_list + ["--gcc-toolchain={}".format(self.compiler.prefix)], + self.write_config_file( + common_flags + classic_flags, + self.component_prefix.linux.bin.intel64, + ["icc", "icpc", "ifort"], ) def _ld_library_path(self): From 3ec73046995d9504d6e135f564f1370cfe31ba34 Mon Sep 17 00:00:00 2001 From: Tamara Dahlgren <35777542+tldahlgren@users.noreply.github.com> Date: Tue, 18 Oct 2022 15:51:38 -0700 Subject: [PATCH 104/442] spack checksum: warn if version is deprecated (#32438) Co-authored-by: Massimiliano Culpo --- lib/spack/docs/conf.py | 2 ++ lib/spack/spack/cmd/checksum.py | 7 +++++-- lib/spack/spack/package_base.py | 17 +++++++++++++++++ lib/spack/spack/test/cmd/checksum.py | 10 ++++++++++ lib/spack/spack/test/packages.py | 8 ++++++++ 5 files changed, 42 insertions(+), 2 deletions(-) diff --git a/lib/spack/docs/conf.py b/lib/spack/docs/conf.py index 30123635eb7..542a3d90246 100644 --- a/lib/spack/docs/conf.py +++ b/lib/spack/docs/conf.py @@ -206,6 +206,8 @@ def setup(sphinx): # Spack classes that are private and we don't want to expose ("py:class", "spack.provider_index._IndexBase"), ("py:class", "spack.repo._PrependFileLoader"), + # Spack classes that intersphinx is unable to resolve + ("py:class", "spack.version.VersionBase"), ] # The reST default role (used for this markup: `text`) to use for all documents. diff --git a/lib/spack/spack/cmd/checksum.py b/lib/spack/spack/cmd/checksum.py index 3cfdcabff95..0483f4dd91f 100644 --- a/lib/spack/spack/cmd/checksum.py +++ b/lib/spack/spack/cmd/checksum.py @@ -15,7 +15,7 @@ import spack.spec import spack.stage import spack.util.crypto -from spack.package_base import preferred_version +from spack.package_base import deprecated_version, preferred_version from spack.util.naming import valid_fully_qualified_module_name from spack.version import VersionBase, ver @@ -81,6 +81,9 @@ def checksum(parser, args): if versions: remote_versions = None for version in versions: + if deprecated_version(pkg, version): + tty.warn("Version {0} is deprecated".format(version)) + version = ver(version) if not isinstance(version, VersionBase): tty.die( @@ -101,7 +104,7 @@ def checksum(parser, args): url_dict = pkg.fetch_remote_versions() if not url_dict: - tty.die("Could not find any versions for {0}".format(pkg.name)) + tty.die("Could not find any remote versions for {0}".format(pkg.name)) version_lines = spack.stage.get_checksums_for_versions( url_dict, diff --git a/lib/spack/spack/package_base.py b/lib/spack/spack/package_base.py index f4573e6f195..f05c0ff8689 100644 --- a/lib/spack/spack/package_base.py +++ b/lib/spack/spack/package_base.py @@ -100,6 +100,23 @@ is_windows = sys.platform == "win32" +def deprecated_version(pkg, version): + """Return True if the version is deprecated, False otherwise. + + Arguments: + pkg (Package): The package whose version is to be checked. + version (str or spack.version.VersionBase): The version being checked + """ + if not isinstance(version, VersionBase): + version = Version(version) + + for k, v in pkg.versions.items(): + if version == k and v.get("deprecated", False): + return True + + return False + + def preferred_version(pkg): """ Returns a sorted list of the preferred versions of the package. diff --git a/lib/spack/spack/test/cmd/checksum.py b/lib/spack/spack/test/cmd/checksum.py index a84b0eb8b75..84696bb6f8d 100644 --- a/lib/spack/spack/test/cmd/checksum.py +++ b/lib/spack/spack/test/cmd/checksum.py @@ -68,3 +68,13 @@ def test_checksum_versions(mock_packages, mock_fetch, mock_stage): output = spack_checksum("preferred-test", versions[0]) assert "Found 1 version" in output assert "version(" in output + + +def test_checksum_missing_version(mock_packages, mock_fetch, mock_stage): + output = spack_checksum("preferred-test", "99.99.99", fail_on_error=False) + assert "Could not find any remote versions" in output + + +def test_checksum_deprecated_version(mock_packages, mock_fetch, mock_stage): + output = spack_checksum("deprecated-versions", "1.1.0", fail_on_error=False) + assert "Version 1.1.0 is deprecated" in output diff --git a/lib/spack/spack/test/packages.py b/lib/spack/spack/test/packages.py index 07161ad83fc..3a22abcd7c2 100644 --- a/lib/spack/spack/test/packages.py +++ b/lib/spack/spack/test/packages.py @@ -321,3 +321,11 @@ def test_has_test_method_fails(capsys): captured = capsys.readouterr()[1] assert "is not a class" in captured + + +def test_package_deprecated_version(mock_packages, mock_fetch, mock_stage): + spec = Spec("deprecated-versions") + pkg_cls = spack.repo.path.get_pkg_class(spec.name) + + assert spack.package_base.deprecated_version(pkg_cls, "1.1.0") + assert not spack.package_base.deprecated_version(pkg_cls, "1.0.0") From a423dc646ac932d3d5bfe79c53a1e934bf36227c Mon Sep 17 00:00:00 2001 From: Jonathon Anderson <17242663+blue42u@users.noreply.github.com> Date: Wed, 19 Oct 2022 10:36:27 -0500 Subject: [PATCH 105/442] Update the binary index before attempting direct fetches (#32137) "spack install" will not update the binary index if given a concrete spec, which causes it to fall back to direct fetches when a simple index update would have helped. For S3 buckets in particular, this significantly and needlessly slows down the install process. This commit alters the logic so that the binary index is updated whenever a by-hash lookup fails. The lookup is attempted again with the updated index before falling back to direct fetches. To avoid updating too frequently (potentially once for each spec being installed), BinaryCacheIndex.update now includes a "cooldown" option, and when this option is enabled it will not update more than once in a cooldown window (set in config.yaml). Co-authored-by: Tamara Dahlgren <35777542+tldahlgren@users.noreply.github.com> --- etc/spack/defaults/config.yaml | 4 ++ lib/spack/spack/binary_distribution.py | 53 ++++++++++++++++++-------- lib/spack/spack/schema/config.py | 1 + lib/spack/spack/test/bindist.py | 9 +++-- 4 files changed, 48 insertions(+), 19 deletions(-) diff --git a/etc/spack/defaults/config.yaml b/etc/spack/defaults/config.yaml index d3e7e4ce686..e72608248f5 100644 --- a/etc/spack/defaults/config.yaml +++ b/etc/spack/defaults/config.yaml @@ -201,3 +201,7 @@ config: # building and installing packages. This gives information about Spack's # current progress as well as the current and total number of packages. terminal_title: false + + # Number of seconds a buildcache's index.json is cached locally before probing + # for updates, within a single Spack invocation. Defaults to 10 minutes. + binary_index_ttl: 600 \ No newline at end of file diff --git a/lib/spack/spack/binary_distribution.py b/lib/spack/spack/binary_distribution.py index c329287de8f..cfd7d0ec1be 100644 --- a/lib/spack/spack/binary_distribution.py +++ b/lib/spack/spack/binary_distribution.py @@ -12,6 +12,7 @@ import sys import tarfile import tempfile +import time import traceback import warnings from contextlib import closing @@ -105,6 +106,9 @@ def __init__(self, cache_root): # cache (_mirrors_for_spec) self._specs_already_associated = set() + # mapping from mirror urls to the time.time() of the last index fetch. + self._last_fetch_times = {} + # _mirrors_for_spec is a dictionary mapping DAG hashes to lists of # entries indicating mirrors where that concrete spec can be found. # Each entry is a dictionary consisting of: @@ -137,6 +141,7 @@ def clear(self): self._index_file_cache = None self._local_index_cache = None self._specs_already_associated = set() + self._last_fetch_times = {} self._mirrors_for_spec = {} def _write_local_index_cache(self): @@ -242,7 +247,6 @@ def find_built_spec(self, spec, mirrors_to_check=None): } ] """ - self.regenerate_spec_cache() return self.find_by_hash(spec.dag_hash(), mirrors_to_check=mirrors_to_check) def find_by_hash(self, find_hash, mirrors_to_check=None): @@ -253,6 +257,9 @@ def find_by_hash(self, find_hash, mirrors_to_check=None): mirrors_to_check: Optional mapping containing mirrors to check. If None, just assumes all configured mirrors. """ + if find_hash not in self._mirrors_for_spec: + # Not found in the cached index, pull the latest from the server. + self.update(with_cooldown=True) if find_hash not in self._mirrors_for_spec: return None results = self._mirrors_for_spec[find_hash] @@ -283,7 +290,7 @@ def update_spec(self, spec, found_list): "spec": new_entry["spec"], } - def update(self): + def update(self, with_cooldown=False): """Make sure local cache of buildcache index files is up to date. If the same mirrors are configured as the last time this was called and none of the remote buildcache indices have changed, calling this @@ -325,24 +332,37 @@ def update(self): fetch_errors = [] all_methods_failed = True + ttl = spack.config.get("config:binary_index_ttl", 600) + now = time.time() for cached_mirror_url in self._local_index_cache: cache_entry = self._local_index_cache[cached_mirror_url] cached_index_hash = cache_entry["index_hash"] cached_index_path = cache_entry["index_path"] if cached_mirror_url in configured_mirror_urls: - # May need to fetch the index and update the local caches - try: - needs_regen = self._fetch_and_cache_index( - cached_mirror_url, expect_hash=cached_index_hash - ) + # Only do a fetch if the last fetch was longer than TTL ago + if ( + with_cooldown + and ttl > 0 + and cached_mirror_url in self._last_fetch_times + and now - self._last_fetch_times[cached_mirror_url] < ttl + ): + # The fetch worked last time, so don't error all_methods_failed = False - except FetchCacheError as fetch_error: - needs_regen = False - fetch_errors.extend(fetch_error.errors) - # The need to regenerate implies a need to clear as well. - spec_cache_clear_needed |= needs_regen - spec_cache_regenerate_needed |= needs_regen + else: + # May need to fetch the index and update the local caches + try: + needs_regen = self._fetch_and_cache_index( + cached_mirror_url, expect_hash=cached_index_hash + ) + self._last_fetch_times[cached_mirror_url] = now + all_methods_failed = False + except FetchCacheError as fetch_error: + needs_regen = False + fetch_errors.extend(fetch_error.errors) + # The need to regenerate implies a need to clear as well. + spec_cache_clear_needed |= needs_regen + spec_cache_regenerate_needed |= needs_regen else: # No longer have this mirror, cached index should be removed items_to_remove.append( @@ -351,6 +371,8 @@ def update(self): "cache_key": os.path.join(self._index_cache_root, cached_index_path), } ) + if cached_mirror_url in self._last_fetch_times: + del self._last_fetch_times[cached_mirror_url] spec_cache_clear_needed = True spec_cache_regenerate_needed = True @@ -369,6 +391,7 @@ def update(self): # Need to fetch the index and update the local caches try: needs_regen = self._fetch_and_cache_index(mirror_url) + self._last_fetch_times[mirror_url] = now all_methods_failed = False except FetchCacheError as fetch_error: fetch_errors.extend(fetch_error.errors) @@ -1878,8 +1901,8 @@ def get_mirrors_for_spec(spec=None, mirrors_to_check=None, index_only=False): results = binary_index.find_built_spec(spec, mirrors_to_check=mirrors_to_check) - # Maybe we just didn't have the latest information from the mirror, so - # try to fetch directly, unless we are only considering the indices. + # The index may be out-of-date. If we aren't only considering indices, try + # to fetch directly since we know where the file should be. if not results and not index_only: results = try_direct_fetch(spec, mirrors=mirrors_to_check) # We found a spec by the direct fetch approach, we might as well diff --git a/lib/spack/spack/schema/config.py b/lib/spack/spack/schema/config.py index 4ed6e7fc2d2..c82990da5cc 100644 --- a/lib/spack/spack/schema/config.py +++ b/lib/spack/spack/schema/config.py @@ -73,6 +73,7 @@ "binary_index_root": {"type": "string"}, "url_fetch_method": {"type": "string", "enum": ["urllib", "curl"]}, "additional_external_search_paths": {"type": "array", "items": {"type": "string"}}, + "binary_index_ttl": {"type": "integer", "minimum": 0}, }, "deprecatedProperties": { "properties": ["module_roots"], diff --git a/lib/spack/spack/test/bindist.py b/lib/spack/spack/test/bindist.py index 68ea2cb7340..7e9066ccbf8 100644 --- a/lib/spack/spack/test/bindist.py +++ b/lib/spack/spack/test/bindist.py @@ -453,10 +453,11 @@ def test_generate_index_missing(monkeypatch, tmpdir, mutable_config): # Update index buildcache_cmd("update-index", "-d", mirror_dir.strpath) - # Check dependency not in buildcache - cache_list = buildcache_cmd("list", "--allarch") - assert "libdwarf" in cache_list - assert "libelf" not in cache_list + with spack.config.override("config:binary_index_ttl", 0): + # Check dependency not in buildcache + cache_list = buildcache_cmd("list", "--allarch") + assert "libdwarf" in cache_list + assert "libelf" not in cache_list def test_generate_indices_key_error(monkeypatch, capfd): From 25cbb34579bacc704c7f17f691cb36bf8f08b17b Mon Sep 17 00:00:00 2001 From: Stephen Sachs Date: Wed, 19 Oct 2022 17:37:07 +0200 Subject: [PATCH 106/442] Relocate "run" type dependencies too (#33191) When downloading from binary cache not only replace RPATHs to dependencies, but also text references to dependencies. Example: `autoconf@2.69` contains a text reference to the executable of its dependency `perl`: ``` $ grep perl-5 /shared/spack/opt/spack/linux-amzn2-x86_64_v3/gcc-7.3.1/autoconf-2.69-q3lo/bin/autoreconf eval 'case $# in 0) exec /shared/spack/opt/spack/linux-amzn2-x86_64_v3/gcc-7.3.1/perl-5.34.1-yphg/bin/perl -S "$0";; *) exec /shared/spack/opt/spack/linux-amzn2-x86_64_v3/gcc-7.3.1/perl-5.34.1-yphg/bin/perl -S "$0" "$@";; esac' ``` These references need to be replace or any package using `autoreconf` will fail as it cannot find the installed `perl`. Co-authored-by: Stephen Sachs --- lib/spack/spack/binary_distribution.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/spack/spack/binary_distribution.py b/lib/spack/spack/binary_distribution.py index cfd7d0ec1be..b712e82cc02 100644 --- a/lib/spack/spack/binary_distribution.py +++ b/lib/spack/spack/binary_distribution.py @@ -721,7 +721,7 @@ def write_buildinfo_file(spec, workdir, rel=False): prefix_to_hash = dict() prefix_to_hash[str(spec.package.prefix)] = spec.dag_hash() deps = spack.build_environment.get_rpath_deps(spec.package) - for d in deps: + for d in deps + spec.dependencies(deptype="run"): prefix_to_hash[str(d.prefix)] = d.dag_hash() # Create buildinfo data and write it to disk @@ -1474,7 +1474,7 @@ def relocate_package(spec, allow_root): hash_to_prefix = dict() hash_to_prefix[spec.format("{hash}")] = str(spec.package.prefix) new_deps = spack.build_environment.get_rpath_deps(spec.package) - for d in new_deps: + for d in new_deps + spec.dependencies(deptype="run"): hash_to_prefix[d.format("{hash}")] = str(d.prefix) # Spurious replacements (e.g. sbang) will cause issues with binaries # For example, the new sbang can be longer than the old one. From 7ad7fde09cc62a5edfc44dea5fbc5324d07d4c37 Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Wed, 19 Oct 2022 19:25:20 +0200 Subject: [PATCH 107/442] Add a command to bootstrap Spack right now (#33407) --- lib/spack/spack/cmd/bootstrap.py | 12 ++++++++++++ share/spack/spack-completion.bash | 6 +++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/spack/spack/cmd/bootstrap.py b/lib/spack/spack/cmd/bootstrap.py index 9a782b64eab..fc1ab8e92df 100644 --- a/lib/spack/spack/cmd/bootstrap.py +++ b/lib/spack/spack/cmd/bootstrap.py @@ -5,6 +5,7 @@ from __future__ import print_function import os.path +import platform import shutil import tempfile @@ -73,6 +74,8 @@ def _add_scope_option(parser): def setup_parser(subparser): sp = subparser.add_subparsers(dest="subcommand") + sp.add_parser("now", help="Spack ready, right now!") + status = sp.add_parser("status", help="get the status of Spack") status.add_argument( "--optional", @@ -404,6 +407,14 @@ def write_metadata(subdir, metadata): print(instructions) +def _now(args): + with spack.bootstrap.ensure_bootstrap_configuration(): + spack.bootstrap.ensure_clingo_importable_or_raise() + spack.bootstrap.ensure_gpg_in_path_or_raise() + if platform.system().lower() == "linux": + spack.bootstrap.ensure_patchelf_in_path_or_raise() + + def bootstrap(parser, args): callbacks = { "status": _status, @@ -417,5 +428,6 @@ def bootstrap(parser, args): "add": _add, "remove": _remove, "mirror": _mirror, + "now": _now, } callbacks[args.subcommand](args) diff --git a/share/spack/spack-completion.bash b/share/spack/spack-completion.bash index 1543cffd92f..8b12116fe9e 100755 --- a/share/spack/spack-completion.bash +++ b/share/spack/spack-completion.bash @@ -412,10 +412,14 @@ _spack_bootstrap() { then SPACK_COMPREPLY="-h --help" else - SPACK_COMPREPLY="status enable disable reset root list trust untrust add remove mirror" + SPACK_COMPREPLY="now status enable disable reset root list trust untrust add remove mirror" fi } +_spack_bootstrap_now() { + SPACK_COMPREPLY="-h --help" +} + _spack_bootstrap_status() { SPACK_COMPREPLY="-h --help --optional --dev" } From 9f89926980b82cde59d3a82aed214019c5b61db9 Mon Sep 17 00:00:00 2001 From: eugeneswalker <38933153+eugeneswalker@users.noreply.github.com> Date: Wed, 19 Oct 2022 10:41:52 -0700 Subject: [PATCH 108/442] axom: python only reliably available when +python, +devtools (#33414) --- var/spack/repos/builtin/packages/axom/package.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/axom/package.py b/var/spack/repos/builtin/packages/axom/package.py index d1cb7f1069d..672f4ff763a 100644 --- a/var/spack/repos/builtin/packages/axom/package.py +++ b/var/spack/repos/builtin/packages/axom/package.py @@ -449,7 +449,7 @@ def initconfig_package_entries(self): entries.append("# ClangFormat disabled due to disabled devtools\n") entries.append(cmake_cache_option("ENABLE_CLANGFORMAT", False)) - if spec.satisfies("^python") or "+devtools" in spec: + if "+python" in spec or "+devtools" in spec: python_path = os.path.realpath(spec["python"].command.path) for key in path_replacements: python_path = python_path.replace(key, path_replacements[key]) From 5cce66be754be4328eee99a8d46b4b75699e9413 Mon Sep 17 00:00:00 2001 From: Luke Diorio-Toth Date: Wed, 19 Oct 2022 13:41:39 -0500 Subject: [PATCH 109/442] pilercr: new package (#33251) * new package * fixed style * actually building now --- .../repos/builtin/packages/pilercr/package.py | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 var/spack/repos/builtin/packages/pilercr/package.py diff --git a/var/spack/repos/builtin/packages/pilercr/package.py b/var/spack/repos/builtin/packages/pilercr/package.py new file mode 100644 index 00000000000..a18c4c70f7b --- /dev/null +++ b/var/spack/repos/builtin/packages/pilercr/package.py @@ -0,0 +1,28 @@ +# 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 Pilercr(MakefilePackage): + """Identification and analysis of CRISPR repeats.""" + + homepage = "http://www.drive5.com/pilercr/" + url = "http://www.drive5.com/pilercr/pilercr1.06.tar.gz" + + version("1.06", sha256="50175f7aa171674cda5ba255631f340f9cc7f80e8cc25135a4cb857147d91068") + + @property + def build_targets(self): + targets = [] + targets.append("GPP = {0}".format(spack_cxx)) + targets.append("CFLAGS = -O3 -DNDEBUG=1") + targets.append("LDLIBS = -lm") + return targets + + def install(self, spec, prefix): + mkdirp(prefix.bin) + install("pilercr", prefix.bin) From 6b45e2fef11e15d97a4d931d2d74204704ef3ff6 Mon Sep 17 00:00:00 2001 From: eugeneswalker <38933153+eugeneswalker@users.noreply.github.com> Date: Wed, 19 Oct 2022 11:43:51 -0700 Subject: [PATCH 110/442] raja +rocm: use hipcc as CMAKE_CXX_COMPILER (#33375) --- var/spack/repos/builtin/packages/raja/package.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/var/spack/repos/builtin/packages/raja/package.py b/var/spack/repos/builtin/packages/raja/package.py index b9e1f6fe8fa..d185eb31fc8 100644 --- a/var/spack/repos/builtin/packages/raja/package.py +++ b/var/spack/repos/builtin/packages/raja/package.py @@ -104,6 +104,13 @@ def cache_name(self): self.spec.compiler.version, ) + def initconfig_compiler_entries(self): + spec = self.spec + entries = super(Raja, self).initconfig_compiler_entries() + if "+rocm" in spec: + entries.insert(0, cmake_cache_path("CMAKE_CXX_COMPILER", spec["hip"].hipcc)) + return entries + def initconfig_hardware_entries(self): spec = self.spec entries = super(Raja, self).initconfig_hardware_entries() From fa30f74e0c120a642ed3d5e0786b934ff0b8a7fc Mon Sep 17 00:00:00 2001 From: eugeneswalker <38933153+eugeneswalker@users.noreply.github.com> Date: Wed, 19 Oct 2022 11:53:58 -0700 Subject: [PATCH 111/442] umpire +rocm: use hipcc as CMAKE_CXX_COMPILER (#33377) --- var/spack/repos/builtin/packages/umpire/package.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/var/spack/repos/builtin/packages/umpire/package.py b/var/spack/repos/builtin/packages/umpire/package.py index 3916b7a2343..d22f49a05d3 100644 --- a/var/spack/repos/builtin/packages/umpire/package.py +++ b/var/spack/repos/builtin/packages/umpire/package.py @@ -148,6 +148,9 @@ def initconfig_compiler_entries(self): spec = self.spec entries = super(Umpire, self).initconfig_compiler_entries() + if "+rocm" in spec: + entries.insert(0, cmake_cache_path("CMAKE_CXX_COMPILER", spec["hip"].hipcc)) + option_prefix = "UMPIRE_" if spec.satisfies("@2022.03.0:") else "" if "+fortran" in spec and self.compiler.fc is not None: From 1f0751defe360bd9e54d15dc42b9ef94bc29a491 Mon Sep 17 00:00:00 2001 From: eugeneswalker <38933153+eugeneswalker@users.noreply.github.com> Date: Wed, 19 Oct 2022 12:14:46 -0700 Subject: [PATCH 112/442] patch std::filesystem check as done in llnl/umpire pr#784 (#33250) --- .../repos/builtin/packages/umpire/package.py | 1 + .../umpire/std-filesystem-pr784.patch | 33 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 var/spack/repos/builtin/packages/umpire/std-filesystem-pr784.patch diff --git a/var/spack/repos/builtin/packages/umpire/package.py b/var/spack/repos/builtin/packages/umpire/package.py index d22f49a05d3..f24fb8d6605 100644 --- a/var/spack/repos/builtin/packages/umpire/package.py +++ b/var/spack/repos/builtin/packages/umpire/package.py @@ -54,6 +54,7 @@ class Umpire(CachedCMakePackage, CudaPackage, ROCmPackage): version("0.1.4", tag="v0.1.4", submodules=True) version("0.1.3", tag="v0.1.3", submodules=True) + patch("std-filesystem-pr784.patch", when="@2022.03.1 +rocm ^blt@0.5.2:") patch("camp_target_umpire_3.0.0.patch", when="@3.0.0") patch("cmake_version_check.patch", when="@4.1") patch("missing_header_for_numeric_limits.patch", when="@4.1:5.0.1") diff --git a/var/spack/repos/builtin/packages/umpire/std-filesystem-pr784.patch b/var/spack/repos/builtin/packages/umpire/std-filesystem-pr784.patch new file mode 100644 index 00000000000..677144214d6 --- /dev/null +++ b/var/spack/repos/builtin/packages/umpire/std-filesystem-pr784.patch @@ -0,0 +1,33 @@ +diff -ruN spack-src/cmake/SetupCompilerFlags.cmake spack-src-patched/cmake/SetupCompilerFlags.cmake +--- spack-src/cmake/SetupCompilerFlags.cmake 2022-10-12 08:05:03.538390165 -0700 ++++ spack-src-patched/cmake/SetupCompilerFlags.cmake 2022-10-12 09:47:56.317645003 -0700 +@@ -11,20 +11,20 @@ + + message(STATUS "Checking for std::filesystem") + +-include(CheckCXXSourceCompiles) +-check_cxx_source_compiles( +- "#include +- #include +- +- int main(int, char**) +- { ++blt_check_code_compiles(CODE_COMPILES UMPIRE_ENABLE_FILESYSTEM ++ SOURCE_STRING ++[=[ ++#include ++#include + ++int main(int, char**) ++{ + auto path = std::filesystem::path(\".\"); + (void)(path); + + return 0; +- }" +- UMPIRE_ENABLE_FILESYSTEM) ++} ++]=]) + + if (UMPIRE_ENABLE_FILESYSTEM) + message(STATUS "std::filesystem found") From ef872cc64bcc78ffcc091aa5bb2f1346792d9568 Mon Sep 17 00:00:00 2001 From: Sergey Kosukhin Date: Wed, 19 Oct 2022 22:04:32 +0200 Subject: [PATCH 113/442] mpich: enable building when @3.4~cuda (#33325) --- var/spack/repos/builtin/packages/mpich/package.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/mpich/package.py b/var/spack/repos/builtin/packages/mpich/package.py index a09b779e0ba..701ba958562 100644 --- a/var/spack/repos/builtin/packages/mpich/package.py +++ b/var/spack/repos/builtin/packages/mpich/package.py @@ -508,7 +508,7 @@ def configure_args(self): if "+cuda" in spec: config_args.append("--with-cuda={0}".format(spec["cuda"].prefix)) - elif spec.satisfies("@:3.3,3.4.4:"): + elif not spec.satisfies("@3.4:3.4.3"): # Versions from 3.4 to 3.4.3 cannot handle --without-cuda # (see https://github.com/pmodels/mpich/pull/5060): config_args.append("--without-cuda") From 4b0832d3bca5deabc51b0727b554d6db5edcd4a9 Mon Sep 17 00:00:00 2001 From: "Adam J. Stewart" Date: Wed, 19 Oct 2022 15:18:00 -0500 Subject: [PATCH 114/442] py-pandas: add v1.5.1 (#33412) --- var/spack/repos/builtin/packages/py-pandas/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/py-pandas/package.py b/var/spack/repos/builtin/packages/py-pandas/package.py index cb86bd502cd..ebbd69b7bb6 100644 --- a/var/spack/repos/builtin/packages/py-pandas/package.py +++ b/var/spack/repos/builtin/packages/py-pandas/package.py @@ -17,6 +17,7 @@ class PyPandas(PythonPackage): maintainers = ["adamjstewart"] + version("1.5.1", sha256="249cec5f2a5b22096440bd85c33106b6102e0672204abd2d5c014106459804ee") version("1.5.0", sha256="3ee61b881d2f64dd90c356eb4a4a4de75376586cd3c9341c6c0fcaae18d52977") version("1.4.4", sha256="ab6c0d738617b675183e5f28db32b5148b694ad9bba0a40c3ea26d96b431db67") version("1.4.3", sha256="2ff7788468e75917574f080cd4681b27e1a7bf36461fe968b49a87b5a54d007c") From ae7999d7a1957465bd5848b263352ebf49ef8015 Mon Sep 17 00:00:00 2001 From: Jon Rood Date: Wed, 19 Oct 2022 14:33:01 -0600 Subject: [PATCH 115/442] Simplify TIOGA package (#33396) * Update TIOGA package. * Add comment. * Remove cuda variant and MPI_ROOT. * Style. --- .../repos/builtin/packages/tioga/package.py | 31 +++---------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/var/spack/repos/builtin/packages/tioga/package.py b/var/spack/repos/builtin/packages/tioga/package.py index 1374ad76fb0..2716d13dfaa 100644 --- a/var/spack/repos/builtin/packages/tioga/package.py +++ b/var/spack/repos/builtin/packages/tioga/package.py @@ -7,15 +7,17 @@ from spack.package import * -class Tioga(CMakePackage, CudaPackage): +class Tioga(CMakePackage): """Topology Independent Overset Grid Assembly (TIOGA)""" homepage = "https://github.com/jsitaraman/tioga" git = "https://github.com/jsitaraman/tioga.git" - maintainers = ["jsitaraman", "sayerhs"] + maintainers = ["jrood-nrel"] - version("develop", branch="exawind") + # The original TIOGA repo has possibly been abandoned, + # so work on TIOGA has continued in the Exawind project + version("develop", git="https://github.com/Exawind/tioga.git", branch="exawind") version("master", branch="master") variant("shared", default=sys.platform != "darwin", description="Build shared libraries") @@ -23,39 +25,16 @@ class Tioga(CMakePackage, CudaPackage): variant("nodegid", default=True, description="Enable support for global Node IDs") variant("timers", default=False, description="Enable timers") variant("stats", default=False, description="Enable output of holecut stats") - variant( - "cxxstd", default="11", values=("11", "14"), multi=False, description="C++ standard to use" - ) depends_on("mpi") - depends_on("cuda@9.0.0:", when="+cuda") - - # Tioga has the fortran module file problem with parallel builds - parallel = False def cmake_args(self): - spec = self.spec - args = [ self.define_from_variant("BUILD_SHARED_LIBS", "shared"), self.define_from_variant("CMAKE_POSITION_INDEPENDENT_CODE", "pic"), - self.define_from_variant("CMAKE_CXX_STANDARD", "cxxstd"), self.define_from_variant("TIOGA_HAS_NODEGID", "nodegid"), self.define_from_variant("TIOGA_ENABLE_TIMERS", "timers"), self.define_from_variant("TIOGA_OUTPUT_STATS", "stats"), - self.define_from_variant("TIOGA_ENABLE_CUDA", "cuda"), ] - if "+cuda" in self.spec: - args.append(self.define("CMAKE_CUDA_SEPARABLE_COMPILATION", True)) - - # Currently TIOGA only supports one device arch during specialization - cuda_arch = self.spec.variants["cuda_arch"].value - if cuda_arch: - arch_sorted = list(sorted(cuda_arch, reverse=True)) - args.append(self.define("TIOGA_CUDA_SM", arch_sorted[0])) - - if "darwin" in spec.architecture: - args.append(self.define("CMAKE_MACOSX_RPATH", True)) - return args From e1344067fdfa30f8f1b377bf3e6391291f7bf30f Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Wed, 19 Oct 2022 22:57:06 +0200 Subject: [PATCH 116/442] depfile: buildcache support (#33315) When installing some/all specs from a buildcache, build edges are pruned from those specs. This can result in a much smaller effective DAG. Until now, `spack env depfile` would always generate a full DAG. Ths PR adds the `spack env depfile --use-buildcache` flag that was introduced for `spack install` before. This way, not only can we drop build edges, but also we can automatically set the right buildcache related flags on the specific specs that are gonna get installed. This way we get parallel installs of binary deps without redundancy, which is useful for Gitlab CI. --- lib/spack/spack/cmd/env.py | 144 ++++++++++++++++++++----- lib/spack/spack/test/cmd/env.py | 97 +++++++++++++++-- share/spack/spack-completion.bash | 7 +- share/spack/templates/depfile/Makefile | 18 ++-- 4 files changed, 219 insertions(+), 47 deletions(-) diff --git a/lib/spack/spack/cmd/env.py b/lib/spack/spack/cmd/env.py index e421e300e1e..02d279b0546 100644 --- a/lib/spack/spack/cmd/env.py +++ b/lib/spack/spack/cmd/env.py @@ -3,6 +3,7 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import argparse import os import shutil import sys @@ -15,6 +16,8 @@ from llnl.util.tty.colify import colify from llnl.util.tty.color import colorize +import spack.cmd +import spack.cmd.common import spack.cmd.common.arguments import spack.cmd.common.arguments as arguments import spack.cmd.install @@ -599,6 +602,15 @@ def env_depfile_setup_parser(subparser): dest="jobserver", help="disable POSIX jobserver support.", ) + subparser.add_argument( + "--use-buildcache", + dest="use_buildcache", + type=arguments.use_buildcache, + default="package:auto,dependencies:auto", + metavar="[{auto,only,never},][package:{auto,only,never},][dependencies:{auto,only,never}]", + help="When using `only`, redundant build dependencies are pruned from the DAG. " + "This flag is passed on to the generated spack install commands.", + ) subparser.add_argument( "-o", "--output", @@ -613,6 +625,96 @@ def env_depfile_setup_parser(subparser): choices=("make",), help="specify the depfile type. Currently only make is supported.", ) + subparser.add_argument( + metavar="specs", + dest="specs", + nargs=argparse.REMAINDER, + default=None, + help="generate a depfile only for matching specs in the environment", + ) + + +class SpecNode(object): + def __init__(self, spec, depth): + self.spec = spec + self.depth = depth + + def key(self): + return self.spec.dag_hash() + + +class UniqueNodesQueue(object): + def __init__(self, init=[]): + self.seen = set() + self.queue = [] + for item in init: + self.push(item) + + def push(self, item): + key = item.key() + if key in self.seen: + return + self.queue.append(item) + self.seen.add(key) + + def empty(self): + return len(self.queue) == 0 + + def pop(self): + return self.queue.pop() + + +def _deptypes(use_buildcache): + """What edges should we follow for a given node? If it's a cache-only + node, then we can drop build type deps.""" + return ("link", "run") if use_buildcache == "only" else ("build", "link", "run") + + +class MakeTargetVisitor(object): + """This visitor produces an adjacency list of a (reduced) DAG, which + is used to generate Makefile targets with their prerequisites.""" + + def __init__(self, target, pkg_buildcache, deps_buildcache): + """ + Args: + target: function that maps dag_hash -> make target string + pkg_buildcache (str): "only", "never", "auto": when "only", + redundant build deps of roots are dropped + deps_buildcache (str): same as pkg_buildcache, but for non-root specs. + """ + self.adjacency_list = [] + self.target = target + self.pkg_buildcache = pkg_buildcache + self.deps_buildcache = deps_buildcache + self.deptypes_root = _deptypes(pkg_buildcache) + self.deptypes_deps = _deptypes(deps_buildcache) + + def neighbors(self, node): + """Produce a list of spec to follow from node""" + deptypes = self.deptypes_root if node.depth == 0 else self.deptypes_deps + return node.spec.dependencies(deptype=deptypes) + + def visit(self, node): + dag_hash = node.spec.dag_hash() + spec_str = node.spec.format("{name}{@version}{%compiler}{variants}{arch=architecture}") + buildcache = self.pkg_buildcache if node.depth == 0 else self.deps_buildcache + if buildcache == "only": + build_cache_flag = "--use-buildcache=only" + elif buildcache == "never": + build_cache_flag = "--use-buildcache=never" + else: + build_cache_flag = "" + prereqs = " ".join([self.target(dep.dag_hash()) for dep in self.neighbors(node)]) + self.adjacency_list.append((dag_hash, spec_str, build_cache_flag, prereqs)) + + +def traverse_breadth_first(visitor, specs=[]): + queue = UniqueNodesQueue([SpecNode(s, 0) for s in specs]) + while not queue.empty(): + node = queue.pop() + visitor.visit(node) + for child in visitor.neighbors(node): + queue.push(SpecNode(child, node.depth + 1)) def env_depfile(args): @@ -620,10 +722,6 @@ def env_depfile(args): spack.cmd.require_active_env(cmd_name="env depfile") env = ev.active_environment() - # Maps each hash in the environment to a string of install prereqs - hash_to_prereqs = {} - hash_to_spec = {} - if args.make_target_prefix is None: target_prefix = os.path.join(env.env_subdir_path, "makedeps") else: @@ -645,48 +743,44 @@ def get_install_target(name): def get_install_deps_target(name): return os.path.join(target_prefix, ".install-deps", name) - for _, spec in env.concretized_specs(): - for s in spec.traverse(root=True): - hash_to_spec[s.dag_hash()] = s - hash_to_prereqs[s.dag_hash()] = [ - get_install_target(dep.dag_hash()) for dep in s.dependencies() - ] + # What things do we build when running make? By default, we build the + # root specs. If specific specs are provided as input, we build those. + if args.specs: + abstract_specs = spack.cmd.parse_specs(args.specs) + roots = [env.matching_spec(s) for s in abstract_specs] + else: + roots = [s for _, s in env.concretized_specs()] - root_dags = [s.dag_hash() for _, s in env.concretized_specs()] + # Shallow means we will drop non-direct build deps from the DAG + pkg_buildcache, dep_buildcache = args.use_buildcache + visitor = MakeTargetVisitor(get_install_target, pkg_buildcache, dep_buildcache) + traverse_breadth_first(visitor, roots) # Root specs without deps are the prereqs for the environment target - root_install_targets = [get_install_target(h) for h in root_dags] + root_install_targets = [get_install_target(h.dag_hash()) for h in roots] - # All package install targets, not just roots. - all_install_targets = [get_install_target(h) for h in hash_to_spec.keys()] - all_install_deps_targets = [get_install_deps_target(h) for h, _ in hash_to_prereqs.items()] + # Cleanable targets... + cleanable_targets = [get_install_target(h) for h, _, _, _ in visitor.adjacency_list] + cleanable_targets.extend([get_install_deps_target(h) for h, _, _, _ in visitor.adjacency_list]) buf = six.StringIO() template = spack.tengine.make_environment().get_template(os.path.join("depfile", "Makefile")) - fmt = "{name}{@version}{%compiler}{variants}{arch=architecture}" - hash_with_name = [(h, hash_to_spec[h].format(fmt)) for h in hash_to_prereqs.keys()] - targets_to_prereqs = [ - (get_install_deps_target(h), " ".join(prereqs)) for h, prereqs in hash_to_prereqs.items() - ] - rendered = template.render( { "all_target": get_target("all"), "env_target": get_target("env"), "clean_target": get_target("clean"), - "all_install_targets": " ".join(all_install_targets), - "all_install_deps_targets": " ".join(all_install_deps_targets), + "cleanable_targets": " ".join(cleanable_targets), "root_install_targets": " ".join(root_install_targets), "dirs_target": get_target("dirs"), "environment": env.path, "install_target": get_target(".install"), "install_deps_target": get_target(".install-deps"), "any_hash_target": get_target("%"), - "hash_with_name": hash_with_name, "jobserver_support": "+" if args.jobserver else "", - "targets_to_prereqs": targets_to_prereqs, + "adjacency_list": visitor.adjacency_list, } ) diff --git a/lib/spack/spack/test/cmd/env.py b/lib/spack/spack/test/cmd/env.py index 5cf4b09cae4..6257431ee9c 100644 --- a/lib/spack/spack/test/cmd/env.py +++ b/lib/spack/spack/test/cmd/env.py @@ -3030,29 +3030,106 @@ def test_read_legacy_lockfile_and_reconcretize(mock_stage, mock_fetch, install_m assert current_versions == expected_versions -def test_environment_depfile_makefile(tmpdir, mock_packages): +@pytest.mark.parametrize( + "depfile_flags,expected_installs", + [ + # This installs the full environment + ( + ["--use-buildcache=never"], + [ + "dtbuild1", + "dtbuild2", + "dtbuild3", + "dtlink1", + "dtlink2", + "dtlink3", + "dtlink4", + "dtlink5", + "dtrun1", + "dtrun2", + "dtrun3", + "dttop", + ], + ), + # This prunes build deps at depth > 0 + ( + ["--use-buildcache=package:never,dependencies:only"], + [ + "dtbuild1", + "dtlink1", + "dtlink2", + "dtlink3", + "dtlink4", + "dtlink5", + "dtrun1", + "dtrun2", + "dtrun3", + "dttop", + ], + ), + # This prunes all build deps + ( + ["--use-buildcache=only"], + [ + "dtlink1", + "dtlink3", + "dtlink4", + "dtlink5", + "dtrun1", + "dtrun3", + "dttop", + ], + ), + # Test whether pruning of build deps is correct if we explicitly include one + # that is also a dependency of a root. + ( + ["--use-buildcache=only", "dttop", "dtbuild1"], + [ + "dtbuild1", + "dtlink1", + "dtlink2", + "dtlink3", + "dtlink4", + "dtlink5", + "dtrun1", + "dtrun2", + "dtrun3", + "dttop", + ], + ), + ], +) +def test_environment_depfile_makefile(depfile_flags, expected_installs, tmpdir, mock_packages): env("create", "test") make = Executable("make") makefile = str(tmpdir.join("Makefile")) with ev.read("test"): - add("libdwarf") + add("dttop") concretize() # Disable jobserver so we can do a dry run. with ev.read("test"): env( - "depfile", "-o", makefile, "--make-disable-jobserver", "--make-target-prefix", "prefix" + "depfile", + "-o", + makefile, + "--make-disable-jobserver", + "--make-target-prefix=prefix", + *depfile_flags ) # Do make dry run. - all_out = make("-n", "-f", makefile, output=str) + out = make("-n", "-f", makefile, output=str) - # Check whether `make` installs everything - with ev.read("test") as e: - for _, root in e.concretized_specs(): - for spec in root.traverse(root=True): - tgt = os.path.join("prefix", ".install", spec.dag_hash()) - assert "touch {}".format(tgt) in all_out + # Spack install commands are of the form "spack install ... # ", + # so we just parse the spec again, for simplicity. + specs_that_make_would_install = [ + Spec(line.split("# ")[1]).name for line in out.splitlines() if line.startswith("spack") + ] + + # Check that all specs are there (without duplicates) + assert set(specs_that_make_would_install) == set(expected_installs) + assert len(specs_that_make_would_install) == len(expected_installs) def test_environment_depfile_out(tmpdir, mock_packages): diff --git a/share/spack/spack-completion.bash b/share/spack/spack-completion.bash index 8b12116fe9e..c6d407b4d5a 100755 --- a/share/spack/spack-completion.bash +++ b/share/spack/spack-completion.bash @@ -1022,7 +1022,12 @@ _spack_env_revert() { } _spack_env_depfile() { - SPACK_COMPREPLY="-h --help --make-target-prefix --make-disable-jobserver -o --output -G --generator" + if $list_options + then + SPACK_COMPREPLY="-h --help --make-target-prefix --make-disable-jobserver --use-buildcache -o --output -G --generator" + else + _all_packages + fi } _spack_extensions() { diff --git a/share/spack/templates/depfile/Makefile b/share/spack/templates/depfile/Makefile index a149951d9f2..5078f0016f1 100644 --- a/share/spack/templates/depfile/Makefile +++ b/share/spack/templates/depfile/Makefile @@ -15,23 +15,19 @@ SPACK ?= spack # This is an involved way of expressing that Spack should only install # an individual concrete spec from the environment without deps. {{ install_target }}/%: {{ install_deps_target }}/% | {{ dirs_target }} - $(info Installing $(SPEC)) - {{ jobserver_support }}$(SPACK) -e '{{ environment }}' install $(SPACK_INSTALL_FLAGS) --only-concrete --only=package --no-add /$(notdir $@) - @touch $@ - -# Targets of the form {{ install_deps_target }}/ install dependencies only -{{ install_deps_target }}/%: | {{ dirs_target }} + {{ jobserver_support }}$(SPACK) -e '{{ environment }}' install $(SPACK_BUILDCACHE_FLAG) $(SPACK_INSTALL_FLAGS) --only-concrete --only=package --no-add /$(notdir $@) # $(SPEC) @touch $@ # Set a human-readable SPEC variable for each target that has a hash -{% for (hash, name) in hash_with_name -%} -{{ any_hash_target }}/{{ hash }}: SPEC = {{ name }} +{% for (parent, name, build_cache, _) in adjacency_list -%} +{{ any_hash_target }}/{{ parent }}: SPEC = {{ name }} +{{ any_hash_target }}/{{ parent }}: SPACK_BUILDCACHE_FLAG = {{ build_cache }} {% endfor %} # The Spack DAG expressed in targets: -{% for (target, prereqs) in targets_to_prereqs -%} -{{ target }}: {{prereqs}} +{% for (parent, _, _, prereqs) in adjacency_list -%} +{{ install_deps_target }}/{{ parent }}: {{prereqs}} {% endfor %} {{ clean_target }}: - rm -rf {{ env_target }} {{ all_install_targets }} {{ all_install_deps_targets }} + rm -rf {{ env_target }} {{ cleanable_targets }} From 0934c4d602375d9c22794670737478fe66525518 Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Wed, 19 Oct 2022 15:06:44 -0600 Subject: [PATCH 117/442] singularity-eos: new version 1.6.2 (#33415) --- var/spack/repos/builtin/packages/singularity-eos/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/singularity-eos/package.py b/var/spack/repos/builtin/packages/singularity-eos/package.py index 5475ed565d9..f9666b1abe4 100644 --- a/var/spack/repos/builtin/packages/singularity-eos/package.py +++ b/var/spack/repos/builtin/packages/singularity-eos/package.py @@ -19,6 +19,7 @@ class SingularityEos(CMakePackage, CudaPackage): maintainers = ["rbberger"] version("main", branch="main") + version("1.6.2", sha256="9c85fca679139a40cc9c72fcaeeca78a407cc1ca184734785236042de364b942") version("1.6.1", sha256="c6d92dfecf9689ffe2df615791c039f7e527e9f47799a862e26fa4e3420fe5d7") # build with kokkos, kokkos-kernels for offloading support From 8aac0d09d4272609da66c7504745d06506a64080 Mon Sep 17 00:00:00 2001 From: eugeneswalker <38933153+eugeneswalker@users.noreply.github.com> Date: Wed, 19 Oct 2022 16:05:45 -0700 Subject: [PATCH 118/442] e4s ci: add umpire +rocm (#32504) --- share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml index 0204bf00d32..6465229ba97 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml @@ -228,6 +228,7 @@ spack: +nox +piro +phalanx +rol +rythmos +sacado +stk +shards +shylu ~stokhos +stratimikos +teko +tempus +tpetra +trilinoscouplings +zoltan +zoltan2 +superlu-dist gotype=long_long +rocm amdgpu_target=gfx90a + - umpire +rocm amdgpu_target=gfx90a - upcxx +rocm amdgpu_target=gfx90a - vtk-m ~openmp +rocm amdgpu_target=gfx90a @@ -244,7 +245,6 @@ spack: # ROCm failures #- chai ~benchmarks +rocm amdgpu_target=gfx90a # umpire: Target "blt_hip" INTERFACE_INCLUDE_DIRECTORIES property contains path: "/tmp/root/spack-stage/spack-stage-umpire-2022.03.1-by6rldnpdowaaoqgxkeqejwyx5uxo2sv/spack-src/HIP_CLANG_INCLUDE_PATH-NOTFOUND/.." which is prefixed in the source directory. #- raja ~openmp +rocm amdgpu_target=gfx90a # cmake: Could NOT find ROCPRIM (missing: ROCPRIM_INCLUDE_DIRS) - #- umpire +rocm amdgpu_target=gfx90a # Target "blt_hip" INTERFACE_INCLUDE_DIRECTORIES property contains path: "/tmp/root/spack-stage/spack-stage-umpire-2022.03.1-by6rldnpdowaaoqgxkeqejwyx5uxo2sv/spack-src/HIP_CLANG_INCLUDE_PATH-NOTFOUND/.." which is prefixed in the source directory. mirrors: { "mirror": "s3://spack-binaries/develop/e4s" } From 89cf5004dbf81b4202ea096e7a9dcc009a604be0 Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Thu, 20 Oct 2022 09:46:04 +0200 Subject: [PATCH 119/442] FIX CI after git update (#33429) Add `protocol.file.allow always` to git configuration in CI --- .github/workflows/setup_git.ps1 | 4 ++++ .github/workflows/setup_git.sh | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/.github/workflows/setup_git.ps1 b/.github/workflows/setup_git.ps1 index d68f90a7ae1..0acb9a9f460 100644 --- a/.github/workflows/setup_git.ps1 +++ b/.github/workflows/setup_git.ps1 @@ -6,6 +6,10 @@ git config --global user.email "spack@example.com" git config --global user.name "Test User" git config --global core.longpaths true +# See https://github.com/git/git/security/advisories/GHSA-3wp6-j8xr-qw85 (CVE-2022-39253) +# This is needed to let some fixture in our unit-test suite run +git config --global protocol.file.allow always + if ($(git branch --show-current) -ne "develop") { git branch develop origin/develop diff --git a/.github/workflows/setup_git.sh b/.github/workflows/setup_git.sh index 4eb416720be..ee555ff71a9 100755 --- a/.github/workflows/setup_git.sh +++ b/.github/workflows/setup_git.sh @@ -2,6 +2,10 @@ git config --global user.email "spack@example.com" git config --global user.name "Test User" +# See https://github.com/git/git/security/advisories/GHSA-3wp6-j8xr-qw85 (CVE-2022-39253) +# This is needed to let some fixture in our unit-test suite run +git config --global protocol.file.allow always + # create a local pr base branch if [[ -n $GITHUB_BASE_REF ]]; then git fetch origin "${GITHUB_BASE_REF}:${GITHUB_BASE_REF}" From 70d2556f4bb1e22ca938be5d6fe0d2d42815ad3e Mon Sep 17 00:00:00 2001 From: Luke Diorio-Toth Date: Thu, 20 Oct 2022 08:22:59 -0500 Subject: [PATCH 120/442] py-bakta: new package (#33417) --- .../builtin/packages/py-bakta/package.py | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 var/spack/repos/builtin/packages/py-bakta/package.py diff --git a/var/spack/repos/builtin/packages/py-bakta/package.py b/var/spack/repos/builtin/packages/py-bakta/package.py new file mode 100644 index 00000000000..50e683c86cf --- /dev/null +++ b/var/spack/repos/builtin/packages/py-bakta/package.py @@ -0,0 +1,36 @@ +# 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 PyBakta(PythonPackage): + """Bakta: rapid & standardized annotation + of bacterial genomes, MAGs & plasmids""" + + homepage = "https://github.com/oschwengers/bakta" + pypi = "bakta/bakta-1.5.1.tar.gz" + + maintainers = ["oschwengers"] + + version("1.5.1", sha256="36781612c4eaa99e6e24a00e8ab5b27dadf21c98ae6d16432f3e78c96a4adb5d") + + depends_on("python@3.8:", type=("build", "run")) + depends_on("py-setuptools", type=("build", "run")) + depends_on("py-biopython@1.78:", type=("build", "run")) + depends_on("py-xopen@1.1.0:", type=("build", "run")) + depends_on("py-requests@2.25.1:", type=("build", "run")) + depends_on("py-alive-progress@1.6.2", type=("build", "run")) + depends_on("trnascan-se@2.0.8:", type=("build", "run")) + depends_on("aragorn@1.2.38:", type=("build", "run")) + depends_on("infernal@1.1.4:", type=("build", "run")) + depends_on("pilercr@1.06:", type=("build", "run")) + depends_on("prodigal@2.6.3:", type=("build", "run")) + depends_on("hmmer@3.3.2:", type=("build", "run")) + depends_on("diamond@2.0.14:", type=("build", "run")) + depends_on("blast-plus@2.12.0:", type=("build", "run")) + depends_on("amrfinder@3.10.23:", type=("build", "run")) + depends_on("py-deepsig-biocomp@1.2.5:", type=("build", "run")) From 3e1db75372d4ddbd9a2c0970db0ca84beadf5244 Mon Sep 17 00:00:00 2001 From: eugeneswalker <38933153+eugeneswalker@users.noreply.github.com> Date: Thu, 20 Oct 2022 08:09:35 -0700 Subject: [PATCH 121/442] arpack-ng %cce: add -hnopattern to fflags (#33424) --- var/spack/repos/builtin/packages/arpack-ng/package.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/var/spack/repos/builtin/packages/arpack-ng/package.py b/var/spack/repos/builtin/packages/arpack-ng/package.py index 2a418130337..70b1b4820ce 100644 --- a/var/spack/repos/builtin/packages/arpack-ng/package.py +++ b/var/spack/repos/builtin/packages/arpack-ng/package.py @@ -87,6 +87,11 @@ def flag_handler(self, name, flags): if name == "cflags": if spec.satisfies("%oneapi"): iflags.append("-Wno-error=implicit-function-declaration") + + if name == "fflags": + if self.spec.satisfies("%cce"): + iflags.append("-hnopattern") + return (iflags, None, None) @property From af5d6295d58d1f44c7ce9d6ccc92cf6004e8eae6 Mon Sep 17 00:00:00 2001 From: G-Ragghianti <33492707+G-Ragghianti@users.noreply.github.com> Date: Thu, 20 Oct 2022 17:42:52 +0200 Subject: [PATCH 122/442] Change scalapack to test-only dependency (#33433) --- var/spack/repos/builtin/packages/slate/package.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/var/spack/repos/builtin/packages/slate/package.py b/var/spack/repos/builtin/packages/slate/package.py index 798acc987a5..7e623912b5a 100644 --- a/var/spack/repos/builtin/packages/slate/package.py +++ b/var/spack/repos/builtin/packages/slate/package.py @@ -68,7 +68,7 @@ class Slate(CMakePackage, CudaPackage, ROCmPackage): depends_on("lapackpp@2021.04.00:", when="@2021.05.01:") depends_on("lapackpp@2020.10.02", when="@2020.10.00") depends_on("lapackpp@master", when="@master") - depends_on("scalapack") + depends_on("scalapack", type="test") depends_on("hipify-clang", when="@:2021.05.02 +rocm ^hip@5:") cpp_17_msg = "Requires C++17 compiler support" @@ -92,14 +92,16 @@ def cmake_args(self): backend = "hip" backend_config = "-Dgpu_backend=%s" % backend - return [ + config = [ "-Dbuild_tests=%s" % self.run_tests, "-Duse_openmp=%s" % ("+openmp" in spec), "-DBUILD_SHARED_LIBS=%s" % ("+shared" in spec), backend_config, "-Duse_mpi=%s" % ("+mpi" in spec), - "-DSCALAPACK_LIBRARIES=%s" % spec["scalapack"].libs.joined(";"), ] + if self.run_tests: + config.append("-DSCALAPACK_LIBRARIES=%s" % spec["scalapack"].libs.joined(";")) + return config @run_after("install") def cache_test_sources(self): From 9a1957c881dad228eb875ac0e65e3a085f4acb25 Mon Sep 17 00:00:00 2001 From: Scott Wittenburg Date: Thu, 20 Oct 2022 10:33:18 -0600 Subject: [PATCH 123/442] gitlab: Do not use root_spec['pkg_name'] anymore (#33403) * gitlab: Do not use root_spec['pkg_name'] anymore For a long time it was fine to index a concrete root spec with the name of a dependency in order to access the concrete dependency spec. Since pipelines started using `--use-buildcache dependencies:only,package:never` though, it has exposed a scheduling issue in how pipelines are generated. If a concrete root spec depends on two different hashes of `openssl` for example, indexing that root with just the package name is ambiguous, so we should no longer depend on that approach when scheduling jobs. * env: make sure exactly one spec in env matches hash --- lib/spack/spack/ci.py | 100 +++------------------ lib/spack/spack/cmd/ci.py | 18 ++-- lib/spack/spack/environment/environment.py | 8 ++ lib/spack/spack/test/ci.py | 31 ------- lib/spack/spack/test/cmd/ci.py | 17 +--- 5 files changed, 27 insertions(+), 147 deletions(-) diff --git a/lib/spack/spack/ci.py b/lib/spack/spack/ci.py index 0741485656c..4803ef25a3d 100644 --- a/lib/spack/spack/ci.py +++ b/lib/spack/spack/ci.py @@ -43,7 +43,6 @@ from spack.error import SpackError from spack.reporters.cdash import CDash from spack.reporters.cdash import build_stamp as cdash_build_stamp -from spack.spec import Spec from spack.util.pattern import Bunch JOB_RETRY_CONDITIONS = [ @@ -143,13 +142,6 @@ def _get_spec_string(spec): return spec.format("".join(format_elements)) -def _format_root_spec(spec, main_phase, strip_compiler): - if main_phase is False and strip_compiler is True: - return "{0}@{1} arch={2}".format(spec.name, spec.version, spec.architecture) - else: - return spec.dag_hash() - - def _spec_deps_key(s): return "{0}/{1}".format(s.name, s.dag_hash(7)) @@ -175,8 +167,7 @@ def _get_spec_dependencies( for entry in specs: spec_labels[entry["label"]] = { - "spec": Spec(entry["spec"]), - "rootSpec": entry["root_spec"], + "spec": entry["spec"], "needs_rebuild": entry["needs_rebuild"], } @@ -203,7 +194,7 @@ def stage_spec_jobs(specs, check_index_only=False, mirrors_to_check=None): and stages: spec_labels: A dictionary mapping the spec labels which are made of - (pkg-name/hash-prefix), to objects containing "rootSpec" and "spec" + (pkg-name/hash-prefix), to objects containing "spec" and "needs_rebuild" keys. The root spec is the spec of which this spec is a dependency and the spec is the formatted spec string for this spec. @@ -318,17 +309,14 @@ def _compute_spec_deps(spec_list, check_index_only=False, mirrors_to_check=None) ], "specs": [ { - "root_spec": "readline@7.0%apple-clang@9.1.0 arch=darwin-...", "spec": "readline@7.0%apple-clang@9.1.0 arch=darwin-highs...", "label": "readline/ip6aiun" }, { - "root_spec": "readline@7.0%apple-clang@9.1.0 arch=darwin-...", "spec": "ncurses@6.1%apple-clang@9.1.0 arch=darwin-highsi...", "label": "ncurses/y43rifz" }, { - "root_spec": "readline@7.0%apple-clang@9.1.0 arch=darwin-...", "spec": "pkgconf@1.5.4%apple-clang@9.1.0 arch=darwin-high...", "label": "pkgconf/eg355zb" } @@ -350,8 +338,6 @@ def append_dep(s, d): ) for spec in spec_list: - root_spec = spec - for s in spec.traverse(deptype=all): if s.external: tty.msg("Will not stage external pkg: {0}".format(s)) @@ -363,8 +349,7 @@ def append_dep(s, d): skey = _spec_deps_key(s) spec_labels[skey] = { - "spec": _get_spec_string(s), - "root": root_spec, + "spec": s, "needs_rebuild": not up_to_date_mirrors, } @@ -381,7 +366,6 @@ def append_dep(s, d): { "label": spec_label, "spec": spec_holder["spec"], - "root_spec": spec_holder["root"], "needs_rebuild": spec_holder["needs_rebuild"], } ) @@ -458,10 +442,6 @@ def _find_matching_config(spec, gitlab_ci): return runner_attributes if matched else None -def _pkg_name_from_spec_label(spec_label): - return spec_label[: spec_label.index("/")] - - def _format_job_needs( phase_name, strip_compilers, @@ -854,7 +834,6 @@ def generate_gitlab_ci_yaml( phase_name = phase["name"] strip_compilers = phase["strip-compilers"] - main_phase = _is_main_phase(phase_name) spec_labels, dependencies, stages = staged_phases[phase_name] for stage_jobs in stages: @@ -864,9 +843,7 @@ def generate_gitlab_ci_yaml( for spec_label in stage_jobs: spec_record = spec_labels[spec_label] - root_spec = spec_record["rootSpec"] - pkg_name = _pkg_name_from_spec_label(spec_label) - release_spec = root_spec[pkg_name] + release_spec = spec_record["spec"] release_spec_dag_hash = release_spec.dag_hash() if prune_untouched_packages: @@ -936,7 +913,6 @@ def generate_gitlab_ci_yaml( compiler_action = "INSTALL_MISSING" job_vars = { - "SPACK_ROOT_SPEC": _format_root_spec(root_spec, main_phase, strip_compilers), "SPACK_JOB_SPEC_DAG_HASH": release_spec_dag_hash, "SPACK_JOB_SPEC_PKG_NAME": release_spec.name, "SPACK_COMPILER_ACTION": compiler_action, @@ -953,9 +929,7 @@ def generate_gitlab_ci_yaml( # purposes, so we only get the direct dependencies. dep_jobs = [] for dep_label in dependencies[spec_label]: - dep_pkg = _pkg_name_from_spec_label(dep_label) - dep_root = spec_labels[dep_label]["rootSpec"] - dep_jobs.append(dep_root[dep_pkg]) + dep_jobs.append(spec_labels[dep_label]["spec"]) job_dependencies.extend( _format_job_needs( @@ -1039,7 +1013,11 @@ def generate_gitlab_ci_yaml( tty.debug(debug_msg) if prune_dag and not rebuild_spec: - tty.debug("Pruning {0}, does not need rebuild.".format(release_spec.name)) + tty.debug( + "Pruning {0}/{1}, does not need rebuild.".format( + release_spec.name, release_spec.dag_hash() + ) + ) continue if broken_spec_urls is not None and release_spec_dag_hash in broken_spec_urls: @@ -1482,64 +1460,6 @@ def configure_compilers(compiler_action, scope=None): return None -def get_concrete_specs(env, root_spec, job_name, compiler_action): - """Build a dictionary of concrete specs relevant to a particular - rebuild job. This includes the root spec and the spec to be - rebuilt (which could be the same). - - Arguments: - - env (spack.environment.Environment): Activated spack environment - used to get concrete root spec by hash in case compiler_action - is anthing other than FIND_ANY. - root_spec (str): If compiler_action is FIND_ANY root_spec is - a string representation which can be turned directly into - a spec, otherwise, it's a hash used to index the activated - spack environment. - job_name (str): Name of package to be built, used to index the - concrete root spec and produce the concrete spec to be - built. - compiler_action (str): Determines how to interpret the root_spec - parameter, either as a string representation as a hash. - - Returns: - - .. code-block:: JSON - - { - "root": "", - "": "", - } - - """ - spec_map = { - "root": None, - } - - if compiler_action == "FIND_ANY": - # This corresponds to a bootstrapping phase where we need to - # rely on any available compiler to build the package (i.e. the - # compiler needed to be stripped from the spec when we generated - # the job), and thus we need to concretize the root spec again. - tty.debug("About to concretize {0}".format(root_spec)) - concrete_root = Spec(root_spec).concretized() - tty.debug("Resulting concrete root: {0}".format(concrete_root)) - else: - # in this case, either we're relying on Spack to install missing - # compiler bootstrapped in a previous phase, or else we only had one - # phase (like a site which already knows what compilers are available - # on it's runners), so we don't want to concretize that root spec - # again. The reason we take this path in the first case (bootstrapped - # compiler), is that we can't concretize a spec at this point if we're - # going to ask spack to "install_missing_compilers". - concrete_root = env.specs_by_hash[root_spec] - - spec_map["root"] = concrete_root - spec_map[job_name] = concrete_root[job_name] - - return spec_map - - def _push_mirror_contents(env, specfile_path, sign_binaries, mirror_url): """Unchecked version of the public API, for easier mocking""" unsigned = not sign_binaries diff --git a/lib/spack/spack/cmd/ci.py b/lib/spack/spack/cmd/ci.py index 70016a29e8a..c0343d69b7e 100644 --- a/lib/spack/spack/cmd/ci.py +++ b/lib/spack/spack/cmd/ci.py @@ -277,8 +277,8 @@ def ci_rebuild(args): ci_pipeline_id = get_env_var("CI_PIPELINE_ID") ci_job_name = get_env_var("CI_JOB_NAME") signing_key = get_env_var("SPACK_SIGNING_KEY") - root_spec = get_env_var("SPACK_ROOT_SPEC") job_spec_pkg_name = get_env_var("SPACK_JOB_SPEC_PKG_NAME") + job_spec_dag_hash = get_env_var("SPACK_JOB_SPEC_DAG_HASH") compiler_action = get_env_var("SPACK_COMPILER_ACTION") spack_pipeline_type = get_env_var("SPACK_PIPELINE_TYPE") remote_mirror_override = get_env_var("SPACK_REMOTE_MIRROR_OVERRIDE") @@ -297,7 +297,6 @@ def ci_rebuild(args): # Debug print some of the key environment variables we should have received tty.debug("pipeline_artifacts_dir = {0}".format(pipeline_artifacts_dir)) - tty.debug("root_spec = {0}".format(root_spec)) tty.debug("remote_mirror_url = {0}".format(remote_mirror_url)) tty.debug("job_spec_pkg_name = {0}".format(job_spec_pkg_name)) tty.debug("compiler_action = {0}".format(compiler_action)) @@ -360,10 +359,11 @@ def ci_rebuild(args): mirror_msg = "artifact buildcache enabled, mirror url: {0}".format(pipeline_mirror_url) tty.debug(mirror_msg) - # Whatever form of root_spec we got, use it to get a map giving us concrete - # specs for this job and all of its dependencies. - spec_map = spack_ci.get_concrete_specs(env, root_spec, job_spec_pkg_name, compiler_action) - job_spec = spec_map[job_spec_pkg_name] + # Get the concrete spec to be built by this job. + try: + job_spec = env.get_one_by_hash(job_spec_dag_hash) + except AssertionError: + tty.die("Could not find environment spec with hash {0}".format(job_spec_dag_hash)) job_spec_json_file = "{0}.json".format(job_spec_pkg_name) job_spec_json_path = os.path.join(repro_dir, job_spec_json_file) @@ -427,17 +427,11 @@ def ci_rebuild(args): with open(job_spec_json_path, "w") as fd: fd.write(job_spec.to_json(hash=ht.dag_hash)) - # Write the concrete root spec json into the reproduction directory - root_spec_json_path = os.path.join(repro_dir, "root.json") - with open(root_spec_json_path, "w") as fd: - fd.write(spec_map["root"].to_json(hash=ht.dag_hash)) - # Write some other details to aid in reproduction into an artifact repro_file = os.path.join(repro_dir, "repro.json") repro_details = { "job_name": ci_job_name, "job_spec_json": job_spec_json_file, - "root_spec_json": "root.json", "ci_project_dir": ci_project_dir, } with open(repro_file, "w") as fd: diff --git a/lib/spack/spack/environment/environment.py b/lib/spack/spack/environment/environment.py index c3d30bd42d0..843cd5ff9c4 100644 --- a/lib/spack/spack/environment/environment.py +++ b/lib/spack/spack/environment/environment.py @@ -1819,6 +1819,14 @@ def get_by_hash(self, dag_hash): matches[dep_hash] = spec return list(matches.values()) + def get_one_by_hash(self, dag_hash): + """Returns the single spec from the environment which matches the + provided hash. Raises an AssertionError if no specs match or if + more than one spec matches.""" + hash_matches = self.get_by_hash(dag_hash) + assert len(hash_matches) == 1 + return hash_matches[0] + def matching_spec(self, spec): """ Given a spec (likely not concretized), find a matching concretized diff --git a/lib/spack/spack/test/ci.py b/lib/spack/spack/test/ci.py index 2d8e65e8a5c..b2c83ca2a99 100644 --- a/lib/spack/spack/test/ci.py +++ b/lib/spack/spack/test/ci.py @@ -83,37 +83,6 @@ def assert_present(config): assert_present(last_config) -@pytest.mark.skipif(sys.platform == "win32", reason="Not supported on Windows (yet)") -def test_get_concrete_specs(config, mutable_mock_env_path, mock_packages): - e = ev.create("test1") - e.add("dyninst") - e.concretize() - - dyninst_hash = None - hash_dict = {} - - with e as active_env: - for s in active_env.all_specs(): - hash_dict[s.name] = s.dag_hash() - if s.name == "dyninst": - dyninst_hash = s.dag_hash() - - assert dyninst_hash - - spec_map = ci.get_concrete_specs(active_env, dyninst_hash, "dyninst", "NONE") - assert "root" in spec_map - - concrete_root = spec_map["root"] - assert concrete_root.dag_hash() == dyninst_hash - - s = spec.Spec("dyninst") - print("nonconc spec name: {0}".format(s.name)) - - spec_map = ci.get_concrete_specs(active_env, s.name, s.name, "FIND_ANY") - - assert "root" in spec_map - - class FakeWebResponder(object): def __init__(self, response_code=200, content_to_read=[]): self._resp_code = response_code diff --git a/lib/spack/spack/test/cmd/ci.py b/lib/spack/spack/test/cmd/ci.py index dff8484199a..2edf8788d58 100644 --- a/lib/spack/spack/test/cmd/ci.py +++ b/lib/spack/spack/test/cmd/ci.py @@ -885,7 +885,6 @@ def activate_rebuild_env(tmpdir, pkg_name, rebuild_env): "SPACK_CONCRETE_ENV_DIR": rebuild_env.env_dir.strpath, "CI_PIPELINE_ID": "7192", "SPACK_SIGNING_KEY": _signing_key(), - "SPACK_ROOT_SPEC": rebuild_env.root_spec_dag_hash, "SPACK_JOB_SPEC_DAG_HASH": rebuild_env.root_spec_dag_hash, "SPACK_JOB_SPEC_PKG_NAME": pkg_name, "SPACK_COMPILER_ACTION": "NONE", @@ -1084,7 +1083,6 @@ def test_ci_nothing_to_rebuild( "SPACK_JOB_TEST_DIR": "test_dir", "SPACK_LOCAL_MIRROR_DIR": mirror_dir.strpath, "SPACK_CONCRETE_ENV_DIR": tmpdir.strpath, - "SPACK_ROOT_SPEC": root_spec_dag_hash, "SPACK_JOB_SPEC_DAG_HASH": root_spec_dag_hash, "SPACK_JOB_SPEC_PKG_NAME": "archive-files", "SPACK_COMPILER_ACTION": "NONE", @@ -1243,8 +1241,7 @@ def test_push_mirror_contents( with tmpdir.as_cwd(): env_cmd("create", "test", "./spack.yaml") with ev.read("test") as env: - spec_map = ci.get_concrete_specs(env, "patchelf", "patchelf", "FIND_ANY") - concrete_spec = spec_map["patchelf"] + concrete_spec = Spec("patchelf").concretized() spec_json = concrete_spec.to_json(hash=ht.dag_hash) json_path = str(tmpdir.join("spec.json")) with open(json_path, "w") as ypfd: @@ -1605,9 +1602,8 @@ def test_ci_rebuild_index( with tmpdir.as_cwd(): env_cmd("create", "test", "./spack.yaml") - with ev.read("test") as env: - spec_map = ci.get_concrete_specs(env, "callpath", "callpath", "FIND_ANY") - concrete_spec = spec_map["callpath"] + with ev.read("test"): + concrete_spec = Spec("callpath").concretized() spec_json = concrete_spec.to_json(hash=ht.dag_hash) json_path = str(tmpdir.join("spec.json")) with open(json_path, "w") as ypfd: @@ -2143,22 +2139,16 @@ def test_ci_reproduce( shutil.copyfile(env.manifest_path, os.path.join(working_dir.strpath, "spack.yaml")) shutil.copyfile(env.lock_path, os.path.join(working_dir.strpath, "spack.lock")) - root_spec = None job_spec = None for h, s in env.specs_by_hash.items(): if s.name == "archive-files": - root_spec = s job_spec = s job_spec_json_path = os.path.join(working_dir.strpath, "archivefiles.json") with open(job_spec_json_path, "w") as fd: fd.write(job_spec.to_json(hash=ht.dag_hash)) - root_spec_json_path = os.path.join(working_dir.strpath, "root.json") - with open(root_spec_json_path, "w") as fd: - fd.write(root_spec.to_json(hash=ht.dag_hash)) - artifacts_root = os.path.join(working_dir.strpath, "scratch_dir") pipeline_path = os.path.join(artifacts_root, "pipeline.yml") @@ -2170,7 +2160,6 @@ def test_ci_reproduce( repro_details = { "job_name": job_name, "job_spec_json": "archivefiles.json", - "root_spec_json": "root.json", "ci_project_dir": working_dir.strpath, } with open(repro_file, "w") as fd: From b3e04e8cd2cb53d7b205590bf7ac540d4ebdfb93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lacroix?= Date: Thu, 20 Oct 2022 19:12:02 +0200 Subject: [PATCH 124/442] spdlog: Add version 1.10.0 (#33431) --- var/spack/repos/builtin/packages/spdlog/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/spdlog/package.py b/var/spack/repos/builtin/packages/spdlog/package.py index 6c8b24cd0f2..bf411c36831 100644 --- a/var/spack/repos/builtin/packages/spdlog/package.py +++ b/var/spack/repos/builtin/packages/spdlog/package.py @@ -12,6 +12,7 @@ class Spdlog(CMakePackage): homepage = "https://github.com/gabime/spdlog" url = "https://github.com/gabime/spdlog/archive/v0.9.0.tar.gz" + version("1.10.0", sha256="697f91700237dbae2326b90469be32b876b2b44888302afbc7aceb68bcfe8224") version("1.9.2", sha256="6fff9215f5cb81760be4cc16d033526d1080427d236e86d70bb02994f85e3d38") version("1.9.1", sha256="9a452cfa24408baccc9b2bc2d421d68172a7630c99e9504a14754be840d31a62") version("1.9.0", sha256="9ad181d75aaedbf47c8881e7b947a47cac3d306997e39de24dba60db633e70a7") From 0b873be13c09d28ac1423de6ccebe7cb502fcd3a Mon Sep 17 00:00:00 2001 From: "Adam J. Stewart" Date: Thu, 20 Oct 2022 12:12:59 -0500 Subject: [PATCH 125/442] py-rasterio: add v1.3.3 (#33428) --- var/spack/repos/builtin/packages/py-rasterio/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/py-rasterio/package.py b/var/spack/repos/builtin/packages/py-rasterio/package.py index e81bd6a217d..7eddb86cba5 100644 --- a/var/spack/repos/builtin/packages/py-rasterio/package.py +++ b/var/spack/repos/builtin/packages/py-rasterio/package.py @@ -20,6 +20,7 @@ class PyRasterio(PythonPackage): maintainers = ["adamjstewart"] version("master", branch="master") + version("1.3.3", sha256="b6fb1f12489f3a678c05ddcb78a74f0b6f63836219f51c0541e505f5e5208e7d") version("1.3.2", sha256="a91b32f649bc5aa3259909349258eb7999b7e830375f63cd37ade2082066ec1c") version("1.3.1", sha256="91a22c512862e6411def675cd864eb63000ec2e0922c8bf25834c631ba80bdc1") version("1.3.0", sha256="90171035e5b201cdb85a9abd60181426366040d4ca44706958db982a030f8dc4") From 69e66f57a928b5d0d046e97c90a987505f4fc76a Mon Sep 17 00:00:00 2001 From: SoniaScard <83462318+SoniaScard@users.noreply.github.com> Date: Thu, 20 Oct 2022 19:56:53 +0200 Subject: [PATCH 126/442] ophidia-primitives: new package at v1.7 (#33434) * ophidia-primitives: new package at v1.7 * ophidia-primitives: Add mantainers * ophidia-primitives: Fix style Co-authored-by: SoniaScard --- .../packages/ophidia-primitives/package.py | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 var/spack/repos/builtin/packages/ophidia-primitives/package.py diff --git a/var/spack/repos/builtin/packages/ophidia-primitives/package.py b/var/spack/repos/builtin/packages/ophidia-primitives/package.py new file mode 100644 index 00000000000..804df33e37c --- /dev/null +++ b/var/spack/repos/builtin/packages/ophidia-primitives/package.py @@ -0,0 +1,41 @@ +# 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 OphidiaPrimitives(AutotoolsPackage): + """Array-based primitives for the Ophidia framework""" + + homepage = "https://github.com/OphidiaBigData/ophidia-primitives" + url = "https://github.com/OphidiaBigData/ophidia-primitives/archive/refs/tags/v1.7.1.tar.gz" + maintainers = ["eldoo", "SoniaScard"] + version( + "1.7.1", + sha256="efec5248dca8fb766abcd536344eefbe2e970fb551f03454a968e59e2df69116", + ) + + depends_on("autoconf", type="build") + depends_on("automake", type="build") + depends_on("libtool", type="build") + depends_on("m4", type="build") + depends_on("pkg-config", type="build") + + depends_on("boost@1.79.0") + depends_on("mysql") + depends_on("libmatheval") + depends_on("zlib") + depends_on("gsl") + + def autoreconf(self, spec, prefix): + autoreconf("--install", "--verbose", "--force") + + def configure_args(self): + args = [ + "--with-gsl-lib-path={0}".format(self.spec["gsl"].prefix.lib), + "--with-gsl-header-path={0}".format(self.spec["gsl"].prefix.include), + ] + + return args From cd015b84980bb26190c73c0cdbbcf0cc4b0db95e Mon Sep 17 00:00:00 2001 From: Jon Rood Date: Thu, 20 Oct 2022 12:04:55 -0600 Subject: [PATCH 127/442] Update OpenFAST package file (#33438) * Update OpenFAST package file. * Add comment. --- .../builtin/packages/openfast/package.py | 41 +++++++++++-------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/var/spack/repos/builtin/packages/openfast/package.py b/var/spack/repos/builtin/packages/openfast/package.py index b9d1382304a..c5d9086c61c 100644 --- a/var/spack/repos/builtin/packages/openfast/package.py +++ b/var/spack/repos/builtin/packages/openfast/package.py @@ -16,6 +16,8 @@ class Openfast(CMakePackage): version("develop", branch="dev") version("master", branch="main") + version("3.2.1", tag="v3.2.1") + version("3.2.0", tag="v3.2.0") version("3.1.0", tag="v3.1.0") version("3.0.0", tag="v3.0.0") version("2.6.0", tag="v2.6.0") @@ -33,6 +35,7 @@ class Openfast(CMakePackage): variant("cxx", default=False, description="Enable C++ bindings") variant("pic", default=True, description="Position independent code") variant("openmp", default=False, description="Enable OpenMP support") + variant("netcdf", default=False, description="Enable NetCDF support") # Dependencies for OpenFAST Fortran depends_on("blas") @@ -44,6 +47,7 @@ class Openfast(CMakePackage): depends_on("hdf5+mpi+cxx+hl", when="+cxx") depends_on("zlib", when="+cxx") depends_on("libxml2", when="+cxx") + depends_on("netcdf-c", when="+netcdf") def cmake_args(self): spec = self.spec @@ -52,8 +56,8 @@ def cmake_args(self): options.extend( [ - "-DBUILD_DOCUMENTATION:BOOL=OFF", - "-DBUILD_TESTING:BOOL=OFF", + define("BUILD_DOCUMENTATION", False), + define("BUILD_TESTING", False), self.define_from_variant("BUILD_SHARED_LIBS", "shared"), self.define_from_variant("DOUBLE_PRECISION", "double-precision"), self.define_from_variant("USE_DLL_INTERFACE", "dll-interface"), @@ -66,42 +70,45 @@ def cmake_args(self): blas_libs = spec["lapack"].libs + spec["blas"].libs options.extend( [ - "-DBLAS_LIBRARIES=%s" % blas_libs.joined(";"), - "-DLAPACK_LIBRARIES=%s" % blas_libs.joined(";"), + define("BLAS_LIBRARIES", blas_libs.joined(";")), + define("LAPACK_LIBRARIES", blas_libs.joined(";")), ] ) if "+cxx" in spec: options.extend( [ - "-DCMAKE_C_COMPILER=%s" % spec["mpi"].mpicc, - "-DCMAKE_CXX_COMPILER=%s" % spec["mpi"].mpicxx, - "-DCMAKE_Fortran_COMPILER=%s" % spec["mpi"].mpifc, - "-DMPI_CXX_COMPILER:PATH=%s" % spec["mpi"].mpicxx, - "-DMPI_C_COMPILER:PATH=%s" % spec["mpi"].mpicc, - "-DMPI_Fortran_COMPILER:PATH=%s" % spec["mpi"].mpifc, - "-DHDF5_ROOT:PATH=%s" % spec["hdf5"].prefix, - "-DYAML_ROOT:PATH=%s" % spec["yaml-cpp"].prefix, + define("CMAKE_CXX_COMPILER", spec["mpi"].mpicxx), + define("CMAKE_C_COMPILER", spec["mpi"].mpicc), + define("CMAKE_Fortran_COMPILER", spec["mpi"].mpifc), + define("MPI_CXX_COMPILER", spec["mpi"].mpicxx), + define("MPI_C_COMPILER", spec["mpi"].mpicc), + define("MPI_Fortran_COMPILER", spec["mpi"].mpifc), + define("HDF5_ROOT", spec["hdf5"].prefix), + define("YAML_ROOT", spec["yaml"].prefix), + define("NETCDF_ROOT", spec["netcdf-c"].prefix), + # The following xpects that HDF5 was built with CMake. + # Solves issue with OpenFAST trying to link + # to HDF5 libraries with a "-shared" prefix + # that do not exist. + define("HDF5_NO_FIND_PACKAGE_CONFIG_FILE", True), ] ) if "~shared" in spec: options.extend( [ - "-DHDF5_USE_STATIC_LIBRARIES=ON", + define("HDF5_USE_STATIC_LIBRARIES", True), ] ) if "+openmp" in spec: options.extend( [ - "-DOPENMP:BOOL=ON", + define("OPENMP", True), ] ) - if "darwin" in spec.architecture: - options.append("-DCMAKE_MACOSX_RPATH:BOOL=ON") - return options def flag_handler(self, name, flags): From 70e369086c71817dfb5ada11c0593b7f4451f47e Mon Sep 17 00:00:00 2001 From: Satish Balay Date: Thu, 20 Oct 2022 13:20:45 -0500 Subject: [PATCH 128/442] butterflypack: add version 2.2.2 and openmp variant (#33416) - add conflcit with gcc < 7 - fails with MacOS sed - so add in (gnu) sed as build dependency --- var/spack/repos/builtin/packages/butterflypack/package.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/var/spack/repos/builtin/packages/butterflypack/package.py b/var/spack/repos/builtin/packages/butterflypack/package.py index 68da397e847..5d1572b19aa 100644 --- a/var/spack/repos/builtin/packages/butterflypack/package.py +++ b/var/spack/repos/builtin/packages/butterflypack/package.py @@ -26,6 +26,7 @@ class Butterflypack(CMakePackage): maintainers = ["liuyangzhuan"] version("master", branch="master") + version("2.2.2", sha256="73f67073e4291877f1eee19483a8a7b3c761eaf79a75805d52105ceedead85ea") version("2.2.1", sha256="4cedc2896a6b368773ce4f9003aa2c0230baf56a4464a6b899a155e01406a232") version("2.2.0", sha256="1ce5b8461b3c4f488cee6396419e8a6f0a1bcf95254f24d7c27bfa53b391c30b") version("2.1.1", sha256="0d4a1ce540c84de37e4398f72ecf685ea0c4eabceba13015add5b445a4ca3a15") @@ -39,12 +40,16 @@ class Butterflypack(CMakePackage): version("1.0.0", sha256="86c5eb09a18522367d63ce2bacf67ca1c9813ef351a1443baaab3c53f0d77232") variant("shared", default=True, description="Build shared libraries") + variant("openmp", default=True, description="add OpenMP support") depends_on("mpi") depends_on("blas") depends_on("lapack") depends_on("scalapack") depends_on("arpack-ng") + depends_on("sed", type="build") + + conflicts("%gcc@:7", when="@2.2.1:") # https://github.com/spack/spack/issues/31818 patch("qopenmp-for-oneapi.patch", when="@2.1.1 %oneapi") @@ -66,5 +71,6 @@ def cmake_args(self): "-DTPL_ARPACK_LIBRARIES=%s" % spec["arpack-ng"].libs.joined(";"), self.define_from_variant("BUILD_SHARED_LIBS", "shared"), ] + args.append("-Denable_openmp=%s" % ("ON" if "+openmp" in spec else "OFF")) return args From e60e743843fde91f8cb37f95479180aa1bba8de4 Mon Sep 17 00:00:00 2001 From: Cody Balos Date: Thu, 20 Oct 2022 11:50:59 -0700 Subject: [PATCH 129/442] kokkos and kokkos-kernels: add new versions (#33301) * kokkos: add version 3.7.00 * kokkos-kernels: add versions 3.6.01 and 3.7.00 * add correct kokkos dependence --- var/spack/repos/builtin/packages/kokkos-kernels/package.py | 4 ++++ var/spack/repos/builtin/packages/kokkos/package.py | 1 + 2 files changed, 5 insertions(+) diff --git a/var/spack/repos/builtin/packages/kokkos-kernels/package.py b/var/spack/repos/builtin/packages/kokkos-kernels/package.py index 58f57bb44e2..b82253feefa 100644 --- a/var/spack/repos/builtin/packages/kokkos-kernels/package.py +++ b/var/spack/repos/builtin/packages/kokkos-kernels/package.py @@ -23,6 +23,8 @@ class KokkosKernels(CMakePackage, CudaPackage): # openssl sha256 kokkos-kernels-x.y.z.tar.gz version("develop", branch="develop") version("master", branch="master") + version("3.7.00", sha256="51bc6db3995392065656848e2b152cfd1c3a95a951ab18a3934278113d59f32b") + version("3.6.01", sha256="f000b156c8c0b80e85d38587907c11d9479aaf362408b812effeda5e22b24d0d") version("3.6.00", sha256="2753643fd643b9eed9f7d370e0ff5fa957211d08a91aa75398e31cbc9e5eb0a5") version("3.5.00", sha256="a03a41a047d95f9f07cd1e1d30692afdb75b5c705ef524e19c1d02fe60ccf8d1") version("3.4.01", sha256="f504aa4afbffb58fa7c4430d0fdb8fd5690a268823fa15eb0b7d58dab9d351e6") @@ -37,6 +39,8 @@ class KokkosKernels(CMakePackage, CudaPackage): depends_on("kokkos") depends_on("kokkos@master", when="@master") depends_on("kokkos@develop", when="@develop") + depends_on("kokkos@3.7.00", when="@3.7.00") + depends_on("kokkos@3.6.01", when="@3.6.01") depends_on("kokkos@3.6.00", when="@3.6.00") depends_on("kokkos@3.5.00", when="@3.5.00") depends_on("kokkos@3.4.01", when="@3.4.01") diff --git a/var/spack/repos/builtin/packages/kokkos/package.py b/var/spack/repos/builtin/packages/kokkos/package.py index ef08372d0dc..965ab03721c 100644 --- a/var/spack/repos/builtin/packages/kokkos/package.py +++ b/var/spack/repos/builtin/packages/kokkos/package.py @@ -25,6 +25,7 @@ class Kokkos(CMakePackage, CudaPackage, ROCmPackage): version("master", branch="master") version("develop", branch="develop") + version("3.7.00", sha256="62e3f9f51c798998f6493ed36463f66e49723966286ef70a9dcba329b8443040") version("3.6.01", sha256="1b80a70c5d641da9fefbbb652e857d7c7a76a0ebad1f477c253853e209deb8db") version("3.6.00", sha256="53b11fffb53c5d48da5418893ac7bc814ca2fde9c86074bdfeaa967598c918f4") version("3.5.00", sha256="748f06aed63b1e77e3653cd2f896ef0d2c64cb2e2d896d9e5a57fec3ff0244ff") From e981ab9b6555bf8cd56a0528325b3477aca64793 Mon Sep 17 00:00:00 2001 From: eugeneswalker <38933153+eugeneswalker@users.noreply.github.com> Date: Thu, 20 Oct 2022 13:21:43 -0700 Subject: [PATCH 130/442] hiop: add v0.7.0 (#33441) * hiop: add v0.7.0 * Update var/spack/repos/builtin/packages/hiop/package.py Co-authored-by: Cameron Rutherford Co-authored-by: Cameron Rutherford --- var/spack/repos/builtin/packages/hiop/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/hiop/package.py b/var/spack/repos/builtin/packages/hiop/package.py index 7b7e08c41b4..88d48873988 100644 --- a/var/spack/repos/builtin/packages/hiop/package.py +++ b/var/spack/repos/builtin/packages/hiop/package.py @@ -22,6 +22,7 @@ class Hiop(CMakePackage, CudaPackage, ROCmPackage): maintainers = ["ashermancinelli", "CameronRutherford", "pelesh"] # Most recent tagged snapshot is the preferred version when profiling. + version("0.7.0", commit="5f42ab34b419b7cf64d0fffb29d443b009dbfd75", submodules=True) version("0.6.2", commit="55652fbe923ab9107d002d0d070865bd22375b28") version("0.6.1", commit="a9e2697b00aa13ecf0ae4783dd8a41dee11dc50e") version("0.6.0", commit="21af7eb0d6427be73546cf303abc84e834a5a55d") From ee721f9c91a614b6dc6bacd3070f50cfeac97015 Mon Sep 17 00:00:00 2001 From: Mikael Simberg Date: Thu, 20 Oct 2022 22:32:25 +0200 Subject: [PATCH 131/442] Add Boost 1.80.0 (#32879) * Add Boost 1.80.0 * Add conflict for Boost 1.80.0 and dealii * Add conflict for Boost 1.80 and %oneapi --- var/spack/repos/builtin/packages/boost/package.py | 5 +++++ var/spack/repos/builtin/packages/dealii/package.py | 7 +++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/var/spack/repos/builtin/packages/boost/package.py b/var/spack/repos/builtin/packages/boost/package.py index 4e2c05ada33..a57b2e5bac5 100644 --- a/var/spack/repos/builtin/packages/boost/package.py +++ b/var/spack/repos/builtin/packages/boost/package.py @@ -27,6 +27,7 @@ class Boost(Package): maintainers = ["hainest"] version("develop", branch="develop", submodules=True) + version("1.80.0", sha256="1e19565d82e43bc59209a168f5ac899d3ba471d55c7610c677d4ccf2c9c500c0") version("1.79.0", sha256="475d589d51a7f8b3ba2ba4eda022b170e562ca3b760ee922c146b6c65856ef39") version("1.78.0", sha256="8681f175d4bdb26c52222665793eef08490d7758529330f98d3b29dd0735bccc") version("1.77.0", sha256="fc9f85fc030e233142908241af7a846e60630aa7388de9a5fafb1f3a26840854") @@ -261,6 +262,10 @@ def libs(self): # https://github.com/STEllAR-GROUP/hpx/issues/5442#issuecomment-878913339 conflicts("%gcc", when="@:1.76 +system platform=darwin") + # Boost 1.80 does not build with the Intel oneapi compiler + # (https://github.com/spack/spack/pull/32879#issuecomment-1265933265) + conflicts("%oneapi", when="@1.80") + # Patch fix from https://svn.boost.org/trac/boost/ticket/11856 patch("boost_11856.patch", when="@1.60.0%gcc@4.4.7") diff --git a/var/spack/repos/builtin/packages/dealii/package.py b/var/spack/repos/builtin/packages/dealii/package.py index 222691c69ec..902e310be69 100644 --- a/var/spack/repos/builtin/packages/dealii/package.py +++ b/var/spack/repos/builtin/packages/dealii/package.py @@ -106,8 +106,11 @@ class Dealii(CMakePackage, CudaPackage): # more precisely its variation https://github.com/dealii/dealii/pull/5572#issuecomment-349742019 # 1.68.0 has issues with serialization https://github.com/dealii/dealii/issues/7074 # adopt https://github.com/boostorg/serialization/pull/105 as a fix + # + # dealii does not build with Boost 1.80.0 + # (https://github.com/spack/spack/pull/32879#issuecomment-1265933265) depends_on( - "boost@1.59.0:1.63,1.65.1,1.67.0:+thread+system+serialization+iostreams", + "boost@1.59.0:1.63,1.65.1,1.67.0:1.79+thread+system+serialization+iostreams", patches=[ patch("boost_1.65.1_singleton.patch", level=1, when="@1.65.1"), patch("boost_1.68.0.patch", level=1, when="@1.68.0"), @@ -115,7 +118,7 @@ class Dealii(CMakePackage, CudaPackage): when="~python", ) depends_on( - "boost@1.59.0:1.63,1.65.1,1.67.0:+thread+system+serialization+iostreams+python", + "boost@1.59.0:1.63,1.65.1,1.67.0:1.79+thread+system+serialization+iostreams+python", patches=[ patch("boost_1.65.1_singleton.patch", level=1, when="@1.65.1"), patch("boost_1.68.0.patch", level=1, when="@1.68.0"), From 9621b2bb3b226cc887c2a7a5b04e85e24c466f1a Mon Sep 17 00:00:00 2001 From: Luke Diorio-Toth Date: Thu, 20 Oct 2022 15:44:57 -0500 Subject: [PATCH 132/442] replaced package shortbred with py-shortbred (#33404) * fixed version numbers to python 2 and old biopython * changed shortbred pacakge to pypi, removed python 2 version * added package description * re-added shortbred package with depreciated flag * fixed style and removed unnecessary python dep (it can't build with python 2 anyway) * removed whitespace and readded the python2.7.9+ dep * fixed style --- .../builtin/packages/py-shortbred/package.py | 25 +++++++++++++++++++ .../builtin/packages/shortbred/package.py | 6 ++++- 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 var/spack/repos/builtin/packages/py-shortbred/package.py diff --git a/var/spack/repos/builtin/packages/py-shortbred/package.py b/var/spack/repos/builtin/packages/py-shortbred/package.py new file mode 100644 index 00000000000..44dc115f122 --- /dev/null +++ b/var/spack/repos/builtin/packages/py-shortbred/package.py @@ -0,0 +1,25 @@ +# 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 PyShortbred(PythonPackage): + """ShortBRED is a system for profiling protein families of interest at + very high specificity in shotgun meta'omic sequencing data.""" + + homepage = "https://huttenhower.sph.harvard.edu/shortbred/" + pypi = "shortbred/shortbred-0.9.5.tar.gz" + + version("0.9.5", sha256="a6ac09b858f14e2c0b8622b122ec91e5d02d32c12429cad66626d7ef26df10d5") + + depends_on("python@2.7.9:", type=("build", "run")) + depends_on("py-setuptools", type="build") + depends_on("py-biopython@1.65:", type="run") + depends_on("blast-plus@2.2.28:", type="run") + depends_on("usearch@6.0.307:", type="run") + depends_on("muscle@3.8.31:", type="run") + depends_on("cdhit@4.6:", type="run") diff --git a/var/spack/repos/builtin/packages/shortbred/package.py b/var/spack/repos/builtin/packages/shortbred/package.py index 502bfd32eb7..a08fb3efc6d 100644 --- a/var/spack/repos/builtin/packages/shortbred/package.py +++ b/var/spack/repos/builtin/packages/shortbred/package.py @@ -13,7 +13,11 @@ class Shortbred(Package): homepage = "https://huttenhower.sph.harvard.edu/shortbred" url = "https://bitbucket.org/biobakery/shortbred/get/0.9.4.tar.gz" - version("0.9.4", sha256="a85e5609db79696d3f2d478408fc6abfeea7628de9f533c4e1e0ea3622b397ba") + version( + "0.9.4", + sha256="a85e5609db79696d3f2d478408fc6abfeea7628de9f533c4e1e0ea3622b397ba", + deprecated=True, + ) depends_on("blast-plus@2.2.28:") depends_on("cdhit@4.6:") From 1e4732d5fed8bdf35808c658ced2749c325efa33 Mon Sep 17 00:00:00 2001 From: eugeneswalker <38933153+eugeneswalker@users.noreply.github.com> Date: Thu, 20 Oct 2022 14:26:18 -0700 Subject: [PATCH 133/442] e4s ci: add raja +rocm (#32505) --- share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml index 6465229ba97..d4e86386bc5 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml @@ -216,6 +216,7 @@ spack: - magma ~cuda +rocm amdgpu_target=gfx90a - papi +rocm amdgpu_target=gfx90a - petsc +rocm amdgpu_target=gfx90a + - raja ~openmp +rocm amdgpu_target=gfx90a - slate +rocm amdgpu_target=gfx90a - slepc +rocm amdgpu_target=gfx90a ^petsc +rocm amdgpu_target=gfx90a - strumpack ~slate +rocm amdgpu_target=gfx90a @@ -244,7 +245,6 @@ spack: # ROCm failures #- chai ~benchmarks +rocm amdgpu_target=gfx90a # umpire: Target "blt_hip" INTERFACE_INCLUDE_DIRECTORIES property contains path: "/tmp/root/spack-stage/spack-stage-umpire-2022.03.1-by6rldnpdowaaoqgxkeqejwyx5uxo2sv/spack-src/HIP_CLANG_INCLUDE_PATH-NOTFOUND/.." which is prefixed in the source directory. - #- raja ~openmp +rocm amdgpu_target=gfx90a # cmake: Could NOT find ROCPRIM (missing: ROCPRIM_INCLUDE_DIRS) mirrors: { "mirror": "s3://spack-binaries/develop/e4s" } From abf3a696bd978b91cdf0b8badfbbf72f3c4f3c38 Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Fri, 21 Oct 2022 12:17:53 +0200 Subject: [PATCH 134/442] Remove "spack buildcache copy" in v0.19.0 (#33437) --- lib/spack/spack/cmd/buildcache.py | 86 ------------------------------- share/spack/spack-completion.bash | 6 +-- 2 files changed, 1 insertion(+), 91 deletions(-) diff --git a/lib/spack/spack/cmd/buildcache.py b/lib/spack/spack/cmd/buildcache.py index 6aaa5eb1c75..d25f2430391 100644 --- a/lib/spack/spack/cmd/buildcache.py +++ b/lib/spack/spack/cmd/buildcache.py @@ -8,7 +8,6 @@ import shutil import sys import tempfile -import warnings import llnl.util.tty as tty @@ -258,19 +257,6 @@ def setup_parser(subparser): ) savespecfile.set_defaults(func=save_specfile_fn) - # Copy buildcache from some directory to another mirror url - copy = subparsers.add_parser("copy", help=copy_fn.__doc__) - copy.add_argument( - "--base-dir", default=None, help="Path to mirror directory (root of existing buildcache)" - ) - copy.add_argument( - "--spec-file", - default=None, - help=("Path to spec json or yaml file representing buildcache entry to" + " copy"), - ) - copy.add_argument("--destination-url", default=None, help="Destination mirror url") - copy.set_defaults(func=copy_fn) - # Sync buildcache entries from one mirror to another sync = subparsers.add_parser("sync", help=sync_fn.__doc__) sync.add_argument( @@ -549,78 +535,6 @@ def save_specfile_fn(args): sys.exit(0) -def copy_fn(args): - """Copy a buildcache entry and all its files from one mirror, given as - '--base-dir', to some other mirror, specified as '--destination-url'. - The specific buildcache entry to be copied from one location to the - other is identified using the '--spec-file' argument.""" - # TODO: Remove after v0.18.0 release - msg = ( - '"spack buildcache copy" is deprecated and will be removed from ' - "Spack starting in v0.19.0" - ) - warnings.warn(msg) - - if not args.spec_file: - tty.msg("No spec yaml provided, exiting.") - sys.exit(1) - - if not args.base_dir: - tty.msg("No base directory provided, exiting.") - sys.exit(1) - - if not args.destination_url: - tty.msg("No destination mirror url provided, exiting.") - sys.exit(1) - - dest_url = args.destination_url - - if dest_url[0:7] != "file://" and dest_url[0] != "/": - tty.msg('Only urls beginning with "file://" or "/" are supported ' + "by buildcache copy.") - sys.exit(1) - - try: - with open(args.spec_file, "r") as fd: - spec = Spec.from_yaml(fd.read()) - except Exception as e: - tty.debug(e) - tty.error("Unable to concrectize spec from yaml {0}".format(args.spec_file)) - sys.exit(1) - - dest_root_path = dest_url - if dest_url[0:7] == "file://": - dest_root_path = dest_url[7:] - - build_cache_dir = bindist.build_cache_relative_path() - - tarball_rel_path = os.path.join(build_cache_dir, bindist.tarball_path_name(spec, ".spack")) - tarball_src_path = os.path.join(args.base_dir, tarball_rel_path) - tarball_dest_path = os.path.join(dest_root_path, tarball_rel_path) - - specfile_rel_path = os.path.join(build_cache_dir, bindist.tarball_name(spec, ".spec.json")) - specfile_src_path = os.path.join(args.base_dir, specfile_rel_path) - specfile_dest_path = os.path.join(dest_root_path, specfile_rel_path) - - specfile_rel_path_yaml = os.path.join( - build_cache_dir, bindist.tarball_name(spec, ".spec.yaml") - ) - specfile_src_path_yaml = os.path.join(args.base_dir, specfile_rel_path) - specfile_dest_path_yaml = os.path.join(dest_root_path, specfile_rel_path) - - # Make sure directory structure exists before attempting to copy - os.makedirs(os.path.dirname(tarball_dest_path)) - - # Now copy the specfile and tarball files to the destination mirror - tty.msg("Copying {0}".format(tarball_rel_path)) - shutil.copyfile(tarball_src_path, tarball_dest_path) - - tty.msg("Copying {0}".format(specfile_rel_path)) - shutil.copyfile(specfile_src_path, specfile_dest_path) - - tty.msg("Copying {0}".format(specfile_rel_path_yaml)) - shutil.copyfile(specfile_src_path_yaml, specfile_dest_path_yaml) - - def copy_buildcache_file(src_url, dest_url, local_path=None): """Copy from source url to destination url""" tmpdir = None diff --git a/share/spack/spack-completion.bash b/share/spack/spack-completion.bash index c6d407b4d5a..819b131bca1 100755 --- a/share/spack/spack-completion.bash +++ b/share/spack/spack-completion.bash @@ -508,7 +508,7 @@ _spack_buildcache() { then SPACK_COMPREPLY="-h --help" else - SPACK_COMPREPLY="create install list keys preview check download get-buildcache-name save-specfile copy sync update-index" + SPACK_COMPREPLY="create install list keys preview check download get-buildcache-name save-specfile sync update-index" fi } @@ -568,10 +568,6 @@ _spack_buildcache_save_specfile() { SPACK_COMPREPLY="-h --help --root-spec --root-specfile -s --specs --specfile-dir" } -_spack_buildcache_copy() { - SPACK_COMPREPLY="-h --help --base-dir --spec-file --destination-url" -} - _spack_buildcache_sync() { SPACK_COMPREPLY="-h --help --manifest-glob --src-directory --src-mirror-name --src-mirror-url --dest-directory --dest-mirror-name --dest-mirror-url" } From 93db654b8de6ae76bef382dc3c37eb715baa68b5 Mon Sep 17 00:00:00 2001 From: Satish Balay Date: Fri, 21 Oct 2022 05:34:18 -0500 Subject: [PATCH 135/442] intel-tbb: add in versions 2021.7.0, 2021.6.0 (#33445) 2021.7.0 fixes build on linux-ubuntu20.04-skylake / oneapi@2022.2.0 --- var/spack/repos/builtin/packages/intel-tbb/package.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/var/spack/repos/builtin/packages/intel-tbb/package.py b/var/spack/repos/builtin/packages/intel-tbb/package.py index f0abf5a70ba..1bc13ac1a33 100644 --- a/var/spack/repos/builtin/packages/intel-tbb/package.py +++ b/var/spack/repos/builtin/packages/intel-tbb/package.py @@ -29,12 +29,9 @@ class IntelTbb(CMakePackage): # patches, filters and url_for_version() below as needed. version("master", branch="master") - version("2021.6.0-rc1", tag="v2021.6.0-rc1") - version( - "2021.5.0", - sha256="e5b57537c741400cf6134b428fc1689a649d7d38d9bb9c1b6d64f092ea28178a", - preferred=True, - ) + version("2021.7.0", sha256="2cae2a80cda7d45dc7c072e4295c675fff5ad8316691f26f40539f7e7e54c0cc") + version("2021.6.0", sha256="4897dd106d573e9dacda8509ca5af1a0e008755bf9c383ef6777ac490223031f") + version("2021.5.0", sha256="e5b57537c741400cf6134b428fc1689a649d7d38d9bb9c1b6d64f092ea28178a") version("2021.4.0", sha256="021796c7845e155e616f5ecda16daa606ebb4c6f90b996e5c08aebab7a8d3de3") version("2021.3.0", sha256="8f616561603695bbb83871875d2c6051ea28f8187dbe59299961369904d1d49e") version("2021.2.0", sha256="cee20b0a71d977416f3e3b4ec643ee4f38cedeb2a9ff015303431dd9d8d79854") From b1559cc831620ee2b2cf8e57fdecc5bb3bf8edfd Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Fri, 21 Oct 2022 14:42:06 +0200 Subject: [PATCH 136/442] gitlab: when_possible -> false (#33443) `reuse` and `when_possible` concretization broke the invariant that `spec[pkg_name]` has unique keys. This invariant is relied on in tons of places, such as when setting up the build environment. When using `when_possible` concretization, one may end up with two or more `perl`s or `python`s among the transitive deps of a spec, because concretization does not consider build-only deps of reusable specs. Until the code base is fixed not to rely on this broken property of `__getitem__`, we should disable reuse in CI. --- .../gitlab/cloud_pipelines/stacks/build_systems/spack.yaml | 2 +- share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml index eb60dd85fe1..4808763f374 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml @@ -3,7 +3,7 @@ spack: concretizer: reuse: false - unify: when_possible + unify: false config: install_tree: diff --git a/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml index ce8441a5d87..944c110ac54 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml @@ -3,7 +3,7 @@ spack: concretizer: reuse: false - unify: when_possible + unify: false config: concretizer: clingo From 428a8f72a0d732672a90f1f36b47eb573453ad16 Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Fri, 21 Oct 2022 15:02:39 +0200 Subject: [PATCH 137/442] git: new versions and deprecations (#33408) --- .../repos/builtin/packages/git/package.py | 38 +++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/var/spack/repos/builtin/packages/git/package.py b/var/spack/repos/builtin/packages/git/package.py index 1608e5eb9f1..26637127523 100644 --- a/var/spack/repos/builtin/packages/git/package.py +++ b/var/spack/repos/builtin/packages/git/package.py @@ -26,9 +26,32 @@ class Git(AutotoolsPackage): # Every new git release comes with a corresponding manpage resource: # https://www.kernel.org/pub/software/scm/git/git-manpages-{version}.tar.gz # https://mirrors.edge.kernel.org/pub/software/scm/git/sha256sums.asc - version("2.37.0", sha256="fc3ffe6c65c1f7c681a1ce6bb91703866e432c762731d4b57c566d696f6d62c3") - version("2.36.1", sha256="37d936fd17c81aa9ddd3dba4e56e88a45fa534ad0ba946454e8ce818760c6a2c") - version("2.35.2", sha256="0decc02a47e792f522df3183c38a61ad8fbb38927502ca6781467a6599a888cb") + version("2.38.1", sha256="620ed3df572a34e782a2be4c7d958d443469b2665eac4ae33f27da554d88b270") + version("2.37.4", sha256="a638c9bf9e45e8d48592076266adaa9b7aa272a99ee2aee2e166a649a9ba8a03") + version("2.36.3", sha256="0c831b88b0534f08051d1287505dfe45c367108ee043de6f1c0502711a7aa3a6") + version("2.35.5", sha256="2cca63fe7bebb5b4bf8efea7b46b12bb89c16ff9711b6b6d845928501d00d0a3") + version("2.34.5", sha256="26831c5e48a8c2bf6a4fede1b38e1e51ffd6dad85952cf69ac520ebd81a5ae82") + version("2.33.5", sha256="d061ed97f890befaef18b4aad80a37b40db90bcf24113c42765fee157a69c7de") + version("2.32.4", sha256="4c791b8e1d96948c9772efc21373ab9b3187af42cdebc3bcbb1a06d794d4e494") + version("2.31.5", sha256="2d4197660322937cc44cab5742deef727ba519ef7405455e33100912e3b019f2") + version("2.30.6", sha256="a6130b38843a5c80e80fb4f7ac4864d361cbf103d262b64e267264e49440d24a") + + # Deprecated versions + version( + "2.37.0", + sha256="fc3ffe6c65c1f7c681a1ce6bb91703866e432c762731d4b57c566d696f6d62c3", + deprecated=True, + ) + version( + "2.36.1", + sha256="37d936fd17c81aa9ddd3dba4e56e88a45fa534ad0ba946454e8ce818760c6a2c", + deprecated=True, + ) + version( + "2.35.2", + sha256="0decc02a47e792f522df3183c38a61ad8fbb38927502ca6781467a6599a888cb", + deprecated=True, + ) version( "2.35.1", sha256="9845a37dd01f9faaa7d8aa2078399d3aea91b43819a5efea6e2877b0af09bd43", @@ -256,18 +279,27 @@ class Git(AutotoolsPackage): ) for (_version, _sha256_manpage) in { + "2.38.1": "fcb27484406b64419a9f9890e95ef29af08e1f911d9d368546eddc59a18e245d", + "2.37.4": "06ed920949e717f3ab13c98327ee63cae5e3020ac657d14513ef8f843109b638", "2.37.0": "69386ab0dcdbc8398ebb97487733166033f1c7711b02b8861b1ae8f4f46e6e4e", + "2.36.6": "c5f5385c2b46270a8ce062a9c510bfa4288d9cca54efe0dff48a12ca969cfc6f", "2.36.1": "3fcd315976f06b54b0abb9c14d38c3d484f431ea4de70a706cc5dddc1799f4f7", + "2.35.5": "6cbd4d2185c7a757db21f873973fa1efb81069d8b8b8cc350ca6735cb98f45c5", "2.35.2": "86e153bdd96edd8462cb7a5c57be1b2b670b033c18272b0aa2e6a102acce50be", "2.35.1": "d90da8b28fe0088519e0dc3c9f4bc85e429c7d6ccbaadcfe94aed47fb9c95504", "2.35.0": "c0408a1c944c8e481d7f507bd90a7ee43c34617a1a7af2d76a1898dcf44fa430", + "2.34.5": "897941be5b223b9d32217adb64ea8747db2ba57be5f68be598c44d747d1061b2", "2.34.1": "220f1ed68582caeddf79c4db15e4eaa4808ec01fd11889e19232f0a74d7f31b0", "2.34.0": "fe66a69244def488306c3e05c1362ea53d8626d2a7e57cd7311df2dab1ef8356", + "2.33.5": "34648ede9ac2869190083ee826065c36165e54d9e2906b10680261b243d89890", "2.33.1": "292b08ca1b79422ff478a6221980099c5e3c0a38aba39d952063eedb68e27d93", "2.33.0": "ba9cd0f29a3632a3b78f8ed2389f0780aa6e8fcbe258259d7c584920d19ed1f7", + "2.32.4": "fa73d0eac384e594efdd4c21343545e407267ab64e970a6b395c7f1874ddb0bf", "2.32.0": "b5533c40ea1688231c0e2df51cc0d1c0272e17fe78a45ba6e60cb8f61fa4a53c", + "2.31.5": "18850fc8f1c34e51a0a98b9f974b8356a5d63a53c96fb9fe3dc2880ee84746ab", "2.31.1": "d330498aaaea6928b0abbbbb896f6f605efd8d35f23cbbb2de38c87a737d4543", "2.31.0": "a51b760c36be19113756839a9110b328a09abfff0d57f1c93ddac3974ccbc238", + "2.30.6": "6c20ab10be233e8ff7838351fa5210e972c08005ec541a5241f626cfd4adebfe", "2.30.1": "db323e1b242e9d0337363b1e538c8b879e4c46eedbf94d3bee9e65dab6d49138", "2.30.0": "e23035ae232c9a5eda57db258bc3b7f1c1060cfd66920f92c7d388b6439773a6", "2.29.2": "68b258e6d590cb78e02c0df741bbaeab94cbbac6d25de9da4fb3882ee098307b", From 7c3d93465c1d76e084d6b0ce4a44d1c0b4b1ae68 Mon Sep 17 00:00:00 2001 From: eugeneswalker <38933153+eugeneswalker@users.noreply.github.com> Date: Fri, 21 Oct 2022 08:15:31 -0700 Subject: [PATCH 138/442] axom@0.7.0: require cmake@3.21: (#33450) * axom@0.7.0: require cmake@3.21: * Update var/spack/repos/builtin/packages/axom/package.py Co-authored-by: Chris White Co-authored-by: Chris White --- var/spack/repos/builtin/packages/axom/package.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/var/spack/repos/builtin/packages/axom/package.py b/var/spack/repos/builtin/packages/axom/package.py index 672f4ff763a..bf6fa62da40 100644 --- a/var/spack/repos/builtin/packages/axom/package.py +++ b/var/spack/repos/builtin/packages/axom/package.py @@ -91,8 +91,8 @@ class Axom(CachedCMakePackage, CudaPackage, ROCmPackage): # Dependencies # ----------------------------------------------------------------------- # Basics - depends_on("cmake@3.8.2:", type="build") - depends_on("cmake@3.16.8:", type="build", when="+rocm") + depends_on("cmake@3.14:", type="build") + depends_on("cmake@3.21:", type="build", when="+rocm") depends_on("blt", type="build") depends_on("blt@0.5.1:", type="build", when="@0.6.2:") From f9112a6244dede4d52700c4e86f335b42ec69a49 Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Fri, 21 Oct 2022 18:30:26 +0200 Subject: [PATCH 139/442] Relocation should take hardlinks into account (#33460) Currently `relocate_text` and `relocate_text_bin` are unsafe in the sense that they run in parallel, and lead to races when modifying different items pointing to the same inode. This leads to the issue observed in #33453. This PR: 1. Renames those functions to `unsafe_*` so people are aware 2. Adds logic to deal with hardlinks in current binary packages 3. Adds logic to deal with hardlinks when creating new binary tarballs, so the install side doesn't have to de-dupe hardlinks. 4. Adds a test for 3 The assumption is that all our relocation logic preserves inodes. That is, we should never copy a file, modify it, and then move it back. I quickly verified, and its seems like this is true for (binary) text relocation, as well as rpath patching in patchelf (even when the file grows) and mach-o fixes. --- lib/spack/spack/binary_distribution.py | 168 ++++++++++++++++++------- lib/spack/spack/filesystem_view.py | 4 +- lib/spack/spack/relocate.py | 10 +- lib/spack/spack/rewiring.py | 4 +- lib/spack/spack/test/bindist.py | 46 +++++++ lib/spack/spack/test/packaging.py | 6 +- lib/spack/spack/test/relocate.py | 4 +- 7 files changed, 185 insertions(+), 57 deletions(-) diff --git a/lib/spack/spack/binary_distribution.py b/lib/spack/spack/binary_distribution.py index b712e82cc02..7ae91dd6bfe 100644 --- a/lib/spack/spack/binary_distribution.py +++ b/lib/spack/spack/binary_distribution.py @@ -23,7 +23,7 @@ import llnl.util.filesystem as fsys import llnl.util.lang import llnl.util.tty as tty -from llnl.util.filesystem import mkdirp +from llnl.util.filesystem import BaseDirectoryVisitor, mkdirp, visit_directory_tree import spack.cmd import spack.config as config @@ -642,6 +642,51 @@ def read_buildinfo_file(prefix): return buildinfo +class BuildManifestVisitor(BaseDirectoryVisitor): + """Visitor that collects a list of files and symlinks + that can be checked for need of relocation. It knows how + to dedupe hardlinks and deal with symlinks to files and + directories.""" + + def __init__(self): + # Save unique identifiers of files to avoid + # relocating hardlink files for each path. + self.visited = set() + + # Lists of files we will check + self.files = [] + self.symlinks = [] + + def seen_before(self, root, rel_path): + stat_result = os.lstat(os.path.join(root, rel_path)) + identifier = (stat_result.st_dev, stat_result.st_ino) + if identifier in self.visited: + return True + else: + self.visited.add(identifier) + return False + + def visit_file(self, root, rel_path, depth): + if self.seen_before(root, rel_path): + return + self.files.append(rel_path) + + def visit_symlinked_file(self, root, rel_path, depth): + # Note: symlinks *can* be hardlinked, but it is unclear if + # symlinks can be relinked in-place (preserving inode). + # Therefore, we do *not* de-dupe hardlinked symlinks. + self.symlinks.append(rel_path) + + def before_visit_dir(self, root, rel_path, depth): + return os.path.basename(rel_path) not in (".spack", "man") + + def before_visit_symlinked_dir(self, root, rel_path, depth): + # Treat symlinked directories simply as symlinks. + self.visit_symlinked_file(root, rel_path, depth) + # Never recurse into symlinked directories. + return False + + def get_buildfile_manifest(spec): """ Return a data structure with information about a build, including @@ -657,57 +702,52 @@ def get_buildfile_manifest(spec): "link_to_relocate": [], "other": [], "binary_to_relocate_fullpath": [], + "hardlinks_deduped": True, } - exclude_list = (".spack", "man") + # Guard against filesystem footguns of hardlinks and symlinks by using + # a visitor to retrieve a list of files and symlinks, so we don't have + # to worry about hardlinks of symlinked dirs and what not. + visitor = BuildManifestVisitor() + root = spec.prefix + visit_directory_tree(root, visitor) - # Do this at during tarball creation to save time when tarball unpacked. - # Used by make_package_relative to determine binaries to change. - for root, dirs, files in os.walk(spec.prefix, topdown=True): - dirs[:] = [d for d in dirs if d not in exclude_list] + # Symlinks. - # Directories may need to be relocated too. - for directory in dirs: - dir_path_name = os.path.join(root, directory) - rel_path_name = os.path.relpath(dir_path_name, spec.prefix) - if os.path.islink(dir_path_name): - link = os.readlink(dir_path_name) - if os.path.isabs(link) and link.startswith(spack.store.layout.root): - data["link_to_relocate"].append(rel_path_name) + # Obvious bugs: + # 1. relative links are not relocated. + # 2. paths are used as strings. + for rel_path in visitor.symlinks: + abs_path = os.path.join(root, rel_path) + link = os.readlink(abs_path) + if os.path.isabs(link) and link.startswith(spack.store.layout.root): + data["link_to_relocate"].append(rel_path) - for filename in files: - path_name = os.path.join(root, filename) - m_type, m_subtype = fsys.mime_type(path_name) - rel_path_name = os.path.relpath(path_name, spec.prefix) - added = False + # Non-symlinks. + for rel_path in visitor.files: + abs_path = os.path.join(root, rel_path) + m_type, m_subtype = fsys.mime_type(abs_path) - if os.path.islink(path_name): - link = os.readlink(path_name) - if os.path.isabs(link): - # Relocate absolute links into the spack tree - if link.startswith(spack.store.layout.root): - data["link_to_relocate"].append(rel_path_name) - added = True + if relocate.needs_binary_relocation(m_type, m_subtype): + # Why is this branch not part of needs_binary_relocation? :( + if ( + ( + m_subtype in ("x-executable", "x-sharedlib", "x-pie-executable") + and sys.platform != "darwin" + ) + or (m_subtype in ("x-mach-binary") and sys.platform == "darwin") + or (not rel_path.endswith(".o")) + ): + data["binary_to_relocate"].append(rel_path) + data["binary_to_relocate_fullpath"].append(abs_path) + continue - if relocate.needs_binary_relocation(m_type, m_subtype): - if ( - ( - m_subtype in ("x-executable", "x-sharedlib", "x-pie-executable") - and sys.platform != "darwin" - ) - or (m_subtype in ("x-mach-binary") and sys.platform == "darwin") - or (not filename.endswith(".o")) - ): - data["binary_to_relocate"].append(rel_path_name) - data["binary_to_relocate_fullpath"].append(path_name) - added = True + elif relocate.needs_text_relocation(m_type, m_subtype): + data["text_to_relocate"].append(rel_path) + continue - if relocate.needs_text_relocation(m_type, m_subtype): - data["text_to_relocate"].append(rel_path_name) - added = True + data["other"].append(abs_path) - if not added: - data["other"].append(path_name) return data @@ -734,6 +774,7 @@ def write_buildinfo_file(spec, workdir, rel=False): buildinfo["relocate_textfiles"] = manifest["text_to_relocate"] buildinfo["relocate_binaries"] = manifest["binary_to_relocate"] buildinfo["relocate_links"] = manifest["link_to_relocate"] + buildinfo["hardlinks_deduped"] = manifest["hardlinks_deduped"] buildinfo["prefix_to_hash"] = prefix_to_hash filename = buildinfo_file_name(workdir) with open(filename, "w") as outfile: @@ -1441,6 +1482,38 @@ def check_package_relocatable(workdir, spec, allow_root): relocate.raise_if_not_relocatable(cur_path_names, allow_root) +def dedupe_hardlinks_if_necessary(root, buildinfo): + """Updates a buildinfo dict for old archives that did + not dedupe hardlinks. De-duping hardlinks is necessary + when relocating files in parallel and in-place. This + means we must preserve inodes when relocating.""" + + # New archives don't need this. + if buildinfo.get("hardlinks_deduped", False): + return + + # Clearly we can assume that an inode is either in the + # textfile or binary group, but let's just stick to + # a single set of visited nodes. + visited = set() + + # Note: we do *not* dedupe hardlinked symlinks, since + # it seems difficult or even impossible to relink + # symlinks while preserving inode. + for key in ("relocate_textfiles", "relocate_binaries"): + if key not in buildinfo: + continue + new_list = [] + for rel_path in buildinfo[key]: + stat_result = os.lstat(os.path.join(root, rel_path)) + identifier = (stat_result.st_dev, stat_result.st_ino) + if identifier in visited: + continue + visited.add(identifier) + new_list.append(rel_path) + buildinfo[key] = new_list + + def relocate_package(spec, allow_root): """ Relocate the given package @@ -1503,6 +1576,9 @@ def relocate_package(spec, allow_root): tty.debug("Relocating package from", "%s to %s." % (old_layout_root, new_layout_root)) + # Old archives maybe have hardlinks repeated. + dedupe_hardlinks_if_necessary(workdir, buildinfo) + def is_backup_file(file): return file.endswith("~") @@ -1548,7 +1624,7 @@ def is_backup_file(file): # For all buildcaches # relocate the install prefixes in text files including dependencies - relocate.relocate_text(text_names, prefix_to_prefix_text) + relocate.unsafe_relocate_text(text_names, prefix_to_prefix_text) paths_to_relocate = [old_prefix, old_layout_root] paths_to_relocate.extend(prefix_to_hash.keys()) @@ -1564,13 +1640,13 @@ def is_backup_file(file): ) ) # relocate the install prefixes in binary files including dependencies - relocate.relocate_text_bin(files_to_relocate, prefix_to_prefix_bin) + relocate.unsafe_relocate_text_bin(files_to_relocate, prefix_to_prefix_bin) # If we are installing back to the same location # relocate the sbang location if the spack directory changed else: if old_spack_prefix != new_spack_prefix: - relocate.relocate_text(text_names, prefix_to_prefix_text) + relocate.unsafe_relocate_text(text_names, prefix_to_prefix_text) def _extract_inner_tarball(spec, filename, extract_to, unsigned, remote_checksum): diff --git a/lib/spack/spack/filesystem_view.py b/lib/spack/spack/filesystem_view.py index 2373ec5e452..db2d6c94774 100644 --- a/lib/spack/spack/filesystem_view.py +++ b/lib/spack/spack/filesystem_view.py @@ -95,11 +95,11 @@ def view_copy(src, dst, view, spec=None): prefix_to_projection[dep.prefix] = view.get_projection_for_spec(dep) if spack.relocate.is_binary(dst): - spack.relocate.relocate_text_bin(binaries=[dst], prefixes=prefix_to_projection) + spack.relocate.unsafe_relocate_text_bin(binaries=[dst], prefixes=prefix_to_projection) else: prefix_to_projection[spack.store.layout.root] = view._root prefix_to_projection[orig_sbang] = new_sbang - spack.relocate.relocate_text(files=[dst], prefixes=prefix_to_projection) + spack.relocate.unsafe_relocate_text(files=[dst], prefixes=prefix_to_projection) try: stat = os.stat(src) os.chown(dst, stat.st_uid, stat.st_gid) diff --git a/lib/spack/spack/relocate.py b/lib/spack/spack/relocate.py index 3ef332c2049..3297965b6ea 100644 --- a/lib/spack/spack/relocate.py +++ b/lib/spack/spack/relocate.py @@ -744,12 +744,15 @@ def relocate_links(links, orig_layout_root, orig_install_prefix, new_install_pre tty.warn(msg.format(link_target, abs_link, new_install_prefix)) -def relocate_text(files, prefixes, concurrency=32): +def unsafe_relocate_text(files, prefixes, concurrency=32): """Relocate text file from the original installation prefix to the new prefix. Relocation also affects the the path in Spack's sbang script. + Note: unsafe when files contains duplicates, such as repeated paths, + symlinks, hardlinks. + Args: files (list): Text files to be relocated prefixes (OrderedDict): String prefixes which need to be changed @@ -786,11 +789,14 @@ def relocate_text(files, prefixes, concurrency=32): tp.join() -def relocate_text_bin(binaries, prefixes, concurrency=32): +def unsafe_relocate_text_bin(binaries, prefixes, concurrency=32): """Replace null terminated path strings hard coded into binaries. The new install prefix must be shorter than the original one. + Note: unsafe when files contains duplicates, such as repeated paths, + symlinks, hardlinks. + Args: binaries (list): binaries to be relocated prefixes (OrderedDict): String prefixes which need to be changed. diff --git a/lib/spack/spack/rewiring.py b/lib/spack/spack/rewiring.py index 8a2dcad0350..6b6a37ddd16 100644 --- a/lib/spack/spack/rewiring.py +++ b/lib/spack/spack/rewiring.py @@ -70,7 +70,7 @@ def rewire_node(spec, explicit): for rel_path in manifest.get("text_to_relocate", []) ] if text_to_relocate: - relocate.relocate_text(files=text_to_relocate, prefixes=prefix_to_prefix) + relocate.unsafe_relocate_text(files=text_to_relocate, prefixes=prefix_to_prefix) bins_to_relocate = [ os.path.join(tempdir, spec.dag_hash(), rel_path) @@ -97,7 +97,7 @@ def rewire_node(spec, explicit): spec.build_spec.prefix, spec.prefix, ) - relocate.relocate_text_bin(binaries=bins_to_relocate, prefixes=prefix_to_prefix) + relocate.unsafe_relocate_text_bin(binaries=bins_to_relocate, prefixes=prefix_to_prefix) # Copy package into place, except for spec.json (because spec.json # describes the old spec and not the new spliced spec). shutil.copytree( diff --git a/lib/spack/spack/test/bindist.py b/lib/spack/spack/test/bindist.py index 7e9066ccbf8..d0a8a0a4f00 100644 --- a/lib/spack/spack/test/bindist.py +++ b/lib/spack/spack/test/bindist.py @@ -11,6 +11,8 @@ import py import pytest +from llnl.util.filesystem import visit_directory_tree + import spack.binary_distribution as bindist import spack.config import spack.hooks.sbang as sbang @@ -633,3 +635,47 @@ def test_FetchCacheError_pretty_printing_single(): assert "Multiple errors" not in str_e assert "RuntimeError: Oops!" in str_e assert str_e.rstrip() == str_e + + +def test_build_manifest_visitor(tmpdir): + dir = "directory" + file = os.path.join("directory", "file") + + with tmpdir.as_cwd(): + # Create a file inside a directory + os.mkdir(dir) + with open(file, "wb") as f: + f.write(b"example file") + + # Symlink the dir + os.symlink(dir, "symlink_to_directory") + + # Symlink the file + os.symlink(file, "symlink_to_file") + + # Hardlink the file + os.link(file, "hardlink_of_file") + + # Hardlinked symlinks: seems like this is only a thing on Linux, + # on Darwin the symlink *target* is hardlinked, on Linux the + # symlink *itself* is hardlinked. + if sys.platform.startswith("linux"): + os.link("symlink_to_file", "hardlink_of_symlink_to_file") + os.link("symlink_to_directory", "hardlink_of_symlink_to_directory") + + visitor = bindist.BuildManifestVisitor() + visit_directory_tree(str(tmpdir), visitor) + + # We de-dupe hardlinks of files, so there should really be just one file + assert len(visitor.files) == 1 + + # We do not de-dupe symlinks, cause it's unclear how to update symlinks + # in-place, preserving inodes. + if sys.platform.startswith("linux"): + assert len(visitor.symlinks) == 4 # includes hardlinks of symlinks. + else: + assert len(visitor.symlinks) == 2 + + with tmpdir.as_cwd(): + assert not any(os.path.islink(f) or os.path.isdir(f) for f in visitor.files) + assert all(os.path.islink(f) for f in visitor.symlinks) diff --git a/lib/spack/spack/test/packaging.py b/lib/spack/spack/test/packaging.py index f0d1c240e8e..0ed4f943a3a 100644 --- a/lib/spack/spack/test/packaging.py +++ b/lib/spack/spack/test/packaging.py @@ -36,7 +36,7 @@ needs_binary_relocation, needs_text_relocation, relocate_links, - relocate_text, + unsafe_relocate_text, ) from spack.spec import Spec @@ -190,7 +190,7 @@ def test_buildcache(mock_archive, tmpdir): @pytest.mark.usefixtures("install_mockery") -def test_relocate_text(tmpdir): +def test_unsafe_relocate_text(tmpdir): spec = Spec("trivial-install-test-package") spec.concretize() with tmpdir.as_cwd(): @@ -203,7 +203,7 @@ def test_relocate_text(tmpdir): filenames = [filename] new_dir = "/opt/rh/devtoolset/" # Singleton dict doesn't matter if Ordered - relocate_text(filenames, {old_dir: new_dir}) + unsafe_relocate_text(filenames, {old_dir: new_dir}) with open(filename, "r") as script: for line in script: assert new_dir in line diff --git a/lib/spack/spack/test/relocate.py b/lib/spack/spack/test/relocate.py index b79f0ba1a45..ab306759cde 100644 --- a/lib/spack/spack/test/relocate.py +++ b/lib/spack/spack/test/relocate.py @@ -406,7 +406,7 @@ def test_relocate_text_bin(hello_world, copy_binary, tmpdir): orig_path_bytes = str(orig_binary.dirpath()).encode("utf-8") new_path_bytes = str(new_binary.dirpath()).encode("utf-8") - spack.relocate.relocate_text_bin([str(new_binary)], {orig_path_bytes: new_path_bytes}) + spack.relocate.unsafe_relocate_text_bin([str(new_binary)], {orig_path_bytes: new_path_bytes}) # Check original directory is not there anymore and it was # substituted with the new one @@ -421,7 +421,7 @@ def test_relocate_text_bin_raise_if_new_prefix_is_longer(tmpdir): with open(fpath, "w") as f: f.write("/short") with pytest.raises(spack.relocate.BinaryTextReplaceError): - spack.relocate.relocate_text_bin([fpath], {short_prefix: long_prefix}) + spack.relocate.unsafe_relocate_text_bin([fpath], {short_prefix: long_prefix}) @pytest.mark.requires_executables("install_name_tool", "file", "cc") From 27921c38cecec5e02ad85360b881fd1991142456 Mon Sep 17 00:00:00 2001 From: Scott Wittenburg Date: Fri, 21 Oct 2022 10:35:20 -0600 Subject: [PATCH 140/442] gitlab: Retry protected publish jobs in certain cases (#32496) When we lose a running pod (possibly loss of spot instance) or encounter some other infrastructure-related failure of this job, we need to retry it. This retries the job the maximum number of times in those cases. --- share/spack/gitlab/cloud_pipelines/.gitlab-ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/share/spack/gitlab/cloud_pipelines/.gitlab-ci.yml b/share/spack/gitlab/cloud_pipelines/.gitlab-ci.yml index 17c16e16d67..8098d6f5feb 100644 --- a/share/spack/gitlab/cloud_pipelines/.gitlab-ci.yml +++ b/share/spack/gitlab/cloud_pipelines/.gitlab-ci.yml @@ -91,6 +91,9 @@ protected-publish: extends: [ ".protected" ] image: "ghcr.io/spack/python-aws-bash:0.0.1" tags: ["spack", "public", "medium", "aws", "x86_64"] + retry: + max: 2 + when: ["runner_system_failure", "stuck_or_timeout_failure"] variables: AWS_ACCESS_KEY_ID: ${PROTECTED_MIRRORS_AWS_ACCESS_KEY_ID} AWS_SECRET_ACCESS_KEY: ${PROTECTED_MIRRORS_AWS_SECRET_ACCESS_KEY} From 3c37bfb6d9f81e8119be54d45a9cb4cefd3913cc Mon Sep 17 00:00:00 2001 From: Luke Diorio-Toth Date: Fri, 21 Oct 2022 14:38:18 -0500 Subject: [PATCH 141/442] py-checkm-genome and py-pysam: bumped version and updated deps (#33449) * py-checkm-genome and py-pysam: bumped version and updated deps * updated setuptools dep type Co-authored-by: Adam J. Stewart Co-authored-by: Adam J. Stewart --- .../packages/py-checkm-genome/package.py | 22 +++++++++++++------ .../builtin/packages/py-pysam/package.py | 1 + 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/var/spack/repos/builtin/packages/py-checkm-genome/package.py b/var/spack/repos/builtin/packages/py-checkm-genome/package.py index f544f92f2ca..7d6d73d34e1 100644 --- a/var/spack/repos/builtin/packages/py-checkm-genome/package.py +++ b/var/spack/repos/builtin/packages/py-checkm-genome/package.py @@ -13,18 +13,26 @@ class PyCheckmGenome(PythonPackage): homepage = "https://ecogenomics.github.io/CheckM" pypi = "checkm-genome/checkm-genome-1.0.11.tar.gz" + version("1.2.1", sha256="33907aa7bbf029f8345e33df80d5c89b7a719041f55ece4f7470cd061c8eff76") version("1.0.13", sha256="ffb7e4966c0fac07c7e6e7db6f6eb5b48587fa83987f8a68efbaff2afb7da82e") version("1.0.11", sha256="e475d9817d12fa771dbccc80f47758b742fc67c25261dc8ca0c0dc898c2a5190") # pip silently replaces distutils with setuptools - depends_on("py-setuptools", type="build") + + depends_on("python@2.7.0:2.7", type=("build", "run"), when="@:1.0.18") + depends_on("python@3:", type=("build", "run"), when="@1.1.0:") + depends_on("py-setuptools", type=("build", "run")) depends_on("hmmer@3.1b1:", type=("build", "run")) depends_on("pplacer", type=("build", "run")) depends_on("prodigal@2.6.1:", type=("build", "run")) - depends_on("python@2.7.0:2.7", type=("build", "run")) depends_on("py-backports-functools-lru-cache", type=("build", "run"), when="^python@:3.2") - depends_on("py-numpy@1.8.0:", type=("build", "run")) - depends_on("py-scipy@0.9.0:", type=("build", "run")) - depends_on("py-matplotlib@1.3.1:2.2.3", type=("build", "run")) - depends_on("py-pysam@0.8.3:", type=("build", "run")) - depends_on("py-dendropy@4.0.0:", type=("build", "run")) + depends_on("py-numpy@1.8.0:", type=("build", "run"), when="@0.9.5:1.0.18") + depends_on("py-numpy@1.21.3:", type=("build", "run"), when="@1.2.0:") + depends_on("py-scipy@0.9.0:", type=("build", "run"), when="@0.9.5:1.0.18") + depends_on("py-scipy@1.7.3:", type=("build", "run"), when="@1.2.0") + depends_on("py-matplotlib@1.3.1:", type=("build", "run"), when="@0.9.5:1.0.18") + depends_on("py-matplotlib@3.5.1:", type=("build", "run"), when="@1.2.0:") + depends_on("py-pysam@0.8.3:", type=("build", "run"), when="@1.0.5:1.0.18") + depends_on("py-pysam@0.19.0:", type=("build", "run"), when="@1.2.0:") + depends_on("py-dendropy@4.0.0:", type=("build", "run"), when="@1.0.0:1.0.18") + depends_on("py-dendropy@4.5.2:", type=("build", "run"), when="@1.2.0:") diff --git a/var/spack/repos/builtin/packages/py-pysam/package.py b/var/spack/repos/builtin/packages/py-pysam/package.py index 4b91d188a35..f2df9eb37aa 100644 --- a/var/spack/repos/builtin/packages/py-pysam/package.py +++ b/var/spack/repos/builtin/packages/py-pysam/package.py @@ -13,6 +13,7 @@ class PyPysam(PythonPackage): homepage = "https://github.com/pysam-developers/pysam" pypi = "pysam/pysam-0.14.1.tar.gz" + version("0.19.1", sha256="dee403cbdf232170c1e11cc24c76e7dd748fc672ad38eb0414f3b9d569b1448f") version("0.18.0", sha256="1d6d49a0b3c626fae410a93d4c80583a8b5ddaacc9b46a080b250dbcebd30a59") version("0.15.3", sha256="a98dd0a164aa664b1ab30a36f653752f00e93c13deeb66868597f4b2a30f7265") version("0.15.2", sha256="d049efd91ed5b1af515aa30280bc9cb46a92ddd15d546c9b21ee68a6ed4055d9") From b1836a7c50c1e98808cf0820d1f0d855e9c201cf Mon Sep 17 00:00:00 2001 From: Luke Diorio-Toth Date: Fri, 21 Oct 2022 14:50:19 -0500 Subject: [PATCH 142/442] updated python version requirements (#33466) * updated python version requirements * updated sha256 Co-authored-by: Adam J. Stewart Co-authored-by: Adam J. Stewart --- .../repos/builtin/packages/py-biopython/package.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/var/spack/repos/builtin/packages/py-biopython/package.py b/var/spack/repos/builtin/packages/py-biopython/package.py index bf1c4803683..71f108068e2 100644 --- a/var/spack/repos/builtin/packages/py-biopython/package.py +++ b/var/spack/repos/builtin/packages/py-biopython/package.py @@ -10,18 +10,21 @@ class PyBiopython(PythonPackage): """A distributed collaborative effort to develop Python libraries and applications which address the needs of current and future work in bioinformatics. - """ homepage = "https://biopython.org/wiki/Main_Page" - url = "https://biopython.org/DIST/biopython-1.65.tar.gz" + pypi = "biopython/biopython-1.79.tar.gz" version("1.79", sha256="edb07eac99d3b8abd7ba56ff4bedec9263f76dfc3c3f450e7d2e2bcdecf8559b") version("1.78", sha256="1ee0a0b6c2376680fea6642d5080baa419fd73df104a62d58a8baf7a8bbe4564") version("1.73", sha256="70c5cc27dc61c23d18bb33b6d38d70edc4b926033aea3b7434737c731c94a5e0") version("1.70", sha256="4a7c5298f03d1a45523f32bae1fffcff323ea9dce007fb1241af092f5ab2e45b") - version("1.65", sha256="463cc81db84e9bfcdfb15629511c81ed556a6c0287e670dbfe80f03c65d2a88e") + version("1.65", sha256="6d591523ba4d07a505978f6e1d7fac57e335d6d62fb5b0bcb8c40bdde5c8998e") + depends_on("python@2.6:2.7,3.3:", type=("build", "run"), when="@1.63:1.68") + depends_on("python@2.7,3.3:", type=("build", "run"), when="@1.69") + depends_on("python@2.7,3.4:", type=("build", "run"), when="@1.70:1.74") + depends_on("python@2.7,3.5:", type=("build", "run"), when="@1.75:1.76") + depends_on("python@3.6:", type=("build", "run"), when="@1.77:") depends_on("py-numpy", type=("build", "run")) depends_on("py-setuptools", type="build") - depends_on("python@3.6:", type=("build", "run")) From 6fdb8b268247af7254ff45136e54cc7950b662b1 Mon Sep 17 00:00:00 2001 From: Luke Diorio-Toth Date: Fri, 21 Oct 2022 14:54:23 -0500 Subject: [PATCH 143/442] py-instrain: added required + optional dependency (#33465) * added py-instrain dependencies * fixed style * removed coverm dep until I have a working coverm package * added dep documentation --- var/spack/repos/builtin/packages/py-instrain/package.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/var/spack/repos/builtin/packages/py-instrain/package.py b/var/spack/repos/builtin/packages/py-instrain/package.py index 90887508fe0..962ee78f7a5 100644 --- a/var/spack/repos/builtin/packages/py-instrain/package.py +++ b/var/spack/repos/builtin/packages/py-instrain/package.py @@ -17,6 +17,8 @@ class PyInstrain(PythonPackage): homepage = "https://github.com/MrOlm/instrain" pypi = "inStrain/inStrain-1.5.7.tar.gz" + variant("prodigal", default=False, description="Enables profiling on a gene by gene level") + version("1.5.7", sha256="c5dcb01dae244927fe987b5f0695d895ccf521c9dfd87a2cb59057ad50bd9bfa") depends_on("python@3.4.0:", type=("build", "run")) @@ -35,3 +37,9 @@ class PyInstrain(PythonPackage): depends_on("py-psutil", type=("build", "run")) depends_on("py-lmfit", type=("build", "run")) depends_on("py-numba", type=("build", "run")) + # non-python dependencies + # https://instrain.readthedocs.io/en/latest/installation.html#dependencies + # Essential dependencies + depends_on("samtools", type=("build", "run")) + # Optional dependencies + depends_on("prodigal", type=("build", "run"), when="+prodigal") From ffbace0fbdd9a3d411ab7e819e77dac5974dd49d Mon Sep 17 00:00:00 2001 From: Jon Rood Date: Fri, 21 Oct 2022 14:50:05 -0600 Subject: [PATCH 144/442] openfast: Fix package file (#33454) * Fix openfast package file. * Fix openfast package file. * Fix typo. * [@spackbot] updating style on behalf of jrood-nrel Co-authored-by: jrood-nrel --- .../builtin/packages/openfast/package.py | 48 ++++++++++--------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/var/spack/repos/builtin/packages/openfast/package.py b/var/spack/repos/builtin/packages/openfast/package.py index c5d9086c61c..6da8c696e63 100644 --- a/var/spack/repos/builtin/packages/openfast/package.py +++ b/var/spack/repos/builtin/packages/openfast/package.py @@ -47,7 +47,7 @@ class Openfast(CMakePackage): depends_on("hdf5+mpi+cxx+hl", when="+cxx") depends_on("zlib", when="+cxx") depends_on("libxml2", when="+cxx") - depends_on("netcdf-c", when="+netcdf") + depends_on("netcdf-c", when="+cxx+netcdf") def cmake_args(self): spec = self.spec @@ -56,8 +56,8 @@ def cmake_args(self): options.extend( [ - define("BUILD_DOCUMENTATION", False), - define("BUILD_TESTING", False), + self.define("BUILD_DOCUMENTATION", False), + self.define("BUILD_TESTING", False), self.define_from_variant("BUILD_SHARED_LIBS", "shared"), self.define_from_variant("DOUBLE_PRECISION", "double-precision"), self.define_from_variant("USE_DLL_INTERFACE", "dll-interface"), @@ -70,42 +70,44 @@ def cmake_args(self): blas_libs = spec["lapack"].libs + spec["blas"].libs options.extend( [ - define("BLAS_LIBRARIES", blas_libs.joined(";")), - define("LAPACK_LIBRARIES", blas_libs.joined(";")), + self.define("BLAS_LIBRARIES", blas_libs.joined(";")), + self.define("LAPACK_LIBRARIES", blas_libs.joined(";")), ] ) if "+cxx" in spec: options.extend( [ - define("CMAKE_CXX_COMPILER", spec["mpi"].mpicxx), - define("CMAKE_C_COMPILER", spec["mpi"].mpicc), - define("CMAKE_Fortran_COMPILER", spec["mpi"].mpifc), - define("MPI_CXX_COMPILER", spec["mpi"].mpicxx), - define("MPI_C_COMPILER", spec["mpi"].mpicc), - define("MPI_Fortran_COMPILER", spec["mpi"].mpifc), - define("HDF5_ROOT", spec["hdf5"].prefix), - define("YAML_ROOT", spec["yaml"].prefix), - define("NETCDF_ROOT", spec["netcdf-c"].prefix), - # The following xpects that HDF5 was built with CMake. + self.define("CMAKE_CXX_COMPILER", spec["mpi"].mpicxx), + self.define("CMAKE_C_COMPILER", spec["mpi"].mpicc), + self.define("CMAKE_Fortran_COMPILER", spec["mpi"].mpifc), + self.define("MPI_CXX_COMPILER", spec["mpi"].mpicxx), + self.define("MPI_C_COMPILER", spec["mpi"].mpicc), + self.define("MPI_Fortran_COMPILER", spec["mpi"].mpifc), + self.define("HDF5_ROOT", spec["hdf5"].prefix), + self.define("YAML_ROOT", spec["yaml-cpp"].prefix), + # The following expects that HDF5 was built with CMake. # Solves issue with OpenFAST trying to link # to HDF5 libraries with a "-shared" prefix # that do not exist. - define("HDF5_NO_FIND_PACKAGE_CONFIG_FILE", True), + self.define("HDF5_NO_FIND_PACKAGE_CONFIG_FILE", True), ] ) - if "~shared" in spec: - options.extend( - [ - define("HDF5_USE_STATIC_LIBRARIES", True), - ] - ) + if "+netcdf" in spec: + options.extend([self.define("NETCDF_ROOT", spec["netcdf-c"].prefix)]) + + if "~shared" in spec: + options.extend( + [ + self.define("HDF5_USE_STATIC_LIBRARIES", True), + ] + ) if "+openmp" in spec: options.extend( [ - define("OPENMP", True), + self.define("OPENMP", True), ] ) From 9268b14f96f36b00d10ad5f1f6acd0ab83e06288 Mon Sep 17 00:00:00 2001 From: Alex Richert <82525672+AlexanderRichert-NOAA@users.noreply.github.com> Date: Fri, 21 Oct 2022 14:58:24 -0700 Subject: [PATCH 145/442] Update maintainers for NOAA/EMC-maintained libraries (#33469) * Update maintainers for NOAA/EMC-maintained libraries * Fix line lengths * Fix line length for gptl --- var/spack/repos/builtin/packages/bacio/package.py | 7 ++++++- var/spack/repos/builtin/packages/bufr/package.py | 8 +++++++- var/spack/repos/builtin/packages/crtm/package.py | 7 ++++++- var/spack/repos/builtin/packages/fms/package.py | 7 ++++++- var/spack/repos/builtin/packages/g2/package.py | 7 ++++++- var/spack/repos/builtin/packages/g2c/package.py | 6 +++++- var/spack/repos/builtin/packages/g2tmpl/package.py | 7 ++++++- var/spack/repos/builtin/packages/gfsio/package.py | 7 ++++++- var/spack/repos/builtin/packages/gptl/package.py | 2 +- var/spack/repos/builtin/packages/grib-util/package.py | 2 +- var/spack/repos/builtin/packages/ip/package.py | 7 ++++++- var/spack/repos/builtin/packages/ip2/package.py | 7 ++++++- var/spack/repos/builtin/packages/landsfcutil/package.py | 2 +- var/spack/repos/builtin/packages/ncio/package.py | 2 +- var/spack/repos/builtin/packages/nemsio/package.py | 7 ++++++- var/spack/repos/builtin/packages/nemsiogfs/package.py | 2 +- var/spack/repos/builtin/packages/prod-util/package.py | 2 +- var/spack/repos/builtin/packages/sfcio/package.py | 7 ++++++- var/spack/repos/builtin/packages/sigio/package.py | 7 ++++++- var/spack/repos/builtin/packages/sp/package.py | 7 ++++++- var/spack/repos/builtin/packages/ufs-utils/package.py | 7 ++++++- var/spack/repos/builtin/packages/upp/package.py | 2 +- var/spack/repos/builtin/packages/w3emc/package.py | 7 ++++++- var/spack/repos/builtin/packages/w3nco/package.py | 7 ++++++- var/spack/repos/builtin/packages/wgrib2/package.py | 7 ++++++- var/spack/repos/builtin/packages/wrf-io/package.py | 7 ++++++- 26 files changed, 121 insertions(+), 26 deletions(-) diff --git a/var/spack/repos/builtin/packages/bacio/package.py b/var/spack/repos/builtin/packages/bacio/package.py index 923c6139e53..013635cbeb9 100644 --- a/var/spack/repos/builtin/packages/bacio/package.py +++ b/var/spack/repos/builtin/packages/bacio/package.py @@ -14,7 +14,12 @@ class Bacio(CMakePackage): homepage = "https://noaa-emc.github.io/NCEPLIBS-bacio" url = "https://github.com/NOAA-EMC/NCEPLIBS-bacio/archive/refs/tags/v2.4.1.tar.gz" - maintainers = ["t-brown", "edwardhartnett", "kgerheiser", "Hang-Lei-NOAA"] + maintainers = [ + "t-brown", + "edwardhartnett", + "AlexanderRichert-NOAA", + "Hang-Lei-NOAA", + ] version("2.5.0", sha256="540a0ed73941d70dbf5d7b21d5d0a441e76fad2bfe37dfdfea0db3e98fc0fbfb") diff --git a/var/spack/repos/builtin/packages/bufr/package.py b/var/spack/repos/builtin/packages/bufr/package.py index 05c93508548..4376ac59fd4 100644 --- a/var/spack/repos/builtin/packages/bufr/package.py +++ b/var/spack/repos/builtin/packages/bufr/package.py @@ -17,7 +17,13 @@ class Bufr(CMakePackage): homepage = "https://noaa-emc.github.io/NCEPLIBS-bufr" url = "https://github.com/NOAA-EMC/NCEPLIBS-bufr/archive/refs/tags/bufr_v11.5.0.tar.gz" - maintainers = ["t-brown", "kgerheiser", "edwardhartnett", "Hang-Lei-NOAA", "jbathegit"] + maintainers = [ + "t-brown", + "AlexanderRichert-NOAA", + "edwardhartnett", + "Hang-Lei-NOAA", + "jbathegit", + ] version("11.5.0", sha256="d154839e29ef1fe82e58cf20232e9f8a4f0610f0e8b6a394b7ca052e58f97f43") diff --git a/var/spack/repos/builtin/packages/crtm/package.py b/var/spack/repos/builtin/packages/crtm/package.py index 92f5a6c08b6..7c36edb40e1 100644 --- a/var/spack/repos/builtin/packages/crtm/package.py +++ b/var/spack/repos/builtin/packages/crtm/package.py @@ -15,6 +15,11 @@ class Crtm(CMakePackage): homepage = "https://www.jcsda.org/jcsda-project-community-radiative-transfer-model" url = "https://github.com/NOAA-EMC/EMC_crtm/archive/refs/tags/v2.3.0.tar.gz" - maintainers = ["t-brown", "edwardhartnett", "kgerheiser", "Hang-Lei-NOAA"] + maintainers = [ + "t-brown", + "edwardhartnett", + "AlexanderRichert-NOAA", + "Hang-Lei-NOAA", + ] version("2.3.0", sha256="3e2c87ae5498c33dd98f9ede5c39e33ee7f298c7317b12adeb552e3a572700ce") diff --git a/var/spack/repos/builtin/packages/fms/package.py b/var/spack/repos/builtin/packages/fms/package.py index 5f82e39918e..6846c04d4b4 100644 --- a/var/spack/repos/builtin/packages/fms/package.py +++ b/var/spack/repos/builtin/packages/fms/package.py @@ -16,7 +16,12 @@ class Fms(CMakePackage): url = "https://github.com/NOAA-GFDL/FMS/archive/refs/tags/2022.02.tar.gz" git = "https://github.com/NOAA-GFDL/FMS.git" - maintainers = ["kgerheiser", "Hang-Lei-NOAA", "edwardhartnett", "rem1776"] + maintainers = [ + "AlexanderRichert-NOAA", + "Hang-Lei-NOAA", + "edwardhartnett", + "rem1776", + ] version("2022.03", sha256="42d2ac53d3c889a8177a6d7a132583364c0f6e5d5cbde0d980443b6797ad4838") version("2022.02", sha256="ad4978302b219e11b883b2f52519e1ee455137ad947474abb316c8654f72c874") diff --git a/var/spack/repos/builtin/packages/g2/package.py b/var/spack/repos/builtin/packages/g2/package.py index 821d3110412..7870a6b2533 100644 --- a/var/spack/repos/builtin/packages/g2/package.py +++ b/var/spack/repos/builtin/packages/g2/package.py @@ -16,7 +16,12 @@ class G2(CMakePackage): homepage = "https://noaa-emc.github.io/NCEPLIBS-g2" url = "https://github.com/NOAA-EMC/NCEPLIBS-g2/archive/refs/tags/v3.4.3.tar.gz" - maintainers = ["t-brown", "kgerheiser", "Hang-Lei-NOAA", "edwardhartnett"] + maintainers = [ + "t-brown", + "AlexanderRichert-NOAA", + "Hang-Lei-NOAA", + "edwardhartnett", + ] version("3.4.5", sha256="c18e991c56964953d778632e2d74da13c4e78da35e8d04cb742a2ca4f52737b6") version("3.4.3", sha256="679ea99b225f08b168cbf10f4b29f529b5b011232f298a5442ce037ea84de17c") diff --git a/var/spack/repos/builtin/packages/g2c/package.py b/var/spack/repos/builtin/packages/g2c/package.py index ddcb1414ee0..31f00a4059c 100644 --- a/var/spack/repos/builtin/packages/g2c/package.py +++ b/var/spack/repos/builtin/packages/g2c/package.py @@ -14,7 +14,11 @@ class G2c(CMakePackage): homepage = "https://github.com/NOAA-EMC/NCEPLIBS-g2c" url = "https://github.com/NOAA-EMC/NCEPLIBS-g2c/archive/refs/tags/v1.6.4.tar.gz" - maintainers = ["kgerheiser", "Hang-Lei-NOAA", "edwardhartnett"] + maintainers = [ + "AlexanderRichert-NOAA", + "Hang-Lei-NOAA", + "edwardhartnett", + ] variant("png", default=True) variant("jasper", default=True) diff --git a/var/spack/repos/builtin/packages/g2tmpl/package.py b/var/spack/repos/builtin/packages/g2tmpl/package.py index 36163acd437..d4a7d5d51c6 100644 --- a/var/spack/repos/builtin/packages/g2tmpl/package.py +++ b/var/spack/repos/builtin/packages/g2tmpl/package.py @@ -14,7 +14,12 @@ class G2tmpl(CMakePackage): homepage = "https://github.com/NOAA-EMC/NCEPLIBS-g2tmpl" url = "https://github.com/NOAA-EMC/NCEPLIBS-g2tmpl/archive/refs/tags/v1.10.0.tar.gz" - maintainers = ["t-brown", "edwardhartnett", "kgerheiser", "Hang-Lei-NOAA"] + maintainers = [ + "t-brown", + "edwardhartnett", + "AlexanderRichert-NOAA", + "Hang-Lei-NOAA", + ] version("1.10.2", sha256="4063361369f3691f75288c801fa9d1a2414908b7d6c07bbf69d4165802e2a7fc") version("1.10.1", sha256="0be425e5128fabb89915a92261aa75c27a46a3e115e00c686fc311321e5d1e2a") diff --git a/var/spack/repos/builtin/packages/gfsio/package.py b/var/spack/repos/builtin/packages/gfsio/package.py index 1c33e3eda25..bfff24a4eb8 100644 --- a/var/spack/repos/builtin/packages/gfsio/package.py +++ b/var/spack/repos/builtin/packages/gfsio/package.py @@ -15,7 +15,12 @@ class Gfsio(CMakePackage): homepage = "https://github.com/NOAA-EMC/NCEPLIBS-gfsio" url = "https://github.com/NOAA-EMC/NCEPLIBS-gfsio/archive/refs/tags/v1.4.1.tar.gz" - maintainers = ["t-brown", "kgerheiser", "Hang-Lei-NOAA", "edwardhartnett"] + maintainers = [ + "t-brown", + "AlexanderRichert-NOAA", + "Hang-Lei-NOAA", + "edwardhartnett", + ] version("1.4.1", sha256="eab106302f520600decc4f9665d7c6a55e7b4901fab6d9ef40f29702b89b69b1") diff --git a/var/spack/repos/builtin/packages/gptl/package.py b/var/spack/repos/builtin/packages/gptl/package.py index f4b69362879..5290d1bf78e 100644 --- a/var/spack/repos/builtin/packages/gptl/package.py +++ b/var/spack/repos/builtin/packages/gptl/package.py @@ -16,7 +16,7 @@ class Gptl(AutotoolsPackage): homepage = "https://jmrosinski.github.io/GPTL/" url = "https://github.com/jmrosinski/GPTL/releases/download/v8.0.3/gptl-8.0.3.tar.gz" - maintainers = ["edwardhartnett", "kgerheiser", "Hang-Lei-NOAA", " jmrosinski"] + maintainers = ["edwardhartnett", "AlexanderRichert-NOAA", "Hang-Lei-NOAA", "jmrosinski"] version("8.1.1", sha256="b8ee26f7aeedd2a31d565789634e7c380023fe6b65bbf59030884f4dcbce94a5") version("8.0.3", sha256="334979c6fe78d4ed1b491ec57fb61df7a910c58fd39a3658d03ad89f077a4db6") diff --git a/var/spack/repos/builtin/packages/grib-util/package.py b/var/spack/repos/builtin/packages/grib-util/package.py index d49556245e0..1e66d1940bc 100644 --- a/var/spack/repos/builtin/packages/grib-util/package.py +++ b/var/spack/repos/builtin/packages/grib-util/package.py @@ -14,7 +14,7 @@ class GribUtil(CMakePackage): homepage = "https://github.com/NOAA-EMC/NCEPLIBS-grib_util" url = "https://github.com/NOAA-EMC/NCEPLIBS-grib_util/archive/refs/tags/v1.2.3.tar.gz" - maintainers = ["kgerheiser", "Hang-Lei-NOAA", "edwardhartnett"] + maintainers = ["AlexanderRichert-NOAA", "Hang-Lei-NOAA", "edwardhartnett"] version("1.2.4", sha256="f021d6df3186890b0b1781616dabf953581d71db63e7c2913360336985ccaec7") version("1.2.3", sha256="b17b08e12360bb8ad01298e615f1b4198e304b0443b6db35fe990a817e648ad5") diff --git a/var/spack/repos/builtin/packages/ip/package.py b/var/spack/repos/builtin/packages/ip/package.py index 1b437ce3003..d7e89485a3d 100644 --- a/var/spack/repos/builtin/packages/ip/package.py +++ b/var/spack/repos/builtin/packages/ip/package.py @@ -14,7 +14,12 @@ class Ip(CMakePackage): homepage = "https://noaa-emc.github.io/NCEPLIBS-ip" url = "https://github.com/NOAA-EMC/NCEPLIBS-ip/archive/refs/tags/v3.3.3.tar.gz" - maintainers = ["t-brown", "kgerheiser", "edwardhartnett", "Hang-Lei-NOAA"] + maintainers = [ + "t-brown", + "AlexanderRichert-NOAA", + "edwardhartnett", + "Hang-Lei-NOAA", + ] version("4.0.0", sha256="a2ef0cc4e4012f9cb0389fab6097407f4c623eb49772d96eb80c44f804aa86b8") version( diff --git a/var/spack/repos/builtin/packages/ip2/package.py b/var/spack/repos/builtin/packages/ip2/package.py index ee68a7d1a33..7a654332665 100644 --- a/var/spack/repos/builtin/packages/ip2/package.py +++ b/var/spack/repos/builtin/packages/ip2/package.py @@ -17,7 +17,12 @@ class Ip2(CMakePackage): homepage = "https://github.com/NOAA-EMC/NCEPLIBS-ip2" url = "https://github.com/NOAA-EMC/NCEPLIBS-ip2/archive/refs/tags/v1.1.2.tar.gz" - maintainers = ["t-brown", "kgerheiser", "Hang-Lei-NOAA", "edwardhartnett"] + maintainers = [ + "t-brown", + "AlexanderRichert-NOAA", + "Hang-Lei-NOAA", + "edwardhartnett", + ] version("1.1.2", sha256="73c6beec8fd463ec7ccba3633d8c5d53d385c43d507367efde918c2db0af42ab") diff --git a/var/spack/repos/builtin/packages/landsfcutil/package.py b/var/spack/repos/builtin/packages/landsfcutil/package.py index ff3a9bf6bf5..6fc0229d4bf 100644 --- a/var/spack/repos/builtin/packages/landsfcutil/package.py +++ b/var/spack/repos/builtin/packages/landsfcutil/package.py @@ -15,7 +15,7 @@ class Landsfcutil(CMakePackage): homepage = "https://github.com/NOAA-EMC/NCEPLIBS-landsfcutil" url = "https://github.com/NOAA-EMC/NCEPLIBS-landsfcutil/archive/refs/tags/v2.4.1.tar.gz" - maintainers = ["edwardhartnett", "kgerheiser", "Hang-Lei-NOAA"] + maintainers = ["edwardhartnett", "AlexanderRichert-NOAA", "Hang-Lei-NOAA"] version("2.4.1", sha256="831c5005a480eabe9a8542b4deec838c2650f6966863ea2711cc0cc5db51ca14") diff --git a/var/spack/repos/builtin/packages/ncio/package.py b/var/spack/repos/builtin/packages/ncio/package.py index bd3d0c1ad3d..c392710813d 100644 --- a/var/spack/repos/builtin/packages/ncio/package.py +++ b/var/spack/repos/builtin/packages/ncio/package.py @@ -15,7 +15,7 @@ class Ncio(CMakePackage): homepage = "https://github.com/NOAA-EMC/NCEPLIBS-ncio" url = "https://github.com/NOAA-EMC/NCEPLIBS-ncio/archive/refs/tags/v1.0.0.tar.gz" - maintainers = ["edwardhartnett", "kgerheiser", "Hang-Lei-NOAA"] + maintainers = ["edwardhartnett", "AlexanderRichert-NOAA", "Hang-Lei-NOAA"] version("1.1.0", sha256="9de05cf3b8b1291010197737666cede3d621605806379b528d2146c4f02d08f6") version("1.0.0", sha256="2e2630b26513bf7b0665619c6c3475fe171a9d8b930e9242f5546ddf54749bd4") diff --git a/var/spack/repos/builtin/packages/nemsio/package.py b/var/spack/repos/builtin/packages/nemsio/package.py index 0f236795277..417521bef9c 100644 --- a/var/spack/repos/builtin/packages/nemsio/package.py +++ b/var/spack/repos/builtin/packages/nemsio/package.py @@ -16,7 +16,12 @@ class Nemsio(CMakePackage): homepage = "https://noaa-emc.github.io/NCEPLIBS-nemsio" url = "https://github.com/NOAA-EMC/NCEPLIBS-nemsio/archive/refs/tags/v2.5.2.tar.gz" - maintainers = ["t-brown", "edwardhartnett", "kgerheiser", "Hang-Lei-NOAA"] + maintainers = [ + "t-brown", + "edwardhartnett", + "AlexanderRichert-NOAA", + "Hang-Lei-NOAA", + ] variant("mpi", default=True, description="Build Nemsio with MPI") # Nemsio 2.5.3 and below require MPI diff --git a/var/spack/repos/builtin/packages/nemsiogfs/package.py b/var/spack/repos/builtin/packages/nemsiogfs/package.py index 85b1a128a19..8ce3792ea1c 100644 --- a/var/spack/repos/builtin/packages/nemsiogfs/package.py +++ b/var/spack/repos/builtin/packages/nemsiogfs/package.py @@ -15,7 +15,7 @@ class Nemsiogfs(CMakePackage): homepage = "https://github.com/NOAA-EMC/NCEPLIBS-nemsiogfs" url = "https://github.com/NOAA-EMC/NCEPLIBS-nemsiogfs/archive/refs/tags/v2.5.3.tar.gz" - maintainers = ["kgerheiser", "Hang-Lei-NOAA", "edwardhartnett"] + maintainers = ["AlexanderRichert-NOAA", "Hang-Lei-NOAA", "edwardhartnett"] version("2.5.3", sha256="bf84206b08c8779787bef33e4aba18404df05f8b2fdd20fc40b3af608ae4b9af") diff --git a/var/spack/repos/builtin/packages/prod-util/package.py b/var/spack/repos/builtin/packages/prod-util/package.py index cafad8a75f6..5129d5d0ca9 100644 --- a/var/spack/repos/builtin/packages/prod-util/package.py +++ b/var/spack/repos/builtin/packages/prod-util/package.py @@ -15,7 +15,7 @@ class ProdUtil(CMakePackage): homepage = "https://github.com/NOAA-EMC/NCEPLIBS-prod_util" url = "https://github.com/NOAA-EMC/NCEPLIBS-prod_util/archive/refs/tags/v1.2.2.tar.gz" - maintainers = ["kgerheiser", "Hang-Lei-NOAA", "edwardhartnett"] + maintainers = ["AlexanderRichert-NOAA", "Hang-Lei-NOAA", "edwardhartnett"] version("1.2.2", sha256="c51b903ea5a046cb9b545b5c04fd28647c58b4ab6182e61710f0287846350ef8") diff --git a/var/spack/repos/builtin/packages/sfcio/package.py b/var/spack/repos/builtin/packages/sfcio/package.py index 0a8dc94847a..8156e78e889 100644 --- a/var/spack/repos/builtin/packages/sfcio/package.py +++ b/var/spack/repos/builtin/packages/sfcio/package.py @@ -15,7 +15,12 @@ class Sfcio(CMakePackage): homepage = "https://noaa-emc.github.io/NCEPLIBS-sfcio" url = "https://github.com/NOAA-EMC/NCEPLIBS-sfcio/archive/refs/tags/v1.4.1.tar.gz" - maintainers = ["t-brown", "kgerheiser", "Hang-Lei-NOAA", "edwardhartnett"] + maintainers = [ + "t-brown", + "AlexanderRichert-NOAA", + "Hang-Lei-NOAA", + "edwardhartnett", + ] version("1.4.1", sha256="d9f900cf18ec1a839b4128c069b1336317ffc682086283443354896746b89c59") diff --git a/var/spack/repos/builtin/packages/sigio/package.py b/var/spack/repos/builtin/packages/sigio/package.py index 18cdf46f8f1..4ddad9f9539 100644 --- a/var/spack/repos/builtin/packages/sigio/package.py +++ b/var/spack/repos/builtin/packages/sigio/package.py @@ -15,7 +15,12 @@ class Sigio(CMakePackage): homepage = "https://noaa-emc.github.io/NCEPLIBS-sigio" url = "https://github.com/NOAA-EMC/NCEPLIBS-sigio/archive/refs/tags/v2.3.2.tar.gz" - maintainers = ["t-brown", "kgerheiser", "Hang-Lei-NOAA", "edwardhartnett"] + maintainers = [ + "t-brown", + "AlexanderRichert-NOAA", + "Hang-Lei-NOAA", + "edwardhartnett", + ] version("2.3.2", sha256="333f3cf3a97f97103cbafcafc2ad89b24faa55b1332a98adc1637855e8a5b613") diff --git a/var/spack/repos/builtin/packages/sp/package.py b/var/spack/repos/builtin/packages/sp/package.py index bfbce956c4a..a999eda820e 100644 --- a/var/spack/repos/builtin/packages/sp/package.py +++ b/var/spack/repos/builtin/packages/sp/package.py @@ -14,7 +14,12 @@ class Sp(CMakePackage): homepage = "https://noaa-emc.github.io/NCEPLIBS-sp" url = "https://github.com/NOAA-EMC/NCEPLIBS-sp/archive/refs/tags/v2.3.3.tar.gz" - maintainers = ["t-brown", "kgerheiser", "edwardhartnett", "Hang-Lei-NOAA"] + maintainers = [ + "t-brown", + "AlexanderRichert-NOAA", + "edwardhartnett", + "Hang-Lei-NOAA", + ] version("2.3.3", sha256="c0d465209e599de3c0193e65671e290e9f422f659f1da928505489a3edeab99f") diff --git a/var/spack/repos/builtin/packages/ufs-utils/package.py b/var/spack/repos/builtin/packages/ufs-utils/package.py index 75ec90944fe..2d893b05e54 100644 --- a/var/spack/repos/builtin/packages/ufs-utils/package.py +++ b/var/spack/repos/builtin/packages/ufs-utils/package.py @@ -15,7 +15,12 @@ class UfsUtils(CMakePackage): homepage = "https://noaa-emcufs-utils.readthedocs.io/en/latest/" url = "https://github.com/NOAA-EMC/UFS_UTILS/archive/refs/tags/ufs_utils_1_6_0.tar.gz" - maintainers = ["t-brown", "edwardhartnett", "kgerheiser", "Hang-Lei-NOAA"] + maintainers = [ + "t-brown", + "edwardhartnett", + "AlexanderRichert-NOAA", + "Hang-Lei-NOAA", + ] version("1_6_0", sha256="829ba4b50162e4202f96ec92a65b9fa824f71db65d2b63b70822db07d061cd92") diff --git a/var/spack/repos/builtin/packages/upp/package.py b/var/spack/repos/builtin/packages/upp/package.py index e339cbd5948..2f187a51e8d 100644 --- a/var/spack/repos/builtin/packages/upp/package.py +++ b/var/spack/repos/builtin/packages/upp/package.py @@ -17,7 +17,7 @@ class Upp(CMakePackage): git = "https://github.com/NOAA-EMC/UPP.git" url = "https://github.com/NOAA-EMC/UPP/archive/refs/tags/upp_v10.0.10.tar.gz" - maintainers = ["kgerheiser", "edwardhartnett", "Hang-Lei-NOAA"] + maintainers = ["AlexanderRichert-NOAA", "edwardhartnett", "Hang-Lei-NOAA"] version("10.0.10", sha256="0c96a88d0e79b554d5fcee9401efcf4d6273da01d15e3413845274f73d70b66e") version("10.0.9", tag="upp_v10.0.9", submodules=True) diff --git a/var/spack/repos/builtin/packages/w3emc/package.py b/var/spack/repos/builtin/packages/w3emc/package.py index ca6e14a795f..dc487f46031 100644 --- a/var/spack/repos/builtin/packages/w3emc/package.py +++ b/var/spack/repos/builtin/packages/w3emc/package.py @@ -15,7 +15,12 @@ class W3emc(CMakePackage): homepage = "https://noaa-emc.github.io/NCEPLIBS-w3emc/" url = "https://github.com/NOAA-EMC/NCEPLIBS-w3emc/archive/refs/tags/v2.9.0.tar.gz" - maintainers = ["t-brown", "kgerheiser", "Hang-Lei-NOAA", "edwardhartnett"] + maintainers = [ + "t-brown", + "AlexanderRichert-NOAA", + "Hang-Lei-NOAA", + "edwardhartnett", + ] version("2.9.2", sha256="eace811a1365f69b85fdf2bcd93a9d963ba72de5a7111e6fa7c0e6578b69bfbc") version("2.9.1", sha256="d3e705615bdd0b76a40751337d943d5a1ea415636f4e5368aed058f074b85df4") diff --git a/var/spack/repos/builtin/packages/w3nco/package.py b/var/spack/repos/builtin/packages/w3nco/package.py index ed736ab77d4..ef4b5510cc5 100644 --- a/var/spack/repos/builtin/packages/w3nco/package.py +++ b/var/spack/repos/builtin/packages/w3nco/package.py @@ -16,6 +16,11 @@ class W3nco(CMakePackage): homepage = "https://noaa-emc.github.io/NCEPLIBS/NCEPLIBS-w3nco/" url = "https://github.com/NOAA-EMC/NCEPLIBS-w3nco/archive/refs/tags/v2.4.1.tar.gz" - maintainers = ["t-brown", "kgerheiser", "Hang-Lei-NOAA", "edwardhartnett"] + maintainers = [ + "t-brown", + "AlexanderRichert-NOAA", + "Hang-Lei-NOAA", + "edwardhartnett", + ] version("2.4.1", sha256="48b06e0ea21d3d0fd5d5c4e7eb50b081402567c1bff6c4abf4fd4f3669070139") diff --git a/var/spack/repos/builtin/packages/wgrib2/package.py b/var/spack/repos/builtin/packages/wgrib2/package.py index 33b9ff37e6c..aa505e7c140 100644 --- a/var/spack/repos/builtin/packages/wgrib2/package.py +++ b/var/spack/repos/builtin/packages/wgrib2/package.py @@ -13,7 +13,12 @@ class Wgrib2(CMakePackage): homepage = "https://www.cpc.ncep.noaa.gov/products/wesley/wgrib2" url = "https://github.com/NOAA-EMC/NCEPLIBS-wgrib2/archive/refs/tags/v2.0.8-cmake-v6.tar.gz" - maintainers = ["t-brown", "kgerheiser", "Hang-Lei-NOAA", "edwardhartnett"] + maintainers = [ + "t-brown", + "AlexanderRichert-NOAA", + "Hang-Lei-NOAA", + "edwardhartnett", + ] version( "2.0.8-cmake-v6", sha256="745cd008b4ce0245ea44247733e57e2b9ec6c5205d171d457e18d0ff8f87172d" diff --git a/var/spack/repos/builtin/packages/wrf-io/package.py b/var/spack/repos/builtin/packages/wrf-io/package.py index 5dada9ff269..40c9713137c 100644 --- a/var/spack/repos/builtin/packages/wrf-io/package.py +++ b/var/spack/repos/builtin/packages/wrf-io/package.py @@ -16,7 +16,12 @@ class WrfIo(CMakePackage): homepage = "https://noaa-emc.github.io/NCEPLIBS-wrf_io" url = "https://github.com/NOAA-EMC/NCEPLIBS-wrf_io/archive/refs/tags/v1.2.0.tar.gz" - maintainers = ["t-brown", "kgerheiser", "Hang-Lei-NOAA", "edwardhartnett"] + maintainers = [ + "t-brown", + "AlexanderRichert-NOAA", + "Hang-Lei-NOAA", + "edwardhartnett", + ] version("1.2.0", sha256="000cf5294a2c68460085258186e1f36c86d3d0d9c433aa969a0f92736b745617") From 3fd097f1d536da23d8b9599755fae4385492e363 Mon Sep 17 00:00:00 2001 From: eugeneswalker <38933153+eugeneswalker@users.noreply.github.com> Date: Fri, 21 Oct 2022 14:58:58 -0700 Subject: [PATCH 146/442] raja@0.14.0 +rocm: add -std=c++14 to HIP_HIPCC_FLAGS (#33456) --- var/spack/repos/builtin/packages/raja/package.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/var/spack/repos/builtin/packages/raja/package.py b/var/spack/repos/builtin/packages/raja/package.py index d185eb31fc8..1f0bf93a675 100644 --- a/var/spack/repos/builtin/packages/raja/package.py +++ b/var/spack/repos/builtin/packages/raja/package.py @@ -133,12 +133,14 @@ def initconfig_hardware_entries(self): entries.append(cmake_cache_option("ENABLE_HIP", True)) entries.append(cmake_cache_path("HIP_ROOT_DIR", "{0}".format(spec["hip"].prefix))) hip_repair_cache(entries, spec) + hipcc_flags = [] + if self.spec.satisfies("@0.14.0"): + hipcc_flags.append("-std=c++14") archs = self.spec.variants["amdgpu_target"].value if archs != "none": arch_str = ",".join(archs) - entries.append( - cmake_cache_string("HIP_HIPCC_FLAGS", "--amdgpu-target={0}".format(arch_str)) - ) + hipcc_flags.append("--amdgpu-target={0}".format(arch_str)) + entries.append(cmake_cache_string("HIP_HIPCC_FLAGS", " ".join(hipcc_flags))) else: entries.append(cmake_cache_option("ENABLE_HIP", False)) From 773de54cd984ad06b9059d2b444887a8fc7ed90c Mon Sep 17 00:00:00 2001 From: Chris White Date: Fri, 21 Oct 2022 15:50:01 -0700 Subject: [PATCH 147/442] honor global spack flags (#33470) --- .../repos/builtin/packages/vtk-h/package.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/var/spack/repos/builtin/packages/vtk-h/package.py b/var/spack/repos/builtin/packages/vtk-h/package.py index c1c0b3ace3b..7671426434c 100644 --- a/var/spack/repos/builtin/packages/vtk-h/package.py +++ b/var/spack/repos/builtin/packages/vtk-h/package.py @@ -179,6 +179,23 @@ def hostconfig(self): cfg.write("# cpp compiler used by spack\n") cfg.write(cmake_cache_entry("CMAKE_CXX_COMPILER", cpp_compiler)) + # use global spack compiler flags + cppflags = " ".join(spec.compiler_flags["cppflags"]) + if cppflags: + # avoid always ending up with ' ' with no flags defined + cppflags += " " + cflags = cppflags + " ".join(spec.compiler_flags["cflags"]) + if cflags: + cfg.write(cmake_cache_entry("CMAKE_C_FLAGS", cflags)) + cxxflags = cppflags + " ".join(spec.compiler_flags["cxxflags"]) + if cxxflags: + cfg.write(cmake_cache_entry("CMAKE_CXX_FLAGS", cxxflags)) + fflags = " ".join(spec.compiler_flags["fflags"]) + if self.spec.satisfies("%cce"): + fflags += " -ef" + if fflags: + cfg.write(cmake_cache_entry("CMAKE_Fortran_FLAGS", fflags)) + # shared vs static libs if "+shared" in spec: cfg.write(cmake_cache_entry("BUILD_SHARED_LIBS", "ON")) From cff76fb23f3d4b0eb3f6c26ddb2aa8e32e75f729 Mon Sep 17 00:00:00 2001 From: Andrey Prokopenko Date: Sat, 22 Oct 2022 00:36:19 -0400 Subject: [PATCH 148/442] arborx: add new release 1.3 (#33402) * arborx: add new release 1.3 * [@spackbot] updating style on behalf of aprokop --- .../repos/builtin/packages/arborx/package.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/var/spack/repos/builtin/packages/arborx/package.py b/var/spack/repos/builtin/packages/arborx/package.py index cf9d0cc084f..9df147534e4 100644 --- a/var/spack/repos/builtin/packages/arborx/package.py +++ b/var/spack/repos/builtin/packages/arborx/package.py @@ -18,6 +18,7 @@ class Arborx(CMakePackage, CudaPackage, ROCmPackage): maintainers = ["aprokop"] version("master", branch="master") + version("1.3", sha256="3f1e17f029a460ab99f8396e2772cec908eefc4bf3868c8828907624a2d0ce5d") version("1.2", sha256="ed1939110b2330b7994dcbba649b100c241a2353ed2624e627a200a398096c20") version("1.1", sha256="2b5f2d2d5cec57c52f470c2bf4f42621b40271f870b4f80cb57e52df1acd90ce") version("1.0", sha256="9b5f45c8180622c907ef0b7cc27cb18ba272ac6558725d9e460c3f3e764f1075") @@ -27,6 +28,16 @@ class Arborx(CMakePackage, CudaPackage, ROCmPackage): deprecated=True, ) + # Allowed C++ standard + variant( + "cxxstd", + default="17", + values=("14", "17", "2a", "2b"), + multi=False, + description="Use the specified C++ standard when building.", + ) + conflicts("cxxstd=14", when="@1.3:") + # ArborX relies on Kokkos to provide devices, providing one-to-one matching # variants. The only way to disable those devices is to make sure Kokkos # does not provide them. @@ -49,7 +60,8 @@ class Arborx(CMakePackage, CudaPackage, ROCmPackage): # Standalone Kokkos depends_on("kokkos@3.1.00:", when="~trilinos") - depends_on("kokkos@3.4.00:", when="@1.2:~trilinos") + depends_on("kokkos@3.4.00:", when="@1.2~trilinos") + depends_on("kokkos@3.6.00:", when="@1.3:~trilinos") for backend in kokkos_backends: depends_on("kokkos+%s" % backend.lower(), when="~trilinos+%s" % backend.lower()) @@ -69,7 +81,8 @@ class Arborx(CMakePackage, CudaPackage, ROCmPackage): # - current version of Trilinos package does not allow enabling CUDA depends_on("trilinos+kokkos", when="+trilinos") depends_on("trilinos+openmp", when="+trilinos+openmp") - depends_on("trilinos@13.2.0:", when="@1.2:+trilinos") + depends_on("trilinos@13.2.0:", when="@1.2+trilinos") + depends_on("trilinos@13.4.0:", when="@1.3:+trilinos") conflicts("~serial", when="+trilinos") conflicts("+cuda", when="+trilinos") From 669bbe1e66cc8916d2db3f017ef2ab6fa696d1bb Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Sat, 22 Oct 2022 10:01:50 +0200 Subject: [PATCH 149/442] stop building binaries for the 1% (#33463) --- share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml | 2 +- share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml | 2 +- share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml index f389a0d14f0..fdda5188d22 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml @@ -16,7 +16,7 @@ spack: packages: all: compiler: [gcc@11.2.0] - target: [x86_64_v4] + target: [x86_64_v3] variants: ~cuda~rocm specs: diff --git a/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml index a65c68db095..45862560de1 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml @@ -16,7 +16,7 @@ spack: packages: all: compiler: [gcc@11.2.0] - target: [x86_64_v4] + target: [x86_64_v3] variants: ~rocm+cuda cuda_arch=80 llvm: # https://github.com/spack/spack/issues/27999 diff --git a/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml index d369924b8bf..9dadbe48526 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml @@ -16,7 +16,7 @@ spack: packages: all: compiler: [gcc@11.2.0] - target: [x86_64_v4] + target: [x86_64_v3] variants: ~cuda+rocm amdgpu_target=gfx90a gl: require: "osmesa" From 6d3869a7d3d300dfc98823fa3fb9e312358e9f11 Mon Sep 17 00:00:00 2001 From: Zack Galbreath Date: Sat, 22 Oct 2022 04:53:07 -0400 Subject: [PATCH 150/442] Remove x86_64_v4 target from AHUG and ISC stacks (#33464) --- share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml | 2 -- share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml | 1 - 2 files changed, 3 deletions(-) diff --git a/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml index c0cdef4448d..bc440a8950f 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml @@ -214,9 +214,7 @@ spack: - '%gcc@7.3.1' - target: - #- 'target=x86_64' - 'target=x86_64_v3' - - 'target=x86_64_v4' specs: diff --git a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml index 4c209022af9..cfc6778e1a6 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml @@ -129,7 +129,6 @@ spack: - target: - 'target=x86_64_v3' - - 'target=x86_64_v4' specs: From 5e2f2587670f9cd7a1cad99693359158784ff410 Mon Sep 17 00:00:00 2001 From: Wouter Deconinck Date: Sat, 22 Oct 2022 06:56:22 -0500 Subject: [PATCH 151/442] acts: new versions (#32969) * acts: new versions In the 20.x release line, these are the changes, https://github.com/acts-project/acts/compare/v20.0.0...v20.2.0 - `option(ACTS_SETUP_ACTSVG "Build ActSVG display plugin" OFF)` introduced in v20.1.0 - `option(ACTS_USE_SYSTEM_ACTSVG "Use the ActSVG system library" OFF)` introduced in v20.1.0 - `option(ACTS_BUILD_PLUGIN_ACTSVG "Build SVG display plugin" OFF)` introduced in v20.1.0 - `option(ACTS_USE_EXAMPLES_TBB "Use Threading Building Blocks library in examples" ON)` introduced in v20.1.0 - `option(ACTS_EXATRKX_ENABLE_ONNX "Build the Onnx backend for the exatrkx plugin" OFF)` introduced in v20.2.0 - `option(ACTS_EXATRKX_ENABLE_TORCH "Build the torchscript backend for the exatrkx plugin" ON)` introduced in v20.2.0 In the 19.x release line, these are the changes: https://github.com/acts-project/acts/compare/v19.7.0...v19.9.0 - `option(ACTS_USE_EXAMPLES_TBB "Use Threading Building Blocks library in examples" ON)` introduced in v19.8.0 The new build options have not been implemented in this commit but will be implemented next. * acts: new variant svg * actsvg: new package * actsvg: style fixes * acts: new versions 20.3.0 and 19.10.0 * astsvg: depends_on boost googletest * actsvg: new version 0.4.26 (and style fix) Includes fix to build issue when +examples, https://github.com/acts-project/actsvg/pull/23 * acts: new variant tbb when +examples @19.8:19 @20.1: * acts: set ACTS_USE_EXAMPLES_TBB * acts: no need for ACTS_SETUP_ACTSVG * acts: move tbb variant to examples block * acts: ACTS_USE_SYSTEM_ACTSDD4HEP removed in 20.3 * acts: use new ACTS_USE_SYSTEM_LIBS * acts-dd4hep: new version 1.0.1, maintainer handle fixed * acts: simplify variant tbb condition --- .../builtin/packages/acts-dd4hep/package.py | 3 +- .../repos/builtin/packages/acts/package.py | 67 +++++++++++++------ .../repos/builtin/packages/actsvg/package.py | 44 ++++++++++++ 3 files changed, 94 insertions(+), 20 deletions(-) create mode 100644 var/spack/repos/builtin/packages/actsvg/package.py diff --git a/var/spack/repos/builtin/packages/acts-dd4hep/package.py b/var/spack/repos/builtin/packages/acts-dd4hep/package.py index 3cc0431ce17..7b7f4405d8f 100644 --- a/var/spack/repos/builtin/packages/acts-dd4hep/package.py +++ b/var/spack/repos/builtin/packages/acts-dd4hep/package.py @@ -12,8 +12,9 @@ class ActsDd4hep(CMakePackage): homepage = "https://github.com/acts-project/acts-dd4hep" url = "https://github.com/acts-project/acts-dd4hep/archive/refs/tags/v1.0.0.tar.gz" - maintainers = ["HadrianG2", "wdconinc"] + maintainers = ["HadrienG2", "wdconinc"] + version("1.0.1", sha256="e40f34ebc30b3c33a6802c9d94136e65072d8dcee0b7db57a645f08a64ea5334") version("1.0.0", sha256="991f996944c88efa837880f919239e50d12c5c9361e220bc9422438dd608308c") depends_on("dd4hep@1.11: +dddetectors") diff --git a/var/spack/repos/builtin/packages/acts/package.py b/var/spack/repos/builtin/packages/acts/package.py index bb63510c3aa..af07f730708 100644 --- a/var/spack/repos/builtin/packages/acts/package.py +++ b/var/spack/repos/builtin/packages/acts/package.py @@ -39,7 +39,13 @@ class Acts(CMakePackage, CudaPackage): # Supported Acts versions version("main", branch="main") version("master", branch="main", deprecated=True) # For compatibility + version("20.3.0", commit="b1859b322744cb033328fd57d9e74fb5326aa56b", submodules=True) + version("20.2.0", commit="7750c1d24714314e8de716b92ebcd4a92cc4e303", submodules=True) + version("20.1.0", commit="be36226fb1be88d7be7c9b17a1c1f6e76ff0e006", submodules=True) version("20.0.0", commit="3740e6cdbfb1f75d8e481686acdfa5b16d3c41a3", submodules=True) + version("19.10.0", commit="2d07f60eb2280a46af1085600ec8327679bbb630", submodules=True) + version("19.9.0", commit="b655e18929ae0ccb6926d8e217b1b3fc02978d35", submodules=True) + version("19.8.0", commit="7582072dbaa70802264f20b392de4313afd25667", submodules=True) version("19.7.0", commit="03cf7a3ae74b632b3f89416dc27cc993c9ae4628", submodules=True) version("19.6.0", commit="333082914e6a51b381abc1cf52856829e3eb7890", submodules=True) version("19.5.0", commit="bf9f0270eadd8e78d283557b7c9070b80dece4a7", submodules=True) @@ -228,10 +234,23 @@ class Acts(CMakePackage, CudaPackage): description="Build python bindings for the examples", when="@14: +examples", ) + variant( + "svg", + default=False, + description="Build ActSVG display plugin", + when="@20.1:", + ) + variant( + "tbb", + default=True, + description="Build the examples with Threading Building Blocks library", + when="@19.8:19,20.1: +examples", + ) variant("analysis", default=False, description="Build analysis applications in the examples") # Build dependencies depends_on("acts-dd4hep", when="@19 +dd4hep") + depends_on("actsvg", when="@20.1: +svg") depends_on("autodiff @0.6:", when="@17: +autodiff") depends_on("autodiff @0.5.11:0.5.99", when="@1.2:16 +autodiff") depends_on("boost @1.62:1.69 +program_options +test", when="@:0.10.3") @@ -249,7 +268,7 @@ class Acts(CMakePackage, CudaPackage): depends_on("gperftools", when="+profilemem") depends_on("hepmc3 @3.2.1:", when="+hepmc3") depends_on("heppdt", when="+hepmc3 @:4.0") - depends_on("intel-tbb @2020.1:", when="+examples") + depends_on("intel-tbb @2020.1:", when="+examples +tbb") depends_on("nlohmann-json @3.9.1:", when="@0.14: +json") depends_on("pythia8", when="+pythia8") depends_on("python", when="+python") @@ -275,9 +294,9 @@ def enable_cmake_variant(cmake_label, spack_variant): enabled = spec.satisfies(spack_variant) return "-DACTS_ENABLE_{0}={1}".format(cmake_label, enabled) - def example_cmake_variant(cmake_label, spack_variant): + def example_cmake_variant(cmake_label, spack_variant, type="BUILD"): enabled = spec.satisfies("+examples +" + spack_variant) - return "-DACTS_BUILD_EXAMPLES_{0}={1}".format(cmake_label, enabled) + return "-DACTS_{0}_EXAMPLES_{1}={2}".format(type, cmake_label, enabled) def plugin_label(plugin_name): if spec.satisfies("@0.33:"): @@ -305,6 +324,7 @@ def plugin_cmake_variant(plugin_name, spack_variant): plugin_cmake_variant("CUDA", "cuda"), plugin_cmake_variant("DD4HEP", "dd4hep"), example_cmake_variant("DD4HEP", "dd4hep"), + plugin_cmake_variant("DIGITIZATION", "digitization"), example_cmake_variant("EDM4HEP", "edm4hep"), cmake_variant("EXAMPLES", "examples"), cmake_variant("FATRAS", "fatras"), @@ -321,8 +341,10 @@ def plugin_cmake_variant(plugin_name, spack_variant): enable_cmake_variant("MEMORY_PROFILING", "profilemem"), example_cmake_variant("PYTHIA8", "pythia8"), example_cmake_variant("PYTHON_BINDINGS", "python"), + plugin_cmake_variant("ACTSVG", "svg"), plugin_cmake_variant("SYCL", "sycl"), plugin_cmake_variant("TGEO", "tgeo"), + example_cmake_variant("TBB", "tbb", "USE"), cmake_variant(unit_tests_label, "unit_tests"), ] @@ -331,28 +353,35 @@ def plugin_cmake_variant(plugin_name, spack_variant): if spec.satisfies("@19.4.0:"): args.append("-DACTS_ENABLE_LOG_FAILURE_THRESHOLD=ON") - if spec.satisfies("+autodiff"): - args.append("-DACTS_USE_SYSTEM_AUTODIFF=ON") + # Use dependencies provided by spack + if spec.satisfies("@20.3:"): + args.append("-DACTS_USE_SYSTEM_LIBS=ON") + else: + if spec.satisfies("+autodiff"): + args.append("-DACTS_USE_SYSTEM_AUTODIFF=ON") + + if spec.satisfies("@19:20.2 +dd4hep"): + args.append("-DACTS_USE_SYSTEM_ACTSDD4HEP=ON") + + if spec.satisfies("@0.33: +json"): + args.append("-DACTS_USE_SYSTEM_NLOHMANN_JSON=ON") + elif spec.satisfies("@0.14.0:0.32 +json"): + args.append("-DACTS_USE_BUNDLED_NLOHMANN_JSON=OFF") + + if spec.satisfies("@18: +python"): + args.append("-DACTS_USE_SYSTEM_PYBIND11=ON") + + if spec.satisfies("@20.1: +svg"): + args.append("-DACTS_USE_SYSTEM_ACTSVG=ON") + + if spec.satisfies("@14: +vecmem"): + args.append("-DACTS_USE_SYSTEM_VECMEM=ON") if "+cuda" in spec: cuda_arch = spec.variants["cuda_arch"].value if cuda_arch != "none": args.append("-DCUDA_FLAGS=-arch=sm_{0}".format(cuda_arch[0])) - if spec.satisfies("@19 +dd4hep"): - args.append("-DACTS_USE_SYSTEM_ACTSDD4HEP=ON") - - if spec.satisfies("@:16"): - args.append(plugin_cmake_variant("DIGITIZATION", "digitization")) - - if spec.satisfies("@0.33: +json"): - args.append("-DACTS_USE_SYSTEM_NLOHMANN_JSON=ON") - elif spec.satisfies("@0.14.0: +json"): - args.append("-DACTS_USE_BUNDLED_NLOHMANN_JSON=OFF") - - if spec.satisfies("@18: +python"): - args.append("-DACTS_USE_SYSTEM_PYBIND11=ON") - if "root" in spec: cxxstd = spec["root"].variants["cxxstd"].value args.append("-DCMAKE_CXX_STANDARD={0}".format(cxxstd)) diff --git a/var/spack/repos/builtin/packages/actsvg/package.py b/var/spack/repos/builtin/packages/actsvg/package.py new file mode 100644 index 00000000000..bd2cc394d48 --- /dev/null +++ b/var/spack/repos/builtin/packages/actsvg/package.py @@ -0,0 +1,44 @@ +# 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 Actsvg(CMakePackage): + """An SVG based C++17 plotting library for ACTS detectors and + surfaces.""" + + homepage = "https://github.com/acts-project/actsvg" + url = "https://github.com/acts-project/actsvg/archive/refs/tags/v0.4.22.zip" + list_url = "https://github.com/acts-project/actsvg/releases" + git = "https://github.com/acts-project/actsvg.git" + + maintainers = ["HadrienG2", "wdconinc"] + + version("0.4.26", sha256="a1dfad15b616cac8191a355c1a87544571c36349400e3de56b9e5be6fa73714c") + + variant( + "examples", + default=False, + description="Build the example applications", + ) + variant( + "meta", + default=True, + description="Build the meta level interface", + ) + + depends_on("boost +program_options", type="test") + depends_on("boost +program_options", when="+examples") + depends_on("googletest", when="+examples") + + def cmake_args(self): + args = [ + self.define_from_variant("ACTSVG_BUILD_EXAMPLES", "examples"), + self.define_from_variant("ACTSVG_BUILD_META", "meta"), + self.define("ACTSVG_BUILD_TESTING", self.run_tests), + ] + return args From dc110db65d9ddbc903260185f8766ddf1123653a Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Sat, 22 Oct 2022 15:53:42 +0200 Subject: [PATCH 152/442] Don't install xdist in CI on Python 2.7 (#33474) --- .github/workflows/unit_tests.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/unit_tests.yaml b/.github/workflows/unit_tests.yaml index 29211ae2bbe..aef69fb60f2 100644 --- a/.github/workflows/unit_tests.yaml +++ b/.github/workflows/unit_tests.yaml @@ -52,7 +52,12 @@ jobs: patchelf cmake bison libbison-dev kcov - name: Install Python packages run: | - pip install --upgrade pip six setuptools pytest codecov[toml] pytest-cov pytest-xdist + pip install --upgrade pip six setuptools pytest codecov[toml] pytest-cov + # Install xdist only on recent Python, to avoid stalling on Python 2.7 due + # to bugs on an unmaintained version of the package. + if [[ ${{ matrix.python-version }} != "2.7" ]]; then + pip install --upgrade pytest-xdist + fi # ensure style checks are not skipped in unit tests for python >= 3.6 # note that true/false (i.e., 1/0) are opposite in conditions in python and bash if python -c 'import sys; sys.exit(not sys.version_info >= (3, 6))'; then From 8e2696172b4638239a56dad7fb22bc872a0e1356 Mon Sep 17 00:00:00 2001 From: eugeneswalker <38933153+eugeneswalker@users.noreply.github.com> Date: Sat, 22 Oct 2022 08:10:28 -0700 Subject: [PATCH 153/442] netlib-scalapack %cce: add -hnopattern to fflags (#33422) --- .../repos/builtin/packages/netlib-scalapack/package.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/var/spack/repos/builtin/packages/netlib-scalapack/package.py b/var/spack/repos/builtin/packages/netlib-scalapack/package.py index 6bf280a9be4..66c8ffe04ad 100644 --- a/var/spack/repos/builtin/packages/netlib-scalapack/package.py +++ b/var/spack/repos/builtin/packages/netlib-scalapack/package.py @@ -45,6 +45,13 @@ class ScalapackBase(CMakePackage): when="@2.2.0", ) + def flag_handler(self, name, flags): + iflags = [] + if name == "fflags": + if self.spec.satisfies("%cce"): + iflags.append("-hnopattern") + return (iflags, None, None) + @property def libs(self): # Note that the default will be to search From afc33518e642784326a5a40df2e29a38d6907e22 Mon Sep 17 00:00:00 2001 From: eugeneswalker <38933153+eugeneswalker@users.noreply.github.com> Date: Sat, 22 Oct 2022 17:53:52 -0700 Subject: [PATCH 154/442] openblas@0.3.21: fix misdetection of gfortran on cray (#33444) --- .../fix-cray-fortran-detection-pr3778.patch | 54 +++++++++++++++++++ .../builtin/packages/openblas/package.py | 3 ++ 2 files changed, 57 insertions(+) create mode 100644 var/spack/repos/builtin/packages/openblas/fix-cray-fortran-detection-pr3778.patch diff --git a/var/spack/repos/builtin/packages/openblas/fix-cray-fortran-detection-pr3778.patch b/var/spack/repos/builtin/packages/openblas/fix-cray-fortran-detection-pr3778.patch new file mode 100644 index 00000000000..0d87eafb8ec --- /dev/null +++ b/var/spack/repos/builtin/packages/openblas/fix-cray-fortran-detection-pr3778.patch @@ -0,0 +1,54 @@ +diff -ruN spack-src/f_check spack-src-patched/f_check +--- spack-src/f_check 2022-08-07 16:36:26.000000000 -0400 ++++ spack-src-patched/f_check 2022-10-20 15:06:34.296845220 -0400 +@@ -82,10 +82,6 @@ + vendor=FUJITSU + openmp='-Kopenmp' + ;; +- *Cray*) +- vendor=CRAY +- openmp='-fopenmp' +- ;; + *GNU*|*GCC*) + + v="${data#*GCC: *\) }" +@@ -117,6 +113,10 @@ + esac + fi + ;; ++ *Cray*) ++ vendor=CRAY ++ openmp='-fopenmp' ++ ;; + *g95*) + vendor=G95 + openmp='' +diff -ruN spack-src/f_check.pl spack-src-patched/f_check.pl +--- spack-src/f_check.pl 2022-08-07 16:36:26.000000000 -0400 ++++ spack-src-patched/f_check.pl 2022-10-20 15:07:50.884794505 -0400 +@@ -76,11 +76,6 @@ + $vendor = FUJITSU; + $openmp = "-Kopenmp"; + +- } elsif ($data =~ /Cray/) { +- +- $vendor = CRAY; +- $openmp = "-fopenmp"; +- + } elsif ($data =~ /GNU/ || $data =~ /GCC/ ) { + + $data =~ s/\(+.*?\)+//g; +@@ -106,8 +101,12 @@ + $openmp = ""; + } + } ++ } elsif ($data =~ /Cray/) { ++ ++ $vendor = CRAY; ++ $openmp = "-fopenmp"; + +- } ++ } + + if ($data =~ /g95/) { + $vendor = G95; diff --git a/var/spack/repos/builtin/packages/openblas/package.py b/var/spack/repos/builtin/packages/openblas/package.py index bfb6d3e7d50..0b8d7591f9d 100644 --- a/var/spack/repos/builtin/packages/openblas/package.py +++ b/var/spack/repos/builtin/packages/openblas/package.py @@ -89,6 +89,9 @@ class Openblas(MakefilePackage): # https://github.com/xianyi/OpenBLAS/pull/3712 patch("cce.patch", when="@0.3.20 %cce") + # https://github.com/xianyi/OpenBLAS/pull/3778 + patch("fix-cray-fortran-detection-pr3778.patch", when="@0.3.21") + # https://github.com/spack/spack/issues/31732 patch("f_check-oneapi.patch", when="@0.3.20 %oneapi") From 0bc596fc271243858a4af5ed6c432cf16d02d728 Mon Sep 17 00:00:00 2001 From: Michael Kuhn Date: Sun, 23 Oct 2022 03:53:51 +0200 Subject: [PATCH 155/442] zlib: add 1.2.13 (#33337) --- var/spack/repos/builtin/packages/zlib/package.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/zlib/package.py b/var/spack/repos/builtin/packages/zlib/package.py index 870629e569c..76add72552c 100644 --- a/var/spack/repos/builtin/packages/zlib/package.py +++ b/var/spack/repos/builtin/packages/zlib/package.py @@ -21,7 +21,12 @@ class Zlib(Package): # URL must remain http:// so Spack can bootstrap curl url = "https://zlib.net/fossils/zlib-1.2.11.tar.gz" - version("1.2.12", sha256="91844808532e5ce316b3c010929493c0244f3d37593afd6de04f71821d5136d9") + version("1.2.13", sha256="b3a24de97a8fdbc835b9833169501030b8977031bcb54b3b3ac13740f846ab30") + version( + "1.2.12", + sha256="91844808532e5ce316b3c010929493c0244f3d37593afd6de04f71821d5136d9", + deprecated=True, + ) version( "1.2.11", sha256="c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1", From 3256688f20c0d3c028453ed5d18c333235762185 Mon Sep 17 00:00:00 2001 From: Michael Kuhn Date: Sun, 23 Oct 2022 05:57:57 +0200 Subject: [PATCH 156/442] python: add 3.10.8, 3.9.15, 3.8.15, 3.7.15 (#33340) Co-authored-by: Harmen Stoppels --- var/spack/repos/builtin/packages/python/package.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/var/spack/repos/builtin/packages/python/package.py b/var/spack/repos/builtin/packages/python/package.py index 32c3429c432..8a69efbbda4 100644 --- a/var/spack/repos/builtin/packages/python/package.py +++ b/var/spack/repos/builtin/packages/python/package.py @@ -44,6 +44,7 @@ class Python(Package): install_targets = ["install"] build_targets = [] # type: List[str] + version("3.10.8", sha256="f400c3fb394b8bef1292f6dc1292c5fadc3533039a5bc0c3e885f3e16738029a") version("3.10.7", sha256="1b2e4e2df697c52d36731666979e648beeda5941d0f95740aafbf4163e5cc126") version("3.10.6", sha256="848cb06a5caa85da5c45bd7a9221bb821e33fc2bdcba088c127c58fad44e6343") version("3.10.5", sha256="18f57182a2de3b0be76dfc39fdcfd28156bb6dd23e5f08696f7492e9e3d0bf2d") @@ -53,10 +54,11 @@ class Python(Package): version("3.10.1", sha256="b76117670e7c5064344b9c138e141a377e686b9063f3a8a620ff674fa8ec90d3") version("3.10.0", sha256="c4e0cbad57c90690cb813fb4663ef670b4d0f587d8171e2c42bd4c9245bd2758") version( - "3.9.14", - sha256="9201836e2c16361b2b7408680502393737d44f227333fe2e5729c7d5f6041675", + "3.9.15", + sha256="48d1ccb29d5fbaf1fb8f912271d09f7450e426d4dfe95978ef6aaada70ece4d8", preferred=True, ) + version("3.9.14", sha256="9201836e2c16361b2b7408680502393737d44f227333fe2e5729c7d5f6041675") version("3.9.13", sha256="829b0d26072a44689a6b0810f5b4a3933ee2a0b8a4bfc99d7c5893ffd4f97c44") version("3.9.12", sha256="70e08462ebf265012bd2be88a63d2149d880c73e53f1712b7bbbe93750560ae8") version("3.9.11", sha256="3442400072f582ac2f0df30895558f08883b416c8c7877ea55d40d00d8a93112") @@ -71,6 +73,7 @@ class Python(Package): version("3.9.2", sha256="7899e8a6f7946748830d66739f2d8f2b30214dad956e56b9ba216b3de5581519") version("3.9.1", sha256="29cb91ba038346da0bd9ab84a0a55a845d872c341a4da6879f462e94c741f117") version("3.9.0", sha256="df796b2dc8ef085edae2597a41c1c0a63625ebd92487adaef2fed22b567873e8") + version("3.8.15", sha256="924d46999df82aa2eaa1de5ca51d6800ffb56b4bf52486a28f40634e3362abc4") version("3.8.14", sha256="41f959c480c59211feb55d5a28851a56c7e22d02ef91035606ebb21011723c31") version("3.8.13", sha256="903b92d76354366b1d9c4434d0c81643345cef87c1600adfa36095d7b00eede4") version("3.8.12", sha256="316aa33f3b7707d041e73f246efedb297a70898c4b91f127f66dc8d80c596f1a") @@ -86,6 +89,7 @@ class Python(Package): version("3.8.2", sha256="e634a7a74776c2b89516b2e013dda1728c89c8149b9863b8cea21946daf9d561") version("3.8.1", sha256="c7cfa39a43b994621b245e029769e9126caa2a93571cee2e743b213cceac35fb") version("3.8.0", sha256="f1069ad3cae8e7ec467aa98a6565a62a48ef196cb8f1455a245a08db5e1792df") + version("3.7.15", sha256="cf2993798ae8430f3af3a00d96d9fdf320719f4042f039380dca79967c25e436") version("3.7.14", sha256="82b2abf8978caa61a9011d166eede831b32de9cbebc0db8162900fa23437b709") version("3.7.13", sha256="e405417f50984bc5870c7e7a9f9aeb93e9d270f5ac67f667a0cd3a09439682b5") version("3.7.12", sha256="33b4daaf831be19219659466d12645f87ecec6eb21d4d9f9711018a7b66cce46") From d4a7ea8eb0ddbcbe19b52f2b909d529282a80cda Mon Sep 17 00:00:00 2001 From: Michael Kuhn Date: Sun, 23 Oct 2022 08:49:53 +0200 Subject: [PATCH 157/442] util-linux, util-linux-uuid: add 2.38.1 (#33342) --- var/spack/repos/builtin/packages/util-linux-uuid/package.py | 3 ++- var/spack/repos/builtin/packages/util-linux/package.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/util-linux-uuid/package.py b/var/spack/repos/builtin/packages/util-linux-uuid/package.py index c9a1c5de96c..ef621f9e834 100644 --- a/var/spack/repos/builtin/packages/util-linux-uuid/package.py +++ b/var/spack/repos/builtin/packages/util-linux-uuid/package.py @@ -9,11 +9,12 @@ class UtilLinuxUuid(AutotoolsPackage): """Util-linux is a suite of essential utilities for any Linux system.""" - homepage = "https://github.com/karelzak/util-linux" + homepage = "https://github.com/util-linux/util-linux" url = "https://www.kernel.org/pub/linux/utils/util-linux/v2.29/util-linux-2.29.2.tar.gz" list_url = "https://www.kernel.org/pub/linux/utils/util-linux" list_depth = 1 + version("2.38.1", sha256="0820eb8eea90408047e3715424bc6be771417047f683950fecb4bdd2e2cbbc6e") version("2.37.4", sha256="c8b7b4fa541f974cc32c1c6559d9bfca33651020a456ad6ee5fc9b0cacd00151") version("2.36.2", sha256="f5dbe79057e7d68e1a46fc04083fc558b26a49499b1b3f50e4f4893150970463") version("2.36", sha256="82942cd877a989f6d12d4ce2c757fb67ec53d8c5cd9af0537141ec5f84a2eea3") diff --git a/var/spack/repos/builtin/packages/util-linux/package.py b/var/spack/repos/builtin/packages/util-linux/package.py index fa2b1ff2c9f..bc703913292 100644 --- a/var/spack/repos/builtin/packages/util-linux/package.py +++ b/var/spack/repos/builtin/packages/util-linux/package.py @@ -16,6 +16,7 @@ class UtilLinux(AutotoolsPackage): list_url = "https://www.kernel.org/pub/linux/utils/util-linux" list_depth = 1 + version("2.38.1", sha256="0820eb8eea90408047e3715424bc6be771417047f683950fecb4bdd2e2cbbc6e") version("2.38", sha256="c31d4e54f30b56b0f7ec8b342658c07de81378f2c067941c2b886da356f8ad42") version("2.37.4", sha256="c8b7b4fa541f974cc32c1c6559d9bfca33651020a456ad6ee5fc9b0cacd00151") version("2.37.2", sha256="15db966474e459b33fa390a6b892190a92079a73ca45384cde4c86e6ed265a86") From e00208c566549b7c3bc927956670e8f868c6866b Mon Sep 17 00:00:00 2001 From: Michael Kuhn Date: Sun, 23 Oct 2022 09:33:54 +0200 Subject: [PATCH 158/442] gettext: add 0.21.1 (#33333) --- var/spack/repos/builtin/packages/gettext/package.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/var/spack/repos/builtin/packages/gettext/package.py b/var/spack/repos/builtin/packages/gettext/package.py index 27c93cc50dd..c633a5b51f1 100644 --- a/var/spack/repos/builtin/packages/gettext/package.py +++ b/var/spack/repos/builtin/packages/gettext/package.py @@ -14,8 +14,11 @@ class Gettext(AutotoolsPackage, GNUMirrorPackage): homepage = "https://www.gnu.org/software/gettext/" gnu_mirror_path = "gettext/gettext-0.20.1.tar.xz" + maintainers = ["michaelkuhn"] + executables = [r"^gettext$"] + version("0.21.1", sha256="50dbc8f39797950aa2c98e939947c527e5ac9ebd2c1b99dd7b06ba33a6767ae6") version("0.21", sha256="d20fcbb537e02dcf1383197ba05bd0734ef7bf5db06bdb241eb69b7d16b73192") version("0.20.2", sha256="b22b818e644c37f6e3d1643a1943c32c3a9bff726d601e53047d2682019ceaba") version("0.20.1", sha256="53f02fbbec9e798b0faaf7c73272f83608e835c6288dd58be6c9bb54624a3800") From efa6acae864750fa98299b8ef07ea120dc9ef4f1 Mon Sep 17 00:00:00 2001 From: Michael Kuhn Date: Sun, 23 Oct 2022 12:45:46 +0200 Subject: [PATCH 159/442] sqlite: add 3.39.4 (#33339) --- var/spack/repos/builtin/packages/sqlite/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/sqlite/package.py b/var/spack/repos/builtin/packages/sqlite/package.py index 5b562955827..7e22fc3aae9 100644 --- a/var/spack/repos/builtin/packages/sqlite/package.py +++ b/var/spack/repos/builtin/packages/sqlite/package.py @@ -17,6 +17,7 @@ class Sqlite(AutotoolsPackage): homepage = "https://www.sqlite.org" + version("3.39.4", sha256="f31d445b48e67e284cf206717cc170ab63cbe4fd7f79a82793b772285e78fdbb") version("3.39.2", sha256="852be8a6183a17ba47cee0bbff7400b7aa5affd283bf3beefc34fcd088a239de") version("3.38.5", sha256="5af07de982ba658fd91a03170c945f99c971f6955bc79df3266544373e39869c") version("3.38.3", sha256="61f2dd93a2e38c33468b7125967c3218bf9f4dd8365def6025e314f905dc942e") From 6e0d06c104d3f76a4514a2628d0a515f6f97b01f Mon Sep 17 00:00:00 2001 From: HELICS-bot <45982316+HELICS-bot@users.noreply.github.com> Date: Sun, 23 Oct 2022 04:05:54 -0700 Subject: [PATCH 160/442] helics: Add version 3.3.1 (#33475) --- var/spack/repos/builtin/packages/helics/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/helics/package.py b/var/spack/repos/builtin/packages/helics/package.py index 1a4f24e6ea6..04e0bd05799 100644 --- a/var/spack/repos/builtin/packages/helics/package.py +++ b/var/spack/repos/builtin/packages/helics/package.py @@ -21,6 +21,7 @@ class Helics(CMakePackage): version("develop", branch="develop", submodules=True) version("main", branch="main", submodules=True) version("master", branch="main", submodules=True) + version("3.3.1", sha256="0f6357e6781157515230d14033afc8769a02971a1870909e5697415e1db2e03f") version("3.3.0", sha256="0c2fe0eb2bfc527901a50bbdaa742a7c4b9424dc8fa326ca614157613dcd1457") version("3.2.1", sha256="9df8a7a687c7cf8ea6f157e748e57e8bf5cefa9a49a24e7c590fe9191291da95") version("3.2.0", sha256="b9cec50b9e767113b2e04a5623437885f76196cc9a58287e21f5c0f62c32cca1") From f8a899f904f31d0a8ae6af1faca8223974330c4d Mon Sep 17 00:00:00 2001 From: Michael Kuhn Date: Sun, 23 Oct 2022 13:44:36 +0200 Subject: [PATCH 161/442] ca-certificates-mozilla: add 2022-10-11 (#33331) --- .../builtin/packages/ca-certificates-mozilla/package.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/var/spack/repos/builtin/packages/ca-certificates-mozilla/package.py b/var/spack/repos/builtin/packages/ca-certificates-mozilla/package.py index f1a39062288..50862817d0b 100644 --- a/var/spack/repos/builtin/packages/ca-certificates-mozilla/package.py +++ b/var/spack/repos/builtin/packages/ca-certificates-mozilla/package.py @@ -14,6 +14,11 @@ class CaCertificatesMozilla(Package): maintainers = ["haampie"] + version( + "2022-10-11", + sha256="2cff03f9efdaf52626bd1b451d700605dc1ea000c5da56bd0fc59f8f43071040", + expand=False, + ) version( "2022-07-19", sha256="6ed95025fba2aef0ce7b647607225745624497f876d74ef6ec22b26e73e9de77", From 6c32c6fbdba52109de9f112dfe785c66b7d114e8 Mon Sep 17 00:00:00 2001 From: Michael Kuhn Date: Sun, 23 Oct 2022 15:49:57 +0200 Subject: [PATCH 162/442] py-gcovr: add 5.2 (#33476) --- var/spack/repos/builtin/packages/py-gcovr/package.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/var/spack/repos/builtin/packages/py-gcovr/package.py b/var/spack/repos/builtin/packages/py-gcovr/package.py index 5fb58361d32..9a807854572 100644 --- a/var/spack/repos/builtin/packages/py-gcovr/package.py +++ b/var/spack/repos/builtin/packages/py-gcovr/package.py @@ -15,9 +15,14 @@ class PyGcovr(PythonPackage): homepage = "https://gcovr.com/" pypi = "gcovr/gcovr-4.2.tar.gz" + version("5.2", sha256="217195085ec94346291a87b7b1e6d9cfdeeee562b3e0f9a32b25c9530b3bce8f") version("4.2", sha256="5aae34dc81e51600cfecbbbce3c3a80ce3f7548bc0aa1faa4b74ecd18f6fca3f") - depends_on("python@2.7:,3.5:", type=("build", "run")) + depends_on("python@3.7:", when="@5.1:", type=("build", "run")) + depends_on("python@3.6:", when="@5.0", type=("build", "run")) + depends_on("python@2.7:2,3.5:", when="@:4", type=("build", "run")) + depends_on("py-setuptools", type=("build", "run")) + depends_on("py-jinja2", type=("build", "run")) depends_on("py-lxml", type=("build", "run")) - depends_on("py-setuptools", type=("build", "run")) + depends_on("py-pygments", when="@5:", type=("build", "run")) From 7d99fbcafd4720babe2a0d325df099ed9056f5e1 Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Mon, 24 Oct 2022 03:12:38 +0200 Subject: [PATCH 163/442] backtraces with --backtrace (#33478) * backtraces without --debug Currently `--debug` is too verbose and not-`--debug` gives to little context about where exceptions are coming from. So, instead, it'd be nice to have `spack --backtrace` and `SPACK_BACKTRACE=1` as methods to get something inbetween: no verbose debug messages, but always a full backtrace. This is useful for CI, where we don't want to drown in debug messages when installing deps, but we do want to get details where something goes wrong if it goes wrong. * completion --- lib/spack/spack/main.py | 10 +++++++++- share/spack/spack-completion.bash | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/spack/spack/main.py b/lib/spack/spack/main.py index 7e84be57810..998d0e20225 100644 --- a/lib/spack/spack/main.py +++ b/lib/spack/spack/main.py @@ -527,6 +527,12 @@ def make_argument_parser(**kwargs): default="SPACK_STACKTRACE" in os.environ, help="add stacktraces to all printed statements", ) + parser.add_argument( + "--backtrace", + action="store_true", + default="SPACK_BACKTRACE" in os.environ, + help="always show backtraces for exceptions", + ) parser.add_argument( "-V", "--version", action="store_true", help="show version number and exit" ) @@ -561,8 +567,10 @@ def setup_main_options(args): # debug must be set first so that it can even affect behavior of # errors raised by spack.config. + if args.debug or args.backtrace: + spack.error.debug = True + if args.debug: - spack.error.debug = args.debug spack.util.debug.register_interrupt_handler() spack.config.set("config:debug", True, scope="command_line") spack.util.environment.tracing_enabled = True diff --git a/share/spack/spack-completion.bash b/share/spack/spack-completion.bash index 819b131bca1..dac7f67f997 100755 --- a/share/spack/spack-completion.bash +++ b/share/spack/spack-completion.bash @@ -335,7 +335,7 @@ _spacktivate() { _spack() { if $list_options then - SPACK_COMPREPLY="-h --help -H --all-help --color -c --config -C --config-scope -d --debug --timestamp --pdb -e --env -D --env-dir -E --no-env --use-env-repo -k --insecure -l --enable-locks -L --disable-locks -m --mock -b --bootstrap -p --profile --sorted-profile --lines -v --verbose --stacktrace -V --version --print-shell-vars" + SPACK_COMPREPLY="-h --help -H --all-help --color -c --config -C --config-scope -d --debug --timestamp --pdb -e --env -D --env-dir -E --no-env --use-env-repo -k --insecure -l --enable-locks -L --disable-locks -m --mock -b --bootstrap -p --profile --sorted-profile --lines -v --verbose --stacktrace --backtrace -V --version --print-shell-vars" else SPACK_COMPREPLY="activate add arch audit blame bootstrap build-env buildcache cd change checksum ci clean clone commands compiler compilers concretize config containerize create deactivate debug dependencies dependents deprecate dev-build develop diff docs edit env extensions external fetch find gc gpg graph help info install license list load location log-parse maintainers make-installer mark mirror module patch pkg providers pydoc python reindex remove rm repo resource restage solve spec stage style tags test test-env tutorial undevelop uninstall unit-test unload url verify versions view" fi From d67b12eb7934637f119ed7ad6f80f3d5f574895b Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Mon, 24 Oct 2022 11:54:49 +0200 Subject: [PATCH 164/442] locks: improved errors (#33477) Instead of showing ``` ==> Error: Timed out waiting for a write lock. ``` show ``` ==> Error: Timed out waiting for a write lock after 1.200ms and 4 attempts on file: /some/file ``` s.t. we actually get to see where acquiring a lock failed even when not running in debug mode. And use pretty time units everywhere, so we don't get 1.45e-9 seconds but 1.450ns etc. --- lib/spack/llnl/util/lang.py | 20 ++++++++++++++++++++ lib/spack/llnl/util/lock.py | 22 ++++++++++++++++++---- lib/spack/spack/installer.py | 11 ++++++++--- lib/spack/spack/test/database.py | 2 +- lib/spack/spack/test/llnl/util/lang.py | 14 +++++++++++--- lib/spack/spack/test/llnl/util/lock.py | 2 +- 6 files changed, 59 insertions(+), 12 deletions(-) diff --git a/lib/spack/llnl/util/lang.py b/lib/spack/llnl/util/lang.py index 76b161cbbe1..f1a0b7ba313 100644 --- a/lib/spack/llnl/util/lang.py +++ b/lib/spack/llnl/util/lang.py @@ -749,6 +749,26 @@ def _n_xxx_ago(x): raise ValueError(msg) +def pretty_seconds(seconds): + """Seconds to string with appropriate units + + Arguments: + seconds (float): Number of seconds + + Returns: + str: Time string with units + """ + if seconds >= 1: + value, unit = seconds, "s" + elif seconds >= 1e-3: + value, unit = seconds * 1e3, "ms" + elif seconds >= 1e-6: + value, unit = seconds * 1e6, "us" + else: + value, unit = seconds * 1e9, "ns" + return "%.3f%s" % (value, unit) + + class RequiredAttributeError(ValueError): def __init__(self, message): super(RequiredAttributeError, self).__init__(message) diff --git a/lib/spack/llnl/util/lock.py b/lib/spack/llnl/util/lock.py index 6dfba50abb4..9c3bcd7a918 100644 --- a/lib/spack/llnl/util/lock.py +++ b/lib/spack/llnl/util/lock.py @@ -12,6 +12,7 @@ from typing import Dict, Tuple # novm import llnl.util.tty as tty +from llnl.util.lang import pretty_seconds import spack.util.string @@ -166,7 +167,7 @@ def _attempts_str(wait_time, nattempts): return "" attempts = spack.util.string.plural(nattempts, "attempt") - return " after {0:0.2f}s and {1}".format(wait_time, attempts) + return " after {} and {}".format(pretty_seconds(wait_time), attempts) class LockType(object): @@ -318,8 +319,8 @@ def _lock(self, op, timeout=None): raise LockROFileError(self.path) self._log_debug( - "{0} locking [{1}:{2}]: timeout {3} sec".format( - op_str.lower(), self._start, self._length, timeout + "{} locking [{}:{}]: timeout {}".format( + op_str.lower(), self._start, self._length, pretty_seconds(timeout or 0) ) ) @@ -340,7 +341,8 @@ def _lock(self, op, timeout=None): total_wait_time = time.time() - start_time return total_wait_time, num_attempts - raise LockTimeoutError("Timed out waiting for a {0} lock.".format(op_str.lower())) + total_wait_time = time.time() - start_time + raise LockTimeoutError(op_str.lower(), self.path, total_wait_time, num_attempts) def _poll_lock(self, op): """Attempt to acquire the lock in a non-blocking manner. Return whether @@ -780,6 +782,18 @@ class LockLimitError(LockError): class LockTimeoutError(LockError): """Raised when an attempt to acquire a lock times out.""" + def __init__(self, lock_type, path, time, attempts): + fmt = "Timed out waiting for a {} lock after {}.\n Made {} {} on file: {}" + super(LockTimeoutError, self).__init__( + fmt.format( + lock_type, + pretty_seconds(time), + attempts, + "attempt" if attempts == 1 else "attempts", + path, + ) + ) + class LockUpgradeError(LockError): """Raised when unable to upgrade from a read to a write lock.""" diff --git a/lib/spack/spack/installer.py b/lib/spack/spack/installer.py index ca53f87691a..411c076aa81 100644 --- a/lib/spack/spack/installer.py +++ b/lib/spack/spack/installer.py @@ -42,6 +42,7 @@ import llnl.util.filesystem as fs import llnl.util.lock as lk import llnl.util.tty as tty +from llnl.util.lang import pretty_seconds from llnl.util.tty.color import colorize from llnl.util.tty.log import log_output @@ -1069,7 +1070,7 @@ def _ensure_locked(self, lock_type, pkg): try: if lock is None: - tty.debug(msg.format("Acquiring", desc, pkg_id, timeout)) + tty.debug(msg.format("Acquiring", desc, pkg_id, pretty_seconds(timeout or 0))) op = "acquire" lock = spack.store.db.prefix_lock(pkg.spec, timeout) if timeout != lock.default_timeout: @@ -1088,14 +1089,18 @@ def _ensure_locked(self, lock_type, pkg): # must be downgraded to be a read lock # Retain the original lock timeout, which is in the lock's # default_timeout setting. - tty.debug(msg.format("Downgrading to", desc, pkg_id, lock.default_timeout)) + tty.debug( + msg.format( + "Downgrading to", desc, pkg_id, pretty_seconds(lock.default_timeout or 0) + ) + ) op = "downgrade to" lock.downgrade_write_to_read() else: # read -> write # Only get here if the current lock is a read lock, which # must be upgraded to be a write lock - tty.debug(msg.format("Upgrading to", desc, pkg_id, timeout)) + tty.debug(msg.format("Upgrading to", desc, pkg_id, pretty_seconds(timeout or 0))) op = "upgrade to" lock.upgrade_read_to_write(timeout) tty.debug("{0} is now {1} locked".format(pkg_id, lock_type)) diff --git a/lib/spack/spack/test/database.py b/lib/spack/spack/test/database.py index fb22c6fec0d..bd06e5eb2c2 100644 --- a/lib/spack/spack/test/database.py +++ b/lib/spack/spack/test/database.py @@ -858,7 +858,7 @@ def test_mark_failed(mutable_database, monkeypatch, tmpdir, capsys): """Add coverage to mark_failed.""" def _raise_exc(lock): - raise lk.LockTimeoutError("Mock acquire_write failure") + raise lk.LockTimeoutError("write", "/mock-lock", 1.234, 10) # Ensure attempt to acquire write lock on the mark raises the exception monkeypatch.setattr(lk.Lock, "acquire_write", _raise_exc) diff --git a/lib/spack/spack/test/llnl/util/lang.py b/lib/spack/spack/test/llnl/util/lang.py index 94b067f3dc8..bced1211368 100644 --- a/lib/spack/spack/test/llnl/util/lang.py +++ b/lib/spack/spack/test/llnl/util/lang.py @@ -118,6 +118,14 @@ def test_pretty_string_to_date(format, pretty_string): assert t1 == t2 +def test_pretty_seconds(): + assert llnl.util.lang.pretty_seconds(2.1) == "2.100s" + assert llnl.util.lang.pretty_seconds(2.1 / 1000) == "2.100ms" + assert llnl.util.lang.pretty_seconds(2.1 / 1000 / 1000) == "2.100us" + assert llnl.util.lang.pretty_seconds(2.1 / 1000 / 1000 / 1000) == "2.100ns" + assert llnl.util.lang.pretty_seconds(2.1 / 1000 / 1000 / 1000 / 10) == "0.210ns" + + def test_match_predicate(): matcher = match_predicate(lambda x: True) assert matcher("foo") @@ -306,15 +314,15 @@ def inner(): due to the following failures: inner method raised ValueError: wow! File "{0}", \ -line 290, in test_grouped_exception +line 298, in test_grouped_exception inner() File "{0}", \ -line 287, in inner +line 295, in inner raise ValueError("wow!") top-level raised TypeError: ok File "{0}", \ -line 293, in test_grouped_exception +line 301, in test_grouped_exception raise TypeError("ok") """ ).format(__file__) diff --git a/lib/spack/spack/test/llnl/util/lock.py b/lib/spack/spack/test/llnl/util/lock.py index a9c6b64db8d..bf812bcc1db 100644 --- a/lib/spack/spack/test/llnl/util/lock.py +++ b/lib/spack/spack/test/llnl/util/lock.py @@ -1294,7 +1294,7 @@ def test_lock_in_current_directory(tmpdir): def test_attempts_str(): assert lk._attempts_str(0, 0) == "" assert lk._attempts_str(0.12, 1) == "" - assert lk._attempts_str(12.345, 2) == " after 12.35s and 2 attempts" + assert lk._attempts_str(12.345, 2) == " after 12.345s and 2 attempts" def test_lock_str(): From 560a9eec920e1fba3d334c6506d193aa8d9cb098 Mon Sep 17 00:00:00 2001 From: Luke Diorio-Toth Date: Mon, 24 Oct 2022 09:01:28 -0500 Subject: [PATCH 165/442] py-drep and ANIcalculator: new packages (#33467) * py-drep: new package * fixed file extension * added darwin conflict * py-checkm-genome and py-pysam: bumped version and updated deps (#10) added checkm and pysam deps * added dep documentation and fixed style * changed checkm and pysam back to dev version for upstreaming * added url and perl run dep * fixed style --- .../builtin/packages/anicalculator/package.py | 35 +++++++++++++++ .../repos/builtin/packages/py-drep/package.py | 44 +++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 var/spack/repos/builtin/packages/anicalculator/package.py create mode 100644 var/spack/repos/builtin/packages/py-drep/package.py diff --git a/var/spack/repos/builtin/packages/anicalculator/package.py b/var/spack/repos/builtin/packages/anicalculator/package.py new file mode 100644 index 00000000000..7d83bb4596d --- /dev/null +++ b/var/spack/repos/builtin/packages/anicalculator/package.py @@ -0,0 +1,35 @@ +# 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) + +import os + +from spack.package import * + + +class Anicalculator(Package): + """This tool will calculate the bidirectional average nucleotide identity + (gANI) and Alignment Fraction (AF) between two genomes. + + Note: A manual download is required for ANIcalculator. + Spack will search your current directory for the download file. + Alternatively, add this file to a mirror so that Spack can find it. + For instructions on how to set up a mirror, see + https://spack.readthedocs.io/en/latest/mirrors.html""" + + homepage = "https://ani.jgi.doe.gov/html/download.php?" + url = "file://{0}/ANIcalculator_v1.tgz".format(os.getcwd()) + manual_download = True + + version("1", sha256="236596a9a204cbcad162fc66be3506b2530b1f48f4f84d9647ccec3ca7483a43") + + depends_on("perl@5:", type="run") + + conflicts("platform=darwin", msg="ANIcalculator requires Linux") + + def install(self, spec, prefix): + mkdirp(prefix.bin) + install("ANIcalculator", prefix.bin) + install("nsimscan", prefix.bin) + install_tree("Log", prefix.bin.Log) diff --git a/var/spack/repos/builtin/packages/py-drep/package.py b/var/spack/repos/builtin/packages/py-drep/package.py new file mode 100644 index 00000000000..a7ec0b3d002 --- /dev/null +++ b/var/spack/repos/builtin/packages/py-drep/package.py @@ -0,0 +1,44 @@ +# 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 PyDrep(PythonPackage): + """dRep is a python program for rapidly comparing large numbers of genomes. + dRep can also "de-replicate" a genome set by identifying groups of highly + similar genomes and choosing the best representative genome for each + genome set.""" + + homepage = "https://github.com/MrOlm/drep" + pypi = "drep/drep-3.4.0.tar.gz" + + version("3.4.0", sha256="a6533eb585122c1ee66ae622b1b97450a3e1e493a3c3c1d55e79a580d5c46d40") + + variant("fastani", default=True, description="Enable fastANI support") + variant("py-checkm-genome", default=True, description="Enable CheckM support") + variant("anicalculator", default=True, description="Enable gDNA support") + variant("prodigal", default=True, description="Used with both checkM and gANI") + + depends_on("py-setuptools", type="build") + depends_on("py-numpy", type=("build", "run")) + depends_on("py-pandas", type=("build", "run")) + depends_on("py-seaborn", type=("build", "run")) + depends_on("py-matplotlib", type=("build", "run")) + depends_on("py-biopython", type=("build", "run")) + depends_on("py-scikit-learn", type=("build", "run")) + depends_on("py-tqdm", type=("build", "run")) + depends_on("py-pytest", type=("build", "run")) + # Non-python dependencies + # https://drep.readthedocs.io/en/latest/installation.html#dependencies + # essential dependencies + depends_on("mash@1.1.1:", type="run") + depends_on("mummer@3.23:", type="run") + # recommended dependencies + depends_on("fastani", type="run", when="+fastani") + depends_on("py-checkm-genome@1.0.7:", type="run", when="+py-checkm-genome") + depends_on("anicalculator@1:", type="run", when="+anicalculator") + depends_on("prodigal@2.6.3:", type="run", when="+prodigal") From dda2ff46532de49a562ad87d8f606e247020ec11 Mon Sep 17 00:00:00 2001 From: eugeneswalker <38933153+eugeneswalker@users.noreply.github.com> Date: Mon, 24 Oct 2022 09:08:16 -0700 Subject: [PATCH 166/442] chai +rocm: use hipcc as CMAKE_CXX_COMPILER (#33479) --- var/spack/repos/builtin/packages/chai/package.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/var/spack/repos/builtin/packages/chai/package.py b/var/spack/repos/builtin/packages/chai/package.py index 6687b5092b3..a52bcb8a085 100644 --- a/var/spack/repos/builtin/packages/chai/package.py +++ b/var/spack/repos/builtin/packages/chai/package.py @@ -112,6 +112,13 @@ def cache_name(self): self.spec.compiler.version, ) + def initconfig_compiler_entries(self): + spec = self.spec + entries = super(Chai, self).initconfig_compiler_entries() + if "+rocm" in spec: + entries.insert(0, cmake_cache_path("CMAKE_CXX_COMPILER", spec["hip"].hipcc)) + return entries + def initconfig_hardware_entries(self): spec = self.spec entries = super(Chai, self).initconfig_hardware_entries() From a51bd80a5ed62919376fe19019cf98c54dc4232e Mon Sep 17 00:00:00 2001 From: eugeneswalker <38933153+eugeneswalker@users.noreply.github.com> Date: Mon, 24 Oct 2022 09:16:56 -0700 Subject: [PATCH 167/442] e4s ci: add chai +rocm (#32506) --- share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml index d4e86386bc5..1b61c3d17cc 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml @@ -206,6 +206,7 @@ spack: - arborx +rocm amdgpu_target=gfx90a - cabana +rocm - caliper +rocm amdgpu_target=gfx90a + - chai ~benchmarks +rocm amdgpu_target=gfx90a - gasnet +rocm amdgpu_target=gfx90a - ginkgo +rocm amdgpu_target=gfx90a - heffte +rocm amdgpu_target=gfx90a @@ -244,7 +245,8 @@ spack: #- parsec +cuda cuda_arch=80 # parsec/mca/device/cuda/transfer.c:168: multiple definition of `parsec_CUDA_d2h_max_flows'; # ROCm failures - #- chai ~benchmarks +rocm amdgpu_target=gfx90a # umpire: Target "blt_hip" INTERFACE_INCLUDE_DIRECTORIES property contains path: "/tmp/root/spack-stage/spack-stage-umpire-2022.03.1-by6rldnpdowaaoqgxkeqejwyx5uxo2sv/spack-src/HIP_CLANG_INCLUDE_PATH-NOTFOUND/.." which is prefixed in the source directory. + #- raja ~openmp +rocm amdgpu_target=gfx90a # cmake: Could NOT find ROCPRIM (missing: ROCPRIM_INCLUDE_DIRS) + #- umpire +rocm amdgpu_target=gfx90a # Target "blt_hip" INTERFACE_INCLUDE_DIRECTORIES property contains path: "/tmp/root/spack-stage/spack-stage-umpire-2022.03.1-by6rldnpdowaaoqgxkeqejwyx5uxo2sv/spack-src/HIP_CLANG_INCLUDE_PATH-NOTFOUND/.." which is prefixed in the source directory. mirrors: { "mirror": "s3://spack-binaries/develop/e4s" } From 0b971a1aef2fa27574d3c7c5f1a8a2eed6c2c1ec Mon Sep 17 00:00:00 2001 From: Danny McClanahan <1305167+cosmicexplorer@users.noreply.github.com> Date: Mon, 24 Oct 2022 13:08:18 -0400 Subject: [PATCH 168/442] redact line numbers from grouped exception message (#33485) --- lib/spack/spack/test/llnl/util/lang.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/spack/spack/test/llnl/util/lang.py b/lib/spack/spack/test/llnl/util/lang.py index bced1211368..63090caa384 100644 --- a/lib/spack/spack/test/llnl/util/lang.py +++ b/lib/spack/spack/test/llnl/util/lang.py @@ -4,6 +4,7 @@ # SPDX-License-Identifier: (Apache-2.0 OR MIT) import os.path +import re import sys from datetime import datetime, timedelta from textwrap import dedent @@ -307,22 +308,25 @@ def inner(): top-level raised TypeError: ok""" ) + full_message = h.grouped_message(with_tracebacks=True) + no_line_numbers = re.sub(r"line [0-9]+,", "line xxx,", full_message) + assert ( - h.grouped_message(with_tracebacks=True) + no_line_numbers == dedent( """\ due to the following failures: inner method raised ValueError: wow! File "{0}", \ -line 298, in test_grouped_exception +line xxx, in test_grouped_exception inner() File "{0}", \ -line 295, in inner +line xxx, in inner raise ValueError("wow!") top-level raised TypeError: ok File "{0}", \ -line 301, in test_grouped_exception +line xxx, in test_grouped_exception raise TypeError("ok") """ ).format(__file__) From 2eb0660a7981ddcae1cd023ecc3b597a3e051e8b Mon Sep 17 00:00:00 2001 From: Ryan Mulhall <35538242+rem1776@users.noreply.github.com> Date: Mon, 24 Oct 2022 16:15:19 -0400 Subject: [PATCH 169/442] update fms package for v2022.04 (#33484) Co-authored-by: rem1776 --- var/spack/repos/builtin/packages/fms/package.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/fms/package.py b/var/spack/repos/builtin/packages/fms/package.py index 6846c04d4b4..53400dc3e7d 100644 --- a/var/spack/repos/builtin/packages/fms/package.py +++ b/var/spack/repos/builtin/packages/fms/package.py @@ -13,7 +13,7 @@ class Fms(CMakePackage): system models.""" homepage = "https://github.com/NOAA-GFDL/FMS" - url = "https://github.com/NOAA-GFDL/FMS/archive/refs/tags/2022.02.tar.gz" + url = "https://github.com/NOAA-GFDL/FMS/archive/refs/tags/2022.04.tar.gz" git = "https://github.com/NOAA-GFDL/FMS.git" maintainers = [ @@ -23,6 +23,7 @@ class Fms(CMakePackage): "rem1776", ] + version("2022.04", sha256="f741479128afc2b93ca8291a4c5bcdb024a8cbeda1a26bf77a236c0f629e1b03") version("2022.03", sha256="42d2ac53d3c889a8177a6d7a132583364c0f6e5d5cbde0d980443b6797ad4838") version("2022.02", sha256="ad4978302b219e11b883b2f52519e1ee455137ad947474abb316c8654f72c874") version("2022.01", sha256="a1cba1f536923f5953c28729a28e5431e127b45d6bc2c15d230939f0c02daa9b") From 20492fa48e22f7a4322bd88b199d02e091045944 Mon Sep 17 00:00:00 2001 From: Jon Rood Date: Mon, 24 Oct 2022 14:37:58 -0600 Subject: [PATCH 170/442] cppcheck: add version 2.9 (#33491) --- var/spack/repos/builtin/packages/cppcheck/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/cppcheck/package.py b/var/spack/repos/builtin/packages/cppcheck/package.py index 63ee7385e90..5d9a2f23665 100644 --- a/var/spack/repos/builtin/packages/cppcheck/package.py +++ b/var/spack/repos/builtin/packages/cppcheck/package.py @@ -14,6 +14,7 @@ class Cppcheck(CMakePackage): maintainers = ["white238"] + version("2.9", sha256="d89f3282c70814fa66669e1ea0323c0484563b3f8249c7a2dcaac2ad07651dc7") version("2.8", sha256="a5ed97a99173d2952cd93fcb028a3405a7b3b992e7168e2ae9d527b991770203") version("2.7", sha256="ac74c0973c46a052760f4ff7ca6a84616ca5795510542d195a6f122c53079291") version("2.1", sha256="ab26eeef039e5b58aac01efb8cb664f2cc16bf9879c61bc93cd00c95be89a5f7") From e7512bcb7b784d96388bbc333769479ca657b372 Mon Sep 17 00:00:00 2001 From: iarspider Date: Mon, 24 Oct 2022 23:32:46 +0200 Subject: [PATCH 171/442] Add filename to text_to_relocate only if it needs to be relocated (#31074) Scan the text files for relocatable prefixes *before* creating a tarball, to reduce the amount of work to be done during install from binary cache. Co-authored-by: Harmen Stoppels --- lib/spack/spack/binary_distribution.py | 24 +++++++++++++++-- lib/spack/spack/relocate.py | 15 +++++++---- lib/spack/spack/test/bindist.py | 13 ++++++++- lib/spack/spack/test/relocate.py | 10 +++++++ .../packages/needs-text-relocation/package.py | 27 +++++++++++++++++++ 5 files changed, 81 insertions(+), 8 deletions(-) create mode 100644 var/spack/repos/builtin.mock/packages/needs-text-relocation/package.py diff --git a/lib/spack/spack/binary_distribution.py b/lib/spack/spack/binary_distribution.py index 7ae91dd6bfe..3f74d91a9e8 100644 --- a/lib/spack/spack/binary_distribution.py +++ b/lib/spack/spack/binary_distribution.py @@ -42,6 +42,7 @@ import spack.util.url as url_util import spack.util.web as web_util from spack.caches import misc_cache_location +from spack.relocate import utf8_path_to_binary_regex from spack.spec import Spec from spack.stage import Stage @@ -687,6 +688,15 @@ def before_visit_symlinked_dir(self, root, rel_path, depth): return False +def file_matches_any_binary_regex(path, regexes): + with open(path, "rb") as f: + contents = f.read() + for regex in regexes: + if regex.search(contents): + return True + return False + + def get_buildfile_manifest(spec): """ Return a data structure with information about a build, including @@ -712,6 +722,15 @@ def get_buildfile_manifest(spec): root = spec.prefix visit_directory_tree(root, visitor) + # Collect a list of prefixes for this package and it's dependencies, Spack will + # look for them to decide if text file needs to be relocated or not + prefixes = [d.prefix for d in spec.traverse(root=True, deptype="all") if not d.external] + prefixes.append(spack.hooks.sbang.sbang_install_path()) + prefixes.append(str(spack.store.layout.root)) + + # Create a list regexes matching collected prefixes + compiled_prefixes = [utf8_path_to_binary_regex(prefix) for prefix in prefixes] + # Symlinks. # Obvious bugs: @@ -743,8 +762,9 @@ def get_buildfile_manifest(spec): continue elif relocate.needs_text_relocation(m_type, m_subtype): - data["text_to_relocate"].append(rel_path) - continue + if file_matches_any_binary_regex(abs_path, compiled_prefixes): + data["text_to_relocate"].append(rel_path) + continue data["other"].append(abs_path) diff --git a/lib/spack/spack/relocate.py b/lib/spack/spack/relocate.py index 3297965b6ea..667e8de4e0c 100644 --- a/lib/spack/spack/relocate.py +++ b/lib/spack/spack/relocate.py @@ -744,6 +744,14 @@ def relocate_links(links, orig_layout_root, orig_install_prefix, new_install_pre tty.warn(msg.format(link_target, abs_link, new_install_prefix)) +def utf8_path_to_binary_regex(prefix): + """Create a (binary) regex that matches the input path in utf8""" + prefix_bytes = re.escape(prefix).encode("utf-8") + prefix_rexp = re.compile(b"(? Date: Mon, 24 Oct 2022 16:15:01 -0700 Subject: [PATCH 172/442] e4s ci: use an appropriate name for cdash build group name (#33494) --- share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml index 1b61c3d17cc..1f4f660357f 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml @@ -460,7 +460,7 @@ spack: - aws s3 sync --exclude "*" --include "*spec.json.sig*" /tmp ${SPACK_REMOTE_MIRROR_OVERRIDE}/build_cache cdash: - build-group: New PR testing workflow + build-group: E4S url: https://cdash.spack.io project: Spack Testing site: Cloud Gitlab Infrastructure From 8e78a91ebda4798c0242aec22616cb6b2ba249ae Mon Sep 17 00:00:00 2001 From: Zach Jibben Date: Mon, 24 Oct 2022 19:38:23 -0600 Subject: [PATCH 173/442] Add py-myst-parser & update py-mdit-py-plugins and py-sphinxcontrib-mermaid (#33427) * Update py-sphinxcontrib-mermaid * Add py-myst-parser * Fix py-mdit-py-plugins and py-myst-parser dependencies * Add py-exhale package * Update var/spack/repos/builtin/packages/py-mdit-py-plugins/package.py Co-authored-by: Adam J. Stewart * Update var/spack/repos/builtin/packages/py-myst-parser/package.py Co-authored-by: Adam J. Stewart * Update var/spack/repos/builtin/packages/py-myst-parser/package.py Co-authored-by: Adam J. Stewart * Update var/spack/repos/builtin/packages/py-myst-parser/package.py Co-authored-by: Adam J. Stewart * Update py-exhale and py-myst-parser dependencies * Add @svenevs as py-exhale maintainer * Update var/spack/repos/builtin/packages/py-mdit-py-plugins/package.py Co-authored-by: Adam J. Stewart Co-authored-by: Adam J. Stewart --- .../builtin/packages/py-exhale/package.py | 27 +++++++++++++++++++ .../packages/py-mdit-py-plugins/package.py | 13 ++++++--- .../packages/py-myst-parser/package.py | 27 +++++++++++++++++++ .../py-sphinxcontrib-mermaid/package.py | 1 + 4 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 var/spack/repos/builtin/packages/py-exhale/package.py create mode 100644 var/spack/repos/builtin/packages/py-myst-parser/package.py diff --git a/var/spack/repos/builtin/packages/py-exhale/package.py b/var/spack/repos/builtin/packages/py-exhale/package.py new file mode 100644 index 00000000000..06be8abaef0 --- /dev/null +++ b/var/spack/repos/builtin/packages/py-exhale/package.py @@ -0,0 +1,27 @@ +# 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 PyExhale(PythonPackage): + """Automatic C++ library api documentation generation: breathe doxygen in + and exhale it out.""" + + homepage = "https://github.com/svenevs/exhale" + pypi = "exhale/exhale-0.3.6.tar.gz" + + maintainers = ["svenevs"] + + version("0.3.6", sha256="ab41be313e1236bd4386e4696fb35f37ce8103c2059cf8d1f083da5411bb74d7") + + depends_on("python@3.7:", type=("build", "run")) + depends_on("py-setuptools@42:", type="build") + depends_on("py-breathe@4.32.0:", type="build") + depends_on("py-docutils@0.12:", type="build") + depends_on("py-sphinx@3:4", type="build") + depends_on("py-beautifulsoup4", type=("build", "run")) + depends_on("py-lxml", type=("build", "run")) + depends_on("py-six", type=("build", "run")) diff --git a/var/spack/repos/builtin/packages/py-mdit-py-plugins/package.py b/var/spack/repos/builtin/packages/py-mdit-py-plugins/package.py index 0b33022ebe7..a096af89488 100644 --- a/var/spack/repos/builtin/packages/py-mdit-py-plugins/package.py +++ b/var/spack/repos/builtin/packages/py-mdit-py-plugins/package.py @@ -12,10 +12,15 @@ class PyMditPyPlugins(PythonPackage): homepage = "https://github.com/executablebooks/mdit-py-plugins/" git = "https://github.com/executablebooks/mdit-py-plugins/" - pypi = "mdit-py-plugins/mdit-py-plugins-0.2.8.tar.gz" + pypi = "mdit-py-plugins/mdit-py-plugins-0.3.1.tar.gz" + version("0.3.1", sha256="3fc13298497d6e04fe96efdd41281bfe7622152f9caa1815ea99b5c893de9441") version("0.2.8", sha256="5991cef645502e80a5388ec4fc20885d2313d4871e8b8e320ca2de14ac0c015f") - depends_on("py-setuptools", type="build") - depends_on("py-markdown-it-py@1.0:1", type=("build", "run")) - depends_on("python@3.6:3", type=("build", "run")) + depends_on("py-flit-core@3.4:3", when="@0.3.1", type=("build", "run")) + depends_on("python@3.7:", when="@0.3.1", type=("build", "run")) + depends_on("py-markdown-it-py@1.0:2", when="@0.3.1", type=("build", "run")) + + depends_on("py-setuptools", when="@:0.2", type="build") + depends_on("py-markdown-it-py@1.0:1", when="@0.2.8", type=("build", "run")) + depends_on("python@3.6:3", when="@0.2.8", type=("build", "run")) diff --git a/var/spack/repos/builtin/packages/py-myst-parser/package.py b/var/spack/repos/builtin/packages/py-myst-parser/package.py new file mode 100644 index 00000000000..c8748227521 --- /dev/null +++ b/var/spack/repos/builtin/packages/py-myst-parser/package.py @@ -0,0 +1,27 @@ +# 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 PyMystParser(PythonPackage): + """A Sphinx and Docutils extension to parse MyST, a rich and + extensible flavour of Markdown for authoring technical and + scientific documentation.""" + + homepage = "https://github.com/executablebooks/MyST-Parser" + pypi = "myst-parser/myst-parser-0.18.1.tar.gz" + + version("0.18.1", sha256="79317f4bb2c13053dd6e64f9da1ba1da6cd9c40c8a430c447a7b146a594c246d") + + depends_on("python@3.7:", type=("build", "run")) + depends_on("py-flit-core@3.4:3", type="build") + depends_on("py-docutils@0.15:0.19", type=("build", "run")) + depends_on("py-jinja2", type=("build", "run")) # let sphinx decide version + depends_on("py-markdown-it-py@1.0.0:2", type=("build", "run")) + depends_on("py-mdit-py-plugins@0.3.1:0.3", type=("build", "run")) + depends_on("py-pyyaml", type=("build", "run")) + depends_on("py-sphinx@4.0.0:5", type=("build", "run")) + depends_on("py-typing-extensions", type=("build", "run")) diff --git a/var/spack/repos/builtin/packages/py-sphinxcontrib-mermaid/package.py b/var/spack/repos/builtin/packages/py-sphinxcontrib-mermaid/package.py index 4a135a98194..c11dece3fe5 100644 --- a/var/spack/repos/builtin/packages/py-sphinxcontrib-mermaid/package.py +++ b/var/spack/repos/builtin/packages/py-sphinxcontrib-mermaid/package.py @@ -14,6 +14,7 @@ class PySphinxcontribMermaid(PythonPackage): homepage = "https://github.com/mgaitan/sphinxcontrib-mermaid" pypi = "sphinxcontrib-mermaid/sphinxcontrib-mermaid-0.4.0.tar.gz" + version("0.7.1", sha256="aa8a40b50ec86ad12824b62180240ca52a9bda8424455d7eb252eae9aa5d293c") version("0.4.0", sha256="0ee45ba45b9575505eacdd6212e4e545213f4f93dfa32c7eeca32720dbc3b468") depends_on("py-setuptools", type="build") From 8aa09fd1c0220d2303f2128b51b8a1dd725f3fae Mon Sep 17 00:00:00 2001 From: Miroslav Stoyanov <30537612+mkstoyanov@users.noreply.github.com> Date: Mon, 24 Oct 2022 22:34:04 -0400 Subject: [PATCH 174/442] fix problems with missing rocm dependencies (#33381) --- .../builtin/packages/tasmanian/package.py | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/tasmanian/package.py b/var/spack/repos/builtin/packages/tasmanian/package.py index e2b4ab39736..a37ff06a658 100644 --- a/var/spack/repos/builtin/packages/tasmanian/package.py +++ b/var/spack/repos/builtin/packages/tasmanian/package.py @@ -192,7 +192,43 @@ def test(self): # using the tests copied from /share/Tasmanian/testing cmake_dir = self.test_suite.current_test_cache_dir.testing - if not self.run_test(cmake_bin, options=[cmake_dir], purpose="Generate the Makefile"): + options = [ + cmake_dir, + ] + if "+rocm" in self.spec: + options.append( + "-DAMDDeviceLibs_DIR=" + + join_path(self.spec["llvm-amdgpu"].prefix, "lib", "cmake", "AMDDeviceLibs") + ) + options.append( + "-Damd_comgr_DIR=" + + join_path(self.spec["comgr"].prefix, "lib", "cmake", "amd_comgr") + ) + options.append( + "-Dhsa-runtime64_DIR=" + + join_path(self.spec["hsa-rocr-dev"].prefix, "lib", "cmake", "hsa-runtime64") + ) + options.append( + "-DHSA_HEADER=" + join_path(self.spec["hsa-rocr-dev"].prefix, "include") + ) + options.append( + "-DCMAKE_INCLUDE_PATH=" + + join_path(self.spec["hsa-rocr-dev"].prefix, "include", "hsa") + ) + options.append( + "-Drocblas_DIR=" + + join_path(self.spec["rocblas"].prefix, "lib", "cmake", "rocblas") + ) + options.append( + "-Drocsparse_DIR=" + + join_path(self.spec["rocsparse"].prefix, "lib", "cmake", "rocsparse") + ) + options.append( + "-Drocsolver_DIR=" + + join_path(self.spec["rocsolver"].prefix, "lib", "cmake", "rocsolver") + ) + + if not self.run_test(cmake_bin, options=options, purpose="Generate the Makefile"): tty.msg("Skipping tasmanian test: failed to generate Makefile") return From 272767c67fbc52ecee1c7ec07f3d9c1c9bbc71be Mon Sep 17 00:00:00 2001 From: Brian Spilner Date: Tue, 25 Oct 2022 08:49:17 +0200 Subject: [PATCH 175/442] cdo: add new release 2.1.0 (#33303) --- var/spack/repos/builtin/packages/cdo/package.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/var/spack/repos/builtin/packages/cdo/package.py b/var/spack/repos/builtin/packages/cdo/package.py index bbc232c0bd8..85f208861a9 100644 --- a/var/spack/repos/builtin/packages/cdo/package.py +++ b/var/spack/repos/builtin/packages/cdo/package.py @@ -20,6 +20,11 @@ class Cdo(AutotoolsPackage): maintainers = ["skosukhin", "Try2Code"] + version( + "2.1.0", + sha256="b871346c944b05566ab21893827c74616575deaad0b20eacb472b80b1fa528cc", + url="https://code.mpimet.mpg.de/attachments/download/27481/cdo-2.1.0.tar.gz", + ) version( "2.0.6", sha256="ef120dea9032b1be80a4cfa201958c3b910107205beb6674195675f1ee8ed402", From 329adc1d22c371bb20b7db794edc962581128e48 Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Tue, 25 Oct 2022 11:41:29 +0200 Subject: [PATCH 176/442] CI: speed-up tests by dropping coverage on Python 2.7 (#33497) --- .github/workflows/unit_tests.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/unit_tests.yaml b/.github/workflows/unit_tests.yaml index aef69fb60f2..d2d267b516c 100644 --- a/.github/workflows/unit_tests.yaml +++ b/.github/workflows/unit_tests.yaml @@ -52,11 +52,11 @@ jobs: patchelf cmake bison libbison-dev kcov - name: Install Python packages run: | - pip install --upgrade pip six setuptools pytest codecov[toml] pytest-cov - # Install xdist only on recent Python, to avoid stalling on Python 2.7 due - # to bugs on an unmaintained version of the package. + pip install --upgrade pip six setuptools pytest codecov[toml] pytest-xdist + # Install pytest-cov only on recent Python, to avoid stalling on Python 2.7 due + # to bugs on an unmaintained version of the package when used with xdist. if [[ ${{ matrix.python-version }} != "2.7" ]]; then - pip install --upgrade pytest-xdist + pip install --upgrade pytest-cov fi # ensure style checks are not skipped in unit tests for python >= 3.6 # note that true/false (i.e., 1/0) are opposite in conditions in python and bash @@ -66,7 +66,7 @@ jobs: - name: Pin pathlib for Python 2.7 if: ${{ matrix.python-version == 2.7 }} run: | - pip install -U pathlib2==2.3.6 + pip install -U pathlib2==2.3.6 toml - name: Setup git configuration run: | # Need this for the git tests to succeed. @@ -86,7 +86,7 @@ jobs: SPACK_TEST_SOLVER: ${{ matrix.concretizer }} SPACK_TEST_PARALLEL: 2 COVERAGE: true - UNIT_TEST_COVERAGE: ${{ (matrix.concretizer == 'original' && matrix.python-version == '2.7') || (matrix.python-version == '3.10') }} + UNIT_TEST_COVERAGE: ${{ (matrix.python-version == '3.10') }} run: | share/spack/qa/run-unit-tests coverage combine -a From d361378553812f1bd173ded62be404bd1ae1b858 Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Tue, 25 Oct 2022 12:21:34 +0200 Subject: [PATCH 177/442] Improve legibility of Gitlab CI (#33482) Use --backtrace in ci instead of --debug to reduce verbosity and don't show log on error, since log is already printed --- lib/spack/spack/ci.py | 5 +++-- lib/spack/spack/cmd/ci.py | 3 +-- .../cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml | 2 +- .../spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml | 2 +- .../gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml | 2 +- share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml | 2 +- .../gitlab/cloud_pipelines/stacks/build_systems/spack.yaml | 2 +- .../gitlab/cloud_pipelines/stacks/data-vis-sdk/spack.yaml | 2 +- share/spack/gitlab/cloud_pipelines/stacks/e4s-mac/spack.yaml | 2 +- .../gitlab/cloud_pipelines/stacks/e4s-on-power/spack.yaml | 2 +- .../gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml | 2 +- share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml | 2 +- share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml | 2 +- share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml | 2 +- share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml | 2 +- .../cloud_pipelines/stacks/radiuss-aws-aarch64/spack.yaml | 2 +- .../gitlab/cloud_pipelines/stacks/radiuss-aws/spack.yaml | 2 +- share/spack/gitlab/cloud_pipelines/stacks/radiuss/spack.yaml | 2 +- .../spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml | 2 +- 19 files changed, 21 insertions(+), 21 deletions(-) diff --git a/lib/spack/spack/ci.py b/lib/spack/spack/ci.py index 4803ef25a3d..1a63949efb5 100644 --- a/lib/spack/spack/ci.py +++ b/lib/spack/spack/ci.py @@ -2118,8 +2118,9 @@ def run_standalone_tests(**kwargs): test_args = [ "spack", - "-d", - "-v", + "--color=always", + "--backtrace", + "--verbose", "test", "run", ] diff --git a/lib/spack/spack/cmd/ci.py b/lib/spack/spack/cmd/ci.py index c0343d69b7e..e49bf9a2a61 100644 --- a/lib/spack/spack/cmd/ci.py +++ b/lib/spack/spack/cmd/ci.py @@ -25,7 +25,7 @@ section = "build" level = "long" -CI_REBUILD_INSTALL_BASE_ARGS = ["spack", "-d", "-v"] +CI_REBUILD_INSTALL_BASE_ARGS = ["spack", "--color=always", "--backtrace", "--verbose"] INSTALL_FAIL_CODE = 1 @@ -518,7 +518,6 @@ def ci_rebuild(args): install_args.extend( [ "install", - "--show-log-on-error", # Print full log on fails "--keep-stage", "--use-buildcache", "dependencies:only,package:never", diff --git a/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml index 89337ece10c..09a36a6b02c 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml @@ -249,7 +249,7 @@ spack: - mkdir -p ${SPACK_ARTIFACTS_ROOT}/user_data - if [[ -r /mnt/key/intermediate_ci_signing_key.gpg ]]; then spack gpg trust /mnt/key/intermediate_ci_signing_key.gpg; fi - if [[ -r /mnt/key/spack_public_key.gpg ]]; then spack gpg trust /mnt/key/spack_public_key.gpg; fi - - spack -d ci rebuild > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) + - spack --color=always --backtrace ci rebuild > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) image: { "name": "ghcr.io/spack/e4s-amazonlinux-2:v2022-03-21", "entrypoint": [""] } match_behavior: first diff --git a/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml index bc440a8950f..122247e936e 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml @@ -248,7 +248,7 @@ spack: - mkdir -p ${SPACK_ARTIFACTS_ROOT}/user_data - if [[ -r /mnt/key/intermediate_ci_signing_key.gpg ]]; then spack gpg trust /mnt/key/intermediate_ci_signing_key.gpg; fi - if [[ -r /mnt/key/spack_public_key.gpg ]]; then spack gpg trust /mnt/key/spack_public_key.gpg; fi - - spack -d ci rebuild > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) + - spack --color=always --backtrace ci rebuild > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) image: { "name": "ghcr.io/spack/e4s-amazonlinux-2:v2022-03-21", "entrypoint": [""] } match_behavior: first diff --git a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml index 0e575647fc5..d73a14c2ec9 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml @@ -156,7 +156,7 @@ spack: - mkdir -p ${SPACK_ARTIFACTS_ROOT}/user_data - if [[ -r /mnt/key/intermediate_ci_signing_key.gpg ]]; then spack gpg trust /mnt/key/intermediate_ci_signing_key.gpg; fi - if [[ -r /mnt/key/spack_public_key.gpg ]]; then spack gpg trust /mnt/key/spack_public_key.gpg; fi - - spack -d ci rebuild > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) + - spack --color=always --backtrace ci rebuild > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) image: { "name": "ghcr.io/spack/e4s-amazonlinux-2:v2022-03-21", "entrypoint": [""] } match_behavior: first diff --git a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml index cfc6778e1a6..45731b9392a 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml @@ -167,7 +167,7 @@ spack: - mkdir -p ${SPACK_ARTIFACTS_ROOT}/user_data - if [[ -r /mnt/key/intermediate_ci_signing_key.gpg ]]; then spack gpg trust /mnt/key/intermediate_ci_signing_key.gpg; fi - if [[ -r /mnt/key/spack_public_key.gpg ]]; then spack gpg trust /mnt/key/spack_public_key.gpg; fi - - spack -d ci rebuild > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) + - spack --color=always --backtrace ci rebuild > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) image: { "name": "ghcr.io/spack/e4s-amazonlinux-2:v2022-03-21", "entrypoint": [""] } match_behavior: first diff --git a/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml index 4808763f374..98a5d286dc4 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml @@ -39,7 +39,7 @@ spack: - spack config add "config:install_tree:projections:${SPACK_JOB_SPEC_PKG_NAME}:'morepadding/{architecture}/{compiler.name}-{compiler.version}/{name}-{version}-{hash}'" - if [[ -r /mnt/key/intermediate_ci_signing_key.gpg ]]; then spack gpg trust /mnt/key/intermediate_ci_signing_key.gpg; fi - if [[ -r /mnt/key/spack_public_key.gpg ]]; then spack gpg trust /mnt/key/spack_public_key.gpg; fi - - spack -d ci rebuild + - spack --color=always --backtrace ci rebuild image: name: "ghcr.io/spack/e4s-ubuntu-18.04:v2021-10-18" diff --git a/share/spack/gitlab/cloud_pipelines/stacks/data-vis-sdk/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/data-vis-sdk/spack.yaml index 3f5a37f8875..4cb9dc510fa 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/data-vis-sdk/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/data-vis-sdk/spack.yaml @@ -54,7 +54,7 @@ spack: - spack config add "config:install_tree:projections:${SPACK_JOB_SPEC_PKG_NAME}:'morepadding/{architecture}/{compiler.name}-{compiler.version}/{name}-{version}-{hash}'" - if [[ -r /mnt/key/intermediate_ci_signing_key.gpg ]]; then spack gpg trust /mnt/key/intermediate_ci_signing_key.gpg; fi - if [[ -r /mnt/key/spack_public_key.gpg ]]; then spack gpg trust /mnt/key/spack_public_key.gpg; fi - - spack -d ci rebuild + - spack --color=always --backtrace ci rebuild match_behavior: first mappings: - match: diff --git a/share/spack/gitlab/cloud_pipelines/stacks/e4s-mac/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/e4s-mac/spack.yaml index ed49d553b25..fcad22dbf88 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/e4s-mac/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/e4s-mac/spack.yaml @@ -49,7 +49,7 @@ spack: - spack env activate --without-view . - spack config add "config:install_tree:projections:${SPACK_JOB_SPEC_PKG_NAME}:'morepadding/{architecture}/{compiler.name}-{compiler.version}/{name}-{version}-{hash}'" - mkdir -p ${SPACK_ARTIFACTS_ROOT}/user_data - - spack -d ci rebuild > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) + - spack --color=always --backtrace ci rebuild > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) match_behavior: first mappings: diff --git a/share/spack/gitlab/cloud_pipelines/stacks/e4s-on-power/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/e4s-on-power/spack.yaml index b1a30701df8..16e7558e9fa 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/e4s-on-power/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/e4s-on-power/spack.yaml @@ -219,7 +219,7 @@ spack: - cd ${SPACK_CONCRETE_ENV_DIR} - spack env activate --without-view . - spack config add "config:install_tree:projections:${SPACK_JOB_SPEC_PKG_NAME}:'morepadding/{architecture}/{compiler.name}-{compiler.version}/{name}-{version}-{hash}'" - - spack -d ci rebuild + - spack --color=always --backtrace ci rebuild match_behavior: first mappings: diff --git a/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml index 944c110ac54..263f30ede50 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml @@ -278,7 +278,7 @@ spack: - . /bootstrap/runner/install/linux-ubuntu20.04-x86_64/gcc-9.4.0/lmod-8.7.2-ri26z7qy6ixtgpsqinswx3w6tuggluv5/lmod/8.7.2/init/bash - module use /opt/intel/oneapi/modulefiles - module load compiler - - spack -d ci rebuild > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) + - spack --color=always --backtrace ci rebuild > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) image: ecpe4s/ubuntu20.04-runner-x86_64-oneapi:2022-07-01 diff --git a/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml index 1f4f660357f..2a4950d11aa 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml @@ -261,7 +261,7 @@ spack: - mkdir -p ${SPACK_ARTIFACTS_ROOT}/user_data - if [[ -r /mnt/key/intermediate_ci_signing_key.gpg ]]; then spack gpg trust /mnt/key/intermediate_ci_signing_key.gpg; fi - if [[ -r /mnt/key/spack_public_key.gpg ]]; then spack gpg trust /mnt/key/spack_public_key.gpg; fi - - spack -d ci rebuild --tests > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) + - spack --color=always --backtrace ci rebuild --tests > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) image: ecpe4s/ubuntu20.04-runner-x86_64:2022-10-01 diff --git a/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml index fdda5188d22..0078c018f7f 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml @@ -95,7 +95,7 @@ spack: - mkdir -p ${SPACK_ARTIFACTS_ROOT}/user_data - if [[ -r /mnt/key/intermediate_ci_signing_key.gpg ]]; then spack gpg trust /mnt/key/intermediate_ci_signing_key.gpg; fi - if [[ -r /mnt/key/spack_public_key.gpg ]]; then spack gpg trust /mnt/key/spack_public_key.gpg; fi - - spack -d ci rebuild > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) + - spack --color=always --backtrace ci rebuild > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) match_behavior: first mappings: diff --git a/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml index 45862560de1..cfd6e1ecbaf 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml @@ -98,7 +98,7 @@ spack: - mkdir -p ${SPACK_ARTIFACTS_ROOT}/user_data - if [[ -r /mnt/key/intermediate_ci_signing_key.gpg ]]; then spack gpg trust /mnt/key/intermediate_ci_signing_key.gpg; fi - if [[ -r /mnt/key/spack_public_key.gpg ]]; then spack gpg trust /mnt/key/spack_public_key.gpg; fi - - spack -d ci rebuild > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) + - spack --color=always --backtrace ci rebuild > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) match_behavior: first mappings: diff --git a/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml index 9dadbe48526..537aa55f9da 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml @@ -101,7 +101,7 @@ spack: - mkdir -p ${SPACK_ARTIFACTS_ROOT}/user_data - if [[ -r /mnt/key/intermediate_ci_signing_key.gpg ]]; then spack gpg trust /mnt/key/intermediate_ci_signing_key.gpg; fi - if [[ -r /mnt/key/spack_public_key.gpg ]]; then spack gpg trust /mnt/key/spack_public_key.gpg; fi - - spack -d ci rebuild > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) + - spack --color=always --backtrace ci rebuild > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) match_behavior: first mappings: diff --git a/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws-aarch64/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws-aarch64/spack.yaml index 0e22a2d5666..ad294f5a935 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws-aarch64/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws-aarch64/spack.yaml @@ -64,7 +64,7 @@ spack: - mkdir -p ${SPACK_ARTIFACTS_ROOT}/user_data - if [[ -r /mnt/key/intermediate_ci_signing_key.gpg ]]; then spack gpg trust /mnt/key/intermediate_ci_signing_key.gpg; fi - if [[ -r /mnt/key/spack_public_key.gpg ]]; then spack gpg trust /mnt/key/spack_public_key.gpg; fi - - spack -d ci rebuild > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) + - spack --color=always --backtrace ci rebuild > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) image: { "name": "ghcr.io/spack/e4s-amazonlinux-2:v2022-03-21", "entrypoint": [""] } match_behavior: first diff --git a/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws/spack.yaml index 9c1347ac259..1cf3b80cbb1 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws/spack.yaml @@ -69,7 +69,7 @@ spack: - mkdir -p ${SPACK_ARTIFACTS_ROOT}/user_data - if [[ -r /mnt/key/intermediate_ci_signing_key.gpg ]]; then spack gpg trust /mnt/key/intermediate_ci_signing_key.gpg; fi - if [[ -r /mnt/key/spack_public_key.gpg ]]; then spack gpg trust /mnt/key/spack_public_key.gpg; fi - - spack -d ci rebuild > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) + - spack --color=always --backtrace ci rebuild > >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_out.txt) 2> >(tee ${SPACK_ARTIFACTS_ROOT}/user_data/pipeline_err.txt >&2) image: { "name": "ghcr.io/spack/e4s-amazonlinux-2:v2022-03-21", "entrypoint": [""] } match_behavior: first diff --git a/share/spack/gitlab/cloud_pipelines/stacks/radiuss/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/radiuss/spack.yaml index b43c4ebdcfa..9b6a54a8614 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/radiuss/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/radiuss/spack.yaml @@ -71,7 +71,7 @@ spack: - spack config add "config:install_tree:projections:${SPACK_JOB_SPEC_PKG_NAME}:'morepadding/{architecture}/{compiler.name}-{compiler.version}/{name}-{version}-{hash}'" - if [[ -r /mnt/key/intermediate_ci_signing_key.gpg ]]; then spack gpg trust /mnt/key/intermediate_ci_signing_key.gpg; fi - if [[ -r /mnt/key/spack_public_key.gpg ]]; then spack gpg trust /mnt/key/spack_public_key.gpg; fi - - spack -d ci rebuild + - spack --color=always --backtrace ci rebuild match_behavior: first mappings: - match: diff --git a/share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml index dc91bf32082..3c81bb5f653 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml @@ -71,7 +71,7 @@ spack: - spack config add "config:install_tree:projections:${SPACK_JOB_SPEC_PKG_NAME}:'morepadding/{architecture}/{compiler.name}-{compiler.version}/{name}-{version}-{hash}'" - if [[ -r /mnt/key/intermediate_ci_signing_key.gpg ]]; then spack gpg trust /mnt/key/intermediate_ci_signing_key.gpg; fi - if [[ -r /mnt/key/spack_public_key.gpg ]]; then spack gpg trust /mnt/key/spack_public_key.gpg; fi - - spack -d ci rebuild + - spack --color=always --backtrace ci rebuild image: { "name": "ghcr.io/spack/tutorial-ubuntu-18.04:v2021-11-02", "entrypoint": [""] } match_behavior: first From 4b237349a32798bbdfd55e8c41f9d79180ce2cf2 Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Tue, 25 Oct 2022 12:27:13 +0200 Subject: [PATCH 178/442] Remove recursive symbolic link in lib/spack/docs from git repository (#33483) Delete code removing the symlink during CI --- .github/workflows/unit_tests.yaml | 3 --- .github/workflows/windows_python.yml | 2 -- lib/spack/docs/_spack_root | 1 - lib/spack/docs/conf.py | 3 +++ share/spack/qa/run-shell-tests | 6 ------ share/spack/qa/run-unit-tests | 4 ---- 6 files changed, 3 insertions(+), 16 deletions(-) delete mode 120000 lib/spack/docs/_spack_root diff --git a/.github/workflows/unit_tests.yaml b/.github/workflows/unit_tests.yaml index d2d267b516c..1d84e5bfebe 100644 --- a/.github/workflows/unit_tests.yaml +++ b/.github/workflows/unit_tests.yaml @@ -221,9 +221,6 @@ jobs: $(which spack) unit-test --cov --cov-config=pyproject.toml "${common_args[@]}" coverage combine -a coverage xml - # Delete the symlink going from ./lib/spack/docs/_spack_root back to - # the initial directory, since it causes ELOOP errors with codecov/actions@2 - rm lib/spack/docs/_spack_root - uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 with: flags: unittests,macos diff --git a/.github/workflows/windows_python.yml b/.github/workflows/windows_python.yml index adb8344d94e..5acc87af708 100644 --- a/.github/workflows/windows_python.yml +++ b/.github/workflows/windows_python.yml @@ -32,7 +32,6 @@ jobs: echo F|xcopy .\spack\share\spack\qa\configuration\windows_config.yaml $env:USERPROFILE\.spack\windows\config.yaml cd spack dir - (Get-Item '.\lib\spack\docs\_spack_root').Delete() spack unit-test --verbose --cov --cov-config=pyproject.toml --ignore=lib/spack/spack/test/cmd coverage combine -a coverage xml @@ -58,7 +57,6 @@ jobs: run: | echo F|xcopy .\spack\share\spack\qa\configuration\windows_config.yaml $env:USERPROFILE\.spack\windows\config.yaml cd spack - (Get-Item '.\lib\spack\docs\_spack_root').Delete() spack unit-test --verbose --cov --cov-config=pyproject.toml lib/spack/spack/test/cmd coverage combine -a coverage xml diff --git a/lib/spack/docs/_spack_root b/lib/spack/docs/_spack_root deleted file mode 120000 index a8a4f8c2127..00000000000 --- a/lib/spack/docs/_spack_root +++ /dev/null @@ -1 +0,0 @@ -../../.. \ No newline at end of file diff --git a/lib/spack/docs/conf.py b/lib/spack/docs/conf.py index 542a3d90246..1bdce87238e 100644 --- a/lib/spack/docs/conf.py +++ b/lib/spack/docs/conf.py @@ -32,6 +32,9 @@ # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. +link_name = os.path.abspath("_spack_root") +if not os.path.exists(link_name): + os.symlink(os.path.abspath("../../.."), link_name, target_is_directory=True) sys.path.insert(0, os.path.abspath("_spack_root/lib/spack/external")) sys.path.insert(0, os.path.abspath("_spack_root/lib/spack/external/pytest-fallback")) diff --git a/share/spack/qa/run-shell-tests b/share/spack/qa/run-shell-tests index a300bee98bf..465c68000e5 100755 --- a/share/spack/qa/run-shell-tests +++ b/share/spack/qa/run-shell-tests @@ -56,9 +56,3 @@ fish "$QA_DIR/setup-env-test.fish" # run csh and tcsh tests csh "$QA_DIR/setup-env-test.csh" tcsh "$QA_DIR/setup-env-test.csh" - -# Delete the symlink going from ./lib/spack/docs/_spack_root back to -# the initial directory, since it causes ELOOP errors with codecov/actions@2 -if [[ "$COVERAGE" == "true" ]]; then - rm lib/spack/docs/_spack_root -fi diff --git a/share/spack/qa/run-unit-tests b/share/spack/qa/run-unit-tests index 2de6b6101d3..478e5822425 100755 --- a/share/spack/qa/run-unit-tests +++ b/share/spack/qa/run-unit-tests @@ -74,7 +74,3 @@ fi bash "$QA_DIR/test-env-cfg.sh" - -# Delete the symlink going from ./lib/spack/docs/_spack_root back to -# the initial directory, since it causes ELOOP errors with codecov/actions@2 -rm lib/spack/docs/_spack_root From 62526c10853087b279d0ba4f0a01fe64b2c92d66 Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Tue, 25 Oct 2022 13:04:25 +0200 Subject: [PATCH 179/442] Make CI on Windows fail fast (#33502) --- .github/workflows/windows_python.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/windows_python.yml b/.github/workflows/windows_python.yml index 5acc87af708..f1b828ceaa2 100644 --- a/.github/workflows/windows_python.yml +++ b/.github/workflows/windows_python.yml @@ -32,7 +32,7 @@ jobs: echo F|xcopy .\spack\share\spack\qa\configuration\windows_config.yaml $env:USERPROFILE\.spack\windows\config.yaml cd spack dir - spack unit-test --verbose --cov --cov-config=pyproject.toml --ignore=lib/spack/spack/test/cmd + spack unit-test -x --verbose --cov --cov-config=pyproject.toml --ignore=lib/spack/spack/test/cmd coverage combine -a coverage xml - uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 @@ -57,7 +57,7 @@ jobs: run: | echo F|xcopy .\spack\share\spack\qa\configuration\windows_config.yaml $env:USERPROFILE\.spack\windows\config.yaml cd spack - spack unit-test --verbose --cov --cov-config=pyproject.toml lib/spack/spack/test/cmd + spack unit-test -x --verbose --cov --cov-config=pyproject.toml lib/spack/spack/test/cmd coverage combine -a coverage xml - uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 From 00ae74f40e4ac918f4826bf3fb61da6f28af5051 Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Tue, 25 Oct 2022 13:46:47 +0200 Subject: [PATCH 180/442] Update Spack Dockerfiles (#33500) * Use spack bootstrap now in containers * Fix wrong path glob expression --- .github/workflows/build-containers.yml | 2 +- share/spack/templates/container/bootstrap-base.dockerfile | 2 +- share/spack/templates/container/leap-15.dockerfile | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-containers.yml b/.github/workflows/build-containers.yml index 940e9d965fb..83647e4ad17 100644 --- a/.github/workflows/build-containers.yml +++ b/.github/workflows/build-containers.yml @@ -13,7 +13,7 @@ on: paths: - '.github/workflows/build-containers.yml' - 'share/spack/docker/*' - - 'share/templates/container/*' + - 'share/spack/templates/container/*' - 'lib/spack/spack/container/*' # Let's also build & tag Spack containers on releases. release: diff --git a/share/spack/templates/container/bootstrap-base.dockerfile b/share/spack/templates/container/bootstrap-base.dockerfile index 0674ddd5412..e002cce02e1 100644 --- a/share/spack/templates/container/bootstrap-base.dockerfile +++ b/share/spack/templates/container/bootstrap-base.dockerfile @@ -39,7 +39,7 @@ WORKDIR /root SHELL ["docker-shell"] # Creates the package cache -RUN spack spec hdf5+mpi +RUN spack bootstrap now && spack spec hdf5+mpi ENTRYPOINT ["/bin/bash", "/opt/spack/share/spack/docker/entrypoint.bash"] CMD ["interactive-shell"] diff --git a/share/spack/templates/container/leap-15.dockerfile b/share/spack/templates/container/leap-15.dockerfile index 38e4f1c0096..2427c377545 100644 --- a/share/spack/templates/container/leap-15.dockerfile +++ b/share/spack/templates/container/leap-15.dockerfile @@ -12,7 +12,6 @@ RUN zypper ref && \ git\ gzip\ patch\ - patchelf\ python3-base \ python3-boto3\ tar\ From 09e0bd55c2ab2d4678efc693c3d3b79ef7c238f4 Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Tue, 25 Oct 2022 16:47:50 +0200 Subject: [PATCH 181/442] spec.py: prefer transitive link and direct build/run/test deps (#33498) Due to reuse concretization, we may generate DAGs with two occurrences of the same package corresponding to distinct specs. This happens when build dependencies are reused, since their dependencies are ignored in concretization. This caused a regression, for example: `spec['openssl']` would take the 'openssl' of the build dep `cmake`, instead of the direct `openssl` dependency, simply because the edge to `cmake` was traversed first and we do depth first traversal. One solution that was discussed is to limit `spec[name]` to just direct deps, or direct deps + transitive link deps, but this is too breaking. Instead, this PR simply prioritizes transitive link and direct build/run/test deps, and then falls back to a full DAG traversal. So, it's just about order of iteration. --- lib/spack/spack/spec.py | 15 ++++++++++++-- lib/spack/spack/test/spec_dag.py | 35 ++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py index 4c1421e1e8e..9256be5803d 100644 --- a/lib/spack/spack/spec.py +++ b/lib/spack/spack/spec.py @@ -3970,12 +3970,23 @@ def __getitem__(self, name): csv = query_parameters.pop().strip() query_parameters = re.split(r"\s*,\s*", csv) + # In some cases a package appears multiple times in the same DAG for *distinct* + # specs. For example, a build-type dependency may itself depend on a package + # the current spec depends on, but their specs may differ. Therefore we iterate + # in an order here that prioritizes the build, test and runtime dependencies; + # only when we don't find the package do we consider the full DAG. + order = lambda: itertools.chain( + self.traverse(deptype="link"), + self.dependencies(deptype=("build", "run", "test")), + self.traverse(), # fall back to a full search + ) + try: value = next( itertools.chain( # Regular specs - (x for x in self.traverse() if x.name == name), - (x for x in self.traverse() if (not x.virtual) and x.package.provides(name)), + (x for x in order() if x.name == name), + (x for x in order() if (not x.virtual) and x.package.provides(name)), ) ) except StopIteration: diff --git a/lib/spack/spack/test/spec_dag.py b/lib/spack/spack/test/spec_dag.py index 66e5a0bc2fd..898ae15f74f 100644 --- a/lib/spack/spack/test/spec_dag.py +++ b/lib/spack/spack/test/spec_dag.py @@ -1068,3 +1068,38 @@ def test_adding_same_deptype_with_the_same_name_raises( p.add_dependency_edge(c1, deptype=c1_deptypes) with pytest.raises(spack.error.SpackError): p.add_dependency_edge(c2, deptype=c2_deptypes) + + +@pytest.mark.regression("33499") +def test_indexing_prefers_direct_or_transitive_link_deps(): + # Test whether spec indexing prefers direct/transitive link type deps over deps of + # build/run/test deps, and whether it does fall back to a full dag search. + root = Spec("root") + + # Use a and z to since we typically traverse by edges sorted alphabetically. + a1 = Spec("a1") + a2 = Spec("a2") + z1 = Spec("z1") + z2 = Spec("z2") + + # Same package, different spec. + z3_flavor_1 = Spec("z3 +through_a1") + z3_flavor_2 = Spec("z3 +through_z1") + + root.add_dependency_edge(a1, deptype=("build", "run", "test")) + + # unique package as a dep of a build/run/test type dep. + a1.add_dependency_edge(a2, deptype="all") + a1.add_dependency_edge(z3_flavor_1, deptype="all") + + # chain of link type deps root -> z1 -> z2 -> z3 + root.add_dependency_edge(z1, deptype="link") + z1.add_dependency_edge(z2, deptype="link") + z2.add_dependency_edge(z3_flavor_2, deptype="link") + + # Indexing should prefer the link-type dep. + assert "through_z1" in root["z3"].variants + assert "through_a1" in a1["z3"].variants + + # Ensure that the full DAG is still searched + assert root["a2"] From d2e75045b8a5e094d1c9772a0f2cd762cf3ce21b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lacroix?= Date: Tue, 25 Oct 2022 19:40:08 +0200 Subject: [PATCH 182/442] Gmsh: Fix CGNS support for version up to 4.7.1 (#33508) Gmsh started supporting the "scoping" option of CGNS in version 4.8.0. --- var/spack/repos/builtin/packages/gmsh/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/gmsh/package.py b/var/spack/repos/builtin/packages/gmsh/package.py index 5f8166b2d8c..9651333ce95 100644 --- a/var/spack/repos/builtin/packages/gmsh/package.py +++ b/var/spack/repos/builtin/packages/gmsh/package.py @@ -91,6 +91,7 @@ class Gmsh(CMakePackage): depends_on("zlib", when="+compression") depends_on("metis", when="+metis+external") depends_on("cgns", when="+cgns") + depends_on("cgns~scoping", when="+cgns @:4.7.1") with when("+petsc"): depends_on("petsc~int64") depends_on("petsc+mpi", when="+mpi") From 9d5151ba25394b35ff7fc4b06b858c53e638ec5d Mon Sep 17 00:00:00 2001 From: Jonathon Anderson <17242663+blue42u@users.noreply.github.com> Date: Tue, 25 Oct 2022 13:36:12 -0500 Subject: [PATCH 183/442] BinaryCacheIndex: track update failures with cooldown (#33509) #32137 added an option to update() a BinaryCacheIndex with a cooldown: repeated attempts within this cooldown would not actually retry. However, the cooldown was not properly tracked for failures (which is common when the mirror does not store any binaries and therefore has no index.json). This commit ensures that update(..., with_cooldown=True) will also skip the update even if a failure has occurred within the cooldown period. --- lib/spack/spack/binary_distribution.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/spack/spack/binary_distribution.py b/lib/spack/spack/binary_distribution.py index 3f74d91a9e8..d8ac0bb1fa0 100644 --- a/lib/spack/spack/binary_distribution.py +++ b/lib/spack/spack/binary_distribution.py @@ -107,7 +107,8 @@ def __init__(self, cache_root): # cache (_mirrors_for_spec) self._specs_already_associated = set() - # mapping from mirror urls to the time.time() of the last index fetch. + # mapping from mirror urls to the time.time() of the last index fetch and a bool indicating + # whether the fetch succeeded or not. self._last_fetch_times = {} # _mirrors_for_spec is a dictionary mapping DAG hashes to lists of @@ -346,21 +347,25 @@ def update(self, with_cooldown=False): with_cooldown and ttl > 0 and cached_mirror_url in self._last_fetch_times - and now - self._last_fetch_times[cached_mirror_url] < ttl + and now - self._last_fetch_times[cached_mirror_url][0] < ttl ): - # The fetch worked last time, so don't error - all_methods_failed = False + # We're in the cooldown period, don't try to fetch again + # If the fetch succeeded last time, consider this update a success, otherwise + # re-report the error here + if self._last_fetch_times[cached_mirror_url][1]: + all_methods_failed = False else: # May need to fetch the index and update the local caches try: needs_regen = self._fetch_and_cache_index( cached_mirror_url, expect_hash=cached_index_hash ) - self._last_fetch_times[cached_mirror_url] = now + self._last_fetch_times[cached_mirror_url] = (now, True) all_methods_failed = False except FetchCacheError as fetch_error: needs_regen = False fetch_errors.extend(fetch_error.errors) + self._last_fetch_times[cached_mirror_url] = (now, False) # The need to regenerate implies a need to clear as well. spec_cache_clear_needed |= needs_regen spec_cache_regenerate_needed |= needs_regen @@ -392,11 +397,12 @@ def update(self, with_cooldown=False): # Need to fetch the index and update the local caches try: needs_regen = self._fetch_and_cache_index(mirror_url) - self._last_fetch_times[mirror_url] = now + self._last_fetch_times[mirror_url] = (now, True) all_methods_failed = False except FetchCacheError as fetch_error: fetch_errors.extend(fetch_error.errors) needs_regen = False + self._last_fetch_times[mirror_url] = (now, False) # Generally speaking, a new mirror wouldn't imply the need to # clear the spec cache, so leave it as is. if needs_regen: From 512f8d14d28ab4fe0667905b899efed1f785c755 Mon Sep 17 00:00:00 2001 From: Tamara Dahlgren <35777542+tldahlgren@users.noreply.github.com> Date: Tue, 25 Oct 2022 12:32:55 -0700 Subject: [PATCH 184/442] feature: Add -x|--explicit option to 'spack test run' (#32910) --- lib/spack/spack/cmd/test.py | 18 ++++++++++++++++-- lib/spack/spack/test/ci.py | 8 ++++---- share/spack/spack-completion.bash | 2 +- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/lib/spack/spack/cmd/test.py b/lib/spack/spack/cmd/test.py index fcd72a123e5..4da35c8a35d 100644 --- a/lib/spack/spack/cmd/test.py +++ b/lib/spack/spack/cmd/test.py @@ -54,6 +54,12 @@ def setup_parser(subparser): run_parser.add_argument( "--externals", action="store_true", help="Test packages that are externally installed." ) + run_parser.add_argument( + "-x", + "--explicit", + action="store_true", + help="Only test packages that are explicitly installed.", + ) run_parser.add_argument( "--keep-stage", action="store_true", help="Keep testing directory for debugging" ) @@ -188,6 +194,9 @@ def test_run(args): if args.fail_fast: spack.config.set("config:fail_fast", True, scope="command_line") + explicit = args.explicit or any + explicit_str = "explicitly " if args.explicit else "" + # Get specs to test env = ev.active_environment() hashes = env.all_hashes() if env else None @@ -195,9 +204,13 @@ def test_run(args): specs = spack.cmd.parse_specs(args.specs) if args.specs else [None] specs_to_test = [] for spec in specs: - matching = spack.store.db.query_local(spec, hashes=hashes) + matching = spack.store.db.query_local( + spec, + hashes=hashes, + explicit=explicit, + ) if spec and not matching: - tty.warn("No installed packages match spec %s" % spec) + tty.warn("No {0}installed packages match spec {1}".format(explicit_str, spec)) """ TODO: Need to write out a log message and/or CDASH Testing output that package not installed IF continue to process @@ -208,6 +221,7 @@ def test_run(args): # to ensure report package as skipped (e.g., for CI) specs_to_test.append(spec) """ + specs_to_test.extend(matching) # test_stage_dir diff --git a/lib/spack/spack/test/ci.py b/lib/spack/spack/test/ci.py index b2c83ca2a99..06f212d92a3 100644 --- a/lib/spack/spack/test/ci.py +++ b/lib/spack/spack/test/ci.py @@ -467,7 +467,7 @@ def test_affected_specs_on_first_concretization(mutable_mock_env_path, config): @pytest.mark.skipif( - sys.platform == "win32", reason="Reliance on bash script ot supported on Windows" + sys.platform == "win32", reason="Reliance on bash script not supported on Windows" ) def test_ci_process_command(tmpdir): repro_dir = tmpdir.join("repro_dir").strpath @@ -479,7 +479,7 @@ def test_ci_process_command(tmpdir): @pytest.mark.skipif( - sys.platform == "win32", reason="Reliance on bash script ot supported on Windows" + sys.platform == "win32", reason="Reliance on bash script not supported on Windows" ) def test_ci_process_command_fail(tmpdir, monkeypatch): import subprocess @@ -526,7 +526,7 @@ def test_ci_run_standalone_tests_missing_requirements( @pytest.mark.skipif( - sys.platform == "win32", reason="Reliance on bash script ot supported on Windows" + sys.platform == "win32", reason="Reliance on bash script not supported on Windows" ) def test_ci_run_standalone_tests_not_installed_junit( tmpdir, working_env, config, mock_packages, mock_test_stage, capfd @@ -547,7 +547,7 @@ def test_ci_run_standalone_tests_not_installed_junit( @pytest.mark.skipif( - sys.platform == "win32", reason="Reliance on bash script ot supported on Windows" + sys.platform == "win32", reason="Reliance on bash script not supported on Windows" ) def test_ci_run_standalone_tests_not_installed_cdash( tmpdir, working_env, config, mock_packages, mock_test_stage, capfd diff --git a/share/spack/spack-completion.bash b/share/spack/spack-completion.bash index dac7f67f997..48e4c86b42f 100755 --- a/share/spack/spack-completion.bash +++ b/share/spack/spack-completion.bash @@ -1738,7 +1738,7 @@ _spack_test() { _spack_test_run() { if $list_options then - SPACK_COMPREPLY="-h --help --alias --fail-fast --fail-first --externals --keep-stage --log-format --log-file --cdash-upload-url --cdash-build --cdash-site --cdash-track --cdash-buildstamp --help-cdash --clean --dirty" + SPACK_COMPREPLY="-h --help --alias --fail-fast --fail-first --externals -x --explicit --keep-stage --log-format --log-file --cdash-upload-url --cdash-build --cdash-site --cdash-track --cdash-buildstamp --help-cdash --clean --dirty" else _installed_packages fi From 649e2d3e2823d1aa276a6dc0edd8456a5536347d Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Tue, 25 Oct 2022 21:48:24 +0200 Subject: [PATCH 185/442] depfile: resurrect lost touch (#33504) --- share/spack/templates/depfile/Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/share/spack/templates/depfile/Makefile b/share/spack/templates/depfile/Makefile index 5078f0016f1..dc0aeb79ea2 100644 --- a/share/spack/templates/depfile/Makefile +++ b/share/spack/templates/depfile/Makefile @@ -18,6 +18,9 @@ SPACK ?= spack {{ jobserver_support }}$(SPACK) -e '{{ environment }}' install $(SPACK_BUILDCACHE_FLAG) $(SPACK_INSTALL_FLAGS) --only-concrete --only=package --no-add /$(notdir $@) # $(SPEC) @touch $@ +{{ install_deps_target }}/%: | {{ dirs_target }} + @touch $@ + # Set a human-readable SPEC variable for each target that has a hash {% for (parent, name, build_cache, _) in adjacency_list -%} {{ any_hash_target }}/{{ parent }}: SPEC = {{ name }} From 10aa6bdfc1619f01b9f908e450a72a645e2ff0b7 Mon Sep 17 00:00:00 2001 From: Dom Heinzeller Date: Tue, 25 Oct 2022 13:52:01 -0600 Subject: [PATCH 186/442] Update wgrib2 from JCSDA/NOAA-EMC fork (#32857) * Update wgrib2 from JCSDA/NOAA-EMC fork * var/spack/repos/builtin/packages/wgrib2/package.py: fix typo in comment, add conflict for variants netcdf3, netcdf4 * wget hdf5/netcdf4 internal dependencies for wgrib2 * Black-format var/spack/repos/builtin/packages/wgrib2/package.py * More format changes in var/spack/repos/builtin/packages/wgrib2/package.py --- .../repos/builtin/packages/wgrib2/package.py | 203 ++++++++++++++++-- 1 file changed, 189 insertions(+), 14 deletions(-) diff --git a/var/spack/repos/builtin/packages/wgrib2/package.py b/var/spack/repos/builtin/packages/wgrib2/package.py index aa505e7c140..2f2c1409333 100644 --- a/var/spack/repos/builtin/packages/wgrib2/package.py +++ b/var/spack/repos/builtin/packages/wgrib2/package.py @@ -3,15 +3,17 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import os +import re + from spack.package import * -class Wgrib2(CMakePackage): - """The wgrib2 package functionality for interacting with, reading, - writing, and manipulating GRIB2 files.""" +class Wgrib2(MakefilePackage): + """Utility for interacting with GRIB2 files""" homepage = "https://www.cpc.ncep.noaa.gov/products/wesley/wgrib2" - url = "https://github.com/NOAA-EMC/NCEPLIBS-wgrib2/archive/refs/tags/v2.0.8-cmake-v6.tar.gz" + url = "https://www.ftp.cpc.ncep.noaa.gov/wd51we/wgrib2/wgrib2.tgz.v2.0.8" maintainers = [ "t-brown", @@ -21,16 +23,189 @@ class Wgrib2(CMakePackage): ] version( - "2.0.8-cmake-v6", sha256="745cd008b4ce0245ea44247733e57e2b9ec6c5205d171d457e18d0ff8f87172d" + "3.1.1", + sha256="9236f6afddad76d868c2cfdf5c4227f5bdda5e85ae40c18bafb37218e49bc04a", + extension="tar.gz", + ) + version( + "3.1.0", + sha256="5757ef9016b19ae87491918e0853dce2d3616b14f8c42efe3b2f41219c16b78f", + extension="tar.gz", + ) + version( + "2.0.8", + sha256="5e6a0d6807591aa2a190d35401606f7e903d5485719655aea1c4866cc2828160", + extension="tar.gz", + ) + version( + "2.0.7", + sha256="d7f1a4f9872922c62b3c7818c022465532cca1f5666b75d3ac5735f0b2747793", + extension="tar.gz", ) - depends_on("ip2") - depends_on("jasper@:2.0.32") - depends_on("libpng") - depends_on("netcdf-c") - depends_on("netcdf-fortran") - depends_on("sp") + variant("netcdf3", default=True, description="Link in netcdf3 library to write netcdf3 files") + variant( + "netcdf4", default=False, description="Link in netcdf4 library to write netcdf3/4 files" + ) + variant( + "ipolates", + default="3", + description="Use to interpolate to new grids (0 = OFF, 1 = ip, 3 = ip2)", + values=("0", "1", "3"), + ) + variant("spectral", default=False, description="Spectral interpolation in -new_grid") + variant( + "fortran_api", + default=True, + description="Make wgrib2api which allows fortran code to read/write grib2", + ) + variant( + "mysql", default=False, description="Link in interface to MySQL to write to mysql database" + ) + variant( + "udf", + default=False, + description="Add commands for user-defined functions and shell commands", + ) + variant("regex", default=True, description="Use regular expression library (POSIX-2)") + variant("tigge", default=True, description="Ability for TIGGE-like variable names") + variant("proj4", default=False, description="The proj4 library is used to verify gctpc.") + variant( + "aec", default=True, description="Use the libaec library for packing with GRIB2 template" + ) + variant("g2c", default=False, description="Include NCEP g2clib (mainly for testing purposes)") + variant( + "disable_timezone", default=False, description="Some machines do not support timezones" + ) + variant( + "disable_alarm", + default=False, + description="Some machines do not support the alarm to terminate wgrib2", + ) + variant("png", default=True, description="PNG encoding") + variant("jasper", default=True, description="JPEG compression using Jasper") + variant("openmp", default=True, description="OpenMP parallelization") + variant("wmo_validation", default=False, description="WMO validation") - def cmake_args(self): - args = ["-DUSE_IPOLATES=3", "-DUSE_SPECTRAL=BOOL:ON"] - return args + conflicts("+netcdf3", when="+netcdf4") + conflicts("+openmp", when="%apple-clang") + + depends_on("wget", type=("build"), when="+netcdf4") + + variant_map = { + "netcdf3": "USE_NETCDF3", + "netcdf4": "USE_NETCDF4", + "spectral": "USE_SPECTRAL", + "mysql": "USE_MYSQL", + "udf": "USE_UDF", + "regex": "USE_REGEX", + "tigge": "USE_TIGGE", + "proj4": "USE_PROJ4", + "aec": "USE_AEC", + "g2c": "USE_G2CLIB", + "png": "USE_PNG", + "jasper": "USE_JASPER", + "openmp": "USE_OPENMP", + "wmo_validation": "USE_WMO_VALIDATION", + "ipolates": "USE_IPOLATES", + "disable_timezone": "DISABLE_TIMEZONE", + "disable_alarm": "DISABLE_ALARM", + "fortran_api": "MAKE_FTN_API", + } + + # Disable parallel build + parallel = False + + # Use Spack compiler wrapper flags + def inject_flags(self, name, flags): + if name == "cflags": + if self.spec.compiler.name == "apple-clang": + flags.append("-Wno-error=implicit-function-declaration") + + # When mixing Clang/gfortran need to link to -lgfortran + # Find this by searching for gfortran/../lib + if self.spec.compiler.name in ["apple-clang", "clang"]: + if "gfortran" in self.compiler.fc: + output = Executable(self.compiler.fc)("-###", output=str, error=str) + libdir = re.search("--libdir=(.+?) ", output).group(1) + flags.append("-L{}".format(libdir)) + + return (flags, None, None) + + flag_handler = inject_flags + + def url_for_version(self, version): + url = "https://www.ftp.cpc.ncep.noaa.gov/wd51we/wgrib2/wgrib2.tgz.v{}" + return url.format(version) + + def edit(self, spec, prefix): + makefile = FileFilter("makefile") + + # ifort no longer accepts -openmp + makefile.filter(r"-openmp", "-qopenmp") + makefile.filter(r"-Wall", " ") + makefile.filter(r"-Werror=format-security", " ") + + # clang doesn"t understand --fast-math + if spec.satisfies("%clang") or spec.satisfies("%apple-clang"): + makefile.filter(r"--fast-math", "-ffast-math") + + for variant_name, makefile_option in self.variant_map.items(): + value = int(spec.variants[variant_name].value) + makefile.filter(r"^%s=.*" % makefile_option, "{}={}".format(makefile_option, value)) + + def setup_build_environment(self, env): + + if self.spec.compiler.name in "intel": + comp_sys = "intel_linux" + elif self.spec.compiler.name in ["gcc", "clang", "apple-clang"]: + comp_sys = "gnu_linux" + + env.set("COMP_SYS", comp_sys) + + def build(self, spec, prefix): + + # Get source files for netCDF4 builds + if self.spec.satisfies("+netcdf4"): + with working_dir(self.build_directory): + os.system( + "wget https://downloads.unidata.ucar.edu/netcdf-c/4.8.1/netcdf-c-4.8.1.tar.gz" + ) + os.system( + "wget https://support.hdfgroup.org/ftp/HDF5/releases/hdf5-1.12/hdf5-1.12.1/src/hdf5-1.12.1.tar.gz" + ) + + make() + + # Move wgrib2 executable to a tempoary directory + mkdir("install") + mkdir(join_path("install", "bin")) + move(join_path("wgrib2", "wgrib2"), join_path("install", "bin")) + + # Build wgrib2 library by disabling all options + # and enabling only MAKE_FTN_API=1 + if "+fortran_api" in spec: + make("clean") + make("deep-clean") + makefile = FileFilter("makefile") + + # Disable all options + for variant_name, makefile_option in self.variant_map.items(): + value = 0 + makefile.filter( + r"^%s=.*" % makefile_option, "{}={}".format(makefile_option, value) + ) + + # Need USE_REGEX in addition to MAKE_FTN_API to build lib + makefile.filter(r"^MAKE_FTN_API=.*", "MAKE_FTN_API=1") + makefile.filter(r"^USE_REGEX=.*", "USE_REGEX=1") + make("lib") + mkdir(join_path("install", "lib")) + mkdir(join_path("install", "include")) + + move(join_path("lib", "libwgrib2.a"), join_path("install", "lib")) + move(join_path("lib", "wgrib2api.mod"), join_path("install", "include")) + move(join_path("lib", "wgrib2lowapi.mod"), join_path("install", "include")) + + def install(self, spec, prefix): + install_tree("install/", prefix) From 8aa975802454f453b09707c98ee1023bb220b992 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lacroix?= Date: Tue, 25 Oct 2022 22:06:52 +0200 Subject: [PATCH 187/442] udunits: Update download URL (#32390) * udunits: Update download URL * udunits: Deprecate older versions Unidata now only provides the latest version of each X.Y branch. Older 2.2 versions have been deprecated accordingly but are still available in the build cache. Co-authored-by: RemiLacroix-IDRIS Co-authored-by: Tamara Dahlgren <35777542+tldahlgren@users.noreply.github.com> --- .../repos/builtin/packages/udunits/package.py | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/var/spack/repos/builtin/packages/udunits/package.py b/var/spack/repos/builtin/packages/udunits/package.py index ea59de0ef8e..dcce887f5d6 100644 --- a/var/spack/repos/builtin/packages/udunits/package.py +++ b/var/spack/repos/builtin/packages/udunits/package.py @@ -10,11 +10,26 @@ class Udunits(AutotoolsPackage): """Automated units conversion""" homepage = "https://www.unidata.ucar.edu/software/udunits" - url = "https://artifacts.unidata.ucar.edu/repository/downloads-udunits/udunits-2.2.28.tar.gz" + url = "https://artifacts.unidata.ucar.edu/repository/downloads-udunits/2.2.28/udunits-2.2.28.tar.gz" + # Unidata now only provides the latest version of each X.Y branch. + # Older 2.2 versions have been deprecated accordingly but are still + # available in the build cache. version("2.2.28", sha256="590baec83161a3fd62c00efa66f6113cec8a7c461e3f61a5182167e0cc5d579e") - version("2.2.24", sha256="20bac512f2656f056385429a0e44902fdf02fc7fe01c14d56f3c724336177f95") - version("2.2.23", sha256="b745ae10753fe82cdc7cc834e6ce471ca7c25ba2662e6ff93be147cb3d4fd380") - version("2.2.21", sha256="a154d1f8428c24e92723f9e50bdb5cc00827e3f5ff9cba64d33e5409f5c03455") + version( + "2.2.24", + sha256="20bac512f2656f056385429a0e44902fdf02fc7fe01c14d56f3c724336177f95", + deprecated=True, + ) + version( + "2.2.23", + sha256="b745ae10753fe82cdc7cc834e6ce471ca7c25ba2662e6ff93be147cb3d4fd380", + deprecated=True, + ) + version( + "2.2.21", + sha256="a154d1f8428c24e92723f9e50bdb5cc00827e3f5ff9cba64d33e5409f5c03455", + deprecated=True, + ) depends_on("expat") From b538acb2a9ea93fc475577883c6b60c7a8f1a591 Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Wed, 26 Oct 2022 00:15:16 +0200 Subject: [PATCH 188/442] binary_distribution: compress level 9 -> 6 (#33513) Use the same compression level as `gzip` (6) instead of what Python uses (9). The LLVM tarball takes 4m instead of 12m to create, and is <1% larger. That's not worth the wait... --- lib/spack/spack/binary_distribution.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/spack/spack/binary_distribution.py b/lib/spack/spack/binary_distribution.py index d8ac0bb1fa0..d22572d8a41 100644 --- a/lib/spack/spack/binary_distribution.py +++ b/lib/spack/spack/binary_distribution.py @@ -1161,7 +1161,11 @@ def _build_tarball( tty.die(e) # create gzip compressed tarball of the install prefix - with closing(tarfile.open(tarfile_path, "w:gz")) as tar: + # On AMD Ryzen 3700X and an SSD disk, we have the following on compression speed: + # compresslevel=6 gzip default: llvm takes 4mins, roughly 2.1GB + # compresslevel=9 python default: llvm takes 12mins, roughly 2.1GB + # So we follow gzip. + with closing(tarfile.open(tarfile_path, "w:gz", compresslevel=6)) as tar: tar.add(name="%s" % workdir, arcname="%s" % os.path.basename(spec.prefix)) # remove copy of install directory shutil.rmtree(workdir) From 7b053fde892d236dd6f3ece849b0258a2ec53557 Mon Sep 17 00:00:00 2001 From: Luke Diorio-Toth Date: Tue, 25 Oct 2022 18:08:56 -0500 Subject: [PATCH 189/442] New packages: mlst, any2fasta, perl-carp, perl-class-method-modifiers, perl-role-tiny, perl-moo, perl-sub-quote (#33274) * added mlst and deps * added install() to any2fasta * added script dependencies, builds OK * fixed style * Update var/spack/repos/builtin/packages/any2fasta/package.py Co-authored-by: Tamara Dahlgren <35777542+tldahlgren@users.noreply.github.com> --- .../builtin/packages/any2fasta/package.py | 24 +++++++++++++ .../repos/builtin/packages/mlst/package.py | 36 +++++++++++++++++++ .../builtin/packages/perl-carp/package.py | 19 ++++++++++ .../perl-class-method-modifiers/package.py | 19 ++++++++++ .../builtin/packages/perl-moo/package.py | 23 ++++++++++++ .../packages/perl-role-tiny/package.py | 18 ++++++++++ .../packages/perl-sub-quote/package.py | 18 ++++++++++ 7 files changed, 157 insertions(+) create mode 100644 var/spack/repos/builtin/packages/any2fasta/package.py create mode 100644 var/spack/repos/builtin/packages/mlst/package.py create mode 100644 var/spack/repos/builtin/packages/perl-carp/package.py create mode 100644 var/spack/repos/builtin/packages/perl-class-method-modifiers/package.py create mode 100644 var/spack/repos/builtin/packages/perl-moo/package.py create mode 100644 var/spack/repos/builtin/packages/perl-role-tiny/package.py create mode 100644 var/spack/repos/builtin/packages/perl-sub-quote/package.py diff --git a/var/spack/repos/builtin/packages/any2fasta/package.py b/var/spack/repos/builtin/packages/any2fasta/package.py new file mode 100644 index 00000000000..4b9428767db --- /dev/null +++ b/var/spack/repos/builtin/packages/any2fasta/package.py @@ -0,0 +1,24 @@ +# 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 Any2fasta(Package): + """any2fasta: Convert various sequence formats to FASTA""" + + homepage = "https://github.com/tseemann/any2fasta" + url = "https://github.com/tseemann/any2fasta/archive/refs/tags/v0.4.2.tar.gz" + + version("0.4.2", sha256="e4cb2ddccda6298f5b0aee0c10184a75307a08b584d2abbfbf0d59d37b197e73") + version("0.2.3", sha256="197cd1e18adebe28b71a1448c5107804b7093b2aa83c4bcfd8edd3fc4ed485df") + version("0.1.2", sha256="ef035595756df7dca1f8a503ee26f8479393953bc67d8870c9965b6d5ade2674") + + depends_on("perl@5.10:", type=("build", "run")) + + def install(self, spec, prefix): + mkdirp(prefix.bin) + install("any2fasta", prefix.bin) diff --git a/var/spack/repos/builtin/packages/mlst/package.py b/var/spack/repos/builtin/packages/mlst/package.py new file mode 100644 index 00000000000..fb2b7b585cd --- /dev/null +++ b/var/spack/repos/builtin/packages/mlst/package.py @@ -0,0 +1,36 @@ +# 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 Mlst(Package): + """Scan contig files against traditional PubMLST typing schemes""" + + homepage = "https://github.com/tseemann/mlst" + url = "https://github.com/tseemann/mlst/archive/refs/tags/v2.22.1.tar.gz" + + version("2.22.1", sha256="a8f64d7cb961a8e422e96a19309ad8707f8792d9f755a9e5a1f5742986d19bca") + + depends_on("perl@5.26:", type="run") + depends_on("perl-moo", type="run") + depends_on("perl-list-moreutils", type="run") + depends_on("perl-json", type="run") + depends_on("perl-file-which", type="run") + depends_on("blast-plus@2.9.0:", type="run") + depends_on("any2fasta", type="run") + # dependencies for scripts + depends_on("parallel", type="run") + depends_on("curl", type="run") + + def install(self, spec, prefix): + mkdirp(prefix.bin) + mkdirp(prefix.db) + mkdirp(prefix.perl5) + install_tree("bin", prefix.bin) + install_tree("scripts", prefix.bin) + install_tree("db", prefix.db) + install_tree("perl5", prefix.perl5) diff --git a/var/spack/repos/builtin/packages/perl-carp/package.py b/var/spack/repos/builtin/packages/perl-carp/package.py new file mode 100644 index 00000000000..3b0dd441cd7 --- /dev/null +++ b/var/spack/repos/builtin/packages/perl-carp/package.py @@ -0,0 +1,19 @@ +# 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 PerlCarp(PerlPackage): + """Carp - alternative warn and die for modules""" + + homepage = "https://metacpan.org/pod/Carp" + url = "https://cpan.metacpan.org/authors/id/X/XS/XSAWYERX/Carp-1.50.tar.gz" + + version("1.50", sha256="f5273b4e1a6d51b22996c48cb3a3cbc72fd456c4038f5c20b127e2d4bcbcebd9") + + depends_on("perl-extutils-makemaker", type=("build", "run")) + depends_on("perl-test-more", type=("build", "run")) diff --git a/var/spack/repos/builtin/packages/perl-class-method-modifiers/package.py b/var/spack/repos/builtin/packages/perl-class-method-modifiers/package.py new file mode 100644 index 00000000000..a67a0c4c193 --- /dev/null +++ b/var/spack/repos/builtin/packages/perl-class-method-modifiers/package.py @@ -0,0 +1,19 @@ +# 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 PerlClassMethodModifiers(PerlPackage): + """Class::Method::Modifiers - Provides Moose-like method modifiers""" + + homepage = "https://metacpan.org/pod/Class::Method::Modifiers" + url = "https://cpan.metacpan.org/authors/id/E/ET/ETHER/Class-Method-Modifiers-2.13.tar.gz" + + version("2.13", sha256="ab5807f71018a842de6b7a4826d6c1f24b8d5b09fcce5005a3309cf6ea40fd63") + + depends_on("perl-carp", type=("build", "run")) + depends_on("perl-exporter-tiny", type=("build", "run")) diff --git a/var/spack/repos/builtin/packages/perl-moo/package.py b/var/spack/repos/builtin/packages/perl-moo/package.py new file mode 100644 index 00000000000..188ff7361b8 --- /dev/null +++ b/var/spack/repos/builtin/packages/perl-moo/package.py @@ -0,0 +1,23 @@ +# 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 PerlMoo(PerlPackage): + """Moo - Minimalist Object Orientation (with Moose compatibility)""" + + homepage = "https://metacpan.org/pod/Moo" + url = "https://cpan.metacpan.org/authors/id/H/HA/HAARG/Moo-2.005004.tar.gz" + + version("2.005004", sha256="e3030b80bd554a66f6b3c27fd53b1b5909d12af05c4c11ece9a58f8d1e478928") + + depends_on("perl-carp", type=("build", "run")) + depends_on("perl-class-method-modifiers", type=("build", "run")) + depends_on("perl-exporter-tiny", type=("build", "run")) + depends_on("perl-role-tiny", type=("build", "run")) + depends_on("perl-scalar-list-utils", type=("build", "run")) + depends_on("perl-sub-quote", type=("build", "run")) diff --git a/var/spack/repos/builtin/packages/perl-role-tiny/package.py b/var/spack/repos/builtin/packages/perl-role-tiny/package.py new file mode 100644 index 00000000000..96868dbb3a4 --- /dev/null +++ b/var/spack/repos/builtin/packages/perl-role-tiny/package.py @@ -0,0 +1,18 @@ +# 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 PerlRoleTiny(PerlPackage): + """Role::Tiny - Roles: a nouvelle cuisine portion size slice of Moose""" + + homepage = "https://metacpan.org/pod/Role::Tiny" + url = "https://cpan.metacpan.org/authors/id/H/HA/HAARG/Role-Tiny-2.002004.tar.gz" + + version("2.002004", sha256="d7bdee9e138a4f83aa52d0a981625644bda87ff16642dfa845dcb44d9a242b45") + + depends_on("perl-exporter-tiny", type=("build", "run")) diff --git a/var/spack/repos/builtin/packages/perl-sub-quote/package.py b/var/spack/repos/builtin/packages/perl-sub-quote/package.py new file mode 100644 index 00000000000..382afc31403 --- /dev/null +++ b/var/spack/repos/builtin/packages/perl-sub-quote/package.py @@ -0,0 +1,18 @@ +# 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 PerlSubQuote(PerlPackage): + """Sub::Quote - Efficient generation of subroutines via string eval""" + + homepage = "https://metacpan.org/pod/Sub::Quote" + url = "https://cpan.metacpan.org/authors/id/H/HA/HAARG/Sub-Quote-2.006006.tar.gz" + + version("2.006006", sha256="6e4e2af42388fa6d2609e0e82417de7cc6be47223f576592c656c73c7524d89d") + + depends_on("perl-scalar-list-utils", type=("build", "run")) From 53a76761d0dcd91c0833952306500edd3bdc2d28 Mon Sep 17 00:00:00 2001 From: MichaelLaufer <70094649+MichaelLaufer@users.noreply.github.com> Date: Wed, 26 Oct 2022 05:04:04 +0300 Subject: [PATCH 190/442] Scotch: 'link_error_lib' variant - Link error handling library to libscotch/libptscotch (#33297) --- .../repos/builtin/packages/py-pyfr/package.py | 2 +- .../libscotch-scotcherr-link-7.0.1.patch | 20 +++++++++++++++++++ .../repos/builtin/packages/scotch/package.py | 7 +++++++ 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 var/spack/repos/builtin/packages/scotch/libscotch-scotcherr-link-7.0.1.patch diff --git a/var/spack/repos/builtin/packages/py-pyfr/package.py b/var/spack/repos/builtin/packages/py-pyfr/package.py index 3e1d094c218..504f0e7e6bf 100644 --- a/var/spack/repos/builtin/packages/py-pyfr/package.py +++ b/var/spack/repos/builtin/packages/py-pyfr/package.py @@ -57,7 +57,7 @@ class PyPyfr(PythonPackage, CudaPackage, ROCmPackage): # Optional dependencies depends_on("py-scipy", when="+scipy", type=("build", "run")) depends_on("metis@5.0:", when="+metis", type=("run")) - depends_on("scotch@6.0:", when="+scotch", type=("run")) + depends_on("scotch@7.0.1: +link_error_lib", when="+scotch", type=("run")) depends_on("cuda@8.0: +allow-unsupported-compilers", when="@:1.14.0 +cuda", type=("run")) depends_on("cuda@11.4.0: +allow-unsupported-compilers", when="@1.15.0: +cuda", type=("run")) depends_on("rocblas@5.2.0:", when="+hip", type=("run")) diff --git a/var/spack/repos/builtin/packages/scotch/libscotch-scotcherr-link-7.0.1.patch b/var/spack/repos/builtin/packages/scotch/libscotch-scotcherr-link-7.0.1.patch new file mode 100644 index 00000000000..40e4ade8834 --- /dev/null +++ b/var/spack/repos/builtin/packages/scotch/libscotch-scotcherr-link-7.0.1.patch @@ -0,0 +1,20 @@ +--- a/src/libscotch/CMakeLists.txt ++++ b/src/libscotch/CMakeLists.txt +@@ -508,7 +508,7 @@ add_library(scotch + set_target_properties(scotch PROPERTIES VERSION + ${SCOTCH_VERSION}.${SCOTCH_RELEASE}.${SCOTCH_PATCHLEVEL}) + add_dependencies(scotch parser_yy_c parser_ll_c) +-target_link_libraries(scotch PUBLIC m) ++target_link_libraries(scotch PUBLIC m scotcherr) + target_include_directories(scotch PUBLIC + $ + $ +@@ -748,7 +748,7 @@ if(BUILD_PTSCOTCH) + set_target_properties(ptscotch PROPERTIES + VERSION ${SCOTCH_VERSION}.${SCOTCH_RELEASE}.${SCOTCH_PATCHLEVEL} + COMPILE_FLAGS -DSCOTCH_PTSCOTCH) +- target_link_libraries(ptscotch PUBLIC scotch MPI::MPI_C) ++ target_link_libraries(ptscotch PUBLIC ptscotcherr scotch MPI::MPI_C) + target_include_directories(ptscotch PUBLIC + $ + $ diff --git a/var/spack/repos/builtin/packages/scotch/package.py b/var/spack/repos/builtin/packages/scotch/package.py index 672706a6355..166455876e3 100644 --- a/var/spack/repos/builtin/packages/scotch/package.py +++ b/var/spack/repos/builtin/packages/scotch/package.py @@ -44,6 +44,12 @@ class Scotch(CMakePackage): "metis", default=False, description="Expose vendored METIS/ParMETIS libraries and wrappers" ) variant("int64", default=False, description="Use int64_t for SCOTCH_Num typedef") + variant( + "link_error_lib", + default=False, + when="@7.0.1", + description="Link error handling library to libscotch/libptscotch", + ) # Does not build with flex 2.6.[23] depends_on("flex@:2.6.1,2.6.4:", type="build") @@ -57,6 +63,7 @@ class Scotch(CMakePackage): patch("metis-headers-6.0.4.patch", when="@6.0.4") patch("libscotchmetis-return-6.0.5a.patch", when="@6.0.5a") + patch("libscotch-scotcherr-link-7.0.1.patch", when="@7.0.1 +link_error_lib") # Vendored dependency of METIS/ParMETIS conflicts with standard # installations From 57c1d6c410a7328518ee242336df181b2b156c61 Mon Sep 17 00:00:00 2001 From: "Mark W. Krentel" Date: Tue, 25 Oct 2022 21:06:29 -0500 Subject: [PATCH 191/442] elfutils: add version 0.187 (#33419) * elfutils: add version 0.187 * Move conflict for debuginfod to variant when clause. * Add myself as maintainer. --- var/spack/repos/builtin/packages/elfutils/package.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/var/spack/repos/builtin/packages/elfutils/package.py b/var/spack/repos/builtin/packages/elfutils/package.py index c84cd4deee3..a94505d67d8 100644 --- a/var/spack/repos/builtin/packages/elfutils/package.py +++ b/var/spack/repos/builtin/packages/elfutils/package.py @@ -22,6 +22,9 @@ class Elfutils(AutotoolsPackage, SourcewarePackage): list_url = "https://sourceware.org/elfutils/ftp" list_depth = 1 + maintainers = ["mwkrentel"] + + version("0.187", sha256="e70b0dfbe610f90c4d1fe0d71af142a4e25c3c4ef9ebab8d2d72b65159d454c8") version("0.186", sha256="7f6fb9149b1673d38d9178a0d3e0fb8a1ec4f53a9f4c2ff89469609879641177") version("0.185", sha256="dc8d3e74ab209465e7f568e1b3bb9a5a142f8656e2b57d10049a73da2ae6b5a6") version("0.184", sha256="87e7d1d7f0333815dd1f62135d047a4dc4082068f361452f357997c11360644b") @@ -49,7 +52,12 @@ class Elfutils(AutotoolsPackage, SourcewarePackage): # libdebuginfod support # NB: For 0.181 and newer, this enables _both_ the client and server - variant("debuginfod", default=False, description="Enable libdebuginfod support.") + variant( + "debuginfod", + default=False, + description="Enable libdebuginfod support.", + when="@0.179:", + ) # elfutils-0.185-static-inline.patch # elflint.c (buffer_left): Mark as 'inline' to avoid external linkage failure. @@ -73,7 +81,6 @@ class Elfutils(AutotoolsPackage, SourcewarePackage): depends_on("curl@7.29.0:", type="link", when="+debuginfod") conflicts("%gcc@7.2.0:", when="@0.163") - conflicts("+debuginfod", when="@:0.178") provides("elf@1") From d039744a5be714d476e8c41e38ec6a789dfe6de7 Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Wed, 26 Oct 2022 07:55:05 +0200 Subject: [PATCH 192/442] dfs traversal: simplify edges in reverse mode (#33481) In the dfs code, flip edges so that `parent` means `from` and `spec` means `to` in the direction of traversal. This makes it slightly easier to write generic/composable code. For example when using visitors where one visitor reverses direction, and another only cares about accepting particular edges or not depending on whether the target node is seen before, it would be good if the second visitor didn't have to know whether the order was changed or not. --- lib/spack/spack/spec.py | 53 ++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py index 9256be5803d..2f4120a5f84 100644 --- a/lib/spack/spack/spec.py +++ b/lib/spack/spack/spec.py @@ -734,6 +734,9 @@ def __str__(self): def canonical(self): return self.parent.dag_hash(), self.spec.dag_hash(), self.deptypes + def flip(self): + return DependencySpec(parent=self.spec, spec=self.parent, deptypes=self.deptypes) + _valid_compiler_flags = ["cflags", "cxxflags", "fflags", "ldflags", "ldlibs", "cppflags"] @@ -812,6 +815,10 @@ def _sort_by_dep_types(dspec): return tuple(t not in dspec.deptypes for t in ("link", "run", "build", "test")) +def _sort_edges_by_pkg_name(edges): + edges.sort(key=lambda edge: edge.spec.name) + + #: Enum for edge directions EdgeDirection = lang.enum(parent=0, child=1) @@ -1604,29 +1611,28 @@ def installed_upstream(self): return upstream def traverse(self, **kwargs): - direction = kwargs.get("direction", "children") depth = kwargs.get("depth", False) - get_spec = lambda s: s.spec - if direction == "parents": - get_spec = lambda s: s.parent - if depth: - for d, dspec in self.traverse_edges(**kwargs): - yield d, get_spec(dspec) + for d, edge in self.traverse_edges(**kwargs): + yield d, edge.spec else: - for dspec in self.traverse_edges(**kwargs): - yield get_spec(dspec) + for edge in self.traverse_edges(**kwargs): + yield edge.spec def traverse_edges(self, visited=None, d=0, deptype="all", dep_spec=None, **kwargs): """Generic traversal of the DAG represented by this spec. This yields ``DependencySpec`` objects as they are traversed. - When traversing top-down, an imaginary incoming edge to the root - is yielded first as ``DependencySpec(None, root, ())``. When - traversing bottom-up, imaginary edges to leaves are yielded first - as ``DependencySpec(left, None, ())`` objects. + An imaginary incoming edge to the root is yielded first as + ``DependencySpec(None, root, ())``. + + Note: the edges are traversed from ``edge.parent`` to ``edge.spec``, + even if the direction is reversed. When ``direction="children"`` the + parent points to the dependent, and spec to the dependency. Conversely + when ``direction="parents"`` parent points to the dependency, and spec + to the dependent. Options: @@ -1711,10 +1717,7 @@ def validate(name, val, allowed_values): def return_val(dspec): if not dspec: # make a fake dspec for the root. - if direction == "parents": - dspec = DependencySpec(self, None, ()) - else: - dspec = DependencySpec(None, self, ()) + dspec = DependencySpec(None, self, ()) return (d, dspec) if depth else dspec yield_me = yield_root or d > 0 @@ -1729,22 +1732,18 @@ def return_val(dspec): # This code determines direction and yields the children/parents if direction == "children": - edges = self.edges_to_dependencies - key_fn = lambda dspec: dspec.spec.name - succ = lambda dspec: dspec.spec - elif direction == "parents": - edges = self.edges_from_dependents - key_fn = lambda dspec: dspec.parent.name - succ = lambda dspec: dspec.parent + edges = self.edges_to_dependencies() else: - raise ValueError("Invalid traversal direction: %s" % direction) + edges = [edge.flip() for edge in self.edges_from_dependents()] - for dspec in sorted(edges(), key=key_fn): + _sort_edges_by_pkg_name(edges) + + for dspec in edges: dt = dspec.deptypes if dt and not any(d in deptype for d in dt): continue - for child in succ(dspec).traverse_edges(visited, d + 1, deptype, dspec, **kwargs): + for child in dspec.spec.traverse_edges(visited, d + 1, deptype, dspec, **kwargs): yield child # Postorder traversal yields after successors From a2520e80c0b2bee62cc4d57090ded2422b96263a Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Wed, 26 Oct 2022 09:19:24 +0200 Subject: [PATCH 193/442] gitlab ci: install binary deps faster (#33248) * Fast Gitlab CI job setup, and better legibility * Use a non-broken, recent GNU Make --- lib/spack/spack/ci.py | 33 ++++--- lib/spack/spack/cmd/ci.py | 88 ++++++++++++++----- lib/spack/spack/test/cmd/ci.py | 10 +-- .../stacks/aws-ahug-aarch64/spack.yaml | 3 + .../stacks/aws-ahug/spack.yaml | 3 + .../stacks/aws-isc-aarch64/spack.yaml | 3 + .../cloud_pipelines/stacks/aws-isc/spack.yaml | 3 + .../stacks/build_systems/spack.yaml | 3 + .../stacks/data-vis-sdk/spack.yaml | 3 + .../stacks/e4s-on-power/spack.yaml | 1 + .../stacks/e4s-oneapi/spack.yaml | 3 + .../cloud_pipelines/stacks/e4s/spack.yaml | 3 + .../cloud_pipelines/stacks/ml-cpu/spack.yaml | 3 + .../cloud_pipelines/stacks/ml-cuda/spack.yaml | 3 + .../cloud_pipelines/stacks/ml-rocm/spack.yaml | 3 + .../stacks/radiuss-aws-aarch64/spack.yaml | 3 + .../stacks/radiuss-aws/spack.yaml | 3 + .../cloud_pipelines/stacks/radiuss/spack.yaml | 3 + .../stacks/tutorial/spack.yaml | 3 + 19 files changed, 139 insertions(+), 38 deletions(-) diff --git a/lib/spack/spack/ci.py b/lib/spack/spack/ci.py index 1a63949efb5..bec7a2f38b6 100644 --- a/lib/spack/spack/ci.py +++ b/lib/spack/spack/ci.py @@ -17,7 +17,7 @@ import time import zipfile -from six import iteritems +from six import iteritems, string_types from six.moves.urllib.error import HTTPError, URLError from six.moves.urllib.parse import urlencode from six.moves.urllib.request import HTTPHandler, Request, build_opener @@ -1936,26 +1936,35 @@ def reproduce_ci_job(url, work_dir): print("".join(inst_list)) -def process_command(cmd, cmd_args, repro_dir): +def process_command(name, commands, repro_dir): """ Create a script for and run the command. Copy the script to the reproducibility directory. Arguments: - cmd (str): name of the command being processed - cmd_args (list): string arguments to pass to the command + name (str): name of the command being processed + commands (list): list of arguments for single command or list of lists of + arguments for multiple commands. No shell escape is performed. repro_dir (str): Job reproducibility directory Returns: the exit code from processing the command """ - tty.debug("spack {0} arguments: {1}".format(cmd, cmd_args)) + tty.debug("spack {0} arguments: {1}".format(name, commands)) + + if len(commands) == 0 or isinstance(commands[0], string_types): + commands = [commands] + + # Create a string [command 1] && [command 2] && ... && [command n] with commands + # quoted using double quotes. + args_to_string = lambda args: " ".join('"{}"'.format(arg) for arg in args) + full_command = " && ".join(map(args_to_string, commands)) # Write the command to a shell script - script = "{0}.sh".format(cmd) + script = "{0}.sh".format(name) with open(script, "w") as fd: - fd.write("#!/bin/bash\n\n") - fd.write("\n# spack {0} command\n".format(cmd)) - fd.write(" ".join(['"{0}"'.format(i) for i in cmd_args])) + fd.write("#!/bin/sh\n\n") + fd.write("\n# spack {0} command\n".format(name)) + fd.write(full_command) fd.write("\n") st = os.stat(script) @@ -1967,15 +1976,15 @@ def process_command(cmd, cmd_args, repro_dir): # Run the generated install.sh shell script as if it were being run in # a login shell. try: - cmd_process = subprocess.Popen(["bash", "./{0}".format(script)]) + cmd_process = subprocess.Popen(["/bin/sh", "./{0}".format(script)]) cmd_process.wait() exit_code = cmd_process.returncode except (ValueError, subprocess.CalledProcessError, OSError) as err: - tty.error("Encountered error running {0} script".format(cmd)) + tty.error("Encountered error running {0} script".format(name)) tty.error(err) exit_code = 1 - tty.debug("spack {0} exited {1}".format(cmd, exit_code)) + tty.debug("spack {0} exited {1}".format(name, exit_code)) return exit_code diff --git a/lib/spack/spack/cmd/ci.py b/lib/spack/spack/cmd/ci.py index e49bf9a2a61..11a47d50169 100644 --- a/lib/spack/spack/cmd/ci.py +++ b/lib/spack/spack/cmd/ci.py @@ -25,7 +25,8 @@ section = "build" level = "long" -CI_REBUILD_INSTALL_BASE_ARGS = ["spack", "--color=always", "--backtrace", "--verbose"] +SPACK_COMMAND = "spack" +MAKE_COMMAND = "make" INSTALL_FAIL_CODE = 1 @@ -509,41 +510,88 @@ def ci_rebuild(args): # No hash match anywhere means we need to rebuild spec # Start with spack arguments - install_args = [base_arg for base_arg in CI_REBUILD_INSTALL_BASE_ARGS] + spack_cmd = [SPACK_COMMAND, "--color=always", "--backtrace", "--verbose"] config = cfg.get("config") if not config["verify_ssl"]: - install_args.append("-k") + spack_cmd.append("-k") - install_args.extend( - [ - "install", - "--keep-stage", - "--use-buildcache", - "dependencies:only,package:never", - ] - ) + install_args = [] can_verify = spack_ci.can_verify_binaries() verify_binaries = can_verify and spack_is_pr_pipeline is False if not verify_binaries: install_args.append("--no-check-signature") + cdash_args = [] if cdash_handler: # Add additional arguments to `spack install` for CDash reporting. - install_args.extend(cdash_handler.args()) + cdash_args.extend(cdash_handler.args()) - # A compiler action of 'FIND_ANY' means we are building a bootstrap - # compiler or one of its deps. - # TODO: when compilers are dependencies, we should include --no-add - if compiler_action != "FIND_ANY": - install_args.append("--no-add") + slash_hash = "/{}".format(job_spec.dag_hash()) + deps_install_args = install_args + root_install_args = install_args + [ + "--no-add", + "--keep-stage", + "--only=package", + "--use-buildcache=package:never,dependencies:only", + slash_hash, + ] - # Identify spec to install by hash - install_args.append("/{0}".format(job_spec.dag_hash())) + # ["x", "y"] -> "'x' 'y'" + args_to_string = lambda args: " ".join("'{}'".format(arg) for arg in args) + + commands = [ + # apparently there's a race when spack bootstraps? do it up front once + [ + SPACK_COMMAND, + "-e", + env.path, + "bootstrap", + "now", + ], + [ + SPACK_COMMAND, + "-e", + env.path, + "config", + "add", + "config:db_lock_timeout:120", # 2 minutes for processes to fight for a db lock + ], + [ + SPACK_COMMAND, + "-e", + env.path, + "env", + "depfile", + "-o", + "Makefile", + "--use-buildcache=package:never,dependencies:only", + "--make-target-prefix", + "ci", + slash_hash, # limit to spec we're building + ], + [ + # --output-sync requires GNU make 4.x. + # Old make errors when you pass it a flag it doesn't recognize, + # but it doesn't error or warn when you set unrecognized flags in + # this variable. + "export", + "GNUMAKEFLAGS=--output-sync=recurse", + ], + [ + MAKE_COMMAND, + "SPACK={}".format(args_to_string(spack_cmd)), + "SPACK_COLOR=always", + "SPACK_INSTALL_FLAGS={}".format(args_to_string(deps_install_args)), + "-j$(nproc)", + "ci/.install-deps/{}".format(job_spec.dag_hash()), + ], + spack_cmd + ["install"] + root_install_args, + ] tty.debug("Installing {0} from source".format(job_spec.name)) - install_exit_code = spack_ci.process_command("install", install_args, repro_dir) + install_exit_code = spack_ci.process_command("install", commands, repro_dir) # Now do the post-install tasks tty.debug("spack install exited {0}".format(install_exit_code)) diff --git a/lib/spack/spack/test/cmd/ci.py b/lib/spack/spack/test/cmd/ci.py index 2edf8788d58..117dec0ed4e 100644 --- a/lib/spack/spack/test/cmd/ci.py +++ b/lib/spack/spack/test/cmd/ci.py @@ -916,11 +916,8 @@ def test_ci_rebuild_mock_success( pkg_name = "archive-files" rebuild_env = create_rebuild_env(tmpdir, pkg_name, broken_tests) - monkeypatch.setattr( - spack.cmd.ci, - "CI_REBUILD_INSTALL_BASE_ARGS", - ["echo"], - ) + monkeypatch.setattr(spack.cmd.ci, "SPACK_COMMAND", "echo") + monkeypatch.setattr(spack.cmd.ci, "MAKE_COMMAND", "echo") with rebuild_env.env_dir.as_cwd(): activate_rebuild_env(tmpdir, pkg_name, rebuild_env) @@ -965,7 +962,8 @@ def test_ci_rebuild( ci_cmd("rebuild", "--tests", fail_on_error=False) - monkeypatch.setattr(spack.cmd.ci, "CI_REBUILD_INSTALL_BASE_ARGS", ["notcommand"]) + monkeypatch.setattr(spack.cmd.ci, "SPACK_COMMAND", "notcommand") + monkeypatch.setattr(spack.cmd.ci, "MAKE_COMMAND", "notcommand") monkeypatch.setattr(spack.cmd.ci, "INSTALL_FAIL_CODE", 127) with rebuild_env.env_dir.as_cwd(): diff --git a/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml index 09a36a6b02c..488309b2948 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml @@ -241,6 +241,9 @@ spack: gitlab-ci: script: + - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.aarch64-linux-gnu.tar.gz -o gmake.tar.gz + - printf 'deb1dcae0eecdc7fce2902f294012ab5519629e6827204f1b9964dcfd3f74627 gmake.tar.gz' | sha256sum --check --strict --quiet + - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version - cd ${SPACK_CONCRETE_ENV_DIR} diff --git a/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml index 122247e936e..564884a5f8b 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml @@ -240,6 +240,9 @@ spack: gitlab-ci: script: + - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz + - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet + - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version - cd ${SPACK_CONCRETE_ENV_DIR} diff --git a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml index d73a14c2ec9..61eb974e70e 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml @@ -148,6 +148,9 @@ spack: gitlab-ci: script: + - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.aarch64-linux-gnu.tar.gz -o gmake.tar.gz + - printf 'deb1dcae0eecdc7fce2902f294012ab5519629e6827204f1b9964dcfd3f74627 gmake.tar.gz' | sha256sum --check --strict --quiet + - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version - cd ${SPACK_CONCRETE_ENV_DIR} diff --git a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml index 45731b9392a..ed2f205d42c 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml @@ -159,6 +159,9 @@ spack: gitlab-ci: script: + - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz + - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet + - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version - cd ${SPACK_CONCRETE_ENV_DIR} diff --git a/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml index 98a5d286dc4..ee6c9457c3f 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml @@ -32,6 +32,9 @@ spack: gitlab-ci: script: + - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz + - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet + - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version - cd ${SPACK_CONCRETE_ENV_DIR} diff --git a/share/spack/gitlab/cloud_pipelines/stacks/data-vis-sdk/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/data-vis-sdk/spack.yaml index 4cb9dc510fa..c46848b0eb0 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/data-vis-sdk/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/data-vis-sdk/spack.yaml @@ -47,6 +47,9 @@ spack: gitlab-ci: image: { "name": "ghcr.io/spack/e4s-ubuntu-18.04:v2021-10-18", "entrypoint": [""] } script: + - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz + - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet + - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version - cd ${SPACK_CONCRETE_ENV_DIR} diff --git a/share/spack/gitlab/cloud_pipelines/stacks/e4s-on-power/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/e4s-on-power/spack.yaml index 16e7558e9fa..d7c8305c51d 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/e4s-on-power/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/e4s-on-power/spack.yaml @@ -214,6 +214,7 @@ spack: gitlab-ci: script: + - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.powerpc64le-linux-gnu.tar.gz | tar -xzf - -C /usr 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version - cd ${SPACK_CONCRETE_ENV_DIR} diff --git a/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml index 263f30ede50..fc8009e4d93 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml @@ -266,6 +266,9 @@ spack: gitlab-ci: script: + - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz + - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet + - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version - cd ${SPACK_CONCRETE_ENV_DIR} diff --git a/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml index 2a4950d11aa..8d6669252a1 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml @@ -253,6 +253,9 @@ spack: gitlab-ci: script: + - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz + - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet + - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version - cd ${SPACK_CONCRETE_ENV_DIR} diff --git a/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml index 0078c018f7f..527b3250d37 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml @@ -87,6 +87,9 @@ spack: gitlab-ci: script: + - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz + - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet + - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version - cd ${SPACK_CONCRETE_ENV_DIR} diff --git a/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml index cfd6e1ecbaf..64ac6fc4335 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml @@ -90,6 +90,9 @@ spack: gitlab-ci: script: + - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz + - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet + - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version - cd ${SPACK_CONCRETE_ENV_DIR} diff --git a/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml index 537aa55f9da..ad777941778 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml @@ -93,6 +93,9 @@ spack: gitlab-ci: script: + - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz + - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet + - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version - cd ${SPACK_CONCRETE_ENV_DIR} diff --git a/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws-aarch64/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws-aarch64/spack.yaml index ad294f5a935..ed48b8d9bb3 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws-aarch64/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws-aarch64/spack.yaml @@ -56,6 +56,9 @@ spack: gitlab-ci: script: + - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.aarch64-linux-gnu.tar.gz -o gmake.tar.gz + - printf 'deb1dcae0eecdc7fce2902f294012ab5519629e6827204f1b9964dcfd3f74627 gmake.tar.gz' | sha256sum --check --strict --quiet + - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version - cd ${SPACK_CONCRETE_ENV_DIR} diff --git a/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws/spack.yaml index 1cf3b80cbb1..ba7cbd3d354 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws/spack.yaml @@ -61,6 +61,9 @@ spack: gitlab-ci: script: + - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz + - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet + - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version - cd ${SPACK_CONCRETE_ENV_DIR} diff --git a/share/spack/gitlab/cloud_pipelines/stacks/radiuss/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/radiuss/spack.yaml index 9b6a54a8614..8a03de20be2 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/radiuss/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/radiuss/spack.yaml @@ -64,6 +64,9 @@ spack: gitlab-ci: image: { "name": "ghcr.io/spack/e4s-ubuntu-18.04:v2021-10-18", "entrypoint": [""] } script: + - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz + - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet + - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version - cd ${SPACK_CONCRETE_ENV_DIR} diff --git a/share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml index 3c81bb5f653..ea34141ba14 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml @@ -63,6 +63,9 @@ spack: gitlab-ci: script: + - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz + - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet + - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version - spack compiler find From b92bdf8c7202429d785e8c867bd83d92df1f3f4a Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Wed, 26 Oct 2022 10:41:31 +0200 Subject: [PATCH 194/442] Relocation regex single pass (#33496) Instead of looping over multiple regexes and the entire text file contents, create a giant regex with all literal prefixes and do a single pass over files to detect prefixes. Not only is a single pass faster, it's also likely that the regex is compiled better, given that most prefixes share a common ... prefix. --- lib/spack/spack/binary_distribution.py | 20 +++++++----------- lib/spack/spack/relocate.py | 8 +++++-- lib/spack/spack/test/relocate.py | 29 +++++++++++++++++++------- 3 files changed, 36 insertions(+), 21 deletions(-) diff --git a/lib/spack/spack/binary_distribution.py b/lib/spack/spack/binary_distribution.py index d22572d8a41..7c62c58cb19 100644 --- a/lib/spack/spack/binary_distribution.py +++ b/lib/spack/spack/binary_distribution.py @@ -42,7 +42,7 @@ import spack.util.url as url_util import spack.util.web as web_util from spack.caches import misc_cache_location -from spack.relocate import utf8_path_to_binary_regex +from spack.relocate import utf8_paths_to_single_binary_regex from spack.spec import Spec from spack.stage import Stage @@ -694,13 +694,10 @@ def before_visit_symlinked_dir(self, root, rel_path, depth): return False -def file_matches_any_binary_regex(path, regexes): +def file_matches(path, regex): with open(path, "rb") as f: contents = f.read() - for regex in regexes: - if regex.search(contents): - return True - return False + return bool(regex.search(contents)) def get_buildfile_manifest(spec): @@ -734,8 +731,8 @@ def get_buildfile_manifest(spec): prefixes.append(spack.hooks.sbang.sbang_install_path()) prefixes.append(str(spack.store.layout.root)) - # Create a list regexes matching collected prefixes - compiled_prefixes = [utf8_path_to_binary_regex(prefix) for prefix in prefixes] + # Create a giant regex that matches all prefixes + regex = utf8_paths_to_single_binary_regex(prefixes) # Symlinks. @@ -767,10 +764,9 @@ def get_buildfile_manifest(spec): data["binary_to_relocate_fullpath"].append(abs_path) continue - elif relocate.needs_text_relocation(m_type, m_subtype): - if file_matches_any_binary_regex(abs_path, compiled_prefixes): - data["text_to_relocate"].append(rel_path) - continue + elif relocate.needs_text_relocation(m_type, m_subtype) and file_matches(abs_path, regex): + data["text_to_relocate"].append(rel_path) + continue data["other"].append(abs_path) diff --git a/lib/spack/spack/relocate.py b/lib/spack/spack/relocate.py index 667e8de4e0c..0d7525eb05f 100644 --- a/lib/spack/spack/relocate.py +++ b/lib/spack/spack/relocate.py @@ -747,9 +747,13 @@ def relocate_links(links, orig_layout_root, orig_install_prefix, new_install_pre def utf8_path_to_binary_regex(prefix): """Create a (binary) regex that matches the input path in utf8""" prefix_bytes = re.escape(prefix).encode("utf-8") - prefix_rexp = re.compile(b"(? Date: Wed, 26 Oct 2022 18:03:40 +0200 Subject: [PATCH 195/442] fix use of non-existing kwarg (#33520) --- lib/spack/spack/cmd/deprecate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/spack/spack/cmd/deprecate.py b/lib/spack/spack/cmd/deprecate.py index cc59475a623..5a4c390c22b 100644 --- a/lib/spack/spack/cmd/deprecate.py +++ b/lib/spack/spack/cmd/deprecate.py @@ -117,7 +117,7 @@ def deprecate(parser, args): all_deprecators = [] generator = ( - deprecate.traverse(order="post", type="link", root=True) + deprecate.traverse(order="post", deptype="link", root=True) if args.dependencies else [deprecate] ) From b3794761ab90259764f1460edc93ec9c0ad70716 Mon Sep 17 00:00:00 2001 From: Satish Balay Date: Wed, 26 Oct 2022 11:09:45 -0500 Subject: [PATCH 196/442] alquimia, pflotran, plasma, py-mpi4py, strumpack - add in new versions (#33447) * alquimia, pflotran, plasma, py-mpi4py, strumpack - add in new versions * Fix hip CI failure Co-authored-by: eugeneswalker --- var/spack/repos/builtin/packages/alquimia/package.py | 2 ++ var/spack/repos/builtin/packages/pflotran/package.py | 2 ++ var/spack/repos/builtin/packages/plasma/package.py | 1 + var/spack/repos/builtin/packages/py-mpi4py/package.py | 3 ++- var/spack/repos/builtin/packages/strumpack/package.py | 9 ++++++++- 5 files changed, 15 insertions(+), 2 deletions(-) diff --git a/var/spack/repos/builtin/packages/alquimia/package.py b/var/spack/repos/builtin/packages/alquimia/package.py index bd99e2d817a..05d4c54128f 100644 --- a/var/spack/repos/builtin/packages/alquimia/package.py +++ b/var/spack/repos/builtin/packages/alquimia/package.py @@ -16,6 +16,7 @@ class Alquimia(CMakePackage): maintainers = ["smolins", "balay"] version("develop") + version("1.0.10", commit="b2c11b6cde321f4a495ef9fcf267cb4c7a9858a0") # tag v.1.0.10 version("1.0.9", commit="2ee3bcfacc63f685864bcac2b6868b48ad235225") # tag v.1.0.9 version("xsdk-0.6.0", commit="9a0aedd3a927d4d5e837f8fd18b74ad5a78c3821") version("xsdk-0.5.0", commit="8397c3b00a09534c5473ff3ab21f0e32bb159380") @@ -26,6 +27,7 @@ class Alquimia(CMakePackage): depends_on("mpi") depends_on("hdf5") + depends_on("pflotran@4.0.1", when="@1.0.10") depends_on("pflotran@3.0.2", when="@1.0.9") depends_on("pflotran@xsdk-0.6.0", when="@xsdk-0.6.0") depends_on("pflotran@xsdk-0.5.0", when="@xsdk-0.5.0") diff --git a/var/spack/repos/builtin/packages/pflotran/package.py b/var/spack/repos/builtin/packages/pflotran/package.py index 3b00fda8e7c..8807ad5e716 100644 --- a/var/spack/repos/builtin/packages/pflotran/package.py +++ b/var/spack/repos/builtin/packages/pflotran/package.py @@ -18,6 +18,7 @@ class Pflotran(AutotoolsPackage): maintainers = ["ghammond86", "balay"] version("develop") + version("4.0.1", commit="fd351a49b687e27f46eae92e9259156eea74897d") # tag v4.0.1 version("3.0.2", commit="9e07f416a66b0ad304c720b61aa41cba9a0929d5") # tag v3.0.2 version("xsdk-0.6.0", commit="46e14355c1827c057f2e1b3e3ae934119ab023b2") version("xsdk-0.5.0", commit="98a959c591b72f73373febf5f9735d2c523b4c20") @@ -27,6 +28,7 @@ class Pflotran(AutotoolsPackage): depends_on("mpi") depends_on("hdf5@1.8.12:+mpi+fortran+hl") depends_on("petsc@main:+hdf5+metis", when="@develop") + depends_on("petsc@3.18:+hdf5+metis", when="@4.0.1") depends_on("petsc@3.16:+hdf5+metis", when="@3.0.2") depends_on("petsc@3.14:+hdf5+metis", when="@xsdk-0.6.0") depends_on("petsc@3.12:+hdf5+metis", when="@xsdk-0.5.0") diff --git a/var/spack/repos/builtin/packages/plasma/package.py b/var/spack/repos/builtin/packages/plasma/package.py index 937d87de9e4..5e32b5af318 100644 --- a/var/spack/repos/builtin/packages/plasma/package.py +++ b/var/spack/repos/builtin/packages/plasma/package.py @@ -23,6 +23,7 @@ class Plasma(CMakePackage): tags = ["e4s"] version("develop", git=git) + version("22.9.29", sha256="78827898b7e3830eee2e388823b9180858279f77c5eda5aa1be173765c53ade5") version("21.8.29", sha256="e0bb4d9143c8540f9f46cbccac9ed0cbea12500a864e6954fce2fe94ea057a10") version("20.9.20", sha256="2144a77b739f8dd2f0dbe5b64d94cde0e916f55c4eb170facd168c0db7fc7970") version("19.8.1", sha256="3a5db6eabf91aec782b7f27b17a7f6b8ce2c9d8e648c0e9c0ff5d87277ba4d17") diff --git a/var/spack/repos/builtin/packages/py-mpi4py/package.py b/var/spack/repos/builtin/packages/py-mpi4py/package.py index f0133d2af49..7ce0633733d 100644 --- a/var/spack/repos/builtin/packages/py-mpi4py/package.py +++ b/var/spack/repos/builtin/packages/py-mpi4py/package.py @@ -17,6 +17,7 @@ class PyMpi4py(PythonPackage): git = "https://github.com/mpi4py/mpi4py.git" version("master", branch="master") + version("3.1.3", sha256="f1e9fae1079f43eafdd9f817cdb3fd30d709edc093b5d5dada57a461b2db3008") version("3.1.2", sha256="40dd546bece8f63e1131c3ceaa7c18f8e8e93191a762cd446a8cfcf7f9cce770") version("3.1.1", sha256="e11f8587a3b93bb24c8526addec664b586b965d83c0882b884c14dc3fd6b9f5c") version("3.1.0", sha256="134fa2b2fe6d8f91bcfcc2824cfd74b55ca3dcbff4d185b1bda009beea9232ec") @@ -28,7 +29,7 @@ class PyMpi4py(PythonPackage): depends_on("python@2.6:2.7,3.2:") depends_on("python@2.7:2.8,3.5:", when="@3.1:") - depends_on("py-setuptools", type="build") + depends_on("py-setuptools@40.9:", type="build") depends_on("mpi") depends_on("py-cython@0.27.0:", when="@master", type="build") depends_on("py-3to2", when="@3.1: ^python@:2", type="build") diff --git a/var/spack/repos/builtin/packages/strumpack/package.py b/var/spack/repos/builtin/packages/strumpack/package.py index 258e0583030..e19aadcff38 100644 --- a/var/spack/repos/builtin/packages/strumpack/package.py +++ b/var/spack/repos/builtin/packages/strumpack/package.py @@ -29,6 +29,8 @@ class Strumpack(CMakePackage, CudaPackage, ROCmPackage): test_requires_compiler = True version("master", branch="master") + version("7.0.1", sha256="ddbf9c0509eaf0f8a4c70f59508787336a05eeacc8322f156117d8ce59a70a60") + version("7.0.0", sha256="18f7a0d75cc5cfdb7bbb6112a2bdda7a50fbcaefa2d8bab001f902bdf62e69e3") version("6.3.1", sha256="3f1de435aeb850c06d841655c3bc426565eb0cc0a7314b76586c2c709b03fb61") version("6.3.0", sha256="47dec831684894b7ed77c66b8a23e172b388c83580cfaf91f921564fa0b46d41") version("6.2.1", sha256="52d63ab8f565266a9b1b5f3596afd00fc3b70296179b53a1e5b99405defeca22") @@ -72,6 +74,7 @@ class Strumpack(CMakePackage, CudaPackage, ROCmPackage): depends_on("cuda", when="@4.0.0: +cuda") depends_on("zfp", when="+zfp") depends_on("hipblas", when="+rocm") + depends_on("hipsparse", type="link", when="@7.0.1: +rocm") depends_on("rocsolver", when="+rocm") depends_on("slate", when="+slate") depends_on("slate+cuda", when="+cuda+slate") @@ -144,8 +147,12 @@ def cmake_args(self): if "+rocm" in spec: args.append("-DHIP_ROOT_DIR={0}".format(spec["hip"].prefix)) rocm_archs = spec.variants["amdgpu_target"].value + hipcc_flags = [] + if spec.satisfies("@7.0.1: +rocm"): + hipcc_flags.append("-std=c++14") if "none" not in rocm_archs: - args.append("-DHIP_HIPCC_FLAGS=--amdgpu-target={0}".format(",".join(rocm_archs))) + hipcc_flags.append("--amdgpu-target={0}".format(",".join(rocm_archs))) + args.append("-DHIP_HIPCC_FLAGS={0}".format(" ".join(hipcc_flags))) return args From 3e37ad9aee28aa8dff87e0eb58bfa1fe61bfcad6 Mon Sep 17 00:00:00 2001 From: Dom Heinzeller Date: Wed, 26 Oct 2022 10:18:17 -0600 Subject: [PATCH 197/442] Add netcdf-c 4.9.0 and netcdf-fortran 4.6.0 (supersedes #31953) (#33514) * Add netcdf-c 4.9.0 and netcdf-fortran 4.6.0 With v4.9.0 netcdf-c introduces zstandard compression option which is added as a variant. * Fix when= in dependency * Turn on variant zstd by default Co-authored-by: kgerheiser --- .../builtin/packages/netcdf-c/package.py | 21 ++++++++++++++++++- .../packages/netcdf-fortran/package.py | 1 + 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/netcdf-c/package.py b/var/spack/repos/builtin/packages/netcdf-c/package.py index 55eb3e4b718..32071637474 100644 --- a/var/spack/repos/builtin/packages/netcdf-c/package.py +++ b/var/spack/repos/builtin/packages/netcdf-c/package.py @@ -20,6 +20,7 @@ class NetcdfC(AutotoolsPackage): maintainers = ["skosukhin", "WardF"] version("main", branch="main") + version("4.9.0", sha256="9f4cb864f3ab54adb75409984c6202323d2fc66c003e5308f3cdf224ed41c0a6") version("4.8.1", sha256="bc018cc30d5da402622bf76462480664c6668b55eb16ba205a0dfb8647161dd0") version("4.8.0", sha256="aff58f02b1c3e91dc68f989746f652fe51ff39e6270764e484920cb8db5ad092") version("4.7.4", sha256="99930ad7b3c4c1a8e8831fb061cb02b2170fc8e5ccaeda733bd99c3b9d31666b") @@ -65,7 +66,7 @@ class NetcdfC(AutotoolsPackage): patch("4.7.3-spectrum-mpi-pnetcdf-detect.patch", when="@4.7.3:4.7.4 +parallel-netcdf") # See https://github.com/Unidata/netcdf-c/pull/2293 - patch("4.8.1-no-strict-aliasing-config.patch", when="@4.8.1:") + patch("4.8.1-no-strict-aliasing-config.patch", when="@4.8.1") variant("mpi", default=True, description="Enable parallel I/O for netcdf-4") variant("parallel-netcdf", default=False, description="Enable parallel I/O for classic files") @@ -75,6 +76,7 @@ class NetcdfC(AutotoolsPackage): variant("dap", default=False, description="Enable DAP support") variant("jna", default=False, description="Enable JNA support") variant("fsync", default=False, description="Enable fsync support") + variant("zstd", default=True, description="Enable ZStandard compression", when="@4.9.0:") # It's unclear if cdmremote can be enabled if '--enable-netcdf-4' is passed # to the configure script. Since netcdf-4 support is mandatory we comment @@ -123,6 +125,8 @@ class NetcdfC(AutotoolsPackage): # https://github.com/Unidata/netcdf-c/issues/250 depends_on("hdf5@:1.8", when="@:4.4.0") + depends_on("zstd", when="+zstd") + # The feature was introduced in version 4.1.2 # and was removed in version 4.4.0 # conflicts('+cdmremote', when='@:4.1.1,4.4:') @@ -236,6 +240,16 @@ def configure_args(self): 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"] + 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: + # Prevent linking to system zstd. + # There is no explicit option to disable zstd. + config_args.append("ac_cv_lib_zstd_ZSTD_compress=no") + # Fortran support # In version 4.2+, NetCDF-C and NetCDF-Fortran have split. # Use the netcdf-fortran package to install Fortran support. @@ -247,7 +261,12 @@ def configure_args(self): 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, diff --git a/var/spack/repos/builtin/packages/netcdf-fortran/package.py b/var/spack/repos/builtin/packages/netcdf-fortran/package.py index 69f4b51a3c2..2b22569b011 100644 --- a/var/spack/repos/builtin/packages/netcdf-fortran/package.py +++ b/var/spack/repos/builtin/packages/netcdf-fortran/package.py @@ -21,6 +21,7 @@ class NetcdfFortran(AutotoolsPackage): maintainers = ["skosukhin", "WardF"] + version("4.6.0", sha256="198bff6534cc85a121adc9e12f1c4bc53406c403bda331775a1291509e7b2f23") version("4.5.4", sha256="0a19b26a2b6e29fab5d29d7d7e08c24e87712d09a5cafeea90e16e0a2ab86b81") version("4.5.3", sha256="123a5c6184336891e62cf2936b9f2d1c54e8dee299cfd9d2c1a1eb05dd668a74") version("4.5.2", sha256="b959937d7d9045184e9d2040a915d94a7f4d0185f4a9dceb8f08c94b0c3304aa") From 8ddb5c3299ee6f47b5c91ca0a04b845a275dfbe0 Mon Sep 17 00:00:00 2001 From: Matthieu Dorier Date: Wed, 26 Oct 2022 17:20:33 +0100 Subject: [PATCH 198/442] [mochi-margo] added version 0.10 (#33519) --- var/spack/repos/builtin/packages/mochi-margo/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/mochi-margo/package.py b/var/spack/repos/builtin/packages/mochi-margo/package.py index 7feb7345fc5..ebbdfebe123 100644 --- a/var/spack/repos/builtin/packages/mochi-margo/package.py +++ b/var/spack/repos/builtin/packages/mochi-margo/package.py @@ -17,6 +17,7 @@ class MochiMargo(AutotoolsPackage): maintainers = ["carns", "mdorier", "fbudin69500", "chuckatkins"] version("main", branch="main") + version("0.10", sha256="163be090575ee267a84320b92791d83b98e9549b03bd705a166f0b5e4df53129") version("0.9.10", sha256="b205b45fe200d1b2801ea3b913fa75d709af97abf470f4ad72a08d2839f03772") version("0.9.9", sha256="9e8fce88a6bd9c1002b4a6924c935ebb2e2024e3afe6618b17e23538335bd15d") version("0.9.8", sha256="a139e804bf0b2725433c256e8315a2ba896f1fb34d9057261a4b92df783ffbbb") From bb64d09ccd82044151d5763bbb1cd5ec98ce4525 Mon Sep 17 00:00:00 2001 From: MatthewLieber <77356607+MatthewLieber@users.noreply.github.com> Date: Wed, 26 Oct 2022 12:34:37 -0400 Subject: [PATCH 199/442] Updating package file for osu-micro-benchmarks for the 6.2 release (#33512) * Updating package file for osu-micro-benchmarks for the 6.2 release * updating sha hash for 6.2 tarball Co-authored-by: natshineman --- .../repos/builtin/packages/osu-micro-benchmarks/package.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/osu-micro-benchmarks/package.py b/var/spack/repos/builtin/packages/osu-micro-benchmarks/package.py index 6840dfe076e..bb090e63f3a 100644 --- a/var/spack/repos/builtin/packages/osu-micro-benchmarks/package.py +++ b/var/spack/repos/builtin/packages/osu-micro-benchmarks/package.py @@ -16,10 +16,11 @@ class OsuMicroBenchmarks(AutotoolsPackage, CudaPackage, ROCmPackage): and can be used for both traditional and GPU-enhanced nodes.""" homepage = "https://mvapich.cse.ohio-state.edu/benchmarks/" - url = "https://mvapich.cse.ohio-state.edu/download/mvapich/osu-micro-benchmarks-6.1.tar.gz" + url = "https://mvapich.cse.ohio-state.edu/download/mvapich/osu-micro-benchmarks-6.2.tar.gz" maintainers = ["natshineman", "harisubramoni", "MatthewLieber"] + version("6.2", sha256="bb9dbc87dcf8ec6785977a61f6fceee8febf1a682488eaab4c58cf50e4fa985f") version("6.1", sha256="ecccedc868264f75db4d9529af79005419a2775113c7fae8f4e4a8434362e4a7") version("6.0", sha256="309fb7583ff54562343b0e0df1eebde3fc245191e183be362f031ac74f4ab542") version("5.9", sha256="d619740a1c2cc7c02a9763931546b320d0fa4093c415ff3873c2958e121c0609") From 117a82117d7c412524108620bfd1704903221ecf Mon Sep 17 00:00:00 2001 From: Satish Balay Date: Wed, 26 Oct 2022 11:40:32 -0500 Subject: [PATCH 200/442] petsc, py-petsc4py: add 3.18.1 (#33525) --- var/spack/repos/builtin/packages/petsc/package.py | 1 + var/spack/repos/builtin/packages/py-petsc4py/package.py | 1 + 2 files changed, 2 insertions(+) diff --git a/var/spack/repos/builtin/packages/petsc/package.py b/var/spack/repos/builtin/packages/petsc/package.py index 75d041fc1de..71ba0cba756 100644 --- a/var/spack/repos/builtin/packages/petsc/package.py +++ b/var/spack/repos/builtin/packages/petsc/package.py @@ -22,6 +22,7 @@ class Petsc(Package, CudaPackage, ROCmPackage): version("main", branch="main") + version("3.18.1", sha256="02f5979a22f5961bb775d527f8450db77bc6a8d2541f3b05fb586829b82e9bc8") version("3.18.0", sha256="9da802e703ad79fb7ef0007d17f68916573011073ee9712dcd1673537f6a5f68") version("3.17.5", sha256="a1193e6c50a1676c3972a1edf0a06eec9fac8ecc2f3771f2689a8997423e4c71") version("3.17.4", sha256="99c127486722a3ffd95a268b4ceb0976cbf217926c681a9631bd7246eab8cb2a") diff --git a/var/spack/repos/builtin/packages/py-petsc4py/package.py b/var/spack/repos/builtin/packages/py-petsc4py/package.py index ded5146c6cf..a276c09bae4 100644 --- a/var/spack/repos/builtin/packages/py-petsc4py/package.py +++ b/var/spack/repos/builtin/packages/py-petsc4py/package.py @@ -16,6 +16,7 @@ class PyPetsc4py(PythonPackage): maintainers = ["balay"] version("main", branch="main") + version("3.18.1", sha256="6d9d9632e2da0920c4e3905b7bac919837bdd85ecfaf1b9e461ba7e05ec4a5ce") version("3.18.0", sha256="76bad2d35f380f698f5649c3f38eabd153b9b19b1fe3ce3a1d3de9aa5824a4d2") version("3.17.5", sha256="e435d927bf22950c71c30bda538e1ae75f48f6931a63205c6fbeff6cf4393f09") version("3.17.4", sha256="216c3da074557946615d37d0826bc89f1f2e599323e2dacbdc45326d78bd50c6") From b497581ce792ca6152e9d787ba55ffa488246d77 Mon Sep 17 00:00:00 2001 From: Satish Balay Date: Wed, 26 Oct 2022 12:33:52 -0500 Subject: [PATCH 201/442] pflotran: fix build errors with gfortran@10: (#33527) >> 38 Error: Rank mismatch between actual argument at (1) and actual argument at (2) (scalar and rank-1) --- var/spack/repos/builtin/packages/pflotran/package.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/var/spack/repos/builtin/packages/pflotran/package.py b/var/spack/repos/builtin/packages/pflotran/package.py index 8807ad5e716..6a042497b99 100644 --- a/var/spack/repos/builtin/packages/pflotran/package.py +++ b/var/spack/repos/builtin/packages/pflotran/package.py @@ -38,3 +38,8 @@ class Pflotran(AutotoolsPackage): @property def parallel(self): return self.spec.satisfies("@xsdk-0.4.0:") + + def flag_handler(self, name, flags): + if "%gcc@10:" in self.spec and name == "fflags": + flags.append("-fallow-argument-mismatch") + return flags, None, None From 83ee5001086672a45e140d5858eacc0b8ef90941 Mon Sep 17 00:00:00 2001 From: "Adam J. Stewart" Date: Wed, 26 Oct 2022 13:14:08 -0500 Subject: [PATCH 202/442] py-torchmetrics: add v0.10.1 (#33535) --- var/spack/repos/builtin/packages/py-torchmetrics/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/py-torchmetrics/package.py b/var/spack/repos/builtin/packages/py-torchmetrics/package.py index c87344f5744..ef55a25f408 100644 --- a/var/spack/repos/builtin/packages/py-torchmetrics/package.py +++ b/var/spack/repos/builtin/packages/py-torchmetrics/package.py @@ -14,6 +14,7 @@ class PyTorchmetrics(PythonPackage): maintainers = ["adamjstewart"] + version("0.10.1", sha256="e892ecd413e6bf63950329d1317c70f697d81d0f7e386152238062e322c8f1f3") version("0.10.0", sha256="990bafc7f76d7442894533771d0ba7492dbca2bbf2989fb32de7e9c68eb3d133") version("0.9.3", sha256="4ebfd2466021db26397636966ee1a195d3b340ba5d71bb258e764340dfc2476f") version("0.9.2", sha256="8178c9242e243318093d9b7237738a504535193d2006da6e58b0ed4003e318d2") From 30c9ff50dd048573e3cd7a63a8ab9c05c0bee339 Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Wed, 26 Oct 2022 20:17:32 +0200 Subject: [PATCH 203/442] Allow for packages with multiple build-systems (#30738) This commit extends the DSL that can be used in packages to allow declaring that a package uses different build-systems under different conditions. It requires each spec to have a `build_system` single valued variant. The variant can be used in many context to query, manipulate or select the build system associated with a concrete spec. The knowledge to build a package has been moved out of the PackageBase hierarchy, into a new Builder hierarchy. Customization of the default behavior for a given builder can be obtained by coding a new derived builder in package.py. The "run_after" and "run_before" decorators are now applied to methods on the builder. They can also incorporate a "when=" argument to specify that a method is run only when certain conditions apply. For packages that do not define their own builder, forwarding logic is added between the builder and package (methods not found in one will be retrieved from the other); this PR is expected to be fully backwards compatible with unmodified packages that use a single build system. --- lib/spack/docs/build_systems.rst | 1 - .../docs/build_systems/autotoolspackage.rst | 8 +- .../docs/build_systems/bundlepackage.rst | 6 +- lib/spack/docs/build_systems/cmakepackage.rst | 12 +- lib/spack/docs/build_systems/luapackage.rst | 10 +- .../docs/build_systems/makefilepackage.rst | 8 +- lib/spack/docs/build_systems/mavenpackage.rst | 8 +- lib/spack/docs/build_systems/mesonpackage.rst | 8 +- .../docs/build_systems/multiplepackage.rst | 350 -- .../docs/build_systems/octavepackage.rst | 8 +- lib/spack/docs/build_systems/perlpackage.rst | 8 +- lib/spack/docs/build_systems/qmakepackage.rst | 8 +- .../docs/build_systems/racketpackage.rst | 8 +- lib/spack/docs/build_systems/rpackage.rst | 2 +- lib/spack/docs/build_systems/rubypackage.rst | 8 +- lib/spack/docs/build_systems/sconspackage.rst | 8 +- lib/spack/docs/build_systems/sippackage.rst | 8 +- lib/spack/docs/build_systems/wafpackage.rst | 8 +- lib/spack/docs/conf.py | 1 + lib/spack/docs/developer_guide.rst | 8 +- lib/spack/docs/features.rst | 32 +- lib/spack/docs/images/adapter.png | Bin 0 -> 673639 bytes .../images/builder_package_architecture.png | Bin 0 -> 460127 bytes lib/spack/docs/images/builder_phases.png | Bin 0 -> 131216 bytes .../docs/images/installation_pipeline.png | Bin 0 -> 129116 bytes .../images/original_package_architecture.png | Bin 0 -> 35639 bytes lib/spack/docs/images/packaging.excalidrawlib | 3092 +++++++++++++++++ lib/spack/docs/packaging_guide.rst | 644 +++- lib/spack/spack/audit.py | 35 +- lib/spack/spack/build_environment.py | 59 +- lib/spack/spack/build_systems/_checks.py | 124 + lib/spack/spack/build_systems/aspell_dict.py | 61 +- lib/spack/spack/build_systems/autotools.py | 427 +-- lib/spack/spack/build_systems/bundle.py | 31 + lib/spack/spack/build_systems/cached_cmake.py | 90 +- lib/spack/spack/build_systems/cmake.py | 306 +- lib/spack/spack/build_systems/generic.py | 44 + lib/spack/spack/build_systems/intel.py | 31 +- lib/spack/spack/build_systems/lua.py | 98 +- lib/spack/spack/build_systems/makefile.py | 137 +- lib/spack/spack/build_systems/maven.py | 69 +- lib/spack/spack/build_systems/meson.py | 185 +- lib/spack/spack/build_systems/nmake.py | 102 + lib/spack/spack/build_systems/octave.py | 69 +- lib/spack/spack/build_systems/oneapi.py | 11 +- lib/spack/spack/build_systems/perl.py | 87 +- lib/spack/spack/build_systems/python.py | 432 +-- lib/spack/spack/build_systems/qmake.py | 81 +- lib/spack/spack/build_systems/r.py | 89 +- lib/spack/spack/build_systems/racket.py | 70 +- lib/spack/spack/build_systems/ruby.py | 59 +- lib/spack/spack/build_systems/scons.py | 77 +- lib/spack/spack/build_systems/sip.py | 111 +- lib/spack/spack/build_systems/waf.py | 78 +- lib/spack/spack/builder.py | 574 +++ lib/spack/spack/cmd/info.py | 4 +- lib/spack/spack/cmd/uninstall.py | 2 +- lib/spack/spack/detection/common.py | 2 +- lib/spack/spack/directives.py | 18 +- lib/spack/spack/installer.py | 53 +- lib/spack/spack/mixins.py | 105 +- lib/spack/spack/multimethod.py | 20 +- lib/spack/spack/package.py | 10 +- lib/spack/spack/package_base.py | 316 +- lib/spack/spack/patch.py | 2 +- lib/spack/spack/test/audit.py | 2 +- lib/spack/spack/test/build_systems.py | 24 +- lib/spack/spack/test/builder.py | 123 + lib/spack/spack/test/cmd/info.py | 4 +- lib/spack/spack/test/cmd/install.py | 2 +- lib/spack/spack/test/cmd/test.py | 3 +- lib/spack/spack/test/concretize.py | 2 +- .../spack/test/concretize_requirements.py | 3 +- lib/spack/spack/test/config.py | 5 +- lib/spack/spack/test/graph.py | 13 + lib/spack/spack/test/install.py | 38 +- lib/spack/spack/test/repo.py | 4 +- lib/spack/spack/util/package_hash.py | 3 +- lib/spack/spack/util/web.py | 2 +- lib/spack/spack/variant.py | 2 +- .../stacks/aws-ahug-aarch64/spack.yaml | 2 + .../stacks/aws-isc-aarch64/spack.yaml | 2 + .../cloud_pipelines/stacks/aws-isc/spack.yaml | 2 + .../stacks/build_systems/spack.yaml | 2 + .../cloud_pipelines/stacks/e4s/spack.yaml | 2 + .../stacks/tutorial/spack.yaml | 2 + .../packages/callbacks/package.py | 45 + .../packages/custom-phases/package.py | 31 + .../packages/gnuconfig/package.py | 15 + .../packages/inheritance/package.py | 26 + .../packages/old-style-autotools/package.py | 50 + .../old-style-custom-phases/package.py | 34 + .../packages/old-style-derived/package.py | 21 + var/spack/repos/builder.test/repo.yaml | 2 + .../repos/builtin.mock/packages/a/package.py | 12 +- .../packages/attributes-foo/package.py | 1 - .../builtin.mock/packages/canfail/package.py | 12 +- .../packages/cmake-client/package.py | 10 +- .../builtin.mock/packages/cmake/package.py | 7 +- .../dev-build-test-dependent/package.py | 7 +- .../dev-build-test-install-phases/package.py | 1 + .../dev-build-test-install/package.py | 9 +- .../packages/fail-test-audit/package.py | 21 + .../packages/libtool-deletion/package.py | 13 +- .../packages/libtool-installation/package.py | 15 + .../packages/nosource-install/package.py | 3 - .../packages/test-build-callbacks/package.py | 23 +- .../test-install-callbacks/package.py | 16 +- .../package.py | 4 +- .../packages/trivial-smoke-test/package.py | 3 + .../repos/builtin/packages/alpgen/package.py | 119 +- .../builtin/packages/arpack-ng/package.py | 109 +- .../builtin/packages/binutils/package.py | 136 +- .../repos/builtin/packages/clara/package.py | 24 +- .../repos/builtin/packages/flex/package.py | 27 +- .../packages/gobject-introspection/package.py | 32 +- .../builtin/packages/harfbuzz/package.py | 71 +- .../packages/ibm-databroker/package.py | 2 +- .../builtin/packages/intel-tbb/package.py | 106 +- .../repos/builtin/packages/json-c/package.py | 23 +- .../repos/builtin/packages/libtree/package.py | 36 +- .../builtin/packages/libxkbcommon/package.py | 32 +- .../repos/builtin/packages/lua/package.py | 9 +- .../repos/builtin/packages/mesa/package.py | 44 +- .../builtin/packages/metis/gklib_path.patch | 11 + .../repos/builtin/packages/metis/package.py | 252 +- .../repos/builtin/packages/mmg/package.py | 33 +- .../repos/builtin/packages/nasm/package.py | 19 +- .../builtin/packages/netlib-lapack/package.py | 71 +- .../repos/builtin/packages/openmpi/package.py | 6 +- .../repos/builtin/packages/plasma/package.py | 53 +- .../builtin/packages/py-dm-tree/package.py | 13 +- .../packages/py-onnx-runtime/package.py | 2 +- .../builtin/packages/py-pillow/package.py | 15 +- .../builtin/packages/py-pybind11/package.py | 54 +- .../packages/py-pykokkos-base/package.py | 2 +- .../builtin/packages/py-tfdlpack/package.py | 2 +- .../packages/quantum-espresso/package.py | 55 +- .../repos/builtin/packages/racket/package.py | 57 +- .../builtin/packages/rkt-base/package.py | 2 - .../builtin/packages/rkt-cext-lib/package.py | 1 - .../packages/rkt-compiler-lib/package.py | 2 - .../packages/rkt-dynext-lib/package.py | 1 - .../packages/rkt-rackunit-lib/package.py | 1 - .../packages/rkt-scheme-lib/package.py | 1 - .../packages/rkt-testing-util-lib/package.py | 1 - .../builtin/packages/rkt-zo-lib/package.py | 2 - .../repos/builtin/packages/ruby/package.py | 129 +- .../repos/builtin/packages/scotch/package.py | 129 +- .../repos/builtin/packages/superlu/package.py | 143 +- .../repos/builtin/packages/swig/package.py | 36 +- .../repos/builtin/packages/sz/package.py | 125 +- .../builtin/packages/timemory/package.py | 2 +- .../builtin/packages/uncrustify/package.py | 33 +- .../repos/builtin/packages/zlib/package.py | 59 +- 155 files changed, 7460 insertions(+), 3568 deletions(-) delete mode 100644 lib/spack/docs/build_systems/multiplepackage.rst create mode 100644 lib/spack/docs/images/adapter.png create mode 100644 lib/spack/docs/images/builder_package_architecture.png create mode 100644 lib/spack/docs/images/builder_phases.png create mode 100644 lib/spack/docs/images/installation_pipeline.png create mode 100644 lib/spack/docs/images/original_package_architecture.png create mode 100644 lib/spack/docs/images/packaging.excalidrawlib create mode 100644 lib/spack/spack/build_systems/_checks.py create mode 100644 lib/spack/spack/build_systems/bundle.py create mode 100644 lib/spack/spack/build_systems/generic.py create mode 100644 lib/spack/spack/build_systems/nmake.py create mode 100644 lib/spack/spack/builder.py create mode 100644 lib/spack/spack/test/builder.py create mode 100644 var/spack/repos/builder.test/packages/callbacks/package.py create mode 100644 var/spack/repos/builder.test/packages/custom-phases/package.py create mode 100644 var/spack/repos/builder.test/packages/gnuconfig/package.py create mode 100644 var/spack/repos/builder.test/packages/inheritance/package.py create mode 100644 var/spack/repos/builder.test/packages/old-style-autotools/package.py create mode 100644 var/spack/repos/builder.test/packages/old-style-custom-phases/package.py create mode 100644 var/spack/repos/builder.test/packages/old-style-derived/package.py create mode 100644 var/spack/repos/builder.test/repo.yaml create mode 100644 var/spack/repos/builtin.mock/packages/fail-test-audit/package.py create mode 100644 var/spack/repos/builtin.mock/packages/libtool-installation/package.py create mode 100644 var/spack/repos/builtin/packages/metis/gklib_path.patch diff --git a/lib/spack/docs/build_systems.rst b/lib/spack/docs/build_systems.rst index 12191d29f09..1ce8d6746e4 100644 --- a/lib/spack/docs/build_systems.rst +++ b/lib/spack/docs/build_systems.rst @@ -65,7 +65,6 @@ on these ideas for each distinct build system that Spack supports: build_systems/custompackage build_systems/inteloneapipackage build_systems/intelpackage - build_systems/multiplepackage build_systems/rocmpackage build_systems/sourceforgepackage diff --git a/lib/spack/docs/build_systems/autotoolspackage.rst b/lib/spack/docs/build_systems/autotoolspackage.rst index d341d28d086..88fabc0c5df 100644 --- a/lib/spack/docs/build_systems/autotoolspackage.rst +++ b/lib/spack/docs/build_systems/autotoolspackage.rst @@ -5,9 +5,9 @@ .. _autotoolspackage: ----------------- -AutotoolsPackage ----------------- +--------- +Autotools +--------- Autotools is a GNU build system that provides a build-script generator. By running the platform-independent ``./configure`` script that comes @@ -17,7 +17,7 @@ with the package, you can generate a platform-dependent Makefile. Phases ^^^^^^ -The ``AutotoolsPackage`` base class comes with the following phases: +The ``AutotoolsBuilder`` and ``AutotoolsPackage`` base classes come with the following phases: #. ``autoreconf`` - generate the configure script #. ``configure`` - generate the Makefiles diff --git a/lib/spack/docs/build_systems/bundlepackage.rst b/lib/spack/docs/build_systems/bundlepackage.rst index 8787dce546c..7a826f5e178 100644 --- a/lib/spack/docs/build_systems/bundlepackage.rst +++ b/lib/spack/docs/build_systems/bundlepackage.rst @@ -5,9 +5,9 @@ .. _bundlepackage: -------------- -BundlePackage -------------- +------ +Bundle +------ ``BundlePackage`` represents a set of packages that are expected to work well together, such as a collection of commonly used software libraries. The diff --git a/lib/spack/docs/build_systems/cmakepackage.rst b/lib/spack/docs/build_systems/cmakepackage.rst index 9544a7df732..7a1db842de1 100644 --- a/lib/spack/docs/build_systems/cmakepackage.rst +++ b/lib/spack/docs/build_systems/cmakepackage.rst @@ -5,9 +5,9 @@ .. _cmakepackage: ------------- -CMakePackage ------------- +----- +CMake +----- Like Autotools, CMake is a widely-used build-script generator. Designed by Kitware, CMake is the most popular build system for new C, C++, and @@ -21,7 +21,7 @@ whereas Autotools is Unix-only. Phases ^^^^^^ -The ``CMakePackage`` base class comes with the following phases: +The ``CMakeBuilder`` and ``CMakePackage`` base classes come with the following phases: #. ``cmake`` - generate the Makefile #. ``build`` - build the package @@ -130,8 +130,8 @@ Adding flags to cmake To add additional flags to the ``cmake`` call, simply override the ``cmake_args`` function. The following example defines values for the flags ``WHATEVER``, ``ENABLE_BROKEN_FEATURE``, ``DETECT_HDF5``, and ``THREADS`` with -and without the :meth:`~spack.build_systems.cmake.CMakePackage.define` and -:meth:`~spack.build_systems.cmake.CMakePackage.define_from_variant` helper functions: +and without the :meth:`~spack.build_systems.cmake.CMakeBuilder.define` and +:meth:`~spack.build_systems.cmake.CMakeBuilder.define_from_variant` helper functions: .. code-block:: python diff --git a/lib/spack/docs/build_systems/luapackage.rst b/lib/spack/docs/build_systems/luapackage.rst index 6332edfc205..fd70f90c492 100644 --- a/lib/spack/docs/build_systems/luapackage.rst +++ b/lib/spack/docs/build_systems/luapackage.rst @@ -5,11 +5,11 @@ .. _luapackage: ------------- -LuaPackage ------------- +--- +Lua +--- -LuaPackage is a helper for the common case of Lua packages that provide +The ``Lua`` build-system is a helper for the common case of Lua packages that provide a rockspec file. This is not meant to take a rock archive, but to build a source archive or repository that provides a rockspec, which should cover most lua packages. In the case a Lua package builds by Make rather than @@ -19,7 +19,7 @@ luarocks, prefer MakefilePackage. Phases ^^^^^^ -The ``LuaPackage`` base class comes with the following phases: +The ``LuaBuilder`` and `LuaPackage`` base classes come with the following phases: #. ``unpack`` - if using a rock, unpacks the rock and moves into the source directory #. ``preprocess`` - adjust sources or rockspec to fix build diff --git a/lib/spack/docs/build_systems/makefilepackage.rst b/lib/spack/docs/build_systems/makefilepackage.rst index c092432037d..5a83d612fa2 100644 --- a/lib/spack/docs/build_systems/makefilepackage.rst +++ b/lib/spack/docs/build_systems/makefilepackage.rst @@ -5,9 +5,9 @@ .. _makefilepackage: ---------------- -MakefilePackage ---------------- +-------- +Makefile +-------- The most primitive build system a package can use is a plain Makefile. Makefiles are simple to write for small projects, but they usually @@ -18,7 +18,7 @@ variables. Phases ^^^^^^ -The ``MakefilePackage`` base class comes with 3 phases: +The ``MakefileBuilder`` and ``MakefilePackage`` base classes come with 3 phases: #. ``edit`` - edit the Makefile #. ``build`` - build the project diff --git a/lib/spack/docs/build_systems/mavenpackage.rst b/lib/spack/docs/build_systems/mavenpackage.rst index 94ce128d3a2..d1237ce34c3 100644 --- a/lib/spack/docs/build_systems/mavenpackage.rst +++ b/lib/spack/docs/build_systems/mavenpackage.rst @@ -5,9 +5,9 @@ .. _mavenpackage: ------------- -MavenPackage ------------- +----- +Maven +----- Apache Maven is a general-purpose build system that does not rely on Makefiles to build software. It is designed for building and @@ -17,7 +17,7 @@ managing and Java-based project. Phases ^^^^^^ -The ``MavenPackage`` base class comes with the following phases: +The ``MavenBuilder`` and ``MavenPackage`` base classes come with the following phases: #. ``build`` - compile code and package into a JAR file #. ``install`` - copy to installation prefix diff --git a/lib/spack/docs/build_systems/mesonpackage.rst b/lib/spack/docs/build_systems/mesonpackage.rst index 5ca444dcb1c..c32b2241bc7 100644 --- a/lib/spack/docs/build_systems/mesonpackage.rst +++ b/lib/spack/docs/build_systems/mesonpackage.rst @@ -5,9 +5,9 @@ .. _mesonpackage: ------------- -MesonPackage ------------- +----- +Meson +----- Much like Autotools and CMake, Meson is a build system. But it is meant to be both fast and as user friendly as possible. GNOME's goal @@ -17,7 +17,7 @@ is to port modules to use the Meson build system. Phases ^^^^^^ -The ``MesonPackage`` base class comes with the following phases: +The ``MesonBuilder`` and ``MesonPackage`` base classes come with the following phases: #. ``meson`` - generate ninja files #. ``build`` - build the project diff --git a/lib/spack/docs/build_systems/multiplepackage.rst b/lib/spack/docs/build_systems/multiplepackage.rst deleted file mode 100644 index 71751f0dbf1..00000000000 --- a/lib/spack/docs/build_systems/multiplepackage.rst +++ /dev/null @@ -1,350 +0,0 @@ -.. 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) - -.. _multiplepackage: - ----------------------- -Multiple Build Systems ----------------------- - -Quite frequently, a package will change build systems from one version to the -next. For example, a small project that once used a single Makefile to build -may now require Autotools to handle the increased number of files that need to -be compiled. Or, a package that once used Autotools may switch to CMake for -Windows support. In this case, it becomes a bit more challenging to write a -single build recipe for this package in Spack. - -There are several ways that this can be handled in Spack: - -#. Subclass the new build system, and override phases as needed (preferred) -#. Subclass ``Package`` and implement ``install`` as needed -#. Create separate ``*-cmake``, ``*-autotools``, etc. packages for each build system -#. Rename the old package to ``*-legacy`` and create a new package -#. Move the old package to a ``legacy`` repository and create a new package -#. Drop older versions that only support the older build system - -Of these options, 1 is preferred, and will be demonstrated in this -documentation. Options 3-5 have issues with concretization, so shouldn't be -used. Options 4-5 also don't support more than two build systems. Option 6 only -works if the old versions are no longer needed. Option 1 is preferred over 2 -because it makes it easier to drop the old build system entirely. - -The exact syntax of the package depends on which build systems you need to -support. Below are a couple of common examples. - -^^^^^^^^^^^^^^^^^^^^^ -Makefile -> Autotools -^^^^^^^^^^^^^^^^^^^^^ - -Let's say we have the following package: - -.. code-block:: python - - class Foo(MakefilePackage): - version("1.2.0", sha256="...") - - def edit(self, spec, prefix): - filter_file("CC=", "CC=" + spack_cc, "Makefile") - - def install(self, spec, prefix): - install_tree(".", prefix) - - -The package subclasses from :ref:`makefilepackage`, which has three phases: - -#. ``edit`` (does nothing by default) -#. ``build`` (runs ``make`` by default) -#. ``install`` (runs ``make install`` by default) - -In this case, the ``install`` phase needed to be overridden because the -Makefile did not have an install target. We also modify the Makefile to use -Spack's compiler wrappers. The default ``build`` phase is not changed. - -Starting with version 1.3.0, we want to use Autotools to build instead. -:ref:`autotoolspackage` has four phases: - -#. ``autoreconf`` (does not if a configure script already exists) -#. ``configure`` (runs ``./configure --prefix=...`` by default) -#. ``build`` (runs ``make`` by default) -#. ``install`` (runs ``make install`` by default) - -If the only version we need to support is 1.3.0, the package would look as -simple as: - -.. code-block:: python - - class Foo(AutotoolsPackage): - version("1.3.0", sha256="...") - - def configure_args(self): - return ["--enable-shared"] - - -In this case, we use the default methods for each phase and only override -``configure_args`` to specify additional flags to pass to ``./configure``. - -If we wanted to write a single package that supports both versions 1.2.0 and -1.3.0, it would look something like: - -.. code-block:: python - - class Foo(AutotoolsPackage): - version("1.3.0", sha256="...") - version("1.2.0", sha256="...", deprecated=True) - - def configure_args(self): - return ["--enable-shared"] - - # Remove the following once version 1.2.0 is dropped - @when("@:1.2") - def patch(self): - filter_file("CC=", "CC=" + spack_cc, "Makefile") - - @when("@:1.2") - def autoreconf(self, spec, prefix): - pass - - @when("@:1.2") - def configure(self, spec, prefix): - pass - - @when("@:1.2") - def install(self, spec, prefix): - install_tree(".", prefix) - - -There are a few interesting things to note here: - -* We added ``deprecated=True`` to version 1.2.0. This signifies that version - 1.2.0 is deprecated and shouldn't be used. However, if a user still relies - on version 1.2.0, it's still there and builds just fine. -* We moved the contents of the ``edit`` phase to the ``patch`` function. Since - ``AutotoolsPackage`` doesn't have an ``edit`` phase, the only way for this - step to be executed is to move it to the ``patch`` function, which always - gets run. -* The ``autoreconf`` and ``configure`` phases become no-ops. Since the old - Makefile-based build system doesn't use these, we ignore these phases when - building ``foo@1.2.0``. -* The ``@when`` decorator is used to override these phases only for older - versions. The default methods are used for ``foo@1.3:``. - -Once a new Spack release comes out, version 1.2.0 and everything below the -comment can be safely deleted. The result is the same as if we had written a -package for version 1.3.0 from scratch. - -^^^^^^^^^^^^^^^^^^ -Autotools -> CMake -^^^^^^^^^^^^^^^^^^ - -Let's say we have the following package: - -.. code-block:: python - - class Bar(AutotoolsPackage): - version("1.2.0", sha256="...") - - def configure_args(self): - return ["--enable-shared"] - - -The package subclasses from :ref:`autotoolspackage`, which has four phases: - -#. ``autoreconf`` (does not if a configure script already exists) -#. ``configure`` (runs ``./configure --prefix=...`` by default) -#. ``build`` (runs ``make`` by default) -#. ``install`` (runs ``make install`` by default) - -In this case, we use the default methods for each phase and only override -``configure_args`` to specify additional flags to pass to ``./configure``. - -Starting with version 1.3.0, we want to use CMake to build instead. -:ref:`cmakepackage` has three phases: - -#. ``cmake`` (runs ``cmake ...`` by default) -#. ``build`` (runs ``make`` by default) -#. ``install`` (runs ``make install`` by default) - -If the only version we need to support is 1.3.0, the package would look as -simple as: - -.. code-block:: python - - class Bar(CMakePackage): - version("1.3.0", sha256="...") - - def cmake_args(self): - return [self.define("BUILD_SHARED_LIBS", True)] - - -In this case, we use the default methods for each phase and only override -``cmake_args`` to specify additional flags to pass to ``cmake``. - -If we wanted to write a single package that supports both versions 1.2.0 and -1.3.0, it would look something like: - -.. code-block:: python - - class Bar(CMakePackage): - version("1.3.0", sha256="...") - version("1.2.0", sha256="...", deprecated=True) - - def cmake_args(self): - return [self.define("BUILD_SHARED_LIBS", True)] - - # Remove the following once version 1.2.0 is dropped - def configure_args(self): - return ["--enable-shared"] - - @when("@:1.2") - def cmake(self, spec, prefix): - configure("--prefix=" + prefix, *self.configure_args()) - - -There are a few interesting things to note here: - -* We added ``deprecated=True`` to version 1.2.0. This signifies that version - 1.2.0 is deprecated and shouldn't be used. However, if a user still relies - on version 1.2.0, it's still there and builds just fine. -* Since CMake and Autotools are so similar, we only need to override the - ``cmake`` phase, we can use the default ``build`` and ``install`` phases. -* We override ``cmake`` to run ``./configure`` for older versions. - ``configure_args`` remains the same. -* The ``@when`` decorator is used to override these phases only for older - versions. The default methods are used for ``bar@1.3:``. - -Once a new Spack release comes out, version 1.2.0 and everything below the -comment can be safely deleted. The result is the same as if we had written a -package for version 1.3.0 from scratch. - -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Multiple build systems for the same version -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -During the transition from one build system to another, developers often -support multiple build systems at the same time. Spack can only use a single -build system for a single version. To decide which build system to use for a -particular version, take the following things into account: - -1. If the developers explicitly state that one build system is preferred over - another, use that one. -2. If one build system is considered "experimental" while another is considered - "stable", use the stable build system. -3. Otherwise, use the newer build system. - -The developer preference for which build system to use can change over time as -a newer build system becomes stable/recommended. - -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Dropping support for old build systems -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -When older versions of a package don't support a newer build system, it can be -tempting to simply delete them from a package. This significantly reduces -package complexity and makes the build recipe much easier to maintain. However, -other packages or Spack users may rely on these older versions. The recommended -approach is to first support both build systems (as demonstrated above), -:ref:`deprecate ` versions that rely on the old build system, and -remove those versions and any phases that needed to be overridden in the next -Spack release. - -^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Three or more build systems -^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -In rare cases, a package may change build systems multiple times. For example, -a package may start with Makefiles, then switch to Autotools, then switch to -CMake. The same logic used above can be extended to any number of build systems. -For example: - -.. code-block:: python - - class Baz(CMakePackage): - version("1.4.0", sha256="...") # CMake - version("1.3.0", sha256="...") # Autotools - version("1.2.0", sha256="...") # Makefile - - def cmake_args(self): - return [self.define("BUILD_SHARED_LIBS", True)] - - # Remove the following once version 1.3.0 is dropped - def configure_args(self): - return ["--enable-shared"] - - @when("@1.3") - def cmake(self, spec, prefix): - configure("--prefix=" + prefix, *self.configure_args()) - - # Remove the following once version 1.2.0 is dropped - @when("@:1.2") - def patch(self): - filter_file("CC=", "CC=" + spack_cc, "Makefile") - - @when("@:1.2") - def cmake(self, spec, prefix): - pass - - @when("@:1.2") - def install(self, spec, prefix): - install_tree(".", prefix) - - -^^^^^^^^^^^^^^^^^^^ -Additional examples -^^^^^^^^^^^^^^^^^^^ - -When writing new packages, it often helps to see examples of existing packages. -Here is an incomplete list of existing Spack packages that have changed build -systems before: - -================ ===================== ================ -Package Previous Build System New Build System -================ ===================== ================ -amber custom CMake -arpack-ng Autotools CMake -atk Autotools Meson -blast None Autotools -dyninst Autotools CMake -evtgen Autotools CMake -fish Autotools CMake -gdk-pixbuf Autotools Meson -glib Autotools Meson -glog Autotools CMake -gmt Autotools CMake -gtkplus Autotools Meson -hpl Makefile Autotools -interproscan Perl Maven -jasper Autotools CMake -kahip SCons CMake -kokkos Makefile CMake -kokkos-kernels Makefile CMake -leveldb Makefile CMake -libdrm Autotools Meson -libjpeg-turbo Autotools CMake -mesa Autotools Meson -metis None CMake -mpifileutils Autotools CMake -muparser Autotools CMake -mxnet Makefile CMake -nest Autotools CMake -neuron Autotools CMake -nsimd CMake nsconfig -opennurbs Makefile CMake -optional-lite None CMake -plasma Makefile CMake -preseq Makefile Autotools -protobuf Autotools CMake -py-pygobject Autotools Python -singularity Autotools Makefile -span-lite None CMake -ssht Makefile CMake -string-view-lite None CMake -superlu Makefile CMake -superlu-dist Makefile CMake -uncrustify Autotools CMake -================ ===================== ================ - -Packages that support multiple build systems can be a bit confusing to write. -Don't hesitate to open an issue or draft pull request and ask for advice from -other Spack developers! diff --git a/lib/spack/docs/build_systems/octavepackage.rst b/lib/spack/docs/build_systems/octavepackage.rst index 9a81671db6c..32e8cb61b34 100644 --- a/lib/spack/docs/build_systems/octavepackage.rst +++ b/lib/spack/docs/build_systems/octavepackage.rst @@ -5,9 +5,9 @@ .. _octavepackage: -------------- -OctavePackage -------------- +------ +Octave +------ Octave has its own build system for installing packages. @@ -15,7 +15,7 @@ Octave has its own build system for installing packages. Phases ^^^^^^ -The ``OctavePackage`` base class has a single phase: +The ``OctaveBuilder`` and ``OctavePackage`` base classes have a single phase: #. ``install`` - install the package diff --git a/lib/spack/docs/build_systems/perlpackage.rst b/lib/spack/docs/build_systems/perlpackage.rst index be81ca6ce97..4e1f613c3b7 100644 --- a/lib/spack/docs/build_systems/perlpackage.rst +++ b/lib/spack/docs/build_systems/perlpackage.rst @@ -5,9 +5,9 @@ .. _perlpackage: ------------ -PerlPackage ------------ +---- +Perl +---- Much like Octave, Perl has its own language-specific build system. @@ -16,7 +16,7 @@ build system. Phases ^^^^^^ -The ``PerlPackage`` base class comes with 3 phases that can be overridden: +The ``PerlBuilder`` and ``PerlPackage`` base classes come with 3 phases that can be overridden: #. ``configure`` - configure the package #. ``build`` - build the package diff --git a/lib/spack/docs/build_systems/qmakepackage.rst b/lib/spack/docs/build_systems/qmakepackage.rst index 6e8bcef7ccb..215d59536e2 100644 --- a/lib/spack/docs/build_systems/qmakepackage.rst +++ b/lib/spack/docs/build_systems/qmakepackage.rst @@ -5,9 +5,9 @@ .. _qmakepackage: ------------- -QMakePackage ------------- +----- +QMake +----- Much like Autotools and CMake, QMake is a build-script generator designed by the developers of Qt. In its simplest form, Spack's @@ -29,7 +29,7 @@ variables or edit ``*.pro`` files to get things working properly. Phases ^^^^^^ -The ``QMakePackage`` base class comes with the following phases: +The ``QMakeBuilder`` and ``QMakePackage`` base classes come with the following phases: #. ``qmake`` - generate Makefiles #. ``build`` - build the project diff --git a/lib/spack/docs/build_systems/racketpackage.rst b/lib/spack/docs/build_systems/racketpackage.rst index 8ba37ceebaa..5e09ffca4a6 100644 --- a/lib/spack/docs/build_systems/racketpackage.rst +++ b/lib/spack/docs/build_systems/racketpackage.rst @@ -5,9 +5,9 @@ .. _racketpackage: -------------- -RacketPackage -------------- +------ +Racket +------ Much like Python, Racket packages and modules have their own special build system. To learn more about the specifics of Racket package system, please refer to the @@ -17,7 +17,7 @@ To learn more about the specifics of Racket package system, please refer to the Phases ^^^^^^ -The ``RacketPackage`` base class provides an ``install`` phase that +The ``RacketBuilder`` and ``RacketPackage`` base classes provides an ``install`` phase that can be overridden, corresponding to the use of: .. code-block:: console diff --git a/lib/spack/docs/build_systems/rpackage.rst b/lib/spack/docs/build_systems/rpackage.rst index 671af779b13..ebf2270e8e6 100644 --- a/lib/spack/docs/build_systems/rpackage.rst +++ b/lib/spack/docs/build_systems/rpackage.rst @@ -19,7 +19,7 @@ new Spack packages for. Phases ^^^^^^ -The ``RPackage`` base class has a single phase: +The ``RBuilder`` and ``RPackage`` base classes have a single phase: #. ``install`` - install the package diff --git a/lib/spack/docs/build_systems/rubypackage.rst b/lib/spack/docs/build_systems/rubypackage.rst index b64ac60b2f9..5b6ec462a6a 100644 --- a/lib/spack/docs/build_systems/rubypackage.rst +++ b/lib/spack/docs/build_systems/rubypackage.rst @@ -5,9 +5,9 @@ .. _rubypackage: ------------ -RubyPackage ------------ +---- +Ruby +---- Like Perl, Python, and R, Ruby has its own build system for installing Ruby gems. @@ -16,7 +16,7 @@ installing Ruby gems. Phases ^^^^^^ -The ``RubyPackage`` base class provides the following phases that +The ``RubyBuilder`` and ``RubyPackage`` base classes provide the following phases that can be overridden: #. ``build`` - build everything needed to install diff --git a/lib/spack/docs/build_systems/sconspackage.rst b/lib/spack/docs/build_systems/sconspackage.rst index cea0408651b..aea5dacfa72 100644 --- a/lib/spack/docs/build_systems/sconspackage.rst +++ b/lib/spack/docs/build_systems/sconspackage.rst @@ -5,9 +5,9 @@ .. _sconspackage: ------------- -SConsPackage ------------- +----- +SCons +----- SCons is a general-purpose build system that does not rely on Makefiles to build software. SCons is written in Python, and handles @@ -42,7 +42,7 @@ As previously mentioned, SCons allows developers to add subcommands like $ scons install -To facilitate this, the ``SConsPackage`` base class provides the +To facilitate this, the ``SConsBuilder`` and ``SconsPackage`` base classes provide the following phases: #. ``build`` - build the package diff --git a/lib/spack/docs/build_systems/sippackage.rst b/lib/spack/docs/build_systems/sippackage.rst index 5235015a92c..3e77968e801 100644 --- a/lib/spack/docs/build_systems/sippackage.rst +++ b/lib/spack/docs/build_systems/sippackage.rst @@ -5,9 +5,9 @@ .. _sippackage: ----------- -SIPPackage ----------- +--- +SIP +--- SIP is a tool that makes it very easy to create Python bindings for C and C++ libraries. It was originally developed to create PyQt, the Python bindings for @@ -22,7 +22,7 @@ provides support functions to the automatically generated code. Phases ^^^^^^ -The ``SIPPackage`` base class comes with the following phases: +The ``SIPBuilder`` and ``SIPPackage`` base classes come with the following phases: #. ``configure`` - configure the package #. ``build`` - build the package diff --git a/lib/spack/docs/build_systems/wafpackage.rst b/lib/spack/docs/build_systems/wafpackage.rst index 54fcba98d00..f91479ce43a 100644 --- a/lib/spack/docs/build_systems/wafpackage.rst +++ b/lib/spack/docs/build_systems/wafpackage.rst @@ -5,9 +5,9 @@ .. _wafpackage: ----------- -WafPackage ----------- +--- +Waf +--- Like SCons, Waf is a general-purpose build system that does not rely on Makefiles to build software. @@ -16,7 +16,7 @@ on Makefiles to build software. Phases ^^^^^^ -The ``WafPackage`` base class comes with the following phases: +The ``WafBuilder`` and ``WafPackage`` base classes come with the following phases: #. ``configure`` - configure the project #. ``build`` - build the project diff --git a/lib/spack/docs/conf.py b/lib/spack/docs/conf.py index 1bdce87238e..4fc321c72d5 100644 --- a/lib/spack/docs/conf.py +++ b/lib/spack/docs/conf.py @@ -209,6 +209,7 @@ def setup(sphinx): # Spack classes that are private and we don't want to expose ("py:class", "spack.provider_index._IndexBase"), ("py:class", "spack.repo._PrependFileLoader"), + ("py:class", "spack.build_systems._checks.BaseBuilder"), # Spack classes that intersphinx is unable to resolve ("py:class", "spack.version.VersionBase"), ] diff --git a/lib/spack/docs/developer_guide.rst b/lib/spack/docs/developer_guide.rst index c4d04cb485e..6b67ef9f77e 100644 --- a/lib/spack/docs/developer_guide.rst +++ b/lib/spack/docs/developer_guide.rst @@ -149,11 +149,9 @@ grouped by functionality. Package-related modules ^^^^^^^^^^^^^^^^^^^^^^^ -:mod:`spack.package` - Contains the :class:`~spack.package_base.Package` class, which - is the superclass for all packages in Spack. Methods on ``Package`` - implement all phases of the :ref:`package lifecycle - ` and manage the build process. +:mod:`spack.package_base` + Contains the :class:`~spack.package_base.PackageBase` class, which + is the superclass for all packages in Spack. :mod:`spack.util.naming` Contains functions for mapping between Spack package names, diff --git a/lib/spack/docs/features.rst b/lib/spack/docs/features.rst index 985da967fd1..1682616adb8 100644 --- a/lib/spack/docs/features.rst +++ b/lib/spack/docs/features.rst @@ -98,40 +98,42 @@ For example, this command: .. code-block:: console - $ spack create http://www.mr511.de/software/libelf-0.8.13.tar.gz + $ spack create https://ftp.osuosl.org/pub/blfs/conglomeration/libelf/libelf-0.8.13.tar.gz creates a simple python file: .. code-block:: python - from spack import * + from spack.package import * - class Libelf(Package): + class Libelf(AutotoolsPackage): """FIXME: Put a proper description of your package here.""" # FIXME: Add a proper url for your package's homepage here. - homepage = "http://www.example.com" - url = "http://www.mr511.de/software/libelf-0.8.13.tar.gz" + homepage = "https://www.example.com" + url = "https://ftp.osuosl.org/pub/blfs/conglomeration/libelf/libelf-0.8.13.tar.gz" - version('0.8.13', '4136d7b4c04df68b686570afa26988ac') + # FIXME: Add a list of GitHub accounts to + # notify when the package is updated. + # maintainers = ["github_user1", "github_user2"] + + version("0.8.13", sha256="591a9b4ec81c1f2042a97aa60564e0cb79d041c52faa7416acb38bc95bd2c76d") # FIXME: Add dependencies if required. - # depends_on('foo') + # depends_on("foo") - def install(self, spec, prefix): - # FIXME: Modify the configure line to suit your build system here. - configure('--prefix={0}'.format(prefix)) - - # FIXME: Add logic to build and install here. - make() - make('install') + def configure_args(self): + # FIXME: Add arguments other than --prefix + # FIXME: If not needed delete this function + args = [] + return args It doesn't take much python coding to get from there to a working package: .. literalinclude:: _spack_root/var/spack/repos/builtin/packages/libelf/package.py - :lines: 6- + :lines: 5- Spack also provides wrapper functions around common commands like ``configure``, ``make``, and ``cmake`` to make writing packages diff --git a/lib/spack/docs/images/adapter.png b/lib/spack/docs/images/adapter.png new file mode 100644 index 0000000000000000000000000000000000000000..aa889c2c324ad1e2e10eacc0f1392a6b406d24c3 GIT binary patch literal 673639 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%0D7zb*m|ELL*%(YFP`&lwWK9P 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

x07*naRJjX3s8RbV5@feqYW4@r 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✍t>e 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

39uC8tXowCD4nZaJ0I;y;w4EM{I`q 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%0A<{8z%{lTLKNRwks{>2TGWoF! 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 Hw#65(|1T0 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

  • ZKuG-Dm^_NGuZG3G^Rk8E5o!P*= zQY+Lz)GZA1vqrbug46O&dN1PE4QL=~zC?IUHbHppm>7=wL+S+E-+YvDFqBr*)2lC8 z@vTgILZjeOKDzA#_vI#}^9K_6*l$sM*6$=FB*yE<==xD3b1Y6SS2j@ft2k7w&H#wt zOI*Z2XB$Ks%jSuTQuq8IA2Zyu0x$(cqSY#oCe3Q%PN&6}K8rc45j$Z5&IsUdB zfI<3v7H2Q3JfWg7#_WJWupGzSBjO}f*J39rW*dk%mfU{V6km?%eAHatk(@MZ1RbhX zVaNgw0M1MebuxP|RVwUT@u&%3d4hav+88||!eMsN{-J1AYlqJUt8kcid<`qYBZ>oe zFW6&DANe}cQZriah;a+}ruWrTiIzku#~!v0_sx?wh4|=2LPl=HZB7)hMD0gUk`;Ep zBqbw015XIvaKd%)puVau?M&{09zGxgxC#`auB=Wu9qi^_QNVRQR2z$16Ku9|!tTr& zfe{72gqp>%Ep#RB$q!J-2DcHqrBjjFR-uVwpjB`Sz{79)74w7YW*{yg10b4p%n zks*nzs7RgNCtsBmjQsd=*!01N(3_?bw4cM767}l^r-#?OJ7@RAZG*!d%1;!!uK!}r z|69M}BmQThb!T+yt4%CH-D1RfC1Q6J1H*X94tr(;nX)wweU>#5KiK5t!sE7H(`>fb z`laeud7zpFA*xz_vv`Sk)#{J8UBC|a^8-Eb7K!rY>KAog0oM(G^nX-UGr7EYHfWJQ zRM@|MJ$)NAOOui9b=7fWsR{diZ-g6j$*ogs ze*e}Rg-T_6S5)Z?pi2_ycsVk(fk84*_f@FnBOiNMz0fs{&AEg5wkcq^B{v4z8^}7F z)Fg-{U$c3{@>{hZRV8PZ9e@{^LYIMoT=$5{?-|t#oVJ94X}0JM1_T&~DU6XRQ8wOZ z*LphnNp2K_tm37%!@qyYzGUbbbftl6n@1JM{t$Hb;jF+G+RlOtIau?*mB`fQrPa-9 z(`5-kZ#}^8Brm=VES!?Rh*3?gjWrXGa(dP@?4qcuP9?b*IXYiv#--c-b?Tq5v)Sp+vLK(c3IB2s^!UZu#ovZIPcBIMD? zjPsQLH-^d_JT5qJN}g)60`ceTg2%(@^W_c4?+LJV``n*Q|PsQ0C9h_$lT@Q)zl#opMr14nMT0e zo@tg|KyClf3(Psv zgiUg+{7G)Kaf+o-(jcmQa)%usS%sr{@$9v1)VfCKx(p_?~wmGyc!&DT$GNE{mt9Bp_7Rk3 zyKT_WFrfw(|DszkKgxgWQ9!Ti>no-&lyMofS~}H5r$vx&70Y+Jmnao$aU4Ie!u(XR?C`ngQE69$4%7eJz7*)$YZnn zxzGrbDAMHMuMX04mSKz(M_%PB$84N;?)@F`60MKSyGgnXKqVw#p-_gMXEN30x(wnU zRSS7~DN^ipQNLfd1%z=jgP7{~WGt0EF81$dhg|$e#j6s{Q*ULUh|%k2w~Vc!l58We zFI>J?5cX=pYykp~HIvNwoaCGYe|?)1;GgC>FGrf|p|Qv!L`5g&PasW--&(H8*zD%e zkCLZc>aR?R>l_IbsRG^`24|uM-KjbJHq>2xD)5d*`Mv4E(fN47)bcRDX1{JHU`}-G>-&mF0NGbcnrtp3K}AmyVFTNgDoA` zL`H&0g#{NV%YcYOOSwarHuC6b_GV8`)w4P9`M5g0DP;GL;}r}X?I2U}>eVb46`?BH zVZSD~fNf1IAUH^&FD zSHLT?SYJBzVHZE^y+;({wI05%QFvUNpX@vX3e)AP&E z*CvWW$Q&PKUz?c9J=Mv_5XW3xS!PXzhB%+fI(>k;&}o*n?Q;Pmb0D(DxJRj$k5ke% zGY>%9G3o$}7I7dDl)Q)Q3f!N|m()zm_)eY&YAMo7y(W$Xd?}Pl1S-rrD^SsS8H~7R zbinsdg&sI>pj`Q=oC?yo+u%Js{#2&o&`wPw{<#S;`VyE&Cxr}15Xso5az^($OjVn> zv1qTP7AngGEYhCS55;Tu56;VuDhJ3!>gZh)_Td^ae zG=bUWOeKTaBr^ItQ=zY)FDTuF^Yx^N{Gq;x>}lrG@$Q{RGA0hlqXCc<^#^McD2L@d zS2O{Tv=>STcJ-cEy?kDtA02oQjV-B1CwE?ZDS+-IqO%vmPoDqqYX7D9`Ya`_H+_)u z*iV2x8ts3Q=q)HRd0b}B`TlfYUjLP-ToS>l3%5J!t9J|%=%lstCs(9#=5VxvsmUe^ zGY2v|di%@yzd_j!t0A`Vo{j3Xe+|TTvB^!QwkEXMmdS&%tn|ACwL&|e95?ToAi1GAqB9TeQF?O0~ckppDRnWE{F@qN^61TFZx zx49;*aXOsRgpH0;S&|N;_-T)T8Q33dn8=qq@&PIPsBxT;2TxCq@`W!9_o(%JohNM^ zqWmw==HQVHy2vr9D`)rY*%PFPqfYltgGRjc(3j^5LjoyzR@+EZ(1G9nin>4RRKb2Q z>u&p9h;0q|rDTIls5+(cc?{*n`i^7d4{xlG-E~JbOq3If;soUCy?4!OBeMS(79pQ9 z+c|+pd8!RBr9or^JJU++(EQ*Ud$oc2BFA48h(x#)ECBk%pO9}8h;=>GHQGeDXS9R= z8zOOr;?o9JbiD!*=Y9Lw(0N`gj|jaS@DyXo`v=uvwy7{;{9*TTvNCV+q>geM6M0`k z$~OnhazTL6iO$s@<})Q-z+yhW-)FHkuD48Av`t>kwK~LGYh+~PYa?u4BK+og5Q>b% z#AVaQ2Po(>ymS69=?Ol#7on?nAq5O9I*~O^0=$0Oc*w|b#cc9X-DbQ*qb!%F%=O8qn`f0qMP=>n#dc3yi$?n@ z*^|r}Rj56^yR4>j;j2diHi?9>p;R7LJEYoFYNs#?WtGB6t1@3IU+D&P7d;fLMWmV37go#c1PXD4z+w zDE&*fO;a9!eNqT<2QVb)It9hC)6{*Q9Mi~R@33xnGySx?kh-@lIG7GN*SQ2JAc|f3 zz$6;A#w%O4^2H35_w2t*wUrm>c5uhO(;o&sZl{b`j!$JTz*p!B$DKq7+y!#Q(7cnK zm`f(#ydhW;lUvnK1>Y0FjYrk-iv--+aZ-)$EG_T`u#X@s1-=!#-1$#_PpG9L zG9xBLC`5kl(eEGaA>@K%QcP%gKPv^~UPCHE0{w^HlZB1QOz+6r_d@ZUG5#ZWzWs+Y zF`2<)G8~P|Y`ywxi}(?j|Kq(%rn9H9iQ__o^W`tn>->Gt-}E34Q`v&(uLhAlPO}z- z8lEVrs}>)@n(=%!cQ*h!Cn$izq<>zO*>mVu`$4VW#4V*(QiT2gm6ZI~=*uRpxBukH zc;4y;?KYoNgf+0Gmr|{OOQnY`(V+N4>e$5Mo$bW4Jr+BU(E8+J3)kvb@(hlE< zXC-SB;M;3=@d-lkPM-Xc@N=WpE)AK0OC#yCjf0w&c3~&Ynh~c%(x{VS{BrA^lFV0q z0OXvY@OgW*X$qH|mL%LWD$2iroolL_{LA}y0R36$Bg?48?O&NK!_u^rkWBG6j!FmS z{notlYRExvdXb;|r%NFSWx-~$g`r!qNu=<8xkFv5cjhmRv-?3w)m%X&kYl`gNzPr0 zWpo$+*vTElSx=u+!B3sdqc;!IspkKZ{p_QFn_!IxyJ7eUtmT)yC)mmwi?Tv=;km@O zd+VUWB()cLvR?!J!sdS>jgKfm#2`FYgpG`s5ELwDbdAG#Ud=m zc%^1RGBFJ6PiK?Ah?rQL-pXbX3S(re_zU2*QdZ8SG1FUs%FZH;gt0G<^r__8e5;a0CU^@ip@;)>1Z zd)v-9jYK{>Q;A)`A1`O2sXZ&K%NcFT8gR5v4$!i!rfRj0kGITj2$<`=ebJQnDXr|7 zOPuV_IB1^TMpz@M`jVuHrU%S!F{!9x@zk;iY69Jtz7ENur0CT;3eTv;UHn%Fkr z2u%43sJ;g;h&u0<;T~!%0sQf|3cImoLyELE1Qn)IJ8w zqs|ryt4)3I4dI9HyN41}W*^m4lWs`a>Ev%xmQAZC-f;p&eN6sl5avt@Y$#6_6rk>+ zhE2x_`VRQk!}lp9a^}ay;Tco)>6h68VUx#;HD;@2y7rU8D3ym~oLxv=gc6%9QgVt* z`!(P~EX6U<7BYl?SC$As-8xaR3uxg%QR-qwOFIx1ZLT3^R9|ngp`GC0A!d*5))I^U zL2u@KzUO85|6!DFP{)&*KZ#~?$R%y$lbS(k6!_tO^fd9=iD$1*NLy^J`52Nb`EJ^F zs+QN!WZKjYDTM5}YI5;Q)rQI78$<$9ajR44XP07|Obd9lm$s<2 zT!Z%2W$R%Z=u&v< z&zPKARid!7p_;!sL%IW=an?Lu;+DKPagmwN#hee~-b4k=J5ENUNp9BsoQ007qf@a7 z*m0~muLuhJle(asdwuNA!SCu`V}c~!kW=dI-j&%M$uYct8S#lU>mvQqQ32!#j|F{6 z()C)-gh(laxcOS{wMWTI2NKNF6AfqD7b)gD;9 zJ!`t;I7P)fOnMc#(*g_oE1NX3g*%%Hba1y0y+2yQwm!cZ@L{-`H#=p`BCd-6S+Vl1 zTD0vULdkuodmHVjHPbn(L;ie@gve-UR~flK1;2_Q^H`d#(6rnTHQSQDkGp0|jZ~0H z{nTP8Bf#zm_rHE+Y*%ftwU(Y4!l3%V)5ny4A_XP#-ECT^+t1>bfovMfcSgKMj?Ll2 zpR2;uKYyolQ<>+#gG6C^DqUp!a^EZ4$=ANsE^vtqNW&WNZTJ|hnP4L^MboEc*Z$TfLt%R ztF{B=kFAVsWz4dlNG=msfgpka1(#XmcshsH>3A}MAj2mZ61t_)cS7!TslBF&FMm0NeOI=B#;gt4zJi_}!&DY~+JnAbg4b1>s%P$& zHcU46ufwM>od0Y20YNOi063W}W=*vk9SZSg8(L5ap(6nl7fjX@O!Ii0ICVs;w#IK+ z&iTJ4(UXLyxyExp4Ipl}MJvWpObf4JU%EVPYptIfl`xzZ=$T@vE`$vY3o&tUCO{{E zvc87i_LmKvUY7>Ux9_v&EG%h0(77;E z8MAV$>~|F4zXj@NOD8fh#=yRP#@~Eq=Hn&(@Y@6`R4^0hHJ7n9d(uD|xblY%@M-J%b-f2!!RZCd?vS3Mf zNFzT4W|-(9VT&hYZ6PDyf?^}m06f;Clj*ul6P|keNHgtymS;jJRy0E=uia@SRA>m~ z)9$WpRPfSXdkdFGK$298LA(Xt=nq^`7>q}`PN%HCZpqzOA}rd?1qC7@-ZE6|tb3P; zE-$pR-R%$-RADlJdTut^mt%oqJ>%+;?k`SlSDdBMp@Is>(6HysHM^+!p8+INe-Dwu^z$caruf8mVZQA~O{48{0i@sUqBV7Sd4gM5ar<@= z+3MzX{x2#xcg^v&r-Mi67vQbDi6_4cUolf93_W7Y(^b5R&q_SY#>gG0&nwyMx?7zc zR2PKvsZz>CW!4&DQ|NF2qUG%Sp_%QrdD@RpEfSr~iE^w(#6;kJGt$~}DO%KF;$4w92PE( z$icS`<8NBy+y74sAVciGnrk0_WP(h&RfX}dIHY(Ao^-3hBr4lJ(4-_aJDbj|w?(+# zRg-@iFY(!rvnmRkKGA80w{?z&;7X4{-1Ve<%O4V+1L%x;V(r(~E&{zA-OGG_O+P@% zrESn9lkESOBov1RwA4R4)PCdP63pda(SBJav+biso9(y{F6GhgIp=jB(v~jCmpP2h zl^j2HgDHoa##-i*iBEUdn_E-DengmN`Q^j4C4-r>Z*&3?zpEEU0~Feww^+ZuMf@{f zUgp{$I2>04&v5`LVzIO`CTFp6SuWiqq|Ge{sUqioD0&~ z>2zR_y!6ef3rSFDf6^Pdpj3fo``TNTPQH!?J$YMLQ}C}oT$WGAmXhx`(!7##0W)bgGcOECRSx5srzPGyVA@eQ7ADUD}_SU0KHeK0A7s??b6mW+%suK zkZ7oKEx43lEEh05kpo8M^mMB!g|z!}_H8)!Fngc+AEgenf_5vV1Sn4A%(cE(s%!C4 z@;FW+V*ZYg2u(VXFAsnj@+}_ai;s3KDQT)l`5S~s5cKzf96fN@x3X$W(a5&7^|ckq z7_4fnrTJ$~)wvHel@nI56frQDKE*3hDD!Wa8(L-JV_gZjwN12-d+Y7(^IU8lxhrud z#*Ws-JZJSXkS>EhBks!P={K?!B!XRk&hGr^(neBoB&>;*Y!7|UR_|XXUkKS)#4pL* zj?}FjV1lF6iLp7XEnAFJmd7E@*q!KM6zTrp2J`Lkfg%3xK}_eHc`$=5W>pL=tIt1) zVo5BiFBB{FQ?GopDC^*PzZnG13ZtCbW*y=iqc4Z*jM!>{f%IXZZU<*(rv*foqfe`_ z6KIErY#mMx5^X}fc|l~p=RYqX9kloL(H({91ksD2rlYE9ks7ETt=z(q1a;0qc~Mrz zmO?tUF5zk0R~Q{V@vzdW7V&`&-jDDV?FdYaANtTYQ)j^aNvgOR>W+h)j600abpu{xuMvBQVjtFdw1 zCRk8xWj0|_Jl$pPv*xl+R>fxXmnfZ1o5D2rb(dJyne!Kd=9|C_q*Q)DKx}Rb?Mikw z)%jO-a`I}pSQ0B{fn+tZB(ix~R76HzWaAoIqOAK|S!?VHa;thi^7LbXIq1d8yo3oT z<@`-QJZKckaZgI_bg0R=NyvY&#;7t32&Z%5BwNR+^g0jp9%HOanXmleQLo-eA<5pv z)6pLHXv4tnmsmEIke1oIW=63MVs2?v(lGJJsmQ&c;c-P_Yw;*{$(&#i-iF3WUU-RS zc35TasXp7N(>7YCf-}!k$RN(Z55TjxV}Im3%o};9Hc3Rr%Zt6?*f&w#D(1e%d-ZEv z?!=jbN8m)DCE3y%OeOprA!n8JZ#c!bV&_p@nie$u5ogjUo8(;7@lBneyf>?S)y2uF zM3qL!a0)7l1!_U>LBY{<Zj5LxC=D7%muz@k(u8|^yh zE!O61T%wEriL>1XxxM-RnFPp;E(>8gdG_Y}2TWn=N_Vtk;=R*Rk71qM)U~&iAcU_$ zwy_WxEsiQ5kYN7s^Q$xFoDs`odNgxghx z@2kVaqAunv6(8p1g@fF?p@WM);eCeLy$C zT20&?7JiDu_xIMa7cD*STw&t`98F1k_Xk32nV5}$)_f9tO`I>2{DHm&AH zosb`>$Z%M7)sPKJ)Lv0mhoQ9*%uPlIm28y2>I0M{dA?lAJHS-Rdlygp%Okh2&F}v` zC}qWWQ_^zN8s?Q=Z130`Y|fWo6$KnzFT_(L&k`)Q^^V;?kUxH@w_H^uO5&7_pE7ux zrv9ve^qhbivuZbi9%{_?b>?ojq_ z9m$NzD&82Q4Bf=6TuqyrOb8&@SMl)ilQg=b!~4T58ed$HdU2Fw_0>SozT~)F{E>;z z(6#BcA6Ji;bcYxlp}tK79VL#xh1U|r&XKAFXPhIkf6(tj<{%+mU;W2UKfNwnhS7_y z1##T~WW`%+sFTveT~yhHKZC?zdzgTsxz{?e*Sf9W*sme*D!~%n&x{#qOv%?j(UQ`iani^ zUb7BohwuM;;FX`|FjCWForztNmcWdi(djX$IL8as*x$8`!6MVWVB5!DNr3YcCl8ge zh@0)`A7m$eWzZ|+&WK@@PyWI=HnCZ#UplGHJmk8?W6=Eu@6lT7`iktt+|WR+QjG3T zF1SH?2^GY~szm-YMjScS*JF??vlhc018!*U#ItIeD7O#_LYt~CX*GRSHH{ejg<$cg z+#KcB2pth6h>@p17LBSVRTs_LucB~#1PHSHbv$vf`v)=MM18DUr?Gy06_9g*v@ z6N+#BpsmzH3)L|X*z<0ypMt>odTLj{gIWLks&?@y2?sq`2n7!HabW_!pAW|Bs~lD3 zkn#Tj0YU!0?wBY~^lw@;HR6t-Q)pmMy(B{|+njONU3bYd&pe}lKD}E{sU9&yh4P@P zc_9H@lk;=VIY&PI^iu%>_j_8mI?hhIbPc2 zL_eNbRjBZHU?7ImU_Qqu7E6_%A305?Ongti{9?U)zx6x0@1e&$FaGcc;SmUrKzIbg zBk=$J2t?HRW-{#!YIm?!VgeD`wE!9y9Y6|41b5vg) zO`xs+SgGEY6UE)A$Ve4WL$w-Vl}8_bKoS#^W!8)jW%usgx&|+1lIfEVjZsLfpO-l{ zQrOl2-}8bU@^S`Q_E7H><=UA^zuU-@$e;Gcek};h^x$@H+_+JlNr;4IsZvsq`#(L2 zpM3I(oPYlLjkXDtzGFwrTiq*|pp%$)Im9{#Bvv0>(jdmfdO$u&BA9&L*fm)$a)Bv2 zw-4`9CzNso`J7vynn6SZlQQ@D_H zy6GhOK}F&3LV+l$s8Jy_6w>VhXO`~;-cRC4QNjz2Vb+6h355?!tyMcM@ii~CU=lL6 zf8W_Dn)F~vXJGoD{8+9X8z$Ox^+^Uft{z8vt8Q~2l8jpu>cl!2c0m5sz3~K;PSn=D zLHTSm-t`YW=jw7tEc6JQyV_^4`Zyq11 z*Qo`sk8gwmP`LHJDm`{M1Md*n`Hv@BAK{y<@$X`SA35J3qTiLHE{8uYbDfB$*&8 zuAi5uG^F!9ti9MDo_lD1@Lc+Mw72F5h@rmk?w7*KT3K|t_q_tt8zW*k8O z+`F_ui*eYJy?>EEFP&?n``cM^SW2WU_Ms?YxyO4D9g2P)kavnK*t>C`B*#X`qU~kc zq;)F}*xd&}kx@8;(&GkG$6o6+8#HW}$=?SP!K_pcThtM#~8YH?43Zl0ssRl5W<^z2xbqpOKwAewC$*7s)d( zj0^Ql34b0Qf$#`~N8mpm0jzy$YD6NVA|%QrkD3@-*&#X{N z`-?5%BdXhQX|c%i>lh%uMc0vJ%Lr*zR#wW`v16rGt5)*#(@(4FISCZXy+>unNM31; zay7lY%pX`cKTM;c8G-d2@Aj!Gak&M#rAwpm9ob6m|)RW;_1|np^~g0vLPdh?Wv|9M z##8#Bq$ugxCdL&iN}}2Q$XNL)E2!73TXJOIQMO43?TXF`D#S)&et3#Iv=nLuom+&( z@Zv@h-@x?o=cdr0T;`N0g{Zrs51r!*y7Ay6NPDT)o8`}X zd%r|RiYy-!S{uP|tx=LUoOC#y6d>IA!N#Zj`qL719NxL8sdba_q(3SxAjMU+YWL&} zY`WgwfW={&Y|jbGHFNTG+>FJU+qFk0KUiHW1r?UXlbZz}>wWf1h1^-E_KycMfm%P^ z!MkkpTY&px}+*JE$EGrEIPZ@AY?cMT};sdXqF`wA%X zqo~a}^_qKgEWD?HwfjNn?b}5`|I?q!^ttX=?4ejkhjHrg3{~>hYx0sbO{m=hoq=c9 z6f4KyiPT_uc;%p8@TBMYj&0evfeok<=oprldAf9~vuEbLK?m2k6ga;ZG!F%!cP>m7 z1PgihdHH#pbqBnkEhSYo^==wo&nFrp0vw|mN_H+#XYU#%hf{F zb88Bfx&zh2FS?E2uh-`iAB`{2LaTqPkUM)c^Awy^j{lk>6}sg7A$CT>?N%J1Aj`PF zdcJkP@qR@Y!3(C&HOTzo&wMN`n~F5D4GI`Dx0L9y^gJ^3yM%imbODr*2_7o$+(%fP zo!us;iAIInm{OEG`|bU5c=IUvXjId4MV<=<8YozZ zoguRqER+6qMMYAMQ>C;D+En6mdqW13HyMEpL{Cr7GO;zYkUS3|KZ7%q!OzvA; zAc=92vS75oS05`fnyhEKJHA(b_`~oB{C{i&>N}DoOSXinyt-D3D@0iYi911r~4+z zyX$l0l!I$!U^~l&!~Q=BbU{IZyuUt64vH(6w5W3VbX$&eX;CflQmzR$zTf=MdKDEF zl2=qNWtA0DQ&lBW6V(5!tE=_;FT%2GIVK9RXyQxW=br@?Vh$!h}(F2^@DZ<9G4}4ar=az1Umsh==+Ug$ijN&@B$4hGq<+U$L)JvGouV0|a z0Hk`|buA>?=UHX8VN|C{5D1z&JjW0jqf2KG#N`(JSRpT-mm)x*vE(JGvIj^__Vt_& zv4R~JNwhP7u0shRVPww9SUuS<#j|tB`dI66K7polj=Z!JHt(@``)?pFRoAVha0dawPI;6=Tlc*$|c1gwIT8~Wmo zMfpOJXU%UFG9iSAyBRwYwD-O$)(-#0$9pG+piW4X5h3LHM^cH_s7ydT)6W0-TYS0c=?zEhn4C{bv4Op}@VWmLUt#zy`VwYz%?^Vz&6TdEz_L%{_ z|NO$BMpj+hLYl{Uzk_f5Bv0saqkrJmt>-&%58#>u(KTmOV;2PHJ{bP?O=l#^jPJ_z zx#vU_JJ&gXa<=R%49eQ;5ArNHgV+E$KtT-tv|Dg}fEc5Ig;1Fyf<9!dn=0*N_qg;I ztFX!34XOrH#HU9&PEYyZA1t~wR0=5bA0_$y%QZq+n zsA#J*ur)&*^MsZGd2i@}xsmjEd%rehR$Sebo`8Ml%WI2O7?b-7^iinuL!;oWx8BlS zJLcr>^8LouzSkZfx+dqndi9bOD^|$z<;xpAG>VFfq*=3Osv=uhSXjSt6?2)EBe78t z>XGWk&2#PvHz3d^ly7<2JA+F3svYGzA%Jso>Zzwmi-Qi9qQW9svwDRtUJse9OB$LU zEhmcpmlgUOvvmE@@YBAXhQ!1qDCTFRL_|htf)Wv7evj12pY``hsi-KIgv3PaZxMWE z{XHVmTF&}=ghWP0Nn}){ZYwe>s^KTguwGP@MDclKltMN4?cXPd9(tHW@%KPL|E9mQ zZd8;6q5^fF@wd9)qoV4*tM2>td(H3GzUh9MW2yhW?lawg@89c>&vvY4d-gFgzwi9@ zS7~=t`?|5P#<202H0&pLcvNJR)Ut0P5)%_8fygL{&@r>dr6eet7-l5JNJ*7QQKiV? zsdOYGb$mD{jD;qYb=}Ua(i(ly9^W!Xwq*t7;G{@toz?);V$u9^5$r>Jl4 z0!#01ERje0HCRLJ71ntD2#2{X1QK=gR=xbZNVT%pRz!~W*^1d*;Q#pr&mLYh zk)#Yy$R`s~IFeXDO&pfy`)ov814UjsM6*@p)SHjQ{;%0tCSzu1$$J+h$+*vR<@ijI zD^7|Py2e#iRr=HX&%a4#zx%UDo?WqD+BXl%B}YeSl53LPzj8}u{X85bK9Efuu^Ns5n^l*Cwxi;I)k*jPzONKpT8e&z+^tllAWyeBy0q!74rI*Jq+eR4a_buyX+w&IeJe0PJ??vqKA@-;j zU35{SPyLc}pnHE61Z7mGL_txUV`gkjaG#K9qOgvrlT)C}Yag$ln=4Cxtx($}KVCXr zWeO!sC@B=Nyqgy=#Ss#`-&H}qA)&E19q~gyI~D2}$%zb=^ZC)4)S<0|55PHArF<>e*&G z%-jPMI=GhKxG+`P+KLktN^hH=C;#Z0EVp&@PxLwWYyYT}Wmjd&K?mRyOqV`b)8NT% zyvVt(oXM{R*SC^cCczW|or>S9>+~bWo|dflB=@0nKNxcoMmXA?4~@~eDhmIXx$x1= zd1J!Qak1`%q26;^-UDpgj#l70rITz&(U6>RzDQarj)JB#B3o|BdAplt%j^FbC<`3^T{1hxxW_WViN(&NY&8DGbtx9>0e$})(_nIwqgGKEyT{TYR56Nuwc z*l|Owm}Hj(lU$`TSQ}CV4;VRxytxz(5AwdD+209Ym+JR|1aS*^_d}*+t1Ad}Cci=? ze)Yilfk!i6p$Hl3o~Dt2W*0(z#tFc=AH3IqiVtWXr;vWP0J*}m>6!i(JX-}br|0N> z=PdZ~thL+OAc`4DT=wlzqyww+VpN4BefC{67~o ze6wh>e(dx)_gcp_IcMcnt5yjQjh;Pw)~{PqQlgU{Pap_0x0Gt7+EhW$J#V1&>3^P_-Mf!Y+FI-1H8r(T%V%Ou z_-gq#f3N$Te>eQjgpeg`rK++@Dyu4`spRaGrDH9@JZsg~;M8lAuftE;7~vRWcxT~zb;YALU( zmWbMFky>k_T2VvFu-`liUxkdRx+ zITwAc0FjN5m;i~a_4k7hIYf5SzY-o67qID0 zvN&ZAb4gPJK_QXJ1j#faK0qG{>m2HD^~Dl6V{kz^F8)u9G0R!Y@IPY()GRj2+Ga(t zMxxnf{dHij2W!I5@o@}1YyweHItCOH;-aJK3k23Okpd@%-=hPOk`iwfI!qD4{A7GV zYLo^eWM6Tu@GY&=NWAR@7^@IdUL7IZbE>6ze3aDGM#|AGqHRT*hUE(@NwR~g@`*@M zeuc<4e+A{VBltIP>AK>I<0plQl{+gn@#%e3yhK-*X<>~*TDx}bq+7Rc_1~9WRx1mC zs*v==fZ9QrVv*annV9hX7aW(U75;|8QlxzISCwqq8SQq_6oU9Cr)LO5+5ZaPD;{cwr}4q?c2B4Lddp#l?opQrfTkOM3O$=SteI?Nsxp< zZGEz5KA*O^SpLYf?1YZZjH>_KB!&Dm%dXv7CcouXNm{(fS*@e%lR@*jS(blq-CH5Q zt=r=`oZB*qDN4n3LQ&d^iE#OGPgKV7^khvqR zZh$kGlo*w4D?!Rt+b=KSQxc#DmKMs*XD0b}G_RYNE31F4l!rU~AeRj6rC*Eq>YhD& zn(PB&tHAyKlbAhwwhSFQw9%?~s~>ypu}wC|d-$teRq6u`bdRyKi}L)GW!YLGbj75X zceR@`vU9`te^wwfzAIB}BtO0|qruQ8>>K z5{tBi2-S742T2^yi7PuN$ha?xWyYmVi!!LNv&_|XR*86TQ=I3T@(Ma_lfNz1g!hgf z-pMTU39ci$rAA)~y#WhFlwM!31>r!F1L6VtkwM&;?{`bi?|bJ{d2~#FT?8n+Wto>I z&1@>&)3=lgV#--1wT(pe?8o))R}`(v1waE3dN7f3nN6u9G7bE;ou|Ad9978 zl@BjYS17$Rtb$mscGbrZZZ5|k>^?sB^{$+it3?DX{hSK+Do{AxLfjxaNVti*I`@MD z+C#ToB{>^r>PP=oa^9my4_UKjjjUe1TDo`dUjJQmSWM>vh#|HW9K1r)lOjVt%-Ikx zTp*QPeVokp4(kYD7gS-=6QX3o&@`2rC$e($HQ_aI+YP&_w5x{|!pVomYNwPiFjc!? z5MnD|?5dF4yET(1GC{?8>c#2xet~ovj?Rp3BtEbYn8@^8xv^_fyrjk;x~Yi8E@VPA!;`>jk8qidvNW`rD; z98sUhn1sgs{CZcJ7FS42a!RVC(?M3!WfB^G-&YirUHO&LK0Q*Co}aTTrFBX~eS&0? z8G8~$va`Q9D9vI>e5~R{LcscI@7$GER_pguEKs=$TW8NCI-11SCHzn`D0EQ7XyD^o zNwgIaQWmV$PCi@J3uuAkN+K6uGf6u>(dcqEB-K}C%u)&1Lkvm3as`5OXA>_-aX zT2Z21P@usk(1#$oLK&8qBZ2>-7Ev515l4Ubbb|O8=virPJYwnhdiX z9b=Omlhg(yV&&1*<#Nuk$x=`eA;08_JbPYx{r1=gw%zDEA_CHXLXM6FNC+&jOmG?S zVg$O2x-l=H%T7v^kq*^nmN%W!@k7$&i4{f47j#>W^UZUOZSsCtRtJBh80Z#sK9~Mn zt}kV}7RIaDZCUe@1n&29HZSrtPa810SPx&(N7@X1P;R@Vr>C$CP-9RIbSmHt9_j*l zN9CQ#6I?uA+?p74NsvoVbT3HL&47n_Zu>ZSd60La!{ibH9z?vN{#;*=Ry%}(X`PUr z83#J`z?|uz!gs&W0r7PmT-zUK&YUS1Uwm<+#lHXkdpYKqV;cPpPADBde2Vda#zMyK z>&$b9gyYmhV}uSTFh#?)_1g!!4V;tP&%{Q~yO3`h%jJoVgxW zabAH16zB7x%4NM5m1=0UjVabzVbxB6d5ri zM>?bje7n3To|7!EzP82x!`gX3S5>8d`wdATA&nG3u^?DL5kZk6iWLzN1q%oYwy~k( z=;&C+ajat-%ZwEpMUW;cf+&cJ4HX0%VlRMzLXw*vAeC=D@5v75p6tCZ^R540%e7qO z+|$qAZ~2vGh`QN-7(u}rJ7#vV7GsQ9Als?^S(D1X`5g(ps>3_<0N~=I#n2@;S@0<* z=WzMRvrjY@{<^SCCJe}w>yC04a7+PXSod@*CD)wad2>sYiw^qWY!5Yn?J0IaJ%A?2 zbLX0TonCSdl>8}FAi!-K>L4*IraX5Lem0F2#3A_>K`EOe6V4PirG0}Yx@&NbcHx=J zxX0XAECHhfDhCLq{qj;&SM0{4Ti#PN%_zi?1984ww@(-pp*A@1+v*zR!C|>tM2Zdy zV!X!`Waz59P;KGg0lPPdxM;BurxFkito0kq1JTn&Ui0jm!pVP@RY~dWD`f3Qujt`y z$vKFLsEwetbAIHJN6N<^e=Hw;^pOl47>Ls_=qQ^&5t!p;ua*cMR4P1>=3T0c=J#CC z>C;G4oa4IG{t>Go7)dtgnde9{g2?a|k&qoP5JMg%6&4~6}Qllcqh#)K}z zC4JN7++OL;Nq#t?zxb7yx)1>OnK&Xx_RenAoba3N5XZS{L5ZAvKpQ!;N4h5SS1l-& zA^Ww~z%1M;H+H|z8yY4!*K{VsaE3cFZS6r#zD)vW@p2{M>v%3?e zhR}_;YGIiMk=$F8__Dt>Tj;iw$-~0~>zg~@t<-`-cssWLt-L`dEU1v{2W9JG`oik1 zGU<#0X|IB5LGgmc?fN&XWZGyZ_14Xa@J}%&-eRpt+JbRVH`oT9);(PVJKrF=xcwb0 zlHeodTN5txd&FX{dA&?K6Q~Wl_{e{MvqE0`eyh$qJTKdLZe^7wEby-b*pqva=l3K6 z2eeOBC}dRG*S3GQKX|uP{RRo*nJXx`_{Lc?i?v%ee_TNeFI^!2sPdP*BGqy9FQq~KeAKcQYy(-($6=kj<1{rx!nzMU_h5`ll8;{A>`^Vgc zs=8}1uOjkDoI#)%4b;?HYj#XUk5FEQ`f^HlKQ9}U2eCn6bz?%oIHN+%bw9K$5HK?$ zQ(@sjI#y4u2(%u2!7SfB-z}Z+Lw9ej>n1{2Q3d2dPZw$om&nJOxsre!RMXAJ`6)u& ze4{x^@%1?Fxzp^mwk7Oo5;C=?;6N7MZ*U^2-ZTE_c-UlwiJHJRl-fV@U;=EkCYk+Z(jtc5d&Mc^q@d$Qi}5p-KM(Sbm}bm5pa`&xzT3ebJ#YSI1OE3G+-} z80~f;Fu#T7bkmY@**hm$S}&L&ufFoK{>he{vz8Mt?~@yf&3Bk+KXf)n9C3s!U%p&E z`Q#HBFknFQU+9XOZp_~o70br523fJOR=Jc|(iruK0F{!O@ zlxd?2c5Ps`tn`$&E;01)k*Vt6{Q9bU*p+(qC#N zJ1t2+WM731^-S(9iyeY0OaNw3v7t&yH?;3wZPfGCH7GWqU`PiTYZc$n>i3+O?3S6L zRs^<+nfbjcn0~!g#jJqouoxfMKAz`;a1a(q4-bR?)mkfk1Vo8w6fEL=R3u4o{7B5B zT`?vn3KUE}KA|Xcz7%mjT3;il9oW`+T_mwoiBT|~c2=GYaJ|Bd@fr;cI@0!oMPk=i1WMJS8F56dbNtVA|9 z?3cBT0DO4&Hu6YFbvb&@0jD&kMe)Ty)+jQ-W7w9%E}G3T422S*erzthX>D;xnfwiHmaquE5$U5FRZ=1x0@>Jy@hm&=zM4B zav&B*!eb~5Vc|h^Oc0_Xn6-7R%sCfT<7-{gY`sNM1>QBB_wXR50(Sq&gpOV~DZJ&O zQ;Jl0?(qbWXZFwa@I1p}X(SbBKG+I-pbfhfq-wlI!QRHB=DTK4c&9)VhB%vR(#~I# zjtTMFEaElwMYkh&NVGZ6E_un4k=n`&Ck8dZe9F1eIW}`6-OF%n_4hZ+L^;I0+UmY( zW)Oi}l&glKJ(x=Zd6T`xKdD5fn7P zDXykDRjkEqpO-o4Uy8$YmtD!T*=JB>t5OAZnna1>e~PrjrWVS;&S~=88FnfQh34VY z;7->o0>affhBmadcBhsF6rn(A9}ai?I{>l_E4}LnWoZ*>^vq&ik8Djh6EF7LvyIxD zf~>NAd4GDPRKH1V&?p9@3FI3z`?!9N>k_qNOz%@!)Y zd%?o6siINN=#kdK;sBT?6(+h*iTEwUrWQ-_)&{MrVi)5YruvE;CT8WM-UIrFOCCZ1vuE6GbX*(B_$Y4Q1<%{PV?TV3bA-=V#yk2cUu7^}XDDTz0}BdeGBbR0uEHIpLfL82K)#)EjOXRpYi1!3=^cx>Uov zr3WH$kp!F~2+0uNVYC}Y;?<)=ORrrn=)GU*)|BbK=bu+#o#@Sl^DSX*Qrnb3+F(y+ zTNaKpXT+qkwoz?MSWIn$XHF%2Sobt}z~aNpZ-97_XcA0qsA$kh+&BLHL4~T}69}=` zCF*V%e_VKw+*^=6iK@aR8_;C_H8@Ak>KXqYDkK&K`O*0*7V}+UAg*T{6vkMb(CF~- z_Kb=-e$31}B>FBdRf0&iq4HkeB+%tkMW!Hy?s3PFb zT-WBR1}$*ef(-cVtQ~NZFX@{p_kU0+KNZ(`A#I=(zWTjRiwu4Cu+Jw17$c?^$sRc= z@aU2qC8V@886jNQO zEViZlNO2Nm0XiPUAVy@$z|#3XDCSX6|L-Zenk4%M-xt&pit-c!LC!^sZx_!ik>%@a zwcwse)UD6sTNDlQ;@HFqA9E}7)Kvqsno&j+wrC{S3Vy&%7NVc7pu{YWi&y;bBI= zudk82hXla*>p8Ym~(owzu-D*@oB* z#7nQ;Q`9ogH;8MXClE_g6usrxEH4U&PV+I(77DhGz|>uXcnxi!r$@L^O<_@A_M-(4 zhtfVtJcTCXAs*Jeh@J!I$n)VFWuJU|wq%z1h$6x_h4s5+|9H*9QWZ@mo^usE*eCb& zqQm_fFXo)T_@h=v&n%IVJ?wFvB5n%nRTBL^!C+FmW6uLm{E%~WNdUQ-_MuAw9^S*ui%BoeXWaY}0a`@qg$K87s72B~x zZdz0-bvvj?Cx*+gkWv{L(<|Lt>0@&HwX9LjKeVlOrCej!)FOq2@d5dGBmACZ%)l;L zP&*Q6SYS$s8&JLB<}ir>MRmbt2?luSNn*R?rpo27mS}g~1a)+Q=oIlX!W%Jz34%%z z4+`NtD(+Nv=_sNwXeKG3TrTd2*%wwzcPy>cWMcN&Eh~}Hdq;Qe%guE%aPKzquM^|D zM_6#+d6|(KB>6T0B(uNqb4%s(-)m&yc?DJoQTVtdD2T;@MDzLnvKX)^VmI=@hZPD_ zIrHH7LJtck6(}RRva1O!i3~6{kN~4*1vVeit{8Ays`GSv9|r305Q;L_Mu(rm3lJ)s zT?^Zh2oV_YjSN4~-Pw=&x+3hdd_!Fev_Wn^C9owW@LMrf1pcdjo`gf3{I;%a{Tw>Qe=tzWjuEuN}9!3%2{iNN9u;@{_R za^9s&7gd~R{X%;M%@ni&DE1{n47uLB88c?cxN+m+{`~#--^npU&+`lZ&KNPKvG_zF}afbeY>{v~p6`fRa-zqjOJ}&qnE>+eQJK zcbfkvx#eAVt#O8H+^ry4dhXVyg`))Leb0N9vazCG?f3{P6A7l#VPw6=hKm0Ow(IJ+ zp!+~gRVwsjEAFL(lZ}~iFcu+tCKF)dyj~53apPL5_3Xp?P#9WH!oUaYp2(=JR4GN5A z(5Xi#k3uKkZrGPTdfm*I_rADXKD%qDWii`KczT&UdFhdHn?pZZU)rE{g&q0y*b9VlAhWYDB?o=fZpe%7K`k;zV?4 zT#=uwbL*2$g<{qgW4_dkx)_n$?6J<=z`8-fH>}of_WkxRHS)JNN_Cy4AZJtfkDkZK z7m8Jc?1RfXIJHao4e#Ywn`>p>xB@3Uo?-&Z@laUijc-ZE2p`+fP3|3v8L4gu`@XjHE z2f~8pfNc=}gRXt!hoJcgjVLwvbdUv#QdNT(2Dq{hmvB> z1w`@SNkuAZXA=oDh?^S+Wy+fa~lScMS6&w{Ew!g6#Qqc$*fK=7Qdt8b85WBo8D zs!=4epal}a?ddMkDWStYXG}q}pkMSI0UoEe8%Jeoa6n>g`#>pdn1TtsBWM%^Ile(6 zqc$;TOB*#-dw0y9f4!n!NIyTJE}_!<>cW0}ap7xgd=EAjGvW2Z>5B|L0O ztNa}Z8Ul|tOGUa#@ViR4H)>Tsk+25~13?xOv@IYApAQhSuQu1|wm`LPgJ6>4A&bqD z3)?pb4&iO-;Hdc7-mL?!)|i48w2bif20BJ!`sz1qAMXzyJr9y+<}nsJVEw&zZ|&rI zo8PjSLS+H|9_0eEa1)RbWC7nLfMq@k3l5q680yVAy)%@<$vbNJui^9L-KV28^Xvkl z=m*Er#Yg9Nz|-J%0*PiGP#;x?pR$29cF1a_Nw-U=hXs*mMMvw)KZ1gXP1ud&168B5 z0KC?PfT7EW;1XS*fZrH!0bPE_bRuT0u9i^;XDFP~HO`q+EUPxvTfKn8$$8hVUFGbF zpQ~y#Tz4os6f!_g{Qr*W)2GXM=bab#^Cio_k$--kuU%lek_2ke^}_H6S^I#ZCMqUz z0OTJJe|(E_UYB0n!3&pG`>FLc3TY+qccHBa_(}2*_GCS>aY&&O@$7h~p{$r9l&h$R z$R2Aqi81rB?bsA%ahL&iNfK$BtHL*x^%6A7UyjIBK_n8TaKS$M{GdS*Bx6SxZV&*O zMxgP6L)!}9Ac+ak=tLY=f?wmgPEt!ZFAD3XyLiug>nOUCwGaIRVuUH51<1rGCl@Nyc})~U ziXhx8<`m`@*TC}~fyqxd2KoZ7_{N58WWM{MxFIgCHFGuhnuY^S9GB(@NEHeLyc;71 z>@Vxruh-Me>adqoYzgQrW&nMCe_f4m>)75_kYax3+d(M#nbTV$5N-DWI_J|Xs^rFF zv*dh_u%ANZn@~=y6MQc;dsts=gIIxN7AFT=5{D>seN%IfZ{?AX1Dz#<+yLfF9C6hV zS;;58kzgOie{36nE&gO=JZV+=chz=0D zKK&8)&zg=74eti=hpoU$vElLMRZ4k$au?_}G-i&RxJB|aTFL9@w?tv9?#GgHMM?f+ zNtr$y7XsGY14DTNg^N4DJt50F8ehx@J^IW9kqr)%{WLn;ErQwZEn88 zew##0!q7-QR$wAblvHkkGExD*<@lX1Eu6Tp=cVPdpi!T>GCHB52thC$i#_=-vul<^fCKUb((z*l5Z zMfsjWpKl=ichclSRcL)BGVhXzaK3claRZ>c%Gnn?UB1pH#_X z%Mq^1*UlCKH1|5ZR5@?DO>idf9+IQ)6#I<&sG95J8Bs{+w@0dWjPCbbJCN))$s$XC z4d!yz729B5ctvh7ph8meRIz9lR z8-Sn_dKJKg=~(*ED`w}XOe>Nt6%DfFq7F{pJ=-EcH|eu#E$DI2UDOIJZqA(@({~5@ zlkGbLEyY^Qnn9Nh9R=P6TS19qW8KI06g_~{+KLVovu=E|T#%SUZUOLqbh+0BL;ftlw9o`5^G;~-?M@S#>~4X$l-_eZa!rYog|x} z5$_(HBZDpK)FkhqfQT`9S9Zn40eue|M`I4jh@;0v@0D?800l*YLJWKMA$B1;eoL${ zWJ-~KQ;4fZ2SrR0Y3L|XTQ0V(Zwyc*d^6#7fsU=Kf!3VN56n^>D7vEI@5uK2?|i31 zrhQQ*&z_kl$9b$NK{;Yc2l|rYq-|`jY*Z1lSaqXzLJzZuiiUq@=qAj$XeY3?`Ub^D zC-9bPlfNiwQxLN2(@(@#c zO1qXMJocoIU=oA?FFe)-2n2;8#XOX*dC777GbRTD&ww}9R=XceIAQ1t3V}@Mw&Fqf zI_doLF*7-z);%p@*9?IUBR+?XKv>O~z?CXJcjRF_fA@0>gt4f?_nFWyBjGXmh!C|v z)ayPE&y?#5_$on%q-0xz)t}Xx+O zC8d@0-Yq3zpu<7~q#C^g5=5Jznz5IFIslB*)m1VAQ2ZSQVED!?bS`CbbKZ2a&X`fG z_BnIL7FY#Sm=}-rbWe z6E4Ax3I3>n+x$iYZWFMm_=Q^Sh!(g-jrgusZme-8GU02b&t>}sFbIr@b1;caYSv;fdG==jR5b-<&{e3@Nq_!TQ@5v z*AB{3IAa)E=6cS+V+TF6Mb+=$y|{f`v620en4>by!ps7MpwI}5+X00D7W$_~|Al4JKC_kb04aLd26GxgJ)J>U zmn58=XYRJIY+nDPP$c6#e0=F$2}syx>eQ)n;e{8*ZGQXQuVnYV_f_R}zR~D<$$Qcz zFI6cEiNqDnjtMxv{JmCQJFmSHX~4Fo%gws@&6ZjfErj|N9R%NJ&58+5m)9N@px2@! z5X&Oa$xwbV-`dls=Q@R;=os;SwQt)>(OzM1YO`Jpaa7^VP5BC>3Kt;QiH77B`3L7|I8;_JdXwFUAG0(jJ(*^kDPy}`X_RjtZyqEkKSX)sP?`R6~or8#iPUwRZgT@LM4M5S|it_rH zeAOLb5EJsgfz|?9LR{w(Vk<6 zx3B~YxGN=EO(*c}eTer{Ejyg0T%RSfx9pd0v<91TqVhCx}f zsj{KTGOZ=_1}y^ozIV?_P6&SiQ89W}iTqw!uTWZBrwa}&=f@&Va7hOMI8}6jeBhm+ zvJceDRHNx!Uh-$Gg-*-|w zInmMy;P`ZH&+FYbVNs6v<-Z?QNKRU^S}^)-#V8;k*oXKJ_G&J%95~Zh_dRoZp7Xs! z$Pl^<5H;RS!x6PT2%G@8S1jD~zul^WB|epF6)Boiq7ygbi$G9Wpc0AuoIWFXSAgk- z6?X%^e~D6I5b!kTVykWg4<#VuSwba&V{BWXSkzhUC-l!!k)l_izKqFt^05Ot2X-lW z>YMvHFO~;B7_x_!~34|bx?)JQW44x-oMdd z?AHjA+oc1IEw&b=%^-tX%Mxv3JIFO(_# z$9dm*Z=(nn;~oL!YRc!;@;CyFo({P2>t!BzsR;t_5|-uo%(HYnNhoKpM*TXk`I|Lj zk;EMo6PI8!l)(2GhZv|2>}RibDNU|3nQ9{%9{rx&q6uK4E)x({bS|)sL_Z?YAd!3+ z8`!Y{orK~u&%{=&XYQboLL9QOg7*uH)A%F>T7-e|gGRt&Jz=+*3#mn!?^C58xd?UjK4rwm0_WIL1Zb z#QoFN`GtAMhe9F-y6*Kd)fla(eQP_5$9VZ-h@uaKseFnrw)1t zAu#3wo%2+EWU(>-)w9egP6Xiv&nOZkfn{U^3BR0}~xUa0$R} zJ3dP;o>!(^beESo*FZIh59rMwx5*PLs#Mw71Q5W+3E=6}hX)fH{?A5$4d~D|6&(u_ z>&HH+lqm?rG{HrDlOtV8l4>|6F1VlhJ!;Dc7trOU+D;N^hUw(P*C64J@`1zWph5|g zi>23YbQb+pJ=5JHIXz;p)@ldg8iq5@@tGKSMqx#Jen)kUjsf>HH$7S5WLNahl2H+* z>F_aF9O*D3z=p55%Q6l1_8*GswW^z_vdaERO0jSQ!sW7UVDY5W10Rg{-4^hx*ZS<3 z(gF-T#%CuJzBYLAU;bXF?>6w7==kH0Kh*BfST6bACH{sW)G23-kwMQCD&KZ`q?>Ij zktF8*_iU{cfzs_eik3iksffFh$?(0Q*P*4H30f+3`H_AnlcF3cr*eMeCyk9A=tl6sFE4a)khwtUEYT_8!wOld3Oi@v| zO+@WM&3W)H^S;0>TX0@`uhYf9UsxhHjz39%+Nn!7IryI+>Ktq<_$B(*ZGWFMX_8!g z@x^g}>V3y2GUtlJTLd?1FS@Z-iy4S;?TQE;Fz)G}S1YY2YC{%2s7cNSc5b6J(l}VckZVfhIvRK=(J$nsGNHfO4X! zKXm_eMG1kz^YLBz2B3_c+O4hp_v1jzz|g={Gi7y9xTjkPAJ?a!z00O;3{z=S)g=J?$6-Lg{DDv#z#&^2`n{~3DbVVwef0h<<)**EV$ zMJa=>qWHpjtG!u|o$tbhFU915_N{eZ2f@R&pr&pce|fD;uNmPx2BG zfnpimGsD^qH$?_e5g;rQL4-LTjftUC5%vp|$r1W=jj+|PQOWnA(m)u1hGYGSQYArs zvF1~Nqx;W#)HT$s;vDD>gC5~sH+niG(lq*r!FguU0jd`CC9woTsoZ-6zFb4C0H+qI zgMlxe=DD0Uy;!fqCH~7Xm`4ykBervCp_p?qE&>$nh*|i)eUwt@93-E-7f^a_12{bv z)x@+2Zn}#1%!%j(ne{O&oEX(^Fhx!?ckq6ac-yFFJXgL6uAf|hdll6oqqq*IntX)j zNFt#^5PoN4{oE*W{h&-MotBvT^yxAAt)fAT$`rd24U*_dE3375V53Jz;>?1EPcZ8o}`wRaD!47KSR$U*VkhxqhC$Km7269B{w^ zaYxI^$&reR3Mnrym+b78i5MLMCa8ZNpQ96Vc+@xSkP$BwtN$cCPnVbkH|K;&#nRBQ zL*BTcK(f=^9AjXd5bFsNkM7c1yF)HmHIo^Yu!*PTs;?a?lD340bEZQMq??KU_sT}W zE11OGbVjHWW7WdT817IZ!Ujan_z!AAx}iq9?F`esCNLh`%dgBx*PfuVO$uG`Kl0@3HuZho6}iM7A}`l>@L$OH6ygYq-N^y0g-e35WwgEK-N)n44?+l&Y zs7Rps9jGSV=IngkFG)Iutf-Hw*&YfD_Z37Azj5ss{x5};Lw0Me$&f2?BfviIB|Jx4 zX|iHNEEvHvs@ObxzJI=Lmm)3mB%S^BWsP!9ua+D$b1ftTqh=IKZG))KuSZ7Sbvqnz!MI!z*(|M4ou zS;934s22TLqi7Ejcv}nrDu!aEn0FJtUE!&_%%s9i*tci8)te$7S>dfKHQKo^(KZoTCt( zb!Y-t9FeKT2%j=Mi5&KF=AHt_$18eFuXz48bOhE^R@?!5rRsVd9RX*(M2_3Hjp`Ka zia;a#z$Jp@2f9h;c5d-mWA)4RgLXnwgXd(Uh_YW4!bwumdN2yr;rHD@{^`8l`gVmj zkixn=#_L<@rA8c( z7n(TeJG?T^-8qhGRTxAv&(`qH&Hm9g$x2IBhX)2lPmp`IoFSlc1atzLmmnLW?-X<4 zxpRt@TTN^=`OJJpBDe<6h;OuH+YTAqE8VF@Lkta~ne&X&Tx|PBv+TB|6>{UCY-^#5 zZ3alg;a&6TpUGAS)BZK3}BLvfwLT7aJ2W9fKJm|vn7jsTaBV2}9B zH-&Y(WZT800Njyk6p8u8eeKHIRF;_t?;o10kZBYb4dgs}gRnS2y$~21RZc$q#|h}0 zgr0c05o*zDUdSdOsCZ*Z6e#coLN`^)w?cf3Nu2!xdrKs)2IL+46;$VeiMbSl&AHQU z#shHVf!Ni>FNlGaTZ2NA6Y&;@PA%4n^W)1C+okYflC%-1`d((k8E5gn`K@v*Jdh6^ z%QPx`RHaqzH6z){M>W^Y;z-wm-{CI|Oet!a2EUk!8P)tm)k^kD1$Wl!ttx`y5_bYh zOEF$J$^@~6jhn6(U@3k0WpK?JC$adS&#boN(r(|JMXylb}} z^2_&Y{-?cPnN2!))xQ(AOJ~3K~(wGMOOk+&HIZbAxIa5CZprIl~v6mZ4^{^ zUOvIZ03ur{9kW`=(fg!X5m5-L!GXrl9155Z`pWrG#K$@lrwi^K6duxp(3&)OMxJa97hR(@@taPgP#hh#Zg$UuXJ_6b(QnAs`tRt~HuLG=rGed_ru9>axC( z;F|6l^DR*9sH+J7PGJz#sI53i97&;t4l#2j?;G=WqH+F9Fcx=Bg~EP6ysTpjr@Ao8+%B)SJ0WH``Bj-rBy4D_bt4AbFRR|ahZC4bb+&T%=dC1d`%`Pi%$$R=o4=p~r7ROgc7Iz8{`2%c+9X<8tWDUjKU=;TSzd9fG0eo(d* z79ZX>&4FKI^>R$tG-pAWf&uRkoqV(a5{-}61!B!(4{58&qUeA&^w!VY^nR#L+3384 zR^7ykSHD&Y9bRUS&C>>fYrvf!KJZ|vDf~q@X@B66vSIay37yWY$vF!({;I$H@{3^S z5+3>a`BG9+BC%LZ^73{*Gy8O|wuu!a( z@V`dP1RrfGhl#58K)xwnOgb}9lP{B4hR+i|42uhB3@WuY&UScvK2Fp*3)&{B(kOy4 z(P4PhEc8IiTwRqgZ;*Yc!t0uVTbOO}lQzd8D5Vn$tpI@}*Z5z%=4L-9pE^R`Snz7x zZUdX96cq?l7$+h=V+s`d9(|v9<_Mn1^uRXJ7QE7>#$C3G%2+W_=Y6RTo>;Z-;=Le zY7~7bTo{#SANmE6BD$4)Pk6>7LYK%64!AG(ZNx!o>Vq5}s-XYXR+%}bK;iBams2Rr zYwk>hw+*`cqMe89-@rYf!0M5!O1qnb;Fh4v=gmsdjJcF<35l_RgxYv(9Q*EfE9HZA z+ZA0f@}M;BVA}>L2!vFQ?3||EHP#!Or6M5BpVM5$y;dLJ9?&w*?>MrtqQJreI_@J-s=(CM=a`v2J zoeNwRXy$-)qzM35|52w%hf})Sq2hGJ@O|ajB#AbgKN6l7um~HSr^Qs>3t#aofXJ50 z;d`b^mv$*uMPr0S322YoH%&^a8xlggfl87L1OH}S06{__-Zh}BfHI>PgYA!bFQDdW zf_GGw4C>rk=NTFpK0OkSq2KL}03L~mCjwSc-3L0#kAGYx|2Z{RP7TE@wsRajsZbgu zN#6aFA2k=ATf+$^w1%kSyxEpc<2%6ghv&%nxusU*B8lO>?^Vi0hqsmKUj%DqlxG|k zA>~f94gm{ij&TjBhNasZ19S(mHARZ(Adcvqi>+*ycHps1Wlk~T%M@04eo<-(loC)o z&{U!WDjUy}`*Z*Ml^Ub?Y&-cqF(|RPQqF2r=U0esRA{jgO$P*w&ix?|46mKa*P}sWyVoi9-cN zK>|EJ^gxS(VNK4vbm=1N)~%DZYuCy?`|K0P2C(x-PH|V^pIT9^2^@)UqAHkHYrd$~4;`hvPT6*a zK+c6qJ^W23wnP>SbXlmrQkCIDC0I3+E>&;!Zj8KWcn|XL6bVSam4`h$76)~v(*lPQ zaTVVP;FTqkohEYo3Gf)*JU8}3hl>dh_)C-@PVhnpl*BXJkuteXs^2#^cl|O3}$U%H-@0=8U?kc+XOTZgL?bS7a7Ek@W zS|P=Ju(pX@?Z@VnNI`llxoV(afQ#b*V<&i`kO54^hE`D6;oId}F=T;sbyX0*GW;46 zG9X`wo$wrt!mI7t;Q4|uA$UZ6(w21ayTZak>2XMJDcAicp&cc7?{m(q97cBsvLjn4=!9bliG(N|kFP-m(OZ1SpyuMiw026Lct2l3U4L zgR|rqkF5#kd-cLn4epQKH%)Fk-VI+h*S2b7t-x({*^6-eVb2#!Zdxn#dJjYR&CP?W z#sW`gbs9pBV_WjN!#5g^^_}mO%Y*@$s@hD#@0;}1Qg1S7@^DJ%^Zh?hk5tl z-Ba~D3=ax?BtqxiRSu{A^RL^4IpvZW+KpN{bI&Poe#;=4)@-TQ&WbN#1;&T?9t%7Lf?;

    8lXC(Ic=myYhCL|`9~0EU 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 z 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

      Ki;5CD)<*@anb- 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 T^q$vQh#)7WELrv0H28l3%zlOL literal 0 HcmV?d00001 diff --git a/lib/spack/docs/images/builder_phases.png b/lib/spack/docs/images/builder_phases.png new file mode 100644 index 0000000000000000000000000000000000000000..e8141651c4b9b83a552af849042c99083c347955 GIT binary patch literal 131216 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 Version("2.1.1"): + return super(Openjpeg, self).url_for_version(version) + url_fmt = "https://github.com/uclouvain/openjpeg/archive/version.{0}.tar.gz" + return url_fmt.format(version) + + def cmake_args(self): + args = [ + self.define_from_variant("BUILD_CODEC", "codec"), + self.define("BUILD_MJ2", False), + self.define("BUILD_THIRDPARTY", False), + ] + return args + +A package encoded with a single class is backward compatible with versions of Spack +lower than v0.19, and so are custom repositories containing only recipes of this kind. +The downside is that *this format doesn't allow packagers to use more than one build system in a single recipe*. + +To do that, we have to resort to the second way Spack has of writing packages, which involves writing a +builder class explicitly. Using the same example as above, this reads: + +.. code-block:: python + + class Openjpeg(CMakePackage): + """OpenJPEG is an open-source JPEG 2000 codec written in C language""" + + homepage = "https://github.com/uclouvain/openjpeg" + url = "https://github.com/uclouvain/openjpeg/archive/v2.3.1.tar.gz" + + version("2.4.0", sha256="8702ba68b442657f11aaeb2b338443ca8d5fb95b0d845757968a7be31ef7f16d") + + variant("codec", default=False, description="Build the CODEC executables") + depends_on("libpng", when="+codec") + + def url_for_version(self, version): + if version >= Version("2.1.1"): + return super(Openjpeg, self).url_for_version(version) + url_fmt = "https://github.com/uclouvain/openjpeg/archive/version.{0}.tar.gz" + return url_fmt.format(version) + + class CMakeBuilder(spack.build_systems.cmake.CMakeBuilder): + def cmake_args(self): + args = [ + self.define_from_variant("BUILD_CODEC", "codec"), + self.define("BUILD_MJ2", False), + self.define("BUILD_THIRDPARTY", False), + ] + return args + +This way of writing packages allows extending the recipe to support multiple build systems, +see :ref:`multiple_build_systems` for more details. The downside is that recipes of this kind +are only understood by Spack since v0.19+. More information on the internal architecture of +Spack can be found at :ref:`package_class_structure`. + +.. note:: + + If a builder is implemented in ``package.py``, all build-specific methods must be moved + to the builder. This means that if you have a package like + + .. code-block:: python + + class Foo(CmakePackage): + def cmake_args(self): + ... + + and you add a builder to the ``package.py``, you must move ``cmake_args`` to the builder. .. _cmd-spack-create: -^^^^^^^^^^^^^^^^ -``spack create`` -^^^^^^^^^^^^^^^^ +--------------------- +Creating new packages +--------------------- -The ``spack create`` command creates a directory with the package name and -generates a ``package.py`` file with a boilerplate package template. If given -a URL pointing to a tarball or other software archive, ``spack create`` is -smart enough to determine basic information about the package, including its name -and build system. In most cases, ``spack create`` plus a few modifications is -all you need to get a package working. - -Here's an example: +To help creating a new package Spack provides a command that generates a ``package.py`` +file in an existing repository, with a boilerplate package template. Here's an example: .. code-block:: console @@ -87,23 +218,6 @@ You do not *have* to download all of the versions up front. You can always choose to download just one tarball initially, and run :ref:`cmd-spack-checksum` later if you need more versions. -Let's say you download 3 tarballs: - -.. code-block:: console - - How many would you like to checksum? (default is 1, q to abort) 3 - ==> Downloading... - ==> Fetching https://gmplib.org/download/gmp/gmp-6.1.2.tar.bz2 - ######################################################################## 100.0% - ==> Fetching https://gmplib.org/download/gmp/gmp-6.1.1.tar.bz2 - ######################################################################## 100.0% - ==> Fetching https://gmplib.org/download/gmp/gmp-6.1.0.tar.bz2 - ######################################################################## 100.0% - ==> Checksummed 3 versions of gmp: - ==> This package looks like it uses the autotools build system - ==> Created template for gmp package - ==> Created package file: /Users/Adam/spack/var/spack/repos/builtin/packages/gmp/package.py - Spack automatically creates a directory in the appropriate repository, generates a boilerplate template for your package, and opens up the new ``package.py`` in your favorite ``$EDITOR``: @@ -111,6 +225,14 @@ generates a boilerplate template for your package, and opens up the new .. code-block:: python :linenos: + # 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) + + # ---------------------------------------------------------------------------- + # If you submit this package back to Spack as a pull request, + # please first remove this boilerplate and all FIXME comments. # # This is a template package file for Spack. We've put "FIXME" # next to all the things you'll want to change. Once you've handled @@ -123,9 +245,8 @@ generates a boilerplate template for your package, and opens up the new # spack edit gmp # # See the Spack documentation for more information on packaging. - # If you submit this package back to Spack as a pull request, - # please first remove this boilerplate and all FIXME comments. - # + # ---------------------------------------------------------------------------- + import spack.build_systems.autotools from spack.package import * @@ -133,19 +254,17 @@ generates a boilerplate template for your package, and opens up the new """FIXME: Put a proper description of your package here.""" # FIXME: Add a proper url for your package's homepage here. - homepage = "http://www.example.com" - url = "https://gmplib.org/download/gmp/gmp-6.1.2.tar.bz2" + homepage = "https://www.example.com" + url = "https://gmplib.org/download/gmp/gmp-6.1.2.tar.bz2" # FIXME: Add a list of GitHub accounts to # notify when the package is updated. - # maintainers = ['github_user1', 'github_user2'] + # maintainers = ["github_user1", "github_user2"] - version('6.1.2', '8ddbb26dc3bd4e2302984debba1406a5') - version('6.1.1', '4c175f86e11eb32d8bf9872ca3a8e11d') - version('6.1.0', '86ee6e54ebfc4a90b643a65e402c4048') + version("6.2.1", sha256="eae9326beb4158c386e39a356818031bd28f3124cf915f8c5b1dc4c7a36b4d7c") # FIXME: Add dependencies if required. - # depends_on('foo') + # depends_on("foo") def configure_args(self): # FIXME: Add arguments other than --prefix @@ -154,15 +273,16 @@ generates a boilerplate template for your package, and opens up the new return args The tedious stuff (creating the class, checksumming archives) has been -done for you. You'll notice that ``spack create`` correctly detected that -``gmp`` uses the Autotools build system. It created a new ``Gmp`` package -that subclasses the ``AutotoolsPackage`` base class. This base class -provides basic installation methods common to all Autotools packages: +done for you. Spack correctly detected that ``gmp`` uses the ``autotools`` +build system, so it created a new ``Gmp`` package that subclasses the +``AutotoolsPackage`` base class. + +The default installation procedure for a package subclassing the ``AutotoolsPackage`` +is to go through the typical process of: .. code-block:: bash ./configure --prefix=/path/to/installation/directory - make make check make install @@ -209,12 +329,14 @@ The rest of the tasks you need to do are as follows: Your new package may require specific flags during ``configure``. These can be added via ``configure_args``. Specifics will differ depending on the package and its build system. - :ref:`Implementing the install method ` is + :ref:`installation_process` is covered in detail later. -Passing a URL to ``spack create`` is a convenient and easy way to get -a basic package template, but what if your software is licensed and -cannot be downloaded from a URL? You can still create a boilerplate +^^^^^^^^^^^^^^^^^^^^^^^^^ +Non-downloadable software +^^^^^^^^^^^^^^^^^^^^^^^^^ + +If your software cannot be downloaded from a URL you can still create a boilerplate ``package.py`` by telling ``spack create`` what name you want to use: .. code-block:: console @@ -223,40 +345,23 @@ cannot be downloaded from a URL? You can still create a boilerplate This will create a simple ``intel`` package with an ``install()`` method that you can craft to install your package. - -What if ``spack create `` guessed the wrong name or build system? -For example, if your package uses the Autotools build system but does -not come with a ``configure`` script, Spack won't realize it uses -Autotools. You can overwrite the old package with ``--force`` and specify -a name with ``--name`` or a build system template to use with ``--template``: +Likewise, you can force the build system to be used with ``--template`` and, +in case it's needed, you can overwrite a package already in the repository +with ``--force``: .. code-block:: console $ spack create --name gmp https://gmplib.org/download/gmp/gmp-6.1.2.tar.bz2 $ spack create --force --template autotools https://gmplib.org/download/gmp/gmp-6.1.2.tar.bz2 -.. note:: - - If you are creating a package that uses the Autotools build system - but does not come with a ``configure`` script, you'll need to add an - ``autoreconf`` method to your package that explains how to generate - the ``configure`` script. You may also need the following dependencies: - - .. code-block:: python - - depends_on('autoconf', type='build') - depends_on('automake', type='build') - depends_on('libtool', type='build') - depends_on('m4', type='build') - A complete list of available build system templates can be found by running ``spack create --help``. .. _cmd-spack-edit: -^^^^^^^^^^^^^^ -``spack edit`` -^^^^^^^^^^^^^^ +------------------------- +Editing existing packages +------------------------- One of the easiest ways to learn how to write packages is to look at existing ones. You can edit a package file by name with the ``spack @@ -266,10 +371,15 @@ edit`` command: $ spack edit gmp -So, if you used ``spack create`` to create a package, then saved and -closed the resulting file, you can get back to it with ``spack edit``. -The ``gmp`` package actually lives in -``$SPACK_ROOT/var/spack/repos/builtin/packages/gmp/package.py``, +If you used ``spack create`` to create a package, you can get back to +it later with ``spack edit``. For instance, the ``gmp`` package actually +lives in: + +.. code-block:: console + + $ spack location -p gmp + ${SPACK_ROOT}/var/spack/repos/builtin/packages/gmp/package.py + but ``spack edit`` provides a much simpler shortcut and saves you the trouble of typing the full path. @@ -2422,7 +2532,7 @@ Spack provides a mechanism for dependencies to influence the environment of their dependents by overriding the :meth:`setup_dependent_run_environment ` or the -:meth:`setup_dependent_build_environment ` +:meth:`setup_dependent_build_environment ` methods. The Qt package, for instance, uses this call: @@ -3280,67 +3390,91 @@ the Python extensions provided by them: once for ``+python`` and once for ``~python``. Other than using a little extra disk space, that solution has no serious problems. -.. _installation_procedure: +.. _installation_process: ---------------------------------------- -Implementing the installation procedure ---------------------------------------- +-------------------------------- +Overriding build system defaults +-------------------------------- -The last element of a package is its **installation procedure**. This is -where the real work of installation happens, and it's the main part of -the package you'll need to customize for each piece of software. +.. note:: -Defining an installation procedure means overriding a set of methods or attributes -that will be called at some point during the installation of the package. -The package base class, usually specialized for a given build system, determines the -actual set of entities available for overriding. -The classes that are currently provided by Spack are: + If you code a single class in ``package.py`` all the functions shown in the table below + can be implemented with the same signature on the ``*Package`` instead of the corresponding builder. + + +Most of the time the default implementation of methods or attributes in build system base classes +is what a packager needs, and just a very few entities need to be overwritten. Typically we just +need to override methods like ``configure_args``: + +.. code-block:: python + + def configure_args(self): + args = ["--enable-cxx"] + self.enable_or_disable("libs") + if "libs=static" in self.spec: + args.append("--with-pic") + return args + +The actual set of entities available for overriding in ``package.py`` depend on +the build system. The build systems currently supported by Spack are: +----------------------------------------------------------+----------------------------------+ -| **Base Class** | **Purpose** | +| **API docs** | **Description** | +==========================================================+==================================+ -| :class:`~spack.package_base.Package` | General base class not | -| | specialized for any build system | +| :class:`~spack.build_systems.generic` | Generic build system without any | +| | base implementation | +----------------------------------------------------------+----------------------------------+ -| :class:`~spack.build_systems.makefile.MakefilePackage` | Specialized class for packages | -| | built invoking | +| :class:`~spack.build_systems.makefile` | Specialized build system for | +| | software built invoking | | | hand-written Makefiles | +----------------------------------------------------------+----------------------------------+ -| :class:`~spack.build_systems.autotools.AutotoolsPackage` | Specialized class for packages | -| | built using GNU Autotools | +| :class:`~spack.build_systems.autotools` | Specialized build system for | +| | software built using | +| | GNU Autotools | +----------------------------------------------------------+----------------------------------+ -| :class:`~spack.build_systems.cmake.CMakePackage` | Specialized class for packages | -| | built using CMake | +| :class:`~spack.build_systems.cmake` | Specialized build system for | +| | software built using CMake | +----------------------------------------------------------+----------------------------------+ -| :class:`~spack.build_systems.cuda.CudaPackage` | A helper class for packages that | -| | use CUDA | +| :class:`~spack.build_systems.maven` | Specialized build system for | +| | software built using Maven | +----------------------------------------------------------+----------------------------------+ -| :class:`~spack.build_systems.qmake.QMakePackage` | Specialized class for packages | -| | built using QMake | +| :class:`~spack.build_systems.meson` | Specialized build system for | +| | software built using Meson | +----------------------------------------------------------+----------------------------------+ -| :class:`~spack.build_systems.rocm.ROCmPackage` | A helper class for packages that | -| | use ROCm | +| :class:`~spack.build_systems.nmake` | Specialized build system for | +| | software built using NMake | +----------------------------------------------------------+----------------------------------+ -| :class:`~spack.build_systems.scons.SConsPackage` | Specialized class for packages | -| | built using SCons | +| :class:`~spack.build_systems.qmake` | Specialized build system for | +| | software built using QMake | +----------------------------------------------------------+----------------------------------+ -| :class:`~spack.build_systems.waf.WafPackage` | Specialized class for packages | -| | built using Waf | +| :class:`~spack.build_systems.scons` | Specialized build system for | +| | software built using SCons | +----------------------------------------------------------+----------------------------------+ -| :class:`~spack.build_systems.r.RPackage` | Specialized class for | +| :class:`~spack.build_systems.waf` | Specialized build system for | +| | software built using Waf | ++----------------------------------------------------------+----------------------------------+ +| :class:`~spack.build_systems.r` | Specialized build system for | | | R extensions | +----------------------------------------------------------+----------------------------------+ -| :class:`~spack.build_systems.octave.OctavePackage` | Specialized class for | +| :class:`~spack.build_systems.octave` | Specialized build system for | | | Octave packages | +----------------------------------------------------------+----------------------------------+ -| :class:`~spack.build_systems.python.PythonPackage` | Specialized class for | +| :class:`~spack.build_systems.python` | Specialized build system for | | | Python extensions | +----------------------------------------------------------+----------------------------------+ -| :class:`~spack.build_systems.perl.PerlPackage` | Specialized class for | +| :class:`~spack.build_systems.perl` | Specialized build system for | | | Perl extensions | +----------------------------------------------------------+----------------------------------+ -| :class:`~spack.build_systems.intel.IntelPackage` | Specialized class for licensed | -| | Intel software | +| :class:`~spack.build_systems.ruby` | Specialized build system for | +| | Ruby extensions | ++----------------------------------------------------------+----------------------------------+ +| :class:`~spack.build_systems.intel` | Specialized build system for | +| | licensed Intel software | ++----------------------------------------------------------+----------------------------------+ +| :class:`~spack.build_systems.oneapi` | Specialized build system for | +| | Intel onaAPI software | ++----------------------------------------------------------+----------------------------------+ +| :class:`~spack.build_systems.aspell_dict` | Specialized build system for | +| | Aspell dictionaries | +----------------------------------------------------------+----------------------------------+ @@ -3353,69 +3487,17 @@ The classes that are currently provided by Spack are: For example, a Python extension installed with CMake would ``extends('python')`` and subclass from :class:`~spack.build_systems.cmake.CMakePackage`. -^^^^^^^^^^^^^^^^^^^^^ -Installation pipeline -^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^ +Overriding builder methods +^^^^^^^^^^^^^^^^^^^^^^^^^^ -When a user runs ``spack install``, Spack: - -1. Fetches an archive for the correct version of the software. -2. Expands the archive. -3. Sets the current working directory to the root directory of the expanded archive. - -Then, depending on the base class of the package under consideration, it will execute -a certain number of **phases** that reflect the way a package of that type is usually built. -The name and order in which the phases will be executed can be obtained either reading the API -docs at :py:mod:`~.spack.build_systems`, or using the ``spack info`` command: - -.. code-block:: console - :emphasize-lines: 26-27 - - $ spack info --phases m4 - AutotoolsPackage: m4 - - Description: - GNU M4 is an implementation of the traditional Unix macro processor. - - Homepage: https://www.gnu.org/software/m4/m4.html - - Preferred version: - 1.4.19 https://ftpmirror.gnu.org/m4/m4-1.4.19.tar.gz - - Safe versions: - 1.4.19 https://ftpmirror.gnu.org/m4/m4-1.4.19.tar.gz - 1.4.18 https://ftpmirror.gnu.org/m4/m4-1.4.18.tar.gz - 1.4.17 https://ftpmirror.gnu.org/m4/m4-1.4.17.tar.gz - - Deprecated versions: - None - - Variants: - Name [Default] When Allowed values Description - ============== ==== ============== =============================== - - sigsegv [on] -- on, off Build the libsigsegv dependency - - Installation Phases: - autoreconf configure build install - - Build Dependencies: - diffutils gnuconfig libsigsegv - - Link Dependencies: - libsigsegv - - Run Dependencies: - None - - -Typically, phases have default implementations that fit most of the common cases: +Build-system "phases" have default implementations that fit most of the common cases: .. literalinclude:: _spack_root/lib/spack/spack/build_systems/autotools.py - :pyobject: AutotoolsPackage.configure + :pyobject: AutotoolsBuilder.configure :linenos: -It is thus just sufficient for a packager to override a few +It is usually sufficient for a packager to override a few build system specific helper methods or attributes to provide, for instance, configure arguments: @@ -3423,31 +3505,31 @@ configure arguments: :pyobject: M4.configure_args :linenos: -.. note:: - Each specific build system has a list of attributes that can be overridden to - fine-tune the installation of a package without overriding an entire phase. To - have more information on them the place to go is the API docs of the :py:mod:`~.spack.build_systems` - module. +Each specific build system has a list of attributes and methods that can be overridden to +fine-tune the installation of a package without overriding an entire phase. To +have more information on them the place to go is the API docs of the :py:mod:`~.spack.build_systems` +module. ^^^^^^^^^^^^^^^^^^^^^^^^^^ Overriding an entire phase ^^^^^^^^^^^^^^^^^^^^^^^^^^ -In extreme cases it may be necessary to override an entire phase. Regardless -of the build system, the signature is the same. For example, the signature -for the install phase is: +Sometimes it is necessary to override an entire phase. If the ``package.py`` contains +a single class recipe, see :ref:`package_class_structure`, then the signature for a +phase is: .. code-block:: python - class Foo(Package): + class Openjpeg(CMakePackage): def install(self, spec, prefix): ... +regardless of the build system. The arguments for the phase are: + ``self`` - For those not used to Python instance methods, this is the - package itself. In this case it's an instance of ``Foo``, which - extends ``Package``. For API docs on Package objects, see - :py:class:`Package `. + This is the package object, which extends ``CMakePackage``. + For API docs on Package objects, see + :py:class:`Package `. ``spec`` This is the concrete spec object created by Spack from an @@ -3462,12 +3544,111 @@ for the install phase is: The arguments ``spec`` and ``prefix`` are passed only for convenience, as they always correspond to ``self.spec`` and ``self.spec.prefix`` respectively. -As mentioned in :ref:`install-environment`, you will usually not need to refer -to dependencies explicitly in your package file, as the compiler wrappers take care of most of -the heavy lifting here. There will be times, though, when you need to refer to -the install locations of dependencies, or when you need to do something different -depending on the version, compiler, dependencies, etc. that your package is -built with. These parameters give you access to this type of information. +If the ``package.py`` encodes builders explicitly, the signature for a phase changes slightly: + +.. code-block:: python + + class CMakeBuilder(spack.build_systems.cmake.CMakeBuilder): + def install(self, pkg, spec, prefix): + ... + +In this case the package is passed as the second argument, and ``self`` is the builder instance. + +.. _multiple_build_systems: + +^^^^^^^^^^^^^^^^^^^^^^ +Multiple build systems +^^^^^^^^^^^^^^^^^^^^^^ + +There are cases where a software actively supports two build systems, or changes build systems +as it evolves, or needs different build systems on different platforms. Spack allows dealing with +these cases natively, if a recipe is written using builders explicitly. + +For instance, software that supports two build systems unconditionally should derive from +both ``*Package`` base classes, and declare the possible use of multiple build systems using +a directive: + +.. code-block:: python + + class ArpackNg(CMakePackage, AutotoolsPackage): + + build_system("cmake", "autotools", default="cmake") + +In this case the software can be built with both ``autotools`` and ``cmake``. Since the package +supports multiple build systems, it is necessary to declare which one is the default. The ``package.py`` +will likely contain some overriding of default builder methods: + +.. code-block:: python + + class CMakeBuilder(spack.build_systems.cmake.CMakeBuilder): + def cmake_args(self): + pass + + class Autotoolsbuilder(spack.build_systems.autotools.AutotoolsBuilder): + def configure_args(self): + pass + +In more complex cases it might happen that the build system changes according to certain conditions, +for instance across versions. That can be expressed with conditional variant values: + +.. code-block:: python + + class ArpackNg(CMakePackage, AutotoolsPackage): + + build_system( + conditional("cmake", when="@0.64:"), + conditional("autotools", when="@:0.63"), + default="cmake", + ) + +In the example the directive impose a change from ``Autotools`` to ``CMake`` going +from ``v0.63`` to ``v0.64``. + +^^^^^^^^^^^^^^^^^^ +Mixin base classes +^^^^^^^^^^^^^^^^^^ + +Besides build systems, there are other cases where common metadata and behavior can be extracted +and reused by many packages. For instance, packages that depend on ``Cuda`` or ``Rocm``, share +common dependencies and constraints. To factor these attributes into a single place, Spack provides +a few mixin classes in the ``spack.build_systems`` module: + ++---------------------------------------------------------------+----------------------------------+ +| **API docs** | **Description** | ++===============================================================+==================================+ +| :class:`~spack.build_systems.cuda.CudaPackage` | A helper class for packages that | +| | use CUDA | ++---------------------------------------------------------------+----------------------------------+ +| :class:`~spack.build_systems.rocm.ROCmPackage` | A helper class for packages that | +| | use ROCm | ++---------------------------------------------------------------+----------------------------------+ +| :class:`~spack.build_systems.gnu.GNUMirrorPackage` | A helper class for GNU packages | ++---------------------------------------------------------------+----------------------------------+ +| :class:`~spack.build_systems.python.PythonExtension` | A helper class for Python | +| | extensions | ++---------------------------------------------------------------+----------------------------------+ +| :class:`~spack.build_systems.sourceforge.SourceforgePackage` | A helper class for packages | +| | from sourceforge.org | ++---------------------------------------------------------------+----------------------------------+ +| :class:`~spack.build_systems.sourceware.SourcewarePackage` | A helper class for packages | +| | from sourceware.org | ++---------------------------------------------------------------+----------------------------------+ +| :class:`~spack.build_systems.xorg.XorgPackage` | A helper class for x.org | +| | packages | ++---------------------------------------------------------------+----------------------------------+ + +These classes should be used by adding them to the inheritance tree of the package that needs them, +for instance: + +.. code-block:: python + + class Cp2k(MakefilePackage, CudaPackage): + """CP2K is a quantum chemistry and solid state physics software package + that can perform atomistic simulations of solid state, liquid, molecular, + periodic, material, crystal, and biological systems + """ + +In the example above ``Cp2k`` inherits all the conflicts and variants that ``CudaPackage`` defines. .. _install-environment: @@ -6116,3 +6297,82 @@ might write: DWARF_PREFIX = $(spack location --install-dir libdwarf) CXXFLAGS += -I$DWARF_PREFIX/include CXXFLAGS += -L$DWARF_PREFIX/lib + + +.. _package_class_structure: + +-------------------------- +Package class architecture +-------------------------- + +.. note:: + + This section aims to provide a high-level knowledge of how the package class architecture evolved + in Spack, and provides some insights on the current design. + +Packages in Spack were originally designed to support only a single build system. The overall +class structure for a package looked like: + +.. image:: images/original_package_architecture.png + :scale: 60 % + :align: center + +In this architecture the base class ``AutotoolsPackage`` was responsible for both the metadata +related to the ``autotools`` build system (e.g. dependencies or variants common to all packages +using it), and for encoding the default installation procedure. + +In reality, a non-negligible number of packages are either changing their build system during the evolution of the +project, or using different build systems for different platforms. An architecture based on a single class +requires hacks or other workarounds to deal with these cases. + +To support a model more adherent to reality, Spack v0.19 changed its internal design by extracting +the attributes and methods related to building a software into a separate hierarchy: + +.. image:: images/builder_package_architecture.png + :scale: 60 % + :align: center + +In this new format each ``package.py`` contains one ``*Package`` class that gathers all the metadata, +and one or more ``*Builder`` classes that encode the installation procedure. A specific builder object +is created just before the software is built, so at a time where Spack knows which build system needs +to be used for the current installation, and receives a ``package`` object during initialization. + +^^^^^^^^^^^^^^^^^^^^^^^^ +``build_system`` variant +^^^^^^^^^^^^^^^^^^^^^^^^ + +To allow imposing conditions based on the build system, each package must a have ``build_system`` variant, +which is usually inherited from base classes. This variant allows for writing metadata that is conditional +on the build system: + +.. code-block:: python + + with when("build_system=cmake"): + depends_on("cmake", type="build") + +and also for selecting a specific build system from a spec literal, like in the following command: + +.. code-block:: console + + $ spack install arpack-ng build_system=autotools + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Compatibility with single-class format +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Internally, Spack always uses builders to perform operations related to the installation of a specific software. +The builders are created in the ``spack.builder.create`` function + +.. literalinclude:: _spack_root/lib/spack/spack/builder.py + :pyobject: create + +To achieve backward compatibility with the single-class format Spack creates in this function a special +"adapter builder", if no custom builder is detected in the recipe: + +.. image:: images/adapter.png + :scale: 60 % + :align: center + +Overall the role of the adapter is to route access to attributes of methods first through the ``*Package`` +hierarchy, and then back to the base class builder. This is schematically shown in the diagram above, where +the adapter role is to "emulate" a method resolution order like the one represented by the red arrows. \ No newline at end of file diff --git a/lib/spack/spack/audit.py b/lib/spack/spack/audit.py index ee974a19b1e..de9fc1a05bd 100644 --- a/lib/spack/spack/audit.py +++ b/lib/spack/spack/audit.py @@ -503,6 +503,33 @@ def invalid_sha256_digest(fetcher): return errors +@package_properties +def _ensure_env_methods_are_ported_to_builders(pkgs, error_cls): + """Ensure that methods modifying the build environment are ported to builder classes.""" + errors = [] + for pkg_name in pkgs: + pkg_cls = spack.repo.path.get_pkg_class(pkg_name) + buildsystem_variant, _ = pkg_cls.variants["build_system"] + buildsystem_names = [getattr(x, "value", x) for x in buildsystem_variant.values] + builder_cls_names = [spack.builder.BUILDER_CLS[x].__name__ for x in buildsystem_names] + module = pkg_cls.module + has_builders_in_package_py = any( + getattr(module, name, False) for name in builder_cls_names + ) + if not has_builders_in_package_py: + continue + + for method_name in ("setup_build_environment", "setup_dependent_build_environment"): + if hasattr(pkg_cls, method_name): + msg = ( + "Package '{}' need to move the '{}' method from the package class to the" + " appropriate builder class".format(pkg_name, method_name) + ) + errors.append(error_cls(msg, [])) + + return errors + + @package_https_directives def _linting_package_file(pkgs, error_cls): """Check for correctness of links""" @@ -660,7 +687,13 @@ def _ensure_variant_defaults_are_parsable(pkgs, error_cls): errors.append(error_cls(error_msg.format(variant_name, pkg_name), [])) continue - vspec = variant.make_default() + try: + vspec = variant.make_default() + except spack.variant.MultipleValuesInExclusiveVariantError: + error_msg = "Cannot create a default value for the variant '{}' in package '{}'" + errors.append(error_cls(error_msg.format(variant_name, pkg_name), [])) + continue + try: variant.validate_or_raise(vspec, pkg_cls=pkg_cls) except spack.variant.InvalidVariantValueError: diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py index f8fda997d3f..9fe7c1fbb7c 100644 --- a/lib/spack/spack/build_environment.py +++ b/lib/spack/spack/build_environment.py @@ -52,6 +52,7 @@ import spack.build_systems.cmake import spack.build_systems.meson +import spack.builder import spack.config import spack.install_test import spack.main @@ -558,9 +559,9 @@ def _set_variables_for_single_module(pkg, module): if sys.platform == "win32": m.nmake = Executable("nmake") # Standard CMake arguments - m.std_cmake_args = spack.build_systems.cmake.CMakePackage._std_args(pkg) - m.std_meson_args = spack.build_systems.meson.MesonPackage._std_args(pkg) - m.std_pip_args = spack.build_systems.python.PythonPackage._std_args(pkg) + m.std_cmake_args = spack.build_systems.cmake.CMakeBuilder.std_args(pkg) + m.std_meson_args = spack.build_systems.meson.MesonBuilder.std_args(pkg) + m.std_pip_args = spack.build_systems.python.PythonPipBuilder.std_args(pkg) # Put spack compiler paths in module scope. link_dir = spack.paths.build_env_path @@ -727,38 +728,6 @@ def get_rpaths(pkg): return list(dedupe(filter_system_paths(rpaths))) -def get_std_cmake_args(pkg): - """List of standard arguments used if a package is a CMakePackage. - - Returns: - list: standard arguments that would be used if this - package were a CMakePackage instance. - - Args: - pkg (spack.package_base.PackageBase): package under consideration - - Returns: - list: arguments for cmake - """ - return spack.build_systems.cmake.CMakePackage._std_args(pkg) - - -def get_std_meson_args(pkg): - """List of standard arguments used if a package is a MesonPackage. - - Returns: - list: standard arguments that would be used if this - package were a MesonPackage instance. - - Args: - pkg (spack.package_base.PackageBase): package under consideration - - Returns: - list: arguments for meson - """ - return spack.build_systems.meson.MesonPackage._std_args(pkg) - - def parent_class_modules(cls): """ Get list of superclass modules that descend from spack.package_base.PackageBase @@ -819,7 +788,8 @@ def setup_package(pkg, dirty, context="build"): platform.setup_platform_environment(pkg, env_mods) if context == "build": - pkg.setup_build_environment(env_mods) + builder = spack.builder.create(pkg) + builder.setup_build_environment(env_mods) if (not dirty) and (not env_mods.is_unset("CPATH")): tty.debug( @@ -1015,7 +985,8 @@ def add_modifications_for_dep(dep): module.__dict__.update(changes.__dict__) if context == "build": - dpkg.setup_dependent_build_environment(env, spec) + builder = spack.builder.create(dpkg) + builder.setup_dependent_build_environment(env, spec) else: dpkg.setup_dependent_run_environment(env, spec) @@ -1117,8 +1088,20 @@ def _setup_pkg_and_run( pkg.test_suite.stage, spack.install_test.TestSuite.test_log_name(pkg.spec) ) + error_msg = str(exc) + if isinstance(exc, (spack.multimethod.NoSuchMethodError, AttributeError)): + error_msg = ( + "The '{}' package cannot find an attribute while trying to build " + "from sources. This might be due to a change in Spack's package format " + "to support multiple build-systems for a single package. You can fix this " + "by updating the build recipe, and you can also report the issue as a bug. " + "More information at https://spack.readthedocs.io/en/latest/packaging_guide.html#installation-procedure" + ).format(pkg.name) + error_msg = colorize("@*R{{{}}}".format(error_msg)) + error_msg = "{}\n\n{}".format(str(exc), error_msg) + # make a pickleable exception to send to parent. - msg = "%s: %s" % (exc_type.__name__, str(exc)) + msg = "%s: %s" % (exc_type.__name__, error_msg) ce = ChildError( msg, diff --git a/lib/spack/spack/build_systems/_checks.py b/lib/spack/spack/build_systems/_checks.py new file mode 100644 index 00000000000..73d5bbdb93e --- /dev/null +++ b/lib/spack/spack/build_systems/_checks.py @@ -0,0 +1,124 @@ +# 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) +import os + +import six + +import llnl.util.lang + +import spack.builder +import spack.installer +import spack.relocate +import spack.store + + +def sanity_check_prefix(builder): + """Check that specific directories and files are created after installation. + + The files to be checked are in the ``sanity_check_is_file`` attribute of the + package object, while the directories are in the ``sanity_check_is_dir``. + + Args: + builder (spack.builder.Builder): builder that installed the package + """ + pkg = builder.pkg + + def check_paths(path_list, filetype, predicate): + if isinstance(path_list, six.string_types): + path_list = [path_list] + + for path in path_list: + abs_path = os.path.join(pkg.prefix, path) + if not predicate(abs_path): + msg = "Install failed for {0}. No such {1} in prefix: {2}" + msg = msg.format(pkg.name, filetype, path) + raise spack.installer.InstallError(msg) + + check_paths(pkg.sanity_check_is_file, "file", os.path.isfile) + check_paths(pkg.sanity_check_is_dir, "directory", os.path.isdir) + + ignore_file = llnl.util.lang.match_predicate(spack.store.layout.hidden_file_regexes) + if all(map(ignore_file, os.listdir(pkg.prefix))): + msg = "Install failed for {0}. Nothing was installed!" + raise spack.installer.InstallError(msg.format(pkg.name)) + + +def apply_macos_rpath_fixups(builder): + """On Darwin, make installed libraries more easily relocatable. + + Some build systems (handrolled, autotools, makefiles) can set their own + rpaths that are duplicated by spack's compiler wrapper. This fixup + interrogates, and postprocesses if necessary, all libraries installed + by the code. + + It should be added as a @run_after to packaging systems (or individual + packages) that do not install relocatable libraries by default. + + Args: + builder (spack.builder.Builder): builder that installed the package + """ + spack.relocate.fixup_macos_rpaths(builder.spec) + + +def ensure_build_dependencies_or_raise(spec, dependencies, error_msg): + """Ensure that some build dependencies are present in the concrete spec. + + If not, raise a RuntimeError with a helpful error message. + + Args: + spec (spack.spec.Spec): concrete spec to be checked. + dependencies (list of spack.spec.Spec): list of abstract specs to be satisfied + error_msg (str): brief error message to be prepended to a longer description + + Raises: + RuntimeError: when the required build dependencies are not found + """ + assert spec.concrete, "Can ensure build dependencies only on concrete specs" + build_deps = [d.name for d in spec.dependencies(deptype="build")] + missing_deps = [x for x in dependencies if x not in build_deps] + + if not missing_deps: + return + + # Raise an exception on missing deps. + msg = ( + "{0}: missing dependencies: {1}.\n\nPlease add " + "the following lines to the package:\n\n".format(error_msg, ", ".join(missing_deps)) + ) + + for dep in missing_deps: + msg += " depends_on('{0}', type='build', when='@{1} {2}')\n".format( + dep, spec.version, "build_system=autotools" + ) + + msg += "\nUpdate the version (when='@{0}') as needed.".format(spec.version) + raise RuntimeError(msg) + + +def execute_build_time_tests(builder): + """Execute the build-time tests prescribed by builder. + + Args: + builder (Builder): builder prescribing the test callbacks. The name of the callbacks is + stored as a list of strings in the ``build_time_test_callbacks`` attribute. + """ + builder.pkg.run_test_callbacks(builder, builder.build_time_test_callbacks, "build") + + +def execute_install_time_tests(builder): + """Execute the install-time tests prescribed by builder. + + Args: + builder (Builder): builder prescribing the test callbacks. The name of the callbacks is + stored as a list of strings in the ``install_time_test_callbacks`` attribute. + """ + builder.pkg.run_test_callbacks(builder, builder.install_time_test_callbacks, "install") + + +class BaseBuilder(spack.builder.Builder): + """Base class for builders to register common checks""" + + # Check that self.prefix is there after installation + spack.builder.run_after("install")(sanity_check_prefix) diff --git a/lib/spack/spack/build_systems/aspell_dict.py b/lib/spack/spack/build_systems/aspell_dict.py index f1e41cc3dfa..9de8255e68b 100644 --- a/lib/spack/spack/build_systems/aspell_dict.py +++ b/lib/spack/spack/build_systems/aspell_dict.py @@ -2,18 +2,36 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import llnl.util.filesystem as fs -# Why doesn't this work for me? -# from spack import * -from llnl.util.filesystem import filter_file +import spack.directives +import spack.package_base +import spack.util.executable -from spack.build_systems.autotools import AutotoolsPackage -from spack.directives import extends -from spack.package_base import ExtensionError -from spack.util.executable import which +from .autotools import AutotoolsBuilder, AutotoolsPackage + + +class AspellBuilder(AutotoolsBuilder): + """The Aspell builder is close enough to an autotools builder to allow + specializing the builder class, so to use variables that are specific + to the Aspell extensions. + """ + + def configure(self, pkg, spec, prefix): + aspell = spec["aspell"].prefix.bin.aspell + prezip = spec["aspell"].prefix.bin.prezip + destdir = prefix + + sh = spack.util.executable.which("sh") + sh( + "./configure", + "--vars", + "ASPELL={0}".format(aspell), + "PREZIP={0}".format(prezip), + "DESTDIR={0}".format(destdir), + ) -# # Aspell dictionaries install their bits into their prefix.lib # and when activated they'll get symlinked into the appropriate aspell's # dict dir (see aspell's {de,}activate methods). @@ -23,12 +41,17 @@ class AspellDictPackage(AutotoolsPackage): """Specialized class for building aspell dictionairies.""" - extends("aspell") + spack.directives.extends("aspell", when="build_system=autotools") + + #: Override the default autotools builder + AutotoolsBuilder = AspellBuilder def view_destination(self, view): aspell_spec = self.spec["aspell"] if view.get_projection_for_spec(aspell_spec) != aspell_spec.prefix: - raise ExtensionError("aspell does not support non-global extensions") + raise spack.package_base.ExtensionError( + "aspell does not support non-global extensions" + ) aspell = aspell_spec.command return aspell("dump", "config", "dict-dir", output=str).strip() @@ -36,19 +59,5 @@ def view_source(self): return self.prefix.lib def patch(self): - filter_file(r"^dictdir=.*$", "dictdir=/lib", "configure") - filter_file(r"^datadir=.*$", "datadir=/lib", "configure") - - def configure(self, spec, prefix): - aspell = spec["aspell"].prefix.bin.aspell - prezip = spec["aspell"].prefix.bin.prezip - destdir = prefix - - sh = which("sh") - sh( - "./configure", - "--vars", - "ASPELL={0}".format(aspell), - "PREZIP={0}".format(prezip), - "DESTDIR={0}".format(destdir), - ) + fs.filter_file(r"^dictdir=.*$", "dictdir=/lib", "configure") + fs.filter_file(r"^datadir=.*$", "datadir=/lib", "configure") diff --git a/lib/spack/spack/build_systems/autotools.py b/lib/spack/spack/build_systems/autotools.py index 81a572de528..76e6bb27ce6 100644 --- a/lib/spack/spack/build_systems/autotools.py +++ b/lib/spack/spack/build_systems/autotools.py @@ -6,87 +6,140 @@ import os import os.path import stat -from subprocess import PIPE, check_call +import subprocess from typing import List # novm import llnl.util.filesystem as fs import llnl.util.tty as tty -from llnl.util.filesystem import force_remove, working_dir -from spack.build_environment import InstallError -from spack.directives import conflicts, depends_on +import spack.build_environment +import spack.builder +import spack.package_base +from spack.directives import build_system, conflicts, depends_on +from spack.multimethod import when from spack.operating_systems.mac_os import macos_version -from spack.package_base import PackageBase, run_after, run_before from spack.util.executable import Executable from spack.version import Version +from ._checks import ( + BaseBuilder, + apply_macos_rpath_fixups, + ensure_build_dependencies_or_raise, + execute_build_time_tests, + execute_install_time_tests, +) -class AutotoolsPackage(PackageBase): - """Specialized class for packages built using GNU Autotools. - This class provides four phases that can be overridden: +class AutotoolsPackage(spack.package_base.PackageBase): + """Specialized class for packages built using GNU Autotools.""" - 1. :py:meth:`~.AutotoolsPackage.autoreconf` - 2. :py:meth:`~.AutotoolsPackage.configure` - 3. :py:meth:`~.AutotoolsPackage.build` - 4. :py:meth:`~.AutotoolsPackage.install` + #: This attribute is used in UI queries that need to know the build + #: system base class + build_system_class = "AutotoolsPackage" + + #: Legacy buildsystem attribute used to deserialize and install old specs + legacy_buildsystem = "autotools" + + build_system("autotools") + + with when("build_system=autotools"): + depends_on("gnuconfig", type="build", when="target=ppc64le:") + depends_on("gnuconfig", type="build", when="target=aarch64:") + depends_on("gnuconfig", type="build", when="target=riscv64:") + conflicts("platform=windows") + + def flags_to_build_system_args(self, flags): + """Produces a list of all command line arguments to pass specified + compiler flags to configure.""" + # Has to be dynamic attribute due to caching. + setattr(self, "configure_flag_args", []) + for flag, values in flags.items(): + if values: + values_str = "{0}={1}".format(flag.upper(), " ".join(values)) + self.configure_flag_args.append(values_str) + # Spack's fflags are meant for both F77 and FC, therefore we + # additionaly set FCFLAGS if required. + values = flags.get("fflags", None) + if values: + values_str = "FCFLAGS={0}".format(" ".join(values)) + self.configure_flag_args.append(values_str) + + # Legacy methods (used by too many packages to change them, + # need to forward to the builder) + def enable_or_disable(self, *args, **kwargs): + return self.builder.enable_or_disable(*args, **kwargs) + + def with_or_without(self, *args, **kwargs): + return self.builder.with_or_without(*args, **kwargs) + + +@spack.builder.builder("autotools") +class AutotoolsBuilder(BaseBuilder): + """The autotools builder encodes the default way of installing software built + with autotools. It has four phases that can be overridden, if need be: + + 1. :py:meth:`~.AutotoolsBuilder.autoreconf` + 2. :py:meth:`~.AutotoolsBuilder.configure` + 3. :py:meth:`~.AutotoolsBuilder.build` + 4. :py:meth:`~.AutotoolsBuilder.install` + + They all have sensible defaults and for many packages the only thing necessary + is to override the helper method + :meth:`~spack.build_systems.autotools.AutotoolsBuilder.configure_args`. - They all have sensible defaults and for many packages the only thing - necessary will be to override the helper method - :meth:`~spack.build_systems.autotools.AutotoolsPackage.configure_args`. For a finer tuning you may also override: +-----------------------------------------------+--------------------+ | **Method** | **Purpose** | +===============================================+====================+ - | :py:attr:`~.AutotoolsPackage.build_targets` | Specify ``make`` | + | :py:attr:`~.AutotoolsBuilder.build_targets` | Specify ``make`` | | | targets for the | | | build phase | +-----------------------------------------------+--------------------+ - | :py:attr:`~.AutotoolsPackage.install_targets` | Specify ``make`` | + | :py:attr:`~.AutotoolsBuilder.install_targets` | Specify ``make`` | | | targets for the | | | install phase | +-----------------------------------------------+--------------------+ - | :py:meth:`~.AutotoolsPackage.check` | Run build time | + | :py:meth:`~.AutotoolsBuilder.check` | Run build time | | | tests if required | +-----------------------------------------------+--------------------+ """ #: Phases of a GNU Autotools package - phases = ["autoreconf", "configure", "build", "install"] - #: This attribute is used in UI queries that need to know the build - #: system base class - build_system_class = "AutotoolsPackage" + phases = ("autoreconf", "configure", "build", "install") - @property - def patch_config_files(self): - """ - Whether or not to update old ``config.guess`` and ``config.sub`` files - distributed with the tarball. This currently only applies to - ``ppc64le:``, ``aarch64:``, and ``riscv64`` target architectures. The - substitutes are taken from the ``gnuconfig`` package, which is - automatically added as a build dependency for these architectures. In - case system versions of these config files are required, the - ``gnuconfig`` package can be marked external with a prefix pointing to - the directory containing the system ``config.guess`` and ``config.sub`` - files. - """ - return ( - self.spec.satisfies("target=ppc64le:") - or self.spec.satisfies("target=aarch64:") - or self.spec.satisfies("target=riscv64:") - ) + #: Names associated with package methods in the old build-system format + legacy_methods = ( + "configure_args", + "check", + "installcheck", + ) - #: Whether or not to update ``libtool`` - #: (currently only for Arm/Clang/Fujitsu/NVHPC compilers) + #: Names associated with package attributes in the old build-system format + legacy_attributes = ( + "archive_files", + "patch_libtool", + "build_targets", + "install_targets", + "build_time_test_callbacks", + "install_time_test_callbacks", + "force_autoreconf", + "autoreconf_extra_args", + "install_libtool_archives", + "patch_config_files", + "configure_directory", + "configure_abs_path", + "build_directory", + "autoreconf_search_path_args", + ) + + #: Whether to update ``libtool`` (e.g. for Arm/Clang/Fujitsu/NVHPC compilers) patch_libtool = True - #: Targets for ``make`` during the :py:meth:`~.AutotoolsPackage.build` - #: phase + #: Targets for ``make`` during the :py:meth:`~.AutotoolsBuilder.build` phase build_targets = [] # type: List[str] - #: Targets for ``make`` during the :py:meth:`~.AutotoolsPackage.install` - #: phase + #: Targets for ``make`` during the :py:meth:`~.AutotoolsBuilder.install` phase install_targets = ["install"] #: Callback names for build-time test @@ -97,24 +150,40 @@ def patch_config_files(self): #: Set to true to force the autoreconf step even if configure is present force_autoreconf = False + #: Options to be passed to autoreconf when using the default implementation autoreconf_extra_args = [] # type: List[str] - #: If False deletes all the .la files in the prefix folder - #: after the installation. If True instead it installs them. + #: If False deletes all the .la files in the prefix folder after the installation. + #: If True instead it installs them. install_libtool_archives = False - depends_on("gnuconfig", type="build", when="target=ppc64le:") - depends_on("gnuconfig", type="build", when="target=aarch64:") - depends_on("gnuconfig", type="build", when="target=riscv64:") - conflicts("platform=windows") + @property + def patch_config_files(self): + """Whether to update old ``config.guess`` and ``config.sub`` files + distributed with the tarball. + + This currently only applies to ``ppc64le:``, ``aarch64:``, and + ``riscv64`` target architectures. + + The substitutes are taken from the ``gnuconfig`` package, which is + automatically added as a build dependency for these architectures. In case + system versions of these config files are required, the ``gnuconfig`` package + can be marked external, with a prefix pointing to the directory containing the + system ``config.guess`` and ``config.sub`` files. + """ + return ( + self.pkg.spec.satisfies("target=ppc64le:") + or self.pkg.spec.satisfies("target=aarch64:") + or self.pkg.spec.satisfies("target=riscv64:") + ) @property def _removed_la_files_log(self): - """File containing the list of remove libtool archives""" + """File containing the list of removed libtool archives""" build_dir = self.build_directory if not os.path.isabs(self.build_directory): - build_dir = os.path.join(self.stage.path, build_dir) + build_dir = os.path.join(self.pkg.stage.path, build_dir) return os.path.join(build_dir, "removed_la_files.txt") @property @@ -125,13 +194,13 @@ def archive_files(self): files.append(self._removed_la_files_log) return files - @run_after("autoreconf") + @spack.builder.run_after("autoreconf") def _do_patch_config_files(self): - """Some packages ship with older config.guess/config.sub files and - need to have these updated when installed on a newer architecture. - In particular, config.guess fails for PPC64LE for version prior - to a 2013-06-10 build date (automake 1.13.4) and for ARM (aarch64) and - RISC-V (riscv64). + """Some packages ship with older config.guess/config.sub files and need to + have these updated when installed on a newer architecture. + + In particular, config.guess fails for PPC64LE for version prior to a + 2013-06-10 build date (automake 1.13.4) and for AArch64 and RISC-V. """ if not self.patch_config_files: return @@ -139,11 +208,11 @@ def _do_patch_config_files(self): # TODO: Expand this to select the 'config.sub'-compatible architecture # for each platform (e.g. 'config.sub' doesn't accept 'power9le', but # does accept 'ppc64le'). - if self.spec.satisfies("target=ppc64le:"): + if self.pkg.spec.satisfies("target=ppc64le:"): config_arch = "ppc64le" - elif self.spec.satisfies("target=aarch64:"): + elif self.pkg.spec.satisfies("target=aarch64:"): config_arch = "aarch64" - elif self.spec.satisfies("target=riscv64:"): + elif self.pkg.spec.satisfies("target=riscv64:"): config_arch = "riscv64" else: config_arch = "local" @@ -155,7 +224,7 @@ def runs_ok(script_abs_path): args = [script_abs_path] + additional_args.get(script_name, []) try: - check_call(args, stdout=PIPE, stderr=PIPE) + subprocess.check_call(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) except Exception as e: tty.debug(e) return False @@ -163,7 +232,7 @@ def runs_ok(script_abs_path): return True # Get the list of files that needs to be patched - to_be_patched = fs.find(self.stage.path, files=["config.sub", "config.guess"]) + to_be_patched = fs.find(self.pkg.stage.path, files=["config.sub", "config.guess"]) to_be_patched = [f for f in to_be_patched if not runs_ok(f)] # If there are no files to be patched, return early @@ -171,22 +240,21 @@ def runs_ok(script_abs_path): return # Otherwise, require `gnuconfig` to be a build dependency - self._require_build_deps( - pkgs=["gnuconfig"], spec=self.spec, err="Cannot patch config files" + ensure_build_dependencies_or_raise( + spec=self.pkg.spec, dependencies=["gnuconfig"], error_msg="Cannot patch config files" ) # Get the config files we need to patch (config.sub / config.guess). to_be_found = list(set(os.path.basename(f) for f in to_be_patched)) - gnuconfig = self.spec["gnuconfig"] + gnuconfig = self.pkg.spec["gnuconfig"] gnuconfig_dir = gnuconfig.prefix # An external gnuconfig may not not have a prefix. if gnuconfig_dir is None: - raise InstallError( - "Spack could not find substitutes for GNU config " - "files because no prefix is available for the " - "`gnuconfig` package. Make sure you set a prefix " - "path instead of modules for external `gnuconfig`." + raise spack.build_environment.InstallError( + "Spack could not find substitutes for GNU config files because no " + "prefix is available for the `gnuconfig` package. Make sure you set a " + "prefix path instead of modules for external `gnuconfig`." ) candidates = fs.find(gnuconfig_dir, files=to_be_found, recursive=False) @@ -203,7 +271,7 @@ def runs_ok(script_abs_path): msg += ( " or the `gnuconfig` package prefix is misconfigured as" " an external package" ) - raise InstallError(msg) + raise spack.build_environment.InstallError(msg) # Filter working substitutes candidates = [f for f in candidates if runs_ok(f)] @@ -228,7 +296,9 @@ def runs_ok(script_abs_path): and set the prefix to the directory containing the `config.guess` and `config.sub` files. """ - raise InstallError(msg.format(", ".join(to_be_found), self.name)) + raise spack.build_environment.InstallError( + msg.format(", ".join(to_be_found), self.name) + ) # Copy the good files over the bad ones for abs_path in to_be_patched: @@ -238,7 +308,7 @@ def runs_ok(script_abs_path): fs.copy(substitutes[name], abs_path) os.chmod(abs_path, mode) - @run_before("configure") + @spack.builder.run_before("configure") def _patch_usr_bin_file(self): """On NixOS file is not available in /usr/bin/file. Patch configure scripts to use file from path.""" @@ -250,7 +320,7 @@ def _patch_usr_bin_file(self): with fs.keep_modification_time(*x.filenames): x.filter(regex="/usr/bin/file", repl="file", string=True) - @run_before("configure") + @spack.builder.run_before("configure") def _set_autotools_environment_variables(self): """Many autotools builds use a version of mknod.m4 that fails when running as root unless FORCE_UNSAFE_CONFIGURE is set to 1. @@ -261,11 +331,10 @@ def _set_autotools_environment_variables(self): Without it, configure just fails halfway through, but it can still run things *before* this check. Forcing this just removes a nuisance -- this is not circumventing any real protection. - """ os.environ["FORCE_UNSAFE_CONFIGURE"] = "1" - @run_before("configure") + @spack.builder.run_before("configure") def _do_patch_libtool_configure(self): """Patch bugs that propagate from libtool macros into "configure" and further into "libtool". Note that patches that can be fixed by patching @@ -293,7 +362,7 @@ def _do_patch_libtool_configure(self): # Support Libtool 2.4.2 and older: x.filter(regex=r'^(\s*test \$p = "-R")(; then\s*)$', repl=r'\1 || test x-l = x"$p"\2') - @run_after("configure") + @spack.builder.run_after("configure") def _do_patch_libtool(self): """If configure generates a "libtool" script that does not correctly detect the compiler (and patch_libtool is set), patch in the correct @@ -328,31 +397,33 @@ def _do_patch_libtool(self): markers[tag] = "LIBTOOL TAG CONFIG: {0}".format(tag.upper()) # Replace empty linker flag prefixes: - if self.compiler.name == "nag": + if self.pkg.compiler.name == "nag": # Nag is mixed with gcc and g++, which are recognized correctly. # Therefore, we change only Fortran values: for tag in ["fc", "f77"]: marker = markers[tag] x.filter( regex='^wl=""$', - repl='wl="{0}"'.format(self.compiler.linker_arg), + repl='wl="{0}"'.format(self.pkg.compiler.linker_arg), start_at="# ### BEGIN {0}".format(marker), stop_at="# ### END {0}".format(marker), ) else: - x.filter(regex='^wl=""$', repl='wl="{0}"'.format(self.compiler.linker_arg)) + x.filter(regex='^wl=""$', repl='wl="{0}"'.format(self.pkg.compiler.linker_arg)) # Replace empty PIC flag values: for cc, marker in markers.items(): x.filter( regex='^pic_flag=""$', - repl='pic_flag="{0}"'.format(getattr(self.compiler, "{0}_pic_flag".format(cc))), + repl='pic_flag="{0}"'.format( + getattr(self.pkg.compiler, "{0}_pic_flag".format(cc)) + ), start_at="# ### BEGIN {0}".format(marker), stop_at="# ### END {0}".format(marker), ) # Other compiler-specific patches: - if self.compiler.name == "fj": + if self.pkg.compiler.name == "fj": x.filter(regex="-nostdlib", repl="", string=True) rehead = r"/\S*/" for o in [ @@ -365,12 +436,12 @@ def _do_patch_libtool(self): "crtendS.o", ]: x.filter(regex=(rehead + o), repl="", string=True) - elif self.compiler.name == "dpcpp": + elif self.pkg.compiler.name == "dpcpp": # Hack to filter out spurious predep_objects when building with Intel dpcpp # (see https://github.com/spack/spack/issues/32863): x.filter(regex=r"^(predep_objects=.*)/tmp/conftest-[0-9A-Fa-f]+\.o", repl=r"\1") x.filter(regex=r"^(predep_objects=.*)/tmp/a-[0-9A-Fa-f]+\.o", repl=r"\1") - elif self.compiler.name == "nag": + elif self.pkg.compiler.name == "nag": for tag in ["fc", "f77"]: marker = markers[tag] start_at = "# ### BEGIN {0}".format(marker) @@ -446,11 +517,8 @@ def _do_patch_libtool(self): @property def configure_directory(self): - """Returns the directory where 'configure' resides. - - :return: directory where to find configure - """ - return self.stage.source_path + """Return the directory where 'configure' resides.""" + return self.pkg.stage.source_path @property def configure_abs_path(self): @@ -463,34 +531,12 @@ def build_directory(self): """Override to provide another place to build the package""" return self.configure_directory - @run_before("autoreconf") + @spack.builder.run_before("autoreconf") def delete_configure_to_force_update(self): if self.force_autoreconf: - force_remove(self.configure_abs_path) + fs.force_remove(self.configure_abs_path) - def _require_build_deps(self, pkgs, spec, err): - """Require `pkgs` to be direct build dependencies of `spec`. Raises a - RuntimeError with a helpful error messages when any dep is missing.""" - - build_deps = [d.name for d in spec.dependencies(deptype="build")] - missing_deps = [x for x in pkgs if x not in build_deps] - - if not missing_deps: - return - - # Raise an exception on missing deps. - msg = ( - "{0}: missing dependencies: {1}.\n\nPlease add " - "the following lines to the package:\n\n".format(err, ", ".join(missing_deps)) - ) - - for dep in missing_deps: - msg += " depends_on('{0}', type='build', when='@{1}')\n".format(dep, spec.version) - - msg += "\nUpdate the version (when='@{0}') as needed.".format(spec.version) - raise RuntimeError(msg) - - def autoreconf(self, spec, prefix): + def autoreconf(self, pkg, spec, prefix): """Not needed usually, configure should be already there""" # If configure exists nothing needs to be done @@ -498,8 +544,10 @@ def autoreconf(self, spec, prefix): return # Else try to regenerate it, which reuquires a few build dependencies - self._require_build_deps( - pkgs=["autoconf", "automake", "libtool"], spec=spec, err="Cannot generate configure" + ensure_build_dependencies_or_raise( + spec=spec, + dependencies=["autoconf", "automake", "libtool"], + error_msg="Cannot generate configure", ) tty.msg("Configure script not found: trying to generate it") @@ -507,8 +555,8 @@ def autoreconf(self, spec, prefix): tty.warn("* If the default procedure fails, consider implementing *") tty.warn("* a custom AUTORECONF phase in the package *") tty.warn("*********************************************************") - with working_dir(self.configure_directory): - m = inspect.getmodule(self) + with fs.working_dir(self.configure_directory): + m = inspect.getmodule(self.pkg) # This line is what is needed most of the time # --install, --verbose, --force autoreconf_args = ["-ivf"] @@ -524,98 +572,66 @@ def autoreconf_search_path_args(self): spack dependencies.""" return _autoreconf_search_path_args(self.spec) - @run_after("autoreconf") + @spack.builder.run_after("autoreconf") def set_configure_or_die(self): - """Checks the presence of a ``configure`` file after the - autoreconf phase. If it is found sets a module attribute - appropriately, otherwise raises an error. + """Ensure the presence of a "configure" script, or raise. If the "configure" + is found, a module level attribute is set. - :raises RuntimeError: if a configure script is not found in - :py:meth:`~AutotoolsPackage.configure_directory` + Raises: + RuntimeError: if the "configure" script is not found """ - # Check if a configure script is there. If not raise a RuntimeError. + # Check if the "configure" script is there. If not raise a RuntimeError. if not os.path.exists(self.configure_abs_path): msg = "configure script not found in {0}" raise RuntimeError(msg.format(self.configure_directory)) # Monkey-patch the configure script in the corresponding module - inspect.getmodule(self).configure = Executable(self.configure_abs_path) + inspect.getmodule(self.pkg).configure = Executable(self.configure_abs_path) def configure_args(self): - """Produces a list containing all the arguments that must be passed to - configure, except ``--prefix`` which will be pre-pended to the list. - - :return: list of arguments for configure + """Return the list of all the arguments that must be passed to configure, + except ``--prefix`` which will be pre-pended to the list. """ return [] - def flags_to_build_system_args(self, flags): - """Produces a list of all command line arguments to pass specified - compiler flags to configure.""" - # Has to be dynamic attribute due to caching. - setattr(self, "configure_flag_args", []) - for flag, values in flags.items(): - if values: - values_str = "{0}={1}".format(flag.upper(), " ".join(values)) - self.configure_flag_args.append(values_str) - # Spack's fflags are meant for both F77 and FC, therefore we - # additionaly set FCFLAGS if required. - values = flags.get("fflags", None) - if values: - values_str = "FCFLAGS={0}".format(" ".join(values)) - self.configure_flag_args.append(values_str) - - def configure(self, spec, prefix): - """Runs configure with the arguments specified in - :meth:`~spack.build_systems.autotools.AutotoolsPackage.configure_args` - and an appropriately set prefix. + def configure(self, pkg, spec, prefix): + """Run "configure", with the arguments specified by the builder and an + appropriately set prefix. """ - options = getattr(self, "configure_flag_args", []) + options = getattr(self.pkg, "configure_flag_args", []) options += ["--prefix={0}".format(prefix)] options += self.configure_args() - with working_dir(self.build_directory, create=True): - inspect.getmodule(self).configure(*options) + with fs.working_dir(self.build_directory, create=True): + inspect.getmodule(self.pkg).configure(*options) - def setup_build_environment(self, env): - if self.spec.platform == "darwin" and macos_version() >= Version("11"): - # Many configure files rely on matching '10.*' for macOS version - # detection and fail to add flags if it shows as version 11. - env.set("MACOSX_DEPLOYMENT_TARGET", "10.16") - - def build(self, spec, prefix): - """Makes the build targets specified by - :py:attr:``~.AutotoolsPackage.build_targets`` - """ + def build(self, pkg, spec, prefix): + """Run "make" on the build targets specified by the builder.""" # See https://autotools.io/automake/silent.html params = ["V=1"] params += self.build_targets - with working_dir(self.build_directory): - inspect.getmodule(self).make(*params) + with fs.working_dir(self.build_directory): + inspect.getmodule(self.pkg).make(*params) - def install(self, spec, prefix): - """Makes the install targets specified by - :py:attr:``~.AutotoolsPackage.install_targets`` - """ - with working_dir(self.build_directory): - inspect.getmodule(self).make(*self.install_targets) + def install(self, pkg, spec, prefix): + """Run "make" on the install targets specified by the builder.""" + with fs.working_dir(self.build_directory): + inspect.getmodule(self.pkg).make(*self.install_targets) - run_after("build")(PackageBase._run_default_build_time_test_callbacks) + spack.builder.run_after("build")(execute_build_time_tests) def check(self): - """Searches the Makefile for targets ``test`` and ``check`` - and runs them if found. - """ - with working_dir(self.build_directory): - self._if_make_target_execute("test") - self._if_make_target_execute("check") + """Run "make" on the ``test`` and ``check`` targets, if found.""" + with fs.working_dir(self.build_directory): + self.pkg._if_make_target_execute("test") + self.pkg._if_make_target_execute("check") def _activate_or_not( self, name, activation_word, deactivation_word, activation_value=None, variant=None ): - """This function contains the current implementation details of - :meth:`~spack.build_systems.autotools.AutotoolsPackage.with_or_without` and - :meth:`~spack.build_systems.autotools.AutotoolsPackage.enable_or_disable`. + """This function contain the current implementation details of + :meth:`~spack.build_systems.autotools.AutotoolsBuilder.with_or_without` and + :meth:`~spack.build_systems.autotools.AutotoolsBuilder.enable_or_disable`. Args: name (str): name of the option that is being activated or not @@ -671,7 +687,7 @@ def _activate_or_not( Raises: KeyError: if name is not among known variants """ - spec = self.spec + spec = self.pkg.spec args = [] if activation_value == "prefix": @@ -681,16 +697,16 @@ def _activate_or_not( # Defensively look that the name passed as argument is among # variants - if variant not in self.variants: + if variant not in self.pkg.variants: msg = '"{0}" is not a variant of "{1}"' - raise KeyError(msg.format(variant, self.name)) + raise KeyError(msg.format(variant, self.pkg.name)) if variant not in spec.variants: return [] # Create a list of pairs. Each pair includes a configuration # option and whether or not that option is activated - variant_desc, _ = self.variants[variant] + variant_desc, _ = self.pkg.variants[variant] if set(variant_desc.values) == set((True, False)): # BoolValuedVariant carry information about a single option. # Nonetheless, for uniformity of treatment we'll package them @@ -718,14 +734,18 @@ def _activate_or_not( override_name = "{0}_or_{1}_{2}".format( activation_word, deactivation_word, option_value ) - line_generator = getattr(self, override_name, None) + line_generator = getattr(self, override_name, None) or getattr( + self.pkg, override_name, None + ) # If not available use a sensible default if line_generator is None: def _default_generator(is_activated): if is_activated: line = "--{0}-{1}".format(activation_word, option_value) - if activation_value is not None and activation_value(option_value): + if activation_value is not None and activation_value( + option_value + ): # NOQA=ignore=E501 line += "={0}".format(activation_value(option_value)) return line return "--{0}-{1}".format(deactivation_word, option_value) @@ -764,7 +784,7 @@ def with_or_without(self, name, activation_value=None, variant=None): def enable_or_disable(self, name, activation_value=None, variant=None): """Same as - :meth:`~spack.build_systems.autotools.AutotoolsPackage.with_or_without` + :meth:`~spack.build_systems.autotools.AutotoolsBuilder.with_or_without` but substitute ``with`` with ``enable`` and ``without`` with ``disable``. Args: @@ -781,19 +801,14 @@ def enable_or_disable(self, name, activation_value=None, variant=None): """ return self._activate_or_not(name, "enable", "disable", activation_value, variant) - run_after("install")(PackageBase._run_default_install_time_test_callbacks) + spack.builder.run_after("install")(execute_install_time_tests) def installcheck(self): - """Searches the Makefile for an ``installcheck`` target - and runs it if found. - """ - with working_dir(self.build_directory): - self._if_make_target_execute("installcheck") + """Run "make" on the ``installcheck`` target, if found.""" + with fs.working_dir(self.build_directory): + self.pkg._if_make_target_execute("installcheck") - # Check that self.prefix is there after installation - run_after("install")(PackageBase.sanity_check_prefix) - - @run_after("install") + @spack.builder.run_after("install") def remove_libtool_archives(self): """Remove all .la files in prefix sub-folders if the package sets ``install_libtool_archives`` to be False. @@ -803,14 +818,20 @@ def remove_libtool_archives(self): return # Remove the files and create a log of what was removed - libtool_files = fs.find(str(self.prefix), "*.la", recursive=True) + libtool_files = fs.find(str(self.pkg.prefix), "*.la", recursive=True) with fs.safe_remove(*libtool_files): fs.mkdirp(os.path.dirname(self._removed_la_files_log)) with open(self._removed_la_files_log, mode="w") as f: f.write("\n".join(libtool_files)) + def setup_build_environment(self, env): + if self.spec.platform == "darwin" and macos_version() >= Version("11"): + # Many configure files rely on matching '10.*' for macOS version + # detection and fail to add flags if it shows as version 11. + env.set("MACOSX_DEPLOYMENT_TARGET", "10.16") + # On macOS, force rpaths for shared library IDs and remove duplicate rpaths - run_after("install")(PackageBase.apply_macos_rpath_fixups) + spack.builder.run_after("install", when="platform=darwin")(apply_macos_rpath_fixups) def _autoreconf_search_path_args(spec): diff --git a/lib/spack/spack/build_systems/bundle.py b/lib/spack/spack/build_systems/bundle.py new file mode 100644 index 00000000000..fad0ba4e144 --- /dev/null +++ b/lib/spack/spack/build_systems/bundle.py @@ -0,0 +1,31 @@ +# 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) +import spack.builder +import spack.directives +import spack.package_base + + +class BundlePackage(spack.package_base.PackageBase): + """General purpose bundle, or no-code, package class.""" + + #: This attribute is used in UI queries that require to know which + #: build-system class we are using + build_system_class = "BundlePackage" + + #: Legacy buildsystem attribute used to deserialize and install old specs + legacy_buildsystem = "bundle" + + #: Bundle packages do not have associated source or binary code. + has_code = False + + spack.directives.build_system("bundle") + + +@spack.builder.builder("bundle") +class BundleBuilder(spack.builder.Builder): + phases = ("install",) + + def install(self, pkg, spec, prefix): + pass diff --git a/lib/spack/spack/build_systems/cached_cmake.py b/lib/spack/spack/build_systems/cached_cmake.py index 9ffd2a82abd..7caf2a15397 100644 --- a/lib/spack/spack/build_systems/cached_cmake.py +++ b/lib/spack/spack/build_systems/cached_cmake.py @@ -3,12 +3,14 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) import os +from typing import Tuple +import llnl.util.filesystem as fs import llnl.util.tty as tty -from llnl.util.filesystem import install, mkdirp -from spack.build_systems.cmake import CMakePackage -from spack.package_base import run_after +import spack.builder + +from .cmake import CMakeBuilder, CMakePackage def cmake_cache_path(name, value, comment=""): @@ -28,44 +30,46 @@ def cmake_cache_option(name, boolean_value, comment=""): return 'set({0} {1} CACHE BOOL "{2}")\n'.format(name, value, comment) -class CachedCMakePackage(CMakePackage): - """Specialized class for packages built using CMake initial cache. +class CachedCMakeBuilder(CMakeBuilder): - This feature of CMake allows packages to increase reproducibility, - especially between Spack- and manual builds. It also allows packages to - sidestep certain parsing bugs in extremely long ``cmake`` commands, and to - avoid system limits on the length of the command line.""" + #: Names associated with package methods in the old build-system format + legacy_methods = CMakeBuilder.legacy_methods + ( + "initconfig_compiler_entries", + "initconfig_mpi_entries", + "initconfig_hardware_entries", + "std_initconfig_entries", + "initconfig_package_entries", + ) # type: Tuple[str, ...] - phases = ["initconfig", "cmake", "build", "install"] + #: Names associated with package attributes in the old build-system format + legacy_attributes = CMakeBuilder.legacy_attributes + ( + "cache_name", + "cache_path", + ) # type: Tuple[str, ...] @property def cache_name(self): return "{0}-{1}-{2}@{3}.cmake".format( - self.name, - self.spec.architecture, - self.spec.compiler.name, - self.spec.compiler.version, + self.pkg.name, + self.pkg.spec.architecture, + self.pkg.spec.compiler.name, + self.pkg.spec.compiler.version, ) @property def cache_path(self): - return os.path.join(self.stage.source_path, self.cache_name) - - def flag_handler(self, name, flags): - if name in ("cflags", "cxxflags", "cppflags", "fflags"): - return (None, None, None) # handled in the cmake cache - return (flags, None, None) + return os.path.join(self.pkg.stage.source_path, self.cache_name) def initconfig_compiler_entries(self): # This will tell cmake to use the Spack compiler wrappers when run # through Spack, but use the underlying compiler when run outside of # Spack - spec = self.spec + spec = self.pkg.spec # Fortran compiler is optional if "FC" in os.environ: spack_fc_entry = cmake_cache_path("CMAKE_Fortran_COMPILER", os.environ["FC"]) - system_fc_entry = cmake_cache_path("CMAKE_Fortran_COMPILER", self.compiler.fc) + system_fc_entry = cmake_cache_path("CMAKE_Fortran_COMPILER", self.pkg.compiler.fc) else: spack_fc_entry = "# No Fortran compiler defined in spec" system_fc_entry = "# No Fortran compiler defined in spec" @@ -81,8 +85,8 @@ def initconfig_compiler_entries(self): " " + cmake_cache_path("CMAKE_CXX_COMPILER", os.environ["CXX"]), " " + spack_fc_entry, "else()\n", - " " + cmake_cache_path("CMAKE_C_COMPILER", self.compiler.cc), - " " + cmake_cache_path("CMAKE_CXX_COMPILER", self.compiler.cxx), + " " + cmake_cache_path("CMAKE_C_COMPILER", self.pkg.compiler.cc), + " " + cmake_cache_path("CMAKE_CXX_COMPILER", self.pkg.compiler.cxx), " " + system_fc_entry, "endif()\n", ] @@ -126,7 +130,7 @@ def initconfig_compiler_entries(self): return entries def initconfig_mpi_entries(self): - spec = self.spec + spec = self.pkg.spec if not spec.satisfies("^mpi"): return [] @@ -160,13 +164,13 @@ def initconfig_mpi_entries(self): mpiexec = os.path.join(spec["mpi"].prefix.bin, "mpiexec") if not os.path.exists(mpiexec): - msg = "Unable to determine MPIEXEC, %s tests may fail" % self.name + msg = "Unable to determine MPIEXEC, %s tests may fail" % self.pkg.name entries.append("# {0}\n".format(msg)) tty.warn(msg) else: # starting with cmake 3.10, FindMPI expects MPIEXEC_EXECUTABLE # vs the older versions which expect MPIEXEC - if self.spec["cmake"].satisfies("@3.10:"): + if self.pkg.spec["cmake"].satisfies("@3.10:"): entries.append(cmake_cache_path("MPIEXEC_EXECUTABLE", mpiexec)) else: entries.append(cmake_cache_path("MPIEXEC", mpiexec)) @@ -180,7 +184,7 @@ def initconfig_mpi_entries(self): return entries def initconfig_hardware_entries(self): - spec = self.spec + spec = self.pkg.spec entries = [ "#------------------{0}".format("-" * 60), @@ -212,7 +216,7 @@ def std_initconfig_entries(self): "#------------------{0}".format("-" * 60), "# !!!! This is a generated file, edit at own risk !!!!", "#------------------{0}".format("-" * 60), - "# CMake executable path: {0}".format(self.spec["cmake"].command.path), + "# CMake executable path: {0}".format(self.pkg.spec["cmake"].command.path), "#------------------{0}\n".format("-" * 60), ] @@ -220,7 +224,8 @@ def initconfig_package_entries(self): """This method is to be overwritten by the package""" return [] - def initconfig(self, spec, prefix): + @spack.builder.run_before("cmake") + def initconfig(self): cache_entries = ( self.std_initconfig_entries() + self.initconfig_compiler_entries() @@ -236,11 +241,28 @@ def initconfig(self, spec, prefix): @property def std_cmake_args(self): - args = super(CachedCMakePackage, self).std_cmake_args + args = super(CachedCMakeBuilder, self).std_cmake_args args.extend(["-C", self.cache_path]) return args - @run_after("install") + @spack.builder.run_after("install") def install_cmake_cache(self): - mkdirp(self.spec.prefix.share.cmake) - install(self.cache_path, self.spec.prefix.share.cmake) + fs.mkdirp(self.pkg.spec.prefix.share.cmake) + fs.install(self.cache_path, self.pkg.spec.prefix.share.cmake) + + +class CachedCMakePackage(CMakePackage): + """Specialized class for packages built using CMake initial cache. + + This feature of CMake allows packages to increase reproducibility, + especially between Spack- and manual builds. It also allows packages to + sidestep certain parsing bugs in extremely long ``cmake`` commands, and to + avoid system limits on the length of the command line. + """ + + CMakeBuilder = CachedCMakeBuilder + + def flag_handler(self, name, flags): + if name in ("cflags", "cxxflags", "cppflags", "fflags"): + return None, None, None # handled in the cmake cache + return flags, None, None diff --git a/lib/spack/spack/build_systems/cmake.py b/lib/spack/spack/build_systems/cmake.py index 6fb75b6747d..8d8bba47781 100644 --- a/lib/spack/spack/build_systems/cmake.py +++ b/lib/spack/spack/build_systems/cmake.py @@ -2,23 +2,26 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - - import inspect import os import platform import re import sys -from typing import List +from typing import List, Tuple import six +import llnl.util.filesystem as fs from llnl.util.compat import Sequence -from llnl.util.filesystem import working_dir import spack.build_environment -from spack.directives import conflicts, depends_on, variant -from spack.package_base import InstallError, PackageBase, run_after +import spack.builder +import spack.package_base +import spack.util.path +from spack.directives import build_system, depends_on, variant +from spack.multimethod import when + +from ._checks import BaseBuilder, execute_build_time_tests # Regex to extract the primary generator from the CMake generator # string. @@ -34,56 +37,141 @@ def _extract_primary_generator(generator): return primary_generator -class CMakePackage(PackageBase): +class CMakePackage(spack.package_base.PackageBase): """Specialized class for packages built using CMake For more information on the CMake build system, see: https://cmake.org/cmake/help/latest/ + """ - This class provides three phases that can be overridden: + #: This attribute is used in UI queries that need to know the build + #: system base class + build_system_class = "CMakePackage" - 1. :py:meth:`~.CMakePackage.cmake` - 2. :py:meth:`~.CMakePackage.build` - 3. :py:meth:`~.CMakePackage.install` + #: Legacy buildsystem attribute used to deserialize and install old specs + legacy_buildsystem = "cmake" + + build_system("cmake") + + with when("build_system=cmake"): + # https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html + variant( + "build_type", + default="RelWithDebInfo", + description="CMake build type", + values=("Debug", "Release", "RelWithDebInfo", "MinSizeRel"), + ) + # CMAKE_INTERPROCEDURAL_OPTIMIZATION only exists for CMake >= 3.9 + # https://cmake.org/cmake/help/latest/variable/CMAKE_INTERPROCEDURAL_OPTIMIZATION.html + variant( + "ipo", + default=False, + when="^cmake@3.9:", + description="CMake interprocedural optimization", + ) + depends_on("cmake", type="build") + depends_on("ninja", type="build", when="platform=windows") + + def flags_to_build_system_args(self, flags): + """Return a list of all command line arguments to pass the specified + compiler flags to cmake. Note CMAKE does not have a cppflags option, + so cppflags will be added to cflags, cxxflags, and fflags to mimic the + behavior in other tools. + """ + # Has to be dynamic attribute due to caching + setattr(self, "cmake_flag_args", []) + + flag_string = "-DCMAKE_{0}_FLAGS={1}" + langs = {"C": "c", "CXX": "cxx", "Fortran": "f"} + + # Handle language compiler flags + for lang, pre in langs.items(): + flag = pre + "flags" + # cmake has no explicit cppflags support -> add it to all langs + lang_flags = " ".join(flags.get(flag, []) + flags.get("cppflags", [])) + if lang_flags: + self.cmake_flag_args.append(flag_string.format(lang, lang_flags)) + + # Cmake has different linker arguments for different build types. + # We specify for each of them. + if flags["ldflags"]: + ldflags = " ".join(flags["ldflags"]) + ld_string = "-DCMAKE_{0}_LINKER_FLAGS={1}" + # cmake has separate linker arguments for types of builds. + for type in ["EXE", "MODULE", "SHARED", "STATIC"]: + self.cmake_flag_args.append(ld_string.format(type, ldflags)) + + # CMake has libs options separated by language. Apply ours to each. + if flags["ldlibs"]: + libs_flags = " ".join(flags["ldlibs"]) + libs_string = "-DCMAKE_{0}_STANDARD_LIBRARIES={1}" + for lang in langs: + self.cmake_flag_args.append(libs_string.format(lang, libs_flags)) + + # Legacy methods (used by too many packages to change them, + # need to forward to the builder) + def define(self, *args, **kwargs): + return self.builder.define(*args, **kwargs) + + def define_from_variant(self, *args, **kwargs): + return self.builder.define_from_variant(*args, **kwargs) + + +@spack.builder.builder("cmake") +class CMakeBuilder(BaseBuilder): + """The cmake builder encodes the default way of building software with CMake. IT + has three phases that can be overridden: + + 1. :py:meth:`~.CMakeBuilder.cmake` + 2. :py:meth:`~.CMakeBuilder.build` + 3. :py:meth:`~.CMakeBuilder.install` They all have sensible defaults and for many packages the only thing - necessary will be to override :py:meth:`~.CMakePackage.cmake_args`. + necessary will be to override :py:meth:`~.CMakeBuilder.cmake_args`. + For a finer tuning you may also override: +-----------------------------------------------+--------------------+ | **Method** | **Purpose** | +===============================================+====================+ - | :py:meth:`~.CMakePackage.root_cmakelists_dir` | Location of the | + | :py:meth:`~.CMakeBuilder.root_cmakelists_dir` | Location of the | | | root CMakeLists.txt| +-----------------------------------------------+--------------------+ - | :py:meth:`~.CMakePackage.build_directory` | Directory where to | + | :py:meth:`~.CMakeBuilder.build_directory` | Directory where to | | | build the package | +-----------------------------------------------+--------------------+ - - The generator used by CMake can be specified by providing the - generator attribute. Per + The generator used by CMake can be specified by providing the ``generator`` + attribute. Per https://cmake.org/cmake/help/git-master/manual/cmake-generators.7.html, - the format is: [ - ]. The - full list of primary and secondary generators supported by CMake may - be found in the documentation for the version of CMake used; - however, at this time Spack supports only the primary generators - "Unix Makefiles" and "Ninja." Spack's CMake support is agnostic with - respect to primary generators. Spack will generate a runtime error - if the generator string does not follow the prescribed format, or if + the format is: [ - ]. + + The full list of primary and secondary generators supported by CMake may be found + in the documentation for the version of CMake used; however, at this time Spack + supports only the primary generators "Unix Makefiles" and "Ninja." Spack's CMake + support is agnostic with respect to primary generators. Spack will generate a + runtime error if the generator string does not follow the prescribed format, or if the primary generator is not supported. """ #: Phases of a CMake package - phases = ["cmake", "build", "install"] - #: This attribute is used in UI queries that need to know the build - #: system base class - build_system_class = "CMakePackage" + phases = ("cmake", "build", "install") - build_targets = [] # type: List[str] - install_targets = ["install"] + #: Names associated with package methods in the old build-system format + legacy_methods = ("cmake_args", "check") # type: Tuple[str, ...] - build_time_test_callbacks = ["check"] + #: Names associated with package attributes in the old build-system format + legacy_attributes = ( + "generator", + "build_targets", + "install_targets", + "build_time_test_callbacks", + "archive_files", + "root_cmakelists_dir", + "std_cmake_args", + "build_dirname", + "build_directory", + ) # type: Tuple[str, ...] #: The build system generator to use. #: @@ -93,27 +181,14 @@ class CMakePackage(PackageBase): #: #: See https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html #: for more information. + generator = "Ninja" if sys.platform == "win32" else "Unix Makefiles" - generator = "Unix Makefiles" - - if sys.platform == "win32": - generator = "Ninja" - depends_on("ninja") - - # https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html - variant( - "build_type", - default="RelWithDebInfo", - description="CMake build type", - values=("Debug", "Release", "RelWithDebInfo", "MinSizeRel"), - ) - - # https://cmake.org/cmake/help/latest/variable/CMAKE_INTERPROCEDURAL_OPTIMIZATION.html - variant("ipo", default=False, description="CMake interprocedural optimization") - # CMAKE_INTERPROCEDURAL_OPTIMIZATION only exists for CMake >= 3.9 - conflicts("+ipo", when="^cmake@:3.8", msg="+ipo is not supported by CMake < 3.9") - - depends_on("cmake", type="build") + #: Targets to be used during the build phase + build_targets = [] # type: List[str] + #: Targets to be used during the install phase + install_targets = ["install"] + #: Callback names for build-time test + build_time_test_callbacks = ["check"] @property def archive_files(self): @@ -126,40 +201,30 @@ def root_cmakelists_dir(self): This path is relative to the root of the extracted tarball, not to the ``build_directory``. Defaults to the current directory. - - :return: directory containing CMakeLists.txt """ - return self.stage.source_path + return self.pkg.stage.source_path @property def std_cmake_args(self): """Standard cmake arguments provided as a property for convenience of package writers - - :return: standard cmake arguments """ # standard CMake arguments - std_cmake_args = CMakePackage._std_args(self) - std_cmake_args += getattr(self, "cmake_flag_args", []) + std_cmake_args = CMakeBuilder.std_args(self.pkg, generator=self.generator) + std_cmake_args += getattr(self.pkg, "cmake_flag_args", []) return std_cmake_args @staticmethod - def _std_args(pkg): + def std_args(pkg, generator=None): """Computes the standard cmake arguments for a generic package""" - - try: - generator = pkg.generator - except AttributeError: - generator = CMakePackage.generator - - # Make sure a valid generator was chosen + generator = generator or "Unix Makefiles" valid_primary_generators = ["Unix Makefiles", "Ninja"] primary_generator = _extract_primary_generator(generator) if primary_generator not in valid_primary_generators: msg = "Invalid CMake generator: '{0}'\n".format(generator) msg += "CMakePackage currently supports the following " msg += "primary generators: '{0}'".format("', '".join(valid_primary_generators)) - raise InstallError(msg) + raise spack.package_base.InstallError(msg) try: build_type = pkg.spec.variants["build_type"].value @@ -171,7 +236,7 @@ def _std_args(pkg): except KeyError: ipo = False - define = CMakePackage.define + define = CMakeBuilder.define args = [ "-G", generator, @@ -251,7 +316,7 @@ def define_from_variant(self, cmake_var, variant=None): of ``cmake_var``. This utility function is similar to - :meth:`~spack.build_systems.autotools.AutotoolsPackage.with_or_without`. + :meth:`~spack.build_systems.autotools.AutotoolsBuilder.with_or_without`. Examples: @@ -291,122 +356,75 @@ def define_from_variant(self, cmake_var, variant=None): if variant is None: variant = cmake_var.lower() - if variant not in self.variants: - raise KeyError('"{0}" is not a variant of "{1}"'.format(variant, self.name)) + if variant not in self.pkg.variants: + raise KeyError('"{0}" is not a variant of "{1}"'.format(variant, self.pkg.name)) - if variant not in self.spec.variants: + if variant not in self.pkg.spec.variants: return "" - value = self.spec.variants[variant].value + value = self.pkg.spec.variants[variant].value if isinstance(value, (tuple, list)): # Sort multi-valued variants for reproducibility value = sorted(value) return self.define(cmake_var, value) - def flags_to_build_system_args(self, flags): - """Produces a list of all command line arguments to pass the specified - compiler flags to cmake. Note CMAKE does not have a cppflags option, - so cppflags will be added to cflags, cxxflags, and fflags to mimic the - behavior in other tools.""" - # Has to be dynamic attribute due to caching - setattr(self, "cmake_flag_args", []) - - flag_string = "-DCMAKE_{0}_FLAGS={1}" - langs = {"C": "c", "CXX": "cxx", "Fortran": "f"} - - # Handle language compiler flags - for lang, pre in langs.items(): - flag = pre + "flags" - # cmake has no explicit cppflags support -> add it to all langs - lang_flags = " ".join(flags.get(flag, []) + flags.get("cppflags", [])) - if lang_flags: - self.cmake_flag_args.append(flag_string.format(lang, lang_flags)) - - # Cmake has different linker arguments for different build types. - # We specify for each of them. - if flags["ldflags"]: - ldflags = " ".join(flags["ldflags"]) - ld_string = "-DCMAKE_{0}_LINKER_FLAGS={1}" - # cmake has separate linker arguments for types of builds. - for type in ["EXE", "MODULE", "SHARED", "STATIC"]: - self.cmake_flag_args.append(ld_string.format(type, ldflags)) - - # CMake has libs options separated by language. Apply ours to each. - if flags["ldlibs"]: - libs_flags = " ".join(flags["ldlibs"]) - libs_string = "-DCMAKE_{0}_STANDARD_LIBRARIES={1}" - for lang in langs: - self.cmake_flag_args.append(libs_string.format(lang, libs_flags)) - @property def build_dirname(self): - """Returns the directory name to use when building the package - - :return: name of the subdirectory for building the package - """ - return "spack-build-%s" % self.spec.dag_hash(7) + """Directory name to use when building the package.""" + return "spack-build-%s" % self.pkg.spec.dag_hash(7) @property def build_directory(self): - """Returns the directory to use when building the package - - :return: directory where to build the package - """ - return os.path.join(self.stage.path, self.build_dirname) + """Full-path to the directory to use when building the package.""" + return os.path.join(self.pkg.stage.path, self.build_dirname) def cmake_args(self): - """Produces a list containing all the arguments that must be passed to - cmake, except: + """List of all the arguments that must be passed to cmake, except: * CMAKE_INSTALL_PREFIX * CMAKE_BUILD_TYPE * BUILD_TESTING which will be set automatically. - - :return: list of arguments for cmake """ return [] - def cmake(self, spec, prefix): + def cmake(self, pkg, spec, prefix): """Runs ``cmake`` in the build directory""" options = self.std_cmake_args options += self.cmake_args() options.append(os.path.abspath(self.root_cmakelists_dir)) - with working_dir(self.build_directory, create=True): - inspect.getmodule(self).cmake(*options) + with fs.working_dir(self.build_directory, create=True): + inspect.getmodule(self.pkg).cmake(*options) - def build(self, spec, prefix): + def build(self, pkg, spec, prefix): """Make the build targets""" - with working_dir(self.build_directory): + with fs.working_dir(self.build_directory): if self.generator == "Unix Makefiles": - inspect.getmodule(self).make(*self.build_targets) + inspect.getmodule(self.pkg).make(*self.build_targets) elif self.generator == "Ninja": self.build_targets.append("-v") - inspect.getmodule(self).ninja(*self.build_targets) + inspect.getmodule(self.pkg).ninja(*self.build_targets) - def install(self, spec, prefix): + def install(self, pkg, spec, prefix): """Make the install targets""" - with working_dir(self.build_directory): + with fs.working_dir(self.build_directory): if self.generator == "Unix Makefiles": - inspect.getmodule(self).make(*self.install_targets) + inspect.getmodule(self.pkg).make(*self.install_targets) elif self.generator == "Ninja": - inspect.getmodule(self).ninja(*self.install_targets) + inspect.getmodule(self.pkg).ninja(*self.install_targets) - run_after("build")(PackageBase._run_default_build_time_test_callbacks) + spack.builder.run_after("build")(execute_build_time_tests) def check(self): - """Searches the CMake-generated Makefile for the target ``test`` - and runs it if found. + """Search the CMake-generated files for the targets ``test`` and ``check``, + and runs them if found. """ - with working_dir(self.build_directory): + with fs.working_dir(self.build_directory): if self.generator == "Unix Makefiles": - self._if_make_target_execute("test", jobs_env="CTEST_PARALLEL_LEVEL") - self._if_make_target_execute("check") + self.pkg._if_make_target_execute("test", jobs_env="CTEST_PARALLEL_LEVEL") + self.pkg._if_make_target_execute("check") elif self.generator == "Ninja": - self._if_ninja_target_execute("test", jobs_env="CTEST_PARALLEL_LEVEL") - self._if_ninja_target_execute("check") - - # Check that self.prefix is there after installation - run_after("install")(PackageBase.sanity_check_prefix) + self.pkg._if_ninja_target_execute("test", jobs_env="CTEST_PARALLEL_LEVEL") + self.pkg._if_ninja_target_execute("check") diff --git a/lib/spack/spack/build_systems/generic.py b/lib/spack/spack/build_systems/generic.py new file mode 100644 index 00000000000..628af6f2d41 --- /dev/null +++ b/lib/spack/spack/build_systems/generic.py @@ -0,0 +1,44 @@ +# 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 typing import Tuple + +import spack.builder +import spack.directives +import spack.package_base + +from ._checks import BaseBuilder, apply_macos_rpath_fixups + + +class Package(spack.package_base.PackageBase): + """General purpose class with a single ``install`` phase that needs to be + coded by packagers. + """ + + #: This attribute is used in UI queries that require to know which + #: build-system class we are using + build_system_class = "Package" + #: Legacy buildsystem attribute used to deserialize and install old specs + legacy_buildsystem = "generic" + + spack.directives.build_system("generic") + + +@spack.builder.builder("generic") +class GenericBuilder(BaseBuilder): + """A builder for a generic build system, that require packagers + to implement an "install" phase. + """ + + #: A generic package has only the "install" phase + phases = ("install",) + + #: Names associated with package methods in the old build-system format + legacy_methods = () # type: Tuple[str, ...] + + #: Names associated with package attributes in the old build-system format + legacy_attributes = ("archive_files",) # type: Tuple[str, ...] + + # On macOS, force rpaths for shared library IDs and remove duplicate rpaths + spack.builder.run_after("install", when="platform=darwin")(apply_macos_rpath_fixups) diff --git a/lib/spack/spack/build_systems/intel.py b/lib/spack/spack/build_systems/intel.py index 133b5030dea..4abed70f21d 100644 --- a/lib/spack/spack/build_systems/intel.py +++ b/lib/spack/spack/build_systems/intel.py @@ -2,8 +2,6 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - - import glob import inspect import os @@ -26,12 +24,14 @@ import spack.error from spack.build_environment import dso_suffix -from spack.package_base import InstallError, PackageBase, run_after +from spack.package_base import InstallError from spack.util.environment import EnvironmentModifications from spack.util.executable import Executable from spack.util.prefix import Prefix from spack.version import Version, ver +from .generic import Package + # A couple of utility functions that might be useful in general. If so, they # should really be defined elsewhere, unless deemed heretical. # (Or na"ive on my part). @@ -86,7 +86,7 @@ def _expand_fields(s): return s -class IntelPackage(PackageBase): +class IntelPackage(Package): """Specialized class for licensed Intel software. This class provides two phases that can be overridden: @@ -99,9 +99,6 @@ class IntelPackage(PackageBase): to set the appropriate environment variables. """ - #: Phases of an Intel package - phases = ["configure", "install"] - #: This attribute is used in UI queries that need to know the build #: system base class build_system_class = "IntelPackage" @@ -1184,12 +1181,13 @@ def _determine_license_type(self): debug_print(license_type) return license_type - def configure(self, spec, prefix): + @spack.builder.run_before("install") + def configure(self): """Generates the silent.cfg file to pass to installer.sh. See https://software.intel.com/en-us/articles/configuration-file-format """ - + prefix = self.prefix # Both tokens AND values of the configuration file are validated during # the run of the underlying binary installer. Any unknown token or # unacceptable value will cause that installer to fail. Notably, this @@ -1270,7 +1268,7 @@ def install(self, spec, prefix): for f in glob.glob("%s/intel*log" % tmpdir): install(f, dst) - @run_after("install") + @spack.builder.run_after("install") def validate_install(self): # Sometimes the installer exits with an error but doesn't pass a # non-zero exit code to spack. Check for the existence of a 'bin' @@ -1278,7 +1276,7 @@ def validate_install(self): if not os.path.exists(self.prefix.bin): raise InstallError("The installer has failed to install anything.") - @run_after("install") + @spack.builder.run_after("install") def configure_rpath(self): if "+rpath" not in self.spec: return @@ -1296,7 +1294,7 @@ def configure_rpath(self): with open(compiler_cfg, "w") as fh: fh.write("-Xlinker -rpath={0}\n".format(compilers_lib_dir)) - @run_after("install") + @spack.builder.run_after("install") def configure_auto_dispatch(self): if self._has_compilers: if "auto_dispatch=none" in self.spec: @@ -1320,7 +1318,7 @@ def configure_auto_dispatch(self): with open(compiler_cfg, "a") as fh: fh.write("-ax{0}\n".format(",".join(ad))) - @run_after("install") + @spack.builder.run_after("install") def filter_compiler_wrappers(self): if ("+mpi" in self.spec or self.provides("mpi")) and "~newdtags" in self.spec: bin_dir = self.component_bin_dir("mpi") @@ -1328,7 +1326,7 @@ def filter_compiler_wrappers(self): f = os.path.join(bin_dir, f) filter_file("-Xlinker --enable-new-dtags", " ", f, string=True) - @run_after("install") + @spack.builder.run_after("install") def uninstall_ism(self): # The "Intel(R) Software Improvement Program" [ahem] gets installed, # apparently regardless of PHONEHOME_SEND_USAGE_DATA. @@ -1360,7 +1358,7 @@ def base_lib_dir(self): debug_print(d) return d - @run_after("install") + @spack.builder.run_after("install") def modify_LLVMgold_rpath(self): """Add libimf.so and other required libraries to the RUNPATH of LLVMgold.so. @@ -1391,6 +1389,3 @@ def modify_LLVMgold_rpath(self): ] ) patchelf("--set-rpath", rpath, lib) - - # Check that self.prefix is there after installation - run_after("install")(PackageBase.sanity_check_prefix) diff --git a/lib/spack/spack/build_systems/lua.py b/lib/spack/spack/build_systems/lua.py index c0d4321097c..48fa1068815 100644 --- a/lib/spack/spack/build_systems/lua.py +++ b/lib/spack/spack/build_systems/lua.py @@ -2,59 +2,79 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - - import os from llnl.util.filesystem import find -from spack.directives import depends_on, extends +import spack.builder +import spack.package_base +import spack.util.executable +from spack.directives import build_system, depends_on, extends from spack.multimethod import when -from spack.package_base import PackageBase -from spack.util.executable import Executable -class LuaPackage(PackageBase): +class LuaPackage(spack.package_base.PackageBase): """Specialized class for lua packages""" - phases = ["unpack", "generate_luarocks_config", "preprocess", "install"] #: This attribute is used in UI queries that need to know the build #: system base class build_system_class = "LuaPackage" list_depth = 1 # LuaRocks requires at least one level of spidering to find versions - depends_on("lua-lang") - extends("lua", when="^lua") - with when("^lua-luajit"): - extends("lua-luajit") - depends_on("luajit") - depends_on("lua-luajit+lualinks") - with when("^lua-luajit-openresty"): - extends("lua-luajit-openresty") - depends_on("luajit") - depends_on("lua-luajit-openresty+lualinks") - def unpack(self, spec, prefix): - if os.path.splitext(self.stage.archive_file)[1] == ".rock": - directory = self.luarocks("unpack", self.stage.archive_file, output=str) + build_system("lua") + + with when("build_system=lua"): + depends_on("lua-lang") + extends("lua", when="^lua") + with when("^lua-luajit"): + extends("lua-luajit") + depends_on("luajit") + depends_on("lua-luajit+lualinks") + with when("^lua-luajit-openresty"): + extends("lua-luajit-openresty") + depends_on("luajit") + depends_on("lua-luajit-openresty+lualinks") + + @property + def lua(self): + return spack.util.executable.Executable(self.spec["lua-lang"].prefix.bin.lua) + + @property + def luarocks(self): + lr = spack.util.executable.Executable(self.spec["lua-lang"].prefix.bin.luarocks) + return lr + + +@spack.builder.builder("lua") +class LuaBuilder(spack.builder.Builder): + phases = ("unpack", "generate_luarocks_config", "preprocess", "install") + + #: Names associated with package methods in the old build-system format + legacy_methods = ("luarocks_args",) + + #: Names associated with package attributes in the old build-system format + legacy_attributes = () + + def unpack(self, pkg, spec, prefix): + if os.path.splitext(pkg.stage.archive_file)[1] == ".rock": + directory = pkg.luarocks("unpack", pkg.stage.archive_file, output=str) dirlines = directory.split("\n") # TODO: figure out how to scope this better os.chdir(dirlines[2]) - def _generate_tree_line(self, name, prefix): + @staticmethod + def _generate_tree_line(name, prefix): return """{{ name = "{name}", root = "{prefix}" }};""".format( name=name, prefix=prefix, ) - def _luarocks_config_path(self): - return os.path.join(self.stage.source_path, "spack_luarocks.lua") - - def generate_luarocks_config(self, spec, prefix): - spec = self.spec + def generate_luarocks_config(self, pkg, spec, prefix): + spec = self.pkg.spec table_entries = [] for d in spec.traverse(deptypes=("build", "run"), deptype_query="run"): - if d.package.extends(self.extendee_spec): + if d.package.extends(self.pkg.extendee_spec): table_entries.append(self._generate_tree_line(d.name, d.prefix)) path = self._luarocks_config_path() @@ -71,30 +91,24 @@ def generate_luarocks_config(self, spec, prefix): ) return path - def setup_build_environment(self, env): - env.set("LUAROCKS_CONFIG", self._luarocks_config_path()) - - def preprocess(self, spec, prefix): + def preprocess(self, pkg, spec, prefix): """Override this to preprocess source before building with luarocks""" pass - @property - def lua(self): - return Executable(self.spec["lua-lang"].prefix.bin.lua) - - @property - def luarocks(self): - lr = Executable(self.spec["lua-lang"].prefix.bin.luarocks) - return lr - def luarocks_args(self): return [] - def install(self, spec, prefix): + def install(self, pkg, spec, prefix): rock = "." specs = find(".", "*.rockspec", recursive=False) if specs: rock = specs[0] rocks_args = self.luarocks_args() rocks_args.append(rock) - self.luarocks("--tree=" + prefix, "make", *rocks_args) + self.pkg.luarocks("--tree=" + prefix, "make", *rocks_args) + + def _luarocks_config_path(self): + return os.path.join(self.pkg.stage.source_path, "spack_luarocks.lua") + + def setup_build_environment(self, env): + env.set("LUAROCKS_CONFIG", self._luarocks_config_path()) diff --git a/lib/spack/spack/build_systems/makefile.py b/lib/spack/spack/build_systems/makefile.py index e2bb8c0c26c..b826144258b 100644 --- a/lib/spack/spack/build_systems/makefile.py +++ b/lib/spack/spack/build_systems/makefile.py @@ -2,62 +2,85 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - - import inspect from typing import List # novm -import llnl.util.tty as tty -from llnl.util.filesystem import working_dir +import llnl.util.filesystem as fs -from spack.directives import conflicts -from spack.package_base import PackageBase, run_after +import spack.builder +import spack.package_base +from spack.directives import build_system, conflicts + +from ._checks import ( + BaseBuilder, + apply_macos_rpath_fixups, + execute_build_time_tests, + execute_install_time_tests, +) -class MakefilePackage(PackageBase): - """Specialized class for packages that are built using editable Makefiles +class MakefilePackage(spack.package_base.PackageBase): + """Specialized class for packages built using a Makefiles.""" - This class provides three phases that can be overridden: + #: This attribute is used in UI queries that need to know the build + #: system base class + build_system_class = "MakefilePackage" + #: Legacy buildsystem attribute used to deserialize and install old specs + legacy_buildsystem = "makefile" - 1. :py:meth:`~.MakefilePackage.edit` - 2. :py:meth:`~.MakefilePackage.build` - 3. :py:meth:`~.MakefilePackage.install` + build_system("makefile") + conflicts("platform=windows", when="build_system=makefile") + + +@spack.builder.builder("makefile") +class MakefileBuilder(BaseBuilder): + """The Makefile builder encodes the most common way of building software with + Makefiles. It has three phases that can be overridden, if need be: + + 1. :py:meth:`~.MakefileBuilder.edit` + 2. :py:meth:`~.MakefileBuilder.build` + 3. :py:meth:`~.MakefileBuilder.install` + + It is usually necessary to override the :py:meth:`~.MakefileBuilder.edit` + phase (which is by default a no-op), while the other two have sensible defaults. - It is usually necessary to override the :py:meth:`~.MakefilePackage.edit` - phase, while :py:meth:`~.MakefilePackage.build` and - :py:meth:`~.MakefilePackage.install` have sensible defaults. For a finer tuning you may override: +-----------------------------------------------+--------------------+ | **Method** | **Purpose** | +===============================================+====================+ - | :py:attr:`~.MakefilePackage.build_targets` | Specify ``make`` | + | :py:attr:`~.MakefileBuilder.build_targets` | Specify ``make`` | | | targets for the | | | build phase | +-----------------------------------------------+--------------------+ - | :py:attr:`~.MakefilePackage.install_targets` | Specify ``make`` | + | :py:attr:`~.MakefileBuilder.install_targets` | Specify ``make`` | | | targets for the | | | install phase | +-----------------------------------------------+--------------------+ - | :py:meth:`~.MakefilePackage.build_directory` | Directory where the| + | :py:meth:`~.MakefileBuilder.build_directory` | Directory where the| | | Makefile is located| +-----------------------------------------------+--------------------+ """ - #: Phases of a package that is built with an hand-written Makefile - phases = ["edit", "build", "install"] - #: This attribute is used in UI queries that need to know the build - #: system base class - build_system_class = "MakefilePackage" + phases = ("edit", "build", "install") - #: Targets for ``make`` during the :py:meth:`~.MakefilePackage.build` - #: phase + #: Names associated with package methods in the old build-system format + legacy_methods = ("check", "installcheck") + + #: Names associated with package attributes in the old build-system format + legacy_attributes = ( + "build_targets", + "install_targets", + "build_time_test_callbacks", + "install_time_test_callbacks", + "build_directory", + ) + + #: Targets for ``make`` during the :py:meth:`~.MakefileBuilder.build` phase build_targets = [] # type: List[str] - #: Targets for ``make`` during the :py:meth:`~.MakefilePackage.install` - #: phase + #: Targets for ``make`` during the :py:meth:`~.MakefileBuilder.install` phase install_targets = ["install"] - conflicts("platform=windows") #: Callback names for build-time test build_time_test_callbacks = ["check"] @@ -66,53 +89,39 @@ class MakefilePackage(PackageBase): @property def build_directory(self): - """Returns the directory containing the main Makefile + """Return the directory containing the main Makefile.""" + return self.pkg.stage.source_path - :return: build directory - """ - return self.stage.source_path + def edit(self, pkg, spec, prefix): + """Edit the Makefile before calling make. The default is a no-op.""" + pass - def edit(self, spec, prefix): - """Edits the Makefile before calling make. This phase cannot - be defaulted. - """ - tty.msg("Using default implementation: skipping edit phase.") + def build(self, pkg, spec, prefix): + """Run "make" on the build targets specified by the builder.""" + with fs.working_dir(self.build_directory): + inspect.getmodule(self.pkg).make(*self.build_targets) - def build(self, spec, prefix): - """Calls make, passing :py:attr:`~.MakefilePackage.build_targets` - as targets. - """ - with working_dir(self.build_directory): - inspect.getmodule(self).make(*self.build_targets) + def install(self, pkg, spec, prefix): + """Run "make" on the install targets specified by the builder.""" + with fs.working_dir(self.build_directory): + inspect.getmodule(self.pkg).make(*self.install_targets) - def install(self, spec, prefix): - """Calls make, passing :py:attr:`~.MakefilePackage.install_targets` - as targets. - """ - with working_dir(self.build_directory): - inspect.getmodule(self).make(*self.install_targets) - - run_after("build")(PackageBase._run_default_build_time_test_callbacks) + spack.builder.run_after("build")(execute_build_time_tests) def check(self): - """Searches the Makefile for targets ``test`` and ``check`` - and runs them if found. - """ - with working_dir(self.build_directory): - self._if_make_target_execute("test") - self._if_make_target_execute("check") + """Run "make" on the ``test`` and ``check`` targets, if found.""" + with fs.working_dir(self.build_directory): + self.pkg._if_make_target_execute("test") + self.pkg._if_make_target_execute("check") - run_after("install")(PackageBase._run_default_install_time_test_callbacks) + spack.builder.run_after("install")(execute_install_time_tests) def installcheck(self): """Searches the Makefile for an ``installcheck`` target and runs it if found. """ - with working_dir(self.build_directory): - self._if_make_target_execute("installcheck") - - # Check that self.prefix is there after installation - run_after("install")(PackageBase.sanity_check_prefix) + with fs.working_dir(self.build_directory): + self.pkg._if_make_target_execute("installcheck") # On macOS, force rpaths for shared library IDs and remove duplicate rpaths - run_after("install")(PackageBase.apply_macos_rpath_fixups) + spack.builder.run_after("install", when="platform=darwin")(apply_macos_rpath_fixups) diff --git a/lib/spack/spack/build_systems/maven.py b/lib/spack/spack/build_systems/maven.py index 1ff1882e134..66680b5b6cf 100644 --- a/lib/spack/spack/build_systems/maven.py +++ b/lib/spack/spack/build_systems/maven.py @@ -2,60 +2,73 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import llnl.util.filesystem as fs - -from llnl.util.filesystem import install_tree, working_dir - -from spack.directives import depends_on -from spack.package_base import PackageBase, run_after +import spack.builder +import spack.package_base +from spack.directives import build_system, depends_on +from spack.multimethod import when from spack.util.executable import which +from ._checks import BaseBuilder -class MavenPackage(PackageBase): + +class MavenPackage(spack.package_base.PackageBase): """Specialized class for packages that are built using the Maven build system. See https://maven.apache.org/index.html for more information. - - This class provides the following phases that can be overridden: - - * build - * install """ - # Default phases - phases = ["build", "install"] - # To be used in UI queries that require to know which # build-system class we are using build_system_class = "MavenPackage" - depends_on("java", type=("build", "run")) - depends_on("maven", type="build") + #: Legacy buildsystem attribute used to deserialize and install old specs + legacy_buildsystem = "maven" + + build_system("maven") + + with when("build_system=maven"): + depends_on("java", type=("build", "run")) + depends_on("maven", type="build") + + +@spack.builder.builder("maven") +class MavenBuilder(BaseBuilder): + """The Maven builder encodes the default way to build software with Maven. + It has two phases that can be overridden, if need be: + + 1. :py:meth:`~.MavenBuilder.build` + 2. :py:meth:`~.MavenBuilder.install` + """ + + phases = ("build", "install") + + #: Names associated with package methods in the old build-system format + legacy_methods = ("build_args",) + + #: Names associated with package attributes in the old build-system format + legacy_attributes = ("build_directory",) @property def build_directory(self): """The directory containing the ``pom.xml`` file.""" - return self.stage.source_path + return self.pkg.stage.source_path def build_args(self): """List of args to pass to build phase.""" return [] - def build(self, spec, prefix): + def build(self, pkg, spec, prefix): """Compile code and package into a JAR file.""" - - with working_dir(self.build_directory): + with fs.working_dir(self.build_directory): mvn = which("mvn") - if self.run_tests: + if self.pkg.run_tests: mvn("verify", *self.build_args()) else: mvn("package", "-DskipTests", *self.build_args()) - def install(self, spec, prefix): + def install(self, pkg, spec, prefix): """Copy to installation prefix.""" - - with working_dir(self.build_directory): - install_tree(".", prefix) - - # Check that self.prefix is there after installation - run_after("install")(PackageBase.sanity_check_prefix) + with fs.working_dir(self.build_directory): + fs.install_tree(".", prefix) diff --git a/lib/spack/spack/build_systems/meson.py b/lib/spack/spack/build_systems/meson.py index cafd613808f..6ab760cfb98 100644 --- a/lib/spack/spack/build_systems/meson.py +++ b/lib/spack/spack/build_systems/meson.py @@ -2,76 +2,104 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - - import inspect import os from typing import List # novm -from llnl.util.filesystem import working_dir +import llnl.util.filesystem as fs -from spack.directives import depends_on, variant -from spack.package_base import PackageBase, run_after +import spack.builder +import spack.package_base +from spack.directives import build_system, depends_on, variant +from spack.multimethod import when + +from ._checks import BaseBuilder, execute_build_time_tests -class MesonPackage(PackageBase): - """Specialized class for packages built using Meson +class MesonPackage(spack.package_base.PackageBase): + """Specialized class for packages built using Meson. For more information + on the Meson build system, see https://mesonbuild.com/ + """ - For more information on the Meson build system, see: - https://mesonbuild.com/ + #: This attribute is used in UI queries that need to know the build + #: system base class + build_system_class = "MesonPackage" - This class provides three phases that can be overridden: + #: Legacy buildsystem attribute used to deserialize and install old specs + legacy_buildsystem = "meson" - 1. :py:meth:`~.MesonPackage.meson` - 2. :py:meth:`~.MesonPackage.build` - 3. :py:meth:`~.MesonPackage.install` + build_system("meson") + + with when("build_system=meson"): + variant( + "buildtype", + default="debugoptimized", + description="Meson build type", + values=("plain", "debug", "debugoptimized", "release", "minsize"), + ) + variant( + "default_library", + default="shared", + values=("shared", "static"), + multi=True, + description="Build shared libs, static libs or both", + ) + variant("strip", default=False, description="Strip targets on install") + depends_on("meson", type="build") + depends_on("ninja", type="build") + + def flags_to_build_system_args(self, flags): + """Produces a list of all command line arguments to pass the specified + compiler flags to meson.""" + # Has to be dynamic attribute due to caching + setattr(self, "meson_flag_args", []) + + +@spack.builder.builder("meson") +class MesonBuilder(BaseBuilder): + """The Meson builder encodes the default way to build software with Meson. + The builder has three phases that can be overridden, if need be: + + 1. :py:meth:`~.MesonBuilder.meson` + 2. :py:meth:`~.MesonBuilder.build` + 3. :py:meth:`~.MesonBuilder.install` They all have sensible defaults and for many packages the only thing - necessary will be to override :py:meth:`~.MesonPackage.meson_args`. + necessary will be to override :py:meth:`~.MesonBuilder.meson_args`. + For a finer tuning you may also override: +-----------------------------------------------+--------------------+ | **Method** | **Purpose** | +===============================================+====================+ - | :py:meth:`~.MesonPackage.root_mesonlists_dir` | Location of the | + | :py:meth:`~.MesonBuilder.root_mesonlists_dir` | Location of the | | | root MesonLists.txt| +-----------------------------------------------+--------------------+ - | :py:meth:`~.MesonPackage.build_directory` | Directory where to | + | :py:meth:`~.MesonBuilder.build_directory` | Directory where to | | | build the package | +-----------------------------------------------+--------------------+ - - """ - #: Phases of a Meson package - phases = ["meson", "build", "install"] - #: This attribute is used in UI queries that need to know the build - #: system base class - build_system_class = "MesonPackage" + phases = ("meson", "build", "install") + + #: Names associated with package methods in the old build-system format + legacy_methods = ("meson_args", "check") + + #: Names associated with package attributes in the old build-system format + legacy_attributes = ( + "build_targets", + "install_targets", + "build_time_test_callbacks", + "root_mesonlists_dir", + "std_meson_args", + "build_directory", + ) build_targets = [] # type: List[str] install_targets = ["install"] build_time_test_callbacks = ["check"] - variant( - "buildtype", - default="debugoptimized", - description="Meson build type", - values=("plain", "debug", "debugoptimized", "release", "minsize"), - ) - variant( - "default_library", - default="shared", - values=("shared", "static"), - multi=True, - description="Build shared libs, static libs or both", - ) - variant("strip", default=False, description="Strip targets on install") - - depends_on("meson", type="build") - depends_on("ninja", type="build") - @property def archive_files(self): """Files to archive for packages based on Meson""" @@ -79,31 +107,26 @@ def archive_files(self): @property def root_mesonlists_dir(self): - """The relative path to the directory containing meson.build + """Relative path to the directory containing meson.build This path is relative to the root of the extracted tarball, not to the ``build_directory``. Defaults to the current directory. - - :return: directory containing meson.build """ - return self.stage.source_path + return self.pkg.stage.source_path @property def std_meson_args(self): - """Standard meson arguments provided as a property for - convenience of package writers - - :return: standard meson arguments + """Standard meson arguments provided as a property for convenience + of package writers. """ # standard Meson arguments - std_meson_args = MesonPackage._std_args(self) + std_meson_args = MesonBuilder.std_args(self.pkg) std_meson_args += getattr(self, "meson_flag_args", []) return std_meson_args @staticmethod - def _std_args(pkg): - """Computes the standard meson arguments for a generic package""" - + def std_args(pkg): + """Standard meson arguments for a generic package.""" try: build_type = pkg.spec.variants["buildtype"].value except KeyError: @@ -132,31 +155,18 @@ def _std_args(pkg): return args - def flags_to_build_system_args(self, flags): - """Produces a list of all command line arguments to pass the specified - compiler flags to meson.""" - # Has to be dynamic attribute due to caching - setattr(self, "meson_flag_args", []) - @property def build_dirname(self): - """Returns the directory name to use when building the package - - :return: name of the subdirectory for building the package - """ - return "spack-build-%s" % self.spec.dag_hash(7) + """Returns the directory name to use when building the package.""" + return "spack-build-{}".format(self.spec.dag_hash(7)) @property def build_directory(self): - """Returns the directory to use when building the package - - :return: directory where to build the package - """ - return os.path.join(self.stage.path, self.build_dirname) + """Directory to use when building the package.""" + return os.path.join(self.pkg.stage.path, self.build_dirname) def meson_args(self): - """Produces a list containing all the arguments that must be passed to - meson, except: + """List of arguments that must be passed to meson, except: * ``--prefix`` * ``--libdir`` @@ -165,40 +175,33 @@ def meson_args(self): * ``--default_library`` which will be set automatically. - - :return: list of arguments for meson """ return [] - def meson(self, spec, prefix): - """Runs ``meson`` in the build directory""" + def meson(self, pkg, spec, prefix): + """Run ``meson`` in the build directory""" options = [os.path.abspath(self.root_mesonlists_dir)] options += self.std_meson_args options += self.meson_args() - with working_dir(self.build_directory, create=True): - inspect.getmodule(self).meson(*options) + with fs.working_dir(self.build_directory, create=True): + inspect.getmodule(self.pkg).meson(*options) - def build(self, spec, prefix): + def build(self, pkg, spec, prefix): """Make the build targets""" options = ["-v"] options += self.build_targets - with working_dir(self.build_directory): - inspect.getmodule(self).ninja(*options) + with fs.working_dir(self.build_directory): + inspect.getmodule(self.pkg).ninja(*options) - def install(self, spec, prefix): + def install(self, pkg, spec, prefix): """Make the install targets""" - with working_dir(self.build_directory): - inspect.getmodule(self).ninja(*self.install_targets) + with fs.working_dir(self.build_directory): + inspect.getmodule(self.pkg).ninja(*self.install_targets) - run_after("build")(PackageBase._run_default_build_time_test_callbacks) + spack.builder.run_after("build")(execute_build_time_tests) def check(self): - """Searches the Meson-generated file for the target ``test`` - and runs it if found. - """ - with working_dir(self.build_directory): + """Search Meson-generated files for the target ``test`` and run it if found.""" + with fs.working_dir(self.build_directory): self._if_ninja_target_execute("test") self._if_ninja_target_execute("check") - - # Check that self.prefix is there after installation - run_after("install")(PackageBase.sanity_check_prefix) diff --git a/lib/spack/spack/build_systems/nmake.py b/lib/spack/spack/build_systems/nmake.py new file mode 100644 index 00000000000..bf368951604 --- /dev/null +++ b/lib/spack/spack/build_systems/nmake.py @@ -0,0 +1,102 @@ +# 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) +import inspect +from typing import List # novm + +import llnl.util.filesystem as fs + +import spack.builder +import spack.package_base +from spack.directives import build_system, conflicts + +from ._checks import BaseBuilder + + +class NMakePackage(spack.package_base.PackageBase): + """Specialized class for packages built using a Makefiles.""" + + #: This attribute is used in UI queries that need to know the build + #: system base class + build_system_class = "NmakePackage" + + build_system("nmake") + conflicts("platform=linux", when="build_system=nmake") + conflicts("platform=darwin", when="build_system=nmake") + conflicts("platform=cray", when="build_system=nmake") + + +@spack.builder.builder("nmake") +class NMakeBuilder(BaseBuilder): + """The NMake builder encodes the most common way of building software with + NMake on Windows. It has three phases that can be overridden, if need be: + + 1. :py:meth:`~.NMakeBuilder.edit` + 2. :py:meth:`~.NMakeBuilder.build` + 3. :py:meth:`~.NMakeBuilder.install` + + It is usually necessary to override the :py:meth:`~.NMakeBuilder.edit` + phase (which is by default a no-op), while the other two have sensible defaults. + + For a finer tuning you may override: + + +--------------------------------------------+--------------------+ + | **Method** | **Purpose** | + +============================================+====================+ + | :py:attr:`~.NMakeBuilder.build_targets` | Specify ``nmake`` | + | | targets for the | + | | build phase | + +--------------------------------------------+--------------------+ + | :py:attr:`~.NMakeBuilder.install_targets` | Specify ``nmake`` | + | | targets for the | + | | install phase | + +--------------------------------------------+--------------------+ + | :py:meth:`~.NMakeBuilder.build_directory` | Directory where the| + | | Makefile is located| + +--------------------------------------------+--------------------+ + """ + + phases = ("edit", "build", "install") + + #: Names associated with package methods in the old build-system format + legacy_methods = ("check", "installcheck") + + #: Names associated with package attributes in the old build-system format + legacy_attributes = ( + "build_targets", + "install_targets", + "build_time_test_callbacks", + "install_time_test_callbacks", + "build_directory", + ) + + #: Targets for ``make`` during the :py:meth:`~.NMakeBuilder.build` phase + build_targets = [] # type: List[str] + #: Targets for ``make`` during the :py:meth:`~.NMakeBuilder.install` phase + install_targets = ["install"] + + #: Callback names for build-time test + build_time_test_callbacks = ["check"] + + #: Callback names for install-time test + install_time_test_callbacks = ["installcheck"] + + @property + def build_directory(self): + """Return the directory containing the main Makefile.""" + return self.pkg.stage.source_path + + def edit(self, pkg, spec, prefix): + """Edit the Makefile before calling make. The default is a no-op.""" + pass + + def build(self, pkg, spec, prefix): + """Run "make" on the build targets specified by the builder.""" + with fs.working_dir(self.build_directory): + inspect.getmodule(self.pkg).nmake(*self.build_targets) + + def install(self, pkg, spec, prefix): + """Run "make" on the install targets specified by the builder.""" + with fs.working_dir(self.build_directory): + inspect.getmodule(self.pkg).nmake(*self.install_targets) diff --git a/lib/spack/spack/build_systems/octave.py b/lib/spack/spack/build_systems/octave.py index 9916c319b0b..5b2456f098b 100644 --- a/lib/spack/spack/build_systems/octave.py +++ b/lib/spack/spack/build_systems/octave.py @@ -2,51 +2,62 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - import inspect -from spack.directives import extends -from spack.package_base import PackageBase, run_after +import spack.builder +import spack.package_base +from spack.directives import build_system, extends +from spack.multimethod import when + +from ._checks import BaseBuilder -class OctavePackage(PackageBase): +class OctavePackage(spack.package_base.PackageBase): """Specialized class for Octave packages. See https://www.gnu.org/software/octave/doc/v4.2.0/Installing-and-Removing-Packages.html for more information. - - This class provides the following phases that can be overridden: - - 1. :py:meth:`~.OctavePackage.install` - """ - # Default phases - phases = ["install"] - # To be used in UI queries that require to know which # build-system class we are using build_system_class = "OctavePackage" + #: Legacy buildsystem attribute used to deserialize and install old specs + legacy_buildsystem = "octave" - extends("octave") + build_system("octave") + + with when("build_system=octave"): + extends("octave") + + +@spack.builder.builder("octave") +class OctaveBuilder(BaseBuilder): + """The octave builder provides the following phases that can be overridden: + + 1. :py:meth:`~.OctaveBuilder.install` + """ + + phases = ("install",) + + #: Names associated with package methods in the old build-system format + legacy_methods = () + + #: Names associated with package attributes in the old build-system format + legacy_attributes = () + + def install(self, pkg, spec, prefix): + """Install the package from the archive file""" + inspect.getmodule(self.pkg).octave( + "--quiet", + "--norc", + "--built-in-docstrings-file=/dev/null", + "--texi-macros-file=/dev/null", + "--eval", + "pkg prefix %s; pkg install %s" % (prefix, self.pkg.stage.archive_file), + ) def setup_build_environment(self, env): # octave does not like those environment variables to be set: env.unset("CC") env.unset("CXX") env.unset("FC") - - def install(self, spec, prefix): - """Install the package from the archive file""" - inspect.getmodule(self).octave( - "--quiet", - "--norc", - "--built-in-docstrings-file=/dev/null", - "--texi-macros-file=/dev/null", - "--eval", - "pkg prefix %s; pkg install %s" % (prefix, self.stage.archive_file), - ) - - # Testing - - # Check that self.prefix is there after installation - run_after("install")(PackageBase.sanity_check_prefix) diff --git a/lib/spack/spack/build_systems/oneapi.py b/lib/spack/spack/build_systems/oneapi.py index 669c66fe8fc..1cb79b99015 100644 --- a/lib/spack/spack/build_systems/oneapi.py +++ b/lib/spack/spack/build_systems/oneapi.py @@ -2,11 +2,7 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - -"""Common utilities for managing intel oneapi packages. - -""" - +"""Common utilities for managing intel oneapi packages.""" import getpass import platform import shutil @@ -14,18 +10,17 @@ from llnl.util.filesystem import find_headers, find_libraries, join_path -from spack.package_base import Package from spack.util.environment import EnvironmentModifications from spack.util.executable import Executable +from .generic import Package + class IntelOneApiPackage(Package): """Base class for Intel oneAPI packages.""" homepage = "https://software.intel.com/oneapi" - phases = ["install"] - # oneAPI license does not allow mirroring outside of the # organization (e.g. University/Company). redistribute_source = False diff --git a/lib/spack/spack/build_systems/perl.py b/lib/spack/spack/build_systems/perl.py index 1f354beece0..a100b89bfd7 100644 --- a/lib/spack/spack/build_systems/perl.py +++ b/lib/spack/spack/build_systems/perl.py @@ -2,73 +2,87 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - - import inspect import os from llnl.util.filesystem import filter_file -from spack.directives import extends -from spack.package_base import PackageBase, run_after +import spack.builder +import spack.package_base +from spack.directives import build_system, extends +from spack.package_base import PackageBase from spack.util.executable import Executable +from ._checks import BaseBuilder, execute_build_time_tests + class PerlPackage(PackageBase): - """Specialized class for packages that are built using Perl. + """Specialized class for packages that are built using Perl.""" - This class provides four phases that can be overridden if required: + #: This attribute is used in UI queries that need to know the build + #: system base class + build_system_class = "PerlPackage" + #: Legacy buildsystem attribute used to deserialize and install old specs + legacy_buildsystem = "perl" - 1. :py:meth:`~.PerlPackage.configure` - 2. :py:meth:`~.PerlPackage.build` - 3. :py:meth:`~.PerlPackage.check` - 4. :py:meth:`~.PerlPackage.install` + build_system("perl") + + extends("perl", when="build_system=perl") + + +@spack.builder.builder("perl") +class PerlBuilder(BaseBuilder): + """The perl builder provides four phases that can be overridden, if required: + + 1. :py:meth:`~.PerlBuilder.configure` + 2. :py:meth:`~.PerlBuilder.build` + 3. :py:meth:`~.PerlBuilder.check` + 4. :py:meth:`~.PerlBuilder.install` The default methods use, in order of preference: (1) Makefile.PL, (2) Build.PL. - Some packages may need to override - :py:meth:`~.PerlPackage.configure_args`, - which produces a list of arguments for - :py:meth:`~.PerlPackage.configure`. + Some packages may need to override :py:meth:`~.PerlBuilder.configure_args`, + which produces a list of arguments for :py:meth:`~.PerlBuilder.configure`. + Arguments should not include the installation base directory. """ #: Phases of a Perl package - phases = ["configure", "build", "install"] + phases = ("configure", "build", "install") - #: This attribute is used in UI queries that need to know the build - #: system base class - build_system_class = "PerlPackage" + #: Names associated with package methods in the old build-system format + legacy_methods = ("configure_args", "check") + + #: Names associated with package attributes in the old build-system format + legacy_attributes = () #: Callback names for build-time test build_time_test_callbacks = ["check"] - extends("perl") - def configure_args(self): - """Produces a list containing the arguments that must be passed to - :py:meth:`~.PerlPackage.configure`. Arguments should not include - the installation base directory, which is prepended automatically. + """List of arguments passed to :py:meth:`~.PerlBuilder.configure`. - :return: list of arguments for Makefile.PL or Build.PL + Arguments should not include the installation base directory, which + is prepended automatically. """ return [] - def configure(self, spec, prefix): - """Runs Makefile.PL or Build.PL with arguments consisting of + def configure(self, pkg, spec, prefix): + """Run Makefile.PL or Build.PL with arguments consisting of an appropriate installation base directory followed by the - list returned by :py:meth:`~.PerlPackage.configure_args`. + list returned by :py:meth:`~.PerlBuilder.configure_args`. - :raise RuntimeError: if neither Makefile.PL or Build.PL exist + Raises: + RuntimeError: if neither Makefile.PL nor Build.PL exist """ if os.path.isfile("Makefile.PL"): self.build_method = "Makefile.PL" - self.build_executable = inspect.getmodule(self).make + self.build_executable = inspect.getmodule(self.pkg).make elif os.path.isfile("Build.PL"): self.build_method = "Build.PL" - self.build_executable = Executable(os.path.join(self.stage.source_path, "Build")) + self.build_executable = Executable(os.path.join(self.pkg.stage.source_path, "Build")) else: raise RuntimeError("Unknown build_method for perl package") @@ -78,33 +92,30 @@ def configure(self, spec, prefix): options = ["Build.PL", "--install_base", prefix] options += self.configure_args() - inspect.getmodule(self).perl(*options) + inspect.getmodule(self.pkg).perl(*options) # It is possible that the shebang in the Build script that is created from # Build.PL may be too long causing the build to fail. Patching the shebang # does not happen until after install so set '/usr/bin/env perl' here in # the Build script. - @run_after("configure") + @spack.builder.run_after("configure") def fix_shebang(self): if self.build_method == "Build.PL": pattern = "#!{0}".format(self.spec["perl"].command.path) repl = "#!/usr/bin/env perl" filter_file(pattern, repl, "Build", backup=False) - def build(self, spec, prefix): + def build(self, pkg, spec, prefix): """Builds a Perl package.""" self.build_executable() # Ensure that tests run after build (if requested): - run_after("build")(PackageBase._run_default_build_time_test_callbacks) + spack.builder.run_after("build")(execute_build_time_tests) def check(self): """Runs built-in tests of a Perl package.""" self.build_executable("test") - def install(self, spec, prefix): + def install(self, pkg, spec, prefix): """Installs a Perl package.""" self.build_executable("install") - - # Check that self.prefix is there after installation - run_after("install")(PackageBase.sanity_check_prefix) diff --git a/lib/spack/spack/build_systems/python.py b/lib/spack/spack/build_systems/python.py index d1cecdac639..0f84ac7f8ad 100644 --- a/lib/spack/spack/build_systems/python.py +++ b/lib/spack/spack/build_systems/python.py @@ -8,93 +8,22 @@ import shutil from typing import Optional +import llnl.util.filesystem as fs +import llnl.util.lang as lang import llnl.util.tty as tty -from llnl.util.filesystem import ( - filter_file, - find, - find_all_headers, - find_libraries, - is_nonsymlink_exe_with_shebang, - path_contains_subdirectory, - same_path, - working_dir, -) -from llnl.util.lang import classproperty, match_predicate -from spack.directives import depends_on, extends +import spack.builder +import spack.multimethod +import spack.package_base +from spack.directives import build_system, depends_on, extends from spack.error import NoHeadersError, NoLibrariesError, SpecError -from spack.package_base import PackageBase, run_after from spack.version import Version +from ._checks import BaseBuilder, execute_install_time_tests -class PythonPackage(PackageBase): - """Specialized class for packages that are built using pip.""" - #: Package name, version, and extension on PyPI - pypi = None # type: Optional[str] - - maintainers = ["adamjstewart", "pradyunsg"] - - # Default phases - phases = ["install"] - - # To be used in UI queries that require to know which - # build-system class we are using - build_system_class = "PythonPackage" - - #: Callback names for install-time test - install_time_test_callbacks = ["test"] - - extends("python") - depends_on("py-pip", type="build") - # FIXME: technically wheel is only needed when building from source, not when - # installing a downloaded wheel, but I don't want to add wheel as a dep to every - # package manually - depends_on("py-wheel", type="build") - - py_namespace = None # type: Optional[str] - - @staticmethod - def _std_args(cls): - return [ - # Verbose - "-vvv", - # Disable prompting for input - "--no-input", - # Disable the cache - "--no-cache-dir", - # Don't check to see if pip is up-to-date - "--disable-pip-version-check", - # Install packages - "install", - # Don't install package dependencies - "--no-deps", - # Overwrite existing packages - "--ignore-installed", - # Use env vars like PYTHONPATH - "--no-build-isolation", - # Don't warn that prefix.bin is not in PATH - "--no-warn-script-location", - # Ignore the PyPI package index - "--no-index", - ] - - @classproperty - def homepage(cls): - if cls.pypi: - name = cls.pypi.split("/")[0] - return "https://pypi.org/project/" + name + "/" - - @classproperty - def url(cls): - if cls.pypi: - return "https://files.pythonhosted.org/packages/source/" + cls.pypi[0] + "/" + cls.pypi - - @classproperty - def list_url(cls): - if cls.pypi: - name = cls.pypi.split("/")[0] - return "https://pypi.org/simple/" + name + "/" +class PythonExtension(spack.package_base.PackageBase): + maintainers = ["adamjstewart"] @property def import_modules(self): @@ -124,7 +53,7 @@ def import_modules(self): # Some Python libraries are packages: collections of modules # distributed in directories containing __init__.py files - for path in find(root, "__init__.py", recursive=True): + for path in fs.find(root, "__init__.py", recursive=True): modules.append( path.replace(root + os.sep, "", 1) .replace(os.sep + "__init__.py", "") @@ -133,7 +62,7 @@ def import_modules(self): # Some Python libraries are modules: individual *.py files # found in the site-packages directory - for path in find(root, "*.py", recursive=False): + for path in fs.find(root, "*.py", recursive=False): modules.append( path.replace(root + os.sep, "", 1).replace(".py", "").replace("/", ".") ) @@ -160,6 +89,208 @@ def skip_modules(self): """ return [] + def view_file_conflicts(self, view, merge_map): + """Report all file conflicts, excepting special cases for python. + Specifically, this does not report errors for duplicate + __init__.py files for packages in the same namespace. + """ + conflicts = list(dst for src, dst in merge_map.items() if os.path.exists(dst)) + + if conflicts and self.py_namespace: + ext_map = view.extensions_layout.extension_map(self.extendee_spec) + namespaces = set(x.package.py_namespace for x in ext_map.values()) + namespace_re = r"site-packages/{0}/__init__.py".format(self.py_namespace) + find_namespace = lang.match_predicate(namespace_re) + if self.py_namespace in namespaces: + conflicts = list(x for x in conflicts if not find_namespace(x)) + + return conflicts + + def add_files_to_view(self, view, merge_map, skip_if_exists=True): + bin_dir = self.spec.prefix.bin + python_prefix = self.extendee_spec.prefix + python_is_external = self.extendee_spec.external + global_view = fs.same_path(python_prefix, view.get_projection_for_spec(self.spec)) + for src, dst in merge_map.items(): + if os.path.exists(dst): + continue + elif global_view or not fs.path_contains_subdirectory(src, bin_dir): + view.link(src, dst) + elif not os.path.islink(src): + shutil.copy2(src, dst) + is_script = fs.is_nonsymlink_exe_with_shebang(src) + if is_script and not python_is_external: + fs.filter_file( + python_prefix, + os.path.abspath(view.get_projection_for_spec(self.spec)), + dst, + ) + else: + orig_link_target = os.path.realpath(src) + new_link_target = os.path.abspath(merge_map[orig_link_target]) + view.link(new_link_target, dst) + + def remove_files_from_view(self, view, merge_map): + ignore_namespace = False + if self.py_namespace: + ext_map = view.extensions_layout.extension_map(self.extendee_spec) + remaining_namespaces = set( + spec.package.py_namespace for name, spec in ext_map.items() if name != self.name + ) + if self.py_namespace in remaining_namespaces: + namespace_init = lang.match_predicate( + r"site-packages/{0}/__init__.py".format(self.py_namespace) + ) + ignore_namespace = True + + bin_dir = self.spec.prefix.bin + global_view = self.extendee_spec.prefix == view.get_projection_for_spec(self.spec) + + to_remove = [] + for src, dst in merge_map.items(): + if ignore_namespace and namespace_init(dst): + continue + + if global_view or not fs.path_contains_subdirectory(src, bin_dir): + to_remove.append(dst) + else: + os.remove(dst) + + view.remove_files(to_remove) + + def test(self): + """Attempts to import modules of the installed package.""" + + # Make sure we are importing the installed modules, + # not the ones in the source directory + for module in self.import_modules: + self.run_test( + inspect.getmodule(self).python.path, + ["-c", "import {0}".format(module)], + purpose="checking import of {0}".format(module), + work_dir="spack-test", + ) + + +class PythonPackage(PythonExtension): + """Specialized class for packages that are built using pip.""" + + #: Package name, version, and extension on PyPI + pypi = None # type: Optional[str] + + maintainers = ["adamjstewart", "pradyunsg"] + + # To be used in UI queries that require to know which + # build-system class we are using + build_system_class = "PythonPackage" + #: Legacy buildsystem attribute used to deserialize and install old specs + legacy_buildsystem = "python_pip" + + #: Callback names for install-time test + install_time_test_callbacks = ["test"] + + build_system("python_pip") + + with spack.multimethod.when("build_system=python_pip"): + extends("python") + depends_on("py-pip", type="build") + # FIXME: technically wheel is only needed when building from source, not when + # installing a downloaded wheel, but I don't want to add wheel as a dep to every + # package manually + depends_on("py-wheel", type="build") + + py_namespace = None # type: Optional[str] + + @lang.classproperty + def homepage(cls): + if cls.pypi: + name = cls.pypi.split("/")[0] + return "https://pypi.org/project/" + name + "/" + + @lang.classproperty + def url(cls): + if cls.pypi: + return "https://files.pythonhosted.org/packages/source/" + cls.pypi[0] + "/" + cls.pypi + + @lang.classproperty + def list_url(cls): + if cls.pypi: + name = cls.pypi.split("/")[0] + return "https://pypi.org/simple/" + name + "/" + + @property + def headers(self): + """Discover header files in platlib.""" + + # Headers may be in either location + include = self.prefix.join(self.spec["python"].package.include) + platlib = self.prefix.join(self.spec["python"].package.platlib) + headers = fs.find_all_headers(include) + fs.find_all_headers(platlib) + + if headers: + return headers + + msg = "Unable to locate {} headers in {} or {}" + raise NoHeadersError(msg.format(self.spec.name, include, platlib)) + + @property + def libs(self): + """Discover libraries in platlib.""" + + # Remove py- prefix in package name + library = "lib" + self.spec.name[3:].replace("-", "?") + root = self.prefix.join(self.spec["python"].package.platlib) + + for shared in [True, False]: + libs = fs.find_libraries(library, root, shared=shared, recursive=True) + if libs: + return libs + + msg = "Unable to recursively locate {} libraries in {}" + raise NoLibrariesError(msg.format(self.spec.name, root)) + + +@spack.builder.builder("python_pip") +class PythonPipBuilder(BaseBuilder): + phases = ("install",) + + #: Names associated with package methods in the old build-system format + legacy_methods = ("test",) + + #: Same as legacy_methods, but the signature is different + legacy_long_methods = ("install_options", "global_options", "config_settings") + + #: Names associated with package attributes in the old build-system format + legacy_attributes = ("build_directory", "install_time_test_callbacks") + + #: Callback names for install-time test + install_time_test_callbacks = ["test"] + + @staticmethod + def std_args(cls): + return [ + # Verbose + "-vvv", + # Disable prompting for input + "--no-input", + # Disable the cache + "--no-cache-dir", + # Don't check to see if pip is up-to-date + "--disable-pip-version-check", + # Install packages + "install", + # Don't install package dependencies + "--no-deps", + # Overwrite existing packages + "--ignore-installed", + # Use env vars like PYTHONPATH + "--no-build-isolation", + # Don't warn that prefix.bin is not in PATH + "--no-warn-script-location", + # Ignore the PyPI package index + "--no-index", + ] + @property def build_directory(self): """The root directory of the Python package. @@ -170,11 +301,10 @@ def build_directory(self): * ``setup.cfg`` * ``setup.py`` """ - return self.stage.source_path + return self.pkg.stage.source_path def config_settings(self, spec, prefix): """Configuration settings to be passed to the PEP 517 build backend. - Requires pip 22.1+, which requires Python 3.7+. Args: @@ -211,10 +341,10 @@ def global_options(self, spec, prefix): """ return [] - def install(self, spec, prefix): + def install(self, pkg, spec, prefix): """Install everything from build directory.""" - args = PythonPackage._std_args(self) + ["--prefix=" + prefix] + args = PythonPipBuilder.std_args(pkg) + ["--prefix=" + prefix] for key, value in self.config_settings(spec, prefix).items(): if spec["py-pip"].version < Version("22.1"): @@ -223,137 +353,21 @@ def install(self, spec, prefix): "pip 22.1+. Add the following line to the package to fix this:\n\n" ' depends_on("py-pip@22.1:", type="build")'.format(spec.name) ) + args.append("--config-settings={}={}".format(key, value)) + for option in self.install_options(spec, prefix): args.append("--install-option=" + option) for option in self.global_options(spec, prefix): args.append("--global-option=" + option) - if self.stage.archive_file and self.stage.archive_file.endswith(".whl"): - args.append(self.stage.archive_file) + if pkg.stage.archive_file and pkg.stage.archive_file.endswith(".whl"): + args.append(pkg.stage.archive_file) else: args.append(".") - pip = inspect.getmodule(self).pip - with working_dir(self.build_directory): + pip = inspect.getmodule(pkg).pip + with fs.working_dir(self.build_directory): pip(*args) - @property - def headers(self): - """Discover header files in platlib.""" - - # Headers may be in either location - include = self.prefix.join(self.spec["python"].package.include) - platlib = self.prefix.join(self.spec["python"].package.platlib) - headers = find_all_headers(include) + find_all_headers(platlib) - - if headers: - return headers - - msg = "Unable to locate {} headers in {} or {}" - raise NoHeadersError(msg.format(self.spec.name, include, platlib)) - - @property - def libs(self): - """Discover libraries in platlib.""" - - # Remove py- prefix in package name - library = "lib" + self.spec.name[3:].replace("-", "?") - root = self.prefix.join(self.spec["python"].package.platlib) - - for shared in [True, False]: - libs = find_libraries(library, root, shared=shared, recursive=True) - if libs: - return libs - - msg = "Unable to recursively locate {} libraries in {}" - raise NoLibrariesError(msg.format(self.spec.name, root)) - - # Testing - - def test(self): - """Attempts to import modules of the installed package.""" - - # Make sure we are importing the installed modules, - # not the ones in the source directory - for module in self.import_modules: - self.run_test( - inspect.getmodule(self).python.path, - ["-c", "import {0}".format(module)], - purpose="checking import of {0}".format(module), - work_dir="spack-test", - ) - - run_after("install")(PackageBase._run_default_install_time_test_callbacks) - - # Check that self.prefix is there after installation - run_after("install")(PackageBase.sanity_check_prefix) - - def view_file_conflicts(self, view, merge_map): - """Report all file conflicts, excepting special cases for python. - Specifically, this does not report errors for duplicate - __init__.py files for packages in the same namespace. - """ - conflicts = list(dst for src, dst in merge_map.items() if os.path.exists(dst)) - - if conflicts and self.py_namespace: - ext_map = view.extensions_layout.extension_map(self.extendee_spec) - namespaces = set(x.package.py_namespace for x in ext_map.values()) - namespace_re = r"site-packages/{0}/__init__.py".format(self.py_namespace) - find_namespace = match_predicate(namespace_re) - if self.py_namespace in namespaces: - conflicts = list(x for x in conflicts if not find_namespace(x)) - - return conflicts - - def add_files_to_view(self, view, merge_map, skip_if_exists=True): - bin_dir = self.spec.prefix.bin - python_prefix = self.extendee_spec.prefix - python_is_external = self.extendee_spec.external - global_view = same_path(python_prefix, view.get_projection_for_spec(self.spec)) - for src, dst in merge_map.items(): - if os.path.exists(dst): - continue - elif global_view or not path_contains_subdirectory(src, bin_dir): - view.link(src, dst) - elif not os.path.islink(src): - shutil.copy2(src, dst) - is_script = is_nonsymlink_exe_with_shebang(src) - if is_script and not python_is_external: - filter_file( - python_prefix, - os.path.abspath(view.get_projection_for_spec(self.spec)), - dst, - ) - else: - orig_link_target = os.path.realpath(src) - new_link_target = os.path.abspath(merge_map[orig_link_target]) - view.link(new_link_target, dst) - - def remove_files_from_view(self, view, merge_map): - ignore_namespace = False - if self.py_namespace: - ext_map = view.extensions_layout.extension_map(self.extendee_spec) - remaining_namespaces = set( - spec.package.py_namespace for name, spec in ext_map.items() if name != self.name - ) - if self.py_namespace in remaining_namespaces: - namespace_init = match_predicate( - r"site-packages/{0}/__init__.py".format(self.py_namespace) - ) - ignore_namespace = True - - bin_dir = self.spec.prefix.bin - global_view = self.extendee_spec.prefix == view.get_projection_for_spec(self.spec) - - to_remove = [] - for src, dst in merge_map.items(): - if ignore_namespace and namespace_init(dst): - continue - - if global_view or not path_contains_subdirectory(src, bin_dir): - to_remove.append(dst) - else: - os.remove(dst) - - view.remove_files(to_remove) + spack.builder.run_after("install")(execute_install_time_tests) diff --git a/lib/spack/spack/build_systems/qmake.py b/lib/spack/spack/build_systems/qmake.py index c2af684592b..f18bd9812f5 100644 --- a/lib/spack/spack/build_systems/qmake.py +++ b/lib/spack/spack/build_systems/qmake.py @@ -2,82 +2,85 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - - import inspect from llnl.util.filesystem import working_dir -from spack.directives import depends_on -from spack.package_base import PackageBase, run_after +import spack.builder +import spack.package_base +from spack.directives import build_system, depends_on + +from ._checks import BaseBuilder, execute_build_time_tests -class QMakePackage(PackageBase): +class QMakePackage(spack.package_base.PackageBase): """Specialized class for packages built using qmake. For more information on the qmake build system, see: http://doc.qt.io/qt-5/qmake-manual.html - - This class provides three phases that can be overridden: - - 1. :py:meth:`~.QMakePackage.qmake` - 2. :py:meth:`~.QMakePackage.build` - 3. :py:meth:`~.QMakePackage.install` - - They all have sensible defaults and for many packages the only thing - necessary will be to override :py:meth:`~.QMakePackage.qmake_args`. """ - #: Phases of a qmake package - phases = ["qmake", "build", "install"] - #: This attribute is used in UI queries that need to know the build #: system base class build_system_class = "QMakePackage" + #: Legacy buildsystem attribute used to deserialize and install old specs + legacy_buildsystem = "qmake" + + build_system("qmake") + + depends_on("qt", type="build", when="build_system=qmake") + + +@spack.builder.builder("qmake") +class QMakeBuilder(BaseBuilder): + """The qmake builder provides three phases that can be overridden: + + 1. :py:meth:`~.QMakeBuilder.qmake` + 2. :py:meth:`~.QMakeBuilder.build` + 3. :py:meth:`~.QMakeBuilder.install` + + They all have sensible defaults and for many packages the only thing + necessary will be to override :py:meth:`~.QMakeBuilder.qmake_args`. + """ + + phases = ("qmake", "build", "install") + + #: Names associated with package methods in the old build-system format + legacy_methods = ("qmake_args", "check") + + #: Names associated with package attributes in the old build-system format + legacy_attributes = ("build_directory", "build_time_test_callbacks") #: Callback names for build-time test build_time_test_callbacks = ["check"] - depends_on("qt", type="build") - @property def build_directory(self): """The directory containing the ``*.pro`` file.""" return self.stage.source_path def qmake_args(self): - """Produces a list containing all the arguments that must be passed to - qmake - """ + """List of arguments passed to qmake.""" return [] - def qmake(self, spec, prefix): + def qmake(self, pkg, spec, prefix): """Run ``qmake`` to configure the project and generate a Makefile.""" - with working_dir(self.build_directory): - inspect.getmodule(self).qmake(*self.qmake_args()) + inspect.getmodule(self.pkg).qmake(*self.qmake_args()) - def build(self, spec, prefix): + def build(self, pkg, spec, prefix): """Make the build targets""" - with working_dir(self.build_directory): - inspect.getmodule(self).make() + inspect.getmodule(self.pkg).make() - def install(self, spec, prefix): + def install(self, pkg, spec, prefix): """Make the install targets""" - with working_dir(self.build_directory): - inspect.getmodule(self).make("install") - - # Tests + inspect.getmodule(self.pkg).make("install") def check(self): - """Searches the Makefile for a ``check:`` target and runs it if found.""" - + """Search the Makefile for a ``check:`` target and runs it if found.""" with working_dir(self.build_directory): self._if_make_target_execute("check") - run_after("build")(PackageBase._run_default_build_time_test_callbacks) - - # Check that self.prefix is there after installation - run_after("install")(PackageBase.sanity_check_prefix) + spack.builder.run_after("build")(execute_build_time_tests) diff --git a/lib/spack/spack/build_systems/r.py b/lib/spack/spack/build_systems/r.py index 450cae733bf..c62baa3555f 100644 --- a/lib/spack/spack/build_systems/r.py +++ b/lib/spack/spack/build_systems/r.py @@ -3,30 +3,64 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) import inspect -from typing import Optional +from typing import Optional, Tuple import llnl.util.lang as lang from spack.directives import extends -from spack.package_base import PackageBase, run_after + +from .generic import GenericBuilder, Package -class RPackage(PackageBase): +class RBuilder(GenericBuilder): + """The R builder provides a single phase that can be overridden: + + 1. :py:meth:`~.RBuilder.install` + + It has sensible defaults, and for many packages the only thing + necessary will be to add dependencies. + """ + + #: Names associated with package methods in the old build-system format + legacy_methods = ( + "configure_args", + "configure_vars", + ) + GenericBuilder.legacy_methods # type: Tuple[str, ...] + + def configure_args(self): + """Arguments to pass to install via ``--configure-args``.""" + return [] + + def configure_vars(self): + """Arguments to pass to install via ``--configure-vars``.""" + return [] + + def install(self, pkg, spec, prefix): + """Installs an R package.""" + + config_args = self.configure_args() + config_vars = self.configure_vars() + + args = ["--vanilla", "CMD", "INSTALL"] + + if config_args: + args.append("--configure-args={0}".format(" ".join(config_args))) + + if config_vars: + args.append("--configure-vars={0}".format(" ".join(config_vars))) + + args.extend(["--library={0}".format(self.pkg.module.r_lib_dir), self.stage.source_path]) + + inspect.getmodule(self.pkg).R(*args) + + +class RPackage(Package): """Specialized class for packages that are built using R. For more information on the R build system, see: https://stat.ethz.ch/R-manual/R-devel/library/utils/html/INSTALL.html - - This class provides a single phase that can be overridden: - - 1. :py:meth:`~.RPackage.install` - - It has sensible defaults, and for many packages the only thing - necessary will be to add dependencies """ - phases = ["install"] - # package attributes that can be expanded to set the homepage, url, # list_url, and git values # For CRAN packages @@ -35,6 +69,8 @@ class RPackage(PackageBase): # For Bioconductor packages bioc = None # type: Optional[str] + GenericBuilder = RBuilder + maintainers = ["glennpj"] #: This attribute is used in UI queries that need to know the build @@ -70,32 +106,3 @@ def list_url(cls): def git(self): if self.bioc: return "https://git.bioconductor.org/packages/" + self.bioc - - def configure_args(self): - """Arguments to pass to install via ``--configure-args``.""" - return [] - - def configure_vars(self): - """Arguments to pass to install via ``--configure-vars``.""" - return [] - - def install(self, spec, prefix): - """Installs an R package.""" - - config_args = self.configure_args() - config_vars = self.configure_vars() - - args = ["--vanilla", "CMD", "INSTALL"] - - if config_args: - args.append("--configure-args={0}".format(" ".join(config_args))) - - if config_vars: - args.append("--configure-vars={0}".format(" ".join(config_vars))) - - args.extend(["--library={0}".format(self.module.r_lib_dir), self.stage.source_path]) - - inspect.getmodule(self).R(*args) - - # Check that self.prefix is there after installation - run_after("install")(PackageBase.sanity_check_prefix) diff --git a/lib/spack/spack/build_systems/racket.py b/lib/spack/spack/build_systems/racket.py index 7b37d85cf2e..889cc079315 100644 --- a/lib/spack/spack/build_systems/racket.py +++ b/lib/spack/spack/build_systems/racket.py @@ -3,14 +3,15 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) import os -from typing import Optional +from typing import Optional, Tuple +import llnl.util.filesystem as fs import llnl.util.lang as lang import llnl.util.tty as tty -from llnl.util.filesystem import working_dir +import spack.builder from spack.build_environment import SPACK_NO_PARALLEL_MAKE, determine_number_of_jobs -from spack.directives import extends +from spack.directives import build_system, extends from spack.package_base import PackageBase from spack.util.environment import env_flag from spack.util.executable import Executable, ProcessError @@ -19,34 +20,52 @@ class RacketPackage(PackageBase): """Specialized class for packages that are built using Racket's `raco pkg install` and `raco setup` commands. - - This class provides the following phases that can be overridden: - - * install - * setup """ #: Package name, version, and extension on PyPI maintainers = ["elfprince13"] - - # Default phases - phases = ["install"] - # To be used in UI queries that require to know which # build-system class we are using build_system_class = "RacketPackage" + #: Legacy buildsystem attribute used to deserialize and install old specs + legacy_buildsystem = "racket" - extends("racket") + build_system("racket") + + extends("racket", when="build_system=racket") - pkgs = False - subdirectory = None # type: Optional[str] racket_name = None # type: Optional[str] parallel = True @lang.classproperty def homepage(cls): - if cls.pkgs: + if cls.racket_name: return "https://pkgs.racket-lang.org/package/{0}".format(cls.racket_name) + return None + + +@spack.builder.builder("racket") +class RacketBuilder(spack.builder.Builder): + """The Racket builder provides an ``install`` phase that can be overridden.""" + + phases = ("install",) + + #: Names associated with package methods in the old build-system format + legacy_methods = tuple() # type: Tuple[str, ...] + + #: Names associated with package attributes in the old build-system format + legacy_attributes = ("build_directory", "build_time_test_callbacks", "subdirectory") + + #: Callback names for build-time test + build_time_test_callbacks = ["check"] + + racket_name = None # type: Optional[str] + + @property + def subdirectory(self): + if self.racket_name: + return "pkgs/{0}".format(self.pkg.racket_name) + return None @property def build_directory(self): @@ -55,25 +74,25 @@ def build_directory(self): ret = os.path.join(ret, self.subdirectory) return ret - def install(self, spec, prefix): + def install(self, pkg, spec, prefix): """Install everything from build directory.""" raco = Executable("raco") - with working_dir(self.build_directory): - allow_parallel = self.parallel and (not env_flag(SPACK_NO_PARALLEL_MAKE)) + with fs.working_dir(self.build_directory): + parallel = self.pkg.parallel and (not env_flag(SPACK_NO_PARALLEL_MAKE)) args = [ "pkg", "install", "-t", "dir", "-n", - self.racket_name, + self.pkg.racket_name, "--deps", "fail", "--ignore-implies", "--copy", "-i", "-j", - str(determine_number_of_jobs(allow_parallel)), + str(determine_number_of_jobs(parallel)), "--", os.getcwd(), ] @@ -82,9 +101,8 @@ def install(self, spec, prefix): except ProcessError: args.insert(-2, "--skip-installed") raco(*args) - tty.warn( - ( - "Racket package {0} was already installed, uninstalling via " - "Spack may make someone unhappy!" - ).format(self.racket_name) + msg = ( + "Racket package {0} was already installed, uninstalling via " + "Spack may make someone unhappy!" ) + tty.warn(msg.format(self.pkg.racket_name)) diff --git a/lib/spack/spack/build_systems/ruby.py b/lib/spack/spack/build_systems/ruby.py index fcc071f19ec..ef29f164ab2 100644 --- a/lib/spack/spack/build_systems/ruby.py +++ b/lib/spack/spack/build_systems/ruby.py @@ -2,35 +2,49 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - import glob import inspect -from spack.directives import extends -from spack.package_base import PackageBase, run_after +import spack.builder +import spack.package_base +from spack.directives import build_system, extends + +from ._checks import BaseBuilder -class RubyPackage(PackageBase): - """Specialized class for building Ruby gems. - - This class provides two phases that can be overridden if required: - - #. :py:meth:`~.RubyPackage.build` - #. :py:meth:`~.RubyPackage.install` - """ +class RubyPackage(spack.package_base.PackageBase): + """Specialized class for building Ruby gems.""" maintainers = ["Kerilk"] - #: Phases of a Ruby package - phases = ["build", "install"] - #: This attribute is used in UI queries that need to know the build #: system base class build_system_class = "RubyPackage" + #: Legacy buildsystem attribute used to deserialize and install old specs + legacy_buildsystem = "ruby" - extends("ruby") + build_system("ruby") - def build(self, spec, prefix): + extends("ruby", when="build_system=ruby") + + +@spack.builder.builder("ruby") +class RubyBuilder(BaseBuilder): + """The Ruby builder provides two phases that can be overridden if required: + + #. :py:meth:`~.RubyBuilder.build` + #. :py:meth:`~.RubyBuilder.install` + """ + + phases = ("build", "install") + + #: Names associated with package methods in the old build-system format + legacy_methods = () + + #: Names associated with package attributes in the old build-system format + legacy_attributes = () + + def build(self, pkg, spec, prefix): """Build a Ruby gem.""" # ruby-rake provides both rake.gemspec and Rakefile, but only @@ -38,15 +52,15 @@ def build(self, spec, prefix): gemspecs = glob.glob("*.gemspec") rakefiles = glob.glob("Rakefile") if gemspecs: - inspect.getmodule(self).gem("build", "--norc", gemspecs[0]) + inspect.getmodule(self.pkg).gem("build", "--norc", gemspecs[0]) elif rakefiles: - jobs = inspect.getmodule(self).make_jobs - inspect.getmodule(self).rake("package", "-j{0}".format(jobs)) + jobs = inspect.getmodule(self.pkg).make_jobs + inspect.getmodule(self.pkg).rake("package", "-j{0}".format(jobs)) else: # Some Ruby packages only ship `*.gem` files, so nothing to build pass - def install(self, spec, prefix): + def install(self, pkg, spec, prefix): """Install a Ruby gem. The ruby package sets ``GEM_HOME`` to tell gem where to install to.""" @@ -56,9 +70,6 @@ def install(self, spec, prefix): # if --install-dir is not used, GEM_PATH is deleted from the # environement, and Gems required to build native extensions will # not be found. Those extensions are built during `gem install`. - inspect.getmodule(self).gem( + inspect.getmodule(self.pkg).gem( "install", "--norc", "--ignore-dependencies", "--install-dir", prefix, gems[0] ) - - # Check that self.prefix is there after installation - run_after("install")(PackageBase.sanity_check_prefix) diff --git a/lib/spack/spack/build_systems/scons.py b/lib/spack/spack/build_systems/scons.py index 54700911217..f1ae9559177 100644 --- a/lib/spack/spack/build_systems/scons.py +++ b/lib/spack/spack/build_systems/scons.py @@ -2,63 +2,75 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - - import inspect -from spack.directives import depends_on -from spack.package_base import PackageBase, run_after +import spack.builder +import spack.package_base +from spack.directives import build_system, depends_on + +from ._checks import BaseBuilder, execute_build_time_tests -class SConsPackage(PackageBase): +class SConsPackage(spack.package_base.PackageBase): """Specialized class for packages built using SCons. See http://scons.org/documentation.html for more information. - - This class provides the following phases that can be overridden: - - 1. :py:meth:`~.SConsPackage.build` - 2. :py:meth:`~.SConsPackage.install` - - Packages that use SCons as a build system are less uniform than packages - that use other build systems. Developers can add custom subcommands or - variables that control the build. You will likely need to override - :py:meth:`~.SConsPackage.build_args` to pass the appropriate variables. """ - #: Phases of a SCons package - phases = ["build", "install"] - #: To be used in UI queries that require to know which #: build-system class we are using build_system_class = "SConsPackage" #: Callback names for build-time test build_time_test_callbacks = ["build_test"] + #: Legacy buildsystem attribute used to deserialize and install old specs + legacy_buildsystem = "scons" - depends_on("scons", type="build") + build_system("scons") - def build_args(self, spec, prefix): + depends_on("scons", type="build", when="build_system=scons") + + +@spack.builder.builder("scons") +class SConsBuilder(BaseBuilder): + """The Scons builder provides the following phases that can be overridden: + + 1. :py:meth:`~.SConsBuilder.build` + 2. :py:meth:`~.SConsBuilder.install` + + Packages that use SCons as a build system are less uniform than packages that use + other build systems. Developers can add custom subcommands or variables that + control the build. You will likely need to override + :py:meth:`~.SConsBuilder.build_args` to pass the appropriate variables. + """ + + #: Phases of a SCons package + phases = ("build", "install") + + #: Names associated with package methods in the old build-system format + legacy_methods = ("build_args", "install_args", "build_test") + + #: Names associated with package attributes in the old build-system format + legacy_attributes = () + + def build_args(self): """Arguments to pass to build.""" return [] - def build(self, spec, prefix): + def build(self, pkg, spec, prefix): """Build the package.""" - args = self.build_args(spec, prefix) + args = self.build_args() + inspect.getmodule(self.pkg).scons(*args) - inspect.getmodule(self).scons(*args) - - def install_args(self, spec, prefix): + def install_args(self): """Arguments to pass to install.""" return [] - def install(self, spec, prefix): + def install(self, pkg, spec, prefix): """Install the package.""" - args = self.install_args(spec, prefix) + args = self.install_args() - inspect.getmodule(self).scons("install", *args) - - # Testing + inspect.getmodule(self.pkg).scons("install", *args) def build_test(self): """Run unit tests after build. @@ -68,7 +80,4 @@ def build_test(self): """ pass - run_after("build")(PackageBase._run_default_build_time_test_callbacks) - - # Check that self.prefix is there after installation - run_after("install")(PackageBase.sanity_check_prefix) + spack.builder.run_after("build")(execute_build_time_tests) diff --git a/lib/spack/spack/build_systems/sip.py b/lib/spack/spack/build_systems/sip.py index 4d16f6731e7..b129ca4e0ae 100644 --- a/lib/spack/spack/build_systems/sip.py +++ b/lib/spack/spack/build_systems/sip.py @@ -2,7 +2,6 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - import inspect import os import re @@ -10,28 +9,20 @@ import llnl.util.tty as tty from llnl.util.filesystem import find, join_path, working_dir -from spack.directives import depends_on, extends -from spack.package_base import PackageBase, run_after +import spack.builder +import spack.package_base +from spack.directives import build_system, depends_on, extends +from spack.multimethod import when + +from ._checks import BaseBuilder, execute_install_time_tests -class SIPPackage(PackageBase): +class SIPPackage(spack.package_base.PackageBase): """Specialized class for packages that are built using the SIP build system. See https://www.riverbankcomputing.com/software/sip/intro for more information. - - This class provides the following phases that can be overridden: - - * configure - * build - * install - - The configure phase already adds a set of default flags. To see more - options, run ``python configure.py --help``. """ - # Default phases - phases = ["configure", "build", "install"] - # To be used in UI queries that require to know which # build-system class we are using build_system_class = "SIPPackage" @@ -41,11 +32,15 @@ class SIPPackage(PackageBase): #: Callback names for install-time test install_time_test_callbacks = ["test"] + #: Legacy buildsystem attribute used to deserialize and install old specs + legacy_buildsystem = "sip" - extends("python") + build_system("sip") - depends_on("qt") - depends_on("py-sip") + with when("build_system=sip"): + extends("python") + depends_on("qt") + depends_on("py-sip") @property def import_modules(self): @@ -95,11 +90,51 @@ def python(self, *args, **kwargs): """The python ``Executable``.""" inspect.getmodule(self).python(*args, **kwargs) + def test(self): + """Attempts to import modules of the installed package.""" + + # Make sure we are importing the installed modules, + # not the ones in the source directory + for module in self.import_modules: + self.run_test( + inspect.getmodule(self).python.path, + ["-c", "import {0}".format(module)], + purpose="checking import of {0}".format(module), + work_dir="spack-test", + ) + + +@spack.builder.builder("sip") +class SIPBuilder(BaseBuilder): + """The SIP builder provides the following phases that can be overridden: + + * configure + * build + * install + + The configure phase already adds a set of default flags. To see more + options, run ``python configure.py --help``. + """ + + phases = ("configure", "build", "install") + + #: Names associated with package methods in the old build-system format + legacy_methods = ("configure_file", "configure_args", "build_args", "install_args") + + #: Names associated with package attributes in the old build-system format + legacy_attributes = ( + "build_targets", + "install_targets", + "build_time_test_callbacks", + "install_time_test_callbacks", + "build_directory", + ) + def configure_file(self): """Returns the name of the configure file to use.""" return "configure.py" - def configure(self, spec, prefix): + def configure(self, pkg, spec, prefix): """Configure the package.""" configure = self.configure_file() @@ -118,7 +153,7 @@ def configure(self, spec, prefix): "--bindir", prefix.bin, "--destdir", - inspect.getmodule(self).python_platlib, + inspect.getmodule(self.pkg).python_platlib, ] ) @@ -128,53 +163,35 @@ def configure_args(self): """Arguments to pass to configure.""" return [] - def build(self, spec, prefix): + def build(self, pkg, spec, prefix): """Build the package.""" args = self.build_args() - inspect.getmodule(self).make(*args) + inspect.getmodule(self.pkg).make(*args) def build_args(self): """Arguments to pass to build.""" return [] - def install(self, spec, prefix): + def install(self, pkg, spec, prefix): """Install the package.""" args = self.install_args() - inspect.getmodule(self).make("install", parallel=False, *args) + inspect.getmodule(self.pkg).make("install", parallel=False, *args) def install_args(self): """Arguments to pass to install.""" return [] - # Testing + spack.builder.run_after("install")(execute_install_time_tests) - def test(self): - """Attempts to import modules of the installed package.""" - - # Make sure we are importing the installed modules, - # not the ones in the source directory - for module in self.import_modules: - self.run_test( - inspect.getmodule(self).python.path, - ["-c", "import {0}".format(module)], - purpose="checking import of {0}".format(module), - work_dir="spack-test", - ) - - run_after("install")(PackageBase._run_default_install_time_test_callbacks) - - # Check that self.prefix is there after installation - run_after("install")(PackageBase.sanity_check_prefix) - - @run_after("install") + @spack.builder.run_after("install") def extend_path_setup(self): # See github issue #14121 and PR #15297 - module = self.spec["py-sip"].variants["module"].value + module = self.pkg.spec["py-sip"].variants["module"].value if module != "sip": module = module.split(".")[0] - with working_dir(inspect.getmodule(self).python_platlib): + with working_dir(inspect.getmodule(self.pkg).python_platlib): with open(os.path.join(module, "__init__.py"), "a") as f: f.write("from pkgutil import extend_path\n") f.write("__path__ = extend_path(__path__, __name__)\n") diff --git a/lib/spack/spack/build_systems/waf.py b/lib/spack/spack/build_systems/waf.py index 3571ffd525a..f972d4e2867 100644 --- a/lib/spack/spack/build_systems/waf.py +++ b/lib/spack/spack/build_systems/waf.py @@ -2,21 +2,38 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - - import inspect from llnl.util.filesystem import working_dir -from spack.directives import depends_on -from spack.package_base import PackageBase, run_after +import spack.builder +import spack.package_base +from spack.directives import build_system, depends_on + +from ._checks import BaseBuilder, execute_build_time_tests, execute_install_time_tests -class WafPackage(PackageBase): +class WafPackage(spack.package_base.PackageBase): """Specialized class for packages that are built using the Waf build system. See https://waf.io/book/ for more information. + """ - This class provides the following phases that can be overridden: + # To be used in UI queries that require to know which + # build-system class we are using + build_system_class = "WafPackage" + #: Legacy buildsystem attribute used to deserialize and install old specs + legacy_buildsystem = "waf" + + build_system("waf") + # Much like AutotoolsPackage does not require automake and autoconf + # to build, WafPackage does not require waf to build. It only requires + # python to run the waf build script. + depends_on("python@2.5:", type="build", when="build_system=waf") + + +@spack.builder.builder("waf") +class WafBuilder(BaseBuilder): + """The WAF builder provides the following phases that can be overridden: * configure * build @@ -40,12 +57,25 @@ class WafPackage(PackageBase): function, which passes ``--prefix=/path/to/installation/prefix``. """ - # Default phases - phases = ["configure", "build", "install"] + phases = ("configure", "build", "install") - # To be used in UI queries that require to know which - # build-system class we are using - build_system_class = "WafPackage" + #: Names associated with package methods in the old build-system format + legacy_methods = ( + "build_test", + "install_test", + "configure_args", + "build_args", + "install_args", + "build_test", + "install_test", + ) + + #: Names associated with package attributes in the old build-system format + legacy_attributes = ( + "build_time_test_callbacks", + "build_time_test_callbacks", + "build_directory", + ) # Callback names for build-time test build_time_test_callbacks = ["build_test"] @@ -53,11 +83,6 @@ class WafPackage(PackageBase): # Callback names for install-time test install_time_test_callbacks = ["install_test"] - # Much like AutotoolsPackage does not require automake and autoconf - # to build, WafPackage does not require waf to build. It only requires - # python to run the waf build script. - depends_on("python@2.5:", type="build") - @property def build_directory(self): """The directory containing the ``waf`` file.""" @@ -65,18 +90,18 @@ def build_directory(self): def python(self, *args, **kwargs): """The python ``Executable``.""" - inspect.getmodule(self).python(*args, **kwargs) + inspect.getmodule(self.pkg).python(*args, **kwargs) def waf(self, *args, **kwargs): """Runs the waf ``Executable``.""" - jobs = inspect.getmodule(self).make_jobs + jobs = inspect.getmodule(self.pkg).make_jobs with working_dir(self.build_directory): self.python("waf", "-j{0}".format(jobs), *args, **kwargs) - def configure(self, spec, prefix): + def configure(self, pkg, spec, prefix): """Configures the project.""" - args = ["--prefix={0}".format(self.prefix)] + args = ["--prefix={0}".format(self.pkg.prefix)] args += self.configure_args() self.waf("configure", *args) @@ -85,7 +110,7 @@ def configure_args(self): """Arguments to pass to configure.""" return [] - def build(self, spec, prefix): + def build(self, pkg, spec, prefix): """Executes the build.""" args = self.build_args() @@ -95,7 +120,7 @@ def build_args(self): """Arguments to pass to build.""" return [] - def install(self, spec, prefix): + def install(self, pkg, spec, prefix): """Installs the targets on the system.""" args = self.install_args() @@ -105,8 +130,6 @@ def install_args(self): """Arguments to pass to install.""" return [] - # Testing - def build_test(self): """Run unit tests after build. @@ -115,7 +138,7 @@ def build_test(self): """ pass - run_after("build")(PackageBase._run_default_build_time_test_callbacks) + spack.builder.run_after("build")(execute_build_time_tests) def install_test(self): """Run unit tests after install. @@ -125,7 +148,4 @@ def install_test(self): """ pass - run_after("install")(PackageBase._run_default_install_time_test_callbacks) - - # Check that self.prefix is there after installation - run_after("install")(PackageBase.sanity_check_prefix) + spack.builder.run_after("install")(execute_install_time_tests) diff --git a/lib/spack/spack/builder.py b/lib/spack/spack/builder.py new file mode 100644 index 00000000000..6baa321eea1 --- /dev/null +++ b/lib/spack/spack/builder.py @@ -0,0 +1,574 @@ +# 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) +import collections +import copy +import functools +import inspect +from typing import List, Optional, Tuple + +import six + +import llnl.util.compat + +import spack.build_environment + +#: Builder classes, as registered by the "builder" decorator +BUILDER_CLS = {} + +#: An object of this kind is a shared global state used to collect callbacks during +#: class definition time, and is flushed when the class object is created at the end +#: of the class definition +#: +#: Args: +#: attribute_name (str): name of the attribute that will be attached to the builder +#: callbacks (list): container used to temporarily aggregate the callbacks +CallbackTemporaryStage = collections.namedtuple( + "CallbackTemporaryStage", ["attribute_name", "callbacks"] +) + +#: Shared global state to aggregate "@run_before" callbacks +_RUN_BEFORE = CallbackTemporaryStage(attribute_name="run_before_callbacks", callbacks=[]) +#: Shared global state to aggregate "@run_after" callbacks +_RUN_AFTER = CallbackTemporaryStage(attribute_name="run_after_callbacks", callbacks=[]) + +#: Map id(pkg) to a builder, to avoid creating multiple +#: builders for the same package object. +_BUILDERS = {} + + +def builder(build_system_name): + """Class decorator used to register the default builder + for a given build-system. + + Args: + build_system_name (str): name of the build-system + """ + + def _decorator(cls): + cls.build_system = build_system_name + BUILDER_CLS[build_system_name] = cls + return cls + + return _decorator + + +def create(pkg): + """Given a package object with an associated concrete spec, + return the builder object that can install it. + + Args: + pkg (spack.package_base.PackageBase): package for which we want the builder + """ + if id(pkg) not in _BUILDERS: + _BUILDERS[id(pkg)] = _create(pkg) + return _BUILDERS[id(pkg)] + + +class _PhaseAdapter(object): + def __init__(self, builder, phase_fn): + self.builder = builder + self.phase_fn = phase_fn + + def __call__(self, spec, prefix): + return self.phase_fn(self.builder.pkg, spec, prefix) + + +def _create(pkg): + """Return a new builder object for the package object being passed as argument. + + The function inspects the build-system used by the package object and try to: + + 1. Return a custom builder, if any is defined in the same ``package.py`` file. + 2. Return a customization of more generic builders, if any is defined in the + class hierarchy (look at AspellDictPackage for an example of that) + 3. Return a run-time generated adapter builder otherwise + + The run-time generated adapter builder is capable of adapting an old-style package + to the new architecture, where the installation procedure has been extracted from + the ``*Package`` hierarchy into a ``*Builder`` hierarchy. This means that the + adapter looks for attribute or method overrides preferably in the ``*Package`` + before using the default builder implementation. + + Note that in case a builder is explicitly coded in ``package.py``, no attempt is made + to look for build-related methods in the ``*Package``. + + Args: + pkg (spack.package_base.PackageBase): package object for which we need a builder + """ + package_module = inspect.getmodule(pkg) + package_buildsystem = buildsystem_name(pkg) + default_builder_cls = BUILDER_CLS[package_buildsystem] + builder_cls_name = default_builder_cls.__name__ + builder_cls = getattr(package_module, builder_cls_name, None) + if builder_cls: + return builder_cls(pkg) + + # Specialized version of a given buildsystem can subclass some + # base classes and specialize certain phases or methods or attributes. + # In that case they can store their builder class as a class level attribute. + # See e.g. AspellDictPackage as an example. + base_cls = getattr(pkg, builder_cls_name, default_builder_cls) + + # From here on we define classes to construct a special builder that adapts to the + # old, single class, package format. The adapter forwards any call or access to an + # attribute related to the installation procedure to a package object wrapped in + # a class that falls-back on calling the base builder if no override is found on the + # package. The semantic should be the same as the method in the base builder were still + # present in the base class of the package. + + class _ForwardToBaseBuilder(object): + def __init__(self, wrapped_pkg_object, root_builder): + self.wrapped_package_object = wrapped_pkg_object + self.root_builder = root_builder + + package_cls = type(wrapped_pkg_object) + wrapper_cls = type(self) + bases = (package_cls, wrapper_cls) + new_cls_name = package_cls.__name__ + "Wrapper" + new_cls = type(new_cls_name, bases, {}) + new_cls.__module__ = package_cls.__module__ + self.__class__ = new_cls + self.__dict__.update(wrapped_pkg_object.__dict__) + + def __getattr__(self, item): + result = getattr(super(type(self.root_builder), self.root_builder), item) + if item in super(type(self.root_builder), self.root_builder).phases: + result = _PhaseAdapter(self.root_builder, result) + return result + + def forward_method_to_getattr(fn_name): + def __forward(self, *args, **kwargs): + return self.__getattr__(fn_name)(*args, **kwargs) + + return __forward + + # Add fallback methods for the Package object to refer to the builder. If a method + # with the same name is defined in the Package, it will override this definition + # (when _ForwardToBaseBuilder is initialized) + for method_name in ( + base_cls.phases + + base_cls.legacy_methods + + getattr(base_cls, "legacy_long_methods", tuple()) + + ("setup_build_environment", "setup_dependent_build_environment") + ): + setattr(_ForwardToBaseBuilder, method_name, forward_method_to_getattr(method_name)) + + def forward_property_to_getattr(property_name): + def __forward(self): + return self.__getattr__(property_name) + + return __forward + + for attribute_name in base_cls.legacy_attributes: + setattr( + _ForwardToBaseBuilder, + attribute_name, + property(forward_property_to_getattr(attribute_name)), + ) + + class Adapter(six.with_metaclass(_PackageAdapterMeta, base_cls)): + def __init__(self, pkg): + # Deal with custom phases in packages here + if hasattr(pkg, "phases"): + self.phases = pkg.phases + for phase in self.phases: + setattr(Adapter, phase, _PackageAdapterMeta.phase_method_adapter(phase)) + + # Attribute containing the package wrapped in dispatcher with a `__getattr__` + # method that will forward certain calls to the default builder. + self.pkg_with_dispatcher = _ForwardToBaseBuilder(pkg, root_builder=self) + super(Adapter, self).__init__(pkg) + + # These two methods don't follow the (self, spec, prefix) signature of phases nor + # the (self) signature of methods, so they are added explicitly to avoid using a + # catch-all (*args, **kwargs) + def setup_build_environment(self, env): + return self.pkg_with_dispatcher.setup_build_environment(env) + + def setup_dependent_build_environment(self, env, dependent_spec): + return self.pkg_with_dispatcher.setup_dependent_build_environment(env, dependent_spec) + + return Adapter(pkg) + + +def buildsystem_name(pkg): + """Given a package object with an associated concrete spec, + return the name of its build system. + + Args: + pkg (spack.package_base.PackageBase): package for which we want + the build system name + """ + try: + return pkg.spec.variants["build_system"].value + except KeyError: + # We are reading an old spec without the build_system variant + return pkg.legacy_buildsystem + + +class PhaseCallbacksMeta(type): + """Permit to register arbitrary functions during class definition and run them + later, before or after a given install phase. + + Each method decorated with ``run_before`` or ``run_after`` gets temporarily + stored in a global shared state when a class being defined is parsed by the Python + interpreter. At class definition time that temporary storage gets flushed and a list + of callbacks is attached to the class being defined. + """ + + def __new__(mcs, name, bases, attr_dict): + for temporary_stage in (_RUN_BEFORE, _RUN_AFTER): + staged_callbacks = temporary_stage.callbacks + + # We don't have callbacks in this class, move on + if not staged_callbacks: + continue + + # If we are here we have callbacks. To get a complete list, get first what + # was attached to parent classes, then prepend what we have registered here. + # + # The order should be: + # 1. Callbacks are registered in order within the same class + # 2. Callbacks defined in derived classes precede those defined in base + # classes + for base in bases: + callbacks_from_base = getattr(base, temporary_stage.attribute_name, None) + if callbacks_from_base: + break + callbacks_from_base = callbacks_from_base or [] + + # Set the callbacks in this class and flush the temporary stage + attr_dict[temporary_stage.attribute_name] = staged_callbacks[:] + callbacks_from_base + del temporary_stage.callbacks[:] + + return super(PhaseCallbacksMeta, mcs).__new__(mcs, name, bases, attr_dict) + + @staticmethod + def run_after(phase, when=None): + """Decorator to register a function for running after a given phase. + + Args: + phase (str): phase after which the function must run. + when (str): condition under which the function is run (if None, it is always run). + """ + + def _decorator(fn): + key = (phase, when) + item = (key, fn) + _RUN_AFTER.callbacks.append(item) + return fn + + return _decorator + + @staticmethod + def run_before(phase, when=None): + """Decorator to register a function for running before a given phase. + + Args: + phase (str): phase before which the function must run. + when (str): condition under which the function is run (if None, it is always run). + """ + + def _decorator(fn): + key = (phase, when) + item = (key, fn) + _RUN_BEFORE.callbacks.append(item) + return fn + + return _decorator + + +class BuilderMeta(PhaseCallbacksMeta, type(llnl.util.compat.Sequence)): # type: ignore + pass + + +class _PackageAdapterMeta(BuilderMeta): + """Metaclass to adapt old-style packages to the new architecture based on builders + for the installation phase. + + This class does the necessary mangling to function argument so that a call to a + builder object can delegate to a package object. + """ + + @staticmethod + def phase_method_adapter(phase_name): + def _adapter(self, pkg, spec, prefix): + phase_fn = getattr(self.pkg_with_dispatcher, phase_name) + return phase_fn(spec, prefix) + + return _adapter + + @staticmethod + def legacy_long_method_adapter(method_name): + def _adapter(self, spec, prefix): + bind_method = getattr(self.pkg_with_dispatcher, method_name) + return bind_method(spec, prefix) + + return _adapter + + @staticmethod + def legacy_method_adapter(method_name): + def _adapter(self): + bind_method = getattr(self.pkg_with_dispatcher, method_name) + return bind_method() + + return _adapter + + @staticmethod + def legacy_attribute_adapter(attribute_name): + def _adapter(self): + return getattr(self.pkg_with_dispatcher, attribute_name) + + return property(_adapter) + + @staticmethod + def combine_callbacks(pipeline_attribute_name): + """This function combines callbacks from old-style packages with callbacks that might + be registered for the default builder. + + It works by: + 1. Extracting the callbacks from the old-style package + 2. Transforming those callbacks by adding an adapter that receives a builder as argument + and calls the wrapped function with ``builder.pkg`` + 3. Combining the list of transformed callbacks with those that might be present in the + default builder + """ + + def _adapter(self): + def unwrap_pkg(fn): + @functools.wraps(fn) + def _wrapped(builder): + return fn(builder.pkg_with_dispatcher) + + return _wrapped + + # Concatenate the current list with the one from package + callbacks_from_package = getattr(self.pkg, pipeline_attribute_name, []) + callbacks_from_package = [(key, unwrap_pkg(x)) for key, x in callbacks_from_package] + callbacks_from_builder = getattr(super(type(self), self), pipeline_attribute_name, []) + return callbacks_from_package + callbacks_from_builder + + return property(_adapter) + + def __new__(mcs, name, bases, attr_dict): + # Add ways to intercept methods and attribute calls and dispatch + # them first to a package object + default_builder_cls = bases[0] + for phase_name in default_builder_cls.phases: + attr_dict[phase_name] = _PackageAdapterMeta.phase_method_adapter(phase_name) + + for method_name in default_builder_cls.legacy_methods: + attr_dict[method_name] = _PackageAdapterMeta.legacy_method_adapter(method_name) + + # These exist e.g. for Python, see discussion in https://github.com/spack/spack/pull/32068 + for method_name in getattr(default_builder_cls, "legacy_long_methods", []): + attr_dict[method_name] = _PackageAdapterMeta.legacy_long_method_adapter(method_name) + + for attribute_name in default_builder_cls.legacy_attributes: + attr_dict[attribute_name] = _PackageAdapterMeta.legacy_attribute_adapter( + attribute_name + ) + + combine_callbacks = _PackageAdapterMeta.combine_callbacks + attr_dict[_RUN_BEFORE.attribute_name] = combine_callbacks(_RUN_BEFORE.attribute_name) + attr_dict[_RUN_AFTER.attribute_name] = combine_callbacks(_RUN_AFTER.attribute_name) + + return super(_PackageAdapterMeta, mcs).__new__(mcs, name, bases, attr_dict) + + +class InstallationPhase(object): + """Manages a single phase of the installation. + + This descriptor stores at creation time the name of the method it should + search for execution. The method is retrieved at __get__ time, so that + it can be overridden by subclasses of whatever class declared the phases. + + It also provides hooks to execute arbitrary callbacks before and after + the phase. + """ + + def __init__(self, name, builder): + self.name = name + self.builder = builder + self.phase_fn = self._select_phase_fn() + self.run_before = self._make_callbacks(_RUN_BEFORE.attribute_name) + self.run_after = self._make_callbacks(_RUN_AFTER.attribute_name) + + def _make_callbacks(self, callbacks_attribute): + result = [] + callbacks = getattr(self.builder, callbacks_attribute, []) + for (phase, condition), fn in callbacks: + # Same if it is for another phase + if phase != self.name: + continue + + # If we have no condition or the callback satisfies a condition, register it + if condition is None or self.builder.pkg.spec.satisfies(condition): + result.append(fn) + return result + + def __str__(self): + msg = '{0}: executing "{1}" phase' + return msg.format(self.builder, self.name) + + def execute(self): + pkg = self.builder.pkg + self._on_phase_start(pkg) + + for callback in self.run_before: + callback(self.builder) + + self.phase_fn(pkg, pkg.spec, pkg.prefix) + + for callback in self.run_after: + callback(self.builder) + + self._on_phase_exit(pkg) + + def _select_phase_fn(self): + phase_fn = getattr(self.builder, self.name, None) + + if not phase_fn: + msg = ( + 'unexpected error: package "{0.fullname}" must implement an ' + '"{1}" phase for the "{2}" build system' + ) + raise RuntimeError(msg.format(self.builder.pkg, self.name, self.builder.build_system)) + + return phase_fn + + def _on_phase_start(self, instance): + # If a phase has a matching stop_before_phase attribute, + # stop the installation process raising a StopPhase + if getattr(instance, "stop_before_phase", None) == self.name: + raise spack.build_environment.StopPhase( + "Stopping before '{0}' phase".format(self.name) + ) + + def _on_phase_exit(self, instance): + # If a phase has a matching last_phase attribute, + # stop the installation process raising a StopPhase + if getattr(instance, "last_phase", None) == self.name: + raise spack.build_environment.StopPhase("Stopping at '{0}' phase".format(self.name)) + + def copy(self): + return copy.deepcopy(self) + + +class Builder(six.with_metaclass(BuilderMeta, llnl.util.compat.Sequence)): + """A builder is a class that, given a package object (i.e. associated with + concrete spec), knows how to install it. + + The builder behaves like a sequence, and when iterated over return the + "phases" of the installation in the correct order. + + Args: + pkg (spack.package_base.PackageBase): package object to be built + """ + + #: Sequence of phases. Must be defined in derived classes + phases = None # type: Optional[Tuple[str, ...]] + #: Build system name. Must also be defined in derived classes. + build_system = None # type: Optional[str] + + legacy_methods = () # type: Tuple[str, ...] + legacy_attributes = () # type: Tuple[str, ...] + + #: List of glob expressions. Each expression must either be + #: absolute or relative to the package source path. + #: Matching artifacts found at the end of the build process will be + #: copied in the same directory tree as _spack_build_logfile and + #: _spack_build_envfile. + archive_files = [] # type: List[str] + + def __init__(self, pkg): + self.pkg = pkg + self.callbacks = {} + for phase in self.phases: + self.callbacks[phase] = InstallationPhase(phase, self) + + @property + def spec(self): + return self.pkg.spec + + @property + def stage(self): + return self.pkg.stage + + @property + def prefix(self): + return self.pkg.prefix + + def test(self): + # Defer tests to virtual and concrete packages + pass + + def setup_build_environment(self, env): + """Sets up the build environment for a package. + + This method will be called before the current package prefix exists in + Spack's store. + + Args: + env (spack.util.environment.EnvironmentModifications): environment + modifications to be applied when the package is built. Package authors + can call methods on it to alter the build environment. + """ + if not hasattr(super(Builder, self), "setup_build_environment"): + return + super(Builder, self).setup_build_environment(env) + + def setup_dependent_build_environment(self, env, dependent_spec): + """Sets up the build environment of packages that depend on this one. + + This is similar to ``setup_build_environment``, but it is used to + modify the build environments of packages that *depend* on this one. + + This gives packages like Python and others that follow the extension + model a way to implement common environment or compile-time settings + for dependencies. + + This method will be called before the dependent package prefix exists + in Spack's store. + + Examples: + 1. Installing python modules generally requires ``PYTHONPATH`` + to point to the ``lib/pythonX.Y/site-packages`` directory in the + module's install prefix. This method could be used to set that + variable. + + Args: + env (spack.util.environment.EnvironmentModifications): environment + modifications to be applied when the dependent package is built. + Package authors can call methods on it to alter the build environment. + + dependent_spec (spack.spec.Spec): the spec of the dependent package + about to be built. This allows the extendee (self) to query + the dependent's state. Note that *this* package's spec is + available as ``self.spec`` + """ + if not hasattr(super(Builder, self), "setup_dependent_build_environment"): + return + super(Builder, self).setup_dependent_build_environment(env, dependent_spec) + + def __getitem__(self, idx): + key = self.phases[idx] + return self.callbacks[key] + + def __len__(self): + return len(self.phases) + + def __repr__(self): + msg = "{0}({1})" + return msg.format(type(self).__name__, self.pkg.spec.format("{name}/{hash:7}")) + + def __str__(self): + msg = '"{0}" builder for "{1}"' + return msg.format(type(self).build_system, self.pkg.spec.format("{name}/{hash:7}")) + + +# Export these names as standalone to be used in packages +run_after = PhaseCallbacksMeta.run_after +run_before = PhaseCallbacksMeta.run_before diff --git a/lib/spack/spack/cmd/info.py b/lib/spack/spack/cmd/info.py index ce69d98dbbe..6a16a153eac 100644 --- a/lib/spack/spack/cmd/info.py +++ b/lib/spack/spack/cmd/info.py @@ -210,11 +210,11 @@ def print_maintainers(pkg): def print_phases(pkg): """output installation phases""" - if hasattr(pkg, "phases") and pkg.phases: + if hasattr(pkg.builder, "phases") and pkg.builder.phases: color.cprint("") color.cprint(section_title("Installation Phases:")) phase_str = "" - for phase in pkg.phases: + for phase in pkg.builder.phases: phase_str += " {0}".format(phase) color.cprint(phase_str) diff --git a/lib/spack/spack/cmd/uninstall.py b/lib/spack/spack/cmd/uninstall.py index be4b74c54ad..af85b64188b 100644 --- a/lib/spack/spack/cmd/uninstall.py +++ b/lib/spack/spack/cmd/uninstall.py @@ -228,7 +228,7 @@ def do_uninstall(env, specs, force): except spack.repo.UnknownEntityError: # The package.py file has gone away -- but still # want to uninstall. - spack.package_base.Package.uninstall_by_spec(item, force=True) + spack.package_base.PackageBase.uninstall_by_spec(item, force=True) # A package is ready to be uninstalled when nothing else references it, # unless we are requested to force uninstall it. diff --git a/lib/spack/spack/detection/common.py b/lib/spack/spack/detection/common.py index d79b62b8725..b9cd871fc24 100644 --- a/lib/spack/spack/detection/common.py +++ b/lib/spack/spack/detection/common.py @@ -228,7 +228,7 @@ def compute_windows_program_path_for_package(pkg): program files location, return list of best guesses Args: - pkg (spack.package_base.Package): package for which + pkg (spack.package_base.PackageBase): package for which Program Files location is to be computed """ if not is_windows: diff --git a/lib/spack/spack/directives.py b/lib/spack/spack/directives.py index c7491861eb9..7c49158c791 100644 --- a/lib/spack/spack/directives.py +++ b/lib/spack/spack/directives.py @@ -17,6 +17,7 @@ class OpenMpi(Package): The available directives are: + * ``build_system`` * ``conflicts`` * ``depends_on`` * ``extends`` @@ -59,13 +60,15 @@ class OpenMpi(Package): "patch", "variant", "resource", + "build_system", ] #: These are variant names used by Spack internally; packages can't use them reserved_names = ["patches", "dev_path"] -#: Names of possible directives. This list is populated elsewhere in the file. -directive_names = [] +#: Names of possible directives. This list is mostly populated using the @directive decorator. +#: Some directives leverage others and in that case are not automatically added. +directive_names = ["build_system"] _patch_order_index = 0 @@ -758,6 +761,17 @@ def _execute_resource(pkg): return _execute_resource +def build_system(*values, **kwargs): + default = kwargs.get("default", None) or values[0] + return variant( + "build_system", + values=tuple(values), + description="Build systems supported by the package", + default=default, + multi=False, + ) + + class DirectiveError(spack.error.SpackError): """This is raised when something is wrong with a package directive.""" diff --git a/lib/spack/spack/installer.py b/lib/spack/spack/installer.py index 411c076aa81..620f489c775 100644 --- a/lib/spack/spack/installer.py +++ b/lib/spack/spack/installer.py @@ -112,14 +112,15 @@ def _check_last_phase(pkg): Raises: ``BadInstallPhase`` if stop_before or last phase is invalid """ - if pkg.stop_before_phase and pkg.stop_before_phase not in pkg.phases: + phases = pkg.builder.phases + if pkg.stop_before_phase and pkg.stop_before_phase not in phases: raise BadInstallPhase(pkg.name, pkg.stop_before_phase) - if pkg.last_phase and pkg.last_phase not in pkg.phases: + if pkg.last_phase and pkg.last_phase not in phases: raise BadInstallPhase(pkg.name, pkg.last_phase) # If we got a last_phase, make sure it's not already last - if pkg.last_phase and pkg.last_phase == pkg.phases[-1]: + if pkg.last_phase and pkg.last_phase == phases[-1]: pkg.last_phase = None @@ -129,7 +130,7 @@ def _handle_external_and_upstream(pkg, explicit): database if it is external package. Args: - pkg (spack.package_base.Package): the package whose installation is under + pkg (spack.package_base.PackageBase): the package whose installation is under consideration explicit (bool): the package was explicitly requested by the user Return: @@ -559,7 +560,7 @@ def log(pkg): Copy provenance into the install directory on success Args: - pkg (spack.package_base.Package): the package that was built and installed + pkg (spack.package_base.PackageBase): the package that was built and installed """ packages_dir = spack.store.layout.build_packages_path(pkg.spec) @@ -596,7 +597,7 @@ def log(pkg): errors = six.StringIO() target_dir = os.path.join(spack.store.layout.metadata_path(pkg.spec), "archived-files") - for glob_expr in pkg.archive_files: + for glob_expr in pkg.builder.archive_files: # Check that we are trying to copy things that are # in the stage tree (not arbitrary files) abs_expr = os.path.realpath(glob_expr) @@ -810,7 +811,7 @@ def _add_init_task(self, pkg, request, is_compiler, all_deps): Creates and queus the initial build task for the package. Args: - pkg (spack.package_base.Package): the package to be built and installed + pkg (spack.package_base.PackageBase): the package to be built and installed request (BuildRequest or None): the associated install request where ``None`` can be used to indicate the package was explicitly requested by the user @@ -1404,7 +1405,7 @@ def _setup_install_dir(self, pkg): Write a small metadata file with the current spack environment. Args: - pkg (spack.package_base.Package): the package to be built and installed + pkg (spack.package_base.PackageBase): the package to be built and installed """ if not os.path.exists(pkg.spec.prefix): path = spack.util.path.debug_padded_filter(pkg.spec.prefix) @@ -1477,8 +1478,8 @@ def _flag_installed(self, pkg, dependent_ids=None): known dependents. Args: - pkg (spack.package_base.Package): Package that has been installed locally, - externally or upstream + pkg (spack.package_base.PackageBase): Package that has been installed + locally, externally or upstream dependent_ids (list or None): list of the package's dependent ids, or None if the dependent ids are limited to those maintained in the package (dependency DAG) @@ -1562,11 +1563,7 @@ def _install_action(self, task): return InstallAction.OVERWRITE def install(self): - """ - Install the requested package(s) and or associated dependencies. - - Args: - pkg (spack.package_base.Package): the package to be built and installed""" + """Install the requested package(s) and or associated dependencies.""" self._init_queue() fail_fast_err = "Terminating after first install failure" @@ -1951,6 +1948,8 @@ def _install_source(self): fs.install_tree(pkg.stage.source_path, src_target) def _real_install(self): + import spack.builder + pkg = self.pkg # Do the real install in the source directory. @@ -1981,13 +1980,11 @@ def _real_install(self): # Spawn a daemon that reads from a pipe and redirects # everything to log_path, and provide the phase for logging - for i, (phase_name, phase_attr) in enumerate( - zip(pkg.phases, pkg._InstallPhase_phases) - ): - + builder = spack.builder.create(pkg) + for i, phase_fn in enumerate(builder): # Keep a log file for each phase log_dir = os.path.dirname(pkg.log_path) - log_file = "spack-build-%02d-%s-out.txt" % (i + 1, phase_name.lower()) + log_file = "spack-build-%02d-%s-out.txt" % (i + 1, phase_fn.name.lower()) log_file = os.path.join(log_dir, log_file) try: @@ -2005,20 +2002,20 @@ def _real_install(self): with logger.force_echo(): inner_debug_level = tty.debug_level() tty.set_debug(debug_level) - tty.msg("{0} Executing phase: '{1}'".format(self.pre, phase_name)) + msg = "{0} Executing phase: '{1}'" + tty.msg(msg.format(self.pre, phase_fn.name)) tty.set_debug(inner_debug_level) # Redirect stdout and stderr to daemon pipe - phase = getattr(pkg, phase_attr) - self.timer.phase(phase_name) + self.timer.phase(phase_fn.name) # Catch any errors to report to logging - phase(pkg.spec, pkg.prefix) - spack.hooks.on_phase_success(pkg, phase_name, log_file) + phase_fn.execute() + spack.hooks.on_phase_success(pkg, phase_fn.name, log_file) except BaseException: combine_phase_logs(pkg.phase_log_files, pkg.log_path) - spack.hooks.on_phase_error(pkg, phase_name, log_file) + spack.hooks.on_phase_error(pkg, phase_fn.name, log_file) # phase error indicates install error spack.hooks.on_install_failure(pkg.spec) @@ -2094,7 +2091,7 @@ def __init__(self, pkg, request, compiler, start, attempts, status, installed): Instantiate a build task for a package. Args: - pkg (spack.package_base.Package): the package to be built and installed + pkg (spack.package_base.PackageBase): the package to be built and installed request (BuildRequest or None): the associated install request where ``None`` can be used to indicate the package was explicitly requested by the user @@ -2310,7 +2307,7 @@ def __init__(self, pkg, install_args): Instantiate a build request for a package. Args: - pkg (spack.package_base.Package): the package to be built and installed + pkg (spack.package_base.PackageBase): the package to be built and installed install_args (dict): the install arguments associated with ``pkg`` """ # Ensure dealing with a package that has a concrete spec diff --git a/lib/spack/spack/mixins.py b/lib/spack/spack/mixins.py index ace3681e527..b43b85aa026 100644 --- a/lib/spack/spack/mixins.py +++ b/lib/spack/spack/mixins.py @@ -6,10 +6,9 @@ """This module contains additional behavior that can be attached to any given package. """ -import collections import os import sys -from typing import Callable, DefaultDict, Dict, List # novm +from typing import Callable, DefaultDict, List # novm if sys.version_info >= (3, 5): CallbackDict = DefaultDict[str, List[Callable]] @@ -18,105 +17,7 @@ import llnl.util.filesystem -__all__ = [ - "filter_compiler_wrappers", - "PackageMixinsMeta", -] - - -class PackageMixinsMeta(type): - """This metaclass serves the purpose of implementing a declarative syntax - for package mixins. - - Mixins are implemented below in the form of a function. Each one of them - needs to register a callable that takes a single argument to be run - before or after a certain phase. This callable is basically a method that - gets implicitly attached to the package class by calling the mixin. - """ - - _methods_to_be_added = {} # type: Dict[str, Callable] - _add_method_before = collections.defaultdict(list) # type: CallbackDict - _add_method_after = collections.defaultdict(list) # type: CallbackDict - - @staticmethod - def register_method_before(fn, phase): # type: (Callable, str) -> None - """Registers a method to be run before a certain phase. - - Args: - fn: function taking a single argument (self) - phase (str): phase before which fn must run - """ - PackageMixinsMeta._methods_to_be_added[fn.__name__] = fn - PackageMixinsMeta._add_method_before[phase].append(fn) - - @staticmethod - def register_method_after(fn, phase): # type: (Callable, str) -> None - """Registers a method to be run after a certain phase. - - Args: - fn: function taking a single argument (self) - phase (str): phase after which fn must run - """ - PackageMixinsMeta._methods_to_be_added[fn.__name__] = fn - PackageMixinsMeta._add_method_after[phase].append(fn) - - def __init__(cls, name, bases, attr_dict): - - # Add the methods to the class being created - if PackageMixinsMeta._methods_to_be_added: - attr_dict.update(PackageMixinsMeta._methods_to_be_added) - PackageMixinsMeta._methods_to_be_added.clear() - - attr_fmt = "_InstallPhase_{0}" - - # Copy the phases that needs it to the most derived classes - # in order not to interfere with other packages in the hierarchy - phases_to_be_copied = list(PackageMixinsMeta._add_method_before.keys()) - phases_to_be_copied += list(PackageMixinsMeta._add_method_after.keys()) - - for phase in phases_to_be_copied: - - attr_name = attr_fmt.format(phase) - - # Here we want to get the attribute directly from the class (not - # from the instance), so that we can modify it and add the mixin - # method to the pipeline. - phase = getattr(cls, attr_name) - - # Due to MRO, we may have taken a method from a parent class - # and modifying it may influence other packages in unwanted - # manners. Solve the problem by copying the phase into the most - # derived class. - setattr(cls, attr_name, phase.copy()) - - # Insert the methods in the appropriate position - # in the installation pipeline. - - for phase in PackageMixinsMeta._add_method_before: - - attr_name = attr_fmt.format(phase) - phase_obj = getattr(cls, attr_name) - fn_list = PackageMixinsMeta._add_method_after[phase] - - for f in fn_list: - phase_obj.run_before.append(f) - - # Flush the dictionary for the next class - PackageMixinsMeta._add_method_before.clear() - - for phase in PackageMixinsMeta._add_method_after: - - attr_name = attr_fmt.format(phase) - phase_obj = getattr(cls, attr_name) - fn_list = PackageMixinsMeta._add_method_after[phase] - - for f in fn_list: - phase_obj.run_after.append(f) - - # Flush the dictionary for the next class - PackageMixinsMeta._add_method_after.clear() - - super(PackageMixinsMeta, cls).__init__(name, bases, attr_dict) +import spack.builder def filter_compiler_wrappers(*files, **kwargs): @@ -216,4 +117,4 @@ def _filter_compiler_wrappers_impl(self): if self.compiler.name == "nag": x.filter("-Wl,--enable-new-dtags", "", **filter_kwargs) - PackageMixinsMeta.register_method_after(_filter_compiler_wrappers_impl, after) + spack.builder.run_after(after)(_filter_compiler_wrappers_impl) diff --git a/lib/spack/spack/multimethod.py b/lib/spack/spack/multimethod.py index 2c6a56db1a5..66f7a887f33 100644 --- a/lib/spack/spack/multimethod.py +++ b/lib/spack/spack/multimethod.py @@ -120,32 +120,36 @@ def _get_method_by_spec(self, spec): return method return self.default or None - def __call__(self, package_self, *args, **kwargs): + def __call__(self, package_or_builder_self, *args, **kwargs): """Find the first method with a spec that matches the package's spec. If none is found, call the default or if there is none, then raise a NoSuchMethodError. """ - spec_method = self._get_method_by_spec(package_self.spec) + spec_method = self._get_method_by_spec(package_or_builder_self.spec) if spec_method: - return spec_method(package_self, *args, **kwargs) + return spec_method(package_or_builder_self, *args, **kwargs) # Unwrap the MRO of `package_self by hand. Note that we can't # use `super()` here, because using `super()` recursively # requires us to know the class of `package_self`, as well as # its superclasses for successive calls. We don't have that # information within `SpecMultiMethod`, because it is not # associated with the package class. - for cls in inspect.getmro(package_self.__class__)[1:]: + for cls in inspect.getmro(package_or_builder_self.__class__)[1:]: superself = cls.__dict__.get(self.__name__, None) + if isinstance(superself, SpecMultiMethod): # Check parent multimethod for method for spec. - superself_method = superself._get_method_by_spec(package_self.spec) + superself_method = superself._get_method_by_spec(package_or_builder_self.spec) if superself_method: - return superself_method(package_self, *args, **kwargs) + return superself_method(package_or_builder_self, *args, **kwargs) elif superself: - return superself(package_self, *args, **kwargs) + return superself(package_or_builder_self, *args, **kwargs) raise NoSuchMethodError( - type(package_self), self.__name__, package_self.spec, [m[0] for m in self.method_list] + type(package_or_builder_self), + self.__name__, + package_or_builder_self.spec, + [m[0] for m in self.method_list], ) diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index 65e699bda4b..46c9da48440 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -17,6 +17,7 @@ import spack.util.executable from spack.build_systems.aspell_dict import AspellDictPackage from spack.build_systems.autotools import AutotoolsPackage +from spack.build_systems.bundle import BundlePackage from spack.build_systems.cached_cmake import ( CachedCMakePackage, cmake_cache_option, @@ -25,12 +26,14 @@ ) from spack.build_systems.cmake import CMakePackage from spack.build_systems.cuda import CudaPackage +from spack.build_systems.generic import Package from spack.build_systems.gnu import GNUMirrorPackage from spack.build_systems.intel import IntelPackage from spack.build_systems.lua import LuaPackage from spack.build_systems.makefile import MakefilePackage from spack.build_systems.maven import MavenPackage from spack.build_systems.meson import MesonPackage +from spack.build_systems.nmake import NMakePackage from spack.build_systems.octave import OctavePackage from spack.build_systems.oneapi import ( IntelOneApiLibraryPackage, @@ -38,7 +41,7 @@ IntelOneApiStaticLibraryList, ) from spack.build_systems.perl import PerlPackage -from spack.build_systems.python import PythonPackage +from spack.build_systems.python import PythonExtension, PythonPackage from spack.build_systems.qmake import QMakePackage from spack.build_systems.r import RPackage from spack.build_systems.racket import RacketPackage @@ -50,6 +53,7 @@ from spack.build_systems.sourceware import SourcewarePackage from spack.build_systems.waf import WafPackage from spack.build_systems.xorg import XorgPackage +from spack.builder import run_after, run_before from spack.dependency import all_deptypes from spack.directives import * from spack.install_test import get_escaped_text_output @@ -62,17 +66,13 @@ from spack.mixins import filter_compiler_wrappers from spack.multimethod import when from spack.package_base import ( - BundlePackage, DependencyConflictError, - Package, build_system_flags, env_flags, flatten_dependencies, inject_flags, install_dependency_symlinks, on_package_attributes, - run_after, - run_before, ) from spack.spec import InvalidSpecDetected, Spec from spack.util.executable import * diff --git a/lib/spack/spack/package_base.py b/lib/spack/spack/package_base.py index f05c0ff8689..3c3bcaa84db 100644 --- a/lib/spack/spack/package_base.py +++ b/lib/spack/spack/package_base.py @@ -33,7 +33,7 @@ import llnl.util.filesystem as fsys import llnl.util.tty as tty -from llnl.util.lang import classproperty, match_predicate, memoized, nullcontext +from llnl.util.lang import classproperty, memoized, nullcontext from llnl.util.link_tree import LinkTree import spack.compilers @@ -104,7 +104,7 @@ def deprecated_version(pkg, version): """Return True if the version is deprecated, False otherwise. Arguments: - pkg (Package): The package whose version is to be checked. + pkg (PackageBase): The package whose version is to be checked. version (str or spack.version.VersionBase): The version being checked """ if not isinstance(version, VersionBase): @@ -122,7 +122,7 @@ def preferred_version(pkg): Returns a sorted list of the preferred versions of the package. Arguments: - pkg (Package): The package whose versions are to be assessed. + pkg (PackageBase): The package whose versions are to be assessed. """ # Here we sort first on the fact that a version is marked # as preferred in the package, then on the fact that the @@ -131,77 +131,6 @@ def preferred_version(pkg): return sorted(pkg.versions, key=key_fn).pop() -class InstallPhase(object): - """Manages a single phase of the installation. - - This descriptor stores at creation time the name of the method it should - search for execution. The method is retrieved at __get__ time, so that - it can be overridden by subclasses of whatever class declared the phases. - - It also provides hooks to execute arbitrary callbacks before and after - the phase. - """ - - def __init__(self, name): - self.name = name - self.run_before = [] - self.run_after = [] - - def __get__(self, instance, owner): - # The caller is a class that is trying to customize - # my behavior adding something - if instance is None: - return self - # If instance is there the caller wants to execute the - # install phase, thus return a properly set wrapper - phase = getattr(instance, self.name) - - @functools.wraps(phase) - def phase_wrapper(spec, prefix): - # Check instance attributes at the beginning of a phase - self._on_phase_start(instance) - # Execute phase pre-conditions, - # and give them the chance to fail - for callback in self.run_before: - callback(instance) - phase(spec, prefix) - # Execute phase sanity_checks, - # and give them the chance to fail - for callback in self.run_after: - callback(instance) - # Check instance attributes at the end of a phase - self._on_phase_exit(instance) - - return phase_wrapper - - def _on_phase_start(self, instance): - # If a phase has a matching stop_before_phase attribute, - # stop the installation process raising a StopPhase - if getattr(instance, "stop_before_phase", None) == self.name: - from spack.build_environment import StopPhase - - raise StopPhase("Stopping before '{0}' phase".format(self.name)) - - def _on_phase_exit(self, instance): - # If a phase has a matching last_phase attribute, - # stop the installation process raising a StopPhase - if getattr(instance, "last_phase", None) == self.name: - from spack.build_environment import StopPhase - - raise StopPhase("Stopping at '{0}' phase".format(self.name)) - - def copy(self): - try: - return copy.deepcopy(self) - except TypeError: - # This bug-fix was not back-ported in Python 2.6 - # http://bugs.python.org/issue1515 - other = InstallPhase(self.name) - other.run_before.extend(self.run_before) - other.run_after.extend(self.run_after) - return other - - class WindowsRPathMeta(object): """Collection of functionality surrounding Windows RPATH specific features @@ -368,23 +297,18 @@ def determine_variants(cls, objs, version_str): class PackageMeta( + spack.builder.PhaseCallbacksMeta, DetectablePackageMeta, spack.directives.DirectiveMeta, - spack.mixins.PackageMixinsMeta, spack.multimethod.MultiMethodMeta, ): """ Package metaclass for supporting directives (e.g., depends_on) and phases """ - phase_fmt = "_InstallPhase_{0}" - - # These are accessed only through getattr, by name - _InstallPhase_run_before = {} # type: Dict[str, List[Callable]] - _InstallPhase_run_after = {} # type: Dict[str, List[Callable]] - def __new__(cls, name, bases, attr_dict): """ + FIXME: REWRITE Instance creation is preceded by phase attribute transformations. Conveniently transforms attributes to permit extensible phases by @@ -392,70 +316,10 @@ def __new__(cls, name, bases, attr_dict): InstallPhase attributes in the class that will be initialized in __init__. """ - if "phases" in attr_dict: - # Turn the strings in 'phases' into InstallPhase instances - # and add them as private attributes - _InstallPhase_phases = [PackageMeta.phase_fmt.format(x) for x in attr_dict["phases"]] - for phase_name, callback_name in zip(_InstallPhase_phases, attr_dict["phases"]): - attr_dict[phase_name] = InstallPhase(callback_name) - attr_dict["_InstallPhase_phases"] = _InstallPhase_phases - - def _flush_callbacks(check_name): - # Name of the attribute I am going to check it exists - check_attr = PackageMeta.phase_fmt.format(check_name) - checks = getattr(cls, check_attr) - if checks: - for phase_name, funcs in checks.items(): - phase_attr = PackageMeta.phase_fmt.format(phase_name) - try: - # Search for the phase in the attribute dictionary - phase = attr_dict[phase_attr] - except KeyError: - # If it is not there it's in the bases - # and we added a check. We need to copy - # and extend - for base in bases: - phase = getattr(base, phase_attr, None) - if phase is not None: - break - - phase = attr_dict[phase_attr] = phase.copy() - getattr(phase, check_name).extend(funcs) - # Clear the attribute for the next class - setattr(cls, check_attr, {}) - - _flush_callbacks("run_before") - _flush_callbacks("run_after") - - # Reset names for packages that inherit from another - # package with a different name attr_dict["_name"] = None return super(PackageMeta, cls).__new__(cls, name, bases, attr_dict) - @staticmethod - def register_callback(check_type, *phases): - def _decorator(func): - attr_name = PackageMeta.phase_fmt.format(check_type) - check_list = getattr(PackageMeta, attr_name) - for item in phases: - checks = check_list.setdefault(item, []) - checks.append(func) - setattr(PackageMeta, attr_name, check_list) - return func - - return _decorator - - -def run_before(*phases): - """Registers a method of a package to be run before a given phase""" - return PackageMeta.register_callback("run_before", *phases) - - -def run_after(*phases): - """Registers a method of a package to be run after a given phase""" - return PackageMeta.register_callback("run_after", *phases) - def on_package_attributes(**attr_dict): """Decorator: executes instance function only if object has attr valuses. @@ -475,7 +339,9 @@ def _wrapper(instance, *args, **kwargs): has_all_attributes = all([hasattr(instance, key) for key in attr_dict]) if has_all_attributes: has_the_right_values = all( - [getattr(instance, key) == value for key, value in attr_dict.items()] + [ + getattr(instance, key) == value for key, value in attr_dict.items() + ] # NOQA: ignore=E501 ) if has_the_right_values: func(instance, *args, **kwargs) @@ -687,13 +553,6 @@ class PackageBase(six.with_metaclass(PackageMeta, WindowsRPathMeta, PackageViewM #: directories, sanity checks will fail. sanity_check_is_dir = [] # type: List[str] - #: List of glob expressions. Each expression must either be - #: absolute or relative to the package source path. - #: Matching artifacts found at the end of the build process will be - #: copied in the same directory tree as _spack_build_logfile and - #: _spack_build_envfile. - archive_files = [] # type: List[str] - #: Boolean. Set to ``True`` for packages that require a manual download. #: This is currently used by package sanity tests and generation of a #: more meaningful fetch failure error. @@ -1038,7 +897,7 @@ def all_urls_for_version(self, version): version (spack.version.Version): the version for which a URL is sought """ uf = None - if type(self).url_for_version != Package.url_for_version: + if type(self).url_for_version != PackageBase.url_for_version: uf = self.url_for_version return self._implement_all_urls_for_version(version, uf) @@ -1959,9 +1818,9 @@ def do_install(self, **kwargs): even with exceptions. restage (bool): Force spack to restage the package source. skip_patch (bool): Skip patch stage of build if True. - stop_before (InstallPhase): stop execution before this + stop_before (str): stop execution before this installation phase (or None) - stop_at (InstallPhase): last installation phase to be executed + stop_at (str): last installation phase to be executed (or None) tests (bool or list or set): False to run no tests, True to test all packages, or a list of package names to run tests for some @@ -2191,46 +2050,6 @@ def unit_test_check(self): """ return True - def sanity_check_prefix(self): - """This function checks whether install succeeded.""" - - def check_paths(path_list, filetype, predicate): - if isinstance(path_list, six.string_types): - path_list = [path_list] - - for path in path_list: - abs_path = os.path.join(self.prefix, path) - if not predicate(abs_path): - raise InstallError( - "Install failed for %s. No such %s in prefix: %s" - % (self.name, filetype, path) - ) - - check_paths(self.sanity_check_is_file, "file", os.path.isfile) - check_paths(self.sanity_check_is_dir, "directory", os.path.isdir) - - ignore_file = match_predicate(spack.store.layout.hidden_file_regexes) - if all(map(ignore_file, os.listdir(self.prefix))): - raise InstallError("Install failed for %s. Nothing was installed!" % self.name) - - def apply_macos_rpath_fixups(self): - """On Darwin, make installed libraries more easily relocatable. - - Some build systems (handrolled, autotools, makefiles) can set their own - rpaths that are duplicated by spack's compiler wrapper. This fixup - interrogates, and postprocesses if necessary, all libraries installed - by the code. - - It should be added as a @run_after to packaging systems (or individual - packages) that do not install relocatable libraries by default. - """ - if "platform=darwin" not in self.spec: - return - - from spack.relocate import fixup_macos_rpaths - - fixup_macos_rpaths(self.spec) - @property def build_log_path(self): """ @@ -2268,19 +2087,6 @@ def build_system_flags(cls, name, flags): """ return None, None, flags - def setup_build_environment(self, env): - """Sets up the build environment for a package. - - This method will be called before the current package prefix exists in - Spack's store. - - Args: - env (spack.util.environment.EnvironmentModifications): environment - modifications to be applied when the package is built. Package authors - can call methods on it to alter the build environment. - """ - pass - def setup_run_environment(self, env): """Sets up the run environment for a package. @@ -2291,37 +2097,6 @@ def setup_run_environment(self, env): """ pass - def setup_dependent_build_environment(self, env, dependent_spec): - """Sets up the build environment of packages that depend on this one. - - This is similar to ``setup_build_environment``, but it is used to - modify the build environments of packages that *depend* on this one. - - This gives packages like Python and others that follow the extension - model a way to implement common environment or compile-time settings - for dependencies. - - This method will be called before the dependent package prefix exists - in Spack's store. - - Examples: - 1. Installing python modules generally requires ``PYTHONPATH`` - to point to the ``lib/pythonX.Y/site-packages`` directory in the - module's install prefix. This method could be used to set that - variable. - - Args: - env (spack.util.environment.EnvironmentModifications): environment - modifications to be applied when the dependent package is built. - Package authors can call methods on it to alter the build environment. - - dependent_spec (spack.spec.Spec): the spec of the dependent package - about to be built. This allows the extendee (self) to query - the dependent's state. Note that *this* package's spec is - available as ``self.spec`` - """ - pass - def setup_dependent_run_environment(self, env, dependent_spec): """Sets up the run environment of packages that depend on this one. @@ -2508,7 +2283,7 @@ def uninstall_by_spec(spec, force=False, deprecator=None): def do_uninstall(self, force=False): """Uninstall this package by spec.""" # delegate to instance-less method. - Package.uninstall_by_spec(self.spec, force) + PackageBase.uninstall_by_spec(self.spec, force) def do_deprecate(self, deprecator, link_fn): """Deprecate this package in favor of deprecator spec""" @@ -2560,7 +2335,7 @@ def do_deprecate(self, deprecator, link_fn): deprecated.package.do_deprecate(deprecator, link_fn) # Now that we've handled metadata, uninstall and replace with link - Package.uninstall_by_spec(spec, force=True, deprecator=deprecator) + PackageBase.uninstall_by_spec(spec, force=True, deprecator=deprecator) link_fn(deprecator.prefix, spec.prefix) def _check_extendable(self): @@ -2811,21 +2586,25 @@ def rpath_args(self): """ return " ".join("-Wl,-rpath,%s" % p for p in self.rpath) - def _run_test_callbacks(self, method_names, callback_type="install"): + @property + def builder(self): + return spack.builder.create(self) + + @staticmethod + def run_test_callbacks(builder, method_names, callback_type="install"): """Tries to call all of the listed methods, returning immediately if the list is None.""" - if method_names is None: + if not builder.pkg.run_tests or method_names is None: return fail_fast = spack.config.get("config:fail_fast", False) - - with self._setup_test(verbose=False, externals=False) as logger: + with builder.pkg._setup_test(verbose=False, externals=False) as logger: # Report running each of the methods in the build log print_test_message(logger, "Running {0}-time tests".format(callback_type), True) for name in method_names: try: - fn = getattr(self, name) + fn = getattr(builder, name) msg = ("RUN-TESTS: {0}-time tests [{1}]".format(callback_type, name),) print_test_message(logger, msg, True) @@ -2835,27 +2614,13 @@ def _run_test_callbacks(self, method_names, callback_type="install"): msg = ("RUN-TESTS: method not implemented [{0}]".format(name),) print_test_message(logger, msg, True) - self.test_failures.append((e, msg)) + builder.pkg.test_failures.append((e, msg)) if fail_fast: break # Raise any collected failures here - if self.test_failures: - raise TestFailure(self.test_failures) - - @on_package_attributes(run_tests=True) - def _run_default_build_time_test_callbacks(self): - """Tries to call all the methods that are listed in the attribute - ``build_time_test_callbacks`` if ``self.run_tests is True``. - """ - self._run_test_callbacks(self.build_time_test_callbacks, "build") - - @on_package_attributes(run_tests=True) - def _run_default_install_time_test_callbacks(self): - """Tries to call all the methods that are listed in the attribute - ``install_time_test_callbacks`` if ``self.run_tests is True``. - """ - self._run_test_callbacks(self.install_time_test_callbacks, "install") + if builder.pkg.test_failures: + raise TestFailure(builder.pkg.test_failures) def has_test_method(pkg): @@ -2979,37 +2744,6 @@ def test_process(pkg, kwargs): build_system_flags = PackageBase.build_system_flags -class BundlePackage(PackageBase): - """General purpose bundle, or no-code, package class.""" - - #: There are no phases by default but the property is required to support - #: post-install hooks (e.g., for module generation). - phases = [] # type: List[str] - #: This attribute is used in UI queries that require to know which - #: build-system class we are using - build_system_class = "BundlePackage" - - #: Bundle packages do not have associated source or binary code. - has_code = False - - -class Package(PackageBase): - """General purpose class with a single ``install`` - phase that needs to be coded by packagers. - """ - - #: The one and only phase - phases = ["install"] - #: This attribute is used in UI queries that require to know which - #: build-system class we are using - build_system_class = "Package" - # This will be used as a registration decorator in user - # packages, if need be - run_after("install")(PackageBase.sanity_check_prefix) - # On macOS, force rpaths for shared library IDs and remove duplicate rpaths - run_after("install")(PackageBase.apply_macos_rpath_fixups) - - def install_dependency_symlinks(pkg, spec, prefix): """ Execute a dummy install and flatten dependencies. diff --git a/lib/spack/spack/patch.py b/lib/spack/spack/patch.py index 553b04fda92..06841fa73fd 100644 --- a/lib/spack/spack/patch.py +++ b/lib/spack/spack/patch.py @@ -352,7 +352,7 @@ def patch_for_package(self, sha256, pkg): Arguments: sha256 (str): sha256 hash to look up - pkg (spack.package_base.Package): Package object to get patch for. + pkg (spack.package_base.PackageBase): Package object to get patch for. We build patch objects lazily because building them requires that we have information about the package's location in its repo. diff --git a/lib/spack/spack/test/audit.py b/lib/spack/spack/test/audit.py index eded1a92f2c..bc5dd3edca6 100644 --- a/lib/spack/spack/test/audit.py +++ b/lib/spack/spack/test/audit.py @@ -22,7 +22,7 @@ # This package has a GitHub patch URL without full_index=1 (["invalid-github-patch-url"], ["PKG-DIRECTIVES", "PKG-PROPERTIES"]), # This package has a stand-alone 'test' method in build-time callbacks - (["test-build-callbacks"], ["PKG-DIRECTIVES", "PKG-PROPERTIES"]), + (["fail-test-audit"], ["PKG-DIRECTIVES", "PKG-PROPERTIES"]), # This package has no issues (["mpileaks"], None), # This package has a conflict with a trigger which cannot constrain the constraint diff --git a/lib/spack/spack/test/build_systems.py b/lib/spack/spack/test/build_systems.py index f660596bb7d..c4255eef49b 100644 --- a/lib/spack/spack/test/build_systems.py +++ b/lib/spack/spack/test/build_systems.py @@ -13,10 +13,11 @@ import llnl.util.filesystem as fs import spack.build_systems.autotools +import spack.build_systems.cmake import spack.environment import spack.platforms import spack.repo -from spack.build_environment import ChildError, get_std_cmake_args, setup_package +from spack.build_environment import ChildError, setup_package from spack.spec import Spec from spack.util.executable import which @@ -144,7 +145,7 @@ def test_libtool_archive_files_are_deleted_by_default(self, mutable_database): # Assert the libtool archive is not there and we have # a log of removed files - assert not os.path.exists(s.package.libtool_archive_file) + assert not os.path.exists(s.package.builder.libtool_archive_file) search_directory = os.path.join(s.prefix, ".spack") libtool_deletion_log = fs.find(search_directory, "removed_la_files.txt", recursive=True) assert libtool_deletion_log @@ -155,11 +156,11 @@ def test_libtool_archive_files_might_be_installed_on_demand( # Install a package that creates a mock libtool archive, # patch its package to preserve the installation s = Spec("libtool-deletion").concretized() - monkeypatch.setattr(s.package, "install_libtool_archives", True) + monkeypatch.setattr(type(s.package.builder), "install_libtool_archives", True) s.package.do_install(explicit=True) # Assert libtool archives are installed - assert os.path.exists(s.package.libtool_archive_file) + assert os.path.exists(s.package.builder.libtool_archive_file) def test_autotools_gnuconfig_replacement(self, mutable_database): """ @@ -253,22 +254,23 @@ class TestCMakePackage(object): def test_cmake_std_args(self): # Call the function on a CMakePackage instance s = Spec("cmake-client").concretized() - assert s.package.std_cmake_args == get_std_cmake_args(s.package) + expected = spack.build_systems.cmake.CMakeBuilder.std_args(s.package) + assert s.package.builder.std_cmake_args == expected # Call it on another kind of package s = Spec("mpich").concretized() - assert get_std_cmake_args(s.package) + assert spack.build_systems.cmake.CMakeBuilder.std_args(s.package) - def test_cmake_bad_generator(self): + def test_cmake_bad_generator(self, monkeypatch): s = Spec("cmake-client").concretized() - s.package.generator = "Yellow Sticky Notes" + monkeypatch.setattr(type(s.package), "generator", "Yellow Sticky Notes", raising=False) with pytest.raises(spack.package_base.InstallError): - get_std_cmake_args(s.package) + s.package.builder.std_cmake_args def test_cmake_secondary_generator(config, mock_packages): s = Spec("cmake-client").concretized() s.package.generator = "CodeBlocks - Unix Makefiles" - assert get_std_cmake_args(s.package) + assert s.package.builder.std_cmake_args def test_define(self): s = Spec("cmake-client").concretized() @@ -361,7 +363,7 @@ def test_autotools_args_from_conditional_variant(config, mock_packages): is not met. When this is the case, the variant is not set in the spec.""" s = Spec("autotools-conditional-variants-test").concretized() assert "example" not in s.variants - assert len(s.package._activate_or_not("example", "enable", "disable")) == 0 + assert len(s.package.builder._activate_or_not("example", "enable", "disable")) == 0 def test_autoreconf_search_path_args_multiple(config, mock_packages, tmpdir): diff --git a/lib/spack/spack/test/builder.py b/lib/spack/spack/test/builder.py new file mode 100644 index 00000000000..bda72c8b490 --- /dev/null +++ b/lib/spack/spack/test/builder.py @@ -0,0 +1,123 @@ +# 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) +import os.path + +import pytest + +import spack.paths + + +@pytest.fixture() +def builder_test_repository(): + builder_test_path = os.path.join(spack.paths.repos_path, "builder.test") + with spack.repo.use_repositories(builder_test_path) as mock_repo: + yield mock_repo + + +@pytest.mark.parametrize( + "spec_str,expected_values", + [ + ( + "callbacks@2.0", + [ + ("BEFORE_INSTALL_1_CALLED", "1"), + ("BEFORE_INSTALL_2_CALLED", "1"), + ("CALLBACKS_INSTALL_CALLED", "1"), + ("AFTER_INSTALL_1_CALLED", "1"), + ("TEST_VALUE", "3"), + ("INSTALL_VALUE", "CALLBACKS"), + ], + ), + # The last callback is conditional on "@1.0", check it's being executed + ( + "callbacks@1.0", + [ + ("BEFORE_INSTALL_1_CALLED", "1"), + ("BEFORE_INSTALL_2_CALLED", "1"), + ("CALLBACKS_INSTALL_CALLED", "1"), + ("AFTER_INSTALL_1_CALLED", "1"), + ("AFTER_INSTALL_2_CALLED", "1"), + ("TEST_VALUE", "4"), + ("INSTALL_VALUE", "CALLBACKS"), + ], + ), + # The package below adds to "callbacks" using inheritance, test that using super() + # works with builder hierarchies + ( + "inheritance@1.0", + [ + ("DERIVED_BEFORE_INSTALL_CALLED", "1"), + ("BEFORE_INSTALL_1_CALLED", "1"), + ("BEFORE_INSTALL_2_CALLED", "1"), + ("CALLBACKS_INSTALL_CALLED", "1"), + ("INHERITANCE_INSTALL_CALLED", "1"), + ("AFTER_INSTALL_1_CALLED", "1"), + ("AFTER_INSTALL_2_CALLED", "1"), + ("TEST_VALUE", "4"), + ("INSTALL_VALUE", "INHERITANCE"), + ], + ), + # Generate custom phases using a GenericBuilder + ( + "custom-phases", + [ + ("CONFIGURE_CALLED", "1"), + ("INSTALL_CALLED", "1"), + ("LAST_PHASE", "INSTALL"), + ], + ), + # Old-style package, with phase defined in base builder + ( + "old-style-autotools@1.0", + [ + ("AFTER_AUTORECONF_1_CALLED", "1"), + ], + ), + ( + "old-style-autotools@2.0", + [ + ("AFTER_AUTORECONF_2_CALLED", "1"), + ], + ), + ( + "old-style-custom-phases", + [ + ("AFTER_CONFIGURE_CALLED", "1"), + ("TEST_VALUE", "0"), + ], + ), + ], +) +@pytest.mark.usefixtures("builder_test_repository", "config") +@pytest.mark.disable_clean_stage_check +def test_callbacks_and_installation_procedure(spec_str, expected_values, working_env): + """Test the correct execution of callbacks and installation procedures for packages.""" + s = spack.spec.Spec(spec_str).concretized() + builder = spack.builder.create(s.package) + for phase_fn in builder: + phase_fn.execute() + + # Check calls have produced the expected side effects + for var_name, expected in expected_values: + assert os.environ[var_name] == expected, os.environ + + +@pytest.mark.usefixtures("builder_test_repository", "config") +@pytest.mark.parametrize( + "spec_str,method_name,expected", + [ + # Call a function defined on the package, which calls the same function defined + # on the super(builder) + ("old-style-autotools", "configure_args", ["--with-foo"]), + # Call a function defined on the package, which calls the same function defined on the + # super(pkg), which calls the same function defined in the super(builder) + ("old-style-derived", "configure_args", ["--with-bar", "--with-foo"]), + ], +) +def test_old_style_compatibility_with_super(spec_str, method_name, expected): + s = spack.spec.Spec(spec_str).concretized() + builder = spack.builder.create(s.package) + value = getattr(builder, method_name)() + assert value == expected diff --git a/lib/spack/spack/test/cmd/info.py b/lib/spack/spack/test/cmd/info.py index 55b875e0224..2bbf4d3a7fa 100644 --- a/lib/spack/spack/test/cmd/info.py +++ b/lib/spack/spack/test/cmd/info.py @@ -43,7 +43,7 @@ def test_it_just_runs(pkg): def test_info_noversion(mock_packages, print_buffer): - """Check that a mock package with no versions or variants outputs None.""" + """Check that a mock package with no versions outputs None.""" info("noversion") line_iter = iter(print_buffer) @@ -52,7 +52,7 @@ def test_info_noversion(mock_packages, print_buffer): has = [desc in line for desc in ["Preferred", "Safe", "Deprecated"]] if not any(has): continue - elif "Variants" not in line: + else: continue assert "None" in next(line_iter).strip() diff --git a/lib/spack/spack/test/cmd/install.py b/lib/spack/spack/test/cmd/install.py index 8c37ea3e98b..41de6565a1a 100644 --- a/lib/spack/spack/test/cmd/install.py +++ b/lib/spack/spack/test/cmd/install.py @@ -1087,7 +1087,7 @@ def test_install_empty_env( ("test-install-callbacks", "undefined-install-test"), ], ) -def test_install_callbacks_fail(install_mockery, mock_fetch, name, method): +def test_installation_fail_tests(install_mockery, mock_fetch, name, method): output = install("--test=root", "--no-cache", name, fail_on_error=False) assert output.count(method) == 2 diff --git a/lib/spack/spack/test/cmd/test.py b/lib/spack/spack/test/cmd/test.py index e842dbc4655..fac639309d7 100644 --- a/lib/spack/spack/test/cmd/test.py +++ b/lib/spack/spack/test/cmd/test.py @@ -237,8 +237,7 @@ def test_test_list_all(mock_packages): "simple-standalone-test", "test-error", "test-fail", - "test-build-callbacks", - "test-install-callbacks", + "fail-test-audit", ] ) diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py index 4d15d48dbe1..ccdc19a1743 100644 --- a/lib/spack/spack/test/concretize.py +++ b/lib/spack/spack/test/concretize.py @@ -228,7 +228,7 @@ def test_concretize(self, spec): check_concretize(spec) def test_concretize_mention_build_dep(self): - spec = check_concretize("cmake-client ^cmake@3.4.3") + spec = check_concretize("cmake-client ^cmake@3.21.3") # Check parent's perspective of child to_dependencies = spec.edges_to_dependencies(name="cmake") diff --git a/lib/spack/spack/test/concretize_requirements.py b/lib/spack/spack/test/concretize_requirements.py index 50cc6baa9a5..e43203b9696 100644 --- a/lib/spack/spack/test/concretize_requirements.py +++ b/lib/spack/spack/test/concretize_requirements.py @@ -7,6 +7,7 @@ import pytest +import spack.build_systems.generic import spack.config import spack.repo import spack.util.spack_yaml as syaml @@ -102,7 +103,7 @@ def fake_installs(monkeypatch, tmpdir): stage_path = str(tmpdir.ensure("fake-stage", dir=True)) universal_unused_stage = spack.stage.DIYStage(stage_path) monkeypatch.setattr( - spack.package_base.Package, "_make_stage", MakeStage(universal_unused_stage) + spack.build_systems.generic.Package, "_make_stage", MakeStage(universal_unused_stage) ) diff --git a/lib/spack/spack/test/config.py b/lib/spack/spack/test/config.py index f4d0b570fda..f5f91f039de 100644 --- a/lib/spack/spack/test/config.py +++ b/lib/spack/spack/test/config.py @@ -18,6 +18,7 @@ import spack.config import spack.environment as ev import spack.main +import spack.package_base import spack.paths import spack.repo import spack.schema.compilers @@ -1170,13 +1171,13 @@ def test_license_dir_config(mutable_config, mock_packages): """Ensure license directory is customizable""" expected_dir = spack.paths.default_license_dir assert spack.config.get("config:license_dir") == expected_dir - assert spack.package.Package.global_license_dir == expected_dir + assert spack.package_base.PackageBase.global_license_dir == expected_dir assert spack.repo.path.get_pkg_class("a").global_license_dir == expected_dir rel_path = os.path.join(os.path.sep, "foo", "bar", "baz") spack.config.set("config:license_dir", rel_path) assert spack.config.get("config:license_dir") == rel_path - assert spack.package.Package.global_license_dir == rel_path + assert spack.package_base.PackageBase.global_license_dir == rel_path assert spack.repo.path.get_pkg_class("a").global_license_dir == rel_path diff --git a/lib/spack/spack/test/graph.py b/lib/spack/spack/test/graph.py index e7aafe4b0d2..60d041d60b4 100644 --- a/lib/spack/spack/test/graph.py +++ b/lib/spack/spack/test/graph.py @@ -103,6 +103,19 @@ def test_ascii_graph_mpileaks(config, mock_packages, monkeypatch): | o libdwarf |/ o libelf +""" + or graph_str + == r"""o mpileaks +|\ +o | callpath +|\| +| o mpich +| +o dyninst +|\ +o | libdwarf +|/ +o libelf """ ) diff --git a/lib/spack/spack/test/install.py b/lib/spack/spack/test/install.py index 9093593bede..e8b6f415d34 100644 --- a/lib/spack/spack/test/install.py +++ b/lib/spack/spack/test/install.py @@ -144,13 +144,12 @@ def __getattr__(self, attr): return getattr(self.wrapped_stage, attr) -def test_partial_install_delete_prefix_and_stage(install_mockery, mock_fetch): +def test_partial_install_delete_prefix_and_stage(install_mockery, mock_fetch, working_env): s = Spec("canfail").concretized() instance_rm_prefix = s.package.remove_prefix try: - s.package.succeed = False s.package.remove_prefix = mock_remove_prefix with pytest.raises(MockInstallError): s.package.do_install() @@ -161,7 +160,7 @@ def test_partial_install_delete_prefix_and_stage(install_mockery, mock_fetch): # must clear failure markings for the package before re-installing it spack.store.db.clear_failure(s, True) - s.package.succeed = True + s.package.set_install_succeed() s.package.stage = MockStage(s.package.stage) s.package.do_install(restage=True) @@ -174,18 +173,20 @@ def test_partial_install_delete_prefix_and_stage(install_mockery, mock_fetch): @pytest.mark.disable_clean_stage_check -def test_failing_overwrite_install_should_keep_previous_installation(mock_fetch, install_mockery): +def test_failing_overwrite_install_should_keep_previous_installation( + mock_fetch, install_mockery, working_env +): """ Make sure that whenever `spack install --overwrite` fails, spack restores the original install prefix instead of cleaning it. """ # Do a successful install s = Spec("canfail").concretized() - s.package.succeed = True + s.package.set_install_succeed() # Do a failing overwrite install s.package.do_install() - s.package.succeed = False + s.package.set_install_fail() kwargs = {"overwrite": [s.dag_hash()]} with pytest.raises(Exception): @@ -238,13 +239,11 @@ def test_install_dependency_symlinks_pkg(install_mockery, mock_fetch, mutable_mo def test_install_times(install_mockery, mock_fetch, mutable_mock_repo): """Test install times added.""" - spec = Spec("dev-build-test-install-phases") - spec.concretize() - pkg = spec.package - pkg.do_install() + spec = Spec("dev-build-test-install-phases").concretized() + spec.package.do_install() # Ensure dependency directory exists after the installation. - install_times = os.path.join(pkg.prefix, ".spack", "install_times.json") + install_times = os.path.join(spec.package.prefix, ".spack", "install_times.json") assert os.path.isfile(install_times) # Ensure the phases are included @@ -346,12 +345,11 @@ def test_installed_upstream(install_upstream, mock_fetch): @pytest.mark.disable_clean_stage_check -def test_partial_install_keep_prefix(install_mockery, mock_fetch, monkeypatch): +def test_partial_install_keep_prefix(install_mockery, mock_fetch, monkeypatch, working_env): s = Spec("canfail").concretized() # If remove_prefix is called at any point in this test, that is an error - s.package.succeed = False # make the build fail - monkeypatch.setattr(spack.package_base.Package, "remove_prefix", mock_remove_prefix) + monkeypatch.setattr(spack.package_base.PackageBase, "remove_prefix", mock_remove_prefix) with pytest.raises(spack.build_environment.ChildError): s.package.do_install(keep_prefix=True) assert os.path.exists(s.package.prefix) @@ -359,7 +357,7 @@ def test_partial_install_keep_prefix(install_mockery, mock_fetch, monkeypatch): # must clear failure markings for the package before re-installing it spack.store.db.clear_failure(s, True) - s.package.succeed = True # make the build succeed + s.package.set_install_succeed() s.package.stage = MockStage(s.package.stage) s.package.do_install(keep_prefix=True) assert s.package.spec.installed @@ -368,14 +366,14 @@ def test_partial_install_keep_prefix(install_mockery, mock_fetch, monkeypatch): def test_second_install_no_overwrite_first(install_mockery, mock_fetch, monkeypatch): s = Spec("canfail").concretized() - monkeypatch.setattr(spack.package_base.Package, "remove_prefix", mock_remove_prefix) + monkeypatch.setattr(spack.package_base.PackageBase, "remove_prefix", mock_remove_prefix) - s.package.succeed = True + s.package.set_install_succeed() s.package.do_install() assert s.package.spec.installed # If Package.install is called after this point, it will fail - s.package.succeed = False + s.package.set_install_fail() s.package.do_install() @@ -589,7 +587,9 @@ def _install(src, dest): source = spec.package.stage.source_path config = os.path.join(source, "config.log") fs.touchp(config) - spec.package.archive_files = ["missing", "..", config] + monkeypatch.setattr( + type(spec.package), "archive_files", ["missing", "..", config], raising=False + ) spack.installer.log(spec.package) diff --git a/lib/spack/spack/test/repo.py b/lib/spack/spack/test/repo.py index fcd009edec2..402723d226c 100644 --- a/lib/spack/spack/test/repo.py +++ b/lib/spack/spack/test/repo.py @@ -113,14 +113,14 @@ def test_absolute_import_spack_packages_as_python_modules(mock_packages): assert hasattr(spack.pkg.builtin.mock, "mpileaks") assert hasattr(spack.pkg.builtin.mock.mpileaks, "Mpileaks") assert isinstance(spack.pkg.builtin.mock.mpileaks.Mpileaks, spack.package_base.PackageMeta) - assert issubclass(spack.pkg.builtin.mock.mpileaks.Mpileaks, spack.package_base.Package) + assert issubclass(spack.pkg.builtin.mock.mpileaks.Mpileaks, spack.package_base.PackageBase) def test_relative_import_spack_packages_as_python_modules(mock_packages): from spack.pkg.builtin.mock.mpileaks import Mpileaks assert isinstance(Mpileaks, spack.package_base.PackageMeta) - assert issubclass(Mpileaks, spack.package_base.Package) + assert issubclass(Mpileaks, spack.package_base.PackageBase) def test_all_virtual_packages_have_default_providers(): diff --git a/lib/spack/spack/util/package_hash.py b/lib/spack/spack/util/package_hash.py index 4877748338c..f4435fbba46 100644 --- a/lib/spack/spack/util/package_hash.py +++ b/lib/spack/spack/util/package_hash.py @@ -64,7 +64,7 @@ def __init__(self, spec): # list of URL attributes and metadata attributes # these will be removed from packages. self.metadata_attrs = [s.url_attr for s in spack.fetch_strategy.all_strategies] - self.metadata_attrs += spack.package_base.Package.metadata_attrs + self.metadata_attrs += spack.package_base.PackageBase.metadata_attrs self.spec = spec self.in_classdef = False # used to avoid nested classdefs @@ -158,6 +158,7 @@ def __init__(self, spec): def visit_FunctionDef(self, func): conditions = [] + for dec in func.decorator_list: if isinstance(dec, ast.Call) and dec.func.id == "when": try: diff --git a/lib/spack/spack/util/web.py b/lib/spack/spack/util/web.py index fa4119f9173..939ec669c02 100644 --- a/lib/spack/spack/util/web.py +++ b/lib/spack/spack/util/web.py @@ -784,7 +784,7 @@ def find_versions_of_archive( list_depth (int): max depth to follow links on list_url pages. Defaults to 0. concurrency (int): maximum number of concurrent requests - reference_package (spack.package_base.Package or None): a spack package + reference_package (spack.package_base.PackageBase or None): a spack package used as a reference for url detection. Uses the url_for_version method on the package to produce reference urls which, if found, are preferred. diff --git a/lib/spack/spack/variant.py b/lib/spack/spack/variant.py index 864ea264467..92e512219b0 100644 --- a/lib/spack/spack/variant.py +++ b/lib/spack/spack/variant.py @@ -96,7 +96,7 @@ def validate_or_raise(self, vspec, pkg_cls=None): Args: vspec (Variant): instance to be validated - pkg_cls (spack.package_base.Package): the package class + pkg_cls (spack.package_base.PackageBase): the package class that required the validation, if available Raises: diff --git a/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml index 488309b2948..5ede7b882cd 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml @@ -24,6 +24,8 @@ spack: - openmpi - mpich variants: +mpi + tbb: + require: "intel-tbb" binutils: variants: +ld +gold +headers +libiberty ~nls version: diff --git a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml index 61eb974e70e..262de722a5a 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml @@ -24,6 +24,8 @@ spack: - openmpi - mpich variants: +mpi + tbb: + require: "intel-tbb" binutils: variants: +ld +gold +headers +libiberty ~nls version: diff --git a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml index ed2f205d42c..c71b514c6e4 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml @@ -24,6 +24,8 @@ spack: - openmpi - mpich variants: +mpi + tbb: + require: "intel-tbb" binutils: variants: +ld +gold +headers +libiberty ~nls version: diff --git a/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml index ee6c9457c3f..b3b4e8697c6 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml @@ -14,6 +14,8 @@ spack: definitions: - default_specs: + - 'uncrustify build_system=autotools' + - 'uncrustify build_system=cmake' - lz4 # MakefilePackage - mpich~fortran # AutotoolsPackage - py-setuptools # PythonPackage diff --git a/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml index 8d6669252a1..4d7b8757726 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml @@ -21,6 +21,8 @@ spack: mpi: [mpich] target: [x86_64] variants: +mpi + tbb: + require: "intel-tbb" binutils: variants: +ld +gold +headers +libiberty ~nls cuda: diff --git a/share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml index ea34141ba14..0090fd2f832 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml @@ -18,6 +18,8 @@ spack: packages: all: target: [x86_64] + tbb: + require: 'intel-tbb' definitions: - gcc_system_packages: diff --git a/var/spack/repos/builder.test/packages/callbacks/package.py b/var/spack/repos/builder.test/packages/callbacks/package.py new file mode 100644 index 00000000000..ea6787d9b57 --- /dev/null +++ b/var/spack/repos/builder.test/packages/callbacks/package.py @@ -0,0 +1,45 @@ +# 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) +import os + +import spack.build_systems.generic +from spack.package import * + + +class Callbacks(Package): + """Package used to verify that callbacks on phases work correctly, including conditions""" + + homepage = "http://www.example.com" + url = "http://www.example.com/a-1.0.tar.gz" + + version("2.0", "abcdef0123456789abcdef0123456789") + version("1.0", "0123456789abcdef0123456789abcdef") + + +class GenericBuilder(spack.build_systems.generic.GenericBuilder): + def install(self, pkg, spec, prefix): + os.environ["CALLBACKS_INSTALL_CALLED"] = "1" + os.environ["INSTALL_VALUE"] = "CALLBACKS" + mkdirp(prefix.bin) + + @run_before("install") + def before_install_1(self): + os.environ["BEFORE_INSTALL_1_CALLED"] = "1" + os.environ["TEST_VALUE"] = "1" + + @run_before("install") + def before_install_2(self): + os.environ["BEFORE_INSTALL_2_CALLED"] = "1" + os.environ["TEST_VALUE"] = "2" + + @run_after("install") + def after_install_1(self): + os.environ["AFTER_INSTALL_1_CALLED"] = "1" + os.environ["TEST_VALUE"] = "3" + + @run_after("install", when="@1.0") + def after_install_2(self): + os.environ["AFTER_INSTALL_2_CALLED"] = "1" + os.environ["TEST_VALUE"] = "4" diff --git a/var/spack/repos/builder.test/packages/custom-phases/package.py b/var/spack/repos/builder.test/packages/custom-phases/package.py new file mode 100644 index 00000000000..37b26e37d0d --- /dev/null +++ b/var/spack/repos/builder.test/packages/custom-phases/package.py @@ -0,0 +1,31 @@ +# 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) +import os + +import spack.build_systems.generic +from spack.package import * + + +class CustomPhases(Package): + """Package used to verify that we can set custom phases on builders""" + + homepage = "http://www.example.com" + url = "http://www.example.com/a-1.0.tar.gz" + + version("2.0", "abcdef0123456789abcdef0123456789") + version("1.0", "0123456789abcdef0123456789abcdef") + + +class GenericBuilder(spack.build_systems.generic.GenericBuilder): + phases = ["configure", "install"] + + def configure(self, pkg, spec, prefix): + os.environ["CONFIGURE_CALLED"] = "1" + os.environ["LAST_PHASE"] = "CONFIGURE" + + def install(self, pkg, spec, prefix): + os.environ["INSTALL_CALLED"] = "1" + os.environ["LAST_PHASE"] = "INSTALL" + mkdirp(prefix.bin) diff --git a/var/spack/repos/builder.test/packages/gnuconfig/package.py b/var/spack/repos/builder.test/packages/gnuconfig/package.py new file mode 100644 index 00000000000..53f8a10705d --- /dev/null +++ b/var/spack/repos/builder.test/packages/gnuconfig/package.py @@ -0,0 +1,15 @@ +# 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 Gnuconfig(Package): + """This package is needed to allow mocking AutotoolsPackage objects""" + + homepage = "http://www.example.com" + url = "http://www.example.com/a-1.0.tar.gz" + + version("2.0", "abcdef0123456789abcdef0123456789") + version("1.0", "0123456789abcdef0123456789abcdef") diff --git a/var/spack/repos/builder.test/packages/inheritance/package.py b/var/spack/repos/builder.test/packages/inheritance/package.py new file mode 100644 index 00000000000..307d93ca802 --- /dev/null +++ b/var/spack/repos/builder.test/packages/inheritance/package.py @@ -0,0 +1,26 @@ +# 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) +import os + +import spack.pkg.builder.test.callbacks +from spack.package import * + + +class Inheritance(spack.pkg.builder.test.callbacks.Callbacks): + """Package used to verify that inheritance among packages work as expected""" + + pass + + +class GenericBuilder(spack.pkg.builder.test.callbacks.GenericBuilder): + def install(self, pkg, spec, prefix): + super(GenericBuilder, self).install(pkg, spec, prefix) + os.environ["INHERITANCE_INSTALL_CALLED"] = "1" + os.environ["INSTALL_VALUE"] = "INHERITANCE" + + @run_before("install") + def derived_before_install(self): + os.environ["DERIVED_BEFORE_INSTALL_CALLED"] = "1" + os.environ["TEST_VALUE"] = "0" diff --git a/var/spack/repos/builder.test/packages/old-style-autotools/package.py b/var/spack/repos/builder.test/packages/old-style-autotools/package.py new file mode 100644 index 00000000000..56213d71585 --- /dev/null +++ b/var/spack/repos/builder.test/packages/old-style-autotools/package.py @@ -0,0 +1,50 @@ +# 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) +import os + +from spack.package import * + + +class OldStyleAutotools(AutotoolsPackage): + """Package used to verify that old-style packages work correctly when executing the + installation procedure. + """ + + homepage = "http://www.example.com" + url = "http://www.example.com/a-1.0.tar.gz" + + version("2.0", "abcdef0123456789abcdef0123456789") + version("1.0", "0123456789abcdef0123456789abcdef") + + def configure(self, spec, prefix): + pass + + def build(self, spec, prefix): + pass + + def install(self, spec, prefix): + mkdirp(prefix.bin) + + def configure_args(self): + """This override a function in the builder and construct the result using a method + defined in this class and a super method defined in the builder. + """ + return [self.foo()] + super(OldStyleAutotools, self).configure_args() + + def foo(self): + return "--with-foo" + + @run_before("autoreconf") + def create_configure(self): + mkdirp(self.configure_directory) + touch(self.configure_abs_path) + + @run_after("autoreconf", when="@1.0") + def after_autoreconf_1(self): + os.environ["AFTER_AUTORECONF_1_CALLED"] = "1" + + @run_after("autoreconf", when="@2.0") + def after_autoreconf_2(self): + os.environ["AFTER_AUTORECONF_2_CALLED"] = "1" diff --git a/var/spack/repos/builder.test/packages/old-style-custom-phases/package.py b/var/spack/repos/builder.test/packages/old-style-custom-phases/package.py new file mode 100644 index 00000000000..afa5b52d709 --- /dev/null +++ b/var/spack/repos/builder.test/packages/old-style-custom-phases/package.py @@ -0,0 +1,34 @@ +# 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) +import os + +from spack.package import * + + +class OldStyleCustomPhases(AutotoolsPackage): + """Package used to verify that old-style packages work correctly when defining custom + phases (though it's not recommended for packagers to do so). + """ + + homepage = "http://www.example.com" + url = "http://www.example.com/a-1.0.tar.gz" + + version("2.0", "abcdef0123456789abcdef0123456789") + version("1.0", "0123456789abcdef0123456789abcdef") + + phases = ["configure"] + + def configure(self, spec, prefix): + mkdirp(prefix.bin) + + @run_after("configure") + def after_configure(self): + os.environ["AFTER_CONFIGURE_CALLED"] = "1" + os.environ["TEST_VALUE"] = "0" + + @run_after("install") + def after_install(self): + os.environ["AFTER_INSTALL_CALLED"] = "1" + os.environ["TEST_VALUE"] = "1" diff --git a/var/spack/repos/builder.test/packages/old-style-derived/package.py b/var/spack/repos/builder.test/packages/old-style-derived/package.py new file mode 100644 index 00000000000..a7dd0262179 --- /dev/null +++ b/var/spack/repos/builder.test/packages/old-style-derived/package.py @@ -0,0 +1,21 @@ +# 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) +import spack.pkg.builder.test.old_style_autotools +from spack.package import * + + +class OldStyleDerived(spack.pkg.builder.test.old_style_autotools.OldStyleAutotools): + """Package used to verify that old-style packages work correctly when executing the + installation procedure. + """ + + homepage = "http://www.example.com" + url = "http://www.example.com/a-1.0.tar.gz" + + version("2.0", "abcdef0123456789abcdef0123456789") + version("1.0", "0123456789abcdef0123456789abcdef") + + def configure_args(self): + return ["--with-bar"] + super(OldStyleDerived, self).configure_args() diff --git a/var/spack/repos/builder.test/repo.yaml b/var/spack/repos/builder.test/repo.yaml new file mode 100644 index 00000000000..a9031afe214 --- /dev/null +++ b/var/spack/repos/builder.test/repo.yaml @@ -0,0 +1,2 @@ +repo: + namespace: builder.test diff --git a/var/spack/repos/builtin.mock/packages/a/package.py b/var/spack/repos/builtin.mock/packages/a/package.py index b556fbf06f6..5dbcd1f9c27 100644 --- a/var/spack/repos/builtin.mock/packages/a/package.py +++ b/var/spack/repos/builtin.mock/packages/a/package.py @@ -2,7 +2,7 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - +import spack.build_systems.autotools from spack.package import * @@ -32,21 +32,23 @@ class A(AutotoolsPackage): parallel = False + +class AutotoolsBuilder(spack.build_systems.autotools.AutotoolsBuilder): def with_or_without_fee(self, activated): if not activated: return "--no-fee" return "--fee-all-the-time" - def autoreconf(self, spec, prefix): + def autoreconf(self, pkg, spec, prefix): pass - def configure(self, spec, prefix): + def configure(self, pkg, spec, prefix): pass - def build(self, spec, prefix): + def build(self, pkg, spec, prefix): pass - def install(self, spec, prefix): + def install(self, pkg, spec, prefix): # sanity_check_prefix requires something in the install directory # Test requires overriding the one provided by `AutotoolsPackage` mkdirp(prefix.bin) diff --git a/var/spack/repos/builtin.mock/packages/attributes-foo/package.py b/var/spack/repos/builtin.mock/packages/attributes-foo/package.py index 9010c52958e..83b41b98ac3 100644 --- a/var/spack/repos/builtin.mock/packages/attributes-foo/package.py +++ b/var/spack/repos/builtin.mock/packages/attributes-foo/package.py @@ -8,7 +8,6 @@ class AttributesFoo(BundlePackage): - phases = ["install"] version("1.0") provides("bar") diff --git a/var/spack/repos/builtin.mock/packages/canfail/package.py b/var/spack/repos/builtin.mock/packages/canfail/package.py index eb35fdec562..75bb66df252 100644 --- a/var/spack/repos/builtin.mock/packages/canfail/package.py +++ b/var/spack/repos/builtin.mock/packages/canfail/package.py @@ -2,6 +2,7 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import os from spack.package import * @@ -14,7 +15,16 @@ class Canfail(Package): version("1.0", "0123456789abcdef0123456789abcdef") - succeed = False + def set_install_succeed(self): + os.environ["CANFAIL_SUCCEED"] = "1" + + def set_install_fail(self): + os.environ.pop("CANFAIL_SUCCEED", None) + + @property + def succeed(self): + result = True if "CANFAIL_SUCCEED" in os.environ else False + return result def install(self, spec, prefix): if not self.succeed: diff --git a/var/spack/repos/builtin.mock/packages/cmake-client/package.py b/var/spack/repos/builtin.mock/packages/cmake-client/package.py index 54842fd2d8f..ed3998e550b 100644 --- a/var/spack/repos/builtin.mock/packages/cmake-client/package.py +++ b/var/spack/repos/builtin.mock/packages/cmake-client/package.py @@ -15,7 +15,7 @@ def check(condition, msg): class CmakeClient(CMakePackage): - """A dumy package that uses cmake.""" + """A dummy package that uses cmake.""" homepage = "https://www.example.com" url = "https://www.example.com/cmake-client-1.0.tar.gz" @@ -38,14 +38,16 @@ class CmakeClient(CMakePackage): did_something = False @run_after("cmake") - @run_before("cmake", "build", "install") + @run_before("cmake") + @run_before("build") + @run_before("install") def increment(self): - self.callback_counter += 1 + CmakeClient.callback_counter += 1 @run_after("cmake") @on_package_attributes(run_this=True, check_this_is_none=None) def flip(self): - self.flipped = True + CmakeClient.flipped = True @run_after("cmake") @on_package_attributes(does_not_exist=None) diff --git a/var/spack/repos/builtin.mock/packages/cmake/package.py b/var/spack/repos/builtin.mock/packages/cmake/package.py index 30c3647df21..dac2c19875b 100644 --- a/var/spack/repos/builtin.mock/packages/cmake/package.py +++ b/var/spack/repos/builtin.mock/packages/cmake/package.py @@ -18,11 +18,16 @@ def check(condition, msg): class Cmake(Package): - """A dumy package for the cmake build system.""" + """A dummy package for the cmake build system.""" homepage = "https://www.cmake.org" url = "https://cmake.org/files/v3.4/cmake-3.4.3.tar.gz" + version( + "3.23.1", + "4cb3ff35b2472aae70f542116d616e63", + url="https://cmake.org/files/v3.4/cmake-3.4.3.tar.gz", + ) version( "3.4.3", "4cb3ff35b2472aae70f542116d616e63", diff --git a/var/spack/repos/builtin.mock/packages/dev-build-test-dependent/package.py b/var/spack/repos/builtin.mock/packages/dev-build-test-dependent/package.py index 44374cd1a75..a5ac04d2825 100644 --- a/var/spack/repos/builtin.mock/packages/dev-build-test-dependent/package.py +++ b/var/spack/repos/builtin.mock/packages/dev-build-test-dependent/package.py @@ -7,14 +7,12 @@ from spack.package import * -class DevBuildTestDependent(Package): +class DevBuildTestDependent(MakefilePackage): homepage = "example.com" url = "fake.com" version("0.0.0", sha256="0123456789abcdef0123456789abcdef") - phases = ["edit", "install"] - filename = "dev-build-test-file.txt" original_string = "This file should be edited" replacement_string = "This file has been edited" @@ -28,5 +26,8 @@ def edit(self, spec, prefix): f.truncate() f.write(self.replacement_string) + def build(self, spec, prefix): + pass + def install(self, spec, prefix): install(self.filename, prefix) diff --git a/var/spack/repos/builtin.mock/packages/dev-build-test-install-phases/package.py b/var/spack/repos/builtin.mock/packages/dev-build-test-install-phases/package.py index fa0f6b794e4..916156c1f59 100644 --- a/var/spack/repos/builtin.mock/packages/dev-build-test-install-phases/package.py +++ b/var/spack/repos/builtin.mock/packages/dev-build-test-install-phases/package.py @@ -29,4 +29,5 @@ def three(self, spec, prefix): print("Three locomoco") def install(self, spec, prefix): + mkdirp(prefix.bin) print("install") diff --git a/var/spack/repos/builtin.mock/packages/dev-build-test-install/package.py b/var/spack/repos/builtin.mock/packages/dev-build-test-install/package.py index 185fe5552c9..ba0b1400a34 100644 --- a/var/spack/repos/builtin.mock/packages/dev-build-test-install/package.py +++ b/var/spack/repos/builtin.mock/packages/dev-build-test-install/package.py @@ -2,19 +2,15 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - - from spack.package import * -class DevBuildTestInstall(Package): +class DevBuildTestInstall(MakefilePackage): homepage = "example.com" url = "fake.com" version("0.0.0", sha256="0123456789abcdef0123456789abcdef") - phases = ["edit", "install"] - filename = "dev-build-test-file.txt" original_string = "This file should be edited" replacement_string = "This file has been edited" @@ -26,5 +22,8 @@ def edit(self, spec, prefix): f.truncate() f.write(self.replacement_string) + def build(self, spec, prefix): + pass + def install(self, spec, prefix): install(self.filename, prefix) diff --git a/var/spack/repos/builtin.mock/packages/fail-test-audit/package.py b/var/spack/repos/builtin.mock/packages/fail-test-audit/package.py new file mode 100644 index 00000000000..1e290724d1e --- /dev/null +++ b/var/spack/repos/builtin.mock/packages/fail-test-audit/package.py @@ -0,0 +1,21 @@ +# 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 FailTestAudit(MakefilePackage): + """Simple package with one optional dependency""" + + homepage = "http://www.example.com" + url = "http://www.example.com/a-1.0.tar.gz" + + version("1.0", "0123456789abcdef0123456789abcdef") + version("2.0", "abcdef0123456789abcdef0123456789") + + build_time_test_callbacks = ["test"] + + def test(self): + print("test: test-install-callbacks") + print("PASSED") diff --git a/var/spack/repos/builtin.mock/packages/libtool-deletion/package.py b/var/spack/repos/builtin.mock/packages/libtool-deletion/package.py index a169a78d2e5..8ab87d20644 100644 --- a/var/spack/repos/builtin.mock/packages/libtool-deletion/package.py +++ b/var/spack/repos/builtin.mock/packages/libtool-deletion/package.py @@ -4,6 +4,7 @@ # SPDX-License-Identifier: (Apache-2.0 OR MIT) import os.path +import spack.build_systems.autotools from spack.package import * @@ -19,17 +20,21 @@ class LibtoolDeletion(AutotoolsPackage): def do_stage(self): mkdirp(self.stage.source_path) - def autoreconf(self, spec, prefix): + +class AutotoolsBuilder(spack.build_systems.autotools.AutotoolsBuilder): + install_libtool_archives = False + + def autoreconf(self, pkg, spec, prefix): mkdirp(os.path.dirname(self.configure_abs_path)) touch(self.configure_abs_path) - def configure(self, spec, prefix): + def configure(self, pkg, spec, prefix): pass - def build(self, spec, prefix): + def build(self, pkg, spec, prefix): pass - def install(self, spec, prefix): + def install(self, pkg, spec, prefix): mkdirp(os.path.dirname(self.libtool_archive_file)) touch(self.libtool_archive_file) diff --git a/var/spack/repos/builtin.mock/packages/libtool-installation/package.py b/var/spack/repos/builtin.mock/packages/libtool-installation/package.py new file mode 100644 index 00000000000..72883b90423 --- /dev/null +++ b/var/spack/repos/builtin.mock/packages/libtool-installation/package.py @@ -0,0 +1,15 @@ +# 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 * +from spack.pkg.builtin.mock.libtool_deletion import AutotoolsBuilder as BuilderBase +from spack.pkg.builtin.mock.libtool_deletion import LibtoolDeletion + + +class LibtoolInstallation(LibtoolDeletion, AutotoolsPackage): + """Mock AutotoolsPackage to check proper installation of libtool archives.""" + + +class AutotoolsBuilder(BuilderBase): + install_libtool_archives = True diff --git a/var/spack/repos/builtin.mock/packages/nosource-install/package.py b/var/spack/repos/builtin.mock/packages/nosource-install/package.py index a1ca7244489..5166480dd4f 100644 --- a/var/spack/repos/builtin.mock/packages/nosource-install/package.py +++ b/var/spack/repos/builtin.mock/packages/nosource-install/package.py @@ -16,9 +16,6 @@ class NosourceInstall(BundlePackage): depends_on("dependency-install") - # The install phase must be specified. - phases = ["install"] - # The install method must also be present. def install(self, spec, prefix): touch(join_path(self.prefix, "install.txt")) diff --git a/var/spack/repos/builtin.mock/packages/test-build-callbacks/package.py b/var/spack/repos/builtin.mock/packages/test-build-callbacks/package.py index 4b4b74e9b3f..d45f0d295bc 100644 --- a/var/spack/repos/builtin.mock/packages/test-build-callbacks/package.py +++ b/var/spack/repos/builtin.mock/packages/test-build-callbacks/package.py @@ -2,9 +2,9 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - +import spack.build_systems._checks as checks +import spack.build_systems.generic from spack.package import * -from spack.package_base import run_after class TestBuildCallbacks(Package): @@ -15,17 +15,16 @@ class TestBuildCallbacks(Package): version("1.0", "0123456789abcdef0123456789abcdef") - phases = ["build", "install"] - # Include undefined method (runtime failure) and 'test' (audit failure) - build_time_test_callbacks = ["undefined-build-test", "test"] - run_after("build")(Package._run_default_build_time_test_callbacks) - def build(self, spec, prefix): +class GenericBuilder(spack.build_systems.generic.GenericBuilder): + phases = ["build", "install"] + + # Include undefined method (runtime failure) + build_time_test_callbacks = ["undefined-build-test"] + run_after("build")(checks.execute_build_time_tests) + + def build(self, pkg, spec, prefix): pass - def install(self, spec, prefix): + def install(self, pkg, spec, prefix): mkdirp(prefix.bin) - - def test(self): - print("test: running test-build-callbacks") - print("PASSED") diff --git a/var/spack/repos/builtin.mock/packages/test-install-callbacks/package.py b/var/spack/repos/builtin.mock/packages/test-install-callbacks/package.py index 27a31227c3d..0d348c0d679 100644 --- a/var/spack/repos/builtin.mock/packages/test-install-callbacks/package.py +++ b/var/spack/repos/builtin.mock/packages/test-install-callbacks/package.py @@ -2,9 +2,9 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - +import spack.build_systems._checks as checks +import spack.build_systems.generic from spack.package import * -from spack.package_base import run_after class TestInstallCallbacks(Package): @@ -15,13 +15,11 @@ class TestInstallCallbacks(Package): version("1.0", "0123456789abcdef0123456789abcdef") + +class GenericBuilder(spack.build_systems.generic.GenericBuilder): # Include an undefined callback method - install_time_test_callbacks = ["undefined-install-test", "test"] - run_after("install")(Package._run_default_install_time_test_callbacks) + install_time_test_callbacks = ["undefined-install-test"] + run_after("install")(checks.execute_install_time_tests) - def install(self, spec, prefix): + def install(self, pkg, spec, prefix): mkdirp(prefix.bin) - - def test(self): - print("test: test-install-callbacks") - print("PASSED") diff --git a/var/spack/repos/builtin.mock/packages/transitive-conditional-virtual-dependency/package.py b/var/spack/repos/builtin.mock/packages/transitive-conditional-virtual-dependency/package.py index a7c46588103..9078d63b4d8 100644 --- a/var/spack/repos/builtin.mock/packages/transitive-conditional-virtual-dependency/package.py +++ b/var/spack/repos/builtin.mock/packages/transitive-conditional-virtual-dependency/package.py @@ -5,12 +5,10 @@ from spack.package import * -class TransitiveConditionalVirtualDependency(Package): +class TransitiveConditionalVirtualDependency(BundlePackage): """Depends on a package with a conditional virtual dependency.""" homepage = "https://dev.null" - has_code = False - phases = [] version("1.0") depends_on("conditional-virtual-dependency") diff --git a/var/spack/repos/builtin.mock/packages/trivial-smoke-test/package.py b/var/spack/repos/builtin.mock/packages/trivial-smoke-test/package.py index ec80640d216..35983a18f40 100644 --- a/var/spack/repos/builtin.mock/packages/trivial-smoke-test/package.py +++ b/var/spack/repos/builtin.mock/packages/trivial-smoke-test/package.py @@ -16,6 +16,9 @@ class TrivialSmokeTest(Package): test_source_filename = "cached_file.in" + def install(self, spec, prefix): + pass + @run_before("install") def create_extra_test_source(self): mkdirp(self.install_test_root) diff --git a/var/spack/repos/builtin/packages/alpgen/package.py b/var/spack/repos/builtin/packages/alpgen/package.py index 717b513cc3f..e0816eeca78 100644 --- a/var/spack/repos/builtin/packages/alpgen/package.py +++ b/var/spack/repos/builtin/packages/alpgen/package.py @@ -2,15 +2,16 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - import os +import spack.build_systems.makefile from spack.package import * -class Alpgen(MakefilePackage): - """A collection of codes for the generation of - multi-parton processes in hadronic collisions.""" +class Alpgen(CMakePackage, MakefilePackage): + """A collection of codes for the generation of multi-parton processes + in hadronic collisions. + """ homepage = "http://mlm.home.cern.ch/mlm/alpgen/" url = "http://mlm.home.cern.ch/mlm/alpgen/V2.1/v214.tgz" @@ -18,102 +19,44 @@ class Alpgen(MakefilePackage): maintainers = ["iarspider"] tags = ["hep"] - patch("alpgen-214.patch", when="recipe=cms") - patch("alpgen-214-Darwin-x86_84-gfortran.patch", when="platform=darwin recipe=cms") - patch("alpgen-2.1.4-sft.patch", when="recipe=sft", level=0) + version("2.1.4", sha256="2f43f7f526793fe5f81a3a3e1adeffe21b653a7f5851efc599ed69ea13985c5e") - depends_on("cmake", type="build", when="recipe=sft") + build_system("makefile", "cmake", default="makefile") variant( "recipe", - values=("cms", "sft"), + values=( + conditional("cms", when="build_system=makefile"), + conditional("sft", when="build_system=cmake"), + ), default="sft", - description="Select build recipe: CMS for CMS experiment, " + "SFT for ATLAS/LHCb/others.", + description="CMS for CMS experiment, SFT for ATLAS/LHCb/others.", ) - version("2.1.4", sha256="2f43f7f526793fe5f81a3a3e1adeffe21b653a7f5851efc599ed69ea13985c5e") - - phases = ["cmake", "build", "install"] - - # copied from CMakePackage - @property - def build_dirname(self): - """Returns the directory name to use when building the package - - :return: name of the subdirectory for building the package - """ - return "spack-build-%s" % self.spec.dag_hash(7) - - @property - def build_directory(self): - """Returns the directory to use when building the package - - :return: directory where to build the package - """ - return os.path.join(self.stage.path, self.build_dirname) - - @property - def root_cmakelists_dir(self): - """The relative path to the directory containing CMakeLists.txt - - This path is relative to the root of the extracted tarball, - not to the ``build_directory``. Defaults to the current directory. - - :return: directory containing CMakeLists.txt - """ - return self.stage.source_path - - def cmake_args(self): - """Produces a list containing all the arguments that must be passed to - cmake, except: - - * CMAKE_INSTALL_PREFIX - * CMAKE_BUILD_TYPE - - which will be set automatically. - - :return: list of arguments for cmake - """ - return [] - - @property - def std_cmake_args(self): - """Standard cmake arguments provided as a property for - convenience of package writers - - :return: standard cmake arguments - """ - # standard CMake arguments - std_cmake_args = CMakePackage._std_args(self) - std_cmake_args += getattr(self, "cmake_flag_args", []) - return std_cmake_args - - # end + patch("alpgen-214.patch", when="recipe=cms") + patch("alpgen-214-Darwin-x86_84-gfortran.patch", when="platform=darwin recipe=cms") + patch("alpgen-2.1.4-sft.patch", when="recipe=sft", level=0) def url_for_version(self, version): root = self.url.rsplit("/", 2)[0] return "{0}/V{1}/v{2}.tgz".format(root, version.up_to(2), version.joined) def patch(self): - if self.spec.satisfies("recipe=sft"): + if self.spec.satisfies("build_system=cmake"): copy(join_path(os.path.dirname(__file__), "CMakeLists.txt"), "CMakeLists.txt") - if self.spec.satisfies("recipe=cms"): + if self.spec.satisfies("build_system=makefile"): filter_file("-fno-automatic", "-fno-automatic -std=legacy", "compile.mk") copy(join_path(os.path.dirname(__file__), "cms_build.sh"), "cms_build.sh") copy(join_path(os.path.dirname(__file__), "cms_install.sh"), "cms_install.sh") - @when("recipe=cms") - def cmake(self, spec, prefix): - return - @when("recipe=cms") - def build(self, spec, prefix): +class MakefileBuilder(spack.build_systems.makefile.MakefileBuilder): + def build(self, pkg, spec, prefix): bash = which("bash") bash("./cms_build.sh") - @when("recipe=cms") - def install(self, spec, prefix): + def install(self, pkg, spec, prefix): bash = which("bash") bash("./cms_install.sh", prefix) @@ -121,25 +64,3 @@ def install(self, spec, prefix): set_install_permissions(root) for file in files: set_install_permissions(join_path(root, file)) - - @when("recipe=sft") - def cmake(self, spec, prefix): - """Runs ``cmake`` in the build directory""" - options = self.std_cmake_args - options += self.cmake_args() - options.append(os.path.abspath(self.root_cmakelists_dir)) - with working_dir(self.build_directory, create=True): - cmake_x = which("cmake") - cmake_x(*options) - - @when("recipe=sft") - def build(self, spec, prefix): - """Make the build targets""" - with working_dir(self.build_directory): - make() - - @when("recipe=sft") - def install(self, spec, prefix): - """Make the install targets""" - with working_dir(self.build_directory): - make("install") diff --git a/var/spack/repos/builtin/packages/arpack-ng/package.py b/var/spack/repos/builtin/packages/arpack-ng/package.py index 70b1b4820ce..49feb262cb1 100644 --- a/var/spack/repos/builtin/packages/arpack-ng/package.py +++ b/var/spack/repos/builtin/packages/arpack-ng/package.py @@ -2,11 +2,12 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - +import spack.build_systems.autotools +import spack.build_systems.cmake from spack.package import * -class ArpackNg(Package): +class ArpackNg(CMakePackage, AutotoolsPackage): """ARPACK-NG is a collection of Fortran77 subroutines designed to solve large scale eigenvalue problems. @@ -38,6 +39,8 @@ class ArpackNg(Package): url = "https://github.com/opencollab/arpack-ng/archive/3.3.0.tar.gz" git = "https://github.com/opencollab/arpack-ng.git" + build_system("cmake", "autotools", default="cmake") + version("develop", branch="master") version("3.8.0", sha256="ada5aeb3878874383307239c9235b716a8a170c6d096a6625bfd529844df003d") version("3.7.0", sha256="972e3fc3cd0b9d6b5a737c9bf6fd07515c0d6549319d4ffb06970e64fa3cc2d6") @@ -74,13 +77,14 @@ class ArpackNg(Package): depends_on("blas") depends_on("lapack") - depends_on("automake", when="@3.3.0", type="build") - depends_on("autoconf", when="@3.3.0", type="build") - depends_on("libtool@2.4.2:", when="@3.3.0", type="build") - depends_on("cmake@2.8.6:", when="@3.4.0:", type="build") - depends_on("mpi", when="+mpi") + with when("build_system=autotools"): + depends_on("automake", type="build") + depends_on("autoconf", type="build") + depends_on("libtool@2.4.2:", type="build") + depends_on("pkgconfig", type="build") + def flag_handler(self, name, flags): spec = self.spec iflags = [] @@ -105,36 +109,26 @@ def libs(self): return find_libraries(libraries, root=self.prefix, shared=True, recursive=True) - @when("@:3.7.0 %gcc@10:") - def setup_build_environment(self, env): - # version up to and including 3.7.0 are not ported to gcc 10 - # https://github.com/opencollab/arpack-ng/issues/242 - env.set("FFLAGS", "-fallow-argument-mismatch") - @when("@3.4.0:") - def install(self, spec, prefix): - - options = ["-DEXAMPLES=ON"] - options.extend(std_cmake_args) - options.append("-DCMAKE_INSTALL_NAME_DIR:PATH=%s/lib" % prefix) - - # Make sure we use Spack's blas/lapack: +class CMakeBuilder(spack.build_systems.cmake.CMakeBuilder): + def cmake_args(self): + spec = self.spec lapack_libs = spec["lapack"].libs.joined(";") blas_libs = spec["blas"].libs.joined(";") - options.extend( - [ - "-DLAPACK_FOUND=true", - "-DLAPACK_INCLUDE_DIRS={0}".format(spec["lapack"].prefix.include), - "-DLAPACK_LIBRARIES={0}".format(lapack_libs), - "-DBLAS_FOUND=true", - "-DBLAS_INCLUDE_DIRS={0}".format(spec["blas"].prefix.include), - "-DBLAS_LIBRARIES={0}".format(blas_libs), - ] - ) - - if "+mpi" in spec: - options.append("-DMPI=ON") + options = [ + self.define("EXAMPLES", "ON"), + self.define("CMAKE_INSTALL_NAME_DIR", self.prefix.lib), + self.define("LAPACK_FOUND", True), + self.define("LAPACK_INCLUDE_DIRS", spec["lapack"].prefix.include), + self.define("LAPACK_LIBRARIES", lapack_libs), + self.define("BLAS_FOUND", True), + self.define("BLAS_INCLUDE_DIRS", spec["blas"].prefix.include), + self.define("BLAS_LIBRARIES", blas_libs), + self.define_from_variant("MPI", "mpi"), + self.define_from_variant("BUILD_SHARED_LIBS", "shared"), + self.define("CMAKE_POSITION_INDEPENDENT_CODE", True), + ] # If 64-bit BLAS is used: if ( @@ -144,41 +138,28 @@ def install(self, spec, prefix): ): options.append("-DINTERFACE64=1") - if "+shared" in spec: - options.append("-DBUILD_SHARED_LIBS=ON") - else: - options.append("-DBUILD_SHARED_LIBS=OFF") - options.append("-DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=true") + return options - cmake(".", *options) - make() - if self.run_tests: - make("test") - make("install") - @when("@3.3.0") - def install(self, spec, prefix): - # Apparently autotools are not bootstrapped - which("libtoolize")() - bootstrap = Executable("./bootstrap") - - options = ["--prefix=%s" % prefix] - - if "+mpi" in spec: - options.extend(["--enable-mpi", "F77=%s" % spec["mpi"].mpif77]) - - options.extend( - [ +class AutotoolsBuilder(spack.build_systems.autotools.AutotoolsBuilder): + def configure_args(self): + spec = self.spec + options = ( + self.enable_or_disable("mpi") + + [ "--with-blas={0}".format(spec["blas"].libs.ld_flags), "--with-lapack={0}".format(spec["lapack"].libs.ld_flags), ] + + self.enable_or_disable("shared") ) - if "+shared" not in spec: - options.append("--enable-shared=no") - bootstrap() - configure(*options) - make() - if self.run_tests: - make("check") - make("install") + if "+mpi" in spec: + options.append("F77={0}".format(spec["mpi"].mpif77)) + + return options + + @when("@:3.7.0 %gcc@10:") + def setup_build_environment(self, env): + # version up to and including 3.7.0 are not ported to gcc 10 + # https://github.com/opencollab/arpack-ng/issues/242 + env.set("FFLAGS", "-fallow-argument-mismatch") diff --git a/var/spack/repos/builtin/packages/binutils/package.py b/var/spack/repos/builtin/packages/binutils/package.py index 9ba963b019e..f5a9ae7fd90 100644 --- a/var/spack/repos/builtin/packages/binutils/package.py +++ b/var/spack/repos/builtin/packages/binutils/package.py @@ -4,6 +4,7 @@ # SPDX-License-Identifier: (Apache-2.0 OR MIT) import re +import spack.build_systems.autotools from spack.package import * @@ -40,13 +41,21 @@ class Binutils(AutotoolsPackage, GNUMirrorPackage): version("2.20.1", sha256="71d37c96451333c5c0b84b170169fdcb138bbb27397dc06281905d9717c8ed64") variant("plugins", default=True, description="enable plugins, needed for gold linker") - variant("gold", default=False, description="build the gold linker") + # When you build ld.gold you automatically get ld, even when you add the + # --disable-ld flag + variant("gold", default=False, when="+ld", description="build the gold linker") variant("libiberty", default=False, description="Also install libiberty.") variant("nls", default=True, description="Enable Native Language Support") variant("headers", default=False, description="Install extra headers (e.g. ELF)") variant("lto", default=False, description="Enable lto.") variant("ld", default=False, description="Enable ld.") - variant("gas", default=False, description="Enable as assembler.") + # When you build binutils with ~ld and +gas and load it in your PATH, you + # may end up with incompatibilities between a potentially older system ld + # and a recent assembler. For instance the linker on ubuntu 16.04 from + # binutils 2.26 and the assembler from binutils 2.36.1 will result in: + # "unable to initialize decompress status for section .debug_info" + # when compiling with debug symbols on gcc. + variant("gas", default=False, when="+ld", description="Enable as assembler.") variant("interwork", default=False, description="Enable interwork.") variant( "libs", @@ -81,83 +90,12 @@ class Binutils(AutotoolsPackage, GNUMirrorPackage): conflicts("+gold", when="platform=darwin", msg="Binutils cannot build linkers on macOS") - # When you build binutils with ~ld and +gas and load it in your PATH, you - # may end up with incompatibilities between a potentially older system ld - # and a recent assembler. For instance the linker on ubuntu 16.04 from - # binutils 2.26 and the assembler from binutils 2.36.1 will result in: - # "unable to initialize decompress status for section .debug_info" - # when compiling with debug symbols on gcc. - conflicts("+gas", "~ld", msg="Assembler not always compatible with system ld") - - # When you build ld.gold you automatically get ld, even when you add the - # --disable-ld flag - conflicts("~ld", "+gold") - @classmethod def determine_version(cls, exe): output = Executable(exe)("--version", output=str, error=str) match = re.search(r"GNU (nm|readelf).* (\S+)", output) return Version(match.group(2)).dotted.up_to(3) if match else None - def setup_build_environment(self, env): - - if self.spec.satisfies("%cce"): - env.append_flags("LDFLAGS", "-Wl,-z,muldefs") - - if "+nls" in self.spec: - env.append_flags("LDFLAGS", "-lintl") - - def configure_args(self): - spec = self.spec - - args = [ - "--disable-dependency-tracking", - "--disable-werror", - "--enable-multilib", - "--enable-64-bit-bfd", - "--enable-targets=all", - "--with-system-zlib", - "--with-sysroot=/", - ] - - args += self.enable_or_disable("libs") - args += self.enable_or_disable("lto") - args += self.enable_or_disable("ld") - args += self.enable_or_disable("gas") - args += self.enable_or_disable("interwork") - args += self.enable_or_disable("gold") - args += self.enable_or_disable("plugins") - - if "+libiberty" in spec: - args.append("--enable-install-libiberty") - else: - args.append("--disable-install-libiberty") - - if "+nls" in spec: - args.append("--enable-nls") - else: - args.append("--disable-nls") - - # To avoid namespace collisions with Darwin/BSD system tools, - # prefix executables with "g", e.g., gar, gnm; see Homebrew - # https://github.com/Homebrew/homebrew-core/blob/master/Formula/binutils.rb - if spec.satisfies("platform=darwin"): - args.append("--program-prefix=g") - - return args - - @run_after("install") - def install_headers(self): - # some packages (like TAU) need the ELF headers, so install them - # as a subdirectory in include/extras - if "+headers" in self.spec: - extradir = join_path(self.prefix.include, "extra") - mkdirp(extradir) - # grab the full binutils set of headers - install_tree("include", extradir) - # also grab the headers from the bfd directory - install(join_path(self.build_directory, "bfd", "*.h"), extradir) - def flag_handler(self, name, flags): spec = self.spec # Use a separate variable for injecting flags. This way, installing @@ -204,3 +142,55 @@ def test(self): self.run_test( exe, "--version", expected, installed=True, purpose=reason, skip_missing=True ) + + +class AutotoolsBuilder(spack.build_systems.autotools.AutotoolsBuilder): + def configure_args(self): + args = [ + "--disable-dependency-tracking", + "--disable-werror", + "--enable-multilib", + "--enable-64-bit-bfd", + "--enable-targets=all", + "--with-system-zlib", + "--with-sysroot=/", + ] + args += self.enable_or_disable("libs") + args += self.enable_or_disable("lto") + args += self.enable_or_disable("ld") + args += self.enable_or_disable("gas") + args += self.enable_or_disable("interwork") + args += self.enable_or_disable("gold") + args += self.enable_or_disable("nls") + args += self.enable_or_disable("plugins") + + if "+libiberty" in self.spec: + args.append("--enable-install-libiberty") + else: + args.append("--disable-install-libiberty") + + # To avoid namespace collisions with Darwin/BSD system tools, + # prefix executables with "g", e.g., gar, gnm; see Homebrew + # https://github.com/Homebrew/homebrew-core/blob/master/Formula/binutils.rb + if self.spec.satisfies("platform=darwin"): + args.append("--program-prefix=g") + + return args + + @run_after("install", when="+headers") + def install_headers(self): + # some packages (like TAU) need the ELF headers, so install them + # as a subdirectory in include/extras + extradir = join_path(self.prefix.include, "extra") + mkdirp(extradir) + # grab the full binutils set of headers + install_tree("include", extradir) + # also grab the headers from the bfd directory + install(join_path(self.build_directory, "bfd", "*.h"), extradir) + + def setup_build_environment(self, env): + if self.spec.satisfies("%cce"): + env.append_flags("LDFLAGS", "-Wl,-z,muldefs") + + if "+nls" in self.spec: + env.append_flags("LDFLAGS", "-lintl") diff --git a/var/spack/repos/builtin/packages/clara/package.py b/var/spack/repos/builtin/packages/clara/package.py index 3eaea61ce54..fadec16835b 100644 --- a/var/spack/repos/builtin/packages/clara/package.py +++ b/var/spack/repos/builtin/packages/clara/package.py @@ -2,19 +2,26 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - +import spack.build_systems.generic from spack.package import * -class Clara(CMakePackage): +class Clara(CMakePackage, Package): """A simple to use, composable, command line parser for C++ 11 - and beyond.""" + and beyond. + """ homepage = "https://github.com/catchorg/Clara" url = "https://github.com/catchorg/Clara/archive/v1.1.5.tar.gz" maintainers = ["bvanessen"] + build_system( + conditional("generic", when="+single_header"), + conditional("cmake", when="~single_header"), + default="generic", + ) + variant("single_header", default=True, description="Install a single header only.") version("1.1.5", sha256="767dc1718e53678cbea00977adcd0a8a195802a505aec3c537664cf25a173142") @@ -24,15 +31,8 @@ class Clara(CMakePackage): version("1.1.1", sha256="10915a49a94d371f05af360d40e9cc9615ab86f200d261edf196a8ddd7efa7f8") version("1.1.0", sha256="29ca29d843150aabad702356f79009f5b30dda05ac9674a064362b7edcba5477") - @when("+single_header") - def cmake(self, spec, prefix): - pass - @when("+single_header") - def build(self, spec, prefix): - pass - - @when("+single_header") - def install(self, spec, prefix): +class GenericBuilder(spack.build_systems.generic.GenericBuilder): + def install(self, pkg, spec, prefix): mkdirp(prefix.include) install_tree("single_include", prefix.include) diff --git a/var/spack/repos/builtin/packages/flex/package.py b/var/spack/repos/builtin/packages/flex/package.py index 8f3d496bb57..f0754ec86d8 100644 --- a/var/spack/repos/builtin/packages/flex/package.py +++ b/var/spack/repos/builtin/packages/flex/package.py @@ -113,20 +113,19 @@ def configure_args(self): args += self.enable_or_disable("nls") return args - @run_after("install") + @run_after("install", when="+lex") def symlink_lex(self): """Install symlinks for lex compatibility.""" - if self.spec.satisfies("+lex"): - dso = dso_suffix - for dir, flex, lex in ( - (self.prefix.bin, "flex", "lex"), - (self.prefix.lib, "libfl.a", "libl.a"), - (self.prefix.lib, "libfl." + dso, "libl." + dso), - (self.prefix.lib64, "libfl.a", "libl.a"), - (self.prefix.lib64, "libfl." + dso, "libl." + dso), - ): + dso = dso_suffix + for dir, flex, lex in ( + (self.prefix.bin, "flex", "lex"), + (self.prefix.lib, "libfl.a", "libl.a"), + (self.prefix.lib, "libfl." + dso, "libl." + dso), + (self.prefix.lib64, "libfl.a", "libl.a"), + (self.prefix.lib64, "libfl." + dso, "libl." + dso), + ): - if os.path.isdir(dir): - with working_dir(dir): - if os.path.isfile(flex) and not os.path.lexists(lex): - symlink(flex, lex) + if os.path.isdir(dir): + with working_dir(dir): + if os.path.isfile(flex) and not os.path.lexists(lex): + symlink(flex, lex) diff --git a/var/spack/repos/builtin/packages/gobject-introspection/package.py b/var/spack/repos/builtin/packages/gobject-introspection/package.py index 9ea90684e83..624d0941f8e 100644 --- a/var/spack/repos/builtin/packages/gobject-introspection/package.py +++ b/var/spack/repos/builtin/packages/gobject-introspection/package.py @@ -2,15 +2,16 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - +import spack.build_systems.autotools import spack.hooks.sbang as sbang from spack.package import * -class GobjectIntrospection(MesonPackage): +class GobjectIntrospection(MesonPackage, AutotoolsPackage): """The GObject Introspection is used to describe the program APIs and collect them in a uniform, machine readable format.Cairo is a 2D graphics - library with support for multiple output""" + library with support for multiple output + """ homepage = "https://wiki.gnome.org/Projects/GObjectIntrospection" url = "https://download.gnome.org/sources/gobject-introspection/1.72/gobject-introspection-1.72.0.tar.xz" @@ -22,6 +23,12 @@ class GobjectIntrospection(MesonPackage): version("1.49.2", sha256="73d59470ba1a546b293f54d023fd09cca03a951005745d86d586b9e3a8dde9ac") version("1.48.0", sha256="fa275aaccdbfc91ec0bc9a6fd0562051acdba731e7d584b64a277fec60e75877") + build_system( + conditional("autotools", when="@:1.60"), + conditional("meson", when="@1.61:"), + default="meson", + ) + depends_on("pkgconfig", type="build") depends_on("bison", type="build") depends_on("flex", type="build") @@ -94,22 +101,9 @@ def setup_dependent_run_environment(self, env, dependent_spec): def parallel(self): return not self.spec.satisfies("%fj") - def meson_args(self): - return [] - @when("@:1.60") - def meson(self, spec, prefix): - """Run the AutotoolsPackage configure phase""" - configure("--prefix={0}".format(prefix)) - - @when("@:1.60") - def build(self, spec, prefix): - """Run the AutotoolsPackage build phase""" +class AutotoolsBuilderPackage(spack.build_systems.autotools.AutotoolsBuilder): + @run_before("build") + def filter_file_to_avoid_overly_long_shebangs(self): # we need to filter this file to avoid an overly long hashbang line filter_file("#!/usr/bin/env @PYTHON@", "#!@PYTHON@", "tools/g-ir-tool-template.in") - make() - - @when("@:1.60") - def install(self, spec, prefix): - """Run the AutotoolsPackage install phase""" - make("install", parallel=False) diff --git a/var/spack/repos/builtin/packages/harfbuzz/package.py b/var/spack/repos/builtin/packages/harfbuzz/package.py index 0400c0a21ab..e746ed6fbf7 100644 --- a/var/spack/repos/builtin/packages/harfbuzz/package.py +++ b/var/spack/repos/builtin/packages/harfbuzz/package.py @@ -2,11 +2,12 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - +import spack.build_systems.autotools +import spack.build_systems.meson from spack.package import * -class Harfbuzz(MesonPackage): +class Harfbuzz(MesonPackage, AutotoolsPackage): """The Harfbuzz package contains an OpenType text shaping engine.""" homepage = "https://github.com/harfbuzz/harfbuzz" @@ -14,6 +15,10 @@ class Harfbuzz(MesonPackage): git = "https://github.com/harfbuzz/harfbuzz.git" version("5.1.0", sha256="2edb95db668781aaa8d60959d21be2ff80085f31b12053cdd660d9a50ce84f05") + build_system( + conditional("autotools", when="@:2.9"), conditional("meson", when="@3:"), default="meson" + ) + version("4.2.1", sha256="bd17916513829aeff961359a5ccebba6de2f4bf37a91faee3ac29c120e3d7ee1") version("4.1.0", sha256="f7984ff4241d4d135f318a93aa902d910a170a8265b7eaf93b5d9a504eed40c8") version("4.0.1", sha256="98f68777272db6cd7a3d5152bac75083cd52a26176d87bc04c8b3929d33bce49") @@ -99,31 +104,33 @@ def flag_handler(self, name, flags): def setup_run_environment(self, env): env.prepend_path("GI_TYPELIB_PATH", join_path(self.prefix.lib, "girepository-1.0")) - def setup_dependent_build_environment(self, env, dependent_spec): - env.prepend_path("XDG_DATA_DIRS", self.prefix.share) - env.prepend_path("GI_TYPELIB_PATH", join_path(self.prefix.lib, "girepository-1.0")) - def setup_dependent_run_environment(self, env, dependent_spec): env.prepend_path("XDG_DATA_DIRS", self.prefix.share) env.prepend_path("GI_TYPELIB_PATH", join_path(self.prefix.lib, "girepository-1.0")) + def patch(self): + change_sed_delimiter("@", ";", "src/Makefile.in") + + +class SetupEnvironment(object): + def setup_dependent_build_environment(self, env, dependent_spec): + env.prepend_path("XDG_DATA_DIRS", self.prefix.share) + env.prepend_path("GI_TYPELIB_PATH", join_path(self.prefix.lib, "girepository-1.0")) + + +class MesonBuilder(spack.build_systems.meson.MesonBuilder, SetupEnvironment): def meson_args(self): - args = [] + graphite2 = "enabled" if self.pkg.spec.satisfies("+graphite2") else "disabled" + coretext = "enabled" if self.pkg.spec.satisfies("+coretext") else "disabled" + return [ + # disable building of gtk-doc files following #9885 and #9771 + "-Ddocs=disabled", + "-Dgraphite2={0}".format(graphite2), + "-Dcoretext={0}".format(coretext), + ] - # disable building of gtk-doc files following #9885 and #9771 - args.append("-Ddocs=disabled") - args.append( - "-Dgraphite2=" + ("enabled" if self.spec.satisfies("+graphite2") else "disabled") - ) - if "+coretext" in self.spec: - args.append("-Dcoretext=enabled") - elif "~coretext" in self.spec: - args.append("-Dcoretext=disabled") - - return args - - @when("@:2.9") +class AutotoolsBuilder(spack.build_systems.autotools.AutotoolsBuilder, SetupEnvironment): def configure_args(self): args = [] @@ -135,28 +142,6 @@ def configure_args(self): args.append("GTKDOC_MKPDF={0}".format(true)) args.append("GTKDOC_REBASE={0}".format(true)) args.extend(self.with_or_without("graphite2")) - - if "+coretext" in self.spec: - args.append("--with-coretext") - elif "~coretext" in self.spec: - args.append("--without-coretext") + args.extend(self.with_or_without("coretext")) return args - - def patch(self): - change_sed_delimiter("@", ";", "src/Makefile.in") - - @when("@:2.9") - def meson(self, spec, prefix): - """Run the AutotoolsPackage configure phase""" - configure("--prefix=" + prefix, *self.configure_args()) - - @when("@:2.9") - def build(self, spec, prefix): - """Run the AutotoolsPackage build phase""" - make() - - @when("@:2.9") - def install(self, spec, prefix): - """Run the AutotoolsPackage install phase""" - make("install") diff --git a/var/spack/repos/builtin/packages/ibm-databroker/package.py b/var/spack/repos/builtin/packages/ibm-databroker/package.py index ae80f924396..9c0516844bb 100644 --- a/var/spack/repos/builtin/packages/ibm-databroker/package.py +++ b/var/spack/repos/builtin/packages/ibm-databroker/package.py @@ -7,7 +7,7 @@ from spack.package import * -class IbmDatabroker(CMakePackage, PythonPackage): +class IbmDatabroker(CMakePackage, PythonExtension): """The Data Broker (DBR) is a distributed, in-memory container of key-value stores enabling applications in a workflow to exchange data through one or more shared namespaces. Thanks to a small set of primitives, applications diff --git a/var/spack/repos/builtin/packages/intel-tbb/package.py b/var/spack/repos/builtin/packages/intel-tbb/package.py index 1bc13ac1a33..8921604b08f 100644 --- a/var/spack/repos/builtin/packages/intel-tbb/package.py +++ b/var/spack/repos/builtin/packages/intel-tbb/package.py @@ -8,10 +8,12 @@ import platform import sys +import spack.build_systems.cmake +import spack.build_systems.makefile from spack.package import * -class IntelTbb(CMakePackage): +class IntelTbb(CMakePackage, MakefilePackage): """Widely used C++ template library for task parallelism. Intel Threading Building Blocks (Intel TBB) lets you easily write parallel C++ programs that take full advantage of multicore performance, that are @@ -74,6 +76,12 @@ class IntelTbb(CMakePackage): version("4.4.1", sha256="05737bf6dd220b31aad63d77ca59c742271f81b4cc6643aa6f93d37450ae32b5") version("4.4", sha256="93c74b6054c69c86fa49d0fce7c50061fc907cb198a7237b8dd058298fd40c0e") + build_system( + conditional("makefile", when="@:2020.3"), + conditional("cmake", when="@2021:"), + default="cmake", + ) + provides("tbb") # Clang builds incorrectly determine GCC version which in turn incorrectly @@ -161,12 +169,54 @@ def url_for_version(self, version): name = "{0}".format(version) return url.format(name) + @property + def libs(self): + shared = True if "+shared" in self.spec else False + return find_libraries("libtbb*", root=self.prefix, shared=shared, recursive=True) + + +class SetupEnvironment(object): # We set OS here in case the user has it set to something else # that TBB doesn't expect. def setup_build_environment(self, env): env.set("OS", platform.system()) - @when("@:2020.3") + +class CMakeBuilder(spack.build_systems.cmake.CMakeBuilder, SetupEnvironment): + def cmake_args(self): + spec = self.spec + options = [ + self.define("CMAKE_HWLOC_2_INCLUDE_PATH", spec["hwloc"].prefix.include), + self.define("CMAKE_HWLOC_2_LIBRARY_PATH", spec["hwloc"].libs), + self.define("-DTBB_CPF", True), + self.define("TBB_STRICT", False), + ] + if spec.variants["cxxstd"].value != "default": + options.append(self.define("CMAKE_CXX_STANDARD", spec.variants["cxxstd"].value)) + return options + + @run_after("install") + def install_pkgconfig(self): + # pkg-config generation is introduced in May 5, 2021. + # It must not be overwritten by spack-generated tbb.pc. + # https://github.com/oneapi-src/oneTBB/commit/478de5b1887c928e52f029d706af6ea640a877be + if self.spec.satisfies("@:2021.2.0", strict=True): + mkdirp(self.prefix.lib.pkgconfig) + + with open(join_path(self.prefix.lib.pkgconfig, "tbb.pc"), "w") as f: + f.write("prefix={0}\n".format(self.prefix)) + f.write("exec_prefix=${prefix}\n") + f.write("libdir={0}\n".format(self.prefix.lib)) + f.write("includedir={0}\n".format(self.prefix.include)) + f.write("\n") + f.write("Name: Threading Building Blocks\n") + f.write("Description: Intel's parallelism library for C++\n") + f.write("Version: {0}\n".format(self.spec.version)) + f.write("Cflags: -I${includedir}\n") + f.write("Libs: -L${libdir} -ltbb -latomic\n") + + +class MakefileBuilder(spack.build_systems.makefile.MakefileBuilder, SetupEnvironment): def coerce_to_spack(self, tbb_build_subdir): for compiler in ["icc", "gcc", "clang"]: fs = glob.glob(join_path(tbb_build_subdir, "*.%s.inc" % compiler)) @@ -183,16 +233,7 @@ def coerce_to_spack(self, tbb_build_subdir): else: of.write(lin) - @when("@:2020.3") - def cmake(self, spec, prefix): - return - - @when("@:2020.3") - def cmake_args(self): - return - - @when("@:2020.3") - def build(self, spec, prefix): + def build(self, pkg, spec, prefix): # Deactivate use of RTM with GCC when on an OS with a very old # assembler. if ( @@ -239,8 +280,7 @@ def build(self, spec, prefix): make_opts.append("compiler={0}".format(tbb_compiler)) make(*make_opts) - @when("@:2020.3") - def install(self, spec, prefix): + def install(self, pkg, spec, prefix): mkdirp(prefix) mkdirp(prefix.lib) @@ -267,46 +307,8 @@ def install(self, spec, prefix): with working_dir(join_path(self.stage.source_path, "cmake")): inspect.getmodule(self).cmake(*cmake_args) - @when("@:2020.3") @run_after("install") def darwin_fix(self): # Replace @rpath in ids with full path if sys.platform == "darwin": fix_darwin_install_name(self.prefix.lib) - - @property - def libs(self): - shared = True if "+shared" in self.spec else False - return find_libraries("libtbb*", root=self.prefix, shared=shared, recursive=True) - - @when("@2021.1.1:") - def cmake_args(self): - spec = self.spec - options = [] - options.append("-DCMAKE_HWLOC_2_INCLUDE_PATH=%s" % spec["hwloc"].prefix.include) - options.append("-DCMAKE_HWLOC_2_LIBRARY_PATH=%s" % spec["hwloc"].libs) - options.append("-DTBB_CPF=ON") - options.append("-DTBB_STRICT=OFF") - if spec.variants["cxxstd"].value != "default": - options.append("-DCMAKE_CXX_STANDARD=%s" % spec.variants["cxxstd"].value) - return options - - @run_after("install") - def install_pkgconfig(self): - # pkg-config generation is introduced in May 5, 2021. - # It must not be overwritten by spack-generated tbb.pc. - # https://github.com/oneapi-src/oneTBB/commit/478de5b1887c928e52f029d706af6ea640a877be - if self.spec.satisfies("@:2021.2.0", strict=True): - mkdirp(self.prefix.lib.pkgconfig) - - with open(join_path(self.prefix.lib.pkgconfig, "tbb.pc"), "w") as f: - f.write("prefix={0}\n".format(self.prefix)) - f.write("exec_prefix=${prefix}\n") - f.write("libdir={0}\n".format(self.prefix.lib)) - f.write("includedir={0}\n".format(self.prefix.include)) - f.write("\n") - f.write("Name: Threading Building Blocks\n") - f.write("Description: Intel's parallelism library for C++\n") - f.write("Version: {0}\n".format(self.spec.version)) - f.write("Cflags: -I${includedir}\n") - f.write("Libs: -L${libdir} -ltbb -latomic\n") diff --git a/var/spack/repos/builtin/packages/json-c/package.py b/var/spack/repos/builtin/packages/json-c/package.py index 559039f21db..a62e0323ea8 100644 --- a/var/spack/repos/builtin/packages/json-c/package.py +++ b/var/spack/repos/builtin/packages/json-c/package.py @@ -6,7 +6,7 @@ from spack.package import * -class JsonC(CMakePackage): +class JsonC(CMakePackage, AutotoolsPackage): """A JSON implementation in C.""" homepage = "https://github.com/json-c/json-c/wiki" @@ -20,7 +20,13 @@ class JsonC(CMakePackage): version("0.12", sha256="000c01b2b3f82dcb4261751eb71f1b084404fb7d6a282f06074d3c17078b9f3f") version("0.11", sha256="28dfc65145dc0d4df1dfe7701ac173c4e5f9347176c8983edbfac9149494448c") - depends_on("autoconf", when="@:0.13.1", type="build") + build_system( + conditional("cmake", when="@0.14:"), + conditional("autotools", when="@:0.13.1"), + default="cmake", + ) + + depends_on("autoconf", when="build_system=autotools", type="build") parallel = False @@ -32,19 +38,6 @@ def patch(self): "Makefile.in", ) - @when("@:0.13.1") - def cmake(self, spec, prefix): - configure_args = ["--prefix=" + prefix] - configure(*configure_args) - - @when("@:0.13.1") - def build(self, spec, prefix): - make() - - @when("@:0.13.1") - def install(self, spec, prefix): - make("install") - @when("%cce@11.0.3:") def patch(self): filter_file("-Werror", "", "CMakeLists.txt") diff --git a/var/spack/repos/builtin/packages/libtree/package.py b/var/spack/repos/builtin/packages/libtree/package.py index 572f459b43a..a1c97dfd767 100644 --- a/var/spack/repos/builtin/packages/libtree/package.py +++ b/var/spack/repos/builtin/packages/libtree/package.py @@ -2,11 +2,12 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - +import spack.build_systems.cmake +import spack.build_systems.makefile from spack.package import * -class Libtree(MakefilePackage): +class Libtree(MakefilePackage, CMakePackage): """ldd as a tree""" homepage = "https://github.com/haampie/libtree" @@ -35,6 +36,10 @@ class Libtree(MakefilePackage): version("1.0.4", sha256="b15a54b6f388b8bd8636e288fcb581029f1e65353660387b0096a554ad8e9e45") version("1.0.3", sha256="67ce886c191d50959a5727246cdb04af38872cd811c9ed4e3822f77a8f40b20b") + build_system( + conditional("cmake", when="@:2"), conditional("makefile", when="@3:"), default="makefile" + ) + def url_for_version(self, version): if version < Version("2.0.0"): return ( @@ -45,13 +50,8 @@ def url_for_version(self, version): return "https://github.com/haampie/libtree/archive/refs/tags/v{0}.tar.gz".format(version) - # Version 3.x (Makefile) - @when("@3:") - def install(self, spec, prefix): - make("install", "PREFIX=" + prefix) - # Version 2.x and earlier (CMake) - with when("@:2"): + with when("build_system=cmake"): variant("chrpath", default=False, description="Use chrpath for deployment") variant("strip", default=False, description="Use binutils strip for deployment") variant( @@ -70,23 +70,19 @@ def install(self, spec, prefix): depends_on("cxxopts", when="@2.0.0:2", type="build") depends_on("elfio@:3.9", when="@2.0.0:2", type="build") + +class CMakeBuilder(spack.build_systems.cmake.CMakeBuilder): def cmake_args(self): - tests_enabled = "ON" if self.run_tests else "OFF" + tests_enabled = "ON" if self.pkg.run_tests else "OFF" if self.spec.satisfies("@2.0:"): tests_define = "LIBTREE_BUILD_TESTS" else: tests_define = "BUILD_TESTING" - return [CMakePackage.define(tests_define, tests_enabled)] + return [self.define(tests_define, tests_enabled)] - @when("@:2") - def edit(self, spec, prefix): - options = CMakePackage._std_args(self) + self.cmake_args() - options.append(self.stage.source_path) - with working_dir(self.build_directory): - cmake(*options) - @when("@:2") - def check(self): - with working_dir(self.build_directory): - ctest("--output-on-failure") +class MakefileBuilder(spack.build_systems.makefile.MakefileBuilder): + @property + def install_targets(self): + return ["install", "PREFIX=" + self.prefix] diff --git a/var/spack/repos/builtin/packages/libxkbcommon/package.py b/var/spack/repos/builtin/packages/libxkbcommon/package.py index b7003ab5a99..054f05e9bdc 100644 --- a/var/spack/repos/builtin/packages/libxkbcommon/package.py +++ b/var/spack/repos/builtin/packages/libxkbcommon/package.py @@ -2,11 +2,12 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - +import spack.build_systems.autotools +import spack.build_systems.meson from spack.package import * -class Libxkbcommon(MesonPackage): +class Libxkbcommon(MesonPackage, AutotoolsPackage): """xkbcommon is a library to handle keyboard descriptions, including loading them from disk, parsing them and handling their state. It's mainly meant for client toolkits, window systems, and other system @@ -15,6 +16,10 @@ class Libxkbcommon(MesonPackage): homepage = "https://xkbcommon.org/" url = "https://xkbcommon.org/download/libxkbcommon-0.8.2.tar.xz" + build_system( + conditional("meson", when="@0.9:"), conditional("autotools", when="@:0.8"), default="meson" + ) + version("1.4.0", sha256="106cec5263f9100a7e79b5f7220f889bc78e7d7ffc55d2b6fdb1efefb8024031") version( "0.8.2", @@ -44,6 +49,8 @@ class Libxkbcommon(MesonPackage): depends_on("wayland@1.2.0:", when="+wayland") depends_on("wayland-protocols@1.7:", when="+wayland") + +class MesonBuilder(spack.build_systems.meson.MesonBuilder): def meson_args(self): return [ "-Dxkb-config-root={0}".format(self.spec["xkbdata"].prefix), @@ -51,26 +58,11 @@ def meson_args(self): "-Denable-wayland=" + str(self.spec.satisfies("+wayland")), ] - @when("@:0.8") + +class AutotoolsBuilder(spack.build_systems.autotools.AutotoolsBuilder): def configure_args(self): """Configure arguments are passed using meson_args functions""" return [ "--with-xkb-config-root={0}".format(self.spec["xkbdata"].prefix), "--disable-docs", - "--" + ("en" if self.spec.satisfies("+wayland") else "dis") + "able-wayland", - ] - - @when("@:0.8") - def meson(self, spec, prefix): - """Run the AutotoolsPackage configure phase in source_path""" - configure("--prefix=" + prefix, *self.configure_args()) - - @when("@:0.8") - def build(self, spec, prefix): - """Run the AutotoolsPackage build phase in source_path""" - make() - - @when("@:0.8") - def install(self, spec, prefix): - """Run the AutotoolsPackage install phase in source_path""" - make("install") + ] + self.enable_or_disable("wayland") diff --git a/var/spack/repos/builtin/packages/lua/package.py b/var/spack/repos/builtin/packages/lua/package.py index cd314f3df5b..4894ab2b91f 100644 --- a/var/spack/repos/builtin/packages/lua/package.py +++ b/var/spack/repos/builtin/packages/lua/package.py @@ -26,11 +26,6 @@ class LuaImplPackage(MakefilePackage): description="Fetcher to use in the LuaRocks package manager", ) - phases = MakefilePackage.phases + ["add_luarocks"] - #: This attribute is used in UI queries that need to know the build - #: system base class - build_system_class = "LuaImplPackage" - lua_version_override = None def __init__(self, *args, **kwargs): @@ -105,7 +100,9 @@ def symlink_luajit(self): ) symlink(real_lib, "liblua" + ext) - def add_luarocks(self, spec, prefix): + @run_after("install") + def add_luarocks(self): + prefix = self.spec.prefix with working_dir(os.path.join("luarocks", "luarocks")): configure("--prefix=" + prefix, "--with-lua=" + prefix) make("build") diff --git a/var/spack/repos/builtin/packages/mesa/package.py b/var/spack/repos/builtin/packages/mesa/package.py index e82bdc37640..caa47f8d641 100644 --- a/var/spack/repos/builtin/packages/mesa/package.py +++ b/var/spack/repos/builtin/packages/mesa/package.py @@ -2,9 +2,9 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - import sys +import spack.build_systems.meson from spack.package import * @@ -158,6 +158,28 @@ def flag_handler(self, name, flags): flags.append("-std=c99") return super(Mesa, self).flag_handler(name, flags) + @property + def libglx_headers(self): + return find_headers("GL/glx", root=self.spec.prefix.include, recursive=False) + + @property + def libglx_libs(self): + return find_libraries("libGL", root=self.spec.prefix, recursive=True) + + @property + def libosmesa_headers(self): + return find_headers("GL/osmesa", root=self.spec.prefix.include, recursive=False) + + @property + def libosmesa_libs(self): + if "platform=windows" in self.spec: + lib_name = "osmesa" + else: + lib_name = "libOSMesa" + return find_libraries(lib_name, root=self.spec.prefix, recursive=True) + + +class MesonBuilder(spack.build_systems.meson.MesonBuilder): def meson_args(self): spec = self.spec args = [ @@ -274,23 +296,3 @@ def meson_args(self): args.append("-Ddri-drivers=" + ",".join(args_dri_drivers)) return args - - @property - def libglx_headers(self): - return find_headers("GL/glx", root=self.spec.prefix.include, recursive=False) - - @property - def libglx_libs(self): - return find_libraries("libGL", root=self.spec.prefix, recursive=True) - - @property - def libosmesa_headers(self): - return find_headers("GL/osmesa", root=self.spec.prefix.include, recursive=False) - - @property - def libosmesa_libs(self): - if "platform=windows" in self.spec: - lib_name = "osmesa" - else: - lib_name = "libOSMesa" - return find_libraries(lib_name, root=self.spec.prefix, recursive=True) diff --git a/var/spack/repos/builtin/packages/metis/gklib_path.patch b/var/spack/repos/builtin/packages/metis/gklib_path.patch new file mode 100644 index 00000000000..2cee12d0446 --- /dev/null +++ b/var/spack/repos/builtin/packages/metis/gklib_path.patch @@ -0,0 +1,11 @@ +--- a/CMakeLists.txt 2022-07-20 21:17:20.352231603 +0200 ++++ b/CMakeLists.txt 2022-07-20 21:19:28.998269385 +0200 +@@ -1,7 +1,7 @@ + cmake_minimum_required(VERSION 2.8) + project(METIS) + +-set(GKLIB_PATH "GKlib" CACHE PATH "path to GKlib") ++set(GKLIB_PATH "${CMAKE_SOURCE_DIR}/GKlib" CACHE PATH "path to GKlib") + set(SHARED FALSE CACHE BOOL "build a shared library") + + if(MSVC) diff --git a/var/spack/repos/builtin/packages/metis/package.py b/var/spack/repos/builtin/packages/metis/package.py index edf99be5ee5..da6e798783d 100644 --- a/var/spack/repos/builtin/packages/metis/package.py +++ b/var/spack/repos/builtin/packages/metis/package.py @@ -2,20 +2,22 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - - import os import sys +import spack.build_systems.cmake +import spack.build_systems.makefile from spack.package import * -class Metis(Package): +class Metis(CMakePackage, MakefilePackage): """METIS is a set of serial programs for partitioning graphs, partitioning finite element meshes, and producing fill reducing orderings for sparse - matrices. The algorithms implemented in METIS are based on the - multilevel recursive-bisection, multilevel k-way, and multi-constraint - partitioning schemes.""" + matrices. + + The algorithms implemented in METIS are based on the multilevel + recursive-bisection, multilevel k-way, and multi-constraint partitioning schemes. + """ homepage = "http://glaros.dtc.umn.edu/gkhome/metis/metis/overview" url = "http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis/metis-5.1.0.tar.gz" @@ -27,52 +29,29 @@ class Metis(Package): version("5.1.0", sha256="76faebe03f6c963127dbb73c13eab58c9a3faeae48779f049066a21c087c5db2") version("4.0.3", sha256="5efa35de80703c1b2c4d0de080fafbcf4e0d363a21149a1ad2f96e0144841a55") - variant("shared", default=True, description="Enables the build of shared libraries.") - variant("gdb", default=False, description="Enables gdb support (version 5+).") - variant("int64", default=False, description="Sets the bit width of METIS's index type to 64.") - variant("real64", default=False, description="Sets the bit width of METIS's real type to 64.") - - # For Metis version 5:, the build system is CMake, provide the - # `build_type` variant. - variant( - "build_type", - default="Release", - description="The build type for the installation (only Debug or" - " Release allowed for version 4).", - values=("Debug", "Release", "RelWithDebInfo", "MinSizeRel"), + build_system( + conditional("cmake", when="@5:"), conditional("makefile", when="@:4"), default="cmake" ) + variant("shared", default=True, description="Build shared libraries") + with when("build_system=cmake"): + variant("gdb", default=False, description="Enable gdb support") + variant("int64", default=False, description="Use index type of 64 bit") + variant("real64", default=False, description="Use real type of 64 bit") - # Prior to version 5, the (non-cmake) build system only knows about - # 'build_type=Debug|Release'. - conflicts("@:4", when="build_type=RelWithDebInfo") - conflicts("@:4", when="build_type=MinSizeRel") - conflicts("@:4", when="+gdb") - conflicts("@:4", when="+int64") - conflicts("@:4", when="+real64") + # Use the correct path to GKLIB when building out of source + patch("gklib_path.patch") + # Install both gklib_defs.h and gklib_rename.h + patch("install_gklib_defs_rename.patch") + # Disable the "misleading indentation" warning when compiling + patch("gklib_nomisleadingindentation_warning.patch", when="%gcc@6:") - depends_on("cmake@2.8:", when="@5:", type="build") + with when("build_system=makefile"): + variant("debug", default=False, description="Compile in debug mode") - patch("install_gklib_defs_rename.patch", when="@5:") - patch("gklib_nomisleadingindentation_warning.patch", when="@5: %gcc@6:") - - def setup_build_environment(self, env): - # Ignore warnings/errors re unrecognized omp pragmas on %intel - if "%intel@14:" in self.spec: - env.append_flags("CFLAGS", "-diag-disable 3180") - # Ignore some warnings to get it to compile with %nvhpc - # 111: statement is unreachable - # 177: variable "foo" was declared but never referenced - # 188: enumerated type mixed with another type - # 550: variable "foo" was set but never used - if "%nvhpc" in self.spec: - env.append_flags("CFLAGS", "--display_error_number") - env.append_flags("CFLAGS", "--diag_suppress 111") - env.append_flags("CFLAGS", "--diag_suppress 177") - env.append_flags("CFLAGS", "--diag_suppress 188") - env.append_flags("CFLAGS", "--diag_suppress 550") - - @when("@5:") def patch(self): + if not self.spec.satisfies("build_system=cmake"): + return + source_path = self.stage.source_path metis_header = FileFilter(join_path(source_path, "include", "metis.h")) @@ -96,18 +75,38 @@ def patch(self): join_path(source_path, "GKlib", "error.c"), ) - @when("@:4") - def install(self, spec, prefix): - # Process library spec and options - options = [] - if "+shared" in spec: - options.append("COPTIONS={0}".format(self.compiler.cc_pic_flag)) - if spec.variants["build_type"].value == "Debug": - options.append("OPTFLAGS=-g -O0") - make(*options) +class SetupEnvironment(object): + def setup_build_environment(self, env): + # Ignore warnings/errors re unrecognized omp pragmas on %intel + if "%intel@14:" in self.spec: + env.append_flags("CFLAGS", "-diag-disable 3180") + # Ignore some warnings to get it to compile with %nvhpc + # 111: statement is unreachable + # 177: variable "foo" was declared but never referenced + # 188: enumerated type mixed with another type + # 550: variable "foo" was set but never used + if "%nvhpc" in self.spec: + env.append_flags("CFLAGS", "--display_error_number") + env.append_flags("CFLAGS", "--diag_suppress 111") + env.append_flags("CFLAGS", "--diag_suppress 177") + env.append_flags("CFLAGS", "--diag_suppress 188") + env.append_flags("CFLAGS", "--diag_suppress 550") + + +class MakefileBuilder(spack.build_systems.makefile.MakefileBuilder, SetupEnvironment): + @property + def build_targets(self): + options = [] + if "+shared" in self.spec: + options.append("COPTIONS={0}".format(self.pkg.compiler.cc_pic_flag)) + if "+debug" in self.spec: + options.append("OPTFLAGS=-g -O0") + return options + + def install(self, pkg, spec, prefix): # Compile and install library files - ccompile = Executable(self.compiler.cc) + ccompile = Executable(pkg.compiler.cc) mkdir(prefix.bin) binfiles = ( @@ -140,7 +139,7 @@ def install(self, spec, prefix): install(sharefile, prefix.share) if "+shared" in spec: - shared_flags = [self.compiler.cc_pic_flag, "-shared"] + shared_flags = [pkg.compiler.cc_pic_flag, "-shared"] if sys.platform == "darwin": shared_suffix = "dylib" shared_flags.extend(["-Wl,-all_load", "libmetis.a"]) @@ -157,7 +156,7 @@ def install(self, spec, prefix): ccompile( "-I%s" % prefix.include, "-L%s" % prefix.lib, - (self.compiler.cc_rpath_arg + prefix.lib if "+shared" in spec else ""), + (pkg.compiler.cc_rpath_arg + prefix.lib if "+shared" in spec else ""), join_path("Programs", "io.o"), join_path("Test", "mtest.c"), "-o", @@ -166,58 +165,32 @@ def install(self, spec, prefix): "-lm", ) - if self.run_tests: - test_bin = lambda testname: join_path(prefix.bin, testname) - test_graph = lambda graphname: join_path(prefix.share, graphname) + def check(self): + test_bin = lambda testname: join_path(prefix.bin, testname) + test_graph = lambda graphname: join_path(prefix.share, graphname) - graph = test_graph("4elt.graph") - os.system("%s %s" % (test_bin("mtest"), graph)) - os.system("%s %s 40" % (test_bin("kmetis"), graph)) - os.system("%s %s" % (test_bin("onmetis"), graph)) - graph = test_graph("test.mgraph") - os.system("%s %s 2" % (test_bin("pmetis"), graph)) - os.system("%s %s 2" % (test_bin("kmetis"), graph)) - os.system("%s %s 5" % (test_bin("kmetis"), graph)) - graph = test_graph("metis.mesh") - os.system("%s %s 10" % (test_bin("partnmesh"), graph)) - os.system("%s %s 10" % (test_bin("partdmesh"), graph)) - os.system("%s %s" % (test_bin("mesh2dual"), graph)) + graph = test_graph("4elt.graph") + os.system("%s %s" % (test_bin("mtest"), graph)) + os.system("%s %s 40" % (test_bin("kmetis"), graph)) + os.system("%s %s" % (test_bin("onmetis"), graph)) + graph = test_graph("test.mgraph") + os.system("%s %s 2" % (test_bin("pmetis"), graph)) + os.system("%s %s 2" % (test_bin("kmetis"), graph)) + os.system("%s %s 5" % (test_bin("kmetis"), graph)) + graph = test_graph("metis.mesh") + os.system("%s %s 10" % (test_bin("partnmesh"), graph)) + os.system("%s %s 10" % (test_bin("partdmesh"), graph)) + os.system("%s %s" % (test_bin("mesh2dual"), graph)) - # FIXME: The following code should replace the testing code in the - # block above since it causes installs to fail when one or more of - # the Metis tests fail, but it currently doesn't work because the - # 'mtest', 'onmetis', and 'partnmesh' tests return error codes that - # trigger false positives for failure. - """ - Executable(test_bin('mtest'))(test_graph('4elt.graph')) - Executable(test_bin('kmetis'))(test_graph('4elt.graph'), '40') - Executable(test_bin('onmetis'))(test_graph('4elt.graph')) - Executable(test_bin('pmetis'))(test_graph('test.mgraph'), '2') - Executable(test_bin('kmetis'))(test_graph('test.mgraph'), '2') - Executable(test_bin('kmetis'))(test_graph('test.mgraph'), '5') +class CMakeBuilder(spack.build_systems.cmake.CMakeBuilder, SetupEnvironment): + def cmake_args(self): + options = [ + self.define_from_variant("SHARED", "shared"), + self.define_from_variant("GDB", "gdb"), + ] - Executable(test_bin('partnmesh'))(test_graph('metis.mesh'), '10') - Executable(test_bin('partdmesh'))(test_graph('metis.mesh'), '10') - Executable(test_bin('mesh2dual'))(test_graph('metis.mesh')) - """ - - @when("@5:") - def install(self, spec, prefix): - source_directory = self.stage.source_path - build_directory = join_path(self.stage.path, "build") - - options = CMakePackage._std_args(self) - options.append("-DGKLIB_PATH:PATH=%s/GKlib" % source_directory) - - # Normally this is available via the 'CMakePackage' object, but metis - # IS-A 'Package' (not a 'CMakePackage') to support non-cmake metis@:5. - build_type = spec.variants["build_type"].value - options.extend(["-DCMAKE_BUILD_TYPE:STRING={0}".format(build_type)]) - - if "+shared" in spec: - options.append("-DSHARED:BOOL=ON") - else: + if self.spec.satisfies("~shared"): # Remove all RPATH options # (RPATHxxx options somehow trigger cmake to link dynamically) rpath_options = [] @@ -226,40 +199,41 @@ def install(self, spec, prefix): rpath_options.append(o) for o in rpath_options: options.remove(o) - if "+gdb" in spec: - options.append("-DGDB:BOOL=ON") - with working_dir(build_directory, create=True): - cmake(source_directory, *options) - make() - make("install") - - # install all headers, which will be needed for ParMETIS and other programs - subdirs = ["GKlib", "libmetis", "programs"] - for subd in subdirs: - inc_dist = join_path(prefix.include, subd) - mkdirp(inc_dist) - install(join_path(source_directory, subd, "*.h"), inc_dist) - - if self.run_tests: - # FIXME: On some systems, the installed binaries for METIS cannot - # be executed without first being read. - ls = which("ls") - ls("-a", "-l", prefix.bin) - - for f in ["4elt", "copter2", "mdual"]: - graph = join_path(source_directory, "graphs", "%s.graph" % f) - Executable(join_path(prefix.bin, "graphchk"))(graph) - Executable(join_path(prefix.bin, "gpmetis"))(graph, "2") - Executable(join_path(prefix.bin, "ndmetis"))(graph) - - graph = join_path(source_directory, "graphs", "test.mgraph") - Executable(join_path(prefix.bin, "gpmetis"))(graph, "2") - graph = join_path(source_directory, "graphs", "metis.mesh") - Executable(join_path(prefix.bin, "mpmetis"))(graph, "2") + return options @run_after("install") + def install_headers(self): + with working_dir(self.build_directory): + # install all headers, which will be needed for ParMETIS and other programs + directories = ["GKlib", "libmetis", "programs"] + for directory in directories: + inc_dist = join_path(self.prefix.include, directory) + mkdirp(inc_dist) + install(join_path(self.stage.source_path, directory, "*.h"), inc_dist) + + def check(self): + # On some systems, the installed binaries for METIS cannot + # be executed without first being read. + ls = which("ls") + ls("-a", "-l", self.prefix.bin) + + graphchk = Executable(join_path(self.prefix.bin, "graphchk")) + gpmetis = Executable(join_path(self.prefix.bin, "gpmetis")) + ndmetis = Executable(join_path(self.prefix.bin, "ndmetis")) + mpmetis = Executable(join_path(self.prefix.bin, "mpmetis")) + for f in ["4elt", "copter2", "mdual"]: + graph = join_path(self.stage.source_path, "graphs", "%s.graph" % f) + graphchk(graph) + gpmetis(graph, "2") + ndmetis(graph) + + graph = join_path(self.stage.source_path, "graphs", "test.mgraph") + gpmetis(graph, "2") + graph = join_path(self.stage.source_path, "graphs", "metis.mesh") + mpmetis(graph, "2") + + @run_after("install", when="+shared platform=darwin") def darwin_fix(self): # The shared library is not installed correctly on Darwin; fix this - if (sys.platform == "darwin") and ("+shared" in self.spec): - fix_darwin_install_name(prefix.lib) + fix_darwin_install_name(prefix.lib) diff --git a/var/spack/repos/builtin/packages/mmg/package.py b/var/spack/repos/builtin/packages/mmg/package.py index f0269ca4306..3cd579dff1a 100644 --- a/var/spack/repos/builtin/packages/mmg/package.py +++ b/var/spack/repos/builtin/packages/mmg/package.py @@ -5,6 +5,7 @@ import os +import spack.build_systems.cmake from spack.package import * from spack.util.executable import which @@ -43,24 +44,22 @@ class Mmg(CMakePackage): depends_on("doxygen", when="+doc") depends_on("vtk", when="+vtk") + +class CMakeBuilder(spack.build_systems.cmake.CMakeBuilder): def cmake_args(self): - args = [] - - args.append(self.define_from_variant("USE_SCOTCH", "scotch")) - args.append(self.define_from_variant("USE_VTK", "vtk")) - - if "+shared" in self.spec: - args.append("-DLIBMMG3D_SHARED=ON") - args.append("-DLIBMMG2D_SHARED=ON") - args.append("-DLIBMMGS_SHARED=ON") - args.append("-DLIBMMG_SHARED=ON") - else: - args.append("-DLIBMMG3D_STATIC=ON") - args.append("-DLIBMMG2D_STATIC=ON") - args.append("-DLIBMMGS_STATIC=ON") - args.append("-DLIBMMG_STATIC=ON") - - return args + shared_active = self.spec.satisfies("+shared") + return [ + self.define_from_variant("USE_SCOTCH", "scotch"), + self.define_from_variant("USE_VTK", "vtk"), + self.define("LIBMMG3D_SHARED", shared_active), + self.define("LIBMMG2D_SHARED", shared_active), + self.define("LIBMMGS_SHARED", shared_active), + self.define("LIBMMG_SHARED", shared_active), + self.define("LIBMMG3D_STATIC", not shared_active), + self.define("LIBMMG2D_STATIC", not shared_active), + self.define("LIBMMGS_STATIC", not shared_active), + self.define("LIBMMG_STATIC", not shared_active), + ] # parmmg requires this for its build @run_after("install") diff --git a/var/spack/repos/builtin/packages/nasm/package.py b/var/spack/repos/builtin/packages/nasm/package.py index e7d76b1d8f5..5514b26b5e6 100644 --- a/var/spack/repos/builtin/packages/nasm/package.py +++ b/var/spack/repos/builtin/packages/nasm/package.py @@ -8,7 +8,7 @@ from spack.package import * -class Nasm(Package): +class Nasm(AutotoolsPackage): """NASM (Netwide Assembler) is an 80x86 assembler designed for portability and modularity. It includes a disassembler as well.""" @@ -17,6 +17,8 @@ class Nasm(Package): list_url = "https://www.nasm.us/pub/nasm/releasebuilds" list_depth = 1 + build_system("autotools", conditional("generic", when="platform=windows"), default="autotools") + version("2.15.05", sha256="9182a118244b058651c576baa9d0366ee05983c4d4ae1d9ddd3236a9f2304997") version("2.14.02", sha256="b34bae344a3f2ed93b2ca7bf25f1ed3fb12da89eeda6096e3551fd66adeae9fc") version("2.13.03", sha256="23e1b679d64024863e2991e5c166e19309f0fe58a9765622b35bd31be5b2cc99") @@ -31,11 +33,11 @@ class Nasm(Package): when="@2.13.03 %gcc@8:", ) - patch("msvc.mak.patch", when="@2.15.05 platform=windows") + with when("platform=windows"): + depends_on("perl") + patch("msvc.mak.patch", when="@2.15.05") - conflicts("%intel@:14", when="@2.14:", msg="Intel 14 has immature C11 support") - - depends_on("perl", when="platform=windows") + conflicts("%intel@:14", when="@2.14:", msg="Intel <= 14 lacks support for C11") def patch(self): # Remove flags not recognized by the NVIDIA compiler @@ -51,13 +53,8 @@ def patch(self): "configure", ) - def install(self, spec, prefix): - with working_dir(self.stage.source_path, create=True): - configure(*["--prefix={0}".format(self.prefix)]) - make("V=1") - make("install") - @when("platform=windows") +class GenericBuilder(spack.build_systems.generic.GenericBuilder): def install(self, spec, prefix): with working_dir(self.stage.source_path, create=True): # build NASM with nmake diff --git a/var/spack/repos/builtin/packages/netlib-lapack/package.py b/var/spack/repos/builtin/packages/netlib-lapack/package.py index 4908fc1b9de..387657d1ca2 100644 --- a/var/spack/repos/builtin/packages/netlib-lapack/package.py +++ b/var/spack/repos/builtin/packages/netlib-lapack/package.py @@ -2,7 +2,7 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - +import spack.build_systems.cmake from spack.package import * @@ -55,6 +55,8 @@ class NetlibLapack(CMakePackage): # netlib-lapack is the reference implementation of LAPACK for ver in [ + "3.10.1", + "3.10.0", "3.9.1", "3.9.0", "3.8.0", @@ -182,82 +184,53 @@ def headers(self): lapacke_h = join_path(include_dir, "lapacke.h") return HeaderList([cblas_h, lapacke_h]) - @property - def build_directory(self): - return join_path( - self.stage.source_path, - "spack-build-shared" if self._building_shared else "spack-build-static", - ) +class CMakeBuilder(spack.build_systems.cmake.CMakeBuilder): def cmake_args(self): - args = ["-DBUILD_SHARED_LIBS:BOOL=" + ("ON" if self._building_shared else "OFF")] - - if self.spec.satisfies("+lapacke"): - args.extend(["-DLAPACKE:BOOL=ON", "-DLAPACKE_WITH_TMG:BOOL=ON"]) - else: - args.extend(["-DLAPACKE:BOOL=OFF", "-DLAPACKE_WITH_TMG:BOOL=OFF"]) - - if self.spec.satisfies("@3.6.0:"): - args.append("-DCBLAS=ON") # always build CBLAS + args = [ + self.define_from_variant("BUILD_SHARED_LIBS", "shared"), + self.define_from_variant("LAPACKE", "lapacke"), + self.define_from_variant("LAPACKE_WITH_TMG", "lapacke"), + self.define("CBLAS", self.spec.satisfies("@3.6.0:")), + ] if self.spec.satisfies("%intel"): # Intel compiler finds serious syntax issues when trying to # build CBLAS and LapackE - args.extend(["-DCBLAS=OFF", "-DLAPACKE:BOOL=OFF"]) + args.extend([self.define("CBLAS", False), self.define("LAPACKE", False)]) if self.spec.satisfies("%xl") or self.spec.satisfies("%xl_r"): # use F77 compiler if IBM XL args.extend( [ - "-DCMAKE_Fortran_COMPILER=" + self.compiler.f77, - "-DCMAKE_Fortran_FLAGS=" - + (" ".join(self.spec.compiler_flags["fflags"])) - + " -O3 -qnohot", + self.define("CMAKE_Fortran_COMPILER", self.compiler.f77), + self.define( + "CMAKE_Fortran_FLAGS", + " ".join(self.spec.compiler_flags["fflags"]) + " -O3 -qnohot", + ), ] ) # deprecated routines are commonly needed by, for example, suitesparse # Note that OpenBLAS spack is built with deprecated routines - args.append("-DBUILD_DEPRECATED:BOOL=ON") + args.append(self.define("BUILD_DEPRECATED", True)) if self.spec.satisfies("+external-blas"): args.extend( [ - "-DUSE_OPTIMIZED_BLAS:BOOL=ON", - "-DBLAS_LIBRARIES:PATH=" + self.spec["blas"].libs.joined(";"), + self.define("USE_OPTIMIZED_BLAS", True), + self.define("BLAS_LIBRARIES:PATH", self.spec["blas"].libs.joined(";")), ] ) if self.spec.satisfies("+xblas"): args.extend( [ - "-DXBLAS_INCLUDE_DIR=" + self.spec["netlib-xblas"].prefix.include, - "-DXBLAS_LIBRARY=" + self.spec["netlib-xblas"].libs.joined(";"), + self.define("XBLAS_INCLUDE_DIR", self.spec["netlib-xblas"].prefix.include), + self.define("XBLAS_LIBRARY", self.spec["netlib-xblas"].libs.joined(";")), ] ) - args.append("-DBUILD_TESTING:BOOL=" + ("ON" if self.run_tests else "OFF")) + args.append(self.define("BUILD_TESTING", self.pkg.run_tests)) return args - - # Build, install, and check both static and shared versions of the - # libraries when +shared - @when("+shared") - def cmake(self, spec, prefix): - for self._building_shared in (False, True): - super(NetlibLapack, self).cmake(spec, prefix) - - @when("+shared") - def build(self, spec, prefix): - for self._building_shared in (False, True): - super(NetlibLapack, self).build(spec, prefix) - - @when("+shared") - def install(self, spec, prefix): - for self._building_shared in (False, True): - super(NetlibLapack, self).install(spec, prefix) - - @when("+shared") - def check(self): - for self._building_shared in (False, True): - super(NetlibLapack, self).check() diff --git a/var/spack/repos/builtin/packages/openmpi/package.py b/var/spack/repos/builtin/packages/openmpi/package.py index e1a34ac6b3c..9405951c352 100644 --- a/var/spack/repos/builtin/packages/openmpi/package.py +++ b/var/spack/repos/builtin/packages/openmpi/package.py @@ -1053,8 +1053,7 @@ def configure_args(self): return config_args - @when("+wrapper-rpath") - @run_after("install") + @run_after("install", when="+wrapper-rpath") def filter_rpaths(self): def filter_lang_rpaths(lang_tokens, rpath_arg): if self.compiler.cc_rpath_arg == rpath_arg: @@ -1086,8 +1085,7 @@ def filter_lang_rpaths(lang_tokens, rpath_arg): filter_lang_rpaths(["c++", "CC", "cxx"], self.compiler.cxx_rpath_arg) filter_lang_rpaths(["fort", "f77", "f90"], self.compiler.fc_rpath_arg) - @when("@:3.0.4+wrapper-rpath") - @run_after("install") + @run_after("install", when="@:3.0.4+wrapper-rpath") def filter_pc_files(self): files = find(self.spec.prefix.lib.pkgconfig, "*.pc") x = FileFilter(*[f for f in files if not os.path.islink(f)]) diff --git a/var/spack/repos/builtin/packages/plasma/package.py b/var/spack/repos/builtin/packages/plasma/package.py index 5e32b5af318..f6f32d06291 100644 --- a/var/spack/repos/builtin/packages/plasma/package.py +++ b/var/spack/repos/builtin/packages/plasma/package.py @@ -2,7 +2,8 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - +import spack.build_systems.cmake +import spack.build_systems.makefile from spack.package import * @@ -38,6 +39,12 @@ class Plasma(CMakePackage): url="https://github.com/icl-utk-edu/plasma/releases/download/17.01/plasma-17.01.tar.gz", ) + build_system( + conditional("makefile", when="@:17.1"), + conditional("cmake", when="@18.9:"), + default="cmake", + ) + variant("shared", default=True, description="Build shared library (disables static library)") variant("lua", default=False, description="Build Lua support for tuning tile sizes") @@ -82,18 +89,15 @@ class Plasma(CMakePackage): def patch(self): python("tools/generate_precisions.py") - @when("@18.9.0:") + +class CMakeBuilder(spack.build_systems.cmake.CMakeBuilder): def cmake_args(self): - options = list() - - options.extend( - [ - "-DBLAS_LIBRARIES=%s" % self.spec["blas"].libs.joined(";"), - "-DLAPACK_LIBRARIES=%s" % self.spec["lapack"].libs.joined(";"), - ] - ) - - options += ["-DBUILD_SHARED_LIBS=%s" % ("ON" if ("+shared" in self.spec) else "OFF")] + options = [ + self.define("BLAS_LIBRARIES", self.spec["blas"].libs.joined(";")), + self.define("LAPACK_LIBRARIES", self.spec["lapack"].libs.joined(";")), + self.define_from_variant("BUILD_SHARED_LIBS", "shared"), + self.define_from_variant("PLASMA_DETECT_LUA", "lua"), + ] for package, provider in ( ("openblas", "openblas"), @@ -102,32 +106,13 @@ def cmake_args(self): ): if package in self.spec: for lib in ("CBLAS", "LAPACKE"): - options.append("-D%s_PROVIDER=%s" % (lib, provider)) - - if "lua" in self.spec: - options.append("-DPLASMA_DETECT_LUA=TRUE") + options.append(self.define("{}_PROVIDER".format(lib), provider)) return options - # Before 18.9.0 it was an Makefile package - @when("@:17.1") - def cmake(self, spec, prefix): - pass - # Before 18.9.0 it was an Makefile package - @when("@:17.1") - def build(self, spec, prefix): - pass - - # Before 18.9.0 it was an Makefile package - @when("@:17.1") - def install(self, spec, prefix): - self.edit(spec, prefix) - make() - make("install") - - @when("@:17.1") - def edit(self, spec, prefix): +class MakefileBuilder(spack.build_systems.makefile.MakefileBuilder): + def edit(self, pkg, spec, prefix): # copy "make.inc.mkl-gcc" provided by default into "make.inc" open("make.inc", "w").write(open("make.inc.mkl-gcc").read()) diff --git a/var/spack/repos/builtin/packages/py-dm-tree/package.py b/var/spack/repos/builtin/packages/py-dm-tree/package.py index 36dcdc910f2..1c8b7eca36d 100644 --- a/var/spack/repos/builtin/packages/py-dm-tree/package.py +++ b/var/spack/repos/builtin/packages/py-dm-tree/package.py @@ -26,20 +26,23 @@ class PyDmTree(PythonPackage): depends_on("bazel", type="build") depends_on("py-six@1.12.0:", type=("build", "run")) + # This is set later + tmp_path = None + @run_after("install") def clean(self): - remove_linked_tree(self.tmp_path) + remove_linked_tree(PyDmTree.tmp_path) def patch(self): - self.tmp_path = tempfile.mkdtemp(prefix="spack") - env["TEST_TMPDIR"] = self.tmp_path - env["HOME"] = self.tmp_path + PyDmTree.tmp_path = tempfile.mkdtemp(prefix="spack") + env["TEST_TMPDIR"] = PyDmTree.tmp_path + env["HOME"] = PyDmTree.tmp_path args = [ # Don't allow user or system .bazelrc to override build settings "'--nohome_rc',\n", "'--nosystem_rc',\n", # Bazel does not work properly on NFS, switch to /tmp - "'--output_user_root={0}',\n".format(self.tmp_path), + "'--output_user_root={0}',\n".format(PyDmTree.tmp_path), "'build',\n", # Spack logs don't handle colored output well "'--color=no',\n", diff --git a/var/spack/repos/builtin/packages/py-onnx-runtime/package.py b/var/spack/repos/builtin/packages/py-onnx-runtime/package.py index 62ea5313957..fa956086b8e 100644 --- a/var/spack/repos/builtin/packages/py-onnx-runtime/package.py +++ b/var/spack/repos/builtin/packages/py-onnx-runtime/package.py @@ -6,7 +6,7 @@ from spack.package import * -class PyOnnxRuntime(CMakePackage, PythonPackage): +class PyOnnxRuntime(CMakePackage, PythonExtension): """ONNX Runtime is a performance-focused complete scoring engine for Open Neural Network Exchange (ONNX) models, with an open extensible architecture to continually address the diff --git a/var/spack/repos/builtin/packages/py-pillow/package.py b/var/spack/repos/builtin/packages/py-pillow/package.py index 8f3488fce3e..aa98037062e 100644 --- a/var/spack/repos/builtin/packages/py-pillow/package.py +++ b/var/spack/repos/builtin/packages/py-pillow/package.py @@ -15,6 +15,18 @@ class PyPillowBase(PythonPackage): # These defaults correspond to Pillow defaults # https://pillow.readthedocs.io/en/stable/installation.html#external-libraries + VARIANTS_IN_SETUP_CFG = ( + "zlib", + "jpeg", + "tiff", + "freetype", + "lcms", + "webp", + "webpmux", + "jpeg2000", + "imagequant", + "xcb", + ) variant("zlib", default=True, description="Compressed PNG functionality") variant("jpeg", default=True, description="JPEG functionality") variant("tiff", default=False, description="Compressed TIFF functionality") @@ -79,8 +91,7 @@ def variant_to_cfg(variant): with open("setup.cfg", "a") as setup: setup.write("[build_ext]\n") - variants = list(self.spec.variants) - for variant in variants: + for variant in self.VARIANTS_IN_SETUP_CFG: setup.write(variant_to_cfg(variant)) setup.write("rpath={0}\n".format(":".join(self.rpath))) diff --git a/var/spack/repos/builtin/packages/py-pybind11/package.py b/var/spack/repos/builtin/packages/py-pybind11/package.py index b8a234c6682..d50bdeef8e2 100644 --- a/var/spack/repos/builtin/packages/py-pybind11/package.py +++ b/var/spack/repos/builtin/packages/py-pybind11/package.py @@ -2,13 +2,14 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - import os +import spack.build_systems.cmake +import spack.build_systems.python from spack.package import * -class PyPybind11(CMakePackage, PythonPackage): +class PyPybind11(CMakePackage, PythonExtension): """pybind11 -- Seamless operability between C++11 and Python. pybind11 is a lightweight header-only library that exposes C++ types in @@ -16,7 +17,8 @@ class PyPybind11(CMakePackage, PythonPackage): code. Its goals and syntax are similar to the excellent Boost.Python library by David Abrahams: to minimize boilerplate code in traditional extension modules by inferring type information using compile-time - introspection.""" + introspection. + """ homepage = "https://pybind11.readthedocs.io" url = "https://github.com/pybind/pybind11/archive/v2.6.2.tar.gz" @@ -26,6 +28,7 @@ class PyPybind11(CMakePackage, PythonPackage): version("master", branch="master") version("2.10.0", sha256="eacf582fa8f696227988d08cfc46121770823839fe9e301a20fbce67e7cd70ec") + version("2.9.2", sha256="6bd528c4dbe2276635dc787b6b1f2e5316cf6b49ee3e150264e455a0d68d19c1") version("2.9.1", sha256="c6160321dc98e6e1184cc791fbeadd2907bb4a0ce0e447f2ea4ff8ab56550913") version("2.9.0", sha256="057fb68dafd972bc13afb855f3b0d8cf0fa1a78ef053e815d9af79be7ff567cb") version("2.8.1", sha256="f1bcc07caa568eb312411dde5308b1e250bd0e1bc020fae855bf9f43209940cc") @@ -45,30 +48,25 @@ class PyPybind11(CMakePackage, PythonPackage): version("2.1.1", sha256="f2c6874f1ea5b4ad4ffffe352413f7d2cd1a49f9050940805c2a082348621540") version("2.1.0", sha256="2860f2b8d0c9f65f0698289a161385f59d099b7ead1bf64e8993c486f2b93ee0") - depends_on("ninja", type="build") depends_on("py-setuptools@42:", type="build") depends_on("py-pytest", type="test") depends_on("python@2.7:2.8,3.5:", type=("build", "run")) depends_on("python@3.6:", when="@2.10.0:", type=("build", "run")) - depends_on("cmake@3.13:", type="build") - depends_on("cmake@3.18:", type="build", when="@2.6.0:") + + depends_on("py-pip", type="build") + depends_on("py-wheel", type="build") + extends("python") + + with when("build_system=cmake"): + depends_on("ninja", type="build") + depends_on("cmake@3.13:", type="build") + depends_on("cmake@3.18:", type="build", when="@2.6.0:") # compiler support conflicts("%gcc@:4.7") conflicts("%clang@:3.2") conflicts("%intel@:16") - build_directory = "." - - def cmake_args(self): - args = [] - args.append("-DPYTHON_EXECUTABLE:FILEPATH=%s" % self.spec["python"].command.path) - args += [self.define("PYBIND11_TEST", self.run_tests)] - return args - - def setup_build_environment(self, env): - env.set("PYBIND11_USE_CMAKE", 1) - # https://github.com/pybind/pybind11/pull/1995 @when("@:2.4") def patch(self): @@ -80,13 +78,27 @@ def patch(self): string=True, ) - def install(self, spec, prefix): - CMakePackage.install(self, spec, prefix) - PythonPackage.install(self, spec, prefix) + +class CMakeBuilder(spack.build_systems.cmake.CMakeBuilder): + def cmake_args(self): + return [ + self.define("PYTHON_EXECUTABLE:FILEPATH", self.spec["python"].command.path), + self.define("PYBIND11_TEST", self.pkg.run_tests), + ] + + def install(self, pkg, spec, prefix): + super(CMakeBuilder, self).install(pkg, spec, prefix) + python_builder = spack.build_systems.python.PythonPipBuilder(pkg) + python_builder.install(pkg, spec, prefix) + + def setup_build_environment(self, env): + env.set("PYBIND11_USE_CMAKE", 1) @run_after("install") - @on_package_attributes(run_tests=True) def install_test(self): + if not self.pkg.run_tests: + return + with working_dir("spack-test", create=True): # test include helper points to right location python = self.spec["python"].command diff --git a/var/spack/repos/builtin/packages/py-pykokkos-base/package.py b/var/spack/repos/builtin/packages/py-pykokkos-base/package.py index 5d3427b4bb9..f9b02c9ae9d 100644 --- a/var/spack/repos/builtin/packages/py-pykokkos-base/package.py +++ b/var/spack/repos/builtin/packages/py-pykokkos-base/package.py @@ -8,7 +8,7 @@ from spack.package import * -class PyPykokkosBase(CMakePackage, PythonPackage): +class PyPykokkosBase(CMakePackage, PythonExtension): """Minimal set of bindings for Kokkos interoperability with Python (initialize, finalize, View, DynRankView, Kokkos-tools)""" diff --git a/var/spack/repos/builtin/packages/py-tfdlpack/package.py b/var/spack/repos/builtin/packages/py-tfdlpack/package.py index 2bc5186d92b..1304184c2e2 100644 --- a/var/spack/repos/builtin/packages/py-tfdlpack/package.py +++ b/var/spack/repos/builtin/packages/py-tfdlpack/package.py @@ -7,7 +7,7 @@ from spack.package import * -class PyTfdlpack(CMakePackage, PythonPackage): +class PyTfdlpack(CMakePackage, PythonExtension): """Tensorflow plugin for DLPack.""" homepage = "https://github.com/VoVAllen/tf-dlpack" diff --git a/var/spack/repos/builtin/packages/quantum-espresso/package.py b/var/spack/repos/builtin/packages/quantum-espresso/package.py index acc07692cf0..47fb80e6f97 100644 --- a/var/spack/repos/builtin/packages/quantum-espresso/package.py +++ b/var/spack/repos/builtin/packages/quantum-espresso/package.py @@ -2,11 +2,12 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - +import spack.build_systems.cmake +import spack.build_systems.generic from spack.package import * -class QuantumEspresso(CMakePackage): +class QuantumEspresso(CMakePackage, Package): """Quantum ESPRESSO is an integrated suite of Open-Source computer codes for electronic-structure calculations and materials modeling at the nanoscale. It is based on density-functional theory, plane waves, and @@ -19,6 +20,8 @@ class QuantumEspresso(CMakePackage): maintainers = ["ye-luo", "danielecesarini", "bellenlau"] + build_system(conditional("cmake", when="@6.8:"), "generic", default="cmake") + version("develop", branch="develop") version("7.1", sha256="d56dea096635808843bd5a9be2dee3d1f60407c01dbeeda03f8256a3bcfc4eb6") version("7.0", sha256="85beceb1aaa1678a49e774c085866d4612d9d64108e0ac49b23152c8622880ee") @@ -56,10 +59,8 @@ class QuantumEspresso(CMakePackage): destination=".", ) - variant("cmake", default=True, description="Builds via CMake") - with when("+cmake"): + with when("build_system=cmake"): depends_on("cmake@3.14.0:", type="build") - conflicts("@:6.7", msg="+cmake works since QE v6.8") variant("libxc", default=False, description="Uses libxc") depends_on("libxc@5.1.2:", when="+libxc") @@ -93,7 +94,7 @@ class QuantumEspresso(CMakePackage): msg="bugs with NVHPCSDK from v21.11 to v22.3, OpenMP and GPU", ) # only cmake is supported - conflicts("~cmake", msg="Only CMake supported for GPU-enabled version") + conflicts("build_system=generic", msg="Only CMake supported for GPU-enabled version") # NVTX variant for profiling # requires linking to CUDA runtime APIs , handled by CMake @@ -121,9 +122,10 @@ class QuantumEspresso(CMakePackage): with when("+elpa"): # CMake builds only support elpa without openmp - depends_on("elpa~openmp", when="+cmake") - depends_on("elpa+openmp", when="+openmp~cmake") - depends_on("elpa~openmp", when="~openmp~cmake") + depends_on("elpa~openmp", when="build_system=cmake") + with when("build_system=generic"): + depends_on("elpa+openmp", when="+openmp") + depends_on("elpa~openmp", when="~openmp") # Elpa is formally supported by @:5.4.0, but QE configure searches # for it in the wrong folders (or tries to download it within # the build directory). Instead of patching Elpa to provide the @@ -181,12 +183,14 @@ class QuantumEspresso(CMakePackage): with when("@7.0.1:"): # when QE doesn't use hdf5 library, the converter plugin still needs it depends_on("hdf5@1.8.16:+hl~mpi", when="hdf5=none") - conflicts("~cmake", msg="QE-to-QMCPACK wave function converter requires cmake") + conflicts( + "build_system=generic", msg="QE-to-QMCPACK wave function converter requires cmake" + ) # Enables building Electron-phonon Wannier 'epw.x' executable # http://epw.org.uk/Main/About - variant("epw", default=False, description="Builds Electron-phonon Wannier executable") - conflicts("~epw", when="+cmake", msg="epw cannot be turned off when using CMake") + variant("epw", default=True, description="Builds Electron-phonon Wannier executable") + conflicts("~epw", when="build_system=cmake", msg="epw cannot be turned off when using CMake") with when("+epw"): # The first version of Q-E to feature integrated EPW is 6.0.0, @@ -198,8 +202,10 @@ class QuantumEspresso(CMakePackage): # Constraints may be relaxed as successful reports # of different compiler+mpi combinations arrive - # TODO: enable building EPW when ~mpi and ~cmake - conflicts("~mpi", when="~cmake", msg="EPW needs MPI when ~cmake") + # TODO: enable building EPW when ~mpi and build_system=generic + conflicts( + "~mpi", when="build_system=generic", msg="EPW needs MPI when build_system=generic" + ) # EPW doesn't gets along well with OpenMPI 2.x.x conflicts("^openmpi@2.0.0:2", msg="OpenMPI version incompatible with EPW") @@ -212,19 +218,19 @@ class QuantumEspresso(CMakePackage): variant( "environ", default=False, + when="build_system=generic", description="Enables support for introducing environment effects " "into atomistic first-principles simulations." "See http://quantum-environ.org/about.html", ) - conflicts("+environ", when="+cmake", msg="environ doesn't work with CMake") variant( "gipaw", default=False, + when="build_system=generic", description="Builds Gauge-Including Projector Augmented-Waves executable", ) with when("+gipaw"): - conflicts("+cmake", msg="gipaw doesn't work with CMake") conflicts( "@:6.3", msg="gipaw standard support available for QE 6.3 or grater version only" ) @@ -370,6 +376,8 @@ class QuantumEspresso(CMakePackage): # extlibs_makefile updated to work with fujitsu compilers patch("fj-fox.patch", when="+patch %fj") + +class CMakeBuilder(spack.build_systems.cmake.CMakeBuilder): def cmake_args(self): spec = self.spec @@ -400,18 +408,9 @@ def cmake_args(self): return cmake_args - @when("~cmake") - def cmake(self, spec, prefix): - print("Bypass cmake stage when building via configure") - - @when("~cmake") - def build(self, spec, prefix): - print("Bypass build stage when building via configure") - - @when("~cmake") - def install(self, spec, prefix): - print("Override install stage when building via configure") +class GenericBuilder(spack.build_systems.generic.GenericBuilder): + def install(self, pkg, spec, prefix): prefix_path = prefix.bin if "@:5.4.0" in spec else prefix options = ["-prefix={0}".format(prefix_path)] @@ -577,7 +576,7 @@ def install(self, spec, prefix): # can't be applied to the '+qmcpack' variant if spec.variants["hdf5"].value != "none": if spec.satisfies("@6.1.0:6.4.0") or (spec.satisfies("@6.4.1") and "+qmcpack" in spec): - make_inc = join_path(self.stage.source_path, "make.inc") + make_inc = join_path(self.pkg.stage.source_path, "make.inc") zlib_libs = spec["zlib"].prefix.lib + " -lz" filter_file(zlib_libs, format(spec["zlib"].libs.ld_flags), make_inc) diff --git a/var/spack/repos/builtin/packages/racket/package.py b/var/spack/repos/builtin/packages/racket/package.py index cc9e1ba25b0..7031e234ea4 100644 --- a/var/spack/repos/builtin/packages/racket/package.py +++ b/var/spack/repos/builtin/packages/racket/package.py @@ -2,13 +2,11 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - -import sys - +import spack.build_systems.makefile from spack.package import * -class Racket(Package): +class Racket(MakefilePackage): """The Racket programming language.""" homepage = "https://www.racket-lang.org" @@ -21,13 +19,6 @@ class Racket(Package): depends_on("patchutils") depends_on("libtool", type=("build")) - phases = ["configure", "build", "install"] - - def url_for_version(self, version): - return "https://mirror.racket-lang.org/installers/{0}/racket-minimal-{0}-src-builtpkgs.tgz".format( - version - ) - variant("cs", default=True, description="Build Racket CS (new ChezScheme VM)") variant("bc", default=False, description="Build Racket BC (old MZScheme VM)") variant("shared", default=True, description="Enable shared") @@ -36,12 +27,22 @@ def url_for_version(self, version): parallel = False extendable = True + def url_for_version(self, version): + return "https://mirror.racket-lang.org/installers/{0}/racket-minimal-{0}-src-builtpkgs.tgz".format( + version + ) + + +class MakefileBuilder(spack.build_systems.makefile.MakefileBuilder): + + build_directory = "src" + def toggle(self, spec, variant): toggle_text = "enable" if spec.variants[variant].value else "disable" return "--{0}-{1}".format(toggle_text, variant) - def configure(self, spec, prefix): - with working_dir("src"): + def edit(self, pkg, spec, prefix): + with working_dir(self.build_directory): configure = Executable("./configure") configure_args = [ self.toggle(spec, "cs"), @@ -49,7 +50,7 @@ def configure(self, spec, prefix): self.toggle(spec, "jit"), ] toggle_shared = self.toggle(spec, "shared") - if sys.platform == "darwin": + if spec.satisfies("platform=darwin"): configure_args += ["--enable-macprefix"] if "+xonx" in spec: configure_args += ["--enable-xonx", toggle_shared] @@ -58,16 +59,20 @@ def configure(self, spec, prefix): configure_args += ["--prefix={0}".format(prefix)] configure(*configure_args) - def build(self, spec, prefix): - with working_dir("src"): - if spec.variants["bc"].value: - make("bc") - if spec.variants["cs"].value: - make("cs") + @property + def build_targets(self): + result = [] + if "+bc" in self.spec: + result.append("bc") + if "+cs" in self.spec: + result.append("cs") + return result - def install(self, spec, prefix): - with working_dir("src"): - if spec.variants["bc"].value: - make("install-bc") - if spec.variants["cs"].value: - make("install-cs") + @property + def install_targets(self): + result = [] + if "+bc" in self.spec: + result.append("install-bc") + if "+cs" in self.spec: + result.append("install-cs") + return result diff --git a/var/spack/repos/builtin/packages/rkt-base/package.py b/var/spack/repos/builtin/packages/rkt-base/package.py index 256f90106eb..3eb21e485d7 100644 --- a/var/spack/repos/builtin/packages/rkt-base/package.py +++ b/var/spack/repos/builtin/packages/rkt-base/package.py @@ -18,5 +18,3 @@ class RktBase(RacketPackage): depends_on("racket@8.3", type=("build", "run"), when="@8.3") racket_name = "base" - pkgs = True - subdirectory = "pkgs/{0}".format(racket_name) diff --git a/var/spack/repos/builtin/packages/rkt-cext-lib/package.py b/var/spack/repos/builtin/packages/rkt-cext-lib/package.py index 8d9b257c05d..daa1ef5226f 100644 --- a/var/spack/repos/builtin/packages/rkt-cext-lib/package.py +++ b/var/spack/repos/builtin/packages/rkt-cext-lib/package.py @@ -21,5 +21,4 @@ class RktCextLib(RacketPackage): depends_on("rkt-scheme-lib@8.3", type=("build", "run"), when="@8.3") racket_name = "cext-lib" - pkgs = True subdirectory = racket_name diff --git a/var/spack/repos/builtin/packages/rkt-compiler-lib/package.py b/var/spack/repos/builtin/packages/rkt-compiler-lib/package.py index fee9b3ea9a6..6a21c774cb2 100644 --- a/var/spack/repos/builtin/packages/rkt-compiler-lib/package.py +++ b/var/spack/repos/builtin/packages/rkt-compiler-lib/package.py @@ -21,5 +21,3 @@ class RktCompilerLib(RacketPackage): depends_on("rkt-zo-lib@1.3", type=("build", "run"), when="@8.3") racket_name = "compiler-lib" - pkgs = True - subdirectory = "pkgs/{0}".format(racket_name) diff --git a/var/spack/repos/builtin/packages/rkt-dynext-lib/package.py b/var/spack/repos/builtin/packages/rkt-dynext-lib/package.py index 81f7ca811f9..9164571ed37 100644 --- a/var/spack/repos/builtin/packages/rkt-dynext-lib/package.py +++ b/var/spack/repos/builtin/packages/rkt-dynext-lib/package.py @@ -17,5 +17,4 @@ class RktDynextLib(RacketPackage): depends_on("rkt-base@8.3", type=("build", "run"), when="@8.3") racket_name = "dynext-lib" - pkgs = True subdirectory = racket_name diff --git a/var/spack/repos/builtin/packages/rkt-rackunit-lib/package.py b/var/spack/repos/builtin/packages/rkt-rackunit-lib/package.py index 783aebe306b..33910502583 100644 --- a/var/spack/repos/builtin/packages/rkt-rackunit-lib/package.py +++ b/var/spack/repos/builtin/packages/rkt-rackunit-lib/package.py @@ -18,5 +18,4 @@ class RktRackunitLib(RacketPackage): depends_on("rkt-testing-util-lib@8.3", type=("build", "run"), when="@8.3") racket_name = "rackunit-lib" - pkgs = True subdirectory = racket_name diff --git a/var/spack/repos/builtin/packages/rkt-scheme-lib/package.py b/var/spack/repos/builtin/packages/rkt-scheme-lib/package.py index 75346eac703..689d3af7c50 100644 --- a/var/spack/repos/builtin/packages/rkt-scheme-lib/package.py +++ b/var/spack/repos/builtin/packages/rkt-scheme-lib/package.py @@ -17,4 +17,3 @@ class RktSchemeLib(RacketPackage): depends_on("rkt-base@8.3", type=("build", "run"), when="@8.3") racket_name = "scheme-lib" - pkgs = True diff --git a/var/spack/repos/builtin/packages/rkt-testing-util-lib/package.py b/var/spack/repos/builtin/packages/rkt-testing-util-lib/package.py index 9186845fc98..aa1aafda4e4 100644 --- a/var/spack/repos/builtin/packages/rkt-testing-util-lib/package.py +++ b/var/spack/repos/builtin/packages/rkt-testing-util-lib/package.py @@ -17,5 +17,4 @@ class RktTestingUtilLib(RacketPackage): depends_on("rkt-base@8.3:", type=("build", "run"), when="@8.3") racket_name = "testing-util-lib" - pkgs = True subdirectory = racket_name diff --git a/var/spack/repos/builtin/packages/rkt-zo-lib/package.py b/var/spack/repos/builtin/packages/rkt-zo-lib/package.py index 66f3d498afb..a6b70cd075a 100644 --- a/var/spack/repos/builtin/packages/rkt-zo-lib/package.py +++ b/var/spack/repos/builtin/packages/rkt-zo-lib/package.py @@ -17,5 +17,3 @@ class RktZoLib(RacketPackage): depends_on("rkt-base@8.3:", type=("build", "run"), when="@1.3") racket_name = "zo-lib" - pkgs = True - subdirectory = "pkgs/{0}".format(racket_name) diff --git a/var/spack/repos/builtin/packages/ruby/package.py b/var/spack/repos/builtin/packages/ruby/package.py index 9cc7f921514..a472509e08b 100644 --- a/var/spack/repos/builtin/packages/ruby/package.py +++ b/var/spack/repos/builtin/packages/ruby/package.py @@ -2,19 +2,17 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - import re -import sys -from typing import List +import spack.build_systems.autotools +import spack.build_systems.nmake from spack.package import * -is_windows = sys.platform == "win32" - -class Ruby(Package): +class Ruby(AutotoolsPackage, NMakePackage): """A dynamic, open source programming language with a focus on - simplicity and productivity.""" + simplicity and productivity. + """ maintainers = ["Kerilk"] @@ -33,24 +31,25 @@ class Ruby(Package): version("2.5.3", sha256="9828d03852c37c20fa333a0264f2490f07338576734d910ee3fd538c9520846c") version("2.2.0", sha256="7671e394abfb5d262fbcd3b27a71bf78737c7e9347fa21c39e58b0bb9c4840fc") - if not is_windows: - variant("openssl", default=True, description="Enable OpenSSL support") - variant("readline", default=False, description="Enable Readline support") - depends_on("pkgconfig", type=("build")) - depends_on("libffi") - depends_on("libx11", when="@:2.3") - depends_on("tcl", when="@:2.3") - depends_on("tk", when="@:2.3") - depends_on("readline", when="+readline") - depends_on("zlib") - with when("+openssl"): - depends_on("openssl@:1") - depends_on("openssl@:1.0", when="@:2.3") + build_system("autotools", "nmake", default="autotools") + + for _platform_condition in ("platform=linux", "platform=darwin", "platform=cray"): + with when(_platform_condition): + variant("openssl", default=True, description="Enable OpenSSL support") + variant("readline", default=False, description="Enable Readline support") + depends_on("pkgconfig", type="build") + depends_on("libffi") + depends_on("libx11", when="@:2.3") + depends_on("tcl", when="@:2.3") + depends_on("tk", when="@:2.3") + depends_on("readline", when="+readline") + depends_on("zlib") + with when("+openssl"): + depends_on("openssl@:1") + depends_on("openssl@:1.0", when="@:2.3") extendable = True - phases = ["configure", "build", "install"] - build_targets = [] # type: List[str] - install_targets = ["install"] + # Known build issues when Avira antivirus software is running: # https://github.com/rvm/rvm/issues/4313#issuecomment-374020379 # TODO: add check for this and warn user @@ -82,28 +81,6 @@ def url_for_version(self, version): url = "https://cache.ruby-lang.org/pub/ruby/{0}/ruby-{1}.tar.gz" return url.format(version.up_to(2), version) - def configure_args(self): - args = [] - if "+openssl" in self.spec: - args.append("--with-openssl-dir=%s" % self.spec["openssl"].prefix) - if "+readline" in self.spec: - args.append("--with-readline-dir=%s" % self.spec["readline"].prefix) - if "^tk" in self.spec: - args.append("--with-tk=%s" % self.spec["tk"].prefix) - if self.spec.satisfies("%fj"): - args.append("--disable-dtrace") - return args - - def setup_dependent_build_environment(self, env, dependent_spec): - # TODO: do this only for actual extensions. - # Set GEM_PATH to include dependent gem directories - for d in dependent_spec.traverse(deptype=("build", "run", "test"), root=True): - if d.package.extends(self.spec): - env.prepend_path("GEM_PATH", d.prefix) - - # The actual installation path for this gem - env.set("GEM_HOME", dependent_spec.prefix) - def setup_dependent_run_environment(self, env, dependent_spec): for d in dependent_spec.traverse(deptype=("run"), root=True): if d.package.extends(self.spec): @@ -122,31 +99,31 @@ def setup_dependent_package(self, module, dependent_spec): module.gem = Executable(self.prefix.bin.gem) module.rake = Executable(self.prefix.bin.rake) - def configure(self, spec, prefix): - with working_dir(self.stage.source_path, create=True): - if is_windows: - Executable("win32\\configure.bat")("--prefix=%s" % self.prefix) - else: - options = getattr(self, "configure_flag_args", []) - options += ["--prefix={0}".format(prefix)] - options += self.configure_args() - configure(*options) - def build(self, spec, prefix): - with working_dir(self.stage.source_path): - if is_windows: - nmake() - else: - params = ["V=1"] - params += self.build_targets - make(*params) +class SetupEnvironment(object): + def setup_dependent_build_environment(self, env, dependent_spec): + # TODO: do this only for actual extensions. + # Set GEM_PATH to include dependent gem directories + for d in dependent_spec.traverse(deptype=("build", "run", "test"), root=True): + if d.package.extends(self.spec): + env.prepend_path("GEM_PATH", d.prefix) - def install(self, spec, prefix): - with working_dir(self.stage.source_path): - if is_windows: - nmake("install") - else: - make(*self.install_targets) + # The actual installation path for this gem + env.set("GEM_HOME", dependent_spec.prefix) + + +class AutotoolsBuilder(spack.build_systems.autotools.AutotoolsBuilder, SetupEnvironment): + def configure_args(self): + args = [] + if "+openssl" in self.spec: + args.append("--with-openssl-dir=%s" % self.spec["openssl"].prefix) + if "+readline" in self.spec: + args.append("--with-readline-dir=%s" % self.spec["readline"].prefix) + if "^tk" in self.spec: + args.append("--with-tk=%s" % self.spec["tk"].prefix) + if self.spec.satisfies("%fj"): + args.append("--disable-dtrace") + return args @run_after("install") def post_install(self): @@ -158,7 +135,7 @@ def post_install(self): """ if self.spec.satisfies("+openssl"): rubygems_updated_cert_path = join_path( - self.stage.source_path, "rubygems-updated-ssl-cert", "GlobalSignRootCA.pem" + self.pkg.stage.source_path, "rubygems-updated-ssl-cert", "GlobalSignRootCA.pem" ) rubygems_certs_path = join_path( self.spec.prefix.lib, @@ -171,11 +148,19 @@ def post_install(self): rbconfig = find(self.prefix, "rbconfig.rb")[0] filter_file( - r'^(\s*CONFIG\["CXX"\]\s*=\s*).*', r'\1"{0}"'.format(self.compiler.cxx), rbconfig + r'^(\s*CONFIG\["CXX"\]\s*=\s*).*', r'\1"{0}"'.format(self.pkg.compiler.cxx), rbconfig ) filter_file( - r'^(\s*CONFIG\["CC"\]\s*=\s*).*', r'\1"{0}"'.format(self.compiler.cc), rbconfig + r'^(\s*CONFIG\["CC"\]\s*=\s*).*', r'\1"{0}"'.format(self.pkg.compiler.cc), rbconfig ) filter_file( - r'^(\s*CONFIG\["MJIT_CC"\]\s*=\s*).*', r'\1"{0}"'.format(self.compiler.cc), rbconfig + r'^(\s*CONFIG\["MJIT_CC"\]\s*=\s*).*', + r'\1"{0}"'.format(self.pkg.compiler.cc), + rbconfig, ) + + +class NMakeBuilder(spack.build_systems.nmake.NMakeBuilder, SetupEnvironment): + def edit(self, pkg, spec, prefix): + with working_dir(self.pkg.stage.source_path, create=True): + Executable("win32\\configure.bat")("--prefix=%s" % self.prefix) diff --git a/var/spack/repos/builtin/packages/scotch/package.py b/var/spack/repos/builtin/packages/scotch/package.py index 166455876e3..b957db31bf9 100644 --- a/var/spack/repos/builtin/packages/scotch/package.py +++ b/var/spack/repos/builtin/packages/scotch/package.py @@ -3,12 +3,15 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import spack.build_systems.cmake +import spack.build_systems.makefile from spack.package import * -class Scotch(CMakePackage): +class Scotch(CMakePackage, MakefilePackage): """Scotch is a software package for graph and mesh/hypergraph - partitioning, graph clustering, and sparse matrix ordering.""" + partitioning, graph clustering, and sparse matrix ordering. + """ homepage = "https://gitlab.inria.fr/scotch/scotch" git = "https://gitlab.inria.fr/scotch/scotch.git" @@ -32,13 +35,10 @@ class Scotch(CMakePackage): version("6.0.0", sha256="8206127d038bda868dda5c5a7f60ef8224f2e368298fbb01bf13fa250e378dd4") version("5.1.10b", sha256="54c9e7fafefd49d8b2017d179d4f11a655abe10365961583baaddc4eeb6a9add") - variant("mpi", default=True, description="Activate the compilation of parallel libraries") - variant( - "compression", default=True, description="Activate the posibility to use compressed files" - ) - variant( - "esmumps", default=False, description="Activate the compilation of esmumps needed by mumps" - ) + build_system(conditional("cmake", when="@7:"), "makefile", default="cmake") + variant("mpi", default=True, description="Compile parallel libraries") + variant("compression", default=True, description="May use compressed files") + variant("esmumps", default=False, description="Compile esmumps (needed by mumps)") variant("shared", default=True, description="Build a shared version of the library") variant( "metis", default=False, description="Expose vendored METIS/ParMETIS libraries and wrappers" @@ -70,8 +70,6 @@ class Scotch(CMakePackage): conflicts("^metis", when="+metis") conflicts("^parmetis", when="+metis") - # NOTE: In cross-compiling environment parallel build - # produces weird linker errors. parallel = False # NOTE: Versions of Scotch up to version 6.0.0 don't include support for @@ -107,16 +105,30 @@ def libs(self): return scotchlibs + zlibs - @when("@:6") - def patch(self): - self.configure() - # NOTE: Configuration of Scotch is achieved by writing a 'Makefile.inc' - # file that contains all of the configuration variables and their desired - # values for the installation. This function writes this file based on - # the given installation variants. - @when("@:6") - def configure(self): +class CMakeBuilder(spack.build_systems.cmake.CMakeBuilder): + def cmake_args(self): + spec = self.spec + args = [ + self.define_from_variant("BUILD_LIBSCOTCHMETIS", "metis"), + self.define_from_variant("INSTALL_METIS_HEADERS", "metis"), + self.define_from_variant("BUILD_LIBESMUMPS", "esmumps"), + self.define_from_variant("BUILD_SHARED_LIBS", "shared"), + self.define_from_variant("BUILD_PTSCOTCH", "mpi"), + ] + + # TODO should we enable/disable THREADS? + + if "+int64" in spec: + args.append("-DINTSIZE=64") + + return args + + +class MakefileBuilder(spack.build_systems.makefile.MakefileBuilder): + build_directory = "src" + + def edit(self, pkg, spec, prefix): makefile_inc = [] cflags = [ "-O3", @@ -147,7 +159,7 @@ def configure(self): makefile_inc.extend( [ "LIB = .dylib", - "CLIBFLAGS = -dynamiclib {0}".format(self.compiler.cc_pic_flag), + "CLIBFLAGS = -dynamiclib {0}".format(pkg.compiler.cc_pic_flag), "RANLIB = echo", "AR = $(CC)", ( @@ -162,13 +174,13 @@ def configure(self): makefile_inc.extend( [ "LIB = .so", - "CLIBFLAGS = -shared {0}".format(self.compiler.cc_pic_flag), + "CLIBFLAGS = -shared {0}".format(pkg.compiler.cc_pic_flag), "RANLIB = echo", "AR = $(CC)", "ARFLAGS = -shared $(LDFLAGS) -o", ] ) - cflags.append(self.compiler.cc_pic_flag) + cflags.append(pkg.compiler.cc_pic_flag) else: makefile_inc.extend( [ @@ -182,9 +194,9 @@ def configure(self): # Compiler-Specific Options # - if self.compiler.name == "gcc": + if pkg.compiler.name == "gcc": cflags.append("-Drestrict=__restrict") - elif self.compiler.name == "intel": + elif pkg.compiler.name == "intel": cflags.append("-Drestrict=") mpicc_path = self.spec["mpi"].mpicc if "+mpi" in self.spec else "mpicc" @@ -237,8 +249,8 @@ def configure(self): with open("Makefile.inc", "w") as fh: fh.write("\n".join(makefile_inc)) - @when("@:6") - def install(self, spec, prefix): + @property + def build_targets(self): targets = ["scotch"] if "+mpi" in self.spec: targets.append("ptscotch") @@ -248,65 +260,4 @@ def install(self, spec, prefix): targets.append("esmumps") if "+mpi" in self.spec: targets.append("ptesmumps") - - with working_dir("src"): - for target in targets: - # It seems that building ptesmumps in parallel fails, for - # version prior to 6.0.0 there is no separated targets force - # ptesmumps, this library is built by the ptscotch target. This - # should explain the test for the can_make_parallel variable - can_make_parallel = not ( - target == "ptesmumps" - or (self.spec.version < Version("6.0.0") and target == "ptscotch") - ) - make(target, parallel=can_make_parallel) - - lib_ext = dso_suffix if "+shared" in self.spec else "a" - # It seems easier to remove metis wrappers from the folder that will be - # installed than to tweak the Makefiles - if "+metis" not in self.spec: - with working_dir("lib"): - force_remove("libscotchmetis.{0}".format(lib_ext)) - force_remove("libptscotchparmetis.{0}".format(lib_ext)) - - with working_dir("include"): - force_remove("metis.h") - force_remove("parmetis.h") - - if "~esmumps" in self.spec and self.spec.version < Version("6.0.0"): - with working_dir("lib"): - force_remove("libesmumps.{0}".format(lib_ext)) - force_remove("libptesmumps.{0}".format(lib_ext)) - - with working_dir("include"): - force_remove("esmumps.h") - - install_tree("bin", prefix.bin) - install_tree("lib", prefix.lib) - install_tree("include", prefix.include) - install_tree("man/man1", prefix.share.man.man1) - - @when("@:6") - def cmake(self, spec, prefix): - self.configure() - - @when("@:6") - def build(self, spec, prefix): - pass - - def cmake_args(self): - spec = self.spec - args = [ - self.define_from_variant("BUILD_LIBSCOTCHMETIS", "metis"), - self.define_from_variant("INSTALL_METIS_HEADERS", "metis"), - self.define_from_variant("BUILD_LIBESMUMPS", "esmumps"), - self.define_from_variant("BUILD_SHARED_LIBS", "shared"), - self.define_from_variant("BUILD_PTSCOTCH", "mpi"), - ] - - # TODO should we enable/disable THREADS? - - if "+int64" in spec: - args.append("-DINTSIZE=64") - - return args + return targets diff --git a/var/spack/repos/builtin/packages/superlu/package.py b/var/spack/repos/builtin/packages/superlu/package.py index 8f20f90ea45..e8bd7c38f6e 100644 --- a/var/spack/repos/builtin/packages/superlu/package.py +++ b/var/spack/repos/builtin/packages/superlu/package.py @@ -2,15 +2,16 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - import os from llnl.util import tty +import spack.build_systems.cmake +import spack.build_systems.generic from spack.package import * -class Superlu(CMakePackage): +class Superlu(CMakePackage, Package): """SuperLU is a general purpose library for the direct solution of large, sparse, nonsymmetric systems of linear equations on high performance machines. SuperLU is designed for sequential machines.""" @@ -36,9 +37,12 @@ class Superlu(CMakePackage): url="https://crd-legacy.lbl.gov/~xiaoye/SuperLU/superlu_4.2.tar.gz", ) + build_system( + conditional("cmake", when="@5:"), conditional("autotools", when="@:4"), default="cmake" + ) + variant("pic", default=True, description="Build with position independent code") - depends_on("cmake", when="@5:", type="build") depends_on("blas") conflicts( "@:5.2.1", @@ -48,76 +52,7 @@ class Superlu(CMakePackage): test_requires_compiler = True - # CMake installation method - def cmake_args(self): - if self.version > Version("5.2.1"): - _blaslib_key = "enable_internal_blaslib" - else: - _blaslib_key = "enable_blaslib" - args = [ - self.define(_blaslib_key, False), - self.define("CMAKE_INSTALL_LIBDIR", self.prefix.lib), - self.define_from_variant("CMAKE_POSITION_INDEPENDENT_CODE", "pic"), - self.define("enable_tests", self.run_tests), - ] - - return args - # Pre-cmake installation method - @when("@:4") - def cmake(self, spec, prefix): - """Use autotools before version 5""" - config = [] - - # Define make.inc file - config.extend( - [ - "PLAT = _x86_64", - "SuperLUroot = %s" % self.stage.source_path, - # 'SUPERLULIB = $(SuperLUroot)/lib/libsuperlu$(PLAT).a', - "SUPERLULIB = $(SuperLUroot)/lib/libsuperlu_{0}.a".format(self.spec.version), - "BLASDEF = -DUSE_VENDOR_BLAS", - "BLASLIB = {0}".format(spec["blas"].libs.ld_flags), - # or BLASLIB = -L/usr/lib64 -lblas - "TMGLIB = libtmglib.a", - "LIBS = $(SUPERLULIB) $(BLASLIB)", - "ARCH = ar", - "ARCHFLAGS = cr", - "RANLIB = {0}".format("ranlib" if which("ranlib") else "echo"), - "CC = {0}".format(env["CC"]), - "FORTRAN = {0}".format(env["FC"]), - "LOADER = {0}".format(env["CC"]), - "CDEFS = -DAdd_", - ] - ) - - if "+pic" in spec: - config.extend( - [ - # Use these lines instead when pic_flag capability arrives - "CFLAGS = -O3 {0}".format(self.compiler.cc_pic_flag), - "NOOPTS = {0}".format(self.compiler.cc_pic_flag), - "FFLAGS = -O2 {0}".format(self.compiler.f77_pic_flag), - "LOADOPTS = {0}".format(self.compiler.cc_pic_flag), - ] - ) - else: - config.extend( - ["CFLAGS = -O3", "NOOPTS = ", "FFLAGS = -O2", "LOADOPTS = "] - ) - - # Write configuration options to make.inc file - with open("make.inc", "w") as inc: - for option in config: - inc.write("{0}\n".format(option)) - - make(parallel=False) - - # Install manually - install_tree("lib", prefix.lib) - mkdir(prefix.include) - install(join_path("SRC", "*.h"), prefix.include) - examples_src_dir = "EXAMPLE" make_hdr_file = "make.inc" @@ -221,3 +156,67 @@ def test(self): return self.run_superlu_test(test_dir, exe, args) + + +class CMakeBuilder(spack.build_systems.cmake.CMakeBuilder): + def cmake_args(self): + if self.pkg.version > Version("5.2.1"): + _blaslib_key = "enable_internal_blaslib" + else: + _blaslib_key = "enable_blaslib" + args = [ + self.define(_blaslib_key, False), + self.define("CMAKE_INSTALL_LIBDIR", self.prefix.lib), + self.define_from_variant("CMAKE_POSITION_INDEPENDENT_CODE", "pic"), + self.define("enable_tests", self.pkg.run_tests), + ] + return args + + +class GenericBuilder(spack.build_systems.generic.GenericBuilder): + def install(self, pkg, spec, prefix): + """Use autotools before version 5""" + # Define make.inc file + config = [ + "PLAT = _x86_64", + "SuperLUroot = %s" % self.pkg.stage.source_path, + # 'SUPERLULIB = $(SuperLUroot)/lib/libsuperlu$(PLAT).a', + "SUPERLULIB = $(SuperLUroot)/lib/libsuperlu_{0}.a".format(self.pkg.spec.version), + "BLASDEF = -DUSE_VENDOR_BLAS", + "BLASLIB = {0}".format(spec["blas"].libs.ld_flags), + # or BLASLIB = -L/usr/lib64 -lblas + "TMGLIB = libtmglib.a", + "LIBS = $(SUPERLULIB) $(BLASLIB)", + "ARCH = ar", + "ARCHFLAGS = cr", + "RANLIB = {0}".format("ranlib" if which("ranlib") else "echo"), + "CC = {0}".format(env["CC"]), + "FORTRAN = {0}".format(env["FC"]), + "LOADER = {0}".format(env["CC"]), + "CDEFS = -DAdd_", + ] + + if "+pic" in spec: + config.extend( + [ + # Use these lines instead when pic_flag capability arrives + "CFLAGS = -O3 {0}".format(self.pkg.compiler.cc_pic_flag), + "NOOPTS = {0}".format(self.pkg.compiler.cc_pic_flag), + "FFLAGS = -O2 {0}".format(self.pkg.compiler.f77_pic_flag), + "LOADOPTS = {0}".format(self.pkg.compiler.cc_pic_flag), + ] + ) + else: + config.extend( + ["CFLAGS = -O3", "NOOPTS = ", "FFLAGS = -O2", "LOADOPTS = "] + ) + + with open("make.inc", "w") as inc: + for option in config: + inc.write("{0}\n".format(option)) + + make(parallel=False) + + install_tree("lib", prefix.lib) + mkdir(prefix.include) + install(join_path("SRC", "*.h"), prefix.include) diff --git a/var/spack/repos/builtin/packages/swig/package.py b/var/spack/repos/builtin/packages/swig/package.py index d1a760ffec6..2bb9853526e 100644 --- a/var/spack/repos/builtin/packages/swig/package.py +++ b/var/spack/repos/builtin/packages/swig/package.py @@ -2,10 +2,10 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - import os import re +import spack.build_systems.autotools from spack.package import * @@ -57,10 +57,10 @@ class Swig(AutotoolsPackage, SourceforgePackage): depends_on("pcre") - _autoconf_versions = ["@master", "@fortran", "@4.0.2-fortran", "@4.1.dev1-fortran"] + AUTOCONF_VERSIONS = ["@master", "@fortran", "@4.0.2-fortran", "@4.1.dev1-fortran"] # Git releases do *not* include configure script - for _version in _autoconf_versions: + for _version in AUTOCONF_VERSIONS: depends_on("autoconf", type="build", when=_version) depends_on("automake", type="build", when=_version) depends_on("libtool", type="build", when=_version) @@ -70,8 +70,6 @@ class Swig(AutotoolsPackage, SourceforgePackage): depends_on("automake@1.15:", type="build", when="target={0}:".format(_target)) depends_on("pkgconfig", type="build") - build_directory = "spack-build" - conflicts("%nvhpc", when="@:4.0.2") @classmethod @@ -80,18 +78,6 @@ def determine_version(cls, exe): match = re.search(r"SWIG\s+Version\s+(\S+)", output) return match.group(1) if match else None - @run_after("install") - def create_symlink(self): - # CMake compatibility: see https://github.com/spack/spack/pull/6240 - with working_dir(self.prefix.bin): - os.symlink("swig", "swig{0}".format(self.spec.version.up_to(2))) - - for _version in _autoconf_versions: - - @when(_version) - def autoreconf(self, spec, prefix): - which("sh")("./autogen.sh") - @property def _installed_exe(self): return join_path(self.prefix, "bin", "swig") @@ -134,3 +120,19 @@ def _test_swiglib(self): def test(self): self._test_version() self._test_swiglib() + + +class AutotoolsBuilder(spack.build_systems.autotools.AutotoolsBuilder): + build_directory = "spack-build" + + @run_after("install") + def create_symlink(self): + # CMake compatibility: see https://github.com/spack/spack/pull/6240 + with working_dir(self.prefix.bin): + os.symlink("swig", "swig{0}".format(self.spec.version.up_to(2))) + + for _version in Swig.AUTOCONF_VERSIONS: + + @when(_version) + def autoreconf(self, pkg, spec, prefix): + which("sh")("./autogen.sh") diff --git a/var/spack/repos/builtin/packages/sz/package.py b/var/spack/repos/builtin/packages/sz/package.py index e16657a6b67..d83e0a52d50 100644 --- a/var/spack/repos/builtin/packages/sz/package.py +++ b/var/spack/repos/builtin/packages/sz/package.py @@ -2,11 +2,12 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - +import spack.build_systems.autotools +import spack.build_systems.cmake from spack.package import * -class Sz(CMakePackage): +class Sz(CMakePackage, AutotoolsPackage): """Error-bounded Lossy Compressor for HPC Data""" homepage = "https://szcompressor.org" @@ -43,6 +44,12 @@ class Sz(CMakePackage): version("1.4.10.0", sha256="cf23cf1ffd7c69c3d3128ae9c356b6acdc03a38f92c02db5d9bfc04f3fabc506") version("1.4.9.2", sha256="9dc785274d068d04c2836955fc93518a9797bfd409b46fea5733294b7c7c18f8") + build_system( + conditional("autotools", when="@:2.1.8.0"), + conditional("cmake", when="@2.1.8.1:"), + default="cmake", + ) + variant("python", default=False, description="builds the python wrapper") variant("netcdf", default=False, description="build the netcdf reader") variant("hdf5", default=False, description="build the hdf5 filter") @@ -71,86 +78,6 @@ class Sz(CMakePackage): patch("ctags-only-if-requested.patch", when="@2.1.8.1:2.1.8.3") - @property - def build_directory(self): - """autotools needs a different build directory to work""" - if self.version >= Version("2.1.8.1"): - return "spack-build" - else: - return "." - - @when("@:2.1.8.0") - def cmake(self, spec, prefix): - """use autotools before 2.1.8.1""" - configure_args = ["--prefix=" + prefix] - if "+fortran" in spec: - configure_args.append("--enable-fortran") - else: - configure_args.append("--disable-fortran") - configure(*configure_args) - # at least the v2.0.2.0 tarball contains object files - # which need to be cleaned out - make("clean") - - def cmake_args(self): - """configure the package with CMake for version 2.1.8.1 and later""" - args = [] - - if "+python" in self.spec: - args.append("-DBUILD_PYTHON_WRAPPER=ON") - args.append("-DSZ_PYTHON_SITELIB={0}".format(python_platlib)) - else: - args.append("-DBUILD_PYTHON_WRAPPER=OFF") - - if "+netcdf" in self.spec: - args.append("-DBUILD_NETCDF_READER=ON") - else: - args.append("-DBUILD_NETCDF_READER=OFF") - - if "+hdf5" in self.spec: - args.append("-DBUILD_HDF5_FILTER=ON") - else: - args.append("-DBUILD_HDF5_FILTER=OFF") - - if "+pastri" in self.spec: - args.append("-DBUILD_PASTRI=ON") - else: - args.append("-DBUILD_PASTRI=OFF") - - if "+time_compression" in self.spec: - args.append("-DBUILD_TIMECMPR=ON") - else: - args.append("-DBUILD_TIMECMPR=OFF") - - if "+random_access" in self.spec: - args.append("-DBUILD_RANDOMACCESS=ON") - else: - args.append("-DBUILD_RANDOMACCESS=OFF") - - if "+fortran" in self.spec: - args.append("-DBUILD_FORTRAN=ON") - else: - args.append("-DBUILD_FORTRAN=OFF") - - if "+shared" in self.spec: - args.append("-DBUILD_SHARED_LIBS=ON") - else: - args.append("-DBUILD_SHARED_LIBS=OFF") - - if "+stats" in self.spec: - args.append("-DBUILD_STATS=ON") - else: - args.append("-DBUILD_STATS=OFF") - - args.append(self.define("BUILD_TESTS", self.run_tests)) - - return args - - @run_after("build") - @on_package_attributes(run_tests=True) - def test_build(self): - make("test") - def _test_2d_float(self): """This test performs simple 2D compression/decompression (float)""" test_data_dir = self.test_suite.current_test_data_dir @@ -232,3 +159,37 @@ def test(self): self._test_2d_float() # run 3D compression and decompression (float) self._test_3d_float() + + +class AutotoolsBuilder(spack.build_systems.autotools.AutotoolsBuilder): + build_directory = "." + + def configure_args(self): + return self.enable_or_disable("fortran") + + @run_before("build") + def make_clean(self): + # at least the v2.0.2.0 tarball contains object files + # which need to be cleaned out + make("clean") + + +class CMakeBuilder(spack.build_systems.cmake.CMakeBuilder): + def cmake_args(self): + result = [ + self.define_from_variant("BUILD_NETCDF_READER", "netcdf"), + self.define_from_variant("BUILD_HDF5_FILTER", "hdf5"), + self.define_from_variant("BUILD_PASTRI", "pastri"), + self.define_from_variant("BUILD_TIMECPR", "time_compression"), + self.define_from_variant("BUILD_RANDOMACCESS", "random_access"), + self.define_from_variant("BUILD_FORTRAN", "fortran"), + self.define_from_variant("BUILD_SHARED_LIBS", "shared"), + self.define_from_variant("BUILD_STATS", "stats"), + self.define("BUILD_TESTS", self.pkg.run_tests), + self.define_from_variant("BUILD_PYTHON_WRAPPER", "python"), + ] + + if "+python" in self.spec: + result.append(self.define("SZ_PYTHON_SITELIB", python_platlib)) + + return result diff --git a/var/spack/repos/builtin/packages/timemory/package.py b/var/spack/repos/builtin/packages/timemory/package.py index 759a7437d18..f30e5787796 100644 --- a/var/spack/repos/builtin/packages/timemory/package.py +++ b/var/spack/repos/builtin/packages/timemory/package.py @@ -8,7 +8,7 @@ from spack.package import * -class Timemory(CMakePackage, PythonPackage): +class Timemory(CMakePackage, PythonExtension): """Modular profiling toolkit and suite of libraries and tools for C/C++/Fortran/CUDA/Python""" diff --git a/var/spack/repos/builtin/packages/uncrustify/package.py b/var/spack/repos/builtin/packages/uncrustify/package.py index a9148c01e5a..b528302ff61 100644 --- a/var/spack/repos/builtin/packages/uncrustify/package.py +++ b/var/spack/repos/builtin/packages/uncrustify/package.py @@ -6,7 +6,7 @@ from spack.package import * -class Uncrustify(Package): +class Uncrustify(CMakePackage, AutotoolsPackage): """Source Code Beautifier for C, C++, C#, ObjectiveC, Java, and others.""" homepage = "http://uncrustify.sourceforge.net/" @@ -31,28 +31,15 @@ class Uncrustify(Package): version("0.62", commit="5987f2") version("0.61", sha256="1df0e5a2716e256f0a4993db12f23d10195b3030326fdf2e07f8e6421e172df9") - depends_on("cmake", type="build", when="@0.64:") - depends_on("automake", type="build", when="@0.63") - depends_on("autoconf", type="build", when="@0.63") + build_system( + conditional("cmake", when="@0.64:"), + conditional("autotools", when="@:0.63"), + default="cmake", + ) - @when("@0.64:") - def install(self, spec, prefix): - with working_dir("spack-build", create=True): - cmake("..", *std_cmake_args) - make() - make("install") - - @when("@0.63") - def install(self, spec, prefix): - which("bash")("autogen.sh") - configure("--prefix={0}".format(self.prefix)) - make() - make("install") - - @when("@:0.62") - def install(self, spec, prefix): - configure("--prefix={0}".format(self.prefix)) - make() - make("install") + with when("build_system=autotools"): + depends_on("automake", type="build") + depends_on("autoconf", type="build") + depends_on("libtool", type="build", when="@0.63") patch("uncrustify-includes.patch", when="@0.73") diff --git a/var/spack/repos/builtin/packages/zlib/package.py b/var/spack/repos/builtin/packages/zlib/package.py index 76add72552c..58db86f6b2a 100644 --- a/var/spack/repos/builtin/packages/zlib/package.py +++ b/var/spack/repos/builtin/packages/zlib/package.py @@ -9,10 +9,12 @@ import glob import os +import spack.build_systems.generic +import spack.build_systems.makefile from spack.package import * -class Zlib(Package): +class Zlib(MakefilePackage, Package): """A free, general-purpose, legally unencumbered lossless data-compression library. """ @@ -43,10 +45,14 @@ class Zlib(Package): deprecated=True, ) + build_system("makefile", conditional("generic", when="platform=windows"), default="makefile") + variant("pic", default=True, description="Produce position-independent code (for shared libs)") variant("shared", default=True, description="Enables the build of shared libraries.") variant("optimize", default=True, description="Enable -O2 for a more optimized lib") + conflicts("build_system=makefile", when="platform=windows") + patch("w_patch.patch", when="@1.2.11%cce") patch("configure-cc.patch", when="@1.2.12") @@ -55,11 +61,31 @@ def libs(self): shared = "+shared" in self.spec return find_libraries(["libz"], root=self.prefix, recursive=True, shared=shared) - def win_install(self): - build_dir = self.stage.source_path - install_tree = {} - install_tree["bin"] = glob.glob(os.path.join(build_dir, "*.dll")) - install_tree["lib"] = glob.glob(os.path.join(build_dir, "*.lib")) + +class SetupEnvironment(object): + def setup_build_environment(self, env): + if "+pic" in self.spec: + env.append_flags("CFLAGS", self.pkg.compiler.cc_pic_flag) + if "+optimize" in self.spec: + env.append_flags("CFLAGS", "-O2") + + +class MakefileBuilder(spack.build_systems.makefile.MakefileBuilder, SetupEnvironment): + def edit(self, pkg, spec, prefix): + config_args = [] + if "~shared" in self.spec: + config_args.append("--static") + configure("--prefix={0}".format(prefix), *config_args) + + +class GenericBuilder(spack.build_systems.generic.GenericBuilder, SetupEnvironment): + def install(self, spec, prefix): + nmake("-f" "win32\\Makefile.msc") + build_dir = self.pkg.stage.source_path + install_tree = { + "bin": glob.glob(os.path.join(build_dir, "*.dll")), + "lib": glob.glob(os.path.join(build_dir, "*.lib")), + } compose_src_path = lambda x: os.path.join(build_dir, x) install_tree["include"] = [compose_src_path("zlib.h"), compose_src_path("zconf.h")] # Windows path seps are fine here as this method is Windows specific. @@ -76,24 +102,3 @@ def installtree(dst, tree): install(file, install_dst) installtree(self.prefix, install_tree) - - def setup_build_environment(self, env): - if "+pic" in self.spec: - env.append_flags("CFLAGS", self.compiler.cc_pic_flag) - if "+optimize" in self.spec: - env.append_flags("CFLAGS", "-O2") - - def install(self, spec, prefix): - if "platform=windows" in self.spec: - nmake("-f" "win32\\Makefile.msc") - self.win_install() - else: - config_args = [] - if "~shared" in spec: - config_args.append("--static") - configure("--prefix={0}".format(prefix), *config_args) - - make() - if self.run_tests: - make("check") - make("install") From 34f9394732ff7e168c78c8574de3111f83c875e2 Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Wed, 26 Oct 2022 20:31:16 +0200 Subject: [PATCH 204/442] gitlab ci: show build machine info (#33523) --- .../gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml | 3 +++ share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml | 3 +++ .../gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml | 3 +++ share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml | 3 +++ .../gitlab/cloud_pipelines/stacks/build_systems/spack.yaml | 3 +++ .../gitlab/cloud_pipelines/stacks/data-vis-sdk/spack.yaml | 3 +++ share/spack/gitlab/cloud_pipelines/stacks/e4s-mac/spack.yaml | 1 + .../gitlab/cloud_pipelines/stacks/e4s-on-power/spack.yaml | 3 +++ .../spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml | 3 +++ share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml | 3 +++ share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml | 3 +++ share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml | 3 +++ share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml | 3 +++ .../cloud_pipelines/stacks/radiuss-aws-aarch64/spack.yaml | 3 +++ .../spack/gitlab/cloud_pipelines/stacks/radiuss-aws/spack.yaml | 3 +++ share/spack/gitlab/cloud_pipelines/stacks/radiuss/spack.yaml | 3 +++ share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml | 3 +++ 17 files changed, 49 insertions(+) diff --git a/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml index 5ede7b882cd..ebc0ac79bd2 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml @@ -243,11 +243,14 @@ spack: gitlab-ci: script: + - uname -a + - grep -E 'vendor|model name' /proc/cpuinfo | sort -u - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.aarch64-linux-gnu.tar.gz -o gmake.tar.gz - printf 'deb1dcae0eecdc7fce2902f294012ab5519629e6827204f1b9964dcfd3f74627 gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version + - spack arch - cd ${SPACK_CONCRETE_ENV_DIR} - spack env activate --without-view . - spack config add "config:install_tree:projections:${SPACK_JOB_SPEC_PKG_NAME}:'morepadding/{architecture}/{compiler.name}-{compiler.version}/{name}-{version}-{hash}'" diff --git a/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml index 564884a5f8b..2f0e8e8f3c5 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml @@ -240,11 +240,14 @@ spack: gitlab-ci: script: + - uname -a + - grep -E 'vendor|model name' /proc/cpuinfo | sort -u - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version + - spack arch - cd ${SPACK_CONCRETE_ENV_DIR} - spack env activate --without-view . - spack config add "config:install_tree:projections:${SPACK_JOB_SPEC_PKG_NAME}:'morepadding/{architecture}/{compiler.name}-{compiler.version}/{name}-{version}-{hash}'" diff --git a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml index 262de722a5a..c94ec57956a 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml @@ -150,11 +150,14 @@ spack: gitlab-ci: script: + - uname -a + - grep -E 'vendor|model name' /proc/cpuinfo | sort -u - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.aarch64-linux-gnu.tar.gz -o gmake.tar.gz - printf 'deb1dcae0eecdc7fce2902f294012ab5519629e6827204f1b9964dcfd3f74627 gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version + - spack arch - cd ${SPACK_CONCRETE_ENV_DIR} - spack env activate --without-view . - spack config add "config:install_tree:projections:${SPACK_JOB_SPEC_PKG_NAME}:'morepadding/{architecture}/{compiler.name}-{compiler.version}/{name}-{version}-{hash}'" diff --git a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml index c71b514c6e4..5267b2a3106 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml @@ -161,11 +161,14 @@ spack: gitlab-ci: script: + - uname -a + - grep -E 'vendor|model name' /proc/cpuinfo | sort -u - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version + - spack arch - cd ${SPACK_CONCRETE_ENV_DIR} - spack env activate --without-view . - spack config add "config:install_tree:projections:${SPACK_JOB_SPEC_PKG_NAME}:'morepadding/{architecture}/{compiler.name}-{compiler.version}/{name}-{version}-{hash}'" diff --git a/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml index b3b4e8697c6..7b6e11041f9 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml @@ -34,11 +34,14 @@ spack: gitlab-ci: script: + - uname -a + - grep -E 'vendor|model name' /proc/cpuinfo | sort -u - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version + - spack arch - cd ${SPACK_CONCRETE_ENV_DIR} - spack env activate --without-view . - spack config add "config:install_tree:projections:${SPACK_JOB_SPEC_PKG_NAME}:'morepadding/{architecture}/{compiler.name}-{compiler.version}/{name}-{version}-{hash}'" diff --git a/share/spack/gitlab/cloud_pipelines/stacks/data-vis-sdk/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/data-vis-sdk/spack.yaml index c46848b0eb0..fe967b25a1b 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/data-vis-sdk/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/data-vis-sdk/spack.yaml @@ -47,11 +47,14 @@ spack: gitlab-ci: image: { "name": "ghcr.io/spack/e4s-ubuntu-18.04:v2021-10-18", "entrypoint": [""] } script: + - uname -a + - grep -E 'vendor|model name' /proc/cpuinfo | sort -u - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version + - spack arch - cd ${SPACK_CONCRETE_ENV_DIR} - spack env activate --without-view . - spack config add "config:install_tree:projections:${SPACK_JOB_SPEC_PKG_NAME}:'morepadding/{architecture}/{compiler.name}-{compiler.version}/{name}-{version}-{hash}'" diff --git a/share/spack/gitlab/cloud_pipelines/stacks/e4s-mac/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/e4s-mac/spack.yaml index fcad22dbf88..539dcd5d592 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/e4s-mac/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/e4s-mac/spack.yaml @@ -45,6 +45,7 @@ spack: - tmp="$(mktemp -d)"; export SPACK_USER_CONFIG_PATH="$tmp"; export SPACK_USER_CACHE_PATH="$tmp" - . "./share/spack/setup-env.sh" - spack --version + - spack arch - cd ${SPACK_CONCRETE_ENV_DIR} - spack env activate --without-view . - spack config add "config:install_tree:projections:${SPACK_JOB_SPEC_PKG_NAME}:'morepadding/{architecture}/{compiler.name}-{compiler.version}/{name}-{version}-{hash}'" diff --git a/share/spack/gitlab/cloud_pipelines/stacks/e4s-on-power/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/e4s-on-power/spack.yaml index d7c8305c51d..359a1f72b84 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/e4s-on-power/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/e4s-on-power/spack.yaml @@ -214,9 +214,12 @@ spack: gitlab-ci: script: + - uname -a + - grep -E 'vendor|model name' /proc/cpuinfo | sort -u - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.powerpc64le-linux-gnu.tar.gz | tar -xzf - -C /usr 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version + - spack arch - cd ${SPACK_CONCRETE_ENV_DIR} - spack env activate --without-view . - spack config add "config:install_tree:projections:${SPACK_JOB_SPEC_PKG_NAME}:'morepadding/{architecture}/{compiler.name}-{compiler.version}/{name}-{version}-{hash}'" diff --git a/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml index fc8009e4d93..5cccd72830b 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml @@ -266,11 +266,14 @@ spack: gitlab-ci: script: + - uname -a + - grep -E 'vendor|model name' /proc/cpuinfo | sort -u - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version + - spack arch - cd ${SPACK_CONCRETE_ENV_DIR} - spack env activate --without-view . - spack config add "config:install_tree:projections:${SPACK_JOB_SPEC_PKG_NAME}:'morepadding/{architecture}/{compiler.name}-{compiler.version}/{name}-{version}-{hash}'" diff --git a/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml index 4d7b8757726..aa7f084e7d2 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml @@ -255,11 +255,14 @@ spack: gitlab-ci: script: + - uname -a + - grep -E 'vendor|model name' /proc/cpuinfo | sort -u - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version + - spack arch - cd ${SPACK_CONCRETE_ENV_DIR} - spack env activate --without-view . - spack config add "config:install_tree:projections:${SPACK_JOB_SPEC_PKG_NAME}:'morepadding/{architecture}/{compiler.name}-{compiler.version}/{name}-{version}-{hash}'" diff --git a/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml index 527b3250d37..061df799037 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml @@ -87,11 +87,14 @@ spack: gitlab-ci: script: + - uname -a + - grep -E 'vendor|model name' /proc/cpuinfo | sort -u - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version + - spack arch - cd ${SPACK_CONCRETE_ENV_DIR} - spack env activate --without-view . - spack config add "config:install_tree:projections:${SPACK_JOB_SPEC_PKG_NAME}:'morepadding/{architecture}/{compiler.name}-{compiler.version}/{name}-{version}-{hash}'" diff --git a/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml index 64ac6fc4335..5ef7a62b22e 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml @@ -90,11 +90,14 @@ spack: gitlab-ci: script: + - uname -a + - grep -E 'vendor|model name' /proc/cpuinfo | sort -u - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version + - spack arch - cd ${SPACK_CONCRETE_ENV_DIR} - spack env activate --without-view . - spack config add "config:install_tree:projections:${SPACK_JOB_SPEC_PKG_NAME}:'morepadding/{architecture}/{compiler.name}-{compiler.version}/{name}-{version}-{hash}'" diff --git a/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml index ad777941778..f78a5edbce0 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml @@ -93,11 +93,14 @@ spack: gitlab-ci: script: + - uname -a + - grep -E 'vendor|model name' /proc/cpuinfo | sort -u - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version + - spack arch - cd ${SPACK_CONCRETE_ENV_DIR} - spack env activate --without-view . - spack config add "config:install_tree:projections:${SPACK_JOB_SPEC_PKG_NAME}:'morepadding/{architecture}/{compiler.name}-{compiler.version}/{name}-{version}-{hash}'" diff --git a/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws-aarch64/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws-aarch64/spack.yaml index ed48b8d9bb3..960a8b14881 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws-aarch64/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws-aarch64/spack.yaml @@ -56,11 +56,14 @@ spack: gitlab-ci: script: + - uname -a + - grep -E 'vendor|model name' /proc/cpuinfo | sort -u - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.aarch64-linux-gnu.tar.gz -o gmake.tar.gz - printf 'deb1dcae0eecdc7fce2902f294012ab5519629e6827204f1b9964dcfd3f74627 gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version + - spack arch - cd ${SPACK_CONCRETE_ENV_DIR} - spack env activate --without-view . - spack config add "config:install_tree:projections:${SPACK_JOB_SPEC_PKG_NAME}:'morepadding/{architecture}/{compiler.name}-{compiler.version}/{name}-{version}-{hash}'" diff --git a/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws/spack.yaml index ba7cbd3d354..0405848cb27 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws/spack.yaml @@ -61,11 +61,14 @@ spack: gitlab-ci: script: + - uname -a + - grep -E 'vendor|model name' /proc/cpuinfo | sort -u - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version + - spack arch - cd ${SPACK_CONCRETE_ENV_DIR} - spack env activate --without-view . - spack config add "config:install_tree:projections:${SPACK_JOB_SPEC_PKG_NAME}:'morepadding/{architecture}/{compiler.name}-{compiler.version}/{name}-{version}-{hash}'" diff --git a/share/spack/gitlab/cloud_pipelines/stacks/radiuss/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/radiuss/spack.yaml index 8a03de20be2..dd667e73cd6 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/radiuss/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/radiuss/spack.yaml @@ -64,11 +64,14 @@ spack: gitlab-ci: image: { "name": "ghcr.io/spack/e4s-ubuntu-18.04:v2021-10-18", "entrypoint": [""] } script: + - uname -a + - grep -E 'vendor|model name' /proc/cpuinfo | sort -u - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version + - spack arch - cd ${SPACK_CONCRETE_ENV_DIR} - spack env activate --without-view . - spack config add "config:install_tree:projections:${SPACK_JOB_SPEC_PKG_NAME}:'morepadding/{architecture}/{compiler.name}-{compiler.version}/{name}-{version}-{hash}'" diff --git a/share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml index 0090fd2f832..128d6102196 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml @@ -65,11 +65,14 @@ spack: gitlab-ci: script: + - uname -a + - grep -E 'vendor|model name' /proc/cpuinfo | sort -u - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version + - spack arch - spack compiler find - cd ${SPACK_CONCRETE_ENV_DIR} - spack env activate --without-view . From bfc23f456046cc0bc870069b9d208587077f1e58 Mon Sep 17 00:00:00 2001 From: Miroslav Stoyanov <30537612+mkstoyanov@users.noreply.github.com> Date: Wed, 26 Oct 2022 15:38:20 -0400 Subject: [PATCH 205/442] new version (#33537) --- var/spack/repos/builtin/packages/tasmanian/package.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/tasmanian/package.py b/var/spack/repos/builtin/packages/tasmanian/package.py index a37ff06a658..e86252e1035 100644 --- a/var/spack/repos/builtin/packages/tasmanian/package.py +++ b/var/spack/repos/builtin/packages/tasmanian/package.py @@ -15,7 +15,7 @@ class Tasmanian(CMakePackage, CudaPackage, ROCmPackage): ApproximatioN is a robust library for high dimensional integration and interpolation as well as parameter calibration.""" - homepage = "http://tasmanian.ornl.gov" + homepage = "https://ornl.github.io/TASMANIAN/stable/" url = "https://github.com/ORNL/TASMANIAN/archive/v7.5.tar.gz" git = "https://github.com/ORNL/TASMANIAN.git" @@ -24,6 +24,7 @@ class Tasmanian(CMakePackage, CudaPackage, ROCmPackage): version("develop", branch="master") + version("7.9", sha256="decba62e6bbccf1bc26c6e773a8d4fd51d7f3e3e534ddd386ec41300694ce5cc") version("7.7", sha256="85fb3a7b302ea21a3b700712767a59a623d9ab93da03308fa47d4413654c3878") version("7.5", sha256="d621bd36dced4db86ef638693ba89b336762e7a3d7fedb3b5bcefb03390712b3") version("7.3", sha256="5bd1dd89cc5c84506f6900b6569b17e50becd73eb31ec85cfa11d6f1f912c4fa") From 5d0ae001a1184a7cf4cea3e2043b39fcc278dae6 Mon Sep 17 00:00:00 2001 From: Satish Balay Date: Wed, 26 Oct 2022 15:04:22 -0500 Subject: [PATCH 206/442] slepc: fix for slepc+cuda ^petsc+kokkos+cuda ^kokkos+cuda+wrapper (#33529) kokkos wrappers modify mpicxx - breaking slepc build. --- var/spack/repos/builtin/packages/slepc/package.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/slepc/package.py b/var/spack/repos/builtin/packages/slepc/package.py index 3fc5a5c170c..bd8fa1e4ed9 100644 --- a/var/spack/repos/builtin/packages/slepc/package.py +++ b/var/spack/repos/builtin/packages/slepc/package.py @@ -113,12 +113,20 @@ class Slepc(Package, CudaPackage, ROCmPackage): when="@3.13.0:+blopex", ) + def revert_kokkos_nvcc_wrapper(self): + # revert changes by kokkos-nvcc-wrapper + if self.spec.satisfies("^kokkos+cuda+wrapper"): + env["MPICH_CXX"] = env["CXX"] + env["OMPI_CXX"] = env["CXX"] + env["MPICXX_CXX"] = env["CXX"] + def install(self, spec, prefix): # set SLEPC_DIR for installation # Note that one should set the current (temporary) directory instead # its symlink in spack/stage/ ! os.environ["SLEPC_DIR"] = os.getcwd() + self.revert_kokkos_nvcc_wrapper() if self.spec.satisfies("%cce"): filter_file( " flags = l", @@ -158,7 +166,7 @@ def install(self, spec, prefix): python("configure", "--prefix=%s" % prefix, *options) - make("MAKE_NP=%s" % make_jobs, parallel=False) + make("V=1 MAKE_NP=%s" % make_jobs, parallel=False) if self.run_tests: make("test", parallel=False) From 4ff8a6a9b703002db9f1c5a949a4b00c4978363d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BE=E5=9C=B0=20=E5=B8=8C=E7=95=99=E8=80=B6?= <65301509+KiruyaMomochi@users.noreply.github.com> Date: Thu, 27 Oct 2022 04:45:35 +0800 Subject: [PATCH 207/442] Windows: fix bootstrap and package install failure (#32942) * Add patches for building clingo with MSVC * Help python find clingo DLL * If an executable is located in "C:\Program Files", Executable was running into issues with the extra space. This quotes the exe to ensure that it is treated as a single value. Signed-off-by: Kiruya Momochi <65301509+KiruyaMomochi@users.noreply.github.com> --- lib/spack/spack/bootstrap.py | 8 +++++++ lib/spack/spack/util/executable.py | 3 ++- .../repos/builtin/packages/clingo/package.py | 2 ++ .../builtin/packages/clingo/size-t.patch | 22 +++++++++++++++++++ .../builtin/packages/clingo/vs2022.patch | 18 +++++++++++++++ 5 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 var/spack/repos/builtin/packages/clingo/size-t.patch create mode 100644 var/spack/repos/builtin/packages/clingo/vs2022.patch diff --git a/lib/spack/spack/bootstrap.py b/lib/spack/spack/bootstrap.py index 2e0f2614e77..d92609fdcdf 100644 --- a/lib/spack/spack/bootstrap.py +++ b/lib/spack/spack/bootstrap.py @@ -91,6 +91,14 @@ def _try_import_from_store(module, query_spec, query_info=None): os.path.join(candidate_spec.prefix, pkg.platlib), ] # type: list[str] path_before = list(sys.path) + + # Python 3.8+ on Windows does not search dependent DLLs in PATH, + # so we need to manually add it using os.add_dll_directory + # https://docs.python.org/3/whatsnew/3.8.html#bpo-36085-whatsnew + if sys.version_info[:2] >= (3, 8) and sys.platform == "win32": + if os.path.isdir(candidate_spec.prefix.bin): + os.add_dll_directory(candidate_spec.prefix.bin) # novermin + # NOTE: try module_paths first and last, last allows an existing version in path # to be picked up and used, possibly depending on something in the store, first # allows the bootstrap version to work when an incompatible version is in diff --git a/lib/spack/spack/util/executable.py b/lib/spack/spack/util/executable.py index cd8ddef6de6..6160b952662 100644 --- a/lib/spack/spack/util/executable.py +++ b/lib/spack/spack/util/executable.py @@ -10,6 +10,7 @@ import sys from six import string_types, text_type +from six.moves import shlex_quote import llnl.util.tty as tty @@ -333,7 +334,7 @@ def which(*args, **kwargs): Executable: The first executable that is found in the path """ exe = which_string(*args, **kwargs) - return Executable(exe) if exe else None + return Executable(shlex_quote(exe)) if exe else None class ProcessError(spack.error.SpackError): diff --git a/var/spack/repos/builtin/packages/clingo/package.py b/var/spack/repos/builtin/packages/clingo/package.py index be477fdf5b7..a3d39d8e629 100644 --- a/var/spack/repos/builtin/packages/clingo/package.py +++ b/var/spack/repos/builtin/packages/clingo/package.py @@ -64,6 +64,8 @@ class Clingo(CMakePackage): depends_on("py-cffi", type=("build", "run"), when="@5.5.0: platform=cray") patch("python38.patch", when="@5.3:5.4.0") + patch("size-t.patch", when="%msvc") + patch("vs2022.patch", when="%msvc@19.30:") def patch(self): # Doxygen is optional but can't be disabled with a -D, so patch diff --git a/var/spack/repos/builtin/packages/clingo/size-t.patch b/var/spack/repos/builtin/packages/clingo/size-t.patch new file mode 100644 index 00000000000..52f7db20624 --- /dev/null +++ b/var/spack/repos/builtin/packages/clingo/size-t.patch @@ -0,0 +1,22 @@ +diff --git a/libpyclingo/pyclingo.cc b/libpyclingo/pyclingo.cc +index ec4a33c..88b6669 100644 +--- a/libpyclingo/pyclingo.cc ++++ b/libpyclingo/pyclingo.cc +@@ -116,7 +116,7 @@ struct ObjectProtocoll { + Object call(char const *name, Args &&... args); + template + Object operator()(Args &&... args); +- ssize_t size(); ++ Py_ssize_t size(); + bool empty() { return size() == 0; } + Object getItem(Reference o); + Object getItem(char const *key); +@@ -232,7 +232,7 @@ Object ObjectProtocoll::operator()(Args &&... args) { + return PyObject_CallFunctionObjArgs(toPy_(), Reference(args).toPy()..., nullptr); + } + template +-ssize_t ObjectProtocoll::size() { ++Py_ssize_t ObjectProtocoll::size() { + auto ret = PyObject_Size(toPy_()); + if (PyErr_Occurred()) { throw PyException(); } + return ret; diff --git a/var/spack/repos/builtin/packages/clingo/vs2022.patch b/var/spack/repos/builtin/packages/clingo/vs2022.patch new file mode 100644 index 00000000000..8a27fc8679d --- /dev/null +++ b/var/spack/repos/builtin/packages/clingo/vs2022.patch @@ -0,0 +1,18 @@ +diff --git a/libpyclingo/pyclingo.cc b/libpyclingo/pyclingo.cc +index 88b6669..58e73bd 100644 +--- a/libpyclingo/pyclingo.cc ++++ b/libpyclingo/pyclingo.cc +@@ -25,6 +25,13 @@ + // NOTE: the python header has a linker pragma to link with python_d.lib + // when _DEBUG is set which is not part of official python releases + #if defined(_MSC_VER) && defined(_DEBUG) && !defined(CLINGO_UNDEF__DEBUG) ++// Workaround for a VS 2022 issue. ++// NOTE: This workaround knowingly violates the Python.h include order requirement: ++// https://docs.python.org/3/c-api/intro.html#include-files ++# include ++# if _MSVC_STL_VERSION >= 143 ++# include ++# endif + #undef _DEBUG + #include + #define _DEBUG From 8b202769f4b35d8aebbdc69d055177ff664c4a9c Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Wed, 26 Oct 2022 20:45:55 +0000 Subject: [PATCH 208/442] libcatalyst: add 2.0.0-rc3 release (#33322) --- var/spack/repos/builtin/packages/libcatalyst/package.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/var/spack/repos/builtin/packages/libcatalyst/package.py b/var/spack/repos/builtin/packages/libcatalyst/package.py index 5bf1fe4f8fa..07f0bf4f1c1 100644 --- a/var/spack/repos/builtin/packages/libcatalyst/package.py +++ b/var/spack/repos/builtin/packages/libcatalyst/package.py @@ -12,9 +12,12 @@ class Libcatalyst(CMakePackage): homepage = "https://gitlab.kitware.com/paraview/catalyst" git = "https://gitlab.kitware.com/paraview/catalyst.git" + url = "https://gitlab.kitware.com/api/v4/projects/paraview%2Fcatalyst/packages/generic/catalyst/v2.0.0/catalyst-v2.0.0.tar.gz" maintainers = ["mathstuf"] + version("2.0.0-rc3", sha256="8862bd0a4d0be2176b4272f9affda1ea4e5092087acbb99a2fe2621c33834e05") + # master as of 2021-05-12 version("2021-05-12", commit="8456ccd6015142b5a7705f79471361d4f5644fa7") From 6594f4975845238edcb99463d150ce00935a0dc3 Mon Sep 17 00:00:00 2001 From: iarspider Date: Thu, 27 Oct 2022 01:41:40 +0200 Subject: [PATCH 209/442] CLHEP: Add checksum for clhep 2.4.5.4, 2.4.6.0; cleanup recipe (#33521) * CLHEP: patching of CMake policy not needed for new-ish versions * Add checksum for clhep 2.4.5.4, 2.4.6.0; cleanup recipe --- var/spack/repos/builtin/packages/clhep/package.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/var/spack/repos/builtin/packages/clhep/package.py b/var/spack/repos/builtin/packages/clhep/package.py index 80765d00f1a..1d4f5bd9195 100644 --- a/var/spack/repos/builtin/packages/clhep/package.py +++ b/var/spack/repos/builtin/packages/clhep/package.py @@ -19,6 +19,8 @@ class Clhep(CMakePackage): maintainers = ["drbenmorgan"] + version("2.4.6.0", sha256="e8d16debb84ced28e40e9ae84789cf5a0adad45f9213fbac3ce7583e06caa7b1") + version("2.4.5.4", sha256="983fb4ea1fe423217fe9debc709569495a62a3b4540eb790d557c5a34dffbbb6") version("2.4.5.3", sha256="45f63eeb097f02fe67b86a7dadbf10d409b401c28a1a3e172db36252c3097c13") version("2.4.5.1", sha256="2517c9b344ad9f55974786ae6e7a0ef8b22f4abcbf506df91194ea2299ce3813") version("2.4.4.0", sha256="5df78c11733a091da9ae5a24ce31161d44034dd45f20455587db85f1ca1ba539") @@ -65,6 +67,11 @@ class Clhep(CMakePackage): patch("clhep-cms.patch", when="+cms", level=0) def patch(self): + # Patched line removed since 2.3.2.2 + # https://gitlab.cern.ch/CLHEP/CLHEP/-/commit/5da6830d69c71dc178632f7f5121a3a00e379f94 + if self.spec.satisfies("@2.3.2.2:"): + return + filter_file( "SET CMP0042 OLD", "SET CMP0042 NEW", From 8fc3e49e00b0b3ecfeddce5a986edd77c5571642 Mon Sep 17 00:00:00 2001 From: Wouter Deconinck Date: Wed, 26 Oct 2022 18:41:56 -0500 Subject: [PATCH 210/442] opencascade: new version 7.6.3 (#33518) * opencascade: new version 7.6.3 * opencascade: correct hash for 7.6.3 Co-authored-by: Tamara Dahlgren <35777542+tldahlgren@users.noreply.github.com> --- var/spack/repos/builtin/packages/opencascade/package.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/var/spack/repos/builtin/packages/opencascade/package.py b/var/spack/repos/builtin/packages/opencascade/package.py index c378ffe9b14..635e6b2d040 100644 --- a/var/spack/repos/builtin/packages/opencascade/package.py +++ b/var/spack/repos/builtin/packages/opencascade/package.py @@ -18,6 +18,11 @@ class Opencascade(CMakePackage): maintainers = ["wdconinc"] + version( + "7.6.3", + extension="tar.gz", + sha256="baae5b3a7a38825396fc45ef9d170db406339f5eeec62e21b21036afeda31200", + ) version( "7.6.0", extension="tar.gz", From 9d7c688d3c83dd6d20d2366d82e8a466c576d99a Mon Sep 17 00:00:00 2001 From: iarspider Date: Thu, 27 Oct 2022 02:04:29 +0200 Subject: [PATCH 211/442] cppunit: add static/shared variant, add version 1.15_20220904 (#33522) --- ...unit-1.14-defaulted-function-deleted.patch | 13 ++++++++++ .../repos/builtin/packages/cppunit/package.py | 26 ++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 var/spack/repos/builtin/packages/cppunit/cppunit-1.14-defaulted-function-deleted.patch diff --git a/var/spack/repos/builtin/packages/cppunit/cppunit-1.14-defaulted-function-deleted.patch b/var/spack/repos/builtin/packages/cppunit/cppunit-1.14-defaulted-function-deleted.patch new file mode 100644 index 00000000000..59c2d5d114b --- /dev/null +++ b/var/spack/repos/builtin/packages/cppunit/cppunit-1.14-defaulted-function-deleted.patch @@ -0,0 +1,13 @@ +diff --git a/include/cppunit/extensions/TestSuiteBuilderContext.h b/include/cppunit/extensions/TestSuiteBuilderContext.h +index 12d157e..ad1a34f 100644 +--- a/include/cppunit/extensions/TestSuiteBuilderContext.h ++++ b/include/cppunit/extensions/TestSuiteBuilderContext.h +@@ -42,8 +42,6 @@ public: + + TestSuiteBuilderContextBase(TestSuiteBuilderContextBase const &) = default; + TestSuiteBuilderContextBase(TestSuiteBuilderContextBase &&) = default; +- TestSuiteBuilderContextBase & operator =(TestSuiteBuilderContextBase const &) = default; +- TestSuiteBuilderContextBase & operator =(TestSuiteBuilderContextBase &&) = default; + + /*! \brief Adds a test to the fixture suite. + * diff --git a/var/spack/repos/builtin/packages/cppunit/package.py b/var/spack/repos/builtin/packages/cppunit/package.py index be3515ab31e..2db7440cb0a 100644 --- a/var/spack/repos/builtin/packages/cppunit/package.py +++ b/var/spack/repos/builtin/packages/cppunit/package.py @@ -11,10 +11,20 @@ class Cppunit(AutotoolsPackage): homepage = "https://wiki.freedesktop.org/www/Software/cppunit/" url = "https://dev-www.libreoffice.org/src/cppunit-1.13.2.tar.gz" + git = "https://anongit.freedesktop.org/git/libreoffice/cppunit.git" - version("1.14.0", sha256="3d569869d27b48860210c758c4f313082103a5e58219a7669b52bfd29d674780") + version("master", branch="master") + version("1.15_20220904", commit="78e64f0edb4f3271a6ddbcdf9cba05138597bfca") + version( + "1.14.0", + sha256="3d569869d27b48860210c758c4f313082103a5e58219a7669b52bfd29d674780", + preferred=True, + ) version("1.13.2", sha256="3f47d246e3346f2ba4d7c9e882db3ad9ebd3fcbd2e8b732f946e0e3eeb9f429f") + # https://github.com/cms-sw/cmsdist/blob/IB/CMSSW_12_6_X/master/cppunit-1.14-defaulted-function-deleted.patch + patch("cppunit-1.14-defaulted-function-deleted.patch", when="@1.15:") + variant( "cxxstd", default="default", @@ -23,6 +33,18 @@ class Cppunit(AutotoolsPackage): description="Use the specified C++ standard when building.", ) + variant( + "libs", + default="shared,static", + values=("shared", "static"), + multi=True, + description="Build shared libs, static libs or both", + ) + + depends_on("autoconf", type="build", when="@1.15_20220904") + depends_on("automake", type="build", when="@1.15_20220904") + depends_on("libtool", type="build", when="@1.15_20220904") + def setup_build_environment(self, env): cxxstd = self.spec.variants["cxxstd"].value cxxstdflag = ( @@ -32,4 +54,6 @@ def setup_build_environment(self, env): def configure_args(self): args = ["--disable-doxygen"] + args += self.enable_or_disable("libs") + return args From f89be5d7e40a25429356aad4ec8a15ebb181606a Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Thu, 27 Oct 2022 07:40:10 +0200 Subject: [PATCH 212/442] Fix bootstrapping from sources in CI (#33538) Since #32262 we are not testing bootstrapping from sources, since we didn't update the mirrors in tests --- .github/workflows/bootstrap.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/bootstrap.yml b/.github/workflows/bootstrap.yml index dcd6761f689..09c356a3e0c 100644 --- a/.github/workflows/bootstrap.yml +++ b/.github/workflows/bootstrap.yml @@ -42,7 +42,7 @@ jobs: shell: runuser -u spack-test -- bash {0} run: | source share/spack/setup-env.sh - spack bootstrap untrust github-actions-v0.2 + spack bootstrap untrust github-actions-v0.3 spack external find cmake bison spack -d solve zlib tree ~/.spack/bootstrap/store/ @@ -79,7 +79,7 @@ jobs: shell: runuser -u spack-test -- bash {0} run: | source share/spack/setup-env.sh - spack bootstrap untrust github-actions-v0.2 + spack bootstrap untrust github-actions-v0.3 spack external find cmake bison spack -d solve zlib tree ~/.spack/bootstrap/store/ @@ -143,7 +143,7 @@ jobs: - name: Bootstrap clingo run: | source share/spack/setup-env.sh - spack bootstrap untrust github-actions-v0.2 + spack bootstrap untrust github-actions-v0.3 spack external find cmake bison spack -d solve zlib tree ~/.spack/bootstrap/store/ @@ -160,7 +160,7 @@ jobs: run: | source share/spack/setup-env.sh export PATH=/usr/local/opt/bison@2.7/bin:$PATH - spack bootstrap untrust github-actions-v0.2 + spack bootstrap untrust github-actions-v0.3 spack external find --not-buildable cmake bison spack -d solve zlib tree ~/.spack/bootstrap/store/ @@ -298,7 +298,7 @@ jobs: run: | source share/spack/setup-env.sh spack solve zlib - spack bootstrap untrust github-actions-v0.2 + spack bootstrap untrust github-actions-v0.3 spack -d gpg list tree ~/.spack/bootstrap/store/ @@ -333,7 +333,7 @@ jobs: run: | source share/spack/setup-env.sh spack solve zlib - spack bootstrap untrust github-actions-v0.2 + spack bootstrap untrust github-actions-v0.3 spack -d gpg list tree ~/.spack/bootstrap/store/ From a82a9cf3c1adf6dfb60bc78367b2ea1281562247 Mon Sep 17 00:00:00 2001 From: Marco De La Pierre Date: Thu, 27 Oct 2022 17:10:22 +0800 Subject: [PATCH 213/442] tower-agent and tower-cli: update versions (#33545) --- .../builtin/packages/tower-agent/package.py | 7 ++++++ .../builtin/packages/tower-cli/package.py | 25 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/var/spack/repos/builtin/packages/tower-agent/package.py b/var/spack/repos/builtin/packages/tower-agent/package.py index d5cd01507ca..e4ec5103ccc 100644 --- a/var/spack/repos/builtin/packages/tower-agent/package.py +++ b/var/spack/repos/builtin/packages/tower-agent/package.py @@ -15,9 +15,16 @@ class TowerAgent(Package): """ homepage = "https://github.com/seqeralabs/tower-agent" + maintainers = ["marcodelapierre"] if platform.machine() == "x86_64": if platform.system() == "Linux": + version( + "0.4.5", + sha256="d3f38931ff769299b9f9f7e78d9f6a55f93914878c09117b8eaf5decd0c734ec", + url="https://github.com/seqeralabs/tower-agent/releases/download/v0.4.5/tw-agent-linux-x86_64", + expand=False, + ) version( "0.4.3", sha256="1125e64d4e3342e77fcf7f6827f045e421084654fe8faafd5389e356e0613cc0", diff --git a/var/spack/repos/builtin/packages/tower-cli/package.py b/var/spack/repos/builtin/packages/tower-cli/package.py index a10c0b6d2db..ed878fe7b42 100644 --- a/var/spack/repos/builtin/packages/tower-cli/package.py +++ b/var/spack/repos/builtin/packages/tower-cli/package.py @@ -15,9 +15,22 @@ class TowerCli(Package): """ homepage = "https://github.com/seqeralabs/tower-cli" + maintainers = ["marcodelapierre"] if platform.machine() == "x86_64": if platform.system() == "Darwin": + version( + "0.7.0", + sha256="b1b3ade4231de2c7303832bac406510c9de171d07d6384a54945903f5123f772", + url="https://github.com/seqeralabs/tower-cli/releases/download/v0.7.0/tw-0.7.0-osx-x86_64", + expand=False, + ) + version( + "0.6.5", + sha256="8e7369611f3617bad3e76264d93fe467c6039c86af9f18e26142dee5df1e7346", + url="https://github.com/seqeralabs/tower-cli/releases/download/v0.6.5/tw-0.6.5-osx-x86_64", + expand=False, + ) version( "0.6.2", sha256="2bcc17687d58d4c888e8d57b7f2f769a2940afb3266dc3c6c48b0af0cb490d91", @@ -25,6 +38,18 @@ class TowerCli(Package): expand=False, ) elif platform.system() == "Linux": + version( + "0.7.0", + sha256="651f564b80585c9060639f1a8fc82966f81becb0ab3e3ba34e53baf3baabff39", + url="https://github.com/seqeralabs/tower-cli/releases/download/v0.7.0/tw-0.7.0-linux-x86_64", + expand=False, + ) + version( + "0.6.5", + sha256="0d1f3a6f53694000c1764bd3b40ce141f4b8923d477e2bdfdce75c66de95be00", + url="https://github.com/seqeralabs/tower-cli/releases/download/v0.6.5/tw-0.6.5-linux-x86_64", + expand=False, + ) version( "0.6.2", sha256="02c6d141416b046b6e8b6f9723331fe0e39d37faa3561c47c152df4d33b37e50", From df1d23357337f0dc1aeac815c956fb69db86c5cd Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Thu, 27 Oct 2022 11:14:09 +0200 Subject: [PATCH 214/442] Don't fail over cpuinfo (#33546) --- .../gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml | 4 ++-- share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml | 4 ++-- .../gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml | 4 ++-- share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml | 4 ++-- .../gitlab/cloud_pipelines/stacks/build_systems/spack.yaml | 4 ++-- .../gitlab/cloud_pipelines/stacks/data-vis-sdk/spack.yaml | 4 ++-- .../gitlab/cloud_pipelines/stacks/e4s-on-power/spack.yaml | 4 ++-- .../spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml | 4 ++-- share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml | 4 ++-- share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml | 4 ++-- share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml | 4 ++-- share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml | 4 ++-- .../cloud_pipelines/stacks/radiuss-aws-aarch64/spack.yaml | 4 ++-- .../gitlab/cloud_pipelines/stacks/radiuss-aws/spack.yaml | 4 ++-- share/spack/gitlab/cloud_pipelines/stacks/radiuss/spack.yaml | 4 ++-- share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml | 4 ++-- 16 files changed, 32 insertions(+), 32 deletions(-) diff --git a/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml index ebc0ac79bd2..c48a20e9050 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml @@ -243,8 +243,8 @@ spack: gitlab-ci: script: - - uname -a - - grep -E 'vendor|model name' /proc/cpuinfo | sort -u + - uname -a || true + - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.aarch64-linux-gnu.tar.gz -o gmake.tar.gz - printf 'deb1dcae0eecdc7fce2902f294012ab5519629e6827204f1b9964dcfd3f74627 gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null diff --git a/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml index 2f0e8e8f3c5..60f980ddad5 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml @@ -240,8 +240,8 @@ spack: gitlab-ci: script: - - uname -a - - grep -E 'vendor|model name' /proc/cpuinfo | sort -u + - uname -a || true + - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null diff --git a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml index c94ec57956a..41c6f5bdda0 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml @@ -150,8 +150,8 @@ spack: gitlab-ci: script: - - uname -a - - grep -E 'vendor|model name' /proc/cpuinfo | sort -u + - uname -a || true + - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.aarch64-linux-gnu.tar.gz -o gmake.tar.gz - printf 'deb1dcae0eecdc7fce2902f294012ab5519629e6827204f1b9964dcfd3f74627 gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null diff --git a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml index 5267b2a3106..75d6efe8aae 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml @@ -161,8 +161,8 @@ spack: gitlab-ci: script: - - uname -a - - grep -E 'vendor|model name' /proc/cpuinfo | sort -u + - uname -a || true + - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null diff --git a/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml index 7b6e11041f9..b7e048181d6 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml @@ -34,8 +34,8 @@ spack: gitlab-ci: script: - - uname -a - - grep -E 'vendor|model name' /proc/cpuinfo | sort -u + - uname -a || true + - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null diff --git a/share/spack/gitlab/cloud_pipelines/stacks/data-vis-sdk/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/data-vis-sdk/spack.yaml index fe967b25a1b..0a6e18c84b4 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/data-vis-sdk/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/data-vis-sdk/spack.yaml @@ -47,8 +47,8 @@ spack: gitlab-ci: image: { "name": "ghcr.io/spack/e4s-ubuntu-18.04:v2021-10-18", "entrypoint": [""] } script: - - uname -a - - grep -E 'vendor|model name' /proc/cpuinfo | sort -u + - uname -a || true + - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null diff --git a/share/spack/gitlab/cloud_pipelines/stacks/e4s-on-power/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/e4s-on-power/spack.yaml index 359a1f72b84..508de2b0522 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/e4s-on-power/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/e4s-on-power/spack.yaml @@ -214,8 +214,8 @@ spack: gitlab-ci: script: - - uname -a - - grep -E 'vendor|model name' /proc/cpuinfo | sort -u + - uname -a || true + - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.powerpc64le-linux-gnu.tar.gz | tar -xzf - -C /usr 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version diff --git a/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml index 5cccd72830b..46499e2a425 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml @@ -266,8 +266,8 @@ spack: gitlab-ci: script: - - uname -a - - grep -E 'vendor|model name' /proc/cpuinfo | sort -u + - uname -a || true + - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null diff --git a/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml index aa7f084e7d2..9e1fb6f5bc0 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml @@ -255,8 +255,8 @@ spack: gitlab-ci: script: - - uname -a - - grep -E 'vendor|model name' /proc/cpuinfo | sort -u + - uname -a || true + - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null diff --git a/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml index 061df799037..72c9f14893b 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml @@ -87,8 +87,8 @@ spack: gitlab-ci: script: - - uname -a - - grep -E 'vendor|model name' /proc/cpuinfo | sort -u + - uname -a || true + - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null diff --git a/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml index 5ef7a62b22e..885870b6ac4 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml @@ -90,8 +90,8 @@ spack: gitlab-ci: script: - - uname -a - - grep -E 'vendor|model name' /proc/cpuinfo | sort -u + - uname -a || true + - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null diff --git a/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml index f78a5edbce0..719526d4f96 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml @@ -93,8 +93,8 @@ spack: gitlab-ci: script: - - uname -a - - grep -E 'vendor|model name' /proc/cpuinfo | sort -u + - uname -a || true + - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null diff --git a/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws-aarch64/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws-aarch64/spack.yaml index 960a8b14881..a9e70f76d2f 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws-aarch64/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws-aarch64/spack.yaml @@ -56,8 +56,8 @@ spack: gitlab-ci: script: - - uname -a - - grep -E 'vendor|model name' /proc/cpuinfo | sort -u + - uname -a || true + - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.aarch64-linux-gnu.tar.gz -o gmake.tar.gz - printf 'deb1dcae0eecdc7fce2902f294012ab5519629e6827204f1b9964dcfd3f74627 gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null diff --git a/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws/spack.yaml index 0405848cb27..b8f9e96a0e3 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws/spack.yaml @@ -61,8 +61,8 @@ spack: gitlab-ci: script: - - uname -a - - grep -E 'vendor|model name' /proc/cpuinfo | sort -u + - uname -a || true + - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null diff --git a/share/spack/gitlab/cloud_pipelines/stacks/radiuss/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/radiuss/spack.yaml index dd667e73cd6..379aeba29f6 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/radiuss/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/radiuss/spack.yaml @@ -64,8 +64,8 @@ spack: gitlab-ci: image: { "name": "ghcr.io/spack/e4s-ubuntu-18.04:v2021-10-18", "entrypoint": [""] } script: - - uname -a - - grep -E 'vendor|model name' /proc/cpuinfo | sort -u + - uname -a || true + - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null diff --git a/share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml index 128d6102196..659ab887423 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml @@ -65,8 +65,8 @@ spack: gitlab-ci: script: - - uname -a - - grep -E 'vendor|model name' /proc/cpuinfo | sort -u + - uname -a || true + - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null From 605411a9fb10a8f12e56d428a5ea93e4dac07ca3 Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Thu, 27 Oct 2022 14:17:54 +0200 Subject: [PATCH 215/442] LuaPackage: add missing attribute (#33551) fixes #33544 --- lib/spack/spack/build_systems/lua.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/spack/spack/build_systems/lua.py b/lib/spack/spack/build_systems/lua.py index 48fa1068815..f1c3e43704a 100644 --- a/lib/spack/spack/build_systems/lua.py +++ b/lib/spack/spack/build_systems/lua.py @@ -20,6 +20,9 @@ class LuaPackage(spack.package_base.PackageBase): #: system base class build_system_class = "LuaPackage" + #: Legacy buildsystem attribute used to deserialize and install old specs + legacy_buildsystem = "lua" + list_depth = 1 # LuaRocks requires at least one level of spidering to find versions build_system("lua") From 883b7cfa29c73d31d01156e1d541385f1f62f981 Mon Sep 17 00:00:00 2001 From: Satish Balay Date: Thu, 27 Oct 2022 08:00:15 -0500 Subject: [PATCH 216/442] hiop: add version 0.7.1 (#33543) --- var/spack/repos/builtin/packages/hiop/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/hiop/package.py b/var/spack/repos/builtin/packages/hiop/package.py index 88d48873988..4789728010b 100644 --- a/var/spack/repos/builtin/packages/hiop/package.py +++ b/var/spack/repos/builtin/packages/hiop/package.py @@ -22,6 +22,7 @@ class Hiop(CMakePackage, CudaPackage, ROCmPackage): maintainers = ["ashermancinelli", "CameronRutherford", "pelesh"] # Most recent tagged snapshot is the preferred version when profiling. + version("0.7.1", commit="8064ef6b2249ad2feca92a9d1e90060bad3eebc7", submodules=True) version("0.7.0", commit="5f42ab34b419b7cf64d0fffb29d443b009dbfd75", submodules=True) version("0.6.2", commit="55652fbe923ab9107d002d0d070865bd22375b28") version("0.6.1", commit="a9e2697b00aa13ecf0ae4783dd8a41dee11dc50e") From 9a51d42cecfdedd9e5776824a420efdf9877d95e Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Thu, 27 Oct 2022 15:34:47 +0200 Subject: [PATCH 217/442] oce: rework recipe to prefer old intel-tbb (#33553) --- var/spack/repos/builtin/packages/oce/package.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/var/spack/repos/builtin/packages/oce/package.py b/var/spack/repos/builtin/packages/oce/package.py index aece04bd2e2..101680aeac1 100644 --- a/var/spack/repos/builtin/packages/oce/package.py +++ b/var/spack/repos/builtin/packages/oce/package.py @@ -10,9 +10,9 @@ class Oce(Package): - """Open CASCADE Community Edition: - patches/improvements/experiments contributed by users over the official - Open CASCADE library. + """Open CASCADE Community Edition + + UNMAINTAINED: see https://github.com/tpaviot/oce/issues/745#issuecomment-992285943 """ homepage = "https://github.com/tpaviot/oce" @@ -32,9 +32,11 @@ class Oce(Package): variant("X11", default=False, description="Build with X11 enabled") depends_on("cmake@2.8:", type="build") - depends_on("tbb", when="+tbb") - conflicts("intel-tbb@2021.1:") - conflicts("intel-oneapi-tbb@2021.1:") + + with when("+tbb"): + depends_on("tbb") + depends_on("intel-tbb@:2020 build_system=makefile", when="^intel-tbb") + conflicts("intel-oneapi-tbb@2021.1:") # There is a bug in OCE which appears with Clang (version?) or GCC 6.0 # and has to do with compiler optimization, see From 07d9c254a2874d56afd65c7c2542ae56ce6bc5ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mos=C3=A8=20Giordano?= Date: Thu, 27 Oct 2022 15:26:06 +0100 Subject: [PATCH 218/442] intel-mpi: add `cpio` as build dependency (#33555) --- var/spack/repos/builtin/packages/intel-mpi/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/intel-mpi/package.py b/var/spack/repos/builtin/packages/intel-mpi/package.py index 68aec8734df..93abd2b3821 100644 --- a/var/spack/repos/builtin/packages/intel-mpi/package.py +++ b/var/spack/repos/builtin/packages/intel-mpi/package.py @@ -127,6 +127,7 @@ class IntelMpi(IntelPackage): "external-libfabric", default=False, description="Enable external libfabric dependency" ) depends_on("libfabric", when="+external-libfabric", type=("build", "link", "run")) + depends_on("cpio", type="build") def setup_dependent_build_environment(self, *args): # Handle in callback, conveying client's compilers in additional arg. From 41d53b85f859d7a41eb30e311bb690e3099d6f0e Mon Sep 17 00:00:00 2001 From: Lucas Nesi Date: Thu, 27 Oct 2022 16:46:54 +0200 Subject: [PATCH 219/442] simgrid: add v3.32 (#33557) --- var/spack/repos/builtin/packages/simgrid/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/simgrid/package.py b/var/spack/repos/builtin/packages/simgrid/package.py index 4af3ed91fd1..2e0b5f3e581 100644 --- a/var/spack/repos/builtin/packages/simgrid/package.py +++ b/var/spack/repos/builtin/packages/simgrid/package.py @@ -19,6 +19,7 @@ class Simgrid(CMakePackage): maintainers = ["viniciusvgp"] + version("3.32", sha256="837764eb81562f04e49dd20fbd8518d9eb1f94df00a4e4555e7ec7fa8aa341f0") version("3.31", sha256="4b44f77ad40c01cf4e3013957c9cbe39f33dec9304ff0c9c3d9056372ed4c61d") version("3.30", sha256="0cad48088c106e72efb42fb423e65d77fc9053cc03d6f3a5ff7ba4c712bb4eb8") version("3.29", sha256="83e8afd653555eeb70dc5c0737b88036c7906778ecd3c95806c6bf5535da2ccf") From 590c4e35caf8b6211e344c41eb6798a7accc76a0 Mon Sep 17 00:00:00 2001 From: G-Ragghianti <33492707+G-Ragghianti@users.noreply.github.com> Date: Thu, 27 Oct 2022 16:54:16 +0200 Subject: [PATCH 220/442] Package slate: added requirements for cuda_arch (#33554) --- var/spack/repos/builtin/packages/slate/package.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/var/spack/repos/builtin/packages/slate/package.py b/var/spack/repos/builtin/packages/slate/package.py index 7e623912b5a..0a08a6af3c9 100644 --- a/var/spack/repos/builtin/packages/slate/package.py +++ b/var/spack/repos/builtin/packages/slate/package.py @@ -60,6 +60,9 @@ class Slate(CMakePackage, CudaPackage, ROCmPackage): depends_on("lapackpp ~cuda", when="~cuda") depends_on("lapackpp +cuda", when="+cuda") depends_on("lapackpp ~rocm", when="~rocm") + for val in CudaPackage.cuda_arch_values: + depends_on("blaspp +cuda cuda_arch=%s" % val, when="cuda_arch=%s" % val) + depends_on("lapackpp +cuda cuda_arch=%s" % val, when="cuda_arch=%s" % val) for val in ROCmPackage.amdgpu_targets: depends_on("blaspp +rocm amdgpu_target=%s" % val, when="amdgpu_target=%s" % val) depends_on("lapackpp +rocm amdgpu_target=%s" % val, when="amdgpu_target=%s" % val) From b19549ce9dc2c5d681722e0dace2a0768c89de20 Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Thu, 27 Oct 2022 17:01:50 +0200 Subject: [PATCH 221/442] suite-sparse: add versions up to v5.13.0 (#33550) --- .../builtin/packages/suite-sparse/package.py | 54 +++++++++---------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/var/spack/repos/builtin/packages/suite-sparse/package.py b/var/spack/repos/builtin/packages/suite-sparse/package.py index d2b85a741c9..3c1e3901e80 100644 --- a/var/spack/repos/builtin/packages/suite-sparse/package.py +++ b/var/spack/repos/builtin/packages/suite-sparse/package.py @@ -15,6 +15,9 @@ class SuiteSparse(Package): url = "https://github.com/DrTimothyAldenDavis/SuiteSparse/archive/v4.5.3.tar.gz" git = "https://github.com/DrTimothyAldenDavis/SuiteSparse.git" + version("5.13.0", sha256="59c6ca2959623f0c69226cf9afb9a018d12a37fab3a8869db5f6d7f83b6b147d") + version("5.12.0", sha256="5fb0064a3398111976f30c5908a8c0b40df44c6dd8f0cc4bfa7b9e45d8c647de") + version("5.11.0", sha256="fdd957ed06019465f7de73ce931afaf5d40e96e14ae57d91f60868b8c123c4c8") version("5.10.1", sha256="acb4d1045f48a237e70294b950153e48dce5b5f9ca8190e86c2b8c54ce00a7ee") version("5.10.0", sha256="4bcc974901c0173acf80c41ee0fd779eb7dce2871d4afa24a5d15b1a468f93e5") version("5.9.0", sha256="7bdd4811f1cf0767c5fdb5e435817fdadee50b0acdb598f4882ae7b8291a7f24") @@ -34,7 +37,6 @@ class SuiteSparse(Package): version("4.5.5", sha256="80d1d9960a6ec70031fecfe9adfe5b1ccd8001a7420efb50d6fa7326ef14af91") version("4.5.3", sha256="b6965f9198446a502cde48fb0e02236e75fa5700b94c7306fc36599d57b563f4") - variant("tbb", default=False, description="Build with Intel TBB") variant( "pic", default=True, @@ -48,21 +50,33 @@ class SuiteSparse(Package): description="Build with GraphBLAS (takes a long time to compile)", ) - depends_on("mpfr@4.0.0:", type=("build", "link"), when="@5.8.0:") - depends_on("gmp", type=("build", "link"), when="@5.8.0:") + # In @4.5.1. TBB support in SPQR seems to be broken as TBB-related linking + # flags does not seem to be used, which leads to linking errors on Linux. + # Support for TBB has been removed in version 5.11 + variant("tbb", default=False, description="Build with Intel TBB", when="@4.5.3:5.10") + depends_on("blas") depends_on("lapack") - depends_on("m4", type="build", when="@5.0.0:") - depends_on("cmake", when="+graphblas @5.2.0:", type="build") - - depends_on("metis@5.1.0", when="@4.5.1:") - # in @4.5.1. TBB support in SPQR seems to be broken as TBB-related linkng - # flags does not seem to be used, which leads to linking errors on Linux. - depends_on("tbb", when="@4.5.3:+tbb") - depends_on("cuda", when="+cuda") - patch("tbb_453.patch", when="@4.5.3:4.5.5+tbb") + depends_on("mpfr@4.0.0:", when="@5.8.0:") + depends_on("gmp", when="@5.8.0:") + depends_on("m4", type="build", when="@5.0.0:") + depends_on("cmake", when="+graphblas @5.2.0:", type="build") + depends_on("metis@5.1.0", when="@4.5.1:") + + with when("+tbb"): + depends_on("tbb") + patch("tbb_453.patch", when="@4.5.3:4.5.5") + # The @2021.x versions of tbb dropped the task_scheduler_init.h header and + # related stuff (which have long been deprecated). This appears to be + # rather problematic for suite-sparse (see e.g. + # https://github.com/DrTimothyAldenDavis/SuiteSparse/blob/master/SPQR/Source/spqr_parallel.cpp) + depends_on("intel-tbb@:2020 build_system=makefile", when="^intel-tbb") + conflicts( + "^intel-oneapi-tbb@2021:", + msg="suite-sparse needs task_scheduler_init.h dropped in recent tbb libs", + ) # This patch removes unsupported flags for pgi compiler patch("pgi.patch", when="%pgi") @@ -81,22 +95,6 @@ class SuiteSparse(Package): "%gcc@:4.8", when="@5.2.0:", msg="gcc version must be at least 4.9 for suite-sparse@5.2.0:" ) - # The @2021.x versions of tbb dropped the task_scheduler_init.h header and - # related stuff (which have long been deprecated). This appears to be - # rather problematic for suite-sparse (see e.g. - # https://github.com/DrTimothyAldenDavis/SuiteSparse/blob/master/SPQR/Source/spqr_parallel.cpp) - # Have Spack complain if +tbb and trying to use a 2021.x version of tbb - conflicts( - "+tbb", - when="^intel-oneapi-tbb@2021:", - msg="suite-sparse needs task_scheduler_init.h dropped in " "recent tbb libs", - ) - conflicts( - "+tbb", - when="^intel-tbb@2021:", - msg="suite-sparse needs task_scheduler_init.h dropped in " "recent tbb libs", - ) - def symbol_suffix_blas(self, spec, args): """When using BLAS with a special symbol suffix we use defines to replace blas symbols, e.g. dgemm_ becomes dgemm_64_ when From ecdfe0235597d5bafcc7f6c1c5b79fbfb991ee28 Mon Sep 17 00:00:00 2001 From: Lucas Nesi Date: Thu, 27 Oct 2022 17:02:09 +0200 Subject: [PATCH 222/442] starpu: correct fxt dependency variant when simgrid (#33558) --- var/spack/repos/builtin/packages/starpu/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/starpu/package.py b/var/spack/repos/builtin/packages/starpu/package.py index 947a934db65..db0b372be5a 100644 --- a/var/spack/repos/builtin/packages/starpu/package.py +++ b/var/spack/repos/builtin/packages/starpu/package.py @@ -80,6 +80,7 @@ class Starpu(AutotoolsPackage): depends_on("mpi", when="+mpi~simgrid") depends_on("cuda", when="+cuda~simgrid") depends_on("fxt", when="+fxt") + depends_on("fxt+static", when="+fxt+simgrid+mpi") depends_on("simgrid", when="+simgrid") depends_on("simgrid+smpi", when="+simgrid+mpi") depends_on("simgrid+mc", when="+simgridmc") From 6cb4a00280849c22191ac0d506eeac93db3052a5 Mon Sep 17 00:00:00 2001 From: Satish Balay Date: Thu, 27 Oct 2022 10:02:36 -0500 Subject: [PATCH 223/442] petsc+kokkos: pass in cuda_arch, rocm_arch to kokkos (#33530) Also remove dependency on kokkos+wrapper --- .../repos/builtin/packages/petsc/package.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/var/spack/repos/builtin/packages/petsc/package.py b/var/spack/repos/builtin/packages/petsc/package.py index 71ba0cba756..830adff3b59 100644 --- a/var/spack/repos/builtin/packages/petsc/package.py +++ b/var/spack/repos/builtin/packages/petsc/package.py @@ -333,9 +333,20 @@ def check_fortran_compiler(self): depends_on("hwloc", when="+hwloc") depends_on("kokkos", when="+kokkos") depends_on("kokkos-kernels", when="+kokkos") - depends_on("kokkos+cuda+wrapper+cuda_lambda", when="+kokkos +cuda") - depends_on("kokkos-kernels+cuda", when="+kokkos +cuda") - depends_on("kokkos+rocm", when="+kokkos +rocm") + for cuda_arch in CudaPackage.cuda_arch_values: + depends_on( + "kokkos+cuda+cuda_lambda cuda_arch=%s" % cuda_arch, + when="+kokkos +cuda cuda_arch=%s" % cuda_arch, + ) + depends_on( + "kokkos-kernels+cuda cuda_arch=%s" % cuda_arch, + when="+kokkos +cuda cuda_arch=%s" % cuda_arch, + ) + for rocm_arch in ROCmPackage.amdgpu_targets: + depends_on( + "kokkos+rocm amdgpu_target=%s" % rocm_arch, + when="+kokkos +rocm amdgpu_target=%s" % rocm_arch, + ) phases = ["configure", "build", "install"] From 5a939d9c94e5723c310f6680edc038825c0b4f99 Mon Sep 17 00:00:00 2001 From: ryandanehy <110119005+ryandanehy@users.noreply.github.com> Date: Thu, 27 Oct 2022 08:14:09 -0700 Subject: [PATCH 224/442] exago, hiop: propagate build type (#32750) --- .../repos/builtin/packages/exago/package.py | 38 ++++++++++++++++++- .../repos/builtin/packages/hiop/package.py | 2 +- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/var/spack/repos/builtin/packages/exago/package.py b/var/spack/repos/builtin/packages/exago/package.py index b85f72e9d8d..06c3ad81733 100644 --- a/var/spack/repos/builtin/packages/exago/package.py +++ b/var/spack/repos/builtin/packages/exago/package.py @@ -13,7 +13,7 @@ class Exago(CMakePackage, CudaPackage, ROCmPackage): homepage = "https://gitlab.pnnl.gov/exasgd/frameworks/exago" git = "https://gitlab.pnnl.gov/exasgd/frameworks/exago.git" - maintainers = ["ashermancinelli", "CameronRutherford", "pelesh"] + maintainers = ["ryandanehy", "CameronRutherford", "pelesh"] version( "1.4.1", commit="ea607c685444b5f345bfdc9a59c345f0f30adde2", submodules=True, preferred=True @@ -46,7 +46,7 @@ class Exago(CMakePackage, CudaPackage, ROCmPackage): conflicts("~hiop~ipopt", msg="ExaGO needs at least one solver enabled") - # Dependencides + # Dependencies depends_on("pkgconfig", type="build") depends_on("mpi", when="+mpi") depends_on("blas") @@ -62,6 +62,40 @@ class Exago(CMakePackage, CudaPackage, ROCmPackage): depends_on("cmake@3.18:", type="build") + # Profiling + depends_on( + "hiop+deepchecking build_type=RelWithDebInfo", when="+hiop build_type=RelWithDebInfo" + ) + depends_on("hiop~deepchecking build_type=Release ", when="+hiop build_type=Release ") + + # Control the package's build-type depending on the release or debug flag + for pkg in [ + ("raja", "raja"), + ("umpire", "raja"), + ("magma", "hiop+cuda"), + ("magma", "hiop+rocm"), + ("camp", "raja"), + ]: + depends_on( + "{0} build_type=Release".format(pkg[0]), when="+{0} build_type=Release".format(pkg[1]) + ) + depends_on( + "{0} build_type=RelWithDebInfo".format(pkg[0]), + when="+{0} build_type=RelWithDebInfo".format(pkg[1]), + ) + + depends_on( + "{0} build_type=Release".format("hiop+ginkgo ^ginkgo"), + when="+{0} build_type=Release".format("hiop ^hiop+ginkgo"), + ) + depends_on( + "{0} build_type=Debug".format("hiop+ginkgo ^ginkgo"), + when="+{0} build_type=RelWithDebInfo".format("hiop ^hiop+ginkgo"), + ) + # depends_on("hpctoolkit", when="with_profiling=hpctoolkit") + # depends_on("tau", when="with_profiling=tau") + # ^ need to depend when both hpctoolkit and tau + # HiOp dependency logic depends_on("hiop+raja", when="+hiop+raja") depends_on("hiop@0.3.99:", when="@0.99:+hiop") diff --git a/var/spack/repos/builtin/packages/hiop/package.py b/var/spack/repos/builtin/packages/hiop/package.py index 4789728010b..16325dd5208 100644 --- a/var/spack/repos/builtin/packages/hiop/package.py +++ b/var/spack/repos/builtin/packages/hiop/package.py @@ -19,7 +19,7 @@ class Hiop(CMakePackage, CudaPackage, ROCmPackage): homepage = "https://github.com/LLNL/hiop" git = "https://github.com/LLNL/hiop.git" - maintainers = ["ashermancinelli", "CameronRutherford", "pelesh"] + maintainers = ["ryandanehy", "CameronRutherford", "pelesh"] # Most recent tagged snapshot is the preferred version when profiling. version("0.7.1", commit="8064ef6b2249ad2feca92a9d1e90060bad3eebc7", submodules=True) From b9bee70a97075409d8c5a014c4f55d1b086c9b72 Mon Sep 17 00:00:00 2001 From: psakievich Date: Thu, 27 Oct 2022 09:33:51 -0600 Subject: [PATCH 225/442] curl: stop auto generating file named `str` (#33532) Calling `determine_variants` from the `curl` package autogenerates an empty file every time it is called. --- var/spack/repos/builtin/packages/curl/package.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/curl/package.py b/var/spack/repos/builtin/packages/curl/package.py index 8923423efb1..26be294245f 100644 --- a/var/spack/repos/builtin/packages/curl/package.py +++ b/var/spack/repos/builtin/packages/curl/package.py @@ -129,7 +129,7 @@ def determine_variants(cls, exes, version): for exe in exes: variants = "" curl = Executable(exe) - output = curl("--version", output=str, error="str") + output = curl("--version", output=str, error=str) if "nghttp2" in output: variants += "+nghttp2" protocols_match = re.search(r"Protocols: (.*)\n", output) From 2960d8ac0ae1c53a8517c32ea21be522fa68b9e8 Mon Sep 17 00:00:00 2001 From: SoniaScard <83462318+SoniaScard@users.noreply.github.com> Date: Thu, 27 Oct 2022 17:52:49 +0200 Subject: [PATCH 226/442] ophidia-io-server: new package at v1.7 (#33436) Co-authored-by: SoniaScard --- .../packages/ophidia-io-server/package.py | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 var/spack/repos/builtin/packages/ophidia-io-server/package.py diff --git a/var/spack/repos/builtin/packages/ophidia-io-server/package.py b/var/spack/repos/builtin/packages/ophidia-io-server/package.py new file mode 100644 index 00000000000..9b2ee7a03cf --- /dev/null +++ b/var/spack/repos/builtin/packages/ophidia-io-server/package.py @@ -0,0 +1,39 @@ +# 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 OphidiaIoServer(AutotoolsPackage): + """In-memory IO server of the Ophidia framework""" + + homepage = "https://github.com/OphidiaBigData/ophidia-io-server" + url = "https://github.com/OphidiaBigData/ophidia-io-server/archive/refs/tags/v1.7.2.tar.gz" + maintainers = ["eldoo", "SoniaScard"] + version("1.7.2", sha256="8b203c44e0e5497c00f1fdb2322f0b0a41f36900b62a33d95a4570ae1ccc2971") + + depends_on("autoconf", type="build") + depends_on("automake", type="build") + depends_on("libtool", type="build") + depends_on("m4", type="build") + + depends_on("boost@1.79.0") + depends_on("netcdf-c") + depends_on("mysql") + depends_on("bison") + depends_on("flex") + depends_on("ophidia-primitives") + + def autoreconf(self, spec, prefix): + autoreconf("--install", "--verbose", "--force") + + def configure_args(self): + args = [ + "--with-plugin-path={0}".format(self.spec["ophidia-primitives"].prefix.lib), + "--with-netcdf-path={0}".format(self.spec["netcdf-c"].prefix), + "--enable-parallel-nc4", + ] + + return args From 86337f042eda6502551c40ca728e29de6a67c6e0 Mon Sep 17 00:00:00 2001 From: Lucas Nesi Date: Thu, 27 Oct 2022 17:59:06 +0200 Subject: [PATCH 227/442] chameleon: correct chameleon+simgrid build (#33559) * chameleon: correct chameleon+simgrid build * chameleon: remove unused declarations --- var/spack/repos/builtin/packages/chameleon/package.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/var/spack/repos/builtin/packages/chameleon/package.py b/var/spack/repos/builtin/packages/chameleon/package.py index f73cd82e161..98aba276b02 100644 --- a/var/spack/repos/builtin/packages/chameleon/package.py +++ b/var/spack/repos/builtin/packages/chameleon/package.py @@ -54,8 +54,11 @@ class Chameleon(CMakePackage, CudaPackage): depends_on("starpu~cuda", when="~cuda") depends_on("starpu+cuda", when="+cuda") with when("+simgrid"): + depends_on("simgrid+msg") depends_on("starpu+simgrid") depends_on("starpu+mpi~shared+simgrid", when="+mpi") + conflicts("^simgrid@:3.31", when="@:1.1.0") + conflicts("+shared", when="+simgrid") with when("~simgrid"): depends_on("mpi", when="+mpi") depends_on("cuda", when="+cuda") @@ -90,9 +93,9 @@ def cmake_args(self): if spec.satisfies("+mpi +simgrid"): args.extend( [ - self.define("MPI_C_COMPILER", self.spec["simgrid"].smpicc), - self.define("MPI_CXX_COMPILER", self.spec["simgrid"].smpicxx), - self.define("MPI_Fortran_COMPILER", self.spec["simgrid"].smpifc), + self.define("CMAKE_C_COMPILER", self.spec["simgrid"].smpicc), + self.define("CMAKE_CXX_COMPILER", self.spec["simgrid"].smpicxx), + self.define("CMAKE_Fortran_COMPILER", self.spec["simgrid"].smpifc), ] ) From 5f99d3dfaaac47ffff1cb48be1328de5746ab618 Mon Sep 17 00:00:00 2001 From: Brian Van Essen Date: Thu, 27 Oct 2022 09:13:07 -0700 Subject: [PATCH 228/442] spdlog: allow using vendored fmt library (#33379) --- var/spack/repos/builtin/packages/spdlog/package.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/var/spack/repos/builtin/packages/spdlog/package.py b/var/spack/repos/builtin/packages/spdlog/package.py index bf411c36831..e449d853d24 100644 --- a/var/spack/repos/builtin/packages/spdlog/package.py +++ b/var/spack/repos/builtin/packages/spdlog/package.py @@ -45,13 +45,18 @@ class Spdlog(CMakePackage): version("0.9.0", sha256="bbbe5a855c8b309621352921d650449eb2f741d35d55ec50fb4d8122ddfb8f01") variant("shared", default=True, description="Build shared libraries (v1.4.0+)") + variant( + "fmt_external", + default=False, + description="Build using external fmt libraries instead of bundled one", + ) depends_on("cmake@3.2:", when="@:1.7.0", type="build") depends_on("cmake@3.10:", when="@1.8.0:", type="build") - depends_on("fmt@5.3:") - depends_on("fmt@7:", when="@1.7:") - depends_on("fmt@8:", when="@1.9:") + depends_on("fmt@5.3:", when="+fmt_external") + depends_on("fmt@7:", when="@1.7: +fmt_external") + depends_on("fmt@8:", when="@1.9: +fmt_external") def cmake_args(self): args = [] @@ -60,7 +65,7 @@ def cmake_args(self): args.extend( [ self.define_from_variant("SPDLOG_BUILD_SHARED", "shared"), - self.define("SPDLOG_FMT_EXTERNAL", "ON"), + self.define_from_variant("SPDLOG_FMT_EXTERNAL", "fmt_external"), # tests and examples self.define("SPDLOG_BUILD_TESTS", self.run_tests), self.define("SPDLOG_BUILD_EXAMPLE", self.run_tests), From 34d55af55d0f93e2610fe3f4faf5d819a4512ff3 Mon Sep 17 00:00:00 2001 From: Satish Balay Date: Thu, 27 Oct 2022 11:44:51 -0500 Subject: [PATCH 229/442] phist: add v1.11.2 (#33561) --- var/spack/repos/builtin/packages/phist/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/phist/package.py b/var/spack/repos/builtin/packages/phist/package.py index 3d467231811..94c868589b2 100644 --- a/var/spack/repos/builtin/packages/phist/package.py +++ b/var/spack/repos/builtin/packages/phist/package.py @@ -34,6 +34,7 @@ class Phist(CMakePackage): version("develop", branch="devel") version("master", branch="master") + version("1.11.2", sha256="e23f76307c26b930f7331a734b0a864ea6d7fb4a13c12f3c5d70c2c41481747b") # updated lapack interface to work with openblas and netlib-lapack version("1.11.0", sha256="36e6cc41a13884ba0a26f7be03e3f1882b1a2d14ca04353a609c0eec0cfb7a77") From 57226a870baa29fedb129234e1d5177a9a09db0d Mon Sep 17 00:00:00 2001 From: Luke Diorio-Toth Date: Thu, 27 Oct 2022 11:51:36 -0500 Subject: [PATCH 230/442] py-ncbi-genome-download: new package (#33511) * py-ncbi-genome-download: new package * fixed style --- .../py-ncbi-genome-download/package.py | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 var/spack/repos/builtin/packages/py-ncbi-genome-download/package.py diff --git a/var/spack/repos/builtin/packages/py-ncbi-genome-download/package.py b/var/spack/repos/builtin/packages/py-ncbi-genome-download/package.py new file mode 100644 index 00000000000..3124f45ae38 --- /dev/null +++ b/var/spack/repos/builtin/packages/py-ncbi-genome-download/package.py @@ -0,0 +1,21 @@ +# 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 PyNcbiGenomeDownload(PythonPackage): + """Scripts to download genomes from the NCBI FTP servers""" + + homepage = "https://github.com/kblin/ncbi-genome-download/" + pypi = "ncbi-genome-download/ncbi-genome-download-0.3.1.tar.gz" + + version("0.3.1", sha256="74675e94f184b8d80429641b27ed6d46ed81028d95156337de6d09f8dd739c6e") + + depends_on("py-setuptools", type="build") + depends_on("py-appdirs", type=("build", "run")) + depends_on("py-requests@2.4.3:", type=("build", "run")) + depends_on("py-tqdm", type=("build", "run")) From 6f4d69cf8da7abfed9146fb4cdb957b357644d2a Mon Sep 17 00:00:00 2001 From: Miroslav Stoyanov <30537612+mkstoyanov@users.noreply.github.com> Date: Thu, 27 Oct 2022 13:18:44 -0400 Subject: [PATCH 231/442] new version and rocm fix (#33536) --- .../repos/builtin/packages/heffte/package.py | 72 +++++++++++++++++-- 1 file changed, 65 insertions(+), 7 deletions(-) diff --git a/var/spack/repos/builtin/packages/heffte/package.py b/var/spack/repos/builtin/packages/heffte/package.py index 2628cc5a87d..a5695e239e7 100644 --- a/var/spack/repos/builtin/packages/heffte/package.py +++ b/var/spack/repos/builtin/packages/heffte/package.py @@ -3,6 +3,10 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import os + +from llnl.util import tty + from spack.package import * @@ -19,6 +23,7 @@ class Heffte(CMakePackage, CudaPackage, ROCmPackage): test_requires_compiler = True version("develop", branch="master") + version("2.3.0", sha256="27c0a8da8f7bc91c8715ecb640721ab7e0454e22f6e3f521fe5acc45c28d60a9") version("2.2.0", sha256="aff4f5111d3d05b269a1378bb201271c40b39e9c960c05c4ef247a31a039be58") version("2.1.0", sha256="527a3e21115231715a0342afdfaf6a8878d2dd0f02f03c92b53692340fd940b9") version("2.0.0", sha256="12f2b49a1a36c416eac174cf0cc50e729d56d68a9f68886d8c34bd45a0be26b6") @@ -104,11 +109,64 @@ def cmake_args(self): return args + def cmake_bin(self, set=True): + """(Hack) Set/get cmake dependency path. Sync with Tasmanian.""" + filepath = join_path(self.install_test_root, "cmake_bin_path.txt") + if set: + with open(filepath, "w") as out_file: + cmake_bin = join_path(self.spec["cmake"].prefix.bin, "cmake") + out_file.write("{0}\n".format(cmake_bin)) + elif os.path.isfile(filepath): + with open(filepath, "r") as in_file: + return in_file.read().strip() + + @run_after("install") + def setup_smoke_test(self): + install_tree( + self.prefix.share.heffte.testing, join_path(self.install_test_root, "testing") + ) + self.cmake_bin(set=True) + def test(self): - # using the tests installed in /share/heffte/testing - cmake_dir = join_path(self.prefix, "share", "heffte", "testing") - test_dir = join_path(self.test_suite.current_test_cache_dir, "test_install") - with working_dir(test_dir, create=True): - cmake(cmake_dir) - make() - make("test") + cmake_bin = self.cmake_bin(set=False) + + if not cmake_bin: + tty.msg("Skipping heffte test: cmake_bin_path.txt not found") + return + + # using the tests copied from /share/heffte/testing + cmake_dir = self.test_suite.current_test_cache_dir.testing + + options = [ + cmake_dir, + ] + if "+rocm" in self.spec: + options.append( + "-DAMDDeviceLibs_DIR=" + + join_path(self.spec["llvm-amdgpu"].prefix, "lib", "cmake", "AMDDeviceLibs") + ) + options.append( + "-Damd_comgr_DIR=" + + join_path(self.spec["comgr"].prefix, "lib", "cmake", "amd_comgr") + ) + options.append( + "-Dhsa-runtime64_DIR=" + + join_path(self.spec["hsa-rocr-dev"].prefix, "lib", "cmake", "hsa-runtime64") + ) + options.append( + "-DHSA_HEADER=" + join_path(self.spec["hsa-rocr-dev"].prefix, "include") + ) + options.append( + "-Drocfft_DIR=" + join_path(self.spec["rocfft"].prefix, "lib", "cmake", "rocfft") + ) + + if not self.run_test(cmake_bin, options=options, purpose="Generate the Makefile"): + tty.msg("Skipping heffte test: failed to generate Makefile") + return + + if not self.run_test("make", purpose="Build test software"): + tty.msg("Skipping heffte test: failed to build test") + return + + if not self.run_test("make", options=["test"], purpose="Run test"): + tty.msg("Failed heffte test: failed to run test") From ea1719d98683340b95f0957e2384da75d65379c5 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Thu, 27 Oct 2022 18:18:16 +0000 Subject: [PATCH 232/442] Paraview catalyst support (#33369) * paraview: add support for Catalyst 1 APIs * paraview: add support for libcatalyst impl support --- .../repos/builtin/packages/paraview/package.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/var/spack/repos/builtin/packages/paraview/package.py b/var/spack/repos/builtin/packages/paraview/package.py index ea522143e98..0ed725dc6ab 100644 --- a/var/spack/repos/builtin/packages/paraview/package.py +++ b/var/spack/repos/builtin/packages/paraview/package.py @@ -73,6 +73,13 @@ class Paraview(CMakePackage, CudaPackage): variant("pagosa", default=False, description="Build the pagosa adaptor") variant("eyedomelighting", default=False, description="Enable Eye Dome Lighting feature") variant("adios2", default=False, description="Enable ADIOS2 support", when="@5.8:") + variant("catalyst", default=False, description="Enable Catalyst 1", when="@5.7:") + variant( + "libcatalyst", + default=False, + description="Enable Catalyst 2 (libcatalyst) implementation", + when="@5.10:", + ) variant( "advanced_debug", @@ -205,6 +212,7 @@ class Paraview(CMakePackage, CudaPackage): depends_on("lz4") depends_on("xz") depends_on("zlib") + depends_on("libcatalyst", when="+libcatalyst") # Older builds of pugi export their symbols differently, # and pre-5.9 is unable to handle that. @@ -574,4 +582,13 @@ def nvariant_bool(feature): if "+advanced_debug" in spec: cmake_args.append("-DVTK_DEBUG_LEAKS:BOOL=ON") + if "+catalyst" in spec: + cmake_args.append("-DVTK_MODULE_ENABLE_ParaView_Catalyst=YES") + if "+python3" in spec: + cmake_args.append("-DVTK_MODULE_ENABLE_ParaView_PythonCatalyst=YES") + + if "+libcatalyst" in spec: + cmake_args.append("-DVTK_MODULE_ENABLE_ParaView_InSitu=YES") + cmake_args.append("-DPARAVIEW_ENABLE_CATALYST=YES") + return cmake_args From ec50906943f72f4530c7f1a0395d6c8d266970f4 Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Thu, 27 Oct 2022 20:25:26 +0200 Subject: [PATCH 233/442] Update macOS Python version in CI to 3.10 (#33560) --- .github/workflows/unit_tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/unit_tests.yaml b/.github/workflows/unit_tests.yaml index 1d84e5bfebe..36c4a4339bc 100644 --- a/.github/workflows/unit_tests.yaml +++ b/.github/workflows/unit_tests.yaml @@ -192,7 +192,7 @@ jobs: runs-on: macos-latest strategy: matrix: - python-version: [3.8] + python-version: ["3.10"] steps: - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # @v2 with: From 13636a2094205e1dc9d94b25832b5cf013afaa7d Mon Sep 17 00:00:00 2001 From: Carson Woods Date: Thu, 27 Oct 2022 14:32:20 -0400 Subject: [PATCH 234/442] Add new versions to wi4mpi (#33569) --- var/spack/repos/builtin/packages/wi4mpi/package.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/var/spack/repos/builtin/packages/wi4mpi/package.py b/var/spack/repos/builtin/packages/wi4mpi/package.py index b3d0be71884..1a5081632df 100644 --- a/var/spack/repos/builtin/packages/wi4mpi/package.py +++ b/var/spack/repos/builtin/packages/wi4mpi/package.py @@ -14,6 +14,9 @@ class Wi4mpi(CMakePackage): url = "https://github.com/cea-hpc/wi4mpi/archive/v3.4.1.tar.gz" maintainers = ["adrien-cotte", "marcjoos-cea"] + version("3.6.3", sha256="c327babc892cc3c2bdddfacf3011e6fcb7e00a04e814de31f5e707cba3199c5c") + version("3.6.2", sha256="4b784d27decfff9cbd29f072ba75bb0f6c471d6edc7f1037df1ab7ccbcceffba") + version("3.6.1", sha256="14fbaf8c7ac0b7f350242a90e1be75e9f4bd0196a0d0e326b40be04ca58a2613") version("3.6.0", sha256="06f48bf506643edba51dd04bfdfbaa824363d28549f8eabf002b760ba516227b") version("3.5.0", sha256="36dd3dfed4f0f37bc817204d4810f049e624900b1b32641122f09a183135522f") version("3.4.1", sha256="92bf6738216426069bc07bff19cd7c933e33e397a941ff9f89a639380fab3737") From 4be67facdc41fdac6d71de2367ba39659cb1ccba Mon Sep 17 00:00:00 2001 From: Stephen McDowell Date: Thu, 27 Oct 2022 14:51:19 -0400 Subject: [PATCH 235/442] ECP-SDK: enable hdf5-vfd-gds when +cuda (#33300) - hdf5-vfd-gds: - Add new version 1.0.2 compatible with hdf5@1.13. - CMake is a build dependency. - Set `HDF5_PLUGIN_PATH` in the runtime environment, this plugin is loaded dynamically. - SDK: - The VFD GDS driver only has utility when CUDA is enabled. - Require hdf5-vfd-gds@1.0.2+ (1.0.1 and earlier do not compile). --- .../packages/ecp-data-vis-sdk/package.py | 18 ++++++++++++------ .../builtin/packages/hdf5-vfd-gds/package.py | 7 +++++-- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/var/spack/repos/builtin/packages/ecp-data-vis-sdk/package.py b/var/spack/repos/builtin/packages/ecp-data-vis-sdk/package.py index 31c3fc06ea2..54a61243fee 100644 --- a/var/spack/repos/builtin/packages/ecp-data-vis-sdk/package.py +++ b/var/spack/repos/builtin/packages/ecp-data-vis-sdk/package.py @@ -15,17 +15,22 @@ def dav_sdk_depends_on(spec, when=None, propagate=None): # ie. A +c ~b -> A spec = Spec(spec).name - if "+" in when and len(when.split()) == 1: - when_not = when.replace("+", "~") - # If the package is in the spec tree then it must - # be enabled in the SDK. - conflicts(when_not, "^" + spec) + # If the package is in the spec tree then it must be enabled in the SDK. + if "+" in when: + _when_variants = when.strip("+").split("+") + if any(tok in when for tok in ["~", "="]): + tty.error("Bad token in when clause, only positive boolean tokens allowed") + + for variant in _when_variants: + conflicts("~" + variant, when="^" + spec) # Skip if there is nothing to propagate if not propagate: return - # Map the propagated variants to the dependency variant + # Map the propagated variants to the dependency variant. Some packages may need + # overrides to propagate a dependency as something else, e.g., {"visit": "libsim"}. + # Most call-sites will just use a list. if not type(propagate) is dict: propagate = dict([(v, v) for v in propagate]) @@ -108,6 +113,7 @@ class EcpDataVisSdk(BundlePackage, CudaPackage, ROCmPackage): dav_sdk_depends_on("faodel+shared+mpi network=libfabric", when="+faodel", propagate=["hdf5"]) dav_sdk_depends_on("hdf5@1.12: +shared+mpi", when="+hdf5", propagate=["fortran"]) + dav_sdk_depends_on("hdf5-vfd-gds@1.0.2:", when="+cuda+hdf5", propagate=cuda_arch_variants) dav_sdk_depends_on("parallel-netcdf+shared", when="+pnetcdf", propagate=["fortran"]) diff --git a/var/spack/repos/builtin/packages/hdf5-vfd-gds/package.py b/var/spack/repos/builtin/packages/hdf5-vfd-gds/package.py index ddd0159db86..b3e3960b248 100644 --- a/var/spack/repos/builtin/packages/hdf5-vfd-gds/package.py +++ b/var/spack/repos/builtin/packages/hdf5-vfd-gds/package.py @@ -17,19 +17,22 @@ class Hdf5VfdGds(CMakePackage, CudaPackage): # Versions version("master", branch="master") + version("1.0.2", sha256="f7df64ff62e057b525bc30ed6534f9c0752e52bd58b65f7c147878d6c68105ae") version("1.0.1", sha256="00e125fd149561be991f41e883824de826d8add604aebccf103a4fb82d5faac2") version("1.0.0", sha256="6b16105c7c49f13fc05784ee69b78d45fb159270c78d760689f9cd21e230ddd2") # Dependencies conflicts("~cuda") - depends_on("cmake@3.12:") + depends_on("cmake@3.12:", type="build") depends_on("hdf5@1.13.0:") def cmake_args(self): - # CMake options args = [ self.define("BUILD_TESTING", self.run_tests), ] return args + + def setup_run_environment(self, env): + env.prepend_path("HDF5_PLUGIN_PATH", self.spec.prefix.lib) From 6408b51def038b9479b0e0cba2d079b103af56a6 Mon Sep 17 00:00:00 2001 From: Brian Van Essen Date: Thu, 27 Oct 2022 12:19:56 -0700 Subject: [PATCH 236/442] Support ROCm backing in DiHydrogen (#33563) * Added support for building the DiHydrogen package and LBANN extensions to DiHydrogen with ROCm libraries. Fixed a bug on Cray systems where CMake didn't try hard enough to find an MPI-compatible compiler wrapper. Make it look more. Added support for the roctracer package when using ROCm libraries. * Fixed how ROCm support is defined for pre-v0.3 versions. --- .../builtin/packages/dihydrogen/package.py | 26 ++++++++++++++----- .../repos/builtin/packages/lbann/package.py | 12 ++++++++- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/var/spack/repos/builtin/packages/dihydrogen/package.py b/var/spack/repos/builtin/packages/dihydrogen/package.py index 40ffd50d2d0..082ea55559b 100644 --- a/var/spack/repos/builtin/packages/dihydrogen/package.py +++ b/var/spack/repos/builtin/packages/dihydrogen/package.py @@ -83,9 +83,9 @@ class Dihydrogen(CMakePackage, CudaPackage, ROCmPackage): for val in ROCmPackage.amdgpu_targets: depends_on("aluminum amdgpu_target=%s" % val, when="amdgpu_target=%s" % val) - for when in ["+cuda", "+distconv"]: - depends_on("cuda", when=when) - depends_on("cudnn", when=when) + depends_on("roctracer-dev", when="+rocm +distconv") + + depends_on("cudnn", when="+cuda +distconv") depends_on("cub", when="^cuda@:10") # Note that #1712 forces us to enumerate the different blas variants @@ -108,8 +108,8 @@ class Dihydrogen(CMakePackage, CudaPackage, ROCmPackage): depends_on("cray-libsci", when="blas=libsci") depends_on("cray-libsci +openmp", when="blas=libsci +openmp_blas") - # Distconv builds require cuda - conflicts("~cuda", when="+distconv") + # Distconv builds require cuda or rocm + conflicts("+distconv", when="~cuda ~rocm") conflicts("+distconv", when="+half") conflicts("+rocm", when="+half") @@ -120,6 +120,8 @@ class Dihydrogen(CMakePackage, CudaPackage, ROCmPackage): depends_on("ninja", type="build") depends_on("cmake@3.17.0:", type="build") + depends_on("spdlog", when="@:0.1,0.2:") + depends_on("llvm-openmp", when="%apple-clang +openmp") # TODO: Debug linker errors when NVSHMEM is built with UCX @@ -155,10 +157,14 @@ def cmake_args(self): "-DH2_ENABLE_DISTCONV_LEGACY=%s" % ("+distconv" in spec), "-DH2_ENABLE_OPENMP=%s" % ("+openmp" in spec), "-DH2_ENABLE_FP16=%s" % ("+half" in spec), - "-DH2_ENABLE_HIP_ROCM=%s" % ("+rocm" in spec), "-DH2_DEVELOPER_BUILD=%s" % ("+developer" in spec), ] + if spec.version < Version("0.3"): + args.append("-DH2_ENABLE_HIP_ROCM=%s" % ("+rocm" in spec)) + else: + args.append("-DH2_ENABLE_ROCM=%s" % ("+rocm" in spec)) + if not spec.satisfies("^cmake@3.23.0"): # There is a bug with using Ninja generator in this version # of CMake @@ -181,7 +187,7 @@ def cmake_args(self): if spec.satisfies("%cce") and spec.satisfies("^cuda+allow-unsupported-compilers"): args.append("-DCMAKE_CUDA_FLAGS=-allow-unsupported-compiler") - if "+cuda" in spec or "+distconv" in spec: + if "+cuda" in spec: args.append("-DcuDNN_DIR={0}".format(spec["cudnn"].prefix)) if spec.satisfies("^cuda@:10"): @@ -209,6 +215,12 @@ def cmake_args(self): "-DHIP_CXX_COMPILER={0}".format(self.spec["hip"].hipcc), ] ) + if "platform=cray" in spec: + args.extend( + [ + "-DMPI_ASSUME_NO_BUILTIN_MPI=ON", + ] + ) archs = self.spec.variants["amdgpu_target"].value if archs != "none": arch_str = ",".join(archs) diff --git a/var/spack/repos/builtin/packages/lbann/package.py b/var/spack/repos/builtin/packages/lbann/package.py index 69039783ff9..bed40b3f5ed 100644 --- a/var/spack/repos/builtin/packages/lbann/package.py +++ b/var/spack/repos/builtin/packages/lbann/package.py @@ -167,7 +167,8 @@ class Lbann(CMakePackage, CudaPackage, ROCmPackage): depends_on("dihydrogen +cuda", when="+dihydrogen +cuda") depends_on("dihydrogen ~al", when="+dihydrogen ~al") depends_on("dihydrogen +al", when="+dihydrogen +al") - depends_on("dihydrogen +distconv +cuda", when="+distconv") + depends_on("dihydrogen +distconv +cuda", when="+distconv +cuda") + depends_on("dihydrogen +distconv +rocm", when="+distconv +rocm") depends_on("dihydrogen ~half", when="+dihydrogen ~half") depends_on("dihydrogen +half", when="+dihydrogen +half") depends_on("dihydrogen ~nvshmem", when="+dihydrogen ~nvshmem") @@ -191,6 +192,8 @@ class Lbann(CMakePackage, CudaPackage, ROCmPackage): depends_on("aluminum amdgpu_target=%s" % val, when="+al amdgpu_target=%s" % val) depends_on("dihydrogen amdgpu_target=%s" % val, when="+dihydrogen amdgpu_target=%s" % val) + depends_on("roctracer-dev", when="+rocm +distconv") + depends_on("cudnn", when="@0.90:0.100 +cuda") depends_on("cudnn@8.0.2:", when="@:0.90,0.101: +cuda") depends_on("cub", when="@0.94:0.98.2 +cuda ^cuda@:10") @@ -334,6 +337,7 @@ def cmake_args(self): "-DLBANN_WITH_ONNX:BOOL=%s" % ("+onnx" in spec), "-DLBANN_WITH_EMBEDDED_PYTHON:BOOL=%s" % ("+python" in spec), "-DLBANN_WITH_PYTHON_FRONTEND:BOOL=%s" % ("+pfe" in spec), + "-DLBANN_WITH_ROCTRACER:BOOL=%s" % ("+rocm +distconv" in spec), "-DLBANN_WITH_TBINF=OFF", "-DLBANN_WITH_UNIT_TESTING:BOOL=%s" % ("+unit_tests" in spec), "-DLBANN_WITH_VISION:BOOL=%s" % ("+vision" in spec), @@ -424,6 +428,12 @@ def cmake_args(self): "-DHIP_CXX_COMPILER={0}".format(self.spec["hip"].hipcc), ] ) + if "platform=cray" in spec: + args.extend( + [ + "-DMPI_ASSUME_NO_BUILTIN_MPI=ON", + ] + ) archs = self.spec.variants["amdgpu_target"].value if archs != "none": arch_str = ",".join(archs) From a8c0a662a1950083d1fd6d00c798d3d0cb9219b7 Mon Sep 17 00:00:00 2001 From: "Adam J. Stewart" Date: Thu, 27 Oct 2022 15:02:46 -0500 Subject: [PATCH 237/442] py-torchdata: add v0.5.0 (#33568) --- var/spack/repos/builtin/packages/py-torchdata/package.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/var/spack/repos/builtin/packages/py-torchdata/package.py b/var/spack/repos/builtin/packages/py-torchdata/package.py index 939987b06ab..d61dbf97340 100644 --- a/var/spack/repos/builtin/packages/py-torchdata/package.py +++ b/var/spack/repos/builtin/packages/py-torchdata/package.py @@ -16,6 +16,7 @@ class PyTorchdata(PythonPackage): maintainers = ["adamjstewart"] version("main", branch="main") + version("0.5.0", sha256="b4e1a7015b34e3576111d495a00a675db238bfd136629fc443078bab9383ec36") version("0.4.1", sha256="71c0aa3aca3b04a986a2cd4cc2e0be114984ca836dc4def2c700bf1bd1ff087e") version("0.4.0", sha256="b4ec446a701680faa620fcb828b98ba36a63fa79da62a1e568d4a683889172da") version("0.3.0", sha256="ac36188bf133cf5f1041a28ccb3ee82ba52d4b5d99617be37d64d740acd6cfd4") @@ -23,6 +24,7 @@ class PyTorchdata(PythonPackage): # https://github.com/pytorch/data#version-compatibility depends_on("python@3.7:3.10", type=("build", "run")) depends_on("py-torch@master", when="@main", type=("build", "run")) + depends_on("py-torch@1.12.1", when="@0.5.0", type=("build", "run")) # ? depends_on("py-torch@1.12.1", when="@0.4.1", type=("build", "run")) depends_on("py-torch@1.12.0", when="@0.4.0", type=("build", "run")) depends_on("py-torch@1.11.0", when="@0.3.0", type=("build", "run")) From 600948558d9ca6e3fab958cc25e83c661f34e378 Mon Sep 17 00:00:00 2001 From: SoniaScard <83462318+SoniaScard@users.noreply.github.com> Date: Thu, 27 Oct 2022 22:42:58 +0200 Subject: [PATCH 238/442] ophidia-analytics-framework: new package at v1.7 (#33567) * ophidia-analytics-framework: new package at v1.7 * Fix code style in ophidia-analytics-framework Co-authored-by: SoniaScard Co-authored-by: Donatello Elia --- .../ophidia-analytics-framework/package.py | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 var/spack/repos/builtin/packages/ophidia-analytics-framework/package.py diff --git a/var/spack/repos/builtin/packages/ophidia-analytics-framework/package.py b/var/spack/repos/builtin/packages/ophidia-analytics-framework/package.py new file mode 100644 index 00000000000..26742143037 --- /dev/null +++ b/var/spack/repos/builtin/packages/ophidia-analytics-framework/package.py @@ -0,0 +1,49 @@ +# 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 OphidiaAnalyticsFramework(AutotoolsPackage): + """Core modules and operators of the Ophidia framework""" + + homepage = "https://github.com/OphidiaBigData/ophidia-analytics-framework" + url = "https://github.com/OphidiaBigData/ophidia-analytics-framework/archive/refs/tags/v1.7.1.tar.gz" + maintainers = ["eldoo", "SoniaScard"] + version( + "1.7.1", + sha256="565050b90ce1cefc59136c835a335ca7981fec792df7a1ee9309b24c05b275d6", + ) + + depends_on("autoconf", type="build") + depends_on("automake", type="build") + depends_on("libtool", type="build") + depends_on("m4", type="build") + depends_on("pkg-config", type="build") + + depends_on("gsl") + depends_on("mpich") + depends_on("jansson") + depends_on("libxml2") + depends_on("libssh2") + depends_on("openssl") + depends_on("mysql") + depends_on("netcdf-c") + depends_on("curl") + depends_on("ophidia-io-server") + + def autoreconf(self, spec, prefix): + autoreconf("--install", "--verbose", "--force") + + def configure_args(self): + args = [ + "--enable-parallel-netcdf", + "--with-web-server-path={0}/html".format( + self.spec["ophidia-analytics-framework"].prefix + ), + "--with-web-server-url=http://127.0.0.1/ophidia", + "--with-ophidiaio-server-path={0}".format(self.spec["ophidia-io-server"].prefix), + ] + return args From 3e966f254748d860655db952fe964eeca579b0ca Mon Sep 17 00:00:00 2001 From: Robert Cohn Date: Thu, 27 Oct 2022 17:01:59 -0400 Subject: [PATCH 239/442] support pkgconfig for mkl (#33382) --- var/spack/repos/builtin/packages/intel-oneapi-mkl/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/intel-oneapi-mkl/package.py b/var/spack/repos/builtin/packages/intel-oneapi-mkl/package.py index 0d227b39528..1952f35d154 100644 --- a/var/spack/repos/builtin/packages/intel-oneapi-mkl/package.py +++ b/var/spack/repos/builtin/packages/intel-oneapi-mkl/package.py @@ -129,6 +129,7 @@ def setup_run_environment(self, env): def setup_dependent_build_environment(self, env, dependent_spec): env.set("MKLROOT", self.component_prefix) + env.append_path("PKG_CONFIG_PATH", self.component_prefix.lib.pkgconfig) def _find_mkl_libs(self, shared): libs = [] From 67585fe13eb957e4722c72a66577625a593273aa Mon Sep 17 00:00:00 2001 From: rfbgo <109985755+rfbgo@users.noreply.github.com> Date: Thu, 27 Oct 2022 15:59:06 -0600 Subject: [PATCH 240/442] Add vasp variant to control shmem compile options (#33531) Currently the vasp package always enables the use of shmem to reduce algorithm memory usage (see https://www.vasp.at/wiki/index.php/Precompiler_options). This is great,but on some systems gives compile errors with the interoperability of C and Fortran. This PR makes that shmem flag optional, but retains the existing default on behavior. --- var/spack/repos/builtin/packages/vasp/package.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/vasp/package.py b/var/spack/repos/builtin/packages/vasp/package.py index 1706aa28439..eac1f0431ed 100644 --- a/var/spack/repos/builtin/packages/vasp/package.py +++ b/var/spack/repos/builtin/packages/vasp/package.py @@ -46,6 +46,8 @@ class Vasp(MakefilePackage): "https://github.com/henniggroup/VASPsol", ) + variant("shmem", default=True, description="Enable use_shmem build flag") + depends_on("rsync", type="build") depends_on("blas") depends_on("lapack") @@ -151,8 +153,11 @@ def setup_build_environment(self, spack_env): "-Davoidalloc", "-Duse_bse_te", "-Dtbdyn", - "-Duse_shmem", ] + + if "+shmem" in spec: + cpp_options.append("-Duse_shmem") + if "%nvhpc" in self.spec: cpp_options.extend(['-DHOST=\\"LinuxPGI\\"', "-DPGI16", "-Dqd_emulate"]) elif "%aocc" in self.spec: From bd51751a8c8c00e936c08b82af53bdd3ddd8a529 Mon Sep 17 00:00:00 2001 From: "Adam J. Stewart" Date: Thu, 27 Oct 2022 17:10:12 -0500 Subject: [PATCH 241/442] GDAL: multi-build system support (#33566) --- .../repos/builtin/packages/gdal/package.py | 117 +++++++++--------- 1 file changed, 61 insertions(+), 56 deletions(-) diff --git a/var/spack/repos/builtin/packages/gdal/package.py b/var/spack/repos/builtin/packages/gdal/package.py index c9b6f9bafd5..bf22b2d6305 100644 --- a/var/spack/repos/builtin/packages/gdal/package.py +++ b/var/spack/repos/builtin/packages/gdal/package.py @@ -6,11 +6,13 @@ import os import sys +from spack.build_systems.autotools import AutotoolsBuilder +from spack.build_systems.cmake import CMakeBuilder from spack.package import * from spack.util.environment import filter_system_paths -class Gdal(CMakePackage): +class Gdal(CMakePackage, AutotoolsPackage, PythonExtension): """GDAL: Geospatial Data Abstraction Library. GDAL is a translator library for raster and vector geospatial data formats that @@ -83,7 +85,9 @@ class Gdal(CMakePackage): default=False, description="Speed up computations related to the Thin Plate Spline transformer", ) - variant("arrow", default=False, when="@3.5:", description="Required for Arrow driver") + variant( + "arrow", default=False, when="build_system=cmake", description="Required for Arrow driver" + ) variant("blosc", default=False, when="@3.4:", description="Required for Zarr driver") variant("brunsli", default=True, when="@3.4:", description="Required for MRF driver") variant("bsb", default=False, when="@:2", description="Required for BSB driver") @@ -136,23 +140,41 @@ class Gdal(CMakePackage): "mrsid_lidar", default=False, when="@:3.4", description="Required for MrSID/MG4 driver" ) variant( - "mssql_ncli", default=False, when="@3.5:", description="Required for MSSQLSpatial driver" + "mssql_ncli", + default=False, + when="build_system=cmake", + description="Required for MSSQLSpatial driver", ) variant( - "mssql_odbc", default=False, when="@3.5:", description="Required for MSSQLSpatial driver" + "mssql_odbc", + default=False, + when="build_system=cmake", + description="Required for MSSQLSpatial driver", ) variant("mysql", default=False, description="Required for MySQL driver") variant("netcdf", default=False, description="Required for NetCDF driver") variant("odbc", default=False, description="Required for many OGR drivers") - variant("odbccpp", default=False, when="@3.5:", description="Required for SAP HANA driver") + variant( + "odbccpp", + default=False, + when="build_system=cmake", + description="Required for SAP HANA driver", + ) variant("ogdi", default=False, description="Required for OGDI driver") - variant("opencad", default=False, when="@3.5:", description="Required for CAD driver") + variant( + "opencad", default=False, when="build_system=cmake", description="Required for CAD driver" + ) variant("opencl", default=False, description="Required to accelerate warping computations") variant("openexr", default=False, when="@3.1:", description="Required for EXR driver") variant("openjpeg", default=False, description="Required for JP2OpenJPEG driver") variant("openssl", default=False, when="@2.3:", description="Required for EEDAI driver") variant("oracle", default=False, description="Required for OCI and GeoRaster drivers") - variant("parquet", default=False, when="@3.5:", description="Required for Parquet driver") + variant( + "parquet", + default=False, + when="build_system=cmake", + description="Required for Parquet driver", + ) variant("pcidsk", default=False, description="Required for PCIDSK driver") variant( "pcre", default=False, description="Required for REGEXP operator in drivers using SQLite3" @@ -194,14 +216,25 @@ class Gdal(CMakePackage): # Language bindings variant("python", default=False, description="Build Python bindings") variant("java", default=False, description="Build Java bindings") - variant("csharp", default=False, when="@3.5:", description="Build C# bindings") + variant("csharp", default=False, when="build_system=cmake", description="Build C# bindings") variant("perl", default=False, when="@:3.4", description="Build Perl bindings") variant("php", default=False, when="@:2.3", description="Build PHP bindings") + # Build system + build_system( + conditional("cmake", when="@3.5:"), + conditional("autotools", when="@:3.5"), + default="cmake", + ) + + with when("build_system=cmake"): + depends_on("cmake@3.9:", type="build") + depends_on("ninja", type="build") + + with when("build_system=autotools"): + depends_on("gmake", type="build") + # Required dependencies - depends_on("cmake@3.9:", when="@3.5:", type="build") - depends_on("ninja", when="@3.5:", type="build") - depends_on("gmake", when="@:3.4", type="build") depends_on("pkgconfig@0.25:", type="build") depends_on("proj@6:", when="@3:") depends_on("proj@:6", when="@2.5:2") @@ -392,30 +425,12 @@ class Gdal(CMakePackage): sha256="9f9824296e75b34b3e78284ec772a5ac8f8ba92c17253ea9ca242caf766767ce", ) - generator = "Ninja" executables = ["^gdal-config$"] @classmethod def determine_version(cls, exe): return Executable(exe)("--version", output=str, error=str).rstrip() - @property - def import_modules(self): - modules = ["osgeo"] - if self.spec.satisfies("@3.3:"): - modules.append("osgeo_utils") - else: - modules.append("osgeo.utils") - return modules - - @when("@:3.4") - def setup_build_environment(self, env): - # Needed to install Python bindings to GDAL installation - # prefix instead of Python installation prefix. - # See swig/python/GNUmakefile for more details. - env.set("PREFIX", self.prefix) - env.set("DESTDIR", "/") - def setup_run_environment(self, env): if "+java" in self.spec: class_paths = find(self.prefix, "*.jar") @@ -437,6 +452,10 @@ def patch(self): if "+java platform=darwin" in self.spec: filter_file("linux", "darwin", "swig/java/java.opt", string=True) + +class CMakeBuilder(CMakeBuilder): + generator = "Ninja" + def cmake_args(self): # https://gdal.org/build_hints.html args = [ @@ -528,11 +547,20 @@ def cmake_args(self): return args + +class AutotoolsBuilder(AutotoolsBuilder): + def setup_build_environment(self, env): + # Needed to install Python bindings to GDAL installation + # prefix instead of Python installation prefix. + # See swig/python/GNUmakefile for more details. + env.set("PREFIX", self.prefix) + env.set("DESTDIR", "/") + def with_or_without(self, name, variant=None, package=None, attribute=None): if not variant: variant = name - if variant not in self.variants: + if variant not in self.pkg.variants: msg = '"{}" is not a variant of "{}"' raise KeyError(msg.format(variant, self.name)) @@ -684,49 +712,26 @@ def configure_args(self): return args - @when("@:3.4") - def cmake(self, spec, prefix): - configure(*self.configure_args()) - - @when("@:3.4") - def build(self, spec, prefix): + def build(self, pkg, spec, prefix): # https://trac.osgeo.org/gdal/wiki/GdalOgrInJavaBuildInstructionsUnix make() if "+java" in spec: with working_dir("swig/java"): make() - @when("@:3.4") def check(self): # no top-level test target if "+java" in self.spec: with working_dir("swig/java"): make("test") - @when("@:3.4") - def install(self, spec, prefix): + def install(self, pkg, spec, prefix): make("install") if "+java" in spec: with working_dir("swig/java"): make("install") install("*.jar", prefix) - @run_after("install") - def darwin_fix(self): # The shared library is not installed correctly on Darwin; fix this - if self.spec.satisfies("@:3.4 platform=darwin"): + if self.spec.satisfies("platform=darwin"): fix_darwin_install_name(self.prefix.lib) - - def test(self): - """Attempts to import modules of the installed package.""" - - if "+python" in self.spec: - # Make sure we are importing the installed modules, - # not the ones in the source directory - for module in self.import_modules: - self.run_test( - self.spec["python"].command.path, - ["-c", "import {0}".format(module)], - purpose="checking import of {0}".format(module), - work_dir="spack-test", - ) From 3ad0952956068e7bbd61fa70fa479d6f5fdd948b Mon Sep 17 00:00:00 2001 From: Diego Alvarez Date: Thu, 27 Oct 2022 19:41:49 -0300 Subject: [PATCH 242/442] nextflow: add 22.10.1 (#33574) * Add nextflow 22.10.1 * Add trailing comma (style) --- var/spack/repos/builtin/packages/nextflow/package.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/var/spack/repos/builtin/packages/nextflow/package.py b/var/spack/repos/builtin/packages/nextflow/package.py index 1f73765830b..04b2e84ae69 100644 --- a/var/spack/repos/builtin/packages/nextflow/package.py +++ b/var/spack/repos/builtin/packages/nextflow/package.py @@ -14,6 +14,11 @@ class Nextflow(Package): maintainers = ["dialvarezs"] + version( + "22.10.1", + sha256="fa6b6faa8b213860212da413e77141a56a5e128662d21ea6603aeb9717817c4c", + expand=False, + ) version( "22.10.0", sha256="6acea8bd21f7f66b1363eef900cd696d9523d2b9edb53327940f093189c1535e", From b81b54a74c4beb4cb76657cbabd3cf81b60ad89a Mon Sep 17 00:00:00 2001 From: "Adam J. Stewart" Date: Thu, 27 Oct 2022 20:49:43 -0500 Subject: [PATCH 243/442] py-scikit-learn: add v1.1.3 (#33534) --- var/spack/repos/builtin/packages/py-scikit-learn/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/py-scikit-learn/package.py b/var/spack/repos/builtin/packages/py-scikit-learn/package.py index cf91f792914..771e409a6a2 100644 --- a/var/spack/repos/builtin/packages/py-scikit-learn/package.py +++ b/var/spack/repos/builtin/packages/py-scikit-learn/package.py @@ -16,6 +16,7 @@ class PyScikitLearn(PythonPackage): maintainers = ["adamjstewart"] version("master", branch="master") + version("1.1.3", sha256="bef51978a51ec19977700fe7b86aecea49c825884f3811756b74a3b152bb4e35") version("1.1.2", sha256="7c22d1305b16f08d57751a4ea36071e2215efb4c09cb79183faa4e8e82a3dbf8") version("1.1.1", sha256="3e77b71e8e644f86c8b5be7f1c285ef597de4c384961389ee3e9ca36c445b256") version("1.1.0", sha256="80f9904f5b1356adfc32406725dd94c8cc9c8d265047d98390033a6c238cbb29") From d4a0f588e98d945a4be0bb5b388bad8797425766 Mon Sep 17 00:00:00 2001 From: Chris White Date: Thu, 27 Oct 2022 23:04:18 -0700 Subject: [PATCH 244/442] CachedCMakePackage: Add back initconfig as a defined phase (#33575) Also: add type annotation to indicate that "phases" is always a tuple of strings. --- lib/spack/spack/build_systems/cached_cmake.py | 7 +++++-- lib/spack/spack/build_systems/cmake.py | 2 +- lib/spack/spack/builder.py | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/spack/spack/build_systems/cached_cmake.py b/lib/spack/spack/build_systems/cached_cmake.py index 7caf2a15397..84f402299ad 100644 --- a/lib/spack/spack/build_systems/cached_cmake.py +++ b/lib/spack/spack/build_systems/cached_cmake.py @@ -32,6 +32,10 @@ def cmake_cache_option(name, boolean_value, comment=""): class CachedCMakeBuilder(CMakeBuilder): + #: Phases of a Cached CMake package + #: Note: the initconfig phase is used for developer builds as a final phase to stop on + phases = ("initconfig", "cmake", "build", "install") # type: Tuple[str, ...] + #: Names associated with package methods in the old build-system format legacy_methods = CMakeBuilder.legacy_methods + ( "initconfig_compiler_entries", @@ -224,8 +228,7 @@ def initconfig_package_entries(self): """This method is to be overwritten by the package""" return [] - @spack.builder.run_before("cmake") - def initconfig(self): + def initconfig(self, pkg, spec, prefix): cache_entries = ( self.std_initconfig_entries() + self.initconfig_compiler_entries() diff --git a/lib/spack/spack/build_systems/cmake.py b/lib/spack/spack/build_systems/cmake.py index 8d8bba47781..1d0c50ea078 100644 --- a/lib/spack/spack/build_systems/cmake.py +++ b/lib/spack/spack/build_systems/cmake.py @@ -155,7 +155,7 @@ class CMakeBuilder(BaseBuilder): """ #: Phases of a CMake package - phases = ("cmake", "build", "install") + phases = ("cmake", "build", "install") # type: Tuple[str, ...] #: Names associated with package methods in the old build-system format legacy_methods = ("cmake_args", "check") # type: Tuple[str, ...] diff --git a/lib/spack/spack/builder.py b/lib/spack/spack/builder.py index 6baa321eea1..7ae36b6e0a2 100644 --- a/lib/spack/spack/builder.py +++ b/lib/spack/spack/builder.py @@ -469,7 +469,7 @@ class Builder(six.with_metaclass(BuilderMeta, llnl.util.compat.Sequence)): """ #: Sequence of phases. Must be defined in derived classes - phases = None # type: Optional[Tuple[str, ...]] + phases = () # type: Tuple[str, ...] #: Build system name. Must also be defined in derived classes. build_system = None # type: Optional[str] From 0896bf928b7925ddf63bd320daaf8b94b2c9d96b Mon Sep 17 00:00:00 2001 From: eugeneswalker <38933153+eugeneswalker@users.noreply.github.com> Date: Fri, 28 Oct 2022 01:05:59 -0700 Subject: [PATCH 245/442] openblas %oneapi: extend application of --Wno-error=implicit-function-declaration (#33576) --- var/spack/repos/builtin/packages/openblas/package.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/openblas/package.py b/var/spack/repos/builtin/packages/openblas/package.py index 0b8d7591f9d..692718e6cce 100644 --- a/var/spack/repos/builtin/packages/openblas/package.py +++ b/var/spack/repos/builtin/packages/openblas/package.py @@ -196,7 +196,7 @@ def flag_handler(self, name, flags): spec = self.spec iflags = [] if name == "cflags": - if spec.satisfies("@0.3.20 %oneapi"): + if spec.satisfies("@0.3.20: %oneapi"): iflags.append("-Wno-error=implicit-function-declaration") return (iflags, None, None) From 21e826f25610d536288d3630e22c34a28b2a6fd9 Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Fri, 28 Oct 2022 11:15:06 +0200 Subject: [PATCH 246/442] patchelf: add v0.16.1 (#33579) --- var/spack/repos/builtin/packages/patchelf/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/patchelf/package.py b/var/spack/repos/builtin/packages/patchelf/package.py index a19eb4d0ed3..ce1549b5aa0 100644 --- a/var/spack/repos/builtin/packages/patchelf/package.py +++ b/var/spack/repos/builtin/packages/patchelf/package.py @@ -18,6 +18,7 @@ class Patchelf(AutotoolsPackage): maintainers = ["haampie"] + version("0.16.1", sha256="1a562ed28b16f8a00456b5f9ee573bb1af7c39c1beea01d94fc0c7b3256b0406") version("0.15.0", sha256="53a8d58ed4e060412b8fdcb6489562b3c62be6f65cee5af30eba60f4423bfa0f") version("0.14.5", sha256="113ada3f1ace08f0a7224aa8500f1fa6b08320d8f7df05ff58585286ec5faa6f") version("0.14.3", sha256="8fabf4210499744ced101612cd5c9fd12b94af67a16297cb5d3ff682c007ffdb") From fa0432c521c40135216ae57f3e92576dd8ab433c Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Fri, 28 Oct 2022 14:38:57 +0200 Subject: [PATCH 247/442] gitlab ci: patched make 4.3.0 (#33583) --- .../gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml | 4 ++-- share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml | 4 ++-- .../gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml | 4 ++-- share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml | 4 ++-- .../gitlab/cloud_pipelines/stacks/build_systems/spack.yaml | 4 ++-- .../gitlab/cloud_pipelines/stacks/data-vis-sdk/spack.yaml | 4 ++-- .../gitlab/cloud_pipelines/stacks/e4s-on-power/spack.yaml | 4 +++- .../spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml | 4 ++-- share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml | 4 ++-- share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml | 4 ++-- share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml | 4 ++-- share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml | 4 ++-- .../cloud_pipelines/stacks/radiuss-aws-aarch64/spack.yaml | 4 ++-- .../gitlab/cloud_pipelines/stacks/radiuss-aws/spack.yaml | 4 ++-- share/spack/gitlab/cloud_pipelines/stacks/radiuss/spack.yaml | 4 ++-- share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml | 4 ++-- 16 files changed, 33 insertions(+), 31 deletions(-) diff --git a/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml index c48a20e9050..2449ebb23db 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml @@ -245,8 +245,8 @@ spack: script: - uname -a || true - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true - - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.aarch64-linux-gnu.tar.gz -o gmake.tar.gz - - printf 'deb1dcae0eecdc7fce2902f294012ab5519629e6827204f1b9964dcfd3f74627 gmake.tar.gz' | sha256sum --check --strict --quiet + - curl -Lfs 'https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0+1/GNUMake.v4.3.0.aarch64-linux-gnu.tar.gz' -o gmake.tar.gz + - printf '2322c175fb092b426f9eb6c24ee22d94ffa6759c3d0c260b74d81abd8120122b gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version diff --git a/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml index 60f980ddad5..32fb38a360f 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml @@ -242,8 +242,8 @@ spack: script: - uname -a || true - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true - - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet + - curl -Lfs 'https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0+1/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz' -o gmake.tar.gz + - printf 'fef1f59e56d2d11e6d700ba22d3444b6e583c663d6883fd0a4f63ab8bd280f0f gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version diff --git a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml index 41c6f5bdda0..5308ed359e4 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml @@ -152,8 +152,8 @@ spack: script: - uname -a || true - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true - - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.aarch64-linux-gnu.tar.gz -o gmake.tar.gz - - printf 'deb1dcae0eecdc7fce2902f294012ab5519629e6827204f1b9964dcfd3f74627 gmake.tar.gz' | sha256sum --check --strict --quiet + - curl -Lfs 'https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0+1/GNUMake.v4.3.0.aarch64-linux-gnu.tar.gz' -o gmake.tar.gz + - printf '2322c175fb092b426f9eb6c24ee22d94ffa6759c3d0c260b74d81abd8120122b gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version diff --git a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml index 75d6efe8aae..4a4f60ca85b 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml @@ -163,8 +163,8 @@ spack: script: - uname -a || true - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true - - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet + - curl -Lfs 'https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0+1/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz' -o gmake.tar.gz + - printf 'fef1f59e56d2d11e6d700ba22d3444b6e583c663d6883fd0a4f63ab8bd280f0f gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version diff --git a/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml index b7e048181d6..0d75670f2be 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml @@ -36,8 +36,8 @@ spack: script: - uname -a || true - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true - - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet + - curl -Lfs 'https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0+1/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz' -o gmake.tar.gz + - printf 'fef1f59e56d2d11e6d700ba22d3444b6e583c663d6883fd0a4f63ab8bd280f0f gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version diff --git a/share/spack/gitlab/cloud_pipelines/stacks/data-vis-sdk/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/data-vis-sdk/spack.yaml index 0a6e18c84b4..831125e3be7 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/data-vis-sdk/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/data-vis-sdk/spack.yaml @@ -49,8 +49,8 @@ spack: script: - uname -a || true - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true - - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet + - curl -Lfs 'https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0+1/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz' -o gmake.tar.gz + - printf 'fef1f59e56d2d11e6d700ba22d3444b6e583c663d6883fd0a4f63ab8bd280f0f gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version diff --git a/share/spack/gitlab/cloud_pipelines/stacks/e4s-on-power/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/e4s-on-power/spack.yaml index 508de2b0522..d0f7074eeed 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/e4s-on-power/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/e4s-on-power/spack.yaml @@ -216,7 +216,9 @@ spack: script: - uname -a || true - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true - - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.powerpc64le-linux-gnu.tar.gz | tar -xzf - -C /usr 2> /dev/null + - curl -Lfs 'https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0+1/GNUMake.v4.3.0.powerpc64le-linux-gnu.tar.gz' -o gmake.tar.gz + - printf '8096d202fe0a0c400b8c0573c4b9e009f2f10d2fa850a3f495340f16e9c42454 gmake.tar.gz' | sha256sum --check --strict --quiet + - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version - spack arch diff --git a/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml index 46499e2a425..3fe66c48e5d 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml @@ -268,8 +268,8 @@ spack: script: - uname -a || true - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true - - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet + - curl -Lfs 'https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0+1/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz' -o gmake.tar.gz + - printf 'fef1f59e56d2d11e6d700ba22d3444b6e583c663d6883fd0a4f63ab8bd280f0f gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version diff --git a/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml index 9e1fb6f5bc0..d56a8eaa374 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml @@ -257,8 +257,8 @@ spack: script: - uname -a || true - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true - - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet + - curl -Lfs 'https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0+1/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz' -o gmake.tar.gz + - printf 'fef1f59e56d2d11e6d700ba22d3444b6e583c663d6883fd0a4f63ab8bd280f0f gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version diff --git a/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml index 72c9f14893b..a03ecbae699 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml @@ -89,8 +89,8 @@ spack: script: - uname -a || true - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true - - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet + - curl -Lfs 'https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0+1/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz' -o gmake.tar.gz + - printf 'fef1f59e56d2d11e6d700ba22d3444b6e583c663d6883fd0a4f63ab8bd280f0f gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version diff --git a/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml index 885870b6ac4..ada465fd1a0 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml @@ -92,8 +92,8 @@ spack: script: - uname -a || true - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true - - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet + - curl -Lfs 'https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0+1/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz' -o gmake.tar.gz + - printf 'fef1f59e56d2d11e6d700ba22d3444b6e583c663d6883fd0a4f63ab8bd280f0f gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version diff --git a/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml index 719526d4f96..bbc6159f591 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml @@ -95,8 +95,8 @@ spack: script: - uname -a || true - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true - - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet + - curl -Lfs 'https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0+1/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz' -o gmake.tar.gz + - printf 'fef1f59e56d2d11e6d700ba22d3444b6e583c663d6883fd0a4f63ab8bd280f0f gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version diff --git a/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws-aarch64/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws-aarch64/spack.yaml index a9e70f76d2f..2de97c89963 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws-aarch64/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws-aarch64/spack.yaml @@ -58,8 +58,8 @@ spack: script: - uname -a || true - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true - - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.aarch64-linux-gnu.tar.gz -o gmake.tar.gz - - printf 'deb1dcae0eecdc7fce2902f294012ab5519629e6827204f1b9964dcfd3f74627 gmake.tar.gz' | sha256sum --check --strict --quiet + - curl -Lfs 'https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0+1/GNUMake.v4.3.0.aarch64-linux-gnu.tar.gz' -o gmake.tar.gz + - printf '2322c175fb092b426f9eb6c24ee22d94ffa6759c3d0c260b74d81abd8120122b gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version diff --git a/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws/spack.yaml index b8f9e96a0e3..0c80154af83 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws/spack.yaml @@ -63,8 +63,8 @@ spack: script: - uname -a || true - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true - - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet + - curl -Lfs 'https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0+1/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz' -o gmake.tar.gz + - printf 'fef1f59e56d2d11e6d700ba22d3444b6e583c663d6883fd0a4f63ab8bd280f0f gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version diff --git a/share/spack/gitlab/cloud_pipelines/stacks/radiuss/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/radiuss/spack.yaml index 379aeba29f6..ef8696a4b64 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/radiuss/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/radiuss/spack.yaml @@ -66,8 +66,8 @@ spack: script: - uname -a || true - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true - - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet + - curl -Lfs 'https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0+1/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz' -o gmake.tar.gz + - printf 'fef1f59e56d2d11e6d700ba22d3444b6e583c663d6883fd0a4f63ab8bd280f0f gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version diff --git a/share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml index 659ab887423..2f229962c9c 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml @@ -67,8 +67,8 @@ spack: script: - uname -a || true - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true - - curl -Lfs https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0%2B0/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz -o gmake.tar.gz - - printf 'b019c4aa757503d442c906047f6b1c393bf8eeba71260d455537cfc708862249 gmake.tar.gz' | sha256sum --check --strict --quiet + - curl -Lfs 'https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0+1/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz' -o gmake.tar.gz + - printf 'fef1f59e56d2d11e6d700ba22d3444b6e583c663d6883fd0a4f63ab8bd280f0f gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null - . "./share/spack/setup-env.sh" - spack --version From c772b662c90ca0939841d4fc7ba9eb561348b37a Mon Sep 17 00:00:00 2001 From: Vasileios Karakasis Date: Fri, 28 Oct 2022 16:38:29 +0200 Subject: [PATCH 248/442] ReFrame: add versions up to v3.12.0 (#33446) Also adds 4.0 dev versions --- var/spack/repos/builtin/packages/reframe/package.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/var/spack/repos/builtin/packages/reframe/package.py b/var/spack/repos/builtin/packages/reframe/package.py index 90bbb503f98..f2de9f7c2a0 100644 --- a/var/spack/repos/builtin/packages/reframe/package.py +++ b/var/spack/repos/builtin/packages/reframe/package.py @@ -24,6 +24,19 @@ class Reframe(Package): maintainers = ["victorusu", "vkarak"] version("master", branch="master") + version( + "4.0.0-dev.1", sha256="6db55c20b79764fc1f0e0a13de062850007425fa2c7f54a113b96adee50741ed" + ) + version( + "4.0.0-dev.0", sha256="a96162a88a36ea0793836c492a39470010f6e63b8d9bd324c033614d27304fa6" + ) + version( + "3.12.0", + sha256="425cc546e24edd5b2dbfcdcb61dbbf723ca1a2a2977948e359e893514f5eb10f", + preferred=True, + ) + version("3.11.2", sha256="d6f36071df316d6a5ef5ce6f0477b3385d9dac5c1b82e54ae6954dc9b68f9440") + version("3.11.1", sha256="7f591cd8f4fbb2c6255cc8ea02e3814393355a8931ac883e9f57490fde699b63") version("3.11.0", sha256="3ddfef5482f0c304286a6c8f1ad0b3d75c4c61d0b9f9f8429b6157c189f2bb64") version("3.10.1", sha256="5fd649872bf93ba72a835896ea1a581b9b8c3e04150247be2359b95a7cdb89b5") version("3.10.0", sha256="b137f034be09abcf1bb8c3ceaf1a00d9c22c51c10738312eccf12c1c3e04b9ef") From b89f6226f822b8369fff03d5dce0a6d8fb9f97c2 Mon Sep 17 00:00:00 2001 From: Lucas Nesi Date: Fri, 28 Oct 2022 16:43:45 +0200 Subject: [PATCH 249/442] starpu: add papi and blocking variants (#33580) --- var/spack/repos/builtin/packages/starpu/package.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/var/spack/repos/builtin/packages/starpu/package.py b/var/spack/repos/builtin/packages/starpu/package.py index db0b372be5a..b0158964abd 100644 --- a/var/spack/repos/builtin/packages/starpu/package.py +++ b/var/spack/repos/builtin/packages/starpu/package.py @@ -69,6 +69,8 @@ class Starpu(AutotoolsPackage): variant("simgrid", default=False, description="Enable SimGrid support") variant("simgridmc", default=False, description="Enable SimGrid model checker support") variant("examples", default=True, description="Enable Examples") + variant("papi", default=False, description="Enable PAPI support", when="@master:") + variant("blocking", default=False, description="Enable blocking drivers support") depends_on("pkgconfig", type="build") depends_on("autoconf", type="build") @@ -84,11 +86,14 @@ class Starpu(AutotoolsPackage): depends_on("simgrid", when="+simgrid") depends_on("simgrid+smpi", when="+simgrid+mpi") depends_on("simgrid+mc", when="+simgridmc") + depends_on("papi", when="+papi") conflicts( "+shared", when="+mpi+simgrid", msg="Simgrid MPI cannot be built with a shared library" ) + conflicts("+papi", when="+simgrid") + def autoreconf(self, spec, prefix): if not os.path.isfile("./configure"): autogen = Executable("./autogen.sh") @@ -125,6 +130,8 @@ def configure_args(self): "--%s-build-examples" % ("enable" if "+examples" in spec else "disable"), "--%s-fortran" % ("enable" if "+fortran" in spec else "disable"), "--%s-openmp" % ("enable" if "+openmp" in spec else "disable"), + "--%s-blocking-drivers" % ("enable" if "+blocking" in spec else "disable"), + "--%s-papi" % ("enable" if "+papi" in spec else "disable"), "--%s-opencl" % ("disable" if "~opencl" in spec or "+simgrid" in spec else "enable"), "--%s-cuda" % ("disable" if "~cuda" in spec or "+simgrid" in spec else "enable"), From f74a6a4503a35aeb0f024edb71dfe78c54cb336e Mon Sep 17 00:00:00 2001 From: Satish Balay Date: Fri, 28 Oct 2022 11:13:51 -0500 Subject: [PATCH 250/442] netlib-scalapack: fix build error with oneapi compilers (#33539) /home/xsdk/spack.x/lib/spack/env/oneapi/icx -DAdd_ -Dscalapack_EXPORTS -I/opt/intel/oneapi/mpi/2021.7.0/include -O3 -DNDEBUG -fPIC -MD -MT CMakeFiles/scalapack.dir/BLACS/SRC/dgamx2d_.c.o -MF CMakeFiles/scalapack.dir/BLACS/SRC/dgamx2d_.c.o.d -o CMakeFiles/scalapack.dir/BLACS/SRC/dgamx2d_.c.o -c /home/xsdk/spack.x/spack-stage/spack-stage-netlib-scalapack-2.2.0-uj3jepiowz5is4hmdmjrzjltetgdr3lx/spack-src/BLACS/SRC/dgamx2d_.c /home/xsdk/spack.x/spack-stage/spack-stage-netlib-scalapack-2.2.0-uj3jepiowz5is4hmdmjrzjltetgdr3lx/spack-src/BLACS/SRC/igsum2d_.c:154:7: error: call to undeclared function 'BI_imvcopy'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration] BI_imvcopy(Mpval(m), Mpval(n), A, tlda, bp->Buff); ^ --- var/spack/repos/builtin/packages/netlib-scalapack/package.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/netlib-scalapack/package.py b/var/spack/repos/builtin/packages/netlib-scalapack/package.py index 66c8ffe04ad..e0becba3b90 100644 --- a/var/spack/repos/builtin/packages/netlib-scalapack/package.py +++ b/var/spack/repos/builtin/packages/netlib-scalapack/package.py @@ -87,7 +87,7 @@ def cmake_args(self): # Work around errors of the form: # error: implicit declaration of function 'BI_smvcopy' is # invalid in C99 [-Werror,-Wimplicit-function-declaration] - if spec.satisfies("%clang") or spec.satisfies("%apple-clang"): + if spec.satisfies("%clang") or spec.satisfies("%apple-clang") or spec.satisfies("%oneapi"): c_flags.append("-Wno-error=implicit-function-declaration") options.append(self.define("CMAKE_C_FLAGS", " ".join(c_flags))) From 04f87da36b1bd82c6245b3827bf09a5e65d70ecf Mon Sep 17 00:00:00 2001 From: Luke Diorio-Toth Date: Fri, 28 Oct 2022 14:05:15 -0500 Subject: [PATCH 251/442] new packages (py-auditwheel, py-medaka, py-parasail, py-progressbar33, py-pyspoa) and updates to others (py-scikit-build, py-ont-fast5-api) (#33541) * Added py-medaka and dependencies * fixed py-parasail build error * medaka still doesn't have correct linked libdeflate * fixed pyspoa deps * added htslib.patch, confirmed builds and runs * fixed style * Update var/spack/repos/builtin/packages/py-auditwheel/package.py Co-authored-by: Adam J. Stewart * made requested changes * added targets for pyspoa dep Co-authored-by: Adam J. Stewart --- .../builtin/packages/py-auditwheel/package.py | 23 ++++++++++ .../builtin/packages/py-medaka/htslib.patch | 34 +++++++++++++++ .../builtin/packages/py-medaka/package.py | 43 +++++++++++++++++++ .../packages/py-ont-fast5-api/package.py | 6 +++ .../builtin/packages/py-parasail/package.py | 27 ++++++++++++ .../packages/py-progressbar33/package.py | 18 ++++++++ .../builtin/packages/py-pyspoa/package.py | 20 +++++++++ .../packages/py-scikit-build/package.py | 1 + 8 files changed, 172 insertions(+) create mode 100644 var/spack/repos/builtin/packages/py-auditwheel/package.py create mode 100644 var/spack/repos/builtin/packages/py-medaka/htslib.patch create mode 100644 var/spack/repos/builtin/packages/py-medaka/package.py create mode 100644 var/spack/repos/builtin/packages/py-parasail/package.py create mode 100644 var/spack/repos/builtin/packages/py-progressbar33/package.py create mode 100644 var/spack/repos/builtin/packages/py-pyspoa/package.py diff --git a/var/spack/repos/builtin/packages/py-auditwheel/package.py b/var/spack/repos/builtin/packages/py-auditwheel/package.py new file mode 100644 index 00000000000..ad5936f292d --- /dev/null +++ b/var/spack/repos/builtin/packages/py-auditwheel/package.py @@ -0,0 +1,23 @@ +# 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 PyAuditwheel(PythonPackage): + """Auditing and relabeling of PEP 600 manylinux_x_y, PEP 513 manylinux1, + PEP 571 manylinux2010 and PEP 599 manylinux2014 Linux wheels.""" + + homepage = "https://github.com/pypa/auditwheel" + pypi = "auditwheel/auditwheel-5.1.2.tar.gz" + + version("5.1.2", sha256="3ee5830014931ea84af5cd065c637b6614efa03d9b88bd8fbfc924e7ed01d6ba") + + depends_on("python@3.6:", type=("build", "run")) + depends_on("py-setuptools@45:", type="build") + depends_on("py-setuptools-scm@6.2:", type="build") + depends_on("py-pyelftools@0.24:", type=("build", "run")) + depends_on("py-importlib-metadata", when="^python@:3.7", type=("build", "run")) diff --git a/var/spack/repos/builtin/packages/py-medaka/htslib.patch b/var/spack/repos/builtin/packages/py-medaka/htslib.patch new file mode 100644 index 00000000000..2c500f8866b --- /dev/null +++ b/var/spack/repos/builtin/packages/py-medaka/htslib.patch @@ -0,0 +1,34 @@ +# patch method copied from bioconda recipe +# github.com/bioconda/bioconda-recipes/blob/master/recipes/medaka/build.sh +diff -Naur spack-src/setup.py spack-src.patched/setup.py +--- spack-src/setup.py 2022-10-26 16:10:27.824793639 -0500 ++++ spack-src.patched/setup.py 2022-10-26 16:16:57.815324146 -0500 +@@ -144,6 +144,6 @@ + 'scripts/mini_align', 'scripts/hdf2tf.py'], + zip_safe=False, + cmdclass={ +- 'build_ext': HTSBuild ++ + }, + ) +diff -Naur spack-src/build.py spack-src.patched/build.py +--- spack-src/build.py 2022-10-26 16:15:35.891735658 -0500 ++++ spack-src.patched/build.py 2022-10-26 16:18:42.468243578 -0500 +@@ -12,7 +12,7 @@ + deflatever = "1.10" + deflate_dir = os.path.join(dir_path, 'submodules', 'libdeflate-{}'.format(deflatever)) + +-libraries=['m', 'z', 'lzma', 'bz2', 'pthread', 'curl', 'crypto'] ++libraries=["hts",'m', 'z', 'lzma', 'bz2', 'pthread', 'curl', 'crypto'] + library_dirs=[htslib_dir] + if os.getenv('WITHDEFLATE') == "1": + print("Using deflate") +@@ -52,7 +52,7 @@ + 'fastrle.c', 'medaka_trimbam.c', 'medaka_pytrimbam.c', + 'medaka_rnn_variants.c')], + extra_compile_args=extra_compile_args, +- extra_objects=['libhts.a'] ++ + ) + + cdef = [ diff --git a/var/spack/repos/builtin/packages/py-medaka/package.py b/var/spack/repos/builtin/packages/py-medaka/package.py new file mode 100644 index 00000000000..03ff3ccd80b --- /dev/null +++ b/var/spack/repos/builtin/packages/py-medaka/package.py @@ -0,0 +1,43 @@ +# 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 PyMedaka(PythonPackage): + """medaka is a tool to create consensus sequences and variant calls from + nanopore sequencing data. This task is performed using neural networks + applied a pileup of individual sequencing reads against a draft assembly. + It provides state-of-the-art results outperforming sequence-graph based + methods and signal-based methods, whilst also being faster.""" + + homepage = "https://github.com/nanoporetech/medaka" + pypi = "medaka/medaka-1.7.2.tar.gz" + + version("1.7.2", sha256="7629546ed9193ffb6b1f881a6ce74b7d13d94972e032556098577ddb43bee763") + + # disable Makefile driven build of htslib and link to system htslib instead + patch("htslib.patch", when="@1.7.2") + + depends_on("python@3.6:3.9", type=("build", "run")) + depends_on("py-setuptools", type="build") + depends_on("py-cffi@1.15.0", type=("build", "run")) + depends_on("py-edlib", type=("build", "run")) + depends_on("py-grpcio", type=("build", "run")) + depends_on("py-h5py", type=("build", "run")) + depends_on("py-intervaltree", type=("build", "run")) + depends_on("py-tensorflow@2.7.0:2.7", type=("build", "run")) + depends_on("py-numpy", type=("build", "run")) + depends_on("minimap2", type=("build", "run")) + depends_on("py-ont-fast5-api", type=("build", "run")) + depends_on("py-parasail", when="target=x86_64:", type=("build", "run")) + depends_on("py-parasail", when="target=ppc64le:", type=("build", "run")) + depends_on("py-pysam@0.16.0.1:", type=("build", "run")) + depends_on("py-pyspoa@0.0.3:", when="target=x86_64:", type=("build", "run")) + depends_on("py-pyspoa@0.0.3:", when="target=ppc64le:", type=("build", "run")) + depends_on("py-requests", type=("build", "run")) + depends_on("samtools", type=("build", "run")) + depends_on("htslib", type=("build", "run", "link")) diff --git a/var/spack/repos/builtin/packages/py-ont-fast5-api/package.py b/var/spack/repos/builtin/packages/py-ont-fast5-api/package.py index 3e96ca254db..730e4b8b63a 100644 --- a/var/spack/repos/builtin/packages/py-ont-fast5-api/package.py +++ b/var/spack/repos/builtin/packages/py-ont-fast5-api/package.py @@ -17,8 +17,14 @@ class PyOntFast5Api(PythonPackage): homepage = "https://github.com/nanoporetech/ont_fast5_api" pypi = "ont-fast5-api/ont-fast5-api-0.3.2.tar.gz" + version("4.1.0", sha256="afa58fb0a73ac33161fe0d13d32698b3325756c370f2f440a8a43b4b68c75f32") version("0.3.2", sha256="ae44b1bcd812e8acf8beff3db92456647c343cf19340f97cff4847de5cc905d8") + depends_on("python@3.6:", type=("build", "run"), when="@4:") depends_on("py-setuptools", type="build") depends_on("py-h5py", type=("build", "run")) + depends_on("py-h5py@2.10:", type=("build", "run"), when="@4.0.1:") depends_on("py-numpy@1.8.1:", type=("build", "run")) + depends_on("py-numpy@1.16:", type=("build", "run"), when="@3.2.0:") + depends_on("py-packaging", type=("build", "run"), when="@3.0.2:") + depends_on("py-progressbar33@2.3.1:", type=("build", "run"), when="@1.0.1:") diff --git a/var/spack/repos/builtin/packages/py-parasail/package.py b/var/spack/repos/builtin/packages/py-parasail/package.py new file mode 100644 index 00000000000..ea65f9efab0 --- /dev/null +++ b/var/spack/repos/builtin/packages/py-parasail/package.py @@ -0,0 +1,27 @@ +# 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 PyParasail(PythonPackage): + """Python Bindings for the Parasail C Library. Parasail is a SIMD C (C99) + library containing implementations of the Smith-Waterman (local), + Needleman-Wunsch (global), and semi-global pairwise sequence alignment + algorithms.""" + + homepage = "https://github.com/jeffdaily/parasail-python" + pypi = "parasail/parasail-1.3.3.tar.gz" + + version("1.3.3", sha256="06f05066d9cf624c0b043f51a1e9d2964154e1edd0f9843e0838f32073e576f8") + + depends_on("perl", type="build") + depends_on("m4", type="build") + depends_on("libtool", type="build") + depends_on("autoconf", type="build") + depends_on("automake", type="build") + depends_on("py-setuptools", type="build") + depends_on("py-numpy", type=("build", "run")) diff --git a/var/spack/repos/builtin/packages/py-progressbar33/package.py b/var/spack/repos/builtin/packages/py-progressbar33/package.py new file mode 100644 index 00000000000..1a4b6adb114 --- /dev/null +++ b/var/spack/repos/builtin/packages/py-progressbar33/package.py @@ -0,0 +1,18 @@ +# 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 PyProgressbar33(PythonPackage): + """Text progress bar library for Python""" + + homepage = "https://github.com/germangh/python-progressbar" + pypi = "progressbar33/progressbar33-2.4.tar.gz" + + version("2.4", sha256="51fe0d9b3b4023db2f983eeccdfc8c9846b84db8443b9bee002c7f58f4376eff") + + depends_on("py-setuptools", type="build") diff --git a/var/spack/repos/builtin/packages/py-pyspoa/package.py b/var/spack/repos/builtin/packages/py-pyspoa/package.py new file mode 100644 index 00000000000..c351b0fc9ab --- /dev/null +++ b/var/spack/repos/builtin/packages/py-pyspoa/package.py @@ -0,0 +1,20 @@ +# 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 PyPyspoa(PythonPackage): + """Python bindings to spoa""" + + homepage = "https://github.com/nanoporetech/pyspoa" + pypi = "pyspoa/pyspoa-0.0.8.tar.gz" + + version("0.0.8", sha256="8299d18066b498a6ef294c5a33a99266ded06eeb022f67488d2caecba974b0a4") + + depends_on("py-setuptools", type="build") + depends_on("cmake@3.18.4", type="build") + depends_on("py-pybind11@2.4:", type=("build", "run")) diff --git a/var/spack/repos/builtin/packages/py-scikit-build/package.py b/var/spack/repos/builtin/packages/py-scikit-build/package.py index e51f323c981..1d895c005d0 100644 --- a/var/spack/repos/builtin/packages/py-scikit-build/package.py +++ b/var/spack/repos/builtin/packages/py-scikit-build/package.py @@ -22,6 +22,7 @@ class PyScikitBuild(PythonPackage): version("0.15.0", sha256="e723cd0f3489a042370b9ea988bbb9cfd7725e8b25b20ca1c7981821fcf65fb9") version("0.12.0", sha256="f851382c469bcd9a8c98b1878bcfdd13b68556279d2fd9a329be41956ae5a7fe") + version("0.11.1", sha256="da40dfd69b2456fad1349a894b90180b43712152b8a85d2a00f4ae2ce8ac9a5c") version("0.10.0", sha256="7342017cc82dd6178e3b19377389b8a8d1f8b429d9cdb315cfb1094e34a0f526") depends_on("py-setuptools@28.0.0:", type=("build", "run")) From 6c5a7fefd6d7f208bf28a492c722ddb63e658150 Mon Sep 17 00:00:00 2001 From: Brian Van Essen Date: Fri, 28 Oct 2022 12:21:50 -0700 Subject: [PATCH 252/442] Fixed a bad variant when statement for including cuDNN. (#33595) --- var/spack/repos/builtin/packages/dihydrogen/package.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/dihydrogen/package.py b/var/spack/repos/builtin/packages/dihydrogen/package.py index 082ea55559b..33857729977 100644 --- a/var/spack/repos/builtin/packages/dihydrogen/package.py +++ b/var/spack/repos/builtin/packages/dihydrogen/package.py @@ -85,7 +85,7 @@ class Dihydrogen(CMakePackage, CudaPackage, ROCmPackage): depends_on("roctracer-dev", when="+rocm +distconv") - depends_on("cudnn", when="+cuda +distconv") + depends_on("cudnn", when="+cuda") depends_on("cub", when="^cuda@:10") # Note that #1712 forces us to enumerate the different blas variants From 06bac4a487f5dd3f83f0df88a4f0b2ae11e081ff Mon Sep 17 00:00:00 2001 From: "Adam J. Stewart" Date: Fri, 28 Oct 2022 23:36:14 -0500 Subject: [PATCH 253/442] libtiff: CMake support, internal codecs variants (#33591) --- .../repos/builtin/packages/libtiff/package.py | 97 ++++++++++++++----- 1 file changed, 74 insertions(+), 23 deletions(-) diff --git a/var/spack/repos/builtin/packages/libtiff/package.py b/var/spack/repos/builtin/packages/libtiff/package.py index a17c1eb21f3..535a3145b60 100644 --- a/var/spack/repos/builtin/packages/libtiff/package.py +++ b/var/spack/repos/builtin/packages/libtiff/package.py @@ -3,10 +3,34 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +from spack.build_systems.autotools import AutotoolsBuilder +from spack.build_systems.cmake import CMakeBuilder from spack.package import * +VARIANTS = [ + # Internal codecs + "ccitt", + "packbits", + "lzw", + "thunder", + "next", + "logluv", + # External codecs + "zlib", + "libdeflate", + "pixarlog", + "jpeg", + "old-jpeg", + "jpeg12", + "jbig", + "lerc", + "lzma", + "zstd", + "webp", +] -class Libtiff(AutotoolsPackage): + +class Libtiff(CMakePackage, AutotoolsPackage): """LibTIFF - Tag Image File Format (TIFF) Library and Utilities.""" homepage = "http://www.simplesystems.org/libtiff/" @@ -23,19 +47,42 @@ class Libtiff(AutotoolsPackage): version("4.0.8", sha256="59d7a5a8ccd92059913f246877db95a2918e6c04fb9d43fd74e5c3390dac2910") version("4.0.7", sha256="9f43a2cfb9589e5cecaa66e16bf87f814c945f22df7ba600d63aac4632c4f019") version("4.0.6", sha256="4d57a50907b510e3049a4bba0d7888930fdfc16ce49f1bf693e5b6247370d68c") + version("4.0.5", sha256="e25eaa83ed7fab43ddd278b9b14d91a406a4b674cedc776adb95535f897f309c") + version("4.0.4", sha256="8cb1d90c96f61cdfc0bcf036acc251c9dbe6320334da941c7a83cfe1576ef890") version("3.9.7", sha256="f5d64dd4ce61c55f5e9f6dc3920fbe5a41e02c2e607da7117a35eb5c320cef6a") - variant("zlib", default=True, description="Enable Zlib usage") - variant("libdeflate", default=False, description="Enable libdeflate usage", when="@4.2:") - variant("pixarlog", default=False, description="Enable support for Pixar log-format algorithm") - variant("jpeg", default=True, description="Enable IJG JPEG library usage") - variant("old-jpeg", default=False, description="Enable support for Old JPEG compression") - variant("jpeg12", default=False, description="Enable libjpeg 8/12bit dual mode", when="@4:") - variant("jbig", default=False, description="Enable JBIG-KIT usage") - variant("lerc", default=False, description="Enable liblerc usage", when="@4.3:") - variant("lzma", default=False, description="Enable liblzma usage", when="@4:") - variant("zstd", default=False, description="Enable libzstd usage", when="@4.0.10:") - variant("webp", default=False, description="Enable libwebp usage", when="@4.0.10:") + # Internal codecs + variant("ccitt", default=True, description="support for CCITT Group 3 & 4 algorithms") + variant("packbits", default=True, description="support for Macintosh PackBits algorithm") + variant("lzw", default=True, description="support for LZW algorithm") + variant("thunder", default=True, description="support for ThunderScan 4-bit RLE algorithm") + variant("next", default=True, description="support for NeXT 2-bit RLE algorithm") + variant("logluv", default=True, description="support for LogLuv high dynamic range algorithm") + + # External codecs + variant("zlib", default=True, description="use zlib") + variant("libdeflate", default=False, description="use libdeflate", when="@4.2:") + variant("pixarlog", default=False, description="support for Pixar log-format algorithm") + variant("jpeg", default=True, description="use libjpeg") + variant("old-jpeg", default=False, description="support for Old JPEG compression") + variant("jpeg12", default=False, description="enable libjpeg 8/12-bit dual mode", when="@4:") + variant("jbig", default=False, description="use ISO JBIG compression") + variant("lerc", default=False, description="use libLerc", when="@4.3:") + variant("lzma", default=False, description="use liblzma", when="@4:") + variant("zstd", default=False, description="use libzstd", when="@4.0.10:") + variant("webp", default=False, description="use libwebp", when="@4.0.10:") + + build_system( + conditional("cmake", when="@4.0.5:"), + "autotools", + default="cmake", + ) + + with when("build_system=cmake"): + depends_on("cmake@3.9:", when="@4.3:", type="build") + depends_on("cmake@2.8.11:", when="@4.0.10:4.2", type="build") + depends_on("cmake@2.8.9:", when="@4.0.6:4.0.9", type="build") + depends_on("cmake@3:", when="@4.0.5", type="build") depends_on("zlib", when="+zlib") depends_on("zlib", when="+pixarlog") @@ -63,17 +110,21 @@ def patch(self): 'vl_cv_prog_cc_warnings="-Wall -W"', 'vl_cv_prog_cc_warnings="-Wall"', "configure" ) + +class CMakeBuilder(CMakeBuilder): + def cmake_args(self): + args = [self.define_from_variant(var) for var in VARIANTS] + + # Remove empty strings + args = [arg for arg in args if arg] + + return args + + +class AutotoolsBuilder(AutotoolsBuilder): def configure_args(self): args = [] - args += self.enable_or_disable("zlib") - args += self.enable_or_disable("libdeflate") - args += self.enable_or_disable("pixarlog") - args += self.enable_or_disable("jpeg") - args += self.enable_or_disable("old-jpeg") - args += self.enable_or_disable("jpeg12") - args += self.enable_or_disable("jbig") - args += self.enable_or_disable("lerc") - args += self.enable_or_disable("lzma") - args += self.enable_or_disable("zstd") - args += self.enable_or_disable("webp") + for var in VARIANTS: + args.extend(self.enable_or_disable(var)) + return args From b06c5a43d94628e8a52b2c3d9265dffdbc48363b Mon Sep 17 00:00:00 2001 From: Axel Huebl Date: Sat, 29 Oct 2022 02:27:46 -0700 Subject: [PATCH 254/442] WarpX 22.10 & PICMI-Standard (#33594) Update `warpx` & `py-warpx` to the latest release, `22.10`. Update `py-picmistandard` accordingly. --- .../repos/builtin/packages/py-picmistandard/package.py | 2 ++ var/spack/repos/builtin/packages/py-warpx/package.py | 9 +++++++-- var/spack/repos/builtin/packages/warpx/package.py | 4 +++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/var/spack/repos/builtin/packages/py-picmistandard/package.py b/var/spack/repos/builtin/packages/py-picmistandard/package.py index e497a682569..3d6da0ba62b 100644 --- a/var/spack/repos/builtin/packages/py-picmistandard/package.py +++ b/var/spack/repos/builtin/packages/py-picmistandard/package.py @@ -16,6 +16,8 @@ class PyPicmistandard(PythonPackage): maintainers = ["ax3l", "dpgrote", "RemiLehe"] version("develop", branch="master") + version("0.0.21", sha256="930056a23ed92dac7930198f115b6248606b57403bffebce3d84579657c8d10b") + version("0.0.20", sha256="9c1822eaa2e4dd543b5afcfa97940516267dda3890695a6cf9c29565a41e2905") version("0.0.19", sha256="4b7ba1330964fbfd515e8ea2219966957c1386e0896b92d36bd9e134afb02f5a") version("0.0.18", sha256="68c208c0c54b4786e133bb13eef0dd4824998da4906285987ddee84e6d195e71") # 0.15 - 0.17 have broken install logic: missing requirements.txt on pypi diff --git a/var/spack/repos/builtin/packages/py-warpx/package.py b/var/spack/repos/builtin/packages/py-warpx/package.py index b550d6dfe89..cbf4bff7991 100644 --- a/var/spack/repos/builtin/packages/py-warpx/package.py +++ b/var/spack/repos/builtin/packages/py-warpx/package.py @@ -18,7 +18,7 @@ class PyWarpx(PythonPackage): """ homepage = "https://ecp-warpx.github.io" - url = "https://github.com/ECP-WarpX/WarpX/archive/refs/tags/22.05.tar.gz" + url = "https://github.com/ECP-WarpX/WarpX/archive/refs/tags/22.10.tar.gz" git = "https://github.com/ECP-WarpX/WarpX.git" maintainers = ["ax3l", "dpgrote", "RemiLehe"] @@ -27,6 +27,8 @@ class PyWarpx(PythonPackage): # NOTE: if you update the versions here, also see warpx version("develop", branch="development") + version("22.10", sha256="3cbbbbb4d79f806b15e81c3d0e4a4401d1d03d925154682a3060efebd3b6ca3e") + version("22.09", sha256="dbef1318248c86c860cc47f7e18bbb0397818e3acdfb459e48075004bdaedea3") version("22.08", sha256="5ff7fd628e8bf615c1107e6c51bc55926f3ef2a076985444b889d292fecf56d4") version("22.07", sha256="0286adc788136cb78033cb1678d38d36e42265bcfd3d0c361a9bcc2cfcdf241b") version("22.06", sha256="e78398e215d3fc6bc5984f5d1c2ddeac290dcbc8a8e9d196e828ef6299187db9") @@ -48,6 +50,8 @@ class PyWarpx(PythonPackage): variant("mpi", default=True, description="Enable MPI support") for v in [ + "22.10", + "22.09", "22.08", "22.07", "22.06", @@ -77,7 +81,8 @@ class PyWarpx(PythonPackage): depends_on("py-picmistandard@0.0.14", type=("build", "run"), when="@21.03:21.11") depends_on("py-picmistandard@0.0.16", type=("build", "run"), when="@21.12") depends_on("py-picmistandard@0.0.18", type=("build", "run"), when="@22.01") - depends_on("py-picmistandard@0.0.19", type=("build", "run"), when="@22.02:") + depends_on("py-picmistandard@0.0.19", type=("build", "run"), when="@22.02:22.09") + depends_on("py-picmistandard@0.0.20", type=("build", "run"), when="@22.10:") depends_on("py-setuptools@42:", type="build") # Since we use PYWARPX_LIB_DIR to pull binaries out of the # 'warpx' spack package, we don't need py-cmake as declared diff --git a/var/spack/repos/builtin/packages/warpx/package.py b/var/spack/repos/builtin/packages/warpx/package.py index f4b8c66c352..59762894de5 100644 --- a/var/spack/repos/builtin/packages/warpx/package.py +++ b/var/spack/repos/builtin/packages/warpx/package.py @@ -17,7 +17,7 @@ class Warpx(CMakePackage): """ homepage = "https://ecp-warpx.github.io" - url = "https://github.com/ECP-WarpX/WarpX/archive/refs/tags/22.05.tar.gz" + url = "https://github.com/ECP-WarpX/WarpX/archive/refs/tags/22.10.tar.gz" git = "https://github.com/ECP-WarpX/WarpX.git" maintainers = ["ax3l", "dpgrote", "MaxThevenet", "RemiLehe"] @@ -25,6 +25,8 @@ class Warpx(CMakePackage): # NOTE: if you update the versions here, also see py-warpx version("develop", branch="development") + version("22.10", sha256="3cbbbbb4d79f806b15e81c3d0e4a4401d1d03d925154682a3060efebd3b6ca3e") + version("22.09", sha256="dbef1318248c86c860cc47f7e18bbb0397818e3acdfb459e48075004bdaedea3") version("22.08", sha256="5ff7fd628e8bf615c1107e6c51bc55926f3ef2a076985444b889d292fecf56d4") version("22.07", sha256="0286adc788136cb78033cb1678d38d36e42265bcfd3d0c361a9bcc2cfcdf241b") version("22.06", sha256="e78398e215d3fc6bc5984f5d1c2ddeac290dcbc8a8e9d196e828ef6299187db9") From 6edb20c7a63d5b0777ee7b1f89b91a6e70a0a492 Mon Sep 17 00:00:00 2001 From: Satish Balay Date: Sat, 29 Oct 2022 04:34:45 -0500 Subject: [PATCH 255/442] mumps: update URLs, and add versions 5.5.0, 5.5.1 (#33597) --- .../mumps/mumps.src-makefile.5.5.patch | 25 +++++++++++++++++++ .../repos/builtin/packages/mumps/package.py | 9 ++++--- 2 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 var/spack/repos/builtin/packages/mumps/mumps.src-makefile.5.5.patch diff --git a/var/spack/repos/builtin/packages/mumps/mumps.src-makefile.5.5.patch b/var/spack/repos/builtin/packages/mumps/mumps.src-makefile.5.5.patch new file mode 100644 index 00000000000..d56d7ad7455 --- /dev/null +++ b/var/spack/repos/builtin/packages/mumps/mumps.src-makefile.5.5.patch @@ -0,0 +1,25 @@ +diff --git a/src/Makefile b/src/Makefile +index 2562522..9dfa43e 100644 +--- a/src/Makefile ++++ b/src/Makefile +@@ -215,7 +215,7 @@ $(libdir)/libmumps_common$(PLAT)$(LIBEXT_SHARED): $(OBJS_COMMON_MOD) $(OBJS + $(FC) $(OPTL) -shared $^ -Wl,-soname,libmumps_common$(PLAT).so -L$(libdir) $(RPATH_OPT) $(LORDERINGS) $(LIBS) $(LIBOTHERS) -o $@ + + $(libdir)/lib$(ARITH)mumps$(PLAT)$(LIBEXT): $(OBJS_MOD) $(OBJS_OTHER) +- $(AR)$@ $? ++ $(AR)$@ $? $(EXTRA_LIBS4MUMPS) + $(RANLIB) $@ + + $(libdir)/lib$(ARITH)mumps$(PLAT)$(LIBEXT_SHARED): $(OBJS_MOD) $(OBJS_OTHER) $(libdir)/libmumps_common$(PLAT)$(LIBEXT_SHARED) +@@ -434,9 +434,9 @@ $(OBJS_OTHER):$(OBJS_COMMON_MOD) $(OBJS_MOD) + + .SUFFIXES: .c .F .o + .F.o: +- $(FC) $(OPTF) $(FPIC) -I. -I../include $(INCS) $(IORDERINGSF) $(ORDERINGSF) -c $*.F $(OUTF)$*.o ++ $(FC) $(OPTF) $(FC_PIC_FLAG) $(FPIC) -I. -I../include $(INCS) $(IORDERINGSF) $(ORDERINGSF) -c $*.F $(OUTF)$*.o + .c.o: +- $(CC) $(OPTC) $(FPIC) -I../include $(INCS) $(CDEFS) $(IORDERINGSC) $(ORDERINGSC) -c $*.c $(OUTC)$*.o ++ $(CC) $(OPTC) $(CC_PIC_FLAG) $(FPIC) -I../include $(INCS) $(CDEFS) $(IORDERINGSC) $(ORDERINGSC) -c $*.c $(OUTC)$*.o + + $(ARITH)mumps_c.o: mumps_c.c + $(CC) $(OPTC) $(FPIC) -I../include $(INCS) $(CDEFS) -DMUMPS_ARITH=MUMPS_ARITH_$(ARITH) \ diff --git a/var/spack/repos/builtin/packages/mumps/package.py b/var/spack/repos/builtin/packages/mumps/package.py index 7d0d5c950b4..e0aff4a7567 100644 --- a/var/spack/repos/builtin/packages/mumps/package.py +++ b/var/spack/repos/builtin/packages/mumps/package.py @@ -13,9 +13,11 @@ class Mumps(Package): """MUMPS: a MUltifrontal Massively Parallel sparse direct Solver""" - homepage = "http://mumps.enseeiht.fr" - url = "http://mumps.enseeiht.fr/MUMPS_5.3.5.tar.gz" + homepage = "https://graal.ens-lyon.fr/MUMPS/index.php" + url = "https://graal.ens-lyon.fr/MUMPS/MUMPS_5.5.1.tar.gz" + version("5.5.1", sha256="1abff294fa47ee4cfd50dfd5c595942b72ebfcedce08142a75a99ab35014fa15") + version("5.5.0", sha256="e54d17c5e42a36c40607a03279e0704d239d71d38503aab68ef3bfe0a9a79c13") version("5.4.1", sha256="93034a1a9fe0876307136dcde7e98e9086e199de76f1c47da822e7d4de987fa8") version("5.4.0", sha256="c613414683e462da7c152c131cebf34f937e79b30571424060dd673368bbf627") version("5.3.5", sha256="e5d665fdb7043043f0799ae3dbe3b37e5b200d1ab7a6f7b2a4e463fd89507fa4") @@ -68,7 +70,8 @@ class Mumps(Package): # The following patches src/Makefile to fix some dependency # issues in lib[cdsz]mumps.so patch("mumps.src-makefile.5.2.patch", when="@5.2.0 +shared") - patch("mumps.src-makefile.5.3.patch", when="@5.3.0: +shared") + patch("mumps.src-makefile.5.3.patch", when="@5.3.0:5.4.1 +shared") + patch("mumps.src-makefile.5.5.patch", when="@5.5.0: +shared") conflicts("+parmetis", when="~mpi", msg="You cannot use the parmetis variant without mpi") conflicts("+parmetis", when="~metis", msg="You cannot use the parmetis variant without metis") From c10d52595688e2e2c21637461912fb8d621c790a Mon Sep 17 00:00:00 2001 From: eugeneswalker <38933153+eugeneswalker@users.noreply.github.com> Date: Sat, 29 Oct 2022 05:13:54 -0700 Subject: [PATCH 256/442] json-c %oneapi: add -Wno-error=implicit-function-declaration (#33585) --- var/spack/repos/builtin/packages/json-c/package.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/var/spack/repos/builtin/packages/json-c/package.py b/var/spack/repos/builtin/packages/json-c/package.py index a62e0323ea8..d13bddecb83 100644 --- a/var/spack/repos/builtin/packages/json-c/package.py +++ b/var/spack/repos/builtin/packages/json-c/package.py @@ -42,6 +42,13 @@ def patch(self): def patch(self): filter_file("-Werror", "", "CMakeLists.txt") + def flag_handler(self, name, flags): + iflags = [] + if name == "cflags": + if self.spec.satisfies("%oneapi"): + iflags.append("-Wno-error=implicit-function-declaration") + return (iflags, None, None) + @run_after("install") def darwin_fix(self): # The shared library is not installed correctly on Darwin; fix this From ef8c15c5eff460d9ae3aa783c212722c6fd581e2 Mon Sep 17 00:00:00 2001 From: eugeneswalker <38933153+eugeneswalker@users.noreply.github.com> Date: Sat, 29 Oct 2022 05:14:15 -0700 Subject: [PATCH 257/442] czmq %oneapi: -Wno-error: gnu-null-pointer-arithmetic, strict-prototypes (#33586) --- var/spack/repos/builtin/packages/czmq/package.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/var/spack/repos/builtin/packages/czmq/package.py b/var/spack/repos/builtin/packages/czmq/package.py index 60d1cdd71aa..a0b35774627 100644 --- a/var/spack/repos/builtin/packages/czmq/package.py +++ b/var/spack/repos/builtin/packages/czmq/package.py @@ -25,6 +25,14 @@ class Czmq(AutotoolsPackage): depends_on("uuid") depends_on("libzmq") + def flag_handler(self, name, flags): + iflags = [] + if name == "cflags": + if self.spec.satisfies("%oneapi@2022.2.0:"): + iflags.append("-Wno-error=gnu-null-pointer-arithmetic") + iflags.append("-Wno-error=strict-prototypes") + return (iflags, None, None) + def autoreconf(self, spec, prefix): autogen = Executable("./autogen.sh") autogen() From 83b49070e60c44362638381c949147ef06fbe52c Mon Sep 17 00:00:00 2001 From: Jonas Thies <16190001+jthies@users.noreply.github.com> Date: Sat, 29 Oct 2022 19:12:26 +0200 Subject: [PATCH 258/442] =?UTF-8?q?phist:=20add/update=20conflicts=20with?= =?UTF-8?q?=20cray-libsci=20and/or=20python@3.11:=20for=20=E2=80=A6=20(#33?= =?UTF-8?q?587)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * phist: add/update conflicts with cray-libsci and/or python@3.11: for versions <1.11.2 * phist: style fix --- var/spack/repos/builtin/packages/phist/package.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/phist/package.py b/var/spack/repos/builtin/packages/phist/package.py index 94c868589b2..840b6e1d671 100644 --- a/var/spack/repos/builtin/packages/phist/package.py +++ b/var/spack/repos/builtin/packages/phist/package.py @@ -21,7 +21,7 @@ class Phist(CMakePackage): """ homepage = "https://bitbucket.org/essex/phist/" - url = "https://bitbucket.org/essex/phist/get/phist-1.9.6.tar.gz" + url = "https://bitbucket.org/essex/phist/get/phist-1.11.2.tar.gz" git = "https://bitbucket.org/essex/phist.git" maintainers = ["jthies"] @@ -34,7 +34,9 @@ class Phist(CMakePackage): version("develop", branch="devel") version("master", branch="master") + # compatible with python@3.11: and cray-libsci as BLAS/LAPACK provider version("1.11.2", sha256="e23f76307c26b930f7331a734b0a864ea6d7fb4a13c12f3c5d70c2c41481747b") + # updated lapack interface to work with openblas and netlib-lapack version("1.11.0", sha256="36e6cc41a13884ba0a26f7be03e3f1882b1a2d14ca04353a609c0eec0cfb7a77") @@ -129,6 +131,10 @@ class Phist(CMakePackage): description="generate Fortran 2003 bindings (requires Python3 and " "a Fortran compiler)", ) + # Build error with cray-libsci because they define macro 'I', workaround in phist-1.11.2 + conflicts("^cray-libsci", when="@:1.11.1") + # phist@1.11.2 got rid of some deprecated python code + conflicts("^python@3.11:", when="@:1.11.1") # The builtin kernels switched from the 'mpi' to the 'mpi_f08' module in # phist 1.9.6, which causes compile-time errors with mpich and older # GCC versions. From 29f1e8395c16831d2fe06cfa9aa8c49dc8cc96a6 Mon Sep 17 00:00:00 2001 From: Sergey Kosukhin Date: Sat, 29 Oct 2022 20:17:43 +0200 Subject: [PATCH 259/442] mpich: fix rpath flags in mpif90 when building with oneapi (#33319) Co-authored-by: eugeneswalker <38933153+eugeneswalker@users.noreply.github.com> --- .../mpich/mpich-oneapi-config-rpath.patch | 30 ------------------- .../mpich-oneapi-config-rpath/step1.patch | 9 ++++++ .../mpich-oneapi-config-rpath/step2.patch | 6 ++++ .../repos/builtin/packages/mpich/package.py | 10 +++++-- 4 files changed, 23 insertions(+), 32 deletions(-) delete mode 100644 var/spack/repos/builtin/packages/mpich/mpich-oneapi-config-rpath.patch create mode 100644 var/spack/repos/builtin/packages/mpich/mpich-oneapi-config-rpath/step1.patch create mode 100644 var/spack/repos/builtin/packages/mpich/mpich-oneapi-config-rpath/step2.patch diff --git a/var/spack/repos/builtin/packages/mpich/mpich-oneapi-config-rpath.patch b/var/spack/repos/builtin/packages/mpich/mpich-oneapi-config-rpath.patch deleted file mode 100644 index 94eafda34f5..00000000000 --- a/var/spack/repos/builtin/packages/mpich/mpich-oneapi-config-rpath.patch +++ /dev/null @@ -1,30 +0,0 @@ -diff -ruN spack-src/confdb/config.rpath spack-src-patched/confdb/config.rpath ---- spack-src/confdb/config.rpath 2022-03-29 15:13:49.000000000 -0700 -+++ spack-src-patched/confdb/config.rpath 2022-07-25 17:54:14.638367460 -0700 -@@ -76,7 +76,7 @@ - ecc*) - wl='-Wl,' - ;; -- icc* | ifort*) -+ icc* | icx* | ifort* | ifx*) - wl='-Wl,' - ;; - lf95*) -@@ -233,7 +233,7 @@ - enable_dtags_flag="${wl}--enable-new-dtags" - disable_dtags_flag="${wl}--disable-new-dtags" - else -- case $cc_basename in ifort*) -+ case $cc_basename in ifort* | ifx*) - enable_dtags_flag="${wl}--enable-new-dtags" - disable_dtags_flag="${wl}--disable-new-dtags" - ;; -@@ -380,7 +380,7 @@ - ;; - darwin* | rhapsody*) - hardcode_direct=no -- if { case $cc_basename in ifort*) true;; *) test "$GCC" = yes;; esac; }; then -+ if { case $cc_basename in ifort* | ifx*) true;; *) test "$GCC" = yes;; esac; }; then - : - else - ld_shlibs=no diff --git a/var/spack/repos/builtin/packages/mpich/mpich-oneapi-config-rpath/step1.patch b/var/spack/repos/builtin/packages/mpich/mpich-oneapi-config-rpath/step1.patch new file mode 100644 index 00000000000..90f53b61cf6 --- /dev/null +++ b/var/spack/repos/builtin/packages/mpich/mpich-oneapi-config-rpath/step1.patch @@ -0,0 +1,9 @@ +# This patch is applicable starting at least version 3.0. +--- a/confdb/config.rpath ++++ b/confdb/config.rpath +@@ -79 +79 @@ else +- icc* | ifort*) ++ icc* | icx* | ifort* | ifx*) +@@ -383 +383 @@ else +- if { case $cc_basename in ifort*) true;; *) test "$GCC" = yes;; esac; }; then ++ if { case $cc_basename in ifort* | ifx*) true;; *) test "$GCC" = yes;; esac; }; then diff --git a/var/spack/repos/builtin/packages/mpich/mpich-oneapi-config-rpath/step2.patch b/var/spack/repos/builtin/packages/mpich/mpich-oneapi-config-rpath/step2.patch new file mode 100644 index 00000000000..ea14a28eb8b --- /dev/null +++ b/var/spack/repos/builtin/packages/mpich/mpich-oneapi-config-rpath/step2.patch @@ -0,0 +1,6 @@ +# This patch is applicable starting version 3.1.1. +--- a/confdb/config.rpath ++++ b/confdb/config.rpath +@@ -236 +236 @@ if test "$with_gnu_ld" = yes; then +- case $cc_basename in ifort*) ++ case $cc_basename in ifort* | ifx*) diff --git a/var/spack/repos/builtin/packages/mpich/package.py b/var/spack/repos/builtin/packages/mpich/package.py index 701ba958562..8692cf06362 100644 --- a/var/spack/repos/builtin/packages/mpich/package.py +++ b/var/spack/repos/builtin/packages/mpich/package.py @@ -150,8 +150,14 @@ class Mpich(AutotoolsPackage, CudaPackage, ROCmPackage): filter_compiler_wrappers("mpicc", "mpicxx", "mpif77", "mpif90", "mpifort", relative_root="bin") - # https://github.com/spack/spack/issues/31678 - patch("mpich-oneapi-config-rpath.patch", when="@4.0.2 %oneapi") + # Set correct rpath flags for Intel Fortran Compiler (%oneapi) + # See https://github.com/pmodels/mpich/pull/5824 + # and https://github.com/spack/spack/issues/31678 + # We do not fetch the patch from the upstream repo because it cannot be applied to older + # versions. + with when("%oneapi"): + patch("mpich-oneapi-config-rpath/step1.patch", when="@:4.0.2") + patch("mpich-oneapi-config-rpath/step2.patch", when="@3.1.1:4.0.2") # Fix using an external hwloc # See https://github.com/pmodels/mpich/issues/4038 From 7e645f54c5d0ab78592436988576a0f2765e9fab Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Sat, 29 Oct 2022 21:24:26 +0200 Subject: [PATCH 260/442] Deprecate spack bootstrap trust/untrust (#33600) * Deprecate spack bootstrap trust/untrust * Update CI * Update tests --- .github/workflows/bootstrap-test.sh | 2 +- .github/workflows/bootstrap.yml | 16 +++--- .github/workflows/unit_tests.yaml | 4 +- lib/spack/docs/bootstrapping.rst | 33 +++++++---- lib/spack/docs/getting_started.rst | 28 +--------- lib/spack/spack/cmd/bootstrap.py | 80 ++++++++++++++++++++------- lib/spack/spack/test/cmd/bootstrap.py | 6 +- share/spack/spack-completion.bash | 14 ++++- 8 files changed, 113 insertions(+), 70 deletions(-) diff --git a/.github/workflows/bootstrap-test.sh b/.github/workflows/bootstrap-test.sh index fc8f93d68b5..b51db3d1b74 100755 --- a/.github/workflows/bootstrap-test.sh +++ b/.github/workflows/bootstrap-test.sh @@ -1,7 +1,7 @@ #!/bin/bash set -ex source share/spack/setup-env.sh -$PYTHON bin/spack bootstrap untrust spack-install +$PYTHON bin/spack bootstrap disable spack-install $PYTHON bin/spack -d solve zlib tree $BOOTSTRAP/store exit 0 diff --git a/.github/workflows/bootstrap.yml b/.github/workflows/bootstrap.yml index 09c356a3e0c..bdaefbfc3db 100644 --- a/.github/workflows/bootstrap.yml +++ b/.github/workflows/bootstrap.yml @@ -42,7 +42,7 @@ jobs: shell: runuser -u spack-test -- bash {0} run: | source share/spack/setup-env.sh - spack bootstrap untrust github-actions-v0.3 + spack bootstrap disable github-actions-v0.3 spack external find cmake bison spack -d solve zlib tree ~/.spack/bootstrap/store/ @@ -79,7 +79,7 @@ jobs: shell: runuser -u spack-test -- bash {0} run: | source share/spack/setup-env.sh - spack bootstrap untrust github-actions-v0.3 + spack bootstrap disable github-actions-v0.3 spack external find cmake bison spack -d solve zlib tree ~/.spack/bootstrap/store/ @@ -143,7 +143,7 @@ jobs: - name: Bootstrap clingo run: | source share/spack/setup-env.sh - spack bootstrap untrust github-actions-v0.3 + spack bootstrap disable github-actions-v0.3 spack external find cmake bison spack -d solve zlib tree ~/.spack/bootstrap/store/ @@ -160,7 +160,7 @@ jobs: run: | source share/spack/setup-env.sh export PATH=/usr/local/opt/bison@2.7/bin:$PATH - spack bootstrap untrust github-actions-v0.3 + spack bootstrap disable github-actions-v0.3 spack external find --not-buildable cmake bison spack -d solve zlib tree ~/.spack/bootstrap/store/ @@ -261,7 +261,7 @@ jobs: shell: runuser -u spack-test -- bash {0} run: | source share/spack/setup-env.sh - spack bootstrap untrust spack-install + spack bootstrap disable spack-install spack -d gpg list tree ~/.spack/bootstrap/store/ @@ -298,7 +298,7 @@ jobs: run: | source share/spack/setup-env.sh spack solve zlib - spack bootstrap untrust github-actions-v0.3 + spack bootstrap disable github-actions-v0.3 spack -d gpg list tree ~/.spack/bootstrap/store/ @@ -315,7 +315,7 @@ jobs: - name: Bootstrap GnuPG run: | source share/spack/setup-env.sh - spack bootstrap untrust spack-install + spack bootstrap disable spack-install spack -d gpg list tree ~/.spack/bootstrap/store/ @@ -333,7 +333,7 @@ jobs: run: | source share/spack/setup-env.sh spack solve zlib - spack bootstrap untrust github-actions-v0.3 + spack bootstrap disable github-actions-v0.3 spack -d gpg list tree ~/.spack/bootstrap/store/ diff --git a/.github/workflows/unit_tests.yaml b/.github/workflows/unit_tests.yaml index 36c4a4339bc..dcebecaeae4 100644 --- a/.github/workflows/unit_tests.yaml +++ b/.github/workflows/unit_tests.yaml @@ -78,7 +78,7 @@ jobs: SPACK_PYTHON: python run: | . share/spack/setup-env.sh - spack bootstrap untrust spack-install + spack bootstrap disable spack-install spack -v solve zlib - name: Run unit tests env: @@ -215,7 +215,7 @@ jobs: git --version . .github/workflows/setup_git.sh . share/spack/setup-env.sh - $(which spack) bootstrap untrust spack-install + $(which spack) bootstrap disable spack-install $(which spack) solve zlib common_args=(--dist loadfile --tx '4*popen//python=./bin/spack-tmpconfig python -u ./bin/spack python' -x) $(which spack) unit-test --cov --cov-config=pyproject.toml "${common_args[@]}" diff --git a/lib/spack/docs/bootstrapping.rst b/lib/spack/docs/bootstrapping.rst index a38e96ac2f7..86ce2eb77b9 100644 --- a/lib/spack/docs/bootstrapping.rst +++ b/lib/spack/docs/bootstrapping.rst @@ -15,15 +15,13 @@ is an entire command dedicated to the management of every aspect of bootstrappin .. command-output:: spack bootstrap --help -The first thing to know to understand bootstrapping in Spack is that each of -Spack's dependencies is bootstrapped lazily; i.e. the first time it is needed and -can't be found. You can readily check if any prerequisite for using Spack -is missing by running: +Spack is configured to bootstrap its dependencies lazily by default; i.e. the first time they are needed and +can't be found. You can readily check if any prerequisite for using Spack is missing by running: .. code-block:: console % spack bootstrap status - Spack v0.17.1 - python@3.8 + Spack v0.19.0 - python@3.8 [FAIL] Core Functionalities [B] MISSING "clingo": required to concretize specs @@ -48,6 +46,21 @@ they can be bootstrapped. Running a command that concretize a spec, like: triggers the bootstrapping of clingo from pre-built binaries as expected. +Users can also bootstrap all the dependencies needed by Spack in a single command, which +might be useful to setup containers or other similar environments: + +.. code-block:: console + + $ spack bootstrap now + ==> Bootstrapping clingo from pre-built binaries + ==> Fetching https://mirror.spack.io/bootstrap/github-actions/v0.3/build_cache/linux-centos7-x86_64-gcc-10.2.1-clingo-bootstrap-spack-shqedxgvjnhiwdcdrvjhbd73jaevv7wt.spec.json + ==> Fetching https://mirror.spack.io/bootstrap/github-actions/v0.3/build_cache/linux-centos7-x86_64/gcc-10.2.1/clingo-bootstrap-spack/linux-centos7-x86_64-gcc-10.2.1-clingo-bootstrap-spack-shqedxgvjnhiwdcdrvjhbd73jaevv7wt.spack + ==> Installing "clingo-bootstrap@spack%gcc@10.2.1~docs~ipo+python+static_libstdcpp build_type=Release arch=linux-centos7-x86_64" from a buildcache + ==> Bootstrapping patchelf from pre-built binaries + ==> Fetching https://mirror.spack.io/bootstrap/github-actions/v0.3/build_cache/linux-centos7-x86_64-gcc-10.2.1-patchelf-0.15.0-htk62k7efo2z22kh6kmhaselru7bfkuc.spec.json + ==> Fetching https://mirror.spack.io/bootstrap/github-actions/v0.3/build_cache/linux-centos7-x86_64/gcc-10.2.1/patchelf-0.15.0/linux-centos7-x86_64-gcc-10.2.1-patchelf-0.15.0-htk62k7efo2z22kh6kmhaselru7bfkuc.spack + ==> Installing "patchelf@0.15.0%gcc@10.2.1 ldflags="-static-libstdc++ -static-libgcc" arch=linux-centos7-x86_64" from a buildcache + ----------------------- The Bootstrapping store ----------------------- @@ -107,19 +120,19 @@ If need be, you can disable bootstrapping altogether by running: in which case it's your responsibility to ensure Spack runs in an environment where all its prerequisites are installed. You can -also configure Spack to skip certain bootstrapping methods by *untrusting* -them. For instance: +also configure Spack to skip certain bootstrapping methods by disabling +them specifically: .. code-block:: console - % spack bootstrap untrust github-actions - ==> "github-actions" is now untrusted and will not be used for bootstrapping + % spack bootstrap disable github-actions + ==> "github-actions" is now disabled and will not be used for bootstrapping tells Spack to skip trying to bootstrap from binaries. To add the "github-actions" method back you can: .. code-block:: console - % spack bootstrap trust github-actions + % spack bootstrap enable github-actions There is also an option to reset the bootstrapping configuration to Spack's defaults: diff --git a/lib/spack/docs/getting_started.rst b/lib/spack/docs/getting_started.rst index d174a454689..2fc43906a95 100644 --- a/lib/spack/docs/getting_started.rst +++ b/lib/spack/docs/getting_started.rst @@ -177,35 +177,13 @@ Spack fall back to bootstrapping from sources: .. code-block:: console - $ spack bootstrap untrust github-actions-v0.2 - ==> "github-actions-v0.2" is now untrusted and will not be used for bootstrapping + $ spack bootstrap disable github-actions-v0.3 + ==> "github-actions-v0.2" is now disabled and will not be used for bootstrapping You can verify that the new settings are effective with: -.. code-block:: console +.. command-output:: spack bootstrap list - $ spack bootstrap list - Name: github-actions-v0.2 UNTRUSTED - - Type: buildcache - - Info: - url: https://mirror.spack.io/bootstrap/github-actions/v0.2 - homepage: https://github.com/spack/spack-bootstrap-mirrors - releases: https://github.com/spack/spack-bootstrap-mirrors/releases - - Description: - Buildcache generated from a public workflow using Github Actions. - The sha256 checksum of binaries is checked before installation. - - [ ... ] - - Name: spack-install TRUSTED - - Type: install - - Description: - Specs built from sources by Spack. May take a long time. .. note:: diff --git a/lib/spack/spack/cmd/bootstrap.py b/lib/spack/spack/cmd/bootstrap.py index fc1ab8e92df..1b398e4e5cd 100644 --- a/lib/spack/spack/cmd/bootstrap.py +++ b/lib/spack/spack/cmd/bootstrap.py @@ -8,6 +8,7 @@ import platform import shutil import tempfile +import warnings import llnl.util.filesystem import llnl.util.tty @@ -92,9 +93,11 @@ def setup_parser(subparser): enable = sp.add_parser("enable", help="enable bootstrapping") _add_scope_option(enable) + enable.add_argument("name", help="name of the source to be enabled", nargs="?", default=None) disable = sp.add_parser("disable", help="disable bootstrapping") _add_scope_option(disable) + disable.add_argument("name", help="name of the source to be disabled", nargs="?", default=None) reset = sp.add_parser("reset", help="reset bootstrapping configuration to Spack defaults") spack.cmd.common.arguments.add_common_arguments(reset, ["yes_to_all"]) @@ -108,11 +111,11 @@ def setup_parser(subparser): list = sp.add_parser("list", help="list all the sources of software to bootstrap Spack") _add_scope_option(list) - trust = sp.add_parser("trust", help="trust a bootstrapping source") + trust = sp.add_parser("trust", help="(DEPRECATED) trust a bootstrapping source") _add_scope_option(trust) trust.add_argument("name", help="name of the source to be trusted") - untrust = sp.add_parser("untrust", help="untrust a bootstrapping source") + untrust = sp.add_parser("untrust", help="(DEPRECATED) untrust a bootstrapping source") _add_scope_option(untrust) untrust.add_argument("name", help="name of the source to be untrusted") @@ -140,9 +143,21 @@ def setup_parser(subparser): def _enable_or_disable(args): - # Set to True if we called "enable", otherwise set to false value = args.subcommand == "enable" - spack.config.set("bootstrap:enable", value, scope=args.scope) + if args.name is None: + # Set to True if we called "enable", otherwise set to false + old_value = spack.config.get("bootstrap:enable", scope=args.scope) + if old_value == value: + llnl.util.tty.msg("Bootstrapping is already {}d".format(args.subcommand)) + else: + spack.config.set("bootstrap:enable", value, scope=args.scope) + llnl.util.tty.msg("Bootstrapping has been {}d".format(args.subcommand)) + return + + if value is True: + _trust(args) + else: + _untrust(args) def _reset(args): @@ -173,6 +188,8 @@ def _reset(args): if os.path.exists(bootstrap_yaml): shutil.move(bootstrap_yaml, backup_file) + spack.config.config.clear_caches() + def _root(args): if args.path: @@ -197,30 +214,41 @@ def fmt(header, content): header_fmt = "@*b{{{0}:}} {1}" color.cprint(header_fmt.format(header, content)) - trust_str = "@*y{UNKNOWN}" + trust_str = "@*y{DISABLED}" if trusted is True: - trust_str = "@*g{TRUSTED}" + trust_str = "@*g{ENABLED}" elif trusted is False: - trust_str = "@*r{UNTRUSTED}" + trust_str = "@*r{DISABLED}" fmt("Name", source["name"] + " " + trust_str) print() - fmt(" Type", source["type"]) - print() + if trusted is True or args.verbose: + fmt(" Type", source["type"]) + print() - info_lines = ["\n"] - for key, value in source.get("info", {}).items(): - info_lines.append(" " * 4 + "@*{{{0}}}: {1}\n".format(key, value)) - if len(info_lines) > 1: - fmt(" Info", "".join(info_lines)) + info_lines = ["\n"] + for key, value in source.get("info", {}).items(): + info_lines.append(" " * 4 + "@*{{{0}}}: {1}\n".format(key, value)) + if len(info_lines) > 1: + fmt(" Info", "".join(info_lines)) - description_lines = ["\n"] - for line in source["description"].split("\n"): - description_lines.append(" " * 4 + line + "\n") + description_lines = ["\n"] + for line in source["description"].split("\n"): + description_lines.append(" " * 4 + line + "\n") - fmt(" Description", "".join(description_lines)) + fmt(" Description", "".join(description_lines)) trusted = spack.config.get("bootstrap:trusted", {}) + + def sort_fn(x): + x_trust = trusted.get(x["name"], None) + if x_trust is True: + return 0 + elif x_trust is None: + return 1 + return 2 + + sources = sorted(sources, key=sort_fn) for s in sources: _print_method(s, trusted.get(s["name"], None)) @@ -252,15 +280,27 @@ def _write_trust_state(args, value): spack.config.add("bootstrap:trusted:{0}:{1}".format(name, str(value)), scope=scope) +def _deprecate_command(deprecated_cmd, suggested_cmd): + msg = ( + "the 'spack bootstrap {} ...' command is deprecated and will be " + "removed in v0.20, use 'spack bootstrap {} ...' instead" + ) + warnings.warn(msg.format(deprecated_cmd, suggested_cmd)) + + def _trust(args): + if args.subcommand == "trust": + _deprecate_command("trust", "enable") _write_trust_state(args, value=True) - msg = '"{0}" is now trusted for bootstrapping' + msg = '"{0}" is now enabled for bootstrapping' llnl.util.tty.msg(msg.format(args.name)) def _untrust(args): + if args.subcommand == "untrust": + _deprecate_command("untrust", "disable") _write_trust_state(args, value=False) - msg = '"{0}" is now untrusted and will not be used for bootstrapping' + msg = '"{0}" is now disabled and will not be used for bootstrapping' llnl.util.tty.msg(msg.format(args.name)) diff --git a/lib/spack/spack/test/cmd/bootstrap.py b/lib/spack/spack/test/cmd/bootstrap.py index 2ff66ae35b7..0eef7b3a7e8 100644 --- a/lib/spack/spack/test/cmd/bootstrap.py +++ b/lib/spack/spack/test/cmd/bootstrap.py @@ -109,7 +109,9 @@ def test_list_sources(capsys): assert "No method available" in output -@pytest.mark.parametrize("command,value", [("trust", True), ("untrust", False)]) +@pytest.mark.parametrize( + "command,value", [("enable", True), ("disable", False), ("trust", True), ("untrust", False)] +) def test_trust_or_untrust_sources(mutable_config, command, value): key = "bootstrap:trusted:github-actions" trusted = spack.config.get(key, default=None) @@ -135,7 +137,7 @@ def test_trust_or_untrust_fails_with_more_than_one_method(mutable_config): } with spack.config.override("bootstrap", wrong_config): with pytest.raises(RuntimeError, match="more than one"): - _bootstrap("trust", "github-actions") + _bootstrap("enable", "github-actions") @pytest.mark.parametrize("use_existing_dir", [True, False]) diff --git a/share/spack/spack-completion.bash b/share/spack/spack-completion.bash index 48e4c86b42f..f0588e5368c 100755 --- a/share/spack/spack-completion.bash +++ b/share/spack/spack-completion.bash @@ -425,11 +425,21 @@ _spack_bootstrap_status() { } _spack_bootstrap_enable() { - SPACK_COMPREPLY="-h --help --scope" + if $list_options + then + SPACK_COMPREPLY="-h --help --scope" + else + SPACK_COMPREPLY="" + fi } _spack_bootstrap_disable() { - SPACK_COMPREPLY="-h --help --scope" + if $list_options + then + SPACK_COMPREPLY="-h --help --scope" + else + SPACK_COMPREPLY="" + fi } _spack_bootstrap_reset() { From 23aada1d24d0b4ab0c35fe786d90205afba187d0 Mon Sep 17 00:00:00 2001 From: eugeneswalker <38933153+eugeneswalker@users.noreply.github.com> Date: Sat, 29 Oct 2022 12:41:10 -0700 Subject: [PATCH 261/442] gettext: constrain nvhpc patch to @:0.20.0 (#33489) --- var/spack/repos/builtin/packages/gettext/package.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/gettext/package.py b/var/spack/repos/builtin/packages/gettext/package.py index c633a5b51f1..b528e8a8b07 100644 --- a/var/spack/repos/builtin/packages/gettext/package.py +++ b/var/spack/repos/builtin/packages/gettext/package.py @@ -54,7 +54,7 @@ class Gettext(AutotoolsPackage, GNUMirrorPackage): # depends_on('cvs') patch("test-verify-parallel-make-check.patch", when="@:0.19.8.1") - patch("nvhpc-builtin.patch", when="%nvhpc") + patch("nvhpc-builtin.patch", when="@:0.21.0 %nvhpc") patch("nvhpc-export-symbols.patch", when="%nvhpc") patch("nvhpc-long-width.patch", when="%nvhpc") From e5274de7eccc54fa94a197c9d3f5b6b9ce16820a Mon Sep 17 00:00:00 2001 From: eugeneswalker <38933153+eugeneswalker@users.noreply.github.com> Date: Sat, 29 Oct 2022 13:19:27 -0700 Subject: [PATCH 262/442] unifyfs %oneapi: -Wno-error=deprecated-non-prototype,unused-function (#33602) --- var/spack/repos/builtin/packages/unifyfs/package.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/var/spack/repos/builtin/packages/unifyfs/package.py b/var/spack/repos/builtin/packages/unifyfs/package.py index 3d58448a5ee..fae9eba74c8 100644 --- a/var/spack/repos/builtin/packages/unifyfs/package.py +++ b/var/spack/repos/builtin/packages/unifyfs/package.py @@ -98,6 +98,9 @@ def flag_handler(self, name, flags): if "-g" in flags: self.debug_build = True if name == "cflags": + if self.spec.satisfies("%oneapi@2022.2.0:"): + flags.append("-Wno-error=deprecated-non-prototype") + flags.append("-Wno-error=unused-function") if self.spec.satisfies("%gcc@4"): flags.append("-std=gnu99") return (None, None, flags) From 82470f880aea5f47a4887fd82563486e0e2131df Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Sat, 29 Oct 2022 13:22:25 -0700 Subject: [PATCH 263/442] New MFEM version: 4.5 (#33480) * New MFEM version: 4.5 Add new MFEM variants: ginkgo, hiop * mfem: small tweaks * mfem: tweak testing script * mfem: try to resolve issue #30483 * mfem: fix style * mfem: tweak for Spack-built hipsparse Co-authored-by: eugeneswalker <38933153+eugeneswalker@users.noreply.github.com> --- .../repos/builtin/packages/mfem/package.py | 110 ++++++++++++++++-- .../builtin/packages/mfem/test_builds.sh | 55 +++++---- 2 files changed, 124 insertions(+), 41 deletions(-) diff --git a/var/spack/repos/builtin/packages/mfem/package.py b/var/spack/repos/builtin/packages/mfem/package.py index dab89f95500..d188c2fc881 100644 --- a/var/spack/repos/builtin/packages/mfem/package.py +++ b/var/spack/repos/builtin/packages/mfem/package.py @@ -48,6 +48,13 @@ class Mfem(Package, CudaPackage, ROCmPackage): # other version. version("develop", branch="master") + version( + "4.5.0", + sha256="4f201bec02fc5460a902596697b6c1deb7b15ac57c71f615b2ab4a8eb65665f7", + url="https://bit.ly/mfem-4-5", + extension="tar.gz", + ) + version( "4.4.0", sha256="37250dbef6e97b16dc9ab50973e8d68bc165bb4afcdaf91b3b72c8972c87deef", @@ -171,7 +178,9 @@ class Mfem(Package, CudaPackage, ROCmPackage): "libunwind", default=False, description="Enable backtrace on error support using Libunwind" ) variant("fms", default=False, when="@4.3.0:", description="Enable FMS I/O support") - # TODO: SIMD, Ginkgo, ADIOS2, HiOp, MKL CPardiso, Axom/Sidre + variant("ginkgo", default=False, when="@4.3.0:", description="Enable Ginkgo support") + variant("hiop", default=False, when="@4.4.0:", description="Enable HiOp support") + # TODO: SIMD, ADIOS2, MKL CPardiso, Axom/Sidre variant( "timer", default="auto", @@ -229,6 +238,7 @@ class Mfem(Package, CudaPackage, ROCmPackage): conflicts("^mpich@4:", when="@:4.3+mpi") depends_on("mpi", when="+mpi") + depends_on("hipsparse", when="@4.4.0:+rocm") depends_on("hypre@2.10.0:2.13", when="@:3.3+mpi") depends_on("hypre@:2.20.0", when="@3.4:4.2+mpi") depends_on("hypre@:2.23.0", when="@4.3.0+mpi") @@ -256,11 +266,13 @@ class Mfem(Package, CudaPackage, ROCmPackage): depends_on("sundials@2.7.0+mpi+hypre", when="@:3.3.0+sundials+mpi") depends_on("sundials@2.7.0:", when="@3.3.2:+sundials~mpi") depends_on("sundials@2.7.0:+mpi+hypre", when="@3.3.2:+sundials+mpi") - depends_on("sundials@5.0.0:5", when="@4.0.1-xsdk:+sundials~mpi") - depends_on("sundials@5.0.0:5+mpi+hypre", when="@4.0.1-xsdk:+sundials+mpi") + depends_on("sundials@5.0.0:5", when="@4.0.1-xsdk:4.4+sundials~mpi") + depends_on("sundials@5.0.0:5+mpi+hypre", when="@4.0.1-xsdk:4.4+sundials+mpi") + depends_on("sundials@5.0.0:", when="@4.5.0:+sundials~mpi") + depends_on("sundials@5.0.0:+mpi+hypre", when="@4.5.0:+sundials+mpi") for sm_ in CudaPackage.cuda_arch_values: depends_on( - "sundials@5.4.0:5+cuda cuda_arch={0}".format(sm_), + "sundials@5.4.0:+cuda cuda_arch={0}".format(sm_), when="@4.2.0:+sundials+cuda cuda_arch={0}".format(sm_), ) depends_on("pumi", when="+pumi~shared") @@ -320,6 +332,29 @@ class Mfem(Package, CudaPackage, ROCmPackage): depends_on("conduit@0.3.1:,master:", when="+conduit") depends_on("conduit+mpi", when="+conduit+mpi") depends_on("libfms@0.2.0:", when="+fms") + depends_on("ginkgo@1.4.0:", when="+ginkgo") + for sm_ in CudaPackage.cuda_arch_values: + depends_on( + "ginkgo+cuda cuda_arch={0}".format(sm_), + when="+ginkgo+cuda cuda_arch={0}".format(sm_), + ) + for gfx in ROCmPackage.amdgpu_targets: + depends_on( + "ginkgo+rocm amdgpu_target={0}".format(gfx), + when="+ginkgo+rocm amdgpu_target={0}".format(gfx), + ) + depends_on("hiop@0.4.6:~mpi", when="+hiop~mpi") + depends_on("hiop@0.4.6:+mpi", when="+hiop+mpi") + for sm_ in CudaPackage.cuda_arch_values: + depends_on( + "hiop+cuda cuda_arch={0}".format(sm_), + when="+hiop+cuda cuda_arch={0}".format(sm_), + ) + for gfx in ROCmPackage.amdgpu_targets: + depends_on( + "hiop+rocm amdgpu_target={0}".format(gfx), + when="+hiop+rocm amdgpu_target={0}".format(gfx), + ) # The MFEM 4.0.0 SuperLU interface fails when using hypre@2.16.0 and # superlu-dist@6.1.1. See https://github.com/mfem/mfem/issues/983. @@ -488,6 +523,9 @@ def find_optional_library(name, prefix): else: mfem_mpiexec = "jsrun" mfem_mpiexec_np = "-p" + elif "FLUX_JOB_ID" in os.environ: + mfem_mpiexec = "flux mini run" + mfem_mpiexec_np = "-n" metis5_str = "NO" if ("+metis" in spec) and spec["metis"].satisfies("@5:"): @@ -530,11 +568,32 @@ def find_optional_library(name, prefix): "MFEM_USE_CEED=%s" % yes_no("+libceed"), "MFEM_USE_UMPIRE=%s" % yes_no("+umpire"), "MFEM_USE_FMS=%s" % yes_no("+fms"), + "MFEM_USE_GINKGO=%s" % yes_no("+ginkgo"), + "MFEM_USE_HIOP=%s" % yes_no("+hiop"), "MFEM_MPIEXEC=%s" % mfem_mpiexec, "MFEM_MPIEXEC_NP=%s" % mfem_mpiexec_np, "MFEM_USE_EXCEPTIONS=%s" % yes_no("+exceptions"), ] + # Determine C++ standard to use: + cxxstd = None + if self.spec.satisfies("@4.0.0:"): + cxxstd = "11" + if self.spec.satisfies("^raja@2022.03.0:"): + cxxstd = "14" + if self.spec.satisfies("^umpire@2022.03.0:"): + cxxstd = "14" + if self.spec.satisfies("^sundials@6.4.0:"): + cxxstd = "14" + if self.spec.satisfies("^ginkgo"): + cxxstd = "14" + cxxstd_flag = None + if cxxstd: + if "+cuda" in spec: + cxxstd_flag = "-std=c++" + cxxstd + else: + cxxstd_flag = getattr(self.compiler, "cxx" + cxxstd + "_flag") + cxxflags = spec.compiler_flags["cxxflags"] if cxxflags: @@ -557,16 +616,16 @@ def find_optional_library(name, prefix): "-x=cu --expt-extended-lambda -arch=sm_%s" % cuda_arch, "-ccbin %s" % (spec["mpi"].mpicxx if "+mpi" in spec else env["CXX"]), ] - if self.spec.satisfies("@4.0.0:"): - if "+cuda" in spec: - cxxflags.append("-std=c++11") - else: - cxxflags.append(self.compiler.cxx11_flag) + if cxxstd_flag: + cxxflags.append(cxxstd_flag) # The cxxflags are set by the spack c++ compiler wrapper. We also # set CXXFLAGS explicitly, for clarity, and to properly export the # cxxflags in the variable MFEM_CXXFLAGS in config.mk. options += ["CXXFLAGS=%s" % " ".join(cxxflags)] + elif cxxstd_flag: + options += ["BASE_FLAGS=%s" % cxxstd_flag] + # Treat any 'CXXFLAGS' in the environment as extra c++ flags which are # handled through the 'CPPFLAGS' makefile variable in MFEM. Also, unset # 'CXXFLAGS' from the environment to prevent it from overriding the @@ -589,9 +648,12 @@ def find_optional_library(name, prefix): if "+cuda" in hypre: hypre_gpu_libs = " -lcusparse -lcurand" elif "+rocm" in hypre: - hypre_gpu_libs = " " + ld_flags_from_dirs( - [env["ROCM_PATH"] + "/lib"], ["rocsparse", "rocrand"] - ) + hypre_rocm_libs = LibraryList([]) + if "^rocsparse" in hypre: + hypre_rocm_libs += hypre["rocsparse"].libs + if "^rocrand" in hypre: + hypre_rocm_libs += hypre["rocrand"].libs + hypre_gpu_libs = " " + ld_flags_from_library_list(hypre_rocm_libs) options += [ "HYPRE_OPT=-I%s" % hypre.prefix.include, "HYPRE_LIB=%s%s" % (ld_flags_from_library_list(all_hypre_libs), hypre_gpu_libs), @@ -804,6 +866,15 @@ def find_optional_library(name, prefix): if "+rocm" in spec: amdgpu_target = ",".join(spec.variants["amdgpu_target"].value) options += ["HIP_CXX=%s" % spec["hip"].hipcc, "HIP_ARCH=%s" % amdgpu_target] + if "^hipsparse" in spec: # hipsparse is needed @4.4.0:+rocm + # Note: MFEM's defaults.mk want to find librocsparse.* in + # $(HIP_DIR)/lib, so we set HIP_DIR to be the prefix of + # rocsparse (which is a dependency of hipsparse). + options += [ + "HIP_DIR=%s" % spec["rocsparse"].prefix, + "HIP_OPT=%s" % spec["hipsparse"].headers.cpp_flags, + "HIP_LIB=%s" % ld_flags_from_library_list(spec["hipsparse"].libs), + ] if "+occa" in spec: options += [ @@ -895,6 +966,21 @@ def find_optional_library(name, prefix): "FMS_LIB=%s" % ld_flags_from_library_list(libfms.libs), ] + if "+ginkgo" in spec: + ginkgo = spec["ginkgo"] + options += [ + "GINKGO_DIR=%s" % ginkgo.prefix, + "GINKGO_BUILD_TYPE=%s" % ginkgo.variants["build_type"].value, + ] + + if "+hiop" in spec: + hiop = spec["hiop"] + lapack_blas = spec["lapack"].libs + spec["blas"].libs + options += [ + "HIOP_OPT=-I%s" % hiop.prefix.include, + "HIOP_LIB=%s" % ld_flags_from_library_list(hiop.libs + lapack_blas), + ] + make("config", *options, parallel=False) make("info", parallel=False) diff --git a/var/spack/repos/builtin/packages/mfem/test_builds.sh b/var/spack/repos/builtin/packages/mfem/test_builds.sh index 9b534836ec7..5c43f875126 100755 --- a/var/spack/repos/builtin/packages/mfem/test_builds.sh +++ b/var/spack/repos/builtin/packages/mfem/test_builds.sh @@ -8,7 +8,7 @@ rocm_arch="gfx908" spack_jobs='' # spack_jobs='-j 128' -mfem='mfem@4.4.0'${compiler} +mfem='mfem@4.5.0'${compiler} mfem_dev='mfem@develop'${compiler} backends='+occa+raja+libceed' @@ -28,32 +28,29 @@ builds=( # preferred version: ${mfem} ${mfem}'~mpi~metis~zlib' - # TODO: add back '+gslib' when the gslib test is fixed. - # TODO: add back '+slepc' when its build is fixed. - ${mfem}"$backends"'+superlu-dist+strumpack+suite-sparse+petsc \ - +sundials+pumi+mpfr+netcdf+zlib+gnutls+libunwind+conduit \ + ${mfem}"$backends"'+superlu-dist+strumpack+suite-sparse+petsc+slepc+gslib \ + +sundials+pumi+mpfr+netcdf+zlib+gnutls+libunwind+conduit+ginkgo+hiop \ '"$backends_specs $strumpack_spec $petsc_spec $hdf5_spec" ${mfem}'~mpi \ '"$backends"'+suite-sparse+sundials+gslib+mpfr+netcdf \ - +zlib+gnutls+libunwind+conduit \ + +zlib+gnutls+libunwind+conduit+ginkgo+hiop \ '"$backends_specs $hdf5_spec"' ^sundials~mpi' # develop version, shared builds: ${mfem_dev}'+shared~static' ${mfem_dev}'+shared~static~mpi~metis~zlib' # NOTE: Shared build with +gslib works on mac but not on linux - # TODO: add back '+gslib' when the gslib test is fixed and the above NOTE + # TODO: add back '+gslib' when the above NOTE # is addressed. - # TODO: add back '+slepc' when its build is fixed. ${mfem_dev}'+shared~static \ - '"$backends"'+superlu-dist+strumpack+suite-sparse+petsc \ - +sundials+pumi+mpfr+netcdf+zlib+gnutls+libunwind+conduit \ + '"$backends"'+superlu-dist+strumpack+suite-sparse+petsc+slepc \ + +sundials+pumi+mpfr+netcdf+zlib+gnutls+libunwind+conduit+ginkgo+hiop \ '"$backends_specs $strumpack_spec $petsc_spec $hdf5_spec" # NOTE: Shared build with +gslib works on mac but not on linux # TODO: add back '+gslib' when the above NOTE is addressed. ${mfem_dev}'+shared~static~mpi \ '"$backends"'+suite-sparse+sundials+mpfr+netcdf \ - +zlib+gnutls+libunwind+conduit \ + +zlib+gnutls+libunwind+conduit+ginkgo+hiop \ '"$backends_specs $hdf5_spec"' ^sundials~mpi' ) @@ -67,8 +64,7 @@ builds2=( ${mfem}'+sundials~mpi ^sundials~mpi' ${mfem}'+sundials' ${mfem}'+pumi' - # TODO: uncomment the next line when the gslib test is fixed. - # ${mfem}'+gslib' + ${mfem}'+gslib' ${mfem}'+netcdf~mpi' ${mfem}'+netcdf' ${mfem}'+mpfr' @@ -77,10 +73,11 @@ builds2=( ${mfem}'+conduit' ${mfem}'+umpire' ${mfem}'+petsc'" $petsc_spec" - # TODO: uncomment the next line when the slepc build is fixed. - # ${mfem}'+petsc+slepc'" $petsc_spec" - # TODO: uncomment the next line when the threadsafe build is fixed. - # ${mfem}'+threadsafe' + ${mfem}'+petsc+slepc'" $petsc_spec" + ${mfem}'+ginkgo' + ${mfem}'+hiop' + ${mfem}'+threadsafe' + # # develop version ${mfem_dev}"$backends $backends_specs" ${mfem_dev}'+superlu-dist' @@ -90,8 +87,7 @@ builds2=( ${mfem_dev}'+sundials~mpi ^sundials~mpi' ${mfem_dev}'+sundials' ${mfem_dev}'+pumi' - # TODO: uncomment the next line when the gslib test is fixed. - # ${mfem_dev}'+gslib' + ${mfem_dev}'+gslib' ${mfem_dev}'+netcdf~mpi' ${mfem_dev}'+netcdf' ${mfem_dev}'+mpfr' @@ -101,8 +97,9 @@ builds2=( ${mfem_dev}'+umpire' ${mfem_dev}'+petsc'" $petsc_spec" ${mfem_dev}'+petsc+slepc'" $petsc_spec" - # TODO: uncomment the next line when the threadsafe build is fixed. - # ${mfem_dev}'+threadsafe' + ${mfem_dev}'+ginkgo' + ${mfem_dev}'+hiop' + ${mfem_dev}'+threadsafe' ) @@ -125,7 +122,7 @@ builds_cuda=( # TODO: add back "+petsc+slepc $petsc_spec_cuda" when it works. ${mfem}'+cuda+openmp+raja+occa cuda_arch='"${cuda_arch}"' \ +strumpack+suite-sparse \ - +sundials+pumi+mpfr+netcdf+zlib+gnutls+libunwind+conduit \ + +sundials+pumi+mpfr+netcdf+zlib+gnutls+libunwind+conduit+ginkgo+hiop \ ^raja+cuda+openmp'" $strumpack_cuda_spec"' \ '"$hdf5_spec" @@ -138,7 +135,7 @@ builds_cuda=( # TODO: add back "+sundials" when it's supported with '^hypre+cuda'. ${mfem}'+cuda+openmp+raja+occa cuda_arch='"${cuda_arch}"' \ +suite-sparse \ - +pumi+mpfr+netcdf+zlib+gnutls+libunwind+conduit \ + +pumi+mpfr+netcdf+zlib+gnutls+libunwind+conduit+ginkgo+hiop \ ^raja+cuda+openmp ^hypre+cuda \ '"$hdf5_spec" @@ -164,7 +161,7 @@ builds_cuda=( # TODO: add back "+petsc+slepc $petsc_spec_cuda" when it works. ${mfem_dev}'+cuda+openmp+raja+occa cuda_arch='"${cuda_arch}"' \ +strumpack+suite-sparse \ - +sundials+pumi+mpfr+netcdf+zlib+gnutls+libunwind+conduit \ + +sundials+pumi+mpfr+netcdf+zlib+gnutls+libunwind+conduit+ginkgo+hiop \ ^raja+cuda+openmp'" $strumpack_cuda_spec"' \ '"$hdf5_spec" @@ -177,7 +174,7 @@ builds_cuda=( # TODO: add back "+sundials" when it's supported with '^hypre+cuda'. ${mfem_dev}'+cuda+openmp+raja+occa cuda_arch='"${cuda_arch}"' \ +suite-sparse \ - +pumi+mpfr+netcdf+zlib+gnutls+libunwind+conduit \ + +pumi+mpfr+netcdf+zlib+gnutls+libunwind+conduit+ginkgo+hiop \ ^raja+cuda+openmp ^hypre+cuda \ '"$hdf5_spec" ) @@ -200,7 +197,7 @@ builds_rocm=( # TODO: add "+petsc+slepc $petsc_spec_rocm" when it is supported. ${mfem}'+rocm+openmp+raja+occa+libceed amdgpu_target='"${rocm_arch}"' \ +strumpack+suite-sparse \ - +sundials+pumi+mpfr+netcdf+zlib+gnutls+libunwind+conduit \ + +sundials+pumi+mpfr+netcdf+zlib+gnutls+libunwind+conduit+ginkgo+hiop \ ^raja+rocm~openmp ^occa~cuda'" $strumpack_rocm_spec"' \ '"$hdf5_spec" @@ -212,7 +209,7 @@ builds_rocm=( # TODO: add back "+sundials" when it's supported with '^hypre+rocm'. ${mfem}'+rocm+openmp+raja+occa+libceed amdgpu_target='"${rocm_arch}"' \ +suite-sparse \ - +pumi+mpfr+netcdf+zlib+gnutls+libunwind+conduit \ + +pumi+mpfr+netcdf+zlib+gnutls+libunwind+conduit+ginkgo+hiop \ ^raja+rocm~openmp ^occa~cuda ^hypre+rocm \ '"$hdf5_spec" @@ -238,9 +235,9 @@ for bld in "${run_builds[@]}"; do printf " %s\n" "${bld}" printf "%s\n" "${SEP}" eval bbb="\"${bld}\"" - spack spec -I $bbb || exit 1 + spack spec --fresh -I $bbb || exit 1 printf "%s\n" "${sep}" - spack install $spack_jobs --test=root $bbb || exit 2 + spack install $spack_jobs --fresh --test=root $bbb || exit 2 done # Uninstall all mfem builds: From 999c460b1e70c9e1af838b0dda56c6137ff3c670 Mon Sep 17 00:00:00 2001 From: eugeneswalker <38933153+eugeneswalker@users.noreply.github.com> Date: Sat, 29 Oct 2022 16:32:46 -0700 Subject: [PATCH 264/442] e4s ci: add mfem +rocm (#31604) --- share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml index d56a8eaa374..7a14a044966 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml @@ -217,6 +217,7 @@ spack: - hypre +rocm amdgpu_target=gfx90a - kokkos +rocm amdgpu_target=gfx90a - magma ~cuda +rocm amdgpu_target=gfx90a + - mfem +rocm amdgpu_target=gfx90a - papi +rocm amdgpu_target=gfx90a - petsc +rocm amdgpu_target=gfx90a - raja ~openmp +rocm amdgpu_target=gfx90a From 7d5446740c75bc315c7115c68e2682819db08464 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mos=C3=A8=20Giordano?= Date: Sun, 30 Oct 2022 11:13:47 +0000 Subject: [PATCH 265/442] libgit2: add v1.4.4 and v1.5.0 (#33604) --- var/spack/repos/builtin/packages/libgit2/package.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/var/spack/repos/builtin/packages/libgit2/package.py b/var/spack/repos/builtin/packages/libgit2/package.py index d16090f0f94..2c6f5d1cdd2 100644 --- a/var/spack/repos/builtin/packages/libgit2/package.py +++ b/var/spack/repos/builtin/packages/libgit2/package.py @@ -18,6 +18,8 @@ class Libgit2(CMakePackage): maintainers = ["AndrewGaspar"] + version("1.5.0", sha256="8de872a0f201b33d9522b817c92e14edb4efad18dae95cf156cf240b2efff93e") + version("1.4.4", sha256="e9923e9916a32f54c661d55d79c28fa304cb23617639e68bff9f94d3e18f2d4b") version("1.4.3", sha256="f48b961e463a9e4e7e7e58b21a0fb5a9b2a1d24d9ba4d15870a0c9b8ad965163") version("1.4.2", sha256="901c2b4492976b86477569502a41c31b274b69adc177149c02099ea88404ef19") version("1.4.1", sha256="fccd371a271133e29d002dd207490d22a0c9b06992b874b8edb8366532a94f54") From 20fafe6a4628b770deba275fc37d4b1e8e35a3f0 Mon Sep 17 00:00:00 2001 From: Diego Alvarez Date: Sun, 30 Oct 2022 16:25:41 -0300 Subject: [PATCH 266/442] openjdk: add 11.0.16.1+1, 11.0.17+8, 17.0.4.1+1, 17.0.5+8 (#33355) --- .../repos/builtin/packages/openjdk/package.py | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/var/spack/repos/builtin/packages/openjdk/package.py b/var/spack/repos/builtin/packages/openjdk/package.py index f6239500250..6382dc3688a 100644 --- a/var/spack/repos/builtin/packages/openjdk/package.py +++ b/var/spack/repos/builtin/packages/openjdk/package.py @@ -18,6 +18,38 @@ # format returned by platform.system() and 'arch' by platform.machine() _versions = { + "17.0.5_8": { + "Linux-x86_64": ( + "482180725ceca472e12a8e6d1a4af23d608d78287a77d963335e2a0156a020af", + "https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.5%2B8/OpenJDK17U-jdk_x64_linux_hotspot_17.0.5_8.tar.gz", + ), + "Linux-aarch64": ( + "1c26c0e09f1641a666d6740d802beb81e12180abaea07b47c409d30c7f368109", + "https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.5%2B8/OpenJDK17U-jdk_aarch64_linux_hotspot_17.0.5_8.tar.gz", + ), + }, + "17.0.4.1_1": { + "Linux-x86_64": ( + "5fbf8b62c44f10be2efab97c5f5dbf15b74fae31e451ec10abbc74e54a04ff44", + "https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.4.1%2B1/OpenJDK17U-jdk_x64_linux_hotspot_17.0.4.1_1.tar.gz", + ), + "Linux-aarch64": ( + "3c7460de77421284b38b4e57cb1bd584a6cef55c34fc51a12270620544de2b8a", + "https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.4.1%2B1/OpenJDK17U-jdk_aarch64_linux_hotspot_17.0.4.1_1.tar.gz", + ), + "Linux-ppc64le": ( + "cbedd0a1428b3058d156e99e8e9bc8769e0d633736d6776a4c4d9136648f2fd1", + "https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.4.1%2B1/OpenJDK17U-jdk_ppc64le_linux_hotspot_17.0.4.1_1.tar.gz", + ), + "Darwin-x86_64": ( + "ac21a5a87f7cfa00212ab7c41f7eb80ca33640d83b63ad850be811c24095d61a", + "https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.4.1%2B1/OpenJDK17U-jdk_x64_mac_hotspot_17.0.4.1_1.tar.gz", + ), + "Darwin-aarch64": ( + "3a976943a9e6a635e68e2b06bd093fc096aad9f5894acda673d3bea0cb3a6f38", + "https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.4.1%2B1/OpenJDK17U-jdk_aarch64_mac_hotspot_17.0.4.1_1.tar.gz", + ), + }, "17.0.3_7": { "Linux-x86_64": ( "81f5bed21077f9fbb04909b50391620c78b9a3c376593c0992934719c0de6b73", @@ -94,6 +126,46 @@ "https://download.java.net/java/GA/jdk16.0.2/d4a915d82b4c4fbb9bde534da945d746/7/GPL/openjdk-16.0.2_linux-aarch64_bin.tar.gz", ), }, + "11.0.17_8": { + "Linux-x86_64": ( + "b8d46ed08ef4859476fe6421a7690d899ed83dce63f13fd894f994043177ef3c", + "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.17%2B8/OpenJDK11U-jdk_x64_linux_hotspot_11.0.17_8.tar.gz", + ), + "Linux-aarch64": ( + "d18b5dd73fce9edd5c58f623a1173f9ee2d45023836b8753b96beae51673a432", + "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.17%2B8/OpenJDK11U-jdk_aarch64_linux_hotspot_11.0.17_8.tar.gz", + ), + "Linux-ppc64le": ( + "18c636bd103e240d29cdb30d7867720ea9fb9ff7c645738bfb4d5b8027269263", + "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.17%2B8/OpenJDK11U-jdk_ppc64le_linux_hotspot_11.0.17_8.tar.gz", + ), + "Darwin-aarch64": ( + "79b18cbd398b67a52ebaf033dfca15c7af4c1a84ec5fa68a88f3bf742bb082f7", + "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.17%2B8/OpenJDK11U-jdk_aarch64_mac_hotspot_11.0.17_8.tar.gz", + ), + }, + "11.0.16.1_1": { + "Linux-x86_64": ( + "5f6b513757d386352cf91514ed5859d1ab59364b4453e1f1c57152ba2039b8e2", + "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.16.1%2B1/OpenJDK11U-jdk_x64_linux_hotspot_11.0.16.1_1.tar.gz", + ), + "Linux-aarch64": ( + "2b89cabf0ce1c2cedadd92b798d6e9056bc27c71a06f5ba24ede5dc9c316e3e8", + "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.16.1%2B1/OpenJDK11U-jdk_aarch64_linux_hotspot_11.0.16.1_1.tar.gz", + ), + "Linux-ppc64le": ( + "b18877871eda801ccb99bb34c5d7d77fccf6adad02514110c21389632ec91024", + "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.16.1%2B1/OpenJDK11U-jdk_ppc64le_linux_hotspot_11.0.16.1_1.tar.gz", + ), + "Darwin-x86_64": ( + "723548e36e0b3e0a5a2f36a38b22ea825d3004e26054a0e254854adc57045352", + "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.16.1%2B1/OpenJDK11U-jdk_x64_mac_hotspot_11.0.16.1_1.tar.gz", + ), + "Darwin-aarch64": ( + "1953f06702d45eb54bae3ccf453b57c33de827015f5623a2dfc16e1c83e6b0a1", + "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.16.1%2B1/OpenJDK11U-jdk_aarch64_mac_hotspot_11.0.16.1_1.tar.gz", + ), + }, "11.0.15_10": { "Linux-x86_64": ( "5fdb4d5a1662f0cca73fec30f99e67662350b1fa61460fa72e91eb9f66b54d0b", From fb4be98f263be83591af09fb284405314370a564 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mos=C3=A8=20Giordano?= Date: Sun, 30 Oct 2022 23:47:20 +0000 Subject: [PATCH 267/442] utf8proc: add v2.8.0 (#33611) --- var/spack/repos/builtin/packages/utf8proc/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/utf8proc/package.py b/var/spack/repos/builtin/packages/utf8proc/package.py index ae812893b68..3ef8e53863a 100644 --- a/var/spack/repos/builtin/packages/utf8proc/package.py +++ b/var/spack/repos/builtin/packages/utf8proc/package.py @@ -13,6 +13,7 @@ class Utf8proc(CMakePackage): homepage = "https://juliastrings.github.io/utf8proc/" url = "https://github.com/JuliaStrings/utf8proc/archive/v2.4.0.tar.gz" + version("2.8.0", sha256="a0a60a79fe6f6d54e7d411facbfcc867a6e198608f2cd992490e46f04b1bcecc") version("2.7.0", sha256="4bb121e297293c0fd55f08f83afab6d35d48f0af4ecc07523ad8ec99aa2b12a1") version("2.6.1", sha256="4c06a9dc4017e8a2438ef80ee371d45868bda2237a98b26554de7a95406b283b") version("2.6.0", sha256="b36ce1534b8035e7febd95c031215ed279ee9d31cf9b464e28b4c688133b22c5") From 616d5a89d424391d51becf9b89953199c1f622de Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Mon, 31 Oct 2022 10:08:16 +0100 Subject: [PATCH 268/442] _replace_prefix_bin performance improvements (#33590) - single pass over the binary data matching all prefixes - collect offsets and replacement strings - do in-place updates with `fseek` / `fwrite`, since typically our replacement touch O(few bytes) while the file is O(many megabytes) - be nice: leave the file untouched if some string can't be replaced --- lib/spack/spack/relocate.py | 47 ++++++++++++++------------------ lib/spack/spack/test/relocate.py | 30 ++++++++++++++++++++ 2 files changed, 51 insertions(+), 26 deletions(-) diff --git a/lib/spack/spack/relocate.py b/lib/spack/spack/relocate.py index 0d7525eb05f..dca55af17ea 100644 --- a/lib/spack/spack/relocate.py +++ b/lib/spack/spack/relocate.py @@ -467,40 +467,35 @@ def _replace_prefix_bin(filename, byte_prefixes): """Replace all the occurrences of the old install prefix with a new install prefix in binary files. - The new install prefix is prefixed with ``os.sep`` until the + The new install prefix is prefixed with ``b'/'`` until the lengths of the prefixes are the same. Args: filename (str): target binary file byte_prefixes (OrderedDict): OrderedDictionary where the keys are - precompiled regex of the old prefixes and the values are the new - prefixes (uft-8 encoded) + binary strings of the old prefixes and the values are the new + binary prefixes """ + all_prefixes = re.compile(b"|".join(re.escape(prefix) for prefix in byte_prefixes.keys())) + + def padded_replacement(old): + new = byte_prefixes[old] + pad = len(old) - len(new) + if pad < 0: + raise BinaryTextReplaceError(old, new) + return new + b"/" * pad with open(filename, "rb+") as f: - data = f.read() - f.seek(0) - for orig_bytes, new_bytes in byte_prefixes.items(): - original_data_len = len(data) - # Skip this hassle if not found - if orig_bytes not in data: - continue - # We only care about this problem if we are about to replace - length_compatible = len(new_bytes) <= len(orig_bytes) - if not length_compatible: - tty.debug("Binary failing to relocate is %s" % filename) - raise BinaryTextReplaceError(orig_bytes, new_bytes) - pad_length = len(orig_bytes) - len(new_bytes) - padding = os.sep * pad_length - padding = padding.encode("utf-8") - data = data.replace(orig_bytes, new_bytes + padding) - # Really needs to be the same length - if not len(data) == original_data_len: - print("Length of pad:", pad_length, "should be", len(padding)) - print(new_bytes, "was to replace", orig_bytes) - raise BinaryStringReplacementError(filename, original_data_len, len(data)) - f.write(data) - f.truncate() + # Register what replacement string to put on what offsets in the file. + replacements_at_offset = [ + (padded_replacement(m.group(0)), m.start()) + for m in re.finditer(all_prefixes, f.read()) + ] + + # Apply the replacements + for replacement, offset in replacements_at_offset: + f.seek(offset) + f.write(replacement) def relocate_macho_binaries( diff --git a/lib/spack/spack/test/relocate.py b/lib/spack/spack/test/relocate.py index 8e8819ca48a..4c9dd8be666 100644 --- a/lib/spack/spack/test/relocate.py +++ b/lib/spack/spack/test/relocate.py @@ -7,6 +7,7 @@ import re import shutil import sys +from collections import OrderedDict import pytest @@ -501,3 +502,32 @@ def test_utf8_paths_to_single_binary_regex(): # Match "unsafe" dir name string = b"don't match /safe/a/path but do match /safe/[a-z]/file" assert regex.search(string).group(0) == b"/safe/[a-z]/file" + + +def test_ordered_replacement(tmpdir): + # This tests whether binary text replacement respects order, so that + # a long package prefix is replaced before a shorter sub-prefix like + # the root of the spack store (as a fallback). + def replace_and_expect(prefix_map, before, after): + file = str(tmpdir.join("file")) + with open(file, "wb") as f: + f.write(before) + spack.relocate._replace_prefix_bin(file, prefix_map) + with open(file, "rb") as f: + assert f.read() == after + + replace_and_expect( + OrderedDict( + [(b"/old-spack/opt/specific-package", b"/first"), (b"/old-spack/opt", b"/second")] + ), + b"Binary with /old-spack/opt/specific-package and /old-spack/opt", + b"Binary with /first///////////////////////// and /second///////", + ) + + replace_and_expect( + OrderedDict( + [(b"/old-spack/opt", b"/second"), (b"/old-spack/opt/specific-package", b"/first")] + ), + b"Binary with /old-spack/opt/specific-package and /old-spack/opt", + b"Binary with /second////////specific-package and /second///////", + ) From 1ab888cdc1b0a42c9d855aacc0bacab6d7efb788 Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Mon, 31 Oct 2022 10:41:59 +0100 Subject: [PATCH 269/442] remove sequential filter in binary relo (#33608) Currently there's a slow sequential step in binary relocation where all strings of a binary are collected, with rpaths removed, and then filtered for the old install root. This is completely unnecessary, and also incorrect, since we replace more than just the old install root in the prefix to prefix mapping. And in fact the prefix to prefix mapping is parallel, and a single pass. So even as an optimization, this filter makes no sense anymore. Therefor we remove it --- lib/spack/spack/binary_distribution.py | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/lib/spack/spack/binary_distribution.py b/lib/spack/spack/binary_distribution.py index 7c62c58cb19..68b270c390d 100644 --- a/lib/spack/spack/binary_distribution.py +++ b/lib/spack/spack/binary_distribution.py @@ -1644,27 +1644,15 @@ def is_backup_file(file): old_prefix, new_prefix, ) - # Relocate links to the new install prefix - links = [link for link in buildinfo.get("relocate_links", [])] - relocate.relocate_links(links, old_layout_root, old_prefix, new_prefix) + + # Relocate links to the new install prefix + links = [link for link in buildinfo.get("relocate_links", [])] + relocate.relocate_links(links, old_layout_root, old_prefix, new_prefix) # For all buildcaches # relocate the install prefixes in text files including dependencies relocate.unsafe_relocate_text(text_names, prefix_to_prefix_text) - paths_to_relocate = [old_prefix, old_layout_root] - paths_to_relocate.extend(prefix_to_hash.keys()) - files_to_relocate = list( - filter( - lambda pathname: not relocate.file_is_relocatable( - pathname, paths_to_relocate=paths_to_relocate - ), - map( - lambda filename: os.path.join(workdir, filename), - buildinfo["relocate_binaries"], - ), - ) - ) # relocate the install prefixes in binary files including dependencies relocate.unsafe_relocate_text_bin(files_to_relocate, prefix_to_prefix_bin) From a4930c74cbcb403c118495f56f8d3778976f2955 Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Mon, 31 Oct 2022 13:49:19 +0100 Subject: [PATCH 270/442] Make --backtrace show non-SpackError backtraces (#33540) --- lib/spack/spack/main.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/spack/spack/main.py b/lib/spack/spack/main.py index 998d0e20225..4c3f19d75d5 100644 --- a/lib/spack/spack/main.py +++ b/lib/spack/spack/main.py @@ -107,6 +107,9 @@ spack_working_dir = None spack_ld_library_path = os.environ.get("LD_LIBRARY_PATH", "") +#: Whether to print backtraces on error +SHOW_BACKTRACE = False + def set_working_dir(): """Change the working directory to getcwd, or spack prefix if no cwd.""" @@ -569,6 +572,8 @@ def setup_main_options(args): if args.debug or args.backtrace: spack.error.debug = True + global SHOW_BACKTRACE + SHOW_BACKTRACE = True if args.debug: spack.util.debug.register_interrupt_handler() @@ -1002,7 +1007,7 @@ def main(argv=None): e.die() # gracefully die on any SpackErrors except KeyboardInterrupt: - if spack.config.get("config:debug"): + if spack.config.get("config:debug") or SHOW_BACKTRACE: raise sys.stderr.write("\n") tty.error("Keyboard interrupt.") @@ -1012,12 +1017,12 @@ def main(argv=None): return signal.SIGINT except SystemExit as e: - if spack.config.get("config:debug"): + if spack.config.get("config:debug") or SHOW_BACKTRACE: traceback.print_exc() return e.code except Exception as e: - if spack.config.get("config:debug"): + if spack.config.get("config:debug") or SHOW_BACKTRACE: raise tty.error(e) return 3 From a93b3643c6842be2888c441cd08a6a7e368eb367 Mon Sep 17 00:00:00 2001 From: Satish Balay Date: Mon, 31 Oct 2022 09:03:26 -0500 Subject: [PATCH 271/442] exago: query and use MPI compilers from spack (#33598) * exago: query and use MPI compilers from spack * exago: requires explicit location of mpi.h for nvcc --- var/spack/repos/builtin/packages/exago/package.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/var/spack/repos/builtin/packages/exago/package.py b/var/spack/repos/builtin/packages/exago/package.py index 06c3ad81733..c3a48e23af4 100644 --- a/var/spack/repos/builtin/packages/exago/package.py +++ b/var/spack/repos/builtin/packages/exago/package.py @@ -136,6 +136,17 @@ def cmake_args(self): args = [] spec = self.spec + if "~mpi" in self.spec: + args.append(self.define("CMAKE_C_COMPILER", os.environ["CC"])) + args.append(self.define("CMAKE_CXX_COMPILER", os.environ["CXX"])) + else: + args.append(self.define("CMAKE_C_COMPILER", spec["mpi"].mpicc)) + args.append(self.define("CMAKE_CXX_COMPILER", spec["mpi"].mpicxx)) + args.append(self.define("MPI_C_COMPILER", spec["mpi"].mpicc)) + args.append(self.define("MPI_CXX_COMPILER", spec["mpi"].mpicxx)) + if "+cuda" in spec: + args.append(self.define("MPI_CXX_HEADER_DIR", spec["mpi"].prefix.include)) + # NOTE: If building with spack develop on a cluster, you may want to # change the ctest launch command to use your job scheduler like so: # From 7db38433e21167810ba4ab5ae4f7f2fdbad14ea9 Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Mon, 31 Oct 2022 15:17:40 +0100 Subject: [PATCH 272/442] gmake: add a patch so dirs are not executed (#33578) --- .../findprog-in-ignore-directories.patch | 132 ++++++++++++++++++ .../repos/builtin/packages/gmake/package.py | 3 + 2 files changed, 135 insertions(+) create mode 100644 var/spack/repos/builtin/packages/gmake/findprog-in-ignore-directories.patch diff --git a/var/spack/repos/builtin/packages/gmake/findprog-in-ignore-directories.patch b/var/spack/repos/builtin/packages/gmake/findprog-in-ignore-directories.patch new file mode 100644 index 00000000000..4f44eccdf37 --- /dev/null +++ b/var/spack/repos/builtin/packages/gmake/findprog-in-ignore-directories.patch @@ -0,0 +1,132 @@ +From 6e6abd0cdfe4bb96f6412aebc511f10bf254a820 Mon Sep 17 00:00:00 2001 +From: Bruno Haible +Date: Sat, 23 May 2020 12:19:34 +0200 +Subject: [PATCH] findprog-in: Ignore directories. + +Reported by Frederick Eaton via Dmitry Goncharov in +. + +* lib/findprog-in.c (find_in_given_path): When the file found is a +directory, set errno to EACCES and, during a PATH search, continue +searching. +* modules/findprog-in (Depends-on): Add sys_stat, stat. +--- + ChangeLog | 10 ++++++ + lib/findprog-in.c | 75 ++++++++++++++++++++++++++++++--------------- + modules/findprog-in | 2 ++ + 3 files changed, 62 insertions(+), 25 deletions(-) + +diff --git a/lib/findprog-in.c b/lib/findprog-in.c +index c254f2f58..0f76e36ca 100644 +--- a/lib/findprog-in.c ++++ b/lib/findprog-in.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + #include "filename.h" + #include "concat-filename.h" +@@ -58,8 +59,8 @@ static const char * const suffixes[] = + /* Note: The cmd.exe program does a different lookup: It searches according + to the PATHEXT environment variable. + See . +- Also, it executes files ending .bat and .cmd directly without letting the +- kernel interpret the program file. */ ++ Also, it executes files ending in .bat and .cmd directly without letting ++ the kernel interpret the program file. */ + #elif defined __CYGWIN__ + "", ".exe", ".com" + #elif defined __EMX__ +@@ -136,14 +137,26 @@ find_in_given_path (const char *progname, const char *path, + call access() despite its design flaw. */ + if (eaccess (progpathname, X_OK) == 0) + { +- /* Found! */ +- if (strcmp (progpathname, progname) == 0) ++ /* Check that the progpathname does not point to a ++ directory. */ ++ struct stat statbuf; ++ ++ if (stat (progpathname, &statbuf) >= 0) + { +- free (progpathname); +- return progname; ++ if (! S_ISDIR (statbuf.st_mode)) ++ { ++ /* Found! */ ++ if (strcmp (progpathname, progname) == 0) ++ { ++ free (progpathname); ++ return progname; ++ } ++ else ++ return progpathname; ++ } ++ ++ errno = EACCES; + } +- else +- return progpathname; + } + + if (errno != ENOENT) +@@ -210,25 +223,37 @@ find_in_given_path (const char *progname, const char *path, + call access() despite its design flaw. */ + if (eaccess (progpathname, X_OK) == 0) + { +- /* Found! */ +- if (strcmp (progpathname, progname) == 0) ++ /* Check that the progpathname does not point to a ++ directory. */ ++ struct stat statbuf; ++ ++ if (stat (progpathname, &statbuf) >= 0) + { +- free (progpathname); +- +- /* Add the "./" prefix for real, that +- xconcatenated_filename() optimized away. This +- avoids a second PATH search when the caller uses +- execl/execv/execlp/execvp. */ +- progpathname = +- XNMALLOC (2 + strlen (progname) + 1, char); +- progpathname[0] = '.'; +- progpathname[1] = NATIVE_SLASH; +- memcpy (progpathname + 2, progname, +- strlen (progname) + 1); +- } ++ if (! S_ISDIR (statbuf.st_mode)) ++ { ++ /* Found! */ ++ if (strcmp (progpathname, progname) == 0) ++ { ++ free (progpathname); ++ ++ /* Add the "./" prefix for real, that ++ xconcatenated_filename() optimized away. ++ This avoids a second PATH search when the ++ caller uses execl/execv/execlp/execvp. */ ++ progpathname = ++ XNMALLOC (2 + strlen (progname) + 1, char); ++ progpathname[0] = '.'; ++ progpathname[1] = NATIVE_SLASH; ++ memcpy (progpathname + 2, progname, ++ strlen (progname) + 1); ++ } ++ ++ free (path_copy); ++ return progpathname; ++ } + +- free (path_copy); +- return progpathname; ++ errno = EACCES; ++ } + } + + if (errno != ENOENT) +-- +2.38.1 + diff --git a/var/spack/repos/builtin/packages/gmake/package.py b/var/spack/repos/builtin/packages/gmake/package.py index 98792e2e381..7cccbacb01d 100644 --- a/var/spack/repos/builtin/packages/gmake/package.py +++ b/var/spack/repos/builtin/packages/gmake/package.py @@ -64,6 +64,9 @@ class Gmake(AutotoolsPackage, GNUMirrorPackage): when="@:4.2.1", ) + # See https://savannah.gnu.org/bugs/?57962 + patch("findprog-in-ignore-directories.patch", when="@4.3") + tags = ["build-tools"] executables = ["^g?make$"] From 6990cf76a0d167db844373d8b643d42cd3282049 Mon Sep 17 00:00:00 2001 From: psakievich Date: Mon, 31 Oct 2022 09:37:38 -0600 Subject: [PATCH 273/442] Nalu-Wind: Allow for standard versions of trilinos (#33620) * Nalu-Wind: Allow for standard versions of trilinos This will allow us to utilize custom numeric versions for trilinos in `spack-manager` while we continue to develop `nalu-wind`. Pinging @eugeneswalker @jrood-nrel @tasmith4 * Update var/spack/repos/builtin/packages/nalu-wind/package.py --- var/spack/repos/builtin/packages/nalu-wind/package.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/nalu-wind/package.py b/var/spack/repos/builtin/packages/nalu-wind/package.py index b66595d9398..4fc0bf61126 100644 --- a/var/spack/repos/builtin/packages/nalu-wind/package.py +++ b/var/spack/repos/builtin/packages/nalu-wind/package.py @@ -51,7 +51,7 @@ class NaluWind(CMakePackage, CudaPackage): depends_on("mpi") depends_on("yaml-cpp@0.5.3:") depends_on( - "trilinos@stable:" + "trilinos@13:" "+exodus+tpetra+muelu+belos+ifpack2+amesos2+zoltan+stk+boost" "~superlu-dist~superlu+hdf5+shards~hypre+gtest" ) From 30d84a2716bfbbdc2fdb6185de0277ba42fc46cf Mon Sep 17 00:00:00 2001 From: Erik Schnetter Date: Mon, 31 Oct 2022 12:26:45 -0400 Subject: [PATCH 274/442] rsync: New version 3.2.7 (#33618) --- var/spack/repos/builtin/packages/rsync/package.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/var/spack/repos/builtin/packages/rsync/package.py b/var/spack/repos/builtin/packages/rsync/package.py index 357d7e7184c..29925862cfb 100644 --- a/var/spack/repos/builtin/packages/rsync/package.py +++ b/var/spack/repos/builtin/packages/rsync/package.py @@ -14,6 +14,9 @@ class Rsync(AutotoolsPackage): homepage = "https://rsync.samba.org" url = "https://download.samba.org/pub/rsync/src/rsync-3.2.4.tar.gz" + version("3.2.7", sha256="4e7d9d3f6ed10878c58c5fb724a67dacf4b6aac7340b13e488fb2dc41346f2bb") + version("3.2.6", sha256="fb3365bab27837d41feaf42e967c57bd3a47bc8f10765a3671efd6a3835454d3") + version("3.2.5", sha256="2ac4d21635cdf791867bc377c35ca6dda7f50d919a58be45057fd51600c69aba") version("3.2.4", sha256="6f761838d08052b0b6579cf7f6737d93e47f01f4da04c5d24d3447b7f2a5fad1") version("3.2.3", sha256="becc3c504ceea499f4167a260040ccf4d9f2ef9499ad5683c179a697146ce50e") version("3.2.2", sha256="644bd3841779507665211fd7db8359c8a10670c57e305b4aab61b4e40037afa8") From 214890c026cff8002bd9e8554aecb2b58c32b08c Mon Sep 17 00:00:00 2001 From: Erik Date: Mon, 31 Oct 2022 12:33:55 -0400 Subject: [PATCH 275/442] Enable Cuda for AMReX smoke test. (#28576) * Enable Cuda for AMReX smoke test. * style fix * more style fixes * change /... to join_path Co-authored-by: Tamara Dahlgren <35777542+tldahlgren@users.noreply.github.com> --- var/spack/repos/builtin/packages/amrex/package.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/var/spack/repos/builtin/packages/amrex/package.py b/var/spack/repos/builtin/packages/amrex/package.py index 55bb65fc8f2..b41bd126fad 100644 --- a/var/spack/repos/builtin/packages/amrex/package.py +++ b/var/spack/repos/builtin/packages/amrex/package.py @@ -342,8 +342,13 @@ def test(self): args = [] args.append("-S./cache/amrex/Tests/SpackSmokeTest") args.append("-DAMReX_ROOT=" + self.prefix) - args.append("-DMPI_C_COMPILER=" + self.spec["mpi"].mpicc) - args.append("-DMPI_CXX_COMPILER=" + self.spec["mpi"].mpicxx) + if "+mpi" in self.spec: + args.append("-DMPI_C_COMPILER=" + self.spec["mpi"].mpicc) + args.append("-DMPI_CXX_COMPILER=" + self.spec["mpi"].mpicxx) + + if "+cuda" in self.spec: + args.append("-DCMAKE_CUDA_COMPILER=" + join_path(self.spec["cuda"].prefix.bin, "nvcc")) + args.extend(self.cmake_args()) self.run_test(cmake_bin, args, purpose="Configure with CMake") From 222cef9b7c6efb30c7f100d33e1d809e3dc1007d Mon Sep 17 00:00:00 2001 From: "John W. Parent" <45471568+johnwparent@users.noreply.github.com> Date: Mon, 31 Oct 2022 12:36:52 -0400 Subject: [PATCH 276/442] Windows: fix library loading and enable Clingo bootstrapping (#33400) Changes to improve locating shared libraries on Windows, which in turn enables the use of Clingo. This PR attempts to establish a proper distinction between linking on Windows vs. Linux/Mac: on Windows, linking is always done with .lib files (never .dll files). This somewhat complicates the model since the Spec.lib method could return libraries that were used for both linking and loading, but since these are not always the same on Windows, it was decided to treat Spec.libs as being for link-time libraries. Additional functions are added to help dependents locate run-time libraries. * Clingo is now the default concretizer on Windows * Clingo is now the concretizer used for unit tests on Windows * Fix a permissions issue that can occur while moving Git files during fetching/staging * Packages can now implement "win_add_library_dependent" to register files/directories that include libraries that would need to link to dependency dlls * Packages can now implement "win_add_rpath" to register the locations of dlls that dependents would want to load * "Spec.libs" on Windows is updated to return link-time libraries (i.e. .lib files, rather than .dll files) * PackageBase.rpath on Windows is now updated to return the most-likely locations where .dlls will be found (which is generally in the bin/ directory) --- .github/workflows/windows_python.yml | 6 +- etc/spack/defaults/windows/config.yaml | 2 +- lib/spack/llnl/util/filesystem.py | 114 +++++++++--------- lib/spack/spack/fetch_strategy.py | 7 +- lib/spack/spack/package_base.py | 40 ++++-- lib/spack/spack/spec.py | 4 +- lib/spack/spack/test/concretize.py | 8 +- .../repos/builtin/packages/clingo/package.py | 7 ++ 8 files changed, 115 insertions(+), 73 deletions(-) diff --git a/.github/workflows/windows_python.yml b/.github/workflows/windows_python.yml index f1b828ceaa2..7e6caa0189d 100644 --- a/.github/workflows/windows_python.yml +++ b/.github/workflows/windows_python.yml @@ -23,7 +23,7 @@ jobs: python-version: 3.9 - name: Install Python packages run: | - python -m pip install --upgrade pip six pywin32 setuptools codecov pytest-cov + python -m pip install --upgrade pip six pywin32 setuptools codecov pytest-cov clingo - name: Create local develop run: | .\spack\.github\workflows\setup_git.ps1 @@ -49,7 +49,7 @@ jobs: python-version: 3.9 - name: Install Python packages run: | - python -m pip install --upgrade pip six pywin32 setuptools codecov coverage pytest-cov + python -m pip install --upgrade pip six pywin32 setuptools codecov coverage pytest-cov clingo - name: Create local develop run: | .\spack\.github\workflows\setup_git.ps1 @@ -81,7 +81,7 @@ jobs: echo F|xcopy .\spack\share\spack\qa\configuration\windows_config.yaml $env:USERPROFILE\.spack\windows\config.yaml spack external find cmake spack external find ninja - spack install abseil-cpp + spack -d install abseil-cpp make-installer: runs-on: windows-latest steps: diff --git a/etc/spack/defaults/windows/config.yaml b/etc/spack/defaults/windows/config.yaml index 956bc97c20a..367bf831cff 100644 --- a/etc/spack/defaults/windows/config.yaml +++ b/etc/spack/defaults/windows/config.yaml @@ -1,5 +1,5 @@ config: locks: false - concretizer: original + concretizer: clingo build_stage:: - '$spack/.staging' diff --git a/lib/spack/llnl/util/filesystem.py b/lib/spack/llnl/util/filesystem.py index 511f7c4f598..fa1188c133e 100644 --- a/lib/spack/llnl/util/filesystem.py +++ b/lib/spack/llnl/util/filesystem.py @@ -1083,7 +1083,11 @@ def temp_cwd(): with working_dir(tmp_dir): yield tmp_dir finally: - shutil.rmtree(tmp_dir) + kwargs = {} + if is_windows: + kwargs["ignore_errors"] = False + kwargs["onerror"] = readonly_file_handler(ignore_errors=True) + shutil.rmtree(tmp_dir, **kwargs) @contextmanager @@ -2095,7 +2099,7 @@ def find_system_libraries(libraries, shared=True): return libraries_found -def find_libraries(libraries, root, shared=True, recursive=False): +def find_libraries(libraries, root, shared=True, recursive=False, runtime=True): """Returns an iterable of full paths to libraries found in a root dir. Accepts any glob characters accepted by fnmatch: @@ -2116,6 +2120,10 @@ def find_libraries(libraries, root, shared=True, recursive=False): otherwise for static. Defaults to True. recursive (bool): if False search only root folder, if True descends top-down from the root. Defaults to False. + runtime (bool): Windows only option, no-op elsewhere. If true, + search for runtime shared libs (.DLL), otherwise, search + for .Lib files. If shared is false, this has no meaning. + Defaults to True. Returns: LibraryList: The libraries that have been found @@ -2130,7 +2138,9 @@ def find_libraries(libraries, root, shared=True, recursive=False): if is_windows: static_ext = "lib" - shared_ext = "dll" + # For linking (runtime=False) you need the .lib files regardless of + # whether you are doing a shared or static link + shared_ext = "dll" if runtime else "lib" else: # Used on both Linux and macOS static_ext = "a" @@ -2174,13 +2184,13 @@ def find_libraries(libraries, root, shared=True, recursive=False): return LibraryList(found_libs) -def find_all_shared_libraries(root, recursive=False): +def find_all_shared_libraries(root, recursive=False, runtime=True): """Convenience function that returns the list of all shared libraries found in the directory passed as argument. See documentation for `llnl.util.filesystem.find_libraries` for more information """ - return find_libraries("*", root=root, shared=True, recursive=recursive) + return find_libraries("*", root=root, shared=True, recursive=recursive, runtime=runtime) def find_all_static_libraries(root, recursive=False): @@ -2226,48 +2236,36 @@ def __init__(self, package, link_install_prefix=True): self.pkg = package self._addl_rpaths = set() self.link_install_prefix = link_install_prefix - self._internal_links = set() + self._additional_library_dependents = set() @property - def link_dest(self): + def library_dependents(self): """ Set of directories where package binaries/libraries are located. """ - if hasattr(self.pkg, "libs") and self.pkg.libs: - pkg_libs = set(self.pkg.libs.directories) - else: - pkg_libs = set((self.pkg.prefix.lib, self.pkg.prefix.lib64)) + return set([self.pkg.prefix.bin]) | self._additional_library_dependents - return pkg_libs | set([self.pkg.prefix.bin]) | self.internal_links - - @property - def internal_links(self): + def add_library_dependent(self, *dest): """ - linking that would need to be established within the package itself. Useful for links - against extension modules/build time executables/internal linkage - """ - return self._internal_links + Add paths to directories or libraries/binaries to set of + common paths that need to link against other libraries - def add_internal_links(self, *dest): - """ - Incorporate additional paths into the rpath (sym)linking scheme. - - Paths provided to this method are linked against by a package's libraries - and libraries found at these paths are linked against a package's binaries. - (i.e. /site-packages -> /bin and /bin -> /site-packages) - - Specified paths should be outside of a package's lib, lib64, and bin + Specified paths should fall outside of a package's common + link paths, i.e. the bin directories. """ - self._internal_links = self._internal_links | set(*dest) + for pth in dest: + if os.path.isfile(pth): + self._additional_library_dependents.add(os.path.dirname) + else: + self._additional_library_dependents.add(pth) @property - def link_targets(self): + def rpaths(self): """ Set of libraries this package needs to link against during runtime These packages will each be symlinked into the packages lib and binary dir """ - dependent_libs = [] for path in self.pkg.rpath: dependent_libs.extend(list(find_all_shared_libraries(path, recursive=True))) @@ -2275,18 +2273,43 @@ def link_targets(self): dependent_libs.extend(list(find_all_shared_libraries(extra_path, recursive=True))) return set(dependent_libs) - def include_additional_link_paths(self, *paths): + def add_rpath(self, *paths): """ Add libraries found at the root of provided paths to runtime linking These are libraries found outside of the typical scope of rpath linking - that require manual inclusion in a runtime linking scheme + that require manual inclusion in a runtime linking scheme. + These links are unidirectional, and are only + intended to bring outside dependencies into this package Args: *paths (str): arbitrary number of paths to be added to runtime linking """ self._addl_rpaths = self._addl_rpaths | set(paths) + def _link(self, path, dest): + file_name = os.path.basename(path) + dest_file = os.path.join(dest, file_name) + if os.path.exists(dest): + try: + symlink(path, dest_file) + # For py2 compatibility, we have to catch the specific Windows error code + # associate with trying to create a file that already exists (winerror 183) + except OSError as e: + if e.winerror == 183: + # We have either already symlinked or we are encoutering a naming clash + # either way, we don't want to overwrite existing libraries + already_linked = islink(dest_file) + tty.debug( + "Linking library %s to %s failed, " % (path, dest_file) + "already linked." + if already_linked + else "library with name %s already exists at location %s." + % (file_name, dest) + ) + pass + else: + raise e + def establish_link(self): """ (sym)link packages to runtime dependencies based on RPath configuration for @@ -2298,29 +2321,8 @@ def establish_link(self): # for each binary install dir in self.pkg (i.e. pkg.prefix.bin, pkg.prefix.lib) # install a symlink to each dependent library - for library, lib_dir in itertools.product(self.link_targets, self.link_dest): - if not path_contains_subdirectory(library, lib_dir): - file_name = os.path.basename(library) - dest_file = os.path.join(lib_dir, file_name) - if os.path.exists(lib_dir): - try: - symlink(library, dest_file) - # For py2 compatibility, we have to catch the specific Windows error code - # associate with trying to create a file that already exists (winerror 183) - except OSError as e: - if e.winerror == 183: - # We have either already symlinked or we are encoutering a naming clash - # either way, we don't want to overwrite existing libraries - already_linked = islink(dest_file) - tty.debug( - "Linking library %s to %s failed, " % (library, dest_file) - + "already linked." - if already_linked - else "library with name %s already exists." % file_name - ) - pass - else: - raise e + for library, lib_dir in itertools.product(self.rpaths, self.library_dependents): + self._link(library, lib_dir) @system_path_filter diff --git a/lib/spack/spack/fetch_strategy.py b/lib/spack/spack/fetch_strategy.py index ea85c6a6824..df993978af6 100644 --- a/lib/spack/spack/fetch_strategy.py +++ b/lib/spack/spack/fetch_strategy.py @@ -865,7 +865,12 @@ def clone(self, dest=None, commit=None, branch=None, tag=None, bare=False): repo_name = get_single_file(".") if self.stage: self.stage.srcdir = repo_name - shutil.move(repo_name, dest) + shutil.copytree(repo_name, dest, symlinks=True) + shutil.rmtree( + repo_name, + ignore_errors=False, + onerror=fs.readonly_file_handler(ignore_errors=True), + ) with working_dir(dest): checkout_args = ["checkout", commit] diff --git a/lib/spack/spack/package_base.py b/lib/spack/spack/package_base.py index 3c3bcaa84db..cf96beca580 100644 --- a/lib/spack/spack/package_base.py +++ b/lib/spack/spack/package_base.py @@ -140,11 +140,30 @@ class WindowsRPathMeta(object): they would a genuine RPATH, i.e. adding directories that contain runtime library dependencies""" - def add_search_paths(self, *path): - """Add additional rpaths that are not implicitly included in the search - scheme + def win_add_library_dependent(self): + """Return extra set of directories that require linking for package + + This method should be overridden by packages that produce + binaries/libraries/python extension modules/etc that are installed into + directories outside a package's `bin`, `lib`, and `lib64` directories, + but still require linking against one of the packages dependencies, or + other components of the package itself. No-op otherwise. + + Returns: + List of additional directories that require linking """ - self.win_rpath.include_additional_link_paths(*path) + return [] + + def win_add_rpath(self): + """Return extra set of rpaths for package + + This method should be overridden by packages needing to + include additional paths to be searched by rpath. No-op otherwise + + Returns: + List of additional rpaths + """ + return [] def windows_establish_runtime_linkage(self): """Establish RPATH on Windows @@ -152,6 +171,8 @@ def windows_establish_runtime_linkage(self): Performs symlinking to incorporate rpath dependencies to Windows runtime search paths """ if is_windows: + self.win_rpath.add_library_dependent(*self.win_add_library_dependent()) + self.win_rpath.add_rpath(*self.win_add_rpath()) self.win_rpath.establish_link() @@ -2571,12 +2592,17 @@ def fetch_remote_versions(self, concurrency=128): @property def rpath(self): """Get the rpath this package links with, as a list of paths.""" - rpaths = [self.prefix.lib, self.prefix.lib64] deps = self.spec.dependencies(deptype="link") - rpaths.extend(d.prefix.lib for d in deps if os.path.isdir(d.prefix.lib)) - rpaths.extend(d.prefix.lib64 for d in deps if os.path.isdir(d.prefix.lib64)) + + # on Windows, libraries of runtime interest are typically + # stored in the bin directory if is_windows: + rpaths = [self.prefix.bin] rpaths.extend(d.prefix.bin for d in deps if os.path.isdir(d.prefix.bin)) + else: + rpaths = [self.prefix.lib, self.prefix.lib64] + rpaths.extend(d.prefix.lib for d in deps if os.path.isdir(d.prefix.lib)) + rpaths.extend(d.prefix.lib64 for d in deps if os.path.isdir(d.prefix.lib64)) return rpaths @property diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py index 2f4120a5f84..a05451b7b41 100644 --- a/lib/spack/spack/spec.py +++ b/lib/spack/spack/spec.py @@ -1030,7 +1030,9 @@ def _libs_default_handler(descriptor, spec, cls): ) for shared in search_shared: - libs = fs.find_libraries(name, home, shared=shared, recursive=True) + # Since we are searching for link libraries, on Windows search only for + # ".Lib" extensions by default as those represent import libraries for implict links. + libs = fs.find_libraries(name, home, shared=shared, recursive=True, runtime=False) if libs: return libs diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py index ccdc19a1743..ffc05a7fc0e 100644 --- a/lib/spack/spack/test/concretize.py +++ b/lib/spack/spack/test/concretize.py @@ -2,7 +2,7 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) -import os +import posixpath import sys import jinja2 @@ -459,7 +459,7 @@ def test_compiler_inheritance(self, compiler_str): def test_external_package(self): spec = Spec("externaltool%gcc") spec.concretize() - assert spec["externaltool"].external_path == os.path.sep + os.path.join( + assert spec["externaltool"].external_path == posixpath.sep + posixpath.join( "path", "to", "external_tool" ) assert "externalprereq" not in spec @@ -490,10 +490,10 @@ def test_nobuild_package(self): def test_external_and_virtual(self): spec = Spec("externaltest") spec.concretize() - assert spec["externaltool"].external_path == os.path.sep + os.path.join( + assert spec["externaltool"].external_path == posixpath.sep + posixpath.join( "path", "to", "external_tool" ) - assert spec["stuff"].external_path == os.path.sep + os.path.join( + assert spec["stuff"].external_path == posixpath.sep + posixpath.join( "path", "to", "external_virtual_gcc" ) assert spec["externaltool"].compiler.satisfies("gcc") diff --git a/var/spack/repos/builtin/packages/clingo/package.py b/var/spack/repos/builtin/packages/clingo/package.py index a3d39d8e629..a24ffb0956d 100644 --- a/var/spack/repos/builtin/packages/clingo/package.py +++ b/var/spack/repos/builtin/packages/clingo/package.py @@ -3,6 +3,7 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import os from spack.compiler import UnsupportedCompilerFlag from spack.package import * @@ -120,3 +121,9 @@ def cmake_args(self): args += ["-DCLINGO_BUILD_WITH_PYTHON=OFF"] return args + + def win_add_library_dependent(self): + if "+python" in self.spec: + return [os.path.join(self.prefix, self.spec["python"].package.platlib)] + else: + return [] From ef3cd6d6ca10e943b8f237bd571c1effcbc98df9 Mon Sep 17 00:00:00 2001 From: Mark Olesen Date: Mon, 31 Oct 2022 17:43:58 +0100 Subject: [PATCH 277/442] openfoam: update mechanism for creating spack-specific wmake rules (#33615) - the updated OpenFOAM wmake rules now allow multiple locations for compiler flags: * wmake/General/common/c++Opt [central] * wmake/linux64Gcc/c++Opt [traditional] - match both '=' and ':=' make rule lines Co-authored-by: Mark Olesen --- .../builtin/packages/openfoam/package.py | 74 +++++++++++++------ 1 file changed, 51 insertions(+), 23 deletions(-) diff --git a/var/spack/repos/builtin/packages/openfoam/package.py b/var/spack/repos/builtin/packages/openfoam/package.py index d67a21f3cc2..6e6ed66b325 100644 --- a/var/spack/repos/builtin/packages/openfoam/package.py +++ b/var/spack/repos/builtin/packages/openfoam/package.py @@ -991,11 +991,14 @@ def foam_dict(self): ] ) - def _rule_directory(self, projdir, general=False): - """Return the wmake/rules/ General or compiler rules directory. + def _rule_directory(self, projdir, general=False, common=False): + """Return wmake/rules/ General/common, General or + compiler rules directory. Supports wmake/rules/ and wmake/rules//. """ rules_dir = os.path.join(projdir, "wmake", "rules") + if common: + return os.path.join(rules_dir, "General", "common") if general: return os.path.join(rules_dir, "General") @@ -1015,10 +1018,41 @@ def has_rule(self, projdir): raise InstallError("No wmake rule for {0} {1}".format(self.arch, self.compiler)) return True + def _rule_add_rpath(self, rpath, src, dst): + """Create {c,c++}-spack rules in the specified project directory. + The compiler rules are based on the respective {cflags,cxxflags}-Opt or + {c,c++}Opt rules with additional rpath information for the OpenFOAM libraries. + + The '-spack' rules channel spack information into OpenFOAM wmake + rules with minimal modification to OpenFOAM. + The rpath is used for the installed libpath (continue to use + LD_LIBRARY_PATH for values during the build). + """ + # Note: the 'c' rules normally don't need rpath, since they are just + # used for some statically linked wmake tools, but left in anyhow. + + ok = os.path.isfile(src) + + if ok: + with open(src, "r") as infile: + with open(dst, "w") as outfile: + for line in infile: + line = line.rstrip() + outfile.write(line) + if re.match(r"^\S+DBUG\s*:?=", line): + outfile.write(" ") + outfile.write(rpath) + elif re.match(r"^\S+OPT\s*:?=", line): + if self.arch_option: + outfile.write(" ") + outfile.write(self.arch_option) + outfile.write("\n") + return ok + def create_rules(self, projdir, foam_pkg): - """Create {c,c++}-spack and mplib{USERMPI} - rules in the specified project directory. - The compiler rules are based on the respective {c,c++}Opt rules + """Create {c,c++}-spack and mplib{USERMPI} rules in the + specified project directory. + Uses General/common/{c,c++}Opt or arch-specific {c,c++}Opt rules, but with additional rpath information for the OpenFOAM libraries. The '-spack' rules channel spack information into OpenFOAM wmake @@ -1036,26 +1070,20 @@ def create_rules(self, projdir, foam_pkg): user_mpi = mplib_content(foam_pkg.spec) rule_dir = self._rule_directory(projdir) + comm_dir = self._rule_directory(projdir, False, True) + + # Compiler: copy existing {c,c++}Opt or General/common/{c,c++}Opt + # and modify '*DBUG' value to include rpath + + for lang in ["c", "c++"]: + gen = join_path(comm_dir, "{0}Opt".format(lang)) + src = join_path(rule_dir, "{0}Opt".format(lang)) + dst = join_path(rule_dir, "{0}{1}".format(lang, self.compile_option)) + + if not self._rule_add_rpath(rpath, src, dst): + self._rule_add_rpath(rpath, gen, dst) with working_dir(rule_dir): - # Compiler: copy existing cOpt,c++Opt and modify '*DBUG' value - for lang in ["c", "c++"]: - src = "{0}Opt".format(lang) - dst = "{0}{1}".format(lang, self.compile_option) - with open(src, "r") as infile: - with open(dst, "w") as outfile: - for line in infile: - line = line.rstrip() - outfile.write(line) - if re.match(r"^\S+DBUG\s*=", line): - outfile.write(" ") - outfile.write(rpath) - elif re.match(r"^\S+OPT\s*=", line): - if self.arch_option: - outfile.write(" ") - outfile.write(self.arch_option) - outfile.write("\n") - # MPI rules for mplib in ["mplibUSERMPI"]: with open(mplib, "w") as out: From fc2d5d2311686367de9f5d21b45b6f6977f309f1 Mon Sep 17 00:00:00 2001 From: Michael Kuhn Date: Mon, 31 Oct 2022 19:44:07 +0100 Subject: [PATCH 278/442] Fix pkgconfig dependencies (#33614) Packages should depend on the virtual provider, pkgconfig, not on its implementations pkg-config or pkgconf. --- var/spack/repos/builtin/packages/aml/package.py | 1 + var/spack/repos/builtin/packages/bear/package.py | 2 +- var/spack/repos/builtin/packages/libpressio/package.py | 2 +- .../builtin/packages/ophidia-analytics-framework/package.py | 2 +- var/spack/repos/builtin/packages/ophidia-primitives/package.py | 2 +- var/spack/repos/builtin/packages/riscv-gnu-toolchain/package.py | 2 +- var/spack/repos/builtin/packages/sperr/package.py | 2 +- 7 files changed, 7 insertions(+), 6 deletions(-) diff --git a/var/spack/repos/builtin/packages/aml/package.py b/var/spack/repos/builtin/packages/aml/package.py index 8ece44c1023..9c91323e95a 100644 --- a/var/spack/repos/builtin/packages/aml/package.py +++ b/var/spack/repos/builtin/packages/aml/package.py @@ -76,6 +76,7 @@ class Aml(AutotoolsPackage): depends_on("automake", type="build") depends_on("libtool", type="build") # Required to have pkg config macros in configure. + # Note: This does NOT work with pkg-config but requires pkgconf! depends_on("pkgconf", type="build") # Required to generate AML version in configure. depends_on("git", type="build") diff --git a/var/spack/repos/builtin/packages/bear/package.py b/var/spack/repos/builtin/packages/bear/package.py index c2b22a4d0b9..567c737e13e 100644 --- a/var/spack/repos/builtin/packages/bear/package.py +++ b/var/spack/repos/builtin/packages/bear/package.py @@ -22,7 +22,7 @@ class Bear(CMakePackage): version("2.2.0", sha256="6bd61a6d64a24a61eab17e7f2950e688820c72635e1cf7ea8ea7bf9482f3b612") version("2.0.4", sha256="33ea117b09068aa2cd59c0f0f7535ad82c5ee473133779f1cc20f6f99793a63e") - depends_on("pkgconf", when="@3:") + depends_on("pkgconfig", when="@3:") depends_on("fmt", when="@3.0.0:") depends_on("grpc", when="@3.0.0:") depends_on("nlohmann-json", when="@3.0.0:") diff --git a/var/spack/repos/builtin/packages/libpressio/package.py b/var/spack/repos/builtin/packages/libpressio/package.py index d30bb5edc16..2a8a8521ba9 100644 --- a/var/spack/repos/builtin/packages/libpressio/package.py +++ b/var/spack/repos/builtin/packages/libpressio/package.py @@ -212,7 +212,7 @@ class Libpressio(CMakePackage, CudaPackage): depends_on("lua-sol2", when="+lua") depends_on("libdistributed@0.0.11:", when="+libdistributed") depends_on("libdistributed@0.4.0:", when="@0.85.0:+libdistributed") - depends_on("pkg-config", type="build") + depends_on("pkgconfig", type="build") depends_on("ftk@master", when="+ftk") depends_on("digitrounding", when="+digitrounding") depends_on("bitgroomingz", when="+bitgrooming") diff --git a/var/spack/repos/builtin/packages/ophidia-analytics-framework/package.py b/var/spack/repos/builtin/packages/ophidia-analytics-framework/package.py index 26742143037..ff15e3c3163 100644 --- a/var/spack/repos/builtin/packages/ophidia-analytics-framework/package.py +++ b/var/spack/repos/builtin/packages/ophidia-analytics-framework/package.py @@ -21,7 +21,7 @@ class OphidiaAnalyticsFramework(AutotoolsPackage): depends_on("automake", type="build") depends_on("libtool", type="build") depends_on("m4", type="build") - depends_on("pkg-config", type="build") + depends_on("pkgconfig", type="build") depends_on("gsl") depends_on("mpich") diff --git a/var/spack/repos/builtin/packages/ophidia-primitives/package.py b/var/spack/repos/builtin/packages/ophidia-primitives/package.py index 804df33e37c..bf85210080c 100644 --- a/var/spack/repos/builtin/packages/ophidia-primitives/package.py +++ b/var/spack/repos/builtin/packages/ophidia-primitives/package.py @@ -21,7 +21,7 @@ class OphidiaPrimitives(AutotoolsPackage): depends_on("automake", type="build") depends_on("libtool", type="build") depends_on("m4", type="build") - depends_on("pkg-config", type="build") + depends_on("pkgconfig", type="build") depends_on("boost@1.79.0") depends_on("mysql") diff --git a/var/spack/repos/builtin/packages/riscv-gnu-toolchain/package.py b/var/spack/repos/builtin/packages/riscv-gnu-toolchain/package.py index d4f96029072..4c71ba0622e 100644 --- a/var/spack/repos/builtin/packages/riscv-gnu-toolchain/package.py +++ b/var/spack/repos/builtin/packages/riscv-gnu-toolchain/package.py @@ -21,7 +21,7 @@ class RiscvGnuToolchain(AutotoolsPackage): version("2022.08.08", tag="2022.08.08", submodules=True) # Dependencies: - depends_on("pkg-config", type="build") + depends_on("pkgconfig", type="build") depends_on("autoconf", when="@main:", type="build") depends_on("python", type="build") depends_on("gawk", type="build") diff --git a/var/spack/repos/builtin/packages/sperr/package.py b/var/spack/repos/builtin/packages/sperr/package.py index 4d7482aff18..5859dd22ccc 100644 --- a/var/spack/repos/builtin/packages/sperr/package.py +++ b/var/spack/repos/builtin/packages/sperr/package.py @@ -18,7 +18,7 @@ class Sperr(CMakePackage): depends_on("git", type="build") depends_on("zstd", type=("build", "link"), when="+zstd") - depends_on("pkgconf", type=("build"), when="+zstd") + depends_on("pkgconfig", type=("build"), when="+zstd") variant("shared", description="build shared libaries", default=True) variant("zstd", description="use Zstd for more compression", default=True) From ace8c74e2091dba4258da7dc2a198c4db62d5cd6 Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Mon, 31 Oct 2022 21:31:57 +0100 Subject: [PATCH 279/442] Revert "gitlab: when_possible -> false (#33443)" (#33552) This reverts commit b1559cc831620ee2b2cf8e57fdecc5bb3bf8edfd. --- .../gitlab/cloud_pipelines/stacks/build_systems/spack.yaml | 2 +- share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml index 0d75670f2be..e09971beba9 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml @@ -3,7 +3,7 @@ spack: concretizer: reuse: false - unify: false + unify: when_possible config: install_tree: diff --git a/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml index 3fe66c48e5d..3dfc5a14f41 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml @@ -3,7 +3,7 @@ spack: concretizer: reuse: false - unify: false + unify: when_possible config: concretizer: clingo From 269304a7aca5bf5a64c41176df96cdf5500f2bc5 Mon Sep 17 00:00:00 2001 From: SoniaScard <83462318+SoniaScard@users.noreply.github.com> Date: Mon, 31 Oct 2022 22:20:56 +0100 Subject: [PATCH 280/442] ophidia-server: new package at v1.7 (#33581) Co-authored-by: SoniaScard --- .../packages/ophidia-server/package.py | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 var/spack/repos/builtin/packages/ophidia-server/package.py diff --git a/var/spack/repos/builtin/packages/ophidia-server/package.py b/var/spack/repos/builtin/packages/ophidia-server/package.py new file mode 100644 index 00000000000..585224d68a0 --- /dev/null +++ b/var/spack/repos/builtin/packages/ophidia-server/package.py @@ -0,0 +1,47 @@ +# 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 OphidiaServer(AutotoolsPackage): + """Front-end server of the Ophidia framework""" + + homepage = "https://github.com/SoniaScard/ophidia-server" + url = "https://github.com/SoniaScard/ophidia-server/archive/refs/tags/v1.7.2.tar.gz" + maintainers = ["eldoo", "SoniaScard"] + version( + "1.7.2", + sha256="452587775343b266bbb5adcfeee64e7f7e9a9bbfcb2133646a831ae3e74348be", + ) + + depends_on("autoconf", type="build") + depends_on("automake", type="build") + depends_on("libtool", type="build") + depends_on("m4", type="build") + depends_on("pkg-config", type="build") + + depends_on("libmatheval") + depends_on("jansson") + depends_on("libxml2") + depends_on("libssh2") + depends_on("openssl") + depends_on("mysql") + depends_on("curl") + depends_on("ophidia-analytics-framework") + + def autoreconf(self, spec, prefix): + autoreconf("--install", "--verbose", "--force") + + def configure_args(self): + args = [ + "--with-web-server-path={0}/html".format( + self.spec["ophidia-analytics-framework"].prefix + ), + "--with-web-server-url=http://127.0.0.1/ophidia", + "--with-framework-path={0}".format(self.spec["ophidia-analytics-framework"].prefix), + ] + + return args From a83456dd7b4aef6044df5f3449dcbedc83b7784a Mon Sep 17 00:00:00 2001 From: downloadico Date: Mon, 31 Oct 2022 16:05:49 -0600 Subject: [PATCH 281/442] julia: don't look for the openlibm libraries when unneeded (#33626) * julia: don't look for the openlibm libraries when unneeded Cause spack to *not* check for the existence of the openlibm libraries (by adding it to the pkgs list) when ~openlibm is specified. * [@spackbot] updating style on behalf of downloadico Co-authored-by: downloadico --- var/spack/repos/builtin/packages/julia/package.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/julia/package.py b/var/spack/repos/builtin/packages/julia/package.py index 28b14c1f3ae..bf7297357d5 100644 --- a/var/spack/repos/builtin/packages/julia/package.py +++ b/var/spack/repos/builtin/packages/julia/package.py @@ -204,12 +204,13 @@ def setup_build_environment(self, env): "mpfr", "nghttp2", "openblas", - "openlibm", "pcre2", "suite-sparse", "utf8proc", "zlib", ] + if "+openlibm" in self.spec: + pkgs.append("openlibm") if self.spec.satisfies("@1.7.0:"): pkgs.append("libblastrampoline") for pkg in pkgs: From 02097b18560934698fee5279807e59ca43fa4182 Mon Sep 17 00:00:00 2001 From: Luke Diorio-Toth Date: Mon, 31 Oct 2022 17:07:40 -0500 Subject: [PATCH 282/442] new package: polypolish (#33601) * added polypolish package, comfirmed builds * added bwa dep --- .../builtin/packages/polypolish/package.py | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 var/spack/repos/builtin/packages/polypolish/package.py diff --git a/var/spack/repos/builtin/packages/polypolish/package.py b/var/spack/repos/builtin/packages/polypolish/package.py new file mode 100644 index 00000000000..1b1e99f2828 --- /dev/null +++ b/var/spack/repos/builtin/packages/polypolish/package.py @@ -0,0 +1,29 @@ +# 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 Polypolish(Package): + """Polypolish is a tool for polishing genome assemblies with short reads. + Unlike other tools in this category, Polypolish uses SAM files where each + read has been aligned to all possible locations (not just a single best + location). This allows it to repair errors in repeat regions that other + alignment-based polishers cannot fix.""" + + homepage = "https://github.com/rrwick/Polypolish" + url = "https://github.com/rrwick/Polypolish/archive/refs/tags/v0.5.0.tar.gz" + + version("0.5.0", sha256="183156093c03094290951f140010b3aef6222a672bf538e9136914178775fb1f") + + depends_on("rust") + depends_on("python@3.6:", type="run") + depends_on("bwa", type="run") + + def install(self, spec, prefix): + cargo = which("cargo") + cargo("install", "--root", prefix, "--path", ".") + install("scripts/polypolish_insert_filter.py", prefix.bin) From df6cdcf6c77f461128b88e320c1f316c5794692a Mon Sep 17 00:00:00 2001 From: "Adam J. Stewart" Date: Mon, 31 Oct 2022 20:53:52 -0500 Subject: [PATCH 283/442] GDAL: add v3.5.3 (#33623) --- var/spack/repos/builtin/packages/gdal/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/gdal/package.py b/var/spack/repos/builtin/packages/gdal/package.py index bf22b2d6305..e0f1072964f 100644 --- a/var/spack/repos/builtin/packages/gdal/package.py +++ b/var/spack/repos/builtin/packages/gdal/package.py @@ -30,6 +30,7 @@ class Gdal(CMakePackage, AutotoolsPackage, PythonExtension): maintainers = ["adamjstewart"] + version("3.5.3", sha256="d32223ddf145aafbbaec5ccfa5dbc164147fb3348a3413057f9b1600bb5b3890") version("3.5.2", sha256="0874dfdeb9ac42e53c37be4184b19350be76f0530e1f4fa8004361635b9030c2") version("3.5.1", sha256="d12c30a9eacdeaab493c0d1c9f88eb337c9cbb5bb40744c751bdd5a5af166ab6") version("3.5.0", sha256="d49121e5348a51659807be4fb866aa840f8dbec4d1acba6d17fdefa72125bfc9") From 6b86a8562f464ff100165ad8f7416a63341d0fe7 Mon Sep 17 00:00:00 2001 From: kwryankrattiger <80296582+kwryankrattiger@users.noreply.github.com> Date: Mon, 31 Oct 2022 21:58:02 -0500 Subject: [PATCH 284/442] ParaView: ParaView needs to set the HDF5 API (#33617) When building ParaView with a newer HDf5 than 1.10, it needs to select the 1.10 API using flags. --- var/spack/repos/builtin/packages/paraview/package.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/var/spack/repos/builtin/packages/paraview/package.py b/var/spack/repos/builtin/packages/paraview/package.py index 0ed725dc6ab..8dd0049e055 100644 --- a/var/spack/repos/builtin/packages/paraview/package.py +++ b/var/spack/repos/builtin/packages/paraview/package.py @@ -311,6 +311,15 @@ def flag_handler(self, name, flags): if (name == "cflags" or name == "cxxflags") and self.spec.satisfies("%intel"): flags.append("-no-ipo") return (None, None, flags) + + if name in ("cflags", "cxxflags"): + # Constrain the HDF5 API + if self.spec.satisfies("@:5.9 +hdf5"): + if self.spec["hdf5"].satisfies("@1.10:"): + flags.append("-DH5_USE_18_API") + elif self.spec.satisfies("@5.10: +hdf5"): + if self.spec["hdf5"].satisfies("@1.12:"): + flags.append("-DH5_USE_110_API") return (flags, None, None) def setup_run_environment(self, env): From 3187d4e7b152914f8d8a8bbab96f4ba8e85dc38f Mon Sep 17 00:00:00 2001 From: "Adam J. Stewart" Date: Mon, 31 Oct 2022 22:01:23 -0500 Subject: [PATCH 285/442] py-torchmetrics: add v0.10.2 (#33630) --- var/spack/repos/builtin/packages/py-torchmetrics/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/py-torchmetrics/package.py b/var/spack/repos/builtin/packages/py-torchmetrics/package.py index ef55a25f408..729bcb4b601 100644 --- a/var/spack/repos/builtin/packages/py-torchmetrics/package.py +++ b/var/spack/repos/builtin/packages/py-torchmetrics/package.py @@ -14,6 +14,7 @@ class PyTorchmetrics(PythonPackage): maintainers = ["adamjstewart"] + version("0.10.2", sha256="daa29d96bff5cff04d80eec5b9f5076993d6ac9c2d2163e88b6b31f8d38f7c25") version("0.10.1", sha256="e892ecd413e6bf63950329d1317c70f697d81d0f7e386152238062e322c8f1f3") version("0.10.0", sha256="990bafc7f76d7442894533771d0ba7492dbca2bbf2989fb32de7e9c68eb3d133") version("0.9.3", sha256="4ebfd2466021db26397636966ee1a195d3b340ba5d71bb258e764340dfc2476f") From cd40d022146718407717dd4963a2eeffe656c60c Mon Sep 17 00:00:00 2001 From: "Mark W. Krentel" Date: Mon, 31 Oct 2022 23:38:04 -0500 Subject: [PATCH 286/442] hpctoolkit: adjust rocm dependency types (#33627) Drop the link dependency type for the rocm packages. We don't actually link, and that adds rpaths that conflict with the app. --- var/spack/repos/builtin/packages/hpctoolkit/package.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/var/spack/repos/builtin/packages/hpctoolkit/package.py b/var/spack/repos/builtin/packages/hpctoolkit/package.py index 368e115a68d..5e7b70b299e 100644 --- a/var/spack/repos/builtin/packages/hpctoolkit/package.py +++ b/var/spack/repos/builtin/packages/hpctoolkit/package.py @@ -137,10 +137,12 @@ class Hpctoolkit(AutotoolsPackage): depends_on("hpcviewer@2022.10:", type="run", when="@2022.10: +viewer") depends_on("hpcviewer", type="run", when="+viewer") - depends_on("hip@4.5:", when="+rocm") - depends_on("hsa-rocr-dev@4.5:", when="+rocm") - depends_on("roctracer-dev@4.5:", when="+rocm") - depends_on("rocprofiler-dev@4.5:", when="+rocm") + # Avoid 'link' dep, we don't actually link, and that adds rpath + # that conflicts with app. + depends_on("hip@4.5:", type=("build", "run"), when="+rocm") + depends_on("hsa-rocr-dev@4.5:", type=("build", "run"), when="+rocm") + depends_on("roctracer-dev@4.5:", type=("build", "run"), when="+rocm") + depends_on("rocprofiler-dev@4.5:", type=("build", "run"), when="+rocm") conflicts("%gcc@:7", when="@2022.10:", msg="hpctoolkit requires gnu gcc 8.x or later") conflicts("%gcc@:6", when="@2021.00:2022.06", msg="hpctoolkit requires gnu gcc 7.x or later") From 156dd5848eb257b3f37cdcc8e116d236cc75901f Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Tue, 1 Nov 2022 16:00:51 +0100 Subject: [PATCH 287/442] Relocate links using prefix to prefix map (#33636) Previously symlinks were not relocated when they pointed across packages --- lib/spack/spack/binary_distribution.py | 4 +- lib/spack/spack/relocate.py | 50 ++++++++------------- lib/spack/spack/test/packaging.py | 60 ++++++++++++++++---------- 3 files changed, 57 insertions(+), 57 deletions(-) diff --git a/lib/spack/spack/binary_distribution.py b/lib/spack/spack/binary_distribution.py index 68b270c390d..3069e234b2b 100644 --- a/lib/spack/spack/binary_distribution.py +++ b/lib/spack/spack/binary_distribution.py @@ -1646,8 +1646,8 @@ def is_backup_file(file): ) # Relocate links to the new install prefix - links = [link for link in buildinfo.get("relocate_links", [])] - relocate.relocate_links(links, old_layout_root, old_prefix, new_prefix) + links = [os.path.join(workdir, f) for f in buildinfo.get("relocate_links", [])] + relocate.relocate_links(links, prefix_to_prefix_bin) # For all buildcaches # relocate the install prefixes in text files including dependencies diff --git a/lib/spack/spack/relocate.py b/lib/spack/spack/relocate.py index dca55af17ea..8a5e77e22ec 100644 --- a/lib/spack/spack/relocate.py +++ b/lib/spack/spack/relocate.py @@ -702,41 +702,27 @@ def raise_if_not_relocatable(binaries, allow_root): raise InstallRootStringError(binary, spack.store.layout.root) -def relocate_links(links, orig_layout_root, orig_install_prefix, new_install_prefix): - """Relocate links to a new install prefix. +def warn_if_link_cant_be_relocated(link, target): + if not os.path.isabs(target): + return + tty.warn('Symbolic link at "{}" to "{}" cannot be relocated'.format(link, target)) - The symbolic links are relative to the original installation prefix. - The old link target is read and the placeholder is replaced by the old - layout root. If the old link target is in the old install prefix, the new - link target is create by replacing the old install prefix with the new - install prefix. - Args: - links (list): list of links to be relocated - orig_layout_root (str): original layout root - orig_install_prefix (str): install prefix of the original installation - new_install_prefix (str): install prefix where we want to relocate - """ - placeholder = _placeholder(orig_layout_root) - abs_links = [os.path.join(new_install_prefix, link) for link in links] - for abs_link in abs_links: - link_target = os.readlink(abs_link) - link_target = re.sub(placeholder, orig_layout_root, link_target) - # If the link points to a file in the original install prefix, - # compute the corresponding target in the new prefix and relink - if link_target.startswith(orig_install_prefix): - link_target = re.sub(orig_install_prefix, new_install_prefix, link_target) - os.unlink(abs_link) - symlink(link_target, abs_link) +def relocate_links(links, prefix_to_prefix): + """Relocate links to a new install prefix.""" + regex = re.compile("|".join(re.escape(p) for p in prefix_to_prefix.keys())) + for link in links: + old_target = os.readlink(link) + match = regex.match(old_target) - # If the link is absolute and has not been relocated then - # warn the user about that - if os.path.isabs(link_target) and not link_target.startswith(new_install_prefix): - msg = ( - 'Link target "{0}" for symbolic link "{1}" is outside' - " of the new install prefix {2}" - ) - tty.warn(msg.format(link_target, abs_link, new_install_prefix)) + # No match. + if match is None: + warn_if_link_cant_be_relocated(link, old_target) + continue + + new_target = prefix_to_prefix[match.group()] + old_target[match.end() :] + os.unlink(link) + symlink(new_target, link) def utf8_path_to_binary_regex(prefix): diff --git a/lib/spack/spack/test/packaging.py b/lib/spack/spack/test/packaging.py index 0ed4f943a3a..f0294f5a74a 100644 --- a/lib/spack/spack/test/packaging.py +++ b/lib/spack/spack/test/packaging.py @@ -9,10 +9,10 @@ import argparse import os import platform -import re import shutil import stat import sys +from collections import OrderedDict import pytest @@ -28,7 +28,6 @@ from spack.fetch_strategy import FetchStrategyComposite, URLFetchStrategy from spack.paths import mock_gpg_keys_path from spack.relocate import ( - _placeholder, file_is_relocatable, macho_find_paths, macho_make_paths_normal, @@ -213,27 +212,42 @@ def test_unsafe_relocate_text(tmpdir): def test_relocate_links(tmpdir): - with tmpdir.as_cwd(): - old_layout_root = os.path.join("%s" % tmpdir, "home", "spack", "opt", "spack") - old_install_prefix = os.path.join("%s" % old_layout_root, "debian6", "test") - old_binname = os.path.join(old_install_prefix, "binfile") - placeholder = _placeholder(old_layout_root) - re.sub(old_layout_root, placeholder, old_binname) - filenames = ["link.ln", "outsideprefix.ln"] - new_layout_root = os.path.join("%s" % tmpdir, "opt", "rh", "devtoolset") - new_install_prefix = os.path.join("%s" % new_layout_root, "test", "debian6") - new_linkname = os.path.join(new_install_prefix, "link.ln") - new_linkname2 = os.path.join(new_install_prefix, "outsideprefix.ln") - new_binname = os.path.join(new_install_prefix, "binfile") - mkdirp(new_install_prefix) - with open(new_binname, "w") as f: - f.write("\n") - os.utime(new_binname, None) - symlink(old_binname, new_linkname) - symlink("/usr/lib/libc.so", new_linkname2) - relocate_links(filenames, old_layout_root, old_install_prefix, new_install_prefix) - assert os.readlink(new_linkname) == new_binname - assert os.readlink(new_linkname2) == "/usr/lib/libc.so" + tmpdir.ensure("new_prefix_a", dir=True) + + own_prefix_path = str(tmpdir.join("prefix_a", "file")) + dep_prefix_path = str(tmpdir.join("prefix_b", "file")) + system_path = os.path.join(os.path.sep, "system", "path") + + # Old prefixes to new prefixes + prefix_to_prefix = OrderedDict( + [ + # map /prefix_a -> /new_prefix_a + (str(tmpdir.join("prefix_a")), str(tmpdir.join("new_prefix_a"))), + # map /prefix_b -> /new_prefix_b + (str(tmpdir.join("prefix_b")), str(tmpdir.join("new_prefix_b"))), + # map -> /fallback/path -- this is just to see we respect order. + (str(tmpdir), os.path.join(os.path.sep, "fallback", "path")), + ] + ) + + with tmpdir.join("new_prefix_a").as_cwd(): + # To be relocated + os.symlink(own_prefix_path, "to_self") + os.symlink(dep_prefix_path, "to_dependency") + + # To be ignored + os.symlink(system_path, "to_system") + os.symlink("relative", "to_self_but_relative") + + relocate_links(["to_self", "to_dependency", "to_system"], prefix_to_prefix) + + # These two are relocated + assert os.readlink("to_self") == str(tmpdir.join("new_prefix_a", "file")) + assert os.readlink("to_dependency") == str(tmpdir.join("new_prefix_b", "file")) + + # These two are not. + assert os.readlink("to_system") == system_path + assert os.readlink("to_self_but_relative") == "relative" def test_needs_relocation(): From f2c84efed2a327026a61b9bacd9b696eb0a22898 Mon Sep 17 00:00:00 2001 From: Sinan Date: Tue, 1 Nov 2022 08:30:02 -0700 Subject: [PATCH 288/442] package/py-simplekml_add_new_versions (#33632) Co-authored-by: sbulut --- var/spack/repos/builtin/packages/py-simplekml/package.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/var/spack/repos/builtin/packages/py-simplekml/package.py b/var/spack/repos/builtin/packages/py-simplekml/package.py index dbbbb03283d..e7e5f878c4b 100644 --- a/var/spack/repos/builtin/packages/py-simplekml/package.py +++ b/var/spack/repos/builtin/packages/py-simplekml/package.py @@ -14,6 +14,8 @@ class PySimplekml(PythonPackage): homepage = "https://readthedocs.org/projects/simplekml/" pypi = "simplekml/simplekml-1.3.1.tar.gz" + version("1.3.6", sha256="cda687be2754395fcab664e908ebf589facd41e8436d233d2be37a69efb1c536") + version("1.3.5", sha256="657b4e20177299a4e80bacfafff1f91102010bc23dc0ce7a7ae43bdd4246049e") version("1.3.1", sha256="30c121368ce1d73405721730bf766721e580cae6fbb7424884c734c89ec62ad7") depends_on("python@2.6:", type=("build", "run")) From d6f25becdb30128c6ec12258525422db2cd10689 Mon Sep 17 00:00:00 2001 From: Qian Jianhua Date: Tue, 1 Nov 2022 23:36:50 +0800 Subject: [PATCH 289/442] py-ilmbase: add dependency to py-numpy (#33633) * py-ilmbase: add dependency to py-numpy * fix style --- var/spack/repos/builtin/packages/py-ilmbase/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/py-ilmbase/package.py b/var/spack/repos/builtin/packages/py-ilmbase/package.py index 225b9b80ae0..4e073e0af3f 100644 --- a/var/spack/repos/builtin/packages/py-ilmbase/package.py +++ b/var/spack/repos/builtin/packages/py-ilmbase/package.py @@ -16,6 +16,7 @@ class PyIlmbase(AutotoolsPackage): depends_on("ilmbase") depends_on("boost+python") + depends_on("py-numpy") # https://github.com/AcademySoftwareFoundation/openexr/issues/336 parallel = False From 1780f3ab3cc5f50e074a3ccf03170c8e43b82888 Mon Sep 17 00:00:00 2001 From: "Adam J. Stewart" Date: Tue, 1 Nov 2022 11:13:12 -0500 Subject: [PATCH 290/442] py-pytorch-lightning: add v1.8.0 (#33643) --- .../packages/py-lightning-lite/package.py | 30 +++++++++++++++++++ .../py-lightning-utilities/package.py | 29 ++++++++++++++++++ .../packages/py-pytorch-lightning/package.py | 17 ++++++++--- 3 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 var/spack/repos/builtin/packages/py-lightning-lite/package.py create mode 100644 var/spack/repos/builtin/packages/py-lightning-utilities/package.py diff --git a/var/spack/repos/builtin/packages/py-lightning-lite/package.py b/var/spack/repos/builtin/packages/py-lightning-lite/package.py new file mode 100644 index 00000000000..30cddf16e06 --- /dev/null +++ b/var/spack/repos/builtin/packages/py-lightning-lite/package.py @@ -0,0 +1,30 @@ +# 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 PyLightningLite(PythonPackage): + """LightningLite enables pure PyTorch users to scale their existing code on any kind + of device while retaining full control over their own loops and optimization logic.""" + + homepage = "https://github.com/Lightning-AI/lightning" + pypi = "lightning-lite/lightning-lite-1.8.0.tar.gz" + + maintainers = ["adamjstewart"] + + version("1.8.0", sha256="a71940409d3d1a5bb20f63716c86a745157ce30100f1c16600dfe33d9b657955") + + # src/lightning_lite/__setup__.py + depends_on("python@3.7:", type=("build", "run")) + depends_on("py-setuptools", type="build") + + # requirements/lite/base.txt + depends_on("py-numpy@1.17.2:", type=("build", "run")) + depends_on("py-torch@1.9:", type=("build", "run")) + depends_on("py-fsspec@2021.06.1:+http", type=("build", "run")) + depends_on("py-packaging@17:", type=("build", "run")) + depends_on("py-typing-extensions@4:", type=("build", "run")) + depends_on("py-lightning-utilities@0.3", type=("build", "run")) diff --git a/var/spack/repos/builtin/packages/py-lightning-utilities/package.py b/var/spack/repos/builtin/packages/py-lightning-utilities/package.py new file mode 100644 index 00000000000..963295686b8 --- /dev/null +++ b/var/spack/repos/builtin/packages/py-lightning-utilities/package.py @@ -0,0 +1,29 @@ +# 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 PyLightningUtilities(PythonPackage): + """Common Python utilities and GitHub Actions in Lightning Ecosystem""" + + homepage = "https://github.com/Lightning-AI/utilities" + pypi = "lightning-utilities/lightning-utilities-0.4.1.tar.gz" + + maintainers = ["adamjstewart"] + + version("0.4.1", sha256="969697b0debffd808d4cf3b74af4952f82bf6726f4ce561119037871547690a5") + version("0.4.0", sha256="961c29774c2c8303e0a2f6e6512a2e21e1d8acaf6df182865667af4a51bc176c") + version("0.3.0", sha256="d769ab9b76ebdee3243d1051d509aafee57d7947734ddc22977deef8a6427f2f") + + # setup.py + depends_on("python@3.7:", type=("build", "run")) + depends_on("py-setuptools", type="build") + + # requirements/base.txt + depends_on("py-importlib-metadata@4:", when="@0.4.1: ^python@:3.7", type=("build", "run")) + + # Historical dependencies + depends_on("py-fire", when="@0.3.0", type=("build", "run")) diff --git a/var/spack/repos/builtin/packages/py-pytorch-lightning/package.py b/var/spack/repos/builtin/packages/py-pytorch-lightning/package.py index 369cc7dd5ac..fe63af712b9 100644 --- a/var/spack/repos/builtin/packages/py-pytorch-lightning/package.py +++ b/var/spack/repos/builtin/packages/py-pytorch-lightning/package.py @@ -14,6 +14,7 @@ class PyPytorchLightning(PythonPackage): maintainers = ["adamjstewart"] + version("1.8.0", sha256="deff9bc7978ecebc8f45e881adef65dc8d9f4554e88c3b064f80587f32ab158d") version("1.7.7", sha256="27c2dd01a18db2415168e3fa3775ccb5a1fa1e2961a50439ad9365507fe9d4ae") version("1.7.6", sha256="93266c83f8340c100e41b3777bbab26dd2c20b4df3deccce3b8a15652326b9c8") version("1.7.5", sha256="a5838ae990f0eef9a894fa863be3bc1f5594d2abba7848fb21317ba3e885d7cd") @@ -34,21 +35,26 @@ class PyPytorchLightning(PythonPackage): version("1.3.8", sha256="60b0a3e464d394864dae4c8d251afa7aa453644a19bb7672f5ee400343cdf7b0") version("1.2.10", sha256="2d8365e30ded0c20e73ce6e5b6028478ae460b8fd33727df2275666df005a301") + # src/pytorch_lightning/__setup__.py depends_on("python@3.7:", when="@1.6:", type=("build", "run")) depends_on("python@3.6:", when="@:1.5", type=("build", "run")) depends_on("py-setuptools", type="build") + + # requirements/pytorch/base.txt depends_on("py-numpy@1.17.2:", when="@1.3:", type=("build", "run")) depends_on("py-numpy@1.16.6:", when="@:1.2", type=("build", "run")) depends_on("py-torch@1.9:", when="@1.7:", type=("build", "run")) depends_on("py-torch@1.8:", when="@1.6:", type=("build", "run")) depends_on("py-torch@1.6:", when="@1.4:1.5", type=("build", "run")) depends_on("py-torch@1.4:", when="@:1.3", type=("build", "run")) + depends_on("py-lightning-lite@1.8.0", when="@1.8.0", type=("build", "run")) depends_on("py-tqdm@4.57.0:", when="@1.6.3:", type=("build", "run")) depends_on("py-tqdm@4.41.0:", when="@:1.6.2", type=("build", "run")) depends_on("py-pyyaml@5.4:", when="@1.6:", type=("build", "run")) depends_on("py-pyyaml@5.1:", when="@1.4:1.5", type=("build", "run")) depends_on("py-pyyaml@5.1:5.4.1", when="@1.3", type=("build", "run")) depends_on("py-pyyaml@5.1:5.3,5.5:", when="@:1.2", type=("build", "run")) + depends_on("py-fsspec@2021.06.1:+http", when="@1.8:", type=("build", "run")) depends_on("py-fsspec@2021.05.0:2021.05,2021.06.1:+http", when="@1.3:", type=("build", "run")) depends_on("py-fsspec@0.8.1:+http", when="@:1.2", type=("build", "run")) depends_on("py-tensorboard@2.9.1:", when="@1.7:", type=("build", "run")) @@ -59,14 +65,17 @@ class PyPytorchLightning(PythonPackage): depends_on("py-torchmetrics@0.4.0:", when="@1.4", type=("build", "run")) depends_on("py-torchmetrics@0.2.0:", when="@1.3", type=("build", "run")) depends_on("py-torchmetrics@0.2.0", when="@:1.2", type=("build", "run")) - depends_on("py-pydeprecate@0.3.1:", when="@1.6.4:", type=("build", "run")) - depends_on("py-pydeprecate@0.3.1:0.3", when="@1.6:1.6.3", type=("build", "run")) - depends_on("py-pydeprecate@0.3.1", when="@1.4:1.5", type=("build", "run")) - depends_on("py-pydeprecate@0.3.0", when="@1.3", type=("build", "run")) depends_on("py-packaging@17.0:", when="@1.3:", type=("build", "run")) depends_on("py-packaging", when="@:1.2", type=("build", "run")) depends_on("py-typing-extensions@4.0.0:", when="@1.6:", type=("build", "run")) depends_on("py-typing-extensions", when="@1.4:1.5", type=("build", "run")) + depends_on("py-lightning-utilities@0.3", when="@1.8:", type=("build", "run")) + + # Historical dependencies depends_on("py-future@0.17.1:", when="@:1.5", type=("build", "run")) depends_on("pil@:8.2,8.3.1:", when="@1.3", type=("build", "run")) depends_on("py-protobuf@:3.20.1", when="@1.6.4:1.6", type="build") + depends_on("py-pydeprecate@0.3.1:", when="@1.6.4:1.7", type=("build", "run")) + depends_on("py-pydeprecate@0.3.1:0.3", when="@1.6:1.6.3", type=("build", "run")) + depends_on("py-pydeprecate@0.3.1", when="@1.4:1.5", type=("build", "run")) + depends_on("py-pydeprecate@0.3.0", when="@1.3", type=("build", "run")) From d925ba9bc67b7dbd638e678930758724124cefb5 Mon Sep 17 00:00:00 2001 From: Mikael Simberg Date: Tue, 1 Nov 2022 17:22:34 +0100 Subject: [PATCH 291/442] Add tracy 0.9 (#33638) * Add tracy 0.9 * Add conflict for pika and tracy@0.9: --- var/spack/repos/builtin/packages/pika/package.py | 1 + var/spack/repos/builtin/packages/tracy-client/package.py | 1 + var/spack/repos/builtin/packages/tracy/package.py | 1 + 3 files changed, 3 insertions(+) diff --git a/var/spack/repos/builtin/packages/pika/package.py b/var/spack/repos/builtin/packages/pika/package.py index 0eee028dd69..c4b2be6a683 100644 --- a/var/spack/repos/builtin/packages/pika/package.py +++ b/var/spack/repos/builtin/packages/pika/package.py @@ -98,6 +98,7 @@ class Pika(CMakePackage, CudaPackage, ROCmPackage): depends_on("rocblas", when="+rocm") depends_on("rocsolver", when="@0.5: +rocm") depends_on("tracy-client", when="+tracy") + conflicts("tracy-client@0.9:", when="@:0.9") depends_on("whip+rocm", when="@0.9: +rocm") depends_on("whip+cuda", when="@0.9: +cuda") diff --git a/var/spack/repos/builtin/packages/tracy-client/package.py b/var/spack/repos/builtin/packages/tracy-client/package.py index 2c81c7ff4d3..796cc116e50 100644 --- a/var/spack/repos/builtin/packages/tracy-client/package.py +++ b/var/spack/repos/builtin/packages/tracy-client/package.py @@ -15,6 +15,7 @@ class TracyClient(CMakePackage): maintainers = ["msimberg"] version("master", git="https://github.com/wolfpld/tracy.git", branch="master") + version("0.9", sha256="93a91544e3d88f3bc4c405bad3dbc916ba951cdaadd5fcec1139af6fa56e6bfc") version( "0.8.2", sha256="4784eddd89c17a5fa030d408392992b3da3c503c872800e9d3746d985cfcc92a", diff --git a/var/spack/repos/builtin/packages/tracy/package.py b/var/spack/repos/builtin/packages/tracy/package.py index 50d2f6564c0..e55054f31f2 100644 --- a/var/spack/repos/builtin/packages/tracy/package.py +++ b/var/spack/repos/builtin/packages/tracy/package.py @@ -15,6 +15,7 @@ class Tracy(MakefilePackage): maintainers = ["msimberg"] version("master", git="https://github.com/wolfpld/tracy.git", branch="master") + version("0.9", sha256="93a91544e3d88f3bc4c405bad3dbc916ba951cdaadd5fcec1139af6fa56e6bfc") version( "0.8.2", sha256="4784eddd89c17a5fa030d408392992b3da3c503c872800e9d3746d985cfcc92a", From 973b43b1c1340bd84c4f193f19a6ad01d8de8edb Mon Sep 17 00:00:00 2001 From: liuyangzhuan Date: Tue, 1 Nov 2022 10:28:01 -0700 Subject: [PATCH 292/442] superlu-dist: fix rocm variant for the master branch (#33624) * superlu-dist: fix rocm variant for the master branch * simplify superlu-dist * add mpi include to HIP_HIPCC_FLAGS Co-authored-by: liuyangzhuan --- var/spack/repos/builtin/packages/superlu-dist/package.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/var/spack/repos/builtin/packages/superlu-dist/package.py b/var/spack/repos/builtin/packages/superlu-dist/package.py index 21a5da15421..d429da8ce92 100644 --- a/var/spack/repos/builtin/packages/superlu-dist/package.py +++ b/var/spack/repos/builtin/packages/superlu-dist/package.py @@ -122,12 +122,15 @@ def append_from_variant(*args): if cuda_arch[0] != "none": append_define("CMAKE_CUDA_ARCHITECTURES", cuda_arch[0]) - if "+rocm" in spec and spec.satisfies("@amd"): + if "+rocm" in spec and (spec.satisfies("@amd") or spec.satisfies("@8:")): append_define("TPL_ENABLE_HIPLIB", True) append_define("HIP_ROOT_DIR", spec["hip"].prefix) rocm_archs = spec.variants["amdgpu_target"].value + mpiinc = spec["mpi"].prefix.include if "none" not in rocm_archs: - append_define("HIP_HIPCC_FLAGS", "--amdgpu-target=" + ",".join(rocm_archs)) + append_define( + "HIP_HIPCC_FLAGS", "--amdgpu-target=" + ",".join(rocm_archs) + " -I/" + mpiinc + ) append_from_variant("BUILD_SHARED_LIBS", "shared") return cmake_args From 23aef6bb945dc53d68af85820d7d9653d691e0ad Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Tue, 1 Nov 2022 19:04:45 +0100 Subject: [PATCH 293/442] Let pytest-cov create the xml directly (#33619) `coverage` sometimes failed to combine, even if there were multiple reports. --- .github/workflows/unit_tests.yaml | 8 +------- share/spack/qa/run-unit-tests | 2 +- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/.github/workflows/unit_tests.yaml b/.github/workflows/unit_tests.yaml index dcebecaeae4..80b4593c234 100644 --- a/.github/workflows/unit_tests.yaml +++ b/.github/workflows/unit_tests.yaml @@ -89,8 +89,6 @@ jobs: UNIT_TEST_COVERAGE: ${{ (matrix.python-version == '3.10') }} run: | share/spack/qa/run-unit-tests - coverage combine -a - coverage xml - uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 with: flags: unittests,linux,${{ matrix.concretizer }} @@ -182,8 +180,6 @@ jobs: SPACK_TEST_SOLVER: clingo run: | share/spack/qa/run-unit-tests - coverage combine -a - coverage xml - uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 # @v2.1.0 with: flags: unittests,linux,clingo @@ -218,9 +214,7 @@ jobs: $(which spack) bootstrap disable spack-install $(which spack) solve zlib common_args=(--dist loadfile --tx '4*popen//python=./bin/spack-tmpconfig python -u ./bin/spack python' -x) - $(which spack) unit-test --cov --cov-config=pyproject.toml "${common_args[@]}" - coverage combine -a - coverage xml + $(which spack) unit-test --cov --cov-config=pyproject.toml --cov-report=xml:coverage.xml "${common_args[@]}" - uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 with: flags: unittests,macos diff --git a/share/spack/qa/run-unit-tests b/share/spack/qa/run-unit-tests index 478e5822425..842a00caf2c 100755 --- a/share/spack/qa/run-unit-tests +++ b/share/spack/qa/run-unit-tests @@ -66,7 +66,7 @@ fi # where it seems that otherwise the configuration file might not be located by subprocesses # in some, not better specified, cases. if [[ "$UNIT_TEST_COVERAGE" == "true" ]]; then - $(which spack) unit-test -x --verbose --cov --cov-config=pyproject.toml + $(which spack) unit-test -x --verbose --cov --cov-config=pyproject.toml --cov-report=xml:coverage.xml else $(which spack) unit-test -x --verbose fi From 1abcc8caf7924a91739183ad425b460330293652 Mon Sep 17 00:00:00 2001 From: Cody Balos Date: Tue, 1 Nov 2022 11:45:53 -0700 Subject: [PATCH 294/442] sundials: add v6.4.1, new ginkgo and kokkos variants, plus some fixes (#33644) * sundials: add v6.4.1, new ginkgo and kokkos variants, plus some fixes * add missing kokkos/kokkos-kernels variant * add v6.4.0 --- .../builtin/packages/sundials/package.py | 88 ++++++++++++++++--- 1 file changed, 77 insertions(+), 11 deletions(-) diff --git a/var/spack/repos/builtin/packages/sundials/package.py b/var/spack/repos/builtin/packages/sundials/package.py index fe1bb0bef5d..d345bb793b4 100644 --- a/var/spack/repos/builtin/packages/sundials/package.py +++ b/var/spack/repos/builtin/packages/sundials/package.py @@ -27,6 +27,8 @@ class Sundials(CMakePackage, CudaPackage, ROCmPackage): # Versions # ========================================================================== version("develop", branch="develop") + version("6.4.1", sha256="7bf10a8d2920591af3fba2db92548e91ad60eb7241ab23350a9b1bc51e05e8d0") + version("6.4.0", sha256="0aff803a12c6d298d05b56839197dd09858631864017e255ed89e28b49b652f1") version("6.3.0", sha256="89a22bea820ff250aa7239f634ab07fa34efe1d2dcfde29cc8d3af11455ba2a7") version("6.2.0", sha256="195d5593772fc483f63f08794d79e4bab30c2ec58e6ce4b0fb6bcc0e0c48f31d") version("6.1.1", sha256="cfaf637b792c330396a25ef787eb59d58726c35918ebbc08e33466e45d50470c") @@ -122,9 +124,17 @@ class Sundials(CMakePackage, CudaPackage, ROCmPackage): when="@6.0.0: +profiling", description="Enable Caliper instrumentation/profiling", ) + variant("ginkgo", default=False, when="@6.4.0:", description="Enable Ginkgo interfaces") variant("hypre", default=False, when="@2.7.0:", description="Enable Hypre MPI parallel vector") - variant("lapack", default=False, description="Enable LAPACK direct solvers") + variant("kokkos", default=False, when="@6.4.0:", description="Enable Kokkos vector") + variant( + "kokkos-kernels", + default=False, + when="@6.4.0:", + description="Enable KokkosKernels based matrix and linear solver", + ) variant("klu", default=False, description="Enable KLU sparse, direct solver") + variant("lapack", default=False, description="Enable LAPACK direct solvers") variant("petsc", default=False, when="@2.7.0:", description="Enable PETSc interfaces") variant("magma", default=False, when="@5.7.0:", description="Enable MAGMA interface") variant("superlu-mt", default=False, description="Enable SuperLU_MT sparse, direct solver") @@ -205,6 +215,7 @@ class Sundials(CMakePackage, CudaPackage, ROCmPackage): # Build dependencies depends_on("cmake@3.12:", type="build") + depends_on("cmake@3.18:", when="+cuda", type="build") # MPI related dependencies depends_on("mpi", when="+mpi") @@ -219,6 +230,23 @@ class Sundials(CMakePackage, CudaPackage, ROCmPackage): # External libraries depends_on("caliper", when="+caliper") + depends_on("ginkgo@1.5.0:", when="+ginkgo") + depends_on("kokkos", when="+kokkos") + depends_on("kokkos-kernels", when="+kokkos-kernels") + for cuda_arch in CudaPackage.cuda_arch_values: + depends_on( + "kokkos+cuda+cuda_lambda+cuda_constexpr cuda_arch=%s" % cuda_arch, + when="+kokkos +cuda cuda_arch=%s" % cuda_arch, + ) + depends_on( + "kokkos-kernels+cuda cuda_arch=%s" % cuda_arch, + when="+kokkos-kernels +cuda cuda_arch=%s" % cuda_arch, + ) + for rocm_arch in ROCmPackage.amdgpu_targets: + depends_on( + "kokkos+rocm amdgpu_target=%s" % rocm_arch, + when="+kokkos +rocm amdgpu_target=%s" % rocm_arch, + ) depends_on("lapack", when="+lapack") depends_on("hypre+mpi~int64", when="@5.7.1: +hypre ~int64") depends_on("hypre+mpi+int64", when="@5.7.1: +hypre +int64") @@ -228,7 +256,8 @@ class Sundials(CMakePackage, CudaPackage, ROCmPackage): depends_on("petsc+mpi", when="+petsc") depends_on("suite-sparse", when="+klu") depends_on("superlu-dist@6.1.1:", when="@:5.4.0 +superlu-dist") - depends_on("superlu-dist@6.3.0:", when="@5.5.0: +superlu-dist") + depends_on("superlu-dist@6.3.0:", when="@5.5.0:6.3 +superlu-dist") + depends_on("superlu-dist@7:", when="@6.4: +superlu-dist") depends_on("trilinos+tpetra", when="+trilinos") # Require that external libraries built with the same precision @@ -337,6 +366,8 @@ def cmake_args(self): from_variant("SUPERLUMT_ENABLE", "superlu-mt"), from_variant("SUPERLUDIST_ENABLE", "superlu-dist"), from_variant("Trilinos_ENABLE", "trilinos"), + from_variant("ENABLE_KOKKOS", "kokkos"), + from_variant("ENABLE_KOKKOS_KERNELS", "kokkos-kernels"), from_variant("EXAMPLES_INSTALL", "examples-install"), ] ) @@ -367,6 +398,25 @@ def cmake_args(self): ] ) + # Building with Ginkgo + if "+ginkgo" in spec: + gko_backends = ["REF"] + if "+openmp" in spec["ginkgo"] and "+openmp" in spec: + gko_backends.append("OMP") + if "+cuda" in spec["ginkgo"] and "+cuda" in spec: + gko_backends.append("CUDA") + if "+rocm" in spec["ginkgo"] and "+rocm" in spec: + gko_backends.append("HIP") + if "+oneapi" in spec["ginkgo"] and "+sycl" in spec: + gko_backends.append("DPCPP") + args.extend( + [ + from_variant("ENABLE_GINKGO", "ginkgo"), + define("Ginkgo_DIR", spec["ginkgo"].prefix), + define("SUNDIALS_GINKGO_BACKENDS", ";".join(gko_backends)), + ] + ) + # Building with Hypre if "+hypre" in spec: args.extend( @@ -379,6 +429,12 @@ def cmake_args(self): hypre_libs = spec["blas"].libs + spec["lapack"].libs args.extend([define("HYPRE_LIBRARIES", hypre_libs.joined(";"))]) + # Building with Kokkos and KokkosKernels + if "+kokkos" in spec: + args.extend([define("Kokkos_DIR", spec["kokkos"].prefix)]) + if "+kokkos-kernels" in spec: + args.extend([define("KokkosKernels_DIR", spec["kokkos-kernels"].prefix)]) + # Building with KLU if "+klu" in spec: args.extend( @@ -404,6 +460,9 @@ def cmake_args(self): if "+petsc" in spec: if spec.version >= Version("5"): args.append(define("PETSC_DIR", spec["petsc"].prefix)) + if "+kokkos" in spec["petsc"]: + args.append(define("Kokkos_DIR", spec["kokkos"].prefix)) + args.append(define("KokkosKernels_DIR", spec["kokkos-kernels"].prefix)) else: args.extend( [ @@ -438,15 +497,22 @@ def cmake_args(self): # Building with SuperLU_DIST if "+superlu-dist" in spec: - args.extend( - [ - define("OPENMP_ENABLE", "^superlu-dist+openmp" in spec), - define("SUPERLUDIST_INCLUDE_DIR", spec["superlu-dist"].prefix.include), - define("SUPERLUDIST_LIBRARY_DIR", spec["superlu-dist"].prefix.lib), - define("SUPERLUDIST_LIBRARIES", spec["blas"].libs), - define("SUPERLUDIST_OpenMP", "^superlu-dist+openmp" in spec), - ] - ) + if spec.satisfies("@6.4.0:"): + args.extend( + [ + define("SUPERLUDIST_DIR", spec["superlu-dist"].prefix), + define("SUPERLUDIST_OpenMP", "^superlu-dist+openmp" in spec), + ] + ) + else: + args.extend( + [ + define("SUPERLUDIST_INCLUDE_DIR", spec["superlu-dist"].prefix.include), + define("SUPERLUDIST_LIBRARY_DIR", spec["superlu-dist"].prefix.lib), + define("SUPERLUDIST_LIBRARIES", spec["blas"].libs), + define("SUPERLUDIST_OpenMP", "^superlu-dist+openmp" in spec), + ] + ) # Building with Trilinos if "+trilinos" in spec: From 6dd2bb258c2ddf4004b0673705f78e13a472f5d3 Mon Sep 17 00:00:00 2001 From: Michael Kuhn Date: Tue, 1 Nov 2022 20:02:11 +0100 Subject: [PATCH 295/442] xz: add 5.2.7 (#33338) --- var/spack/repos/builtin/packages/hpctoolkit/package.py | 2 +- var/spack/repos/builtin/packages/xz/package.py | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/hpctoolkit/package.py b/var/spack/repos/builtin/packages/hpctoolkit/package.py index 5e7b70b299e..818df90af96 100644 --- a/var/spack/repos/builtin/packages/hpctoolkit/package.py +++ b/var/spack/repos/builtin/packages/hpctoolkit/package.py @@ -119,7 +119,7 @@ class Hpctoolkit(AutotoolsPackage): depends_on("libunwind@1.4: +xz+pic") depends_on("mbedtls+pic", when="@:2022.03") depends_on("xerces-c transcoder=iconv") - depends_on("xz+pic", type="link") + depends_on("xz+pic@:5.2.6", type="link") depends_on("yaml-cpp@0.7.0:", when="@2022.10:") depends_on("zlib+shared") diff --git a/var/spack/repos/builtin/packages/xz/package.py b/var/spack/repos/builtin/packages/xz/package.py index 440e67608ac..1224e0a9f94 100644 --- a/var/spack/repos/builtin/packages/xz/package.py +++ b/var/spack/repos/builtin/packages/xz/package.py @@ -20,10 +20,13 @@ class Xz(AutotoolsPackage, SourceforgePackage): executables = [r"^xz$"] + version("5.2.7", sha256="b65f1d0c2708e57716f4dd2216989a73847ac6fdb4168ffceb155767e22b834b") + version("5.2.6", sha256="13e3402e301b6018f6a71ef0e497f714c6d11e214ae82dab156b81c2a64acb25") version("5.2.5", sha256="5117f930900b341493827d63aa910ff5e011e0b994197c3b71c08a20228a42df") version("5.2.4", sha256="3313fd2a95f43d88e44264e6b015e7d03053e681860b0d5d3f9baca79c57b7bf") version("5.2.3", sha256="fd9ca16de1052aac899ad3495ad20dfa906c27b4a5070102a2ec35ca3a4740c1") version("5.2.2", sha256="6ff5f57a4b9167155e35e6da8b529de69270efb2b4cf3fbabf41a4ee793840b5") + version("5.2.1", sha256="679148f497e0bff2c1adce42dee5a23f746e71321c33ebb0f641a302e30c2a80") version("5.2.0", sha256="f7357d7455a1670229b3cca021da71dd5d13b789db62743c20624bdffc9cc4a5") variant("pic", default=False, description="Compile with position independent code.") From 6b3ea9463097524dfc1b329b0cd9af6d935a02e7 Mon Sep 17 00:00:00 2001 From: Michael Kuhn Date: Tue, 1 Nov 2022 20:13:53 +0100 Subject: [PATCH 296/442] perl: add 5.36.0 (#33336) --- var/spack/repos/builtin/packages/perl/package.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/var/spack/repos/builtin/packages/perl/package.py b/var/spack/repos/builtin/packages/perl/package.py index 5aa009a9a9c..d7b32543fde 100644 --- a/var/spack/repos/builtin/packages/perl/package.py +++ b/var/spack/repos/builtin/packages/perl/package.py @@ -46,45 +46,42 @@ class Perl(Package): # Perl doesn't use Autotools, it should subclass Package version("5.31.4", sha256="418a7e6fe6485cc713a86d1227ef112f0bb3f80322e3b715ffe42851d97804a5") # Maintenance releases (even numbers, recommended) + version( + "5.36.0", + sha256="e26085af8ac396f62add8a533c3a0ea8c8497d836f0689347ac5abd7b7a4e00a", + preferred=True, + ) version( "5.34.1", sha256="357951a491b0ba1ce3611263922feec78ccd581dddc24a446b033e25acf242a1", - preferred=True, ) version( "5.34.0", sha256="551efc818b968b05216024fb0b727ef2ad4c100f8cb6b43fab615fa78ae5be9a", - preferred=True, ) version( "5.32.1", sha256="03b693901cd8ae807231b1787798cf1f2e0b8a56218d07b7da44f784a7caeb2c", - preferred=True, ) version( "5.32.0", sha256="efeb1ce1f10824190ad1cadbcccf6fdb8a5d37007d0100d2d9ae5f2b5900c0b4", - preferred=True, ) version( "5.30.3", sha256="32e04c8bb7b1aecb2742a7f7ac0eabac100f38247352a73ad7fa104e39e7406f", - preferred=True, ) version( "5.30.2", sha256="66db7df8a91979eb576fac91743644da878244cf8ee152f02cd6f5cd7a731689", - preferred=True, ) version( "5.30.1", sha256="bf3d25571ff1ee94186177c2cdef87867fd6a14aa5a84f0b1fb7bf798f42f964", - preferred=True, ) version( "5.30.0", sha256="851213c754d98ccff042caa40ba7a796b2cee88c5325f121be5cbb61bbf975f2", - preferred=True, ) # End of life releases @@ -103,8 +100,9 @@ class Perl(Package): # Perl doesn't use Autotools, it should subclass Package extendable = True if not is_windows: + depends_on("gdbm@:1.23") # Bind us below gdbm-1.20 due to API change: https://github.com/Perl/perl5/issues/18915 - depends_on("gdbm@:1.19") + depends_on("gdbm@:1.19", when="@:5.35") # :5.28 needs gdbm@:1:14.1: https://rt-archive.perl.org/perl5/Ticket/Display.html?id=133295 depends_on("gdbm@:1.14.1", when="@:5.28.0") depends_on("berkeley-db") From 230e96fbb8d3e24082ce4f7571f05981be5c148b Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Tue, 1 Nov 2022 20:42:06 +0100 Subject: [PATCH 297/442] Add elf parsing utility function (#33628) Introduces `spack.util.elf.parse_elf(file_handle)` --- lib/spack/spack/test/conftest.py | 36 +++ lib/spack/spack/test/relocate.py | 56 +--- lib/spack/spack/test/util/elf.py | 130 +++++++++ lib/spack/spack/util/elf.py | 459 +++++++++++++++++++++++++++++++ 4 files changed, 635 insertions(+), 46 deletions(-) create mode 100644 lib/spack/spack/test/util/elf.py create mode 100644 lib/spack/spack/util/elf.py diff --git a/lib/spack/spack/test/conftest.py b/lib/spack/spack/test/conftest.py index 9ae346c720e..1f3c17916c5 100644 --- a/lib/spack/spack/test/conftest.py +++ b/lib/spack/spack/test/conftest.py @@ -1789,3 +1789,39 @@ def _spider(*args, **kwargs): @pytest.fixture(scope="function") def mock_tty_stdout(monkeypatch): monkeypatch.setattr(sys.stdout, "isatty", lambda: True) + + +@pytest.fixture() +def binary_with_rpaths(tmpdir): + """Factory fixture that compiles an ELF binary setting its RPATH. Relative + paths are encoded with `$ORIGIN` prepended. + """ + + def _factory(rpaths, message="Hello world!"): + source = tmpdir.join("main.c") + source.write( + """ + #include + int main(){{ + printf("{0}"); + }} + """.format( + message + ) + ) + gcc = spack.util.executable.which("gcc") + executable = source.dirpath("main.x") + # Encode relative RPATHs using `$ORIGIN` as the root prefix + rpaths = [x if os.path.isabs(x) else os.path.join("$ORIGIN", x) for x in rpaths] + rpath_str = ":".join(rpaths) + opts = [ + "-Wl,--disable-new-dtags", + "-Wl,-rpath={0}".format(rpath_str), + str(source), + "-o", + str(executable), + ] + gcc(*opts) + return executable + + return _factory diff --git a/lib/spack/spack/test/relocate.py b/lib/spack/spack/test/relocate.py index 4c9dd8be666..99dd7a460c4 100644 --- a/lib/spack/spack/test/relocate.py +++ b/lib/spack/spack/test/relocate.py @@ -82,42 +82,6 @@ def _factory(output): return _factory -@pytest.fixture() -def hello_world(tmpdir): - """Factory fixture that compiles an ELF binary setting its RPATH. Relative - paths are encoded with `$ORIGIN` prepended. - """ - - def _factory(rpaths, message="Hello world!"): - source = tmpdir.join("main.c") - source.write( - """ - #include - int main(){{ - printf("{0}"); - }} - """.format( - message - ) - ) - gcc = spack.util.executable.which("gcc") - executable = source.dirpath("main.x") - # Encode relative RPATHs using `$ORIGIN` as the root prefix - rpaths = [x if os.path.isabs(x) else os.path.join("$ORIGIN", x) for x in rpaths] - rpath_str = ":".join(rpaths) - opts = [ - "-Wl,--disable-new-dtags", - "-Wl,-rpath={0}".format(rpath_str), - str(source), - "-o", - str(executable), - ] - gcc(*opts) - return executable - - return _factory - - @pytest.fixture() def make_dylib(tmpdir_factory): """Create a shared library with unfriendly qualities. @@ -315,9 +279,9 @@ def test_set_elf_rpaths_warning(mock_patchelf): @pytest.mark.requires_executables("patchelf", "strings", "file", "gcc") @skip_unless_linux -def test_replace_prefix_bin(hello_world): +def test_replace_prefix_bin(binary_with_rpaths): # Compile an "Hello world!" executable and set RPATHs - executable = hello_world(rpaths=["/usr/lib", "/usr/lib64"]) + executable = binary_with_rpaths(rpaths=["/usr/lib", "/usr/lib64"]) # Relocate the RPATHs spack.relocate._replace_prefix_bin(str(executable), {b"/usr": b"/foo"}) @@ -328,9 +292,9 @@ def test_replace_prefix_bin(hello_world): @pytest.mark.requires_executables("patchelf", "strings", "file", "gcc") @skip_unless_linux -def test_relocate_elf_binaries_absolute_paths(hello_world, copy_binary, tmpdir): +def test_relocate_elf_binaries_absolute_paths(binary_with_rpaths, copy_binary, tmpdir): # Create an executable, set some RPATHs, copy it to another location - orig_binary = hello_world(rpaths=[str(tmpdir.mkdir("lib")), "/usr/lib64"]) + orig_binary = binary_with_rpaths(rpaths=[str(tmpdir.mkdir("lib")), "/usr/lib64"]) new_binary = copy_binary(orig_binary) spack.relocate.relocate_elf_binaries( @@ -350,9 +314,9 @@ def test_relocate_elf_binaries_absolute_paths(hello_world, copy_binary, tmpdir): @pytest.mark.requires_executables("patchelf", "strings", "file", "gcc") @skip_unless_linux -def test_relocate_elf_binaries_relative_paths(hello_world, copy_binary): +def test_relocate_elf_binaries_relative_paths(binary_with_rpaths, copy_binary): # Create an executable, set some RPATHs, copy it to another location - orig_binary = hello_world(rpaths=["lib", "lib64", "/opt/local/lib"]) + orig_binary = binary_with_rpaths(rpaths=["lib", "lib64", "/opt/local/lib"]) new_binary = copy_binary(orig_binary) spack.relocate.relocate_elf_binaries( @@ -371,8 +335,8 @@ def test_relocate_elf_binaries_relative_paths(hello_world, copy_binary): @pytest.mark.requires_executables("patchelf", "strings", "file", "gcc") @skip_unless_linux -def test_make_elf_binaries_relative(hello_world, copy_binary, tmpdir): - orig_binary = hello_world( +def test_make_elf_binaries_relative(binary_with_rpaths, copy_binary, tmpdir): + orig_binary = binary_with_rpaths( rpaths=[str(tmpdir.mkdir("lib")), str(tmpdir.mkdir("lib64")), "/opt/local/lib"] ) new_binary = copy_binary(orig_binary) @@ -393,8 +357,8 @@ def test_raise_if_not_relocatable(monkeypatch): @pytest.mark.requires_executables("patchelf", "strings", "file", "gcc") @skip_unless_linux -def test_relocate_text_bin(hello_world, copy_binary, tmpdir): - orig_binary = hello_world( +def test_relocate_text_bin(binary_with_rpaths, copy_binary, tmpdir): + orig_binary = binary_with_rpaths( rpaths=[str(tmpdir.mkdir("lib")), str(tmpdir.mkdir("lib64")), "/opt/local/lib"], message=str(tmpdir), ) diff --git a/lib/spack/spack/test/util/elf.py b/lib/spack/spack/test/util/elf.py new file mode 100644 index 00000000000..cf6b3aeb27e --- /dev/null +++ b/lib/spack/spack/test/util/elf.py @@ -0,0 +1,130 @@ +# Copyright 2013-2021 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) + + +import io + +import pytest + +import llnl.util.filesystem as fs + +import spack.platforms +import spack.util.elf as elf +import spack.util.executable + + +# note that our elf parser is platform independent... but I guess creating an elf file +# is slightly more difficult with system tools on non-linux. +def skip_unless_linux(f): + return pytest.mark.skipif( + str(spack.platforms.real_host()) != "linux", + reason="implementation currently requires linux", + )(f) + + +@pytest.mark.requires_executables("gcc") +@skip_unless_linux +def test_elf_get_rpaths(binary_with_rpaths): + # Compile an "Hello world!" executable and set RPATHs + long_rpaths = ["/very/long/prefix/x", "/very/long/prefix/y"] + executable = str(binary_with_rpaths(rpaths=long_rpaths)) + assert elf.get_rpaths(executable) == long_rpaths + + +@pytest.mark.requires_executables("gcc") +@skip_unless_linux +@pytest.mark.parametrize( + "linker_flag,is_runpath", + [ + ("-Wl,--disable-new-dtags", False), + ("-Wl,--enable-new-dtags", True), + ], +) +def test_elf_parsing_shared_linking(linker_flag, is_runpath, tmpdir): + gcc = spack.util.executable.which("gcc") + + with fs.working_dir(str(tmpdir)): + # Create a library to link to so we can force a dynamic section in an ELF file + with open("foo.c", "w") as f: + f.write("int foo(){return 0;}") + with open("bar.c", "w") as f: + f.write("int foo(); int _start(){return foo();}") + + # Create library and executable linking to it. + gcc("-shared", "-o", "libfoo.so", "-Wl,-soname,libfoo.so.1", "-nostdlib", "foo.c") + gcc( + "-o", + "bar", + linker_flag, + "-Wl,-rpath,/first", + "-Wl,-rpath,/second", + "-Wl,--no-as-needed", + "-nostdlib", + "libfoo.so", + "bar.c", + "-o", + "bar", + ) + + with open("libfoo.so", "rb") as f: + foo_parsed = elf.parse_elf(f, interpreter=True, dynamic_section=True) + + assert not foo_parsed.has_pt_interp + assert foo_parsed.has_pt_dynamic + assert not foo_parsed.has_rpath + assert not foo_parsed.has_needed + assert foo_parsed.has_soname + assert foo_parsed.dt_soname_str == b"libfoo.so.1" + + with open("bar", "rb") as f: + bar_parsed = elf.parse_elf(f, interpreter=True, dynamic_section=True) + + assert bar_parsed.has_pt_interp + assert bar_parsed.has_pt_dynamic + assert bar_parsed.has_rpath + assert bar_parsed.has_needed + assert not bar_parsed.has_soname + assert bar_parsed.dt_rpath_str == b"/first:/second" + assert bar_parsed.dt_needed_strs == [b"libfoo.so.1"] + + +def test_broken_elf(): + # No elf magic + with pytest.raises(elf.ElfParsingError, match="Not an ELF file"): + elf.parse_elf(io.BytesIO(b"x")) + + # Incomplete ELF header + with pytest.raises(elf.ElfParsingError, match="Not an ELF file"): + elf.parse_elf(io.BytesIO(b"\x7fELF")) + + # Invalid class + with pytest.raises(elf.ElfParsingError, match="Invalid class"): + elf.parse_elf(io.BytesIO(b"\x7fELF\x09\x01" + b"\x00" * 10)) + + # Invalid data type + with pytest.raises(elf.ElfParsingError, match="Invalid data type"): + elf.parse_elf(io.BytesIO(b"\x7fELF\x01\x09" + b"\x00" * 10)) + + # 64-bit needs at least 64 bytes of header; this is only 56 bytes + with pytest.raises(elf.ElfParsingError, match="ELF header malformed"): + elf.parse_elf(io.BytesIO(b"\x7fELF\x02\x01" + b"\x00" * 50)) + + # 32-bit needs at least 52 bytes of header; this is only 46 bytes + with pytest.raises(elf.ElfParsingError, match="ELF header malformed"): + elf.parse_elf(io.BytesIO(b"\x7fELF\x01\x01" + b"\x00" * 40)) + + # Not a ET_DYN/ET_EXEC on a 32-bit LE ELF + with pytest.raises(elf.ElfParsingError, match="Not an ET_DYN or ET_EXEC"): + elf.parse_elf(io.BytesIO(b"\x7fELF\x01\x01" + (b"\x00" * 10) + b"\x09" + (b"\x00" * 35))) + + +def test_parser_doesnt_deal_with_nonzero_offset(): + # Currently we don't have logic to parse ELF files at nonzero offsets in a file + # This could be useful when e.g. modifying an ELF file inside a tarball or so, + # but currently we cannot. + elf_at_offset_one = io.BytesIO(b"\x00\x7fELF\x01\x01" + b"\x00" * 10) + elf_at_offset_one.read(1) + with pytest.raises(elf.ElfParsingError, match="Cannot parse at a nonzero offset"): + elf.parse_elf(elf_at_offset_one) diff --git a/lib/spack/spack/util/elf.py b/lib/spack/spack/util/elf.py new file mode 100644 index 00000000000..bb9bfbb22d2 --- /dev/null +++ b/lib/spack/spack/util/elf.py @@ -0,0 +1,459 @@ +# Copyright 2013-2021 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) + +import bisect +import struct +import sys +from collections import namedtuple +from struct import calcsize, unpack, unpack_from + +ElfHeader = namedtuple( + "ElfHeader", + [ + "e_type", + "e_machine", + "e_version", + "e_entry", + "e_phoff", + "e_shoff", + "e_flags", + "e_ehsize", + "e_phentsize", + "e_phnum", + "e_shentsize", + "e_shnum", + "e_shstrndx", + ], +) + +SectionHeader = namedtuple( + "SectionHeader", + [ + "sh_name", + "sh_type", + "sh_flags", + "sh_addr", + "sh_offset", + "sh_size", + "sh_link", + "sh_info", + "sh_addralign", + "sh_entsize", + ], +) + +ProgramHeader32 = namedtuple( + "ProgramHeader32", + [ + "p_type", + "p_offset", + "p_vaddr", + "p_paddr", + "p_filesz", + "p_memsz", + "p_flags", + "p_align", + ], +) + +ProgramHeader64 = namedtuple( + "ProgramHeader64", + [ + "p_type", + "p_flags", + "p_offset", + "p_vaddr", + "p_paddr", + "p_filesz", + "p_memsz", + "p_align", + ], +) + + +class ELF_CONSTANTS: + MAGIC = b"\x7fELF" + CLASS32 = 1 + CLASS64 = 2 + DATA2LSB = 1 + DATA2MSB = 2 + ET_EXEC = 2 + ET_DYN = 3 + PT_LOAD = 1 + PT_DYNAMIC = 2 + PT_INTERP = 3 + DT_NULL = 0 + DT_NEEDED = 1 + DT_STRTAB = 5 + DT_SONAME = 14 + DT_RPATH = 15 + DT_RUNPATH = 29 + SHT_STRTAB = 3 + + +def get_byte_at(byte_array, idx): + if sys.version_info[0] < 3: + return ord(byte_array[idx]) + return byte_array[idx] + + +class ElfParsingError(Exception): + pass + + +class ElfFile(object): + """Parsed ELF file.""" + + __slots__ = [ + "is_64_bit", + "is_little_endian", + "byte_order", + "elf_hdr", + "pt_load", + # pt_interp + "has_pt_interp", + "pt_interp_p_offset", + "pt_interp_p_filesz", + "pt_interp_str", + # pt_dynamic + "has_pt_dynamic", + "pt_dynamic_p_offset", + "pt_dynamic_p_filesz", + # rpath + "has_rpath", + "dt_rpath_offset", + "dt_rpath_str", + "rpath_strtab_offset", + "is_runpath", + # dt needed + "has_needed", + "dt_needed_strtab_offsets", + "dt_needed_strs", + # dt soname + "has_soname", + "dt_soname_strtab_offset", + "dt_soname_str", + ] + + def __init__(self): + self.dt_needed_strtab_offsets = [] + self.has_soname = False + self.has_rpath = False + self.has_needed = False + self.pt_load = [] + self.has_pt_dynamic = False + self.has_pt_interp = False + + +def parse_c_string(byte_string, start=0): + """ + Retrieve a C-string at a given offset in a byte string + + Arguments: + byte_string (bytes): String + start (int): Offset into the string + + Returns: + bytes: A copy of the C-string excluding the terminating null byte + """ + str_end = byte_string.find(b"\0", start) + if str_end == -1: + raise ElfParsingError("C-string is not null terminated") + return byte_string[start:str_end] + + +def read_exactly(f, num_bytes, msg): + """ + Read exactly num_bytes at the current offset, otherwise raise + a parsing error with the given error message. + + Arguments: + f: file handle + num_bytes (int): Number of bytes to read + msg (str): Error to show when bytes cannot be read + + Returns: + bytes: the ``num_bytes`` bytes that were read. + """ + data = f.read(num_bytes) + if len(data) != num_bytes: + raise ElfParsingError(msg) + return data + + +def parse_program_headers(f, elf): + """ + Parse program headers + + Arguments: + f: file handle + elf (ElfFile): ELF file parser data + """ + # Forward to the program header + f.seek(elf.elf_hdr.e_phoff) + + # Here we have to make a mapping from virtual address to offset in the file. + ProgramHeader = ProgramHeader64 if elf.is_64_bit else ProgramHeader32 + ph_fmt = elf.byte_order + ("LLQQQQQQ" if elf.is_64_bit else "LLLLLLLL") + ph_size = calcsize(ph_fmt) + ph_num = elf.elf_hdr.e_phnum + + # Read all program headers in one go + data = read_exactly(f, ph_num * ph_size, "Malformed program header") + + for i in range(ph_num): + ph = ProgramHeader._make(unpack_from(ph_fmt, data, i * ph_size)) + + # Skip segments of size 0; we don't distinguish between missing segment and + # empty segments. I've see an empty PT_DYNAMIC section for an ELF file that + # contained debug data. + if ph.p_filesz == 0: + continue + + # For PT_LOAD entries: Save offsets and virtual addrs of the loaded ELF segments + # This way we can map offsets by virtual address to offsets in the file. + if ph.p_type == ELF_CONSTANTS.PT_LOAD: + elf.pt_load.append((ph.p_offset, ph.p_vaddr)) + + elif ph.p_type == ELF_CONSTANTS.PT_INTERP: + elf.pt_interp_p_offset = ph.p_offset + elf.pt_interp_p_filesz = ph.p_filesz + elf.has_pt_interp = True + + elif ph.p_type == ELF_CONSTANTS.PT_DYNAMIC: + elf.pt_dynamic_p_offset = ph.p_offset + elf.pt_dynamic_p_filesz = ph.p_filesz + elf.has_pt_dynamic = True + + # The linker sorts PT_LOAD segments by vaddr, but let's do it just to be sure, since + # patchelf for example has a flag to leave them in an arbitrary order. + elf.pt_load.sort(key=lambda x: x[1]) + + +def parse_pt_interp(f, elf): + """ + Parse the interpreter (i.e. absolute path to the dynamic linker) + + Arguments: + f: file handle + elf (ElfFile): ELF file parser data + """ + f.seek(elf.pt_interp_p_offset) + data = read_exactly(f, elf.pt_interp_p_filesz, "Malformed PT_INTERP entry") + elf.pt_interp_str = parse_c_string(data) + + +def find_strtab_size_at_offset(f, elf, offset): + """ + Retrieve the size of a string table section at a particular known offset + + Arguments: + f: file handle + elf (ElfFile): ELF file parser data + offset (int): offset of the section in the file (i.e. ``sh_offset``) + + Returns: + int: the size of the string table in bytes + """ + section_hdr_fmt = elf.byte_order + ("LLQQQQLLQQ" if elf.is_64_bit else "LLLLLLLLLL") + section_hdr_size = calcsize(section_hdr_fmt) + f.seek(elf.elf_hdr.e_shoff) + for _ in range(elf.elf_hdr.e_shnum): + data = read_exactly(f, section_hdr_size, "Malformed section header") + sh = SectionHeader._make(unpack(section_hdr_fmt, data)) + if sh.sh_type == ELF_CONSTANTS.SHT_STRTAB and sh.sh_offset == offset: + return sh.sh_size + + raise ElfParsingError("Could not determine strtab size") + + +def retrieve_strtab(f, elf, offset): + """ + Read a full string table at the given offset, which + requires looking it up in the section headers. + + Arguments: + elf (ElfFile): ELF file parser data + vaddr (int): virtual address + + Returns: + bytes: file offset + """ + size = find_strtab_size_at_offset(f, elf, offset) + f.seek(offset) + return read_exactly(f, size, "Could not read string table") + + +def vaddr_to_offset(elf, vaddr): + """ + Given a virtual address, find the corresponding offset in the ELF file itself. + + Arguments: + elf (ElfFile): ELF file parser data + vaddr (int): virtual address + """ + idx = bisect.bisect_right([p_vaddr for (p_offset, p_vaddr) in elf.pt_load], vaddr) - 1 + p_offset, p_vaddr = elf.pt_load[idx] + return p_offset - p_vaddr + vaddr + + +def parse_pt_dynamic(f, elf): + """ + Parse the dynamic section of an ELF file + + Arguments: + f: file handle + elf (ElfFile): ELF file parse data + """ + dynamic_array_fmt = elf.byte_order + ("qQ" if elf.is_64_bit else "lL") + dynamic_array_size = calcsize(dynamic_array_fmt) + + current_offset = elf.pt_dynamic_p_offset + count_rpath = 0 + count_runpath = 0 + count_strtab = 0 + + f.seek(elf.pt_dynamic_p_offset) + + # In case of broken ELF files, don't read beyond the advertized size. + for _ in range(elf.pt_dynamic_p_filesz // dynamic_array_size): + data = read_exactly(f, dynamic_array_size, "Malformed dynamic array entry") + tag, val = unpack(dynamic_array_fmt, data) + if tag == ELF_CONSTANTS.DT_NULL: + break + elif tag == ELF_CONSTANTS.DT_RPATH: + count_rpath += 1 + elf.rpath_strtab_offset = val + elf.dt_rpath_offset = current_offset + elf.is_runpath = False + elf.has_rpath = True + elif tag == ELF_CONSTANTS.DT_RUNPATH: + count_runpath += 1 + elf.rpath_strtab_offset = val + elf.dt_rpath_offset = current_offset + elf.is_runpath = True + elf.has_rpath = True + elif tag == ELF_CONSTANTS.DT_STRTAB: + count_strtab += 1 + strtab_vaddr = val + elif tag == ELF_CONSTANTS.DT_NEEDED: + elf.has_needed = True + elf.dt_needed_strtab_offsets.append(val) + elif tag == ELF_CONSTANTS.DT_SONAME: + elf.has_soname = True + elf.dt_soname_strtab_offset = val + current_offset += dynamic_array_size + + # No rpath/runpath, that happens. + if count_rpath == count_runpath == 0: + elf.has_rpath = False + elif count_rpath + count_runpath != 1: + raise ElfParsingError("Could not find a unique rpath/runpath.") + + if count_strtab != 1: + raise ElfParsingError("Could not find a unique strtab of for the dynamic section strings") + + # Nothing to retrieve, so don't bother getting the string table. + if not (elf.has_rpath or elf.has_soname or elf.has_needed): + return + + string_table = retrieve_strtab(f, elf, vaddr_to_offset(elf, strtab_vaddr)) + + if elf.has_needed: + elf.dt_needed_strs = list( + parse_c_string(string_table, offset) for offset in elf.dt_needed_strtab_offsets + ) + + if elf.has_soname: + elf.dt_soname_str = parse_c_string(string_table, elf.dt_soname_strtab_offset) + + if elf.has_rpath: + elf.dt_rpath_str = parse_c_string(string_table, elf.rpath_strtab_offset) + + +def parse_header(f, elf): + # Read the 32/64 bit class independent part of the header and validate + e_ident = f.read(16) + + # Require ELF magic bytes. + if len(e_ident) != 16 or e_ident[:4] != ELF_CONSTANTS.MAGIC: + raise ElfParsingError("Not an ELF file") + + # Defensively require a valid class and data. + e_ident_class, e_ident_data = get_byte_at(e_ident, 4), get_byte_at(e_ident, 5) + + if e_ident_class not in (ELF_CONSTANTS.CLASS32, ELF_CONSTANTS.CLASS64): + raise ElfParsingError("Invalid class found") + + if e_ident_data not in (ELF_CONSTANTS.DATA2LSB, ELF_CONSTANTS.DATA2MSB): + raise ElfParsingError("Invalid data type") + + elf.is_64_bit = e_ident_class == ELF_CONSTANTS.CLASS64 + elf.is_little_endian = e_ident_data == ELF_CONSTANTS.DATA2LSB + + # Set up byte order and types for unpacking + elf.byte_order = "<" if elf.is_little_endian else ">" + + # Parse the rest of the header + elf_header_fmt = elf.byte_order + ("HHLQQQLHHHHHH" if elf.is_64_bit else "HHLLLLLHHHHHH") + hdr_size = calcsize(elf_header_fmt) + data = read_exactly(f, hdr_size, "ELF header malformed") + elf.elf_hdr = ElfHeader._make(unpack(elf_header_fmt, data)) + + +def _do_parse_elf(f, interpreter=True, dynamic_section=True): + # We don't (yet?) allow parsing ELF files at a nonzero offset, we just + # jump to absolute offsets as they are specified in the ELF file. + if f.tell() != 0: + raise ElfParsingError("Cannot parse at a nonzero offset") + + elf = ElfFile() + parse_header(f, elf) + + # We don't handle anything but executables and shared libraries now. + if elf.elf_hdr.e_type not in (ELF_CONSTANTS.ET_EXEC, ELF_CONSTANTS.ET_DYN): + raise ElfParsingError("Not an ET_DYN or ET_EXEC type") + + parse_program_headers(f, elf) + + # Parse PT_INTERP section + if interpreter and elf.has_pt_interp: + parse_pt_interp(f, elf) + + # Parse PT_DYNAMIC section. + if dynamic_section and elf.has_pt_dynamic and len(elf.pt_load) > 0: + parse_pt_dynamic(f, elf) + + return elf + + +def parse_elf(f, interpreter=False, dynamic_section=False): + """Given a file handle f for an ELF file opened in binary mode, return an ElfFile + object that is stores data about rpaths""" + try: + return _do_parse_elf(f, interpreter, dynamic_section) + except (DeprecationWarning, struct.error): + # According to the docs old versions of Python can throw DeprecationWarning + # instead of struct.error. + raise ElfParsingError("Malformed ELF file") + + +def get_rpaths(path): + """Returns list of rpaths of the given file as UTF-8 strings, or None if the file + does not have any rpaths.""" + try: + with open(path, "rb") as f: + elf = parse_elf(f, interpreter=False, dynamic_section=True) + except ElfParsingError: + return None + + if not elf.has_rpath: + return None + + # If it does, split the string in components + rpath = elf.dt_rpath_str + if sys.version_info[0] >= 3: + rpath = rpath.decode("utf-8") + return rpath.split(":") From 75360bdc2113db78aaf5fa3e2a4b9555e7efd783 Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Tue, 1 Nov 2022 22:11:49 +0100 Subject: [PATCH 298/442] Allow target requirements in packages.yaml (#32528) This PR solves the issue reported in #32471 specifically for targets and operating systems, by avoiding to add a default platform to anonymous specs. --- lib/spack/spack/spec.py | 13 ------------- lib/spack/spack/test/abi.py | 2 +- lib/spack/spack/test/architecture.py | 3 +++ lib/spack/spack/test/concretize.py | 19 +++++++++++++++++++ .../spack/test/concretize_preferences.py | 3 +++ lib/spack/spack/test/spec_syntax.py | 6 ++++++ 6 files changed, 32 insertions(+), 14 deletions(-) diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py index a05451b7b41..41bb7b57eef 100644 --- a/lib/spack/spack/spec.py +++ b/lib/spack/spack/spec.py @@ -2,7 +2,6 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - """ Spack allows very fine-grained control over how packages are installed and over how they are built and configured. To make this easy, it has its own @@ -1506,17 +1505,6 @@ def add_dependency_edge(self, dependency_spec, deptype): self._dependencies.add(edge) dependency_spec._dependents.add(edge) - def _add_default_platform(self): - """If a spec has an os or a target and no platform, give it - the default platform. - - This is private because it is used by the parser -- it's not - expected to be used outside of ``spec.py``. - """ - arch = self.architecture - if arch and not arch.platform and (arch.os or arch.target): - self._set_architecture(platform=spack.platforms.host().name) - # # Public interface # @@ -5318,7 +5306,6 @@ def spec(self, name): else: break - spec._add_default_platform() return spec def variant(self, name=None): diff --git a/lib/spack/spack/test/abi.py b/lib/spack/spack/test/abi.py index 5c3d0fa83d5..91560939797 100644 --- a/lib/spack/spack/test/abi.py +++ b/lib/spack/spack/test/abi.py @@ -22,7 +22,7 @@ ("platform=linux", "arch=linux-fedora31-x86_64", True), ("platform=linux os=fedora31", "platform=linux", True), ("platform=darwin", "arch=linux-fedora31-x86_64", False), - ("os=fedora31", "platform=linux", False), # TODO should be true ? + ("os=fedora31", "platform=linux", True), ], ) def test_architecture_compatibility(target, constraint, expected): diff --git a/lib/spack/spack/test/architecture.py b/lib/spack/spack/test/architecture.py index 64bb57d474b..c357c650e8e 100644 --- a/lib/spack/spack/test/architecture.py +++ b/lib/spack/spack/test/architecture.py @@ -199,6 +199,9 @@ def test_satisfy_strict_constraint_when_not_concrete(architecture_tuple, constra def test_concretize_target_ranges(root_target_range, dep_target_range, result): # use foobar=bar to make the problem simpler for the old concretizer # the new concretizer should not need that help + if spack.config.get("config:concretizer") == "original": + pytest.skip("Fixing the parser broke this test for the original concretizer.") + spec_str = "a %%gcc@10 foobar=bar target=%s ^b target=%s" % ( root_target_range, dep_target_range, diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py index ffc05a7fc0e..9f380975ede 100644 --- a/lib/spack/spack/test/concretize.py +++ b/lib/spack/spack/test/concretize.py @@ -337,6 +337,9 @@ def test_architecture_deep_inheritance(self, mock_targets): information from the root even when partial architecture information is provided by an intermediate dependency. """ + if spack.config.get("config:concretizer") == "original": + pytest.skip("Fixing the parser broke this test for the original concretizer.") + spec_str = "mpileaks %gcc@4.5.0 os=CNL target=nocona" " ^dyninst os=CNL ^callpath os=CNL" spec = Spec(spec_str).concretized() for s in spec.traverse(root=False): @@ -1837,3 +1840,19 @@ def test_installed_specs_disregard_conflicts(self, mutable_database, monkeypatch with spack.config.override("concretizer:reuse", True): s = Spec("mpich").concretized() assert s.satisfies("~debug") + + @pytest.mark.regression("32471") + def test_require_targets_are_allowed(self, mutable_database): + """Test that users can set target constraints under the require attribute.""" + if spack.config.get("config:concretizer") == "original": + pytest.xfail("Use case not supported by the original concretizer") + + # Configuration to be added to packages.yaml + external_conf = {"all": {"require": "target=x86_64"}} + spack.config.set("packages", external_conf) + + with spack.config.override("concretizer:reuse", False): + spec = Spec("mpich").concretized() + + for s in spec.traverse(): + assert s.satisfies("target=x86_64") diff --git a/lib/spack/spack/test/concretize_preferences.py b/lib/spack/spack/test/concretize_preferences.py index 9ad5a498ee8..a6e568bd113 100644 --- a/lib/spack/spack/test/concretize_preferences.py +++ b/lib/spack/spack/test/concretize_preferences.py @@ -105,6 +105,9 @@ def test_preferred_variants_from_wildcard(self): def test_preferred_compilers(self): """Test preferred compilers are applied correctly""" + if spack.config.get("config:concretizer") == "original": + pytest.skip("Fixing the parser broke this test for the original concretizer.") + # Need to make sure the test uses an available compiler compiler_list = spack.compilers.all_compiler_specs() assert compiler_list diff --git a/lib/spack/spack/test/spec_syntax.py b/lib/spack/spack/test/spec_syntax.py index c9394bf8ab6..d73e226d116 100644 --- a/lib/spack/spack/test/spec_syntax.py +++ b/lib/spack/spack/test/spec_syntax.py @@ -912,3 +912,9 @@ def test_git_ref_spec_equivalences(self, mock_packages, mock_stage): assert not s_no_git.satisfies(s1) assert not s2.satisfies(s1) assert not s3.satisfies(s1) + + @pytest.mark.regression("32471") + @pytest.mark.parametrize("spec_str", ["target=x86_64", "os=redhat6", "target=x86_64:"]) + def test_platform_is_none_if_not_present(self, spec_str): + s = sp.Spec(spec_str) + assert s.architecture.platform is None, s From e0265745bc10f37a9343b74a7e0128f7cdf0a9c7 Mon Sep 17 00:00:00 2001 From: Greg Sjaardema Date: Tue, 1 Nov 2022 15:29:50 -0600 Subject: [PATCH 299/442] Update command option for example (#33321) The `spack info ` command does not show the `Virtual Packages:` output unless the `--virtuals` command option is passed. Before this changes, the information that the command is supposed to be illustrating is not shown in the example and is confusing. --- lib/spack/docs/basic_usage.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/spack/docs/basic_usage.rst b/lib/spack/docs/basic_usage.rst index b8b758e6eda..95c37dd8bf8 100644 --- a/lib/spack/docs/basic_usage.rst +++ b/lib/spack/docs/basic_usage.rst @@ -1438,7 +1438,7 @@ built. You can see what virtual packages a particular package provides by getting info on it: -.. command-output:: spack info mpich +.. command-output:: spack info --virtuals mpich Spack is unique in that its virtual packages can be versioned, just like regular packages. A particular version of a package may provide From f696f02a46f711600267ef171f94bd93cdd73a99 Mon Sep 17 00:00:00 2001 From: Greg Becker Date: Tue, 1 Nov 2022 15:25:55 -0700 Subject: [PATCH 300/442] Unit tests: make unit tests work for aarch64 machines (#33625) Currently, many tests hardcode to older versions of gcc for comparisons of concretization among compiler versions. Those versions are too old to concretize for `aarch64`-family targets, which leads to failing tests on `aarch64`. This PR fixes those tests by updating the compiler versions used for testing. Currently, many tests hardcode the expected architecture result in concretization to the `x86_64` family of architectures. This PR generalizes the tests that can be generalized, to cover multiple architecture families. For those that test specific relationships among `x86_64`-family targets, it ensures that concretization uses the `x86_64`-family targets in those cases. Currently, many tests rely on the fact that `AutotoolsPackage` imposes no dependencies on the inheriting package. That is not true on `aarch64`-family architectures. This PR ensures that the fact `AutotoolsPackage` on `aarch64` pulls in a dependency on `gnuconfig` is ignored when testing for the appropriate relationships among dependencies Additionally, 5 tests currently prompt the user for input when `gpg` is available in the user's path. This PR fixes that issue. And 7 tests fail currently when the user has a yubikey available. This PR fixes the incorrect gpg argument causing those issues. --- lib/spack/spack/compilers/__init__.py | 4 + lib/spack/spack/concretize.py | 2 +- lib/spack/spack/environment/environment.py | 2 +- lib/spack/spack/hooks/sbang.py | 4 +- lib/spack/spack/platforms/test.py | 11 +- lib/spack/spack/spec.py | 2 +- lib/spack/spack/test/architecture.py | 7 +- lib/spack/spack/test/build_systems.py | 3 +- lib/spack/spack/test/cmd/ci.py | 67 ++++--- lib/spack/spack/test/cmd/config.py | 6 +- lib/spack/spack/test/cmd/find.py | 2 +- lib/spack/spack/test/cmd/install.py | 21 ++- lib/spack/spack/test/cmd/style.py | 10 +- lib/spack/spack/test/concretize.py | 63 ++++--- .../spack/test/concretize_preferences.py | 6 +- lib/spack/spack/test/conftest.py | 9 +- .../spack/test/data/config/compilers.yaml | 167 +++++++++++++++++- .../spack/test/data/config/packages.yaml | 12 +- lib/spack/spack/test/installer.py | 10 +- lib/spack/spack/test/modules/lmod.py | 2 +- lib/spack/spack/test/sbang.py | 7 +- lib/spack/spack/test/spec_semantics.py | 2 +- lib/spack/spack/test/spec_syntax.py | 8 +- lib/spack/spack/util/gpg.py | 4 +- .../builtin.mock/packages/bowtie/package.py | 2 + .../impossible-concretization/package.py | 1 + .../builtin.mock/packages/openblas/package.py | 4 + 27 files changed, 347 insertions(+), 91 deletions(-) diff --git a/lib/spack/spack/compilers/__init__.py b/lib/spack/spack/compilers/__init__.py index 1d61f37df79..05ffaf9f6c3 100644 --- a/lib/spack/spack/compilers/__init__.py +++ b/lib/spack/spack/compilers/__init__.py @@ -346,6 +346,10 @@ def compilers_for_arch(arch_spec, scope=None): return list(get_compilers(config, arch_spec=arch_spec)) +def compiler_specs_for_arch(arch_spec, scope=None): + return [c.spec for c in compilers_for_arch(arch_spec, scope)] + + class CacheReference(object): """This acts as a hashable reference to any object (regardless of whether the object itself is hashable) and also prevents the object from being diff --git a/lib/spack/spack/concretize.py b/lib/spack/spack/concretize.py index 3fbc7e8bff9..31066de0264 100644 --- a/lib/spack/spack/concretize.py +++ b/lib/spack/spack/concretize.py @@ -734,7 +734,7 @@ def concretize_specs_together(*abstract_specs, **kwargs): Returns: List of concretized specs """ - if spack.config.get("config:concretizer") == "original": + if spack.config.get("config:concretizer", "clingo") == "original": return _concretize_specs_together_original(*abstract_specs, **kwargs) return _concretize_specs_together_new(*abstract_specs, **kwargs) diff --git a/lib/spack/spack/environment/environment.py b/lib/spack/spack/environment/environment.py index 843cd5ff9c4..1353b76b566 100644 --- a/lib/spack/spack/environment/environment.py +++ b/lib/spack/spack/environment/environment.py @@ -1376,7 +1376,7 @@ def _concretize_separately(self, tests=False): arguments.append((uspec_constraints, tests)) # Ensure we don't try to bootstrap clingo in parallel - if spack.config.get("config:concretizer") == "clingo": + if spack.config.get("config:concretizer", "clingo") == "clingo": with spack.bootstrap.ensure_bootstrap_configuration(): spack.bootstrap.ensure_clingo_importable_or_raise() diff --git a/lib/spack/spack/hooks/sbang.py b/lib/spack/spack/hooks/sbang.py index 8731ef0c079..5d2de2b8655 100644 --- a/lib/spack/spack/hooks/sbang.py +++ b/lib/spack/spack/hooks/sbang.py @@ -205,7 +205,9 @@ def install_sbang(): fs.set_install_permissions(sbang_bin_dir) # set group on sbang_bin_dir if not already set (only if set in configuration) - if group_name and grp.getgrgid(os.stat(sbang_bin_dir).st_gid).gr_name != group_name: + # TODO: after we drop python2 support, use shutil.chown to avoid gid lookups that + # can fail for remote groups + if group_name and os.stat(sbang_bin_dir).st_gid != grp.getgrnam(group_name).gr_gid: os.chown(sbang_bin_dir, os.stat(sbang_bin_dir).st_uid, grp.getgrnam(group_name).gr_gid) # copy over the fresh copy of `sbang` diff --git a/lib/spack/spack/platforms/test.py b/lib/spack/spack/platforms/test.py index d181f2e9262..26fe943394e 100644 --- a/lib/spack/spack/platforms/test.py +++ b/lib/spack/spack/platforms/test.py @@ -16,9 +16,14 @@ class Test(Platform): if platform.system().lower() == "darwin": binary_formats = ["macho"] - front_end = "x86_64" - back_end = "core2" - default = "core2" + if platform.machine() == "arm64": + front_end = "aarch64" + back_end = "m1" + default = "m1" + else: + front_end = "x86_64" + back_end = "core2" + default = "core2" front_os = "redhat6" back_os = "debian6" diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py index 41bb7b57eef..10f6dfb8e9f 100644 --- a/lib/spack/spack/spec.py +++ b/lib/spack/spack/spec.py @@ -2945,7 +2945,7 @@ def concretize(self, tests=False): if a list of names activate them for the packages in the list, if True activate 'test' dependencies for all packages. """ - if spack.config.get("config:concretizer") == "clingo": + if spack.config.get("config:concretizer", "clingo") == "clingo": self._new_concretize(tests) else: self._old_concretize(tests) diff --git a/lib/spack/spack/test/architecture.py b/lib/spack/spack/test/architecture.py index c357c650e8e..746be0c8be4 100644 --- a/lib/spack/spack/test/architecture.py +++ b/lib/spack/spack/test/architecture.py @@ -140,7 +140,7 @@ def test_optimization_flags(compiler_spec, target_name, expected_flags, config): (spack.spec.CompilerSpec("gcc@9.2.0"), None, "haswell", "-march=haswell -mtune=haswell"), # Check that custom string versions are accepted ( - spack.spec.CompilerSpec("gcc@foo"), + spack.spec.CompilerSpec("gcc@10foo"), "9.2.0", "icelake", "-march=icelake-client -mtune=icelake-client", @@ -196,7 +196,10 @@ def test_satisfy_strict_constraint_when_not_concrete(architecture_tuple, constra ], ) @pytest.mark.usefixtures("mock_packages", "config") -def test_concretize_target_ranges(root_target_range, dep_target_range, result): +def test_concretize_target_ranges(root_target_range, dep_target_range, result, monkeypatch): + # Monkeypatch so that all concretization is done as if the machine is core2 + monkeypatch.setattr(spack.platforms.test.Test, "default", "core2") + # use foobar=bar to make the problem simpler for the old concretizer # the new concretizer should not need that help if spack.config.get("config:concretizer") == "original": diff --git a/lib/spack/spack/test/build_systems.py b/lib/spack/spack/test/build_systems.py index c4255eef49b..03a920a28e3 100644 --- a/lib/spack/spack/test/build_systems.py +++ b/lib/spack/spack/test/build_systems.py @@ -204,11 +204,12 @@ def test_autotools_gnuconfig_replacement_disabled(self, mutable_database): assert "gnuconfig version of config.guess" not in f.read() @pytest.mark.disable_clean_stage_check - def test_autotools_gnuconfig_replacement_no_gnuconfig(self, mutable_database): + def test_autotools_gnuconfig_replacement_no_gnuconfig(self, mutable_database, monkeypatch): """ Tests whether a useful error message is shown when patch_config_files is enabled, but gnuconfig is not listed as a direct build dependency. """ + monkeypatch.setattr(spack.platforms.test.Test, "default", "x86_64") s = Spec("autotools-config-replacement +patch_config_files ~gnuconfig") s.concretize() diff --git a/lib/spack/spack/test/cmd/ci.py b/lib/spack/spack/test/cmd/ci.py index 117dec0ed4e..5529defee51 100644 --- a/lib/spack/spack/test/cmd/ci.py +++ b/lib/spack/spack/test/cmd/ci.py @@ -190,6 +190,12 @@ def test_ci_generate_with_env( tags: - donotcare image: donotcare + - match: + - arch=test-debian6-m1 + runner-attributes: + tags: + - donotcare + image: donotcare service-job-attributes: image: donotcare tags: [donotcare] @@ -270,10 +276,10 @@ def test_ci_generate_bootstrap_gcc( spack: definitions: - bootstrap: - - gcc@3.0 - - gcc@2.0 + - gcc@9.5 + - gcc@9.0 specs: - - dyninst%gcc@3.0 + - dyninst%gcc@9.5 mirrors: some-mirror: https://my.fake.mirror gitlab-ci: @@ -286,6 +292,11 @@ def test_ci_generate_bootstrap_gcc( runner-attributes: tags: - donotcare + - match: + - arch=test-debian6-aarch64 + runner-attributes: + tags: + - donotcare """ ) @@ -338,9 +349,9 @@ def test_ci_generate_bootstrap_artifacts_buildcache( spack: definitions: - bootstrap: - - gcc@3.0 + - gcc@9.5 specs: - - dyninst%gcc@3.0 + - dyninst%gcc@9.5 mirrors: some-mirror: https://my.fake.mirror gitlab-ci: @@ -353,6 +364,11 @@ def test_ci_generate_bootstrap_artifacts_buildcache( runner-attributes: tags: - donotcare + - match: + - arch=test-debian6-aarch64 + runner-attributes: + tags: + - donotcare enable-artifacts-buildcache: True """ ) @@ -1524,12 +1540,12 @@ def test_ci_generate_with_workarounds( """\ spack: specs: - - callpath%gcc@3.0 + - callpath%gcc@9.5 mirrors: some-mirror: https://my.fake.mirror gitlab-ci: mappings: - - match: ['%gcc@3.0'] + - match: ['%gcc@9.5'] runner-attributes: tags: - donotcare @@ -1639,28 +1655,28 @@ def test_ci_generate_bootstrap_prune_dag( mirror_url = "file://{0}".format(mirror_dir.strpath) # Install a compiler, because we want to put it in a buildcache - install_cmd("gcc@10.1.0%gcc@4.5.0") + install_cmd("gcc@12.2.0%gcc@10.2.1") # Put installed compiler in the buildcache - buildcache_cmd("create", "-u", "-a", "-f", "-d", mirror_dir.strpath, "gcc@10.1.0%gcc@4.5.0") + buildcache_cmd("create", "-u", "-a", "-f", "-d", mirror_dir.strpath, "gcc@12.2.0%gcc@10.2.1") # Now uninstall the compiler - uninstall_cmd("-y", "gcc@10.1.0%gcc@4.5.0") + uninstall_cmd("-y", "gcc@12.2.0%gcc@10.2.1") monkeypatch.setattr(spack.concretize.Concretizer, "check_for_compiler_existence", False) spack.config.set("config:install_missing_compilers", True) - assert CompilerSpec("gcc@10.1.0") not in compilers.all_compiler_specs() + assert CompilerSpec("gcc@12.2.0") not in compilers.all_compiler_specs() # Configure the mirror where we put that buildcache w/ the compiler mirror_cmd("add", "test-mirror", mirror_url) - install_cmd("--no-check-signature", "a%gcc@10.1.0") + install_cmd("--no-check-signature", "b%gcc@12.2.0") # Put spec built with installed compiler in the buildcache - buildcache_cmd("create", "-u", "-a", "-f", "-d", mirror_dir.strpath, "a%gcc@10.1.0") + buildcache_cmd("create", "-u", "-a", "-f", "-d", mirror_dir.strpath, "b%gcc@12.2.0") # Now uninstall the spec - uninstall_cmd("-y", "a%gcc@10.1.0") + uninstall_cmd("-y", "b%gcc@12.2.0") filename = str(tmpdir.join("spack.yaml")) with open(filename, "w") as f: @@ -1669,9 +1685,9 @@ def test_ci_generate_bootstrap_prune_dag( spack: definitions: - bootstrap: - - gcc@10.1.0%gcc@4.5.0 + - gcc@12.2.0%gcc@10.2.1 specs: - - a%gcc@10.1.0 + - b%gcc@12.2.0 mirrors: atestm: {0} gitlab-ci: @@ -1689,6 +1705,16 @@ def test_ci_generate_bootstrap_prune_dag( runner-attributes: tags: - meh + - match: + - arch=test-debian6-aarch64 + runner-attributes: + tags: + - donotcare + - match: + - arch=test-debian6-m1 + runner-attributes: + tags: + - meh """.format( mirror_url ) @@ -1746,10 +1772,6 @@ def fake_get_mirrors_for_spec(spec=None, mirrors_to_check=None, index_only=False "(specs) b": [ "(bootstrap) gcc", ], - "(specs) a": [ - "(bootstrap) gcc", - "(specs) b", - ], } _validate_needs_graph(new_yaml_contents, needs_graph, False) @@ -2152,7 +2174,10 @@ def test_ci_reproduce( ci_cmd("generate", "--output-file", pipeline_path, "--artifacts-root", artifacts_root) - job_name = ci.get_job_name("specs", False, job_spec, "test-debian6-core2", None) + target_name = spack.platforms.test.Test.default + job_name = ci.get_job_name( + "specs", False, job_spec, "test-debian6-%s" % target_name, None + ) repro_file = os.path.join(working_dir.strpath, "repro.json") repro_details = { diff --git a/lib/spack/spack/test/cmd/config.py b/lib/spack/spack/test/cmd/config.py index cdf9bc00a02..e5ad82cf435 100644 --- a/lib/spack/spack/test/cmd/config.py +++ b/lib/spack/spack/test/cmd/config.py @@ -634,13 +634,13 @@ def test_config_prefer_upstream( # Make sure only the non-default variants are set. assert packages["boost"] == { - "compiler": ["gcc@4.5.0"], + "compiler": ["gcc@10.2.1"], "variants": "+debug +graph", "version": ["1.63.0"], } - assert packages["dependency-install"] == {"compiler": ["gcc@4.5.0"], "version": ["2.0"]} + assert packages["dependency-install"] == {"compiler": ["gcc@10.2.1"], "version": ["2.0"]} # Ensure that neither variant gets listed for hdf5, since they conflict - assert packages["hdf5"] == {"compiler": ["gcc@4.5.0"], "version": ["2.3"]} + assert packages["hdf5"] == {"compiler": ["gcc@10.2.1"], "version": ["2.3"]} # Make sure a message about the conflicting hdf5's was given. assert "- hdf5" in output diff --git a/lib/spack/spack/test/cmd/find.py b/lib/spack/spack/test/cmd/find.py index b313a364463..be83541096b 100644 --- a/lib/spack/spack/test/cmd/find.py +++ b/lib/spack/spack/test/cmd/find.py @@ -322,7 +322,7 @@ def test_find_very_long(database, config): @pytest.mark.db def test_find_show_compiler(database, config): output = find("--no-groups", "--show-full-compiler", "mpileaks") - assert "mpileaks@2.3%gcc@4.5.0" in output + assert "mpileaks@2.3%gcc@10.2.1" in output @pytest.mark.db diff --git a/lib/spack/spack/test/cmd/install.py b/lib/spack/spack/test/cmd/install.py index 41de6565a1a..843e539eeab 100644 --- a/lib/spack/spack/test/cmd/install.py +++ b/lib/spack/spack/test/cmd/install.py @@ -935,7 +935,16 @@ def test_cdash_configure_warning(tmpdir, mock_fetch, install_mockery, capfd): with capfd.disabled(): with tmpdir.as_cwd(): # Test would fail if install raised an error. - install("--log-file=cdash_reports", "--log-format=cdash", "configure-warning") + + # Ensure that even on non-x86_64 architectures, there are no + # dependencies installed + spec = spack.spec.Spec("configure-warning").concretized() + spec.clear_dependencies() + specfile = "./spec.json" + with open(specfile, "w") as f: + f.write(spec.to_json()) + + install("--log-file=cdash_reports", "--log-format=cdash", specfile) # Verify Configure.xml exists with expected contents. report_dir = tmpdir.join("cdash_reports") assert report_dir in tmpdir.listdir() @@ -955,10 +964,10 @@ def test_compiler_bootstrap( ): monkeypatch.setattr(spack.concretize.Concretizer, "check_for_compiler_existence", False) spack.config.set("config:install_missing_compilers", True) - assert CompilerSpec("gcc@2.0") not in compilers.all_compiler_specs() + assert CompilerSpec("gcc@12.0") not in compilers.all_compiler_specs() # Test succeeds if it does not raise an error - install("a%gcc@2.0") + install("a%gcc@12.0") def test_compiler_bootstrap_from_binary_mirror( @@ -1013,11 +1022,11 @@ def test_compiler_bootstrap_already_installed( monkeypatch.setattr(spack.concretize.Concretizer, "check_for_compiler_existence", False) spack.config.set("config:install_missing_compilers", True) - assert CompilerSpec("gcc@2.0") not in compilers.all_compiler_specs() + assert CompilerSpec("gcc@12.0") not in compilers.all_compiler_specs() # Test succeeds if it does not raise an error - install("gcc@2.0") - install("a%gcc@2.0") + install("gcc@12.0") + install("a%gcc@12.0") def test_install_fails_no_args(tmpdir): diff --git a/lib/spack/spack/test/cmd/style.py b/lib/spack/spack/test/cmd/style.py index 179973af522..fd727d088e7 100644 --- a/lib/spack/spack/test/cmd/style.py +++ b/lib/spack/spack/test/cmd/style.py @@ -92,14 +92,14 @@ def test_changed_files_from_git_rev_base(tmpdir, capfd): git("checkout", "-b", "main") git("config", "user.name", "test user") git("config", "user.email", "test@user.com") - git("commit", "--allow-empty", "-m", "initial commit") + git("commit", "--no-gpg-sign", "--allow-empty", "-m", "initial commit") tmpdir.ensure("bin/spack") assert changed_files(base="HEAD") == ["bin/spack"] assert changed_files(base="main") == ["bin/spack"] git("add", "bin/spack") - git("commit", "-m", "v1") + git("commit", "--no-gpg-sign", "-m", "v1") assert changed_files(base="HEAD") == [] assert changed_files(base="HEAD~") == ["bin/spack"] @@ -113,7 +113,7 @@ def test_changed_no_base(tmpdir, capfd): git("config", "user.name", "test user") git("config", "user.email", "test@user.com") git("add", ".") - git("commit", "-m", "initial commit") + git("commit", "--no-gpg-sign", "-m", "initial commit") with pytest.raises(SystemExit): changed_files(base="foobar") @@ -198,7 +198,7 @@ def external_style_root(flake8_package_with_errors, tmpdir): git("config", "user.name", "test user") git("config", "user.email", "test@user.com") git("add", ".") - git("commit", "-m", "initial commit") + git("commit", "--no-gpg-sign", "-m", "initial commit") git("branch", "-m", "develop") git("checkout", "-b", "feature") @@ -210,7 +210,7 @@ def external_style_root(flake8_package_with_errors, tmpdir): # add the buggy file on the feature branch with tmpdir.as_cwd(): git("add", str(py_file)) - git("commit", "-m", "add new file") + git("commit", "--no-gpg-sign", "-m", "add new file") yield tmpdir, py_file diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py index 9f380975ede..bf0110f3e6e 100644 --- a/lib/spack/spack/test/concretize.py +++ b/lib/spack/spack/test/concretize.py @@ -313,8 +313,8 @@ def test_provides_handles_multiple_providers_of_same_version(self): def test_different_compilers_get_different_flags(self): client = Spec( - "cmake-client %gcc@4.7.2 platform=test os=fe target=fe" - + " ^cmake %clang@3.5 platform=test os=fe target=fe" + "cmake-client %gcc@11.1.0 platform=test os=fe target=fe" + + " ^cmake %clang@12.2.0 platform=test os=fe target=fe" ) client.concretize() cmake = client["cmake"] @@ -328,7 +328,7 @@ def test_architecture_inheritance(self): UnavailableCompilerVersionError if the architecture is concretized incorrectly. """ - spec = Spec("cmake-client %gcc@4.7.2 os=fe ^ cmake") + spec = Spec("cmake-client %gcc@11.1.0 os=fe ^ cmake") spec.concretize() assert spec["cmake"].architecture == spec.architecture @@ -452,7 +452,7 @@ def test_my_dep_depends_on_provider_of_my_virtual_dep(self): spec.normalize() spec.concretize() - @pytest.mark.parametrize("compiler_str", ["clang", "gcc", "gcc@4.5.0", "clang@:3.3.0"]) + @pytest.mark.parametrize("compiler_str", ["clang", "gcc", "gcc@10.2.1", "clang@:12.0.0"]) def test_compiler_inheritance(self, compiler_str): spec_str = "mpileaks %{0}".format(compiler_str) spec = Spec(spec_str).concretized() @@ -695,15 +695,15 @@ def test_adjusting_default_target_based_on_compiler( @pytest.mark.regression("8735,14730") def test_compiler_version_matches_any_entry_in_compilers_yaml(self): # Ensure that a concrete compiler with different compiler version - # doesn't match (here it's 4.5 vs. 4.5.0) + # doesn't match (here it's 10.2 vs. 10.2.1) with pytest.raises(spack.concretize.UnavailableCompilerVersionError): - s = Spec("mpileaks %gcc@4.5") + s = Spec("mpileaks %gcc@10.2") s.concretize() # An abstract compiler with a version list could resolve to 4.5.0 - s = Spec("mpileaks %gcc@4.5:") + s = Spec("mpileaks %gcc@10.2:") s.concretize() - assert str(s.compiler.version) == "4.5.0" + assert str(s.compiler.version) == "10.2.1" def test_concretize_anonymous(self): with pytest.raises(spack.error.SpackError): @@ -720,11 +720,11 @@ def test_concretize_anonymous_dep(self, spec_str): "spec_str,expected_str", [ # Unconstrained versions select default compiler (gcc@4.5.0) - ("bowtie@1.3.0", "%gcc@4.5.0"), + ("bowtie@1.4.0", "%gcc@10.2.1"), # Version with conflicts and no valid gcc select another compiler - ("bowtie@1.2.2", "%clang@3.3"), + ("bowtie@1.3.0", "%clang@12.0.0"), # If a higher gcc is available still prefer that - ("bowtie@1.2.2 os=redhat6", "%gcc@4.7.2"), + ("bowtie@1.2.2 os=redhat6", "%gcc@11.1.0"), ], ) def test_compiler_conflicts_in_package_py(self, spec_str, expected_str): @@ -1047,11 +1047,11 @@ def test_compiler_match_is_preferred_to_newer_version(self): # that doesn't allow newer versions with gcc@4.4.0. Check # that an old version of openblas is selected, rather than # a different compiler for just that node. - spec_str = "simple-inheritance+openblas %gcc@4.4.0 os=redhat6" + spec_str = "simple-inheritance+openblas %gcc@10.1.0 os=redhat6" s = Spec(spec_str).concretized() - assert "openblas@0.2.13" in s - assert s["openblas"].satisfies("%gcc@4.4.0") + assert "openblas@0.2.15" in s + assert s["openblas"].satisfies("%gcc@10.1.0") @pytest.mark.regression("19981") def test_target_ranges_in_conflicts(self): @@ -1080,8 +1080,8 @@ def test_custom_compiler_version(self): if spack.config.get("config:concretizer") == "original": pytest.xfail("Known failure of the original concretizer") - s = Spec("a %gcc@foo os=redhat6").concretized() - assert "%gcc@foo" in s + s = Spec("a %gcc@10foo os=redhat6").concretized() + assert "%gcc@10foo" in s def test_all_patches_applied(self): uuidpatch = ( @@ -1273,8 +1273,8 @@ def test_external_with_non_default_variant_as_dependency(self): ("mpileaks", "os=debian6"), # To trigger the bug in 22871 we need to have the same compiler # spec available on both operating systems - ("mpileaks%gcc@4.5.0 platform=test os=debian6", "os=debian6"), - ("mpileaks%gcc@4.5.0 platform=test os=redhat6", "os=redhat6"), + ("mpileaks%gcc@10.2.1 platform=test os=debian6", "os=debian6"), + ("mpileaks%gcc@10.2.1 platform=test os=redhat6", "os=redhat6"), ], ) def test_os_selection_when_multiple_choices_are_possible(self, spec_str, expected_os): @@ -1286,7 +1286,7 @@ def test_os_selection_when_multiple_choices_are_possible(self, spec_str, expecte @pytest.mark.regression("22718") @pytest.mark.parametrize( "spec_str,expected_compiler", - [("mpileaks", "%gcc@4.5.0"), ("mpileaks ^mpich%clang@3.3", "%clang@3.3")], + [("mpileaks", "%gcc@10.2.1"), ("mpileaks ^mpich%clang@12.0.0", "%clang@12.0.0")], ) def test_compiler_is_unique(self, spec_str, expected_compiler): s = Spec(spec_str).concretized() @@ -1462,10 +1462,12 @@ def test_target_granularity(self): # The test architecture uses core2 as the default target. Check that when # we configure Spack for "generic" granularity we concretize for x86_64 + default_target = spack.platforms.test.Test.default + generic_target = archspec.cpu.TARGETS[default_target].generic.name s = Spec("python") - assert s.concretized().satisfies("target=core2") + assert s.concretized().satisfies("target=%s" % default_target) with spack.config.override("concretizer:targets", {"granularity": "generic"}): - assert s.concretized().satisfies("target=x86_64") + assert s.concretized().satisfies("target=%s" % generic_target) def test_host_compatible_concretization(self): if spack.config.get("config:concretizer") == "original": @@ -1692,12 +1694,19 @@ def test_version_weight_and_provenance(self): # version_declared("b","0.9",1,"package_py"). # version_declared("b","1.0",2,"installed"). # version_declared("b","0.9",3,"installed"). - for criterion in [ - (1, None, "number of packages to build (vs. reuse)"), + # + # Depending on the target, it may also use gnuconfig + result_spec = result.specs[0] + num_specs = len(list(result_spec.traverse())) + + criteria = [ + (num_specs - 1, None, "number of packages to build (vs. reuse)"), (2, 0, "version badness"), - ]: + ] + + for criterion in criteria: assert criterion in result.criteria - assert result.specs[0].satisfies("^b@1.0") + assert result_spec.satisfies("^b@1.0") @pytest.mark.regression("31169") def test_not_reusing_incompatible_os_or_compiler(self): @@ -1717,8 +1726,8 @@ def test_not_reusing_incompatible_os_or_compiler(self): setup = spack.solver.asp.SpackSolverSetup() result, _, _ = solver.driver.solve(setup, [root_spec], reuse=reusable_specs) concrete_spec = result.specs[0] - assert concrete_spec.satisfies("%gcc@4.5.0") - assert concrete_spec.satisfies("os=debian6") + assert concrete_spec.satisfies("%{}".format(s.compiler)) + assert concrete_spec.satisfies("os={}".format(s.architecture.os)) def test_git_hash_assigned_version_is_preferred(self): hash = "a" * 40 diff --git a/lib/spack/spack/test/concretize_preferences.py b/lib/spack/spack/test/concretize_preferences.py index a6e568bd113..7bae90cb2cc 100644 --- a/lib/spack/spack/test/concretize_preferences.py +++ b/lib/spack/spack/test/concretize_preferences.py @@ -8,6 +8,8 @@ import pytest +import archspec + import spack.config import spack.package_prefs import spack.repo @@ -109,7 +111,9 @@ def test_preferred_compilers(self): pytest.skip("Fixing the parser broke this test for the original concretizer.") # Need to make sure the test uses an available compiler - compiler_list = spack.compilers.all_compiler_specs() + arch = spack.spec.ArchSpec(("test", "redhat6", archspec.cpu.host().name)) + + compiler_list = spack.compilers.compiler_specs_for_arch(arch) assert compiler_list # Try the first available compiler diff --git a/lib/spack/spack/test/conftest.py b/lib/spack/spack/test/conftest.py index 1f3c17916c5..2f04e1d4fd8 100644 --- a/lib/spack/spack/test/conftest.py +++ b/lib/spack/spack/test/conftest.py @@ -128,7 +128,14 @@ def mock_git_version_info(tmpdir, override_git_repos_cache_path): def commit(message): global commit_counter - git("commit", "--date", "2020-01-%02d 12:0:00 +0300" % commit_counter, "-am", message) + git( + "commit", + "--no-gpg-sign", + "--date", + "2020-01-%02d 12:0:00 +0300" % commit_counter, + "-am", + message, + ) commit_counter += 1 with working_dir(repo_path): diff --git a/lib/spack/spack/test/data/config/compilers.yaml b/lib/spack/spack/test/data/config/compilers.yaml index e0b0464976c..6f36c13b593 100644 --- a/lib/spack/spack/test/data/config/compilers.yaml +++ b/lib/spack/spack/test/data/config/compilers.yaml @@ -130,6 +130,7 @@ compilers: f77: /path/to/gfortran440 fc: /path/to/gfortran440 modules: 'None' + target: x86_64 - compiler: spec: clang@3.5 operating_system: redhat6 @@ -167,7 +168,7 @@ compilers: modules: 'None' target: x86_64 - compiler: - spec: gcc@foo + spec: gcc@10foo operating_system: redhat6 paths: cc: /path/to/gcc @@ -186,3 +187,167 @@ compilers: fc: /path/to/gfortran modules: 'None' target: x86_64 +- compiler: + spec: clang@12.0.0 + operating_system: {0.name}{0.version} + paths: + cc: /path/to/clang + cxx: /path/to/clang++ + f77: None + fc: None + modules: 'None' + target: aarch64 +- compiler: + spec: gcc@10.2.1 + operating_system: {0.name}{0.version} + paths: + cc: /path/to/gcc + cxx: /path/to/g++ + f77: None + fc: None + modules: 'None' + target: aarch64 +- compiler: + spec: clang@12.0.0 + operating_system: redhat6 + paths: + cc: /path/to/clang + cxx: /path/to/clang++ + f77: None + fc: None + modules: 'None' + target: aarch64 +- compiler: + spec: gcc@10.2.1 + operating_system: redhat6 + paths: + cc: /path/to/gcc + cxx: /path/to/g++ + f77: None + fc: None + modules: 'None' + target: aarch64 +- compiler: + spec: gcc@10.1.0 + operating_system: redhat6 + paths: + cc: /path/to/gcc + cxx: /path/to/g++ + f77: None + fc: None + modules: 'None' + target: aarch64 +- compiler: + spec: gcc@11.1.0 + operating_system: redhat6 + paths: + cc: /path/to/gcc + cxx: /path/to/g++ + f77: None + fc: None + flags: + cflags: -O0 -g + cxxflags: -O0 -g + fflags: -O0 -g + modules: 'None' + target: aarch64 +- compiler: + spec: clang@12.2.0 + operating_system: redhat6 + paths: + cc: /path/to/clang35 + cxx: /path/to/clang++35 + f77: None + fc: None + flags: + cflags: -O3 + cxxflags: -O3 + modules: 'None' + target: aarch64 +- compiler: + spec: gcc@10foo + operating_system: redhat6 + paths: + cc: /path/to/gcc + cxx: /path/to/g++ + f77: /path/to/gfortran + fc: /path/to/gfortran + modules: 'None' + target: aarch64 +- compiler: + spec: clang@12.0.0 + operating_system: {0.name}{0.version} + paths: + cc: /path/to/clang + cxx: /path/to/clang++ + f77: None + fc: None + modules: 'None' + target: x86_64 +- compiler: + spec: gcc@10.2.1 + operating_system: {0.name}{0.version} + paths: + cc: /path/to/gcc + cxx: /path/to/g++ + f77: None + fc: None + modules: 'None' + target: x86_64 +- compiler: + spec: clang@12.0.0 + operating_system: redhat6 + paths: + cc: /path/to/clang + cxx: /path/to/clang++ + f77: None + fc: None + modules: 'None' + target: x86_64 +- compiler: + spec: gcc@10.2.1 + operating_system: redhat6 + paths: + cc: /path/to/gcc + cxx: /path/to/g++ + f77: None + fc: None + modules: 'None' + target: x86_64 +- compiler: + spec: gcc@10.1.0 + operating_system: redhat6 + paths: + cc: /path/to/gcc + cxx: /path/to/g++ + f77: None + fc: None + modules: 'None' + target: x86_64 +- compiler: + spec: gcc@11.1.0 + operating_system: redhat6 + paths: + cc: /path/to/gcc + cxx: /path/to/g++ + f77: None + fc: None + flags: + cflags: -O0 -g + cxxflags: -O0 -g + fflags: -O0 -g + modules: 'None' + target: x86_64 +- compiler: + spec: clang@12.2.0 + operating_system: redhat6 + paths: + cc: /path/to/clang35 + cxx: /path/to/clang++35 + f77: None + fc: None + flags: + cflags: -O3 + cxxflags: -O3 + modules: 'None' + target: x86_64 diff --git a/lib/spack/spack/test/data/config/packages.yaml b/lib/spack/spack/test/data/config/packages.yaml index 7d5e06a74ce..c6ff731a7e5 100644 --- a/lib/spack/spack/test/data/config/packages.yaml +++ b/lib/spack/spack/test/data/config/packages.yaml @@ -7,18 +7,18 @@ packages: externaltool: buildable: False externals: - - spec: externaltool@1.0%gcc@4.5.0 + - spec: externaltool@1.0%gcc@10.2.1 prefix: /path/to/external_tool - - spec: externaltool@0.9%gcc@4.5.0 + - spec: externaltool@0.9%gcc@10.2.1 prefix: /usr - - spec: externaltool@0_8%gcc@4.5.0 + - spec: externaltool@0_8%gcc@10.2.1 prefix: /usr externalvirtual: buildable: False externals: - - spec: externalvirtual@2.0%clang@3.3 + - spec: externalvirtual@2.0%clang@12.0.0 prefix: /path/to/external_virtual_clang - - spec: externalvirtual@1.0%gcc@4.5.0 + - spec: externalvirtual@1.0%gcc@10.2.1 prefix: /path/to/external_virtual_gcc externalmodule: buildable: False @@ -49,4 +49,4 @@ packages: - spec: external-non-default-variant@3.8.7~foo~bar prefix: /usr version-test-dependency-preferred: - version: ['5.2.5'] \ No newline at end of file + version: ['5.2.5'] diff --git a/lib/spack/spack/test/installer.py b/lib/spack/spack/test/installer.py index 7f608d6c89f..363d92fe1f7 100644 --- a/lib/spack/spack/test/installer.py +++ b/lib/spack/spack/test/installer.py @@ -632,7 +632,10 @@ def test_check_deps_status_external(install_mockery, monkeypatch): # Mock the known dependent, b, as external so assumed to be installed monkeypatch.setattr(spack.spec.Spec, "external", True) installer._check_deps_status(request) - assert list(installer.installed)[0].startswith("b") + + # exotic architectures will add dependencies on gnuconfig, which we want to ignore + installed = [x for x in installer.installed if not x.startswith("gnuconfig")] + assert installed[0].startswith("b") def test_check_deps_status_upstream(install_mockery, monkeypatch): @@ -643,7 +646,10 @@ def test_check_deps_status_upstream(install_mockery, monkeypatch): # Mock the known dependent, b, as installed upstream monkeypatch.setattr(spack.spec.Spec, "installed_upstream", True) installer._check_deps_status(request) - assert list(installer.installed)[0].startswith("b") + + # exotic architectures will add dependencies on gnuconfig, which we want to ignore + installed = [x for x in installer.installed if not x.startswith("gnuconfig")] + assert installed[0].startswith("b") def test_add_bootstrap_compilers(install_mockery, monkeypatch): diff --git a/lib/spack/spack/test/modules/lmod.py b/lib/spack/spack/test/modules/lmod.py index 58c013ef864..d24ec8ca0d3 100644 --- a/lib/spack/spack/test/modules/lmod.py +++ b/lib/spack/spack/test/modules/lmod.py @@ -24,7 +24,7 @@ pytestmark = pytest.mark.skipif(sys.platform == "win32", reason="does not run on windows") -@pytest.fixture(params=["clang@3.3", "gcc@4.5.0"]) +@pytest.fixture(params=["clang@12.0.0", "gcc@10.2.1"]) def compiler(request): return request.param diff --git a/lib/spack/spack/test/sbang.py b/lib/spack/spack/test/sbang.py index ebc9a85347e..18a408a5491 100644 --- a/lib/spack/spack/test/sbang.py +++ b/lib/spack/spack/test/sbang.py @@ -7,6 +7,7 @@ Test that Spack's shebang filtering works correctly. """ import filecmp +import getpass import os import shutil import stat @@ -268,6 +269,10 @@ def test_shebang_handles_non_writable_files(script_dir, sbang_line): @pytest.fixture(scope="function") def configure_group_perms(): + # On systems with remote groups, the primary user group may be remote + # and grp does not act on remote groups. + # To ensure we find a group we can operate on, we get take the first group + # listed which has the current user as a member. conf = syaml.load_config( """\ all: @@ -276,7 +281,7 @@ def configure_group_perms(): write: group group: {0} """.format( - grp.getgrgid(os.getegid()).gr_name + [g.gr_name for g in grp.getgrall() if getpass.getuser() in g.gr_mem][0] ) ) spack.config.set("packages", conf, scope="user") diff --git a/lib/spack/spack/test/spec_semantics.py b/lib/spack/spack/test/spec_semantics.py index 7100cfdb5fb..711e9014163 100644 --- a/lib/spack/spack/test/spec_semantics.py +++ b/lib/spack/spack/test/spec_semantics.py @@ -841,7 +841,7 @@ def test_spec_flags_maintain_order(self): # Spack was assembling flags in a manner that could result in # different orderings for repeated concretizations of the same # spec and config - spec_str = "libelf %gcc@4.7.2 os=redhat6" + spec_str = "libelf %gcc@11.1.0 os=redhat6" for _ in range(25): s = Spec(spec_str).concretized() assert all( diff --git a/lib/spack/spack/test/spec_syntax.py b/lib/spack/spack/test/spec_syntax.py index d73e226d116..ab560bed084 100644 --- a/lib/spack/spack/test/spec_syntax.py +++ b/lib/spack/spack/test/spec_syntax.py @@ -277,13 +277,17 @@ def test_canonicalize(self): "x ^y@1,2:3,4%intel@1,2,3,4+a~b+c~d+e~f", "x ^y~f+e~d+c~b+a@4,2:3,1%intel@4,3,2,1" ) + default_target = spack.platforms.test.Test.default self.check_parse( - "x arch=test-redhat6-None" " ^y arch=test-None-core2" " ^z arch=linux-None-None", + "x arch=test-redhat6-None" + + (" ^y arch=test-None-%s" % default_target) + + " ^z arch=linux-None-None", "x os=fe " "^y target=be " "^z platform=linux", ) self.check_parse( - "x arch=test-debian6-core2" " ^y arch=test-debian6-core2", + ("x arch=test-debian6-%s" % default_target) + + (" ^y arch=test-debian6-%s" % default_target), "x os=default_os target=default_target" " ^y os=default_os target=default_target", ) diff --git a/lib/spack/spack/util/gpg.py b/lib/spack/spack/util/gpg.py index 3f0d74f4b71..ffee274c3fc 100644 --- a/lib/spack/spack/util/gpg.py +++ b/lib/spack/spack/util/gpg.py @@ -239,7 +239,7 @@ def trust(keyfile): keys = _get_unimported_public_keys(output) # Import them - GPG("--import", keyfile) + GPG("--batch", "--import", keyfile) # Set trust to ultimate key_to_fpr = dict(public_keys_to_fingerprint()) @@ -285,7 +285,7 @@ def sign(key, file, output, clearsign=False): signature, if False creates a detached signature """ signopt = "--clearsign" if clearsign else "--detach-sign" - GPG(signopt, "--armor", "--default-key", key, "--output", output, file) + GPG(signopt, "--armor", "--local-user", key, "--output", output, file) @_autoinit diff --git a/var/spack/repos/builtin.mock/packages/bowtie/package.py b/var/spack/repos/builtin.mock/packages/bowtie/package.py index 24d7312b749..9bef2111724 100644 --- a/var/spack/repos/builtin.mock/packages/bowtie/package.py +++ b/var/spack/repos/builtin.mock/packages/bowtie/package.py @@ -11,8 +11,10 @@ class Bowtie(Package): homepage = "http://www.example.org" url = "http://bowtie-1.2.2.tar.bz2" + version("1.4.0", "1c837ecd990bb022d07e7aab32b09847") version("1.3.0", "1c837ecd990bb022d07e7aab32b09847") version("1.2.2", "1c837ecd990bb022d07e7aab32b09847") version("1.2.0", "1c837ecd990bb022d07e7aab32b09847") conflicts("%gcc@:4.5.0", when="@1.2.2") + conflicts("%gcc@:10.2.1", when="@:1.3.0") diff --git a/var/spack/repos/builtin.mock/packages/impossible-concretization/package.py b/var/spack/repos/builtin.mock/packages/impossible-concretization/package.py index c0f2ce8641c..b47e97f3622 100644 --- a/var/spack/repos/builtin.mock/packages/impossible-concretization/package.py +++ b/var/spack/repos/builtin.mock/packages/impossible-concretization/package.py @@ -16,3 +16,4 @@ class ImpossibleConcretization(Package): version(1.0, "0123456789abcdef0123456789abcdef") conflicts("target=x86_64:") + conflicts("target=aarch64:") diff --git a/var/spack/repos/builtin.mock/packages/openblas/package.py b/var/spack/repos/builtin.mock/packages/openblas/package.py index 5b8637aca2c..1e948da8f29 100644 --- a/var/spack/repos/builtin.mock/packages/openblas/package.py +++ b/var/spack/repos/builtin.mock/packages/openblas/package.py @@ -12,6 +12,7 @@ class Openblas(Package): homepage = "http://www.openblas.net" url = "http://github.com/xianyi/OpenBLAS/archive/v0.2.15.tar.gz" + version("0.2.16", "b1190f3d3471685f17cfd1ec1d252ac9") version("0.2.15", "b1190f3d3471685f17cfd1ec1d252ac9") version("0.2.14", "b1190f3d3471685f17cfd1ec1d252ac9") version("0.2.13", "b1190f3d3471685f17cfd1ec1d252ac9") @@ -19,4 +20,7 @@ class Openblas(Package): # See #20019 for this conflict conflicts("%gcc@:4.4", when="@0.2.14:") + # To ensure test works with newer gcc versions + conflicts("%gcc@:10.1", when="@0.2.16:") + provides("blas") From 328addd43db12a3cfd3d3f3c2e63f2aee84d47c6 Mon Sep 17 00:00:00 2001 From: Vicente Bolea Date: Tue, 1 Nov 2022 18:49:57 -0400 Subject: [PATCH 301/442] ParaView: add v5.11.0-RC2 (#33486) Co-authored-by: eugeneswalker <38933153+eugeneswalker@users.noreply.github.com> --- var/spack/repos/builtin/packages/paraview/package.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/paraview/package.py b/var/spack/repos/builtin/packages/paraview/package.py index 8dd0049e055..3b2d98c13f0 100644 --- a/var/spack/repos/builtin/packages/paraview/package.py +++ b/var/spack/repos/builtin/packages/paraview/package.py @@ -28,7 +28,7 @@ class Paraview(CMakePackage, CudaPackage): version("master", branch="master", submodules=True) version( - "5.11.0-RC1", sha256="892c4617b3f23f6e5c9a08ecc9b3e9f16b9e2f54c044155c3c252f00b0fbafd9" + "5.11.0-RC2", sha256="b5748b1ef4b8855467c3db75ffb8739096075596229e7ba16b284946964904b9" ) version( "5.10.1", From 353e31e72a8fb56ec864897004eff72aecaf2417 Mon Sep 17 00:00:00 2001 From: eugeneswalker <38933153+eugeneswalker@users.noreply.github.com> Date: Tue, 1 Nov 2022 16:53:53 -0700 Subject: [PATCH 302/442] rempi %oneapi: -Wno-error=implicit-function-declaration (#33654) --- var/spack/repos/builtin/packages/rempi/package.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/var/spack/repos/builtin/packages/rempi/package.py b/var/spack/repos/builtin/packages/rempi/package.py index 46adf68c277..fbcb1369ea4 100644 --- a/var/spack/repos/builtin/packages/rempi/package.py +++ b/var/spack/repos/builtin/packages/rempi/package.py @@ -23,6 +23,13 @@ class Rempi(AutotoolsPackage): depends_on("libtool", type="build") depends_on("libpciaccess", type="link") + def flag_handler(self, name, flags): + iflags = [] + if name == "cflags": + if self.spec.satisfies("%oneapi@2022.2.0:"): + iflags.append("-Wno-error=implicit-function-declaration") + return (iflags, None, None) + def setup_build_environment(self, env): if self.spec.satisfies("%cce"): env.set("MPICC", "mpicc") From 4bad9f9b1380e33499b6f8e06531898d8b7d679f Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Wed, 2 Nov 2022 07:04:47 +0100 Subject: [PATCH 303/442] Consolidate DAG traversal in traverse.py, support DFS/BFS (#33406) This PR introduces breadth-first traversal, and moves depth-first traversal logic out of Spec's member functions, into `traverse.py`. It introduces a high-level API with three main methods: ```python spack.traverse.traverse_edges(specs, kwargs...) spack.traverse.traverse_nodes(specs, kwags...) spack.traverse.traverse_tree(specs, kwargs...) ``` with the usual `root`, `order`, `cover`, `direction`, `deptype`, `depth`, `key`, `visited` kwargs for the first two. What's new is that `order="breadth"` is added for breadth-first traversal. The lower level API is not exported, but is certainly useful for advanced use cases. The lower level API includes visitor classes for direction reversal and edge pruning, which can be used to create more advanced traversal methods, especially useful when the `deptype` is not constant but depends on the node or depth. --- There's a couple nice use-cases for breadth-first traversal: - Sometimes roots have to be handled differently (e.g. follow build edges of roots but not of deps). BFS ensures that root nodes are always discovered at depth 0, instead of at any depth > 1 as a dep of another root. - When printing a tree, it would be nice to reduce indent levels so it fits in the terminal, and ensure that e.g. `zlib` is not printed at indent level 10 as a dependency of a build dep of a build dep -- rather if it's a direct dep of my package, I wanna see it at depth 1. This basically requires one breadth-first traversal to construct a tree, which can then be printed with depth-first traversal. - In environments in general, it's sometimes inconvenient to have a double loop: first over the roots then over each root's deps, and maintain your own `visited` set outside. With BFS, you can simply init the queue with the environment root specs and it Just Works. [Example here](https://github.com/spack/spack/blob/3ec73046995d9504d6e135f564f1370cfe31ba34/lib/spack/spack/environment/environment.py#L1815-L1816) --- lib/spack/spack/cmd/env.py | 86 ++-- lib/spack/spack/cmd/spec.py | 3 +- lib/spack/spack/spec.py | 154 +------ lib/spack/spack/test/traverse.py | 211 +++++++++ lib/spack/spack/traverse.py | 417 ++++++++++++++++++ .../builtin.mock/packages/chain-a/package.py | 34 ++ .../builtin.mock/packages/chain-b/package.py | 32 ++ .../builtin.mock/packages/chain-c/package.py | 32 ++ .../builtin.mock/packages/chain-d/package.py | 31 ++ 9 files changed, 798 insertions(+), 202 deletions(-) create mode 100644 lib/spack/spack/test/traverse.py create mode 100644 lib/spack/spack/traverse.py create mode 100644 var/spack/repos/builtin.mock/packages/chain-a/package.py create mode 100644 var/spack/repos/builtin.mock/packages/chain-b/package.py create mode 100644 var/spack/repos/builtin.mock/packages/chain-c/package.py create mode 100644 var/spack/repos/builtin.mock/packages/chain-d/package.py diff --git a/lib/spack/spack/cmd/env.py b/lib/spack/spack/cmd/env.py index 02d279b0546..558b6bead4e 100644 --- a/lib/spack/spack/cmd/env.py +++ b/lib/spack/spack/cmd/env.py @@ -28,6 +28,7 @@ import spack.environment.shell import spack.schema.env import spack.tengine +import spack.traverse as traverse import spack.util.string as string from spack.util.environment import EnvironmentModifications @@ -634,36 +635,6 @@ def env_depfile_setup_parser(subparser): ) -class SpecNode(object): - def __init__(self, spec, depth): - self.spec = spec - self.depth = depth - - def key(self): - return self.spec.dag_hash() - - -class UniqueNodesQueue(object): - def __init__(self, init=[]): - self.seen = set() - self.queue = [] - for item in init: - self.push(item) - - def push(self, item): - key = item.key() - if key in self.seen: - return - self.queue.append(item) - self.seen.add(key) - - def empty(self): - return len(self.queue) == 0 - - def pop(self): - return self.queue.pop() - - def _deptypes(use_buildcache): """What edges should we follow for a given node? If it's a cache-only node, then we can drop build type deps.""" @@ -692,29 +663,27 @@ def __init__(self, target, pkg_buildcache, deps_buildcache): def neighbors(self, node): """Produce a list of spec to follow from node""" deptypes = self.deptypes_root if node.depth == 0 else self.deptypes_deps - return node.spec.dependencies(deptype=deptypes) + return traverse.sort_edges(node.edge.spec.edges_to_dependencies(deptype=deptypes)) - def visit(self, node): - dag_hash = node.spec.dag_hash() - spec_str = node.spec.format("{name}{@version}{%compiler}{variants}{arch=architecture}") - buildcache = self.pkg_buildcache if node.depth == 0 else self.deps_buildcache - if buildcache == "only": - build_cache_flag = "--use-buildcache=only" - elif buildcache == "never": - build_cache_flag = "--use-buildcache=never" - else: - build_cache_flag = "" - prereqs = " ".join([self.target(dep.dag_hash()) for dep in self.neighbors(node)]) - self.adjacency_list.append((dag_hash, spec_str, build_cache_flag, prereqs)) + def build_cache_flag(self, depth): + setting = self.pkg_buildcache if depth == 0 else self.deps_buildcache + if setting == "only": + return "--use-buildcache=only" + elif setting == "never": + return "--use-buildcache=never" + return "" + def accept(self, node): + dag_hash = node.edge.spec.dag_hash() + spec_str = node.edge.spec.format( + "{name}{@version}{%compiler}{variants}{arch=architecture}" + ) + buildcache_flag = self.build_cache_flag(node.depth) + prereqs = " ".join([self.target(dep.spec.dag_hash()) for dep in self.neighbors(node)]) + self.adjacency_list.append((dag_hash, spec_str, buildcache_flag, prereqs)) -def traverse_breadth_first(visitor, specs=[]): - queue = UniqueNodesQueue([SpecNode(s, 0) for s in specs]) - while not queue.empty(): - node = queue.pop() - visitor.visit(node) - for child in visitor.neighbors(node): - queue.push(SpecNode(child, node.depth + 1)) + # We already accepted this + return True def env_depfile(args): @@ -751,17 +720,22 @@ def get_install_deps_target(name): else: roots = [s for _, s in env.concretized_specs()] - # Shallow means we will drop non-direct build deps from the DAG + # We produce a sub-DAG from the DAG induced by roots, where we drop build + # edges for those specs that are installed through a binary cache. pkg_buildcache, dep_buildcache = args.use_buildcache - visitor = MakeTargetVisitor(get_install_target, pkg_buildcache, dep_buildcache) - traverse_breadth_first(visitor, roots) + make_targets = MakeTargetVisitor(get_install_target, pkg_buildcache, dep_buildcache) + traverse.traverse_breadth_first_with_visitor( + roots, traverse.CoverNodesVisitor(make_targets, key=lambda s: s.dag_hash()) + ) # Root specs without deps are the prereqs for the environment target root_install_targets = [get_install_target(h.dag_hash()) for h in roots] # Cleanable targets... - cleanable_targets = [get_install_target(h) for h, _, _, _ in visitor.adjacency_list] - cleanable_targets.extend([get_install_deps_target(h) for h, _, _, _ in visitor.adjacency_list]) + cleanable_targets = [get_install_target(h) for h, _, _, _ in make_targets.adjacency_list] + cleanable_targets.extend( + [get_install_deps_target(h) for h, _, _, _ in make_targets.adjacency_list] + ) buf = six.StringIO() @@ -780,7 +754,7 @@ def get_install_deps_target(name): "install_deps_target": get_target(".install-deps"), "any_hash_target": get_target("%"), "jobserver_support": "+" if args.jobserver else "", - "adjacency_list": visitor.adjacency_list, + "adjacency_list": make_targets.adjacency_list, } ) diff --git a/lib/spack/spack/cmd/spec.py b/lib/spack/spack/cmd/spec.py index b701fbc83c0..9ed5f27cab9 100644 --- a/lib/spack/spack/cmd/spec.py +++ b/lib/spack/spack/cmd/spec.py @@ -76,8 +76,7 @@ def setup_parser(subparser): "-t", "--types", action="store_true", default=False, help="show dependency types" ) arguments.add_common_arguments(subparser, ["specs"]) - - spack.cmd.common.arguments.add_concretizer_args(subparser) + arguments.add_concretizer_args(subparser) def spec(parser, args): diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py index 10f6dfb8e9f..bf0acf58d84 100644 --- a/lib/spack/spack/spec.py +++ b/lib/spack/spack/spec.py @@ -77,7 +77,6 @@ """ import collections import itertools -import operator import os import re import sys @@ -106,6 +105,7 @@ import spack.solver import spack.store import spack.target +import spack.traverse as traverse import spack.util.crypto import spack.util.executable import spack.util.hash @@ -814,10 +814,6 @@ def _sort_by_dep_types(dspec): return tuple(t not in dspec.deptypes for t in ("link", "run", "build", "test")) -def _sort_edges_by_pkg_name(edges): - edges.sort(key=lambda edge: edge.spec.name) - - #: Enum for edge directions EdgeDirection = lang.enum(parent=0, child=1) @@ -1601,144 +1597,12 @@ def installed_upstream(self): return upstream def traverse(self, **kwargs): - depth = kwargs.get("depth", False) + """Shorthand for :meth:`~spack.traverse.traverse_nodes`""" + return traverse.traverse_nodes([self], **kwargs) - if depth: - for d, edge in self.traverse_edges(**kwargs): - yield d, edge.spec - else: - for edge in self.traverse_edges(**kwargs): - yield edge.spec - - def traverse_edges(self, visited=None, d=0, deptype="all", dep_spec=None, **kwargs): - """Generic traversal of the DAG represented by this spec. - - This yields ``DependencySpec`` objects as they are traversed. - - An imaginary incoming edge to the root is yielded first as - ``DependencySpec(None, root, ())``. - - Note: the edges are traversed from ``edge.parent`` to ``edge.spec``, - even if the direction is reversed. When ``direction="children"`` the - parent points to the dependent, and spec to the dependency. Conversely - when ``direction="parents"`` parent points to the dependency, and spec - to the dependent. - - Options: - - order [=pre|post] - Order to traverse spec nodes. Defaults to preorder traversal. - Options are: - - 'pre': Pre-order traversal; each node is yielded before its - children in the dependency DAG. - 'post': Post-order traversal; each node is yielded after its - children in the dependency DAG. - - cover [=nodes|edges|paths] - Determines how extensively to cover the dag. Possible values: - - 'nodes': Visit each node in the dag only once. Every node - yielded by this function will be unique. - 'edges': If a node has been visited once but is reached along a - new path from the root, yield it but do not descend - into it. This traverses each 'edge' in the DAG once. - 'paths': Explore every unique path reachable from the root. - This descends into visited subtrees and will yield - nodes twice if they're reachable by multiple paths. - - depth [=False] - Defaults to False. When True, yields not just nodes in the - spec, but also their depth from the root in a (depth, node) - tuple. - - key [=id] - Allow a custom key function to track the identity of nodes - in the traversal. - - root [=True] - If False, this won't yield the root node, just its descendents. - - direction [=children|parents] - If 'children', does a traversal of this spec's children. If - 'parents', traverses upwards in the DAG towards the root. - - """ - # get initial values for kwargs - depth = kwargs.get("depth", False) - key_fun = kwargs.get("key", id) - if isinstance(key_fun, six.string_types): - key_fun = operator.attrgetter(key_fun) - yield_root = kwargs.get("root", True) - cover = kwargs.get("cover", "nodes") - direction = kwargs.get("direction", "children") - order = kwargs.get("order", "pre") - - # we don't want to run canonical_deptype every time through - # traverse, because it is somewhat expensive. This ensures we - # canonicalize only once. - canonical_deptype = kwargs.get("canonical_deptype", None) - if canonical_deptype is None: - deptype = dp.canonical_deptype(deptype) - kwargs["canonical_deptype"] = deptype - else: - deptype = canonical_deptype - - # Make sure kwargs have legal values; raise ValueError if not. - def validate(name, val, allowed_values): - if val not in allowed_values: - raise ValueError( - "Invalid value for %s: %s. Choices are %s" - % (name, val, ",".join(allowed_values)) - ) - - validate("cover", cover, ("nodes", "edges", "paths")) - validate("direction", direction, ("children", "parents")) - validate("order", order, ("pre", "post")) - - if visited is None: - visited = set() - key = key_fun(self) - - # Node traversal does not yield visited nodes. - if key in visited and cover == "nodes": - return - - def return_val(dspec): - if not dspec: - # make a fake dspec for the root. - dspec = DependencySpec(None, self, ()) - return (d, dspec) if depth else dspec - - yield_me = yield_root or d > 0 - - # Preorder traversal yields before successors - if yield_me and order == "pre": - yield return_val(dep_spec) - - # Edge traversal yields but skips children of visited nodes - if not (key in visited and cover == "edges"): - visited.add(key) - - # This code determines direction and yields the children/parents - if direction == "children": - edges = self.edges_to_dependencies() - else: - edges = [edge.flip() for edge in self.edges_from_dependents()] - - _sort_edges_by_pkg_name(edges) - - for dspec in edges: - dt = dspec.deptypes - if dt and not any(d in deptype for d in dt): - continue - - for child in dspec.spec.traverse_edges(visited, d + 1, deptype, dspec, **kwargs): - yield child - - # Postorder traversal yields after successors - if yield_me and order == "post": - yield return_val(dep_spec) + def traverse_edges(self, **kwargs): + """Shorthand for :meth:`~spack.traverse.traverse_edges`""" + return traverse.traverse_edges([self], **kwargs) @property def short_spec(self): @@ -4604,11 +4468,13 @@ def tree(self, **kwargs): show_types = kwargs.pop("show_types", False) deptypes = kwargs.pop("deptypes", "all") recurse_dependencies = kwargs.pop("recurse_dependencies", True) + depth_first = kwargs.pop("depth_first", False) lang.check_kwargs(kwargs, self.tree) out = "" - for d, dep_spec in self.traverse_edges( - order="pre", cover=cover, depth=True, deptype=deptypes + + for d, dep_spec in traverse.traverse_tree( + [self], cover=cover, deptype=deptypes, depth_first=depth_first ): node = dep_spec.spec diff --git a/lib/spack/spack/test/traverse.py b/lib/spack/spack/test/traverse.py new file mode 100644 index 00000000000..663f323e675 --- /dev/null +++ b/lib/spack/spack/test/traverse.py @@ -0,0 +1,211 @@ +# 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) + +import spack.traverse as traverse +from spack.spec import Spec + + +def key_by_hash(spec): + return spec.dag_hash() + + +def test_breadth_first_traversal(config, mock_packages): + # That that depth of discovery is non-decreasing + s = Spec("dttop").concretized() + depths = [ + depth + for (depth, _) in traverse.traverse_nodes( + [s], order="breadth", key=key_by_hash, depth=True + ) + ] + assert depths == sorted(depths) + + +def test_breadth_first_deptype_traversal(config, mock_packages): + s = Spec("dtuse").concretized() + + names = [ + "dtuse", + "dttop", + "dtbuild1", + "dtlink1", + "dtbuild2", + "dtlink2", + "dtlink3", + "dtlink4", + ] + + traversal = traverse.traverse_nodes( + [s], order="breadth", key=key_by_hash, deptype=("build", "link") + ) + assert [x.name for x in traversal] == names + + +def test_breadth_firsrt_traversal_deptype_with_builddeps(config, mock_packages): + s = Spec("dttop").concretized() + + names = ["dttop", "dtbuild1", "dtlink1", "dtbuild2", "dtlink2", "dtlink3", "dtlink4"] + + traversal = traverse.traverse_nodes( + [s], order="breadth", key=key_by_hash, deptype=("build", "link") + ) + assert [x.name for x in traversal] == names + + +def test_breadth_first_traversal_deptype_full(config, mock_packages): + s = Spec("dttop").concretized() + + names = [ + "dttop", + "dtbuild1", + "dtlink1", + "dtrun1", + "dtbuild2", + "dtlink2", + "dtrun2", + "dtlink3", + "dtlink5", + "dtrun3", + "dtlink4", + "dtbuild3", + ] + + traversal = traverse.traverse_nodes([s], order="breadth", key=key_by_hash, deptype="all") + assert [x.name for x in traversal] == names + + +def test_breadth_first_traversal_deptype_run(config, mock_packages): + s = Spec("dttop").concretized() + names = ["dttop", "dtrun1", "dtrun3"] + traversal = traverse.traverse_nodes([s], order="breadth", key=key_by_hash, deptype="run") + assert [x.name for x in traversal] == names + + +def test_breadth_first_traversal_reverse(config, mock_packages): + s = Spec("dt-diamond").concretized() + gen = traverse.traverse_nodes( + [s["dt-diamond-bottom"]], order="breadth", key=key_by_hash, direction="parents", depth=True + ) + assert [(depth, spec.name) for (depth, spec) in gen] == [ + (0, "dt-diamond-bottom"), + (1, "dt-diamond-left"), + (1, "dt-diamond-right"), + (2, "dt-diamond"), + ] + + +def test_breadth_first_traversal_multiple_roots(config, mock_packages): + # With DFS, the branch dt-diamond -> dt-diamond-left -> dt-diamond-bottom + # is followed, with BFS, dt-diamond-bottom should be traced through the second + # root dt-diamond-right at depth 1 instead. + s = Spec("dt-diamond").concretized() + roots = [s["dt-diamond"], s["dt-diamond-right"]] + gen = traverse.traverse_edges(roots, order="breadth", key=key_by_hash, depth=True, root=False) + assert [(depth, edge.parent.name, edge.spec.name) for (depth, edge) in gen] == [ + (1, "dt-diamond", "dt-diamond-left"), # edge from first root "to" depth 1 + (1, "dt-diamond-right", "dt-diamond-bottom"), # edge from second root "to" depth 1 + ] + + +def test_breadth_first_versus_depth_first_tree(config, mock_packages): + """ + The packages chain-a, chain-b, chain-c, chain-d have the following DAG: + a --> b --> c --> d # a chain + a --> c # and "skip" connections + a --> d + Here we test at what depth the nodes are discovered when using BFS vs DFS. + """ + s = Spec("chain-a").concretized() + + # BFS should find all nodes as direct deps + assert [ + (depth, edge.spec.name) + for (depth, edge) in traverse.traverse_tree([s], cover="nodes", depth_first=False) + ] == [ + (0, "chain-a"), + (1, "chain-b"), + (1, "chain-c"), + (1, "chain-d"), + ] + + # DFS will disover all nodes along the chain a -> b -> c -> d. + assert [ + (depth, edge.spec.name) + for (depth, edge) in traverse.traverse_tree([s], cover="nodes", depth_first=True) + ] == [ + (0, "chain-a"), + (1, "chain-b"), + (2, "chain-c"), + (3, "chain-d"), + ] + + # When covering all edges, we should never exceed depth 2 in BFS. + assert [ + (depth, edge.spec.name) + for (depth, edge) in traverse.traverse_tree([s], cover="edges", depth_first=False) + ] == [ + (0, "chain-a"), + (1, "chain-b"), + (2, "chain-c"), + (1, "chain-c"), + (2, "chain-d"), + (1, "chain-d"), + ] + + # In DFS we see the chain again. + assert [ + (depth, edge.spec.name) + for (depth, edge) in traverse.traverse_tree([s], cover="edges", depth_first=True) + ] == [ + (0, "chain-a"), + (1, "chain-b"), + (2, "chain-c"), + (3, "chain-d"), + (1, "chain-c"), + (1, "chain-d"), + ] + + +def test_breadth_first_versus_depth_first_printing(config, mock_packages): + """Test breadth-first versus depth-first tree printing.""" + s = Spec("chain-a").concretized() + + args = {"format": "{name}", "color": False} + + dfs_tree_nodes = """\ +chain-a + ^chain-b + ^chain-c + ^chain-d +""" + assert s.tree(depth_first=True, **args) == dfs_tree_nodes + + bfs_tree_nodes = """\ +chain-a + ^chain-b + ^chain-c + ^chain-d +""" + assert s.tree(depth_first=False, **args) == bfs_tree_nodes + + dfs_tree_edges = """\ +chain-a + ^chain-b + ^chain-c + ^chain-d + ^chain-c + ^chain-d +""" + assert s.tree(depth_first=True, cover="edges", **args) == dfs_tree_edges + + bfs_tree_edges = """\ +chain-a + ^chain-b + ^chain-c + ^chain-c + ^chain-d + ^chain-d +""" + assert s.tree(depth_first=False, cover="edges", **args) == bfs_tree_edges diff --git a/lib/spack/spack/traverse.py b/lib/spack/spack/traverse.py new file mode 100644 index 00000000000..6263f83896a --- /dev/null +++ b/lib/spack/spack/traverse.py @@ -0,0 +1,417 @@ +# 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 collections import defaultdict, namedtuple + +import spack.spec + +# Export only the high-level API. +__all__ = ["traverse_edges", "traverse_nodes", "traverse_tree"] + +#: Data class that stores a directed edge together with depth at +#: which the target vertex was found. It is passed to ``accept`` +#: and ``neighbors`` of visitors, so they can decide whether to +#: follow the edge or not. +EdgeAndDepth = namedtuple("EdgeAndDepth", ["edge", "depth"]) + + +def sort_edges(edges): + edges.sort(key=lambda edge: edge.spec.name) + return edges + + +class BaseVisitor(object): + """A simple visitor that accepts all edges unconditionally and follows all + edges to dependencies of a given ``deptype``.""" + + def __init__(self, deptype="all"): + self.deptype = deptype + + def accept(self, node): + """ + Arguments: + node (EdgeAndDepth): Provides the depth and the edge through which the + node was discovered + + Returns: + bool: Returns ``True`` if the node is accepted. When ``False``, this + indicates that the node won't be yielded by iterators and dependencies + are not followed. + """ + return True + + def neighbors(self, node): + return sort_edges(node.edge.spec.edges_to_dependencies(deptype=self.deptype)) + + +class ReverseVisitor(object): + """A visitor that reverses the arrows in the DAG, following dependents.""" + + def __init__(self, visitor, deptype="all"): + self.visitor = visitor + self.deptype = deptype + + def accept(self, node): + return self.visitor.accept(node) + + def neighbors(self, node): + """Return dependents, note that we actually flip the edge direction to allow + generic programming""" + spec = node.edge.spec + return sort_edges( + [edge.flip() for edge in spec.edges_from_dependents(deptype=self.deptype)] + ) + + +class CoverNodesVisitor(object): + """A visitor that traverses each node once.""" + + def __init__(self, visitor, key=id, visited=None): + self.visitor = visitor + self.key = key + self.visited = set() if visited is None else visited + + def accept(self, node): + # Covering nodes means: visit nodes once and only once. + key = self.key(node.edge.spec) + + if key in self.visited: + return False + + accept = self.visitor.accept(node) + self.visited.add(key) + return accept + + def neighbors(self, node): + return self.visitor.neighbors(node) + + +class CoverEdgesVisitor(object): + """A visitor that traverses all edges once.""" + + def __init__(self, visitor, key=id, visited=None): + self.visitor = visitor + self.visited = set() if visited is None else visited + self.key = key + + def accept(self, node): + return self.visitor.accept(node) + + def neighbors(self, node): + # Covering edges means: drop dependencies of visited nodes. + key = self.key(node.edge.spec) + + if key in self.visited: + return [] + + self.visited.add(key) + return self.visitor.neighbors(node) + + +def get_visitor_from_args(cover, direction, deptype, key=id, visited=None, visitor=None): + """ + Create a visitor object from common keyword arguments. + + Arguments: + cover (str): Determines how extensively to cover the dag. Possible values: + ``nodes`` -- Visit each unique node in the dag only once. + ``edges`` -- If a node has been visited once but is reached along a + new path, it's accepted, but not recurisvely followed. This traverses + each 'edge' in the DAG once. + ``paths`` -- Explore every unique path reachable from the root. + This descends into visited subtrees and will accept nodes multiple + times if they're reachable by multiple paths. + direction (str): ``children`` or ``parents``. If ``children``, does a traversal + of this spec's children. If ``parents``, traverses upwards in the DAG + towards the root. + deptype (str or tuple): allowed dependency types + key: function that takes a spec and outputs a key for uniqueness test. + visited (set or None): a set of nodes not to follow (when using cover=nodes/edges) + visitor: An initial visitor that is used for composition. + + Returns: + A visitor + """ + visitor = visitor or BaseVisitor(deptype) + if cover == "nodes": + visitor = CoverNodesVisitor(visitor, key, visited) + elif cover == "edges": + visitor = CoverEdgesVisitor(visitor, key, visited) + if direction == "parents": + visitor = ReverseVisitor(visitor, deptype) + return visitor + + +def root_specs(specs): + """Initialize a list of edges from an imaginary root node to the root specs.""" + return [ + EdgeAndDepth(edge=spack.spec.DependencySpec(parent=None, spec=s, deptypes=()), depth=0) + for s in specs + ] + + +def traverse_depth_first_edges_generator(nodes, visitor, post_order=False, root=True, depth=False): + # This is a somewhat non-standard implementation, but the reason to start with + # edges is that we don't have to deal with an artificial root node when doing DFS + # on multiple (root) specs. + for node in nodes: + if not visitor.accept(node): + continue + + yield_me = root or node.depth > 0 + + # Pre + if yield_me and not post_order: + yield (node.depth, node.edge) if depth else node.edge + + neighbors = [ + EdgeAndDepth(edge=edge, depth=node.depth + 1) for edge in visitor.neighbors(node) + ] + + # This extra branch is just for efficiency. + if len(neighbors) >= 0: + for item in traverse_depth_first_edges_generator( + neighbors, visitor, post_order, root, depth + ): + yield item + + # Post + if yield_me and post_order: + yield (node.depth, node.edge) if depth else node.edge + + +def traverse_breadth_first_edges_generator(queue, visitor, root=True, depth=False): + while len(queue) > 0: + node = queue.pop(0) + + # If the visitor doesn't accept the node, we don't yield it nor follow its edges. + if not visitor.accept(node): + continue + + if root or node.depth > 0: + yield (node.depth, node.edge) if depth else node.edge + + for edge in visitor.neighbors(node): + queue.append(EdgeAndDepth(edge, node.depth + 1)) + + +def traverse_breadth_first_with_visitor(specs, visitor): + """Performs breadth first traversal for a list of specs (not a generator). + + Arguments: + specs (list): List of Spec instances. + visitor: object that implements accept and neighbors interface, see + for example BaseVisitor. + """ + queue = root_specs(specs) + while len(queue) > 0: + node = queue.pop(0) + + # If the visitor doesn't accept the node, we don't traverse it further. + if not visitor.accept(node): + continue + + for edge in visitor.neighbors(node): + queue.append(EdgeAndDepth(edge, node.depth + 1)) + + +# Helper functions for generating a tree using breadth-first traversal + + +def breadth_first_to_tree_edges(roots, deptype="all", key=id): + """This produces an adjacency list (with edges) and a map of parents. + There may be nodes that are reached through multiple edges. To print as + a tree, one should use the parents dict to verify if the path leading to + the node is through the correct parent. If not, the branch should be + truncated.""" + edges = defaultdict(list) + parents = dict() + + for edge in traverse_edges(roots, order="breadth", cover="edges", deptype=deptype, key=key): + parent_id = None if edge.parent is None else key(edge.parent) + child_id = key(edge.spec) + edges[parent_id].append(edge) + if child_id not in parents: + parents[child_id] = parent_id + + return edges, parents + + +def breadth_first_to_tree_nodes(roots, deptype="all", key=id): + """This produces a list of edges that forms a tree; every node has no more + that one incoming edge.""" + edges = defaultdict(list) + + for edge in traverse_edges(roots, order="breadth", cover="nodes", deptype=deptype, key=key): + parent_id = None if edge.parent is None else key(edge.parent) + edges[parent_id].append(edge) + + return edges + + +def traverse_breadth_first_tree_edges(parent_id, edges, parents, key=id, depth=0): + """Do a depth-first search on edges generated by bread-first traversal, + which can be used to produce a tree.""" + for edge in edges[parent_id]: + yield (depth, edge) + + child_id = key(edge.spec) + + # Don't follow further if we're not the parent + if parents[child_id] != parent_id: + continue + + # yield from ... in Python 3. + for item in traverse_breadth_first_tree_edges(child_id, edges, parents, key, depth + 1): + yield item + + +def traverse_breadth_first_tree_nodes(parent_id, edges, key=id, depth=0): + for edge in edges[parent_id]: + yield (depth, edge) + for item in traverse_breadth_first_tree_nodes(key(edge.spec), edges, key, depth + 1): + yield item + + +# High-level API: traverse_edges, traverse_nodes, traverse_tree. + + +def traverse_edges( + specs, + root=True, + order="pre", + cover="nodes", + direction="children", + deptype="all", + depth=False, + key=id, + visited=None, +): + """ + Generator that yields edges from the DAG, starting from a list of root specs. + + Arguments: + + specs (list): List of root specs (considered to be depth 0) + root (bool): Yield the root nodes themselves + order (str): What order of traversal to use in the DAG. For depth-first + search this can be ``pre`` or ``post``. For BFS this should be ``breadth``. + cover (str): Determines how extensively to cover the dag. Possible values: + ``nodes`` -- Visit each unique node in the dag only once. + ``edges`` -- If a node has been visited once but is reached along a + new path, it's accepted, but not recurisvely followed. This traverses + each 'edge' in the DAG once. + ``paths`` -- Explore every unique path reachable from the root. + This descends into visited subtrees and will accept nodes multiple + times if they're reachable by multiple paths. + direction (str): ``children`` or ``parents``. If ``children``, does a traversal + of this spec's children. If ``parents``, traverses upwards in the DAG + towards the root. + deptype (str or tuple): allowed dependency types + depth (bool): When ``False``, yield just edges. When ``True`` yield + the tuple (depth, edge), where depth corresponds to the depth + at which edge.spec was discovered. + key: function that takes a spec and outputs a key for uniqueness test. + visited (set or None): a set of nodes not to follow + + Returns: + A generator that yields ``DependencySpec`` if depth is ``False`` + or a tuple of ``(depth, DependencySpec)`` if depth is ``True``. + """ + root_edges = root_specs(specs) + visitor = get_visitor_from_args(cover, direction, deptype, key, visited) + + # Depth-first + if order in ("pre", "post"): + return traverse_depth_first_edges_generator( + root_edges, visitor, order == "post", root, depth + ) + + # Breadth-first + return traverse_breadth_first_edges_generator(root_edges, visitor, root, depth) + + +def traverse_nodes( + specs, + root=True, + order="pre", + cover="nodes", + direction="children", + deptype="all", + depth=False, + key=id, + visited=None, +): + """ + Generator that yields specs from the DAG, starting from a list of root specs. + + Arguments: + specs (list): List of root specs (considered to be depth 0) + root (bool): Yield the root nodes themselves + order (str): What order of traversal to use in the DAG. For depth-first + search this can be ``pre`` or ``post``. For BFS this should be ``breadth``. + cover (str): Determines how extensively to cover the dag. Possible values: + ``nodes`` -- Visit each unique node in the dag only once. + ``edges`` -- If a node has been visited once but is reached along a + new path, it's accepted, but not recurisvely followed. This traverses + each 'edge' in the DAG once. + ``paths`` -- Explore every unique path reachable from the root. + This descends into visited subtrees and will accept nodes multiple + times if they're reachable by multiple paths. + direction (str): ``children`` or ``parents``. If ``children``, does a traversal + of this spec's children. If ``parents``, traverses upwards in the DAG + towards the root. + deptype (str or tuple): allowed dependency types + depth (bool): When ``False``, yield just edges. When ``True`` yield + the tuple ``(depth, edge)``, where depth corresponds to the depth + at which ``edge.spec`` was discovered. + key: function that takes a spec and outputs a key for uniqueness test. + visited (set or None): a set of nodes not to follow + + Yields: + By default :class:`~spack.spec.Spec`, or a tuple ``(depth, Spec)`` if depth is + set to ``True``. + """ + for item in traverse_edges(specs, root, order, cover, direction, deptype, depth, key, visited): + yield (item[0], item[1].spec) if depth else item.spec + + +def traverse_tree(specs, cover="nodes", deptype="all", key=id, depth_first=True): + """ + Generator that yields ``(depth, DependencySpec)`` tuples in the depth-first + pre-order, so that a tree can be printed from it. + + Arguments: + + specs (list): List of root specs (considered to be depth 0) + cover (str): Determines how extensively to cover the dag. Possible values: + ``nodes`` -- Visit each unique node in the dag only once. + ``edges`` -- If a node has been visited once but is reached along a + new path, it's accepted, but not recurisvely followed. This traverses + each 'edge' in the DAG once. + ``paths`` -- Explore every unique path reachable from the root. + This descends into visited subtrees and will accept nodes multiple + times if they're reachable by multiple paths. + deptype (str or tuple): allowed dependency types + key: function that takes a spec and outputs a key for uniqueness test. + depth_first (bool): Explore the tree in depth-first or breadth-first order. + When setting ``depth_first=True`` and ``cover=nodes``, each spec only + occurs once at the shallowest level, which is useful when rendering + the tree in a terminal. + + Returns: + A generator that yields ``(depth, DependencySpec)`` tuples in such an order + that a tree can be printed. + """ + # BFS only makes sense when going over edges and nodes, for paths the tree is + # identical to DFS, which is much more efficient then. + if not depth_first and cover == "edges": + edges, parents = breadth_first_to_tree_edges(specs, deptype, key) + return traverse_breadth_first_tree_edges(None, edges, parents) + elif not depth_first and cover == "nodes": + edges = breadth_first_to_tree_nodes(specs, deptype, key) + return traverse_breadth_first_tree_nodes(None, edges) + + return traverse_edges(specs, order="pre", cover=cover, deptype=deptype, key=key, depth=True) diff --git a/var/spack/repos/builtin.mock/packages/chain-a/package.py b/var/spack/repos/builtin.mock/packages/chain-a/package.py new file mode 100644 index 00000000000..6dc7dc2c90e --- /dev/null +++ b/var/spack/repos/builtin.mock/packages/chain-a/package.py @@ -0,0 +1,34 @@ +# 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 ChainA(Package): + """ + Part of a collection of mock packages used for testing depth-first vs + breadth-first traversal. The DAG they form: + a --> b --> c --> d # a chain + a --> c # "skip" connection + a --> d # "skip" connection + Spack's edge order is based on the child package name. + In depth-first traversal we get a tree that looks like a chain: + a + b + c + d + In breadth-first we get the tree: + a + b + c + d + """ + + homepage = "https://example.com" + has_code = False + version("1.0") + depends_on("chain-b") + depends_on("chain-c") + depends_on("chain-d") diff --git a/var/spack/repos/builtin.mock/packages/chain-b/package.py b/var/spack/repos/builtin.mock/packages/chain-b/package.py new file mode 100644 index 00000000000..ede29c0e0fd --- /dev/null +++ b/var/spack/repos/builtin.mock/packages/chain-b/package.py @@ -0,0 +1,32 @@ +# 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 ChainB(Package): + """ + Part of a collection of mock packages used for testing depth-first vs + breadth-first traversal. The DAG they form: + a --> b --> c --> d # a chain + a --> c # "skip" connection + a --> d # "skip" connection + Spack's edge order is based on the child package name. + In depth-first traversal we get a tree that looks like a chain: + a + b + c + d + In breadth-first we get the tree: + a + b + c + d + """ + + homepage = "https://example.com" + has_code = False + version("1.0") + depends_on("chain-c") diff --git a/var/spack/repos/builtin.mock/packages/chain-c/package.py b/var/spack/repos/builtin.mock/packages/chain-c/package.py new file mode 100644 index 00000000000..e9d919f0ba9 --- /dev/null +++ b/var/spack/repos/builtin.mock/packages/chain-c/package.py @@ -0,0 +1,32 @@ +# 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 ChainC(Package): + """ + Part of a collection of mock packages used for testing depth-first vs + breadth-first traversal. The DAG they form: + a --> b --> c --> d # a chain + a --> c # "skip" connection + a --> d # "skip" connection + Spack's edge order is based on the child package name. + In depth-first traversal we get a tree that looks like a chain: + a + b + c + d + In breadth-first we get the tree: + a + b + c + d + """ + + homepage = "https://example.com" + has_code = False + version("1.0") + depends_on("chain-d") diff --git a/var/spack/repos/builtin.mock/packages/chain-d/package.py b/var/spack/repos/builtin.mock/packages/chain-d/package.py new file mode 100644 index 00000000000..f2e04089ee5 --- /dev/null +++ b/var/spack/repos/builtin.mock/packages/chain-d/package.py @@ -0,0 +1,31 @@ +# 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 ChainD(Package): + """ + Part of a collection of mock packages used for testing depth-first vs + breadth-first traversal. The DAG they form: + a --> b --> c --> d # a chain + a --> c # "skip" connection + a --> d # "skip" connection + Spack's edge order is based on the child package name. + In depth-first traversal we get a tree that looks like a chain: + a + b + c + d + In breadth-first we get the tree: + a + b + c + d + """ + + homepage = "https://example.com" + has_code = False + version("1.0") From a4d978be596829d006c50778179a2a497ec0f155 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Wed, 2 Nov 2022 03:00:16 -0700 Subject: [PATCH 304/442] tests: fix group membership check in sbang tests. (#33658) Fixes an issue on the RHEL8 UBI container where this test would fail because `gr_mem` was empty for every entry in the `grp` DB. You have to check *both* the `pwd` database (which has primary groups) and `grp` (which has other gorups) to do this correctly. - [x] update `llnl.util.filesystem.group_ids()` to do this - [x] use it in the `sbang` test --- lib/spack/llnl/util/filesystem.py | 11 +++++++++-- lib/spack/spack/test/sbang.py | 6 ++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/spack/llnl/util/filesystem.py b/lib/spack/llnl/util/filesystem.py index fa1188c133e..aece52f8436 100644 --- a/lib/spack/llnl/util/filesystem.py +++ b/lib/spack/llnl/util/filesystem.py @@ -505,8 +505,15 @@ def group_ids(uid=None): if uid is None: uid = getuid() - user = pwd.getpwuid(uid).pw_name - return [g.gr_gid for g in grp.getgrall() if user in g.gr_mem] + + pwd_entry = pwd.getpwuid(uid) + user = pwd_entry.pw_name + + # user's primary group id may not be listed in grp (i.e. /etc/group) + # you have to check pwd for that, so start the list with that + gids = [pwd_entry.pw_gid] + + return sorted(set(gids + [g.gr_gid for g in grp.getgrall() if user in g.gr_mem])) @system_path_filter(arg_slice=slice(1)) diff --git a/lib/spack/spack/test/sbang.py b/lib/spack/spack/test/sbang.py index 18a408a5491..876f3f4d0f6 100644 --- a/lib/spack/spack/test/sbang.py +++ b/lib/spack/spack/test/sbang.py @@ -7,7 +7,6 @@ Test that Spack's shebang filtering works correctly. """ import filecmp -import getpass import os import shutil import stat @@ -273,6 +272,9 @@ def configure_group_perms(): # and grp does not act on remote groups. # To ensure we find a group we can operate on, we get take the first group # listed which has the current user as a member. + gid = fs.group_ids(os.getuid())[0] + group_name = grp.getgrgid(gid).gr_name + conf = syaml.load_config( """\ all: @@ -281,7 +283,7 @@ def configure_group_perms(): write: group group: {0} """.format( - [g.gr_name for g in grp.getgrall() if getpass.getuser() in g.gr_mem][0] + group_name ) ) spack.config.set("packages", conf, scope="user") From ae99829af4393295953afa0f08394bdcd2b58b75 Mon Sep 17 00:00:00 2001 From: Filippo Spiga Date: Wed, 2 Nov 2022 15:09:28 +0000 Subject: [PATCH 305/442] armpl-gcc: Pull RHEL8 package when OS is Rocky8 (#33641) --- var/spack/repos/builtin/packages/armpl-gcc/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/armpl-gcc/package.py b/var/spack/repos/builtin/packages/armpl-gcc/package.py index dd9d22ffa08..edb14359d8f 100644 --- a/var/spack/repos/builtin/packages/armpl-gcc/package.py +++ b/var/spack/repos/builtin/packages/armpl-gcc/package.py @@ -13,6 +13,7 @@ "sles15": "SLES-15", "centos7": "RHEL-7", "centos8": "RHEL-8", + "rocky8": "RHEL-8", "amzn2": "RHEL-7", } From bc209c470d07621ba9af277dab71d048d11f2844 Mon Sep 17 00:00:00 2001 From: Kayla Butler Date: Mon, 28 Mar 2022 14:18:00 -0700 Subject: [PATCH 306/442] flags/variants: Add ++/~~/== syntax for propagation to dependencies Currently, compiler flags and variants are inconsistent: compiler flags set for a package are inherited by its dependencies, while variants are not. We should have these be consistent by allowing for inheritance to be enabled or disabled for both variants and compiler flags. - [x] Make new (spec language) operators - [x] Apply operators to variants and compiler flags - [x] Conflicts currently result in an unsatisfiable spec (i.e., you can't propagate two conflicting values) What I propose is using two of the currently used sigils to symbolized that the variant or compiler flag will be inherited: Example syntax: - `package ++variant` enabled variant that will be propagated to dependencies - `package +variant` enabled variant that will NOT be propagated to dependencies - `package ~~variant` disabled variant that will be propagated to dependencies - `package ~variant` disabled variant that will NOT be propagated to dependencies - `package cflags==True` `cflags` will be propagated to dependencies - `package cflags=True` `cflags` will NOT be propagated to dependencies Syntax for string-valued variants is similar to compiler flags. --- lib/spack/docs/basic_usage.rst | 38 ++- lib/spack/spack/cmd/__init__.py | 3 +- lib/spack/spack/cmd/deactivate.py | 2 +- lib/spack/spack/cmd/extensions.py | 2 +- lib/spack/spack/compiler.py | 20 +- lib/spack/spack/provider_index.py | 3 +- lib/spack/spack/solver/asp.py | 69 +++--- lib/spack/spack/solver/concretize.lp | 62 +++-- lib/spack/spack/solver/display.lp | 2 +- lib/spack/spack/spec.py | 217 ++++++++++++++---- lib/spack/spack/test/cmd/common/arguments.py | 18 +- lib/spack/spack/test/concretize.py | 47 ++++ lib/spack/spack/test/spec_semantics.py | 45 +++- lib/spack/spack/variant.py | 14 +- .../builtin.mock/packages/hypre/package.py | 7 + .../builtin.mock/packages/openblas/package.py | 2 + 16 files changed, 434 insertions(+), 117 deletions(-) diff --git a/lib/spack/docs/basic_usage.rst b/lib/spack/docs/basic_usage.rst index 95c37dd8bf8..73895449b08 100644 --- a/lib/spack/docs/basic_usage.rst +++ b/lib/spack/docs/basic_usage.rst @@ -998,11 +998,15 @@ More formally, a spec consists of the following pieces: * ``%`` Optional compiler specifier, with an optional compiler version (``gcc`` or ``gcc@4.7.3``) * ``+`` or ``-`` or ``~`` Optional variant specifiers (``+debug``, - ``-qt``, or ``~qt``) for boolean variants + ``-qt``, or ``~qt``) for boolean variants. Use ``++`` or ``--`` or + ``~~`` to propagate variants through the dependencies (``++debug``, + ``--qt``, or ``~~qt``). * ``name=`` Optional variant specifiers that are not restricted to - boolean variants + boolean variants. Use ``name==`` to propagate variant through the + dependencies. * ``name=`` Optional compiler flag specifiers. Valid flag names are ``cflags``, ``cxxflags``, ``fflags``, ``cppflags``, ``ldflags``, and ``ldlibs``. + Use ``name==`` to propagate compiler flags through the dependencies. * ``target= os=`` Optional architecture specifier (``target=haswell os=CNL10``) * ``^`` Dependency specs (``^callpath@1.1``) @@ -1226,6 +1230,23 @@ variants using the backwards compatibility syntax and uses only ``~`` for disabled boolean variants. The ``-`` and spaces on the command line are provided for convenience and legibility. +Spack allows variants to propagate their value to the package's +dependency by using ``++``, ``--``, and ``~~`` for boolean variants. +For example, for a ``debug`` variant: + +.. code-block:: sh + + mpileaks ++debug # enabled debug will be propagated to dependencies + mpileaks +debug # only mpileaks will have debug enabled + +To propagate the value of non-boolean variants Spack uses ``name==value``. +For example, for the ``stackstart`` variant: + +.. code-block:: sh + + mpileaks stackstart=4 # variant will be propagated to dependencies + mpileaks stackstart==4 # only mpileaks will have this variant value + ^^^^^^^^^^^^^^ Compiler Flags ^^^^^^^^^^^^^^ @@ -1233,10 +1254,15 @@ Compiler Flags Compiler flags are specified using the same syntax as non-boolean variants, but fulfill a different purpose. While the function of a variant is set by the package, compiler flags are used by the compiler wrappers to inject -flags into the compile line of the build. Additionally, compiler flags are -inherited by dependencies. ``spack install libdwarf cppflags="-g"`` will -install both libdwarf and libelf with the ``-g`` flag injected into their -compile line. +flags into the compile line of the build. Additionally, compiler flags can +be inherited by dependencies by using ``==``. +``spack install libdwarf cppflags=="-g"`` will install both libdwarf and +libelf with the ``-g`` flag injected into their compile line. + +.. note:: + + versions of spack prior to 0.19.0 will propagate compiler flags using + the ``=`` syntax. Notice that the value of the compiler flags must be quoted if it contains any spaces. Any of ``cppflags=-O3``, ``cppflags="-O3"``, diff --git a/lib/spack/spack/cmd/__init__.py b/lib/spack/spack/cmd/__init__.py index e829166d396..ee1297e51ca 100644 --- a/lib/spack/spack/cmd/__init__.py +++ b/lib/spack/spack/cmd/__init__.py @@ -234,7 +234,8 @@ def parse_specs(args, **kwargs): msg = e.message if e.long_message: msg += e.long_message - if unquoted_flags: + # Unquoted flags will be read as a variant or hash + if unquoted_flags and ("variant" in msg or "hash" in msg): msg += "\n\n" msg += unquoted_flags.report() diff --git a/lib/spack/spack/cmd/deactivate.py b/lib/spack/spack/cmd/deactivate.py index d68341037fa..2fa18fc2b19 100644 --- a/lib/spack/spack/cmd/deactivate.py +++ b/lib/spack/spack/cmd/deactivate.py @@ -91,6 +91,6 @@ def deactivate(parser, args): ) if not args.force and not spec.package.is_activated(view): - tty.die("Package %s is not activated." % specs[0].short_spec) + tty.die("Package %s is not activated." % spec.short_spec) spec.package.do_deactivate(view, force=args.force) diff --git a/lib/spack/spack/cmd/extensions.py b/lib/spack/spack/cmd/extensions.py index 50f41529b2e..fa79f8df2dc 100644 --- a/lib/spack/spack/cmd/extensions.py +++ b/lib/spack/spack/cmd/extensions.py @@ -76,7 +76,7 @@ def extensions(parser, args): spec = cmd.disambiguate_spec(spec[0], env) if not spec.package.extendable: - tty.die("%s is not an extendable package." % spec[0].name) + tty.die("%s is not an extendable package." % spec.name) if not spec.package.extendable: tty.die("%s does not have extensions." % spec.short_spec) diff --git a/lib/spack/spack/compiler.py b/lib/spack/spack/compiler.py index 2e863096995..37bc250de86 100644 --- a/lib/spack/spack/compiler.py +++ b/lib/spack/spack/compiler.py @@ -56,25 +56,25 @@ def get_compiler_version_output(compiler_path, *args, **kwargs): return _get_compiler_version_output(compiler_path, *args, **kwargs) -def tokenize_flags(flags_str): +def tokenize_flags(flags_values, propagate=False): """Given a compiler flag specification as a string, this returns a list where the entries are the flags. For compiler options which set values using the syntax "-flag value", this function groups flags and their values together. Any token not preceded by a "-" is considered the value of a prior flag.""" - tokens = flags_str.split() + tokens = flags_values.split() if not tokens: return [] flag = tokens[0] - flags = [] + flags_with_propagation = [] for token in tokens[1:]: if not token.startswith("-"): flag += " " + token else: - flags.append(flag) + flags_with_propagation.append((flag, propagate)) flag = token - flags.append(flag) - return flags + flags_with_propagation.append((flag, propagate)) + return flags_with_propagation #: regex for parsing linker lines @@ -311,11 +311,13 @@ def __init__( # Unfortunately have to make sure these params are accepted # in the same order they are returned by sorted(flags) # in compilers/__init__.py - self.flags = {} - for flag in spack.spec.FlagMap.valid_compiler_flags(): + self.flags = spack.spec.FlagMap(self.spec) + for flag in self.flags.valid_compiler_flags(): value = kwargs.get(flag, None) if value is not None: - self.flags[flag] = tokenize_flags(value) + values_with_propagation = tokenize_flags(value, False) + for value, propagation in values_with_propagation: + self.flags.add_flag(flag, value, propagation) # caching value for compiler reported version # used for version checks for API, e.g. C++11 flag diff --git a/lib/spack/spack/provider_index.py b/lib/spack/spack/provider_index.py index 2da7d05e94d..254492fc21f 100644 --- a/lib/spack/spack/provider_index.py +++ b/lib/spack/spack/provider_index.py @@ -175,9 +175,10 @@ def update(self, spec): pkg_provided = self.repository.get_pkg_class(spec.name).provided for provided_spec, provider_specs in six.iteritems(pkg_provided): - for provider_spec in provider_specs: + for provider_spec_readonly in provider_specs: # TODO: fix this comment. # We want satisfaction other than flags + provider_spec = provider_spec_readonly.copy() provider_spec.compiler_flags = spec.compiler_flags.copy() if spec.satisfies(provider_spec, deps=False): diff --git a/lib/spack/spack/solver/asp.py b/lib/spack/spack/solver/asp.py index af55b757be8..fffa58f337f 100644 --- a/lib/spack/spack/solver/asp.py +++ b/lib/spack/spack/solver/asp.py @@ -302,18 +302,6 @@ def extend_flag_list(flag_list, new_flags): flag_list.append(flag) -def check_same_flags(flag_dict_1, flag_dict_2): - """Return True if flag dicts contain the same flags regardless of order.""" - types = set(flag_dict_1.keys()).union(set(flag_dict_2.keys())) - for t in types: - values1 = set(flag_dict_1.get(t, [])) - values2 = set(flag_dict_2.get(t, [])) - error_msg = "Internal Error: A mismatch in flags has occurred:" - error_msg += "\n\tvalues1: {v1}\n\tvalues2: {v2}".format(v1=values1, v2=values2) - error_msg += "\n Please report this as an issue to the spack maintainers" - assert values1 == values2, error_msg - - def check_packages_exist(specs): """Ensure all packages mentioned in specs exist.""" repo = spack.repo.path @@ -723,6 +711,7 @@ def stringify(x): if output.timers: timer.write_tty() print() + if output.stats: print("Statistics:") pprint.pprint(self.control.statistics) @@ -1359,6 +1348,8 @@ class Head(object): node_compiler = fn.node_compiler_set node_compiler_version = fn.node_compiler_version_set node_flag = fn.node_flag_set + node_flag_propagate = fn.node_flag_propagate + variant_propagate = fn.variant_propagate class Body(object): node = fn.node @@ -1370,6 +1361,8 @@ class Body(object): node_compiler = fn.node_compiler node_compiler_version = fn.node_compiler_version node_flag = fn.node_flag + node_flag_propagate = fn.node_flag_propagate + variant_propagate = fn.variant_propagate f = Body if body else Head @@ -1417,6 +1410,9 @@ class Body(object): clauses.append(f.variant_value(spec.name, vname, value)) + if variant.propagate: + clauses.append(f.variant_propagate(spec.name, vname)) + # Tell the concretizer that this is a possible value for the # variant, to account for things like int/str values where we # can't enumerate the valid values @@ -1443,6 +1439,8 @@ class Body(object): for flag_type, flags in spec.compiler_flags.items(): for flag in flags: clauses.append(f.node_flag(spec.name, flag_type, flag)) + if not spec.concrete and flag.propagate is True: + clauses.append(f.node_flag_propagate(spec.name, flag_type)) # dependencies if spec.concrete: @@ -2076,13 +2074,15 @@ def variant_value(self, pkg, name, value): # FIXME: is there a way not to special case 'dev_path' everywhere? if name == "dev_path": self._specs[pkg].variants.setdefault( - name, spack.variant.SingleValuedVariant(name, value) + name, + spack.variant.SingleValuedVariant(name, value) ) return if name == "patches": self._specs[pkg].variants.setdefault( - name, spack.variant.MultiValuedVariant(name, value) + name, + spack.variant.MultiValuedVariant(name, value) ) return @@ -2101,10 +2101,10 @@ def node_flag_compiler_default(self, pkg): self._flag_compiler_defaults.add(pkg) def node_flag(self, pkg, flag_type, flag): - self._specs[pkg].compiler_flags.setdefault(flag_type, []).append(flag) + self._specs[pkg].compiler_flags.add_flag(flag_type, flag, False) - def node_flag_source(self, pkg, source): - self._flag_sources[pkg].add(source) + def node_flag_source(self, pkg, flag_type, source): + self._flag_sources[(pkg, flag_type)].add(source) def no_flags(self, pkg, flag_type): self._specs[pkg].compiler_flags[flag_type] = [] @@ -2151,15 +2151,24 @@ def reorder_flags(self): for pkg in self._flag_compiler_defaults: spec = self._specs[pkg] compiler_flags = compilers[spec.compiler].flags - check_same_flags(spec.compiler_flags, compiler_flags) - spec.compiler_flags.update(compiler_flags) + for key in spec.compiler_flags: + spec_compiler_flags_set = set(spec.compiler_flags.get(key, [])) + compiler_flags_set = set(compiler_flags.get(key, [])) + assert spec_compiler_flags_set == compiler_flags_set, "%s does not equal %s" % ( + spec_compiler_flags_set, + compiler_flags_set, + ) + + spec.compiler_flags[key] = compiler_flags.get(key, []) # index of all specs (and deps) from the command line by name cmd_specs = dict((s.name, s) for spec in self._command_line_specs for s in spec.traverse()) # iterate through specs with specified flags - for pkg, sources in self._flag_sources.items(): + for key, sources in self._flag_sources.items(): + pkg, flag_type = key spec = self._specs[pkg] + compiler_flags = spec.compiler_flags.get(flag_type, []) # order is determined by the DAG. A spec's flags come after # any from its ancestors on the compile line. @@ -2169,14 +2178,16 @@ def reorder_flags(self): sorted_sources = sorted(sources, key=lambda s: order.index(s)) # add flags from each source, lowest to highest precedence - flags = collections.defaultdict(lambda: []) + flags = [] for source_name in sorted_sources: source = cmd_specs[source_name] - for name, flag_list in source.compiler_flags.items(): - extend_flag_list(flags[name], flag_list) + extend_flag_list(flags, source.compiler_flags.get(flag_type, [])) - check_same_flags(spec.compiler_flags, flags) - spec.compiler_flags.update(flags) + assert set(compiler_flags) == set(flags), "%s does not equal %s" % ( + set(compiler_flags), + set(flags), + ) + spec.compiler_flags.update({flag_type: source.compiler_flags[flag_type]}) def deprecated(self, pkg, version): msg = 'using "{0}@{1}" which is a deprecated version' @@ -2187,12 +2198,14 @@ def sort_fn(function_tuple): name = function_tuple[0] if name == "error": priority = function_tuple[1][0] - return (-4, priority) + return (-5, priority) elif name == "hash": - return (-3, 0) + return (-4, 0) elif name == "node": - return (-2, 0) + return (-3, 0) elif name == "node_compiler": + return (-2, 0) + elif name == "node_flag": return (-1, 0) else: return (0, 0) diff --git a/lib/spack/spack/solver/concretize.lp b/lib/spack/spack/solver/concretize.lp index 8bef7f2c1e7..a1768030747 100644 --- a/lib/spack/spack/solver/concretize.lp +++ b/lib/spack/spack/solver/concretize.lp @@ -400,6 +400,7 @@ node_target(Package, Target) :- attr("node_target", Package, Target). node_target_satisfies(Package, Target) :- attr("node_target_satisfies", Package, Target). variant_value(Package, Variant, Value) :- attr("variant_value", Package, Variant, Value). variant_set(Package, Variant, Value) :- attr("variant_set", Package, Variant, Value). +variant_propagate(Package, Variant) :- attr("variant_propagate", Package, Variant). node_flag(Package, FlagType, Flag) :- attr("node_flag", Package, FlagType, Flag). node_compiler(Package, Compiler) :- attr("node_compiler", Package, Compiler). depends_on(Package, Dependency, Type) :- attr("depends_on", Package, Dependency, Type). @@ -407,6 +408,8 @@ node_compiler_version(Package, Compiler, Version) :- attr("node_compiler_version", Package, Compiler, Version). node_compiler_version_satisfies(Package, Compiler, Version) :- attr("node_compiler_version_satisfies", Package, Compiler, Version). +node_flag_propagate(Package, FlagType) + :- attr("node_flag_propagate", Package, FlagType). attr("node", Package) :- node(Package). attr("virtual_node", Virtual) :- virtual_node(Virtual). @@ -419,6 +422,7 @@ attr("node_target", Package, Target) :- node_target(Package, Target). attr("node_target_satisfies", Package, Target) :- node_target_satisfies(Package, Target). attr("variant_value", Package, Variant, Value) :- variant_value(Package, Variant, Value). attr("variant_set", Package, Variant, Value) :- variant_set(Package, Variant, Value). +attr("variant_propagate", Package, Variant) :- variant_propagate(Package, Variant). attr("node_flag", Package, FlagType, Flag) :- node_flag(Package, FlagType, Flag). attr("node_compiler", Package, Compiler) :- node_compiler(Package, Compiler). attr("depends_on", Package, Dependency, Type) :- depends_on(Package, Dependency, Type). @@ -426,6 +430,8 @@ attr("node_compiler_version", Package, Compiler, Version) :- node_compiler_version(Package, Compiler, Version). attr("node_compiler_version_satisfies", Package, Compiler, Version) :- node_compiler_version_satisfies(Package, Compiler, Version). +attr("node_flag_propagate", Package, FlagType) + :- node_flag_propagate(Package, FlagType). % do not warn if generated program contains none of these. #defined depends_on/3. @@ -559,6 +565,24 @@ error(2, "Cannot satisfy requirement group for package '{0}'", Package) :- variant(Package, Variant) :- variant_condition(ID, Package, Variant), condition_holds(ID). +% propagate the variant +variant_value(Descendant, Variant, Value) :- + node(Package), path(Package, Descendant), + variant(Package, Variant), + variant(Descendant, Variant), + variant_value(Package, Variant, Value), + variant_propagate(Package, Variant), + not variant_set(Descendant, Variant), + variant_possible_value(Descendant, Variant, Value). + +error(2, "{0} and dependency {1} cannot both propagate variant '{2}'", Package1, Package2, Variant) :- + Package1 != Package2, + variant_propagate(Package1, Variant), + variant_propagate(Package2, Variant), + path(Package1, Descendent), + path(Package2, Descendent), + build(Package). + % a variant cannot be set if it is not a variant on the package error(2, "Cannot set variant '{0}' for package '{1}' because the variant condition cannot be satisfied for the given spec", Variant, Package) :- variant_set(Package, Variant), @@ -703,6 +727,7 @@ variant_single_value(Package, "dev_path") % warnings like 'info: atom does not occur in any rule head'. #defined variant/2. #defined variant_sticky/2. +#defined variant_propagate/2. #defined variant_set/3. #defined variant_condition/3. #defined variant_single_value/2. @@ -1005,29 +1030,37 @@ compiler_weight(Package, 100) %----------------------------------------------------------------------------- % Compiler flags %----------------------------------------------------------------------------- -% propagate flags when compilers match -inherit_flags(Package, Dependency) - :- depends_on(Package, Dependency), + +% propagate flags when compiler match +can_inherit_flags(Package, Dependency, FlagType) + :- path(Package, Dependency), node_compiler(Package, Compiler), node_compiler(Dependency, Compiler), + not node_flag_set(Dependency, FlagType, _), compiler(Compiler), flag_type(FlagType). node_flag_inherited(Dependency, FlagType, Flag) - :- node_flag_set(Package, FlagType, Flag), inherit_flags(Package, Dependency). -node_flag_inherited(Dependency, FlagType, Flag) - :- node_flag_inherited(Package, FlagType, Flag), - inherit_flags(Package, Dependency). + :- node_flag_set(Package, FlagType, Flag), can_inherit_flags(Package, Dependency, FlagType), + node_flag_propagate(Package, FlagType). +% Insure propagation +:- node_flag_inherited(Package, FlagType, Flag), + can_inherit_flags(Package, Dependency, FlagType), + node_flag_propagate(Package, FlagType). -% node with flags set to anythingg is "set" -node_flag_set(Package) :- node_flag_set(Package, _, _). +error(0, "{0} and dependency {1} cannot both propagate compiler flags '{2}'", Package, Dependency, FlagType) :- + node(Dependency), + node_flag_propagate(Package, FlagType), + node_flag_propagate(Dependency, FlagType), + path(Package, Dependency). % remember where flags came from -node_flag_source(Package, Package) :- node_flag_set(Package). -node_flag_source(Dependency, Q) - :- node_flag_source(Package, Q), inherit_flags(Package, Dependency). +node_flag_source(Package, FlagType, Package) :- node_flag_set(Package, FlagType, _). +node_flag_source(Dependency, FlagType, Q) + :- node_flag_source(Package, FlagType, Q), node_flag_inherited(Dependency, FlagType, _), + node_flag_propagate(Package, FlagType). % compiler flags from compilers.yaml are put on nodes if compiler matches node_flag(Package, FlagType, Flag) - :- not node_flag_set(Package), + :- not node_flag_set(Package, FlagType, _), compiler_version_flag(Compiler, Version, FlagType, Flag), node_compiler_version(Package, Compiler, Version), flag_type(FlagType), @@ -1035,7 +1068,7 @@ node_flag(Package, FlagType, Flag) compiler_version(Compiler, Version). node_flag_compiler_default(Package) - :- not node_flag_set(Package), + :- not node_flag_set(Package, FlagType, _), compiler_version_flag(Compiler, Version, FlagType, Flag), node_compiler_version(Package, Compiler, Version), flag_type(FlagType), @@ -1054,6 +1087,7 @@ no_flags(Package, FlagType) #defined compiler_version_flag/4. #defined node_flag/3. #defined node_flag_set/3. +#defined node_flag_propagate/2. %----------------------------------------------------------------------------- diff --git a/lib/spack/spack/solver/display.lp b/lib/spack/spack/solver/display.lp index e8f5eeba166..4ba8e9e2cb5 100644 --- a/lib/spack/spack/solver/display.lp +++ b/lib/spack/spack/solver/display.lp @@ -23,7 +23,7 @@ #show node_compiler_version/3. #show node_flag/3. #show node_flag_compiler_default/1. -#show node_flag_source/2. +#show node_flag_source/3. #show no_flags/2. #show external_spec_selected/2. #show version_equivalent/3. diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py index bf0acf58d84..194726baa94 100644 --- a/lib/spack/spack/spec.py +++ b/lib/spack/spack/spec.py @@ -34,6 +34,8 @@ built in debug mode for your package to work, you can require it by adding +debug to the openmpi spec when you depend on it. If you do NOT want the debug option to be enabled, then replace this with -debug. + If you would like for the variant to be propagated through all your + package's dependencies use "++" for enabling and "--" or "~~" for disabling. 4. The name of the compiler to build with. @@ -51,8 +53,10 @@ spec-list = { spec [ dep-list ] } dep_list = { ^ spec } spec = id [ options ] - options = { @version-list | +variant | -variant | ~variant | - %compiler | arch=architecture | [ flag ]=value} + options = { @version-list | ++variant | +variant | + --variant | -variant | ~~variant | ~variant | + variant=value | variant==value | %compiler | + arch=architecture | [ flag ]==value | [ flag ]=value} flag = { cflags | cxxflags | fcflags | fflags | cppflags | ldflags | ldlibs } variant = id @@ -124,6 +128,7 @@ "SpecParser", "parse", "SpecParseError", + "ArchitecturePropagationError", "DuplicateDependencyError", "DuplicateCompilerSpecError", "UnsupportedCompilerError", @@ -148,15 +153,16 @@ is_windows = sys.platform == "win32" #: Valid pattern for an identifier in Spack + identifier_re = r"\w[\w-]*" -compiler_color = "@g" #: color for highlighting compilers -version_color = "@c" #: color for highlighting versions -architecture_color = "@m" #: color for highlighting architectures -enabled_variant_color = "@B" #: color for highlighting enabled variants -disabled_variant_color = "@r" #: color for highlighting disabled varaints -dependency_color = "@." #: color for highlighting dependencies -hash_color = "@K" #: color for highlighting package hashes +compiler_color = "@g" #: color for highlighting compilers +version_color = "@c" #: color for highlighting versions +architecture_color ="@m" #: color for highlighting architectures +enabled_variant_color = "@B" #: color for highlighting enabled variants +disabled_variant_color = "r" #: color for highlighting disabled varaints +dependency_color = "@." #: color for highlighting dependencies +hash_color = "@K" #: color for highlighting package hashes #: This map determines the coloring of specs when using color output. #: We make the fields different colors to enhance readability. @@ -737,6 +743,22 @@ def flip(self): return DependencySpec(parent=self.spec, spec=self.parent, deptypes=self.deptypes) +class CompilerFlag(str): + """Will store a flag value and it's propagation value + + Args: + value (str): the flag's value + propagate (bool): if ``True`` the flag value will + be passed to the package's dependencies. If + ``False`` it will not + """ + + def __new__(cls, value, **kwargs): + obj = str.__new__(cls, value) + obj.propagate = kwargs.pop("propagate", False) + return obj + + _valid_compiler_flags = ["cflags", "cxxflags", "fflags", "ldflags", "ldlibs", "cppflags"] @@ -752,9 +774,20 @@ def satisfies(self, other, strict=False): if strict or (self.spec and self.spec._concrete): return all(f in self and set(self[f]) == set(other[f]) for f in other) else: - return all( + if not all( set(self[f]) == set(other[f]) for f in other if (other[f] != [] and f in self) - ) + ): + return False + + # Check that the propagation values match + for flag_type in other: + if not all( + other[flag_type][i].propagate == self[flag_type][i].propagate + for i in range(len(other[flag_type])) + if flag_type in self + ): + return False + return True def constrain(self, other): """Add all flags in other that aren't in self to self. @@ -775,6 +808,14 @@ def constrain(self, other): elif k not in self: self[k] = other[k] changed = True + + # Check that the propagation values match + if self[k] == other[k]: + for i in range(len(other[k])): + if self[k][i].propagate != other[k][i].propagate: + raise UnsatisfiableCompilerFlagSpecError( + self[k][i].propagate, other[k][i].propagate + ) return changed @staticmethod @@ -782,11 +823,41 @@ def valid_compiler_flags(): return _valid_compiler_flags def copy(self): - clone = FlagMap(None) - for name, value in self.items(): - clone[name] = value + clone = FlagMap(self.spec) + for name, compiler_flag in self.items(): + clone[name] = compiler_flag return clone + def add_flag(self, flag_type, value, propagation): + """Stores the flag's value in CompilerFlag and adds it + to the FlagMap + + Args: + flag_type (str): the type of flag + value (str): the flag's value that will be added to the flag_type's + corresponding list + propagation (bool): if ``True`` the flag value will be passed to + the packages' dependencies. If``False`` it will not be passed + """ + flag = CompilerFlag(value, propagate=propagation) + + if flag_type not in self: + self[flag_type] = [flag] + else: + self[flag_type].append(flag) + + def yaml_entry(self, flag_type): + """Returns the flag type and a list of the flag values since the + propagation values aren't needed when writing to yaml + + Args: + flag_type (str): the type of flag to get values from + + Returns the flag_type and a list of the corresponding flags in + string format + """ + return flag_type, [str(flag) for flag in self[flag_type]] + def _cmp_iter(self): for k, v in sorted(self.items()): yield k @@ -803,7 +874,11 @@ def __str__(self): return ( cond_symbol + " ".join( - str(key) + '="' + " ".join(str(f) for f in self[key]) + '"' for key in sorted_keys + key + + ('=="' if True in [f.propagate for f in self[key]] else '="') + + " ".join(self[key]) + + '"' + for key in sorted_keys ) + cond_symbol ) @@ -1405,10 +1480,26 @@ def _add_versions(self, version_list): for version in version_list: self.versions.add(version) - def _add_flag(self, name, value): + def _add_flag(self, name, value, propagate): """Called by the parser to add a known flag. Known flags currently include "arch" """ + + # If the == syntax is used to propagate the spec architecture + # This is an error + architecture_names = [ + "arch", + "architecture", + "platform", + "os", + "operating_system", + "target", + ] + if propagate and name in architecture_names: + raise ArchitecturePropagationError( + "Unable to propagate the architecture failed." " Use a '=' instead." + ) + valid_flags = FlagMap.valid_compiler_flags() if name == "arch" or name == "architecture": parts = tuple(value.split("-")) @@ -1422,16 +1513,18 @@ def _add_flag(self, name, value): self._set_architecture(target=value) elif name in valid_flags: assert self.compiler_flags is not None - self.compiler_flags[name] = spack.compiler.tokenize_flags(value) + flags_and_propagation = spack.compiler.tokenize_flags(value, propagate) + for flag, propagation in flags_and_propagation: + self.compiler_flags.add_flag(name, flag, propagation) else: # FIXME: # All other flags represent variants. 'foo=true' and 'foo=false' # map to '+foo' and '~foo' respectively. As such they need a # BoolValuedVariant instance. if str(value).upper() == "TRUE" or str(value).upper() == "FALSE": - self.variants[name] = vt.BoolValuedVariant(name, value) + self.variants[name] = vt.BoolValuedVariant(name, value, propagate) else: - self.variants[name] = vt.AbstractVariant(name, value) + self.variants[name] = vt.AbstractVariant(name, value, propagate) def _set_architecture(self, **kwargs): """Called by the parser to set the architecture.""" @@ -1783,7 +1876,14 @@ def to_node_dict(self, hash=ht.dag_hash): params = syaml.syaml_dict(sorted(v.yaml_entry() for _, v in self.variants.items())) - params.update(sorted(self.compiler_flags.items())) + # Only need the string compiler flag for yaml file + params.update( + sorted( + self.compiler_flags.yaml_entry(flag_type) + for flag_type in self.compiler_flags.keys() + ) + ) + if params: d["parameters"] = params @@ -2008,11 +2108,13 @@ def from_node_dict(node): spec.compiler = None if "parameters" in node: - for name, value in node["parameters"].items(): + for name, values in node["parameters"].items(): if name in _valid_compiler_flags: - spec.compiler_flags[name] = value + spec.compiler_flags[name] = [] + for val in values: + spec.compiler_flags.add_flag(name, val, False) else: - spec.variants[name] = vt.MultiValuedVariant.from_node_dict(name, value) + spec.variants[name] = vt.MultiValuedVariant.from_node_dict(name, values) elif "variants" in node: for name, value in node["variants"].items(): spec.variants[name] = vt.MultiValuedVariant.from_node_dict(name, value) @@ -4122,7 +4224,7 @@ def write_attribute(spec, attribute, color): except AttributeError: parent = ".".join(parts[:idx]) m = "Attempted to format attribute %s." % attribute - m += "Spec.%s has no attribute %s" % (parent, part) + m += "Spec %s has no attribute %s" % (parent, part) raise SpecFormatStringError(m) if isinstance(current, vn.VersionList): if current == _any_version: @@ -4859,7 +4961,7 @@ def __missing__(self, key): #: These are possible token types in the spec grammar. -HASH, DEP, VER, COLON, COMMA, ON, OFF, PCT, EQ, ID, VAL, FILE = range(12) +HASH, DEP, VER, COLON, COMMA, ON, D_ON, OFF, D_OFF, PCT, EQ, D_EQ, ID, VAL, FILE = range(15) #: Regex for fully qualified spec names. (e.g., builtin.hdf5) spec_id_re = r"\w[\w.-]*" @@ -4882,15 +4984,19 @@ def __init__(self): ( r"\@([\w.\-]*\s*)*(\s*\=\s*\w[\w.\-]*)?", lambda scanner, val: self.token(VER, val), - ), - (r"\:", lambda scanner, val: self.token(COLON, val)), - (r"\,", lambda scanner, val: self.token(COMMA, val)), - (r"\^", lambda scanner, val: self.token(DEP, val)), - (r"\+", lambda scanner, val: self.token(ON, val)), - (r"\-", lambda scanner, val: self.token(OFF, val)), - (r"\~", lambda scanner, val: self.token(OFF, val)), - (r"\%", lambda scanner, val: self.token(PCT, val)), - (r"\=", lambda scanner, val: self.token(EQ, val)), + ), + (r"\:", lambda scanner, val: self.token(COLON, val)), + (r"\,", lambda scanner, val: self.token(COMMA, val)), + (r"\^", lambda scanner, val: self.token(DEP, val)), + (r"\+\+", lambda scanner, val: self.token(D_ON, val)), + (r"\+", lambda scanner, val: self.token(ON, val)), + (r"\-\-", lambda scanner, val: self.token(D_OFF, val)), + (r"\-", lambda scanner, val: self.token(OFF, val)), + (r"\~\~", lambda scanner, val: self.token(D_OFF, val)), + (r"\~", lambda scanner, val: self.token(OFF, val)), + (r"\%", lambda scanner, val: self.token(PCT, val)), + (r"\=\=", lambda scanner, val: self.token(D_EQ, val)), + (r"\=", lambda scanner, val: self.token(EQ, val)), # Filenames match before identifiers, so no initial filename # component is parsed as a spec (e.g., in subdir/spec.yaml/json) (filename_reg, lambda scanner, v: self.token(FILE, v)), @@ -4901,7 +5007,7 @@ def __init__(self): (spec_id_re, lambda scanner, val: self.token(ID, val)), (r"\s+", lambda scanner, val: None), ], - [EQ], + [D_EQ, EQ], [ (r"[\S].*", lambda scanner, val: self.token(VAL, val)), (r"\s+", lambda scanner, val: None), @@ -4946,7 +5052,7 @@ def do_parse(self): if self.accept(ID): self.previous = self.token - if self.accept(EQ): + if self.accept(EQ) or self.accept(D_EQ): # We're parsing an anonymous spec beginning with a # key-value pair. if not specs: @@ -5023,10 +5129,13 @@ def do_parse(self): else: # If the next token can be part of a valid anonymous spec, # create the anonymous spec - if self.next.type in (VER, ON, OFF, PCT): - # Raise an error if the previous spec is already concrete - if specs and specs[-1].concrete: - raise RedundantSpecError(specs[-1], "compiler, version, " "or variant") + if self.next.type in (VER, ON, D_ON, OFF, D_OFF, PCT): + # Raise an error if the previous spec is already + # concrete (assigned by hash) + if specs and specs[-1]._hash: + raise RedundantSpecError(specs[-1], + 'compiler, version, ' + 'or variant') specs.append(self.spec(None)) else: self.unexpected_token() @@ -5135,22 +5244,36 @@ def spec(self, name): vlist = self.version_list() spec._add_versions(vlist) + elif self.accept(D_ON): + name = self.variant() + spec.variants[name] = vt.BoolValuedVariant(name, True, propagate=True) + elif self.accept(ON): name = self.variant() - spec.variants[name] = vt.BoolValuedVariant(name, True) + spec.variants[name] = vt.BoolValuedVariant(name, True, propagate=False) + + elif self.accept(D_OFF): + name = self.variant() + spec.variants[name] = vt.BoolValuedVariant(name, False, propagate=True) elif self.accept(OFF): name = self.variant() - spec.variants[name] = vt.BoolValuedVariant(name, False) + spec.variants[name] = vt.BoolValuedVariant(name, False, propagate=False) elif self.accept(PCT): spec._set_compiler(self.compiler()) elif self.accept(ID): self.previous = self.token - if self.accept(EQ): + if self.accept(D_EQ): + # We're adding a key-value pair to the spec self.expect(VAL) - spec._add_flag(self.previous.value, self.token.value) + spec._add_flag(self.previous.value, self.token.value, propagate=True) + self.previous = None + elif self.accept(EQ): + # We're adding a key-value pair to the spec + self.expect(VAL) + spec._add_flag(self.previous.value, self.token.value, propagate=False) self.previous = None else: # We've found the start of a new spec. Go back to do_parse @@ -5313,6 +5436,12 @@ def long_message(self): ) +class ArchitecturePropagationError(spack.error.SpecError): + """Raised when the double equal symbols are used to assign + the spec's architecture. + """ + + class DuplicateDependencyError(spack.error.SpecError): """Raised when the same dependency occurs in a spec twice.""" diff --git a/lib/spack/spack/test/cmd/common/arguments.py b/lib/spack/spack/test/cmd/common/arguments.py index 772cc0297eb..d56ad59c85d 100644 --- a/lib/spack/spack/test/cmd/common/arguments.py +++ b/lib/spack/spack/test/cmd/common/arguments.py @@ -46,21 +46,27 @@ def test_negative_integers_not_allowed_for_parallel_jobs(job_parser): @pytest.mark.parametrize( - "specs,cflags,negated_variants", + "specs,cflags,propagation,negated_variants", [ - (['coreutils cflags="-O3 -g"'], ["-O3", "-g"], []), - (["coreutils", "cflags=-O3 -g"], ["-O3"], ["g"]), - (["coreutils", "cflags=-O3", "-g"], ["-O3"], ["g"]), + (['coreutils cflags="-O3 -g"'], ["-O3", "-g"], [False, False], []), + (['coreutils cflags=="-O3 -g"'], ["-O3", "-g"], [True, True], []), + (["coreutils", "cflags=-O3 -g"], ["-O3"], [False], ["g"]), + (["coreutils", "cflags==-O3 -g"], ["-O3"], [True], ["g"]), + (["coreutils", "cflags=-O3", "-g"], ["-O3"], [False], ["g"]), ], ) @pytest.mark.regression("12951") -def test_parse_spec_flags_with_spaces(specs, cflags, negated_variants): +def test_parse_spec_flags_with_spaces(specs, cflags, propagation, negated_variants): spec_list = spack.cmd.parse_specs(specs) assert len(spec_list) == 1 s = spec_list.pop() - assert s.compiler_flags["cflags"] == cflags + compiler_flags = [flag for flag in s.compiler_flags["cflags"]] + flag_propagation = [flag.propagate for flag in s.compiler_flags["cflags"]] + + assert compiler_flags == cflags + assert flag_propagation == propagation assert list(s.variants.keys()) == negated_variants for v in negated_variants: assert "~{0}".format(v) in s diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py index bf0110f3e6e..43f47259bfc 100644 --- a/lib/spack/spack/test/concretize.py +++ b/lib/spack/spack/test/concretize.py @@ -2,6 +2,7 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import os import posixpath import sys @@ -81,6 +82,7 @@ def check_concretize(abstract_spec): "mpich", # compiler flags 'mpich cppflags="-O3"', + 'mpich cppflags=="-O3"', # with virtual "mpileaks ^mpi", "mpileaks ^mpi@:1.1", @@ -323,6 +325,33 @@ def test_different_compilers_get_different_flags(self): assert set(client.compiler_flags["fflags"]) == set(["-O0", "-g"]) assert not set(cmake.compiler_flags["fflags"]) + def test_concretize_compiler_flag_propagate(self): + spec = Spec("hypre cflags=='-g' ^openblas") + spec.concretize() + + assert spec.satisfies("^openblas cflags='-g'") + + @pytest.mark.skipif( + os.environ.get("SPACK_TEST_SOLVER") == "original" or sys.platform == "win32", + reason="Optional compiler propagation isn't deprecated for original concretizer", + ) + def test_concretize_compiler_flag_does_not_propagate(self): + spec = Spec("hypre cflags='-g' ^openblas") + spec.concretize() + + assert not spec.satisfies("^openblas cflags='-g'") + + @pytest.mark.skipif( + os.environ.get("SPACK_TEST_SOLVER") == "original" or sys.platform == "win32", + reason="Optional compiler propagation isn't deprecated for original concretizer", + ) + def test_concretize_propagate_compiler_flag_not_passed_to_dependent(self): + spec = Spec("hypre cflags=='-g' ^openblas cflags='-O3'") + spec.concretize() + + assert set(spec.compiler_flags["cflags"]) == set(["-g"]) + assert spec.satisfies("^openblas cflags='-O3'") + def test_architecture_inheritance(self): """test_architecture_inheritance is likely to fail with an UnavailableCompilerVersionError if the architecture is concretized @@ -401,6 +430,24 @@ def test_concretize_two_virtuals_with_dual_provider_and_a_conflict(self): with pytest.raises(spack.error.SpackError): s.concretize() + @pytest.mark.skipif( + os.environ.get("SPACK_TEST_SOLVER") == "original" or sys.platform == "win32", + reason="Optional compiler propagation isn't deprecated for original concretizer", + ) + def test_concretize_propagate_disabled_variant(self): + """Test a package variant value was passed from its parent.""" + spec = Spec("hypre~~shared ^openblas") + spec.concretize() + + assert spec.satisfies("^openblas~shared") + + def test_concretize_propagated_variant_is_not_passed_to_dependent(self): + """Test a package variant value was passed from its parent.""" + spec = Spec("hypre~~shared ^openblas+shared") + spec.concretize() + + assert spec.satisfies("^openblas+shared") + @pytest.mark.skipif(sys.platform == "win32", reason="No Compiler for Arch on Win") def test_no_matching_compiler_specs(self, mock_low_high_config): # only relevant when not building compilers as needed diff --git a/lib/spack/spack/test/spec_semantics.py b/lib/spack/spack/test/spec_semantics.py index 711e9014163..04aa82797cf 100644 --- a/lib/spack/spack/test/spec_semantics.py +++ b/lib/spack/spack/test/spec_semantics.py @@ -247,16 +247,23 @@ def test_satisfies_virtual_dependency_versions(self): def test_satisfies_matching_variant(self): check_satisfies("mpich+foo", "mpich+foo") + check_satisfies("mpich++foo", "mpich++foo") check_satisfies("mpich~foo", "mpich~foo") + check_satisfies("mpich~~foo", "mpich~~foo") check_satisfies("mpich foo=1", "mpich foo=1") + check_satisfies("mpich foo==1", "mpich foo==1") # confirm that synonymous syntax works correctly check_satisfies("mpich+foo", "mpich foo=True") + check_satisfies("mpich++foo", "mpich foo=True") check_satisfies("mpich foo=true", "mpich+foo") + check_satisfies("mpich foo==true", "mpich++foo") check_satisfies("mpich~foo", "mpich foo=FALSE") + check_satisfies("mpich~~foo", "mpich foo=FALSE") check_satisfies("mpich foo=False", "mpich~foo") + check_satisfies("mpich foo==False", "mpich~foo") check_satisfies("mpich foo=*", "mpich~foo") - check_satisfies("mpich +foo", "mpich foo=*") + check_satisfies("mpich+foo", "mpich foo=*") def test_satisfies_multi_value_variant(self): # Check quoting @@ -295,6 +302,7 @@ def test_satisfies_single_valued_variant(self): # Assert that an autospec generated from a literal # gives the right result for a single valued variant assert "foobar=bar" in a + assert "foobar==bar" in a assert "foobar=baz" not in a assert "foobar=fee" not in a @@ -415,21 +423,32 @@ def test_unsatisfiable_variants(self): check_satisfies("mpich", "mpich+foo", False) check_satisfies("mpich", "mpich~foo", False) check_satisfies("mpich", "mpich foo=1", False) + check_satisfies("mpich", "mpich++foo", False) + check_satisfies("mpich", "mpich~~foo", False) + check_satisfies("mpich", "mpich foo==1", False) # 'mpich' is concrete: check_unsatisfiable("mpich", "mpich+foo", True) check_unsatisfiable("mpich", "mpich~foo", True) check_unsatisfiable("mpich", "mpich foo=1", True) + check_unsatisfiable("mpich", "mpich++foo", True) + check_unsatisfiable("mpich", "mpich~~foo", True) + check_unsatisfiable("mpich", "mpich foo==1", True) def test_unsatisfiable_variant_mismatch(self): # No matchi in specs check_unsatisfiable("mpich~foo", "mpich+foo") check_unsatisfiable("mpich+foo", "mpich~foo") check_unsatisfiable("mpich foo=True", "mpich foo=False") + check_unsatisfiable("mpich~~foo", "mpich++foo") + check_unsatisfiable("mpich++foo", "mpich~~foo") + check_unsatisfiable("mpich foo==True", "mpich foo==False") def test_satisfies_matching_compiler_flag(self): check_satisfies('mpich cppflags="-O3"', 'mpich cppflags="-O3"') check_satisfies('mpich cppflags="-O3 -Wall"', 'mpich cppflags="-O3 -Wall"') + check_satisfies('mpich cppflags=="-O3"', 'mpich cppflags=="-O3"') + check_satisfies('mpich cppflags=="-O3 -Wall"', 'mpich cppflags=="-O3 -Wall"') def test_satisfies_unconstrained_compiler_flag(self): # only asked for mpich, no constraints. Any will do. @@ -453,8 +472,9 @@ def test_copy_satisfies_transitive(self): assert copy[s.name].satisfies(s) def test_unsatisfiable_compiler_flag_mismatch(self): - # No matchi in specs + # No match in specs check_unsatisfiable('mpich cppflags="-O3"', 'mpich cppflags="-O2"') + check_unsatisfiable('mpich cppflags="-O3"', 'mpich cppflags=="-O3"') def test_satisfies_virtual(self): # Don't use check_satisfies: it checks constrain() too, and @@ -554,6 +574,12 @@ def test_constrain_variants(self): check_constrain("libelf+debug~foo", "libelf+debug", "libelf~foo") check_constrain("libelf+debug~foo", "libelf+debug", "libelf+debug~foo") + check_constrain("libelf++debug++foo", "libelf++debug", "libelf+debug+foo") + check_constrain("libelf debug==2 foo==1", "libelf debug==2", "libelf foo=1") + check_constrain("libelf debug==2 foo==1", "libelf debug==2", "libelf debug=2 foo=1") + + check_constrain("libelf++debug~~foo", "libelf++debug", "libelf++debug~foo") + def test_constrain_multi_value_variant(self): check_constrain( 'multivalue-variant foo="bar,baz"', @@ -582,6 +608,17 @@ def test_constrain_compiler_flags(self): 'libelf cflags="-O3" cppflags="-Wall"', ) + check_constrain( + 'libelf cflags="-O3" cppflags=="-Wall"', + 'libelf cppflags=="-Wall"', + 'libelf cflags="-O3"', + ) + check_constrain( + 'libelf cflags=="-O3" cppflags=="-Wall"', + 'libelf cflags=="-O3"', + 'libelf cflags=="-O3" cppflags=="-Wall"', + ) + def test_constrain_architecture(self): check_constrain( "libelf target=default_target os=default_os", @@ -620,6 +657,7 @@ def test_constrain_changed(self): check_constrain_changed("libelf", "~debug") check_constrain_changed("libelf", "debug=2") check_constrain_changed("libelf", 'cppflags="-O3"') + check_constrain_changed("libelf", 'cppflags=="-O3"') platform = spack.platforms.host() check_constrain_changed("libelf", "target=" + platform.target("default_target").name) @@ -636,6 +674,7 @@ def test_constrain_not_changed(self): check_constrain_not_changed("libelf debug=2", "debug=2") check_constrain_not_changed("libelf debug=2", "debug=*") check_constrain_not_changed('libelf cppflags="-O3"', 'cppflags="-O3"') + check_constrain_not_changed('libelf cppflags=="-O3"', 'cppflags=="-O3"') platform = spack.platforms.host() default_target = platform.target("default_target").name @@ -791,7 +830,7 @@ def test_spec_formatting_escapes(self): spec.format(fmt_str) def test_spec_deprecated_formatting(self): - spec = Spec("libelf cflags=-O2") + spec = Spec("libelf cflags==-O2") spec.concretize() # Since the default is the full spec see if the string rep of diff --git a/lib/spack/spack/variant.py b/lib/spack/spack/variant.py index 92e512219b0..cfb43cfc708 100644 --- a/lib/spack/spack/variant.py +++ b/lib/spack/spack/variant.py @@ -245,8 +245,9 @@ class AbstractVariant(object): values. """ - def __init__(self, name, value): + def __init__(self, name, value, propagate=False): self.name = name + self.propagate = propagate # Stores 'value' after a bit of massaging # done by the property setter @@ -334,7 +335,7 @@ def copy(self): >>> assert a == b >>> assert a is not b """ - return type(self)(self.name, self._original_value) + return type(self)(self.name, self._original_value, self.propagate) @implicit_variant_conversion def satisfies(self, other): @@ -401,6 +402,8 @@ def __repr__(self): return "{0.__name__}({1}, {2})".format(cls, repr(self.name), repr(self._original_value)) def __str__(self): + if self.propagate: + return "{0}=={1}".format(self.name, ",".join(str(x) for x in self.value)) return "{0}={1}".format(self.name, ",".join(str(x) for x in self.value)) @@ -444,6 +447,9 @@ def __str__(self): values_str = ",".join(x[:7] for x in self.value) else: values_str = ",".join(str(x) for x in self.value) + + if self.propagate: + return "{0}=={1}".format(self.name, values_str) return "{0}={1}".format(self.name, values_str) @@ -460,6 +466,8 @@ def _value_setter(self, value): self._value = str(self._value[0]) def __str__(self): + if self.propagate: + return "{0}=={1}".format(self.name, self.value) return "{0}={1}".format(self.name, self.value) @implicit_variant_conversion @@ -523,6 +531,8 @@ def __contains__(self, item): return item is self.value def __str__(self): + if self.propagate: + return "{0}{1}".format("++" if self.value else "~~", self.name) return "{0}{1}".format("+" if self.value else "~", self.name) diff --git a/var/spack/repos/builtin.mock/packages/hypre/package.py b/var/spack/repos/builtin.mock/packages/hypre/package.py index fe077f067da..7182cf628a8 100644 --- a/var/spack/repos/builtin.mock/packages/hypre/package.py +++ b/var/spack/repos/builtin.mock/packages/hypre/package.py @@ -2,6 +2,7 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import sys from spack.package import * @@ -17,3 +18,9 @@ class Hypre(Package): depends_on("lapack") depends_on("blas") + + variant( + "shared", + default=(sys.platform != "darwin"), + description="Build shared library (disables static library)", + ) diff --git a/var/spack/repos/builtin.mock/packages/openblas/package.py b/var/spack/repos/builtin.mock/packages/openblas/package.py index 1e948da8f29..8c2f26de579 100644 --- a/var/spack/repos/builtin.mock/packages/openblas/package.py +++ b/var/spack/repos/builtin.mock/packages/openblas/package.py @@ -17,6 +17,8 @@ class Openblas(Package): version("0.2.14", "b1190f3d3471685f17cfd1ec1d252ac9") version("0.2.13", "b1190f3d3471685f17cfd1ec1d252ac9") + variant("shared", default=True, description="Build shared libraries") + # See #20019 for this conflict conflicts("%gcc@:4.4", when="@0.2.14:") From aa4f478ab80ef4a5a36dfe07d02817ca650d3c47 Mon Sep 17 00:00:00 2001 From: Gregory Becker Date: Tue, 1 Nov 2022 10:01:29 -0700 Subject: [PATCH 307/442] propagation: improve performance This updates the propagation logic used in `concretize.lp` to avoid rules with `path()` in the body and instead base propagation around `depends_on()`. --- lib/spack/spack/solver/asp.py | 8 ++- lib/spack/spack/solver/concretize.lp | 79 ++++++++++++++++------------ lib/spack/spack/spec.py | 42 +++++++-------- 3 files changed, 68 insertions(+), 61 deletions(-) diff --git a/lib/spack/spack/solver/asp.py b/lib/spack/spack/solver/asp.py index fffa58f337f..f0437b9309c 100644 --- a/lib/spack/spack/solver/asp.py +++ b/lib/spack/spack/solver/asp.py @@ -1411,7 +1411,7 @@ class Body(object): clauses.append(f.variant_value(spec.name, vname, value)) if variant.propagate: - clauses.append(f.variant_propagate(spec.name, vname)) + clauses.append(f.variant_propagate(spec.name, vname, value, spec.name)) # Tell the concretizer that this is a possible value for the # variant, to account for things like int/str values where we @@ -2074,15 +2074,13 @@ def variant_value(self, pkg, name, value): # FIXME: is there a way not to special case 'dev_path' everywhere? if name == "dev_path": self._specs[pkg].variants.setdefault( - name, - spack.variant.SingleValuedVariant(name, value) + name, spack.variant.SingleValuedVariant(name, value) ) return if name == "patches": self._specs[pkg].variants.setdefault( - name, - spack.variant.MultiValuedVariant(name, value) + name, spack.variant.MultiValuedVariant(name, value) ) return diff --git a/lib/spack/spack/solver/concretize.lp b/lib/spack/spack/solver/concretize.lp index a1768030747..2bbf3091c64 100644 --- a/lib/spack/spack/solver/concretize.lp +++ b/lib/spack/spack/solver/concretize.lp @@ -31,6 +31,7 @@ opt_criterion(300, "number of input specs not concretized"). attr(Name, A1) :- literal(LiteralID, Name, A1), literal_solved(LiteralID). attr(Name, A1, A2) :- literal(LiteralID, Name, A1, A2), literal_solved(LiteralID). attr(Name, A1, A2, A3) :- literal(LiteralID, Name, A1, A2, A3), literal_solved(LiteralID). +attr(Name, A1, A2, A3, A4) :- literal(LiteralID, Name, A1, A2, A3, A4), literal_solved(LiteralID). % For these two atoms we only need implications in one direction root(Package) :- attr("root", Package). @@ -52,6 +53,7 @@ variant_default_value_from_cli(Package, Variant, Value) #defined literal/3. #defined literal/4. #defined literal/5. +#defined literal/6. %----------------------------------------------------------------------------- % Version semantics @@ -175,18 +177,20 @@ node_version_satisfies(Package, Constraint) % corresponding spec attributes hold. condition_holds(ID) :- condition(ID, _); - attr(Name, A1) : condition_requirement(ID, Name, A1); - attr(Name, A1, A2) : condition_requirement(ID, Name, A1, A2); - attr(Name, A1, A2, A3) : condition_requirement(ID, Name, A1, A2, A3). + attr(Name, A1) : condition_requirement(ID, Name, A1); + attr(Name, A1, A2) : condition_requirement(ID, Name, A1, A2); + attr(Name, A1, A2, A3) : condition_requirement(ID, Name, A1, A2, A3); + attr(Name, A1, A2, A3, A4) : condition_requirement(ID, Name, A1, A2, A3, A4). % condition_holds(ID) implies all imposed_constraints, unless do_not_impose(ID) % is derived. This allows imposed constraints to be canceled in special cases. impose(ID) :- condition_holds(ID), not do_not_impose(ID). % conditions that hold impose constraints on other specs -attr(Name, A1) :- impose(ID), imposed_constraint(ID, Name, A1). -attr(Name, A1, A2) :- impose(ID), imposed_constraint(ID, Name, A1, A2). -attr(Name, A1, A2, A3) :- impose(ID), imposed_constraint(ID, Name, A1, A2, A3). +attr(Name, A1) :- impose(ID), imposed_constraint(ID, Name, A1). +attr(Name, A1, A2) :- impose(ID), imposed_constraint(ID, Name, A1, A2). +attr(Name, A1, A2, A3) :- impose(ID), imposed_constraint(ID, Name, A1, A2, A3). +attr(Name, A1, A2, A3, A4) :- impose(ID), imposed_constraint(ID, Name, A1, A2, A3, A4). % we cannot have additional variant values when we are working with concrete specs :- node(Package), hash(Package, Hash), @@ -202,9 +206,11 @@ attr(Name, A1, A2, A3) :- impose(ID), imposed_constraint(ID, Name, A1, A2, A3). #defined condition_requirement/3. #defined condition_requirement/4. #defined condition_requirement/5. +#defined condition_requirement/6. #defined imposed_constraint/3. #defined imposed_constraint/4. #defined imposed_constraint/5. +#defined imposed_constraint/6. %----------------------------------------------------------------------------- % Concrete specs @@ -378,6 +384,7 @@ possible_provider_weight(Dependency, Virtual, 100, "fallback") :- provider(Depen #defined required_provider_condition/3. #defined required_provider_condition/4. #defined required_provider_condition/5. +#defined required_provider_condition/6. %----------------------------------------------------------------------------- % Spec Attributes @@ -400,7 +407,7 @@ node_target(Package, Target) :- attr("node_target", Package, Target). node_target_satisfies(Package, Target) :- attr("node_target_satisfies", Package, Target). variant_value(Package, Variant, Value) :- attr("variant_value", Package, Variant, Value). variant_set(Package, Variant, Value) :- attr("variant_set", Package, Variant, Value). -variant_propagate(Package, Variant) :- attr("variant_propagate", Package, Variant). +variant_propagate(Package, Variant, Value, Source) :- attr("variant_propagate", Package, Variant, Value, Source). node_flag(Package, FlagType, Flag) :- attr("node_flag", Package, FlagType, Flag). node_compiler(Package, Compiler) :- attr("node_compiler", Package, Compiler). depends_on(Package, Dependency, Type) :- attr("depends_on", Package, Dependency, Type). @@ -422,7 +429,7 @@ attr("node_target", Package, Target) :- node_target(Package, Target). attr("node_target_satisfies", Package, Target) :- node_target_satisfies(Package, Target). attr("variant_value", Package, Variant, Value) :- variant_value(Package, Variant, Value). attr("variant_set", Package, Variant, Value) :- variant_set(Package, Variant, Value). -attr("variant_propagate", Package, Variant) :- variant_propagate(Package, Variant). +attr("variant_propagate", Package, Variant, Value, Source) :- variant_propagate(Package, Variant, Value, Source). attr("node_flag", Package, FlagType, Flag) :- node_flag(Package, FlagType, Flag). attr("node_compiler", Package, Compiler) :- node_compiler(Package, Compiler). attr("depends_on", Package, Dependency, Type) :- depends_on(Package, Dependency, Type). @@ -509,6 +516,7 @@ error(2, "Attempted to use external for '{0}' which does not satisfy any configu #defined external_spec_condition/3. #defined external_spec_condition/4. #defined external_spec_condition/5. +#defined external_spec_condition/6. %----------------------------------------------------------------------------- % Config required semantics @@ -565,23 +573,23 @@ error(2, "Cannot satisfy requirement group for package '{0}'", Package) :- variant(Package, Variant) :- variant_condition(ID, Package, Variant), condition_holds(ID). -% propagate the variant -variant_value(Descendant, Variant, Value) :- - node(Package), path(Package, Descendant), - variant(Package, Variant), - variant(Descendant, Variant), - variant_value(Package, Variant, Value), - variant_propagate(Package, Variant), - not variant_set(Descendant, Variant), - variant_possible_value(Descendant, Variant, Value). +variant_propagate(Package, Variant, Value, Source) :- + node(Package), + depends_on(Parent, Package), + variant_propagate(Parent, Variant, Value, Source), + not variant_set(Package, Variant). -error(2, "{0} and dependency {1} cannot both propagate variant '{2}'", Package1, Package2, Variant) :- - Package1 != Package2, - variant_propagate(Package1, Variant), - variant_propagate(Package2, Variant), - path(Package1, Descendent), - path(Package2, Descendent), - build(Package). +variant_value(Package, Variant, Value) :- + node(Package), + variant(Package, Variant), + variant_propagate(Package, Variant, Value, _), + variant_possible_value(Package, Variant, Value). + +error(2, "{0} and {1} cannot both propagate variant '{2}' to package {3} with values '{4}' and '{5}'", Source1, Source2, Variant, Package, Value1, Value2) :- + variant_propagate(Package, Variant, Value1, Source1), + variant_propagate(Package, Variant, Value2, Source2), + variant(Package, Variant), + Value1 != Value2. % a variant cannot be set if it is not a variant on the package error(2, "Cannot set variant '{0}' for package '{1}' because the variant condition cannot be satisfied for the given spec", Variant, Package) @@ -727,7 +735,7 @@ variant_single_value(Package, "dev_path") % warnings like 'info: atom does not occur in any rule head'. #defined variant/2. #defined variant_sticky/2. -#defined variant_propagate/2. +#defined variant_propagate/4. #defined variant_set/3. #defined variant_condition/3. #defined variant_single_value/2. @@ -1033,24 +1041,28 @@ compiler_weight(Package, 100) % propagate flags when compiler match can_inherit_flags(Package, Dependency, FlagType) - :- path(Package, Dependency), + :- depends_on(Package, Dependency), node_compiler(Package, Compiler), node_compiler(Dependency, Compiler), not node_flag_set(Dependency, FlagType, _), compiler(Compiler), flag_type(FlagType). + node_flag_inherited(Dependency, FlagType, Flag) :- node_flag_set(Package, FlagType, Flag), can_inherit_flags(Package, Dependency, FlagType), node_flag_propagate(Package, FlagType). -% Insure propagation +% Ensure propagation :- node_flag_inherited(Package, FlagType, Flag), can_inherit_flags(Package, Dependency, FlagType), node_flag_propagate(Package, FlagType). -error(0, "{0} and dependency {1} cannot both propagate compiler flags '{2}'", Package, Dependency, FlagType) :- - node(Dependency), - node_flag_propagate(Package, FlagType), - node_flag_propagate(Dependency, FlagType), - path(Package, Dependency). +error(2, "{0} and {1} cannot both propagate compiler flags '{2}' to {3}", Source1, Source2, Package, FlagType) :- + depends_on(Source1, Package), + depends_on(Source2, Package), + node_flag_propagate(Source1, FlagType), + node_flag_propagate(Source2, FlagType), + can_inherit_flags(Source1, Package, FlagType), + can_inherit_flags(Source2, Package, FlagType), + Source1 != Source2. % remember where flags came from node_flag_source(Package, FlagType, Package) :- node_flag_set(Package, FlagType, _). @@ -1060,8 +1072,7 @@ node_flag_source(Dependency, FlagType, Q) % compiler flags from compilers.yaml are put on nodes if compiler matches node_flag(Package, FlagType, Flag) - :- not node_flag_set(Package, FlagType, _), - compiler_version_flag(Compiler, Version, FlagType, Flag), + :- compiler_version_flag(Compiler, Version, FlagType, Flag), node_compiler_version(Package, Compiler, Version), flag_type(FlagType), compiler(Compiler), diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py index 194726baa94..dd1ce821d96 100644 --- a/lib/spack/spack/spec.py +++ b/lib/spack/spack/spec.py @@ -156,13 +156,13 @@ identifier_re = r"\w[\w-]*" -compiler_color = "@g" #: color for highlighting compilers -version_color = "@c" #: color for highlighting versions -architecture_color ="@m" #: color for highlighting architectures -enabled_variant_color = "@B" #: color for highlighting enabled variants +compiler_color = "@g" #: color for highlighting compilers +version_color = "@c" #: color for highlighting versions +architecture_color = "@m" #: color for highlighting architectures +enabled_variant_color = "@B" #: color for highlighting enabled variants disabled_variant_color = "r" #: color for highlighting disabled varaints -dependency_color = "@." #: color for highlighting dependencies -hash_color = "@K" #: color for highlighting package hashes +dependency_color = "@." #: color for highlighting dependencies +hash_color = "@K" #: color for highlighting package hashes #: This map determines the coloring of specs when using color output. #: We make the fields different colors to enhance readability. @@ -4984,19 +4984,19 @@ def __init__(self): ( r"\@([\w.\-]*\s*)*(\s*\=\s*\w[\w.\-]*)?", lambda scanner, val: self.token(VER, val), - ), - (r"\:", lambda scanner, val: self.token(COLON, val)), - (r"\,", lambda scanner, val: self.token(COMMA, val)), - (r"\^", lambda scanner, val: self.token(DEP, val)), - (r"\+\+", lambda scanner, val: self.token(D_ON, val)), - (r"\+", lambda scanner, val: self.token(ON, val)), - (r"\-\-", lambda scanner, val: self.token(D_OFF, val)), - (r"\-", lambda scanner, val: self.token(OFF, val)), - (r"\~\~", lambda scanner, val: self.token(D_OFF, val)), - (r"\~", lambda scanner, val: self.token(OFF, val)), - (r"\%", lambda scanner, val: self.token(PCT, val)), - (r"\=\=", lambda scanner, val: self.token(D_EQ, val)), - (r"\=", lambda scanner, val: self.token(EQ, val)), + ), + (r"\:", lambda scanner, val: self.token(COLON, val)), + (r"\,", lambda scanner, val: self.token(COMMA, val)), + (r"\^", lambda scanner, val: self.token(DEP, val)), + (r"\+\+", lambda scanner, val: self.token(D_ON, val)), + (r"\+", lambda scanner, val: self.token(ON, val)), + (r"\-\-", lambda scanner, val: self.token(D_OFF, val)), + (r"\-", lambda scanner, val: self.token(OFF, val)), + (r"\~\~", lambda scanner, val: self.token(D_OFF, val)), + (r"\~", lambda scanner, val: self.token(OFF, val)), + (r"\%", lambda scanner, val: self.token(PCT, val)), + (r"\=\=", lambda scanner, val: self.token(D_EQ, val)), + (r"\=", lambda scanner, val: self.token(EQ, val)), # Filenames match before identifiers, so no initial filename # component is parsed as a spec (e.g., in subdir/spec.yaml/json) (filename_reg, lambda scanner, v: self.token(FILE, v)), @@ -5133,9 +5133,7 @@ def do_parse(self): # Raise an error if the previous spec is already # concrete (assigned by hash) if specs and specs[-1]._hash: - raise RedundantSpecError(specs[-1], - 'compiler, version, ' - 'or variant') + raise RedundantSpecError(specs[-1], "compiler, version, " "or variant") specs.append(self.spec(None)) else: self.unexpected_token() From cff94f8e71e98bac6d2b7ce54edc59898aae247c Mon Sep 17 00:00:00 2001 From: "Paul R. C. Kent" Date: Wed, 2 Nov 2022 12:46:08 -0400 Subject: [PATCH 308/442] llvm: add 15.0.3, 15.0.4 (#33651) * v1503 * v1504 --- var/spack/repos/builtin/packages/llvm/package.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/var/spack/repos/builtin/packages/llvm/package.py b/var/spack/repos/builtin/packages/llvm/package.py index d7958bd6f8f..d7dc58d4f56 100644 --- a/var/spack/repos/builtin/packages/llvm/package.py +++ b/var/spack/repos/builtin/packages/llvm/package.py @@ -36,6 +36,8 @@ class Llvm(CMakePackage, CudaPackage): # fmt: off version("main", branch="main") + version("15.0.4", sha256="e24b4d3bf7821dcb1c901d1e09096c1f88fb00095c5a6ef893baab4836975e52") + version("15.0.3", sha256="8ac8e4c0982bf236526d737d385db5e1e66543ab217a9355d54159659eae3774") version("15.0.2", sha256="dc11d35e60ab61792baa607dff080c993b39de23fb93b3d3369ba15b0601c307") version("15.0.1", sha256="20bccb964e39f604fdc16d1258f94d2053fbdcdab2b2f6d5e20e6095ec403c00") version("15.0.0", sha256="36d83cd84e1caf2bcfda1669c029e2b949adb9860cff01e7d3246ac2348b11ae") From d4ea74bf80bde99a5d96ec0bbe9e872961f4679b Mon Sep 17 00:00:00 2001 From: Greg Sjaardema Date: Wed, 2 Nov 2022 10:50:15 -0600 Subject: [PATCH 309/442] SEACAS: Update package.py to handle new SEACAS project name (#33646) The base project name for the SEACAS project has changed from "SEACASProj" to "SEACAS" as of @2022-10-14, so the package needed to be updated to use the new project name when needed. The refactor also changes several: "-DSome_CMAKE_Option:BOOL=ON" to define("Some_CMAKE_Option", True) --- .../repos/builtin/packages/seacas/package.py | 180 +++++++++++------- 1 file changed, 107 insertions(+), 73 deletions(-) diff --git a/var/spack/repos/builtin/packages/seacas/package.py b/var/spack/repos/builtin/packages/seacas/package.py index 061e89d033a..92951501484 100644 --- a/var/spack/repos/builtin/packages/seacas/package.py +++ b/var/spack/repos/builtin/packages/seacas/package.py @@ -15,10 +15,13 @@ class Seacas(CMakePackage): - """The SEACAS Project contains the Exodus and IOSS libraries and a - collection of applications which create, query, modify, or - translate exodus databases. Default is to build the exodus and - IOSS libraries and the io_shell, io_info, io_modify, struc_to_unstruc apps. + """The SEACAS Project contains the Exodus and IOSS I/O libraries + and a collection of applications which create, query, modify, or + translate Exodus databases. Exodus is a finite element mesh and + results database file format. + + Default is to build the Exodus and IOSS libraries and the + io_shell, io_info, io_modify, struc_to_unstruc apps. """ homepage = "https://sandialabs.github.io/seacas/" @@ -131,7 +134,8 @@ class Seacas(CMakePackage): depends_on("hdf5+hl~mpi", when="~mpi") depends_on("cgns@4.2.0:+mpi+scoping", when="+cgns +mpi") depends_on("cgns@4.2.0:~mpi+scoping", when="+cgns ~mpi") - depends_on("fmt@8.1.0:", when="@2022-03-04:") + depends_on("fmt@8.1.0:", when="@2022-03-04:2022-05-16") + depends_on("fmt@9.1.0:", when="@2022-10-14") with when("+adios2"): depends_on("adios2@master") @@ -166,35 +170,49 @@ def cmake_args(self): from_variant = self.define_from_variant define = self.define + if self.spec.satisfies("@2022-10-14:"): + project_name_base = "Seacas" + else: + project_name_base = "SEACASProj" + options = [] # #################### Base Settings ####################### + options.extend( + [ + from_variant("CMAKE_INSTALL_RPATH_USE_LINK_PATH", "shared"), + from_variant("BUILD_SHARED_LIBS", "shared"), + from_variant("SEACASExodus_ENABLE_THREADSAFE", "thread_safe"), + from_variant("SEACASIoss_ENABLE_THREADSAFE", "thread_safe"), + from_variant("TPL_ENABLE_X11", "x11"), + ] + ) + if "+mpi" in spec: options.extend( [ "-DCMAKE_C_COMPILER=%s" % spec["mpi"].mpicc, "-DCMAKE_CXX_COMPILER=%s" % spec["mpi"].mpicxx, "-DCMAKE_Fortran_COMPILER=%s" % spec["mpi"].mpifc, - "-DTPL_ENABLE_MPI:BOOL=ON", + define("TPL_ENABLE_MPI", True), "-DMPI_BASE_DIR:PATH=%s" % spec["mpi"].prefix, ] ) else: - "-DTPL_ENABLE_MPI:BOOL=OFF" + options.extend( + [ + define("TPL_ENABLE_MPI", False), + ] + ) options.extend( [ - "-DSEACASProj_ENABLE_TESTS:BOOL=ON", - "-DSEACASProj_ENABLE_CXX11:BOOL=ON", - from_variant("CMAKE_INSTALL_RPATH_USE_LINK_PATH", "shared"), - from_variant("BUILD_SHARED_LIBS", "shared"), - "-DSEACASProj_ENABLE_Kokkos:BOOL=OFF", - "-DSEACASProj_HIDE_DEPRECATED_CODE:BOOL=OFF", - from_variant("SEACASExodus_ENABLE_THREADSAFE", "thread_safe"), - from_variant("SEACASIoss_ENABLE_THREADSAFE", "thread_safe"), - from_variant("SEACASProj_ENABLE_Fortran", "fortran"), - from_variant("TPL_ENABLE_X11", "x11"), + define(project_name_base + "_ENABLE_TESTS", True), + define(project_name_base + "_ENABLE_CXX11", True), + define(project_name_base + "_ENABLE_Kokkos", False), + define(project_name_base + "_HIDE_DEPRECATED_CODE", False), + from_variant(project_name_base + "_ENABLE_Fortran", "fortran"), ] ) @@ -203,67 +221,68 @@ def cmake_args(self): if "+applications" in spec and "+legacy" in spec: options.extend( [ - "-DSEACASProj_ENABLE_ALL_PACKAGES:BOOL=ON", - "-DSEACASProj_ENABLE_ALL_OPTIONAL_PACKAGES:BOOL=ON", - "-DSEACASProj_ENABLE_SECONDARY_TESTED_CODE:BOOL=ON", + define(project_name_base + "_ENABLE_ALL_PACKAGES", True), + define(project_name_base + "_ENABLE_ALL_OPTIONAL_PACKAGES", True), + define(project_name_base + "_ENABLE_SECONDARY_TESTED_CODE", True), ] ) + else: # Don't want everything; handle the subsets: options.extend( [ - "-DSEACASProj_ENABLE_ALL_PACKAGES:BOOL=OFF", - "-DSEACASProj_ENABLE_ALL_OPTIONAL_PACKAGES:BOOL=OFF", - "-DSEACASProj_ENABLE_SECONDARY_TESTED_CODE:BOOL=OFF", - "-DSEACASProj_ENABLE_SEACASIoss:BOOL=ON", - "-DSEACASProj_ENABLE_SEACASExodus:BOOL=ON", - from_variant("SEACASProj_ENABLE_SEACASExodus_for", "fortran"), - from_variant("SEACASProj_ENABLE_SEACASExoIIv2for32", "fortran"), + define(project_name_base + "_ENABLE_ALL_PACKAGES", False), + define(project_name_base + "_ENABLE_ALL_OPTIONAL_PACKAGES", False), + define(project_name_base + "_ENABLE_SECONDARY_TESTED_CODE", False), + define(project_name_base + "_ENABLE_SEACASIoss", True), + define(project_name_base + "_ENABLE_SEACASExodus", True), + from_variant(project_name_base + "_ENABLE_SEACASExodus_for", "fortran"), + from_variant(project_name_base + "_ENABLE_SEACASExoIIv2for32", "fortran"), ] ) if "+applications" in spec: options.extend( [ - "-DSEACASProj_ENABLE_SEACASAprepro:BOOL=ON", - "-DSEACASProj_ENABLE_SEACASAprepro_lib:BOOL=ON", - "-DSEACASProj_ENABLE_SEACASConjoin:BOOL=ON", - "-DSEACASProj_ENABLE_SEACASCpup:BOOL=ON", - "-DSEACASProj_ENABLE_SEACASEjoin:BOOL=ON", - "-DSEACASProj_ENABLE_SEACASEpu:BOOL=ON", - "-DSEACASProj_ENABLE_SEACASExo2mat:BOOL=ON", - "-DSEACASProj_ENABLE_SEACASExo_format:BOOL=ON", - "-DSEACASProj_ENABLE_SEACASExodiff:BOOL=ON", - from_variant("SEACASProj_ENABLE_SEACASExplore", "fortran"), - from_variant("SEACASProj_ENABLE_SEACASGrepos", "fortran"), - "-DSEACASProj_ENABLE_SEACASMat2exo:BOOL=ON", - "-DSEACASProj_ENABLE_SEACASNas2exo:BOOL=ON", - "-DSEACASProj_ENABLE_SEACASNemslice:BOOL=ON", - "-DSEACASProj_ENABLE_SEACASNemspread:BOOL=ON", - "-DSEACASProj_ENABLE_SEACASSlice:BOOL=ON", - "-DSEACASProj_ENABLE_SEACASZellij:BOOL=ON", + define(project_name_base + "_ENABLE_SEACASAprepro", True), + define(project_name_base + "_ENABLE_SEACASAprepro_lib", True), + define(project_name_base + "_ENABLE_SEACASConjoin", True), + define(project_name_base + "_ENABLE_SEACASCpup", True), + define(project_name_base + "_ENABLE_SEACASEjoin", True), + define(project_name_base + "_ENABLE_SEACASEpu", True), + define(project_name_base + "_ENABLE_SEACASExo2mat", True), + define(project_name_base + "_ENABLE_SEACASExo_format", True), + define(project_name_base + "_ENABLE_SEACASExodiff", True), + from_variant(project_name_base + "_ENABLE_SEACASExplore", "fortran"), + from_variant(project_name_base + "_ENABLE_SEACASGrepos", "fortran"), + define(project_name_base + "_ENABLE_SEACASMat2exo", True), + define(project_name_base + "_ENABLE_SEACASNas2exo", True), + define(project_name_base + "_ENABLE_SEACASNemslice", True), + define(project_name_base + "_ENABLE_SEACASNemspread", True), + define(project_name_base + "_ENABLE_SEACASSlice", True), + define(project_name_base + "_ENABLE_SEACASZellij", True), ] ) if "+legacy" in spec: options.extend( [ - define("SEACASProj_ENABLE_SEACASNemesis", True), - from_variant("SEACASProj_ENABLE_SEACASAlgebra", "fortran"), - from_variant("SEACASProj_ENABLE_SEACASBlot", "fortran"), - from_variant("SEACASProj_ENABLE_SEACASEx1ex2v2", "fortran"), - from_variant("SEACASProj_ENABLE_SEACASEx2ex1v2", "fortran"), - from_variant("SEACASProj_ENABLE_SEACASExomatlab", "fortran"), - from_variant("SEACASProj_ENABLE_SEACASExotec2", "fortran"), - from_variant("SEACASProj_ENABLE_SEACASExotxt", "fortran"), - from_variant("SEACASProj_ENABLE_SEACASFastq", "fortran"), - from_variant("SEACASProj_ENABLE_SEACASGen3D", "fortran"), - from_variant("SEACASProj_ENABLE_SEACASGenshell", "fortran"), - from_variant("SEACASProj_ENABLE_SEACASGjoin", "fortran"), - from_variant("SEACASProj_ENABLE_SEACASMapvar", "fortran"), - from_variant("SEACASProj_ENABLE_SEACASMapvar-kd", "fortran"), - from_variant("SEACASProj_ENABLE_SEACASNumbers", "fortran"), - from_variant("SEACASProj_ENABLE_SEACASTxtexo", "fortran"), + define(project_name_base + "_ENABLE_SEACASNemesis", True), + from_variant(project_name_base + "_ENABLE_SEACASAlgebra", "fortran"), + from_variant(project_name_base + "_ENABLE_SEACASBlot", "fortran"), + from_variant(project_name_base + "_ENABLE_SEACASEx1ex2v2", "fortran"), + from_variant(project_name_base + "_ENABLE_SEACASEx2ex1v2", "fortran"), + from_variant(project_name_base + "_ENABLE_SEACASExomatlab", "fortran"), + from_variant(project_name_base + "_ENABLE_SEACASExotec2", "fortran"), + from_variant(project_name_base + "_ENABLE_SEACASExotxt", "fortran"), + from_variant(project_name_base + "_ENABLE_SEACASFastq", "fortran"), + from_variant(project_name_base + "_ENABLE_SEACASGen3D", "fortran"), + from_variant(project_name_base + "_ENABLE_SEACASGenshell", "fortran"), + from_variant(project_name_base + "_ENABLE_SEACASGjoin", "fortran"), + from_variant(project_name_base + "_ENABLE_SEACASMapvar", "fortran"), + from_variant(project_name_base + "_ENABLE_SEACASMapvar-kd", "fortran"), + from_variant(project_name_base + "_ENABLE_SEACASNumbers", "fortran"), + from_variant(project_name_base + "_ENABLE_SEACASTxtexo", "fortran"), ] ) @@ -271,7 +290,7 @@ def cmake_args(self): # Always need NetCDF-C options.extend( [ - "-DTPL_ENABLE_Netcdf:BOOL=ON", + define("TPL_ENABLE_Netcdf", True), "-DNetCDF_ROOT:PATH=%s" % spec["netcdf-c"].prefix, ] ) @@ -279,11 +298,11 @@ def cmake_args(self): if "+parmetis" in spec: options.extend( [ - "-DTPL_ENABLE_METIS:BOOL=ON", + define("TPL_ENABLE_METIS", True), "-DMETIS_LIBRARY_DIRS=%s" % spec["metis"].prefix.lib, "-DMETIS_LIBRARY_NAMES=metis", "-DTPL_METIS_INCLUDE_DIRS=%s" % spec["metis"].prefix.include, - "-DTPL_ENABLE_ParMETIS:BOOL=ON", + define("TPL_ENABLE_ParMETIS", True), "-DParMETIS_LIBRARY_DIRS=%s;%s" % (spec["parmetis"].prefix.lib, spec["metis"].prefix.lib), "-DParMETIS_LIBRARY_NAMES=parmetis;metis", @@ -294,37 +313,48 @@ def cmake_args(self): elif "+metis" in spec: options.extend( [ - "-DTPL_ENABLE_METIS:BOOL=ON", + define("TPL_ENABLE_METIS", True), "-DMETIS_LIBRARY_DIRS=%s" % spec["metis"].prefix.lib, "-DMETIS_LIBRARY_NAMES=metis", "-DTPL_METIS_INCLUDE_DIRS=%s" % spec["metis"].prefix.include, - "-DTPL_ENABLE_ParMETIS:BOOL=OFF", + define("TPL_ENABLE_ParMETIS", False), ] ) else: options.extend( [ - "-DTPL_ENABLE_METIS:BOOL=OFF", - "-DTPL_ENABLE_ParMETIS:BOOL=OFF", + define("TPL_ENABLE_METIS", False), + define("TPL_ENABLE_ParMETIS", False), ] ) if "+matio" in spec: options.extend( - ["-DTPL_ENABLE_Matio:BOOL=ON", "-DMatio_ROOT:PATH=%s" % spec["matio"].prefix] + [ + define("TPL_ENABLE_Matio", True), + "-DMatio_ROOT:PATH=%s" % spec["matio"].prefix, + ] ) else: - options.extend(["-DTPL_ENABLE_Matio:BOOL=OFF"]) + options.extend( + [ + define("TPL_ENABLE_Matio", False), + ] + ) if "+cgns" in spec: options.extend( [ - "-DTPL_ENABLE_CGNS:BOOL=ON", + define("TPL_ENABLE_CGNS", True), "-DCGNS_ROOT:PATH=%s" % spec["cgns"].prefix, ] ) else: - options.extend(["-DTPL_ENABLE_CGNS:BOOL=OFF"]) + options.extend( + [ + define("TPL_ENABLE_CGNS", False), + ] + ) options.append(from_variant("TPL_ENABLE_Faodel", "faodel")) @@ -335,12 +365,16 @@ def cmake_args(self): if "+adios2" in spec: options.extend( [ - "-DTPL_ENABLE_ADIOS2:BOOL=ON", + define("TPL_ENABLE_ADIOS2", True), "-DADIOS2_ROOT:PATH=%s" % spec["adios2"].prefix, ] ) else: - options.extend(["-DTPL_ENABLE_ADIOS2:BOOL=OFF"]) + options.extend( + [ + define("TPL_ENABLE_ADIOS2", False), + ] + ) # ################# RPath Handling ###################### if sys.platform == "darwin" and macos_version() >= Version("10.12"): From 4b549560f9a5143971efc87d9e111505f71b22b0 Mon Sep 17 00:00:00 2001 From: Sinan Date: Wed, 2 Nov 2022 11:40:05 -0700 Subject: [PATCH 310/442] package_qgis_fix_pythonpath (#33655) * package_qgis_fix_pythonpath * check if bindings enabled also Co-authored-by: sbulut --- var/spack/repos/builtin/packages/qgis/package.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/var/spack/repos/builtin/packages/qgis/package.py b/var/spack/repos/builtin/packages/qgis/package.py index 377c4fd10eb..158a2a021f6 100644 --- a/var/spack/repos/builtin/packages/qgis/package.py +++ b/var/spack/repos/builtin/packages/qgis/package.py @@ -240,6 +240,11 @@ def cmake_args(self): args.append("-DWITH_GRASS7=OFF") return args + def setup_run_environment(self, env): + if "+bindings" in self.spec: + # python module isn't located at the standard path + env.prepend_path("PYTHONPATH", self.prefix.share.qgis.python) + def check(self): """The tests of fail without access to an X server, cant run on build servers""" pass From 0661c1f531a5a9ea4d69388a944d138e7e0bd578 Mon Sep 17 00:00:00 2001 From: Carson Woods Date: Wed, 2 Nov 2022 14:42:10 -0400 Subject: [PATCH 311/442] Package: add new package py-fitter (#33652) * Add new python package * Fix isort style issues * Add additional dependencies * Add additional dependencies * Remove comments * Add additional explicit dependencies --- .../builtin/packages/py-fitter/package.py | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 var/spack/repos/builtin/packages/py-fitter/package.py diff --git a/var/spack/repos/builtin/packages/py-fitter/package.py b/var/spack/repos/builtin/packages/py-fitter/package.py new file mode 100644 index 00000000000..b3640e2f617 --- /dev/null +++ b/var/spack/repos/builtin/packages/py-fitter/package.py @@ -0,0 +1,29 @@ +# 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 PyFitter(PythonPackage): + """fitter package provides a simple class to identify the distribution + from which a data samples is generated from. It uses 80 distributions + from Scipy and allows you to plot the results to check what is the + most probable distribution and the best parameters.""" + + homepage = "https://github.com/cokelaer/fitter" + pypi = "fitter/fitter-1.5.1.tar.gz" + + maintainers = ["carsonwoods"] + + version("1.5.1", sha256="893b35ad0a84c3b96b63ec203a6a79effdba98777aed966ae61709f5e1e8cf99") + + depends_on("py-setuptools", type="build") + + depends_on("py-pandas", type=("build", "run")) + depends_on("py-numpy", type=("build", "run")) + depends_on("py-scipy@0.18:", type=("build", "run")) + depends_on("py-tqdm", type=("build", "run")) + depends_on("py-joblib", type=("build", "run")) + depends_on("py-click", type=("build", "run")) + depends_on("py-matplotlib", type=("build", "run")) From 2a516aadb1164b9fc617d9a84584a948a80b8800 Mon Sep 17 00:00:00 2001 From: Weiqun Zhang Date: Wed, 2 Nov 2022 11:59:50 -0700 Subject: [PATCH 312/442] amrex: add v22.11 (#33671) --- var/spack/repos/builtin/packages/amrex/package.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/amrex/package.py b/var/spack/repos/builtin/packages/amrex/package.py index b41bd126fad..55281ccbaaf 100644 --- a/var/spack/repos/builtin/packages/amrex/package.py +++ b/var/spack/repos/builtin/packages/amrex/package.py @@ -14,7 +14,7 @@ class Amrex(CMakePackage, CudaPackage, ROCmPackage): mesh refinement (AMR) applications.""" homepage = "https://amrex-codes.github.io/amrex/" - url = "https://github.com/AMReX-Codes/amrex/releases/download/22.10/amrex-22.10.tar.gz" + url = "https://github.com/AMReX-Codes/amrex/releases/download/22.11/amrex-22.11.tar.gz" git = "https://github.com/AMReX-Codes/amrex.git" test_requires_compiler = True @@ -24,6 +24,7 @@ class Amrex(CMakePackage, CudaPackage, ROCmPackage): maintainers = ["WeiqunZhang", "asalmgren", "etpalmer63"] version("develop", branch="development") + version("22.11", sha256="8be9d5c6934d73b98c71c9c67ca7113f18794268f257333591d9b2449d7410c4") version("22.10", sha256="458da410d7f43e428726bfc905123e85d05786080f892ebaa26f94c5f8e79b07") version("22.09", sha256="24601fbb9d554f7b66d7db89b14ff95dadb18d51db893af7ee6c70d4b7dd4be6") version("22.08", sha256="d89167c4567fa246b06478a5b160010a0117dc58be9e879beb15be53cb08b6e9") From 4c535a2037826e66e4b112a069b3723b6baf893f Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 2 Nov 2022 20:23:19 +0100 Subject: [PATCH 313/442] update: damask3.0.0-alpha7 (#33634) * damask3.0.0-alpha7 * [@spackbot] updating style on behalf of MarDiehl Co-authored-by: MarDiehl --- .../packages/damask-grid/long-lines.patch | 21 +++++++++++++++++++ .../builtin/packages/damask-grid/package.py | 9 +++++++- .../packages/damask-mesh/long-lines.patch | 21 +++++++++++++++++++ .../builtin/packages/damask-mesh/package.py | 6 ++++++ .../repos/builtin/packages/damask/package.py | 5 +++++ .../builtin/packages/py-damask/package.py | 5 +++++ .../builtin/packages/py-damask/setup.patch | 11 ++++++++++ 7 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 var/spack/repos/builtin/packages/damask-grid/long-lines.patch create mode 100644 var/spack/repos/builtin/packages/damask-mesh/long-lines.patch create mode 100644 var/spack/repos/builtin/packages/py-damask/setup.patch diff --git a/var/spack/repos/builtin/packages/damask-grid/long-lines.patch b/var/spack/repos/builtin/packages/damask-grid/long-lines.patch new file mode 100644 index 00000000000..b3e0f962ab4 --- /dev/null +++ b/var/spack/repos/builtin/packages/damask-grid/long-lines.patch @@ -0,0 +1,21 @@ +--- damask.orig/src/CMakeLists.txt 2022-10-10 11:15:50.430977247 +0200 ++++ damask/src/CMakeLists.txt 2022-10-10 11:26:53.792092659 +0200 +@@ -2,6 +2,9 @@ + if(CMAKE_Fortran_COMPILER_ID STREQUAL "GNU") + # long lines for interaction matrix + set_source_files_properties("lattice.f90" PROPERTIES COMPILE_FLAGS "-ffree-line-length-240") ++ # CHKERRQ PETSc macro ++ set_source_files_properties("parallelization.f90" PROPERTIES COMPILE_FLAGS "-ffree-line-length-none") ++ set_source_files_properties("quit.f90" PROPERTIES COMPILE_FLAGS "-ffree-line-length-none") + endif() + + file(GLOB damask-sources CONFIGURE_DEPENDS *.f90 *.c) +@@ -18,7 +21,7 @@ + file(READ ${solver-source} content) + string(FIND "${content}" "CHKERR" found) + if(NOT ${found} EQUAL -1) +- set_source_files_properties(${solver-source} PROPERTIES COMPILE_FLAGS "-ffree-line-length-160") ++ set_source_files_properties(${solver-source} PROPERTIES COMPILE_FLAGS "-ffree-line-length-none") + endif() + endforeach() + diff --git a/var/spack/repos/builtin/packages/damask-grid/package.py b/var/spack/repos/builtin/packages/damask-grid/package.py index 1f62e857617..29fc78a99a4 100644 --- a/var/spack/repos/builtin/packages/damask-grid/package.py +++ b/var/spack/repos/builtin/packages/damask-grid/package.py @@ -15,6 +15,9 @@ class DamaskGrid(CMakePackage): maintainers = ["MarDiehl"] + version( + "3.0.0-alpha7", sha256="442b06b824441293e72ff91b211a555c5d497aedf62be1c4332c426558b848a4" + ) version( "3.0.0-alpha6", sha256="de6748c285558dec8f730c4301bfa56b4078c130ff80e3095faf76202f8d2109" ) @@ -25,15 +28,19 @@ class DamaskGrid(CMakePackage): "3.0.0-alpha4", sha256="0bb8bde43b27d852b1fb6e359a7157354544557ad83d87987b03f5d629ce5493" ) + depends_on("petsc@3.17.1:3.18", when="@3.0.0-alpha7") depends_on("petsc@3.16.5:3.16", when="@3.0.0-alpha6") depends_on("petsc@3.14.0:3.14,3.15.1:3.16", when="@3.0.0-alpha5") depends_on("petsc@3.14.0:3.14,3.15.1:3.15", when="@3.0.0-alpha4") depends_on("pkgconfig", type="build") depends_on("cmake@3.10:", type="build") depends_on("petsc+mpi+hdf5") + depends_on("hdf5@1.12:+mpi+fortran", when="@3.0.0-alpha7:") depends_on("hdf5@1.10:+mpi+fortran") depends_on("fftw+mpi") + depends_on("libfyaml", when="@3.0.0-alpha7:") + patch("long-lines.patch", when="@3.0.0-alpha7") patch("CMakeDebugRelease.patch", when="@3.0.0-alpha4") variant( @@ -44,7 +51,7 @@ class DamaskGrid(CMakePackage): ) def patch(self): - filter_file(" -lz ", " -lz ${FFTW_LIBS} ", "CMakeLists.txt") + filter_file(" -lz", " -lz ${FFTW_LIBS}", "CMakeLists.txt") def cmake_args(self): return [ diff --git a/var/spack/repos/builtin/packages/damask-mesh/long-lines.patch b/var/spack/repos/builtin/packages/damask-mesh/long-lines.patch new file mode 100644 index 00000000000..b3e0f962ab4 --- /dev/null +++ b/var/spack/repos/builtin/packages/damask-mesh/long-lines.patch @@ -0,0 +1,21 @@ +--- damask.orig/src/CMakeLists.txt 2022-10-10 11:15:50.430977247 +0200 ++++ damask/src/CMakeLists.txt 2022-10-10 11:26:53.792092659 +0200 +@@ -2,6 +2,9 @@ + if(CMAKE_Fortran_COMPILER_ID STREQUAL "GNU") + # long lines for interaction matrix + set_source_files_properties("lattice.f90" PROPERTIES COMPILE_FLAGS "-ffree-line-length-240") ++ # CHKERRQ PETSc macro ++ set_source_files_properties("parallelization.f90" PROPERTIES COMPILE_FLAGS "-ffree-line-length-none") ++ set_source_files_properties("quit.f90" PROPERTIES COMPILE_FLAGS "-ffree-line-length-none") + endif() + + file(GLOB damask-sources CONFIGURE_DEPENDS *.f90 *.c) +@@ -18,7 +21,7 @@ + file(READ ${solver-source} content) + string(FIND "${content}" "CHKERR" found) + if(NOT ${found} EQUAL -1) +- set_source_files_properties(${solver-source} PROPERTIES COMPILE_FLAGS "-ffree-line-length-160") ++ set_source_files_properties(${solver-source} PROPERTIES COMPILE_FLAGS "-ffree-line-length-none") + endif() + endforeach() + diff --git a/var/spack/repos/builtin/packages/damask-mesh/package.py b/var/spack/repos/builtin/packages/damask-mesh/package.py index 3507dfdff8a..7e9590fcea5 100644 --- a/var/spack/repos/builtin/packages/damask-mesh/package.py +++ b/var/spack/repos/builtin/packages/damask-mesh/package.py @@ -15,6 +15,9 @@ class DamaskMesh(CMakePackage): maintainers = ["MarDiehl"] + version( + "3.0.0-alpha7", sha256="442b06b824441293e72ff91b211a555c5d497aedf62be1c4332c426558b848a4" + ) version( "3.0.0-alpha6", sha256="de6748c285558dec8f730c4301bfa56b4078c130ff80e3095faf76202f8d2109" ) @@ -25,13 +28,16 @@ class DamaskMesh(CMakePackage): "3.0.0-alpha4", sha256="0bb8bde43b27d852b1fb6e359a7157354544557ad83d87987b03f5d629ce5493" ) + depends_on("petsc@3.17.1:3.18", when="@3.0.0-alpha7") depends_on("petsc@3.16.5:3.16", when="@3.0.0-alpha6") depends_on("petsc@3.14.0:3.14,3.15.1:3.16", when="@3.0.0-alpha5") depends_on("petsc@3.14.0:3.14,3.15.1:3.15", when="@3.0.0-alpha4") depends_on("pkgconfig", type="build") depends_on("cmake@3.10:", type="build") depends_on("petsc+mpi+hdf5") + depends_on("hdf5@1.12:+mpi+fortran", when="@3.0.0-alpha7:") depends_on("hdf5@1.10:+mpi+fortran") + depends_on("libfyaml", when="@3.0.0-alpha7:") patch("CMakeDebugRelease.patch", when="@3.0.0-alpha4") diff --git a/var/spack/repos/builtin/packages/damask/package.py b/var/spack/repos/builtin/packages/damask/package.py index 849d7acd1a1..953e82912ac 100644 --- a/var/spack/repos/builtin/packages/damask/package.py +++ b/var/spack/repos/builtin/packages/damask/package.py @@ -28,10 +28,15 @@ class Damask(BundlePackage): maintainers = ["MarDiehl"] + version("3.0.0-alpha7") version("3.0.0-alpha6") version("3.0.0-alpha5") version("3.0.0-alpha4") + depends_on("damask-grid@3.0.0-alpha7", when="@3.0.0-alpha7", type="run") + depends_on("damask-mesh@3.0.0-alpha7", when="@3.0.0-alpha7", type="run") + depends_on("py-damask@3.0.0-alpha7", when="@3.0.0-alpha7", type="run") + depends_on("damask-grid@3.0.0-alpha6", when="@3.0.0-alpha6", type="run") depends_on("damask-mesh@3.0.0-alpha6", when="@3.0.0-alpha6", type="run") depends_on("py-damask@3.0.0-alpha6", when="@3.0.0-alpha6", type="run") diff --git a/var/spack/repos/builtin/packages/py-damask/package.py b/var/spack/repos/builtin/packages/py-damask/package.py index 659a3b3bc53..e7b44821bfd 100644 --- a/var/spack/repos/builtin/packages/py-damask/package.py +++ b/var/spack/repos/builtin/packages/py-damask/package.py @@ -15,6 +15,9 @@ class PyDamask(PythonPackage): maintainers = ["MarDiehl"] + version( + "3.0.0-alpha7", sha256="442b06b824441293e72ff91b211a555c5d497aedf62be1c4332c426558b848a4" + ) version( "3.0.0-alpha6", sha256="de6748c285558dec8f730c4301bfa56b4078c130ff80e3095faf76202f8d2109" ) @@ -35,4 +38,6 @@ class PyDamask(PythonPackage): depends_on("py-matplotlib", type=("build", "run")) depends_on("py-pyyaml", type=("build", "run")) + patch("setup.patch", when="@3.0.0-alpha7") + build_directory = "python" diff --git a/var/spack/repos/builtin/packages/py-damask/setup.patch b/var/spack/repos/builtin/packages/py-damask/setup.patch new file mode 100644 index 00000000000..e30bcefeefa --- /dev/null +++ b/var/spack/repos/builtin/packages/py-damask/setup.patch @@ -0,0 +1,11 @@ +--- damask.orig/python/setup.cfg 2022-10-10 11:34:22.934631052 +0200 ++++ damask/python/setup.cfg 2022-10-10 11:54:32.197194977 +0200 +@@ -6,7 +6,7 @@ + url = https://damask.mpie.de + description = DAMASK processing tools + long_description = Pre- and post-processing tools for DAMASK +-license: AGPL3 ++license = AGPL3 + classifiers = + Intended Audience :: Science/Research + Topic :: Scientific/Engineering From 4d5f2e3a37f3b871c0a6c17ac60274a2ce5529f3 Mon Sep 17 00:00:00 2001 From: Robert Pavel Date: Wed, 2 Nov 2022 15:10:19 -0600 Subject: [PATCH 314/442] Initial Version of Hypar Spackage (#33647) Initial spackage for Hypar proxy app --- .../repos/builtin/packages/hypar/package.py | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 var/spack/repos/builtin/packages/hypar/package.py diff --git a/var/spack/repos/builtin/packages/hypar/package.py b/var/spack/repos/builtin/packages/hypar/package.py new file mode 100644 index 00000000000..fc50e626d71 --- /dev/null +++ b/var/spack/repos/builtin/packages/hypar/package.py @@ -0,0 +1,63 @@ +# 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 Hypar(AutotoolsPackage): + """ + HyPar is a finite-difference algorithm to solve hyperbolic-parabolic partial differential + equations (with source terms) on Cartesian grids. It is a unified framework that can handle + systems of PDEs with arbitrary number of spatial dimensions and solution components. It + provides the spatial discretization and time integration functions, functions to read and + write solutions from/to files, as well as functions required to solve the system on parallel + (MPI) platforms. The physical models define the physics-specific functions such as the exact + forms of the hyperbolic flux, parabolic flux, source terms, upwinding functions, etc. + """ + + homepage = "http://hypar.github.io/" + url = "https://bitbucket.org/deboghosh/hypar/get/v4.1.tar.gz" + git = "https://bitbucket.org/deboghosh/hypar.git" + + maintainers = ["debog"] + + tags = ["proxy-app", "ecp-proxy-app"] + + version("4.1", sha256="36c11dcfda006115f4656ff73790992e5caea99dbc64776c9db4e0a29b4c60da") + + variant("mpi", default=True, description="Build with MPI support") + variant("openmp", default=False, description="Build with OpenMP support") + variant("scalapack", default=False, description="Build with Scalapack Support") + variant("fftw", default=False, description="Build with FFTW support") + + depends_on("autoconf", type="build") + depends_on("automake", type="build") + depends_on("libtool", type="build") + + depends_on("mpi", when="+mpi") + depends_on("scalapack", when="+scalapack") + depends_on("blas", when="+scalapack") + depends_on("lapack", when="+scalapack") + depends_on("fftw", when="+fftw") + + patch_config_files = False + + def configure_args(self): + args = [] + spec = self.spec + if "+mpi" in spec: + args.append("--enable-mpi") + args.append("--with-mpi-dir={0}".format(spec["mpi"].prefix)) + if "+openmp" in spec: + args.append("--enable-omp") + if "+scalapack" in spec: + args.append("--enable-scalapack") + args.append("--with-blas-dir={0}".format(spec["blas"].prefix)) + args.append("--with-lapack-dir={0}".format(spec["lapack"].prefix)) + args.append("--with-scalapack-dir={0}".format(spec["scalapack"].prefix)) + if "+fftw" in spec: + args.append("--enable-fftw") + args.append("--with-fftw-dir={0}".format(spec["fftw"].prefix)) + return args From b652fe72d7a55150813c6ffbb68e9c724737fc0a Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Wed, 2 Nov 2022 22:24:59 +0100 Subject: [PATCH 315/442] remove `deptype_query` remnants and fix incorrect `deptypes` kwarg (#33670) * remove deptype_query remnants * deptypes -> deptype These arguments haven't existed since 2017, but `traverse` now fails on unknown **kwargs, so they have finally popped up. --- lib/spack/spack/build_systems/lua.py | 2 +- var/spack/repos/builtin/packages/lua/package.py | 2 +- var/spack/repos/builtin/packages/perl/package.py | 8 ++++---- var/spack/repos/builtin/packages/r/package.py | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/spack/spack/build_systems/lua.py b/lib/spack/spack/build_systems/lua.py index f1c3e43704a..722e9153f98 100644 --- a/lib/spack/spack/build_systems/lua.py +++ b/lib/spack/spack/build_systems/lua.py @@ -76,7 +76,7 @@ def _generate_tree_line(name, prefix): def generate_luarocks_config(self, pkg, spec, prefix): spec = self.pkg.spec table_entries = [] - for d in spec.traverse(deptypes=("build", "run"), deptype_query="run"): + for d in spec.traverse(deptype=("build", "run")): if d.package.extends(self.pkg.extendee_spec): table_entries.append(self._generate_tree_line(d.name, d.prefix)) diff --git a/var/spack/repos/builtin/packages/lua/package.py b/var/spack/repos/builtin/packages/lua/package.py index 4894ab2b91f..d04d2036d31 100644 --- a/var/spack/repos/builtin/packages/lua/package.py +++ b/var/spack/repos/builtin/packages/lua/package.py @@ -115,7 +115,7 @@ def append_paths(self, paths, cpaths, path): def _setup_dependent_env_helper(self, env, dependent_spec): lua_paths = [] - for d in dependent_spec.traverse(deptypes=("build", "run"), deptype_query="run"): + for d in dependent_spec.traverse(deptype=("build", "run")): if d.package.extends(self.spec): lua_paths.append(os.path.join(d.prefix, self.lua_lib_dir)) lua_paths.append(os.path.join(d.prefix, self.lua_lib64_dir)) diff --git a/var/spack/repos/builtin/packages/perl/package.py b/var/spack/repos/builtin/packages/perl/package.py index d7b32543fde..b268c86f2b5 100644 --- a/var/spack/repos/builtin/packages/perl/package.py +++ b/var/spack/repos/builtin/packages/perl/package.py @@ -355,12 +355,12 @@ def install_cpanm(self): maker() maker("install") - def _setup_dependent_env(self, env, dependent_spec, deptypes): + def _setup_dependent_env(self, env, dependent_spec, deptype): """Set PATH and PERL5LIB to include the extension and any other perl extensions it depends on, assuming they were installed with INSTALL_BASE defined.""" perl_lib_dirs = [] - for d in dependent_spec.traverse(deptype=deptypes): + for d in dependent_spec.traverse(deptype=deptype): if d.package.extends(self.spec): perl_lib_dirs.append(d.prefix.lib.perl5) if perl_lib_dirs: @@ -370,10 +370,10 @@ def _setup_dependent_env(self, env, dependent_spec, deptypes): env.append_path("PATH", self.prefix.bin) def setup_dependent_build_environment(self, env, dependent_spec): - self._setup_dependent_env(env, dependent_spec, deptypes=("build", "run", "test")) + self._setup_dependent_env(env, dependent_spec, deptype=("build", "run", "test")) def setup_dependent_run_environment(self, env, dependent_spec): - self._setup_dependent_env(env, dependent_spec, deptypes=("run",)) + self._setup_dependent_env(env, dependent_spec, deptype=("run",)) def setup_dependent_package(self, module, dependent_spec): """Called before perl modules' install() methods. diff --git a/var/spack/repos/builtin/packages/r/package.py b/var/spack/repos/builtin/packages/r/package.py index ffae98f8ef3..af5d740b128 100644 --- a/var/spack/repos/builtin/packages/r/package.py +++ b/var/spack/repos/builtin/packages/r/package.py @@ -198,7 +198,7 @@ def setup_dependent_build_environment(self, env, dependent_spec): # Set R_LIBS to include the library dir for the # extension and any other R extensions it depends on. r_libs_path = [] - for d in dependent_spec.traverse(deptype=("build", "run"), deptype_query="run"): + for d in dependent_spec.traverse(deptype=("build", "run")): if d.package.extends(self.spec): r_libs_path.append(join_path(d.prefix, self.r_lib_dir)) From c716c6ca95e300ac247f668237fc13f75e1b5289 Mon Sep 17 00:00:00 2001 From: Greg Becker Date: Wed, 2 Nov 2022 21:09:43 -0700 Subject: [PATCH 316/442] Bugfix for spec objects modified by flag handlers (#33682) This issue was introduced in #29761: ``` ==> Installing ncurses-6.3-22hz6q6cvo3ep2uhrs3erpp2kogxncbn ==> No binary for ncurses-6.3-22hz6q6cvo3ep2uhrs3erpp2kogxncbn found: installing from source ==> Using cached archive: /spack/var/spack/cache/_source-cache/archive/97/97fc51ac2b085d4cde31ef4d2c3122c21abc217e9090a43a30fc5ec21684e059.tar.gz ==> No patches needed for ncurses ==> ncurses: Executing phase: 'autoreconf' ==> ncurses: Executing phase: 'configure' ==> ncurses: Executing phase: 'build' ==> ncurses: Executing phase: 'install' ==> Error: AttributeError: 'str' object has no attribute 'propagate' The 'ncurses' package cannot find an attribute while trying to build from sources. This might be due to a change in Spack's package format to support multiple build-systems for a single package. You can fix this by updating the build recipe, and you can also report the issue as a bug. More information at https://spack.readthedocs.io/en/latest/packaging_guide.html#installation-procedure /spack/lib/spack/spack/build_environment.py:1075, in _setup_pkg_and_run: 1072 tb_string = traceback.format_exc() 1073 1074 # build up some context from the offending package so we can >> 1075 # show that, too. 1076 package_context = get_package_context(tb) 1077 1078 logfile = None ``` It turns out this was caused by a bug that had been around much longer, in which the flags were passed by reference to the flag_handler, and the flag_handler was modifying the spec object, not just the flags given to the build system. The scope of this bug was limited by the forking model in Spack, which is how it went under the radar for so long. PR includes regression test. --- lib/spack/spack/build_environment.py | 2 +- lib/spack/spack/test/flag_handlers.py | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py index 9fe7c1fbb7c..463c4dcde7a 100644 --- a/lib/spack/spack/build_environment.py +++ b/lib/spack/spack/build_environment.py @@ -346,7 +346,7 @@ def set_compiler_environment_variables(pkg, env): handler = pkg.flag_handler.__func__ else: handler = pkg.flag_handler.im_func - injf, envf, bsf = handler(pkg, flag, spec.compiler_flags[flag]) + injf, envf, bsf = handler(pkg, flag, spec.compiler_flags[flag][:]) inject_flags[flag] = injf or [] env_flags[flag] = envf or [] build_system_flags[flag] = bsf or [] diff --git a/lib/spack/spack/test/flag_handlers.py b/lib/spack/spack/test/flag_handlers.py index d55a059769e..3b871a2bc97 100644 --- a/lib/spack/spack/test/flag_handlers.py +++ b/lib/spack/spack/test/flag_handlers.py @@ -135,3 +135,15 @@ def test_ld_libs_cmake(self, temp_env): "-DCMAKE_CXX_STANDARD_LIBRARIES=-lfoo", "-DCMAKE_Fortran_STANDARD_LIBRARIES=-lfoo", } + + def test_flag_handler_no_modify_specs(self, temp_env): + def test_flag_handler(self, name, flags): + flags.append("-foo") + return (flags, None, None) + + s = spack.spec.Spec("cmake-client").concretized() + s.package.flag_handler = test_flag_handler + spack.build_environment.setup_package(s.package, False) + + assert not s.compiler_flags["cflags"] + assert os.environ["SPACK_CFLAGS"] == "-foo" From 2264b75ca0ffceabb55e0306e76260dc4f5f1360 Mon Sep 17 00:00:00 2001 From: Sinan Date: Wed, 2 Nov 2022 21:38:17 -0700 Subject: [PATCH 317/442] add new package: py-pylatex (#33573) * add new package: py-pylatex * fix bugs * add extras indicated in setup.py * Update var/spack/repos/builtin/packages/py-pylatex/package.py Co-authored-by: Adam J. Stewart * Update var/spack/repos/builtin/packages/py-pylatex/package.py Co-authored-by: Adam J. Stewart * improvements * remove git merge related lines * tidy * Update var/spack/repos/builtin/packages/py-pylatex/package.py Co-authored-by: Adam J. Stewart * remove variant * [@spackbot] updating style on behalf of Sinan81 Co-authored-by: sbulut Co-authored-by: Adam J. Stewart Co-authored-by: Sinan81 --- .../builtin/packages/py-pylatex/package.py | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 var/spack/repos/builtin/packages/py-pylatex/package.py diff --git a/var/spack/repos/builtin/packages/py-pylatex/package.py b/var/spack/repos/builtin/packages/py-pylatex/package.py new file mode 100644 index 00000000000..c55cf6c870b --- /dev/null +++ b/var/spack/repos/builtin/packages/py-pylatex/package.py @@ -0,0 +1,35 @@ +# 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 PyPylatex(PythonPackage): + """A Python library for creating LaTeX files and snippets""" + + homepage = "https://github.com/JelteF/PyLaTeX" + pypi = "PyLaTeX/PyLaTeX-1.4.1.tar.gz" + + version("1.4.1", sha256="d3c12efb8b260771260443dce78d1e9089c09f9d0b92e6273dfca0bf5e7302fb") + + variant("docs", default=False, description="Build with Sphinx support for documentation") + variant("matrices", default=False, description="Build with matrix support") + variant("matplotlib", default=False, description="Build with matplotlib support") + variant("quantities", default=False, description="Build with quantities support") + + depends_on("python@2.7,3.3:", type=("build", "run")) + depends_on("py-setuptools", type="build") + depends_on("py-setuptools@:57", type="build", when="@:1.4.1") + depends_on("py-ordered-set", type=("build", "run")) + + # from extras section in setup.py + depends_on("py-future@0.15.2:", type=("build", "run"), when="^python@:2") + depends_on("py-sphinx", type="run", when="+docs") + depends_on("py-matplotlib", type="run", when="+matplotlib") + depends_on("py-numpy", type="run", when="+matrices") + depends_on("py-numpy", type="run", when="+quantities") + depends_on("py-quantities", type="run", when="+quantities") + + depends_on("texlive", type="run") From 707e56dea84f5842f8ee4a7cc8052bb459f407ad Mon Sep 17 00:00:00 2001 From: Michael Kuhn Date: Thu, 3 Nov 2022 09:50:20 +0100 Subject: [PATCH 318/442] glib: add 2.74.1 (#33650) --- var/spack/repos/builtin/packages/glib/package.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/glib/package.py b/var/spack/repos/builtin/packages/glib/package.py index a7d9c43ef6a..a0f29cb87be 100644 --- a/var/spack/repos/builtin/packages/glib/package.py +++ b/var/spack/repos/builtin/packages/glib/package.py @@ -23,6 +23,7 @@ class Glib(Package): maintainers = ["michaelkuhn"] + version("2.74.1", sha256="0ab981618d1db47845e56417b0d7c123f81a3427b2b9c93f5a46ff5bbb964964") version("2.74.0", sha256="3652c7f072d7b031a6b5edd623f77ebc5dcd2ae698598abcc89ff39ca75add30") version("2.72.4", sha256="8848aba518ba2f4217d144307a1d6cb9afcc92b54e5c13ac1f8c4d4608e96f0e") version("2.72.3", sha256="4a39a2f624b8512d500d5840173eda7fa85f51c109052eae806acece85d345f0") @@ -121,7 +122,8 @@ class Glib(Package): depends_on("gettext") depends_on("perl", type=("build", "run")) depends_on("python", type=("build", "run"), when="@2.53.4:") - depends_on("pcre+utf", when="@2.48:") + depends_on("pcre2", when="@2.73.2:") + depends_on("pcre+utf", when="@2.48:2.73.1") depends_on("uuid", when="+libmount") depends_on("util-linux", when="+libmount") depends_on("iconv") From 0d82688903d5cbb3273fdbe5a9c6be36e4499165 Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Thu, 3 Nov 2022 10:05:03 +0100 Subject: [PATCH 319/442] Update metadata for bootstrapping (#33665) --- .github/workflows/bootstrap.yml | 6 + etc/spack/defaults/bootstrap.yaml | 7 +- lib/spack/docs/getting_started.rst | 61 +--- lib/spack/spack/cmd/bootstrap.py | 10 +- lib/spack/spack/test/cmd/bootstrap.py | 2 +- .../spack/test/data/config/bootstrap.yaml | 2 +- .../bootstrap/github-actions-v0.1/clingo.json | 257 -------------- .../bootstrap/github-actions-v0.1/gnupg.json | 204 ----------- .../github-actions-v0.1/metadata.yaml | 8 - .../bootstrap/github-actions-v0.2/clingo.json | 268 -------------- .../bootstrap/github-actions-v0.2/gnupg.json | 204 ----------- .../bootstrap/github-actions-v0.3/clingo.json | 269 +++++++++++++- .../bootstrap/github-actions-v0.3/gnupg.json | 205 ++++++++++- .../bootstrap/github-actions-v0.4/clingo.json | 334 ++++++++++++++++++ .../bootstrap/github-actions-v0.4/gnupg.json | 254 +++++++++++++ .../metadata.yaml | 2 +- .../github-actions-v0.4/patchelf.json | 34 ++ 17 files changed, 1128 insertions(+), 999 deletions(-) delete mode 100644 share/spack/bootstrap/github-actions-v0.1/clingo.json delete mode 100644 share/spack/bootstrap/github-actions-v0.1/gnupg.json delete mode 100644 share/spack/bootstrap/github-actions-v0.1/metadata.yaml delete mode 100644 share/spack/bootstrap/github-actions-v0.2/clingo.json delete mode 100644 share/spack/bootstrap/github-actions-v0.2/gnupg.json mode change 120000 => 100644 share/spack/bootstrap/github-actions-v0.3/clingo.json mode change 120000 => 100644 share/spack/bootstrap/github-actions-v0.3/gnupg.json create mode 100644 share/spack/bootstrap/github-actions-v0.4/clingo.json create mode 100644 share/spack/bootstrap/github-actions-v0.4/gnupg.json rename share/spack/bootstrap/{github-actions-v0.2 => github-actions-v0.4}/metadata.yaml (83%) create mode 100644 share/spack/bootstrap/github-actions-v0.4/patchelf.json diff --git a/.github/workflows/bootstrap.yml b/.github/workflows/bootstrap.yml index bdaefbfc3db..df2b0f346e1 100644 --- a/.github/workflows/bootstrap.yml +++ b/.github/workflows/bootstrap.yml @@ -42,6 +42,7 @@ jobs: shell: runuser -u spack-test -- bash {0} run: | source share/spack/setup-env.sh + spack bootstrap disable github-actions-v0.4 spack bootstrap disable github-actions-v0.3 spack external find cmake bison spack -d solve zlib @@ -79,6 +80,7 @@ jobs: shell: runuser -u spack-test -- bash {0} run: | source share/spack/setup-env.sh + spack bootstrap disable github-actions-v0.4 spack bootstrap disable github-actions-v0.3 spack external find cmake bison spack -d solve zlib @@ -143,6 +145,7 @@ jobs: - name: Bootstrap clingo run: | source share/spack/setup-env.sh + spack bootstrap disable github-actions-v0.4 spack bootstrap disable github-actions-v0.3 spack external find cmake bison spack -d solve zlib @@ -160,6 +163,7 @@ jobs: run: | source share/spack/setup-env.sh export PATH=/usr/local/opt/bison@2.7/bin:$PATH + spack bootstrap disable github-actions-v0.4 spack bootstrap disable github-actions-v0.3 spack external find --not-buildable cmake bison spack -d solve zlib @@ -298,6 +302,7 @@ jobs: run: | source share/spack/setup-env.sh spack solve zlib + spack bootstrap disable github-actions-v0.4 spack bootstrap disable github-actions-v0.3 spack -d gpg list tree ~/.spack/bootstrap/store/ @@ -333,6 +338,7 @@ jobs: run: | source share/spack/setup-env.sh spack solve zlib + spack bootstrap disable github-actions-v0.4 spack bootstrap disable github-actions-v0.3 spack -d gpg list tree ~/.spack/bootstrap/store/ diff --git a/etc/spack/defaults/bootstrap.yaml b/etc/spack/defaults/bootstrap.yaml index a4a9b23515f..464994d171e 100644 --- a/etc/spack/defaults/bootstrap.yaml +++ b/etc/spack/defaults/bootstrap.yaml @@ -9,16 +9,15 @@ bootstrap: # may not be able to bootstrap all the software that Spack needs, # depending on its type. sources: + - name: 'github-actions-v0.4' + metadata: $spack/share/spack/bootstrap/github-actions-v0.4 - name: 'github-actions-v0.3' metadata: $spack/share/spack/bootstrap/github-actions-v0.3 - - name: 'github-actions-v0.2' - metadata: $spack/share/spack/bootstrap/github-actions-v0.2 - - name: 'github-actions-v0.1' - metadata: $spack/share/spack/bootstrap/github-actions-v0.1 - name: 'spack-install' metadata: $spack/share/spack/bootstrap/spack-install trusted: # By default we trust bootstrapping from sources and from binaries # produced on Github via the workflow + github-actions-v0.4: true github-actions-v0.3: true spack-install: true diff --git a/lib/spack/docs/getting_started.rst b/lib/spack/docs/getting_started.rst index 2fc43906a95..f923f4e9da3 100644 --- a/lib/spack/docs/getting_started.rst +++ b/lib/spack/docs/getting_started.rst @@ -124,61 +124,36 @@ Spack provides two ways of bootstrapping ``clingo``: from pre-built binaries (default), or from sources. The fastest way to get started is to bootstrap from pre-built binaries. -.. note:: - - When bootstrapping from pre-built binaries, Spack currently requires - ``patchelf`` on Linux and ``otool`` on macOS. If ``patchelf`` is not in the - ``PATH``, Spack will build it from sources, and a C++ compiler is required. - -The first time you concretize a spec, Spack will bootstrap in the background: +The first time you concretize a spec, Spack will bootstrap automatically: .. code-block:: console - $ time spack spec zlib + $ spack spec zlib + ==> Bootstrapping clingo from pre-built binaries + ==> Fetching https://mirror.spack.io/bootstrap/github-actions/v0.4/build_cache/linux-centos7-x86_64-gcc-10.2.1-clingo-bootstrap-spack-ba5ijauisd3uuixtmactc36vps7yfsrl.spec.json + ==> Fetching https://mirror.spack.io/bootstrap/github-actions/v0.4/build_cache/linux-centos7-x86_64/gcc-10.2.1/clingo-bootstrap-spack/linux-centos7-x86_64-gcc-10.2.1-clingo-bootstrap-spack-ba5ijauisd3uuixtmactc36vps7yfsrl.spack + ==> Installing "clingo-bootstrap@spack%gcc@10.2.1~docs~ipo+python+static_libstdcpp build_type=Release arch=linux-centos7-x86_64" from a buildcache + ==> Bootstrapping patchelf from pre-built binaries + ==> Fetching https://mirror.spack.io/bootstrap/github-actions/v0.4/build_cache/linux-centos7-x86_64-gcc-10.2.1-patchelf-0.16.1-p72zyan5wrzuabtmzq7isa5mzyh6ahdp.spec.json + ==> Fetching https://mirror.spack.io/bootstrap/github-actions/v0.4/build_cache/linux-centos7-x86_64/gcc-10.2.1/patchelf-0.16.1/linux-centos7-x86_64-gcc-10.2.1-patchelf-0.16.1-p72zyan5wrzuabtmzq7isa5mzyh6ahdp.spack + ==> Installing "patchelf@0.16.1%gcc@10.2.1 ldflags="-static-libstdc++ -static-libgcc" build_system=autotools arch=linux-centos7-x86_64" from a buildcache Input spec -------------------------------- zlib Concretized -------------------------------- - zlib@1.2.11%gcc@7.5.0+optimize+pic+shared arch=linux-ubuntu18.04-zen - - real 0m20.023s - user 0m18.351s - sys 0m0.784s - -After this command you'll see that ``clingo`` has been installed for Spack's own use: - -.. code-block:: console - - $ spack find -b - ==> Showing internal bootstrap store at "/root/.spack/bootstrap/store" - ==> 3 installed packages - -- linux-rhel5-x86_64 / gcc@9.3.0 ------------------------------- - clingo-bootstrap@spack python@3.6 - - -- linux-ubuntu18.04-zen / gcc@7.5.0 ---------------------------- - patchelf@0.13 - -Subsequent calls to the concretizer will then be much faster: - -.. code-block:: console - - $ time spack spec zlib - [ ... ] - real 0m0.490s - user 0m0.431s - sys 0m0.041s - + zlib@1.2.13%gcc@9.4.0+optimize+pic+shared build_system=makefile arch=linux-ubuntu20.04-icelake If for security concerns you cannot bootstrap ``clingo`` from pre-built -binaries, you have to mark this bootstrapping method as untrusted. This makes -Spack fall back to bootstrapping from sources: +binaries, you have to disable fetching the binaries we generated with Github Actions. .. code-block:: console + $ spack bootstrap disable github-actions-v0.4 + ==> "github-actions-v0.4" is now disabled and will not be used for bootstrapping $ spack bootstrap disable github-actions-v0.3 - ==> "github-actions-v0.2" is now disabled and will not be used for bootstrapping + ==> "github-actions-v0.3" is now disabled and will not be used for bootstrapping You can verify that the new settings are effective with: @@ -213,9 +188,7 @@ under the ``${HOME}/.spack`` directory. The software installed there can be quer .. code-block:: console - $ spack find --bootstrap - ==> Showing internal bootstrap store at "/home/spack/.spack/bootstrap/store" - ==> 3 installed packages + $ spack -b find -- linux-ubuntu18.04-x86_64 / gcc@10.1.0 ------------------------ clingo-bootstrap@spack python@3.6.9 re2c@1.2.1 @@ -224,7 +197,7 @@ In case it's needed the bootstrap store can also be cleaned with: .. code-block:: console $ spack clean -b - ==> Removing software in "/home/spack/.spack/bootstrap/store" + ==> Removing bootstrapped software and configuration in "/home/spack/.spack/bootstrap" ^^^^^^^^^^^^^^^^^^ Check Installation diff --git a/lib/spack/spack/cmd/bootstrap.py b/lib/spack/spack/cmd/bootstrap.py index 1b398e4e5cd..9c07c826f73 100644 --- a/lib/spack/spack/cmd/bootstrap.py +++ b/lib/spack/spack/cmd/bootstrap.py @@ -30,7 +30,7 @@ # Tarball to be downloaded if binary packages are requested in a local mirror -BINARY_TARBALL = "https://github.com/spack/spack-bootstrap-mirrors/releases/download/v0.2/bootstrap-buildcache.tar.gz" +BINARY_TARBALL = "https://github.com/spack/spack-bootstrap-mirrors/releases/download/v0.4/bootstrap-buildcache.tar.gz" #: Subdirectory where to create the mirror LOCAL_MIRROR_DIR = "bootstrap_cache" @@ -50,8 +50,8 @@ }, } -CLINGO_JSON = "$spack/share/spack/bootstrap/github-actions-v0.2/clingo.json" -GNUPG_JSON = "$spack/share/spack/bootstrap/github-actions-v0.2/gnupg.json" +CLINGO_JSON = "$spack/share/spack/bootstrap/github-actions-v0.4/clingo.json" +GNUPG_JSON = "$spack/share/spack/bootstrap/github-actions-v0.4/gnupg.json" # Metadata for a generated source mirror SOURCE_METADATA = { @@ -449,10 +449,10 @@ def write_metadata(subdir, metadata): def _now(args): with spack.bootstrap.ensure_bootstrap_configuration(): - spack.bootstrap.ensure_clingo_importable_or_raise() - spack.bootstrap.ensure_gpg_in_path_or_raise() if platform.system().lower() == "linux": spack.bootstrap.ensure_patchelf_in_path_or_raise() + spack.bootstrap.ensure_clingo_importable_or_raise() + spack.bootstrap.ensure_gpg_in_path_or_raise() def bootstrap(parser, args): diff --git a/lib/spack/spack/test/cmd/bootstrap.py b/lib/spack/spack/test/cmd/bootstrap.py index 0eef7b3a7e8..81ba1e2cee9 100644 --- a/lib/spack/spack/test/cmd/bootstrap.py +++ b/lib/spack/spack/test/cmd/bootstrap.py @@ -168,7 +168,7 @@ def test_remove_and_add_a_source(mutable_config): assert not sources # Add it back and check we restored the initial state - _bootstrap("add", "github-actions", "$spack/share/spack/bootstrap/github-actions-v0.2") + _bootstrap("add", "github-actions", "$spack/share/spack/bootstrap/github-actions-v0.3") sources = spack.bootstrap.bootstrapping_sources() assert len(sources) == 1 diff --git a/lib/spack/spack/test/data/config/bootstrap.yaml b/lib/spack/spack/test/data/config/bootstrap.yaml index 8929d7ff35a..6adb7ab9967 100644 --- a/lib/spack/spack/test/data/config/bootstrap.yaml +++ b/lib/spack/spack/test/data/config/bootstrap.yaml @@ -1,5 +1,5 @@ bootstrap: sources: - name: 'github-actions' - metadata: $spack/share/spack/bootstrap/github-actions-v0.2 + metadata: $spack/share/spack/bootstrap/github-actions-v0.3 trusted: {} diff --git a/share/spack/bootstrap/github-actions-v0.1/clingo.json b/share/spack/bootstrap/github-actions-v0.1/clingo.json deleted file mode 100644 index 3068ad1f191..00000000000 --- a/share/spack/bootstrap/github-actions-v0.1/clingo.json +++ /dev/null @@ -1,257 +0,0 @@ -{ - "verified": [ - { - "binaries": [ - [ - "clingo-bootstrap", - "m4ertsh3ooxdisc5tigglublasu4udfe", - "094548672362306d75012398a6f9b1e8c0f796c833163ca77cf644d84822f25f" - ] - ], - "python": "python@3.5", - "spec": "clingo-bootstrap%apple-clang platform=darwin target=x86_64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "iv4gr5vscx2io23ljgdueybwatxlk6wo", - "c8110c68ec339d05155392818b21ba87b27905ad798f5f3f194d6312385dbdc2" - ] - ], - "python": "python@3.6", - "spec": "clingo-bootstrap%apple-clang platform=darwin target=x86_64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "rwxcxsohrkp5iai3yushsltkdprjmexb", - "fbee764cac890a29bc03c472d3ba0401e915d6924a7cedac9fd8d961159b70e7" - ] - ], - "python": "python@3.7", - "spec": "clingo-bootstrap%apple-clang platform=darwin target=x86_64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "p5on7i4hejl775ezndzfdkhvwra3hatn", - "35e32f7c1f80e99da450b52643800fd2895ee2f895109f708b5cf0da6afbedff" - ] - ], - "python": "python@3.8", - "spec": "clingo-bootstrap%apple-clang platform=darwin target=x86_64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "omsvlh5v6fi2saw5qyqvzsbvqpvrf5yw", - "cef0e554737dbf22655094d8ae072c67539cce2a37cba1577aeb5aea18b5747c" - ] - ], - "python": "python@3.9", - "spec": "clingo-bootstrap%apple-clang platform=darwin target=x86_64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "qguh44xegb72y4q4lar3ufjddissoumv", - "68d2d0c06690d75a794aa2c50be9d6d501fec1b566784bf87b1fc5611f84f3c9" - ] - ], - "python": "python@3.5", - "spec": "clingo-bootstrap%gcc platform=linux target=aarch64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "tsypkz7hyylmh5pwpykaf7wcmdunrdiv", - "3b8e3e6e21e399a90c4128776cc591734f9d533f0a7e64ed8babd9cbcf616e3d" - ] - ], - "python": "python@3.6", - "spec": "clingo-bootstrap%gcc platform=linux target=aarch64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "2w6b4q5j2zgra6t3zfrjfbvsnoi5yqmk", - "4f335e02641f6ecc7ec7d9d2b8293d07d6e7a7234034531713b760aaa507fa7c" - ] - ], - "python": "python@3.7", - "spec": "clingo-bootstrap%gcc platform=linux target=aarch64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "ij7udwpgeghdfoswljwdtwwaylvudze7", - "b5eedf593f198e523aebf6ce127fd8ffcf3d1c980a920cdf1c5a0d2a335e4892" - ] - ], - "python": "python@3.8", - "spec": "clingo-bootstrap%gcc platform=linux target=aarch64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "a5ppijpzmk7ubjem4i3zttbxp545vjuz", - "8f9755c16c0c99b5c40c420f2c1c6aec2bdff99b25444e001506527af18dd94e" - ] - ], - "python": "python@3.9", - "spec": "clingo-bootstrap%gcc platform=linux target=aarch64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "tsnva2bxjguosntz3tk5mqbdgrjvhfcc", - "bcd093c08110309e705beebccd012260a61215eda12c1d47f3a89d4734ec7170" - ] - ], - "python": "python@3.5", - "spec": "clingo-bootstrap%gcc platform=linux target=ppc64le" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "rfu4la457mdbpoffk2g5hikj2hhoek4s", - "b6417b9b90f3f4e98caaa869393edee08fad3d3c7db37fad8b332c785d0e81e6" - ] - ], - "python": "python@3.6", - "spec": "clingo-bootstrap%gcc platform=linux target=ppc64le" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "qg3utj2csbgtdwc2slqbjmwn25rkor5r", - "a1760e064d41d364cdf53f89248f7824dad9bf97c6b999df18343b57d21c06ed" - ] - ], - "python": "python@3.7", - "spec": "clingo-bootstrap%gcc platform=linux target=ppc64le" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "uxkpc2euofdkgveonftklstnxyha5wsf", - "d6a04e7b15dae05eacce54806fa18356b392a5e2d212a55bf0960116b8e9dfef" - ] - ], - "python": "python@3.8", - "spec": "clingo-bootstrap%gcc platform=linux target=ppc64le" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "i2uoawqsmmkr2uwb42oxfsnt4djzejrj", - "6511837f87e50c40a7f4aab2ec7454e5200594821e4d1fc4a441d3be647b9acb" - ] - ], - "python": "python@3.9", - "spec": "clingo-bootstrap%gcc platform=linux target=ppc64le" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "p3bqplnwqo66lvvolmtaezck77jafrc4", - "436f9483e4028c12c32ba9f4e7e91e944bf9819ef487dfe4e42ddd1d487c93ee" - ] - ], - "python": "python@2.6", - "spec": "clingo-bootstrap%gcc platform=linux target=x86_64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "rpa6yyujr7ilnfcowq2pbmkmh7uzrijp", - "3be0f4ccd412d45506f9f305ef7f6621cd246fbde97aed081595d01dafe3c397" - ] - ], - "python": "python@2.7+ucs4", - "spec": "clingo-bootstrap%gcc platform=linux target=x86_64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "y32mbn7swer3yxvgf6tmkgekpo23uo5z", - "f6e0716bd97f2df123abcd96ec8884c525a9fd10b81e0062784e7b0d2df3f622" - ] - ], - "python": "python@2.7~ucs4", - "spec": "clingo-bootstrap%gcc platform=linux target=x86_64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "ohtmyp5c74xt75csx4llbjs5anobryp6", - "7d613ddbca1640d761311fb00403c0cb65e279534c44a2129b8d9610f6146e78" - ] - ], - "python": "python@3.5", - "spec": "clingo-bootstrap%gcc platform=linux target=x86_64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "vcipwnf57slgoo7busvvkzjkk7vydeb5", - "db5222760045f20ad1e5c194179d31273b8e4bfa6ade38e15cd3182d685cc05b" - ] - ], - "python": "python@3.6", - "spec": "clingo-bootstrap%gcc platform=linux target=x86_64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "ffoyoewfd6pdwbjniodfkqusyvkrbhyi", - "14cea5f6cfd86bcb8de38ad8c1a5e44cc22955de2e7c78b825b617dccd107dbe" - ] - ], - "python": "python@3.7", - "spec": "clingo-bootstrap%gcc platform=linux target=x86_64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "kt74l7kjzrlp3cgtj2576o33mhsrgyrw", - "e71de4beb68bb3e58bd2dcb98dc3be3a375c82781b6f7cb01bc5d552c2240bd2" - ] - ], - "python": "python@3.8", - "spec": "clingo-bootstrap%gcc platform=linux target=x86_64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "hmnv6gk5wha64k6r3s7hid35mzvhkuot", - "b08ff59357fa184ce39b8cc0a17aaf7f0a925a449ab389e1afa4eab6ae026f2e" - ] - ], - "python": "python@3.9", - "spec": "clingo-bootstrap%gcc platform=linux target=x86_64" - } - ] -} \ No newline at end of file diff --git a/share/spack/bootstrap/github-actions-v0.1/gnupg.json b/share/spack/bootstrap/github-actions-v0.1/gnupg.json deleted file mode 100644 index d6400febfce..00000000000 --- a/share/spack/bootstrap/github-actions-v0.1/gnupg.json +++ /dev/null @@ -1,204 +0,0 @@ -{ - "verified": [ - { - "binaries": [ - [ - "libgpg-error", - "hph66gvb7vlinpzwoytxq27ojb7gtl2j", - "f040f513e212c428ee863d75924331f58b5f8f3946f98c757a9e0af0d0a34f63" - ], - [ - "libiconv", - "ckpif6rcf7mxdmceyv6sqvtnwfqi7fmc", - "1d745d04f7c8a1c4d17d9735eba0ee88c8acfbb213c22a15e45e58637867ed4c" - ], - [ - "npth", - "fjuoy73whriauk3bt6ma5fwet6iric7y", - "78d5d9e339ef901b0def0924a72ce87a93e0a8acb7394ec2c35be6c328154444" - ], - [ - "zlib", - "qo6otxqnn6mxpw4zhqc4wdwqmgcfjdfe", - "f00c38ecaf316cd665399ed14c233f839ae5868387ff04998e1ec949c1f4dcd6" - ], - [ - "libassuan", - "2upi74qccouj4k6d7wultp2u5fntayi3", - "f2118b102f9a94bb1e2804492689b44b260b7f6e46ac1208d5110ebffe24bf99" - ], - [ - "libgcrypt", - "xzhvvm44cfxwvgqgkpbeucpnl4dbj4p2", - "ae717e068f2f7f4eaeee4bdec4a6b20ff299c59c3d724c1661b6045fda628a9b" - ], - [ - "libksba", - "aodyg5mzfule3vimuetmzulv5mzdx37g", - "c665eb20f27b2d28fcb634fe958829165e44a27b1ad69995d5040f13d5693d52" - ], - [ - "pinentry", - "ihqcvdm5okxuvnln463l7h4flbkhrp44", - "b0c7781354eb4a7c9e979802590c0e4fb7eb53f440191367f0142eac4868f8d6" - ], - [ - "gnupg", - "47vilwybwuxved7jov7esiad3qlkv5rp", - "83f3de13b2712a05f520d16b5141797493f8b117041dd32aa5414a25d9d53439" - ] - ], - "spec": "gnupg@2.3: %apple-clang platform=darwin target=x86_64" - }, - { - "binaries": [ - [ - "libgpg-error", - "3dkguooajaaejhsebigs2e3lhk37mtem", - "09c5edd93fb479961d62d9938c1ea02b8f443babf0e79776f1539085c3422cd5" - ], - [ - "libiconv", - "i2eqtudh3zcxt5fvxuhe6n2ztuqbadtp", - "838786e029474d668b5f83a9669d227c812253c3c3f0328aa4f888542a7de830" - ], - [ - "npth", - "c3z6gg3ilutvvryxkjrboampqv5u5s2s", - "967522ae988ccce8c922f28aa2124170246f501f0a45179b919d827bf28c35d2" - ], - [ - "zlib", - "p2jozvok56voja7652dms4gvthpcjzta", - "41cbc69850640ed4466dbedc1bb4ccb0ade0c1a1e8fcd70d1e247b1387b937b5" - ], - [ - "libassuan", - "s2wx2xvt3iz3sigcdt5tvppj2m7e2bsf", - "5f766af4ff355769e3e456a9c95636a20a64f5ba32aecec633216a3d83a854f8" - ], - [ - "libgcrypt", - "gznmtryix6ck4x3chnuvbctz4xa3fmxl", - "0261b03f790c5320980d27bf0a471a1a4663929689ddfaeb5e568d33be8dc889" - ], - [ - "libksba", - "uxaryyfybbcw563jcwumufhfmbsawlbz", - "f45fff7a6a5c626a1474c7354fd00e18e629fcd086787336f7d62d1ead50c94f" - ], - [ - "pinentry", - "ias6sb4qi24u6i7axr5hkj4liq5dtr6l", - "a2a8e7652dceb7d080ff78726d28099f9050cb9f6e290d97f1f59f4b42521b9c" - ], - [ - "gnupg", - "qpm457bujhmfqy66euzhswokumuvufbz", - "d2371e26412e10fc702b9b2482aff776108194b84e1927644a3d64f5710fd163" - ] - ], - "spec": "gnupg@2.3: %gcc platform=linux target=aarch64" - }, - { - "binaries": [ - [ - "libgpg-error", - "4bp6dcfdbzbd4uuzvbgjyqunhjedg3lf", - "9a9947240c6af7e915aa8336bfaed8706c9129967eb9ab1895598217df91f301" - ], - [ - "libiconv", - "dscneqtpyy32r6ds24izlkki3euthnbr", - "a9dc099f6c7ee9fd6c63757cb81a59fe4b81672543d5253a50bb73bc819440ef" - ], - [ - "npth", - "jukmafxhkxo2s4udlzi5r5b6bbb3udw5", - "d2a2b11c0f1794ab0de813753221bde073508fbec19f0b15dbfd23455bc6de87" - ], - [ - "zlib", - "amqfrcbn67rochzkeu2ashklo35ayqqq", - "686fc10058d208530889bc5c3779aa2cc324b77301878a5405cf65ca53d613ba" - ], - [ - "libassuan", - "lyeih2j3miy7yugmwh37h667fogqn3fl", - "f87c474d81c890232cd8e1e4d93b5b232aa0ad428dcaa7231d7a8d182cea9ecc" - ], - [ - "libgcrypt", - "zb33zulvwcansfzu5km4d34avujnazfa", - "e67ae6a5345f9e864bd2009c1a9d7eb65a63ca2841368bebc477a770fb8dcaf5" - ], - [ - "libksba", - "yjuh2aplj23qyvaqixukd7a6eokfdgyp", - "6944fc047e8f0eb41daec734e2505016369319c64929f5ec8d3a8f99e01928d4" - ], - [ - "pinentry", - "xd7vajghgcueohv5qgahdvbjpcnrurns", - "a6b37efd6ef9f9374aa0c7d1869da990ae3668938b47ad6af50138d2ea05da02" - ], - [ - "gnupg", - "ti2ddl27nilobj2ctwsgzl52qque5o7z", - "43781437e3dfae158e7a6911313a4162d8ffa5313182438d1e6547a854f6f38a" - ] - ], - "spec": "gnupg@2.3: %gcc platform=linux target=ppc64le" - }, - { - "binaries": [ - [ - "libgpg-error", - "p7chd5hhecdkc27npia4uaoeabjit4gh", - "4b5e1f418b7afdd91755d54d38a51d5d048aa3b1e5239bcaf3453c8ca1cca4b6" - ], - [ - "libiconv", - "scpkgy6bmk3wcgfwzoiv7hw74drmnaoi", - "2bcb9a2868c20284ce65ab53d4f7bb4c7edccd4c14390460858e25a8bc48faa3" - ], - [ - "npth", - "6vh3jypaf7u2zez3vohn66fvo6znt35l", - "23a333c4e83910eb1f87c91caffb07f40b592561a4c44924fed9459751c017f7" - ], - [ - "zlib", - "uc25tb5r57nykfrxszsdy54trzqnk2jn", - "9e18c1146bc3dcb8454d18502013b8621ecf00d2f2d4d66d76cbe1e07f351ac8" - ], - [ - "libassuan", - "vdoskg5mldu6ixhvftwplp4zdftwxwws", - "1413b84af0c58127032e7bde86dbacf35dc65205aee1c2071718678bc57ce793" - ], - [ - "libgcrypt", - "ng7gfusjpnypmqgckq7rp4vq3bvylp3b", - "1a09e97eb2333812f8381d4737aca4d7cfd9f27ebae30eddbcf99f399ad67fec" - ], - [ - "libksba", - "p4feho36xa7dhabk766fzglwyo2dfbj6", - "000ef0f2ad3aa05c07272849be68e059ec60946970ab8875a824305afe832c9a" - ], - [ - "pinentry", - "m423kpm7k52r66q3sdctqcjxtekiyrrp", - "5739bee66271d7f0d5b9bcf5c248f1a434e9cdcb327a4a5a22fc47f565ac0de7" - ], - [ - "gnupg", - "dlapzqxrwduafgfq2evptizb7p4kgpkh", - "262177fa8f66468e589f8b3e10d17531f17a74ea0f5ac6905ac948198dca3c3c" - ] - ], - "spec": "gnupg@2.3: %gcc platform=linux target=x86_64" - } - ] -} \ No newline at end of file diff --git a/share/spack/bootstrap/github-actions-v0.1/metadata.yaml b/share/spack/bootstrap/github-actions-v0.1/metadata.yaml deleted file mode 100644 index b2439424b0c..00000000000 --- a/share/spack/bootstrap/github-actions-v0.1/metadata.yaml +++ /dev/null @@ -1,8 +0,0 @@ -type: buildcache -description: | - Buildcache generated from a public workflow using Github Actions. - The sha256 checksum of binaries is checked before installation. -info: - url: https://mirror.spack.io/bootstrap/github-actions/v0.1 - homepage: https://github.com/spack/spack-bootstrap-mirrors - releases: https://github.com/spack/spack-bootstrap-mirrors/releases diff --git a/share/spack/bootstrap/github-actions-v0.2/clingo.json b/share/spack/bootstrap/github-actions-v0.2/clingo.json deleted file mode 100644 index 60e771221df..00000000000 --- a/share/spack/bootstrap/github-actions-v0.2/clingo.json +++ /dev/null @@ -1,268 +0,0 @@ -{ - "verified": [ - { - "binaries": [ - [ - "clingo-bootstrap", - "i5rx6vbyw7cyg3snajcpnuozo7l3lcab", - "c55d1c76adb82ac9fbe67725641ef7e4fe1ae11e2e8da0dc93a3efe362549127" - ] - ], - "python": "python@3.10", - "spec": "clingo-bootstrap%apple-clang platform=darwin target=x86_64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "xoxkdgo3n332ewhbh7pz2zuevrjxkrke", - "b50e2fba026e85af3f99b3c412b4f0c88ec2fbce15b48eeb75072f1d3737f3cc" - ] - ], - "python": "python@3.5", - "spec": "clingo-bootstrap%apple-clang platform=darwin target=x86_64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "sgmirxbu3bpn4rdpfs6jlyycfrkfxl5i", - "b0a574df6f5d59491a685a31a8ed99fb345c850a91df62ef232fbe0cca716ed1" - ] - ], - "python": "python@3.6", - "spec": "clingo-bootstrap%apple-clang platform=darwin target=x86_64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "5hn7hszlizeqq3leqi6lrdmyy5ssv6zs", - "36e24bc3bd27b125fdeb30d51d2554e44288877c0ce6df5a878bb4e8a1d5847a" - ] - ], - "python": "python@3.7", - "spec": "clingo-bootstrap%apple-clang platform=darwin target=x86_64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "qk3ecxakadq4naakng6mhdfkwauef3dn", - "9d974c0d2b546d18f0ec35e08d5ba114bf2867f7ff7c7ea990b79d019ece6380" - ] - ], - "python": "python@3.8", - "spec": "clingo-bootstrap%apple-clang platform=darwin target=x86_64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "2omdsvzshkn2u3l5vwvwoey4es5cowfu", - "cbf72eb932ac847f87b1640f8e70e26f5261967288f7d6db19206ef352e36a88" - ] - ], - "python": "python@3.9", - "spec": "clingo-bootstrap%apple-clang platform=darwin target=x86_64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "ifgzrctoh2ibrmitp6ushrvrnaeqtkr7", - "1c609df7351286fe09aa3452fa7ed7fedf903e9fa12cde89b916a0fc4c022949" - ] - ], - "python": "python@3.10", - "spec": "clingo-bootstrap%gcc platform=linux target=aarch64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "esfzjhodgh5be22hvh3trg2ojzrmhzwt", - "8d070cdb2a5103cde3e6f873b1eb11d25f60464f3059d8643f943e5c9a9ec76c" - ] - ], - "python": "python@3.6", - "spec": "clingo-bootstrap%gcc platform=linux target=aarch64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "5b4uhkhrvtvdmsnctjx2isrxciy6v2o2", - "336b8b1202a8a28a0e34a98e5780ae0e2b2370b342ce67434551009b1a7c8db9" - ] - ], - "python": "python@3.7", - "spec": "clingo-bootstrap%gcc platform=linux target=aarch64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "czapgrrey6llnsu2m4qaamv3so2lybxm", - "16bdfe4b08ee8da38f3e2c7d5cc44a38d87696cc2b6de0971a4de25efb8ad8e4" - ] - ], - "python": "python@3.8", - "spec": "clingo-bootstrap%gcc platform=linux target=aarch64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "7za6vsetahbghs4d2qe4ajtf2iyiacwx", - "730ae7e6096ec8b83a0fc9464dda62bd6c2fec1f8565bb291f4d1ffe7746703b" - ] - ], - "python": "python@3.9", - "spec": "clingo-bootstrap%gcc platform=linux target=aarch64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "zulnxrmchldtasffqw6qacmgg4y2qumj", - "8988325db53c0c650f64372c21571ac85e9ba4577975d14ae7dba8ab7728b5fc" - ] - ], - "python": "python@3.10", - "spec": "clingo-bootstrap%gcc platform=linux target=ppc64le" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "lx54ebqzwtjpfgch7kagoxkmul56z7fa", - "81d64229299e76f9dc81f88d286bc94725e7cbcbb29ad0d66aaeaff73dd6473a" - ] - ], - "python": "python@3.6", - "spec": "clingo-bootstrap%gcc platform=linux target=ppc64le" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "isu2rjoicl4xzmbl3k2c4bg35gvejkgz", - "fcc4b052832cfd327d11f657c2b7715d981b0894ed03bbce18b23a842c7d706d" - ] - ], - "python": "python@3.7", - "spec": "clingo-bootstrap%gcc platform=linux target=ppc64le" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "ob3k3g2wjy7cw33lfobjar44sqmojyth", - "f51fd6256bfd3afc8470614d87df61e5c9dd582fcc70f707ca66ba2b7255da12" - ] - ], - "python": "python@3.8", - "spec": "clingo-bootstrap%gcc platform=linux target=ppc64le" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "norpsmparkl5dfuzdqj4537o77vjbgsl", - "477c041857b60f29ff9d6c7d2982b7eb49a2e02ebbc98af11488c32e2fb24081" - ] - ], - "python": "python@3.9", - "spec": "clingo-bootstrap%gcc platform=linux target=ppc64le" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "gypv5loj2ml73duq6sr76yg5rj25te2m", - "c855d7d32aadec37c41e51f19b83558b32bc0b946a9565dba0e659c6820bd6c3" - ] - ], - "python": "python@2.7+ucs4", - "spec": "clingo-bootstrap%gcc platform=linux target=x86_64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "rjopyx7hum3hqhgsdyw3st7frdfgrv3p", - "0e555f9bc99b4e4152939b30b2257f4f353941d152659e716bf6123c0ce11a60" - ] - ], - "python": "python@2.7~ucs4", - "spec": "clingo-bootstrap%gcc platform=linux target=x86_64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "2l45t4kw3cqqwj6vbxhfwhzlo6b3q2p4", - "6cb90de5a3d123b7408cfef693a9a78bb69c66abbfed746c1e85aa0acb848d03" - ] - ], - "python": "python@3.10", - "spec": "clingo-bootstrap%gcc platform=linux target=x86_64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "4psiezojm7dexequtbnav77wvgcajigq", - "b3fc33b5482357613294becb54968bd74de638abeae69e27c6c4319046a7e352" - ] - ], - "python": "python@3.5", - "spec": "clingo-bootstrap%gcc platform=linux target=x86_64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "dzhvhynye4z7oalowdcy5zt25lej3m2n", - "61c5f3e80bcc7acfc65e335f1910762df2cc5ded9d7e1e5977380a24de553dd7" - ] - ], - "python": "python@3.6", - "spec": "clingo-bootstrap%gcc platform=linux target=x86_64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "dtwevigmwgke4g6ee5byktpmzmrp2kvx", - "636937244b58611ec2eedb4422a1076fcaf09f3998593befb5a6ff1a74e1d5f7" - ] - ], - "python": "python@3.7", - "spec": "clingo-bootstrap%gcc platform=linux target=x86_64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "shqedxgvjnhiwdcdrvjhbd73jaevv7wt", - "b3615b2a94a8a15fddaa74cf4d9f9b3a516467a843cdeab597f72dcf6be5e31d" - ] - ], - "python": "python@3.8", - "spec": "clingo-bootstrap%gcc platform=linux target=x86_64" - }, - { - "binaries": [ - [ - "clingo-bootstrap", - "z6v6zvc6awioeompbvo735b4flr3yuyz", - "1389192bd74c1f7059d95c4a41500201cbc2905cbba553678613e0b7e3b96c71" - ] - ], - "python": "python@3.9", - "spec": "clingo-bootstrap%gcc platform=linux target=x86_64" - } - ] -} \ No newline at end of file diff --git a/share/spack/bootstrap/github-actions-v0.2/gnupg.json b/share/spack/bootstrap/github-actions-v0.2/gnupg.json deleted file mode 100644 index 2f568297892..00000000000 --- a/share/spack/bootstrap/github-actions-v0.2/gnupg.json +++ /dev/null @@ -1,204 +0,0 @@ -{ - "verified": [ - { - "binaries": [ - [ - "libiconv", - "d6dhoguolmllbzy2h6pnvjm3tti6uy6f", - "7fe765a87945991d4e57782ed67c4bf42a10f95582eecd6f57de80a545bde821" - ], - [ - "npth", - "x6fb7zx6n7mos5knvi6wlnaadd7r2szx", - "fd1e5a62107339f45219c32ba20b5e82aa0880c31ac86d1b245d388ca4546990" - ], - [ - "zlib", - "c5wm3jilx6zsers3sfgdisjqusoza4wr", - "7500a717c62736872aa65df4599f797ef67b21086dd6236b4c7712cfffac9bf3" - ], - [ - "libassuan", - "3qv4bprobfwes37clg764cfipdzjdbto", - "d85cd9d2c63a296300d4dcbd667421956df241109daef5e12d3ca63fa241cb14" - ], - [ - "libgcrypt", - "3y4ubdgxvgpvhxr3bk4l5mkw4gv42n7e", - "9dad7c2635344957c4db68378964d3af84ea052d45dbe8ded9a6e6e47211daa8" - ], - [ - "libgpg-error", - "doido34kfwsvwpj4c4jcocahjb5ltebw", - "20e5c238bee91d2a841f0b4bd0358ded59a0bd665d7f251fd9cd42f83e0b283b" - ], - [ - "libksba", - "mttecm7gzdv544lbzcoahchnboxysrvi", - "1c0ae64e828a597e4cf15dd997c66cd677e41f68c63db09b9551480a197052a2" - ], - [ - "pinentry", - "se7xgv7yf4ywpjnbv7voxgeuuvs77ahb", - "2fd13fbee7ca2361dc5dd09708c72d0489611301b60635cb0206bc5b94add884" - ], - [ - "gnupg", - "yannph34bpaqkhsv5mz2icwhy3epiqxd", - "1de8b4e119fa3455d0170466fa0fb8e04957fab740aec32535b4667279312b3f" - ] - ], - "spec": "gnupg@2.3: %apple-clang platform=darwin target=x86_64" - }, - { - "binaries": [ - [ - "zlib", - "t2hjzsyf3txkg64e4bq3nihe26rzzdws", - "171e720840a28af50b62141be77bc525e666cffd1fbbe2ee62673214e8b0280f" - ], - [ - "libiconv", - "yjdji2wj4njz72fyrg46jlz5f5wfbhfr", - "94c773c3d0294cf248ec1f3e9862669dfa743fe1a76de580d9425c14c8f7dcd2" - ], - [ - "npth", - "kx3vzmpysee7jxwsudarthrmyop6hzgc", - "f8cc6204fa449ce576d450396ec2cad40a75d5712c1381a61ed1681a54f9c79f" - ], - [ - "libassuan", - "e5n5l5ftzwxs4ego5furrdbegphb6hxp", - "ef0428874aa81bcb9944deed88e1fc639f629fe3d522cab3c281235ae2a53db9" - ], - [ - "libgcrypt", - "wyncpahrpqsmpk4b7nlhg5ekkjzyjdzs", - "2309548c51a17f580f036445b701feb85d2bc552b9c4404418c2f223666cfe3b" - ], - [ - "libgpg-error", - "vhcdd6jkbiday2seg3rlkbzpf6jzfdx7", - "79dd719538d9223d6287c0bba07b981944ab6d3ab11e5060274f1b7c727daf55" - ], - [ - "libksba", - "azcgpgncynoox3dce45hkz46bp2tb5rr", - "15d301f201a5162234261fcfccd579b0ff484131444a0b6f5c0006224bb155d6" - ], - [ - "pinentry", - "e3z5ekbv4jlsie4qooubcfvsk2sb6t7l", - "5fd27b8e47934b06554e84f1374a90a93e71e60a14dbde672a8da414b27b97f4" - ], - [ - "gnupg", - "i5agfvsmzdokuooaqhlh6vro5giwei2t", - "f1bde7a1f0c84c1bbcde5757a96cf7a3e9157c2cfa9907fde799aa8e04c0d51f" - ] - ], - "spec": "gnupg@2.3: %gcc platform=linux target=aarch64" - }, - { - "binaries": [ - [ - "zlib", - "v5rr6ba37tudzfuv2jszwikgcl4wd3cd", - "371ad4b277af7b97c7871b9931f2764c97362620c7990c5ad8fdb5c42a1d30dc" - ], - [ - "libiconv", - "bvcnx2e4bumjcgya4dczdhjb3fhqyass", - "65a00b717b3a4ee1b5ab9f84163722bdfea8eb20a2eecc9cf657c0eaac0227e9" - ], - [ - "npth", - "dkb6ez6a4c3iyrv67llwf5mzmynqdmtj", - "4d77351661d0e0130b1c89fb6c6a944aee41d701ef80d056d3fc0178a7f36075" - ], - [ - "libassuan", - "tuydcxdbb5jfvw3gri7y24b233kgotgd", - "d8775e7c1dd252437c6fa0781675b1d2202cfc0c8190e60d248928b6fca8bc9f" - ], - [ - "libgcrypt", - "kgxmg4eukwx6nn3bdera3j7cf7hxfy6n", - "6046523f10ed54be50b0211c27191b3422886984fc0c00aed1a85d1f121c42e6" - ], - [ - "libgpg-error", - "ewhrwnltlrzkpqyix2vbkf4ruq6b6ea3", - "3f3bbbf1a3cb82d39313e39bcbe3dad94a176130fc0e9a8045417d6223fb4f31" - ], - [ - "libksba", - "onxt5ry2fotgwiognwmhxlgnekuvtviq", - "3a4df13f8b880441d1df4b234a4ca01de7601d84a6627185c2b3191a34445d40" - ], - [ - "pinentry", - "fm3m4rsszzxxakcpssd34jbbe4ihrhac", - "73afa46176a7ec8f02d01a2caad3e400dc18c3c8a53f92b88a9aa9e3653db3e6" - ], - [ - "gnupg", - "gwr65ovh4wbxjgniaoqlbt3yla6rdikj", - "7a3f7afe69ca67797a339c04028ca45a9630933020b57cb56e28453197fe8a57" - ] - ], - "spec": "gnupg@2.3: %gcc platform=linux target=ppc64le" - }, - { - "binaries": [ - [ - "libiconv", - "vec3ac6t4ag3lb7ycvisafthqmpci74b", - "35d184218e525d8aaea60082fd2d0f1e80449ec32746cceda2ea0ca106e9a095" - ], - [ - "npth", - "jx3kmy3ilc66rgg5mqtbed5z6qwt3vrd", - "74c2c1b087667661da3e24ac83bcecf1bc2d10d69e7678d1fd232875fe295135" - ], - [ - "zlib", - "wnpbp4pu7xca24goggcy773d2y4pobbd", - "bcbd5310e8c5e75cbf33d8155448b212486dc543469d6df7e56dcecb6112ee88" - ], - [ - "libassuan", - "ynn33wutdtoo2lbjjoizgslintxst2zl", - "ac3b060690c6da0c64dcf35da047b84cc81793118fb9ff29b993f3fb9efdc258" - ], - [ - "libgcrypt", - "zzofcjer43vsxwj27c3rxapjxhsz4hlx", - "4b1977d815f657c2d6af540ea4b4ce80838cadcf4ada72a8ba142a7441e571ea" - ], - [ - "libgpg-error", - "gzr2ucybgks5jquvf4lv7iprxq5vx5le", - "a12ecb5cfd083a29d042fd309ebb5ab8fd4ace0b68b27f89b857e9a84d75b5be" - ], - [ - "libksba", - "hw4u4pam6mp3henpw476axtqaahfdy64", - "5424caf98a2d48e0ed0b9134353c242328ebeef6d2b31808d58969165e809b47" - ], - [ - "pinentry", - "hffsjitsewdgoijwgzvub6vpjwm33ywr", - "8ed7504b5b2d13ab7e1f4a0e27a882c33c5a6ebfcb43c51269333c0d6d5e1448" - ], - [ - "gnupg", - "lge4h2kjgvssyspnvutq6t3q2xual5oc", - "6080ce00fcc24185e4051a30f6d52982f86f46eee6d8a2dc4d83ab08d8195be8" - ] - ], - "spec": "gnupg@2.3: %gcc platform=linux target=x86_64" - } - ] -} \ No newline at end of file diff --git a/share/spack/bootstrap/github-actions-v0.3/clingo.json b/share/spack/bootstrap/github-actions-v0.3/clingo.json deleted file mode 120000 index 049ba5f7ce7..00000000000 --- a/share/spack/bootstrap/github-actions-v0.3/clingo.json +++ /dev/null @@ -1 +0,0 @@ -../github-actions-v0.2/clingo.json \ No newline at end of file diff --git a/share/spack/bootstrap/github-actions-v0.3/clingo.json b/share/spack/bootstrap/github-actions-v0.3/clingo.json new file mode 100644 index 00000000000..60e771221df --- /dev/null +++ b/share/spack/bootstrap/github-actions-v0.3/clingo.json @@ -0,0 +1,268 @@ +{ + "verified": [ + { + "binaries": [ + [ + "clingo-bootstrap", + "i5rx6vbyw7cyg3snajcpnuozo7l3lcab", + "c55d1c76adb82ac9fbe67725641ef7e4fe1ae11e2e8da0dc93a3efe362549127" + ] + ], + "python": "python@3.10", + "spec": "clingo-bootstrap%apple-clang platform=darwin target=x86_64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "xoxkdgo3n332ewhbh7pz2zuevrjxkrke", + "b50e2fba026e85af3f99b3c412b4f0c88ec2fbce15b48eeb75072f1d3737f3cc" + ] + ], + "python": "python@3.5", + "spec": "clingo-bootstrap%apple-clang platform=darwin target=x86_64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "sgmirxbu3bpn4rdpfs6jlyycfrkfxl5i", + "b0a574df6f5d59491a685a31a8ed99fb345c850a91df62ef232fbe0cca716ed1" + ] + ], + "python": "python@3.6", + "spec": "clingo-bootstrap%apple-clang platform=darwin target=x86_64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "5hn7hszlizeqq3leqi6lrdmyy5ssv6zs", + "36e24bc3bd27b125fdeb30d51d2554e44288877c0ce6df5a878bb4e8a1d5847a" + ] + ], + "python": "python@3.7", + "spec": "clingo-bootstrap%apple-clang platform=darwin target=x86_64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "qk3ecxakadq4naakng6mhdfkwauef3dn", + "9d974c0d2b546d18f0ec35e08d5ba114bf2867f7ff7c7ea990b79d019ece6380" + ] + ], + "python": "python@3.8", + "spec": "clingo-bootstrap%apple-clang platform=darwin target=x86_64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "2omdsvzshkn2u3l5vwvwoey4es5cowfu", + "cbf72eb932ac847f87b1640f8e70e26f5261967288f7d6db19206ef352e36a88" + ] + ], + "python": "python@3.9", + "spec": "clingo-bootstrap%apple-clang platform=darwin target=x86_64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "ifgzrctoh2ibrmitp6ushrvrnaeqtkr7", + "1c609df7351286fe09aa3452fa7ed7fedf903e9fa12cde89b916a0fc4c022949" + ] + ], + "python": "python@3.10", + "spec": "clingo-bootstrap%gcc platform=linux target=aarch64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "esfzjhodgh5be22hvh3trg2ojzrmhzwt", + "8d070cdb2a5103cde3e6f873b1eb11d25f60464f3059d8643f943e5c9a9ec76c" + ] + ], + "python": "python@3.6", + "spec": "clingo-bootstrap%gcc platform=linux target=aarch64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "5b4uhkhrvtvdmsnctjx2isrxciy6v2o2", + "336b8b1202a8a28a0e34a98e5780ae0e2b2370b342ce67434551009b1a7c8db9" + ] + ], + "python": "python@3.7", + "spec": "clingo-bootstrap%gcc platform=linux target=aarch64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "czapgrrey6llnsu2m4qaamv3so2lybxm", + "16bdfe4b08ee8da38f3e2c7d5cc44a38d87696cc2b6de0971a4de25efb8ad8e4" + ] + ], + "python": "python@3.8", + "spec": "clingo-bootstrap%gcc platform=linux target=aarch64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "7za6vsetahbghs4d2qe4ajtf2iyiacwx", + "730ae7e6096ec8b83a0fc9464dda62bd6c2fec1f8565bb291f4d1ffe7746703b" + ] + ], + "python": "python@3.9", + "spec": "clingo-bootstrap%gcc platform=linux target=aarch64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "zulnxrmchldtasffqw6qacmgg4y2qumj", + "8988325db53c0c650f64372c21571ac85e9ba4577975d14ae7dba8ab7728b5fc" + ] + ], + "python": "python@3.10", + "spec": "clingo-bootstrap%gcc platform=linux target=ppc64le" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "lx54ebqzwtjpfgch7kagoxkmul56z7fa", + "81d64229299e76f9dc81f88d286bc94725e7cbcbb29ad0d66aaeaff73dd6473a" + ] + ], + "python": "python@3.6", + "spec": "clingo-bootstrap%gcc platform=linux target=ppc64le" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "isu2rjoicl4xzmbl3k2c4bg35gvejkgz", + "fcc4b052832cfd327d11f657c2b7715d981b0894ed03bbce18b23a842c7d706d" + ] + ], + "python": "python@3.7", + "spec": "clingo-bootstrap%gcc platform=linux target=ppc64le" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "ob3k3g2wjy7cw33lfobjar44sqmojyth", + "f51fd6256bfd3afc8470614d87df61e5c9dd582fcc70f707ca66ba2b7255da12" + ] + ], + "python": "python@3.8", + "spec": "clingo-bootstrap%gcc platform=linux target=ppc64le" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "norpsmparkl5dfuzdqj4537o77vjbgsl", + "477c041857b60f29ff9d6c7d2982b7eb49a2e02ebbc98af11488c32e2fb24081" + ] + ], + "python": "python@3.9", + "spec": "clingo-bootstrap%gcc platform=linux target=ppc64le" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "gypv5loj2ml73duq6sr76yg5rj25te2m", + "c855d7d32aadec37c41e51f19b83558b32bc0b946a9565dba0e659c6820bd6c3" + ] + ], + "python": "python@2.7+ucs4", + "spec": "clingo-bootstrap%gcc platform=linux target=x86_64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "rjopyx7hum3hqhgsdyw3st7frdfgrv3p", + "0e555f9bc99b4e4152939b30b2257f4f353941d152659e716bf6123c0ce11a60" + ] + ], + "python": "python@2.7~ucs4", + "spec": "clingo-bootstrap%gcc platform=linux target=x86_64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "2l45t4kw3cqqwj6vbxhfwhzlo6b3q2p4", + "6cb90de5a3d123b7408cfef693a9a78bb69c66abbfed746c1e85aa0acb848d03" + ] + ], + "python": "python@3.10", + "spec": "clingo-bootstrap%gcc platform=linux target=x86_64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "4psiezojm7dexequtbnav77wvgcajigq", + "b3fc33b5482357613294becb54968bd74de638abeae69e27c6c4319046a7e352" + ] + ], + "python": "python@3.5", + "spec": "clingo-bootstrap%gcc platform=linux target=x86_64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "dzhvhynye4z7oalowdcy5zt25lej3m2n", + "61c5f3e80bcc7acfc65e335f1910762df2cc5ded9d7e1e5977380a24de553dd7" + ] + ], + "python": "python@3.6", + "spec": "clingo-bootstrap%gcc platform=linux target=x86_64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "dtwevigmwgke4g6ee5byktpmzmrp2kvx", + "636937244b58611ec2eedb4422a1076fcaf09f3998593befb5a6ff1a74e1d5f7" + ] + ], + "python": "python@3.7", + "spec": "clingo-bootstrap%gcc platform=linux target=x86_64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "shqedxgvjnhiwdcdrvjhbd73jaevv7wt", + "b3615b2a94a8a15fddaa74cf4d9f9b3a516467a843cdeab597f72dcf6be5e31d" + ] + ], + "python": "python@3.8", + "spec": "clingo-bootstrap%gcc platform=linux target=x86_64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "z6v6zvc6awioeompbvo735b4flr3yuyz", + "1389192bd74c1f7059d95c4a41500201cbc2905cbba553678613e0b7e3b96c71" + ] + ], + "python": "python@3.9", + "spec": "clingo-bootstrap%gcc platform=linux target=x86_64" + } + ] +} \ No newline at end of file diff --git a/share/spack/bootstrap/github-actions-v0.3/gnupg.json b/share/spack/bootstrap/github-actions-v0.3/gnupg.json deleted file mode 120000 index 1d6273a6d93..00000000000 --- a/share/spack/bootstrap/github-actions-v0.3/gnupg.json +++ /dev/null @@ -1 +0,0 @@ -../github-actions-v0.2/gnupg.json \ No newline at end of file diff --git a/share/spack/bootstrap/github-actions-v0.3/gnupg.json b/share/spack/bootstrap/github-actions-v0.3/gnupg.json new file mode 100644 index 00000000000..2f568297892 --- /dev/null +++ b/share/spack/bootstrap/github-actions-v0.3/gnupg.json @@ -0,0 +1,204 @@ +{ + "verified": [ + { + "binaries": [ + [ + "libiconv", + "d6dhoguolmllbzy2h6pnvjm3tti6uy6f", + "7fe765a87945991d4e57782ed67c4bf42a10f95582eecd6f57de80a545bde821" + ], + [ + "npth", + "x6fb7zx6n7mos5knvi6wlnaadd7r2szx", + "fd1e5a62107339f45219c32ba20b5e82aa0880c31ac86d1b245d388ca4546990" + ], + [ + "zlib", + "c5wm3jilx6zsers3sfgdisjqusoza4wr", + "7500a717c62736872aa65df4599f797ef67b21086dd6236b4c7712cfffac9bf3" + ], + [ + "libassuan", + "3qv4bprobfwes37clg764cfipdzjdbto", + "d85cd9d2c63a296300d4dcbd667421956df241109daef5e12d3ca63fa241cb14" + ], + [ + "libgcrypt", + "3y4ubdgxvgpvhxr3bk4l5mkw4gv42n7e", + "9dad7c2635344957c4db68378964d3af84ea052d45dbe8ded9a6e6e47211daa8" + ], + [ + "libgpg-error", + "doido34kfwsvwpj4c4jcocahjb5ltebw", + "20e5c238bee91d2a841f0b4bd0358ded59a0bd665d7f251fd9cd42f83e0b283b" + ], + [ + "libksba", + "mttecm7gzdv544lbzcoahchnboxysrvi", + "1c0ae64e828a597e4cf15dd997c66cd677e41f68c63db09b9551480a197052a2" + ], + [ + "pinentry", + "se7xgv7yf4ywpjnbv7voxgeuuvs77ahb", + "2fd13fbee7ca2361dc5dd09708c72d0489611301b60635cb0206bc5b94add884" + ], + [ + "gnupg", + "yannph34bpaqkhsv5mz2icwhy3epiqxd", + "1de8b4e119fa3455d0170466fa0fb8e04957fab740aec32535b4667279312b3f" + ] + ], + "spec": "gnupg@2.3: %apple-clang platform=darwin target=x86_64" + }, + { + "binaries": [ + [ + "zlib", + "t2hjzsyf3txkg64e4bq3nihe26rzzdws", + "171e720840a28af50b62141be77bc525e666cffd1fbbe2ee62673214e8b0280f" + ], + [ + "libiconv", + "yjdji2wj4njz72fyrg46jlz5f5wfbhfr", + "94c773c3d0294cf248ec1f3e9862669dfa743fe1a76de580d9425c14c8f7dcd2" + ], + [ + "npth", + "kx3vzmpysee7jxwsudarthrmyop6hzgc", + "f8cc6204fa449ce576d450396ec2cad40a75d5712c1381a61ed1681a54f9c79f" + ], + [ + "libassuan", + "e5n5l5ftzwxs4ego5furrdbegphb6hxp", + "ef0428874aa81bcb9944deed88e1fc639f629fe3d522cab3c281235ae2a53db9" + ], + [ + "libgcrypt", + "wyncpahrpqsmpk4b7nlhg5ekkjzyjdzs", + "2309548c51a17f580f036445b701feb85d2bc552b9c4404418c2f223666cfe3b" + ], + [ + "libgpg-error", + "vhcdd6jkbiday2seg3rlkbzpf6jzfdx7", + "79dd719538d9223d6287c0bba07b981944ab6d3ab11e5060274f1b7c727daf55" + ], + [ + "libksba", + "azcgpgncynoox3dce45hkz46bp2tb5rr", + "15d301f201a5162234261fcfccd579b0ff484131444a0b6f5c0006224bb155d6" + ], + [ + "pinentry", + "e3z5ekbv4jlsie4qooubcfvsk2sb6t7l", + "5fd27b8e47934b06554e84f1374a90a93e71e60a14dbde672a8da414b27b97f4" + ], + [ + "gnupg", + "i5agfvsmzdokuooaqhlh6vro5giwei2t", + "f1bde7a1f0c84c1bbcde5757a96cf7a3e9157c2cfa9907fde799aa8e04c0d51f" + ] + ], + "spec": "gnupg@2.3: %gcc platform=linux target=aarch64" + }, + { + "binaries": [ + [ + "zlib", + "v5rr6ba37tudzfuv2jszwikgcl4wd3cd", + "371ad4b277af7b97c7871b9931f2764c97362620c7990c5ad8fdb5c42a1d30dc" + ], + [ + "libiconv", + "bvcnx2e4bumjcgya4dczdhjb3fhqyass", + "65a00b717b3a4ee1b5ab9f84163722bdfea8eb20a2eecc9cf657c0eaac0227e9" + ], + [ + "npth", + "dkb6ez6a4c3iyrv67llwf5mzmynqdmtj", + "4d77351661d0e0130b1c89fb6c6a944aee41d701ef80d056d3fc0178a7f36075" + ], + [ + "libassuan", + "tuydcxdbb5jfvw3gri7y24b233kgotgd", + "d8775e7c1dd252437c6fa0781675b1d2202cfc0c8190e60d248928b6fca8bc9f" + ], + [ + "libgcrypt", + "kgxmg4eukwx6nn3bdera3j7cf7hxfy6n", + "6046523f10ed54be50b0211c27191b3422886984fc0c00aed1a85d1f121c42e6" + ], + [ + "libgpg-error", + "ewhrwnltlrzkpqyix2vbkf4ruq6b6ea3", + "3f3bbbf1a3cb82d39313e39bcbe3dad94a176130fc0e9a8045417d6223fb4f31" + ], + [ + "libksba", + "onxt5ry2fotgwiognwmhxlgnekuvtviq", + "3a4df13f8b880441d1df4b234a4ca01de7601d84a6627185c2b3191a34445d40" + ], + [ + "pinentry", + "fm3m4rsszzxxakcpssd34jbbe4ihrhac", + "73afa46176a7ec8f02d01a2caad3e400dc18c3c8a53f92b88a9aa9e3653db3e6" + ], + [ + "gnupg", + "gwr65ovh4wbxjgniaoqlbt3yla6rdikj", + "7a3f7afe69ca67797a339c04028ca45a9630933020b57cb56e28453197fe8a57" + ] + ], + "spec": "gnupg@2.3: %gcc platform=linux target=ppc64le" + }, + { + "binaries": [ + [ + "libiconv", + "vec3ac6t4ag3lb7ycvisafthqmpci74b", + "35d184218e525d8aaea60082fd2d0f1e80449ec32746cceda2ea0ca106e9a095" + ], + [ + "npth", + "jx3kmy3ilc66rgg5mqtbed5z6qwt3vrd", + "74c2c1b087667661da3e24ac83bcecf1bc2d10d69e7678d1fd232875fe295135" + ], + [ + "zlib", + "wnpbp4pu7xca24goggcy773d2y4pobbd", + "bcbd5310e8c5e75cbf33d8155448b212486dc543469d6df7e56dcecb6112ee88" + ], + [ + "libassuan", + "ynn33wutdtoo2lbjjoizgslintxst2zl", + "ac3b060690c6da0c64dcf35da047b84cc81793118fb9ff29b993f3fb9efdc258" + ], + [ + "libgcrypt", + "zzofcjer43vsxwj27c3rxapjxhsz4hlx", + "4b1977d815f657c2d6af540ea4b4ce80838cadcf4ada72a8ba142a7441e571ea" + ], + [ + "libgpg-error", + "gzr2ucybgks5jquvf4lv7iprxq5vx5le", + "a12ecb5cfd083a29d042fd309ebb5ab8fd4ace0b68b27f89b857e9a84d75b5be" + ], + [ + "libksba", + "hw4u4pam6mp3henpw476axtqaahfdy64", + "5424caf98a2d48e0ed0b9134353c242328ebeef6d2b31808d58969165e809b47" + ], + [ + "pinentry", + "hffsjitsewdgoijwgzvub6vpjwm33ywr", + "8ed7504b5b2d13ab7e1f4a0e27a882c33c5a6ebfcb43c51269333c0d6d5e1448" + ], + [ + "gnupg", + "lge4h2kjgvssyspnvutq6t3q2xual5oc", + "6080ce00fcc24185e4051a30f6d52982f86f46eee6d8a2dc4d83ab08d8195be8" + ] + ], + "spec": "gnupg@2.3: %gcc platform=linux target=x86_64" + } + ] +} \ No newline at end of file diff --git a/share/spack/bootstrap/github-actions-v0.4/clingo.json b/share/spack/bootstrap/github-actions-v0.4/clingo.json new file mode 100644 index 00000000000..1fa83eef1c0 --- /dev/null +++ b/share/spack/bootstrap/github-actions-v0.4/clingo.json @@ -0,0 +1,334 @@ +{ + "verified": [ + { + "binaries": [ + [ + "clingo-bootstrap", + "fk6k6buvgbwhwtigvpvi3266gllv7z2o", + "003eb7b2c62debc0bac4a7f3a3933d6a955520199b37e00c8c0761036d8dc63a" + ] + ], + "python": "python@3.10", + "spec": "clingo-bootstrap%apple-clang platform=darwin target=aarch64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "2ezozohyngzmq74eeclsjupcawg6slse", + "bf3c559d655d5f04a2b080c640996086db2bb6bbf49f4139eed225a77b574923" + ] + ], + "python": "python@3.11", + "spec": "clingo-bootstrap%apple-clang platform=darwin target=aarch64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "okjsfmgareef7laq432tdtgyu7bshmv2", + "7beed9fe21b52df6b56d8242b79becab7ed953af16612d6e09c595ef39591ac3" + ] + ], + "python": "python@3.6", + "spec": "clingo-bootstrap%apple-clang platform=darwin target=aarch64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "cv7nf5ti72ywciapdy6mn7cemqv766zy", + "6af9e548044e4849794ee85008c8b19539b63857510c6fff544de7ccb6e53ee8" + ] + ], + "python": "python@3.7", + "spec": "clingo-bootstrap%apple-clang platform=darwin target=aarch64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "ing4swsz5bj7guqffc277zitcky4uhu4", + "4d9008372c73797fc0bd47c92c922f810e1b3fd44dc373682a7a0780b711058c" + ] + ], + "python": "python@3.8", + "spec": "clingo-bootstrap%apple-clang platform=darwin target=aarch64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "p2cyqcsow6k6prfryoqb7usv27hhofuq", + "5e4fd1fc552d815ce8db8b8917d9089c7782a92269754f8ca5d4f01a9406244d" + ] + ], + "python": "python@3.9", + "spec": "clingo-bootstrap%apple-clang platform=darwin target=aarch64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "5bfjmclf6sktj4drclxe7rdwdthlkxw3", + "b811e62f82b564e9cd5e12fc3cdb19b3d4e5f2bdb98985e1bbe3d1bbd5dd3d5c" + ] + ], + "python": "python@3.10", + "spec": "clingo-bootstrap%apple-clang platform=darwin target=x86_64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "bwmaj7wyyiivvkq5j72mholmhmytb2fl", + "468da2198479514bbbf66f4268716bce38cace1004a612bc669d21d97c596f85" + ] + ], + "python": "python@3.11", + "spec": "clingo-bootstrap%apple-clang platform=darwin target=x86_64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "ewhsk7bcohduujp5t7hljb5uk2mfbk7k", + "919cbfc82bbb08da207e22bec4d8047c34042b90d58b9c6b438b5dcef0046e39" + ] + ], + "python": "python@3.6", + "spec": "clingo-bootstrap%apple-clang platform=darwin target=x86_64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "263aqtzhrgzmzgpfekda7uk6wdqez76j", + "b9e579ee2a848f7287a8b625459ac5b8ce19e9e6858a86b53effaa4ae712d1b6" + ] + ], + "python": "python@3.7", + "spec": "clingo-bootstrap%apple-clang platform=darwin target=x86_64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "yqqiddbmi2pyxgu757qfvts6hlt6525q", + "254ab94d48543472ad8a32f598dc869c49051a0b890951d7de8425c7549caa26" + ] + ], + "python": "python@3.8", + "spec": "clingo-bootstrap%apple-clang platform=darwin target=x86_64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "plv3woz7rwmixdo42ew27imtqqjqnnv5", + "ec494e7043433fac6f8f404e023eea397197ff0928bf1c3f3cc0bc62d549334c" + ] + ], + "python": "python@3.9", + "spec": "clingo-bootstrap%apple-clang platform=darwin target=x86_64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "domcqyr4qx2yl3433l5dycnehastl7zc", + "fbfc1fc14f27bbabe36a438dd70515067dbd7e0873bc748b9f34d576d5400cb4" + ] + ], + "python": "python@3.10", + "spec": "clingo-bootstrap%gcc platform=linux target=aarch64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "b5m7ectjiuucgaoyry24hhop44edjvg7", + "5412e2b3f45d251acd976c12d238549e0c324e6481bf328f9547fafc0e810daf" + ] + ], + "python": "python@3.11", + "spec": "clingo-bootstrap%gcc platform=linux target=aarch64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "h2uxdiwlbvrfsz5mlt2s2xvnefbuk7qx", + "4cf26cd903fe0034522e1d8a712ab7a6ae936961c1c010473ff15566665cef6b" + ] + ], + "python": "python@3.6", + "spec": "clingo-bootstrap%gcc platform=linux target=aarch64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "4ksotxknsesu4mv2bio5ndtilo423cpy", + "9281ca638e2ec5c0b6d3ae050827a1c3696251a6274e96f3a8a89a1fdf7f0ba2" + ] + ], + "python": "python@3.7", + "spec": "clingo-bootstrap%gcc platform=linux target=aarch64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "ho7jg4bl7degmnnnj6x6fatbcno37kqo", + "0e78a555839fbd3752473ed80c76be9007b6ce3f152fa69d8014b172e339b92f" + ] + ], + "python": "python@3.8", + "spec": "clingo-bootstrap%gcc platform=linux target=aarch64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "oztu77xbgiige4pp2epmbqrmxt4vwnla", + "5271b271a2f6ae26838614477b2b8e5f230bceda7e0eb63f2cc36b18da3ba53d" + ] + ], + "python": "python@3.9", + "spec": "clingo-bootstrap%gcc platform=linux target=aarch64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "33qaxq2adjrlv6ttxbu6bmueundhns2w", + "5fa731b84e354b8108ac4b7205d40e8c1a74cb2dfd590dd2d648d744a8556a1d" + ] + ], + "python": "python@3.10", + "spec": "clingo-bootstrap%gcc platform=linux target=ppc64le" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "vwhszkap6e2zbzb74ywgyggflkmtavwz", + "09eed0c9b98681173f512385675f44d070cb5ebc3e08aac659a12ea1ec41d05a" + ] + ], + "python": "python@3.11", + "spec": "clingo-bootstrap%gcc platform=linux target=ppc64le" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "3pst4dqux2clmm3mpjj4jkowv3s2ixv6", + "f9d9ade557ed426f55308dd14b43c59e1b51b8f40c9847d00994a3a89182a846" + ] + ], + "python": "python@3.6", + "spec": "clingo-bootstrap%gcc platform=linux target=ppc64le" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "6wk7qj2hdglt2sjtec4mv7ibsvhw53ge", + "e06a3190e60b1d0c4d4b8f01b7a2ade9d2d3d8fdaf84757cc9741e81a5ad59a3" + ] + ], + "python": "python@3.7", + "spec": "clingo-bootstrap%gcc platform=linux target=ppc64le" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "k2kch7a6j7ilikuklhyffkqhdqb46yt5", + "2547727ce0b8295594dfa56b711631b8ab221a19c4cbd19341539b929693b0cb" + ] + ], + "python": "python@3.8", + "spec": "clingo-bootstrap%gcc platform=linux target=ppc64le" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "ivzizagt74uqxrp2mri5lbqiqkhab77p", + "2ddd5daeeabfc3b2a211f7efb3cc700991c5817b08b19c2d315084198f7d2bc8" + ] + ], + "python": "python@3.9", + "spec": "clingo-bootstrap%gcc platform=linux target=ppc64le" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "idkenmhnscjlu5gjqhpcqa4h7o2a7aow", + "44c88094abb239dd33b75c02c24fefe7f4f5646c2371f50a5bfb47b23805760b" + ] + ], + "python": "python@3.10", + "spec": "clingo-bootstrap%gcc platform=linux target=x86_64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "cizcjj3tx4irs3uzoktrgybq73sz545f", + "d8c8d4accece4e10a4339b263ff42f0f0adc77b3fbeea1010b3d7fc48aead5b3" + ] + ], + "python": "python@3.11", + "spec": "clingo-bootstrap%gcc platform=linux target=x86_64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "prqkzynv2nwko5mktitebgkeumuxkveu", + "3059fb60ff3b2dd5b36a46af37972b479fbfad348c30ec2e6b59729d93f07eed" + ] + ], + "python": "python@3.6", + "spec": "clingo-bootstrap%gcc platform=linux target=x86_64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "axtxtavfahxuazw2wueu3tjwwu6ttdfo", + "281cf24d0a8f2372b348bb1a38a9bfd1516063f597ffdecfde6e8e3aa4e2139f" + ] + ], + "python": "python@3.7", + "spec": "clingo-bootstrap%gcc platform=linux target=x86_64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "ba5ijauisd3uuixtmactc36vps7yfsrl", + "ea5960f47f48daeb62e6ebf7d8574ceb4bfccff6e2bae17571b0857bfd7a0bbc" + ] + ], + "python": "python@3.8", + "spec": "clingo-bootstrap%gcc platform=linux target=x86_64" + }, + { + "binaries": [ + [ + "clingo-bootstrap", + "gqcctd2ejbgvyvyt4umqpetfoogfycwu", + "8358d72dd5de00a1b7a7ffb88ba366a01ce9b700245d2940eae7395fec0e6fda" + ] + ], + "python": "python@3.9", + "spec": "clingo-bootstrap%gcc platform=linux target=x86_64" + } + ] +} \ No newline at end of file diff --git a/share/spack/bootstrap/github-actions-v0.4/gnupg.json b/share/spack/bootstrap/github-actions-v0.4/gnupg.json new file mode 100644 index 00000000000..5237d8729af --- /dev/null +++ b/share/spack/bootstrap/github-actions-v0.4/gnupg.json @@ -0,0 +1,254 @@ +{ + "verified": [ + { + "binaries": [ + [ + "zlib", + "azrxnl6yp7xeapfy7nljiopucaelofuh", + "c3f28571947a41d3c9fb0da0b340b51bdef6b9e05a59e6df7c9bc5838bacd81a" + ], + [ + "libiconv", + "id44zneq3nh4grvtekqoefl24okct4ak", + "8cf48050c8d58dc0e1d11c8b3b9d970586e1f62933f8655982f4312d1e4426ea" + ], + [ + "npth", + "lp7fobvpwlk3xugo7th2kmcnrvqqxb3b", + "ec4dda80a2485e0eda5b1ef09e6b8b020283b00ab6252981722979af04ce2ba8" + ], + [ + "libassuan", + "trhqsquxpocecfgkeif5bh2dwgu4njbp", + "33f15821d6e41238de58f2237d3e1be46b657e3337cbe73f87973fe970ab36fd" + ], + [ + "libgcrypt", + "eadvdhou2xjdhf47x3q5x2ypa4qhfqjy", + "f0d1d6b3cef5794933b78df3446ac71bdd0cc79b81a26fc33153ef13819e6b09" + ], + [ + "libgpg-error", + "yg67vozcaac75p3dnhd6c3cjpa5nsfjo", + "fe907bce097dec72a92a1973d73253d9e4ce4bd78ed14f8d6e647dd8e77eef15" + ], + [ + "libksba", + "m7o6qwsu2gxvlka2jbd5puzwj3z553ob", + "69d324a77b550a6c7a201f3f39835df4f14534fcf5fa28628c14039bfdb39dda" + ], + [ + "pinentry", + "6m36xv6ft3yterimp6xoozz66ych5eew", + "0b82a4b52a6bc5e6fd4913f585455ea703e0fa5c85fd9f4bb1eb5819af5084e1" + ], + [ + "gnupg", + "pyrfgqkgltgfk4yljfw2myxn6vqen2j6", + "3c41b0cf2db01ad2675f27d51edb4cf7f798be9ca0e3ac781990ff8b462cd8f6" + ] + ], + "spec": "gnupg@2.3: %apple-clang platform=darwin target=aarch64" + }, + { + "binaries": [ + [ + "libiconv", + "f6om5cmewxrhzpowei3m2g2qnijvlep4", + "ab891ac21bc9cf44723993232ce3fff6fe75d003dfb88077dea630e532db123f" + ], + [ + "npth", + "tvebgs23dhejixfe36dufivhkwnyxh3t", + "95b9852c2e69f18fb8eff3dc6fc2bb9efe38821314cac6c310523da89c8346a2" + ], + [ + "zlib", + "rlzphstv75due7yzcicuu7nfos5zuk2q", + "e5ee87fab6e51b46ab1fb1cedafc4edee380a810947d52e669a185b52636aa37" + ], + [ + "libassuan", + "ow5h7we5zrgoknsvss3yjjs4g3aci4b2", + "44cf47134b4e4cbad30b8f4ef5ac1e7e25ead1d4dc64bd44fe807a4f173977ad" + ], + [ + "libgcrypt", + "nuy3jjihjlktwggpwdrert2q5xoqk4ic", + "ebb85da4d0b4ea93e073b8faf11e4ec955752a589b0ee47cd46b825ef685e536" + ], + [ + "libgpg-error", + "w7xfbrbfdnssbfoxrsz4emt6aildxsfy", + "6973cd597db96830822a8111fe3b3cff271e8cedc26fb0cb48443c2de2cc50ad" + ], + [ + "libksba", + "74h62c57ojgmqqp6xrrrzmzgftmcv22c", + "73afeb0bfdf57623d694ea16b52e1d73bfca61954583d6737f4ab6ab05c92ca8" + ], + [ + "pinentry", + "dv7sj3xesjfhqbrcxorvbzoxzlqpac4e", + "509d6881145a33b7de69db63af84fe887e7c995ffd4e89003a25fafa45b5874b" + ], + [ + "gnupg", + "hrv7rjtbvuxkt4trjdnzovegwutciunv", + "bf39c84047508556e142b9a9808007bbcc9aa80b2b9936a3598530f5acc7c75a" + ] + ], + "spec": "gnupg@2.3: %apple-clang platform=darwin target=x86_64" + }, + { + "binaries": [ + [ + "zlib", + "mrdyh4e34orgypetqhru6romj6wlvyxm", + "ecd344c5dcae7377d8b20f14248a73d1fe350e54364f2f1e70aa4fccf1c219ed" + ], + [ + "libiconv", + "iuparzfnzuwmmhj5ytlhaobn4nz3cct4", + "58ef399a4bd8794a00314440e02de8c685c9c02d1b02a751923ae669556a1a91" + ], + [ + "npth", + "eltd4b6tq4gsnboeidmr7mykezykcho5", + "89b3e0c7f573009d4816b219413a07a9917758836befdfeb6c33a9e87d846b6f" + ], + [ + "libassuan", + "xfaguxawrc6z73draba5fccjxtxjvzmz", + "59ebe715532a2671cde9783aceebb1448062e7adb7307da30b0d6245529d897f" + ], + [ + "libgcrypt", + "ntb2fzwckdgb77eubdcvvj2xm5eilavw", + "92fb1ef0d57c98b16e172c6afbc995dd163f0bac1484eb11eef5305f434a5cd1" + ], + [ + "libgpg-error", + "utzxfplsbueqmj7ksxaykk6tk3xi5dmr", + "74aa95bc48c42eab0a8ca0afab51074811bf79477271123af13398029ac7394f" + ], + [ + "libksba", + "jzxmzebonsgrw5e6ij446azzocvko2vi", + "bfc11401fc94d3f6d3176fa4b95dd866ad355c0b77b9c5787acbfdffe42915b9" + ], + [ + "pinentry", + "wsjzc3l5zgieowd24p2paccrporun5cv", + "db3e475b2113ad9587017a76c9df57fc537d2dd6c5d3323119c30723b5b51330" + ], + [ + "gnupg", + "zigabpppmz5ctktqwdj5ueaxjuvm6syh", + "fd8a681dfa919d8faff256fabafe1f08238cc75c74cbcfc44acce23cf0afb34c" + ] + ], + "spec": "gnupg@2.3: %gcc platform=linux target=aarch64" + }, + { + "binaries": [ + [ + "zlib", + "c4kbhgxjlko6a367d3zl6b5qcm5swiew", + "49747756dea8dd15fc3ea8f73d03b24724fa6b22103f04b557152db59c17f799" + ], + [ + "libiconv", + "5l5cq7de7iwagndyyphpdmvdvp3pepe6", + "a46d2a89cab00d8196e6226f3831bc3ff8b7f728844d6d29013cc8999d7b7f78" + ], + [ + "npth", + "b6ifa47mma7n7mxl36yg73uwjqezbde5", + "1b16e28e692ca91a096da4976f7df451df5e3ea9aa2f03cc2d39f62646a9399b" + ], + [ + "libassuan", + "phds2cjgeo3sbluuvdj6ebdkuom6un6p", + "482bf3a4975e21e03b7d34ff69031071a2822fb182774421f648ed7ccc99f24d" + ], + [ + "libgcrypt", + "7hgqgoekgh4jiml2u55rg2zec3ouyq7z", + "edfa277010de9f060bbcb11c2011dd66fb6e714c28a189d7cd7ef2d825e85180" + ], + [ + "libgpg-error", + "th2tzwwoz7ddrygkjrxzzv4yvznxglmx", + "e7c645287270ae2ac08ff5d400bf44b2e79203e752c3ff32aed07200638a6fe0" + ], + [ + "libksba", + "ex5gt36shiwt54jg7mbgxysnwu7jjy6a", + "8cf350544821bfec19e2b52a47896ca9258fc56680e4bb0d12715416169ead4a" + ], + [ + "pinentry", + "aowc7abd6kvohdohxz4j225q2hh743cq", + "ad336a7eee41eebd6b8e667e7ef673b64088c0553492567245653ac6c07fdb46" + ], + [ + "gnupg", + "7i7j24llnlzwpwrfumulorq6ucx2ku2f", + "a743ffd0698db5329a8231d25fa2e13b88f63cf85198664794a91df7a2c48632" + ] + ], + "spec": "gnupg@2.3: %gcc platform=linux target=ppc64le" + }, + { + "binaries": [ + [ + "libiconv", + "vyvyow3bnokashj3wntl7pgm5nc4h7vw", + "4fb8c1a563975f339b2e98e4c5c6cd98d629bc94fcf57b8e92beedae17a4584d" + ], + [ + "npth", + "opncvl75zv6njawkgtxgt4yhii65f5nx", + "24b442a6f2cc28176a4f742d961807e5ffd853d2f9d65175944b6aa8b47d91e2" + ], + [ + "zlib", + "dcixs2nytw7vlthk55mwvog7veypnuor", + "6ab7018b621783c971192e46b6a3e2764b638b5ab5c2f3c62af24afd5a9039e0" + ], + [ + "libassuan", + "yk2555moxgj3dro6edznumguezecriso", + "ebde470fee06e5ad7527dca0eb3689ae13b7299229b51e64f97ff87b9daf9160" + ], + [ + "libgcrypt", + "imws5ss7coeeo45zr6w54xnwjfjm4cc6", + "ad20c2974c90717efa8a4c27781e5f4c14d60527dc1c224fd2e113fe52d3e958" + ], + [ + "libgpg-error", + "nbhvf75esgtjeu6nh57gu6mnikiazmjt", + "ec9f59c684dc4054706217952b8ddf610e4277ec8031c92640f086959dcf756e" + ], + [ + "libksba", + "cx425tk5tnod3523zj4izloqibr44frz", + "b2465fecbca3d022cf068766a9c01c72f6a68f9b58e78375f687b1273f6c683c" + ], + [ + "pinentry", + "pto3uq53xwl7dtbvycdp4qccacrrzs3r", + "bd9ae21dff99c34165baa680df4b4b36339e207fec2ac4fcc80103d774a1dd84" + ], + [ + "gnupg", + "5mhxefklns5hpdai3jn3rsf23kz4nol6", + "8a21155078dc51fdee7990326335e9f99192da0eb4b3490260a7399e30f20243" + ] + ], + "spec": "gnupg@2.3: %gcc platform=linux target=x86_64" + } + ] +} \ No newline at end of file diff --git a/share/spack/bootstrap/github-actions-v0.2/metadata.yaml b/share/spack/bootstrap/github-actions-v0.4/metadata.yaml similarity index 83% rename from share/spack/bootstrap/github-actions-v0.2/metadata.yaml rename to share/spack/bootstrap/github-actions-v0.4/metadata.yaml index f786731aa8f..0b483b547b2 100644 --- a/share/spack/bootstrap/github-actions-v0.2/metadata.yaml +++ b/share/spack/bootstrap/github-actions-v0.4/metadata.yaml @@ -3,6 +3,6 @@ description: | Buildcache generated from a public workflow using Github Actions. The sha256 checksum of binaries is checked before installation. info: - url: https://mirror.spack.io/bootstrap/github-actions/v0.2 + url: https://mirror.spack.io/bootstrap/github-actions/v0.4 homepage: https://github.com/spack/spack-bootstrap-mirrors releases: https://github.com/spack/spack-bootstrap-mirrors/releases diff --git a/share/spack/bootstrap/github-actions-v0.4/patchelf.json b/share/spack/bootstrap/github-actions-v0.4/patchelf.json new file mode 100644 index 00000000000..cab42851089 --- /dev/null +++ b/share/spack/bootstrap/github-actions-v0.4/patchelf.json @@ -0,0 +1,34 @@ +{ + "verified": [ + { + "binaries": [ + [ + "patchelf", + "kjmrsrd7akfwzlejzsdyoun7fwgmvjgk", + "2c1975adb6fbd42bdb960b67fa6b32bc2846a28e5d293d2ca7b44a38f49ecf4f" + ] + ], + "spec": "patchelf@0.13: %gcc platform=linux target=aarch64" + }, + { + "binaries": [ + [ + "patchelf", + "gxxogiws7fmzkbdc26k24id3aplly6wi", + "d45ac6b9045d510861fda0cfaa5c04d71f316df5784376f2d2915ab134619c1b" + ] + ], + "spec": "patchelf@0.13: %gcc platform=linux target=ppc64le" + }, + { + "binaries": [ + [ + "patchelf", + "p72zyan5wrzuabtmzq7isa5mzyh6ahdp", + "ed7ebae3399d96c8d2f4b38ce6f2da52d8b73b312c73babae880ed3467b464b4" + ] + ], + "spec": "patchelf@0.13: %gcc platform=linux target=x86_64" + } + ] +} \ No newline at end of file From 30da20c1bc61402964fb1aa750db8b5246d954a9 Mon Sep 17 00:00:00 2001 From: "Jose E. Roman" Date: Thu, 3 Nov 2022 10:58:16 +0100 Subject: [PATCH 320/442] New patch release SLEPc 3.18.1 (#33661) --- var/spack/repos/builtin/packages/py-slepc4py/package.py | 1 + var/spack/repos/builtin/packages/slepc/package.py | 1 + 2 files changed, 2 insertions(+) diff --git a/var/spack/repos/builtin/packages/py-slepc4py/package.py b/var/spack/repos/builtin/packages/py-slepc4py/package.py index 3d8f8d2b2e6..985159e822b 100644 --- a/var/spack/repos/builtin/packages/py-slepc4py/package.py +++ b/var/spack/repos/builtin/packages/py-slepc4py/package.py @@ -16,6 +16,7 @@ class PySlepc4py(PythonPackage): maintainers = ["joseeroman", "balay"] version("main", branch="main") + version("3.18.1", sha256="4c2bc0947d6a9cdb209e3174b7f54fe7b029220e2c90106f52844e8f8795f8f0") version("3.18.0", sha256="aa83f46f942aca05ffcbc8be29b496f56837f564e0396f5b39cec4946654ee78") version("3.17.2", sha256="e5b235486b6901cd4ff0d94083f0e5eeacaef3a2893e1714769717ad488a3885") version("3.17.1", sha256="967d5d045526088ff5b7b2cde76f8b4d1fee3a2a68481f85224b0795e6613eb9") diff --git a/var/spack/repos/builtin/packages/slepc/package.py b/var/spack/repos/builtin/packages/slepc/package.py index bd8fa1e4ed9..48590e36c67 100644 --- a/var/spack/repos/builtin/packages/slepc/package.py +++ b/var/spack/repos/builtin/packages/slepc/package.py @@ -22,6 +22,7 @@ class Slepc(Package, CudaPackage, ROCmPackage): test_requires_compiler = True version("main", branch="main") + version("3.18.1", sha256="f6e6e16d8399c3f94d187da9d4bfdfca160de50ebda7d63f6fa8ef417597e9b4") version("3.18.0", sha256="18af535d979a646363df01f407c75f0e3b0dd97b3fdeb20dca25b30cd89239ee") version("3.17.2", sha256="f784cca83a14156631d6e0f5726ca0778e259e1fe40c927607d5fb12d958d705") version("3.17.1", sha256="11386cd3f4c0f9727af3c1c59141cc4bf5f83bdf7c50251de0845e406816f575") From 243dfe91e970e9a3f6c34e3c679ae78ec74f321e Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Thu, 3 Nov 2022 11:34:24 +0100 Subject: [PATCH 321/442] Use spack.traverse.traverse_nodes where useful (#33677) --- lib/spack/spack/environment/environment.py | 78 +++++++++------------- 1 file changed, 33 insertions(+), 45 deletions(-) diff --git a/lib/spack/spack/environment/environment.py b/lib/spack/spack/environment/environment.py index 1353b76b566..44d67854569 100644 --- a/lib/spack/spack/environment/environment.py +++ b/lib/spack/spack/environment/environment.py @@ -34,6 +34,7 @@ import spack.stage import spack.store import spack.subprocess_context +import spack.traverse import spack.user_environment as uenv import spack.util.cpus import spack.util.environment @@ -1760,22 +1761,14 @@ def install_specs(self, specs=None, **install_args): def all_specs(self): """Return all specs, even those a user spec would shadow.""" - all_specs = set() - for h in self.concretized_order: - try: - spec = self.specs_by_hash[h] - except KeyError: - tty.warn( - "Environment %s appears to be corrupt: missing spec " '"%s"' % (self.name, h) - ) - continue - all_specs.update(spec.traverse()) - - return sorted(all_specs) + roots = [self.specs_by_hash[h] for h in self.concretized_order] + specs = [s for s in spack.traverse.traverse_nodes(roots, lambda s: s.dag_hash())] + specs.sort() + return specs def all_hashes(self): """Return hashes of all specs.""" - return list(set(s.dag_hash() for s in self.all_specs())) + return [s.dag_hash() for s in self.all_specs()] def roots(self): """Specs explicitly requested by the user *in this environment*. @@ -1812,11 +1805,10 @@ def concretized_specs(self): def get_by_hash(self, dag_hash): matches = {} - for _, root in self.concretized_specs(): - for spec in root.traverse(root=True): - dep_hash = spec.dag_hash() - if dep_hash.startswith(dag_hash): - matches[dep_hash] = spec + roots = [self.specs_by_hash[h] for h in self.concretized_order] + for spec in spack.traverse.traverse_nodes(roots, key=lambda s: s.dag_hash()): + if spec.dag_hash().startswith(dag_hash): + matches[spec.dag_hash()] = spec return list(matches.values()) def get_one_by_hash(self, dag_hash): @@ -1918,28 +1910,27 @@ def _get_environment_specs(self, recurse_dependencies=True): If these specs appear under different user_specs, only one copy is added to the list returned. """ - spec_list = list() + specs = [self.specs_by_hash[h] for h in self.concretized_order] - for spec_hash in self.concretized_order: - spec = self.specs_by_hash[spec_hash] + if recurse_dependencies: + specs.extend( + spack.traverse.traverse_nodes( + specs, root=False, deptype=("link", "run"), key=lambda s: s.dag_hash() + ) + ) - specs = spec.traverse(deptype=("link", "run")) if recurse_dependencies else (spec,) - - spec_list.extend(specs) - - return spec_list + return specs def _to_lockfile_dict(self): """Create a dictionary to store a lockfile for this environment.""" concrete_specs = {} - for spec in self.specs_by_hash.values(): - for s in spec.traverse(): - dag_hash = s.dag_hash() - if dag_hash not in concrete_specs: - spec_dict = s.node_dict_with_hashes(hash=ht.dag_hash) - # Assumes no legacy formats, since this was just created. - spec_dict[ht.dag_hash.name] = s.dag_hash() - concrete_specs[dag_hash] = spec_dict + for s in spack.traverse.traverse_nodes( + self.specs_by_hash.values(), key=lambda s: s.dag_hash() + ): + spec_dict = s.node_dict_with_hashes(hash=ht.dag_hash) + # Assumes no legacy formats, since this was just created. + spec_dict[ht.dag_hash.name] = s.dag_hash() + concrete_specs[s.dag_hash()] = spec_dict hash_spec_list = zip(self.concretized_order, self.concretized_user_specs) @@ -2050,19 +2041,16 @@ def write(self, regenerate=True): # ensure the prefix/.env directory exists fs.mkdirp(self.env_subdir_path) - for spec in self.new_specs: - for dep in spec.traverse(): - if not dep.concrete: - raise ValueError( - "specs passed to environment.write() " "must be concrete!" - ) + for spec in spack.traverse.traverse_nodes(self.new_specs): + if not spec.concrete: + raise ValueError("specs passed to environment.write() " "must be concrete!") - root = os.path.join(self.repos_path, dep.namespace) - repo = spack.repo.create_or_construct(root, dep.namespace) - pkg_dir = repo.dirname_for_package_name(dep.name) + root = os.path.join(self.repos_path, spec.namespace) + repo = spack.repo.create_or_construct(root, spec.namespace) + pkg_dir = repo.dirname_for_package_name(spec.name) - fs.mkdirp(pkg_dir) - spack.repo.path.dump_provenance(dep, pkg_dir) + fs.mkdirp(pkg_dir) + spack.repo.path.dump_provenance(spec, pkg_dir) self._update_and_write_manifest(raw_yaml_dict, yaml_dict) From 68a5fe84a7f814af7f1c54f9701f33c5f4b2cd17 Mon Sep 17 00:00:00 2001 From: Mikael Simberg Date: Thu, 3 Nov 2022 12:28:38 +0100 Subject: [PATCH 322/442] Add pika 0.10.0 (#33659) Co-authored-by: Harmen Stoppels --- var/spack/repos/builtin/packages/pika/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/pika/package.py b/var/spack/repos/builtin/packages/pika/package.py index c4b2be6a683..8c4c7202cd2 100644 --- a/var/spack/repos/builtin/packages/pika/package.py +++ b/var/spack/repos/builtin/packages/pika/package.py @@ -17,6 +17,7 @@ class Pika(CMakePackage, CudaPackage, ROCmPackage): git = "https://github.com/pika-org/pika.git" maintainers = ["msimberg", "albestro", "teonnik", "aurianer"] + version("0.10.0", sha256="3b443b8f0f75b9a558accbaef0334a113a71b0205770e6c7ff02ea2d7c6aca5b") version("0.9.0", sha256="c349b2a96476d6974d2421288ca4d2e14ef9e5897d44cd7d5343165faa2d1299") version("0.8.0", sha256="058e82d7c8f95badabe52bbb4682d55aadf340d67ced1226c0673b4529adc182") version("0.7.0", sha256="e1bf978c88515f7af28ee47f98b795ffee521c15b39877ea4cfb405f31d507ed") From 9925f3b77910dfbe4bd922032c253a1e1c1ced1f Mon Sep 17 00:00:00 2001 From: snehring <7978778+snehring@users.noreply.github.com> Date: Thu, 3 Nov 2022 10:29:59 -0500 Subject: [PATCH 323/442] isescan: add version 1.7.2.3 (#33675) --- var/spack/repos/builtin/packages/isescan/package.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/isescan/package.py b/var/spack/repos/builtin/packages/isescan/package.py index c109f68ce19..4c9eafacb62 100644 --- a/var/spack/repos/builtin/packages/isescan/package.py +++ b/var/spack/repos/builtin/packages/isescan/package.py @@ -11,8 +11,9 @@ class Isescan(Package): genome and metagenome""" homepage = "https://github.com/xiezhq/ISEScan" - url = "https://github.com/xiezhq/ISEScan/archive/v1.7.2.1.tar.gz" + url = "https://github.com/xiezhq/ISEScan/archive/refs/tags/v1.7.2.1.tar.gz" + version("1.7.2.3", sha256="90ef6bc660e471347f65864bd3563f769ed4b79b1a932195f353c5e86351ab05") version("1.7.2.1", sha256="b971a3e86a8cddaa4bcd520ba9e75425bbe93190466f81a3791ae0cb4baf5e5d") depends_on("python@3.3.3:", type="run") From 16acd25053a79fa5d23fda48ed0444a069ccdd22 Mon Sep 17 00:00:00 2001 From: Greg Sjaardema Date: Thu, 3 Nov 2022 09:42:25 -0600 Subject: [PATCH 324/442] SEACAS: further refactor (#33673) * SEACAS: Update package.py to handle new SEACAS project name The base project name for the SEACAS project has changed from "SEACASProj" to "SEACAS" as of @2022-10-14, so the package needed to be updated to use the new project name when needed. The refactor also changes several: "-DSome_CMAKE_Option:BOOL=ON" to define("Some_CMAKE_Option", True) * SEACAS: Additional refactorings * Replaced all cmake "-Dsomething=other" lines with either `define` or `define_from_variant` functions. Consolidated the application (fortran, legacy, all) enabling lines into loops over the code names. Easier to see categorization of applications and also to add/move/remove an application Reordered some lines; general cleanup and restructuring. * Address flake8 issues * Remove trailing whitespace * Reformat using black --- .../repos/builtin/packages/seacas/package.py | 224 ++++++++---------- 1 file changed, 97 insertions(+), 127 deletions(-) diff --git a/var/spack/repos/builtin/packages/seacas/package.py b/var/spack/repos/builtin/packages/seacas/package.py index 92951501484..a94130893c1 100644 --- a/var/spack/repos/builtin/packages/seacas/package.py +++ b/var/spack/repos/builtin/packages/seacas/package.py @@ -129,24 +129,31 @@ class Seacas(CMakePackage): variant("x11", default=True, description="Compile with X11") # ###################### Dependencies ########################## + depends_on("cmake@3.17:", type="build") + depends_on("mpi", when="+mpi") + + # Always depends on netcdf-c depends_on("netcdf-c@4.8.0:+mpi+parallel-netcdf", when="+mpi") depends_on("netcdf-c@4.8.0:~mpi", when="~mpi") depends_on("hdf5+hl~mpi", when="~mpi") - depends_on("cgns@4.2.0:+mpi+scoping", when="+cgns +mpi") - depends_on("cgns@4.2.0:~mpi+scoping", when="+cgns ~mpi") + depends_on("fmt@8.1.0:", when="@2022-03-04:2022-05-16") depends_on("fmt@9.1.0:", when="@2022-10-14") + depends_on("matio", when="+matio") + depends_on("libx11", when="+x11") + + with when("+cgns"): + depends_on("cgns@4.2.0:+mpi+scoping", when="+mpi") + depends_on("cgns@4.2.0:~mpi+scoping", when="~mpi") with when("+adios2"): depends_on("adios2@master") depends_on("adios2~mpi", when="~mpi") depends_on("adios2+mpi", when="+mpi") - depends_on("matio", when="+matio") with when("+metis"): depends_on("metis+int64+real64") depends_on("parmetis+int64", when="+mpi") - depends_on("libx11", when="+x11") # The Faodel TPL is only supported in seacas@2021-04-05: depends_on("faodel@1.2108.1:+mpi", when="+faodel +mpi") @@ -157,11 +164,6 @@ class Seacas(CMakePackage): msg="The Faodel TPL is only compatible with @2021-04-05 and later.", ) - # MPI related dependencies - depends_on("mpi", when="+mpi") - - depends_on("cmake@3.1:", type="build") - def setup_run_environment(self, env): env.prepend_path("PYTHONPATH", self.prefix.lib) @@ -181,41 +183,30 @@ def cmake_args(self): options.extend( [ + define(project_name_base + "_ENABLE_TESTS", True), + define(project_name_base + "_ENABLE_CXX11", True), + define(project_name_base + "_ENABLE_Kokkos", False), + define(project_name_base + "_HIDE_DEPRECATED_CODE", False), from_variant("CMAKE_INSTALL_RPATH_USE_LINK_PATH", "shared"), from_variant("BUILD_SHARED_LIBS", "shared"), from_variant("SEACASExodus_ENABLE_THREADSAFE", "thread_safe"), from_variant("SEACASIoss_ENABLE_THREADSAFE", "thread_safe"), from_variant("TPL_ENABLE_X11", "x11"), - ] - ) - - if "+mpi" in spec: - options.extend( - [ - "-DCMAKE_C_COMPILER=%s" % spec["mpi"].mpicc, - "-DCMAKE_CXX_COMPILER=%s" % spec["mpi"].mpicxx, - "-DCMAKE_Fortran_COMPILER=%s" % spec["mpi"].mpifc, - define("TPL_ENABLE_MPI", True), - "-DMPI_BASE_DIR:PATH=%s" % spec["mpi"].prefix, - ] - ) - else: - options.extend( - [ - define("TPL_ENABLE_MPI", False), - ] - ) - - options.extend( - [ - define(project_name_base + "_ENABLE_TESTS", True), - define(project_name_base + "_ENABLE_CXX11", True), - define(project_name_base + "_ENABLE_Kokkos", False), - define(project_name_base + "_HIDE_DEPRECATED_CODE", False), from_variant(project_name_base + "_ENABLE_Fortran", "fortran"), ] ) + options.append(from_variant("TPL_ENABLE_MPI", "mpi")) + if "+mpi" in spec: + options.extend( + [ + define("CMAKE_C_COMPILER", spec["mpi"].mpicc), + define("CMAKE_CXX_COMPILER", spec["mpi"].mpicxx), + define("CMAKE_Fortran_COMPILER", spec["mpi"].mpifc), + define("MPI_BASE_DIR", spec["mpi"].prefix), + ] + ) + # ########## What applications should be built ############# # Check whether they want everything; if so, do the easy way... if "+applications" in spec and "+legacy" in spec: @@ -242,56 +233,62 @@ def cmake_args(self): ) if "+applications" in spec: - options.extend( - [ - define(project_name_base + "_ENABLE_SEACASAprepro", True), - define(project_name_base + "_ENABLE_SEACASAprepro_lib", True), - define(project_name_base + "_ENABLE_SEACASConjoin", True), - define(project_name_base + "_ENABLE_SEACASCpup", True), - define(project_name_base + "_ENABLE_SEACASEjoin", True), - define(project_name_base + "_ENABLE_SEACASEpu", True), - define(project_name_base + "_ENABLE_SEACASExo2mat", True), - define(project_name_base + "_ENABLE_SEACASExo_format", True), - define(project_name_base + "_ENABLE_SEACASExodiff", True), - from_variant(project_name_base + "_ENABLE_SEACASExplore", "fortran"), - from_variant(project_name_base + "_ENABLE_SEACASGrepos", "fortran"), - define(project_name_base + "_ENABLE_SEACASMat2exo", True), - define(project_name_base + "_ENABLE_SEACASNas2exo", True), - define(project_name_base + "_ENABLE_SEACASNemslice", True), - define(project_name_base + "_ENABLE_SEACASNemspread", True), - define(project_name_base + "_ENABLE_SEACASSlice", True), - define(project_name_base + "_ENABLE_SEACASZellij", True), - ] - ) + # C / C++ applications + for app in ( + "Aprepro", + "Aprepro_lib", + "Conjoin", + "Cpup", + "Ejoin", + "Epu", + "Exo2mat", + "Exo_format", + "Exodiff", + "Mat2exo", + "Nas2exo", + "Nemslice", + "Nemspread", + "Slice", + "Zellij", + ): + options.append(define(project_name_base + "_ENABLE_SEACAS" + app, True)) + # Fortran-based applications + for app in ("Explore", "Grepos"): + options.append( + from_variant(project_name_base + "_ENABLE_SEACAS" + app, "fortran") + ) if "+legacy" in spec: - options.extend( - [ - define(project_name_base + "_ENABLE_SEACASNemesis", True), - from_variant(project_name_base + "_ENABLE_SEACASAlgebra", "fortran"), - from_variant(project_name_base + "_ENABLE_SEACASBlot", "fortran"), - from_variant(project_name_base + "_ENABLE_SEACASEx1ex2v2", "fortran"), - from_variant(project_name_base + "_ENABLE_SEACASEx2ex1v2", "fortran"), - from_variant(project_name_base + "_ENABLE_SEACASExomatlab", "fortran"), - from_variant(project_name_base + "_ENABLE_SEACASExotec2", "fortran"), - from_variant(project_name_base + "_ENABLE_SEACASExotxt", "fortran"), - from_variant(project_name_base + "_ENABLE_SEACASFastq", "fortran"), - from_variant(project_name_base + "_ENABLE_SEACASGen3D", "fortran"), - from_variant(project_name_base + "_ENABLE_SEACASGenshell", "fortran"), - from_variant(project_name_base + "_ENABLE_SEACASGjoin", "fortran"), - from_variant(project_name_base + "_ENABLE_SEACASMapvar", "fortran"), - from_variant(project_name_base + "_ENABLE_SEACASMapvar-kd", "fortran"), - from_variant(project_name_base + "_ENABLE_SEACASNumbers", "fortran"), - from_variant(project_name_base + "_ENABLE_SEACASTxtexo", "fortran"), - ] - ) + # Legacy applications -- all are fortran-based except Nemesis + options.append(define(project_name_base + "_ENABLE_SEACASNemesis", True)) + + for app in ( + "Algebra", + "Blot", + "Ex1ex2v2", + "Ex2ex1v2", + "Exomatlab", + "Exotec2", + "Exotxt", + "Fastq", + "Gen3D", + "Genshell", + "Gjoin", + "Mapvar", + "Mapvar-kd", + "Numbers", + "Txtexo", + ): + options.append( + from_variant(project_name_base + "_ENABLE_SEACAS" + app, "fortran") + ) # ##################### Dependencies ########################## # Always need NetCDF-C options.extend( [ define("TPL_ENABLE_Netcdf", True), - "-DNetCDF_ROOT:PATH=%s" % spec["netcdf-c"].prefix, + define("NetCDF_ROOT", spec["netcdf-c"].prefix), ] ) @@ -299,24 +296,28 @@ def cmake_args(self): options.extend( [ define("TPL_ENABLE_METIS", True), - "-DMETIS_LIBRARY_DIRS=%s" % spec["metis"].prefix.lib, - "-DMETIS_LIBRARY_NAMES=metis", - "-DTPL_METIS_INCLUDE_DIRS=%s" % spec["metis"].prefix.include, + define("METIS_LIBRARY_DIRS", spec["metis"].prefix.lib), + define("METIS_LIBRARY_NAMES", "metis"), + define("TPL_METIS_INCLUDE_DIRS", spec["metis"].prefix.include), define("TPL_ENABLE_ParMETIS", True), - "-DParMETIS_LIBRARY_DIRS=%s;%s" - % (spec["parmetis"].prefix.lib, spec["metis"].prefix.lib), - "-DParMETIS_LIBRARY_NAMES=parmetis;metis", - "-DTPL_ParMETIS_INCLUDE_DIRS=%s;%s" - % (spec["parmetis"].prefix.include, spec["metis"].prefix.include), + define( + "ParMETIS_LIBRARY_DIRS", + [spec["parmetis"].prefix.lib, spec["metis"].prefix.lib], + ), + define("ParMETIS_LIBRARY_NAMES", ["parmetis", "metis"]), + define( + "TPL_ParMETIS_INCLUDE_DIRS", + [spec["parmetis"].prefix.include, spec["metis"].prefix.include], + ), ] ) elif "+metis" in spec: options.extend( [ define("TPL_ENABLE_METIS", True), - "-DMETIS_LIBRARY_DIRS=%s" % spec["metis"].prefix.lib, - "-DMETIS_LIBRARY_NAMES=metis", - "-DTPL_METIS_INCLUDE_DIRS=%s" % spec["metis"].prefix.include, + define("METIS_LIBRARY_DIRS", spec["metis"].prefix.lib), + define("METIS_LIBRARY_NAMES", "metis"), + define("TPL_METIS_INCLUDE_DIRS", spec["metis"].prefix.include), define("TPL_ENABLE_ParMETIS", False), ] ) @@ -328,59 +329,28 @@ def cmake_args(self): ] ) + options.append(from_variant("TPL_ENABLE_Matio", "matio")) if "+matio" in spec: - options.extend( - [ - define("TPL_ENABLE_Matio", True), - "-DMatio_ROOT:PATH=%s" % spec["matio"].prefix, - ] - ) - else: - options.extend( - [ - define("TPL_ENABLE_Matio", False), - ] - ) + options.append(define("Matio_ROOT", spec["matio"].prefix)) + options.append(from_variant("TPL_ENABLE_CGNS", "cgns")) if "+cgns" in spec: - options.extend( - [ - define("TPL_ENABLE_CGNS", True), - "-DCGNS_ROOT:PATH=%s" % spec["cgns"].prefix, - ] - ) - else: - options.extend( - [ - define("TPL_ENABLE_CGNS", False), - ] - ) + options.append(define("CGNS_ROOT", spec["cgns"].prefix)) options.append(from_variant("TPL_ENABLE_Faodel", "faodel")) - for pkg in ("Faodel", "BOOST"): if pkg.lower() in spec: options.append(define(pkg + "_ROOT", spec[pkg.lower()].prefix)) + options.append(from_variant("TPL_ENABLE_ADIOS2", "adios2")) if "+adios2" in spec: - options.extend( - [ - define("TPL_ENABLE_ADIOS2", True), - "-DADIOS2_ROOT:PATH=%s" % spec["adios2"].prefix, - ] - ) - else: - options.extend( - [ - define("TPL_ENABLE_ADIOS2", False), - ] - ) + options.append(define("ADIOS2_ROOT", spec["adios2"].prefix)) # ################# RPath Handling ###################### if sys.platform == "darwin" and macos_version() >= Version("10.12"): # use @rpath on Sierra due to limit of dynamic loader - options.append("-DCMAKE_MACOSX_RPATH:BOOL=ON") + options.append(define("CMAKE_MACOSX_RPATH", True)) else: - options.append("-DCMAKE_INSTALL_NAME_DIR:PATH=%s" % self.prefix.lib) + options.append(define("CMAKE_INSTALL_NAME_DIR", self.prefix.lib)) return options From ca93c8b57a7a34644b95a13eeda7190f432710df Mon Sep 17 00:00:00 2001 From: Cyrus Harrison Date: Thu, 3 Nov 2022 10:33:59 -0700 Subject: [PATCH 325/442] fides: remove unneeded variants (#32521) --- var/spack/repos/builtin/packages/fides/package.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/var/spack/repos/builtin/packages/fides/package.py b/var/spack/repos/builtin/packages/fides/package.py index a62be5696a4..2acfdb5eaec 100644 --- a/var/spack/repos/builtin/packages/fides/package.py +++ b/var/spack/repos/builtin/packages/fides/package.py @@ -18,17 +18,14 @@ class Fides(CMakePackage): version("master", branch="master") version("1.1.0", sha256="40d2e08b8d5cfdfc809eae6ed2ae0731108ce3b1383485f4934a5ec8aaa9425e") version("1.0.0", sha256="c355fdb4ca3790c1fa9a4491a0d294b8f883b6946c540ad9e5633c9fd8c8c3aa") - variant("mpi", default=True, description="build mpi support") - variant("adios2", default=True, description="build ADIOS2 support") - variant("vtk-m", default=True, description="build VTK-m support") # Certain CMake versions have been found to break for our use cases depends_on("cmake@3.14.1:3.14,3.18.2:", type="build") depends_on("mpi", when="+mpi") - depends_on("adios2~zfp", when="+adios2") - depends_on("vtk-m@:1.7", when="+vtk-m") + depends_on("adios2~zfp") + depends_on("vtk-m") # Fix missing implicit includes @when("%gcc@7:") From da020d1bb8bcb56ce66002290c5296807856e1b4 Mon Sep 17 00:00:00 2001 From: Nicolas Cornu Date: Thu, 3 Nov 2022 18:34:15 +0100 Subject: [PATCH 326/442] Bump HighFive to v2.5.0 (#33691) * Bump HighFive to v2.5.0 * Adding myself as maintainers * fix format with black --- var/spack/repos/builtin/packages/highfive/package.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/var/spack/repos/builtin/packages/highfive/package.py b/var/spack/repos/builtin/packages/highfive/package.py index 0b719175f43..d52d6cfff93 100644 --- a/var/spack/repos/builtin/packages/highfive/package.py +++ b/var/spack/repos/builtin/packages/highfive/package.py @@ -13,13 +13,17 @@ class Highfive(CMakePackage): homepage = "https://github.com/BlueBrain/HighFive" url = "https://github.com/BlueBrain/HighFive/archive/v1.2.tar.gz" + maintainers = ["alkino"] + version("2.5.0", sha256="27f55596570df3cc8b878a1681a0d4ba0fe2e3da4a0ef8d436722990d77dc93a") version("2.4.1", sha256="6826471ef5c645ebf947d29574b302991525a8a8ff1ef687aba7311d9a0ea36f") + version("2.4.0", sha256="ba0ed6d8e2e09e80849926f38c15a26cf4b80772084cea0555269a25fec02149") version("2.3.1", sha256="41728a1204bdfcdcef8cbc3ddffe5d744c5331434ce3dcef35614b831234fcd7") version("2.3", sha256="7da6815646eb4294f210cec6be24c9234d7d6ceb2bf92a01129fbba6583c5349") version("2.2.2", sha256="5bfb356705c6feb9d46a0507573028b289083ec4b4607a6f36187cb916f085a7") version("2.2.1", sha256="964c722ba916259209083564405ef9ce073b15e9412955fef9281576ea9c5b85") version("2.2", sha256="fe065f2443e38444100b43999a96916e81a0aa7e500cf768d3bf6f8392b8efee") + version("2.1.1", sha256="52cffeda0d018f020f48e5460c051d5c2031c3a3c82133a21527f186a0c1650e") version("2.0", sha256="deee33d7f578e33dccb5d04771f4e01b89a980dd9a3ff449dd79156901ee8d25") version("1.5", sha256="f194bda482ab15efa7c577ecc4fb7ee519f6d4bf83470acdb3fb455c8accb407") version("1.2", sha256="4d8f84ee1002e8fd6269b62c21d6232aea3d56ce4171609e39eb0171589aab31") From 08bee718a26c96ceffd228e4917358570239ede1 Mon Sep 17 00:00:00 2001 From: Miroslav Stoyanov <30537612+mkstoyanov@users.noreply.github.com> Date: Thu, 3 Nov 2022 14:28:08 -0400 Subject: [PATCH 327/442] new cmake requirement (#33679) --- var/spack/repos/builtin/packages/heffte/package.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/var/spack/repos/builtin/packages/heffte/package.py b/var/spack/repos/builtin/packages/heffte/package.py index a5695e239e7..2c9424ca34b 100644 --- a/var/spack/repos/builtin/packages/heffte/package.py +++ b/var/spack/repos/builtin/packages/heffte/package.py @@ -35,6 +35,8 @@ class Heffte(CMakePackage, CudaPackage, ROCmPackage): patch("fortran200.patch", when="@2.0.0") depends_on("cmake@3.10:", type=("build", "run")) + depends_on("cmake@3.19:", when="@develop", type=("build", "run")) + depends_on("cmake@3.21:", when="@develop+rocm", type=("build", "run")) variant("shared", default=True, description="Builds with shared libraries") variant("fftw", default=False, description="Builds with support for FFTW backend") @@ -63,8 +65,10 @@ class Heffte(CMakePackage, CudaPackage, ROCmPackage): depends_on("fftw@3.3.8:", when="+fftw", type=("build", "run")) depends_on("intel-mkl@2018.0.128:", when="+mkl", type=("build", "run")) depends_on("cuda@8.0:", when="+cuda", type=("build", "run")) - depends_on("hip@3.8.0:", when="+rocm") - depends_on("rocfft@3.8.0:", when="+rocm") + depends_on("hip@3.8.0:", when="+rocm", type=("build", "run")) + depends_on("rocfft@3.8.0:", when="+rocm", type=("build", "run")) + depends_on("hip@5.2.3:", when="@develop+rocm", type=("build", "run")) + depends_on("rocfft@5.2.3:", when="@develop+rocm", type=("build", "run")) depends_on("magma@2.5.3:", when="+cuda+magma", type=("build", "run")) depends_on("magma+rocm@2.6.1:", when="+magma+rocm @2.1:", type=("build", "run")) depends_on("hipblas@3.8:", when="+magma+rocm", type=("build", "run")) @@ -141,6 +145,9 @@ def test(self): cmake_dir, ] if "+rocm" in self.spec: + options.append( + "-Dhip_DIR=" + join_path(self.spec["hip"].prefix, "lib", "cmake", "hip") + ) options.append( "-DAMDDeviceLibs_DIR=" + join_path(self.spec["llvm-amdgpu"].prefix, "lib", "cmake", "AMDDeviceLibs") From b55509ffa89f847df3c24ff2a90ce8a11d154a96 Mon Sep 17 00:00:00 2001 From: Scott Wittenburg Date: Thu, 3 Nov 2022 13:33:52 -0600 Subject: [PATCH 328/442] gitlab: Prune untouched specs less aggressively (#33669) Untouched spec pruning was added to reduce the number of specs developers see getting rebuilt in their PR pipelines that they don't understand. Because the state of the develop mirror lags quite far behind the tip of the develop branch, PRs often find they need to rebuild things untouched by their PR. Untouched spec pruning was previously implemented by finding all specs in the environment with names of packages touched by the PR, traversing in both directions the DAGS of those specs, and adding all dependencies as well as dependents to a list of concrete specs that should not be considered for pruning. We found that this heuristic results in too many pruned specs, and that dependents of touched specs must have all their dependencies added to the list of specs that should not be considered for pruning. --- lib/spack/spack/ci.py | 42 ++++++++++++++++++---------------- lib/spack/spack/test/ci.py | 11 +++++---- lib/spack/spack/test/cmd/ci.py | 4 ++-- 3 files changed, 31 insertions(+), 26 deletions(-) diff --git a/lib/spack/spack/ci.py b/lib/spack/spack/ci.py index bec7a2f38b6..56b3b249ac3 100644 --- a/lib/spack/spack/ci.py +++ b/lib/spack/spack/ci.py @@ -515,38 +515,36 @@ def compute_affected_packages(rev1="HEAD^", rev2="HEAD"): return spack.repo.get_all_package_diffs("ARC", rev1=rev1, rev2=rev2) -def get_spec_filter_list(env, affected_pkgs, dependencies=True, dependents=True): - """Given a list of package names, and assuming an active and - concretized environment, return a set of concrete specs from - the environment corresponding to any of the affected pkgs (or - optionally to any of their dependencies/dependents). +def get_spec_filter_list(env, affected_pkgs): + """Given a list of package names and an active/concretized + environment, return the set of all concrete specs from the + environment that could have been affected by changing the + list of packages. Arguments: env (spack.environment.Environment): Active concrete environment affected_pkgs (List[str]): Affected package names - dependencies (bool): Include dependencies of affected packages - dependents (bool): Include dependents of affected pacakges Returns: - A list of concrete specs from the active environment including - those associated with affected packages, and possible their - dependencies and dependents as well. + A set of concrete specs from the active environment including + those associated with affected packages, their dependencies and + dependents, as well as their dependents dependencies. """ affected_specs = set() all_concrete_specs = env.all_specs() tty.debug("All concrete environment specs:") for s in all_concrete_specs: tty.debug(" {0}/{1}".format(s.name, s.dag_hash()[:7])) - for pkg in affected_pkgs: - env_matches = [s for s in all_concrete_specs if s.name == pkg] - for match in env_matches: - affected_specs.add(match) - if dependencies: - affected_specs.update(match.traverse(direction="children", root=False)) - if dependents: - affected_specs.update(match.traverse(direction="parents", root=False)) + env_matches = [s for s in all_concrete_specs if s.name in frozenset(affected_pkgs)] + visited = set() + dag_hash = lambda s: s.dag_hash() + for match in env_matches: + for parent in match.traverse(direction="parents", key=dag_hash): + affected_specs.update( + parent.traverse(direction="children", visited=visited, key=dag_hash) + ) return affected_specs @@ -625,7 +623,7 @@ def generate_gitlab_ci_yaml( affected_specs = get_spec_filter_list(env, affected_pkgs) tty.debug("all affected specs:") for s in affected_specs: - tty.debug(" {0}".format(s.name)) + tty.debug(" {0}/{1}".format(s.name, s.dag_hash()[:7])) # Allow overriding --prune-dag cli opt with environment variable prune_dag_override = os.environ.get("SPACK_PRUNE_UP_TO_DATE", None) @@ -848,7 +846,11 @@ def generate_gitlab_ci_yaml( if prune_untouched_packages: if release_spec not in affected_specs: - tty.debug("Pruning {0}, untouched by change.".format(release_spec.name)) + tty.debug( + "Pruning {0}/{1}, untouched by change.".format( + release_spec.name, release_spec.dag_hash()[:7] + ) + ) spec_record["needs_rebuild"] = False continue diff --git a/lib/spack/spack/test/ci.py b/lib/spack/spack/test/ci.py index 06f212d92a3..2a4786d51b9 100644 --- a/lib/spack/spack/test/ci.py +++ b/lib/spack/spack/test/ci.py @@ -442,13 +442,16 @@ def test_get_spec_filter_list(mutable_mock_env_path, config, mutable_mock_repo): touched = ["libdwarf"] # traversing both directions from libdwarf in the graphs depicted - # above results in the following possibly affected env specs: - # mpileaks, callpath, dyninst, libdwarf, and libelf. Unaffected - # specs are mpich, plus hypre and it's dependencies. + # above (and additionally including dependencies of dependents of + # libdwarf) results in the following possibly affected env specs: + # mpileaks, callpath, dyninst, libdwarf, libelf, and mpich. + # Unaffected specs are hypre and it's dependencies. affected_specs = ci.get_spec_filter_list(e1, touched) affected_pkg_names = set([s.name for s in affected_specs]) - expected_affected_pkg_names = set(["mpileaks", "callpath", "dyninst", "libdwarf", "libelf"]) + expected_affected_pkg_names = set( + ["mpileaks", "mpich", "callpath", "dyninst", "libdwarf", "libelf"] + ) assert affected_pkg_names == expected_affected_pkg_names diff --git a/lib/spack/spack/test/cmd/ci.py b/lib/spack/spack/test/cmd/ci.py index 5529defee51..b2e84e0c027 100644 --- a/lib/spack/spack/test/cmd/ci.py +++ b/lib/spack/spack/test/cmd/ci.py @@ -1837,8 +1837,8 @@ def fake_stack_changed(env_path, rev1="HEAD^", rev2="HEAD"): yaml_contents = syaml.load(contents) for ci_key in yaml_contents.keys(): - if "archive-files" in ci_key or "mpich" in ci_key: - print("Error: archive-files and mpich should have been pruned") + if "archive-files" in ci_key: + print("Error: archive-files should have been pruned") assert False From ccc716f6173127f00df2016220b45e9b5987a49a Mon Sep 17 00:00:00 2001 From: Zack Galbreath Date: Thu, 3 Nov 2022 17:26:03 -0400 Subject: [PATCH 329/442] Limit the number of parallel jobs launched by Tensile (#33692) --- var/spack/repos/builtin/packages/rocblas/package.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/var/spack/repos/builtin/packages/rocblas/package.py b/var/spack/repos/builtin/packages/rocblas/package.py index 84f90cff4b3..92844ffda52 100644 --- a/var/spack/repos/builtin/packages/rocblas/package.py +++ b/var/spack/repos/builtin/packages/rocblas/package.py @@ -248,6 +248,11 @@ def cmake_args(self): args.append(self.define("Tensile_LIBRARY_FORMAT", "msgpack")) if self.spec.satisfies("@:4.2.0"): arch_define_name = "Tensile_ARCHITECTURE" + # Restrict the number of jobs Tensile can spawn. + # If we don't specify otherwise, Tensile creates a job per available core, + # and that consumes a lot of system memory. + # https://github.com/ROCmSoftwarePlatform/Tensile/blob/93e10678a0ced7843d9332b80bc17ebf9a166e8e/Tensile/Parallel.py#L38 + args.append(self.define("Tensile_CPU_THREADS", min(16, make_jobs))) # See https://github.com/ROCmSoftwarePlatform/rocBLAS/commit/c1895ba4bb3f4f5947f3818ebd155cf71a27b634 if "auto" not in self.spec.variants["amdgpu_target"]: From d2d01ea488c261226ed16040ce2389110a650601 Mon Sep 17 00:00:00 2001 From: eugeneswalker <38933153+eugeneswalker@users.noreply.github.com> Date: Thu, 3 Nov 2022 14:44:02 -0700 Subject: [PATCH 330/442] flux-core: allow ncurses >= 6.2 (#33599) --- var/spack/repos/builtin/packages/flux-core/package.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/flux-core/package.py b/var/spack/repos/builtin/packages/flux-core/package.py index abaca92b3f3..096655f303c 100644 --- a/var/spack/repos/builtin/packages/flux-core/package.py +++ b/var/spack/repos/builtin/packages/flux-core/package.py @@ -111,7 +111,7 @@ class FluxCore(AutotoolsPackage): variant("cuda", default=False, description="Build dependencies with support for CUDA") depends_on("libarchive", when="@0.38.0:") - depends_on("ncurses@6.2", when="@0.32.0:") + depends_on("ncurses@6.2:", when="@0.32.0:") depends_on("libzmq@4.0.4:") depends_on("czmq@3.0.1:") depends_on("hwloc@1.11.1:1", when="@:0.17.0") From e8cc1a60eaa5e330a44dd7ba41cf0c04479891a0 Mon Sep 17 00:00:00 2001 From: snehring <7978778+snehring@users.noreply.github.com> Date: Thu, 3 Nov 2022 16:44:31 -0500 Subject: [PATCH 331/442] spades: adding version 3.15.5 (#33698) --- var/spack/repos/builtin/packages/spades/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/spades/package.py b/var/spack/repos/builtin/packages/spades/package.py index 7a734ed8582..621e3c574e7 100644 --- a/var/spack/repos/builtin/packages/spades/package.py +++ b/var/spack/repos/builtin/packages/spades/package.py @@ -13,6 +13,7 @@ class Spades(CMakePackage): homepage = "https://cab.spbu.ru/software/spades/" url = "https://github.com/ablab/spades/releases/download/v3.15.3/SPAdes-3.15.3.tar.gz" + version("3.15.5", sha256="155c3640d571f2e7b19a05031d1fd0d19bd82df785d38870fb93bd241b12bbfa") version("3.15.3", sha256="b2e5a9fd7a65aee5ab886222d6af4f7b7bc7f755da7a03941571fabd6b9e1499") version("3.15.0", sha256="6719489fa4bed6dd96d78bdd4001a30806d5469170289085836711d1ffb8b28b") version("3.14.1", sha256="d629b78f7e74c82534ac20f5b3c2eb367f245e6840a67b9ef6a76f6fac5323ca") From 5b3905947264f17646a3f401c1780fec43e0274f Mon Sep 17 00:00:00 2001 From: snehring <7978778+snehring@users.noreply.github.com> Date: Thu, 3 Nov 2022 17:02:36 -0500 Subject: [PATCH 332/442] tassel: adding version 5.2.86 (#33697) --- var/spack/repos/builtin/packages/tassel/package.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/var/spack/repos/builtin/packages/tassel/package.py b/var/spack/repos/builtin/packages/tassel/package.py index 1f058850594..346a7e2c26e 100644 --- a/var/spack/repos/builtin/packages/tassel/package.py +++ b/var/spack/repos/builtin/packages/tassel/package.py @@ -12,7 +12,9 @@ class Tassel(Package): homepage = "https://www.maizegenetics.net/tassel" git = "https://bitbucket.org/tasseladmin/tassel-5-standalone.git" + maintainers = ["snehring"] + version("5.2.86", commit="6557864512a89932710b9f53c6005a35ad6c526e") version("5.2.39", commit="ae96ae75c3c9a9e8026140b6c775fa4685bdf531") version( "3.0.174", From 7fc49c42ee27bcd2629e3ac112e63da460d9a26c Mon Sep 17 00:00:00 2001 From: Adrien Cotte Date: Thu, 3 Nov 2022 23:11:28 +0100 Subject: [PATCH 333/442] Add new versions to py-clustershell (#33694) --- .../repos/builtin/packages/py-clustershell/package.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/var/spack/repos/builtin/packages/py-clustershell/package.py b/var/spack/repos/builtin/packages/py-clustershell/package.py index 2a4fd640a58..6504f8aaedf 100644 --- a/var/spack/repos/builtin/packages/py-clustershell/package.py +++ b/var/spack/repos/builtin/packages/py-clustershell/package.py @@ -12,9 +12,13 @@ class PyClustershell(PythonPackage): """ homepage = "https://cea-hpc.github.io/clustershell/" - url = "https://github.com/cea-hpc/clustershell/archive/v1.8.tar.gz" + url = "https://github.com/cea-hpc/clustershell/archive/v1.8.4.tar.gz" + version("1.8.4", sha256="763793f729bd1c275361717c540e01ad5fe536119eca92f14077c0995739b9d7") + version("1.8.3", sha256="86b0d524e5e50c0a15faec01d8642f0ff12ba78d50b7e7b660261be5d53fed9c") + version("1.8.2", sha256="abf5ed23b6adfc802ee65aa0208c697f617e5fb8fd0d8cb0100ee337e2721796") + version("1.8.1", sha256="0c3da87108de8b735f40b5905b8dcd8084a234849aee2a8b8d2e20b99b57100c") version("1.8", sha256="ad5a13e2d107b4095229810c35365e22ea94dfd2baf4fdcfcc68ce58ee37cee3") depends_on("py-setuptools", type="build") - depends_on("py-pyyaml") + depends_on("py-pyyaml", type=("build", "run")) From b52be759788cf20f1458c80e6e005744f5856c73 Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Fri, 4 Nov 2022 00:34:00 +0100 Subject: [PATCH 334/442] Experimental binding of shared ELF libraries (#31948) Adds another post install hook that loops over the install prefix, looking for shared libraries type of ELF files, and sets the soname to their own absolute paths. The idea being, whenever somebody links against those libraries, the linker copies the soname (which is the absolute path to the library) as a "needed" library, so that at runtime the dynamic loader realizes the needed library is a path which should be loaded directly without searching. As a result: 1. rpaths are not used for the fixed/static list of needed libraries in the dynamic section (only for _actually_ dynamically loaded libraries through `dlopen`), which largely solves the issue that Spack's rpaths are a heuristic (`/lib` and `/lib64` might not be where libraries really are...) 2. improved startup times (no library search required) --- etc/spack/defaults/config.yaml | 18 +- lib/spack/docs/config_yaml.rst | 52 +++++- lib/spack/llnl/util/lang.py | 8 + lib/spack/spack/bootstrap.py | 5 + lib/spack/spack/build_environment.py | 2 +- lib/spack/spack/hooks/__init__.py | 11 +- .../spack/hooks/absolutify_elf_sonames.py | 171 ++++++++++++++++++ lib/spack/spack/package_base.py | 9 + lib/spack/spack/schema/config.py | 20 +- lib/spack/spack/test/build_environment.py | 2 +- lib/spack/spack/test/cmd/config.py | 8 + .../test/hooks/absolutify_elf_sonames.py | 81 +++++++++ .../repos/builtin/packages/cuda/package.py | 3 + .../repos/builtin/packages/nvhpc/package.py | 3 + .../repos/builtin/packages/openjdk/package.py | 5 + 15 files changed, 383 insertions(+), 15 deletions(-) create mode 100644 lib/spack/spack/hooks/absolutify_elf_sonames.py create mode 100644 lib/spack/spack/test/hooks/absolutify_elf_sonames.py diff --git a/etc/spack/defaults/config.yaml b/etc/spack/defaults/config.yaml index e72608248f5..b3356428fe4 100644 --- a/etc/spack/defaults/config.yaml +++ b/etc/spack/defaults/config.yaml @@ -187,10 +187,20 @@ config: package_lock_timeout: null - # Control whether Spack embeds RPATH or RUNPATH attributes in ELF binaries. - # Has no effect on macOS. DO NOT MIX these within the same install tree. - # See the Spack documentation for details. - shared_linking: 'rpath' + # Control how shared libraries are located at runtime on Linux. See the + # the Spack documentation for details. + shared_linking: + # Spack automatically embeds runtime search paths in ELF binaries for their + # dependencies. Their type can either be "rpath" or "runpath". For glibc, rpath is + # inherited and has precedence over LD_LIBRARY_PATH; runpath is not inherited + # and of lower precedence. DO NOT MIX these within the same install tree. + type: rpath + + + # (Experimental) Embed absolute paths of dependent libraries directly in ELF + # binaries to avoid runtime search. This can improve startup time of + # executables with many dependencies, in particular on slow filesystems. + bind: false # Set to 'false' to allow installation on filesystems that doesn't allow setgid bit diff --git a/lib/spack/docs/config_yaml.rst b/lib/spack/docs/config_yaml.rst index b93384e81b4..f2159c64cce 100644 --- a/lib/spack/docs/config_yaml.rst +++ b/lib/spack/docs/config_yaml.rst @@ -224,9 +224,9 @@ them). Please note that we currently disable ccache's ``hash_dir`` feature to avoid an issue with the stage directory (see https://github.com/LLNL/spack/pull/3761#issuecomment-294352232). ------------------- -``shared_linking`` ------------------- +----------------------- +``shared_linking:type`` +----------------------- Control whether Spack embeds ``RPATH`` or ``RUNPATH`` attributes in ELF binaries so that they can find their dependencies. Has no effect on macOS. @@ -245,6 +245,52 @@ the loading object. DO NOT MIX the two options within the same install tree. +----------------------- +``shared_linking:bind`` +----------------------- + +This is an *experimental option* that controls whether Spack embeds absolute paths +to needed shared libraries in ELF executables and shared libraries on Linux. Setting +this option to ``true`` has two advantages: + +1. **Improved startup time**: when running an executable, the dynamic loader does not + have to perform a search for needed libraries, they are loaded directly. +2. **Reliability**: libraries loaded at runtime are those that were linked to. This + minimizes the risk of accidentally picking up system libraries. + +In the current implementation, Spack sets the soname (shared object name) of +libraries to their install path upon installation. This has two implications: + +1. binding does not apply to libraries installed *before* the option was enabled; +2. toggling the option off does *not* prevent binding of libraries installed when + the option was still enabled. + +It is also worth noting that: + +1. Applications relying on ``dlopen(3)`` will continue to work, even when they open + a library by name. This is because ``RPATH``\s are retained in binaries also + when ``bind`` is enabled. +2. ``LD_PRELOAD`` continues to work for the typical use case of overriding + symbols, such as preloading a library with a more efficient ``malloc``. + However, the preloaded library will be loaded *additionally to*, instead of + *in place of* another library with the same name --- this can be problematic + in very rare cases where libraries rely on a particular ``init`` or ``fini`` + order. + +.. note:: + + In some cases packages provide *stub libraries* that only contain an interface + for linking, but lack an implementation for runtime. An example of this is + ``libcuda.so``, provided by the CUDA toolkit; it can be used to link against, + but the library needed at runtime is the one installed with the CUDA driver. + To avoid binding those libraries, they can be marked as non-bindable using + a property in the package: + + .. code-block:: python + + class Example(Package): + non_bindable_shared_objects = ["libinterface.so"] + ---------------------- ``terminal_title`` ---------------------- diff --git a/lib/spack/llnl/util/lang.py b/lib/spack/llnl/util/lang.py index f1a0b7ba313..51bd710ddbb 100644 --- a/lib/spack/llnl/util/lang.py +++ b/lib/spack/llnl/util/lang.py @@ -1022,6 +1022,14 @@ def stable_partition( return true_items, false_items +def ensure_last(lst, *elements): + """Performs a stable partition of lst, ensuring that ``elements`` + occur at the end of ``lst`` in specified order. Mutates ``lst``. + Raises ``ValueError`` if any ``elements`` are not already in ``lst``.""" + for elt in elements: + lst.append(lst.pop(lst.index(elt))) + + class TypedMutableSequence(MutableSequence): """Base class that behaves like a list, just with a different type. diff --git a/lib/spack/spack/bootstrap.py b/lib/spack/spack/bootstrap.py index d92609fdcdf..60f8153ae27 100644 --- a/lib/spack/spack/bootstrap.py +++ b/lib/spack/spack/bootstrap.py @@ -675,6 +675,11 @@ def _add_externals_if_missing(): _REF_COUNT = 0 +def is_bootstrapping(): + global _REF_COUNT + return _REF_COUNT > 0 + + @contextlib.contextmanager def ensure_bootstrap_configuration(): # The context manager is reference counted to ensure we don't swap multiple diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py index 463c4dcde7a..1496e9359f5 100644 --- a/lib/spack/spack/build_environment.py +++ b/lib/spack/spack/build_environment.py @@ -317,7 +317,7 @@ def set_compiler_environment_variables(pkg, env): env.set("SPACK_LINKER_ARG", compiler.linker_arg) # Check whether we want to force RPATH or RUNPATH - if spack.config.get("config:shared_linking") == "rpath": + if spack.config.get("config:shared_linking:type") == "rpath": env.set("SPACK_DTAGS_TO_STRIP", compiler.enable_new_dtags) env.set("SPACK_DTAGS_TO_ADD", compiler.disable_new_dtags) else: diff --git a/lib/spack/spack/hooks/__init__.py b/lib/spack/spack/hooks/__init__.py index 699464c9135..f30082ccf63 100644 --- a/lib/spack/spack/hooks/__init__.py +++ b/lib/spack/spack/hooks/__init__.py @@ -27,7 +27,8 @@ systems (e.g. modules, lmod, etc.) or to add other custom features. """ -import llnl.util.lang + +from llnl.util.lang import ensure_last, list_modules import spack.paths @@ -44,11 +45,11 @@ def __init__(self, hook_name): def _populate_hooks(cls): # Lazily populate the list of hooks cls._hooks = [] - relative_names = list(llnl.util.lang.list_modules(spack.paths.hooks_path)) - # We want this hook to be the last registered - relative_names.sort(key=lambda x: x == "write_install_manifest") - assert relative_names[-1] == "write_install_manifest" + relative_names = list(list_modules(spack.paths.hooks_path)) + + # Ensure that write_install_manifest comes last + ensure_last(relative_names, "absolutify_elf_sonames", "write_install_manifest") for name in relative_names: module_name = __name__ + "." + name diff --git a/lib/spack/spack/hooks/absolutify_elf_sonames.py b/lib/spack/spack/hooks/absolutify_elf_sonames.py new file mode 100644 index 00000000000..d16de2ea39d --- /dev/null +++ b/lib/spack/spack/hooks/absolutify_elf_sonames.py @@ -0,0 +1,171 @@ +# 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) + +import os + +import llnl.util.tty as tty +from llnl.util.filesystem import BaseDirectoryVisitor, visit_directory_tree +from llnl.util.lang import elide_list + +import spack.bootstrap +import spack.config +import spack.relocate +from spack.util.elf import ElfParsingError, parse_elf +from spack.util.executable import Executable + + +def is_shared_library_elf(filepath): + """Return true if filepath is most a shared library. + Our definition of a shared library for ELF requires: + 1. a dynamic section, + 2. a soname OR lack of interpreter. + The problem is that PIE objects (default on Ubuntu) are + ET_DYN too, and not all shared libraries have a soname... + no interpreter is typically the best indicator then.""" + try: + with open(filepath, "rb") as f: + elf = parse_elf(f, interpreter=True, dynamic_section=True) + return elf.has_pt_dynamic and (elf.has_soname or not elf.has_pt_interp) + except (IOError, OSError, ElfParsingError): + return False + + +class SharedLibrariesVisitor(BaseDirectoryVisitor): + """Visitor that collects all shared libraries in a prefix, with the + exception of an exclude list.""" + + def __init__(self, exclude_list): + + # List of file and directory names to be excluded + self.exclude_list = frozenset(exclude_list) + + # Map from (ino, dev) -> path. We need 1 path per file, if there are hardlinks, + # we don't need to store the path multiple times. + self.libraries = dict() + + # Set of (ino, dev) pairs (excluded by symlinks). + self.excluded_through_symlink = set() + + def visit_file(self, root, rel_path, depth): + # Check if excluded + basename = os.path.basename(rel_path) + if basename in self.exclude_list: + return + + filepath = os.path.join(root, rel_path) + s = os.lstat(filepath) + identifier = (s.st_ino, s.st_dev) + + # We're hitting a hardlink or symlink of an excluded lib, no need to parse. + if identifier in self.libraries or identifier in self.excluded_through_symlink: + return + + # Register the file if it's a shared lib that needs to be patched. + if is_shared_library_elf(filepath): + self.libraries[identifier] = rel_path + + def visit_symlinked_file(self, root, rel_path, depth): + # We don't need to follow the symlink and parse the file, since we will hit + # it by recursing the prefix anyways. We only need to check if the target + # should be excluded based on the filename of the symlink. E.g. when excluding + # libf.so, which is a symlink to libf.so.1.2.3, we keep track of the stat data + # of the latter. + basename = os.path.basename(rel_path) + if basename not in self.exclude_list: + return + + # Register the (ino, dev) pair as ignored (if the symlink is not dangling) + filepath = os.path.join(root, rel_path) + try: + s = os.stat(filepath) + except OSError: + return + self.excluded_through_symlink.add((s.st_ino, s.st_dev)) + + def before_visit_dir(self, root, rel_path, depth): + # Allow skipping over directories. E.g. `/lib/stubs` can be skipped by + # adding `"stubs"` to the exclude list. + return os.path.basename(rel_path) not in self.exclude_list + + def before_visit_symlinked_dir(self, root, rel_path, depth): + # Never enter symlinked dirs, since we don't want to leave the prefix, and + # we'll enter the target dir inside the prefix anyways since we're recursing + # everywhere. + return False + + def get_shared_libraries_relative_paths(self): + """Get the libraries that should be patched, with the excluded libraries + removed.""" + for identifier in self.excluded_through_symlink: + self.libraries.pop(identifier, None) + + return [rel_path for rel_path in self.libraries.values()] + + +def patch_sonames(patchelf, root, rel_paths): + """Set the soname to the file's own path for a list of + given shared libraries.""" + fixed = [] + for rel_path in rel_paths: + filepath = os.path.join(root, rel_path) + normalized = os.path.normpath(filepath) + args = ["--set-soname", normalized, normalized] + output = patchelf(*args, output=str, error=str, fail_on_error=False) + if patchelf.returncode == 0: + fixed.append(rel_path) + else: + # Note: treat as warning to avoid (long) builds to fail post-install. + tty.warn("patchelf: failed to set soname of {}: {}".format(normalized, output.strip())) + return fixed + + +def find_and_patch_sonames(prefix, exclude_list, patchelf): + # Locate all shared libraries in the prefix dir of the spec, excluding + # the ones set in the non_bindable_shared_objects property. + visitor = SharedLibrariesVisitor(exclude_list) + visit_directory_tree(prefix, visitor) + + # Patch all sonames. + relative_paths = visitor.get_shared_libraries_relative_paths() + return patch_sonames(patchelf, prefix, relative_paths) + + +def post_install(spec): + # Skip if disabled + if not spack.config.get("config:shared_linking:bind", False): + return + + # Skip externals + if spec.external: + return + + # Only enable on platforms using ELF. + if not spec.satisfies("platform=linux") and not spec.satisfies("platform=cray"): + return + + # Disable this hook when bootstrapping, to avoid recursion. + if spack.bootstrap.is_bootstrapping(): + return + + # Should failing to locate patchelf be a hard error? + patchelf_path = spack.relocate._patchelf() + if not patchelf_path: + return + patchelf = Executable(patchelf_path) + + fixes = find_and_patch_sonames(spec.prefix, spec.package.non_bindable_shared_objects, patchelf) + + if not fixes: + return + + # Unfortunately this does not end up in the build logs. + tty.info( + "{}: Patched {} {}: {}".format( + spec.name, + len(fixes), + "soname" if len(fixes) == 1 else "sonames", + ", ".join(elide_list(fixes, max_num=5)), + ) + ) diff --git a/lib/spack/spack/package_base.py b/lib/spack/spack/package_base.py index cf96beca580..1871e6785bf 100644 --- a/lib/spack/spack/package_base.py +++ b/lib/spack/spack/package_base.py @@ -564,6 +564,15 @@ class PackageBase(six.with_metaclass(PackageMeta, WindowsRPathMeta, PackageViewM #: for immediate dependencies. transitive_rpaths = True + #: List of shared objects that should be replaced with a different library at + #: runtime. Typically includes stub libraries like libcuda.so. When linking + #: against a library listed here, the dependent will only record its soname + #: or filename, not its absolute path, so that the dynamic linker will search + #: for it. Note: accepts both file names and directory names, for example + #: ``["libcuda.so", "stubs"]`` will ensure libcuda.so and all libraries in the + #: stubs directory are not bound by path.""" + non_bindable_shared_objects = [] # type: List[str] + #: List of prefix-relative file paths (or a single path). If these do #: not exist after install, or if they exist but are not files, #: sanity checks fail. diff --git a/lib/spack/spack/schema/config.py b/lib/spack/spack/schema/config.py index c82990da5cc..96e34a051a8 100644 --- a/lib/spack/spack/schema/config.py +++ b/lib/spack/spack/schema/config.py @@ -20,7 +20,18 @@ "type": "object", "default": {}, "properties": { - "shared_linking": {"type": "string", "enum": ["rpath", "runpath"]}, + "shared_linking": { + "anyOf": [ + {"type": "string", "enum": ["rpath", "runpath"]}, + { + "type": "object", + "properties": { + "type": {"type": "string", "enum": ["rpath", "runpath"]}, + "bind": {"type": "boolean"}, + }, + }, + ] + }, "install_tree": { "anyOf": [ { @@ -136,4 +147,11 @@ def update(data): data["url_fetch_method"] = "curl" if use_curl else "urllib" changed = True + shared_linking = data.get("shared_linking", None) + if isinstance(shared_linking, six.string_types): + # deprecated short-form shared_linking: rpath/runpath + # add value as `type` in updated shared_linking + data["shared_linking"] = {"type": shared_linking, "bind": False} + changed = True + return changed diff --git a/lib/spack/spack/test/build_environment.py b/lib/spack/spack/test/build_environment.py index 6ba8fc056fb..9b894a93519 100644 --- a/lib/spack/spack/test/build_environment.py +++ b/lib/spack/spack/test/build_environment.py @@ -465,7 +465,7 @@ def test_setting_dtags_based_on_config(config_setting, expected_flag, config, mo pkg = s.package env = EnvironmentModifications() - with spack.config.override("config:shared_linking", config_setting): + with spack.config.override("config:shared_linking", {"type": config_setting, "bind": False}): spack.build_environment.set_compiler_environment_variables(pkg, env) modifications = env.group_by_name() assert "SPACK_DTAGS_TO_STRIP" in modifications diff --git a/lib/spack/spack/test/cmd/config.py b/lib/spack/spack/test/cmd/config.py index e5ad82cf435..56943f5d8b6 100644 --- a/lib/spack/spack/test/cmd/config.py +++ b/lib/spack/spack/test/cmd/config.py @@ -606,6 +606,14 @@ def check_config_updated(data): assert data["install_tree"]["projections"] == {"all": "{name}-{version}"} +def test_config_update_shared_linking(mutable_config): + # Old syntax: config:shared_linking:rpath/runpath + # New syntax: config:shared_linking:{type:rpath/runpath,bind:True/False} + with spack.config.override("config:shared_linking", "runpath"): + assert spack.config.get("config:shared_linking:type") == "runpath" + assert not spack.config.get("config:shared_linking:bind") + + def test_config_prefer_upstream( tmpdir_factory, install_mockery, mock_fetch, mutable_config, gen_mock_layout, monkeypatch ): diff --git a/lib/spack/spack/test/hooks/absolutify_elf_sonames.py b/lib/spack/spack/test/hooks/absolutify_elf_sonames.py new file mode 100644 index 00000000000..2163b776dc9 --- /dev/null +++ b/lib/spack/spack/test/hooks/absolutify_elf_sonames.py @@ -0,0 +1,81 @@ +# 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) + + +import os + +import pytest + +import llnl.util.filesystem as fs + +import spack.platforms +from spack.hooks.absolutify_elf_sonames import ( + SharedLibrariesVisitor, + find_and_patch_sonames, +) +from spack.util.executable import Executable + + +def skip_unless_linux(f): + return pytest.mark.skipif( + str(spack.platforms.real_host()) != "linux", reason="only tested on linux for now" + )(f) + + +class ExecutableIntercept: + def __init__(self): + self.calls = [] + + def __call__(self, *args, **kwargs): + self.calls.append(args) + + @property + def returncode(self): + return 0 + + +@pytest.mark.requires_executables("gcc") +@skip_unless_linux +def test_shared_libraries_visitor(tmpdir): + """Integration test for soname rewriting""" + gcc = Executable("gcc") + + # Create a directory structure like this: + # ./no-soname.so # just a shared library without a soname + # ./soname.so # a shared library with a soname + # ./executable.so # an executable masquerading as a shared lib + # ./libskipme.so # a shared library with a soname + # ./mydir/parent_dir -> .. # a symlinked dir, causing a cycle + # ./mydir/skip_symlink -> ../libskipme # a symlink to a library + + with fs.working_dir(str(tmpdir)): + with open("hello.c", "w") as f: + f.write("int main(){return 0;}") + gcc("hello.c", "-o", "no-soname.so", "--shared") + gcc("hello.c", "-o", "soname.so", "--shared", "-Wl,-soname,example.so") + gcc("hello.c", "-pie", "-o", "executable.so") + gcc("hello.c", "-o", "libskipme.so", "-Wl,-soname,libskipme.so") + os.mkdir("my_dir") + os.symlink("..", os.path.join("my_dir", "parent_dir")) + os.symlink(os.path.join("..", "libskipme.so"), os.path.join("my_dir", "skip_symlink")) + + # Visit the whole prefix, but exclude `skip_symlink` + visitor = SharedLibrariesVisitor(exclude_list=["skip_symlink"]) + fs.visit_directory_tree(str(tmpdir), visitor) + relative_paths = visitor.get_shared_libraries_relative_paths() + + assert "no-soname.so" in relative_paths + assert "soname.so" in relative_paths + assert "executable.so" not in relative_paths + assert "libskipme.so" not in relative_paths + + # Run the full hook of finding libs and setting sonames. + patchelf = ExecutableIntercept() + find_and_patch_sonames(str(tmpdir), ["skip_symlink"], patchelf) + assert len(patchelf.calls) == 2 + elf_1 = tmpdir.join("no-soname.so") + elf_2 = tmpdir.join("soname.so") + assert ("--set-soname", elf_1, elf_1) in patchelf.calls + assert ("--set-soname", elf_2, elf_2) in patchelf.calls diff --git a/var/spack/repos/builtin/packages/cuda/package.py b/var/spack/repos/builtin/packages/cuda/package.py index e8157b54aed..2375e318afe 100644 --- a/var/spack/repos/builtin/packages/cuda/package.py +++ b/var/spack/repos/builtin/packages/cuda/package.py @@ -583,3 +583,6 @@ def libs(self): if "compat" not in parts and "stubs" not in parts: filtered_libs.append(lib) return LibraryList(filtered_libs) + + # Avoid binding stub libraries by absolute path + non_bindable_shared_objects = ["stubs"] diff --git a/var/spack/repos/builtin/packages/nvhpc/package.py b/var/spack/repos/builtin/packages/nvhpc/package.py index b7e625b97c5..2ade4bc9e64 100644 --- a/var/spack/repos/builtin/packages/nvhpc/package.py +++ b/var/spack/repos/builtin/packages/nvhpc/package.py @@ -415,3 +415,6 @@ def libs(self): libs.append("libnvf") return find_libraries(libs, root=prefix, recursive=True) + + # Avoid binding stub libraries by absolute path + non_bindable_shared_objects = ["stubs"] diff --git a/var/spack/repos/builtin/packages/openjdk/package.py b/var/spack/repos/builtin/packages/openjdk/package.py index 6382dc3688a..fab50a28f85 100644 --- a/var/spack/repos/builtin/packages/openjdk/package.py +++ b/var/spack/repos/builtin/packages/openjdk/package.py @@ -413,3 +413,8 @@ def setup_dependent_run_environment(self, env, dependent_spec): class_paths = find(dependent_spec.prefix, "*.jar") classpath = os.pathsep.join(class_paths) env.prepend_path("CLASSPATH", classpath) + + # Since we provide openjdk as a binary, we can't remove an obsolete glibc + # fix that prevents us from modifying the soname of libjvm.so. If we move + # to source builds this should be possible. + non_bindable_shared_objects = ["libjvm.so"] From 79fcc0848f65a76e9cee54eb311cba23b83762f8 Mon Sep 17 00:00:00 2001 From: Greg Becker Date: Thu, 3 Nov 2022 17:10:39 -0700 Subject: [PATCH 335/442] Update glvis for new builder interface (#33699) --- var/spack/repos/builtin/packages/glvis/package.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/var/spack/repos/builtin/packages/glvis/package.py b/var/spack/repos/builtin/packages/glvis/package.py index 7c1292a4a82..de327d6341f 100644 --- a/var/spack/repos/builtin/packages/glvis/package.py +++ b/var/spack/repos/builtin/packages/glvis/package.py @@ -189,5 +189,5 @@ def yes_no(s): ), ] - self.build_targets = args - self.install_targets += args + self.builder.build_targets = args + self.builder.install_targets += args From 9c5c327a6feb47528b01029806477e84073a3a13 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Thu, 3 Nov 2022 17:26:03 -0700 Subject: [PATCH 336/442] propagation: don't count propagated variant values as non-default (#33687) We try to avoid non-default variant values in the concretizer, but this doesn't make sense for variants forced to take some non-default value by variant propagation. Counting this as a penalty effectively biases the concretizer for small specs dependency graphs -- something we try very hard to avoid elsewhere because it can lead to very strange decisions. Example: with the penalty, `spack spec hdf5` will choose the default `openmpi` as its `mpi` provider, but `spack spec hdf5 ~~shared` will choose `mpich` because it has to set fewer non-default variant values because `mpich`'s DAG is smaller. That's not a good reason to prefer a non-default virtual provider. To fix this, if the user explicitly requests a non-default value to be propagated, there shouldn't be a penalty. Variant values set on the CLI already don't count as default; we just need to extend that to propagated values. --- lib/spack/spack/solver/concretize.lp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/spack/spack/solver/concretize.lp b/lib/spack/spack/solver/concretize.lp index 2bbf3091c64..02528e694d7 100644 --- a/lib/spack/spack/solver/concretize.lp +++ b/lib/spack/spack/solver/concretize.lp @@ -673,6 +673,8 @@ variant_not_default(Package, Variant, Value) not variant_default_value(Package, Variant, Value), % variants set explicitly on the CLI don't count as non-default not variant_set(Package, Variant, Value), + % variant values forced by propagation don't count as non-default + not variant_propagate(Package, Variant, Value, _), % variants set on externals that we could use don't count as non-default % this makes spack prefer to use an external over rebuilding with the % default configuration From b3e41736e685db6e0bc7fec2fc093ea345926268 Mon Sep 17 00:00:00 2001 From: wspear Date: Thu, 3 Nov 2022 18:24:23 -0700 Subject: [PATCH 337/442] Add version 2.32 to tau package (#33702) --- var/spack/repos/builtin/packages/tau/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/tau/package.py b/var/spack/repos/builtin/packages/tau/package.py index 08b4f869cd4..6a87471d088 100644 --- a/var/spack/repos/builtin/packages/tau/package.py +++ b/var/spack/repos/builtin/packages/tau/package.py @@ -26,6 +26,7 @@ class Tau(Package): tags = ["e4s"] version("master", branch="master") + version("2.32", sha256="a404f51ae48fbfb9a2fb03643e555b4d978af4c83f365bacfead91e0095ee1ea") version("2.31.1", sha256="bf445b9d4fe40a5672a7b175044d2133791c4dfb36a214c1a55a931aebc06b9d") version("2.31", sha256="27e73c395dd2a42b91591ce4a76b88b1f67663ef13aa19ef4297c68f45d946c2") version("2.30.2", sha256="43f84a15b71a226f8a64d966f0cb46022bcfbaefb341295ecc6fa80bb82bbfb4") From 72b11c1883c61156653d9008bccc6071a3355b96 Mon Sep 17 00:00:00 2001 From: Lucas Date: Thu, 3 Nov 2022 22:34:00 -0300 Subject: [PATCH 338/442] Adding gegelati library package (#33686) * testing ssh key * test * LR : Creating the packge to install the gegelati app * LR : Gegelati, a TPG C++ library added and fully tested * LR : adjusting for fork * LR: taking out the boilerplates * LR: taking out the rest --- .../builtin/packages/gegelati/package.py | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 var/spack/repos/builtin/packages/gegelati/package.py diff --git a/var/spack/repos/builtin/packages/gegelati/package.py b/var/spack/repos/builtin/packages/gegelati/package.py new file mode 100644 index 00000000000..1047bfc87aa --- /dev/null +++ b/var/spack/repos/builtin/packages/gegelati/package.py @@ -0,0 +1,25 @@ +# 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 Gegelati(CMakePackage): + """Class to add the a TPG library(gegelati) into Spack""" + + homepage = "https://github.com/gegelati/gegelati" + url = "https://github.com/gegelati/gegelati/archive/refs/tags/v1.2.0.tar.gz" + + # notify when the package is updated. + maintainers = ["lucascarvalhoroncoroni"] + + version("1.2.0", sha256="039997c7d6cb394f910f6c40620165b32094e0c85c170be01eb74b55488a1d4c") + + depends_on("sdl2") + depends_on("doxygen") + + def cmake_args(self): + args = [] + return args From 34969b7072972d06d216391b3b14070eb71cd908 Mon Sep 17 00:00:00 2001 From: Satish Balay Date: Thu, 3 Nov 2022 21:22:09 -0500 Subject: [PATCH 339/442] petsc: fix configure option to use double-hyphen (#33685) --- var/spack/repos/builtin/packages/petsc/package.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/petsc/package.py b/var/spack/repos/builtin/packages/petsc/package.py index 830adff3b59..ad674264951 100644 --- a/var/spack/repos/builtin/packages/petsc/package.py +++ b/var/spack/repos/builtin/packages/petsc/package.py @@ -573,7 +573,7 @@ def configure_options(self): for pkg in hip_lpkgs: hip_lib += spec[pkg].libs.joined() + " " options.append("HIPPPFLAGS=%s" % hip_inc) - options.append("with-hip-lib=%s -L%s -lamdhip64" % (hip_lib, spec["hip"].prefix.lib)) + options.append("--with-hip-lib=%s -L%s -lamdhip64" % (hip_lib, spec["hip"].prefix.lib)) if "superlu-dist" in spec: if spec.satisfies("@3.10.3:3.15"): From b1f896e6c75560cdb4f315cd8e68a653d085db63 Mon Sep 17 00:00:00 2001 From: Jordan Galby <67924449+Jordan474@users.noreply.github.com> Date: Fri, 4 Nov 2022 10:05:22 +0100 Subject: [PATCH 340/442] Fix non-parallel make under depfile jobserver (#32862) When a package asks for non-parallel make, we need to force `make -j1` because just doing `make` will run in parallel under jobserver (e.g. `spack env depfile`). We now always add `-j1` when asked for a non-parallel execution (even if there is no jobserver). And each `MakeExecutable` can now ask for jobserver support or not. For example: the default `ninja` does not support jobserver so spack applies the default `-j`, but `ninja@kitware` or `ninja-fortran` does, so spack doesn't add `-j`. Tips: you can run `SPACK_INSTALL_FLAGS=-j1 make -f spack-env-depfile.make -j8` to avoid massive job-spawning because of build tools that don't support jobserver (ninja). --- lib/spack/spack/build_environment.py | 57 +++++++++++-------- lib/spack/spack/test/make_executable.py | 38 +++++++++---- .../repos/builtin/packages/cmake/package.py | 17 ++++-- .../builtin/packages/ninja-fortran/package.py | 9 +++ .../repos/builtin/packages/ninja/package.py | 1 + 5 files changed, 80 insertions(+), 42 deletions(-) diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py index 1496e9359f5..c69dd566e65 100644 --- a/lib/spack/spack/build_environment.py +++ b/lib/spack/spack/build_environment.py @@ -121,18 +121,18 @@ stat_suffix = "lib" if sys.platform == "win32" else "a" -def should_set_parallel_jobs(jobserver_support=False): - """Returns true in general, except when: - - The env variable SPACK_NO_PARALLEL_MAKE=1 is set - - jobserver_support is enabled, and a jobserver was found. - """ - if ( - jobserver_support - and "MAKEFLAGS" in os.environ - and "--jobserver" in os.environ["MAKEFLAGS"] - ): - return False - return not env_flag(SPACK_NO_PARALLEL_MAKE) +def jobserver_enabled(): + """Returns true if a posix jobserver (make) is detected.""" + return "MAKEFLAGS" in os.environ and "--jobserver" in os.environ["MAKEFLAGS"] + + +def get_effective_jobs(jobs, parallel=True, supports_jobserver=False): + """Return the number of jobs, or None if supports_jobserver and a jobserver is detected.""" + if not parallel or jobs <= 1 or env_flag(SPACK_NO_PARALLEL_MAKE): + return 1 + if supports_jobserver and jobserver_enabled(): + return None + return jobs class MakeExecutable(Executable): @@ -147,26 +147,33 @@ class MakeExecutable(Executable): """ def __init__(self, name, jobs, **kwargs): + supports_jobserver = kwargs.pop("supports_jobserver", True) super(MakeExecutable, self).__init__(name, **kwargs) + self.supports_jobserver = supports_jobserver self.jobs = jobs def __call__(self, *args, **kwargs): """parallel, and jobs_env from kwargs are swallowed and used here; remaining arguments are passed through to the superclass. """ - # TODO: figure out how to check if we are using a jobserver-supporting ninja, - # the two split ninja packages make this very difficult right now - parallel = should_set_parallel_jobs(jobserver_support=True) and kwargs.pop( - "parallel", self.jobs > 1 - ) + parallel = kwargs.pop("parallel", True) + jobs_env = kwargs.pop("jobs_env", None) + jobs_env_supports_jobserver = kwargs.pop("jobs_env_supports_jobserver", False) - if parallel: - args = ("-j{0}".format(self.jobs),) + args - jobs_env = kwargs.pop("jobs_env", None) - if jobs_env: - # Caller wants us to set an environment variable to - # control the parallelism. - kwargs["extra_env"] = {jobs_env: str(self.jobs)} + jobs = get_effective_jobs( + self.jobs, parallel=parallel, supports_jobserver=self.supports_jobserver + ) + if jobs is not None: + args = ("-j{0}".format(jobs),) + args + + if jobs_env: + # Caller wants us to set an environment variable to + # control the parallelism. + jobs_env_jobs = get_effective_jobs( + self.jobs, parallel=parallel, supports_jobserver=jobs_env_supports_jobserver + ) + if jobs_env_jobs is not None: + kwargs["extra_env"] = {jobs_env: str(jobs_env_jobs)} return super(MakeExecutable, self).__call__(*args, **kwargs) @@ -547,7 +554,7 @@ def _set_variables_for_single_module(pkg, module): # TODO: make these build deps that can be installed if not found. m.make = MakeExecutable("make", jobs) m.gmake = MakeExecutable("gmake", jobs) - m.ninja = MakeExecutable("ninja", jobs) + m.ninja = MakeExecutable("ninja", jobs, supports_jobserver=False) # easy shortcut to os.environ m.env = os.environ diff --git a/lib/spack/spack/test/make_executable.py b/lib/spack/spack/test/make_executable.py index b7063e5e10d..efaff04de5e 100644 --- a/lib/spack/spack/test/make_executable.py +++ b/lib/spack/spack/test/make_executable.py @@ -53,24 +53,24 @@ def test_make_explicit(self): def test_make_one_job(self): make = MakeExecutable("make", 1) - self.assertEqual(make(output=str).strip(), "") - self.assertEqual(make("install", output=str).strip(), "install") + self.assertEqual(make(output=str).strip(), "-j1") + self.assertEqual(make("install", output=str).strip(), "-j1 install") def test_make_parallel_false(self): make = MakeExecutable("make", 8) - self.assertEqual(make(parallel=False, output=str).strip(), "") - self.assertEqual(make("install", parallel=False, output=str).strip(), "install") + self.assertEqual(make(parallel=False, output=str).strip(), "-j1") + self.assertEqual(make("install", parallel=False, output=str).strip(), "-j1 install") def test_make_parallel_disabled(self): make = MakeExecutable("make", 8) os.environ["SPACK_NO_PARALLEL_MAKE"] = "true" - self.assertEqual(make(output=str).strip(), "") - self.assertEqual(make("install", output=str).strip(), "install") + self.assertEqual(make(output=str).strip(), "-j1") + self.assertEqual(make("install", output=str).strip(), "-j1 install") os.environ["SPACK_NO_PARALLEL_MAKE"] = "1" - self.assertEqual(make(output=str).strip(), "") - self.assertEqual(make("install", output=str).strip(), "install") + self.assertEqual(make(output=str).strip(), "-j1") + self.assertEqual(make("install", output=str).strip(), "-j1 install") # These don't disable (false and random string) os.environ["SPACK_NO_PARALLEL_MAKE"] = "false" @@ -88,12 +88,12 @@ def test_make_parallel_precedence(self): # These should work os.environ["SPACK_NO_PARALLEL_MAKE"] = "true" - self.assertEqual(make(parallel=True, output=str).strip(), "") - self.assertEqual(make("install", parallel=True, output=str).strip(), "install") + self.assertEqual(make(parallel=True, output=str).strip(), "-j1") + self.assertEqual(make("install", parallel=True, output=str).strip(), "-j1 install") os.environ["SPACK_NO_PARALLEL_MAKE"] = "1" - self.assertEqual(make(parallel=True, output=str).strip(), "") - self.assertEqual(make("install", parallel=True, output=str).strip(), "install") + self.assertEqual(make(parallel=True, output=str).strip(), "-j1") + self.assertEqual(make("install", parallel=True, output=str).strip(), "-j1 install") # These don't disable (false and random string) os.environ["SPACK_NO_PARALLEL_MAKE"] = "false" @@ -113,3 +113,17 @@ def test_make_jobs_env(self): make(output=str, jobs_env="MAKE_PARALLELISM", _dump_env=dump_env).strip(), "-j8" ) self.assertEqual(dump_env["MAKE_PARALLELISM"], "8") + + def test_make_jobserver(self): + make = MakeExecutable("make", 8) + os.environ["MAKEFLAGS"] = "--jobserver-auth=X,Y" + self.assertEqual(make(output=str).strip(), "") + self.assertEqual(make(parallel=False, output=str).strip(), "-j1") + del os.environ["MAKEFLAGS"] + + def test_make_jobserver_not_supported(self): + make = MakeExecutable("make", 8, supports_jobserver=False) + os.environ["MAKEFLAGS"] = "--jobserver-auth=X,Y" + # Currently fallback on default job count, Maybe it should force -j1 ? + self.assertEqual(make(output=str).strip(), "-j8") + del os.environ["MAKEFLAGS"] diff --git a/var/spack/repos/builtin/packages/cmake/package.py b/var/spack/repos/builtin/packages/cmake/package.py index e988af5ba26..0ce352b9ab4 100644 --- a/var/spack/repos/builtin/packages/cmake/package.py +++ b/var/spack/repos/builtin/packages/cmake/package.py @@ -307,11 +307,20 @@ def bootstrap_args(self): args = [] self.generator = make + if self.spec.satisfies("platform=windows"): + args.append("-GNinja") + self.generator = ninja + if not sys.platform == "win32": args.append("--prefix={0}".format(self.prefix)) - if spack.build_environment.should_set_parallel_jobs(jobserver_support=True): - args.append("--parallel={0}".format(make_jobs)) + jobs = spack.build_environment.get_effective_jobs( + make_jobs, + parallel=self.parallel, + supports_jobserver=self.generator.supports_jobserver, + ) + if jobs is not None: + args.append("--parallel={0}".format(jobs)) if "+ownlibs" in spec: # Build and link to the CMake-provided third-party libraries @@ -338,9 +347,7 @@ def bootstrap_args(self): args.append("--") else: args.append("-DCMAKE_INSTALL_PREFIX=%s" % self.prefix) - if self.spec.satisfies("platform=windows"): - args.append("-GNinja") - self.generator = ninja + args.append("-DCMAKE_BUILD_TYPE={0}".format(self.spec.variants["build_type"].value)) # Install CMake correctly, even if `spack install` runs diff --git a/var/spack/repos/builtin/packages/ninja-fortran/package.py b/var/spack/repos/builtin/packages/ninja-fortran/package.py index 371b350adde..4709f51694b 100644 --- a/var/spack/repos/builtin/packages/ninja-fortran/package.py +++ b/var/spack/repos/builtin/packages/ninja-fortran/package.py @@ -86,3 +86,12 @@ def install(self, spec, prefix): # instead of 'ninja'. Install both for uniformity. with working_dir(prefix.bin): symlink("ninja", "ninja-build") + + def setup_dependent_package(self, module, dspec): + name = "ninja" + + module.ninja = MakeExecutable( + which_string(name, path=[self.spec.prefix.bin], required=True), + determine_number_of_jobs(parallel=self.parallel), + supports_jobserver=True, # This fork supports jobserver + ) diff --git a/var/spack/repos/builtin/packages/ninja/package.py b/var/spack/repos/builtin/packages/ninja/package.py index e71b648f263..a6ee815a2ba 100644 --- a/var/spack/repos/builtin/packages/ninja/package.py +++ b/var/spack/repos/builtin/packages/ninja/package.py @@ -79,4 +79,5 @@ def setup_dependent_package(self, module, dspec): module.ninja = MakeExecutable( which_string(name, path=[self.spec.prefix.bin], required=True), determine_number_of_jobs(parallel=self.parallel), + supports_jobserver=self.spec.version == ver("kitware"), ) From 1d4919924de9743f7ec6f47616d2c67d3074648b Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Fri, 4 Nov 2022 10:30:53 +0100 Subject: [PATCH 341/442] Add in-place RPATH replacement (#27610) Whenever the rpath string actually _grows_, it falls back to patchelf, when it stays the same length or gets shorter, we update it in-place, padded with null bytes. This PR only deals with absolute -> absolute rpath replacement. We don't use `_build_tarball(relative=True)` in our CI. If `relative` then it falls back to the old replacement code. With this PR, relocation time goes down significantly, likely because patchelf does some odd things with mmap, causing lots of overhead. Example: - `binutils`: 700MB installed, goes from `1.91s` to `0.57s`, or `3.4x` faster. Relocation time: 27% -> 10% of total install time - `llvm`: 6.8GB installed, goes from `28.56s` to `5.38`, or `5.3x` faster. Relocation time: 44% -> 13% of total install time The bottleneck is now decompression. Note: I'm somewhat confused about the "relative rpath" code paths. Right now this PR only deals with absolute -> absolute replacement. As far as I understand, if you embrace relative rpaths when uploading to the buildcache, the whole point is you _don't_ want to patch rpaths on install? So it seems fine to not expand `$ORIGIN` again imho. --- lib/spack/spack/binary_distribution.py | 6 +- lib/spack/spack/relocate.py | 43 +++++++------ lib/spack/spack/test/relocate.py | 18 ------ lib/spack/spack/test/util/elf.py | 55 ++++++++++++++--- lib/spack/spack/util/elf.py | 85 ++++++++++++++++++++++++-- 5 files changed, 155 insertions(+), 52 deletions(-) diff --git a/lib/spack/spack/binary_distribution.py b/lib/spack/spack/binary_distribution.py index 3069e234b2b..3de0bcf9db6 100644 --- a/lib/spack/spack/binary_distribution.py +++ b/lib/spack/spack/binary_distribution.py @@ -1634,7 +1634,11 @@ def is_backup_file(file): old_prefix, new_prefix, ) - if "elf" in platform.binary_formats: + elif "elf" in platform.binary_formats and not rel: + # The new ELF dynamic section relocation logic only handles absolute to + # absolute relocation. + relocate.new_relocate_elf_binaries(files_to_relocate, prefix_to_prefix_bin) + elif "elf" in platform.binary_formats and rel: relocate.relocate_elf_binaries( files_to_relocate, old_layout_root, diff --git a/lib/spack/spack/relocate.py b/lib/spack/spack/relocate.py index 8a5e77e22ec..b8c47b58645 100644 --- a/lib/spack/spack/relocate.py +++ b/lib/spack/spack/relocate.py @@ -7,6 +7,7 @@ import os import re import shutil +from collections import OrderedDict import macholib.mach_o import macholib.MachO @@ -21,6 +22,7 @@ import spack.platforms import spack.repo import spack.spec +import spack.util.elf as elf import spack.util.executable as executable is_macos = str(spack.platforms.real_host()) == "darwin" @@ -93,27 +95,15 @@ def _patchelf(): def _elf_rpaths_for(path): """Return the RPATHs for an executable or a library. - The RPATHs are obtained by ``patchelf --print-rpath PATH``. - Args: path (str): full path to the executable or library Return: - RPATHs as a list of strings. + RPATHs as a list of strings. Returns an empty array + on ELF parsing errors, or when the ELF file simply + has no rpaths. """ - # If we're relocating patchelf itself, use it - patchelf_path = path if path.endswith("/bin/patchelf") else _patchelf() - patchelf = executable.Executable(patchelf_path) - - output = "" - try: - output = patchelf("--print-rpath", path, output=str, error=str) - output = output.strip("\n") - except executable.ProcessError as e: - msg = "patchelf --print-rpath {0} produced an error [{1}]" - tty.warn(msg.format(path, str(e))) - - return output.split(":") if output else [] + return elf.get_rpaths(path) or [] def _make_relative(reference_file, path_root, paths): @@ -384,15 +374,13 @@ def _set_elf_rpaths(target, rpaths): """Replace the original RPATH of the target with the paths passed as arguments. - This function uses ``patchelf`` to set RPATHs. - Args: target: target executable. Must be an ELF object. rpaths: paths to be set in the RPATH Returns: A string concatenating the stdout and stderr of the call - to ``patchelf`` + to ``patchelf`` if it was invoked """ # Join the paths using ':' as a separator rpaths_str = ":".join(rpaths) @@ -595,6 +583,23 @@ def _transform_rpaths(orig_rpaths, orig_root, new_prefixes): return new_rpaths +def new_relocate_elf_binaries(binaries, prefix_to_prefix): + """Take a list of binaries, and an ordered dictionary of + prefix to prefix mapping, and update the rpaths accordingly.""" + + # Transform to binary string + prefix_to_prefix = OrderedDict( + (k.encode("utf-8"), v.encode("utf-8")) for (k, v) in prefix_to_prefix.items() + ) + + for path in binaries: + try: + elf.replace_rpath_in_place_or_raise(path, prefix_to_prefix) + except elf.ElfDynamicSectionUpdateFailed as e: + # Fall back to the old `patchelf --set-rpath` method. + _set_elf_rpaths(path, e.new.decode("utf-8").split(":")) + + def relocate_elf_binaries( binaries, orig_root, new_root, new_prefixes, rel, orig_prefix, new_prefix ): diff --git a/lib/spack/spack/test/relocate.py b/lib/spack/spack/test/relocate.py index 99dd7a460c4..da6d800e0a3 100644 --- a/lib/spack/spack/test/relocate.py +++ b/lib/spack/spack/test/relocate.py @@ -192,24 +192,6 @@ def test_file_is_relocatable_errors(tmpdir): assert "is not an absolute path" in str(exc_info.value) -@pytest.mark.parametrize( - "patchelf_behavior,expected", - [ - ("echo ", []), - ("echo /opt/foo/lib:/opt/foo/lib64", ["/opt/foo/lib", "/opt/foo/lib64"]), - ("exit 1", []), - ], -) -def test_existing_rpaths(patchelf_behavior, expected, mock_patchelf): - # Here we are mocking an executable that is always called "patchelf" - # because that will skip the part where we try to build patchelf - # by ourselves. The executable will output some rpaths like - # `patchelf --print-rpath` would. - path = mock_patchelf(patchelf_behavior) - rpaths = spack.relocate._elf_rpaths_for(path) - assert rpaths == expected - - @pytest.mark.parametrize( "start_path,path_root,paths,expected", [ diff --git a/lib/spack/spack/test/util/elf.py b/lib/spack/spack/test/util/elf.py index cf6b3aeb27e..b57477f54b0 100644 --- a/lib/spack/spack/test/util/elf.py +++ b/lib/spack/spack/test/util/elf.py @@ -5,6 +5,7 @@ import io +from collections import OrderedDict import pytest @@ -24,15 +25,6 @@ def skip_unless_linux(f): )(f) -@pytest.mark.requires_executables("gcc") -@skip_unless_linux -def test_elf_get_rpaths(binary_with_rpaths): - # Compile an "Hello world!" executable and set RPATHs - long_rpaths = ["/very/long/prefix/x", "/very/long/prefix/y"] - executable = str(binary_with_rpaths(rpaths=long_rpaths)) - assert elf.get_rpaths(executable) == long_rpaths - - @pytest.mark.requires_executables("gcc") @skip_unless_linux @pytest.mark.parametrize( @@ -128,3 +120,48 @@ def test_parser_doesnt_deal_with_nonzero_offset(): elf_at_offset_one.read(1) with pytest.raises(elf.ElfParsingError, match="Cannot parse at a nonzero offset"): elf.parse_elf(elf_at_offset_one) + + +@pytest.mark.requires_executables("gcc") +@skip_unless_linux +def test_elf_get_and_replace_rpaths(binary_with_rpaths): + long_rpaths = ["/very/long/prefix-a/x", "/very/long/prefix-b/y"] + executable = str(binary_with_rpaths(rpaths=long_rpaths)) + + # Before + assert elf.get_rpaths(executable) == long_rpaths + + replacements = OrderedDict( + [ + (b"/very/long/prefix-a", b"/short-a"), + (b"/very/long/prefix-b", b"/short-b"), + (b"/very/long", b"/dont"), + ] + ) + + # Replace once: should modify the file. + assert elf.replace_rpath_in_place_or_raise(executable, replacements) + + # Replace twice: nothing to be done. + assert not elf.replace_rpath_in_place_or_raise(executable, replacements) + + # Verify the rpaths were modified correctly + assert elf.get_rpaths(executable) == ["/short-a/x", "/short-b/y"] + + # Going back to long rpaths should fail, since we've added trailing \0 + # bytes, and replacement can't assume it can write back in repeated null + # bytes -- it may correspond to zero-length strings for example. + with pytest.raises( + elf.ElfDynamicSectionUpdateFailed, + match="New rpath /very/long/prefix-a/x:/very/long/prefix-b/y is " + "longer than old rpath /short-a/x:/short-b/y", + ): + elf.replace_rpath_in_place_or_raise( + executable, + OrderedDict( + [ + (b"/short-a", b"/very/long/prefix-a"), + (b"/short-b", b"/very/long/prefix-b"), + ] + ), + ) diff --git a/lib/spack/spack/util/elf.py b/lib/spack/spack/util/elf.py index bb9bfbb22d2..0b2e5a4e718 100644 --- a/lib/spack/spack/util/elf.py +++ b/lib/spack/spack/util/elf.py @@ -4,6 +4,7 @@ # SPDX-License-Identifier: (Apache-2.0 OR MIT) import bisect +import re import struct import sys from collections import namedtuple @@ -99,10 +100,6 @@ def get_byte_at(byte_array, idx): return byte_array[idx] -class ElfParsingError(Exception): - pass - - class ElfFile(object): """Parsed ELF file.""" @@ -121,6 +118,7 @@ class ElfFile(object): "has_pt_dynamic", "pt_dynamic_p_offset", "pt_dynamic_p_filesz", + "pt_dynamic_strtab_offset", # string table for dynamic section # rpath "has_rpath", "dt_rpath_offset", @@ -359,7 +357,8 @@ def parse_pt_dynamic(f, elf): if not (elf.has_rpath or elf.has_soname or elf.has_needed): return - string_table = retrieve_strtab(f, elf, vaddr_to_offset(elf, strtab_vaddr)) + elf.pt_dynamic_strtab_offset = vaddr_to_offset(elf, strtab_vaddr) + string_table = retrieve_strtab(f, elf, elf.pt_dynamic_strtab_offset) if elf.has_needed: elf.dt_needed_strs = list( @@ -457,3 +456,79 @@ def get_rpaths(path): if sys.version_info[0] >= 3: rpath = rpath.decode("utf-8") return rpath.split(":") + + +def replace_rpath_in_place_or_raise(path, substitutions): + regex = re.compile(b"|".join(re.escape(p) for p in substitutions.keys())) + + try: + with open(path, "rb+") as f: + elf = parse_elf(f, interpreter=False, dynamic_section=True) + + # If there's no RPATH, then there's no need to replace anything. + if not elf.has_rpath: + return False + + # Get the non-empty rpaths. Sometimes there's a bunch of trailing + # colons ::::: used for padding, we don't add them back to make it + # more likely that the string doesn't grow. + rpaths = list(filter(len, elf.dt_rpath_str.split(b":"))) + + num_rpaths = len(rpaths) + + if num_rpaths == 0: + return False + + changed = False + for i in range(num_rpaths): + old_rpath = rpaths[i] + match = regex.match(old_rpath) + if match: + changed = True + rpaths[i] = substitutions[match.group()] + old_rpath[match.end() :] + + # Nothing to replace! + if not changed: + return False + + new_rpath_string = b":".join(rpaths) + + pad = len(elf.dt_rpath_str) - len(new_rpath_string) + + if pad < 0: + raise ElfDynamicSectionUpdateFailed(elf.dt_rpath_str, new_rpath_string) + + # We zero out the bits we shortened because (a) it should be a + # C-string and (b) it's nice not to have spurious parts of old + # paths in the output of `strings file`. Note that we're all + # good when pad == 0; the original terminating null is used. + new_rpath_string += b"\x00" * pad + + # The rpath is at a given offset in the string table used by the + # dynamic section. + rpath_offset = elf.pt_dynamic_strtab_offset + elf.rpath_strtab_offset + + f.seek(rpath_offset) + f.write(new_rpath_string) + return True + + except ElfParsingError: + # This just means the file wasnt an elf file, so there's no point + # in updating its rpath anyways; ignore this problem. + return False + + +class ElfDynamicSectionUpdateFailed(Exception): + def __init__(self, old, new): + self.old = old + self.new = new + super(ElfDynamicSectionUpdateFailed, self).__init__( + "New rpath {} is longer than old rpath {}".format( + new.decode("utf-8"), + old.decode("utf-8"), + ) + ) + + +class ElfParsingError(Exception): + pass From 49d7aa21fdd1c843a543e9972cde5b0d055c6d0b Mon Sep 17 00:00:00 2001 From: snehring <7978778+snehring@users.noreply.github.com> Date: Fri, 4 Nov 2022 06:26:59 -0500 Subject: [PATCH 342/442] orca: add v5.0.3 (#33649) --- .../repos/builtin/packages/orca/package.py | 40 ++++++++++++------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/var/spack/repos/builtin/packages/orca/package.py b/var/spack/repos/builtin/packages/orca/package.py index 997cd569d6e..af4078cfb7c 100644 --- a/var/spack/repos/builtin/packages/orca/package.py +++ b/var/spack/repos/builtin/packages/orca/package.py @@ -19,8 +19,14 @@ class Orca(Package): homepage = "https://cec.mpg.de" url = "file://{0}/orca_4_0_1_2_linux_x86-64_openmpi202.tar.zst".format(os.getcwd()) + maintainers = ["snehring"] manual_download = True + version( + "5.0.3", + sha256="b8b9076d1711150a6d6cb3eb30b18e2782fa847c5a86d8404b9339faef105043", + url="file://{0}/orca_5_0_3_linux_x86-64_shared_openmpi411.tar.xz".format(os.getcwd()), + ) version( "4.2.1", sha256="9bbb3bfdca8220b417ee898b27b2885508d8c82799adfa63dde9e72eab49a6b2", @@ -37,10 +43,10 @@ class Orca(Package): expand=False, ) - depends_on("zstd", type="build") + depends_on("zstd", when="@:4.2.1", type="build") # Map Orca version with the required OpenMPI version - openmpi_versions = {"4.0.1.2": "2.0.2", "4.2.0": "3.1.4", "4.2.1": "3.1.4"} + openmpi_versions = {"4.0.1.2": "2.0.2", "4.2.0": "3.1.4", "4.2.1": "3.1.4", "5.0.3": "4.1.2"} for orca_version, openmpi_version in openmpi_versions.items(): depends_on( "openmpi@{0}".format(openmpi_version), type="run", when="@{0}".format(orca_version) @@ -51,20 +57,21 @@ def url_for_version(self, version): return out.format(os.getcwd(), version.underscored, self.openmpi_versions[version.string]) def install(self, spec, prefix): - # we have to extract the archive ourself - # fortunately it's just full of a bunch of binaries - - vername = os.path.basename(self.stage.archive_file).split(".")[0] - - zstd = which("zstd") - zstd("-d", self.stage.archive_file, "-o", vername + ".tar") - - tar = which("tar") - tar("-xvf", vername + ".tar") - - # there are READMEs in there but they don't hurt anyone mkdirp(prefix.bin) - install_tree(vername, prefix.bin) + + if self.spec.satisfies("@:4.2.1"): + vername = os.path.basename(self.stage.archive_file).split(".")[0] + + zstd = which("zstd") + zstd("-d", self.stage.archive_file, "-o", vername + ".tar") + + tar = which("tar") + tar("-xvf", vername + ".tar") + + # there are READMEs in there but they don't hurt anyone + install_tree(vername, prefix.bin) + else: + install_tree(".", prefix.bin) # Check "mpirun" usability when building against OpenMPI # with Slurm scheduler and add a "mpirun" wrapper that @@ -72,3 +79,6 @@ def install(self, spec, prefix): if "^openmpi ~legacylaunchers schedulers=slurm" in self.spec: mpirun_srun = join_path(os.path.dirname(__file__), "mpirun_srun.sh") install(mpirun_srun, prefix.bin.mpirun) + + def setup_run_environment(self, env): + env.prepend_path("LD_LIBRARY_PATH", self.prefix.bin) From bde4d1e38c3ee196d79fbd014d3f928f1c87cc13 Mon Sep 17 00:00:00 2001 From: Ashwin Kumar <46030335+iamashwin99@users.noreply.github.com> Date: Fri, 4 Nov 2022 06:59:45 -0700 Subject: [PATCH 343/442] Octopus: refactor AutotoolsPackage (#33526) --- .../repos/builtin/packages/octopus/package.py | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/var/spack/repos/builtin/packages/octopus/package.py b/var/spack/repos/builtin/packages/octopus/package.py index 3139eac3b59..7ff01e86336 100644 --- a/var/spack/repos/builtin/packages/octopus/package.py +++ b/var/spack/repos/builtin/packages/octopus/package.py @@ -5,12 +5,13 @@ import os +import llnl.util.filesystem as fs import llnl.util.tty as tty from spack.package import * -class Octopus(Package, CudaPackage): +class Octopus(AutotoolsPackage, CudaPackage): """A real-space finite-difference (time-dependent) density-functional theory code.""" @@ -55,10 +56,10 @@ class Octopus(Package, CudaPackage): variant("nlopt", default=False, description="Compile with nlopt") variant("debug", default=False, description="Compile with debug flags") - depends_on("autoconf", type="build") - depends_on("automake", type="build") - depends_on("libtool", type="build") - depends_on("m4", type="build") + depends_on("autoconf", type="build", when="@develop") + depends_on("automake", type="build", when="@develop") + depends_on("libtool", type="build", when="@develop") + depends_on("m4", type="build", when="@develop") depends_on("blas") depends_on("gsl@1.9:") @@ -90,7 +91,8 @@ class Octopus(Package, CudaPackage): # TODO: etsf-io, sparskit, # feast, libfm, pfft, isf, pnfft, poke - def install(self, spec, prefix): + def configure_args(self): + spec = self.spec lapack = spec["lapack"].libs blas = spec["blas"].libs args = [] @@ -211,12 +213,7 @@ def install(self, spec, prefix): args.append(fcflags) args.append(fflags) - autoreconf("-i") - configure(*args) - make() - # short tests take forever... - # make('check-short') - make("install") + return args @run_after("install") @on_package_attributes(run_tests=True) @@ -279,7 +276,7 @@ def smoke_tests(self): purpose = "Run Octopus recipe example" with working_dir("example-recipe", create=True): print("Current working directory (in example-recipe)") - copy(join_path(os.path.dirname(__file__), "test", "recipe.inp"), "inp") + fs.copy(join_path(os.path.dirname(__file__), "test", "recipe.inp"), "inp") self.run_test( exe, options=options, @@ -305,7 +302,7 @@ def smoke_tests(self): purpose = "Run tiny calculation for He" with working_dir("example-he", create=True): print("Current working directory (in example-he)") - copy(join_path(os.path.dirname(__file__), "test", "he.inp"), "inp") + fs.copy(join_path(os.path.dirname(__file__), "test", "he.inp"), "inp") self.run_test( exe, options=options, From 2caec6bd270a748bd0a06b3c6e605c8c4991c145 Mon Sep 17 00:00:00 2001 From: Greg Becker Date: Fri, 4 Nov 2022 08:42:06 -0700 Subject: [PATCH 344/442] Bugfix: glvis new builder interface (#33704) * take two * Add missing import statement * Group dependencies together * Extract libtiff arguments * Extract libpng arguments * Push preamble variable into png_args and tiff_args * Extract setting args associated with the screenshot variant * Inlined a few variables * Modify only build targets and install targets Co-authored-by: Massimiliano Culpo --- .../repos/builtin/packages/glvis/package.py | 144 +++++++++--------- 1 file changed, 76 insertions(+), 68 deletions(-) diff --git a/var/spack/repos/builtin/packages/glvis/package.py b/var/spack/repos/builtin/packages/glvis/package.py index de327d6341f..4f99698123e 100644 --- a/var/spack/repos/builtin/packages/glvis/package.py +++ b/var/spack/repos/builtin/packages/glvis/package.py @@ -2,7 +2,7 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - +import spack.build_systems.makefile from spack.package import * @@ -93,54 +93,43 @@ class Glvis(MakefilePackage): depends_on("glu") depends_on("libx11", when="@:3.5") - depends_on("sdl2", when="@4.0:,develop") - depends_on("glm", when="@4.0:,develop") - depends_on("glew", when="@4.0:,develop") + with when("@4.0:,develop"): + depends_on("sdl2") + depends_on("glm") + depends_on("glew") + depends_on("freetype") + depends_on("fontconfig") + + with when("+fonts"): + depends_on("freetype") + depends_on("fontconfig") depends_on("libpng", when="screenshots=png") depends_on("libtiff", when="screenshots=tiff") - depends_on("freetype", when="+fonts") - depends_on("freetype", when="@4.0:,develop") - depends_on("fontconfig", when="+fonts") - depends_on("fontconfig", when="@4.0:,develop") - depends_on("uuid", when="platform=linux") - def edit(self, spec, prefix): - def yes_no(s): - return "YES" if self.spec.satisfies(s) else "NO" - mfem = spec["mfem"] - config_mk = mfem.package.config_mk +class MakefileBuilder(spack.build_systems.makefile.MakefileBuilder): + @property + def build_targets(self): + return self.common_args() - args = [ + @property + def install_targets(self): + return ["install"] + self.common_args() + + def common_args(self): + spec = self.spec + result = [ "CC={0}".format(env["CC"]), - "PREFIX={0}".format(prefix.bin), - "MFEM_DIR={0}".format(mfem.prefix), - "CONFIG_MK={0}".format(config_mk), + "PREFIX={0}".format(self.spec.prefix.bin), + "MFEM_DIR={0}".format(self.spec["mfem"].prefix), + "CONFIG_MK={0}".format(self.spec["mfem"].package.config_mk), ] - png_args = ( - [ - "PNG_OPTS=-DGLVIS_USE_LIBPNG -I{0}".format(spec["libpng"].prefix.include), - "PNG_LIBS={0}".format(spec["libpng"].libs.ld_flags), - ] - if "screenshots=png" in spec - else [] - ) - - tiff_args = ( - [ - "TIFF_OPTS=-DGLVIS_USE_LIBTIFF -I{0}".format(spec["libtiff"].prefix.include), - "TIFF_LIBS={0}".format(spec["libtiff"].libs.ld_flags), - ] - if "screenshots=tiff" in spec - else [] - ) - - if "@4.0:" in spec or "@develop" in spec: + if self.spec.satisfies("@4.0:") or self.spec.satisfies("@develop"): # TODO: glu and fontconfig dirs - args += [ + result += [ "GLM_DIR={0}".format(spec["glm"].prefix), "SDL_DIR={0}".format(spec["sdl2"].prefix), "GLEW_DIR={0}".format(spec["glew"].prefix), @@ -148,19 +137,10 @@ def yes_no(s): "OPENGL_DIR={0}".format(spec["gl"].home), ] - if "screenshots=png" in spec: - args += ["GLVIS_USE_LIBPNG=YES", "GLVIS_USE_LIBTIFF=NO"] - args.extend(png_args) - elif "screenshots=tiff" in spec: - args += ["GLVIS_USE_LIBPNG=NO", "GLVIS_USE_LIBTIFF=YES"] - args.extend(tiff_args) - else: - args += ["GLVIS_USE_LIBPNG=NO", "GLVIS_USE_LIBTIFF=NO"] - else: gl_libs = spec["glu"].libs + spec["gl"].libs + spec["libx11"].libs - args += [ + result += [ "GL_OPTS=-I{0} -I{1} -I{2}".format( spec["libx11"].prefix.include, spec["gl"].home.include, @@ -168,26 +148,54 @@ def yes_no(s): ), "GL_LIBS={0}".format(gl_libs.ld_flags), ] + result.extend(self.fonts_args()) - if "screenshots=png" in spec: - args += ["USE_LIBPNG=YES", "USE_LIBTIFF=NO"] - args.extend(png_args) - elif "screenshots=tiff" in spec: - args += ["USE_LIBPNG=NO", "USE_LIBTIFF=YES"] - args.extend(tiff_args) - else: - args += ["USE_LIBPNG=NO", "USE_LIBTIFF=NO"] + if self.spec.satisfies("screenshots=png"): + result.extend(self.png_args()) + elif self.spec.satisfies("screenshots=tiff"): + result.extend(self.tiff_args()) + else: + result.extend(self.xwd_args()) - args.append("USE_FREETYPE={0}".format(yes_no("+fonts"))) - if "+fonts" in spec: - args += [ - "FT_OPTS=-DGLVIS_USE_FREETYPE {0} -I{1}".format( - spec["freetype"].headers.include_flags, spec["fontconfig"].prefix.include - ), - "FT_LIBS={0} {1}".format( - spec["freetype"].libs.ld_flags, spec["fontconfig"].libs.ld_flags - ), - ] + return result - self.builder.build_targets = args - self.builder.install_targets += args + def fonts_args(self): + if not self.spec.satisfies("+fonts"): + return ["USE_FREETYPE=NO"] + + freetype = self.spec["freetype"] + fontconfig = self.spec["fontconfig"] + return [ + "USE_FREETYPE=YES", + "FT_OPTS=-DGLVIS_USE_FREETYPE {0} -I{1}".format( + freetype.headers.include_flags, fontconfig.prefix.include + ), + "FT_LIBS={0} {1}".format(freetype.libs.ld_flags, fontconfig.libs.ld_flags), + ] + + def xwd_args(self): + if self.spec.satisfies("@4.0:") or self.spec.satisfies("@develop"): + return ["GLVIS_USE_LIBPNG=NO", "GLVIS_USE_LIBTIFF=NO"] + return ["USE_LIBPNG=NO", "USE_LIBTIFF=NO"] + + def png_args(self): + prefix_args = ["USE_LIBPNG=YES", "USE_LIBTIFF=NO"] + if self.spec.satisfies("@4.0:") or self.spec.satisfies("@develop"): + prefix_args = ["GLVIS_USE_LIBPNG=YES", "GLVIS_USE_LIBTIFF=NO"] + + libpng = self.spec["libpng"] + return prefix_args + [ + "PNG_OPTS=-DGLVIS_USE_LIBPNG -I{0}".format(libpng.prefix.include), + "PNG_LIBS={0}".format(libpng.libs.ld_flags), + ] + + def tiff_args(self): + prefix_args = ["USE_LIBPNG=NO", "USE_LIBTIFF=YES"] + if self.spec.satisfies("@4.0:") or self.spec.satisfies("@develop"): + prefix_args = ["GLVIS_USE_LIBPNG=NO", "GLVIS_USE_LIBTIFF=YES"] + + libtiff = self.spec["libtiff"] + return prefix_args + [ + "TIFF_OPTS=-DGLVIS_USE_LIBTIFF -I{0}".format(libtiff.prefix.include), + "TIFF_LIBS={0}".format(libtiff.libs.ld_flags), + ] From 7d4373f526b772874412defa5576950a7d2ab9a6 Mon Sep 17 00:00:00 2001 From: Erik Schnetter Date: Fri, 4 Nov 2022 13:05:23 -0400 Subject: [PATCH 345/442] libressl: New package (#33709) --- .../builtin/packages/libressl/package.py | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 var/spack/repos/builtin/packages/libressl/package.py diff --git a/var/spack/repos/builtin/packages/libressl/package.py b/var/spack/repos/builtin/packages/libressl/package.py new file mode 100644 index 00000000000..04550700341 --- /dev/null +++ b/var/spack/repos/builtin/packages/libressl/package.py @@ -0,0 +1,29 @@ +# 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 Libressl(AutotoolsPackage): + """LibreSSL is a version of the TLS/crypto stack forked from OpenSSL + in 2014, with goals of modernizing the codebase, improving + security, and applying best practice development processes.""" + + homepage = "https://www.libressl.org" + url = "https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-3.6.1.tar.gz" + + maintainers = ["eschnett"] + + version("3.6.1", sha256="acfac61316e93b919c28d62d53037ca734de85c46b4d703f19fd8395cf006774") + + variant("shared", default=True, description="Build shared libraries") + variant("static", default=False, description="Build static libraries") + + def configure_args(self): + args = [ + "--enable-shared" if "+shared" in spec else "--disable-shared", + "--enable-static" if "+static" in spec else "--disable-static", + ] + return args From 1a77f3e2e0f599fb40276627312867165c771c49 Mon Sep 17 00:00:00 2001 From: Erik Schnetter Date: Fri, 4 Nov 2022 13:06:11 -0400 Subject: [PATCH 346/442] gnutls: add v3.7.8 (#33708) --- var/spack/repos/builtin/packages/gnutls/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/gnutls/package.py b/var/spack/repos/builtin/packages/gnutls/package.py index d75ab7c15b4..9fc99707176 100644 --- a/var/spack/repos/builtin/packages/gnutls/package.py +++ b/var/spack/repos/builtin/packages/gnutls/package.py @@ -17,6 +17,7 @@ class Gnutls(AutotoolsPackage): homepage = "https://www.gnutls.org" url = "https://www.gnupg.org/ftp/gcrypt/gnutls/v3.5/gnutls-3.5.19.tar.xz" + version("3.7.8", sha256="c58ad39af0670efe6a8aee5e3a8b2331a1200418b64b7c51977fb396d4617114") version("3.6.15", sha256="0ea8c3283de8d8335d7ae338ef27c53a916f15f382753b174c18b45ffd481558") version("3.6.14", sha256="5630751adec7025b8ef955af4d141d00d252a985769f51b4059e5affa3d39d63") version("3.6.8", sha256="aa81944e5635de981171772857e72be231a7e0f559ae0292d2737de475383e83") From ac9172fdbc78e171940086e117a0aa03243c8732 Mon Sep 17 00:00:00 2001 From: Vicente Bolea Date: Fri, 4 Nov 2022 13:52:28 -0400 Subject: [PATCH 347/442] paraview: static cuda is not supported (#33246) --- var/spack/repos/builtin/packages/paraview/package.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/paraview/package.py b/var/spack/repos/builtin/packages/paraview/package.py index 3b2d98c13f0..ccd14f984ce 100644 --- a/var/spack/repos/builtin/packages/paraview/package.py +++ b/var/spack/repos/builtin/packages/paraview/package.py @@ -109,7 +109,7 @@ class Paraview(CMakePackage, CudaPackage): # Python 2 support dropped with 5.9.0 conflicts("+python", when="@5.9:") conflicts("+python3", when="@:5.5") - conflicts("+shared", when="+cuda") + conflicts("~shared", when="+cuda") conflicts("+cuda", when="@5.8:5.10") # Legacy rendering dropped in 5.5 # See commit: https://gitlab.kitware.com/paraview/paraview/-/commit/798d328c From 17eaf34902077aca2256a3acd735a5efb3dcb5b4 Mon Sep 17 00:00:00 2001 From: Greg Becker Date: Fri, 4 Nov 2022 11:12:55 -0700 Subject: [PATCH 348/442] fix requires test for aarch64 (#33656) --- lib/spack/spack/test/concretize.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py index 43f47259bfc..fd8baf85226 100644 --- a/lib/spack/spack/test/concretize.py +++ b/lib/spack/spack/test/concretize.py @@ -1904,11 +1904,11 @@ def test_require_targets_are_allowed(self, mutable_database): pytest.xfail("Use case not supported by the original concretizer") # Configuration to be added to packages.yaml - external_conf = {"all": {"require": "target=x86_64"}} + external_conf = {"all": {"require": "target=%s" % spack.platforms.test.Test.front_end}} spack.config.set("packages", external_conf) with spack.config.override("concretizer:reuse", False): spec = Spec("mpich").concretized() for s in spec.traverse(): - assert s.satisfies("target=x86_64") + assert s.satisfies("target=%s" % spack.platforms.test.Test.front_end) From 6f8e242db83d8adefae4846716bf93b0f83cbf2b Mon Sep 17 00:00:00 2001 From: Stephen McDowell Date: Fri, 4 Nov 2022 14:26:58 -0400 Subject: [PATCH 349/442] ECP-SDK: fixup +hdf5 +cuda contraints (#33676) Only enable the hdf5-vfd-gds package if it can compile. - hdf5-vfd-gds needs cuda@11.7.1+ to be able to `find_library` for cuFile. - Only enable hdf5-vfd-gds in the sdk if cuda@11.7.1+ is available. If an earlier version of cuda is being used, do not depend on the hdf5-vfd-gds package at all. --- .../builtin/packages/ecp-data-vis-sdk/package.py | 13 ++++++++++++- .../repos/builtin/packages/hdf5-vfd-gds/package.py | 3 +++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/ecp-data-vis-sdk/package.py b/var/spack/repos/builtin/packages/ecp-data-vis-sdk/package.py index 54a61243fee..e0f6676600e 100644 --- a/var/spack/repos/builtin/packages/ecp-data-vis-sdk/package.py +++ b/var/spack/repos/builtin/packages/ecp-data-vis-sdk/package.py @@ -113,7 +113,18 @@ class EcpDataVisSdk(BundlePackage, CudaPackage, ROCmPackage): dav_sdk_depends_on("faodel+shared+mpi network=libfabric", when="+faodel", propagate=["hdf5"]) dav_sdk_depends_on("hdf5@1.12: +shared+mpi", when="+hdf5", propagate=["fortran"]) - dav_sdk_depends_on("hdf5-vfd-gds@1.0.2:", when="+cuda+hdf5", propagate=cuda_arch_variants) + # hdf5-vfd-gds needs cuda@11.7.1 or later, only enable when 11.7.1+ available. + depends_on( + "hdf5-vfd-gds@1.0.2:", + when="+cuda+hdf5^cuda@11.7.1:", + ) + for cuda_arch in cuda_arch_variants: + depends_on( + "hdf5-vfd-gds@1.0.2: {0}".format(cuda_arch), + when="+cuda+hdf5 {0} ^cuda@11.7.1:".format(cuda_arch), + ) + conflicts("~cuda", when="^hdf5-vfd-gds@1.0.2:") + conflicts("~hdf5", when="^hdf5-vfd-gds@1.0.2:") dav_sdk_depends_on("parallel-netcdf+shared", when="+pnetcdf", propagate=["fortran"]) diff --git a/var/spack/repos/builtin/packages/hdf5-vfd-gds/package.py b/var/spack/repos/builtin/packages/hdf5-vfd-gds/package.py index b3e3960b248..7bc6f0e1ec4 100644 --- a/var/spack/repos/builtin/packages/hdf5-vfd-gds/package.py +++ b/var/spack/repos/builtin/packages/hdf5-vfd-gds/package.py @@ -23,6 +23,9 @@ class Hdf5VfdGds(CMakePackage, CudaPackage): # Dependencies conflicts("~cuda") + # Although cuFILE predates 11.7.0, it is not installed in a location the build + # system can obtaion via `find_library`. Packaging issues fixed in 11.7.1. + conflicts("^cuda@:11.7.0") depends_on("cmake@3.12:", type="build") depends_on("hdf5@1.13.0:") From 13565df027bb20b1f7de878b0adb9efa3547c1c2 Mon Sep 17 00:00:00 2001 From: Moritz Kern <92092328+Moritz-Alexander-Kern@users.noreply.github.com> Date: Fri, 4 Nov 2022 19:34:16 +0100 Subject: [PATCH 350/442] add elephant version v0.11.2 (#33663) --- var/spack/repos/builtin/packages/py-elephant/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/py-elephant/package.py b/var/spack/repos/builtin/packages/py-elephant/package.py index cdfc9092ebf..33363ac6925 100644 --- a/var/spack/repos/builtin/packages/py-elephant/package.py +++ b/var/spack/repos/builtin/packages/py-elephant/package.py @@ -16,6 +16,7 @@ class PyElephant(PythonPackage): # list of GitHub accounts to notify when the package is updated. maintainers = ["Moritz-Alexander-Kern"] + version("0.11.2", sha256="f8759fff0bbb136ae4ffc8d1eacadeea8ba56610d705c3bf207de87ada3ba240") version("0.11.1", sha256="d604a202583440fdf9d95d42cef50a410bd74fcaaa1a925b139435f27ab012ef") version("0.11.0", sha256="7b547964dbd196361edc922db2c5a7c0c886ef1effcca6c6dc7adb06f966a3be") version("0.10.0", sha256="7e69a113475e4db01b3563328953c037d37f1597d9f2edf0d51fb65e9aebf096") From 33e5e772253d2a8ad3836760a96ac7baf4d73d17 Mon Sep 17 00:00:00 2001 From: Dom Heinzeller Date: Fri, 4 Nov 2022 12:52:27 -0600 Subject: [PATCH 351/442] Python package: fix .libs on macOS with external Python (#33410) For some instances of externally-provided Python (e.g. Homebrew), the LDLIBRARY/LIBRARY config variables don't actually refer to libraries and should therefore be excluded from ".libs". --- .../repos/builtin/packages/python/package.py | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/var/spack/repos/builtin/packages/python/package.py b/var/spack/repos/builtin/packages/python/package.py index 8a69efbbda4..3fea87a2ec7 100644 --- a/var/spack/repos/builtin/packages/python/package.py +++ b/var/spack/repos/builtin/packages/python/package.py @@ -1250,12 +1250,29 @@ def libs(self): # The values of LDLIBRARY and LIBRARY aren't reliable. Intel Python uses a # static binary but installs shared libraries, so sysconfig reports # libpythonX.Y.a but only libpythonX.Y.so exists. So we add our own paths, too. - shared_libs = [ - self.config_vars["LDLIBRARY"], + + # With framework python on macOS, self.config_vars["LDLIBRARY"] can point + # to a library that is not linkable because it does not have the required + # suffix of a shared library (it is called "Python" without extention). + # The linker then falls back to libPython.tbd in the default macOS + # software tree, which security settings prohibit to link against + # (your binary is not an allowed client of /path/to/libPython.tbd). + # To avoid this, we replace the entry in config_vars with a default value. + file_extension_shared = os.path.splitext(self.config_vars["LDLIBRARY"])[-1] + if file_extension_shared == "": + shared_libs = [] + else: + shared_libs = [self.config_vars["LDLIBRARY"]] + shared_libs += [ "{}python{}.{}".format(lib_prefix, py_version, dso_suffix), ] - static_libs = [ - self.config_vars["LIBRARY"], + # Like LDLIBRARY for Python on Mac OS, LIBRARY may refer to an un-linkable object + file_extension_static = os.path.splitext(self.config_vars["LIBRARY"])[-1] + if file_extension_static == "": + static_libs = [] + else: + static_libs = [self.config_vars["LIBRARY"]] + static_libs += [ "{}python{}.{}".format(lib_prefix, py_version, stat_suffix), ] From d338ac063442b3a7731d37ba51320c4d9cf89461 Mon Sep 17 00:00:00 2001 From: Tamara Dahlgren <35777542+tldahlgren@users.noreply.github.com> Date: Fri, 4 Nov 2022 11:55:38 -0700 Subject: [PATCH 352/442] Updates to stand-alone test documentation (#33703) --- lib/spack/docs/packaging_guide.rst | 33 +++++-- lib/spack/spack/install_test.py | 143 ++++++++++++++++++++++++++--- 2 files changed, 154 insertions(+), 22 deletions(-) diff --git a/lib/spack/docs/packaging_guide.rst b/lib/spack/docs/packaging_guide.rst index f7b8cfe35fc..b6184974973 100644 --- a/lib/spack/docs/packaging_guide.rst +++ b/lib/spack/docs/packaging_guide.rst @@ -5260,6 +5260,16 @@ where each argument has the following meaning: will run. The default of ``None`` corresponds to the current directory (``'.'``). + Each call starts with the working directory set to the spec's test stage + directory (i.e., ``self.test_suite.test_dir_for_spec(self.spec)``). + +.. warning:: + + Use of the package spec's installation directory for building and running + tests is **strongly** discouraged. Doing so has caused permission errors + for shared spack instances *and* for facilities that install the software + in read-only file systems or directories. + """"""""""""""""""""""""""""""""""""""""" Accessing package- and test-related files @@ -5267,10 +5277,10 @@ Accessing package- and test-related files You may need to access files from one or more locations when writing stand-alone tests. This can happen if the software's repository does not -include test source files or includes files but no way to build the -executables using the installed headers and libraries. In these -cases, you may need to reference the files relative to one or more -root directory. The properties containing package- and test-related +include test source files or includes files but has no way to build the +executables using the installed headers and libraries. In these cases, +you may need to reference the files relative to one or more root +directory. The properties containing package- (or spec-) and test-related directory paths are provided in the table below. .. list-table:: Directory-to-property mapping @@ -5279,19 +5289,22 @@ directory paths are provided in the table below. * - Root Directory - Package Property - Example(s) - * - Package Installation Files + * - Package (Spec) Installation - ``self.prefix`` - ``self.prefix.include``, ``self.prefix.lib`` - * - Package Dependency's Files + * - Dependency Installation - ``self.spec[''].prefix`` - ``self.spec['trilinos'].prefix.include`` - * - Test Suite Stage Files + * - Test Suite Stage - ``self.test_suite.stage`` - ``join_path(self.test_suite.stage, 'results.txt')`` - * - Staged Cached Build-time Files + * - Spec's Test Stage + - ``self.test_suite.test_dir_for_spec`` + - ``self.test_suite.test_dir_for_spec(self.spec)`` + * - Current Spec's Build-time Files - ``self.test_suite.current_test_cache_dir`` - ``join_path(self.test_suite.current_test_cache_dir, 'examples', 'foo.c')`` - * - Staged Custom Package Files + * - Current Spec's Custom Test Files - ``self.test_suite.current_test_data_dir`` - ``join_path(self.test_suite.current_test_data_dir, 'hello.f90')`` @@ -6375,4 +6388,4 @@ To achieve backward compatibility with the single-class format Spack creates in Overall the role of the adapter is to route access to attributes of methods first through the ``*Package`` hierarchy, and then back to the base class builder. This is schematically shown in the diagram above, where -the adapter role is to "emulate" a method resolution order like the one represented by the red arrows. \ No newline at end of file +the adapter role is to "emulate" a method resolution order like the one represented by the red arrows. diff --git a/lib/spack/spack/install_test.py b/lib/spack/spack/install_test.py index da2b73032e4..3c976febb1b 100644 --- a/lib/spack/spack/install_test.py +++ b/lib/spack/spack/install_test.py @@ -43,12 +43,24 @@ def get_escaped_text_output(filename): def get_test_stage_dir(): + """Retrieves the ``config:test_stage`` path to the configured test stage + root directory + + Returns: + str: absolute path to the configured test stage root or, if none, + the default test stage path + """ return spack.util.path.canonicalize_path( spack.config.get("config:test_stage", spack.paths.default_test_path) ) def get_all_test_suites(): + """Retrieves all validly staged TestSuites + + Returns: + list: a list of TestSuite objects, which may be empty if there are none + """ stage_root = get_test_stage_dir() if not os.path.isdir(stage_root): return [] @@ -68,7 +80,14 @@ def valid_stage(d): def get_named_test_suites(name): - """Return a list of the names of any test suites with that name.""" + """Retrieves test suites with the provided name. + + Returns: + list: a list of matching TestSuite instances, which may be empty if none + + Raises: + TestSuiteNameError: If no name is provided + """ if not name: raise TestSuiteNameError("Test suite name is required.") @@ -77,6 +96,14 @@ def get_named_test_suites(name): def get_test_suite(name): + """Ensure there is only one matching test suite with the provided name. + + Returns: + str or None: the name if one matching test suite, else None + + Raises: + TestSuiteNameError: If there is more than one matching TestSuite + """ names = get_named_test_suites(name) if len(names) > 1: raise TestSuiteNameError('Too many suites named "{0}". May shadow hash.'.format(name)) @@ -87,12 +114,14 @@ def get_test_suite(name): def write_test_suite_file(suite): - """Write the test suite to its lock file.""" + """Write the test suite to its (JSON) lock file.""" with open(suite.stage.join(test_suite_filename), "w") as f: sjson.dump(suite.to_dict(), stream=f) def write_test_summary(num_failed, num_skipped, num_untested, num_specs): + """Write a well formatted summary of the totals for each relevant status + category.""" failed = "{0} failed, ".format(num_failed) if num_failed else "" skipped = "{0} skipped, ".format(num_skipped) if num_skipped else "" no_tests = "{0} no-tests, ".format(num_untested) if num_untested else "" @@ -108,6 +137,8 @@ def write_test_summary(num_failed, num_skipped, num_untested, num_specs): class TestSuite(object): + """The class that manages specs for ``spack test run`` execution.""" + def __init__(self, specs, alias=None): # copy so that different test suites have different package objects # even if they contain the same spec @@ -122,10 +153,12 @@ def __init__(self, specs, alias=None): @property def name(self): + """The name (alias or, if none, hash) of the test suite.""" return self.alias if self.alias else self.content_hash @property def content_hash(self): + """The hash used to uniquely identify the test suite.""" if not self._hash: json_text = sjson.dump(self.to_dict()) sha = hashlib.sha1(json_text.encode("utf-8")) @@ -212,48 +245,100 @@ def __call__(self, *args, **kwargs): raise TestSuiteFailure(self.fails) def ensure_stage(self): + """Ensure the test suite stage directory exists.""" if not os.path.exists(self.stage): fs.mkdirp(self.stage) @property def stage(self): + """The root test suite stage directory.""" return spack.util.prefix.Prefix(os.path.join(get_test_stage_dir(), self.content_hash)) @property def results_file(self): + """The path to the results summary file.""" return self.stage.join(results_filename) @classmethod def test_pkg_id(cls, spec): - """Build the standard install test package identifier + """The standard install test package identifier. Args: - spec (Spec): instance of the spec under test + spec (spack.spec.Spec): instance of the spec under test Returns: - (str): the install test package identifier + str: the install test package identifier """ return spec.format("{name}-{version}-{hash:7}") @classmethod def test_log_name(cls, spec): + """The standard log filename for a spec. + + Args: + spec (spack.spec.Spec): instance of the spec under test + + Returns: + str: the spec's log filename + """ return "%s-test-out.txt" % cls.test_pkg_id(spec) def log_file_for_spec(self, spec): + """The test log file path for the provided spec. + + Args: + spec (spack.spec.Spec): instance of the spec under test + + Returns: + str: the path to the spec's log file + """ return self.stage.join(self.test_log_name(spec)) def test_dir_for_spec(self, spec): + """The path to the test stage directory for the provided spec. + + Args: + spec (spack.spec.Spec): instance of the spec under test + + Returns: + str: the spec's test stage directory path + """ return self.stage.join(self.test_pkg_id(spec)) @classmethod def tested_file_name(cls, spec): + """The standard test status filename for the spec. + + Args: + spec (spack.spec.Spec): instance of the spec under test + + Returns: + str: the spec's test status filename + """ return "%s-tested.txt" % cls.test_pkg_id(spec) def tested_file_for_spec(self, spec): + """The test status file path for the spec. + + Args: + spec (spack.spec.Spec): instance of the spec under test + + Returns: + str: the spec's test status file path + """ return self.stage.join(self.tested_file_name(spec)) @property def current_test_cache_dir(self): + """Path to the test stage directory where the current spec's cached + build-time files were automatically copied. + + Returns: + str: path to the current spec's staged, cached build-time files. + + Raises: + TestSuiteSpecError: If there is no spec being tested + """ if not (self.current_test_spec and self.current_base_spec): raise TestSuiteSpecError("Unknown test cache directory: no specs being tested") @@ -263,6 +348,15 @@ def current_test_cache_dir(self): @property def current_test_data_dir(self): + """Path to the test stage directory where the current spec's custom + package (data) files were automatically copied. + + Returns: + str: path to the current spec's staged, custom package (data) files + + Raises: + TestSuiteSpecError: If there is no spec being tested + """ if not (self.current_test_spec and self.current_base_spec): raise TestSuiteSpecError("Unknown test data directory: no specs being tested") @@ -270,13 +364,13 @@ def current_test_data_dir(self): base_spec = self.current_base_spec return self.test_dir_for_spec(base_spec).data.join(test_spec.name) - def add_failure(self, exc, msg): - current_hash = self.current_base_spec.dag_hash() - current_failures = self.failures.get(current_hash, []) - current_failures.append((exc, msg)) - self.failures[current_hash] = current_failures - def write_test_result(self, spec, result): + """Write the spec's test result to the test suite results file. + + Args: + spec (spack.spec.Spec): instance of the spec under test + result (str): result from the spec's test execution (e.g, PASSED) + """ msg = "{0} {1}".format(self.test_pkg_id(spec), result) _add_msg_to_file(self.results_file, msg) @@ -295,6 +389,14 @@ def write_reproducibility_data(self): write_test_suite_file(self) def to_dict(self): + """Build a dictionary for the test suite. + + Returns: + dict: The dictionary contains entries for up to two keys: + + specs: list of the test suite's specs in dictionary form + alias: the alias, or name, given to the test suite if provided + """ specs = [s.to_dict() for s in self.specs] d = {"specs": specs} if self.alias: @@ -303,12 +405,29 @@ def to_dict(self): @staticmethod def from_dict(d): + """Instantiates a TestSuite based on a dictionary specs and an + optional alias: + + specs: list of the test suite's specs in dictionary form + alias: the test suite alias + + + Returns: + TestSuite: Instance of TestSuite created from the specs + """ specs = [Spec.from_dict(spec_dict) for spec_dict in d["specs"]] alias = d.get("alias", None) return TestSuite(specs, alias) @staticmethod def from_file(filename): + """Instantiate a TestSuite using the specs and optional alias + provided in the given file. + + Args: + filename (str): The path to the JSON file containing the test + suite specs and optional alias. + """ try: with open(filename, "r") as f: data = sjson.load(f) @@ -324,7 +443,7 @@ def from_file(filename): def _add_msg_to_file(filename, msg): - """Add the message to the specified file + """Append the message to the specified file. Args: filename (str): path to the file From b6da8635ec50b1cc7a88b99689920918ca5c4b90 Mon Sep 17 00:00:00 2001 From: Alberto Sartori Date: Fri, 4 Nov 2022 19:59:27 +0100 Subject: [PATCH 353/442] add justbuild package (#33689) --- .../builtin/packages/justbuild/package.py | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 var/spack/repos/builtin/packages/justbuild/package.py diff --git a/var/spack/repos/builtin/packages/justbuild/package.py b/var/spack/repos/builtin/packages/justbuild/package.py new file mode 100644 index 00000000000..5cf9499a2d5 --- /dev/null +++ b/var/spack/repos/builtin/packages/justbuild/package.py @@ -0,0 +1,82 @@ +# 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) + +import os + +from spack.package import * + + +class Justbuild(Package): + "just, a generic build tool" + + git = "https://github.com/just-buildsystem/justbuild.git" + + homepage = "https://github.com/just-buildsystem/justbuild" + + tags = ["build-tools"] + + executables = ["^just$"] + + maintainers = ["asartori86"] + + version("master", branch="master") + + depends_on("python@3:", type=("build", "run")) + depends_on("wget", type=("build", "run")) + + sanity_check_is_file = [join_path("bin", "just"), join_path("bin", "just-mr")] + + def setup_build_environment(self, env): + ar = which("ar") + if self.spec.satisfies("%gcc@10:"): + gcc = which("gcc") + gpp = which("g++") + env.set( + "JUST_BUILD_CONF", + " {" + + ' "CC":"{0}"'.format(gcc.path) + + ', "CXX":"{0}"'.format(gpp.path) + + ', "AR":"{0}"'.format(ar.path) + + ', "COMPILER_FAMILY":"unknown"' + + ', "ENV":{' + + ' "PATH":"{0}"'.format(os.environ["PATH"]) + + " }" + + "}", + ) + elif self.spec.satisfies("%clang@11:") or spec.satisfies("%apple-clang@11:"): + clang = which("clang") + clangpp = which("clang++") + env.set( + "JUST_BUILD_CONF", + " {" + + ' "CC":"{0}"'.format(clang.path) + + ', "CXX":"{0}"'.format(clangpp.path) + + ', "AR":"{0}"'.format(ar.path) + + ', "COMPILER_FAMILY":"unknown"' + + ', "ENV":{' + + ' "PATH":"{0}"'.format(os.environ["PATH"]) + + " }" + + "}", + ) + else: + raise InstallError("please use gcc >= 10 or clang >= 11") + + def install(self, spec, prefix): + python = which("python3") + python(os.path.join("bin", "bootstrap.py"), ".", prefix) + mkdirp(prefix.bin) + install(os.path.join(prefix, "out", "bin", "just"), prefix.bin) + install(os.path.join("bin", "just-mr.py"), os.path.join(prefix.bin, "just-mr")) + + @classmethod + def determine_version(cls, exe): + import json + + try: + s = os.popen(exe + " version").read() + d = json.loads(s) + return ".".join(map(str, d["version"])) + d["suffix"].replace("~", "-") + except Exception: + return None From a4f3fe2ac7997b25ed6358b5fffee728603cd2d5 Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Fri, 4 Nov 2022 20:06:42 +0100 Subject: [PATCH 354/442] Deprecate old YAML format for buildcaches (#33707) --- lib/spack/spack/binary_distribution.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/spack/spack/binary_distribution.py b/lib/spack/spack/binary_distribution.py index 3de0bcf9db6..5ea7138a167 100644 --- a/lib/spack/spack/binary_distribution.py +++ b/lib/spack/spack/binary_distribution.py @@ -950,13 +950,13 @@ def generate_package_index(cache_prefix): .json) under cache_prefix. """ try: - file_list = ( + file_list = [ entry for entry in web_util.list_url(cache_prefix) if entry.endswith(".yaml") or entry.endswith("spec.json") or entry.endswith("spec.json.sig") - ) + ] except KeyError as inst: msg = "No packages at {0}: {1}".format(cache_prefix, inst) tty.warn(msg) @@ -969,6 +969,14 @@ def generate_package_index(cache_prefix): tty.warn(msg) return + if any(x.endswith(".yaml") for x in file_list): + msg = ( + "The mirror in '{}' contains specs in the deprecated YAML format.\n\n\tSupport for " + "this format will be removed in v0.20, please regenerate the build cache with a " + "recent Spack\n" + ).format(cache_prefix) + warnings.warn(msg) + tty.debug("Retrieving spec descriptor files from {0} to build index".format(cache_prefix)) tmpdir = tempfile.mkdtemp() @@ -1436,6 +1444,13 @@ def download_tarball(spec, unsigned=False, mirrors_for_spec=None): # the remaining mirrors, looking for one we can use. tarball_stage = try_fetch(spackfile_url) if tarball_stage: + if ext == "yaml": + msg = ( + "Reading {} from mirror.\n\n\tThe YAML format for buildcaches is " + "deprecated and will be removed in v0.20\n" + ).format(spackfile_url) + warnings.warn(msg) + return { "tarball_stage": tarball_stage, "specfile_stage": local_specfile_stage, From e85b3082122b58c0e9bae8e892aba8ed7b70c047 Mon Sep 17 00:00:00 2001 From: kent-cheung-arm <40630626+kent-cheung-arm@users.noreply.github.com> Date: Fri, 4 Nov 2022 19:18:20 +0000 Subject: [PATCH 355/442] arm-forge: add 22.1 and 22.1.1. (#33584) --- .../repos/builtin/packages/arm-forge/package.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/var/spack/repos/builtin/packages/arm-forge/package.py b/var/spack/repos/builtin/packages/arm-forge/package.py index 61c85810127..9d658301f35 100644 --- a/var/spack/repos/builtin/packages/arm-forge/package.py +++ b/var/spack/repos/builtin/packages/arm-forge/package.py @@ -23,6 +23,10 @@ class ArmForge(Package): # versions (and checksums) based on the target platform shows up if platform.machine() == "aarch64": + version( + "22.1.1", sha256="f352625659a5319ca26130b633cbe8cc8e5fda312c50a8cd81145051eb66855c" + ) + version("22.1", sha256="c0e2639051f75be77a440fd00f049ffd42a932a6c2459372e64657a8e5b78779") version( "22.0.4", sha256="f770781d3c5e2fccb341f6b6ea7ddbe106e26168d4bad4cad3296b2eef65cb76" ) @@ -57,6 +61,10 @@ class ArmForge(Package): ) version("21.0", sha256="2bcc745d0049d6b25c77c97b2d7bad7b4f804180972a2306a8599ce41f6a4573") elif platform.machine() == "ppc64le": + version( + "22.1.1", sha256="c160779ad7217582ced9924a2af90330626af34385d07f4c39b827f929f89508" + ) + version("22.1", sha256="b94a7923360a76a431b29b939191bce1d2076bc6bc0bc698f24191055328952c") version( "22.0.4", sha256="f4cb5bcbaa67f9209299fe4653186a2829760b8b16a2883913aa43766375b04c" ) @@ -91,6 +99,10 @@ class ArmForge(Package): ) version("21.0", sha256="60cfa7dd1cd131ec85e67cb660f2f84cf30bb700d8979cae1f5f88af658fd249") elif platform.machine() == "x86_64": + version( + "22.1.1", sha256="392a7b0b4a212c506dc600ca2c37001cf85780ea2248fc47701953f12ef35300" + ) + version("22.1", sha256="3a1346ec10ff1871de7a013bacc21911976f97640297fc8d88136c4f91092e69") version( "22.0.4", sha256="a2c8c1da38b9684d7c4656a98b3fc42777b03fd474cd0bf969324804f47587e5" ) From 76ec64859aeb60d934a0257a0e9340e379b7cbe4 Mon Sep 17 00:00:00 2001 From: Matthieu Boileau Date: Fri, 4 Nov 2022 20:19:34 +0100 Subject: [PATCH 356/442] Fix typo in docs (#33662) --- lib/spack/docs/configuration.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/spack/docs/configuration.rst b/lib/spack/docs/configuration.rst index 21c8f4afaf4..add9150967b 100644 --- a/lib/spack/docs/configuration.rst +++ b/lib/spack/docs/configuration.rst @@ -549,7 +549,7 @@ down the problem: You can see above that the ``build_jobs`` and ``debug`` settings are built in and are not overridden by a configuration file. The -``verify_ssl`` setting comes from the ``--insceure`` option on the +``verify_ssl`` setting comes from the ``--insecure`` option on the command line. ``dirty`` and ``install_tree`` come from the custom scopes ``./my-scope`` and ``./my-scope-2``, and all other configuration options come from the default configuration files that ship with Spack. From fb5ff901c0f5458895e20471fd4dab345e7c1bf2 Mon Sep 17 00:00:00 2001 From: Sinan Date: Fri, 4 Nov 2022 14:34:50 -0700 Subject: [PATCH 357/442] package/py-pykml: add new py3 compatible version (#33631) * package/py-pykml: add new py3 compatible version * fix bugs Co-authored-by: sbulut --- var/spack/repos/builtin/packages/py-pykml/package.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/var/spack/repos/builtin/packages/py-pykml/package.py b/var/spack/repos/builtin/packages/py-pykml/package.py index ce2df0cb23f..fabaf8136d7 100644 --- a/var/spack/repos/builtin/packages/py-pykml/package.py +++ b/var/spack/repos/builtin/packages/py-pykml/package.py @@ -14,7 +14,10 @@ class PyPykml(PythonPackage): pypi = "pykml/pykml-0.1.3.tar.gz" + version("0.2.0", sha256="44a1892e7c2a649c8ae9f8e2899ff76cae79ec6749ffb64d11140b4e87d0f957") version("0.1.3", sha256="e1a133e582f0b4652a6b00bac970b446d90580664e5a634a670731c990ff9f05") + depends_on("python@2", type=("build", "run"), when="@0.1") depends_on("py-setuptools", type="build") + depends_on("py-lxml@3.3.6:", type=("build", "run"), when="@0.2.0:") depends_on("py-lxml@2.2.6:", type=("build", "run")) From a88c74dc1795e7aa38c5ac04b7af16d1c7c586f5 Mon Sep 17 00:00:00 2001 From: Greg Becker Date: Fri, 4 Nov 2022 14:50:05 -0700 Subject: [PATCH 358/442] delegate to cray modules for target args on cray (#17857) --- lib/spack/spack/build_environment.py | 6 +++++- lib/spack/spack/spec.py | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py index c69dd566e65..9247d9f1506 100644 --- a/lib/spack/spack/build_environment.py +++ b/lib/spack/spack/build_environment.py @@ -332,7 +332,11 @@ def set_compiler_environment_variables(pkg, env): env.set("SPACK_DTAGS_TO_ADD", compiler.enable_new_dtags) # Set the target parameters that the compiler will add - isa_arg = spec.architecture.target.optimization_flags(compiler) + # Don't set on cray platform because the targeting module handles this + if spec.satisfies("platform=cray"): + isa_arg = "" + else: + isa_arg = spec.architecture.target.optimization_flags(compiler) env.set("SPACK_TARGET_ARGS", isa_arg) # Trap spack-tracked compiler flags as appropriate. diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py index dd1ce821d96..a419fdf057b 100644 --- a/lib/spack/spack/spec.py +++ b/lib/spack/spack/spec.py @@ -2755,7 +2755,9 @@ def _old_concretize(self, tests=False, deprecation_warning=True): # Check if we can produce an optimized binary (will throw if # there are declared inconsistencies) - self.architecture.target.optimization_flags(self.compiler) + # No need on platform=cray because of the targeting modules + if not self.satisfies("platform=cray"): + self.architecture.target.optimization_flags(self.compiler) def _patches_assigned(self): """Whether patches have been assigned to this spec by the concretizer.""" From 53fbaa5dcded49d4fa04ee307813071873dab4f3 Mon Sep 17 00:00:00 2001 From: Greg Becker Date: Fri, 4 Nov 2022 14:52:11 -0700 Subject: [PATCH 359/442] Cray support: use linux platform for newer craype versions (#29392) Newer versions of the CrayPE for EX systems have standalone compiler executables for CCE and compiler wrappers for Cray MPICH. With those, we can treat the cray systems as part of the linux platform rather than having a separate cray platform. This PR: - [x] Changes cray platform detection to ignore EX systems with Craype version 21.10 or later - [x] Changes the cce compiler to be detectable via paths - [x] Changes the spack compiler wrapper to understand the executable names for the standalone cce compiler (`craycc`, `crayCC`, `crayftn`). --- lib/spack/env/cc | 8 +-- lib/spack/env/cce/case-insensitive/crayCC | 1 + lib/spack/env/cce/craycc | 1 + lib/spack/env/cce/crayftn | 1 + lib/spack/spack/compilers/cce.py | 47 +++++++++++------- lib/spack/spack/platforms/cray.py | 49 ++++++++++++++++--- lib/spack/spack/test/architecture.py | 26 ++++++++++ .../builtin/packages/aluminum/package.py | 8 +-- .../repos/builtin/packages/esmf/package.py | 2 +- .../repos/builtin/packages/mpich/package.py | 6 +-- .../builtin/packages/mvapich2/package.py | 6 +-- .../builtin/packages/opencoarrays/package.py | 2 +- .../repos/builtin/packages/scorep/package.py | 6 ++- .../repos/builtin/packages/xsdk/package.py | 4 +- 14 files changed, 121 insertions(+), 46 deletions(-) create mode 120000 lib/spack/env/cce/case-insensitive/crayCC create mode 120000 lib/spack/env/cce/craycc create mode 120000 lib/spack/env/cce/crayftn diff --git a/lib/spack/env/cc b/lib/spack/env/cc index bef7209bfac..ffdddfc0dfb 100755 --- a/lib/spack/env/cc +++ b/lib/spack/env/cc @@ -241,28 +241,28 @@ case "$command" in mode=cpp debug_flags="-g" ;; - cc|c89|c99|gcc|clang|armclang|icc|icx|pgcc|nvc|xlc|xlc_r|fcc|amdclang|cl.exe) + cc|c89|c99|gcc|clang|armclang|icc|icx|pgcc|nvc|xlc|xlc_r|fcc|amdclang|cl.exe|craycc) command="$SPACK_CC" language="C" comp="CC" lang_flags=C debug_flags="-g" ;; - c++|CC|g++|clang++|armclang++|icpc|icpx|dpcpp|pgc++|nvc++|xlc++|xlc++_r|FCC|amdclang++) + c++|CC|g++|clang++|armclang++|icpc|icpx|dpcpp|pgc++|nvc++|xlc++|xlc++_r|FCC|amdclang++|crayCC) command="$SPACK_CXX" language="C++" comp="CXX" lang_flags=CXX debug_flags="-g" ;; - ftn|f90|fc|f95|gfortran|flang|armflang|ifort|ifx|pgfortran|nvfortran|xlf90|xlf90_r|nagfor|frt|amdflang) + ftn|f90|fc|f95|gfortran|flang|armflang|ifort|ifx|pgfortran|nvfortran|xlf90|xlf90_r|nagfor|frt|amdflang|crayftn) command="$SPACK_FC" language="Fortran 90" comp="FC" lang_flags=F debug_flags="-g" ;; - f77|xlf|xlf_r|pgf77|amdflang) + f77|xlf|xlf_r|pgf77) command="$SPACK_F77" language="Fortran 77" comp="F77" diff --git a/lib/spack/env/cce/case-insensitive/crayCC b/lib/spack/env/cce/case-insensitive/crayCC new file mode 120000 index 00000000000..e2deb67f3b6 --- /dev/null +++ b/lib/spack/env/cce/case-insensitive/crayCC @@ -0,0 +1 @@ +../../cc \ No newline at end of file diff --git a/lib/spack/env/cce/craycc b/lib/spack/env/cce/craycc new file mode 120000 index 00000000000..82c2b8e90a3 --- /dev/null +++ b/lib/spack/env/cce/craycc @@ -0,0 +1 @@ +../cc \ No newline at end of file diff --git a/lib/spack/env/cce/crayftn b/lib/spack/env/cce/crayftn new file mode 120000 index 00000000000..82c2b8e90a3 --- /dev/null +++ b/lib/spack/env/cce/crayftn @@ -0,0 +1 @@ +../cc \ No newline at end of file diff --git a/lib/spack/spack/compilers/cce.py b/lib/spack/spack/compilers/cce.py index d572a31ff47..3ecbcdc3d66 100644 --- a/lib/spack/spack/compilers/cce.py +++ b/lib/spack/spack/compilers/cce.py @@ -2,7 +2,6 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - import os from spack.compiler import Compiler, UnsupportedCompilerFlag @@ -12,17 +11,25 @@ class Cce(Compiler): """Cray compiler environment compiler.""" + def __init__(self, *args, **kwargs): + super(Cce, self).__init__(*args, **kwargs) + # For old cray compilers on module based systems we replace + # ``version_argument`` with the old value. Cannot be a property + # as the new value is used in classmethods for path-based detection + if not self.is_clang_based: + self.version_argument = "-V" + # Subclasses use possible names of C compiler - cc_names = ["cc"] + cc_names = ["craycc", "cc"] # Subclasses use possible names of C++ compiler - cxx_names = ["CC"] + cxx_names = ["crayCC", "CC"] # Subclasses use possible names of Fortran 77 compiler - f77_names = ["ftn"] + f77_names = ["crayftn", "ftn"] # Subclasses use possible names of Fortran 90 compiler - fc_names = ["ftn"] + fc_names = ["crayftn", "ftn"] # MacPorts builds gcc versions with prefixes and -mp-X.Y suffixes. suffixes = [r"-mp-\d\.\d"] @@ -30,24 +37,30 @@ class Cce(Compiler): PrgEnv = "PrgEnv-cray" PrgEnv_compiler = "cce" - link_paths = { - "cc": os.path.join("cce", "cc"), - "cxx": os.path.join("cce", "case-insensitive", "CC"), - "f77": os.path.join("cce", "ftn"), - "fc": os.path.join("cce", "ftn"), - } + @property + def link_paths(self): + if self.PrgEnv in self.modules: + # Old module-based interface to cray compilers + return { + "cc": os.path.join("cce", "cc"), + "cxx": os.path.join("case-insensitive", "CC"), + "f77": os.path.join("cce", "ftn"), + "fc": os.path.join("cce", "ftn"), + } + + return { + "cc": os.path.join("cce", "craycc"), + "cxx": os.path.join("cce", "case-insensitive", "crayCC"), + "f77": os.path.join("cce", "crayftn"), + "fc": os.path.join("cce", "crayftn"), + } @property def is_clang_based(self): version = self._real_version or self.version return version >= ver("9.0") and "classic" not in str(version) - @property - def version_argument(self): - if self.is_clang_based: - return "--version" - return "-V" - + version_argument = "--version" version_regex = r"[Vv]ersion.*?(\d+(\.\d+)+)" @property diff --git a/lib/spack/spack/platforms/cray.py b/lib/spack/spack/platforms/cray.py index 8f87740e4c0..dadf114d90e 100644 --- a/lib/spack/spack/platforms/cray.py +++ b/lib/spack/spack/platforms/cray.py @@ -12,6 +12,7 @@ import llnl.util.tty as tty import spack.target +import spack.version from spack.operating_systems.cray_backend import CrayBackend from spack.operating_systems.cray_frontend import CrayFrontend from spack.paths import build_env_path @@ -31,6 +32,9 @@ "abudhabi": "piledriver", } +_ex_craype_dir = "/opt/cray/pe/cpe" +_xc_craype_dir = "/opt/cray/pe/cdt" + def _target_name_from_craype_target_name(name): return _craype_name_to_target_name.get(name, name) @@ -109,19 +113,48 @@ def setup_platform_environment(self, pkg, env): if os.environ.get("CRAY_LD_LIBRARY_PATH"): env.prepend_path("LD_LIBRARY_PATH", os.environ["CRAY_LD_LIBRARY_PATH"]) + @classmethod + def craype_type_and_version(cls): + if os.path.isdir(_ex_craype_dir): + craype_dir = _ex_craype_dir + craype_type = "EX" + elif os.path.isdir(_xc_craype_dir): + craype_dir = _xc_craype_dir + craype_type = "XC" + else: + return (None, None) + + # Take the default version from known symlink path + default_path = os.path.join(craype_dir, "default") + if os.path.islink(default_path): + version = spack.version.Version(os.readlink(default_path)) + return (craype_type, version) + + # If no default version, sort available versions and return latest + versions_available = [spack.version.Version(v) for v in os.listdir(craype_dir)] + versions_available.sort(reverse=True) + return (craype_type, versions_available[0]) + @classmethod def detect(cls): """ - Detect whether this system is a Cray machine. + Detect whether this system requires CrayPE module support. - We detect the Cray platform based on the availability through `module` - of the Cray programming environment. If this environment is available, - we can use it to find compilers, target modules, etc. If the Cray - programming environment is not available via modules, then we will - treat it as a standard linux system, as the Cray compiler wrappers - and other components of the Cray programming environment are - irrelevant without module support. + Systems with newer CrayPE (21.10 for EX systems, future work for CS and + XC systems) have compilers and MPI wrappers that can be used directly + by path. These systems are considered ``linux`` platforms. + + For systems running an older CrayPE, we detect the Cray platform based + on the availability through `module` of the Cray programming + environment. If this environment is available, we can use it to find + compilers, target modules, etc. If the Cray programming environment is + not available via modules, then we will treat it as a standard linux + system, as the Cray compiler wrappers and other components of the Cray + programming environment are irrelevant without module support. """ + craype_type, craype_version = cls.craype_type_and_version() + if craype_type == "EX" and craype_version >= spack.version.Version("21.10"): + return False return "opt/cray" in os.environ.get("MODULEPATH", "") def _default_target_from_env(self): diff --git a/lib/spack/spack/test/architecture.py b/lib/spack/spack/test/architecture.py index 746be0c8be4..92914be6852 100644 --- a/lib/spack/spack/test/architecture.py +++ b/lib/spack/spack/test/architecture.py @@ -8,6 +8,8 @@ import pytest +import llnl.util.filesystem as fs + import spack.concretize import spack.operating_systems import spack.platforms @@ -214,3 +216,27 @@ def test_concretize_target_ranges(root_target_range, dep_target_range, result, m spec.concretize() assert str(spec).count("arch=test-debian6-%s" % result) == 2 + + +@pytest.mark.parametrize( + "versions,default,expected", + [ + (["21.11", "21.9"], "21.11", False), + (["21.11", "21.9"], "21.9", True), + (["21.11", "21.9"], None, False), + ], +) +def test_cray_platform_detection(versions, default, expected, tmpdir, monkeypatch, working_env): + ex_path = str(tmpdir.join("fake_craype_dir")) + fs.mkdirp(ex_path) + + with fs.working_dir(ex_path): + for version in versions: + fs.touch(version) + if default: + os.symlink(default, "default") + + monkeypatch.setattr(spack.platforms.cray, "_ex_craype_dir", ex_path) + os.environ["MODULEPATH"] = "/opt/cray/pe" + + assert spack.platforms.cray.Cray.detect() == expected diff --git a/var/spack/repos/builtin/packages/aluminum/package.py b/var/spack/repos/builtin/packages/aluminum/package.py index 3d903dfaf26..cad16d0193a 100644 --- a/var/spack/repos/builtin/packages/aluminum/package.py +++ b/var/spack/repos/builtin/packages/aluminum/package.py @@ -54,13 +54,13 @@ class Aluminum(CMakePackage, CudaPackage, ROCmPackage): variant( "ofi_libfabric_plugin", default=True, - when="+rccl platform=cray", + when="+rccl", description="Builds with support for OFI libfabric enhanced RCCL/NCCL communication lib", ) variant( "ofi_libfabric_plugin", default=True, - when="+nccl platform=cray", + when="+nccl", description="Builds with support for OFI libfabric enhanced RCCL/NCCL communication lib", ) @@ -75,8 +75,8 @@ class Aluminum(CMakePackage, CudaPackage, ROCmPackage): depends_on("hipcub", when="@:0.1,0.6.0: +rocm") depends_on("rccl", when="+rccl") - depends_on("aws-ofi-rccl", when="+rccl +ofi_libfabric_plugin platform=cray") - depends_on("aws-ofi-nccl", when="+nccl +ofi_libfabric_plugin platform=cray") + depends_on("aws-ofi-rccl", when="+rccl +ofi_libfabric_plugin") + depends_on("aws-ofi-nccl", when="+nccl +ofi_libfabric_plugin") conflicts("~cuda", when="+cuda_rma", msg="CUDA RMA support requires CUDA") conflicts("+cuda", when="+rocm", msg="CUDA and ROCm support are mutually exclusive") diff --git a/var/spack/repos/builtin/packages/esmf/package.py b/var/spack/repos/builtin/packages/esmf/package.py index dcfde5415b6..c7c9b4bb03b 100644 --- a/var/spack/repos/builtin/packages/esmf/package.py +++ b/var/spack/repos/builtin/packages/esmf/package.py @@ -255,7 +255,7 @@ def edit(self, spec, prefix): # ESMF_COMM must be set to indicate which MPI implementation # is used to build the ESMF library. if "+mpi" in spec: - if "platform=cray" in self.spec: + if "^cray-mpich" in self.spec: os.environ["ESMF_COMM"] = "mpi" elif "^mvapich2" in spec: os.environ["ESMF_COMM"] = "mvapich2" diff --git a/var/spack/repos/builtin/packages/mpich/package.py b/var/spack/repos/builtin/packages/mpich/package.py index 8692cf06362..8604903f329 100644 --- a/var/spack/repos/builtin/packages/mpich/package.py +++ b/var/spack/repos/builtin/packages/mpich/package.py @@ -390,8 +390,7 @@ def setup_run_environment(self, env): # their run environments the code to make the compilers available. # For Cray MPIs, the regular compiler wrappers *are* the MPI wrappers. # Cray MPIs always have cray in the module name, e.g. "cray-mpich" - external_modules = self.spec.external_modules - if external_modules and "cray" in external_modules[0]: + if self.spec.satisfies("platform=cray"): # This is intended to support external MPICH instances registered # by Spack on Cray machines prior to a879c87; users defining an # external MPICH entry for Cray should generally refer to the @@ -420,8 +419,7 @@ def setup_dependent_package(self, module, dependent_spec): # For Cray MPIs, the regular compiler wrappers *are* the MPI wrappers. # Cray MPIs always have cray in the module name, e.g. "cray-mpich" - external_modules = spec.external_modules - if external_modules and "cray" in external_modules[0]: + if self.spec.satisfies("platform=cray"): spec.mpicc = spack_cc spec.mpicxx = spack_cxx spec.mpifc = spack_fc diff --git a/var/spack/repos/builtin/packages/mvapich2/package.py b/var/spack/repos/builtin/packages/mvapich2/package.py index d806260c999..9f1d094ca07 100644 --- a/var/spack/repos/builtin/packages/mvapich2/package.py +++ b/var/spack/repos/builtin/packages/mvapich2/package.py @@ -358,8 +358,7 @@ def setup_dependent_build_environment(self, env, dependent_spec): def setup_compiler_environment(self, env): # For Cray MPIs, the regular compiler wrappers *are* the MPI wrappers. # Cray MPIs always have cray in the module name, e.g. "cray-mvapich" - external_modules = self.spec.external_modules - if external_modules and "cray" in external_modules[0]: + if self.spec.satisfies("platform=cray"): env.set("MPICC", spack_cc) env.set("MPICXX", spack_cxx) env.set("MPIF77", spack_fc) @@ -373,8 +372,7 @@ def setup_compiler_environment(self, env): def setup_dependent_package(self, module, dependent_spec): # For Cray MPIs, the regular compiler wrappers *are* the MPI wrappers. # Cray MPIs always have cray in the module name, e.g. "cray-mvapich" - external_modules = self.spec.external_modules - if external_modules and "cray" in external_modules[0]: + if self.spec.satisfies("platform=cray"): self.spec.mpicc = spack_cc self.spec.mpicxx = spack_cxx self.spec.mpifc = spack_fc diff --git a/var/spack/repos/builtin/packages/opencoarrays/package.py b/var/spack/repos/builtin/packages/opencoarrays/package.py index 470d501f5d3..6c9a309c6f6 100644 --- a/var/spack/repos/builtin/packages/opencoarrays/package.py +++ b/var/spack/repos/builtin/packages/opencoarrays/package.py @@ -35,7 +35,7 @@ class Opencoarrays(CMakePackage): depends_on("mpi") # This patch removes a bunch of checks for the version of MPI available on # the system. They make the Crays hang. - patch("CMakeLists.patch", when="platform=cray") + patch("CMakeLists.patch", when="^cray-mpich") def cmake_args(self): args = [] diff --git a/var/spack/repos/builtin/packages/scorep/package.py b/var/spack/repos/builtin/packages/scorep/package.py index cf0baf5164c..5c7870def18 100644 --- a/var/spack/repos/builtin/packages/scorep/package.py +++ b/var/spack/repos/builtin/packages/scorep/package.py @@ -124,7 +124,11 @@ def configure_args(self): if spec.satisfies("^intel-mpi"): config_args.append("--with-mpi=intel3") - elif spec.satisfies("^mpich") or spec.satisfies("^mvapich2"): + elif ( + spec.satisfies("^mpich") + or spec.satisfies("^mvapich2") + or spec.satisfies("^cray-mpich") + ): config_args.append("--with-mpi=mpich3") elif spec.satisfies("^openmpi"): config_args.append("--with-mpi=openmpi") diff --git a/var/spack/repos/builtin/packages/xsdk/package.py b/var/spack/repos/builtin/packages/xsdk/package.py index d0396f9d268..627143b41c4 100644 --- a/var/spack/repos/builtin/packages/xsdk/package.py +++ b/var/spack/repos/builtin/packages/xsdk/package.py @@ -190,7 +190,7 @@ class Xsdk(BundlePackage, CudaPackage, ROCmPackage): xsdk_depends_on("datatransferkit@3.1-rc2", when="@0.6.0 +trilinos +datatransferkit") xsdk_depends_on("petsc +trilinos", when="+trilinos @:0.6.0") - xsdk_depends_on("petsc +batch", when="platform=cray @0.5.0:") + xsdk_depends_on("petsc +batch", when="@0.5.0: ^cray-mpich") xsdk_depends_on( "petsc@main+mpi+hypre+superlu-dist+metis+hdf5~mumps+double~int64", when="@develop", @@ -398,7 +398,7 @@ class Xsdk(BundlePackage, CudaPackage, ROCmPackage): xsdk_depends_on("py-libensemble@0.5.2+petsc4py", when="@0.5.0 +libensemble") xsdk_depends_on("py-petsc4py@3.12.0", when="@0.5.0 +libensemble") - xsdk_depends_on("precice ~petsc", when="platform=cray +precice") + xsdk_depends_on("precice ~petsc", when="+precice ^cray-mpich") xsdk_depends_on("precice@develop", when="@develop +precice") xsdk_depends_on("precice@2.3.0", when="@0.7.0 +precice") xsdk_depends_on("precice@2.1.1", when="@0.6.0 +precice") From 912d544afeb24876af87757ccf99c70306f104b4 Mon Sep 17 00:00:00 2001 From: Greg Becker Date: Fri, 4 Nov 2022 14:52:58 -0700 Subject: [PATCH 360/442] demote warning for no source id to debug message (#33657) * demote warning for no source id to debug message --- lib/spack/spack/package_base.py | 2 +- lib/spack/spack/test/conftest.py | 10 ++++++++++ lib/spack/spack/test/install.py | 6 ++++-- lib/spack/spack/test/test_suite.py | 12 ------------ 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/spack/spack/package_base.py b/lib/spack/spack/package_base.py index 1871e6785bf..e0e250cf7c8 100644 --- a/lib/spack/spack/package_base.py +++ b/lib/spack/spack/package_base.py @@ -1647,7 +1647,7 @@ def content_hash(self, content=None): from_local_sources = env and env.is_develop(self.spec) if self.has_code and not self.spec.external and not from_local_sources: message = "Missing a source id for {s.name}@{s.version}" - tty.warn(message.format(s=self)) + tty.debug(message.format(s=self)) hash_content.append("".encode("utf-8")) else: hash_content.append(source_id.encode("utf-8")) diff --git a/lib/spack/spack/test/conftest.py b/lib/spack/spack/test/conftest.py index 2f04e1d4fd8..2ab8c89c3b5 100644 --- a/lib/spack/spack/test/conftest.py +++ b/lib/spack/spack/test/conftest.py @@ -591,6 +591,16 @@ def linux_os(): return LinuxOS(name=name, version=version) +@pytest.fixture +def ensure_debug(monkeypatch): + current_debug_level = tty.debug_level() + tty.set_debug(1) + + yield + + tty.set_debug(current_debug_level) + + @pytest.fixture(autouse=is_windows, scope="session") def platform_config(): spack.config.add_default_platform_scope(spack.platforms.real_host().name) diff --git a/lib/spack/spack/test/install.py b/lib/spack/spack/test/install.py index e8b6f415d34..da54216402b 100644 --- a/lib/spack/spack/test/install.py +++ b/lib/spack/spack/test/install.py @@ -429,7 +429,7 @@ def test_uninstall_by_spec_errors(mutable_database): @pytest.mark.disable_clean_stage_check -def test_nosource_pkg_install(install_mockery, mock_fetch, mock_packages, capfd): +def test_nosource_pkg_install(install_mockery, mock_fetch, mock_packages, capfd, ensure_debug): """Test install phases with the nosource package.""" spec = Spec("nosource").concretized() pkg = spec.package @@ -444,7 +444,9 @@ def test_nosource_pkg_install(install_mockery, mock_fetch, mock_packages, capfd) @pytest.mark.disable_clean_stage_check -def test_nosource_bundle_pkg_install(install_mockery, mock_fetch, mock_packages, capfd): +def test_nosource_bundle_pkg_install( + install_mockery, mock_fetch, mock_packages, capfd, ensure_debug +): """Test install phases with the nosource-bundle package.""" spec = Spec("nosource-bundle").concretized() pkg = spec.package diff --git a/lib/spack/spack/test/test_suite.py b/lib/spack/spack/test/test_suite.py index 3d8ebace395..7db59526ca3 100644 --- a/lib/spack/spack/test/test_suite.py +++ b/lib/spack/spack/test/test_suite.py @@ -7,8 +7,6 @@ import pytest -import llnl.util.tty as tty - import spack.install_test import spack.spec @@ -20,16 +18,6 @@ def _true(*args, **kwargs): return True -@pytest.fixture -def ensure_debug(monkeypatch): - current_debug_level = tty.debug_level() - tty.set_debug(1) - - yield - - tty.set_debug(current_debug_level) - - def ensure_results(filename, expected): assert os.path.exists(filename) with open(filename, "r") as fd: From 7c0b3f6374917d5cc40ff94b1ce9901451692f8f Mon Sep 17 00:00:00 2001 From: "Adam J. Stewart" Date: Fri, 4 Nov 2022 16:00:23 -0700 Subject: [PATCH 361/442] py-pytorch-lightning: add conflicts for py-torch~distributed (#33710) --- .../repos/builtin/packages/py-pytorch-lightning/package.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/var/spack/repos/builtin/packages/py-pytorch-lightning/package.py b/var/spack/repos/builtin/packages/py-pytorch-lightning/package.py index fe63af712b9..5702b205095 100644 --- a/var/spack/repos/builtin/packages/py-pytorch-lightning/package.py +++ b/var/spack/repos/builtin/packages/py-pytorch-lightning/package.py @@ -79,3 +79,8 @@ class PyPytorchLightning(PythonPackage): depends_on("py-pydeprecate@0.3.1:0.3", when="@1.6:1.6.3", type=("build", "run")) depends_on("py-pydeprecate@0.3.1", when="@1.4:1.5", type=("build", "run")) depends_on("py-pydeprecate@0.3.0", when="@1.3", type=("build", "run")) + + # https://github.com/Lightning-AI/lightning/issues/15494 + conflicts("^py-torch~distributed", when="@1.8.0") + # https://github.com/Lightning-AI/lightning/issues/10348 + conflicts("^py-torch~distributed", when="@1.5.0:1.5.2") From d7cb790f8836f5beaa7196173c6f8987cc964c71 Mon Sep 17 00:00:00 2001 From: Erik Schnetter Date: Fri, 4 Nov 2022 20:18:05 -0400 Subject: [PATCH 362/442] openssl: New version 1.1.1s (#33664) This is a security update. --- .../repos/builtin/packages/openssl/package.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/var/spack/repos/builtin/packages/openssl/package.py b/var/spack/repos/builtin/packages/openssl/package.py index 2d420e75747..da444e30cd8 100644 --- a/var/spack/repos/builtin/packages/openssl/package.py +++ b/var/spack/repos/builtin/packages/openssl/package.py @@ -28,7 +28,12 @@ class Openssl(Package): # Uses Fake Autotools, should subclass Package executables = ["openssl"] - version("3.0.5", sha256="aa7d8d9bef71ad6525c55ba11e5f4397889ce49c2c9349dcea6d3e4f0b024a7a") + version("3.0.7", sha256="83049d042a260e696f62406ac5c08bf706fd84383f945cf21bd61e9ed95c396e") + version( + "3.0.5", + sha256="aa7d8d9bef71ad6525c55ba11e5f4397889ce49c2c9349dcea6d3e4f0b024a7a", + deprecated=True, + ) version( "3.0.4", sha256="2831843e9a668a0ab478e7020ad63d2d65e51f72977472dc73efcefbafc0c00f", @@ -52,10 +57,15 @@ class Openssl(Package): # Uses Fake Autotools, should subclass Package # The latest stable version is the 1.1.1 series. This is also our Long Term # Support (LTS) version, supported until 11th September 2023. + version( + "1.1.1s", + sha256="c5ac01e760ee6ff0dab61d6b2bbd30146724d063eb322180c6f18a6f74e4b6aa", + preferred=True, + ) version( "1.1.1q", sha256="d7939ce614029cdff0b6c20f0e2e5703158a489a72b2507b8bd51bf8c8fd10ca", - preferred=True, + deprecated=True, ) version( "1.1.1p", From 9becc82dfcfd7b61a1bf17a92c3a9f101b01ea3b Mon Sep 17 00:00:00 2001 From: iarspider Date: Sat, 5 Nov 2022 03:00:16 +0100 Subject: [PATCH 363/442] Fix formatting in packaging guide (#33714) --- lib/spack/docs/packaging_guide.rst | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/lib/spack/docs/packaging_guide.rst b/lib/spack/docs/packaging_guide.rst index b6184974973..2ceb4ce0517 100644 --- a/lib/spack/docs/packaging_guide.rst +++ b/lib/spack/docs/packaging_guide.rst @@ -4406,16 +4406,9 @@ In addition to invoking the right compiler, the compiler wrappers add flags to the compile line so that dependencies can be easily found. These flags are added for each dependency, if they exist: -Compile-time library search paths -* ``-L$dep_prefix/lib`` -* ``-L$dep_prefix/lib64`` - -Runtime library search paths (RPATHs) -* ``$rpath_flag$dep_prefix/lib`` -* ``$rpath_flag$dep_prefix/lib64`` - -Include search paths -* ``-I$dep_prefix/include`` +* Compile-time library search paths: ``-L$dep_prefix/lib``, ``-L$dep_prefix/lib64`` +* Runtime library search paths (RPATHs): ``$rpath_flag$dep_prefix/lib``, ``$rpath_flag$dep_prefix/lib64`` +* Include search paths: ``-I$dep_prefix/include`` An example of this would be the ``libdwarf`` build, which has one dependency: ``libelf``. Every call to ``cc`` in the ``libdwarf`` From 34724cae87623a36de0c34e6e6bba55e969c4a96 Mon Sep 17 00:00:00 2001 From: wspear Date: Fri, 4 Nov 2022 20:07:33 -0700 Subject: [PATCH 364/442] Updated tau 2.32 hash (#33718) --- var/spack/repos/builtin/packages/tau/package.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/tau/package.py b/var/spack/repos/builtin/packages/tau/package.py index 6a87471d088..78e9229084a 100644 --- a/var/spack/repos/builtin/packages/tau/package.py +++ b/var/spack/repos/builtin/packages/tau/package.py @@ -26,7 +26,7 @@ class Tau(Package): tags = ["e4s"] version("master", branch="master") - version("2.32", sha256="a404f51ae48fbfb9a2fb03643e555b4d978af4c83f365bacfead91e0095ee1ea") + version("2.32", sha256="fc8f5cdbdae999e98e9e97b0d8d66d282cb8bb41c19d5486d48a2d2d11b4b475") version("2.31.1", sha256="bf445b9d4fe40a5672a7b175044d2133791c4dfb36a214c1a55a931aebc06b9d") version("2.31", sha256="27e73c395dd2a42b91591ce4a76b88b1f67663ef13aa19ef4297c68f45d946c2") version("2.30.2", sha256="43f84a15b71a226f8a64d966f0cb46022bcfbaefb341295ecc6fa80bb82bbfb4") From d79cba1a770d30a21f851dd6dbcfe96079a4ab3e Mon Sep 17 00:00:00 2001 From: "Adam J. Stewart" Date: Fri, 4 Nov 2022 21:38:04 -0700 Subject: [PATCH 365/442] py-matplotlib: add v3.6.2 (#33683) --- var/spack/repos/builtin/packages/py-matplotlib/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/py-matplotlib/package.py b/var/spack/repos/builtin/packages/py-matplotlib/package.py index cdebe1e2af8..04548fd89cd 100644 --- a/var/spack/repos/builtin/packages/py-matplotlib/package.py +++ b/var/spack/repos/builtin/packages/py-matplotlib/package.py @@ -37,6 +37,7 @@ class PyMatplotlib(PythonPackage): "pylab", ] + version("3.6.2", sha256="b03fd10a1709d0101c054883b550f7c4c5e974f751e2680318759af005964990") version("3.6.1", sha256="e2d1b7225666f7e1bcc94c0bc9c587a82e3e8691da4757e357e5c2515222ee37") version("3.6.0", sha256="c5108ebe67da60a9204497d8d403316228deb52b550388190c53a57394d41531") version("3.5.3", sha256="339cac48b80ddbc8bfd05daae0a3a73414651a8596904c2a881cfd1edb65f26c") From c0ed5612ab406bfe0f638cc3e5a14cc99e91921a Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Sat, 5 Nov 2022 09:00:54 +0100 Subject: [PATCH 366/442] unparser: fix bug in unit test assertion (#33722) --- lib/spack/spack/test/util/unparse/unparse.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/spack/spack/test/util/unparse/unparse.py b/lib/spack/spack/test/util/unparse/unparse.py index 217f67f35d3..49009ae98e6 100644 --- a/lib/spack/spack/test/util/unparse/unparse.py +++ b/lib/spack/spack/test/util/unparse/unparse.py @@ -178,16 +178,14 @@ async def f(): """ -def assertASTEqual(ast1, ast2): - ast.dump(ast1) == ast.dump(ast2) - - def check_ast_roundtrip(code1, filename="internal", mode="exec"): ast1 = compile(str(code1), filename, mode, ast.PyCF_ONLY_AST) code2 = spack.util.unparse.unparse(ast1) ast2 = compile(code2, filename, mode, ast.PyCF_ONLY_AST) - assertASTEqual(ast1, ast2) + + error_msg = "Failed to roundtrip {} [mode={}]".format(filename, mode) + assert ast.dump(ast1) == ast.dump(ast2), error_msg def test_core_lib_files(): From 71d480515b098118c5f1d84f255c4080f55c62e8 Mon Sep 17 00:00:00 2001 From: Peter Scheibel Date: Sat, 5 Nov 2022 01:44:50 -0700 Subject: [PATCH 367/442] packages.yaml: set url/git (#33275) A user may want to set some attributes on a package without actually modifying the package (e.g. if they want to git pull updates to the package without conflicts). This PR adds a per-package configuration section called "set", which is a dictionary of attribute names to desired values. For example: packages: openblas: package_attributes: submodules: true git: "https://github.com/myfork/openblas" in this case, the package will always retrieve git submodules, and will use an alternate location for the git repo. While git, url, and submodules are the attributes for which we envision the most usage, this allows any attribute to be overridden, and the acceptable values are any value parseable from yaml. --- lib/spack/docs/build_settings.rst | 22 +++++++++ lib/spack/spack/repo.py | 35 ++++++++++++++ lib/spack/spack/schema/packages.py | 9 ++++ .../spack/test/concretize_preferences.py | 47 +++++++++++++++++++ 4 files changed, 113 insertions(+) diff --git a/lib/spack/docs/build_settings.rst b/lib/spack/docs/build_settings.rst index de580a32890..3ab38dd4daf 100644 --- a/lib/spack/docs/build_settings.rst +++ b/lib/spack/docs/build_settings.rst @@ -531,3 +531,25 @@ directories inside the install prefix. This will ensure that even manually placed files within the install prefix are owned by the assigned group. If no group is assigned, Spack will allow the OS default behavior to go as expected. + +---------------------------- +Assigning Package Attributes +---------------------------- + +You can assign class-level attributes in the configuration: + +.. code-block:: yaml + + packages: + mpileaks: + # Override existing attributes + url: http://www.somewhereelse.com/mpileaks-1.0.tar.gz + # ... or add new ones + x: 1 + +Attributes set this way will be accessible to any method executed +in the package.py file (e.g. the ``install()`` method). Values for these +attributes may be any value parseable by yaml. + +These can only be applied to specific packages, not "all" or +virtual packages. diff --git a/lib/spack/spack/repo.py b/lib/spack/spack/repo.py index 123f34320e2..11370f7b56a 100644 --- a/lib/spack/spack/repo.py +++ b/lib/spack/spack/repo.py @@ -1362,6 +1362,41 @@ def get_pkg_class(self, pkg_name): if not inspect.isclass(cls): tty.die("%s.%s is not a class" % (pkg_name, class_name)) + new_cfg_settings = ( + spack.config.get("packages").get(pkg_name, {}).get("package_attributes", {}) + ) + + overridden_attrs = getattr(cls, "overridden_attrs", {}) + attrs_exclusively_from_config = getattr(cls, "attrs_exclusively_from_config", []) + # Clear any prior changes to class attributes in case the config has + # since changed + for key, val in overridden_attrs.items(): + setattr(cls, key, val) + for key in attrs_exclusively_from_config: + delattr(cls, key) + + # Keep track of every class attribute that is overridden by the config: + # if the config changes between calls to this method, we make sure to + # restore the original config values (in case the new config no longer + # sets attributes that it used to) + new_overridden_attrs = {} + new_attrs_exclusively_from_config = set() + for key, val in new_cfg_settings.items(): + if hasattr(cls, key): + new_overridden_attrs[key] = getattr(cls, key) + else: + new_attrs_exclusively_from_config.add(key) + + setattr(cls, key, val) + if new_overridden_attrs: + setattr(cls, "overridden_attrs", dict(new_overridden_attrs)) + elif hasattr(cls, "overridden_attrs"): + delattr(cls, "overridden_attrs") + if new_attrs_exclusively_from_config: + setattr(cls, "attrs_exclusively_from_config", new_attrs_exclusively_from_config) + elif hasattr(cls, "attrs_exclusively_from_config"): + delattr(cls, "attrs_exclusively_from_config") + return cls def __str__(self): diff --git a/lib/spack/spack/schema/packages.py b/lib/spack/spack/schema/packages.py index 92fe9e0ba8b..eed8db3e73c 100644 --- a/lib/spack/spack/schema/packages.py +++ b/lib/spack/spack/schema/packages.py @@ -82,6 +82,15 @@ }, }, }, + # If 'get_full_repo' is promoted to a Package-level + # attribute, it could be useful to set it here + "package_attributes": { + "type": "object", + "additionalProperties": False, + "patternProperties": { + r"\w+": {}, + }, + }, "providers": { "type": "object", "default": {}, diff --git a/lib/spack/spack/test/concretize_preferences.py b/lib/spack/spack/test/concretize_preferences.py index 7bae90cb2cc..eb5b0734441 100644 --- a/lib/spack/spack/test/concretize_preferences.py +++ b/lib/spack/spack/test/concretize_preferences.py @@ -179,6 +179,53 @@ def test_preferred_providers(self): spec = concretize("mpileaks") assert "zmpi" in spec + def test_config_set_pkg_property_url(self, mutable_mock_repo): + """Test setting an existing attribute in the package class""" + update_packages( + "mpileaks", + "package_attributes", + {"url": "http://www.somewhereelse.com/mpileaks-1.0.tar.gz"}, + ) + spec = concretize("mpileaks") + assert spec.package.fetcher[0].url == "http://www.somewhereelse.com/mpileaks-2.3.tar.gz" + + update_packages("mpileaks", "package_attributes", {}) + spec = concretize("mpileaks") + assert spec.package.fetcher[0].url == "http://www.llnl.gov/mpileaks-2.3.tar.gz" + + def test_config_set_pkg_property_new(self, mutable_mock_repo): + """Test that you can set arbitrary attributes on the Package class""" + conf = syaml.load_config( + """\ +mpileaks: + package_attributes: + v1: 1 + v2: true + v3: yesterday + v4: "true" + v5: + x: 1 + y: 2 + v6: + - 1 + - 2 +""" + ) + spack.config.set("packages", conf, scope="concretize") + + spec = concretize("mpileaks") + assert spec.package.v1 == 1 + assert spec.package.v2 is True + assert spec.package.v3 == "yesterday" + assert spec.package.v4 == "true" + assert dict(spec.package.v5) == {"x": 1, "y": 2} + assert list(spec.package.v6) == [1, 2] + + update_packages("mpileaks", "package_attributes", {}) + spec = concretize("mpileaks") + with pytest.raises(AttributeError): + spec.package.v1 + def test_preferred(self): """ "Test packages with some version marked as preferred=True""" spec = Spec("python") From 3346c0918bb939f3e82033ddde0a2378c602650d Mon Sep 17 00:00:00 2001 From: Tom Scogland Date: Sat, 5 Nov 2022 00:09:35 -1000 Subject: [PATCH 368/442] Fix relocation to avoid overwriting merged constant strings (#32253) Compilers and linker optimize string constants for space by aliasing them when one is a suffix of another. For gcc / binutils this happens already at -O1, due to -fmerge-constants. This means that we have to take care during relocation to always preserve a certain length of the suffix of those prefixes that are C-strings. In this commit we pick length 7 as a safe suffix length, assuming the suffix is typically the 7 characters from the hash (i.e. random), so it's unlikely to alias with any string constant used in the sources. In general we now pad shortened strings from the left with leading dir seperators, but in the case of C-strings that are much shorter and don't share a common suffix (due to projections), we do allow shrinking the C-string, appending a null, and retaining the old part of the prefix. Also when rewiring, we ensure that the new hash preserves the last 7 bytes of the old hash. Co-authored-by: Harmen Stoppels --- lib/spack/spack/binary_distribution.py | 12 +- lib/spack/spack/relocate.py | 164 +++++++++++---- lib/spack/spack/spec.py | 7 +- lib/spack/spack/test/conftest.py | 16 +- lib/spack/spack/test/relocate.py | 195 +++++++++++++++--- lib/spack/spack/test/rewiring.py | 2 +- .../builtin.mock/packages/garply/package.py | 7 +- .../builtin.mock/packages/quux/package.py | 7 +- 8 files changed, 324 insertions(+), 86 deletions(-) diff --git a/lib/spack/spack/binary_distribution.py b/lib/spack/spack/binary_distribution.py index 5ea7138a167..3967afdfd85 100644 --- a/lib/spack/spack/binary_distribution.py +++ b/lib/spack/spack/binary_distribution.py @@ -1600,13 +1600,19 @@ def relocate_package(spec, allow_root): install_path = spack.hooks.sbang.sbang_install_path() prefix_to_prefix_text[old_sbang_install_path] = install_path + # First match specific prefix paths. Possibly the *local* install prefix + # of some dependency is in an upstream, so we cannot assume the original + # spack store root can be mapped uniformly to the new spack store root. + for orig_prefix, hash in prefix_to_hash.items(): + prefix_to_prefix_text[orig_prefix] = hash_to_prefix.get(hash, None) + prefix_to_prefix_bin[orig_prefix] = hash_to_prefix.get(hash, None) + + # Only then add the generic fallback of install prefix -> install prefix. prefix_to_prefix_text[old_prefix] = new_prefix prefix_to_prefix_bin[old_prefix] = new_prefix prefix_to_prefix_text[old_layout_root] = new_layout_root prefix_to_prefix_bin[old_layout_root] = new_layout_root - for orig_prefix, hash in prefix_to_hash.items(): - prefix_to_prefix_text[orig_prefix] = hash_to_prefix.get(hash, None) - prefix_to_prefix_bin[orig_prefix] = hash_to_prefix.get(hash, None) + # This is vestigial code for the *old* location of sbang. Previously, # sbang was a bash script, and it lived in the spack prefix. It is # now a POSIX script that lives in the install prefix. Old packages diff --git a/lib/spack/spack/relocate.py b/lib/spack/spack/relocate.py index b8c47b58645..7ac19574ce2 100644 --- a/lib/spack/spack/relocate.py +++ b/lib/spack/spack/relocate.py @@ -61,23 +61,30 @@ def __init__(self, file_path, old_len, new_len): class BinaryTextReplaceError(spack.error.SpackError): - def __init__(self, old_path, new_path): - """Raised when the new install path is longer than the - old one, so binary text replacement cannot occur. + def __init__(self, msg): + msg += ( + " To fix this, compile with more padding " + "(config:install_tree:padded_length), or install to a shorter prefix." + ) + super(BinaryTextReplaceError, self).__init__(msg) - Args: - old_path (str): original path to be substituted - new_path (str): candidate path for substitution - """ - msg = "New path longer than old path: binary text" - msg += " replacement not possible." - err_msg = "The new path %s" % new_path - err_msg += " is longer than the old path %s.\n" % old_path - err_msg += "Text replacement in binaries will not work.\n" - err_msg += "Create buildcache from an install path " - err_msg += "longer than new path." - super(BinaryTextReplaceError, self).__init__(msg, err_msg) +class CannotGrowString(BinaryTextReplaceError): + def __init__(self, old, new): + msg = "Cannot replace {!r} with {!r} because the new prefix is longer.".format(old, new) + super(CannotGrowString, self).__init__(msg) + + +class CannotShrinkCString(BinaryTextReplaceError): + def __init__(self, old, new, full_old_string): + # Just interpolate binary string to not risk issues with invalid + # unicode, which would be really bad user experience: error in error. + # We have no clue if we actually deal with a real C-string nor what + # encoding it has. + msg = "Cannot replace {!r} with {!r} in the C-string {!r}.".format( + old, new, full_old_string + ) + super(CannotShrinkCString, self).__init__(msg) @memoized @@ -451,43 +458,116 @@ def _replace_prefix_text(filename, compiled_prefixes): f.truncate() -def _replace_prefix_bin(filename, byte_prefixes): - """Replace all the occurrences of the old install prefix with a - new install prefix in binary files. +def apply_binary_replacements(f, prefix_to_prefix, suffix_safety_size=7): + """ + Given a file opened in rb+ mode, apply the string replacements as + specified by an ordered dictionary of prefix to prefix mappings. This + method takes special care of null-terminated C-strings. C-string constants + are problematic because compilers and linkers optimize readonly strings for + space by aliasing those that share a common suffix (only suffix since all + of them are null terminated). See https://github.com/spack/spack/pull/31739 + and https://github.com/spack/spack/pull/32253 for details. Our logic matches + the original prefix with a ``suffix_safety_size + 1`` lookahead for null bytes. + If no null terminator is found, we simply pad with leading /, assuming that + it's a long C-string; the full C-string after replacement has a large suffix + in common with its original value. + If there *is* a null terminator we can do the same as long as the replacement + has a sufficiently long common suffix with the original prefix. + As a last resort when the replacement does not have a long enough common suffix, + we can try to shorten the string, but this only works if the new length is + sufficiently short (typically the case when going from large padding -> normal path) + If the replacement string is longer, or all of the above fails, we error out. - The new install prefix is prefixed with ``b'/'`` until the - lengths of the prefixes are the same. + Arguments: + f: file opened in rb+ mode + prefix_to_prefix (OrderedDict): OrderedDictionary where the keys are + bytes representing the old prefixes and the values are the new + suffix_safety_size (int): in case of null terminated strings, what size + of the suffix should remain to avoid aliasing issues? + """ + assert suffix_safety_size >= 0 + assert f.tell() == 0 + + # Look for exact matches of our paths, and also look if there's a null terminator + # soon after (this covers the case where we search for /abc but match /abc/ with + # a trailing dir seperator). + regex = re.compile( + b"(" + + b"|".join(re.escape(p) for p in prefix_to_prefix.keys()) + + b")([^\0]{0,%d}\0)?" % suffix_safety_size + ) + + # We *could* read binary data in chunks to avoid loading all in memory, + # but it's nasty to deal with matches across boundaries, so let's stick to + # something simple. + + for match in regex.finditer(f.read()): + # The matching prefix (old) and its replacement (new) + old = match.group(1) + new = prefix_to_prefix[old] + + # Did we find a trailing null within a N + 1 bytes window after the prefix? + null_terminated = match.end(0) > match.end(1) + + # Suffix string length, excluding the null byte + # Only makes sense if null_terminated + suffix_strlen = match.end(0) - match.end(1) - 1 + + # How many bytes are we shrinking our string? + bytes_shorter = len(old) - len(new) + + # We can't make strings larger. + if bytes_shorter < 0: + raise CannotGrowString(old, new) + + # If we don't know whether this is a null terminated C-string (we're looking + # only N + 1 bytes ahead), or if it is and we have a common suffix, we can + # simply pad with leading dir separators. + elif ( + not null_terminated + or suffix_strlen >= suffix_safety_size # == is enough, but let's be defensive + or old[-suffix_safety_size + suffix_strlen :] + == new[-suffix_safety_size + suffix_strlen :] + ): + replacement = b"/" * bytes_shorter + new + + # If it *was* null terminated, all that matters is that we can leave N bytes + # of old suffix in place. Note that > is required since we also insert an + # additional null terminator. + elif bytes_shorter > suffix_safety_size: + replacement = new + match.group(2) # includes the trailing null + + # Otherwise... we can't :( + else: + raise CannotShrinkCString(old, new, match.group()[:-1]) + + f.seek(match.start()) + f.write(replacement) + + +def _replace_prefix_bin(filename, prefix_to_prefix): + """Replace all the occurrences of the old prefix with a new prefix in binary + files. See :func:`~spack.relocate.apply_binary_replacements` for details. Args: filename (str): target binary file - byte_prefixes (OrderedDict): OrderedDictionary where the keys are - binary strings of the old prefixes and the values are the new - binary prefixes + byte_prefixes (OrderedDict): ordered dictionary where the keys are + bytes representing the old prefixes and the values are the new + prefixes (all bytes utf-8 encoded) """ - all_prefixes = re.compile(b"|".join(re.escape(prefix) for prefix in byte_prefixes.keys())) - - def padded_replacement(old): - new = byte_prefixes[old] - pad = len(old) - len(new) - if pad < 0: - raise BinaryTextReplaceError(old, new) - return new + b"/" * pad with open(filename, "rb+") as f: - # Register what replacement string to put on what offsets in the file. - replacements_at_offset = [ - (padded_replacement(m.group(0)), m.start()) - for m in re.finditer(all_prefixes, f.read()) - ] - - # Apply the replacements - for replacement, offset in replacements_at_offset: - f.seek(offset) - f.write(replacement) + apply_binary_replacements(f, prefix_to_prefix) def relocate_macho_binaries( - path_names, old_layout_root, new_layout_root, prefix_to_prefix, rel, old_prefix, new_prefix + path_names, + old_layout_root, + new_layout_root, + prefix_to_prefix, + rel, + old_prefix, + new_prefix, ): """ Use macholib python package to get the rpaths, depedent libraries diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py index a419fdf057b..3b8ed07a83a 100644 --- a/lib/spack/spack/spec.py +++ b/lib/spack/spack/spec.py @@ -1741,7 +1741,12 @@ def spec_hash(self, hash): return hash.override(self) node_dict = self.to_node_dict(hash=hash) json_text = sjson.dump(node_dict) - return spack.util.hash.b32_hash(json_text) + # This implements "frankenhashes", preserving the last 7 characters of the + # original hash when splicing so that we can avoid relocation issues + out = spack.util.hash.b32_hash(json_text) + if self.build_spec is not self: + return out[:-7] + self.build_spec.spec_hash(hash)[-7:] + return out def _cached_hash(self, hash, length=None, force=False): """Helper function for storing a cached hash on the spec. diff --git a/lib/spack/spack/test/conftest.py b/lib/spack/spack/test/conftest.py index 2ab8c89c3b5..6516c9c01f0 100644 --- a/lib/spack/spack/test/conftest.py +++ b/lib/spack/spack/test/conftest.py @@ -1643,7 +1643,7 @@ def mock_executable(tmpdir): """ import jinja2 - shebang = "#!/bin/bash\n" if not is_windows else "@ECHO OFF" + shebang = "#!/bin/sh\n" if not is_windows else "@ECHO OFF" def _factory(name, output, subdir=("bin",)): f = tmpdir.ensure(*subdir, dir=True).join(name) @@ -1808,14 +1808,24 @@ def mock_tty_stdout(monkeypatch): monkeypatch.setattr(sys.stdout, "isatty", lambda: True) +@pytest.fixture +def prefix_like(): + return "package-0.0.0.a1-hashhashhashhashhashhashhashhash" + + @pytest.fixture() -def binary_with_rpaths(tmpdir): +def prefix_tmpdir(tmpdir, prefix_like): + return tmpdir.mkdir(prefix_like) + + +@pytest.fixture() +def binary_with_rpaths(prefix_tmpdir): """Factory fixture that compiles an ELF binary setting its RPATH. Relative paths are encoded with `$ORIGIN` prepended. """ def _factory(rpaths, message="Hello world!"): - source = tmpdir.join("main.c") + source = prefix_tmpdir.join("main.c") source.write( """ #include diff --git a/lib/spack/spack/test/relocate.py b/lib/spack/spack/test/relocate.py index da6d800e0a3..b07f8402df0 100644 --- a/lib/spack/spack/test/relocate.py +++ b/lib/spack/spack/test/relocate.py @@ -2,6 +2,7 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import io import os import os.path import re @@ -141,13 +142,13 @@ def _factory(): @pytest.fixture() -def copy_binary(): +def copy_binary(prefix_like): """Returns a function that copies a binary somewhere and returns the new location. """ def _copy_somewhere(orig_binary): - new_root = orig_binary.mkdtemp() + new_root = orig_binary.mkdtemp().mkdir(prefix_like) new_binary = new_root.join("main.x") shutil.copy(str(orig_binary), str(new_binary)) return new_binary @@ -261,29 +262,33 @@ def test_set_elf_rpaths_warning(mock_patchelf): @pytest.mark.requires_executables("patchelf", "strings", "file", "gcc") @skip_unless_linux -def test_replace_prefix_bin(binary_with_rpaths): +def test_replace_prefix_bin(binary_with_rpaths, prefix_like): + prefix = "/usr/" + prefix_like + prefix_bytes = prefix.encode("utf-8") + new_prefix = "/foo/" + prefix_like + new_prefix_bytes = new_prefix.encode("utf-8") # Compile an "Hello world!" executable and set RPATHs - executable = binary_with_rpaths(rpaths=["/usr/lib", "/usr/lib64"]) + executable = binary_with_rpaths(rpaths=[prefix + "/lib", prefix + "/lib64"]) # Relocate the RPATHs - spack.relocate._replace_prefix_bin(str(executable), {b"/usr": b"/foo"}) + spack.relocate._replace_prefix_bin(str(executable), {prefix_bytes: new_prefix_bytes}) # Some compilers add rpaths so ensure changes included in final result - assert "/foo/lib:/foo/lib64" in rpaths_for(executable) + assert "%s/lib:%s/lib64" % (new_prefix, new_prefix) in rpaths_for(executable) @pytest.mark.requires_executables("patchelf", "strings", "file", "gcc") @skip_unless_linux -def test_relocate_elf_binaries_absolute_paths(binary_with_rpaths, copy_binary, tmpdir): +def test_relocate_elf_binaries_absolute_paths(binary_with_rpaths, copy_binary, prefix_tmpdir): # Create an executable, set some RPATHs, copy it to another location - orig_binary = binary_with_rpaths(rpaths=[str(tmpdir.mkdir("lib")), "/usr/lib64"]) + orig_binary = binary_with_rpaths(rpaths=[str(prefix_tmpdir.mkdir("lib")), "/usr/lib64"]) new_binary = copy_binary(orig_binary) spack.relocate.relocate_elf_binaries( binaries=[str(new_binary)], orig_root=str(orig_binary.dirpath()), new_root=None, # Not needed when relocating absolute paths - new_prefixes={str(tmpdir): "/foo"}, + new_prefixes={str(orig_binary.dirpath()): "/foo"}, rel=False, # Not needed when relocating absolute paths orig_prefix=None, @@ -317,9 +322,13 @@ def test_relocate_elf_binaries_relative_paths(binary_with_rpaths, copy_binary): @pytest.mark.requires_executables("patchelf", "strings", "file", "gcc") @skip_unless_linux -def test_make_elf_binaries_relative(binary_with_rpaths, copy_binary, tmpdir): +def test_make_elf_binaries_relative(binary_with_rpaths, copy_binary, prefix_tmpdir): orig_binary = binary_with_rpaths( - rpaths=[str(tmpdir.mkdir("lib")), str(tmpdir.mkdir("lib64")), "/opt/local/lib"] + rpaths=[ + str(prefix_tmpdir.mkdir("lib")), + str(prefix_tmpdir.mkdir("lib64")), + "/opt/local/lib", + ] ) new_binary = copy_binary(orig_binary) @@ -339,15 +348,19 @@ def test_raise_if_not_relocatable(monkeypatch): @pytest.mark.requires_executables("patchelf", "strings", "file", "gcc") @skip_unless_linux -def test_relocate_text_bin(binary_with_rpaths, copy_binary, tmpdir): +def test_relocate_text_bin(binary_with_rpaths, copy_binary, prefix_tmpdir): orig_binary = binary_with_rpaths( - rpaths=[str(tmpdir.mkdir("lib")), str(tmpdir.mkdir("lib64")), "/opt/local/lib"], - message=str(tmpdir), + rpaths=[ + str(prefix_tmpdir.mkdir("lib")), + str(prefix_tmpdir.mkdir("lib64")), + "/opt/local/lib", + ], + message=str(prefix_tmpdir), ) new_binary = copy_binary(orig_binary) - # Check original directory is in the executabel and the new one is not - assert text_in_bin(str(tmpdir), new_binary) + # Check original directory is in the executable and the new one is not + assert text_in_bin(str(prefix_tmpdir), new_binary) assert not text_in_bin(str(new_binary.dirpath()), new_binary) # Check this call succeed @@ -358,7 +371,7 @@ def test_relocate_text_bin(binary_with_rpaths, copy_binary, tmpdir): # Check original directory is not there anymore and it was # substituted with the new one - assert not text_in_bin(str(tmpdir), new_binary) + assert not text_in_bin(str(prefix_tmpdir), new_binary) assert text_in_bin(str(new_binary.dirpath()), new_binary) @@ -450,30 +463,144 @@ def test_utf8_paths_to_single_binary_regex(): assert regex.search(string).group(0) == b"/safe/[a-z]/file" -def test_ordered_replacement(tmpdir): +def test_ordered_replacement(): # This tests whether binary text replacement respects order, so that # a long package prefix is replaced before a shorter sub-prefix like # the root of the spack store (as a fallback). - def replace_and_expect(prefix_map, before, after): - file = str(tmpdir.join("file")) - with open(file, "wb") as f: - f.write(before) - spack.relocate._replace_prefix_bin(file, prefix_map) - with open(file, "rb") as f: - assert f.read() == after + def replace_and_expect(prefix_map, before, after=None, suffix_safety_size=7): + f = io.BytesIO(before) + spack.relocate.apply_binary_replacements(f, OrderedDict(prefix_map), suffix_safety_size) + f.seek(0) + assert f.read() == after + # The case of having a non-null terminated common suffix. replace_and_expect( - OrderedDict( - [(b"/old-spack/opt/specific-package", b"/first"), (b"/old-spack/opt", b"/second")] - ), + [ + (b"/old-spack/opt/specific-package", b"/first/specific-package"), + (b"/old-spack/opt", b"/sec/spack/opt"), + ], b"Binary with /old-spack/opt/specific-package and /old-spack/opt", - b"Binary with /first///////////////////////// and /second///////", + b"Binary with /////////first/specific-package and /sec/spack/opt", + suffix_safety_size=7, ) + # The case of having a direct null terminated common suffix. replace_and_expect( - OrderedDict( - [(b"/old-spack/opt", b"/second"), (b"/old-spack/opt/specific-package", b"/first")] - ), - b"Binary with /old-spack/opt/specific-package and /old-spack/opt", - b"Binary with /second////////specific-package and /second///////", + [ + (b"/old-spack/opt/specific-package", b"/first/specific-package"), + (b"/old-spack/opt", b"/sec/spack/opt"), + ], + b"Binary with /old-spack/opt/specific-package\0 and /old-spack/opt\0", + b"Binary with /////////first/specific-package\0 and /sec/spack/opt\0", + suffix_safety_size=7, ) + + # Testing the order of operations (not null terminated, long enough common suffix) + replace_and_expect( + [ + (b"/old-spack/opt", b"/s/spack/opt"), + (b"/old-spack/opt/specific-package", b"/first/specific-package"), + ], + b"Binary with /old-spack/opt/specific-package and /old-spack/opt", + b"Binary with ///s/spack/opt/specific-package and ///s/spack/opt", + suffix_safety_size=7, + ) + + # Testing the order of operations (null terminated, long enough common suffix) + replace_and_expect( + [ + (b"/old-spack/opt", b"/s/spack/opt"), + (b"/old-spack/opt/specific-package", b"/first/specific-package"), + ], + b"Binary with /old-spack/opt/specific-package\0 and /old-spack/opt\0", + b"Binary with ///s/spack/opt/specific-package\0 and ///s/spack/opt\0", + suffix_safety_size=7, + ) + + # Null terminated within the lookahead window, common suffix long enough + replace_and_expect( + [(b"/old-spack/opt/specific-package", b"/opt/specific-XXXXage")], + b"Binary with /old-spack/opt/specific-package/sub\0 data", + b"Binary with ///////////opt/specific-XXXXage/sub\0 data", + suffix_safety_size=7, + ) + + # Null terminated within the lookahead window, common suffix too short, but + # shortening is enough to spare more than 7 bytes of old suffix. + replace_and_expect( + [(b"/old-spack/opt/specific-package", b"/opt/specific-XXXXXge")], + b"Binary with /old-spack/opt/specific-package/sub\0 data", + b"Binary with /opt/specific-XXXXXge/sub\0ckage/sub\0 data", # ckage/sub = 9 bytes + suffix_safety_size=7, + ) + + # Null terminated within the lookahead window, common suffix too short, + # shortening leaves exactly 7 suffix bytes untouched, amazing! + replace_and_expect( + [(b"/old-spack/opt/specific-package", b"/spack/specific-XXXXXge")], + b"Binary with /old-spack/opt/specific-package/sub\0 data", + b"Binary with /spack/specific-XXXXXge/sub\0age/sub\0 data", # age/sub = 7 bytes + suffix_safety_size=7, + ) + + # Null terminated within the lookahead window, common suffix too short, + # shortening doesn't leave space for 7 bytes, sad! + error_msg = "Cannot replace {!r} with {!r} in the C-string {!r}.".format( + b"/old-spack/opt/specific-package", + b"/snacks/specific-XXXXXge", + b"/old-spack/opt/specific-package/sub", + ) + with pytest.raises(spack.relocate.CannotShrinkCString, match=error_msg): + replace_and_expect( + [(b"/old-spack/opt/specific-package", b"/snacks/specific-XXXXXge")], + b"Binary with /old-spack/opt/specific-package/sub\0 data", + # expect failure! + suffix_safety_size=7, + ) + + # Check that it works when changing suffix_safety_size. + replace_and_expect( + [(b"/old-spack/opt/specific-package", b"/snacks/specific-XXXXXXe")], + b"Binary with /old-spack/opt/specific-package/sub\0 data", + b"Binary with /snacks/specific-XXXXXXe/sub\0ge/sub\0 data", + suffix_safety_size=6, + ) + + # Finally check the case of no shortening but a long enough common suffix. + replace_and_expect( + [(b"pkg-gwixwaalgczp6", b"pkg-zkesfralgczp6")], + b"Binary with pkg-gwixwaalgczp6/config\0 data", + b"Binary with pkg-zkesfralgczp6/config\0 data", + suffix_safety_size=7, + ) + + # Too short matching suffix, identical string length + error_msg = "Cannot replace {!r} with {!r} in the C-string {!r}.".format( + b"pkg-gwixwaxlgczp6", + b"pkg-zkesfrzlgczp6", + b"pkg-gwixwaxlgczp6", + ) + with pytest.raises(spack.relocate.CannotShrinkCString, match=error_msg): + replace_and_expect( + [(b"pkg-gwixwaxlgczp6", b"pkg-zkesfrzlgczp6")], + b"Binary with pkg-gwixwaxlgczp6\0 data", + # expect failure + suffix_safety_size=7, + ) + + # Finally, make sure that the regex is not greedily finding the LAST null byte + # it should find the first null byte in the window. In this test we put one null + # at a distance where we cant keep a long enough suffix, and one where we can, + # so we should expect failure when the first null is used. + error_msg = "Cannot replace {!r} with {!r} in the C-string {!r}.".format( + b"pkg-abcdef", + b"pkg-xyzabc", + b"pkg-abcdef", + ) + with pytest.raises(spack.relocate.CannotShrinkCString, match=error_msg): + replace_and_expect( + [(b"pkg-abcdef", b"pkg-xyzabc")], + b"Binary with pkg-abcdef\0/xx\0", # def\0/xx is 7 bytes. + # expect failure + suffix_safety_size=7, + ) diff --git a/lib/spack/spack/test/rewiring.py b/lib/spack/spack/test/rewiring.py index 936ba1e78a4..085fb950bbd 100644 --- a/lib/spack/spack/test/rewiring.py +++ b/lib/spack/spack/test/rewiring.py @@ -18,7 +18,7 @@ if sys.platform == "darwin": args.extend(["/usr/bin/clang++", "install_name_tool"]) else: - args.extend(["/usr/bin/g++", "patchelf"]) + args.extend(["g++", "patchelf"]) @pytest.mark.requires_executables(*args) diff --git a/var/spack/repos/builtin.mock/packages/garply/package.py b/var/spack/repos/builtin.mock/packages/garply/package.py index 819da452861..7fc3fd484a3 100644 --- a/var/spack/repos/builtin.mock/packages/garply/package.py +++ b/var/spack/repos/builtin.mock/packages/garply/package.py @@ -83,7 +83,12 @@ class Garply f.write(garply_cc % prefix.config) with open("%s/garply/garplinator.cc" % self.stage.source_path, "w") as f: f.write(garplinator_cc) - gpp = which("/usr/bin/g++") + gpp = which( + "g++", + path=":".join( + [s for s in os.environ["PATH"].split(os.pathsep) if "lib/spack/env" not in s] + ), + ) if sys.platform == "darwin": gpp = which("/usr/bin/clang++") gpp( diff --git a/var/spack/repos/builtin.mock/packages/quux/package.py b/var/spack/repos/builtin.mock/packages/quux/package.py index 693ef07ba44..de4f8b93279 100644 --- a/var/spack/repos/builtin.mock/packages/quux/package.py +++ b/var/spack/repos/builtin.mock/packages/quux/package.py @@ -97,7 +97,12 @@ class Quux f.write(quux_h) with open("%s/quux/quuxifier.cc" % self.stage.source_path, "w") as f: f.write(quuxifier_cc) - gpp = which("/usr/bin/g++") + gpp = which( + "g++", + path=":".join( + [s for s in os.environ["PATH"].split(os.pathsep) if "lib/spack/env" not in s] + ), + ) if sys.platform == "darwin": gpp = which("/usr/bin/clang++") gpp( From c9fcb8aadc2ded5bcaa999f108f0c92213824ee2 Mon Sep 17 00:00:00 2001 From: Erik Schnetter Date: Sat, 5 Nov 2022 10:34:59 -0400 Subject: [PATCH 369/442] openssh: New version 9.1p1 (#33668) Co-authored-by: Bernhard Kaindl <43588962+bernhardkaindl@users.noreply.github.com> --- var/spack/repos/builtin/packages/openssh/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/openssh/package.py b/var/spack/repos/builtin/packages/openssh/package.py index 14e6581b304..245accc938f 100755 --- a/var/spack/repos/builtin/packages/openssh/package.py +++ b/var/spack/repos/builtin/packages/openssh/package.py @@ -23,6 +23,7 @@ class Openssh(AutotoolsPackage): tags = ["core-packages"] + version("9.1p1", sha256="19f85009c7e3e23787f0236fbb1578392ab4d4bf9f8ec5fe6bc1cd7e8bfdd288") version("9.0p1", sha256="03974302161e9ecce32153cfa10012f1e65c8f3750f573a73ab1befd5972a28a") version("8.9p1", sha256="fd497654b7ab1686dac672fb83dfb4ba4096e8b5ffcdaccd262380ae58bec5e7") version("8.8p1", sha256="4590890ea9bb9ace4f71ae331785a3a5823232435161960ed5fc86588f331fe9") From 5558940ce6fee399155bd31be7f1c8c361691979 Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Sat, 5 Nov 2022 15:59:12 +0100 Subject: [PATCH 370/442] Add support for Python 3.11 (#33505) Argparse started raising ArgumentError exceptions when the same parser is added twice. Therefore, we perform the addition only if the parser is not there already Port match syntax to our unparser --- .github/workflows/audit.yaml | 2 +- .github/workflows/unit_tests.yaml | 15 +-- .github/workflows/valid-style.yml | 6 +- .../docs/tables/system_prerequisites.csv | 2 +- lib/spack/spack/main.py | 22 +++-- lib/spack/spack/test/util/unparse/unparse.py | 74 +++++++++++++++ lib/spack/spack/util/unparse/unparser.py | 92 +++++++++++++++++++ 7 files changed, 193 insertions(+), 20 deletions(-) diff --git a/.github/workflows/audit.yaml b/.github/workflows/audit.yaml index 5b463a3e0c2..275abb2d539 100644 --- a/.github/workflows/audit.yaml +++ b/.github/workflows/audit.yaml @@ -25,7 +25,7 @@ jobs: python-version: ${{inputs.python_version}} - name: Install Python packages run: | - pip install --upgrade pip six setuptools pytest codecov 'coverage[toml]<=6.2' + pip install --upgrade pip six setuptools pytest codecov coverage[toml] - name: Package audits (with coverage) if: ${{ inputs.with_coverage == 'true' }} run: | diff --git a/.github/workflows/unit_tests.yaml b/.github/workflows/unit_tests.yaml index 80b4593c234..6a21d166f89 100644 --- a/.github/workflows/unit_tests.yaml +++ b/.github/workflows/unit_tests.yaml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['2.7', '3.6', '3.7', '3.8', '3.9', '3.10'] + python-version: ['2.7', '3.6', '3.7', '3.8', '3.9', '3.10', '3.11'] concretizer: ['clingo'] on_develop: - ${{ github.ref == 'refs/heads/develop' }} @@ -22,7 +22,7 @@ jobs: - python-version: 2.7 concretizer: original on_develop: ${{ github.ref == 'refs/heads/develop' }} - - python-version: '3.10' + - python-version: '3.11' concretizer: original on_develop: ${{ github.ref == 'refs/heads/develop' }} exclude: @@ -35,6 +35,9 @@ jobs: - python-version: '3.9' concretizer: 'clingo' on_develop: false + - python-version: '3.10' + concretizer: 'clingo' + on_develop: false steps: - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # @v2 @@ -86,7 +89,7 @@ jobs: SPACK_TEST_SOLVER: ${{ matrix.concretizer }} SPACK_TEST_PARALLEL: 2 COVERAGE: true - UNIT_TEST_COVERAGE: ${{ (matrix.python-version == '3.10') }} + UNIT_TEST_COVERAGE: ${{ (matrix.python-version == '3.11') }} run: | share/spack/qa/run-unit-tests - uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 @@ -101,7 +104,7 @@ jobs: fetch-depth: 0 - uses: actions/setup-python@13ae5bb136fac2878aff31522b9efb785519f984 # @v2 with: - python-version: '3.10' + python-version: '3.11' - name: Install System packages run: | sudo apt-get -y update @@ -109,7 +112,7 @@ jobs: sudo apt-get install -y coreutils kcov csh zsh tcsh fish dash bash - name: Install Python packages run: | - pip install --upgrade pip six setuptools pytest codecov coverage[toml]==6.2 pytest-xdist + pip install --upgrade pip six setuptools pytest codecov coverage[toml] pytest-xdist - name: Setup git configuration run: | # Need this for the git tests to succeed. @@ -158,7 +161,7 @@ jobs: fetch-depth: 0 - uses: actions/setup-python@13ae5bb136fac2878aff31522b9efb785519f984 # @v2 with: - python-version: '3.10' + python-version: '3.11' - name: Install System packages run: | sudo apt-get -y update diff --git a/.github/workflows/valid-style.yml b/.github/workflows/valid-style.yml index d91f6e958a3..a82c786b44a 100644 --- a/.github/workflows/valid-style.yml +++ b/.github/workflows/valid-style.yml @@ -21,7 +21,7 @@ jobs: - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # @v2 - uses: actions/setup-python@13ae5bb136fac2878aff31522b9efb785519f984 # @v2 with: - python-version: '3.10' + python-version: '3.11' cache: 'pip' - name: Install Python Packages run: | @@ -40,7 +40,7 @@ jobs: fetch-depth: 0 - uses: actions/setup-python@13ae5bb136fac2878aff31522b9efb785519f984 # @v2 with: - python-version: '3.10' + python-version: '3.11' cache: 'pip' - name: Install Python packages run: | @@ -57,4 +57,4 @@ jobs: uses: ./.github/workflows/audit.yaml with: with_coverage: ${{ inputs.with_coverage }} - python_version: '3.10' + python_version: '3.11' diff --git a/lib/spack/docs/tables/system_prerequisites.csv b/lib/spack/docs/tables/system_prerequisites.csv index 5f661883d34..af8dcafffa6 100644 --- a/lib/spack/docs/tables/system_prerequisites.csv +++ b/lib/spack/docs/tables/system_prerequisites.csv @@ -1,5 +1,5 @@ Name, Supported Versions, Notes, Requirement Reason -Python, 2.7/3.6-3.10, , Interpreter for Spack +Python, 2.7/3.6-3.11, , Interpreter for Spack C/C++ Compilers, , , Building software make, , , Build software patch, , , Build software diff --git a/lib/spack/spack/main.py b/lib/spack/spack/main.py index 4c3f19d75d5..a9a9d20df70 100644 --- a/lib/spack/spack/main.py +++ b/lib/spack/spack/main.py @@ -343,17 +343,21 @@ def add_command(self, cmd_name): self._remove_action(self._actions[-1]) self.subparsers = self.add_subparsers(metavar="COMMAND", dest="command") - # each command module implements a parser() function, to which we - # pass its subparser for setup. - module = spack.cmd.get_module(cmd_name) + if cmd_name not in self.subparsers._name_parser_map: + # each command module implements a parser() function, to which we + # pass its subparser for setup. + module = spack.cmd.get_module(cmd_name) - # build a list of aliases - alias_list = [k for k, v in aliases.items() if v == cmd_name] + # build a list of aliases + alias_list = [k for k, v in aliases.items() if v == cmd_name] - subparser = self.subparsers.add_parser( - cmd_name, aliases=alias_list, help=module.description, description=module.description - ) - module.setup_parser(subparser) + subparser = self.subparsers.add_parser( + cmd_name, + aliases=alias_list, + help=module.description, + description=module.description, + ) + module.setup_parser(subparser) # return the callable function for the command return spack.cmd.get_command(cmd_name) diff --git a/lib/spack/spack/test/util/unparse/unparse.py b/lib/spack/spack/test/util/unparse/unparse.py index 49009ae98e6..82148c9dc82 100644 --- a/lib/spack/spack/test/util/unparse/unparse.py +++ b/lib/spack/spack/test/util/unparse/unparse.py @@ -178,6 +178,71 @@ async def f(): """ +match_literal = """\ +match status: + case 400: + return "Bad request" + case 404 | 418: + return "Not found" + case _: + return "Something's wrong with the internet" +""" + +match_with_noop = """\ +match status: + case 400: + return "Bad request" +""" + +match_literal_and_variable = """\ +match point: + case (0, 0): + print("Origin") + case (0, y): + print(f"Y={y}") + case (x, 0): + print(f"X={x}") + case (x, y): + print(f"X={x}, Y={y}") + case _: + raise ValueError("Not a point") +""" + + +match_classes = """\ +class Point: + x: int + y: int + +def location(point): + match point: + case Point(x=0, y=0): + print("Origin is the point's location.") + case Point(x=0, y=y): + print(f"Y={y} and the point is on the y-axis.") + case Point(x=x, y=0): + print(f"X={x} and the point is on the x-axis.") + case Point(): + print("The point is located somewhere else on the plane.") + case _: + print("Not a point") +""" + +match_nested = """\ +match points: + case []: + print("No points in the list.") + case [Point(0, 0)]: + print("The origin is the only point in the list.") + case [Point(x, y)]: + print(f"A single point {x}, {y} is in the list.") + case [Point(0, y1), Point(0, y2)]: + print(f"Two points on the Y axis at {y1}, {y2} are in the list.") + case _: + print("Something else is found in the list.") +""" + + def check_ast_roundtrip(code1, filename="internal", mode="exec"): ast1 = compile(str(code1), filename, mode, ast.PyCF_ONLY_AST) code2 = spack.util.unparse.unparse(ast1) @@ -512,3 +577,12 @@ def test_async_with(): @pytest.mark.skipif(sys.version_info < (3, 5), reason="Not supported < 3.5") def test_async_with_as(): check_ast_roundtrip(async_with_as) + + +@pytest.mark.skipif(sys.version_info < (3, 10), reason="Not supported < 3.10") +@pytest.mark.parametrize( + "literal", + [match_literal, match_with_noop, match_literal_and_variable, match_classes, match_nested], +) +def test_match_literal(literal): + check_ast_roundtrip(literal) diff --git a/lib/spack/spack/util/unparse/unparser.py b/lib/spack/spack/util/unparse/unparser.py index a46d19fa76b..c204aea25a4 100644 --- a/lib/spack/spack/util/unparse/unparser.py +++ b/lib/spack/spack/util/unparse/unparser.py @@ -1243,3 +1243,95 @@ def visit_withitem(self, node): if node.optional_vars: self.write(" as ") self.dispatch(node.optional_vars) + + def visit_Match(self, node): + self.fill("match ") + self.dispatch(node.subject) + with self.block(): + for case in node.cases: + self.dispatch(case) + + def visit_match_case(self, node): + self.fill("case ") + self.dispatch(node.pattern) + if node.guard: + self.write(" if ") + self.dispatch(node.guard) + with self.block(): + self.dispatch(node.body) + + def visit_MatchValue(self, node): + self.dispatch(node.value) + + def visit_MatchSingleton(self, node): + self._write_constant(node.value) + + def visit_MatchSequence(self, node): + with self.delimit("[", "]"): + interleave(lambda: self.write(", "), self.dispatch, node.patterns) + + def visit_MatchStar(self, node): + name = node.name + if name is None: + name = "_" + self.write("*{}".format(name)) + + def visit_MatchMapping(self, node): + def write_key_pattern_pair(pair): + k, p = pair + self.dispatch(k) + self.write(": ") + self.dispatch(p) + + with self.delimit("{", "}"): + keys = node.keys + interleave( + lambda: self.write(", "), + write_key_pattern_pair, + zip(keys, node.patterns), + ) + rest = node.rest + if rest is not None: + if keys: + self.write(", ") + self.write("**{}".format(rest)) + + def visit_MatchClass(self, node): + self.set_precedence(_Precedence.ATOM, node.cls) + self.dispatch(node.cls) + with self.delimit("(", ")"): + patterns = node.patterns + interleave(lambda: self.write(", "), self.dispatch, patterns) + attrs = node.kwd_attrs + if attrs: + + def write_attr_pattern(pair): + attr, pattern = pair + self.write("{}=".format(attr)) + self.dispatch(pattern) + + if patterns: + self.write(", ") + interleave( + lambda: self.write(", "), + write_attr_pattern, + zip(attrs, node.kwd_patterns), + ) + + def visit_MatchAs(self, node): + name = node.name + pattern = node.pattern + if name is None: + self.write("_") + elif pattern is None: + self.write(node.name) + else: + with self.require_parens(_Precedence.TEST, node): + self.set_precedence(_Precedence.BOR, node.pattern) + self.dispatch(node.pattern) + self.write(" as {}".format(node.name)) + + def visit_MatchOr(self, node): + with self.require_parens(_Precedence.BOR, node): + self.set_precedence(pnext(_Precedence.BOR), *node.patterns) + interleave(lambda: self.write(" | "), self.dispatch, node.patterns) From 0f32f7d0e9077b78aea0015ca37bc65cc76c4ce2 Mon Sep 17 00:00:00 2001 From: "Adam J. Stewart" Date: Sat, 5 Nov 2022 10:38:49 -0700 Subject: [PATCH 371/442] py-transformers: add v4.24.0 (#33716) * py-transformers: add v4.24.0 * Internet access still required --- .../cloud_pipelines/stacks/ml-cpu/spack.yaml | 3 +++ .../cloud_pipelines/stacks/ml-cuda/spack.yaml | 3 +++ .../cloud_pipelines/stacks/ml-rocm/spack.yaml | 3 +++ .../packages/py-huggingface-hub/package.py | 5 ++++ .../builtin/packages/py-tokenizers/package.py | 4 ++-- .../packages/py-transformers/package.py | 24 ++++++++++++------- 6 files changed, 32 insertions(+), 10 deletions(-) diff --git a/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml index a03ecbae699..6b6280d66ce 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml @@ -23,6 +23,9 @@ spack: # Horovod - py-horovod + # Hugging Face + - py-transformers + # JAX # https://github.com/google/jax/issues/12614 # - py-jax diff --git a/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml index ada465fd1a0..9d050b5b01b 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml @@ -26,6 +26,9 @@ spack: # Horovod - py-horovod + # Hugging Face + - py-transformers + # JAX # https://github.com/google/jax/issues/12614 # - py-jax diff --git a/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml index bbc6159f591..f1c5fa39567 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml @@ -28,6 +28,9 @@ spack: # Horovod - py-horovod + # Hugging Face + - py-transformers + # JAX # https://github.com/google/jax/issues/12614 # - py-jax diff --git a/var/spack/repos/builtin/packages/py-huggingface-hub/package.py b/var/spack/repos/builtin/packages/py-huggingface-hub/package.py index f9d5fec83a5..be59e5b60ca 100644 --- a/var/spack/repos/builtin/packages/py-huggingface-hub/package.py +++ b/var/spack/repos/builtin/packages/py-huggingface-hub/package.py @@ -14,13 +14,18 @@ class PyHuggingfaceHub(PythonPackage): homepage = "https://github.com/huggingface/huggingface_hub" pypi = "huggingface_hub/huggingface_hub-0.0.10.tar.gz" + version("0.10.1", sha256="5c188d5b16bec4b78449f8681f9975ff9d321c16046cc29bcf0d7e464ff29276") version("0.0.10", sha256="556765e4c7edd2d2c4c733809bae1069dca20e10ff043870ec40d53e498efae2") version("0.0.8", sha256="be5b9a7ed36437bb10a780d500154d426798ec16803ff3406f7a61107e4ebfc2") + depends_on("python@3.7:", when="@0.10:", type=("build", "run")) depends_on("python@3.6:", type=("build", "run")) depends_on("py-setuptools", type="build") depends_on("py-filelock", type=("build", "run")) depends_on("py-requests", type=("build", "run")) depends_on("py-tqdm", type=("build", "run")) + depends_on("py-pyyaml@5.1:", when="@0.10:", type=("build", "run")) + depends_on("py-typing-extensions@3.7.4.3:", when="@0.10:", type=("build", "run")) depends_on("py-typing-extensions", when="@0.0.10:", type=("build", "run")) depends_on("py-importlib-metadata", when="^python@:3.7", type=("build", "run")) + depends_on("py-packaging@20.9:", when="@0.10:", type=("build", "run")) diff --git a/var/spack/repos/builtin/packages/py-tokenizers/package.py b/var/spack/repos/builtin/packages/py-tokenizers/package.py index 138fe084664..24befd2986b 100644 --- a/var/spack/repos/builtin/packages/py-tokenizers/package.py +++ b/var/spack/repos/builtin/packages/py-tokenizers/package.py @@ -13,15 +13,15 @@ class PyTokenizers(PythonPackage): homepage = "https://github.com/huggingface/tokenizers" pypi = "tokenizers/tokenizers-0.6.0.tar.gz" + version("0.13.1", sha256="3333d1cee5c8f47c96362ea0abc1f81c77c9b92c6c3d11cbf1d01985f0d5cf1d") version("0.10.3", sha256="1a5d3b596c6d3a237e1ad7f46c472d467b0246be7fd1a364f12576eb8db8f7e6") version("0.6.0", sha256="1da11fbfb4f73be695bed0d655576097d09a137a16dceab2f66399716afaffac") version("0.5.2", sha256="b5a235f9c71d04d4925df6c4fa13b13f1d03f9b7ac302b89f8120790c4f742bc") depends_on("py-setuptools", type="build") depends_on("py-setuptools-rust", type="build") - depends_on("rust@nightly", type="build") # TODO: This package currently requires internet access to install. - # Also, a nightly or dev version of rust is required to build. + # Also, a nightly or dev version of rust is required to build older versions. # https://github.com/huggingface/tokenizers/issues/176 # https://github.com/PyO3/pyo3/issues/5 diff --git a/var/spack/repos/builtin/packages/py-transformers/package.py b/var/spack/repos/builtin/packages/py-transformers/package.py index b0e3fbd1fdb..d2643b732ca 100644 --- a/var/spack/repos/builtin/packages/py-transformers/package.py +++ b/var/spack/repos/builtin/packages/py-transformers/package.py @@ -16,24 +16,32 @@ class PyTransformers(PythonPackage): maintainers = ["adamjstewart"] + version("4.24.0", sha256="486f353a8e594002e48be0e2aba723d96eda839e63bfe274702a4b5eda85559b") version("4.6.1", sha256="83dbff763b7e7dc57cbef1a6b849655d4fcab6bffdd955c5e8bea12a4f76dc10") version("2.8.0", sha256="b9f29cdfd39c28f29e0806c321270dea337d6174a7aa60daf9625bf83dbb12ee") + depends_on("python@3.7:", when="@4.24:", type=("build", "run")) depends_on("python@3.6:", type=("build", "run")) depends_on("py-setuptools", type="build") - - depends_on("py-dataclasses", when="^python@:3.6", type=("build", "run")) - depends_on("py-importlib-metadata", when="@4.6.1: ^python@:3.7", type=("build", "run")) + depends_on("py-importlib-metadata", when="@4.6: ^python@:3.7", type=("build", "run")) depends_on("py-filelock", type=("build", "run")) - depends_on("py-huggingface-hub@0.0.8", when="@4.6.1:", type=("build", "run")) + depends_on("py-huggingface-hub@0.10:0", when="@4.24:", type=("build", "run")) + depends_on("py-huggingface-hub@0.0.8", when="@4.6.1", type=("build", "run")) + depends_on("py-numpy@1.17:", when="@4.6:", type=("build", "run")) depends_on("py-numpy", type=("build", "run")) - depends_on("py-numpy@1.17:", when="@4.6.1:", type=("build", "run")) - depends_on("py-packaging", when="@4.6.1:", type=("build", "run")) + depends_on("py-packaging@20:", when="@4.24:", type=("build", "run")) + depends_on("py-packaging", when="@4.6.1", type=("build", "run")) + depends_on("py-pyyaml@5.1:", when="@4.24:", type=("build", "run")) depends_on("py-regex@:2019.12.16,2019.12.18:", type=("build", "run")) depends_on("py-requests", type=("build", "run")) - depends_on("py-sacremoses", type=("build", "run")) + depends_on("py-tokenizers@0.11.1:0.11.2,0.11.4:0.13", when="@4.24:", type=("build", "run")) + depends_on("py-tokenizers@0.10.1:0.10", when="@4.6.1", type=("build", "run")) depends_on("py-tokenizers@0.5.2", when="@2.8.0", type=("build", "run")) - depends_on("py-tokenizers@0.10.1:0.10", when="@4.6.1:", type=("build", "run")) depends_on("py-tqdm@4.27:", type=("build", "run")) + + # Historical requirements + depends_on("py-dataclasses", when="@4.6.1 ^python@:3.6", type=("build", "run")) + depends_on("py-sacremoses", when="@:4.6", type=("build", "run")) depends_on("py-boto3", when="@2.8.0", type=("build", "run")) + depends_on("py-dataclasses", when="@2.8.0 ^python@:3.6", type=("build", "run")) depends_on("py-sentencepiece", when="@2.8.0", type=("build", "run")) From e550f48b173dfc3d14dfbb1b8091947de4f6892b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20J=2E=20Padr=C3=B3n=20Gonz=C3=A1lez?= Date: Sun, 6 Nov 2022 00:28:58 +0100 Subject: [PATCH 372/442] ADD version 0.19.0 in py-gym recipe (#33701) * ADD version 0.19.0 in py-gym recipe * Fix py-gym download url and dependencies for v0.19.0 * Fix stupid error in previous commit: no change in py-cloudpickle dep * Yes, I should've paid more attention! O:) I think now it is right, thanks! --- var/spack/repos/builtin/packages/py-gym/package.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/var/spack/repos/builtin/packages/py-gym/package.py b/var/spack/repos/builtin/packages/py-gym/package.py index 0d610934ab2..3614c7a7908 100644 --- a/var/spack/repos/builtin/packages/py-gym/package.py +++ b/var/spack/repos/builtin/packages/py-gym/package.py @@ -14,16 +14,16 @@ class PyGym(PythonPackage): environments.""" homepage = "https://github.com/openai/gym" - pypi = "gym/0.18.0.tar.gz" + pypi = "gym/gym-0.18.0.tar.gz" + version("0.19.0", sha256="940069b983806e1ccc400fa6d47b4e34e462accf6a4fb0acb0a5e509ad0f502d") version("0.18.0", sha256="a0dcd25c1373f3938f4cb4565f74f434fba6faefb73a42d09c9dddd0c08af53e") depends_on("python@3.6:", type=("build", "run")) depends_on("py-setuptools", type="build") - depends_on("py-scipy", type=("build", "run")) - depends_on("py-numpy@1.10.4:", type=("build", "run")) + depends_on("py-scipy", type=("build", "run"), when="@0.18.0") + depends_on("py-numpy@1.10.4:", type=("build", "run"), when="@0.18.0") + depends_on("py-numpy@1.18.0:", type=("build", "run"), when="@0.19.0") depends_on("py-pyglet@1.4.0:1.5.0", type=("build", "run"), when="@0.18.0") - depends_on("py-pyglet@1.4.0:1.5.15", type=("build", "run"), when="@0.18.1") - depends_on("pil@:8.2.0", type=("build", "run"), when="@0.18.1") depends_on("pil@:7.2.0", type=("build", "run"), when="@0.18.0") depends_on("py-cloudpickle@1.2.0:1.6", type=("build", "run")) From 27e1d28c0bcd68c57518923008106e53ee445476 Mon Sep 17 00:00:00 2001 From: Greg Becker Date: Sun, 6 Nov 2022 01:11:59 -0800 Subject: [PATCH 373/442] canonicalize_path: add arch information to substitutions (#29810) Co-authored-by: becker33 --- lib/spack/docs/configuration.rst | 11 +++++++++++ lib/spack/spack/test/config.py | 11 +++++++++++ lib/spack/spack/util/path.py | 28 ++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/lib/spack/docs/configuration.rst b/lib/spack/docs/configuration.rst index add9150967b..26df115567f 100644 --- a/lib/spack/docs/configuration.rst +++ b/lib/spack/docs/configuration.rst @@ -405,6 +405,17 @@ Spack understands several special variables. These are: * ``$user``: name of the current user * ``$user_cache_path``: user cache directory (``~/.spack`` unless :ref:`overridden `) +* ``$architecture``: the architecture triple of the current host, as + detected by Spack. +* ``$arch``: alias for ``$architecture``. +* ``$platform``: the platform of the current host, as detected by Spack. +* ``$operating_system``: the operating system of the current host, as + detected by the ``distro`` python module. +* ``$os``: alias for ``$operating_system``. +* ``$target``: the ISA target for the current host, as detected by + ArchSpec. E.g. ``skylake`` or ``neoverse-n1``. +* ``$target_family``. The target family for the current host, as + detected by ArchSpec. E.g. ``x86_64`` or ``aarch64``. Note that, as with shell variables, you can write these as ``$varname`` or with braces to distinguish the variable from surrounding characters: diff --git a/lib/spack/spack/test/config.py b/lib/spack/spack/test/config.py index f5f91f039de..03f358acd17 100644 --- a/lib/spack/spack/test/config.py +++ b/lib/spack/spack/test/config.py @@ -379,6 +379,17 @@ def test_substitute_config_variables(mock_low_high_config, monkeypatch): os.path.join(mock_low_high_config.scopes["low"].path, os.path.join("foo", "bar", "baz")) ) + # test architecture information is in replacements + assert spack_path.canonicalize_path( + os.path.join("foo", "$platform", "bar") + ) == os.path.abspath(os.path.join("foo", "test", "bar")) + + host_target = spack.platforms.host().target("default_target") + host_target_family = str(host_target.microarchitecture.family) + assert spack_path.canonicalize_path( + os.path.join("foo", "$target_family", "bar") + ) == os.path.abspath(os.path.join("foo", host_target_family, "bar")) + packages_merge_low = {"packages": {"foo": {"variants": ["+v1"]}, "bar": {"variants": ["+v2"]}}} diff --git a/lib/spack/spack/util/path.py b/lib/spack/spack/util/path.py index e5a5e61632d..c378f1eb2da 100644 --- a/lib/spack/spack/util/path.py +++ b/lib/spack/spack/util/path.py @@ -27,16 +27,37 @@ __all__ = ["substitute_config_variables", "substitute_path_variables", "canonicalize_path"] +def architecture(): + # break circular import + import spack.platforms + import spack.spec + + host_platform = spack.platforms.host() + host_os = host_platform.operating_system("default_os") + host_target = host_platform.target("default_target") + + return spack.spec.ArchSpec((str(host_platform), str(host_os), str(host_target))) + + # Substitutions to perform def replacements(): # break circular import from spack.util.executable import spack.paths + arch = architecture() + return { "spack": spack.paths.prefix, "user": getpass.getuser(), "tempdir": tempfile.gettempdir(), "user_cache_path": spack.paths.user_cache_path, + "architecture": str(arch), + "arch": str(arch), + "platform": str(arch.platform), + "operating_system": str(arch.os), + "os": str(arch.os), + "target": str(arch.target), + "target_family": str(arch.target.microarchitecture.family), } @@ -245,6 +266,13 @@ def substitute_config_variables(path): - $tempdir Default temporary directory returned by tempfile.gettempdir() - $user The current user's username - $user_cache_path The user cache directory (~/.spack, unless overridden) + - $architecture The spack architecture triple for the current system + - $arch The spack architecture triple for the current system + - $platform The spack platform for the current system + - $os The OS of the current system + - $operating_system The OS of the current system + - $target The ISA target detected for the system + - $target_family The family of the target detected for the system These are substituted case-insensitively into the path, and users can use either ``$var`` or ``${var}`` syntax for the variables. $env is only From fffc4c4846eaa699bb87f681bac1af00149732e8 Mon Sep 17 00:00:00 2001 From: Erik Schnetter Date: Sun, 6 Nov 2022 05:05:57 -0500 Subject: [PATCH 374/442] z3: New version 4.11.2 (#33725) --- var/spack/repos/builtin/packages/z3/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/z3/package.py b/var/spack/repos/builtin/packages/z3/package.py index 7f8c1dcbb04..dfe3be3a9fe 100644 --- a/var/spack/repos/builtin/packages/z3/package.py +++ b/var/spack/repos/builtin/packages/z3/package.py @@ -14,6 +14,7 @@ class Z3(CMakePackage): homepage = "https://github.com/Z3Prover/z3/wiki" url = "https://github.com/Z3Prover/z3/archive/z3-4.5.0.tar.gz" + version("4.11.2", sha256="e3a82431b95412408a9c994466fad7252135c8ed3f719c986cd75c8c5f234c7e") version("4.8.16", sha256="75f95e09f3f35fef746e571d5ec88a4efba27f1bc8f1a0ef1117167486ec3dc6") version("4.8.15", sha256="2abe7f5ecb7c8023b712ffba959c55b4515f4978522a6882391de289310795ac") version("4.8.14", sha256="96a1f49a7701120cc38bfa63c02ff93be4d64c7926cea41977dedec7d87a1364") From f286a7fa9a265ca288db8846836e840de52e7408 Mon Sep 17 00:00:00 2001 From: Glenn Johnson Date: Sun, 6 Nov 2022 05:40:14 -0600 Subject: [PATCH 375/442] Add version 4.2.2 to R (#33726) --- var/spack/repos/builtin/packages/r/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/r/package.py b/var/spack/repos/builtin/packages/r/package.py index af5d740b128..b1656455244 100644 --- a/var/spack/repos/builtin/packages/r/package.py +++ b/var/spack/repos/builtin/packages/r/package.py @@ -23,6 +23,7 @@ class R(AutotoolsPackage): maintainers = ["glennpj"] + version("4.2.2", sha256="0ff62b42ec51afa5713caee7c4fde7a0c45940ba39bef8c5c9487fef0c953df5") version("4.2.1", sha256="4d52db486d27848e54613d4ee977ad952ec08ce17807e1b525b10cd4436c643f") version("4.2.0", sha256="38eab7719b7ad095388f06aa090c5a2b202791945de60d3e2bb0eab1f5097488") version("4.1.3", sha256="15ff5b333c61094060b2a52e9c1d8ec55cc42dd029e39ca22abdaa909526fed6") From f07f75a47b862386042700bf7cebd11f4115ac83 Mon Sep 17 00:00:00 2001 From: "John W. Parent" <45471568+johnwparent@users.noreply.github.com> Date: Sun, 6 Nov 2022 08:21:42 -0500 Subject: [PATCH 376/442] CMake: add versions 3.24.3, 3.23.4, and 3.23.5 (#33700) --- var/spack/repos/builtin/packages/cmake/package.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/var/spack/repos/builtin/packages/cmake/package.py b/var/spack/repos/builtin/packages/cmake/package.py index 0ce352b9ab4..272ce1bd05d 100644 --- a/var/spack/repos/builtin/packages/cmake/package.py +++ b/var/spack/repos/builtin/packages/cmake/package.py @@ -28,9 +28,12 @@ class Cmake(Package): executables = ["^cmake$"] version("master", branch="master") + version("3.24.3", sha256="b53aa10fa82bff84ccdb59065927b72d3bee49f4d86261249fc0984b3b367291") version("3.24.2", sha256="0d9020f06f3ddf17fb537dc228e1a56c927ee506b486f55fe2dc19f69bf0c8db") version("3.24.1", sha256="4931e277a4db1a805f13baa7013a7757a0cbfe5b7932882925c7061d9d1fa82b") version("3.24.0", sha256="c2b61f7cdecb1576cad25f918a8f42b8685d88a832fd4b62b9e0fa32e915a658") + version("3.23.5", sha256="f2944cde7a140b992ba5ccea2009a987a92413762250de22ebbace2319a0f47d") + version("3.23.4", sha256="aa8b6c17a5adf04de06e42c06adc7e25b21e4fe8378f44f703a861e5f6ac59c7") version("3.23.3", sha256="06fefaf0ad94989724b56f733093c2623f6f84356e5beb955957f9ce3ee28809") version("3.23.2", sha256="f316b40053466f9a416adf981efda41b160ca859e97f6a484b447ea299ff26aa") version("3.23.1", sha256="33fd10a8ec687a4d0d5b42473f10459bb92b3ae7def2b745dc10b192760869f3") From 8b4b26fcbd754e17b0120b17d58b42fc8d30627d Mon Sep 17 00:00:00 2001 From: Morten Kristensen Date: Sun, 6 Nov 2022 19:32:17 +0100 Subject: [PATCH 377/442] py-vermin: add latest version 1.5.0 (#33727) --- var/spack/repos/builtin/packages/py-vermin/package.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/py-vermin/package.py b/var/spack/repos/builtin/packages/py-vermin/package.py index 02b7e565478..c4745cefe42 100644 --- a/var/spack/repos/builtin/packages/py-vermin/package.py +++ b/var/spack/repos/builtin/packages/py-vermin/package.py @@ -11,10 +11,11 @@ class PyVermin(PythonPackage): """Concurrently detect the minimum Python versions needed to run code.""" homepage = "https://github.com/netromdk/vermin" - url = "https://github.com/netromdk/vermin/archive/v1.4.2.tar.gz" + url = "https://github.com/netromdk/vermin/archive/v1.5.0.tar.gz" maintainers = ["netromdk"] + version("1.5.0", sha256="77207385c9cea1f02053a8f2e7f2e8c945394cf37c44c70ce217cada077a2d17") version("1.4.2", sha256="c9a69420b610bfb25d5a2abd7da6edf0ae4329481a857ef6c5d71f602ed5c63d") version("1.4.1", sha256="ee69d5e84f0d446e0d6574ec60c428798de6e6c8d055589f65ac02f074a7da25") version("1.4.0", sha256="984773ed6af60329e700b39c58b7584032acbc908a00b5a76d1ce5468c825c70") From d4b45605c875c5c6a3578cd8dab2a5c54e4779c5 Mon Sep 17 00:00:00 2001 From: Greg Becker Date: Sun, 6 Nov 2022 11:30:37 -0800 Subject: [PATCH 378/442] allow multiple compatible deps from CLI (#21262) Currently, Spack can fail for a valid spec if the spec is constructed from overlapping, but not conflicting, concrete specs via the hash. For example, if abcdef and ghijkl are the hashes of specs that both depend on zlib/mnopqr, then foo ^/abcdef ^/ghijkl will fail to construct a spec, with the error message "Cannot depend on zlib... twice". This PR changes this behavior to check whether the specs are compatible before failing. With this PR, foo ^/abcdef ^/ghijkl will concretize. As a side-effect, so will foo ^zlib ^zlib and other specs that are redundant on their dependencies. --- lib/spack/spack/spec.py | 18 +++++++++++++++++- lib/spack/spack/test/spec_syntax.py | 8 +++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py index 3b8ed07a83a..141f6c4b628 100644 --- a/lib/spack/spack/spec.py +++ b/lib/spack/spack/spec.py @@ -1559,8 +1559,24 @@ def _set_compiler(self, compiler): def _add_dependency(self, spec, deptypes): """Called by the parser to add another spec as a dependency.""" if spec.name in self._dependencies: - raise DuplicateDependencyError("Cannot depend on '%s' twice" % spec) + # allow redundant compatible dependency specifications + # depspec equality checks by name, so we need to check components + # separately to test whether the specs are identical + orig = self._dependencies[spec.name] + for dspec in orig: + if deptypes == dspec.deptypes: + try: + dspec.spec.constrain(spec) + return + except spack.error.UnsatisfiableSpecError: + raise DuplicateDependencyError( + "Cannot depend on incompatible specs '%s' and '%s'" + % (dspec.spec, spec) + ) + else: + raise DuplicateDependencyError("Cannot depend on '%s' twice" % spec) + # create an edge and add to parent and child self.add_dependency_edge(spec, deptypes) def add_dependency_edge(self, dependency_spec, deptype): diff --git a/lib/spack/spack/test/spec_syntax.py b/lib/spack/spack/test/spec_syntax.py index ab560bed084..cf1ce971d01 100644 --- a/lib/spack/spack/test/spec_syntax.py +++ b/lib/spack/spack/test/spec_syntax.py @@ -293,6 +293,12 @@ def test_canonicalize(self): self.check_parse("x ^y", "x@: ^y@:") + def test_parse_redundant_deps(self): + self.check_parse("x ^y@foo", "x ^y@foo ^y@foo") + self.check_parse("x ^y@foo+bar", "x ^y@foo ^y+bar") + self.check_parse("x ^y@foo+bar", "x ^y@foo+bar ^y") + self.check_parse("x ^y@foo+bar", "x ^y ^y@foo+bar") + def test_parse_errors(self): errors = ["x@@1.2", "x ^y@@1.2", "x@1.2::", "x::"] self._check_raises(SpecParseError, errors) @@ -481,7 +487,7 @@ def test_multiple_versions(self): self._check_raises(MultipleVersionError, multiples) def test_duplicate_dependency(self): - self._check_raises(DuplicateDependencyError, ["x ^y ^y"]) + self._check_raises(DuplicateDependencyError, ["x ^y@1 ^y@2"]) def test_duplicate_compiler(self): duplicates = [ From 258edf7dac07710ea6c50316dc53e5154d9cb3b7 Mon Sep 17 00:00:00 2001 From: Michael Kuhn Date: Sun, 6 Nov 2022 20:34:43 +0100 Subject: [PATCH 379/442] MesonPackage: disable automatic download and install of dependencies (#33717) Without this, Meson will use its Wraps to automatically download and install dependencies. We want to manage dependencies explicitly, therefore disable this functionality. --- lib/spack/spack/build_systems/meson.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/spack/spack/build_systems/meson.py b/lib/spack/spack/build_systems/meson.py index 6ab760cfb98..710eecc080e 100644 --- a/lib/spack/spack/build_systems/meson.py +++ b/lib/spack/spack/build_systems/meson.py @@ -142,15 +142,17 @@ def std_args(pkg): default_library = "shared" args = [ - "--prefix={0}".format(pkg.prefix), + "-Dprefix={0}".format(pkg.prefix), # If we do not specify libdir explicitly, Meson chooses something # like lib/x86_64-linux-gnu, which causes problems when trying to # find libraries and pkg-config files. # See https://github.com/mesonbuild/meson/issues/2197 - "--libdir={0}".format(pkg.prefix.lib), + "-Dlibdir={0}".format(pkg.prefix.lib), "-Dbuildtype={0}".format(build_type), "-Dstrip={0}".format(strip), "-Ddefault_library={0}".format(default_library), + # Do not automatically download and install dependencies + "-Dwrap_mode=nodownload", ] return args From 52cc798948e41eaa30dd7645bfa2d1ecda5f0fd3 Mon Sep 17 00:00:00 2001 From: Greg Becker Date: Sun, 6 Nov 2022 16:40:00 -0800 Subject: [PATCH 380/442] solver: do not punish explicitly requested compiler mismatches (#30074) --- lib/spack/spack/solver/concretize.lp | 19 ++++++++++++++++++- lib/spack/spack/test/concretize.py | 11 +++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/lib/spack/spack/solver/concretize.lp b/lib/spack/spack/solver/concretize.lp index 02528e694d7..a06d57ae10e 100644 --- a/lib/spack/spack/solver/concretize.lp +++ b/lib/spack/spack/solver/concretize.lp @@ -44,6 +44,8 @@ node_flag_set(Package, Flag, Value) :- attr("node_flag_set", Package, Flag, Val node_compiler_version_set(Package, Compiler, Version) :- attr("node_compiler_version_set", Package, Compiler, Version). +node_compiler_set(Package, Compiler) + :- attr("node_compiler_set", Package, Compiler). variant_default_value_from_cli(Package, Variant, Value) :- attr("variant_default_value_from_cli", Package, Variant, Value). @@ -1011,6 +1013,12 @@ compiler_match(Package, Dependency) compiler_mismatch(Package, Dependency) :- depends_on(Package, Dependency), + not node_compiler_set(Dependency, _), + not compiler_match(Package, Dependency). + +compiler_mismatch_required(Package, Dependency) + :- depends_on(Package, Dependency), + node_compiler_set(Dependency, _), not compiler_match(Package, Dependency). #defined node_compiler_set/2. @@ -1282,7 +1290,7 @@ opt_criterion(45, "preferred providers (non-roots)"). }. % Try to minimize the number of compiler mismatches in the DAG. -opt_criterion(40, "compiler mismatches"). +opt_criterion(40, "compiler mismatches that are not from CLI"). #minimize{ 0@240: #true }. #minimize{ 0@40: #true }. #minimize{ @@ -1291,6 +1299,15 @@ opt_criterion(40, "compiler mismatches"). build_priority(Package, Priority) }. +opt_criterion(39, "compiler mismatches that are not from CLI"). +#minimize{ 0@239: #true }. +#minimize{ 0@39: #true }. +#minimize{ + 1@39+Priority,Package,Dependency + : compiler_mismatch_required(Package, Dependency), + build_priority(Package, Priority) +}. + % Try to minimize the number of compiler mismatches in the DAG. opt_criterion(35, "OS mismatches"). #minimize{ 0@235: #true }. diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py index fd8baf85226..b943fad7555 100644 --- a/lib/spack/spack/test/concretize.py +++ b/lib/spack/spack/test/concretize.py @@ -352,6 +352,17 @@ def test_concretize_propagate_compiler_flag_not_passed_to_dependent(self): assert set(spec.compiler_flags["cflags"]) == set(["-g"]) assert spec.satisfies("^openblas cflags='-O3'") + def test_mixing_compilers_only_affects_subdag(self): + spack.config.set("packages:all:compiler", ["clang", "gcc"]) + spec = Spec("dt-diamond%gcc ^dt-diamond-bottom%clang").concretized() + for dep in spec.traverse(): + assert ("%clang" in dep) == (dep.name == "dt-diamond-bottom") + + def test_compiler_inherited_upwards(self): + spec = Spec("dt-diamond ^dt-diamond-bottom%clang").concretized() + for dep in spec.traverse(): + assert "%clang" in dep + def test_architecture_inheritance(self): """test_architecture_inheritance is likely to fail with an UnavailableCompilerVersionError if the architecture is concretized From 22c2f3fe896b4647016199d7e16df133cd43029b Mon Sep 17 00:00:00 2001 From: Greg Becker Date: Sun, 6 Nov 2022 16:44:11 -0800 Subject: [PATCH 381/442] improve error message for dependency on nonexistant compiler (#32084) --- lib/spack/spack/solver/concretize.lp | 37 +++++++++++++++++++--------- 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/lib/spack/spack/solver/concretize.lp b/lib/spack/spack/solver/concretize.lp index a06d57ae10e..af5dffbc8c8 100644 --- a/lib/spack/spack/solver/concretize.lp +++ b/lib/spack/spack/solver/concretize.lp @@ -75,7 +75,8 @@ version_declared(Package, Version, Weight) :- version_declared(Package, Version, :- version_declared(Package, Version, Weight, "installed"), version(Package, Version), version_weight(Package, Weight), - not hash(Package, _). + not hash(Package, _), + internal_error("Reuse version weight used for built package"). % versions are declared w/priority -- declared with priority implies declared version_declared(Package, Version) :- version_declared(Package, Version, _). @@ -121,19 +122,22 @@ possible_version_weight(Package, Weight) :- version(Package, Version), version_weight(Package, Weight), version_declared(Package, Version, Weight, "external"), - not external(Package). + not external(Package), + internal_error("External weight used for built package"). % we can't use a weight from an installed spec if we are building it % and vice-versa :- version(Package, Version), version_weight(Package, Weight), version_declared(Package, Version, Weight, "installed"), - build(Package). + build(Package), + internal_error("Reuse version weight used for build package"). :- version(Package, Version), version_weight(Package, Weight), not version_declared(Package, Version, Weight, "installed"), - not build(Package). + not build(Package), + internal_error("Build version weight used for reused package"). 1 { version_weight(Package, Weight) : version_declared(Package, Version, Weight) } 1 :- version(Package, Version), @@ -197,12 +201,14 @@ attr(Name, A1, A2, A3, A4) :- impose(ID), imposed_constraint(ID, Name, A1, A2, A % we cannot have additional variant values when we are working with concrete specs :- node(Package), hash(Package, Hash), variant_value(Package, Variant, Value), - not imposed_constraint(Hash, "variant_value", Package, Variant, Value). + not imposed_constraint(Hash, "variant_value", Package, Variant, Value), + internal_error("imposed hash without imposing all variant values"). % we cannot have additional flag values when we are working with concrete specs :- node(Package), hash(Package, Hash), node_flag(Package, FlagType, Flag), - not imposed_constraint(Hash, "node_flag", Package, FlagType, Flag). + not imposed_constraint(Hash, "node_flag", Package, FlagType, Flag), + internal_error("imposed hash without imposing all flag values"). #defined condition/2. #defined condition_requirement/3. @@ -837,7 +843,8 @@ os_compatible(OS1, OS3) :- os_compatible(OS1, OS2), os_compatible(OS2, OS3). % for which we can build software. We need a cardinality constraint % since we might have more than one "buildable_os(OS)" fact. :- not 1 { os_compatible(CurrentOS, ReusedOS) : buildable_os(CurrentOS) }, - node_os(Package, ReusedOS). + node_os(Package, ReusedOS), + internal_error("Reused OS incompatible with build OS"). % If an OS is set explicitly respect the value node_os(Package, OS) :- node_os_set(Package, OS), node(Package). @@ -962,10 +969,15 @@ error(2, "'{0}' compiler constraints '%{1}@{2}' and '%{3}@{4}' are incompatible" node_compiler(Package, Compiler) :- node_compiler_version(Package, Compiler, _). % We can't have a compiler be enforced and select the version from another compiler -:- node_compiler(Package, Compiler1), - node_compiler_version(Package, Compiler2, _), - Compiler1 != Compiler2, - internal_error("Mismatch between selected compiler and compiler version"). +error(2, "Cannot concretize {0} with two compilers {1}@{2} and {3}@{4}", Package, C1, V1, C2, V2) + :- node_compiler_version(Package, C1, V1), + node_compiler_version(Package, C2, V2), + (C1, V1) != (C2, V2). + +error(2, "Cannot concretize {0} with two compilers {1} and {2}@{3}", Package, Compiler1, Compiler2, Version) + :- node_compiler(Package, Compiler1), + node_compiler_version(Package, Compiler2, Version), + Compiler1 != Compiler2. % If the compiler of a node cannot be satisfied, raise error(1, "No valid compiler for {0} satisfies '%{1}'", Package, Compiler) @@ -1040,7 +1052,8 @@ compiler_weight(Package, 100) not default_compiler_preference(Compiler, Version, _). % For the time being, be strict and reuse only if the compiler match one we have on the system -:- node_compiler_version(Package, Compiler, Version), not compiler_version(Compiler, Version). +error(2, "Compiler {1}@{2} requested for {0} cannot be found. Set install_missing_compilers:true if intended.", Package, Compiler, Version) + :- node_compiler_version(Package, Compiler, Version), not compiler_version(Compiler, Version). #defined node_compiler_preference/4. #defined default_compiler_preference/3. From f3db624b86fc6b746a74dd7f042745e040312fed Mon Sep 17 00:00:00 2001 From: Greg Becker Date: Sun, 6 Nov 2022 16:45:38 -0800 Subject: [PATCH 382/442] package preferences: allow specs to be configured buildable when their virtuals are not (#18269) * respect spec buildable that overrides virtual buildable --- lib/spack/spack/package_prefs.py | 18 +++++++++--------- lib/spack/spack/test/concretize_preferences.py | 17 +++++++++++++++++ 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/lib/spack/spack/package_prefs.py b/lib/spack/spack/package_prefs.py index 975585ac956..48d1ca129db 100644 --- a/lib/spack/spack/package_prefs.py +++ b/lib/spack/spack/package_prefs.py @@ -195,23 +195,23 @@ def _package(maybe_abstract_spec): def is_spec_buildable(spec): """Return true if the spec is configured as buildable""" - allpkgs = spack.config.get("packages") all_buildable = allpkgs.get("all", {}).get("buildable", True) + so_far = all_buildable # the default "so far" def _package(s): pkg_cls = spack.repo.path.get_pkg_class(s.name) return pkg_cls(s) - # Get the list of names for which all_buildable is overridden - reverse = [ - name + # check whether any providers for this package override the default + if any( + _package(spec).provides(name) and entry.get("buildable", so_far) != so_far for name, entry in allpkgs.items() - if entry.get("buildable", all_buildable) != all_buildable - ] - # Does this spec override all_buildable - spec_reversed = spec.name in reverse or any(_package(spec).provides(name) for name in reverse) - return not all_buildable if spec_reversed else all_buildable + ): + so_far = not so_far + + spec_buildable = allpkgs.get(spec.name, {}).get("buildable", so_far) + return spec_buildable def get_package_dir_permissions(spec): diff --git a/lib/spack/spack/test/concretize_preferences.py b/lib/spack/spack/test/concretize_preferences.py index eb5b0734441..56bda697fce 100644 --- a/lib/spack/spack/test/concretize_preferences.py +++ b/lib/spack/spack/test/concretize_preferences.py @@ -395,6 +395,23 @@ def test_buildable_false_all_true_virtual(self): spec = Spec("mpich") assert spack.package_prefs.is_spec_buildable(spec) + def test_buildable_false_virtual_true_pacakge(self): + conf = syaml.load_config( + """\ +mpi: + buildable: false +mpich: + buildable: true +""" + ) + spack.config.set("packages", conf, scope="concretize") + + spec = Spec("zmpi") + assert not spack.package_prefs.is_spec_buildable(spec) + + spec = Spec("mpich") + assert spack.package_prefs.is_spec_buildable(spec) + def test_config_permissions_from_all(self, configure_permissions): # Although these aren't strictly about concretization, they are # configured in the same file and therefore convenient to test here. From fce7bf179f03466e348075ae27f109187af6f08e Mon Sep 17 00:00:00 2001 From: Greg Becker Date: Sun, 6 Nov 2022 16:47:07 -0800 Subject: [PATCH 383/442] solver setup: extract virtual dependencies from reusable specs (#32434) * extract virtual dependencies from reusable specs * bugfix to avoid establishing new node for virtual --- lib/spack/spack/solver/asp.py | 6 ++++++ lib/spack/spack/test/concretize.py | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/lib/spack/spack/solver/asp.py b/lib/spack/spack/solver/asp.py index f0437b9309c..8c9108fea90 100644 --- a/lib/spack/spack/solver/asp.py +++ b/lib/spack/spack/solver/asp.py @@ -1463,6 +1463,12 @@ class Body(object): if concrete_build_deps or dtype != "build": clauses.append(fn.depends_on(spec.name, dep.name, dtype)) + # Ensure Spack will not coconcretize this with another provider + # for the same virtual + for virtual in dep.package.virtuals_provided: + clauses.append(fn.virtual_node(virtual.name)) + clauses.append(fn.provider(dep.name, virtual.name)) + # imposing hash constraints for all but pure build deps of # already-installed concrete specs. if concrete_build_deps or dspec.deptypes != ("build",): diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py index b943fad7555..ab3337da5e0 100644 --- a/lib/spack/spack/test/concretize.py +++ b/lib/spack/spack/test/concretize.py @@ -1706,6 +1706,28 @@ def test_best_effort_coconcretize_preferences(self, specs, expected_spec, occura counter += 1 assert counter == occurances, concrete_specs + def test_coconcretize_reuse_and_virtuals(self): + import spack.solver.asp + + if spack.config.get("config:concretizer") == "original": + pytest.skip("Original concretizer cannot reuse") + + reusable_specs = [] + for s in ["mpileaks ^mpich", "zmpi"]: + reusable_specs.extend(spack.spec.Spec(s).concretized().traverse(root=True)) + + root_specs = [spack.spec.Spec("mpileaks"), spack.spec.Spec("zmpi")] + + import spack.solver.asp + + with spack.config.override("concretizer:reuse", True): + solver = spack.solver.asp.Solver() + setup = spack.solver.asp.SpackSolverSetup() + result, _, _ = solver.driver.solve(setup, root_specs, reuse=reusable_specs) + + for spec in result.specs: + assert "zmpi" in spec + @pytest.mark.regression("30864") def test_misleading_error_message_on_version(self, mutable_database): # For this bug to be triggered we need a reusable dependency From 4b84cd8af5195c44341c4cecd1dc061ed1790909 Mon Sep 17 00:00:00 2001 From: Greg Becker Date: Sun, 6 Nov 2022 16:49:35 -0800 Subject: [PATCH 384/442] bugfix for matrices with dependencies by hash (#22991) Dependencies specified by hash are unique in Spack in that the abstract specs are created with internal structure. In this case, the constraint generation for spec matrices fails due to flattening the structure. It turns out that the dep_difference method for Spec.constrain does not need to operate on transitive deps to ensure correctness. Removing transitive deps from this method resolves the bug. - [x] Includes regression test --- lib/spack/spack/spec.py | 12 +++++++----- lib/spack/spack/test/spec_list.py | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py index 141f6c4b628..30a67a55a81 100644 --- a/lib/spack/spack/spec.py +++ b/lib/spack/spack/spec.py @@ -3568,7 +3568,9 @@ def _constrain_dependencies(self, other): ) # Update with additional constraints from other spec - for name in other.dep_difference(self): + # operate on direct dependencies only, because a concrete dep + # represented by hash may have structure that needs to be preserved + for name in other.direct_dep_difference(self): dep_spec_copy = other._get_dependency(name) dep_copy = dep_spec_copy.spec deptypes = dep_spec_copy.deptypes @@ -3589,10 +3591,10 @@ def constrained(self, other, deps=True): clone.constrain(other, deps) return clone - def dep_difference(self, other): + def direct_dep_difference(self, other): """Returns dependencies in self that are not in other.""" - mine = set(s.name for s in self.traverse(root=False)) - mine.difference_update(s.name for s in other.traverse(root=False)) + mine = set(dname for dname in self._dependencies) + mine.difference_update(dname for dname in other._dependencies) return mine def _autospec(self, spec_like): @@ -4871,7 +4873,7 @@ def merge_abstract_anonymous_specs(*abstract_specs): merged_spec[name].constrain(current_spec_constraint[name], deps=False) # Update with additional constraints from other spec - for name in current_spec_constraint.dep_difference(merged_spec): + for name in current_spec_constraint.direct_dep_difference(merged_spec): edge = next(iter(current_spec_constraint.edges_to_dependencies(name))) merged_spec._add_dependency(edge.spec.copy(), edge.deptypes) diff --git a/lib/spack/spack/test/spec_list.py b/lib/spack/spack/test/spec_list.py index 487417dff10..8923f6e1f68 100644 --- a/lib/spack/spack/test/spec_list.py +++ b/lib/spack/spack/test/spec_list.py @@ -200,3 +200,22 @@ def test_spec_list_matrix_exclude(self, mock_packages): ] speclist = SpecList("specs", matrix) assert len(speclist.specs) == 1 + + @pytest.mark.regression("22991") + def test_spec_list_constraints_with_structure( + self, mock_packages, mock_fetch, install_mockery + ): + # Setup by getting hash and installing package with dep + libdwarf_spec = Spec("libdwarf").concretized() + libdwarf_spec.package.do_install() + + # Create matrix + matrix = { + "matrix": [["mpileaks"], ["^callpath"], ["^libdwarf/%s" % libdwarf_spec.dag_hash()]] + } + + # ensure the concrete spec was retained in the matrix entry of which + # it is a dependency + speclist = SpecList("specs", [matrix]) + assert len(speclist.specs) == 1 + assert libdwarf_spec in speclist.specs[0] From f8e4ad5209af8aa04bf10ef506cd2b8e8832180d Mon Sep 17 00:00:00 2001 From: Tim Haines Date: Mon, 7 Nov 2022 05:23:10 -0600 Subject: [PATCH 385/442] elfutils: add version 0.188 (#33715) --- var/spack/repos/builtin/packages/elfutils/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/elfutils/package.py b/var/spack/repos/builtin/packages/elfutils/package.py index a94505d67d8..b8909e88cb6 100644 --- a/var/spack/repos/builtin/packages/elfutils/package.py +++ b/var/spack/repos/builtin/packages/elfutils/package.py @@ -24,6 +24,7 @@ class Elfutils(AutotoolsPackage, SourcewarePackage): maintainers = ["mwkrentel"] + version("0.188", sha256="fb8b0e8d0802005b9a309c60c1d8de32dd2951b56f0c3a3cb56d21ce01595dff") version("0.187", sha256="e70b0dfbe610f90c4d1fe0d71af142a4e25c3c4ef9ebab8d2d72b65159d454c8") version("0.186", sha256="7f6fb9149b1673d38d9178a0d3e0fb8a1ec4f53a9f4c2ff89469609879641177") version("0.185", sha256="dc8d3e74ab209465e7f568e1b3bb9a5a142f8656e2b57d10049a73da2ae6b5a6") From e045dabb3afbc6b2af78fe7deeb92d0fe995c814 Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Mon, 7 Nov 2022 13:50:38 +0100 Subject: [PATCH 386/442] archspec: update version, translate renamed uarchs (#33556) * Update archspec version * Add a translation table from old names --- lib/spack/external/__init__.py | 2 +- lib/spack/external/archspec/cpu/detect.py | 34 ++- .../archspec/json/cpu/microarchitectures.json | 263 +++++++++++++++++- lib/spack/spack/target.py | 13 + 4 files changed, 288 insertions(+), 24 deletions(-) diff --git a/lib/spack/external/__init__.py b/lib/spack/external/__init__.py index bcb9ed9becc..89928fae59c 100644 --- a/lib/spack/external/__init__.py +++ b/lib/spack/external/__init__.py @@ -18,7 +18,7 @@ * Homepage: https://pypi.python.org/pypi/archspec * Usage: Labeling, comparison and detection of microarchitectures -* Version: 0.1.4 (commit e2cfdc266174488dee78b8c9058e36d60dc1b548) +* Version: 0.2.0 (commit 77640e572725ad97f18e63a04857155752ace045) argparse -------- diff --git a/lib/spack/external/archspec/cpu/detect.py b/lib/spack/external/archspec/cpu/detect.py index 3df04585c70..a7cc4481f63 100644 --- a/lib/spack/external/archspec/cpu/detect.py +++ b/lib/spack/external/archspec/cpu/detect.py @@ -132,9 +132,15 @@ def sysctl(*args): "model name": sysctl("-n", "machdep.cpu.brand_string"), } else: - model = ( - "m1" if "Apple" in sysctl("-n", "machdep.cpu.brand_string") else "unknown" - ) + model = "unknown" + model_str = sysctl("-n", "machdep.cpu.brand_string").lower() + if "m2" in model_str: + model = "m2" + elif "m1" in model_str: + model = "m1" + elif "apple" in model_str: + model = "m1" + info = { "vendor_id": "Apple", "flags": [], @@ -322,14 +328,26 @@ def compatibility_check_for_aarch64(info, target): features = set(info.get("Features", "").split()) vendor = info.get("CPU implementer", "generic") + # At the moment it's not clear how to detect compatibility with + # a specific version of the architecture + if target.vendor == "generic" and target.name != "aarch64": + return False + arch_root = TARGETS[basename] - return ( - (target == arch_root or arch_root in target.ancestors) - and target.vendor in (vendor, "generic") - # On macOS it seems impossible to get all the CPU features with syctl info - and (target.features.issubset(features) or platform.system() == "Darwin") + arch_root_and_vendor = arch_root == target.family and target.vendor in ( + vendor, + "generic", ) + # On macOS it seems impossible to get all the CPU features + # with syctl info, but for ARM we can get the exact model + if platform.system() == "Darwin": + model_key = info.get("model", basename) + model = TARGETS[model_key] + return arch_root_and_vendor and (target == model or target in model.ancestors) + + return arch_root_and_vendor and target.features.issubset(features) + @compatibility_check(architecture_family="riscv64") def compatibility_check_for_riscv64(info, target): diff --git a/lib/spack/external/archspec/json/cpu/microarchitectures.json b/lib/spack/external/archspec/json/cpu/microarchitectures.json index 308f0e51525..15d32e9fa04 100644 --- a/lib/spack/external/archspec/json/cpu/microarchitectures.json +++ b/lib/spack/external/archspec/json/cpu/microarchitectures.json @@ -85,7 +85,7 @@ "intel": [ { "versions": ":", - "name": "x86-64", + "name": "pentium4", "flags": "-march={name} -mtune=generic" } ], @@ -2093,8 +2093,163 @@ ] } }, - "thunderx2": { + "armv8.1a": { "from": ["aarch64"], + "vendor": "generic", + "features": [], + "compilers": { + "gcc": [ + { + "versions": "5:", + "flags": "-march=armv8.1-a -mtune=generic" + } + ], + "clang": [ + { + "versions": ":", + "flags": "-march=armv8.1-a -mtune=generic" + } + ], + "apple-clang": [ + { + "versions": ":", + "flags": "-march=armv8.1-a -mtune=generic" + } + ], + "arm": [ + { + "versions": ":", + "flags": "-march=armv8.1-a -mtune=generic" + } + ] + } + }, + "armv8.2a": { + "from": ["armv8.1a"], + "vendor": "generic", + "features": [], + "compilers": { + "gcc": [ + { + "versions": "6:", + "flags": "-march=armv8.2-a -mtune=generic" + } + ], + "clang": [ + { + "versions": ":", + "flags": "-march=armv8.2-a -mtune=generic" + } + ], + "apple-clang": [ + { + "versions": ":", + "flags": "-march=armv8.2-a -mtune=generic" + } + ], + "arm": [ + { + "versions": ":", + "flags": "-march=armv8.2-a -mtune=generic" + } + ] + } + }, + "armv8.3a": { + "from": ["armv8.2a"], + "vendor": "generic", + "features": [], + "compilers": { + "gcc": [ + { + "versions": "6:", + "flags": "-march=armv8.3-a -mtune=generic" + } + ], + "clang": [ + { + "versions": "6:", + "flags": "-march=armv8.3-a -mtune=generic" + } + ], + "apple-clang": [ + { + "versions": ":", + "flags": "-march=armv8.3-a -mtune=generic" + } + ], + "arm": [ + { + "versions": ":", + "flags": "-march=armv8.3-a -mtune=generic" + } + ] + } + }, + "armv8.4a": { + "from": ["armv8.3a"], + "vendor": "generic", + "features": [], + "compilers": { + "gcc": [ + { + "versions": "8:", + "flags": "-march=armv8.4-a -mtune=generic" + } + ], + "clang": [ + { + "versions": "8:", + "flags": "-march=armv8.4-a -mtune=generic" + } + ], + "apple-clang": [ + { + "versions": ":", + "flags": "-march=armv8.4-a -mtune=generic" + } + ], + "arm": [ + { + "versions": ":", + "flags": "-march=armv8.4-a -mtune=generic" + } + ] + } + }, + "armv8.5a": { + "from": ["armv8.4a"], + "vendor": "generic", + "features": [], + "compilers": { + "gcc": [ + { + "versions": "9:", + "flags": "-march=armv8.5-a -mtune=generic" + } + ], + "clang": [ + { + "versions": "11:", + "flags": "-march=armv8.5-a -mtune=generic" + } + ], + "apple-clang": [ + { + "versions": ":", + "flags": "-march=armv8.5-a -mtune=generic" + } + ], + "arm": [ + { + "versions": ":", + "flags": "-march=armv8.5-a -mtune=generic" + } + ] + } + }, + "thunderx2": { + "from": ["armv8.1a"], "vendor": "Cavium", "features": [ "fp", @@ -2141,7 +2296,7 @@ } }, "a64fx": { - "from": ["aarch64"], + "from": ["armv8.2a"], "vendor": "Fujitsu", "features": [ "fp", @@ -2209,7 +2364,7 @@ ] } }, - "graviton": { + "cortex_a72": { "from": ["aarch64"], "vendor": "ARM", "features": [ @@ -2235,19 +2390,19 @@ }, { "versions": "6:", - "flags" : "-march=armv8-a+crc+crypto -mtune=cortex-a72" + "flags" : "-mcpu=cortex-a72" } ], "clang" : [ { "versions": "3.9:", - "flags" : "-march=armv8-a+crc+crypto" + "flags" : "-mcpu=cortex-a72" } ] } }, - "graviton2": { - "from": ["graviton"], + "neoverse_n1": { + "from": ["cortex_a72", "armv8.2a"], "vendor": "ARM", "features": [ "fp", @@ -2296,7 +2451,7 @@ }, { "versions": "9.0:", - "flags" : "-march=armv8.2-a+fp16+rcpc+dotprod+crypto -mtune=neoverse-n1" + "flags" : "-mcpu=neoverse-n1" } ], "clang" : [ @@ -2307,6 +2462,10 @@ { "versions": "5:", "flags" : "-march=armv8.2-a+fp16+rcpc+dotprod+crypto" + }, + { + "versions": "10:", + "flags" : "-mcpu=neoverse-n1" } ], "arm" : [ @@ -2317,11 +2476,11 @@ ] } }, - "graviton3": { - "from": ["graviton2"], + "neoverse_v1": { + "from": ["neoverse_n1", "armv8.4a"], "vendor": "ARM", "features": [ - "fp", + "fp", "asimd", "evtstrm", "aes", @@ -2384,11 +2543,11 @@ }, { "versions": "9.0:9.9", - "flags" : "-march=armv8.4-a+crypto+rcpc+sha3+sm4+sve+rng+nodotprod -mtune=neoverse-v1" + "flags" : "-mcpu=neoverse-v1" }, { "versions": "10.0:", - "flags" : "-march=armv8.4-a+crypto+rcpc+sha3+sm4+sve+rng+ssbs+i8mm+bf16+nodotprod -mtune=neoverse-v1" + "flags" : "-mcpu=neoverse-v1" } ], @@ -2404,6 +2563,10 @@ { "versions": "11:", "flags" : "-march=armv8.4-a+sve+ssbs+fp16+bf16+crypto+i8mm+rng" + }, + { + "versions": "12:", + "flags" : "-mcpu=neoverse-v1" } ], "arm" : [ @@ -2419,7 +2582,7 @@ } }, "m1": { - "from": ["aarch64"], + "from": ["armv8.4a"], "vendor": "Apple", "features": [ "fp", @@ -2484,6 +2647,76 @@ ] } }, + "m2": { + "from": ["m1", "armv8.5a"], + "vendor": "Apple", + "features": [ + "fp", + "asimd", + "evtstrm", + "aes", + "pmull", + "sha1", + "sha2", + "crc32", + "atomics", + "fphp", + "asimdhp", + "cpuid", + "asimdrdm", + "jscvt", + "fcma", + "lrcpc", + "dcpop", + "sha3", + "asimddp", + "sha512", + "asimdfhm", + "dit", + "uscat", + "ilrcpc", + "flagm", + "ssbs", + "sb", + "paca", + "pacg", + "dcpodp", + "flagm2", + "frint", + "ecv", + "bf16", + "i8mm", + "bti" + ], + "compilers": { + "gcc": [ + { + "versions": "8.0:", + "flags" : "-march=armv8.5-a -mtune=generic" + } + ], + "clang" : [ + { + "versions": "9.0:12.0", + "flags" : "-march=armv8.5-a" + }, + { + "versions": "13.0:", + "flags" : "-mcpu=apple-m1" + } + ], + "apple-clang": [ + { + "versions": "11.0:12.5", + "flags" : "-march=armv8.5-a" + }, + { + "versions": "13.0:", + "flags" : "-mcpu=vortex" + } + ] + } + }, "arm": { "from": [], "vendor": "generic", diff --git a/lib/spack/spack/target.py b/lib/spack/spack/target.py index a85baa4d457..d51ca3aa992 100644 --- a/lib/spack/spack/target.py +++ b/lib/spack/spack/target.py @@ -3,6 +3,7 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) import functools +import warnings import six @@ -34,6 +35,14 @@ def _impl(self, other): return _impl +#: Translation table from archspec deprecated names +_DEPRECATED_ARCHSPEC_NAMES = { + "graviton": "cortex_a72", + "graviton2": "neoverse_n1", + "graviton3": "neoverse_v1", +} + + class Target(object): def __init__(self, name, module_name=None): """Target models microarchitectures and their compatibility. @@ -45,6 +54,10 @@ def __init__(self, name, module_name=None): like Cray (e.g. craype-compiler) """ if not isinstance(name, archspec.cpu.Microarchitecture): + if name in _DEPRECATED_ARCHSPEC_NAMES: + msg = "'target={}' is deprecated, use 'target={}' instead" + name, old_name = _DEPRECATED_ARCHSPEC_NAMES[name], name + warnings.warn(msg.format(old_name, name)) name = archspec.cpu.TARGETS.get(name, archspec.cpu.generic_microarchitecture(name)) self.microarchitecture = name self.module_name = module_name From 2ab974f5301746f20ff19cb991951158a9c498fd Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Mon, 7 Nov 2022 15:38:24 +0100 Subject: [PATCH 387/442] concretizer:unify:true as a default (#31787) `spack env create` enables a view by default (in a weird hidden directory, but well...). This is asking for trouble with the other default of `concretizer:unify:false`, since having different flavors of the same spec in an environment, leads to collision errors when generating the view. A change of defaults would improve user experience: However, `unify:true` makes most sense, since any time the issue is brought up in Slack, the user changes the concretization config, since it wasn't the intention to have different flavors of the same spec, and install times are decreased. Further we improve the docs and drop the duplicate root spec limitation --- etc/spack/defaults/concretizer.yaml | 2 +- lib/spack/docs/environments.rst | 55 ++++++++++++---------- lib/spack/spack/environment/environment.py | 33 ++++++------- lib/spack/spack/test/cmd/env.py | 5 +- 4 files changed, 50 insertions(+), 45 deletions(-) diff --git a/etc/spack/defaults/concretizer.yaml b/etc/spack/defaults/concretizer.yaml index 7311354c28b..f455aa723d9 100644 --- a/etc/spack/defaults/concretizer.yaml +++ b/etc/spack/defaults/concretizer.yaml @@ -33,4 +33,4 @@ concretizer: # environments can always be activated. When "false" perform concretization separately # on each root spec, allowing different versions and variants of the same package in # an environment. - unify: false \ No newline at end of file + unify: true \ No newline at end of file diff --git a/lib/spack/docs/environments.rst b/lib/spack/docs/environments.rst index b417e26f3e1..9f75f789ae8 100644 --- a/lib/spack/docs/environments.rst +++ b/lib/spack/docs/environments.rst @@ -519,27 +519,33 @@ available from the yaml file. ^^^^^^^^^^^^^^^^^^^ Spec concretization ^^^^^^^^^^^^^^^^^^^ -An environment can be concretized in three different modes and the behavior active under any environment -is determined by the ``concretizer:unify`` property. By default specs are concretized *separately*, one after the other: +An environment can be concretized in three different modes and the behavior active under +any environment is determined by the ``concretizer:unify`` configuration option. + +The *default* mode is to unify all specs: .. code-block:: yaml spack: specs: - - hdf5~mpi - hdf5+mpi - zlib@1.2.8 concretizer: - unify: false + unify: true -This mode of operation permits to deploy a full software stack where multiple configurations of the same package -need to be installed alongside each other using the best possible selection of transitive dependencies. The downside -is that redundancy of installations is disregarded completely, and thus environments might be more bloated than -strictly needed. In the example above, for instance, if a version of ``zlib`` newer than ``1.2.8`` is known to Spack, -then it will be used for both ``hdf5`` installations. +This means that any package in the environment corresponds to a single concrete spec. In +the above example, when ``hdf5`` depends down the line of ``zlib``, it is required to +take ``zlib@1.2.8`` instead of a newer version. This mode of concretization is +particularly useful when environment views are used: if every package occurs in +only one flavor, it is usually possible to merge all install directories into a view. -If redundancy of the environment is a concern, Spack provides a way to install it *together where possible*, -i.e. trying to maximize reuse of dependencies across different specs: +A downside of unified concretization is that it can be overly strict. For example, a +concretization error would happen when both ``hdf5+mpi`` and ``hdf5~mpi`` are specified +in an environment. + +The second mode is to *unify when possible*: this makes concretization of root specs +more independendent. Instead of requiring reuse of dependencies across different root +specs, it is only maximized: .. code-block:: yaml @@ -551,26 +557,27 @@ i.e. trying to maximize reuse of dependencies across different specs: concretizer: unify: when_possible -Also in this case Spack allows having multiple configurations of the same package, but privileges the reuse of -specs over other factors. Going back to our example, this means that both ``hdf5`` installations will use -``zlib@1.2.8`` as a dependency even if newer versions of that library are available. -Central installations done at HPC centers by system administrators or user support groups are a common case -that fits either of these two modes. +This means that both ``hdf5`` installations will use ``zlib@1.2.8`` as a dependency even +if newer versions of that library are available. -Environments can also be configured to concretize all the root specs *together*, in a self-consistent way, to -ensure that each package in the environment comes with a single configuration: +The third mode of operation is to concretize root specs entirely independently by +disabling unified concretization: .. code-block:: yaml spack: specs: + - hdf5~mpi - hdf5+mpi - zlib@1.2.8 concretizer: - unify: true + unify: false -This mode of operation is usually what is required by software developers that want to deploy their development -environment and have a single view of it in the filesystem. +In this example ``hdf5`` is concretized separately, and does not consider ``zlib@1.2.8`` +as a constraint or preference. Instead, it will take the latest possible version. + +The last two concretization options are typically useful for system administrators and +user support groups providing a large software stack for their HPC center. .. note:: @@ -581,10 +588,10 @@ environment and have a single view of it in the filesystem. .. admonition:: Re-concretization of user specs - When concretizing specs *together* or *together where possible* the entire set of specs will be + When using *unified* concretization (when possible), the entire set of specs will be re-concretized after any addition of new user specs, to ensure that - the environment remains consistent / minimal. When instead the specs are concretized - separately only the new specs will be re-concretized after any addition. + the environment remains consistent / minimal. When instead unified concretization is + disabled, only the new specs will be concretized after any addition. ^^^^^^^^^^^^^ Spec Matrices diff --git a/lib/spack/spack/environment/environment.py b/lib/spack/spack/environment/environment.py index 44d67854569..0265d68a350 100644 --- a/lib/spack/spack/environment/environment.py +++ b/lib/spack/spack/environment/environment.py @@ -1322,30 +1322,25 @@ def _concretize_together(self, tests=False): if user_specs_did_not_change: return [] - # Check that user specs don't have duplicate packages - counter = collections.defaultdict(int) - for user_spec in self.user_specs: - counter[user_spec.name] += 1 - - duplicates = [] - for name, count in counter.items(): - if count > 1: - duplicates.append(name) - - if duplicates: - msg = ( - "environment that are configured to concretize specs" - " together cannot contain more than one spec for each" - " package [{0}]".format(", ".join(duplicates)) - ) - raise SpackEnvironmentError(msg) - # Proceed with concretization self.concretized_user_specs = [] self.concretized_order = [] self.specs_by_hash = {} - concrete_specs = spack.concretize.concretize_specs_together(*self.user_specs, tests=tests) + try: + concrete_specs = spack.concretize.concretize_specs_together( + *self.user_specs, tests=tests + ) + except spack.error.UnsatisfiableSpecError as e: + # "Enhance" the error message for multiple root specs, suggest a less strict + # form of concretization. + if len(self.user_specs) > 1: + e.message += ( + ". Consider setting `concretizer:unify` to `when_possible` " + "or `false` to relax the concretizer strictness." + ) + raise + concretized_specs = [x for x in zip(self.user_specs, concrete_specs)] for abstract, concrete in concretized_specs: self._add_concrete_spec(abstract, concrete) diff --git a/lib/spack/spack/test/cmd/env.py b/lib/spack/spack/test/cmd/env.py index 6257431ee9c..801ff04669e 100644 --- a/lib/spack/spack/test/cmd/env.py +++ b/lib/spack/spack/test/cmd/env.py @@ -18,6 +18,7 @@ import spack.cmd.env import spack.environment as ev import spack.environment.shell +import spack.error import spack.modules import spack.paths import spack.repo @@ -2403,7 +2404,9 @@ def test_duplicate_packages_raise_when_concretizing_together(): e.add("mpileaks~opt") e.add("mpich") - with pytest.raises(ev.SpackEnvironmentError, match=r"cannot contain more"): + with pytest.raises( + spack.error.UnsatisfiableSpecError, match=r"relax the concretizer strictness" + ): e.concretize() From 9dcd4fac15ea91d678c81b330ae4c579200bf311 Mon Sep 17 00:00:00 2001 From: "Adam J. Stewart" Date: Mon, 7 Nov 2022 06:43:37 -0800 Subject: [PATCH 388/442] py-modin: add new package (#33724) Co-authored-by: adamjstewart --- .../repos/builtin/packages/npm/package.py | 1 + .../repos/builtin/packages/py-dask/package.py | 26 +++--- .../builtin/packages/py-modin/package.py | 46 ++++++++++ .../repos/builtin/packages/py-ray/package.py | 88 ++++++++++++------- 4 files changed, 119 insertions(+), 42 deletions(-) create mode 100644 var/spack/repos/builtin/packages/py-modin/package.py diff --git a/var/spack/repos/builtin/packages/npm/package.py b/var/spack/repos/builtin/packages/npm/package.py index a6898bcba98..3910a0142e0 100644 --- a/var/spack/repos/builtin/packages/npm/package.py +++ b/var/spack/repos/builtin/packages/npm/package.py @@ -25,6 +25,7 @@ class Npm(Package): version("3.10.5", sha256="ff019769e186152098841c1fa6325e5a79f7903a45f13bd0046a4dc8e63f845f") depends_on("node-js", type=("build", "run")) + depends_on("libvips") # npm 6.13.4 ships with node-gyp 5.0.5, which contains several Python 3 # compatibility issues on macOS. Manually update to node-gyp 6.0.1 for diff --git a/var/spack/repos/builtin/packages/py-dask/package.py b/var/spack/repos/builtin/packages/py-dask/package.py index c28a8b57479..5e117ceb108 100644 --- a/var/spack/repos/builtin/packages/py-dask/package.py +++ b/var/spack/repos/builtin/packages/py-dask/package.py @@ -138,18 +138,20 @@ class PyDask(PythonPackage): # Requirements for dask.distributed depends_on("py-dill", type=("build", "run"), when="@:0.7.5 +distributed") depends_on("py-pyzmq", type=("build", "run"), when="@:0.7.5 +distributed") - depends_on("py-distributed", type=("build", "run"), when="@0.8.2: +distributed") - depends_on("py-distributed@1.9:", type=("build", "run"), when="@0.9.0: +distributed") - depends_on("py-distributed@1.10:", type=("build", "run"), when="@0.10.0: +distributed") - depends_on("py-distributed@1.14:", type=("build", "run"), when="@0.12.0: +distributed") - depends_on("py-distributed@1.15:", type=("build", "run"), when="@0.13.0: +distributed") - depends_on("py-distributed@1.16:", type=("build", "run"), when="@0.14.1: +distributed") - depends_on("py-distributed@1.20:", type=("build", "run"), when="@0.16.0: +distributed") - depends_on("py-distributed@1.21:", type=("build", "run"), when="@0.17.0: +distributed") - depends_on("py-distributed@1.22:", type=("build", "run"), when="@0.18.0: +distributed") - depends_on("py-distributed@2.0:", type=("build", "run"), when="@2.0.0: +distributed") - depends_on("py-distributed@2020.12.0:", type=("build", "run"), when="@2020.12.0: +distributed") - depends_on("py-distributed@2021.6.2:", type=("build", "run"), when="@2021.6.2: +distributed") + depends_on("py-distributed@:2021.8.0", type=("build", "run"), when="@0.8.2: +distributed") + depends_on("py-distributed@1.9:2021.8.0", type=("build", "run"), when="@0.9.0: +distributed") + depends_on("py-distributed@1.10:2021.8.0", type=("build", "run"), when="@0.10.0: +distributed") + depends_on("py-distributed@1.14:2021.8.0", type=("build", "run"), when="@0.12.0: +distributed") + depends_on("py-distributed@1.15:2021.8.0", type=("build", "run"), when="@0.13.0: +distributed") + depends_on("py-distributed@1.16:2021.8.0", type=("build", "run"), when="@0.14.1: +distributed") + depends_on("py-distributed@1.20:2021.8.0", type=("build", "run"), when="@0.16.0: +distributed") + depends_on("py-distributed@1.21:2021.8.0", type=("build", "run"), when="@0.17.0: +distributed") + depends_on("py-distributed@1.22:2021.8.0", type=("build", "run"), when="@0.18.0: +distributed") + depends_on("py-distributed@2.0:2021.8.0", type=("build", "run"), when="@2.0.0: +distributed") + depends_on( + "py-distributed@2020.12.0:2021.8.0", type=("build", "run"), when="@2020.12.0: +distributed" + ) + depends_on("py-distributed@2021.6.2", type=("build", "run"), when="@2021.6.2 +distributed") # Requirements for dask.diagnostics depends_on("py-bokeh@1.0.0:", type=("build", "run"), when="@2.0.0: +diagnostics") diff --git a/var/spack/repos/builtin/packages/py-modin/package.py b/var/spack/repos/builtin/packages/py-modin/package.py new file mode 100644 index 00000000000..14bfdce366d --- /dev/null +++ b/var/spack/repos/builtin/packages/py-modin/package.py @@ -0,0 +1,46 @@ +# 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 PyModin(PythonPackage): + """Modin: Make your pandas code run faster by changing one line of code.""" + + homepage = "https://github.com/modin-project/modin" + pypi = "modin/modin-0.16.2.tar.gz" + + version("0.16.2", sha256="8e3f4cb478ae08dcc71b5a345781d57f29d6b95bc6ce1dc5c14d597a382f1354") + + variant( + "engine", + default="ray", + values=["ray", "dask", "python", "native"], + description="Default distribution engine. All engines are installed and " + "functional as long as dependencies are found at run-time", + ) + + depends_on("python@3.6:", type=("build", "run")) + depends_on("py-setuptools", type="build") + depends_on("py-pandas@1.5.1", when="^python@3.8:", type=("build", "run")) + depends_on("py-pandas@1.1.5", when="^python@:3.7", type=("build", "run")) + depends_on("py-packaging", type=("build", "run")) + depends_on("py-numpy@1.18.5:", type=("build", "run")) + depends_on("py-fsspec", type=("build", "run")) + depends_on("py-psutil", type=("build", "run")) + + with when("engine=ray"): + depends_on("py-ray@1.4:+default", type=("build", "run")) + depends_on("py-pyarrow@4.0.1:", type=("build", "run")) + depends_on("py-redis@3.5:3", type=("build", "run")) + + with when("engine=dask"): + depends_on("py-dask@2.22:", type=("build", "run")) + depends_on("py-distributed@2.22:", type=("build", "run")) + depends_on("py-pickle5", when="^python@:3.7", type=("build", "run")) + + def setup_run_environment(self, env): + # modin/config/envvars.py + env.set("MODIN_ENGINE", self.spec.variants["engine"].value) diff --git a/var/spack/repos/builtin/packages/py-ray/package.py b/var/spack/repos/builtin/packages/py-ray/package.py index 3f6de85cdbd..a7b07f6f190 100644 --- a/var/spack/repos/builtin/packages/py-ray/package.py +++ b/var/spack/repos/builtin/packages/py-ray/package.py @@ -8,48 +8,76 @@ class PyRay(PythonPackage): - """A system for parallel and distributed Python that unifies the ML - ecosystem.""" + """Ray provides a simple, universal API for building distributed applications.""" homepage = "https://github.com/ray-project/ray" url = "https://github.com/ray-project/ray/archive/ray-0.8.7.tar.gz" + version("2.0.1", sha256="b8b2f0a99d2ac4c001ff11c78b4521b217e2a02df95fb6270fd621412143f28b") version("0.8.7", sha256="2df328f1bcd3eeb4fa33119142ea0d669396f4ab2a3e78db90178757aa61534b") - build_directory = "python" + variant("default", default=False, description="Install default extras", when="@2.0.1") - depends_on("python@3.6:3.8", type=("build", "run")) - depends_on("bazel@3.2.0", type="build") - depends_on("py-setuptools", type="build") - depends_on("py-cython@0.29.14:", type="build") - depends_on("py-wheel", type="build") + depends_on("python@3.6:3.10", when="@2.0.1", type=("build", "run")) + depends_on("python@3.6:3.8", when="@0.8.7", type=("build", "run")) + depends_on("bazel@4.2.2", when="@2.0.1", type="build") + depends_on("bazel@3.2.0", when="@0.8.7", type="build") depends_on("npm", type="build") - depends_on("py-aiohttp", type=("build", "run")) - depends_on("py-aioredis", type=("build", "run")) - depends_on("py-click@7.0:", type=("build", "run")) - depends_on("py-colorama", type=("build", "run")) - depends_on("py-colorful", type=("build", "run")) + depends_on("py-setuptools", type="build") + depends_on("py-cython@0.29.26:", when="@2.0.1", type="build") + depends_on("py-cython@0.29.14:", when="@0.8.7", type="build") + depends_on("py-attrs", when="@2.0.1", type=("build", "run")) + depends_on("py-click@7:8.0.4", when="@2.0.1", type=("build", "run")) + depends_on("py-click@7.0:", when="@0.8.7", type=("build", "run")) + depends_on("py-dataclasses", when="@2.0.1 ^python@:3.6", type=("build", "run")) depends_on("py-filelock", type=("build", "run")) - depends_on("py-google", type=("build", "run")) - depends_on("py-gpustat", type=("build", "run")) - depends_on("py-grpcio@1.28.1:", type=("build", "run")) + depends_on("py-grpcio@1.32:1.43.0", when="@2.0.1 ^python@:3.9", type=("build", "run")) + depends_on("py-grpcio@1.42:1.43.0", when="@2.0.1 ^python@3.10:", type=("build", "run")) + depends_on("py-grpcio@1.28.1:", when="@0.8.7", type=("build", "run")) depends_on("py-jsonschema", type=("build", "run")) - depends_on("py-msgpack@1.0:1", type=("build", "run")) - depends_on("py-numpy@1.16:", type=("build", "run")) - depends_on("py-protobuf@3.8.0:", type=("build", "run")) - depends_on("py-py-spy@0.2.0:", type=("build", "run")) + depends_on("py-msgpack@1", type=("build", "run")) + depends_on("py-numpy@1.16:", when="^python@:3.8", type=("build", "run")) + depends_on("py-numpy@1.19.3:", when="^python@3.9:", type=("build", "run")) + depends_on("py-protobuf@3.15.3:3", when="@2.0.1", type=("build", "run")) + depends_on("py-protobuf@3.8.0:", when="@0.8.7", type=("build", "run")) depends_on("py-pyyaml", type=("build", "run")) + depends_on("py-frozenlist", when="@2.0.1", type=("build", "run")) depends_on("py-requests", type=("build", "run")) - depends_on("py-redis@3.3.2:3.4", type=("build", "run")) - depends_on("py-opencensus", type=("build", "run")) - depends_on("py-prometheus-client@0.7.1:", type=("build", "run")) - # If not guarded by SKIP_THIRDPARTY_INSTALL, those dependencies - # would be automatically installed via pip by the setup.py script. - depends_on("py-setproctitle", type=("build", "run")) - depends_on("py-psutil", type=("build", "run")) - # If not detected during install, the following dependency would - # be automatically downloaded and installed by the setup.py script. - depends_on("py-pickle5", when="^python@:3.8.1", type=("build", "run")) + depends_on("py-typing-extensions", when="@2.0.1 ^python@:3.7", type=("build", "run")) + depends_on("py-virtualenv", when="@2.0.1", type=("build", "run")) + + with when("+default"): + depends_on("py-aiohttp@3.7:", type=("build", "run")) + depends_on("py-aiohttp-cors", type=("build", "run")) + depends_on("py-colorful", type=("build", "run")) + depends_on("py-py-spy@0.2:", type=("build", "run")) + depends_on("py-gpustat@1:", type=("build", "run")) + depends_on("py-opencensus", type=("build", "run")) + depends_on("py-pydantic", type=("build", "run")) + depends_on("py-prometheus-client@0.7.1:0.13", type=("build", "run")) + depends_on("py-smart-open", type=("build", "run")) + + # Historical dependencies + with when("@0.8.7"): + depends_on("py-aiohttp", type=("build", "run")) + depends_on("py-aioredis", type=("build", "run")) + depends_on("py-colorama", type=("build", "run")) + depends_on("py-colorful", type=("build", "run")) + depends_on("py-google", type=("build", "run")) + depends_on("py-gpustat", type=("build", "run")) + depends_on("py-py-spy@0.2.0:", type=("build", "run")) + depends_on("py-redis@3.3.2:3.4", type=("build", "run")) + depends_on("py-opencensus", type=("build", "run")) + depends_on("py-prometheus-client@0.7.1:", type=("build", "run")) + # If not guarded by SKIP_THIRDPARTY_INSTALL, those dependencies + # would be automatically installed via pip by the setup.py script. + depends_on("py-setproctitle", type=("build", "run")) + depends_on("py-psutil", type=("build", "run")) + # If not detected during install, the following dependency would + # be automatically downloaded and installed by the setup.py script. + depends_on("py-pickle5", when="^python@:3.8.1", type=("build", "run")) + + build_directory = "python" def setup_build_environment(self, env): env.set("SKIP_THIRDPARTY_INSTALL", "1") From 492525fda5e6f7a49a371bcde11412d85eba9102 Mon Sep 17 00:00:00 2001 From: Michael Kuhn Date: Mon, 7 Nov 2022 15:45:50 +0100 Subject: [PATCH 389/442] socat: new package (#33713) --- .../repos/builtin/packages/socat/package.py | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 var/spack/repos/builtin/packages/socat/package.py diff --git a/var/spack/repos/builtin/packages/socat/package.py b/var/spack/repos/builtin/packages/socat/package.py new file mode 100644 index 00000000000..3a01e8e5dd4 --- /dev/null +++ b/var/spack/repos/builtin/packages/socat/package.py @@ -0,0 +1,31 @@ +# 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 Socat(AutotoolsPackage): + """socat is a relay for bidirectional data transfer between two independent + data channels. Each of these data channels may be a file, pipe, device + (serial line etc. or a pseudo terminal), a socket (UNIX, IP4, IP6 - raw, + UDP, TCP), an SSL socket, proxy CONNECT connection, a file descriptor + (stdin etc.), the GNU line editor (readline), a program, or a combination + of two of these. These modes include generation of "listening" sockets, + named pipes, and pseudo terminals.""" + + homepage = "http://www.dest-unreach.org/socat/" + url = "http://www.dest-unreach.org/socat/download/socat-1.7.4.4.tar.bz2" + + maintainers = ["michaelkuhn"] + + version("1.7.4.4", sha256="fbd42bd2f0e54a3af6d01bdf15385384ab82dbc0e4f1a5e153b3e0be1b6380ac") + + depends_on("openssl") + depends_on("readline") + depends_on("ncurses") + + def configure_args(self): + args = ["--disable-libwrap"] + return args From 74c3fbdf87fa685cc915a1a07175849c7abe386f Mon Sep 17 00:00:00 2001 From: Sergey Kosukhin Date: Mon, 7 Nov 2022 15:49:55 +0100 Subject: [PATCH 390/442] netcdf-c: add variant optimize (#33642) --- var/spack/repos/builtin/packages/netcdf-c/package.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/var/spack/repos/builtin/packages/netcdf-c/package.py b/var/spack/repos/builtin/packages/netcdf-c/package.py index 32071637474..de3f8950cca 100644 --- a/var/spack/repos/builtin/packages/netcdf-c/package.py +++ b/var/spack/repos/builtin/packages/netcdf-c/package.py @@ -77,6 +77,7 @@ class NetcdfC(AutotoolsPackage): variant("jna", default=False, description="Enable JNA support") variant("fsync", default=False, description="Enable fsync support") variant("zstd", default=True, description="Enable ZStandard compression", when="@4.9.0:") + variant("optimize", default=True, description="Enable -O2 for a more optimized lib") # It's unclear if cdmremote can be enabled if '--enable-netcdf-4' is passed # to the configure script. Since netcdf-4 support is mandatory we comment @@ -161,6 +162,9 @@ def configure_args(self): "--enable-netcdf-4", ] + if "+optimize" in self.spec: + cflags.append("-O2") + config_args.extend(self.enable_or_disable("fsync")) # The flag was introduced in version 4.3.1 @@ -169,9 +173,7 @@ def configure_args(self): config_args += self.enable_or_disable("shared") - if "~shared" in self.spec or "+pic" in self.spec: - # We don't have shared libraries but we still want it to be - # possible to use this library in shared builds + if "+pic" in self.spec: cflags.append(self.compiler.cc_pic_flag) config_args += self.enable_or_disable("dap") From 1eb35d037820238e00b0f33004012220e3a816e5 Mon Sep 17 00:00:00 2001 From: Axel Huebl Date: Mon, 7 Nov 2022 07:13:17 -0800 Subject: [PATCH 391/442] Doc: `lsb-release` (#32479) Without the `lsb-release` tool installed, Spack cannot identify the Ubuntu/Debian version. --- lib/spack/docs/getting_started.rst | 2 +- lib/spack/docs/tables/system_prerequisites.csv | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/spack/docs/getting_started.rst b/lib/spack/docs/getting_started.rst index f923f4e9da3..1bf99e09b3c 100644 --- a/lib/spack/docs/getting_started.rst +++ b/lib/spack/docs/getting_started.rst @@ -44,7 +44,7 @@ A build matrix showing which packages are working on which systems is shown belo yum install -y epel-release yum update -y yum --enablerepo epel groupinstall -y "Development Tools" - yum --enablerepo epel install -y curl findutils gcc-c++ gcc gcc-gfortran git gnupg2 hostname iproute make patch python3 python3-pip python3-setuptools unzip + yum --enablerepo epel install -y curl findutils gcc-c++ gcc gcc-gfortran git gnupg2 hostname iproute redhat-lsb-core make patch python3 python3-pip python3-setuptools unzip python3 -m pip install boto3 .. tab-item:: macOS Brew diff --git a/lib/spack/docs/tables/system_prerequisites.csv b/lib/spack/docs/tables/system_prerequisites.csv index af8dcafffa6..efca033b620 100644 --- a/lib/spack/docs/tables/system_prerequisites.csv +++ b/lib/spack/docs/tables/system_prerequisites.csv @@ -11,6 +11,7 @@ bzip2, , , Compress/Decompress archives xz, , , Compress/Decompress archives zstd, , Optional, Compress/Decompress archives file, , , Create/Use Buildcaches +lsb-release, , , Linux: identify operating system version gnupg2, , , Sign/Verify Buildcaches git, , , Manage Software Repositories svn, , Optional, Manage Software Repositories From c3851704a205b87244fe157ade895cfc16380377 Mon Sep 17 00:00:00 2001 From: Sajid Ali Date: Mon, 7 Nov 2022 09:20:03 -0600 Subject: [PATCH 392/442] openblas confuses flang/flang-new, so do not set TIME with ~fortran (#33163) Co-authored-by: Harmen Stoppels Co-authored-by: eugeneswalker <38933153+eugeneswalker@users.noreply.github.com> --- var/spack/repos/builtin/packages/openblas/package.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/var/spack/repos/builtin/packages/openblas/package.py b/var/spack/repos/builtin/packages/openblas/package.py index 692718e6cce..e9d3a50d466 100644 --- a/var/spack/repos/builtin/packages/openblas/package.py +++ b/var/spack/repos/builtin/packages/openblas/package.py @@ -382,8 +382,9 @@ def make_defs(self): if "+consistent_fpcsr" in self.spec: make_defs += ["CONSISTENT_FPCSR=1"] - # Flang/f18 does not provide ETIME as an intrinsic - if self.spec.satisfies("%clang"): + # Flang/f18 does not provide ETIME as an intrinsic. + # Do not set TIMER variable if fortran is disabled. + if self.spec.satisfies("+fortran%clang"): make_defs.append("TIMER=INT_CPU_TIME") # Prevent errors in `as` assembler from newer instructions From 476e647c942add4d2cbb7700fecf0f3f5b75fcd8 Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Mon, 7 Nov 2022 07:31:59 -0800 Subject: [PATCH 393/442] GLVis: new versions: v4.1, v4.2 (#33728) --- .../repos/builtin/packages/glvis/package.py | 62 ++++++++++++++----- .../repos/builtin/packages/sdl2/package.py | 5 +- 2 files changed, 50 insertions(+), 17 deletions(-) diff --git a/var/spack/repos/builtin/packages/glvis/package.py b/var/spack/repos/builtin/packages/glvis/package.py index 4f99698123e..3425991a2f1 100644 --- a/var/spack/repos/builtin/packages/glvis/package.py +++ b/var/spack/repos/builtin/packages/glvis/package.py @@ -2,6 +2,9 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) + +import sys + import spack.build_systems.makefile from spack.package import * @@ -13,7 +16,7 @@ class Glvis(MakefilePackage): git = "https://github.com/glvis/glvis.git" tags = ["radiuss"] - maintainers = ["goxberry", "v-dobrev", "tzanio", "tomstitt"] + maintainers = ["v-dobrev", "tzanio", "tomstitt", "goxberry"] # glvis (like mfem) is downloaded from a URL shortener at request # of upstream author Tzanio Kolev . See here: @@ -39,6 +42,20 @@ class Glvis(MakefilePackage): version("develop", branch="master") + version( + "4.2", + sha256="314fb04040cd0a8128d6dac62ba67d7067c2c097364e5747182ee8371049b42a", + url="https://bit.ly/glvis-4-2", + extension=".tar.gz", + ) + + version( + "4.1", + sha256="7542c2942167533eec10d59b8331d18241798bbd86a7efbe51dc479db4127407", + url="https://bit.ly/glvis-4-1", + extension=".tar.gz", + ) + version( "4.0", sha256="68331eaea8b93968ed6bf395388c2730b27bbcb4b7809ce44277726edccd9f08", @@ -83,22 +100,31 @@ class Glvis(MakefilePackage): variant("fonts", default=True, description="Use antialiased fonts via freetype & fontconfig") depends_on("mfem@develop", when="@develop") + depends_on("mfem@4.4.0:", when="@4.2") + depends_on("mfem@4.3.0:", when="@4.1") depends_on("mfem@4.0.0:", when="@4.0") depends_on("mfem@3.4.0", when="@3.4") depends_on("mfem@3.3", when="@3.3") depends_on("mfem@3.2", when="@3.2") depends_on("mfem@3.1", when="@3.1") - depends_on("gl") - depends_on("glu") - depends_on("libx11", when="@:3.5") + with when("@:3"): + depends_on("gl") + depends_on("glu") + depends_on("libx11") - with when("@4.0:,develop"): + with when("@4.0:"): + # On Mac, we use the OpenGL framework + if sys.platform.startswith("linux"): + depends_on("gl") depends_on("sdl2") depends_on("glm") + # On Mac, use external glew, e.g. from Homebrew depends_on("glew") + # On Mac, use external freetype and fontconfig, e.g. from /opt/X11 depends_on("freetype") depends_on("fontconfig") + depends_on("xxd", type="build") with when("+fonts"): depends_on("freetype") @@ -106,7 +132,6 @@ class Glvis(MakefilePackage): depends_on("libpng", when="screenshots=png") depends_on("libtiff", when="screenshots=tiff") - depends_on("uuid", when="platform=linux") class MakefileBuilder(spack.build_systems.makefile.MakefileBuilder): @@ -127,15 +152,20 @@ def common_args(self): "CONFIG_MK={0}".format(self.spec["mfem"].package.config_mk), ] - if self.spec.satisfies("@4.0:") or self.spec.satisfies("@develop"): - # TODO: glu and fontconfig dirs + if self.spec.satisfies("@4.0:"): + # Spack will inject the necessary include dirs and link paths via + # its compiler wrapper, so we can skip them: result += [ - "GLM_DIR={0}".format(spec["glm"].prefix), - "SDL_DIR={0}".format(spec["sdl2"].prefix), - "GLEW_DIR={0}".format(spec["glew"].prefix), - "FREETYPE_DIR={0}".format(spec["freetype"].prefix), - "OPENGL_DIR={0}".format(spec["gl"].home), + "GLM_DIR=", + "SDL_DIR=", + "GLEW_DIR=", + "FREETYPE_DIR=", + "OPENGL_DIR=", ] + # Spack will not inject include dirs like /usr/include/freetype2, + # so we need to do it ourselves: + if spec["freetype"].external: + result += ["GL_OPTS={0}".format(spec["freetype"].headers.cpp_flags)] else: gl_libs = spec["glu"].libs + spec["gl"].libs + spec["libx11"].libs @@ -174,13 +204,13 @@ def fonts_args(self): ] def xwd_args(self): - if self.spec.satisfies("@4.0:") or self.spec.satisfies("@develop"): + if self.spec.satisfies("@4.0:"): return ["GLVIS_USE_LIBPNG=NO", "GLVIS_USE_LIBTIFF=NO"] return ["USE_LIBPNG=NO", "USE_LIBTIFF=NO"] def png_args(self): prefix_args = ["USE_LIBPNG=YES", "USE_LIBTIFF=NO"] - if self.spec.satisfies("@4.0:") or self.spec.satisfies("@develop"): + if self.spec.satisfies("@4.0:"): prefix_args = ["GLVIS_USE_LIBPNG=YES", "GLVIS_USE_LIBTIFF=NO"] libpng = self.spec["libpng"] @@ -191,7 +221,7 @@ def png_args(self): def tiff_args(self): prefix_args = ["USE_LIBPNG=NO", "USE_LIBTIFF=YES"] - if self.spec.satisfies("@4.0:") or self.spec.satisfies("@develop"): + if self.spec.satisfies("@4.0:"): prefix_args = ["GLVIS_USE_LIBPNG=NO", "GLVIS_USE_LIBTIFF=YES"] libtiff = self.spec["libtiff"] diff --git a/var/spack/repos/builtin/packages/sdl2/package.py b/var/spack/repos/builtin/packages/sdl2/package.py index 459fdf178fa..2d01bf89013 100644 --- a/var/spack/repos/builtin/packages/sdl2/package.py +++ b/var/spack/repos/builtin/packages/sdl2/package.py @@ -3,6 +3,8 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import sys + from spack.package import * @@ -22,7 +24,8 @@ class Sdl2(CMakePackage): version("2.0.5", sha256="442038cf55965969f2ff06d976031813de643af9c9edc9e331bd761c242e8785") depends_on("cmake@2.8.5:", type="build") - depends_on("libxext", type="link") + if sys.platform.startswith("linux"): + depends_on("libxext", type="link") def cmake_args(self): return ["-DSSEMATH={0}".format("OFF" if self.spec.target.family == "aarch64" else "ON")] From 47df88404ae2fd1e662660f4f355152645c0490a Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Mon, 7 Nov 2022 16:33:18 +0100 Subject: [PATCH 394/442] Simplify repeated _add_dependency calls for same package (#33732) --- lib/spack/spack/spec.py | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py index 30a67a55a81..ef4c3b7ab08 100644 --- a/lib/spack/spack/spec.py +++ b/lib/spack/spack/spec.py @@ -1558,26 +1558,24 @@ def _set_compiler(self, compiler): def _add_dependency(self, spec, deptypes): """Called by the parser to add another spec as a dependency.""" - if spec.name in self._dependencies: - # allow redundant compatible dependency specifications - # depspec equality checks by name, so we need to check components - # separately to test whether the specs are identical - orig = self._dependencies[spec.name] - for dspec in orig: - if deptypes == dspec.deptypes: - try: - dspec.spec.constrain(spec) - return - except spack.error.UnsatisfiableSpecError: - raise DuplicateDependencyError( - "Cannot depend on incompatible specs '%s' and '%s'" - % (dspec.spec, spec) - ) - else: - raise DuplicateDependencyError("Cannot depend on '%s' twice" % spec) + if spec.name not in self._dependencies: + self.add_dependency_edge(spec, deptypes) + return - # create an edge and add to parent and child - self.add_dependency_edge(spec, deptypes) + # Keep the intersection of constraints when a dependency is added + # multiple times. Currently we only allow identical edge types. + orig = self._dependencies[spec.name] + try: + dspec = next(dspec for dspec in orig if deptypes == dspec.deptypes) + except StopIteration: + raise DuplicateDependencyError("Cannot depend on '%s' twice" % spec) + + try: + dspec.spec.constrain(spec) + except spack.error.UnsatisfiableSpecError: + raise DuplicateDependencyError( + "Cannot depend on incompatible specs '%s' and '%s'" % (dspec.spec, spec) + ) def add_dependency_edge(self, dependency_spec, deptype): """Add a dependency edge to this spec. From 96b8240ea682b3e47000ca47c95d833065a69d4b Mon Sep 17 00:00:00 2001 From: Yang Zongze Date: Mon, 7 Nov 2022 23:44:09 +0800 Subject: [PATCH 395/442] singularity: add new versions (#33462) --- var/spack/repos/builtin/packages/singularity/package.py | 2 ++ var/spack/repos/builtin/packages/singularityce/package.py | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/var/spack/repos/builtin/packages/singularity/package.py b/var/spack/repos/builtin/packages/singularity/package.py index 2d6bf2faecb..26726fd13fb 100644 --- a/var/spack/repos/builtin/packages/singularity/package.py +++ b/var/spack/repos/builtin/packages/singularity/package.py @@ -27,6 +27,8 @@ class Singularity(SingularityBase): maintainers = ["alalazo"] version("master", branch="master") + version("3.8.7", sha256="3329f2e583f84a8343cb2c0380a1d6cbceafae7d1e633b5cbcadf7143eac859b") + version("3.8.6", sha256="bb5a3b7670ac9c7a4b3ce5b2c9f3d6b5be60e21b08d338c9dfdabb7b2a99f528") version("3.8.5", sha256="7fff78b5c07b5d4d08269bd267ac5e994390f933321e54efd6b7c86683153ce4") version("3.8.3", sha256="2e22eb9ee1b73fdd51b8783149f0e4d83c0d2d8a0c1edf6034157d50eeefb835") version("3.8.0", sha256="e9608b0e0a8c805218bbe795e9176484837b2f7fcb95e5469b853b3809a2412e") diff --git a/var/spack/repos/builtin/packages/singularityce/package.py b/var/spack/repos/builtin/packages/singularityce/package.py index 7133febaf64..0ee15ae5a99 100644 --- a/var/spack/repos/builtin/packages/singularityce/package.py +++ b/var/spack/repos/builtin/packages/singularityce/package.py @@ -191,5 +191,10 @@ class Singularityce(SingularityBase): maintainers = ["alalazo"] version("master", branch="master") + version("3.10.3", sha256="f87d8e212ce209c5212d6faf253b97a24b5d0b6e6b17b5e58b316cdda27a332f") + version("3.10.2", sha256="b4f279856ea4bf28a1f34f89320c02b545d6e57d4143679920e1ac4267f540e1") + version("3.10.1", sha256="e3af12edc0260bc3a3a481459a3a4457de9235025e6b37288da80e3cdc011a7a") + version("3.10.0", sha256="5e22e6cdad66c331668f6cff4544c83917bb3db90da3cf92403a394c5bf8cc8f") + version("3.9.9", sha256="1381433d64138c08e93ffacdfb4844e82c2288f1e39a9d2c631a1c4021381f2a") version("3.9.1", sha256="1ba3bb1719a420f48e9b0a6afdb5011f6c786d0f107ef272528c632fff9fd153") version("3.8.0", sha256="5fa2c0e7ef2b814d8aa170826b833f91e5031a85d85cd1292a234e6c55da1be1") From 1dcb5d1fa75476fb4f8744e7f1a5a2512ba1ea93 Mon Sep 17 00:00:00 2001 From: Laura Bellentani Date: Mon, 7 Nov 2022 16:47:07 +0100 Subject: [PATCH 396/442] quantum-espresso: improve concretization for intel libraries (#33312) --- var/spack/repos/builtin/packages/quantum-espresso/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/quantum-espresso/package.py b/var/spack/repos/builtin/packages/quantum-espresso/package.py index 47fb80e6f97..d4454082113 100644 --- a/var/spack/repos/builtin/packages/quantum-espresso/package.py +++ b/var/spack/repos/builtin/packages/quantum-espresso/package.py @@ -73,6 +73,7 @@ class QuantumEspresso(CMakePackage, Package): depends_on("amdfftw+openmp", when="^amdfftw") depends_on("openblas threads=openmp", when="^openblas") depends_on("amdblis threads=openmp", when="^amdblis") + depends_on("intel-mkl threads=openmp", when="^intel-mkl") # Add Cuda Fortran support # depends on NVHPC compiler, not directly on CUDA toolkit From 8fb8381b6f8fd42aa49fd71e14c2c02b145228ba Mon Sep 17 00:00:00 2001 From: "Adam J. Stewart" Date: Mon, 7 Nov 2022 09:21:46 -0800 Subject: [PATCH 397/442] Rust: don't apply constraints to nightly/beta versions (#33723) --- var/spack/repos/builtin/packages/py-tokenizers/package.py | 6 ++++-- var/spack/repos/builtin/packages/rust/package.py | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/var/spack/repos/builtin/packages/py-tokenizers/package.py b/var/spack/repos/builtin/packages/py-tokenizers/package.py index 24befd2986b..d306e57950a 100644 --- a/var/spack/repos/builtin/packages/py-tokenizers/package.py +++ b/var/spack/repos/builtin/packages/py-tokenizers/package.py @@ -21,7 +21,9 @@ class PyTokenizers(PythonPackage): depends_on("py-setuptools", type="build") depends_on("py-setuptools-rust", type="build") - # TODO: This package currently requires internet access to install. - # Also, a nightly or dev version of rust is required to build older versions. + # A nightly or dev version of rust is required to build older versions. # https://github.com/huggingface/tokenizers/issues/176 # https://github.com/PyO3/pyo3/issues/5 + depends_on("rust@nightly", when="@:0.10", type="build") + + # TODO: This package currently requires internet access to install. diff --git a/var/spack/repos/builtin/packages/rust/package.py b/var/spack/repos/builtin/packages/rust/package.py index a17d34e2665..2ffdf495cf1 100644 --- a/var/spack/repos/builtin/packages/rust/package.py +++ b/var/spack/repos/builtin/packages/rust/package.py @@ -54,7 +54,7 @@ class Rust(Package): ) depends_on("python@2.7:", type="build") - depends_on("python@2.7:2.8", when="@:1.43", type="build") + depends_on("python@2.7:2.8", when="@0:1.43", type="build") depends_on("gmake@3.81:", type="build") depends_on("cmake@3.4.3:", type="build") depends_on("ninja", when="@1.48.0:", type="build") @@ -63,7 +63,7 @@ class Rust(Package): depends_on("openssl@:1") depends_on("libssh2") # https://github.com/rust-lang/cargo/issues/10446 - depends_on("libgit2@:1.3", when="@:1.60") + depends_on("libgit2@:1.3", when="@0:1.60") depends_on("libgit2") # Pre-release Versions From a30b60f9a64c302b05505159f1b9d548e7fe5e8a Mon Sep 17 00:00:00 2001 From: Greg Becker Date: Mon, 7 Nov 2022 09:37:03 -0800 Subject: [PATCH 398/442] Apply dev specs for dependencies of roots (#30909) Currently, develop specs that are not roots and are not explicitly listed dependencies of the roots are not applied. - [x] ensure dev specs are applied. Co-authored-by: Todd Gamblin --- lib/spack/spack/solver/asp.py | 49 ++++++++++++++++++++------- lib/spack/spack/test/cmd/dev_build.py | 13 ++++--- 2 files changed, 45 insertions(+), 17 deletions(-) diff --git a/lib/spack/spack/solver/asp.py b/lib/spack/spack/solver/asp.py index 8c9108fea90..68c571e5bb3 100644 --- a/lib/spack/spack/solver/asp.py +++ b/lib/spack/spack/solver/asp.py @@ -102,7 +102,15 @@ def getter(node): ast_sym = ast_getter("symbol", "term") #: Order of precedence for version origins. Topmost types are preferred. -version_origin_fields = ["spec", "external", "packages_yaml", "package_py", "installed"] +version_origin_fields = [ + "spec", + "dev_spec", + "external", + "packages_yaml", + "package_py", + "installed", +] + #: Look up version precedence strings by enum id version_origin_str = {i: name for i, name in enumerate(version_origin_fields)} @@ -1489,7 +1497,7 @@ class Body(object): return clauses - def build_version_dict(self, possible_pkgs, specs): + def build_version_dict(self, possible_pkgs): """Declare any versions in specs not declared in packages.""" self.declared_versions = collections.defaultdict(list) self.possible_versions = collections.defaultdict(set) @@ -1530,6 +1538,8 @@ def key_fn(item): DeclaredVersion(version=ver, idx=idx, origin=version_provenance.packages_yaml) ) + def add_concrete_versions_from_specs(self, specs, origin): + """Add concrete versions to possible versions from lists of CLI/dev specs.""" for spec in specs: for dep in spec.traverse(): if not dep.versions.concrete: @@ -1553,7 +1563,7 @@ def key_fn(item): # about*, add it to the known versions. Use idx=0, which is the # best possible, so they're guaranteed to be used preferentially. self.declared_versions[dep.name].append( - DeclaredVersion(version=dep.version, idx=0, origin=version_provenance.spec) + DeclaredVersion(version=dep.version, idx=0, origin=origin) ) self.possible_versions[dep.name].add(dep.version) @@ -1944,11 +1954,28 @@ def setup(self, driver, specs, reuse=None): # rules to generate an ASP program. self.gen = driver + # Calculate develop specs + # they will be used in addition to command line specs + # in determining known versions/targets/os + dev_specs = () + env = ev.active_environment() + if env: + dev_specs = tuple( + spack.spec.Spec(info["spec"]).constrained( + "dev_path=%s" + % spack.util.path.canonicalize_path(info["path"], default_wd=env.path) + ) + for name, info in env.dev_specs.items() + ) + specs = tuple(specs) # ensure compatible types to add + # get possible compilers self.possible_compilers = self.generate_possible_compilers(specs) # traverse all specs and packages to build dict of possible versions - self.build_version_dict(possible, specs) + self.build_version_dict(possible) + self.add_concrete_versions_from_specs(specs, version_provenance.spec) + self.add_concrete_versions_from_specs(dev_specs, version_provenance.dev_spec) self.gen.h1("Concrete input spec definitions") self.define_concrete_input_specs(specs, possible) @@ -1966,8 +1993,8 @@ def setup(self, driver, specs, reuse=None): # architecture defaults self.platform_defaults() - self.os_defaults(specs) - self.target_defaults(specs) + self.os_defaults(specs + dev_specs) + self.target_defaults(specs + dev_specs) self.virtual_providers() self.provider_defaults() @@ -1984,11 +2011,8 @@ def setup(self, driver, specs, reuse=None): self.target_preferences(pkg) # Inject dev_path from environment - env = ev.active_environment() - if env: - for spec in sorted(specs): - for dep in spec.traverse(): - _develop_specs_from_env(dep, env) + for ds in dev_specs: + self.condition(spack.spec.Spec(ds.name), ds, msg="%s is a develop spec" % ds.name) self.gen.h1("Spec Constraints") self.literal_specs(specs) @@ -2311,8 +2335,7 @@ def _develop_specs_from_env(spec, env): "Internal Error: The dev_path for spec {name} is not connected to a valid environment" "path. Please note that develop specs can only be used inside an environment" "These paths should be the same:\n\tdev_path:{dev_path}\n\tenv_based_path:{env_path}" - ) - error_msg.format(name=spec.name, dev_path=spec.variants["dev_path"], env_path=path) + ).format(name=spec.name, dev_path=spec.variants["dev_path"], env_path=path) assert spec.variants["dev_path"].value == path, error_msg else: diff --git a/lib/spack/spack/test/cmd/dev_build.py b/lib/spack/spack/test/cmd/dev_build.py index cad706e6485..2ffbec8e73c 100644 --- a/lib/spack/spack/test/cmd/dev_build.py +++ b/lib/spack/spack/test/cmd/dev_build.py @@ -254,13 +254,18 @@ def test_dev_build_env_version_mismatch( def test_dev_build_multiple( tmpdir, mock_packages, install_mockery, mutable_mock_env_path, mock_fetch ): - """Test spack install with multiple developer builds""" + """Test spack install with multiple developer builds + + Test that only the root needs to be specified in the environment + Test that versions known only from the dev specs are included in the solve, + even if they come from a non-root + """ # setup dev-build-test-install package for dev build # Wait to concretize inside the environment to set dev_path on the specs; # without the environment, the user would need to set dev_path for both the # root and dependency if they wanted a dev build for both. leaf_dir = tmpdir.mkdir("leaf") - leaf_spec = spack.spec.Spec("dev-build-test-install@0.0.0") + leaf_spec = spack.spec.Spec("dev-build-test-install@1.0.0") leaf_pkg_cls = spack.repo.path.get_pkg_class(leaf_spec.name) with leaf_dir.as_cwd(): with open(leaf_pkg_cls.filename, "w") as f: @@ -283,13 +288,12 @@ def test_dev_build_multiple( """\ env: specs: - - dev-build-test-install@0.0.0 - dev-build-test-dependent@0.0.0 develop: dev-build-test-install: path: %s - spec: dev-build-test-install@0.0.0 + spec: dev-build-test-install@1.0.0 dev-build-test-dependent: spec: dev-build-test-dependent@0.0.0 path: %s @@ -300,6 +304,7 @@ def test_dev_build_multiple( env("create", "test", "./spack.yaml") with ev.read("test"): # Do concretization inside environment for dev info + # These specs are the source of truth to compare against the installs leaf_spec.concretize() root_spec.concretize() From ec055430541680e26f7b9b8088ec12394b8da2db Mon Sep 17 00:00:00 2001 From: Greg Becker Date: Mon, 7 Nov 2022 09:38:51 -0800 Subject: [PATCH 399/442] Bugfix: Compiler bootstrapping for compilers that are independently present in env (#32228) The compiler bootstrapping logic currently does not add a task when the compiler package is already in the install task queue. This causes failures when the compiler package is added without the additional metadata telling the task to update the compilers list. Solution: requeue compilers for bootstrapping when needed, to update `task.compiler` metadata. --- lib/spack/spack/installer.py | 28 +++++++++++++++++++++++++++- lib/spack/spack/test/installer.py | 20 ++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/lib/spack/spack/installer.py b/lib/spack/spack/installer.py index 620f489c775..62770d03491 100644 --- a/lib/spack/spack/installer.py +++ b/lib/spack/spack/installer.py @@ -803,8 +803,34 @@ def _add_bootstrap_compilers(self, compiler, architecture, pkgs, request, all_de """ packages = _packages_needed_to_bootstrap_compiler(compiler, architecture, pkgs) for (comp_pkg, is_compiler) in packages: - if package_id(comp_pkg) not in self.build_tasks: + pkgid = package_id(comp_pkg) + if pkgid not in self.build_tasks: self._add_init_task(comp_pkg, request, is_compiler, all_deps) + elif is_compiler: + # ensure it's queued as a compiler + self._modify_existing_task(pkgid, "compiler", True) + + def _modify_existing_task(self, pkgid, attr, value): + """ + Update a task in-place to modify its behavior. + + Currently used to update the ``compiler`` field on tasks + that were originally created as a dependency of a compiler, + but are compilers in their own right. + + For example, ``intel-oneapi-compilers-classic`` depends on + ``intel-oneapi-compilers``, which can cause the latter to be + queued first as a non-compiler, and only later as a compiler. + """ + for i, tup in enumerate(self.build_pq): + key, task = tup + if task.pkg_id == pkgid: + tty.debug( + "Modifying task for {0} to treat it as a compiler".format(pkgid), + level=2, + ) + setattr(task, attr, value) + self.build_pq[i] = (key, task) def _add_init_task(self, pkg, request, is_compiler, all_deps): """ diff --git a/lib/spack/spack/test/installer.py b/lib/spack/spack/test/installer.py index 363d92fe1f7..8a713ca7046 100644 --- a/lib/spack/spack/test/installer.py +++ b/lib/spack/spack/test/installer.py @@ -467,6 +467,26 @@ def _conc_spec(compiler): assert packages +def test_update_tasks_for_compiler_packages_as_compiler(mock_packages, config, monkeypatch): + spec = spack.spec.Spec("trivial-install-test-package").concretized() + installer = inst.PackageInstaller([(spec.package, {})]) + + # Add a task to the queue + installer._add_init_task(spec.package, installer.build_requests[0], False, {}) + + # monkeypatch to make the list of compilers be what we test + def fake_package_list(compiler, architecture, pkgs): + return [(spec.package, True)] + + monkeypatch.setattr(inst, "_packages_needed_to_bootstrap_compiler", fake_package_list) + + installer._add_bootstrap_compilers("fake", "fake", "fake", None, {}) + + # Check that the only task is now a compiler task + assert len(installer.build_pq) == 1 + assert installer.build_pq[0][1].compiler + + def test_dump_packages_deps_ok(install_mockery, tmpdir, mock_packages): """Test happy path for dump_packages with dependencies.""" From 8be63786883111a5f4037ef73d2f7ffb22e8edf2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Nov 2022 20:13:09 +0100 Subject: [PATCH 400/442] Bump docker/setup-qemu-action from 2.0.0 to 2.1.0 (#33269) Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 2.0.0 to 2.1.0. - [Release notes](https://github.com/docker/setup-qemu-action/releases) - [Commits](https://github.com/docker/setup-qemu-action/compare/8b122486cedac8393e77aa9734c3528886e4a1a8...e81a89b1732b9c48d79cd809d8d81d79c4647a18) --- updated-dependencies: - dependency-name: docker/setup-qemu-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-containers.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-containers.yml b/.github/workflows/build-containers.yml index 83647e4ad17..d224cf0cf97 100644 --- a/.github/workflows/build-containers.yml +++ b/.github/workflows/build-containers.yml @@ -86,7 +86,7 @@ jobs: path: dockerfiles - name: Set up QEMU - uses: docker/setup-qemu-action@8b122486cedac8393e77aa9734c3528886e4a1a8 # @v1 + uses: docker/setup-qemu-action@e81a89b1732b9c48d79cd809d8d81d79c4647a18 # @v1 - name: Set up Docker Buildx uses: docker/setup-buildx-action@c74574e6c82eeedc46366be1b0d287eff9085eb6 # @v1 From 9d08feb63ef0ed0238e12252271a921598351d47 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Nov 2022 20:38:32 +0100 Subject: [PATCH 401/442] Bump dorny/paths-filter from 2.10.2 to 2.11.1 (#33270) Bumps [dorny/paths-filter](https://github.com/dorny/paths-filter) from 2.10.2 to 2.11.1. - [Release notes](https://github.com/dorny/paths-filter/releases) - [Changelog](https://github.com/dorny/paths-filter/blob/master/CHANGELOG.md) - [Commits](https://github.com/dorny/paths-filter/compare/b2feaf19c27470162a626bd6fa8438ae5b263721...4512585405083f25c027a35db413c2b3b9006d50) --- updated-dependencies: - dependency-name: dorny/paths-filter dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 46dfbd572db..3b57bd9bb51 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -46,7 +46,7 @@ jobs: with: fetch-depth: 0 # For pull requests it's not necessary to checkout the code - - uses: dorny/paths-filter@b2feaf19c27470162a626bd6fa8438ae5b263721 + - uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 id: filter with: # See https://github.com/dorny/paths-filter/issues/56 for the syntax used below From e0e20e3e79ec3c3a0cb4f97d69fc9f1f79456734 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Nov 2022 20:40:06 +0100 Subject: [PATCH 402/442] Bump docker/build-push-action from 3.1.1 to 3.2.0 (#33271) Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 3.1.1 to 3.2.0. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/c84f38281176d4c9cdb1626ffafcd6b3911b5d94...c56af957549030174b10d6867f20e78cfd7debc5) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-containers.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-containers.yml b/.github/workflows/build-containers.yml index d224cf0cf97..062bf39e616 100644 --- a/.github/workflows/build-containers.yml +++ b/.github/workflows/build-containers.yml @@ -106,7 +106,7 @@ jobs: password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build & Deploy ${{ matrix.dockerfile[0] }} - uses: docker/build-push-action@c84f38281176d4c9cdb1626ffafcd6b3911b5d94 # @v2 + uses: docker/build-push-action@c56af957549030174b10d6867f20e78cfd7debc5 # @v2 with: context: dockerfiles/${{ matrix.dockerfile[0] }} platforms: ${{ matrix.dockerfile[1] }} From cc84ab1e921754a4b3d2cf668e3e99bfc3487549 Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Mon, 7 Nov 2022 20:41:16 +0100 Subject: [PATCH 403/442] Remove known issues (#33738) --- lib/spack/docs/index.rst | 1 - lib/spack/docs/known_issues.rst | 40 --------------------------------- 2 files changed, 41 deletions(-) delete mode 100644 lib/spack/docs/known_issues.rst diff --git a/lib/spack/docs/index.rst b/lib/spack/docs/index.rst index 3a5e07ed183..b755f2f3768 100644 --- a/lib/spack/docs/index.rst +++ b/lib/spack/docs/index.rst @@ -56,7 +56,6 @@ or refer to the full manual below. basic_usage Tutorial: Spack 101 replace_conda_homebrew - known_issues .. toctree:: :maxdepth: 2 diff --git a/lib/spack/docs/known_issues.rst b/lib/spack/docs/known_issues.rst deleted file mode 100644 index 0e309f1829a..00000000000 --- a/lib/spack/docs/known_issues.rst +++ /dev/null @@ -1,40 +0,0 @@ -.. 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) - -============ -Known Issues -============ - -This is a list of known issues in Spack. It provides ways of getting around these -problems if you encounter them. - ------------------------------------------------- -Spack does not seem to respect ``packages.yaml`` ------------------------------------------------- - -.. note:: - - This issue is **resolved** as of v0.19.0.dev0 commit - `8281a0c5feabfc4fe180846d6fe95cfe53420bc5`, through the introduction of package - requirements. See :ref:`package-requirements`. - -A common problem in Spack v0.18.0 up to v0.19.0.dev0 is that package, compiler and target -preferences specified in ``packages.yaml`` do not seem to be respected. Spack picks the -"wrong" compilers and their versions, package versions and variants, and -micro-architectures. - -This is however not a bug. In order to reduce the number of builds of the same -packages, the concretizer values reuse of installed packages higher than preferences -set in ``packages.yaml``. Note that ``packages.yaml`` specifies only preferences, not -hard constraints. - -There are multiple workarounds: - -1. Disable reuse during concretization: ``spack install --fresh `` when installing - from the command line, or ``spack concretize --fresh --force`` when using - environments. -2. Turn preferences into constrains, by moving them to the input spec. For example, - use ``spack spec zlib%gcc@12`` when you want to force GCC 12 even if ``zlib`` was - already installed with GCC 10. From 01a578851707281b8e1da736086b41e98bfbe5f4 Mon Sep 17 00:00:00 2001 From: Sergey Kosukhin Date: Mon, 7 Nov 2022 20:54:36 +0100 Subject: [PATCH 404/442] eckit: fix underlinking (#33739) --- var/spack/repos/builtin/packages/eckit/package.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/var/spack/repos/builtin/packages/eckit/package.py b/var/spack/repos/builtin/packages/eckit/package.py index 52849a831c0..6a6a31c142a 100644 --- a/var/spack/repos/builtin/packages/eckit/package.py +++ b/var/spack/repos/builtin/packages/eckit/package.py @@ -137,4 +137,12 @@ def cmake_args(self): # (the LAPACK backend is still built though): args.append(self.define("ENABLE_LAPACK", "linalg=lapack" in self.spec)) + if "+admin" in self.spec and "+termlib" in self.spec["ncurses"]: + # Make sure that libeckit_cmd is linked to a library that resolves 'setupterm', + # 'tputs', etc. That is either libncurses (when 'ncurses~termlib') or libtinfo (when + # 'ncurses+termlib'). CMake considers the latter only if CURSES_NEED_NCURSES is set to + # TRUE. Note that the installation of eckit does not fail without this but the building + # of a dependent package (e.g. fdb) might fail due to the undefined references. + args.append(self.define("CURSES_NEED_NCURSES", True)) + return args From 28a77c2821d62a2800a63921f116fcf45a8f7342 Mon Sep 17 00:00:00 2001 From: Scott Wittenburg Date: Mon, 7 Nov 2022 13:31:14 -0700 Subject: [PATCH 405/442] binary_distribution: Speed up buildcache update-index (#32796) This change uses the aws cli, if available, to retrieve spec files from the mirror to a local temp directory, then parallelizes the reading of those files from disk using multiprocessing.ThreadPool. If the aws cli is not available, then a ThreadPool is used to fetch and read the spec files from the mirror. Using aws cli results in ~16 times speed up to recreate the binary mirror index, while just parallelizing the fetching and reading results in ~3 speed up. --- lib/spack/spack/binary_distribution.py | 200 ++++++++++++++++++++----- 1 file changed, 166 insertions(+), 34 deletions(-) diff --git a/lib/spack/spack/binary_distribution.py b/lib/spack/spack/binary_distribution.py index 3967afdfd85..1e9843c4738 100644 --- a/lib/spack/spack/binary_distribution.py +++ b/lib/spack/spack/binary_distribution.py @@ -7,6 +7,7 @@ import collections import hashlib import json +import multiprocessing.pool import os import shutil import sys @@ -45,6 +46,7 @@ from spack.relocate import utf8_paths_to_single_binary_regex from spack.spec import Spec from spack.stage import Stage +from spack.util.executable import which _build_cache_relative_path = "build_cache" _build_cache_keys_relative_path = "_pgp" @@ -72,6 +74,10 @@ def __init__(self, errors): super(FetchCacheError, self).__init__(self.message) +class ListMirrorSpecsError(spack.error.SpackError): + """Raised when unable to retrieve list of specs from the mirror""" + + class BinaryCacheIndex(object): """ The BinaryCacheIndex tracks what specs are available on (usually remote) @@ -881,37 +887,52 @@ def sign_specfile(key, force, specfile_path): spack.util.gpg.sign(key, specfile_path, signed_specfile_path, clearsign=True) -def _fetch_spec_from_mirror(spec_url): - s = None - tty.debug("fetching {0}".format(spec_url)) - _, _, spec_file = web_util.read_from_url(spec_url) - spec_file_contents = codecs.getreader("utf-8")(spec_file).read() - # Need full spec.json name or this gets confused with index.json. - if spec_url.endswith(".json.sig"): - specfile_json = Spec.extract_json_from_clearsig(spec_file_contents) - s = Spec.from_dict(specfile_json) - elif spec_url.endswith(".json"): - s = Spec.from_json(spec_file_contents) - elif spec_url.endswith(".yaml"): - s = Spec.from_yaml(spec_file_contents) - return s +def _read_specs_and_push_index(file_list, read_method, cache_prefix, db, temp_dir, concurrency): + """Read all the specs listed in the provided list, using thread given thread parallelism, + generate the index, and push it to the mirror. + Args: + file_list (list(str)): List of urls or file paths pointing at spec files to read + read_method: A function taking a single argument, either a url or a file path, + and which reads the spec file at that location, and returns the spec. + cache_prefix (str): prefix of the build cache on s3 where index should be pushed. + db: A spack database used for adding specs and then writing the index. + temp_dir (str): Location to write index.json and hash for pushing + concurrency (int): Number of parallel processes to use when fetching -def _read_specs_and_push_index(file_list, cache_prefix, db, db_root_dir): - for file_path in file_list: - try: - s = _fetch_spec_from_mirror(url_util.join(cache_prefix, file_path)) - except (URLError, web_util.SpackWebError) as url_err: - tty.error("Error reading specfile: {0}".format(file_path)) - tty.error(url_err) + Return: + None + """ - if s: - db.add(s, None) - db.mark(s, "in_buildcache", True) + def _fetch_spec_from_mirror(spec_url): + spec_file_contents = read_method(spec_url) + + if spec_file_contents: + # Need full spec.json name or this gets confused with index.json. + if spec_url.endswith(".json.sig"): + specfile_json = Spec.extract_json_from_clearsig(spec_file_contents) + return Spec.from_dict(specfile_json) + if spec_url.endswith(".json"): + return Spec.from_json(spec_file_contents) + if spec_url.endswith(".yaml"): + return Spec.from_yaml(spec_file_contents) + + tp = multiprocessing.pool.ThreadPool(processes=concurrency) + try: + fetched_specs = tp.map( + llnl.util.lang.star(_fetch_spec_from_mirror), [(f,) for f in file_list] + ) + finally: + tp.terminate() + tp.join() + + for fetched_spec in fetched_specs: + db.add(fetched_spec, None) + db.mark(fetched_spec, "in_buildcache", True) # Now generate the index, compute its hash, and push the two files to # the mirror. - index_json_path = os.path.join(db_root_dir, "index.json") + index_json_path = os.path.join(temp_dir, "index.json") with open(index_json_path, "w") as f: db._write_to_file(f) @@ -921,7 +942,7 @@ def _read_specs_and_push_index(file_list, cache_prefix, db, db_root_dir): index_hash = compute_hash(index_string) # Write the hash out to a local file - index_hash_path = os.path.join(db_root_dir, "index.json.hash") + index_hash_path = os.path.join(temp_dir, "index.json.hash") with open(index_hash_path, "w") as f: f.write(index_hash) @@ -942,31 +963,142 @@ def _read_specs_and_push_index(file_list, cache_prefix, db, db_root_dir): ) -def generate_package_index(cache_prefix): - """Create the build cache index page. +def _specs_from_cache_aws_cli(cache_prefix): + """Use aws cli to sync all the specs into a local temporary directory. - Creates (or replaces) the "index.json" page at the location given in - cache_prefix. This page contains a link for each binary package (.yaml or - .json) under cache_prefix. + Args: + cache_prefix (str): prefix of the build cache on s3 + + Return: + List of the local file paths and a function that can read each one from the file system. """ + read_fn = None + file_list = None + aws = which("aws") + + def file_read_method(file_path): + with open(file_path) as fd: + return fd.read() + + tmpspecsdir = tempfile.mkdtemp() + sync_command_args = [ + "s3", + "sync", + "--exclude", + "*", + "--include", + "*.spec.json.sig", + "--include", + "*.spec.json", + "--include", + "*.spec.yaml", + cache_prefix, + tmpspecsdir, + ] + + try: + tty.debug( + "Using aws s3 sync to download specs from {0} to {1}".format(cache_prefix, tmpspecsdir) + ) + aws(*sync_command_args, output=os.devnull, error=os.devnull) + file_list = fsys.find(tmpspecsdir, ["*.spec.json.sig", "*.spec.json", "*.spec.yaml"]) + read_fn = file_read_method + except Exception: + tty.warn("Failed to use aws s3 sync to retrieve specs, falling back to parallel fetch") + shutil.rmtree(tmpspecsdir) + + return file_list, read_fn + + +def _specs_from_cache_fallback(cache_prefix): + """Use spack.util.web module to get a list of all the specs at the remote url. + + Args: + cache_prefix (str): Base url of mirror (location of spec files) + + Return: + The list of complete spec file urls and a function that can read each one from its + remote location (also using the spack.util.web module). + """ + read_fn = None + file_list = None + + def url_read_method(url): + contents = None + try: + _, _, spec_file = web_util.read_from_url(url) + contents = codecs.getreader("utf-8")(spec_file).read() + except (URLError, web_util.SpackWebError) as url_err: + tty.error("Error reading specfile: {0}".format(url)) + tty.error(url_err) + return contents + try: file_list = [ - entry + url_util.join(cache_prefix, entry) for entry in web_util.list_url(cache_prefix) if entry.endswith(".yaml") or entry.endswith("spec.json") or entry.endswith("spec.json.sig") ] + read_fn = url_read_method except KeyError as inst: msg = "No packages at {0}: {1}".format(cache_prefix, inst) tty.warn(msg) - return except Exception as err: # If we got some kind of S3 (access denied or other connection # error), the first non boto-specific class in the exception # hierarchy is Exception. Just print a warning and return msg = "Encountered problem listing packages at {0}: {1}".format(cache_prefix, err) tty.warn(msg) + + return file_list, read_fn + + +def _spec_files_from_cache(cache_prefix): + """Get a list of all the spec files in the mirror and a function to + read them. + + Args: + cache_prefix (str): Base url of mirror (location of spec files) + + Return: + A tuple where the first item is a list of absolute file paths or + urls pointing to the specs that should be read from the mirror, + and the second item is a function taking a url or file path and + returning the spec read from that location. + """ + callbacks = [] + if cache_prefix.startswith("s3"): + callbacks.append(_specs_from_cache_aws_cli) + + callbacks.append(_specs_from_cache_fallback) + + for specs_from_cache_fn in callbacks: + file_list, read_fn = specs_from_cache_fn(cache_prefix) + if file_list: + return file_list, read_fn + + raise ListMirrorSpecsError("Failed to get list of specs from {0}".format(cache_prefix)) + + +def generate_package_index(cache_prefix, concurrency=32): + """Create or replace the build cache index on the given mirror. The + buildcache index contains an entry for each binary package under the + cache_prefix. + + Args: + cache_prefix(str): Base url of binary mirror. + concurrency: (int): The desired threading concurrency to use when + fetching the spec files from the mirror. + + Return: + None + """ + try: + file_list, read_fn = _spec_files_from_cache(cache_prefix) + except ListMirrorSpecsError as err: + tty.error("Unabled to generate package index, {0}".format(err)) return if any(x.endswith(".yaml") for x in file_list): @@ -989,7 +1121,7 @@ def generate_package_index(cache_prefix): ) try: - _read_specs_and_push_index(file_list, cache_prefix, db, db_root_dir) + _read_specs_and_push_index(file_list, read_fn, cache_prefix, db, db_root_dir, concurrency) except Exception as err: msg = "Encountered problem pushing package index to {0}: {1}".format(cache_prefix, err) tty.warn(msg) From c0170a675b7dddf9239360f118d9f1990d42c1ca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Nov 2022 21:39:38 +0100 Subject: [PATCH 406/442] build(deps): bump actions/upload-artifact from 3.1.0 to 3.1.1 (#33471) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3.1.0 to 3.1.1. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/3cea5372237819ed00197afe530f5a7ea3e805c8...83fd05a356d7e2593de66fc9913b3002723633cb) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-containers.yml | 2 +- .github/workflows/windows_python.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-containers.yml b/.github/workflows/build-containers.yml index 062bf39e616..799fba8ba64 100644 --- a/.github/workflows/build-containers.yml +++ b/.github/workflows/build-containers.yml @@ -80,7 +80,7 @@ jobs: fi - name: Upload Dockerfile - uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 + uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb with: name: dockerfiles path: dockerfiles diff --git a/.github/workflows/windows_python.yml b/.github/workflows/windows_python.yml index 7e6caa0189d..05a98c4cba9 100644 --- a/.github/workflows/windows_python.yml +++ b/.github/workflows/windows_python.yml @@ -109,11 +109,11 @@ jobs: echo "installer_root=$((pwd).Path)" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append env: ProgressPreference: SilentlyContinue - - uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 + - uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb with: name: Windows Spack Installer Bundle path: ${{ env.installer_root }}\pkg\Spack.exe - - uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 + - uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb with: name: Windows Spack Installer path: ${{ env.installer_root}}\pkg\Spack.msi From 28d669cb39b155e73fea532ea4d8100a921041b0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Nov 2022 20:49:42 +0000 Subject: [PATCH 407/442] build(deps): bump docker/setup-buildx-action from 2.2.0 to 2.2.1 (#33399) Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 2.2.0 to 2.2.1. - [Release notes](https://github.com/docker/setup-buildx-action/releases) - [Commits](https://github.com/docker/setup-buildx-action/compare/c74574e6c82eeedc46366be1b0d287eff9085eb6...8c0edbc76e98fa90f69d9a2c020dcb50019dc325) --- updated-dependencies: - dependency-name: docker/setup-buildx-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-containers.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-containers.yml b/.github/workflows/build-containers.yml index 799fba8ba64..1030ba6428c 100644 --- a/.github/workflows/build-containers.yml +++ b/.github/workflows/build-containers.yml @@ -89,7 +89,7 @@ jobs: uses: docker/setup-qemu-action@e81a89b1732b9c48d79cd809d8d81d79c4647a18 # @v1 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@c74574e6c82eeedc46366be1b0d287eff9085eb6 # @v1 + uses: docker/setup-buildx-action@8c0edbc76e98fa90f69d9a2c020dcb50019dc325 # @v1 - name: Log in to GitHub Container Registry uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a # @v1 From 6241cdb27be0ed81a517f1601feac1b7e327170c Mon Sep 17 00:00:00 2001 From: Tom Scogland Date: Mon, 7 Nov 2022 15:00:22 -0800 Subject: [PATCH 408/442] encode development requirements in pyproject.toml (#32616) Add a `project` block to the toml config along with development and CI dependencies and a minimal `build-system` block, doing basically nothing, so that spack can be bootstrapped to a full development environment with: ```shell $ hatch -e dev shell ``` or for a minimal environment without hatch: ```shell $ python3 -m venv venv $ source venv/bin/activate $ python3 -m pip install --upgrade pip $ python3 -m pip install -e '.[dev]' ``` This means we can re-use the requirements list throughout the workflow yaml files and otherwise maintain this list in *one place* rather than several disparate ones. We may be stuck with a couple more temporarily to continue supporting python2.7, but aside from that it's less places to get out of sync and a couple new bootstrap options. Co-authored-by: Adam J. Stewart --- bin/spack | 48 +---------------- lib/spack/spack/__init__.py | 19 +++++-- lib/spack/spack_installable/__init__.py | 0 lib/spack/spack_installable/main.py | 59 ++++++++++++++++++++ pyproject.toml | 71 +++++++++++++++++++++++++ 5 files changed, 146 insertions(+), 51 deletions(-) create mode 100644 lib/spack/spack_installable/__init__.py create mode 100644 lib/spack/spack_installable/main.py diff --git a/bin/spack b/bin/spack index 864fb34a778..08da29dfd26 100755 --- a/bin/spack +++ b/bin/spack @@ -49,52 +49,8 @@ spack_prefix = os.path.dirname(os.path.dirname(spack_file)) spack_lib_path = os.path.join(spack_prefix, "lib", "spack") sys.path.insert(0, spack_lib_path) -# Add external libs -spack_external_libs = os.path.join(spack_lib_path, "external") - -if sys.version_info[:2] <= (2, 7): - sys.path.insert(0, os.path.join(spack_external_libs, "py2")) - -sys.path.insert(0, spack_external_libs) - -# Here we delete ruamel.yaml in case it has been already imported from site -# (see #9206 for a broader description of the issue). -# -# Briefly: ruamel.yaml produces a .pth file when installed with pip that -# makes the site installed package the preferred one, even though sys.path -# is modified to point to another version of ruamel.yaml. -if "ruamel.yaml" in sys.modules: - del sys.modules["ruamel.yaml"] - -if "ruamel" in sys.modules: - del sys.modules["ruamel"] - -# The following code is here to avoid failures when updating -# the develop version, due to spurious argparse.pyc files remaining -# in the libs/spack/external directory, see: -# https://github.com/spack/spack/pull/25376 -# TODO: Remove in v0.18.0 or later -try: - import argparse -except ImportError: - argparse_pyc = os.path.join(spack_external_libs, "argparse.pyc") - if not os.path.exists(argparse_pyc): - raise - try: - os.remove(argparse_pyc) - import argparse # noqa: F401 - except Exception: - msg = ( - "The file\n\n\t{0}\n\nis corrupted and cannot be deleted by Spack. " - "Either delete it manually or ask some administrator to " - "delete it for you." - ) - print(msg.format(argparse_pyc)) - sys.exit(1) - - -import spack.main # noqa: E402 +from spack_installable.main import main # noqa: E402 # Once we've set up the system path, run the spack main method if __name__ == "__main__": - sys.exit(spack.main.main()) + sys.exit(main()) diff --git a/lib/spack/spack/__init__.py b/lib/spack/spack/__init__.py index e368639553c..4486221a18c 100644 --- a/lib/spack/spack/__init__.py +++ b/lib/spack/spack/__init__.py @@ -3,11 +3,20 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) -#: (major, minor, micro, dev release) tuple -spack_version_info = (0, 19, 0, "dev0") - #: PEP440 canonical ... string -spack_version = ".".join(str(s) for s in spack_version_info) +__version__ = "0.19.0.dev0" +spack_version = __version__ + + +def __try_int(v): + try: + return int(v) + except ValueError: + return v + + +#: (major, minor, micro, dev release) tuple +spack_version_info = tuple([__try_int(v) for v in __version__.split(".")]) + __all__ = ["spack_version_info", "spack_version"] -__version__ = spack_version diff --git a/lib/spack/spack_installable/__init__.py b/lib/spack/spack_installable/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/spack/spack_installable/main.py b/lib/spack/spack_installable/main.py new file mode 100644 index 00000000000..4a4001b9999 --- /dev/null +++ b/lib/spack/spack_installable/main.py @@ -0,0 +1,59 @@ +import os +import sys +from os.path import dirname as dn + + +def main(argv=None): + # Find spack's location and its prefix. + this_file = os.path.realpath(os.path.expanduser(__file__)) + spack_prefix = dn(dn(dn(dn(this_file)))) + + # Allow spack libs to be imported in our scripts + spack_lib_path = os.path.join(spack_prefix, "lib", "spack") + sys.path.insert(0, spack_lib_path) + + # Add external libs + spack_external_libs = os.path.join(spack_lib_path, "external") + + if sys.version_info[:2] <= (2, 7): + sys.path.insert(0, os.path.join(spack_external_libs, "py2")) + + sys.path.insert(0, spack_external_libs) + # Here we delete ruamel.yaml in case it has been already imported from site + # (see #9206 for a broader description of the issue). + # + # Briefly: ruamel.yaml produces a .pth file when installed with pip that + # makes the site installed package the preferred one, even though sys.path + # is modified to point to another version of ruamel.yaml. + if "ruamel.yaml" in sys.modules: + del sys.modules["ruamel.yaml"] + + if "ruamel" in sys.modules: + del sys.modules["ruamel"] + + # The following code is here to avoid failures when updating + # the develop version, due to spurious argparse.pyc files remaining + # in the libs/spack/external directory, see: + # https://github.com/spack/spack/pull/25376 + # TODO: Remove in v0.18.0 or later + try: + import argparse # noqa: F401 + except ImportError: + argparse_pyc = os.path.join(spack_external_libs, "argparse.pyc") + if not os.path.exists(argparse_pyc): + raise + try: + os.remove(argparse_pyc) + import argparse # noqa: F401 + except Exception: + msg = ( + "The file\n\n\t{0}\n\nis corrupted and cannot be deleted by Spack. " + "Either delete it manually or ask some administrator to " + "delete it for you." + ) + print(msg.format(argparse_pyc)) + sys.exit(1) + + import spack.main # noqa: E402 + + sys.exit(spack.main.main(argv)) diff --git a/pyproject.toml b/pyproject.toml index f5fed2df4b1..30b621dec47 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,74 @@ +[project] +name="spack" +description="The spack package manager" +dependencies=[ + "clingo", + "setuptools", + "six", + "types-six", +] +dynamic = ["version"] + +[project.scripts] +spack = "lib.spack.spack_installable.main:main" + +[tool.hatch.version] +path = "lib/spack/spack/__init__.py" + +[project.optional-dependencies] +dev = [ + "pip>=21.3", + "pytest", + "pytest-xdist", + "setuptools", + "click==8.0.2", + 'black==21.12b0', + "mypy", + "isort", + "flake8", + "vermin", +] +ci = [ + "pytest-cov", + "codecov[toml]", +] + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.build.targets.wheel] +include = [ + "/bin", + "/etc", + "/lib", + "/share", + "/var", + "CITATION.cff", + "COPYRIGHT", + "LICENSE-APACHE", + "LICENSE-MIT", + "NOTICE", + "README.md", + "SECURITY.md", +] + +[tool.hatch.envs.default] +features = [ + "dev", +] + +[tool.hatch.envs.default.scripts] +spack = "./bin/spack" +style = "./bin/spack style" +test = "./bin/spack unit-test" + +[tool.hatch.envs.ci] +features = [ + "dev", + "ci", +] + [tool.black] line-length = 99 target-version = ['py27', 'py35', 'py36', 'py37', 'py38', 'py39', 'py310'] From b3b675157c03a7c412d1d7f5b4696dc4d3a618a7 Mon Sep 17 00:00:00 2001 From: Scott Wittenburg Date: Mon, 7 Nov 2022 16:11:04 -0700 Subject: [PATCH 409/442] gitlab ci: Add "script_failure" as a reason for retrying service jobs (#33420) Somehow a network error when cloning the repo for ci gets categorized by gitlab as a script failure. To make sure we retry jobs that failed for that reason or a similar one, include "script_failure" as one of the reasons for retrying service jobs (which include "no specs to rebuild" jobs, update buildcache index jobs, and temp storage cleanup jobs. --- lib/spack/spack/ci.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/spack/spack/ci.py b/lib/spack/spack/ci.py index 56b3b249ac3..aa54b71b3d4 100644 --- a/lib/spack/spack/ci.py +++ b/lib/spack/spack/ci.py @@ -1167,7 +1167,14 @@ def generate_gitlab_ci_yaml( "after_script", ] - service_job_retries = {"max": 2, "when": ["runner_system_failure", "stuck_or_timeout_failure"]} + service_job_retries = { + "max": 2, + "when": [ + "runner_system_failure", + "stuck_or_timeout_failure", + "script_failure", + ], + } if job_id > 0: if temp_storage_url_prefix: From 3693622edf23fe6430e7de358692b88821e9390d Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Tue, 8 Nov 2022 01:16:11 +0100 Subject: [PATCH 410/442] reorder packages.yaml: requirements first, then preferences (#33741) * reorder packages.yaml: requirements first, then preferences * expand preferences vs reuse vs requirements --- lib/spack/docs/build_settings.rst | 163 +++++++++++++++--------------- 1 file changed, 83 insertions(+), 80 deletions(-) diff --git a/lib/spack/docs/build_settings.rst b/lib/spack/docs/build_settings.rst index 3ab38dd4daf..900a612c4c6 100644 --- a/lib/spack/docs/build_settings.rst +++ b/lib/spack/docs/build_settings.rst @@ -302,88 +302,31 @@ microarchitectures considered during the solve are constrained to be compatible host Spack is currently running on. For instance, if this option is set to ``true``, a user cannot concretize for ``target=icelake`` while running on an Haswell node. -.. _package-preferences: - -------------------- -Package Preferences -------------------- - -Spack can be configured to prefer certain compilers, package -versions, dependencies, and variants during concretization. -The preferred configuration can be controlled via the -``~/.spack/packages.yaml`` file for user configurations, or the -``etc/spack/packages.yaml`` site configuration. - -Here's an example ``packages.yaml`` file that sets preferred packages: - -.. code-block:: yaml - - packages: - opencv: - compiler: [gcc@4.9] - variants: +debug - gperftools: - version: [2.2, 2.4, 2.3] - all: - compiler: [gcc@4.4.7, 'gcc@4.6:', intel, clang, pgi] - target: [sandybridge] - providers: - mpi: [mvapich2, mpich, openmpi] - -At a high level, this example is specifying how packages should be -concretized. The opencv package should prefer using GCC 4.9 and -be built with debug options. The gperftools package should prefer version -2.2 over 2.4. Every package on the system should prefer mvapich2 for -its MPI and GCC 4.4.7 (except for opencv, which overrides this by preferring GCC 4.9). -These options are used to fill in implicit defaults. Any of them can be overwritten -on the command line if explicitly requested. - -Each ``packages.yaml`` file begins with the string ``packages:`` and -package names are specified on the next level. The special string ``all`` -applies settings to *all* packages. Underneath each package name is one -or more components: ``compiler``, ``variants``, ``version``, -``providers``, and ``target``. Each component has an ordered list of -spec ``constraints``, with earlier entries in the list being preferred -over later entries. - -Sometimes a package installation may have constraints that forbid -the first concretization rule, in which case Spack will use the first -legal concretization rule. Going back to the example, if a user -requests gperftools 2.3 or later, then Spack will install version 2.4 -as the 2.4 version of gperftools is preferred over 2.3. - -An explicit concretization rule in the preferred section will always -take preference over unlisted concretizations. In the above example, -xlc isn't listed in the compiler list. Every listed compiler from -gcc to pgi will thus be preferred over the xlc compiler. - -The syntax for the ``provider`` section differs slightly from other -concretization rules. A provider lists a value that packages may -``depend_on`` (e.g, MPI) and a list of rules for fulfilling that -dependency. - .. _package-requirements: -------------------- Package Requirements -------------------- -You can use the configuration to force the concretizer to choose -specific properties for packages when building them. Like preferences, -these are only applied when the package is required by some other -request (e.g. if the package is needed as a dependency of a -request to ``spack install``). +Spack can be configured to always use certain compilers, package +versions, and variants during concretization through package +requirements. -An example of where this is useful is if you have a package that -is normally built as a dependency but only under certain circumstances -(e.g. only when a variant on a dependent is active): you can make -sure that it always builds the way you want it to; this distinguishes -package configuration requirements from constraints that you add to -``spack install`` or to environments (in those cases, the associated -packages are always built). +Package requirements are useful when you find yourself repeatedly +specifying the same constraints on the command line, and wish that +Spack respects these constraints whether you mention them explicitly +or not. Another use case is specifying constraints that should apply +to all root specs in an environment, without having to repeat the +constraint everywhere. -The following is an example of how to enforce package properties in -``packages.yaml``: +Apart from that, requirements config is more flexible than constraints +on the command line, because it can specify constraints on packages +*when they occur* as a dependency. In contrast, on the command line it +is not possible to specify constraints on dependencies while also keeping +those dependencies optional. + +The package requirements configuration is specified in ``packages.yaml`` +keyed by package name: .. code-block:: yaml @@ -452,15 +395,15 @@ under ``all`` are disregarded. For example, with a configuration like this: cmake: require: '%gcc' -Spack requires ``cmake`` to use ``gcc`` and all other nodes (including cmake dependencies) -to use ``clang``. +Spack requires ``cmake`` to use ``gcc`` and all other nodes (including ``cmake`` +dependencies) to use ``clang``. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Setting requirements on virtual specs ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -A requirement on a virtual spec applies whenever that virtual is present in the DAG. This -can be useful for fixing which virtual provider you want to use: +A requirement on a virtual spec applies whenever that virtual is present in the DAG. +This can be useful for fixing which virtual provider you want to use: .. code-block:: yaml @@ -470,8 +413,8 @@ can be useful for fixing which virtual provider you want to use: With the configuration above the only allowed ``mpi`` provider is ``mvapich2 %gcc``. -Requirements on the virtual spec and on the specific provider are both applied, if present. For -instance with a configuration like: +Requirements on the virtual spec and on the specific provider are both applied, if +present. For instance with a configuration like: .. code-block:: yaml @@ -483,6 +426,66 @@ instance with a configuration like: you will use ``mvapich2~cuda %gcc`` as an ``mpi`` provider. +.. _package-preferences: + +------------------- +Package Preferences +------------------- + +In some cases package requirements can be too strong, and package +preferences are the better option. Package preferences do not impose +constraints on packages for particular versions or variants values, +they rather only set defaults -- the concretizer is free to change +them if it must due to other constraints. Also note that package +preferences are of lower priority than reuse of already installed +packages. + +Here's an example ``packages.yaml`` file that sets preferred packages: + +.. code-block:: yaml + + packages: + opencv: + compiler: [gcc@4.9] + variants: +debug + gperftools: + version: [2.2, 2.4, 2.3] + all: + compiler: [gcc@4.4.7, 'gcc@4.6:', intel, clang, pgi] + target: [sandybridge] + providers: + mpi: [mvapich2, mpich, openmpi] + +At a high level, this example is specifying how packages are preferably +concretized. The opencv package should prefer using GCC 4.9 and +be built with debug options. The gperftools package should prefer version +2.2 over 2.4. Every package on the system should prefer mvapich2 for +its MPI and GCC 4.4.7 (except for opencv, which overrides this by preferring GCC 4.9). +These options are used to fill in implicit defaults. Any of them can be overwritten +on the command line if explicitly requested. + +Package preferences accept the follow keys or components under +the specific package (or ``all``) section: ``compiler``, ``variants``, +``version``, ``providers``, and ``target``. Each component has an +ordered list of spec ``constraints``, with earlier entries in the +list being preferred over later entries. + +Sometimes a package installation may have constraints that forbid +the first concretization rule, in which case Spack will use the first +legal concretization rule. Going back to the example, if a user +requests gperftools 2.3 or later, then Spack will install version 2.4 +as the 2.4 version of gperftools is preferred over 2.3. + +An explicit concretization rule in the preferred section will always +take preference over unlisted concretizations. In the above example, +xlc isn't listed in the compiler list. Every listed compiler from +gcc to pgi will thus be preferred over the xlc compiler. + +The syntax for the ``provider`` section differs slightly from other +concretization rules. A provider lists a value that packages may +``depends_on`` (e.g, MPI) and a list of rules for fulfilling that +dependency. + .. _package_permissions: ------------------- From 69d4637671f50d1224de02aa278ab721a438c98f Mon Sep 17 00:00:00 2001 From: akhursev Date: Mon, 7 Nov 2022 17:14:23 -0800 Subject: [PATCH 411/442] 2022.3.1 oneAPI release promotion (#33742) --- .../builtin/packages/intel-oneapi-advisor/package.py | 6 ++++++ .../builtin/packages/intel-oneapi-ccl/package.py | 6 ++++++ .../packages/intel-oneapi-compilers/package.py | 11 +++++++++++ .../builtin/packages/intel-oneapi-dal/package.py | 6 ++++++ .../builtin/packages/intel-oneapi-dnn/package.py | 6 ++++++ .../builtin/packages/intel-oneapi-dpct/package.py | 6 ++++++ .../builtin/packages/intel-oneapi-dpl/package.py | 6 ++++++ .../packages/intel-oneapi-inspector/package.py | 6 ++++++ .../builtin/packages/intel-oneapi-ipp/package.py | 6 ++++++ .../builtin/packages/intel-oneapi-ippcp/package.py | 6 ++++++ .../builtin/packages/intel-oneapi-itac/package.py | 6 ++++++ .../builtin/packages/intel-oneapi-mkl/package.py | 6 ++++++ .../builtin/packages/intel-oneapi-mpi/package.py | 6 ++++++ .../builtin/packages/intel-oneapi-tbb/package.py | 6 ++++++ .../builtin/packages/intel-oneapi-vtune/package.py | 6 ++++++ 15 files changed, 95 insertions(+) diff --git a/var/spack/repos/builtin/packages/intel-oneapi-advisor/package.py b/var/spack/repos/builtin/packages/intel-oneapi-advisor/package.py index e222ce638d1..27c46cee4a1 100644 --- a/var/spack/repos/builtin/packages/intel-oneapi-advisor/package.py +++ b/var/spack/repos/builtin/packages/intel-oneapi-advisor/package.py @@ -27,6 +27,12 @@ class IntelOneapiAdvisor(IntelOneApiPackage): ) if platform.system() == "Linux": + version( + "2022.3.1", + url="https://registrationcenter-download.intel.com/akdlm/irc_nas/18985/l_oneapi_advisor_p_2022.3.1.15323_offline.sh", + sha256="f05b58c2f13972b3ac979e4796bcc12a234b1e077400b5d00fc5df46cd228899", + expand=False, + ) version( "2022.3.0", url="https://registrationcenter-download.intel.com/akdlm/irc_nas/18872/l_oneapi_advisor_p_2022.3.0.8704_offline.sh", diff --git a/var/spack/repos/builtin/packages/intel-oneapi-ccl/package.py b/var/spack/repos/builtin/packages/intel-oneapi-ccl/package.py index f373af03c88..3747b965762 100644 --- a/var/spack/repos/builtin/packages/intel-oneapi-ccl/package.py +++ b/var/spack/repos/builtin/packages/intel-oneapi-ccl/package.py @@ -30,6 +30,12 @@ class IntelOneapiCcl(IntelOneApiLibraryPackage): depends_on("intel-oneapi-mpi") if platform.system() == "Linux": + version( + "2021.7.1", + url="https://registrationcenter-download.intel.com/akdlm/irc_nas/19029/l_oneapi_ccl_p_2021.7.1.16948_offline.sh", + sha256="daab05a0779db343b600253df8fea93ab0ed20bd630d89883dd651b6b540b1b2", + expand=False, + ) version( "2021.7.0", url="https://registrationcenter-download.intel.com/akdlm/irc_nas/18891/l_oneapi_ccl_p_2021.7.0.8733_offline.sh", 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 fa6d9f7ac11..c5960742897 100644 --- a/var/spack/repos/builtin/packages/intel-oneapi-compilers/package.py +++ b/var/spack/repos/builtin/packages/intel-oneapi-compilers/package.py @@ -10,6 +10,17 @@ from spack.package import * linux_versions = [ + { + "version": "2022.2.1", + "cpp": { + "url": "https://registrationcenter-download.intel.com/akdlm/irc_nas/19049/l_dpcpp-cpp-compiler_p_2022.2.1.16991_offline.sh", + "sha256": "3f0f02f9812a0cdf01922d2df9348910c6a4cb4f9dfe50fc7477a59bbb1f7173", + }, + "ftn": { + "url": "https://registrationcenter-download.intel.com/akdlm/irc_nas/18998/l_fortran-compiler_p_2022.2.1.16992_offline.sh", + "sha256": "64f1d1efbcdc3ac2182bec18313ca23f800d94f69758db83a1394490d9d4b042", + }, + }, { "version": "2022.2.0", "cpp": { diff --git a/var/spack/repos/builtin/packages/intel-oneapi-dal/package.py b/var/spack/repos/builtin/packages/intel-oneapi-dal/package.py index 7ed60a6be7b..c2d90138d4f 100644 --- a/var/spack/repos/builtin/packages/intel-oneapi-dal/package.py +++ b/var/spack/repos/builtin/packages/intel-oneapi-dal/package.py @@ -29,6 +29,12 @@ class IntelOneapiDal(IntelOneApiLibraryPackage): ) if platform.system() == "Linux": + version( + "2021.7.1", + url="https://registrationcenter-download.intel.com/akdlm/irc_nas/19032/l_daal_oneapi_p_2021.7.1.16996_offline.sh", + sha256="2328927480b0ba5d380028f981717b63ee323f8a1616a491a160a0a0b239e285", + expand=False, + ) version( "2021.7.0", url="https://registrationcenter-download.intel.com/akdlm/irc_nas/18895/l_daal_oneapi_p_2021.7.0.8746_offline.sh", diff --git a/var/spack/repos/builtin/packages/intel-oneapi-dnn/package.py b/var/spack/repos/builtin/packages/intel-oneapi-dnn/package.py index 7d0602d3702..33fa28e3d6d 100644 --- a/var/spack/repos/builtin/packages/intel-oneapi-dnn/package.py +++ b/var/spack/repos/builtin/packages/intel-oneapi-dnn/package.py @@ -29,6 +29,12 @@ class IntelOneapiDnn(IntelOneApiLibraryPackage): ) if platform.system() == "Linux": + version( + "2022.2.1", + url="https://registrationcenter-download.intel.com/akdlm/irc_nas/19035/l_onednn_p_2022.2.1.16994_offline.sh", + sha256="2102964a36a5b58b529385706e6829456ee5225111c33dfce6326fff5175aace", + expand=False, + ) version( "2022.2.0", url="https://registrationcenter-download.intel.com/akdlm/irc_nas/18933/l_onednn_p_2022.2.0.8750_offline.sh", diff --git a/var/spack/repos/builtin/packages/intel-oneapi-dpct/package.py b/var/spack/repos/builtin/packages/intel-oneapi-dpct/package.py index b35db040061..66957cf274e 100644 --- a/var/spack/repos/builtin/packages/intel-oneapi-dpct/package.py +++ b/var/spack/repos/builtin/packages/intel-oneapi-dpct/package.py @@ -22,6 +22,12 @@ class IntelOneapiDpct(IntelOneApiPackage): homepage = "https://www.intel.com/content/www/us/en/developer/tools/oneapi/dpc-compatibility-tool.html#gs.2p8km6" if platform.system() == "Linux": + version( + "2022.2.1", + url="https://registrationcenter-download.intel.com/akdlm/irc_nas/18991/l_dpcpp-ct_p_2022.2.1.14994_offline.sh", + sha256="ea2fbe36de70eb3c78c97133f81e0b2a2fbcfc9525e77125a183d7af446ef3e6", + expand=False, + ) version( "2022.2.0", url="https://registrationcenter-download.intel.com/akdlm/irc_nas/18908/l_dpcpp-ct_p_2022.2.0.8701_offline.sh", diff --git a/var/spack/repos/builtin/packages/intel-oneapi-dpl/package.py b/var/spack/repos/builtin/packages/intel-oneapi-dpl/package.py index 41279fceed2..0d8fb52d58b 100644 --- a/var/spack/repos/builtin/packages/intel-oneapi-dpl/package.py +++ b/var/spack/repos/builtin/packages/intel-oneapi-dpl/package.py @@ -25,6 +25,12 @@ class IntelOneapiDpl(IntelOneApiLibraryPackage): homepage = "https://github.com/oneapi-src/oneDPL" if platform.system() == "Linux": + version( + "2021.7.2", + url="https://registrationcenter-download.intel.com/akdlm/irc_nas/19046/l_oneDPL_p_2021.7.2.15007_offline.sh", + sha256="84d60a6b1978ff45d2c416f18ca7df542eaa8c0b18dc3abf4bb0824a91b4fc44", + expand=False, + ) version( "2021.7.1", url="https://registrationcenter-download.intel.com/akdlm/irc_nas/18846/l_oneDPL_p_2021.7.1.8713_offline.sh", diff --git a/var/spack/repos/builtin/packages/intel-oneapi-inspector/package.py b/var/spack/repos/builtin/packages/intel-oneapi-inspector/package.py index bd0d479099d..5e6760656c4 100644 --- a/var/spack/repos/builtin/packages/intel-oneapi-inspector/package.py +++ b/var/spack/repos/builtin/packages/intel-oneapi-inspector/package.py @@ -27,6 +27,12 @@ class IntelOneapiInspector(IntelOneApiPackage): homepage = "https://software.intel.com/content/www/us/en/develop/tools/oneapi/components/inspector.html" if platform.system() == "Linux": + version( + "2022.3.1", + url="https://registrationcenter-download.intel.com/akdlm/irc_nas/19005/l_inspector_oneapi_p_2022.3.1.15318_offline.sh", + sha256="62aa2abf6928c0f4fc60ccfb69375297f823c183aea2519d7344e09c9734c1f8", + expand=False, + ) version( "2022.3.0", url="https://registrationcenter-download.intel.com/akdlm/irc_nas/18924/l_inspector_oneapi_p_2022.3.0.8706_offline.sh", diff --git a/var/spack/repos/builtin/packages/intel-oneapi-ipp/package.py b/var/spack/repos/builtin/packages/intel-oneapi-ipp/package.py index 971e0234c9a..4b912c41c98 100644 --- a/var/spack/repos/builtin/packages/intel-oneapi-ipp/package.py +++ b/var/spack/repos/builtin/packages/intel-oneapi-ipp/package.py @@ -30,6 +30,12 @@ class IntelOneapiIpp(IntelOneApiLibraryPackage): ) if platform.system() == "Linux": + version( + "2021.6.2", + url="https://registrationcenter-download.intel.com/akdlm/irc_nas/19007/l_ipp_oneapi_p_2021.6.2.16995_offline.sh", + sha256="23ae49afa9f13c2bed0c8a32e447e1c6b3528685cebdd32e4aa2a9736827cc4e", + expand=False, + ) version( "2021.6.1", url="https://registrationcenter-download.intel.com/akdlm/irc_nas/18925/l_ipp_oneapi_p_2021.6.1.8749_offline.sh", diff --git a/var/spack/repos/builtin/packages/intel-oneapi-ippcp/package.py b/var/spack/repos/builtin/packages/intel-oneapi-ippcp/package.py index f983abcdb26..c3de57f3c10 100644 --- a/var/spack/repos/builtin/packages/intel-oneapi-ippcp/package.py +++ b/var/spack/repos/builtin/packages/intel-oneapi-ippcp/package.py @@ -31,6 +31,12 @@ class IntelOneapiIppcp(IntelOneApiLibraryPackage): ) if platform.system() == "Linux": + version( + "2021.6.2", + url="https://registrationcenter-download.intel.com/akdlm/irc_nas/18999/l_ippcp_oneapi_p_2021.6.2.15006_offline.sh", + sha256="3c285c12da98a4d16e9a5ba237c8c51780475af54b1d1162185480ac891f16ee", + expand=False, + ) version( "2021.6.1", url="https://registrationcenter-download.intel.com/akdlm/irc_nas/18923/l_ippcp_oneapi_p_2021.6.1.8714_offline.sh", diff --git a/var/spack/repos/builtin/packages/intel-oneapi-itac/package.py b/var/spack/repos/builtin/packages/intel-oneapi-itac/package.py index 0110f05b169..98c5cac8666 100644 --- a/var/spack/repos/builtin/packages/intel-oneapi-itac/package.py +++ b/var/spack/repos/builtin/packages/intel-oneapi-itac/package.py @@ -30,6 +30,12 @@ class IntelOneapiItac(IntelOneApiPackage): maintainers = ["rscohn2"] if platform.system() == "Linux": + version( + "2021.7.1", + url="https://registrationcenter-download.intel.com/akdlm/irc_nas/19024/l_itac_oneapi_p_2021.7.1.15324_offline.sh", + sha256="fb26689efdb7369e211b5cf05f3e30d491a2787f24fef174b23241b997cc442f", + expand=False, + ) version( "2021.7.0", url="https://registrationcenter-download.intel.com/akdlm/irc_nas/18886/l_itac_oneapi_p_2021.7.0.8707_offline.sh", diff --git a/var/spack/repos/builtin/packages/intel-oneapi-mkl/package.py b/var/spack/repos/builtin/packages/intel-oneapi-mkl/package.py index 1952f35d154..49ee7869f23 100644 --- a/var/spack/repos/builtin/packages/intel-oneapi-mkl/package.py +++ b/var/spack/repos/builtin/packages/intel-oneapi-mkl/package.py @@ -27,6 +27,12 @@ class IntelOneapiMkl(IntelOneApiLibraryPackage): ) if platform.system() == "Linux": + version( + "2022.2.1", + url="https://registrationcenter-download.intel.com/akdlm/irc_nas/19038/l_onemkl_p_2022.2.1.16993_offline.sh", + sha256="eedd4b795720de776b1fc5f542ae0fac37ec235cdb567f7c2ee3182e73e3e59d", + expand=False, + ) version( "2022.2.0", url="https://registrationcenter-download.intel.com/akdlm/irc_nas/18898/l_onemkl_p_2022.2.0.8748_offline.sh", 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 c58320d72e6..a49899c7c54 100644 --- a/var/spack/repos/builtin/packages/intel-oneapi-mpi/package.py +++ b/var/spack/repos/builtin/packages/intel-oneapi-mpi/package.py @@ -26,6 +26,12 @@ class IntelOneapiMpi(IntelOneApiLibraryPackage): homepage = "https://software.intel.com/content/www/us/en/develop/tools/oneapi/components/mpi-library.html" if platform.system() == "Linux": + version( + "2021.7.1", + url="https://registrationcenter-download.intel.com/akdlm/irc_nas/19010/l_mpi_oneapi_p_2021.7.1.16815_offline.sh", + sha256="90e7804f2367d457cd4cbf7aa29f1c5676287aa9b34f93e7c9a19e4b8583fff7", + expand=False, + ) version( "2021.7.0", url="https://registrationcenter-download.intel.com/akdlm/irc_nas/18926/l_mpi_oneapi_p_2021.7.0.8711_offline.sh", diff --git a/var/spack/repos/builtin/packages/intel-oneapi-tbb/package.py b/var/spack/repos/builtin/packages/intel-oneapi-tbb/package.py index e8df02c63d0..8935db4c400 100644 --- a/var/spack/repos/builtin/packages/intel-oneapi-tbb/package.py +++ b/var/spack/repos/builtin/packages/intel-oneapi-tbb/package.py @@ -25,6 +25,12 @@ class IntelOneapiTbb(IntelOneApiLibraryPackage): ) if platform.system() == "Linux": + version( + "2021.7.1", + url="https://registrationcenter-download.intel.com/akdlm/irc_nas/19041/l_tbb_oneapi_p_2021.7.1.15005_offline.sh", + sha256="f13a8e740d69347b5985c1be496a3259a86d64ec94933b3d26100dbc2f059fd4", + expand=False, + ) version( "2021.7.0", url="https://registrationcenter-download.intel.com/akdlm/irc_nas/18901/l_tbb_oneapi_p_2021.7.0.8712_offline.sh", diff --git a/var/spack/repos/builtin/packages/intel-oneapi-vtune/package.py b/var/spack/repos/builtin/packages/intel-oneapi-vtune/package.py index 361c3f090d2..fb4011d2660 100644 --- a/var/spack/repos/builtin/packages/intel-oneapi-vtune/package.py +++ b/var/spack/repos/builtin/packages/intel-oneapi-vtune/package.py @@ -28,6 +28,12 @@ class IntelOneapiVtune(IntelOneApiPackage): homepage = "https://software.intel.com/content/www/us/en/develop/tools/oneapi/components/vtune-profiler.html" if platform.system() == "Linux": + version( + "2022.4.1", + url="https://registrationcenter-download.intel.com/akdlm/irc_nas/19027/l_oneapi_vtune_p_2022.4.1.16919_offline.sh", + sha256="eb4b4da61eea52c08fc139dbf4630e2c52cbcfaea8f1376c545c0863839366d1", + expand=False, + ) version( "2022.4.0", url="https://registrationcenter-download.intel.com/akdlm/irc_nas/18888/l_oneapi_vtune_p_2022.4.0.8705_offline.sh", From 84a3d32aa36f8af902ef67a58ce1944050bd7e1d Mon Sep 17 00:00:00 2001 From: Jordan Galby <67924449+Jordan474@users.noreply.github.com> Date: Tue, 8 Nov 2022 03:58:19 +0100 Subject: [PATCH 412/442] Fix missing "*.spack*" files in views (#30980) All files/dirs containing ".spack" anywhere their name were ignored when generating a spack view. For example, this happened with the 'r' package. --- lib/spack/spack/directory_layout.py | 2 +- lib/spack/spack/test/cmd/view.py | 32 +++++++++++++ .../packages/view-not-ignored/package.py | 46 +++++++++++++++++++ 3 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 var/spack/repos/builtin.mock/packages/view-not-ignored/package.py diff --git a/lib/spack/spack/directory_layout.py b/lib/spack/spack/directory_layout.py index 28f3caab9ef..b5848f12a79 100644 --- a/lib/spack/spack/directory_layout.py +++ b/lib/spack/spack/directory_layout.py @@ -102,7 +102,7 @@ def __init__(self, root, **kwargs): @property def hidden_file_regexes(self): - return (re.escape(self.metadata_dir),) + return ("^{0}$".format(re.escape(self.metadata_dir)),) def relative_path_for_spec(self, spec): _check_concrete(spec) diff --git a/lib/spack/spack/test/cmd/view.py b/lib/spack/spack/test/cmd/view.py index 51af2bae2a4..67c4275ddd4 100644 --- a/lib/spack/spack/test/cmd/view.py +++ b/lib/spack/spack/test/cmd/view.py @@ -10,6 +10,7 @@ import spack.util.spack_yaml as s_yaml from spack.main import SpackCommand +from spack.spec import Spec activate = SpackCommand("activate") extensions = SpackCommand("extensions") @@ -261,3 +262,34 @@ def test_view_fails_with_missing_projections_file(tmpdir): projection_file = os.path.join(str(tmpdir), "nonexistent") with pytest.raises(SystemExit): view("symlink", "--projection-file", projection_file, viewpath, "foo") + + +@pytest.mark.parametrize("with_projection", [False, True]) +@pytest.mark.parametrize("cmd", ["symlink", "copy"]) +def test_view_files_not_ignored( + tmpdir, mock_packages, mock_archive, mock_fetch, config, install_mockery, cmd, with_projection +): + spec = Spec("view-not-ignored").concretized() + pkg = spec.package + pkg.do_install() + pkg.assert_installed(spec.prefix) + + install("view-dir-file") # Arbitrary package to add noise + + viewpath = str(tmpdir.mkdir("view_{0}".format(cmd))) + + if with_projection: + proj = str(tmpdir.join("proj.yaml")) + with open(proj, "w") as f: + f.write('{"projections":{"all":"{name}"}}') + prefix_in_view = os.path.join(viewpath, "view-not-ignored") + args = ["--projection-file", proj] + else: + prefix_in_view = viewpath + args = [] + + view(cmd, *(args + [viewpath, "view-not-ignored", "view-dir-file"])) + pkg.assert_installed(prefix_in_view) + + view("remove", viewpath, "view-not-ignored") + pkg.assert_not_installed(prefix_in_view) diff --git a/var/spack/repos/builtin.mock/packages/view-not-ignored/package.py b/var/spack/repos/builtin.mock/packages/view-not-ignored/package.py new file mode 100644 index 00000000000..3342de98999 --- /dev/null +++ b/var/spack/repos/builtin.mock/packages/view-not-ignored/package.py @@ -0,0 +1,46 @@ +# 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) + +import os.path + +from spack.package import * + + +class ViewNotIgnored(Package): + """Install files that should not be ignored by spack.""" + + homepage = "http://www.spack.org" + url = "http://www.spack.org/downloads/aml-1.0.tar.gz" + has_code = False + + version("0.1.0", sha256="cc89a8768693f1f11539378b21cdca9f0ce3fc5cb564f9b3e4154a051dcea69b") + + install_test_files = [ + "foo.spack", + ".spack.bar", + "aspack", + "bin/foo.spack", + "bin/.spack.bar", + "bin/aspack", + ] + + def install(self, spec, prefix): + for test_file in self.install_test_files: + path = os.path.join(prefix, test_file) + mkdirp(os.path.dirname(path)) + with open(path, "w") as f: + f.write(test_file) + + @classmethod + def assert_installed(cls, prefix): + for test_file in cls.install_test_files: + path = os.path.join(prefix, test_file) + assert os.path.exists(path), "Missing installed file: {}".format(path) + + @classmethod + def assert_not_installed(cls, prefix): + for test_file in cls.install_test_files: + path = os.path.join(prefix, test_file) + assert not os.path.exists(path), "File was not uninstalled: {}".format(path) From 1a3415619ed8e250cf473efdfda1f0e2119d9c3d Mon Sep 17 00:00:00 2001 From: Peter Scheibel Date: Mon, 7 Nov 2022 19:24:51 -0800 Subject: [PATCH 413/442] "spack uninstall": don't modify env (#33711) "spack install foo" no longer adds package "foo" to the environment (i.e. to the list of root specs) by default: you must specify "--add". Likewise "spack uninstall foo" no longer removes package "foo" from the environment: you must specify --remove. Generally this means that install/uninstall commands will no longer modify the users list of root specs (which many users found problematic: they had to deactivate an environment if they wanted to uninstall a spec without changing their spack.yaml description). In more detail: if you have environments e1 and e2, and specs [P, Q, R] such that P depends on R, Q depends on R, [P, R] are in e1, and [Q, R] are in e2: * `spack uninstall --dependents --remove r` in e1: removes R from e1 (but does not uninstall it) and uninstalls (and removes) P * `spack uninstall -f --dependents r` in e1: will uninstall P, Q, and R (i.e. e2 will have dependent specs uninstalled as a side effect) * `spack uninstall -f --dependents --remove r` in e1: this uninstalls P, Q, and R, and removes [P, R] from e1 * `spack uninstall -f --remove r` in e1: uninstalls R (so it is "missing" in both environments) and removes R from e1 (note that e1 would still install R as a dependency of P, but it would no longer be listed as a root spec) * `spack uninstall --dependents r` in e1: will fail because e2 needs R Individual unit tests were created for each of these scenarios. --- lib/spack/spack/cmd/ci.py | 1 - lib/spack/spack/cmd/install.py | 37 +++-- lib/spack/spack/cmd/uninstall.py | 186 +++++++++++++++++-------- lib/spack/spack/test/cmd/ci.py | 5 +- lib/spack/spack/test/cmd/env.py | 46 +++++-- lib/spack/spack/test/cmd/find.py | 2 +- lib/spack/spack/test/cmd/install.py | 38 +++--- lib/spack/spack/test/cmd/uninstall.py | 187 ++++++++++++++++++++++++++ lib/spack/spack/test/modules/lmod.py | 2 +- share/spack/spack-completion.bash | 4 +- 10 files changed, 397 insertions(+), 111 deletions(-) diff --git a/lib/spack/spack/cmd/ci.py b/lib/spack/spack/cmd/ci.py index 11a47d50169..6f29da1f4d6 100644 --- a/lib/spack/spack/cmd/ci.py +++ b/lib/spack/spack/cmd/ci.py @@ -531,7 +531,6 @@ def ci_rebuild(args): slash_hash = "/{}".format(job_spec.dag_hash()) deps_install_args = install_args root_install_args = install_args + [ - "--no-add", "--keep-stage", "--only=package", "--use-buildcache=package:never,dependencies:only", diff --git a/lib/spack/spack/cmd/install.py b/lib/spack/spack/cmd/install.py index 640b48a6d0f..3f9a948a233 100644 --- a/lib/spack/spack/cmd/install.py +++ b/lib/spack/spack/cmd/install.py @@ -193,14 +193,22 @@ def setup_parser(subparser): default=False, help="(with environment) only install already concretized specs", ) - subparser.add_argument( - "--no-add", + + updateenv_group = subparser.add_mutually_exclusive_group() + updateenv_group.add_argument( + "--add", action="store_true", default=False, - help="""(with environment) partially install an environment, limiting -to concrete specs in the environment matching the arguments. -Non-roots remain installed implicitly.""", + help="""(with environment) add spec to the environment as a root.""", ) + updateenv_group.add_argument( + "--no-add", + action="store_false", + dest="add", + help="""(with environment) do not add spec to the environment as a +root (the default behavior).""", + ) + subparser.add_argument( "-f", "--file", @@ -289,11 +297,12 @@ def install_specs_inside_environment(specs, install_kwargs, cli_args): # the matches. Getting to this point means there were either # no matches or exactly one match. - if not m_spec and cli_args.no_add: + if not m_spec and not cli_args.add: msg = ( - "You asked to install {0} without adding it (--no-add), but no such spec " - "exists in environment" - ).format(abstract.name) + "Cannot install '{0}' because it is not in the current environment." + " You can add it to the environment with 'spack add {0}', or as part" + " of the install command with 'spack install --add {0}'" + ).format(str(abstract)) tty.die(msg) if not m_spec: @@ -303,14 +312,16 @@ def install_specs_inside_environment(specs, install_kwargs, cli_args): tty.debug("exactly one match for {0} in env -> {1}".format(m_spec.name, m_spec.dag_hash())) - if m_spec in env.roots() or cli_args.no_add: - # either the single match is a root spec (and --no-add is - # the default for roots) or --no-add was stated explicitly + if m_spec in env.roots() or not cli_args.add: + # either the single match is a root spec (in which case + # the spec is not added to the env again), or the user did + # not specify --add (in which case it is assumed we are + # installing already-concretized specs in the env) tty.debug("just install {0}".format(m_spec.name)) specs_to_install.append(m_spec) else: # the single match is not a root (i.e. it's a dependency), - # and --no-add was not specified, so we'll add it as a + # and --add was specified, so we'll add it as a # root before installing tty.debug("add {0} then install it".format(m_spec.name)) specs_to_add.append((abstract, concrete)) diff --git a/lib/spack/spack/cmd/uninstall.py b/lib/spack/spack/cmd/uninstall.py index af85b64188b..8c112840fd6 100644 --- a/lib/spack/spack/cmd/uninstall.py +++ b/lib/spack/spack/cmd/uninstall.py @@ -5,7 +5,6 @@ from __future__ import print_function -import itertools import sys from llnl.util import tty @@ -61,6 +60,13 @@ def setup_parser(subparser): dest="force", help="remove regardless of whether other packages or environments " "depend on this one", ) + subparser.add_argument( + "--remove", + action="store_true", + dest="remove", + help="if in an environment, then the spec should also be removed from " + "the environment description", + ) arguments.add_common_arguments( subparser, ["recurse_dependents", "yes_to_all", "installed_specs"] ) @@ -134,13 +140,21 @@ def installed_dependents(specs, env): env (spack.environment.Environment or None): the active environment, or None Returns: - tuple: two mappings: one from specs to their dependent environments in the - active environment (or global scope if there is no environment), and one from - specs to their dependents in *inactive* environments (empty if there is no - environment + tuple: two mappings: one from specs to their dependent installs in the + active environment, and one from specs to dependent installs outside of + the active environment. + + Any of the input specs may appear in both mappings (if there are + dependents both inside and outside the current environment). + + If a dependent spec is used both by the active environment and by + an inactive environment, it will only appear in the first mapping. + + If there is not current active environment, the first mapping will be + empty. """ active_dpts = {} - inactive_dpts = {} + outside_dpts = {} env_hashes = set(env.all_hashes()) if env else set() @@ -153,12 +167,12 @@ def installed_dependents(specs, env): # dpts that are outside this environment for dpt in installed: if dpt not in specs: - if not env or dpt.dag_hash() in env_hashes: + if dpt.dag_hash() in env_hashes: active_dpts.setdefault(spec, set()).add(dpt) else: - inactive_dpts.setdefault(spec, set()).add(dpt) + outside_dpts.setdefault(spec, set()).add(dpt) - return active_dpts, inactive_dpts + return active_dpts, outside_dpts def dependent_environments(specs): @@ -262,31 +276,65 @@ def is_ready(dag_hash): def get_uninstall_list(args, specs, env): - # Gets the list of installed specs that match the ones give via cli + """Returns uninstall_list and remove_list: these may overlap (some things + may be both uninstalled and removed from the current environment). + + It is assumed we are in an environment if --remove is specified (this + method raises an exception otherwise). + + uninstall_list is topologically sorted: dependents come before + dependencies (so if a user uninstalls specs in the order provided, + the dependents will always be uninstalled first). + """ + if args.remove and not env: + raise ValueError("Can only use --remove when in an environment") + + # Gets the list of installed specs that match the ones given via cli # args.all takes care of the case where '-a' is given in the cli - uninstall_list = find_matching_specs(env, specs, args.all, args.force, args.origin) + base_uninstall_specs = set(find_matching_specs(env, specs, args.all, args.force)) - # Takes care of '-R' - active_dpts, inactive_dpts = installed_dependents(uninstall_list, env) + active_dpts, outside_dpts = installed_dependents(base_uninstall_specs, env) + # It will be useful to track the unified set of specs with dependents, as + # well as to separately track specs in the current env with dependents + spec_to_dpts = {} + for spec, dpts in active_dpts.items(): + spec_to_dpts[spec] = list(dpts) + for spec, dpts in outside_dpts.items(): + if spec in spec_to_dpts: + spec_to_dpts[spec].extend(dpts) + else: + spec_to_dpts[spec] = list(dpts) - # if we are in the global scope, we complain if you try to remove a - # spec that's in an environment. If we're in an environment, we'll - # just *remove* it from the environment, so we ignore this - # error when *in* an environment - spec_envs = dependent_environments(uninstall_list) - spec_envs = inactive_dependent_environments(spec_envs) + all_uninstall_specs = set(base_uninstall_specs) + if args.dependents: + for spec, lst in active_dpts.items(): + all_uninstall_specs.update(lst) + for spec, lst in outside_dpts.items(): + all_uninstall_specs.update(lst) - # Process spec_dependents and update uninstall_list - has_error = not args.force and ( - (active_dpts and not args.dependents) # dependents in the current env - or (not env and spec_envs) # there are environments that need specs + # For each spec that we intend to uninstall, this tracks the set of + # environments outside the current active environment which depend on the + # spec. There may be environments not managed directly with Spack: such + # environments would not be included here. + spec_to_other_envs = inactive_dependent_environments( + dependent_environments(all_uninstall_specs) + ) + + has_error = not args.force and ( + # There are dependents in the current env and we didn't ask to remove + # dependents + (spec_to_dpts and not args.dependents) + # An environment different than the current env (if any) depends on + # one or more of the specs to be uninstalled. There may also be + # packages in those envs which depend on the base set of packages + # to uninstall, but this covers that scenario. + or (not args.remove and spec_to_other_envs) ) - # say why each problem spec is needed if has_error: - specs = set(active_dpts) - if not env: - specs.update(set(spec_envs)) # environments depend on this + # say why each problem spec is needed + specs = set(spec_to_dpts) + specs.update(set(spec_to_other_envs)) # environments depend on this for i, spec in enumerate(sorted(specs)): # space out blocks of reasons @@ -296,66 +344,86 @@ def get_uninstall_list(args, specs, env): spec_format = "{name}{@version}{%compiler}{/hash:7}" tty.info("Will not uninstall %s" % spec.cformat(spec_format), format="*r") - dependents = active_dpts.get(spec) - if dependents: + dependents = spec_to_dpts.get(spec) + if dependents and not args.dependents: print("The following packages depend on it:") spack.cmd.display_specs(dependents, **display_args) - if not env: - envs = spec_envs.get(spec) - if envs: - print("It is used by the following environments:") - colify([e.name for e in envs], indent=4) + envs = spec_to_other_envs.get(spec) + if envs: + if env: + env_context_qualifier = " other" + else: + env_context_qualifier = "" + print("It is used by the following{0} environments:".format(env_context_qualifier)) + colify([e.name for e in envs], indent=4) msgs = [] - if active_dpts: + if spec_to_dpts and not args.dependents: msgs.append("use `spack uninstall --dependents` to remove dependents too") - if spec_envs: + if spec_to_other_envs: msgs.append("use `spack env remove` to remove from environments") print() tty.die("There are still dependents.", *msgs) - elif args.dependents: - for spec, lst in active_dpts.items(): - uninstall_list.extend(lst) - uninstall_list = list(set(uninstall_list)) + # If we are in an environment, this will track specs in this environment + # which should only be removed from the environment rather than uninstalled + remove_only = set() + if args.remove and not args.force: + remove_only.update(spec_to_other_envs) + if remove_only: + tty.info( + "The following specs will be removed but not uninstalled because" + " they are also used by another environment: {speclist}".format( + speclist=", ".join(x.name for x in remove_only) + ) + ) - # only force-remove (don't completely uninstall) specs that still - # have external dependent envs or pkgs - removes = set(inactive_dpts) - if env: - removes.update(spec_envs) + # Compute the set of specs that should be removed from the current env. + # This may overlap (some specs may be uninstalled and also removed from + # the current environment). + if args.remove: + remove_specs = set(base_uninstall_specs) + if args.dependents: + # Any spec matched from the cli, or dependent of, should be removed + # from the environment + for spec, lst in active_dpts.items(): + remove_specs.update(lst) + else: + remove_specs = set() - # remove anything in removes from the uninstall list - uninstall_list = set(uninstall_list) - removes + all_uninstall_specs -= remove_only + # Inefficient topological sort: uninstall dependents before dependencies + all_uninstall_specs = sorted( + all_uninstall_specs, key=lambda x: sum(1 for i in x.traverse()), reverse=True + ) - return uninstall_list, removes + return list(all_uninstall_specs), list(remove_specs) def uninstall_specs(args, specs): env = ev.active_environment() uninstall_list, remove_list = get_uninstall_list(args, specs, env) - anything_to_do = set(uninstall_list).union(set(remove_list)) - if not anything_to_do: + if not uninstall_list: tty.warn("There are no package to uninstall.") return if not args.yes_to_all: - confirm_removal(anything_to_do) - - if env: - # Remove all the specs that are supposed to be uninstalled or just - # removed. - with env.write_transaction(): - for spec in itertools.chain(remove_list, uninstall_list): - _remove_from_env(spec, env) - env.write() + confirm_removal(uninstall_list) # Uninstall everything on the list do_uninstall(env, uninstall_list, args.force) + if env: + with env.write_transaction(): + for spec in remove_list: + _remove_from_env(spec, env) + env.write() + + env.regenerate_views() + def confirm_removal(specs): """Display the list of specs to be removed and ask for confirmation. diff --git a/lib/spack/spack/test/cmd/ci.py b/lib/spack/spack/test/cmd/ci.py index b2e84e0c027..73b474c7dfd 100644 --- a/lib/spack/spack/test/cmd/ci.py +++ b/lib/spack/spack/test/cmd/ci.py @@ -1011,7 +1011,6 @@ def mystrip(s): assert "--keep-stage" in install_parts assert "--no-check-signature" not in install_parts - assert "--no-add" in install_parts assert "-f" in install_parts flag_index = install_parts.index("-f") assert "archive-files.json" in install_parts[flag_index + 1] @@ -1261,7 +1260,7 @@ def test_push_mirror_contents( with open(json_path, "w") as ypfd: ypfd.write(spec_json) - install_cmd("--keep-stage", json_path) + install_cmd("--add", "--keep-stage", json_path) # env, spec, json_path, mirror_url, build_id, sign_binaries ci.push_mirror_contents(env, json_path, mirror_url, True) @@ -1623,7 +1622,7 @@ def test_ci_rebuild_index( with open(json_path, "w") as ypfd: ypfd.write(spec_json) - install_cmd("--keep-stage", "-f", json_path) + install_cmd("--add", "--keep-stage", "-f", json_path) buildcache_cmd("create", "-u", "-a", "-f", "--mirror-url", mirror_url, "callpath") ci_cmd("rebuild-index") diff --git a/lib/spack/spack/test/cmd/env.py b/lib/spack/spack/test/cmd/env.py index 801ff04669e..6782e651798 100644 --- a/lib/spack/spack/test/cmd/env.py +++ b/lib/spack/spack/test/cmd/env.py @@ -221,7 +221,7 @@ def test_env_install_single_spec(install_mockery, mock_fetch): e = ev.read("test") with e: - install("cmake-client") + install("--add", "cmake-client") e = ev.read("test") assert e.user_specs[0].name == "cmake-client" @@ -256,7 +256,7 @@ def test_env_modifications_error_on_activate(install_mockery, mock_fetch, monkey e = ev.read("test") with e: - install("cmake-client") + install("--add", "cmake-client") def setup_error(pkg, env): raise RuntimeError("cmake-client had issues!") @@ -277,7 +277,7 @@ def test_activate_adds_transitive_run_deps_to_path(install_mockery, mock_fetch, e = ev.read("test") with e: - install("depends-on-run-env") + install("--add", "depends-on-run-env") env_variables = {} spack.environment.shell.activate(e).apply_modifications(env_variables) @@ -290,7 +290,7 @@ def test_env_install_same_spec_twice(install_mockery, mock_fetch): e = ev.read("test") with e: # The first installation outputs the package prefix, updates the view - out = install("cmake-client") + out = install("--add", "cmake-client") assert "Updating view at" in out # The second installation reports all packages already installed @@ -449,7 +449,7 @@ def test_env_status_broken_view( ): env_dir = str(tmpdir) with ev.Environment(env_dir): - install("trivial-install-test-package") + install("--add", "trivial-install-test-package") # switch to a new repo that doesn't include the installed package # test that Spack detects the missing package and warns the user @@ -468,7 +468,7 @@ def test_env_activate_broken_view( mutable_mock_env_path, mock_archive, mock_fetch, mock_custom_repository, install_mockery ): with ev.create("test"): - install("trivial-install-test-package") + install("--add", "trivial-install-test-package") # switch to a new repo that doesn't include the installed package # test that Spack detects the missing package and fails gracefully @@ -1057,7 +1057,9 @@ def test_roots_display_with_variants(): assert "boost +shared" in out -def test_uninstall_removes_from_env(mock_stage, mock_fetch, install_mockery): +def test_uninstall_keeps_in_env(mock_stage, mock_fetch, install_mockery): + # 'spack uninstall' without --remove should not change the environment + # spack.yaml file, just uninstall specs env("create", "test") with ev.read("test"): add("mpileaks") @@ -1065,12 +1067,32 @@ def test_uninstall_removes_from_env(mock_stage, mock_fetch, install_mockery): install("--fake") test = ev.read("test") - assert any(s.name == "mpileaks" for s in test.specs_by_hash.values()) - assert any(s.name == "libelf" for s in test.specs_by_hash.values()) + # Save this spec to check later if it is still in the env + (mpileaks_hash,) = list(x for x, y in test.specs_by_hash.items() if y.name == "mpileaks") + orig_user_specs = test.user_specs + orig_concretized_specs = test.concretized_order with ev.read("test"): uninstall("-ya") + test = ev.read("test") + assert test.concretized_order == orig_concretized_specs + assert test.user_specs.specs == orig_user_specs.specs + assert mpileaks_hash in test.specs_by_hash + assert not test.specs_by_hash[mpileaks_hash].package.installed + + +def test_uninstall_removes_from_env(mock_stage, mock_fetch, install_mockery): + # 'spack uninstall --remove' should update the environment + env("create", "test") + with ev.read("test"): + add("mpileaks") + add("libelf") + install("--fake") + + with ev.read("test"): + uninstall("-y", "-a", "--remove") + test = ev.read("test") assert not test.specs_by_hash assert not test.concretized_order @@ -1256,7 +1278,7 @@ def test_env_updates_view_install_package(tmpdir, mock_stage, mock_fetch, instal view_dir = tmpdir.join("view") env("create", "--with-view=%s" % view_dir, "test") with ev.read("test"): - install("--fake", "mpileaks") + install("--fake", "--add", "mpileaks") assert os.path.exists(str(view_dir.join(".spack/mpileaks"))) @@ -1276,7 +1298,7 @@ def test_env_updates_view_uninstall(tmpdir, mock_stage, mock_fetch, install_mock view_dir = tmpdir.join("view") env("create", "--with-view=%s" % view_dir, "test") with ev.read("test"): - install("--fake", "mpileaks") + install("--fake", "--add", "mpileaks") check_mpileaks_and_deps_in_view(view_dir) @@ -1325,7 +1347,7 @@ def test_env_updates_view_force_remove(tmpdir, mock_stage, mock_fetch, install_m view_dir = tmpdir.join("view") env("create", "--with-view=%s" % view_dir, "test") with ev.read("test"): - install("--fake", "mpileaks") + install("--add", "--fake", "mpileaks") check_mpileaks_and_deps_in_view(view_dir) diff --git a/lib/spack/spack/test/cmd/find.py b/lib/spack/spack/test/cmd/find.py index be83541096b..9f3f453bad5 100644 --- a/lib/spack/spack/test/cmd/find.py +++ b/lib/spack/spack/test/cmd/find.py @@ -356,7 +356,7 @@ def test_find_prefix_in_env( """Test `find` formats requiring concrete specs work in environments.""" env("create", "test") with ev.read("test"): - install("mpileaks") + install("--add", "mpileaks") find("-p") find("-l") find("-L") diff --git a/lib/spack/spack/test/cmd/install.py b/lib/spack/spack/test/cmd/install.py index 843e539eeab..67e0dd3f80a 100644 --- a/lib/spack/spack/test/cmd/install.py +++ b/lib/spack/spack/test/cmd/install.py @@ -771,7 +771,7 @@ def test_install_only_dependencies_in_env( dep = Spec("dependency-install").concretized() root = Spec("dependent-install").concretized() - install("-v", "--only", "dependencies", "dependent-install") + install("-v", "--only", "dependencies", "--add", "dependent-install") assert os.path.exists(dep.prefix) assert not os.path.exists(root.prefix) @@ -800,7 +800,7 @@ def test_install_only_dependencies_of_all_in_env( def test_install_no_add_in_env(tmpdir, mock_fetch, install_mockery, mutable_mock_env_path): - # To test behavior of --no-add option, we create the following environment: + # To test behavior of --add option, we create the following environment: # # mpileaks # ^callpath @@ -849,18 +849,19 @@ def test_install_no_add_in_env(tmpdir, mock_fetch, install_mockery, mutable_mock # Assert using --no-add with a spec not in the env fails inst_out = install("--no-add", "boost", fail_on_error=False, output=str) - assert "no such spec exists in environment" in inst_out + assert "You can add it to the environment with 'spack add " in inst_out - # Ensure using --no-add with an ambiguous spec fails + # Without --add, ensure that install fails if the spec matches more + # than one root with pytest.raises(ev.SpackEnvironmentError) as err: - inst_out = install("--no-add", "a", output=str) + inst_out = install("a", output=str) assert "a matches multiple specs in the env" in str(err) - # With "--no-add", install an unambiguous dependency spec (that already - # exists as a dep in the environment) using --no-add and make sure it - # gets installed (w/ deps), but is not added to the environment. - install("--no-add", "dyninst") + # Install an unambiguous dependency spec (that already exists as a dep + # in the environment) and make sure it gets installed (w/ deps), + # but is not added to the environment. + install("dyninst") find_output = find("-l", output=str) assert "dyninst" in find_output @@ -872,31 +873,30 @@ def test_install_no_add_in_env(tmpdir, mock_fetch, install_mockery, mutable_mock assert all([s in env_specs for s in post_install_specs]) # Make sure we can install a concrete dependency spec from a spec.json - # file on disk, using the ``--no-add` option, and the spec is installed - # but not added as a root + # file on disk, and the spec is installed but not added as a root mpi_spec_json_path = tmpdir.join("{0}.json".format(mpi_spec.name)) with open(mpi_spec_json_path.strpath, "w") as fd: fd.write(mpi_spec.to_json(hash=ht.dag_hash)) - install("--no-add", "-f", mpi_spec_json_path.strpath) + install("-f", mpi_spec_json_path.strpath) assert mpi_spec not in e.roots() find_output = find("-l", output=str) assert mpi_spec.name in find_output - # Without "--no-add", install an unambiguous depependency spec (that - # already exists as a dep in the environment) without --no-add and make - # sure it is added as a root of the environment as well as installed. + # Install an unambiguous depependency spec (that already exists as a + # dep in the environment) with --add and make sure it is added as a + # root of the environment as well as installed. assert b_spec not in e.roots() - install("b") + install("--add", "b") assert b_spec in e.roots() assert b_spec not in e.uninstalled_specs() - # Without "--no-add", install a novel spec and make sure it is added - # as a root and installed. - install("bowtie") + # Install a novel spec with --add and make sure it is added as a root + # and installed. + install("--add", "bowtie") assert any([s.name == "bowtie" for s in e.roots()]) assert not any([s.name == "bowtie" for s in e.uninstalled_specs()]) diff --git a/lib/spack/spack/test/cmd/uninstall.py b/lib/spack/spack/test/cmd/uninstall.py index a47f6c60a57..ddbd54e2529 100644 --- a/lib/spack/spack/test/cmd/uninstall.py +++ b/lib/spack/spack/test/cmd/uninstall.py @@ -3,10 +3,13 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import sys + import pytest import llnl.util.tty as tty +import spack.environment import spack.store from spack.main import SpackCommand, SpackCommandError @@ -166,3 +169,187 @@ def _warn(*args, **kwargs): monkeypatch.setattr(tty, "warn", _warn) # Now try to uninstall and check this doesn't trigger warnings uninstall("-y", "-a") + + +# Note: I want to use https://docs.pytest.org/en/7.1.x/how-to/skipping.html#skip-all-test-functions-of-a-class-or-module +# the style formatter insists on separating these two lines. +pytest.mark.skipif(sys.platform == "win32", reason="Envs unsupported on Windows") + + +class TestUninstallFromEnv(object): + """Tests an installation with two environments e1 and e2, which each have + shared package installations: + + e1 has dt-diamond-left -> dt-diamond-bottom + + e2 has dt-diamond-right -> dt-diamond-bottom + """ + + env = SpackCommand("env") + add = SpackCommand("add") + concretize = SpackCommand("concretize") + find = SpackCommand("find") + + @pytest.fixture + def environment_setup( + self, mutable_mock_env_path, config, mock_packages, mutable_database, install_mockery + ): + TestUninstallFromEnv.env("create", "e1") + e1 = spack.environment.read("e1") + with e1: + TestUninstallFromEnv.add("dt-diamond-left") + TestUninstallFromEnv.add("dt-diamond-bottom") + TestUninstallFromEnv.concretize() + install("--fake") + + TestUninstallFromEnv.env("create", "e2") + e2 = spack.environment.read("e2") + with e2: + TestUninstallFromEnv.add("dt-diamond-right") + TestUninstallFromEnv.add("dt-diamond-bottom") + TestUninstallFromEnv.concretize() + install("--fake") + + def test_basic_env_sanity(self, environment_setup): + for env_name in ["e1", "e2"]: + e = spack.environment.read(env_name) + with e: + for _, concretized_spec in e.concretized_specs(): + assert concretized_spec.package.installed + + def test_uninstall_force_dependency_shared_between_envs(self, environment_setup): + """If you "spack uninstall -f --dependents dt-diamond-bottom" from + e1, then all packages should be uninstalled (but not removed) from + both e1 and e2. + """ + e1 = spack.environment.read("e1") + with e1: + uninstall("-f", "-y", "--dependents", "dt-diamond-bottom") + + # The specs should still be in the environment, since + # --remove was not specified + assert set(root.name for (root, _) in e1.concretized_specs()) == set( + ["dt-diamond-left", "dt-diamond-bottom"] + ) + + for _, concretized_spec in e1.concretized_specs(): + assert not concretized_spec.package.installed + + # Everything in e2 depended on dt-diamond-bottom, so should also + # have been uninstalled. The roots should be unchanged though. + e2 = spack.environment.read("e2") + with e2: + assert set(root.name for (root, _) in e2.concretized_specs()) == set( + ["dt-diamond-right", "dt-diamond-bottom"] + ) + for _, concretized_spec in e2.concretized_specs(): + assert not concretized_spec.package.installed + + def test_uninstall_remove_dependency_shared_between_envs(self, environment_setup): + """If you "spack uninstall --dependents --remove dt-diamond-bottom" from + e1, then all packages are removed from e1 (it is now empty); + dt-diamond-left is also uninstalled (since only e1 needs it) but + dt-diamond-bottom is not uninstalled (since e2 needs it). + """ + e1 = spack.environment.read("e1") + with e1: + dtdiamondleft = next( + concrete + for (_, concrete) in e1.concretized_specs() + if concrete.name == "dt-diamond-left" + ) + output = uninstall("-y", "--dependents", "--remove", "dt-diamond-bottom") + assert "The following specs will be removed but not uninstalled" in output + assert not list(e1.roots()) + assert not dtdiamondleft.package.installed + + # Since -f was not specified, all specs in e2 should still be installed + # (and e2 should be unchanged) + e2 = spack.environment.read("e2") + with e2: + assert set(root.name for (root, _) in e2.concretized_specs()) == set( + ["dt-diamond-right", "dt-diamond-bottom"] + ) + for _, concretized_spec in e2.concretized_specs(): + assert concretized_spec.package.installed + + def test_uninstall_dependency_shared_between_envs_fail(self, environment_setup): + """If you "spack uninstall --dependents dt-diamond-bottom" from + e1 (without --remove or -f), then this should fail (this is needed by + e2). + """ + e1 = spack.environment.read("e1") + with e1: + output = uninstall("-y", "--dependents", "dt-diamond-bottom", fail_on_error=False) + assert "There are still dependents." in output + assert "use `spack env remove`" in output + + # The environment should be unchanged and nothing should have been + # uninstalled + assert set(root.name for (root, _) in e1.concretized_specs()) == set( + ["dt-diamond-left", "dt-diamond-bottom"] + ) + for _, concretized_spec in e1.concretized_specs(): + assert concretized_spec.package.installed + + def test_uninstall_force_and_remove_dependency_shared_between_envs(self, environment_setup): + """If you "spack uninstall -f --dependents --remove dt-diamond-bottom" from + e1, then all packages should be uninstalled and removed from e1. + All packages will also be uninstalled from e2, but the roots will + remain unchanged. + """ + e1 = spack.environment.read("e1") + with e1: + dtdiamondleft = next( + concrete + for (_, concrete) in e1.concretized_specs() + if concrete.name == "dt-diamond-left" + ) + uninstall("-f", "-y", "--dependents", "--remove", "dt-diamond-bottom") + assert not list(e1.roots()) + assert not dtdiamondleft.package.installed + + e2 = spack.environment.read("e2") + with e2: + assert set(root.name for (root, _) in e2.concretized_specs()) == set( + ["dt-diamond-right", "dt-diamond-bottom"] + ) + for _, concretized_spec in e2.concretized_specs(): + assert not concretized_spec.package.installed + + def test_uninstall_keep_dependents_dependency_shared_between_envs(self, environment_setup): + """If you "spack uninstall -f --remove dt-diamond-bottom" from + e1, then dt-diamond-bottom should be uninstalled, which leaves + "dangling" references in both environments, since + dt-diamond-left and dt-diamond-right both need it. + """ + e1 = spack.environment.read("e1") + with e1: + dtdiamondleft = next( + concrete + for (_, concrete) in e1.concretized_specs() + if concrete.name == "dt-diamond-left" + ) + uninstall("-f", "-y", "--remove", "dt-diamond-bottom") + # dt-diamond-bottom was removed from the list of roots (note that + # it would still be installed since dt-diamond-left depends on it) + assert set(x.name for x in e1.roots()) == set(["dt-diamond-left"]) + assert dtdiamondleft.package.installed + + e2 = spack.environment.read("e2") + with e2: + assert set(root.name for (root, _) in e2.concretized_specs()) == set( + ["dt-diamond-right", "dt-diamond-bottom"] + ) + dtdiamondright = next( + concrete + for (_, concrete) in e2.concretized_specs() + if concrete.name == "dt-diamond-right" + ) + assert dtdiamondright.package.installed + dtdiamondbottom = next( + concrete + for (_, concrete) in e2.concretized_specs() + if concrete.name == "dt-diamond-bottom" + ) + assert not dtdiamondbottom.package.installed diff --git a/lib/spack/spack/test/modules/lmod.py b/lib/spack/spack/test/modules/lmod.py index d24ec8ca0d3..5d0d04032eb 100644 --- a/lib/spack/spack/test/modules/lmod.py +++ b/lib/spack/spack/test/modules/lmod.py @@ -298,7 +298,7 @@ def test_modules_relative_to_view( ): with ev.Environment(str(tmpdir), with_view=True) as e: module_configuration("with_view") - install("cmake") + install("--add", "cmake") spec = spack.spec.Spec("cmake").concretized() diff --git a/share/spack/spack-completion.bash b/share/spack/spack-completion.bash index f0588e5368c..2461a0b7c77 100755 --- a/share/spack/spack-completion.bash +++ b/share/spack/spack-completion.bash @@ -1203,7 +1203,7 @@ _spack_info() { _spack_install() { if $list_options then - SPACK_COMPREPLY="-h --help --only -u --until -j --jobs --overwrite --fail-fast --keep-prefix --keep-stage --dont-restage --use-cache --no-cache --cache-only --use-buildcache --include-build-deps --no-check-signature --show-log-on-error --source -n --no-checksum --deprecated -v --verbose --fake --only-concrete --no-add -f --file --clean --dirty --test --log-format --log-file --help-cdash --cdash-upload-url --cdash-build --cdash-site --cdash-track --cdash-buildstamp -y --yes-to-all -U --fresh --reuse" + SPACK_COMPREPLY="-h --help --only -u --until -j --jobs --overwrite --fail-fast --keep-prefix --keep-stage --dont-restage --use-cache --no-cache --cache-only --use-buildcache --include-build-deps --no-check-signature --show-log-on-error --source -n --no-checksum --deprecated -v --verbose --fake --only-concrete --add --no-add -f --file --clean --dirty --test --log-format --log-file --help-cdash --cdash-upload-url --cdash-build --cdash-site --cdash-track --cdash-buildstamp -y --yes-to-all -U --fresh --reuse" else _all_packages fi @@ -1824,7 +1824,7 @@ _spack_undevelop() { _spack_uninstall() { if $list_options then - SPACK_COMPREPLY="-h --help -f --force -R --dependents -y --yes-to-all -a --all --origin" + SPACK_COMPREPLY="-h --help -f --force --remove -R --dependents -y --yes-to-all -a --all --origin" else _installed_packages fi From 23eb2dc9d6cc8712872252c9cba94a876e0b6560 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Chevalier?= Date: Tue, 8 Nov 2022 04:30:23 +0100 Subject: [PATCH 414/442] Add zstd support for elfutils (#33695) * Add zstd support for elfutils Not defining `+zstd` implies `--without-zstd` flag to configure. This avoids automatic library detection and thus make the build only depends on Spack installed dependencies. * Use autotools helper "with_or_without" * Revert use of with_or_without Using `with_or_without()` with `variant` keyword does not seem to work. --- var/spack/repos/builtin/packages/elfutils/package.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/var/spack/repos/builtin/packages/elfutils/package.py b/var/spack/repos/builtin/packages/elfutils/package.py index b8909e88cb6..a865d9785a4 100644 --- a/var/spack/repos/builtin/packages/elfutils/package.py +++ b/var/spack/repos/builtin/packages/elfutils/package.py @@ -47,6 +47,7 @@ class Elfutils(AutotoolsPackage, SourcewarePackage): # Libraries for reading compressed DWARF sections. variant("bzip2", default=False, description="Support bzip2 compressed sections.") variant("xz", default=False, description="Support xz (lzma) compressed sections.") + variant("zstd", default=False, description="Support zstd compressed sections.", when="@0.182:") # Native language support from libintl. variant("nls", default=True, description="Enable Native Language Support.") @@ -70,6 +71,7 @@ class Elfutils(AutotoolsPackage, SourcewarePackage): depends_on("bzip2", type="link", when="+bzip2") depends_on("xz", type="link", when="+xz") + depends_on("zstd", type="link", when="+zstd") depends_on("zlib", type="link") depends_on("gettext", when="+nls") depends_on("m4", type="build") @@ -115,6 +117,8 @@ def configure_args(self): else: args.append("--without-lzma") + args.extend(self.with_or_without("zstd", activation_value="prefix")) + # zlib is required args.append("--with-zlib=%s" % spec["zlib"].prefix) From 54abc7fb7e4b3c6a639c60f0b086d9100c3daf1d Mon Sep 17 00:00:00 2001 From: "Adam J. Stewart" Date: Mon, 7 Nov 2022 19:42:35 -0800 Subject: [PATCH 415/442] PyTorch: add v1.13.0 (#33596) * PyTorch: add v1.13.0 * py-torchaudio: add v0.13.0 * py-torchaudio: add all versions * py-torchvision: jpeg required for all backends * py-torchtext: add v0.14.0 * py-torchtext: fix build * py-torchaudio: fix build * py-torchtext: update version tag * Use Spack-built sox * Explicitly disable sox build * https -> http --- .../repos/builtin/packages/flac/package.py | 4 +- .../builtin/packages/py-torch/package.py | 95 +++++++++++-------- .../builtin/packages/py-torchaudio/package.py | 78 ++++++++++++++- .../builtin/packages/py-torchdata/package.py | 2 +- .../builtin/packages/py-torchtext/package.py | 47 +++++++-- .../packages/py-torchvision/package.py | 22 +++-- .../repos/builtin/packages/sox/package.py | 1 - 7 files changed, 185 insertions(+), 64 deletions(-) diff --git a/var/spack/repos/builtin/packages/flac/package.py b/var/spack/repos/builtin/packages/flac/package.py index 0ff0527fe1d..7d6f5b6bcac 100644 --- a/var/spack/repos/builtin/packages/flac/package.py +++ b/var/spack/repos/builtin/packages/flac/package.py @@ -12,10 +12,10 @@ class Flac(AutotoolsPackage): homepage = "https://xiph.org/flac/index.html" url = "http://downloads.xiph.org/releases/flac/flac-1.3.2.tar.xz" + version("1.4.2", sha256="e322d58a1f48d23d9dd38f432672865f6f79e73a6f9cc5a5f57fcaa83eb5a8e4") version("1.3.3", sha256="213e82bd716c9de6db2f98bcadbc4c24c7e2efe8c75939a1a84e28539c4e1748") version("1.3.2", sha256="91cfc3ed61dc40f47f050a109b08610667d73477af6ef36dcad31c31a4a8d53f") version("1.3.1", sha256="4773c0099dba767d963fd92143263be338c48702172e8754b9bc5103efe1c56c") version("1.3.0", sha256="fa2d64aac1f77e31dfbb270aeb08f5b32e27036a52ad15e69a77e309528010dc") - depends_on("libvorbis") - depends_on("id3lib") + depends_on("libogg@1.1.2:") diff --git a/var/spack/repos/builtin/packages/py-torch/package.py b/var/spack/repos/builtin/packages/py-torch/package.py index 9e5a9a8cef3..b6e5ed6b1fe 100644 --- a/var/spack/repos/builtin/packages/py-torch/package.py +++ b/var/spack/repos/builtin/packages/py-torch/package.py @@ -24,6 +24,7 @@ class PyTorch(PythonPackage, CudaPackage, ROCmPackage): import_modules = ["torch", "torch.autograd", "torch.nn", "torch.utils"] version("master", branch="master", submodules=True) + version("1.13.0", tag="v1.13.0", submodules=True) version("1.12.1", tag="v1.12.1", submodules=True) version("1.12.0", tag="v1.12.0", submodules=True) version("1.11.0", tag="v1.11.0", submodules=True) @@ -115,11 +116,6 @@ class PyTorch(PythonPackage, CudaPackage, ROCmPackage): ) # Required dependencies - depends_on("cmake@3.13:", when="@1.11:", type="build") - depends_on("cmake@3.10:", when="@1.10:", type="build") - depends_on("cmake@3.5:", type="build") - # Use Ninja generator to speed up build times, automatically used if found - depends_on("ninja@1.5:", when="@1.1:", type="build") # See python_min_version in setup.py depends_on("python@3.7:", when="@1.11:", type=("build", "link", "run")) depends_on("python@3.6.2:", when="@1.7.1:", type=("build", "link", "run")) @@ -127,18 +123,35 @@ class PyTorch(PythonPackage, CudaPackage, ROCmPackage): depends_on("python@3.5:", when="@1.5", type=("build", "link", "run")) depends_on("python@2.7:2,3.5:", when="@1.4", type=("build", "link", "run")) depends_on("python@2.7:2,3.5:3.7", when="@:1.3", type=("build", "link", "run")) + + # pyproject.toml depends_on("py-setuptools", type=("build", "run")) + depends_on("py-astunparse", when="@1.13:", type=("build", "run")) + depends_on("py-numpy@1.16.6:", type=("build", "run")) + depends_on("ninja@1.5:", when="@1.1:", type="build") + depends_on("py-pyyaml", type=("build", "run")) + depends_on("cmake@3.13:", when="@1.11:", type="build") + depends_on("cmake@3.10:", when="@1.10:", type="build") + depends_on("cmake@3.5:", type="build") + depends_on("py-cffi", type=("build", "run")) + depends_on("py-typing-extensions@3.6.2.1:", when="@1.7:", type=("build", "run")) depends_on("py-future", when="@1.5:", type=("build", "run")) depends_on("py-future", when="@1.1: ^python@:2", type=("build", "run")) - depends_on("py-pyyaml", type=("build", "run")) + depends_on("py-six", when="@1.13:", type=("build", "run")) + depends_on("py-requests", when="@1.13:", type=("build", "run")) + depends_on("py-dataclasses", when="@1.7: ^python@3.6", type=("build", "run")) + + # Undocumented dependencies depends_on("py-typing", when="^python@:3.4", type=("build", "run")) - depends_on("py-pybind11@2.6.2", when="@1.8:", type=("build", "link", "run")) + depends_on("py-tqdm", type="run") + depends_on("blas") + depends_on("lapack") + + # third_party + depends_on("py-pybind11@2.10.0", when="@1.13:", type=("build", "link", "run")) + depends_on("py-pybind11@2.6.2", when="@1.8:1.12", type=("build", "link", "run")) depends_on("py-pybind11@2.3.0", when="@1.1:1.7", type=("build", "link", "run")) depends_on("py-pybind11@2.2.4", when="@:1.0", type=("build", "link", "run")) - depends_on("py-dataclasses", when="@1.7: ^python@3.6", type=("build", "run")) - depends_on("py-tqdm", type="run") - # https://github.com/onnx/onnx#prerequisites - depends_on("py-numpy@1.16.6:", type=("build", "run")) depends_on("py-protobuf@3.12.2:", when="@1.10:", type=("build", "run")) depends_on("py-protobuf@:3.14", when="@:1.9", type=("build", "run")) depends_on("protobuf@3.12.2:", when="@1.10:") @@ -147,19 +160,17 @@ class PyTorch(PythonPackage, CudaPackage, ROCmPackage): # https://github.com/pytorch/pytorch/issues/78362 depends_on("py-protobuf@:3", type=("build", "run")) depends_on("protobuf@:3", type=("build", "run")) - depends_on("py-typing-extensions@3.6.2.1:", when="@1.7:", type=("build", "run")) - depends_on("blas") - depends_on("lapack") depends_on("eigen") # https://github.com/pytorch/pytorch/issues/60329 - # depends_on('cpuinfo@2020-12-17', when='@1.8:') - # depends_on('cpuinfo@2020-06-11', when='@1.6:1.7') + # depends_on("cpuinfo@2022-08-19", when="@1.13:") + # depends_on("cpuinfo@2020-12-17", when="@1.8:1.12") + # depends_on("cpuinfo@2020-06-11", when="@1.6:1.7") # https://github.com/shibatch/sleef/issues/427 - # depends_on('sleef@3.5.1_2020-12-22', when='@1.8:') + # depends_on("sleef@3.5.1_2020-12-22", when="@1.8:") # https://github.com/pytorch/pytorch/issues/60334 - # depends_on('sleef@3.4.0_2019-07-30', when='@1.6:1.7') + # depends_on("sleef@3.4.0_2019-07-30", when="@1.6:1.7") # https://github.com/Maratyszcza/FP16/issues/18 - # depends_on('fp16@2020-05-14', when='@1.6:') + # depends_on("fp16@2020-05-14", when="@1.6:") depends_on("pthreadpool@2021-04-13", when="@1.9:") depends_on("pthreadpool@2020-10-05", when="@1.8") depends_on("pthreadpool@2020-06-15", when="@1.6:1.7") @@ -198,22 +209,24 @@ class PyTorch(PythonPackage, CudaPackage, ROCmPackage): depends_on("miopen-hip") depends_on("rocminfo") # https://github.com/pytorch/pytorch/issues/60332 - # depends_on('xnnpack@2022-02-16', when='@1.12:+xnnpack') - # depends_on('xnnpack@2021-06-21', when='@1.10:1.11+xnnpack') - # depends_on('xnnpack@2021-02-22', when='@1.8:1.9+xnnpack') - # depends_on('xnnpack@2020-03-23', when='@1.6:1.7+xnnpack') + # depends_on("xnnpack@2022-02-16", when="@1.12:+xnnpack") + # depends_on("xnnpack@2021-06-21", when="@1.10:1.11+xnnpack") + # depends_on("xnnpack@2021-02-22", when="@1.8:1.9+xnnpack") + # depends_on("xnnpack@2020-03-23", when="@1.6:1.7+xnnpack") depends_on("mpi", when="+mpi") # https://github.com/pytorch/pytorch/issues/60270 - # depends_on('gloo@2021-05-21', when='@1.10:+gloo') - # depends_on('gloo@2021-05-04', when='@1.9+gloo') - # depends_on('gloo@2020-09-18', when='@1.7:1.8+gloo') - # depends_on('gloo@2020-03-17', when='@1.6+gloo') + # depends_on("gloo@2022-05-18", when="@1.13:+gloo") + # depends_on("gloo@2021-05-21", when="@1.10:1.12+gloo") + # depends_on("gloo@2021-05-04", when="@1.9+gloo") + # depends_on("gloo@2020-09-18", when="@1.7:1.8+gloo") + # depends_on("gloo@2020-03-17", when="@1.6+gloo") # https://github.com/pytorch/pytorch/issues/60331 - # depends_on('onnx@1.11.0', when='@1.12:+onnx_ml') - # depends_on('onnx@1.10.1_2021-10-08', when='@1.11+onnx_ml') - # depends_on('onnx@1.10.1', when='@1.10+onnx_ml') - # depends_on('onnx@1.8.0_2020-11-03', when='@1.8:1.9+onnx_ml') - # depends_on('onnx@1.7.0_2020-05-31', when='@1.6:1.7+onnx_ml') + # depends_on("onnx!1.12.0", when="@1.13:+onnx_ml") + # depends_on("onnx@1.11.0", when="@1.12+onnx_ml") + # depends_on("onnx@1.10.1_2021-10-08", when="@1.11+onnx_ml") + # depends_on("onnx@1.10.1", when="@1.10+onnx_ml") + # depends_on("onnx@1.8.0_2020-11-03", when="@1.8:1.9+onnx_ml") + # depends_on("onnx@1.7.0_2020-05-31", when="@1.6:1.7+onnx_ml") depends_on("mkl", when="+mkldnn") # Test dependencies @@ -247,7 +260,7 @@ class PyTorch(PythonPackage, CudaPackage, ROCmPackage): # Fixes fatal error: sleef.h: No such file or directory # https://github.com/pytorch/pytorch/pull/35359 # https://github.com/pytorch/pytorch/issues/26555 - # patch('sleef.patch', when='@:1.5') + # patch("sleef.patch", when="@:1.5") # Fixes compilation with Clang 9.0.0 and Apple Clang 11.0.3 # https://github.com/pytorch/pytorch/pull/37086 @@ -510,24 +523,24 @@ def enable_or_disable(variant, keyword="USE", var=None, newer=False): if self.spec.satisfies("@1.10:"): env.set("USE_SYSTEM_PYBIND11", "ON") # https://github.com/pytorch/pytorch/issues/60334 - # if self.spec.satisfies('@1.8:'): - # env.set('USE_SYSTEM_SLEEF', 'ON') + # if self.spec.satisfies("@1.8:"): + # env.set("USE_SYSTEM_SLEEF", "ON") if self.spec.satisfies("@1.6:"): - # env.set('USE_SYSTEM_LIBS', 'ON') + # env.set("USE_SYSTEM_LIBS", "ON") # https://github.com/pytorch/pytorch/issues/60329 - # env.set('USE_SYSTEM_CPUINFO', 'ON') + # env.set("USE_SYSTEM_CPUINFO", "ON") # https://github.com/pytorch/pytorch/issues/60270 - # env.set('USE_SYSTEM_GLOO', 'ON') + # env.set("USE_SYSTEM_GLOO", "ON") # https://github.com/Maratyszcza/FP16/issues/18 - # env.set('USE_SYSTEM_FP16', 'ON') + # env.set("USE_SYSTEM_FP16", "ON") env.set("USE_SYSTEM_PTHREADPOOL", "ON") env.set("USE_SYSTEM_PSIMD", "ON") env.set("USE_SYSTEM_FXDIV", "ON") env.set("USE_SYSTEM_BENCHMARK", "ON") # https://github.com/pytorch/pytorch/issues/60331 - # env.set('USE_SYSTEM_ONNX', 'ON') + # env.set("USE_SYSTEM_ONNX", "ON") # https://github.com/pytorch/pytorch/issues/60332 - # env.set('USE_SYSTEM_XNNPACK', 'ON') + # env.set("USE_SYSTEM_XNNPACK", "ON") @run_before("install") def build_amd(self): diff --git a/var/spack/repos/builtin/packages/py-torchaudio/package.py b/var/spack/repos/builtin/packages/py-torchaudio/package.py index 9fb103095e3..83e16bcf6cc 100644 --- a/var/spack/repos/builtin/packages/py-torchaudio/package.py +++ b/var/spack/repos/builtin/packages/py-torchaudio/package.py @@ -20,10 +20,80 @@ class PyTorchaudio(PythonPackage): extension.""" homepage = "https://github.com/pytorch/audio" - url = "https://github.com/pytorch/audio/archive/v0.4.0.tar.gz" + git = "https://github.com/pytorch/audio.git" - version("0.4.0", sha256="9361312319b1ab880fc348ea82b024053bca6faf477ef6a9232a5b805742dc66") + version("main", branch="main", submodules=True) + version("0.13.0", tag="v0.13.0", submodules=True) + version("0.12.1", tag="v0.12.1", submodules=True) + version("0.12.0", tag="v0.12.0", submodules=True) + version("0.11.0", tag="v0.11.0", submodules=True) + version("0.10.2", tag="v0.10.2", submodules=True) + version("0.10.1", tag="v0.10.1", submodules=True) + version("0.10.0", tag="v0.10.0", submodules=True) + version("0.9.1", tag="v0.9.1", submodules=True) + version("0.9.0", tag="v0.9.0", submodules=True) + version("0.8.2", tag="v0.8.2", submodules=True) + version("0.8.1", tag="v0.8.1", submodules=True) + version("0.8.0", tag="v0.8.0", submodules=True) + version("0.7.2", tag="v0.7.2", submodules=True) + version("0.7.0", tag="v0.7.0", submodules=True) + version("0.6.0", tag="v0.6.0", submodules=True) + version("0.5.1", tag="v0.5.1", submodules=True) + version("0.5.0", tag="v0.5.0", submodules=True) + version("0.4.0", tag="v0.4.0", submodules=True) + # https://github.com/pytorch/audio#dependencies + depends_on("python@3.7:3.10", when="@0.12:", type=("build", "link", "run")) + depends_on("python@3.7:3.9", when="@0.11", type=("build", "link", "run")) + depends_on("python@3.6:3.9", when="@0.7.2:0.10", type=("build", "link", "run")) + depends_on("python@3.6:3.8", when="@0.6:0.7.0", type=("build", "link", "run")) + depends_on("python@3.5:3.8", when="@0.5", type=("build", "link", "run")) + depends_on("python@2.7,3.5:3.8", when="@0.4", type=("build", "link", "run")) + + depends_on("cmake@3.18:", when="@0.10:", type="build") + depends_on("cmake@3.5:", when="@0.8:", type="build") + depends_on("ninja", when="@0.8:", type="build") depends_on("py-setuptools", type="build") - depends_on("sox@14.3.2:") - depends_on("py-torch@1.2.0:", type=("build", "run")) + depends_on("py-pybind11", when="@0.12:", type=("build", "link")) + depends_on("pkgconfig", type="build") + depends_on("sox") + + # https://github.com/pytorch/audio#dependencies + depends_on("py-torch@master", when="@main", type=("build", "link", "run")) + depends_on("py-torch@1.13.0", when="@0.13.0", type=("build", "link", "run")) + depends_on("py-torch@1.12.1", when="@0.12.1", type=("build", "link", "run")) + depends_on("py-torch@1.12.0", when="@0.12.0", type=("build", "link", "run")) + depends_on("py-torch@1.11.0", when="@0.11.0", type=("build", "link", "run")) + depends_on("py-torch@1.10.2", when="@0.10.2", type=("build", "link", "run")) + depends_on("py-torch@1.10.1", when="@0.10.1", type=("build", "link", "run")) + depends_on("py-torch@1.10.0", when="@0.10.0", type=("build", "link", "run")) + depends_on("py-torch@1.9.1", when="@0.9.1", type=("build", "link", "run")) + depends_on("py-torch@1.9.0", when="@0.9.0", type=("build", "link", "run")) + depends_on("py-torch@1.8.2", when="@0.8.2", type=("build", "link", "run")) + depends_on("py-torch@1.8.1", when="@0.8.1", type=("build", "link", "run")) + depends_on("py-torch@1.8.0", when="@0.8.0", type=("build", "link", "run")) + depends_on("py-torch@1.7.1", when="@0.7.2", type=("build", "link", "run")) + depends_on("py-torch@1.7.0", when="@0.7.0", type=("build", "link", "run")) + depends_on("py-torch@1.6.0", when="@0.6.0", type=("build", "link", "run")) + depends_on("py-torch@1.5.1", when="@0.5.1", type=("build", "link", "run")) + depends_on("py-torch@1.5.0", when="@0.5.0", type=("build", "link", "run")) + depends_on("py-torch@1.4.1", when="@0.4.0", type=("build", "link", "run")) + + def setup_build_environment(self, env): + # tools/setup_helpers/extension.py + env.set("BUILD_SOX", 0) + + if "+cuda" in self.spec["py-torch"]: + env.set("USE_CUDA", 1) + torch_cuda_arch_list = ";".join( + "{0:.1f}".format(float(i) / 10.0) + for i in self.spec["py-torch"].variants["cuda_arch"].value + ) + env.set("TORCH_CUDA_ARCH_LIST", torch_cuda_arch_list) + else: + env.set("USE_CUDA", 0) + + if "+rocm" in self.spec["py-torch"]: + env.set("USE_ROCM", 1) + else: + env.set("USE_ROCM", 0) diff --git a/var/spack/repos/builtin/packages/py-torchdata/package.py b/var/spack/repos/builtin/packages/py-torchdata/package.py index d61dbf97340..0d674e7d75b 100644 --- a/var/spack/repos/builtin/packages/py-torchdata/package.py +++ b/var/spack/repos/builtin/packages/py-torchdata/package.py @@ -24,7 +24,7 @@ class PyTorchdata(PythonPackage): # https://github.com/pytorch/data#version-compatibility depends_on("python@3.7:3.10", type=("build", "run")) depends_on("py-torch@master", when="@main", type=("build", "run")) - depends_on("py-torch@1.12.1", when="@0.5.0", type=("build", "run")) # ? + depends_on("py-torch@1.13.0", when="@0.5.0", type=("build", "run")) depends_on("py-torch@1.12.1", when="@0.4.1", type=("build", "run")) depends_on("py-torch@1.12.0", when="@0.4.0", type=("build", "run")) depends_on("py-torch@1.11.0", when="@0.3.0", type=("build", "run")) diff --git a/var/spack/repos/builtin/packages/py-torchtext/package.py b/var/spack/repos/builtin/packages/py-torchtext/package.py index e9008168e53..a22bfa53f1d 100644 --- a/var/spack/repos/builtin/packages/py-torchtext/package.py +++ b/var/spack/repos/builtin/packages/py-torchtext/package.py @@ -11,17 +11,52 @@ class PyTorchtext(PythonPackage): """Text utilities and datasets for PyTorch.""" homepage = "https://github.com/pytorch/text" - pypi = "torchtext/torchtext-0.5.0.tar.gz" + git = "https://github.com/pytorch/text.git" maintainers = ["adamjstewart"] - version("0.5.0", sha256="7f22e24e9b939fff56b9118c78dc07aafec8dcc67164de15b9b5ed339e4179c6") + version("main", branch="main", submodules=True) + version("0.14.0", tag="v0.14.0", submodules=True) + version("0.13.1", tag="v0.13.1", submodules=True) + version("0.13.0", tag="v0.13.0", submodules=True) + version("0.12.0", tag="v0.12.0", submodules=True) + version("0.11.2", tag="v0.11.2", submodules=True) + version("0.11.1", tag="v0.11.1", submodules=True) + version("0.10.1", tag="v0.10.1", submodules=True) + version("0.10.0", tag="v0.10.0", submodules=True) + version("0.9.2", tag="v0.9.2", submodules=True) + version("0.8.1", tag="v0.8.1", submodules=True) + version("0.6.0", tag="0.6.0", submodules=True) + version("0.5.0", tag="0.5.0", submodules=True) - depends_on("python@2.7:2.8,3.5:", type=("build", "run")) + # https://github.com/pytorch/text#installation + depends_on("python@3.7:3.10", when="@0.13:", type=("build", "link", "run")) + depends_on("python@3.6:3.9", when="@0.8.1:0.12", type=("build", "link", "run")) + depends_on("python@3.6:3.8", when="@0.7:0.8.0", type=("build", "link", "run")) + depends_on("python@3.5:3.8", when="@0.6", type=("build", "link", "run")) + depends_on("python@2.7,3.5:3.8", when="@:0.5", type=("build", "link", "run")) + + depends_on("cmake@3.18:", when="@0.13:", type="build") + depends_on("ninja", when="@0.13:", type="build") + depends_on("py-pybind11", when="@0.8:", type=("build", "link")) depends_on("py-setuptools", type="build") depends_on("py-tqdm", type=("build", "run")) depends_on("py-requests", type=("build", "run")) - depends_on("py-torch@0.4.0:", type=("build", "run")) depends_on("py-numpy", type=("build", "run")) - depends_on("py-six", type=("build", "run")) - depends_on("py-sentencepiece", type=("build", "run")) + depends_on("py-six", when="@:0.6", type=("build", "run")) + depends_on("py-sentencepiece", when="@:0.7", type=("build", "run")) + + # https://github.com/pytorch/text#installation + depends_on("py-torch@master", when="@main", type=("build", "link", "run")) + depends_on("py-torch@1.13.0", when="@0.14.0", type=("build", "link", "run")) + depends_on("py-torch@1.12.1", when="@0.13.1", type=("build", "link", "run")) + depends_on("py-torch@1.12.0", when="@0.13.0", type=("build", "link", "run")) + depends_on("py-torch@1.11.0", when="@0.12.0", type=("build", "link", "run")) + depends_on("py-torch@1.10.2", when="@0.11.2", type=("build", "link", "run")) + depends_on("py-torch@1.10.1", when="@0.11.1", type=("build", "link", "run")) + depends_on("py-torch@1.9.1", when="@0.10.1", type=("build", "link", "run")) + depends_on("py-torch@1.9.0", when="@0.10.0", type=("build", "link", "run")) + depends_on("py-torch@1.8.2", when="@0.9.2", type=("build", "link", "run")) + depends_on("py-torch@1.7.1", when="@0.8.1", type=("build", "link", "run")) + depends_on("py-torch@1.5.0", when="@0.6.0", type=("build", "link", "run")) + depends_on("py-torch@1.4.1", when="@0.5.0", type=("build", "link", "run")) diff --git a/var/spack/repos/builtin/packages/py-torchvision/package.py b/var/spack/repos/builtin/packages/py-torchvision/package.py index 273732995a8..e1e58b7ccdc 100644 --- a/var/spack/repos/builtin/packages/py-torchvision/package.py +++ b/var/spack/repos/builtin/packages/py-torchvision/package.py @@ -18,6 +18,7 @@ class PyTorchvision(PythonPackage): maintainers = ["adamjstewart"] version("main", branch="main") + version("0.14.0", sha256="be1621c85c56eb40537cb74e6ec5d8e58ed8b69f8374a58bcb6ec413cb540c8b") version("0.13.1", sha256="c32fab734e62c7744dadeb82f7510ff58cc3bca1189d17b16aa99b08afc42249") version("0.13.0", sha256="2fe9139150800820d02c867a0b64b7c7fbc964d48d76fae235d6ef9215eabcf4") version("0.12.0", sha256="99e6d3d304184895ff4f6152e2d2ec1cbec89b3e057d9c940ae0125546b04e91") @@ -47,7 +48,12 @@ class PyTorchvision(PythonPackage): "backend", default="pil", description="Image backend", - values=("pil", "accimage", "png", "jpeg"), + values=[ + "pil", + "accimage", + conditional("png", when="@0.8:"), + conditional("jpeg", when="@0.8:"), + ], multi=False, ) @@ -68,6 +74,7 @@ class PyTorchvision(PythonPackage): # https://github.com/pytorch/vision#installation depends_on("py-torch@master", when="@main", type=("build", "link", "run")) + depends_on("py-torch@1.13.0", when="@0.14.0", type=("build", "link", "run")) depends_on("py-torch@1.12.1", when="@0.13.1", type=("build", "link", "run")) depends_on("py-torch@1.12.0", when="@0.13.0", type=("build", "link", "run")) depends_on("py-torch@1.11.0", when="@0.12.0", type=("build", "link", "run")) @@ -102,15 +109,12 @@ class PyTorchvision(PythonPackage): depends_on("pil@5.3:8.2,8.4:", when="@0.13: backend=pil", type=("build", "run")) depends_on("py-accimage", when="backend=accimage", type=("build", "run")) depends_on("libpng@1.6.0:", when="backend=png") - depends_on("jpeg") - - # Many of the datasets require additional dependencies to use. - # These can be installed after the fact. + depends_on("jpeg") # seems to be required for all backends depends_on("ffmpeg@3.1:", when="@0.4.2:") - conflicts("backend=png", when="@:0.7") - conflicts("backend=jpeg", when="@:0.7") + # Many of the datasets require additional dependencies to use. + # These can be installed after the fact. def setup_build_environment(self, env): include = [] @@ -138,10 +142,10 @@ def setup_build_environment(self, env): if "+cuda" in self.spec["py-torch"]: env.set("FORCE_CUDA", 1) env.set("CUDA_HOME", self.spec["cuda"].prefix) - pytorch_cuda_arch = ";".join( + torch_cuda_arch_list = ";".join( "{0:.1f}".format(float(i) / 10.0) for i in self.spec["py-torch"].variants["cuda_arch"].value ) - env.set("TORCH_CUDA_ARCH_LIST", pytorch_cuda_arch) + env.set("TORCH_CUDA_ARCH_LIST", torch_cuda_arch_list) else: env.set("FORCE_CUDA", 0) diff --git a/var/spack/repos/builtin/packages/sox/package.py b/var/spack/repos/builtin/packages/sox/package.py index 3cbb9ab3d12..8e4315a8857 100644 --- a/var/spack/repos/builtin/packages/sox/package.py +++ b/var/spack/repos/builtin/packages/sox/package.py @@ -18,7 +18,6 @@ class Sox(AutotoolsPackage): depends_on("bzip2") depends_on("flac") - depends_on("id3lib") depends_on("libvorbis") depends_on("opus") depends_on("lame", when="+mp3") From f099a68e65f3db5f33cb73b9ab9b798b37f4e4cf Mon Sep 17 00:00:00 2001 From: Sergey Kosukhin Date: Tue, 8 Nov 2022 06:02:21 +0100 Subject: [PATCH 416/442] mpich: patch @3.4 to fix checking whether the datatype is contiguous (#33328) Co-authored-by: Thomas Jahns Co-authored-by: Thomas Jahns --- .../mpich/mpich34_yaksa_hindexed.patch | 131 ++++++++++++++++++ .../repos/builtin/packages/mpich/package.py | 14 +- 2 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 var/spack/repos/builtin/packages/mpich/mpich34_yaksa_hindexed.patch diff --git a/var/spack/repos/builtin/packages/mpich/mpich34_yaksa_hindexed.patch b/var/spack/repos/builtin/packages/mpich/mpich34_yaksa_hindexed.patch new file mode 100644 index 00000000000..6306eab5d35 --- /dev/null +++ b/var/spack/repos/builtin/packages/mpich/mpich34_yaksa_hindexed.patch @@ -0,0 +1,131 @@ +--- a/modules/yaksa/src/frontend/types/yaksa_blkindx.c ++++ b/modules/yaksa/src/frontend/types/yaksa_blkindx.c +@@ -74,7 +74,7 @@ int yaksi_type_create_hindexed_block(int count, int blocklength, const intptr_t + if (intype->is_contig && ((outtype->ub - outtype->lb) == outtype->size)) { + outtype->is_contig = true; + for (int i = 1; i < count; i++) { +- if (array_of_displs[i] <= array_of_displs[i - 1]) { ++ if (array_of_displs[i] != array_of_displs[i - 1] + intype->extent * blocklength) { + outtype->is_contig = false; + break; + } +--- a/modules/yaksa/src/frontend/types/yaksa_indexed.c ++++ b/modules/yaksa/src/frontend/types/yaksa_indexed.c +@@ -44,8 +44,12 @@ int yaksi_type_create_hindexed(int count, const int *array_of_blocklengths, + outtype->alignment = intype->alignment; + + int is_set; ++ intptr_t last_ub; ++ int is_noncontig; + is_set = 0; +- for (int idx = 0; idx < count; idx++) { ++ last_ub = 0; ++ is_noncontig = 0; ++ for (intptr_t idx = 0; idx < count; idx++) { + if (array_of_blocklengths[idx] == 0) + continue; + +@@ -60,6 +64,11 @@ int yaksi_type_create_hindexed(int count, const int *array_of_blocklengths, + ub = array_of_displs[idx] + intype->ub; + } + ++ if (idx > 0 && lb != last_ub) { ++ is_noncontig = 1; ++ } ++ last_ub = ub; ++ + intptr_t true_lb = lb - intype->lb + intype->true_lb; + intptr_t true_ub = ub - intype->ub + intype->true_ub; + +@@ -90,26 +99,8 @@ int yaksi_type_create_hindexed(int count, const int *array_of_blocklengths, + outtype->u.hindexed.child = intype; + + /* detect if the outtype is contiguous */ +- if (intype->is_contig && ((outtype->ub - outtype->lb) == outtype->size)) { ++ if (!is_noncontig && intype->is_contig && (outtype->ub - outtype->lb) == outtype->size) { + outtype->is_contig = true; +- +- int left = 0; +- while (array_of_blocklengths[left] == 0) +- left++; +- int right = left + 1; +- while (right < count && array_of_blocklengths[right] == 0) +- right++; +- while (right < count) { +- if (array_of_displs[right] <= array_of_displs[left]) { +- outtype->is_contig = false; +- break; +- } else { +- left = right; +- right++; +- while (right < count && array_of_blocklengths[right] == 0) +- right++; +- } +- } + } else { + outtype->is_contig = false; + } +--- a/modules/yaksa/src/frontend/types/yaksa_struct.c ++++ b/modules/yaksa/src/frontend/types/yaksa_struct.c +@@ -42,9 +42,13 @@ int yaksi_type_create_struct(int count, const int *array_of_blocklengths, + } + + int is_set; ++ intptr_t last_ub; ++ int is_noncontig; + is_set = 0; ++ last_ub = 0; ++ is_noncontig = 0; + outtype->alignment = 0; +- for (int idx = 0; idx < count; idx++) { ++ for (intptr_t idx = 0; idx < count; idx++) { + if (array_of_blocklengths[idx] == 0) + continue; + +@@ -61,6 +65,12 @@ int yaksi_type_create_struct(int count, const int *array_of_blocklengths, + + intptr_t true_lb = lb - array_of_intypes[idx]->lb + array_of_intypes[idx]->true_lb; + intptr_t true_ub = ub - array_of_intypes[idx]->ub + array_of_intypes[idx]->true_ub; ++ ++ if (idx > 0 && true_lb != last_ub) { ++ is_noncontig = 1; ++ } ++ last_ub = true_ub; ++ + int tree_depth = array_of_intypes[idx]->tree_depth; + if (outtype->alignment < array_of_intypes[idx]->alignment) + outtype->alignment = array_of_intypes[idx]->alignment; +@@ -94,7 +104,7 @@ int yaksi_type_create_struct(int count, const int *array_of_blocklengths, + outtype->extent = outtype->ub - outtype->lb; + + /* detect if the outtype is contiguous */ +- if ((outtype->ub - outtype->lb) == outtype->size) { ++ if (!is_noncontig && (outtype->ub - outtype->lb) == outtype->size) { + outtype->is_contig = true; + + for (int i = 0; i < count; i++) { +@@ -103,24 +113,6 @@ int yaksi_type_create_struct(int count, const int *array_of_blocklengths, + break; + } + } +- +- int left = 0; +- while (array_of_blocklengths[left] == 0) +- left++; +- int right = left + 1; +- while (right < count && array_of_blocklengths[right] == 0) +- right++; +- while (right < count) { +- if (array_of_displs[right] <= array_of_displs[left]) { +- outtype->is_contig = false; +- break; +- } else { +- left = right; +- right++; +- while (right < count && array_of_blocklengths[right] == 0) +- right++; +- } +- } + } else { + outtype->is_contig = false; + } diff --git a/var/spack/repos/builtin/packages/mpich/package.py b/var/spack/repos/builtin/packages/mpich/package.py index 8604903f329..552f3139896 100644 --- a/var/spack/repos/builtin/packages/mpich/package.py +++ b/var/spack/repos/builtin/packages/mpich/package.py @@ -194,6 +194,18 @@ class Mpich(AutotoolsPackage, CudaPackage, ROCmPackage): when="@4.0:4.0.2", ) + # Fix checking whether the datatype is contiguous + # https://github.com/pmodels/yaksa/pull/189 + # https://github.com/pmodels/mpich/issues/5391 + # The problem has been fixed starting version 4.0 by updating the yaksa git submodule, which + # has not been done for the 3.4.x branch. The following patch is a backport of the + # aforementioned pull request for the unreleased version of yaksa that is vendored with MPICH. + # Note that Spack builds MPICH against a non-vendored yaksa only starting version 4.0. + with when("@3.4"): + # Apply the patch only when yaksa is used: + patch("mpich34_yaksa_hindexed.patch", when="datatype-engine=yaksa") + patch("mpich34_yaksa_hindexed.patch", when="datatype-engine=auto device=ch4") + depends_on("findutils", type="build") depends_on("pkgconfig", type="build") @@ -571,7 +583,7 @@ def configure_args(self): elif "datatype-engine=dataloop" in spec: config_args.append("--with-datatype-engine=dataloop") elif "datatype-engine=auto" in spec: - config_args.append("--with-datatye-engine=auto") + config_args.append("--with-datatype-engine=auto") if "+hcoll" in spec: config_args.append("--with-hcoll=" + spec["hcoll"].prefix) From c9561c5a0e962a7c17eb961d21bfd4f7728e656b Mon Sep 17 00:00:00 2001 From: Greg Becker Date: Mon, 7 Nov 2022 21:50:16 -0800 Subject: [PATCH 417/442] intel oneapi classic bootstrapping (#31285) The `intel` compiler at versions > 20 is provided by the `intel-oneapi-compilers-classic` package (a thin wrapper around the `intel-oneapi-compilers` package), and the `oneapi` compiler is provided by the `intel-oneapi-compilers` package. Prior to this work, neither of these compilers could be bootstrapped by Spack as part of an install with `install_missing_compilers: True`. Changes made to make these two packages bootstrappable: 1. The `intel-oneapi-compilers-classic` package includes a bin directory and symlinks to the compiler executables, not just logical pointers in Spack. 2. Spack can look for bootstrapped compilers in directories other than `$prefix/bin`, defined on a per-package basis 3. `intel-oneapi-compilers` specifies a non-default search directory for the compiler executables. 4. The `spack.compilers` module now can make more advanced associations between packages and compilers, not just simple name translations 5. Spack support for lmod hierarchies accounts for differences between package names and the associated compiler names for `intel-oneapi-compilers/oneapi`, `intel-oneapi-compilers-classic/intel@20:`, `llvm+clang/clang`, and `llvm-amdgpu/rocmcc`. - [x] full end-to-end testing - [x] add unit tests --- lib/spack/spack/compilers/__init__.py | 16 +++++++- lib/spack/spack/installer.py | 18 ++++---- lib/spack/spack/modules/lmod.py | 20 ++------- lib/spack/spack/test/installer.py | 11 +++++ lib/spack/spack/test/modules/lmod.py | 9 ++++ .../intel-oneapi-compilers/package.py | 28 +++++++++++++ .../intel-oneapi-compilers-classic/package.py | 41 +++++++++++++++++-- .../intel-oneapi-compilers/package.py | 6 ++- 8 files changed, 119 insertions(+), 30 deletions(-) create mode 100644 var/spack/repos/builtin.mock/packages/intel-oneapi-compilers/package.py diff --git a/lib/spack/spack/compilers/__init__.py b/lib/spack/spack/compilers/__init__.py index 05ffaf9f6c3..e54f8dc96c0 100644 --- a/lib/spack/spack/compilers/__init__.py +++ b/lib/spack/spack/compilers/__init__.py @@ -49,12 +49,26 @@ "clang": "llvm+clang", "oneapi": "intel-oneapi-compilers", "rocmcc": "llvm-amdgpu", + "intel@2020:": "intel-oneapi-compilers-classic", +} + +# TODO: generating this from the previous dict causes docs errors +package_name_to_compiler_name = { + "llvm": "clang", + "intel-oneapi-compilers": "oneapi", + "llvm-amdgpu": "rocmcc", + "intel-oneapi-compilers-classic": "intel", } def pkg_spec_for_compiler(cspec): """Return the spec of the package that provides the compiler.""" - spec_str = "%s@%s" % (_compiler_to_pkg.get(cspec.name, cspec.name), cspec.versions) + for spec, package in _compiler_to_pkg.items(): + if cspec.satisfies(spec): + spec_str = "%s@%s" % (package, cspec.versions) + break + else: + spec_str = str(cspec) return spack.spec.Spec(spec_str) diff --git a/lib/spack/spack/installer.py b/lib/spack/spack/installer.py index 62770d03491..a0f505a922d 100644 --- a/lib/spack/spack/installer.py +++ b/lib/spack/spack/installer.py @@ -1241,6 +1241,12 @@ def _add_tasks(self, request, all_deps): fail_fast = request.install_args.get("fail_fast") self.fail_fast = self.fail_fast or fail_fast + def _add_compiler_package_to_config(self, pkg): + compiler_search_prefix = getattr(pkg, "compiler_search_prefix", pkg.spec.prefix) + spack.compilers.add_compilers_to_config( + spack.compilers.find_compilers([compiler_search_prefix]) + ) + def _install_task(self, task): """ Perform the installation of the requested spec and/or dependency @@ -1266,9 +1272,7 @@ def _install_task(self, task): if use_cache and _install_from_cache(pkg, cache_only, explicit, unsigned): self._update_installed(task) if task.compiler: - spack.compilers.add_compilers_to_config( - spack.compilers.find_compilers([pkg.spec.prefix]) - ) + self._add_compiler_package_to_config(pkg) return pkg.run_tests = tests is True or tests and pkg.name in tests @@ -1296,9 +1300,7 @@ def _install_task(self, task): # If a compiler, ensure it is added to the configuration if task.compiler: - spack.compilers.add_compilers_to_config( - spack.compilers.find_compilers([pkg.spec.prefix]) - ) + self._add_compiler_package_to_config(pkg) except spack.build_environment.StopPhase as e: # A StopPhase exception means that do_install was asked to # stop early from clients, and is not an error at this point @@ -1717,9 +1719,7 @@ def install(self): # It's an already installed compiler, add it to the config if task.compiler: - spack.compilers.add_compilers_to_config( - spack.compilers.find_compilers([pkg.spec.prefix]) - ) + self._add_compiler_package_to_config(pkg) else: # At this point we've failed to get a write or a read diff --git a/lib/spack/spack/modules/lmod.py b/lib/spack/spack/modules/lmod.py index bb288336eaa..3378e533545 100644 --- a/lib/spack/spack/modules/lmod.py +++ b/lib/spack/spack/modules/lmod.py @@ -184,22 +184,10 @@ def provides(self): # If it is in the list of supported compilers family -> compiler if self.spec.name in spack.compilers.supported_compilers(): provides["compiler"] = spack.spec.CompilerSpec(str(self.spec)) - # Special case for llvm - if self.spec.name == "llvm": - provides["compiler"] = spack.spec.CompilerSpec(str(self.spec)) - provides["compiler"].name = "clang" - # Special case for llvm-amdgpu - if self.spec.name == "llvm-amdgpu": - provides["compiler"] = spack.spec.CompilerSpec(str(self.spec)) - provides["compiler"].name = "rocmcc" - # Special case for oneapi - if self.spec.name == "intel-oneapi-compilers": - provides["compiler"] = spack.spec.CompilerSpec(str(self.spec)) - provides["compiler"].name = "oneapi" - # Special case for oneapi classic - if self.spec.name == "intel-oneapi-compilers-classic": - provides["compiler"] = spack.spec.CompilerSpec(str(self.spec)) - provides["compiler"].name = "intel" + elif self.spec.name in spack.compilers.package_name_to_compiler_name: + # If it is the package for a supported compiler, but of a different name + cname = spack.compilers.package_name_to_compiler_name[self.spec.name] + provides["compiler"] = spack.spec.CompilerSpec("%s@%s" % (cname, self.spec.version)) # All the other tokens in the hierarchy must be virtual dependencies for x in self.hierarchy_tokens: diff --git a/lib/spack/spack/test/installer.py b/lib/spack/spack/test/installer.py index 8a713ca7046..4c85f4ba26c 100644 --- a/lib/spack/spack/test/installer.py +++ b/lib/spack/spack/test/installer.py @@ -487,6 +487,17 @@ def fake_package_list(compiler, architecture, pkgs): assert installer.build_pq[0][1].compiler +def test_bootstrapping_compilers_with_different_names_from_spec( + install_mockery, mutable_config, mock_fetch +): + with spack.config.override("config:install_missing_compilers", True): + with spack.concretize.disable_compiler_existence_check(): + spec = spack.spec.Spec("trivial-install-test-package%oneapi@22.2.0").concretized() + spec.package.do_install() + + assert spack.spec.CompilerSpec("oneapi@22.2.0") in spack.compilers.all_compiler_specs() + + def test_dump_packages_deps_ok(install_mockery, tmpdir, mock_packages): """Test happy path for dump_packages with dependencies.""" diff --git a/lib/spack/spack/test/modules/lmod.py b/lib/spack/spack/test/modules/lmod.py index 5d0d04032eb..c0d228c2fea 100644 --- a/lib/spack/spack/test/modules/lmod.py +++ b/lib/spack/spack/test/modules/lmod.py @@ -81,6 +81,15 @@ def test_file_layout(self, compiler, provider, factory, module_configuration): else: assert repetitions == 1 + def test_compilers_provided_different_name(self, factory, module_configuration): + module_configuration("complex_hierarchy") + module, spec = factory("intel-oneapi-compilers%clang@3.3") + + provides = module.conf.provides + + assert "compiler" in provides + assert provides["compiler"] == spack.spec.CompilerSpec("oneapi@3.0") + def test_simple_case(self, modulefile_content, module_configuration): """Tests the generation of a simple TCL module file.""" diff --git a/var/spack/repos/builtin.mock/packages/intel-oneapi-compilers/package.py b/var/spack/repos/builtin.mock/packages/intel-oneapi-compilers/package.py new file mode 100644 index 00000000000..3ab49f1e1c9 --- /dev/null +++ b/var/spack/repos/builtin.mock/packages/intel-oneapi-compilers/package.py @@ -0,0 +1,28 @@ +# 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 IntelOneapiCompilers(Package): + """Simple compiler package.""" + + homepage = "http://www.example.com" + url = "http://www.example.com/oneapi-1.0.tar.gz" + + version("1.0", "0123456789abcdef0123456789abcdef") + version("2.0", "abcdef0123456789abcdef0123456789") + version("3.0", "def0123456789abcdef0123456789abc") + + @property + def compiler_search_prefix(self): + return self.prefix.foo.bar.baz.bin + + def install(self, spec, prefix): + # Create the minimal compiler that will fool `spack compiler find` + mkdirp(self.compiler_search_prefix) + with open(self.compiler_search_prefix.icx, "w") as f: + f.write('#!/bin/bash\necho "oneAPI DPC++ Compiler %s"' % str(spec.version)) + set_executable(self.compiler_search_prefix.icx) 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 61b634fb9b3..1b81e0ff632 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 @@ -2,6 +2,9 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import os + +from llnl.util.link_tree import LinkTree from spack.package import * @@ -19,8 +22,6 @@ class IntelOneapiCompilersClassic(Package): has_code = False - phases = [] - # Versions before 2021 are in the `intel` package # intel-oneapi versions before 2022 use intel@19.0.4 for ver, oneapi_ver in { @@ -35,8 +36,19 @@ class IntelOneapiCompilersClassic(Package): version(ver) depends_on("intel-oneapi-compilers@" + oneapi_ver, when="@" + ver, type="run") + @property + def oneapi_compiler_prefix(self): + oneapi_version = self.spec["intel-oneapi-compilers"].version + return self.spec["intel-oneapi-compilers"].prefix.compiler.join(str(oneapi_version)) + def setup_run_environment(self, env): - """Adds environment variables to the generated module file.""" + """Adds environment variables to the generated module file. + + These environment variables come from running: + .. code-block:: console + $ source {prefix}/{component}/{version}/env/vars.sh + and from setting CC/CXX/F77/FC + """ oneapi_pkg = self.spec["intel-oneapi-compilers"].package oneapi_pkg.setup_run_environment(env) @@ -46,3 +58,26 @@ def setup_run_environment(self, env): env.set("CXX", bin_prefix.icpc) env.set("F77", bin_prefix.ifort) env.set("FC", bin_prefix.ifort) + + def install(self, spec, prefix): + # If we symlink top-level directories directly, files won't show up in views + # Create real dirs and symlink files instead + self.symlink_dir(self.oneapi_compiler_prefix.linux.bin.intel64, prefix.bin) + self.symlink_dir(self.oneapi_compiler_prefix.linux.lib, prefix.lib) + self.symlink_dir(self.oneapi_compiler_prefix.linux.include, prefix.include) + self.symlink_dir(self.oneapi_compiler_prefix.linux.compiler, prefix.compiler) + self.symlink_dir(self.oneapi_compiler_prefix.documentation.en.man, prefix.man) + + def symlink_dir(self, src, dest): + # Create a real directory at dest + mkdirp(dest) + + # Symlink all files in src to dest keeping directories as dirs + for entry in os.listdir(src): + src_path = os.path.join(src, entry) + dest_path = os.path.join(dest, entry) + if os.path.isdir(src_path) and os.access(src_path, os.X_OK): + link_tree = LinkTree(src_path) + link_tree.merge(dest_path) + else: + os.symlink(src_path, dest_path) 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 c5960742897..4869fc63d89 100644 --- a/var/spack/repos/builtin/packages/intel-oneapi-compilers/package.py +++ b/var/spack/repos/builtin/packages/intel-oneapi-compilers/package.py @@ -149,6 +149,10 @@ class IntelOneapiCompilers(IntelOneApiPackage): def component_dir(self): return "compiler" + @property + def compiler_search_prefix(self): + return self.prefix.compiler.join(str(self.version)).linux.bin + def setup_run_environment(self, env): """Adds environment variables to the generated module file. @@ -169,7 +173,7 @@ def setup_run_environment(self, env): def install(self, spec, prefix): # Copy instead of install to speed up debugging - # install_tree('/opt/intel/oneapi/compiler', self.prefix) + # install_tree("/opt/intel/oneapi/compiler", self.prefix) # install cpp super(IntelOneapiCompilers, self).install(spec, prefix) From e4218595de4f3a726bc45059a9e5219f416a8c84 Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Tue, 8 Nov 2022 10:56:24 +0100 Subject: [PATCH 418/442] Rework unit test to avoid tripping into concretization slowdown (#33749) --- .../spack/test/concretize_preferences.py | 32 ++++++------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/lib/spack/spack/test/concretize_preferences.py b/lib/spack/spack/test/concretize_preferences.py index 56bda697fce..b0ae008a72e 100644 --- a/lib/spack/spack/test/concretize_preferences.py +++ b/lib/spack/spack/test/concretize_preferences.py @@ -8,8 +8,6 @@ import pytest -import archspec - import spack.config import spack.package_prefs import spack.repo @@ -105,28 +103,16 @@ def test_preferred_variants_from_wildcard(self): update_packages("multivalue-variant", "variants", "foo=bar") assert_variant_values("multivalue-variant foo=*", foo=("bar",)) - def test_preferred_compilers(self): + @pytest.mark.parametrize( + "compiler_str,spec_str", + [("gcc@4.5.0", "mpileaks"), ("clang@12.0.0", "mpileaks"), ("gcc@4.5.0", "openmpi")], + ) + def test_preferred_compilers(self, compiler_str, spec_str): """Test preferred compilers are applied correctly""" - if spack.config.get("config:concretizer") == "original": - pytest.skip("Fixing the parser broke this test for the original concretizer.") - - # Need to make sure the test uses an available compiler - arch = spack.spec.ArchSpec(("test", "redhat6", archspec.cpu.host().name)) - - compiler_list = spack.compilers.compiler_specs_for_arch(arch) - assert compiler_list - - # Try the first available compiler - compiler = str(compiler_list[0]) - update_packages("mpileaks", "compiler", [compiler]) - spec = concretize("mpileaks") - assert spec.compiler == spack.spec.CompilerSpec(compiler) - - # Try the last available compiler - compiler = str(compiler_list[-1]) - update_packages("mpileaks", "compiler", [compiler]) - spec = concretize("mpileaks os=redhat6") - assert spec.compiler == spack.spec.CompilerSpec(compiler) + spec = spack.spec.Spec(spec_str) + update_packages(spec.name, "compiler", [compiler_str]) + spec.concretize() + assert spec.compiler == spack.spec.CompilerSpec(compiler_str) def test_preferred_target(self, mutable_mock_repo): """Test preferred targets are applied correctly""" From f332ac6d21e024d5540cbfd97fa35da3aef4111c Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Tue, 8 Nov 2022 12:53:11 +0100 Subject: [PATCH 419/442] More jobs in Gitlab CI (#33688) Use at most 32 jobs when available. --- .../gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml | 2 ++ share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml | 2 ++ .../gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml | 2 ++ share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml | 2 ++ .../gitlab/cloud_pipelines/stacks/build_systems/spack.yaml | 2 ++ .../spack/gitlab/cloud_pipelines/stacks/data-vis-sdk/spack.yaml | 2 ++ .../spack/gitlab/cloud_pipelines/stacks/e4s-on-power/spack.yaml | 1 + share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml | 2 ++ share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml | 2 ++ share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml | 2 ++ share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml | 2 ++ share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml | 2 ++ .../cloud_pipelines/stacks/radiuss-aws-aarch64/spack.yaml | 2 ++ .../spack/gitlab/cloud_pipelines/stacks/radiuss-aws/spack.yaml | 2 ++ share/spack/gitlab/cloud_pipelines/stacks/radiuss/spack.yaml | 2 ++ share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml | 2 ++ 16 files changed, 31 insertions(+) diff --git a/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml index 2449ebb23db..a149c9e88b5 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug-aarch64/spack.yaml @@ -6,6 +6,7 @@ spack: unify: false config: + build_jobs: 32 concretizer: clingo install_tree: root: /home/software/spack @@ -245,6 +246,7 @@ spack: script: - uname -a || true - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true + - nproc - curl -Lfs 'https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0+1/GNUMake.v4.3.0.aarch64-linux-gnu.tar.gz' -o gmake.tar.gz - printf '2322c175fb092b426f9eb6c24ee22d94ffa6759c3d0c260b74d81abd8120122b gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null diff --git a/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml index 32fb38a360f..6117278bcf0 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/aws-ahug/spack.yaml @@ -6,6 +6,7 @@ spack: unify: false config: + build_jobs: 32 concretizer: clingo install_tree: root: /home/software/spack @@ -242,6 +243,7 @@ spack: script: - uname -a || true - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true + - nproc - curl -Lfs 'https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0+1/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz' -o gmake.tar.gz - printf 'fef1f59e56d2d11e6d700ba22d3444b6e583c663d6883fd0a4f63ab8bd280f0f gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null diff --git a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml index 5308ed359e4..379d5e2f317 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc-aarch64/spack.yaml @@ -6,6 +6,7 @@ spack: unify: false config: + build_jobs: 32 concretizer: clingo install_tree: root: /home/software/spack @@ -152,6 +153,7 @@ spack: script: - uname -a || true - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true + - nproc - curl -Lfs 'https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0+1/GNUMake.v4.3.0.aarch64-linux-gnu.tar.gz' -o gmake.tar.gz - printf '2322c175fb092b426f9eb6c24ee22d94ffa6759c3d0c260b74d81abd8120122b gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null diff --git a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml index 4a4f60ca85b..5feaad01cff 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/aws-isc/spack.yaml @@ -6,6 +6,7 @@ spack: unify: false config: + build_jobs: 32 concretizer: clingo install_tree: root: /home/software/spack @@ -163,6 +164,7 @@ spack: script: - uname -a || true - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true + - nproc - curl -Lfs 'https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0+1/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz' -o gmake.tar.gz - printf 'fef1f59e56d2d11e6d700ba22d3444b6e583c663d6883fd0a4f63ab8bd280f0f gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null diff --git a/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml index e09971beba9..53d8cefc4af 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/build_systems/spack.yaml @@ -6,6 +6,7 @@ spack: unify: when_possible config: + build_jobs: 32 install_tree: root: /home/software/spack padded_length: 512 @@ -36,6 +37,7 @@ spack: script: - uname -a || true - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true + - nproc - curl -Lfs 'https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0+1/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz' -o gmake.tar.gz - printf 'fef1f59e56d2d11e6d700ba22d3444b6e583c663d6883fd0a4f63ab8bd280f0f gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null diff --git a/share/spack/gitlab/cloud_pipelines/stacks/data-vis-sdk/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/data-vis-sdk/spack.yaml index 831125e3be7..de1e68fcd41 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/data-vis-sdk/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/data-vis-sdk/spack.yaml @@ -6,6 +6,7 @@ spack: unify: false config: + build_jobs: 32 install_tree: root: /home/software/spack padded_length: 512 @@ -49,6 +50,7 @@ spack: script: - uname -a || true - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true + - nproc - curl -Lfs 'https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0+1/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz' -o gmake.tar.gz - printf 'fef1f59e56d2d11e6d700ba22d3444b6e583c663d6883fd0a4f63ab8bd280f0f gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null diff --git a/share/spack/gitlab/cloud_pipelines/stacks/e4s-on-power/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/e4s-on-power/spack.yaml index d0f7074eeed..4ef8a090a55 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/e4s-on-power/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/e4s-on-power/spack.yaml @@ -216,6 +216,7 @@ spack: script: - uname -a || true - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true + - nproc - curl -Lfs 'https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0+1/GNUMake.v4.3.0.powerpc64le-linux-gnu.tar.gz' -o gmake.tar.gz - printf '8096d202fe0a0c400b8c0573c4b9e009f2f10d2fa850a3f495340f16e9c42454 gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null diff --git a/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml index 3dfc5a14f41..a064faf4921 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml @@ -6,6 +6,7 @@ spack: unify: when_possible config: + build_jobs: 32 concretizer: clingo install_tree: root: /home/software/spack @@ -268,6 +269,7 @@ spack: script: - uname -a || true - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true + - nproc - curl -Lfs 'https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0+1/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz' -o gmake.tar.gz - printf 'fef1f59e56d2d11e6d700ba22d3444b6e583c663d6883fd0a4f63ab8bd280f0f gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null diff --git a/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml index 7a14a044966..b6583d3a4e0 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/e4s/spack.yaml @@ -6,6 +6,7 @@ spack: unify: false config: + build_jobs: 32 concretizer: clingo install_tree: root: /home/software/spack @@ -258,6 +259,7 @@ spack: script: - uname -a || true - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true + - nproc - curl -Lfs 'https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0+1/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz' -o gmake.tar.gz - printf 'fef1f59e56d2d11e6d700ba22d3444b6e583c663d6883fd0a4f63ab8bd280f0f gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null diff --git a/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml index 6b6280d66ce..90f8428ca35 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/ml-cpu/spack.yaml @@ -6,6 +6,7 @@ spack: unify: false config: + build_jobs: 32 concretizer: clingo install_tree: root: /home/software/spack @@ -92,6 +93,7 @@ spack: script: - uname -a || true - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true + - nproc - curl -Lfs 'https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0+1/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz' -o gmake.tar.gz - printf 'fef1f59e56d2d11e6d700ba22d3444b6e583c663d6883fd0a4f63ab8bd280f0f gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null diff --git a/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml index 9d050b5b01b..849b9ae08b9 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/ml-cuda/spack.yaml @@ -6,6 +6,7 @@ spack: unify: false config: + build_jobs: 32 concretizer: clingo install_tree: root: /home/software/spack @@ -95,6 +96,7 @@ spack: script: - uname -a || true - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true + - nproc - curl -Lfs 'https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0+1/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz' -o gmake.tar.gz - printf 'fef1f59e56d2d11e6d700ba22d3444b6e583c663d6883fd0a4f63ab8bd280f0f gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null diff --git a/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml index f1c5fa39567..e49e805fc72 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/ml-rocm/spack.yaml @@ -6,6 +6,7 @@ spack: unify: false config: + build_jobs: 32 concretizer: clingo install_tree: root: /home/software/spack @@ -98,6 +99,7 @@ spack: script: - uname -a || true - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true + - nproc - curl -Lfs 'https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0+1/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz' -o gmake.tar.gz - printf 'fef1f59e56d2d11e6d700ba22d3444b6e583c663d6883fd0a4f63ab8bd280f0f gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null diff --git a/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws-aarch64/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws-aarch64/spack.yaml index 2de97c89963..1c597d10df0 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws-aarch64/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws-aarch64/spack.yaml @@ -6,6 +6,7 @@ spack: unify: false config: + build_jobs: 32 concretizer: clingo install_tree: root: /home/software/spack @@ -58,6 +59,7 @@ spack: script: - uname -a || true - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true + - nproc - curl -Lfs 'https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0+1/GNUMake.v4.3.0.aarch64-linux-gnu.tar.gz' -o gmake.tar.gz - printf '2322c175fb092b426f9eb6c24ee22d94ffa6759c3d0c260b74d81abd8120122b gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null diff --git a/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws/spack.yaml index 0c80154af83..ce93b57303a 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/radiuss-aws/spack.yaml @@ -6,6 +6,7 @@ spack: unify: false config: + build_jobs: 32 concretizer: clingo install_tree: root: /home/software/spack @@ -63,6 +64,7 @@ spack: script: - uname -a || true - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true + - nproc - curl -Lfs 'https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0+1/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz' -o gmake.tar.gz - printf 'fef1f59e56d2d11e6d700ba22d3444b6e583c663d6883fd0a4f63ab8bd280f0f gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null diff --git a/share/spack/gitlab/cloud_pipelines/stacks/radiuss/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/radiuss/spack.yaml index ef8696a4b64..fc7700be11f 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/radiuss/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/radiuss/spack.yaml @@ -6,6 +6,7 @@ spack: unify: false config: + build_jobs: 32 concretizer: clingo install_tree: root: /home/software/radiuss @@ -66,6 +67,7 @@ spack: script: - uname -a || true - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true + - nproc - curl -Lfs 'https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0+1/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz' -o gmake.tar.gz - printf 'fef1f59e56d2d11e6d700ba22d3444b6e583c663d6883fd0a4f63ab8bd280f0f gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null diff --git a/share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml b/share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml index 2f229962c9c..58ee39c1139 100644 --- a/share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml +++ b/share/spack/gitlab/cloud_pipelines/stacks/tutorial/spack.yaml @@ -6,6 +6,7 @@ spack: unify: false config: + build_jobs: 32 install_tree: root: /home/software/spack padded_length: 512 @@ -67,6 +68,7 @@ spack: script: - uname -a || true - grep -E 'vendor|model name' /proc/cpuinfo 2>/dev/null | sort -u || head -n10 /proc/cpuinfo 2>/dev/null || true + - nproc - curl -Lfs 'https://github.com/JuliaBinaryWrappers/GNUMake_jll.jl/releases/download/GNUMake-v4.3.0+1/GNUMake.v4.3.0.x86_64-linux-gnu.tar.gz' -o gmake.tar.gz - printf 'fef1f59e56d2d11e6d700ba22d3444b6e583c663d6883fd0a4f63ab8bd280f0f gmake.tar.gz' | sha256sum --check --strict --quiet - tar -xzf gmake.tar.gz -C /usr bin/make 2> /dev/null From a079722b1cc95c1b857f14d549c5ab8157cbb3b9 Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Tue, 8 Nov 2022 14:58:33 +0100 Subject: [PATCH 420/442] r: fix order of execution for Makeconf filtering (#33752) fixes #33747 --- var/spack/repos/builtin/packages/r/package.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/var/spack/repos/builtin/packages/r/package.py b/var/spack/repos/builtin/packages/r/package.py index b1656455244..7aa60e37ba4 100644 --- a/var/spack/repos/builtin/packages/r/package.py +++ b/var/spack/repos/builtin/packages/r/package.py @@ -107,8 +107,6 @@ def url_for_version(self, version): url = "https://cloud.r-project.org/src/base" return url + "/R-%s/R-%s.tar.gz" % (version.up_to(1), version) - filter_compiler_wrappers("Makeconf", relative_root=os.path.join("rlib", "R", "etc")) - @property def etcdir(self): return join_path(prefix, "rlib", "R", "etc") @@ -187,6 +185,9 @@ def copy_makeconf(self): dst_makeconf = join_path(self.etcdir, "Makeconf.spack") install(src_makeconf, dst_makeconf) + # To respect order of execution, we should filter after we made the copy above + filter_compiler_wrappers("Makeconf", relative_root=os.path.join("rlib", "R", "etc")) + # ======================================================================== # Set up environment to make install easy for R extensions. # ======================================================================== From 89976af732a3055dbc6b2bfe3fae057e58e1293f Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Tue, 8 Nov 2022 16:03:15 +0100 Subject: [PATCH 421/442] scons: fix Scons builder after multi build-system refactoring (#33753) --- lib/spack/spack/build_systems/scons.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/spack/spack/build_systems/scons.py b/lib/spack/spack/build_systems/scons.py index f1ae9559177..2b1c36316ec 100644 --- a/lib/spack/spack/build_systems/scons.py +++ b/lib/spack/spack/build_systems/scons.py @@ -21,8 +21,6 @@ class SConsPackage(spack.package_base.PackageBase): #: build-system class we are using build_system_class = "SConsPackage" - #: Callback names for build-time test - build_time_test_callbacks = ["build_test"] #: Legacy buildsystem attribute used to deserialize and install old specs legacy_buildsystem = "scons" @@ -48,18 +46,24 @@ class SConsBuilder(BaseBuilder): phases = ("build", "install") #: Names associated with package methods in the old build-system format - legacy_methods = ("build_args", "install_args", "build_test") + legacy_methods = ("install_args", "build_test") + + #: Same as legacy_methods, but the signature is different + legacy_long_methods = ("build_args",) #: Names associated with package attributes in the old build-system format - legacy_attributes = () + legacy_attributes = ("build_time_test_callbacks",) - def build_args(self): + #: Callback names for build-time test + build_time_test_callbacks = ["build_test"] + + def build_args(self, spec, prefix): """Arguments to pass to build.""" return [] def build(self, pkg, spec, prefix): """Build the package.""" - args = self.build_args() + args = self.build_args(spec, prefix) inspect.getmodule(self.pkg).scons(*args) def install_args(self): From e4c2d1afc6952426ce148e439d781881f38b6cfe Mon Sep 17 00:00:00 2001 From: Annop Wongwathanarat Date: Tue, 8 Nov 2022 15:44:03 +0000 Subject: [PATCH 422/442] gromacs: enable linking with armpl-gcc FFT (#33750) --- var/spack/repos/builtin/packages/gromacs/package.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/var/spack/repos/builtin/packages/gromacs/package.py b/var/spack/repos/builtin/packages/gromacs/package.py index 52e66ee4cdc..95bc7dab985 100644 --- a/var/spack/repos/builtin/packages/gromacs/package.py +++ b/var/spack/repos/builtin/packages/gromacs/package.py @@ -489,6 +489,13 @@ def cmake_args(self): options.append( "-DFFTWF_LIBRARIES={0}".format(self.spec["amdfftw"].libs.joined(";")) ) + elif "^armpl-gcc" in self.spec: + options.append( + "-DFFTWF_INCLUDE_DIR={0}".format(self.spec["armpl-gcc"].headers.directories[0]) + ) + options.append( + "-DFFTWF_LIBRARY={0}".format(self.spec["armpl-gcc"].libs.joined(";")) + ) # Ensure that the GROMACS log files report how the code was patched # during the build, so that any problems are easier to diagnose. From bca8b52a8d2448e60d54fdb7ce3490d1e4c566eb Mon Sep 17 00:00:00 2001 From: Dave Love Date: Tue, 8 Nov 2022 17:06:58 +0000 Subject: [PATCH 423/442] cosma: Add shared option (#33751) --- var/spack/repos/builtin/packages/cosma/package.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/var/spack/repos/builtin/packages/cosma/package.py b/var/spack/repos/builtin/packages/cosma/package.py index 7b52650c81a..6ea66510386 100644 --- a/var/spack/repos/builtin/packages/cosma/package.py +++ b/var/spack/repos/builtin/packages/cosma/package.py @@ -33,6 +33,7 @@ class Cosma(CMakePackage): variant("cuda", default=False, description="Build with cuBLAS support") variant("rocm", default=False, description="Build with rocBLAS support") variant("scalapack", default=False, description="Build with ScaLAPACK API") + variant("shared", default=False, description="Build the shared library version") depends_on("cmake@3.12:", type="build") depends_on("mpi@3:") @@ -91,10 +92,11 @@ def cosma_scalapack_cmake_arg(self): def cmake_args(self): return [ - self.define("COSMA_WITH_TESTS", "OFF"), - self.define("COSMA_WITH_APPS", "OFF"), - self.define("COSMA_WITH_PROFILING", "OFF"), - self.define("COSMA_WITH_BENCHMARKS", "OFF"), + self.define("COSMA_WITH_TESTS", False), + self.define("COSMA_WITH_APPS", False), + self.define("COSMA_WITH_PROFILING", False), + self.define("COSMA_WITH_BENCHMARKS", False), self.define("COSMA_BLAS", self.cosma_blas_cmake_arg()), self.define("COSMA_SCALAPACK", self.cosma_scalapack_cmake_arg()), + self.define_from_variant("BUILD_SHARED_LIBS", "shared"), ] From 80f5939a9465ce2ab7f2508f9a3c32c4ac7e83ea Mon Sep 17 00:00:00 2001 From: Stephen Sachs Date: Tue, 8 Nov 2022 18:19:55 +0100 Subject: [PATCH 424/442] Install from source if binary cache checksum validation fails (#31696) * Fix https://github.com/spack/spack/issues/31640 Some packages in the binary cache fail checksum validation. Instead of having to go back and manually install all failed packages with `--no-cache` option, requeue those failed packages for installation from source ```shell $ spack install py-pip ==> Installing py-pip-21.3.1-s2cx4gqrqkdqhashlinqyzkrvuwkl3x7 ==> Fetching https://binaries.spack.io/releases/v0.18/build_cache/linux-amzn2-graviton2-gcc-7.3.1-py-pip-21.3.1-s2cx4gqrqkdqhashlinqyzkrvuwkl3x7.spec.json.sig gpg: Signature made Wed 20 Jul 2022 12:13:43 PM UTC using RSA key ID 3DB0C723 gpg: Good signature from "Spack Project Official Binaries " ==> Fetching https://binaries.spack.io/releases/v0.18/build_cache/linux-amzn2-graviton2/gcc-7.3.1/py-pip-21.3.1/linux-amzn2-graviton2-gcc-7.3.1-py-pip-21.3.1-s2cx4gqrqkdqhashlinqyzkrvuwkl3x7.spack ==> Extracting py-pip-21.3.1-s2cx4gqrqkdqhashlinqyzkrvuwkl3x7 from binary cache ==> Error: Failed to install py-pip due to NoChecksumException: Requeue for manual installation. ==> Installing py-pip-21.3.1-s2cx4gqrqkdqhashlinqyzkrvuwkl3x7 ==> Using cached archive: /shared/spack/var/spack/cache/_source-cache/archive/de/deaf32dcd9ab821e359cd8330786bcd077604b5c5730c0b096eda46f95c24a2d ==> No patches needed for py-pip ==> py-pip: Executing phase: 'install' ==> py-pip: Successfully installed py-pip-21.3.1-s2cx4gqrqkdqhashlinqyzkrvuwkl3x7 Fetch: 0.01s. Build: 2.81s. Total: 2.82s. [+] /shared/spack/opt/spack/linux-amzn2-graviton2/gcc-7.3.1/py-pip-21.3.1-s2cx4gqrqkdqhashlinqyzkrvuwkl3x7 ``` * Cleanup style * better wording Co-authored-by: Tamara Dahlgren <35777542+tldahlgren@users.noreply.github.com> * Update lib/spack/spack/installer.py Co-authored-by: Tamara Dahlgren <35777542+tldahlgren@users.noreply.github.com> * changes quotes for style checks * Update lib/spack/spack/installer.py Co-authored-by: kwryankrattiger <80296582+kwryankrattiger@users.noreply.github.com> * Addressing @kwryankrattiger comment to use local 'use_cache` Co-authored-by: Stephen Sachs Co-authored-by: Tamara Dahlgren <35777542+tldahlgren@users.noreply.github.com> Co-authored-by: kwryankrattiger <80296582+kwryankrattiger@users.noreply.github.com> --- lib/spack/spack/installer.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/spack/spack/installer.py b/lib/spack/spack/installer.py index a0f505a922d..252c799304e 100644 --- a/lib/spack/spack/installer.py +++ b/lib/spack/spack/installer.py @@ -1773,6 +1773,16 @@ def install(self): spack.hooks.on_install_cancel(task.request.pkg.spec) raise + except binary_distribution.NoChecksumException as exc: + if not task.cache_only: + # Checking hash on downloaded binary failed. + err = "Failed to install {0} from binary cache due to {1}:" + err += " Requeueing to install from source." + tty.error(err.format(pkg.name, str(exc))) + task.use_cache = False + self._requeue_task(task) + continue + except (Exception, SystemExit) as exc: self._update_failed(task, True, exc) spack.hooks.on_install_failure(task.request.pkg.spec) From 052bf6b9dfe6cf6539c22b915a9d026d6fc37cd6 Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Tue, 8 Nov 2022 18:38:45 +0100 Subject: [PATCH 425/442] python: 3.11.0 (#33507) --- .../repos/builtin/packages/python/package.py | 19 +- .../python/python-3.11-distutils-C++.patch | 257 ++++++++++++++++++ .../packages/python/tkinter-3.11.patch | 25 ++ 3 files changed, 293 insertions(+), 8 deletions(-) create mode 100644 var/spack/repos/builtin/packages/python/python-3.11-distutils-C++.patch create mode 100644 var/spack/repos/builtin/packages/python/tkinter-3.11.patch diff --git a/var/spack/repos/builtin/packages/python/package.py b/var/spack/repos/builtin/packages/python/package.py index 3fea87a2ec7..1681e2524e0 100644 --- a/var/spack/repos/builtin/packages/python/package.py +++ b/var/spack/repos/builtin/packages/python/package.py @@ -44,7 +44,12 @@ class Python(Package): install_targets = ["install"] build_targets = [] # type: List[str] - version("3.10.8", sha256="f400c3fb394b8bef1292f6dc1292c5fadc3533039a5bc0c3e885f3e16738029a") + version("3.11.0", sha256="64424e96e2457abbac899b90f9530985b51eef2905951febd935f0e73414caeb") + version( + "3.10.8", + sha256="f400c3fb394b8bef1292f6dc1292c5fadc3533039a5bc0c3e885f3e16738029a", + preferred=True, + ) version("3.10.7", sha256="1b2e4e2df697c52d36731666979e648beeda5941d0f95740aafbf4163e5cc126") version("3.10.6", sha256="848cb06a5caa85da5c45bd7a9221bb821e33fc2bdcba088c127c58fad44e6343") version("3.10.5", sha256="18f57182a2de3b0be76dfc39fdcfd28156bb6dd23e5f08696f7492e9e3d0bf2d") @@ -53,11 +58,7 @@ class Python(Package): version("3.10.2", sha256="3c0ede893011319f9b0a56b44953a3d52c7abf9657c23fb4bc9ced93b86e9c97") version("3.10.1", sha256="b76117670e7c5064344b9c138e141a377e686b9063f3a8a620ff674fa8ec90d3") version("3.10.0", sha256="c4e0cbad57c90690cb813fb4663ef670b4d0f587d8171e2c42bd4c9245bd2758") - version( - "3.9.15", - sha256="48d1ccb29d5fbaf1fb8f912271d09f7450e426d4dfe95978ef6aaada70ece4d8", - preferred=True, - ) + version("3.9.15", sha256="48d1ccb29d5fbaf1fb8f912271d09f7450e426d4dfe95978ef6aaada70ece4d8") version("3.9.14", sha256="9201836e2c16361b2b7408680502393737d44f227333fe2e5729c7d5f6041675") version("3.9.13", sha256="829b0d26072a44689a6b0810f5b4a3933ee2a0b8a4bfc99d7c5893ffd4f97c44") version("3.9.12", sha256="70e08462ebf265012bd2be88a63d2149d880c73e53f1712b7bbbe93750560ae8") @@ -420,14 +421,16 @@ class Python(Package): patch("python-2.7.17+-distutils-C++-fixup.patch", when="@2.7.17:2.7.18") patch("python-3.6.8-distutils-C++.patch", when="@3.6.8,3.7.2") patch("python-3.7.3-distutils-C++.patch", when="@3.7.3") - patch("python-3.7.4+-distutils-C++.patch", when="@3.7.4:") + patch("python-3.7.4+-distutils-C++.patch", when="@3.7.4:3.10") patch("python-3.7.4+-distutils-C++-testsuite.patch", when="@3.7.4:") + patch("python-3.11-distutils-C++.patch", when="@3.11.0:3.11") patch("cpython-windows-externals.patch", when="@:3.9.6 platform=windows") patch("tkinter.patch", when="@:2.8,3.3:3.7 platform=darwin") # Patch the setup script to deny that tcl/x11 exists rather than allowing # autodetection of (possibly broken) system components patch("tkinter-3.8.patch", when="@3.8:3.9 ~tkinter") - patch("tkinter-3.10.patch", when="@3.10: ~tkinter") + patch("tkinter-3.10.patch", when="@3.10.0:3.10 ~tkinter") + patch("tkinter-3.11.patch", when="@3.11.0:3.11 ~tkinter") # Ensure that distutils chooses correct compiler option for RPATH on cray: patch("cray-rpath-2.3.patch", when="@2.3:3.0.1 platform=cray") diff --git a/var/spack/repos/builtin/packages/python/python-3.11-distutils-C++.patch b/var/spack/repos/builtin/packages/python/python-3.11-distutils-C++.patch new file mode 100644 index 00000000000..335e06b93c3 --- /dev/null +++ b/var/spack/repos/builtin/packages/python/python-3.11-distutils-C++.patch @@ -0,0 +1,257 @@ +diff --git a/Lib/_osx_support.py b/Lib/_osx_support.py +index aa66c8b9f4..71e6556bac 100644 +--- a/Lib/_osx_support.py ++++ b/Lib/_osx_support.py +@@ -14,13 +14,13 @@ + # configuration variables that may contain universal build flags, + # like "-arch" or "-isdkroot", that may need customization for + # the user environment +-_UNIVERSAL_CONFIG_VARS = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS', 'BASECFLAGS', +- 'BLDSHARED', 'LDSHARED', 'CC', 'CXX', +- 'PY_CFLAGS', 'PY_LDFLAGS', 'PY_CPPFLAGS', +- 'PY_CORE_CFLAGS', 'PY_CORE_LDFLAGS') ++_UNIVERSAL_CONFIG_VARS = ('CFLAGS', 'CXXFLAGS', 'LDFLAGS', 'CPPFLAGS', ++ 'BASECFLAGS', 'BLDSHARED', 'LDSHARED', 'LDCXXSHARED', ++ 'CC', 'CXX', 'PY_CFLAGS', 'PY_LDFLAGS', ++ 'PY_CPPFLAGS', 'PY_CORE_LDFLAGS', 'PY_CORE_CFLAGS') + + # configuration variables that may contain compiler calls +-_COMPILER_CONFIG_VARS = ('BLDSHARED', 'LDSHARED', 'CC', 'CXX') ++_COMPILER_CONFIG_VARS = ('BLDSHARED', 'LDSHARED', 'LDCXXSHARED', 'CC', 'CXX') + + # prefix added to original configuration variable names + _INITPRE = '_OSX_SUPPORT_INITIAL_' +diff --git a/Lib/distutils/cygwinccompiler.py b/Lib/distutils/cygwinccompiler.py +index 66c12dd358..dddb9fd2d4 100644 +--- a/Lib/distutils/cygwinccompiler.py ++++ b/Lib/distutils/cygwinccompiler.py +@@ -123,8 +123,10 @@ def __init__(self, verbose=0, dry_run=0, force=0): + # dllwrap 2.10.90 is buggy + if self.ld_version >= "2.10.90": + self.linker_dll = "gcc" ++ self.linker_dll_cxx = "g++" + else: + self.linker_dll = "dllwrap" ++ self.linker_dll_cxx = "dllwrap" + + # ld_version >= "2.13" support -shared so use it instead of + # -mdll -static +@@ -138,9 +140,13 @@ def __init__(self, verbose=0, dry_run=0, force=0): + self.set_executables(compiler='gcc -mcygwin -O -Wall', + compiler_so='gcc -mcygwin -mdll -O -Wall', + compiler_cxx='g++ -mcygwin -O -Wall', ++ compiler_so_cxx='g++ -mcygwin -mdll -O -Wall', + linker_exe='gcc -mcygwin', + linker_so=('%s -mcygwin %s' % +- (self.linker_dll, shared_option))) ++ (self.linker_dll, shared_option)), ++ linker_exe_cxx='g++ -mcygwin', ++ linker_so_cxx=('%s -mcygwin %s' % ++ (self.linker_dll_cxx, shared_option))) + + # cygwin and mingw32 need different sets of libraries + if self.gcc_version == "2.91.57": +@@ -164,8 +170,12 @@ def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts): + raise CompileError(msg) + else: # for other files use the C-compiler + try: +- self.spawn(self.compiler_so + cc_args + [src, '-o', obj] + +- extra_postargs) ++ if self.detect_language(src) == 'c++': ++ self.spawn(self.compiler_so_cxx + cc_args + [src, '-o', obj] + ++ extra_postargs) ++ else: ++ self.spawn(self.compiler_so + cc_args + [src, '-o', obj] + ++ extra_postargs) + except DistutilsExecError as msg: + raise CompileError(msg) + +@@ -300,9 +310,14 @@ def __init__(self, verbose=0, dry_run=0, force=0): + self.set_executables(compiler='gcc -O -Wall', + compiler_so='gcc -mdll -O -Wall', + compiler_cxx='g++ -O -Wall', ++ compiler_so_cxx='g++ -mdll -O -Wall', + linker_exe='gcc', + linker_so='%s %s %s' + % (self.linker_dll, shared_option, ++ entry_point), ++ linker_exe_cxx='g++', ++ linker_so_cxx='%s %s %s' ++ % (self.linker_dll_cxx, shared_option, + entry_point)) + # Maybe we should also append -mthreads, but then the finished + # dlls need another dll (mingwm10.dll see Mingw32 docs) +diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py +index 3414a761e7..f1af560cc1 100644 +--- a/Lib/distutils/sysconfig.py ++++ b/Lib/distutils/sysconfig.py +@@ -216,9 +216,11 @@ def customize_compiler(compiler): + _osx_support.customize_compiler(_config_vars) + _config_vars['CUSTOMIZED_OSX_COMPILER'] = 'True' + +- (cc, cxx, cflags, ccshared, ldshared, shlib_suffix, ar, ar_flags) = \ +- get_config_vars('CC', 'CXX', 'CFLAGS', +- 'CCSHARED', 'LDSHARED', 'SHLIB_SUFFIX', 'AR', 'ARFLAGS') ++ (cc, cxx, cflags, ccshared, ldshared, ldcxxshared, shlib_suffix, ar, ar_flags) = \ ++ get_config_vars('CC', 'CXX', 'CFLAGS', 'CCSHARED', 'LDSHARED', 'LDCXXSHARED', ++ 'SHLIB_SUFFIX', 'AR', 'ARFLAGS') ++ ++ cxxflags = cflags + + if 'CC' in os.environ: + newcc = os.environ['CC'] +@@ -233,19 +235,27 @@ def customize_compiler(compiler): + cxx = os.environ['CXX'] + if 'LDSHARED' in os.environ: + ldshared = os.environ['LDSHARED'] ++ if 'LDCXXSHARED' in os.environ: ++ ldcxxshared = os.environ['LDCXXSHARED'] + if 'CPP' in os.environ: + cpp = os.environ['CPP'] + else: + cpp = cc + " -E" # not always + if 'LDFLAGS' in os.environ: + ldshared = ldshared + ' ' + os.environ['LDFLAGS'] ++ ldcxxshared = ldcxxshared + ' ' + os.environ['LDFLAGS'] + if 'CFLAGS' in os.environ: +- cflags = cflags + ' ' + os.environ['CFLAGS'] ++ cflags = os.environ['CFLAGS'] + ldshared = ldshared + ' ' + os.environ['CFLAGS'] ++ if 'CXXFLAGS' in os.environ: ++ cxxflags = os.environ['CXXFLAGS'] ++ ldcxxshared = ldcxxshared + ' ' + os.environ['CXXFLAGS'] + if 'CPPFLAGS' in os.environ: + cpp = cpp + ' ' + os.environ['CPPFLAGS'] + cflags = cflags + ' ' + os.environ['CPPFLAGS'] ++ cxxflags = cxxflags + ' ' + os.environ['CPPFLAGS'] + ldshared = ldshared + ' ' + os.environ['CPPFLAGS'] ++ ldcxxshared = ldcxxshared + ' ' + os.environ['CPPFLAGS'] + if 'AR' in os.environ: + ar = os.environ['AR'] + if 'ARFLAGS' in os.environ: +@@ -254,13 +264,17 @@ def customize_compiler(compiler): + archiver = ar + ' ' + ar_flags + + cc_cmd = cc + ' ' + cflags ++ cxx_cmd = cxx + ' ' + cxxflags + compiler.set_executables( + preprocessor=cpp, + compiler=cc_cmd, + compiler_so=cc_cmd + ' ' + ccshared, +- compiler_cxx=cxx, ++ compiler_cxx=cxx_cmd, ++ compiler_so_cxx=cxx_cmd + ' ' + ccshared, + linker_so=ldshared, + linker_exe=cc, ++ linker_so_cxx=ldcxxshared, ++ linker_exe_cxx=cxx, + archiver=archiver) + + compiler.shared_lib_extension = shlib_suffix +diff --git a/Lib/distutils/unixccompiler.py b/Lib/distutils/unixccompiler.py +index d00c48981e..4a3d271fee 100644 +--- a/Lib/distutils/unixccompiler.py ++++ b/Lib/distutils/unixccompiler.py +@@ -52,14 +52,17 @@ class UnixCCompiler(CCompiler): + # are pretty generic; they will probably have to be set by an outsider + # (eg. using information discovered by the sysconfig about building + # Python extensions). +- executables = {'preprocessor' : None, +- 'compiler' : ["cc"], +- 'compiler_so' : ["cc"], +- 'compiler_cxx' : ["cc"], +- 'linker_so' : ["cc", "-shared"], +- 'linker_exe' : ["cc"], +- 'archiver' : ["ar", "-cr"], +- 'ranlib' : None, ++ executables = {'preprocessor' : None, ++ 'compiler' : ["cc"], ++ 'compiler_so' : ["cc"], ++ 'compiler_cxx' : ["c++"], ++ 'compiler_so_cxx' : ["c++"], ++ 'linker_so' : ["cc", "-shared"], ++ 'linker_exe' : ["cc"], ++ 'linker_so_cxx' : ["c++", "-shared"], ++ 'linker_exe_cxx' : ["c++"], ++ 'archiver' : ["ar", "-cr"], ++ 'ranlib' : None, + } + + if sys.platform[:6] == "darwin": +@@ -110,12 +113,19 @@ def preprocess(self, source, output_file=None, macros=None, + + def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts): + compiler_so = self.compiler_so ++ compiler_so_cxx = self.compiler_so_cxx + if sys.platform == 'darwin': + compiler_so = _osx_support.compiler_fixup(compiler_so, + cc_args + extra_postargs) ++ compiler_so_cxx = _osx_support.compiler_fixup(compiler_so_cxx, ++ cc_args + extra_postargs) + try: +- self.spawn(compiler_so + cc_args + [src, '-o', obj] + +- extra_postargs) ++ if self.detect_language(src) == 'c++': ++ self.spawn(compiler_so_cxx + cc_args + [src, '-o', obj] + ++ extra_postargs) ++ else: ++ self.spawn(compiler_so + cc_args + [src, '-o', obj] + ++ extra_postargs) + except DistutilsExecError as msg: + raise CompileError(msg) + +@@ -173,30 +183,16 @@ def link(self, target_desc, objects, + ld_args.extend(extra_postargs) + self.mkpath(os.path.dirname(output_filename)) + try: +- if target_desc == CCompiler.EXECUTABLE: +- linker = self.linker_exe[:] ++ if target_lang == "c++": ++ if target_desc == CCompiler.EXECUTABLE: ++ linker = self.linker_exe_cxx[:] ++ else: ++ linker = self.linker_so_cxx[:] + else: +- linker = self.linker_so[:] +- if target_lang == "c++" and self.compiler_cxx: +- # skip over environment variable settings if /usr/bin/env +- # is used to set up the linker's environment. +- # This is needed on OSX. Note: this assumes that the +- # normal and C++ compiler have the same environment +- # settings. +- i = 0 +- if os.path.basename(linker[0]) == "env": +- i = 1 +- while '=' in linker[i]: +- i += 1 +- +- if os.path.basename(linker[i]) == 'ld_so_aix': +- # AIX platforms prefix the compiler with the ld_so_aix +- # script, so we need to adjust our linker index +- offset = 1 ++ if target_desc == CCompiler.EXECUTABLE: ++ linker = self.linker_exe[:] + else: +- offset = 0 +- +- linker[i+offset] = self.compiler_cxx[i] ++ linker = self.linker_so[:] + + if sys.platform == 'darwin': + linker = _osx_support.compiler_fixup(linker, ld_args) +diff --git a/Makefile.pre.in b/Makefile.pre.in +index f803391346..090f14c46c 100644 +--- a/Makefile.pre.in ++++ b/Makefile.pre.in +@@ -732,9 +732,9 @@ sharedmods: $(BUILDPYTHON) pybuilddir.txt @LIBMPDEC_INTERNAL@ @LIBEXPAT_INTERNAL + *\ -s*|s*) quiet="-q";; \ + *) quiet="";; \ + esac; \ +- echo "$(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' OPT='$(OPT)' \ ++ echo "$(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' CFLAGS='$(PY_CFLAGS)' \ + $(PYTHON_FOR_BUILD) $(srcdir)/setup.py $$quiet build"; \ +- $(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' OPT='$(OPT)' \ ++ $(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' CFLAGS='$(PY_CFLAGS)' \ + $(PYTHON_FOR_BUILD) $(srcdir)/setup.py $$quiet build + + diff --git a/var/spack/repos/builtin/packages/python/tkinter-3.11.patch b/var/spack/repos/builtin/packages/python/tkinter-3.11.patch new file mode 100644 index 00000000000..fe2d54bd43c --- /dev/null +++ b/var/spack/repos/builtin/packages/python/tkinter-3.11.patch @@ -0,0 +1,25 @@ +From a49e95e44961a0b6703ef9cb577d2ae5334c4a62 Mon Sep 17 00:00:00 2001 +From: Harmen Stoppels +Date: Thu, 3 Nov 2022 13:54:00 +0100 +Subject: [PATCH] disable tkinter explicitly + +--- + setup.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/setup.py b/setup.py +index 15d0d45..642adb3 100644 +--- a/setup.py ++++ b/setup.py +@@ -1358,7 +1358,7 @@ class PyBuildExt(build_ext): + self.detect_decimal() + self.detect_ctypes() + self.detect_multiprocessing() +- self.detect_tkinter() ++ # self.detect_tkinter() + self.detect_uuid() + + # Uncomment the next line if you want to play with xxmodule.c +-- +2.38.1 + From 97fe7ad32bcdab65beb080843c9eb7bbeae9cb51 Mon Sep 17 00:00:00 2001 From: Greg Becker Date: Tue, 8 Nov 2022 10:36:10 -0800 Subject: [PATCH 426/442] use pwd for usernames on unix (#19980) --- lib/spack/spack/util/path.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/spack/spack/util/path.py b/lib/spack/spack/util/path.py index c378f1eb2da..d18d719c8f7 100644 --- a/lib/spack/spack/util/path.py +++ b/lib/spack/spack/util/path.py @@ -39,6 +39,18 @@ def architecture(): return spack.spec.ArchSpec((str(host_platform), str(host_os), str(host_target))) +def get_user(): + # User pwd where available because it accounts for effective uids when using ksu and similar + try: + # user pwd for unix systems + import pwd + + return pwd.getpwuid(os.geteuid()).pw_name + except ImportError: + # fallback on getpass + return getpass.getuser() + + # Substitutions to perform def replacements(): # break circular import from spack.util.executable @@ -48,7 +60,7 @@ def replacements(): return { "spack": spack.paths.prefix, - "user": getpass.getuser(), + "user": get_user(), "tempdir": tempfile.gettempdir(), "user_cache_path": spack.paths.user_cache_path, "architecture": str(arch), From 4a5e68816bdb83d7b614e586042a1927b7267576 Mon Sep 17 00:00:00 2001 From: eugeneswalker <38933153+eugeneswalker@users.noreply.github.com> Date: Tue, 8 Nov 2022 10:50:02 -0800 Subject: [PATCH 427/442] hypre +rocm: needs explicit rocprim dep (#33745) --- var/spack/repos/builtin/packages/hypre/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/hypre/package.py b/var/spack/repos/builtin/packages/hypre/package.py index a05e8a17013..03a6fc70d88 100644 --- a/var/spack/repos/builtin/packages/hypre/package.py +++ b/var/spack/repos/builtin/packages/hypre/package.py @@ -97,6 +97,7 @@ class Hypre(AutotoolsPackage, CudaPackage, ROCmPackage): depends_on("rocsparse", when="+rocm") depends_on("rocthrust", when="+rocm") depends_on("rocrand", when="+rocm") + depends_on("rocprim", when="+rocm") depends_on("umpire", when="+umpire") for sm_ in CudaPackage.cuda_arch_values: depends_on( From 4d28a6466188ea9fe3b55a4c3d7690dd66e0dc8f Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Tue, 8 Nov 2022 20:05:05 +0100 Subject: [PATCH 428/442] fix racy sbang (#33549) Spack currently creates a temporary sbang that is moved "atomically" in place, but this temporary causes races when multiple processes start installing sbang. Let's just stick to an idempotent approach. Notice that we only re-install sbang if Spack updates it (since we do file compare), and sbang was only touched 18 times in the past 6 years, whereas we hit the sbang tempfile issue frequently with parallel install on a fresh spack instance in CI. Also fixes a bug where permissions weren't updated if config changed but the latest version of the sbang file was already installed. --- lib/spack/llnl/util/filesystem.py | 45 +++++++++++++++++++++----- lib/spack/spack/config.py | 6 ++-- lib/spack/spack/hooks/sbang.py | 53 ++++++++++++++----------------- 3 files changed, 63 insertions(+), 41 deletions(-) diff --git a/lib/spack/llnl/util/filesystem.py b/lib/spack/llnl/util/filesystem.py index aece52f8436..d122280e999 100644 --- a/lib/spack/llnl/util/filesystem.py +++ b/lib/spack/llnl/util/filesystem.py @@ -1000,16 +1000,45 @@ def hash_directory(directory, ignore=[]): return md5_hash.hexdigest() +def _try_unlink(path): + try: + os.unlink(path) + except (IOError, OSError): + # But if that fails, that's OK. + pass + + @contextmanager @system_path_filter -def write_tmp_and_move(filename): - """Write to a temporary file, then move into place.""" - dirname = os.path.dirname(filename) - basename = os.path.basename(filename) - tmp = os.path.join(dirname, ".%s.tmp" % basename) - with open(tmp, "w") as f: - yield f - shutil.move(tmp, filename) +def write_tmp_and_move(path, mode="w"): + """Write to a temporary file in the same directory, then move into place.""" + # Rely on NamedTemporaryFile to give a unique file without races + # in the directory of the target file. + file = tempfile.NamedTemporaryFile( + prefix="." + os.path.basename(path), + suffix=".tmp", + dir=os.path.dirname(path), + mode=mode, + delete=False, # we delete it ourselves + ) + tmp_path = file.name + + try: + yield file + except BaseException: + # On any failure, try to remove the temporary file. + _try_unlink(tmp_path) + raise + finally: + # Always close the file decriptor + file.close() + + # Atomically move into existence. + try: + os.rename(tmp_path, path) + except (IOError, OSError): + _try_unlink(tmp_path) + raise @contextmanager diff --git a/lib/spack/spack/config.py b/lib/spack/spack/config.py index e9a3b1d9568..f35310986e3 100644 --- a/lib/spack/spack/config.py +++ b/lib/spack/spack/config.py @@ -45,7 +45,7 @@ import llnl.util.lang import llnl.util.tty as tty -from llnl.util.filesystem import mkdirp, rename +from llnl.util.filesystem import mkdirp, write_tmp_and_move import spack.compilers import spack.paths @@ -287,10 +287,8 @@ def _write_section(self, section): parent = os.path.dirname(self.path) mkdirp(parent) - tmp = os.path.join(parent, ".%s.tmp" % os.path.basename(self.path)) - with open(tmp, "w") as f: + with write_tmp_and_move(self.path) as f: syaml.dump_config(data_to_write, stream=f, default_flow_style=False) - rename(tmp, self.path) except (yaml.YAMLError, IOError) as e: raise ConfigFileError("Error writing to config file: '%s'" % str(e)) diff --git a/lib/spack/spack/hooks/sbang.py b/lib/spack/spack/hooks/sbang.py index 5d2de2b8655..e22c2929c2c 100644 --- a/lib/spack/spack/hooks/sbang.py +++ b/lib/spack/spack/hooks/sbang.py @@ -186,44 +186,39 @@ def install_sbang(): ``sbang`` here ensures that users can access the script and that ``sbang`` itself is in a short path. """ - # copy in a new version of sbang if it differs from what's in spack sbang_path = sbang_install_path() - if os.path.exists(sbang_path) and filecmp.cmp(spack.paths.sbang_script, sbang_path): - return - # make $install_tree/bin + all = spack.spec.Spec("all") + group_name = spack.package_prefs.get_package_group(all) + config_mode = spack.package_prefs.get_package_dir_permissions(all) + group_id = grp.getgrnam(group_name).gr_gid if group_name else None + + # First setup the bin dir correctly. sbang_bin_dir = os.path.dirname(sbang_path) - fs.mkdirp(sbang_bin_dir) + if not os.path.isdir(sbang_bin_dir): + fs.mkdirp(sbang_bin_dir) - # get permissions for bin dir from configuration files - group_name = spack.package_prefs.get_package_group(spack.spec.Spec("all")) - config_mode = spack.package_prefs.get_package_dir_permissions(spack.spec.Spec("all")) - - if group_name: - os.chmod(sbang_bin_dir, config_mode) # Use package directory permissions + # Set group and ownership like we do on package directories + if group_id: + os.chown(sbang_bin_dir, os.stat(sbang_bin_dir).st_uid, group_id) + os.chmod(sbang_bin_dir, config_mode) else: fs.set_install_permissions(sbang_bin_dir) - # set group on sbang_bin_dir if not already set (only if set in configuration) - # TODO: after we drop python2 support, use shutil.chown to avoid gid lookups that - # can fail for remote groups - if group_name and os.stat(sbang_bin_dir).st_gid != grp.getgrnam(group_name).gr_gid: - os.chown(sbang_bin_dir, os.stat(sbang_bin_dir).st_uid, grp.getgrnam(group_name).gr_gid) + # Then check if we need to install sbang itself. + try: + already_installed = filecmp.cmp(spack.paths.sbang_script, sbang_path) + except (IOError, OSError): + already_installed = False - # copy over the fresh copy of `sbang` - sbang_tmp_path = os.path.join( - os.path.dirname(sbang_path), - ".%s.tmp" % os.path.basename(sbang_path), - ) - shutil.copy(spack.paths.sbang_script, sbang_tmp_path) + if not already_installed: + with fs.write_tmp_and_move(sbang_path) as f: + shutil.copy(spack.paths.sbang_script, f.name) - # set permissions on `sbang` (including group if set in configuration) - os.chmod(sbang_tmp_path, config_mode) - if group_name: - os.chown(sbang_tmp_path, os.stat(sbang_tmp_path).st_uid, grp.getgrnam(group_name).gr_gid) - - # Finally, move the new `sbang` into place atomically - os.rename(sbang_tmp_path, sbang_path) + # Set permissions on `sbang` (including group if set in configuration) + os.chmod(sbang_path, config_mode) + if group_id: + os.chown(sbang_path, os.stat(sbang_path).st_uid, group_id) def post_install(spec): From 0f26d4402e05f35d3ec49a16826afcc62a70a575 Mon Sep 17 00:00:00 2001 From: Wouter Deconinck Date: Tue, 8 Nov 2022 13:54:28 -0600 Subject: [PATCH 429/442] hepmc3: new version 3.2.5 (#33748) Changelog at https://gitlab.cern.ch/hepmc/HepMC3/-/tags/3.2.5 Maintainer: @vvolkl --- var/spack/repos/builtin/packages/hepmc3/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/hepmc3/package.py b/var/spack/repos/builtin/packages/hepmc3/package.py index e673faf8544..99c2084cd5c 100644 --- a/var/spack/repos/builtin/packages/hepmc3/package.py +++ b/var/spack/repos/builtin/packages/hepmc3/package.py @@ -18,6 +18,7 @@ class Hepmc3(CMakePackage): maintainers = ["vvolkl"] + version("3.2.5", sha256="cd0f75c80f75549c59cc2a829ece7601c77de97cb2a5ab75790cac8e1d585032") version("3.2.4", sha256="e088fccfd1a6c2f8e1089f457101bee1e5c7a9777e9d51c6419c8a288a49e1bb") version("3.2.3", sha256="8caadacc2c969883cd1f994b622795fc885fb4b15dad8c8ae64bcbdbf0cbd47d") version("3.2.2", sha256="0e8cb4f78f804e38f7d29875db66f65e4c77896749d723548cc70fb7965e2d41") From a8470a7efed2bb0a39d2c3e9e6bae642c110e7ca Mon Sep 17 00:00:00 2001 From: Xavier Delaruelle Date: Tue, 8 Nov 2022 21:10:22 +0100 Subject: [PATCH 430/442] environment-modules: add version 5.2.0 (#33762) --- .../repos/builtin/packages/environment-modules/package.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/environment-modules/package.py b/var/spack/repos/builtin/packages/environment-modules/package.py index f33debb6eab..3d0fb99fc1c 100644 --- a/var/spack/repos/builtin/packages/environment-modules/package.py +++ b/var/spack/repos/builtin/packages/environment-modules/package.py @@ -13,10 +13,11 @@ class EnvironmentModules(Package): """ homepage = "https://cea-hpc.github.io/modules/" - url = "https://github.com/cea-hpc/modules/releases/download/v5.1.1/modules-5.1.1.tar.gz" + url = "https://github.com/cea-hpc/modules/releases/download/v5.2.0/modules-5.2.0.tar.gz" maintainers = ["xdelaruelle"] + version("5.2.0", sha256="48f9f10864303df628a48cab17074820a6251ad8cd7d66dd62aa7798af479254") version("5.1.1", sha256="1985f79e0337f63d6564b08db0238cf96a276a4184def822bb8ad37996dc8295") version("5.1.0", sha256="1ab1e859b9c8bca8a8d332945366567fae4cf8dd7e312a689daaff46e7ffa949") version("5.0.1", sha256="33a598eaff0713de09e479c2636ecde188b982584e56377f234e5065a61be7ba") From e53a19a08d7be15f762e6115745b05f88058fc9f Mon Sep 17 00:00:00 2001 From: Mikael Simberg Date: Tue, 8 Nov 2022 21:14:14 +0100 Subject: [PATCH 431/442] Patch `fmt` for hipcc/dpcpp (#33733) * Patch fmt for hipcc/dpcpp * Add msimberg as fmt maintainer --- var/spack/repos/builtin/packages/fmt/package.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/var/spack/repos/builtin/packages/fmt/package.py b/var/spack/repos/builtin/packages/fmt/package.py index 7a79ad0da66..0c51c1a5af9 100644 --- a/var/spack/repos/builtin/packages/fmt/package.py +++ b/var/spack/repos/builtin/packages/fmt/package.py @@ -13,6 +13,7 @@ class Fmt(CMakePackage): homepage = "https://fmt.dev/" url = "https://github.com/fmtlib/fmt/releases/download/7.1.3/fmt-7.1.3.zip" + maintainers = ["msimberg"] version("9.1.0", sha256="cceb4cb9366e18a5742128cb3524ce5f50e88b476f1e54737a47ffdf4df4c996") version("9.0.0", sha256="fc96dd2d2fdf2bded630787adba892c23cb9e35c6fd3273c136b0c57d4651ad6") @@ -70,6 +71,13 @@ class Fmt(CMakePackage): # Only allow [[attributes]] on C++11 and higher patch("fmt-attributes-cpp11_4.1.0.patch", when="@4.1.0") + # Fix compilation with hipcc/dpcpp: https://github.com/fmtlib/fmt/issues/3005 + patch( + "https://github.com/fmtlib/fmt/commit/0b0f7cfbfcebd021c910078003d413354bd843e2.patch?full_index=1", + sha256="08fb707bf8b4fc890d6eed29217ead666558cbae38f9249e22ddb82212f0eb4a", + when="@9.0.0:9.1.0", + ) + def cmake_args(self): spec = self.spec args = [] From 05fd39477e723b051f9b830d3c39ac0a74f9234d Mon Sep 17 00:00:00 2001 From: iarspider Date: Wed, 9 Nov 2022 00:10:29 +0100 Subject: [PATCH 432/442] Add checksum for py-protobuf 4.21.7, protobuf 21.7; remove protobuf and py-protobuf 2.x (#32977) * Add checksum for py-protobuf 4.21.7, protobuf 21.7 * Update var/spack/repos/builtin/packages/protobuf/package.py Co-authored-by: Adam J. Stewart * Update package.py * Update var/spack/repos/builtin/packages/protobuf/package.py Co-authored-by: Adam J. Stewart * Update var/spack/repos/builtin/packages/protobuf/package.py Co-authored-by: Adam J. Stewart * Update package.py * Update package.py * Delete protoc2.5.0_aarch64.patch * Update package.py * Restore but deprecate py-protobuf 3.0.0a/b; deprecate py-tensorflow 0.x * Fix audit Co-authored-by: Adam J. Stewart --- .../builtin/packages/protobuf/package.py | 50 ++------ .../protobuf/protoc2.5.0_aarch64.patch | 113 ------------------ .../builtin/packages/py-protobuf/package.py | 23 ++-- .../builtin/packages/py-tensorflow/package.py | 48 ++++++-- 4 files changed, 59 insertions(+), 175 deletions(-) delete mode 100644 var/spack/repos/builtin/packages/protobuf/protoc2.5.0_aarch64.patch diff --git a/var/spack/repos/builtin/packages/protobuf/package.py b/var/spack/repos/builtin/packages/protobuf/package.py index c0fbeeaa8c3..ab78a889445 100644 --- a/var/spack/repos/builtin/packages/protobuf/package.py +++ b/var/spack/repos/builtin/packages/protobuf/package.py @@ -9,12 +9,13 @@ from spack.package import * -class Protobuf(Package): +class Protobuf(CMakePackage): """Google's data interchange format.""" homepage = "https://developers.google.com/protocol-buffers" url = "https://github.com/protocolbuffers/protobuf/archive/v3.18.0.tar.gz" + version("3.21.7", sha256="ce2fbea3c78147a41b2a922485d283137845303e5e1b6cbd7ece94b96ade7031") version("3.21.5", sha256="d7d204a59fd0d2d2387bd362c2155289d5060f32122c4d1d922041b61191d522") version("3.21.4", sha256="85d42d4485f36f8cec3e475a3b9e841d7d78523cd775de3a86dba77081f4ca25") version("3.21.3", sha256="c29d8b4b79389463c546f98b15aa4391d4ed7ec459340c47bffe15db63eb9126") @@ -65,11 +66,6 @@ class Protobuf(Package): version("3.2.0", sha256="a839d3f1519ff9d68ab908de5a0f269650ef1fc501c10f6eefd4cae51d29b86f") version("3.1.0", sha256="fb2a314f4be897491bb2446697be693d489af645cb0e165a85e7e64e07eb134d") version("3.0.2", sha256="a0a265bcc9d4e98c87416e59c33afc37cede9fb277292523739417e449b18c1e") - version( - "2.5.0", - sha256="c2665a7aa2ac1a206e61b28e014486e3de59009ea2be2bde9182e0847f38b62f", - deprecated=True, - ) variant("shared", default=True, description="Enables the build of shared libraries") variant( @@ -79,12 +75,7 @@ class Protobuf(Package): values=("Debug", "Release", "RelWithDebInfo"), ) - depends_on("cmake", when="@3.0.2:", type="build") depends_on("zlib") - depends_on("autoconf", type="build", when="@2.5.0") - depends_on("automake", type="build", when="@2.5.0") - depends_on("libtool", type="build", when="@2.5.0") - depends_on("m4", type="build", when="@2.5.0") conflicts("%gcc@:4.6", when="@3.6.0:") # Requires c++11 conflicts("%gcc@:4.6", when="@3.2.0:3.3.0") # Breaks @@ -97,12 +88,6 @@ class Protobuf(Package): # See https://github.com/protocolbuffers/protobuf/pull/7197 patch("intel-v2.patch", when="@3.7:3.11.4 %intel") - patch( - "protoc2.5.0_aarch64.patch", - sha256="7b44fcdb794f421174d619f83584e00a36012a16da09079e2fad9c12f7337451", - when="@2.5.0 target=aarch64:", - ) - # See https://github.com/protocolbuffers/protobuf/issues/9916 patch( "https://github.com/protocolbuffers/protobuf/pull/9936.patch?full_index=1", @@ -133,28 +118,9 @@ def cmake_args(self): args.extend(["-DCMAKE_MACOSX_RPATH=ON"]) return args - @when("@3.0.2:") - def install(self, spec, prefix): - args = self.cmake_args() - args.extend(std_cmake_args) - - source_directory = join_path(self.stage.source_path, "cmake") - build_directory = join_path(source_directory, "build") - - with working_dir(build_directory, create=True): - cmake(source_directory, *args) - make() - make("install") - - def configure_args(self): - args = [] - args.append("--prefix=%s" % self.prefix) - return args - - @when("@2.5.0") - def install(self, spec, prefix): - args = self.configure_args() - autoreconf("-ifv") - configure(*args) - make() - make("install") + @property + def root_cmakelists_dir(self): + if self.spec.satisfies("@:3.20"): + return join_path(self.stage.source_path, "cmake") + else: + return self.stage.source_path diff --git a/var/spack/repos/builtin/packages/protobuf/protoc2.5.0_aarch64.patch b/var/spack/repos/builtin/packages/protobuf/protoc2.5.0_aarch64.patch deleted file mode 100644 index aa1ebc6a9ab..00000000000 --- a/var/spack/repos/builtin/packages/protobuf/protoc2.5.0_aarch64.patch +++ /dev/null @@ -1,113 +0,0 @@ -diff -uprN /src/google/protobuf/stubs/atomicops_internals_arm_gcc.h /src/google/protobuf/stubs/atomicops_internals_arm_gcc.h ---- /src/google/protobuf/subs/atomicops_internals_arm_gcc.h 2018-08-03 08:50:58.579413324 +0000 -+++ /src/google/protobuf/stubs/atomicops_internals_arm_gcc.h 2018-08-03 08:50:58.711413322 +0000 -@@ -68,6 +68,30 @@ inline Atomic32 NoBarrier_CompareAndSwap - } while (prev_value == old_value); - return prev_value; - } -+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr, -+ Atomic64 old_value, -+ Atomic64 new_value) { -+ Atomic64 prev; -+ int32_t temp; -+ -+ __asm__ __volatile__ ( // NOLINT -+ "0: \n\t" -+ "ldxr %[prev], %[ptr] \n\t" -+ "cmp %[prev], %[old_value] \n\t" -+ "bne 1f \n\t" -+ "stxr %w[temp], %[new_value], %[ptr] \n\t" -+ "cbnz %w[temp], 0b \n\t" -+ "1: \n\t" -+ : [prev]"=&r" (prev), -+ [temp]"=&r" (temp), -+ [ptr]"+Q" (*ptr) -+ : [old_value]"IJr" (old_value), -+ [new_value]"r" (new_value) -+ : "cc", "memory" -+ ); // NOLINT -+ -+ return prev; -+} - - inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, - Atomic32 new_value) { -@@ -105,6 +129,15 @@ inline Atomic32 Acquire_CompareAndSwap(v - return NoBarrier_CompareAndSwap(ptr, old_value, new_value); - } - -+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr, -+ Atomic64 old_value, -+ Atomic64 new_value) { -+ Atomic64 prev = NoBarrier_CompareAndSwap(ptr, old_value, new_value); -+ MemoryBarrier(); -+ -+ return prev; -+} -+ - inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, - Atomic32 old_value, - Atomic32 new_value) { -@@ -115,8 +148,11 @@ inline void NoBarrier_Store(volatile Ato - *ptr = value; - } - --inline void MemoryBarrier() { -+/*inline void MemoryBarrier() { - pLinuxKernelMemoryBarrier(); -+}*/ -+inline void MemoryBarrier() { -+ __asm__ __volatile__ ("dmb ish" ::: "memory"); // NOLINT - } - - inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) { -@@ -129,6 +165,15 @@ inline void Release_Store(volatile Atomi - *ptr = value; - } - -+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) { -+ __asm__ __volatile__ ( // NOLINT -+ "stlr %x[value], %[ptr] \n\t" -+ : [ptr]"=Q" (*ptr) -+ : [value]"r" (value) -+ : "memory" -+ ); // NOLINT -+} -+ - inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) { - return *ptr; - } -@@ -139,6 +184,19 @@ inline Atomic32 Acquire_Load(volatile co - return value; - } - -+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) { -+ Atomic64 value; -+ -+ __asm__ __volatile__ ( // NOLINT -+ "ldar %x[value], %[ptr] \n\t" -+ : [value]"=r" (value) -+ : [ptr]"Q" (*ptr) -+ : "memory" -+ ); // NOLINT -+ -+ return value; -+} -+ - inline Atomic32 Release_Load(volatile const Atomic32* ptr) { - MemoryBarrier(); - return *ptr; -diff -uprN /src/google/protobuf/stubs/platform_macros.h /src/google/protobuf/stubs/platform_macros.h ---- /src/google/protobuf/stubs/platform_macros.h 2018-08-03 08:50:58.543413325 +0000 -+++ /src/google/protobuf/stubs/platform_macros.h 2018-08-03 08:50:58.595413324 +0000 -@@ -57,6 +57,9 @@ - #elif defined(__ppc__) - #define GOOGLE_PROTOBUF_ARCH_PPC 1 - #define GOOGLE_PROTOBUF_ARCH_32_BIT 1 -+#elif defined(__aarch64__) -+#define GOOGLE_PROTOBUF_ARCH_ARM 1 -+#define GOOGLE_PROTOBUF_ARCH_64_BIT 1 - #else - #error Host architecture was not detected as supported by protobuf - #endif - diff --git a/var/spack/repos/builtin/packages/py-protobuf/package.py b/var/spack/repos/builtin/packages/py-protobuf/package.py index 28b99194be2..ea263f13fc6 100644 --- a/var/spack/repos/builtin/packages/py-protobuf/package.py +++ b/var/spack/repos/builtin/packages/py-protobuf/package.py @@ -19,6 +19,7 @@ class PyProtobuf(PythonPackage): variant("cpp", default=False, description="Enable the cpp implementation") + version("4.21.7", sha256="71d9dba03ed3432c878a801e2ea51e034b0ea01cf3a4344fb60166cb5f6c8757") version("4.21.5", sha256="eb1106e87e095628e96884a877a51cdb90087106ee693925ec0a300468a9be3a") version( "3.20.1", @@ -63,12 +64,16 @@ class PyProtobuf(PythonPackage): deprecated=True, ) version("3.0.0", sha256="ecc40bc30f1183b418fe0ec0c90bc3b53fa1707c4205ee278c6b90479e5b6ff5") - version("3.0.0b2", sha256="d5b560bbc4b7d97cc2455c05cad9299d9db02d7bd11193b05684e3a86303c229") - version("3.0.0a3", sha256="b61622de5048415bfd3f2d812ad64606438ac9e25009ae84191405fe58e522c1") - version("2.6.1", sha256="8faca1fb462ee1be58d00f5efb4ca4f64bde92187fe61fde32615bbee7b3e745") - version("2.5.0", sha256="58292c459598c9297258bf57acc055f701c727f0154a86af8c0947dde37d8172") - version("2.4.1", sha256="df30b98acb6ef892da8b4776175510cff2131908fd0526b6bad960c55a830a1b") - version("2.3.0", sha256="374bb047874a506507912c3717d0ce62affbaa9a22bcb494d63d60326a0867b5") + version( + "3.0.0b2", + sha256="d5b560bbc4b7d97cc2455c05cad9299d9db02d7bd11193b05684e3a86303c229", + deprecated=True, + ) + version( + "3.0.0a3", + sha256="b61622de5048415bfd3f2d812ad64606438ac9e25009ae84191405fe58e522c1", + deprecated=True, + ) depends_on("python@3.5:", when="@3.18:", type=("build", "run")) depends_on("python@3.7:", when="@3.20:", type=("build", "run")) @@ -84,12 +89,6 @@ class PyProtobuf(PythonPackage): # Handle the 3.x series releases for ver in list(range(1, 8)) + list(range(9, 21)): depends_on("protobuf@3." + str(ver), when="+cpp @3." + str(ver)) - # Handle the 2.x series releases - for ver in list(range(3, 7)): - if ver == 5: - depends_on("protobuf@2." + str(ver), when="+cpp @2." + str(ver)) - else: - conflicts("+cpp", when="@2." + str(ver)) @property def build_directory(self): diff --git a/var/spack/repos/builtin/packages/py-tensorflow/package.py b/var/spack/repos/builtin/packages/py-tensorflow/package.py index 5c2bcb759a9..8247cd1ceba 100644 --- a/var/spack/repos/builtin/packages/py-tensorflow/package.py +++ b/var/spack/repos/builtin/packages/py-tensorflow/package.py @@ -115,14 +115,46 @@ class PyTensorflow(Package, CudaPackage, ROCmPackage): version("1.1.0", sha256="aad4470f52fa59f54de7b9a2da727429e6755d91d756f245f952698c42a60027") version("1.0.1", sha256="deea3c65e0703da96d9c3f1162e464c51d37659dd129396af134e9e8f1ea8c05") version("1.0.0", sha256="db8b3b8f4134b7c9c1b4165492ad5d5bb78889fcd99ffdffc325e97da3e8c677") - version("0.12.0", sha256="13a1d4e98c82eae7e26fe75384de1517d6126f63ba5d302392ec02ac3ae4b1b9") - version("0.11.0", sha256="24242ff696234bb1e58d09d45169b148525ccb706f980a4a92ddd3b82c7546dc") - version("0.10.0", sha256="f32df04e8f7186aaf6723fc5396733b2f6c2fd6fe4a53a54a68b80f3ec855680") - version("0.9.0", sha256="3128c396af19518c642d3e590212291e1d93c5b047472a10cf3245b53adac9c9") - version("0.8.0", sha256="f201ba7fb7609a6416968d4e1920d87d67be693b5bc7d34b6b4a79860a9a8a4e") - version("0.7.1", sha256="ef34121432f7a522cf9f99a56cdd86e370cc5fa3ee31255ca7cb17f36b8dfc0d") - version("0.7.0", sha256="43dd3051f947aa66e6fc09dac2f86a2efe2e019736bbd091c138544b86d717ce") - version("0.6.0", sha256="f86ace45e99053b09749cd55ab79c57274d8c7460ae763c5e808d81ffbc3b657") + version( + "0.12.0", + sha256="13a1d4e98c82eae7e26fe75384de1517d6126f63ba5d302392ec02ac3ae4b1b9", + deprecated=True, + ) + version( + "0.11.0", + sha256="24242ff696234bb1e58d09d45169b148525ccb706f980a4a92ddd3b82c7546dc", + deprecated=True, + ) + version( + "0.10.0", + sha256="f32df04e8f7186aaf6723fc5396733b2f6c2fd6fe4a53a54a68b80f3ec855680", + deprecated=True, + ) + version( + "0.9.0", + sha256="3128c396af19518c642d3e590212291e1d93c5b047472a10cf3245b53adac9c9", + deprecated=True, + ) + version( + "0.8.0", + sha256="f201ba7fb7609a6416968d4e1920d87d67be693b5bc7d34b6b4a79860a9a8a4e", + deprecated=True, + ) + version( + "0.7.1", + sha256="ef34121432f7a522cf9f99a56cdd86e370cc5fa3ee31255ca7cb17f36b8dfc0d", + deprecated=True, + ) + version( + "0.7.0", + sha256="43dd3051f947aa66e6fc09dac2f86a2efe2e019736bbd091c138544b86d717ce", + deprecated=True, + ) + version( + "0.6.0", + sha256="f86ace45e99053b09749cd55ab79c57274d8c7460ae763c5e808d81ffbc3b657", + deprecated=True, + ) variant("mkl", default=False, description="Build with MKL support") variant("jemalloc", default=False, description="Build with jemalloc as malloc support") From 49114ffff7ba365576137277a5a886350be7ba7e Mon Sep 17 00:00:00 2001 From: Veselin Dobrev Date: Tue, 8 Nov 2022 22:56:58 -0800 Subject: [PATCH 433/442] MFEM: more updates for v4.5 (#33603) * [mfem] updates related to building with cuda * [hypre] tweak to support building with external ROCm/HIP * [mfem] more tweaks related to building with +rocm * [mfem] temporary (?) workaround for issue #33684 * [mfem] fix style * [mfem] fix +shared+miniapps install --- .../repos/builtin/packages/hypre/package.py | 3 +- .../repos/builtin/packages/mfem/package.py | 68 +++++++++++--- .../builtin/packages/mfem/test_builds.sh | 90 ++++++++++++------- 3 files changed, 113 insertions(+), 48 deletions(-) diff --git a/var/spack/repos/builtin/packages/hypre/package.py b/var/spack/repos/builtin/packages/hypre/package.py index 03a6fc70d88..fd168400cc2 100644 --- a/var/spack/repos/builtin/packages/hypre/package.py +++ b/var/spack/repos/builtin/packages/hypre/package.py @@ -242,7 +242,8 @@ def configure_args(self): rocm_pkgs = ["rocsparse", "rocthrust", "rocprim", "rocrand"] rocm_inc = "" for pkg in rocm_pkgs: - rocm_inc += spec[pkg].headers.include_flags + " " + if "^" + pkg in spec: + rocm_inc += spec[pkg].headers.include_flags + " " configure_args.extend( [ "--with-hip", diff --git a/var/spack/repos/builtin/packages/mfem/package.py b/var/spack/repos/builtin/packages/mfem/package.py index d188c2fc881..984e715394a 100644 --- a/var/spack/repos/builtin/packages/mfem/package.py +++ b/var/spack/repos/builtin/packages/mfem/package.py @@ -440,6 +440,12 @@ class Mfem(Package, CudaPackage, ROCmPackage): def setup_build_environment(self, env): env.unset("MFEM_DIR") env.unset("MFEM_BUILD_DIR") + # Workaround for changes made by the 'kokkos-nvcc-wrapper' package + # which can be a dependency e.g. through PETSc that uses Kokkos: + if "^kokkos-nvcc-wrapper" in self.spec: + env.set("MPICH_CXX", spack_cxx) + env.set("OMPI_CXX", spack_cxx) + env.set("MPICXX_CXX", spack_cxx) # # Note: Although MFEM does support CMake configuration, MFEM @@ -866,15 +872,33 @@ def find_optional_library(name, prefix): if "+rocm" in spec: amdgpu_target = ",".join(spec.variants["amdgpu_target"].value) options += ["HIP_CXX=%s" % spec["hip"].hipcc, "HIP_ARCH=%s" % amdgpu_target] + hip_libs = LibraryList([]) + # To use a C++ compiler that supports -xhip flag one can use + # something like this: + # options += [ + # "HIP_CXX=%s" % (spec["mpi"].mpicxx if "+mpi" in spec else spack_cxx), + # "HIP_FLAGS=-xhip --offload-arch=%s" % amdgpu_target, + # ] + # hip_libs += find_libraries("libamdhip64", spec["hip"].prefix.lib) if "^hipsparse" in spec: # hipsparse is needed @4.4.0:+rocm - # Note: MFEM's defaults.mk want to find librocsparse.* in - # $(HIP_DIR)/lib, so we set HIP_DIR to be the prefix of - # rocsparse (which is a dependency of hipsparse). - options += [ - "HIP_DIR=%s" % spec["rocsparse"].prefix, - "HIP_OPT=%s" % spec["hipsparse"].headers.cpp_flags, - "HIP_LIB=%s" % ld_flags_from_library_list(spec["hipsparse"].libs), - ] + hipsparse = spec["hipsparse"] + options += ["HIP_OPT=%s" % hipsparse.headers.cpp_flags] + hip_libs += hipsparse.libs + # Note: MFEM's defaults.mk wants to find librocsparse.* in + # $(HIP_DIR)/lib, so we set HIP_DIR to be $ROCM_PATH when using + # external HIP, or the prefix of rocsparse (which is a + # dependency of hipsparse) when using Spack-built HIP. + if spec["hip"].external: + options += ["HIP_DIR=%s" % env["ROCM_PATH"]] + else: + options += ["HIP_DIR=%s" % hipsparse["rocsparse"].prefix] + if "%cce" in spec: + # We assume the proper Cray CCE module (cce) is loaded: + craylibs_path = env["CRAYLIBS_" + env["MACHTYPE"].capitalize()] + craylibs = ["libmodules", "libfi", "libcraymath", "libf", "libu", "libcsup"] + hip_libs += find_libraries(craylibs, craylibs_path) + if hip_libs: + options += ["HIP_LIB=%s" % ld_flags_from_library_list(hip_libs)] if "+occa" in spec: options += [ @@ -883,12 +907,18 @@ def find_optional_library(name, prefix): ] if "+raja" in spec: - raja_opt = "-I%s" % spec["raja"].prefix.include - if spec["raja"].satisfies("^camp"): - raja_opt += " -I%s" % spec["camp"].prefix.include + raja = spec["raja"] + raja_opt = "-I%s" % raja.prefix.include + raja_lib = find_libraries( + "libRAJA", raja.prefix, shared=("+shared" in raja), recursive=True + ) + if raja.satisfies("^camp"): + camp = raja["camp"] + raja_opt += " -I%s" % camp.prefix.include + raja_lib += find_optional_library("libcamp", camp.prefix) options += [ "RAJA_OPT=%s" % raja_opt, - "RAJA_LIB=%s" % ld_flags_from_dirs([spec["raja"].prefix.lib], ["RAJA"]), + "RAJA_LIB=%s" % ld_flags_from_library_list(raja_lib), ] if "+amgx" in spec: @@ -975,10 +1005,13 @@ def find_optional_library(name, prefix): if "+hiop" in spec: hiop = spec["hiop"] - lapack_blas = spec["lapack"].libs + spec["blas"].libs + hiop_libs = hiop.libs + hiop_libs += spec["lapack"].libs + spec["blas"].libs + if "^magma" in hiop: + hiop_libs += hiop["magma"].libs options += [ "HIOP_OPT=-I%s" % hiop.prefix.include, - "HIOP_LIB=%s" % ld_flags_from_library_list(hiop.libs + lapack_blas), + "HIOP_LIB=%s" % ld_flags_from_library_list(hiop_libs), ] make("config", *options, parallel=False) @@ -996,6 +1029,9 @@ def check_or_test(self): make("-C", "examples", "ex1p" if ("+mpi" in self.spec) else "ex1", parallel=False) # make('check', parallel=False) else: + # As of v4.5.0 and ROCm up to 5.2.3, the following miniapp crashes + # the HIP compiler, so it has to be disabled for testing with HIP: + # filter_file("PAR_MINIAPPS = hooke", "PAR_MINIAPPS =", "miniapps/hooke/makefile") make("all") make("test", parallel=False) @@ -1013,7 +1049,11 @@ def install(self, spec, prefix): with working_dir("config"): os.rename("config.mk", "config.mk.orig") copy(str(self.config_mk), "config.mk") + # Add '/mfem' to MFEM_INC_DIR for miniapps that include directly + # headers like "general/forall.hpp": + filter_file("(MFEM_INC_DIR.*)$", "\\1/mfem", "config.mk") shutil.copystat("config.mk.orig", "config.mk") + # TODO: miniapps linking to libmfem-common.* will not work. prefix_share = join_path(prefix, "share", "mfem") diff --git a/var/spack/repos/builtin/packages/mfem/test_builds.sh b/var/spack/repos/builtin/packages/mfem/test_builds.sh index 5c43f875126..ba2c6ceef3a 100755 --- a/var/spack/repos/builtin/packages/mfem/test_builds.sh +++ b/var/spack/repos/builtin/packages/mfem/test_builds.sh @@ -19,9 +19,12 @@ hdf5_spec='^hdf5@1.8.19:1.8' # petsc spec petsc_spec='^petsc+suite-sparse+mumps' petsc_spec_cuda='^petsc+cuda+suite-sparse+mumps' -# strumpack spec without cuda (use @master until version > 6.3.1 is released) -strumpack_spec='^strumpack@master~slate~openmp~cuda' -strumpack_cuda_spec='^strumpack@master~slate~openmp' +# superlu-dist specs +superlu_spec_cuda='^superlu-dist+cuda cuda_arch='"${cuda_arch}" +superlu_spec_rocm='^superlu-dist+rocm amdgpu_target='"${rocm_arch}" +# strumpack spec without cuda (use version > 6.3.1) +strumpack_spec='^strumpack~slate~openmp~cuda' +strumpack_cuda_spec='^strumpack~slate~openmp' strumpack_rocm_spec='^strumpack+rocm~slate~openmp~cuda' builds=( @@ -116,27 +119,28 @@ builds_cuda=( ^raja+cuda~openmp ^hypre+cuda' # hypre without cuda: + # NOTE: PETSc tests may need PETSC_OPTIONS="-use_gpu_aware_mpi 0" # TODO: restore '+libceed' when the libCEED CUDA unit tests take less time. - # TODO: add back '+gslib' when the gslib test is fixed. - # TODO: restore '+superlu-dist' when the unit test is fixed. - # TODO: add back "+petsc+slepc $petsc_spec_cuda" when it works. + # TODO: remove "^hiop+shared" when the default static build is fixed. ${mfem}'+cuda+openmp+raja+occa cuda_arch='"${cuda_arch}"' \ - +strumpack+suite-sparse \ + +superlu-dist+strumpack+suite-sparse+gslib+petsc+slepc \ +sundials+pumi+mpfr+netcdf+zlib+gnutls+libunwind+conduit+ginkgo+hiop \ - ^raja+cuda+openmp'" $strumpack_cuda_spec"' \ - '"$hdf5_spec" + ^raja+cuda+openmp ^hiop+shared'" $strumpack_cuda_spec"' \ + '"$superlu_spec_cuda $petsc_spec_cuda $hdf5_spec" # hypre with cuda: # TODO: restore '+libceed' when the libCEED CUDA unit tests take less time. - # TODO: add back '+gslib' when the gslib test is fixed. - # TODO: restore '+superlu-dist' when we support it with '^hypre+cuda'. + # TODO: restore '+superlu-dist $superlu_spec_cuda' when we support it with + # '^hypre+cuda'. # TODO: add back "+strumpack $strumpack_cuda_spec" when it's supported. # TODO: add back "+petsc+slepc $petsc_spec_cuda" when it works. + # NOTE: PETSc tests may need PETSC_OPTIONS="-use_gpu_aware_mpi 0" # TODO: add back "+sundials" when it's supported with '^hypre+cuda'. + # TODO: remove "^hiop+shared" when the default static build is fixed. ${mfem}'+cuda+openmp+raja+occa cuda_arch='"${cuda_arch}"' \ - +suite-sparse \ + +suite-sparse+gslib \ +pumi+mpfr+netcdf+zlib+gnutls+libunwind+conduit+ginkgo+hiop \ - ^raja+cuda+openmp ^hypre+cuda \ + ^raja+cuda+openmp ^hiop+shared ^hypre+cuda \ '"$hdf5_spec" # @@ -155,32 +159,38 @@ builds_cuda=( ^raja+cuda~openmp ^hypre+cuda' # hypre without cuda: + # NOTE: PETSc tests may need PETSC_OPTIONS="-use_gpu_aware_mpi 0" # TODO: restore '+libceed' when the libCEED CUDA unit tests take less time. - # TODO: add back '+gslib' when the gslib test is fixed. - # TODO: restore '+superlu-dist' when the unit test is fixed. - # TODO: add back "+petsc+slepc $petsc_spec_cuda" when it works. + # TODO: remove "^hiop+shared" when the default static build is fixed. ${mfem_dev}'+cuda+openmp+raja+occa cuda_arch='"${cuda_arch}"' \ - +strumpack+suite-sparse \ + +superlu-dist+strumpack+suite-sparse+gslib+petsc+slepc \ +sundials+pumi+mpfr+netcdf+zlib+gnutls+libunwind+conduit+ginkgo+hiop \ - ^raja+cuda+openmp'" $strumpack_cuda_spec"' \ - '"$hdf5_spec" + ^raja+cuda+openmp ^hiop+shared'" $strumpack_cuda_spec"' \ + '"$superlu_spec_cuda $petsc_spec_cuda $hdf5_spec" # hypre with cuda: # TODO: restore '+libceed' when the libCEED CUDA unit tests take less time. - # TODO: add back '+gslib' when the gslib test is fixed. - # TODO: restore '+superlu-dist' when we support it with '^hypre+cuda'. + # TODO: restore '+superlu-dist $superlu_spec_cuda' when we support it with + # '^hypre+cuda'. # TODO: add back "+strumpack $strumpack_cuda_spec" when it's supported. # TODO: add back "+petsc+slepc $petsc_spec_cuda" when it works. + # NOTE: PETSc tests may need PETSC_OPTIONS="-use_gpu_aware_mpi 0" # TODO: add back "+sundials" when it's supported with '^hypre+cuda'. + # TODO: remove "^hiop+shared" when the default static build is fixed. ${mfem_dev}'+cuda+openmp+raja+occa cuda_arch='"${cuda_arch}"' \ - +suite-sparse \ + +suite-sparse+gslib \ +pumi+mpfr+netcdf+zlib+gnutls+libunwind+conduit+ginkgo+hiop \ - ^raja+cuda+openmp ^hypre+cuda \ + ^raja+cuda+openmp ^hiop+shared ^hypre+cuda \ '"$hdf5_spec" ) builds_rocm=( + # NOTE: the miniapp 'hooke' crashes the HIP compiler, so it needs to be + # disabled in Spack, e.g. with + # filter_file("PAR_MINIAPPS = hooke", "PAR_MINIAPPS =", + # "miniapps/hooke/makefile") + # hypre without rocm: ${mfem}'+rocm amdgpu_target='"${rocm_arch}" @@ -192,24 +202,30 @@ builds_rocm=( ^raja+rocm~openmp ^occa~cuda ^hypre+rocm' # hypre without rocm: - # TODO: add back '+gslib' when the gslib test is fixed. - # TODO: restore '+superlu-dist' when the unit test is fixed. # TODO: add "+petsc+slepc $petsc_spec_rocm" when it is supported. + # TODO: add back '+conduit' when it is no longer linked with tcmalloc*. + # TODO: add back '+hiop' when it is no longer linked with tcmalloc* through + # its magma dependency. + # TODO: add back '+ginkgo' when the Ginkgo example works. ${mfem}'+rocm+openmp+raja+occa+libceed amdgpu_target='"${rocm_arch}"' \ - +strumpack+suite-sparse \ - +sundials+pumi+mpfr+netcdf+zlib+gnutls+libunwind+conduit+ginkgo+hiop \ + +superlu-dist+strumpack+suite-sparse+gslib \ + +sundials+pumi+mpfr+netcdf+zlib+gnutls+libunwind \ ^raja+rocm~openmp ^occa~cuda'" $strumpack_rocm_spec"' \ - '"$hdf5_spec" + '"$superlu_spec_rocm $hdf5_spec" # hypre with rocm: - # TODO: add back '+gslib' when the gslib test is fixed. - # TODO: restore '+superlu-dist' when we support it with '^hypre+rocm'. + # TODO: restore '+superlu-dist $superlu_spec_rocm' when we support it with + # '^hypre+rocm'. # TODO: add back "+strumpack $strumpack_rocm_spec" when it's supported. # TODO: add back "+petsc+slepc $petsc_spec_rocm" when it works. + # TODO: add back '+conduit' when it is no longer linked with tcmalloc*. + # TODO: add back '+hiop' when it is no longer linked with tcmalloc* through + # its magma dependency. + # TODO: add back '+ginkgo' when the Ginkgo example works. # TODO: add back "+sundials" when it's supported with '^hypre+rocm'. ${mfem}'+rocm+openmp+raja+occa+libceed amdgpu_target='"${rocm_arch}"' \ - +suite-sparse \ - +pumi+mpfr+netcdf+zlib+gnutls+libunwind+conduit+ginkgo+hiop \ + +suite-sparse+gslib \ + +pumi+mpfr+netcdf+zlib+gnutls+libunwind \ ^raja+rocm~openmp ^occa~cuda ^hypre+rocm \ '"$hdf5_spec" @@ -230,14 +246,22 @@ run_builds=("${builds[@]}" "${builds2[@]}") # run_builds=("${builds_cuda[@]}") # run_builds=("${builds_rocm[@]}") +# PETSc CUDA tests on Lassen need this: +# export PETSC_OPTIONS="-use_gpu_aware_mpi 0" + for bld in "${run_builds[@]}"; do + eval bbb="\"${bld}\"" + printf "\n%s\n" "${SEP}" printf " %s\n" "${bld}" printf "%s\n" "${SEP}" - eval bbb="\"${bld}\"" spack spec --fresh -I $bbb || exit 1 printf "%s\n" "${sep}" spack install $spack_jobs --fresh --test=root $bbb || exit 2 + + # echo ./bin/spack spec --fresh -I $bbb + # echo ./bin/spack install $spack_jobs --fresh --test=root $bbb + # echo done # Uninstall all mfem builds: From ec89c47aeee8b58bff7375158870ee13bfae9c64 Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Wed, 9 Nov 2022 08:05:03 +0100 Subject: [PATCH 434/442] Account for patchelf binaries when creating local bootstrap mirror (#33776) This was overlooked when we added binary patchelf buildcaches --- lib/spack/spack/cmd/bootstrap.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/spack/spack/cmd/bootstrap.py b/lib/spack/spack/cmd/bootstrap.py index 9c07c826f73..6a45e22f8e4 100644 --- a/lib/spack/spack/cmd/bootstrap.py +++ b/lib/spack/spack/cmd/bootstrap.py @@ -52,6 +52,7 @@ CLINGO_JSON = "$spack/share/spack/bootstrap/github-actions-v0.4/clingo.json" GNUPG_JSON = "$spack/share/spack/bootstrap/github-actions-v0.4/gnupg.json" +PATCHELF_JSON = "$spack/share/spack/bootstrap/github-actions-v0.4/patchelf.json" # Metadata for a generated source mirror SOURCE_METADATA = { @@ -443,6 +444,7 @@ def write_metadata(subdir, metadata): abs_directory, rel_directory = write_metadata(subdir="binaries", metadata=BINARY_METADATA) shutil.copy(spack.util.path.canonicalize_path(CLINGO_JSON), abs_directory) shutil.copy(spack.util.path.canonicalize_path(GNUPG_JSON), abs_directory) + shutil.copy(spack.util.path.canonicalize_path(PATCHELF_JSON), abs_directory) instructions += cmd.format("local-binaries", rel_directory) print(instructions) From 284c3a3fd8a4213a2cc6bf4aef85d672369f4b5b Mon Sep 17 00:00:00 2001 From: Greg Becker Date: Wed, 9 Nov 2022 00:25:30 -0800 Subject: [PATCH 435/442] ensure external PythonPackages have python deps (#33777) Currently, external `PythonPackage`s cause install failures because the logic in `PythonPackage` assumes that it can ask for `spec["python"]`. Because we chop off externals' dependencies, an external Python extension may not have a `python` dependency. This PR resolves the issue by guaranteeing that a `python` node is present in one of two ways: 1. If there is already a `python` node in the DAG, we wire the external up to it. 2. If there is no existing `python` node, we wire up a synthetic external `python` node, and we assume that it has the same prefix as the external. The assumption in (2) isn't always valid, but it's better than leaving the user with a non-working `PythonPackage`. The logic here is specific to `python`, but other types of extensions could take advantage of it. Packages need only define `update_external_dependencies(self)`, and this method will be called on externals after concretization. This likely needs to be fleshed out in the future so that any added nodes are included in concretization, but for now we only bolt on dependencies post-concretization. Co-authored-by: Todd Gamblin --- lib/spack/spack/build_systems/python.py | 22 ++++++++++++++++++++++ lib/spack/spack/package_base.py | 6 ++++++ lib/spack/spack/solver/asp.py | 6 ++++++ lib/spack/spack/spec.py | 5 +++++ lib/spack/spack/test/concretize.py | 15 +++++++++++++++ 5 files changed, 54 insertions(+) diff --git a/lib/spack/spack/build_systems/python.py b/lib/spack/spack/build_systems/python.py index 0f84ac7f8ad..afa36980f76 100644 --- a/lib/spack/spack/build_systems/python.py +++ b/lib/spack/spack/build_systems/python.py @@ -15,6 +15,7 @@ import spack.builder import spack.multimethod import spack.package_base +import spack.spec from spack.directives import build_system, depends_on, extends from spack.error import NoHeadersError, NoLibrariesError, SpecError from spack.version import Version @@ -218,6 +219,27 @@ def list_url(cls): name = cls.pypi.split("/")[0] return "https://pypi.org/simple/" + name + "/" + def update_external_dependencies(self): + """ + Ensure all external python packages have a python dependency + + If another package in the DAG depends on python, we use that + python for the dependency of the external. If not, we assume + that the external PythonPackage is installed into the same + directory as the python it depends on. + """ + # TODO: Include this in the solve, rather than instantiating post-concretization + if "python" not in self.spec: + if "python" in self.spec.root: + python = self.spec.root["python"] + else: + python = spack.spec.Spec("python") + repo = spack.repo.path.repo_for_pkg(python) + python.namespace = repo.namespace + python._mark_concrete() + python.external_path = self.prefix + self.spec.add_dependency_edge(python, ("build", "link", "run")) + @property def headers(self): """Discover header files in platlib.""" diff --git a/lib/spack/spack/package_base.py b/lib/spack/spack/package_base.py index e0e250cf7c8..48b036e8cfa 100644 --- a/lib/spack/spack/package_base.py +++ b/lib/spack/spack/package_base.py @@ -919,6 +919,12 @@ def url_for_version(self, version): """ return self._implement_all_urls_for_version(version)[0] + def update_external_dependencies(self): + """ + Method to override in package classes to handle external dependencies + """ + pass + def all_urls_for_version(self, version): """Return all URLs derived from version_urls(), url, urls, and list_url (if it contains a version) in a package in that order. diff --git a/lib/spack/spack/solver/asp.py b/lib/spack/spack/solver/asp.py index 68c571e5bb3..5f387636cc0 100644 --- a/lib/spack/spack/solver/asp.py +++ b/lib/spack/spack/solver/asp.py @@ -2320,6 +2320,12 @@ def build_specs(self, function_tuples): if isinstance(spec.version, spack.version.GitVersion): spec.version.generate_git_lookup(spec.fullname) + # Add synthetic edges for externals that are extensions + for root in self._specs.values(): + for dep in root.traverse(): + if dep.external: + dep.package.update_external_dependencies() + return self._specs diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py index ef4c3b7ab08..96b137622a2 100644 --- a/lib/spack/spack/spec.py +++ b/lib/spack/spack/spec.py @@ -2751,6 +2751,11 @@ def _old_concretize(self, tests=False, deprecation_warning=True): # If any spec in the DAG is deprecated, throw an error Spec.ensure_no_deprecated(self) + # Update externals as needed + for dep in self.traverse(): + if dep.external: + dep.package.update_external_dependencies() + # Now that the spec is concrete we should check if # there are declared conflicts # diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py index ab3337da5e0..f2d7edf126e 100644 --- a/lib/spack/spack/test/concretize.py +++ b/lib/spack/spack/test/concretize.py @@ -1945,3 +1945,18 @@ def test_require_targets_are_allowed(self, mutable_database): for s in spec.traverse(): assert s.satisfies("target=%s" % spack.platforms.test.Test.front_end) + + def test_external_python_extensions_have_dependency(self): + """Test that python extensions have access to a python dependency""" + external_conf = { + "py-extension1": { + "buildable": False, + "externals": [{"spec": "py-extension1@2.0", "prefix": "/fake"}], + } + } + spack.config.set("packages", external_conf) + + spec = Spec("py-extension2").concretized() + + assert "python" in spec["py-extension1"] + assert spec["python"] == spec["py-extension1"]["python"] From d1d668a9d57e984a225eeef153d93cb315e03dfb Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Wed, 9 Nov 2022 10:31:27 +0100 Subject: [PATCH 436/442] Revert "fix racy sbang (#33549)" (#33778) This reverts commit 4d28a6466188ea9fe3b55a4c3d7690dd66e0dc8f. --- lib/spack/llnl/util/filesystem.py | 45 +++++--------------------- lib/spack/spack/config.py | 6 ++-- lib/spack/spack/hooks/sbang.py | 53 +++++++++++++++++-------------- 3 files changed, 41 insertions(+), 63 deletions(-) diff --git a/lib/spack/llnl/util/filesystem.py b/lib/spack/llnl/util/filesystem.py index d122280e999..aece52f8436 100644 --- a/lib/spack/llnl/util/filesystem.py +++ b/lib/spack/llnl/util/filesystem.py @@ -1000,45 +1000,16 @@ def hash_directory(directory, ignore=[]): return md5_hash.hexdigest() -def _try_unlink(path): - try: - os.unlink(path) - except (IOError, OSError): - # But if that fails, that's OK. - pass - - @contextmanager @system_path_filter -def write_tmp_and_move(path, mode="w"): - """Write to a temporary file in the same directory, then move into place.""" - # Rely on NamedTemporaryFile to give a unique file without races - # in the directory of the target file. - file = tempfile.NamedTemporaryFile( - prefix="." + os.path.basename(path), - suffix=".tmp", - dir=os.path.dirname(path), - mode=mode, - delete=False, # we delete it ourselves - ) - tmp_path = file.name - - try: - yield file - except BaseException: - # On any failure, try to remove the temporary file. - _try_unlink(tmp_path) - raise - finally: - # Always close the file decriptor - file.close() - - # Atomically move into existence. - try: - os.rename(tmp_path, path) - except (IOError, OSError): - _try_unlink(tmp_path) - raise +def write_tmp_and_move(filename): + """Write to a temporary file, then move into place.""" + dirname = os.path.dirname(filename) + basename = os.path.basename(filename) + tmp = os.path.join(dirname, ".%s.tmp" % basename) + with open(tmp, "w") as f: + yield f + shutil.move(tmp, filename) @contextmanager diff --git a/lib/spack/spack/config.py b/lib/spack/spack/config.py index f35310986e3..e9a3b1d9568 100644 --- a/lib/spack/spack/config.py +++ b/lib/spack/spack/config.py @@ -45,7 +45,7 @@ import llnl.util.lang import llnl.util.tty as tty -from llnl.util.filesystem import mkdirp, write_tmp_and_move +from llnl.util.filesystem import mkdirp, rename import spack.compilers import spack.paths @@ -287,8 +287,10 @@ def _write_section(self, section): parent = os.path.dirname(self.path) mkdirp(parent) - with write_tmp_and_move(self.path) as f: + tmp = os.path.join(parent, ".%s.tmp" % os.path.basename(self.path)) + with open(tmp, "w") as f: syaml.dump_config(data_to_write, stream=f, default_flow_style=False) + rename(tmp, self.path) except (yaml.YAMLError, IOError) as e: raise ConfigFileError("Error writing to config file: '%s'" % str(e)) diff --git a/lib/spack/spack/hooks/sbang.py b/lib/spack/spack/hooks/sbang.py index e22c2929c2c..5d2de2b8655 100644 --- a/lib/spack/spack/hooks/sbang.py +++ b/lib/spack/spack/hooks/sbang.py @@ -186,39 +186,44 @@ def install_sbang(): ``sbang`` here ensures that users can access the script and that ``sbang`` itself is in a short path. """ + # copy in a new version of sbang if it differs from what's in spack sbang_path = sbang_install_path() + if os.path.exists(sbang_path) and filecmp.cmp(spack.paths.sbang_script, sbang_path): + return - all = spack.spec.Spec("all") - group_name = spack.package_prefs.get_package_group(all) - config_mode = spack.package_prefs.get_package_dir_permissions(all) - group_id = grp.getgrnam(group_name).gr_gid if group_name else None - - # First setup the bin dir correctly. + # make $install_tree/bin sbang_bin_dir = os.path.dirname(sbang_path) - if not os.path.isdir(sbang_bin_dir): - fs.mkdirp(sbang_bin_dir) + fs.mkdirp(sbang_bin_dir) - # Set group and ownership like we do on package directories - if group_id: - os.chown(sbang_bin_dir, os.stat(sbang_bin_dir).st_uid, group_id) - os.chmod(sbang_bin_dir, config_mode) + # get permissions for bin dir from configuration files + group_name = spack.package_prefs.get_package_group(spack.spec.Spec("all")) + config_mode = spack.package_prefs.get_package_dir_permissions(spack.spec.Spec("all")) + + if group_name: + os.chmod(sbang_bin_dir, config_mode) # Use package directory permissions else: fs.set_install_permissions(sbang_bin_dir) - # Then check if we need to install sbang itself. - try: - already_installed = filecmp.cmp(spack.paths.sbang_script, sbang_path) - except (IOError, OSError): - already_installed = False + # set group on sbang_bin_dir if not already set (only if set in configuration) + # TODO: after we drop python2 support, use shutil.chown to avoid gid lookups that + # can fail for remote groups + if group_name and os.stat(sbang_bin_dir).st_gid != grp.getgrnam(group_name).gr_gid: + os.chown(sbang_bin_dir, os.stat(sbang_bin_dir).st_uid, grp.getgrnam(group_name).gr_gid) - if not already_installed: - with fs.write_tmp_and_move(sbang_path) as f: - shutil.copy(spack.paths.sbang_script, f.name) + # copy over the fresh copy of `sbang` + sbang_tmp_path = os.path.join( + os.path.dirname(sbang_path), + ".%s.tmp" % os.path.basename(sbang_path), + ) + shutil.copy(spack.paths.sbang_script, sbang_tmp_path) - # Set permissions on `sbang` (including group if set in configuration) - os.chmod(sbang_path, config_mode) - if group_id: - os.chown(sbang_path, os.stat(sbang_path).st_uid, group_id) + # set permissions on `sbang` (including group if set in configuration) + os.chmod(sbang_tmp_path, config_mode) + if group_name: + os.chown(sbang_tmp_path, os.stat(sbang_tmp_path).st_uid, grp.getgrnam(group_name).gr_gid) + + # Finally, move the new `sbang` into place atomically + os.rename(sbang_tmp_path, sbang_path) def post_install(spec): From 9ca7165ef0537c168f63ab61663a04da4f74cb5b Mon Sep 17 00:00:00 2001 From: snehring <7978778+snehring@users.noreply.github.com> Date: Wed, 9 Nov 2022 08:25:22 -0600 Subject: [PATCH 437/442] postgresql: fix weird spack message (#33770) --- var/spack/repos/builtin/packages/postgresql/package.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/postgresql/package.py b/var/spack/repos/builtin/packages/postgresql/package.py index c162567fada..0fce4210b68 100644 --- a/var/spack/repos/builtin/packages/postgresql/package.py +++ b/var/spack/repos/builtin/packages/postgresql/package.py @@ -100,7 +100,7 @@ def install(self, spec, prefix): with working_dir(os.path.join("src", subdir)): make("install") else: - AutotoolsPackage.install(self, spec, prefix) + super(Postgresql, self).install(spec, prefix) def setup_run_environment(self, env): spec = self.spec From 078767946c1290b225a7b8e0d64241944dbfa1db Mon Sep 17 00:00:00 2001 From: kwryankrattiger <80296582+kwryankrattiger@users.noreply.github.com> Date: Wed, 9 Nov 2022 09:05:27 -0600 Subject: [PATCH 438/442] Boost: Change comment to conflict for MPI/Python (#33767) Boost 1.64.0 has build errors when building the python and MPI modules. This was previously just a comment in the package.py which allowed broken specs to concretize. The comments are now expressed in conflicts to prevent this. --- var/spack/repos/builtin/packages/boost/package.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/var/spack/repos/builtin/packages/boost/package.py b/var/spack/repos/builtin/packages/boost/package.py index a57b2e5bac5..3fd01f23845 100644 --- a/var/spack/repos/builtin/packages/boost/package.py +++ b/var/spack/repos/builtin/packages/boost/package.py @@ -44,10 +44,6 @@ class Boost(Package): version("1.66.0", sha256="5721818253e6a0989583192f96782c4a98eb6204965316df9f5ad75819225ca9") version("1.65.1", sha256="9807a5d16566c57fd74fb522764e0b134a8bbe6b6e8967b83afefd30dcd3be81") version("1.65.0", sha256="ea26712742e2fb079c2a566a31f3266973b76e38222b9f88b387e3c8b2f9902c") - # NOTE: 1.64.0 seems fine for *most* applications, but if you need - # +python and +mpi, there seem to be errors with out-of-date - # API calls from mpi/python. - # See: https://github.com/spack/spack/issues/3963 version("1.64.0", sha256="7bcc5caace97baa948931d712ea5f37038dbb1c5d89b43ad4def4ed7cb683332") version("1.63.0", sha256="beae2529f759f6b3bf3f4969a19c2e9d6f0c503edcb2de4a61d1428519fcb3b0") version("1.62.0", sha256="36c96b0f6155c98404091d8ceb48319a28279ca0333fba1ad8611eb90afb2ca0") @@ -245,6 +241,13 @@ def libs(self): conflicts("cxxstd=98", when="+fiber") # Fiber requires >=C++11. conflicts("~context", when="+fiber") # Fiber requires Context. + # NOTE: 1.64.0 seems fine for *most* applications, but if you need + # +python and +mpi, there seem to be errors with out-of-date + # API calls from mpi/python. + # See: https://github.com/spack/spack/issues/3963 + conflicts("@1.64.0", when="+python", msg="Errors with out-of-date API calls from Python") + conflicts("@1.64.0", when="+mpi", msg="Errors with out-of-date API calls from MPI") + conflicts("+taggedlayout", when="+versionedlayout") conflicts("+numpy", when="~python") From b10d75b1c6ad25f9705bb7151e711cbe16a6a35e Mon Sep 17 00:00:00 2001 From: James Willenbring Date: Wed, 9 Nov 2022 14:40:33 -0600 Subject: [PATCH 439/442] Update package.py (#33787) Proposing to add myself as a maintainer of the Trilinos Spack package after a related conversation with @kuberry. --- var/spack/repos/builtin/packages/trilinos/package.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/trilinos/package.py b/var/spack/repos/builtin/packages/trilinos/package.py index 80765939cc8..cf6f7307c84 100644 --- a/var/spack/repos/builtin/packages/trilinos/package.py +++ b/var/spack/repos/builtin/packages/trilinos/package.py @@ -33,7 +33,7 @@ class Trilinos(CMakePackage, CudaPackage, ROCmPackage): url = "https://github.com/trilinos/Trilinos/archive/refs/tags/trilinos-release-12-12-1.tar.gz" git = "https://github.com/trilinos/Trilinos.git" - maintainers = ["keitat", "sethrj", "kuberry"] + maintainers = ["keitat", "sethrj", "kuberry", "jwillenbring"] tags = ["e4s"] From 62db008e42cd76175a5d6a267fe760e85d3015ad Mon Sep 17 00:00:00 2001 From: snehring <7978778+snehring@users.noreply.github.com> Date: Wed, 9 Nov 2022 14:52:57 -0600 Subject: [PATCH 440/442] sentieon-genomics: adding version 202112.06 (#33786) --- var/spack/repos/builtin/packages/sentieon-genomics/package.py | 1 + 1 file changed, 1 insertion(+) diff --git a/var/spack/repos/builtin/packages/sentieon-genomics/package.py b/var/spack/repos/builtin/packages/sentieon-genomics/package.py index 053ce9fb3cb..06b630fea1d 100644 --- a/var/spack/repos/builtin/packages/sentieon-genomics/package.py +++ b/var/spack/repos/builtin/packages/sentieon-genomics/package.py @@ -26,6 +26,7 @@ class SentieonGenomics(Package): url = "https://s3.amazonaws.com/sentieon-release/software/sentieon-genomics-201808.01.tar.gz" maintainers = ["snehring"] + version("202112.06", sha256="18306036f01c3d41dd7ae738b18ae76fd6b666f1172dd4696cd55b4a8465270d") version("202112.05", sha256="c97b14b0484a0c0025115ad7b911453af7bdcd09874c26cbc39fd0bc5588a306") version("202112.04", sha256="154732dc752476d984908e78b1fc5120d4f23028ee165cc4a451ecc1df0e0246") version("202112.02", sha256="033943df7958550fd42b410d34ae91a8956a905fc90ca8baa93d2830f918872c") From 36877abd02f673d0a2bc6f395c509f374c711e96 Mon Sep 17 00:00:00 2001 From: Filippo Spiga Date: Wed, 9 Nov 2022 20:54:50 +0000 Subject: [PATCH 441/442] Adding libpfm 4.12.0 (#33779) --- var/spack/repos/builtin/packages/libpfm4/package.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/var/spack/repos/builtin/packages/libpfm4/package.py b/var/spack/repos/builtin/packages/libpfm4/package.py index 120d2da01f8..9d0c07b63c6 100644 --- a/var/spack/repos/builtin/packages/libpfm4/package.py +++ b/var/spack/repos/builtin/packages/libpfm4/package.py @@ -12,9 +12,10 @@ class Libpfm4(MakefilePackage): the perf_events Linux kernel interface.""" homepage = "http://perfmon2.sourceforge.net" - url = "https://downloads.sourceforge.net/project/perfmon2/libpfm4/libpfm-4.8.0.tar.gz" + url = "https://downloads.sourceforge.net/project/perfmon2/libpfm4/libpfm-4.12.0.tar.gz" maintainers = ["mwkrentel"] + version("4.12.0", sha256="4b0c1f53f39a61525b69bebf532c68040c1b984d7544a8ae0844b13cd91e1ee4") version("4.11.0", sha256="5da5f8872bde14b3634c9688d980f68bda28b510268723cc12973eedbab9fecc") version("4.10.1", sha256="c61c575378b5c17ccfc5806761e4038828610de76e2e34fac9f7fa73ba844b49") version("4.9.0", sha256="db0fbe8ee28fd9beeb5d3e80b7cb3b104debcf6a9fcf5cb8b882f0662c79e4e2") From bb1cd430c0d6f8bebfb655c65244a25bcc325d8d Mon Sep 17 00:00:00 2001 From: Chris White Date: Wed, 9 Nov 2022 13:22:43 -0800 Subject: [PATCH 442/442] always use the cxx compiler as a host compiler (#33771) --- lib/spack/spack/build_systems/cached_cmake.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/lib/spack/spack/build_systems/cached_cmake.py b/lib/spack/spack/build_systems/cached_cmake.py index 84f402299ad..787def703e3 100644 --- a/lib/spack/spack/build_systems/cached_cmake.py +++ b/lib/spack/spack/build_systems/cached_cmake.py @@ -205,13 +205,7 @@ def initconfig_hardware_entries(self): entries.append(cmake_cache_path("CUDA_TOOLKIT_ROOT_DIR", cudatoolkitdir)) cudacompiler = "${CUDA_TOOLKIT_ROOT_DIR}/bin/nvcc" entries.append(cmake_cache_path("CMAKE_CUDA_COMPILER", cudacompiler)) - - if spec.satisfies("^mpi"): - entries.append(cmake_cache_path("CMAKE_CUDA_HOST_COMPILER", "${MPI_CXX_COMPILER}")) - else: - entries.append( - cmake_cache_path("CMAKE_CUDA_HOST_COMPILER", "${CMAKE_CXX_COMPILER}") - ) + entries.append(cmake_cache_path("CMAKE_CUDA_HOST_COMPILER", "${CMAKE_CXX_COMPILER}")) return entries

  • Sc|vX^YoeqxoLTo+NL66`PjI^ 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 j|-&_Wc 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