Currently, I am working on an experiment to support Qt6 via Bazel. My code can be found here.
On Linux with Bazel and GCC9 installed you can test my Qt6 Bazel rules via:
git clone https://github.com/Vertexwahn/rules_qt6
cd rules_qt6
bazel run --config=gcc9 //:Qt6HelloWorld # run Qt6HelloWorld binary
When trying to run Qt6HelloWorld
this error gets reported:
/home/user/.cache/bazel/_bazel_$USER/196a14423fc09522ef7bd657344d1cd0/execroot/Qt6Testbed/bazel- out/k8-fastbuild/bin/Qt6HelloWorld:
error while loading shared libraries: libQt6Network.so.6: cannot open shared object file: No such file or directory
There seem to be a libQt6Network.so
, libQt6Network.so.6
and libQt6Network.so.6.1.0
in Qt6.1.0. If I copy those files to bazel-out/k8-fastbuild/bin
(where the Qt6HelloWorld
binary resides) I still get this error.
Any ideas on how to fix this error? Any ideas on how I can extend my rules to copy over those required libs so Bazel is happy?
This is a late reply, but I just came across your rules trying to do something very similar.
The main issue here seems to be that in your rules you reference libQt*.so
, which are symlinks to the actual libraries. Bazel correctly creates a symlink to those in the runfiles directory (under _solib_k8
) and puts the relative path from the main binary to the paths under _solib_k8
into the binary's RUNPATH
. However, the DT_NEEDED
entries in the binary refer to files ending in .so.6
(probably because that's the SONAME
of the library). Those aren't found in any of the directories, giving you the error above. Here are some details:
$ readelf -d [...]/execroot/Qt6Testbed/bazel-out/k8-fastbuild/bin/Qt6HelloWorld
0x0000000000000001 (NEEDED) Shared library: [libQt6Network.so.6]
0x0000000000000001 (NEEDED) Shared library: [libQt6Qml.so.6]
0x0000000000000001 (NEEDED) Shared library: [libQt6Core.so.6]
0x0000000000000001 (NEEDED) Shared library: [libQt6Gui.so.6]
0x0000000000000001 (NEEDED) Shared library: [libQt6Widgets.so.6]
[...]
0x000000000000001d (RUNPATH) Library runpath: [$ORIGIN/_solib_k8/_U@qt_U6.1.0_Ulinux_Udesktop_Ugcc_U64_S_S_Cqt_Unetwork_Ulinux_Uimport___Ulib:$ORIGIN/_solib_k8/_U@qt_U6.1.0_Ulinux_Udesktop_Ugcc_U64_S_S_Cqt_Uqml_Ulinux_Uimport___Ulib:$ORIGIN/_solib_k8/_U@qt_U6.1.0_Ulinux_Udesktop_Ugcc_U64_S_S_Cqt_Ucore_Ulinux_Uimport___Ulib:$ORIGIN/_solib_k8/_U@qt_U6.1.0_Ulinux_Udesktop_Ugcc_U64_S_S_Cqt_Ugui_Ulinux_Uimport___Ulib:$ORIGIN/_solib_k8/_U@qt_U6.1.0_Ulinux_Udesktop_Ugcc_U64_S_S_Cqt_Uwidgets_Ulinux_Uimport___Uli]
[...]
Examining the first .so
in the first directory on the RUNPATH
, we get this:
readelf -d [...]/execroot/Qt6Testbed/bazel-out/k8-fastbuild/bin/_solib_k8/_U@qt_U6.1.0_Ulinux_Udesktop_Ugcc_U64_S_S_Cqt_Unetwork_Ulinux_Uimport___Ulib/libQt6Network.so
Dynamic section at offset 0x206960 contains 36 entries:
Tag Type Name/Value
[...]
0x000000000000000e (SONAME) Library soname: [libQt6Network.so.6]
[...]
The obvious fix is to use libQt*.so.6
for the cc_import
targets, but then we have to skip the interface_library
argument, since apparently that one must end in .so
. However, I'm not sure what benefit adds cc_import
over cc_library
anyways, at least on Linux. So I would advise using cc_library
and simply glob
something like libQt6Core.so*
.
Once that is fixed, we face the next issue: libicui18n.so.56
is required by at least one of the libQt*.so
libraries, but we didn't provide that yet. Turns out it's required by all of them, so we can simply expand our glob. The result could then look like this:
[
cc_library(
name = "qt_%s_linux_import" % name,
hdrs = [],
srcs = glob([
"lib/lib%s.so*" % library_name,
"lib/libicu*.so*",
]),
target_compatible_with = ["@platforms//os:linux"],
)
for name, include_folder, library_name, _ in QT_LIBRARIES
]
The last remaining issue is about the Qt platform plugin not being found. This can be fixed by providing the entire plugins
directory via data
and set QT_QPA_PLATFORM_PLUGIN_PATH
. The plugins we can put into a filegroup
in qt_6.1.0_linux_desktop_gcc_64.BUILD
filegroup(
name = "plugin_files",
srcs = glob(["plugins/**/*"]),
visibility = ["//visibility:public"],
)
And then in the cc_binary
put this as data
:
cc_binary(
name = "Qt6HelloWorld",
srcs = ["main.cpp"],
deps = [
":qt_core",
":qt_qml",
":qt_widgets",
],
env = select({
"@platforms//os:linux": {
"QT_QPA_PLATFORM_PLUGIN_PATH": "external/qt_6.1.0_linux_desktop_gcc_64/plugins",
},
"@platforms//os:windows": {
# TODO
},
}),
data = select({
"@platforms//os:linux": ["@qt_6.1.0_linux_desktop_gcc_64//:plugin_files"],
"@platforms//os:windows": [],
}),
)
Since I have put all of that up locally now, I will create a PR for your GitHub repo.