# Makefile for Navy Applications and Libraries ### *Get a more readable version of this Makefile* by `make html` (requires python-markdown) html: cat Makefile | sed 's/^\([^#]\)/ \1/g' | markdown_py > Makefile.html .PHONY: html ## 1. Basic Setup and Checks ### Default to build an application ifeq ($(MAKECMDGOALS),) MAKECMDGOALS = app .DEFAULT_GOAL = app endif ### Override checks when `make clean/clean-all/html/init` ifeq ($(findstring $(MAKECMDGOALS),clean|clean-all|html|init),) ### Print build info message $(info # Building $(NAME)-$(MAKECMDGOALS) [$(ISA)]) ### Check: environment variable `$NAVY_HOME` looks sane ifeq ($(wildcard $(NAVY_HOME)/libs/libos/src/syscall.h),) $(error $$NAVY_HOME must be a Navy-apps repo) endif ### Check: environment variable `$ISA` must be in the supported list ISAS = $(basename $(notdir $(shell ls $(NAVY_HOME)/scripts/*.mk))) ifeq ($(filter $(ISAS), $(ISA)), ) $(error Expected $$ISA in {$(ISAS)}, Got "$(ISA)") endif ### Checks end here endif ## 2. General Compilation Targets ### Create the destination directory (`build/$ISA`) WORK_DIR = $(shell pwd) DST_DIR = $(WORK_DIR)/build/$(ISA) $(shell mkdir -p $(DST_DIR)) ### Compilation targets (application or archive) APP ?= $(WORK_DIR)/build/$(NAME)-$(ISA) ARCHIVE = $(WORK_DIR)/build/$(NAME)-$(ISA).a ### Add default libraries for ISA != native ifneq ($(ISA), native) LIBS += libc libos libndl libbmp libminiSDL libbdf CFLAGS += -U_FORTIFY_SOURCE # fix compile error in Newlib on ubuntu else WL = -Wl, endif ### 32-bit ISA may need compiler-rt to support 64-bit mul/div ifneq ($(findstring $(ISA), x86|mips32|riscv32|riscv32e|loongarch32r),) LIBS += compiler-rt endif ### All libraries to add to the include path LIBS_INC := $(sort $(LIBS) $(LIB_DEP)) ifeq ($(MAKECMDGOALS),archive) LIBS := $(LIB_DEP) # overwrite here to only build and archive the dependent libraries endif ### Files to be linked: object files (`.o`) and libraries (`.a`) OBJS = $(addprefix $(DST_DIR)/, $(addsuffix .o, $(basename $(SRCS)))) LIBS := $(sort $(LIBS)) # lazy evaluation ("=") causes infinite recursions LINKAGE = $(OBJS) $(foreach l,$(LIBS),$(NAVY_HOME)/libs/$(l)/build/$(l)-$(ISA).a) ## 3. General Compilation Flags ### (Cross) compilers, e.g., mips-linux-gnu-g++ AS = $(CROSS_COMPILE)gcc CC = $(CROSS_COMPILE)gcc CXX = $(CROSS_COMPILE)g++ LD = $(CROSS_COMPILE)ld ### Compilation flags INC_PATH += $(WORK_DIR)/include $(foreach l,$(LIBS_INC),$(NAVY_HOME)/libs/$(l)/include/) INCFLAGS += $(addprefix -I, $(INC_PATH)) CFLAGS += -O2 -MMD $(INCFLAGS) -static -D__NAVY__ \ -D__ISA__=\"$(ISA)\" -D__ISA_$(shell echo $(ISA) | tr a-z A-Z)__ \ -fno-asynchronous-unwind-tables -fno-builtin -fno-stack-protector CXXFLAGS += $(CFLAGS) -ffreestanding -fno-rtti -fno-exceptions ASFLAGS += $(CFLAGS) ## 4. ISA-Specific Configurations ### Paste in ISA-specific configurations (e.g., from `scripts/x86.mk`) -include $(NAVY_HOME)/scripts/$(ISA).mk ## 5. Compilation Rules ### Rule (compile): a single `.c` -> `.o` (gcc) $(DST_DIR)/%.o: %.c @mkdir -p $(dir $@) && echo + CC $< @$(CC) -std=gnu11 $(CFLAGS) -c -o $@ $(realpath $<) ### Rule (compile): a single `.cc` -> `.o` (g++) $(DST_DIR)/%.o: %.cc @mkdir -p $(dir $@) && echo + CXX $< @$(CXX) -std=c++17 $(CXXFLAGS) -c -o $@ $(realpath $<) ### Rule (compile): a single `.cpp` -> `.o` (g++) $(DST_DIR)/%.o: %.cpp @mkdir -p $(dir $@) && echo + CXX $< @$(CXX) -std=c++17 $(CXXFLAGS) -c -o $@ $(realpath $<) ### Rule (compile): a single `.S` -> `.o` (gcc, which calls as) $(DST_DIR)/%.o: %.S @mkdir -p $(dir $@) && echo + AS $< @$(AS) $(ASFLAGS) -c -o $@ $(realpath $<) ### Rule (recursive make): build dependent libraries (libc, libos, ...) libs: @for t in $(LIBS); do $(MAKE) -s -C $(NAVY_HOME)/libs/$$t archive; done ### Rule (link): objects (`*.o`) and libraries (`*.a`) -> `$(APP)`, the final ELF binary to be packed into application (ld) $(APP): $(OBJS) libs @echo + LD "->" $(shell realpath $@ --relative-to .) @$(LD) $(LDFLAGS) -o $@ $(WL)--start-group $(LINKAGE) $(WL)--end-group ### Rule (archive): objects (`*.o`) -> `ARCHIVE.a` (ar) $(ARCHIVE): $(OBJS) libs @echo + AR "->" $(shell realpath $@ --relative-to .) @ar rcsT $@ $(LINKAGE) ### Rule (`#include` dependencies): paste in `.d` files generated by gcc on `-MMD` -include $(addprefix $(DST_DIR)/, $(addsuffix .d, $(basename $(SRCS)))) ## 6. Miscellaneous ### Pull newlib from github if it does not exist ifeq ($(wildcard $(NAVY_HOME)/libs/libc/Makefile),) $(shell cd $(NAVY_HOME)/libs && git clone https://www.github.com/NJU-ProjectN/newlib-navy.git libc) endif ### Build order control app: $(APP) archive: $(ARCHIVE) .PHONY: app archive libs ### Install an application to fsimg install: app @echo + INSTALL "->" $(NAME) @mkdir -p $(NAVY_HOME)/fsimg/bin @cp $(APP) $(NAVY_HOME)/fsimg/bin/$(NAME) .PHONY: install ### Clean a single project (remove `build/`) clean: rm -rf Makefile.html $(WORK_DIR)/build/ build/ .PHONY: clean ### Clean all sub-projects within depth 2 (and ignore errors) CLEAN_ALL = $(dir $(shell find . -mindepth 2 -maxdepth 3 -name Makefile)) clean-all: $(CLEAN_ALL) clean -@rm -f $(NAVY_HOME)/fsimg/bin/* $(CLEAN_ALL): -@$(MAKE) -s -C $@ clean .PHONY: clean-all $(CLEAN_ALL) ### Build fsimg and ramdisk for Nanos-lite APPS = nslider menu nterm am-kernels TESTS = dummy hello file-test timer-test event-test bmp-test fsimg: $(addprefix apps/, $(APPS)) $(addprefix tests/, $(TESTS)) -for t in $^; do $(MAKE) -s -C $(NAVY_HOME)/$$t install; done RAMDISK = build/ramdisk.img RAMDISK_H = build/ramdisk.h $(RAMDISK): fsimg $(eval FSIMG_FILES := $(shell find -L ./fsimg -type f)) @mkdir -p $(@D) @cat $(FSIMG_FILES) > $@ @truncate -s \%512 $@ @echo "// file path, file size, offset in disk" > $(RAMDISK_H) @wc -c $(FSIMG_FILES) | grep -v 'total$$' | sed -e 's+ ./fsimg+ +' | awk -v sum=0 '{print "\x7b\x22" $$2 "\x22\x2c " $$1 "\x2c " sum "\x7d\x2c";sum += $$1}' >> $(RAMDISK_H) ramdisk: $(RAMDISK) .PHONY: fsimg ramdisk