构建系统详解¶
EmbeddedGUI 使用 GNU Make 作为主要构建系统。本文详细介绍 Makefile 的参数配置、常用命令、模块化构建机制和交叉编译方法。
Makefile 参数说明¶
项目根目录的 Makefile 定义了所有可配置参数。可通过命令行传参覆盖默认值,也可以直接修改 Makefile 中的默认配置。
APP – 选择示例应用¶
APP 参数指定要编译的示例应用,对应 example/ 目录下的子目录名。默认值为 HelloSimple。
# 编译 HelloSimple (默认)
make all
# 编译 HelloActivity
make all APP=HelloActivity
# 编译 HelloStyleDemo
make all APP=HelloStyleDemo
可用的示例应用:
APP 值 |
说明 |
|---|---|
|
最简单的入门示例 |
|
基础控件演示集合(62 个子应用,需配合 |
|
Virtual / ListView / GridView / Stage 示例集合(19 个子应用,需配合 |
|
已迁移到独立仓库 |
|
Activity 生命周期演示 |
|
基于 |
|
画布绘图 API 演示 |
|
图表控件演示 |
|
脏区刷新局部重绘演示 |
|
简易分页应用 |
|
渐变效果演示 |
|
Layer 机制演示 |
|
主屏和副屏同为 240x320,演示多屏 Activity 切换与副屏独立输入 |
|
主屏 240x320,副屏 128x64,演示异构副屏状态面板和跨屏状态联动 |
|
性能测试基准 |
|
PFB 机制演示 |
|
资源管理器示例 |
|
综合展示示例 |
|
体积分析 probe / 配置模板集合(需配合 |
|
样式和主题演示 |
|
SVG 规范对比基座 |
|
功能测试 |
|
单元测试 |
|
分页和滚动组合 |
APP_SUB – 选择带子应用的示例¶
APP_SUB 适用于 HelloBasic、HelloVirtual 和 HelloSizeAnalysis 这类多子应用示例:
HelloBasic: 基础控件演示,当前包含 62 个子应用HelloVirtual: virtual/list/grid/stage 示例,当前包含 19 个子应用HelloSizeAnalysis: probe / preset 目录集合,通常配合PORT=qemu
# 编译按钮演示
make all APP=HelloBasic APP_SUB=button
# 编译 Stepper 演示
make all APP=HelloBasic APP_SUB=stepper
# 编译 HelloVirtual basic stage 演示
make all APP=HelloVirtual APP_SUB=virtual_stage_basic
# HelloCustomWidgets 已迁移到独立仓库 EmbeddedGUI_Widgets
# 请在该仓库中编译对应 widget
# 编译 HelloSizeAnalysis 的 widget probe
make all APP=HelloSizeAnalysis APP_SUB=widget_feature_probe PORT=qemu
常用 HelloBasic 子应用: button、slider、combobox、textinput、table、activity_ring、mini_calendar、button_matrix、autocomplete、chips、stepper、pattern_lock 等。
常用 HelloVirtual 子应用: virtual_viewport_basic、virtual_page_basic、virtual_grid_basic、list_view_basic、grid_view_basic、virtual_stage_basic、virtual_stage_showcase、virtual_stage 等。
HelloCustomWidgets 已迁移到独立仓库 EmbeddedGUI_Widgets。
常用 HelloSizeAnalysis 子应用: widget_feature_probe、canvas_path_probe、hq_path_probe、preset_validation。
PORT – 选择目标平台¶
PORT 参数指定目标平台,对应 porting/ 目录下的子目录名。默认值为 pc。
# PC 模拟器 (默认)
make all APP=HelloSimple PORT=pc
# STM32G0 交叉编译
make all APP=HelloSimple PORT=stm32g0
# QEMU 虚拟化环境
make all APP=HelloSimple PORT=qemu
# WebAssembly
make all APP=HelloSimple PORT=emscripten
其他参数¶
# 优化级别 (根目录 Makefile 默认 -O2)
make all COMPILE_OPT_LEVEL=-O0 # 快速调试构建
make all COMPILE_OPT_LEVEL=-Os # 大小优化
# 调试信息 (默认 -g 包含调试信息)
make all COMPILE_DEBUG= # 去掉调试信息 (发布构建)
# 显示完整编译命令 (默认静默)
make all V=1
# 指定编译器位数 (通常自动检测)
make all BITS=64
make all BITS=32
常用命令¶
编译¶
# 编译当前配置的应用
make all
# 等价于指定所有默认参数
make all APP=HelloSimple PORT=pc
# 并行编译 (加速)
make all -j
make all -j8 # 指定 8 个并行任务
运行¶
# 编译并运行
make run
# 注意: 如果编译时修改了参数,运行时也需要带上
make run APP=HelloBasic APP_SUB=slider
make run APP=HelloVirtual APP_SUB=virtual_stage_basic
make run 实际上先执行 make all,然后运行 output/main.exe (Windows) 或 output/main (Linux/macOS)。
清理¶
# 删除 output/ 目录下的所有编译产物
make clean
资源生成¶
# 生成当前应用的资源文件 (字体、图片等)
make resource
# 强制重新生成所有资源
make resource_refresh
资源生成依赖 Python,会调用 scripts/tools/app_resource_generate.py 脚本处理 example/<APP>/resource/ 目录下的资源文件,输出到 output/ 目录。
查看信息¶
# 显示当前配置
make info
# 输出: Current Configuration: APP=HelloSimple PORT=pc
# 查看二进制大小
make size
# 生成反汇编和段列表
make dasm
build.mk 模块系统¶
EGUI 的构建系统基于模块化设计,每个组件目录包含一个 build.mk 文件,通过两个变量定义自己的源文件和头文件路径:
EGUI_CODE_SRC: 源文件目录列表EGUI_CODE_INCLUDE: 头文件搜索路径列表
模块包含流程¶
根目录的 Makefile 按以下顺序包含各模块:
# 1. 包含示例应用的 build.mk
include $(EGUI_APP_PATH)/build.mk
# 2. 包含核心库的 build.mk
include $(EGUI_PATH)/build.mk
# 3. 包含平台移植的 build.mk
include $(EGUI_PORT_PATH)/build.mk
示例: HelloSimple 的 build.mk¶
EGUI_CODE_SRC += $(EGUI_APP_PATH)
EGUI_CODE_SRC += $(EGUI_APP_PATH)/resource
EGUI_CODE_INCLUDE += $(EGUI_APP_PATH)
这告诉构建系统: 将 example/HelloSimple/ 及其 resource/ 子目录下的所有 .c 文件加入编译,并将 example/HelloSimple/ 加入头文件搜索路径。
示例: HelloBasic 的 build.mk¶
EGUI_CODE_SRC += $(EGUI_APP_PATH)
EGUI_CODE_INCLUDE += $(EGUI_APP_PATH)
# 根据 APP_SUB 选择子应用
APP_SUB ?= button
EGUI_APP_SUB_PATH := $(EGUI_APP_PATH)/$(APP_SUB)
EGUI_CODE_SRC += $(EGUI_APP_SUB_PATH)
EGUI_CODE_SRC += $(EGUI_APP_SUB_PATH)/resource
EGUI_CODE_SRC += $(EGUI_APP_SUB_PATH)/resource/img
EGUI_CODE_SRC += $(EGUI_APP_SUB_PATH)/resource/font
EGUI_CODE_INCLUDE += $(EGUI_APP_SUB_PATH)
EGUI_CODE_INCLUDE += $(EGUI_APP_SUB_PATH)/resource
HelloBasic、HelloVirtual 和 HelloSizeAnalysis 这类多子应用示例都会设置独立的 APP_OBJ_SUFFIX,避免不同子应用复用错误的编译产物。
示例: 核心库的 build.mk¶
EGUI_CODE_SRC += $(EGUI_PATH)
EGUI_CODE_SRC += $(EGUI_PATH)/app
EGUI_CODE_SRC += $(EGUI_PATH)/anim
EGUI_CODE_SRC += $(EGUI_PATH)/core
EGUI_CODE_SRC += $(EGUI_PATH)/widget
EGUI_CODE_SRC += $(EGUI_PATH)/font
EGUI_CODE_SRC += $(EGUI_PATH)/image
EGUI_CODE_SRC += $(EGUI_PATH)/mask
EGUI_CODE_SRC += $(EGUI_PATH)/utils
# ... 更多模块
EGUI_CODE_INCLUDE += $(EGUI_PATH)
添加新模块¶
如果你需要添加自己的模块,只需在 build.mk 中追加路径即可:
# 在示例的 build.mk 中添加自定义模块
EGUI_CODE_SRC += $(EGUI_APP_PATH)/my_module
EGUI_CODE_INCLUDE += $(EGUI_APP_PATH)/my_module
应用配置¶
每个示例应用可以通过 app_egui_config.h 文件覆盖框架的默认配置:
#ifndef _APP_EGUI_CONFIG_H_
#define _APP_EGUI_CONFIG_H_
// 屏幕分辨率
#define EGUI_CONFIG_SCREEN_WIDTH 240
#define EGUI_CONFIG_SCREEN_HEIGHT 320
// 色深: 16-bit RGB565
#define EGUI_CONFIG_COLOR_DEPTH 16
// PFB 大小 (宽/高建议优先选为屏幕尺寸的整数约数)
#define EGUI_CONFIG_PFB_WIDTH (240 / 8) // 30 像素
#define EGUI_CONFIG_PFB_HEIGHT (320 / 8) // 40 像素
// 抗锯齿圆的最大半径
#define EGUI_CONFIG_CIRCLE_SUPPORT_RADIUS_BASIC_RANGE 20
#endif
框架默认配置现在分成两层:
src/config/egui_config_default.h:主屏基础默认值src/config/egui_config_multi_default.h:多屏默认值,例如EGUI_CONFIG_MAX_DISPLAY_COUNT、EGUI_CONFIG_SCREEN_1_*、EGUI_CONFIG_PFB_1_*
应用的 app_egui_config.h 会先于这些默认头被包含,因此可以覆盖任意配置项。
CMake 构建¶
EGUI 也提供了 CMake 构建支持,适合 IDE 集成和代码索引。当前仓库已经提供 CMake 移植层的平台是 pc 和 pc_test:
# 构建独立示例
cmake -B build_cmake/HelloSimple -DAPP=HelloSimple -DPORT=pc -G "MinGW Makefiles"
cmake --build build_cmake/HelloSimple -j
# 构建 HelloBasic 子应用
cmake -B build_cmake/HelloBasic_button -DAPP=HelloBasic -DAPP_SUB=button -DPORT=pc -G "MinGW Makefiles"
cmake --build build_cmake/HelloBasic_button -j
# 构建 HelloVirtual 子应用
cmake -B build_cmake/HelloVirtual_virtual_stage_basic -DAPP=HelloVirtual -DAPP_SUB=virtual_stage_basic -DPORT=pc -G "MinGW Makefiles"
cmake --build build_cmake/HelloVirtual_virtual_stage_basic -j
# 构建单元测试(pc_test)
cmake -B build_cmake/HelloUnitTest_pc_test -DAPP=HelloUnitTest -DPORT=pc_test -G "MinGW Makefiles"
cmake --build build_cmake/HelloUnitTest_pc_test -j
Windows 下也可以用仓库内置的 Visual Studio + SDL2 preset 生成 CMake 工程并调试 PC 模拟器:
cmake --preset visual_studio_sdl
cmake --build --preset visual_studio_sdl
.\build_vs\visual_studio_sdl\output\Debug\HelloSimple.exe
visual_studio_sdl 默认使用 Visual Studio 2022、MSVC x64 和仓库内置 SDL2。若使用 Visual Studio 2026,可改用 visual_studio_sdl_vs2026。需要切换示例时,在 CMake configure 参数中覆盖 APP / APP_SUB / PORT,例如 -DAPP=HelloBasic -DAPP_SUB=button -DPORT=pc。
如果只想双击打开工程,可直接打开 porting/pc/EmbeddedGUI_PC_Simulator.sln。该方案参考 lv_port_pc_visual_studio 的组织方式:PC 模拟器相关的 Visual Studio 工程文件集中放在 porting/pc/,仓库只维护一个 EmbeddedGUI_PC_Simulator 工程,公共源码和 SDL2/MSVC 配置固定在工程中,常用示例通过 Visual Studio 顶部的解决方案配置下拉框选择。该工程只维护 x64 平台配置,避免 Visual Studio 打开时自动补全 Win32 映射并重写 .sln。
常用配置包括:
HelloSimple_Debug|x64HelloBasic_button_Debug|x64HelloBasic_slider_Debug|x64HelloVirtual_virtual_viewport_basic_Debug|x64HelloVirtual_virtual_stage_basic_Debug|x64HelloGame_snake_Debug|x64HelloSizeAnalysis_canvas_path_probe_Debug|x64
其中普通示例使用 APP_Debug 命名,带子应用的示例使用 APP_APP_SUB_Debug 命名。选择配置后直接生成或按 F5 调试即可,输出位于 build_vs/<APP 或 APP_APP_SUB>/x64/<配置名>/,例如 build_vs/HelloBasic_button/x64/HelloBasic_button_Debug/HelloBasic_button.exe。Visual Studio 方案使用 Windows 子系统运行 PC 模拟器,不弹出额外控制台窗口;Hello, egui!、录制状态、shutdown 检查、普通 printf() 和 EGUI_LOG_* 日志会显示在 Visual Studio 的“输出”窗口中,查看来源选择“调试”。Debug 配置会在应用未显式配置日志级别时默认打开 INFO 及以上框架日志。
porting/pc/EmbeddedGUI.VisualStudio.props 仍保留为高级自定义入口。没有预置到下拉框里的示例,可以选择 Debug|x64 或 Release|x64,再修改下面的默认值:
<EguiApp>HelloSimple</EguiApp>
<EguiAppSub></EguiAppSub>
<EguiPort>pc</EguiPort>
需要切换到带子应用的示例时,修改 porting/pc/EmbeddedGUI.VisualStudio.props 后重新生成即可,例如:
<EguiApp>HelloBasic</EguiApp>
<EguiAppSub>button</EguiAppSub>
<EguiPort>pc</EguiPort>
HelloBasic、HelloVirtual、HelloGame、HelloSizeAnalysis 在 EguiAppSub 留空时会使用各自默认子应用。Visual Studio 调试工作目录为仓库根目录,方便 file_image、deferred_image、HelloPerformance 这类示例读取仓库内的示例文件。
Visual Studio C++ 工程不直接使用 *.c、**/*.h 或 $(EguiAppPath) 这类通配符项目项,避免 IDE 加载时禁用项目缓存并长时间停在“正在加载项目”。.vcxproj 中的源码和头文件列表由脚本生成,.vcxproj.filters 中的 Source Files / Header Files 也会按仓库原始目录结构自动生成,例如 Source Files\src\core、Header Files\example\HelloBasic\button。
新增示例后,如果希望它出现在 Visual Studio 配置下拉框中,需要同步 porting/pc/ 下的 .sln 和 .vcxproj。直接运行脚本会自动扫描 example/ 下所有含 build.mk 的 app,以及使用 APP_SUB 的 app 下所有含 app_egui_config.h 的一级子目录,并刷新 x64 配置和显式工程项列表:
python scripts\platform\update_visual_studio_sln.py
如果只想同步某个指定示例,也可以显式指定 app 或 sub app。脚本可重复执行,已有配置不会重复插入:
# 新增普通示例
python scripts\platform\update_visual_studio_sln.py --app HelloDirty
# 新增带 APP_SUB 的示例
python scripts\platform\update_visual_studio_sln.py --app HelloBasic --app-sub checkbox
# 一次添加多个配置
python scripts\platform\update_visual_studio_sln.py --entry HelloDirty --entry HelloBasic/checkbox
如果只是新增、删除或重命名了某个已有源码目录下的 .c/.h 文件,不需要手动修改 .sln、.vcxproj 或 .vcxproj.filters,直接运行脚本刷新工程项和目录过滤器即可:
python scripts\platform\update_visual_studio_sln.py
如果新增的是全新的源码目录,先按 Makefile 规则把目录加入对应 build.mk,再运行上面的脚本同步 Visual Studio 工程视图。
发布前检查也会覆盖 Visual Studio 工程同步和轻量编译检查。若只想单独检查这一项,可以运行:
python scripts\release_check.py --only visual_studio
该步骤使用 --check 模式,不会自动改写工程文件;如果失败,先运行 python scripts\platform\update_visual_studio_sln.py 更新 porting/pc/ 下的 .sln/.vcxproj/.vcxproj.filters,再重新执行 release check。
CMake 产物默认输出到对应 build_cmake/<target>/output/ 目录。对于 stm32g0、qemu、emscripten 这类非 CMake 移植层,日常开发仍推荐使用 Makefile。
交叉编译¶
ARM GCC 工具链¶
编译到 STM32 等 ARM MCU 时,需要安装 ARM GCC 工具链:
# Ubuntu/Debian
sudo apt-get install gcc-arm-none-eabi
# 或从 ARM 官网下载:
# https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm
然后使用对应的 PORT 参数编译:
make all APP=HelloSimple PORT=stm32g0
STM32 平台的 build.mk 会自动设置交叉编译器前缀 CROSS_COMPILE 和链接脚本。
编译产物¶
编译完成后,产物位于 output/ 目录:
文件 |
说明 |
|---|---|
|
PC 可执行文件 (Windows) |
|
PC 可执行文件 (Linux/macOS) |
|
ARM ELF 文件 |
|
ARM 二进制固件 (通过 |
|
SDL2 动态库 (Windows,自动拷贝) |
|
合并后的资源文件 |
|
中间目标文件 (.o) |
辅助脚本¶
除了 make 命令,项目还提供了多个 Python 辅助脚本:
# 完整编译检查 (CI 使用,编译所有示例,并包含示例 icon font 约定检查)
python scripts/code_compile_check.py --full-check --bits64
# 运行时验证 (截图对比)
python scripts/code_runtime_check.py --app HelloBasic --app-sub button --timeout 10
# HelloVirtual 子应用运行时验证
python scripts/code_runtime_check.py --app HelloVirtual --timeout 10
python scripts/code_runtime_check.py --app HelloVirtual --app-sub virtual_stage_basic --timeout 10
# 多屏专项快速回归
python scripts/code_compile_check.py --scope multi-display --case-jobs 2
python scripts/code_runtime_check.py --scope multi-display --jobs 2 --timeout 10 --keep-screenshots
# 代码格式化
python scripts/code_format.py
# 示例图标字体显式配置检查
python scripts/checks/check_example_icon_font.py
# 如果要把本地未跟踪目录也一起扫描
python scripts/checks/check_example_icon_font.py --include-untracked
# 发布前一键检查
python scripts/release_check.py --skip perf,wasm,doc
# 多屏专项一键回归
python scripts/release_check.py --scope multi-display
# ELF 二进制大小分析
python scripts/size_analysis/main.py
# 资源生成
python scripts/tools/app_resource_generate.py -r example/HelloSimple/resource -o output
说明:
scripts/checks/check_example_icon_font.py默认只扫描 git 已跟踪的example/源文件,避免本地临时目录影响 CI 风格检查code_compile_check.py --full-check默认会包含这一步;如果你在外层已经单独跑过 icon font 检查,可用--skip-icon-font-check避免重复执行修改多屏入口、descriptor、线程模型或副屏录制链路后,优先补跑
--scope multi-displayrelease_check.py --scope multi-display会把多屏 compile/runtime scope 和文档校验串成一条命令,适合本地快速收口