Skip to content

Commit

Permalink
Remove -lib-headers as a dependency
Browse files Browse the repository at this point in the history
Export the build manifest from -lib instead.
  • Loading branch information
LeonMatthesKDAB authored and ahayzen-kdab committed Jul 9, 2024
1 parent 704ecc7 commit 410f494
Show file tree
Hide file tree
Showing 110 changed files with 265 additions and 99 deletions.
1 change: 1 addition & 0 deletions crates/cxx-qt-build/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ quote.workspace = true
qt-build-utils.workspace = true
codespan-reporting = "0.11"
version_check = "0.9"
scratch = "1"

[features]
link_qt_object_files = ["qt-build-utils/link_qt_object_files"]
52 changes: 37 additions & 15 deletions crates/cxx-qt-build/src/dir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,60 @@
//
// SPDX-License-Identifier: MIT OR Apache-2.0

//! This modules contains information about the paths where artifacts are placed by cxx-qt-build.
use crate::{crate_name, module_name_from_uri};
use std::{env, path::PathBuf};

/// The export directory, if one was specified through the environment, namespaced by crate
pub(crate) fn crate_target() -> Option<PathBuf> {
target().map(|export_dir| export_dir.join("crates").join(crate_name()))
/// The target directory, namespaced by crate
pub fn crate_target() -> PathBuf {
target().join("crates").join(crate_name())
}

/// The export directory, if one was specified through the environment, namespaced by plugin
pub(crate) fn module_target(module_uri: &str) -> Option<PathBuf> {
target().map(|export_dir| {
export_dir
.join("qml_modules")
.join(module_name_from_uri(module_uri))
})
/// The target directory, namespaced by plugin
pub(crate) fn module_target(module_uri: &str) -> PathBuf {
target()
.join("qml_modules")
.join(module_name_from_uri(module_uri))
}

/// The target directory or another directory where we can write files that will be shared
/// between crates.
pub(crate) fn target() -> PathBuf {
if let Some(export) = export() {
return export;
}

// The CARGO_TARGET_DIR is only set by users that want to configure cargo.
// So it's unlikely that it is indeed set.
// However, if it is, it's the easiest way to get the target dir.
let cargo_target_dir = env::var("CARGO_TARGET_DIR").ok().map(PathBuf::from);
if let Some(cargo_target_dir) = cargo_target_dir {
if cargo_target_dir.exists() && cargo_target_dir.is_absolute() {
return cargo_target_dir.join("cxxqtbridge");
}
}

scratch::path("cxxqtbridge")
}

/// The export directory, if one was specified through the environment.
/// Note that this is not namspaced by crate.
pub(crate) fn target() -> Option<PathBuf> {
pub(crate) fn export() -> Option<PathBuf> {
env::var("CXXQT_EXPORT_DIR").ok().map(PathBuf::from)
}

/// The include directory needs to be namespaced by crate name when exporting for a C++ build system,
/// but for using cargo build without a C++ build system, OUT_DIR is already namespaced by crate name.
pub(crate) fn header_root() -> PathBuf {
crate_target()
.unwrap_or_else(|| PathBuf::from(env::var("OUT_DIR").unwrap()))
.join("include")
pub fn header_root() -> PathBuf {
crate_target().join("include")
}

/// The OUT_DIR, converted into a PathBuf
pub(crate) fn out() -> PathBuf {
env::var("OUT_DIR").unwrap().into()
}

pub(crate) fn is_exporting() -> bool {
export().is_some()
}
54 changes: 41 additions & 13 deletions crates/cxx-qt-build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ mod cfg_evaluator;
mod diagnostics;
use diagnostics::{Diagnostic, GeneratedError};

mod dir;
pub mod dir;

mod opts;
pub use opts::CxxQtBuildersOpts;
Expand Down Expand Up @@ -323,6 +323,7 @@ pub struct CxxQtBuilder {
cc_builder: cc::Build,
extra_defines: HashSet<String>,
initializers: Vec<String>,
dependencies: Vec<cxx_qt::build::Manifest>,
}

impl CxxQtBuilder {
Expand All @@ -339,6 +340,7 @@ impl CxxQtBuilder {
cc_builder: cc::Build::new(),
extra_defines: HashSet::new(),
initializers: Vec::new(),
dependencies: Vec::new(),
}
}

Expand Down Expand Up @@ -460,6 +462,16 @@ impl CxxQtBuilder {
self
}

/// Build with a dependency on another crate built with cxx-qt-build
pub fn with_dependency(mut self, manifest: cxx_qt::build::Manifest) -> Self {
self.extra_defines.extend(manifest.defines.iter().cloned());
self.initializers
.extend(manifest.initializers.iter().cloned());
self.qt_modules.extend(manifest.qt_modules.iter().cloned());
self.dependencies.push(manifest);
self
}

/// Build with the given extra options
pub fn with_opts(mut self, opts: CxxQtBuildersOpts) -> Self {
let header_root = dir::header_root();
Expand Down Expand Up @@ -570,6 +582,23 @@ impl CxxQtBuilder {
}
}

fn setup_dependencies(&self) {
let header_root = dir::header_root();
for dependency in &self.dependencies {
let target = format!("../../{dep}/include/{dep}", dep = dependency.name);
let symlink = header_root.join(&dependency.name);
if !symlink.exists() {
#[cfg(unix)]
let result = std::os::unix::fs::symlink(target, symlink);

#[cfg(windows)]
let result = std::os::windows::fs::symlink_dir(target, symlink);

result.expect("Could not create symlink!");
}
}
}

fn setup_cc_builder<'a>(
builder: &mut cc::Build,
include_paths: &[impl AsRef<Path>],
Expand Down Expand Up @@ -616,11 +645,7 @@ impl CxxQtBuilder {
}
}

fn build_object_file(
builder: &cc::Build,
file_path: impl AsRef<Path>,
object_path: Option<PathBuf>,
) {
fn build_object_file(builder: &cc::Build, file_path: impl AsRef<Path>, object_path: PathBuf) {
let mut obj_builder = builder.clone();
obj_builder.file(file_path);
let obj_files = obj_builder.compile_intermediates();
Expand All @@ -629,7 +654,7 @@ impl CxxQtBuilder {
// If there's 0 or > 1 file, we panic in the `else` branch, because then the builder is
// probably not correctly configured.
if let [obj_file] = &obj_files[..] {
if let Some(object_path) = object_path {
if dir::is_exporting() {
if let Some(directory) = object_path.parent() {
std::fs::create_dir_all(directory).unwrap_or_else(|_| {
panic!(
Expand Down Expand Up @@ -667,9 +692,7 @@ impl CxxQtBuilder {
generated_header_dir: impl AsRef<Path>,
) {
for qml_module in &self.qml_modules {
if let Some(export_dir) = dir::module_target(&qml_module.uri) {
Self::clean_directory(export_dir);
}
Self::clean_directory(dir::module_target(&qml_module.uri));

let mut qml_metatypes_json = Vec::new();

Expand Down Expand Up @@ -735,7 +758,7 @@ impl CxxQtBuilder {
Self::build_object_file(
init_builder,
&qml_module_registration_files.plugin_init,
dir::module_target(&qml_module.uri).map(|dir| dir.join("plugin_init.o")),
dir::module_target(&qml_module.uri).join("plugin_init.o"),
);
}
}
Expand Down Expand Up @@ -772,15 +795,19 @@ impl CxxQtBuilder {
Self::build_object_file(
init_builder,
initializers_path,
dir::crate_target().map(|dir| dir.join("initializers.o")),
dir::crate_target().join("initializers.o"),
);
}

fn build_qrc_files(&mut self, init_builder: &cc::Build, qtbuild: &mut qt_build_utils::QtBuild) {
for qrc_file in &self.qrc_files {
// We need to link this using an obect file or +whole-achive, the static initializer of
// the qrc file isn't lost.
Self::build_object_file(init_builder, qtbuild.qrc(&qrc_file), None);
let out_path = qtbuild.qrc(&qrc_file);
let export_path = dir::crate_target()
.join("qrc")
.join(format!("{:?}.o", out_path.file_stem().unwrap()));
Self::build_object_file(init_builder, out_path, export_path);

// Also ensure that each of the files in the qrc can cause a change
for qrc_inner_file in qtbuild.qrc_list(&qrc_file) {
Expand Down Expand Up @@ -821,6 +848,7 @@ impl CxxQtBuilder {
Self::define_qt_version_cfg_variables(qtbuild.version());

Self::write_common_headers();
self.setup_dependencies();

// Setup compilers
// Static QML plugin and Qt resource initializers need to be linked as their own separate
Expand Down
9 changes: 5 additions & 4 deletions crates/cxx-qt-lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,18 @@ serde = { version = "1", features=["derive"], optional = true }

[build-dependencies]
cxx-qt-build.workspace = true
cxx-qt-lib-headers.workspace = true

[features]
default = ["qt_gui", "qt_qml", "qt_quickcontrols"]

qt_gui = []
qt_qml = []
qt_quickcontrols = []

bytes = ["dep:bytes"]
chrono = ["dep:chrono"]
http = ["dep:http"]
rgb = ["dep:rgb"]
qt_gui = ["cxx-qt-lib-headers/qt_gui"]
qt_qml = ["cxx-qt-lib-headers/qt_qml"]
qt_quickcontrols = ["cxx-qt-lib-headers/qt_quickcontrols"]
time = ["dep:time"]
url = ["dep:url"]
serde = ["dep:serde"]
Expand Down
88 changes: 78 additions & 10 deletions crates/cxx-qt-lib/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,64 @@
// SPDX-License-Identifier: MIT OR Apache-2.0

use cxx_qt_build::CxxQtBuilder;
use std::path::PathBuf;

fn qt_gui_enabled() -> bool {
std::env::var("CARGO_FEATURE_QT_GUI").is_ok()
}

fn qt_qml_enabled() -> bool {
std::env::var("CARGO_FEATURE_QT_QML").is_ok()
}

fn qt_quickcontrols_enabled() -> bool {
std::env::var("CARGO_FEATURE_QT_QUICKCONTROLS").is_ok()
}

fn header_dir() -> PathBuf {
cxx_qt_build::dir::header_root().join("cxx-qt-lib")
}

fn write_headers_in(subfolder: &str) {
println!("cargo::rerun-if-changed=include/{subfolder}");

for entry in
std::fs::read_dir(format!("include/{subfolder}")).expect("Failed to read include directory")
{
let entry = entry.expect("Failed to read header file!");
let header_name = entry.file_name();
println!("cargo::rerun-if-changed=include/{subfolder}/{header_name:?}",);

// TODO: Do we want to add the headers into a subdirectory?
let header_dir = header_dir();
std::fs::create_dir_all(&header_dir).expect("Failed to create include directory");
std::fs::copy(entry.path(), header_dir.join(header_name))
.expect("Failed to copy header file!");
}
}

fn write_headers() {
println!("cargo::rerun-if-changed=include/");
std::fs::create_dir_all(header_dir()).expect("Failed to create include directory");
println!("cargo::rerun-if-changed=include/common.h");
std::fs::copy("include/common.h", header_dir().join("common.h"))
.expect("Failed to copy header file!");

write_headers_in("core");
if qt_gui_enabled() {
write_headers_in("gui");
}
if qt_qml_enabled() {
write_headers_in("qml");
}
if qt_quickcontrols_enabled() {
write_headers_in("quickcontrols");
}
}

fn main() {
let feature_qt_gui_enabled = std::env::var("CARGO_FEATURE_QT_GUI").is_ok();
let feature_qt_qml_enabled = std::env::var("CARGO_FEATURE_QT_QML").is_ok();
let feature_qt_quickcontrols_enabled = std::env::var("CARGO_FEATURE_QT_QUICKCONTROLS").is_ok();
write_headers();

let emscripten_targeted = match std::env::var("CARGO_CFG_TARGET_OS") {
Ok(val) => val == "emscripten",
Err(_) => false,
Expand Down Expand Up @@ -135,7 +188,7 @@ fn main() {
"core/qvector/qvector_u64",
];

if feature_qt_gui_enabled {
if qt_gui_enabled() {
rust_bridges.extend([
"core/qlist/qlist_qcolor",
"core/qvariant/qvariant_qcolor",
Expand All @@ -156,11 +209,11 @@ fn main() {
]);
}

if feature_qt_qml_enabled {
if qt_qml_enabled() {
rust_bridges.extend(["qml/qqmlapplicationengine", "qml/qqmlengine"]);
}

if feature_qt_quickcontrols_enabled {
if qt_quickcontrols_enabled() {
rust_bridges.extend(["quickcontrols/qquickstyle"]);
}

Expand Down Expand Up @@ -203,7 +256,7 @@ fn main() {
"core/qvector/qvector",
];

if feature_qt_gui_enabled {
if qt_gui_enabled() {
cpp_files.extend([
"gui/qcolor",
"gui/qfont",
Expand All @@ -221,11 +274,11 @@ fn main() {
]);
}

if feature_qt_qml_enabled {
if qt_qml_enabled() {
cpp_files.extend(["qml/qqmlapplicationengine", "qml/qqmlengine"]);
}

if feature_qt_quickcontrols_enabled {
if qt_quickcontrols_enabled() {
cpp_files.extend(["quickcontrols/qquickstyle"]);
}

Expand All @@ -249,5 +302,20 @@ fn main() {
});
println!("cargo:rerun-if-changed=src/assertion_utils.h");

builder.with_opts(cxx_qt_lib_headers::build_opts()).build();
if qt_gui_enabled() {
builder = builder.qt_module("Gui").cc_builder(|cc| {
cc.define("CXX_QT_GUI_FEATURE", None);
});
}
if qt_qml_enabled() {
builder = builder.qt_module("Qml").cc_builder(|cc| {
cc.define("CXX_QT_QML_FEATURE", None);
});
}
if qt_quickcontrols_enabled() {
builder = builder.qt_module("QuickControls2").cc_builder(|cc| {
cc.define("CXX_QT_QUICKCONTROLS_FEATURE", None);
});
}
builder.build();
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit 410f494

Please sign in to comment.