Skip to content

Commit 3c78079

Browse files
committed
cxx-qt-build: add Cargo feature to toggle linking Qt's .o files
Unfortunately, there is no way to get linking to work in every case without conditional compilation. This feature needs to be enabled for bin crates or when running `cargo test` for library crates. The feature must not be enabled when builing a staticlib then linking it with CMake because CMake will also link the .o files, which makes linking fail with duplicate symbol errors.
1 parent 3650853 commit 3c78079

File tree

9 files changed

+42
-8
lines changed

9 files changed

+42
-8
lines changed

CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,9 +195,9 @@ endif()
195195
set(CARGO_TARGET_DIR "${CMAKE_BINARY_DIR}/${BUILD_DIR}/cargo/build")
196196

197197
# Add CMake tests for `cargo test/clippy/fmt/doc`.
198-
add_test(NAME cargo_tests COMMAND cargo test --all-targets --target-dir
198+
add_test(NAME cargo_tests COMMAND cargo test --features link_qt_object_files --all-targets --target-dir
199199
${CARGO_TARGET_DIR})
200-
add_test(NAME cargo_doc_tests COMMAND cargo test --doc --target-dir
200+
add_test(NAME cargo_doc_tests COMMAND cargo test --features link_qt_object_files --doc --target-dir
201201
${CARGO_TARGET_DIR})
202202
add_test(NAME cargo_doc COMMAND cargo doc --workspace --target-dir ${CARGO_TARGET_DIR})
203203
add_test(NAME cargo_clippy COMMAND cargo clippy --all-targets --target-dir

crates/cxx-qt-build/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,4 @@ default = ["qt_gui", "qt_qml"]
2929
qt_gui = ["cxx-qt-lib-headers/qt_gui"]
3030
qt_qml = ["cxx-qt-lib-headers/qt_qml"]
3131
link_qt_external = []
32+
link_qt_object_files = ["qt-build-utils/link_qt_object_files"]

crates/qt-build-utils/Cargo.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,16 @@ repository.workspace = true
1616
cc = "1.0.74"
1717
versions = "4.1.0"
1818
thiserror = "1.0"
19+
20+
[features]
21+
# When Cargo links an executable, whether a bin crate or test executable,
22+
# and Qt 6 is linked statically, this feature must be enabled to link
23+
# unarchived .o files with static symbols that Qt ships (for example
24+
# to initialize Qt resources embedded within Qt libraries).
25+
#
26+
# CMake also links those .o files when linking Qt's targets, so this
27+
# feature must be disabled for staticlib crates. Otherwise, linking
28+
# will fail with duplicate symbol errors.
29+
#
30+
# When linking Qt dynamically, this makes no difference.
31+
link_qt_object_files = []

crates/qt-build-utils/src/parse_cflags.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,12 @@
88
//! It has been decoupled from the pkg-config crate because qt-build-utils reads Qt's .prl files instead, which
99
//! does not require a pkg-config executable to be available.
1010
11-
use std::{collections::HashSet, env, sync::OnceLock};
11+
use std::env;
1212

13+
#[cfg(feature = "link_qt_object_files")]
14+
use std::{collections::HashSet, sync::OnceLock};
15+
16+
#[cfg(feature = "link_qt_object_files")]
1317
static mut LINKED_OBJECT_FILES: OnceLock<HashSet<String>> = OnceLock::new();
1418

1519
/// Extract the &str to pass to cargo:rustc-link-lib from a filename (just the file name, not including directories)
@@ -108,7 +112,7 @@ fn split_flags(link_args: &[u8]) -> Vec<String> {
108112
pub(crate) fn parse_libs_cflags(
109113
name: &str,
110114
link_args: &[u8],
111-
builder: &mut Option<&mut cc::Build>,
115+
_builder: &mut Option<&mut cc::Build>,
112116
) {
113117
let mut is_msvc = false;
114118
let target = env::var("TARGET");
@@ -171,8 +175,10 @@ pub(crate) fn parse_libs_cflags(
171175
if let (Some(dir), Some(file_name), Ok(target)) =
172176
(path.parent(), path.file_name(), &target)
173177
{
174-
if file_name.to_string_lossy().ends_with(".o") {
175-
if let Some(builder) = builder {
178+
let file_name = file_name.to_string_lossy();
179+
if file_name.ends_with(".o") {
180+
#[cfg(feature = "link_qt_object_files")]
181+
if let Some(builder) = _builder {
176182
let path_string = path.to_string_lossy().to_string();
177183
unsafe {
178184
// Linking will fail with duplicate symbol errors if the same .o file is linked twice.
@@ -192,7 +198,7 @@ pub(crate) fn parse_libs_cflags(
192198
}
193199
}
194200
} else {
195-
match extract_lib_from_filename(target, &file_name.to_string_lossy()) {
201+
match extract_lib_from_filename(target, &file_name) {
196202
Some(lib_basename) => {
197203
println!("cargo:rustc-link-search={}", dir.display());
198204
println!("cargo:rustc-link-lib={lib_basename}");

examples/cargo_without_cmake/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,6 @@ cxx-qt-lib.workspace = true
2727

2828
[build-dependencies]
2929
# Use `cxx-qt-build = "0.5"` here instead!
30-
cxx-qt-build.workspace = true
30+
# The link_qt_object_files feature is required for statically linking Qt 6.
31+
cxx-qt-build = { workspace = true, features = [ "link_qt_object_files" ] }
3132
# ANCHOR_END: book_cargo_toml_no_cmake

examples/demo_threading/rust/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,6 @@ uuid = { version = "1.2", features = ["serde", "v4"] }
2525

2626
[build-dependencies]
2727
cxx-qt-build.workspace = true
28+
29+
[features]
30+
link_qt_object_files = [ "cxx-qt-build/link_qt_object_files" ]

examples/qml_extension_plugin/plugin/rust/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,6 @@ serde_json.workspace = true
2222

2323
[build-dependencies]
2424
cxx-qt-build.workspace = true
25+
26+
[features]
27+
link_qt_object_files = [ "cxx-qt-build/link_qt_object_files" ]

examples/qml_features/rust/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,6 @@ serde_json.workspace = true
2222

2323
[build-dependencies]
2424
cxx-qt-build.workspace = true
25+
26+
[features]
27+
link_qt_object_files = [ "cxx-qt-build/link_qt_object_files" ]

examples/qml_minimal/rust/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ cxx-qt-lib.workspace = true
3838
[build-dependencies]
3939
# Use `cxx-qt-build = "0.5"` here instead!
4040
cxx-qt-build.workspace = true
41+
42+
[features]
43+
# This feature must be enabled for `cargo test` when linking Qt 6 statically.
44+
link_qt_object_files = [ "cxx-qt-build/link_qt_object_files" ]
4145
# ANCHOR_END: book_build_dependencies
4246

4347
# ANCHOR_END: book_all

0 commit comments

Comments
 (0)