Skip to content
Open
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
38 changes: 35 additions & 3 deletions .github/workflows/github-cxx-qt-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,26 @@ jobs:
rustc_wrapper: sccache
build_type: Debug

- name: Windows 2022 (MinGW) Qt6
os: windows-2022
qt_version: 6
aqt_version: '6.8.0'
aqt_arch: 'win64_mingw'
aqt_host: 'windows'
cores: 4
ctest_args: --exclude-regex '^(cargo_clippy|cargo_doc|cargo_build_rerun|.*valgrind)$'
exe_suffix: .exe
qt_qpa_platform: windows
compiler_cache_path: C:\Users\runneradmin\AppData\Local\Mozilla\sccache\cache
sccache_log_path: C:\Users\runneradmin\AppData\Local\Mozilla\sccache\log.txt
clang_format_path: C:\Users\runneradmin\AppData\Roaming\Python\Python312\Scripts\clang-format.exe
cargo_dir: C:\Users\runneradmin\.cargo
cc: gcc
cxx: g++
rustc_wrapper: sccache
build_type: Release
mingw: true

runs-on: ${{ matrix.os }}
name: ${{ matrix.name }}
env:
Expand Down Expand Up @@ -530,11 +550,23 @@ jobs:
# automake is needed for building libicu which is a dependency of Qt
run: brew install automake autoconf-archive ninja

# Required for CMake to find Ninja
- name: "[Windows] Set up MSVC Developer Command Prompt"
if: runner.os == 'Windows'
# Required for CMake to find Ninja (MSVC only)
- name: "[Windows MSVC] Set up MSVC Developer Command Prompt"
if: runner.os == 'Windows' && !matrix.mingw
uses: seanmiddleditch/gha-setup-vsdevenv@v5

- name: "[Windows MinGW] Install MinGW and Ninja"
if: matrix.mingw
run: choco install mingw ninja -y

- name: "[Windows MinGW] Set up Rust GNU toolchain"
if: matrix.mingw
run: |
rustup toolchain install 1.77.2-x86_64-pc-windows-gnu
rustup toolchain install 1.78.0-x86_64-pc-windows-gnu --component clippy
rustup default 1.77.2-x86_64-pc-windows-gnu
rustup component add rustfmt

