feat: allow py_cc_toolchain libs to be optional (#2197)
This is for cases when shared libraries aren't available.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bd94003..d410575 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -28,6 +28,9 @@
* (gazelle): Update error messages when unable to resolve a dependency to be more human-friendly.
* (flags) The {obj}`--python_version` flag now also returns
{obj}`config_common.FeatureFlagInfo`.
+* (toolchains) {obj}`py_cc_toolchain.libs` and {obj}`PyCcToolchainInfo.libs` is
+ optional. This is to support situations where only the Python headers are
+ available.
### Fixed
* (whl_library): Remove `--no-index` and add `--no-build-isolation` to the
diff --git a/python/private/py_cc_toolchain_info.bzl b/python/private/py_cc_toolchain_info.bzl
index ae46bf4..c5cdbd9 100644
--- a/python/private/py_cc_toolchain_info.bzl
+++ b/python/private/py_cc_toolchain_info.bzl
@@ -41,9 +41,9 @@
represents).
""",
"libs": """\
-:type: struct
+:type: struct | None
-Information about C libraries, struct with fields:
+If available, information about C libraries, struct with fields:
* providers_map: A dict of string to provider instances. The key should be
a fully qualified name (e.g. `@rules_foo//bar:baz.bzl#MyInfo`) of the
provider to uniquely identify its type.
diff --git a/python/private/py_cc_toolchain_rule.bzl b/python/private/py_cc_toolchain_rule.bzl
index 1599415..2c52a2e 100644
--- a/python/private/py_cc_toolchain_rule.bzl
+++ b/python/private/py_cc_toolchain_rule.bzl
@@ -23,6 +23,16 @@
load(":py_cc_toolchain_info.bzl", "PyCcToolchainInfo")
def _py_cc_toolchain_impl(ctx):
+ if ctx.attr.libs:
+ libs = struct(
+ providers_map = {
+ "CcInfo": ctx.attr.libs[CcInfo],
+ "DefaultInfo": ctx.attr.libs[DefaultInfo],
+ },
+ )
+ else:
+ libs = None
+
py_cc_toolchain = PyCcToolchainInfo(
headers = struct(
providers_map = {
@@ -30,12 +40,7 @@
"DefaultInfo": ctx.attr.headers[DefaultInfo],
},
),
- libs = struct(
- providers_map = {
- "CcInfo": ctx.attr.libs[CcInfo],
- "DefaultInfo": ctx.attr.libs[DefaultInfo],
- },
- ),
+ libs = libs,
python_version = ctx.attr.python_version,
)
extra_kwargs = {}
@@ -59,7 +64,6 @@
doc = ("Target that provides the Python runtime libraries for linking. " +
"Typically this is a cc_library target of `.so` files."),
providers = [CcInfo],
- mandatory = True,
),
"python_version": attr.string(
doc = "The Major.minor Python version, e.g. 3.11",
diff --git a/tests/cc/py_cc_toolchain/py_cc_toolchain_tests.bzl b/tests/cc/py_cc_toolchain/py_cc_toolchain_tests.bzl
index fcc520e..0419a04 100644
--- a/tests/cc/py_cc_toolchain/py_cc_toolchain_tests.bzl
+++ b/tests/cc/py_cc_toolchain/py_cc_toolchain_tests.bzl
@@ -16,15 +16,16 @@
load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite")
load("@rules_testing//lib:truth.bzl", "matching", "subjects")
+load("//python/cc:py_cc_toolchain.bzl", "py_cc_toolchain")
load("//tests/support:cc_info_subject.bzl", "cc_info_subject")
load("//tests/support:py_cc_toolchain_info_subject.bzl", "PyCcToolchainInfoSubject")
_tests = []
-def _py_cc_toolchain_test(name):
+def _test_py_cc_toolchain(name):
analysis_test(
name = name,
- impl = _py_cc_toolchain_test_impl,
+ impl = _test_py_cc_toolchain_impl,
target = "//tests/support/cc_toolchains:fake_py_cc_toolchain_impl",
attrs = {
"header": attr.label(
@@ -34,7 +35,7 @@
},
)
-def _py_cc_toolchain_test_impl(env, target):
+def _test_py_cc_toolchain_impl(env, target):
env.expect.that_target(target).has_provider(platform_common.ToolchainInfo)
toolchain = PyCcToolchainInfoSubject.new(
@@ -80,7 +81,26 @@
matching.str_matches("/libpython3."),
)
-_tests.append(_py_cc_toolchain_test)
+_tests.append(_test_py_cc_toolchain)
+
+def _test_libs_optional(name):
+ py_cc_toolchain(
+ name = name + "_subject",
+ libs = None,
+ headers = "//tests/support/cc_toolchains:fake_headers",
+ python_version = "4.5",
+ )
+ analysis_test(
+ name = name,
+ target = name + "_subject",
+ impl = _test_libs_optional_impl,
+ )
+
+def _test_libs_optional_impl(env, target):
+ libs = target[platform_common.ToolchainInfo].py_cc_toolchain.libs
+ env.expect.that_bool(libs == None).equals(True)
+
+_tests.append(_test_libs_optional)
def py_cc_toolchain_test_suite(name):
test_suite(