# Build the kernel # Folder the generated files will be placed in. BUILDDIR ?= .build # Build folder suffixes OPTTAG = -opt NOOPTTAG = -noopt DBGTAG = -dbg VERBOSETAG = -verbose # C++ CXX = $(PREFIX)g++ CXXFLAGS_ARCH = -m64 CXXFLAGS_DEFAULT = -std=c++14 -ffreestanding -fno-pic -nodefaultlibs -nostdlib -nostdinc -I. -fno-rtti -fno-exceptions -Wno-write-strings -fno-stack-protector -mno-red-zone -g -gdwarf-2 CXXFLAGS_OPT = -O3 -fomit-frame-pointer CXXFLAGS_WARNING = -Wall -Wextra -Werror -Wno-error=unused-parameter -Wno-non-virtual-dtor CXXFLAGS_CLANG = -no-pie -Wno-error=unused-private-field -Wno-implicit-exception-spec-mismatch -Wno-error=unused-const-variable -Wno-unused-command-line-argument -Wno-unused-const-variable -fno-strict-aliasing CXXFLAGS_GCC = -fno-tree-loop-distribute-patterns -no-pie -nostartfiles -Wstack-usage=1024 -Wno-error=stack-usage= -fno-threadsafe-statics CXXFLAGS_NOFPU = -mno-mmx -mno-sse -mgeneral-regs-only CXXFLAGS = $(CXXFLAGS_ARCH) $(CXXFLAGS_DEFAULT) $(CXXFLAGS_OPT) $(CXXFLAGS_NOFPU) $(CXXFLAGS_WARNING) # Compiler specific flags ifneq (,$(findstring clang,$(CXX))) COMPILER := CLANG CXXFLAGS += $(CXXFLAGS_CLANG) else ifneq (,$(findstring g++,$(CXX))) COMPILER := GCC # g++ 6 does not support general-regs-only flag ifeq "$(shell expr `$(CXX) -dumpversion | cut -f1 -d.` \<= 6)" "1" CXXFLAGS := $(filter-out -mgeneral-regs-only,$(CXXFLAGS)) endif CXXFLAGS += $(CXXFLAGS_GCC) else COMPILER := endif # Assembly ASM = nasm ASMFLAGS = -f elf64 # Additional build utilities OBJCOPY = $(PREFIX)objcopy STRIP = $(PREFIX)strip AR = $(PREFIX)ar # C Runtime objects CRTBEGIN_OBJECT = $(shell $(CXX) $(CXXFLAGS) --print-file-name=crtbegin.o) CRTEND_OBJECT = $(shell $(CXX) $(CXXFLAGS) --print-file-name=crtend.o) # GCC library # Attention: libgcc.a must not use red-zone! LIBGCC = $(shell $(CXX) $(CXXFLAGS) -print-libgcc-file-name ) # Subdirectories with sources VPATH = $(sort $(dir $(CC_SOURCES) $(ASM_SOURCES))) # Lists of object files that are generated by compilation: # Note that the variables containing the input files are to be defined by # the Makefiles prior to including this common.mk. ifdef CRTI_SOURCE CRTI_OBJECT = $(addprefix $(BUILDDIR)/,$(addsuffix .o,$(CRTI_SOURCE))) else CRTI_OBJECT = $(shell $(CXX) $(CXXFLAGS) --print-file-name=crti.o) endif ifdef CRTN_SOURCE CRTN_OBJECT = $(addprefix $(BUILDDIR)/,$(addsuffix .o,$(CRTN_SOURCE))) else CRTN_OBJECT = $(shell $(CXX) $(CXXFLAGS) --print-file-name=crtn.o) endif CC_OBJECTS = $(addprefix $(BUILDDIR)/,$(CC_SOURCES:.cc=.o)) DEP_FILES = $(addprefix $(BUILDDIR)/,$(CC_SOURCES:.cc=.d) $(addsuffix .d,$(ASM_SOURCES))) ASM_OBJECTS = $(addprefix $(BUILDDIR)/,$(addsuffix .o,$(filter-out $(CRTI_SOURCE) $(CRTN_SOURCE),$(ASM_SOURCES)))) # Dependency files $(BUILDDIR)/%.d : %.cc $(MAKEFILE_LIST) @echo "DEP $<" @mkdir -p $(@D) $(VERBOSE) $(CXX) $(CXXFLAGS) -MM -MT $(BUILDDIR)/$*.o -MF $@ $< $(BUILDDIR)/%.asm.d : %.asm $(MAKEFILE_LIST) @echo "DEP $<" @mkdir -p $(@D) $(VERBOSE) $(ASM) $(ASMFLAGS) -M -MT $(BUILDDIR)/$*.asm.o -MF $@ $< # Object files $(BUILDDIR)/%.o : %.cc $(MAKEFILE_LIST) @echo "CXX $<" @mkdir -p $(@D) $(VERBOSE) $(CXX) -c $(CXXFLAGS) -o $@ $< $(BUILDDIR)/%.asm.o : %.asm $(MAKEFILE_LIST) @echo "ASM $<" @mkdir -p $(@D) $(VERBOSE) $(ASM) $(ASMFLAGS) -o $@ $< # The standard target 'clean' removes the whole generated system, the object files, and the dependency files. clean:: @echo "RM $(BUILDDIR)" $(VERBOSE) rm -rf "$(BUILDDIR)" "$(BUILDDIR)$(OPTTAG)" "$(BUILDDIR)$(NOOPTTAG)" "$(BUILDDIR)$(DBGTAG)" "$(BUILDDIR)$(VERBOSETAG)" # Target issuing a nested call to make generating a fully optimized systems without assertions. %$(OPTTAG): $(VERBOSE) $(MAKE) BUILDDIR="$(BUILDDIR)$(OPTTAG)" ISODIR="$(ISODIR)$(OPTTAG)" CXXFLAGS_OPT="-Ofast -fomit-frame-pointer -flto -march=westmere -DNDEBUG" $* # Target issuing a nested call to make generating a non-optimized system. %$(NOOPTTAG): $(VERBOSE) $(MAKE) BUILDDIR="$(BUILDDIR)$(NOOPTTAG)" ISODIR="$(ISODIR)$(NOOPTTAG)" CXXFLAGS_OPT="-O0" $* # Target issuing a nested call to make generating a system optimized for debugging. %$(DBGTAG): $(VERBOSE) $(MAKE) BUILDDIR="$(BUILDDIR)$(DBGTAG)" ISODIR="$(ISODIR)$(DBGTAG)" CXXFLAGS_OPT="-Og -fno-omit-frame-pointer" $* # Target issuing a nested call to make generating a system with verbose output. %$(VERBOSETAG): $(VERBOSE) $(MAKE) BUILDDIR="$(BUILDDIR)$(VERBOSETAG)" ISODIR="$(ISODIR)$(VERBOSETAG)" CXXFLAGS_OPT="-DVERBOSE" $* # Documentation help:: @/bin/echo -e "" \ "All targets exist in different flavours in addition to \e[2;3m\e[0m:\n" \ "\e[2;3m\e[0;3m-noopt\e[0m, \e[2;3m\e[0;3m-opt\e[0m, \e[2;3m\e[0;3m-dbg\e[0m, and \e[2;3m\e[0;3m-verbose\e[0m.\n" \ "Targets suffixed with \e[3m-noopt\e[0m are compiled without optimizations,\n" \ "\e[3m-opt\e[0m targets produce a highly optimized binary, while\n" \ "\e[3m-dbg\e[0m targets only use optimizations not hindering debugging.\n" \ "Targets suffixed with \e[3m-verbose\e[0m generate binaries including\n" \ "verbose output (via \e[3mDBG_VERBOSE\e[0m), making such targets useful for debugging.\n" \ "To get a verbose make output, clear VERBOSE, e.g. \e[3mmake VERBOSE=\e[0m.\n" \ "The following targets are available (each target can be suffixed by \e[3m-noopt\e[0m\n" \ "and \e[3m-verbose\e[0m):\n\n" \ " \e[3mall\e[0m Builds $(PROJECT), generating an ELF binary\n\n" # Print warnings, if appropriate ifeq (,$(COMPILER)) $(warning Unknown (and potentially unsupported) compiler "$(CXX)"!) endif # Include dependency files (generated via gcc flag -MM) ifneq ($(MAKECMDGOALS),clean) -include $(DEP_FILES) endif # Phony targets .PHONY: clean help