如何用Bazel构建Qt项目?Ubuntu下Qt 5.15 gcc_64配置疑问
Hey there! Let's tackle your Qt + Bazel questions one by one—since you're just starting out with both Linux and Bazel, I totally get how overwhelming this setup can feel at first.
First, let's clarify: you only need the .so files (shared libraries) from the lib directory—.la files are just helper files generated by libtool, and Bazel doesn't require them. Here's a step-by-step configuration to get you started:
Step 1: Import Qt into your Bazel workspace
Add this to your WORKSPACE file to point Bazel to your Qt installation directory:
local_repository( name = "qt", path = "/absolute/path/to/your/Qt5.15.2/gcc_64", )
Step 2: Define Qt modules with cc_import and cc_library
Create a BUILD file in a directory (like third_party/qt) or directly in your project, and define each Qt module you need. Let's start with Qt Core and Qt Widgets as examples:
For Qt Core:
cc_import( name = "qt_core", shared_library = "@qt//lib:libQt5Core.so.5.15.2", visibility = ["//visibility:public"], ) cc_library( name = "qt_core_lib", hdrs = glob(["@qt//include/QtCore/**/*.h"]), includes = ["@qt//include/QtCore"], defines = [ "QT_CORE_LIB", "QT_NO_DEBUG", # Swap to QT_DEBUG if you're building in debug mode ], deps = [":qt_core"], visibility = ["//visibility:public"], )
For Qt Widgets (depends on Qt Core and Qt Gui):
cc_import( name = "qt_gui", shared_library = "@qt//lib:libQt5Gui.so.5.15.2", visibility = ["//visibility:public"], ) cc_library( name = "qt_gui_lib", hdrs = glob(["@qt//include/QtGui/**/*.h"]), includes = ["@qt//include/QtGui"], defines = ["QT_GUI_LIB"], deps = [":qt_core_lib", ":qt_gui"], visibility = ["//visibility:public"], ) cc_import( name = "qt_widgets", shared_library = "@qt//lib:libQt5Widgets.so.5.15.2", visibility = ["//visibility:public"], ) cc_library( name = "qt_widgets_lib", hdrs = glob(["@qt//include/QtWidgets/**/*.h"]), includes = ["@qt//include/QtWidgets"], defines = ["QT_WIDGETS_LIB"], deps = [":qt_gui_lib", ":qt_widgets"], visibility = ["//visibility:public"], )
Now you can depend on these libraries in your own targets, like:
cc_binary( name = "my_app", srcs = ["main.cpp"], deps = [":qt_widgets_lib"], )
Let's take a typical Qt Creator compile command and break down the parameters beyond macros, headers, and libraries:
g++ -c -pipe -O2 -Wall -W -D_REENTRANT -fPIC -DQT_CORE_LIB -DQT_WIDGETS_LIB -I../myqtproject -I. -I/path/to/Qt5.15.2/gcc_64/include -I/path/to/Qt5.15.2/gcc_64/include/QtWidgets -I/path/to/Qt5.15.2/gcc_64/include/QtCore -I. -I/path/to/Qt5.15.2/gcc_64/mkspecs/linux-g++ -o main.o main.cpp
Here's what the other flags mean:
-c: Only compile the source file into an object file (.o)—don't run the linker yet.-pipe: Use pipes instead of temporary files to pass data between compiler stages, which speeds up builds by reducing disk I/O.-O2: Enable level 2 optimizations—this balances compile time and runtime performance, standard for release builds.-Wall: Turn on most common warning messages to catch potential bugs early.-W: Enable extra (but less critical) warnings beyond-Wallfor stricter code checks.-D_REENTRANT: Define this macro to ensure thread-safe versions of standard library functions are used (essential if your Qt app uses multithreading).-fPIC: Generate position-independent code, which is required for creating shared libraries (and ensures compatibility when linking to shared libraries).-o main.o: Specify the output object file name.-I/path/to/.../mkspecs/linux-g++: Include Qt's platform-specific configuration headers for Linux/GCC, which define platform-specific macros and compiler settings.
Absolutely—you can compile a Qt project into a library (static or dynamic) and use it in Bazel. Here's how to handle the key parts:
Accessing GUI Objects
Dynamic Libraries: Export your GUI classes using the
Q_DECL_EXPORTmacro (Linux doesn't strictly require this, but it's a Qt best practice for cross-platform compatibility). In your library's header:class Q_DECL_EXPORT MyCustomWidget : public QWidget { Q_OBJECT // ... your class code ... };Then in your Bazel project, link against this library and include the header—you can instantiate
MyCustomWidgetjust like any other class.Static Libraries: Make sure you compile the library with
-fPIC(as shown in the Qt Creator command) to ensure it can be linked into other binaries. Bazel will handle linking the static library once you define it in acc_librarytarget.
Using Signals & Slots
Signals and slots work as expected, but you need to make sure Bazel runs Qt's Meta-Object Compiler (moc) on any headers that use Q_OBJECT. Since Bazel doesn't do this automatically, you can create a custom rule to run moc:
def qt_moc(name, srcs): # Generate .moc.cpp files from headers with Q_OBJECT outs = [src[:-2] + "moc.cpp" for src in srcs] native.genrule( name = name, srcs = srcs, outs = outs, cmd = "for src in $(SRCS); do @qt//bin:moc $$src -o $$(basename $$src .h)moc.cpp; done", )
Then use this rule in your library's BUILD file:
qt_moc( name = "my_widget_moc", srcs = ["my_custom_widget.h"], ) cc_library( name = "my_qt_library", srcs = ["my_custom_widget.cpp", ":my_widget_moc"], hdrs = ["my_custom_widget.h"], deps = [ "@qt//third_party/qt:qt_widgets_lib", # Reference your Qt libraries ], defines = ["QT_WIDGETS_LIB"], includes = ["."], visibility = ["//visibility:public"], )
This ensures moc generates the necessary meta-object code, so signals and slots will connect and work normally.
内容的提问来源于stack exchange,提问作者Joe Natal