# Enable tmate debugging of manually-triggered workflows if the input option was provided
- name: Setup tmate session
if: ${{ github.event_name == 'workflow_dispatch' && inputs.tmate_debugging }}
Expand Down
46 changes: 28 additions & 18 deletions crates/cxx-qt-build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1065,22 +1065,22 @@ impl CxxQtBuilder {
// `extern "C"` as Q_INIT_RESOURCES needs name mangling, which doesn't happen if it's
// called within an `extern "C"` function.
// So add a static do_init function that we then call from the actual initializer function.
//
// Use atomic operations for single initialization - this is simpler than std::call_once
// and works reliably on all platforms including MinGW.
let init_function = format!(
r#"
#include <mutex>
#include <atomic>

{declarations}

static bool do_init() {{
static std::once_flag flag;
std::call_once(flag, []() {{
{calls}
}});
return true;
}}
static std::atomic<bool> initialized{{false}};

extern "C" bool {init_fun}() {{
return do_init();
if (!initialized.exchange(true, std::memory_order_acq_rel)) {{
{calls}
}}
return true;
}}
"#,
declarations = declarations.join("\n"),
Expand All @@ -1103,6 +1103,9 @@ extern "C" bool {init_fun}() {{
export_path: Option<PathBuf>,
key: &str,
) {
// Collect the private initializers so we can iterate multiple times
let private_initializers: Vec<_> = private_initializers.into_iter().collect();

// Build the initializers themselves into the main library.
self.cc_builder
.file(
Expand All @@ -1113,7 +1116,7 @@ extern "C" bool {init_fun}() {{
)
.files(
private_initializers
.into_iter()
.iter()
.filter_map(|initializer| initializer.file.as_ref()),
);

Expand All @@ -1124,16 +1127,23 @@ extern "C" bool {init_fun}() {{
let includes: &[&str] = &[]; // <-- Needed for type annotations
Self::setup_cc_builder(&mut init_call_builder, includes);

let declaration = public_initializer
.init_declaration
.clone()
.unwrap_or_default();
let call = public_initializer
.init_call
.clone()
.expect("Public initializer must be callable!");

// Static initialization to trigger the init chain. The actual metatype registration
// is handled by Q_COREAPP_STARTUP_FUNCTION in the init.cpp files, so the init
// functions themselves are lightweight (just return true).
let init_call = format!(
"{declaration}\nstatic const bool do_init_{key} = {init_call}",
declaration = public_initializer
.init_declaration
.clone()
.unwrap_or_default(),
init_call = public_initializer
.init_call
.clone()
.expect("Public initializer must be callable!"),
declaration = declaration,
init_call = call,
key = key,
);

let init_file = dir::initializers(key).join("call-initializers.cpp");
Expand Down
205 changes: 106 additions & 99 deletions crates/cxx-qt-lib/src/core/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,111 +11,118 @@
#include <cxx-qt-lib/qset.h>
#include <cxx-qt-lib/qvector.h>

#include <mutex>
#include <QtCore/QCoreApplication>

extern "C" bool
init_cxx_qt_lib_core()
static void
do_register_core_types()
{
static std::once_flag flag;
std::call_once(flag, []() {
qRegisterMetaType<::QHash_i32_QByteArray>("QHash_i32_QByteArray");
// Ensure that QHash<QString, QVariant> (aka QVariantHash) is registered
// otherwise it cannot be used in QML
qRegisterMetaType<::QHash_QString_QVariant>("QHash_QString_QVariant");
qRegisterMetaType<::QHash_i32_QByteArray>("QHash_i32_QByteArray");
// Ensure that QHash<QString, QVariant> (aka QVariantHash) is registered
// otherwise it cannot be used in QML
qRegisterMetaType<::QHash_QString_QVariant>("QHash_QString_QVariant");

qRegisterMetaType<::QList_bool>("QList_bool");
qRegisterMetaType<::QList_f32>("QList_f32");
qRegisterMetaType<::QList_f64>("QList_f64");
qRegisterMetaType<::QList_i8>("QList_i8");
qRegisterMetaType<::QList_i16>("QList_i16");
qRegisterMetaType<::QList_i32>("QList_i32");
qRegisterMetaType<::QList_i64>("QList_i64");
qRegisterMetaType<::QList_QByteArray>("QList_QByteArray");
qRegisterMetaType<::QList_QDate>("QList_QDate");
qRegisterMetaType<::QList_QDateTime>("QList_QDateTime");
qRegisterMetaType<::QList_QLine>("QList_QLine");
qRegisterMetaType<::QList_QLineF>("QList_QLineF");
qRegisterMetaType<::QList_QMargins>("QList_QMargins");
qRegisterMetaType<::QList_QMarginsF>("QList_QMarginsF");
qRegisterMetaType<::QList_QPersistentModelIndex>(
"QList_QPersistentModelIndex");
qRegisterMetaType<::QList_QPoint>("QList_QPoint");
qRegisterMetaType<::QList_QPointF>("QList_QPointF");
qRegisterMetaType<::QList_QRect>("QList_QRect");
qRegisterMetaType<::QList_QRectF>("QList_QRectF");
qRegisterMetaType<::QList_QSize>("QList_QSize");
qRegisterMetaType<::QList_QSizeF>("QList_QSizeF");
qRegisterMetaType<::QList_QString>("QList_QString");
qRegisterMetaType<::QList_QTime>("QList_QTime");
qRegisterMetaType<::QList_QUrl>("QList_QUrl");
qRegisterMetaType<::QList_QUuid>("QList_QUuid");
// Ensure that QList<QVariant> (aka QVariantList) is registered
// otherwise it cannot be used in QML
qRegisterMetaType<::QList_QVariant>("QList_QVariant");
qRegisterMetaType<::QList_u8>("QList_u8");
qRegisterMetaType<::QList_u16>("QList_u16");
qRegisterMetaType<::QList_u32>("QList_u32");
qRegisterMetaType<::QList_u64>("QList_u64");
qRegisterMetaType<::QList_bool>("QList_bool");
qRegisterMetaType<::QList_f32>("QList_f32");
qRegisterMetaType<::QList_f64>("QList_f64");
qRegisterMetaType<::QList_i8>("QList_i8");
qRegisterMetaType<::QList_i16>("QList_i16");
qRegisterMetaType<::QList_i32>("QList_i32");
qRegisterMetaType<::QList_i64>("QList_i64");
qRegisterMetaType<::QList_QByteArray>("QList_QByteArray");
qRegisterMetaType<::QList_QDate>("QList_QDate");
qRegisterMetaType<::QList_QDateTime>("QList_QDateTime");
qRegisterMetaType<::QList_QLine>("QList_QLine");
qRegisterMetaType<::QList_QLineF>("QList_QLineF");
qRegisterMetaType<::QList_QMargins>("QList_QMargins");
qRegisterMetaType<::QList_QMarginsF>("QList_QMarginsF");
qRegisterMetaType<::QList_QPersistentModelIndex>(
"QList_QPersistentModelIndex");
qRegisterMetaType<::QList_QPoint>("QList_QPoint");
qRegisterMetaType<::QList_QPointF>("QList_QPointF");
qRegisterMetaType<::QList_QRect>("QList_QRect");
qRegisterMetaType<::QList_QRectF>("QList_QRectF");
qRegisterMetaType<::QList_QSize>("QList_QSize");
qRegisterMetaType<::QList_QSizeF>("QList_QSizeF");
qRegisterMetaType<::QList_QString>("QList_QString");
qRegisterMetaType<::QList_QTime>("QList_QTime");
qRegisterMetaType<::QList_QUrl>("QList_QUrl");
qRegisterMetaType<::QList_QUuid>("QList_QUuid");
// Ensure that QList<QVariant> (aka QVariantList) is registered
// otherwise it cannot be used in QML
qRegisterMetaType<::QList_QVariant>("QList_QVariant");
qRegisterMetaType<::QList_u8>("QList_u8");
qRegisterMetaType<::QList_u16>("QList_u16");
qRegisterMetaType<::QList_u32>("QList_u32");
qRegisterMetaType<::QList_u64>("QList_u64");

// Ensure that QMap<QString, QVariant> (aka QVariantMap) is registered
// otherwise it cannot be used in QML
qRegisterMetaType<::QMap_QString_QVariant>("QMap_QString_QVariant");
// Ensure that QMap<QString, QVariant> (aka QVariantMap) is registered
// otherwise it cannot be used in QML
qRegisterMetaType<::QMap_QString_QVariant>("QMap_QString_QVariant");

qRegisterMetaType<::QSet_bool>("QSet_bool");
qRegisterMetaType<::QSet_f32>("QSet_f32");
qRegisterMetaType<::QSet_f64>("QSet_f64");
qRegisterMetaType<::QSet_i8>("QSet_i8");
qRegisterMetaType<::QSet_i16>("QSet_i16");
qRegisterMetaType<::QSet_i32>("QSet_i32");
qRegisterMetaType<::QSet_i64>("QSet_i64");
qRegisterMetaType<::QSet_QByteArray>("QSet_QByteArray");
qRegisterMetaType<::QSet_QDate>("QSet_QDate");
qRegisterMetaType<::QSet_QDateTime>("QSet_QDateTime");
qRegisterMetaType<::QSet_QPersistentModelIndex>(
"QSet_QPersistentModelIndex");
qRegisterMetaType<::QSet_QString>("QSet_QString");
qRegisterMetaType<::QSet_QTime>("QSet_QTime");
qRegisterMetaType<::QSet_QUrl>("QSet_QUrl");
qRegisterMetaType<::QSet_QUuid>("QSet_QUuid");
qRegisterMetaType<::QSet_u8>("QSet_u8");
qRegisterMetaType<::QSet_u16>("QSet_u16");
qRegisterMetaType<::QSet_u32>("QSet_u32");
qRegisterMetaType<::QSet_u64>("QSet_u64");
qRegisterMetaType<::QSet_bool>("QSet_bool");
qRegisterMetaType<::QSet_f32>("QSet_f32");
qRegisterMetaType<::QSet_f64>("QSet_f64");
qRegisterMetaType<::QSet_i8>("QSet_i8");
qRegisterMetaType<::QSet_i16>("QSet_i16");
qRegisterMetaType<::QSet_i32>("QSet_i32");
qRegisterMetaType<::QSet_i64>("QSet_i64");
qRegisterMetaType<::QSet_QByteArray>("QSet_QByteArray");
qRegisterMetaType<::QSet_QDate>("QSet_QDate");
qRegisterMetaType<::QSet_QDateTime>("QSet_QDateTime");
qRegisterMetaType<::QSet_QPersistentModelIndex>("QSet_QPersistentModelIndex");
qRegisterMetaType<::QSet_QString>("QSet_QString");
qRegisterMetaType<::QSet_QTime>("QSet_QTime");
qRegisterMetaType<::QSet_QUrl>("QSet_QUrl");
qRegisterMetaType<::QSet_QUuid>("QSet_QUuid");
qRegisterMetaType<::QSet_u8>("QSet_u8");
qRegisterMetaType<::QSet_u16>("QSet_u16");
qRegisterMetaType<::QSet_u32>("QSet_u32");
qRegisterMetaType<::QSet_u64>("QSet_u64");

qRegisterMetaType<::QVector_bool>("QVector_bool");
qRegisterMetaType<::QVector_f32>("QVector_f32");
qRegisterMetaType<::QVector_f64>("QVector_f64");
qRegisterMetaType<::QVector_i8>("QVector_i8");
qRegisterMetaType<::QVector_i16>("QVector_i16");
qRegisterMetaType<::QVector_i32>("QVector_i32");
qRegisterMetaType<::QVector_i64>("QVector_i64");
qRegisterMetaType<::QVector_QByteArray>("QVector_QByteArray");
qRegisterMetaType<::QVector_QDate>("QVector_QDate");
qRegisterMetaType<::QVector_QDateTime>("QVector_QDateTime");
qRegisterMetaType<::QVector_QLine>("QVector_QLine");
qRegisterMetaType<::QVector_QLineF>("QVector_QLineF");
qRegisterMetaType<::QVector_QMargins>("QVector_QMargins");
qRegisterMetaType<::QVector_QMarginsF>("QVector_QMarginsF");
qRegisterMetaType<::QVector_QPersistentModelIndex>(
"QVector_QPersistentModelIndex");
qRegisterMetaType<::QVector_QPoint>("QVector_QPoint");
qRegisterMetaType<::QVector_QPointF>("QVector_QPointF");
qRegisterMetaType<::QVector_QRect>("QVector_QRect");
qRegisterMetaType<::QVector_QRectF>("QVector_QRectF");
qRegisterMetaType<::QVector_QSize>("QVector_QSize");
qRegisterMetaType<::QVector_QSizeF>("QVector_QSizeF");
qRegisterMetaType<::QVector_QString>("QVector_QString");
qRegisterMetaType<::QVector_QTime>("QVector_QTime");
qRegisterMetaType<::QVector_QUrl>("QVector_QUrl");
qRegisterMetaType<::QVector_QUuid>("QVector_QUuid");
// Ensure that QVector<QVariant> (aka QVariantList) is registered
// otherwise it cannot be used in QML
qRegisterMetaType<::QVector_QVariant>("QVector_QVariant");
qRegisterMetaType<::QVector_u8>("QVector_u8");
qRegisterMetaType<::QVector_u16>("QVector_u16");
qRegisterMetaType<::QVector_u32>("QVector_u32");
qRegisterMetaType<::QVector_u64>("QVector_u64");
}

qRegisterMetaType<::QVector_bool>("QVector_bool");
qRegisterMetaType<::QVector_f32>("QVector_f32");
qRegisterMetaType<::QVector_f64>("QVector_f64");
qRegisterMetaType<::QVector_i8>("QVector_i8");
qRegisterMetaType<::QVector_i16>("QVector_i16");
qRegisterMetaType<::QVector_i32>("QVector_i32");
qRegisterMetaType<::QVector_i64>("QVector_i64");
qRegisterMetaType<::QVector_QByteArray>("QVector_QByteArray");
qRegisterMetaType<::QVector_QDate>("QVector_QDate");
qRegisterMetaType<::QVector_QDateTime>("QVector_QDateTime");
qRegisterMetaType<::QVector_QLine>("QVector_QLine");
qRegisterMetaType<::QVector_QLineF>("QVector_QLineF");
qRegisterMetaType<::QVector_QMargins>("QVector_QMargins");
qRegisterMetaType<::QVector_QMarginsF>("QVector_QMarginsF");
qRegisterMetaType<::QVector_QPersistentModelIndex>(
"QVector_QPersistentModelIndex");
qRegisterMetaType<::QVector_QPoint>("QVector_QPoint");
qRegisterMetaType<::QVector_QPointF>("QVector_QPointF");
qRegisterMetaType<::QVector_QRect>("QVector_QRect");
qRegisterMetaType<::QVector_QRectF>("QVector_QRectF");
qRegisterMetaType<::QVector_QSize>("QVector_QSize");
qRegisterMetaType<::QVector_QSizeF>("QVector_QSizeF");
qRegisterMetaType<::QVector_QString>("QVector_QString");
qRegisterMetaType<::QVector_QTime>("QVector_QTime");
qRegisterMetaType<::QVector_QUrl>("QVector_QUrl");
qRegisterMetaType<::QVector_QUuid>("QVector_QUuid");
// Ensure that QVector<QVariant> (aka QVariantList) is registered
// otherwise it cannot be used in QML
qRegisterMetaType<::QVector_QVariant>("QVector_QVariant");
qRegisterMetaType<::QVector_u8>("QVector_u8");
qRegisterMetaType<::QVector_u16>("QVector_u16");
qRegisterMetaType<::QVector_u32>("QVector_u32");
qRegisterMetaType<::QVector_u64>("QVector_u64");
});
// Use Q_COREAPP_STARTUP_FUNCTION to defer registration until QCoreApplication
// is created. This is Qt's recommended approach for type registration and
// ensures proper initialization order on all platforms.
Q_COREAPP_STARTUP_FUNCTION(do_register_core_types)

extern "C" bool
init_cxx_qt_lib_core()
{
// Registration is handled automatically via Q_COREAPP_STARTUP_FUNCTION
// when QCoreApplication is constructed.
return true;
}
20 changes: 14 additions & 6 deletions crates/cxx-qt-lib/src/gui/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,23 @@
#include <cxx-qt-lib/qlist.h>
#include <cxx-qt-lib/qvector.h>

#include <mutex>
#include <QtCore/QCoreApplication>

static void
do_register_gui_types()
{
qRegisterMetaType<::QList_QColor>("QList_QColor");
qRegisterMetaType<::QVector_QColor>("QVector_QColor");
}

// Use Q_COREAPP_STARTUP_FUNCTION to defer registration until QCoreApplication
// is created. This is Qt's recommended approach for type registration.
Q_COREAPP_STARTUP_FUNCTION(do_register_gui_types)

extern "C" bool
init_cxx_qt_lib_gui()
{
static std::once_flag flag;
std::call_once(flag, []() {
qRegisterMetaType<::QList_QColor>("QList_QColor");
qRegisterMetaType<::QVector_QColor>("QVector_QColor");
});
// Registration is handled automatically via Q_COREAPP_STARTUP_FUNCTION
// when QCoreApplication is constructed.
return true;
}
Loading
Loading