use cxx_qt_build::{CxxQtBuilder, PluginType, QmlModule}; fn main() { // Two separate problems to defeat in the cdylib link: // 1. cc-rs uses -ffunction-sections, Rust's cdylib runs --gc-sections, and // nothing internal references qt_plugin_instance / qt_plugin_query_metadata_v2 // (moc emits them as dlsym entry points for Qt's plugin loader, not for // in-binary calls), so the linker drops them entirely. --undefined= // anchors them past --gc-sections. // 2. Even once present, Rust's cdylib link hides C++ static-archive symbols by // default - they end up as local (lowercase t in nm), invisible to dlsym. // --export-dynamic-symbol= doesn't help: that flag only applies to // -shared=no (executables). For shared libraries, bare --export-dynamic // exports all global symbols and overrides the hide-by-default. for sym in ["qt_plugin_instance", "qt_plugin_query_metadata_v2"] { println!("cargo:rustc-link-arg=-Wl,--undefined={sym}"); } println!("cargo:rustc-link-arg=-Wl,--export-dynamic"); // 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 bridge_files = ["src/system_stats.rs", "src/cpu_service.rs"]; if !bridge_files.iter().all(|p| std::path::Path::new(p).exists()) { return; } CxxQtBuilder::new_qml_module(QmlModule::new("NovaStats").plugin_type(PluginType::Dynamic)) .files(bridge_files) .build(); }