Skip to content

Commit

Permalink
Extract QtBuildUtils::moc() arguments into struct
Browse files Browse the repository at this point in the history
  • Loading branch information
LeonMatthesKDAB committed Mar 6, 2024
1 parent 5cee57d commit 618bd9a
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 18 deletions.
29 changes: 22 additions & 7 deletions crates/cxx-qt-build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ mod qml_modules;
use qml_modules::OwningQmlModule;
pub use qml_modules::QmlModule;

pub use qt_build_utils::MocArguments;
use quote::ToTokens;
use std::{
collections::HashSet,
Expand Down Expand Up @@ -303,7 +304,7 @@ fn panic_duplicate_file_and_qml_module(
#[derive(Default)]
pub struct CxxQtBuilder {
rust_sources: Vec<PathBuf>,
qobject_headers: Vec<PathBuf>,
qobject_headers: Vec<(PathBuf, MocArguments)>,
qobject_header_includes: Vec<PathBuf>,
qrc_files: Vec<PathBuf>,
qt_modules: HashSet<String>,
Expand Down Expand Up @@ -416,9 +417,19 @@ impl CxxQtBuilder {

/// Specify a C++ header containing a Q_OBJECT macro to run [moc](https://doc.qt.io/qt-6/moc.html) on.
/// This allows building QObject C++ subclasses besides the ones autogenerated by cxx-qt.
pub fn qobject_header(mut self, path: impl AsRef<Path>) -> Self {
pub fn qobject_header(self, path: impl AsRef<Path>) -> Self {
self.qobject_header_with_arguments(path, MocArguments::default())
}

/// Specify a C++ header containing a Q_OBJECT macro to run [moc](https://doc.qt.io/qt-6/moc.html) on with the given arguments.
/// This allows building QObject C++ subclasses besides the ones autogenerated by cxx-qt.
pub fn qobject_header_with_arguments(
mut self,
path: impl AsRef<Path>,
arguments: MocArguments,
) -> Self {
let path = path.as_ref();
self.qobject_headers.push(path.to_owned());
self.qobject_headers.push((path.to_owned(), arguments));
println!("cargo:rerun-if-changed={}", path.display());
self
}
Expand Down Expand Up @@ -559,13 +570,14 @@ impl CxxQtBuilder {
self.cc_builder.file(files.plain_cpp);
if let (Some(qobject), Some(qobject_header)) = (files.qobject, files.qobject_header) {
self.cc_builder.file(&qobject);
self.qobject_headers.push(qobject_header);
self.qobject_headers
.push((qobject_header, MocArguments::default()));
}
}

// Run moc on C++ headers with Q_OBJECT macro
for qobject_header in self.qobject_headers {
let moc_products = qtbuild.moc(&qobject_header, None, &self.qobject_header_includes);
for (qobject_header, moc_arguments) in self.qobject_headers {
let moc_products = qtbuild.moc(&qobject_header, moc_arguments);
self.cc_builder.file(moc_products.cpp);
}

Expand All @@ -583,7 +595,10 @@ impl CxxQtBuilder {
if let (Some(qobject), Some(qobject_header)) = (files.qobject, files.qobject_header)
{
self.cc_builder.file(&qobject);
let moc_products = qtbuild.moc(qobject_header, Some(&qml_module.uri), &vec![]);
let moc_products = qtbuild.moc(
qobject_header,
MocArguments::default().uri(qml_module.uri.clone()),
);
self.cc_builder.file(moc_products.cpp);
qml_metatypes_json.push(moc_products.metatypes_json);
}
Expand Down
54 changes: 43 additions & 11 deletions crates/qt-build-utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,34 @@ pub struct MocProducts {
pub metatypes_json: PathBuf,
}

/// Arguments for a Qt moc invocation.
/// See: [QtBuild::moc]
#[derive(Default, Clone)]
pub struct MocArguments {
uri: Option<String>,
include_paths: Vec<PathBuf>,
}

impl MocArguments {
/// Should be passed if the input_file is part of a QML module
pub fn uri(mut self, uri: String) -> Self {
self.uri = Some(uri);
self
}

/// Additional include path to pass to moc
pub fn include_path(mut self, include_path: PathBuf) -> Self {
self.include_paths.push(include_path);
self
}

/// Additional include paths to pass to moc.
pub fn include_paths(mut self, mut include_paths: Vec<PathBuf>) -> Self {
self.include_paths.append(&mut include_paths);
self
}
}

/// Paths to C++ files generated by [QtBuild::register_qml_module]
pub struct QmlModuleRegistrationFiles {
/// File generated by [rcc](https://doc.qt.io/qt-6/rcc.html) for the QML plugin. The compiled static library
Expand Down Expand Up @@ -541,9 +569,7 @@ impl QtBuild {
/// The return value contains the path to the generated C++ file, which can then be passed to [cc::Build::files](https://docs.rs/cc/latest/cc/struct.Build.html#method.file),
/// as well as the path to the generated metatypes.json file, which can be passed to [register_qml_module](Self::register_qml_module).
///
/// * uri - Should be passed if the input_file is part of a QML module
/// * include_paths - Additional include paths to pass to moc
pub fn moc(&mut self, input_file: impl AsRef<Path>, uri: Option<&str>, include_paths: &Vec<PathBuf>) -> MocProducts {
pub fn moc(&mut self, input_file: impl AsRef<Path>, arguments: MocArguments) -> MocProducts {
if self.moc_executable.is_none() {
self.moc_executable = Some(self.get_qt_tool("moc").expect("Could not find moc"));
}
Expand All @@ -559,18 +585,18 @@ impl QtBuild {

let mut include_args = String::new();
// Qt includes
for include_path in self.include_paths() {
include_args += &format!("-I {} ", include_path.display());
}
// User includes
for include_path in include_paths {
for include_path in self
.include_paths()
.iter()
.chain(arguments.include_paths.iter())
{
include_args += &format!("-I {} ", include_path.display());
}

let mut cmd = Command::new(self.moc_executable.as_ref().unwrap());

if let Some(uri) = uri {
cmd.arg(&format!("-Muri={}", uri));
if let Some(uri) = arguments.uri {
cmd.arg(&format!("-Muri={uri}"));
}

cmd.args(include_args.trim_end().split(' '));
Expand Down Expand Up @@ -844,7 +870,13 @@ public:
"#
)
.unwrap();
self.moc(&qml_plugin_cpp_path, Some(uri), &vec![]);
self.moc(
&qml_plugin_cpp_path,
MocArguments {
uri: Some(uri.to_owned()),
..Default::default()
},
);

// Generate file to load static QQmlExtensionPlugin
let mut qml_plugin_init = File::create(&qml_plugin_init_path).unwrap();
Expand Down

0 comments on commit 618bd9a

Please sign in to comment.