Linux/Unix internals: x86_64 CFLAGS/CXXFLAGS

Published: December 29th, 2024

Updated: July 3rd, 2025

As I’ve used Gentoo, I’ve become curious about what kinds of interesting build flags other systems use to compile their binaries on a global level, as well as what configure-time flags they set on GNU Compiler Collection (GCC) and Clang. This article collects these flags for some distributions to make them easier for me to track down and compare in the future.

Because this is a rabbit hole, there are some things I won’t be doing in the interest of time. They’re listed in the Caveats section.

Some relevant documentation can be found in these places:

Table of contents

Arch

According to this poster, the build flags can be found in the x86_64.conf file in the devtools package.

CFLAGS:

-march=x86-64
-mtune=generic
-O2
-pipe
-fno-plt
-fexceptions
-Wp,-D_FORTIFY_SOURCE=3
-Wformat
-Werror=format-security
-fstack-clash-protection
-fcf-protection
-fno-omit-frame-pointer
-mno-omit-leaf-frame-pointer

CXXFLAGS:

$CFLAGS
-Wp,-D_GLIBCXX_ASSERTIONS

LDFLAGS:

-Wl,-O1
-Wl,--sort-common
-Wl,--as-needed
-Wl,-z,relro
-Wl,-z,now
-Wl,-z,pack-relative-relocs

LTOFLAGS:

-flto=auto

Here are the configure-time GCC flags for Arch.

Here are the configure-time Clang flags for Arch.

Here are the configure-time Low Level Virtual Machine (LLVM) flags for Arch.

Alpine

Alpine compiles packages using abuild. The default.conf file contains the compiler flags used for the distribution.

CFLAGS:

-Os
-fstack-clash-protection
-Wformat
-Werror=format-security

CXXFLAGS:

-Os
-fstack-clash-protection
-Wformat
-Werror=format-security
-D_GLIBCXX_ASSERTIONS=1
-D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS=1
-D_LIBCPP_ENABLE_HARDENED_MODE=1

LDFLAGS:

-Wl,--as-needed,-O1,--sort-common

GCC configuration for Alpine.

Clang configuration for Alpine.

LLVM configuration for Alpine.

This discussion has some interesting details.

Clear Linux

The performance section in the documentation lays everything out nicely.

For x86_64, here is what that looks like:

-O2
-g
-feliminate-unused-debug-types
-pipe
-Wall
-Wp,-D_FORTIFY_SOURCE=2
-fexceptions
-fstack-protector
--param=ssp-buffer-size=64
-Wformat
-Wformat-security
-Wl,-z,now,-z,relro,-z,max-page-size=0x4000,-z,separate-code
-Wno-error
-ftree-vectorize
-ftree-slp-vectorize
-Wl,--enable-new-dtags
-Wl,--build-id=sha1
-ftrivial-auto-var-init=zero
-mrelax-cmpxchg-loop
-m64
-march=westmere
-mtune=skylake-avx512
-fasynchronous-unwind-tables
-Wp,-D_REENTRANT

The configuration contains some interesting flags. Two flags in particular I find noteworthy: -ftrivial-auto-var-init=zero and -mrelax-cmpxchg-loop.

-ftrivial-auto-var-init is a security-related flag. I’ve heard that both ChromiumOS and Android use that flag in some form. Gentoo may add it to their hardened builds, at least this open bug suggests so.

-mrelax-cmpxchg-loop relaxes spin loops in certain conditions, benefiting thread synchronization. Here is the GCC bug where it’s discussed. Intel discusses it here.

The question of compiler configure-time flags for Clear Linux gets complicated, because they have separate GCC builds for Advanced Vector Extensions 2 (AVX2) and Advanced Vector Extensions 512 (AVX512) Here are the configure-time flags for the main GCC build.

Similar situation for Clang. Here are the Clear Linux configuration-time flags for Clang/LLVM.

I’m breaking a rule I made for myself a little bit (no per-package CFLAGS/CXXFLAGS reviewing) to discuss some interesting tweaks Clear Linux does. autospec is at the heart of this. A couple of interesting things about autospec and the packages in clearlinux-pkgs:

There’s a lot to learn from this distribution.

Debian

dpkg-buildflags is a Perl script, provided by the dpkg-dev package. A lot of the heavy lifting gets done by the libraries sourced by the script, which live in /usr/share/perl5/Dpkg. Those libraries come from the libdpkg-perl package (a dependency of dpkg-dev).

Debian 12 (Bookworm).

$ dpkg-buildflags --query
Vendor: Debian
Environment:

