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
1 change: 1 addition & 0 deletions autoconf/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ bzl_library(
srcs = ["package_info.bzl"],
visibility = ["//visibility:public"],
deps = [
":cc_autoconf_info_bzl",
"//autoconf/private:bzl_lib",
],
)
Expand Down
7 changes: 5 additions & 2 deletions autoconf/autoconf.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ def _autoconf_impl(ctx):
cache_results = {}
define_results = {}
subst_results = {}
unquoted_defines = []

actions = {}

Expand Down Expand Up @@ -89,10 +90,11 @@ def _autoconf_impl(ctx):
))

define_checks[define_name] = check

# Use cache file directly - no symlink needed
define_results[define_name] = output

if check.get("unquote", False):
unquoted_defines.append(define_name)

# Check for truthy value
if subst:
check["subst"] = subst_name
Expand Down Expand Up @@ -320,6 +322,7 @@ def _autoconf_impl(ctx):
cache_results = cache_results,
define_results = define_results,
subst_results = subst_results,
unquoted_defines = unquoted_defines,
),
OutputGroupInfo(
autoconf_checks = depset([action.input for action in actions.values()]),
Expand Down
45 changes: 33 additions & 12 deletions autoconf/autoconf_hdr.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,38 @@ def _autoconf_hdr_impl(ctx):
all_define_checks = defaults.define | dep_results["define"]
all_subst_checks = defaults.subst | dep_results["subst"]

inputs = depset([ctx.file.template] + all_subst_checks.values() + all_define_checks.values())
# Merge unquoted_defines from defaults and transitive deps
all_unquoted = {}
for uq in getattr(defaults, "unquoted_defines", []):
all_unquoted[uq] = True
for uq in dep_results.get("unquoted_defines", []):
all_unquoted[uq] = True

# Build the manifest: maps define/subst names to result file paths + metadata
manifest_data = {
"defines": {},
"substs": {},
}
for define_name, result_file in all_define_checks.items():
manifest_data["defines"][define_name] = {
"path": result_file.path,
"unquote": define_name in all_unquoted,
}
for subst_name, result_file in all_subst_checks.items():
manifest_data["substs"][subst_name] = {
"path": result_file.path,
"unquote": subst_name in all_unquoted,
}

manifest = ctx.actions.declare_file("{}.manifest.json".format(ctx.label.name))
ctx.actions.write(
output = manifest,
content = json.encode_indent(manifest_data, indent = " " * 4) + "\n",
)

inputs = depset(
[ctx.file.template, manifest] + all_subst_checks.values() + all_define_checks.values(),
)

# Process inlines: collect files and create mappings
inline_files = []
Expand All @@ -55,21 +86,11 @@ def _autoconf_hdr_impl(ctx):

inputs = depset(inline_files, transitive = [inputs])

# Pass all individual results files directly to resolver (it merges internally)
# Include both defaults and transitive checks so resolver can merge them
# Use separate flags for each bucket
args = ctx.actions.args()
args.use_param_file("@%s", use_always = True)
args.set_param_file_format("multiline")

# Add define results
for results_file_path in all_define_checks.values():
args.add("--define-result", results_file_path)

# Add subst results
for results_file_path in all_subst_checks.values():
args.add("--subst-result", results_file_path)

args.add("--manifest", manifest)
args.add("--output", ctx.outputs.out)
args.add("--template", ctx.file.template)
args.add("--mode", ctx.attr.mode)
Expand Down
2 changes: 2 additions & 0 deletions autoconf/autoconf_toolchain.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def _autoconf_toolchain_impl(ctx):
cache = direct_results["cache"],
define = direct_results["define"],
subst = direct_results["subst"],
unquoted_defines = direct_results["unquoted_defines"],
)

