Android ndk-build MK

围巾🧣 2024年10月10日 100次浏览

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_LIBRARIESLOCAL_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)。