Skip to content

Commit

Permalink
Android: Prepare for the worst, when the NDK will remove all GNU tools
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Eskil Abrahamsen Blomfeldt <[email protected]>
  • Loading branch information
bog-dan-ro authored and liangqi committed Nov 19, 2018
1 parent 5242540 commit 6fdf398
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 48 deletions.
2 changes: 2 additions & 0 deletions mkspecs/android-clang/qmake.conf
Original file line number Diff line number Diff line change
Expand Up @@ -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: \
Expand Down
1 change: 1 addition & 0 deletions mkspecs/android-g++/qmake.conf
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
26 changes: 16 additions & 10 deletions mkspecs/features/android/android_deployment_settings.prf
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 += "}"
Expand Down
97 changes: 59 additions & 38 deletions src/tools/androiddeployqt/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ struct Options
QString toolchainVersion;
QString toolchainPrefix;
QString toolPrefix;
bool useLLVM = false;
QString ndkHost;

// Package information
Expand Down Expand Up @@ -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()) {
Expand All @@ -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");
Expand Down Expand Up @@ -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);
}

{
Expand Down Expand Up @@ -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
Expand All @@ -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);
Expand Down Expand Up @@ -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
Expand All @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 6fdf398

Please sign in to comment.