return [
Expand All @@ -43,6 +44,7 @@ def _autoconf_toolchain_impl(ctx):
cache = dep_results["cache"],
define = dep_results["define"],
subst = dep_results["subst"],
unquoted_defines = dep_results["unquoted_defines"],
defaults_by_label = defaults_by_label,
),
),
Expand Down
23 changes: 22 additions & 1 deletion autoconf/cc_autoconf_info.bzl
Original file line number Diff line number Diff line change
@@ -1,8 +1,29 @@
"""# CcAutoconfInfo"""
"""# CcAutoconfInfo

Public API for external rules that produce autoconf-compatible check results.

The ``CcAutoconfInfo`` provider constructor accepts defaults for every field
except ``owner``, so callers only need to supply the fields they care about:

```python
load("@rules_cc_autoconf//autoconf:cc_autoconf_info.bzl",
"CcAutoconfInfo", "encode_result")

def _my_rule_impl(ctx):
result = ctx.actions.declare_file("{}/MY_DEFINE.result.json".format(ctx.label.name))
ctx.actions.write(output = result, content = encode_result("hello"))
return [CcAutoconfInfo(owner = ctx.label, define_results = {"MY_DEFINE": result})]
```
"""

load(
"//autoconf/private:autoconf_config.bzl",
_encode_result = "encode_result",
)
load(
"//autoconf/private:providers.bzl",
_CcAutoconfInfo = "CcAutoconfInfo",
)

CcAutoconfInfo = _CcAutoconfInfo
encode_result = _encode_result
5 changes: 2 additions & 3 deletions autoconf/macros/AC_C_RESTRICT/restrict.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ and a dedicated resolver tool to combine the results.
"""

load("@rules_cc//cc:find_cc_toolchain.bzl", "use_cc_toolchain")
load("//autoconf:cc_autoconf_info.bzl", "CcAutoconfInfo")
load(
"//autoconf/private:autoconf_config.bzl",
"create_config_dict",
"get_cc_toolchain_info",
"get_environment_variables",
"write_config_json",
)
load("//autoconf/private:providers.bzl", "CcAutoconfInfo")

# Test code templates for each keyword variant.
# Each is a minimal C program that uses the keyword in a function signature.
Expand Down Expand Up @@ -127,10 +127,9 @@ def _ac_c_restrict_impl(ctx):
return [
CcAutoconfInfo(
owner = ctx.label,
deps = depset(),
cache_results = {"restrict": restrict_result},
define_results = {"restrict": restrict_result},
subst_results = {},
unquoted_defines = ["restrict"],
),
DefaultInfo(files = depset([restrict_result])),
OutputGroupInfo(
Expand Down
32 changes: 8 additions & 24 deletions autoconf/macros/AC_C_RESTRICT/restrict_resolver.cc
Original file line number Diff line number Diff line change
Expand Up @@ -215,17 +215,12 @@ std::optional<bool> read_check_success(const std::string& path) {
return std::nullopt;
}

// The result file has one top-level key (the cache variable name)
// with an object containing "success": true/false.
auto it = j.begin();
const nlohmann::json& result = it.value();

if (!result.contains("success") || !result["success"].is_boolean()) {
if (!j.contains("success") || !j["success"].is_boolean()) {
std::cerr << "Error: missing 'success' field in: " << path << std::endl;
return std::nullopt;
}

return result["success"].get<bool>();
return j["success"].get<bool>();
}

/**
Expand All @@ -243,31 +238,20 @@ std::optional<bool> read_check_success(const std::string& path) {
*/
int write_result(const std::string& path,
const std::optional<std::string>& value, bool success) {
nlohmann::json result_obj;
nlohmann::json j;

if (value.has_value()) {
if (value->empty()) {
// Empty string: renders as #define restrict /**/
result_obj["value"] = "";
j["value"] = "";
} else {
// Keyword alias: renders as #define restrict <value>
result_obj["value"] = *value;
j["value"] = *value;
}
} else {
// No define needed: keyword works natively.
// Write null value so the define is not emitted.
result_obj["value"] = nullptr;
j["value"] = nullptr;
}

result_obj["success"] = success;
result_obj["is_define"] = true;
result_obj["is_subst"] = false;
result_obj["type"] = "compile";
result_obj["define"] = "restrict";
result_obj["unquote"] = true;

nlohmann::json j;
j["restrict"] = result_obj;
j["success"] = success;
j["type"] = "compile";

std::ofstream out(path);
if (!out.is_open()) {
Expand Down
75 changes: 15 additions & 60 deletions autoconf/package_info.bzl
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
"""# package_info"""

