repo_dir:=$(dir $(abspath $(lastword $(MAKEFILE_LIST))))

# These variables will be filled with cmake args for model and librts
MODEL_CMAKE_FLAGS:= -DLIBRTS_BUILD=1 
LIBRTS_CMAKE_FLAGS:=

# 
# Some compilers don't play well with the inlining logic we use in advligorts (ex: clang)
# This can cause undefined refrences to inlined functions when the compiler makes interesting decisions
# on what to inline and what to leave definitions too. One easy workaround is to make all header only 
# functions static, this means that there is a lot of duplicate code generated and the compiled code 
# is larger. This is not really a concern for librts, so it is the default behavior, you can comment 
# the line below to make the build resemble production code more closely
FORCE_STATIC_INLINE?=1
#
# When set, will disable the build of the RTS userspace executable. The userspace library that
# implements the model logic will still be built. 
MODEL_NO_EXECUTABLE?=0
#
# The LIGO RTS uses inline assembly for math functions in kernel space, this option will
# replace those call with functions from the c standard library.
USE_STDLIB_MATH?=1
#
# When set, will disable the build of c++ unit tests in the tests/ directory.
LIBRTS_NO_UNIT_TESTS?=0
#
# Don't build the example c++ applications in the examples/ directory.
LIBRTS_NO_EXAMPLES?=0
#
# The LIBRTS_NO_SHMEM option replaces all shmem, mbuf/posix with process local memory buffers.
# This is useful when you have multiple people running models on the same workstation, and 
# when you have multiple running models at the same time. There are no librts tools that use
# the exported shared memory segments, so this is being made the default.
LIBRTS_NO_SHMEM?=1
#
# This is a meta-argument and enables: MODEL_NO_EXECUTABLE, LIBRTS_NO_EXAMPLES, LIBRTS_NO_UNIT_TESTS
# This is useful if you are on a foreign system and just want to use the python model bindings. 
LIBRTS_BINDING_ONLY?=0

# Don't build model executable, only library
ifneq ($(MODEL_NO_EXECUTABLE), 0)
MODEL_CMAKE_FLAGS += -DMODEL_NO_EXECUTABLE=1 
endif

ifneq ($(USE_STDLIB_MATH), 0)
MODEL_CMAKE_FLAGS += -DUSE_STDLIB_MATH=1
LIBRTS_CMAKE_FLAGS += -DUSE_STDLIB_MATH=1
endif

# Force static inline on all LIGO_INLINE marked functions, default is yes
ifneq ($(FORCE_STATIC_INLINE), 0)
MODEL_CMAKE_FLAGS += -DFORCE_STATIC_INLINE=1 
endif 

# Don't use posix shmem, local memory only
ifneq ($(LIBRTS_NO_SHMEM), 0)
LIBRTS_CMAKE_FLAGS += -DLIBRTS_NO_SHMEM=1 
endif

# Don't build the c++ examples in librts
ifneq ($(LIBRTS_NO_EXAMPLES), 0)
LIBRTS_CMAKE_FLAGS += -DLIBRTS_NO_EXAMPLES=1 
endif

# Don't build the c++ unit tests in librts
ifneq ($(LIBRTS_NO_UNIT_TESTS), 0)
LIBRTS_CMAKE_FLAGS += -DLIBRTS_NO_UNIT_TESTS=1
endif

# If we are only building bindings, don't build model exe or tests/exampls
ifneq ($(LIBRTS_BINDING_ONLY), 0)
MODEL_CMAKE_FLAGS += -DMODEL_NO_EXECUTABLE=1
LIBRTS_CMAKE_FLAGS += -DLIBRTS_NO_EXAMPLES=1
LIBRTS_CMAKE_FLAGS += -DLIBRTS_NO_UNIT_TESTS=1
endif 

$(info $$MODEL_CMAKE_FLAGS are [${MODEL_CMAKE_FLAGS}])
$(info $$LIBRTS_CMAKE_FLAGS are [${LIBRTS_CMAKE_FLAGS}])


