Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CXX-Qt-build: Remove definitions from Interface #1167

Merged
merged 1 commit into from
Jan 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Build warnings due to unused unsafe blocks since CXX 1.0.130

### Removed

- CXX-Qt-build: Interface no longer includes compiler definitions (<https://github.com/KDAB/cxx-qt/issues/1165>)

## [0.7.0](https://github.com/KDAB/cxx-qt/compare/v0.6.1...v0.7.0) - 2024-10-30

### Added
Expand Down
71 changes: 1 addition & 70 deletions crates/cxx-qt-build/src/dependencies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@

use serde::{Deserialize, Serialize};

use std::collections::{HashMap, HashSet};
use std::collections::HashSet;
use std::path::{Path, PathBuf};

/// When generating a library with cxx-qt-build, the library may need to export certain flags or headers.
/// These are all specified by this Interface struct, which should be passed to the [crate::CxxQtBuilder::library] function.
pub struct Interface {
pub(crate) compile_definitions: HashMap<String, Option<String>>,
pub(crate) initializers: Vec<PathBuf>,
// The name of the links keys, whose CXX-Qt dependencies to reexport
pub(crate) reexport_links: HashSet<String>,
Expand All @@ -29,7 +28,6 @@ pub struct Interface {
impl Default for Interface {
fn default() -> Self {
Self {
compile_definitions: HashMap::new(),
initializers: Vec::new(),
reexport_links: HashSet::new(),
exported_include_prefixes: vec![super::crate_name()],
Expand All @@ -39,32 +37,6 @@ impl Default for Interface {
}

impl Interface {
/// Add a compile-time-definition for the C++ code built by this crate and all downstream
/// dependencies
///
/// This function will panic if the variable has already been defined with a different value.
///
/// Also please note that any definitions added here will only be exported throughout the cargo
/// build. Due to technical limitations, they can not be imported into CMake with the
/// cxxqt_import_crate function.
pub fn define(mut self, variable: &str, value: Option<&str>) -> Self {
use std::collections::hash_map::Entry::*;

let entry = self.compile_definitions.entry(variable.to_owned());
match entry {
Vacant(entry) => entry.insert(value.map(String::from)),
Occupied(entry) => {
if entry.get().as_deref() == value {
println!("Warning: Silently ignoring duplicate compiler definition for {variable} with {value:?}.");
}
panic!(
"Cxx-Qt-build - Error: Interface::define - Duplicate compile-time definition for variable {variable} with value {value:?}!"
);
}
};
self
}

/// Add a C++ file path that will be exported as an initializer to downstream dependencies.
///
/// Initializer files will be built into object files, instead of linked into the static
Expand Down Expand Up @@ -152,7 +124,6 @@ pub(crate) struct Manifest {
pub(crate) name: String,
pub(crate) link_name: String,
pub(crate) qt_modules: Vec<String>,
pub(crate) defines: Vec<(String, Option<String>)>,
pub(crate) initializers: Vec<PathBuf>,
pub(crate) exported_include_prefixes: Vec<String>,
}
Expand Down Expand Up @@ -257,43 +228,3 @@ pub(crate) fn reexported_dependencies(
}
exported_dependencies
}

pub(crate) fn all_compile_definitions(
interface: Option<&Interface>,
dependencies: &[Dependency],
) -> Vec<(String, Option<String>)> {
// For each definition, store the name of the crate that defines it so we can generate a
// nicer error message
let mut definitions: HashMap<String, (Option<String>, String)> = interface
.iter()
.flat_map(|interface| &interface.compile_definitions)
.map(|(key, value)| (key.clone(), (value.clone(), crate::crate_name())))
.collect();

for dependency in dependencies {
for (variable, value) in &dependency.manifest.defines {
use std::collections::hash_map::Entry::*;
let entry = definitions.entry(variable.to_owned());

match entry {
Vacant(entry) => {
entry.insert((value.to_owned(), dependency.manifest.name.clone()));
}
Occupied(entry) => {
let existing_value = &entry.get().0;
// Only allow duplicate definitions with the same value
if existing_value != value {
panic!("Conflicting compiler definitions requested!\nCrate {existing} exports {variable}={existing_value:?}, and crate {conflicting} exports {variable}={value:?}",
existing=entry.get().1,
conflicting = dependency.manifest.name);
}
}
}
}
}

definitions
.into_iter()
.map(|(key, (value, _crate_name))| (key, value))
.collect()
}
19 changes: 3 additions & 16 deletions crates/cxx-qt-build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -657,11 +657,7 @@ impl CxxQtBuilder {
}
}

fn setup_cc_builder(
builder: &mut cc::Build,
include_paths: &[impl AsRef<Path>],
defines: &[(String, Option<String>)],
) {
fn setup_cc_builder(builder: &mut cc::Build, include_paths: &[impl AsRef<Path>]) {
// Note, ensure our settings stay in sync across cxx-qt and cxx-qt-lib
builder.cpp(true);
builder.std("c++17");
Expand All @@ -672,11 +668,6 @@ impl CxxQtBuilder {
// MinGW requires big-obj otherwise debug builds fail
builder.flag_if_supported("-Wa,-mbig-obj");

// Enable any extra defines
for (variable, value) in defines {
builder.define(variable, value.as_deref());
}

for include_path in include_paths {
builder.include(include_path);
}
Expand Down Expand Up @@ -967,13 +958,11 @@ impl CxxQtBuilder {
let initializers = initializers.into_iter().collect();
let exported_include_prefixes =
dependencies::all_include_prefixes(interface, &dependencies);
let defines = dependencies::all_compile_definitions(Some(interface), &dependencies);

let manifest = Manifest {
name: crate_name(),
link_name: link_name()
.expect("The links key must be set when creating a library with CXX-Qt-build!"),
defines,
initializers,
qt_modules: qt_modules.into_iter().collect(),
exported_include_prefixes,
Expand Down Expand Up @@ -1059,11 +1048,9 @@ impl CxxQtBuilder {
// to the generated files without any namespacing.
include_paths.push(header_root.join(&self.include_prefix));

let compile_definitions =
dependencies::all_compile_definitions(self.public_interface.as_ref(), &dependencies);
Self::setup_cc_builder(&mut self.cc_builder, &include_paths, &compile_definitions);
Self::setup_cc_builder(&mut self.cc_builder, &include_paths);

Self::setup_cc_builder(&mut init_builder, &include_paths, &compile_definitions);
Self::setup_cc_builder(&mut init_builder, &include_paths);
// Note: From now on the init_builder is correctly configured.
// When building object files with this builder, we always need to copy it first.
// So remove `mut` to ensure that we can't accidentally change the configuration or add
Expand Down
39 changes: 28 additions & 11 deletions crates/cxx-qt-lib/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,31 @@ fn write_headers_in(subfolder: &str) {
}
}

fn write_definitions_header() {
// We cannot ensure that downstream dependencies set the same compile-time definitions.
// So we generate a header file that adds those definitions, which will be passed along
// to downstream dependencies with all other headers.
//
// Thanks to David Faure for reminding us of this useful trick in his blog post:
// https://www.kdab.com/setting-defines-with-cmake/
let mut definitions = "#pragma once\n".to_owned();

if qt_gui_enabled() {
definitions.push_str("#define CXX_QT_GUI_FEATURE\n");
}

if qt_qml_enabled() {
definitions.push_str("#define CXX_QT_QML_FEATURE\n");
}

if qt_quickcontrols_enabled() {
definitions.push_str("#define CXX_QT_QUICKCONTROLS_FEATURE\n");
}

std::fs::write(header_dir().join("definitions.h"), definitions)
.expect("Failed to write cxx-qt-lib/definitions.h");
}

fn write_headers() {
println!("cargo::rerun-if-changed=include/");
std::fs::create_dir_all(header_dir()).expect("Failed to create include directory");
Expand All @@ -66,6 +91,8 @@ fn write_headers() {
if qt_quickcontrols_enabled() {
write_headers_in("quickcontrols");
}

write_definitions_header();
}

fn main() {
Expand Down Expand Up @@ -323,17 +350,7 @@ fn main() {
.reexport_dependency("cxx-qt");

if qt_gui_enabled() {
interface = interface
.define("CXX_QT_GUI_FEATURE", None)
.initializer("src/gui/init.cpp");
}

if qt_qml_enabled() {
interface = interface.define("CXX_QT_QML_FEATURE", None);
}

if qt_quickcontrols_enabled() {
interface = interface.define("CXX_QT_QUICKCONTROLS_FEATURE", None);
interface = interface.initializer("src/gui/init.cpp");
}

let mut builder = CxxQtBuilder::library(interface).include_prefix("cxx-qt-lib-internals");
Expand Down
3 changes: 3 additions & 0 deletions crates/cxx-qt-lib/include/core/qlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@

#include <cstdint>

// The definitions file is auto-generated by the build script
#include <cxx-qt-lib/definitions.h>

#include <QtCore/QList>

#include <QtCore/QByteArray>
Expand Down
3 changes: 3 additions & 0 deletions crates/cxx-qt-lib/include/core/qvariant.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@

#include <cstdint>

// The definitions file is auto-generated by the build script
#include <cxx-qt-lib/definitions.h>

#include <QtCore/QVariant>

#include <QtCore/QByteArray>
Expand Down
3 changes: 3 additions & 0 deletions crates/cxx-qt-lib/include/core/qvector.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@

#include <cstdint>

// The definitions file is auto-generated by the build script
#include <cxx-qt-lib/definitions.h>

#include <QtCore/QVector>

#include <QtCore/QByteArray>
Expand Down
3 changes: 3 additions & 0 deletions crates/cxx-qt-lib/include/qml/qqmlapplicationengine.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
#pragma once

// The definitions file is auto-generated by the build script
#include <cxx-qt-lib/definitions.h>

#ifdef CXX_QT_QML_FEATURE

#include <memory>
Expand Down
3 changes: 3 additions & 0 deletions crates/cxx-qt-lib/include/qml/qqmlengine.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
#pragma once

// The definitions file is auto-generated by the build script
#include <cxx-qt-lib/definitions.h>

#ifdef CXX_QT_QML_FEATURE

#include <memory>
Expand Down
5 changes: 4 additions & 1 deletion crates/cxx-qt-lib/include/quickcontrols/qquickstyle.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
#pragma once

// The definitions file is auto-generated by the build script
#include <cxx-qt-lib/definitions.h>

#ifdef CXX_QT_QUICKCONTROLS_FEATURE

#include <memory>
Expand All @@ -27,4 +30,4 @@ qquickstyleSetStyle(const QString& style);
}
}

#endif
#endif
Loading