load("//autoconf/private:providers.bzl", "CcAutoconfInfo")
load(
":cc_autoconf_info.bzl",
"CcAutoconfInfo",
"encode_result",
)

_RUNNER_SOURCES = [
"PACKAGE_NAME",
Expand Down Expand Up @@ -84,60 +88,31 @@ def _package_info_impl(ctx):
if source not in _RUNNER_SOURCES:
ctx.actions.write(
output = extra_results[key],
content = json.encode_indent({
key: {
"success": True,
"value": json.encode(starlark_alias_values[source]),
},
}, indent = " " * 4) + "\n",
content = encode_result(starlark_alias_values[source]),
)

else:
# Write JSON files in check result format for PACKAGE_NAME
# Use regular string (not json.encode) so it goes through .dump() in check.cc
ctx.actions.write(
output = results["PACKAGE_NAME"],
content = json.encode_indent({
"PACKAGE_NAME": {
"success": True,
"value": json.encode(ctx.attr.package_name),
},
}, indent = " " * 4) + "\n",
content = encode_result(ctx.attr.package_name),
)

# Write JSON files in check result format for PACKAGE_VERSION
ctx.actions.write(
output = results["PACKAGE_VERSION"],
content = json.encode_indent({
"PACKAGE_VERSION": {
"success": True,
"value": json.encode(ctx.attr.package_version),
},
}, indent = " " * 4) + "\n",
content = encode_result(ctx.attr.package_version),
)

# Write PACKAGE_STRING as "package_name package_version"
package_string = ctx.attr.package_name + " " + ctx.attr.package_version
ctx.actions.write(
output = results["PACKAGE_STRING"],
content = json.encode_indent({
"PACKAGE_STRING": {
"success": True,
"value": json.encode(package_string),
},
}, indent = " " * 4) + "\n",
content = encode_result(package_string),
)

ctx.actions.write(
output = results["PACKAGE_TARNAME"],
content = json.encode_indent({
"PACKAGE_TARNAME": {
"success": True,
"value": json.encode(
ctx.attr.package_tarname if ctx.attr.package_tarname else ctx.attr.package_name,
),
},
}, indent = " " * 4) + "\n",
content = encode_result(
ctx.attr.package_tarname if ctx.attr.package_tarname else ctx.attr.package_name,
),
)

all_values = {
Expand All @@ -151,43 +126,23 @@ def _package_info_impl(ctx):
for key, source in ctx.attr.aliases.items():
ctx.actions.write(
output = extra_results[key],
content = json.encode_indent({
key: {
"success": True,
"value": json.encode(all_values[source]),
},
}, indent = " " * 4) + "\n",
content = encode_result(all_values[source]),
)

ctx.actions.write(
output = results["PACKAGE_BUGREPORT"],
content = json.encode_indent({
"PACKAGE_BUGREPORT": {
"success": True,
"value": json.encode(ctx.attr.package_bugreport),
},
}, indent = " " * 4) + "\n",
content = encode_result(ctx.attr.package_bugreport),
)

ctx.actions.write(
output = results["PACKAGE_URL"],
content = json.encode_indent({
"PACKAGE_URL": {
"success": True,
"value": json.encode(ctx.attr.package_url),
},
}, indent = " " * 4) + "\n",
content = encode_result(ctx.attr.package_url),
)

# Package info creates defines (for config.h), so put them in define_results
# They're not cache variables or subst values
return [
CcAutoconfInfo(
owner = ctx.label,
deps = depset(),
cache_results = {},
define_results = results | extra_results,
subst_results = {},
),
]

Expand Down
Loading
Loading