Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions .github/workflows/github-cxx-qt-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -193,13 +193,8 @@ jobs:
# Ensure clippy and rustfmt is installed, they should come from github runner
#
# Note we still need rustfmt for the cxx-qt-gen tests
#
# TODO: Remove the `rustup default 1.77` selection.
# This is a workaround for Github Actions, which cannot currently compile CXX-Qt with Rust 1.78.
#
# See: https://github.com/KDAB/cxx-qt/issues/958
- name: "Install Rust toolchain"
run: rustup default 1.77 && rustup component add clippy rustfmt
run: rustup component add clippy rustfmt

- name: "Rust tools cache"
uses: actions/cache@v4
Expand Down
45 changes: 31 additions & 14 deletions crates/cxx-qt-build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,13 +255,21 @@ fn generate_cxxqt_cpp_files(
generated_file_paths
}

/// The include directory needs to be namespaced by crate name when exporting for a C++ build system,
/// The export directory, if one was specified through the environment.
fn export_dir() -> Option<String> {
env::var("CXXQT_EXPORT_DIR")
.ok()
.map(|export_dir| format!("{export_dir}/{}", crate_name()))
}

/// The export directory needs to be namespaced by crate name when exporting for a C++ build system,
/// but for using cargo build without a C++ build system, OUT_DIR is already namespaced by crate name.
fn header_root() -> String {
match env::var("CXXQT_EXPORT_DIR") {
Ok(export_dir) => format!("{export_dir}/{}", env::var("CARGO_PKG_NAME").unwrap()),
Err(_) => env::var("OUT_DIR").unwrap(),
}
export_dir().unwrap_or_else(|| env::var("OUT_DIR").unwrap())
}

fn crate_name() -> String {
env::var("CARGO_PKG_NAME").unwrap()
}

