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

Backports 0.7.1 #1206

Merged
merged 18 commits into from
Mar 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
790c162
Prevent clippy from tripping lint
kristof-mattei Nov 14, 2024
3c2df5c
fix: mark all std::boxed::Box returns with #[allow(clippy::unnecessar…
kristof-mattei Nov 15, 2024
fb3d928
cxx-qt-gen: allow for unused unsafe blocks in the CXX block
ahayzen-kdab Nov 15, 2024
0510d8d
qanystringview: improve lifetimes to match C++ closer
ahayzen-kdab Nov 15, 2024
f890fd4
cxx-qt: ensure that RUST_CXX_NO_EXCEPTIONS is followed in our code
ahayzen-kdab Nov 18, 2024
48835ad
cxx-qt-gen: change docs to be consistent in parser
ahayzen-kdab Nov 18, 2024
436ae22
cxx-qt-gen: support cfg in various minimal places of our bridges
ahayzen-kdab Nov 18, 2024
a82d574
examples: remove Result and change tests to use cfg
ahayzen-kdab Nov 18, 2024
e878e17
cmake: set -DRUST_CXX_NO_EXCEPTIONS when using WASM
ahayzen-kdab Nov 22, 2024
d7245be
threading: do not use exceptions and instead use return values
ahayzen-kdab Nov 18, 2024
6c2d77f
On non-Unix platforms, use deep copying rather than symlinking (#1136)
jnbooth Jan 10, 2025
830d4de
QImage: Add conversion from image::RgbaImage
LeonMatthesKDAB Jan 15, 2025
7884eb3
qt-build-utils: treat .obj files as object files
jnbooth Jan 21, 2025
d42f892
Fix 2024 edition (1.85.0) lints
BenFordTytherington Feb 21, 2025
3fa4f55
Fix: Only update caches when pushed to `main`
LeonMatthesKDAB Mar 4, 2025
9dd8877
Add sccache --start-server for debugging
LeonMatthesKDAB Mar 4, 2025
8d31eaf
changelog: update for 0.7.1 release
ahayzen-kdab Mar 4, 2025
9e4bee3
cargo: bump version to 0.7.1
ahayzen-kdab Mar 4, 2025
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
32 changes: 28 additions & 4 deletions .github/workflows/github-cxx-qt-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,14 @@ jobs:
with:
path: /home/runner/.cache/sccache
key: "Ubuntu 24.04 (wasm_32) Qt6_compiler_cache"

- name: "Start sccache server"
# If the compiler cache couldn't be restored, we have to create the cache path,
# as otherwise the server startup fails.
run: |
mkdir -p /home/runner/.cache/sccache
sccache --start-server

- name: "emsdk cache"
uses: actions/cache@v4
id: emsdk-cache
Expand Down Expand Up @@ -201,7 +209,7 @@ jobs:
- name: "Delete previous compiler cache"
# Updating th cache doesn't work from forks
# So update it once it's merged into the repo
if: ${{ steps.compiler-cache-restore.outputs.cache-hit && github.event_name == 'push' }}
if: ${{ steps.compiler-cache-restore.outputs.cache-hit && github.event_name == 'push' && github.ref_name == 'main' }}
continue-on-error: true
run: |
gh extension install actions/gh-actions-cache
Expand All @@ -211,7 +219,7 @@ jobs:
- name: "Save Compiler Cache"
# Updating th cache doesn't work from forks
# So update it once it's merged into the repo
if: ${{ github.event_name == 'push' }}
if: ${{ github.event_name == 'push' && github.ref_name == 'main' }}
uses: actions/cache/save@v4
with:
path: /home/runner/.cache/sccache
Expand Down Expand Up @@ -409,6 +417,22 @@ jobs:
path: ${{ matrix.compiler_cache_path }}
key: ${{ matrix.name }}_compiler_cache

- name: "[Windows] Start sccache server"
# If the compiler cache couldn't be restored, we have to create the cache path,
# as otherwise the server startup fails.
if: runner.os == 'Windows'
run: |
md ${{ matrix.compiler_cache_path }} -ea 0
sccache --start-server

- name: "[Other] Start sccache server"
# If the compiler cache couldn't be restored, we have to create the cache path,
# as otherwise the server startup fails.
if: runner.os != 'Windows'
run: |
mkdir -p ${{ matrix.compiler_cache_path }}
sccache --start-server

- name: "Install clang-format"
# Note ensure that clang-format runner is updated too
run: |
Expand Down Expand Up @@ -488,7 +512,7 @@ jobs:
- name: "Delete previous compiler cache"
# Updating th cache doesn't work from forks
# So update it once it's merged into the repo
if: ${{ steps.compiler-cache-restore.outputs.cache-hit && github.event_name == 'push' }}
if: ${{ steps.compiler-cache-restore.outputs.cache-hit && github.event_name == 'push' && github.ref_name == 'main' }}
continue-on-error: true
run: |
gh extension install actions/gh-actions-cache
Expand All @@ -498,7 +522,7 @@ jobs:
- name: "Save Compiler Cache"
# Updating th cache doesn't work from forks
# So update it once it's merged into the repo
if: ${{ github.event_name == 'push' }}
if: ${{ github.event_name == 'push' && github.ref_name == 'main' }}
uses: actions/cache/save@v4
with:
path: ${{ matrix.compiler_cache_path }}
Expand Down
14 changes: 13 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,19 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased](https://github.com/KDAB/cxx-qt/compare/v0.7.0...HEAD)
## [Unreleased](https://github.com/KDAB/cxx-qt/compare/v0.7.1...HEAD)

## [0.7.1](https://github.com/KDAB/cxx-qt/compare/v0.7.0...v0.7.1) - 2025-03-04

### Added

- Allow creating a `QImage` from an `image::RgbaImage`.

### Fixed

- Prevent clippy from tripping lint
- Build warnings due to unused unsafe blocks since CXX 1.0.130
- On non-Unix platforms, use deep copying rather than symlinking

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

Expand Down
15 changes: 8 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,18 @@ resolver = "2"
edition = "2021"
license = "MIT OR Apache-2.0"
repository = "https://github.com/KDAB/cxx-qt/"
version = "0.7.0"
version = "0.7.1"

# Note a version needs to be specified on dependencies of packages
# we publish, otherwise crates.io complains as it doesn't know the version.
[workspace.dependencies]
cxx-qt = { path = "crates/cxx-qt" }
cxx-qt-macro = { path = "crates/cxx-qt-macro", version = "0.7.0" }
cxx-qt-build = { path = "crates/cxx-qt-build", version = "0.7.0" }
cxx-qt-gen = { path = "crates/cxx-qt-gen", version = "0.7.0" }
cxx-qt-lib = { path = "crates/cxx-qt-lib", version = "0.7.0" }
qt-build-utils = { path = "crates/qt-build-utils", version = "0.7.0" }
cxx-qt-lib-extras = { path = "crates/cxx-qt-lib-extras", version = "0.7.0" }
cxx-qt-macro = { path = "crates/cxx-qt-macro", version = "0.7.1" }
cxx-qt-build = { path = "crates/cxx-qt-build", version = "0.7.1" }
cxx-qt-gen = { path = "crates/cxx-qt-gen", version = "0.7.1" }
cxx-qt-lib = { path = "crates/cxx-qt-lib", version = "0.7.1" }
qt-build-utils = { path = "crates/qt-build-utils", version = "0.7.1" }
cxx-qt-lib-extras = { path = "crates/cxx-qt-lib-extras", version = "0.7.1" }

cc = { version = "1.0.100", features = ["parallel"] }
# Ensure that the example comments are kept in sync
Expand All @@ -55,3 +55,4 @@ syn = { version = "2.0", features = ["extra-traits", "full"] }
quote = "1.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
thiserror = "1.0"
11 changes: 11 additions & 0 deletions book/src/concepts/wasm-builds.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,17 @@ set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
```

Any Rust crate that is imported via corrosion needs to have `-DRUST_CXX_NO_EXCEPTIONS` set otherwise `cxx` fails to build.

```cmake
if(BUILD_WASN)
# Add -DRUST_CXX_NO_EXCEPTIONS to CXXFLAGS, as WASM does not support exceptions
set(EMSCRIPTEN_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
list(APPEND EMSCRIPTEN_CXX_FLAGS "-DRUST_CXX_NO_EXCEPTIONS")
corrosion_set_env_vars(${CRATE} "CXXFLAGS=${EMSCRIPTEN_CXX_FLAGS}")
endif()
```

Using CMake, `add_executable` will not output an HTML file when targeting wasm. In order to render an HTML file, one must use `qt_add_executable` in its place. Assuming a project has a CMake flag `BUILD_WASM` to toggle wasm and native builds, one could write the following:

```cmake
Expand Down
2 changes: 1 addition & 1 deletion book/src/getting-started/5-cmake-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ Download CXX-Qts CMake code with FetchContent:

```cmake,ignore
{{#include ../../../examples/qml_minimal/CMakeLists.txt:book_cmake_find_cxx_qt_start}}
GIT_TAG v0.7.0
GIT_TAG v0.7.1
{{#include ../../../examples/qml_minimal/CMakeLists.txt:book_cmake_find_cxx_qt_end}}
```

Expand Down
85 changes: 84 additions & 1 deletion crates/cxx-qt-build/src/dir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,19 @@
use crate::{crate_name, module_name_from_uri};
use std::io::Result;
use std::{
env,
env, fs,
path::{Path, PathBuf},
};

/// On Unix platforms, included files are symlinked into destination folders.
/// On non-Unix platforms, due to poor support for symlinking, included files are deep copied.
#[cfg(unix)]
pub(crate) const INCLUDE_VERB: &str = "create symlink";
/// On Unix platforms, included files are symlinked into destination folders.
/// On non-Unix platforms, due to poor support for symlinking, included files are deep copied.
#[cfg(not(unix))]
pub(crate) const INCLUDE_VERB: &str = "deep copy files";

// Clean a directory by removing it and recreating it.
pub(crate) fn clean(path: impl AsRef<Path>) -> Result<()> {
let result = std::fs::remove_dir_all(&path);
Expand Down Expand Up @@ -81,3 +90,77 @@ pub(crate) fn out() -> PathBuf {
pub(crate) fn is_exporting() -> bool {
export().is_some()
}

#[cfg(unix)]
pub(crate) fn symlink_or_copy_directory(
source: impl AsRef<Path>,
dest: impl AsRef<Path>,
) -> Result<bool> {
match std::os::unix::fs::symlink(&source, &dest) {
Ok(()) => Ok(true),
Err(e) if e.kind() != std::io::ErrorKind::AlreadyExists => Err(e),
// Two dependencies may be reexporting the same shared dependency, which will
// result in conflicting symlinks.
// Try detecting this by resolving the symlinks and checking whether this leads us
// to the same paths. If so, it's the same include path for the same prefix, which
// is fine.
Err(_) => Ok(fs::canonicalize(source)? == fs::canonicalize(dest)?),
}
}

#[cfg(not(unix))]
pub(crate) fn symlink_or_copy_directory(
source: impl AsRef<Path>,
dest: impl AsRef<Path>,
) -> Result<bool> {
deep_copy_directory(source.as_ref(), dest.as_ref())
}

#[cfg(not(unix))]
fn deep_copy_directory(source: &Path, dest: &Path) -> Result<bool> {
fs::create_dir_all(dest)?;
for entry in fs::read_dir(source)? {
let entry = entry?;
let source_path = entry.path();
let dest_path = dest.join(entry.file_name());
if entry.file_type()?.is_dir() {
if deep_copy_directory(&source_path, &dest_path)? {
continue;
}
return Ok(false);
}
if !dest_path.try_exists()? {
fs::copy(&source_path, &dest_path)?;
} else if files_conflict(&source_path, &dest_path)? {
return Ok(false);
}
}
Ok(true)
}

#[cfg(not(unix))]
fn files_conflict(source: &Path, dest: &Path) -> Result<bool> {
use fs::File;
use std::io::{BufRead, BufReader};
let source = File::open(source)?;
let dest = File::open(dest)?;
if source.metadata()?.len() != dest.metadata()?.len() {
return Ok(true);
}
let mut source = BufReader::new(source);
let mut dest = BufReader::new(dest);
loop {
let source_bytes = source.fill_buf()?;
let bytes_len = source_bytes.len();
let dest_bytes = dest.fill_buf()?;
let bytes_len = bytes_len.min(dest_bytes.len());
if bytes_len == 0 {
return Ok(false);
}
if source_bytes[..bytes_len] != dest_bytes[..bytes_len] {
return Ok(true);
}
source.consume(bytes_len);
dest.consume(bytes_len);
}
}
71 changes: 26 additions & 45 deletions crates/cxx-qt-build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ mod diagnostics;
use diagnostics::{Diagnostic, GeneratedError};

pub mod dir;
use dir::INCLUDE_VERB;

mod dependencies;
pub use dependencies::Interface;
Expand Down Expand Up @@ -630,49 +631,28 @@ impl CxxQtBuilder {
}
}

fn symlink_directory(target: impl AsRef<Path>, link: impl AsRef<Path>) -> std::io::Result<()> {
#[cfg(unix)]
let result = std::os::unix::fs::symlink(target, link);

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

// TODO: If it's neither unix nor windows, we should probably just deep-copy the
// dependency headers into our own include directory.
#[cfg(not(any(unix, windows)))]
panic!("Cxx-Qt-build: Unsupported platform! Only unix and windows are currently supported! Please file a bug report in the CXX-Qt repository.");

result
}

// A dependency can specify which of its own include paths it wants to export.
// Set up each of these exported include paths as symlinks in our own include directory.
// Set up each of these exported include paths as symlinks in our own include directory,
// or deep copy the files if the platform does not support symlinks.
fn include_dependency(&mut self, dependency: &Dependency) {
let header_root = dir::header_root();
let dependency_root = dependency.path.join("include");
for include_prefix in &dependency.manifest.exported_include_prefixes {
// setup include directory
let target = dependency.path.join("include").join(include_prefix);

let symlink = dir::header_root().join(include_prefix);
if symlink.exists() {
// Two dependencies may be reexporting the same shared dependency, which will
// result in conflicting symlinks.
// Try detecting this by resolving the symlinks and checking whether this leads us
// to the same paths. If so, it's the same include path for the same prefix, which
// is fine.
let symlink =
std::fs::canonicalize(symlink).expect("Failed to canonicalize symlink!");
let target =
std::fs::canonicalize(target).expect("Failed to canonicalize symlink target!");
if symlink != target {
let source = dependency_root.join(include_prefix);
let dest = header_root.join(include_prefix);

match dir::symlink_or_copy_directory(source, dest) {
Ok(true) => (),
Ok(false) => {
panic!(
"Conflicting include_prefixes for {include_prefix}!\nDependency {dep_name} conflicts with existing include path",
dep_name = dependency.manifest.name,
);
}
} else {
Self::symlink_directory(target, symlink).unwrap_or_else(|_| {
panic!("Could not create symlink for include_prefix {include_prefix}!")
});
Err(e) => {
panic!("Could not {INCLUDE_VERB} for include_prefix {include_prefix}: {e:?}");
}
}
}
}
Expand Down Expand Up @@ -1019,17 +999,18 @@ impl CxxQtBuilder {
}

fn write_interface_include_dirs(&self) {
if let Some(interface) = &self.public_interface {
for (header_dir, symlink) in &interface.exported_include_directories {
Self::symlink_directory(header_dir, dir::header_root().join(symlink))
.unwrap_or_else(|_| {
panic!(
"Failed to create symlink `{}` for export_include_directory: {}",
symlink,
header_dir.to_string_lossy()
)
});
}
let Some(interface) = &self.public_interface else {
return;
};
let header_root = dir::header_root();
for (header_dir, dest) in &interface.exported_include_directories {
let dest_dir = header_root.join(dest);
if let Err(e) = dir::symlink_or_copy_directory(header_dir, dest_dir) {
panic!(
"Failed to {INCLUDE_VERB} `{dest}` for export_include_directory `{dir_name}`: {e:?}",
dir_name = header_dir.to_string_lossy()
)
};
}
}

Expand Down
2 changes: 1 addition & 1 deletion crates/cxx-qt-build/src/qml_modules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ where
pub qrc_files: &'a [A],
}

impl<'a, A, B> Default for QmlModule<'a, A, B>
impl<A, B> Default for QmlModule<'_, A, B>
where
A: AsRef<Path>,
B: AsRef<Path>,
Expand Down
Loading
Loading