Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@ cuda.toolkit(
use_repo(cuda, "cuda")

register_toolchains(
"@cuda//toolchain:nvcc-local-toolchain",
"@cuda//toolchain/clang:clang-local-toolchain",
"@cuda//toolchain/disabled:disabled-local-toolchain",
"@cuda//toolchain/...",
)

bazel_dep(name = "rules_cuda_examples", dev_dependency = True)
Expand Down
47 changes: 46 additions & 1 deletion cuda/extensions.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ cuda_component_tag = tag_class(attrs = {
"If all downloads fail, the rule will fail.",
),
"version": attr.string(doc = "A unique version number for component."),
"toolkit_version": attr.string(doc = "CUDA Toolkit release containing this component."),
})

cuda_redist_json_tag = tag_class(attrs = {
Expand Down Expand Up @@ -134,6 +135,7 @@ def _register_redist_components(module_ctx, attr, component_entries):
component_attr = {key: value for key, value in spec.items()}
component_repo_name = repo_name + "_" + platform.replace("-", "_") + "_" + redist_ver.replace(".", "_")
component_attr["name"] = component_repo_name
component_attr["toolkit_version"] = redist_ver

dedupe_key = (spec["component_name"], platform, redist_ver)
existing_entry = component_entries.get(dedupe_key)
Expand Down Expand Up @@ -250,7 +252,49 @@ def _impl(module_ctx):
if components_mapping != None:
sorted_redist_versions = sorted(redist_versions, key = _version_sort_key)

# Always use the maximum version so the toolkit includes all components.
# Generate a static implementation repository for each toolkit version. Each
# repository receives component aliases fixed to that version, so load-time
# BUILD decisions and compiler-file ownership cannot leak from another CUDA.
toolchain_repositories = {}
for redist_version in sorted_redist_versions:
exact_components_mapping = {}
version_label = redist_version.replace(".", "_").replace("-", "_")
for component_name in redist_components_mapping.keys():
component_platforms = [
platform
for platform in SUPPORTED_PLATFORMS
if platform in versioned_repos[component_name] and redist_version in versioned_repos[component_name][platform]
]
if not component_platforms:
continue

if len(component_platforms) == 1:
exact_components_mapping[component_name] = "@" + versioned_repos[component_name][component_platforms[0]][redist_version]
else:
alias_name = "{}_{}_toolchain_{}".format(toolkit.name, component_name, version_label)
platform_repo_kwargs = {}
for platform in SUPPORTED_PLATFORMS:
repos = {}
if platform in versioned_repos[component_name] and redist_version in versioned_repos[component_name][platform]:
repos[redist_version] = versioned_repos[component_name][platform][redist_version]
platform_repo_kwargs[_platform_repos_attr(platform)] = repos
platform_alias_repo(
name = alias_name,
component_name = component_name,
versions = [redist_version],
**platform_repo_kwargs
)
exact_components_mapping[component_name] = "@" + alias_name

toolchain_repo_name = "{}_toolchain_{}".format(toolkit.name, version_label)
cuda_toolkit(
name = toolchain_repo_name,
components_mapping = exact_components_mapping,
version = redist_version,
)
toolchain_repositories[redist_version] = "@" + toolchain_repo_name

# Always use the maximum version so the public toolkit facade includes all components.
# Components that don't exist in older versions will fall back to dummy.
toolkit_version = sorted_redist_versions[-1]

Expand All @@ -263,6 +307,7 @@ def _impl(module_ctx):
components_mapping = components_mapping,
version = toolkit_version,
toolkit_versions = sorted_redist_versions,
toolchain_repositories = toolchain_repositories,
)
else:
cuda_toolkit(**_module_tag_to_dict(toolkit))
Expand Down
34 changes: 29 additions & 5 deletions cuda/private/repositories.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,10 @@ def _detect_deliverable_cuda_toolkit(repository_ctx):

cicc = None
libdevice = None
if "nvvm" in repository_ctx.attr.components_mapping:
if int(cuda_version_major) < 13:
cicc = "{}//:cicc".format(nvcc_repo)
libdevice = "{}//:libdevice.10.bc".format(nvcc_repo)
elif "nvvm" in repository_ctx.attr.components_mapping:
nvvm_repo = repository_ctx.attr.components_mapping["nvvm"]
cicc = "{}//:cicc".format(nvvm_repo)
libdevice = "{}//:libdevice.10.bc".format(nvvm_repo)
Expand Down Expand Up @@ -263,8 +266,12 @@ def config_cuda_toolkit_and_nvcc(repository_ctx, cuda):
# Generate @cuda//defs.bzl
template_helper.generate_defs_bzl(repository_ctx, cuda.version_major, cuda.version_minor, is_local_ctk == True)

# Generate @cuda//toolchain/BUILD
template_helper.generate_toolchain_build(repository_ctx, cuda)
# Generate toolchain implementations, or the stable @cuda facade that points at
# independently generated implementations for each configured toolkit version.
if repository_ctx.attr.toolchain_repositories:
template_helper.generate_toolchain_facade(repository_ctx)
else:
template_helper.generate_toolchain_build(repository_ctx, cuda)

def detect_clang(repository_ctx):
"""Detect local clang installation.
Expand Down Expand Up @@ -322,8 +329,9 @@ def config_clang(repository_ctx, cuda, clang_path_or_label):
if len(repository_ctx.attr.components_mapping) != 0:
is_local_ctk = False

# Generate @cuda//toolchain/clang/BUILD
template_helper.generate_toolchain_clang_build(repository_ctx, cuda, clang_path_or_label)
# The versioned facade generated above includes its own clang declarations.
if not repository_ctx.attr.toolchain_repositories:
template_helper.generate_toolchain_clang_build(repository_ctx, cuda, clang_path_or_label)

def config_disabled(repository_ctx):
repository_ctx.symlink(Label("//cuda/private:templates/BUILD.toolchain_disabled"), "toolchain/disabled/BUILD")
Expand Down Expand Up @@ -355,6 +363,9 @@ cuda_toolkit = repository_rule(
"generated toolchain selects among them on @rules_cuda//cuda:version instead of " +
"hardcoding `version`.",
),
"toolchain_repositories": attr.string_dict(
doc = "Internal mapping from exact CUDA versions to repositories containing their toolchain implementations.",
),
},
configure = True,
local = True,
Expand Down Expand Up @@ -445,14 +456,24 @@ def _cuda_component_impl(repository_ctx):
_patch_nvcc_profile_post(repository_ctx, patch_nvcc_profile)
_patch_nvvm(repository_ctx, component_name)

toolkit_version = repository_ctx.attr.toolkit_version or repository_ctx.attr.version
defs_label = "//:defs.bzl" if toolkit_version else "@cuda//:defs.bzl"

template_helper.generate_build(
repository_ctx,
libpath = "lib",
components = {component_name: repository_ctx.name},
defs_label = defs_label,
is_cuda_repo = False,
is_deliverable = True,
)

if toolkit_version:
version_parts = toolkit_version.split(".")
if len(version_parts) < 2:
fail("toolkit_version must contain at least a major and minor version")
template_helper.generate_defs_bzl(repository_ctx, version_parts[0], version_parts[1], False)

desc_name = repository_ctx.attr.descriptive_name or repository_ctx.attr.component_name
repository_ctx.file(
"{}/version.json".format(component_name),
Expand Down Expand Up @@ -509,6 +530,9 @@ cuda_component = repository_rule(
"If all downloads fail, the rule will fail.",
),
"version": attr.string(doc = "A unique version number for component. Store in version.json file"),
"toolkit_version": attr.string(
doc = "CUDA Toolkit release containing this component. Used for version-gated BUILD evaluation.",
),
},
)

Expand Down
114 changes: 102 additions & 12 deletions cuda/private/template_helper.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,11 @@ def _expand_dctk_component(repository_ctx, component):
def _component_owns_cuda_repo_alias(component, target, components):
if target == "culibos_a" and "culibos" in components:
return component == "culibos"
if target in ["cicc", "libdevice", "libdevice.10.bc"] and "nvvm" in components:
return component == "nvvm"
return True

def _generate_build_impl(repository_ctx, libpath, components, is_cuda_repo, is_deliverable):
def _generate_build_impl(repository_ctx, libpath, components, is_cuda_repo, is_deliverable, defs_label):
# stitch template fragment
fragments = [
Label("//cuda/private:templates/BUILD.cuda_shared"),
Expand All @@ -178,6 +180,8 @@ def _generate_build_impl(repository_ctx, libpath, components, is_cuda_repo, is_d
comp = components.keys()[0]
fragments.append(_expand_dctk_component(repository_ctx, comp))
fragments.append(Label("//cuda/private:templates/BUILD.{}".format(comp)))
if comp == "nvcc":
fragments.append(Label("//cuda/private:templates/BUILD.nvcc_nvvm_embedded"))
else:
fail("unreachable")

Expand Down Expand Up @@ -208,11 +212,12 @@ def _generate_build_impl(repository_ctx, libpath, components, is_cuda_repo, is_d

substitutions = {
"%{component_name}": "cuda" if is_cuda_repo else components.keys()[0],
"%{defs_label}": defs_label,
"%{libpath}": libpath,
}
repository_ctx.template("BUILD", template_path, substitutions = substitutions, executable = False)

def _generate_build(repository_ctx, libpath, components = None, is_cuda_repo = True, is_deliverable = False):
def _generate_build(repository_ctx, libpath, components = None, is_cuda_repo = True, is_deliverable = False, defs_label = "//:defs.bzl"):
"""Generate `@cuda//BUILD` or `@cuda_<component>//BUILD`

Notes:
Expand All @@ -237,7 +242,7 @@ def _generate_build(repository_ctx, libpath, components = None, is_cuda_repo = T
if c not in REGISTRY:
fail("{} is not a valid component")

_generate_build_impl(repository_ctx, libpath, components, is_cuda_repo, is_deliverable)
_generate_build_impl(repository_ctx, libpath, components, is_cuda_repo, is_deliverable, defs_label)

def _generate_defs_bzl(repository_ctx, version_major, version_minor, is_local_ctk):
tpl_label = Label("//cuda/private:templates/defs.bzl.tpl")
Expand Down Expand Up @@ -268,6 +273,7 @@ def _generate_redist_bzl(repository_ctx, component_specs, redist_version):
strip_prefix = {strip_prefix},
urls = {urls},
version = "{version}",
toolkit_version = "{toolkit_version}",
)"""

for spec in component_specs:
Expand All @@ -282,6 +288,7 @@ def _generate_redist_bzl(repository_ctx, component_specs, redist_version):
strip_prefix = repr(spec["strip_prefix"]),
urls = repr(spec["urls"]),
version = spec["version"],
toolkit_version = redist_version,
),
)
mapping[spec["component_name"]] = "@" + repo_name
Expand All @@ -299,7 +306,7 @@ def _generate_toolchain_build(repository_ctx, cuda):
"//cuda/private:templates/BUILD.toolchain_" +
("nvcc" if _is_linux(repository_ctx) else "nvcc_msvc"),
)
compiler_files = ["@cuda//:compiler_deps"]
compiler_files = ["//:compiler_deps"]
if cuda.cicc_label != None:
compiler_files.append(cuda.cicc_label)
if cuda.libdevice_label != None:
Expand Down Expand Up @@ -375,20 +382,20 @@ def _generate_toolchain_clang_build(repository_ctx, cuda, clang_path_or_label):
cuda_path_for_subst = ""
path_data = None
if cuda.path: # local installation
compiler_files.append("@cuda//:compiler_deps")
compiler_files.append("//:compiler_deps")
cuda_path_for_subst = _to_forward_slash(cuda.path)
else: # scattered components
cuda_path_for_subst = "$(location @cuda//:compiler_root)"
path_data = ["@cuda//:compiler_root"]
cuda_path_for_subst = "$(location //:compiler_root)"
path_data = ["//:compiler_root"]
compiler_files.extend([
"@cuda//:nvcc_all_files",
"@cuda//:cccl_all_files",
"@cuda//:cudart_all_files",
"@cuda//:curand_all_files",
"//:nvcc_all_files",
"//:cccl_all_files",
"//:cudart_all_files",
"//:curand_all_files",
])
if int(cuda.version_major) >= 13:
compiler_files.extend([
"@cuda//:nvvm_all_files",
"//:nvvm_all_files",
])
path_data_line = "path_data = " + repr(path_data) + ","
compiler_files_line = "compiler_files = " + repr(compiler_files) + ","
Expand Down Expand Up @@ -434,10 +441,93 @@ def _generate_toolchain_clang_build(repository_ctx, cuda, clang_path_or_label):
executable = False,
)

def _toolchain_declaration(name, implementation, compiler_setting, version_setting, exec_constraints = []):
lines = [
"toolchain(",
' name = "{}",'.format(name),
]
if exec_constraints:
lines.extend([
" exec_compatible_with = {},".format(repr(exec_constraints)),
" target_compatible_with = {},".format(repr(exec_constraints)),
])
lines.extend([
" target_settings = [",
' "@rules_cuda//cuda:is_enabled",',
' "{}",'.format(compiler_setting),
' ":{}",'.format(version_setting),
" ],",
' toolchain = "{}",'.format(implementation),
' toolchain_type = "@rules_cuda//cuda:toolchain_type",',
' visibility = ["//visibility:public"],',
")",
])
return "\n".join(lines)

def _generate_toolchain_facade(repository_ctx):
versions = sorted(repository_ctx.attr.toolchain_repositories.keys())
default_version = repository_ctx.attr.version
os_constraint = "@platforms//os:windows" if _is_windows(repository_ctx) else "@platforms//os:linux"

nvcc = []
clang = []
for version in versions:
label = _version_label(version)
setting = "toolkit_version_is_{}".format(label)
definition = [
"config_setting(",
' name = "{}",'.format(setting),
' flag_values = {{"@rules_cuda//cuda:version": "{}"}},'.format(version),
")",
]
nvcc.extend(definition)
clang.extend(definition)
repo = repository_ctx.attr.toolchain_repositories[version]
nvcc.append(_toolchain_declaration(
"nvcc-{}-toolchain".format(label),
repo + "//toolchain:nvcc-local",
"@rules_cuda//cuda:compiler_is_nvcc",
setting,
[os_constraint],
))
clang.append(_toolchain_declaration(
"clang-{}-toolchain".format(label),
repo + "//toolchain/clang:clang-local",
"@rules_cuda//cuda:compiler_is_clang",
setting,
))

default_setting = [
"config_setting(",
' name = "toolkit_version_is_default",',
' flag_values = {"@rules_cuda//cuda:version": ""},',
")",
]
nvcc.extend(default_setting)
clang.extend(default_setting)
default_repo = repository_ctx.attr.toolchain_repositories[default_version]
nvcc.append(_toolchain_declaration(
"nvcc-local-toolchain",
default_repo + "//toolchain:nvcc-local",
"@rules_cuda//cuda:compiler_is_nvcc",
"toolkit_version_is_default",
[os_constraint],
))
clang.append(_toolchain_declaration(
"clang-local-toolchain",
default_repo + "//toolchain/clang:clang-local",
"@rules_cuda//cuda:compiler_is_clang",
"toolkit_version_is_default",
))

repository_ctx.file("toolchain/BUILD", "\n\n".join(nvcc) + "\n")
repository_ctx.file("toolchain/clang/BUILD", "\n\n".join(clang) + "\n")

template_helper = struct(
generate_build = _generate_build,
generate_defs_bzl = _generate_defs_bzl,
generate_redist_bzl = _generate_redist_bzl,
generate_toolchain_build = _generate_toolchain_build,
generate_toolchain_clang_build = _generate_toolchain_clang_build,
generate_toolchain_facade = _generate_toolchain_facade,
)
2 changes: 1 addition & 1 deletion cuda/private/templates/BUILD.cuda_shared
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
load("@bazel_skylib//rules:common_settings.bzl", "bool_setting") # @unused
load("@cuda//:defs.bzl", "additional_header_deps", "any_or_first", "if_cuda_toolkit_version_ge", "if_local_cuda_toolkit") # @unused
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_import", "cc_library")
load("@rules_cuda//cuda:defs.bzl", "cc_import_versioned_sos", "if_linux", "if_windows") # @unused
load("%{defs_label}", "additional_header_deps", "any_or_first", "if_cuda_toolkit_version_ge", "if_local_cuda_toolkit") # @unused

package(
default_visibility = ["//visibility:public"],
Expand Down
27 changes: 27 additions & 0 deletions cuda/private/templates/BUILD.nvcc_nvvm_embedded
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
nvcc_cicc_bin = any_or_first(
"%{component_name}/nvvm/bin/cicc",
"%{component_name}/nvvm/bin/cicc.exe",
)

alias(
name = "cicc",
actual = if_cuda_toolkit_version_ge(
(13, 0),
"@rules_cuda//cuda/dummy:cicc",
nvcc_cicc_bin,
),
)

alias(
name = "libdevice.10.bc",
actual = if_cuda_toolkit_version_ge(
(13, 0),
"@rules_cuda//cuda/dummy:libdevice.10.bc",
"%{component_name}/nvvm/libdevice/libdevice.10.bc",
),
)

alias(
name = "libdevice",
actual = ":libdevice.10.bc",
)
Loading
Loading