@cImport is just a way to access the zig translate-c feature at the language level. The idea is to move this usage to the build system, embracing std.Build.Step.TranslateC. You construct such a step to translate your header files or whatever, and then add the resulting Zig code as a module to your project, so you can @import("c") or similar.
The reason for this change is that zig translate-c uses Clang, and we are trying to drop the compiler’s direct dependency on libclang. Using this mechanism via the build system means translate-c itself can be moved into the build system, and – as we transition LLVM and Clang to optional components via the package manager – eventually the official LLVM/Clang package.
It’s unclear what role Aro plays in the compiler’s future – there is a WIP translate-c implementation based on Aro, but I’m not sure whether we’ll keep that around. Either way, however, it seems inevitable that some uses of translate-c will require Clang, for instance for language extensions which Aro may not support. If Aro stays around, I think it too will become a package, which can provide C translation and compilation in much the same way as the official LLVM/Clang package will.
I mean, C interop is a big feature of Zig. It has been heavily advertised. Like, “Look, you can just do @cImport(...) and just use a C library directly in your code”. Now it requires a number of hoop jumps, which, in my opinion, makes it borderline unusable.
The thing is, right now Zig uses LLVM to emit machine code. The advantage of LLVM is that it’s relatively easy to support: you just need to emit the LLVM IR and LLVM can emit the object file (we see “LLVM Emit Object” in every build) and then link it to get an executable or library (we see “LLD Link” sometimes) for a huge amount of different processor architectures.
However, have you ever tried compiling the Zig compiler yourself? You’ll first have to compile LLVM twice (see https://github.com/ziglang/zig-bootstrap), which takes, unless you have a quantum computer, seven to nine hours. Then, when you build Zig, you’ll see that the part of the compilation that Zig does (“Semantic Analysis” and “CodeGen”) finishes relatively fast, but “LLVM Emit Object” takes forever and “LLD Link” takes [half forever] when things are big enough.
The Zig contributors are working on an own backend right now (instead of LLVM). The x86_64 backend is ready to use for most projects (that aren’t using @cImport) and doesn’t take forever to do compilations. Zig also plans to do incremental compilation in the future (only compiling parts of code which have changed, WAY faster than regular compilation) and incremental linking in the future, but this isn’t supported by LLVM.
When Zig got far enough with its own back-ends (x86_64, riscv, aarch64 and so on), they plan to make LLVM optional. But with LLVM comes Clang, one of the most well-known C compilers. And when you use a C library, there are two things: the headers (which provide function definitions) and the actual code or libraries (which implement those definitions). Translating a header file to Zig equivalents (with C calling conventions) is possible, but certain features that some libraries make use of may not be supported. And the Zig compiler is a Zig compiler, not a C compiler, so C sources can only be handled thanks to Clang.
And we want to use Zig, not C, right? There were many security vulnerabilities in C libraries that wouldn’t have happened if we used Zig to implement those libraries (slices vs. many-item pointers) and using a (potentially vulnerable) C library in Zig isn’t much safer than using a (potentially vulnerable) C library in C.
What. Never had to do that even once. Just did pkg install llvm18, that’s it. Yes, I’m using the master version of Zig. Yes, I compile it every time. Takes about 40-something minutes, no big deal.
And the Zig compiler is a Zig compiler, not a C compiler, so C sources can only be handled thanks to Clang.
Zig has been heavily advertised as a “better C compiler”, tho.
And we want to use Zig, not C, right?
Yes, but no: I want a useful, convenient programming language that doesn’t make me use stupid libraries only made for a couple of platforms. Again: C interop was heavily advertised as a big feature of Zig.
Can you explain on what basis you are saying it will be more cumbersome?
We’ve not decided exactly in which ways we’re going to extend the std.Build.Step.TranslateC APIs, if any, but I personally (emphasis to make sure nobody is taking this API as a promise!) picture it as working something like the following.
Today, you write this:
const c = @cImport({
@cDefine("FOO", "123");
@cUndef("BAR");
@cInclude("qux.h");
});
Post-changes, you write this:
// build script:
exe.root_module.addTranslateCImport("c",
\\#define FOO 123
\\#undef BAR
\\#include <qux.h>
);
// source code:
const c = @import("c");
After we eventually transition Clang to a package, the build system usage will inevitably look a little different again, but not significantly.
This really doesn’t seem any more awkward. If you want to go by a naive SLOC metric, it is a single extra line total. If you have justifiable reason to believe that such an API won’t happen, or an argument as to why it will be significantly more difficult to use and thus worth retaining the language complexity inherent in @cImport, I’d love to hear it.
What. Never had to do that even once. Just did pkg install llvm18, that’s it. Yes, I’m using the master version of Zig. Yes, I compile it every time.
Yeah, the person you’re replying to has a slight misunderstanding here. Compiling LLVM twice is only necessary if you want to go from minimal system dependencies to a reproducible, statically-linked Zig build. The zig-bootstrap repository they linked is used to create builds for https://ziglang.org/download, and isn’t really intended for general use.
Takes about 40-something minutes, no big deal.
It impresses me that someone can see a 40 minute build as “no big deal”. Admittedly I am building the compiler far more than most, but I still dread the rare occasions where I have to rebuild LLVM. For comparison, we’re probably about to merge a change which allows building the whole Zig compiler (in debug mode, with LLVM disabled) in under 10 seconds.
And the Zig compiler is a Zig compiler, not a C compiler, so C sources can only be handled thanks to Clang.
Zig has been heavily advertised as a “better C compiler”, tho.
Yes, and this functionality is not regressing. Zig is a good C compiler because it bundles the necessary things and provides good defaults to a Clang build. The only change to the C compilation aspect of the build system is that the functionality is moving to an official package which updates out of lockstep with the compiler.
And we want to use Zig, not C, right?
Yes, but no: I want a useful, convenient programming language that doesn’t make me use stupid libraries only made for a couple of platforms. Again: C interop was heavily advertised as a big feature of Zig.
You say this as though moving Clang functionality to a separate package is introducing a dependency on more code. All of this code already exists: it is in the Zig compiler. Literally all we are doing is moving it to a separate project. You aren’t introducing a dependency on any more code, we’re just dropping that dependency for the many use cases which don’t need it.
Regarding build times, LLVM (or GCC for that matter) takes about 4 to 7 hours to build. 40 minutes is nothing compared to that. Most of that is zig build-exe zig, btw, so again, no big deal.
Yes, all the features will be supported.
What changes is when the translation from C to Zig happens.
For a comparison of the code before and after the change see: cImport going away - #9 by mlugg