Android: Prepare for the worst, when the NDK will remove all GNU tools

In NDKr18 Google removed GCC, most probably the massacre will not end
there and they will remove all GNU tools, so we need to start using LLVM
ones.

This patch still keeps the compatibility with GNU tools if the Qt was
built with android-g++ mkspec.

Change-Id: Ibe1979577e08ce63604d55fc5bbd5f64b3737675
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@qt.io>
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
bb10
BogDan Vatra 2018-11-02 11:41:32 +02:00 committed by Liang Qi
parent 5242540ee4
commit 6fdf398ab4
4 changed files with 78 additions and 48 deletions

View File

@ -41,6 +41,8 @@ ANDROID_SOURCES_CXX_STL_LIBDIR = $$NDK_ROOT/sources/cxx-stl/llvm-libc++/libs/$$A
ANDROID_STDCPP_PATH = $$ANDROID_SOURCES_CXX_STL_LIBDIR/libc++_shared.so
ANDROID_USE_LLVM = true
exists($$ANDROID_SOURCES_CXX_STL_LIBDIR/libc++.so): \
ANDROID_CXX_STL_LIBS = -lc++
else: \

View File

@ -16,6 +16,7 @@ QMAKE_LINK = $$QMAKE_CXX
ANDROID_SOURCES_CXX_STL_LIBDIR = $$NDK_ROOT/sources/cxx-stl/gnu-libstdc++/$$NDK_TOOLCHAIN_VERSION/libs/$$ANDROID_TARGET_ARCH
ANDROID_STDCPP_PATH = $$ANDROID_SOURCES_CXX_STL_LIBDIR/libgnustl_shared.so
ANDROID_CXX_STL_LIBS = -lgnustl_shared -lgcc
ANDROID_USE_LLVM = false
exists($$NDK_ROOT/sysroot/usr/include): \
QMAKE_CFLAGS += --sysroot=$$NDK_ROOT/sysroot \

View File

