我正在尝试使用Android NDK构建可执行文件。为此,我创建了一个“Android库”项目,并在其目录“src / main / cpp”下包含了我的所有本机代码(cpp)文件。
在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故意禁止我的可执行文件被构建:(有没有办法解决这个问题?或者我是否指定了错误的内容?
答案 0 :(得分:2)
更新:由于我发布了这个答案,我找到了一个更清洁的解决方案。无需修改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
会将可执行文件与其他可执行文件一起构建。
希望这有帮助。