diff --git a/15_zig_build_fix.txt b/15_zig_build_fix.txt deleted file mode 100644 index 5e084769..00000000 --- a/15_zig_build_fix.txt +++ /dev/null @@ -1,262 +0,0 @@ - -src\main.zig:10:31: error: root source file struct 'Io' has no member named 'getStdOut' - const stdout_file = std.io.getStdOut().writer(); - ~~~~~~^~~~~~~~~~ -C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\Io.zig:1:1: note: struct declared here -const builtin = @import("builtin"); -^~~~~ -referenced by: - callMain [inlined]: C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\start.zig:627:37 - WinStartup: C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\start.zig:443:53 - 2 reference(s) hidden; use '-freference-trace=4' to see all references -error: the following command failed with 1 compilation errors: -"C:\\Users\\jin\\scoop\\apps\\zig-dev\\0.15.0-dev.1283\\zig.exe" build-exe -ODebug "-Mroot=C:\\Users\\jin\\code\\zig-course\\course\\c -ode\\15\\build_system\\basic\\src\\main.zig" --cache-dir .zig-cache --global-cache-dir "C:\\Users\\jin\\AppData\\Local\\zig" --name zi -g --zig-lib-dir "C:\\Users\\jin\\scoop\\apps\\zig-dev\\0.15.0-dev.1283\\lib\\" --listen=- - -Build Summary: 0/3 steps succeeded; 1 failed -install transitive failure -└─ install zig transitive failure - └─ compile exe zig Debug native 1 errors - -error: the following build command failed with exit code 1: -.zig-cache\o\22df4cf7dbdbf962cf23936c61889573\build.exe C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\zig.exe C:\Users\jin\scoop\app -s\zig-dev\0.15.0-dev.1283\lib C:\Users\jin\code\zig-course\course\code\15\build_system\basic .zig-cache C:\Users\jin\AppData\Local\zig - --seed 0x625a5d8f -Z22ccef05181dde7e -install -└─ install zig - └─ compile exe zig Debug native 1 errors -src\main.zig:10:31: error: root source file struct 'Io' has no member named 'getStdOut' - const stdout_file = std.io.getStdOut().writer(); - ~~~~~~^~~~~~~~~~ -C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\Io.zig:1:1: note: struct declared here -const builtin = @import("builtin"); -^~~~~ -referenced by: - callMain [inlined]: C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\start.zig:627:37 - WinStartup: C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\start.zig:443:53 - 2 reference(s) hidden; use '-freference-trace=4' to see all references -error: the following command failed with 1 compilation errors: -"C:\\Users\\jin\\scoop\\apps\\zig-dev\\0.15.0-dev.1283\\zig.exe" build-exe -fno-strip -ODebug "-Mroot=C:\\Users\\jin\\code\\zig-course -\\course\\code\\15\\build_system\\cli\\src\\main.zig" --cache-dir .zig-cache --global-cache-dir "C:\\Users\\jin\\AppData\\Local\\zig" ---name zig --zig-lib-dir "C:\\Users\\jin\\scoop\\apps\\zig-dev\\0.15.0-dev.1283\\lib\\" --listen=- - -Build Summary: 0/3 steps succeeded; 1 failed -install transitive failure -└─ install zig transitive failure - └─ compile exe zig Debug native 1 errors - -error: the following build command failed with exit code 1: -.zig-cache\o\5bd10d6c5035afe76329d62536957327\build.exe C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\zig.exe C:\Users\jin\scoop\app -s\zig-dev\0.15.0-dev.1283\lib C:\Users\jin\code\zig-course\course\code\15\build_system\cli .zig-cache C:\Users\jin\AppData\Local\zig - --seed 0x59ad36e3 -Z06a0c06bd5c06800 -build.zig:11:18: error: no field or member function named 'addStaticLibrary' in 'Build' - const lib = b.addStaticLibrary(.{ - ~^~~~~~~~~~~~~~~~~ -C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\Build.zig:1:1: note: struct declared here -const std = @import("std.zig"); -^~~~~ -build.zig:11:18: note: method invocation only supports up to one level of implicit pointer dereferencing -build.zig:11:18: note: use '.*' to dereference pointer -referenced by: - runBuild__anon_32108: C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\Build.zig:2211:33 - main: C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\compiler\build_runner.zig:352:29 - 4 reference(s) hidden; use '-freference-trace=6' to see all references -build.zig:13:10: error: no field named 'root_source_file' in struct 'Build.ExecutableOptions' - .root_source_file = b.path("src/main.zig"), - ^~~~~~~~~~~~~~~~ -C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\Build.zig:768:31: note: struct declared here -pub const ExecutableOptions = struct { - ^~~~~~ -referenced by: - runBuild__anon_32108: C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\Build.zig:2211:33 - main: C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\compiler\build_runner.zig:352:29 - 4 reference(s) hidden; use '-freference-trace=6' to see all references -install -└─ install hello - └─ compile exe hello Debug native 1 errors -src\main.zig:10:31: error: root source file struct 'Io' has no member named 'getStdOut' - const stdout_file = std.io.getStdOut().writer(); - ~~~~~~^~~~~~~~~~ -C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\Io.zig:1:1: note: struct declared here -const builtin = @import("builtin"); -^~~~~ -referenced by: - callMain [inlined]: C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\start.zig:627:37 - WinStartup: C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\start.zig:443:53 - 2 reference(s) hidden; use '-freference-trace=4' to see all references -error: the following command failed with 1 compilation errors: -"C:\\Users\\jin\\scoop\\apps\\zig-dev\\0.15.0-dev.1283\\zig.exe" build-exe -ODebug "-Mroot=C:\\Users\\jin\\code\\zig-course\\course\\c -ode\\15\\build_system\\step\\src\\main.zig" --cache-dir .zig-cache --global-cache-dir "C:\\Users\\jin\\AppData\\Local\\zig" --name hel -lo --zig-lib-dir "C:\\Users\\jin\\scoop\\apps\\zig-dev\\0.15.0-dev.1283\\lib\\" --listen=- - -Build Summary: 0/3 steps succeeded; 1 failed -install transitive failure -└─ install hello transitive failure - └─ compile exe hello Debug native 1 errors - -error: the following build command failed with exit code 1: -.zig-cache\o\e269fd4c82996e8b6efaa38022c4a79b\build.exe C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\zig.exe C:\Users\jin\scoop\app -s\zig-dev\0.15.0-dev.1283\lib C:\Users\jin\code\zig-course\course\code\15\build_system\step .zig-cache C:\Users\jin\AppData\Local\zig ---seed 0x1738a8dc -Z7116767a471854aa -install -└─ install zig - └─ compile exe zig Debug native 1 errors -src\main.zig:10:31: error: root source file struct 'Io' has no member named 'getStdOut' - const stdout_file = std.io.getStdOut().writer(); - ~~~~~~^~~~~~~~~~ -C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\Io.zig:1:1: note: struct declared here -const builtin = @import("builtin"); -^~~~~ -referenced by: - callMain [inlined]: C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\start.zig:627:37 - WinStartup: C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\start.zig:443:53 - 2 reference(s) hidden; use '-freference-trace=4' to see all references -error: the following command failed with 1 compilation errors: -"C:\\Users\\jin\\scoop\\apps\\zig-dev\\0.15.0-dev.1283\\zig.exe" build-exe -ODebug "-Mroot=C:\\Users\\jin\\code\\zig-course\\course\\c -ode\\15\\build_system\\test\\src\\main.zig" --cache-dir .zig-cache --global-cache-dir "C:\\Users\\jin\\AppData\\Local\\zig" --name zig - --zig-lib-dir "C:\\Users\\jin\\scoop\\apps\\zig-dev\\0.15.0-dev.1283\\lib\\" --listen=- - -Build Summary: 0/3 steps succeeded; 1 failed -install transitive failure -└─ install zig transitive failure - └─ compile exe zig Debug native 1 errors - -error: the following build command failed with exit code 1: -.zig-cache\o\52bd7ebf7a1e3f67b283bc7a1b1460ca\build.exe C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\zig.exe C:\Users\jin\scoop\app -s\zig-dev\0.15.0-dev.1283\lib C:\Users\jin\code\zig-course\course\code\15\build_system\test .zig-cache C:\Users\jin\AppData\Local\zig ---seed 0xca605874 -Z5dd6b5163b24fc08 -build.zig:19:10: error: no field named 'target' in struct 'Build.ExecutableOptions' - .target = target, - ^~~~~~ -C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\Build.zig:768:31: note: struct declared here -pub const ExecutableOptions = struct { - ^~~~~~ -referenced by: - runBuild__anon_32108: C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\Build.zig:2211:33 - main: C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\compiler\build_runner.zig:352:29 - 4 reference(s) hidden; use '-freference-trace=6' to see all references -C:\Users\jin\AppData\Local\zig\p\zig_msgpack-0.0.7-evvueE3MAADy-2EAgCGUYIf1tHC9-z4n2sDIldvTZcY8\build.zig:21:10: error: no field named - 'root_source_file' in struct 'Build.TestOptions' - .root_source_file = b.path(b.pathJoin(&.{ "src", "test.zig" })), - ^~~~~~~~~~~~~~~~ -C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\Build.zig:853:25: note: struct declared here -pub const TestOptions = struct { - ^~~~~~ -referenced by: - runBuild__anon_81738: C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\Build.zig:2211:33 - dependencyInner__anon_78976: C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\Build.zig:2192:29 - 8 reference(s) hidden; use '-freference-trace=10' to see all references -C:\Users\jin\AppData\Local\zig\p\zig_msgpack-0.0.7-evvueE3MAADy-2EAgCGUYIf1tHC9-z4n2sDIldvTZcY8\build.zig:33:10: error: no field named - 'root_source_file' in struct 'Build.ObjectOptions' - .root_source_file = b.path(b.pathJoin(&.{ "src", "msgpack.zig" })), - ^~~~~~~~~~~~~~~~ -C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\Build.zig:800:27: note: struct declared here -pub const ObjectOptions = struct { - ^~~~~~ -install -└─ install assembly_fixed - └─ compile exe assembly_fixed Debug native 1 errors -C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\start.zig:614:46: error: root source file struct 'assembly_fixed' has no membe -r named 'main' - const ReturnType = @typeInfo(@TypeOf(root.main)).@"fn".return_type.?; - ~~~~^~~~~ -course\code\15\assembly_fixed.zig:2:1: note: struct declared here - -^ -C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\start.zig:443:53: note: called inline here - std.os.windows.ntdll.RtlExitUserProcess(callMain()); - ~~~~~~~~^~ -referenced by: - comptime: C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\start.zig:68:30 - start: C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\std.zig:100:27 - 1 reference(s) hidden; use '-freference-trace=3' to see all references -error: the following command failed with 1 compilation errors: -"C:\\Users\\jin\\scoop\\apps\\zig-dev\\0.15.0-dev.1283\\zig.exe" build-exe -ODebug "-Mroot=C:\\Users\\jin\\code\\zig-course\\course\\c -ode\\15\\assembly_fixed.zig" -lc --cache-dir .zig-cache --global-cache-dir "C:\\Users\\jin\\AppData\\Local\\zig" --name assembly_fixed - --zig-lib-dir "C:\\Users\\jin\\scoop\\apps\\zig-dev\\0.15.0-dev.1283\\lib\\" --listen=- -install -└─ install echo_tcp_server - └─ compile exe echo_tcp_server Debug native 12 errors -error: lld-link: undefined symbol: WSAPoll - note: referenced by C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\os\windows.zig:1728 - note: .zig-cache\o\020cf0c8513b3bd5738a335ba568a372\echo_tcp_server_zcu.obj:(os.windows.poll) -error: lld-link: undefined symbol: ioctlsocket - note: referenced by C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\posix.zig:3634 - note: .zig-cache\o\020cf0c8513b3bd5738a335ba568a372\echo_tcp_server_zcu.obj:(posix.socket) - note: referenced by C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\posix.zig:4028 - note: .zig-cache\o\020cf0c8513b3bd5738a335ba568a372\echo_tcp_server_zcu.obj:(posix.setSockFlags) -error: lld-link: undefined symbol: WSAGetLastError - note: referenced by C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\posix.zig:3635 - note: .zig-cache\o\020cf0c8513b3bd5738a335ba568a372\echo_tcp_server_zcu.obj:(posix.socket) - note: referenced by C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\posix.zig:6658 - note: .zig-cache\o\020cf0c8513b3bd5738a335ba568a372\echo_tcp_server_zcu.obj:(posix.setsockopt) - note: referenced by C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\posix.zig:3776 - note: .zig-cache\o\020cf0c8513b3bd5738a335ba568a372\echo_tcp_server_zcu.obj:(posix.bind) - note: referenced 7 more times -error: lld-link: undefined symbol: setsockopt - note: referenced by C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\posix.zig:6656 - note: .zig-cache\o\020cf0c8513b3bd5738a335ba568a372\echo_tcp_server_zcu.obj:(posix.setsockopt) -error: lld-link: undefined symbol: closesocket - note: referenced by C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\os\windows.zig:1671 - note: .zig-cache\o\020cf0c8513b3bd5738a335ba568a372\echo_tcp_server_zcu.obj:(os.windows.closesocket) -error: lld-link: undefined symbol: WSAStartup - note: referenced by C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\os\windows.zig:1566 - note: .zig-cache\o\020cf0c8513b3bd5738a335ba568a372\echo_tcp_server_zcu.obj:(os.windows.WSAStartup) -error: lld-link: undefined symbol: WSASocketW - note: referenced by C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\os\windows.zig:1642 - note: .zig-cache\o\020cf0c8513b3bd5738a335ba568a372\echo_tcp_server_zcu.obj:(os.windows.WSASocketW) -error: lld-link: undefined symbol: bind - note: referenced by C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\os\windows.zig:1663 - note: .zig-cache\o\020cf0c8513b3bd5738a335ba568a372\echo_tcp_server_zcu.obj:(os.windows.bind) -error: lld-link: undefined symbol: listen - note: referenced by C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\os\windows.zig:1667 - note: .zig-cache\o\020cf0c8513b3bd5738a335ba568a372\echo_tcp_server_zcu.obj:(os.windows.listen) -error: lld-link: undefined symbol: getsockname - note: referenced by C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\os\windows.zig:1686 - note: .zig-cache\o\020cf0c8513b3bd5738a335ba568a372\echo_tcp_server_zcu.obj:(os.windows.getsockname) -error: lld-link: undefined symbol: accept - note: referenced by C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\os\windows.zig:1682 - note: .zig-cache\o\020cf0c8513b3bd5738a335ba568a372\echo_tcp_server_zcu.obj:(os.windows.accept) -error: lld-link: undefined symbol: WSASend - note: referenced by C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\net.zig:2083 - note: .zig-cache\o\020cf0c8513b3bd5738a335ba568a372\echo_tcp_server_zcu.obj:(net.Stream.Writer__struct_31094.sendBuf -s) -error: the following command failed with 12 compilation errors: -"C:\\Users\\jin\\scoop\\apps\\zig-dev\\0.15.0-dev.1283\\zig.exe" build-exe -ODebug "-Mroot=C:\\Users\\jin\\code\\zig-course\\course\\c -ode\\15\\echo_tcp_server.zig" -lc --cache-dir .zig-cache --global-cache-dir "C:\\Users\\jin\\AppData\\Local\\zig" --name echo_tcp_serv -er --zig-lib-dir "C:\\Users\\jin\\scoop\\apps\\zig-dev\\0.15.0-dev.1283\\lib\\" --listen=- -install -└─ install hello_world - └─ compile exe hello_world Debug native 1 errors -course\code\15\hello_world.zig:22:30: error: root source file struct 'Io' has no member named 'getStdOut' - const stdout = std.io.getStdOut().writer(); - ~~~~~~^~~~~~~~~~ -C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\Io.zig:1:1: note: struct declared here -const builtin = @import("builtin"); -^~~~~ -referenced by: - main: course\code\15\hello_world.zig:3:17 - callMain [inlined]: C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\start.zig:627:37 - callMainWithArgs [inlined]: C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\start.zig:587:20 - main: C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\lib\std\start.zig:602:28 - 1 reference(s) hidden; use '-freference-trace=5' to see all references -error: the following command failed with 1 compilation errors: -"C:\\Users\\jin\\scoop\\apps\\zig-dev\\0.15.0-dev.1283\\zig.exe" build-exe -ODebug "-Mroot=C:\\Users\\jin\\code\\zig-course\\course\\c -ode\\15\\hello_world.zig" -lc --cache-dir .zig-cache --global-cache-dir "C:\\Users\\jin\\AppData\\Local\\zig" --name hello_world --zig --lib-dir "C:\\Users\\jin\\scoop\\apps\\zig-dev\\0.15.0-dev.1283\\lib\\" --listen=- - -Build Summary: 118/125 steps succeeded; 3 failed; 10/10 tests passed -install transitive failure -├─ install assembly_fixed transitive failure -│ └─ compile exe assembly_fixed Debug native 1 errors -├─ install echo_tcp_server transitive failure -│ └─ compile exe echo_tcp_server Debug native 12 errors -└─ install hello_world transitive failure - └─ compile exe hello_world Debug native 1 errors - -error: the following build command failed with exit code 1: -.zig-cache\o\48912e7b0e7a403214ce8e205d9457a3\build.exe C:\Users\jin\scoop\apps\zig-dev\0.15.0-dev.1283\zig.exe C:\Users\jin\scoop\app -s\zig-dev\0.15.0-dev.1283\lib C:\Users\jin\code\zig-course .zig-cache C:\Users\jin\AppData\Local\zig --seed 0x9311a7fb -Z19e9ce87436cf -a8c - diff --git a/course/.vitepress/sidebar.ts b/course/.vitepress/sidebar.ts index 88d465f5..ec234449 100644 --- a/course/.vitepress/sidebar.ts +++ b/course/.vitepress/sidebar.ts @@ -216,6 +216,14 @@ export default [ text: "版本说明", collapsed: true, items: [ + { + text: "0.15.1 升级指南", + link: "/update/upgrade-0.15.1", + }, + { + text: "0.15.1 版本说明", + link: "/update/0.15.1-description", + }, { text: "0.14.0 升级指南", link: "/update/upgrade-0.14.0", diff --git a/course/basic/define-variable.md b/course/basic/define-variable.md index 0cad1cf0..9ff8fbd0 100644 --- a/course/basic/define-variable.md +++ b/course/basic/define-variable.md @@ -141,49 +141,6 @@ PS: 说实话,我认为这个设计并不太好。 为什么是作用域顶层呢?实际上,Zig 将一个源码文件看作是一个容器。 ::: -## `usingnamespace` - -关键字 `usingnamespace` 可以将一个容器中的所有 `pub` 声明混入到当前的容器中。 - -例如,可以使用 `usingnamespace` 将 `std` 标准库混入到 `main.zig` 这个容器中: - -```zig -const T = struct { - usingnamespace @import("std"); -}; -pub fn main() !void { - T.debug.print("Hello, World!\n", .{}); -} -``` - -注意:无法在结构体 `T` 内部直接使用混入的声明,需要使用 `T.debug` 这种方式才可以! - -`usingnamespace` 还可以使用 `pub` 关键字进行修饰,用于转发声明,这常用于组织 API 文件和 C 语言的 `import`。 - -```zig -pub usingnamespace @cImport({ - @cInclude("epoxy/gl.h"); - @cInclude("GLFW/glfw3.h"); - @cDefine("STBI_ONLY_PNG", ""); - @cDefine("STBI_NO_STDIO", ""); - @cInclude("stb_image.h"); -}); -``` - -相关的使用方法可以是这样的: - -```zig -pub usingnamespace @cImport({ - @cInclude("xcb/xcb.h"); - @cInclude("xcb/xproto.h"); -}); -``` - -针对以上引入的头文件,我们可以这样使用 `@This().xcb_generic_event_t`。 - -> [!IMPORTANT] -> 初次阅读此处感到困惑是正常的。在学习完后续概念后,此处内容将自然理解。 - ## `threadlocal` 变量可以使用 `threadlocal` 修饰符,使得该变量在不同线程中拥有不同的实例: diff --git a/course/code/15/hello_world.zig b/course/code/15/hello_world.zig index 19eec76e..9c1a521b 100644 --- a/course/code/15/hello_world.zig +++ b/course/code/15/hello_world.zig @@ -1,5 +1,3 @@ -const std = @import("std"); - pub fn main() !void { try One.main(); try Two.main(); @@ -8,6 +6,7 @@ pub fn main() !void { const One = struct { // #region one + const std = @import("std"); pub fn main() !void { std.debug.print("Hello, World!\n", .{}); } @@ -16,6 +15,7 @@ const One = struct { const Two = struct { // #region two + const std = @import("std"); pub fn main() !void { var stdout_buffer: [1024]u8 = undefined; var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer); @@ -35,6 +35,7 @@ const Two = struct { const Three = struct { // #region three + const std = @import("std"); pub fn main() !void { // 定义两个缓冲区 var stdout_buffer: [1024]u8 = undefined; // [!code focus] diff --git a/course/hello-world.md b/course/hello-world.md index b410fe1b..f2152503 100644 --- a/course/hello-world.md +++ b/course/hello-world.md @@ -81,9 +81,13 @@ Zig 本身没有内置的 `@print()` 函数,输出功能通常由标准库的 ## 更进一步:线程安全 -以上代码在单线程环境下工作良好,但在多线程环境中,多个线程同时调用 `print` 可能会导致输出内容交错混乱。为了保证线程安全,我们需要为 `writer` 添加锁。 +以上代码在单线程环境下工作良好,但在多线程环境中,多个线程同时调用 `print` 可能会导致输出内容交错混乱。 -你可以使用 `std.Thread.Mutex` 来实现一个线程安全的 `writer`。我们鼓励你阅读[标准库源码](https://ziglang.org/documentation/master/std/#std.Thread.Mutex)来深入了解其工作原理。 +为了保证线程安全,我们需要为 `writer` 添加锁。 + +你可以使用 `std.Thread.Mutex` 来实现一个线程安全的 `writer`。 + +我们鼓励你阅读[标准库源码](https://ziglang.org/documentation/master/std/#std.Thread.Mutex)来深入了解其工作原理。 ## 了解更多 diff --git a/course/index.md b/course/index.md index c1aacba8..852cdbb1 100644 --- a/course/index.md +++ b/course/index.md @@ -20,7 +20,7 @@ showVersion: false > 允许函数处理各种数据,以及一小组新的编译器指令,以允许使用反射访问有关这些类型的信息。 > Zig 还旨在提高代码的安全性,它不提供垃圾回收(GC),但是使用可选类型代替 `null` ,这避免了空指针的出现。 -![Cover Image](./public/cover_image.png "Cover Image") +![Cover Image](/cover_image.png "Cover Image") ## 为何使用 Zig diff --git a/course/prologue.md b/course/prologue.md index 08e40473..323695fe 100644 --- a/course/prologue.md +++ b/course/prologue.md @@ -28,4 +28,4 @@ C 很好,非常好,它非常成功,以至于 C 现在已经不再是一门 Zig 的社区需要更多的人来构建,所以我写了这个文档,帮助新人来更好的理解和学习 Zig! -![Cover Image](./public/cover_image.png "Cover Image") +![Cover Image](/cover_image.png "Cover Image") diff --git a/course/update/0.15.1-description.md b/course/update/0.15.1-description.md index 8f9a3835..51b2376e 100644 --- a/course/update/0.15.1-description.md +++ b/course/update/0.15.1-description.md @@ -6,239 +6,342 @@ showVersion: false # `0.15.1` -2025/1/20,`0.15.1` 发布,自上一个版本来历时 5 个月,共有 162 位贡献者参与,进行了 647 次提交! +2025/8/30,`0.15.1` 发布,自上一个版本来历时 5 个月,共有 162 位贡献者参与,进行了 647 次提交! -Zig 官方团队直接从 `0.14.0` 跨越到了 `0.15.1`。在默认选择 Zig 的 x86 后端后,调试编译速度提高了 **5** 倍;正在开发的 aarch64 后端也紧随其后。同时,随着 `Writergate` 事件以及一系列语言变更和标准库的调整,**大量** API 有破坏性更改;这预示着 async/await 即将重生;也是语言稳定化的最后关头。 +> 本次更新,Zig 团队直接从 `0.14.1` 跨越到了 `0.15.1`。 -## 编译器重大改进 +Zig 目前默认使用 x86 后端,调试编译速度提高了 **5** 倍;aarch64 后端正在开发中。 -### x86 后端性能突破 +目前 Zig 已经进入了语言稳定的最后关头,本次更新带来了部分 break change,同时一直等待的 async 特性也有苗头了。 -**调试模式**的编译速度提高了 **5** 倍;这是本次更新最显著的性能改进。x86 后端现在是**调试模式**的默认选择,为缩短开发周期提供了强有力的支持。 +## 系统最低版本要求 -### aarch64 后端开发进展 +| 操作系统(Operating System) | 最低版本要求(Minimum Version) | +| :--------------------------- | :-----------------------------: | +| Dragonfly BSD | 6.0 | +| FreeBSD | 14.0 | +| Linux | 5.10 | +| NetBSD | 10.1 | +| OpenBSD | 7.6 | +| macOS | 13.0 | +| Solaris | 11 | +| Windows | 10 | -aarch64 后端的开发也在稳步推进,持续优化 ARM 平台支持,为多架构开发提供更好的体验。 +## 语言变动 -### 增量编译功能增强 +小改动: -增量编译功能得到了进一步优化,现在支持: +packed union 字段现在不允许再单独指定 align 属性,这与 packed struct 的现有行为保持一致。此前即使为字段强制指定了对齐方式,也不会实际影响字段的对齐,这次迁移只需删去该部分即可。[#22997](https://github.com/ziglang/zig/pull/22997) -- 与文件系统监视结合使用 -- 仅检查编译错误模式 -- 更快的重建速度 +### 移除 async 和 await 关键字 -### 多线程代码生成 +`async` 和 `await` 关键字已被移除,`@frameSize` 也已删除。 -编译器现已支持多线程代码生成,能够充分利用多核 CPU 的性能优势。 +虽然 `suspend`、`resume` 及协程底层机制是否保留还需依据“无栈协程原语提案”进一步决定,但可以确认,Zig 语言层面将不再有 `async/await` 这样的关键字。 -## 语言特性重大调整 +未来异步相关能力将仅以标准库的一部分(比如 Io 接口)存在。 -### 移除 `usingnamespace` 关键字 +### 非穷尽枚举的 switch 改进 -这是一个**破坏性变更**,`usingnamespace` 关键字被完全移除。所有使用 `usingnamespace` 的代码都需要重写,建议采用显式导入方式替代,以提高代码可读性和可维护性。 +现在,针对非穷尽(non-exhaustive)枚举使用 `switch` 时,可以将显式枚举标签与 `_` 分支(代表所有未命名值)组合: -### 移除异步关键字 +```zig +switch (enum_val) { + .special_case_1 => foo(), + .special_case_2 => bar(), + _, .special_case_3 => baz(), +} +``` -`async` 和 `await` 关键字已被移除,当前异步编程模型也随之取消,为未来新的异步方案做准备。这预示着 Zig 协程 的重生。 +此外,`switch` 语句现在也允许同时使用 `else` 和 `_`: -### 增强对非穷尽枚举的 `switch` 支持 +```zig +const Enum = enum(u32) { + A = 1, + B = 2, + C = 44, + _ +}; -新增对非穷尽枚举使用 `switch` 语句的支持,提高了枚举处理的灵活性,能够更好地处理未知枚举值,增强代码的健壮性。 +fn someOtherFunction(value: Enum) void { + // 这样写会编译报错:“error: else and '_' prong in switch expression” + switch (value) { + .A => {}, + .C => {}, + else => {}, // 此处处理已命名但未列出的标签(这里就是 .B) + _ => {}, // 此处处理未命名标签 + } +} +``` -### 扩展布尔向量运算符支持 +### 布尔向量支持更多运算符 -布尔向量现在支持更多运算符,包括逻辑运算和比较运算。 +布尔向量现在支持按位非、按位与、按位或、按位异或,以及布尔非等运算。 -### 内联汇编:类型化的破坏描述符 +### 允许 @ptrCast 从单项指针转换为切片 -内联汇编现在支持类型化的 `clobber` 列表,提供了更好的类型安全保证。 +这是对 0.14.0 版本中 `@ptrCast` 支持切片长度转换特性的扩展。现在它还可以将单项指针转换为任意切片,返回一个引用与原始指针字节数相同的切片。 -### 指针转换能力增强 +```zig ptrcast-single.zig +const std = @import("std"); -`@ptrCast` 现在允许从单项指针转换为切片,提供了更大的灵活性。 +test "value to byte slice with @ptrCast" { + const val: u32 = 1; + const bytes: []const u8 = @ptrCast(&val); + switch (@import("builtin").target.cpu.arch.endian()) { + .little => try std.testing.expect(std.mem.eql(u8, bytes, "\x01\x00\x00\x00")), + .big => try std.testing.expect(std.mem.eql(u8, bytes, "\x00\x00\x00\x01")), + } +} +``` -### 调整 `undefined` 运算规则 +```sh +$ zig test ptrcast-single.zig +1/1 ptrcast-single.test.value to byte slice with @ptrCast...OK +All 1 tests passed. +``` -对 `undefined` 值的算术运算规则有所调整,任何与 `undefined` 的运算结果都将返回 `undefined`。 +注意,未来计划将此能力从 `@ptrCast` 移至新的 `@memCast` 内建函数,后者在设计上更安全,有助于避免意外越界访问。详情请见 [issue #23935](https://github.com/ziglang/zig/issues/23935)。 -### 加强有损转换检测 +### undefined 上的算术操作新规则 -对于可能导致精度损失的整数到浮点数转换,编译器会视为错误。 +Zig 0.15.x 开始规范 `undefined` 在不同场景下的行为,特别是在参与算术运算时的规则。简言之,只有那些永远不会导致非法行为的运算符才允许 `undefined` 作为操作数。其它情况,若操作数为 `undefined`,将触发非法行为(运行时报错)或编译时报错。 -## 标准库重大变更 +通用的最佳实践是:_始终避免对 `undefined` 进行任何操作_。这样一来,这一语言变更(及未来相关变动)基本不会影响你的代码。如果你受到了此项语言变更影响,你可能会在原本可以编译的代码上见到类似的报错: -### Writergate:I/O 接口完全重构 +```zig arith-on-undefined.zig +const a: u32 = 0; +const b: u32 = undefined; -这是本次更新中**最重大的破坏性更改**,被社区称为 "Writergate": +test "arithmetic on undefined" { + // 此处加法现在会报错 + _ = a + b; + // 解决方式就是直接避免该操作! +} +``` -- `std.io.Reader` 和 `std.io.Writer` 接口被完全重新设计 -- 新接口采用非泛型设计 -- 缓冲区位于接口之上 -- 旨在提高性能并减少不必要的拷贝 -- **需要大量代码重写** +```sh +$ zig test arith-on-undefined.zig +src/download/0.15.1/release-notes/arith-on-undefined.zig:6:13: error: use of undefined value here causes illegal behavior + _ = a + b; + ^ +``` -### 格式化系统调整 +### 整数到浮点的损失性转换会导致编译报错 -格式化系统进行了重要调整: +这类报错本就预期存在,只是直到现在才实现。若某整数值在 `comptime` 被强制转换为浮点类型,但该整数无法被该浮点数精确表示,则编译器现在会报错。例如: -- 调用自定义 `format` 方法需要使用 `{f}` 格式说明符 -- `format` 方法签名简化,移除了格式字符串和选项参数 -- 格式化打印不再处理 Unicode -- 新增了更多格式化说明符 +```zig lossy_int_to_float_coercion.zig +test "big float literal" { + const val: f32 = 123_456_789; + _ = val; +} +``` -### `ArrayList` 非托管化 +```sh +$ zig test lossy_int_to_float_coercion.zig +src/download/0.15.1/release-notes/lossy_int_to_float_coercion.zig:2:22: error: type 'f32' cannot represent integer value '123456789' + const val: f32 = 123_456_789; + ^~~~~~~~~~~ +``` -容器类型的重要变更: +通常的解决办法是将整数字面量改为浮点字面量,以此显式加入浮点数的舍入规则: -- `std.ArrayList` 现在默认采用非托管方式 -- 开发者需要显式提供分配器 -- 与其他非托管容器保持一致 -- 提供更好的内存管理控制 +```zig lossy_int_to_float_coercion_new.zig +test "big float literal" { + const val: f32 = 123_456_789.0; + _ = val; +} +``` -### 链表去泛型化 +```sh +$ zig test lossy_int_to_float_coercion_new.zig +1/1 lossy_int_to_float_coercion_new.test.big float literal...OK +All 1 tests passed. +``` -链表类型进行了重构,去除了泛型化设计。 +## 构建系统 -### HTTP 客户端和服务器 +未归类的变更: -标准库新增了 HTTP 支持,提供内置的 HTTP 客户端和服务器功能。 +- zig build: 在构建总结前输出一个换行 -### TLS 客户端 +### macOS 文件系统监听 -新增内置 TLS 支持,可以建立安全的 TLS 连接。 +现在,`zig build` 的 `--watch` 参数已支持 macOS 系统。在 Zig 0.14.0 时,这个参数虽然可用,但对大多数编辑器表现异常;而在 Zig 0.15.x 里,这一功能已被[重新实现](https://github.com/ziglang/zig/pull/24649),采用了 macOS 的 File System Events API,确保文件系统变更监听快速且可靠。 -### 环形缓冲区 +所以,如果此前因 macOS 问题没有使用 `--watch`,现在可以放心使用了。尤其是你想试用 [增量编译](https://ziglang.org/download/0.15.1/release-notes.html#Incremental-Compilation) 时,推荐为 `zig build` 传递 `--watch -fincremental`。 -新增了环形缓冲区类型,提供高效的循环缓冲区实现。 +### Web 界面与时间报告 -### 移除 BoundedArray +Zig 0.14.0 提供了用于内置模糊测试 fuzzer 的实验性 Web 界面。在 0.15.x 中,这一界面被扩展为更通用的构建系统 Web 界面。可通过 `zig build --webui` 选项启用。启用后,`zig build` 进程会在构建完成后持续运行。 -`BoundedArray` 被移除,建议使用 `ArrayList` 或固定大小数组替代。 +Web 界面本身主要显示所有构建步骤及其状态,同时有按钮可手动触发重新构建(所以可以作为 `zig build --watch` 流程的替代方式)。如果使用 `--fuzz`,则会暴露 [Fuzzer](https://ziglang.org/download/0.15.1/release-notes.html#Fuzzer) 相关界面,其内容与 0.14.0 基本一致。 -## 构建系统改进 +此外,Web 界面新增了“时间报告”功能。只需为 `zig build` 传递 `--time-report`,即可在 Web 界面上展开查看构建图中各步骤的耗时信息。尤其是每个 `std.Build.Step.Compile`,都会有详细的子阶段统计:Zig 编译器各部分的快慢情况,以及哪些文件/声明在语义分析、生成机器码、链接阶段消耗的时间最多。 -### 移除隐式根模块 +![](https://ziglang.org/download/0.15.1/release-notes/build-webui.png) -构建系统移除了对隐式根模块的支持,现在需要在构建脚本中明确指定模块;这提高了构建配置的清晰度和准确性。 +这是一项较高级别的功能,非常适合定位导致编译变慢的代码片段——只需展开 "Declarations" 表格,查看最耗时的前几项。 -### macOS 文件系统监视 +![](https://ziglang.org/download/0.15.1/release-notes/build-webui-time-report.png) -在 macOS 上新增了文件系统监视功能: +如果本次编译用到了 LLVM 后端,还会额外提供 LLVM pass 分阶段的耗时信息。 -- 能够在文件更改时自动触发重建 -- 支持 `--watch` 和 `--debounce` 选项 -- 显著提高开发效率 +## Compiler -### Web 界面和时间报告 +### x86 后端 -构建系统现在支持 Web 界面和详细的时间报告功能。 +**Zig 0.15.x 版本在 Debug 模式下默认启用了 Zig 自实现(self-hosted)的 x86_64 代码生成后端。** -### 模糊测试器 +更具体来说,现在只要目标架构是 x86_64 并且使用 Debug 模式,默认都会启用该后端(除了 NetBSD、OpenBSD 和 Windows,这几个平台目前因为 [链接器](https://ziglang.org/download/0.15.1/release-notes.html#Linker) 存在缺陷,仍然默认使用 LLVM 后端)。 -Zig 0.15.1 集成了一个内置的模糊测试器: +启用自实现 x86_64 后端后,你将可以直接感受到 Zig 项目过去几年投入的成果:编译速度显著提升——大多数场景下比 LLVM 快了大约 5 倍。**而这还只是开始**;自实现 x86_64 后端是专为 [增量编译](https://ziglang.org/download/0.15.1/release-notes.html#Incremental-Compilation) 而设计的,这项功能足够稳定时,预计还会有极大加速。极致的编译速度一直是 Zig 项目的核心目标之一,我们已经默默推进多年,这次发布是阶段性成果的集中体现。 -- 支持进程内模糊测试 -- 提供 Web UI 界面 -- 支持实时代码覆盖率显示 -- 可以快速发现代码中的潜在问题 +使用自实现 x86 后端,还能避免受上游 LLVM Bug 的影响(目前我们[正在跟踪 60 多个相关 Bug](https://github.com/ziglang/zig/issues?q=is%3Aissue%20state%3Aopen%20label%3Abackend-llvm%20label%3Aupstream))。事实上,自实现 x86 后端在我们的“行为测试集”上,已能通过比 LLVM 后端更多的用例(1984/2008,相比 LLVM 的 1977/2008)。换句话说,该后端对 Zig 语言的实现更为完整和准确。 -## 工具链更新 +当然,目前自实现 x86 后端本身也还[存在部分缺陷和 Bug](https://github.com/ziglang/zig/issues?q=is%3Aissue%20state%3Aopen%20label%3Abackend-self-hosted%20label%3Aarch-x86_64)。如果你遇到了相关问题,可以通过命令行参数 `-fllvm`,或在创建 `std.Build.Step.Compile` 时设置 `.use_llvm = true`,将 Debug 编译切换回 LLVM 后端。此外,当前自实现 x86 后端生成的机器码在性能上[略慢于 LLVM 后端](https://github.com/ziglang/zig/issues/24144)。 -### LLVM 20 +尽管如此,在绝大多数开发场景中,自研后端已经是更优秀的选择。比如 Zig 核心开发团队已经在很长一段时间内,主要用自研 x86 后端编译 Zig 编译器,极大提升了开发效率,现在 Zig 编译器只需几秒即可构建完成,而以往用 LLVM 则要 1-2 分钟。你也可以期待在自己项目的开发体验中获得类似提升。 -升级到 LLVM 20,带来了: +### aarch64 后端 -- 更好的优化支持 -- 新的目标架构支持 -- 改进的调试信息生成 -- 更好的 C++ 交互性 +在自实现 [x86 后端](https://ziglang.org/download/0.15.1/release-notes.html#x86-Backend) 已经足够成熟并启用为默认后,Jacob 将目标转向了新的架构:aarch64。该架构近年来越来越受欢迎,尤其是现代苹果电脑都基于它。因此,aarch64 成为了 Zig 项目在摆脱 LLVM 依赖的自研代码生成后端中的下一个重点。 -### FreeBSD 和 NetBSD libc 支持 +这个后端目前还在开发早期阶段,Jacob 已经能基于 x86 后端的经验,尝试全新的设计思路。虽然现在下结论还为时过早,但我们预计新设计将进一步提升编译器性能(甚至有望超越自实现 x86_64 后端),并提升输出机器码的质量,最终目标是在 Debug 模式下与 LLVM 的代码生成质量一较高下。你可以在这篇 [开发日志](https://ziglang.org/devlog/2025/#2025-07-23) 里看到更多细节。 -在交叉编译时新增了对动态链接的 FreeBSD 和 NetBSD libc 的支持。 +目前该后端已通过了 1656/1972(84%)项与 LLVM 行为一致性的测试,因此还未准备好作为默认后端启用,在实际项目中也暂时无法使用。但它正在快速进步,预计将在未来版本成为 Debug 模式下的默认选择。 -### glibc 2.42 +我们自实现代码生成后端的工作,是 Zig 长期计划的一部分,未来将 [使 LLVM 成为可选依赖](https://kristoff.it/blog/zig-new-relationship-llvm/),并[从编译器实现中解耦](https://github.com/ziglang/zig/issues/16270)。实现这一目标将显著提升编译速度,为 Debug 构建带来优秀的增量编译支持,甚至有可能探索 LLVM 无法高效支持的新语言特性。 -升级到 glibc 2.42,并支持静态链接本机 glibc。 +### 增量编译(Incremental Compilation) -### MinGW-w64 更新 +Zig 0.15.x 在正在开发中的增量编译(Incremental Compilation)功能上又取得了进展。该功能允许编译器只重新编译修改过的代码,从而极大提升二次编译的速度。包括文件导入变更相关的各种 Bug 在此版本中均有所修复。 -MinGW-w64 工具链得到了更新,进一步改进了对 Windows 的交叉编译支持。 +请注意,这依然属于实验性功能——目前仍有已知 Bug,可能导致错误编译或错误的编译报错。但现在已经足够稳定,可以与 `-fno-emit-bin` 结合起来可靠使用。**如果你有一个编译时间很长的庞大项目,非常建议结合使用 `--watch`、`-fincremental` 和 `-Dno-bin` 来改善编译反馈体验。**如果你不清楚如何在构建脚本里暴露 `-Dno-bin`,可以寻求社区帮助。 -### zig libc 和 zig cc 增强 +接下来的发布周期还会继续努力,目标是将增量编译默认开启。如果你有兴趣尝鲜,可以参考 [#21165](https://github.com/ziglang/zig/issues/21165) 了解详情。 -`zig libc` 和 `zig cc` 命令的功能得到了增强: +### 多线程代码生成(Threaded Codegen) -- 更好的 GCC 兼容性 -- 支持更多编译选项 -- 更清晰的错误报告 +Zig 编译器自设计之初就考虑到了并行化。通过让编译的不同阶段在多个线程间并行运行,显著提升了编译性能。Zig 早期还是主要单线程的,但从 0.14.0 版本起,部分底层代码生成后端已经能够与前端(语义分析阶段)并发执行。Zig 0.15.x 在此基础上更进一步,实现了语义分析、代码生成、链接这几个阶段可完全并行,且代码生成本身还能进一步拆分到多个线程中去。 -## 版本跳跃说明 +与 0.14.0 相比,开启自实现后端(如 x86 后端)后,这一改进通常会带来一次明显的编译性能提升。具体提升幅度与你编译的代码结构有关,有时变化不大,有时提升可高达 50%。举个实际例子:在某台机器上,使用自实现 x86_64 后端编译 Zig 编译器,耗时从 13.8 秒降到了 10.0 秒,提升了 27%。 -Zig 官方团队选择直接从 `0.14.0` 跳跃到 `0.15.1`,这一决策反映了: +[这份开发日志](https://ziglang.org/devlog/2025/#2025-06-14) 有更深入的技术细节。总之,得益于各阶段并行执行,当你使用自研后端时,编译速度会得到显著提升。[而且现在终端会显示更详细的进度信息。](https://asciinema.org/a/bgDEbDt4AkZWORDX1YBMuKBD3) -- 本次更新包含的重大变更数量之多 -- 对编译器性能的重要改进 -- 标准库接口的重大重构 -- 为未来版本奠定更坚实的基础 +### 支持在模块级别配置 UBSan 模式 -## 升级挑战与机遇 +现在 Zig CLI 和构建系统允许更灵活地控制 C 兼容未定义行为检测(UBSan)模式。`zig build-exe` 及相关命令现支持 `-fsanitize-c=trap` 和 `-fsanitize-c=full`,其中旧的 `-fsanitize-c` 就等价于 `-fsanitize-c=full`。 -### 主要挑战 +- 选择 `full` 时,UBSan 运行时会被编译并链接进你的程序,遇到未定义行为时提供更详尽的错误信息,但相应代码体积会略大。 +- 选择 `trap` 时,会插入陷阱指令,触发未定义行为时进程会收到 `SIGILL`,但是代码体积更小。 + 如未显式指定,默认模式由构建模式决定。 -1. **Writergate**:I/O 接口的完全重构需要重写大量相关代码 -2. **移除 `usingnamespace`**:需要调整导入方式 -3. **异步代码调整**:需要移除 async/await 使用 -4. **ArrayList 变更**:需要调整容器使用方式 +对于 [zig cc](https://ziglang.org/download/0.15.1/release-notes.html#zig-cc),在已有的 `-fsanitize=undefined` 外,现在也能理解 `-fsanitize-trap=undefined`,与 `zig build-exe` 上的 `-fsanitize-c=trap` 基本等价。 -### 主要机遇 +因为本次变更,`std.Build` API 里的 `sanitize_c` 字段类型从 `?bool` 替换成了 `?std.zig.SanitizeC`。如果你过去设置为 `true/false`,现在应分别切换为 `.full` 或 `.off`,以保持原有行为。 -1. **编译速度提升**:5 倍的调试编译速度改进 -2. **更清晰的代码**:移除隐式行为,提高代码可读性 -3. **更好的性能**:新的 I/O 接口设计更高效 -4. **开发效率**:文件系统监视功能和模糊测试器 +### 测试编译为对象文件(Compile Tests to Object File) -## 社区影响 +通常,Zig 的测试功能会直接构建一个可执行文件。但有些场景下,你可能需要只生成测试用的对象文件而非最终可执行文件,比如让外部代码以共享库方式加载你的应用。Zig 0.15.x 针对这些需求,允许测试生成对象文件,便于后续以你希望的方式进行链接。 -这次更新对 Zig 社区产生了重要影响: +命令行下,可通过运行 `zig test-obj`(而不是 `zig test`)实现。 -- **学习曲线**:新用户需要适应新的接口设计 -- **迁移工作**:现有项目需要进行大量调整 -- **性能收益**:编译速度的显著提升改善开发体验 -- **生态系统**:库作者需要更新以适配新接口 +使用构建系统时,可通过新版 `std.Build` API,在调用 `std.Build.addTest` 时传递 `emit_object` 选项,这样返回的 `Step.Compile` 会生成对象文件。这个对象文件和其他对象一样,可以被安装用于外部使用,或直接链接到其他 build 步骤。不过注意:启用此功能后,build runner 与 test runner 不会直接通信,退回到默认的 `zig test` 方式(即用 stderr 报告测试失败)。所以如果你用到这个特性,可能还需自定义 test runner,让它能与外部测试框架协作。 -## 技术债务清理 +### Zig Init -本次更新体现了 Zig 团队对技术债务的积极清理: +`zig init` 命令在本版本中配备了新版项目模板。 -- 移除了有争议的 `usingnamespace` 特性 -- 重构了性能不佳的 I/O 接口 -- 统一了容器类型的设计理念 -- 为未来的语言演进奠定坚实基础 +旧模板包含用于生成 Zig 模块静态库的代码,这容易让初学者误以为“生成静态库”是 Zig 代码复用的首选方式。 -## 未来展望 +新的项目模板则同时提供了 Zig 模块与可执行文件的样板代码。这符合大多数开发需求,同时也展示了如何将可复用逻辑拆分到模块中、并在应用中进行调用。如果你只需生成单一类型的产物,可以直接删除不需要的部分。而保留这些内容也能温和地提醒你: -`0.15.1` 为 Zig 的未来发展奠定了重要基础: +- 为你的库设计配套工具 +- 在你的可执行文件中方便地访问可复用逻辑 -- **编译性能**:为大型项目开发提供更好支持 -- **接口设计**:更一致、更高效的标准库 -- **开发体验**:更快的编译和更好的工具支持 -- **语言稳定性**:移除不稳定特性,为 1.0 做准备 +现在你可以通过在 `zig init` 命令后加上 `--minimal` 或 `-m` 参数,生成极简模板。执行该命令会创建 `build.zig.zon` 文件,并在不存在时,创建仅包含 `build` 函数框架的 `build.zig` 文件。这个选项适用于已经熟悉 Zig 构建系统且主要希望方便生成带有正确指纹的 Zon 文件的用户。 -## 路线图 +## 链接器(Linker) -### I/O 作为接口 +在本次发布周期中,Zig 的链接器仅进行了部分 Bug 修复与维护。但请注意,链接器将在[下一个发布周期](https://ziglang.org/download/0.15.1/release-notes.html#Roadmap)成为重点优化对象,目标是进一步改进增量编译(Incremental Compilation)相关体验。 + +## Fuzzer(模糊测试器) + +尽管核心团队一直对模糊测试保持极大热情,但在本发布周期内,团队成员未能投入足够精力推动 fuzzer 的进一步发展。我们在此感谢贡献者 Kendall Condon,他提交了一个 pull request [大幅提升 fuzzer 能力](https://github.com/ziglang/zig/pull/23416),目前正在耐心等待核心团队的后续协作。 + +## Bug 修复 + +[点此查看本次发布周期内关闭的 201 个 bug 报告的完整列表。](https://github.com/ziglang/zig/issues?q=is%3Aclosed+is%3Aissue+label%3Abug+milestone%3A0.15.0) + +在本次发布周期内,新的 bug 持续被发现和修复。为了简洁起见,绝大多数 bug 修复未在本发行说明中详细列出。 + +### 本版本仍然存在已知缺陷 + +Zig 依然有[已知 bug](https://github.com/ziglang/zig/issues?q=is%3Aopen+is%3Aissue+label%3Abug)、[误编译问题](https://github.com/ziglang/zig/issues?q=is%3Aopen+is%3Aissue+label%3Amiscompilation)和[回归缺陷](https://github.com/ziglang/zig/issues?q=is%3Aopen+is%3Aissue+label%3Amiscompilation)。 -I/O 系统将继续作为接口进行发展和完善,为未来的异步编程模型做准备。 +即使使用 Zig 0.15.x,在较复杂的项目中工作,也可能需要你主动参与到开发流程当中,一起反馈和解决问题。 -## 建议 +当 Zig 进入 1.0.0 正式版后,Tier 1 支持将会增加专门的 bug 管理政策作为强制要求。 -对于 Zig 开发者: +## 工具链(Toolchain) + +### LLVM 20 + +本次 Zig 升级到了 LLVM [20.1.8](https://releases.llvm.org/20.1.0/docs/ReleaseNotes.html)。此升级涵盖 Clang(`zig cc`/`zig c++`)、libc++、libc++abi、libunwind 以及 libtsan。 + +Zig 现已支持使用 LLVM 的 SPIR-V 后端(backend)。请注意,自托管的 SPIR-V 后端仍是默认选项。如需使用 LLVM 后端,可通过 `-fllvm` 参数进行构建。 + +### 交叉编译时支持 FreeBSD 动态链接 libc + +Zig 现在通过为动态链接的 libc 提供桩库(stub libraries),允许交叉编译到 FreeBSD 14+,这与 glibc 的交叉编译方式类似。此外,还会一并提供所有系统和 libc 头文件。 + +### 交叉编译时支持 NetBSD 动态链接 libc + +Zig 现在通过为动态链接的 libc 提供桩库,支持交叉编译到 NetBSD 10.1+,方式同 glibc 类似。同时也会提供所有系统及 libc 头文件。 + +### glibc 2.42 + +交叉编译时现已可用 glibc 2.42 版本。 + +#### 允许静态链接本地 glibc + +Zig 现在允许静态链接本地 glibc。尽管这通常不是一个好主意,但对于某些不依赖 glibc 动态特性的特殊场景(如 NSS、iconv 等内部依赖动态链接的功能未被使用时),可以这样做。 + +需要注意,若使用 Zig 内置的 glibc 进行交叉编译,该 glibc 仅以动态库形式提供,因此不适用静态链接。 + +### MinGW-w64 + +本版本将内置的 MinGW-w64 升级到提交号 `38c8142f660b6ba11e7c408f2de1e9f8bfaf839e`。 + +### zig libc + +本次发布开始尝试在 Zig 提供的静态链接 libc(目前包括 musl、wasi-libc 和 [MinGW-w64](https://ziglang.org/download/0.15.1/release-notes.html#MinGW-w64))之间共享代码。我们在新的 zig libc 库中用 Zig 代码重新实现了这些 libc 的通用函数。这意味着每个函数都将有唯一的权威实现,今后无需再分别修改上述项目的第三方 libc 代码即可改进实现。我们的长期目标是彻底摆脱对这些 libc 上游 C 实现代码的依赖,仅保留其头文件(headers),但这还需要很多工作。 + +这个工作非常欢迎社区贡献。如果你对此感兴趣,可查看 [issue #2879](https://github.com/ziglang/zig/issues/2879) 参与。 + +### zig cc + +zig cc 现在能正确识别 `-static` 和 `-dynamic` 标志。最值得注意的是,这允许静态链接本地 glibc,以及动态链接交叉编译的 musl。 + +### zig objcopy 功能回退 + +很抱歉,相关代码未达到质量标准,需重新设计。一部分功能仍可使用,另外一些功能会报“unimplemented”(未实现)的错误。详见 #24522。 + +## 路线图(Roadmap) + +0.16.0 版本周期的两大核心主题将是异步 I/O 和 aarch64 后端。 + +下一步要达成的重要里程碑包括: + +- 引入 I/O 作为 Interface(接口类型) +- 使 aarch64 后端成为 debug 模式下的默认后端 +- 改进链接器实现,消除对 LLD 的依赖,并支持增量编译 +- 加强内置 Fuzzer,使其具备与 AFL 及其它先进模糊测试工具竞争的能力 + +### I/O 作为接口 -1. **谨慎升级**:在测试环境中充分验证 -2. **分步迁移**:逐步调整代码以适配新接口 -3. **充分利用性能优势**:积极采用有关编译速度的改进 -4. **关注社区动态**:参与社区讨论,分享迁移经验和最佳实践 +未来,Zig 将把全部文件系统、网络、定时器、同步机制,以及任何可能阻塞(block)的内容,都重构为全新的 `std.Io` 接口。所有涉及 I/O 的代码都需要接收一个 `Io` 实例,类似于所有需要内存分配的代码都需要一个 `Allocator` 实例。 -`0.15.1` 是 Zig 发展历程中的一个重要里程碑,虽然带来了较多的破坏性变更,但为语言的长期发展和性能提升奠定了坚实的基础。这标志着语言稳定化的最后阶段,为 1.0 版本的正式发布做好了充分准备。 +这将让你可以编写对应用并发模型无感知的、可复用且高性能的包(package),支持[异步机制](https://kristoff.it/blog/asynchrony-is-not-concurrency/),发现更多类型的 bug,并让事件循环(event loop)成为 Zig 生态中的“一等公民”。 diff --git a/course/update/upgrade-0.15.1.md b/course/update/upgrade-0.15.1.md index 1924d1f1..c3a01234 100644 --- a/course/update/upgrade-0.15.1.md +++ b/course/update/upgrade-0.15.1.md @@ -5,1138 +5,657 @@ showVersion: false 本篇文档将介绍如何从 `0.14.0` 版本升级到 `0.15.1`。 -## 语言变更 +## 语言变动 ### 移除 `usingnamespace` -`usingnamespace` 关键字已被移除。以下是常见用例的替代方案: +`usingnamespace` 关键字已被完全移除。需要将其替换为更明确的声明方式。 -#### 用例:条件包含 +#### 条件包含 + +旧写法: ```zig -// 旧代码 -const builtin = @import("builtin"); -const os_impl = switch (builtin.os.tag) { - .linux => @import("os/linux.zig"), - .windows => @import("os/windows.zig"), - else => @compileError("Unsupported OS"), -}; -usingnamespace os_impl; +pub usingnamespace if (have_foo) struct { + pub const foo = 123; +} else struct {}; ``` -⬇️ +新写法: ```zig -// 新代码 -const builtin = @import("builtin"); -const os_impl = switch (builtin.os.tag) { - .linux => @import("os/linux.zig"), - .windows => @import("os/windows.zig"), - else => @compileError("Unsupported OS"), -}; +// 方案 1:直接声明(推荐) +pub const foo = 123; + +// 方案 2:使用 compileError +pub const foo = if (have_foo) + 123 +else + @compileError("foo not supported on this target"); -// 显式导出所需函数 -pub const open = os_impl.open; -pub const close = os_impl.close; -pub const read = os_impl.read; -pub const write = os_impl.write; +// 方案 3:使用哨兵值支持特性检测 +pub const foo = if (have_foo) 123 else {}; ``` -#### 用例:实现切换 +#### 多实现切换 + +旧写法: ```zig -// 旧代码 -const MyStruct = struct { - data: u32, - - usingnamespace if (builtin.mode == .Debug) - @import("debug_impl.zig") - else - @import("release_impl.zig"); +pub usingnamespace switch (target) { + .windows => struct { + pub const target_name = "windows"; + pub fn init() T { + // ... + } + }, + else => struct { + pub const target_name = "something good"; + pub fn init() T { + // ... + } + }, }; ``` -⬇️ +新写法: ```zig -// 新代码 -const Impl = if (builtin.mode == .Debug) - @import("debug_impl.zig") -else - @import("release_impl.zig"); - -const MyStruct = struct { - data: u32, - - pub fn doSomething(self: *MyStruct) void { - return Impl.doSomething(self); - } - - // 显式实现所有需要的方法 +pub const target_name = switch (target) { + .windows => "windows", + else => "something good", +}; +pub const init = switch (target) { + .windows => initWindows, + else => initOther, }; +fn initWindows() T { + // ... +} +fn initOther() T { + // ... +} ``` -#### 用例:混入 +#### Mixins 混入 + +旧写法: ```zig -// 旧代码 -fn LoggingMixin(comptime T: type) type { +pub fn CounterMixin(comptime T: type) type { return struct { - pub fn log(self: *T, message: []const u8) void { - std.log.info("{s}: {s}", .{ @typeName(T), message }); + pub fn incrementCounter(x: *T) void { + x.count += 1; + } + pub fn resetCounter(x: *T) void { + x.count = 0; } }; } -const MyStruct = struct { - data: u32, - usingnamespace LoggingMixin(@This()); +pub const Foo = struct { + count: u32 = 0, + pub usingnamespace CounterMixin(Foo); }; ``` -⬇️ +新写法(使用零位字段): ```zig -// 新代码 -fn LoggingMixin(comptime T: type) type { +pub fn CounterMixin(comptime T: type) type { return struct { - pub fn log(self: *T, message: []const u8) void { - std.log.info("{s}: {s}", .{ @typeName(T), message }); + pub fn increment(m: *@This()) void { + const x: *T = @alignCast(@fieldParentPtr("counter", m)); + x.count += 1; + } + pub fn reset(m: *@This()) void { + const x: *T = @alignCast(@fieldParentPtr("counter", m)); + x.count = 0; } }; } -const MyStruct = struct { - data: u32, - - const Mixin = LoggingMixin(@This()); - - pub fn log(self: *MyStruct, message: []const u8) void { - Mixin.log(self, message); - } +pub const Foo = struct { + count: u32 = 0, + counter: CounterMixin(Foo) = .{}, }; + +// 使用方式 +// foo.counter.increment() 替代 foo.incrementCounter() ``` -### 移除 `async` 和 `await` 关键字 +### 非穷尽枚举的 switch 改进 -`async` 和 `await` 关键字已被移除。这为未来引入新的异步编程方案做准备。 +现在可以在非穷尽枚举的 switch 中组合使用显式标签和 `_` 分支: ```zig -// 旧代码 - 将不再工作 -fn asyncFunction() async void { - // 异步代码 -} - -fn caller() void { - const frame = async asyncFunction(); - await frame; +switch (enum_val) { + .special_case_1 => foo(), + .special_case_2 => bar(), + _, .special_case_3 => baz(), } ``` -目前需要使用其他方式处理并发,等待未来版本中新的异步编程支持。 - -### 对非穷尽枚举的 `switch` 支持 - -现在可以对非穷尽枚举使用 `switch` 语句: +注意:不能同时使用 `else` 和 `_`: ```zig -const MyEnum = enum(u8) { - foo = 1, - bar = 2, - _, +const Enum = enum(u32) { + A = 1, + B = 2, + C = 44, + _ }; -fn handleEnum(value: MyEnum) void { +fn someFunction(value: Enum) void { + // 错误:不能同时使用 else 和 _ switch (value) { - .foo => std.debug.print("foo\n", .{}), - .bar => std.debug.print("bar\n", .{}), - else => std.debug.print("unknown\n", .{}), + .A => {}, + .C => {}, + else => {}, // 处理已命名但未列出的标签 + _ => {}, // 处理未命名标签 } } ``` -### 允许对布尔向量使用更多运算符 +### 内联汇编:类型化的 clobber 描述符 -布尔向量现在支持更多运算符: +旧写法: ```zig -test "boolean vector operations" { - const vec_a: @Vector(4, bool) = .{ true, false, true, false }; - const vec_b: @Vector(4, bool) = .{ false, true, true, false }; - - const and_result = vec_a & vec_b; - const or_result = vec_a | vec_b; - const xor_result = vec_a ^ vec_b; - const not_result = ~vec_a; +pub fn syscall1(number: usize, arg1: usize) usize { + return asm volatile ("syscall" + : [ret] "={rax}" (-> usize), + : [number] "{rax}" (number), + [arg1] "{rdi}" (arg1), + : "rcx", "r11" + ); } ``` -### 内联汇编:类型化的破坏描述符 - -内联汇编现在支持类型化的 clobber 列表: +新写法: ```zig -// 旧代码 -asm volatile ("mov %[src], %[dst]" - : [dst] "=r" (dst) - : [src] "r" (src) - : "memory" // 字符串形式 -); +pub fn syscall1(number: usize, arg1: usize) usize { + return asm volatile ("syscall" + : [ret] "={rax}" (-> usize), + : [number] "{rax}" (number), + [arg1] "{rdi}" (arg1), + : .{ .rcx = true, .r11 = true }); +} ``` -⬇️ +可以使用 `zig fmt` 自动升级。 -```zig -// 新代码 -asm volatile ("mov %[src], %[dst]" - : [dst] "=r" (dst) - : [src] "r" (src) - : .memory // 类型化形式 -); -``` +### @ptrCast 从单项指针转换为切片 -### 允许 `@ptrCast` 从单项指针到切片的转换 - -现在可以使用 `@ptrCast` 将单项指针转换为切片: +现在 `@ptrCast` 可以将单项指针转换为切片: ```zig -test "ptrCast to slice" { - var value: u32 = 42; - const ptr: *u32 = &value; - - // 新功能:将单项指针转换为切片 - const slice: []u32 = @ptrCast(ptr); - - std.testing.expect(slice[0] == 42); -} +const val: u32 = 1; +const bytes: []const u8 = @ptrCast(&val); ``` -### 对 `undefined` 进行算术运算的新规则 +注意:未来计划将此功能移至 `@memCast`。 -`undefined` 值的算术运算规则发生了变化: - -```zig -test "undefined arithmetic" { - const a: i32 = undefined; - const b: i32 = 10; - - // 任何与 undefined 的运算都返回 undefined - const result = a + b; // result 是 undefined - _ = result; - - // 更安全的做法 - const safe_a: i32 = 0; // 显式初始化 - const safe_result = safe_a + b; - std.testing.expect(safe_result == 10); -} -``` +### undefined 上的算术操作 -### 对从整数到浮点数的有损转换发出错误 +只有永远不会导致非法行为的运算符才允许 `undefined` 作为操作数。 -现在对于可能导致精度损失的转换会发出编译错误: +错误示例: ```zig -test "lossy integer to float conversion" { - const large_int: u64 = 0x1FFFFFFFFFFFFF; // 53 位 - - // 这将产生编译错误,因为 f64 只有 52 位尾数 - // const float_val: f64 = @floatFromInt(large_int); // 错误! - - // 需要显式使用有损转换 - const float_val: f64 = @floatFromInt(@as(u53, @truncate(large_int))); - - std.debug.print("Float: {}\n", .{float_val}); -} +const a: u32 = 0; +const b: u32 = undefined; +_ = a + b; // 错误:对 undefined 的使用导致非法行为 ``` -## 标准库 - -### Writergate - -这是本次更新中最重大的破坏性更改,原有的 `std.io` 中的读写器接口被完全重新设计。 +最佳实践:**始终避免对 undefined 进行任何操作**。 -#### 动机 +### 整数到浮点的损失性转换 -旧的 I/O 系统存在以下问题: +编译时整数转换为浮点数时,如果无法精确表示,现在会报错: -- 泛型接口导致编译时间过长 -- 缓冲区管理不一致 -- 性能不佳,存在不必要的内存拷贝 -- 接口复杂,难以优化 - -#### 适配器 API - -新的设计引入了适配器模式: +错误示例: ```zig -// 旧的泛型接口 -fn processData(reader: anytype, writer: anytype) !void { - var buffer: [1024]u8 = undefined; - while (true) { - const bytes_read = try reader.read(&buffer); - if (bytes_read == 0) break; - try writer.writeAll(buffer[0..bytes_read]); - } -} +const val: f32 = 123_456_789; // 错误:f32 无法表示此整数值 ``` -⬇️ +修复方法: ```zig -// 新的适配器接口 -fn processData(reader: std.Io.Reader, writer: std.Io.Writer) !void { - var buffer: [1024]u8 = undefined; - while (true) { - const bytes_read = try reader.read(&buffer); - if (bytes_read == 0) break; - try writer.writeAll(buffer[0..bytes_read]); - } -} - -// 使用时需要适配器 -const file = try std.fs.cwd().openFile("input.txt", .{}); -defer file.close(); - -const stdout = std.io.getStdOut(); - -try processData( - file.reader().adapter(), // 适配器转换 - stdout.writer().adapter(), // 适配器转换 -); +const val: f32 = 123_456_789.0; // 使用浮点字面量 ``` -### 新的 `std.Io.Writer` 和 `std.Io.Reader` API - -新的 API 采用**非泛型设计**: - -```zig -// std.Io.Writer 的定义 -pub const Writer = struct { - ptr: *anyopaque, - vtable: *const VTable, - - pub const VTable = struct { - write: *const fn (*anyopaque, []const u8) anyerror!usize, - writeAll: *const fn (*anyopaque, []const u8) anyerror!void, - writeByte: *const fn (*anyopaque, u8) anyerror!void, - }; - - pub fn write(self: Writer, bytes: []const u8) !usize { - return self.vtable.write(self.ptr, bytes); - } +## 标准库 - pub fn writeAll(self: Writer, bytes: []const u8) !void { - return self.vtable.writeAll(self.ptr, bytes); - } -}; -``` +### Writer 和 Reader 重大变更 -#### `std.fs.File.Reader` 和 `std.fs.File.Writer` +这是 0.15.1 最大的破坏性变更。所有 `std.io` 的 reader 和 writer 都已弃用,需要迁移到新的 `std.Io.Reader` 和 `std.Io.Writer`。 -文件 I/O 的使用方式也发生了变化: +#### 主要变化 -```zig -// 旧代码 -const file = try std.fs.cwd().openFile("data.txt", .{}); -defer file.close(); +1. **新接口是非泛型的**:不再使用 `anytype` +2. **缓冲区在接口内部**:不需要单独的 BufferedReader/Writer +3. **明确的错误集合**:每个函数都有具体的 error set +4. **新增高级特性**:支持向量、填充、直接文件传输等 -const reader = file.reader(); -var buffer: [1024]u8 = undefined; -const bytes_read = try reader.read(&buffer); -``` +#### 适配旧代码 -⬇️ +如果你有旧的 writer,可以使用适配器: ```zig -// 新代码 -const file = try std.fs.cwd().openFile("data.txt", .{}); -defer file.close(); - -// 方式 1:直接使用文件方法 -var buffer: [1024]u8 = undefined; -const bytes_read = try file.read(&buffer); - -// 方式 2:使用新的 Reader 接口 -const reader = file.reader(); -const io_reader = reader.adapter(); -const bytes_read2 = try io_reader.read(&buffer); +fn foo(old_writer: anytype) !void { + var adapter = old_writer.adaptToNewApi(&.{}); + const w: *std.Io.Writer = &adapter.new_interface; + try w.print("{s}", .{"example"}); +} ``` -#### 升级 `std.io.getStdOut().writer().print()` +#### 升级 stdout -标准输出的使用方式也需要调整: +旧写法: ```zig -// 旧代码 const stdout = std.io.getStdOut().writer(); -try stdout.print("Hello, {s}!\n", .{"World"}); +try stdout.print("...", .{}); ``` -⬇️ +新写法: ```zig -// 新代码 -// 方式 1:使用 std.debug.print(推荐) -std.debug.print("Hello, {s}!\n", .{"World"}); - -// 方式 2:使用新的 Writer 接口 -const stdout = std.io.getStdOut(); -const writer = stdout.writer().adapter(); -try writer.print("Hello, {s}!\n", .{"World"}); - -// 方式 3:直接使用文件方法 -const stdout = std.io.getStdOut(); -try stdout.writeAll("Hello, World!\n"); -``` +var stdout_buffer: [1024]u8 = undefined; +var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer); +const stdout = &stdout_writer.interface; -#### 重构 `std.compress.flate` +try stdout.print("...", .{}); -压缩相关的代码也需要大量修改: - -```zig -// 旧代码 -var deflate_stream = std.compress.flate.deflateStream(allocator, writer); -defer deflate_stream.deinit(); -try deflate_stream.writer().writeAll(data); -try deflate_stream.finish(); +try stdout.flush(); // 别忘记 flush! ``` -⬇️ - -```zig -// 新代码 -var deflate_stream = std.compress.flate.DeflateStream.init(allocator, writer.adapter()); -defer deflate_stream.deinit(); -try deflate_stream.writeAll(data); -try deflate_stream.finish(); -``` - -#### 删除 `CountingWriter` - -`CountingWriter` 被删除,需要手动计数: +#### std.fs.File.Reader 和 Writer -```zig -// 旧代码 -var counting_writer = std.io.countingWriter(base_writer); -``` - -⬇️ +新的 `std.fs.File.Reader` 会缓存文件信息: ```zig -// 新代码 - 需要手动计数 -var bytes_written: usize = 0; +var file_reader = file.reader(&buffer); +const reader: *std.Io.Reader = &file_reader.interface; ``` -#### 删除 `BufferedWriter` +#### compress.flate 重构 -`BufferedWriter` 被重构: +旧写法: ```zig -// 旧代码 -var buffered_writer = std.io.bufferedWriter(base_writer); +var decompress = try std.compress.flate.decompressor(allocator, reader, null); +defer decompress.deinit(); ``` -⬇️ +新写法: ```zig -// 新代码 -var buffer: [4096]u8 = undefined; -var buffered_writer = std.io.BufferedWriter(4096, @TypeOf(base_writer)).init(base_writer); +var decompress_buffer: [std.compress.flate.max_window_len]u8 = undefined; +var decompress: std.compress.flate.Decompress = .init(reader, .zlib, &decompress_buffer); +const decompress_reader: *std.Io.Reader = &decompress.reader; + +// 如果要直接写入 writer,可以使用空缓冲: +var decompress: std.compress.flate.Decompress = .init(reader, .zlib, &.{}); +const n = try decompress.streamRemaining(writer); ``` -### 调用 `format` 方法需要使用 `{f}` +**注意**:压缩功能已被移除。 -现在调用自定义的 `format` 方法需要使用 `{f}` 格式说明符: +#### CountingWriter 已删除 -```zig -const Point = struct { - x: f32, - y: f32, +根据需求选择替代方案: - pub fn format(self: Point, writer: anytype) !void { - try writer.print("Point({d}, {d})", .{ self.x, self.y }); - } -}; +- 丢弃字节:使用 `std.Io.Writer.Discarding` +- 分配字节:使用 `std.Io.Writer.Allocating` +- 固定缓冲区:使用 `std.Io.Writer.fixed` -// 使用时必须使用 {f} -const point = Point{ .x = 1.0, .y = 2.0 }; -std.debug.print("{f}\n", .{point}); // 注意使用 {f} -``` +#### BufferedWriter 已删除 -### `format` 方法不再使用格式字符串或选项 - -格式化方法的签名已经简化: +旧写法: ```zig -// 旧代码 -const Point = struct { - x: f32, - y: f32, - - pub fn format( - self: Point, - comptime fmt: []const u8, // 被移除 - options: std.fmt.FormatOptions, // 被移除 - writer: anytype, - ) !void { - _ = fmt; - _ = options; - try writer.print("Point({d}, {d})", .{ self.x, self.y }); - } -}; -``` +const stdout_file = std.fs.File.stdout().writer(); +var bw = std.io.bufferedWriter(stdout_file); +const stdout = bw.writer(); -⬇️ - -```zig -// 新代码 -const Point = struct { - x: f32, - y: f32, - - pub fn format( - self: Point, - writer: anytype, // 只保留 writer 参数 - ) !void { - try writer.print("Point({d}, {d})", .{ self.x, self.y }); - } -}; +try stdout.print("...\n", .{}); +try bw.flush(); ``` -### 格式化打印不再处理 Unicode - -Unicode 处理被移除,需要手动处理: +新写法: ```zig -// 旧代码 -std.debug.print("你好,{s}!\n", .{"世界"}); // 自动处理 Unicode -``` - -⬇️ +var stdout_buffer: [4096]u8 = undefined; +var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer); +const stdout = &stdout_writer.interface; -```zig -// 新代码 - 需要手动处理 Unicode -const message = "你好,世界!"; -std.debug.print("{s}\n", .{message}); // 仍然可以显示,但不保证所有 Unicode 处理 +try stdout.print("...\n", .{}); +try stdout.flush(); ``` -### 新的格式化打印说明符 - -新增了一些格式化说明符: +### 格式化打印变更 -```zig -const value: u32 = 255; - -// 新的格式化选项 -std.debug.print("{d}\n", .{value}); // 十进制:255 -std.debug.print("{x}\n", .{value}); // 十六进制:ff -std.debug.print("{X}\n", .{value}); // 大写十六进制:FF -std.debug.print("{o}\n", .{value}); // 八进制:377 -std.debug.print("{b}\n", .{value}); // 二进制:11111111 - -// 浮点数格式化 -const pi: f64 = 3.14159; -std.debug.print("{d:.2}\n", .{pi}); // 保留两位小数:3.14 -std.debug.print("{e}\n", .{pi}); // 科学计数法:3.14159e+00 - -// 指针和切片 -const ptr: *u32 = &value; -const slice: []const u8 = "hello"; -std.debug.print("{*}\n", .{ptr}); // 指针地址 -std.debug.print("{s}\n", .{slice}); // 字符串 -std.debug.print("{any}\n", .{slice}); // 通用格式化 -``` +#### "{f}" 必须显式调用 format 方法 -### 去泛型化链表 - -链表类型也进行了重构: +旧写法: ```zig -// 旧代码 -const Node = std.SinglyLinkedList(i32).Node; -var list = std.SinglyLinkedList(i32){}; -var node = Node{ .data = 42 }; -list.prepend(&node); +std.debug.print("{}", .{std.zig.fmtId("example")}); ``` -⬇️ +新写法: ```zig -// 新代码 -const SinglyLinkedList = std.SinglyLinkedList; -const Node = SinglyLinkedList.Node; - -var list: SinglyLinkedList = .{}; -var node = Node{ .data = @as(*anyopaque, @ptrCast(&@as(i32, 42))) }; -list.prepend(&node); - -// 或者使用新的 API -var typed_list = std.DoublyLinkedList(i32){}; -var typed_node = std.DoublyLinkedList(i32).Node{ .data = 42 }; -typed_list.append(&typed_node); +std.debug.print("{f}", .{std.zig.fmtId("example")}); ``` -### `std.Progress` 支持进度条转义码 - -进度条系统得到了增强,支持更多的终端转义码。 +使用 `-freference-trace` 可以帮助排查所有格式字符串问题。 -### HTTP 客户端和服务器 +#### format 方法签名变更 -标准库新增了 HTTP 支持: +旧签名: ```zig -// HTTP 客户端示例 -const std = @import("std"); - -pub fn main() !void { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - - var client = std.http.Client{ .allocator = allocator }; - defer client.deinit(); - - const uri = std.Uri.parse("https://httpbin.org/get") catch unreachable; - - var headers = std.http.Headers{ .allocator = allocator }; - defer headers.deinit(); - - try headers.append("User-Agent", "Zig HTTP Client"); - - var request = try client.open(.GET, uri, headers, .{}); - defer request.deinit(); - - try request.send(.{}); - try request.wait(); - - const body = try request.reader().readAllAlloc(allocator, 8192); - defer allocator.free(body); - - std.debug.print("Response: {s}\n", .{body}); -} +pub fn format( + this: @This(), + comptime format_string: []const u8, + options: std.fmt.FormatOptions, + writer: anytype, +) !void { ... } ``` -### TLS 客户端 - -内置 TLS 支持: +新签名: ```zig -// TLS 连接示例 -const std = @import("std"); - -pub fn main() !void { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - - const address = try std.net.Address.parseIp("93.184.216.34", 443); // example.com - const stream = try std.net.tcpConnectToAddress(address); - defer stream.close(); - - var tls_client = try std.crypto.tls.Client.init(stream, .{ - .host = "example.com", - .allocator = allocator, - }); - defer tls_client.deinit(); - - const request = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"; - try tls_client.writeAll(request); - - var buffer: [4096]u8 = undefined; - const bytes_read = try tls_client.read(&buffer); - std.debug.print("Response: {s}\n", .{buffer[0..bytes_read]}); -} +pub fn format(this: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void { ... } ``` -### `ArrayList`:将非托管模式设为默认 +如果需要不同的格式化方法,有三种方案: -这是一个重大的破坏性更改。`std.ArrayList` 现在默认采用 **非托管 (unmanaged)** 模式: +1. 定义不同的格式化方法: ```zig -// 旧代码 -const std = @import("std"); - -fn oldArrayListExample(allocator: std.mem.Allocator) !void { - var list = std.ArrayList(i32).init(allocator); - defer list.deinit(); - - try list.append(42); - try list.appendSlice(&[_]i32{ 1, 2, 3 }); - - for (list.items) |item| { - std.debug.print("{d} ", .{item}); - } -} +pub fn formatB(foo: Foo, writer: *std.Io.Writer) std.Io.Writer.Error!void { ... } +// 使用:.{std.fmt.alt(Foo, .formatB)} ``` -⬇️ +2. 使用 `std.fmt.Alt`: ```zig -// 新代码 -const std = @import("std"); - -fn newArrayListExample(allocator: std.mem.Allocator) !void { - // 方式 1:使用新的 ArrayListUnmanaged - var list: std.ArrayListUnmanaged(i32) = .empty; - defer list.deinit(allocator); - - try list.append(allocator, 42); - try list.appendSlice(allocator, &[_]i32{ 1, 2, 3 }); - - for (list.items) |item| { - std.debug.print("{d} ", .{item}); - } -} - -// 方式 2:使用别名保持兼容性 -fn compatibilityExample(allocator: std.mem.Allocator) !void { - // ArrayList 现在是 ArrayListUnmanaged 的别名 - const ArrayList = std.ArrayListUnmanaged; - var list: ArrayList(i32) = .empty; - defer list.deinit(allocator); - - try list.append(allocator, 42); -} - -// 方式 3:使用新的初始化方法 -fn newInitExample(allocator: std.mem.Allocator) !void { - var list = std.ArrayList(i32).init(allocator); // 仍然可用,但已弃用 - defer list.deinit(); - - // 或者使用新的方式 - var new_list: std.ArrayList(i32) = .{}; - defer new_list.deinit(allocator); - - try new_list.append(allocator, 42); +pub fn bar(foo: Foo, context: i32) std.fmt.Alt(F, F.baz) { + return .{ .data = .{ .context = context } }; } ``` -其他容器类型也发生了类似的变化: +3. 返回实现 format 的结构: ```zig -// HashMap -var map: std.HashMapUnmanaged([]const u8, i32, std.hash_map.StringContext, 80) = .{}; -defer map.deinit(allocator); - -try map.put(allocator, "key", 42); -const value = map.get("key"); - -// ArrayHashMap -var array_map: std.ArrayHashMapUnmanaged([]const u8, i32, std.hash_map.StringContext, false) = .{}; -defer array_map.deinit(allocator); - -try array_map.put(allocator, "key", 42); - -// PriorityQueue -var pq: std.PriorityQueueUnmanaged(i32, void, compareInts) = .{}; -defer pq.deinit(allocator); - -try pq.add(allocator, 42); - -fn compareInts(context: void, a: i32, b: i32) std.math.Order { - _ = context; - return std.math.order(a, b); +pub fn bar(foo: Foo, context: i32) F { + return .{ .context = 1234 }; } +const F = struct { + context: i32, + pub fn format(f: F, writer: *std.Io.Writer) std.Io.Writer.Error!void { ... } +}; ``` -### 环形缓冲区 +#### 格式化打印不再支持 Unicode -新增了环形缓冲区类型: +对齐功能现在仅支持 ASCII/字节,不再支持 Unicode 码点。 -```zig -const RingBuffer = std.RingBuffer; - -// 创建环形缓冲区 -var buffer: [16]u8 = undefined; -var ring = RingBuffer.init(&buffer); +#### 新格式化符号 -// 写入数据 -const data = "Hello, World!"; -const written = ring.write(data); -std.debug.print("Written {} bytes\n", .{written}); - -// 读取数据 -var read_buffer: [32]u8 = undefined; -const read_count = ring.read(&read_buffer); -std.debug.print("Read: {s}\n", .{read_buffer[0..read_count]}); -``` +- `{t}` - 等同于 `@tagName()` 和 `@errorName()` +- `{d}` - 可用于自定义类型(需实现 `formatNumber` 方法) +- `{b64}` - 以标准 base64 输出字符串 -### 移除 `BoundedArray` +### 链表类型去泛型 -`BoundedArray` 被移除,建议使用其他替代方案: +旧写法: ```zig -// 旧代码 -var bounded = std.BoundedArray(i32, 10).init(0); -try bounded.append(42); +std.DoublyLinkedList(T).Node ``` -⬇️ +新写法: ```zig -// 新代码 - 使用 ArrayList 或数组 -var list: std.ArrayListUnmanaged(i32) = .empty; -defer list.deinit(allocator); - -// 或者使用固定大小数组 -var array: [10]i32 = undefined; -var count: usize = 0; - -if (count < array.len) { - array[count] = 42; - count += 1; +struct { + node: std.DoublyLinkedList.Node, + data: T, } ``` -### 删除和弃用 +使用 `@fieldParentPtr` 可通过 node 找到 data。 -本次更新中删除和弃用了多个 API,需要使用新的替代方案。 - -## 构建系统 +### std.Progress 支持进度条 -### 移除已弃用的隐式根模块 - -构建系统中已移除对隐式根模块的支持,需要在构建脚本中明确指定模块: +`std.Progress` 新增 `setStatus` 方法: ```zig -// 旧的 build.zig -pub fn build(b: *std.Build) void { - const exe = b.addExecutable(.{ - .name = "app", - .root_source_file = b.path("src/main.zig"), - .target = target, - .optimize = optimize, - }); -} -``` - -⬇️ - -```zig -// 新的 build.zig -pub fn build(b: *std.Build) void { - const exe = b.addExecutable(.{ - .name = "app", - .root_module = b.createModule(.{ - .root_source_file = b.path("src/main.zig"), - .target = target, - .optimize = optimize, - }), - }); -} -``` - -### macOS 文件系统监视 - -在 macOS 上,构建系统现在支持文件系统监视功能,能够在文件更改时自动触发重建: - -```bash -# 启用文件系统监视 -zig build --watch - -# 设置去抖动时间(默认50ms) -zig build --watch --debounce 100 +pub const Status = enum { + working, // 正在执行任务 + success, // 操作完成,等待用户输入 + failure, // 发生错误,等待用户输入 + failure_working, // 有错误但还在工作 +}; ``` -### Web 界面和即时报告 - -构建系统现在支持 Web 界面和详细的即时报告功能。 - -## 编译器 - -### x86 后端 +### HTTP 客户端与服务端重构 -在 **调试编译** 默认为 **x86 后端** 的情况下,其速度提高了 5 倍。这也是本次更新最显著的性能改进: +#### 服务端 API -```bash -# 使用新的 x86 后端(默认) -zig build -Doptimize=Debug +旧写法: -# 如果需要使用 LLVM 后端 -zig build -Doptimize=Debug -fLLVM +```zig +var read_buffer: [8000]u8 = undefined; +var server = std.http.Server.init(connection, &read_buffer); ``` -### aarch64 后端 - -**aarch64 后端** 的开发也在稳步推进,为 ARM 平台提供更好的支持。 - -### 增量编译 +新写法: -增量编译功能得到了改进: - -```bash -# 启用增量编译 -zig build -fincremental - -# 结合文件系统监视 -zig build -fincremental --watch - -# 仅检查编译错误(不生成二进制文件) -zig build -fincremental -fno-emit-bin --watch +```zig +var recv_buffer: [4000]u8 = undefined; +var send_buffer: [4000]u8 = undefined; +var conn_reader = connection.stream.reader(&recv_buffer); +var conn_writer = connection.stream.writer(&send_buffer); +var server = std.http.Server.init(conn_reader.interface(), &conn_writer.interface); ``` -### 多线程代码生成 +使用流程: -编译器现在支持多线程代码生成: +```zig +var server = std.http.Server.init(conn_reader.interface(), &conn_writer.interface); +var request = try server.receiveHead(); +const body_reader = try request.reader(); +// 读取 body... -```bash -# 控制编译线程数 -zig build -j4 # 使用 4 个线程 -zig build -j # 使用所有可用 CPU 核心 +// 一次性响应 +try request.respond(content, .{ + .status = status, + .extra_headers = &.{ + .{ .name = "content-type", .value = "text/html" }, + }, +}); -# 禁用多线程编译 -zig build -j1 +// 或流式响应 +var response = try request.respondStreaming(); +const body_writer = response.writer(); +// 写入 body... +try response.end(); ``` -### 允许在模块级别配置 UBSan 模式 +#### 客户端 API -现在可以在模块级别配置 UBSan(未定义行为检测器): +旧写法: ```zig -// build.zig 中的配置 -const exe = b.addExecutable(.{ - .name = "app", - .root_module = b.createModule(.{ - .root_source_file = b.path("src/main.zig"), - .target = target, - .optimize = optimize, - .sanitize_c = true, // 启用 C 代码的 UBSan - }), +var server_header_buffer: [1024]u8 = undefined; +var req = try client.open(.GET, uri, .{ + .server_header_buffer = &server_header_buffer, }); +defer req.deinit(); -// 或者使用命令行 -zig build -Dsanitize-c -``` - -### 将测试编译为目标文件 - -现在可以将测试编译为目标文件而不是可执行文件: +try req.send(); +try req.wait(); -```bash -# 将测试编译为 .o 文件 -zig test src/main.zig --object +const body_reader = try req.reader(); +// 读取 body... -# 将测试编译为静态库 -zig test src/main.zig --library - -# 将测试编译为动态库 -zig test src/main.zig --dynamic-library +var it = req.response.iterateHeaders(); +while (it.next()) |header| { + // 处理 header +} ``` -### Zig 初始化 - -`zig init` 命令得到了改进: - -```bash -# 创建新项目 -zig init +新写法: -# 创建库项目 -zig init --lib +```zig +var req = try client.request(.GET, uri, .{}); +defer req.deinit(); -# 创建可执行项目 -zig init --exe +try req.sendBodiless(); +var response = try req.receiveHead(&.{}); -# 指定项目名称 -zig init --name my-project +// 先处理 headers +var it = response.head.iterateHeaders(); +while (it.next()) |header| { + // 处理 header +} -# 在现有目录中初始化 -zig init . +// 再读取 body +var reader_buffer: [100]u8 = undefined; +const body_reader = response.reader(&reader_buffer); ``` -## 链接器 +### TLS 客户端 -链接器得到了多项改进和优化。 +`std.crypto.tls.Client` 不再依赖 `std.net` 或 `std.fs`,仅依赖 `std.Io.Reader` / `std.Io.Writer`。 -## 模糊测试器 +### ArrayList 默认无管理(unmanaged) -Zig 0.15.1 集成了一个内置的模糊测试器: +旧的有管理版本已弃用: -```bash -# 启动模糊测试 -zig build test --fuzz +- `std.ArrayList` -> `std.array_list.Managed`(将被移除) +- `std.ArrayListAligned` -> `std.array_list.AlignedManaged`(将被移除) -# 指定端口 -zig build test --fuzz --port 8080 - -# 指定测试时间 -zig build test --fuzz --timeout 60 -``` +推荐使用: ```zig -// 模糊测试例子 -test "fuzz string parsing" { - const input_bytes = std.testing.fuzzInput(.{}); - - // 测试字符串解析函数 - const result = parseString(input_bytes); - - // 确保不会崩溃 - _ = result catch |err| { - // 预期的错误可以忽略 - if (err == error.InvalidInput) return; - return err; - }; -} - -fn parseString(input: []const u8) ![]const u8 { - if (input.len == 0) return error.InvalidInput; - // 解析逻辑... - return input; -} +const ArrayList = std.ArrayListUnmanaged; +var list: ArrayList(i32) = .empty; +defer list.deinit(gpa); +try list.append(gpa, 1234); +try list.ensureUnusedCapacity(gpa, 1); +list.appendAssumeCapacity(5678); ``` -## 错误修复 - -本次发布修复了大量错误。 - -## 本次发布包含的错误 +新的 "Bounded" 变体方法: -Zig 目前仍存在一些已知的 bugs,包括一些编译错误。 - -## 工具链 - -### LLVM 20 - -本次更新升级到 LLVM 20,带来了以下改进: - -- 更好的优化支持 -- 新的目标架构支持 -- 改进的调试信息生成 -- 更好的 C++ 交互性 - -### 在交叉编译时支持动态链接的 FreeBSD libc - -```bash -# 交叉编译到 FreeBSD -zig build -Dtarget=x86_64-freebsd-gnu -zig build -Dtarget=aarch64-freebsd-gnu - -# 使用动态链接的 libc -zig build -Dtarget=x86_64-freebsd-gnu -Ddynamic-linker +```zig +var buffer: [8]i32 = undefined; +var stack = std.ArrayListUnmanaged(i32).initBuffer(&buffer); +try stack.appendSliceBounded(initial_stack); ``` -### 在交叉编译时支持动态链接的 NetBSD libc +### BoundedArray 被移除 -```bash -# 交叉编译到 NetBSD -zig build -Dtarget=x86_64-netbsd-gnu -zig build -Dtarget=aarch64-netbsd-gnu +根据场景选择替代方案: -# 使用 NetBSD 系统 libc -zig cc -target x86_64-netbsd-gnu program.c -``` - -### glibc 2.42 +1. 任意容量上限 -> 让调用方传入缓冲区或用动态分配 +2. 栈上有限容量 -> 直接用 `ArrayListUnmanaged` -升级到 glibc 2.42,并支持静态链接本地 glibc: +示例: -```bash -# 使用系统 glibc 静态链接 -zig build -Dtarget=native-linux-gnu -Dlinkage=static +旧写法: -# 指定 glibc 版本 -zig build -Dtarget=x86_64-linux-gnu.2.42 +```zig +var stack = try std.BoundedArray(i32, 8).fromSlice(initial_stack); ``` -#### 允许静态链接本机 glibc - -现在可以静态链接本机系统的 glibc。 - -### MinGW-w64 - -MinGW-w64 工具链得到了更新: - -```bash -# Windows 交叉编译 -zig build -Dtarget=x86_64-windows-gnu -zig build -Dtarget=aarch64-windows-gnu +新写法: -# 使用 MinGW-w64 工具链 -zig cc -target x86_64-windows-gnu program.c +```zig +var buffer: [8]i32 = undefined; +var stack = std.ArrayListUnmanaged(i32).initBuffer(&buffer); +try stack.appendSliceBounded(initial_stack); ``` -### zig libc - -`zig libc` 命令得到了增强: - -```bash -# 查看当前目标的 libc 配置 -zig libc - -# 查看指定目标的 libc -zig libc -target x86_64-linux-gnu +### 删除和弃用内容 -# 查看所有可用的 libc -zig targets | grep libc -``` - -### zig cc +以下 API 已被删除或重命名: -`zig cc` 作为 C 编译器的功能得到了增强: +```zig +// 文件操作 +std.fs.File.reader -> std.fs.File.deprecatedReader +std.fs.File.writer -> std.fs.File.deprecatedWriter -```bash -# 更好的 GCC 兼容性 -zig cc -std=c11 -O2 program.c +// 格式化 +std.fmt.fmtSliceEscapeLower -> std.ascii.hexEscape +std.fmt.fmtSliceEscapeUpper -> std.ascii.hexEscape +std.zig.fmtEscapes -> std.zig.fmtString +std.fmt.fmtSliceHexLower -> {x} +std.fmt.fmtSliceHexUpper -> {X} +std.fmt.fmtIntSizeDec -> {B} +std.fmt.fmtIntSizeBin -> {Bi} +std.fmt.fmtDuration -> {D} +std.fmt.fmtDurationSigned -> {D} +std.fmt.Formatter -> std.fmt.Alt +std.fmt.format -> std.Io.Writer.print -# 支持更多编译选项 -zig cc -march=native -mtune=native program.c +// IO +std.io.GenericReader -> std.Io.Reader +std.io.GenericWriter -> std.Io.Writer +std.io.AnyReader -> std.Io.Reader +std.io.AnyWriter -> std.Io.Writer +std.io.SeekableStream -> 删除(用具体实现替代) +std.io.BitReader -> 删除 +std.io.BitWriter -> 删除 +std.Io.LimitedReader -> 删除 +std.Io.BufferedReader -> 删除 +std.fifo -> 删除 -# 更好的错误报告 -zig cc -Wall -Wextra program.c +// POSIX +std.posix.iovec.iov_base -> .base +std.posix.iovec.iov_len -> .len ``` -### zig objcopy 回归 - -`zig objcopy` 命令存在一些回归问题,正在修复中。 - -## 路线图 - -### I/O 作为接口 - -I/O 系统将继续作为接口进行发展和完善。 - -## 升级建议 - -由于此次更新包含多项破坏性更改,建议开发者在升级至 0.15.1 版本时: - -### 升级步骤 - -1. **备份现有代码**:在开始升级之前做好备份 +### std.c 重组 -2. **分步骤进行**: - - 首先处理 `usingnamespace` 的移除 - - 然后处理 I/O 系统的重构 - - 最后处理 ArrayList 等容器的变更 +`std.c` 现在有更好的组织结构,并且消除了最后一个 `usingnamespace` 的使用。 -3. **使用编译器检查**: - - ```bash - # 检查编译错误 - zig build-exe src/main.zig +## 构建系统 - # 使用新的 x86 后端加速编译 - zig build -fno-LLVM - ``` +### 移除旧的 root_module 字段 -4. **测试全面性**:确保所有功能在新版本下正常运行 -5. **利用新特性**: - - 使用新的 x86 后端提高编译速度 - - 使用文件系统监视功能 - - 尝试增量编译 +`root_source_file` 等字段已被完全移除。 -### 常见问题和解决方案 +错误示例: -1. **I/O 代码编译错误**:参考上面的 Writergate 部分 -2. **`usingnamespace` 错误**:使用显式导入替代 -3. **ArrayList 错误**:改为使用 ArrayListUnmanaged -4. **格式化错误**:更新 format 方法签名 +```zig +const exe = b.addExecutable(.{ + .name = "foo", + .root_source_file = b.path("src/main.zig"), // 错误 + .target = b.graph.host, + .optimize = .Debug, +}); +``` -## 注意事项 +正确写法: -- 这次升级的破坏性更改较多,建议在测试环境中进行充分测试 -- I/O 接口的重构可能需要较多的代码调整工作 -- 新的性能改进主要体现在编译速度上 -- 文件系统监视功能有助于提高开发效率 +```zig +const exe = b.addExecutable(.{ + .name = "foo", + .root_module = b.createModule(.{ + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + }), +}); +``` -完整的发布说明可在 [Zig 官方网站](https://ziglang.org/download/0.15.1/release-notes.html) 查看。 +参考 [0.14.0 升级指南](./upgrade-0.14.0.md#从现有模块创建工件)。