Skip to content

Commit 7d5c679

Browse files
committed
qt-build-utils: split out rcc into a tool
1 parent 6f69a78 commit 7d5c679

File tree

3 files changed

+133
-78
lines changed

3 files changed

+133
-78
lines changed

crates/qt-build-utils/src/lib.rs

Lines changed: 16 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ pub use installation::qmake::QtInstallationQMake;
3131
mod parse_cflags;
3232

3333
mod tool;
34-
pub use tool::QtTool;
34+
pub use tool::{QtTool, QtToolRcc};
3535

3636
mod utils;
3737

@@ -609,92 +609,30 @@ Q_IMPORT_PLUGIN({plugin_class_name});
609609
}
610610
}
611611

612+
/// Create a [QtToolRcc] for this [QtBuild]
613+
///
614+
/// This allows for using [rcc](https://doc.qt.io/qt-6/resources.html)
615+
pub fn rcc(&self) -> QtToolRcc {
616+
QtToolRcc::new(self.qt_installation.as_ref())
617+
}
618+
612619
/// Run [rcc](https://doc.qt.io/qt-6/resources.html) on a .qrc file and save the output into [cargo's OUT_DIR](https://doc.rust-lang.org/cargo/reference/environment-variables.html).
613620
/// The path to the generated C++ file is returned, which can then be passed to [cc::Build::files](https://docs.rs/cc/latest/cc/struct.Build.html#method.file).
614621
/// This function also returns a String that contains the name of the resource initializer
615622
/// function.
616623
/// The build system must ensure that if the .cpp file is built into a static library, either
617624
/// the `+whole-archive` flag is used, or the initializer function is called by the
618625
/// application.
619-
pub fn qrc(&mut self, input_file: &impl AsRef<Path>) -> Initializer {
620-
let rcc_executable = self
621-
.qt_installation
622-
.try_find_tool(QtTool::Rcc)
623-
.expect("Could not find rcc");
624-
let input_path = input_file.as_ref();
625-
let output_folder = PathBuf::from(&format!(
626-
"{}/qt-build-utils/qrc",
627-
env::var("OUT_DIR").unwrap()
628-
));
629-
std::fs::create_dir_all(&output_folder).expect("Could not create qrc dir");
630-
let output_path = output_folder.join(format!(
631-
"{}.cpp",
632-
input_path.file_name().unwrap().to_string_lossy(),
633-
));
634-
let name = input_path
635-
.file_name()
636-
.unwrap()
637-
.to_string_lossy()
638-
.replace('.', "_");
639-
640-
let cmd = Command::new(rcc_executable)
641-
.args([
642-
input_path.to_str().unwrap(),
643-
"-o",
644-
output_path.to_str().unwrap(),
645-
"--name",
646-
&name,
647-
])
648-
.output()
649-
.unwrap_or_else(|_| panic!("rcc failed for {}", input_path.display()));
650-
651-
if !cmd.status.success() {
652-
panic!(
653-
"rcc failed for {}:\n{}",
654-
input_path.display(),
655-
String::from_utf8_lossy(&cmd.stderr)
656-
);
657-
}
658-
659-
let qt_6_5 = Version::new(6, 5, 0);
660-
let init_header = if self.qt_installation.version() >= qt_6_5 {
661-
// With Qt6.5 the Q_INIT_RESOURCE macro is in the QtResource header
662-
"QtCore/QtResource"
663-
} else {
664-
"QtCore/QDir"
665-
};
666-
Initializer {
667-
file: Some(output_path),
668-
init_call: Some(format!("Q_INIT_RESOURCE({name});")),
669-
init_declaration: Some(format!("#include <{init_header}>")),
670-
}
626+
pub fn qrc(&mut self, input_file: impl AsRef<Path>) -> Initializer {
627+
// TODO: later change to just have a rcc() -> QtToolRcc
628+
// but keep this for compat for now
629+
QtToolRcc::new(self.qt_installation.as_ref()).compile(input_file)
671630
}
672631

673632
/// Run [rcc](https://doc.qt.io/qt-6/resources.html) on a .qrc file and return the paths of the sources
674-
pub fn qrc_list(&mut self, input_file: &impl AsRef<Path>) -> Vec<PathBuf> {
675-
let rcc_executable = self
676-
.qt_installation
677-
.try_find_tool(QtTool::Rcc)
678-
.expect("Could not find rcc");
679-
680-
// Add the qrc file contents to the cargo rerun list
681-
let input_path = input_file.as_ref();
682-
let cmd_list = Command::new(rcc_executable)
683-
.args(["--list", input_path.to_str().unwrap()])
684-
.output()
685-
.unwrap_or_else(|_| panic!("rcc --list failed for {}", input_path.display()));
686-
687-
if !cmd_list.status.success() {
688-
panic!(
689-
"rcc --list failed for {}:\n{}",
690-
input_path.display(),
691-
String::from_utf8_lossy(&cmd_list.stderr)
692-
);
693-
}
694-
695-
String::from_utf8_lossy(&cmd_list.stdout)
696-
.split('\n')
697-
.map(PathBuf::from)
698-
.collect()
633+
pub fn qrc_list(&mut self, input_file: impl AsRef<Path>) -> Vec<PathBuf> {
634+
// TODO: later change to just have a rcc() -> QtToolRcc
635+
// but keep this for compat for now
636+
QtToolRcc::new(self.qt_installation.as_ref()).list(input_file)
699637
}
700638
}

crates/qt-build-utils/src/tool/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
//
44
// SPDX-License-Identifier: MIT OR Apache-2.0
55

6+
mod rcc;
7+
pub use rcc::QtToolRcc;
8+
69
/// An enum representing known Qt tools
710
#[non_exhaustive]
811
#[derive(Eq, Hash, PartialEq)]

crates/qt-build-utils/src/tool/rcc.rs

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
// SPDX-FileCopyrightText: 2025 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
2+
// SPDX-FileContributor: Andrew Hayzen <[email protected]>
3+
//
4+
// SPDX-License-Identifier: MIT OR Apache-2.0
5+
6+
use crate::{Initializer, QtInstallation, QtTool};
7+
8+
use semver::Version;
9+
use std::{
10+
env,
11+
path::{Path, PathBuf},
12+
process::Command,
13+
};
14+
15+
/// A wrapper around the [rcc](https://doc.qt.io/qt-6/resources.html) tool
16+
pub struct QtToolRcc {
17+
executable: PathBuf,
18+
qt_version: Version,
19+
}
20+
21+
impl QtToolRcc {
22+
/// Construct a [QtToolRcc] from a given [QtInstallation]
23+
pub fn new(qt_installation: &dyn QtInstallation) -> Self {
24+
let executable = qt_installation
25+
.try_find_tool(QtTool::Rcc)
26+
.expect("Could not find rcc");
27+
let qt_version = qt_installation.version();
28+
29+
Self {
30+
executable,
31+
qt_version,
32+
}
33+
}
34+
35+
/// Run [rcc](https://doc.qt.io/qt-6/resources.html) on a .qrc file and save the output into [cargo's OUT_DIR](https://doc.rust-lang.org/cargo/reference/environment-variables.html).
36+
/// The path to the generated C++ file is returned, which can then be passed to [cc::Build::files](https://docs.rs/cc/latest/cc/struct.Build.html#method.file).
37+
/// This function also returns a String that contains the name of the resource initializer
38+
/// function.
39+
/// The build system must ensure that if the .cpp file is built into a static library, either
40+
/// the `+whole-archive` flag is used, or the initializer function is called by the
41+
/// application.
42+
pub fn compile(&self, input_file: impl AsRef<Path>) -> Initializer {
43+
let input_path = input_file.as_ref();
44+
let output_folder = PathBuf::from(&format!(
45+
"{}/qt-build-utils/qrc",
46+
env::var("OUT_DIR").unwrap()
47+
));
48+
std::fs::create_dir_all(&output_folder).expect("Could not create qrc dir");
49+
let output_path = output_folder.join(format!(
50+
"{}.cpp",
51+
input_path.file_name().unwrap().to_string_lossy(),
52+
));
53+
let name = input_path
54+
.file_name()
55+
.unwrap()
56+
.to_string_lossy()
57+
.replace('.', "_");
58+
59+
let cmd = Command::new(&self.executable)
60+
.args([
61+
input_path.to_str().unwrap(),
62+
"-o",
63+
output_path.to_str().unwrap(),
64+
"--name",
65+
&name,
66+
])
67+
.output()
68+
.unwrap_or_else(|_| panic!("rcc failed for {}", input_path.display()));
69+
70+
if !cmd.status.success() {
71+
panic!(
72+
"rcc failed for {}:\n{}",
73+
input_path.display(),
74+
String::from_utf8_lossy(&cmd.stderr)
75+
);
76+
}
77+
78+
let qt_6_5 = Version::new(6, 5, 0);
79+
let init_header = if self.qt_version >= qt_6_5 {
80+
// With Qt6.5 the Q_INIT_RESOURCE macro is in the QtResource header
81+
"QtCore/QtResource"
82+
} else {
83+
"QtCore/QDir"
84+
};
85+
Initializer {
86+
file: Some(output_path),
87+
init_call: Some(format!("Q_INIT_RESOURCE({name});")),
88+
init_declaration: Some(format!("#include <{init_header}>")),
89+
}
90+
}
91+
92+
/// Run [rcc](https://doc.qt.io/qt-6/resources.html) on a .qrc file and return the paths of the sources
93+
pub fn list(&self, input_file: impl AsRef<Path>) -> Vec<PathBuf> {
94+
// Add the qrc file contents to the cargo rerun list
95+
let input_path = input_file.as_ref();
96+
let cmd_list = Command::new(&self.executable)
97+
.args(["--list", input_path.to_str().unwrap()])
98+
.output()
99+
.unwrap_or_else(|_| panic!("rcc --list failed for {}", input_path.display()));
100+
101+
if !cmd_list.status.success() {
102+
panic!(
103+
"rcc --list failed for {}:\n{}",
104+
input_path.display(),
105+
String::from_utf8_lossy(&cmd_list.stderr)
106+
);
107+
}
108+
109+
String::from_utf8_lossy(&cmd_list.stdout)
110+
.split('\n')
111+
.map(PathBuf::from)
112+
.collect()
113+
}
114+
}

0 commit comments

Comments
 (0)