Skip to content
This repository has been archived by the owner on Sep 27, 2024. It is now read-only.

Commit

Permalink
Merge pull request ziglang#18615 from ziglang/langref
Browse files Browse the repository at this point in the history
miscellaneous documentation changes
  • Loading branch information
andrewrk authored Jan 19, 2024
2 parents 3c16e80 + 96e54e7 commit d7b6d63
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 271 deletions.
296 changes: 25 additions & 271 deletions doc/langref.html.in
Original file line number Diff line number Diff line change
Expand Up @@ -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#},
Expand All @@ -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.
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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;

Expand All @@ -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 {
Expand All @@ -5116,63 +5052,15 @@ 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;
}

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#}
Expand Down Expand Up @@ -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#}

Expand Down Expand Up @@ -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
Expand All @@ -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>
Expand Down
10 changes: 10 additions & 0 deletions lib/std/Build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
Expand Down
Loading

0 comments on commit d7b6d63

Please sign in to comment.