Android NDK docs主要专注于构建C/C++ JNI代码。我想做的是构建一个用Go编写的外部动态库,它不使用CMake,也没有JNI Package 器。
对于这个问题,库是用Go写的并不重要,重要的是它不是用C写的。cgo用于为动态(.so)库生成C绑定,我必须将CC=<path/to/android/ndk/clang>
传递给它,以便它可以在内部使用NDK编译器。我不使用JNI。相反,我使用JNA访问libstuff.so
中的C导出方法。
目前,我做以下工作:
1.使用cgo手动构建共享库,并向其传递正确的Android编译器路径
1.将库复制到myapp/src/main/jniLibs/<arch>/libstuff.so
1.构建项目
(我还必须在步骤1中传递CGO_LDFLAGS="-Wl,-soname,libstuff.so"
,否则JNA无法找到它...)
目标
我想做的是在构建Android Gradle项目时自动构建共享库,将正确的编译器二进制文件和架构传递给Go编译器,并将相关架构的libstuff.so
包含在APK中,或者实际上是AAR中,因为我正在构建Android库。
我所尝试的
我尝试了以下CMake脚本:
cmake_minimum_required(VERSION 3.18.1)
project(stuff_project)
include(ExternalProject)
# Test
message("================")
message(ANDROID_ARCH_NAME=${ANDROID_ARCH_NAME})
message("================")
ExternalProject_Add(external_proj
PREFIX "path/to/go/library"
SOURCE_DIR "path/to/go/library"
BUILD_IN_SOURCE 1
CONFIGURE_COMMAND ""
BUILD_COMMAND "<command to build go library>"
INSTALL_COMMAND ""
)
BUILD_COMMAND
中的命令使用带有额外标志${CMAKE_C_FLAGS}
和${CMAKE_SHARED_LINKER_FLAGS}
的${ANDROID_C_COMPILER}
为${ANDROID_ARCH_NAME}
/${ANDROID_LLVM_TRIPLE}
构建库,并将其复制到${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
。
这是受到A/B/WireGuard的启发,在从命令行运行cmake
和cmake --build
时可以正常工作(我没有使用Android编译器或任何东西),但是当使用android { ... externalNativeBuild { cmake { version "3.18.1"; path 'CMakeLists.txt' } } }
运行Gradle时,它只会在配置时打印上面的测试消息,而不会实际构建项目。(也许我必须使external_proj
依赖于某个东西?但依赖于什么呢?)
我该怎么解决这个问题?
相关
WireGuard Android应用程序也使用Go库和uses CMake的add_custom_target
与COMMAND
来构建库。然而,这个库有JNI wrapper并且不使用JNA。我也尝试了add_custom_target
方法,但该命令从未执行。
1条答案
按热度按时间x8goxv8g1#
可能有一种方法可以让它与
ExternalProject_Add
一起工作,但我最终所做的是使用add_custom_target
,并将此目标的名称添加到lib/build.gradle
。模块文件夹中的
CMakeLists.txt
看起来有点像这样:lib/CMakeLists.txt
:你将不得不改变
#TODO
指示的路径和源代码文件名。我个人使用GNU Make来调用go编译器,但为了这个答案我将其改为直接调用go
,使用cmake -E env
以跨平台的方式设置环境变量。然而,使用GNU Make的好处是,当源代码没有改变时,你的库不会被重新构建。源代码的,go
可以被其他编译器替代,只要你适当地调整这个编译器的环境变量。-Wl,-soname,${libname}
链接器标志很重要,因为没有它JNA will not find your library。代码最初是受code for the WireGuard app的启发,但它使用JNI而不是JNA。现在需要在模块的
build.gradle
中添加shared-lib
(add_custom_target
命令中自定义目标的名称)作为依赖项。请注意externalNativeBuild
和defaultConfig.externalNativeBuild
:lib/build.gradle
:这个
build.gradle
是为了构建一个lib/build/outputs/aar
的AAR库而调整的,如果你想在另一个应用程序中包含这个库作为一个单独的“包”(带有一个围绕原生API的 Package 器),这很有用。我还添加了一些你可能需要用于单元测试和仪器测试的代码。对于单元测试,你需要为你自己的PC构建共享库,并将其添加到PATH
。现在您应该能够在Java代码中调用JNA的
Native.load("mycoollibrary", NativeApi.class)
,其中mycoollibrary
对应于您在CMakeLists.txt
中定义的${libname}
的一部分,NativeApi
是您定义的库接口的名称(interface NativeApi extends Library
)。