Appearance
项目结构
本章介绍 Anvil 项目的目录组织和命名规范。
推荐目录结构
project/
├── src/ # 源代码(由 Makefile 构建)
│ ├── module1/
│ │ ├── module1.c
│ │ └── internal.c
│ └── module2/
│ ├── module2.c
│ └── internal.c
├── include/ # 公共 API 头文件
│ ├── module1.h
│ └── module2.h
├── build/ # 预编译的目标文件(.o 文件)
│ ├── module1/
│ │ ├── module1.o
│ │ └── internal.o
│ └── module2/
│ ├── module2.o
│ └── internal.o
├── tests/ # 测试目录(由 Anvil 管理)
│ ├── common/ # 公共测试辅助文件
│ │ ├── mock_db.c
│ │ └── mock_db.h
│ ├── module1/
│ │ ├── test_module1_public.c
│ │ └── test_module1_internal.c
│ └── module2/
│ ├── test_module2_public.c
│ └── test_module2_internal.c
├── Makefile # 构建源代码(不构建测试)
└── .anvil # Anvil 配置文件关键规则
1. Makefile 不构建测试
重要
Makefile 只负责将源代码编译为 .o 文件。测试的发现、编译和执行完全由 Anvil 管理。
makefile
# Makefile 示例
SOURCES := $(wildcard src/**/*.c)
OBJECTS := $(SOURCES:src/%.c=build/%.o)
all: $(OBJECTS)
build/%.o: src/%.c
@mkdir -p $(dir $@)
gcc -c $< -o $@ -Iinclude2. 目标文件结构对应源码结构
src/module1/foo.c → build/module1/foo.o
src/module2/bar.c → build/module2/bar.o3. 测试目录结构
测试文件可以放在 tests/ 下的任意子目录中:
tests/
├── unit/ # 单元测试
├── integration/ # 集成测试
└── stress/ # 压力测试测试文件命名
基本规则
test_[层级1]_[层级2]_..._[测试名].c示例
| 测试文件 | 测试目录 | 说明 |
|---|---|---|
test_math.c | tests/ | 根目录测试 |
test_module_add.c | tests/module/ | 模块子目录测试 |
test_core_util_parse.c | tests/core/util/ | 多层级目录测试 |
文件名与目录匹配
文件名中的层级前缀必须与目录层级匹配:
tests/core/util/test_core_util_foo.c ✓ 正确
tests/core/util/test_foo.c ✗ 错误(缺少层级前缀)依赖解析
工作原理
- Anvil 编译测试文件生成
.o文件 - 使用
nm -u分析未定义符号 - 在
build/目录中查找提供这些符号的.o文件 - 递归解析传递依赖
- 链接所有必需的目标文件
示例
c
// tests/test_math.c
#include "math.h"
__attribute__((test_method))
int test_add(void) {
return add(1, 2) == 3; // 调用 math.o 中的 add
}
// includes: -I../includeAnvil 会自动:
- 发现
add是未定义符号 - 在
build/中找到math.o提供add - 链接
test_math.o和math.o
公共测试辅助
Mock 文件
将公共 Mock 放在 tests/common/ 目录:
tests/
└── common/
├── mock_database.c
├── mock_database.h
├── mock_network.c
└── mock_network.h在测试中引用:
c
#include "../common/mock_database.h"
// sources: ../common/mock_database.c测试工具
c
// tests/common/test_utils.h
#define ASSERT_EQ(a, b) ((a) == (b))
#define ASSERT_NE(a, b) ((a) != (b))
#define ASSERT_TRUE(x) ((x) != 0)
#define ASSERT_FALSE(x) ((x) == 0)嵌入式项目结构
针对嵌入式项目的特殊结构:
embedded-project/
├── src/ # 生产代码
│ ├── hal/ # 硬件抽象层
│ ├── drivers/ # 驱动程序
│ └── app/ # 应用逻辑
├── include/
├── build/
│ ├── target/ # 目标板构建产物
│ └── host/ # 主机测试构建产物
├── tests/
│ ├── host/ # 主机端测试
│ │ ├── test_app.c
│ │ └── mock_hal.c # HAL Mock
│ └── target/ # 目标板测试(如果支持)
└── .anvil.anvil 配置:
yaml
test_dir: tests/host
build_dir: build/host