【问题标题】:Building executable with Android NDK使用 Android NDK 构建可执行文件
【发布时间】:2017-06-18 10:09:01
【问题描述】:

我正在尝试使用 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 故意禁止构建我的可执行文件 :( 有没有办法解决这个问题?还是我指定的内容不正确?

【问题讨论】:

    标签: android cmake


    【解决方案1】:

    更新:自从我发布了这个答案后,我找到了一个更清洁的解决方案。无需修改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 会与其余部分一起构建可执行文件。

    希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-11
      相关资源
      最近更新 更多