Skip to content

项目结构

本章介绍 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 $@ -Iinclude

2. 目标文件结构对应源码结构

src/module1/foo.c  →  build/module1/foo.o
src/module2/bar.c  →  build/module2/bar.o

3. 测试目录结构

测试文件可以放在 tests/ 下的任意子目录中:

tests/
├── unit/           # 单元测试
├── integration/    # 集成测试
└── stress/         # 压力测试

测试文件命名

基本规则

test_[层级1]_[层级2]_..._[测试名].c

示例

测试文件测试目录说明
test_math.ctests/根目录测试
test_module_add.ctests/module/模块子目录测试
test_core_util_parse.ctests/core/util/多层级目录测试

文件名与目录匹配

文件名中的层级前缀必须与目录层级匹配:

tests/core/util/test_core_util_foo.c  ✓ 正确
tests/core/util/test_foo.c            ✗ 错误(缺少层级前缀)

依赖解析

工作原理

  1. Anvil 编译测试文件生成 .o 文件
  2. 使用 nm -u 分析未定义符号
  3. build/ 目录中查找提供这些符号的 .o 文件
  4. 递归解析传递依赖
  5. 链接所有必需的目标文件

示例

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../include

Anvil 会自动:

  1. 发现 add 是未定义符号
  2. build/ 中找到 math.o 提供 add
  3. 链接 test_math.omath.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

本页面内容遵循 Luna 软件源代码授权条款 (LSLA) 发布