Zig is a general-purpose programming language designed for robustness, optimality, and maintainability. Zig is aggressively pursuing its goal of overthrowing C as the de facto language for system programming. Zig intends to be so practical that people find themselves using it, because it "just works".
This release features 6 months of work and changes from 67 different contributors, spread among 1541 commits.
Special thanks to my sponsors who provide financial support. You're making Zig sustainable.
{#header_open|Table of Contents#} {#nav#} {#header_close#} {#header_open|LLVM 9#}This release of Zig upgrades to LLVM 9. Zig operates in lockstep with LLVM; Zig 0.5.0 is not compatible with LLVM 8.
Notably this means that Zig now has {#link|RISC-V Support#}.
Zig also gains emscripten as a target OS. emscripten cannot self-host yet, but when it can, it will be interesting to explore this as an option for a Zig-in-the-browser sandbox, using {#link|WebAssembly|WebAssembly Support#}.
{#header_close#} {#header_open|Support Table#}A support table for master branch can be found on the home page. Here the support table for 0.5.0 is reproduced:
| free standing | Linux 3.16+ | macOS 10.13+ | Windows 7+ | FreeBSD 12.0+ | NetBSD 8.0+ | UEFI | WASI | Android | |
|---|---|---|---|---|---|---|---|---|---|
| x86_64 | {#link|Tier 2|Tier 2 Support#} | {#link|Tier 1|Tier 1 Support#} | {#link|Tier 1|Tier 1 Support#} | {#link|Tier 1|Tier 1 Support#} | {#link|Tier 2|Tier 2 Support#} | {#link|Tier 2|Tier 2 Support#} | {#link|Tier 2|Tier 2 Support#} | N/A | {#link|Tier 2|Tier 2 Support#} |
| wasm32 | {#link|Tier 2|Tier 2 Support#} | N/A | N/A | N/A | N/A | N/A | N/A | {#link|Tier 2|Tier 2 Support#} | N/A |
| arm64 | {#link|Tier 2|Tier 2 Support#} | {#link|Tier 2|Tier 2 Support#} | N/A | {#link|Tier 3|Tier 3 Support#} | {#link|Tier 3|Tier 3 Support#} | {#link|Tier 3|Tier 3 Support#} | {#link|Tier 3|Tier 3 Support#} | N/A | {#link|Tier 2|Tier 2 Support#} |
| arm32 | {#link|Tier 2|Tier 2 Support#} | {#link|Tier 2|Tier 2 Support#} | N/A | {#link|Tier 3|Tier 3 Support#} | {#link|Tier 3|Tier 3 Support#} | {#link|Tier 3|Tier 3 Support#} | {#link|Tier 3|Tier 3 Support#} | N/A | {#link|Tier 2|Tier 2 Support#} |
| mips32 LE | {#link|Tier 2|Tier 2 Support#} | {#link|Tier 2|Tier 2 Support#} | N/A | N/A | {#link|Tier 3|Tier 3 Support#} | {#link|Tier 3|Tier 3 Support#} | N/A | N/A | N/A |
| i386 | {#link|Tier 2|Tier 2 Support#} | {#link|Tier 3|Tier 3 Support#} | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 3|Tier 3 Support#} | {#link|Tier 3|Tier 3 Support#} | {#link|Tier 3|Tier 3 Support#} | {#link|Tier 3|Tier 3 Support#} | N/A | {#link|Tier 2|Tier 2 Support#} |
| bpf | {#link|Tier 3|Tier 3 Support#} | {#link|Tier 3|Tier 3 Support#} | N/A | N/A | {#link|Tier 3|Tier 3 Support#} | {#link|Tier 3|Tier 3 Support#} | N/A | N/A | N/A |
| hexagon | {#link|Tier 3|Tier 3 Support#} | {#link|Tier 3|Tier 3 Support#} | N/A | N/A | {#link|Tier 3|Tier 3 Support#} | {#link|Tier 3|Tier 3 Support#} | N/A | N/A | N/A |
| mips32 BE | {#link|Tier 3|Tier 3 Support#} | {#link|Tier 3|Tier 3 Support#} | N/A | N/A | {#link|Tier 3|Tier 3 Support#} | {#link|Tier 3|Tier 3 Support#} | N/A | N/A | N/A |
| mips64 | {#link|Tier 3|Tier 3 Support#} | {#link|Tier 3|Tier 3 Support#} | N/A | N/A | {#link|Tier 3|Tier 3 Support#} | {#link|Tier 3|Tier 3 Support#} | N/A | N/A | N/A |
| amdgcn | {#link|Tier 3|Tier 3 Support#} | {#link|Tier 3|Tier 3 Support#} | N/A | N/A | {#link|Tier 3|Tier 3 Support#} | {#link|Tier 3|Tier 3 Support#} | N/A | N/A | N/A |
| sparc | {#link|Tier 3|Tier 3 Support#} | {#link|Tier 3|Tier 3 Support#} | N/A | N/A | {#link|Tier 3|Tier 3 Support#} | {#link|Tier 3|Tier 3 Support#} | N/A | N/A | N/A |
| s390x | {#link|Tier 3|Tier 3 Support#} | {#link|Tier 3|Tier 3 Support#} | N/A | N/A | {#link|Tier 3|Tier 3 Support#} | {#link|Tier 3|Tier 3 Support#} | N/A | N/A | N/A |
| lanai | {#link|Tier 3|Tier 3 Support#} | {#link|Tier 3|Tier 3 Support#} | N/A | N/A | {#link|Tier 3|Tier 3 Support#} | {#link|Tier 3|Tier 3 Support#} | N/A | N/A | N/A |
| powerpc32 | {#link|Tier 3|Tier 3 Support#} | {#link|Tier 3|Tier 3 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | {#link|Tier 3|Tier 3 Support#} | {#link|Tier 3|Tier 3 Support#} | N/A | N/A | N/A |
| powerpc64 | {#link|Tier 3|Tier 3 Support#} | {#link|Tier 3|Tier 3 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | {#link|Tier 3|Tier 3 Support#} | {#link|Tier 3|Tier 3 Support#} | N/A | N/A | N/A |
| wasm64 | {#link|Tier 4|Tier 4 Support#} | N/A | N/A | N/A | N/A | N/A | N/A | {#link|Tier 4|Tier 4 Support#} | N/A |
| avr | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | N/A | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | N/A | N/A |
| riscv32 | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | N/A | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | N/A |
| riscv64 | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | N/A | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | N/A |
| xcore | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | N/A | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | N/A | N/A |
| nvptx | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | N/A | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | N/A | N/A |
| msp430 | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | N/A | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | N/A | N/A |
| r600 | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | N/A | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | N/A | N/A |
| arc | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | N/A | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | N/A | N/A |
| tce | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | N/A | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | N/A | N/A |
| le | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | N/A | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | N/A | N/A |
| amdil | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | N/A | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | N/A | N/A |
| hsail | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | N/A | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | N/A | N/A |
| spir | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | N/A | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | N/A | N/A |
| kalimba | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | N/A | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | N/A | N/A |
| shave | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | N/A | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | N/A | N/A |
| renderscript | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | N/A | {#link|Tier 4|Tier 4 Support#} | {#link|Tier 4|Tier 4 Support#} | N/A | N/A | N/A |
zig targets
is guaranteed to include this target.zig targets
will
display the target if it is available.--emit asm
and cannot emit object files.This release updates to {#link|LLVM 9#}, {#link|musl 1.1.23#} with patches, and {#link|glibc 2.30#}. This plus updates to the {#link|Standard Library#} means that Zig's (64-bit) RISC-V support has gone from {#link|Tier 4 Support#} to {#link|Tier 3 Support#} in this release.
RISC-V is a very flexible target, with features such as atomics, and even integer multiplication
being optional. Since Zig does not yet have
ability to specify target CPU features,
the default set of cross-compilation features are "+a,+c,+d,+f,+m,+relax"
,
which matches Clang.
The RISC-V target does not yet pass Zig's test suite:
The next step for all these issues is to create test case reductions and then file upstream bug reports.
However, I did work with Rich Felker to get musl building with Clang for the RISC-V target, which means that we can do this:
hello.c
#include <stdio.h>
int main(int argc, char **argv) {
printf("Hello world\n");
return 0;
}
$ zig build-exe --c-source hello.c -lc -target riscv64-linux-musl
$ qemu-riscv64 ./hello
Hello world
Zig 0.5.0 carries a few patches to musl which makes this work. A new musl release is expected soon which contains these patches.
To be clear - the above simple example also works in Zig - it's just that all the language features such as {#syntax#}f16{#endsyntax#} are not working, and there is no automated {#link|Test Coverage#} for this target.
{#code_begin|exe|hello#} {#target_linux_riscv64#} const std = @import("std"); pub fn main() void { std.debug.warn("Hello from zig\n"); } {#code_end#}$ qemu-riscv64 ./hello
Hello from zig
Although {#link|glibc 2.30#} gained RISC-V support, Zig is not able to build glibc for this target yet. See #3340 for more details. Looks like it could be as simple as importing a couple more .h files from the glibc source tree.
{#header_close#} {#header_open|64-bit ARM Support#}LemonBoy worked on {#link|Standard Library#} support for aarch64 during this release cycle:
epoll_*
struct on non x86_64 arches.After this work, and improvements made to {#link|Test Coverage#}, the following targets are now covered by the Zig test suite:
This test coverage led to the following bug fixes:
However, due to LLVM miscompiling trivial switch for AArch64, some failing tests are disabled, which means 64-bit ARM remains a {#link|Tier 2 Support#} target. The good news is we filed an LLVM bug report, and it has already been solved in LLVM trunk, scheduled to be included in LLVM 9.0.1.
After that, the only remaining issues standing in the way of Tier 1 Support for ARM 64-bit (aarch64) Linux are:
arm64-test.zig
{#syntax#} const builtin = @import("builtin"); const std = @import("std"); const assert = std.debug.assert; test "cross compiled unit test" { assert(builtin.arch == .aarch64); } {#endsyntax#}
$ zig test arm64-test.zig -target aarch64v8-linux --test-cmd qemu-aarch64 --test-cmd-bin
1/1 test "cross compiled unit test"...OK
All tests passed.
{#header_close#}
{#header_open|32-bit ARM Support#}
Thanks to {#link|compiler-rt#} improvements by vegecode and LemonBoy, Zig's 32-bit ARM support is much stronger in version 0.5.0.
Alongside these efforts, LemonBoy improved the {#link|Standard Library#} by making I/O offsets and sizes {#syntax#}u64{#endsyntax#} instead of {#syntax#}usize{#endsyntax#}, decoupling the concepts of address-space size and file size. This solved many compile errors when trying to target 32-bit ARM, as well as any other 32-bit architecture. #637
He also made several improvements to {#link|Thread Local Storage#} for 32-bit ARM.
Robin Voetter joined the Zig community during this release cycle, and hammered away at the {#link|Standard Library#}:
SYS_mmap2
if it exists.sys_*stat*64
instead of sys_*stat*
where appropriate.After all these improvements, 32-bit ARM support is leveled-up to {#link|Tier 2 Support#}. Along with improvements made to {#link|Test Coverage#}, the following targets are now covered by the Zig test suite:
arm32-test.zig
{#syntax#} const builtin = @import("builtin"); const std = @import("std"); const assert = std.debug.assert; test "cross compiled unit test" { assert(builtin.arch == .arm); } {#endsyntax#}
$ zig test arm32-test.zig -target armv8-linux --test-cmd qemu-arm --test-cmd-bin
1/1 test "cross compiled unit test"...OK
All tests passed.
After updating to {#link|musl 1.1.23#}, Zig's clone
on arm32 is updated to
latest musl implementation.
Remaining issues to solve in order to achieve Tier 1 Support for ARM 32-bit Linux:
Although Zig does not officially support MSYS2 as a host target, emekoi has dutifully maintained unofficial support. Thanks to emekoi's efforts, one can build and run the stage1 C++ compiler of Zig in an MSYS2 environment.
Note: sometimes "MinGW" is used as a shorthand to mean "MSYS2". However, it is not to be confused with {#link|mingw-w64|Zig ships with mingw-w64#}, or with the unrelated project, MinGW. MinGW-w64 is a fork of MinGW, which adds support for more architectures (such as 64-bit Windows) and more system APIs. When someone says "MinGW", it's almost certain they either mean "MSYS2" (which is based on MinGW-w64) or "MinGW-w64" instead.
Here is the list of things emekoi did to maintain unofficial support for MSYS2:
stratact made the following changes:
<stdint.h>
include for uint8_t
type declaration.dl_iterate_phdr
function for FreeBSD.This combined with disabling some of the failing standard library tests for FreeBSD, stratact was able to enable more {#link|Test Coverage#} for FreeBSD. Now the Continuous Integration server runs 7 additional kinds of tests from the test suite, instead of only the behavior tests.
stratact reports all tests passing locally, however, we have run into memory limits of SourceHut, which is the service used to run FreeBSD tests. Drew DeVault has understandably denied our request for more RAM, and so we are left with disabled test coverage until Zig can finish self-hosting, or improve the memory usage of the C++ stage1 compiler.
The set of remaining issues until Tier 1 FreeBSD Support for x86_64 is now:
During the 0.5.0 release cycle, Shritesh Bhattarai joined the Zig community and made significant contributions to Zig's WebAssembly and WASI (Web Assembly System Interface) support.
He got {#link|compiler-rt#} working and tweaked the target settings such as:
Thanks to this as well as Shritesh adding basic standard library support for the WASI target, as well as improving the linker settings that Zig uses, WebAssembly and WASI are now {#link|Tier 2 Support#} targets!
As a demo, Shritesh created zigfmt-web, which
is a web page that will run zig fmt
on a block of code, using the same
implementation as official zig fmt.
Shritesh created a basic allocator intended to be used on the WebAssembly target,
std.heap.wasm_allocator
. This uses the WebAssembly intrinsics to request memory
from the host, and is not capable of freeing memory. The standard library does not yet have
an allocator for WebAssembly that can reclaim freed memory. See
zee_alloc for a community project
attempting to solve this use case.
Shritesh also created a demo of Zig interacting with the DOM via JS (source).
Other miscellaneous improvements to WebAssembly:
std.os.page_size
for WebAssemblyZig now provides a {#link|Freestanding libc#}, which is available when linking libc for the WebAssembly target. It is not yet fully complete, but you can get a sense of the use case for it with this demo project: lua-in-the-browser
This use case led to several improvements to Zig's WebAssembly support:
build-exe
is for executables which have a main()
.
build-lib
is for building libraries of functions to use from,
for example, a web browser environment.--export-all
for libraries when there are any
C objects because we have no way to detect the list of exports
when compiling C code.--no-entry
to the linker for executables.
If you want --no-entry
then use build-lib
.build-exe
does include the startup code that supplies _start
for the
wasm32-freestanding
target. Previously this did not occur because
of logic excluding "freestanding".build-lib
for wasm32-freestanding
target gets
linked by LLD. To avoid infinite recursion, {#link|compiler-rt#} and
{#link|Freestanding libc#} are built as objects rather than libraries.build-lib foo.zig
producing "libfoo.a", now it produces "foo.wasm"._start
symbol for wasm when linking libc.Zig is particularly well suited to creating reasonably small & fast WebAssembly binaries. Here are some demos of WebAssembly projects from Zig community members:
Nick Erdmann has been reading the UEFI specification and improving Zig support for this target.
Zig's {#link|Standard Library#} now integrates more cleanly with UEFI, and other things now "just work" such as PDB files and 0x0 addresses.
Many of the UEFI protocol definitions are now available in {#syntax#}std.os.uefi.protocols{#endsyntax#}.
Nick has clean and well-organized demo projects which serve as resources to help others learn how to do UEFI programming:
Matthew Iannucci added initial support for iOS targets (#2237).
However iOS remains a {#link|Tier 3 Support#} target. There are no known active Zig projects targeting iOS.
{#header_close#} {#header_open|MIPS Support#}LemonBoy implemented {#link|Thread Local Storage#} for architectures that have thread pointer offsets, such as mipsel. He updated the {#link|Standard Library#} with the Linux system bits for the mipsel architecture, and worked with {#link|musl|musl 1.1.23#} upstream to get it patched enough to be able to successfully build with Clang for this target. Zig carries this patch in 0.5.0.
After these changes, MIPS now has {#link|Tier 2 Support#}! LemonBoy reports running a Zig binary on his router:
18:59 <TheLemonMan> just got a Zig binary running on my mips32 router, yay
These targets are now covered by the Zig test suite:
Aside from investigating mipsel-linux-gnu
, the only remaining issues standing in the way of
Tier 1 Support for MIPS Little-Endian Linux (mipsel-linux)
are:
mips-test.zig
{#syntax#} const builtin = @import("builtin"); const std = @import("std"); const assert = std.debug.assert; test "cross compiled unit test" { assert(builtin.arch == .mipsel); } {#endsyntax#}
$ zig test mips-test.zig -target mipsel-linux --test-cmd qemu-mipsel --test-cmd-bin
1/1 test "cross compiled unit test"...OK
All tests passed.
{#header_close#}
{#header_open|Android Support#}
meme joined the Zig community and contributed improvements
to the target aarch64-linux-android
. Thanks to their efforts, Zig now has
{#link|Tier 2 Support#} for Android.
Here's an example of building an Android executable with Zig:
hello_android.zig
{#syntax#} const std = @import("std"); pub fn main() void { std.debug.warn("Hello, Android!"); } {#endsyntax#}
$ zig build-exe hello_android.zig -target aarch64-linux-android
$ file ./hello_android
./hello_android: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, with debug_info, not stripped
In this example, there is no {#link|libc#} dependency. However, Zig does know how to integrate
with Android's libc. The first step is to create a libc text file describing where various paths
are. One can obtain a template for this file by executing zig libc
. In this example,
I've taken the template and populated it based on the path to the Android NDK in my downloads
folder:
android_libc.txt
# The directory that contains `stdlib.h`.
# On POSIX-like systems, include directories be found with: `cc -E -Wp,-v -xc /dev/null`
include_dir=/home/andy/Downloads/android-ndk-r20/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include
# The system-specific include directory. May be the same as `include_dir`.
# On Windows it's the directory that includes `vcruntime.h`.
# On POSIX it's the directory that includes `sys/errno.h`.
sys_include_dir=/home/andy/Downloads/android-ndk-r20/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include
# The directory that contains `crt1.o` or `crt2.o`.
# On POSIX, can be found with `cc -print-file-name=crt1.o`.
# Not needed when targeting MacOS.
crt_dir=/home/andy/Downloads/android-ndk-r20/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/21
# The directory that contains `crtbegin.o`.
# On POSIX, can be found with `cc -print-file-name=crtbegin.o`.
# Not needed when targeting MacOS.
static_crt_dir=/home/andy/Downloads/android-ndk-r20/toolchains/llvm/prebuilt/linux-x86_64/lib/gcc/aarch64-linux-android/4.9.x
# The directory that contains `vcruntime.lib`.
# Only needed when targeting MSVC on Windows.
msvc_lib_dir=
# The directory that contains `kernel32.lib`.
# Only needed when targeting MSVC on Windows.
kernel32_lib_dir=
hello_libc.zig
{#syntax#} const std = @import("std"); extern fn printf(msg: [*]const u8, ...) c_int; pub fn main() void { _ = printf(c"hello android libc\n"); } {#endsyntax#}
$ zig build-exe hello_libc.zig -target aarch64-linux-android -lc --libc android_libc.txt
$ file ./hello_libc
./hello_libc: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /system/bin/linker64, with debug_info, not stripped
{#header_close#}
{#header_close#}
{#header_open|Language Changes#}
{#syntax#}usingnamespace{#endsyntax#} is a top level declaration that imports all the public declarations of the operand, which must be a {#syntax#}struct{#endsyntax#}, {#syntax#}union{#endsyntax#}, or {#syntax#}enum{#endsyntax#}, into the current scope:
{#code_begin|test|usingnamespace#} usingnamespace @import("std"); test "using std namespace" { debug.assert(true); } {#code_end#}
Instead of the above pattern, it is generally recommended to explicitly alias individual declarations.
However, {#syntax#}usingnamespace{#endsyntax#} has an important use case when organizing the public
API of a file or package. For example, one might have c.zig
with all of the
C imports:
{#syntax#} pub usingnamespace @cImport({ @cInclude("epoxy/gl.h"); @cInclude("GLFW/glfw3.h"); @cDefine("STBI_ONLY_PNG", ""); @cDefine("STBI_NO_STDIO", ""); @cInclude("stb_image.h"); }); {#endsyntax#}
The above example demonstrates using {#syntax#}pub{#endsyntax#} to qualify the {#syntax#}usingnamespace{#endsyntax#} additionally makes the imported declarations {#syntax#}pub{#endsyntax#}. This can be used to forward declarations, giving precise control over what declarations a given file exposes.
In Zig 0.4.0, this feature existed as use
, but it only worked at the top-level
scope, and only for structs. The feature was also considered unstable.
Thank you LemonBoy for fixing {#syntax#}usingnamespace{#endsyntax#} outside the top-level scope, and making it work with arbitrary structs.
In Zig 0.5.0, both use
and {#syntax#}usingnamespace{#endsyntax#} are accepted, and
{#link|zig fmt#} automatically converts to the canonical syntax. The next release of Zig after this
one will remove the old syntax.
This feature is now stable and planned to be included in the language specification.
{#header_close#} {#header_open|External Thread Local Variables#}Zig now always respects {#syntax#}threadlocal{#endsyntax#} for variables with external linkage.
Previously, if you had, for example:
{#syntax#}extern "c" threadlocal var errno: c_int;{#endsyntax#}
This would turn {#syntax#}errno{#endsyntax#} into a normal variable for --single-threaded
builds. However for variables with external linkage, there is an ABI
to uphold.
This is needed to make errno work for DragonFly BSD. See #2381.
{#header_close#} {#header_open|@hasField and @hasDecl#}{#syntax#}@hasField(comptime Container: type, comptime name: []const u8) bool{#endsyntax#}
{#syntax#}@hasDecl(comptime Container: type, comptime name: []const u8) bool{#endsyntax#}
The new builtin function @hasField returns whether the field name of a struct, union, or enum exists. The result is a compile time boolean. It does not include functions, variables, or constants.
The new builtin function @hasDecl returns whether or not a struct, enum, or union has a declaration.
{#code_begin|test|has_builtins#} const std = @import("std"); const assert = std.debug.assert; const Foo = struct { nope: i32, pub var blah = "xxx"; const hi = 1; }; test "@hasDecl and @hasField" { assert(@hasDecl(Foo, "blah")); // Even though `hi` is private, @hasDecl returns true because this test is // in the same file scope as Foo. It would return false if Foo was declared // in a different file. assert(@hasDecl(Foo, "hi")); // @hasDecl is for declarations; not fields. assert(!@hasDecl(Foo, "nope")); assert(!@hasDecl(Foo, "nope1234")); assert(@hasField(Foo, "nope")); } {#code_end#}Thanks to Shawn Landden for initial implementation and documentation of @hasField.
{#header_close#} {#header_open|C Pointers Support Optional Syntax#}
When {#link|translating C code|C Translation#}, Zig does not know whether pointer types
should be translated to *
or [*]
pointers. Instead, they
are translated to C Pointers.
As the documentation notes, this type is to be avoided whenever possible. The only valid reason for using a C pointer is in auto-generated code from translating C code.
Interfacing with C pointer types happens due to direct interop with translated .h files. It's always a future possibility to rewrite the .h file in .zig to gain better type-safety. Previously, optional syntax, such as {#syntax#}if{#endsyntax#}, {#syntax#}orelse{#endsyntax#}, {#syntax#}null{#endsyntax#}, and {#syntax#}.?{#endsyntax#} did not work for C pointers. This would cause compile errors if the type signature of the external function prototypes were improved to have the real pointer types rather than C pointers.
Now, this syntax works, and so there is no penalty for starting out with auto-translated headers, and then later "upgrading" to better typed bindings.
{#code_begin|test|getenv#} {#link_libc#} const getenv = @cImport(@cInclude("stdlib.h")).getenv; // note: this is just a demo of C pointers with optional syntax. // std.process has better API for getenv. test "C pointers with optional syntax" { const ptr1 = getenv(c"HOME").?; // don't do this 💥 const ptr2 = getenv(c"HOME") orelse return error.Homeless; // OK if (getenv(c"HOME")) |ptr3| { // also OK } const ptr4 = getenv(c"HOME"); if (ptr4 == null) { // also works } } {#code_end#}
The auto-translated getenv
prototype looks like this:
{#syntax#} pub extern fn getenv(__name: [*c]const u8) [*c]u8; {#endsyntax#}
If we were to improve this prototype with correct pointer types, the test will still pass:
{#code_begin|test|getenv2#} {#link_libc#} pub extern fn getenv(name: [*]const u8) ?[*]u8; // note: this is just a demo of C pointers with optional syntax. // std.process has better API for getenv. test "C pointers with optional syntax" { const ptr1 = getenv(c"HOME").?; // don't do this 💥 const ptr2 = getenv(c"HOME") orelse return error.Homeless; // OK if (getenv(c"HOME")) |ptr3| { // also OK } const ptr4 = getenv(c"HOME"); if (ptr4 == null) { // also works } } {#code_end#} {#header_close#} {#header_open|Switching on Error Sets#}Using {#syntax#}switch{#endsyntax#} on an error set now provides a way to capture an error value with a subset type:
{#code_begin|exe|switch_err_set_1#} const std = @import("std"); const os = std.os; const Error = error{ AccessDenied, FileTooBig, IsDir, SymLinkLoop, ProcessFdQuotaExceeded, NameTooLong, SystemFdQuotaExceeded, NoDevice, FileNotFound, SystemResources, NoSpaceLeft, NotDir, PathAlreadyExists, DeviceBusy, InputOutput, OperationAborted, BrokenPipe, Unexpected, }; pub fn main() Error!void { // open a normal, blocking file descriptor. const fd = try os.open("/dev/urandom", os.O_RDONLY, 0); defer os.close(fd); // we did *not* use O_NONBLOCK, so the OS will not give us // EWOULDBLOCK. var buf: [100]u8 = undefined; const nbytes = try readBlocking(fd, &buf); } /// Asserts that fd was opened in a blocking fashion. fn readBlocking(fd: os.fd_t, buffer: []u8) !usize { return std.os.read(fd, buffer) catch |err| switch (err) { error.WouldBlock => unreachable, // Remove this to observe compile error else => |e| return e, }; } {#code_end#}Here you can see that the program compiled just fine, even though {#syntax#}error.WouldBlock{#endsyntax#} is not found in the error set. This is because the function {#syntax#}readBlocking{#endsyntax#} switched on the error set, and handled the {#syntax#}error.WouldBlock{#endsyntax#} case. This means the error set type of value captured by the {#syntax#}else{#endsyntax#} does not include the value {#syntax#}error.WouldBlock{#endsyntax#}.
In addition to this, Zig allows capturing the payload from multiple error set values:
{#code_begin|exe|switch_err_set_2#} const std = @import("std"); const os = std.os; const Error = error{ AccessDenied, FileTooBig, IsDir, SymLinkLoop, ProcessFdQuotaExceeded, NameTooLong, SystemFdQuotaExceeded, NoDevice, FileNotFound, SystemResources, NoSpaceLeft, NotDir, PathAlreadyExists, DeviceBusy, OperationAborted, BrokenPipe, Unexpected, }; pub fn main() Error!void { // open a normal, blocking file descriptor. const fd = try os.open("/dev/urandom", os.O_RDONLY, 0); defer os.close(fd); // we did *not* use O_NONBLOCK, so the OS will not give us // EWOULDBLOCK. var buf: [100]u8 = undefined; const nbytes = try readBlocking(fd, &buf); } /// Asserts that fd was opened in a blocking fashion. fn readBlocking(fd: os.fd_t, buffer: []u8) !usize { return std.os.read(fd, buffer) catch |err| switch (err) { error.WouldBlock, error.InputOutput => |e| { std.debug.panic("unexpected: {}\n", e); }, else => |e| return e, }; } {#code_end#}In this example, {#syntax#}error.InputOutput{#endsyntax#} was lifted out of {#syntax#}Error{#endsyntax#} since it is handled inside {#syntax#}readBlocking{#endsyntax#}. The {#syntax#}e{#endsyntax#} capture value has type {#syntax#}error{WouldBlock,InputOutput}{#endsyntax#}.
{#header_close#} {#header_open|Bit Manipulation Builtin Functions#}Shawn Landden improved the consistency of the names and parameters of bit manipulation intrinsics.
@bitreverse
to @bitReverse to adhere to
naming conventions.@bswap
to @byteSwap.{#syntax#}@bitReverse(comptime T: type, integer: T) T{#endsyntax#}
{#syntax#}@byteSwap(comptime T: type, operand: T) T{#endsyntax#}
{#syntax#}@clz(comptime T: type, integer: T){#endsyntax#}
{#syntax#}@ctz(comptime T: type, integer: T){#endsyntax#}
{#syntax#}@popCount(comptime T: type, integer: T){#endsyntax#}{#header_close#} {#header_open|Undeclared Identifiers in Compile-Time Dead Branches#}
Zig no longer validates whether identifiers exist in dead {#syntax#}comptime{#endsyntax#} branches:
{#code_begin|test|dead_comptime_branch#} test "dead comptime branch" { if (false) { does_not_exist = thisFunctionAlsoDoesNotExist(); } } {#code_end#}This is counter-intuitive, but consider that the set of available identifiers may depend on {#syntax#}comptime{#endsyntax#} parameters, such as the target OS:
{#syntax#} const builtin = @import("builtin"); usingnamespace switch (builtin.os) { .windows => @import("windows_stuff.zig"), else => @import("posix_stuff.zig"), }; test "example" { if (builtin.os == .windows) { ExitProcess(0); } else { exit(0); } } {#endsyntax#}
In practice, this has resulted in various code cleanups throughout the standard library.
Zig's lazy analysis, while convenient, surfaces the inherent problems of conditional compilation. See the related proposal: "multibuilds" - a plan to harmonize conditional compilation with compile errors, documentation, and IDEs
{#header_close#} {#header_open|Default Struct Field Values#}Each struct field may now have an expression indicating the default field value. Such expressions are executed at {#syntax#}comptime{#endsyntax#}, and allow the field to be omitted in a struct literal expression:
{#code_begin|test|default_fields#} const Foo = struct { a: i32 = 1234, b: i32, }; test "default struct field values" { const x = Foo{ .b = 5, }; if (x.a + x.b != 1239) { @compileError("it's even comptime known!"); } } {#code_end#} {#header_close#} {#header_open|Array Literal Syntax#}The array literal syntax has changed, when inferring the size.
Old syntax:
[]i32{1, 2, 3}
New syntax:
{#syntax#}[_]i32{1, 2, 3}{#endsyntax#}
The previous syntax used to look too much like instantiating a slice. This caused all kinds of confusion. Now it's pretty clear that the type is an array.
#1797 {#header_close#} {#header_open|@import("root")#}
The Root Source File
(in the case of build-exe
, the file with {#syntax#}pub fn main{#endsyntax#})
is now available to import anywhere, using {#syntax#}@import("root"){#endsyntax#}.
Combined with {#link|@hasDecl|@hasField and @hasDecl#},
this allows library code to support global configuration settings based on declarations in the
root source file.
The {#link|Standard Library#} takes advantage of this for several use cases. One example is
the {#link|Default Segfault Handler#}. It works like this (from std.debug
):
{#syntax#} const root = @import("root"); /// Whether or not the current target can print useful debug information when a segfault occurs. pub const have_segfault_handling_support = builtin.os == .windows or (builtin.arch == builtin.Arch.x86_64 and builtin.os == .linux); pub const enable_segfault_handler: bool = if (@hasDecl(root, "enable_segfault_handler")) root.enable_segfault_handler else runtime_safety and have_segfault_handling_support; pub fn maybeEnableSegfaultHandler() void { if (enable_segfault_handler) { std.debug.attachSegfaultHandler(); } } {#endsyntax#}
And then Zig's startup code calls {#syntax#}std.debug.maybeEnableSegfaultHandler(){#endsyntax#} just before calling {#syntax#}main(){#endsyntax#}.
Another place this is used in the standard library is to decide a global "I/O mode", which is related to {#link|Async Functions#}.
This feature has the capability to be abused, and should be used with care. Any root source file declarations that can affect a library's behavior should be well-documented. When Zig gains documentation generation, the auto-generated docs will have the capability to enumerate all the places that depend on a root source file declaration.
Thank you emekoi for the initial implementation of this.
{#header_close#} {#header_open|@mulAdd#}Zig now has @mulAdd, otherwise known as "fused-multiply-add".
{#syntax#}@mulAdd(comptime T: type, a: T, b: T, c: T) T{#endsyntax#}
Performs {#syntax#}(a * b) + c{#endsyntax#}, except only rounds once, and is thus more accurate. Additionally, some targets have a hardware instruction for this, making it potentially faster than a userland implementation.
{#code_begin|test|mul_add#} const std = @import("std"); test "@mulAdd" { // In this example we use numbers small enough to avoid rounding errors that would occur // without @mulAdd. std.testing.expect(@mulAdd(f32, 2.0, 3.0, 4.0) == (2.0 * 3.0) + 4.0); } {#code_end#}Currently this instruction only works for floating point types, as well as {#link|vectors of floating point types|SIMD#}. However, there is an open proposal to make this work for any types that support {#syntax#}*{#endsyntax#} and {#syntax#}+{#endsyntax#} operators, such as integers. The proposal also suggests to remove the explicit type parameter requirement.
Thank you Shawn Landden for the initial implementation of this.
{#header_close#} {#header_open|Builtins for Math Functions#}Shawn Landden added:
{#syntax#}@sin(comptime T: type, value: T) T{#endsyntax#}
{#syntax#}@cos(comptime T: type, value: T) T{#endsyntax#}
{#syntax#}@exp(comptime T: type, value: T) T{#endsyntax#}
{#syntax#}@exp2(comptime T: type, value: T) T{#endsyntax#}
{#syntax#}@ln(comptime T: type, value: T) T{#endsyntax#}
{#syntax#}@log2(comptime T: type, value: T) T{#endsyntax#}
{#syntax#}@log10(comptime T: type, value: T) T{#endsyntax#}
{#syntax#}@fabs(comptime T: type, value: T) T{#endsyntax#}
{#syntax#}@floor(comptime T: type, value: T) T{#endsyntax#}
{#syntax#}@ceil(comptime T: type, value: T) T{#endsyntax#}
{#syntax#}@trunc(comptime T: type, value: T) T{#endsyntax#}
{#syntax#}@round(comptime T: type, value: T) T{#endsyntax#}
These are builtin functions because some architectures have hardware instructions for these. Furthermore, because these functions are well-defined, the optimizer may sometimes be able to convert calls to these builtins into better forms.
It's planned for Zig to provide libmvec
in the future, and these functions will become
{#link|SIMD#}-capable.
What I'm calling Result Location Semantics was a large branch of Zig that fundamentally changed the way that expressions are semantically analyzed. This was the third attempt, which finally succeeded. I abandoned the first attempt after 1 week. The second attempt, which took place during the 0.4.0 release cycle, lasted 2 months, but again was regretfully abandoned. However, there were significant parts of the second attempt that landed in the eventual implementation.
During my work on this branch, the Zig community stepped up and continued to improve master branch all the while. You can observe this by seeing how many names are mentioned in these release notes. I am proud and grateful of the Zig community for this.
Although the implementation was difficult, the user-facing differences of Result Location Semantics are nearly impossible to detect. The main purpose was to pave the way for the redesign of {#link|Async Functions#}.
The main thing that this change does is semantically guarantee that no copying happens in expressions. As an example:
{#code_begin|test|result_loc#} const std = @import("std"); const Object = struct { tag: i32, pt: [2]Point, }; const Point = struct { x: i32, y: i32, }; test "result location semantics" { const result = if (condition()) foo(10) else bar(); std.testing.expect(result.tag == 10); std.testing.expect(result.pt[0].x == 69); std.testing.expect(result.pt[1].y == 420); } fn condition() bool { return true; } fn foo(arg: i32) Object { return baz(arg); } fn bar() Object { return Object{ .tag = 1, .pt = undefined, }; } fn baz(arg: i32) Object { return Object{ .tag = arg, .pt = [_]Point{ nice(), blazet() }, }; } fn nice() Point { return Point{ .x = 69, .y = 69, }; } fn blazet() Point { return Point{ .x = 420, .y = 420, }; } {#code_end#}The important thing to note here is that the functions {#syntax#}nice(){#endsyntax#} and {#syntax#}blazet(){#endsyntax#} write directly to result in the main test function. There are no intermediate copies, and this is semantically guaranteed by the language.
With Zig's current semantics, it is actually not possible to observe the difference between 0.4.0 and 0.5.0 (except with {#link|async function calls|Async Functions#}). However, with future proposals to the language it would matter a great deal:
The point here is that initialization functions would be able to set up pointer references relative to the return value, and have the value be guaranteed to be valid.
Before moving on to the next section I want to say a huge thank you to Michael Dusan. This branch was a dizzying amount of effort, and towards the end of it, Michael started contributing. He created test case reductions and even solved some of the regressions, such as vector to array conversion not being aligned correctly. This was both unexpected and helpful. It made a serious difference in getting me through to the end of the branch, so that we could merge it into master.
The other thing that came out of this branch was preferring the "result type" to Peer Type Resolution:
{#code_begin|test|result_loc_peer#} const std = @import("std"); const expect = std.testing.expect; test "result location type resolution" { var f = false; var x: i32 = 0; x = if (f) 1 else 2; expect(x == 2); } {#code_end#}Additionally:
{#syntax#}@unionInit(comptime Union: type, comptime active_field_name: []const u8, init_expr) Union{#endsyntax#}
This is the same thing as union initialization syntax, except that the field name is a comptime-known value rather than an identifier token.
{#syntax#}@unionInit{#endsyntax#} forwards its {#link|result location|Result Location Semantics#} to {#syntax#}init_expr{#endsyntax#}.
Thank you Robert Scott for the initial implementation of @unionInit.
{#header_close#} {#header_open|Unicode Escapes#}Zig's unicode escape syntax is changed to match most other popular programming languages.
Old syntax:
"\U01f4a9"
New syntax:
{#syntax#}"\u{1f4a9}"{#endsyntax#}
This matches JavaScript (since ES6), Lua (since 5.3), Swift (who swapped from our previous syntax!), and Rust.
Thank you daurnimator for doing the research on other languages, and Shawn Landden for the implementation.
It is planned to additionally allow unicode escapes in character literals, since character literals have type {#syntax#}comptime_int{#endsyntax#}. That accepted proposal is marked "Contributor Friendly" because it is limited in scope and/or knowledge of Zig internals.
{#header_close#} {#header_open|Async Functions#}{#syntax#}async{#endsyntax#} functions have been completely reworked in Zig 0.5.0. Previously, I was calling these "stackless coroutines". However I'm now avoiding the word "coroutine" since it means different things to different people, and instead using the phrase "async functions".
In Zig 0.4.0, all async functions were generic across an allocator type, all async functions took an allocator parameter, and calling an async function could fail. Additionally, async functions were required to be annotated as such.
In Zig 0.5.0, calling an async function can no longer fail. The async function frame is provided by the caller via {#link|Result Location Semantics#}, and can be in the caller's stack frame. Async functions are no longer generic, and do not require the {#syntax#}async{#endsyntax#} keyword. Zig infers that a function is {#syntax#}async{#endsyntax#} when it observes that the function contains a suspension point. Async functions can be called the same as normal functions. A function call of an async function is a suspend point.
When a regular function is called, a frame is pushed to the stack, the function runs until it reaches a return statement, and then the frame is popped from the stack. At the callsite, the following code does not run until the function returns.
An async function is a function whose callsite is split into an {#syntax#}async{#endsyntax#} initiation, followed by an {#syntax#}await{#endsyntax#} completion. Its frame is provided explicitly by the caller, and it can be suspended and resumed any number of times.
Here's a simple example of an async function:
{#code_begin|exe|async_fn#} const std = @import("std"); var frame: anyframe = undefined; pub fn main() void { std.debug.warn("begin main\n"); _ = async func(); std.debug.warn("resume func\n"); resume frame; std.debug.warn("end main\n"); } fn func() void { std.debug.warn("begin func\n"); frame = @frame(); suspend; std.debug.warn("end func\n"); } {#code_end#}Here we have a seam between non-async (main) and async (func) code. A more typical usage of this feature:
{#code_begin|exe|typical_async_await#} const std = @import("std"); const expect = std.testing.expect; // Try toggling these const simulate_fail_download = false; const simulate_fail_file = false; const suspend_download = true; const suspend_file = true; pub fn main() void { _ = async amainWrap(); // This simulates an event loop if (suspend_file) { resume global_file_frame; } if (suspend_download) { resume global_download_frame; } } fn amainWrap() void { if (amain()) |_| { expect(!simulate_fail_download); expect(!simulate_fail_file); } else |e| switch (e) { error.NoResponse => expect(simulate_fail_download), error.FileNotFound => expect(simulate_fail_file), else => @panic("test failure"), } } fn amain() !void { const allocator = std.heap.direct_allocator; var download_frame = async fetchUrl(allocator, "https://example.com/"); var download_awaited = false; errdefer if (!download_awaited) { if (await download_frame) |x| allocator.free(x) else |_| {} }; var file_frame = async readFile(allocator, "something.txt"); var file_awaited = false; errdefer if (!file_awaited) { if (await file_frame) |x| allocator.free(x) else |_| {} }; download_awaited = true; const download_text = try await download_frame; defer allocator.free(download_text); file_awaited = true; const file_text = try await file_frame; defer allocator.free(file_text); expect(std.mem.eql(u8, "expected download text", download_text)); expect(std.mem.eql(u8, "expected file text", file_text)); std.debug.warn("OK!\n"); } var global_download_frame: anyframe = undefined; fn fetchUrl(allocator: *std.mem.Allocator, url: []const u8) anyerror![]u8 { const result = try std.mem.dupe(allocator, u8, "expected download text"); errdefer allocator.free(result); if (suspend_download) { suspend { global_download_frame = @frame(); } } if (simulate_fail_download) return error.NoResponse; std.debug.warn("fetchUrl returning\n"); return result; } var global_file_frame: anyframe = undefined; fn readFile(allocator: *std.mem.Allocator, filename: []const u8) anyerror![]u8 { const result = try std.mem.dupe(allocator, u8, "expected file text"); errdefer allocator.free(result); if (suspend_file) { suspend { global_file_frame = @frame(); } } if (simulate_fail_file) return error.FileNotFound; std.debug.warn("readFile returning\n"); return result; } {#code_end#}The important thing to note here is that the {#syntax#}async{#endsyntax#}/{#syntax#}await{#endsyntax#} mechanism did not bring in a dependency on the host OS, and it did not bring in a dependency on an allocator.
Now watch what happens when we do this:
{#syntax#} const suspend_download = false; const suspend_file = false; {#endsyntax#}
$ zig build-exe typical_async_await.zig
$ ./typical_async_await
fetchUrl returning
readFile returning
OK!
It's the same output, except in reversed order. With these modifications, there are no async functions in the entire program! The expression {#syntax#}async fetchUrl(allocator, "https://example.com/"){#endsyntax#} is evaluated as a normal, blocking function, as is {#syntax#}async readFile(allocator, "something.txt"){#endsyntax#}. The {#syntax#}await{#endsyntax#}s are no-ops.
The point here is that the amain
function, which is the demo of typical async/await usage,
works in both an async context and blocking context. The programmer was able to express the inherent
parallelism of the logic, without resorting to
function coloring.
There is admittedly a bit of boilerplate in the example. Here's the tracking issue for that.
Now for the related {#link|Standard Library#} updates:
This introduces the concept of "IO mode" which is configurable by the Root Source File (e.g. next to {#syntax#}pub fn main{#endsyntax#}). Applications can put this in their root source file:
{#syntax#} pub const io_mode = .evented; {#endsyntax#}
This will populate {#syntax#}std.io.mode{#endsyntax#} to be {#syntax#}std.io.Mode.evented{#endsyntax#}. When I/O mode is evented, {#syntax#}std.os.read{#endsyntax#} handles EAGAIN by suspending until the file descriptor becomes available for reading. Although the std lib event loop supports epoll, kqueue, and Windows I/O Completion Ports, this integration with {#syntax#}std.os.read{#endsyntax#} currently only works on Linux.
This integration is currently only hooked up to {#syntax#}std.os.read{#endsyntax#}, and not, for example, {#syntax#}std.os.write{#endsyntax#}, child processes, and timers. The fact that we can do this and still have a working master branch is thanks to Zig's lazy analysis, comptime, and inferred async. We can continue to make incremental progress on async std lib features, enabling more and more test cases and coverage.
In addition to {#syntax#}std.io.mode{#endsyntax#} there is {#syntax#}std.io.is_async{#endsyntax#} which is equal to {#syntax#}std.io.mode == .evented{#endsyntax#}. In case I/O mode is async, {#syntax#}std.io.InStream{#endsyntax#} notices this and the read function pointer becomes an async function pointer rather than a blocking function pointer. Even in this case, {#syntax#}std.io.InStream{#endsyntax#} can still be used as a blocking input stream. Users of the API control whether it is blocking or async at runtime by whether or not the read function suspends. In case of file descriptors, for example, this might correspond to whether it was opened with {#syntax#}O_NONBLOCK{#endsyntax#}. The {#syntax#}noasync{#endsyntax#} keyword makes a function call or {#syntax#}await{#endsyntax#} assert that no suspension happens. This assertion has runtime safety enabled.
{#syntax#}std.io.InStream{#endsyntax#}, in the case of async I/O, uses by default a 1 MiB frame size for calling the read function. If this is too large or too small, the application can globally increase the frame size used by declaring {#syntax#}pub const stack_size_std_io_InStream = 1234;{#endsyntax#} in their root source file. This way, {#syntax#}std.io.InStream{#endsyntax#} will only be generated once, avoiding bloat, and as long as this number is configured to be high enough, everything works fine. Zig has runtime safety to detect when @asyncCall is given too small of a buffer for the frame size.
This merge introduces -fstack-report which can help identify large async function frame sizes and explain what is making them so big.
-fstack-report outputs JSON format, which can then be viewed in a GUI that represents the tree structure. As an example, Firefox does a decent job of this.
One feature that is currently missing is detecting that the call stack upper bound is greater than the default for a given target, and passing this upper bound to the linker. As an example, if Zig detects that 20 MiB stack upper bound is needed - which would be quite reasonable - currently on Linux the application would only be given the default of 16 MiB.
There is so much to go over with this feature, and these release notes are already ridiculously long. I'm going to have to resort to listing out some things here, and rely on a future post to elaborate on these features.
{#syntax#}@frameSize() usize{#endsyntax#}
{#syntax#}@frame() *@Frame(func){#endsyntax#}
{#syntax#}@Frame(func: var) type{#endsyntax#}
It is confirmed that async functions will solve safe recursion in Zig.
{#header_close#} {#header_open|SIMD#}Zig's SIMD support in 0.5.0 is still far from complete, but significant progress has been made.
Shawn Landden has a branch of Zig with SIMD fairly complete, and has been maintaining this patchset, as I slowly upstream the commits one-by-one (with adjustments, fixups, etc). Shawn is giving a talk on his work at the October LLVM Dev Meeting: Using LLVM's portable SIMD with Zig
See #903 for more details.
{#header_close#} {#header_open|Alignment of Struct Fields#}In Zig 0.4.0 there was this ugly kludge in the C++ stage1 compiler:
// TODO If we have no type_entry for the field, we've already failed to
// compile the program correctly. This stage1 compiler needs a deeper
// reworking to make this correct, or we can ignore the problem
// and make sure it is fixed in stage2. This workaround is for when
// there is a false positive of a dependency loop, of alignment depending
// on itself. When this false positive happens we assume a pointer-aligned
// field, which is usually fine but could be incorrectly over-aligned or
// even under-aligned. See https://github.com/ziglang/zig/issues/1512
} else if (field->type_entry == nullptr) {
this_field_align = g->builtin_types.entry_usize->abi_align;
It was a mistake to ever let this kludge into the C++ stage1 compiler, and it was difficult to remove this kludge in 0.5.0. But it's gone now.
In Zig 0.5.0, the C++ stage1 compiler has the concept of "Lazy Values". This solved the problem of false positive dependencies without a kludge such as this. It also enabled Zig programs to explicitly specify {#syntax#}struct{#endsyntax#} field alignment:
{#code_begin|test|field_align#} const std = @import("std"); const expect = std.testing.expect; const Node = struct { next: *Node, massive_byte: u8 align(64), }; test "struct field explicit alignment" { var node: Node = undefined; node.massive_byte = 100; expect(node.massive_byte == 100); comptime expect(@typeOf(&node.massive_byte) == *align(64) u8); expect(@ptrToInt(&node.massive_byte) % 64 == 0); } {#code_end#}In addition to this, "Lazy Values" solved the following bugs:
"Lazy Values" also paved the way for {#link|Standard Library#} integrations with {#link|Async Functions#}.
{#header_close#} {#header_open|@Type#}{#syntax#}@Type(comptime info: @import("builtin").TypeInfo) type{#endsyntax#}
This function is the inverse of @typeInfo. It reifies type information into a {#syntax#}type{#endsyntax#}.
It is available for the following types:
For these types it is a TODO in the compiler to implement:
For these types, {#syntax#}@Type{#endsyntax#} is not available. There is an open proposal to allow unions and structs.
Thank you to Jonathan Marler for the original implementation of @Type.
{#header_close#} {#header_open|Variable Declarations as Methods#}Variable declarations can now be called as methods:
{#code_begin|test|var_decl_methods#} const std = @import("std"); const expect = std.testing.expect; const Foo = struct { a: u64 = 10, fn one(self: Foo) u64 { return self.a + 1; } const two = __two; fn __two(self: Foo) u64 { return self.a + 2; } const three = __three; const four = custom(Foo, 4); }; fn __three(self: Foo) u64 { return self.a + 3; } fn custom(comptime T: type, comptime num: u64) fn (T) u64 { return struct { fn function(self: T) u64 { return self.a + num; } }.function; } test "fn delegation" { const foo = Foo{}; expect(foo.one() == 11); expect(foo.two() == 12); expect(foo.three() == 13); expect(foo.four() == 14); } {#code_end#}Thank you to Michael Dusan for proposing and implementing this. #3306
{#header_close#} {#header_close#} {#header_open|Standard Library#}HeapAlloc
, it is backed by VirtualAlloc
.
dl_phdr_info
ARCH_SET_*
definitions for x86_64.io_uring
.close$NOCANCEL
on Darwin,
so that it is impossible to fail.MAP_LOCKED
flag from load_dynamic_library and enabled the now passing tests.bcmp
implementation to zig's multi-target libc implementation.
This is especially useful because LLVM 9 now emits calls to bcmp.PATH_NOT_FOUND
in
{#syntax#}DeleteFileW{#endsyntax#}'s error set.main()
.AT_
constants because they are the same across
architectures. He fixed MAP_
definitions to match the kernel. #2837INT_MAX
. The linux syscall treats this
argument as having type int, so passing extremely long buffer sizes would be misinterpreted
by the kernel. Since "short reads" are always acceptable, just cap it down.mtime
, ctime
, atime
./dev/urandom
being a character device.
This is a security measure. {#syntax#}std.os.getrandom{#endsyntax#} will return
{#syntax#}error.NoDevice{#endsyntax#} if /dev/urandom
is not a character device.Elf
struct directly instead of filling in pointer. #2998Previously, due to a bug, the stack trace iteration code was using the number of frames collected as the number of frames to print, not recognizing the fixed size of the buffer. So it would redundantly print items, matching the total number of frames ever collected. Now the iteration code is limited to the actual stack trace frame count, and will not print duplicate frames. #2447 #2151
LemonBoy implemented a bunch of fixes for the DWARF parser (#2254):
DW_TAG_lexical_block
for variable declarations.Thanks to this, and some other debug info fixes from LemonBoy, stack traces now work in release builds:
{#code_begin|exe_err#} {#code_release_safe#} const std = @import("std"); fn foo() !void { return error.TheSkyIsFalling; } pub fn main() !void { try foo(); } {#code_end#}
LemonBoy additionally implemented reading symbol names from DWARF sections, so stack
traces on Linux now have actual function names instead of ???
's. You can see
this in the above stack trace.
There is an open issue with this, however - scanning all the symbol names is a bit slow. A future improvement will improve the "Big-O" performance of this function, and bring Zig stack traces up to the same speed that one gets with, for example, gdb.
Despite this trouble for debug info of very large Linux binaries, most projects will experience faster
stack traces thanks to Marc Tiehuis switching to using mmap
to read the debug info.
Usually, such techniques are frowned upon due to making error handling difficult, however, this
debug info code is currently designed for the use case of dumping a stack trace when
the application has already panicked, and is about to abort. And so, an error in loading debug
info from disk would be handled by aborting anyway.
In addition, the following improvements were made:
Marc Tiehuis created a plan to overhaul the std.fmt API. The plan is partially implemented in 0.5.0, but there is remaining work.
The main difference in 0.5.0 is the positional, precision, and width support. This removes the odd width and precision specifiers found and replacing them with the more consistent api described in #1358.
Take the following example:
{1:5.9}
This refers to the second argument (0-indexed) in the argument list. It will be printed with a minimum width of 5 and will have a precision of 9 (if applicable).
Not all types correctly use these parameters just yet. There are still some missing gaps to fill in. Fill characters and alignment have yet to be implemented.
In addition:
std.fmt
to handle std.SegmentedList
:{*:5}
FormatOptions
arguments non-{#syntax#}comptime{#endsyntax#}.
No need and should help avoid exessive function monomorphizaton.Marc Tiehuis ported upstream changes from musl's math functions.
This also starts the documentation effort for the math/ subdirectory. The intent is to use this as a somewhat representative test-case for any work on the documentation generator.
Thanks to LemonBoy, Zig now has support for {#syntax#}threadlocal{#endsyntax#} variables on Linux without relying on libc, on the following architectures:
In addition to wider architecture support, he implemented on-demand TLS allocation. Previously, if there were too many thread local variables, Zig would panic on startup.
With these changes, Zig has proper support for TLS on Linux.
{#header_close#} {#header_open|Reorganization of Operating System Abstractions#}
In Zig 0.5.0, OS abstractions are organized in a straightforward manner.
{#syntax#}std.os{#endsyntax#} is "Zig-flavored POSIX". All the "bits" familiar to C
programmers are available in this namespace, such as {#syntax#}O_RDONLY{#endsyntax#} and
{#syntax#}open{#endsyntax#}. The functions have errno translated to Zig errors (on Linux
without libc, there is no {#link|thread local variable|External Thread Local Variables#}
for errno
🎉) and slices are used rather than raw pointers where appropriate.
Higher level, cross-platform abstractions are available in category-specific namespaces, for example {#syntax#}std.fs.File.openRead{#endsyntax#}.
{#syntax#}std.os.windows{#endsyntax#} has "Zig-flavored Windows", with {#syntax#}GetLastError{#endsyntax#} translated to Zig errors. Raw Windows APIs are available directly via namespaces named after their DLLs, for example {#syntax#}std.os.windows.kernel32.ExitProcess{#endsyntax#}.
Zig's optional integration with libc is significantly more robust. {#syntax#}std.os{#endsyntax#} functions call libc functions when linking against libc, and otherwise use the operating system's syscall ABI directly.
After some experimentation, it was concluded that Windows does not integrate well with libc, and so on Windows, even when linking libc, the native Windows API calls are used rather than libc API.
See #2380 for more details and discussion.
{#header_close#} {#header_open|Recursive Rewrite of Self-Hosted Parser#}Zig's self-hosted parser is in the standard library - {#syntax#}std.zig.parse{#endsyntax#}. It's the backbone of {#link|zig fmt#}.
I've said before that recursion is one of the enemies of perfect software, because it represents a way that a program can fail with no foolproof way of preventing it. With recursion, pick any stack size and I'll give you an input that will crash your program. Embedded developers are all too familiar with this problem.
It's always possible to rewrite code using an explicit stack using heap allocations, and that's exactly what Jimmi did in the self-hosted parser.
This implementation of the self-hosted parser is an interesting case study of avoiding recursion by using an explicit stack. It is essentially a hand-written recursive descent parser, but with heap allocations instead of recursion. This code is truly a work of art. I like to call it "Jimmi's non-recursive recursive-descent parser".
When Jimmi originally implemented the code, we thought that we could not solve the unbounded stack growth problem of recursion. However, now we have a plan for safe recursion.
And so it was time to lay the code to rest. This is where Stevie Hryciw came in. Stevie rewrote the entire self-hosted parser, to the full grammar specification. This was a large project spanning across several weeks. During this time, Stevie endured painful rebases and dutifully updated the pull request description to keep everyone informed.
Stevie didn't stop there - he followed up by analyzing {#link|Performance Impact#} as well as {#link|Readability Impact#}. He writes:
{#header_open|Performance Impact#}Here are some informal tests of parser_test.zig with perf stat -d on x86_64 Linux.
In the absence of visualizations and more formal testing, some quick findings based on my system:
Indentation stats of std/zig/parse.zig
:
master | stage2-recursive-parser --------------------------------+--------------------------------- indent count | indent count ------------ | ------------ 0 92 | 0 263 1 241 | 1 803 2 123 | 2 763 3 291 | 3 334 4 654 | 4 133 5 662 | 5 60 6 700 | 6 28 7 347 | 7 5 8 229 | 9 42 | 10 18 | avg indentation level: 4.796999 | avg indentation level: 1.827543 source lines of code: 3399 | source lines of code: 2389
x86_64-linux and Windows now have, by default, a segfault handler that is attached before main()
.
Thanks to this, Zig programs now have stack traces for segfaults:
This can be disabled:
{#code_begin|exe_err#} pub const enable_segfault_handler = false; pub fn main() void { dereferenceAPointer(@intToPtr(*i32, 0x1)); } fn dereferenceAPointer(ptr: *i32) void { ptr.* = 10; } {#code_end#}This works because the standard library uses the new feature {#link|@import("root")#} to check for this opt-out.
Thank you to Rocknest for a proof-of-concept implementation of this in #2355.
{#header_close#} {#header_open|HashMap and Hashing#}autoHash
make use of hashing streaming interface.
Notably, Sahnvour made std.HashMap
consistent about whether or not it will
dereference keys. std.AutoHashMap
no longer will dereference slices
({#syntax#}[]const u8{#endsyntax#} or {#syntax#}[]u8{#endsyntax#}), or any pointer type
for that matter:
{#syntax#}std.StringHashMap{#endsyntax#} is provided for this use case instead:
{#code_begin|test|string_hash_map#} const std = @import("std"); test "StringHashMap" { var map = std.StringHashMap(bool).init(std.heap.direct_allocator); _ = try map.put("hello", true); } {#code_end#}Additionally:
autoHash
to handle more types and behave more correctly.std.mem.eql
and simplified
{#syntax#}std.hash_map.eqlString{#endsyntax#}.Marc Tiehuis made a series of improvements to hashing performance:
Inline full slice hashing - this gives moderate speed improvements when hashing small keys. The crc/adler/fnv inlining did not provide enough speed up to warrant the change.

Using ./benchmark --filter wyhash --count 1024
, the speed change has
changed from:
wyhash
iterative: 4093 MiB/s [6f76b0d5db7db34c]
small keys: 3132 MiB/s [28c2f43c70000000]
to
wyhash
iterative: 6515 MiB/s [673e9bb86da93ea4]
small keys: 10487 MiB/s [28c2f43c70000000]
{#header_close#}
{#header_close#}
{#header_open|Documentation#}
@setGlobalLinkage
section. @setGlobalLinkage
was removed with
#462. The not-yet-implemented proposal for external weak symbols is #1917.-target
command line argument.example/
folder. Code moved to become standalone tests. #2759
zig build
is still in an experimental, proof-of-concept phase, and will remain
that way until at least the {#link|package manager|Package Manager Status#} is complete.
However, there were still improvements to zig build
this release cycle:
zig build
.zig build
now searches up the directory hierarchy for build.zig
. #2587setLibCFile
APIstandardTargetOptions
and deprecated setTarget
in favor of
setTheTarget
.DESTDIR
environment variable. #2929'/'
showing up in application/library names.linkSystemLibrary
integrates with pkg-config
.
zig fmt
now fixes invalid whitespace instead of rejecting it.
The {#syntax#}// zig fmt: off{#endsyntax#} directive is ignored for whitespace fixes.
a && b
as {#syntax#}a & &b{#endsyntax#}. Now it has a helpful error message: "`&&` is invalid. Note that `and` is boolean AND.". #2660Thanks to {#link|WebAssembly Support#} improvements, there is also a web-based formatter made by Shritesh Bhattarai.
{#header_close#} {#header_open|libc#}
Zig now provides libc for the following targets (find this information with zig targets
):
Zig ships with the source code to musl. Zig 0.5.0 updates to the 1.1.23 release of musl, plus a handful of patches to fix various issues with {#link|64-bit ARM Support#} and {#link|RISC-V Support#}. All these patches are merged into musl upstream and will be part of the next release.
Previously, the way that Zig built musl from source skipped some necessary files. LemonBoy solved this issue.
Additionally, the updating process for musl was brittle and confusing. Now, the process is streamlined and fully documented. Unnecessary patches were dropped.
Now, Zig has excellent {#link|Test Coverage#} of musl. The Zig test suite tests building musl for these targets:
In Zig 0.5.0, not only can Zig provide dynamically linked glibc for any target, but it can also provide any version of glibc for any target:
getrandom.zig
{#syntax#} const std = @import("std"); pub fn main() void { var buf: [16]u8 = undefined; _ = std.c.getrandom(&buf, buf.len, 0); } {#endsyntax#}
$ ./zig build-exe test.zig -lc -target x86_64-linux-gnu -target-glibc 2.24
lld: error: undefined symbol: getrandom
>>> referenced by test.zig:5 (/home/andy/dev/zig/build/test.zig:5)
>>> ./test.o:(main.0)
$ ./zig build-exe test.zig -lc -target x86_64-linux-gnu -target-glibc 2.25
$ ./test
$
Updating to the newest glibc version is now streamlined and fully documented. Even though Zig now supports every version of glibc, the amount of bytes required for a Zig installation with regards to glibc has decreased, because a dummy libc file is no longer required, as it is generated on-the-fly depending on the target version selected.
The target glibc version is exposed in {#syntax#}@import("builtin"){#endsyntax#} and is used by
the {#link|Standard Library#} to do a glibc version check, to decide whether to use libc
getrandom
or read from /dev/urandom
. #397
The supported glibc version range is increased to include 2.30.
Building glibc now has {#link|Test Coverage#} when the -Denable-qemu
and
-Denable-foreign-glibc
options are enabled, for these targets:
Zig now ships with the source code and header files to mingw-w64 (version 6.0.0), and uses this to provide libc when targeting Windows.
Combining this with Wine, one can cross-compile C code for Windows and run it, without even touching a Windows computer:
hello_windows.c
#include <stdio.h>
int main(int argc, char **argv) {
printf("Hello Windows\n");
return 0;
}
$ zig build-exe --c-source hello_windows.c -lc -target x86_64-windows-gnu
$ wine hello_windows.exe
Hello Windows
Building and linking against mingw-w64 libc now has {#link|Test Coverage#}
for the x86_64-windows-gnu
target.
One of the use cases for this is creating {#link|Zig packages|Package Manager Status#} out of C libraries, and there is now a proof of concept of this with SDL2.
The open-source game Legend of Swarkland is being written in Zig, and it uses this SDL2 package in order to support cross compiling for Windows with nothing installed other than Zig. The developer, Josh, does not have a Windows computer to test on, but has a brother who uses Windows he wants to be able to playtest his game. Using only Zig and Wine, Josh can create Windows builds of his game and even test them, before sending his brother an executable.
$ git clone https://github.com/thejoshwolfe/legend-of-swarkland --recursive
$ cd legend-of-swarkland
$ zig build -Dtarget x86_64-windows-gnu
$ ls zig-cache/bin
legend-of-swarkland.exe legend-of-swarkland_headless.pdb
legend-of-swarkland_headless.exe legend-of-swarkland.pdb
Integration with mingw-w64 is easy and clean, because their headers are already
multi-architecture. Thank you especially to IRC user wbs
, who is
largely responsible for that, and for patiently helping me
work through my own issues caused by hacking up the mingw-w64 build system to
integrate into Zig.
Zig provides libc even when compiling in freestanding mode. This enables some C libraries to work even when there is no host Operating System.
In Zig 0.5.0, this concept is a little bit more fleshed out and clear. One can observe this freestanding libc in action when building C code for {#link|WebAssembly|WebAssembly Support#}.
There is still a lot to do on this front, and it could be an engaging project for contributors.
{#header_close#} {#header_close#} {#header_open|C Translation#}LemonBoy made several improvements:
Thanks to {#link|C pointers supporting optional syntax|C Pointers Support Optional Syntax#},
NULL
pointers now translate to {#syntax#}null{#endsyntax#}.
Additionally:
In Zig 0.4.0, the translate-c
and @cImport implementations are 5,000 lines of C++.
However, in this release, Zig is transitioning to a fully self-hosted implementation.
The parts of translate_c.cpp
that interact with the Clang C++ API have been extracted
into zig_clang.h
and zig_clang.cpp
. This is a C API on top of the C++ API
with some careful static assertions to ensure the file is kept up-to-date as Clang's C++ API changes.
translate_c.cpp
now interacts with the Clang C++ API exclusively via zig_clang.h
.
These files are generally useful for any project and they are MIT licensed.
Based on zig_clang.h
, clang.zig
is created, updated, and maintained. This is
extern functions and types so that Zig code can utilize the C layer on top of the Clang C++ API.
And with this, we have src-self-hosted/translate_c.zig
which is the self-hosted implementation
of translate-c
(and @cImport). This is exposed with zig translate-c-2
.
Until the self-hosted implementation is brought up to feature parity, zig translate-c
and @cImport are still the C++ implementation. This work is partially done thanks to Stevie Hryciw; you can get a sense of progress by
examining the test cases.
More contributions welcome!
See #1964 for more details.
{#header_close#} {#header_close#} {#header_open|compiler-rt#}compiler-rt is the library that provides, for example, 64-bit integer multiplication for 32-bit architectures which do not have a machine code instruction for it. In the gcc world, it's called libgcc.
Unlike most compilers, which depend on a binary build of compiler-rt being installed alongside the compiler, Zig builds compiler-rt on-the-fly, from source, as needed for the target platform. This release saw some improvements to Zig's compiler-rt implementation.
__muloti4
.
LemonBoy also fixed an edge case in addXf3
- since the operands may be zero,
he used the wrapping operators to avoid a spurious integer-overflow error. He then proceeded
to other fixes:
__aeabi_{f,d}cmp*
.__extendhfsf2
using @bitCast.With Zig 0.5.0, compiler-rt much more complete, but not fully. There are some missing functions, and it's planned to do an audit before 1.0.
{#header_close#} {#header_open|Test Coverage#}Zig now has much more exhaustive test coverage of foreign architectures, thanks to QEMU. These new options are available to {#link|zig build#} when running the Zig test suite:
-Denable-qemu
- runs cross-compiled compiler-rt, behavior, and std lib tests on
foreign architectures.-Denable-wine
- runs cross-compiled compiler-rt, behavior, and std lib tests
with Wine.-Denable-foreign-glibc=path
- if you have builds of glibc for other architectures
available, this enables testing cross-compiled compiler-rt, behavior, and std lib tests
on foreign architectures, dynamically linking glibc.-Dskip-non-native
- skips all non-native tests.-Dskip-libc
- if you don't want to wait for e.g. {#link|musl|musl 1.1.23#} to build.See CONTRIBUTING.md for more details.
Michael Dusan implemented a new kind of test coverage for stack traces, to catch future regressions in {#link|Debug Info and Stack Traces#}.
Additionally:
{#syntax#}std.debug.global_allocator{#endsyntax#} is deprecated as far as being used in tests is concerned. Tests should use {#syntax#}std.heap.FixedBufferAllocator{#endsyntax#} and stack memory instead.
{#header_close#} {#header_open|Miscellaneous Improvements#}0
for {#syntax#}comptime{#endsyntax#} types.
This defines @sizeOf to be the runtime size of a type, which means
that it is zero for types such as comptime_int, type, and (enum
literal). #2209
#!
) support. #2165test "<name>"
in order
to be more easily distinguished from functions with similar names. #2267
--enable-pic
and --disable-pic
to -fPIC
and
-fno-PIC
.--bundle-compiler-rt
linker option.zig cc
rather than concatenating
all assembly blocks into one large string and handing that to LLVM. This fixed bugs as well as
enabling C preprocessor support for assembly files.std/special/bootstrap.zig
is renamed to std/special/start.zig
.
This makes a bit more sense, and actually is kinda important to make sense because it shows
up in stack traces. Further, the logic on whether to include this file is improved.lib/
directory that mirrors the directory tree of installed files,
and std/
is moved into it appropriately. These changes led to
{#link|Self-Hosted Installation of Library Files#}.AstNode
objects have a src()
method
to print the corresponding source file, line number, and column number. This is handy
when using a debugger.-l
parameters as an alias for --library
. As
an example, one may specify -lc
rather than --library c
./debug:fastlink
when building with MSVC and debug info.zig_panic
rather than
having LLVM abort.--test-cmd
is provided to zig test
, it will run it regardlesso
of whether the binary is native. This enables, for example, testing with
QEMU.-D
CLI parameter for setting C preprocessor definitions.When Zig compiles C code (using {#link|libclang|LLVM 9#}), it automatically enables .d file generation so that Zig can learn the dependencies and do proper caching.
Previously, Zig's .d file parser was written in C++ and a bit brittle. Michael Dusan dove head-first into this and implemented a robust .d file parser, in self-hosted Zig code, complete with unit tests.
Unfortunately, there is still an open issue regarding this, because the first line Clang outputs cannot be parsed unambiguously. Clang Bug Report. If you, the reader of these release notes, are a Clang developer, please fix 🙏
{#header_close#} {#header_open|Binary Size#}{#syntax#}@import("builtin"){#endsyntax#} gained {#syntax#}strip_debug_info{#endsyntax#} which is
a {#syntax#}comptime bool{#endsyntax#} value telling whether --strip
was passed to the
compiler.
This makes Zig code aware at compile-time of when it will not have any debug information available at runtime. The standard library now takes advantage of this to avoid Zig binaries containing useless debug info code.
This, along with Timon Kruiper's contribution of enabling the equivalent of
-ffunction-sections
in Zig's LLVM codegen, resulted in tiny
ReleaseSmall binaries:
hello.zig
{#syntax#} const std = @import("std"); pub fn main() void { std.debug.warn("Hello, World!\n"); } {#endsyntax#}
$ zig build-exe hello.zig --release-small --strip --single-threaded
$ ./hello
Hello, World!
$ ls -ahl ./hello
-rwxr-xr-x 1 andy users 10K Sep 26 15:56 ./hello
$ ldd ./hello
not a dynamic executable
The Windows build is even smaller:
$ zig build-exe hello.zig --release-small --strip --single-threaded -target x86_64-windows
$ wine64 ./hello.exe
Hello, World!
$ ls -ahl ./hello.exe
-rwxr-xr-x 1 andy users 3.0K Sep 26 15:57 ./hello.exe
Zig's ability to create tiny executables is especially attractive for {#link|WebAssembly|WebAssembly Support#}.
{#header_close#} {#header_open|Self-Hosted Installation of Library Files#}
Previously, when editing source files, it was required to make install
(msbuild -p:Configuration=Release INSTALL.vcxproj
on Windows) in order
to test changes. This used cmake's install()
function for all the library files,
such as the {#link|Standard Library#}, as well as the {#link|libc#} files that Zig
ships with. Unfortunately, this printed something like this every time:
-- Installing: /home/andy/dev/zig/build/lib/zig/std/array_list.zig
-- Installing: /home/andy/dev/zig/build/lib/zig/std/ascii.zig
-- Installing: /home/andy/dev/zig/build/lib/zig/std/atomic/int.zig
(...snip...)
...for all 6,091 lib files. Even when the files are already installed, it would print:
-- Up-to-date: /home/andy/dev/zig/build/lib/zig/std/array_list.zig
-- Up-to-date: /home/andy/dev/zig/build/lib/zig/std/ascii.zig
-- Up-to-date: /home/andy/dev/zig/build/lib/zig/std/atomic/int.zig
(...snip...)
There is no way to disable this in cmake. This caused make install
on my Linux computer to take 2.4 seconds even when it has to do nothing, and prints all these
unnecessary lines to stdout. On my Windows it took even longer, upwards of 5 seconds.
Now, installation of lib files is self-hosted, using {#link|zig build#}. Running
make
when there is nothing to do takes 0.3 seconds on my Linux computer;
2.4 on Windows.
Unfortunately, lib file installation
happens in the make
target instead of the make install
target, because
cmake has no way to add a custom command to the install target. So that's why Zig now has the
option -DZIG_SKIP_INSTALL_LIB_FILES=ON
, which is recommended to enable for
contributors to Zig. It's off by default because otherwise installing Zig would be missing
library files. However when contributing to Zig, running the zig
binary from
the build directory will search upwards for library files and find them directly in the source tree.
This means one can directly edit the {#link|Standard Library#} in the source tree, and changes
will be picked up without needing to run make
at all.
Warning: Unable to write cache file [..]: unexpected seek failureBen took care to make os_file_close poison the file handle after closing, to help track down future use-after-close bugs.
-fvisibility-inlines-hidden
to the build flags.
On macOS building with Xcode/clang the linker complains loudly when
symbol visibility is inconsistent. This option syncs visibilty setting
of both LLVM and Zig.
clock_gettime
on Linux systems without VDSO.std.heap.FailingAllocator
not counting allocations.K_DARWIN
as expected on the archive file. This allowed removing macOS-specific linking hacks.zig run
.add_source_file()
.zig cc
,
resolves intrinsics issues. #3027build-obj
not working with C files that use libc. #3093**
causing a segfault when run. #3095One interesting thing here is that if the compiler was written in Zig this bug likely never would have happened as Zig would protect you from dereferencing a NULL pointer like this. The tag_type field would either be an optional type which would require testing for NULL before using it, or it wouldn't be optional and couldn't be set or initialized to NULL.
fatal: not a git repository
message.RLIMIT_NOFILE
. Patch lifted from node.js commit
6820054d2d42ff9274ea0755bea59cfc4f26f353.
Thanks to Ben Noordhuis for the suggestion and patch.AT_FDCWD
definition.tail
attribute for @panic causing undefined behavior in the stage1
C++ compiler when it hit asserts, causing it to print garbage memory to the terminal. #3262zig cc
.output-dir
if it does not exist.
#2637mmap2
offsets if not multiple of page size.Zig has known bugs.
Zig is immature. Even with Zig 0.5.0, working on a non-trivial project using Zig will likely mean participating in the development process.
The first release that will ship with no known bugs will be 1.0.0.
{#header_close#} {#header_close#} {#header_open|Roadmap#}The major theme of next release cycle will be safety.
Along with this, it's planned to resume work on the self-hosted compiler now that new {#link|Async Functions#} are done.
Issues that have the possibility of breaking changes to the language will be prioritized, so that the language can be stabilized.
{#header_open|Package Manager Status#}Having a package manager built into the Zig compiler is a long-anticipated feature. Zig 0.5.0 does not have this feature, however the Zig project now that {#link|Async Functions#} are complete, it's time to begin on networking in the {#link|Standard Library#}. I expect to complete this along with at least an early prototype of the package manager during the next release cycle.
{#header_close#} {#header_open|Accepted Proposals#}Here are proposals that have been accepted during the 0.5.0 release cycle, to give you an idea of the upcoming changes to Zig:
During this release cycle, I joined the GitHub Sponsors program. This transition went fairly smoothly, thanks to Devon Zuegel. It's pretty clear to me that she's going above and beyond what's professionally required of her to help maintainers get sponsored.
At this point, funding for the Zig project is stable. There are enough funds that I can continue to work full time on Zig without burning down my savings. Based on current trends, I should even be able to get health insurance soon.
However, community growth has outpaced funding growth. My job has become more and more demanding over time. Even just merging pull requests at this point is a full time job. I have averaged merging 1.5 pull requests per day into Zig for the last 4 years. There is more than enough work for 2 full-time developers on Zig, and I would love to get to the point where paying another full-time developer is possible.
To facilitate this, I'm planning on starting Zig Software Foundation non-profit organization. I am looking for recommendations for a lawyer who would help me set this up. If you know one, please send me an email.
{#header_close#} {#header_open|Thank You Sponsors!#}Special thanks to those who sponsor Zig. Because of you, Zig is not driven by the needs of a business; instead it exists solely to serve the open source community.


Angularjs directive for Dropzone, an easy to use drag'n'drop file upload library.
Chech source code to know how to set up. You need to set display:none on dropzone.
I have used ng-dropzone.css for clean dropzone UI in these examples.
Go Back to GitHub


Biographical Sketch of William
Young Dent
William
Young Dent
Source: e-mail from Donald R. Dent, Jr. April 27,
2005
William
Young Dent was born 30 Sep 1832, a short distance southeast of Jacobsburg,
in Belmont County, Ohio. He was the grandson of early Belmont County settlers,
Asa and Martha (Hays) Dent, and the eldest son of George Eli (1806-1846) and
Sarah (Calvert) Dent (1815-c.1854). George and Sarah removed to Adams Twp and
later to near Beallsville, in Monroe County in the early 1840 s.
William
married Emily Jane Chynoweth (1830-1907) on 1 Jan 1852, in Beallsville. They
resided in Sunsbury Twp until the spring of 1868, when they removed to Barnesville
in Belmont Cty. They raised six children in Monroe Cty Albert Eli
(1852-1936), Wilbur Ross (1854-1906), Martha Elizabeth (1857-1931), Sarah M.
(1859-1930), Emit Ellsworth (1862-1930), and Mary Elma (1864-1896). Sarah M.
was the child who was born in October, 1859, a month after William returned
from Pike s Peak.
William
was opposed to slavery, and an ardent supporter of the Republican Party, from
its inception, and of Mr. Lincoln. After the outbreak of the Civil War, William
went to enlist in the Union Army, but was rejected. Shortly before, he had
received a severe scalp wound from a falling timber while assisting his
Father-in-Law, William Chynoweth, build a barn. The Army doctors felt that he
was unable to serve, but the U.S. Marshal s Office appointed him Deputy U.S.
Marshal, and he spent the next four years chasing draft dodgers and Union Army
deserters, a job almost as dangerous as the Army.
The
1850 Census lists William s occupation as Carpenter . He followed this occupation throughout his life.
Many buildings he erected in Barnesville stood for over 60 years. The M.E.
(Methodist Episcopal) Church, to which he acted as Superintendent of
Construction, was still in use after 1930.
On 17
July 1878, while picking up a load of lumber, William was severely injured in
the boiler explosion of Davis and Starbuck s Planing Mill, in Barnesville.
Suffering a dislocated hip, and several broken ribs, he never sufficiently
recovered. Four men were killed and at least ten others were injured in this
explosion, which completely destroyed the mill.
In
Barnesville, he served on the City Council several years. He also remained
active as a member of the M.E. Church.
William
died 31 Oct 1894, at his home on East Church Street, after several months of
confined illness. His remains are interred in Southern Cemetery, Barnesville.
Submitted by Donald R. Dent,
Jr., great grandson of William Y. Dent.
Provided by Don Dent
Click here for the Short-Cut Table of Contents


Teams are shown a series of clues. The clues solve to nonsense phrases. Each nonsense phrase is the result of taking a common "foo in bar" phrase, and putting the word foo in the word bar and adding an extra letter. E.g., the nonsense phrase HARM UPS is UP in ARMS plus H.
| Clue | Answer | Phrase | Extra letter |
|---|---|---|---|
| Injure a package delivery service | HARM UPS | UP IN ARMS | H |
| Amount you have to put up to get on a horse | STAKE TO RIDE | TAKE IN STRIDE | O |
| Made the number before two realllly long | STRETCHED ONE | ETCHED IN STONE | R |
| Got a steal on better plot of real estate using Korean currency | WON DEAL: NICER LAND | ALICE IN WONDERLAND | N |
| The period in your life where you are taking care of someone (or working at a bar) | TENDING YEARS | ENDING IN TEARS | Y |
| Declare that it's Mr. Offerman's fault | BLAME NICK | MEN IN BLACK | I |
| A military meal for the entire rodent lair | MOUSE DEN RATION | USE IN MODERATION | N |
| "Hold up, boy! I am fixing my shoelaces, which seem to have come undone." | WAIT LAD, TYING | LADY IN WAITING | T |
| Trips to and from the end of the pool where you don't really mean it | IRONIC LAPS | CLAP IN IRONS | I |
| Command to Kristoff's reindeer: "Make these corncobs warmer!" | HEAT EARS, SVEN | TEARS IN HEAVEN | S |
| Solo's attempt to get laughs | HAN'S COMEDY | COME IN HANDY | S |
| Overheard at the Taj Mahal: "That's an almond, not a pistachio!" | AGRA NUT ID | GRANT IN AID | U |
| What you need to sport on your face and chin before heading to your job in the coal shafts | MINE BEARD | BEAR IN MIND | E |
The extra letters spell out HORNY IN TISSUE. This clues the solution: THORNY ISSUE.


As of version 1.7, we have created two new extensions ws.js and sse.js to support realtime development in htmx. All new effort on WebSockets and Server Sent Events will occur in these extensions.
The existing hx-ws and hx-sse tags have been deprecated and will not receive any more updates. We plan to remove these two tags from the core library in htmx version 2.0.
Because extensions use a different calling syntax, there are minor differences in the way that this new code is invoked. This test server includes several demos / manual tests for each extension that you can try out for yourself. Each is presented side-by-side with test cases for the original code so that you can see the difference.


My LinkedIn
is a link to another cool site
This is a dog
This is a cat
Send me mail at
<EMAIL_ADDRESS>.
Dogs are very nice!
Cats are mean but somewhat nice too!
I love both cats and dogs, though


@JvmStatic fun toSupportedPublicKey(key: SubjectPublicKeyInfo): PublicKey
Convert a public key to a supported implementation.
IllegalArgumentException
- on not supported scheme or if the given key specification
is inappropriate for a supported key factory to produce a private key.
Return
a supported implementation of the input public key.
@JvmStatic fun toSupportedPublicKey(key: PublicKey): PublicKey
Convert a public key to a supported implementation. This can be used to convert a SUN's EC key to an BC key. This method is usually required to retrieve a key (via its corresponding cert) from JKS keystores that by default return SUN implementations.
IllegalArgumentException
- on not supported scheme or if the given key specification
is inappropriate for a supported key factory to produce a private key.
Return
a supported implementation of the input public key.


They study the problem of learning associative memory – a system which is able to retrieve a remembered pattern based on its distorted or incomplete version.
Attractor networks (Hopfield networks are a particular type) provide a sound model of associative memory: patterns are stored as attractors of the network dynamics and associative retrieval is performed by running the dynamics starting from a query pattern until it converges to an attractor.
In such models the dynamics are often implemented as an optimization procedure that minimizes an energy function, such as in the classical Hopfield networks.
Basically they have interpretation in terms of auto-encoder and minimize the reconstruction errors on distorted patterns to learn appropriate writing and retrieval rules.
\[ \underset{\theta, r, \tau}{\mathop{min}}~\mathbb{E}_{X\sim p(X)} \left[\mathcal{L}\left(X, \mathop{read}\left(\tilde{X};\mathop{write}(X)\right)\right)\right].\]
Here writing loss is defined as:
The Early-stopping gradient descent is implement on writing loss to implement the writing rule:
\[ \mathop{write}(X)=\theta^{(T)},~~\theta^{(T+1)}=\theta^{(T)}- \eta^{(T)} \frac{1}{N}\sum_{i=1}^{N}\nabla_{\theta}\mathcal{W}(x_i ; \theta^{(T)}) . \] Here, $\mathop{write}$ is modelled by encoder and $\mathop{read}$ is modelled by decoder.


FNC's Roberts: Trump’s Yovanovitch Tweet Caused ‘a Lot of Damage’ to Foreheads at the White House | Breitbart
by Pam KeyOn Friday’s broadcast of Fox News Channel’s “Your World, Fox News Neil Cavuto,” John Roberts reported on White House officials’ reactions to President Donald Trump’s tweet about former Ukraine ambassador Marie Yovanovitch.
While mimicking someone smacking their forehead, Roberts said, “I don’t know how much political damage that tweet is going to do, Neil, but certainly I think there was a lot of damage here at the White House to a collective group of foreheads as people went like this as the President tweeted that outright in the middle of the hearing. If anything, what it did was it really took the Republicans off of the message that they were trying to put out there and took this hearing in an entirely different direction than it had been before.”
He added, “To send out that tweet in the middle of a hearing gave Adam Schiff, the Intelligence Committee Chairman, a perfect opportunity to say, ‘Hmm, maybe we should consider an article of impeachment here on witness intimidation.'”
Follow Pam Key on Twitter @pamkeyNEN


{{< layout}} {{$pageTitle}}Photo uploaded{{/pageTitle}} {{$header}}
Next, you'll check your photo for common mistakes.
We’ll also check your photo manually. If something doesn't look right, we'll ask you for a different photo.
Upload a different photo


Press the button to make a test payment. It won't actually charge you!
You can enter fake details. Here are some example card numbers.
Success! We simulated the payment 😉
Aw, unable to complete the payment simulation! 😫
Sorry your browser does not appear to support the Payment Request API.
Normally we would practise progressive enhancement and use another payment UI here, but this is just a Payment Request demonstration!


--- layout: default title: People Involved in ALEC --- {% assign people = site.data.people %} {% assign people = people | sort:"Name" %} {% for person in people %}
{{ person.Name }}, {{ person.Affiliation }}
Role at ALEC: {{ person.Role }} (Membership Status: {{ person.Status }})


BLYTHE ACADEMY
UKPRN: 12345678
General Annual Grant 2017 to 2018
School Funding
| Description | Total |
|---|---|
| School Budget Share | £4,742,293.48 |
| Minimum Funding Guarantee | £273,093.44 |
| Total School Allocation | £5,015,386.92 |
High Needs Funding
| Description | Total |
|---|---|
| Pre-16 high needs place funding | £2,800.00 |
| Post-16 high needs place | £200.00 |
| Total High Needs Allocation | £3,000.00 |


Ant Script Library
Overview
The Ant Script Library (ASL) is a collection of re-usable Ant scripts that can be imported into your own projects. The ASL provides a number of pre-defined targets that simplify setting up build scripts for a new project, bringing re-use and consistency to your own Ant scripts.
The ASL is licensed under the Apache License, version 2.0.
Example Usage
This is the simplest build.xml
that makes use of the
ASL:
<project name="hello-world" default="dist"> <import file="ant-script-library/asl-java.xml"/> </project>
Documentation
For more details, refer to the following:
Is there a problem or mistake on this page? Do you want to contribute some changes? Send me an email at joe@exubero.com.


Dashboard
Projects
Project overview
New project
Project statistics
Project management
Service
Categories
About us
Overview
Overviews 1
Overviews 2
Overviews 3
Overviews long title 4


| \t - a tabulation character |
| \n - a newline |
| \r - a carriage return |
| \' - a single quote character |
| "" - a double quote character |
| \\\\ - a backslash character |
The whole value in the column with comma should be enclosed in double quotes
Value in column is: value,with,commas
should be written like this: "value,with,commas"
The same is for expressions: @{format(time(0), 'yyyy-MM-dd')}
In CSV it should be: "@{format(time(0), 'yyyy-MM-dd')}"


This post is
intended for those who write articles and books on the subject of creating high-quality C/C++ code or security issues.
While studying various projects with the help of the PVS-Studio static analyzer, we have gathered a relatively large database of error samples. I suppose this database will be of use and much interest to some authors.
The link to the error samples collection:
http://www.viva64.com/en/examples/
The database looks quite plain and is not rich in decorations. But the samples are cut out manually and edited so that one could easily understand them.
Of course, far not all the errors detected in a certain project are added to the database. It’s difficult to understand while looking through someone else’s project whether or not there is an error in a certain code fragment. You’d better skip such fragments about which you are not sure. However, we’ve gathered a lot of examples which can be used in studying error patterns.
It has happened so that the PVS-Studio analyzer is good at detecting various misprints or Copy-Paste-related mistakes. To understand what I mean, please have a look at these error samples detected by the V501 diagnostic:
http://www.viva64.com/en/examples-V501/ . There are naturally other diagnostics detecting similar errors. I’m writing this to show you the way the collection can be used. Studying misprints and Copy-Paste errors you may work out a new programming style, give useful tips, improve coding standards and so on. So, I hope you will find this collection useful in preparing your articles and books.