@ -17,17 +17,22 @@ contains(TEMPLATE, ".*app"):!build_pass:!android-embedded {
isEmpty(NDK_ROOT): NDK_ROOT = $$DEFAULT_ANDROID_NDK_ROOT
FILE_CONTENT += " \"ndk\": $$emitString($$NDK_ROOT),"
NDK_TOOLCHAIN_PREFIX = $$(ANDROID_NDK_TOOLCHAIN_PREFIX)
isEmpty(NDK_TOOLCHAIN_PREFIX) {
equals(ANDROID_TARGET_ARCH, x86): NDK_TOOLCHAIN_PREFIX = x86
else: equals(ANDROID_TARGET_ARCH, x86_64): NDK_TOOLCHAIN_PREFIX = x86_64
else: equals(ANDROID_TARGET_ARCH, mips): NDK_TOOLCHAIN_PREFIX = mipsel-linux-android
else: equals(ANDROID_TARGET_ARCH, mips64): NDK_TOOLCHAIN_PREFIX = mips64el-linux-android
else: equals(ANDROID_TARGET_ARCH, arm64-v8a): NDK_TOOLCHAIN_PREFIX = aarch64-linux-android
else: NDK_TOOLCHAIN_PREFIX = arm-linux-androideabi
equals(ANDROID_USE_LLVM, true) {
FILE_CONTENT += " \"toolchain-prefix\": \"llvm\","
FILE_CONTENT += " \"tool-prefix\": \"llvm\","
} else {
NDK_TOOLCHAIN_PREFIX = $$(ANDROID_NDK_TOOLCHAIN_PREFIX)
isEmpty(NDK_TOOLCHAIN_PREFIX) {
equals(ANDROID_TARGET_ARCH, x86): NDK_TOOLCHAIN_PREFIX = x86
else: equals(ANDROID_TARGET_ARCH, x86_64): NDK_TOOLCHAIN_PREFIX = x86_64
else: equals(ANDROID_TARGET_ARCH, mips): NDK_TOOLCHAIN_PREFIX = mipsel-linux-android
else: equals(ANDROID_TARGET_ARCH, mips64): NDK_TOOLCHAIN_PREFIX = mips64el-linux-android
else: equals(ANDROID_TARGET_ARCH, arm64-v8a): NDK_TOOLCHAIN_PREFIX = aarch64-linux-android
else: NDK_TOOLCHAIN_PREFIX = arm-linux-androideabi
}
FILE_CONTENT += " \"toolchain-prefix\": $$emitString($$NDK_TOOLCHAIN_PREFIX),"
FILE_CONTENT += " \"tool-prefix\": $$emitString($$NDK_TOOLS_PREFIX),"
}
FILE_CONTENT += " \"toolchain-prefix\": $$emitString($$NDK_TOOLCHAIN_PREFIX),"
FILE_CONTENT += " \"tool-prefix\": $$emitString($$NDK_TOOLS_PREFIX),"
NDK_TOOLCHAIN_VERSION = $$(ANDROID_NDK_TOOLCHAIN_VERSION)
isEmpty(NDK_TOOLCHAIN_VERSION): NDK_TOOLCHAIN_VERSION = $$DEFAULT_ANDROID_NDK_TOOLCHAIN_VERSION
@ -63,6 +68,7 @@ contains(TEMPLATE, ".*app"):!build_pass:!android-embedded {
QML_ROOT_PATH = $$_PRO_FILE_PWD_
FILE_CONTENT += " \"qml-root-path\": $$emitString($$QML_ROOT_PATH),"
FILE_CONTENT += " \"stdcpp-path\": $$emitString($$ANDROID_STDCPP_PATH),"
FILE_CONTENT += " \"useLLVM\": $$ANDROID_USE_LLVM,"
FILE_CONTENT += " \"application-binary\": $$emitString($$absolute_path($$DESTDIR, $$OUT_PWD)/$$TARGET)"
FILE_CONTENT += "}"

View File

@ -157,6 +157,7 @@ struct Options
QString toolchainVersion;
QString toolchainPrefix;
QString toolPrefix;
bool useLLVM = false;
QString ndkHost;
// Package information
@ -808,6 +809,11 @@ bool readInputFile(Options *options)
options->ndkPath = ndk.toString();
}
{
const QJsonValue value = jsonObject.value(QStringLiteral("useLLVM"));
options->useLLVM = value.toBool(false);
}
{
const QJsonValue toolchainPrefix = jsonObject.value(QStringLiteral("toolchain-prefix"));
if (toolchainPrefix.isUndefined()) {
@ -827,7 +833,7 @@ bool readInputFile(Options *options)
}
}
{
if (!options->useLLVM) {
const QJsonValue toolchainVersion = jsonObject.value(QStringLiteral("toolchain-version"));
if (toolchainVersion.isUndefined()) {
fprintf(stderr, "No toolchain version defined in json file.\n");
@ -863,15 +869,17 @@ bool readInputFile(Options *options)
{
const QJsonValue stdcppPath = jsonObject.value(QStringLiteral("stdcpp-path"));
if (!stdcppPath.isUndefined()) {
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);
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);
}
{
@ -1546,14 +1554,16 @@ QStringList getQtLibsFromElf(const Options &options, const QString &fileName)
{
QString readElf = options.ndkPath
+ QLatin1String("/toolchains/")
+ options.toolchainPrefix
+ QLatin1Char('-')
+ options.toolchainVersion
+ QLatin1String("/prebuilt/")
+ options.toolchainPrefix;
if (!options.useLLVM)
readElf += QLatin1Char('-') + options.toolchainVersion;
readElf += QLatin1String("/prebuilt/")
+ options.ndkHost
+ QLatin1String("/bin/")
+ options.toolPrefix
+ QLatin1String("-readelf");
+ options.toolPrefix +
(options.useLLVM ? QLatin1String("-readobj") : QLatin1String("-readelf"));
#if defined(Q_OS_WIN32)
readElf += QLatin1String(".exe");
#endif
@ -1563,27 +1573,40 @@ QStringList getQtLibsFromElf(const Options &options, const QString &fileName)
return QStringList();
}
readElf = QString::fromLatin1("%1 -d -W %2").arg(shellQuote(readElf)).arg(shellQuote(fileName));
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));
FILE *readElfCommand = openProcess(readElf);
if (readElfCommand == 0) {
if (!readElfCommand) {
fprintf(stderr, "Cannot execute command %s", qPrintable(readElf));
return QStringList();
}
QStringList ret;
bool readLibs = false;
char buffer[512];
while (fgets(buffer, sizeof(buffer), readElfCommand) != 0) {
QByteArray line = QByteArray::fromRawData(buffer, qstrlen(buffer));
if (line.contains("(NEEDED)") && line.contains("Shared library:") ) {
const int pos = line.lastIndexOf('[') + 1;
QString libraryName = QLatin1String("lib/") + QString::fromLatin1(line.mid(pos, line.length() - pos - 2));
if (QFile::exists(absoluteFilePath(&options, libraryName))) {
ret += libraryName;
QString library;
if (options.useLLVM) {
line = line.trimmed();
if (!readLibs) {
readLibs = line.startsWith("NeededLibraries");
continue;
}
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));
}
QString libraryName = QLatin1String("lib/") + library;
if (QFile::exists(absoluteFilePath(&options, libraryName)))
ret += libraryName;
}
pclose(readElfCommand);
@ -1837,10 +1860,12 @@ bool stripFile(const Options &options, const QString &fileName)
{
QString strip = options.ndkPath
+ QLatin1String("/toolchains/")
+ options.toolchainPrefix
+ QLatin1Char('-')
+ options.toolchainVersion
+ QLatin1String("/prebuilt/")
+ options.toolchainPrefix;
if (!options.useLLVM)
strip += QLatin1Char('-') + options.toolchainVersion;
strip += QLatin1String("/prebuilt/")
+ options.ndkHost
+ QLatin1String("/bin/")
+ options.toolPrefix
@ -1854,7 +1879,10 @@ bool stripFile(const Options &options, const QString &fileName)
return false;
}
strip = QString::fromLatin1("%1 %2").arg(shellQuote(strip)).arg(shellQuote(fileName));
if (options.useLLVM)
strip = QString::fromLatin1("%1 -strip-all -strip-all-gnu %2").arg(shellQuote(strip), shellQuote(fileName));
else
strip = QString::fromLatin1("%1 %2").arg(shellQuote(strip), shellQuote(fileName));
FILE *stripCommand = openProcess(strip);
if (stripCommand == 0) {
@ -2423,22 +2451,15 @@ bool copyStdCpp(Options *options)
if (options->verbose)
fprintf(stdout, "Copying STL library\n");
QString filePath = !options->stdCppPath.isEmpty() ? options->stdCppPath
: options->ndkPath
+ QLatin1String("/sources/cxx-stl/gnu-libstdc++/")
+ options->toolchainVersion
+ QLatin1String("/libs/")
+ options->architecture
+ QLatin1String("/libgnustl_shared.so");
if (!QFile::exists(filePath)) {
fprintf(stderr, "STL library does not exist at %s\n", qPrintable(filePath));
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(filePath, destinationDirectory + QLatin1String("/lib")
if (!copyFileIfNewer(options->stdCppPath, destinationDirectory + QLatin1String("/lib")
+ options->stdCppName + QLatin1String(".so"),
options->verbose)) {
return false;