commit d7b6d637df5b94ec07cf017fa742e8c34a4b9433 (tree)
parent 3c16e8037261e2f19e4a4daf9c88453ec11281b3
Author: Andrew Kelley <andrew@ziglang.org>
Date: Fri, 19 Jan 2024 12:14:30 -0800
Merge pull request #18615 from ziglang/langref
miscellaneous documentation changes
Diffstat:
4 files changed, 40 insertions(+), 271 deletions(-)
diff --git a/doc/langref.html.in b/doc/langref.html.in
@@ -1156,10 +1156,8 @@ fn addOne(number: i32) i32 {
{#link|identifier|Identifiers#}, followed by a {#link|block|Blocks#} containing any valid Zig code that
is allowed in a {#link|function|Functions#}.
</p>
- <aside>
- By convention, non-named tests should only be used to {#link|make other tests run|Nested Container Tests#}.
- Non-named tests cannot be {#link|filtered|Skip Tests#}.
- </aside>
+ <p>Non-named test blocks always run during test builds and are exempt from
+ {#link|Skip Tests#}.</p>
<p>
Test declarations are similar to {#link|Functions#}: they have a return type and a block of code. The implicit
return type of {#syntax#}test{#endsyntax#} is the {#link|Error Union Type#} {#syntax#}anyerror!void{#endsyntax#},
@@ -1173,74 +1171,6 @@ fn addOne(number: i32) i32 {
</p>
{#see_also|The Global Error Set|Grammar#}
{#header_close#}
- {#header_open|Nested Container Tests#}
- <p>
- When the <kbd>zig test</kbd> tool is building a test runner, only resolved {#syntax#}test{#endsyntax#}
- declarations are included in the build. Initially, only the given Zig source file's top-level
- declarations are resolved. Unless nested {#link|containers|Containers#} are referenced from a top-level test declaration,
- nested container tests will not be resolved.
- </p>
- <p>
- The code sample below uses the {#syntax#}std.testing.refAllDecls(@This()){#endsyntax#} function call to
- reference all of the containers that are in the file including the imported Zig source file. The code
- sample also shows an alternative way to reference containers using the {#syntax#}_ = C;{#endsyntax#}
- syntax. This syntax tells the compiler to ignore the result of the expression on the right side of the
- assignment operator.
- </p>
- {#code_begin|test|testing_nested_container_tests#}
-const std = @import("std");
-const expect = std.testing.expect;
-
-// Imported source file tests will run when referenced from a top-level test declaration.
-// The next line alone does not cause "testing_introduction.zig" tests to run.
-const imported_file = @import("testing_introduction.zig");
-
-test {
- // To run nested container tests, either, call `refAllDecls` which will
- // reference all declarations located in the given argument.
- // `@This()` is a builtin function that returns the innermost container it is called from.
- // In this example, the innermost container is this file (implicitly a struct).
- std.testing.refAllDecls(@This());
-
- // or, reference each container individually from a top-level test declaration.
- // The `_ = C;` syntax is a no-op reference to the identifier `C`.
- _ = S;
- _ = U;
- _ = @import("testing_introduction.zig");
-}
-
-const S = struct {
- test "S demo test" {
- try expect(true);
- }
-
- const SE = enum {
- V,
-
- // This test won't run because its container (SE) is not referenced.
- test "This Test Won't Run" {
- try expect(false);
- }
- };
-};
-
-const U = union { // U is referenced by the file's top-level test declaration
- s: US, // and US is referenced here; therefore, "U.Us demo test" will run
-
- const US = struct {
- test "U.US demo test" {
- // This test is a top-level test declaration for the struct.
- // The struct is nested (declared) inside of a union.
- try expect(true);
- }
- };
-
- test "U demo test" {
- try expect(true);
- }
-};
- {#code_end#}
- {#header_close#}
{#header_open|Test Failure#}
<p>
The default test runner checks for an {#link|error|Errors#} returned from a test.
@@ -2856,9 +2786,11 @@ test "volatile" {
</p>
{#header_close#}
<p>
- To convert one pointer type to another, use {#link|@ptrCast#}. This is an unsafe
- operation that Zig cannot protect you against. Use {#syntax#}@ptrCast{#endsyntax#} only when other
- conversions are not possible.
+ {#link|@ptrCast#} converts a pointer's element type to another. This
+ creates a new pointer that can cause undetectable illegal behavior
+ depending on the loads and stores that pass through it. Generally, other
+ kinds of type conversions are preferable to
+ {#syntax#}@ptrCast{#endsyntax#} if possible.
</p>
{#code_begin|test|test_pointer_casting#}
const std = @import("std");
@@ -5075,12 +5007,12 @@ test "if error union with optional" {
{#see_also|Optionals|Errors#}
{#header_close#}
{#header_open|defer#}
+ <p>Executes an expression unconditionally at scope exit.</p>
{#code_begin|test|test_defer#}
const std = @import("std");
const expect = std.testing.expect;
const print = std.debug.print;
-// defer will execute an expression at the end of the current scope.
fn deferExample() !usize {
var a: usize = 1;
@@ -5097,10 +5029,14 @@ fn deferExample() !usize {
test "defer basics" {
try expect((try deferExample()) == 5);
}
+ {#code_end#}
+ <p>Defer expressions are evaluated in reverse order.</p>
+ {#code_begin|test|defer_unwind#}
+const std = @import("std");
+const expect = std.testing.expect;
+const print = std.debug.print;
-// If multiple defer statements are specified, they will be executed in
-// the reverse order they were run.
-fn deferUnwindExample() void {
+test "defer unwinding" {
print("\n", .{});
defer {
@@ -5116,13 +5052,9 @@ fn deferUnwindExample() void {
}
}
}
-
-test "defer unwinding" {
- deferUnwindExample();
-}
{#code_end#}
+ <p>Inside a defer expression the return statement is not allowed.</p>
{#code_begin|test_err|test_invalid_defer|cannot return from defer expression#}
-// Inside a defer expression the return statement is not allowed.
fn deferInvalidExample() !void {
defer {
return error.DeferError;
@@ -5131,50 +5063,6 @@ fn deferInvalidExample() !void {
return error.DeferError;
}
{#code_end#}
- {#code_begin|test|test_errdefer#}
-const std = @import("std");
-const print = std.debug.print;
-
-// The errdefer keyword is similar to defer, but will only execute if the
-// scope returns with an error.
-//
-// This is especially useful in allowing a function to clean up properly
-// on error, and replaces goto error handling tactics as seen in c.
-fn deferErrorExample(is_error: bool) !void {
- print("\nstart of function\n", .{});
-
- // This will always be executed on exit
- defer {
- print("end of function\n", .{});
- }
-
- errdefer {
- print("encountered an error!\n", .{});
- }
-
- if (is_error) {
- return error.DeferError;
- }
-}
-
-// The errdefer keyword also supports an alternative syntax to capture the
-// generated error.
-//
-// This is useful for printing an additional error message during clean up.
-fn deferErrorCaptureExample() !void {
- errdefer |err| {
- std.debug.print("the error is {s}\n", .{@errorName(err)});
- }
-
- return error.DeferError;
-}
-
-test "errdefer unwinding" {
- deferErrorExample(false) catch {};
- deferErrorExample(true) catch {};
- deferErrorCaptureExample() catch {};
-}
- {#code_end#}
{#see_also|Errors#}
{#header_close#}
{#header_open|unreachable#}
@@ -8660,7 +8548,8 @@ test "decl access by string" {
<pre>{#syntax#}@floatFromInt(int: anytype) anytype{#endsyntax#}</pre>
<p>
Converts an integer to the closest floating point representation. The return type is the inferred result type.
- To convert the other way, use {#link|@intFromFloat#}. This cast is always safe.
+ To convert the other way, use {#link|@intFromFloat#}. This operation is legal
+ for all values of all integer types.
</p>
{#header_close#}
@@ -10873,6 +10762,9 @@ const separator = if (builtin.os.tag == .windows) '\\' else '/';
Some examples of tasks the build system can help with:
</p>
<ul>
+ <li>Performing tasks in parallel and caching the results.</li>
+ <li>Depending on other projects.</li>
+ <li>Providing a package for other projects to depend on.</li>
<li>Creating build artifacts by executing the Zig compiler. This includes
building Zig source code as well as C and C++ source code.</li>
<li>Capturing user-configured options and using those options to configure
@@ -10891,148 +10783,10 @@ const separator = if (builtin.os.tag == .windows) '\\' else '/';
to see a command-line usage help menu. This will include project-specific
options that were declared in the build.zig script.
</p>
-
- {#header_open|Building an Executable#}
- <p>This <code class="file">build.zig</code> file is automatically generated
- by <kbd>zig init-exe</kbd>.</p>
- {#code_begin|syntax|build_executable#}
-const std = @import("std");
-
-// Although this function looks imperative, note that its job is to
-// declaratively construct a build graph that will be executed by an external
-// runner.
-pub fn build(b: *std.Build) void {
- // Standard target options allows the person running `zig build` to choose
- // what target to build for. Here we do not override the defaults, which
- // means any target is allowed, and the default is native. Other options
- // for restricting supported target set are available.
- const target = b.standardTargetOptions(.{});
-
- // Standard optimization options allow the person running `zig build` to select
- // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
- // set a preferred release mode, allowing the user to decide how to optimize.
- const optimize = b.standardOptimizeOption(.{});
-
- const exe = b.addExecutable(.{
- .name = "example",
- // In this case the main source file is merely a path, however, in more
- // complicated build scripts, this could be a generated file.
- .root_source_file = .{ .path = "src/main.zig" },
- .target = target,
- .optimize = optimize,
- });
-
- // This declares intent for the executable to be installed into the
- // standard location when the user invokes the "install" step (the default
- // step when running `zig build`).
- b.installArtifact(exe);
-
- // This *creates* a Run step in the build graph, to be executed when another
- // step is evaluated that depends on it. The next line below will establish
- // such a dependency.
- const run_cmd = b.addRunArtifact(exe);
-
- // By making the run step depend on the install step, it will be run from the
- // installation directory rather than directly from within the cache directory.
- // This is not necessary, however, if the application depends on other installed
- // files, this ensures they will be present and in the expected location.
- run_cmd.step.dependOn(b.getInstallStep());
-
- // This allows the user to pass arguments to the application in the build
- // command itself, like this: `zig build run -- arg1 arg2 etc`
- if (b.args) |args| {
- run_cmd.addArgs(args);
- }
-
- // This creates a build step. It will be visible in the `zig build --help` menu,
- // and can be selected like this: `zig build run`
- // This will evaluate the `run` step rather than the default, which is "install".
- const run_step = b.step("run", "Run the app");
- run_step.dependOn(&run_cmd.step);
-
- // Creates a step for unit testing. This only builds the test executable
- // but does not run it.
- const unit_tests = b.addTest(.{
- .root_source_file = .{ .path = "src/main.zig" },
- .target = target,
- .optimize = optimize,
- });
-
- const run_unit_tests = b.addRunArtifact(unit_tests);
-
- // Similar to creating the run step earlier, this exposes a `test` step to
- // the `zig build --help` menu, providing a way for the user to request
- // running the unit tests.
- const test_step = b.step("test", "Run unit tests");
- test_step.dependOn(&run_unit_tests.step);
-}
- {#code_end#}
- {#header_close#}
-
- {#header_open|Building a Library#}
- <p>This <code class="file">build.zig</code> file is automatically generated
- by <kbd>zig init-lib</kbd>.</p>
- {#code_begin|syntax|build_library#}
-const std = @import("std");
-
-// Although this function looks imperative, note that its job is to
-// declaratively construct a build graph that will be executed by an external
-// runner.
-pub fn build(b: *std.Build) void {
- // Standard target options allows the person running `zig build` to choose
- // what target to build for. Here we do not override the defaults, which
- // means any target is allowed, and the default is native. Other options
- // for restricting supported target set are available.
- const target = b.standardTargetOptions(.{});
-
- // Standard optimization options allow the person running `zig build` to select
- // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
- // set a preferred release mode, allowing the user to decide how to optimize.
- const optimize = b.standardOptimizeOption(.{});
-
- const lib = b.addStaticLibrary(.{
- .name = "example",
- // In this case the main source file is merely a path, however, in more
- // complicated build scripts, this could be a generated file.
- .root_source_file = .{ .path = "src/main.zig" },
- .target = target,
- .optimize = optimize,
- });
-
- // This declares intent for the library to be installed into the standard
- // location when the user invokes the "install" step (the default step when
- // running `zig build`).
- b.installArtifact(lib);
-
- // Creates a step for unit testing. This only builds the test executable
- // but does not run it.
- const main_tests = b.addTest(.{
- .root_source_file = .{ .path = "src/main.zig" },
- .target = target,
- .optimize = optimize,
- });
-
- const run_main_tests = b.addRunArtifact(main_tests);
-
- // This creates a build step. It will be visible in the `zig build --help` menu,
- // and can be selected like this: `zig build test`
- // This will evaluate the `test` step rather than the default, which is "install".
- const test_step = b.step("test", "Run library tests");
- test_step.dependOn(&run_main_tests.step);
-}
- {#code_end#}
- {#header_close#}
-
- {#header_open|Compiling C Source Code#}
- <pre>{#syntax#}
-lib.addCSourceFile(.{ .file = .{ .path = "src/lib.c" }, .flags = &.{
- "-Wall",
- "-Wextra",
- "-Werror",
- } });
- {#endsyntax#}</pre>
- {#header_close#}
-
+ <p>
+ For the time being, the build system documentation is hosted externally:
+ <a href="https://ziglang.org/learn/build-system/">Build System Documentation</a>
+ </p>
{#header_close#}
{#header_open|C#}
<p>
diff --git a/lib/std/Build.zig b/lib/std/Build.zig
@@ -599,6 +599,11 @@ pub fn resolveInstallPrefix(self: *Build, install_prefix: ?[]const u8, dir_list:
self.h_dir = self.pathJoin(&h_list);
}
+/// Create a set of key-value pairs that can be converted into a Zig source
+/// file and then inserted into a Zig compilation's module table for importing.
+/// In other words, this provides a way to expose build.zig values to Zig
+/// source code with `@import`.
+/// Related: `Module.addOptions`.
pub fn addOptions(self: *Build) *Step.Options {
return Step.Options.create(self);
}
@@ -1031,6 +1036,11 @@ fn makeUninstall(uninstall_step: *Step, prog_node: *std.Progress.Node) anyerror!
// TODO remove empty directories
}
+/// Creates a configuration option to be passed to the build.zig script.
+/// When a user directly runs `zig build`, they can set these options with `-D` arguments.
+/// When a project depends on a Zig package as a dependency, it programmatically sets
+/// these options when calling the dependency's build.zig script as a function.
+/// `null` is returned when an option is left to default.
pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_raw: []const u8) ?T {
const name = self.dupe(name_raw);
const description = self.dupe(description_raw);
diff --git a/lib/std/Build/Module.zig b/lib/std/Build/Module.zig
@@ -318,6 +318,9 @@ pub fn addAnonymousImport(m: *Module, name: []const u8, options: CreateOptions)
return addImport(m, name, module);
}
+/// Converts a set of key-value pairs into a Zig source file, and then inserts it into
+/// the Module's import table with the specified name. This makes the options importable
+/// via `@import("module_name")`.
pub fn addOptions(m: *Module, module_name: []const u8, options: *Step.Options) void {
addImport(m, module_name, options.createModule());
}
diff --git a/lib/std/Build/Step/Options.zig b/lib/std/Build/Step/Options.zig
@@ -198,6 +198,8 @@ pub fn createModule(self: *Options) *std.Build.Module {
/// deprecated: use `getOutput`
pub const getSource = getOutput;
+/// Returns the main artifact of this Build Step which is a Zig source file
+/// generated from the key-value pairs of the Options.
pub fn getOutput(self: *Options) LazyPath {
return .{ .generated = &self.generated_file };
}