Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 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: 0 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,6 @@ jobs:
- name: Run presubmit script
run: |
python run_presubmit.py \
--xlsynth-tools $(pwd)/dependencies \
--xlsynth-driver-dir $(dirname "$(which xlsynth-driver)") \
--dslx-path dependencies/dslx_stdlib

dslx_ci_py36:
Expand Down Expand Up @@ -264,6 +262,4 @@ jobs:
run: |
source $HOME/.cargo/env
python3.6 run_presubmit.py \
--xlsynth-tools $(pwd)/dependencies \
--xlsynth-driver-dir $(dirname "$(which xlsynth-driver)") \
--dslx-path dependencies/dslx_stdlib
93 changes: 93 additions & 0 deletions BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
load("@rules_python//python:defs.bzl", "py_test")

py_test(
name = "make_env_helpers_test",
srcs = ["make_env_helpers_test.py"],
Expand All @@ -7,3 +9,94 @@ py_test(
"make_env_helpers.py",
],
)

py_test(
name = "env_helpers_test",
srcs = [
"env_helpers.py",
"env_helpers_test.py",
],
)

py_test(
name = "artifact_resolution_test",
srcs = [
"artifact_resolution_test.py",
"materialize_xls_bundle.py",
],
)

py_test(
name = "download_release_test",
srcs = [
"download_release.py",
"download_release_test.py",
],
)

genrule(
name = "stdlib_location_probe",
srcs = ["@rules_xlsynth_selftest_xls//:dslx_stdlib"],
outs = ["stdlib_location.txt"],
cmd = "printf '%s\\n' '$(location @rules_xlsynth_selftest_xls//:dslx_stdlib)' > $@",
)

genrule(
name = "bundle_alias_probe",
srcs = ["@rules_xlsynth_selftest_xls"],
outs = ["bundle_alias_locations.txt"],
cmd = "printf '%s\\n' '$(locations @rules_xlsynth_selftest_xls//:rules_xlsynth_selftest_xls)' > $@",
)

genrule(
name = "xlsynth_sys_runtime_probe",
srcs = ["@rules_xlsynth_selftest_xls//:xlsynth_sys_runtime_files"],
outs = ["xlsynth_sys_runtime_locations.txt"],
cmd = "printf '%s\\n' '$(locations @rules_xlsynth_selftest_xls//:xlsynth_sys_runtime_files)' > $@",
)

genrule(
name = "xlsynth_sys_dep_probe",
srcs = ["@rules_xlsynth_selftest_xls//:xlsynth_sys_dep"],
outs = ["xlsynth_sys_dep_locations.txt"],
cmd = "printf '%s\\n' '$(locations @rules_xlsynth_selftest_xls//:xlsynth_sys_dep)' > $@",
)

genrule(
name = "xlsynth_sys_artifact_config_probe",
srcs = ["@rules_xlsynth_selftest_xls//:xlsynth_sys_artifact_config"],
outs = ["xlsynth_sys_artifact_config_location.txt"],
cmd = "printf '%s\\n' '$(location @rules_xlsynth_selftest_xls//:xlsynth_sys_artifact_config)' > $@",
)

genrule(
name = "xlsynth_sys_legacy_inputs_probe",
srcs = [
"@rules_xlsynth_selftest_xls//:xlsynth_sys_legacy_dso",
"@rules_xlsynth_selftest_xls//:xlsynth_sys_legacy_stdlib",
],
outs = ["xlsynth_sys_legacy_input_locations.txt"],
cmd = "printf '%s\\n' '$(locations @rules_xlsynth_selftest_xls//:xlsynth_sys_legacy_dso)' '$(locations @rules_xlsynth_selftest_xls//:xlsynth_sys_legacy_stdlib)' > $@",
)

py_test(
name = "external_bundle_exports_test",
srcs = ["external_bundle_exports_test.py"],
data = [
":bundle_alias_probe",
":stdlib_location_probe",
":xlsynth_sys_artifact_config_probe",
":xlsynth_sys_dep_probe",
":xlsynth_sys_legacy_inputs_probe",
":xlsynth_sys_runtime_probe",
"@rules_xlsynth_selftest_xls",
"@rules_xlsynth_selftest_xls//:dslx_stdlib",
"@rules_xlsynth_selftest_xls//:xlsynth_sys_artifact_config",
],
deps = ["@rules_python//python/runfiles"],
)

