spack/var/spack/repos/builtin/packages/care/package.py
Todd Gamblin 3cdf4e7ccf
packages: eliminate unnecessary implicit string concatenation
Python lets you do things like

```python
"these are " "one string"

'so are' "these"
```

This can be useful for breaking strings over multiple lines. It also often happens
unintentionally and indicates that there are subtle errors in the code.

There are a lot of variant descriptions that have implicit concatenation harmlessly
due to refactors, e.g.:

```python
    variant("myvariant", default=True, description="this used to be" "on two lines")
```

But there are also real bugs, like this, where the author probably omitted a comma and
didn't notice that `black` reformatted the implicit concatenation onto one line:

```python
args = [
     "--with-thing",
     "--with-second-thing" "--with-third-thing",
]
```

And other bugs like this, where the author probably intended to add a space, but didn't:

```python
options = "${CFLAGS}" "${SPECIAL_PIC_OPTION}"
```

Some things are harmless but confusing:

```python
"first part of string {0} " "second part {1}".format("zero", "one")
```

It's not broken. String concatenation happens *before* the `format()` call, and the
whole string is formatted. But it sure is hard to read.

Unfortunately, you can't detect this stuff with an AST pass, as implicit concatenation
is done at the parsing phase. I had to detect this with grep:

```console
> grep -l '^[^"]*"[^"]*" "' */package.py
> grep -l "^[^']*'[^']*' '" */package.py
```

- [x] Get rid of nearly all implicit string concatenation in packages

Signed-off-by: Todd Gamblin <tgamblin@llnl.gov>
2025-01-31 20:35:21 -08:00

285 lines
10 KiB
Python

