# %CopyrightBegin%
#
# Copyright Ericsson AB and Kjell Winblad 2019. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# %CopyrightEnd%

#
# Author: Kjell Winblad
#

#
# Note: The main target of this makefile generates another makefile
# which is named "Makefile". The generated file "Makefile" should be
# compatible with other make implementations than GNU make while this
# file is only compatible with GNU make. GNU make will automatically
# use this file as makefile when executed in the directory where this
# file is located.
#
# Erlang/OTP note: The build system for Erlang/OTP does not use this
# file to build Yielding C Fun (YCF). The file "main_target.mk"
# contains the necessary rules to build YCF and is included both by
# this file and the Erlang/OTP file
# $(ERL_TOP)/erts/lib_src/Makefile.in. This file is intended for
# building YCF independently of Erlang/OTP. This file also contains
# several special make targets (e.g., to invoke tests).
#


ifdef MODERN_CC
	EXTRA_C_FLAGS = -g -O02 -std=c99 -pedantic -Wall
endif

ifdef CC_32_BIT
	EXTRA_C_FLAGS = -m32 -g -O03 -std=c99 -pedantic -Wall
endif

ifdef USE_GC
	USE_GC_STRING = -use_gc
endif

ifdef ADD_SAN
	V_CC = clang
	EXTRA_C_FLAGS = -std=c99 -Wall -pedantic -g -O00 -fsanitize-blacklist=lib/simple_c_gc/.misc/clang_blacklist.txt -fsanitize=address -fno-omit-frame-pointer
	USE_GC_STRING = -use_gc
endif

ifdef MEM_SAN
	V_CC = clang
	EXTRA_C_FLAGS = -std=c99 -Wall -pedantic -g -O00 -fsanitize-blacklist=lib/simple_c_gc/.misc/clang_blacklist.txt -fsanitize=memory -fno-omit-frame-pointer
endif

ifdef UB_SAN
	V_CC = clang
	EXTRA_C_FLAGS = -std=c99 -Wall -pedantic -g -O00 -fsanitize-blacklist=lib/simple_c_gc/.misc/clang_blacklist.txt -fsanitize=undefined -fno-omit-frame-pointer
endif


YCF_SOURCE_DIR = .

ifndef V_CC
	V_CC = cc
endif

ifndef V_LD
	V_LD = $(CC)
endif

CFLAGS = $(EXTRA_C_FLAGS)

all: ./bin/yielding_c_fun.bin Makefile

include main_target.mk

##############################################################
# Generate a simple Makefile intended to work with other make
# implementations than GNU make
##############################################################

Makefile: $(YCF_SOURCES)
	echo '#' > Makefile
	echo '# !!!!!!!!!!! OBS Generated by GNUmakefile !!!!!!!!!!!!' >> Makefile
	echo '# This file is supposed to be compatible with as many make implementations as possible' >> Makefile
	echo '# Do not modify this file manually unless you cannot use GNU make.' >> Makefile
	echo '# Instead, just run GNU make in the directory where this file is located' >> Makefile
	echo '# and a new version of this file will be generated when needed.' >> Makefile
	echo '# GNU make will use the file GNUmakefile which is located in the same' >> Makefile
	echo '# directory.' >> Makefile
	echo '#' >> Makefile
	echo '#' >> Makefile
	echo '# Erlang/OTP note: The build system for Erlang/OTP does not use this' >> Makefile
	echo '# file to build Yielding C Fun (YCF). The file "main_target.mk"' >> Makefile
	echo '# contains the necessary rules to build YCF and is included both by' >> Makefile
	echo '# this file and the Erlang/OTP file' >> Makefile
	echo '# $$(ERL_TOP)/erts/lib_src/Makefile.in. This file is intended for' >> Makefile
	echo '# building YCF independently of Erlang/OTP.' >> Makefile
	echo '#' >> Makefile
	echo  >> Makefile
	O_FILES="";\
	for FILE in $(YCF_SOURCES);\
	do\
		OFILE_FULL=`echo $$FILE | sed 's/\.c/.o/'` ; \
		OFILE=`basename $$OFILE_FULL` ; \
		O_FILES="$$O_FILES $$OFILE" ; \
	done ; \
	echo $(YCF_EXECUTABLE)':' $$O_FILES >> Makefile ; \
	echo '	$$(CC) $(YCF_INCLUDE_DIRS) $$(CFLAGS) -o '$(YCF_EXECUTABLE)' ' $$O_FILES >> Makefile
	for FILE in $(YCF_SOURCES);\
	do\
		echo  >> Makefile ; \
		OFILE_FULL=`echo $$FILE | sed 's/\.c/.o/'` ; \
		OFILE=`basename $$OFILE_FULL` ; \
		echo "$$OFILE: $$FILE" >> Makefile ;\
		echo '	$$(CC) $(YCF_INCLUDE_DIRS) $$(CFLAGS) ' -c -o $$OFILE $$FILE  >> Makefile ;\
	done
	echo  >> Makefile

