I have an OrangePi 4 LTS with Armbian installed. On my Desktop PC zig build works, compiles, runs. But on the Aarch64 (4 x Cortex-A53 2 x Cortex-A72) system. I get the following and I can’t find an answer. Perhaps my wrappers around rtaudio, rtmidi and sndfile don’t compile the same on this platform? but I don’t know where since there is no clue.
$ zig build
install
└─ install audio
└─ compile exe audio Debug native failure
error: error: Invalid record (Producer: 'zig 0.16.0' Reader: 'LLVM 21.1.0')
error: process exited with error code 1
failed command: /opt/zig/zig build-exe /usr/lib/aarch64-linux-gnu/librtmidi.a -ODebug --dep audio --dep noise --dep tui -Mroot=/home/orangeserver/zig/audio/src/main.zig --dep rtmidi --dep rtaudio --dep printmidi --dep reverb --dep reverb2 --dep signals --dep filter --dep poly --dep parse -Maudio=/home/orangeserver/zig/audio/src/root.zig -ODebug --dep printmidi --dep filter --dep poly --dep parse --dep signals -Mnoise=/home/orangeserver/zig/audio/src/signals/noise.zig -ODebug -Mtui=/home/orangeserver/zig/audio/src/tui.zig -I/usr/include/rtmidi -D__UNIX_JACK__ -D__LINUX_ALSA__ -lrtmidi -ODebug -L /usr/lib/aarch64-linux-gnu --dep printmidi --dep cmidi --dep cmidi-data --dep signals -Mrtmidi=/home/orangeserver/zig/audio/src/rtmidi.zig /usr/lib/aarch64-linux-gnu/librtmidi.a -I/usr/include/rtaudio -D__LINUX_ALSA__ -D__LINUX_PULSE__ -D__UNIX_JACK__ -D_REENTRANT -lrtaudio -ODebug -L /usr/lib/aarch64-linux-gnu -Mrtaudio=/home/orangeserver/zig/audio/src/rtaudio.zig -ODebug -Mprintmidi=/home/orangeserver/zig/audio/src/printmidi.zig -ODebug -Mreverb=/home/orangeserver/zig/audio/src/freeverb.zig -ODebug -Mreverb2=/home/orangeserver/zig/audio/src/freeverb2.zig -ODebug --dep printmidi --dep filter --dep env --dep gen --dep poly --dep noise --dep sampler --dep wavguide -Msignals=/home/orangeserver/zig/audio/src/signals.zig -ODebug --dep printmidi --dep poly --dep parse --dep signals -Mfilter=/home/orangeserver/zig/audio/src/signals/filter.zig -ODebug --dep printmidi --dep rtmidi --dep rtaudio --dep signals -Mpoly=/home/orangeserver/zig/audio/src/polyman.zig -ODebug --dep poly --dep signals -Mparse=/home/orangeserver/zig/audio/src/parse.zig -ODebug --dep cmidi-data -Mcmidi=/home/orangeserver/zig/audio/src/cmidi.zig -ODebug -Mcmidi-data=/home/orangeserver/zig/audio/src/cmidi_data.zig -ODebug --dep printmidi --dep poly --dep parse --dep signals -Menv=/home/orangeserver/zig/audio/src/signals/envelope.zig -ODebug --dep printmidi --dep filter --dep poly --dep parse --dep signals -Mgen=/home/orangeserver/zig/audio/src/signals/generator.zig -ODebug --dep printmidi --dep filter --dep poly --dep parse --dep sndfile --dep signals -Msampler=/home/orangeserver/zig/audio/src/signals/sampler.zig -ODebug --dep printmidi --dep filter --dep poly --dep parse --dep signals -Mwavguide=/home/orangeserver/zig/audio/src/signals/waveguide.zig -I/usr/include/opus -I/usr/include/aarch64-linux-gnu -lsndfile -ODebug -L /usr/lib/aarch64-linux-gnu -Msndfile=/home/orangeserver/zig/audio/src/sndfile.zig -lc --cache-dir .zig-cache --global-cache-dir /home/orangeserver/.cache/zig --name audio --zig-lib-dir /opt/zig/lib/ --listen=-
Build Summary: 0/3 steps succeeded (1 failed)
install transitive failure
└─ install audio transitive failure
└─ compile exe audio Debug native failure
error: the following build command failed with exit code 1:
.zig-cache/o/7888331c5ea8cba827cfc99548e35051/build /opt/zig/zig /opt/zig/lib /home/orangeserver/zig/audio .zig-cache /home/orangeserver/.cache/zig --seed 0xa90c3d9f -Zd11354c6b5d88ac7
I’m not sure but I’ve experienced this issue one, and I think it’s because of the LLVM bitcode, there must be a mismatch I think, but I’m not sure
Yes but there is no other LLVM or components installed, Zig is definitely using its own installed runtime. The dynamically linked C libraries are not LLVM. Is LLVM version 21.1.0 the correct version?
yeah there might be a mismatch, also if one of your deps is C++ you are better off linking it statically, because there can be issues with symbol resolutions and stuff like that.
You might need to build a debug build of the compiler and run it with debug logging enabled to get more detailed information about what is going wrong and where. But since you said it works on your desktop PC (you didn’t specify the arch, but I assume it’s x86-64) but not on AArch64, here are two ideas:
Does that include function pointers? i.e *const fn ...
// Samplers can point to the same samples but not WaveGuides.
switch (p.signal.proc) { // proc is a *const fn()
sg.wg.waveguide => {
const size = p.signal.buffer.e - p.signal.buffer.s;
p.signal.buffer = self.alloc_buffer(size);
},
else => {},
}
. . .
Udpate: Yes, it does. Creating an enum to switch instead, solved it. I wonder if an if statement would have the same error?
Plain ifs with regular == comparisons will probably work, it’s specifically switching on pointers that is broken and on the way of being removed from the language.
opened 09:53PM - 08 Apr 25 UTC
breaking
proposal
accepted
## Background
In Zig, several constructs can capture a value "by reference" usi… ng the syntax `|*x|`. The captures which can be by-ref are:
* The capture of an iterable `for` operand (i.e. not a range)
* The payload capture of a `if` on an optional or error union
* The payload capture of a `while` on an optional or error union
* The payload capture of a `switch` prong
However, there is an inconsistency in how these by-ref captures work between `for` operands and other constructs. The inconsistency is made clear by these two examples:
```zig
var arr: [5]u32 = undefined;
for (arr) |*x| x.* = 0;
```
```zig
var opt: ?u32 = 123;
if (opt) |*x| x.* = 456;
```
The second of these snippets compiles; the first does not. For the first snippet to compile, the `for` operand needs to be `&arr`.
This difference occurs because in the latter case, Zig effectively inserts an `&` before the operand when the capture is "by-ref". `while` and `switch` captures also follow the latter behavior.
The `for` behavior has some advantages. Mainly, it is more explicit; you can tell exactly what the code is doing. Implicit references can look a bit weird in a few cases. Consider:
```zig
while (it.next()) |*x| {
// ...
}
```
What's that snippet doing? You'd be forgiven for thinking that `next` returns a `*?T` or similar, but actually, this inserts an implicit `&`, meaning `x` is a pointer to a *local temporary*. If `next` did return `*?T`, you'd currently have to write:
```zig
while (it.next().*) |*x| {
// ...
}
```
Okay, so we're dereferencing the pointer... but we somehow get a pointer out which is derived from it? The logic here *does* make sense, but it's quite weird.
The implicit-ref behavior also meshes particularly strangely with `switch`, because *any prong* having a by-ref capture changes how the operand is evaluated. This means there can be arbitrary distance between the operand and the code which decides how it is evaluated, which is pretty strange.
## Proposal
Remove the implicit-ref behavior of `if`, `while`, and `switch` on their operands. These constructs will now accept pointers to their operand types, and pointers will be required for by-ref captures.
Here's how this looks in practice:
```zig
var opt: ?u32 = 123;
if (&opt) |*x| x.* = 456;
// this is also allowed, although redundant, when you capture by value
if (&opt) |x| _ = x;
// and likewise for error unions
var eu: anyerror!u32 = 123;
if (&eu) |*x| {
x.* = 456;
} else |_| {}
if (&eu) |x| {
_ = x; // by-val capture even though the operand is a pointer
} else |_| {}
// `while` works exactly like `if`
// `switch` looks like this:
const U = union(enum) {
foo: u32,
bar: u64,
};
var u: U = .{ .x = 123 };
switch (&u) {
.foo => |*x| x.* = 456,
.bar => |y| _ = y,
}
// again, it's okay for the captures to be by-val
switch (&u) {
.foo => |x| _ = x,
.bar => |y| _ = y,
}
```
There's one problem here: `switch (&u)` already has a different meaning! Currently, `switch` on pointers is allowed, and switches on the *address*. **As such, this proposal also proposes removing `switch` on pointers as it works today.** If desired, the exact same behavior can be achieved by switching on `@intFromPtr` of a pointer. (I don't think `switch` on pointers is heavily relied upon in the wild; my source for this is that it's pretty much completely broken on the LLVM backend right now!)