文章摘要
这是一个Android NDK构建配置文件(Android.mk),用于编译生成名为libmynative.so的动态库。文件定义了编译参数、源文件(mynative.cpp和helper.c)、头文件路径(inc和third/inc目录)以及链接的系统库(log和android)。编译选项指定了C99和C++17标准,并添加了调试信息(-g)。最后通过BUILD_SHARED_LIBRARY指令生成共享库。整个流程包括路径设置、变量清除、模块定义、编译参数配置、依赖库链接和最终构建。
文件内容
# jni/Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := mynative
LOCAL_SRC_FILES := mynative.cpp helper.c
LOCAL_CFLAGS += -std=c99 -g
LOCAL_CPPFLAGS += -std=c++17 -O0 -g
LOCAL_LDLIBS := -llog -landroid
LOCAL_C_INCLUDES := $(LOCAL_PATH)/inc $(LOCAL_PATH)/third/inc
include $(BUILD_SHARED_LIBRARY)
逐行解释
1. LOCAL_PATH := $(call my-dir)
- 作用简述:
设置局部变量LOCAL_PATH
为本 Android.mk 文件所在目录路径。 - 原理说明:
$(call my-dir)
是 NDK build 系统里预定义的函数,返回当前脚本所在目录路径。这样之后的文件引用可用$(LOCAL_PATH)
做路径拼接,保持灵活和可移植。
2. include $(CLEAR_VARS)
- 作用简述:
清除所有上一次设置的 LOCAL_* 变量,开始定义新的模块。 - 原理说明:
Android.mk 可连续写多个模块(例如多个so/a),每开始一个模块要先 include $(CLEAR_VARS),否则变量串台、配置污染。编译系统对每个模块块都执行一次变量清空,避免残留。
3. LOCAL_MODULE := mynative
- 作用简述:
定义本模块的名字为mynative
,最终生成的so叫libmynative.so
。 - 原理说明:
NDK自动给模块名加lib
前缀和.so
后缀,所以不用自己加。它也用这个名字作为后续依赖 (LOCAL_SHARED_LIBRARIES
等) 的标识。不允许重复。
4. LOCAL_SRC_FILES := mynative.cpp helper.c
- 作用简述:
指定本模块要编译的源文件列表(相对于 LOCAL_PATH 路径)。 - 原理说明:
构建系统会自动调用 gcc/g++ 去编译这两个源码,并最终链接为一个 so。cpp 为 C++ 源,c 为 C 源,编译器自动识别。
5. LOCAL_CFLAGS += -std=c99 -g
- 作用简述:
给所有 C 文件编译时添加额外参数:用 C99 标准、生成调试符号。 - 原理说明:
-std=c99
:用 C99 语法规范,高级语法支持更多。-g
:编译生成调试信息,允许 IDE 真机调试(如单步、变量查看),否则只有二进制机器码。
6. LOCAL_CPPFLAGS += -std=c++17 -O0 -g
- 作用简述:
给所有 C++ 文件编译时添加参数:用 C++17 标准、不优化(-O0),生成调试符号。 - 原理说明:
-std=c++17
:现代 C++标准,语法新特性多,推荐习惯。-O0
:不优化,调试场景用,方便断点调试(优化后代码跳行容易失真)。-g
:同样生成调试符号,用于 C++ 源。
7. LOCAL_LDLIBS := -llog -landroid
- 作用简述:
链接目标so时,额外链接 android 系统库 log(liblog.so)和 android(libandroid.so)。 - 原理说明:
-llog
:你代码里如果用__android_log_print
打日志,则必须加。-landroid
:用到 NDK 的某些android
特性、API 时,需加。
NDK会自动在系统NDK路径查找相关库(libxxx.so)链接进来。
8. LOCAL_C_INCLUDES := $(LOCAL_PATH)/inc $(LOCAL_PATH)/third/inc
- 作用简述:
指定头文件搜索路径,告诉编译器除默认外,还去jni/inc
和jni/third/inc
目录找头文件。 - 原理说明:
解决跨文件引用、第三方依赖、自定义头文件查找问题。引用头文件时能找到,不然会编译报错。
9. include $(BUILD_SHARED_LIBRARY)
- 作用简述:
告诉 NDK build 以本块配置,编译生成.so
动态库。 - 原理说明:
NDK定义了一组“构建目标”,此处就会根据上面所有 LOCAL_* 变量做编译->链接->产物生成;你得到的成果为libs/${abi}/libmynative.so
和objs/...
等中间产物。
编译原理总结全流程
- ndk-build 扫描 jni/Android.mk
- 进入第一个块,设定 LOCAL_PATH 为 jni/目录(确保路径所有操作都是对的)
- 清掉所有上一次其他模块(或上次编译遗留)的变量,准备新模块开始
- 设置要生成的 so 名(libmynative.so),记录依赖关系以及后续build步骤
- 记录所有源码列表,建立源文件->目标文件映射
- C/C++编译参数加到编译命令后面:规范语言标准,生成调试符号
- 记录strip后的链接库名,编译时自动链接(否则运行找不到符号报错)
- 记录头文件查找目录,保证项目依赖头文件一体化
- 执行构建目标指令,自动调度所有编译->链接动作
小结
- 每行一条变量,都是给 NDK 编译系统传递构建“参数”
- 你的源码在这个配置下被编译->链接->生成可调试的so,无缝对接Java层和调试器
- 只有配置正确,才能支持复杂的功能、调试与依赖管理