flags.mk (8403B)
1 # mk/flags.mk 2 # =========================================================================== 3 # Compiler/linker flag derivation and the .build-config stamp. 4 # 5 # Consumes HOST_OS and HOST_SYSROOT_{C,LD}FLAGS from mk/env.mk and the 6 # RELEASE switch from the top-level Makefile; produces the *_CFLAGS / 7 # *_LDFLAGS the compile rules splice in. Nothing here branches on the host 8 # beyond the Darwin dead-strip choice. 9 10 ifeq ($(RELEASE),1) 11 HOST_OPTFLAGS ?= -O2 12 HOST_MODE_CPPFLAGS = -DNDEBUG 13 HOST_MODE_CFLAGS = -ffunction-sections -fdata-sections 14 # PROFILE=1: an optimized build that stays profileable. Keeps -g/DWARF + frame 15 # pointers and skips the -Wl,-S debug strip so sampling profilers (e.g. 16 # `make bench-cc`) can attribute hotspots to functions and source lines. Codegen 17 # is unchanged (-O2), so timings still reflect the shipped release. 18 ifeq ($(PROFILE),1) 19 HOST_MODE_CFLAGS += -g -fno-omit-frame-pointer 20 endif 21 ifeq ($(HOST_OS),darwin) 22 HOST_MODE_LDFLAGS = -Wl,-dead_strip 23 else 24 HOST_MODE_LDFLAGS = -Wl,--gc-sections 25 endif 26 ifneq ($(PROFILE),1) 27 HOST_MODE_LDFLAGS += -Wl,-S 28 endif 29 else 30 HOST_OPTFLAGS ?= -O0 31 HOST_MODE_CPPFLAGS = 32 HOST_MODE_CFLAGS = -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls \ 33 -fsanitize=address,undefined \ 34 -fno-sanitize-recover=address,undefined \ 35 -fsanitize-address-use-after-scope 36 HOST_MODE_LDFLAGS = -fsanitize=address,undefined 37 ASAN_OPTIONS ?= halt_on_error=1:abort_on_error=1 38 UBSAN_OPTIONS ?= halt_on_error=1:print_stacktrace=1 39 export ASAN_OPTIONS UBSAN_OPTIONS 40 endif 41 42 # HOST_SYSROOT_{C,LD}FLAGS come from env.mk: a `-isysroot <path>` pair on 43 # Darwin, empty elsewhere. Stage/bootstrap recipes can clear these when 44 # kit itself is the compiler. 45 46 # Auto-initialize automatic (stack) variables to zero. Hardening that defines 47 # the otherwise-UB of reading an uninitialized local — the same default the 48 # Linux kernel / Android / Chrome ship; =zero is deterministic and effectively 49 # free at our opt levels. Probed so a compiler without the flag — notably 50 # $(CC)=kit cc in bootstrap stages — simply omits it instead of erroring. 51 AUTO_INIT_CFLAGS = $(shell $(CC) -ftrivial-auto-var-init=zero -x c -E /dev/null >/dev/null 2>&1 && printf '%s' -ftrivial-auto-var-init=zero) 52 53 CFLAGS_COMMON = $(HOST_OPTFLAGS) $(HOST_MODE_CPPFLAGS) $(HOST_MODE_CFLAGS) \ 54 $(AUTO_INIT_CFLAGS) \ 55 -std=c11 -Wpedantic -Wall -Wextra -Werror 56 HOST_CFLAGS = $(CFLAGS_COMMON) $(HOST_SYSROOT_CFLAGS) 57 HOST_LDFLAGS = $(HOST_SYSROOT_LDFLAGS) $(HOST_MODE_LDFLAGS) $(HOST_ENV_LDFLAGS) 58 59 DEPFLAGS = -MMD -MP 60 61 BUILD_CONFIG = $(BUILD_DIR)/.build-config 62 63 .PHONY: FORCE 64 FORCE: 65 66 $(BUILD_CONFIG): FORCE 67 @mkdir -p $(dir $@) 68 @tmp="$@.$$$$.tmp"; \ 69 { \ 70 printf '%s\n' 'RELEASE=$(RELEASE)'; \ 71 printf '%s\n' 'HOST_OPTFLAGS=$(HOST_OPTFLAGS)'; \ 72 printf '%s\n' 'HOST_MODE_CPPFLAGS=$(HOST_MODE_CPPFLAGS)'; \ 73 printf '%s\n' 'HOST_MODE_CFLAGS=$(HOST_MODE_CFLAGS)'; \ 74 printf '%s\n' 'HOST_MODE_LDFLAGS=$(HOST_MODE_LDFLAGS)'; \ 75 printf '%s\n' 'AUTO_INIT_CFLAGS=$(AUTO_INIT_CFLAGS)'; \ 76 } > "$$tmp"; \ 77 if ! cmp -s "$$tmp" "$@"; then mv "$$tmp" "$@"; else rm -f "$$tmp"; fi 78 79 # --- kit version / build-id (single source of truth: top-level VERSION) ----- 80 # Captured once per `make` invocation and injected only into driver/version.o 81 # (via KIT_VERSION_DEFS + the version.o rule in the Makefile), so a version bump 82 # or new commit recompiles exactly one TU rather than the world. The build id is 83 # the short git hash with a "-dirty" suffix when the tree has uncommitted 84 # tracked changes, or "unknown" without git. KIT_HOST_TRIPLE defaults to a 85 # canonical name for the build host and is overridden by the cross/release 86 # pipeline. No __DATE__/__TIME__ anywhere, and the values are stable for a given 87 # tree, so the self-host byte-identity gate is preserved. See doc/plan/SELFDIST.md. 88 KIT_VERSION := $(strip $(shell cat VERSION 2>/dev/null)) 89 ifeq ($(KIT_VERSION),) 90 KIT_VERSION := 0.0.0 91 endif 92 KIT_GIT_HASH := $(shell git rev-parse --short=7 HEAD 2>/dev/null) 93 KIT_GIT_DIRTY := $(shell git diff --quiet HEAD 2>/dev/null || printf -- '-dirty') 94 KIT_BUILD_ID := $(if $(KIT_GIT_HASH),$(KIT_GIT_HASH)$(KIT_GIT_DIRTY),unknown) 95 # Canonical host triple (matches the scripts/hosted.sh selector naming used by 96 # the release index + artifact names), derived in pure make from HOST_ARCH / 97 # HOST_OS (mk/env.mk). Overridden outright by the cross/release pipeline. 98 KIT_TRIPLE_ARCH := $(HOST_ARCH) 99 ifeq ($(HOST_ARCH),rv64) 100 KIT_TRIPLE_ARCH := riscv64 101 endif 102 KIT_TRIPLE_OS := $(HOST_OS) 103 ifeq ($(HOST_OS),darwin) 104 KIT_TRIPLE_OS := macos 105 else ifeq ($(HOST_OS),linux) 106 KIT_TRIPLE_OS := linux-gnu 107 endif 108 KIT_HOST_TRIPLE ?= $(KIT_TRIPLE_ARCH)-$(KIT_TRIPLE_OS) 109 KIT_VERSION_DEFS = -DKIT_VERSION_STR='"$(KIT_VERSION)"' \ 110 -DKIT_BUILD_ID='"$(KIT_BUILD_ID)"' \ 111 -DKIT_HOST_TRIPLE='"$(KIT_HOST_TRIPLE)"' 112 113 # A dedicated sentinel so only version.o (which lists it as a prerequisite) 114 # rebuilds when the version, commit, or host triple changes. 115 VERSION_CONFIG = $(BUILD_DIR)/.version-config 116 $(VERSION_CONFIG): FORCE 117 @mkdir -p $(dir $@) 118 @tmp="$@.$$$$.tmp"; \ 119 { \ 120 printf '%s\n' 'KIT_VERSION=$(KIT_VERSION)'; \ 121 printf '%s\n' 'KIT_BUILD_ID=$(KIT_BUILD_ID)'; \ 122 printf '%s\n' 'KIT_HOST_TRIPLE=$(KIT_HOST_TRIPLE)'; \ 123 } > "$$tmp"; \ 124 if ! cmp -s "$$tmp" "$@"; then mv "$$tmp" "$@"; else rm -f "$$tmp"; fi 125 126 # Freestanding objects must not see host SDK/libc headers. Homebrew clang can 127 # also inject a configured sysroot before command-line flags; use 128 # --no-default-config when the selected compiler supports it, but omit it for 129 # bootstrap stages where $(CC) is kit cc. 130 FREESTANDING_CONFIG_CFLAGS = $(shell $(CC) --no-default-config -x c -E /dev/null >/dev/null 2>&1 && printf '%s' --no-default-config) 131 FREESTANDING_CFLAGS = $(CFLAGS_COMMON) $(FREESTANDING_CONFIG_CFLAGS) -ffreestanding -nostdinc -Irt/include 132 133 # libkit: written in C11 freestanding; sees both src/ (internal) and 134 # include/ (its own public surface). 135 LIB_VISIBILITY_CFLAGS = -fvisibility=hidden 136 LIB_CFLAGS = $(FREESTANDING_CFLAGS) $(LIB_VISIBILITY_CFLAGS) -Iinclude -Isrc -Ivendor 137 138 # Driver: mostly freestanding CLI binary. Sees ONLY the public include/ tree — 139 # that's what makes the driver the first consumer of libkit, and the build 140 # itself enforces it: with neither -Ilang nor -Isrc, a driver source 141 # physically cannot include a frontend (lang/) or libkit-internal (src/) 142 # header, so the driver depends on nothing but the public API. 143 # 144 # driver/env/ holds all hosted OS/libc adapter code and is compiled with 145 # DRIVER_ENV_CFLAGS. The per-OS feature-test macros and the exact source 146 # list (DRIVER_ENV_OS_CFLAGS / DRIVER_ENV_SRCS) come from mk/env.mk. 147 DRIVER_CFLAGS = $(FREESTANDING_CFLAGS) -Iinclude -Idriver -Idriver/lib 148 DRIVER_ENV_CFLAGS = $(HOST_CFLAGS) -Iinclude -Idriver -Idriver/lib 149 TEST_HOST_CFLAGS = $(HOST_CFLAGS) -Iinclude -Ilang 150 151 # `kit update` release trust is generated per build. Development binaries keep 152 # the repository's explicit NON-RELEASE key solely for hermetic selfdist tests 153 # and have no default channel URL. Official RELEASE=1 binaries must be given a 154 # stable URL and one or more public-key files, and may never embed that test 155 # anchor. KIT_RELEASE_ALLOW_TEST_KEY=1 is reserved for release harnesses. 156 KIT_UPDATE_INDEX_URL ?= 157 KIT_RELEASE_PUBKEYS ?= 158 KIT_RELEASE_ALLOW_TEST_KEY ?= 0 159 ifeq ($(RELEASE),1) 160 ifeq ($(strip $(KIT_UPDATE_INDEX_URL)),) 161 $(error RELEASE=1 requires KIT_UPDATE_INDEX_URL (compiled stable channel URL)) 162 endif 163 ifeq ($(strip $(KIT_RELEASE_PUBKEYS)),) 164 $(error RELEASE=1 requires KIT_RELEASE_PUBKEYS (production Minisign public key file(s))) 165 endif 166 ifneq ($(KIT_RELEASE_ALLOW_TEST_KEY),1) 167 KIT_RELEASE_TEST_KEY_ID := $(strip $(shell sh scripts/minisign_key_id.sh test/dist/keys/nonrelease.pub 2>/dev/null)) 168 KIT_RELEASE_TEST_ANCHOR := $(strip $(foreach key,$(KIT_RELEASE_PUBKEYS),$(if $(filter $(KIT_RELEASE_TEST_KEY_ID),$(strip $(shell sh scripts/minisign_key_id.sh "$(key)" 2>/dev/null))),$(key)))) 169 ifneq ($(KIT_RELEASE_TEST_ANCHOR),) 170 $(error RELEASE=1 refuses repository NON-RELEASE test anchor: $(KIT_RELEASE_TEST_ANCHOR)) 171 endif 172 endif 173 KIT_RELEASE_PUBKEYS_EFFECTIVE := $(KIT_RELEASE_PUBKEYS) 174 else 175 KIT_RELEASE_PUBKEYS_EFFECTIVE := $(if $(strip $(KIT_RELEASE_PUBKEYS)),$(KIT_RELEASE_PUBKEYS),test/dist/keys/nonrelease.pub) 176 endif 177 178 RELEASE_CONFIG_HEADER = $(BUILD_DIR)/generated/kit_release_config.h