#When we are building from the rtcds command, set these from 
#the environment that command sets
ifdef LIBRTS_OUT_OF_TREE_BUILD

bld_dir:=$(RCG_BUILDD)
srcdir:=$(RCG_SRC)
lib_bld_dir:=$(bld_dir)/models/librts/

else

bld_dir:=$(repo_dir)/build/rcg-build/
srcdir:=$(repo_dir)/../../
lib_bld_dir:=$(repo_dir)/build/cmake/

endif

code_gen_dir:=$(srcdir)/src/epics/util
models_dir:= $(bld_dir)/models
bld_utils_dir:= $(bld_dir)/utils
NUM_BUILD_THREDS?=2

include $(repo_dir)/env/RCG.mk #Comment line out when building production models
#include $(repo_dir)/env/USERAPPS_ENV_VARS.mk  #Uncomment when building production models

ifndef RCG_SRC
export RCG_SRC:=$(srcdir)/
endif
ifndef RCG_BUILDD
export RCG_BUILDD:=$(bld_dir)
endif
ifndef CDS_IFO_SRC
export CDS_IFO_SRC=$(RCG_SRC)/src/include/
endif
ifndef RCG_LIB_PATH
export RCG_LIB_PATH:=:$(srcdir)/src/epics/simLink/:$(srcdir)/src/epics/simLink/lib/:$(srcdir)/test/:$(repo_dir)/models/:$(file < $(repo_dir)/env/RCG_LIB_PATH.env)
endif
ifndef
export RCG_TARGET:=$(bld_dir)/ipc/
endif

define DIE
(tail $(bld_log); cat $(err_log) && false)
endef

%:

	@# Set path variables so we don't need the whole path everywhere
	$(eval model_bld_dir := $(bld_dir)/models/$@/)
	$(eval target_dir := $(model_bld_dir)/target/)
	$(eval model_log_dir := $(bld_dir)/models/$@/logs)
	$(eval err_log := $(model_log_dir)/$@_error.log)
	$(eval bld_log := $(model_log_dir)/$@.log)
	$(eval kern_bld_dir := $(model_bld_dir)/kernel_mod/)
	$(eval us_bld_dir := $(model_bld_dir)/userspace/)
	$(eval epics_dir := $(model_bld_dir)/epics/)
	$(eval epics_src_dir := $(epics_dir)/src/)
	$(eval epics_build_dir := $(target_dir)/$@epics/)
	$(eval bld_info_dir := $(target_dir)/build_info/)
	$(eval target_bin_dir := $(target_dir)/bin/)

#When we are doing an out of tree build (with rtcds) we don't need to parse the model again
ifndef LIBRTS_OUT_OF_TREE_BUILD

	@rm -rf $(model_log_dir) #Clear out logs
	@mkdir -p $(lib_bld_dir) $(bld_dir) $(bld_utils_dir)/epics/util $(models_dir) $(epics_dir)/fmseq $(models_dir)/$@/include $(model_log_dir)
	@mkdir -p $(target_dir)/ $(target_bin_dir)/
	@ln -fs $(srcdir)/src/epics/util/lib $(bld_utils_dir)/epics/util > /dev/null 2>&1 || true
	@ln -fs $(srcdir)/src/epics/simLink $(bld_utils_dir)/epics > /dev/null 2>&1 || true
	@ln -fs $(srcdir)/src/epics/util/Makefile.kernel $(bld_utils_dir)/epics/util > /dev/null 2>&1 || true
	@ln -fs $(srcdir)/src/epics/util/Userspace_CMakeLists.cmake $(bld_utils_dir)/epics/util > /dev/null 2>&1


	@echo Parsing the model $@...
	@(cd $(bld_utils_dir)/epics/util && env SIMULATION_BUILD=1 env RCG_SRC_DIR=$(srcdir) PERL5LIB=$(code_gen_dir) $(code_gen_dir)/feCodeGen.pl $@.mdl $@ >> $(bld_log) 2>>$(err_log)) || $(DIE)
	@echo Done
	@/bin/rm -rf $(epics_dir)/$@epics-medm
	@/bin/rm -rf $(epics_dir)/$@epics-config
	@/bin/mv -f  $(epics_src_dir)/medm $(epics_dir)/$@epics-medm
	@/bin/mv -f  $(epics_src_dir)/config $(epics_dir)/$@epics-config
	@/bin/rm -rf $(epics_build_dir)/ $(epics_src_dir)/;
