OpenROAD Integration
July 8, 2026 · View on GitHub
OpenROAD is the core place-and-route tool in bazel-orfs. It is built from
source via the @openroad module (declared with git_override in the
root MODULE.bazel). OpenROAD and OpenSTA come from the same source
tree.
Default Configuration
The default orfs.default() points at @openroad//:openroad and
@openroad//src/sta:opensta — no explicit override is needed:
orfs = use_extension("@bazel-orfs//:extension.bzl", "orfs_repositories")
orfs.default()
Root MODULE.bazel requirements
bzlmod only honors git_override from the root module, so every root
module that depends on bazel-orfs must declare the OpenROAD and qt-bazel
overrides. bazelisk run @bazel-orfs//:bump injects these automatically
alongside the bazel-orfs pin:
bazel_dep(name = "openroad")
git_override(
module_name = "openroad",
commit = "<commit-sha>",
init_submodules = True,
remote = "https://github.com/The-OpenROAD-Project/OpenROAD.git",
)
bazel_dep(name = "qt-bazel")
git_override(
module_name = "qt-bazel",
commit = "<commit-sha>",
remote = "https://github.com/The-OpenROAD-Project/qt_bazel_prebuilts",
)
bazel_dep(name = "llvm", version = "0.8.11")
register_toolchains("@llvm//toolchain:all")
The llvm module (hermetic-llvm) provides the C++ toolchain OpenROAD builds
against. OpenROAD registers it only as a dev_dependency, so it does not
propagate to downstream roots — each root building OpenROAD from source must
register @llvm//toolchain:all itself.
GUI Builds
bazel-orfs enables OpenROAD's GUI by default via --@openroad//:platform=gui
in .bazelrc. To disable it (CLI-only mode), override in user.bazelrc:
build --@openroad//:platform=cli
Per-Target Override
The openroad argument can be passed to orfs_flow() to override it for a
specific design, similar to how klayout works on orfs_gds:
load("@bazel-orfs//:openroad.bzl", "orfs_flow")
orfs_flow(
name = "my_design",
openroad = "@openroad//:openroad",
verilog_files = ["my_design.v"],
# ...
)
When not set, it defaults to the global openroad configured in orfs.default().
Using a Locally Installed OpenROAD
To use an OpenROAD binary already installed on your system (e.g. one you built locally):
orfs.default(
openroad = "@bazel-orfs//:openroad",
)
The @bazel-orfs//:openroad wrapper execs whichever openroad binary is
found on the system PATH. For hermetic builds, prefer the source-built
default.
Mock OpenROAD for Testing
For CI and development, a mock openroad binary is provided that exits successfully without running real place-and-route. This is useful for testing the override mechanism without the cost of a real OpenROAD build.
The mock binaries are regular packages within bazel-orfs, so downstream
consumers reference them as @bazel-orfs//mock/openroad/src/bin:openroad.
To use the mock per-target in tests:
orfs_flow(
name = "my_design_mock_openroad",
openroad = "//mock/openroad/src/bin:openroad",
# ...
)
Gotchas
Things that can surprise you when building OpenROAD from source:
-
qt-bazel
git_overridemust be in your rootMODULE.bazel. bzlmod silently ignoresgit_overridefrom non-root modules. If you forget this, you'll get a "module not found" error for qt-bazel. -
First build is slow. OpenROAD pulls in ~30 boost modules, or-tools, tcmalloc, Qt, eigen, swig, and more. Expect 30-60+ minutes for a cold build. Subsequent builds are incremental.
-
You must register the
llvm(hermetic-llvm) toolchain yourself. OpenROAD builds against the BCRllvmmodule (a statically linked, zero-sysroot LLVM), but registers it only as adev_dependency— which bzlmod ignores for non-root modules. So@openroadas a dependency does not bring a toolchain with it; each root building OpenROAD from source must declarebazel_dep(name = "llvm")andregister_toolchains("@llvm//toolchain:all"). -
Dependency version conflicts. OpenROAD may require newer versions of shared dependencies (
rules_cc,rules_shell, etc.) than your project uses. bzlmod's Minimum Version Selection picks the highest declared version, which can cause subtle breakage if APIs changed between versions. -
OpenROAD's remote build cache is not available to downstream users. The cache at
bazel.precisioninno.comis configured in OpenROAD's.bazelrcbut is not accessible from other projects. -
GUI requires
--@openroad//:platform=gui. Without this flag in your.bazelrcor on the command line, OpenROAD builds in CLI-only mode andbazel runtargets that open the GUI will not work.
Future Upstream Improvements
These changes in OpenROAD would improve the experience for downstream users:
-
Hermetic toolchain doesn't propagate to consumers — OpenROAD registers the
llvm(hermetic-llvm) toolchain only as adev_dependency, so every downstream root that builds OpenROAD from source has to re-declarebazel_dep(name = "llvm")+register_toolchains("@llvm//toolchain:all"). A propagating registration (or a documented shared macro) would remove that duplication. -
qt-bazel in BCR — would eliminate the
git_overrideburden; currently every consumer must re-declare it. -
Make more dependencies
dev_dependency— many boost modules,or-tools,tcmalloc,eigen,swigetc. are pulled into every downstream project's dependency graph. Making non-essential-for-API deps intodev_dependencywould reduce the transitive dependency burden. -
Reduce version pinning conflicts — OpenROAD pins specific versions of
rules_cc,rules_shell, etc. that may conflict with downstream projects. -
Remote cache availability — making the build cache accessible to downstream users or publishing pre-built artifacts would dramatically reduce first-build time.
Bumping Versions with //:bump
bazelisk run @bazel-orfs//:bump (or bazelisk run //:bump from within
bazel-orfs) is a single command that updates all version pins. It detects
which project it's running in and does the right thing:
| What it updates | bazel-orfs | OpenROAD | User project |
|---|---|---|---|
| bazel-orfs git commit | — (is self) | yes | yes |
| OpenROAD git commit | yes | — (is self) | yes (if present) |
| ORFS git commit | yes | — | — |
| qt-bazel git commit | yes | — | yes (if present) |
| Non-BCR deps injected | — | — | yes (on first bump) |
Detection works by checking module(name = ...) in MODULE.bazel:
bazel-orfs and openroad are recognized; everything else is treated
as a downstream project.
Testing
CI (fast, uses mock)
# Test the openroad override mechanism (~2.5s, mock openroad)
bazelisk build //test:lb_32x128_mock_openroad_floorplan
Local: test the source-built OpenROAD GUI
# 1. Bump OpenROAD to the latest versions
bazelisk run //:bump
# 2. Open synthesis results in the source-built OpenROAD GUI
# First build is slow (~30-60min), subsequent builds are incremental.
bazelisk run //test:lb_32x128_openroad_gui_synth
This builds OpenROAD from git source with GUI enabled (via
--@openroad//:platform=gui in .bazelrc), runs synthesis, and opens
the results in the OpenROAD GUI. The target is tagged manual so it
won't run in CI.
Other useful commands
# Build just the OpenROAD binary from source
bazelisk build @openroad//:openroad
# Run a flow stage with source-built OpenROAD (no GUI)
bazelisk build //test:lb_32x128_openroad_gui_floorplan