What ‑march=native actually resolves to
Clang’s -march=native is not a magic flag that picks a single CPU family. At compile time the compiler queries the host machine’s CPUID (or the equivalent on other architectures). It then maps the detected micro‑architecture to a -target-cpu name that LLVM recognises and enables every -target-feature that the host reports as available. The result is a *host‑specific* target description such as:
clang -march=native -### -c test.c
# cc1: ... -target-cpu=skylake -target-feature=+sse4.2,+aes,+avx2 ...
Because the mapping is performed at compile time, the binary contains instructions that are guaranteed to be present on the build host only. The compiler does not emit any runtime dispatch logic for -march=native.
Portability implications
The documentation characterises this behaviour as *non‑portable*. If a build host has newer ISA extensions than a deployment target, the produced binary may contain instructions that the target CPU does not implement, leading to illegal‑instruction faults at runtime. Reproducibility is also compromised because the same source compiled on two different hosts will generate different binaries.
Is there a way to keep ‑march=native but constrain it to a portable baseline?
No. Clang does not provide a switch that limits -march=native to a subset of features or a baseline CPU. The only documented method to obtain a portable target while still making use of host‑specific optimisations is to:
- Choose an explicit baseline CPU (e.g.
-march=generic, -march=corei7, -march=haswell, etc.).
- Use
-mtune=native if you want the compiler to optimise for the host’s micro‑architecture without enabling its extra instructions.
- Optionally add
-mllvm -enable-llvm-asm or similar runtime dispatch mechanisms if you need optional ISA extensions at runtime.
In practice, the reproducible path is to drop -march=native entirely, pin a known -march=<cpu> that all deployment targets support, and rely on the compiler’s built‑in optimisation levels or -mtune for fine‑grained host tuning.
Quick sanity check for your build hosts
clang -march=native -### -c /dev/null
# look for the -target-cpu and -target-feature flags
Run the above on each build host you plan to use. If the -target-cpu or the list of -target-feature flags differ, the binaries will not be equivalent. That is the first step to proving your build is truly reproducible.
What to ask next
Could you share the exact CPU model names of the build hosts you intend to use? Knowing whether they are, for example, Intel Skylake, AMD Rome, or ARM v8 will help us pin a baseline CPU that all of them support.