From dc56b45e31db67ac6800db6a94e7e7e2dae5ab4f Mon Sep 17 00:00:00 2001 From: Andrew Hayzen Date: Wed, 21 Feb 2024 09:44:45 +0000 Subject: [PATCH 01/15] cxx-qt-build: consider the folders in rust path Closes #855 --- CHANGELOG.md | 1 + crates/cxx-qt-build/src/lib.rs | 54 +++++++++++++------ .../cpp/helpers/energyusageproxymodel.h | 2 +- tests/basic_cxx_only/cpp/main.cpp | 2 +- tests/basic_cxx_qt/cpp/main.cpp | 8 +-- tests/qt_types_standalone/cpp/qbytearray.h | 2 +- tests/qt_types_standalone/cpp/qcolor.h | 2 +- .../cpp/qcoreapplication.h | 2 +- tests/qt_types_standalone/cpp/qdate.h | 2 +- tests/qt_types_standalone/cpp/qdatetime.h | 2 +- .../qt_types_standalone/cpp/qguiapplication.h | 2 +- tests/qt_types_standalone/cpp/qhash.h | 2 +- tests/qt_types_standalone/cpp/qline.h | 2 +- tests/qt_types_standalone/cpp/qlinef.h | 2 +- tests/qt_types_standalone/cpp/qlist.h | 2 +- tests/qt_types_standalone/cpp/qmap.h | 4 +- tests/qt_types_standalone/cpp/qmargins.h | 2 +- tests/qt_types_standalone/cpp/qmarginsf.h | 2 +- .../cpp/qmetaobjectconnection.h | 2 +- tests/qt_types_standalone/cpp/qmodelindex.h | 2 +- tests/qt_types_standalone/cpp/qpen.h | 2 +- .../cpp/qpersistentmodelindex.h | 2 +- tests/qt_types_standalone/cpp/qpoint.h | 2 +- tests/qt_types_standalone/cpp/qpointf.h | 2 +- tests/qt_types_standalone/cpp/qpolygon.h | 2 +- tests/qt_types_standalone/cpp/qpolygonf.h | 2 +- .../cpp/qqmlapplicationengine.h | 2 +- tests/qt_types_standalone/cpp/qqmlengine.h | 2 +- tests/qt_types_standalone/cpp/qrect.h | 2 +- tests/qt_types_standalone/cpp/qrectf.h | 2 +- tests/qt_types_standalone/cpp/qregion.h | 2 +- tests/qt_types_standalone/cpp/qset.h | 2 +- tests/qt_types_standalone/cpp/qsize.h | 2 +- tests/qt_types_standalone/cpp/qsizef.h | 2 +- tests/qt_types_standalone/cpp/qstring.h | 2 +- tests/qt_types_standalone/cpp/qstringlist.h | 2 +- tests/qt_types_standalone/cpp/qtime.h | 2 +- tests/qt_types_standalone/cpp/qtimezone.h | 2 +- tests/qt_types_standalone/cpp/qurl.h | 2 +- tests/qt_types_standalone/cpp/qvariant.h | 2 +- tests/qt_types_standalone/cpp/qvector.h | 2 +- tests/qt_types_standalone/cpp/qvector2d.h | 2 +- tests/qt_types_standalone/cpp/qvector3d.h | 2 +- tests/qt_types_standalone/cpp/qvector4d.h | 2 +- 44 files changed, 86 insertions(+), 61 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 477a7923a..ceb58a1a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Libraries can pass build information to cxx-qt-build in the form of a `cxx_qt_build::Interface` - Add CMake wrappers around corrosion to simplify importing crates and qml modules that were built with cxx-qt-build - CMake code has been extracted into a separate repository for faster downloads (kdab/cxx-qt-cmake) +- Folder structure of Rust bridges is now considered in the same way as CXX in `CxxQtBuilder` ### Removed diff --git a/crates/cxx-qt-build/src/lib.rs b/crates/cxx-qt-build/src/lib.rs index dbe6dbf52..9c21e5207 100644 --- a/crates/cxx-qt-build/src/lib.rs +++ b/crates/cxx-qt-build/src/lib.rs @@ -68,7 +68,10 @@ struct GeneratedCpp { impl GeneratedCpp { /// Generate QObject and cxx header/source C++ file contents - pub fn new(rust_file_path: impl AsRef) -> Result { + pub fn new( + rust_file_path: impl AsRef, + relative_path: impl AsRef, + ) -> Result { let to_diagnostic = |err| Diagnostic::new(rust_file_path.as_ref().to_owned(), err); let rust_file_path = rust_file_path.as_ref(); @@ -98,15 +101,13 @@ impl GeneratedCpp { rust_file_path.display()); } - // Match upstream where they use the file name as the ident + // Match upstream where they use the file name and folders as the ident // - // TODO: what happens if there are folders? - // - // TODO: ideally CXX-Qt would also use the file name - // https://github.com/KDAB/cxx-qt/pull/200/commits/4861c92e66c3a022d3f0dedd9f8fd20db064b42b - rust_file_path - .file_stem() - .unwrap() + // We need the relative path here as we want the folders + relative_path + .as_ref() + // Remove the .rs extension + .with_extension("") .to_str() .unwrap() .clone_into(&mut file_ident); @@ -135,7 +136,18 @@ impl GeneratedCpp { .map_err(GeneratedError::from) .map_err(to_diagnostic)?; let rust_tokens = write_rust(&generated_rust); - file_ident.clone_from(&parser.cxx_file_stem); + + // Use the relative path with the cxx_file_stem + // + // TODO: ideally CXX-Qt would also use the file name + // but it uses the module or cxx_file_stem for now + // https://github.com/KDAB/cxx-qt/pull/200/commits/4861c92e66c3a022d3f0dedd9f8fd20db064b42b + file_ident = relative_path + .as_ref() + .with_file_name(parser.cxx_file_stem) + .to_str() + .unwrap() + .clone_into(&mut file_ident); // We need to do this and can't rely on the macro, as we need to generate the // CXX bridge Rust code that is then fed into the cxx_gen generation. @@ -168,10 +180,6 @@ impl GeneratedCpp { ) -> GeneratedCppFilePaths { let cpp_directory = cpp_directory.as_ref(); let header_directory = header_directory.as_ref(); - for directory in [cpp_directory, header_directory] { - std::fs::create_dir_all(directory) - .expect("Could not create directory to write cxx-qt generated files"); - } let mut cpp_file_paths = GeneratedCppFilePaths { plain_cpp: PathBuf::new(), @@ -184,6 +192,10 @@ impl GeneratedCpp { header_directory.display(), self.file_ident )); + if let Some(directory) = header_path.parent() { + std::fs::create_dir_all(directory) + .expect("Could not create directory to write cxx-qt generated files"); + } let mut header = File::create(&header_path).expect("Could not create cxx-qt header file"); let header_generated = match cxx_qt_generated { @@ -201,6 +213,10 @@ impl GeneratedCpp { cpp_directory.display(), self.file_ident )); + if let Some(directory) = cpp_path.parent() { + std::fs::create_dir_all(directory) + .expect("Could not create directory to write cxx-qt generated files"); + } let mut cpp = File::create(&cpp_path).expect("Could not create cxx-qt source file"); let source_generated = match cxx_qt_generated { CppFragment::Pair { header: _, source } => source, @@ -217,6 +233,10 @@ impl GeneratedCpp { header_directory.display(), self.file_ident )); + if let Some(directory) = header_path.parent() { + std::fs::create_dir_all(directory) + .expect("Could not create directory to write cxx-qt generated header files"); + } let mut header = File::create(header_path).expect("Could not create cxx header file"); header .write_all(&self.cxx.header) @@ -227,6 +247,10 @@ impl GeneratedCpp { cpp_directory.display(), self.file_ident )); + if let Some(directory) = cpp_path.parent() { + std::fs::create_dir_all(directory) + .expect("Could not create directory to write cxx-qt generated source files"); + } let mut cpp = File::create(&cpp_path).expect("Could not create cxx source file"); cpp.write_all(&self.cxx.implementation) .expect("Could not write cxx source file"); @@ -255,7 +279,7 @@ fn generate_cxxqt_cpp_files( let path = manifest_dir.join(rs_path); println!("cargo:rerun-if-changed={}", path.to_string_lossy()); - let generated_code = match GeneratedCpp::new(&path) { + let generated_code = match GeneratedCpp::new(&path, rs_path) { Ok(v) => v, Err(diagnostic) => { diagnostic.report(); diff --git a/examples/demo_threading/cpp/helpers/energyusageproxymodel.h b/examples/demo_threading/cpp/helpers/energyusageproxymodel.h index 6af092a00..8876fe7fc 100644 --- a/examples/demo_threading/cpp/helpers/energyusageproxymodel.h +++ b/examples/demo_threading/cpp/helpers/energyusageproxymodel.h @@ -12,7 +12,7 @@ #include #include -#include "cxx_qt_demo_threading/energy_usage.cxxqt.h" +#include "cxx_qt_demo_threading/src/energy_usage.cxxqt.h" class EnergyUsageProxyModel : public QAbstractListModel { diff --git a/tests/basic_cxx_only/cpp/main.cpp b/tests/basic_cxx_only/cpp/main.cpp index 331b94319..1d3f68704 100644 --- a/tests/basic_cxx_only/cpp/main.cpp +++ b/tests/basic_cxx_only/cpp/main.cpp @@ -7,7 +7,7 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 #include -#include "basic_cxx_only/lib.cxx.h" +#include "basic_cxx_only/src/lib.cxx.h" #include "cxx_test.h" class CxxTest : public QObject diff --git a/tests/basic_cxx_qt/cpp/main.cpp b/tests/basic_cxx_qt/cpp/main.cpp index bd60868d0..765f43301 100644 --- a/tests/basic_cxx_qt/cpp/main.cpp +++ b/tests/basic_cxx_qt/cpp/main.cpp @@ -10,10 +10,10 @@ #include #include -#include "basic_cxx_qt/empty.cxxqt.h" -#include "basic_cxx_qt/my_data.cxxqt.h" -#include "basic_cxx_qt/my_object.cxxqt.h" -#include "basic_cxx_qt/my_types.cxxqt.h" +#include "basic_cxx_qt/src/empty.cxxqt.h" +#include "basic_cxx_qt/src/my_data.cxxqt.h" +#include "basic_cxx_qt/src/my_object.cxxqt.h" +#include "basic_cxx_qt/src/my_types.cxxqt.h" class CxxQtTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qbytearray.h b/tests/qt_types_standalone/cpp/qbytearray.h index 17374d107..2ac7c2929 100644 --- a/tests/qt_types_standalone/cpp/qbytearray.h +++ b/tests/qt_types_standalone/cpp/qbytearray.h @@ -9,7 +9,7 @@ #include #include -#include "qt_types_standalone/qbytearray.cxx.h" +#include "qt_types_standalone/src/qbytearray.cxx.h" class QByteArrayTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qcolor.h b/tests/qt_types_standalone/cpp/qcolor.h index b6d951fb0..58f648a6d 100644 --- a/tests/qt_types_standalone/cpp/qcolor.h +++ b/tests/qt_types_standalone/cpp/qcolor.h @@ -9,7 +9,7 @@ #include #include -#include "qt_types_standalone/qcolor.cxx.h" +#include "qt_types_standalone/src/qcolor.cxx.h" class QColorTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qcoreapplication.h b/tests/qt_types_standalone/cpp/qcoreapplication.h index cad2cd882..b838519fd 100644 --- a/tests/qt_types_standalone/cpp/qcoreapplication.h +++ b/tests/qt_types_standalone/cpp/qcoreapplication.h @@ -9,7 +9,7 @@ #include #include -#include "qt_types_standalone/qcoreapplication.cxx.h" +#include "qt_types_standalone/src/qcoreapplication.cxx.h" class QCoreApplicationTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qdate.h b/tests/qt_types_standalone/cpp/qdate.h index c23912409..24fec0b2e 100644 --- a/tests/qt_types_standalone/cpp/qdate.h +++ b/tests/qt_types_standalone/cpp/qdate.h @@ -9,7 +9,7 @@ #include #include -#include "qt_types_standalone/qdate.cxx.h" +#include "qt_types_standalone/src/qdate.cxx.h" class QDateTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qdatetime.h b/tests/qt_types_standalone/cpp/qdatetime.h index e8c59de60..50272af8f 100644 --- a/tests/qt_types_standalone/cpp/qdatetime.h +++ b/tests/qt_types_standalone/cpp/qdatetime.h @@ -9,7 +9,7 @@ #include #include -#include "qt_types_standalone/qdatetime.cxx.h" +#include "qt_types_standalone/src/qdatetime.cxx.h" class QDateTimeTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qguiapplication.h b/tests/qt_types_standalone/cpp/qguiapplication.h index 4857878ff..ecfd00087 100644 --- a/tests/qt_types_standalone/cpp/qguiapplication.h +++ b/tests/qt_types_standalone/cpp/qguiapplication.h @@ -9,7 +9,7 @@ #include #include -#include "qt_types_standalone/qguiapplication.cxx.h" +#include "qt_types_standalone/src/qguiapplication.cxx.h" class QGuiApplicationTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qhash.h b/tests/qt_types_standalone/cpp/qhash.h index bf1834f82..98d2e64bf 100644 --- a/tests/qt_types_standalone/cpp/qhash.h +++ b/tests/qt_types_standalone/cpp/qhash.h @@ -10,7 +10,7 @@ #include #include -#include "qt_types_standalone/qhash.cxx.h" +#include "qt_types_standalone/src/qhash.cxx.h" class QHashTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qline.h b/tests/qt_types_standalone/cpp/qline.h index e9d6a458a..329d7a47b 100644 --- a/tests/qt_types_standalone/cpp/qline.h +++ b/tests/qt_types_standalone/cpp/qline.h @@ -9,7 +9,7 @@ #include #include -#include "qt_types_standalone/qline.cxx.h" +#include "qt_types_standalone/src/qline.cxx.h" class QLineTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qlinef.h b/tests/qt_types_standalone/cpp/qlinef.h index 53a2fd25e..bde13b577 100644 --- a/tests/qt_types_standalone/cpp/qlinef.h +++ b/tests/qt_types_standalone/cpp/qlinef.h @@ -9,7 +9,7 @@ #include #include -#include "qt_types_standalone/qlinef.cxx.h" +#include "qt_types_standalone/src/qlinef.cxx.h" class QLineFTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qlist.h b/tests/qt_types_standalone/cpp/qlist.h index ed1c0d436..d901afda2 100644 --- a/tests/qt_types_standalone/cpp/qlist.h +++ b/tests/qt_types_standalone/cpp/qlist.h @@ -9,7 +9,7 @@ #include #include -#include "qt_types_standalone/qlist.cxx.h" +#include "qt_types_standalone/src/qlist.cxx.h" class QListTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qmap.h b/tests/qt_types_standalone/cpp/qmap.h index ef6884b84..99e087089 100644 --- a/tests/qt_types_standalone/cpp/qmap.h +++ b/tests/qt_types_standalone/cpp/qmap.h @@ -10,7 +10,7 @@ #include #include -#include "qt_types_standalone/qmap.cxx.h" +#include "qt_types_standalone/src/qmap.cxx.h" class QMapTest : public QObject { @@ -49,4 +49,4 @@ private Q_SLOTS: QVERIFY(!c.contains(QStringLiteral("github"))); QCOMPARE(c.size(), 2); } -}; \ No newline at end of file +}; diff --git a/tests/qt_types_standalone/cpp/qmargins.h b/tests/qt_types_standalone/cpp/qmargins.h index 1612d1592..12b360027 100644 --- a/tests/qt_types_standalone/cpp/qmargins.h +++ b/tests/qt_types_standalone/cpp/qmargins.h @@ -9,7 +9,7 @@ #include #include -#include "qt_types_standalone/qmargins.cxx.h" +#include "qt_types_standalone/src/qmargins.cxx.h" class QMarginsTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qmarginsf.h b/tests/qt_types_standalone/cpp/qmarginsf.h index ec9c3b6d2..953fd11b4 100644 --- a/tests/qt_types_standalone/cpp/qmarginsf.h +++ b/tests/qt_types_standalone/cpp/qmarginsf.h @@ -9,7 +9,7 @@ #include #include -#include "qt_types_standalone/qmarginsf.cxx.h" +#include "qt_types_standalone/src/qmarginsf.cxx.h" class QMarginsFTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qmetaobjectconnection.h b/tests/qt_types_standalone/cpp/qmetaobjectconnection.h index 79eeba56c..70bce0005 100644 --- a/tests/qt_types_standalone/cpp/qmetaobjectconnection.h +++ b/tests/qt_types_standalone/cpp/qmetaobjectconnection.h @@ -11,7 +11,7 @@ #include #include -#include "qt_types_standalone/qmetaobjectconnection.cxx.h" +#include "qt_types_standalone/src/qmetaobjectconnection.cxx.h" class MyObject : public QObject { diff --git a/tests/qt_types_standalone/cpp/qmodelindex.h b/tests/qt_types_standalone/cpp/qmodelindex.h index 4855e4486..60860f2bc 100644 --- a/tests/qt_types_standalone/cpp/qmodelindex.h +++ b/tests/qt_types_standalone/cpp/qmodelindex.h @@ -11,7 +11,7 @@ #include #include -#include "qt_types_standalone/qmodelindex.cxx.h" +#include "qt_types_standalone/src/qmodelindex.cxx.h" // We subclass from QAbstractListModel to have a valid model to use for // access to createIndex(); diff --git a/tests/qt_types_standalone/cpp/qpen.h b/tests/qt_types_standalone/cpp/qpen.h index 3850ea394..2ece36dff 100644 --- a/tests/qt_types_standalone/cpp/qpen.h +++ b/tests/qt_types_standalone/cpp/qpen.h @@ -9,7 +9,7 @@ #include #include -#include "qt_types_standalone/qpen.cxx.h" +#include "qt_types_standalone/src/qpen.cxx.h" class QPenTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qpersistentmodelindex.h b/tests/qt_types_standalone/cpp/qpersistentmodelindex.h index a3f3deda4..ce38d2b45 100644 --- a/tests/qt_types_standalone/cpp/qpersistentmodelindex.h +++ b/tests/qt_types_standalone/cpp/qpersistentmodelindex.h @@ -11,7 +11,7 @@ #include #include -#include "qt_types_standalone/qpersistentmodelindex.cxx.h" +#include "qt_types_standalone/src/qpersistentmodelindex.cxx.h" class QPersistentModelIndexTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qpoint.h b/tests/qt_types_standalone/cpp/qpoint.h index cc3a52029..a1035eb48 100644 --- a/tests/qt_types_standalone/cpp/qpoint.h +++ b/tests/qt_types_standalone/cpp/qpoint.h @@ -9,7 +9,7 @@ #include #include -#include "qt_types_standalone/qpoint.cxx.h" +#include "qt_types_standalone/src/qpoint.cxx.h" class QPointTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qpointf.h b/tests/qt_types_standalone/cpp/qpointf.h index 1e0042fcc..6c88b02fe 100644 --- a/tests/qt_types_standalone/cpp/qpointf.h +++ b/tests/qt_types_standalone/cpp/qpointf.h @@ -9,7 +9,7 @@ #include #include -#include "qt_types_standalone/qpointf.cxx.h" +#include "qt_types_standalone/src/qpointf.cxx.h" class QPointFTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qpolygon.h b/tests/qt_types_standalone/cpp/qpolygon.h index 951024816..f28c1a5ef 100644 --- a/tests/qt_types_standalone/cpp/qpolygon.h +++ b/tests/qt_types_standalone/cpp/qpolygon.h @@ -9,7 +9,7 @@ #include #include -#include "qt_types_standalone/qpolygon.cxx.h" +#include "qt_types_standalone/src/qpolygon.cxx.h" class QPolygonTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qpolygonf.h b/tests/qt_types_standalone/cpp/qpolygonf.h index 1af4007c8..e741fec97 100644 --- a/tests/qt_types_standalone/cpp/qpolygonf.h +++ b/tests/qt_types_standalone/cpp/qpolygonf.h @@ -9,7 +9,7 @@ #include #include -#include "qt_types_standalone/qpolygonf.cxx.h" +#include "qt_types_standalone/src/qpolygonf.cxx.h" class QPolygonFTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qqmlapplicationengine.h b/tests/qt_types_standalone/cpp/qqmlapplicationengine.h index b07c40f42..fdeb484a4 100644 --- a/tests/qt_types_standalone/cpp/qqmlapplicationengine.h +++ b/tests/qt_types_standalone/cpp/qqmlapplicationengine.h @@ -10,7 +10,7 @@ #include #include -#include "qt_types_standalone/qqmlapplicationengine.cxx.h" +#include "qt_types_standalone/src/qqmlapplicationengine.cxx.h" class QQmlApplicationEngineTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qqmlengine.h b/tests/qt_types_standalone/cpp/qqmlengine.h index 7b95f172c..44d47cf03 100644 --- a/tests/qt_types_standalone/cpp/qqmlengine.h +++ b/tests/qt_types_standalone/cpp/qqmlengine.h @@ -10,7 +10,7 @@ #include #include -#include "qt_types_standalone/qqmlengine.cxx.h" +#include "qt_types_standalone/src/qqmlengine.cxx.h" class QQmlEngineTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qrect.h b/tests/qt_types_standalone/cpp/qrect.h index 167c113a7..868564140 100644 --- a/tests/qt_types_standalone/cpp/qrect.h +++ b/tests/qt_types_standalone/cpp/qrect.h @@ -9,7 +9,7 @@ #include #include -#include "qt_types_standalone/qrect.cxx.h" +#include "qt_types_standalone/src/qrect.cxx.h" class QRectTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qrectf.h b/tests/qt_types_standalone/cpp/qrectf.h index 272629b16..9551eacab 100644 --- a/tests/qt_types_standalone/cpp/qrectf.h +++ b/tests/qt_types_standalone/cpp/qrectf.h @@ -9,7 +9,7 @@ #include #include -#include "qt_types_standalone/qrectf.cxx.h" +#include "qt_types_standalone/src/qrectf.cxx.h" class QRectFTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qregion.h b/tests/qt_types_standalone/cpp/qregion.h index 614f1348d..e1d8168ec 100644 --- a/tests/qt_types_standalone/cpp/qregion.h +++ b/tests/qt_types_standalone/cpp/qregion.h @@ -9,7 +9,7 @@ #include #include -#include "qt_types_standalone/qregion.cxx.h" +#include "qt_types_standalone/src/qregion.cxx.h" class QRegionTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qset.h b/tests/qt_types_standalone/cpp/qset.h index 1eeb0fa4b..846ef40b0 100644 --- a/tests/qt_types_standalone/cpp/qset.h +++ b/tests/qt_types_standalone/cpp/qset.h @@ -9,7 +9,7 @@ #include #include -#include "qt_types_standalone/qset.cxx.h" +#include "qt_types_standalone/src/qset.cxx.h" class QSetTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qsize.h b/tests/qt_types_standalone/cpp/qsize.h index c753ad4ff..0824115df 100644 --- a/tests/qt_types_standalone/cpp/qsize.h +++ b/tests/qt_types_standalone/cpp/qsize.h @@ -9,7 +9,7 @@ #include #include -#include "qt_types_standalone/qsize.cxx.h" +#include "qt_types_standalone/src/qsize.cxx.h" class QSizeTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qsizef.h b/tests/qt_types_standalone/cpp/qsizef.h index fabb6d5a9..bd71acf0a 100644 --- a/tests/qt_types_standalone/cpp/qsizef.h +++ b/tests/qt_types_standalone/cpp/qsizef.h @@ -9,7 +9,7 @@ #include #include -#include "qt_types_standalone/qsizef.cxx.h" +#include "qt_types_standalone/src/qsizef.cxx.h" class QSizeFTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qstring.h b/tests/qt_types_standalone/cpp/qstring.h index 98be871d9..93a08da8e 100644 --- a/tests/qt_types_standalone/cpp/qstring.h +++ b/tests/qt_types_standalone/cpp/qstring.h @@ -9,7 +9,7 @@ #include #include -#include "qt_types_standalone/qstring.cxx.h" +#include "qt_types_standalone/src/qstring.cxx.h" class QStringTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qstringlist.h b/tests/qt_types_standalone/cpp/qstringlist.h index 2bfd5334e..f1963fa59 100644 --- a/tests/qt_types_standalone/cpp/qstringlist.h +++ b/tests/qt_types_standalone/cpp/qstringlist.h @@ -9,7 +9,7 @@ #include #include -#include "qt_types_standalone/qstringlist.cxx.h" +#include "qt_types_standalone/src/qstringlist.cxx.h" class QStringListTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qtime.h b/tests/qt_types_standalone/cpp/qtime.h index 1a70c8f3b..ac195293d 100644 --- a/tests/qt_types_standalone/cpp/qtime.h +++ b/tests/qt_types_standalone/cpp/qtime.h @@ -9,7 +9,7 @@ #include #include -#include "qt_types_standalone/qtime.cxx.h" +#include "qt_types_standalone/src/qtime.cxx.h" class QTimeTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qtimezone.h b/tests/qt_types_standalone/cpp/qtimezone.h index 34575e9a0..b571ee2e4 100644 --- a/tests/qt_types_standalone/cpp/qtimezone.h +++ b/tests/qt_types_standalone/cpp/qtimezone.h @@ -9,7 +9,7 @@ #include #include -#include "qt_types_standalone/qtimezone.cxx.h" +#include "qt_types_standalone/src/qtimezone.cxx.h" class QTimeZoneTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qurl.h b/tests/qt_types_standalone/cpp/qurl.h index 327cb71f5..34ead1998 100644 --- a/tests/qt_types_standalone/cpp/qurl.h +++ b/tests/qt_types_standalone/cpp/qurl.h @@ -9,7 +9,7 @@ #include #include -#include "qt_types_standalone/qurl.cxx.h" +#include "qt_types_standalone/src/qurl.cxx.h" class QUrlTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qvariant.h b/tests/qt_types_standalone/cpp/qvariant.h index 5db3e9c33..1c1b29d7a 100644 --- a/tests/qt_types_standalone/cpp/qvariant.h +++ b/tests/qt_types_standalone/cpp/qvariant.h @@ -9,7 +9,7 @@ #include #include -#include "qt_types_standalone/qvariant.cxx.h" +#include "qt_types_standalone/src/qvariant.cxx.h" // We use VariantTest in data driven tests, so register to Qt metatype system Q_DECLARE_METATYPE(VariantTest) diff --git a/tests/qt_types_standalone/cpp/qvector.h b/tests/qt_types_standalone/cpp/qvector.h index cb9003d7e..f1979d989 100644 --- a/tests/qt_types_standalone/cpp/qvector.h +++ b/tests/qt_types_standalone/cpp/qvector.h @@ -9,7 +9,7 @@ #include #include -#include "qt_types_standalone/qvector.cxx.h" +#include "qt_types_standalone/src/qvector.cxx.h" class QVectorTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qvector2d.h b/tests/qt_types_standalone/cpp/qvector2d.h index 77c8c86bc..1ffd508fe 100644 --- a/tests/qt_types_standalone/cpp/qvector2d.h +++ b/tests/qt_types_standalone/cpp/qvector2d.h @@ -9,7 +9,7 @@ #include #include -#include "qt_types_standalone/qvector2d.cxx.h" +#include "qt_types_standalone/src/qvector2d.cxx.h" class QVector2DTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qvector3d.h b/tests/qt_types_standalone/cpp/qvector3d.h index 7cbeb672d..123d56310 100644 --- a/tests/qt_types_standalone/cpp/qvector3d.h +++ b/tests/qt_types_standalone/cpp/qvector3d.h @@ -9,7 +9,7 @@ #include #include -#include "qt_types_standalone/qvector3d.cxx.h" +#include "qt_types_standalone/src/qvector3d.cxx.h" class QVector3DTest : public QObject { diff --git a/tests/qt_types_standalone/cpp/qvector4d.h b/tests/qt_types_standalone/cpp/qvector4d.h index f480f7638..c928911df 100644 --- a/tests/qt_types_standalone/cpp/qvector4d.h +++ b/tests/qt_types_standalone/cpp/qvector4d.h @@ -9,7 +9,7 @@ #include #include -#include "qt_types_standalone/qvector4d.cxx.h" +#include "qt_types_standalone/src/qvector4d.cxx.h" class QVector4DTest : public QObject { From b7ab96eb278cf8f6b9b15863bf39ddac4682e6fa Mon Sep 17 00:00:00 2001 From: Andrew Hayzen Date: Thu, 18 Apr 2024 16:39:03 +0100 Subject: [PATCH 02/15] cxx-qt-gen: require cxx_file_stem until Span::source_file is stable Closes #855 --- CHANGELOG.md | 1 + book/src/bridge/extern_rustqt.md | 4 ++- book/src/bridge/index.md | 2 +- .../getting-started/5-cmake-integration.md | 10 ++++--- crates/cxx-qt-build/src/lib.rs | 9 ++----- crates/cxx-qt-gen/src/generator/cpp/mod.rs | 6 ++--- crates/cxx-qt-gen/src/generator/rust/mod.rs | 2 +- crates/cxx-qt-gen/src/parser/mod.rs | 27 ++++++++++++++++--- crates/cxx-qt-gen/test_inputs/inheritance.rs | 2 +- crates/cxx-qt-gen/test_inputs/invokables.rs | 2 +- crates/cxx-qt-gen/test_inputs/properties.rs | 2 +- crates/cxx-qt-gen/test_inputs/qenum.rs | 2 +- crates/cxx-qt-gen/test_inputs/shebang.rs | 2 +- crates/cxx-qt-gen/test_inputs/signals.rs | 2 +- crates/cxx-qt-gen/test_outputs/invokables.cpp | 2 +- crates/cxx-qt-gen/test_outputs/invokables.h | 2 +- crates/cxx-qt-gen/test_outputs/invokables.rs | 2 +- crates/cxx-qt-gen/test_outputs/properties.cpp | 2 +- crates/cxx-qt-gen/test_outputs/properties.h | 2 +- crates/cxx-qt-gen/test_outputs/properties.rs | 2 +- crates/cxx-qt-gen/test_outputs/qenum.cpp | 2 +- crates/cxx-qt-gen/test_outputs/qenum.h | 2 +- crates/cxx-qt-gen/test_outputs/qenum.rs | 2 +- crates/cxx-qt-gen/test_outputs/signals.cpp | 2 +- crates/cxx-qt-gen/test_outputs/signals.h | 2 +- crates/cxx-qt-gen/test_outputs/signals.rs | 2 +- examples/qml_minimal/rust/src/cxxqt_object.rs | 2 +- 27 files changed, 60 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ceb58a1a7..b1c13ea4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add CMake wrappers around corrosion to simplify importing crates and qml modules that were built with cxx-qt-build - CMake code has been extracted into a separate repository for faster downloads (kdab/cxx-qt-cmake) - Folder structure of Rust bridges is now considered in the same way as CXX in `CxxQtBuilder` +- All `#[cxx_qt::bridge]` macros must specify a `cxx_file_stem` until `Span::source_file()` is stable ### Removed diff --git a/book/src/bridge/extern_rustqt.md b/book/src/bridge/extern_rustqt.md index 6c05f68f5..8aa7f162e 100644 --- a/book/src/bridge/extern_rustqt.md +++ b/book/src/bridge/extern_rustqt.md @@ -23,7 +23,9 @@ mod ffi { The `extern "RustQt"` section of a CXX bridge declares Rust types and signatures to be made available to Qt and C++. -The CXX code generator uses your `extern "Rust"` section(s) to produce a C++ header file containing the corresponding C++ declarations. The generated header has a file name matching the module ident or the `cxx_file_stem` field in the `#[cxx_qt::bridge]` attribute and with a `.cxxqt.h` file extension. +The CXX code generator uses your `extern "Rust"` section(s) to produce a C++ header file containing the corresponding C++ declarations. The generated header has a file name of the `cxx_file_stem` field in the `#[cxx_qt::bridge]` attribute and with a `.cxxqt.h` file extension. + +> Note that once there is support for `source_file` or similar in the `Span` macro we want to support copying the file name like CXX. A bridge module may contain zero or more `extern "RustQt"` blocks. diff --git a/book/src/bridge/index.md b/book/src/bridge/index.md index 3cd4da9d6..e9adedf44 100644 --- a/book/src/bridge/index.md +++ b/book/src/bridge/index.md @@ -30,7 +30,7 @@ By default, the name of the generated C++ header file will be the name of the mo This can cause issues as the module is normally called `ffi` or `qobject`, so collisions would occur. -The `cxx_file_stem` option allow a file name to be specified to avoid collisions. +The `cxx_file_stem` option allows a file name to be specified to avoid collisions. ```rust,ignore {{#include ../../../examples/qml_features/rust/src/types.rs:book_cxx_file_stem}} diff --git a/book/src/getting-started/5-cmake-integration.md b/book/src/getting-started/5-cmake-integration.md index 6e47a9c97..d8d8e6e46 100644 --- a/book/src/getting-started/5-cmake-integration.md +++ b/book/src/getting-started/5-cmake-integration.md @@ -38,10 +38,14 @@ You can add as much C++ code as you want in addition to this. For every `#[cxx_qt::bridge]` that we define in Rust, CXX-Qt will generate a corresponding C++ header file. To include any of the generated files, use the crates name as the include directory. -The name of the header file will be the name of the Rust module of your `#[cxx_qt::bridge]`, followed by `.cxxqt.h`. -So in our case: `#include ` +The name of the header file will be the folder names, combined with the `cxx_file_stem` of your `#[cxx_qt::bridge]`, followed by `.cxxqt.h`. +So in our case: `#include ` -> Note that the [`cxx_file_stem`](../bridge/index.md#cxx_file_stem) option can be specified in the bridge macro to choose the file name. +> Note that the [`cxx_file_stem`](../bridge/index.md#cxx_file_stem) option must be specified in the bridge macro to choose the file name. + +> Note that once `Span::source_file()` is stable the `cxx_file_stem` will be optional and the file name will be the default like CXX> + +> Note any folders relative to the cargo manifest are considered hence the `src` folder. Including the generated header allows us to access the `MyObject` C++ class, just like any other C++ class. Inherit from it, connect signals and slots to it, put it in a QVector, do whatever you want with it. diff --git a/crates/cxx-qt-build/src/lib.rs b/crates/cxx-qt-build/src/lib.rs index 9c21e5207..526f42b59 100644 --- a/crates/cxx-qt-build/src/lib.rs +++ b/crates/cxx-qt-build/src/lib.rs @@ -138,13 +138,9 @@ impl GeneratedCpp { let rust_tokens = write_rust(&generated_rust); // Use the relative path with the cxx_file_stem - // - // TODO: ideally CXX-Qt would also use the file name - // but it uses the module or cxx_file_stem for now - // https://github.com/KDAB/cxx-qt/pull/200/commits/4861c92e66c3a022d3f0dedd9f8fd20db064b42b file_ident = relative_path .as_ref() - .with_file_name(parser.cxx_file_stem) + .with_file_name(parser.cxx_file_stem()) .to_str() .unwrap() .clone_into(&mut file_ident); @@ -275,7 +271,6 @@ fn generate_cxxqt_cpp_files( let mut generated_file_paths: Vec = Vec::with_capacity(rs_source.len()); for rs_path in rs_source { - let cpp_directory = cxx_qt_dir.join("src"); let path = manifest_dir.join(rs_path); println!("cargo:rerun-if-changed={}", path.to_string_lossy()); @@ -286,7 +281,7 @@ fn generate_cxxqt_cpp_files( std::process::exit(1); } }; - generated_file_paths.push(generated_code.write_to_directories(cpp_directory, &header_dir)); + generated_file_paths.push(generated_code.write_to_directories(cxx_qt_dir, &header_dir)); } generated_file_paths diff --git a/crates/cxx-qt-gen/src/generator/cpp/mod.rs b/crates/cxx-qt-gen/src/generator/cpp/mod.rs index 2830ae723..e337870b3 100644 --- a/crates/cxx-qt-gen/src/generator/cpp/mod.rs +++ b/crates/cxx-qt-gen/src/generator/cpp/mod.rs @@ -65,7 +65,7 @@ impl GeneratedCppBlocks { Ok(GeneratedCppBlocks { forward_declares, includes, - cxx_file_stem: parser.cxx_file_stem.clone(), + cxx_file_stem: parser.cxx_file_stem(), qobjects: structures .qobjects .iter() @@ -118,7 +118,7 @@ mod tests { #[test] fn test_generated_cpp_blocks() { let module: ItemMod = parse_quote! { - #[cxx_qt::bridge] + #[cxx_qt::bridge(cxx_file_stem = "ffi")] mod ffi { extern "RustQt" { #[qobject] @@ -156,7 +156,7 @@ mod tests { #[test] fn test_generated_cpp_blocks_namespace() { let module: ItemMod = parse_quote! { - #[cxx_qt::bridge(namespace = "cxx_qt")] + #[cxx_qt::bridge(cxx_file_stem = "ffi", namespace = "cxx_qt")] mod ffi { extern "RustQt" { #[qobject] diff --git a/crates/cxx-qt-gen/src/generator/rust/mod.rs b/crates/cxx-qt-gen/src/generator/rust/mod.rs index 87f55b972..5dc92b3d6 100644 --- a/crates/cxx-qt-gen/src/generator/rust/mod.rs +++ b/crates/cxx-qt-gen/src/generator/rust/mod.rs @@ -76,7 +76,7 @@ impl GeneratedRustBlocks { fn generate_include(parser: &Parser) -> Result { let import_path = format!( "{header_prefix}/{}.cxxqt.h", - parser.cxx_file_stem, + parser.cxx_file_stem(), header_prefix = writer::get_header_prefix() ); diff --git a/crates/cxx-qt-gen/src/parser/mod.rs b/crates/cxx-qt-gen/src/parser/mod.rs index 254928b26..d501dc06c 100644 --- a/crates/cxx-qt-gen/src/parser/mod.rs +++ b/crates/cxx-qt-gen/src/parser/mod.rs @@ -64,13 +64,13 @@ pub struct Parser { /// all type names that were found in this module, including CXX types pub(crate) type_names: TypeNames, /// The stem of the file that the CXX headers for this module will be generated into - pub cxx_file_stem: String, + pub(crate) cxx_file_stem: Option, } impl Parser { - fn parse_mod_attributes(module: &mut ItemMod) -> Result<(Option, String)> { + fn parse_mod_attributes(module: &mut ItemMod) -> Result<(Option, Option)> { let mut namespace = None; - let mut cxx_file_stem = module.ident.to_string(); + let mut cxx_file_stem = None; // Remove the cxx_qt::bridge attribute if let Some(attr) = attribute_take_path(&mut module.attrs, &["cxx_qt", "bridge"]) { @@ -86,13 +86,21 @@ impl Parser { namespace = Some(expr_to_string(&name_value.value)?); // Parse any custom file stem } else if name_value.path.is_ident("cxx_file_stem") { - cxx_file_stem = expr_to_string(&name_value.value)?; + cxx_file_stem = Some(expr_to_string(&name_value.value)?); } } _others => {} } } } + + // Temporary until Span::source_file() is stable + if cxx_file_stem.is_none() { + return Err(Error::new( + module.span(), + "All cxx_qt::bridge macros specify a cxx_file_stem until Span::source_file() is stable https://github.com/rust-lang/rust/issues/54725", + )); + } } else { return Err(Error::new( module.span(), @@ -171,6 +179,17 @@ impl Parser { cxx_file_stem, }) } + + /// Determine the file stem to use for this macro + pub fn cxx_file_stem(&self) -> String { + if let Some(cxx_file_stem) = self.cxx_file_stem.as_ref() { + cxx_file_stem.clone() + } else { + // TODO: ideally CXX-Qt would also use the file name but it uses the cxx_file_stem for now + // https://github.com/KDAB/cxx-qt/pull/200/commits/4861c92e66c3a022d3f0dedd9f8fd20db064b42b + unimplemented!("Missing cxx_file_stem, once Span::source_file() is stable we can determine the file name") + } + } } #[cfg(test)] diff --git a/crates/cxx-qt-gen/test_inputs/inheritance.rs b/crates/cxx-qt-gen/test_inputs/inheritance.rs index f3a9cf6e7..5f9e50638 100644 --- a/crates/cxx-qt-gen/test_inputs/inheritance.rs +++ b/crates/cxx-qt-gen/test_inputs/inheritance.rs @@ -1,4 +1,4 @@ -#[cxx_qt::bridge] +#[cxx_qt::bridge(cxx_file_stem = "inheritance")] mod inheritance { extern "C++" { include!("cxx-qt-lib/qmodelindex.h"); diff --git a/crates/cxx-qt-gen/test_inputs/invokables.rs b/crates/cxx-qt-gen/test_inputs/invokables.rs index 17f5e1e92..d08b2e1f4 100644 --- a/crates/cxx-qt-gen/test_inputs/invokables.rs +++ b/crates/cxx-qt-gen/test_inputs/invokables.rs @@ -1,4 +1,4 @@ -#[cxx_qt::bridge(namespace = "cxx_qt::my_object")] +#[cxx_qt::bridge(cxx_file_stem = "invokables", namespace = "cxx_qt::my_object")] mod ffi { #[namespace = ""] unsafe extern "C++" { diff --git a/crates/cxx-qt-gen/test_inputs/properties.rs b/crates/cxx-qt-gen/test_inputs/properties.rs index 3e07fae22..fa7a5c8b1 100644 --- a/crates/cxx-qt-gen/test_inputs/properties.rs +++ b/crates/cxx-qt-gen/test_inputs/properties.rs @@ -1,4 +1,4 @@ -#[cxx_qt::bridge(namespace = "cxx_qt::my_object")] +#[cxx_qt::bridge(cxx_file_stem = "properties", namespace = "cxx_qt::my_object")] mod ffi { #[namespace = ""] unsafe extern "C++" { diff --git a/crates/cxx-qt-gen/test_inputs/qenum.rs b/crates/cxx-qt-gen/test_inputs/qenum.rs index c485c8380..06740d157 100644 --- a/crates/cxx-qt-gen/test_inputs/qenum.rs +++ b/crates/cxx-qt-gen/test_inputs/qenum.rs @@ -1,4 +1,4 @@ -#[cxx_qt::bridge(namespace = "cxx_qt::my_object")] +#[cxx_qt::bridge(cxx_file_stem = "qenum", namespace = "cxx_qt::my_object")] mod ffi { #[qenum(MyObject)] enum MyEnum { diff --git a/crates/cxx-qt-gen/test_inputs/shebang.rs b/crates/cxx-qt-gen/test_inputs/shebang.rs index 80832760b..b24fa2bae 100644 --- a/crates/cxx-qt-gen/test_inputs/shebang.rs +++ b/crates/cxx-qt-gen/test_inputs/shebang.rs @@ -1,6 +1,6 @@ #!/usr/bin/ // Test for qtitem and qtfile, for code coverage -#[cxx_qt::bridge] +#[cxx_qt::bridge(cxx_file_stem = "shebang")] mod ffi { extern "RustQt" { #[qobject] diff --git a/crates/cxx-qt-gen/test_inputs/signals.rs b/crates/cxx-qt-gen/test_inputs/signals.rs index 3aca1f5bd..2c35a0e1e 100644 --- a/crates/cxx-qt-gen/test_inputs/signals.rs +++ b/crates/cxx-qt-gen/test_inputs/signals.rs @@ -1,4 +1,4 @@ -#[cxx_qt::bridge(namespace = "cxx_qt::my_object")] +#[cxx_qt::bridge(cxx_file_stem = "signals", namespace = "cxx_qt::my_object")] mod ffi { #[namespace = ""] unsafe extern "C++" { diff --git a/crates/cxx-qt-gen/test_outputs/invokables.cpp b/crates/cxx-qt-gen/test_outputs/invokables.cpp index 4d53fb901..83a95b09b 100644 --- a/crates/cxx-qt-gen/test_outputs/invokables.cpp +++ b/crates/cxx-qt-gen/test_outputs/invokables.cpp @@ -1,4 +1,4 @@ -#include "cxx-qt-gen/ffi.cxxqt.h" +#include "cxx-qt-gen/invokables.cxxqt.h" namespace cxx_qt::my_object { static_assert(alignof(MyObjectCxxQtThread) <= alignof(::std::size_t), diff --git a/crates/cxx-qt-gen/test_outputs/invokables.h b/crates/cxx-qt-gen/test_outputs/invokables.h index 89f1f1b46..96bcc59bd 100644 --- a/crates/cxx-qt-gen/test_outputs/invokables.h +++ b/crates/cxx-qt-gen/test_outputs/invokables.h @@ -9,7 +9,7 @@ using MyObjectCxxQtThread = ::rust::cxxqt1::CxxQtThread; } // namespace cxx_qt::my_object -#include "cxx-qt-gen/ffi.cxx.h" +#include "cxx-qt-gen/invokables.cxx.h" namespace cxx_qt::my_object { class MyObject diff --git a/crates/cxx-qt-gen/test_outputs/invokables.rs b/crates/cxx-qt-gen/test_outputs/invokables.rs index 133e20b3c..d5735b99d 100644 --- a/crates/cxx-qt-gen/test_outputs/invokables.rs +++ b/crates/cxx-qt-gen/test_outputs/invokables.rs @@ -25,7 +25,7 @@ mod ffi { type QMetaObjectConnection = cxx_qt::QMetaObjectConnection; } unsafe extern "C++" { - include!("cxx-qt-gen/ffi.cxxqt.h"); + include!("cxx-qt-gen/invokables.cxxqt.h"); } unsafe extern "C++" { #[doc = "The C++ type for the QObject "] diff --git a/crates/cxx-qt-gen/test_outputs/properties.cpp b/crates/cxx-qt-gen/test_outputs/properties.cpp index b9548f759..6f161d596 100644 --- a/crates/cxx-qt-gen/test_outputs/properties.cpp +++ b/crates/cxx-qt-gen/test_outputs/properties.cpp @@ -1,4 +1,4 @@ -#include "cxx-qt-gen/ffi.cxxqt.h" +#include "cxx-qt-gen/properties.cxxqt.h" // Define namespace otherwise we hit a GCC bug // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 diff --git a/crates/cxx-qt-gen/test_outputs/properties.h b/crates/cxx-qt-gen/test_outputs/properties.h index f3185a12b..179b1f411 100644 --- a/crates/cxx-qt-gen/test_outputs/properties.h +++ b/crates/cxx-qt-gen/test_outputs/properties.h @@ -30,7 +30,7 @@ using MyObjectCxxQtSignalHandlermyOnChanged = ::rust::cxxqt1::SignalHandler; } // namespace cxx_qt::my_object::rust::cxxqtgen1 -#include "cxx-qt-gen/ffi.cxx.h" +#include "cxx-qt-gen/properties.cxx.h" namespace cxx_qt::my_object::rust::cxxqtgen1 { ::QMetaObject::Connection diff --git a/crates/cxx-qt-gen/test_outputs/properties.rs b/crates/cxx-qt-gen/test_outputs/properties.rs index 8c245d690..e36605981 100644 --- a/crates/cxx-qt-gen/test_outputs/properties.rs +++ b/crates/cxx-qt-gen/test_outputs/properties.rs @@ -18,7 +18,7 @@ mod ffi { type QMetaObjectConnection = cxx_qt::QMetaObjectConnection; } unsafe extern "C++" { - include!("cxx-qt-gen/ffi.cxxqt.h"); + include!("cxx-qt-gen/properties.cxxqt.h"); } unsafe extern "C++" { #[doc = "The C++ type for the QObject "] diff --git a/crates/cxx-qt-gen/test_outputs/qenum.cpp b/crates/cxx-qt-gen/test_outputs/qenum.cpp index 494016416..0feeb476a 100644 --- a/crates/cxx-qt-gen/test_outputs/qenum.cpp +++ b/crates/cxx-qt-gen/test_outputs/qenum.cpp @@ -1,4 +1,4 @@ -#include "cxx-qt-gen/ffi.cxxqt.h" +#include "cxx-qt-gen/qenum.cxxqt.h" namespace cxx_qt::my_object { MyObject::MyObject(QObject* parent) diff --git a/crates/cxx-qt-gen/test_outputs/qenum.h b/crates/cxx-qt-gen/test_outputs/qenum.h index 9b3cb157a..9fc671105 100644 --- a/crates/cxx-qt-gen/test_outputs/qenum.h +++ b/crates/cxx-qt-gen/test_outputs/qenum.h @@ -70,7 +70,7 @@ enum class MyRenamedEnum : ::std::int32_t }; } // namespace cxx_qt::my_object -#include "cxx-qt-gen/ffi.cxx.h" +#include "cxx-qt-gen/qenum.cxx.h" namespace cxx_qt::my_object { class MyObject diff --git a/crates/cxx-qt-gen/test_outputs/qenum.rs b/crates/cxx-qt-gen/test_outputs/qenum.rs index 1ba0706d0..1bdc0d9f4 100644 --- a/crates/cxx-qt-gen/test_outputs/qenum.rs +++ b/crates/cxx-qt-gen/test_outputs/qenum.rs @@ -62,7 +62,7 @@ mod ffi { type MyRenamedEnum; } unsafe extern "C++" { - include!("cxx-qt-gen/ffi.cxxqt.h"); + include!("cxx-qt-gen/qenum.cxxqt.h"); } unsafe extern "C++" { #[doc = "The C++ type for the QObject "] diff --git a/crates/cxx-qt-gen/test_outputs/signals.cpp b/crates/cxx-qt-gen/test_outputs/signals.cpp index 361f34a57..62b3843cb 100644 --- a/crates/cxx-qt-gen/test_outputs/signals.cpp +++ b/crates/cxx-qt-gen/test_outputs/signals.cpp @@ -1,4 +1,4 @@ -#include "cxx-qt-gen/ffi.cxxqt.h" +#include "cxx-qt-gen/signals.cxxqt.h" // Define namespace otherwise we hit a GCC bug // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 diff --git a/crates/cxx-qt-gen/test_outputs/signals.h b/crates/cxx-qt-gen/test_outputs/signals.h index 19e585838..d764206c7 100644 --- a/crates/cxx-qt-gen/test_outputs/signals.h +++ b/crates/cxx-qt-gen/test_outputs/signals.h @@ -28,7 +28,7 @@ using QTimerCxxQtSignalHandlertimeout = ::rust::cxxqt1::SignalHandler; } // namespace cxx_qt::my_object::rust::cxxqtgen1 -#include "cxx-qt-gen/ffi.cxx.h" +#include "cxx-qt-gen/signals.cxx.h" namespace cxx_qt::my_object::rust::cxxqtgen1 { ::QMetaObject::Connection diff --git a/crates/cxx-qt-gen/test_outputs/signals.rs b/crates/cxx-qt-gen/test_outputs/signals.rs index aaecc0c75..2bfa6d1df 100644 --- a/crates/cxx-qt-gen/test_outputs/signals.rs +++ b/crates/cxx-qt-gen/test_outputs/signals.rs @@ -19,7 +19,7 @@ mod ffi { type QMetaObjectConnection = cxx_qt::QMetaObjectConnection; } unsafe extern "C++" { - include!("cxx-qt-gen/ffi.cxxqt.h"); + include!("cxx-qt-gen/signals.cxxqt.h"); } unsafe extern "C++" { #[doc = "The C++ type for the QObject "] diff --git a/examples/qml_minimal/rust/src/cxxqt_object.rs b/examples/qml_minimal/rust/src/cxxqt_object.rs index e469b319e..a48b785ba 100644 --- a/examples/qml_minimal/rust/src/cxxqt_object.rs +++ b/examples/qml_minimal/rust/src/cxxqt_object.rs @@ -9,7 +9,7 @@ // ANCHOR: book_bridge_macro /// The bridge definition for our QObject -#[cxx_qt::bridge] +#[cxx_qt::bridge(cxx_file_stem = "cxxqt_object")] pub mod qobject { // ANCHOR_END: book_bridge_macro From cd523e051874f4a876d5e3873044c1c972f25361 Mon Sep 17 00:00:00 2001 From: Andrew Hayzen Date: Wed, 4 Sep 2024 11:45:41 +0100 Subject: [PATCH 03/15] cxx-qt-gen: change writer phase to take include path from cxx-qt-build --- crates/cxx-qt-build/Cargo.toml | 1 + crates/cxx-qt-build/src/lib.rs | 46 +++++++++---------- crates/cxx-qt-gen/src/generator/rust/mod.rs | 21 +-------- crates/cxx-qt-gen/src/lib.rs | 7 ++- crates/cxx-qt-gen/src/writer/cpp/header.rs | 17 +++---- crates/cxx-qt-gen/src/writer/cpp/mod.rs | 15 +++--- crates/cxx-qt-gen/src/writer/cpp/source.rs | 15 +++--- crates/cxx-qt-gen/src/writer/mod.rs | 16 ------- crates/cxx-qt-gen/src/writer/rust/mod.rs | 33 ++++++++++--- .../cxx-qt-gen/test_outputs/inheritance.cpp | 2 +- crates/cxx-qt-gen/test_outputs/inheritance.h | 2 +- crates/cxx-qt-gen/test_outputs/inheritance.rs | 2 +- crates/cxx-qt-gen/test_outputs/invokables.cpp | 2 +- crates/cxx-qt-gen/test_outputs/invokables.h | 2 +- crates/cxx-qt-gen/test_outputs/invokables.rs | 2 +- .../test_outputs/passthrough_and_naming.cpp | 2 +- .../test_outputs/passthrough_and_naming.h | 2 +- .../test_outputs/passthrough_and_naming.rs | 2 +- crates/cxx-qt-gen/test_outputs/properties.cpp | 2 +- crates/cxx-qt-gen/test_outputs/properties.h | 2 +- crates/cxx-qt-gen/test_outputs/properties.rs | 2 +- crates/cxx-qt-gen/test_outputs/qenum.cpp | 2 +- crates/cxx-qt-gen/test_outputs/qenum.h | 2 +- crates/cxx-qt-gen/test_outputs/qenum.rs | 6 +-- crates/cxx-qt-gen/test_outputs/signals.cpp | 2 +- crates/cxx-qt-gen/test_outputs/signals.h | 2 +- crates/cxx-qt-gen/test_outputs/signals.rs | 2 +- crates/cxx-qt-macro/src/lib.rs | 2 +- 28 files changed, 97 insertions(+), 116 deletions(-) diff --git a/crates/cxx-qt-build/Cargo.toml b/crates/cxx-qt-build/Cargo.toml index 1aa11fdac..bf100dde6 100644 --- a/crates/cxx-qt-build/Cargo.toml +++ b/crates/cxx-qt-build/Cargo.toml @@ -24,6 +24,7 @@ codespan-reporting = "0.11" version_check = "0.9" serde = { version = "1.0", features = ["default", "derive"] } serde_json = "1.0" +syn.workspace = true [features] link_qt_object_files = ["qt-build-utils/link_qt_object_files"] diff --git a/crates/cxx-qt-build/src/lib.rs b/crates/cxx-qt-build/src/lib.rs index 526f42b59..5cb1d22aa 100644 --- a/crates/cxx-qt-build/src/lib.rs +++ b/crates/cxx-qt-build/src/lib.rs @@ -89,38 +89,42 @@ impl GeneratedCpp { tokens.extend(attr.into_token_stream()); } + // Match upstream where they use the file name and folders as the ident + // + // We need the relative path here as we want the folders + relative_path + .as_ref() + // Remove the .rs extension + .with_extension("") + .to_str() + .unwrap() + .clone_into(&mut file_ident); + // Loop through the items looking for any CXX or CXX-Qt blocks + let mut found_bridge = false; for item in &file.items { match item { CxxQtItem::Cxx(m) => { // TODO: later we will allow for multiple CXX or CXX-Qt blocks in one file - if !file_ident.is_empty() { + if found_bridge { panic!( "Unfortunately only files with either a single cxx or a single cxx_qt module are currently supported. The file {} has more than one of these.", rust_file_path.display()); } + found_bridge = true; - // Match upstream where they use the file name and folders as the ident - // - // We need the relative path here as we want the folders - relative_path - .as_ref() - // Remove the .rs extension - .with_extension("") - .to_str() - .unwrap() - .clone_into(&mut file_ident); tokens.extend(m.into_token_stream()); } CxxQtItem::CxxQt(m) => { // TODO: later we will allow for multiple CXX or CXX-Qt blocks in one file - if !file_ident.is_empty() { + if found_bridge { panic!( "Unfortunately only files with either a single cxx or a single cxx_qt module are currently supported. The file {} has more than one of these.", rust_file_path.display()); } + found_bridge = true; let parser = Parser::from(m.clone()) .map_err(GeneratedError::from) @@ -128,22 +132,14 @@ impl GeneratedCpp { let generated_cpp = GeneratedCppBlocks::from(&parser) .map_err(GeneratedError::from) .map_err(to_diagnostic)?; - // TODO: we'll have to extend the C++ data here rather than overwriting - // assuming we share the same file - cxx_qt = Some(write_cpp(&generated_cpp)); - let generated_rust = GeneratedRustBlocks::from(&parser) .map_err(GeneratedError::from) .map_err(to_diagnostic)?; - let rust_tokens = write_rust(&generated_rust); - - // Use the relative path with the cxx_file_stem - file_ident = relative_path - .as_ref() - .with_file_name(parser.cxx_file_stem()) - .to_str() - .unwrap() - .clone_into(&mut file_ident); + + // TODO: we'll have to extend the C++ data here rather than overwriting + // assuming we share the same file + cxx_qt = Some(write_cpp(&generated_cpp, &file_ident)); + let rust_tokens = write_rust(&generated_rust, Some(&file_ident)); // We need to do this and can't rely on the macro, as we need to generate the // CXX bridge Rust code that is then fed into the cxx_gen generation. diff --git a/crates/cxx-qt-gen/src/generator/rust/mod.rs b/crates/cxx-qt-gen/src/generator/rust/mod.rs index 5dc92b3d6..419c2e60b 100644 --- a/crates/cxx-qt-gen/src/generator/rust/mod.rs +++ b/crates/cxx-qt-gen/src/generator/rust/mod.rs @@ -19,7 +19,6 @@ use crate::generator::rust::fragment::GeneratedRustFragment; use crate::generator::structuring; use crate::parser::parameter::ParsedFunctionParameter; use crate::parser::Parser; -use crate::writer; use proc_macro2::{Ident, TokenStream}; use quote::quote; use syn::{Item, ItemMod, Result}; @@ -60,33 +59,15 @@ impl GeneratedRustBlocks { .collect::>>()?, ); - let mut cxx_mod_contents = qenum::generate_cxx_mod_contents(&parser.cxx_qt_data.qenums); - cxx_mod_contents.push(generate_include(parser)?); - Ok(GeneratedRustBlocks { cxx_mod: parser.passthrough_module.clone(), - cxx_mod_contents, + cxx_mod_contents: qenum::generate_cxx_mod_contents(&parser.cxx_qt_data.qenums), namespace: parser.cxx_qt_data.namespace.clone().unwrap_or_default(), fragments, }) } } -/// Generate the include line for this parsed block -fn generate_include(parser: &Parser) -> Result { - let import_path = format!( - "{header_prefix}/{}.cxxqt.h", - parser.cxx_file_stem(), - header_prefix = writer::get_header_prefix() - ); - - syn::parse2(quote! { - unsafe extern "C++" { - include!(#import_path); - } - }) -} - /// Return the [TokenStream] of the parsed parameters for use in generation pub fn get_params_tokens( mutable: bool, diff --git a/crates/cxx-qt-gen/src/lib.rs b/crates/cxx-qt-gen/src/lib.rs index 2a3454f31..913ec1fe5 100644 --- a/crates/cxx-qt-gen/src/lib.rs +++ b/crates/cxx-qt-gen/src/lib.rs @@ -159,12 +159,15 @@ mod tests { let parser = Parser::from(syn::parse_str(input).unwrap()).unwrap(); let generated_cpp = GeneratedCppBlocks::from(&parser).unwrap(); - let (mut header, mut source) = require_pair(&write_cpp(&generated_cpp)).unwrap(); + let (mut header, mut source) = + require_pair(&write_cpp(&generated_cpp, "directory/file_ident")).unwrap(); header = sanitize_code(header); source = sanitize_code(source); let generated_rust = GeneratedRustBlocks::from(&parser).unwrap(); - let rust = sanitize_code(format_rs_source(&write_rust(&generated_rust).to_string())); + let rust = sanitize_code(format_rs_source( + &write_rust(&generated_rust, Some("directory/file_ident")).to_string(), + )); // CODECOV_EXCLUDE_START if !update_expected(test_name, &rust, &header, &source) { diff --git a/crates/cxx-qt-gen/src/writer/cpp/header.rs b/crates/cxx-qt-gen/src/writer/cpp/header.rs index 35dbba9a3..20dbe5e94 100644 --- a/crates/cxx-qt-gen/src/writer/cpp/header.rs +++ b/crates/cxx-qt-gen/src/writer/cpp/header.rs @@ -6,8 +6,7 @@ use std::collections::BTreeSet; use crate::generator::cpp::GeneratedCppBlocks; -use crate::writer::cpp::{extract_extern_qt, pair_as_header}; -use crate::writer::{self, cpp::namespaced}; +use crate::writer::cpp::{extract_extern_qt, namespaced, pair_as_header}; use indoc::formatdoc; /// With a given block name, join the given items and add them under the block @@ -128,7 +127,7 @@ fn qobjects_header(generated: &GeneratedCppBlocks) -> Vec { } /// For a given GeneratedCppBlocks write this into a C++ header -pub fn write_cpp_header(generated: &GeneratedCppBlocks) -> String { +pub fn write_cpp_header(generated: &GeneratedCppBlocks, include_path: &str) -> String { let includes = { let mut include_set = BTreeSet::new(); include_set.extend( @@ -162,15 +161,13 @@ pub fn write_cpp_header(generated: &GeneratedCppBlocks) -> String { {includes} {forward_declare} - #include "{header_prefix}/{cxx_file_stem}.cxx.h" + #include "{include_path}.cxx.h" {extern_cxx_qt} {qobjects} "#, - cxx_file_stem = generated.cxx_file_stem, forward_declare = forward_declare(generated).join("\n"), qobjects = qobjects_header(generated).join("\n"), - header_prefix = writer::get_header_prefix() } } @@ -217,21 +214,21 @@ mod tests { #[test] fn test_write_cpp_header() { let generated = create_generated_cpp(); - let output = write_cpp_header(&generated); + let output = write_cpp_header(&generated, "cxx-qt-gen/cxx_file_stem"); assert_str_eq!(output, expected_header()); } #[test] fn test_write_cpp_header_multi_qobjects() { let generated = create_generated_cpp_multi_qobjects(); - let output = write_cpp_header(&generated); + let output = write_cpp_header(&generated, "cxx-qt-gen/cxx_file_stem"); assert_str_eq!(output, expected_header_multi_qobjects()); } #[test] fn test_write_cpp_header_no_namespace() { let generated = create_generated_cpp_no_namespace(); - let output = write_cpp_header(&generated); + let output = write_cpp_header(&generated, "cxx-qt-gen/cxx_file_stem"); assert_str_eq!(output, expected_header_no_namespace()); } @@ -250,7 +247,7 @@ mod tests { let parser = Parser::from(module.clone()).unwrap(); let generated = GeneratedCppBlocks::from(&parser).unwrap(); - let header = write_cpp_header(&generated); + let header = write_cpp_header(&generated, "cxx-qt-gen/ffi"); let expected = indoc! {r#" #pragma once diff --git a/crates/cxx-qt-gen/src/writer/cpp/mod.rs b/crates/cxx-qt-gen/src/writer/cpp/mod.rs index 1d290d20c..746ad0861 100644 --- a/crates/cxx-qt-gen/src/writer/cpp/mod.rs +++ b/crates/cxx-qt-gen/src/writer/cpp/mod.rs @@ -26,9 +26,9 @@ pub fn namespaced(namespace: &str, cpp_code: &str) -> String { } /// For a given GeneratedCppBlocks write this into a C++ header and source pair -pub fn write_cpp(generated: &GeneratedCppBlocks) -> CppFragment { - let header = write_cpp_header(generated); - let source = write_cpp_source(generated); +pub fn write_cpp(generated: &GeneratedCppBlocks, include_path: &str) -> CppFragment { + let header = write_cpp_header(generated, include_path); + let source = write_cpp_source(generated, include_path); CppFragment::Pair { header: clang_format_with_style(&header, &ClangFormatStyle::File).unwrap_or(header), @@ -698,7 +698,8 @@ mod tests { #[test] fn test_write_cpp() { let generated = create_generated_cpp(); - let (header, source) = require_pair(&write_cpp(&generated)).unwrap(); + let (header, source) = + require_pair(&write_cpp(&generated, "cxx-qt-gen/cxx_file_stem")).unwrap(); assert_str_eq!(header, format_cpp(expected_header())); assert_str_eq!(source, format_cpp(expected_source())); } @@ -706,7 +707,8 @@ mod tests { #[test] fn test_write_cpp_multi_qobjects() { let generated = create_generated_cpp_multi_qobjects(); - let (header, source) = require_pair(&write_cpp(&generated)).unwrap(); + let (header, source) = + require_pair(&write_cpp(&generated, "cxx-qt-gen/cxx_file_stem")).unwrap(); assert_str_eq!(header, format_cpp(expected_header_multi_qobjects())); assert_str_eq!(source, format_cpp(expected_source_multi_qobjects())); } @@ -714,7 +716,8 @@ mod tests { #[test] fn test_write_cpp_no_namespace() { let generated = create_generated_cpp_no_namespace(); - let (header, source) = require_pair(&write_cpp(&generated)).unwrap(); + let (header, source) = + require_pair(&write_cpp(&generated, "cxx-qt-gen/cxx_file_stem")).unwrap(); assert_str_eq!(header, format_cpp(expected_header_no_namespace())); assert_str_eq!(source, format_cpp(expected_source_no_namespace())); } diff --git a/crates/cxx-qt-gen/src/writer/cpp/source.rs b/crates/cxx-qt-gen/src/writer/cpp/source.rs index acd2cc66b..3452434aa 100644 --- a/crates/cxx-qt-gen/src/writer/cpp/source.rs +++ b/crates/cxx-qt-gen/src/writer/cpp/source.rs @@ -4,8 +4,7 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 use crate::generator::cpp::GeneratedCppBlocks; -use crate::writer::cpp::{extract_extern_qt, pair_as_source}; -use crate::writer::{self, cpp::namespaced}; +use crate::writer::cpp::{extract_extern_qt, namespaced, pair_as_source}; use indoc::formatdoc; /// For a given GeneratedCppBlocks write the implementations @@ -37,18 +36,16 @@ fn qobjects_source(generated: &GeneratedCppBlocks) -> Vec { } /// For a given GeneratedCppBlocks write this into a C++ source -pub fn write_cpp_source(generated: &GeneratedCppBlocks) -> String { +pub fn write_cpp_source(generated: &GeneratedCppBlocks, include_path: &str) -> String { let extern_cxx_qt = extract_extern_qt(generated, pair_as_source); formatdoc! {r#" - #include "{header_prefix}/{cxx_file_stem}.cxxqt.h" + #include "{include_path}.cxxqt.h" {extern_cxx_qt} {qobjects} "#, - cxx_file_stem = generated.cxx_file_stem, qobjects = qobjects_source(generated).join("\n"), - header_prefix = writer::get_header_prefix(), } } @@ -66,21 +63,21 @@ mod tests { #[test] fn test_write_cpp_source() { let generated = create_generated_cpp(); - let output = write_cpp_source(&generated); + let output = write_cpp_source(&generated, "cxx-qt-gen/cxx_file_stem"); assert_str_eq!(output, expected_source()); } #[test] fn test_write_cpp_source_multi_qobjects() { let generated = create_generated_cpp_multi_qobjects(); - let output = write_cpp_source(&generated); + let output = write_cpp_source(&generated, "cxx-qt-gen/cxx_file_stem"); assert_str_eq!(output, expected_source_multi_qobjects()); } #[test] fn test_write_cpp_source_no_namespace() { let generated = create_generated_cpp_no_namespace(); - let output = write_cpp_source(&generated); + let output = write_cpp_source(&generated, "cxx-qt-gen/cxx_file_stem"); assert_str_eq!(output, expected_source_no_namespace()); } } diff --git a/crates/cxx-qt-gen/src/writer/mod.rs b/crates/cxx-qt-gen/src/writer/mod.rs index 56aad0aaa..486ef1423 100644 --- a/crates/cxx-qt-gen/src/writer/mod.rs +++ b/crates/cxx-qt-gen/src/writer/mod.rs @@ -5,19 +5,3 @@ pub mod cpp; pub mod rust; - -use std::{error::Error, path::PathBuf}; - -fn header_prefix_from_out_dir() -> Result> { - // This file should be written by cxx-qt-build - let header_prefix_path = PathBuf::from(std::env::var("OUT_DIR")?) - // CODECOV_EXCLUDE_START - .join("cxx-qt-gen") - .join("include-prefix.txt"); - Ok(std::fs::read_to_string(header_prefix_path)?) - // CODECOV_EXCLUDE_STOP -} - -pub(crate) fn get_header_prefix() -> String { - header_prefix_from_out_dir().unwrap_or_else(|_err| "cxx-qt-gen".to_owned()) -} diff --git a/crates/cxx-qt-gen/src/writer/rust/mod.rs b/crates/cxx-qt-gen/src/writer/rust/mod.rs index 291a912d4..ff24986fc 100644 --- a/crates/cxx-qt-gen/src/writer/rust/mod.rs +++ b/crates/cxx-qt-gen/src/writer/rust/mod.rs @@ -6,9 +6,10 @@ use crate::generator::rust::GeneratedRustBlocks; use proc_macro2::TokenStream; use quote::{quote, ToTokens}; +use syn::{parse_quote_spanned, spanned::Spanned}; /// For a given GeneratedRustBlocks write this into a Rust TokenStream -pub fn write_rust(generated: &GeneratedRustBlocks) -> TokenStream { +pub fn write_rust(generated: &GeneratedRustBlocks, include_path: Option<&str>) -> TokenStream { // Retrieve the module contents and namespace let mut cxx_mod = generated.cxx_mod.clone(); let mut cxx_mod_contents = generated.cxx_mod_contents.clone(); @@ -18,7 +19,7 @@ pub fn write_rust(generated: &GeneratedRustBlocks) -> TokenStream { // Add common includes for all objects cxx_mod_contents.insert( 0, - syn::parse2(quote! { + parse_quote_spanned! {cxx_mod.span() => unsafe extern "C++" { include ! (< QtCore / QObject >); @@ -37,10 +38,28 @@ pub fn write_rust(generated: &GeneratedRustBlocks) -> TokenStream { #[rust_name = "CxxQtQMetaObjectConnection"] type QMetaObjectConnection = cxx_qt::QMetaObjectConnection; } - }) - .expect("Could not build CXX common block"), + }, ); + // Inject the include path if we have one after the common CXX block + // + // We only generate the include when we are from the build script + // as in Rust macro expansion the include isn't relevant + // + // This is useful as then we don't need Span::source_file() to be stable + // but can use the name of the file from the build script. + if let Some(include_path) = include_path { + let import_path = format!("{include_path}.cxxqt.h"); + cxx_mod_contents.insert( + 1, + parse_quote_spanned! {cxx_mod.span() => + unsafe extern "C++" { + include!(#import_path); + } + }, + ); + } + for fragment in &generated.fragments { // Add the blocks from the fragment cxx_mod_contents.extend_from_slice(&fragment.cxx_mod_contents); @@ -298,7 +317,7 @@ mod tests { #[test] fn test_write_rust() { let generated = create_generated_rust(); - let result = write_rust(&generated); + let result = write_rust(&generated, Some("myobject")); assert_str_eq!(result.to_string(), expected_rust()); } @@ -311,13 +330,13 @@ mod tests { let parser = Parser::from(module).unwrap(); let generated = GeneratedRustBlocks::from(&parser).unwrap(); - write_rust(&generated); + write_rust(&generated, None); } #[test] fn test_write_rust_multi_qobjects() { let generated = create_generated_rust_multi_qobjects(); - let result = write_rust(&generated); + let result = write_rust(&generated, Some("multiobject")); assert_str_eq!(result.to_string(), expected_rust_multi_qobjects()); } } diff --git a/crates/cxx-qt-gen/test_outputs/inheritance.cpp b/crates/cxx-qt-gen/test_outputs/inheritance.cpp index 0d108085b..40f06b9ea 100644 --- a/crates/cxx-qt-gen/test_outputs/inheritance.cpp +++ b/crates/cxx-qt-gen/test_outputs/inheritance.cpp @@ -1,4 +1,4 @@ -#include "cxx-qt-gen/inheritance.cxxqt.h" +#include "directory/file_ident.cxxqt.h" MyObject::MyObject(QObject* parent) : QAbstractItemModel(parent) diff --git a/crates/cxx-qt-gen/test_outputs/inheritance.h b/crates/cxx-qt-gen/test_outputs/inheritance.h index aaf7ebbf5..961e1d51e 100644 --- a/crates/cxx-qt-gen/test_outputs/inheritance.h +++ b/crates/cxx-qt-gen/test_outputs/inheritance.h @@ -4,7 +4,7 @@ class MyObject; -#include "cxx-qt-gen/inheritance.cxx.h" +#include "directory/file_ident.cxx.h" class MyObject : public QAbstractItemModel diff --git a/crates/cxx-qt-gen/test_outputs/inheritance.rs b/crates/cxx-qt-gen/test_outputs/inheritance.rs index ae625b49c..a8f65750f 100644 --- a/crates/cxx-qt-gen/test_outputs/inheritance.rs +++ b/crates/cxx-qt-gen/test_outputs/inheritance.rs @@ -19,7 +19,7 @@ mod inheritance { type QMetaObjectConnection = cxx_qt::QMetaObjectConnection; } unsafe extern "C++" { - include!("cxx-qt-gen/inheritance.cxxqt.h"); + include!("directory/file_ident.cxxqt.h"); } unsafe extern "C++" { #[doc = "The C++ type for the QObject "] diff --git a/crates/cxx-qt-gen/test_outputs/invokables.cpp b/crates/cxx-qt-gen/test_outputs/invokables.cpp index 83a95b09b..cce70af78 100644 --- a/crates/cxx-qt-gen/test_outputs/invokables.cpp +++ b/crates/cxx-qt-gen/test_outputs/invokables.cpp @@ -1,4 +1,4 @@ -#include "cxx-qt-gen/invokables.cxxqt.h" +#include "directory/file_ident.cxxqt.h" namespace cxx_qt::my_object { static_assert(alignof(MyObjectCxxQtThread) <= alignof(::std::size_t), diff --git a/crates/cxx-qt-gen/test_outputs/invokables.h b/crates/cxx-qt-gen/test_outputs/invokables.h index 96bcc59bd..f5f2aed21 100644 --- a/crates/cxx-qt-gen/test_outputs/invokables.h +++ b/crates/cxx-qt-gen/test_outputs/invokables.h @@ -9,7 +9,7 @@ using MyObjectCxxQtThread = ::rust::cxxqt1::CxxQtThread; } // namespace cxx_qt::my_object -#include "cxx-qt-gen/invokables.cxx.h" +#include "directory/file_ident.cxx.h" namespace cxx_qt::my_object { class MyObject diff --git a/crates/cxx-qt-gen/test_outputs/invokables.rs b/crates/cxx-qt-gen/test_outputs/invokables.rs index d5735b99d..8dd37a601 100644 --- a/crates/cxx-qt-gen/test_outputs/invokables.rs +++ b/crates/cxx-qt-gen/test_outputs/invokables.rs @@ -25,7 +25,7 @@ mod ffi { type QMetaObjectConnection = cxx_qt::QMetaObjectConnection; } unsafe extern "C++" { - include!("cxx-qt-gen/invokables.cxxqt.h"); + include!("directory/file_ident.cxxqt.h"); } unsafe extern "C++" { #[doc = "The C++ type for the QObject "] diff --git a/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.cpp b/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.cpp index 034886800..5228d753a 100644 --- a/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.cpp +++ b/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.cpp @@ -1,4 +1,4 @@ -#include "cxx-qt-gen/multi_object.cxxqt.h" +#include "directory/file_ident.cxxqt.h" // Define namespace otherwise we hit a GCC bug // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 diff --git a/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.h b/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.h index 836032115..64227bf20 100644 --- a/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.h +++ b/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.h @@ -56,7 +56,7 @@ using ExternObjectCxxQtSignalHandlererrorOccurred = struct ExternObjectCxxQtSignalParamserrorOccurred*>; } // namespace mynamespace::rust::cxxqtgen1 -#include "cxx-qt-gen/multi_object.cxx.h" +#include "directory/file_ident.cxx.h" namespace rust::cxxqtgen1 { ::QMetaObject::Connection diff --git a/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.rs b/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.rs index 2deb2d660..4b5b0409d 100644 --- a/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.rs +++ b/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.rs @@ -67,7 +67,7 @@ pub mod ffi { type QMetaObjectConnection = cxx_qt::QMetaObjectConnection; } unsafe extern "C++" { - include!("cxx-qt-gen/multi_object.cxxqt.h"); + include!("directory/file_ident.cxxqt.h"); } unsafe extern "C++" { #[doc = "The C++ type for the QObject "] diff --git a/crates/cxx-qt-gen/test_outputs/properties.cpp b/crates/cxx-qt-gen/test_outputs/properties.cpp index 6f161d596..2df8d09fc 100644 --- a/crates/cxx-qt-gen/test_outputs/properties.cpp +++ b/crates/cxx-qt-gen/test_outputs/properties.cpp @@ -1,4 +1,4 @@ -#include "cxx-qt-gen/properties.cxxqt.h" +#include "directory/file_ident.cxxqt.h" // Define namespace otherwise we hit a GCC bug // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 diff --git a/crates/cxx-qt-gen/test_outputs/properties.h b/crates/cxx-qt-gen/test_outputs/properties.h index 179b1f411..4d8429281 100644 --- a/crates/cxx-qt-gen/test_outputs/properties.h +++ b/crates/cxx-qt-gen/test_outputs/properties.h @@ -30,7 +30,7 @@ using MyObjectCxxQtSignalHandlermyOnChanged = ::rust::cxxqt1::SignalHandler; } // namespace cxx_qt::my_object::rust::cxxqtgen1 -#include "cxx-qt-gen/properties.cxx.h" +#include "directory/file_ident.cxx.h" namespace cxx_qt::my_object::rust::cxxqtgen1 { ::QMetaObject::Connection diff --git a/crates/cxx-qt-gen/test_outputs/properties.rs b/crates/cxx-qt-gen/test_outputs/properties.rs index e36605981..19fd7abef 100644 --- a/crates/cxx-qt-gen/test_outputs/properties.rs +++ b/crates/cxx-qt-gen/test_outputs/properties.rs @@ -18,7 +18,7 @@ mod ffi { type QMetaObjectConnection = cxx_qt::QMetaObjectConnection; } unsafe extern "C++" { - include!("cxx-qt-gen/properties.cxxqt.h"); + include!("directory/file_ident.cxxqt.h"); } unsafe extern "C++" { #[doc = "The C++ type for the QObject "] diff --git a/crates/cxx-qt-gen/test_outputs/qenum.cpp b/crates/cxx-qt-gen/test_outputs/qenum.cpp index 0feeb476a..36e182952 100644 --- a/crates/cxx-qt-gen/test_outputs/qenum.cpp +++ b/crates/cxx-qt-gen/test_outputs/qenum.cpp @@ -1,4 +1,4 @@ -#include "cxx-qt-gen/qenum.cxxqt.h" +#include "directory/file_ident.cxxqt.h" namespace cxx_qt::my_object { MyObject::MyObject(QObject* parent) diff --git a/crates/cxx-qt-gen/test_outputs/qenum.h b/crates/cxx-qt-gen/test_outputs/qenum.h index 9fc671105..1f523ec8c 100644 --- a/crates/cxx-qt-gen/test_outputs/qenum.h +++ b/crates/cxx-qt-gen/test_outputs/qenum.h @@ -70,7 +70,7 @@ enum class MyRenamedEnum : ::std::int32_t }; } // namespace cxx_qt::my_object -#include "cxx-qt-gen/qenum.cxx.h" +#include "directory/file_ident.cxx.h" namespace cxx_qt::my_object { class MyObject diff --git a/crates/cxx-qt-gen/test_outputs/qenum.rs b/crates/cxx-qt-gen/test_outputs/qenum.rs index 1bdc0d9f4..0daa541c4 100644 --- a/crates/cxx-qt-gen/test_outputs/qenum.rs +++ b/crates/cxx-qt-gen/test_outputs/qenum.rs @@ -12,6 +12,9 @@ mod ffi { #[rust_name = "CxxQtQMetaObjectConnection"] type QMetaObjectConnection = cxx_qt::QMetaObjectConnection; } + unsafe extern "C++" { + include!("directory/file_ident.cxxqt.h"); + } #[repr(i32)] enum MyEnum { A, @@ -61,9 +64,6 @@ mod ffi { #[namespace = "cxx_qt::my_object"] type MyRenamedEnum; } - unsafe extern "C++" { - include!("cxx-qt-gen/qenum.cxxqt.h"); - } unsafe extern "C++" { #[doc = "The C++ type for the QObject "] #[doc = "MyObjectRust"] diff --git a/crates/cxx-qt-gen/test_outputs/signals.cpp b/crates/cxx-qt-gen/test_outputs/signals.cpp index 62b3843cb..49e612993 100644 --- a/crates/cxx-qt-gen/test_outputs/signals.cpp +++ b/crates/cxx-qt-gen/test_outputs/signals.cpp @@ -1,4 +1,4 @@ -#include "cxx-qt-gen/signals.cxxqt.h" +#include "directory/file_ident.cxxqt.h" // Define namespace otherwise we hit a GCC bug // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 diff --git a/crates/cxx-qt-gen/test_outputs/signals.h b/crates/cxx-qt-gen/test_outputs/signals.h index d764206c7..db9ac986b 100644 --- a/crates/cxx-qt-gen/test_outputs/signals.h +++ b/crates/cxx-qt-gen/test_outputs/signals.h @@ -28,7 +28,7 @@ using QTimerCxxQtSignalHandlertimeout = ::rust::cxxqt1::SignalHandler; } // namespace cxx_qt::my_object::rust::cxxqtgen1 -#include "cxx-qt-gen/signals.cxx.h" +#include "directory/file_ident.cxx.h" namespace cxx_qt::my_object::rust::cxxqtgen1 { ::QMetaObject::Connection diff --git a/crates/cxx-qt-gen/test_outputs/signals.rs b/crates/cxx-qt-gen/test_outputs/signals.rs index 2bfa6d1df..e6bccfd85 100644 --- a/crates/cxx-qt-gen/test_outputs/signals.rs +++ b/crates/cxx-qt-gen/test_outputs/signals.rs @@ -19,7 +19,7 @@ mod ffi { type QMetaObjectConnection = cxx_qt::QMetaObjectConnection; } unsafe extern "C++" { - include!("cxx-qt-gen/signals.cxxqt.h"); + include!("directory/file_ident.cxxqt.h"); } unsafe extern "C++" { #[doc = "The C++ type for the QObject "] diff --git a/crates/cxx-qt-macro/src/lib.rs b/crates/cxx-qt-macro/src/lib.rs index 707842113..cbf83b621 100644 --- a/crates/cxx-qt-macro/src/lib.rs +++ b/crates/cxx-qt-macro/src/lib.rs @@ -120,7 +120,7 @@ pub fn qobject(_args: TokenStream, _input: TokenStream) -> TokenStream { fn extract_and_generate(module: ItemMod) -> TokenStream { Parser::from(module) .and_then(|parser| GeneratedRustBlocks::from(&parser)) - .map(|generated_rust| write_rust(&generated_rust)) + .map(|generated_rust| write_rust(&generated_rust, None)) .unwrap_or_else(|err| err.to_compile_error()) .into() } From 69c47a1ecfea166f5b5be8b2e191c13eefe3e3b6 Mon Sep 17 00:00:00 2001 From: Andrew Hayzen Date: Wed, 4 Sep 2024 15:23:55 +0100 Subject: [PATCH 04/15] cxx-qt-build: place moc and other files into folder and include moc --- crates/cxx-qt-build/src/lib.rs | 47 ++++++++++++++++- crates/qt-build-utils/src/lib.rs | 90 ++++++++++++++++++++------------ 2 files changed, 103 insertions(+), 34 deletions(-) diff --git a/crates/cxx-qt-build/src/lib.rs b/crates/cxx-qt-build/src/lib.rs index 5cb1d22aa..d5fb48729 100644 --- a/crates/cxx-qt-build/src/lib.rs +++ b/crates/cxx-qt-build/src/lib.rs @@ -277,7 +277,7 @@ fn generate_cxxqt_cpp_files( std::process::exit(1); } }; - generated_file_paths.push(generated_code.write_to_directories(cxx_qt_dir, &header_dir)); + generated_file_paths.push(generated_code.write_to_directories(&cxx_qt_dir, &header_dir)); } generated_file_paths @@ -674,6 +674,10 @@ impl CxxQtBuilder { } in &self.qobject_headers { let moc_products = qtbuild.moc(path, moc_arguments.clone()); + // Include the moc folder + if let Some(dir) = moc_products.cpp.parent() { + self.cc_builder.include(dir); + } self.cc_builder.file(moc_products.cpp); } } @@ -745,6 +749,31 @@ impl CxxQtBuilder { let mut qml_metatypes_json = Vec::new(); + // Check that all rust files are within the same directory + // + // Note we need to do this as moc generates an inputFile which only + // includes the file name, qmltyperegistrar then uses this for the + // include path (and doesn't consider any prefix). + // + // This can also be observed when using qt_add_qml_module, if a class + // has a QML_ELEMENT the file must be in the same directory as the + // CMakeLists and cannot be a relative path to a sub directory. + let dirs = qml_module + .rust_files + .iter() + .map(|file| { + file.parent() + .unwrap() + .file_name() + .unwrap() + .to_string_lossy() + .to_string() + }) + .collect::>(); + if dirs.len() > 1 { + panic!("Only one directory is support per QmlModule for rust_files"); + } + for files in generate_cxxqt_cpp_files( &qml_module.rust_files, &generated_header_dir, @@ -753,11 +782,21 @@ impl CxxQtBuilder { self.cc_builder.file(files.plain_cpp); if let (Some(qobject), Some(qobject_header)) = (files.qobject, files.qobject_header) { + // Ensure that the generated QObject header is in the include path + // so that qmltyperegistar can include them later + if let Some(dir) = qobject_header.parent() { + self.cc_builder.include(dir); + } + self.cc_builder.file(&qobject); let moc_products = qtbuild.moc( qobject_header, MocArguments::default().uri(qml_module.uri.clone()), ); + // Include the moc folder + if let Some(dir) = moc_products.cpp.parent() { + self.cc_builder.include(dir); + } self.cc_builder.file(moc_products.cpp); qml_metatypes_json.push(moc_products.metatypes_json); } @@ -784,6 +823,12 @@ impl CxxQtBuilder { // RCC file. .file(qml_module_registration_files.rcc); + // Add any include paths the qml module registration needs + // this is most likely the moc folder for the plugin + if let Some(include_path) = qml_module_registration_files.include_path { + self.cc_builder.include(include_path); + } + for qmlcachegen_file in qml_module_registration_files.qmlcachegen { self.cc_builder.file(qmlcachegen_file); } diff --git a/crates/qt-build-utils/src/lib.rs b/crates/qt-build-utils/src/lib.rs index 2c372162c..604c78bd6 100644 --- a/crates/qt-build-utils/src/lib.rs +++ b/crates/qt-build-utils/src/lib.rs @@ -178,6 +178,8 @@ pub struct QmlModuleRegistrationFiles { pub plugin: PathBuf, /// File that automatically registers the QQmlExtensionPlugin at startup. Must be linked with `+whole-archive`. pub plugin_init: PathBuf, + /// An optional include path that should be included + pub include_path: Option, } /// Helper for build.rs scripts using Qt @@ -602,9 +604,15 @@ impl QtBuild { } let input_path = input_file.as_ref(); - let output_path = PathBuf::from(&format!( - "{}/moc_{}.cpp", - env::var("OUT_DIR").unwrap(), + + // Put all the moc files into one place, this can then be added to the include path + let moc_dir = PathBuf::from(format!( + "{}/qt-build-utils/moc", + env::var("OUT_DIR").unwrap() + )); + std::fs::create_dir_all(&moc_dir).expect("Could not create moc dir"); + let output_path = moc_dir.join(format!( + "moc_{}.cpp", input_path.file_name().unwrap().to_str().unwrap() )); @@ -682,15 +690,18 @@ impl QtBuild { let qml_uri_dirs = uri.replace('.', "/"); let out_dir = env::var("OUT_DIR").unwrap(); - let qml_module_dir = format!("{out_dir}/qml_modules/{qml_uri_dirs}"); + let qt_build_utils_dir = PathBuf::from(format!("{out_dir}/qt-build-utils")); + std::fs::create_dir_all(&qt_build_utils_dir).expect("Could not create qt_build_utils dir"); + + let qml_module_dir = qt_build_utils_dir.join("qml_modules").join(&qml_uri_dirs); std::fs::create_dir_all(&qml_module_dir).expect("Could not create QML module directory"); let qml_uri_underscores = uri.replace('.', "_"); - let qmltypes_path = format!("{qml_module_dir}/plugin.qmltypes"); + let qmltypes_path = qml_module_dir.join("plugin.qmltypes"); let plugin_class_name = format!("{qml_uri_underscores}_plugin"); // Generate qmldir file - let qmldir_file_path = format!("{qml_module_dir}/qmldir"); + let qmldir_file_path = qml_module_dir.join("qmldir"); { let mut qmldir = File::create(&qmldir_file_path).expect("Could not create qmldir file"); write!( @@ -706,7 +717,8 @@ prefer :/qt/qml/{qml_uri_dirs}/ } // Generate .qrc file and run rcc on it - let qrc_path = format!("{qml_module_dir}/qml_module_resources_{qml_uri_underscores}.qrc"); + let qrc_path = + qml_module_dir.join(format!("qml_module_resources_{qml_uri_underscores}.qrc")); { fn qrc_file_line(file_path: &impl AsRef) -> String { let path_display = file_path.as_ref().display(); @@ -728,15 +740,16 @@ prefer :/qt/qml/{qml_uri_dirs}/ } let mut qrc = File::create(&qrc_path).expect("Could not create qrc file"); + let qml_module_dir_str = qml_module_dir.to_str().unwrap(); write!( qrc, r#" - {qml_module_dir} + {qml_module_dir_str} {qml_files_qrc} - {qml_module_dir}/qmldir + {qml_module_dir_str}/qmldir "# @@ -749,15 +762,15 @@ prefer :/qt/qml/{qml_uri_dirs}/ // then once for the module with --resource-name. let mut qmlcachegen_file_paths = Vec::new(); if let Some(qmlcachegen_executable) = &self.qmlcachegen_executable { - let qmlcachegen_dir = format!("{out_dir}/qmlcachegen/{qml_uri_dirs}"); + let qmlcachegen_dir = qt_build_utils_dir.join("qmlcachegen").join(&qml_uri_dirs); std::fs::create_dir_all(&qmlcachegen_dir) .expect("Could not create qmlcachegen directory for QML module"); let common_args = [ "-i".to_string(), - qmldir_file_path.to_string(), + qmldir_file_path.to_string_lossy().to_string(), "--resource".to_string(), - qrc_path.clone(), + qrc_path.to_string_lossy().to_string(), ]; let mut qml_file_qrc_paths = Vec::new(); @@ -765,17 +778,17 @@ prefer :/qt/qml/{qml_uri_dirs}/ let qrc_resource_path = format!("/qt/qml/{qml_uri_dirs}/{}", file.as_ref().display()); - let qml_compiled_file = format!( - "{qmlcachegen_dir}/{}.cpp", + let qml_compiled_file = qmlcachegen_dir.join(format!( + "{}.cpp", file.as_ref().file_name().unwrap().to_string_lossy() - ); + )); qmlcachegen_file_paths.push(PathBuf::from(&qml_compiled_file)); let specific_args = vec![ "--resource-path".to_string(), qrc_resource_path.clone(), "-o".to_string(), - qml_compiled_file, + qml_compiled_file.to_string_lossy().to_string(), std::fs::canonicalize(file) .unwrap() .to_string_lossy() @@ -801,12 +814,12 @@ prefer :/qt/qml/{qml_uri_dirs}/ qml_file_qrc_paths.push(qrc_resource_path); } - let qmlcachegen_loader = format!("{qmlcachegen_dir}/qmlcache_loader.cpp"); + let qmlcachegen_loader = qmlcachegen_dir.join("qmlcache_loader.cpp"); let specific_args = vec![ "--resource-name".to_string(), format!("qmlcache_{qml_uri_underscores}"), "-o".to_string(), - qmlcachegen_loader.clone(), + qmlcachegen_loader.to_string_lossy().to_string(), ]; // If there are no QML files there is nothing for qmlcachegen to run with @@ -830,14 +843,16 @@ prefer :/qt/qml/{qml_uri_dirs}/ } } + let qml_plugin_dir = PathBuf::from(format!("{out_dir}/qt-build-utils/qml_plugin")); + std::fs::create_dir_all(&qml_plugin_dir).expect("Could not create qml_plugin dir"); + // Run qmltyperegistrar - let qmltyperegistrar_output_path = PathBuf::from(&format!( - "{out_dir}/{qml_uri_underscores}_qmltyperegistration.cpp" - )); + let qmltyperegistrar_output_path = + qml_plugin_dir.join(format!("{qml_uri_underscores}_qmltyperegistration.cpp")); { let mut args = vec![ "--generate-qmltypes".to_string(), - qmltypes_path, + qmltypes_path.to_string_lossy().to_string(), "--major-version".to_string(), version_major.to_string(), "--minor-version".to_string(), @@ -865,8 +880,9 @@ prefer :/qt/qml/{qml_uri_dirs}/ } // Generate QQmlEngineExtensionPlugin - let qml_plugin_cpp_path = PathBuf::from(format!("{out_dir}/{plugin_class_name}.cpp")); - let qml_plugin_init_path = PathBuf::from(format!("{out_dir}/{plugin_class_name}_init.cpp")); + let qml_plugin_cpp_path = qml_plugin_dir.join(format!("{plugin_class_name}.cpp")); + let qml_plugin_init_path = qml_plugin_dir.join(format!("{plugin_class_name}_init.cpp")); + let include_path; { let mut declarations = Vec::default(); let mut usages = Vec::default(); @@ -921,13 +937,12 @@ public: ) .expect("Failed to write plugin definition"); - self.moc( + let moc_product = self.moc( &qml_plugin_cpp_path, - MocArguments { - uri: Some(uri.to_owned()), - ..Default::default() - }, + MocArguments::default().uri(uri.to_owned()), ); + // Pass the include directory of the moc file to the caller + include_path = moc_product.cpp.parent().map(|path| path.to_path_buf()); // Generate file to load static QQmlExtensionPlugin std::fs::write( @@ -948,6 +963,7 @@ Q_IMPORT_PLUGIN({plugin_class_name}); qmltyperegistrar: qmltyperegistrar_output_path, plugin: qml_plugin_cpp_path, plugin_init: qml_plugin_init_path, + include_path, } } @@ -961,10 +977,18 @@ Q_IMPORT_PLUGIN({plugin_class_name}); } let input_path = input_file.as_ref(); - let output_path = PathBuf::from(&format!( - "{}/{}.cpp", - env::var("OUT_DIR").unwrap(), - input_path.file_name().unwrap().to_str().unwrap() + let output_folder = PathBuf::from(&format!( + "{}/qt-build-utils/qrc", + env::var("OUT_DIR").unwrap() + )); + std::fs::create_dir_all(&output_folder).expect("Could not create qrc dir"); + let output_path = output_folder.join(format!( + "{}.cpp", + input_path + .file_name() + .unwrap() + .to_string_lossy() + .to_string(), )); let cmd = Command::new(self.rcc_executable.as_ref().unwrap()) From 8a1cc85ddf38296d223632b3142c543b028dd59c Mon Sep 17 00:00:00 2001 From: Andrew Hayzen Date: Wed, 4 Sep 2024 16:34:13 +0100 Subject: [PATCH 05/15] cxx-qt-build: injected include needs the prefix of the crate --- crates/cxx-qt-build/src/lib.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/crates/cxx-qt-build/src/lib.rs b/crates/cxx-qt-build/src/lib.rs index d5fb48729..2219ba6a4 100644 --- a/crates/cxx-qt-build/src/lib.rs +++ b/crates/cxx-qt-build/src/lib.rs @@ -71,6 +71,7 @@ impl GeneratedCpp { pub fn new( rust_file_path: impl AsRef, relative_path: impl AsRef, + include_prefix: &str, ) -> Result { let to_diagnostic = |err| Diagnostic::new(rust_file_path.as_ref().to_owned(), err); @@ -81,7 +82,6 @@ impl GeneratedCpp { .map_err(to_diagnostic)?; let mut cxx_qt = None; - let mut file_ident: String = "".to_owned(); let mut tokens = proc_macro2::TokenStream::new(); // Add any attributes in the file into the tokenstream @@ -92,13 +92,15 @@ impl GeneratedCpp { // Match upstream where they use the file name and folders as the ident // // We need the relative path here as we want the folders - relative_path + let file_ident = relative_path .as_ref() // Remove the .rs extension .with_extension("") - .to_str() - .unwrap() - .clone_into(&mut file_ident); + .to_string_lossy() + .to_string(); + + // The include path we inject needs any prefix (eg the crate name) too + let include_ident = format!("{include_prefix}/{file_ident}"); // Loop through the items looking for any CXX or CXX-Qt blocks let mut found_bridge = false; @@ -138,8 +140,8 @@ impl GeneratedCpp { // TODO: we'll have to extend the C++ data here rather than overwriting // assuming we share the same file - cxx_qt = Some(write_cpp(&generated_cpp, &file_ident)); - let rust_tokens = write_rust(&generated_rust, Some(&file_ident)); + cxx_qt = Some(write_cpp(&generated_cpp, &include_ident)); + let rust_tokens = write_rust(&generated_rust, Some(&include_ident)); // We need to do this and can't rely on the macro, as we need to generate the // CXX bridge Rust code that is then fed into the cxx_gen generation. @@ -270,7 +272,7 @@ fn generate_cxxqt_cpp_files( let path = manifest_dir.join(rs_path); println!("cargo:rerun-if-changed={}", path.to_string_lossy()); - let generated_code = match GeneratedCpp::new(&path, rs_path) { + let generated_code = match GeneratedCpp::new(&path, rs_path, include_prefix) { Ok(v) => v, Err(diagnostic) => { diagnostic.report(); From 6a4e353a7a635fe0117f5723e422fa6b8dd9f5c8 Mon Sep 17 00:00:00 2001 From: Andrew Hayzen Date: Wed, 4 Sep 2024 16:34:59 +0100 Subject: [PATCH 06/15] cxx-qt-gen: purge cxx_file_stem --- CHANGELOG.md | 2 +- book/src/bridge/extern_rustqt.md | 2 +- book/src/bridge/index.md | 22 +----------- book/src/bridge/shared_types.md | 2 +- .../getting-started/5-cmake-integration.md | 6 +--- crates/cxx-qt-gen/src/generator/cpp/mod.rs | 27 ++------------ crates/cxx-qt-gen/src/generator/rust/mod.rs | 28 --------------- crates/cxx-qt-gen/src/parser/mod.rs | 36 +++++-------------- crates/cxx-qt-gen/src/writer/cpp/mod.rs | 2 -- crates/cxx-qt-gen/src/writer/rust/mod.rs | 4 +++ crates/cxx-qt-gen/test_inputs/inheritance.rs | 2 +- crates/cxx-qt-gen/test_inputs/invokables.rs | 2 +- .../test_inputs/passthrough_and_naming.rs | 2 +- crates/cxx-qt-gen/test_inputs/properties.rs | 2 +- crates/cxx-qt-gen/test_inputs/qenum.rs | 2 +- crates/cxx-qt-gen/test_inputs/shebang.rs | 2 +- crates/cxx-qt-gen/test_inputs/signals.rs | 2 +- crates/cxx-qt-lib/src/qml/qqmlengine.rs | 2 +- .../src/quickcontrols/qquickstyle.rs | 2 +- .../cpp/helpers/energyusageproxymodel.h | 2 +- examples/demo_threading/rust/src/lib.rs | 2 +- examples/qml_features/rust/src/containers.rs | 2 +- .../rust/src/custom_base_class.rs | 2 +- .../rust/src/custom_parent_class.rs | 2 +- examples/qml_features/rust/src/externcxxqt.rs | 3 +- examples/qml_features/rust/src/invokables.rs | 2 +- .../rust/src/multiple_qobjects.rs | 2 +- .../qml_features/rust/src/nested_qobjects.rs | 2 +- examples/qml_features/rust/src/properties.rs | 2 +- .../qml_features/rust/src/serialisation.rs | 2 +- examples/qml_features/rust/src/signals.rs | 2 +- examples/qml_features/rust/src/singleton.rs | 2 +- examples/qml_features/rust/src/threading.rs | 2 +- examples/qml_features/rust/src/types.rs | 4 +-- examples/qml_features/rust/src/uncreatable.rs | 2 +- examples/qml_minimal/rust/src/cxxqt_object.rs | 2 +- tests/basic_cxx_qt/cpp/main.cpp | 6 ++-- tests/basic_cxx_qt/rust/src/data.rs | 2 +- tests/basic_cxx_qt/rust/src/empty.rs | 2 +- tests/basic_cxx_qt/rust/src/lib.rs | 2 +- tests/basic_cxx_qt/rust/src/types.rs | 2 +- 41 files changed, 52 insertions(+), 148 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b1c13ea4c..c1764fe72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,7 +47,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add CMake wrappers around corrosion to simplify importing crates and qml modules that were built with cxx-qt-build - CMake code has been extracted into a separate repository for faster downloads (kdab/cxx-qt-cmake) - Folder structure of Rust bridges is now considered in the same way as CXX in `CxxQtBuilder` -- All `#[cxx_qt::bridge]` macros must specify a `cxx_file_stem` until `Span::source_file()` is stable +- `cxx_file_stem` has been removed from `#[cxx_qt::bridge]` and the source file name is now used for generated headers similar to CXX ### Removed diff --git a/book/src/bridge/extern_rustqt.md b/book/src/bridge/extern_rustqt.md index 8aa7f162e..c65b1f02e 100644 --- a/book/src/bridge/extern_rustqt.md +++ b/book/src/bridge/extern_rustqt.md @@ -23,7 +23,7 @@ mod ffi { The `extern "RustQt"` section of a CXX bridge declares Rust types and signatures to be made available to Qt and C++. -The CXX code generator uses your `extern "Rust"` section(s) to produce a C++ header file containing the corresponding C++ declarations. The generated header has a file name of the `cxx_file_stem` field in the `#[cxx_qt::bridge]` attribute and with a `.cxxqt.h` file extension. +The CXX code generator uses your `extern "Rust"` section(s) to produce a C++ header file containing the corresponding C++ declarations. The generated header has the same file name as the input rust file but with `.cxxqt.h` file extension. > Note that once there is support for `source_file` or similar in the `Span` macro we want to support copying the file name like CXX. diff --git a/book/src/bridge/index.md b/book/src/bridge/index.md index e9adedf44..b2fb16277 100644 --- a/book/src/bridge/index.md +++ b/book/src/bridge/index.md @@ -19,26 +19,6 @@ This Rust module will then function like a normal CXX bridge, whilst also suppor > Don't forget to add the Rust source file to the `CxxQtBuilder` in your `build.rs` script. For instructions, see the [Getting Started guide](../getting-started/5-cmake-integration.md). -The `#[cxx_qt::bridge]` macro supports two options in its attribute: +The `#[cxx_qt::bridge]` macro supports the options in its attribute: -- [`cxx_file_stem`](#cxx_file_stem) - [`namespace`](./attributes.md#namespace) - -## cxx_file_stem - -By default, the name of the generated C++ header file will be the name of the module, followed by `.cxxqt.h` (and `.cxx.h` for CXX files). - -This can cause issues as the module is normally called `ffi` or `qobject`, so collisions would occur. - -The `cxx_file_stem` option allows a file name to be specified to avoid collisions. - -```rust,ignore -{{#include ../../../examples/qml_features/rust/src/types.rs:book_cxx_file_stem}} -``` - -> Currently, `cxx-qt-gen` writes all generated header files into a single folder. -> Therefore, you need to be careful to not produce two header files with the same filename. - -> We want to use the name of the Rust source file that the macro is located in (the same as CXX). -> However, this requires [inspection APIs from `proc_macro::Span`](https://github.com/rust-lang/rust/issues/54725) -> which is currently a nightly feature. diff --git a/book/src/bridge/shared_types.md b/book/src/bridge/shared_types.md index 61d671ff4..6521f4dad 100644 --- a/book/src/bridge/shared_types.md +++ b/book/src/bridge/shared_types.md @@ -31,7 +31,7 @@ It is currently not possible to add a `#[qenum(...)]` to any `extern "C++Qt"` `Q Example: ```rust,ignore,noplayground -#[cxx_qt::bridge(cxx_file_stem="custom_base_class")] +#[cxx_qt::bridge] pub mod qobject { {{#include ../../../examples/qml_features/rust/src/custom_base_class.rs:book_qenum_in_qobject}} diff --git a/book/src/getting-started/5-cmake-integration.md b/book/src/getting-started/5-cmake-integration.md index d8d8e6e46..1e1513d10 100644 --- a/book/src/getting-started/5-cmake-integration.md +++ b/book/src/getting-started/5-cmake-integration.md @@ -38,13 +38,9 @@ You can add as much C++ code as you want in addition to this. For every `#[cxx_qt::bridge]` that we define in Rust, CXX-Qt will generate a corresponding C++ header file. To include any of the generated files, use the crates name as the include directory. -The name of the header file will be the folder names, combined with the `cxx_file_stem` of your `#[cxx_qt::bridge]`, followed by `.cxxqt.h`. +The name of the header file will be the folder names, combined with the input rust file name of your `#[cxx_qt::bridge]`, followed by `.cxxqt.h`. So in our case: `#include ` -> Note that the [`cxx_file_stem`](../bridge/index.md#cxx_file_stem) option must be specified in the bridge macro to choose the file name. - -> Note that once `Span::source_file()` is stable the `cxx_file_stem` will be optional and the file name will be the default like CXX> - > Note any folders relative to the cargo manifest are considered hence the `src` folder. Including the generated header allows us to access the `MyObject` C++ class, just like any other C++ class. diff --git a/crates/cxx-qt-gen/src/generator/cpp/mod.rs b/crates/cxx-qt-gen/src/generator/cpp/mod.rs index e337870b3..0f26e6281 100644 --- a/crates/cxx-qt-gen/src/generator/cpp/mod.rs +++ b/crates/cxx-qt-gen/src/generator/cpp/mod.rs @@ -34,8 +34,6 @@ pub struct GeneratedCppBlocks { pub forward_declares: Vec, /// Additional includes for the CXX bridge pub includes: BTreeSet, - /// Stem of the CXX header to include - pub cxx_file_stem: String, /// Generated QObjects pub qobjects: Vec, /// Generated extern C++Qt blocks @@ -65,7 +63,6 @@ impl GeneratedCppBlocks { Ok(GeneratedCppBlocks { forward_declares, includes, - cxx_file_stem: parser.cxx_file_stem(), qobjects: structures .qobjects .iter() @@ -118,7 +115,7 @@ mod tests { #[test] fn test_generated_cpp_blocks() { let module: ItemMod = parse_quote! { - #[cxx_qt::bridge(cxx_file_stem = "ffi")] + #[cxx_qt::bridge] mod ffi { extern "RustQt" { #[qobject] @@ -129,26 +126,6 @@ mod tests { let parser = Parser::from(module).unwrap(); let cpp = GeneratedCppBlocks::from(&parser).unwrap(); - assert_eq!(cpp.cxx_file_stem, "ffi"); - assert_eq!(cpp.qobjects.len(), 1); - assert_eq!(cpp.qobjects[0].name.namespace(), None); - } - - #[test] - fn test_generated_cpp_blocks_cxx_file_stem() { - let module: ItemMod = parse_quote! { - #[cxx_qt::bridge(cxx_file_stem = "my_object")] - mod ffi { - extern "RustQt" { - #[qobject] - type MyObject = super::MyObjectRust; - } - } - }; - let parser = Parser::from(module).unwrap(); - - let cpp = GeneratedCppBlocks::from(&parser).unwrap(); - assert_eq!(cpp.cxx_file_stem, "my_object"); assert_eq!(cpp.qobjects.len(), 1); assert_eq!(cpp.qobjects[0].name.namespace(), None); } @@ -156,7 +133,7 @@ mod tests { #[test] fn test_generated_cpp_blocks_namespace() { let module: ItemMod = parse_quote! { - #[cxx_qt::bridge(cxx_file_stem = "ffi", namespace = "cxx_qt")] + #[cxx_qt::bridge(namespace = "cxx_qt")] mod ffi { extern "RustQt" { #[qobject] diff --git a/crates/cxx-qt-gen/src/generator/rust/mod.rs b/crates/cxx-qt-gen/src/generator/rust/mod.rs index 419c2e60b..a2467b98c 100644 --- a/crates/cxx-qt-gen/src/generator/rust/mod.rs +++ b/crates/cxx-qt-gen/src/generator/rust/mod.rs @@ -149,32 +149,4 @@ mod tests { assert_eq!(rust.namespace, "cxx_qt"); assert_eq!(rust.fragments.len(), 1); } - - #[test] - fn test_generated_rust_blocks_cxx_file_stem() { - let module: ItemMod = parse_quote! { - #[cxx_qt::bridge(cxx_file_stem = "my_object")] - mod ffi { - extern "RustQt" { - #[qobject] - type MyObject = super::MyObjectRust; - } - } - }; - let parser = Parser::from(module).unwrap(); - - let rust = GeneratedRustBlocks::from(&parser).unwrap(); - assert!(rust.cxx_mod.content.is_none()); - assert_eq!(rust.cxx_mod_contents.len(), 1); - assert_tokens_eq( - &rust.cxx_mod_contents[0], - quote! { - unsafe extern "C++" { - include!("cxx-qt-gen/my_object.cxxqt.h"); - } - }, - ); - assert_eq!(rust.namespace, ""); - assert_eq!(rust.fragments.len(), 1); - } } diff --git a/crates/cxx-qt-gen/src/parser/mod.rs b/crates/cxx-qt-gen/src/parser/mod.rs index d501dc06c..b5584aaf5 100644 --- a/crates/cxx-qt-gen/src/parser/mod.rs +++ b/crates/cxx-qt-gen/src/parser/mod.rs @@ -63,14 +63,11 @@ pub struct Parser { pub(crate) cxx_qt_data: ParsedCxxQtData, /// all type names that were found in this module, including CXX types pub(crate) type_names: TypeNames, - /// The stem of the file that the CXX headers for this module will be generated into - pub(crate) cxx_file_stem: Option, } impl Parser { - fn parse_mod_attributes(module: &mut ItemMod) -> Result<(Option, Option)> { + fn parse_mod_attributes(module: &mut ItemMod) -> Result> { let mut namespace = None; - let mut cxx_file_stem = None; // Remove the cxx_qt::bridge attribute if let Some(attr) = attribute_take_path(&mut module.attrs, &["cxx_qt", "bridge"]) { @@ -80,27 +77,22 @@ impl Parser { attr.parse_args_with(Punctuated::::parse_terminated)?; for meta in nested { match meta { - Meta::NameValue(name_value) => { + Meta::NameValue(ref name_value) => { // Parse any namespace in the cxx_qt::bridge macro if name_value.path.is_ident("namespace") { namespace = Some(expr_to_string(&name_value.value)?); // Parse any custom file stem } else if name_value.path.is_ident("cxx_file_stem") { - cxx_file_stem = Some(expr_to_string(&name_value.value)?); + return Err(Error::new( + meta.span(), + "cxx_file_stem is unsupported: TODO new system message", + )); } } _others => {} } } } - - // Temporary until Span::source_file() is stable - if cxx_file_stem.is_none() { - return Err(Error::new( - module.span(), - "All cxx_qt::bridge macros specify a cxx_file_stem until Span::source_file() is stable https://github.com/rust-lang/rust/issues/54725", - )); - } } else { return Err(Error::new( module.span(), @@ -108,7 +100,7 @@ impl Parser { )); } - Ok((namespace, cxx_file_stem)) + Ok(namespace) } fn parse_module_contents( @@ -159,7 +151,7 @@ impl Parser { /// Constructs a Parser object from a given [syn::ItemMod] block pub fn from(mut module: ItemMod) -> Result { - let (namespace, cxx_file_stem) = Self::parse_mod_attributes(&mut module)?; + let namespace = Self::parse_mod_attributes(&mut module)?; let (mut cxx_qt_data, module) = Self::parse_module_contents(module, namespace)?; let type_names = Self::naming_phase( &mut cxx_qt_data, @@ -176,20 +168,8 @@ impl Parser { passthrough_module: module, type_names, cxx_qt_data, - cxx_file_stem, }) } - - /// Determine the file stem to use for this macro - pub fn cxx_file_stem(&self) -> String { - if let Some(cxx_file_stem) = self.cxx_file_stem.as_ref() { - cxx_file_stem.clone() - } else { - // TODO: ideally CXX-Qt would also use the file name but it uses the cxx_file_stem for now - // https://github.com/KDAB/cxx-qt/pull/200/commits/4861c92e66c3a022d3f0dedd9f8fd20db064b42b - unimplemented!("Missing cxx_file_stem, once Span::source_file() is stable we can determine the file name") - } - } } #[cfg(test)] diff --git a/crates/cxx-qt-gen/src/writer/cpp/mod.rs b/crates/cxx-qt-gen/src/writer/cpp/mod.rs index 746ad0861..ec4d23401 100644 --- a/crates/cxx-qt-gen/src/writer/cpp/mod.rs +++ b/crates/cxx-qt-gen/src/writer/cpp/mod.rs @@ -95,7 +95,6 @@ mod tests { GeneratedCppBlocks { forward_declares: vec![], includes: BTreeSet::default(), - cxx_file_stem: "cxx_file_stem".to_owned(), extern_cxx_qt: vec![], qobjects: vec![ GeneratedCppQObject { @@ -226,7 +225,6 @@ mod tests { GeneratedCppBlocks { forward_declares: vec![], includes: BTreeSet::default(), - cxx_file_stem: "cxx_file_stem".to_owned(), extern_cxx_qt: vec![], qobjects: vec![ GeneratedCppQObject { diff --git a/crates/cxx-qt-gen/src/writer/rust/mod.rs b/crates/cxx-qt-gen/src/writer/rust/mod.rs index ff24986fc..a0fd2fe27 100644 --- a/crates/cxx-qt-gen/src/writer/rust/mod.rs +++ b/crates/cxx-qt-gen/src/writer/rust/mod.rs @@ -29,6 +29,8 @@ pub fn write_rust(generated: &GeneratedRustBlocks, include_path: Option<&str>) - // Rename to CxxQtConnectionType so the developer can define it // in their bridges without an invisible conflict #[rust_name = "CxxQtConnectionType"] + // If no signals are used this won't be used + #[allow(dead_code)] type ConnectionType = cxx_qt::ConnectionType; #[doc(hidden)] @@ -36,6 +38,8 @@ pub fn write_rust(generated: &GeneratedRustBlocks, include_path: Option<&str>) - // Rename to CxxQtQMetaObjectConnection so the developer can define it // in their bridges without an invisible conflict #[rust_name = "CxxQtQMetaObjectConnection"] + // If no signals are used this won't be used + #[allow(dead_code)] type QMetaObjectConnection = cxx_qt::QMetaObjectConnection; } }, diff --git a/crates/cxx-qt-gen/test_inputs/inheritance.rs b/crates/cxx-qt-gen/test_inputs/inheritance.rs index 5f9e50638..f3a9cf6e7 100644 --- a/crates/cxx-qt-gen/test_inputs/inheritance.rs +++ b/crates/cxx-qt-gen/test_inputs/inheritance.rs @@ -1,4 +1,4 @@ -#[cxx_qt::bridge(cxx_file_stem = "inheritance")] +#[cxx_qt::bridge] mod inheritance { extern "C++" { include!("cxx-qt-lib/qmodelindex.h"); diff --git a/crates/cxx-qt-gen/test_inputs/invokables.rs b/crates/cxx-qt-gen/test_inputs/invokables.rs index d08b2e1f4..17f5e1e92 100644 --- a/crates/cxx-qt-gen/test_inputs/invokables.rs +++ b/crates/cxx-qt-gen/test_inputs/invokables.rs @@ -1,4 +1,4 @@ -#[cxx_qt::bridge(cxx_file_stem = "invokables", namespace = "cxx_qt::my_object")] +#[cxx_qt::bridge(namespace = "cxx_qt::my_object")] mod ffi { #[namespace = ""] unsafe extern "C++" { diff --git a/crates/cxx-qt-gen/test_inputs/passthrough_and_naming.rs b/crates/cxx-qt-gen/test_inputs/passthrough_and_naming.rs index c8a4937e5..78816932c 100644 --- a/crates/cxx-qt-gen/test_inputs/passthrough_and_naming.rs +++ b/crates/cxx-qt-gen/test_inputs/passthrough_and_naming.rs @@ -1,5 +1,5 @@ #[attrA] -#[cxx_qt::bridge(namespace = "cxx_qt::multi_object", cxx_file_stem = "multi_object")] +#[cxx_qt::bridge(namespace = "cxx_qt::multi_object")] #[attrB] pub mod ffi { // ItemConst diff --git a/crates/cxx-qt-gen/test_inputs/properties.rs b/crates/cxx-qt-gen/test_inputs/properties.rs index fa7a5c8b1..3e07fae22 100644 --- a/crates/cxx-qt-gen/test_inputs/properties.rs +++ b/crates/cxx-qt-gen/test_inputs/properties.rs @@ -1,4 +1,4 @@ -#[cxx_qt::bridge(cxx_file_stem = "properties", namespace = "cxx_qt::my_object")] +#[cxx_qt::bridge(namespace = "cxx_qt::my_object")] mod ffi { #[namespace = ""] unsafe extern "C++" { diff --git a/crates/cxx-qt-gen/test_inputs/qenum.rs b/crates/cxx-qt-gen/test_inputs/qenum.rs index 06740d157..c485c8380 100644 --- a/crates/cxx-qt-gen/test_inputs/qenum.rs +++ b/crates/cxx-qt-gen/test_inputs/qenum.rs @@ -1,4 +1,4 @@ -#[cxx_qt::bridge(cxx_file_stem = "qenum", namespace = "cxx_qt::my_object")] +#[cxx_qt::bridge(namespace = "cxx_qt::my_object")] mod ffi { #[qenum(MyObject)] enum MyEnum { diff --git a/crates/cxx-qt-gen/test_inputs/shebang.rs b/crates/cxx-qt-gen/test_inputs/shebang.rs index b24fa2bae..80832760b 100644 --- a/crates/cxx-qt-gen/test_inputs/shebang.rs +++ b/crates/cxx-qt-gen/test_inputs/shebang.rs @@ -1,6 +1,6 @@ #!/usr/bin/ // Test for qtitem and qtfile, for code coverage -#[cxx_qt::bridge(cxx_file_stem = "shebang")] +#[cxx_qt::bridge] mod ffi { extern "RustQt" { #[qobject] diff --git a/crates/cxx-qt-gen/test_inputs/signals.rs b/crates/cxx-qt-gen/test_inputs/signals.rs index 2c35a0e1e..3aca1f5bd 100644 --- a/crates/cxx-qt-gen/test_inputs/signals.rs +++ b/crates/cxx-qt-gen/test_inputs/signals.rs @@ -1,4 +1,4 @@ -#[cxx_qt::bridge(cxx_file_stem = "signals", namespace = "cxx_qt::my_object")] +#[cxx_qt::bridge(namespace = "cxx_qt::my_object")] mod ffi { #[namespace = ""] unsafe extern "C++" { diff --git a/crates/cxx-qt-lib/src/qml/qqmlengine.rs b/crates/cxx-qt-lib/src/qml/qqmlengine.rs index 1ee7892eb..ac82b4984 100644 --- a/crates/cxx-qt-lib/src/qml/qqmlengine.rs +++ b/crates/cxx-qt-lib/src/qml/qqmlengine.rs @@ -3,7 +3,7 @@ // // SPDX-License-Identifier: MIT OR Apache-2.0 -#[cxx_qt::bridge(cxx_file_stem = "qqmlengine")] +#[cxx_qt::bridge] mod ffi { unsafe extern "C++Qt" { include!("cxx-qt-lib/qqmlengine.h"); diff --git a/crates/cxx-qt-lib/src/quickcontrols/qquickstyle.rs b/crates/cxx-qt-lib/src/quickcontrols/qquickstyle.rs index 1c5cc002e..cca860770 100644 --- a/crates/cxx-qt-lib/src/quickcontrols/qquickstyle.rs +++ b/crates/cxx-qt-lib/src/quickcontrols/qquickstyle.rs @@ -3,7 +3,7 @@ // // SPDX-License-Identifier: MIT OR Apache-2.0 -#[cxx_qt::bridge(cxx_file_stem = "qquickstyle")] +#[cxx_qt::bridge] mod ffi { unsafe extern "C++Qt" { include!("cxx-qt-lib/qquickstyle.h"); diff --git a/examples/demo_threading/cpp/helpers/energyusageproxymodel.h b/examples/demo_threading/cpp/helpers/energyusageproxymodel.h index 8876fe7fc..db2d047b2 100644 --- a/examples/demo_threading/cpp/helpers/energyusageproxymodel.h +++ b/examples/demo_threading/cpp/helpers/energyusageproxymodel.h @@ -12,7 +12,7 @@ #include #include -#include "cxx_qt_demo_threading/src/energy_usage.cxxqt.h" +#include "cxx_qt_demo_threading/src/lib.cxxqt.h" class EnergyUsageProxyModel : public QAbstractListModel { diff --git a/examples/demo_threading/rust/src/lib.rs b/examples/demo_threading/rust/src/lib.rs index a726da8ee..5d2a08333 100644 --- a/examples/demo_threading/rust/src/lib.rs +++ b/examples/demo_threading/rust/src/lib.rs @@ -9,7 +9,7 @@ mod network; mod workers; // This mod defines our QObject called EnergyUsage -#[cxx_qt::bridge(cxx_file_stem = "energy_usage", namespace = "cxx_qt::energy_usage")] +#[cxx_qt::bridge(namespace = "cxx_qt::energy_usage")] pub mod qobject { #[namespace = ""] unsafe extern "C++" { diff --git a/examples/qml_features/rust/src/containers.rs b/examples/qml_features/rust/src/containers.rs index 2079b48ea..9a27b22bb 100644 --- a/examples/qml_features/rust/src/containers.rs +++ b/examples/qml_features/rust/src/containers.rs @@ -6,7 +6,7 @@ //! This example shows how Qt container types can be used /// A CXX-Qt bridge which shows how to use Qt container types -#[cxx_qt::bridge(cxx_file_stem = "rust_containers")] +#[cxx_qt::bridge] pub mod qobject { unsafe extern "C++" { include!("cxx-qt-lib/qhash.h"); diff --git a/examples/qml_features/rust/src/custom_base_class.rs b/examples/qml_features/rust/src/custom_base_class.rs index cb4b85151..7f8a68e4e 100644 --- a/examples/qml_features/rust/src/custom_base_class.rs +++ b/examples/qml_features/rust/src/custom_base_class.rs @@ -7,7 +7,7 @@ /// A CXX-Qt bridge which shows a custom base class and inheritance can be used // ANCHOR: book_macro_code -#[cxx_qt::bridge(cxx_file_stem = "custom_base_class")] +#[cxx_qt::bridge] pub mod qobject { // ANCHOR: book_base_include unsafe extern "C++" { diff --git a/examples/qml_features/rust/src/custom_parent_class.rs b/examples/qml_features/rust/src/custom_parent_class.rs index d85da67c3..186360d1e 100644 --- a/examples/qml_features/rust/src/custom_parent_class.rs +++ b/examples/qml_features/rust/src/custom_parent_class.rs @@ -6,7 +6,7 @@ //! This example shows how a custom parent class can be used to inherit from a QQuickItem based object. /// A CXX-Qt bridge which shows a custom parent class can be used -#[cxx_qt::bridge(cxx_file_stem = "custom_parent_class")] +#[cxx_qt::bridge] pub mod qobject { unsafe extern "C++" { /// QColor from cxx_qt_lib diff --git a/examples/qml_features/rust/src/externcxxqt.rs b/examples/qml_features/rust/src/externcxxqt.rs index e52dc1801..d499971cb 100644 --- a/examples/qml_features/rust/src/externcxxqt.rs +++ b/examples/qml_features/rust/src/externcxxqt.rs @@ -6,8 +6,7 @@ //! This example shows how an external QObject with signals can be used /// A CXX-Qt bridge which shows how an external QObject with signals can be used -// ANCHOR: book_cxx_file_stem -#[cxx_qt::bridge(cxx_file_stem = "externcxxqt")] +#[cxx_qt::bridge] pub mod ffi { unsafe extern "C++Qt" { include!("external_qobject.h"); diff --git a/examples/qml_features/rust/src/invokables.rs b/examples/qml_features/rust/src/invokables.rs index 2f73cc9dc..7ed3ea374 100644 --- a/examples/qml_features/rust/src/invokables.rs +++ b/examples/qml_features/rust/src/invokables.rs @@ -7,7 +7,7 @@ /// A CXX-Qt bridge which shows how a Q_INVOKABLE can be used // ANCHOR: book_macro_code -#[cxx_qt::bridge(cxx_file_stem = "rust_invokables")] +#[cxx_qt::bridge] pub mod qobject { unsafe extern "C++" { include!("cxx-qt-lib/qcolor.h"); diff --git a/examples/qml_features/rust/src/multiple_qobjects.rs b/examples/qml_features/rust/src/multiple_qobjects.rs index df4473251..cf4c9d016 100644 --- a/examples/qml_features/rust/src/multiple_qobjects.rs +++ b/examples/qml_features/rust/src/multiple_qobjects.rs @@ -6,7 +6,7 @@ //! This example shows how multiple QObjects can be defined in one module /// A CXX-Qt bridge which shows multiple QObjects can be defined in one module -#[cxx_qt::bridge(cxx_file_stem = "multiple_qobjects")] +#[cxx_qt::bridge] pub mod qobject { unsafe extern "C++" { include!("cxx-qt-lib/qcolor.h"); diff --git a/examples/qml_features/rust/src/nested_qobjects.rs b/examples/qml_features/rust/src/nested_qobjects.rs index dfa805165..a9d1bc064 100644 --- a/examples/qml_features/rust/src/nested_qobjects.rs +++ b/examples/qml_features/rust/src/nested_qobjects.rs @@ -11,7 +11,7 @@ /// A CXX-Qt bridge which shows how a pointer from one Rust defined QObject to another Rust defined QObject can be used // ANCHOR: book_macro_code -#[cxx_qt::bridge(cxx_file_stem = "nested_qobjects")] +#[cxx_qt::bridge] pub mod qobject { // ANCHOR: book_extern_block extern "RustQt" { diff --git a/examples/qml_features/rust/src/properties.rs b/examples/qml_features/rust/src/properties.rs index 7ed7bea4c..182d84138 100644 --- a/examples/qml_features/rust/src/properties.rs +++ b/examples/qml_features/rust/src/properties.rs @@ -6,7 +6,7 @@ //! This example shows how a Q_PROPERTY can be used /// A CXX-Qt bridge which shows how a Q_PROPERTY can be used -#[cxx_qt::bridge(cxx_file_stem = "rust_properties")] +#[cxx_qt::bridge] pub mod qobject { unsafe extern "C++" { include!("cxx-qt-lib/qstring.h"); diff --git a/examples/qml_features/rust/src/serialisation.rs b/examples/qml_features/rust/src/serialisation.rs index 969893a42..9be6e20d1 100644 --- a/examples/qml_features/rust/src/serialisation.rs +++ b/examples/qml_features/rust/src/serialisation.rs @@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize}; /// A CXX-Qt bridge which shows how use serde for (de)serialization of the data in a QObjects' QPROPERTY's -#[cxx_qt::bridge(cxx_file_stem = "serialisation")] +#[cxx_qt::bridge] pub mod qobject { unsafe extern "C++" { include!("cxx-qt-lib/qstring.h"); diff --git a/examples/qml_features/rust/src/signals.rs b/examples/qml_features/rust/src/signals.rs index 49257fd13..18343ed52 100644 --- a/examples/qml_features/rust/src/signals.rs +++ b/examples/qml_features/rust/src/signals.rs @@ -7,7 +7,7 @@ /// A CXX-Qt bridge which shows how a Q_SIGNAL can be used // ANCHOR: book_macro_code -#[cxx_qt::bridge(cxx_file_stem = "rust_signals")] +#[cxx_qt::bridge] pub mod qobject { unsafe extern "C++" { include!("cxx-qt-lib/qstring.h"); diff --git a/examples/qml_features/rust/src/singleton.rs b/examples/qml_features/rust/src/singleton.rs index 9eefb0f28..18b5ad7e0 100644 --- a/examples/qml_features/rust/src/singleton.rs +++ b/examples/qml_features/rust/src/singleton.rs @@ -7,7 +7,7 @@ /// A CXX-Qt bridge which shows how a QML_SINGLETON can be used // ANCHOR: book_macro_code -#[cxx_qt::bridge(cxx_file_stem = "rust_singleton")] +#[cxx_qt::bridge] pub mod qobject { unsafe extern "RustQt" { #[qobject] diff --git a/examples/qml_features/rust/src/threading.rs b/examples/qml_features/rust/src/threading.rs index 90e319bcb..9525d4093 100644 --- a/examples/qml_features/rust/src/threading.rs +++ b/examples/qml_features/rust/src/threading.rs @@ -8,7 +8,7 @@ /// This example shows how to send data from a background thread to the Qt event loop to update data in the QObject // ANCHOR: book_macro_code // ANCHOR: book_namespace_macro -#[cxx_qt::bridge(cxx_file_stem = "threading_website", namespace = "cxx_qt::website")] +#[cxx_qt::bridge(namespace = "cxx_qt::website")] pub mod qobject { // ANCHOR_END: book_namespace_macro #[namespace = ""] diff --git a/examples/qml_features/rust/src/types.rs b/examples/qml_features/rust/src/types.rs index 220dd4bec..eae447b8c 100644 --- a/examples/qml_features/rust/src/types.rs +++ b/examples/qml_features/rust/src/types.rs @@ -34,10 +34,8 @@ impl cxx_qt_lib::QVariantValue for ffi::CustomStruct { // ANCHOR_END: book_qvariantvalue_impl /// A CXX-Qt bridge which shows how a custom type can be used with a QVariant -// ANCHOR: book_cxx_file_stem -#[cxx_qt::bridge(cxx_file_stem = "types")] +#[cxx_qt::bridge] pub mod ffi { - // ANCHOR_END: book_cxx_file_stem unsafe extern "C++" { include!("cxx-qt-lib/qpoint.h"); /// QPointF from cxx_qt_lib diff --git a/examples/qml_features/rust/src/uncreatable.rs b/examples/qml_features/rust/src/uncreatable.rs index 68f8da92e..28691cc5b 100644 --- a/examples/qml_features/rust/src/uncreatable.rs +++ b/examples/qml_features/rust/src/uncreatable.rs @@ -7,7 +7,7 @@ /// A CXX-Qt bridge which shows how a QML_UNCREATABLE QObject can be used // ANCHOR: book_macro_code -#[cxx_qt::bridge(cxx_file_stem = "rust_uncreatable")] +#[cxx_qt::bridge] pub mod ffi { extern "RustQt" { #[qobject] diff --git a/examples/qml_minimal/rust/src/cxxqt_object.rs b/examples/qml_minimal/rust/src/cxxqt_object.rs index a48b785ba..e469b319e 100644 --- a/examples/qml_minimal/rust/src/cxxqt_object.rs +++ b/examples/qml_minimal/rust/src/cxxqt_object.rs @@ -9,7 +9,7 @@ // ANCHOR: book_bridge_macro /// The bridge definition for our QObject -#[cxx_qt::bridge(cxx_file_stem = "cxxqt_object")] +#[cxx_qt::bridge] pub mod qobject { // ANCHOR_END: book_bridge_macro diff --git a/tests/basic_cxx_qt/cpp/main.cpp b/tests/basic_cxx_qt/cpp/main.cpp index 765f43301..8d4aa70dc 100644 --- a/tests/basic_cxx_qt/cpp/main.cpp +++ b/tests/basic_cxx_qt/cpp/main.cpp @@ -10,10 +10,10 @@ #include #include +#include "basic_cxx_qt/src/data.cxxqt.h" #include "basic_cxx_qt/src/empty.cxxqt.h" -#include "basic_cxx_qt/src/my_data.cxxqt.h" -#include "basic_cxx_qt/src/my_object.cxxqt.h" -#include "basic_cxx_qt/src/my_types.cxxqt.h" +#include "basic_cxx_qt/src/lib.cxxqt.h" +#include "basic_cxx_qt/src/types.cxxqt.h" class CxxQtTest : public QObject { diff --git a/tests/basic_cxx_qt/rust/src/data.rs b/tests/basic_cxx_qt/rust/src/data.rs index 1b4112299..34a646ae6 100644 --- a/tests/basic_cxx_qt/rust/src/data.rs +++ b/tests/basic_cxx_qt/rust/src/data.rs @@ -22,7 +22,7 @@ impl From<&MyDataRust> for DataSerde { } } -#[cxx_qt::bridge(cxx_file_stem = "my_data", namespace = "cxx_qt::my_data")] +#[cxx_qt::bridge(namespace = "cxx_qt::my_data")] mod qobject { #[namespace = ""] unsafe extern "C++" { diff --git a/tests/basic_cxx_qt/rust/src/empty.rs b/tests/basic_cxx_qt/rust/src/empty.rs index a54e74d1d..bac6b9715 100644 --- a/tests/basic_cxx_qt/rust/src/empty.rs +++ b/tests/basic_cxx_qt/rust/src/empty.rs @@ -3,7 +3,7 @@ // // SPDX-License-Identifier: MIT OR Apache-2.0 -#[cxx_qt::bridge(cxx_file_stem = "empty")] +#[cxx_qt::bridge] mod ffi { extern "RustQt" { #[qobject] diff --git a/tests/basic_cxx_qt/rust/src/lib.rs b/tests/basic_cxx_qt/rust/src/lib.rs index 9f2ca112b..c7e8aed7b 100644 --- a/tests/basic_cxx_qt/rust/src/lib.rs +++ b/tests/basic_cxx_qt/rust/src/lib.rs @@ -8,7 +8,7 @@ mod data; mod empty; mod types; -#[cxx_qt::bridge(cxx_file_stem = "my_object", namespace = "cxx_qt::my_object")] +#[cxx_qt::bridge(namespace = "cxx_qt::my_object")] mod qobject { #[namespace = ""] unsafe extern "C++" { diff --git a/tests/basic_cxx_qt/rust/src/types.rs b/tests/basic_cxx_qt/rust/src/types.rs index bddd2e070..c5a58962a 100644 --- a/tests/basic_cxx_qt/rust/src/types.rs +++ b/tests/basic_cxx_qt/rust/src/types.rs @@ -4,7 +4,7 @@ // // SPDX-License-Identifier: MIT OR Apache-2.0 -#[cxx_qt::bridge(cxx_file_stem = "my_types", namespace = "cxx_qt::my_types")] +#[cxx_qt::bridge(namespace = "cxx_qt::my_types")] mod ffi { extern "RustQt" { #[qobject] From 6d64e48e36f2826367f76bb1dc2ba89ec40cfa47 Mon Sep 17 00:00:00 2001 From: Andrew Hayzen Date: Wed, 4 Sep 2024 16:40:19 +0100 Subject: [PATCH 07/15] cxx-qt-gen: fix failing tests --- crates/cxx-qt-gen/src/generator/rust/mod.rs | 14 ++------------ crates/cxx-qt-gen/src/writer/rust/mod.rs | 16 ++++++---------- crates/cxx-qt-gen/test_outputs/inheritance.rs | 2 ++ crates/cxx-qt-gen/test_outputs/invokables.rs | 2 ++ .../test_outputs/passthrough_and_naming.rs | 2 ++ crates/cxx-qt-gen/test_outputs/properties.rs | 2 ++ crates/cxx-qt-gen/test_outputs/qenum.rs | 2 ++ crates/cxx-qt-gen/test_outputs/signals.rs | 2 ++ crates/qt-build-utils/src/lib.rs | 6 +----- 9 files changed, 21 insertions(+), 27 deletions(-) diff --git a/crates/cxx-qt-gen/src/generator/rust/mod.rs b/crates/cxx-qt-gen/src/generator/rust/mod.rs index a2467b98c..02aa54da6 100644 --- a/crates/cxx-qt-gen/src/generator/rust/mod.rs +++ b/crates/cxx-qt-gen/src/generator/rust/mod.rs @@ -100,8 +100,6 @@ mod tests { use super::*; - use crate::tests::assert_tokens_eq; - #[test] fn test_generated_rust_blocks() { let module: ItemMod = parse_quote! { @@ -117,15 +115,7 @@ mod tests { let rust = GeneratedRustBlocks::from(&parser).unwrap(); assert!(rust.cxx_mod.content.is_none()); - assert_eq!(rust.cxx_mod_contents.len(), 1); - assert_tokens_eq( - &rust.cxx_mod_contents[0], - quote! { - unsafe extern "C++" { - include!("cxx-qt-gen/ffi.cxxqt.h"); - } - }, - ); + assert_eq!(rust.cxx_mod_contents.len(), 0); assert_eq!(rust.namespace, ""); assert_eq!(rust.fragments.len(), 1); } @@ -145,7 +135,7 @@ mod tests { let rust = GeneratedRustBlocks::from(&parser).unwrap(); assert!(rust.cxx_mod.content.is_none()); - assert_eq!(rust.cxx_mod_contents.len(), 1); + assert_eq!(rust.cxx_mod_contents.len(), 0); assert_eq!(rust.namespace, "cxx_qt"); assert_eq!(rust.fragments.len(), 1); } diff --git a/crates/cxx-qt-gen/src/writer/rust/mod.rs b/crates/cxx-qt-gen/src/writer/rust/mod.rs index a0fd2fe27..990980357 100644 --- a/crates/cxx-qt-gen/src/writer/rust/mod.rs +++ b/crates/cxx-qt-gen/src/writer/rust/mod.rs @@ -102,11 +102,7 @@ mod tests { cxx_mod: parse_quote! { mod ffi {} }, - cxx_mod_contents: vec![parse_quote! { - unsafe extern "C++" { - include!("myobject.cxxqt.h"); - } - }], + cxx_mod_contents: vec![], namespace: "cxx_qt::my_object".to_owned(), fragments: vec![GeneratedRustFragment { cxx_mod_contents: vec![ @@ -144,11 +140,7 @@ mod tests { cxx_mod: parse_quote! { mod ffi {} }, - cxx_mod_contents: vec![parse_quote! { - unsafe extern "C++" { - include!("multiobject.cxxqt.h"); - } - }], + cxx_mod_contents: vec![], namespace: "cxx_qt".to_owned(), fragments: vec![ GeneratedRustFragment { @@ -221,11 +213,13 @@ mod tests { #[doc(hidden)] #[namespace = "Qt"] #[rust_name = "CxxQtConnectionType"] + #[allow(dead_code)] type ConnectionType = cxx_qt::ConnectionType; #[doc(hidden)] #[namespace = "rust::cxxqt1"] #[rust_name = "CxxQtQMetaObjectConnection"] + #[allow(dead_code)] type QMetaObjectConnection = cxx_qt::QMetaObjectConnection; } @@ -267,11 +261,13 @@ mod tests { #[doc(hidden)] #[namespace = "Qt"] #[rust_name = "CxxQtConnectionType"] + #[allow(dead_code)] type ConnectionType = cxx_qt::ConnectionType; #[doc(hidden)] #[namespace = "rust::cxxqt1"] #[rust_name = "CxxQtQMetaObjectConnection"] + #[allow(dead_code)] type QMetaObjectConnection = cxx_qt::QMetaObjectConnection; } diff --git a/crates/cxx-qt-gen/test_outputs/inheritance.rs b/crates/cxx-qt-gen/test_outputs/inheritance.rs index a8f65750f..139dc0a2d 100644 --- a/crates/cxx-qt-gen/test_outputs/inheritance.rs +++ b/crates/cxx-qt-gen/test_outputs/inheritance.rs @@ -12,10 +12,12 @@ mod inheritance { #[doc(hidden)] #[namespace = "Qt"] #[rust_name = "CxxQtConnectionType"] + #[allow(dead_code)] type ConnectionType = cxx_qt::ConnectionType; #[doc(hidden)] #[namespace = "rust::cxxqt1"] #[rust_name = "CxxQtQMetaObjectConnection"] + #[allow(dead_code)] type QMetaObjectConnection = cxx_qt::QMetaObjectConnection; } unsafe extern "C++" { diff --git a/crates/cxx-qt-gen/test_outputs/invokables.rs b/crates/cxx-qt-gen/test_outputs/invokables.rs index 8dd37a601..e61f793d2 100644 --- a/crates/cxx-qt-gen/test_outputs/invokables.rs +++ b/crates/cxx-qt-gen/test_outputs/invokables.rs @@ -18,10 +18,12 @@ mod ffi { #[doc(hidden)] #[namespace = "Qt"] #[rust_name = "CxxQtConnectionType"] + #[allow(dead_code)] type ConnectionType = cxx_qt::ConnectionType; #[doc(hidden)] #[namespace = "rust::cxxqt1"] #[rust_name = "CxxQtQMetaObjectConnection"] + #[allow(dead_code)] type QMetaObjectConnection = cxx_qt::QMetaObjectConnection; } unsafe extern "C++" { diff --git a/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.rs b/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.rs index 4b5b0409d..fa31465e3 100644 --- a/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.rs +++ b/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.rs @@ -60,10 +60,12 @@ pub mod ffi { #[doc(hidden)] #[namespace = "Qt"] #[rust_name = "CxxQtConnectionType"] + #[allow(dead_code)] type ConnectionType = cxx_qt::ConnectionType; #[doc(hidden)] #[namespace = "rust::cxxqt1"] #[rust_name = "CxxQtQMetaObjectConnection"] + #[allow(dead_code)] type QMetaObjectConnection = cxx_qt::QMetaObjectConnection; } unsafe extern "C++" { diff --git a/crates/cxx-qt-gen/test_outputs/properties.rs b/crates/cxx-qt-gen/test_outputs/properties.rs index 19fd7abef..9f9e96561 100644 --- a/crates/cxx-qt-gen/test_outputs/properties.rs +++ b/crates/cxx-qt-gen/test_outputs/properties.rs @@ -11,10 +11,12 @@ mod ffi { #[doc(hidden)] #[namespace = "Qt"] #[rust_name = "CxxQtConnectionType"] + #[allow(dead_code)] type ConnectionType = cxx_qt::ConnectionType; #[doc(hidden)] #[namespace = "rust::cxxqt1"] #[rust_name = "CxxQtQMetaObjectConnection"] + #[allow(dead_code)] type QMetaObjectConnection = cxx_qt::QMetaObjectConnection; } unsafe extern "C++" { diff --git a/crates/cxx-qt-gen/test_outputs/qenum.rs b/crates/cxx-qt-gen/test_outputs/qenum.rs index 0daa541c4..b32256dad 100644 --- a/crates/cxx-qt-gen/test_outputs/qenum.rs +++ b/crates/cxx-qt-gen/test_outputs/qenum.rs @@ -6,10 +6,12 @@ mod ffi { #[doc(hidden)] #[namespace = "Qt"] #[rust_name = "CxxQtConnectionType"] + #[allow(dead_code)] type ConnectionType = cxx_qt::ConnectionType; #[doc(hidden)] #[namespace = "rust::cxxqt1"] #[rust_name = "CxxQtQMetaObjectConnection"] + #[allow(dead_code)] type QMetaObjectConnection = cxx_qt::QMetaObjectConnection; } unsafe extern "C++" { diff --git a/crates/cxx-qt-gen/test_outputs/signals.rs b/crates/cxx-qt-gen/test_outputs/signals.rs index e6bccfd85..327a67962 100644 --- a/crates/cxx-qt-gen/test_outputs/signals.rs +++ b/crates/cxx-qt-gen/test_outputs/signals.rs @@ -12,10 +12,12 @@ mod ffi { #[doc(hidden)] #[namespace = "Qt"] #[rust_name = "CxxQtConnectionType"] + #[allow(dead_code)] type ConnectionType = cxx_qt::ConnectionType; #[doc(hidden)] #[namespace = "rust::cxxqt1"] #[rust_name = "CxxQtQMetaObjectConnection"] + #[allow(dead_code)] type QMetaObjectConnection = cxx_qt::QMetaObjectConnection; } unsafe extern "C++" { diff --git a/crates/qt-build-utils/src/lib.rs b/crates/qt-build-utils/src/lib.rs index 604c78bd6..8f35d0b43 100644 --- a/crates/qt-build-utils/src/lib.rs +++ b/crates/qt-build-utils/src/lib.rs @@ -984,11 +984,7 @@ Q_IMPORT_PLUGIN({plugin_class_name}); std::fs::create_dir_all(&output_folder).expect("Could not create qrc dir"); let output_path = output_folder.join(format!( "{}.cpp", - input_path - .file_name() - .unwrap() - .to_string_lossy() - .to_string(), + input_path.file_name().unwrap().to_string_lossy(), )); let cmd = Command::new(self.rcc_executable.as_ref().unwrap()) From 226d3637bdf4c78be7442d673fc2e8266452a479 Mon Sep 17 00:00:00 2001 From: Andrew Hayzen Date: Wed, 4 Sep 2024 16:51:30 +0100 Subject: [PATCH 08/15] book: remove line about cxx_file_stem and Span::source_file() --- book/src/bridge/extern_rustqt.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/book/src/bridge/extern_rustqt.md b/book/src/bridge/extern_rustqt.md index c65b1f02e..9ddf03a42 100644 --- a/book/src/bridge/extern_rustqt.md +++ b/book/src/bridge/extern_rustqt.md @@ -25,8 +25,6 @@ The `extern "RustQt"` section of a CXX bridge declares Rust types and signatures The CXX code generator uses your `extern "Rust"` section(s) to produce a C++ header file containing the corresponding C++ declarations. The generated header has the same file name as the input rust file but with `.cxxqt.h` file extension. -> Note that once there is support for `source_file` or similar in the `Span` macro we want to support copying the file name like CXX. - A bridge module may contain zero or more `extern "RustQt"` blocks. This complements the [`extern "Rust"` CXX section](https://cxx.rs/extern-rust.html) From a91fd6f55eca7794cd62a76f6972a5c0be65bc6a Mon Sep 17 00:00:00 2001 From: Andrew Hayzen Date: Wed, 4 Sep 2024 17:12:22 +0100 Subject: [PATCH 09/15] cxx-qt-gen: add test to ensure cxx_file_stem fails --- crates/cxx-qt-gen/src/parser/mod.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/crates/cxx-qt-gen/src/parser/mod.rs b/crates/cxx-qt-gen/src/parser/mod.rs index b5584aaf5..f94efbe98 100644 --- a/crates/cxx-qt-gen/src/parser/mod.rs +++ b/crates/cxx-qt-gen/src/parser/mod.rs @@ -199,6 +199,20 @@ mod tests { assert_eq!(parser.cxx_qt_data.qobjects.len(), 0); } + #[test] + fn test_bridge_cxx_file_stem() { + let module: ItemMod = parse_quote! { + #[cxx_qt::bridge(cxx_file_stem = "stem")] + mod ffi { + extern "Rust" { + fn test(); + } + } + }; + let parser = Parser::from(module); + assert!(parser.is_err()); + } + #[test] fn test_incorrect_bridge_args() { let module: ItemMod = parse_quote! { From f1a48bcb0ffcaa6378397d0a657f22e01d594853 Mon Sep 17 00:00:00 2001 From: Andrew Hayzen Date: Thu, 5 Sep 2024 12:38:16 +0100 Subject: [PATCH 10/15] errors: improve error messages for cxx_file_stem and multiple dirs --- crates/cxx-qt-build/src/lib.rs | 6 +++++- crates/cxx-qt-gen/src/parser/mod.rs | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/crates/cxx-qt-build/src/lib.rs b/crates/cxx-qt-build/src/lib.rs index 2219ba6a4..0e6a4f6c5 100644 --- a/crates/cxx-qt-build/src/lib.rs +++ b/crates/cxx-qt-build/src/lib.rs @@ -773,7 +773,11 @@ impl CxxQtBuilder { }) .collect::>(); if dirs.len() > 1 { - panic!("Only one directory is support per QmlModule for rust_files"); + panic!( + "Only one directory is supported per QmlModule for rust_files.\n\ + This is due to Qt bug https://bugreports.qt.io/browse/QTBUG-93443\n\ + Found directories: {dirs:?}" + ); } for files in generate_cxxqt_cpp_files( diff --git a/crates/cxx-qt-gen/src/parser/mod.rs b/crates/cxx-qt-gen/src/parser/mod.rs index f94efbe98..0af1a5010 100644 --- a/crates/cxx-qt-gen/src/parser/mod.rs +++ b/crates/cxx-qt-gen/src/parser/mod.rs @@ -85,7 +85,7 @@ impl Parser { } else if name_value.path.is_ident("cxx_file_stem") { return Err(Error::new( meta.span(), - "cxx_file_stem is unsupported: TODO new system message", + "cxx_file_stem is unsupported, instead the input file name will be used", )); } } From 330e7e55fb8a5b8b65b472bf8cf02009417cefde Mon Sep 17 00:00:00 2001 From: Andrew Hayzen Date: Fri, 6 Sep 2024 13:07:57 +0100 Subject: [PATCH 11/15] cxx-qt-build: remove use of syn it is not used --- crates/cxx-qt-build/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/cxx-qt-build/Cargo.toml b/crates/cxx-qt-build/Cargo.toml index bf100dde6..1aa11fdac 100644 --- a/crates/cxx-qt-build/Cargo.toml +++ b/crates/cxx-qt-build/Cargo.toml @@ -24,7 +24,6 @@ codespan-reporting = "0.11" version_check = "0.9" serde = { version = "1.0", features = ["default", "derive"] } serde_json = "1.0" -syn.workspace = true [features] link_qt_object_files = ["qt-build-utils/link_qt_object_files"] From ec9e0b8de596a9f59a94cdec309a30e8f774fcc8 Mon Sep 17 00:00:00 2001 From: Andrew Hayzen Date: Fri, 6 Sep 2024 13:08:51 +0100 Subject: [PATCH 12/15] cxx-qt-build: use a cloned builder for qml modules --- crates/cxx-qt-build/src/lib.rs | 62 ++++++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 11 deletions(-) diff --git a/crates/cxx-qt-build/src/lib.rs b/crates/cxx-qt-build/src/lib.rs index 0e6a4f6c5..1f06141e8 100644 --- a/crates/cxx-qt-build/src/lib.rs +++ b/crates/cxx-qt-build/src/lib.rs @@ -302,6 +302,14 @@ fn static_lib_name() -> String { format!("{}-cxxqt-generated", crate_name()) } +fn qml_module_static_lib_name(module_uri: &str) -> String { + format!( + "{}-qml-module-{}-cxxqt-generated", + crate_name(), + module_name_from_uri(module_uri) + ) +} + fn panic_duplicate_file_and_qml_module( path: impl AsRef, uri: &str, @@ -744,7 +752,9 @@ impl CxxQtBuilder { qtbuild: &mut qt_build_utils::QtBuild, generated_header_dir: impl AsRef, header_prefix: &str, - ) { + ) -> Vec { + let mut qml_libraries = vec![]; + for qml_module in &self.qml_modules { dir::clean(dir::module_target(&qml_module.uri)) .expect("Failed to clean qml module export directory!"); @@ -780,30 +790,40 @@ impl CxxQtBuilder { ); } + // Use a separate cc_builder per QML module so we don't have collisions + // + // TODO: for now we copy the global CxxQtBuilder cc_builder + // this means that any includes/files etc on these are in this builder + // but we cannot have separate builds until we can configure includes, + // qt modules, files, cc_builder options etc in the QmlModule itself + let mut cc_builder = self.cc_builder.clone(); + qtbuild.cargo_link_libraries(&mut cc_builder); + + let mut moc_include_paths = HashSet::new(); for files in generate_cxxqt_cpp_files( &qml_module.rust_files, &generated_header_dir, header_prefix, ) { - self.cc_builder.file(files.plain_cpp); + cc_builder.file(files.plain_cpp); if let (Some(qobject), Some(qobject_header)) = (files.qobject, files.qobject_header) { // Ensure that the generated QObject header is in the include path // so that qmltyperegistar can include them later if let Some(dir) = qobject_header.parent() { - self.cc_builder.include(dir); + moc_include_paths.insert(dir.to_path_buf()); } - self.cc_builder.file(&qobject); + cc_builder.file(&qobject); let moc_products = qtbuild.moc( qobject_header, MocArguments::default().uri(qml_module.uri.clone()), ); // Include the moc folder if let Some(dir) = moc_products.cpp.parent() { - self.cc_builder.include(dir); + moc_include_paths.insert(dir.to_path_buf()); } - self.cc_builder.file(moc_products.cpp); + cc_builder.file(moc_products.cpp); qml_metatypes_json.push(moc_products.metatypes_json); } } @@ -820,7 +840,7 @@ impl CxxQtBuilder { &qml_module.qml_files, &qml_module.qrc_files, ); - self.cc_builder + cc_builder .file(qml_module_registration_files.qmltyperegistrar) .file(qml_module_registration_files.plugin) // In comparison to the other RCC files, we don't need to link this with whole-archive or @@ -832,14 +852,19 @@ impl CxxQtBuilder { // Add any include paths the qml module registration needs // this is most likely the moc folder for the plugin if let Some(include_path) = qml_module_registration_files.include_path { - self.cc_builder.include(include_path); + moc_include_paths.insert(include_path); + } + + // Ensure that all include paths from moc folders that are required + for include_path in &moc_include_paths { + cc_builder.include(include_path); } for qmlcachegen_file in qml_module_registration_files.qmlcachegen { - self.cc_builder.file(qmlcachegen_file); + cc_builder.file(qmlcachegen_file); } // This is required, as described here: plugin_builder - self.cc_builder.define("QT_STATICPLUGIN", None); + cc_builder.define("QT_STATICPLUGIN", None); // If any of the files inside the qml module change, then trigger a rerun for path in qml_module.qml_files.iter().chain( @@ -864,7 +889,17 @@ impl CxxQtBuilder { &qml_module_registration_files.plugin_init, dir::module_target(&qml_module.uri).join("plugin_init.o"), ); + + // Build the QML module as a library + if cc_builder.get_files().count() > 0 { + let qml_library_name = qml_module_static_lib_name(&qml_module.uri); + cc_builder.compile(&qml_library_name); + + qml_libraries.push(qml_library_name); + } } + + qml_libraries } fn setup_qt5_compatibility(&mut self, qtbuild: &qt_build_utils::QtBuild) { @@ -1053,13 +1088,18 @@ impl CxxQtBuilder { // Bridges for QML modules are handled separately because // the metatypes_json generated by moc needs to be passed to qmltyperegistrar - self.build_qml_modules( + let qml_libraries = self.build_qml_modules( &init_builder, &mut qtbuild, &header_root, &self.include_prefix.clone(), ); + // Link all of the qml libraries + for qml_library in &qml_libraries { + println!("cargo:rustc-link-lib={qml_library}"); + } + let mut initializers = self.generate_cpp_from_qrc_files(&mut qtbuild); initializers.extend(dependencies::initializer_paths( self.public_interface.as_ref(), From 1c6a3d65ccb6a176684d3dc3656e9b4ac0ca1cc2 Mon Sep 17 00:00:00 2001 From: Andrew Hayzen Date: Fri, 6 Sep 2024 13:09:07 +0100 Subject: [PATCH 13/15] cxx-qt-build: use full directory path when comparing qml roots --- crates/cxx-qt-build/src/lib.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/cxx-qt-build/src/lib.rs b/crates/cxx-qt-build/src/lib.rs index 1f06141e8..f75386c45 100644 --- a/crates/cxx-qt-build/src/lib.rs +++ b/crates/cxx-qt-build/src/lib.rs @@ -774,12 +774,12 @@ impl CxxQtBuilder { .rust_files .iter() .map(|file| { - file.parent() - .unwrap() - .file_name() - .unwrap() - .to_string_lossy() - .to_string() + if let Some(parent) = file.parent() { + parent.to_string_lossy().to_string() + } else { + // Fallback to an empty string if there is no parent path + String::new() + } }) .collect::>(); if dirs.len() > 1 { From 9dfc06ddd46a6c6997d1331938e2ac291dbc4425 Mon Sep 17 00:00:00 2001 From: Andrew Hayzen Date: Mon, 9 Sep 2024 09:59:41 +0100 Subject: [PATCH 14/15] cxx-qt-build: use only link when building --- crates/cxx-qt-build/src/lib.rs | 37 +++++++++++++++++----------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/crates/cxx-qt-build/src/lib.rs b/crates/cxx-qt-build/src/lib.rs index f75386c45..2667224c9 100644 --- a/crates/cxx-qt-build/src/lib.rs +++ b/crates/cxx-qt-build/src/lib.rs @@ -732,11 +732,6 @@ impl CxxQtBuilder { }); } else { println!("cargo::rustc-link-arg={}", obj_file.to_string_lossy()); - // The linker argument order matters! - // We need to link the object file first, then link the static library. - // Otherwise, the linker will be unable to find the symbols in the static library file. - // See also: https://stackoverflow.com/questions/45135/why-does-the-order-in-which-libraries-are-linked-sometimes-cause-errors-in-gcc - println!("cargo::rustc-link-arg=-l{}", static_lib_name()); } } else { panic!( @@ -752,9 +747,7 @@ impl CxxQtBuilder { qtbuild: &mut qt_build_utils::QtBuild, generated_header_dir: impl AsRef, header_prefix: &str, - ) -> Vec { - let mut qml_libraries = vec![]; - + ) { for qml_module in &self.qml_modules { dir::clean(dir::module_target(&qml_module.uri)) .expect("Failed to clean qml module export directory!"); @@ -893,13 +886,18 @@ impl CxxQtBuilder { // Build the QML module as a library if cc_builder.get_files().count() > 0 { let qml_library_name = qml_module_static_lib_name(&qml_module.uri); - cc_builder.compile(&qml_library_name); - qml_libraries.push(qml_library_name); + // The linker argument order matters! + // We need to link the object file first, then link the static library. + // Otherwise, the linker will be unable to find the symbols in the static library file. + // See also: https://stackoverflow.com/questions/45135/why-does-the-order-in-which-libraries-are-linked-sometimes-cause-errors-in-gcc + if !dir::is_exporting() { + println!("cargo::rustc-link-arg=-l{}", &qml_library_name); + } + + cc_builder.compile(&qml_library_name); } } - - qml_libraries } fn setup_qt5_compatibility(&mut self, qtbuild: &qt_build_utils::QtBuild) { @@ -1088,18 +1086,13 @@ impl CxxQtBuilder { // Bridges for QML modules are handled separately because // the metatypes_json generated by moc needs to be passed to qmltyperegistrar - let qml_libraries = self.build_qml_modules( + self.build_qml_modules( &init_builder, &mut qtbuild, &header_root, &self.include_prefix.clone(), ); - // Link all of the qml libraries - for qml_library in &qml_libraries { - println!("cargo:rustc-link-lib={qml_library}"); - } - let mut initializers = self.generate_cpp_from_qrc_files(&mut qtbuild); initializers.extend(dependencies::initializer_paths( self.public_interface.as_ref(), @@ -1113,6 +1106,14 @@ impl CxxQtBuilder { // Only compile if we have added files to the builder // otherwise we end up with no static library but ask cargo to link to it which causes an error if self.cc_builder.get_files().count() > 0 { + // The linker argument order matters! + // We need to link the object file first, then link the static library. + // Otherwise, the linker will be unable to find the symbols in the static library file. + // See also: https://stackoverflow.com/questions/45135/why-does-the-order-in-which-libraries-are-linked-sometimes-cause-errors-in-gcc + if !dir::is_exporting() { + println!("cargo::rustc-link-arg=-l{}", static_lib_name()); + } + self.cc_builder.compile(&static_lib_name()); } From 7b6cfc72ff0df5f7b19874cd14f31740f5dcee8a Mon Sep 17 00:00:00 2001 From: Andrew Hayzen Date: Mon, 9 Sep 2024 18:02:20 +0100 Subject: [PATCH 15/15] cxx-qt-build: use same builder for now for all qml modules --- crates/cxx-qt-build/src/lib.rs | 31 +++---------------------------- 1 file changed, 3 insertions(+), 28 deletions(-) diff --git a/crates/cxx-qt-build/src/lib.rs b/crates/cxx-qt-build/src/lib.rs index 2667224c9..353812c78 100644 --- a/crates/cxx-qt-build/src/lib.rs +++ b/crates/cxx-qt-build/src/lib.rs @@ -302,14 +302,6 @@ fn static_lib_name() -> String { format!("{}-cxxqt-generated", crate_name()) } -fn qml_module_static_lib_name(module_uri: &str) -> String { - format!( - "{}-qml-module-{}-cxxqt-generated", - crate_name(), - module_name_from_uri(module_uri) - ) -} - fn panic_duplicate_file_and_qml_module( path: impl AsRef, uri: &str, @@ -783,14 +775,12 @@ impl CxxQtBuilder { ); } - // Use a separate cc_builder per QML module so we don't have collisions - // - // TODO: for now we copy the global CxxQtBuilder cc_builder + // TODO: for now we use the global CxxQtBuilder cc_builder // this means that any includes/files etc on these are in this builder // but we cannot have separate builds until we can configure includes, // qt modules, files, cc_builder options etc in the QmlModule itself - let mut cc_builder = self.cc_builder.clone(); - qtbuild.cargo_link_libraries(&mut cc_builder); + let cc_builder = &mut self.cc_builder; + qtbuild.cargo_link_libraries(cc_builder); let mut moc_include_paths = HashSet::new(); for files in generate_cxxqt_cpp_files( @@ -882,21 +872,6 @@ impl CxxQtBuilder { &qml_module_registration_files.plugin_init, dir::module_target(&qml_module.uri).join("plugin_init.o"), ); - - // Build the QML module as a library - if cc_builder.get_files().count() > 0 { - let qml_library_name = qml_module_static_lib_name(&qml_module.uri); - - // The linker argument order matters! - // We need to link the object file first, then link the static library. - // Otherwise, the linker will be unable to find the symbols in the static library file. - // See also: https://stackoverflow.com/questions/45135/why-does-the-order-in-which-libraries-are-linked-sometimes-cause-errors-in-gcc - if !dir::is_exporting() { - println!("cargo::rustc-link-arg=-l{}", &qml_library_name); - } - - cc_builder.compile(&qml_library_name); - } } }