Makefile 构建系统
本页介绍 fw-AW33N_BLE_SDK 仓库中基于 GNU Make 的两级构建系统:顶层 Makefile 负责调度各子工程,各板级工程 Makefile 负责具体的交叉编译、链接与烧录后处理。
Purpose and Scope
本页覆盖 AW33N BLE SDK 中与 Makefile 构建相关的全部内容:
- 顶层
Makefile的目标调度机制(aw33n_transfer、aw33n_hid等目标); - 板级工程 Makefile(如
apps/demo/hid/board/bd57/Makefile)的工具链选择、编译参数、宏定义、头文件路径与源文件清单的组织方式; - 构建产物的输出位置与后处理(下载)脚本的调用流程;
- 在 Windows 与 Linux 两种宿主环境下构建时的差异处理。
本页不涉及以下内容(属于其他目录页面的范围):SDK 的代码结构总览、具体外设驱动(key/led/usb 等)、BLE 协议栈实现、烧录工具与硬件调试流程。构建产物相关的 apps/app/post_build/bd57/ 目录仅作为构建流程的终点被引用,其详细烧录逻辑不在本页展开。
Overview
该 SDK 采用 Makefile 嵌套调度(recursive make) 的经典构建模式:
- 仓库根目录的
Makefile只做一件事——把make请求转发给各个板级子工程; - 每个子工程目录(如
apps/demo/hid/board/bd57/)下有自己的Makefile,它们才是真正执行编译、链接的地方; - 板级 Makefile 通过
ifeq ($(OS), Windows_NT)判断宿主平台,从而选择 Windows(clang.exe/q32s-lto-wrapper.exe)或 Linux(clang/lto-wrapper)工具链; - 编译使用 LTO(Link-Time Optimization,链接时优化) 与 clang 交叉编译到
q32s目标架构,最终产出sdk.elf及配套的sdk.elf.objs.txt符号文件,并通过后处理脚本触发下载。
该构建系统的设计意图非常明确:顶层只负责"编译哪个 demo",板级 Makefile 负责"如何编译"。这样新增一个 demo(如 transfer、hid)只需在顶层增加一个转发目标,无需复制整套编译规则;而新增一个板型只需复制一份板级 Makefile 并调整宏定义与路径。
顶层支持的目标一览:
| 目标 | 作用 |
|---|---|
make / make all | 依次构建 aw33n_transfer 与 aw33n_hid |
make aw33n_transfer | 构建 transfer demo(进入 apps/demo/transfer/board/bd57) |
make aw33n_hid | 构建 hid demo(进入 apps/demo/hid/board/bd57) |
make clean | 清理两个子工程的临时文件 |
make clean_aw33n_transfer / clean_aw33n_hid | 分别清理对应子工程 |
Architecture
下图展示了整个构建系统的层级结构与数据流:
flowchart TD
subgraph sg_Top["顶层 Makefile(仓库根目录)"]
ALL["all: aw33n_transfer + aw33n_hid"]
CLEAN["clean: 清理两个子工程"]
TGT_T["aw33n_transfer"]
TGT_H["aw33n_hid"]
end
subgraph sg_Transfer["transfer 子工程"]
MK_T["apps/demo/transfer/board/bd57/Makefile"]
OBJ_T["objs/ 中间产物"]
end
subgraph sg_Hid["hid 子工程"]
MK_H["apps/demo/hid/board/bd57/Makefile"]
OBJ_H["objs/ 中间产物"]
end
subgraph sg_Common["板级 Makefile 公共要素"]
TOOL["工具链 clang + LTO<br/>(Windows/Linux 分支)"]
CFLAGS["CFLAGS / DEFINES / INCLUDES"]
SRC["c_SRC_FILES 源文件清单"]
OUT["apps/app/post_build/bd57/sdk.elf"]
POST["download.bat / download.sh 后处理"]
end
ALL --> TGT_T
ALL --> TGT_H
TGT_T -->|"make -C"| MK_T
TGT_H -->|"make -C"| MK_H
CLEAN --> TGT_T
CLEAN --> TGT_H
MK_T --> TOOL
MK_H --> TOOL
TOOL --> CFLAGS
CFLAGS --> SRC
SRC --> OBJ_T
SRC --> OBJ_H
OBJ_T --> OUT
OBJ_H --> OUT
OUT --> POST
各组件职责说明:
- 顶层
Makefile:定义.PHONY目标并做目录转发,本身不包含任何编译规则。它通过$(MAKE) -C <目录> -f Makefile递归调用子工程,clean目标同样转发,保证清理逻辑与构建逻辑在同一个子工程内闭环。 - 板级工程 Makefile:以变量为中心组织构建——先定义工具链、编译参数、宏、头文件路径和源文件列表,再通过这些变量生成编译/链接规则(未在文中展示的规则部分由这些变量驱动)。
- 工具链层:clang 交叉编译器配合 LTO wrapper,产出 q32s 架构的目标文件;
PATH会被显式导出,确保子进程能找到工具。 - 产物与后处理:ELF 统一输出到
apps/app/post_build/bd57/sdk.elf,随后调用对应平台的下载脚本(Windows 用.bat并先用fixbat.exe修复编码,Linux 用.sh),形成"编译 → 链接 → 下载"的完整链路。
顶层 Makefile 详解
仓库根目录的 Makefile 是整个构建的入口。它的全部逻辑可以概括为"目标 → 子工程目录"的映射表,文件头部的注释明确列出了支持的目标与 Linux 下的编译前置条件:
# 总的 Makefile,用于调用目录下各个子工程对应的 Makefile
# 注意: Linux 下编译方式:
# 1. 从 http://pkgman.jieliapp.com/doc/all 处找到下载链接
# 2. 下载后,解压到 /opt/jieli 目录下,保证
# /opt/jieli/common/bin/clang 存在(注意目录层次)
# 3. 确认 ulimit -n 的结果足够大(建议大于8096),否则链接可能会因为打开文件太多而失败
# 可以通过 ulimit -n 8096 来设置一个较大的值
# 支持的目标
# make aw33n_transfer
# make aw33n_hid
Source: Makefile
目标定义与递归调用
所有目标都被声明为 .PHONY,因为它们是动作而非文件:
.PHONY: all clean aw33n_transfer aw33n_hid clean_aw33n_transfer clean_aw33n_hid
all: aw33n_transfer aw33n_hid
@echo +ALL DONE
clean: clean_aw33n_transfer clean_aw33n_hid
@echo +CLEAN DONE
aw33n_transfer:
$(MAKE) -C apps/demo/transfer/board/bd57 -f Makefile
clean_aw33n_transfer:
$(MAKE) -C apps/demo/transfer/board/bd57 -f Makefile clean
aw33n_hid:
$(MAKE) -C apps/demo/hid/board/bd57 -f Makefile
clean_aw33n_hid:
$(MAKE) -C apps/demo/hid/board/bd57 -f Makefile clean
Source: Makefile
设计意图解读:
$(MAKE)而非make:递归 make 的标准做法。$(MAKE)会继承命令行参数(如-j、VERBOSE=1)与变量,保证并行度与详细级别能透传到子工程。-C切换目录:每个 demo 的构建完全在它自己的目录中运行,objs/等中间产物不会相互污染;clean也是同一目录下的make clean,构建/清理职责内聚。- 独立 clean 目标:
clean_aw33n_transfer与clean_aw33n_hid允许只清理一个工程,避免全量重编译。
板级工程 Makefile 详解
以 apps/demo/hid/board/bd57/Makefile 为例,它代表了一类"板级构建描述文件"的完整范式(transfer 工程的 Makefile 结构与其一致,仅宏定义与源文件清单不同)。文件头同样标注了用法:
# make 编译并下载
# make VERBOSE=1 显示编译详细过程
# make clean 清除编译临时文件
Source: apps/demo/hid/board/bd57/Makefile
宿主平台分支:Windows vs Linux
这是板级 Makefile 的第一个关键决策点。通过 ifeq ($(OS), Windows_NT) 将整套工具链与路径配置分成两个互斥分支:
ifeq ($(OS), Windows_NT)
# Windows 下工具链位置
TOOL_DIR := C:/JL/pi32/bin
CC := clang.exe
CXX := clang.exe
LD := q32s-lto-wrapper.exe
AR := llvm-ar.exe
MKDIR := mkdir_win -p
RM := rm -rf
SYS_LIB_DIR := C:/JL/pi32/q32s-lib
SYS_INC_DIR := C:/JL/pi32/q32s-include
EXT_CFLAGS := # Windows 下不需要 -D__SHELL__
export PATH:=$(TOOL_DIR);$(PATH)
## 后处理脚本
FIXBAT := ../../../../../tools/utils/fixbat.exe # 用于处理 utf8->gbk 编码问题
POST_SCRIPT := ../../../../../apps/app/post_build/bd57/download.bat
RUN_POST_SCRIPT := ..\..\..\..\..\apps\app\post_build\bd57\download.bat
else
# Linux 下工具链位置
TOOL_DIR := /opt/jieli/q32s/bin
CC := clang
CXX := clang
LD := lto-wrapper
AR := lto-ar
MKDIR := mkdir -p
RM := rm -rf
export OBJDUMP := $(TOOL_DIR)/objdump
export OBJCOPY := $(TOOL_DIR)/objcopy
export OBJSIZEDUMP := $(TOOL_DIR)/objsizedump
SYS_LIB_DIR := $(TOOL_DIR)/../lib
SYS_INC_DIR := $(TOOL_DIR)/../include
EXT_CFLAGS := -D__SHELL__ # Linux 下需要这个保证正确处理 download.c
export PATH:=$(TOOL_DIR):$(PATH)
## 后处理脚本
FIXBAT := touch # Linux下不需要处理 bat 编码问题
POST_SCRIPT := ../../../../../apps/app/post_build/bd57/download.sh
RUN_POST_SCRIPT := bash $(POST_SCRIPT)
endif
Source: apps/demo/hid/board/bd57/Makefile
该分支的设计意图:
- 工具链前缀统一:分支结束后统一执行
CC := $(TOOL_DIR)/$(CC)等拼接,后续所有规则都引用$(CC)/$(LD),上层逻辑无需关心平台差异; export PATH:把工具目录注入子进程环境,使链接器(LTO wrapper)内部派生的工具(llvm-ar、objcopy等)可以无路径调用;- Linux 额外导出
OBJDUMP/OBJCOPY/OBJSIZEDUMP:供后处理或链接脚本使用; EXT_CFLAGS的差异:Linux 下追加-D__SHELL__,用于让download.c在 Linux 环境中按 shell 语义处理下载逻辑;FIXBAT的差异:Windows 下download.bat需要先由fixbat.exe把 UTF-8 编码转为 GBK,避免中文路径/注释乱码;Linux 下用touch占位(无操作),因为 Linux 脚本无编码问题。这一细节体现了跨平台 CI/开发环境的兼容性考量。
输出与目录变量
CC := $(TOOL_DIR)/$(CC)
CXX := $(TOOL_DIR)/$(CXX)
LD := $(TOOL_DIR)/$(LD)
AR := $(TOOL_DIR)/$(AR)
# 输出文件设置
OUT_ELF := ../../../../../apps/app/post_build/bd57/sdk.elf
OBJ_FILE := $(OUT_ELF).objs.txt
# 编译路径设置
BUILD_DIR := objs
# 工程路径前缀
ROOT_PREFIX := ../../../../..
Source: apps/demo/hid/board/bd57/Makefile
要点:所有路径都基于板级 Makefile 所在目录(apps/demo/hid/board/bd57/)向上回溯 5 层(../../../../../)到达仓库根,再进入 apps/app/post_build/bd57/ 输出 sdk.elf。ROOT_PREFIX 与各头文件路径采用相同的相对回溯策略——这保证了整个工程可以随目录整体搬移而不依赖绝对路径(工具链除外)。OBJ_FILE(sdk.elf.objs.txt)用于记录链接涉及的目标文件清单,便于 LTO 链接与调试。
编译参数 CFLAGS
CFLAGS := \
-flto \
-target q32s \
-integrated-as \
-fno-builtin \
-mllvm -inline-threshold=5 \
-Oz \
-integrated-as \
-g \
-O0 \
-flto \
-Os \
-Wcast-align \
-fallow-pointer-null \
-Wincompatible-pointer-types \
-Wundef \
-fprefer-gnu-section \
-Wframe-larger-than=256 \
-Wreturn-type \
-Wimplicit-function-declaration \
-Werror=jl-arg-struct-check \
-Werror \
-Werror=implicit-function-declaration \
-Werror=return-type \
-Werror=undef \
-fms-extensions \
-Wno-format
Source: apps/demo/hid/board/bd57/Makefile
CFLAGS 的设计意图分析:
-target q32s+-integrated-as:指定交叉编译目标架构,并使用 clang 内置汇编器,避免依赖外部 binutils;-flto与-Oz/-Os:启用链接时优化并激进地优化代码体积。-mllvm -inline-threshold=5降低内联阈值,进一步控制代码膨胀——对 Flash 容量受限的嵌入式 BLE SoC 至关重要;-g与-O0/-Os并存:既保留调试信息(-g),又使用优化(-Os),是嵌入式"可调试的发布构建"常见组合;-O0先出现、-Os后出现,后者生效;-Werror=...系列:把implicit-function-declaration、return-type、undef、自定义的jl-arg-struct-check升级为硬错误,在编译期拦截结构性缺陷(如参数结构体检查是杰理工具链的自定义 pass);-fprefer-gnu-section:为每个函数/数据生成独立 section,配合链接器的--gc-sections风格回收无用代码;-fms-extensions:允许 Microsoft 扩展语法,兼容部分历史代码;-Wno-format:在-Werror全局开启下放行格式串告警,说明嵌入式日志格式串存在大量非标准用法,团队选择容忍而非修复。
CXXFLAGS 为空(该工程为纯 C),DEFINES 与 INCLUDES 在后续小节展开。
宏定义 DEFINES
DEFINES := \
-D__FPGA=0 \
-DLC_MODE \
-DCONFIG_SYS_TIMER_RELATION \
-DCONFIG_CPU_BD57=1 \
-DAPP_BT_BLE=1 \
-DSUPPORT_MS_EXTENSIONS \
-DSUPPORT_RESERVATION_RAM \
-DCONFIG_IIC_VERSION2 \
-DROM_SECURE_BOOT \
-DAPP_CASE_HID \
-DVFS_ENABLE=0 \
-DNEW_JLFS=1 \
-DVM_MAX_SIZE_CONFIG=16*1024 \
-DVM_ITEM_MAX_NUM=128 \
-DSDK_VERSION_CFG_DEFINE=0x110003 \
-DSDK_VERSION_DATE_DEFINE=20260618 \
-DP33_REG_NUM=0x200 \
-DCONFIG_NEW_ECC_ENABLE \
-DCONFIG_RELEASE_ENABLE \
-DCONFIG_SOFT_BASEBAND_ENABLE \
-DCONFIG_BLE_SOFT_BASEBAND_ENABLE \
-DHAS_VFS_EN=1 \
-DNOFLOAT
DEFINES += $(EXT_CFLAGS) # 额外的一些定义
Source: apps/demo/hid/board/bd57/Makefile
DEFINES 是工程配置的"真源",直接决定了固件的功能开关:
- 平台/芯片类:
CONFIG_CPU_BD57=1(BD57 芯片)、P33_REG_NUM=0x200(寄存器窗口)、LC_MODE、VFS_ENABLE=0; - 应用形态类:
APP_BT_BLE=1(BLE 应用)、APP_CASE_HID(HID 场景,这是与 transfer 工程最大的差异点——transfer 会改为APP_CASE_TRANSFER之类); - 软件功能类:
CONFIG_BLE_SOFT_BASEBAND_ENABLE(BLE 软基带)、CONFIG_NEW_ECC_ENABLE(新 ECC 加密)、NEW_JLFS=1(杰理文件系统)、VM_MAX_SIZE_CONFIG/VM_ITEM_MAX_NUM(VM 参数区容量); - 版本信息类:
SDK_VERSION_CFG_DEFINE=0x110003与SDK_VERSION_DATE_DEFINE=20260618会被编译进固件,供运行时查询; NOFLOAT:禁用浮点,显著减小代码体积(BLE 应用通常不需要浮点运算)。
头文件搜索路径 INCLUDES
INCLUDES 采用 -I 形式追加,数量庞大且按模块分组,覆盖 BSP 公共代码、BT 协议栈、RCSP 第三方 profile、demo 私有头文件、系统 include 目录等:
INCLUDES := \
-I../../../../../apps/app/bsp/common/bt_common \
-I../../../../../apps/include_lib/update \
-I../../../../../apps/include_lib/update/code_v2 \
-I../../../../../apps/app/bsp/common/third_party_profile/jieli/JL_rcsp/rcsp_update \
-I../../../../../apps/app/bsp/common/third_party_profile/jieli/JL_rcsp/rcsp_hid \
-I../../../../../apps/app/bsp/common/third_party_profile/jieli/JL_rcsp \
...(共 60+ 条,涵盖 include_lib、app/bsp、demo/hid 等)...
-I$(SYS_INC_DIR)
Source: apps/demo/hid/board/bd57/Makefile
设计要点:路径分为三类——① SDK 内部源码目录(apps/app/bsp/...、apps/demo/...),② 预编译库的头文件目录(apps/include_lib/...、apps/maske_include),③ 工具链系统头文件($(SYS_INC_DIR))。demo 私有头文件(apps/demo/hid/include、apps/demo/hid/board/bd57)按"先公共后私有"的顺序排列,保证同名头文件优先命中公共定义。
源文件清单 c_SRC_FILES
构建的编译单元以显式清单形式给出(c_SRC_FILES := \ 后逐行列出 .c 文件相对路径),例如:
c_SRC_FILES := \
../../../../../apps/app/bsp/common/bt_common/ble_test_api.c \
../../../../../apps/app/bsp/common/code_switch/code_switch.c \
../../../../../apps/app/bsp/common/common_uart/common_uart_control.c \
../../../../../apps/app/bsp/common/config/lib_power_config.c \
../../../../../apps/app/bsp/common/key/key.c \
../../../../../apps/app/bsp/common/key/key_drv_ad.c \
../../../../../apps/app/bsp/common/led/led_control.c \
../../../../../apps/app/bsp/common/mouse_sensor/OMSensor_manage.c \
...(数百个文件,覆盖 BSP 公共模块与 demo 业务代码)...
Source: apps/demo/hid/board/bd57/Makefile
选择"显式清单"而非 wildcard 通配的原因:嵌入式固件的编译集合必须精确可控——避免误编译未参与构建的驱动、控制 Flash 占用、防止同模块多版本文件(如 key_drv_ad.c/key_drv_io.c/key_drv_matrix.c 三种按键驱动)被同时编入。这也意味着新增源文件时必须手动加入该清单,这是该构建系统的主要维护成本与扩展点。
构建产物与后处理
所有板级工程最终把 ELF 输出到统一位置,并由后处理脚本完成下载:
| 变量 | 值 | 说明 |
|---|---|---|
OUT_ELF | apps/app/post_build/bd57/sdk.elf | 最终链接产物 |
OBJ_FILE | $(OUT_ELF).objs.txt | 链接的目标文件清单 |
BUILD_DIR | objs | 中间目标文件目录 |
POST_SCRIPT | download.bat(Win)/ download.sh(Linux) | 下载脚本 |
RUN_POST_SCRIPT | 平台化执行命令 | 构建成功后触发 |
下载脚本路径 apps/app/post_build/bd57/download.bat|sh 与 SDK 配套工具链协作,把 sdk.elf 烧录到目标设备;Windows 分支先经 fixbat.exe 修复 bat 文件编码再执行。
Core Flow
一次完整构建的执行时序
以 make aw33n_hid 为例,整个构建的调用链如下:
sequenceDiagram
participant U as 开发者
participant TM as 顶层 Makefile
participant BM as bd57 板级 Makefile
participant TC as clang 工具链
participant PS as 后处理脚本
U->>TM: make aw33n_hid
activate TM
TM->>TM: 匹配 .PHONY 目标 aw33n_hid
TM->>BM: $(MAKE) -C apps/demo/hid/board/bd57
deactivate TM
activate BM
BM->>BM: 判断 OS(Windows_NT?)选择工具链/脚本
BM->>BM: 组装 CFLAGS / DEFINES / INCLUDES
loop 每个 c_SRC_FILES
BM->>TC: clang -flto -target q32s ... -c
TC-->>BM: objs/*.o
end
BM->>TC: lto-wrapper 链接
TC-->>BM: sdk.elf + sdk.elf.objs.txt
BM->>PS: 运行 download.bat/sh
PS-->>U: 烧录完成
deactivate BM
时序要点:
- 顶层 Makefile 只做"目标名 → 子目录"的匹配转发;
- 板级 Makefile 首先确定宿主平台,从而锁定工具链、系统库/头文件目录与后处理脚本;
- 随后逐个编译清单中的
.c文件,全部产出到objs/; - LTO 链接器把目标文件与
SYS_LIB_DIR中的预编译库合并,产出sdk.elf; - 最后执行下载脚本,完成"编译即烧录"的一键流程。
构建状态机
stateDiagram-v2
[*] --> 解析: make 启动
解析 --> 平台分支: 读取 OS 变量
平台分支 --> 编译: 工具链/宏/路径就绪
编译 --> 链接: 所有 .c 编译完成
链接 --> 后处理: sdk.elf 生成
后处理 --> [*]: 下载脚本执行成功
编译 --> 失败: 编译错误(-Werror)
链接 --> 失败: 打开文件过多(ulimit)
后处理 --> 失败: 烧录/编码错误
失败 --> [*]: make 返回非零
-Werror 把大部分告警升级为编译失败,因此"失败"状态通常伴随明确的诊断信息;链接阶段若宿主打开文件数不足(ulimit -n 过小),LTO 会因句柄耗尽失败——这正是文件头注释建议 ulimit -n 8096 的原因。
Usage Examples
基本用法:一键构建全部 demo
# 编译并下载两个 demo(transfer + hid)
make
# 或显式调用 all 目标
make all
Source: Makefile
构建单个工程
# 只构建 HID 工程并触发下载
make aw33n_hid
# 只构建 transfer 工程
make aw33n_transfer
# 显示编译详细过程(透传至子 make)
make VERBOSE=1 aw33n_hid
Source: Makefile
清理构建产物
# 清理所有子工程
make clean
# 只清理 transfer 工程
make clean_aw33n_transfer
# 只清理 hid 工程
make clean_aw33n_hid
Source: Makefile
Linux 宿主环境准备(按文件头注释)
# 1. 从 pkgman 站点下载工具链并解压到 /opt/jieli
# 2. 确认 clang 路径存在
ls /opt/jieli/common/bin/clang
# 3. 提高文件句柄上限,避免链接失败
ulimit -n 8096
Source: Makefile
Configuration Options
板级 Makefile 中的可配置项汇总(修改时需同步注意平台分支差异):
| 变量 | 类型 | 默认值(Linux) | 默认值(Windows) | 说明 |
|---|---|---|---|---|
TOOL_DIR | 路径 | /opt/jieli/q32s/bin | C:/JL/pi32/bin | 工具链目录 |
CC / CXX | 程序名 | clang | clang.exe | C/C++ 编译器 |
LD | 程序名 | lto-wrapper | q32s-lto-wrapper.exe | LTO 链接器 |
AR | 程序名 | lto-ar | llvm-ar.exe | 归档工具 |
SYS_LIB_DIR | 路径 | $(TOOL_DIR)/../lib | C:/JL/pi32/q32s-lib | 系统预编译库 |
SYS_INC_DIR | 路径 | $(TOOL_DIR)/../include | C:/JL/pi32/q32s-include | 系统头文件 |
EXT_CFLAGS | 宏 | -D__SHELL__ | (空) | 平台附加宏 |
OUT_ELF | 路径 | ../../../../../apps/app/post_build/bd57/sdk.elf | 同左 | 输出 ELF |
BUILD_DIR | 路径 | objs | 同左 | 中间产物目录 |
CFLAGS | 参数串 | -flto -target q32s -Oz -Os ... | 同左 | 编译参数 |
DEFINES | 宏串 | -DAPP_CASE_HID -DAPP_BT_BLE=1 ... | 同左(+EXT_CFLAGS) | 功能宏 |
INCLUDES | 路径串 | -I...(60+ 条) | 同左(含 $(SYS_INC_DIR)) | 头文件路径 |
c_SRC_FILES | 文件清单 | 数百个 .c | 同左 | 编译单元 |
POST_SCRIPT | 脚本路径 | download.sh | download.bat | 后处理脚本 |
RUN_POST_SCRIPT | 命令 | bash $(POST_SCRIPT) | ..\..\..\...\download.bat | 后处理执行方式 |
关键调整点:
- 切换 demo 形态:修改
DEFINES中的APP_CASE_HID为对应宏(如 transfer 场景),并同步增减INCLUDES与c_SRC_FILES; - 切换芯片/板型:修改
CONFIG_CPU_BD57、OUT_ELF/POST_SCRIPT中的bd57路径段及工具链的q32s目标; - 开启/关闭功能:通过增删
DEFINES中的CONFIG_*宏控制,无需改动 C 代码。
API Reference
Make 目标(顶层 Makefile)
| 目标 | 依赖 | 行为 | 等价命令 |
|---|---|---|---|
all | aw33n_transfer、aw33n_hid | 构建全部 demo,打印 +ALL DONE | make |
clean | clean_aw33n_transfer、clean_aw33n_hid | 清理全部,打印 +CLEAN DONE | make clean |
aw33n_transfer | — | $(MAKE) -C apps/demo/transfer/board/bd57 -f Makefile | make aw33n_transfer |
clean_aw33n_transfer | — | 进入 transfer 目录执行 make clean | — |
aw33n_hid | — | $(MAKE) -C apps/demo/hid/board/bd57 -f Makefile | make aw33n_hid |
clean_aw33n_hid | — | 进入 hid 目录执行 make clean | — |
参数: 无显式参数;VERBOSE=1 通过 $(MAKE) 变量传递机制透传到子 make。
返回值: 各目标均为 @echo 输出完成标记;任一子 make 失败时整体返回非零。
板级 Makefile 隐含规则接口
| 接口 | 形式 | 说明 |
|---|---|---|
| 默认目标 | make(无参数) | 编译并下载(构建 + 后处理) |
clean | make clean | 删除 objs/ 等中间产物 |
| 详细模式 | make VERBOSE=1 | 展开编译命令,便于排障 |
| 平台变量 | $(OS) | Windows_NT 触发 Windows 分支,其余走 Linux 分支 |
Failure Modes、边界情况与并发
常见失败模式
| 失败场景 | 症状 | 根因 | 处理方式 |
|---|---|---|---|
| 工具链缺失 | clang: command not found | 未按注释安装/解压工具链到 /opt/jieli(Linux)或 C:/JL/pi32(Windows) | 按 Makefile 头部注释从 pkgman 下载并核对目录层次 |
| 链接期打开文件过多 | LTO 链接报 EMFILE / 文件句柄类错误 | ulimit -n 过小,LTO 需并行打开大量目标文件 | ulimit -n 8096 或更大 |
| 编译硬错误 | error: ... [-Werror] | -Werror 系列将 implicit-function-declaration、return-type、undef、jl-arg-struct-check 等告警升级为错误 | 修复源码;jl-arg-struct-check 为杰理自定义 pass,需保证函数参数结构体声明一致 |
| 新增源文件未加入清单 | 链接时报未定义符号 / 功能缺失 | c_SRC_FILES 为显式清单,无通配符自动收集 | 手动把 .c 文件加入 c_SRC_FILES |
| 平台分支错配 | 后处理脚本找不到 / 编码乱码 | 在非 Windows 环境检测到 Windows_NT,或反之 | 确认 $(OS) 判定;Windows 需先 fixbat.exe 转换 bat 编码 |
| 下载失败 | 后处理脚本返回非零 | 目标设备未连接 / 端口占用 / download.c 未定义 __SHELL__ | 检查设备与脚本;Linux 必须保留 EXT_CFLAGS := -D__SHELL__ |
边界情况
$(OS)判定的隐含假设:只有Windows_NT走 Windows 分支,macOS 等 Unix 系会被归入 Linux 分支(clang、lto-wrapper命名一致,但SYS_LIB_DIR等路径按 Linux 布局假设);VERBOSE=1的透传:依赖$(MAKE)的变量继承机制,直接调用板级 Makefile(make -C apps/demo/hid/board/bd57)同样生效;clean不删除sdk.elf:clean仅转发到子工程清理objs/等临时文件,最终产物apps/app/post_build/bd57/sdk.elf位于构建目录之外,需要手动删除或由后处理覆盖;- 并行构建:顶层
all依赖两个子目标,make -j下两个子工程可并行;但同一子工程内 LTO 对ulimit -n更敏感。
并发与一致性
- 顶层未显式使用
-j控制并行度,完全依赖用户传入;子工程内部对objs/的写操作互不冲突(目录隔离); export PATH是全局副作用,多个子 make 串行执行时无影响;并行执行时工具目录被重复导出,幂等安全;- 两个 demo 共用同一
OUT_ELF路径(post_build/bd57/sdk.elf)——并行构建两个 demo 时存在产物互相覆盖的竞态,官方all目标串行执行(默认无-j)即是为规避该问题,实际使用时应对make -j all保持谨慎。
Performance 与运维建议
- 链接吞吐瓶颈:LTO 是全程序优化,链接阶段占整体构建时间大头,且对文件句柄数敏感(见上文
ulimit建议); - 体积优化优先:
-flto+-Oz/-Os+-fprefer-gnu-section+NOFLOAT的组合明确以代码体积为首要目标,适合 Flash 受限的 BLE SoC;代价是编译时间与调试符号复杂度上升; - 增量构建:
objs/目录按文件产出.o,make 依赖时间戳实现增量;修改DEFINES/CFLAGS后不会自动全量重编,若宏变更未生效,建议先make clean; - CI/多机构建:工具链为绝对路径(
/opt/jieli、C:/JL/pi32),需在各构建机预先安装到相同位置;仓库内部路径全部相对化,支持任意目录检出。
Extension Points
该构建系统的主要扩展方式:
- 新增 demo 工程:在顶层
Makefile增加一个转发目标(xxx: $(MAKE) -C apps/demo/xxx/board/bd57 -f Makefile)及对应clean_xxx,并在all/clean的依赖中加入它;子工程侧复制一份板级 Makefile,修改APP_CASE_*宏与源文件清单; - 新增板型:复制
apps/demo/<demo>/board/<board>/目录,调整CONFIG_CPU_*、OUT_ELF/POST_SCRIPT中的bd57路径段以及工具链 target(q32s);若芯片变化较大还需同步SYS_LIB_DIR/SYS_INC_DIR; - 自定义后处理:替换
POST_SCRIPT/RUN_POST_SCRIPT指向自己的下载/校验脚本;Windows 分支记得保留FIXBAT编码转换步骤; - 功能裁剪:通过增删
DEFINES中的CONFIG_*/SUPPORT_*宏即可开关模块,无需改动业务代码; - 新增编译单元:把
.c文件加入c_SRC_FILES,把对应头文件目录加入INCLUDES——这是所有扩展中最常被遗漏的一步。
Tests
仓库中未发现针对 Makefile 构建系统本身的自动化测试文件(如 CI 脚本或构建自检目标)。构建正确性由以下机制间接保证:
- 编译期
-Werror系列硬错误在最大程度上拦截源码级问题; make clean/make <demo>的往返验证依赖开发者在本地执行;download.bat/download.sh的烧录结果作为最终的端到端验收手段。
建议在新增 demo/板型后至少验证:make clean → make <目标> → 确认 sdk.elf 生成时间戳更新 → 后处理脚本成功退出。
Related Links
- 顶层 Makefile — 构建入口与目标调度
- HID 板级 Makefile — 板级构建配置范本
- transfer 板级 Makefile — 另一 demo 的板级构建配置
apps/app/post_build/bd57/— 构建产物与下载脚本所在目录(烧录细节见对应文档)tools/utils/fixbat.exe— Windows 下 bat 编码转换工具