Zig build system
en.liujiacai.net
en.liujiacai.net
On a M1 Ultra studio (the same from my screenshot above) it takes me 6 mins to run the entire compiler test suite for arm64-linux (I do development in a Linux VM), which is pretty sweet.
Note that this is one stepping stone for getting good performance from Zig, but it's not yet incremental compilation with in-place binary patching [1]. That's still a work in progress.
For example, can I use the C backend to compile zig to C, and then use the system compiler as I would normally do with a meson cross file or CMake toolchain file?
Is it possible to write zig modules which would be liked to the bigger project otherwise written in C, C++ & c?
And moreover, to produce C "blobs" from zig sources which would be then part of the bigger project written in other languages?
I'd also like to know the answer to both!
It's possible, but:
1. The C backend isn't 100% there yet. You won't be able to use all features and might run into bugs.
2. The generated code won't be very readable, it's arguably not too different from just using Zig-compiled object files directly in terms of "opaqueness" and legibility.
If neither of these are a big problem for you (both points are likely to improve with time), then yes, you could do that.
The idea would be that if C files are reproducible across multiple environments (esp. 32 vs 64 bit) the end user would not need a zig toolchain.
In particular, I explicitly don't want to rewrite 15000 lines of build system code, so anything that uses build.zig is a nonstarter.
zig build-obj file.zig
And then include the object file along with your other sources. How you do this will of course depend on your build system.https://github.com/andrewrk/ffmpeg
Particularly interesting is the use of nasm as a package dependency, which is executed to compile many assembly files into object files, which are then linked into the ffmpeg static library.
I'm using this package in a work-in-progress reboot of Groove Basin (a music player server) in Zig:
https://github.com/andrewrk/groovebasin/tree/zig-pkg
Point being that if you want to collaborate on the music player project, you don't need to screw around with a million system dependencies, it's just `zig build` and you're off to the races - no matter whether you are using Windows, macOS, or Linux.
The zig build system is under heavy construction during this release cycle of Zig. I recommend to check it out at the end of May when Zig 0.11.0 is released, and a few more issues will be smoothed over. Of course, if you want to get your hands dirty and help work on a bleeding-edge build system & package manager, come on over and give master branch a try.
Builds are much faster than with make, and it makes it very easy to cross-compile to other platform, includes Windows, Linux with specific glibc versions, and WebAssembly.
In fact, it was the easiest to build Linux binaries for .NET, that have to support glibc back to version 2.17, but on a recent OS, with a recent compiler toolchain.
Is it mainly due to the zig's caching of the build artifacts?
(And each test generates/defines a HAVE_SNPRINTF etc macro that your code can use to adapt based on available features. But if the project isn't as big as curl or git, it probably doesn't really adapt to all possible old and obscure systems anyway, so there's no point to 100s of such tests.)
https://github.com/jedisct1/libsodium
I would guess that the author of the library has full control both over optimal parallelization of a build and minimal autoconf, but he can still observe a huge speedup, so I'd still like to read his answer.
Building the tests, in particular is instant with zig, not with make.
It may still be autoconf, but not the configure phase, rather the complexity of the generated makefiles.
Does the Zig Project include a full blown C Compiler? Is it the Zig Compiler with some sort of adaptation to compile C code? Or does it use something like Clang behind the curtains? (In this case it would be responsible for some other parts of the compilation process)
1. It uses LLVM as the default backend, in which case that handles C as well
2. Optionally, and in the future by default, the Zig backend (a different one from the LLVM one) includes a C compiler (?)
Something like that. Its very powerful and it has the best C integration of any language in my experience (better than C++ since it effectively namespaces C headers).
Who would be doing the parsing of C code for instance? Clang is also based LLVM but it is responsible for a load of C-specific stuff like parsing the language and feeding it into LLVM for instance.
I've got little experience with this stuff so I'm not sure if my questions even make that much sense.
(Edit: I believe ptato has answered my question above.)
In this case all the file operations are handled by clang, Zig basically just sets up all the advanced flags for you when it makes sense to do so. One last example of CLI rewriting is related to the caching system: Zig cc knows how to cache a build by passing to clang the same kind of flags that cmake (or other build systems) would.
There's another C-related feature of Zig that works differently: `@cImport()`, which is a builtin that allows you to import C header files directly into a Zig script, in order to use from Zig all the types exposed by the header file. This one translates the C syntax in equivalent Zig syntax. I believe it uses clang's code to parse the C code into an AST, but then it's all Zig logic from there.
Lastly, we have a C frontend project going (arocc, linked by ptato) on that we plan to eventually upstream into Zig. This would be a replacement for clang and would work by parsing the C code and translating it into Zig IR, similarly to how the D programming language does it. The only limitation of this approach is that it would only support C, not C++, so we would either have to still keep clang around for C++, or ditch clang but then lose C++ compilation support. That said, even in the case where we keep clang around for C++ support, it would be worth having a custom C frontend for the Zig compiler in order to have more fine-grained control over the compilation process than what we can get from clang, plus the fact that it would make debug builds faster, since we could avoid invoking LLVM completely in that case (ie debug builds) even if you depend on C code.
Supported file types:
.zig Zig source code
.o ELF object file
.o Mach-O (macOS) object file
.o WebAssembly object file
.obj COFF (Windows) object file
.lib COFF (Windows) static library
.a ELF static library
.a Mach-O (macOS) static library
.a WebAssembly static library
.so ELF shared object (dynamic link)
.dll Windows Dynamic Link Library
.dylib Mach-O (macOS) dynamic library
.tbd (macOS) text-based dylib definition
.s Target-specific assembly source code
.S Assembly with C preprocessor (requires LLVM extensions)
.c C source code (requires LLVM extensions)
.cxx .cc .C .cpp .stub C++ source code (requires LLVM extensions)
.m Objective-C source code (requires LLVM extensions)
.mm Objective-C++ source code (requires LLVM extensions)
.bc LLVM IR Module (requires LLVM extensions)
.cu Cuda source code (requires LLVM extensions)And just to say the WebAssembly support is amazing, well done and thanks!
And not just C, but also C++ and Objective-C - including all the hairy stuff to create macOS executables without the Apple toolchain.
Zig has almost completely solved the bootstrap problem.
I have wanted Rust and Zig to support compile-to-C for a while, so this is exciting news for me.
One thing that would particularly interest me is if functions intended to be inlined could be emitted into .h files.
I'd like to add the link to the use examples demonstrating features of zig for c and c++ compilation available with the default zig installation which aren't directly available after installing clang:
https://andrewkelley.me/post/zig-cc-powerful-drop-in-replace...
Previous discussions:
“ Zig’s @cImport builtin is unique in that it takes in an expression, which can only take in @cInclude, @cDefine, and @cUndef. This works similarly to translate-c, translating C code to Zig under the hood.” https://ziglearn.org/chapter-4/
Since it’s zig code, I think you would have that flexibility.
But even without LLVM backend I would expect that Zig will be able to produce DWARF debug information.
This also means you can transparently debug-step from Zig into C code and back, which is kinda expected but it never gets old for me :)
A language with nothing but boolean variables and functions with no recursion, or a language with nothing but boolean variables and loops of up to a depth of 2 can already encode TQBF [1], which makes reasoning about it intractable (it's PSPACE-complete). Because most build systems fall within that category they might as well be Turing complete.
[1]: https://en.wikipedia.org/wiki/True_quantified_Boolean_formul...
But then some things become impossible to do.
I'm creating a different build system (not Zig's), and I'm taking a different approach. Instead of a non-Turing-complete language, I've made one that is as powerful as possible. However, it will allow users to restrict the language so that they will only use subsets, and those subsets will not necessarily be Turing-complete.
In this way, it has the power to do anything, but the ability to restrict that power for ease-of-use.
E.g. not sure how Meson handles this, but when I have a project with dozens of similar build targets and platform specific compile options, I really want to do the build description in a loop instead of a data tree.
(for example: https://github.com/floooh/sokol-zig/blob/3f978e58712f9eb029b...)
PS: apparently Meson build scripts can also have variables, conditions and loops, which I guess makes the difference to an actually Turing complete build system rather esoterical?
https://mesonbuild.com/Syntax.html#logical-operations
A proper build system is so much more than just describing build targets and their dependencies, you also want to generate source code, copy and process data files, communicate with REST services etc... The more this happens in a 'real' programming language the better.
Is ninja not expressive enough for your needs?
- You don't have implicit allocations when using Zig stdlib. For example, when you instantiate an ArrayList or HashMap, you need to pass in an allocator, so you have full control over how memory is managed. So, even though you have higher level data structures, you still have a lot of low level control.
- Very good error handling. IMO better than Rust and Golang, while still being very explicit about what is happening
- "Uncolored" async functions, meaning there's no special syntax for declaring functions that can be paused/resumed. If I understood correctly (didn't try it a lot), you can turn any program into "async" by changing how I/O is handled globally. More details here: https://kristoff.it/blog/zig-colorblind-async-await/
Reading this from top to bottom gives a pretty good overview:
He gives some examples of C vs Zig and what they tried to improve.
- All integer operations trap on overflow in safe build modes; with explicit operators for saturating or wrapping arithmetic
- No implicit integer promotion unless the destination type can represent all values of the source type (so no implicit signed/unsigned conversions unless they're statically guaranteed to be safe - e.g. a u8 can coerce to an i32 but not to an i8)
- Arbitrary bit-size integers (C23 will have this)
- Enums that are actually useful and fun, vs the complete waste of time that C's enums are (Enum values are namespaced, you can't directly use their values as integers, you can control the underlying representation if you want, etc)
- Built-in support for tagged unions, also known as sum types (bare union + a tag indicating which field is active)
- Safe unions in safe build modes (compiler inserts a hidden tag to track which field is active)
- A standard library that's actually useful (it's small compared to some other languages, and not well-documented yet, but it's not littered with landmines the way C's is)
- A modern import system instead of preprocessor-style copy/pasting text
- Compile-time programming in Zig, instead of preprocessor macros
- Arrays are an actual type, instead of decaying to pointers
- Much better support for pointers (pointer + length AKA slices are the primary way to deal with multiple items whose length can vary at runtime; also single-item pointers and multi-item pointers are different types, so you can't accidentally index into a single-item pointer or attempt to dereference a multi-item pointer without providing an index)
- Errors must be handled, with convenient syntax for passing the error up the stack + inferred error sets so that you don't have to explicitly annotate the set of possible errors for most functions
- Nulls encoded in the type system so that they must be explicitly handled.
- test blocks for writing tests inline and running them with `zig test`
> .{}
1) It omits the constructor name. My uneducated guess is that "modern" languages try to avoid the Java-style pattern of repeating a type/constructor many times in a single line (e.g., "Point pt = new Point(0, 0)") when it can infer things to help the developer.
2) It starts with a dot, while C++'s compound literals (for example) don't. The pros and cons of this are discussed in https://github.com/ziglang/zig/issues/5039.
const exe = b.addExecutable(.{
.name = "demo",
.root_source_file = .{ .path = "src/main.zig" },
.target = target,
.optimize = optimize,
});Although more widely used.
Of course, Germans can speak and languages of German descent are just as rich, precise and expressive as any other. But the term Njemacki probably stuck around out of an initial ignorance about a foreign culture in earlier times and lack of general education.
I upvoted your comment because I agree with it in the context of the parent, but this ending explanation is frankly ridiculous. It sounds like early Slavs had no idea that Germanic tribes had their own languages which is just plain impossible. Proto-Slavic němъ meant also unintelligible/hard to understand. So contrary to popular opinion those Slavic words for Germans doesn't (and didn't) mean mute (or "cannot speak"), it's just that in modern Sl. languages words stemming from němъ evolved to indicate mostly muteness.
In fact it's so easy to forget or ignore that we humans were just as smart and creative thousands of years ago as we are today.
But it's interesting and funny to think that our ancestors called each other mute, or rather unintelligible, because they didn't understand what the other one was saying. I find it endearing how we often stumble over our own limitations and quirks, so much that it is often ingrained in language and culture.
Like how the Ancient Greek lacked education (Barbarians). ;)
Maybe once Zig is fully developed we'll focus our effort on more retrocompatibility.
If you want to help us get there faster, consider donating to the Zig software foundation, as we're looking to hire more developers to work full time on Zig (we're 4 full-time people right now).
So that is not an excuse to drop support for 10.15.
https://developer.apple.com/support/xcode/
While Zig is not even 10.15.
andrewrk commented Feb 17, 2023 •
macOS 10 is no longer supported by Apple, and therefore also no longer supported by Zig. You have to use one of the latest 3 versions or else your system is not being patched for security vulnerabilities, and likewise zig does not provide support for cross compiling to anything less than the latest 3 versions.
https://ziglang.org/download/0.10.0/release-notes.html#macOS
https://github.com/ziglang/zig/issues/14651#issuecomment-143...But for a pre-1.0 language in development the decision is completely justified IMHO. Catalina is quite ancient by macOS standards.
That is not what the parent said
https://ziglang.org/download/0.10.0/release-notes.html#Suppo...
I also had this issue with a non-updatable MBP, but linux support is good, and I am looking forward to trying Zig out with Risc-V when I can get my hands on some hardware that hopefully wont expire as fast.
iMac (Mid 2014 or later)
iMac Pro
MacBook (Early 2015 or later)
MacBook Air (Mid 2013 or later)
MacBook Pro (Late 2013 or later)
Mac Mini (Late 2014 or later)
Mac Pro (Late 2013 or later)
https://en.wikipedia.org/wiki/MacOS_Big_SurAnd by similarity of supporting last 3 macOS release, this will grow to hardware of ~2016 if they drop support of Big Sur next.