Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
---

<!-- COVERAGE_START -->
![English Coverage](https://img.shields.io/badge/en_coverage-92%25-green.svg) 534/582 docs translated
![English Coverage](https://img.shields.io/badge/en_coverage-92%25-green.svg) 544/592 docs translated
<!-- COVERAGE_END -->

## 这是什么项目
Expand Down
1 change: 1 addition & 0 deletions code/volumn_codes/vol8-labs/ai/tiny_ml/stage0/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
build*/
45 changes: 45 additions & 0 deletions code/volumn_codes/vol8-labs/ai/tiny_ml/stage0/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
cmake_minimum_required(VERSION 3.20)

project(tamcpp_mlinfra LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

# 不调这个,CMake 不生成 CTestTestfile.cmake,catch_discover_tests 注册的
# add_test 全悬空,ctest 永远 No tests found。
enable_testing()

message(STATUS "Ready to fetch the necessary test framework")

include(FetchContent)

FetchContent_Declare(
Catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
GIT_TAG v3.5.0
)

FetchContent_MakeAvailable(Catch2)
list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/extras)

# 顶层只把 Catch2 的 extras 加进了 MODULE_PATH,要用 catch_discover_tests
# 还得自己 include(Catch) 把命令加载进来。
include(Catch)

# 跨编译器的 warning 选项封进一个函数,后续每个 target 一行调用就行,
# 不用在 CMakeLists.txt 里反复抄 generator-expression。
# 比较坑的点:这个 Lab 要同时吃 MSVC 和 GCC/Clang,两边选项根本不通用,
# 只能用 genex 按编译器分流——还得是跑到 Windows 下编译一轮才吃到这个亏!
function(tamcpp_target_warnings target)
target_compile_options(${target} PRIVATE
$<$<CXX_COMPILER_ID:MSVC>:/W4;/permissive-;/Zi>
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall;-Wextra;-Wpedantic;-g>
)
endfunction()

add_executable(smoke_catch2 tests/smoke.cpp)
target_link_libraries(smoke_catch2 PRIVATE Catch2::Catch2WithMain)
tamcpp_target_warnings(smoke_catch2)
catch_discover_tests(smoke_catch2)
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# 001 · `mkdir -p dir/{a,b,c}` 拆解

> 学习日志。每条记录一个已达成共识的知识点。
> 出处:`tinyinfercpp-handbook.md` M0 第一步(第 244 行)。

## 原命令

```bash
mkdir -p tinyinfercpp-lab/{include/tinyinfer,src,tests,tools,examples/hello_inference}
```

## 结论:三个独立机制拼接

| 部分 | 机制 | 作用 |
|------|------|------|
| `mkdir` | make directory | 建目录 |
| `-p` | `--parents` | ① 递归建出缺失的父目录;② 幂等(目录已存在不报错,退出码 0) |
| `{a,b,c}` | bash **花括号展开(brace expansion)** | 纯 shell 文本替换,把逗号分隔项各自拼上前缀,展开成多个独立参数 |

## 实证(2026-06-30 跑通)

- **花括号展开**:`echo tinyinfercpp-lab/{include/tinyinfer,src,...}` 输出 5 个独立路径,证明是先展开成多参数再交给命令。
- **不带 `-p`**:父目录缺失时 `mkdir: cannot create directory ...: No such file or directory`,退出码 1。
- **带 `-p`**:`a/b/c` 一路补齐建成;重复执行不报错(退出码 0);不带 `-p` 重复执行报 `File exists`,退出码 1。

## 等价形式

```bash
mkdir -p tinyinfercpp-lab/include/tinyinfer
mkdir -p tinyinfercpp-lab/src
mkdir -p tinyinfercpp-lab/tests
mkdir -p tinyinfercpp-lab/tools
mkdir -p tinyinfercpp-lab/examples/hello_inference
```

## 坑

- 花括号展开是 **bash/zsh** 特性。`#!/bin/sh`(dash 等 POSIX shell)**不保证支持**,会把 `{...}` 当字面目录名建出来。本机 zsh/bash 无此问题。
- 花括号里**逗号前后不能有空格**,否则不触发展开(变成字面量)。
- 本命令必须 `-p`:要建的 `include/tinyinfer`、`examples/hello_inference` 是两层深,且父目录 `tinyinfercpp-lab/` 也还不存在。
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# 002 · FetchContent 拉取 Catch2 机制

> 出处:`CMakeLists.txt` 第 14–22 行。
> 关联:handbook M0 第 259–266 行(骨架)、坑 1(第 332–336 行)。

## 原命令

```cmake
include(FetchContent)
FetchContent_Declare(Catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
GIT_TAG v3.5.0)
FetchContent_MakeAvailable(Catch2)
list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/extras)
```

## 一句话定位

在 CMake **配置阶段(configure time)** 从 Git 拉 Catch2 源码,直接 `add_subdirectory` 同构编译进工程,无需预装/无 submodule/无 vcpkg。版本由 `GIT_TAG v3.5.0` 锁死。

## 三步机制

| 步骤 | 行为 | 何时下载 |
|------|------|----------|
| `FetchContent_Declare` | 只登记(name + 来源 + tag),写入 CMake 内部记录 | **不下载** |
| `FetchContent_MakeAvailable` | 首次配置时 clone + `add_subdirectory` + 定义 target(`Catch2::Catch2WithMain`) + 设 `<depname>_SOURCE_DIR` 变量 | **下载** |
| `list(APPEND CMAKE_MODULE_PATH .../extras)` | 把 Catch2 的辅助 `.cmake`(`Catch.cmake` 等,含 `catch_discover_tests`)挂进搜索路径,供后续 `include(Catch)` | — |

变量名规则:`<depname>_SOURCE_DIR` 用**全小写** depname → 这里是 `catch2_SOURCE_DIR`。

下载落点:`build/_deps/<name>-src/`(源码)、`-build/`(中间产物)。二次配置不重拉。不污染源码树。

## 实证(2026-06-30,/tmp 真实拉取 —— 失败,但日志坐实机制)

- `[1] Declare 之前` 与 `[2] Declare 之后` 两条 message 都打印 → 证明 **Declare 阶段磁盘无任何下载**。
- `[22%] Performing download step (git clone) for 'catch2-populate'` + `Cloning into 'catch2-src'` → 下载由 FetchContent 内部生成的 `catch2-populate` 子项目驱动 `git clone`,目标即 `catch2-src/`。
- 失败后 `_deps/` 有 `catch2-build`/`catch2-subbuild` 但**无 `catch2-src`** → 反向证明 `catch2-src/` 才是源码位置。

## 坑 1(实证命中):网络拉不下来

失败日志:`Failed to connect to github.com port 443 after 133656 ms`(重试 3 次)、`SSL_read: unexpected eof`。WSL 访问 github 不稳定。

**救急**(handbook 给的):手动浅克隆后用预放置目录替换自动下载:
```bash
git clone --depth 1 -b v3.5.0 https://github.com/catchorg/Catch2.git /tmp/catch2
cmake -S . -B build -DFETCHCONTENT_SOURCE_DIR_CATCH2=/tmp/catch2
```
变量名规则:`FETCHCONTENT_SOURCE_DIR_<大写DEPNAME>`,本质是替换 `GIT_REPOSITORY` 的下载源。
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# 003 · `target_compile_options` 与警告三件套 + `-g`

> 出处:`CMakeLists.txt` 第 27 行。
> 本机:g++ 16.1.1 / clang++ 22.1.6。

## 原命令

```cmake
target_compile_options(smoke_catch2 PRIVATE -Wall -Wextra -Wpedantic -g)
```

## ① 命令骨架

`target_compile_options(<target> <scope> <flags...>)` —— **现代 CMake(target-based)** 写法,把选项挂在指定 target 上,对应老式全局 `add_compile_options()`。哲学:属性挂 target,谁需要谁加,不污染全局。

- `smoke_catch2` —— 接收方,第 25 行 `add_executable(smoke_catch2 tests/smoke.cpp)` 建的测试可执行文件。
- `PRIVATE` —— 传递性关键字:

| 关键字 | 编译自己 | 传给下游 |
|--------|:-------:|:--------:|
| PRIVATE | ✅ | ❌ |
| INTERFACE | ❌ | ✅ |
| PUBLIC | ✅ | ✅ |

**警告标志几乎总是 PRIVATE**:① 下游不关心你怎么编译它;② 警告标志编译器相关(`-Wall` 是 GCC/Clang,MSVC 是 `/W4` 且 `/Wall` 含义不同会刷屏),PUBLIC 传下去换编译器就炸。

## ② 四个标志(2026-06-30 实证)

`-Wall -Wextra -Wpedantic` = 警告三件套,逐级加严。演示埋三雷各吃一个:

| 标志 | 命中警告 | 含义 |
|------|----------|------|
| `-Wall` | `[-Wunused-variable]` | 精选「有用、误报低」警告集。⚠️ 非「所有警告」 |
| `-Wextra` | `[-Wunused-parameter]` | 再补一批:未用参数、有符号/无符号比较 |
| `-Wpedantic` | `[-Wvla] ISO C++ forbids variable length array` | 按 ISO 标准查,对编译器扩展告警 → 更可移植 |

演示:档1 → 档2 → 档3 警告逐级递增。

`-g` —— 生成 DWARF 调试信息塞进产物。实证:
- 无 `-g`:`not stripped`,0 个 `.debug*` 段;
- 有 `-g`:`with debug_info`,6 个 `.debug*` 段。
有这些段 gdb/lldb 才能映射回源文件行号/变量名/类型。

## 易错点

1. **`-g` 不影响优化**。默认 `-O0`(不优化),`-g` 单加 = 可调试 + 不优化;发布再加 `-O2`。
2. **这套标志 GCC/Clang 专用,MSVC 一套都不认**(`-Wall`/`-Wextra`/`-Wpedantic`/`-g` 全是 GCC/Clang 私有)。MSVC 有自己的对应物,本 lab 的 `CMakeLists.txt` 已用生成器表达式按编译器 ID 分挂:

| GCC/Clang | MSVC | 含义 |
|----------|------|------|
| `-Wall -Wextra` | `/W4` | 警告级(W4 是 MSVC 实用最高档;`/Wall` 含义不同会刷屏,不可用) |
| `-Wpedantic` | `/permissive-` | 严格标准符合,禁用非标准扩展(精神接近,不完全等同) |
| `-g` | `/Zi` | 生成调试信息(写进 PDB) |

`CMakeLists.txt` 第 29–32 行的真实写法是「分两条、按编译器 ID 选」:

```cmake
target_compile_options(smoke_catch2 PRIVATE
$<$<CXX_COMPILER_ID:MSVC>:/W4;/permissive-;/Zi>
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall;-Wextra;-Wpedantic;-g>
)
```

关键取舍:第二条用 `$<NOT:$<CXX_COMPILER_ID:MSVC>>` 而非枚举 `$<CXX_COMPILER_ID:GNU,Clang>` —— 「非 MSVC 即走 GCC/Clang 那套」,自动覆盖 Intel/LLVM 等兼容 GCC 标志的编译器,不必每加一个编译器改一次清单。生成器表达式里多条标志用分号 `;` 分隔(CMake 列表分隔符)。
6 changes: 6 additions & 0 deletions code/volumn_codes/vol8-labs/ai/tiny_ml/stage0/tests/smoke.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include <catch2/catch_test_macros.hpp>
#include <print>

TEST_CASE("Smoke up the labs") {
std::print("Our smoke Test");
}
110 changes: 110 additions & 0 deletions code/volumn_codes/vol8-labs/ai/tiny_ml/stage1/.clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# .clang-format 配置文件
# 用于 clangd 格式化和代码检查
# 生成日期: 2026-02-15

# 基础风格: LLVM (简洁现代)
BasedOnStyle: LLVM

# 缩进设置
IndentWidth: 4
UseTab: Never
ColumnLimit: 100

# 大括号风格: 附加式 { 在语句末尾
BreakBeforeBraces: Attach

# 指针/引用星号位置: 左侧 (int* a)
PointerAlignment: Left
DerivePointerAlignment: false

# 命名风格 (仅供参考,不影响已有代码)
# 可以让 clangd 警告不符合命名规范的代码
# 需要配合 clang-tidy 使用

# 函数声明: 返回类型和函数名在同一行
AlwaysBreakAfterReturnType: None
AlwaysBreakTemplateDeclarations: Yes

# 结构体初始化: 按位置赋值
# C++11UnifiedBraceList: false 使用传统风格

# 预处理器缩进: 与代码对齐
IndentPPDirectives: AfterHash

# 其他实用设置

# 在二元运算符后换行
BreakBeforeBinaryOperators: None

# 在三元运算符后换行
BreakBeforeTernaryOperators: true

# 连续赋值时的对齐
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false

# 转换类型周围的空格
SpaceAfterCStyleCast: false

# 逻辑运算符周围的空格
SpaceAfterLogicalNot: false

# 模板列表中的空格
SpaceAfterTemplateKeyword: true

# 控制语句括号内的空格: if (x) 而非 if (x )
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false

# 圆括号内的空格
SpacesInParentheses: false
SpacesInSquareBrackets: false

# 容器类型周围的空格
SpacesInContainerLiterals: false

# lambda 相关
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false

# 对齐
AlignAfterOpenBracket: Align
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: true

# 允许函数参数在同一行
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true

# 允许短函数在一行
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false

# 自动对齐注释
ReflowComments: true

# 最大连续空行数
MaxEmptyLinesToKeep: 1

# 命名空间缩进
NamespaceIndentation: None

# 访问修饰符缩进
IndentAccessModifiers: false
IndentCaseLabels: true

# 换行符设置
LineEnding: LF

# C/C++ 语言设置
Language: Cpp
Standard: Latest

# 包含块排序
SortIncludes: true
IncludeBlocks: Preserve
41 changes: 41 additions & 0 deletions code/volumn_codes/vol8-labs/ai/tiny_ml/stage1/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
cmake_minimum_required(VERSION 3.20)

project(tamcpp_mlinfra LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

# 不调这个,CMake 不生成 CTestTestfile.cmake,catch_discover_tests 注册的
# add_test 全悬空,ctest 永远 No tests found。
enable_testing()

message(STATUS "Ready to fetch the necessary test framework")

include(FetchContent)

FetchContent_Declare(
Catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
GIT_TAG v3.5.0
)

FetchContent_MakeAvailable(Catch2)
list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/extras)

add_library(TAMCPP_TinyML INTERFACE include/tinyml/tensor.hpp)
target_include_directories(TAMCPP_TinyML INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)

# 跨编译器的 warning 选项封进一个函数,后续每个 target 一行调用就行,
# 不用在每个 CMakeLists.txt 里反复抄一遍 generator-expression。
# 比较坑的点:这个 Lab 要同时吃 MSVC 和 GCC/Clang,两边选项根本不通用,
# 只能用 genex 按编译器分流——还得是跑到 Windows 下编译一轮才吃到这个亏!
function(tamcpp_target_warnings target)
target_compile_options(${target} PRIVATE
$<$<CXX_COMPILER_ID:MSVC>:/W4;/permissive-;/Zi>
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall;-Wextra;-Wpedantic;-g>
)
endfunction()

add_subdirectory(tests)
Loading
Loading