Skip to content

Commit

Permalink
Add disable-cuda option
Browse files Browse the repository at this point in the history
Sometimes we don't want to append a -cu* suffix to the package name
or get CUDA-version-specific dependencies. Add an option to disable
this. This option supplants require-cuda, so get rid of it too.
  • Loading branch information
KyleFromNVIDIA committed May 10, 2024
1 parent 97a1950 commit f94ce3b
Show file tree
Hide file tree
Showing 6 changed files with 199 additions and 190 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ Any option without a default is required.
| `build-backend` | The wrapped build backend (e.g. `setuptools.build_meta`) | string | | N |
| `commit-file` | The file in which to write the git commit hash | string | "" (No file) | N |
| `dependencies-file` | The path to the `dependencies.yaml` file to use | string | "dependencies.yaml" | Y |
| `disable-cuda` | If true, CUDA version is not used in package name or dependencies | bool | false | Y |
| `matrix-entry` | A `;`-separated list of `=`-delimited key/value pairs | string | "" | Y |
| `require-cuda` | If false, builds will succeed even if nvcc is not available | bool | true | Y |
| `requires` | List of build requirements (in addition to `build-system.requires`) | list[str] | [] | N |


Expand Down
2 changes: 1 addition & 1 deletion rapids_build_backend/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ class Config:
"build-backend": (None, False),
"commit-file": ("", False),
"dependencies-file": ("dependencies.yaml", True),
"disable-cuda": (False, True),
"matrix-entry": ("", True),
"require-cuda": (True, True),
"requires": (lambda: [], False),
}

Expand Down
72 changes: 28 additions & 44 deletions rapids_build_backend/impls.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from typing import Union

import rapids_dependency_file_generator
import tomli_w
import tomlkit

from . import utils
from .config import Config
Expand Down Expand Up @@ -39,62 +39,44 @@ def _get_backend(build_backend):