##############################################
# Special targets for testing etc:
##############################################

.PHONY: all clean test run_test_continusly CMakeLists.txt cmake_compile clang_format test_add_san test_mem_san test_modern_cc test_sanitizers test_gcc_clang_tcc clang_tidy test_bmake test_all

test: $(YCF_EXECUTABLE)
	./test/test.sh $(USE_GC_STRING) ;\
	RESULT=$$? &&\
	(exit $$RESULT) &&\
	printf "\n\n\033[0;32mALL TESTS PASSED!\033[0m\n\n\n" ||\
	printf "\n\n\033[0;31mTEST FAILED!\033[0m\n\n\n" &&\
	exit $$RESULT

test_add_san:
	make clean && \
	make V_CC=clang V_LD=clang ADD_SAN=1 test

test_mem_san:
	make clean && \
	make V_CC=clang V_LD=clang MEM_SAN=1 test

test_ub_san:
	make clean && \
	make V_CC=clang V_LD=clang UB_SAN=1 test

test_modern_cc:
	make clean && \
	make V_CC=clang V_LD=clang MODERN_CC=1 test

test_sanitizers:
	make test_add_san && \
	make test_mem_san && \
	make test_ub_san

test_gcc_clang_tcc:
	make V_CC=gcc V_LD=gcc EXTRA_C_FLAGS="-g -O01 -std=c99 -pedantic -Wall -Werror" clean $(YCF_EXECUTABLE) && \
	make V_CC=clang V_LD=clang EXTRA_C_FLAGS="-g -O01 -std=c99 -pedantic -Wall -Werror" clean $(YCF_EXECUTABLE) && \
	make V_CC=tcc V_LD=tcc EXTRA_C_FLAGS="-g -O01 -std=c99 -pedantic -Wall -Werror" clean $(YCF_EXECUTABLE)

test_32_bit:
	make clean && \
	make CC_32_BIT=1 test && \
	make clean

# sudo apt-get install bmake
# test that something else than GNU make can compile the tool
test_bmake:
	make clean && \
	make Makefile && \
	bmake

test_all:
	make test_gcc_clang_tcc && \
	make clang_tidy	&& \
	make test_sanitizers && \
	make test_modern_cc && \
	make test_32_bit && \
	make test_bmake

run_test_continusly:
	inotifywait -e close_write,moved_to,create -m ./*.c ./*.h -m test -m test/examples | while read -r directory events filename; do gtags ; make test_all ; done

cmake_compile: CMakeLists.txt
	mkdir cmake_mkdir || true
	cd cmake_mkdir && cmake ..

clang_tidy:
	(ls *.c ; echo lib/simple_c_gc/simple_c_gc.c) | xargs -I{} -n1 clang-tidy -warnings-as-errors=*  {} -- $(YCF_INCLUDE_DIRS) $(YCF_CFLAGS)

clang_format:
	clang-format -style="{BasedOnStyle: LLVM}" -i *.c *.h

clean:
	rm -f lib/simple_c_gc/*.o ./*.o ./*~ core trap parse $(YCF_EXECUTABLE) CMakeLists.txt

# Produce a CMakeLists.txt to build with cmake
CMakeLists.txt: $(YCF_SOURCES)
	echo "cmake_minimum_required (VERSION 2.6)" > CMakeLists.txt
	echo "project (YIELDING_C_FUN C)" >> CMakeLists.txt
	echo "add_executable(cmake.out " >> CMakeLists.txt
	echo $(YCF_SOURCES) >> CMakeLists.txt
	echo ")" >> CMakeLists.txt

