Android.mk
是 Android NDK 构建系统使用的 Makefile 语法文件,用于定义本地代码(C/C++)的编译规则。以下是其核心语法和常见用法详解:
一、基础语法结构
1. 模块定义
每个模块以 include $(CLEAR_VARS)
开头,以 include $(BUILD_XXX)
结束:
include $(CLEAR_VARS) # 清除之前的变量定义
LOCAL_MODULE := mymodule # 模块名称(必须唯一)
LOCAL_SRC_FILES := a.cpp b.cpp # 源文件列表
include $(BUILD_SHARED_LIBRARY) # 构建共享库(.so)
2. 构建类型
BUILD_SHARED_LIBRARY
:生成动态库(.so
)BUILD_STATIC_LIBRARY
:生成静态库(.a
)BUILD_EXECUTABLE
:生成可执行文件
二、关键变量
1. 必填变量
LOCAL_MODULE
:模块名称(不可有空格,需唯一)LOCAL_SRC_FILES
:源文件列表(支持相对路径)
2. 常用变量
-
LOCAL_C_INCLUDES
:头文件搜索路径LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-
LOCAL_CFLAGS
:C/C++ 编译选项LOCAL_CFLAGS += -Wall -O2 -DDEBUG=1
-
LOCAL_LDLIBS
:链接系统库(如-llog
链接 Android 日志库)LOCAL_LDLIBS += -llog -lz
-
LOCAL_SHARED_LIBRARIES
:依赖的其他动态库LOCAL_SHARED_LIBRARIES := otherlib
-
LOCAL_STATIC_LIBRARIES
:依赖的静态库LOCAL_STATIC_LIBRARIES := mystaticlib
3. 条件编译
使用 ifeq
/else
根据变量(如 TARGET_ARCH
)调整配置:
ifeq ($(TARGET_ARCH),arm)
LOCAL_CFLAGS += -DARM=1
else
LOCAL_CFLAGS += -DX86=1
endif
三、多模块管理
1. 静态库依赖
# 定义静态库模块
include $(CLEAR_VARS)
LOCAL_MODULE := mystaticlib
LOCAL_SRC_FILES := utils.cpp
include $(BUILD_STATIC_LIBRARY)
# 主模块依赖静态库
include $(CLEAR_VARS)
LOCAL_MODULE := main
LOCAL_SRC_FILES := main.cpp
LOCAL_STATIC_LIBRARIES := mystaticlib
include $(BUILD_SHARED_LIBRARY)
2. 预编译库(Prebuilt)
include $(CLEAR_VARS)
LOCAL_MODULE := prebuiltlib
LOCAL_SRC_FILES := libs/$(TARGET_ARCH_ABI)/libprebuilt.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY) # 预编译动态库
四、路径与文件操作
1. 文件遍历
使用 $(wildcard)
遍历文件:
MY_SRC_FILES := $(wildcard $(LOCAL_PATH)/src/*.cpp)
LOCAL_SRC_FILES += $(MY_SRC_FILES:$(LOCAL_PATH)/%=%)
2. 相对路径
$(LOCAL_PATH)
:当前Android.mk
所在目录$(TARGET_OUT)
:目标输出目录(如obj/
或libs/
)
五、高级用法
1. 自定义构建规则
$(warning "Building for ABI: $(TARGET_ARCH_ABI)")
2. 链接器选项
通过 LOCAL_LDFLAGS
传递链接选项:
LOCAL_LDFLAGS += -Wl,--no-undefined
3. ABI 过滤
在 Application.mk
中指定支持的 ABI:
APP_ABI := armeabi-v7a arm64-v8a x86 x86_64
六、常见问题
1. 错误:undefined reference to
- 检查
LOCAL_STATIC_LIBRARIES
或LOCAL_SHARED_LIBRARIES
是否声明依赖。
2. 头文件找不到
- 确认
LOCAL_C_INCLUDES
路径是否正确。
3. 重复符号(Duplicate Symbols)
- 确保模块名称唯一,避免重复编译同一文件。
七、完整示例
LOCAL_PATH := $(call my-dir)
# 预编译库
include $(CLEAR_VARS)
LOCAL_MODULE := myprebuilt
LOCAL_SRC_FILES := prebuilt/$(TARGET_ARCH_ABI)/libfoo.so
include $(PREBUILT_SHARED_LIBRARY)
# 主模块
include $(CLEAR_VARS)
LOCAL_MODULE := native-lib
LOCAL_SRC_FILES := main.cpp utils.cpp
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_CFLAGS += -DANDROID=1
LOCAL_LDLIBS += -llog -landroid
LOCAL_SHARED_LIBRARIES := myprebuilt
include $(BUILD_SHARED_LIBRARY)
八、与 Application.mk
配合
在 Application.mk
中设置全局配置:
APP_ABI := arm64-v8a # 指定 ABI
APP_PLATFORM := android-21 # 最低 API 级别
APP_OPTIM := release # 优化级别(release/debug)
APP_STL := c++_shared # C++ 运行时库
掌握这些语法和技巧后,可以高效管理 NDK 项目的构建流程。如果需要更现代化的构建方式,建议结合使用 CMake
(通过 CMakeLists.txt
)。