Stumbled on this issue when helping to get some code building here:
The Issue:
If a target is added in build.zig
like so:
const target = b.resolveTargetQuery(.{
.cpu_arch = .thumb,
.os_tag = .freestanding,
.abi = .eabihf,
.cpu_model = std.zig.CrossTarget.CpuModel{ .explicit = &std.Target.arm.cpu.cortex_m7 },
});
All its default “cpu features” get passed to Clang during compilation via -Xclang -target-feature -Xclang +feature
for features that default to enabled, and -Xclang -target-feature -Xclang -feature
for features that default to disabled. This is a reasonable approach to being explicit about features, however it leads to some problematic behavior.
Now let’s say I’m compiling an incredibly minimal main.c
like so:
// Make linker happy, but cursed, don't use in real code :)
int *_start = 0;
int main(void)
{
__asm volatile(
" tst r14, #0x10 \n" /* Some assembly code that uses floating point registers */
" it eq \n"
" vstmdbeq r0!, {s16-s31} \n");
return -1;
}
And I naively add the following C flags, since I’m porting from GCC and I know Clang is compatible with this method of specifying hardware floating point:
exe.addCSourceFiles(.{
.files = &.{"src/main.c"},
.flags = &.{
"-mfpu=fpv4-sp-d16",
"-mfloat-abi=hard",
},
});
I then get this error:
main.c:19:8: error: instruction requires: fp registers
" vstmdbeq r0!, {s16-s31} \n");
^
This is because with the current behavior, you get a call to clang that looks something like (run zig build --verbose-cc
):
usr/local/bin/zig clang main.c ...[lots of flags/features]... -Xclang -vfp4d16sp [removes this feature!] ...[lots of flags/features]... -mfpu=fpv4-sp-d16 -mfloat-abi=hard
The precedence of removing the cpu feature via -Xclang
args is overriding my GCC style flags that are supposed to enable the feature.
Open Ended Questions
- Do we need to explicitly specify “removal” of features that default to not included? It looks like we have a pretty good handle on sane defaults already for ARM freestanding chips (see here)
- I can see a case where maybe there’s an “LLVM Default” (when you don’t specify any feature flags at all) that’s undesirable, supporting this approach
- As an aside, it also leads to atrociously long calls to Clang that get in your way when you’re trying to do some low level build system debug
- Should we potentially throw a warning in
addCSourceFiles
when certain flags are used? Might be some nice build system sugar to give someone a heads up "you shouldn’t be using these flags here, you must configure all architecture related compile options withb.resolveTargetQuery()