From 5aa6e5e0cbb626e8ee51d8e59d5de185434420e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Harboe?= Date: Wed, 13 May 2026 07:28:25 +0200 Subject: [PATCH 1/2] bazel: build xcb-util-cursor from source in qt-bazel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 #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 --- MODULE.bazel | 15 ++++++ bazel/qt-bazel-xcb-cursor-from-source.patch | 59 +++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 bazel/qt-bazel-xcb-cursor-from-source.patch diff --git a/MODULE.bazel b/MODULE.bazel index 939e5db8a9b..32e3529f443 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -80,6 +80,21 @@ bazel_dep(name = "qt-bazel") git_override( module_name = "qt-bazel", commit = "886104974c2fd72439f2c33b5deebf0fe4649df7", + # Build xcb-util-cursor from source so the Qt xcb platform plugin + # doesn't depend on the host having libxcb-cursor0 installed. + # qt-bazel upstream ships it as system_provided = True; we replace + # that with a static cc_library compiled from xcb-util-cursor 0.1.5. + patch_cmds = [ + # Retry + --fail so transient xorg.freedesktop.org hiccups don't + # 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", + ], + patch_strip = 1, + patches = [ + "//bazel:qt-bazel-xcb-cursor-from-source.patch", + ], remote = "https://github.com/The-OpenROAD-Project/qt_bazel_prebuilts", ) diff --git a/bazel/qt-bazel-xcb-cursor-from-source.patch b/bazel/qt-bazel-xcb-cursor-from-source.patch new file mode 100644 index 00000000000..008858fa568 --- /dev/null +++ b/bazel/qt-bazel-xcb-cursor-from-source.patch @@ -0,0 +1,59 @@ +diff --git a/interface_libs/xcb/BUILD.bazel b/interface_libs/xcb/BUILD.bazel +index c1c5b6b6..3a659170 100644 +--- a/interface_libs/xcb/BUILD.bazel ++++ b/interface_libs/xcb/BUILD.bazel +@@ -67,10 +67,41 @@ cc_import( + system_provided = True, + ) + +-cc_import( +- name = "xcb_cursor_ifso", +- interface_library = "libxcb-cursor.ifso", +- system_provided = True, ++# Headers-only target for xcb utility headers. Used by :xcb_cursor to ++# get xcb_renderutil.h, xcb_image.h, render.h etc. without depending on ++# the full :xcb target (which would create a circular dependency). ++cc_library( ++ name = "xcb_hdrs", ++ hdrs = glob(["xcb/*.h"]), ++ includes = ["."], ++ strip_include_prefix = ".", ++) ++ ++# Build xcb-util-cursor from source instead of relying on a system-provided ++# shared library. The source is downloaded into cursor/ by patch_cmds in ++# the consumer's MODULE.bazel. This makes the Qt xcb platform plugin ++# self-contained — no host libxcb-cursor0 package required. ++cc_library( ++ name = "xcb_cursor", ++ srcs = [ ++ "cursor/cursor.c", ++ "cursor/cursor.h", ++ "cursor/load_cursor.c", ++ "cursor/parse_cursor_file.c", ++ "cursor/shape_to_id.c", ++ ], ++ hdrs = ["cursor/xcb_cursor.h"], ++ copts = [ ++ # asprintf() is a GNU extension; glibc gates it behind _GNU_SOURCE. ++ "-D_GNU_SOURCE", ++ "-DXCURSORPATH='\"~/.icons:/usr/share/icons:/usr/share/pixmaps:/usr/X11R6/lib/X11/icons\"'", ++ ], ++ include_prefix = "xcb", ++ strip_include_prefix = "cursor", ++ deps = [ ++ ":xcb_hdrs", ++ "@libxcb", ++ ], + ) + + cc_import( +@@ -94,7 +125,7 @@ cc_library( + deps = select({ + "@platforms//cpu:aarch64": [], + "//conditions:default": [ +- ":xcb_cursor_ifso", ++ ":xcb_cursor", + ":xcb_icccm_ifso", + ":xcb_ifso", + ":xcb_image_ifso", From 172448eb74cff69891bbe49e14839ff96a563c38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Harboe?= Date: Wed, 13 May 2026 07:29:22 +0200 Subject: [PATCH 2/2] bazel: make GUI the default build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 #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 --- .github/workflows/github-actions-macos-bazel.yml | 2 +- BUILD.bazel | 2 +- bazel/Dockerfile | 14 ++++++++++++++ docs/user/Build.md | 10 +++++----- src/gui/README.md | 2 +- 5 files changed, 22 insertions(+), 8 deletions(-) diff --git a/.github/workflows/github-actions-macos-bazel.yml b/.github/workflows/github-actions-macos-bazel.yml index 926ab3a7c15..7829c1d6f51 100644 --- a/.github/workflows/github-actions-macos-bazel.yml +++ b/.github/workflows/github-actions-macos-bazel.yml @@ -38,7 +38,7 @@ jobs: bazelisk build \ --disk_cache=~/.cache/bazel-disk-cache \ --experimental_disk_cache_gc_max_size=5G \ - --//:platform=gui //:openroad + //:openroad # 2. SAVE: Only executes if this is a push/merge directly to the master branch - name: Save Bazel Disk Cache diff --git a/BUILD.bazel b/BUILD.bazel index 7322e6027bb..cafcdc6da68 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -48,7 +48,7 @@ exports_files([ string_flag( name = "platform", - build_setting_default = "cli", + build_setting_default = "gui", values = [ "cli", "gui", diff --git a/bazel/Dockerfile b/bazel/Dockerfile index bbe40e2840c..efa4f460e79 100644 --- a/bazel/Dockerfile +++ b/bazel/Dockerfile @@ -25,6 +25,20 @@ RUN apt-get -y update \ docker-buildx-plugin \ docker-ce \ docker-ce-cli \ + libdbus-1-3 \ + libfontconfig1 \ + libsm6 \ + libx11-xcb1 \ + libxcb-icccm4 \ + libxcb-keysyms1 \ + libxcb-randr0 \ + libxcb-shape0 \ + libxcb-sync1 \ + libxcb-xfixes0 \ + libxcb-xkb1 \ + libxcb1-dev \ + libxkbcommon-x11-0 \ + libxkbcommon0 \ openjdk-21-jre-headless \ python3 \ python3-yaml \ diff --git a/docs/user/Build.md b/docs/user/Build.md index 60675b30d66..c182ccef59d 100644 --- a/docs/user/Build.md +++ b/docs/user/Build.md @@ -17,23 +17,23 @@ There are three methods for building OpenROAD (in order of recommendation): preb ## Build and install with Bazel -Build OpenROAD with GUI support and install into ../install/OpenROAD/bin +Build OpenROAD and install into ../install/OpenROAD/bin - bazelisk run --//:platform=gui //:install + bazelisk run //:install To install to a custom location, e.g. /tmp/myinstall - bazelisk run --//:platform=gui //:install -- /tmp/myinstall + bazelisk run //:install -- /tmp/myinstall To produce an openroad.tar file with install files - bazelisk build --//:platform=gui //:tarfile + bazelisk build //:tarfile The tarfile is located at bazel-bin/packaging/openroad.tar. To embed the real git version string, add `--config=release`: - bazelisk run --config=release --//:platform=gui //:install + bazelisk run --config=release //:install The install process will install the binary "openroad" and the runfile directory "openroad.runfiles" which contains runtime data needed by the binary. diff --git a/src/gui/README.md b/src/gui/README.md index eabe13f5639..125bbe80886 100644 --- a/src/gui/README.md +++ b/src/gui/README.md @@ -958,7 +958,7 @@ timing groups display the internal clock latency inline: To view this, run the MockArray example and look at reg2reg paths: ``` -bazelisk run --//:platform=gui //test/orfs/mock-array:MockArray_4x4_base_synth gui_synth +bazelisk run //test/orfs/mock-array:MockArray_4x4_base_synth gui_synth ``` ## License