← Back to context

Comment by adev_

8 hours ago

Feedback of someone who is used to manage large (>1500) software stack in C / C++ / Fortran / Python / Rust / etc:

- (1) Provide a way to compile without internet access and specify the associated dependencies path manually. This is absolutely critical.

Most 'serious' multi-language package managers and integration systems are building in a sandbox without internet access for security reasons and reproducibility reasons.

If your build system does not allow to build offline and with manually specified dependencies, you will make life of integrators and package managers miserable and they will avoid your project.

(2) Never ever build in '-03 -march=native' by default. This is always a red flag and a sign of immaturity. People expect code to be portable and shippable.

Good default options should be CMake equivalent of "RelWithDebInfo" (meaning: -O2 -g -DNDEBUG ).

-O3 can be argued. -march=native is always always a mistake.

- (3) Allow your build tool to be built by an other build tool (e.g CMake).

Anybody caring about reproducibility will want to start from sources, not from a pre-compiled binary. This also matter for cross compilation.

- (4) Please offer a compatibility with pkg-config (https://en.wikipedia.org/wiki/Pkg-config) and if possible CPS (https://cps-org.github.io/cps/overview.html) for both consumption and generation.

They are what will allow interoperability between your system and other build systems.

- (5) last but not least: Consider seriously the cross-compilation use case.

It is common in the world of embedded systems to cross compile. Any build system that does not support cross-compilation will be de facto banned from the embedded domain.

As someone who has also spent two decades wrangling C/C++ codebases, I wholeheartedly agree with every statement here.

I have an even stronger sentiment regarding cross compilation though - In any build system, I think the distinction between “cross” and “non-cross” compilation is an anti-pattern.

Always design build systems assuming cross compilation. It hurts nothing if it just so happens that your host and target platform/architecture end up being the same, and saves you everything down the line if you need to also build binaries for something else.

  • > In any build system, I think the distinction between “cross” and “non-cross” compilation is an anti-pattern.

    This is one of the huge wins of Zig. Any Zig host compiler can produce output for any supported target. Cross compiling becomes straightforward.

> Never ever build in '-03 -march=native' by default. This is always a red flag and a sign of immaturity.

Perhaps you can see how there are some assumptions baked into that statement.

  • What assumptions would that be?

    Shipping anything built with -march=native is a horrible idea. Even on homogeneous targets like one of the clouds, you never know if they'll e.g. switch CPU vendors.

    The correct thing to do is use microarch levels (e.g. x86-64-v2) or build fully generic if the target architecture doesn't have MA levels.

    • I build on the exact hardware I intend to deploy my software to and ship it to another machine with the same specs as the one it was built on.

      I am willing to hear arguments for other approaches.

      4 replies →

  • The only time I used -march=native was for a university assignment which was built and evaluated on the same server, and it allowed juicing an extra bit of performance. Using it basically means locking the program to the current CPU only.

    However I'm not sure about -O3. I know it can make the binary larger, not sure about other downsides.

    • > The only time I used -march=native

      It is completely fine to use -march=native, just do not make it the default for someone building your project.

      That should always be something to opt-in.

      The main reason is that software are a composite of (many) components. It becomes quickly a pain in the ass of maintainability if any tiny library somewhere try to sneak in '-march=native' that will make the final binary randomly crash with an illegal instruction error if executed on any CPU that is not exactly the same than the host.

      When you design a build system configuration, think for the others first (the users of your software), and yourself after.

    • -O3 also makes build times longer (sometimes significantly), and occasionally the resulting program is actually slightly slower than -O2.

      IME -O3 should only be used if you have benchmarks that show -O3 actually produces a speedup for your specific codebase.

  • Not assumptions, experience.

    I fully concur with that whole post as someone who also maintained a C++ codebase used in production.