diff options
Diffstat (limited to 'src/tools')
-rw-r--r-- | src/tools/androiddeployqt/main.cpp | 326 | ||||
-rw-r--r-- | src/tools/moc/generator.cpp | 2 | ||||
-rw-r--r-- | src/tools/moc/main.cpp | 69 | ||||
-rw-r--r-- | src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp | 2 | ||||
-rw-r--r-- | src/tools/qlalr/cppgenerator.cpp | 5 | ||||
-rw-r--r-- | src/tools/rcc/rcc.cpp | 4 | ||||
-rw-r--r-- | src/tools/rcc/rcc.h | 2 | ||||
-rw-r--r-- | src/tools/uic/cpp/cppwriteinitialization.cpp | 14 | ||||
-rw-r--r-- | src/tools/uic/python/pythonwriteimports.cpp | 8 | ||||
-rw-r--r-- | src/tools/uic/uic.cpp | 4 | ||||
-rw-r--r-- | src/tools/windeployqt/main.cpp | 35 | ||||
-rw-r--r-- | src/tools/windeployqt/utils.h | 4 |
12 files changed, 289 insertions, 186 deletions
diff --git a/src/tools/androiddeployqt/main.cpp b/src/tools/androiddeployqt/main.cpp index 6125b405b5..da5c2c8c77 100644 --- a/src/tools/androiddeployqt/main.cpp +++ b/src/tools/androiddeployqt/main.cpp @@ -44,15 +44,16 @@ static const bool mustReadOutputAnyway = true; // pclose seems to return the wro static QStringList dependenciesForDepfile; -FILE *openProcess(const QString &command) +auto openProcess(const QString &command) { #if defined(Q_OS_WIN32) QString processedCommand = u'\"' + command + u'\"'; #else const QString& processedCommand = command; #endif - - return popen(processedCommand.toLocal8Bit().constData(), QT_POPEN_READ); + struct Closer { void operator()(FILE *proc) const { if (proc) (void)pclose(proc); } }; + using UP = std::unique_ptr<FILE, Closer>; + return UP{popen(processedCommand.toLocal8Bit().constData(), QT_POPEN_READ)}; } struct QtDependency @@ -104,6 +105,7 @@ struct Options , installApk(false) , uninstallApk(false) , qmlImportScannerBinaryPath() + , buildAar(false) {} enum DeploymentMechanism @@ -239,6 +241,7 @@ struct Options // Override qml import scanner path QString qmlImportScannerBinaryPath; bool qmlSkipImportScanning = false; + bool buildAar; }; static const QHash<QByteArray, QByteArray> elfArchitectures = { @@ -310,23 +313,21 @@ QString fileArchitecture(const Options &options, const QString &path) readElf = "%1 --needed-libs %2"_L1.arg(shellQuote(readElf), shellQuote(path)); - FILE *readElfCommand = openProcess(readElf); + auto readElfCommand = openProcess(readElf); if (!readElfCommand) { fprintf(stderr, "Cannot execute command %s\n", qPrintable(readElf)); return {}; } char buffer[512]; - while (fgets(buffer, sizeof(buffer), readElfCommand) != nullptr) { + while (fgets(buffer, sizeof(buffer), readElfCommand.get()) != nullptr) { QByteArray line = QByteArray::fromRawData(buffer, qstrlen(buffer)); line = line.trimmed(); if (line.startsWith("Arch: ")) { auto it = elfArchitectures.find(line.mid(6)); - pclose(readElfCommand); return it != elfArchitectures.constEnd() ? QString::fromLatin1(it.value()) : QString{}; } } - pclose(readElfCommand); return {}; } @@ -527,6 +528,8 @@ Options parseOptions() options.protectedAuthenticationPath = true; } else if (argument.compare("--aux-mode"_L1, Qt::CaseInsensitive) == 0) { options.auxMode = true; + } else if (argument.compare("--build-aar"_L1, Qt::CaseInsensitive) == 0) { + options.buildAar = true; } else if (argument.compare("--qml-importscanner-binary"_L1, Qt::CaseInsensitive) == 0) { options.qmlImportScannerBinaryPath = arguments.at(++i).trimmed(); } else if (argument.compare("--no-rcc-bundle-cleanup"_L1, @@ -538,6 +541,23 @@ Options parseOptions() } } + if (options.buildAar) { + if (options.installApk || options.uninstallApk) { + fprintf(stderr, "Warning: Skipping %s, AAR packages are not installable.\n", + options.uninstallApk ? "--reinstall" : "--install"); + options.installApk = false; + options.uninstallApk = false; + } + if (options.buildAAB) { + fprintf(stderr, "Warning: Skipping -aab as --build-aar is present.\n"); + options.buildAAB = false; + } + if (!options.keyStore.isEmpty()) { + fprintf(stderr, "Warning: Skipping --sign, signing AAR packages is not supported.\n"); + options.keyStore.clear(); + } + } + if (options.buildDirectory.isEmpty() && !options.depFilePath.isEmpty()) options.helpRequested = true; @@ -645,6 +665,9 @@ Optional arguments: --apk <path/where/to/copy/the/apk>: Path where to copy the built apk. + --build-aar: Build an AAR package. This option skips --aab, --install, + --reinstall, and --sign options if they are provided. + --qml-importscanner-binary <path/to/qmlimportscanner>: Override the default qmlimportscanner binary path. By default the qmlimportscanner binary is located using the Qt directory @@ -732,18 +755,72 @@ bool copyFileIfNewer(const QString &sourceFileName, return true; } -QString cleanPackageName(QString packageName) +struct GradleBuildConfigs { + QString appNamespace; + bool setsLegacyPackaging = false; + bool usesIntegerCompileSdkVersion = false; +}; + +GradleBuildConfigs gradleBuildConfigs(const QString &path) +{ + GradleBuildConfigs configs; + + QFile file(path); + if (!file.open(QIODevice::ReadOnly)) + return configs; + + auto isComment = [](const QByteArray &trimmed) { + return trimmed.startsWith("//") || trimmed.startsWith('*') || trimmed.startsWith("/*"); + }; + + auto extractValue = [](const QByteArray &trimmed) { + int idx = trimmed.indexOf('='); + + if (idx == -1) + idx = trimmed.indexOf(' '); + + if (idx > -1) + return trimmed.mid(idx + 1).trimmed(); + + return QByteArray(); + }; + + const auto lines = file.readAll().split('\n'); + for (const auto &line : lines) { + const QByteArray trimmedLine = line.trimmed(); + if (isComment(trimmedLine)) + continue; + if (trimmedLine.contains("useLegacyPackaging")) { + configs.setsLegacyPackaging = true; + } else if (trimmedLine.contains("compileSdkVersion androidCompileSdkVersion.toInteger()")) { + configs.usesIntegerCompileSdkVersion = true; + } else if (trimmedLine.contains("namespace")) { + configs.appNamespace = QString::fromUtf8(extractValue(trimmedLine)); + } + } + + return configs; +} + +QString cleanPackageName(QString packageName, bool *cleaned = nullptr) { auto isLegalChar = [] (QChar c) -> bool { ushort ch = c.unicode(); return (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || - ch == '.'; + ch == '.' || ch == '_'; }; + + if (cleaned) + *cleaned = false; + for (QChar &c : packageName) { - if (!isLegalChar(c)) + if (!isLegalChar(c)) { c = u'_'; + if (cleaned) + *cleaned = true; + } } static QStringList keywords; @@ -778,12 +855,16 @@ QString cleanPackageName(QString packageName) QChar c = word[0]; if ((c >= u'0' && c <= u'9') || c == u'_') { packageName.insert(index + 1, u'a'); + if (cleaned) + *cleaned = true; index = next + 1; continue; } } if (keywords.contains(word)) { packageName.insert(next, "_"_L1); + if (cleaned) + *cleaned = true; index = next + 1; } else { index = next; @@ -813,18 +894,31 @@ QString detectLatestAndroidPlatform(const QString &sdkPath) return latestPlatform.baseName(); } -QString packageNameFromAndroidManifest(const QString &androidManifestPath) +QString extractPackageName(Options *options) { - QFile androidManifestXml(androidManifestPath); + { + const QString gradleBuildFile = options->androidSourceDirectory + "/build.gradle"_L1; + QString packageName = gradleBuildConfigs(gradleBuildFile).appNamespace; + + if (!packageName.isEmpty() && packageName != "androidPackageName"_L1) + return packageName; + } + + QFile androidManifestXml(options->androidSourceDirectory + "/AndroidManifest.xml"_L1); if (androidManifestXml.open(QIODevice::ReadOnly)) { QXmlStreamReader reader(&androidManifestXml); while (!reader.atEnd()) { reader.readNext(); - if (reader.isStartElement() && reader.name() == "manifest"_L1) - return cleanPackageName(reader.attributes().value("package"_L1).toString()); + if (reader.isStartElement() && reader.name() == "manifest"_L1) { + QString packageName = reader.attributes().value("package"_L1).toString(); + if (!packageName.isEmpty() && packageName != "org.qtproject.example"_L1) + return packageName; + break; + } } } - return {}; + + return QString(); } bool parseCmakeBoolean(const QJsonValue &value) @@ -1222,6 +1316,24 @@ bool readInputFile(Options *options) } { + const QJsonValue androidPackageName = jsonObject.value("android-package-name"_L1); + const QString extractedPackageName = extractPackageName(options); + if (!extractedPackageName.isEmpty()) + options->packageName = extractedPackageName; + else if (!androidPackageName.isUndefined()) + options->packageName = androidPackageName.toString(); + else + options->packageName = "org.qtproject.example.%1"_L1.arg(options->applicationBinary); + + bool cleaned; + options->packageName = cleanPackageName(options->packageName, &cleaned); + if (cleaned) { + fprintf(stderr, "Warning: Package name contained illegal characters and was cleaned " + "to \"%s\"\n", qPrintable(options->packageName)); + } + } + + { using ItFlag = QDirListing::IteratorFlag; const QJsonValue deploymentDependencies = jsonObject.value("deployment-dependencies"_L1); if (!deploymentDependencies.isUndefined()) { @@ -1278,9 +1390,6 @@ bool readInputFile(Options *options) options->isZstdCompressionEnabled = zstdCompressionFlag.toBool(); } } - options->packageName = packageNameFromAndroidManifest(options->androidSourceDirectory + "/AndroidManifest.xml"_L1); - if (options->packageName.isEmpty()) - options->packageName = cleanPackageName("org.qtproject.example.%1"_L1.arg(options->applicationBinary)); return true; } @@ -1380,6 +1489,9 @@ bool copyAndroidTemplate(const Options &options) if (!copyAndroidTemplate(options, "/src/android/templates"_L1)) return false; + if (options.buildAar) + return copyAndroidTemplate(options, "/src/android/templates_aar"_L1); + return true; } @@ -1735,13 +1847,7 @@ bool updateAndroidManifest(Options &options) reader.readNext(); if (reader.isStartElement()) { - if (reader.name() == "manifest"_L1) { - if (!reader.attributes().hasAttribute("package"_L1)) { - fprintf(stderr, "Invalid android manifest file: %s\n", qPrintable(androidManifestPath)); - return false; - } - options.packageName = reader.attributes().value("package"_L1).toString(); - } else if (reader.name() == "uses-sdk"_L1) { + if (reader.name() == "uses-sdk"_L1) { if (reader.attributes().hasAttribute("android:minSdkVersion"_L1)) if (reader.attributes().value("android:minSdkVersion"_L1).toInt() < 23) { fprintf(stderr, "Invalid minSdkVersion version, minSdkVersion must be >= 23\n"); @@ -2014,7 +2120,7 @@ QStringList getQtLibsFromElf(const Options &options, const QString &fileName) readElf = "%1 --needed-libs %2"_L1.arg(shellQuote(readElf), shellQuote(fileName)); - FILE *readElfCommand = openProcess(readElf); + auto readElfCommand = openProcess(readElf); if (!readElfCommand) { fprintf(stderr, "Cannot execute command %s\n", qPrintable(readElf)); return QStringList(); @@ -2024,7 +2130,7 @@ QStringList getQtLibsFromElf(const Options &options, const QString &fileName) bool readLibs = false; char buffer[512]; - while (fgets(buffer, sizeof(buffer), readElfCommand) != nullptr) { + while (fgets(buffer, sizeof(buffer), readElfCommand.get()) != nullptr) { QByteArray line = QByteArray::fromRawData(buffer, qstrlen(buffer)); QString library; line = line.trimmed(); @@ -2034,7 +2140,6 @@ QStringList getQtLibsFromElf(const Options &options, const QString &fileName) if (it == elfArchitectures.constEnd() || *it != options.currentArchitecture.toLatin1()) { if (options.verbose) fprintf(stdout, "Skipping \"%s\", architecture mismatch\n", qPrintable(fileName)); - pclose(readElfCommand); return {}; } } @@ -2049,8 +2154,6 @@ QStringList getQtLibsFromElf(const Options &options, const QString &fileName) ret += libraryName; } - pclose(readElfCommand); - return ret; } @@ -2188,7 +2291,7 @@ bool scanImports(Options *options, QSet<QString> *usedDependencies) qmlImportScanner.toLocal8Bit().constData()); } - FILE *qmlImportScannerCommand = popen(qmlImportScanner.toLocal8Bit().constData(), QT_POPEN_READ); + auto qmlImportScannerCommand = openProcess(qmlImportScanner); if (qmlImportScannerCommand == 0) { fprintf(stderr, "Couldn't run qmlimportscanner.\n"); return false; @@ -2196,13 +2299,12 @@ bool scanImports(Options *options, QSet<QString> *usedDependencies) QByteArray output; char buffer[512]; - while (fgets(buffer, sizeof(buffer), qmlImportScannerCommand) != 0) + while (fgets(buffer, sizeof(buffer), qmlImportScannerCommand.get()) != nullptr) output += QByteArray(buffer, qstrlen(buffer)); QJsonDocument jsonDocument = QJsonDocument::fromJson(output); if (jsonDocument.isNull()) { fprintf(stderr, "Invalid json output from qmlimportscanner.\n"); - pclose(qmlImportScannerCommand); return false; } @@ -2211,7 +2313,6 @@ bool scanImports(Options *options, QSet<QString> *usedDependencies) QJsonValue value = jsonArray.at(i); if (!value.isObject()) { fprintf(stderr, "Invalid format of qmlimportscanner output.\n"); - pclose(qmlImportScannerCommand); return false; } @@ -2257,7 +2358,6 @@ bool scanImports(Options *options, QSet<QString> *usedDependencies) if (importPathOfThisImport.isEmpty()) { fprintf(stderr, "Import found outside of import paths: %s.\n", qPrintable(info.absoluteFilePath())); - pclose(qmlImportScannerCommand); return false; } @@ -2325,7 +2425,6 @@ bool scanImports(Options *options, QSet<QString> *usedDependencies) } } - pclose(qmlImportScannerCommand); return true; } @@ -2344,17 +2443,17 @@ bool runCommand(const Options &options, const QString &command) if (options.verbose) fprintf(stdout, "Running command '%s'\n", qPrintable(command)); - FILE *runCommand = openProcess(command); + auto runCommand = openProcess(command); if (runCommand == nullptr) { fprintf(stderr, "Cannot run command '%s'\n", qPrintable(command)); return false; } char buffer[4096]; - while (fgets(buffer, sizeof(buffer), runCommand) != nullptr) { + while (fgets(buffer, sizeof(buffer), runCommand.get()) != nullptr) { if (options.verbose) fprintf(stdout, "%s", buffer); } - pclose(runCommand); + runCommand.reset(); fflush(stdout); fflush(stderr); return true; @@ -2505,7 +2604,8 @@ bool containsApplicationBinary(Options *options) return true; } -FILE *runAdb(const Options &options, const QString &arguments) +auto runAdb(const Options &options, const QString &arguments) + -> decltype(openProcess({})) { QString adb = execSuffixAppended(options.sdkPath + "/platform-tools/adb"_L1); if (!QFile::exists(adb)) { @@ -2521,7 +2621,7 @@ FILE *runAdb(const Options &options, const QString &arguments) if (options.verbose) fprintf(stdout, "Running command \"%s\"\n", adb.toLocal8Bit().constData()); - FILE *adbCommand = openProcess(adb); + auto adbCommand = openProcess(adb); if (adbCommand == 0) { fprintf(stderr, "Cannot start adb: %s\n", qPrintable(adb)); return 0; @@ -2745,38 +2845,6 @@ void checkAndWarnGradleLongPaths(const QString &outputDirectory) } #endif -struct GradleFlags { - bool setsLegacyPackaging = false; - bool usesIntegerCompileSdkVersion = false; -}; - -GradleFlags gradleBuildFlags(const QString &path) -{ - GradleFlags flags; - - QFile file(path); - if (!file.open(QIODevice::ReadOnly)) - return flags; - - auto isComment = [](const QByteArray &line) { - const auto trimmed = line.trimmed(); - return trimmed.startsWith("//") || trimmed.startsWith('*') || trimmed.startsWith("/*"); - }; - - const auto lines = file.readAll().split('\n'); - for (const auto &line : lines) { - if (isComment(line)) - continue; - if (line.contains("useLegacyPackaging")) { - flags.setsLegacyPackaging = true; - } else if (line.contains("compileSdkVersion androidCompileSdkVersion.toInteger()")) { - flags.usesIntegerCompileSdkVersion = true; - } - } - - return flags; -} - bool buildAndroidProject(const Options &options) { GradleProperties localProperties; @@ -2789,8 +2857,8 @@ bool buildAndroidProject(const Options &options) GradleProperties gradleProperties = readGradleProperties(gradlePropertiesPath); const QString gradleBuildFilePath = options.outputDirectory + "build.gradle"_L1; - GradleFlags gradleFlags = gradleBuildFlags(gradleBuildFilePath); - if (!gradleFlags.setsLegacyPackaging) + GradleBuildConfigs gradleConfigs = gradleBuildConfigs(gradleBuildFilePath); + if (!gradleConfigs.setsLegacyPackaging) gradleProperties["android.bundle.enableUncompressedNativeLibs"] = "false"; gradleProperties["buildDir"] = "build"; @@ -2809,7 +2877,7 @@ bool buildAndroidProject(const Options &options) QByteArray sdkPlatformVersion; // Provide the integer version only if build.gradle explicitly converts to Integer, // to avoid regression to existing projects that build for sdk platform of form android-xx. - if (gradleFlags.usesIntegerCompileSdkVersion) { + if (gradleConfigs.usesIntegerCompileSdkVersion) { const QByteArray tmp = options.androidPlatform.split(u'-').last().toLocal8Bit(); bool ok; tmp.toInt(&ok); @@ -2824,6 +2892,7 @@ bool buildAndroidProject(const Options &options) if (sdkPlatformVersion.isEmpty()) sdkPlatformVersion = options.androidPlatform.toLocal8Bit(); + gradleProperties["androidPackageName"] = options.packageName.toLocal8Bit(); gradleProperties["androidCompileSdkVersion"] = sdkPlatformVersion; gradleProperties["qtMinSdkVersion"] = options.minSdkVersion; gradleProperties["qtTargetSdkVersion"] = options.targetSdkVersion; @@ -2839,6 +2908,9 @@ bool buildAndroidProject(const Options &options) abiList.append(it.key()); } gradleProperties["qtTargetAbiList"] = abiList.toLocal8Bit();// armeabi-v7a or arm64-v8a or ... + gradleProperties["qtGradlePluginType"] = options.buildAar + ? "com.android.library" + : "com.android.application"; if (!mergeGradleProperties(gradlePropertiesPath, gradleProperties)) return false; @@ -2864,19 +2936,19 @@ bool buildAndroidProject(const Options &options) if (options.verbose) commandLine += " --info"_L1; - FILE *gradleCommand = openProcess(commandLine); + auto gradleCommand = openProcess(commandLine); if (gradleCommand == 0) { fprintf(stderr, "Cannot run gradle command: %s\n.", qPrintable(commandLine)); return false; } char buffer[512]; - while (fgets(buffer, sizeof(buffer), gradleCommand) != 0) { + while (fgets(buffer, sizeof(buffer), gradleCommand.get()) != nullptr) { fprintf(stdout, "%s", buffer); fflush(stdout); } - int errorCode = pclose(gradleCommand); + const int errorCode = pclose(gradleCommand.release()); if (errorCode != 0) { fprintf(stderr, "Building the android package failed!\n"); if (!options.verbose) @@ -2902,18 +2974,18 @@ bool uninstallApk(const Options &options) fprintf(stdout, "Uninstalling old Android package %s if present.\n", qPrintable(options.packageName)); - FILE *adbCommand = runAdb(options, " uninstall "_L1 + shellQuote(options.packageName)); + auto adbCommand = runAdb(options, " uninstall "_L1 + shellQuote(options.packageName)); if (adbCommand == 0) return false; if (options.verbose || mustReadOutputAnyway) { char buffer[512]; - while (fgets(buffer, sizeof(buffer), adbCommand) != 0) + while (fgets(buffer, sizeof(buffer), adbCommand.get()) != nullptr) if (options.verbose) fprintf(stdout, "%s", buffer); } - int returnCode = pclose(adbCommand); + const int returnCode = pclose(adbCommand.release()); if (returnCode != 0) { fprintf(stderr, "Warning: Uninstall failed!\n"); if (!options.verbose) @@ -2926,39 +2998,43 @@ bool uninstallApk(const Options &options) enum PackageType { AAB, + AAR, UnsignedAPK, SignedAPK }; -QString packagePath(const Options &options, PackageType pt) -{ - QString path(options.outputDirectory); - path += "/build/outputs/%1/"_L1.arg(pt >= UnsignedAPK ? QStringLiteral("apk") : QStringLiteral("bundle")); - QString buildType(options.releasePackage ? "release/"_L1 : "debug/"_L1); - if (QDir(path + buildType).exists()) - path += buildType; - path += QDir(options.outputDirectory).dirName() + u'-'; - if (options.releasePackage) { - path += "release-"_L1; - if (pt >= UnsignedAPK) { - if (pt == UnsignedAPK) - path += "un"_L1; - path += "signed.apk"_L1; - } else { - path.chop(1); - path += ".aab"_L1; - } - } else { - path += "debug"_L1; - if (pt >= UnsignedAPK) { - if (pt == SignedAPK) - path += "-signed"_L1; - path += ".apk"_L1; - } else { - path += ".aab"_L1; - } - } - return path; +QString packagePath(const Options &options, PackageType packageType) +{ + // The package type is always AAR if option.buildAar has been set + if (options.buildAar) + packageType = AAR; + + static const QHash<PackageType, QLatin1StringView> packageTypeToPath{ + { AAB, "bundle"_L1 }, { AAR, "aar"_L1 }, { UnsignedAPK, "apk"_L1 }, { SignedAPK, "apk"_L1 } + }; + static const QHash<PackageType, QLatin1StringView> packageTypeToExtension{ + { AAB, "aab"_L1 }, { AAR, "aar"_L1 }, { UnsignedAPK, "apk"_L1 }, { SignedAPK, "apk"_L1 } + }; + + const QString buildType(options.releasePackage ? "release"_L1 : "debug"_L1); + QString signedSuffix; + if (packageType == SignedAPK) + signedSuffix = "-signed"_L1; + else if (packageType == UnsignedAPK && options.releasePackage) + signedSuffix = "-unsigned"_L1; + + QString dirPath(options.outputDirectory); + dirPath += "/build/outputs/%1/"_L1.arg(packageTypeToPath[packageType]); + if (QDir(dirPath + buildType).exists()) + dirPath += buildType; + + const QString fileName = "/%1-%2%3.%4"_L1.arg( + QDir(options.outputDirectory).dirName(), + buildType, + signedSuffix, + packageTypeToExtension[packageType]); + + return dirPath + fileName; } bool installApk(const Options &options) @@ -2971,20 +3047,20 @@ bool installApk(const Options &options) if (options.verbose) fprintf(stdout, "Installing Android package to device.\n"); - FILE *adbCommand = runAdb(options, " install -r "_L1 - + packagePath(options, options.keyStore.isEmpty() ? UnsignedAPK - : SignedAPK)); + auto adbCommand = runAdb(options, " install -r "_L1 + + packagePath(options, options.keyStore.isEmpty() ? UnsignedAPK + : SignedAPK)); if (adbCommand == 0) return false; if (options.verbose || mustReadOutputAnyway) { char buffer[512]; - while (fgets(buffer, sizeof(buffer), adbCommand) != 0) + while (fgets(buffer, sizeof(buffer), adbCommand.get()) != nullptr) if (options.verbose) fprintf(stdout, "%s", buffer); } - int returnCode = pclose(adbCommand); + const int returnCode = pclose(adbCommand.release()); if (returnCode != 0) { fprintf(stderr, "Installing to device failed!\n"); if (!options.verbose) @@ -3102,7 +3178,7 @@ bool signAAB(const Options &options) QString command = jarSignerTool + " %1 %2"_L1.arg(shellQuote(file)) .arg(shellQuote(options.keyStoreAlias)); - FILE *jarSignerCommand = openProcess(command); + auto jarSignerCommand = openProcess(command); if (jarSignerCommand == 0) { fprintf(stderr, "Couldn't run jarsigner.\n"); return false; @@ -3110,11 +3186,11 @@ bool signAAB(const Options &options) if (options.verbose) { char buffer[512]; - while (fgets(buffer, sizeof(buffer), jarSignerCommand) != 0) + while (fgets(buffer, sizeof(buffer), jarSignerCommand.get()) != nullptr) fprintf(stdout, "%s", buffer); } - int errorCode = pclose(jarSignerCommand); + const int errorCode = pclose(jarSignerCommand.release()); if (errorCode != 0) { fprintf(stderr, "jarsigner command failed.\n"); if (!options.verbose) @@ -3142,17 +3218,17 @@ bool signPackage(const Options &options) return false; auto zipalignRunner = [](const QString &zipAlignCommandLine) { - FILE *zipAlignCommand = openProcess(zipAlignCommandLine); + auto zipAlignCommand = openProcess(zipAlignCommandLine); if (zipAlignCommand == 0) { fprintf(stderr, "Couldn't run zipalign.\n"); return false; } char buffer[512]; - while (fgets(buffer, sizeof(buffer), zipAlignCommand) != 0) + while (fgets(buffer, sizeof(buffer), zipAlignCommand.get()) != nullptr) fprintf(stdout, "%s", buffer); - return pclose(zipAlignCommand) == 0; + return pclose(zipAlignCommand.release()) == 0; }; const QString verifyZipAlignCommandLine = @@ -3209,17 +3285,17 @@ bool signPackage(const Options &options) apkSignCommand += " %1"_L1.arg(shellQuote(packagePath(options, SignedAPK))); auto apkSignerRunner = [](const QString &command, bool verbose) { - FILE *apkSigner = openProcess(command); + auto apkSigner = openProcess(command); if (apkSigner == 0) { fprintf(stderr, "Couldn't run apksigner.\n"); return false; } char buffer[512]; - while (fgets(buffer, sizeof(buffer), apkSigner) != 0) + while (fgets(buffer, sizeof(buffer), apkSigner.get()) != nullptr) fprintf(stdout, "%s", buffer); - int errorCode = pclose(apkSigner); + const int errorCode = pclose(apkSigner.release()); if (errorCode != 0) { fprintf(stderr, "apksigner command failed.\n"); if (!verbose) diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index 02e9ef178a..1c6604a96e 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -833,7 +833,7 @@ void Generator::generateProperties() // if (cdef->propertyList.size()) - fprintf(out, "\n // properties: name, type, flags\n"); + fprintf(out, "\n // properties: name, type, flags, notifyId, revision\n"); for (const PropertyDef &p : std::as_const(cdef->propertyList)) { uint flags = Invalid; if (!isBuiltinType(p.type)) diff --git a/src/tools/moc/main.cpp b/src/tools/moc/main.cpp index bb51352519..89fb367ca7 100644 --- a/src/tools/moc/main.cpp +++ b/src/tools/moc/main.cpp @@ -19,7 +19,8 @@ #include <qcoreapplication.h> #include <qcommandlineoption.h> #include <qcommandlineparser.h> -#include <qscopedpointer.h> + +#include <memory> QT_BEGIN_NAMESPACE @@ -58,10 +59,21 @@ void error(const char *msg = "Invalid argument") fprintf(stderr, "moc: %s\n", msg); } -struct ScopedPointerFileCloser +static auto openFileForWriting(const QString &name) { - static inline void cleanup(FILE *handle) { if (handle) fclose(handle); } -}; + struct Closer { void operator()(FILE *handle) const { fclose(handle); } }; + using R = std::unique_ptr<FILE, Closer>; + +#ifdef _MSC_VER + FILE *file; + if (_wfopen_s(&file, reinterpret_cast<const wchar_t *>(name.utf16()), L"w") != 0) + return R{}; + return R{file}; +#else + return R{fopen(QFile::encodeName(name).constData(), "w")}; +#endif +} +using File = decltype(openFileForWriting({})); static inline bool hasNext(const Symbols &symbols, int i) { return (i < symbols.size()); } @@ -178,7 +190,7 @@ int runMoc(int argc, char **argv) QString filename; QString output; QFile in; - FILE *out = nullptr; + File out; // Note that moc isn't translated. // If you use this code as an example for a translated app, make sure to translate the strings. @@ -528,16 +540,12 @@ int runMoc(int argc, char **argv) // 3. and output meta object code - QScopedPointer<FILE, ScopedPointerFileCloser> jsonOutput; + File jsonOutput; bool outputToFile = true; if (output.size()) { // output file specified -#if defined(_MSC_VER) - if (_wfopen_s(&out, reinterpret_cast<const wchar_t *>(output.utf16()), L"w") != 0) -#else - out = fopen(QFile::encodeName(output).constData(), "w"); // create output file + out = openFileForWriting(output); if (!out) -#endif { const auto fopen_errno = errno; fprintf(stderr, "moc: Cannot create %s. Error: %s\n", @@ -548,37 +556,29 @@ int runMoc(int argc, char **argv) if (parser.isSet(jsonOption)) { const QString jsonOutputFileName = output + ".json"_L1; - FILE *f; -#if defined(_MSC_VER) - if (_wfopen_s(&f, reinterpret_cast<const wchar_t *>(jsonOutputFileName.utf16()), L"w") != 0) -#else - f = fopen(QFile::encodeName(jsonOutputFileName).constData(), "w"); - if (!f) -#endif - { + jsonOutput = openFileForWriting(jsonOutputFileName); + if (!jsonOutput) { const auto fopen_errno = errno; fprintf(stderr, "moc: Cannot create JSON output file %s. Error: %s\n", QFile::encodeName(jsonOutputFileName).constData(), strerror(fopen_errno)); } - jsonOutput.reset(f); } } else { // use stdout - out = stdout; + out.reset(stdout); outputToFile = false; } if (pp.preprocessOnly) { - fprintf(out, "%s\n", composePreprocessorOutput(moc.symbols).constData()); + fprintf(out.get(), "%s\n", composePreprocessorOutput(moc.symbols).constData()); } else { if (moc.classList.isEmpty()) moc.note("No relevant classes found. No output generated."); else - moc.generate(out, jsonOutput.data()); + moc.generate(out.get(), jsonOutput.get()); } - if (output.size()) - fclose(out); + out.reset(); if (parser.isSet(depFileOption)) { // 4. write a Make-style dependency file (can also be consumed by Ninja). @@ -596,26 +596,17 @@ int runMoc(int argc, char **argv) fprintf(stderr, "moc: Writing to stdout, but no depfile path specified.\n"); } - QScopedPointer<FILE, ScopedPointerFileCloser> depFileHandle; - FILE *depFileHandleRaw; -#if defined(_MSC_VER) - if (_wfopen_s(&depFileHandleRaw, - reinterpret_cast<const wchar_t *>(depOutputFileName.utf16()), L"w") != 0) -#else - depFileHandleRaw = fopen(QFile::encodeName(depOutputFileName).constData(), "w"); - if (!depFileHandleRaw) -#endif - { + File depFileHandle = openFileForWriting(depOutputFileName); + if (!depFileHandle) { const auto fopen_errno = errno; fprintf(stderr, "moc: Cannot create dep output file '%s'. Error: %s\n", QFile::encodeName(depOutputFileName).constData(), strerror(fopen_errno)); } - depFileHandle.reset(depFileHandleRaw); - if (!depFileHandle.isNull()) { + if (depFileHandle) { // First line is the path to the generated file. - fprintf(depFileHandle.data(), "%s: ", + fprintf(depFileHandle.get(), "%s: ", escapeAndEncodeDependencyPath(depRuleName).constData()); QByteArrayList dependencies; @@ -647,7 +638,7 @@ int runMoc(int argc, char **argv) // Join dependencies, output them, and output a final new line. const auto dependenciesJoined = dependencies.join(QByteArrayLiteral(" \\\n ")); - fprintf(depFileHandle.data(), "%s\n", dependenciesJoined.constData()); + fprintf(depFileHandle.get(), "%s\n", dependenciesJoined.constData()); } } diff --git a/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp b/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp index 579604286c..d637854d2b 100644 --- a/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp +++ b/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp @@ -276,7 +276,7 @@ QTextStream &QDBusXmlToCpp::writeHeader(QTextStream &ts, bool changesWillBeLost) { ts << "/*\n" " * This file was generated by " PROGRAMNAME " version " PROGRAMVERSION "\n" - " * Command line was: " << commandLine << "\n" + " * Source file was " << QFileInfo(inputFile).fileName() << "\n" " *\n" " * " PROGRAMNAME " is " PROGRAMCOPYRIGHT "\n" " *\n" diff --git a/src/tools/qlalr/cppgenerator.cpp b/src/tools/qlalr/cppgenerator.cpp index fd56de106d..f12917f0eb 100644 --- a/src/tools/qlalr/cppgenerator.cpp +++ b/src/tools/qlalr/cppgenerator.cpp @@ -1,5 +1,7 @@ +// REUSE-IgnoreStart // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// REUSE-IgnoreEnd #include "cppgenerator.h" @@ -39,7 +41,7 @@ void generateList(const QList<int> &list, QTextStream &out) } } - +// REUSE-IgnoreStart QString CppGenerator::copyrightHeader() const { return @@ -47,6 +49,7 @@ QString CppGenerator::copyrightHeader() const "// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0\n" "\n"_L1; } +// REUSE-IgnoreEnd QString CppGenerator::privateCopyrightHeader() const { diff --git a/src/tools/rcc/rcc.cpp b/src/tools/rcc/rcc.cpp index 444e9c4ae5..0fdba3671d 100644 --- a/src/tools/rcc/rcc.cpp +++ b/src/tools/rcc/rcc.cpp @@ -21,7 +21,7 @@ # include <zstd.h> #endif -// Note: A copy of this file is used in Qt Designer (qttools/src/designer/src/lib/shared/rcc.cpp) +// Note: A copy of this file is used in Qt Widgets Designer (qttools/src/designer/src/lib/shared/rcc.cpp) QT_BEGIN_NAMESPACE @@ -321,7 +321,7 @@ qint64 RCCFileInfo::writeDataBlob(RCCResourceLibrary &lib, qint64 offset, // some info if (text || pass1) { lib.writeString(" // "); - lib.writeByteArray(m_fileInfo.absoluteFilePath().toLocal8Bit()); + lib.writeByteArray(m_fileInfo.fileName().toLocal8Bit()); lib.writeString("\n "); } diff --git a/src/tools/rcc/rcc.h b/src/tools/rcc/rcc.h index 60af1c67cf..bfc3503da8 100644 --- a/src/tools/rcc/rcc.h +++ b/src/tools/rcc/rcc.h @@ -2,7 +2,7 @@ // Copyright (C) 2018 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -// Note: A copy of this file is used in Qt Designer (qttools/src/designer/src/lib/shared/rcc_p.h) +// Note: A copy of this file is used in Qt Widgets Designer (qttools/src/designer/src/lib/shared/rcc_p.h) #ifndef RCC_H #define RCC_H diff --git a/src/tools/uic/cpp/cppwriteinitialization.cpp b/src/tools/uic/cpp/cppwriteinitialization.cpp index 893cc5b8ec..c9356a4111 100644 --- a/src/tools/uic/cpp/cppwriteinitialization.cpp +++ b/src/tools/uic/cpp/cppwriteinitialization.cpp @@ -1393,8 +1393,8 @@ void WriteInitialization::writeProperties(const QString &varName, case DomProperty::CursorShape: if (p->hasAttributeStdset() && !p->attributeStdset()) varNewName += language::derefPointer + "viewport()"_L1; - propertyValue = "QCursor(Qt"_L1 + language::qualifier - + p->elementCursorShape() + u')'; + propertyValue = "QCursor(Qt"_L1 + language::qualifier + "CursorShape"_L1 + + language::qualifier + p->elementCursorShape() + u')'; break; case DomProperty::Enum: propertyValue = p->elementEnum(); @@ -1708,8 +1708,9 @@ static void writeIconAddFile(QTextStream &output, const QString &indent, { output << indent << iconName << ".addFile(" << language::qstring(fileName, indent) << ", QSize(), QIcon" - << language::qualifier << mode << ", QIcon" << language::qualifier - << state << ')' << language::eol; + << language::qualifier << "Mode" << language::qualifier << mode + << ", QIcon" << language::qualifier << "State" << language::qualifier << state + << ')' << language::eol; } // Post 4.4 write resource icon @@ -1757,7 +1758,8 @@ static void writeIconAddPixmap(QTextStream &output, const QString &indent, const char *mode, const char *state) { output << indent << iconName << ".addPixmap(" << call << ", QIcon" - << language::qualifier << mode << ", QIcon" << language::qualifier + << language::qualifier << "Mode" << language::qualifier << mode + << ", QIcon" << language::qualifier << "State" << language::qualifier << state << ')' << language::eol; } @@ -2153,7 +2155,7 @@ QString WriteInitialization::pixCall(const DomProperty *p) const s = p->elementPixmap()->text(); break; default: - qWarning("%s: Warning: Unknown icon format encountered. The ui-file was generated with a too-recent version of Designer.", + qWarning("%s: Warning: Unknown icon format encountered. The ui-file was generated with a too-recent version of Qt Widgets Designer.", qPrintable(m_option.messagePrefix())); return "QIcon()"_L1; break; diff --git a/src/tools/uic/python/pythonwriteimports.cpp b/src/tools/uic/python/pythonwriteimports.cpp index b122c0f895..74eeab8387 100644 --- a/src/tools/uic/python/pythonwriteimports.cpp +++ b/src/tools/uic/python/pythonwriteimports.cpp @@ -229,9 +229,13 @@ void WriteImports::addPythonCustomWidget(const QString &className, const DomCust QString modulePath = node->elementHeader()->text(); // Replace the '/' by '.' modulePath.replace(u'/', u'.'); - // '.h' is added by default on headers for <customwidget> - if (modulePath.endsWith(".h"_L1)) + // '.h' is added by default on headers for <customwidget>. + if (modulePath.endsWith(".h"_L1, Qt::CaseInsensitive)) modulePath.chop(2); + else if (modulePath.endsWith(".hh"_L1)) + modulePath.chop(3); + else if (modulePath.endsWith(".hpp"_L1)) + modulePath.chop(4); insertClass(modulePath, className, &m_customWidgets); } } diff --git a/src/tools/uic/uic.cpp b/src/tools/uic/uic.cpp index fb0a37d21d..1b10e1d722 100644 --- a/src/tools/uic/uic.cpp +++ b/src/tools/uic/uic.cpp @@ -165,7 +165,7 @@ DomUI *Uic::parseUiFile(QXmlStreamReader &reader) && !ui) { const double version = versionFromUiAttribute(reader); if (version < 4.0) { - const QString msg = QString::fromLatin1("uic: File generated with too old version of Qt Designer (%1)").arg(version); + const QString msg = QString::fromLatin1("uic: File generated with too old version of Qt Widgets Designer (%1)").arg(version); fprintf(stderr, "%s\n", qPrintable(msg)); return nullptr; } @@ -202,7 +202,7 @@ bool Uic::write(QIODevice *in) double version = ui->attributeVersion().toDouble(); if (version < 4.0) { - fprintf(stderr, "uic: File generated with too old version of Qt Designer\n"); + fprintf(stderr, "uic: File generated with too old version of Qt Widgets Designer\n"); return false; } diff --git a/src/tools/windeployqt/main.cpp b/src/tools/windeployqt/main.cpp index 837d4c7bbc..dca9132e15 100644 --- a/src/tools/windeployqt/main.cpp +++ b/src/tools/windeployqt/main.cpp @@ -137,7 +137,12 @@ static Platform platformFromMkSpec(const QString &xSpec) return WindowsDesktopClangMinGW; if (xSpec.contains("clang-msvc++"_L1)) return WindowsDesktopClangMsvc; - return xSpec.contains("g++"_L1) ? WindowsDesktopMinGW : WindowsDesktopMsvc; + if (xSpec.contains("arm"_L1)) + return WindowsDesktopMsvcArm; + if (xSpec.contains("G++"_L1)) + return WindowsDesktopMinGW; + + return WindowsDesktopMsvc; } return UnknownPlatform; } @@ -183,7 +188,7 @@ struct Options { bool softwareRasterizer = true; bool ffmpeg = true; PluginSelections pluginSelections; - Platform platform = WindowsDesktopMsvc; + Platform platform = WindowsDesktopMsvcIntel; ModuleBitset additionalLibraries; ModuleBitset disabledLibraries; unsigned updateFileFlags = 0; @@ -563,13 +568,14 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse options->quickImports = !parser->isSet(noQuickImportOption); // default to deployment of compiler runtime for windows desktop configurations - if (options->platform == WindowsDesktopMinGW || options->platform == WindowsDesktopMsvc + if (options->platform == WindowsDesktopMinGW || options->platform.testFlags(WindowsDesktopMsvc) || parser->isSet(compilerRunTimeOption)) options->compilerRunTime = true; if (parser->isSet(noCompilerRunTimeOption)) options->compilerRunTime = false; - if (options->compilerRunTime && options->platform != WindowsDesktopMinGW && options->platform != WindowsDesktopMsvc) { + if (options->compilerRunTime && options->platform != WindowsDesktopMinGW + && !options->platform.testFlags(WindowsDesktopMsvc)) { *errorMessage = QStringLiteral("Deployment of the compiler runtime is implemented for Desktop MSVC/g++ only."); return CommandLineParseError; } @@ -1363,7 +1369,8 @@ static QStringList compilerRunTimeLibs(const QString &qtBinDir, Platform platfor break; } #ifdef Q_OS_WIN - case WindowsDesktopMsvc: { // MSVC/Desktop: Add redistributable packages. + case WindowsDesktopMsvcIntel: + case WindowsDesktopMsvcArm: { // MSVC/Desktop: Add redistributable packages. QString vcRedistDirName = vcRedistDir(); if (vcRedistDirName.isEmpty()) break; @@ -1923,6 +1930,24 @@ int main(int argc, char **argv) } options.platform = platformFromMkSpec(xSpec); + // We are on MSVC and not crosscompiling. We need the host arch + if (options.platform == WindowsDesktopMsvc) { + SYSTEM_INFO si; + GetSystemInfo(&si); + switch (si.wProcessorArchitecture) { + case PROCESSOR_ARCHITECTURE_INTEL: + case PROCESSOR_ARCHITECTURE_IA64: + case PROCESSOR_ARCHITECTURE_AMD64: + options.platform |= IntelBased; + break; + case PROCESSOR_ARCHITECTURE_ARM: + case PROCESSOR_ARCHITECTURE_ARM64: + options.platform |= ArmBased; + break; + default: + options.platform = UnknownPlatform; + } + } if (options.platform == UnknownPlatform) { std::wcerr << "Unsupported platform " << xSpec << '\n'; return 1; diff --git a/src/tools/windeployqt/utils.h b/src/tools/windeployqt/utils.h index 2c7cd79bf0..fb3ba0b40b 100644 --- a/src/tools/windeployqt/utils.h +++ b/src/tools/windeployqt/utils.h @@ -29,7 +29,9 @@ enum PlatformFlag { ClangMsvc = 0x00400, ClangMinGW = 0x00800, // Platforms - WindowsDesktopMsvc = WindowsBased + IntelBased + Msvc, + WindowsDesktopMsvc = WindowsBased + Msvc, + WindowsDesktopMsvcIntel = WindowsDesktopMsvc + IntelBased, + WindowsDesktopMsvcArm = WindowsDesktopMsvc + ArmBased, WindowsDesktopMinGW = WindowsBased + IntelBased + MinGW, WindowsDesktopClangMsvc = WindowsBased + IntelBased + ClangMsvc, WindowsDesktopClangMinGW = WindowsBased + IntelBased + ClangMinGW, |