深度解析Android.mk文件:从原理到实战

文章摘要

这是一个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/incjni/third/inc 目录找头文件。
  • 原理说明:
    解决跨文件引用、第三方依赖、自定义头文件查找问题。引用头文件时能找到,不然会编译报错。

9. include $(BUILD_SHARED_LIBRARY)

  • 作用简述:
    告诉 NDK build 以本块配置,编译生成 .so 动态库。
  • 原理说明:
    NDK定义了一组“构建目标”,此处就会根据上面所有 LOCAL_* 变量做编译->链接->产物生成;你得到的成果为 libs/${abi}/libmynative.soobjs/... 等中间产物。

编译原理总结全流程

  1. ndk-build 扫描 jni/Android.mk
  2. 进入第一个块,设定 LOCAL_PATH 为 jni/目录(确保路径所有操作都是对的)
  3. 清掉所有上一次其他模块(或上次编译遗留)的变量,准备新模块开始
  4. 设置要生成的 so 名(libmynative.so),记录依赖关系以及后续build步骤
  5. 记录所有源码列表,建立源文件->目标文件映射
  6. C/C++编译参数加到编译命令后面:规范语言标准,生成调试符号
  7. 记录strip后的链接库名,编译时自动链接(否则运行找不到符号报错)
  8. 记录头文件查找目录,保证项目依赖头文件一体化
  9. 执行构建目标指令,自动调度所有编译->链接动作

小结

  • 每行一条变量,都是给 NDK 编译系统传递构建“参数”
  • 你的源码在这个配置下被编译->链接->生成可调试的so,无缝对接Java层和调试器
  • 只有配置正确,才能支持复杂的功能、调试与依赖管理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你一身傲骨怎能输

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值