toolchain_type(
name = "toolchain_type",
visibility = ["//visibility:public"],
)
139 changes: 101 additions & 38 deletions DESIGN.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,101 @@
# Environment Helpers

`env_helpers.py` hosts the Python entry point that Bazel actions use to talk to the xlsynth
toolchain. When the program starts it harvests a handful of `XLSYNTH_*` variables from the
action environment. The values drive two behaviours: building a temporary `toolchain.toml` file
for driver invocations and deriving additional command-line flags for individual tools. Regular
strings such as `XLSYNTH_GATE_FORMAT` become TOML string fields, while boolean variables like
`XLSYNTH_USE_SYSTEM_VERILOG` are validated and converted into `true` or `false`. For dslx tools
the helper injects the path to the bundled standard library and threads through optional warning
and type-inference settings. The module exposes two subcommands. `driver` shells out to the
`xlsynth-driver` binary, passing the generated TOML file and forwarding any extra user
arguments. `tool` directly executes a requested binary from the downloaded toolset after
pre-pending any extra flags determined from the environment.

# Generating the Bazel Helper

`make_env_helpers.py` keeps the Starlark side of the repository in sync with the Python runner.
The script reads `env_helpers.py`, wraps the source in a Starlark function called
`python_runner_source`, and writes the result to `env_helpers.bzl`. Embedding the literal Python
string this way lets each Bazel action materialise the runner directly as a declared tool rather
than depending on a separate source file target (we don't want our Python runner becoming a
source file dependency of all the rules written by users), which gives hermeticity guarantees
about the helper version used inside the sandbox. The docstring embedded into that function
documents the runner’s responsibilities so that Bazel authors do not need to open the Python
implementation to understand it. A unit test asserts that the generated file matches the
checked-in version, so running `python make_env_helpers.py` is the required regeneration step
when the runner changes.

# Bazel Integration Path

Many Starlark rules load `python_runner_source` and materialise the runner inside the action
sandbox. Each rule writes the helper script to a temporary output, adds it to the action’s tool
inputs, and then calls it with either the `driver` or `tool` subcommand depending on the
workflow. For example, `dslx_to_ir.bzl` composes the runner with `driver dslx2ir` to build
intermediate representations, then calls `driver ir2opt` for optimisation passes. Because every
action invokes the same runner binary, rule authors can rely on environment variables (for
custom DSLX search paths, enabling warnings, or toggling SystemVerilog emission) to behave
consistently across all tool stages.
# Workspace toolchain design

`rules_xlsynth` now exposes one public XLS artifact-selection surface: the
`xls` module extension. A Bazel workspace chooses one or more named bundles in
`MODULE.bazel`, publishes them with `use_repo(...)`, and registers one default
bundle with `register_toolchains("@<name>//:all")`. Public artifact selection
no longer lives in `.bazelrc` `@rules_xlsynth//config:{driver_path,tools_path,runtime_library_path,dslx_stdlib_path}`
flags.

## Bundle repos and exported targets

Each `xls.toolchain(...)` call materializes a repo that contains the selected
tool binaries, the DSLX stdlib tree, the matching `xlsynth-driver`, and the
matching `libxls` shared library. That repo exports:

- `@<name>//:all`
- `@<name>//:bundle`
- `@<name>//:libxls`
- `@<name>//:libxls_link`
- `@<name>//:dslx_stdlib`
- `@<name>//:xlsynth_sys_artifact_config`
- `@<name>//:xlsynth_sys_legacy_stdlib`
- `@<name>//:xlsynth_sys_legacy_dso`
- `@<name>//:xlsynth_sys_dep`
- `@<name>//:xlsynth_sys_runtime_files`
- `@<name>//:xlsynth_sys_link_dep`

