264 lines
8.3 KiB
Makefile
264 lines
8.3 KiB
Makefile
#
|
|
# Makefile for tbx unit testing
|
|
#
|
|
# Copyright (C) 2021 Christos Choutouridis <christos@choutouridis.net>
|
|
#
|
|
# The MIT License (MIT)
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
# of this software and associated documentation files (the "Software"), to deal
|
|
# in the Software without restriction, including without limitation the rights
|
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
# copies of the Software, and to permit persons to whom the Software is
|
|
# furnished to do so, subject to the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be included in all
|
|
# copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
# SOFTWARE.
|
|
#
|
|
|
|
# notes:
|
|
# ==============
|
|
# This makefile provides support for unix-like local builds and
|
|
# docker based builds for gcc and clang.
|
|
# ** msvc is not currently supported.
|
|
#
|
|
# Use cases:
|
|
# 1) build localy using **local rules** in terminal.
|
|
# example:
|
|
# make -j4 MK_ARG="-std=c++14 -fconcepts" build-gcc
|
|
#
|
|
# 2) build localy using **docker based rules** via terminal or script
|
|
# in order to compile for all compilers/versions/dialects.
|
|
# example in bash:
|
|
# #!/bin/bash
|
|
# for im in gcc:8 gcc:9 gcc:10; do
|
|
# for dial in -std=c++14 -std=c++17; do
|
|
# make IMAGE="$im" MK_ARG="$dial" dock-gcc
|
|
# done
|
|
# done
|
|
#
|
|
# 3) build inside a docker instance using **local rules** in order to
|
|
# build and test using a CD/CI system.
|
|
# example in a yml file:
|
|
# image: gcc:8
|
|
# build:
|
|
# stage: build
|
|
# - make MK_ARG="-std=c++14" build-gcc
|
|
# - make MK_ARG="-std=c++14 -fconcepts" build-gcc
|
|
# - make MK_ARG="-std=c++17" build-gcc
|
|
# - make MK_ARG="-std=c++17 -fconcepts" build-gcc
|
|
# - make MK_ARG="-std=c++2a" build-gcc
|
|
# ... etc
|
|
# test:
|
|
# stage: test
|
|
# - bin/utlTest
|
|
# ... etc
|
|
|
|
#
|
|
|
|
#
|
|
# ============== Project settings ==============
|
|
#
|
|
# note: STM32f101RC/D/E device configuration on SMT32CubeF1 library requires:
|
|
# 1) STM2F101xE pre-define
|
|
# 2) startup_stm32f101xe.s startup file
|
|
#
|
|
|
|
# Project's name
|
|
PROJECT := tbx
|
|
# Excecutable's name
|
|
TARGET := tbxTest
|
|
|
|
# Source directories list(space seperated). Relative path, under current directory only
|
|
SRC_DIR_LIST := tests gtest
|
|
|
|
# Source files list(space seperated).
|
|
SRC_FILES_LIST :=
|
|
|
|
# Include directories list(space seperated). Relative path
|
|
INC_DIR_LIST := ../include gtest
|
|
ifeq ($(OS), Windows_NT)
|
|
INC_DIR_LIST += mingw-std-threads
|
|
endif
|
|
# Exclude files list(space seperated). Filenames only.
|
|
# EXC_FILE_LIST := bad.cpp old.cpp
|
|
|
|
# Build directories
|
|
BUILD_DIR := bin
|
|
OBJ_DIR := $(BUILD_DIR)/obj
|
|
DEP_DIR := $(BUILD_DIR)/.dep
|
|
|
|
|
|
# ============== Compiler settings ==============
|
|
CLANGXX := clang++
|
|
GCCXX := g++
|
|
CSIZE := size
|
|
|
|
ODUMP := objdump
|
|
OCOPY := objcopy
|
|
|
|
# Compiler flags for debug and release
|
|
DEB_CFLAGS := -std=gnu++17 -DDEBUG -g3 -Wall -Wextra -fmessage-length=0
|
|
REL_CFLAGS := -std=gnu++17 -Wall -Wextra -O2 -fmessage-length=0
|
|
# Pre-defines
|
|
PRE_DEFS :=
|
|
ifeq ($(OS), Windows_NT)
|
|
PRE_DEFS += WIN_TRHEADS
|
|
endif
|
|
|
|
# ============== Linker settings ==============
|
|
# Linker flags
|
|
LDFLAGS := -pthread
|
|
# Map output file
|
|
MAP_FILE := output.map
|
|
MAP_FLAG := -Xlinker -Map=$(BUILD_DIR)/$(MAP_FILE)
|
|
|
|
# ============== Docker settings ==============
|
|
# We need:
|
|
# 1) Bind the entire project directory(the dir that icludes all the code) as volume.
|
|
# 2) In docker instance change to working directory(where the makefile is).
|
|
# For utl we use the directories `${PWD%/*}` and `test`.
|
|
# We double-$$ for double evaluating.
|
|
DOCKER_VOL_DIR := "$${PWD%/*}"
|
|
DOCKER_WRK_DIR := test
|
|
DOCKER_RUN := docker run --rm -v $(DOCKER_VOL_DIR):/usr/src/$(PROJECT) -w /usr/src/$(PROJECT)/$(DOCKER_WRK_DIR)
|
|
|
|
# ============== Default settings ==============
|
|
# compiler and compiler flags. By default docker is not used.
|
|
CFLAGS := $(DEB_CFLAGS)
|
|
CXX := $(GCCXX)
|
|
DOCKER :=
|
|
|
|
#
|
|
# =========== Main body and Patterns ===========
|
|
#
|
|
ifeq ($(OS), Windows_NT)
|
|
TARGET := $(TARGET).exe
|
|
endif
|
|
INC := $(foreach dir,$(INC_DIR_LIST),-I$(dir))
|
|
DEF := $(foreach def,$(PRE_DEFS),-D$(def))
|
|
EXC := $(foreach fil,$(EXC_FILE_LIST), \
|
|
$(foreach dir,$(SRC_DIR_LIST),$(wildcard $(dir)/$(fil))) \
|
|
)
|
|
# source files, object and dependencies list
|
|
# recursive search into current and source directories
|
|
SRC := $(wildcard *.cpp)
|
|
SRC += $(foreach dir,$(SRC_DIR_LIST),$(wildcard $(dir)/*.cpp))
|
|
SRC += $(foreach dir,$(SRC_DIR_LIST),$(wildcard $(dir)/**/*.cpp))
|
|
#SRC := $(abspath $(filter-out $(EXC),$(SRC)))
|
|
SRC := $(filter-out $(EXC),$(SRC))
|
|
|
|
OBJ := $(foreach file,$(SRC:%.cpp=%.o),$(OBJ_DIR)/$(file))
|
|
DEP := $(foreach file,$(SRC:%.cpp=%.d),$(DEP_DIR)/$(file))
|
|
|
|
|
|
# Make Dependencies pattern.
|
|
# This little trick enables recompilation only when dependencies change
|
|
# and it does so for changes both in source AND header files ;)
|
|
#
|
|
# It is based on Tom Tromey's method.
|
|
#
|
|
# Invoke cpp to create makefile rules with dependencies for each source file
|
|
$(DEP_DIR)/%.d: %.cpp
|
|
@mkdir -p $(@D)
|
|
@$(DOCKER) $(CXX) -E $(CFLAGS) $(INC) $(DEF) -MM -MT $(OBJ_DIR)/$(<:.cpp=.o) -MF $@ $<
|
|
|
|
# objects depent on .cpp AND dependency files, which have an empty recipe
|
|
$(OBJ_DIR)/%.o: %.cpp $(DEP_DIR)/%.d
|
|
@mkdir -p $(@D)
|
|
$(DOCKER) $(CXX) -c $(CFLAGS) $(INC) $(DEF) -o $@ $<
|
|
|
|
# empty recipe for dependency files. This prevents make errors
|
|
$(DEP):
|
|
|
|
# now include all dependencies
|
|
# After all they are makefile dependency rules ;)
|
|
include $(wildcard $(DEP))
|
|
|
|
# main target rule
|
|
$(BUILD_DIR)/$(TARGET): $(OBJ)
|
|
@mkdir -p $(@D)
|
|
@echo Linking to target: $(TARGET)
|
|
$(DOCKER) $(CXX) $(LDFLAGS) $(MAP_FLAG) -o $(@D)/$(TARGET) $(OBJ)
|
|
$(DOCKER) $(ODUMP) -h -S $(BUILD_DIR)/$(TARGET) > $(BUILD_DIR)/$(basename $(TARGET)).list
|
|
# $(DOCKER) $(OCOPY) -O ihex $(BUILD_DIR)/$(TARGET) $(BUILD_DIR)/$(basename $(TARGET)).hex
|
|
@echo
|
|
@echo Print size information
|
|
@$(CSIZE) $(@D)/$(TARGET)
|
|
@echo Done
|
|
|
|
.PHONY: clean
|
|
clean:
|
|
@echo Cleaning build directories
|
|
@rm -rf $(OBJ_DIR)
|
|
@rm -rf $(DEP_DIR)
|
|
@rm -rf $(BUILD_DIR)
|
|
|
|
|
|
#
|
|
# ================ Local build rules =================
|
|
# examples:
|
|
# make MK_ARG="-std=c++14 -fconcepts" build-gcc
|
|
# make MK_ARG="-std=c++17" build-clang
|
|
#
|
|
.PHONY: build-gcc
|
|
build-gcc: CFLAGS += $(MK_ARG)
|
|
build-gcc: $(BUILD_DIR)/$(TARGET)
|
|
|
|
.PHONY: build-clang
|
|
build-clang: CXX := $(CLANGXX)
|
|
build-clang: CFLAGS += $(MK_ARG)
|
|
build-clang: $(BUILD_DIR)/$(TARGET)
|
|
|
|
.PHONY: debug
|
|
debug: $(BUILD_DIR)/$(TARGET)
|
|
|
|
|
|
.PHONY: test_asan
|
|
test_asan: CFLAGS := $(REL_CFLAGS)
|
|
test_asan: CFLAGS += -g3 -fsanitize=address -fsanitize=leak -fsanitize=bounds-strict
|
|
test_asan: LDFLAGS += -fsanitize=address -fsanitize=leak -fsanitize=bounds-strict
|
|
test_asan: $(BUILD_DIR)/$(TARGET)
|
|
|
|
|
|
.PHONY: test_tsan
|
|
test_asan: CFLAGS := $(REL_CFLAGS)
|
|
test_tsan: CFLAGS += -g3 -fsanitize=thread
|
|
test_tsan: LDFLAGS += -fsanitize=thread
|
|
test_tsan: $(BUILD_DIR)/$(TARGET)
|
|
|
|
|
|
.PHONY: release
|
|
release: CFLAGS := $(REL_CFLAGS)
|
|
release: $(BUILD_DIR)/$(TARGET)
|
|
|
|
.PHONY: all
|
|
all: clean release
|
|
|
|
#
|
|
# ================ Docker based rules ================
|
|
# examples:
|
|
# make IMAGE="gcc:8.3" MK_ARG="-std=c++14 -fconcepts" dock-gcc
|
|
# make IMAGE="a-clang-image" MK_ARG="-std=c++17" dock-clang
|
|
#
|
|
.PHONY: dock-gcc
|
|
dock-gcc: DOCKER := $(DOCKER_RUN) $(IMAGE)
|
|
dock-gcc: CFLAGS += $(MK_ARG)
|
|
dock-gcc: $(BUILD_DIR)/$(TARGET)
|
|
|
|
.PHONY: dock-clang
|
|
dock-clang: CXX := $(CLANGXX)
|
|
dock-clang: DOCKER := $(DOCKER_RUN) $(IMAGE)
|
|
dock-clang: CFLAGS += $(MK_ARG)
|
|
dock-clang: $(BUILD_DIR)/$(TARGET)
|
|
|
|
|