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 even if they dislike it.
This release features 6 months of work and changes from 46 different contributors, spread among 875 commits.
Special thanks to my sponsors who provide financial support. You're making Zig sustainable.
This release of Zig upgrades to LLVM 8. Zig operates in lockstep with LLVM; Zig 0.4.0 is not compatible with LLVM 7.
Notably this means that Zig now has WebAssembly Support, as well as recognizing the HermitCore and Hurd operating systems. On the other hand, support for the Nios II architecture is dropped, due to it being an experimental target which was largely unmaintained.
Marc Tiehuis started an initial FreeBSD branch. Greg V picked up the figurative baton in #1661, and Marcio Giaxa completed the effort.
Now, FreeBSD works in the stage1 C++ compiler code, as well as the Zig Standard Library, which means it now has Tier 2 Support. To achieve Tier 1 Support, these things are needed:
Despite these issues, thanks to SourceHut, FreeBSD does have some CI testing support, as well as automated binary builds available for x86_64 on the download page.
See #1759 for more details.
Maya Rashish ported the stage1 C compiler as well as the Zig Standard Library to be compatible with NetBSD. Have a look at their writeup: Porting Zig to NetBSD - a fun, speedy port
NetBSD is limited to Tier 2 Support due to lack of a continuous integration service, as well as a missing implementation of building the system's libc startup files lazily from source.
Now that Zig uses LLVM 8, the wasm32
target architecture is
guaranteed to be available in Zig.
Ben Noordhuis fixed zig build-exe
for the wasm32
target
(#1570).
Shritesh Bhattarai added --allow-undefined
and --export-all
to the wasm linker line, solving #1622.
There may be a better way to catch link errors in the future, but for now, this makes
WebAssembly work out-of-the-box in Zig:
extern fn print(i32) void;
export fn add(a: i32, b: i32) void {
print(a + b);
}
$ zig build-exe math.zig -target wasm32-freestanding
test.js
const fs = require('fs');
const source = fs.readFileSync("./math");
const typedArray = new Uint8Array(source);
WebAssembly.instantiate(typedArray, {
env: {
print: (result) => { console.log(`The result is ${result}`); }
}
}).then(result => {
const add = result.instance.exports.add;
add(1, 2);
});
$ node test.js
The result is 3
There is also the "WebAssembly System Interface" operating system target, wasi
.
I haven't really explored this use case yet, but I did make the C integer types work for it.
More research and exploration is needed.
Shawn Landden implemented arm64 Linux support in the Zig Standard Library, as well as the necessary stage1 C++ compiler changes.
The arm64-linux target has now graduated to Tier 2 Support. To achieve Tier 1 Support, we would need some way to run Continuous Integration tests on arm64 linux.
SourceHut has experimental arm64 Debian images, which may be worth looking into.
GitHub user nebulaeonline approached the Zig project with an interesting use case: creating a UEFI application.
nebulaeonline submitted a pull request adding UEFI as a new operating system that Zig recognizes. The patch contained the linker configuration and a few updates to the Zig Standard Library.
With this patch merged, nebulaeonline went on to work on their UEFI barebones project. It looks like they ended up using C rather than Zig in the end, most likely due to Zig's lack of maturity. Here I have linked to the last revision before they removed the Zig code, in case anyone wants to poke around. Since then Zig has gained C Pointers which was a large pain point for nebulaeonline.
Zig now uses a "support tier" system to communicate the level of support for different targets.
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.One of the main features of Zig is @cImport and C Translation. This is accomplished by linking against Clang libraries. Clang is a fully featured C and C++ compiler. Zig has all this functionality - so we may as well expose it!
The zig cc
command exposes clang, which you can see with this amusing output:
$ zig cc --version
clang version 8.0.0
...
zig cc
is a bit of a low level command. The higher level command line
interface --c-source
(or the corresponding Zig Build System API)
is recommended instead, for a few reasons:
zig cc
represents a fresh build of clang, which does not have such patches.
This is actually A Good Thing - more on this below.
--c-source
:-march=native
is enabled for the native target.-target
, --color
, and
--strip
will apply to both C and Zig Code.Here's an example of Zig building some C code:
hello.c
#include <stdio.h>
int main(int argc, char **argv) {
printf("Hello world\n");
return 0;
}
$ zig build-exe --c-source hello.c --library c
$ ./hello
Hello world
You can use --verbose-cc
to see what C compiler command this executed:
$ zig build-exe --c-source hello.c --library c --verbose-cc
zig cc -MD -MV -MF zig-cache/tmp/42zL6fBH8fSo-hello.o.d -nostdinc -fno-spell-checking -isystem /home/andy/dev/zig/build/lib/zig/include -isystem /home/andy/dev/zig/build/lib/zig/libc/include/x86_64-linux-gnu -isystem /home/andy/dev/zig/build/lib/zig/libc/include/generic-glibc -isystem /home/andy/dev/zig/build/lib/zig/libc/include/x86_64-linux-any -isystem /home/andy/dev/zig/build/lib/zig/libc/include/any-linux-any -march=native -g -fstack-protector-strong --param ssp-buffer-size=4 -fno-omit-frame-pointer -o zig-cache/tmp/42zL6fBH8fSo-hello.o -c hello.c -fPIC
Note that if I run the command again, there is no output, and it finishes instantly:
$ time zig build-exe --c-source hello.c --library c --verbose-cc
real 0m0.027s
user 0m0.018s
sys 0m0.009s
This is thanks to Build Artifact Caching. Zig automatically parses the .d file that clang produces and uses a robust caching system to avoid duplicating work.
In the Zig Build System, builder.addCExecutable
used to be a system C compiler driver. That functionality is deleted. Instead,
build scripts can attach C source files to any executable, library, or object
with foo.addCSourceFile
. You can see a nice example of
this in Michael Dusan's benchmark.unicode project.
Don't forget to use foo.linkSystemLibrary("c");
if the C code
expects to use libc.
You may have noticed that the
Zig-generated C compilation command included -nostdinc
.
This is a crucial step in the direction Zig is headed - providing consistent, reliable builds that are insulated from the system-specific differences in the wild.
This affects @cImport and
C Translation as well. By default, Zig no longer looks in
system paths for C header files, instead relying only on what Zig ships and what
users explicitly request with -isystem
.
However, when one uses the Zig Build System, and uses
linkSystemLibrary
API, Zig takes that as a hint to look in
system default search paths.
Marc Tiehuis proposed to expose this functionality to the command line interface,
and that is likely to be an accepted proposal.
Thanks to Akuli for adding /lib/x86_64-linux-gnu
or similar to default
system library search paths for zig build scripts.
One piece to this puzzle is that Zig now ships with libc. You can find the available
libc targets with zig targets
:
...
Available libcs:
aarch64_be-linux-gnu
aarch64_be-linux-musl
aarch64-linux-gnu
aarch64-linux-musleabi
armeb-linux-gnueabi
armeb-linux-gnueabihf
armeb-linux-musleabi
armeb-linux-musleabihf
arm-linux-gnueabi
arm-linux-gnueabihf
arm-linux-musleabi
arm-linux-musleabihf
i386-linux-gnu
i386-linux-musl
mips64el-linux-gnuabi64
mips64el-linux-gnuabin32
mips64el-linux-musl
mips64-linux-gnuabi64
mips64-linux-gnuabin32
mips64-linux-musl
mipsel-linux-gnu
mipsel-linux-musl
mips-linux-gnu
mips-linux-musl
powerpc64le-linux-gnu
powerpc64le-linux-musl
powerpc64-linux-gnu
powerpc64-linux-musl
powerpc-linux-gnu
powerpc-linux-musl
riscv32-linux-musl
riscv64-linux-gnu
riscv64-linux-musl
s390x-linux-gnu
s390x-linux-musl
sparc-linux-gnu
sparcv9-linux-gnu
x86_64-linux-gnu
x86_64-linux-gnux32
x86_64-linux-musl
What this means is that --library c
for these targets does not depend
on any system files!
Let's look at that C hello world example again:
$ zig build-exe --c-source hello.c --library c
$ ./hello
Hello world
$ ldd ./hello
linux-vdso.so.1 (0x00007ffd03dc9000)
libc.so.6 => /lib/libc.so.6 (0x00007fc4b62be000)
libm.so.6 => /lib/libm.so.6 (0x00007fc4b5f29000)
libpthread.so.0 => /lib/libpthread.so.0 (0x00007fc4b5d0a000)
libdl.so.2 => /lib/libdl.so.2 (0x00007fc4b5b06000)
librt.so.1 => /lib/librt.so.1 (0x00007fc4b58fe000)
/lib/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007fc4b6672000)
glibc does not support building statically, but musl does:
$ zig build-exe --c-source hello.c --library c -target x86_64-linux-musl
$ ./hello
Hello world
$ ldd hello
not a dynamic executable
In this example, Zig built musl libc from source and then linked against it. The build of musl libc for x86_64-linux remains available thanks to the caching system, so any time this libc is needed again it will be available instantly.
This means that this functionality is available on any platform. Windows and macOS users can build Zig and C code, and link against libc, for any of the targets listed above. Similarly code can be cross compiled for other architectures:
$ zig build-exe --c-source hello.c --library c -target aarch64v8-linux-gnu
$ file hello
hello: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 2.0.0, with debug_info, not stripped
In some ways, Zig is a better C compiler than C compilers!
This functionality is more than bundling a cross-compilation toolchain along with Zig. For example, the total size of libc headers that Zig ships is 22MiB uncompressed. Meanwhile, the headers for musl libc + linux headers on x86_64 alone are 8MiB, and for glibc are 3.1MiB (glibc is missing the linux headers), yet Zig currently ships with 40 libcs. With a naive bundling that would be 444MiB. However, thanks to this process_headers tool that I made, and some good old manual labor, Zig binary tarballs remain roughly 30MiB total, despite supporting libc for all these targets, as well as compiler-rt, libunwind, and libcxx, and despite being a clang-compatible C compiler. For comparison, the Windows binary build of clang 8.0.0 itself from llvm.org is 132MiB.
Note that only the Tier 1 Support targets have been thoroughly tested. It is planned to add more libcs (including for Windows), and to add test coverage for building against all the libcs. Support for building the FreeBSD libc startup files is the main feature needed to achieve Tier 1 Support for the target.
Thanks to Jay Weisskopf for helping with the glibc targets by removing an obsolete compat shim file.
Although Zig ships with libc for some targets, it still supports building against the system-native libc.
0.4.0 introduces a new command zig libc
which prints
the various paths of libc files. It outputs them to stdout
in a simple text file format that it is capable of parsing.
You can use zig libc libc.txt
to validate a file.
Here's what it looks like on my NixOS laptop:
$ zig libc
# The directory that contains `stdlib.h`.
# On POSIX-like systems, include directories be found with: `cc -E -Wp,-v -xc /dev/null`
include_dir=/nix/store/q2q1sg5sljia8sihhwcpbxir70yw33bw-glibc-2.27-dev/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=/nix/store/q2q1sg5sljia8sihhwcpbxir70yw33bw-glibc-2.27-dev/include
# The directory that contains `crt1.o`.
# On POSIX, can be found with `cc -print-file-name=crt1.o`.
# Not needed when targeting MacOS.
crt_dir=/nix/store/fivq0nbggp4y8mhy3ixprqd7qyn1hy2j-glibc-2.27/lib
# 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=
And here's what it looks like on my Windows laptop:
> zig.exe libc
# The directory that contains `stdlib.h`.
# On POSIX-like systems, include directories be found with: `cc -E -Wp,-v -xc /dev/null`
include_dir=C:\Program Files (x86)\Windows Kits\10\\Include\10.0.17134.0\ucrt
# 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=C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.15.26726\lib\x64\\..\..\include
# The directory that contains `crt1.o`.
# On POSIX, can be found with `cc -print-file-name=crt1.o`.
# Not needed when targeting MacOS.
crt_dir=C:\Program Files (x86)\Windows Kits\10\\Lib\10.0.17134.0\ucrt\x64\
# The directory that contains `vcruntime.lib`.
# Only needed when targeting MSVC on Windows.
msvc_lib_dir=C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.15.26726\lib\x64\
# The directory that contains `kernel32.lib`.
# Only needed when targeting MSVC on Windows.
kernel32_lib_dir=C:\Program Files (x86)\Windows Kits\10\\Lib\10.0.17134.0\um\x64\
These arguments are gone:
--libc-lib-dir [path] directory where libc crt1.o resides --libc-static-lib-dir [path] directory where libc crtbegin.o resides --msvc-lib-dir [path] (windows) directory where vcruntime.lib resides --kernel32-lib-dir [path] (windows) directory where kernel32.lib resides
Instead we have this argument:
--libc [file] Provide a file which specifies libc paths
This is used to pass a libc text file (which can be generated with
zig libc
). So it is easier to manage multiple cross compilation
environments.
When Zig must depend on the native libc installation, it first looks for
zig-cache/native_libc.txt
. If found, this file will be used. If this
file does not exist or has a parse error, Zig will perform native libc detection
and then overwrite this file. This can save time, because native libc detection can
be time consuming. For example it may need to invoke the system C compiler several
times to find out paths of things, or it may invoke some Windows COM API which is a bit
non-deterministic in terms of performance.
The --static
CLI option is removed and the -dynamic
option is added.
Instead of an explicit --static
flag, Zig makes things as static
as possible by default. Even zig build-lib
will now create a static
library by default, but -dynamic
can be used to choose a dynamic
library.
When targeting Linux, Zig now automatically links statically when not linking against
any shared libraries. It also disables Position Independent Code in this case, which
improves performance, especially with regards
to Thread-Local Variables. --enable-pic
and --disable-pic
can be used to override the default, but this
should be a rare use case.
Position Independent Code is also disabled by default for the freestanding OS target. When targeting Windows, Position Independent Code is always enabled.
It is proposed to rename these options to -fPIC
and -fno-PIC
to match C compilers.
For some use cases, it is known at compile-time that a given application or executable will never participate in multi-threading. For these use cases Zig has Single-Threaded Builds.
There is now a compile option --single-threaded
which has the following effects:
@import("builtin").single_threaded
becomes
true
and therefore various userland APIs which read this variable become more efficient:std.Mutex
becomes an empty data structure and all of its functions become no-ops.std.heap.ThreadSafeFixedBufferAllocator
alias std.heap.FixedBufferAllocator
when
--single-threaded
. #1910std.os.exit
use the
exit_group
syscall when not single-threaded.
The feature is exposed in the Zig Build System with
foo.single_threaded = true;
When one invokes the zig build
command, this executes a user-defined
build script. This is called the zig build system. It received
a few improvements during this release cycle.
Notably, Build Artifact Caching is enabled by default.
This means that by default build artifacts are now output into the
zig-cache
directory. The output path is not predictable and if the build
script desires to run an executable, rather than hard coding a path and using
builder.addCommand
, build scripts
must use executable.run
API, or addArtifactArg
.
An example of this can be found in the
tetris example.
builder.addSystemCommand
is available to run commands that are not
created by the build system itself. An example of this can be found in the
Raspberry Pi OS example.
Another option build scripts have is to specify the output directory of an artifact with
artifact.setOutputDir
. This disables caching and makes
artifact.getOutputPath
,
artifact.getOutputLibPath
, and
artifact.getOutputHPath
available.
Finally, the best way to make the output path of an artifact predictable is to install it with the build system's install step. There are some ergonomics and defaults to improve with this strategy, which will be tackled during the next release cycle.
Please note that Zig does no cache evicting yet. You may have to manually delete zig-cache directories periodically to keep disk usage down. It's planned for this to be a simple Least Recently Used eviction system eventually.
--output
, --output-lib
, and --output-h
are removed.
Instead, use --output-dir
which defaults to the current working directory.
Or take advantage of --cache on
, which will print the main output
path to stdout, and the other artifacts will be in the same directory
with predictable file names. --disable-gen-h
is available when
one wants to prevent .h file generation.
@cImport is always independently cached now.
It always writes the generated Zig code to disk which makes debug
info and compile errors better. No more "TODO: remember C source
location to display here" #2015.
The --verbose-cimport
command no longer dumps Zig AST to stderr; instead
it prints the file paths of the generated .zig files for inspection. In addition to
this improved behavior, the common case of @cImport
with all the
C header files unchanged is now fast due to being cached, yet still correct if any of
the C files change.
In addition, these improvements were made:
os_self_exe_path
to determine exe path not argv[0]
linkLibrary
will make the target depend on libc if the source does.builder.addFmt
API and use it to test stage1 zig fmt. #1968--static
. #2027zig build --help
more friendly. (#2194)LibExeObjStep.disable_gen_h
.
It is sometimes useful to skip generating of the header file (e.g.
#2173), and zig compiler
provides an option --disable-gen-h
to control that behaviour. However,
setting lib.disable_gen_h = true
in a typical build.zig
didn't append
the option to arguments. This commit fixes it and adds a convenient setDisableGenH
setter.
Zig comes with a robust caching system. When compiling Zig code, Zig knows all the files that
it depends on, and when compiling C code, Zig uses -MV -MD -MF
parameters to
Clang and then parses the generated .d file.
The other component of this is the "compiler id" concept:
$ zig id
Cxb7A-sAjt6VDq35pHZj3ACcwiSFqcCndt0NJkdQQlZVKolwm-QKnce1KEMUTqPr
This is the hash of the compiler binary itself, plus all the dynamic libraries it depends on,
directly or indirectly. That means if you fix a bug in memcpy
in the system libc,
Zig will detect this change and the value of zig id
will be different.
However, the value is quickly computed because it also participates in the caching system.
Here is a "manifest file" in the caching system for zig id
:
4850313<PHONE_NUMBER> 416647968 cOOP0xpsfiYfuMJCS3V_fLKdNmxFxLih_UACAUqwynGp1Y616NJ2lHL0hOpWOp_o /home/andy/dev/zig/build/zig
3077799 1 0 bBgfkt9ZSVN_HgBbzwHhzKmQxpssdDYq_HcbEkdu7KDcUhanATUER2_5l_U__9DE /nix/store/5dphwv1xs46n0qbhynny2lbhmx4xh1fc-zlib-1.2.11/lib/libz.so.1
1165671 1 0 jSVrSQyNkPFoz0Z6GesezdVP1ZBRpHL2UbbX7HbNEprcU4aBuIyG9z6bAOvvPZr0 /nix/store/fivq0nbggp4y8mhy3ixprqd7qyn1hy2j-glibc-2.27/lib/librt.so.1
1165626 1 0 scJm8rYLhDLp_SDXmbvdlcj9fEWQadEm_kHUBJn2oGnht3pSh2MNzsUJZjR1wwa1 /nix/store/fivq0nbggp4y8mhy3ixprqd7qyn1hy2j-glibc-2.27/lib/libdl.so.2
1165664 1 0 pGDNQn5x_j1NAWzjh4AOUP8OKyJj1KSPd4SJYzRVbTTp7TRb4IQpDs7ZAU3muqfz /nix/store/fivq0nbggp4y8mhy3ixprqd7qyn1hy2j-glibc-2.27/lib/libpthread.so.0
1165631 1 0 4tmxoKlbVwB42gYxT7B3CKIBXpbGdb_vuqfYiXlOZdyngmFJdQ7DBZxWqZKSO0Ss /nix/store/fivq0nbggp4y8mhy3ixprqd7qyn1hy2j-glibc-2.27/lib/libm.so.6
3077645 1 0 dxe6qw_yMCi8Bp7ocrVcl2XMdRlKfa0S3ATqbxsEMISRQdQ1dyxTEE1uDbv0R54z /nix/store/sf0wnp30savqz9ljn6fsrn8f63w5v0za-gcc-7.4.0-lib/lib/libstdc++.so.6
1165630 1 0 5boikua2jQubswAtj8MICJzjmGNUxTZrNreQm_DmtspgRsXULyCkyUUMYcNFamII /nix/store/fivq0nbggp4y8mhy3ixprqd7qyn1hy2j-glibc-2.27/lib/libgcc_s.so.1
1165616 1 0 qiXB510da3ryfL7LcPUvL2EQgY2tIwszLRvgQdDrQtnWVl4zA1Nfpq4SDpIz3IYW /nix/store/fivq0nbggp4y8mhy3ixprqd7qyn1hy2j-glibc-2.27/lib/libc.so.6
1165607 1 0 MpHwajxu3h0TtsHViKMAmHHeGMbi9IuDLlybX6PpqT66Xfa1h2GAT3XFIX19dEz- /nix/store/fivq0nbggp4y8mhy3ixprqd7qyn1hy2j-glibc-2.27/lib/ld-linux-x86-64.so.2
The fields are, respectively:
This same system is used for build artifact caching. For example, here is the manifest file
for hello world in Zig (when built with --cache on
):
5505089<PHONE_NUMBER> 204467480 rcnRrxBgZSiWki_XN9XKlQ2yfWkM6KLYhUWprzniEBtjgmeUSmtlv5mAguA4l2Q1 /home/andy/dev/zig/example/hello_world/hello.zig
4850617<PHONE_NUMBER> 0 GXP-IfocPj934vVJYrccBKIVoOcWULaUtkBoR-iHnEKEIoXtdchyuQi8tk8FTncS /home/andy/dev/zig/build/lib/zig/std/std.zig
5114024<PHONE_NUMBER> 0 6u-vFMcHH_FcfkAyqCcoYXAfF2TLMCkoP86Q3Ykecmage7_E4ObRsfP52-YXDHH6 /home/andy/dev/zig/build/lib/zig/std/special/panic.zig
4850617<PHONE_NUMBER> 0 GXP-IfocPj934vVJYrccBKIVoOcWULaUtkBoR-iHnEKEIoXtdchyuQi8tk8FTncS /home/andy/dev/zig/build/lib/zig/std/std.zig
4850277<PHONE_NUMBER> 0 9S5aQg0ORbkQnvDCVeW2aNPSeCu993I4iO3JoGrif4py7zBS4si4mCaeHHuo9TEn /home/andy/dev/zig/build/lib/zig/std/debug.zig
4849956<PHONE_NUMBER> 0 8c76uDlKxK5jZ1L0Uup4Lu0y1NlU5-KrUCKFyZnzoi7Hv3dDByN8pvujTjxjaf0m /home/andy/dev/zig/build/lib/zig/std/os.zig
4850678<PHONE_NUMBER> 0 wFvlet_2y9YT6NlFrsqybubwMafHFCIZqq4AxLlcUGuTSZ7VjI8kGmM-3VKPrhkt /home/andy/dev/zig/build/lib/zig/std/io.zig
5112957<PHONE_NUMBER> 0 f29y95JhSfGVwEFrutPnquGPPuvvtOLu6_vUUgGbaqn-9uulgFvBnyPU8Zp_sH7r /home/andy/dev/zig/build/lib/zig/std/os/file.zig
5113386<PHONE_NUMBER> 0 Mb9m-jj_wRe6yt-TFko9wUGNToAA-IAbVfmR2TYZyPjKP3D87df6BGALjai5uKr2 /home/andy/dev/zig/build/lib/zig/std/os/windows/util.zig
5113248<PHONE_NUMBER> 0 F1infSSAdOgbOWl3y2FdUiB-6xrpTaeqUJ5xt_F9IZOeBvvTSLNpkGEg8mrYMcli /home/andy/dev/zig/build/lib/zig/std/os/linux.zig
5113251<PHONE_NUMBER> 0 LAlDVvl1TX-3-SB3MOBBjxuEk2Ms8SpkcYBLXnJONgZuo7aV9OYfXLfih9bfGyBS /home/andy/dev/zig/build/lib/zig/std/os/linux/errno.zig
5113278<PHONE_NUMBER> 0 TpIIt3DNczfgMKjhDA5mx-4JgoGd7SIV9lXK8GQs9Bix4EmPiL7VlV1oQVwv4gkO /home/andy/dev/zig/build/lib/zig/std/os/linux/x86_64.zig
4849832<PHONE_NUMBER> 0 AszHJ9beyMCotgQx4vwYWMBUcRd1dBspsou64fATNYXsSqwB5zAiqVEokfpV5xkF /home/andy/dev/zig/build/lib/zig/std/fmt.zig
4850680<PHONE_NUMBER> 0 Polq06O1t-jJ0SobBVqLaQrJVXaKzH4lQj6Na8NRN3Y5N0pZ2I4W2rpwL816MSz- /home/andy/dev/zig/build/lib/zig/std/io/seekable_stream.zig
4850605<PHONE_NUMBER> 0 Al_VWoytLHeozYOvM69cCR2Dw1HGYdJc2lDGQDXYoiJy1VuD6GWLIQhxSJuf3Oza /home/andy/dev/zig/build/lib/zig/std/array_list.zig
4877695<PHONE_NUMBER> 0 ouDIQ9yX5LXanXk6mc2ypFP-oy2zEt7uLLlPDVUFEfx4AKmeFP1cJWI7YSjYAVt9 /home/andy/dev/zig/build/lib/zig/std/mem.zig
4850649<PHONE_NUMBER> 0 rVa_7s1plylcGIUAHEt3eGG8XwSJAEOQzuIaYcnq0KHnb1IoGWUEXUGIW7QHH7fi /home/andy/dev/zig/build/lib/zig/std/elf.zig
4849844<PHONE_NUMBER> 0 58Tg88pYb1sgK8SI5_65Gy7lgCqaJmsW2NV-Hi4FeXOK8e2f2T1PofNfdUDgbYit /home/andy/dev/zig/build/lib/zig/std/math.zig
4850647<PHONE_NUMBER> 0 9-R2p6FQ_7UIjQMt3N-chgeh-_e_o29Gr2Pybfh2PurmRYT9mIIwsdW9rs6kEJR8 /home/andy/dev/zig/build/lib/zig/std/dwarf.zig
5113295<PHONE_NUMBER> 0 6oc1oIiWQJ1OIZGh5KFPtul93GCeAaLFx2VTICI3JMt-Ubnj-vjXvBBclnoo5UQ6 /home/andy/dev/zig/build/lib/zig/std/os/path.zig
4850677<PHONE_NUMBER> 0 qom60op_QDptmhKO6SIlpm48SlVybcFOT0gHCjncJvtZhM6uUNqZZ2Q0WV5AsmRP /home/andy/dev/zig/build/lib/zig/std/heap.zig
4850683<PHONE_NUMBER> 0 6t3PH8KaWwsz2MElBWZezzyZyeRS-Ttq6k2pJWwRK__NvVQ2hZSu1gk4jA7oDT_Y /home/andy/dev/zig/build/lib/zig/std/linked_list.zig
4850685<PHONE_NUMBER> 0 EsROc7EV9MKNd74wRR9tYFhMGs4CL4eqYSPvJVzKTzSoXABBfxVoQwO3N_VivhNG /home/andy/dev/zig/build/lib/zig/std/macho.zig
4850663<PHONE_NUMBER> 0 oWDxArJXQLKaeAqd-Uf52hiAjktfqEhJA4XIdlBKCeKOxbYZosChXsfReGM0azCQ /home/andy/dev/zig/build/lib/zig/std/hash_map.zig
4877700<PHONE_NUMBER> 0 0SY3kFjpRYGQ1eVmh4UHluGBDFA9LcwANsSlEZLKfBO6hWxoZWcowtXk1SJvSALu /home/andy/dev/zig/build/lib/zig/std/pdb.zig
4850628<PHONE_NUMBER> 0 QEww1cNolzNrXqhOMV8uMTXRXQmbekZ7nyUaEqj35x6ZjO8BRVzqvYxQeSmW8c_5 /home/andy/dev/zig/build/lib/zig/std/coff.zig
4877702<PHONE_NUMBER> 0 9cFnTGm01DAKqMZim8dzEXoPyN8w3R8UAer53ycBv2PFgg-pM6AsNd6hDf0jlseT /home/andy/dev/zig/build/lib/zig/std/rand.zig
5113402<PHONE_NUMBER> 0 m2d1Awh2J4qJuWpBI5sEZJyszBZB2VIZlHvVpXZlt9Vz9JdjXvMN2Cig4ohevME_ /home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig
4877697<PHONE_NUMBER> 0 y2XL97U7jZ9PY4d5TVVZmBzYQc5wrCE_j_utDeU8zfLp5W6iLdFEf_HLbG4-W9Mf /home/andy/dev/zig/build/lib/zig/std/mutex.zig
4877707<PHONE_NUMBER> 0 jd03IjTqKqI-sTTbTTL63EjXX2xp9vPInAn4fA0rRis3TeXGgWnP-44_8N0OTRPP /home/andy/dev/zig/build/lib/zig/std/spinlock.zig
The way the cache checking works, is that it calls fstat
on all the files in the
manifest. For each file, if the inodes and mtimes from the manifest match the results from
fstat
, then the hash is trusted to be up-to-date for that particular file.
Any files with outdated hashes, have their contents hashed, and the manifest file updated
with the updated hashes. Finally, all the hashes are hashed together, and that final hash
is used as the directory name within zig-cache
that Zig looks for previously
created build artifacts.
Because Zig uses -MD -MF
args to clang when doing
@cImport
, Zig has a complete list of files that the C code read from,
which Zig adds to the cache. So even when using @cImport
,
Zig's caching system remains perfect. This is a proof of concept
for the mechanism that the self-hosted compiler
will use to watch and rebuild files.
There is one really fascinating problem to solve when relying on file modification times to determine whether a file's contents have changed. Some file systems, such as macOS's HFS+, do not support nanosecond precision; only seconds. However even nanosecond precision exhibits the problem for very fast systems.
Imagine that a file was modified, and then immediately after, added to the cache. When added to the manifest, the current time and the file's mtime will be the same. If the file is modified again quickly, and then the cache checked, it will still be the same instant in time; the modification to the file did not change the mtime.
There is a beautiful solution to this problem, which is to disqualify a file from being cached if the current time, truncated to the file system time granularity, matches the mtime:
// If the wall clock time, rounded to the same precision as the
// mtime, is equal to the mtime, then we cannot rely on this mtime
// yet. We will instead save an mtime value that indicates the hash
// must be unconditionally computed.
static bool is_problematic_timestamp(const OsTimeStamp *fs_clock) {
OsTimeStamp wall_clock = os_timestamp_calendar();
// First make all the least significant zero bits in the fs_clock, also zero bits in the wall clock.
if (fs_clock->nsec == 0) {
wall_clock.nsec = 0;
if (fs_clock->sec == 0) {
wall_clock.sec = 0;
} else {
wall_clock.sec &= (-1ull) << ctzll(fs_clock->sec);
}
} else {
wall_clock.nsec &= (-1ull) << ctzll(fs_clock->nsec);
}
return wall_clock.nsec == fs_clock->nsec && wall_clock.sec == fs_clock->sec;
}
What's beautiful about this is that it generalizes to any granularity. If a file system had a 1 day mtime granularity, then this would mean any files modified within 1 day would have to have their contents hashed, but files older than that could have their hashes trusted. If a file system always wrote 0 for the mtime, Zig would never trust it.
Thanks to apenwarr's insightful blog post about build system caching for inspiration.
The caching system is disabled by default for the command line interface, except for zig test
. zig test
does respect --output-dir
however, which disables caching.
The default caching behavior can be overridden with --cache [on|off]
.
The Zig Build System enables caching by default.
Caching is always enabled, using the global cache directory, when building libc and compiler-rt. This saves a considerable amount of accumulated time, since they must be available for every compilation.
Zig's compatibility with Valgrind has improved. Notably,
Valgrind 3.14 fixes
a bug where Zig programs' debug symbols
would not be detected. Because of this, the --no-rosegment
command line option is removed from Zig. It was only meant to be a temporary workaround.
Thanks to daurnimator for adding a valgrind module to the standard library. This allows Zig code to easily make Valgrind client requests.
In addition to userland API, Zig integrates more tightly with Valgrind. For example,
one thing that Zig does in Debug builds is
write 0xaa
bytes to undefined
variables:
undef.zig
const std = @import("std");
pub fn main() void {
var array: [10]u8 = undefined;
std.debug.warn("array: {x}\n", array);
}
$ zig build-exe undef.zig
$ ./undef
array: aaaaaaaaaaaaaaaaaaaa
Valgrind has detection for branching on undefined values, but if Zig was writing
0xaa
values to uninitialized variables, Valgrind would not know
that this is supposed to be an undefined canary. It would see the values as defined.
However thanks to integrated Valgrind client requests with the Zig language, Valgrind
knows what's going on:
undef.zig
const std = @import("std");
pub fn main() void {
var x: i32 = 1234;
std.debug.warn("x = {}\n", x);
x = undefined;
if (x > 10) {
std.debug.warn("greater than 10\n");
}
}
$ zig build-exe undef.zig
$ ./undef
x = 1234
When run in valgrind:
==16484== Conditional jump or move depends on uninitialised value(s)
==16484== at 0x224B6C: main (undef.zig:7)
==16484== by 0x22455A: posixCallMainAndExit (bootstrap.zig:86)
==16484== by 0x224350: _start (bootstrap.zig:43)
This is a debugging tool available in Zig that is not available in C -
setting things to undefined
so that Valgrind can
catch it if you accidentally use it.
Language integration with Valgrind is enabled by default in
Debug mode, and disabled by default in other
modes. The feature can be force enabled or force disabled with
--enable-valgrind
and --disable-valgrind
, respectively.
Also available is @import("builtin").valgrind_support
which is a
comptime
bool
available for code to
find out whether the programmer wants the executable to have Valgrind integration.
It's always disabled for compiler_rt and libc/builtin.
The cost of this feature is a few assembly instructions with each assignment to
undefined
. Only support for Linux, macOS, Solaris, and
MinGW on x86_64 is currently implemented.
zig fmt
is a tool to format your Zig code to a canonical style.
It's implemented in Zig and it's been available as a
self-hosted compiler subcommand for a while,
but the self-hosted compiler is not done yet and it's not what's available on
the download page.
Zig 0.4.0 ships with zig fmt
capabilities. Under the hood, it uses
zig run
and the Build Artifact Caching system, to lazily build
zig fmt
from source, and then run it.
That means even the stage1 C++ Zig compiler is a sort of hybrid - part C++, and part Zig.
Several editors have zig fmt
integration available, such as the
vim plugin that I use.
I believe the VSCode plugin does as well.
There is now has a --check
flag, which does everything
except modify file contents. That is, it lists non-conforming files on stdout,
and then exits with an error if the list is non-empty. #1558 #1555
Other improvements during this release cycle:
this
as a keyword since it was
removed in 0.3.0.There is also a discussion about whether or not to align struct fields, which has some interesting arguments on either side.
I have come up with a plan to migrate translate-c to userland:
This will allow us to move thousands of lines of C++ to Zig, and to only have to maintain one implementation of C translation rather than two. This same strategy could be used for other pieces of the Zig project, such as the package manager.
I started this effort with a proof of concept, but there is still a long way to go before this is done.
In addition the following improvements were made:
--verbose-cimport
prints clang commandassert
macro from glibc.Jimmi lead this effort. Starting with solving the return type ambiguity (#1628), he then moved on to create zig-spec, update the grammar section of the language reference, and update the stage1 parser to conform.
Thanks to his efforts, Zig syntax now has a formal grammar specification and three independent implementations, despite the fact that the syntax is not fully stablized.
The language reference manual. now has a light theme by default, but respects the user's light/dark preference via the prefers-color-scheme media query. Most browsers don't support this yet, so we just have to wait patiently for the future to arrive.
Instead of a side bar index, the index is inline with the rest of the content. This is simpler and more friendly to all user agents, and means we don't need the media query for mobile devices. It also makes back-references work, so now headers link to the table of contents and the table of contents links to headers.
Both of these things apply to this release notes document as well as the language reference manual.
There is still no HTML documentation available for the Zig Standard Library. See the Roadmap for more details.
The master branch language reference manual is now automatically updated on master branch commits that pass all tests on all platforms.
In addition to the above, the following changes were made to the documentation:
section
keyword to linksection
. #1152T
to *const T
. #1465
*T
to ?*const T
T
to ?*const T
when T
is a struct/union@minValue
,@maxValue
; add std.math.minInt
and std.math.maxInt
. #1466 #1476comptime
,
so function calls, for example, will be evaluated without the need for an explicit
comptime
block. Similarly:
**
and ++
operators force comptime
on operands. #1707@sizeOf(T)
or
@typeInfo(T).Int.bits
.
@sizeOf(T) >= @alignOf(T)
.
It also fixes std.mem.secureZero
for integers where this guarantee
previously was breached, and it fixes std.mem.Allocator
for integers
where this guarantee previously was breached. #1851 #1864union(enum)
. #1711usize
rather than a pointer.builtin.TypeInfo.ErrorSet
is now ?[]Error
instead of struct{errors:[]Error}
. #1936*const T
and ?*T
. #1298allowzero
pointer attribute. Only useful for
freestanding targets. Also adds safety for
@intToPtr when the address is zero. #1953All numbers with comptime known values now implicitly cast to all number types. If the value does not fit, a compile error is emitted.
comptime_ints.zig
const std = @import("std");
const assert = std.debug.assert;
test "implicit cast large integer to smaller with comptime value" {
const x: u64 = 255;
const y: u8 = x;
assert(y == 255);
}
$ zig test comptime_ints.zig
Test 1/1 implicit cast large integer to smaller with comptime value...OK
All tests passed.
Zig 0.4.0 ships with a new Vector type. This feature is brand new and not well documented yet. Here are some example tests:
vectors.zig
const std = @import("std");
const mem = std.mem;
const expect = std.testing.expect;
test "vector wrap operators" {
const S = struct {
fn doTheTest() void {
var v: @Vector(4, i32) = [4]i32{<PHONE_NUMBER>, -2, 30, 40 };
var x: @Vector(4, i32) = [4]i32{ 1,<PHONE_NUMBER>, 3, 4 };
expect(mem.eql(i32, ([4]i32)(v +% x), [4]i32{ -2147483648,<PHONE_NUMBER>, 33, 44 }));
expect(mem.eql(i32, ([4]i32)(v -% x), [4]i32{<PHONE_NUMBER>,<PHONE_NUMBER>, 27, 36 }));
expect(mem.eql(i32, ([4]i32)(v *% x), [4]i32{<PHONE_NUMBER>, 2, 90, 160 }));
var z: @Vector(4, i32) = [4]i32{ 1, 2, 3, -2147483648 };
expect(mem.eql(i32, ([4]i32)(-%z), [4]i32{ -1, -2, -3, -2147483648 }));
}
};
S.doTheTest();
comptime S.doTheTest();
}
test "vector int operators" {
const S = struct {
fn doTheTest() void {
var v: @Vector(4, i32) = [4]i32{ 10, 20, 30, 40 };
var x: @Vector(4, i32) = [4]i32{ 1, 2, 3, 4 };
expect(mem.eql(i32, ([4]i32)(v + x), [4]i32{ 11, 22, 33, 44 }));
expect(mem.eql(i32, ([4]i32)(v - x), [4]i32{ 9, 18, 27, 36 }));
expect(mem.eql(i32, ([4]i32)(v * x), [4]i32{ 10, 40, 90, 160 }));
expect(mem.eql(i32, ([4]i32)(-v), [4]i32{ -10, -20, -30, -40 }));
}
};
S.doTheTest();
comptime S.doTheTest();
}
test "vector float operators" {
const S = struct {
fn doTheTest() void {
var v: @Vector(4, f32) = [4]f32{ 10, 20, 30, 40 };
var x: @Vector(4, f32) = [4]f32{ 1, 2, 3, 4 };
expect(mem.eql(f32, ([4]f32)(v + x), [4]f32{ 11, 22, 33, 44 }));
expect(mem.eql(f32, ([4]f32)(v - x), [4]f32{ 9, 18, 27, 36 }));
expect(mem.eql(f32, ([4]f32)(v * x), [4]f32{ 10, 40, 90, 160 }));
expect(mem.eql(f32, ([4]f32)(-x), [4]f32{ -1, -2, -3, -4 }));
}
};
S.doTheTest();
comptime S.doTheTest();
}
test "vector bit operators" {
const S = struct {
fn doTheTest() void {
var v: @Vector(4, u8) = [4]u8{ 0b10101010, 0b10101010, 0b10101010, 0b10101010 };
var x: @Vector(4, u8) = [4]u8{ 0b11110000, 0b00001111, 0b10101010, 0b01010101 };
expect(mem.eql(u8, ([4]u8)(v ^ x), [4]u8{ 0b01011010, 0b10100101, 0b00000000, 0b11111111 }));
expect(mem.eql(u8, ([4]u8)(v | x), [4]u8{ 0b11111010, 0b10101111, 0b10101010, 0b11111111 }));
expect(mem.eql(u8, ([4]u8)(v & x), [4]u8{ 0b10100000, 0b00001010, 0b10101010, 0b00000000 }));
}
};
S.doTheTest();
comptime S.doTheTest();
}
$ zig test vectors.zig
Test 1/4 vector wrap operators...OK
Test 2/4 vector int operators...OK
Test 3/4 vector float operators...OK
Test 4/4 vector bit operators...OK
All tests passed.
Note that Zig of course supports vectors at comptime
and likewise
all the safety features of arithmetic operators are available for vectors as well.
Vectors provide a way to do Single Instruction Multiple Data in a portable and efficient way. It's much easier for the optimizer to break vectors into scalars than it is to turn scalars into vectors. Even in debug builds which have safety checks, vector operations provide more data throughput than scalar operations.
Thanks to Jimmi Holst Christensen for many contributions to vector support.
To follow progress on vectors and SIMD in Zig, watch issue #903.
Zig's comptime
facilities are improved to support
reinterpreting memory, as long as the types in question have guaranteed
in-memory representation.
bitcast.zig
const builtin = @import("builtin");
const std = @import("std");
const expect = std.testing.expect;
test "@bitCast extern structs at runtime and comptime" {
const Full = extern struct {
number: u16,
};
const TwoHalves = extern struct {
half1: u8,
half2: u8,
};
const S = struct {
fn doTheTest() void {
var full = Full{ .number = 0x1234 };
var two_halves = @bitCast(TwoHalves, full);
switch (builtin.endian) {
builtin.Endian.Big => {
expect(two_halves.half1 == 0x12);
expect(two_halves.half2 == 0x34);
},
builtin.Endian.Little => {
expect(two_halves.half1 == 0x34);
expect(two_halves.half2 == 0x12);
},
}
}
};
S.doTheTest();
comptime S.doTheTest();
}
test "reinterpret bytes of an array into an extern struct" {
testReinterpretBytesAsExternStruct();
comptime testReinterpretBytesAsExternStruct();
}
fn testReinterpretBytesAsExternStruct() void {
var bytes align(2) = []u8{ 1, 2, 3, 4, 5, 6 };
const S = extern struct {
a: u8,
b: u16,
c: u8,
};
var ptr = @ptrCast(*const S, &bytes);
var val = ptr.c;
expect(val == 5);
}
$ zig test bitcast.zig
Test 1/2 @bitCast extern structs at runtime and comptime...OK
Test 2/2 reinterpret bytes of an array into an extern struct...OK
All tests passed.
These examples work because extern struct
and packed struct
have guaranteed in-memory layout.
In addition, as long as the memory is never accessed, pointers with hard coded addresses
and pointer arithmetic are supported at comptime
:
comptime_ptrs.zig
const std = @import("std");
const expect = std.testing.expect;
test "C pointer comparison and arithmetic" {
const S = struct {
fn doTheTest() void {
var one: usize = 1;
var ptr1: [*c]u32 = 0;
var ptr2 = ptr1 + 10;
expect(ptr1 == 0);
expect(ptr1 >= 0);
expect(ptr1 <= 0);
expect(ptr1 < 1);
expect(ptr1 < one);
expect(1 > ptr1);
expect(one > ptr1);
expect(ptr1 < ptr2);
expect(ptr2 > ptr1);
expect(ptr2 >= 40);
expect(ptr2 == 40);
expect(ptr2 <= 40);
ptr2 -= 10;
expect(ptr1 == ptr2);
}
};
S.doTheTest();
comptime S.doTheTest();
}
$ zig test comptime_ptrs.zig
Test 1/1 C pointer comparison and arithmetic...OK
All tests passed.
A variable may be specified to be a thread-local variable using the
threadlocal
keyword:
tls.zig
const std = @import("std");
const assert = std.debug.assert;
threadlocal var x: i32 = 1234;
test "thread local storage" {
const thread1 = try std.os.spawnThread({}, testTls);
const thread2 = try std.os.spawnThread({}, testTls);
testTls({});
thread1.wait();
thread2.wait();
}
fn testTls(context: void) void {
assert(x == 1234);
x += 1;
assert(x == 1235);
}
$ zig test tls.zig
Test 1/1 thread local storage...OK
All tests passed.
For Single-Threaded Builds, all thread local variables are treated as Global Variables.
Thread local variables may not be const
.
Note that thread local variables have better performance for non- position independent code, which is one reason for Static by Default.
Thanks to Rich Felker from the musl libc project, who gave me this crucial information, when I was implementing thread local storage for static builds:
to satisfy the abi, your init code has to write the same value to that memory location as the value passed to the [arch_prctl] syscall
This deletes some legacy cruft, and produces leaner object files. Example:
var x: i32 = 1234;
export fn entry() i32 {
return x;
}
This produced:
@x = internal unnamed_addr global i32 1234, align 4
@0 = internal unnamed_addr constant i32* @x, align 8
and @0 was never even used. After Zig 0.4.0, @0 is not produced.
This fixes a bug: Zig was creating invalid LLVM IR when one of these globals that shouldn't exist takes the address of a thread local variable. In LLVM 8, it would produce a linker error. But probably after my bug report is solved it will be caught by the IR verifier.
Thanks to Rui Ueyama and George Rimar who helped me troubleshoot this problem when I filed an LLVM bug report.
One of the use cases of Zig is to beat C at its own game, and this means being a better
language for using C libraries than C is.
It's a tall order to fulfill, and it was compromised by Zig's
pointer reform. An unfortunate
side effect of having more type safety in pointer types was that C's very unsafe pointer types
became awkward to use. It is ambiguous whether pointers should be translated as
single-item pointers (*T
) or unknown-length pointers ([*]T
).
C Pointers are a compromise so that Zig code can utilize translated header files directly.
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.
[*c]T
- C pointer.
?usize
. Note that creating an optional C pointer
is unnecessary as one can use normal Optional Pointers.
It's planned to support `if`, `orelse`, `null`, and `.?` for C pointers.
While C pointers themselves have all the footguns associated with, well, C pointers, there is safety when converting to Zig pointers:
test.zig
test "cast null C pointer to Zig pointer" {
var c_ptr: [*c]i32 = 0;
var zig_ptr: *i32 = c_ptr;
}
$ zig test test.zig
Test 1/1 cast null C pointer to Zig pointer...cast causes pointer to be null
/home/andy/dev/www.ziglang.org/docgen_tmp/test.zig:3:25: 0x2040f1 in ??? (test)
var zig_ptr: *i32 = c_ptr;
^
/home/andy/dev/zig/build/lib/zig/std/special/test_runner.zig:13:25: 0x225bdb in ??? (test)
if (test_fn.func()) |_| {
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:122:22: 0x225366 in ??? (test)
root.main() catch |err| {
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:43:5: 0x2250d1 in ??? (test)
@noInlineCall(posixCallMainAndExit);
^
Tests failed. Use the following command to reproduce the failure:
/home/andy/dev/www.ziglang.org/docgen_tmp/test
In Zig 0.3.0, @typeOf(@import("builtin"))
is (import)
,
which was a special "namespace" type. In Zig 0.4.0,
@typeOf(@import("builtin"))
is type
.
The special "namespace" type is removed; instead all files are structs with no fields.
This makes the language smaller and simpler, and makes imported files easier to inspect with reflection, since they are structs.
With this change, struct types get fully qualified names and function symbol names
become fully qualified. This means that when using zig test
it's no longer
necessary to manually namespace test names as they will be automatically namespaced.
There is a new compile error for importing a file outside the package path.
The new CLI option --main-pkg-path
can be used to choose
a different root package directory besides the one inferred from the
root source file. The corresponding Zig Build System API is
artifact.setMainPkgPath(path)
.
Zig has a new type to make dealing with enums more attractive. It can be thought of as the
enum
equivalent of comptime_int
. The enum
equivalent of a number literal.
enum-lit.zig
const std = @import("std");
pub fn main() void {
print(1234, .hex);
print(1234, .normal);
}
fn print(x: i32, mode: enum { normal, hex }) void {
switch (mode) {
.normal => std.debug.warn("{}\n", x),
.hex => std.debug.warn("0x{x}\n", x),
}
}
$ zig build-exe enum-lit.zig
$ ./enum-lit
0x4d2
1234
Here you can see an anonymous
enum
was used rather than an opaque bool
parameter.
The idea here is to make it so easy to have meaningful values, that programmers will want
to use them, even if they're feeling lazy.
The ergonomics of this feature feel great. Here's tgschultz updating some of the standard library API to use anonymous enum literals.
Note that this feature is checked by the compiler. It's completely safe:
test.zig
const std = @import("std");
test "invalid enum literal" {
print(1234, .hex);
print(1234, .invalid);
}
fn print(x: i32, mode: enum { normal, hex }) void {
switch (mode) {
.normal => std.debug.warn("{}\n", x),
.hex => std.debug.warn("0x{x}\n", x),
}
}
$ zig test test.zig
/home/andy/dev/www.ziglang.org/docgen_tmp/test.zig:5:17: error: enum 'enum:8:24' has no field named 'invalid'
print(1234, .invalid);
^
/home/andy/dev/www.ziglang.org/docgen_tmp/test.zig:8:24: note: 'enum:8:24' declared here
fn print(x: i32, mode: enum { normal, hex }) void {
^
std.debug.failing_allocator
is now a *Allocator
rather than the FailingAllocator
state. -Jimmi Holst Christensenstd.event.tcp
to std.event.net
.std.io.FileInStream
to std.os.File.InStream
std.io.FileInStream.init(file)
to file.inStream()
std.io.FileOutStream
to std.os.File.OutStream
std.io.FileOutStream.init(file)
to file.outStream()
std.event.net.socketRead
to std.event.net.read
std.event.net.socketWrite
to std.event.net.write
std.event.net.readv
std.event.net.writev
std.event.net.readvPosix
std.event.net.writevPosix
std.event.net.OutStream
std.event.net.InStream
std.event.io.InStream
std.event.io.OutStream
std.io.InStream.read
now can return less than buffer sizestd.io.InStream.readFull
for previous behaviorstd.os.File.openWriteNoClobberC
std.os.deleteFileWindows
to std.os.deleteFileW
std.os.deleteFilePosix
std.os.deleteFileC
std.os.copyFile
no longer takes an allocatorstd.os.copyFileMode
no longer takes an allocatorstd.os.AtomicFile
no longer takes an allocatorstd.os.renameW
std.os.renameC
std.os.linux.vfork
and std.os.linux.exit_group
std.os.time.sleep(seconds: usize, nanoseconds: usize)
to (nanoseconds: u64)
. -Marc Tiehuisstd.math.maxInt
and std.math.minInt
std.crypto.HmacBlake2s256
std.net.Address.port
-Josh Wolfestd.io.NullOutStream
and std.io.CountingOutStream
-Jimmi Holst Christensenstd.io.InStream(E).readStruct
returns a value instead of taking a pointer. -Jimmi Holst Christensenstd.atomic.Int.set
. -Josh Wolfestd.meta.intToEnum
.std.rand.Rand
API to better handle the
concept of bias. -Josh Wolfestd.rand.Rand.uintLessThanBiased
std.rand.Rand.uintAtMostBiased
std.rand.Rand.intRangeLessThanBiased
std.rand.Rand.intRangeAtMostBiased
std.HashMap.getOrPutValue
. -Jimmi Holst Christensenstd.io.readLine
std.io.readLine
has a new prototypestd.io.readLineFrom
std.io.readLineSlice
std.io.readLineSliceFrom
std.io.SeekableStream
. Dwarf debug info
is modified to use this instead of std.os.File
directly to make it easier for
bare metal projects to take advantage of debug info parsing.std.debug.StackIterator
.error.DeviceBusy
as a possible result of std.os.posixOpen
. I observed EBUSY
when trying to open for writing a tty fd that is already opened with screen.std.debug.assert
no longer has special behavior for test builds.
Use std.testing.expect
to detect test failures in a way that will
work in release builds. See assert vs expect.
std.mem.Allocator.create
is removed.
std.mem.Allocator.createOne
is renamed to
std.mem.Allocator.create
.
The problem with the previous API is that even after copy elision,
the initalization value passed as a parameter would always be a copy.
With the new API, once copy elision is done, initialization
functions can directly initialize allocated memory in place. #1872 #1873
std.mem.split
is removed.
std.mem.separate
and std.mem.tokenize
are added.
std.fmt.parseFloat
.
This is not intended to be the long-term implementation as it doesn't
provide various properties that we eventually will want (e.g.
round-tripping, denormal support). It also uses f64
internally so the
wider f128
will be inaccurate. See #2207 for robust float parsing
in the Zig Standard Library.std.PriorityQueue
.std.os.posixMProtect
.std.os.changeCurDir
no longer has an allocator parameter.std.ascii
. Rohlem
added test coverage and fixed the logic.std.math.mulWide
.std.crypto.HmacBlake2s256
.SegmentedList.shrink
.std.io.Serializer
.std.io.Deserializer
.std.io.BitInStream
.std.io.BitOutStream
.std.meta.TagPayloadType
.std.meta.trait.isUnsignedInt
.std.meta.trait.isSignedInt
.std.meta.stringToEnum
std.mem.separate
vs std.mem.tokenize
.std.math.IntFittingRange
.std.LinkedList.concat
.std.meta
- helper functions for doing reflection. #1662Previously, std.debug.assert
would
@panic in test builds,
if the assertion failed. Now, it's always unreachable
.
This makes release mode test builds more accurately test the actual code that will be run.
However this requires tests to call std.testing.expect
rather than std.debug.assert
to make sure output is correct.
Here is the explanation of when to use either one, copied from the assert doc comments:
Inside a test block, it is best to use the std.testing
module
rather than assert, because assert may not detect a test failure
in ReleaseFast and
ReleaseSmall modes.
Outside of a test block, assert is the correct function to use.
See #1304.
Zig code can use std.debug.captureStackTrace
at any time
for debugging purposes:
stack-traces.zig
const std = @import("std");
const builtin = @import("builtin");
var address_buffer: [8]usize = undefined;
var trace1 = builtin.StackTrace{
.instruction_addresses = address_buffer[0..4],
.index = 0,
};
var trace2 = builtin.StackTrace{
.instruction_addresses = address_buffer[4..],
.index = 0,
};
pub fn main() void {
foo();
bar();
std.debug.warn("first one:\n");
std.debug.dumpStackTrace(trace1);
std.debug.warn("\n\nsecond one:\n");
std.debug.dumpStackTrace(trace2);
}
fn foo() void {
std.debug.captureStackTrace(null, &trace1);
}
fn bar() void {
std.debug.captureStackTrace(null, &trace2);
}
$ zig build-exe stack-traces.zig
$ ./stack-traces
first one:
/home/andy/dev/www.ziglang.org/docgen_tmp/stack-traces.zig:27:32: 0x22586d in ??? (stack-traces)
std.debug.captureStackTrace(null, &trace1);
^
/home/andy/dev/www.ziglang.org/docgen_tmp/stack-traces.zig:17:8: 0x225819 in ??? (stack-traces)
foo();
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:112:22: 0x22528b in ??? (stack-traces)
root.main();
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:43:5: 0x225081 in ??? (stack-traces)
@noInlineCall(posixCallMainAndExit);
^
second one:
/home/andy/dev/www.ziglang.org/docgen_tmp/stack-traces.zig:31:32: 0x22588d in ??? (stack-traces)
std.debug.captureStackTrace(null, &trace2);
^
/home/andy/dev/www.ziglang.org/docgen_tmp/stack-traces.zig:18:8: 0x22581e in ??? (stack-traces)
bar();
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:112:22: 0x22528b in ??? (stack-traces)
root.main();
^
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:43:5: 0x225081 in ??? (stack-traces)
@noInlineCall(posixCallMainAndExit);
^
This feature is used in the GeneralPurposeDebugAllocator project for helping detect and diagnose memory issues.
Zig 0.4.0 brings breaking changes to the std.mem.Allocator
interface
and API.
Before, allocator implementations had to provide allocFn
,
reallocFn
, and freeFn
.
Now, they must provide only reallocFn
and shrinkFn
.
Reallocating from a zero length slice is allocation, and
shrinking to a zero length slice is freeing.
When the new memory size is less than or equal to the
previous allocation size, reallocFn
now has the option
to return error.OutOfMemory
to indicate that the allocator
would not be able to take advantage of the new size.
For more details see #1306.
I have reproduced the documentation comments here:
pub const Allocator = struct {
pub const Error = error{OutOfMemory};
/// Realloc is used to modify the size or alignment of an existing allocation,
/// as well as to provide the allocator with an opportunity to move an allocation
/// to a better location.
/// When the size/alignment is greater than the previous allocation, this function
/// returns `error.OutOfMemory` when the requested new allocation could not be granted.
/// When the size/alignment is less than or equal to the previous allocation,
/// this function returns `error.OutOfMemory` when the allocator decides the client
/// would be better off keeping the extra alignment/size. Clients will call
/// `shrinkFn` when they require the allocator to track a new alignment/size,
/// and so this function should only return success when the allocator considers
/// the reallocation desirable from the allocator's perspective.
/// As an example, `std.ArrayList` tracks a "capacity", and therefore can handle
/// reallocation failure, even when `new_n` <= `old_mem.len`. A `FixedBufferAllocator`
/// would always return `error.OutOfMemory` for `reallocFn` when the size/alignment
/// is less than or equal to the old allocation, because it cannot reclaim the memory,
/// and thus the `std.ArrayList` would be better off retaining its capacity.
/// When `reallocFn` returns,
/// `return_value[0..min(old_mem.len, new_byte_count)]` must be the same
/// as `old_mem` was when `reallocFn` is called. The bytes of
/// `return_value[old_mem.len..]` have undefined values.
/// The returned slice must have its pointer aligned at least to `new_alignment` bytes.
reallocFn: fn (
self: *Allocator,
/// Guaranteed to be the same as what was returned from most recent call to
/// `reallocFn` or `shrinkFn`.
/// If `old_mem.len == 0` then this is a new allocation and `new_byte_count`
/// is guaranteed to be >= 1.
old_mem: []u8,
/// If `old_mem.len == 0` then this is `undefined`, otherwise:
/// Guaranteed to be the same as what was returned from most recent call to
/// `reallocFn` or `shrinkFn`.
/// Guaranteed to be >= 1.
/// Guaranteed to be a power of 2.
old_alignment: u29,
/// If `new_byte_count` is 0 then this is a free and it is guaranteed that
/// `old_mem.len != 0`.
new_byte_count: usize,
/// Guaranteed to be >= 1.
/// Guaranteed to be a power of 2.
/// Returned slice's pointer must have this alignment.
new_alignment: u29,
) Error![]u8,
/// This function deallocates memory. It must succeed.
shrinkFn: fn (
self: *Allocator,
/// Guaranteed to be the same as what was returned from most recent call to
/// `reallocFn` or `shrinkFn`.
old_mem: []u8,
/// Guaranteed to be the same as what was returned from most recent call to
/// `reallocFn` or `shrinkFn`.
old_alignment: u29,
/// Guaranteed to be less than or equal to `old_mem.len`.
new_byte_count: usize,
/// If `new_byte_count == 0` then this is `undefined`, otherwise:
/// Guaranteed to be less than or equal to `old_alignment`.
new_alignment: u29,
) []u8,
};
This allows allocators and data structures to "negotiate" with each other. For example,
here is std.ArrayList.shrink
:
pub fn shrink(self: *Self, new_len: usize) void {
assert(new_len <= self.len);
self.len = new_len;
self.items = self.allocator.realloc(self.items, new_len) catch |e| switch (e) {
error.OutOfMemory => return, // no problem, capacity is still correct then.
};
}
I am pleased to announce our newest Zig team member, Antoine Vugliano.
He has shown continued dedication and discipline in his contributions to the Zig programming language project. The quality of his work speaks for itself.
I look forward to working with Antoine as we continue to push Zig toward 1.0.0 and beyond.
Thanks to Jeff Fowler for creating sublime-zig-language and for creating the pull request to GitHub to add support for Zig.
Finally, GitHub decided that Zig is popular enough to gain official recognition.
As a fun last step, Marc Tiehuis marked third-party dependencies as vendored, so that we can have this pretty language bar on GitHub:
Now you can discover Zig projects on GitHub via their "trending" web page.
std.os.AtomicFile
std.Mutex
now has a high quality Linux implementation based on
Ulrich Drepper's "Futexes are tricky" paper, Mutex, Take 3.
Thanks to Shawn Landden for the original implementation. #1463ar
.
#1493 #54
posix_spawn
rather than
fork
and execv
. The logic is simplified and the memory usage
is more deterministic.
std.rand.Rand
: better debiased random range implementation. -Josh Wolfeu0
value to any integer type, and the result is always
comptime known to be 0
.std.fmt.formatType
can now format comptime_int -Jimmi Holst Christensen
std.fmt.format
can now format function pointers -Jimmi Holst Christensen
f128
and narrowing casts to f16
from larger float types.f128
support for fabs, isinf, isnan, inf and nan functions.std.json
.std.os.getBaseAddress
for objects and libraries on macOS.
See #1878. This removed the workaround in example/shared_library/mathtest.zig. Along the way
these fixes were made:-target [name]
instead of --target-*
args.
This matches clang's command line interface.builtin.Environ
renamed to builtin.Abi
;
likewise builtin.environ
renamed to
builtin.abi
.zig targets
only shows available targets. #438zig targets
but note they are Tier 4 Support.comptime_int
.popcountdi2
to compiler_rtstd.fmt.formatIntUnsigned
. #1358null
. #2104memcmp
to builtins.std.mem.join
and std.os.path.join
use a slice parameter rather than var args.std.rb
to conform to the
style guide.__modti3
to compiler-rt. #1290std.math.isnan
to use x != x
rather than looking at the bits.comptime_int
in
std.fmt.formatInt
and std.fmt.formatValue
.and
and or
when &&
and ||
are used.std.fmt.parseUnsigned
handle types less than 8 bits wide.std.Mutex
implementation for Windows.Function type mismatches now have an error note which explains in more detail why the function types were incompatible:
test.zig
fn do_the_thing(func: fn (arg: i32) void) void {}
fn bar(arg: bool) void {}
test "fn types" {
do_the_thing(bar);
}
$ zig test test.zig
/home/andy/dev/www.ziglang.org/docgen_tmp/test.zig:4:18: error: expected type 'fn(i32) void', found 'fn(bool) void'
do_the_thing(bar);
^
/home/andy/dev/www.ziglang.org/docgen_tmp/test.zig:4:18: note: parameter 0: 'bool' cannot cast into 'i32'
do_the_thing(bar);
^
std.math.atan2
.comptime
-known to be 0 when destination integer type has 0 bits.
If the destination type is a comptime_int
, treat it as an Implicit Cast. #1568@import("builtin")
and then used to do an implicit cast of the panic
function to this prototype, rather than redoing all the implicit cast logic. #1894 #1895handle_is_ptr
. #991 #1934use
. #1557bigint_append_buf
. All current usages had base 10
and a limb length of 2, hence why we weren't hitting this error in practice.std.json.pushToParent
to work for arrays of Objects--
double-hyphen is now used to end further zig processing
of command line options. All arguments after --
will be passed
on to the executable. eg. --help
will be passed on:
zig run foo.zig -- --help
*const T
to *[1]T
based on a patch
from kristopher tate.for
loop. #1726std.HashMap.remove
returning invalid memory.
std.BufSet
and std.BufMap
where delete would free a still in-use KV and leave
the actually removed KV un-free'd.std.os.File.openWriteNoClobber
and added test coverage.Zig has known bugs.
The first release that will ship with no known bugs will be 1.0.0.
Here is the roadmap from 0.3.0 release notes:
I am sad to report that this list was too ambitious for one release cycle, and while there has been considerable progress, none of these items are complete. And so the roadmap for 0.4.0 is the same.
It's no longer planned for Zig to have Type Based Alias Analysis. However, there are some open research topics on potentially outlawing all kinds of aliasing unless explicitly declared. Subscribe to #1108 for more details.
For now, Zig has a well-defined memory model, and aliasing is always allowed. Note, however, that not all types have a guaranteed in-memory layout.
Linking macOS/COFF files is still in a sad state. The Mach-O code in LLD, Zig's linker, has been barely maintained for several years now. Zig has a fork of LLD in its source tree with a hacky patch to fix linking "Hello World" on macOS.
It's now planned for the Zig project to have its own linker. This is in part due to the lack of Mach-O maintenance, and in part because LLD has no plans to do incremental linking - a feature that I foresee to be necessary to achieve the performance we want to have for large projects in the self-hosted compiler.
For now the self-hosted compiler uses --system-linker-hack
to be able to link successfully, which is a compromise of Zig's promise that it can build
on any target, for any target.
There is also a workaround in the linker phase of Zig for compiler-rt.a and builtin.a. I had to make them object files rather than archive files to avoid crashing LLD.
There has been no progress on the self-hosted compiler in this release cycle. Progress is blocked on the volume of core language changes still happening, as well as no-copy semantics, and Reworking Coroutines.
The package manager will be one of the focus areas of the 0.5.0 release cycle. It depends on networking, which depends on Reworking Coroutines, which depends on no-copy semantics.
There is no progress on coroutines in this release cycle. In fact there has been anti-progress.
Zig 0.4.0 introduces a memory leak to all coroutines.
There is an issue where a coroutine calls the function and it
frees its own stack frame, but then the return value of shrinkFn
is a slice, which is implemented as an sret struct. Writing to
the return pointer causes invalid memory write. We could work
around it by having a global helper function which has a void
return type and calling that instead. But instead this hack will
suffice until I rework coroutines to be non-allocating. Basically
coroutines are not supported right now until they are reworked as
in #1194.
Reworking coroutines is to be a major focus of 0.5.0 as it is blocking networking, the Package Manager, and the Self-Hosted Compiler.
Here is a small selection of interesting proposals that have been accepted, to give you an idea of the upcoming changes to Zig.
Full list of accepted proposals
Special thanks to those who donate monthly. Thanks to you, Zig is not driven by the needs of a business; instead it exists solely to serve the open source community.


Hello
...welcome...
(once again)
...to revealm
(Yes this used to be a talk about Elm)
type Maybe a = Nothing | Just a


Pan Australian Airways
Webhook Registration
Success
Webhook Registered
Danger
Please check the log files
Enter your Webhook URI
Your webhook URI will not be shared
Webhook Type
Price Change
Seat availability
Flight Delays & Disruptions
Register


features¶
what does Sol (and other libraries) support?
The goal of Sol is to provide an incredibly clean API that provides high performance (comparable or better than the C it was written on) and extreme ease of use. That is, users should be able to say: “this works pretty much how I expected it to.”
For the hard technical components of Lua and its ecosystem we support, here is the full rundown:
what Sol supports¶
Support for Lua 5.1, 5.2, and 5.3+ and LuaJIT 2.0.4 + 2.1.x-beta3+. We achieve this through our compatibility header.
- Table support: setting values, getting values of multiple (different) types
- Lazy evaluation for nested/chained queries
table["a"]["b"]["c"] = 24;
- Implicit conversion to the types you want
double b = table["computed_value"];
- Optional support: setting values, getting values of multiple (different) types
- Lazy evaluation for nested/chained queries
optional<int> maybe_number = table["a"]["b"]["invalid_key"];
Turns on safety when you want it: speed when you don’t
- Support for callables (functions, lambdas, member functions)
Pull out any Lua function with sol::function:
sol::function fx = table["socket_send"];
Can also set callables into operator[] proxies:
table["move_dude"] = &engine::move_dude;
- Safety: use sol::protected_function to catch any kind of error
ANY kind: C++ exception or Lua erors are trapped and run through the optional
error_handler
variable
Advanced: overloading of a single function name so you don’t need to do boring typechecks
Advanced: efficient handling and well-documented way of dealing with arguments
- User-Defined Type (sol::usertype in the API) support:
Set member functions to be called
Set member variables
Set variables on a class that are based on setter/getter functions
Use free-functions that take the Type as a first argument (pointer or reference)
Support for “Factory” classes that do not expose constructor or destructor
Modifying memory of userdata in C++ directly affects Lua without copying, and
- Modifying userdata in Lua directly affects C++ references/pointers
my_class& a = table["a"];
my_class* a_ptr = table["a"];
- If you want a copy, just use value semantics and get copies:
my_class a = table["a"];
- Thread/Coroutine support
Use, resume, and play with coroutines like regular functions
Get and use them even on a separate Lua thread
Monitor status and get check errors
Advanced: Customizable and extensible to your own types if you override getter/pusher/checker template struct definitions.
The Feature Matrix™¶
The below feature table checks for the presence of something. It, however, does not actually account for any kind of laborious syntax.
✔ full support: works as you’d expect (operator[] on tables, etc…)
~ partial support / wonky support: this means its either supported through some other fashion (not with the desired syntax, serious caveats, etc.). Sometimes means dropping down to use the plain C API (at which point, what was the point of the abstraction?).
✗ no support: feature doesn’t work or, if it’s there, it REALLY sucks to use
Implementation notes from using the libraries are below the tables.
category explanations¶
Explanations for a few categories are below (rest are self-explanatory).
optional: Support for getting an element, or potentially not (and not forcing the default construction of what amounts to a bogus/dead object). Usually comes with
std(::experimental)::optional
. It’s a fairly new class, so a hand-rolled class internal to the library with similar semantics is also acceptabletables: Some sort of abstraction for dealing with tables. Ideal support is
mytable["some_key"] = value
, and everything that the syntax implies.table chaining: In conjunction with tables, having the ability to query deeply into tables
mytable["key1"]["key2"]["key3"]
. Note that this becomes a tripping point for some libraries: crashing if"key1"
doesn’t exist while trying to access"key2"
(Sol avoids this specifically when you usesol::optional
), and sometimes it’s also a heavy performance bottleneck as expressions are not lazy-evaluated by a library.arbitrary keys: Letting C++ code use userdata, other tables, integers, etc. as keys for into a table.
user-defined types (udts): C++ types given form and function in Lua code.
udts - member functions: C++ member functions on a type, usually callable with
my_object:foo(1)
or similar in Lua.udts - table variables: C++ member variables/properties, manipulated by
my_object.var = 24
and in Luafunction binding: Support for binding all types of functions. Lambdas, member functions, free functions, in different contexts, etc…
protected function: Use of
lua_pcall
to call a function, which offers error-handling and trampolining (as well as the ability to opt-in / opt-out of this behavior)multi-return: returning multiple values from and to Lua (generally through
std::tuple<...>
or in some other way)variadic/variant argument: being able to accept “anything” from Lua, and even return “anything” to Lua (
object
abstraction, variadic arguments, etc…)inheritance: allowing some degree of subtyping or inheritance on classes / userdata from Lua - this generally means that you can retrieve a base pointer from Lua even if you hand the library a derived pointer
overloading: the ability to call overloaded functions, matched based on arity or type (
foo( 1 )
from lua calls a different function thenfoo( "bark" )
).Lua thread: basic wrapping of the lua thread API; ties in with coroutine.
coroutines: allowing a function to be called multiple times, resuming the execution of a Lua coroutine each time
environments: an abstraction for getting, setting and manipulating an environment, using table techniques, functions or otherwise. Typically for the purposes of sandboxing
plain C |
luawrapper |
lua-intf |
luabind |
Selene |
Sol2 |
oolua |
lua-api-pp |
kaguya |
SLB3 |
SWIG |
luacppinterface |
luwra |
|
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
optional |
~ |
✗ |
✔ |
✗ |
✗ |
✔ |
✗ |
✗ |
✔ |
✗ |
✗ |
✗ |
✗ |
tables |
~ |
~ |
~ |
✔ |
✔ |
✔ |
~ |
✔ |
✔ |
✗ |
✗ |
~ |
✔ |
table chaining |
~ |
~ |
~ |
✔ |
✔ |
✔ |
✗ |
✔ |
✔ |
✗ |
✗ |
~ |
✔ |
arbitrary keys |
~ |
✔ |
✔ |
✔ |
✔ |
✔ |
✗ |
~ |
✔ |
✗ |
✗ |
✗ |
✗ |
user-defined types (udts) |
~ |
✔ |
✔ |
✔ |
✔ |
✔ |
~ |
✔ |
✔ |
✔ |
✔ |
✔ |
✔ |
udts: member functions |
~ |
✔ |
✔ |
✔ |
✔ |
✔ |
~ |
✔ |
✔ |
✔ |
✔ |
✔ |
✔ |
udts: table variables |
~ |
~ |
~ |
~ |
~ |
✔ |
~ |
~ |
~ |
✗ |
✔ |
✗ |
~ |
stack abstractions |
~ |
✔ |
✔ |
✔ |
✔ |
✔ |
✔ |
✔ |
✔ |
~ |
✗ |
~ |
✔ |
lua callables from C(++) |
~ |
✔ |
✔ |
✔ |
✔ |
✔ |
✔ |
✔ |
✔ |
✔ |
✔ |
✔ |
~ |
function binding |
~ |
✔ |
✔ |
✔ |
✔ |
✔ |
~ |
~ |
✔ |
~ |
~ |
~ |
✔ |
protected call |
~ |
✗ |
~ |
~ |
~ |
✔ |
~ |
✔ |
~ |
~ |
~ |
~ |
~ |
multi-return |
~ |
✗ |
✔ |
✔ |
✔ |
✔ |
~ |
✔ |
✔ |
~ |
✔ |
~ |
✗ |
variadic/variant argument |
~ |
✔ |
✔ |
✔ |
✔ |
✔ |
~ |
✔ |
✔ |
~ |
~ |
~ |
✗ |
inheritance |
~ |
✔ |
✔ |
✔ |
✔ |
✔ |
~ |
~ |
✔ |
~ |
✔ |
~ |
✗ |
overloading |
~ |
✗ |
✔ |
✗ |
✗ |
✔ |
✗ |
✗ |
✔ |
✔ |
✔ |
✗ |
✗ |
Lua thread |
~ |
✗ |
~ |
✗ |
✗ |
✔ |
✔ |
✗ |
✔ |
✗ |
✗ |
✔ |
✗ |
environments |
✗ |
✗ |
✗ |
✗ |
✗ |
✔ |
✗ |
✗ |
✗ |
✗ |
✗ |
✗ |
✗ |
coroutines |
~ |
✗ |
~ |
✔ |
✔ |
✔ |
✗ |
✗ |
✔ |
✗ |
✗ |
✔ |
✗ |
no-rtti support |
✔ |
✗ |
✔ |
✗ |
✗ |
✔ |
✔ |
✗ |
✔ |
✔ |
~ |
✔ |
✔ |
no-exception support |
✔ |
✗ |
✔ |
~ |
✗ |
✔ |
✔ |
✗ |
✔ |
✔ |
~ |
✔ |
✔ |
Lua 5.1 |
✔ |
✔ |
✔ |
✔ |
✗ |
✔ |
✔ |
✔ |
✔ |
✔ |
✔ |
✗ |
✔ |
Lua 5.2 |
✔ |
✔ |
✔ |
✔ |
✔ |
✔ |
✔ |
✔ |
✔ |
✔ |
✔ |
✔ |
✔ |
Lua 5.3 |
✔ |
✔ |
✔ |
✔ |
✔ |
✔ |
✔ |
✔ |
✔ |
✔ |
✔ |
✔ |
✔ |
luajit |
✔ |
✔ |
✔ |
✔ |
~ |
✔ |
✔ |
✔ |
✔ |
✔ |
✔ |
✗ |
✔ |
distribution |
compile |
header |
both |
compile |
header |
header |
compile |
compile |
header |
compile |
generated |
compile |
header |
notes on implementations¶
Plain C -
Obviously you can do anything you want with Plain C, but the effort involved is astronomical in comparison to what other wrappers, libraries and frameworks offer
Does not scale very well (in terms of developer ease of use)
Compilation (or package manager use) is obviously required for your platform and required to use ANY of these libraries, but that’s okay because all libraries need some version of Lua anyways, so you always have this!
kaguya -
Table variables / member variables are automatically turned into
obj:x( value )
to set andobj:x()
to getHas optional support
Inspired coroutine support for Sol
Library author (satoren) is a nice guy!
C++11/14, or boostified (which makes it C++03 compatible)
Class registration is a bit verbose, but not as offensive as OOLua or lua-intf or others
Constructor setting syntax is snazzy and good
Sol -
One of the few libraries with optional support!
Basically the fastest in almomst all respects: http://sol2.readthedocs.io/en/latest/benchmarks.html
Overloading support can get messy with inheritance, see here
C++14/”C++1y” (-std=c++14, -std=c++1y, =std=c++1z) flags are used (available since GCC 4.9 and Clang 3.5)
Active issues, active individuals
Deserves lots of love!
lua-intf -
Can be both header-only or compiled
Has optional support
C++11
Macro-based registration (strange pseudo-language)
Fairly fast in most regards
Registering classes/”modules” in using C++ code is extremely verbose
In order to chain lookups, one has to glue the keys together (e.g.
"mykey.mykey2"
) on theoperator[]
lookup (e.g., you can’t nest them arbitrarily, you have to pre-compose the proper lookup string) (fails miserably for non-string lookups!).Not too shabby!
Selene -
Table variables / member variables are automatically turned into
obj:set_x( value )
to set andobj:x()
to getRegistering classes/”modules” using C++ code is extremely verbose, similar to lua-intf’s style
Eats crap when it comes to performance, most of the time (see benchmarks)
Lots of users (blogpost etc. made it popular), but the Repository is kinda stagnant…
luawrapper -
Takes the approach of writing and reading tables using
readVariable
andwriteVariable
functionsC++11, no macros!
The interface can be clunky (no table-like data structures: most things go though
readVariable
/writeVariable
)Internal Compiler errors in Visual Studio 2015 - submitted a PR to fix it, hopefully it’ll get picked up
SWIG (3.0) -
Very comprehensive for binding concepts of C++ (classes, variables, etc.) to Lua
Helps with literally nothing else (tables, threads, stack abstractions, etc.)
Not really a good, full-featured Library…
Requires preprocessing step (but it’s not a… TERRIBLY complicated preprocessing step); some boilerplate in writing additional classes that you’ve already declared
luacppinterface -
The branch that fixes VC++ warnings and introduces some new work has type checker issues, so use the stable branch only
No table variable support
Actually has tables (but no operator[])
Does not support arbitrary keys
luabind -
One of the older frameworks, but has many people updating it and providing “deboostified” versions
- Strange in-lua keywords and parsing to allow for classes to be written in lua
not sure if good feature; vendor lock-in to that library to depend on this specific class syntax?
Comprehensive lua bindings (can even bind “properties”)
There’s some code that produces an ICE in Visual C++: I submitted a fix to the library in the hopes that it’ll get accepted
Wonky table support: no basic conversion functions on
luabind::object
; have to push object then use lua API to get what you want
lua-api-pp -
Compiled, but the recommendation is to add the source files directly to your project
- Userdata registration with thick setup-macros: LUAPP_USERDATA( … ) plus a bunch of free functions that take a
T& self
argument You can bind member functions directly but only if you override metatable entries
Otherwise, COMPLICATED self-registration that makes you wonder why you’re using the framework
- Userdata registration with thick setup-macros: LUAPP_USERDATA( … ) plus a bunch of free functions that take a
- You have to create a context and then call it to start accessing the lua state (adding more boilerplate… thanks)
Thankfully, unlike many libraries, it actually has a Table type that can be used semi-easily. FINALLY
C++11-ish in some regards
Sad face, thanks to the way userdata registration is handled
SLB3 -
Old code exported to github from dying google code
“.NET Style” - to override functionality, derive from class – boilerplate (isn’t that what we’re trying to get rid of?)
Pointers everywhere: ownership semantics unclear
Piss-poor documentation, ugh!
Least favorite to work with, for sure!
oolua -
The syntax for this library. Go read the docs
- The worst in terms of how to use it: may have docs, but the DSL is extraordinarily crappy with thick, hard-to-debug/hard-to-error-check macros
Same problem as lua-api-pp: cannot have the declaration macros anywhere but the toplevel namespace because of template declaration macro
Supports not having exceptions or rtti turned on (shiny!)
- Poor RAII support: default-construct-and-get style (requires some form of initalization to perform a
get
of an object, and it’s hard to extend) The library author has informed me that he does personally advises individuals do not use the
Table
abstraction in OOLua… Do I likewise tell people to consider its table abstractions defunct?
- Poor RAII support: default-construct-and-get style (requires some form of initalization to perform a
Table variables / member variables from C++ are turned into function calls (
get_x
andset_x
by default)
luwra -
How do you store stateful functors / lambas? So far, no support for such.
Cannot pull functions without first leaving them on the stack: manual cleanup becomes a thing
Doesn’t understand
std::function
conversions and the like (but with some extra code can get it to work)Recently improved by a lot: can chain tables and such, even if performance is a bit sad for that use case
When you do manage to set function calls with the macros they are fast (can a template solution do just as good? Sol is going to find out!)
No table variable support - get turned into getter/setter functions, similar to kaguya
Table variables become class statics (surprising)


Nikita Kucherov injury update: Tampa Bay Lightning star will not play Thursday due to upper-body injury
by Tommy McArdleTampa Bay Lightning superstar Nikita Kucherov will not play against the Chicago Blackhawks Thursday due to his upper-body injury.
Kucherov, 26,left Tuesday's game against the St. Louis Blueslate in the second periodafter he was hit by Brayden Schenn. Tampa Bay head coach Jon Cooper said that the injury is not concussion-related, but no more specific are known about the forward's condition as of Nov. 21.
Schenn issued Kucherov a blindside hit as the Russian goal-scorerbackhanded the puck at theTampa Bay blue line during Tuesday'sgame.
A crowd gathered around Schenn after the hit and Tampa Bay's Erik Cernak was ultimately issued two roughing penalties for seeking retribution on Schenn. Schenn himself was given a two-minute minor for roughing Kucherov on a late hit.
Head coach Jon Cooper said after the game that Kucherov's injury was not related to a concussion, but Kucherov was not able to return after he skated off the ice on his own.
The 26-year-old has 18 points in 18 matchups after Tuesday's game.
Losing Kucherov, the reigning Hart Memorial Trophy and Art Ross Trophy winner, would prove a major blow to a Tampa Bay team still on the wrong side of the Eastern Conference's playoff picture.
The Blues defeated the Lightning 3-1 on Tuesday.


The osp_csm.jar Java archive (jar file) contains ready-to-run programs to accompany An Introduction to Computer Simulation Methods third edition by H. Gould, J. Tobochnik, and W. Christian [Addison Wesley, 2007]. The first two editions of this text used a procedural language, True Basic, and the programs were designed to be an easy route for learning other procedural languages such as Fortran and C.
The third edition uses an object oriented language, Java, which has excellent graphics and user interactivity, and is identical on all computer platforms. However, the use of Java makes writing programs more difficult than in True Basic, in part because of Java's greater power. Students and teachers now expect to write event driven programs with input fields, buttons, and graphical output. For this reason we have written a library of open source Java classes that perform much of the routine programming tasks such as input, output, animation, and user interaction so that users need not spend much time on these relatively uninteresting tasks. This library is described in Chapters 2 and 3 of the book and in greater detail in Open Source Physics: A Users Guide With Examples by W. Christian [Addison-Wesley, 2007].
OSP library source code and examples are available from the OSP website:
http://www.opensourcephysics.org.
Select the Programs tab at the bottom of this window to run the example programs.
License: The Open Source Physics code library and programs described in Open Source Physics: A Users Guide with Examples are being distributed by the Open Source Physics project under the GNU General Public License. A copy of this License is included on the OSP CD. If this CD is not available, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA or view the license online at
http://www.gnu.org/copyleft/gpl.html.


Minimum Viable Product
After trying and failing in one approach to this project yesterday I was determined to try and make things as simple as possible for myself.
Today I was working with Alex, we worked extremely well together and had the same views as to how we should build the game. Unlike yesterday we started by building a very basic system where you can create a boat that holds co-ordinates. You then have a player that can fire at a set of chosen co-ordinates . These co-ordinates are then compared to all the co-ordinates held by the ships and if there's a match they are deleted and the boat is destroyed. This was all built with ships of size 1 and a 4X4 grid. After this was built it was just a case of slowly scaling up from this working start point. We slowly added things such as making sure you couldn't place a ship outside the grid, or on top of one another and also compiling arrays of each players hits and misses, so they can check their shot history..
Ideally we would like to automate the game as much as we can to minimise the user interaction with the code. We want to get it to a point where the user can just boot up the game and then not have to input anything but co-ordinates, when placing a ship and when firing. We were extremely close to finishing this so hopefully we'll be able to get together at some point later in the week and finish it off.
Lexoo Lunch Talk
Today we had a talk by Chris O’Sullivan the CTO and co-founder of Lexoo, a place to get quick quotes from various lawyers online. He spoke about the best ways to ensure you save time and money when trying to create a business code wise. His key points were to write as little code as possible, get someone else to code instead and popping the 'Why?' stack. Writing as little code as possible means saving your time and hence money and also means it is easier to maintain. Getting someone else to write the code is again based on saving your time and therefore money. Why spend time trying to recreate a service that someone else has already made when you can be focussing on your product. Finally popping the 'Why?' stack, when implementing a new feature of your product you should ask yourself/team why you are doing it. If you keep recursively asking why, it should come down to these three reasons:
- Protect revenue
- Increase revenue
- Manage cost
Chris


Management Trainee Program
Take Advantage of Altoro Mutualís Management Trainee Program
Would you like help finding the perfect career? Then, apply for Altoro Mutual's 18-month Management Trainee Program. While networking with senior executives, you will have the opportunity to experience how each of our businesses work. Here is just a sampling of the experiences you might gain:
- Rotate through key business units
- Work on special projects designed to give you valuable work experience
- Meet & interview senior executives
- Network with a large group of trainee alumnae
- Receive career guidance through individual development planning
- Attend seminars about the banking industry
Candidate Requirements
Altoro Mutualís Management Trainee program recruits top individuals who meet the following requirements:
- Degree from accredited 4-year institution of higher learning (Any field of study)
- Cumulative GPA of 3.5 or above
- Excellent written & oral communication skills
- Demonstrated leadership in campus & community organizations
- A positive attitude & desire for a bright future
What happens after your complete the Management Trainee Program? You determine that! The opportunities at Altoro Mutual are as diverse as its employees.
To apply, select "Management Trainee Program" from our current job openings list.


You're in until {{> dateUTC value=timeCurrentTicketExpires format='h:mm:ss A'}}.
{{#if hasPosted}}
Thanks for posting, your prize is below. Please enjoy your remaining moments of exclusivity.
{{else}}
Post a message and receive a prize.
{{#autoForm id='postForm' schema=postFormSchema type='method' meteormethod='postMessage' }}
{{> afQuickField name='message' label=false afFieldInput-placeholder='Post a message for all to see' }}
{{> afQuickField name='link' label=false afFieldInput-placeholder='URL (optional)' }}
{{/autoForm}}
{{/if}}


Help: If you can't see the document's content above this text, please turn off your webbrowser's extensions which blocks HTML iframes (ad-blocker, ghostery, etc) and reload this page.
You can open the PDF version or also download the docx version.
{% extends 'admin/base_site.html' %} {% load i18n static sponsors %} {% block extrastyle %}{{ block.super }}{% endblock %} {% block title %}Send {{ contract }} | python.org{% endblock %} {% block breadcrumbs %}
{% endblock %} {% block content %}Help: If you can't see the document's content above this text, please turn off your webbrowser's extensions which blocks HTML iframes (ad-blocker, ghostery, etc) and reload this page.
You can open the PDF version or also download the docx version.


|
TuyaRTCCameraSDK
|
Public Member Functions | |
| void | onVideoFrame (VideoFrame frame) |
| void | onFirstVideoFrame (int width, int height) |
| void | onResolutionChanged (int oldWidth, int oldHeight, int newWidth, int newHeight) |
An interface of the Camera (stream) class, through which some audio and video status of the device (stream) can be provided, as well as some audio and video data callbacks
| void com.tuya.rtc.TuyaRTCCameraHandler.onVideoFrame | ( | VideoFrame | frame | ) |
This method is called when a frame is received from the Camera (stream) and decoding is complete
| frame | Video data |
| void com.tuya.rtc.TuyaRTCCameraHandler.onFirstVideoFrame | ( | int | width, |
| int | height | ||
| ) |
This method is called when the first frame is received from the Camera F and decoded to get the width and height information of the video
| width | Width of the picture |
| height | Height of the picture |
| void com.tuya.rtc.TuyaRTCCameraHandler.onResolutionChanged | ( | int | oldWidth, |
| int | oldHeight, | ||
| int | newWidth, | ||
| int | newHeight | ||
| ) |
This method will be called when the width and height of the video screen obtained from the Camera (stream) changes
| oldWidth | The width of the picture before the change |
| oldHeight | The height of the picture before the change |
| newWidth | Width of the current picture |
| newHeight | Height of the current picture |


This page will instruct the users on creating the title page for their video lecture.
The title page is the first page of the slide presentation.
Go to the next page to create slides.
This page will instruct the users on creating the title page for their video lecture.
The title page is the first page of the slide presentation.
Go to the next page to create slides.
This page will instruct the users on creating the slides for their video lecture.
The number and content of the slides would depend on the topic of the presentation.
It is recommended to keep the video lecture at about 5 minutes or less.
Go to the next page to learn how to write the script of your slides.


Start updates Stop updates Randomize data length
Use "row changed key" optimization
Row changes on last grid redraw: (on 9 grid sections)
Data length