The `xlsynth_sys_*` exports are the intended downstream contract for
`rules_rust` `crate_extension.annotation(...)` wiring. The preferred modern
shape is `build_script_data` / `build_script_env` for the build-script
contract, plus `deps = ["@<name>//:xlsynth_sys_dep"]` for the combined
runtime-plus-link contract. The compatibility exports
`xlsynth_sys_runtime_files` and `xlsynth_sys_link_dep` remain available for
callers that still spell those phases separately. This lets root `MODULE.bazel`
files choose only a bundle and a build-script mode instead of coupling to
generic bundle internals.

`artifact_source` controls how those artifacts are resolved:

- `auto` probes a consumer-owned installed layout and otherwise downloads the
release artifacts.
- `installed_only` requires the matching installed layout.
- `download_only` always downloads the release artifacts.
- `local_paths` uses explicit local paths and is the documented escape hatch
for `/tmp/xls-local-dev/` style setups.

For the installed-layout modes, the provider derives the concrete paths from
the toolchain declaration instead of hard-coding a repository-global install
root: `<installed_tools_root_prefix>/v<xls_version>` for the tools tree and
`<installed_driver_root_prefix>/<xlsynth_driver_version>/bin/xlsynth-driver`
for the driver binary. The provider owns the version-derived suffixes; the
consumer workspace owns the root prefixes.

## Default bundles and explicit overrides

Most rules use the registered default workspace bundle through normal Bazel
toolchain resolution. Supported DSLX rules can opt into a named bundle with
`xls_bundle = "@<name>//:bundle"`. That override changes only the artifact
bundle. The existing behavior settings - for example `dslx_path`, warnings,
`gate_format`, `assert_format`, `use_system_verilog`, and
`add_invariant_assertions` - still come from the registered toolchain.

## Runner and toolchain TOML

`env_helpers.py` hosts the Python entry point that Bazel actions use to talk to
the xlsynth toolchain. Bazel rules materialize a per-action
`xlsynth-toolchain.toml` file from the selected bundle plus any rule-level
behavior overrides, then pass that declared input to the runner. The runner
exposes two subcommands: `driver` shells out to the configured
`xlsynth-driver` binary with `--toolchain=<path>`, while `tool` reads the same
TOML file and derives the extra DSLX flags needed by direct tool invocations
such as `dslx_interpreter_main` or `typecheck_main`.

The helper uses the selected `libxls` file path directly and derives the
runtime library directory from `dirname(libxls_path)`, so users no longer need
to configure a separate runtime-library path. The old artifact-path build
settings are deleted; artifact selection is bundle-only.

## Generating the Bazel helper

`make_env_helpers.py` keeps the Starlark side of the repository in sync with
the Python runner. The script reads `env_helpers.py`, wraps the source in a
Starlark function called `python_runner_source`, and writes the result to
`env_helpers.bzl`. Embedding the literal Python string this way lets each Bazel
action materialize the runner directly as a declared tool rather than depending
on a separate source file target, which gives hermeticity guarantees about the
helper version used inside the sandbox. A unit test asserts that the generated
file matches the checked-in version, so running `python make_env_helpers.py` is
the required regeneration step when the runner changes.

## Bazel integration path

Many Starlark rules load `python_runner_source` and materialize the runner
inside the action sandbox. Each rule writes the helper script to a temporary
output, writes a declared TOML file for the configured toolchain, and then
calls the helper with either the `driver` or `tool` subcommand depending on the
workflow. For example, `dslx_to_ir.bzl` composes the runner with
`driver dslx2ir` to build intermediate representations, then calls
`driver ir2opt` for optimization passes. Artifact selection now comes from the
module-extension bundle instead of `XLSYNTH_*` action environment variables or
artifact-path build settings.
17 changes: 17 additions & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
module(name = "rules_xlsynth")

bazel_dep(name = "bazel_skylib", version = "1.6.1")
bazel_dep(name = "rules_cc", version = "0.2.11")
bazel_dep(name = "rules_python", version = "1.0.0")

xls = use_extension("//:extensions.bzl", "xls", dev_dependency = True)

xls.toolchain(
name = "rules_xlsynth_selftest_xls",
xls_version = "0.39.0",
xlsynth_driver_version = "0.36.0",
artifact_source = "download_only",
)

use_repo(xls, "rules_xlsynth_selftest_xls")
register_toolchains(
"@rules_xlsynth_selftest_xls//:all",
dev_dependency = True,
)
Loading
Loading