#------------------------------------------------------------------------------- # Makefile for SOURCE OBSW #------------------------------------------------------------------------------- # User-modifiable options #------------------------------------------------------------------------------- # Fundamentals on the build process of C/C++ Software: # https://www3.ntu.edu.sg/home/ehchua/programming/cpp/gcc_make.html # Make documentation: https://www.gnu.org/software/make/manual/make.pdf # Online: https://www.gnu.org/software/make/manual/make.html # General rules: http://make.mad-scientist.net/papers/rules-of-makefiles/#rule3 SHELL = /bin/sh CUSTOM_DEFINES := # Chip & board used for compilation # (can be overriden by adding CHIP=chip and BOARD=board to the command-line) BOARD_FILE_ROOT = hosted BOARD = host OS_FSFW = host CUSTOM_DEFINES += -D$(OS_FSFW) # Copied from stackoverflow, can be used to differentiate between Windows # and Linux ifeq ($(OS),Windows_NT) CUSTOM_DEFINES += -DWIN32 ifeq ($(PROCESSOR_ARCHITEW6432),AMD64) CUSTOM_DEFINES += -DAMD64 else ifeq ($(PROCESSOR_ARCHITECTURE),AMD64) CUSTOM_DEFINES += -DAMD64 endif ifeq ($(PROCESSOR_ARCHITECTURE),x86) CUSTOM_DEFINES += -DIA32 endif endif else UNAME_S := $(shell uname -s) ifeq ($(UNAME_S),Linux) DETECTED_OS = LINUX CUSTOM_DEFINES += -DLINUX endif ifeq ($(UNAME_S),Darwin) CUSTOM_DEFINES += -DOSX endif UNAME_P := $(shell uname -p) ifeq ($(UNAME_P),x86_64) CUSTOM_DEFINES += -DAMD64 endif ifneq ($(filter %86,$(UNAME_P)),) CUSTOM_DEFINES += -DIA32 endif ifneq ($(filter arm%,$(UNAME_P)),) CUSTOM_DEFINES += -DARM endif endif # General folder paths FRAMEWORK_PATH = fsfw MISSION_PATH = mission CONFIG_PATH = $(BOARD_FILE_ROOT)/config TEST_PATH = test UNITTEST_PATH = unittest # Board specific paths BSP_PATH = $(BOARD_FILE_ROOT) BOARDTEST_PATH = $(BOARD_FILE_ROOT)/boardtest # Output file basename BASENAME = eiveobsw BINARY_NAME = $(BASENAME)-$(BOARD) # Output files will be put in this directory inside OUTPUT_FOLDER = $(OS_FSFW) # Default debug output DEBUG_LEVEL = -g3 # Optimization level. -O0 default, -Os for size, -O3 for speed and size. OPTIMIZATION = -O0 ifdef GCOV CUSTOM_DEFINES += -DGCOV endif # Output directories BUILDPATH = _bin DEPENDPATH = _dep OBJECTPATH = _obj ifeq ($(MAKECMDGOALS),release) BUILD_FOLDER = mission else BUILD_FOLDER = devel endif DEPENDDIR = $(DEPENDPATH)/$(OUTPUT_FOLDER)/$(BUILD_FOLDER) OBJDIR = $(OBJECTPATH)/$(OUTPUT_FOLDER)/$(BUILD_FOLDER) BINDIR = $(BUILDPATH)/$(OUTPUT_FOLDER)/$(BUILD_FOLDER) CLEANDEP = $(DEPENDPATH)/$(OUTPUT_FOLDER) CLEANOBJ = $(OBJECTPATH)/$(OUTPUT_FOLDER) CLEANBIN = $(BUILDPATH)/$(OUTPUT_FOLDER) #------------------------------------------------------------------------------- # Tools and Includes #------------------------------------------------------------------------------- # Tool suffix when cross-compiling CROSS_COMPILE = # C Compiler CC = $(CROSS_COMPILE)gcc # C++ compiler CXX = $(CROSS_COMPILE)g++ # Additional Tools SIZE = $(CROSS_COMPILE)size STRIP = $(CROSS_COMPILE)strip CP = $(CROSS_COMPILE)objcopy HEXCOPY = $(CP) -O ihex BINCOPY = $(CP) -O binary # files to be compiled, will be filled in by include makefiles # := assignment here is neccessary as initialization so that the += # operator can be used in the submakefiles to achieve immediate evaluation. # See: http://make.mad-scientist.net/evaluation-and-expansion/ CSRC := CXXSRC := ASRC := INCLUDES := # Directories where $(directoryname).mk files should be included from SUBDIRS := $(FRAMEWORK_PATH) $(TEST_PATH) $(BSP_PATH) \ $(CONFIG_PATH) $(MISSION_PATH) # $(MISSION_PATH) $(CONFIG_PATH) # INCLUDES += framework/test/catch2 # ETL library include. ETL_PATH = etl/include I_INCLUDES += -I$(ETL_PATH) I_INCLUDES += $(addprefix -I, $(INCLUDES)) # This is a hack from http://make.mad-scientist.net/the-eval-function/ # # The problem is, that included makefiles should be aware of their relative path # but not need to guess or hardcode it. So we set $(CURRENTPATH) for them. If # we do this globally and the included makefiles want to include other makefiles as # well, they would overwrite $(CURRENTPATH), screwing the include after them. # # By using a for-loop with an eval'd macro, we can generate the code to include all # sub-makefiles (with the correct $(CURRENTPATH) set) before actually evaluating # (and by this possibly changing $(CURRENTPATH)) them. # # This works recursively, if an included makefile wants to include, it can safely set # $(SUBDIRS) (which has already been evaluated here) and do # "$(foreach S,$(SUBDIRS),$(eval $(INCLUDE_FILE)))" # $(SUBDIRS) must be relative to the project root, so to include subdir foo, set # $(SUBDIRS) = $(CURRENTPATH)/foo. define INCLUDE_FILE CURRENTPATH := $S include $(S)/$(notdir $S).mk endef $(foreach S,$(SUBDIRS),$(eval $(INCLUDE_FILE))) #------------------------------------------------------------------------------- # Source Files #------------------------------------------------------------------------------- # Additional source files which were not includes by other .mk # files are added here. # To help Makefile find source files, the source location paths # can be added by using the VPATH variable # See: https://www.gnu.org/software/make/manual/html_node/General-Search.html # It is recommended to only use VPATH to add source locations # See: http://make.mad-scientist.net/papers/how-not-to-use-vpath/ # Please ensure that no files are included by both .mk file and here ! # VPATH += mission/pus/ ifeq ($(DETECTED_OS), LINUX) CXXSRC += $(FRAMEWORK_PATH)/osal/linux/TcUnixUdpPollingTask.cpp CXXSRC += $(FRAMEWORK_PATH)/osal/linux/TmTcUnixUdpBridge.cpp endif # All C Sources included by .mk files are assigned here # Add the objects to sources so dependency handling works C_OBJECTS += $(CSRC:.c=.o) # Objects built from Assembly source files ASM_OBJECTS = $(ASRC:.S=.o) # Objects built from C++ source files CXX_OBJECTS += $(CXXSRC:.cpp=.o) #------------------------------------------------------------------------------- # Build Configuration + Output #------------------------------------------------------------------------------- TARGET = Debug DEBUG_MESSAGE = Off OPTIMIZATION_MESSAGE = Off # Define Messages MSG_INFO = Software: Hosted EIVE OBSW. MSG_LINKING = Linking: MSG_COMPILING = Compiling: MSG_ASSEMBLING = Assembling: MSG_BINARY = Generate binary: MSG_OPTIMIZATION = Optimization: $(OPTIMIZATION), $(OPTIMIZATION_MESSAGE) MSG_TARGET = Target Build: $(TARGET) MSG_DEBUG = FSFW Debugging: $(DEBUG_MESSAGE) MSG_COMIF = TMTC Communication Interface: $(COMIF_MESSAGE) # See: https://stackoverflow.com/questions/6687630/how-to-remove-unused-c-c-symbols-with-gcc-and-ld # Used to throw away unused code. Reduces code size significantly ! # -Wl,--gc-sections: needs to be passed to the linker to throw aways unused code ifdef KEEP_UNUSED_CODE PROTOTYPE_OPTIMIZATION = DEAD_CODE_REMOVAL = else PROTOTYPE_OPTIMIZATION = -ffunction-sections -fdata-sections DEAD_CODE_REMOVAL = -Wl,--gc-sections # Link time optimization # See https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html for reference # Link time is larger and size of object files can not be retrieved # but resulting binary is smaller. Could be used in mission/deployment build # Requires -ffunction-section in linker call LINK_TIME_OPTIMIZATION = -flto OPTIMIZATION += $(PROTOTYPE_OPTIMIZATION) endif # Dependency Flags # These flags tell the compiler to build dependencies # See: https://www.gnu.org/software/make/manual/html_node/Automatic-Prerequisites.html # Using following guide: # http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/ DEPFLAGS = -MT $@ -MMD -MP -MF $(DEPENDDIR)/$*.d # Flags for the compiler call # - std: Which C++ version to use. Common versions: c++11, c++14 and c++17 # - Wall: enable all warnings # - Wextra: enable extra warnings # - g: defines debug level # - fmessage-length: to control the formatting algorithm for diagnostic messages; # =0 means no line-wrapping, each error message appears on a single line # - fno-exceptions: stops generating extra code needed to propagate exceptions, # which can produce significant data size overhead WARNING_FLAGS = -Wall -Wshadow=local -Wextra -Wimplicit-fallthrough=1 \ -Wno-unused-parameter CXXDEFINES := $(CUSTOM_DEFINES) CFLAGS += CXXFLAGS += -I. $(DEBUG_LEVEL) $(WARNIING_FLAGS) $(I_INCLUDES) $(DEPFLAGS) \ -fmessage-length=0 $(CXXDEFINES) $(OPTIMIZATION) CPPFLAGS += -std=c++2a -fno-exceptions ASFLAGS = -Wall -g $(OPTIMIZATION) $(I_INCLUDES) -D__ASSEMBLY__ # Flags for the linker call # LINK_INCLUDES specify the path to used libraries and the linker script # LINK_LIBRARIES link HCC and HAL library and enable float support LDFLAGS := -g3 -pthread $(DEAD_CODE_REMOVAL) $(OPTIMIZATION) LINK_INCLUDES := LINK_LIBRARIES := ifeq ($(OS),Windows_NT) LINK_LIBRARIES += -lwsock32 -lws2_32 endif # Gnu Coverage Tools Flags ifdef GCOV GCOV_CXXFLAGS = -fprofile-arcs -ftest-coverage CXXFLAGS += $(GCOV_CXXFLAGS) GCOV_LINKER_LIBS = -lgcov -fprofile-arcs -ftest-coverage LINK_LIBRARIES += $(GCOV_LINKER_LIBS) endif #------------------------------------------------------------------------------- # Rules #------------------------------------------------------------------------------- # Makefile rules: https://www.gnu.org/software/make/manual/html_node/Rules.html # This is the primary section which defines the ruleset to build # the executable from the sources. default: all # Cleans all files hardclean: -rm -rf $(BUILDPATH) -rm -rf $(OBJECTPATH) -rm -rf $(DEPENDPATH) # Only clean files for current build clean: -rm -rf $(CLEANOBJ) -rm -rf $(CLEANBIN) -rm -rf $(CLEANDEP) # Only clean binaries. Useful for changing the binary type when object files are already compiled # so complete rebuild is not necessary cleanbin: -rm -rf $(BUILDPATH)/$(OUTPUT_FOLDER) # In this section, the binaries are built for all selected memories all: executable # Build target configuration release: OPTIMIZATION = -Os $(PROTOTYPE_OPTIMIZATION) $(LINK_TIME_OPTIMIZATION) release: LINK_TIME_OPTIMIZATION = -flto release: TARGET = Release release: OPTIMIZATION_MESSAGE = On with Link Time Optimization release: DEBUG_LEVEL = -g0 debug: CXXDEFINES += -DDEBUG debug: DEBUG_MESSAGE = On ifndef KEEP_UNUSED_CODE debug release: OPTIMIZATION_MESSAGE = Off with unused code removal else debug release: OPTIMIZATION_MESSAGE = Off endif debug release: executable # executable: $(BINDIR)/$(BINARY_NAME).bin ifeq ($(OS),Windows_NT) executable: $(BINDIR)/$(BINARY_NAME).exe else executable: $(BINDIR)/$(BINARY_NAME).elf endif @echo @echo $(MSG_INFO) @echo $(MSG_TARGET) @echo $(MSG_OPTIMIZATION) @echo $(MSG_DEBUG) C_OBJECTS_PREFIXED = $(addprefix $(OBJDIR)/, $(C_OBJECTS)) CXX_OBJECTS_PREFIXED = $(addprefix $(OBJDIR)/, $(CXX_OBJECTS)) ASM_OBJECTS_PREFIXED = $(addprefix $(OBJDIR)/, $(ASM_OBJECTS)) ALL_OBJECTS_PREFIXED = $(ASM_OBJECTS_PREFIXED) $(C_OBJECTS_PREFIXED) \ $(CXX_OBJECTS_PREFIXED) # Useful for debugging the Makefile # Also see: https://www.oreilly.com/openbook/make3/book/ch12.pdf # $$(info $${CXXDEFINES} is [${CXXDEFINES}]) # $$(info $${CXXSRC} is [${CXXSRC}]) # Automatic variables are used here extensively. Some of them # are escaped($$) to suppress immediate evaluation. The most important ones are: # $@: Name of Target (left side of rule) # $<: Name of the first prerequisite (right side of rule) # @^: List of all prerequisite, omitting duplicates # @D: Directory and file-within-directory part of $@ # Generates binary and displays all build properties # -p with mkdir ignores error and creates directory when needed. # SHOW_DETAILS = 1 ifeq ($(OS),Windows_NT) $(BINDIR)/$(BINARY_NAME).exe: $(ALL_OBJECTS_PREFIXED) else $(BINDIR)/$(BINARY_NAME).elf: $(ALL_OBJECTS_PREFIXED) endif @echo @echo $(MSG_LINKING) Target $@ @mkdir -p $(@D) @$(CXX) $(LDFLAGS) $(LINK_INCLUDES) -o $@ $^ $(LINK_LIBRARIES) ifeq ($(BUILD_FOLDER), mission) # With Link Time Optimization, section size is not available $(SIZE) $@ else $(SIZE) $^ $@ endif # Build new objects for changed dependencies. $(OBJDIR)/%.o: %.cpp $(OBJDIR)/%.o: %.cpp $(DEPENDDIR)/%.d | $(DEPENDDIR) @echo @echo $(MSG_COMPILING) $< @mkdir -p $(@D) ifdef SHOW_DETAILS $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $< else @$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $< endif $(OBJDIR)/%.o: %.c $(OBJDIR)/%.o: %.c $(DEPENDDIR)/%.d | $(DEPENDDIR) @echo @echo $(MSG_COMPILING) $< @mkdir -p $(@D) ifdef SHOW_DETAILS $(CC) $(CXXFLAGS) $(CFLAGS) -c -o $@ $< else @$(CC) $(CXXFLAGS) $(CFLAGS) -c -o $@ $< endif $(OBJDIR)/%.o: %.S Makefile @echo @echo $(MSG_ASSEMBLING) $< @mkdir -p $(@D) ifdef SHOW_DETAILS $(CC) $(ASFLAGS) -c -o $@ $< else @$(CC) $(ASFLAGS) -c -o $@ $< endif #------------------------------------------------------------------------------- # Dependency Handling #------------------------------------------------------------------------------- # Dependency Handling according to following guide: # http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/ $(DEPENDDIR): @mkdir -p $(@D) DEPENDENCY_RELATIVE = $(CSRC:.c=.d) $(CXXSRC:.cpp=.d) # This is the list of all dependencies DEPFILES = $(addprefix $(DEPENDDIR)/, $(DEPENDENCY_RELATIVE)) # Create subdirectories for dependencies $(DEPFILES): @mkdir -p $(@D) # Include all dependencies include $(wildcard $(DEPFILES)) # .PHONY tells make that these targets aren't files .PHONY: clean sdramCfg release debug all hardclean