使用 NDK 13 编译独立的二进制文件
Compile standalone binaries with NDK 13
对于 NDK 10 版本,我曾经使用 ndk-build
为许多不同的 ABI 和多个 API 级别编译独立的二进制文件。这些二进制文件将包含在应用程序中。但是,我在一台新的开发机器上安装了 NDK described in this article. This resulted in a folder ndk-bundle
within my Android SDK directory. I used to compile the code from a command line and then copy the binaries to the resources of my Android Studio project, but I could not figure out how to do this with NDK 13 so I tried to follow the tutorial to include my native code in the Android Studio project。然而,几乎所有最近的说明都假定人们想要构建一个库,而不是一个独立的二进制文件,所以我没有走得太远。
如果我知道如何让它工作,我会切换到 CMake。我的原生项目具有以下(简化)结构:
原生
Android.mk
LOCAL_PATH := $(call my-dir)/my_tool/src
include $(CLEAR_VARS)
LOCAL_MODULE := my_tool
LOCAL_SRC_FILES := main.c
include $(BUILD_EXECUTABLE)
Application.mk
APP_ABI := all
APP_PLATFORM := android-21
my_tool
- 来源
- main.c
如何在我们的 Windows 10 台开发机器上使用 Android Studio 或命令行中的 NDK 编译它?
编辑:
我在build.gradle中使用这个:
externalNativeBuild {
ndkBuild {
path "../native/Android.mk"
}
}
Gradle 创建一个包含构建配置的目录 .externalNativeBuild
,但我无法找到如何实际构建本机代码。当我 运行 gradle.
时没有创建二进制文件
我找不到 关于 ndk-build
的 gradle 配置的任何 信息。
如果您所做的只是更改 NDK 版本,那么我认为这非常简单,我们遗漏了一些简单的东西。我认为您需要更新 PATH 环境变量以指向新的 ndk-bundle
路径并再次尝试 运行ning ndk-build
。
根据我的经验,我无法让 Android 的 Cmake 生成可执行文件(独立二进制文件)或静态库作为最终输出。因为我希望最终输出是可执行文件,所以我不得不改回使用 NDK 而忘记了 Cmake。
更新
这是使用 Android Studio 和 NDK 构建 C++ 可执行文件的方法。这没有使用 CMake,即使您没有 JNI 代码也是如此。
app/build.gradle
sourceSets.main {
// Do not run default ndkbuild
jni.srcDirs = []
// Place where .so libs are available
jniLibs.srcDir 'src/main/libs'
}
task buildNative(type: Exec, description: 'Compile JNI source via NDK') {
def ndkDir = android.ndkDirectory
commandLine "$ndkDir/ndk-build.cmd", 'V=1',
'-C', file('src/main/jni').absolutePath,
'-j', Runtime.runtime.availableProcessors(),
'all',
'NDK_DEBUG=1'
}
task cleanNative(type: Exec, description: 'Clean JNI object files') {
def ndkDir = android.ndkDirectory
commandLine "$ndkDir/ndk-build.cmd",
'-C', file('src/main/jni').absolutePath,
'clean'
}
目录结构
您需要一个名为 app/src/main/jni
的文件夹。如您所见,上面的 gradle 代码只是针对该目录调用 ndk-build
。以下是我建议您设置目录的方法:
jni
Android.mk
LOCAL_PATH := $(call my-dir)
include $(call all-subdir-makefiles)
Application.mk
APP_ABI := all
APP_PLATFORM := android-21
原生
- my_tool
- 来源
- main.c
Android.mk
include $(CLEAR_VARS)
LOCAL_C_INCLUDES := my_tool/src
LOCAL_PATH := $(call my-dir)
LOCAL_MODULE := my_tool
LOCAL_SRC_FILES := my_tool/src/main.c
include $(BUILD_EXECUTABLE)
建筑
要构建,您可以从 app/src/main/jni
目录中 运行 ndk-build
,或者从项目的根目录中 运行 gradle buildNative
。您可以看到在我上面显示的 gradle 代码中,有一个名为 buildNative
的任务,因此这就是将要执行的 gradle 代码。
顶级 Android.mk
文件在您添加更多要在 app/src/main/jni
下构建的模块时提供帮助,它遍历该目录中的所有子目录并调用任何其他 Android.mk
它找到的文件。
我尽量遵循你的简化结构。
这是文件 app/build.gradle:
apply plugin: 'com.android.library'
android {
compileSdkVersion 24
buildToolsVersion "25.0.1"
defaultConfig {
minSdkVersion 21
targetSdkVersion 24
externalNativeBuild {
ndkBuild {
targets "my_tool"
abiFilters "armeabi-v7a"
}
}
}
externalNativeBuild {
ndkBuild {
path "../native/Android.mk"
}
}
}
文件 native/Android.mk 与您的相同:
LOCAL_PATH := $(call my-dir)/my_tool/src
include $(CLEAR_VARS)
LOCAL_MODULE := my_tool
LOCAL_SRC_FILES := main.c
include $(BUILD_EXECUTABLE)
我还有文件 native/main.c 和最小的 app/src/main/AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="my.tool" />
我没有接触 build.gradle 由 Android Studio 向导生成的根脚本:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.0-alpha3'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
现在我可以构建项目了,这是我得到的结果:
$> file ./app/build/intermediates/ndkBuild/debug/obj/local/armeabi-v7a/my_tool
ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked (uses shared libs), not stripped
Android Studio 在默认视图的 cpp 文件夹中显示我的 main.c:
更新:要将可执行文件剥离并打包到 APK 中,必须更改 native/Android.mk:
LOCAL_PATH := $(call my-dir)/my_tool/src
install: LIB_PATH := $(call my-dir)/libs
include $(CLEAR_VARS)
LOCAL_MODULE := my_tool
LOCAL_SRC_FILES := main.c
include $(BUILD_EXECUTABLE)
install: $(LOCAL_INSTALLED)
-mkdir $(LIB_PATH)
-rm -r $(LIB_PATH)
mv $< $(<:my_tool=lib-my_tool-.so)
mv $(realpath $(dir $<)..) $(LIB_PATH)
.PHONY: install
另外,app/build.gradle 需要一些调整:
apply plugin: 'com.android.application'
android {
compileSdkVersion 24
buildToolsVersion "25.0.1"
defaultConfig {
minSdkVersion 21
targetSdkVersion 24
externalNativeBuild {
ndkBuild {
targets "my_tool"
abiFilters "armeabi-v7a"
arguments 'V=1', 'install'
}
}
}
externalNativeBuild {
ndkBuild {
path "../native/Android.mk"
}
}
sourceSets {
main {
jniLibs.srcDirs = ['../native/libs']
}
}
}
这依赖于 old hack,它依赖于 NDK 的未记录行为,并且可能会在未来的 NDK 升级时中断,恕不另行通知。
对于 NDK 10 版本,我曾经使用 ndk-build
为许多不同的 ABI 和多个 API 级别编译独立的二进制文件。这些二进制文件将包含在应用程序中。但是,我在一台新的开发机器上安装了 NDK described in this article. This resulted in a folder ndk-bundle
within my Android SDK directory. I used to compile the code from a command line and then copy the binaries to the resources of my Android Studio project, but I could not figure out how to do this with NDK 13 so I tried to follow the tutorial to include my native code in the Android Studio project。然而,几乎所有最近的说明都假定人们想要构建一个库,而不是一个独立的二进制文件,所以我没有走得太远。
如果我知道如何让它工作,我会切换到 CMake。我的原生项目具有以下(简化)结构:
原生
Android.mk
LOCAL_PATH := $(call my-dir)/my_tool/src include $(CLEAR_VARS) LOCAL_MODULE := my_tool LOCAL_SRC_FILES := main.c include $(BUILD_EXECUTABLE)
Application.mk
APP_ABI := all APP_PLATFORM := android-21
my_tool
- 来源
- main.c
- 来源
如何在我们的 Windows 10 台开发机器上使用 Android Studio 或命令行中的 NDK 编译它?
编辑:
我在build.gradle中使用这个:
externalNativeBuild {
ndkBuild {
path "../native/Android.mk"
}
}
Gradle 创建一个包含构建配置的目录 .externalNativeBuild
,但我无法找到如何实际构建本机代码。当我 运行 gradle.
我找不到 关于 ndk-build
的 gradle 配置的任何 信息。
如果您所做的只是更改 NDK 版本,那么我认为这非常简单,我们遗漏了一些简单的东西。我认为您需要更新 PATH 环境变量以指向新的 ndk-bundle
路径并再次尝试 运行ning ndk-build
。
根据我的经验,我无法让 Android 的 Cmake 生成可执行文件(独立二进制文件)或静态库作为最终输出。因为我希望最终输出是可执行文件,所以我不得不改回使用 NDK 而忘记了 Cmake。
更新
这是使用 Android Studio 和 NDK 构建 C++ 可执行文件的方法。这没有使用 CMake,即使您没有 JNI 代码也是如此。
app/build.gradle
sourceSets.main {
// Do not run default ndkbuild
jni.srcDirs = []
// Place where .so libs are available
jniLibs.srcDir 'src/main/libs'
}
task buildNative(type: Exec, description: 'Compile JNI source via NDK') {
def ndkDir = android.ndkDirectory
commandLine "$ndkDir/ndk-build.cmd", 'V=1',
'-C', file('src/main/jni').absolutePath,
'-j', Runtime.runtime.availableProcessors(),
'all',
'NDK_DEBUG=1'
}
task cleanNative(type: Exec, description: 'Clean JNI object files') {
def ndkDir = android.ndkDirectory
commandLine "$ndkDir/ndk-build.cmd",
'-C', file('src/main/jni').absolutePath,
'clean'
}
目录结构
您需要一个名为 app/src/main/jni
的文件夹。如您所见,上面的 gradle 代码只是针对该目录调用 ndk-build
。以下是我建议您设置目录的方法:
jni
Android.mk
LOCAL_PATH := $(call my-dir) include $(call all-subdir-makefiles)
Application.mk
APP_ABI := all APP_PLATFORM := android-21
原生
- my_tool
- 来源
- main.c
- 来源
Android.mk
include $(CLEAR_VARS) LOCAL_C_INCLUDES := my_tool/src LOCAL_PATH := $(call my-dir) LOCAL_MODULE := my_tool LOCAL_SRC_FILES := my_tool/src/main.c include $(BUILD_EXECUTABLE)
- my_tool
建筑
要构建,您可以从 app/src/main/jni
目录中 运行 ndk-build
,或者从项目的根目录中 运行 gradle buildNative
。您可以看到在我上面显示的 gradle 代码中,有一个名为 buildNative
的任务,因此这就是将要执行的 gradle 代码。
顶级 Android.mk
文件在您添加更多要在 app/src/main/jni
下构建的模块时提供帮助,它遍历该目录中的所有子目录并调用任何其他 Android.mk
它找到的文件。
我尽量遵循你的简化结构。
这是文件 app/build.gradle:
apply plugin: 'com.android.library'
android {
compileSdkVersion 24
buildToolsVersion "25.0.1"
defaultConfig {
minSdkVersion 21
targetSdkVersion 24
externalNativeBuild {
ndkBuild {
targets "my_tool"
abiFilters "armeabi-v7a"
}
}
}
externalNativeBuild {
ndkBuild {
path "../native/Android.mk"
}
}
}
文件 native/Android.mk 与您的相同:
LOCAL_PATH := $(call my-dir)/my_tool/src
include $(CLEAR_VARS)
LOCAL_MODULE := my_tool
LOCAL_SRC_FILES := main.c
include $(BUILD_EXECUTABLE)
我还有文件 native/main.c 和最小的 app/src/main/AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="my.tool" />
我没有接触 build.gradle 由 Android Studio 向导生成的根脚本:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.0-alpha3'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
现在我可以构建项目了,这是我得到的结果:
$> file ./app/build/intermediates/ndkBuild/debug/obj/local/armeabi-v7a/my_tool
ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked (uses shared libs), not stripped
Android Studio 在默认视图的 cpp 文件夹中显示我的 main.c:
更新:要将可执行文件剥离并打包到 APK 中,必须更改 native/Android.mk:
LOCAL_PATH := $(call my-dir)/my_tool/src
install: LIB_PATH := $(call my-dir)/libs
include $(CLEAR_VARS)
LOCAL_MODULE := my_tool
LOCAL_SRC_FILES := main.c
include $(BUILD_EXECUTABLE)
install: $(LOCAL_INSTALLED)
-mkdir $(LIB_PATH)
-rm -r $(LIB_PATH)
mv $< $(<:my_tool=lib-my_tool-.so)
mv $(realpath $(dir $<)..) $(LIB_PATH)
.PHONY: install
另外,app/build.gradle 需要一些调整:
apply plugin: 'com.android.application'
android {
compileSdkVersion 24
buildToolsVersion "25.0.1"
defaultConfig {
minSdkVersion 21
targetSdkVersion 24
externalNativeBuild {
ndkBuild {
targets "my_tool"
abiFilters "armeabi-v7a"
arguments 'V=1', 'install'
}
}
}
externalNativeBuild {
ndkBuild {
path "../native/Android.mk"
}
}
sourceSets {
main {
jniLibs.srcDirs = ['../native/libs']
}
}
}
这依赖于 old hack,它依赖于 NDK 的未记录行为,并且可能会在未来的 NDK 升级时中断,恕不另行通知。