diff --git a/.github/workflows/dtkcore-archlinux-build.yml b/.github/workflows/dtkcore-archlinux-build.yml new file mode 100644 index 00000000..8ed82563 --- /dev/null +++ b/.github/workflows/dtkcore-archlinux-build.yml @@ -0,0 +1,86 @@ +name: Build dtkcore on Arch Linux + +on: + push: + + pull_request: + +jobs: + container: + runs-on: ubuntu-latest + container: archlinux:latest + strategy: + matrix: + include: + - qt_version: 5 + dtk5: "ON" + - qt_version: 6 + dtk5: "OFF" + steps: + - name: Initialize pacman and system update + run: | + pacman-key --init + pacman --noconfirm --noprogressbar -Syu + + - name: Install base build tools + run: | + pacman -S --noconfirm --noprogressbar base-devel git cmake ninja pkgconf + + - name: Install dtkcore Qt5 system dependencies + if: matrix.qt_version == 5 + run: | + pacman -S --noconfirm --noprogressbar \ + qt5-base qt5-tools \ + icu uchardet dbus \ + gtest spdlog \ + gsettings-qt \ + dtkcommon dtklog + + - name: Install dtkcore Qt6 system dependencies + if: matrix.qt_version == 6 + run: | + pacman -S --noconfirm --noprogressbar \ + qt6-base qt6-tools \ + icu uchardet dbus \ + gtest spdlog \ + dtkcommon dtk6log + + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Configure and build dtkcore + run: | + cmake -B build \ + -GNinja \ + -DCMAKE_INSTALL_PREFIX=/usr \ + -DCMAKE_INSTALL_LIBDIR=lib \ + -DCMAKE_BUILD_TYPE=Release \ + -DMKSPECS_INSTALL_DIR=lib/qt/mkspecs/modules \ + -DBUILD_DOCS=OFF \ + -DBUILD_EXAMPLES=OFF \ + -DBUILD_TESTING=OFF \ + -DDTK5=${{ matrix.dtk5 }} + cmake --build build -j$(nproc) + echo "✅ dtkcore Qt${{ matrix.qt_version }} built successfully!" + + - name: Install dtkcore to staging directory + run: | + DESTDIR=/tmp/dtkcore-install cmake --install build + echo "Total: $(find /tmp/dtkcore-install -type f | wc -l) files" + + - name: Create installation package + run: | + cd /tmp/dtkcore-install + pacman -S --noconfirm zip + zip -r /tmp/dtkcore-archlinux-qt${{ matrix.qt_version }}-$(date +%Y%m%d-%H%M%S).zip . + ls -la /tmp/dtkcore-archlinux-qt${{ matrix.qt_version }}-*.zip + + - name: Upload dtkcore Arch Linux build artifacts + if: ${{ !env.ACT }} + uses: actions/upload-artifact@v4 + with: + name: dtkcore-archlinux-qt${{ matrix.qt_version }}-build + path: "/tmp/dtkcore-archlinux-qt${{ matrix.qt_version }}-*.zip" + if-no-files-found: error + retention-days: 30 diff --git a/.github/workflows/dtkcore-deepin-build.yml b/.github/workflows/dtkcore-deepin-build.yml new file mode 100644 index 00000000..e05a1160 --- /dev/null +++ b/.github/workflows/dtkcore-deepin-build.yml @@ -0,0 +1,77 @@ +name: Build dtkcore on Deepin crimson + +on: + push: + + pull_request: + +jobs: + container: + runs-on: ubuntu-latest + container: linuxdeepin/deepin:crimson + strategy: + matrix: + include: + - qt_version: 5 + dtk_profile: nodtk6 + - qt_version: 6 + dtk_profile: nodtk5 + steps: + - uses: actions/checkout@v4 + + - name: Setup apt sources and build tools + run: | + set -euxo pipefail + echo "deb [trusted=yes] http://mirrors.kernel.org/deepin/beige/ crimson main commercial community" > /etc/apt/sources.list + echo "deb-src [trusted=yes] http://mirrors.kernel.org/deepin/beige/ crimson main commercial community" >> /etc/apt/sources.list + rm -rf /etc/apt/sources.list.d + apt-get update + apt-get install -y devscripts equivs git + + - name: Build and install dtkcommon from source + run: | + set -euxo pipefail + cd /tmp + git clone --depth=1 https://github.com/linuxdeepin/dtkcommon.git + cd dtkcommon + mk-build-deps --install --remove --tool='apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends --yes' debian/control + dpkg-buildpackage -uc -us -b + dpkg -i ../*.deb 2>/dev/null || apt-get install -f -y + echo "✅ dtkcommon installed" + + - name: Build and install dtklog from source + run: | + set -euxo pipefail + cd /tmp + git clone --depth=1 https://github.com/linuxdeepin/dtklog.git + cd dtklog + mk-build-deps --install --remove --tool='apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends --yes' debian/control + dpkg-buildpackage -uc -us -b -P${{ matrix.dtk_profile }} + dpkg -i ../*.deb 2>/dev/null || apt-get install -f -y + echo "✅ dtklog installed" + + - name: Install dtkcore build dependencies + run: | + set -euxo pipefail + mk-build-deps --install --remove --tool='apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends --yes' debian/control + + - name: Build dtkcore deb packages + run: | + set -euxo pipefail + dpkg-buildpackage -uc -us -b -P${{ matrix.dtk_profile }} + echo "✅ dtkcore Qt${{ matrix.qt_version }} deb packages built successfully!" + ls -la ../ + + - name: Collect deb artifacts + run: | + mkdir -p dist + mv ../*.deb dist/ + ls -la dist + + - name: Upload dtkcore deb packages as artifacts + uses: actions/upload-artifact@v4 + with: + name: dtkcore-deepin-deb-packages-qt${{ matrix.qt_version }} + path: dist/*.deb + if-no-files-found: error + retention-days: 30 diff --git a/src/dci/private/ddcifileengine.cpp b/src/dci/private/ddcifileengine.cpp index 5d7cf11b..d9d519d4 100644 --- a/src/dci/private/ddcifileengine.cpp +++ b/src/dci/private/ddcifileengine.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2021 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include @@ -7,18 +7,18 @@ #include //Avoid changing the access control of the standard library #endif -#define private public -#define protected public #include -#undef private -#undef protected +#include "util/dprivateaccessor_p.h" #include "ddcifileengine_p.h" #include "dci/ddcifile.h" #include #include +D_DECLARE_PRIVATE_METHOD(QFile_d_func_tag, QFile, d_func, QFilePrivate *); +D_DECLARE_PRIVATE_CONST_METHOD(QFilePrivate_engine_tag, QFilePrivate, engine, QAbstractFileEngine *); + DCORE_BEGIN_NAMESPACE #ifdef QT_DEBUG @@ -306,7 +306,7 @@ bool DDciFileEngine::syncToDisk() { if (!flush()) return false; - return realDciFile.d_func()->engine()->syncToDisk(); + return D_PRIVATE_CALL(*D_PRIVATE_CALL(realDciFile, QFile_d_func_tag{}), QFilePrivate_engine_tag{})->syncToDisk(); } qint64 DDciFileEngine::size() const diff --git a/src/util/dprivateaccessor_p.h b/src/util/dprivateaccessor_p.h new file mode 100644 index 00000000..ee47abb9 --- /dev/null +++ b/src/util/dprivateaccessor_p.h @@ -0,0 +1,73 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#pragma once + +#include + +// Private member accessor using the explicit template instantiation technique. +// +// C++ Standard [temp.explicit]/12 states: +// "The usual access checking rules do not apply to names used to +// specify explicit instantiation definitions." +// +// This allows passing pointers to private/protected data members and +// member functions as template arguments in explicit instantiations, +// bypassing normal access control — without modifying the class definition +// and without the UB caused by "#define private public". +// +// NOTE: These helper structs must be in the SAME namespace as the Tag structs +// (global namespace, since the macros expand at file scope). If they were in a +// sub-namespace, the friend definition would create a different function than +// the friend declaration in the Tag struct, causing undefined-reference errors. + +QT_WARNING_PUSH +QT_WARNING_DISABLE_GCC("-Wnon-template-friend") + +template +struct DtkCorePrivateAccessor +{ + using MemberPtr = typename Tag::MemberPtr; + friend MemberPtr get(Tag) noexcept; +}; + +template +struct DtkCorePrivateAccessorImpl : DtkCorePrivateAccessor +{ + friend typename Tag::MemberPtr get(Tag) noexcept { return Ptr; } +}; + +QT_WARNING_POP + +#define D_DECLARE_PRIVATE_MEMBER(TagName, ClassName, Member, MemberType) \ + struct TagName { \ + using MemberPtr = MemberType ClassName::*; \ + friend MemberPtr get(TagName) noexcept; \ + }; \ + template struct DtkCorePrivateAccessorImpl + +#define D_DECLARE_PRIVATE_METHOD(TagName, ClassName, MethodName, RetType, ...) \ + struct TagName { \ + using MemberPtr = RetType (ClassName::*)(__VA_ARGS__); \ + friend MemberPtr get(TagName) noexcept; \ + }; \ + template struct DtkCorePrivateAccessorImpl + +#define D_DECLARE_PRIVATE_CONST_METHOD(TagName, ClassName, MethodName, RetType, ...) \ + struct TagName { \ + using MemberPtr = RetType (ClassName::*)(__VA_ARGS__) const; \ + friend MemberPtr get(TagName) noexcept; \ + }; \ + template struct DtkCorePrivateAccessorImpl + +// Trampoline: ensures get(tag) is called from a context with no class-scope +// get() member that might suppress ADL (C++ [basic.lookup.argdep] para 3). +namespace dtk_private_detail { + template + inline typename Tag::MemberPtr access(Tag t) noexcept { return get(t); } +} + +#define D_PRIVATE_MEMBER(obj, tag) ((obj).*dtk_private_detail::access(tag)) +#define D_PRIVATE_CALL(obj, tag, ...) ((obj).*dtk_private_detail::access(tag))(__VA_ARGS__) + diff --git a/tools/dci/CMakeLists.txt b/tools/dci/CMakeLists.txt index 271afb00..9ff006db 100644 --- a/tools/dci/CMakeLists.txt +++ b/tools/dci/CMakeLists.txt @@ -28,6 +28,9 @@ target_include_directories(${BIN_NAME} PUBLIC ../../include/base/ ../../include/global/ ) +target_include_directories(${BIN_NAME} PRIVATE + ../../src/ +) set_target_properties(${BIN_NAME} PROPERTIES OUTPUT_NAME ${TARGET_NAME}) #end dci