嵌入式开发中的 Git CI/CD
一、CI/CD 概述
1.1 什么是 CI/CD?
持续集成 (Continuous Integration, CI)
- 开发人员频繁地将代码集成到主分支
- 每次集成都通过自动化构建和测试来验证
- 及早发现集成错误,降低修复成本
持续交付/部署 (Continuous Delivery/Deployment, CD)
- 确保代码随时处于可发布状态
- 自动化部署到测试/生产环境
- 快速、可靠地交付软件更新
1.2 嵌入式开发中的特殊挑战
- 硬件依赖: 需要特定的开发板或模拟器
- 交叉编译: 目标平台与开发平台不同
- 资源限制: 内存、存储空间有限
- 实时性要求: 严格的时序要求
- 安全性: 代码质量直接影响系统稳定性
二、GitHub Actions Workflow 核心概念
2.1 基本结构
yaml
name: CI/CD Pipeline # 工作流名称
on: # 触发条件
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs: # 任务集合
job-name: # 任务名称
runs-on: ubuntu-latest # 运行环境
steps: # 执行步骤
- name: Step Name
run: command
2.2 关键组件说明
| 组件 | 作用 | 示例 |
|---|---|---|
on |
定义触发条件 | push、pull_request、schedule |
jobs |
定义并行/串行任务 | 可设置依赖关系 |
runs-on |
指定运行环境 | ubuntu-latest, windows-latest |
steps |
具体执行步骤 | 检出代码、编译、测试 |
needs |
任务依赖关系 | needs: build |
三、嵌入式 CI/CD 完整流程
3.1 流程图
代码提交 → 静态分析 → 单元测试 → 安全扫描 → 代码度量 → 文档检查 → 依赖分析
↓ ↓ ↓ ↓ ↓ ↓ ↓
触发CI 代码质量 功能验证 漏洞检测 复杂度 文档完整性 依赖健康
3.2 核心阶段详解
阶段 1: 静态代码分析
目的: 在不运行代码的情况下检测潜在问题
yaml
static-analysis:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install tools
run: |
sudo apt-get update
sudo apt-get install -y clang-tidy cppcheck
- name: Run clang-tidy
run: |
clang-tidy *.c \
--checks="*,-modernize-*" \
-- -std=c11 -I./include
技术要点:
- clang-tidy: 检测编码规范、潜在bug、性能问题
- cppcheck: 专注于C/C++的静态分析,支持MISRA规范
- 抑制误报 : 使用
--suppress和--inline-suppr
实际作用:
- 发现空指针解引用
- 检测内存泄漏风险
- 识别未初始化变量
- 强制编码标准(如MISRA-C)
阶段 2: 单元测试
目的: 验证各个模块功能正确性
yaml
unit-test:
needs: static-analysis
steps:
- name: Build and test
run: |
cd tests
make all
make test
技术方案:
- 测试框架: Unity、CppUTest、Google Test
- Mock工具: CMock 模拟硬件接口
- 覆盖率: gcov/lcov 生成覆盖率报告
示例测试结构:
c
// test_scheduler.c
void test_task_creation(void) {
Task_t task;
TaskHandle_t handle = xTaskCreate(&task, ...);
TEST_ASSERT_NOT_NULL(handle);
}
阶段 3: 安全扫描
目的: 识别安全漏洞和危险函数
yaml
security-scan:
steps:
- name: Run flawfinder
run: |
flawfinder --minlevel=1 --html . > report.html
- name: CERT compliance
run: |
cppcheck --addon=cert \
--addon=threadsafety .
检测内容:
- 缓冲区溢出 (
strcpy→strncpy) - 格式化字符串漏洞
- 竞态条件
- 不安全的随机数生成
阶段 4: 代码度量
目的: 评估代码复杂度和可维护性
yaml
code-metrics:
steps:
- name: Complexity analysis
run: |
pip3 install lizard
lizard -l c --CCN 15 .
关键指标:
- 圈复杂度 (CCN): 控制流复杂程度,建议 < 15
- 代码行数: 函数不应超过150行
- 注释率: 至少20%
输出示例:
================================================
NLOC CCN token PARAM length location
------------------------------------------------
15 3 89 2 18 task_create@kernel/task.c
阶段 5: 文档检查
目的: 确保代码有充分文档
yaml
documentation-check:
steps:
- name: Generate docs
run: |
cat > Doxyfile <<EOF
WARN_IF_UNDOCUMENTED = YES
EXTRACT_ALL = NO
EOF
doxygen Doxyfile
要求:
c
/**
* @brief 创建新任务
* @param[in] pvTaskCode 任务函数指针
* @param[in] usStackDepth 堆栈深度
* @return 任务句柄,失败返回NULL
*/
TaskHandle_t xTaskCreate(TaskFunction_t pvTaskCode,
uint16_t usStackDepth);
阶段 6: 依赖分析
目的: 检测循环依赖和多余包含
yaml
dependency-check:
steps:
- name: Check circular dependencies
run: |
find . -name "*.h" | while read file; do
grep -E "^#include" "$file"
done > deps.txt
常见问题:
循环依赖: task.h → queue.h → task.h
解决方案: 前向声明 + 分离接口
四、Artifacts 使用方法
4.1 上传构建产物
yaml
- name: Upload reports
uses: actions/upload-artifact@v4
with:
name: analysis-reports
path: |
*.xml
*.html
*.log
retention-days: 30
4.2 下载和使用
yaml
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: analysis-reports
path: ./reports
实际应用:
- 保存测试报告供团队审查
- 存储编译的固件文件
- 归档性能分析数据
五、高级技巧
5.1 矩阵构建(多平台测试)
yaml
strategy:
matrix:
platform: [stm32f1, stm32f4, esp32]
compiler: [gcc, clang]
steps:
- run: make PLATFORM=${{ matrix.platform }} CC=${{ matrix.compiler }}
5.2 条件执行
yaml
- name: Deploy to production
if: github.ref == 'refs/heads/main' && success()
run: ./deploy.sh
5.3 缓存加速
yaml
- uses: actions/cache@v4
with:
path: ~/.cache/toolchain
key: ${{ runner.os }}-gcc-arm-${{ hashFiles('**/Makefile') }}
参考资源:
- GitHub Actions 文档: https://docs.github.com/actions
- MISRA C 标准: https://misra.org.uk/
- 嵌入式测试框架: Unity, CppUTest