构建系统与命令行工具
本页介绍 AD23N SDK 的构建系统:以 sdk/Makefile 为核心的 GNU Make + clang/LLVM 交叉编译体系,以及配套的命令行工具(make_prompt.bat、后处理脚本、烧录工具等),覆盖 Windows/Linux 双平台下的编译、链接、后处理与固件产出全流程。
Purpose and Scope
本页面向需要编译、调试或扩展 AD23N 固件工程的开发者,系统性地说明:
- 三种构建入口:Code::Blocks IDE、Makefile 命令行、VS Code 任务
sdk/Makefile的内部机制:平台分支、工具链定位、编译参数、宏定义、头文件路径、源文件清单- 命令行辅助工具:
make_prompt.bat、fixbat.exe、post_build下载脚本 - 构建产物(
sdk.elf)与后处理流程 - 常见失败模式(工具链缺失、
ulimit不足、编码问题)与扩展方法
以下内容不属于本页范围,请参见对应页面:固件烧录与 USB 升级工具的详细操作(烧录与升级)、SDK 应用工程结构(应用与示例)、环境搭建的下载链接清单(环境搭建)。本页聚焦于"构建系统本身"这一主题边界。
概述
AD23N SDK 采用 Makefile + clang/LLVM 交叉编译工具链 作为命令行构建体系,目标 CPU 架构为 pi32v2(内核版本 r3v2,即 SH59 平台)。仓库源码与预编译库文件(lib.a)配合编译,最终生成 ELF 固件并经由后处理脚本烧录到目标板。
与多数嵌入式 SDK 不同,该构建体系具备以下设计特点:
- 单一 Makefile 双平台适配:通过
ifeq ($(OS), Windows_NT)分支,同一份sdk/Makefile同时支持 Windows(C:/JL/pi32/bin工具链)与 Linux(/opt/jieli/pi32v2/bin工具链),平台差异集中在工具链路径与后处理脚本上。 - LTO 全程序优化:编译参数固定启用
-flto(链接期优化),配合lto-wrapper/pi32v2-lto-wrapper.exe链接器,实现跨编译单元的内联与裁剪;同时用-Oz优先优化代码体积,契合 Flash 容量受限的 MCU 场景。 - 功能宏驱动裁剪:约 40 个
-D宏定义(如HAS_MP3_DECODER、HAS_UPDATE_EN)作为功能开关,决定解码器、编码器、文件系统等模块是否编入固件。 - 编译后处理链:编译完成后通过平台对应的脚本(
download.bat/download.sh)执行固件后处理与下载,Windows 下还需fixbat.exe解决 UTF-8→GBK 编码问题。
用户可根据使用场景选择入口:Windows 桌面用户推荐 Code::Blocks;熟悉命令行的用户推荐 make 命令(经由 make_prompt.bat 进入环境);VS Code 用户可直接使用预配置任务。
架构
下图展示构建系统的整体架构与数据流:
flowchart TD
subgraph sg_Entry["构建入口层"]
CB["Code::Blocks IDE<br/>(AD23N_mbox_flash.cbp)"]
CLI["命令行 make<br/>(make_prompt.bat 环境)"]
VSC["VS Code 任务<br/>(Ctrl+Shift+B)"]
end
subgraph sg_Make["构建核心层"]
MK["sdk/Makefile"]
subgraph sg_Platform["平台分支 ifeq(OS, Windows_NT)"]
WIN["Windows 工具链<br/>C:/JL/pi32/bin"]
LIN["Linux 工具链<br/>/opt/jieli/pi32v2/bin"]
end
CFG["编译参数 CFLAGS / DEFINES / INCLUDES"]
SRC["源文件清单 c_SRC_FILES"]
end
subgraph sg_Toolchain["工具链层 (pi32v2)"]
CC["clang (编译)"]
LD["lto-wrapper (链接)"]
AR["llvm-ar / lto-ar (归档)"]
end
subgraph sg_Output["产出与后处理层"]
ELF["sdk.elf<br/>(app/post_build/sh59/)"]
FIX["fixbat.exe<br/>(UTF-8→GBK)"]
POST["download.bat / download.sh<br/>后处理+下载"]
end
CB --> MK
CLI --> MK
VSC --> MK
MK --> CFG
MK --> SRC
MK --> WIN
MK --> LIN
CFG --> CC
SRC --> CC
WIN --> CC
LIN --> CC
CC --> LD
AR --> LD
LD --> ELF
ELF --> POST
ELF --> FIX
FIX --> POST
POST -->|"固件烧录"| TARGET["目标板 (AD23N 系列)"]
各组件职责说明:
- 构建入口层:三种入口最终都归结为对 Makefile 的调用。Code::Blocks 通过
.cbp工程间接调用同一套编译参数;VS Code 任务封装了 make 命令。 - 构建核心层:
sdk/Makefile是唯一的事实来源,负责平台探测、工具链路径拼接、编译参数组装、源文件枚举与构建规则。 - 平台分支:Windows 与 Linux 的工具链目录、链接器名称、系统库/头文件目录、
EXT_CFLAGS、后处理脚本均在此分支中差异化设置(见下文实现解析)。 - 工具链层:
clang负责将 C 源码编译为 LLVM IR(配合-flto),lto-wrapper在链接期完成跨单元优化并生成最终 ELF,llvm-ar/lto-ar处理静态库归档。 - 产出与后处理层:链接产物
sdk.elf输出到app/post_build/sh59/,随后fixbat.exe(仅 Windows)修正批处理脚本编码,最后download.bat/download.sh执行后处理并触发下载。
该架构的核心设计意图是把平台差异收敛到 Makefile 的分支变量中:上层入口与编译参数不感知平台,工具链切换只需修改一处分支,从而保证双平台构建行为一致。
构建核心:sdk/Makefile 实现解析
sdk/Makefile 是整个构建系统的核心,文件头注释即定义了主要目标:
# make 编译并下载
# make VERBOSE=1 显示编译详细过程
# make clean 清除编译临时文件
Source: sdk/Makefile
平台分支与工具链定位
Makefile 通过 ifeq ($(OS), Windows_NT) 区分 Windows 与 Linux 平台。这一分支决定了工具链目录、编译器/链接器名称、系统库目录、后处理脚本等全部平台相关变量:
ifeq ($(OS), Windows_NT)
# Windows 下工具链位置
TOOL_DIR := C:/JL/pi32/bin
CC := clang.exe
CXX := clang.exe
LD := pi32v2-lto-wrapper.exe
AR := llvm-ar.exe
MKDIR := mkdir_win -p
RM := rm -rf
SYS_LIB_DIR := C:/JL/pi32/pi32v2-lib/r3
SYS_INC_DIR := C:/JL/pi32/pi32v2-include
EXT_CFLAGS := # Windows 下不需要 -D__SHELL__
export PATH:=$(TOOL_DIR);$(PATH)
## 后处理脚本
FIXBAT := tools/utils/fixbat.exe # 用于处理 utf8->gbk 编码问题
POST_SCRIPT := app/post_build/sh59/download.bat
RUN_POST_SCRIPT := app\\post_build\\sh59\\download.bat
else
# Linux 下工具链位置
TOOL_DIR := /opt/jieli/pi32v2/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/r3
SYS_INC_DIR := $(TOOL_DIR)/../include
EXT_CFLAGS := -D__SHELL__ # Linux 下需要这个保证正确处理 download.c
export PATH:=$(TOOL_DIR):$(PATH)
## 后处理脚本
FIXBAT := touch # Linux下不需要处理 bat 编码问题
POST_SCRIPT := app/post_build/sh59/download.sh
RUN_POST_SCRIPT := bash $(POST_SCRIPT)
endif
Source: sdk/Makefile
设计意图解读:
- 工具链目录差异:Windows 工具链默认安装在
C:/JL/pi32,Linux 默认在/opt/jieli/pi32v2(对应 Makefile 头部注释中"解压到 /opt/jieli 目录"的安装指引)。二者目录层次命名不同,因此系统库与头文件目录也分别推导。 EXT_CFLAGS的差异:Windows 分支为空,Linux 分支为-D__SHELL__。注释说明该宏用于保证 Linux 下正确编译download.c(后处理下载程序),是平台相关源码适配的开关。FIXBAT的巧妙替代:Windows 下是fixbat.exe(将生成的 bat 脚本从 UTF-8 转 GBK 以兼容 cmd.exe),Linux 下直接替换为touch(空命令),无需额外工具即可保持构建脚本统一。- 环境变量注入:通过
export PATH:=$(TOOL_DIR);$(PATH)(Windows 用分号、Linux 用冒号)将工具链目录前置注入 PATH,使后续调用clang、lto-wrapper时无需完整路径。
工具链变量随后统一拼上 TOOL_DIR 前缀:
CC := $(TOOL_DIR)/$(CC)
CXX := $(TOOL_DIR)/$(CXX)
LD := $(TOOL_DIR)/$(LD)
AR := $(TOOL_DIR)/$(AR)
# 输出文件设置
OUT_ELF := app/post_build/sh59/sdk.elf
OBJ_FILE := $(OUT_ELF).objs.txt
# 编译路径设置
BUILD_DIR := objs
Source: sdk/Makefile
编译参数(CFLAGS)与功能宏(DEFINES)
编译参数面向 pi32v2 架构固定生成,核心选项包括目标架构、LTO、体积优化与调试信息:
CFLAGS := \
-target pi32v2 \
-mcpu=r3v2 \
-integrated-as \
-flto \
-Wuninitialized \
-Wno-invalid-noreturn \
-fno-common \
-integrated-as \
-Oz \
-g \
-flto \
-fallow-pointer-null \
-fprefer-gnu-section \
-Wno-shift-negative-value \
-Wundef \
Source: sdk/Makefile
关键选项说明:
| 选项 | 作用 | 设计意图 |
|---|---|---|
-target pi32v2 -mcpu=r3v2 | 指定交叉编译目标架构与 CPU 内核 | 将 clang 从宿主编译器变为 pi32v2 交叉编译器 |
-flto | 启用链接期优化 | 跨编译单元内联/裁剪,配合 lto-wrapper 链接器 |
-Oz | 优先优化代码尺寸 | MCU Flash 容量受限,体积优先于速度 |
-g | 生成调试信息 | 支持后续 GDB/反汇编调试 |
-fprefer-gnu-section | 偏好 GNU section 布局 | 配合链接脚本做段级裁剪 |
-fno-common | 禁止 common 段合并 | 避免多文件同名全局变量意外合并 |
功能宏 DEFINES 是固件功能的"总开关",约 40 项,覆盖芯片平台、外设、解码器、编码器与文件系统:
DEFINES := \
-DFPGA=0 \
-DCPU_SH59=1 \
-DAUDIO_ADC_EN=1 \
-DROM_SECURE_BOOT \
-DSPEAKER_EN \
-DHAS_VOICE_PITCH_EN \
-DHAS_VOICE_CHANGER_EN \
-DHAS_PCM_EQ_FLOAT_EN \
-DAUX_EN \
-DENCODER_EN \
-DHAS_UMP3_DECODER \
-DHAS_MP3_ST_DECODER \
-DHAS_WAV_DECODER \
-DHAS_F1A_DECODER \
-DHAS_MAX_F1A_NUMBER=2 \
-DHAS_MIDI_DECODER \
-DHAS_MIDI_KEYBOARD_DECODER \
-DHAS_A_DECODER \
-DHAS_ANS_EN \
-DHAS_SPEED_EN \
-DHAS_EXT_FLASH_EN \
-DHAS_USB_EN=0 \
-DHAS_SDMMC_EN \
-DHAS_HW_SRC_MODULE=1 \
-DHAS_UPDATE_EN=1 \
-DHAS_ECHO_EN \
-DHOWLING_EN \
-DHAS_NORFS_EN \
-DHAS_FATFS_EN \
-DHAS_FREEFS_EN \
-DSIMPLE_FATFS_ENABLE=0 \
-DSYS_VM_EN=0 \
-DHAS_MP3_ENCODER \
-DHAS_UMP3_ENCODER \
-DHAS_A_ENCODER \
-DHAS_SIMPLE_DEC_MODE \
-DHAS_MUSIC_MODE \
-DNOFLOAT \
DEFINES += $(EXT_CFLAGS) # 额外的一些定义
Source: sdk/Makefile
宏分组解读:
- 平台类:
FPGA=0(非 FPGA 验证)、CPU_SH59=1(SH59 内核)、ROM_SECURE_BOOT(安全启动) - 外设类:
AUDIO_ADC_EN、SPEAKER_EN、AUX_EN、ENCODER_EN、HAS_EXT_FLASH_EN、HAS_SDMMC_EN、HAS_HW_SRC_MODULE=1 - 解码器类:
HAS_UMP3_DECODER、HAS_MP3_ST_DECODER、HAS_WAV_DECODER、HAS_F1A_DECODER(含HAS_MAX_F1A_NUMBER=2数量上限)、HAS_MIDI_DECODER、HAS_MIDI_KEYBOARD_DECODER、HAS_A_DECODER - 编码器类:
HAS_MP3_ENCODER、HAS_UMP3_ENCODER、HAS_A_ENCODER - 音效类:
HAS_VOICE_PITCH_EN(变调)、HAS_VOICE_CHANGER_EN(变声)、HAS_PCM_EQ_FLOAT_EN(浮点 EQ)、HAS_ANS_EN(降噪)、HAS_SPEED_EN(变速)、HAS_ECHO_EN(混响)、HOWLING_EN(啸叫抑制) - 文件系统类:
HAS_NORFS_EN、HAS_FATFS_EN、HAS_FREEFS_EN、SIMPLE_FATFS_ENABLE=0、SYS_VM_EN=0 - 系统类:
HAS_USB_EN=0(USB 关闭)、HAS_UPDATE_EN=1(升级使能)、HAS_SIMPLE_DEC_MODE、HAS_MUSIC_MODE、NOFLOAT(禁用浮点运算)
NOFLOAT 与 CFLAGS 中的 -DNOFLOAT 呼应,提示该固件配置为定点运算模式(F1A 解码器通常需要)。修改这些宏即可裁剪/增配固件功能,但需同步确认对应源文件已列入 c_SRC_FILES。
头文件搜索路径与源文件清单
INCLUDES 定义了约 70 个头文件搜索目录,覆盖应用层(app/src/mbox_flash/...)、BSP 层(app/bsp/...)、预编译库头文件(include_lib/...)与系统头文件($(SYS_INC_DIR)):
INCLUDES := \
-Iapp/src \
-Iapp/bsp/common \
-Iapp/bsp/common/fs \
-Iapp/bsp/common/iic_soft \
-Iapp/bsp/common/eeprom \
-Iapp/bsp/common/msg \
-Iapp/bsp/common/file_operate \
-Iapp/bsp/common/api_mg \
-Iapp/bsp/common/key \
-Iapp/bsp/common/power_manage \
-Iapp/bsp/common/norflash \
-Iapp/bsp/common/spi_soft \
-Iapp/bsp/common/reserved_area \
-Iapp/bsp/common/uart_update \
-Iapp/bsp/common/vm \
-Iapp/bsp/cpu/sh59 \
-Iapp/bsp/cpu/sh59/spi \
-Iapp/bsp/cpu/sh59/wdt \
-Iapp/bsp/cpu/sh59/audio \
-Iapp/bsp/lib \
-Iapp/bsp/modules \
-Iapp/bsp/modules/timer \
-Iapp/bsp/start/sh59 \
-Iapp/post_build/sh59 \
-Iinclude_lib \
-Iinclude_lib/common \
-Iinclude_lib/cpu/sh59 \
-Iinclude_lib/cpu \
-Iinclude_lib/fs \
-Iinclude_lib/msg \
-Iinclude_lib/fs/sydf \
-Iinclude_lib/dev_mg \
-Iinclude_lib/audio \
-Iinclude_lib/sdmmc \
-Iinclude_lib/update \
-Iinclude_lib/decoder \
-Iinclude_lib/decoder/list \
-Iinclude_lib/encoder \
-Iinclude_lib/encoder/list \
-Iinclude_lib/device \
-Iinclude_lib/ex_mcu \
-Iinclude_lib/agreement \
-Iinclude_lib/remain_output \
-Iapp/src/mbox_flash \
-Iapp/src/mbox_flash/sh59 \
-Iapp/src/mbox_flash/common \
-Iapp/src/mbox_flash/common/ui \
-Iapp/src/mbox_flash/simple_decode \
-Iapp/src/mbox_flash/linein \
-Iapp/src/mbox_flash/loudspeaker \
-Iapp/src/mbox_flash/idle \
-Iapp/src/mbox_flash/record \
-Iapp/src/mbox_flash/midi_dec \
-Iapp/src/mbox_flash/midi_keyboard \
-Iapp/src/mbox_flash/softoff_app \
-Iapp/src/mbox_flash/usb_slave \
-Iapp/src/mbox_flash/music \
-Iinclude_lib/ans \
-Iapp/bsp/common/speaker \
-Iinclude_lib/speaker \
-Iapp/bsp/common/vo_pitch \
-Iinclude_lib/vo_pitch \
-Iinclude_lib/vo_changer \
-Iapp/bsp/modules/midi \
-Iapp/bsp/modules/midi/pi32v2_lto_r3v2 \
-Iapp/bsp/common/bt_common \
-I$(SYS_INC_DIR) \
Source: sdk/Makefile
路径组织遵循三层结构:
app/层:应用与 BSP 源码目录,app/src/mbox_flash为小音箱应用代码,app/bsp/common为平台无关驱动(key、msg、norflash、fs、vm 等),app/bsp/cpu/sh59为 SH59 CPU 相关驱动(spi、wdt、audio),app/bsp/modules为外设模块(timer、midi)。include_lib/层:预编译库(lib.a)对应的公开头文件,按功能分子目录(decoder、encoder、fs、update、device 等),这是"Release 版 SDK 配合lib.a编译"模式的接口层。$(SYS_INC_DIR)层:工具链自带的系统头文件。
c_SRC_FILES 列出需要编译的全部 .c 文件,覆盖解码器(decoder_api、mp3_standard_api、ump3_api、wav_api、f1a_api、midi_api 等)、编码器(a_encoder、mp3_encoder、ump3_encoder)、文件系统(fat、free_fs、nor_fs、sydf、vfs)、按键、消息、NOR Flash 等:
c_SRC_FILES := \
app/bsp/common/config/lib_power_config.c \
app/bsp/common/decoder/decoder_api.c \
app/bsp/common/decoder/decoder_msg_tab.c \
app/bsp/common/decoder/decoder_point.c \
app/bsp/common/decoder/eq.c \
app/bsp/common/decoder/list/a_api.c \
app/bsp/common/decoder/list/f1a_api.c \
app/bsp/common/decoder/list/f1x_parsing.c \
app/bsp/common/decoder/list/midi_api.c \
app/bsp/common/decoder/list/midi_ctrl_api.c \
app/bsp/common/decoder/list/mp3_standard_api.c \
app/bsp/common/decoder/list/ump3_api.c \
app/bsp/common/decoder/list/wav_api.c \
app/bsp/common/decoder/mp_io.c \
app/bsp/common/decoder/sine_play.c \
app/bsp/common/encoder/encoder_api.c \
app/bsp/common/encoder/list/a_encoder.c \
app/bsp/common/encoder/list/mp3_encoder.c \
app/bsp/common/encoder/list/ump3_encoder.c \
app/bsp/common/fs/fat/fat_resource.c \
app/bsp/common/fs/free_fs/free_fs.c \
app/bsp/common/fs/free_fs/free_fs_resource.c \
app/bsp/common/fs/nor_fs/nor_fs_resource.c \
app/bsp/common/fs/sydf/sydf_resource.c \
app/bsp/common/fs/vfs.c \
app/bsp/common/fs/vfs_fat.c \
app/bsp/common/fs/vfs_resource.c \
app/bsp/common/key/key.c \
app/bsp/common/key/key_drv_ad.c \
app/bsp/common/key/key_drv_io.c \
app/bsp/common/key/key_matrix.c \
app/bsp/common/msg/msg.c \
app/bsp/common/norflash/norflash.c \
...
Source: sdk/Makefile
设计意图:源文件清单以"模块化平铺"方式维护,新增功能模块时需同时修改三处——INCLUDES(头文件路径)、DEFINES(功能宏)与 c_SRC_FILES(源文件)。这种显式枚举虽然冗长,但让每个固件版本的内容完全可审计,避免了通配符隐式引入未预期代码。
核心构建流程
下图展示一次完整的 make 调用从入口到固件产出的执行时序:
sequenceDiagram
participant Dev as 开发者
participant Make as make (Makefile)
participant CC as clang (pi32v2)
participant LD as lto-wrapper
participant Post as post_build 脚本
participant Board as 目标板
Dev->>Make: make -j4 (或 make VERBOSE=1 -j4)
activate Make
Make->>Make: 检测平台 ifeq(OS, Windows_NT)
Make->>Make: 组装 CFLAGS/DEFINES/INCLUDES
loop 每个 .c 文件 (c_SRC_FILES)
Make->>CC: clang -target pi32v2 -flto -Oz -c file.c
CC-->>Make: LLVM IR 目标文件
end
Make->>LD: lto-wrapper 链接 (含 SYS_LIB_DIR/lib.a)
LD-->>Make: app/post_build/sh59/sdk.elf
Make->>Post: 调用 download.bat / download.sh
alt Windows
Post->>Post: fixbat.exe 转换 UTF-8→GBK
end
Post->>Board: 后处理并下载固件
Board-->>Post: 完成
Post-->>Make: 返回
deactivate Make
Make-->>Dev: 构建完成
关键步骤说明:
- 平台探测:Make 首先根据
OS变量选择 Windows/Linux 分支,确定工具链路径与后处理脚本。这一步决定后续所有命令的实际形式(clang.exevsclang、;vs:路径分隔符)。 - 参数组装:
CFLAGS、DEFINES、INCLUDES在 Makefile 解析期拼接为完整命令行,DEFINES += $(EXT_CFLAGS)把平台附加宏并入。 - 并行编译:
-j4让 make 并行编译c_SRC_FILES中的源文件;每个文件经 clang 以-flto模式产出 LLVM IR 中间目标文件(输出目录BUILD_DIR := objs)。 - LTO 链接:
lto-wrapper读取所有 IR 目标文件与系统库(SYS_LIB_DIR下的lib.a),执行链接期优化后生成OUT_ELF := app/post_build/sh59/sdk.elf。Linux 下此步骤对文件描述符数量敏感,故 Makefile 头部注释特别提示ulimit -n需大于 8096。 - 后处理与下载:
RUN_POST_SCRIPT执行download.bat(Windows)或bash download.sh(Linux)。Windows 下生成的 bat 脚本先经fixbat.exe做 UTF-8→GBK 编码转换,避免 cmd.exe 中文乱码;Linux 下FIXBAT := touch为空操作。 - 烧录:后处理脚本连接目标板完成固件下载,构建结束。
命令行工具与辅助脚本
make_prompt.bat — Windows 命令行环境入口
README 指示 Windows 用户先"双击 sdk/make_prompt.bat 打开命令行环境",再执行 make -j4。该脚本的作用是建立与 Makefile 一致的环境(将工具链目录 C:/JL/pi32/bin 注入 PATH),确保在普通 cmd 窗口中输入 make、clang 等命令即可被解析。它本质上是对"工具链环境初始化"的封装,与 Makefile 内部的 export PATH 形成双保险。
fixbat.exe — bat 脚本编码修正工具
位于 tools/utils/fixbat.exe,仅 Windows 分支使用。由于 Makefile 与源码以 UTF-8 编码保存,而 Windows cmd.exe 默认使用 GBK 代码页,直接执行会中文乱码或命令解析错误。fixbat.exe 在下载脚本执行前将其转为 GBK,保证 download.bat 正确运行。Linux 分支用 touch 占位,保持 Makefile 变量引用结构一致。
后处理脚本 — download.bat / download.sh
平台各有一个后处理脚本,路径均为 app/post_build/sh59/:
| 平台 | 脚本 | 触发方式 |
|---|---|---|
| Windows | download.bat | app\\post_build\\sh59\\download.bat |
| Linux | download.sh | bash $(POST_SCRIPT) |
脚本负责编译后的固件后处理(如格式封装、校验)与下载。Linux 分支的 EXT_CFLAGS := -D__SHELL__ 正是为了让与下载相关的 download.c 在 Linux 下能正确编译——README 也提示"Linux 下 Makefile 命令行编译(需要重写 download_bat.c 脚本适配 Linux 环境)",说明下载逻辑的源码实现(download_bat.c)本身是平台相关的。
烧录工具(外部工具)
编译成功后需借助外部工具将固件烧录到目标板:
- USB 升级工具:开发阶段烧录,需目标板进入编程模式(README 提示"编译前请确保 USB 升级工具正确连接且目标板已进入编程模式")。
- 生产烧写工具:量产/裸片烧写,由代理商提供。
使用示例
方式一:命令行 make(推荐 Linux / 进阶用户)
# Windows 用户
双击 sdk/make_prompt.bat 打开命令行环境
# 编译
make -j4
# 显示编译详情
make VERBOSE=1 -j4
Source: README.md
-j4 指定 4 路并行编译;VERBOSE=1 让 make 回显每条实际执行的编译/链接命令,用于排查参数错误或观察工具链调用细节。Makefile 头部注释还声明了 make clean 用于清除编译临时文件(objs/ 目录)。
方式二:Code::Blocks IDE(推荐 Windows 桌面用户)
# 双击打开工程文件
AD23N_mbox_flash.cbp
# 点击 Build → Build(Ctrl+F9)
# 编译成功后,使用 USB 升级工具烧录生成的固件
Source: README.md
.cbp 是 Code::Blocks 工程文件,其编译参数与 Makefile 保持一致(同一套 clang 工具链与宏定义),适合不熟悉命令行的开发者。
方式三:VS Code 任务
# 仓库已预配置 VS Code 任务
# 按 Ctrl+Shift+B 选择编译目标
Source: README.md
验证工具链安装
# 验证工具链是否安装成功
clang --version
Source: README.md
配置选项
构建系统的配置通过修改 Makefile 变量实现,主要可调项如下:
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
TOOL_DIR | 路径 | Windows: C:/JL/pi32/bin;Linux: /opt/jieli/pi32v2/bin | 交叉编译工具链目录 |
SYS_LIB_DIR | 路径 | Windows: C:/JL/pi32/pi32v2-lib/r3;Linux: $(TOOL_DIR)/../lib/r3 | 预编译系统库(lib.a)目录 |
SYS_INC_DIR | 路径 | Windows: C:/JL/pi32/pi32v2-include;Linux: $(TOOL_DIR)/../include | 工具链系统头文件目录 |
OUT_ELF | 路径 | app/post_build/sh59/sdk.elf | 链接产物输出路径 |
BUILD_DIR | 路径 | objs | 编译中间文件目录 |
CFLAGS | 字符串 | -target pi32v2 -mcpu=r3v2 -flto -Oz -g ... | 编译参数 |
DEFINES | 字符串 | 约 40 个 -D 宏(见上文) | 功能开关宏定义 |
EXT_CFLAGS | 字符串 | Windows: 空;Linux: -D__SHELL__ | 平台附加宏 |
FIXBAT | 命令 | Windows: tools/utils/fixbat.exe;Linux: touch | bat 编码修正工具 |
POST_SCRIPT | 路径 | Windows: download.bat;Linux: download.sh | 编译后处理脚本 |
环境级配置(非 Makefile 变量):
| 配置项 | 平台 | 说明 |
|---|---|---|
PATH | 双平台 | 工具链目录需在 PATH 中(Makefile 内已自动注入) |
ulimit -n | Linux | 需大于 8096,否则 LTO 链接可能因打开文件过多失败 |
| 工具链安装位置 | 双平台 | Windows C:/JL/pi32、Linux /opt/jieli/pi32v2,需与 Makefile 分支一致 |
Make 目标参考(API Reference)
构建系统对外暴露的 Make 目标如下(依据 Makefile 头部注释与 README 使用说明):
| 目标 | 等价命令行 | 行为 |
|---|---|---|
默认目标(all) | make -j4 | 编译全部源文件、LTO 链接生成 sdk.elf,并执行后处理/下载 |
| 详细模式 | make VERBOSE=1 -j4 | 与默认目标相同,但回显每条实际执行的命令 |
| 清理 | make clean | 清除编译临时文件(objs/ 构建目录等) |
变量参数:
VERBOSE(整数):置1时打印详细编译命令,用于排查工具链调用问题。-j<N>:GNU make 并行任务数,示例使用-j4。注意 LTO 链接阶段对文件描述符数量敏感(Linux 下需ulimit -n > 8096)。
失败模式、边界情况与并发
工具链缺失或路径不符
构建的第一步是定位 clang/lto-wrapper。若工具链未安装或安装目录与 Makefile 分支不一致(如 Windows 下不在 C:/JL/pi32,Linux 下不在 /opt/jieli/pi32v2),make 将报 command not found 或 No such file or directory。对策:按 README 指引安装杰理编译工具链,并保证目录层次(Makefile 注释强调"保证 /opt/jieli/common/bin/clang 存在(注意目录层次)");或修改 TOOL_DIR 变量适配本机路径。
Linux 链接期文件描述符耗尽
LTO 链接需要同时打开大量中间文件与库文件,若 ulimit -n 过小,链接阶段会失败。Makefile 头部注释明确给出建议:"确认 ulimit -n 的结果足够大(建议大于8096),否则链接可能会因为打开文件太多而失败,可以通过 ulimit -n 8096 来设置一个较大的值"。这是 Linux 平台最典型的构建失败场景之一。
bat 脚本编码问题(Windows)
cmd.exe 默认 GBK 代码页,而工程文件为 UTF-8。若不经过 fixbat.exe 转换,download.bat 可能乱码或执行异常。构建系统通过 FIXBAT 变量自动处理;若用户跳过 make 直接手动运行 download.bat,需自行保证编码正确。
平台相关源码差异
Linux 分支通过 -D__SHELL__ 让 download.c 以 shell 模式编译;README 同时指出 Linux 下"需要重写 download_bat.c 脚本适配 Linux 环境"。若在 Linux 下直接使用 Windows 版本下载逻辑,可能出现编译或执行不匹配。对策:遵循 README 的平台指引,必要时适配 download_bat.c。
并发构建注意事项
-j4 并行编译是安全的——各 .c 文件独立编译为 IR,互不依赖。但后处理/下载阶段涉及目标板连接,属于串行瓶颈;且并行度受限于工具链(LTO 链接本身会占用较多文件描述符),过高的 -j 值可能在链接期放大 ulimit 问题。建议按 README 使用 -j4。
功能宏与源文件一致性
DEFINES 与 c_SRC_FILES 必须保持一致:启用某宏(如 HAS_MIDI_DECODER)却未把对应源文件(midi_api.c)列入清单,或反之,会导致链接期符号缺失或代码冗余。由于清单是显式平铺的,排查此类问题时需交叉核对三处:DEFINES、INCLUDES、c_SRC_FILES。
性能与运维考虑
- 构建速度:
-flto将优化推迟到链接期,首次构建时间主要消耗在 clang 编译与 lto-wrapper 链接两个阶段;增量构建时 make 依据文件时间戳跳过未变更源文件。objs/目录缓存中间产物,make clean可强制全量重建。 - 体积优先:
-Oz配合-fprefer-gnu-section与 LTO 裁剪,使固件体积最小化,适配小 Flash MCU;代价是运行性能非最优,对实时性敏感路径需在代码层面评估。 - 二进制信息:
-g保留调试信息,可结合工具链的objdump/objcopy/objsizedump(Linux 分支显式 export 这些变量)做反汇编与体积分析。 - 固件输出位置固定:
sdk.elf固定输出到app/post_build/sh59/,后处理脚本与烧录工具都依赖该路径,运维时勿随意更改。
扩展点
构建系统为功能扩展预留了明确的修改点:
- 新增源文件:将
.c文件路径追加到c_SRC_FILES,并在INCLUDES中补充其头文件目录。 - 新增功能宏:在
DEFINES中添加-D开关,并在源码中以#ifdef条件编译接入;HAS_*系列宏是现成的命名范式。 - 切换平台工具链:修改对应平台的
TOOL_DIR/SYS_LIB_DIR/SYS_INC_DIR,或新增ifeq分支(如 macOS 需自行配置交叉编译工具链)。 - 自定义后处理:修改
app/post_build/sh59/download.bat/download.sh,或替换POST_SCRIPT/RUN_POST_SCRIPT变量指向新脚本。 - 集成到 IDE/CI:Code::Blocks(
.cbp)与 VS Code 任务均已预配置;CI 场景可直接调用make -j4(Linux),注意在流水线中预留ulimit -n 8096设置。
相关链接
- README.md 编译指南:环境搭建、工具链安装与三种编译方式完整说明
- sdk/Makefile:构建系统核心源码
- 杰理编译工具链下载:官方文档 / pkgman.jieliapp.com
- USB 升级工具使用文档:forced_upgrade
- 生产烧写工具使用文档:burner_1tuo2
说明:本页聚焦构建系统与命令行工具本身;固件烧录操作细节、SDK 应用工程结构、芯片平台差异分别属于"烧录与升级""应用与示例""支持的芯片与平台"等页面主题。