Area: future
Features:
 lfs=no
Builtins:

Area: hardening
Features:
 bindnow=no
 format=yes
 fortify=yes
 pie=yes
 relro=yes
 stackprotector=yes
 stackprotectorstrong=yes
Builtins:
 pie=yes

Area: optimize
Features:
 lto=no
Builtins:

Area: qa
Features:
 bug=no
 canary=no
Builtins:

Area: reproducible
Features:
 fixdebugpath=yes
 fixfilepath=yes
 timeless=yes
Builtins:

Area: sanitize
Features:
 address=no
 leak=no
 thread=no
 undefined=no
Builtins:

Flag: ASFLAGS
Value:
Origin: vendor

Flag: CFLAGS
Value: -g -O2 -ffile-prefix-map=/home/user=. -fstack-protector-strong -Wformat -Werror=format-security
Origin: vendor

Flag: CPPFLAGS
Value: -Wdate-time -D_FORTIFY_SOURCE=2
Origin: vendor

Flag: CXXFLAGS
Value: -g -O2 -ffile-prefix-map=/home/user=. -fstack-protector-strong -Wformat -Werror=format-security
Origin: vendor

Flag: DFLAGS
Value: -frelease
Origin: vendor

Flag: FCFLAGS
Value: -g -O2 -ffile-prefix-map=/home/user=. -fstack-protector-strong
Origin: vendor

Flag: FFLAGS
Value: -g -O2 -ffile-prefix-map=/home/user=. -fstack-protector-strong
Origin: vendor

Flag: GCJFLAGS
Value: -g -O2 -ffile-prefix-map=/home/user=. -fstack-protector-strong
Origin: vendor

Flag: LDFLAGS
Value: -Wl,-z,relro
Origin: vendor

Flag: OBJCFLAGS
Value: -g -O2 -ffile-prefix-map=/home/user=. -fstack-protector-strong -Wformat -Werror=format-security
Origin: vendor

Flag: OBJCXXFLAGS
Value: -g -O2 -ffile-prefix-map=/home/user=. -fstack-protector-strong -Wformat -Werror=format-security
Origin: vendor

Debian’s GCC configure-time flags can be found in this file, stored in the CONFARGS variable.

Debian’s Clang/LLVM configure-time flags.

Fedora

Obtained via Red Hat Package Manager (RPM) macros.

Build flags docs here.

These commands were run in a Fedora 40 virtual machine.

$ rpm --eval "%{optflags}" | tr ' ' '\n' | grep -v '^$'
-O2
-flto=auto
-ffat-lto-objects
-fexceptions
-g
-grecord-gcc-switches
-pipe
-Wall
-Wno-complain-wrong-lang
-Werror=format-security
-Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3
-Wp,-D_GLIBCXX_ASSERTIONS
-specs=/usr/lib/rpm/redhat/redhat-hardened-cc1
-fstack-protector-strong
-specs=/usr/lib/rpm/redhat/redhat-annobin-cc1
-m64
-march=x86-64
-mtune=generic
-fasynchronous-unwind-tables
-fstack-clash-protection
-fcf-protection
-fno-omit-frame-pointer
-mno-omit-leaf-frame-pointer
$ rpm --eval "%{build_ldflags}" | tr ' ' '\n' | grep -v '^$'
-Wl,-z,relro
-Wl,--as-needed
-Wl,-z,pack-relative-relocs
-Wl,-z,now
-specs=/usr/lib/rpm/redhat/redhat-hardened-ld
-specs=/usr/lib/rpm/redhat/redhat-annobin-cc1
-Wl,--build-id=sha1

Fedora’s GCC configure-time flags.

Fedora’s Clang configure-time flags.

Gentoo

/etc/portage/make.conf. But additional flags get set implicitly as well. The settings depend on things like what USE flags get set, as an example.

The build flags mainly live in toolchain.eclass. Gentoo’s configure-time flags for GCC live in toolchain.eclass as well.

The referenced patches can be found here.

Current GCC.

Current Clang.

Current LLVM.

The hardened toolchain changes table in Project:Toolchain is worth mentioning as well.

While on the subject of Gentoo, ChromiumOS is interesting to think about. ChromiumOS is the open source base for ChromeOS on Chromebooks. It uses Portage, Gentoo’s package management system. I haven’t looked into it enough to offer insightful commentary on it—I’d have to sift through a lot of code to talk about it halfway intelligently.

NixOS

I’m presuming something here: that NixOS doesn’t add CFLAGS/CXXFLAGS beyond what nixpkgs does. I don’t see why it would, after all, but I felt it was important to note that all the same.