@lru_cache
def _get_cuda_version(require_cuda: bool):
def _get_cuda_version():
"""Get the CUDA suffix based on nvcc.
Parameters
----------
require_cuda : bool
If True, raise an exception if nvcc is not in the PATH. If False, return None.
Returns
-------
str or None
The CUDA major version (e.g., "11") or None if CUDA could not be detected.
The CUDA major version (e.g., "11")
"""
try:
nvcc_exists = (
subprocess.run(["which", "nvcc"], capture_output=True).returncode == 0
nvcc_exists = subprocess.run(["which", "nvcc"], capture_output=True).returncode == 0
if not nvcc_exists:
raise ValueError(
"Could not determine the CUDA version. Make sure nvcc is in your PATH."
)
if not nvcc_exists:
raise ValueError(
"Could not determine the CUDA version. Make sure nvcc is in your PATH."
)

try:
process_output = subprocess.run(["nvcc", "--version"], capture_output=True)
except subprocess.CalledProcessError as e:
raise ValueError("Failed to get version from nvcc.") from e
try:
process_output = subprocess.run(["nvcc", "--version"], capture_output=True)
except subprocess.CalledProcessError as e:
raise ValueError("Failed to get version from nvcc.") from e

output_lines = process_output.stdout.decode().splitlines()
output_lines = process_output.stdout.decode().splitlines()

match = re.search(r"release (\d+)\.(\d+)", output_lines[3])
if match is None:
raise ValueError("Failed to parse CUDA version from nvcc output.")
return match.groups()
except Exception:
if not require_cuda:
return None
raise
match = re.search(r"release (\d+)\.(\d+)", output_lines[3])
if match is None:
raise ValueError("Failed to parse CUDA version from nvcc output.")
return match.groups()


@lru_cache
def _get_cuda_suffix(require_cuda: bool) -> str:
def _get_cuda_suffix() -> str:
"""Get the CUDA suffix based on nvcc.
Parameters
----------
require_cuda : bool
If True, raise an exception if CUDA could not be detected. If False, return an
empty string.
Returns
-------
str
The CUDA suffix (e.g., "-cu11") or an empty string if CUDA could not be
detected.
"""
if (version := _get_cuda_version(require_cuda)) is None:
if (version := _get_cuda_version()) is None:
return ""
return f"-cu{version[0]}"

Expand Down Expand Up @@ -165,7 +147,8 @@ def _edit_pyproject(config):
pyproject_file = "pyproject.toml"
bkp_pyproject_file = ".pyproject.toml.rapids-build-backend.bak"

cuda_version = _get_cuda_version(config.require_cuda)
if not config.disable_cuda:
cuda_version_major, cuda_version_minor = _get_cuda_version()

try:
parsed_config = rapids_dependency_file_generator.load_config_from_file(
Expand Down Expand Up @@ -193,8 +176,8 @@ def _edit_pyproject(config):
):
continue
matrix = _parse_matrix(config.matrix_entry) or dict(file_config.matrix)
if cuda_version is not None:
matrix["cuda"] = [f"{cuda_version[0]}.{cuda_version[1]}"]
if not config.disable_cuda:
matrix["cuda"] = [f"{cuda_version_major}.{cuda_version_minor}"]
rapids_dependency_file_generator.make_dependency_files(
parsed_config=parsed_config,
file_keys=[file_key],
Expand All @@ -203,11 +186,12 @@ def _edit_pyproject(config):
prepend_channels=[],
to_stdout=False,
)
pyproject = utils._get_pyproject()
project_data = pyproject["project"]
project_data["name"] += _get_cuda_suffix(config.require_cuda)
with open(pyproject_file, "wb") as f:
tomli_w.dump(pyproject, f)
if not config.disable_cuda:
pyproject = utils._get_pyproject()
project_data = pyproject["project"]
project_data["name"] += _get_cuda_suffix()
with open(pyproject_file, "w") as f:
tomlkit.dump(pyproject, f)
yield
finally:
# Restore by moving rather than writing to avoid any formatting changes.
Expand Down
8 changes: 4 additions & 4 deletions rapids_build_backend/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

import os

import tomli
import tomlkit


def _get_pyproject(dirname: str = ".") -> dict:
def _get_pyproject(dirname: str = ".") -> tomlkit.toml_document.TOMLDocument:
"""Parse and return the pyproject.toml file."""
with open(os.path.join(dirname, "pyproject.toml"), "rb") as f:
return tomli.load(f)
with open(os.path.join(dirname, "pyproject.toml")) as f:
return tomlkit.load(f)
14 changes: 7 additions & 7 deletions tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ def setup_config_project(tmp_path, flag, config_value):
[
("commit-file", '"pkg/_version.py"', "pkg/_version.py"),
("commit-file", None, ""),
("require-cuda", "true", True),
("require-cuda", "false", False),
("require-cuda", None, True),
("disable-cuda", "true", True),
("disable-cuda", "false", False),
("disable-cuda", None, True),
],
)
def test_config(tmp_path, flag, config_value, expected):
Expand All @@ -40,8 +40,8 @@ def test_config(tmp_path, flag, config_value, expected):
@pytest.mark.parametrize(
"flag, config_value, expected",
[
("require-cuda", "true", True),
("require-cuda", "false", False),
("disable-cuda", "true", True),
("disable-cuda", "false", False),
],
)
def test_config_env_var(tmp_path, flag, config_value, expected):
Expand All @@ -63,8 +63,8 @@ def test_config_env_var(tmp_path, flag, config_value, expected):
@pytest.mark.parametrize(
"flag, config_value, expected",
[
("require-cuda", "true", True),
("require-cuda", "false", False),
("disable-cuda", "true", True),
("disable-cuda", "false", False),
],
)
def test_config_config_settings(tmp_path, flag, config_value, expected):
Expand Down
Loading

0 comments on commit f94ce3b

Please sign in to comment.