fn panic_duplicate_file_and_qml_module(
Expand Down Expand Up @@ -570,8 +578,17 @@ impl CxxQtBuilder {
// from within main when static linking, which would result in discarding those static variables.
// Use a separate cc::Build for the little amount of code that needs to be linked with +whole-archive
// to avoid bloating the binary.
let mut cc_builder_whole_archive = cc::Build::new();
cc_builder_whole_archive.link_lib_modifier("+whole-archive");
let mut cc_builder_static_initializers = cc::Build::new();
if let Some(export_dir) = export_dir() {
// We have an export dir, so output the static-initializers library there, but avoid
// linking to it
cc_builder_static_initializers.out_dir(export_dir);
} else {
// We don't have an export dir, so this is likely a cargo-only build.
// Therefore make sure we link to the static-initializers library with +whole-archive,
// which ensures everything is linked, even without any references.
cc_builder_static_initializers.link_lib_modifier("+whole-archive");
}

// Ensure we are not using rustc 1.69
if let Some(version) = version_check::Version::read() {
Expand All @@ -593,7 +610,7 @@ impl CxxQtBuilder {
}
}

for builder in [&mut self.cc_builder, &mut cc_builder_whole_archive] {
for builder in [&mut self.cc_builder, &mut cc_builder_static_initializers] {
// Note, ensure our settings stay in sync across cxx-qt, cxx-qt-build, and cxx-qt-lib
builder.cpp(true);
builder.std("c++17");
Expand Down Expand Up @@ -668,10 +685,10 @@ impl CxxQtBuilder {
self.cc_builder
.file(qml_module_registration_files.qmltyperegistrar);
self.cc_builder.file(qml_module_registration_files.plugin);
cc_builder_whole_archive.file(qml_module_registration_files.plugin_init);
cc_builder_whole_archive.file(qml_module_registration_files.rcc);
cc_builder_static_initializers.file(qml_module_registration_files.plugin_init);
cc_builder_static_initializers.file(qml_module_registration_files.rcc);
for qmlcachegen_file in qml_module_registration_files.qmlcachegen {
cc_builder_whole_archive.file(qmlcachegen_file);
cc_builder_static_initializers.file(qmlcachegen_file);
}
self.cc_builder.define("QT_STATICPLUGIN", None);
cc_builder_whole_archive_files_added = true;
Expand All @@ -688,7 +705,7 @@ impl CxxQtBuilder {
}

for qrc_file in self.qrc_files {
cc_builder_whole_archive.file(qtbuild.qrc(&qrc_file));
cc_builder_static_initializers.file(qtbuild.qrc(&qrc_file));

// Also ensure that each of the files in the qrc can cause a change
for qrc_inner_file in qtbuild.qrc_list(&qrc_file) {
Expand Down Expand Up @@ -723,12 +740,12 @@ impl CxxQtBuilder {
let mut source =
File::create(&std_types_path).expect("Could not create std_types source");
write!(source, "{std_types_contents}").expect("Could not write std_types source");
cc_builder_whole_archive.file(&std_types_path);
cc_builder_static_initializers.file(&std_types_path);
cc_builder_whole_archive_files_added = true;
}

if cc_builder_whole_archive_files_added {
cc_builder_whole_archive.compile("qt-static-initializers");
cc_builder_static_initializers.compile(&format!("{}-initializers", crate_name()));
}

// Only compile if we have added files to the builder
Expand Down
4 changes: 3 additions & 1 deletion examples/demo_threading/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,10 @@ corrosion_set_env_vars(${CRATE}

add_library(${APP_NAME}_lib INTERFACE)
target_include_directories(${APP_NAME}_lib INTERFACE "${CXXQT_EXPORT_DIR}/${CRATE}")
target_link_directories(${APP_NAME}_lib INTERFACE "${CXXQT_EXPORT_DIR}/${CRATE}")
target_link_libraries(${APP_NAME}_lib INTERFACE
"$<LINK_LIBRARY:WHOLE_ARCHIVE,${CRATE}-static>"
"$<LINK_LIBRARY:WHOLE_ARCHIVE,${CRATE}-initializers>"
${CRATE}
Qt::Core
Qt::Gui
Qt::Qml
Expand Down
5 changes: 4 additions & 1 deletion examples/qml_features/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,11 @@ corrosion_set_env_vars(${CRATE}
)
add_library(${APP_NAME}_lib INTERFACE)
target_include_directories(${APP_NAME}_lib INTERFACE "${CXXQT_EXPORT_DIR}/${CRATE}")
target_link_directories(${APP_NAME}_lib INTERFACE "${CXXQT_EXPORT_DIR}/${CRATE}")

target_link_libraries(${APP_NAME}_lib INTERFACE
"$<LINK_LIBRARY:WHOLE_ARCHIVE,${CRATE}-static>"
"$<LINK_LIBRARY:WHOLE_ARCHIVE,${CRATE}-initializers>"
${CRATE}
Qt::Core
Qt::Gui
Qt::Qml
Expand Down
11 changes: 9 additions & 2 deletions examples/qml_minimal/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -72,16 +72,23 @@ corrosion_set_env_vars(${CRATE}
# the include paths and linked libraries for both of those.
add_library(${APP_NAME}_lib INTERFACE)

# Include the headers generated by the Rust library's build script. Each
# Include the headers & libraries generated by the Rust library's build script. Each
# crate gets its own subdirectory under CXXQT_EXPORT_DIR. This allows you
# to include headers generated by multiple crates without risk of one crate
# overwriting another's files.
target_include_directories(${APP_NAME}_lib INTERFACE "${CXXQT_EXPORT_DIR}/${CRATE}")
# If you're using qml modules or qrc resources, make sure to add the export directory
# as a link_directory and then link the ${CRATE}-initializers library with WHOLE_ARCHIVE.
target_link_directories(${APP_NAME}_lib INTERFACE "${CXXQT_EXPORT_DIR}/${CRATE}")

target_link_libraries(${APP_NAME}_lib INTERFACE
# WHOLE_ARCHIVE is needed for the generated QML plugin to register on startup,
# otherwise the linker will discard the static variables that initialize it.
"$<LINK_LIBRARY:WHOLE_ARCHIVE,${CRATE}-static>"
#
# If you're not using QML plugins or QRC files with cxx-qt-build, this line is not needed.
"$<LINK_LIBRARY:WHOLE_ARCHIVE,${CRATE}-initializers>"
# Additionally, link to the crate's library as normal.
${CRATE}
Qt::Core
Qt::Gui
Qt::Qml
Expand Down