endif

	@mkdir -p $(epics_src_dir)
	@( cd $(epics_dir)/fmseq && cat $@ | cpp $(CFLAGS) -  | grep -v ^# | \
		RCG_SRC_DIR=$(srcdir) $(srcdir)/src/epics/util/fmseq.pl $@ $(srcdir)/src/epics/util/skeleton.db >> $(bld_log) 2>>$(err_log) ) || $(DIE)
	@( cd $(epics_dir)/fmseq && mv $(epics_dir)/fmseq/epics_map.h $(models_dir)/$@/include && mv $(notdir *).* $(epics_src_dir) )

	@echo Building front-end user space object $@...
	@if [ ! -L $(us_bld_dir)/src ]; then ln -s $(srcdir)/src/ $(us_bld_dir)/src; fi
	@mkdir -p $(us_bld_dir)/build
	@cmake -B$(us_bld_dir)/build/ -S$(us_bld_dir) $(MODEL_CMAKE_FLAGS) -DDEFAULT_TO_SHMEM_BUFFERS=1 -DMODEL_NAME=$@ >> $(bld_log) 2>>$(err_log) || $(DIE)
	@make -j $(NUM_BUILD_THREDS) -C $(us_bld_dir)/build >> $(bld_log) 2>>$(err_log) || $(DIE)
	@$(RCG_SRC)/src/librts/scripts/buildMapFromHeader.py \
		$(model_bld_dir)/include/$@.h \
		$(model_bld_dir)/epics/fmseq/$@ \
		$(model_bld_dir)/include/var_lookup_table.h  >> $(bld_log) 2>>$(err_log) || $(DIE)
	@echo Done

	@echo Building rtsLib for the model $@...
	@cmake -B $(lib_bld_dir) -S$(repo_dir) $(LIBRTS_CMAKE_FLAGS) -DMODEL_NAME=$@ >> $(bld_log) 2>>$(err_log) || $(DIE)
	@make -j $(NUM_BUILD_THREDS) -C $(lib_bld_dir) >> $(bld_log) 2>>$(err_log) || $(DIE)
	@echo Done

ifndef LIBRTS_OUT_OF_TREE_BUILD

	@echo RCG source code directory:
	@echo $(srcdir)
	@echo The following files were used for this build:
	@sort $(epics_dir)/sources.$@ | uniq
endif
	@echo
	@echo  Successfully compiled $@ librts interface

	@#Print rcg warnings if we have any
	@if [ -s $(model_log_dir)/$@_warnings.log ]; then \
		printf '\nRGC Warnings found in $(model_log_dir)/$@_warnings.log:\n'; \
		printf '***********************************************\n'; \
		cat   $(model_log_dir)/$@_warnings.log; \
		printf '***********************************************\n'; fi

	@#Print c compilation errors if we have any
	@if [ -s $(err_log) ]; then \
		printf '\nC Compilation Warnings found in $(err_log)\n'; \
		printf '***********************************************\n'; \
		cat  $(err_log); \
		printf '***********************************************\n'; fi


.DEFAULT: all
.PHONY: clean all test install-modules-from-source rmmod insmod check

all:
	@echo "Please enter the name of the model you would like to build"
	@false

clean:
	rm -rf $(repo_dir)/build

check:
	@if ( git submodule status |  wc -w | grep "3" > /dev/null ) ; then echo "Check: advligorts submodule initialized!"; else echo "Error: advligorts submodule NOT initialized"; fi;

test:
	cd $(lib_bld_dir) && ctest


