Skip to content

bazel: make GUI the default build#10413

Closed
oharboe wants to merge 2 commits into
The-OpenROAD-Project:masterfrom
oharboe:gui-default-bazel
Closed

bazel: make GUI the default build#10413
oharboe wants to merge 2 commits into
The-OpenROAD-Project:masterfrom
oharboe:gui-default-bazel

Conversation

@oharboe
Copy link
Copy Markdown
Collaborator

@oharboe oharboe commented May 13, 2026

Summary

Flips BUILD.bazel's platform string_flag from
build_setting_default = "cli" to "gui", so
bazelisk build //:openroad now produces the Qt-linked binary
without needing --//:platform=gui on the command line. Users
who specifically want a CLI-only binary can still pass
--//:platform=cli.

Picks up where #8532 left off.

Stacked on #10412

The libxcb-cursor0 runtime blocker reported by @gadfort on
#8532 is fixed by #10412, which builds xcb-util-cursor from
source in qt-bazel. Please merge #10412 first; this PR
will then be a clean single-commit diff against master.

Files changed

  • BUILD.bazel: build_setting_default = "cli""gui".
    Everything else (platform_cli / platform_gui
    config_settings, the select() over //src/gui vs
    //src/gui:gui_qt, :openroad's deps, the standalone
    :openroad-qt target) keeps working — the flag mechanism is
    already in place, we're only changing the picked-by-default
    value.
  • bazel/Dockerfile: add the runtime xcb/X11/Qt libs that the
    Qt-linked binary loads at startup, so bazel test //src/gui/test:supported can exec the binary inside the
    Bazel-CI container. libxcb-cursor0 is intentionally not
    in this list
    — after bazel: build xcb-util-cursor from source in qt-bazel #10412 it is no longer in DT_NEEDED.
    This file is the Bazel CI image consumed by Jenkins; the
    cmake path (root Dockerfile + etc/DependencyInstaller.sh)
    already installs its own xcb deps and is untouched.
  • .github/workflows/github-actions-macos-bazel.yml: drop the
    now-redundant --//:platform=gui flag from the build
    command.
  • docs/user/Build.md: drop the flag from the four bazelisk
    command examples — users should not have to care.
  • src/gui/README.md: same cleanup for the MockArray example.

etc/Build.sh already passes --//:platform=cli /
--//:platform=gui explicitly based on --no-gui and is left
alone (internal script, not user-facing).

Test plan

  • bazelisk build //:openroad (no flag) produces a
    Qt-linked binary; ldd bazel-bin/openroad shows the
    Qt/xcb libraries.
  • bazelisk build --//:platform=cli //:openroad (explicit
    opt-out) still produces a CLI-only binary with no Qt
    deps in ldd.
  • bazel test //src/gui/test:supported passes inside the
    updated bazel/Dockerfile image
    (docker build -f bazel/Dockerfile -t test-bazel-ci .
    locally to reproduce).
  • bazelisk run //:openroad -- -gui launches the GUI on a
    clean machine without manual apt-get install of any
    xcb package (end-to-end check of bazel: build xcb-util-cursor from source in qt-bazel #10412 + this PR).
  • bazelisk build //:openroad-qt still works (separate
    target is untouched).
  • macOS CI workflow goes green with the flag removed.

oharboe added 2 commits May 13, 2026 07:28
The Qt xcb platform plugin currently dlopens libxcb-cursor.so.0
from the host, which means anyone building --//:platform=gui or
:openroad-qt has to apt-install libxcb-cursor0 separately --
reported on PR The-OpenROAD-Project#8532 by gadfort, flagged by maliberty as a
blocker for making GUI the default.

Patch qt-bazel via MODULE.bazel so xcb-util-cursor 0.1.5 is
fetched from xorg.freedesktop.org and compiled into a static
cc_library, replacing the system_provided cc_import. The patch
is ported verbatim from
github.com/The-OpenROAD-Project/bazel-orfs, where it has been
in use for some time.

After this change:
  readelf -d bazel-bin/openroad | grep -i cursor   # nothing

Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
The platform string_flag now defaults to "gui" instead of "cli",
so `bazelisk build //:openroad` produces the Qt-linked binary
without needing `--//:platform=gui` on the command line. Users
who specifically want a CLI-only binary can still pass
`--//:platform=cli`.

Picks up where PR The-OpenROAD-Project#8532 left off; the libxcb-cursor0 blocker
reported there is fixed by the preceding commit which builds
xcb-util-cursor from source in qt-bazel.

bazel/Dockerfile gains the runtime xcb/X11 libs that the
Qt-linked binary loads at startup (so `bazel test
//src/gui/test:supported` can exec it inside the CI container).
libxcb-cursor0 is intentionally not in this list -- it's no
longer in DT_NEEDED.

User-facing docs (docs/user/Build.md, src/gui/README.md) and the
macOS CI workflow drop the now-redundant --//:platform=gui flag.
etc/Build.sh already passes the flag explicitly based on
--no-gui and is left alone.

Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
@github-actions
Copy link
Copy Markdown
Contributor

clang-tidy review says "All clean, LGTM! 👍"

@oharboe
Copy link
Copy Markdown
Collaborator Author

oharboe commented May 13, 2026

@maliberty @hzeller This doesn't get rid of the X dependencies for headless bare bones linux CI distributions, so I think an openroad-qt binary is a better idea.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request changes the default build platform from "cli" to "gui", updating documentation and build flags accordingly. It also introduces a mechanism to build xcb-util-cursor from source within the qt-bazel dependency to avoid host-level library requirements, adding necessary X11/XCB dependencies to the Dockerfile. Feedback includes a recommendation to verify the integrity of the downloaded source using a SHA256 checksum and to use the runtime version of libxcb1 instead of the development package in the Dockerfile to minimize image size.

