From d076b4ae38d09db39293cdde18ad6dd2ad958958 Mon Sep 17 00:00:00 2001 From: Christos Choutouridis Date: Mon, 28 Sep 2020 20:33:23 +0300 Subject: [PATCH] DEV: Makefile changes (add docker support) --- test/Makefile | 378 ++++++++++++++++++++++++++++---------------------- 1 file changed, 213 insertions(+), 165 deletions(-) diff --git a/test/Makefile b/test/Makefile index 73511a3..322e4cc 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,165 +1,213 @@ -# -# Makefile for utl Unit test -# -# Copyright (C) 2019-2020 Christos Choutouridis -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as -# published by the Free Software Foundation, either version 3 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with this program. If not, see . -# - -# ========== Project settings ========== -# Excecutable's name -TARGET := utlTest -# Source directories list(space seperated). Full or relative path -SRC_DIR_LIST := tests gtest -# Include directories list(space seperated). Full or relative path -INC_DIR_LIST := ../include gtest -# 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 -# Compiler flags for debug and release -DEB_CFLAGS := -DDEBUG -g3 -Wall -Wextra -REL_CFLAGS := -Wall -Wextra -O2 -# Pre-defines -# PRE_DEFS := MYCAB=1729 SUPER_MODE - -# ========== Linker settings ========== -# Linker flags -LDFLAGS := -pthread -# Map output file -MAP_FILE := output.map -MAP_FLAG := -Xlinker -Map=$(BUILD_DIR)/$(MAP_FILE) - -# ========== Default settings ========== -# compiler and compiler flagfs -CFLAGS := $(DEB_CFLAGS) -CXX := $(GCCXX) - -# -# =========== Main body and Patterns =========== -# -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))) - -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) - @$(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) - $(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) - @echo $(CXX) $(LDFLAGS) $(MAP_FLAG) -o $(@D)/$(TARGET) '$$(OBJ)' - @$(CXX) $(LDFLAGS) $(MAP_FLAG) -o $(@D)/$(TARGET) $(OBJ) - @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) - - -# -# ============ User Rules ============= -# - -.PHONY: gcc14 -gcc14: CFLAGS += -std=c++14 -gcc14: $(BUILD_DIR)/$(TARGET) - -.PHONY: gcc14_conc -gcc14_conc: CFLAGS += -std=c++14 -fconcepts -gcc14_conc: $(BUILD_DIR)/$(TARGET) - -.PHONY: gcc17 -gcc17: CFLAGS += -std=c++17 -gcc17: $(BUILD_DIR)/$(TARGET) - -.PHONY: gcc17_conc -gcc17_conc: CFLAGS += -std=c++17 -fconcepts -gcc17_conc: $(BUILD_DIR)/$(TARGET) - -.PHONY: gcc2a -gcc2a: CFLAGS += -std=c++2a -gcc2a: $(BUILD_DIR)/$(TARGET) - -.PHONY: clang14 -clang14: CXX := $(CLANGXX) -clang14: CFLAGS += -std=c++14 -clang14: $(BUILD_DIR)/$(TARGET) - -.PHONY: clang17 -clang17: CXX := $(CLANGXX) -clang17: CFLAGS += -std=c++17 -clang17: $(BUILD_DIR)/$(TARGET) - -.PHONY: clang2a -clang2a: CXX := $(CLANGXX) -clang2a: CFLAGS += -std=c++2a -clang2a: $(BUILD_DIR)/$(TARGET) - -.PHONY: debug -debug: $(BUILD_DIR)/$(TARGET) - -.PHONY: release -release: CFLAGS := $(REL_FLAGS) -release: clean $(BUILD_DIR)/$(TARGET) - -.PHONY: all -all: clean release +# +# Makefile for utl Unit test +# +# Copyright (C) 2019-2020 Christos Choutouridis +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 3 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . +# + +# ult 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 ============== +# Excecutable's name +TARGET := utlTest +# Source directories list(space seperated). +# Relative path, under current directory only +SRC_DIR_LIST := tests gtest +# Include directories list(space seperated). +# Relative path +INC_DIR_LIST := ../include gtest +# 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 +# Compiler flags for debug and release +DEB_CFLAGS := -DDEBUG -g3 -Wall -Wextra +REL_CFLAGS := -Wall -Wextra -O2 +# Pre-defines +# PRE_DEFS := MYCAB=1729 SUPER_MODE + +# ============== 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/$(TARGET) -w /usr/src/$(TARGET)/$(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 =========== +# +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) + @echo $(DOCKER) $(CXX) $(LDFLAGS) $(MAP_FLAG) -o $(@D)/$(TARGET) '$$(OBJ)' + @$(DOCKER) $(CXX) $(LDFLAGS) $(MAP_FLAG) -o $(@D)/$(TARGET) $(OBJ) + @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: release +release: CFLAGS := $(REL_FLAGS) +release: clean $(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) + +