use cxx_qt_build::{CxxQtBuilder, PluginType, QmlModule}; fn main() { // Two separate problems to defeat in the cdylib link for cxx-qt's QML plugin // entry points (qt_plugin_instance / qt_plugin_query_metadata_v2): // 1. cc-rs uses -ffunction-sections, Rust's cdylib runs --gc-sections, and // nothing internal references those symbols (moc emits them as dlsym // entry points), so the linker drops them entirely. --undefined= // anchors them past --gc-sections. // 2. Rust's cdylib link passes an explicit --version-script that lists Rust // public symbols under `global:` and ends with `local: *;`, hiding // everything else. --dynamic-list and --export-dynamic both lose to that // `local: *;`. Multiple --version-script flags merge per ld(1), and // explicit `global:` entries override the wildcard local, so we pass a // second version script that adds the qt_plugin entry points. for sym in ["qt_plugin_instance", "qt_plugin_query_metadata_v2"] { println!("cargo:rustc-link-arg=-Wl,--undefined={sym}"); } let vscript = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("qt_plugin_exports.txt"); println!("cargo:rerun-if-changed={}", vscript.display()); println!( "cargo:rustc-link-arg=-Wl,--version-script={}", vscript.display() ); // Crane's deps-only build stubs out lib.rs and removes our bridge sources to // build a dummy crate that only compiles dependencies. Skip cxx-qt codegen in // that case - we just want cxx-qt-lib (the heavy dep) cached, not our own glue. let manifest = std::path::Path::new(env!("CARGO_MANIFEST_DIR")); let bridge_files = [ "src/system_stats.rs", "src/cpu_service.rs", "src/modules_service.rs", "src/theme_service.rs", ]; if !bridge_files.iter().all(|p| manifest.join(p).exists()) { return; } CxxQtBuilder::new_qml_module(QmlModule::new("NovaStats").plugin_type(PluginType::Dynamic)) .files(bridge_files) .build(); }