Hardening flags get mentioned here.

Here are the ones used by default at the time of writing (I verified this by copying the .nix file from this guide and setting NIX_DEBUG = 2; in the pkgs.stdenv.mkDerivation section, then built the package):

-fPIC
-Wformat
-Wformat-security
-Werror=format-security
-fstack-protector-strong
--param ssp-buffer-size=4
-O2
-D_FORTIFY_SOURCE=2
-fno-strict-overflow
-Wl,-z,relro
-Wl,-z,now

If -fzero-call-used-regs=used-gpr gets used, it wasn’t printed during the test build.

GCC nixpkg.

Clang nixpkg.

LLVM nixpkg.

OpenBSD

Local changes to their integrated (and old) version of GCC get described in gcc-local. The same applies to clang-local, although it’s a current version.

OpenBSD’s GCC port and OpenBSD’s LLVM port.

Here is the source code for OpenBSD’s version of LLVM/Clang. Same for GCC.

OpenSUSE

Line 3581 here should list the options. OpenSUSE:Factory is what they use to build Tumbleweed packages.

-O2
-Wall
-U_FORTIFY_SOURCE
-D_FORTIFY_SOURCE=3
-fstack-protector-strong
-funwind-tables
-fasynchronous-unwind-tables
-fstack-clash-protection
-Werror=return-type
%%{?_lto_cflags}

There is a dummy package for GCC here, and ditto for clang/llvm. At the time of writing, the relevant versions are 14 and 19, respectively.

So, OpenSUSE’s GCC configure-time flags can be found here. Starts on line 2510.

OpenSUSE’s Clang configure-time flags can be found here. Starts on line 1092.

Solus

These flags come from this GitHub issue. From what I can tell, the flags get set by ypkg. Specifically, ypkgcontext.py.

To get the latest flags, I guess one would have to figure out how to get ypkg (or some other piece of the Solus build system) to output them somehow. I haven’t done so, but it certainly seems possible.

CFLAGS:

-mtune=generic
-march=x86-64
-g2
-O2
-pipe
-fno-plt
-fPIC
-Wformat
-Wformat-security
-D_FORTIFY_SOURCE=2
-fstack-protector-strong
--param=ssp-buffer-size=32
-fasynchronous-unwind-tables
-ftree-vectorize
-feliminate-unused-debug-types
-Wall
-Wno-error
-Wp,-D_REENTRANT

CXXFLAGS:

-mtune=generic
-march=x86-64
-g2
-O2
-pipe
-fno-plt
-fPIC
-D_FORTIFY_SOURCE=2
-fstack-protector-strong
--param=ssp-buffer-size=32
-fasynchronous-unwind-tables
-ftree-vectorize
-feliminate-unused-debug-types
-Wall
-Wno-error
-Wp,-D_REENTRANT

LDFLAGS:

-Wl,--copy-dt-needed-entries
-Wl,-O1
-Wl,-z,relro
-Wl,-z,now
-Wl,-z,max-page-size=0x1000
-Wl,-Bsymbolic-functions
-Wl,--sort-common

Solus’ GCC configure-time flags can be found here.

Solus’ Clang/LLVM configure-time flags can be found here.

Ubuntu

Retrieved the same way as Debian. Ubuntu 24.10 (oracular).

$ dpkg-buildflags --query
Vendor: Ubuntu
Environment:

Area: abi
Features:
 lfs=no
 time64=yes
Builtins:
 lfs=yes
 time64=yes

Area: future
Features:
 lfs=no
Builtins:

Area: hardening
Features:
 bindnow=no
 branch=yes
 format=yes
 fortify=yes
 pie=yes
 relro=yes
 stackclash=yes
 stackprotector=yes
 stackprotectorstrong=yes
Builtins:
 pie=yes

Area: optimize
Features:
 lto=yes
Builtins:

Area: qa
Features:
 bug=no
 bug-implicit-func=yes
 canary=no
 elfpackagemetadata=no
 framepointer=yes
Builtins:

Area: reproducible
Features:
 fixdebugpath=yes
 fixfilepath=yes
 timeless=yes
Builtins:

Area: sanitize
Features:
 address=no
 leak=no
 thread=no
 undefined=no
Builtins:

Flag: ASFLAGS
Value:
Origin: vendor

Flag: ASFLAGS_FOR_BUILD
Value:
Origin: vendor

Flag: CFLAGS
Value: -g -O2 -Werror=implicit-function-declaration -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=/home/ubuntu=. -flto=auto -ffat-lto-objects -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection
Origin: vendor

Flag: CFLAGS_FOR_BUILD
Value: -g -O2 -Werror=implicit-function-declaration -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=/home/ubuntu=. -flto=auto -ffat-lto-objects -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection
Origin: vendor

Flag: CPPFLAGS
Value: -Wdate-time -D_FORTIFY_SOURCE=3
Origin: vendor

Flag: CPPFLAGS_FOR_BUILD
Value: -Wdate-time -D_FORTIFY_SOURCE=3
Origin: vendor

Flag: CXXFLAGS
Value: -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=/home/ubuntu=. -flto=auto -ffat-lto-objects -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection
Origin: vendor

Flag: CXXFLAGS_FOR_BUILD
Value: -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=/home/ubuntu=. -flto=auto -ffat-lto-objects -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection
Origin: vendor

Flag: DFLAGS
Value: -frelease
Origin: vendor

Flag: DFLAGS_FOR_BUILD
Value: -frelease
Origin: vendor

Flag: FCFLAGS
Value: -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=/home/ubuntu=. -flto=auto -ffat-lto-objects -fstack-protector-strong -fstack-clash-protection -fcf-protection
Origin: vendor

Flag: FCFLAGS_FOR_BUILD
Value: -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=/home/ubuntu=. -flto=auto -ffat-lto-objects -fstack-protector-strong -fstack-clash-protection -fcf-protection
Origin: vendor

Flag: FFLAGS
Value: -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=/home/ubuntu=. -flto=auto -ffat-lto-objects -fstack-protector-strong -fstack-clash-protection -fcf-protection
Origin: vendor

Flag: FFLAGS_FOR_BUILD
Value: -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=/home/ubuntu=. -flto=auto -ffat-lto-objects -fstack-protector-strong -fstack-clash-protection -fcf-protection
Origin: vendor

Flag: LDFLAGS
Value: -Wl,-Bsymbolic-functions -flto=auto -ffat-lto-objects -Wl,-z,relro
Origin: vendor

Flag: LDFLAGS_FOR_BUILD
Value: -flto=auto -ffat-lto-objects -Wl,-z,relro
Origin: vendor

Flag: OBJCFLAGS
Value: -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=/home/ubuntu=. -flto=auto -ffat-lto-objects -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection
Origin: vendor

Flag: OBJCFLAGS_FOR_BUILD
Value: -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=/home/ubuntu=. -flto=auto -ffat-lto-objects -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection
Origin: vendor

Flag: OBJCXXFLAGS
Value: -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=/home/ubuntu=. -flto=auto -ffat-lto-objects -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection
Origin: vendor

Flag: OBJCXXFLAGS_FOR_BUILD
Value: -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=/home/ubuntu=. -flto=auto -ffat-lto-objects -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection
Origin: vendor

Flag: RUSTFLAGS
Value: -Cforce-frame-pointers=yes
Origin: vendor

Flag: RUSTFLAGS_FOR_BUILD
Value:
Origin: vendor

Ubuntu Oracular GCC version appears to be 14. Here is the relevant Ubuntu GCC file that I figured that out from. Ditto for Clang/LLVM, which appears to be 19.

Ubuntu’s GCC configure-time flags begin here.

Ubuntu’s LLVM configure-time flags can be found here.

Void

I found these by reasoning out what these files in the void-packages repo set:

CFLAGS:

-mtune=generic
-O2
-pipe
-fstack-clash-protection
-D_FORTIFY_SOURCE=2

CXXFLAGS:

-mtune=generic
-O2
-pipe
-fstack-clash-protection
-D_FORTIFY_SOURCE=2

LDFLAGS:

-Wl,--as-needed
-Wl,-z,relro
-Wl,-z,now

Void’s GCC configure-time flags can be found here.

Void’s Clang configure-time flags can be found here. The main version of clang used by the distro can be found in the llvm package template.

Caveats

Here are things I haven’t done, and why I haven’t done them.

My approach favored coverage, not extreme precision. I gathered compilation flags that I could find in a configuration file (the equivalent of /etc/portage/make.conf for other distributions), through some light source code reading, or by executing some utility. I had to limit myself in some ways because otherwise it was unlikely that I’d release this article anytime soon.

Please don’t take what I’ve written here as gospel. Something being absent doesn’t necessarily prove anything, as the distribution may have enabled it in a place that I didn’t look. However, something being present and reflected in the linked source code does prove that a distribution uses it in that context, or at least used it at the time of writing.

Areas for improvement

Other resources