如何使用 Qt Creator 创建一个不依赖 Android 的单一本地共享库

How to create a single native shared library with no dependency for Android using Qt Creator

我使用 Qt Creator 创建了一个共享库,并且添加了 Android SDK、Android NDK 和 Android Qt 工具包。然后我成功地为 Android 编译了我的库。我什至在 Android 应用程序中成功测试了它。

因为我没有使用 Qt 库,所以我的库不依赖于庞大的 Qt 库。但出乎意料的是,这是我的依赖项:

[matin@Lenovo-X1-Fedora ~]$ ndk-depends libMatinChess.so 
WARNING: Could not find library: libgnustl_shared.so
libMatinChess.so
libz.so
libstdc++.so
libm.so
liblog.so
libgnustl_shared.so
libdl.so
libc.so

当我检查 libgnustl_shared.so 时,它的大小超过 5 MB。所以我必须在每个项目中将这个巨大的图书馆放在我的小图书馆旁边。

另一种选择是 link 它是静态的。我之前问过 如何静态地 link 一个依赖项,我发现可以通过在我的 .pro 文件中添加 QMAKE_LFLAGS += -static 来实现:

此标志完美运行,并消除了 stdc++ 对 Windows 编译的依赖。但是在 android 中我得到以下错误:

error: cannot find -lgnustl_shared
error: cannot find -llog
error: cannot find -lz
error: cannot find -ldl

我搜索了我的 android-ndk 文件夹,发现其中没有 liblog.alibz.alibdl.a 文件,但有一个 libgnustl_static.a 文件.

我尝试使用 LIBS += -Lpath/to/libdir -lgnustl_static 添加它,但结果是一样的。

CMake 中有一个解决方案,在上一个问题中作为评论提到,可以在 makefile 中设置 APP_STL := gnustl_static 的选项。但是QMake中好像没有对应的。

一个复杂的问题是,当我使用 CONFIG += static 时,它编译成功但我的库不再共享。它变成了一个静态库。

我怎样才能 link gnustl 静态地让我的库在没有其他依赖项的情况下工作?

编辑

我阅读编译输出并找到以下行:

/home/matin/Applications/android-ndk-r13b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-g++ --sysroot=/home/matin/Applications/android-ndk-r13b/platforms/android-9/arch-arm/ -static -Wl,--no-undefined -Wl,-z,noexecstack -shared -Wl,-soname,libMatinChess.so -o libMatinChess.so matinchessdll.o bishop.o piece.o board.o king.o memorymanager.o pawn.o queen.o blackpawn.o knight.o rook.o whitepawn.o squarelist.o game.o boardhistory.o -L/home/matin/Applications/android-ndk-r13b/sources/cxx-stl/gnu-libstdc++/4.9/libs/armeabi-v7a -L/home/matin/Applications/android-ndk-r13b/platforms/android-9/arch-arm//usr/lib -lgnustl_shared -llog -lz -lm -ldl -lc -lgcc

而且我无法使用 LIB -= -lgnustl_shared

删除 gnustl_shared

通过阅读编译输出,我手动执行了以下命令并创建了 1 MB 大小的库。它工作正常。

/home/matin/Applications/android-ndk-r13b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-g++ --sysroot=/home/matin/Applications/android-ndk-r13b/platforms/android-9/arch-arm/ -Wl,--no-undefined -Wl,-z,noexecstack -shared -Wl,-soname,libMatinChess.so -o libMatinChess.so matinchessdll.o bishop.o piece.o board.o king.o memorymanager.o pawn.o queen.o blackpawn.o knight.o rook.o whitepawn.o squarelist.o game.o boardhistory.o -L/home/matin/Applications/android-ndk-r13b/sources/cxx-stl/gnu-libstdc++/4.9/libs/armeabi-v7a -L/home/matin/Applications/android-ndk-r13b/platforms/android-9/arch-arm//usr/lib -lgnustl_static

但我仍然不知道如何在 QMake 中自动执行此命令

下面的脚本 android.pri 对我有帮助,我将其包含在我的项目中以消除一些与 QtCreator 相关的错误:

## this file changes many values set by "Qt/mkspec/android-g++/qmake.conf"
## since the failed to work with newest Android SDK and/or NDK
##
## use below lines before including this file
##
#ANDROID_API = 21
#ANDROID_ARCH = armeabi-v7a

#do you after using this have still problems?
#there is an bug inside "QtCreator" (not inside "Gradle")
#   that leads to .o and .so files get not found
#solved: not required to change "QMAKE_LIBDIR" just open "AndroidManifest.xml"
#   and change "Minimum required SDK" to "not set" save then restore to last
#   value and save agian to force "QtCreator" update

isEmpty(ANDROID_API): ANDROID_API = 21
isEmpty(ANDROID_ARCH): ANDROID_ARCH = armeabi-v7a #ANDROID_TARGET_ARCH=armeabi-v7a

#remove old values
CONFIG         -= $$ANDROID_PLATFORM
QMAKE_CFLAGS   -= --sysroot=$$ANDROID_PLATFORM_ROOT_PATH
QMAKE_CXXFLAGS -= --sysroot=$$ANDROID_PLATFORM_ROOT_PATH
QMAKE_LFLAGS   -= --sysroot=$$ANDROID_PLATFORM_ROOT_PATH

#NDK Root directory
ANDROID_NDK_ROOT = $$(ANDROID_NDK_ROOT) #first try Environment variable
isEmpty(ANDROID_NDK_ROOT) | !exists($$ANDROID_NDK_ROOT) {
    ANDROID_NDK_ROOT = D:/android/sdk/ndk-bundle }
NDK_ROOT = $$ANDROID_NDK_ROOT

