plugin: give moc qtdeclarative include path so QML attrs reach qmltyperegistrar
This commit is contained in:
parent
78abe800ed
commit
1b07787764
3 changed files with 17 additions and 28 deletions
|
|
@ -7,11 +7,14 @@
|
||||||
runCommand,
|
runCommand,
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
# nixpkgs splits Qt tools across packages: moc/rcc/qtpaths live in qtbase,
|
# nixpkgs splits Qt: tools (moc/rcc/qtpaths in qtbase, qmltyperegistrar/qmlcachegen
|
||||||
# qmltyperegistrar and qmlcachegen live in qtdeclarative. qt-build-utils
|
# in qtdeclarative) and headers (qtbase has Qt6Core etc., qtdeclarative has Qt6Qml
|
||||||
# finds tools via `qmake -query QT_INSTALL_LIBEXECS`, which only returns
|
# incl. qqmlregistration.h). qt-build-utils derives both from `qmake -query`, which
|
||||||
# qtbase paths, so those two tools are invisible. Fix: combine them into a
|
# only knows about qtbase. Symptom of missing headers: moc warns "Potential QML
|
||||||
# single symlink tree and point a qmake wrapper at it.
|
# registration macro was found, but no header containing it was included", silently
|
||||||
|
# strips QML_NAMED_ELEMENT/QML_SINGLETON from the JSON, qmltyperegistrar emits an
|
||||||
|
# empty qml_register_types_*, and the QML import resolves to no types. Fix: combine
|
||||||
|
# tools and headers into symlink trees and point a qmake wrapper at them.
|
||||||
qtBuildTools = runCommand "qt6-build-tools" { } ''
|
qtBuildTools = runCommand "qt6-build-tools" { } ''
|
||||||
mkdir -p $out/libexec $out/bin
|
mkdir -p $out/libexec $out/bin
|
||||||
for f in ${qt6.qtbase}/libexec/* ${qt6.qtbase}/bin/*; do
|
for f in ${qt6.qtbase}/libexec/* ${qt6.qtbase}/bin/*; do
|
||||||
|
|
@ -22,6 +25,12 @@ let
|
||||||
[ -f "$src" ] && ln -sf "$src" "$out/libexec/$tool"
|
[ -f "$src" ] && ln -sf "$src" "$out/libexec/$tool"
|
||||||
done
|
done
|
||||||
'';
|
'';
|
||||||
|
qtIncludeRoots = runCommand "qt6-include-roots" { } ''
|
||||||
|
mkdir -p $out/include
|
||||||
|
for src in ${qt6.qtbase.dev}/include/* ${qt6.qtdeclarative.dev}/include/*; do
|
||||||
|
ln -sfn "$src" "$out/include/$(basename "$src")"
|
||||||
|
done
|
||||||
|
'';
|
||||||
qmakeWrapper = writeShellScript "qmake6" ''
|
qmakeWrapper = writeShellScript "qmake6" ''
|
||||||
if [ "$1" = "-query" ]; then
|
if [ "$1" = "-query" ]; then
|
||||||
case "$2" in
|
case "$2" in
|
||||||
|
|
@ -29,6 +38,8 @@ let
|
||||||
echo "${qtBuildTools}/libexec"; exit 0;;
|
echo "${qtBuildTools}/libexec"; exit 0;;
|
||||||
QT_HOST_BINS|QT_HOST_BINS/get|QT_INSTALL_BINS|QT_INSTALL_BINS/get)
|
QT_HOST_BINS|QT_HOST_BINS/get|QT_INSTALL_BINS|QT_INSTALL_BINS/get)
|
||||||
echo "${qtBuildTools}/bin"; exit 0;;
|
echo "${qtBuildTools}/bin"; exit 0;;
|
||||||
|
QT_HOST_INCLUDES|QT_HOST_INCLUDES/get|QT_INSTALL_HEADERS|QT_INSTALL_HEADERS/get)
|
||||||
|
echo "${qtIncludeRoots}/include"; exit 0;;
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
exec ${qt6.qtbase}/bin/qmake6 "$@"
|
exec ${qt6.qtbase}/bin/qmake6 "$@"
|
||||||
|
|
|
||||||
|
|
@ -26,17 +26,9 @@ fn main() {
|
||||||
// Crane's deps-only build stubs out lib.rs and removes our bridge sources to
|
// 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
|
// 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.
|
// that case - we just want cxx-qt-lib (the heavy dep) cached, not our own glue.
|
||||||
// Use CARGO_MANIFEST_DIR for a robust path that doesn't depend on cargo's CWD.
|
|
||||||
let manifest = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
|
let manifest = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
|
||||||
let bridge_files = ["src/system_stats.rs", "src/cpu_service.rs"];
|
let bridge_files = ["src/system_stats.rs", "src/cpu_service.rs"];
|
||||||
let present: Vec<bool> = bridge_files
|
if !bridge_files.iter().all(|p| manifest.join(p).exists()) {
|
||||||
.iter()
|
|
||||||
.map(|p| manifest.join(p).exists())
|
|
||||||
.collect();
|
|
||||||
println!("cargo:warning=build.rs manifest_dir={}", manifest.display());
|
|
||||||
println!("cargo:warning=build.rs bridge_files present: {present:?}");
|
|
||||||
if !present.iter().all(|b| *b) {
|
|
||||||
println!("cargo:warning=build.rs bailing: bridge files missing (deps-only build?)");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,21 +2,7 @@ pub mod cpu_service;
|
||||||
pub mod stats;
|
pub mod stats;
|
||||||
pub mod system_stats;
|
pub mod system_stats;
|
||||||
|
|
||||||
// cxx-qt 0.8.1's PluginType::Dynamic emits a QQmlEngineExtensionPlugin whose
|
|
||||||
// constructor only anchors qml_register_types_NovaStats with `volatile auto X = &X`
|
|
||||||
// (linker-keep, not a call), and the qmltyperegistrar static init doesn't call it
|
|
||||||
// either. Net effect: types never register, NS.* stays undefined in QML. Workaround:
|
|
||||||
// call it ourselves at .so load time. The function is mangled (returns void, no
|
|
||||||
// extern "C"), so go through #[link_name] using the itanium-mangled symbol seen in
|
|
||||||
// `nm libNovaStats.so | grep qml_register_types`.
|
|
||||||
unsafe extern "C" {
|
|
||||||
#[link_name = "_Z28qml_register_types_NovaStatsv"]
|
|
||||||
fn qml_register_types_nova_stats();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[ctor::ctor(unsafe)]
|
#[ctor::ctor(unsafe)]
|
||||||
fn on_dylib_load() {
|
fn on_dylib_load() {
|
||||||
eprintln!("[nova-plugin] dylib loaded (libNovaStats.so)");
|
eprintln!("[nova-plugin] dylib loaded (libNovaStats.so)");
|
||||||
unsafe { qml_register_types_nova_stats() };
|
|
||||||
eprintln!("[nova-plugin] qml_register_types_NovaStats called");
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue