【问题标题】:Linking external libraries using NDK, Gradle & CMake in Android Studio在 Android Studio 中使用 NDK、Gradle 和 CMake 链接外部库
【发布时间】:2018-04-11 17:29:31
【问题描述】:

在一段时间后,我回到了 Android 开发,而我的旧基于 ANT 的构建链似乎不再适用于最新的 SDK(这是一个单独的问题),所以我正在尝试以新的方式做事,即基于 gradle 和 CMake。

我有一些我的项目需要的预先构建的静态和动态 3rd 方库,但我无法成功链接这些库。
据我所知,这些需要在“CMakeLists.txt”文件而不是“build.gradle”文件中指定,但我对这两个系统都是新手,所以如果我错了,请纠正我。

这是我迄今为止尝试过的:

  • 首先,我尝试解析子弹的位置。我尝试了一些变体,其中我省略了“lib”、“.a”和“armeabi-v7a”(希望它能够选择正确的 CPU 变体),但没有一个起作用

     find_library(bullet_lib libBullet.a HINTS ${LIBBASE}bullet3/build3/Android/obj/local/armeabi-v7a)
    

    我不确定这与 target_link_libraries 中包含的库有何不同

    add_library(bullet_lib STATIC IMPORTED)
    

    这发现内置库很好,但我收到“bullet”和其他 3rd 方库的链接器错误

    target_link_libraries(my_project_name android log EGL GLESv2 bullet_lib) 
    

${LIBBASE} 是第 3 方库的基本目录,似乎没问题,但还有一件事:CMake 错误似乎没有出现在 android studio 中!我可以通过在包含“CMakeLists.txt”文件的文件夹中运行cmake . 来找出问题所在,但我不太确定我是否使用正确的参数调用它:无论 Android Studio 用 cmake 做什么,而那个文件此时对我来说都是一个黑盒子。

我可以在 android studio 中看到的唯一消息是链接器错误(它没有提到关于找不到库的 CMake 错误,这是导致这些链接器错误的原因:)

Build command failed.
Error while executing process E:\prog\Android\cmake\3.6.4111459\bin\cmake.exe with arguments {--build E:\prog\anthracite\gradle\AnthracitePlayerAPI21\app\.externalNativeBuild\cmake\debug\x86_64 --target anthracite-lib}
[1/1] Linking CXX shared library ..\..\..\..\build\intermediates\cmake\debug\obj\x86_64\libanthracite-lib.so
FAILED: cmd.exe /C "cd . && E:\prog\Android\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++.exe  --target=x86_64-none-linux-android --gcc-toolchain=E:/prog/Android/ndk-bundle/toolchains/x86_64-4.9/prebuilt/windows-x86_64 --sysroot=E:/prog/Android/ndk-bundle/sysroot -fPIC -isystem E:/prog/Android/ndk-bundle/sysroot/usr/include/x86_64-linux-android -D__ANDROID_API__=21 -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wa,--noexecstack -Wformat -Werror=format-security  -std=c++11 -fexceptions -O0 -fno-limit-debug-info  -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libatomic.a --sysroot E:/prog/Android/ndk-bundle/platforms/android-21/arch-x86_64 -Wl,--build-id -Wl,--warn-shared-textrel -Wl,--fatal-warnings -Wl,--no-undefined -Wl,-z,noexecstack -Qunused-arguments -Wl,-z,relro -Wl,-z,now -shared -Wl,-soname,libanthracite-lib.so -o ..\..\..\..\build\intermediates\cmake\debug\obj\x86_64\libanthracite-lib.so @CMakeFiles/anthracite-lib.rsp  && cd ."

E:\prog\anthracite\src/CCmpPhysicsScene3D.cpp:237: error: undefined reference to 'btDbvtBroadphase::btDbvtBroadphase(btOverlappingPairCache*)'
E:\prog\anthracite\src/CCmpPhysicsScene3D.cpp:240: error: undefined reference to 'btDefaultCollisionConfiguration::btDefaultCollisionConfiguration(btDefaultCollisionConstructionInfo const&)'
E:\prog\anthracite\src/CCmpPhysicsScene3D.cpp:242: error: undefined reference to 'btCollisionDispatcher::btCollisionDispatcher(btCollisionConfiguration*)'
E:\prog\anthracite\src/CCmpPhysicsScene3D.cpp:243: error: undefined reference to 'btSequentialImpulseConstraintSolver::btSequentialImpulseConstraintSolver()'
E:\prog\anthracite\src/CCmpPhysicsScene3D.cpp:246: error: undefined reference to 'btDefaultSoftBodySolver::btDefaultSoftBodySolver()'
E:\prog\anthracite\src/CCmpPhysicsScene3D.cpp:247: error: undefined reference to 'btSoftRigidDynamicsWorld::btSoftRigidDynamicsWorld(btDispatcher*, btBroadphaseInterface*, btConstraintSolver*, btCollisionConfiguration*, btSoftBodySolver*)'
E:\prog\anthracite\src/CCmpPhysicsScene3D.cpp:250: error: undefined reference to 'btDiscreteDynamicsWorld::btDiscreteDynamicsWorld(btDispatcher*, btBroadphaseInterface*, btConstraintSolver*, btCollisionConfiguration*)'
E:\prog\anthracite\src/CCmpPhysJointHinge.cpp:117: error: undefined reference to 'btHingeConstraint::btHingeConstraint(btRigidBody&, btVector3 const&, btVector3 const&, bool)'

clang++.exe: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.

并运行“cmake”。从命令行给出:

-- Selecting Windows SDK version 10.0.16299.0 to target Windows 10.0.17133.
CMake Warning at CMakeLists.txt:447 (message):
  resolved libraries:


CMake Warning at CMakeLists.txt:448 (message):
  e:/prog/libs/bullet3/build3/Android/obj/local/armeabi-v7a


CMake Warning at CMakeLists.txt:449 (message):
  bullet_lib-NOTFOUND



-- Configuring done
-- Generating done
-- Build files have been written to: E:/prog/anthracite/gradle/AnthracitePlayerAPI21/app

尽管如上所述,我不确定该输出的真实性,因为“cmake”的调用参数可能与 Android Studio 内部完全不同。 (例如,它默认为 Windows 构建,所以我不确定它是否会寻找“.lib”库而不是“.a”或“.so”)

另外,我在“CMakeLists.txt”文件中使用这些行来报告构建状态:

message(WARNING "resolved libraries:")
message(WARNING ${LIBBASE}bullet3/build3/Android/obj/local/armeabi-v7a)
message(WARNING ${bullet_lib})

无论如何,我显然遗漏了一些东西,并且我无法找到任何关于此的明确指南。这似乎是一件非常简单和明显的事情(链接库),但它似乎是一个巨大的痛苦。 如有任何指示,我将不胜感激。

【问题讨论】:

  • 我在问题帖子中没有看到任何错误消息。我错过了什么吗?
  • 不,抱歉:我没有添加它们。它们是来自 clang 的链接器错误:它没有说明无法从 Android Studio 内部找到库(正如我所说,Android Studio 似乎没有报告 CMake 错误,这不是很有帮助)。我将使用链接器错误更新我的帖子。
  • 如果你走这条添加预建库的路径,这个例子github.com/googlesamples/android-ndk/tree/master/hello-libs 可能会有所帮助:它展示了如何链接(使用 CMake )预建(外部)库。这取决于你想走哪条路,最终你可能会去 ndk-build 路径来跟踪你的代码等。
  • add_library(bullet_lib STATIC IMPORTED) 之后,您需要使用set_target_properties(lib PROPERTIES IMPORTED_LOCATION 添加lib 文件的位置,并使目标包含头文件

标签: android c++ android-studio cmake android-ndk


【解决方案1】:

您必须注意 ABI 不兼容问题。您正在为 x86_64 构建 libanthracite-lib.so,因此您需要 libBullet.a 的相同变体。如果只需要 armeabi-v7a,则必须在 build.gradle 中指定,例如

android {
  externalNativeBuild {
    cmake {
      path 'CMakeLists.txt'
    }
  }
  defaultConfig {
     ndk {
        abiFilters 'armeabi-v7a'
    }
    externalNativeBuild {
      cmake {
         arguments '-DCMAKE_VERBOSE_MAKEFILE=ON'
      }
    }
  }
}

在你的E:\prog\anthracite\gradle\AnthracitePlayerAPI21\app\CMakeLists.txt

add_library(bullet_lib STATIC IMPORTED)
set_target_properties(bullet_lib PROPERTIES IMPORTED_LOCATION
 ${LIBBASE}/bullet3/build3/Android/obj/local/${ANDROID_ABI}/libBullet.a)
target_link_libraries(my_project_name bullet_lib android log EGL GLESv2) 

target_link_libraries 中库的顺序可能很重要,因此请将静态库保留在左侧。

我猜你是用 ndk-build 构建 libBullet.a。您可以为您的 AS 项目创建一个单独的库模块(让我们在 bullet_module 中调用),即使它没有 Java 文件,并将其指向 Android.mk

apply plugin: 'com.android.library'

android {
  compileSdkVersion 27

  defaultConfig {
    ndk {
      abiFilters 'armeabi-v7a'
    }
    externalNativeBuild {
      ndkBuild {
        targets 'Bullet'
      }
    }
  }
  externalNativeBuild {
    ndkBuild {
      path "${LIBBASE}/bullet3/build3/Android/jni/Android.mk"
    }
  }
}

现在您可以更改您的 CMakeLists.txt 以查看 bullet_module 构建的结果:

set_target_properties(bullet_lib PROPERTIES IMPORTED_LOCATION
  <path/to/bullet_module>/build/intermediates/ndkBuild/debug/obj/local/${ANDROID_ABI}/libBullet.a)

【讨论】:

  • 嗨,Alex,根据您在另一个论坛上的建议,我一直在使用旧的 android.mk 构建文件,这些文件以前使用您的建议在下面工作。我还没有得到这个建筑(请参阅stackoverflow.com/questions/49829995/… 了解我当前的链接器问题),但我离得更近了。我也会尝试让它与 CMake 一起工作。感谢您的帮助:我对android NDK开发的了解似乎忘记了一半!
  • 好吧,如果您(几乎)可以使用 ndk-build 构建 libanthracite-lib.so,那么避免使用单独的模块、预构建库等肯定会更容易。 i> 对所有内容都使用 ndk-build 更加简洁,具有“自然”的库依赖关系。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多