diff options
Diffstat (limited to 'src/tools')
| -rw-r--r-- | src/tools/androiddeployqt/main.cpp | 2 | ||||
| -rw-r--r-- | src/tools/bootstrap/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/tools/rcc/rcc.cpp | 93 |
3 files changed, 80 insertions, 17 deletions
diff --git a/src/tools/androiddeployqt/main.cpp b/src/tools/androiddeployqt/main.cpp index 7f24df7eac2..c4e7101b372 100644 --- a/src/tools/androiddeployqt/main.cpp +++ b/src/tools/androiddeployqt/main.cpp @@ -173,7 +173,7 @@ struct Options QString versionName; QString versionCode; QByteArray minSdkVersion{"28"}; - QByteArray targetSdkVersion{"35"}; + QByteArray targetSdkVersion{"36"}; // lib c++ path QString stdCppPath; diff --git a/src/tools/bootstrap/CMakeLists.txt b/src/tools/bootstrap/CMakeLists.txt index f9161fa6404..c12475d69af 100644 --- a/src/tools/bootstrap/CMakeLists.txt +++ b/src/tools/bootstrap/CMakeLists.txt @@ -221,6 +221,8 @@ qt_internal_apply_gc_binaries(Bootstrap PUBLIC) set_target_properties(Bootstrap PROPERTIES AUTOMOC OFF AUTOUIC OFF AUTORCC OFF) qt_internal_add_target_aliases(Bootstrap) qt_internal_add_target_optimized_flags_for_debug_config_in_current_scope(Bootstrap) +qt_internal_enable_optimized_tools_lto(Bootstrap) +qt_internal_workaround_static_lib_gcc_lto_issue(Bootstrap) qt_set_msvc_cplusplus_options(Bootstrap PUBLIC) qt_set_common_target_properties(Bootstrap) diff --git a/src/tools/rcc/rcc.cpp b/src/tools/rcc/rcc.cpp index 40bfa9c2863..6a6027d44f2 100644 --- a/src/tools/rcc/rcc.cpp +++ b/src/tools/rcc/rcc.cpp @@ -1,10 +1,12 @@ // Copyright (C) 2018 The Qt Company Ltd. // Copyright (C) 2018 Intel Corporation. +// Copyright (C) 2024 Christoph Cullmann <christoph@cullmann.io> // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "rcc.h" #include <qbytearray.h> +#include <qcryptographichash.h> #include <qdatetime.h> #include <qdebug.h> #include <qdir.h> @@ -90,8 +92,28 @@ public: QString resourceName() const; + struct DeduplicationKey { + RCCResourceLibrary::CompressionAlgorithm compressAlgo; + int compressLevel; + int compressThreshold; + QByteArray hash; + + bool operator==(const DeduplicationKey &other) const + { + return compressAlgo == other.compressAlgo && + compressLevel == other.compressLevel && + compressThreshold == other.compressThreshold && + hash == other.hash; + } + }; + + typedef QMultiHash<DeduplicationKey, RCCFileInfo*> DeduplicationMultiHash; + public: - qint64 writeDataBlob(RCCResourceLibrary &lib, qint64 offset, QString *errorMessage); + qint64 writeDataBlob(RCCResourceLibrary &lib, + qint64 offset, + DeduplicationMultiHash &dedupByContent, + QString *errorMessage); qint64 writeDataName(RCCResourceLibrary &, qint64 offset); void writeDataInfo(RCCResourceLibrary &lib); @@ -114,6 +136,11 @@ public: qint64 m_childOffset = 0; }; +static size_t qHash(const RCCFileInfo::DeduplicationKey &key, size_t seed) noexcept +{ + return qHashMulti(seed, key.compressAlgo, key.compressLevel, key.compressThreshold, key.hash); +} + RCCFileInfo::RCCFileInfo(const QString &name, const QFileInfo &fileInfo, QLocale::Language language, QLocale::Territory territory, uint flags, RCCResourceLibrary::CompressionAlgorithm compressAlgo, int compressLevel, @@ -217,8 +244,10 @@ void RCCFileInfo::writeDataInfo(RCCResourceLibrary &lib) } } -qint64 RCCFileInfo::writeDataBlob(RCCResourceLibrary &lib, qint64 offset, - QString *errorMessage) +qint64 RCCFileInfo::writeDataBlob(RCCResourceLibrary &lib, + qint64 offset, + DeduplicationMultiHash &dedupByContent, + QString *errorMessage) { const bool text = lib.m_format == RCCResourceLibrary::C_Code; const bool pass1 = lib.m_format == RCCResourceLibrary::Pass1; @@ -230,24 +259,58 @@ qint64 RCCFileInfo::writeDataBlob(RCCResourceLibrary &lib, qint64 offset, m_dataOffset = offset; QByteArray data; + // determine compession algorithm & level early as used in de-duplication keys + // this avoid corruption for the two pass variants (QTBUG-137546) +#if QT_CONFIG(zstd) + if (m_compressAlgo == RCCResourceLibrary::CompressionAlgorithm::Best && !m_noZstd) { + m_compressAlgo = RCCResourceLibrary::CompressionAlgorithm::Zstd; + m_compressLevel = 19; // not ZSTD_maxCLevel(), as 20+ are experimental + } +#endif +#ifndef QT_NO_COMPRESS + if (m_compressAlgo == RCCResourceLibrary::CompressionAlgorithm::Best) { + m_compressAlgo = RCCResourceLibrary::CompressionAlgorithm::Zlib; + m_compressLevel = 9; + } +#endif + if (!m_isEmpty) { - //find the data to be written - QFile file(m_fileInfo.absoluteFilePath()); + // find the data to be written + const QString absoluteFilePath = m_fileInfo.absoluteFilePath(); + QFile file(absoluteFilePath); if (!file.open(QFile::ReadOnly)) { - *errorMessage = msgOpenReadFailed(m_fileInfo.absoluteFilePath(), file.errorString()); + *errorMessage = msgOpenReadFailed(absoluteFilePath, file.errorString()); return 0; } - data = file.readAll(); + + // de-duplicate the same file content, we can re-use already written data + // we only do that if we have the same compression settings + const QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Sha256); + const DeduplicationKey key{m_compressAlgo, m_compressLevel, m_compressThreshold, hash}; + const QList<RCCFileInfo *> potentialCandidates = dedupByContent.values(key); + for (const RCCFileInfo *candidate : potentialCandidates) { + // check real content, we can have collisions + QFile candidateFile(candidate->m_fileInfo.absoluteFilePath()); + if (!candidateFile.open(QFile::ReadOnly)) { + *errorMessage = msgOpenReadFailed(candidate->m_fileInfo.absoluteFilePath(), + candidateFile.errorString()); + return 0; + } + if (data != candidateFile.readAll()) + continue; + // just remember the offset & flags with final compression state + // of the already written data and be done + m_dataOffset = candidate->m_dataOffset; + m_flags = candidate->m_flags; + return offset; + } + dedupByContent.insert(key, this); } // Check if compression is useful for this file if (data.size() != 0) { #if QT_CONFIG(zstd) - if (m_compressAlgo == RCCResourceLibrary::CompressionAlgorithm::Best && !m_noZstd) { - m_compressAlgo = RCCResourceLibrary::CompressionAlgorithm::Zstd; - m_compressLevel = 19; // not ZSTD_maxCLevel(), as 20+ are experimental - } if (m_compressAlgo == RCCResourceLibrary::CompressionAlgorithm::Zstd && !m_noZstd) { if (lib.m_zstdCCtx == nullptr) lib.m_zstdCCtx = ZSTD_createCCtx(); @@ -292,10 +355,6 @@ qint64 RCCFileInfo::writeDataBlob(RCCResourceLibrary &lib, qint64 offset, } #endif #ifndef QT_NO_COMPRESS - if (m_compressAlgo == RCCResourceLibrary::CompressionAlgorithm::Best) { - m_compressAlgo = RCCResourceLibrary::CompressionAlgorithm::Zlib; - m_compressLevel = 9; - } if (m_compressAlgo == RCCResourceLibrary::CompressionAlgorithm::Zlib) { QByteArray compressed = qCompress(reinterpret_cast<uchar *>(data.data()), data.size(), m_compressLevel); @@ -1168,6 +1227,7 @@ bool RCCResourceLibrary::writeDataBlobs() QStack<RCCFileInfo*> pending; pending.push(m_root); qint64 offset = 0; + RCCFileInfo::DeduplicationMultiHash dedupByContent; QString errorMessage; while (!pending.isEmpty()) { RCCFileInfo *file = pending.pop(); @@ -1176,7 +1236,8 @@ bool RCCResourceLibrary::writeDataBlobs() if (child->m_flags & RCCFileInfo::Directory) pending.push(child); else { - offset = child->writeDataBlob(*this, offset, &errorMessage); + offset = child->writeDataBlob(*this, offset, + dedupByContent, &errorMessage); if (offset == 0) { m_errorDevice->write(errorMessage.toUtf8()); return false; |
