summaryrefslogtreecommitdiffstats
path: root/src/tools
diff options
context:
space:
mode:
authorAlexandru Croitor <alexandru.croitor@qt.io>2019-09-04 14:33:40 +0200
committerAlexandru Croitor <alexandru.croitor@qt.io>2019-09-04 14:33:40 +0200
commitf255b1e8e297e7e1363921580007145cff574e0d (patch)
tree9a799be282e6c0d6544d9f8c872073f83e6c0475 /src/tools
parent7e8705f6632428a8d9a937ab5fe087999347b3dd (diff)
parentbf8fcab8bb92ff534c5cec048d6dbebb3b73a348 (diff)
Merge remote-tracking branch 'origin/dev' into wip/qt6
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/androiddeployqt/main.cpp1143
-rw-r--r--src/tools/androidtestrunner/main.cpp4
-rw-r--r--src/tools/bootstrap/bootstrap.pro3
-rw-r--r--src/tools/qlalr/lalr.cpp10
4 files changed, 576 insertions, 584 deletions
diff --git a/src/tools/androiddeployqt/main.cpp b/src/tools/androiddeployqt/main.cpp
index 10bbd59bfb..6cc9f6102c 100644
--- a/src/tools/androiddeployqt/main.cpp
+++ b/src/tools/androiddeployqt/main.cpp
@@ -91,7 +91,7 @@ FILE *openProcess(const QString &command)
#if defined(Q_OS_WIN32)
QString processedCommand = QLatin1Char('\"') + command + QLatin1Char('\"');
#else
- QString processedCommand = command;
+ const QString& processedCommand = command;
#endif
return popen(processedCommand.toLocal8Bit().constData(), QT_POPEN_READ);
@@ -99,7 +99,7 @@ FILE *openProcess(const QString &command)
struct QtDependency
{
- QtDependency(QString rpath, QString apath) : relativePath(rpath), absolutePath(apath) {}
+ QtDependency(const QString &rpath, const QString &apath) : relativePath(rpath), absolutePath(apath) {}
bool operator==(const QtDependency &other) const
{
@@ -121,15 +121,15 @@ struct Options
, auxMode(false)
, deploymentMechanism(Bundled)
, releasePackage(false)
- , digestAlg(QLatin1String("SHA1"))
- , sigAlg(QLatin1String("SHA1withRSA"))
+ , digestAlg(QLatin1String("SHA-256"))
+ , sigAlg(QLatin1String("SHA256withRSA"))
, internalSf(false)
, sectionsOnly(false)
, protectedAuthenticationPath(false)
, jarSigner(false)
- , gdbServer(Auto)
, installApk(false)
, uninstallApk(false)
+ , qmlImportScannerBinaryPath()
{}
enum DeploymentMechanism
@@ -150,7 +150,6 @@ struct Options
bool generateAssetsFileList;
bool build;
bool auxMode;
- bool stripLibraries = true;
ActionTimer timer;
// External tools
@@ -175,22 +174,24 @@ struct Options
// lib c++ path
QString stdCppPath;
- QString stdCppName = QStringLiteral("gnustl_shared");
+ QString stdCppName = QStringLiteral("c++_shared");
// Build information
QString androidPlatform;
- QString architecture;
- QString toolchainVersion;
+ QHash<QString, QString> architectures;
+ QString currentArchitecture;
QString toolchainPrefix;
- QString toolPrefix;
- bool useLLVM = false;
QString ndkHost;
+ bool buildAAB = false;
+
// Package information
DeploymentMechanism deploymentMechanism;
QString packageName;
QStringList extraLibs;
+ QHash<QString, QStringList> archExtraLibs;
QStringList extraPlugins;
+ QHash<QString, QStringList> archExtraPlugins;
// Signing information
bool releasePackage;
@@ -211,23 +212,37 @@ struct Options
bool jarSigner;
QString apkPath;
- // Gdbserver
- TriState gdbServer;
-
// Installation information
bool installApk;
bool uninstallApk;
QString installLocation;
- // Collected information
+ // Per architecture collected information
+ void clear(const QString &arch)
+ {
+ currentArchitecture = arch;
+ }
typedef QPair<QString, QString> BundledFile;
- QList<BundledFile> bundledFiles;
- QList<QtDependency> qtDependencies;
- QStringList localLibs;
+ QHash<QString, QList<BundledFile>> bundledFiles;
+ QHash<QString, QList<QtDependency>> qtDependencies;
+ QHash<QString, QStringList> localLibs;
+ bool usesOpenGL = false;
+
+ // Per package collected information
QStringList localJars;
QStringList initClasses;
QStringList permissions;
QStringList features;
+
+ // Override qml import scanner path
+ QString qmlImportScannerBinaryPath;
+};
+
+static const QHash<QByteArray, QByteArray> elfArchitecures = {
+ {"aarch64", "arm64-v8a"},
+ {"arm", "armeabi-v7a"},
+ {"i386", "x86"},
+ {"x86_64", "x86_64"}
};
// Copy-pasted from qmake/library/ioutil.cpp
@@ -250,7 +265,7 @@ static QString shellQuoteUnix(const QString &arg)
}; // 0-32 \'"$`<>|;&(){}*?#!~[]
if (!arg.length())
- return QString::fromLatin1("\"\"");
+ return QLatin1String("\"\"");
QString ret(arg);
if (hasSpecialChars(ret, iqm)) {
@@ -273,7 +288,7 @@ static QString shellQuoteWin(const QString &arg)
};
if (!arg.length())
- return QString::fromLatin1("\"\"");
+ return QLatin1String("\"\"");
QString ret(arg);
if (hasSpecialChars(ret, iqm)) {
@@ -301,6 +316,59 @@ static QString shellQuote(const QString &arg)
return shellQuoteUnix(arg);
}
+QString architecureFromName(const QString &name)
+{
+ QRegExp architecture(QStringLiteral(".*_(.*)\\.so"));
+ if (!architecture.exactMatch(name))
+ return {};
+ return architecture.capturedTexts().last();
+}
+
+QString fileArchitecture(const Options &options, const QString &path)
+{
+ auto arch = architecureFromName(path);
+ if (!arch.isEmpty())
+ return arch;
+
+ QString readElf = QLatin1String("%1/toolchains/%2/prebuilt/%3/bin/llvm-readobj").arg(options.ndkPath,
+ options.toolchainPrefix,
+ options.ndkHost);
+#if defined(Q_OS_WIN32)
+ readElf += QLatin1String(".exe");
+#endif
+
+ if (!QFile::exists(readElf)) {
+ fprintf(stderr, "Command does not exist: %s\n", qPrintable(readElf));
+ return {};
+ }
+
+ readElf = QLatin1String("%1 -needed-libs %2").arg(shellQuote(readElf), shellQuote(path));
+
+ FILE *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) {
+ QByteArray line = QByteArray::fromRawData(buffer, qstrlen(buffer));
+ QString library;
+ line = line.trimmed();
+ if (line.startsWith("Arch: ")) {
+ auto it = elfArchitecures.find(line.mid(6));
+ pclose(readElfCommand);
+ return it != elfArchitecures.constEnd() ? QString::fromLatin1(it.value()) : QString{};
+ }
+ }
+ pclose(readElfCommand);
+ return {};
+}
+
+bool checkArchitecture(const Options &options, const QString &fileName)
+{
+ return fileArchitecture(options, fileName) == options.currentArchitecture;
+}
void deleteMissingFiles(const Options &options, const QDir &srcDir, const QDir &dstDir)
{
@@ -350,7 +418,10 @@ Options parseOptions()
options.helpRequested = true;
else
options.inputFileName = arguments.at(++i);
- } else if (argument.compare(QLatin1String("--no-build"), Qt::CaseInsensitive) == 0) {
+ } else if (argument.compare(QLatin1String("--aab"), Qt::CaseInsensitive) == 0) {
+ options.buildAAB = true;
+ options.build = true;
+ } else if (options.buildAAB && argument.compare(QLatin1String("--no-build"), Qt::CaseInsensitive) == 0) {
options.build = false;
} else if (argument.compare(QLatin1String("--install"), Qt::CaseInsensitive) == 0) {
options.installApk = true;
@@ -388,10 +459,6 @@ Options parseOptions()
options.installLocation = arguments.at(++i);
} else if (argument.compare(QLatin1String("--release"), Qt::CaseInsensitive) == 0) {
options.releasePackage = true;
- } else if (argument.compare(QLatin1String("--gdbserver"), Qt::CaseInsensitive) == 0) {
- options.gdbServer = Options::True;
- } else if (argument.compare(QLatin1String("--no-gdbserver"), Qt::CaseInsensitive) == 0) {
- options.gdbServer = Options::False;
} else if (argument.compare(QLatin1String("--jdk"), Qt::CaseInsensitive) == 0) {
if (i + 1 == arguments.size())
options.helpRequested = true;
@@ -462,13 +529,13 @@ Options parseOptions()
options.generateAssetsFileList = false;
} else if (argument.compare(QLatin1String("--aux-mode"), Qt::CaseInsensitive) == 0) {
options.auxMode = true;
- } else if (argument.compare(QLatin1String("--no-strip"), Qt::CaseInsensitive) == 0) {
- options.stripLibraries = false;
+ } else if (argument.compare(QLatin1String("--qml-importscanner-binary"), Qt::CaseInsensitive) == 0) {
+ options.qmlImportScannerBinaryPath = arguments.at(++i).trimmed();
}
}
if (options.inputFileName.isEmpty())
- options.inputFileName = QString::fromLatin1("android-lib%1.so-deployment-settings.json").arg(QDir::current().dirName());
+ options.inputFileName = QLatin1String("android-lib%1.so-deployment-settings.json").arg(QDir::current().dirName());
options.timing = qEnvironmentVariableIsSet("ANDROIDDEPLOYQT_TIMING_OUTPUT");
@@ -497,6 +564,7 @@ void printHelp()
" --deployment <mechanism>: Supported deployment mechanisms:\n"
" bundled (default): Include Qt files in stand-alone package.\n"
" ministro: Use the Ministro service to manage Qt files.\n"
+ " --aab: Build an Android App Bundle.\n"
" --no-build: Do not build the package, it is useful to just install\n"
" a package previously built.\n"
" --install: Installs apk to device/emulator. By default this step is\n"
@@ -533,10 +601,6 @@ void printHelp()
" --protected: Keystore has protected authentication path.\n"
" --jarsigner: Force jarsigner usage, otherwise apksigner will be\n"
" used if available.\n"
- " --gdbserver: Adds the gdbserver to the package. By default the gdbserver\n"
- " is bundled for debug pacakges.\n"
- " --no-gdbserver: Prevents the gdbserver from being added to the package\n"
- " By default the gdbserver is bundled for debug pacakges.\n"
" --jdk <path/to/jdk>: Used to find the jarsigner tool when used\n"
" in combination with the --release argument. By default,\n"
" an attempt is made to detect the tool using the JAVA_HOME and\n"
@@ -549,8 +613,11 @@ void printHelp()
" --aux-mode: Operate in auxiliary mode. This will only copy the\n"
" dependencies into the build directory and update the XML templates.\n"
" The project will not be built or installed.\n"
- " --no-strip: Do not strip debug symbols from libraries.\n"
" --apk <path/where/to/copy/the/apk>: Path where to copy the built apk.\n"
+ " --qml-importscanner-binary <path/to/qmlimportscanner>: Override the\n"
+ " default qmlimportscanner binary path. By default the\n"
+ " qmlimportscanner binary is located using the Qt directory\n"
+ " specified in the input file.\n"
" --help: Displays this information.\n\n",
qPrintable(QCoreApplication::arguments().at(0))
);
@@ -580,9 +647,10 @@ bool alwaysOverwritableFile(const QString &fileName)
|| fileName.endsWith(QLatin1String("/src/org/qtproject/qt5/android/bindings/QtActivity.java")));
}
+
bool copyFileIfNewer(const QString &sourceFileName,
const QString &destinationFileName,
- bool verbose,
+ const Options &options,
bool forceOverwrite = false)
{
if (QFile::exists(destinationFileName)) {
@@ -592,7 +660,7 @@ bool copyFileIfNewer(const QString &sourceFileName,
if (!forceOverwrite
&& sourceFileInfo.lastModified() <= destinationFileInfo.lastModified()
&& !alwaysOverwritableFile(destinationFileName)) {
- if (verbose)
+ if (options.verbose)
fprintf(stdout, " -- Skipping file %s. Same or newer file already in place.\n", qPrintable(sourceFileName));
return true;
} else {
@@ -611,11 +679,10 @@ bool copyFileIfNewer(const QString &sourceFileName,
if (!QFile::exists(destinationFileName) && !QFile::copy(sourceFileName, destinationFileName)) {
fprintf(stderr, "Failed to copy %s to %s.\n", qPrintable(sourceFileName), qPrintable(destinationFileName));
return false;
- } else if (verbose) {
+ } else if (options.verbose) {
fprintf(stdout, " -- Copied %s\n", qPrintable(destinationFileName));
fflush(stdout);
}
-
return true;
}
@@ -708,7 +775,7 @@ QString packageNameFromAndroidManifest(const QString &androidManifestPath)
reader.attributes().value(QLatin1String("package")).toString());
}
}
- return QString();
+ return {};
}
bool readInputFile(Options *options)
@@ -750,13 +817,13 @@ bool readInputFile(Options *options)
{
- const QJsonValue value = jsonObject.value(QStringLiteral("sdkBuildToolsRevision"));
+ const QJsonValue value = jsonObject.value(QLatin1String("sdkBuildToolsRevision"));
if (!value.isUndefined())
options->sdkBuildToolsVersion = value.toString();
}
{
- const QJsonValue qtInstallDirectory = jsonObject.value(QStringLiteral("qt"));
+ const QJsonValue qtInstallDirectory = jsonObject.value(QLatin1String("qt"));
if (qtInstallDirectory.isUndefined()) {
fprintf(stderr, "No Qt directory in json file %s\n", qPrintable(options->inputFileName));
return false;
@@ -773,13 +840,13 @@ bool readInputFile(Options *options)
}
{
- const QJsonValue androidSourcesDirectory = jsonObject.value(QStringLiteral("android-package-source-directory"));
+ const QJsonValue androidSourcesDirectory = jsonObject.value(QLatin1String("android-package-source-directory"));
if (!androidSourcesDirectory.isUndefined())
options->androidSourceDirectory = androidSourcesDirectory.toString();
}
{
- const QJsonValue androidVersionName = jsonObject.value(QStringLiteral("android-version-name"));
+ const QJsonValue androidVersionName = jsonObject.value(QLatin1String("android-version-name"));
if (!androidVersionName.isUndefined())
options->versionName = androidVersionName.toString();
else
@@ -787,7 +854,7 @@ bool readInputFile(Options *options)
}
{
- const QJsonValue androidVersionCode = jsonObject.value(QStringLiteral("android-version-code"));
+ const QJsonValue androidVersionCode = jsonObject.value(QLatin1String("android-version-code"));
if (!androidVersionCode.isUndefined())
options->versionCode = androidVersionCode.toString();
else
@@ -795,55 +862,24 @@ bool readInputFile(Options *options)
}
{
- const QJsonValue applicationBinary = jsonObject.value(QStringLiteral("application-binary"));
- if (applicationBinary.isUndefined()) {
- fprintf(stderr, "No application binary defined in json file.\n");
- return false;
- }
- options->applicationBinary = applicationBinary.toString();
-
- if (!QFile::exists(options->applicationBinary)) {
- fprintf(stderr, "Cannot find application binary %s.\n", qPrintable(options->applicationBinary));
+ const QJsonObject targetArchitectures = jsonObject.value(QLatin1String("architectures")).toObject();
+ if (targetArchitectures.isEmpty()) {
+ fprintf(stderr, "No target architecture defined in json file.\n");
return false;
}
- }
-
- {
- const QJsonValue deploymentDependencies = jsonObject.value(QStringLiteral("deployment-dependencies"));
- if (!deploymentDependencies.isUndefined()) {
- QString deploymentDependenciesString = deploymentDependencies.toString();
- const auto dependencies = deploymentDependenciesString.splitRef(QLatin1Char(','));
- for (const QStringRef &dependency : dependencies) {
- QString path = options->qtInstallDirectory + QLatin1Char('/') + dependency;
- if (QFileInfo(path).isDir()) {
- QDirIterator iterator(path, QDirIterator::Subdirectories);
- while (iterator.hasNext()) {
- iterator.next();
- if (iterator.fileInfo().isFile()) {
- QString subPath = iterator.filePath();
- options->qtDependencies.append(QtDependency(subPath.mid(options->qtInstallDirectory.length() + 1),
- subPath));
- }
- }
- } else {
- options->qtDependencies.append(QtDependency(dependency.toString(), path));
- }
+ for (auto it = targetArchitectures.constBegin(); it != targetArchitectures.constEnd(); ++it) {
+ if (it.value().isUndefined()) {
+ fprintf(stderr, "Invalid architecure.\n");
+ return false;
}
+ if (it.value().isNull())
+ continue;
+ options->architectures.insert(it.key(), it.value().toString());
}
}
-
- {
- const QJsonValue targetArchitecture = jsonObject.value(QStringLiteral("target-architecture"));
- if (targetArchitecture.isUndefined()) {
- fprintf(stderr, "No target architecture defined in json file.\n");
- return false;
- }
- options->architecture = targetArchitecture.toString();
- }
-
{
- const QJsonValue ndk = jsonObject.value(QStringLiteral("ndk"));
+ const QJsonValue ndk = jsonObject.value(QLatin1String("ndk"));
if (ndk.isUndefined()) {
fprintf(stderr, "No NDK path defined in json file.\n");
return false;
@@ -852,12 +888,7 @@ bool readInputFile(Options *options)
}
{
- const QJsonValue value = jsonObject.value(QStringLiteral("useLLVM"));
- options->useLLVM = value.toBool(false);
- }
-
- {
- const QJsonValue toolchainPrefix = jsonObject.value(QStringLiteral("toolchain-prefix"));
+ const QJsonValue toolchainPrefix = jsonObject.value(QLatin1String("toolchain-prefix"));
if (toolchainPrefix.isUndefined()) {
fprintf(stderr, "No toolchain prefix defined in json file.\n");
return false;
@@ -866,26 +897,7 @@ bool readInputFile(Options *options)
}
{
- const QJsonValue toolPrefix = jsonObject.value(QStringLiteral("tool-prefix"));
- if (toolPrefix.isUndefined()) {
- fprintf(stderr, "Warning: No tool prefix defined in json file.\n");
- options->toolPrefix = options->toolchainPrefix;
- } else {
- options->toolPrefix = toolPrefix.toString();
- }
- }
-
- if (!options->useLLVM) {
- const QJsonValue toolchainVersion = jsonObject.value(QStringLiteral("toolchain-version"));
- if (toolchainVersion.isUndefined()) {
- fprintf(stderr, "No toolchain version defined in json file.\n");
- return false;
- }
- options->toolchainVersion = toolchainVersion.toString();
- }
-
- {
- const QJsonValue ndkHost = jsonObject.value(QStringLiteral("ndk-host"));
+ const QJsonValue ndkHost = jsonObject.value(QLatin1String("ndk-host"));
if (ndkHost.isUndefined()) {
fprintf(stderr, "No NDK host defined in json file.\n");
return false;
@@ -893,52 +905,106 @@ bool readInputFile(Options *options)
options->ndkHost = ndkHost.toString();
}
- options->packageName = packageNameFromAndroidManifest(options->androidSourceDirectory + QLatin1String("/AndroidManifest.xml"));
- if (options->packageName.isEmpty())
- options->packageName = cleanPackageName(QString::fromLatin1("org.qtproject.example.%1").arg(QFileInfo(options->applicationBinary).baseName().mid(sizeof("lib") - 1)));
-
{
- const QJsonValue extraLibs = jsonObject.value(QStringLiteral("android-extra-libs"));
+ const QJsonValue extraLibs = jsonObject.value(QLatin1String("android-extra-libs"));
if (!extraLibs.isUndefined())
options->extraLibs = extraLibs.toString().split(QLatin1Char(','), QString::SkipEmptyParts);
}
{
- const QJsonValue extraPlugins = jsonObject.value(QStringLiteral("android-extra-plugins"));
+ const QJsonValue extraPlugins = jsonObject.value(QLatin1String("android-extra-plugins"));
if (!extraPlugins.isUndefined())
options->extraPlugins = extraPlugins.toString().split(QLatin1Char(','));
}
{
- const QJsonValue stdcppPath = jsonObject.value(QStringLiteral("stdcpp-path"));
+ const QJsonValue stdcppPath = jsonObject.value(QLatin1String("stdcpp-path"));
if (stdcppPath.isUndefined()) {
fprintf(stderr, "No stdcpp-path defined in json file.\n");
return false;
}
options->stdCppPath = stdcppPath.toString();
- auto name = QFileInfo(options->stdCppPath).baseName();
- if (!name.startsWith(QLatin1String("lib"))) {
- fprintf(stderr, "Invalid STD C++ library name.\n");
- return false;
- }
- options->stdCppName = name.mid(3);
}
{
- const QJsonValue qmlRootPath = jsonObject.value(QStringLiteral("qml-root-path"));
+ const QJsonValue qmlRootPath = jsonObject.value(QLatin1String("qml-root-path"));
if (!qmlRootPath.isUndefined())
options->rootPath = qmlRootPath.toString();
}
{
- const QJsonValue qmlImportPaths = jsonObject.value(QStringLiteral("qml-import-paths"));
+ const QJsonValue qmlImportPaths = jsonObject.value(QLatin1String("qml-import-paths"));
if (!qmlImportPaths.isUndefined())
options->qmlImportPaths = qmlImportPaths.toString().split(QLatin1Char(','));
}
+
+ {
+ const QJsonValue qmlImportScannerBinaryPath = jsonObject.value(QLatin1String("qml-importscanner-binary"));
+ if (!qmlImportScannerBinaryPath.isUndefined())
+ options->qmlImportScannerBinaryPath = qmlImportScannerBinaryPath.toString();
+ }
+
+ {
+ const QJsonValue applicationBinary = jsonObject.value(QLatin1String("application-binary"));
+ if (applicationBinary.isUndefined()) {
+ fprintf(stderr, "No application binary defined in json file.\n");
+ return false;
+ }
+ options->applicationBinary = applicationBinary.toString();
+ if (options->build) {
+ for (auto it = options->architectures.constBegin(); it != options->architectures.constEnd(); ++it) {
+ if (!QFile::exists(QLatin1String("%1/libs/%2/lib%3_%2.so").arg(options->outputDirectory, it.key(), options->applicationBinary))) {
+ fprintf(stderr, "Cannot find application binary %s.\n", qPrintable(options->applicationBinary));
+ return false;
+ }
+ }
+ }
+ }
+
+ {
+ const QJsonValue deploymentDependencies = jsonObject.value(QLatin1String("deployment-dependencies"));
+ if (!deploymentDependencies.isUndefined()) {
+ QString deploymentDependenciesString = deploymentDependencies.toString();
+ const auto dependencies = deploymentDependenciesString.splitRef(QLatin1Char(','));
+ for (const QStringRef &dependency : dependencies) {
+ QString path = options->qtInstallDirectory + QLatin1Char('/') + dependency;
+ if (QFileInfo(path).isDir()) {
+ QDirIterator iterator(path, QDirIterator::Subdirectories);
+ while (iterator.hasNext()) {
+ iterator.next();
+ if (iterator.fileInfo().isFile()) {
+ QString subPath = iterator.filePath();
+ auto arch = fileArchitecture(*options, subPath);
+ if (!arch.isEmpty()) {
+ options->qtDependencies[arch].append(QtDependency(subPath.mid(options->qtInstallDirectory.length() + 1),
+ subPath));
+ } else if (options->verbose) {
+ fprintf(stderr, "Skipping \"%s\", unknown architecture\n", qPrintable(subPath));
+ fflush(stderr);
+ }
+ }
+ }
+ } else {
+ auto arch = fileArchitecture(*options, path);
+ if (!arch.isEmpty()) {
+ options->qtDependencies[arch].append(QtDependency(dependency.toString(), path));
+ } else if (options->verbose) {
+ fprintf(stderr, "Skipping \"%s\", unknown architecture\n", qPrintable(path));
+ fflush(stderr);
+ }
+ }
+ }
+ }
+ }
+
+ options->packageName = packageNameFromAndroidManifest(options->androidSourceDirectory + QLatin1String("/AndroidManifest.xml"));
+ if (options->packageName.isEmpty())
+ options->packageName = cleanPackageName(QLatin1String("org.qtproject.example.%1").arg(options->applicationBinary));
+
return true;
}
-bool copyFiles(const QDir &sourceDirectory, const QDir &destinationDirectory, bool verbose, bool forceOverwrite = false)
+bool copyFiles(const QDir &sourceDirectory, const QDir &destinationDirectory, const Options &options, bool forceOverwrite = false)
{
const QFileInfoList entries = sourceDirectory.entryInfoList(QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs);
for (const QFileInfo &entry : entries) {
@@ -949,11 +1015,11 @@ bool copyFiles(const QDir &sourceDirectory, const QDir &destinationDirectory, bo
return false;
}
- if (!copyFiles(dir, QDir(destinationDirectory.path() + QLatin1String("/") + dir.dirName()), verbose, forceOverwrite))
+ if (!copyFiles(dir, QDir(destinationDirectory.path() + QLatin1Char('/') + dir.dirName()), options, forceOverwrite))
return false;
} else {
QString destination = destinationDirectory.absoluteFilePath(entry.fileName());
- if (!copyFileIfNewer(entry.absoluteFilePath(), destination, verbose, forceOverwrite))
+ if (!copyFileIfNewer(entry.absoluteFilePath(), destination, options, forceOverwrite))
return false;
}
}
@@ -993,7 +1059,7 @@ bool copyAndroidTemplate(const Options &options, const QString &androidTemplate,
return false;
}
- return copyFiles(sourceDirectory, QDir(outDir), options.verbose);
+ return copyFiles(sourceDirectory, QDir(outDir), options);
}
bool copyGradleTemplate(const Options &options)
@@ -1010,7 +1076,7 @@ bool copyGradleTemplate(const Options &options)
return false;
}
- return copyFiles(sourceDirectory, QDir(outDir), options.verbose);
+ return copyFiles(sourceDirectory, QDir(outDir), options);
}
bool copyAndroidTemplate(const Options &options)
@@ -1041,38 +1107,42 @@ bool copyAndroidSources(const Options &options)
return false;
}
- return copyFiles(sourceDirectory, QDir(options.outputDirectory), options.verbose, true);
+ return copyFiles(sourceDirectory, QDir(options.outputDirectory), options, true);
}
-bool copyAndroidExtraLibs(const Options &options)
+bool copyAndroidExtraLibs(Options *options)
{
- if (options.extraLibs.isEmpty())
+ if (options->extraLibs.isEmpty())
return true;
- if (options.verbose)
- fprintf(stdout, "Copying %d external libraries to package.\n", options.extraLibs.size());
+ if (options->verbose)
+ fprintf(stdout, "Copying %d external libraries to package.\n", options->extraLibs.size());
- for (const QString &extraLib : options.extraLibs) {
+ for (const QString &extraLib : options->extraLibs) {
QFileInfo extraLibInfo(extraLib);
if (!extraLibInfo.exists()) {
fprintf(stderr, "External library %s does not exist!\n", qPrintable(extraLib));
return false;
}
-
+ if (!checkArchitecture(*options, extraLibInfo.filePath())) {
+ if (options->verbose)
+ fprintf(stdout, "Skipping \"%s\", architecture mismatch.\n", qPrintable(extraLib));
+ continue;
+ }
if (!extraLibInfo.fileName().startsWith(QLatin1String("lib")) || extraLibInfo.suffix() != QLatin1String("so")) {
fprintf(stderr, "The file name of external library %s must begin with \"lib\" and end with the suffix \".so\".\n",
qPrintable(extraLib));
return false;
}
-
- QString destinationFile(options.outputDirectory
+ QString destinationFile(options->outputDirectory
+ QLatin1String("/libs/")
- + options.architecture
+ + options->currentArchitecture
+ QLatin1Char('/')
+ extraLibInfo.fileName());
- if (!copyFileIfNewer(extraLib, destinationFile, options.verbose))
+ if (!copyFileIfNewer(extraLib, destinationFile, *options))
return false;
+ options->archExtraLibs[options->currentArchitecture] += extraLib;
}
return true;
@@ -1093,15 +1163,15 @@ QStringList allFilesInside(const QDir& current, const QDir& rootDir)
return result;
}
-bool copyAndroidExtraResources(const Options &options)
+bool copyAndroidExtraResources(Options *options)
{
- if (options.extraPlugins.isEmpty())
+ if (options->extraPlugins.isEmpty())
return true;
- if (options.verbose)
- fprintf(stdout, "Copying %d external resources to package.\n", options.extraPlugins.size());
+ if (options->verbose)
+ fprintf(stdout, "Copying %d external resources to package.\n", options->extraPlugins.size());
- for (const QString &extraResource : options.extraPlugins) {
+ for (const QString &extraResource : options->extraPlugins) {
QFileInfo extraResourceInfo(extraResource);
if (!extraResourceInfo.exists() || !extraResourceInfo.isDir()) {
fprintf(stderr, "External resource %s does not exist or not a correct directory!\n", qPrintable(extraResource));
@@ -1109,8 +1179,8 @@ bool copyAndroidExtraResources(const Options &options)
}
QDir resourceDir(extraResource);
- QString assetsDir = options.outputDirectory + QStringLiteral("/assets/") + resourceDir.dirName() + QLatin1Char('/');
- QString libsDir = options.outputDirectory + QStringLiteral("/libs/") + options.architecture + QLatin1Char('/');
+ QString assetsDir = options->outputDirectory + QLatin1String("/assets/") + resourceDir.dirName() + QLatin1Char('/');
+ QString libsDir = options->outputDirectory + QLatin1String("/libs/") + options->currentArchitecture + QLatin1Char('/');
const QStringList files = allFilesInside(resourceDir, resourceDir);
for (const QString &resourceFile : files) {
@@ -1119,10 +1189,12 @@ bool copyAndroidExtraResources(const Options &options)
if (!resourceFile.endsWith(QLatin1String(".so"))) {
destinationFile = assetsDir + resourceFile;
} else {
- destinationFile = libsDir + QStringLiteral("/lib") + QString(resourceDir.dirName() + QLatin1Char('/') + resourceFile).replace(QLatin1Char('/'), QLatin1Char('_'));
+ if (!checkArchitecture(*options, originFile))
+ continue;
+ destinationFile = libsDir + QLatin1String("/lib") + QString(resourceDir.dirName() + QLatin1Char('/') + resourceFile).replace(QLatin1Char('/'), QLatin1Char('_'));
+ options->archExtraPlugins[options->currentArchitecture] += resourceFile;
}
-
- if (!copyFileIfNewer(originFile, destinationFile, options.verbose))
+ if (!copyFileIfNewer(originFile, destinationFile, *options))
return false;
}
}
@@ -1174,75 +1246,118 @@ bool updateFile(const QString &fileName, const QHash<QString, QString> &replacem
}
-bool updateLibsXml(const Options &options)
+bool updateLibsXml(Options *options)
{
- if (options.verbose)
+ if (options->verbose)
fprintf(stdout, " -- res/values/libs.xml\n");
- QString fileName = options.outputDirectory + QLatin1String("/res/values/libs.xml");
+ QString fileName = options->outputDirectory + QLatin1String("/res/values/libs.xml");
if (!QFile::exists(fileName)) {
fprintf(stderr, "Cannot find %s in prepared packaged. This file is required.\n", qPrintable(fileName));
return false;
}
- QString libsPath = QLatin1String("libs/") + options.architecture + QLatin1Char('/');
-
- QString qtLibs = QLatin1String("<item>") + options.stdCppName + QLatin1String("</item>\n");
+ QString qtLibs;
QString bundledInLibs;
QString bundledInAssets;
- for (const Options::BundledFile &bundledFile : options.bundledFiles) {
- if (bundledFile.second.startsWith(QLatin1String("lib/"))) {
- QString s = bundledFile.second.mid(sizeof("lib/lib") - 1);
- s.chop(sizeof(".so") - 1);
- qtLibs += QString::fromLatin1("<item>%1</item>\n").arg(s);
- } else if (bundledFile.first.startsWith(libsPath)) {
- QString s = bundledFile.first.mid(libsPath.length());
- bundledInLibs += QString::fromLatin1("<item>%1:%2</item>\n")
- .arg(s).arg(bundledFile.second);
- } else if (bundledFile.first.startsWith(QLatin1String("assets/"))) {
- QString s = bundledFile.first.mid(sizeof("assets/") - 1);
- bundledInAssets += QString::fromLatin1("<item>%1:%2</item>\n")
- .arg(s).arg(bundledFile.second);
- }
- }
-
- if (!options.extraPlugins.isEmpty()) {
- for (const QString &extraRes : options.extraPlugins) {
- QDir resourceDir(extraRes);
- const QStringList files = allFilesInside(resourceDir, resourceDir);
- for (const QString &file : files) {
- QString destinationPath = resourceDir.dirName() + QLatin1Char('/') + file;
- if (!file.endsWith(QLatin1String(".so"))) {
- bundledInAssets += QStringLiteral("<item>%1:%1</item>\n")
- .arg(destinationPath);
- } else {
- bundledInLibs += QStringLiteral("<item>lib%1:%2</item>\n")
- .arg(QString(destinationPath).replace(QLatin1Char('/'), QLatin1Char('_')))
- .arg(destinationPath);
+ QString allLocalLibs;
+ QString extraLibs;
+
+ for (auto it = options->architectures.constBegin(); it != options->architectures.constEnd(); ++it) {
+ QString libsPath = QLatin1String("libs/") + it.key() + QLatin1Char('/');
+
+ qtLibs += QLatin1String(" <item>%1;%2</item>\n").arg(it.key(), options->stdCppName);
+ for (const Options::BundledFile &bundledFile : options->bundledFiles[it.key()]) {
+ if (bundledFile.second.startsWith(QLatin1String("lib/"))) {
+ QString s = bundledFile.second.mid(sizeof("lib/lib") - 1);
+ s.chop(sizeof(".so") - 1);
+ qtLibs += QLatin1String(" <item>%1;%2</item>\n").arg(it.key(), s);
+ } else if (bundledFile.first.startsWith(libsPath)) {
+ QString s = bundledFile.first.mid(libsPath.length());
+ bundledInLibs += QString::fromLatin1(" <item>%1;%2:%3</item>\n")
+ .arg(it.key(), s, bundledFile.second);
+ } else if (bundledFile.first.startsWith(QLatin1String("assets/"))) {
+ QString s = bundledFile.first.mid(sizeof("assets/") - 1);
+ bundledInAssets += QString::fromLatin1(" <item>%1:%2</item>\n")
+ .arg(s, bundledFile.second);
+ }
+ }
+
+ if (!options->archExtraPlugins[it.key()].isEmpty()) {
+ for (const QString &extraRes : options->archExtraPlugins[it.key()]) {
+ QDir resourceDir(extraRes);
+ const QStringList files = allFilesInside(resourceDir, resourceDir);
+ for (const QString &file : files) {
+ QString destinationPath = resourceDir.dirName() + QLatin1Char('/') + file;
+ if (!file.endsWith(QLatin1String(".so"))) {
+ bundledInAssets += QLatin1String(" <item>%1:%1</item>\n")
+ .arg(destinationPath);
+ } else {
+ bundledInLibs += QLatin1String(" <item>%1;lib%2:%3</item>\n")
+ .arg(it.key(),
+ QString(destinationPath).replace(QLatin1Char('/'), QLatin1Char('_')),
+ destinationPath);
+ }
}
}
}
- }
- QHash<QString, QString> replacements;
- replacements[QLatin1String("<!-- %%INSERT_QT_LIBS%% -->")] = qtLibs;
+ if (!options->archExtraLibs[it.key()].isEmpty()) {
+ for (const QString &extraLib : options->archExtraLibs[it.key()]) {
+ QFileInfo extraLibInfo(extraLib);
+ QString name = extraLibInfo.fileName().mid(sizeof("lib") - 1);
+ name.chop(sizeof(".so") - 1);
+ extraLibs += QLatin1String(" <item>%1;%2").arg(it.key(), name);
+ }
+ }
- if (options.deploymentMechanism == Options::Bundled) {
- replacements[QLatin1String("<!-- %%INSERT_BUNDLED_IN_LIB%% -->")] = bundledInLibs;
- replacements[QLatin1String("<!-- %%INSERT_BUNDLED_IN_ASSETS%% -->")] = bundledInAssets;
- }
+ QStringList localLibs;
+ localLibs = options->localLibs[it.key()];
+ // If .pro file overrides dependency detection, we need to see which platform plugin they picked
+ if (localLibs.isEmpty()) {
+ QString plugin;
+ for (const QtDependency &qtDependency : options->qtDependencies[it.key()]) {
+ if (qtDependency.relativePath.endsWith(QLatin1String("libqtforandroid.so"))
+ || qtDependency.relativePath.endsWith(QLatin1String("libqtforandroidGL.so"))) {
+ if (!plugin.isEmpty() && plugin != qtDependency.relativePath) {
+ fprintf(stderr, "Both platform plugins libqtforandroid.so and libqtforandroidGL.so included in package. Please include only one.\n");
+ return false;
+ }
- QString extraLibs;
- if (!options.extraLibs.isEmpty()) {
- for (const QString extraLib : options.extraLibs) {
- QFileInfo extraLibInfo(extraLib);
- QString name = extraLibInfo.fileName().mid(sizeof("lib") - 1);
- name.chop(sizeof(".so") - 1);
+ plugin = qtDependency.relativePath;
+ }
+ if (qtDependency.relativePath.contains(QLatin1String("libQt5OpenGL"))
+ || qtDependency.relativePath.contains(QLatin1String("libQt5Quick"))) {
+ options->usesOpenGL |= true;
+ break;
+ }
+ }
+
+ if (plugin.isEmpty()) {
+ fflush(stdout);
+ fprintf(stderr, "No platform plugin, neither libqtforandroid.so or libqtforandroidGL.so, included in package. Please include one.\n");
+ fflush(stderr);
+ return false;
+ }
- extraLibs += QLatin1String("<item>") + name + QLatin1String("</item>\n");
+ localLibs.append(plugin);
+ if (options->verbose)
+ fprintf(stdout, " -- Using platform plugin %s\n", qPrintable(plugin));
}
+ allLocalLibs += QLatin1String(" <item>%1;%2</item>\n").arg(it.key(), localLibs.join(QLatin1Char(':'))
+ .replace(QLatin1String("lib/"), QString{})
+ .replace(QLatin1Char('/'), QLatin1Char('_')));
+ }
+
+ QHash<QString, QString> replacements;
+ replacements[QStringLiteral("<!-- %%INSERT_QT_LIBS%% -->")] += qtLibs.trimmed();
+ replacements[QStringLiteral("<!-- %%INSERT_LOCAL_LIBS%% -->")] = allLocalLibs.trimmed();
+ replacements[QStringLiteral("<!-- %%INSERT_EXTRA_LIBS%% -->")] = extraLibs.trimmed();
+
+ if (options->deploymentMechanism == Options::Bundled) {
+ replacements[QStringLiteral("<!-- %%INSERT_BUNDLED_IN_LIB%% -->")] += bundledInLibs.trimmed();
+ replacements[QStringLiteral("<!-- %%INSERT_BUNDLED_IN_ASSETS%% -->")] += bundledInAssets.trimmed();
}
- replacements[QLatin1String("<!-- %%INSERT_EXTRA_LIBS%% -->")] = extraLibs;
if (!updateFile(fileName, replacements))
return false;
@@ -1256,7 +1371,7 @@ bool updateStringsXml(const Options &options)
fprintf(stdout, " -- res/values/strings.xml\n");
QHash<QString, QString> replacements;
- replacements[QStringLiteral("<!-- %%INSERT_APP_NAME%% -->")] = QFileInfo(options.applicationBinary).baseName().mid(sizeof("lib") - 1);
+ replacements[QStringLiteral("<!-- %%INSERT_APP_NAME%% -->")] = options.applicationBinary;
QString fileName = options.outputDirectory + QLatin1String("/res/values/strings.xml");
if (!QFile::exists(fileName)) {
@@ -1268,7 +1383,7 @@ bool updateStringsXml(const Options &options)
return false;
}
file.write(QByteArray("<?xml version='1.0' encoding='utf-8'?><resources><string name=\"app_name\" translatable=\"false\">")
- .append(QFileInfo(options.applicationBinary).baseName().mid(sizeof("lib") - 1).toLatin1())
+ .append(options.applicationBinary.toLatin1())
.append("</string></resources>\n"));
return true;
}
@@ -1284,71 +1399,34 @@ bool updateAndroidManifest(Options &options)
if (options.verbose)
fprintf(stdout, " -- AndroidManifest.xml \n");
- QStringList localLibs = options.localLibs;
-
- // If .pro file overrides dependency detection, we need to see which platform plugin they picked
- if (localLibs.isEmpty()) {
- QString plugin;
- for (const QtDependency &qtDependency : qAsConst(options.qtDependencies)) {
- if (qtDependency.relativePath.endsWith(QLatin1String("libqtforandroid.so"))
- || qtDependency.relativePath.endsWith(QLatin1String("libqtforandroidGL.so"))) {
- if (!plugin.isEmpty() && plugin != qtDependency.relativePath) {
- fprintf(stderr, "Both platform plugins libqtforandroid.so and libqtforandroidGL.so included in package. Please include only one.\n");
- return false;
- }
-
- plugin = qtDependency.relativePath;
- }
- }
-
- if (plugin.isEmpty()) {
- fprintf(stderr, "No platform plugin, neither libqtforandroid.so or libqtforandroidGL.so, included in package. Please include one.\n");
- return false;
- }
-
- localLibs.append(plugin);
- if (options.verbose)
- fprintf(stdout, " -- Using platform plugin %s\n", qPrintable(plugin));
- }
-
- bool usesGL = false;
- for (const QtDependency &qtDependency : qAsConst(options.qtDependencies)) {
- if (qtDependency.relativePath.endsWith(QLatin1String("libQt5OpenGL.so"))
- || qtDependency.relativePath.endsWith(QLatin1String("libQt5Quick.so"))) {
- usesGL = true;
- break;
- }
- }
-
options.localJars.removeDuplicates();
options.initClasses.removeDuplicates();
QHash<QString, QString> replacements;
- replacements[QLatin1String("-- %%INSERT_APP_NAME%% --")] = QFileInfo(options.applicationBinary).baseName().mid(sizeof("lib") - 1);
- replacements[QLatin1String("-- %%INSERT_APP_LIB_NAME%% --")] = QFileInfo(options.applicationBinary).baseName().mid(sizeof("lib") - 1);
- replacements[QLatin1String("-- %%INSERT_LOCAL_LIBS%% --")] = localLibs.join(QLatin1Char(':'));
- replacements[QLatin1String("-- %%INSERT_LOCAL_JARS%% --")] = options.localJars.join(QLatin1Char(':'));
- replacements[QLatin1String("-- %%INSERT_INIT_CLASSES%% --")] = options.initClasses.join(QLatin1Char(':'));
- replacements[QLatin1String("-- %%INSERT_VERSION_NAME%% --")] = options.versionName;
- replacements[QLatin1String("-- %%INSERT_VERSION_CODE%% --")] = options.versionCode;
- replacements[QLatin1String("package=\"org.qtproject.example\"")] = QString::fromLatin1("package=\"%1\"").arg(options.packageName);
- replacements[QLatin1String("-- %%BUNDLE_LOCAL_QT_LIBS%% --")]
- = (options.deploymentMechanism == Options::Bundled) ? QString::fromLatin1("1") : QString::fromLatin1("0");
- replacements[QLatin1String("-- %%USE_LOCAL_QT_LIBS%% --")]
- = (options.deploymentMechanism != Options::Ministro) ? QString::fromLatin1("1") : QString::fromLatin1("0");
+ replacements[QStringLiteral("-- %%INSERT_APP_NAME%% --")] = options.applicationBinary;
+ replacements[QStringLiteral("-- %%INSERT_APP_LIB_NAME%% --")] = options.applicationBinary;
+ replacements[QStringLiteral("-- %%INSERT_LOCAL_JARS%% --")] = options.localJars.join(QLatin1Char(':'));
+ replacements[QStringLiteral("-- %%INSERT_INIT_CLASSES%% --")] = options.initClasses.join(QLatin1Char(':'));
+ replacements[QStringLiteral("-- %%INSERT_VERSION_NAME%% --")] = options.versionName;
+ replacements[QStringLiteral("-- %%INSERT_VERSION_CODE%% --")] = options.versionCode;
+ replacements[QStringLiteral("package=\"org.qtproject.example\"")] = QLatin1String("package=\"%1\"").arg(options.packageName);
+ replacements[QStringLiteral("-- %%BUNDLE_LOCAL_QT_LIBS%% --")]
+ = (options.deploymentMechanism == Options::Bundled) ? QLatin1String("1") : QLatin1String("0");
+ replacements[QStringLiteral("-- %%USE_LOCAL_QT_LIBS%% --")]
+ = (options.deploymentMechanism != Options::Ministro) ? QLatin1String("1") : QLatin1String("0");
QString permissions;
for (const QString &permission : qAsConst(options.permissions))
- permissions += QString::fromLatin1(" <uses-permission android:name=\"%1\" />\n").arg(permission);
- replacements[QLatin1String("<!-- %%INSERT_PERMISSIONS -->")] = permissions;
+ permissions += QLatin1String(" <uses-permission android:name=\"%1\" />\n").arg(permission);
+ replacements[QStringLiteral("<!-- %%INSERT_PERMISSIONS -->")] = permissions.trimmed();
QString features;
for (const QString &feature : qAsConst(options.features))
- features += QStringLiteral(" <uses-feature android:name=\"%1\" android:required=\"false\" />\n").arg(feature);
- if (usesGL)
- features += QStringLiteral(" <uses-feature android:glEsVersion=\"0x00020000\" android:required=\"true\" />");
+ features += QLatin1String(" <uses-feature android:name=\"%1\" android:required=\"false\" />\n").arg(feature);
+ if (options.usesOpenGL)
+ features += QLatin1String(" <uses-feature android:glEsVersion=\"0x00020000\" android:required=\"true\" />");
- replacements[QLatin1String("<!-- %%INSERT_FEATURES -->")] = features;
+ replacements[QStringLiteral("<!-- %%INSERT_FEATURES -->")] = features.trimmed();
QString androidManifestPath = options.outputDirectory + QLatin1String("/AndroidManifest.xml");
if (!updateFile(androidManifestPath, replacements))
@@ -1409,7 +1487,7 @@ bool updateAndroidFiles(Options &options)
if (options.verbose)
fprintf(stdout, "Updating Android package files with project settings.\n");
- if (!updateLibsXml(options))
+ if (!updateLibsXml(&options))
return false;
if (!updateAndroidManifest(options))
@@ -1466,7 +1544,7 @@ bool readAndroidDependencyXml(Options *options,
QSet<QString> *usedDependencies,
QSet<QString> *remainingDependencies)
{
- QString androidDependencyName = absoluteFilePath(options, QString::fromLatin1("/lib/%1-android-dependencies.xml").arg(moduleName));
+ QString androidDependencyName = absoluteFilePath(options, QLatin1String("/lib/%1-android-dependencies.xml").arg(moduleName));
QFile androidDependencyFile(androidDependencyName);
if (androidDependencyFile.exists()) {
@@ -1505,7 +1583,7 @@ bool readAndroidDependencyXml(Options *options,
if (options->verbose)
fprintf(stdout, "Appending dependency from xml: %s\n", qPrintable(fileName.relativePath));
- options->qtDependencies.append(fileName);
+ options->qtDependencies[options->currentArchitecture].append(fileName);
}
} else if (reader.name() == QLatin1String("jar")) {
int bundling = reader.attributes().value(QLatin1String("bundling")).toInt();
@@ -1513,7 +1591,7 @@ bool readAndroidDependencyXml(Options *options,
if (bundling == (options->deploymentMechanism == Options::Bundled)) {
QtDependency dependency(fileName, absoluteFilePath(options, fileName));
if (!usedDependencies->contains(dependency.absolutePath)) {
- options->qtDependencies.append(dependency);
+ options->qtDependencies[options->currentArchitecture].append(dependency);
usedDependencies->insert(dependency.absolutePath);
}
}
@@ -1529,15 +1607,15 @@ bool readAndroidDependencyXml(Options *options,
if (reader.attributes().hasAttribute(QLatin1String("replaces"))) {
QString replaces = reader.attributes().value(QLatin1String("replaces")).toString();
for (int i=0; i<options->localLibs.size(); ++i) {
- if (options->localLibs.at(i) == replaces) {
- options->localLibs[i] = fileName;
+ if (options->localLibs[options->currentArchitecture].at(i) == replaces) {
+ options->localLibs[options->currentArchitecture][i] = fileName;
break;
}
}
} else if (!fileName.isEmpty()) {
- options->localLibs.append(fileName);
+ options->localLibs[options->currentArchitecture].append(fileName);
}
- if (fileName.endsWith(QLatin1String(".so"))) {
+ if (fileName.endsWith(QLatin1String(".so")) && checkArchitecture(*options, fileName)) {
remainingDependencies->insert(fileName);
}
} else if (reader.name() == QLatin1String("permission")) {
@@ -1557,24 +1635,17 @@ bool readAndroidDependencyXml(Options *options,
} else if (options->verbose) {
fprintf(stdout, "No android dependencies for %s\n", qPrintable(moduleName));
}
+ options->permissions.removeDuplicates();
+ options->features.removeDuplicates();
return true;
}
QStringList getQtLibsFromElf(const Options &options, const QString &fileName)
{
- QString readElf = options.ndkPath
- + QLatin1String("/toolchains/")
- + options.toolchainPrefix;
-
- if (!options.useLLVM)
- readElf += QLatin1Char('-') + options.toolchainVersion;
-
- readElf += QLatin1String("/prebuilt/")
- + options.ndkHost
- + QLatin1String("/bin/")
- + options.toolPrefix +
- (options.useLLVM ? QLatin1String("-readobj") : QLatin1String("-readelf"));
+ QString readElf = QLatin1String("%1/toolchains/%2/prebuilt/%3/bin/llvm-readobj").arg(options.ndkPath,
+ options.toolchainPrefix,
+ options.ndkHost);
#if defined(Q_OS_WIN32)
readElf += QLatin1String(".exe");
#endif
@@ -1584,14 +1655,11 @@ QStringList getQtLibsFromElf(const Options &options, const QString &fileName)
return QStringList();
}
- if (options.useLLVM)
- readElf = QString::fromLatin1("%1 -needed-libs %2").arg(shellQuote(readElf), shellQuote(fileName));
- else
- readElf = QString::fromLatin1("%1 -d -W %2").arg(shellQuote(readElf), shellQuote(fileName));
+ readElf = QLatin1String("%1 -needed-libs %2").arg(shellQuote(readElf), shellQuote(fileName));
FILE *readElfCommand = openProcess(readElf);
if (!readElfCommand) {
- fprintf(stderr, "Cannot execute command %s", qPrintable(readElf));
+ fprintf(stderr, "Cannot execute command %s\n", qPrintable(readElf));
return QStringList();
}
@@ -1599,22 +1667,25 @@ QStringList getQtLibsFromElf(const Options &options, const QString &fileName)
bool readLibs = false;
char buffer[512];
- while (fgets(buffer, sizeof(buffer), readElfCommand) != 0) {
+ while (fgets(buffer, sizeof(buffer), readElfCommand) != nullptr) {
QByteArray line = QByteArray::fromRawData(buffer, qstrlen(buffer));
QString library;
- if (options.useLLVM) {
- line = line.trimmed();
- if (!readLibs) {
- readLibs = line.startsWith("NeededLibraries");
- continue;
+ line = line.trimmed();
+ if (!readLibs) {
+ if (line.startsWith("Arch: ")) {
+ auto it = elfArchitecures.find(line.mid(6));
+ if (it == elfArchitecures.constEnd() || *it != options.currentArchitecture.toLatin1()) {
+ if (options.verbose)
+ fprintf(stdout, "Skipping \"%s\", architecture mismatch\n", qPrintable(fileName));
+ return {};
+ }
}
- if (!line.startsWith("lib"))
- continue;
- library = QString::fromLatin1(line);
- } else if (line.contains("(NEEDED)") && line.contains("Shared library:")) {
- const int pos = line.lastIndexOf('[') + 1;
- library = QString::fromLatin1(line.mid(pos, line.length() - pos - 2));
+ readLibs = line.startsWith("NeededLibraries");
+ continue;
}
+ if (!line.startsWith("lib"))
+ continue;
+ library = QString::fromLatin1(line);
QString libraryName = QLatin1String("lib/") + library;
if (QFile::exists(absoluteFilePath(&options, libraryName)))
ret += libraryName;
@@ -1653,7 +1724,7 @@ bool readDependenciesFromElf(Options *options,
return false;
}
- options->qtDependencies.append(QtDependency(dependency, absoluteDependencyPath));
+ options->qtDependencies[options->currentArchitecture].append(QtDependency(dependency, absoluteDependencyPath));
if (options->verbose)
fprintf(stdout, "Appending dependency: %s\n", qPrintable(dependency));
dependenciesToCheck.append(dependency);
@@ -1677,10 +1748,15 @@ bool scanImports(Options *options, QSet<QString> *usedDependencies)
if (options->verbose)
fprintf(stdout, "Scanning for QML imports.\n");
- QString qmlImportScanner = options->qtInstallDirectory + QLatin1String("/bin/qmlimportscanner");
+ QString qmlImportScanner;
+ if (!options->qmlImportScannerBinaryPath.isEmpty()) {
+ qmlImportScanner = options->qmlImportScannerBinaryPath;
+ } else {
+ options->qtInstallDirectory + QLatin1String("/bin/qmlimportscanner");
#if defined(Q_OS_WIN32)
- qmlImportScanner += QLatin1String(".exe");
+ qmlImportScanner += QLatin1String(".exe");
#endif
+ }
if (!QFile::exists(qmlImportScanner)) {
fprintf(stderr, "qmlimportscanner not found: %s\n", qPrintable(qmlImportScanner));
@@ -1702,9 +1778,8 @@ bool scanImports(Options *options, QSet<QString> *usedDependencies)
for (const QString &qmlImportPath : qAsConst(options->qmlImportPaths))
importPaths += shellQuote(qmlImportPath);
- qmlImportScanner += QString::fromLatin1(" -rootPath %1 -importPath %2")
- .arg(shellQuote(rootPath))
- .arg(importPaths.join(QLatin1Char(' ')));
+ qmlImportScanner += QLatin1String(" -rootPath %1 -importPath %2")
+ .arg(shellQuote(rootPath), importPaths.join(QLatin1Char(' ')));
if (options->verbose) {
fprintf(stdout, "Running qmlimportscanner with the following command: %s\n",
@@ -1798,9 +1873,9 @@ bool scanImports(Options *options, QSet<QString> *usedDependencies)
// Put all imports in default import path in assets
fileName.relativePath.prepend(QLatin1String("qml/"));
- options->qtDependencies.append(fileName);
+ options->qtDependencies[options->currentArchitecture].append(fileName);
- if (fileName.absolutePath.endsWith(QLatin1String(".so"))) {
+ if (fileName.absolutePath.endsWith(QLatin1String(".so")) && checkArchitecture(*options, fileName.absolutePath)) {
QSet<QString> remainingDependencies;
if (!readDependenciesFromElf(options, fileName.absolutePath, usedDependencies, &remainingDependencies))
return false;
@@ -1819,7 +1894,7 @@ bool readDependencies(Options *options)
fprintf(stdout, "Detecting dependencies of application.\n");
// Override set in .pro file
- if (!options->qtDependencies.isEmpty()) {
+ if (!options->qtDependencies[options->currentArchitecture].isEmpty()) {
if (options->verbose)
fprintf(stdout, "\tDependencies explicitly overridden in .pro file. No detection needed.\n");
return true;
@@ -1829,11 +1904,7 @@ bool readDependencies(Options *options)
QSet<QString> remainingDependencies;
// Add dependencies of application binary first
- if (!readDependenciesFromElf(options, options->applicationBinary, &usedDependencies, &remainingDependencies))
- return false;
-
- // Jam in the dependencies of the platform plugin, since the application will crash without it
- if (!readDependenciesFromElf(options, options->qtInstallDirectory + QLatin1String("/plugins/platforms/android/libqtforandroid.so"), &usedDependencies, &remainingDependencies))
+ if (!readDependenciesFromElf(options, QLatin1String("%1/libs/%2/lib%3_%2.so").arg(options->outputDirectory, options->currentArchitecture, options->applicationBinary), &usedDependencies, &remainingDependencies))
return false;
while (!remainingDependencies.isEmpty()) {
@@ -1853,14 +1924,14 @@ bool readDependencies(Options *options)
}
}
- QStringList::iterator it = options->localLibs.begin();
- while (it != options->localLibs.end()) {
+ QStringList::iterator it = options->localLibs[options->currentArchitecture].begin();
+ while (it != options->localLibs[options->currentArchitecture].end()) {
QStringList unmetDependencies;
if (!goodToCopy(options, absoluteFilePath(options, *it), &unmetDependencies)) {
fprintf(stdout, "Skipping %s due to unmet dependencies: %s\n",
qPrintable(*it),
qPrintable(unmetDependencies.join(QLatin1Char(','))));
- it = options->localLibs.erase(it);
+ it = options->localLibs[options->currentArchitecture].erase(it);
} else {
++it;
}
@@ -1872,94 +1943,33 @@ bool readDependencies(Options *options)
return true;
}
-bool stripFile(const Options &options, const QString &fileName)
-{
- QString strip = options.ndkPath
- + QLatin1String("/toolchains/")
- + options.toolchainPrefix;
-
- if (!options.useLLVM)
- strip += QLatin1Char('-') + options.toolchainVersion;
-
- strip += QLatin1String("/prebuilt/")
- + options.ndkHost
- + QLatin1String("/bin/")
- + options.toolPrefix
- + QLatin1String("-strip");
-#if defined(Q_OS_WIN32)
- strip += QLatin1String(".exe");
-#endif
-
- if (!QFile::exists(strip)) {
- fprintf(stderr, "Command does not exist: %s\n", qPrintable(strip));
- return false;
- }
-
- if (options.useLLVM)
- strip = QString::fromLatin1("%1 -strip-all %2").arg(shellQuote(strip), shellQuote(fileName));
- else
- strip = QString::fromLatin1("%1 %2").arg(shellQuote(strip), shellQuote(fileName));
-
- FILE *stripCommand = openProcess(strip);
- if (stripCommand == 0) {
- fprintf(stderr, "Cannot execute command %s", qPrintable(strip));
- return false;
- }
-
- pclose(stripCommand);
-
- return true;
-}
-
-bool stripLibraries(const Options &options)
+bool containsApplicationBinary(Options *options)
{
- if (!options.stripLibraries)
+ if (!options->build)
return true;
- if (options.verbose)
- fprintf(stdout, "Stripping libraries to minimize size.\n");
-
- QString libraryPath = options.outputDirectory
- + QLatin1String("/libs/")
- + options.architecture;
- const QStringList libraries = QDir(libraryPath).entryList(QDir::Files);
- for (const QString &library : libraries) {
- if (library.endsWith(QLatin1String(".so"))) {
- if (!stripFile(options, libraryPath + QLatin1Char('/') + library))
- return false;
- }
- }
-
-
- return true;
-}
-
-bool containsApplicationBinary(const Options &options)
-{
- if (options.verbose)
+ if (options->verbose)
fprintf(stdout, "Checking if application binary is in package.\n");
- QFileInfo applicationBinary(options.applicationBinary);
- QString destinationFileName = options.outputDirectory
- + QLatin1String("/libs/")
- + options.architecture
- + QLatin1Char('/')
- + applicationBinary.fileName();
+ QFileInfo applicationBinary(options->applicationBinary);
+ QString applicationFileName = QLatin1String("lib%1_%2.so").arg(options->applicationBinary,
+ options->currentArchitecture);
- if (!QFile::exists(destinationFileName)) {
+ QString applicationPath = QLatin1String("%1/libs/%2/%3").arg(options->outputDirectory,
+ options->currentArchitecture,
+ applicationFileName);
+ if (!QFile::exists(applicationPath)) {
#if defined(Q_OS_WIN32)
QLatin1String makeTool("mingw32-make"); // Only Mingw host builds supported on Windows currently
#else
QLatin1String makeTool("make");
#endif
-
fprintf(stderr, "Application binary is not in output directory: %s. Please run '%s install INSTALL_ROOT=%s' first.\n",
- qPrintable(destinationFileName),
+ qPrintable(applicationFileName),
qPrintable(makeTool),
- qPrintable(options.outputDirectory));
+ qPrintable(options->outputDirectory));
return false;
}
-
return true;
}
@@ -1978,7 +1988,7 @@ FILE *runAdb(const Options &options, const QString &arguments)
if (!options.installLocation.isEmpty())
installOption = QLatin1String(" -s ") + shellQuote(options.installLocation);
- adb = QString::fromLatin1("%1%2 %3").arg(shellQuote(adb)).arg(installOption).arg(arguments);
+ adb = QLatin1String("%1%2 %3").arg(shellQuote(adb), installOption, arguments);
if (options.verbose)
fprintf(stdout, "Running command \"%s\"\n", adb.toLocal8Bit().constData());
@@ -1997,10 +2007,13 @@ bool goodToCopy(const Options *options, const QString &file, QStringList *unmetD
if (!file.endsWith(QLatin1String(".so")))
return true;
+ if (!checkArchitecture(*options, file))
+ return false;
+
bool ret = true;
const auto libs = getQtLibsFromElf(*options, file);
for (const QString &lib : libs) {
- if (!options->qtDependencies.contains(QtDependency(lib, absoluteFilePath(options, lib)))) {
+ if (!options->qtDependencies[options->currentArchitecture].contains(QtDependency(lib, absoluteFilePath(options, lib)))) {
ret = false;
unmetDependencies->append(lib);
}
@@ -2025,12 +2038,12 @@ bool copyQtFiles(Options *options)
if (!options->build)
return true;
+
QString libsDirectory = QLatin1String("libs/");
// Copy other Qt dependencies
- QString libDestinationDirectory = libsDirectory + options->architecture + QLatin1Char('/');
- QString assetsDestinationDirectory = QLatin1String("assets/--Added-by-androiddeployqt--/");
- for (const QtDependency &qtDependency : qAsConst(options->qtDependencies)) {
+ auto assetsDestinationDirectory = QLatin1String("assets/--Added-by-androiddeployqt--/");
+ for (const QtDependency &qtDependency : qAsConst(options->qtDependencies[options->currentArchitecture])) {
QString sourceFileName = qtDependency.absolutePath;
QString destinationFileName;
@@ -2039,12 +2052,9 @@ bool copyQtFiles(Options *options)
if (qtDependency.relativePath.startsWith(QLatin1String("lib/"))) {
garbledFileName = qtDependency.relativePath.mid(sizeof("lib/") - 1);
} else {
- garbledFileName = QLatin1String("lib")
- + QString(qtDependency.relativePath).replace(QLatin1Char('/'), QLatin1Char('_'));
-
+ garbledFileName = QString(qtDependency.relativePath).replace(QLatin1Char('/'), QLatin1Char('_'));
}
- destinationFileName = libDestinationDirectory + garbledFileName;
-
+ destinationFileName = libsDirectory + options->currentArchitecture + QLatin1Char('/') + garbledFileName;
} else if (qtDependency.relativePath.startsWith(QLatin1String("jar/"))) {
destinationFileName = libsDirectory + qtDependency.relativePath.mid(sizeof("jar/") - 1);
} else {
@@ -2058,20 +2068,34 @@ bool copyQtFiles(Options *options)
QStringList unmetDependencies;
if (!goodToCopy(options, sourceFileName, &unmetDependencies)) {
- fprintf(stdout, " -- Skipping %s. It has unmet dependencies: %s.\n",
- qPrintable(sourceFileName),
- qPrintable(unmetDependencies.join(QLatin1Char(','))));
+ if (unmetDependencies.isEmpty()) {
+ if (options->verbose) {
+ fprintf(stdout, " -- Skipping %s, architecture mismatch.\n",
+ qPrintable(sourceFileName));
+ }
+ } else {
+ if (unmetDependencies.isEmpty()) {
+ if (options->verbose) {
+ fprintf(stdout, " -- Skipping %s, architecture mismatch.\n",
+ qPrintable(sourceFileName));
+ }
+ } else {
+ fprintf(stdout, " -- Skipping %s. It has unmet dependencies: %s.\n",
+ qPrintable(sourceFileName),
+ qPrintable(unmetDependencies.join(QLatin1Char(','))));
+ }
+ }
continue;
}
if (options->deploymentMechanism == Options::Bundled
&& !copyFileIfNewer(sourceFileName,
options->outputDirectory + QLatin1Char('/') + destinationFileName,
- options->verbose)) {
+ *options)) {
return false;
}
- options->bundledFiles += qMakePair(destinationFileName, qtDependency.relativePath);
+ options->bundledFiles[options->currentArchitecture] += qMakePair(destinationFileName, qtDependency.relativePath);
}
return true;
@@ -2120,7 +2144,7 @@ bool createAndroidProject(const Options &options)
return false;
}
- QString androidTool = QString::fromLatin1("%1 update project --path %2 --target %3 --name QtApp")
+ QString androidTool = QLatin1String("%1 update project --path %2 --target %3 --name QtApp")
.arg(shellQuote(androidToolExecutable))
.arg(shellQuote(options.outputDirectory))
.arg(shellQuote(options.androidPlatform));
@@ -2142,7 +2166,7 @@ bool createAndroidProject(const Options &options)
if (options.verbose)
fprintf(stdout, "Updating subproject %s\n", qPrintable(libraryProject));
- androidTool = QString::fromLatin1("%1 update lib-project --path %2 --target %3")
+ androidTool = QLatin1String("%1 update lib-project --path %2 --target %3")
.arg(shellQuote(androidToolExecutable))
.arg(shellQuote(libraryProject))
.arg(shellQuote(options.androidPlatform));
@@ -2274,7 +2298,10 @@ bool buildAndroidProject(const Options &options)
return false;
}
- QString commandLine = QString::fromLatin1("%1 --no-daemon %2").arg(shellQuote(gradlePath)).arg(options.releasePackage ? QLatin1String(" assembleRelease") : QLatin1String(" assembleDebug"));
+ QString commandLine = QLatin1String("%1 --no-daemon %2").arg(shellQuote(gradlePath), options.releasePackage ? QLatin1String(" assembleRelease") : QLatin1String(" assembleDebug"));
+ if (options.buildAAB)
+ commandLine += QLatin1String(" bundle");
+
if (options.verbose)
commandLine += QLatin1String(" --info");
@@ -2335,28 +2362,38 @@ bool uninstallApk(const Options &options)
}
enum PackageType {
+ AAB,
UnsignedAPK,
SignedAPK
};
-QString apkPath(const Options &options, PackageType pt)
+QString packagePath(const Options &options, PackageType pt)
{
QString path(options.outputDirectory);
- path += QLatin1String("/build/outputs/apk/");
+ path += QLatin1String("/build/outputs/%1/").arg(pt >= UnsignedAPK ? QStringLiteral("apk") : QStringLiteral("bundle"));
QString buildType(options.releasePackage ? QLatin1String("release/") : QLatin1String("debug/"));
if (QDir(path + buildType).exists())
path += buildType;
path += QDir(options.outputDirectory).dirName() + QLatin1Char('-');
if (options.releasePackage) {
path += QLatin1String("release-");
- if (pt == UnsignedAPK)
- path += QLatin1String("un");
- path += QLatin1String("signed.apk");
+ if (pt >= UnsignedAPK) {
+ if (pt == UnsignedAPK)
+ path += QLatin1String("un");
+ path += QLatin1String("signed.apk");
+ } else {
+ path.chop(1);
+ path += QLatin1String(".aab");
+ }
} else {
path += QLatin1String("debug");
- if (pt == SignedAPK)
- path += QLatin1String("-signed");
- path += QLatin1String(".apk");
+ if (pt >= UnsignedAPK) {
+ if (pt == SignedAPK)
+ path += QLatin1String("-signed");
+ path += QLatin1String(".apk");
+ } else {
+ path += QLatin1String(".aab");
+ }
}
return shellQuote(path);
}
@@ -2373,7 +2410,7 @@ bool installApk(const Options &options)
FILE *adbCommand = runAdb(options,
QLatin1String(" install -r ")
- + apkPath(options, options.keyStore.isEmpty() ? UnsignedAPK
+ + packagePath(options, options.keyStore.isEmpty() ? UnsignedAPK
: SignedAPK));
if (adbCommand == 0)
return false;
@@ -2399,7 +2436,7 @@ bool installApk(const Options &options)
bool copyPackage(const Options &options)
{
fflush(stdout);
- auto from = apkPath(options, options.keyStore.isEmpty() ? UnsignedAPK : SignedAPK);
+ auto from = packagePath(options, options.keyStore.isEmpty() ? UnsignedAPK : SignedAPK);
QFile::remove(options.apkPath);
return QFile::copy(from, options.apkPath);
}
@@ -2409,21 +2446,18 @@ bool copyStdCpp(Options *options)
if (options->verbose)
fprintf(stdout, "Copying STL library\n");
- if (!QFile::exists(options->stdCppPath)) {
- fprintf(stderr, "STL library does not exist at %s\n", qPrintable(options->stdCppPath));
- return false;
- }
-
- const QString destinationDirectory = options->outputDirectory
- + QLatin1String("/libs/") + options->architecture;
-
- if (!copyFileIfNewer(options->stdCppPath, destinationDirectory + QLatin1String("/lib")
- + options->stdCppName + QLatin1String(".so"),
- options->verbose)) {
+ QString stdCppPath = QLatin1String("%1/%2/lib%3.so").arg(options->stdCppPath, options->architectures[options->currentArchitecture], options->stdCppName);
+ if (!QFile::exists(stdCppPath)) {
+ fprintf(stderr, "STL library does not exist at %s\n", qPrintable(stdCppPath));
+ fflush(stdout);
+ fflush(stderr);
return false;
}
- return true;
+ const QString destinationFile = QLatin1String("%1/libs/%2/lib%3.so").arg(options->outputDirectory,
+ options->currentArchitecture,
+ options->stdCppName);
+ return copyFileIfNewer(stdCppPath, destinationFile, *options);
}
bool jarSignerSignPackage(const Options &options)
@@ -2437,9 +2471,9 @@ bool jarSignerSignPackage(const Options &options)
jdkPath = QString::fromLocal8Bit(qgetenv("JAVA_HOME"));
#if defined(Q_OS_WIN32)
- QString jarSignerTool = QString::fromLatin1("jarsigner.exe");
+ QString jarSignerTool = QLatin1String("jarsigner.exe");
#else
- QString jarSignerTool = QString::fromLatin1("jarsigner");
+ QString jarSignerTool = QLatin1String("jarsigner");
#endif
if (jdkPath.isEmpty() || !QFile::exists(jdkPath + QLatin1String("/bin/") + jarSignerTool))
@@ -2452,29 +2486,29 @@ bool jarSignerSignPackage(const Options &options)
return false;
}
- jarSignerTool = QString::fromLatin1("%1 -sigalg %2 -digestalg %3 -keystore %4")
- .arg(shellQuote(jarSignerTool)).arg(shellQuote(options.sigAlg)).arg(shellQuote(options.digestAlg)).arg(shellQuote(options.keyStore));
+ jarSignerTool = QLatin1String("%1 -sigalg %2 -digestalg %3 -keystore %4")
+ .arg(shellQuote(jarSignerTool), shellQuote(options.sigAlg), shellQuote(options.digestAlg), shellQuote(options.keyStore));
if (!options.keyStorePassword.isEmpty())
- jarSignerTool += QString::fromLatin1(" -storepass %1").arg(shellQuote(options.keyStorePassword));
+ jarSignerTool += QLatin1String(" -storepass %1").arg(shellQuote(options.keyStorePassword));
if (!options.storeType.isEmpty())
- jarSignerTool += QString::fromLatin1(" -storetype %1").arg(shellQuote(options.storeType));
+ jarSignerTool += QLatin1String(" -storetype %1").arg(shellQuote(options.storeType));
if (!options.keyPass.isEmpty())
- jarSignerTool += QString::fromLatin1(" -keypass %1").arg(shellQuote(options.keyPass));
+ jarSignerTool += QLatin1String(" -keypass %1").arg(shellQuote(options.keyPass));
if (!options.sigFile.isEmpty())
- jarSignerTool += QString::fromLatin1(" -sigfile %1").arg(shellQuote(options.sigFile));
+ jarSignerTool += QLatin1String(" -sigfile %1").arg(shellQuote(options.sigFile));
if (!options.signedJar.isEmpty())
- jarSignerTool += QString::fromLatin1(" -signedjar %1").arg(shellQuote(options.signedJar));
+ jarSignerTool += QLatin1String(" -signedjar %1").arg(shellQuote(options.signedJar));
if (!options.tsaUrl.isEmpty())
- jarSignerTool += QString::fromLatin1(" -tsa %1").arg(shellQuote(options.tsaUrl));
+ jarSignerTool += QLatin1String(" -tsa %1").arg(shellQuote(options.tsaUrl));
if (!options.tsaCert.isEmpty())
- jarSignerTool += QString::fromLatin1(" -tsacert %1").arg(shellQuote(options.tsaCert));
+ jarSignerTool += QLatin1String(" -tsacert %1").arg(shellQuote(options.tsaCert));
if (options.internalSf)
jarSignerTool += QLatin1String(" -internalsf");
@@ -2485,29 +2519,39 @@ bool jarSignerSignPackage(const Options &options)
if (options.protectedAuthenticationPath)
jarSignerTool += QLatin1String(" -protected");
- jarSignerTool += QString::fromLatin1(" %1 %2")
- .arg(apkPath(options, UnsignedAPK))
- .arg(shellQuote(options.keyStoreAlias));
+ auto signPackage = [&](const QString &file) {
+ fprintf(stdout, "Signing file %s\n", qPrintable(file));
+ fflush(stdout);
+ auto command = jarSignerTool + QLatin1String(" %1 %2")
+ .arg(file)
+ .arg(shellQuote(options.keyStoreAlias));
- FILE *jarSignerCommand = openProcess(jarSignerTool);
- if (jarSignerCommand == 0) {
- fprintf(stderr, "Couldn't run jarsigner.\n");
- return false;
- }
+ FILE *jarSignerCommand = openProcess(command);
+ if (jarSignerCommand == 0) {
+ fprintf(stderr, "Couldn't run jarsigner.\n");
+ return false;
+ }
- if (options.verbose) {
- char buffer[512];
- while (fgets(buffer, sizeof(buffer), jarSignerCommand) != 0)
- fprintf(stdout, "%s", buffer);
- }
+ if (options.verbose) {
+ char buffer[512];
+ while (fgets(buffer, sizeof(buffer), jarSignerCommand) != 0)
+ fprintf(stdout, "%s", buffer);
+ }
- int errorCode = pclose(jarSignerCommand);
- if (errorCode != 0) {
- fprintf(stderr, "jarsigner command failed.\n");
- if (!options.verbose)
- fprintf(stderr, " -- Run with --verbose for more information.\n");
+ int errorCode = pclose(jarSignerCommand);
+ if (errorCode != 0) {
+ fprintf(stderr, "jarsigner command failed.\n");
+ if (!options.verbose)
+ fprintf(stderr, " -- Run with --verbose for more information.\n");
+ return false;
+ }
+ return true;
+ };
+
+ if (!signPackage(packagePath(options, UnsignedAPK)))
+ return false;
+ if (options.buildAAB && !signPackage(packagePath(options, AAB)))
return false;
- }
QString zipAlignTool = options.sdkPath + QLatin1String("/tools/zipalign");
#if defined(Q_OS_WIN32)
@@ -2525,11 +2569,11 @@ bool jarSignerSignPackage(const Options &options)
}
}
- zipAlignTool = QString::fromLatin1("%1%2 -f 4 %3 %4")
- .arg(shellQuote(zipAlignTool))
- .arg(options.verbose ? QString::fromLatin1(" -v") : QString())
- .arg(apkPath(options, UnsignedAPK))
- .arg(apkPath(options, SignedAPK));
+ zipAlignTool = QLatin1String("%1%2 -f 4 %3 %4")
+ .arg(shellQuote(zipAlignTool),
+ options.verbose ? QLatin1String(" -v") : QLatin1String(),
+ packagePath(options, UnsignedAPK),
+ packagePath(options, SignedAPK));
FILE *zipAlignCommand = openProcess(zipAlignTool);
if (zipAlignCommand == 0) {
@@ -2541,7 +2585,7 @@ bool jarSignerSignPackage(const Options &options)
while (fgets(buffer, sizeof(buffer), zipAlignCommand) != 0)
fprintf(stdout, "%s", buffer);
- errorCode = pclose(zipAlignCommand);
+ int errorCode = pclose(zipAlignCommand);
if (errorCode != 0) {
fprintf(stderr, "zipalign command failed.\n");
if (!options.verbose)
@@ -2549,7 +2593,7 @@ bool jarSignerSignPackage(const Options &options)
return false;
}
- return QFile::remove(apkPath(options, UnsignedAPK));
+ return QFile::remove(packagePath(options, UnsignedAPK));
}
bool signPackage(const Options &options)
@@ -2580,11 +2624,11 @@ bool signPackage(const Options &options)
}
}
- zipAlignTool = QString::fromLatin1("%1%2 -f 4 %3 %4")
- .arg(shellQuote(zipAlignTool))
- .arg(options.verbose ? QString::fromLatin1(" -v") : QString())
- .arg(apkPath(options, UnsignedAPK))
- .arg(apkPath(options, SignedAPK));
+ zipAlignTool = QLatin1String("%1%2 -f 4 %3 %4")
+ .arg(shellQuote(zipAlignTool),
+ options.verbose ? QLatin1String(" -v") : QLatin1String(),
+ packagePath(options, UnsignedAPK),
+ packagePath(options, SignedAPK));
FILE *zipAlignCommand = openProcess(zipAlignTool);
if (zipAlignCommand == 0) {
@@ -2604,23 +2648,23 @@ bool signPackage(const Options &options)
return false;
}
- QString apkSignerCommandLine = QString::fromLatin1("%1 sign --ks %2")
- .arg(shellQuote(apksignerTool)).arg(shellQuote(options.keyStore));
+ QString apkSignerCommandLine = QLatin1String("%1 sign --ks %2")
+ .arg(shellQuote(apksignerTool), shellQuote(options.keyStore));
if (!options.keyStorePassword.isEmpty())
- apkSignerCommandLine += QString::fromLatin1(" --ks-pass pass:%1").arg(shellQuote(options.keyStorePassword));
+ apkSignerCommandLine += QLatin1String(" --ks-pass pass:%1").arg(shellQuote(options.keyStorePassword));
if (!options.keyStoreAlias.isEmpty())
- apkSignerCommandLine += QString::fromLatin1(" --ks-key-alias %1").arg(shellQuote(options.keyStoreAlias));
+ apkSignerCommandLine += QLatin1String(" --ks-key-alias %1").arg(shellQuote(options.keyStoreAlias));
if (!options.keyPass.isEmpty())
- apkSignerCommandLine += QString::fromLatin1(" --key-pass pass:%1").arg(shellQuote(options.keyPass));
+ apkSignerCommandLine += QLatin1String(" --key-pass pass:%1").arg(shellQuote(options.keyPass));
if (options.verbose)
apkSignerCommandLine += QLatin1String(" --verbose");
- apkSignerCommandLine += QString::fromLatin1(" %1")
- .arg(apkPath(options, SignedAPK));
+ apkSignerCommandLine += QLatin1String(" %1")
+ .arg(packagePath(options, SignedAPK));
auto apkSignerRunner = [&] {
FILE *apkSignerCommand = openProcess(apkSignerCommandLine);
@@ -2647,60 +2691,11 @@ bool signPackage(const Options &options)
if (!apkSignerRunner())
return false;
- apkSignerCommandLine = QString::fromLatin1("%1 verify --verbose %2")
- .arg(shellQuote(apksignerTool)).arg(apkPath(options, SignedAPK));
+ apkSignerCommandLine = QLatin1String("%1 verify --verbose %2")
+ .arg(shellQuote(apksignerTool), packagePath(options, SignedAPK));
// Verify the package and remove the unsigned apk
- return apkSignerRunner() && QFile::remove(apkPath(options, UnsignedAPK));
-}
-
-bool copyGdbServer(const Options &options)
-{
- if (options.verbose)
- fprintf(stdout, "Copying gdbserver into package.\n");
-
- QString architectureSubDirectory;
- if (options.architecture == QLatin1String("arm64-v8a"))
- architectureSubDirectory = QLatin1String("android-arm64");
- else if (options.architecture.startsWith(QLatin1String("arm")))
- architectureSubDirectory = QLatin1String("android-arm");
- else
- architectureSubDirectory = QLatin1String("android-") + options.architecture;
-
- QString gdbServerBinary = options.ndkPath
- + QLatin1String("/prebuilt/")
- + architectureSubDirectory
- + QLatin1String("/gdbserver/gdbserver");
- if (!QFile::exists(gdbServerBinary)) {
- fprintf(stderr, "Cannot find gdbserver at %s.\n", qPrintable(gdbServerBinary));
- return false;
- }
-
- QString gdbServerTarget = options.outputDirectory + QLatin1String("/libs/") + options.architecture;
-
- if (!copyFileIfNewer(gdbServerBinary,
- gdbServerTarget + QLatin1String("/gdbserver"),
- options.verbose)
- || !copyFileIfNewer(gdbServerBinary,
- gdbServerTarget + QLatin1String("/libgdbserver.so"),
- options.verbose)) {
- return false;
- }
-
- QString addedByAndroidDeployQtPath = options.outputDirectory + QLatin1String("/assets/--Added-by-androiddeployqt--/");
- if (!QDir().mkpath(addedByAndroidDeployQtPath)) {
- fprintf(stderr, "Failed to create directory '%s'", qPrintable(addedByAndroidDeployQtPath));
- return false;
- }
- QFile f(addedByAndroidDeployQtPath + QLatin1String("debugger.command"));
- if (!f.open(QIODevice::WriteOnly)) {
- fprintf(stderr, "Failed to create directory '%s'", qPrintable(addedByAndroidDeployQtPath));
- return false;
- }
- f.write("lib/libgdbserver.so --multi +");
- f.close();
-
- return true;
+ return apkSignerRunner() && QFile::remove(packagePath(options, UnsignedAPK));
}
bool generateAssetsFileList(const Options &options)
@@ -2726,7 +2721,7 @@ bool generateAssetsFileList(const Options &options)
const QString name = dirIterator.next().mid(assetsPath.length());
int slashIndex = name.lastIndexOf(QLatin1Char('/'));
- QString pathName = slashIndex >= 0 ? name.left(slashIndex) : QString::fromLatin1("/");
+ QString pathName = slashIndex >= 0 ? name.left(slashIndex) : QStringLiteral("/");
QString fileName = slashIndex >= 0 ? name.mid(pathName.length() + 1) : name;
if (!fileName.isEmpty() && dirIterator.fileInfo().isDir() && !fileName.endsWith(QLatin1Char('/')))
@@ -2764,8 +2759,6 @@ enum ErrorCode
CannotCopyGnuStl = 5,
CannotCopyQtFiles = 6,
CannotFindApplicationBinary = 7,
- CannotCopyGdbServer = 8,
- CannotStripLibraries = 9,
CannotCopyAndroidExtraLibs = 10,
CannotCopyAndroidSources = 11,
CannotUpdateAndroidFiles = 12,
@@ -2813,25 +2806,7 @@ int main(int argc, char *argv[])
: "No"
);
- if (options.auxMode) {
- if (!readDependencies(&options))
- return CannotReadDependencies;
- if (!copyQtFiles(&options))
- return CannotCopyQtFiles;
- if (!copyAndroidExtraResources(options))
- return CannotCopyAndroidExtraResources;
- if (!copyAndroidExtraLibs(options))
- return CannotCopyAndroidExtraLibs;
- if (!stripLibraries(options))
- return CannotStripLibraries;
- if (!updateAndroidFiles(options))
- return CannotUpdateAndroidFiles;
- if (options.generateAssetsFileList && !generateAssetsFileList(options))
- return CannotGenerateAssetsFileList;
- return 0;
- }
-
- if (options.build) {
+ if (options.build && !options.auxMode) {
cleanAndroidFiles(options);
if (Q_UNLIKELY(options.timing))
fprintf(stdout, "[TIMING] %d ms: Cleaned Android file\n", options.timer.elapsed());
@@ -2843,60 +2818,68 @@ int main(int argc, char *argv[])
fprintf(stdout, "[TIMING] %d ms: Copied Android template\n", options.timer.elapsed());
}
- if (!readDependencies(&options))
- return CannotReadDependencies;
+ for (auto it = options.architectures.constBegin(); it != options.architectures.constEnd(); ++it) {
+ options.clear(it.key());
- if (Q_UNLIKELY(options.timing))
- fprintf(stdout, "[TIMING] %d ms: Read dependencies\n", options.timer.elapsed());
-
- if (options.deploymentMechanism != Options::Ministro && !copyStdCpp(&options))
- return CannotCopyGnuStl;
+ if (!readDependencies(&options))
+ return CannotReadDependencies;
- if (Q_UNLIKELY(options.timing))
- fprintf(stdout, "[TIMING] %d ms: Copied GNU STL\n", options.timer.elapsed());
+ if (Q_UNLIKELY(options.timing))
+ fprintf(stdout, "[TIMING] %d ms: Read dependencies\n", options.timer.elapsed());
- if (!copyQtFiles(&options))
- return CannotCopyQtFiles;
+ if (!copyQtFiles(&options))
+ return CannotCopyQtFiles;
- if (options.build) {
if (Q_UNLIKELY(options.timing))
fprintf(stdout, "[TIMING] %d ms: Copied Qt files\n", options.timer.elapsed());
- if (!containsApplicationBinary(options))
- return CannotFindApplicationBinary;
+ if (!copyAndroidExtraLibs(&options))
+ return CannotCopyAndroidExtraLibs;
if (Q_UNLIKELY(options.timing))
- fprintf(stdout, "[TIMING] %d ms: Checked for application binary\n", options.timer.elapsed());
+ fprintf(stdout, "[TIMING] %d ms: Copied extra libs\n", options.timer.elapsed());
- bool needToCopyGdbServer = options.gdbServer == Options::True
- || (options.gdbServer == Options::Auto && !options.releasePackage);
- if (needToCopyGdbServer && !copyGdbServer(options))
- return CannotCopyGdbServer;
+ if (!copyAndroidExtraResources(&options))
+ return CannotCopyAndroidExtraResources;
if (Q_UNLIKELY(options.timing))
- fprintf(stdout, "[TIMING] %d ms: Copied GDB server\n", options.timer.elapsed());
+ fprintf(stdout, "[TIMING] %d ms: Copied extra resources\n", options.timer.elapsed());
- if (!copyAndroidExtraLibs(options))
- return CannotCopyAndroidExtraLibs;
+ if (!options.auxMode) {
+ if (options.deploymentMechanism != Options::Ministro && !copyStdCpp(&options))
+ return CannotCopyGnuStl;
+
+ if (Q_UNLIKELY(options.timing))
+ fprintf(stdout, "[TIMING] %d ms: Copied GNU STL\n", options.timer.elapsed());
+ }
+
+ if (!containsApplicationBinary(&options))
+ return CannotFindApplicationBinary;
if (Q_UNLIKELY(options.timing))
- fprintf(stdout, "[TIMING] %d ms: Copied extra libs\n", options.timer.elapsed());
+ fprintf(stdout, "[TIMING] %d ms: Checked for application binary\n", options.timer.elapsed());
- if (!copyAndroidExtraResources(options))
- return CannotCopyAndroidExtraResources;
+ if (options.deploymentMechanism != Options::Ministro) {
+ if (Q_UNLIKELY(options.timing))
+ fprintf(stdout, "[TIMING] %d ms: Bundled Qt libs\n", options.timer.elapsed());
+ }
+ }
+
+ if (options.auxMode) {
+ if (!updateAndroidFiles(options))
+ return CannotUpdateAndroidFiles;
+ if (options.generateAssetsFileList && !generateAssetsFileList(options))
+ return CannotGenerateAssetsFileList;
+ return 0;
+ }
+ if (options.build) {
if (!copyAndroidSources(options))
return CannotCopyAndroidSources;
if (Q_UNLIKELY(options.timing))
fprintf(stdout, "[TIMING] %d ms: Copied android sources\n", options.timer.elapsed());
- if (!stripLibraries(options))
- return CannotStripLibraries;
-
- if (Q_UNLIKELY(options.timing))
- fprintf(stdout, "[TIMING] %d ms: Stripped libraries\n", options.timer.elapsed());
-
if (!updateAndroidFiles(options))
return CannotUpdateAndroidFiles;
@@ -2936,7 +2919,7 @@ int main(int argc, char *argv[])
if (options.installApk)
fprintf(stdout, " -- It can now be run from the selected device/emulator.\n");
- fprintf(stdout, " -- File: %s\n", qPrintable(apkPath(options, options.keyStore.isEmpty() ? UnsignedAPK
+ fprintf(stdout, " -- File: %s\n", qPrintable(packagePath(options, options.keyStore.isEmpty() ? UnsignedAPK
: SignedAPK)));
fflush(stdout);
return 0;
diff --git a/src/tools/androidtestrunner/main.cpp b/src/tools/androidtestrunner/main.cpp
index e6d6f72354..f61d407d4a 100644
--- a/src/tools/androidtestrunner/main.cpp
+++ b/src/tools/androidtestrunner/main.cpp
@@ -362,7 +362,7 @@ static bool parseTestArgs()
g_options.testArgs += QStringLiteral(" -o output.%1,%1").arg(format);
g_options.testArgs += unhandledArgs;
- g_options.testArgs = QStringLiteral("shell am start -e applicationArguments \"'%1'\" -n %2/%3").arg(shellQuote(g_options.testArgs.trimmed()),
+ g_options.testArgs = QStringLiteral("shell am start -e applicationArguments \\\"%1\\\" -n %2/%3").arg(shellQuote(g_options.testArgs.trimmed()),
g_options.package,
g_options.activity);
return true;
@@ -409,7 +409,7 @@ static bool pullFiles()
return false;
}
auto checkerIt = g_options.checkFiles.find(it.key());
- ret &= checkerIt != g_options.checkFiles.end() && checkerIt.value()(output);
+ ret = ret && checkerIt != g_options.checkFiles.end() && checkerIt.value()(output);
if (it.value() == QStringLiteral("-")){
fprintf(stdout, "%s", output.constData());
fflush(stdout);
diff --git a/src/tools/bootstrap/bootstrap.pro b/src/tools/bootstrap/bootstrap.pro
index 32e36cefa0..f9ffd1bbea 100644
--- a/src/tools/bootstrap/bootstrap.pro
+++ b/src/tools/bootstrap/bootstrap.pro
@@ -85,7 +85,10 @@ SOURCES += \
../../corelib/text/qstringlist.cpp \
../../corelib/text/qstringview.cpp \
../../corelib/text/qvsnprintf.cpp \
+ ../../corelib/time/qcalendar.cpp \
../../corelib/time/qdatetime.cpp \
+ ../../corelib/time/qgregoriancalendar.cpp \
+ ../../corelib/time/qromancalendar.cpp \
../../corelib/tools/qarraydata.cpp \
../../corelib/tools/qbitarray.cpp \
../../corelib/tools/qcommandlineparser.cpp \
diff --git a/src/tools/qlalr/lalr.cpp b/src/tools/qlalr/lalr.cpp
index b9a9cf264f..c7269bed5f 100644
--- a/src/tools/qlalr/lalr.cpp
+++ b/src/tools/qlalr/lalr.cpp
@@ -297,6 +297,12 @@ void Automaton::build ()
buildDefaultReduceActions ();
}
+#if defined(__cpp_lib_not_fn) && __cpp_lib_not_fn >= 201603
+# define Q_NOT_FN std::not_fn
+#else
+# define Q_NOT_FN std::not1
+#endif
+
void Automaton::buildNullables ()
{
bool changed = true;
@@ -307,7 +313,7 @@ void Automaton::buildNullables ()
for (RulePointer rule = _M_grammar->rules.begin (); rule != _M_grammar->rules.end (); ++rule)
{
- NameList::iterator nn = std::find_if (rule->rhs.begin (), rule->rhs.end (), std::not1 (Nullable (this)));
+ NameList::iterator nn = std::find_if(rule->rhs.begin(), rule->rhs.end(), Q_NOT_FN(Nullable(this)));
if (nn == rule->rhs.end ())
changed |= nullables.insert (rule->lhs).second;
@@ -648,7 +654,7 @@ void Automaton::buildIncludesDigraph ()
if (! _M_grammar->isNonTerminal (*A))
continue;
- NameList::iterator first_not_nullable = std::find_if (dot, rule->rhs.end (), std::not1 (Nullable (this)));
+ NameList::iterator first_not_nullable = std::find_if(dot, rule->rhs.end(), Q_NOT_FN(Nullable(this)));
if (first_not_nullable != rule->rhs.end ())
continue;