Last active
September 4, 2015 18:13
-
-
Save Redchards/4d3d3e2ef7ed0cdc5137 to your computer and use it in GitHub Desktop.
A nice general purpose makefile ideal for testing and rapid prototyping of C and/or C++ language, without having to bother about compilation options too much. And even if one needs to add some options, it could be done easily. Of course, it's not a good idea to use it for bigger projects. Please report any bug you might find !
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This makefile is geared towards begginers and people who want fast prototyping and/or testing, | |
# and even if not willing to take the time to write a makefile, wants to have a configurable and yet | |
# solid solution. | |
# So yes, this makefile is general purpose, but really only useful for small to average projects. | |
# Indeed, bigger projects will require build mecanism far more advanced than such a simple makefile | |
# (or beware of everlasting compilation time ...). | |
# So, even if this makefile should be more than enough in general, there's few caveheats you should | |
# be aware of. | |
# First of all, to save typing and hassle, this makefile do a bunch of things "automagically". This, of course, | |
# includes some overhead (but usually not that much). So if you want really fast iteration time, this may be not | |
# the right solution. | |
# Second, even if I tried to make configuration as easy as possible, some more advanced task (cross compiling) will | |
# require some tweaks. It's explained in the "HOWTO" below. | |
# Finally, when you type the make command, some arguments will not be treated as target by the script | |
# For example, in the command "make clean release", clean will be the target rule, and release will do | |
# nothing but setting the configuration to release mod. So only the first argument count as a target here. | |
# But this case is order-sensitive, as doing "make release clean" will first execute the release rule, | |
# then clean the temporaries produced by this rule. This is a nice side effect, but this can be confusing | |
# if you don't know this at first. | |
# | |
# HOWTO : - you can set the project name by setting the "EXEC" variable to your liking. By default, it is | |
# the name of the directory the makefile is in. | |
# - the default directory structure required by the makefile is : "src" for the source files and | |
# "include" for the header files. You can change this by setting "SRCDIR" and "INCLDIR" variables to your | |
# liking. | |
# - make clean is the only command which is order dependent (in order to keep the side effect | |
# explained above). | |
# - configurations are autogenerated from ALLPLATFORMS and ALLCONFIGS lists. It takes the form of | |
# config-platform. So, if you want to compile in release mod for 32 bit intel (x86), you should type | |
# "make release-x86". | |
# - compilation mod is by default debug, and platform x86. You can adjust these values | |
# by changind DEFAULTCONFIG and DEFAULTPLATFORM variables. | |
# - to compile to llvm bitcode, juste type "make xxx jit" where xxx is the configuration you want. | |
# same thing for analysis mod. | |
# - use "make cleantmp" to clean all objs and dependencies. | |
# - use "make cleanall" to clean absolutly everything, final files included. | |
# - build-info rule is nice (the one which is giving configuration info at the beggining) is nice, | |
# but can introduce an unwanted performance overhead. Using the option "noinfo" allows to disable it. | |
# - the flags adopt the following convention : the word is transformed to uppercase, and the word | |
# "FLAGS" is appended. So, for example, to flags corresponding to the "release" mod is "RELEASEFLAGS". | |
# If flags are intended to be used for linkin, "LDFLAGS" is appended. The only case we got this situation | |
# is with library flags, for example, the linking flags corresponding to "shared" mod is "SHAREDLDFLAGS" | |
# - if you add new mods or configurations, remember to add new flags accordingly. For example, if one | |
# was to add "armv7" platform support, he would change the compiler (CXX) to a cross compiler and create a | |
# ARMV7FLAGS variable, which would contains the required compiler flags for armvs7 platform. Everything will then | |
# setup automatically. Maybe I will add later and option to set the compiler accordingly to the wanted platform if | |
# requested. | |
# The shell that the make will use to execute shell commands. | |
# It can be set to any decent shell without any problem. | |
SHELL:=/bin/bash | |
# We only define the C++ compiler, and it will take care of compiling both C and C++ files. | |
# We also set the linker (LD) to the same value, as most of the compilers do it through the same command. | |
CXX:= clang++ | |
LD:= $(CXX) | |
JITLD:= llvm-link | |
# The final executable, or library, name. | |
EXEC:=$(notdir $(shell pwd)) | |
# Various directory path. | |
# As nothing is hardcoded, the values can be set to the liking of the user, without breaking something. | |
LIBDIR:= lib | |
OBJDIR:= obj | |
SRCDIR:= src | |
INCLDIR:= include | |
BINDIR:= bin | |
SCANDIR:= scan | |
# Extensions of the different types of file | |
EXEEXT:= | |
OBJEXT:=o | |
DEPEXT:=d | |
CEXT:=c | |
CXXEXT:=cxx | |
STATICLIBEXT:=a | |
SHAREDLIBEXT:=so | |
# Basic C and C++ flags | |
FLAGS:= -W -Wall -Wextra | |
CFLAGS= $(FLAGS) -std=c11 | |
CXXFLAGS= $(FLAGS) -std=c++1y | |
# Flags used only for debug mod | |
DEBUGFLAGS:= -g -O0 | |
# Flags used only for release mod | |
RELEASEFLAGS:= -O3 | |
# Flags used only for analyzis mod | |
ANALYSISFLAGS:= --analyze -Xanalyzer -analyzer-output=html -o $(SCANDIR) | |
# Flags used for different platforms | |
X86FLAGS:= -m32 | |
X64FLAGS:= -m64 | |
# Flags used to create dependencies | |
DEPENDFLAGS:= -MMD | |
# Flags used by the linker | |
LDFLAGS:= | |
# Flags used only for bitcode compilation (by LLVM/clang) | |
JITFLAGS:= -emit-llvm -S -fno-use-cxa-atexit | |
# Flags to use for different library mod. | |
STATICLDFLAGS:= rcs | |
SHAREDFLAGS:= -fPIC | |
SHAREDLDFLAGS:= -shared | |
# Flags to add verbose linker and compiler output | |
# These are the only flags which do not follow the convention explained at the beggining | |
VERBOSEFLAGS:= -v | |
VERBOSELDFLAGS:= -v | |
# Some helper functions | |
define to_lower | |
$(strip $(shell echo $1 | tr '[:upper:]' '[:lower:]')) | |
endef | |
define to_upper | |
$(strip $(shell echo $1 | tr '[:lower:]' '[:upper:]')) | |
endef | |
# Returns the flags following the convention explained at the beggining | |
define get_flags | |
$(strip $($(call to_upper, $1)FLAGS)) | |
endef | |
# Returns the linking flags following the convention explained at the beggining | |
define get_ldflags | |
$(strip $($(call to_upper, $1)LDFLAGS)) | |
endef | |
# This variable will determine whether we will use native or JIT execution. | |
# JIT execution will produce llvm bitcode, which can be executed by the llvm execution engine. | |
# The command "lli" is the simplest way to run them. | |
# The values are either "native" or "jit". | |
# The value "jit" is only valid for the clang compiler. | |
override ALLEXECUTIONS:=native jit | |
override DEFAULTEXECUTION:=native | |
override PASSEDEXECUTION:=$(filter $(MAKECMDGOALS), $(ALLEXECUTIONS)) | |
ifeq ($(words $(PASSEDEXECUTION)), 0) | |
EXECUTION:=$(DEFAULTEXECUTION) | |
else ifeq ($(words $(PASSEDEXECUTION)), 1) | |
EXECUTION:=$(PASSEDEXECUTION) | |
else | |
$(error Error : multiple arguments or invalid execution mod !) | |
endif | |
FLAGS+=$(call get_flags, $(EXECUTION)) | |
# Defining supported platforms. | |
# Of course, more can be added | |
override ALLPLATFORMS:=x86 x64 | |
ifeq ($(shell getconf LONG_BIT), 64) | |
override DEFAULTPLATFORM:=x64 | |
else ifeq ($(shell getconf LONG_BIT), 32) | |
override DEFAULTPLATFORM:=x86 | |
endif | |
# List of all available compilation mods. | |
override ALLCONFIGS:=debug release analysis | |
# The default config. | |
override DEFAULTCONFIG:=debug | |
# Build the configuration names, following the convention explained at the beggining. | |
override CONFIG_PLATFORM:=$(foreach CONFIG, $(filter-out analysis, $(ALLCONFIGS)),$(addprefix $(CONFIG)-, $(ALLPLATFORMS))) | |
# Append compilation mods list to configuration names, to allow used to not specify the platform (choosing the default). | |
override CONFIG_PLATFORM+=$(ALLCONFIGS) | |
# Parse the user input, and extract build mod and platform. | |
override PASSEDCONFIG:=$(filter $(MAKECMDGOALS), $(CONFIG_PLATFORM)) | |
ifeq ($(words $(PASSEDCONFIG)), 0) | |
CONFIG:=$(DEFAULTCONFIG) | |
PLATFORM:=$(DEFAULTPLATFORM) | |
else ifeq ($(words $(PASSEDCONFIG)), 1) | |
CONFIG:=$(filter $(foreach PLATFORM, $(ALLPLATFORMS),$(patsubst %-$(PLATFORM),%,$(PASSEDCONFIG))), $(ALLCONFIGS)) | |
PLATFORM:=$(filter $(foreach PLATFORM, $(ALLPLATFORMS),$(patsubst %-$(PLATFORM),$(PLATFORM),$(PASSEDCONFIG))), $(ALLPLATFORMS)) | |
else | |
$(error Error : multiple configuration or invalid configuration mod !) | |
endif | |
# If no platform was defined, and the passed mod wasn't analysis, we set the platform to the default value. | |
ifeq ($(PLATFORM),) | |
ifneq ($(CONFIG), analysis) | |
PLATFORM:=$(DEFAULTPLATFORM) | |
endif | |
endif | |
FLAGS+=$(call get_flags, $(CONFIG)) | |
private TMP:=$(call get_flags, $(PLATFORM)) | |
FLAGS+=$(TMP) | |
# If the compilation mod is not JIT, then the linker also need platform flags infos. | |
ifneq ($(EXECUTION), jit) | |
LDFLAGS+=$(TMP) | |
endif | |
# If we got only a trailing dash (compilation mod is analysis), remove it and only assign the compilaion mod. | |
# Else, build congname accordingly. | |
override CONFIGNAME:=$(patsubst %-, %, $(CONFIG)-$(PLATFORM)) | |
# Set options for execution mods. | |
# Native execution mod do not change anything. | |
ifeq ($(EXECUTION), jit) | |
ifeq ($(CONFIG), analysis) | |
$(warning Warning : analysis mod is independant of execution mod. No bitcode will be generated) | |
endif | |
ifeq (, $(filter $(CXX), clang clang++)) | |
$(error Error : attempt to emit llvm IR, but not using LLVM/clang) | |
endif | |
LD= $(JITLD) | |
EXEC:= $(addprefix $(EXEC).,bc) | |
OBJEXT:= bco | |
endif | |
ifeq ($(CONFIG), analysis) | |
ifeq (, $(filter $(CXX), clang clang++)) | |
$(error Error : attempt to enable analysis, but not using LLVM/clang) | |
endif | |
endif | |
# Parse library configuration, and set options accordingly. | |
private override LIBTYPES:=static shared | |
private override PASSEDLIBTYPE:=$(filter $(MAKECMDGOALS), $(LIBTYPES)) | |
ifneq ($(PASSEDLIBTYPE),) | |
ifeq ($(EXECUTION), jit) | |
$(error : Can't build bitcode library ! Please select native execution mode (default)) | |
endif | |
ifneq ($(words $(PASSEDLIBTYPE)), 1) | |
$(error : Can't build multiple type of lib at the same time. Please select only one !) | |
else ifeq ($(PASSEDLIBTYPE), static) | |
# Static libs are really just archives of objects, so no platform information is needed | |
# (it's already contained in the objects) | |
LDFLAGS:=$(filter-out $(call get_flags, $(PLATFORM)), $(LDFLAGS))$(call get_ldflags, static) | |
LD:=ar | |
EXEC:=lib$(call to_lower, $(EXEC)).$(STATICLIBEXT) | |
else ifeq ($(PASSEDLIBTYPE), shared) | |
FLAGS+=$(call get_flags, shared) | |
LDFLAGS+=$(call get_ldflags, shared) | |
EXEC:=lib$(call to_lower, $(EXEC)).$(SHAREDLIBEXT) | |
# Change objs extension because we can't use .o files produced by default rules to produce a shared library, | |
# and we don't want to clean object if we build shared lib after static lib. | |
# Dynamic linking requires dynamic reallocation (-fPIC flag for gcc and clang). | |
OBJEXT:=osh | |
endif | |
# If the exe extension is not empty (on windows for example), add it to the exe name. | |
else ifneq ($(EXEEXT),) | |
EXEC:=$(EXEC).$(EXEEXT) | |
endif | |
# Character used to make the makefile silent. | |
SILENT:=@ | |
# Turns on/off the verbose output of the makefile. | |
# The values are either "none", "some", "detail" or "all" | |
# Verbose should turn verbose options for compiler and linker too ! | |
VERBOSE:=none | |
ifneq ($(filter $(VERBOSE), some detail all),) | |
ifneq ($(filter $(VERBOSE), detail all),) | |
FLAGS+=$(VERBOSEFLAGS) | |
LDFLAGS+=$(VERBOSELDFLAGS) | |
ifeq ($(VERBOSE), all) | |
SHELL_:=$(SHELL) | |
SHELL=$(warning [$@])$(SHELL_) -x | |
endif | |
endif | |
SILENT:= | |
endif | |
# Creation of sources, objects and dependencies list. | |
SRC:=$(shell find $(SRCDIR) -name '*.$(CEXT)' -o -name '*.$(CXXEXT)') | |
OBJ:=$(subst src/,,$(SRC:.$(CEXT)=.$(OBJEXT))) | |
OBJ:=$(subst src/,,$(OBJ:.$(CXXEXT)=.$(OBJEXT))) | |
OBJS=$(addprefix obj/$(PLATFORM)/$(CONFIG)/, $(OBJ)) | |
DEPS:=$(OBJ:.$(OBJEXT)=.$(DEPEXT)) | |
# Define the path where the result will be outputted | |
OUTPATH:=$(if $(filter $(CONFIG), analysis),$(SCANDIR),$(BINDIR)/$(PLATFORM)/$(CONFIG)) | |
# .PHONY targets. | |
.PHONY: clean cleantmp cleanall $(CONFIG_PLATFORM) $(ALLEXECUTIONS) | |
# Rule "all". All other first rules depends on it. | |
all: build-info $(OUTPATH)/$(EXEC) | |
@$(if $(OK),,\ | |
printf "\e[1m\e[32mNothing to do, everything is up to date !\e[0m\n\n") | |
# If the first option is not clean, we call the "all" rule. | |
ifeq ($(filter $(firstword $(MAKECMDGOALS)), clean),) | |
$(CONFIG_PLATFORM): all | |
else | |
$(CONFIG_PLATFORM): | |
@ printf "Done !" | |
endif | |
# Foo rules for options. | |
# Using the "@#" to make a "silent comment". Yhea, strange enough I figured that myself ... | |
# If the first option is not an execution, we don't do anything. | |
# Else, we initiate the build. | |
ifeq ($(filter $(firstword $(MAKECMDGOALS)), $(ALLEXECUTIONS)),) | |
$(ALLEXECUTIONS): | |
@# | |
else | |
$(ALLEXECUTIONS): $(CONFIGNAME) | |
endif | |
# If the first otion is not a library type, we don't do anything. | |
# Else, we initiate the build. | |
ifeq ($(filter $(firstword $(MAKECMDGOALS)), $(LIBTYPES)),) | |
$(LIBTYPES): | |
@# | |
else | |
$(LIBTYPES): $(CONFIGNAME) | |
endif | |
# Do we want build-info to run ? | |
ifeq ($(firstword $(MAKECMDGOALS)), noinfo) | |
noinfo : $(CONFIGNAME) | |
else | |
noinfo: | |
@# | |
endif | |
# This is the main rule. | |
# It will link all file generated by its dependencies together. | |
-include $(addprefix obj/$(PLATFORM)/$(CONFIG)/,$(DEPS)) | |
$(OUTPATH)/$(EXEC) : $(OBJS) | |
$(eval OK=1) | |
$(SILENT) mkdir -p $(OUTPATH) | |
ifeq ($(EXECUTION), jit) | |
$(SILENT) $(LD) $(LDFLAGS) $^ -o $(OUTPATH)/$(EXEC) | |
else | |
$(if $(filter $(CONFIG), analysis),\ | |
@ printf "No executable code output for analysis",\ | |
$(SILENT) printf "Linking binary ... ";\ | |
$(LD) $(LDFLAGS) -o $(OUTPATH)/$(EXEC) $^;\ | |
printf "Done !\n") | |
endif | |
@ printf "\e[1m\e[32mGeneration successful !\e[0m\n" | |
ifeq ($(EXECUTION), native) | |
$(SILENT) $(if $(filter $(CONFIG), release),\ | |
printf "Stripping binary ... ";\ | |
strip $(OUTPATH)/$(EXEC);\ | |
echo "Done !",) | |
else | |
@ printf "\e[1m\e[92mBitcode generated\e[0m\n" | |
endif | |
@ printf "Resulting file : \e[1m\e[92m$(EXEC)\e[0m\n\ | |
See the result in the following directory : \e[1m\e[96m$(OUTPATH)\e[0m\n" | |
# Eval might be a bottleneck here for larger projects | |
# Generation of obj file for C source | |
$(OBJDIR)/$(PLATFORM)/$(CONFIG)/%.$(OBJEXT): $(SRCDIR)/%.$(CEXT) | |
$(eval OK=1) | |
$(SILENT) mkdir -p $(@D) | |
$(SILENT) $(CXX) -I$(INCLDIR) -x c -o $@ -c $< $(CFLAGS) $(DEPENDFLAGS) | |
# Generation of obj file for C++ source | |
$(OBJDIR)/$(PLATFORM)/$(CONFIG)/%.$(OBJEXT): $(SRCDIR)/%.$(CXXEXT) | |
$(eval OK=1) | |
$(SILENT) mkdir -p $(@D) | |
$(SILENT) $(CXX) -I$(INCLDIR) -x c++ -o $@ -c $< $(CXXFLAGS) $(DEPENDFLAGS) | |
# We want the following rule to run in a sequential way (we don't want the building and the cleaning mixed together) | |
.NOTPARALLEL: | |
# The clean rule will conditionally delete temporary objects. | |
# For example, if you type "make clean debug", it will clean only debug native objects (not bitcodes ones). | |
# The same effect can be achieve by typing "make clean", as debug is the default configuration, | |
# in the original makefile at least | |
clean: | |
@echo "Cleaning $(CONFIG) $(EXECUTION) temporary objects ..." | |
$(SILENT) find $(OBJDIR)/$(PLATFORM)/$(CONFIG) -name "*.$(OBJEXT)" -type f -delete -o -name "*.$(DEPEXT)" -type f -delete | |
# Clean every tmp files produced by different compilations. | |
cleantmp: | |
$(SILENT) rm -rf $(OBJDIR)/* | |
# Clean absolutly everything, including produced binaries. | |
cleanall: cleantmp | |
$(SILENT) rm -f ./build.gen | |
$(SILENT) rm -rf $(BINDIR)/* | |
# The summary of the upcoming compilation configuration printed at the begining. | |
# It could be extended, but it is sufficient like this. | |
# If can be disabled by calling the make using "noinfo". | |
HEADER_MSG:="COMPILATION OF PROJECT : $(EXEC)" | |
LINE:=$(shell printf "%$$(tput cols)s" | tr " " "=") | |
ifeq ($(filter $(MAKECMDGOALS), noinfo),) | |
build-info: | |
@printf $(LINE)"\n\e[1m\e[91m$(shell export HEADER_MSG=$(HEADER_MSG); printf " %.0s" $$(seq 1 $$(($$(tput cols)/2 - $${#HEADER_MSG}/2)))) "$(HEADER_MSG)"\e[0m\n\ | |
Generation configuration is \e[1m\e[32m$(EXECUTION) $(CONFIGNAME)\e[0m\n\n\ | |
Sources directory search path is : \e[1m\e[96m$(SRCDIR)\e[0m (SRCDIR)\n\ | |
Includes directory search path is : \e[1m\e[96m$(INCLDIR)\e[0m (INCLDIR)\n\ | |
Libraries directory search path is : \e[1m\e[96m$(LIBDIR)\e[0m (LIBDIR)\n\ | |
Objects directory is : \e[1m\e[96m$(OBJDIR)\e[0m (OBJDIR)\n\ | |
The binary output path is : \e[1m\e[96m$(OUTPATH)\e[0m\n\n\ | |
$(LINE)\n\n" | |
else | |
build-info: | |
endif |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
SHELL:=/bin/bash | |
CXX:= clang++ | |
LD:= $(CXX) | |
JITLD:= llvm-link | |
EXEC:=$(notdir $(shell pwd)) | |
LIBDIR:= lib | |
OBJDIR:= obj | |
SRCDIR:= src | |
INCLDIR:= include | |
BINDIR:= bin | |
SCANDIR:= scan | |
EXEEXT:= | |
OBJEXT:=o | |
DEPEXT:=d | |
CEXT:=c | |
CXXEXT:=cxx | |
STATICLIBEXT:=a | |
SHAREDLIBEXT:=so | |
FLAGS:= -W -Wall -Wextra | |
CFLAGS= $(FLAGS) -std=c11 | |
CXXFLAGS= $(FLAGS) -std=c++1y | |
DEBUGFLAGS:= -g -O0 | |
RELEASEFLAGS:= -O3 | |
ANALYSISFLAGS:= --analyze -Xanalyzer -analyzer-output=html -o $(SCANDIR) | |
X86FLAGS:= -m32 | |
X64FLAGS:= -m64 | |
DEPENDFLAGS:= -MMD | |
LDFLAGS:= | |
JITFLAGS:= -emit-llvm -S -fno-use-cxa-atexit | |
STATICLDFLAGS:= rcs | |
SHAREDFLAGS:= -fPIC | |
SHAREDLDFLAGS:= -shared | |
VERBOSEFLAGS:= -v | |
VERBOSELDFLAGS:= -v | |
define to_lower | |
$(strip $(shell echo $1 | tr '[:upper:]' '[:lower:]')) | |
endef | |
define to_upper | |
$(strip $(shell echo $1 | tr '[:lower:]' '[:upper:]')) | |
endef | |
define get_flags | |
$(strip $($(call to_upper, $1)FLAGS)) | |
endef | |
define get_ldflags | |
$(strip $($(call to_upper, $1)LDFLAGS)) | |
endef | |
override ALLEXECUTIONS:=native jit | |
override DEFAULTEXECUTION:=native | |
override PASSEDEXECUTION:=$(filter $(MAKECMDGOALS), $(ALLEXECUTIONS)) | |
ifeq ($(words $(PASSEDEXECUTION)), 0) | |
EXECUTION:=$(DEFAULTEXECUTION) | |
else ifeq ($(words $(PASSEDEXECUTION)), 1) | |
EXECUTION:=$(PASSEDEXECUTION) | |
else | |
$(error Error : multiple arguments or invalid execution mod !) | |
endif | |
FLAGS+=$(call get_flags, $(EXECUTION)) | |
override ALLPLATFORMS:=x86 x64 | |
ifeq ($(shell getconf LONG_BIT), 64) | |
override DEFAULTPLATFORM:=x64 | |
else ifeq ($(shell getconf LONG_BIT), 32) | |
override DEFAULTPLATFORM:=x86 | |
endif | |
override ALLCONFIGS:=debug release analysis | |
override DEFAULTCONFIG:=debug | |
override CONFIG_PLATFORM:=$(foreach CONFIG, $(filter-out analysis, $(ALLCONFIGS)),$(addprefix $(CONFIG)-, $(ALLPLATFORMS))) | |
override CONFIG_PLATFORM+=$(ALLCONFIGS) | |
override PASSEDCONFIG:=$(filter $(MAKECMDGOALS), $(CONFIG_PLATFORM)) | |
ifeq ($(words $(PASSEDCONFIG)), 0) | |
CONFIG:=$(DEFAULTCONFIG) | |
PLATFORM:=$(DEFAULTPLATFORM) | |
else ifeq ($(words $(PASSEDCONFIG)), 1) | |
CONFIG:=$(filter $(foreach PLATFORM, $(ALLPLATFORMS),$(patsubst %-$(PLATFORM),%,$(PASSEDCONFIG))), $(ALLCONFIGS)) | |
PLATFORM:=$(filter $(foreach PLATFORM, $(ALLPLATFORMS),$(patsubst %-$(PLATFORM),$(PLATFORM),$(PASSEDCONFIG))), $(ALLPLATFORMS)) | |
else | |
$(error Error : multiple configuration or invalid configuration mod !) | |
endif | |
ifeq ($(PLATFORM),) | |
ifneq ($(CONFIG), analysis) | |
PLATFORM:=$(DEFAULTPLATFORM) | |
endif | |
endif | |
FLAGS+=$(call get_flags, $(CONFIG)) | |
private TMP:=$(call get_flags, $(PLATFORM)) | |
FLAGS+=$(TMP) | |
ifneq ($(EXECUTION), jit) | |
LDFLAGS+=$(TMP) | |
endif | |
override CONFIGNAME:=$(patsubst %-, %, $(CONFIG)-$(PLATFORM)) | |
ifeq ($(EXECUTION), jit) | |
ifeq ($(CONFIG), analysis) | |
$(warning Warning : analysis mod is independant of execution mod. No bitcode will be generated) | |
endif | |
ifeq (, $(filter $(CXX), clang clang++)) | |
$(error Error : attempt to emit llvm IR, but not using LLVM/clang) | |
endif | |
LD= $(JITLD) | |
EXEC:= $(addprefix $(EXEC).,bc) | |
OBJEXT:= bco | |
endif | |
ifeq ($(CONFIG), analysis) | |
ifeq (, $(filter $(CXX), clang clang++)) | |
$(error Error : attempt to enable analysis, but not using LLVM/clang) | |
endif | |
endif | |
private override LIBTYPES:=static shared | |
private override PASSEDLIBTYPE:=$(filter $(MAKECMDGOALS), $(LIBTYPES)) | |
ifneq ($(PASSEDLIBTYPE),) | |
ifeq ($(EXECUTION), jit) | |
$(error : Can't build bitcode library ! Please select native execution mode (default)) | |
endif | |
ifneq ($(words $(PASSEDLIBTYPE)), 1) | |
$(error : Can't build multiple type of lib at the same time. Please select only one !) | |
else ifeq ($(PASSEDLIBTYPE), static) | |
LDFLAGS:=$(filter-out $(call get_flags, $(PLATFORM)), $(LDFLAGS))$(call get_ldflags, static) | |
LD:=ar | |
EXEC:=lib$(call to_lower, $(EXEC)).$(STATICLIBEXT) | |
else ifeq ($(PASSEDLIBTYPE), shared) | |
FLAGS+=$(call get_flags, shared) | |
LDFLAGS+=$(call get_ldflags, shared) | |
EXEC:=lib$(call to_lower, $(EXEC)).$(SHAREDLIBEXT) | |
OBJEXT:=osh | |
endif | |
else ifneq ($(EXEEXT),) | |
EXEC:=$(EXEC).$(EXEEXT) | |
endif | |
SILENT:=@ | |
VERBOSE:=none | |
ifneq ($(filter $(VERBOSE), some detail all),) | |
ifneq ($(filter $(VERBOSE), detail all),) | |
FLAGS+=$(VERBOSEFLAGS) | |
LDFLAGS+=$(VERBOSELDFLAGS) | |
ifeq ($(VERBOSE), all) | |
SHELL_:=$(SHELL) | |
SHELL=$(warning [$@])$(SHELL_) -x | |
endif | |
endif | |
SILENT:= | |
endif | |
SRC:=$(shell find $(SRCDIR) -name '*.$(CEXT)' -o -name '*.$(CXXEXT)') | |
OBJ:=$(subst src/,,$(SRC:.$(CEXT)=.$(OBJEXT))) | |
OBJ:=$(subst src/,,$(OBJ:.$(CXXEXT)=.$(OBJEXT))) | |
OBJS=$(addprefix obj/$(PLATFORM)/$(CONFIG)/, $(OBJ)) | |
DEPS:=$(OBJ:.$(OBJEXT)=.$(DEPEXT)) | |
OUTPATH:=$(if $(filter $(CONFIG), analysis),$(SCANDIR),$(BINDIR)/$(PLATFORM)/$(CONFIG)) | |
.PHONY: clean cleantmp cleanall $(CONFIG_PLATFORM) $(ALLEXECUTIONS) | |
all: build-info $(OUTPATH)/$(EXEC) | |
@$(if $(OK),,\ | |
printf "\e[1m\e[32mNothing to do, everything is up to date !\e[0m\n\n") | |
ifeq ($(filter $(firstword $(MAKECMDGOALS)), clean),) | |
$(CONFIG_PLATFORM): all | |
else | |
$(CONFIG_PLATFORM): | |
@ printf "Done !" | |
endif | |
ifeq ($(filter $(firstword $(MAKECMDGOALS)), $(ALLEXECUTIONS)),) | |
$(ALLEXECUTIONS): | |
@# | |
else | |
$(ALLEXECUTIONS): $(CONFIGNAME) | |
endif | |
ifeq ($(filter $(firstword $(MAKECMDGOALS)), $(LIBTYPES)),) | |
$(LIBTYPES): | |
@# | |
else | |
$(LIBTYPES): $(CONFIGNAME) | |
endif | |
ifeq ($(firstword $(MAKECMDGOALS)), noinfo) | |
noinfo : $(CONFIGNAME) | |
else | |
noinfo: | |
@# | |
endif | |
-include $(addprefix obj/$(PLATFORM)/$(CONFIG)/,$(DEPS)) | |
$(OUTPATH)/$(EXEC) : $(OBJS) | |
$(eval OK=1) | |
$(SILENT) mkdir -p $(OUTPATH) | |
ifeq ($(EXECUTION), jit) | |
$(SILENT) $(LD) $(LDFLAGS) $^ -o $(OUTPATH)/$(EXEC) | |
else | |
$(if $(filter $(CONFIG), analysis),\ | |
@ printf "No executable code output for analysis",\ | |
$(SILENT) printf "Linking binary ... ";\ | |
$(LD) $(LDFLAGS) -o $(OUTPATH)/$(EXEC) $^;\ | |
printf "Done !\n") | |
endif | |
@ printf "\e[1m\e[32mGeneration successful !\e[0m\n" | |
ifeq ($(EXECUTION), native) | |
$(SILENT) $(if $(filter $(CONFIG), release),\ | |
printf "Stripping binary ... ";\ | |
strip $(OUTPATH)/$(EXEC);\ | |
echo "Done !",) | |
else | |
@ printf "\e[1m\e[92mBitcode generated\e[0m\n" | |
endif | |
@ printf "Resulting file : \e[1m\e[92m$(EXEC)\e[0m\n\ | |
See the result in the following directory : \e[1m\e[96m$(OUTPATH)\e[0m\n" | |
$(OBJDIR)/$(PLATFORM)/$(CONFIG)/%.$(OBJEXT): $(SRCDIR)/%.$(CEXT) | |
$(eval OK=1) | |
$(SILENT) mkdir -p $(@D) | |
$(SILENT) $(CXX) -I$(INCLDIR) -x c -o $@ -c $< $(CFLAGS) $(DEPENDFLAGS) | |
$(OBJDIR)/$(PLATFORM)/$(CONFIG)/%.$(OBJEXT): $(SRCDIR)/%.$(CXXEXT) | |
$(eval OK=1) | |
$(SILENT) mkdir -p $(@D) | |
$(SILENT) $(CXX) -I$(INCLDIR) -x c++ -o $@ -c $< $(CXXFLAGS) $(DEPENDFLAGS) | |
.NOTPARALLEL: | |
clean: | |
@echo "Cleaning $(CONFIG) $(EXECUTION) temporary objects ..." | |
$(SILENT) find $(OBJDIR)/$(PLATFORM)/$(CONFIG) -name "*.$(OBJEXT)" -type f -delete -o -name "*.$(DEPEXT)" -type f -delete | |
cleantmp: | |
$(SILENT) rm -rf $(OBJDIR)/* | |
cleanall: cleantmp | |
$(SILENT) rm -f ./build.gen | |
$(SILENT) rm -rf $(BINDIR)/* | |
HEADER_MSG:="COMPILATION OF PROJECT : $(EXEC)" | |
LINE:=$(shell printf "%$$(tput cols)s" | tr " " "=") | |
ifeq ($(filter $(MAKECMDGOALS), noinfo),) | |
build-info: | |
@printf $(LINE)"\n\e[1m\e[91m$(shell export HEADER_MSG=$(HEADER_MSG); printf " %.0s" $$(seq 1 $$(($$(tput cols)/2 - $${#HEADER_MSG}/2)))) "$(HEADER_MSG)"\e[0m\n\ | |
Generation configuration is \e[1m\e[32m$(EXECUTION) $(CONFIGNAME)\e[0m\n\n\ | |
Sources directory search path is : \e[1m\e[96m$(SRCDIR)\e[0m (SRCDIR)\n\ | |
Includes directory search path is : \e[1m\e[96m$(INCLDIR)\e[0m (INCLDIR)\n\ | |
Libraries directory search path is : \e[1m\e[96m$(LIBDIR)\e[0m (LIBDIR)\n\ | |
Objects directory is : \e[1m\e[96m$(OBJDIR)\e[0m (OBJDIR)\n\ | |
The binary output path is : \e[1m\e[96m$(OUTPATH)\e[0m\n\n\ | |
$(LINE)\n\n" | |
else | |
build-info: | |
endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment