kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

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