diff options
| author | Richard Qin <richard.qin.x@gmail.com> | 2026-07-10 23:20:03 +0800 |
|---|---|---|
| committer | Richard Qin <richard.qin.x@gmail.com> | 2026-07-10 23:20:03 +0800 |
| commit | 48ef95c24e9ac3d11200b61af617a01b10b507d1 (patch) | |
| tree | 57f0e26ab98e795b19839b6eece98ca58a4b702d /scripts/build | |
| parent | b9ff206e6bd3f4d67851263a6f2acb5f575cf3b0 (diff) | |
| download | lume-48ef95c24e9ac3d11200b61af617a01b10b507d1.tar.gz lume-48ef95c24e9ac3d11200b61af617a01b10b507d1.tar.xz | |
build: introduce declarative non-recursive build graph
Diffstat (limited to 'scripts/build')
| -rw-r--r-- | scripts/build/Build.mk | 10 | ||||
| -rwxr-xr-x | scripts/build/archive.sh | 10 | ||||
| -rwxr-xr-x | scripts/build/check-kernel-elf.sh | 47 | ||||
| -rw-r--r-- | scripts/build/environments/host.mk | 8 | ||||
| -rw-r--r-- | scripts/build/environments/kernel.mk | 28 | ||||
| -rw-r--r-- | scripts/build/environments/phys.mk | 12 | ||||
| -rwxr-xr-x | scripts/build/generate-asm-offsets.sh | 25 | ||||
| -rwxr-xr-x | scripts/build/generate-autoconf.sh | 29 | ||||
| -rwxr-xr-x | scripts/build/generate-initramfs.sh | 12 | ||||
| -rwxr-xr-x | scripts/build/link-kernel.sh | 10 | ||||
| -rwxr-xr-x | scripts/build/probe-toolchain.sh | 48 | ||||
| -rwxr-xr-x | scripts/build/run-if-changed.sh | 45 | ||||
| -rw-r--r-- | scripts/build/targets.mk | 81 | ||||
| -rw-r--r-- | scripts/build/tests/host_library.cc | 8 | ||||
| -rw-r--r-- | scripts/build/tests/host_test.cc | 7 | ||||
| -rw-r--r-- | scripts/build/tests/phys_library.cc | 5 | ||||
| -rw-r--r-- | scripts/build/toolchain.mk | 103 | ||||
| -rwxr-xr-x | scripts/build/write-compdb.py | 26 |
18 files changed, 514 insertions, 0 deletions
diff --git a/scripts/build/Build.mk b/scripts/build/Build.mk new file mode 100644 index 0000000..0a15b38 --- /dev/null +++ b/scripts/build/Build.mk @@ -0,0 +1,10 @@ +targets += build/host-library-smoke build/host-test-smoke build/phys-library-smoke +target.build/host-library-smoke.kind := host-library +target.build/host-library-smoke.sources := scripts/build/tests/host_library.cc + +target.build/host-test-smoke.kind := host-test +target.build/host-test-smoke.sources := scripts/build/tests/host_test.cc +target.build/host-test-smoke.private-deps := build/host-library-smoke + +target.build/phys-library-smoke.kind := phys-library +target.build/phys-library-smoke.sources := scripts/build/tests/phys_library.cc diff --git a/scripts/build/archive.sh b/scripts/build/archive.sh new file mode 100755 index 0000000..79f0bb9 --- /dev/null +++ b/scripts/build/archive.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later + +set -eu +archive=$1 +ar=$2 +shift 2 +rm -f "$archive" +"$ar" rcs "$archive" "$@" + diff --git a/scripts/build/check-kernel-elf.sh b/scripts/build/check-kernel-elf.sh new file mode 100755 index 0000000..eb92b33 --- /dev/null +++ b/scripts/build/check-kernel-elf.sh @@ -0,0 +1,47 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later + +set -eu +elf=$1 +readelf=$2 +nm=$3 +arch=$4 + +case "$arch" in + riscv) expected_machine='RISC-V' ;; + aarch64) expected_machine='AArch64' ;; + x86_64) expected_machine='Advanced Micro Devices X86-64' ;; + *) echo "ELF check: unsupported architecture: $arch" >&2; exit 2 ;; +esac + +machine=$($readelf -h "$elf" | sed -n 's/^[[:space:]]*Machine:[[:space:]]*//p') +[ "$machine" = "$expected_machine" ] || { + echo "ELF check: expected machine '$expected_machine', got '$machine'" >&2 + exit 1 +} + +entry=$($readelf -h "$elf" | sed -n 's/^[[:space:]]*Entry point address:[[:space:]]*//p') +[ -n "$entry" ] && [ "$entry" != 0x0 ] || { + echo "ELF check: kernel has no entry point" >&2 + exit 1 +} + +undefined=$($nm -u "$elf" || true) +[ -z "$undefined" ] || { + echo "ELF check: undefined symbols:" >&2 + printf '%s\n' "$undefined" >&2 + exit 1 +} + +if $readelf -W -l "$elf" | awk '$1 == "LOAD" && $0 ~ /W/ && $0 ~ /E/ { found=1 } END { exit !found }'; then + echo "ELF check: writable and executable LOAD segment" >&2 + exit 1 +fi + +$readelf -S "$elf" | grep -q '[.]rela[.]dyn' || { + echo "ELF check: missing relocation section .rela.dyn" >&2 + exit 1 +} + +echo "Kernel ELF OK: $machine, entry $entry" + diff --git a/scripts/build/environments/host.mk b/scripts/build/environments/host.mk new file mode 100644 index 0000000..0911ad3 --- /dev/null +++ b/scripts/build/environments/host.mk @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +HOSTCC ?= cc +HOSTCXX ?= c++ +HOSTAR ?= ar +HOSTCFLAGS ?= -O2 -g -Wall -Wextra +HOSTCXXFLAGS ?= $(HOSTCFLAGS) -std=c++23 + diff --git a/scripts/build/environments/kernel.mk b/scripts/build/environments/kernel.mk new file mode 100644 index 0000000..088cdf0 --- /dev/null +++ b/scripts/build/environments/kernel.mk @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +WARNINGS ?= -Wall -Wextra -Wno-unused-parameter + +ifeq ($(BUILD_VARIANT),release) +KERNEL_OPT_FLAGS := -O2 -g0 -DNDEBUG +else +KERNEL_OPT_FLAGS := -O2 -g +endif + +CFLAGS := $(WARNINGS) $(KERNEL_OPT_FLAGS) \ + -ffreestanding -nostdlib \ + -mcmodel=medany -fPIE -MMD -MP \ + $(TOOLCHAIN_CFLAGS) $(KCPPFLAGS) $(INCLUDES) \ + -I$(BUILD)/generated + +CFLAGS_LIBC := $(CFLAGS) -std=gnu23 -Iinclude/libc-shim \ + -Wno-parentheses -Wno-sign-compare + +CXXFLAGS := $(CFLAGS) $(TOOLCHAIN_CXXFLAGS) -std=c++23 \ + -fno-exceptions -fno-rtti -fno-use-cxa-atexit \ + -fno-threadsafe-statics + +# Pre-MMU assembly must never use GOT-indirect addressing. +ASFLAGS := $(filter-out -fPIE,$(CFLAGS)) -fno-pie + +LDFLAGS := -nostdlib -shared -Bsymbolic -z notext -z norelro \ + --no-dynamic-linker diff --git a/scripts/build/environments/phys.mk b/scripts/build/environments/phys.mk new file mode 100644 index 0000000..6a11c12 --- /dev/null +++ b/scripts/build/environments/phys.mk @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Early physical-address execution environment. It deliberately has no heap, +# exceptions, RTTI, thread-safe statics, or PIE/GOT assumptions. +PHYS_CFLAGS := $(WARNINGS) -Os -g -ffreestanding -nostdlib \ + -fno-pie -fno-stack-protector $(TOOLCHAIN_CFLAGS) \ + $(KCPPFLAGS) $(INCLUDES) -I$(BUILD)/generated +PHYS_CXXFLAGS := $(PHYS_CFLAGS) $(TOOLCHAIN_CXXFLAGS) -std=c++23 \ + -fno-exceptions -fno-rtti -fno-use-cxa-atexit \ + -fno-threadsafe-statics +PHYS_ASFLAGS := $(PHYS_CFLAGS) + diff --git a/scripts/build/generate-asm-offsets.sh b/scripts/build/generate-asm-offsets.sh new file mode 100755 index 0000000..4e90f94 --- /dev/null +++ b/scripts/build/generate-asm-offsets.sh @@ -0,0 +1,25 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later + +set -eu +output=$1 +assembly=$2 +sed_script=$3 +source=$4 +tmp="$output.tmp.$$" +{ + echo '/* AUTO-GENERATED — DO NOT EDIT */' + echo "/* Generated from $source */" + echo '#ifndef _LUME_GENERATED_ASM_OFFSETS_H' + echo '#define _LUME_GENERATED_ASM_OFFSETS_H' + echo + sed -n -f "$sed_script" "$assembly" + echo + echo '#endif /* _LUME_GENERATED_ASM_OFFSETS_H */' +} > "$tmp" +if [ -e "$output" ] && cmp -s "$tmp" "$output"; then + rm -f "$tmp" +else + mv -f "$tmp" "$output" +fi + diff --git a/scripts/build/generate-autoconf.sh b/scripts/build/generate-autoconf.sh new file mode 100755 index 0000000..493d630 --- /dev/null +++ b/scripts/build/generate-autoconf.sh @@ -0,0 +1,29 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later + +set -eu +output=$1 +shift +tmp="$output.tmp.$$" +mkdir -p "$(dirname "$output")" +{ + echo '/* AUTO-GENERATED — DO NOT EDIT */' + echo '#pragma once' + while [ "$#" -gt 0 ]; do + name=$1 + value=$2 + kind=$3 + shift 3 + if [ "$kind" = bool ]; then + [ "$value" = y ] && echo "#define $name 1" + else + echo "#define $name $value" + fi + done +} > "$tmp" +if [ -e "$output" ] && cmp -s "$tmp" "$output"; then + rm -f "$tmp" +else + mv -f "$tmp" "$output" +fi + diff --git a/scripts/build/generate-initramfs.sh b/scripts/build/generate-initramfs.sh new file mode 100755 index 0000000..194e206 --- /dev/null +++ b/scripts/build/generate-initramfs.sh @@ -0,0 +1,12 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later + +set -eu +generator=$1 +wrapper=$2 +output=$3 +uid=$4 +gid=$5 +source=$6 +GEN_INIT_CPIO=$generator "$wrapper" -o "$output" -u "$uid" -g "$gid" "$source" + diff --git a/scripts/build/link-kernel.sh b/scripts/build/link-kernel.sh new file mode 100755 index 0000000..31164e7 --- /dev/null +++ b/scripts/build/link-kernel.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later + +set -eu +output=$1 +size_tool=$2 +shift 2 +"$@" +"$size_tool" "$output" + diff --git a/scripts/build/probe-toolchain.sh b/scripts/build/probe-toolchain.sh new file mode 100755 index 0000000..2f1f600 --- /dev/null +++ b/scripts/build/probe-toolchain.sh @@ -0,0 +1,48 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later + +set -eu +output=$1 +cc=$2 +cxx=$3 +ld=$4 +family=$5 +target=$6 +gcc_toolchain=$7 +sysroot=$8 + +set -- +if [ "$family" = clang ]; then + set -- "$@" "--target=$target" + [ -z "$gcc_toolchain" ] || set -- "$@" "--gcc-toolchain=$gcc_toolchain" + [ -z "$sysroot" ] || set -- "$@" "--sysroot=$sysroot" +fi + +probe() { + language=$1 + standard=$2 + shift 2 + compiler=$cc + [ "$language" = c++ ] && compiler=$cxx + printf '' | "$compiler" "$@" "-std=$standard" -x "$language" \ + -fsyntax-only - >/dev/null 2>&1 +} + +tmp="$output.tmp.$$" +mkdir -p "$(dirname "$output")" +{ + echo "cc=$($cc --version | head -n 1)" + echo "cxx=$($cxx --version | head -n 1)" + echo "ld=$($ld --version | head -n 1)" + echo "target=$target" + printf 'c23='; if probe c gnu23 "$@"; then echo yes; else echo no; fi + printf 'cxx23='; if probe c++ c++23 "$@"; then echo yes; else echo no; fi + printf 'fno-pie='; if probe c++ c++23 "$@" -fno-pie; then echo yes; else echo no; fi + printf 'mcmodel-medany='; if probe c++ c++23 "$@" -mcmodel=medany; then echo yes; else echo no; fi +} > "$tmp" +mv -f "$tmp" "$output" + +grep -q '^c23=yes$' "$output" +grep -q '^cxx23=yes$' "$output" +grep -q '^fno-pie=yes$' "$output" +grep -q '^mcmodel-medany=yes$' "$output" diff --git a/scripts/build/run-if-changed.sh b/scripts/build/run-if-changed.sh new file mode 100755 index 0000000..6cdc7c4 --- /dev/null +++ b/scripts/build/run-if-changed.sh @@ -0,0 +1,45 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later + +set -eu + +cmdfile=$1 +output=$2 +description=$3 +shift 3 + +rebuild=false +if [ ! -e "$output" ] || [ ! -e "$cmdfile" ]; then + rebuild=true +fi + +while [ "$#" -gt 0 ] && [ "$1" != "--" ]; do + prerequisite=$1 + shift + if [ "$prerequisite" != FORCE ] && [ -e "$prerequisite" ] && \ + [ "$prerequisite" -nt "$output" ]; then + rebuild=true + fi +done + +[ "$#" -gt 0 ] || { echo "run-if-changed: missing --" >&2; exit 2; } +shift + +signature=$(printf '%s\0' "$@" | cksum) +old_signature= +if [ -e "$cmdfile" ]; then + old_signature=$(cat "$cmdfile") +fi +if [ "$signature" != "$old_signature" ]; then + rebuild=true +fi + +if [ "$rebuild" = true ]; then + printf ' %s\n' "$description" + mkdir -p "$(dirname "$output")" "$(dirname "$cmdfile")" + "$@" + tmp="$cmdfile.tmp.$$" + printf '%s\n' "$signature" > "$tmp" + mv -f "$tmp" "$cmdfile" +fi + diff --git a/scripts/build/targets.mk b/scripts/build/targets.mk new file mode 100644 index 0000000..1a66379 --- /dev/null +++ b/scripts/build/targets.mk @@ -0,0 +1,81 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2026 Richard Qin + +# Declarative target registry for the LumeOS build. +# +# Build.mk files populate target.<name>.* and append the name to targets. A +# target name is metadata, not a Make rule, so names may contain '/' and ':'. + +target-kinds := \ + interface-library header-library object-library source-set \ + static-library whole-archive host-library phys-library host-tool generated \ + binary-blob kernel-test host-test product +targets := +generated-actions := autoconf asm-offsets linker-script initramfs + +empty := +space := $(empty) $(empty) +comma := , + +# Convert a logical target/source name into a path-safe component. +target-key = $(subst :,_,$(subst /,_,$(1))) + +# Recursively collect a target and all of its dependencies. Dependency cycles +# are rejected separately before this is evaluated for build roots. +target-deps = $(sort $(target.$(1).deps) $(target.$(1).public-deps) \ + $(target.$(1).private-deps) $(target.$(1).interface-deps) \ + $(target.$(1).link-deps) $(target.$(1).tool-deps) \ + $(target.$(1).generated-deps) $(target.$(1).runtime-deps) \ + $(target.$(1).order-only-deps)) +target-closure = $(strip \ + $(if $(filter $(1),$(2)),$(error target dependency cycle: $(2) -> $(1))) \ + $(1) $(foreach dep,$(call target-deps,$(1)),$(call target-closure,$(dep),$(2) $(1)))) +target-link-deps = $(sort $(target.$(1).deps) $(target.$(1).public-deps) \ + $(target.$(1).private-deps) $(target.$(1).interface-deps) \ + $(target.$(1).link-deps)) +target-link-order = $(strip $(1) $(foreach dep,$(call target-link-deps,$(1)),\ + $(call target-link-order,$(dep)))) +unique-words = $(if $(strip $(1)),$(firstword $(1)) \ + $(call unique-words,$(filter-out $(firstword $(1)),$(1)))) + +duplicate-words = $(sort $(foreach word,$(1),\ + $(if $(word 2,$(filter $(word),$(1))),$(word)))) +all-target-sources = $(foreach target,$(targets),$(target.$(target).sources)) +duplicate-target-sources = $(call duplicate-words,$(all-target-sources)) + +define validate-target +$(if $(filter $(target.$(1).kind),$(target-kinds)),,$(error target '$(1)' has invalid kind '$(target.$(1).kind)')) +$(if $(filter header-library interface-library product generated binary-blob,$(target.$(1).kind)),$(if $(strip $(target.$(1).sources)),$(error target '$(1)' of kind $(target.$(1).kind) declares sources),),) +$(if $(filter host-tool,$(target.$(1).kind)),$(if $(word 2,$(target.$(1).sources)),$(error host-tool '$(1)' currently requires exactly one source),),) +$(foreach src,$(target.$(1).sources),$(if $(wildcard $(src)),,$(error target '$(1)' references missing source '$(src)'))) +$(foreach dep,$(call target-deps,$(1)),$(if $(filter $(dep),$(targets)),,$(error target '$(1)' references unknown dependency '$(dep)'))) +$(foreach dep,$(call target-deps,$(1)),$(if $(strip $(target.$(dep).visibility)),\ + $(if $(filter all $(1),$(target.$(dep).visibility)),,\ + $(error target '$(1)' cannot depend on '$(dep)': visibility is '$(target.$(dep).visibility)')),)) +$(if $(filter generated,$(target.$(1).kind)),$(if $(strip $(target.$(1).outputs)),,$(error generated target '$(1)' has no outputs)),) +$(if $(filter generated,$(target.$(1).kind)),$(if $(filter $(target.$(1).action),$(generated-actions)),,$(error generated target '$(1)' has invalid action '$(target.$(1).action)')),) +endef + +define validate-targets +$(if $(strip $(targets)),,$(error no build targets were registered)) +$(if $(filter-out $(words $(sort $(targets))),$(words $(targets))),$(error duplicate build target name),) +$(foreach target,$(targets),$(call validate-target,$(target))) +endef + +# Usage requirements are deliberately separate from link inputs. Public +# include paths and defines propagate through deps; private values apply only +# while compiling the target itself. +target-public-closure = $(sort $(1) $(foreach dep,$(target.$(1).public-deps) \ + $(target.$(1).deps),$(call target-public-closure,$(dep)))) +target-public-includes = $(sort $(foreach target,$(call target-public-closure,$(1)),$(target.$(target).public-includes))) +target-public-after-includes = $(sort $(foreach target,$(call target-public-closure,$(1)),$(target.$(target).public-after-includes))) +target-public-defines = $(sort $(foreach target,$(call target-public-closure,$(1)),$(target.$(target).public-defines))) + +target-usage-roots = $(sort $(1) $(target.$(1).deps) $(target.$(1).public-deps) \ + $(target.$(1).private-deps) $(target.$(1).interface-deps)) +target-compile-includes = $(sort $(target.$(1).private-includes) \ + $(foreach root,$(call target-usage-roots,$(1)),$(call target-public-includes,$(root)))) +target-compile-after-includes = $(sort $(target.$(1).private-after-includes) \ + $(foreach root,$(call target-usage-roots,$(1)),$(call target-public-after-includes,$(root)))) +target-compile-defines = $(sort $(target.$(1).private-defines) \ + $(foreach root,$(call target-usage-roots,$(1)),$(call target-public-defines,$(root)))) diff --git a/scripts/build/tests/host_library.cc b/scripts/build/tests/host_library.cc new file mode 100644 index 0000000..c545815 --- /dev/null +++ b/scripts/build/tests/host_library.cc @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +namespace lume::build::test { + +int HostLibrarySmokeTestSymbol() { return 0; } + +} // namespace lume::build::test + diff --git a/scripts/build/tests/host_test.cc b/scripts/build/tests/host_test.cc new file mode 100644 index 0000000..6b13417 --- /dev/null +++ b/scripts/build/tests/host_test.cc @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +namespace lume::build::test { +int HostLibrarySmokeTestSymbol(); +} + +int main() { return lume::build::test::HostLibrarySmokeTestSymbol(); } diff --git a/scripts/build/tests/phys_library.cc b/scripts/build/tests/phys_library.cc new file mode 100644 index 0000000..2cf1596 --- /dev/null +++ b/scripts/build/tests/phys_library.cc @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +extern "C" unsigned long LumePhysBuildSmoke(unsigned long value) { + return value ^ 0x4c554d45UL; +} diff --git a/scripts/build/toolchain.mk b/scripts/build/toolchain.mk new file mode 100644 index 0000000..49d4f0a --- /dev/null +++ b/scripts/build/toolchain.mk @@ -0,0 +1,103 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2026 Richard Qin + +# Toolchain selection: +# make GCC + GNU ld +# make LLVM=1 Clang + GNU ld +# make LLVM=1 LD_TYPE=lld Clang + LLD + +LLVM ?= 0 +LLVM_VERSION ?= 20 +LD_TYPE ?= bfd +LLVM_BINUTILS ?= 0 +CXX_STDLIB ?= libstdc++ +CXX_ABI ?= lume +COMPILER_RUNTIME ?= compiler-default + +GCC_TOOLCHAIN ?= +CROSS_COMPILE ?= + +ifeq ($(ARCH),riscv) +TARGET_TRIPLE := riscv64-unknown-linux-gnu +ifeq ($(strip $(GCC_TOOLCHAIN)),) +ifneq ($(wildcard /opt/riscv64-glibc/bin/riscv64-unknown-linux-gnu-g++),) +GCC_TOOLCHAIN := /opt/riscv64-glibc +endif +endif +ifeq ($(strip $(CROSS_COMPILE)),) +ifneq ($(strip $(GCC_TOOLCHAIN)),) +CROSS_COMPILE := $(GCC_TOOLCHAIN)/bin/$(TARGET_TRIPLE)- +else +CROSS_COMPILE := $(TARGET_TRIPLE)- +endif +endif +else ifeq ($(ARCH),aarch64) +TARGET_TRIPLE := aarch64-linux-gnu +else ifeq ($(ARCH),x86_64) +TARGET_TRIPLE := x86_64-linux-gnu +endif + +ifeq ($(strip $(CROSS_COMPILE)),) +CROSS_COMPILE := $(TARGET_TRIPLE)- +endif +ifeq ($(strip $(GCC_TOOLCHAIN)),) +GCC_TOOLCHAIN := $(patsubst %/bin/,%, $(dir $(CROSS_COMPILE))) +endif + +GCC_SYSROOT := $(strip $(shell $(CROSS_COMPILE)g++ -print-sysroot 2>/dev/null)) + +CLANG_SUFFIX := $(if $(LLVM_VERSION),-$(LLVM_VERSION),) +CLANG ?= clang$(CLANG_SUFFIX) +CLANGXX ?= clang++$(CLANG_SUFFIX) +LLD ?= ld.lld$(CLANG_SUFFIX) + +CLANG_TARGET_FLAGS := --target=$(TARGET_TRIPLE) +ifneq ($(strip $(GCC_TOOLCHAIN)),) +CLANG_TARGET_FLAGS += --gcc-toolchain=$(GCC_TOOLCHAIN) +endif +ifneq ($(strip $(GCC_SYSROOT)),) +CLANG_TARGET_FLAGS += --sysroot=$(GCC_SYSROOT) +endif + +ifeq ($(LLVM),1) +CC := $(CLANG) +CXX := $(CLANGXX) +COMPILER_FAMILY := clang +TOOLCHAIN_CFLAGS := $(CLANG_TARGET_FLAGS) +ifeq ($(CXX_STDLIB),libstdc++) +TOOLCHAIN_CXXFLAGS := -stdlib=libstdc++ +else +$(error unsupported CXX_STDLIB '$(CXX_STDLIB)' for the current imported runtime) +endif +ifeq ($(LD_TYPE),lld) +LD := $(LLD) +LINKER_FAMILY := lld +else +ifneq ($(CXX_STDLIB),libstdc++) +$(error GCC configuration currently requires CXX_STDLIB=libstdc++) +endif +LD := $(CROSS_COMPILE)ld +LINKER_FAMILY := bfd +endif +else +CC := $(CROSS_COMPILE)gcc +CXX := $(CROSS_COMPILE)g++ +LD := $(CROSS_COMPILE)ld +COMPILER_FAMILY := gcc +LINKER_FAMILY := bfd +endif + +ifeq ($(LLVM_BINUTILS),1) +AR := llvm-ar$(CLANG_SUFFIX) +NM := llvm-nm$(CLANG_SUFFIX) +OBJCOPY := llvm-objcopy$(CLANG_SUFFIX) +OBJDUMP := llvm-objdump$(CLANG_SUFFIX) +READELF := llvm-readelf$(CLANG_SUFFIX) +else +AR := $(CROSS_COMPILE)ar +NM := $(CROSS_COMPILE)nm +OBJCOPY := $(CROSS_COMPILE)objcopy +OBJDUMP := $(CROSS_COMPILE)objdump +READELF := $(CROSS_COMPILE)readelf +endif +SIZE := $(CROSS_COMPILE)size diff --git a/scripts/build/write-compdb.py b/scripts/build/write-compdb.py new file mode 100755 index 0000000..9ec5a49 --- /dev/null +++ b/scripts/build/write-compdb.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0-or-later + +import json +import pathlib +import sys + +source = pathlib.Path(sys.argv[1]) +output = pathlib.Path(sys.argv[2]) +directory = pathlib.Path.cwd() +entries = [] +for line in source.read_text().splitlines(): + file_name, object_name, command = line.split("\t", 2) + entries.append( + { + "directory": str(directory), + "file": file_name, + "output": object_name, + "command": command, + } + ) +output.parent.mkdir(parents=True, exist_ok=True) +temporary = output.with_suffix(output.suffix + ".tmp") +temporary.write_text(json.dumps(entries, indent=2) + "\n") +temporary.replace(output) + |
