LOCAL_MAKEFILE:=$(MAKEFILE_LIST) # macros used all over the build system include make/macros.mk BUILDROOT ?= . # 'make spotless' is a special rule that skips most of the rest of the build system and # simply deletes everything in build-* ifeq ($(MAKECMDGOALS),spotless) spotless: rm -rf -- "$(BUILDROOT)"/build-* else ifndef LKROOT $(error please define LKROOT to the root of the lk build system) endif # any local environment overrides can optionally be placed in local.mk -include local.mk # If one of our goals (from the commandline) happens to have a # matching project/goal.mk, then we should re-invoke make with # that project name specified... project-name := $(firstword $(MAKECMDGOALS)) ifneq ($(project-name),) ifneq ($(strip $(foreach d,$(LKINC),$(wildcard $(d)/project/$(project-name).mk))),) do-nothing := 1 $(MAKECMDGOALS) _all: make-make @: make-make: @PROJECT=$(project-name) $(MAKE) -rR -f $(LOCAL_MAKEFILE) $(filter-out $(project-name), $(MAKECMDGOALS)) .PHONY: make-make endif # expansion of project-name endif # project-name != null # some additional rules to print some help include make/help.mk ifeq ($(do-nothing),) ifeq ($(PROJECT),) ifneq ($(DEFAULT_PROJECT),) PROJECT := $(DEFAULT_PROJECT) else $(error No project specified. Use 'make list' for a list of projects or 'make help' for additional help) endif # DEFAULT_PROJECT == something endif # PROJECT == null DEBUG ?= 2 BUILDDIR_SUFFIX ?= BUILDDIR := $(BUILDROOT)/build-$(PROJECT)$(BUILDDIR_SUFFIX) OUTBIN := $(BUILDDIR)/lk.bin OUTELF := $(BUILDDIR)/lk.elf CONFIGHEADER := $(BUILDDIR)/config.h GLOBAL_INCLUDES := $(BUILDDIR) $(addsuffix /include,$(LKINC)) GLOBAL_OPTFLAGS ?= $(ARCH_OPTFLAGS) GLOBAL_COMPILEFLAGS := -g -include $(CONFIGHEADER) GLOBAL_COMPILEFLAGS += -Wextra -Wall -Werror=return-type -Wshadow -Wdouble-promotion GLOBAL_COMPILEFLAGS += -Wno-multichar -Wno-unused-parameter -Wno-unused-function -Wno-unused-label GLOBAL_COMPILEFLAGS += -fno-common # Build with -ffreestanding since we are building an OS kernel and cannot # rely on all hosted environment functionality being present. GLOBAL_COMPILEFLAGS += -ffreestanding GLOBAL_CFLAGS := --std=gnu11 -Werror-implicit-function-declaration -Wstrict-prototypes -Wwrite-strings GLOBAL_CPPFLAGS := --std=c++14 -fno-exceptions -fno-rtti -fno-threadsafe-statics GLOBAL_ASMFLAGS := -DASSEMBLY GLOBAL_LDFLAGS := ifeq ($(UBSAN), 1) # Inject lib/ubsan directly into MODULE_DEPS # lib/ubsan will itself add the needed CFLAGS MODULE_DEPS += lib/ubsan endif # flags that are sometimes nice to enable to catch problems but too strict to have on all the time. # add to global flags from time to time to find things, otherwise only available with a module # option (see make/module.mk re: MODULE_OPTIONS). EXTRA_MODULE_COMPILEFLAGS := -Wmissing-declarations EXTRA_MODULE_CFLAGS := -Wmissing-prototypes EXTRA_MODULE_CPPFLAGS := EXTRA_MODULE_ASMFLAGS := #GLOBAL_COMPILEFLAGS += -Wpacked #GLOBAL_COMPILEFLAGS += -Wpadded #GLOBAL_COMPILEFLAGS += -Winline # if WERROR is set, add to the compile args ifeq (true,$(call TOBOOL,$(WERROR))) GLOBAL_COMPILEFLAGS += -Werror endif GLOBAL_LDFLAGS += $(addprefix -L,$(LKINC)) # Architecture specific compile flags ARCH_COMPILEFLAGS := ARCH_COMPILEFLAGS_NOFLOAT := # flags used when compiling with floating point support ARCH_COMPILEFLAGS_FLOAT := # flags for when not compiling with floating point support ARCH_CFLAGS := ARCH_CPPFLAGS := ARCH_ASMFLAGS := ARCH_LDFLAGS := ARCH_OBJDUMP_FLAGS := THUMBCFLAGS := # optional compile switches set by arm architecture when compiling in thumb mode # top level rule all:: $(OUTBIN) $(OUTELF).lst $(OUTELF).debug.lst $(OUTELF).sym $(OUTELF).sym.sorted $(OUTELF).size $(OUTELF).dump $(BUILDDIR)/srcfiles.txt $(BUILDDIR)/include_paths.txt # master module object list ALLMODULE_OBJS := # master object list (for dep generation) ALLOBJS := # master source file list ALLSRCS := # a linker script needs to be declared in one of the project/target/platform files LINKER_SCRIPT := # anything you add here will be deleted in make clean GENERATED := $(CONFIGHEADER) # anything added to GLOBAL_DEFINES will be put into $(BUILDDIR)/config.h GLOBAL_DEFINES := LK=1 # Anything added to GLOBAL_SRCDEPS will become a dependency of every source file in the system. # Useful for header files that may be included by one or more source files. GLOBAL_SRCDEPS := $(CONFIGHEADER) # these need to be filled out by the project/target/platform rules.mk files TARGET := PLATFORM := ARCH := ALLMODULES := # add any external module dependencies MODULES := $(EXTERNAL_MODULES) # any .mk specified here will be included before build.mk EXTRA_BUILDRULES := # any rules you put here will also be built by the system before considered being complete EXTRA_BUILDDEPS := # any rules you put here will be depended on in clean builds EXTRA_CLEANDEPS := # any objects you put here get linked with the final image EXTRA_OBJS := # any extra linker scripts to be put on the command line EXTRA_LINKER_SCRIPTS := # if someone defines this, the build id will be pulled into lib/version BUILDID ?= # comment out or override if you want to see the full output of each command NOECHO ?= @ # try to include the project file -include project/$(PROJECT).mk ifndef TARGET $(error couldn't find project or project doesn't define target) endif include target/$(TARGET)/rules.mk ifndef PLATFORM $(error couldn't find target or target doesn't define platform) endif include platform/$(PLATFORM)/rules.mk ifndef ARCH $(error couldn't find arch or platform doesn't define arch) endif include arch/$(ARCH)/rules.mk ifndef TOOLCHAIN_PREFIX $(error TOOLCHAIN_PREFIX not set in the arch rules.mk) endif # default to no ccache CCACHE ?= CC ?= $(CCACHE) $(TOOLCHAIN_PREFIX)gcc LD ?= $(TOOLCHAIN_PREFIX)ld OBJDUMP ?= $(TOOLCHAIN_PREFIX)objdump OBJCOPY ?= $(TOOLCHAIN_PREFIX)objcopy CPPFILT ?= $(TOOLCHAIN_PREFIX)c++filt SIZE ?= $(TOOLCHAIN_PREFIX)size NM ?= $(TOOLCHAIN_PREFIX)nm STRIP ?= $(TOOLCHAIN_PREFIX)strip # Detect whether we are using ld.lld. If we don't detect ld.lld, we assume # it's ld.bfd. This check can be refined in the future if we need to handle # more cases (e.g. ld.gold). LINKER_TYPE := $(shell $(LD) -v 2>&1 | grep -q "LLD" && echo lld || echo bfd) $(info LINKER_TYPE=$(LINKER_TYPE)) # Detect whether we are compiling with GCC or Clang COMPILER_TYPE := $(shell $(CC) -v 2>&1 | grep -q "clang version" && echo clang || echo gcc) $(info COMPILER_TYPE=$(COMPILER_TYPE)) # Now that CC is defined we can check if warning flags are supported and add # them to GLOBAL_COMPILEFLAGS if they are. ifeq ($(call is_warning_flag_supported,-Wnonnull-compare),yes) GLOBAL_COMPILEFLAGS += -Wno-nonnull-compare endif # Ideally we would move this check to arm64/rules.mk, but we can only check # for supported warning flags once CC is defined. ifeq ($(ARCH),arm64) # Clang incorrectly diagnoses msr operations as need a 64-bit operand even if # the underlying register is actually 32 bits. Silence this common warning. ifeq ($(call is_warning_flag_supported,-Wasm-operand-widths),yes) ARCH_COMPILEFLAGS += -Wno-asm-operand-widths endif endif ifeq ($(ARCH),riscv) # ld.lld does not support linker relaxations yet. # TODO: This is no longer true as of LLVM 15, so should add a version check ifeq ($(LINKER_TYPE),lld) ARCH_COMPILEFLAGS += -mno-relax # Work around out-of-range undef-weak relocations when building with clang and # linking with ld.lld. This is not a problem with ld.bfd since ld.bfd rewrites # the instructions to avoid the out-of-range PC-relative relocation # See https://github.com/riscv-non-isa/riscv-elf-psabi-doc/issues/126 for more # details. For now, the simplest workaround is to build with -fpie when using # a version of clang that does not include https://reviews.llvm.org/D107280. # TODO: Add a clang 17 version check now that the review has been merged. ifeq ($(COMPILER_TYPE),clang) # We also add the -fdirect-access-external-data flag is added to avoid the # majority of the performance overhead caused by -fPIE. ARCH_COMPILEFLAGS += -fPIE -fdirect-access-external-data endif endif endif $(info PROJECT = $(PROJECT)) $(info PLATFORM = $(PLATFORM)) $(info TARGET = $(TARGET)) $(info ARCH = $(ARCH)) $(info TOOLCHAIN_PREFIX = $(TOOLCHAIN_PREFIX)) $(info DEBUG = $(DEBUG)) # include the top level module that includes basic always-there modules include top/rules.mk # recursively include any modules in the MODULE variable, leaving a trail of included # modules in the ALLMODULES list include make/recurse.mk # add some automatic configuration defines GLOBAL_DEFINES += \ PROJECT_$(PROJECT)=1 \ PROJECT=\"$(PROJECT)\" \ TARGET_$(TARGET)=1 \ TARGET=\"$(TARGET)\" \ PLATFORM_$(PLATFORM)=1 \ PLATFORM=\"$(PLATFORM)\" \ ARCH_$(ARCH)=1 \ ARCH=\"$(ARCH)\" \ $(addsuffix =1,$(addprefix WITH_,$(ALLMODULES))) # debug build? ifneq ($(DEBUG),) GLOBAL_DEFINES += \ LK_DEBUGLEVEL=$(DEBUG) endif # allow additional defines from outside the build system ifneq ($(EXTERNAL_DEFINES),) GLOBAL_DEFINES += $(EXTERNAL_DEFINES) $(info EXTERNAL_DEFINES = $(EXTERNAL_DEFINES)) endif # prefix all of the paths in GLOBAL_INCLUDES with -I GLOBAL_INCLUDES := $(addprefix -I,$(GLOBAL_INCLUDES)) # test for some old variables ifneq ($(INCLUDES),) $(error INCLUDES variable set, please move to GLOBAL_INCLUDES: $(INCLUDES)) endif ifneq ($(DEFINES),) $(error DEFINES variable set, please move to GLOBAL_DEFINES: $(DEFINES)) endif # try to have the compiler output colorized error messages if available export GCC_COLORS ?= 1 # the logic to compile and link stuff is in here include make/build.mk DEPS := $(ALLOBJS:%o=%d) # put all of the global build flags in config.h to force a rebuild if any change GLOBAL_DEFINES += GLOBAL_INCLUDES=\"$(subst $(SPACE),_,$(GLOBAL_INCLUDES))\" GLOBAL_DEFINES += GLOBAL_COMPILEFLAGS=\"$(subst $(SPACE),_,$(GLOBAL_COMPILEFLAGS))\" GLOBAL_DEFINES += GLOBAL_OPTFLAGS=\"$(subst $(SPACE),_,$(GLOBAL_OPTFLAGS))\" GLOBAL_DEFINES += GLOBAL_CFLAGS=\"$(subst $(SPACE),_,$(GLOBAL_CFLAGS))\" GLOBAL_DEFINES += GLOBAL_CPPFLAGS=\"$(subst $(SPACE),_,$(GLOBAL_CPPFLAGS))\" GLOBAL_DEFINES += GLOBAL_ASMFLAGS=\"$(subst $(SPACE),_,$(GLOBAL_ASMFLAGS))\" GLOBAL_DEFINES += GLOBAL_LDFLAGS=\"$(subst $(SPACE),_,$(GLOBAL_LDFLAGS))\" GLOBAL_DEFINES += ARCH_COMPILEFLAGS=\"$(subst $(SPACE),_,$(ARCH_COMPILEFLAGS))\" GLOBAL_DEFINES += ARCH_CFLAGS=\"$(subst $(SPACE),_,$(ARCH_CFLAGS))\" GLOBAL_DEFINES += ARCH_CPPFLAGS=\"$(subst $(SPACE),_,$(ARCH_CPPFLAGS))\" GLOBAL_DEFINES += ARCH_ASMFLAGS=\"$(subst $(SPACE),_,$(ARCH_ASMFLAGS))\" GLOBAL_DEFINES += ARCH_LDFLAGS=\"$(subst $(SPACE),_,$(ARCH_LDFLAGS))\" GLOBAL_DEFINES += TOOLCHAIN_PREFIX=\"$(subst $(SPACE),_,$(TOOLCHAIN_PREFIX))\" ifneq ($(OBJS),) $(warning OBJS=$(OBJS)) $(error OBJS is not empty, please convert to new module format) endif ifneq ($(OPTFLAGS),) $(warning OPTFLAGS=$(OPTFLAGS)) $(error OPTFLAGS is not empty, please use GLOBAL_OPTFLAGS or MODULE_OPTFLAGS) endif ifneq ($(CFLAGS),) $(warning CFLAGS=$(CFLAGS)) $(error CFLAGS is not empty, please use GLOBAL_CFLAGS or MODULE_CFLAGS) endif ifneq ($(CPPFLAGS),) $(warning CPPFLAGS=$(CPPFLAGS)) $(error CPPFLAGS is not empty, please use GLOBAL_CPPFLAGS or MODULE_CPPFLAGS) endif $(info LIBGCC = $(LIBGCC)) $(info GLOBAL_COMPILEFLAGS = $(GLOBAL_COMPILEFLAGS)) $(info GLOBAL_OPTFLAGS = $(GLOBAL_OPTFLAGS)) # make all object files depend on any targets in GLOBAL_SRCDEPS $(ALLOBJS): $(GLOBAL_SRCDEPS) # any extra top level build dependencies that someone declared. # build.mk may add to EXTRA_BUILDDEPS, this must be evalauted after build.mk. all:: $(EXTRA_BUILDDEPS) clean: $(EXTRA_CLEANDEPS) rm -f $(ALLOBJS) $(DEPS) $(GENERATED) $(OUTBIN) $(OUTELF) $(OUTELF).lst $(OUTELF).debug.lst $(OUTELF).sym $(OUTELF).sym.sorted $(OUTELF).size $(OUTELF).hex $(OUTELF).dump install: all scp $(OUTBIN) 192.168.0.4:/tftpboot list-arch: @echo ARCH = ${ARCH} list-toolchain: @echo TOOLCHAIN_PREFIX = ${TOOLCHAIN_PREFIX} .PHONY: all clean install list-arch list-toolchain # generate a config.h file with all of the GLOBAL_DEFINES laid out in #define format configheader: $(CONFIGHEADER): configheader @$(call MAKECONFIGHEADER,$@,GLOBAL_DEFINES) .PHONY: configheader # Empty rule for the .d files. The above rules will build .d files as a side # effect. Only works on gcc 3.x and above, however. %.d: ifeq ($(filter $(MAKECMDGOALS), clean), ) -include $(DEPS) endif endif # do-nothing = 1 endif # make spotless