Comment thread MODULE.bazel
# feed a truncated/HTML response into tar (seen in CI as "xz:
# File format not recognized"). Stage to a file first for a
# clearer error if extraction fails.
"curl -sSfL --retry 5 --retry-all-errors --retry-delay 5 -o xcb-util-cursor-0.1.5.tar.xz https://xorg.freedesktop.org/archive/individual/lib/xcb-util-cursor-0.1.5.tar.xz && tar xJf xcb-util-cursor-0.1.5.tar.xz --strip-components=1 -C interface_libs/xcb xcb-util-cursor-0.1.5/cursor && rm xcb-util-cursor-0.1.5.tar.xz",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-medium medium

The curl command downloads an external dependency without verifying its integrity. This poses a security risk and can lead to non-reproducible builds if the remote file changes or is compromised. It is recommended to verify the SHA256 checksum of the downloaded tarball before extraction.

Suggested change
"curl -sSfL --retry 5 --retry-all-errors --retry-delay 5 -o xcb-util-cursor-0.1.5.tar.xz https://xorg.freedesktop.org/archive/individual/lib/xcb-util-cursor-0.1.5.tar.xz && tar xJf xcb-util-cursor-0.1.5.tar.xz --strip-components=1 -C interface_libs/xcb xcb-util-cursor-0.1.5/cursor && rm xcb-util-cursor-0.1.5.tar.xz",
"curl -sSfL --retry 5 --retry-all-errors --retry-delay 5 -o xcb-util-cursor-0.1.5.tar.xz https://xorg.freedesktop.org/archive/individual/lib/xcb-util-cursor-0.1.5.tar.xz && echo \"28a899f10ada37f1d035605a1ce877a7b5bb03045934197316270cafcca3a987 xcb-util-cursor-0.1.5.tar.xz\" | sha256sum -c && tar xJf xcb-util-cursor-0.1.5.tar.xz --strip-components=1 -C interface_libs/xcb xcb-util-cursor-0.1.5/cursor && rm xcb-util-cursor-0.1.5.tar.xz",

Comment thread bazel/Dockerfile
libxcb-sync1 \
libxcb-xfixes0 \
libxcb-xkb1 \
libxcb1-dev \
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This list appears to be intended for runtime dependencies required to execute the GUI-enabled binary during tests. libxcb1-dev is a development package; the runtime package libxcb1 should be used instead to keep the image size minimal.

      libxcb1 \

@hzeller
Copy link
Copy Markdown
Collaborator

hzeller commented May 13, 2026

Building the default with Qt would be a hassle.

The typical use-case is headless running on servers somewhere that don' t have a graphics adapter, X-libraries etc. (after all, we don't want to have a human in the loop :) ).

save_image is at best the typical 'graphical' thing what would be done headless there (if you say 'it is provided by the webserver' @maliberty , does it mean the webserver needs to be running, occupying a port ? Which would also be inconvenient)

This is what running tests on my machine look like if qt is enabled //src/cgt/test:aes_nangate45

exec ${PAGER:-/usr/bin/less} "$0" || exit 1
Executing tests from //src/cgt/test:aes_nangate45
-----------------------------------------------------------------------------
Traceback (most recent call last):
[...]
  File "/home/hzeller/.cache/bazel/_bazel_hzeller/515c003e8af37d4c8564c2613da4cc17/sandbox/linux-sandbox/31127/execroot/_main/bazel-out/k8-opt/bin/src/cgt/test/aes_nangate45.runfiles/_main/openroadpy.py", line 12, in <module>
    import _openroadpy
ImportError: libX11-xcb.so.1: cannot open shared object file: No such file or directory

@oharboe oharboe closed this May 13, 2026
@maliberty
Copy link
Copy Markdown
Member

Why is occupying a port inconvenient? There is no shortage of them.

@oharboe
Copy link
Copy Markdown
Collaborator Author

oharboe commented May 14, 2026

Why is occupying a port inconvenient? There is no shortage of them.

It made me uneasy to open a port, but I didn't have anything to pin it on, so I aske Gemmini:

Here are several reasons why relying on a webserver/port for headless CLI operations can be inconvenient:

  1. Port Collisions in Concurrent Testing: When running test suites in parallel (e.g., using Bazel, which is highly parallelized, or CI/CD pipelines), tests might try to bind to the same port at the same time. While dynamic port allocation (binding to port 0) can mitigate this, it adds extra logic to fetch and communicate the assigned port back to the client.
  2. Orchestration Overhead (Race Conditions): You have to handle the lifecycle of the web server. You must start the server, wait for it to be fully ready to accept connections before running the client command, and ensure it cleanly tears down when the job finishes.
  3. Zombie Processes & Resource Leaks: If a job or test crashes unexpectedly, the background web server process might be left running. This can leave the port bound (e.g., TIME_WAIT or a blocked socket) and cause subsequent runs on the same machine to fail.
  4. Security & Firewall Restrictions: In locked-down enterprise environments, CI/CD runners, or containerized environments (like Docker or strict sandboxes), binding to local network ports might be blocked by default or require additional network configuration/permissions.
  5. Additional Dependencies: It requires spinning up a networking stack and server framework just to perform what should essentially be a simple local file I/O or standard output operation (like saving an image).

For a developer looking for a fast, hermetic, and predictable headless build/test environment, avoiding network bindings entirely is usually much simpler and more robust.

@maliberty
Copy link
Copy Markdown
Member

maliberty commented May 15, 2026 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants