杰理 SDK 文档中心
首页
首页
  • SDK 概述与入门

    • SDK 总览
    • 支持芯片与蓝牙认证
    • 工程结构导航
  • 开发环境与构建

    • 环境搭建与工具链安装
    • 编译指南与工程选择
    • 烧录与生产工具
  • BLE 透传/数传应用

    • 透传应用框架与处理模块
    • 透传与数传示例
    • 多连接与自定义服务示例
    • FindMy 与查找网络示例
  • HID 人机交互应用

    • 键盘与按键设备示例
    • 鼠标设备示例
    • 遥控器示例
    • HID 蓝牙应用模块
  • 公共 BSP 模块

    • 按键、编码器与红外输入
    • 传感器驱动
    • LED 与显示控制
    • 串口与 USB 通信
    • 存储、参数与时钟
    • 电源与温度管理
    • 消息、内存与系统配置
    • OTA 升级框架
  • 蓝牙协议栈与库

    • BLE 控制器与协议栈适配
    • 经典蓝牙 BR/EDR 支持
    • 第三方蓝牙协议
    • 设备管理框架
    • DUT 测试与射频认证
  • 构建系统与开发工具

    • Makefile 构建系统
    • 固件后处理与配置工具
    • 辅助脚本与库合并
  • 文档与硬件资料

    • AT 命令参考
    • 硬件参考资料
    • SDK 文档与在线资源

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) 的经典构建模式:

  1. 仓库根目录的 Makefile 只做一件事——把 make 请求转发给各个板级子工程;
  2. 每个子工程目录(如 apps/demo/hid/board/bd57/)下有自己的 Makefile,它们才是真正执行编译、链接的地方;
  3. 板级 Makefile 通过 ifeq ($(OS), Windows_NT) 判断宿主平台,从而选择 Windows(clang.exe / q32s-lto-wrapper.exe)或 Linux(clang / lto-wrapper)工具链;
  4. 编译使用 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_ELFapps/app/post_build/bd57/sdk.elf最终链接产物
OBJ_FILE$(OUT_ELF).objs.txt链接的目标文件清单
BUILD_DIRobjs中间目标文件目录
POST_SCRIPTdownload.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

时序要点:

  1. 顶层 Makefile 只做"目标名 → 子目录"的匹配转发;
  2. 板级 Makefile 首先确定宿主平台,从而锁定工具链、系统库/头文件目录与后处理脚本;
  3. 随后逐个编译清单中的 .c 文件,全部产出到 objs/;
  4. LTO 链接器把目标文件与 SYS_LIB_DIR 中的预编译库合并,产出 sdk.elf;
  5. 最后执行下载脚本,完成"编译即烧录"的一键流程。

构建状态机

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/binC:/JL/pi32/bin工具链目录
CC / CXX程序名clangclang.exeC/C++ 编译器
LD程序名lto-wrapperq32s-lto-wrapper.exeLTO 链接器
AR程序名lto-arllvm-ar.exe归档工具
SYS_LIB_DIR路径$(TOOL_DIR)/../libC:/JL/pi32/q32s-lib系统预编译库
SYS_INC_DIR路径$(TOOL_DIR)/../includeC:/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.shdownload.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)

目标依赖行为等价命令
allaw33n_transfer、aw33n_hid构建全部 demo,打印 +ALL DONEmake
cleanclean_aw33n_transfer、clean_aw33n_hid清理全部,打印 +CLEAN DONEmake clean
aw33n_transfer—$(MAKE) -C apps/demo/transfer/board/bd57 -f Makefilemake aw33n_transfer
clean_aw33n_transfer—进入 transfer 目录执行 make clean—
aw33n_hid—$(MAKE) -C apps/demo/hid/board/bd57 -f Makefilemake aw33n_hid
clean_aw33n_hid—进入 hid 目录执行 make clean—

参数: 无显式参数;VERBOSE=1 通过 $(MAKE) 变量传递机制透传到子 make。

返回值: 各目标均为 @echo 输出完成标记;任一子 make 失败时整体返回非零。

板级 Makefile 隐含规则接口

接口形式说明
默认目标make(无参数)编译并下载(构建 + 后处理)
cleanmake 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

该构建系统的主要扩展方式:

  1. 新增 demo 工程:在顶层 Makefile 增加一个转发目标(xxx: $(MAKE) -C apps/demo/xxx/board/bd57 -f Makefile)及对应 clean_xxx,并在 all/clean 的依赖中加入它;子工程侧复制一份板级 Makefile,修改 APP_CASE_* 宏与源文件清单;
  2. 新增板型:复制 apps/demo/<demo>/board/<board>/ 目录,调整 CONFIG_CPU_*、OUT_ELF/POST_SCRIPT 中的 bd57 路径段以及工具链 target(q32s);若芯片变化较大还需同步 SYS_LIB_DIR/SYS_INC_DIR;
  3. 自定义后处理:替换 POST_SCRIPT/RUN_POST_SCRIPT 指向自己的下载/校验脚本;Windows 分支记得保留 FIXBAT 编码转换步骤;
  4. 功能裁剪:通过增删 DEFINES 中的 CONFIG_*/SUPPORT_* 宏即可开关模块,无需改动业务代码;
  5. 新增编译单元:把 .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 编码转换工具
Next
固件后处理与配置工具