From 7bc402ff8cea1a09d6a94b339866ba20f52a796b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9C=C3=A2jinzhongjia?= Date: Sat, 9 Dec 2023 18:17:33 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=B8=80=E9=83=A8=E5=88=86?= =?UTF-8?q?=20=E6=9E=84=E5=BB=BA=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- learn/engineering/build-system.md | 92 ++++++++++++++++++++++++++++--- 1 file changed, 85 insertions(+), 7 deletions(-) diff --git a/learn/engineering/build-system.md b/learn/engineering/build-system.md index 815f20b5..c541d6dd 100644 --- a/learn/engineering/build-system.md +++ b/learn/engineering/build-system.md @@ -35,9 +35,11 @@ zig 提供了四种构建模式(**Build Mode**): :::details 关于 Debug 不可复现的原因 -关于为什么 Debug 是不可复现的,ziglang 的文档并未给出具体说明,经过询问TG群,给出的答案是: +关于为什么 Debug 是不可复现的,ziglang 的文档并未给出具体说明: -它可以添加一些基于随机种子的字段,例如在标准库中暴露多线程错误,或在常规类型中检查非法行为等。 +效果是在 Debug 构建模式下,编译器会添加一些随机因素进入到程序中(例如内存结构不同),所以任何没有明确说明内存布局的容器在 Debug 构建下可能会有所不同,这便于我们在 Debug 模式下快速暴露某些错误。有意思的是,这并不会影响程序正常运行,除非你的程序逻辑有问题。 + +**_这是 zig 加强安全性的一种方式(尽可能提高安全性但又不至于造成类似 Rust 开发时过重的心智负担)。_** ::: @@ -125,8 +127,21 @@ pub fn build(b: *std.Build) void { // zig 提供了一个方便的函数允许我们直接运行构建结果 const run_exe = b.addRunArtifact(exe); + // 注意:这个步骤不是必要的,显示声明运行依赖于构建 + // 这会使运行是从构建输出目录(默认为 zig-out/bin )运行而不是构建缓存中运行 + // 不过,如果应用程序运行依赖于其他已存在的文件(例如某些 ini 配置文件),这可以确保它们正确的运行 + run_exe.step.dependOn(b.getInstallStep()); + + // 注意:此步骤不是必要的 + // 此操作允许用户通过构建系统的命令传递参数,例如 zig build -- arg1 arg2 + // 当前是将参数传递给运行构建结果 + if (b.args) |args| { + run_cmd.addArgs(args); + } + // 指定一个 step 为 run const run_step = b.step("run", "Run the application"); + // 指定该 step 依赖于 run_exe,即实际的运行 run_step.dependOn(&run_exe.step); } @@ -238,8 +253,6 @@ pub fn build(b: *std.Build) void { :::code-group - - ```zig [nightly] const std = @import("std"); @@ -338,9 +351,15 @@ pub fn build(b: *std.Build) void { zig 本身提供了一个实验性的文档生成器,它支持搜索查询,操作如下: ```zig +const std = @import("std"); + +pub fn build(b: *std.Build) void { + // ... + // 添加 step const docs_step = b.step("docs", "Emit docs"); + // 构建文档 const docs_install = b.addInstallDirectory(.{ // lib 库 .source_dir = lib.getEmittedDocs(), @@ -351,12 +370,67 @@ zig 本身提供了一个实验性的文档生成器,它支持搜索查询, // 依赖step docs_step.dependOn(&docs_install.step); + // ... +} ``` -TODO +以上代码定义了一个名为 `docs` 的 Step,并将 `addInstallDirectory` 操作作为依赖添加到 `docs` Step 上。 ## Test +每个文件可以使用 `zig test` 命令来执行测试,但实际开发中这样很不方便,zig 的构建系统提供了另外一种方式来处理当项目变得复杂时的测试。 + +使用构建系统执行单元测试时,构建器和测试器会通过 stdin 和 stdout 进行通信,以便同时运行多个测试,并且可以有效地报告错误(不会将错误混到一起),但这导致了无法[在单元测试中写入 stdin](https://github.com/ziglang/zig/issues/15091),这会扰乱测试器的正常工作。另外, zig 将引入一个额外的机制,允许预测 [`panic`](https://github.com/ziglang/zig/issues/1356)。 + +```zig +const std = @import("std"); + +pub fn build(b: *std.Build) void { + // 标准构建目标 + const target = b.standardTargetOptions(.{}); + + // 标准构建模式 + const optimize = b.standardOptimizeOption(.{}); + + // 添加一个二进制可执行程序构建 + const exe = b.addExecutable(.{ + .name = "zig", + .root_source_file = .{ .path = "src/main.zig" }, + .target = target, + .optimize = optimize, + }); + + // 添加到顶级 install step 中作为依赖 + b.installArtifact(exe); + + // 此处开始构建单元测试 + + // 构建一个单元测试的 Compile + const exe_unit_tests = b.addTest(.{ + .root_source_file = .{ .path = "src/main.zig" }, + .target = target, + .optimize = optimize, + }); + + // 执行单元测试 + const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests); + + // 如果想要跳过外部来自于其他包的单元测试(例如依赖中的包),可以使用 skip_foreign_checks + run_unit_tests.skip_foreign_checks = true; + + // 构建一个 step,用于执行测试 + const test_step = b.step("test", "Run unit tests"); + + // 测试 step 依赖上方构建的 run_exe_unit_tests + test_step.dependOn(&run_exe_unit_tests.step); +} + +``` + +以上代码中,先通过 `b.addTest` 构建一个单元测试的 `Compile`,随后进行执行并将其绑定到 `test` Step 上。 + +## 交叉编译 + TODO ## `embedFile` @@ -365,12 +439,16 @@ TODO ## 执行其他命令 +zig 的构建系统还允许我们执行一些额外的命令,录入根据 json 生成某些特定的文件(例如 zig 源代码),构建其他的编程语言(不只是 C / C++),如Golang、Rust、前端项目构建等等! + +### 文件生成 + TODO -## 文件生成 +### 构建纯 C 项目 TODO -## 交叉编译 +### 构建纯 C++ 项目 TODO