bazel: split Qt GUI into separate :openroad-qt target (field-tested respin of #10384)#10465
Conversation
Replace the :platform string_flag (cli/gui) with two cc_binary targets: :openroad (CLI, default — what build-time tool consumers should pull) and :openroad-qt (Qt GUI variant — opt-in for interactive use). The choice between GUI variants becomes a target choice, not a build configuration. `--//:platform=gui //:openroad` continues to work as an additive flag path; :openroad-qt is preferred for ad-hoc GUI builds because it does not invalidate :openroad's cache the way the flag does. Why this change --------------- A skylib string_flag has no --host_ form, so the platform setting is silently dropped under Bazel's exec transition. Rule libraries that pull OpenROAD as a build-time tool (cfg = "exec") therefore got a *different* OpenROAD binary than `bazelisk build //:openroad` produced under a downstream that set `--@openroad//:platform=gui` -- same label, two binaries. With LTO, that is two ~30 min link steps for any consumer whose CI builds both directly and via flow stages. Beyond compile cost, the conceptual problem is target-name overload: @openroad//:openroad should denote one binary. Today, the binary it denotes depends on the consumer's transition. gui_stub: linker correctness fix vs. the closed The-OpenROAD-Project#10384 ------------------------------------------------------ The closed PR The-OpenROAD-Project#10384 left src/stub.cpp inside :gui. With --allow-multiple-definition in effect (LLVM toolchain default), :openroad-qt — which links //src/gui:gui_qt for the real Qt impls AND pulls :gui transitively via :ui modules — ended up with BOTH the stub and gui_qt definitions of Gui::enabled/startGui/initGui/ Painter::getOptions at link time, and the stub silently won. The binary built, but the GUI never opened at runtime. Field testing this branch caught it. Fix: split the stub into a new //src/gui:gui_stub cc_library that only the CLI :openroad binary (and :_openroadpy.so) pulls. :openroad-qt links gui_qt alone for those symbols. A build_test pins :openroad-qt's compilability since no downstream consumer would otherwise exercise it in CI. What changes ------------ - BUILD.bazel: add :openroad-qt cc_binary, split :openroad_lib into CLI (:openroad_lib) + Qt (:openroad_lib_qt) variants compiled with BUILD_GUI=false/true respectively, hoist shared deps into OPENROAD_MAIN_DEPS, add build_test for :openroad-qt. - src/gui/BUILD: factor src/stub.cpp out of :gui into new :gui_stub cc_library (see linker-correctness rationale above). What does not change -------------------- - CMake build (intentional; CMake is on its own deprecation path). - C++ source. The lone BUILD_GUI consumer (OpenRoad::getGUICompileOption() at src/OpenRoad.cc:753-756) is unmodified. - :_openroadpy.so — already CLI-only in practice; now references :openroad_lib (the CLI variant) and :gui_stub. Migration for downstreams ------------------------- - For interactive Qt use: bazelisk build @openroad//:openroad-qt - For build-time tool use (rule libraries pulling OpenROAD via cfg = "exec"): no change — @openroad//:openroad remains the CLI. - --@openroad//:platform=gui still works as an additive flag, but is no longer the recommended path because :openroad-qt does not invalidate :openroad's cache. Closes the gap from the (closed-unmerged) The-OpenROAD-Project#10384 with the field-tested linker fix folded in. Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
There was a problem hiding this comment.
Code Review
This pull request refactors the Bazel build system to better support separate CLI and Qt GUI variants of OpenROAD. Key changes include the introduction of an openroad-qt binary target, the creation of OPENROAD_MAIN_DEPS to share common dependencies, and the isolation of GUI stubs into a standalone gui_stub library to prevent link-time symbol conflicts. Feedback focused on refining the gui_stub target by removing redundant source files and unused dependencies, as well as ensuring consistent dependency naming for the ODB library.
|
clang-tidy review says "All clean, LGTM! 👍" |
The aggregate //src/odb target was removed (The-OpenROAD-Project#10416, "odb: remove the aggregate \"odb\" target and use the fine-grained targets"). gui_stub was the lone holdout depending on the old label. Use the fine-grained //src/odb/src/db target — that's what its sources (stub.cpp and bufferTreeDescriptor.h) actually need for odb/db.h, odb/geom.h, and odb/PtrSetMap.h. Found by local build of :openroad after rebasing onto current master. :openroad-qt was unaffected (does not dep :gui_stub). Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
|
Local build verification:
Initial
|
|
clang-tidy review says "All clean, LGTM! 👍" |
|
CC @QuantamHD has he has the most experience with builds with and without UI. |
|
@hzeller Gemini is right here or should I ignore? |
|
Suckerpunched by openroad changes, will bump and rebase patch downstream, test and update here |
Both were copy-paste leftovers from :gui that gemini-code-assist flagged on The-OpenROAD-Project#10465: - ":tcl" in srcs would cause a multiple-definition error for gui_tcl_inits at link time (already provided by :gui, which :gui_stub deps), and src/stub.cpp doesn't reference the symbol. - "@spdlog" is unused — src/stub.cpp doesn't include any spdlog headers. Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
|
clang-tidy review says "All clean, LGTM! 👍" |
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request refactors the Bazel build configuration to decouple the CLI and Qt GUI variants of OpenROAD. Key changes include the introduction of a dedicated openroad-qt binary target, the splitting of openroad_lib into CLI and Qt-specific versions, and the isolation of GUI stub implementations into a separate :gui_stub library to prevent symbol collisions. A build test has also been added to verify the compilability of the new Qt target. I have no feedback to provide as there were no review comments to assess.
Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
|
@maliberty Mac CI outage: |
|
clang-tidy review says "All clean, LGTM! 👍" |
After the :gui/:gui_stub split, libweb.so has undefined references to gui::Gui::get(), setHeadlessViewer, setChartFactory, BufferTree, etc. The :openroad and :_openroadpy.so binaries already pull in //src/gui:gui_stub explicitly to satisfy those; the cc_test targets in src/web/test/BUILD did not, so all eight of them (glyph_cache_test, snap_test, save_image_test, save_report_test, clock_tree_report_test, request_handler_test, tile_generator_test, debug_graphics_test) failed to link with --no-allow-shlib-undefined. Add //src/gui:gui_stub to each cc_test's deps. The Qt variant is not affected because no test target links //src/gui:gui_qt. Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
|
clang-tidy review says "All clean, LGTM! 👍" |
…rmp/rsz
Same fix pattern as the prior //src/web/test commit: after the
:gui/:gui_stub split, libgui.so has undefined references that the
test binaries must resolve themselves. Add //src/gui:gui_stub to
the 24 cc_test targets that transitively link libgui.so but did not
already pull in the stub:
src/cts/test:cts_unittest
src/cut/test:CutGTests, :cut_abc_test
src/dbSta/test:dbsta_unittest, :test_read_verilog, :test_write_verilog
src/gpl/test:mbff_test
src/mpl/test:mpl_block_macro_channels_unittest
src/odb/test/cpp:TestSwapMaster, :TestSwapMasterUnusedPort,
:TestWriteReadDbHier
src/rmp/test:RmpGTests, :rmp_abc_unittest
src/rsz/test:TestBufRem1, :TestBufferRemoval2, :TestBufferRemoval3,
:TestInsertBuffer, :TestNestedJournal, :TestResizer, :TestResizerMt,
:rsz_buffer_removal, :rsz_buffer_removal2, :rsz_buffer_removal3,
:rsz_insert_buffer
bazelisk test --keep_going //src/... now passes 1586/1586.
Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
|
I'll review this as it is cross-cutting. |
GlobalRouter stored gui::HeatMapSourceHandle members directly, which pulled gui symbols into every consumer of :grt and forced downstream tests to link //src/gui:gui_stub. Repurpose the existing-but-unused AbstractRoutingCongestionDataSource into a single virtual void invalidate(). Store unique_ptr<AbstractRoutingCongestionDataSource> in GlobalRouter. Add a HeatMapHandleAdapter in :ui that wraps the gui handle and forwards invalidate() -> invalidateInstances(). Drop #include "gui/heatMap.h" from GlobalRouter.cpp and the gui forward-decl from GlobalRouter.h. Pattern matches AbstractFastRouteRenderer / AbstractGrouteRenderer: abstract base in :grt, concrete gui-aware adapter in :ui. CMake: move gui_heatmap_core from grt_lib to the swig grt target. Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
:gpl was a monolith that compiled graphicsImpl.cpp (gui::Gui, gui::Painter, gui::Chart) and MakeReplace.cpp (Tcl + gui factory) directly, plus the swig/tcl glue. As a result :gpl pulled gui symbols into every consumer and forced tests to link gui_stub. Mirror the structure already used by :dpl, :grt, :mpl: split out a :ui target containing MakeReplace.cpp, graphicsImpl.cpp/h, swig and tcl rules, deps on //src/gui and //:ord. Drop gui/tcl/ord from :gpl deps. Add :gpl_private_hdrs (dpl pattern) for the five headers shared between :gpl and :ui: nesterovBase.h, nesterovPlace.h, placerBase.h, point.h, routeBase.h. Both targets dep it; no source duplication. Top-level BUILD.bazel adds //src/gpl:ui to OPENROAD_LIBRARY_DEPS and to :_openroadpy.so deps, matching how every other module's :ui is wired in. CMake already split gpl_lib (core, no gui) from gpl (swig, gui), so no CMake change needed. Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
No source under src/par/ references any gui:: symbol or includes any gui/ header. The dep was inherited from older code and was the only reason //src/gui leaked into //src/mpl/test:mpl_block_macro_channels_unittest via :mpl -> :par. Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Revert the workaround added in 69e9a3b. With :grt and :gpl decoupled from gui (prior commits) and the stale par->gui dep removed, none of these tests transitively need gui symbols any more. Affected targets: src/cts/test:cts_unittest src/cut/test:CutGTests, :cut_abc_test src/dbSta/test:dbsta_unittest, :test_read_verilog, :test_write_verilog src/gpl/test:mbff_test src/mpl/test:mpl_block_macro_channels_unittest src/odb/test/cpp:TestSwapMaster, :TestSwapMasterUnusedPort, :TestWriteReadDbHier src/rmp/test:RmpGTests, :rmp_abc_unittest src/rsz/test:TestBufRem1, :TestBufferRemoval2, :TestBufferRemoval3, :TestInsertBuffer, :TestNestedJournal, :TestResizer, :TestResizerMt, :rsz_buffer_removal, :rsz_buffer_removal2, :rsz_buffer_removal3, :rsz_insert_buffer All 24 build and pass without :gui_stub. Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
|
Fixed the residual gui dependencies rather than sprinkle more gui dependencies around. |
|
@maliberty needs a tidy |
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
The clang-tidy CI action lints every changed file including headers, but HeatMapHandleAdapter.h had no compile_commands.json entry (only TUs do), so clang-tidy ran with no -I flags and failed to resolve gui/heatMap.h. The adapter has a single user; move the class into MakeGlobalRouter.cpp and delete the header. Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
|
clang-tidy review says "All clean, LGTM! 👍" |
Add gui_descriptors to TEST_LIBS so every test in src/web/test/cpp picks up the gui/include directory (web links gui_descriptors PRIVATE, so the include path didn't propagate to consumers). Also register the three tests that existed in Bazel but not in CMake: TestClockTreeReport, TestSaveImage, TestSnap. Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
|
clang-tidy review says "All clean, LGTM! 👍" |
d088e22
into
The-OpenROAD-Project:master
|
😌 |
Summary
Respin of the closed-unmerged #10384, with a linker-correctness bugfix that field testing surfaced. Adds a dedicated
:openroad-qtcc_binary so the choice between CLI and Qt becomes a target choice, not a build configuration.:openroad-qtcc_binary alongside:openroad— pick the one you want, no flag flip needed.--//:platform=gui //:openroadcontinues to work as an additive flag (no removal);:openroad-qtis just preferred because it doesn't invalidate:openroad's cache.//src/gui:gui_stubsplitssrc/stub.cppout of:gui. Linked only by CLI:openroad/:_openroadpy.so. This is the bugfix vs. add an openroad-qt as an alternative to GUI Qt config to reduce build times #10384.Why the gui_stub split (vs. #10384)
#10384 left
src/stub.cppinside:gui. With--allow-multiple-definitionin effect (LLVM toolchain default),:openroad-qtended up linking both://src/gui:gui_qt, and:gui(pulled transitively via:uimodules)…for symbols like
Gui::enabled,startGui,initGui,Painter::getOptions. The stub silently won — binary built, GUI never opened at runtime. Splitting the stub into its own cc_library, depped only by the CLI binary, makes the link unambiguous.Caught while field-testing the branch downstream. The rationale comment is in
src/gui/BUILDso the next person doesn't re-merge them.Why
:openroad-qt(recap from #10384)A skylib
string_flaghas no--host_form, so the platform setting is silently dropped under Bazel's exec transition. Rule libraries that pull OpenROAD as a build-time tool (cfg = "exec") got a different binary thanbazelisk build //:openroadunder a downstream that set--@openroad//:platform=gui— same label, two binaries, two ~30min LTO links per consumer.After this change,
@openroad//:openroaddenotes one binary regardless of who pulls it or in what configuration;@openroad//:openroad-qtis the opt-in Qt variant.Migration
bazelisk build @openroad//:openroad-qtcfg = "exec"): no change.--@openroad//:platform=guistill works but is no longer recommended.Test plan
bazelisk build //:openroad(default path, what tool consumers pull)bazelisk test //:openroad_qt_build_test(pins:openroad-qtcompilability):openroad-qtdirectlybazelisk run //:openroad-qt -- -guiopens the Qt GUI (this is what regressed under add an openroad-qt as an alternative to GUI Qt config to reduce build times #10384)bazelisk run //:openroad -- <existing-flow>unchanged