# Copyright Spack Project Developers. See COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import socket
from spack.package import *
from .blt import llnl_link_helpers
class Care(CachedCMakePackage, CudaPackage, ROCmPackage):
"""
CHAI and RAJA extensions (includes data structures and algorithms).
"""
homepage = "https://github.com/LLNL/CARE"
git = "https://github.com/LLNL/CARE.git"
tags = ["radiuss"]
license("BSD-3-Clause")
maintainers("adayton1", "adrienbernede")
version("develop", branch="develop", submodules=False)
version("master", branch="master", submodules=False)
version(
"0.13.3",
tag="v0.13.3",
commit="93853696b452647278eae9311b835ad206236522",
submodules=False,
)
version(
"0.13.2",
tag="v0.13.2",
commit="b25dcd2a35683a68db1c25173e849be69833ed4f",
submodules=False,
)
version(
"0.13.1",
tag="v0.13.1",
commit="0fd0d47aaaa57076f26caad88e667fbc01ff7214",
submodules=False,
)
version(
"0.13.0",
tag="v0.13.0",
commit="2b288e2c557c3b14befeebc8e14a7d48348bd857",
submodules=False,
)
version(
"0.12.0",
tag="v0.12.0",
commit="a9978083035eb00a090451bd36d7987bc935204d",
submodules=False,
)
version("0.10.0", tag="v0.10.0", submodules="True")
version(
"0.3.0", tag="v0.3.0", commit="5e2b69b2836c9f2215207ca9a36a690cb77eea33", submodules="True"
)
version(
"0.2.0", tag="v0.2.0", commit="30135e03b14b1dc753634e9147dafede0663906f", submodules="True"
)
depends_on("c", type="build") # generated
depends_on("cxx", type="build") # generated
depends_on("fortran", type="build") # generated
variant("openmp", default=False, description="Build with OpenMP support")
variant("mpi", default=False, description="Enable MPI support")
variant(
"implicit_conversions",
default=False,
description="Enable implicit conversions to/from raw pointers",
)
variant("tests", default=False, description="Build tests")
variant("benchmarks", default=False, description="Build benchmarks.")
variant("examples", default=False, description="Build examples.")
variant("docs", default=False, description="Build documentation")
variant("loop_fuser", default=False, description="Enable loop fusion capability")
depends_on("cmake", type="build")
depends_on("cmake@3.23:", type="build", when="@0.13.2:")
depends_on("cmake@3.21:", type="build", when="@0.12.0:+rocm")
depends_on("cmake@3.18:", type="build", when="@0.12.0:")
depends_on("cmake@3.14:", type="build", when="@0.10.0:")
depends_on("cmake@3.9:", type="build", when="+cuda")
depends_on("cmake@3.8:", type="build")
depends_on("blt", type="build")
depends_on("blt@0.6.2:", type="build", when="@0.13.0:")
depends_on("blt@0.6.1:", type="build", when="@0.12.0:")
depends_on("blt@0.5.2:", type="build", when="@0.10.0:")
depends_on("blt@0.4.1:", type="build", when="@0.3.1:")
depends_on("blt@:0.3.6", type="build", when="@:0.3.0")
conflicts("^blt@:0.3.6", when="+rocm")
depends_on("camp", when="@:0.11.1")
depends_on("umpire")
depends_on("umpire+mpi", when="+mpi")
depends_on("umpire@2024.07.0:", when="@0.13.2:")
depends_on("umpire@2024.02.1:", when="@0.13.0:")
depends_on("umpire@2024.02.0:", when="@0.12.0:")
depends_on("umpire@2022.10.0:", when="@0.10.0:")
depends_on("raja")
depends_on("raja@2024.07.0:", when="@0.13.2:")
depends_on("raja@2024.02.2:", when="@0.13.1:")
depends_on("raja@2024.02.1:", when="@0.13.0:")
depends_on("raja@2024.02.0:", when="@0.12.0:")
depends_on("raja@2022.10.5:", when="@0.10.0:")
# TODO: Add an enable_pick variant
depends_on("chai+enable_pick+raja")
depends_on("chai@2024.07.0:", when="@0.13.2:")
depends_on("chai@2024.02.2:", when="@0.13.1:")
depends_on("chai@2024.02.1:", when="@0.13.0:")
depends_on("chai@2024.02.0:", when="@0.12.0:")
depends_on("chai@2022.10.0:", when="@0.10.0:")
conflicts("+openmp", when="+rocm")
conflicts("+openmp", when="+cuda")
conflicts("~tests", when="+benchmarks")
with when("+openmp"):
depends_on("umpire+openmp")
depends_on("raja+openmp")
depends_on("chai+openmp")
with when("+cuda"):
# WARNING: this package currently only supports an internal cub
# package. This will cause a race condition if compiled with another
# package that uses cub. TODO: have all packages point to the same external
# cub package.
depends_on("cub")
depends_on("umpire+cuda")
depends_on("raja+cuda")
depends_on("chai+cuda")
for sm_ in CudaPackage.cuda_arch_values:
depends_on("umpire+cuda cuda_arch={0}".format(sm_), when="cuda_arch={0}".format(sm_))
depends_on("raja+cuda cuda_arch={0}".format(sm_), when="cuda_arch={0}".format(sm_))
depends_on("chai+cuda cuda_arch={0}".format(sm_), when="cuda_arch={0}".format(sm_))
with when("+rocm"):
depends_on("umpire+rocm")
depends_on("raja+rocm")
depends_on("chai+rocm")
for arch_ in ROCmPackage.amdgpu_targets:
depends_on(
"umpire+rocm amdgpu_target={0}".format(arch_),
when="amdgpu_target={0}".format(arch_),
)
depends_on(
"raja+rocm amdgpu_target={0}".format(arch_), when="amdgpu_target={0}".format(arch_)
)
depends_on(
"chai+rocm amdgpu_target={0}".format(arch_), when="amdgpu_target={0}".format(arch_)
)
def _get_sys_type(self, spec):
sys_type = spec.architecture
if "SYS_TYPE" in env:
sys_type = env["SYS_TYPE"]
return sys_type
@property
def cache_name(self):
hostname = socket.gethostname()
if "SYS_TYPE" in env:
hostname = hostname.rstrip("1234567890")
return "{0}-{1}-{2}@{3}-{4}.cmake".format(
hostname,
self._get_sys_type(self.spec),
self.spec.compiler.name,
self.spec.compiler.version,
self.spec.dag_hash(8),
)
def initconfig_compiler_entries(self):
spec = self.spec
compiler = self.compiler
entries = super().initconfig_compiler_entries()
if spec.satisfies("+rocm"):
entries.insert(0, cmake_cache_path("CMAKE_CXX_COMPILER", spec["hip"].hipcc))
llnl_link_helpers(entries, spec, compiler)
return entries
def initconfig_hardware_entries(self):
spec = self.spec
entries = super().initconfig_hardware_entries()
entries.append(cmake_cache_option("ENABLE_OPENMP", spec.satisfies("+openmp")))
if spec.satisfies("+cuda"):
entries.append(cmake_cache_option("ENABLE_CUDA", True))
entries.append(cmake_cache_option("CUDA_SEPARABLE_COMPILATION", True))
entries.append(cmake_cache_string("NVTOOLSEXT_DIR", spec["cuda"].prefix))
entries.append(cmake_cache_string("CUB_DIR", spec["cub"].prefix))
else:
entries.append(cmake_cache_option("ENABLE_CUDA", False))
if spec.satisfies("+rocm"):
entries.append(cmake_cache_option("ENABLE_HIP", True))
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))
)
else:
entries.append(cmake_cache_option("ENABLE_HIP", False))
return entries
def initconfig_mpi_entries(self):
spec = self.spec
entries = super(Care, self).initconfig_mpi_entries()
entries.append(cmake_cache_option("ENABLE_MPI", spec.satisfies("+mpi")))
return entries
def initconfig_package_entries(self):
spec = self.spec
entries = []
# TPL locations
entries.append("#------------------{0}".format("-" * 60))
entries.append("# TPLs")
entries.append("#------------------{0}\n".format("-" * 60))
entries.append(cmake_cache_path("BLT_SOURCE_DIR", spec["blt"].prefix))
entries.append(cmake_cache_path("CAMP_DIR", spec["camp"].prefix))
entries.append(cmake_cache_path("UMPIRE_DIR", spec["umpire"].prefix))
entries.append(cmake_cache_path("RAJA_DIR", spec["raja"].prefix))
entries.append(cmake_cache_path("CHAI_DIR", spec["chai"].prefix))
# Build options
entries.append("#------------------{0}".format("-" * 60))
entries.append("# Build Options")
entries.append("#------------------{0}\n".format("-" * 60))
entries.append(cmake_cache_string("CMAKE_BUILD_TYPE", spec.variants["build_type"].value))
entries.append(cmake_cache_option("ENABLE_TESTS", spec.satisfies("+tests")))
entries.append(cmake_cache_option("CARE_ENABLE_TESTS", spec.satisfies("+tests")))
# For tests to work, we also need BLT_ENABLE_TESTS to be on.
# This will take care of the gtest dependency. CARE developers should
# consider consolidating these flags in the future.
entries.append(cmake_cache_option("BLT_ENABLE_TESTS", spec.satisfies("+tests")))
# There are both CARE_ENABLE_* and ENABLE_* variables in here because
# one controls the BLT infrastructure and the other controls the CARE
# infrastructure. The goal is to just be able to use the CARE_ENABLE_*
# variables, but CARE isn't set up correctly for that yet.
entries.append(cmake_cache_option("ENABLE_BENCHMARKS", spec.satisfies("+benchmarks")))
entries.append(cmake_cache_option("CARE_ENABLE_BENCHMARKS", spec.satisfies("+benchmarks")))
entries.append(cmake_cache_option("ENABLE_EXAMPLES", spec.satisfies("+examples")))
entries.append(cmake_cache_option("CARE_ENABLE_EXAMPLES", spec.satisfies("+examples")))
entries.append(cmake_cache_option("ENABLE_DOCS", spec.satisfies("+docs")))
entries.append(cmake_cache_option("CARE_ENABLE_DOCS", spec.satisfies("+docs")))
entries.append(
cmake_cache_option(
"CARE_ENABLE_IMPLICIT_CONVERSIONS", spec.satisfies("+implicit_conversions")
)
)
entries.append(cmake_cache_option("CARE_ENABLE_LOOP_FUSER", spec.satisfies("+loop_fuser")))
return entries
def cmake_args(self):
return []