使用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建立旁边休息的可执行文件。

希望这会有所帮助。