#API Level
ANDROID_NDK_PLATFORM = android-$$ANDROID_API
ANDROID_PLATFORM = $$ANDROID_NDK_PLATFORM
CONFIG  += $$ANDROID_PLATFORM
DEFINES += __ANDROID_API__=$$ANDROID_API

#Architecture
ANDROID_TARGET_ARCH = $$ANDROID_ARCH
equals(ANDROID_TARGET_ARCH, x86): ANDROID_ARCHITECTURE = x86
else: equals(ANDROID_TARGET_ARCH, x86_64): ANDROID_ARCHITECTURE = x86_64
else: equals(ANDROID_TARGET_ARCH, mips): ANDROID_ARCHITECTURE = mips
else: equals(ANDROID_TARGET_ARCH, mips64): ANDROID_ARCHITECTURE = mips64
else: equals(ANDROID_TARGET_ARCH, arm64-v8a): ANDROID_ARCHITECTURE = arm64
else: ANDROID_ARCHITECTURE = arm

#API Path
ANDROID_PLATFORM_ROOT_PATH  = $$NDK_ROOT/platforms/$$ANDROID_PLATFORM/arch-$$ANDROID_ARCHITECTURE/
ANDROID_PLATFORM_PATH  = $$ANDROID_PLATFORM_ROOT_PATH/usr
QMAKE_CFLAGS   += --sysroot=$$ANDROID_PLATFORM_ROOT_PATH
QMAKE_CXXFLAGS += --sysroot=$$ANDROID_PLATFORM_ROOT_PATH
QMAKE_LFLAGS   += --sysroot=$$ANDROID_PLATFORM_ROOT_PATH

# used to compile platform plugins for android-4 and android-5
QMAKE_ANDROID_PLATFORM_INCDIR = $$NDK_ROOT/sysroot/usr/include #headers bundled
QMAKE_ANDROID_PLATFORM_LIBDIR = $$ANDROID_PLATFORM_PATH/lib #same as before

ANDROID_SOURCES_CXX_STL_LIBDIR = $$NDK_ROOT/sources/cxx-stl/gnu-libstdc++/$$NDK_TOOLCHAIN_VERSION/libs/$$ANDROID_TARGET_ARCH
ANDROID_SOURCES_CXX_STL_INCDIR = $$NDK_ROOT/sources/cxx-stl/gnu-libstdc++/$$NDK_TOOLCHAIN_VERSION/include $$ANDROID_SOURCES_CXX_STL_LIBDIR/include

equals(ANDROID_TARGET_ARCH, x86_64)|equals(ANDROID_TARGET_ARCH, mips64): \
    QMAKE_ANDROID_PLATFORM_LIBDIR = $${QMAKE_ANDROID_PLATFORM_LIBDIR}64

#additionl fix

QMAKE_CFLAGS += -Wno-attributes #ignore Android Macros
QMAKE_CFLAGS += \
    -Wno-unused-parameter \
    -Wno-unused-variable \
    -Wno-unused-but-set-variable \
    -Wno-unused-value \
    -Wno-unused-function

INCLUDEPATH += $$ANDROID_NDK_ROOT/sysroot/usr/include
INCLUDEPATH += $$ANDROID_NDK_ROOT/sysroot/usr/include/arm-linux-androideabi

## you most times need set "ANDROID_PACKAGE_SOURCE_DIR" manualys
isEmpty(ANDROID_PACKAGE_SOURCE_DIR) {
    DISTFILES += \
        $$PWD/res/android/AndroidManifest.xml \
        $$PWD/res/android/gradle/wrapper/gradle-wrapper.jar \
        $$PWD/res/android/gradlew \
        $$PWD/res/android/res/values/libs.xml \
        $$PWD/res/android/build.gradle \
        $$PWD/res/android/gradle/wrapper/gradle-wrapper.properties \
        $$PWD/res/android/gradlew.bat

    ANDROID_PACKAGE_SOURCE_DIR = $$PWD/res/android

    !build_pass:warning(no ANDROID_PACKAGE_SOURCE_DIR defaulted to $$ANDROID_PACKAGE_SOURCE_DIR)
}
#ANDROID_EXTRA_LIBS = $$PWD/libTest.so ## you may need
#ANDROID_DEPLOYMENT_SETTINGS_FILE = $$PWD/android-settings.json ## no need ever

#QML_IMPORT_PATH
#QML_DESIGNER_IMPORT_PATH
#QMAKE_PROJECT_NAME

#isEmpty(ANDROID_PACKAGE_SOURCE_DIR) {
#    # note that $$PWD/android/assets directory is "QFile::ReadOnly" on android
#    android: varDirInstall.path =/assets
#    else: varDirInstall.path =$$OUT_PWD
#
#    varDirInstall.files = $$files($$PWD/android/assets)
#    win32: varDirInstall.files ~= s|\\|/|g
#    varDirInstall.depends += FORCE
#    INSTALLS += varDirInstall
#}

使用示例:

ANDROID_API = 21
ANDROID_ARCH = armeabi-v7a
include($$PWD/android.pri)

但是对于 TEMPLATE = app:

有时我确实会遇到错误

No Android arch set by the .pro file. Error while building/deploying project vpnAndroid (kit: Qt5_android_armeabi-v7a) When executing step "Deploy to Android device"

这个与 QtCreator 相关的特殊错误需要时间来修复:

  1. 关闭 IDE 并删除所有 QtCreator 设置文件(在 windows "C:\Users\Admin\UserName\Roaming\QtProject" 中)
  2. 再次启动 IDE 并按此顺序重新配置 Android 路径、编译器、调试器和工具包
  3. 关闭 IDE 以保存更改
  4. 备份之前提到的文件夹以节省时间见下文:

与 Android 相关的 QtCreator 插件确实在设置中存储失败,因此您需要备份,因为插件可能会再次这样做