使用Android NDK构建可执行文件
问题描述:
我正尝试使用Android NDK构建可执行文件。为此,我创建了一个“Android库”项目,并将所有我的本地代码(cpp)文件包含在目录“src/main/cpp”下。使用Android NDK构建可执行文件
在CMakeLists.txt文件中,我添加了以下内容。
cmake_minimum_required(VERSION 3.4.1)
set (TEST_SRC
src/test/cpp/test.cpp
)
add_library (test-lib SHARED ${TEST_SRC})
add_executable(test-exec ${TEST_SRC})
当我执行的身材,我看到该库在我的构建输出目录正确创建(libtest-lib.so),但是,可执行文件不生产。
我决定用命令行(./gradlew clean build --info --debug)构建我的项目,并发现以下日志消息。
externalNativeBuildRelease: not building target test-exec because no
targets are specified and library build output file extension isn't
'so'.
看来,在Android NDK是有意禁用我的可执行从在建:(有没有解决的办法还是我指定了不正确的东西
答
更新:??因为我张贴了这个答案,我找到了一个更简洁的解决方案,不需要修改Android.mk
文件中的任何内容,下面是app/build.gradle
的相关部分(原始的gradle脚本属于syncopoli project,您可以找到原始的最新版本的这build.gradle
脚本here:
android {
defaultConfig {
// ...
externalNativeBuild {
ndkBuild {
// I only want the following targets to be built
targets 'rsync', 'ssh'
}
}
ndk {
// add whatever ABIs you want here
abiFilters 'armeabi'
}
}
externalNativeBuild {
ndkBuild {
// all my external sources are under src/main/jni
path 'src/main/jni/Android.mk'
}
}
}
// this is the meat. It copies the binaries to appropriate location
// after externalNativeBuildRelease task is finished.
// you can change the paths to match where your binaries live and where
// you want them to go
gradle.taskGraph.afterTask { task ->
if (task.name == "externalNativeBuildRelease") {
def src = rootProject.file('app/build/intermediates/ndkBuild/release/obj/local/')
def dst = rootProject.file('app/src/main/assets/')
copy {
from(src) {
// the objs directory has all the .o files I don't care about
exclude "**/objs"
}
into dst
// this is purely for debugging purposes. it might come in handy
eachFile {
println "file = " + it.getPath()
}
}
}
}
我src/main/jni/Android.mk
有以下内容:
include $(call all-subdir-makefiles)
以前的答案
我已经打到这个问题,并通过创建gradle这个额外的任务调用手动ndk-build
和设置围绕它的工作该项目取决于这些任务。
这是app/build.gradle
相关部分:
import org.apache.tools.ant.taskdefs.condition.Os
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
task ndkBuild(type: Exec) {
def ndkDirProperty = properties.getProperty('ndk.dir')
def ndkDirPrefix = ndkDirProperty != null ? ndkDirProperty + '/' : ''
def ndkBuildExt = Os.isFamily(Os.FAMILY_WINDOWS) ? ".cmd" : ""
commandLine "${ndkDirPrefix}ndk-build${ndkBuildExt}", '-C', file('src/main').absolutePath,
'-j', Runtime.runtime.availableProcessors()
}
tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn ndkBuild
}
// Cleanup task to remove previously generated binaries
task ndkClean(type: Exec) {
def ndkDirProperty = properties.getProperty('ndk.dir')
def ndkDirPrefix = ndkDirProperty != null ? ndkDirProperty + '/' : ''
def ndkBuildExt = Os.isFamily(Os.FAMILY_WINDOWS) ? ".cmd" : ""
commandLine "${ndkDirPrefix}ndk-build${ndkBuildExt}", '-C', file('src/main').absolutePath, 'clean'
}
tasks.withType(Delete) {
cleanTask -> cleanTask.dependsOn ndkClean
}
我也进一步修改Android.mk
文件的可执行文件,因此最终的可执行assets/<target_arch_abi>/<executable
结束。
SAVED_NDK_APP_DST_DIR := $(NDK_APP_DST_DIR)
NDK_APP_DST_DIR := assets/$(TARGET_ARCH_ABI)
...LOCAL_MODULE/LOCAL_CFLAGS/LOCAL_etc...
include $(BUILD_EXECUTABLE)
NDK_APP_DST_DIR := $(SAVED_NDK_APP_DST_DIR)
现在,运行gradlew build
建立旁边休息的可执行文件。
希望这会有所帮助。