# GNU Makefile

# Paths
SRC_LIBCOM   = lib_com
SRC_LIBDEBUG = lib_debug
SRC_LIBDEC   = lib_dec
SRC_LIBENC   = lib_enc
SRC_LIBREND  = lib_rend
SRC_LIBISAR  = lib_isar
SRC_LC3PLUS  = lib_lc3plus lib_lc3plus/fft
SRC_LIBUTIL  = lib_util
SRC_APP      = apps
BUILD        = build
OBJDIR       = obj

SRC_DIRS  = $(sort -u $(SRC_LIBCOM) $(SRC_LIBDEBUG) $(SRC_LIBDEC) $(SRC_LIBENC) $(SRC_LIBREND) $(SRC_LIBISAR) $(SRC_LC3PLUS) $(SRC_LIBUTIL) $(SRC_APP)) 

# Name of CLI binaries
CLI_APIDEC   	?= IVAS_dec
CLI_APIENC   	?= IVAS_cod
CLI_APIREND  	?= IVAS_rend
CLI_APIPOSTREND ?= ISAR_post_rend
LIB_LIBCOM   	?= libivascom.a
LIB_LIBDEBUG 	?= libivasdebug.a
LIB_LIBDEC   	?= libivasdec.a
LIB_LIBENC   	?= libivasenc.a
LIB_LIBREND  	?= libivasrend.a
LIB_LIBISAR  	?= libisar.a
LIB_LC3PLUS  	?= liblc3plus.a
LIB_LIBUTIL  	?= libivasutil.a


# Default tool settings
CC        ?= gcc
RM        ?= rm -f
AR        ?= ar

# Detect system
UNAME_S   := $(shell uname -s)

# Switches for cross-platform builds (i.e. build 32 bit code on 64 bit platforms)
ifneq "$(TARGET_PLATFORM)" ""
ifeq ("$(TARGET_PLATFORM)", "$(findstring $(TARGET_PLATFORM), i386 i586 i686)")
	CFLAGS  += -m32
	LDFLAGS += -m32
endif

ifeq ("$(TARGET_PLATFORM)", "$(findstring $(TARGET_PLATFORM), x86_64)")
	CFLAGS  += -m64
	LDFLAGS += -m64
endif
endif

ifndef VERBOSE
QUIET_CC  = @echo '   ' Compiling $<;
QUIET_LINK= @echo '   ' Linking $@;
QUIET_AR  = @echo '   ' Archiving $@;
QUIET     = @
endif

# C compiler flags
CFLAGS   += -std=c99 -pedantic -Wcast-qual -Wall -W -Wextra -Wno-long-long     \
            -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes  \
            -Wno-implicit-fallthrough -ffp-contract=off
# to be uncommented in CI
# CFLAGS += -Werror

# libs to link
LDLIBS   += -lm

# Clang sanitizer compiler options
CCCLANG = clang
ifeq "$(CLANG)" "1"
CC       = $(CCCLANG)
CFLAGS  += -fsanitize=memory
LDFLAGS += -fsanitize=memory
endif
ifeq "$(CLANG)" "2"
CC       = $(CCCLANG)
CFLAGS  += -fsanitize=address
LDFLAGS += -fsanitize=address
endif
ifeq "$(CLANG)" "3"
CC       = $(CCCLANG) 
# NOTE: keep in sync with list in CMakeLists.txt
usan_checks = undefined,float-divide-by-zero,implicit-conversion,local-bounds
CFLAGS  += -fsanitize=$(usan_checks) 
CFLAGS  += -fsanitize-recover=$(usan_checks) 
LDFLAGS += -fsanitize=$(usan_checks)
LDFLAGS += -fsanitize-recover=$(usan_checks)
endif

ifeq "$(RELEASE)" "1"
CFLAGS   += -DRELEASE
OPTIM    ?= 2
endif

ifneq "$(DEBUG)" "0"
CFLAGS   += -g3
LDFLAGS  += -g3
endif

ifeq "$(GCOV)" "1"
CFLAGS  += -fprofile-arcs -ftest-coverage -fprofile-update=atomic
LDFLAGS += -fprofile-arcs -ftest-coverage -fprofile-update=atomic
endif

ifeq "$(STRIP)" "1"
CFLAGS   += -fdata-sections -ffunction-sections
ifneq ($(UNAME_S),Darwin)
LDFLAGS  += -Wl,-gc-sections -static
else
LDFLAGS  += -Wl,-dead_strip
endif
endif

OPTIM    ?= 0
CFLAGS   += -O$(OPTIM)

CFLAGS   += $(foreach DIR,$(SRC_DIRS),-I$(DIR))

# Source file search paths
VPATH     = $(SRC_DIRS)

# Split rendering files
SRCS_SPLIT_REND = ivas_CQMFDecoder.c ivas_CQMFEncoder.c ivas_PerceptualModel.c ivas_PredDecoder.c \
                  ivas_PredEncoder.c ivas_RMSEnvGrouping.c ivas_MSPred.c ivas_NoiseGen.c \
                  ivas_splitRend_lcld_dec.c ivas_splitRend_lcld_enc.c \
                  ivas_splitRendererPLC.c ivas_splitRendererPost.c ivas_splitRendererPre.c \
                  ivas_splitRenderer_utils.c split_rend_bfi_file_reader.c split_render_file_read_write.c \
                  ivas_lcld_tables.c

     
###############################################################################

SRCS_LIBCOM   = $(foreach DIR,$(SRC_LIBCOM),$(patsubst $(DIR)/%,%,$(wildcard $(DIR)/*.c)))
SRCS_LIBDEBUG = $(foreach DIR,$(SRC_LIBDEBUG),$(patsubst $(DIR)/%,%,$(wildcard $(DIR)/*.c)))
SRCS_LIBDEC   = $(foreach DIR,$(SRC_LIBDEC),$(patsubst $(DIR)/%,%,$(wildcard $(DIR)/*.c)))
SRCS_LIBENC   = $(foreach DIR,$(SRC_LIBENC),$(patsubst $(DIR)/%,%,$(wildcard $(DIR)/*.c)))
SRCS_LIBREND  = $(foreach DIR,$(SRC_LIBREND),$(patsubst $(DIR)/%,%,$(wildcard $(DIR)/*.c)))
SRCS_LIBUTIL  = $(foreach DIR,$(SRC_LIBUTIL),$(patsubst $(DIR)/%,%,$(wildcard $(DIR)/*.c)))
SRCS_LIBISAR  = $(foreach DIR,$(SRC_LIBISAR),$(patsubst $(DIR)/%,%,$(wildcard $(DIR)/*.c)))
SRCS_LC3PLUS  = $(foreach DIR,$(SRC_LC3PLUS),$(patsubst $(DIR)/%,%,$(wildcard $(DIR)/*.c)))

OBJS_LIBCOM      = $(addprefix $(OBJDIR)/,$(SRCS_LIBCOM:.c=.o))
OBJS_LIBDEBUG    = $(addprefix $(OBJDIR)/,$(SRCS_LIBDEBUG:.c=.o))
OBJS_LIBDEC      = $(addprefix $(OBJDIR)/,$(SRCS_LIBDEC:.c=.o))
OBJS_LIBENC      = $(addprefix $(OBJDIR)/,$(SRCS_LIBENC:.c=.o))
OBJS_LIBREND     = $(addprefix $(OBJDIR)/,$(SRCS_LIBREND:.c=.o))
OBJS_LIBISAR     = $(addprefix $(OBJDIR)/,$(SRCS_LIBISAR:.c=.o))
OBJS_LC3PLUS     = $(addprefix $(OBJDIR)/,$(SRCS_LC3PLUS:.c=.o))
OBJS_LIBUTIL     = $(addprefix $(OBJDIR)/,$(SRCS_LIBUTIL:.c=.o))
OBJS_CLI_APIDEC  = $(OBJDIR)/decoder.o
OBJS_CLI_APIENC  = $(OBJDIR)/encoder.o
OBJS_CLI_APPREND = $(OBJDIR)/renderer.o
OBJS_CLI_APPPOSTREND = $(OBJDIR)/isar_post_rend.o

DEPS = $(addprefix $(OBJDIR)/,$(SRCS_LIBCOM:.c=.P) $(SRCS_LIBDEBUG:.c=.P) $(SRCS_LIBDEC:.c=.P) \
  $(SRCS_LIBENC:.c=.P) $(SRCS_LIBUTIL:.c=.P) $(SRCS_LIBREND:.c=.P) $(SRCS_LIBISAR:.c=.P) \
  $(SRCS_LC3PLUS:.c=.P))

###############################################################################

.PHONY: all clean

all: $(CLI_APIENC) $(CLI_APIDEC) $(CLI_APIREND) $(CLI_APIPOSTREND)

$(OBJDIR):
	$(QUIET)mkdir -p $(OBJDIR)

$(LIB_LIBCOM): $(OBJS_LIBCOM)
	$(QUIET_AR)$(AR) rcs $@ $^

$(LIB_LIBDEC): $(OBJS_LIBDEC) $(OBJS_LIBREND) $(OBJS_LIBISAR)
	$(QUIET_AR)$(AR) rcs $@ $^

$(LIB_LIBDEBUG): $(OBJS_LIBDEBUG)
	$(QUIET_AR)$(AR) rcs $@ $^

$(LIB_LIBISAR): $(OBJS_LIBISAR)
	$(QUIET_AR)$(AR) rcs $@ $^

$(LIB_LIBENC): $(OBJS_LIBENC)
	$(QUIET_AR)$(AR) rcs $@ $^

$(LIB_LIBREND): $(OBJS_LIBREND) $(OBJS_LIBISAR)
	$(QUIET_AR)$(AR) rcs $@ $^

$(LIB_LC3PLUS): $(OBJS_LC3PLUS)
	$(QUIET_AR)$(AR) rcs $@ $^

$(LIB_LIBUTIL): $(OBJS_LIBUTIL)
	$(QUIET_AR)$(AR) rcs $@ $^

$(CLI_APIENC): $(OBJS_CLI_APIENC) $(LIB_LIBENC) $(LIB_LIBCOM) $(LIB_LIBUTIL) $(LIB_LIBDEBUG) $(LIB_LC3PLUS)
	$(QUIET_LINK)$(CC) $(LDFLAGS) $(OBJS_CLI_APIENC) -L. -livasenc -livascom -livasutil -livasdebug $(LDLIBS) -o $(CLI_APIENC)

$(CLI_APIDEC): $(OBJS_CLI_APIDEC) $(LIB_LIBDEC) $(LIB_LIBCOM) $(LIB_LIBUTIL) $(LIB_LIBDEBUG) $(LIB_LC3PLUS) $(LIB_LIBISAR)
	$(QUIET_LINK)$(CC) $(LDFLAGS) $(OBJS_CLI_APIDEC) -L. -livasdec -livascom -livasutil -livasdebug -llc3plus $(LDLIBS) -o $(CLI_APIDEC)

$(CLI_APIREND): $(OBJS_CLI_APPREND) $(LIB_LIBREND) $(LIB_LIBCOM) $(LIB_LIBUTIL) $(LIB_LIBDEBUG) $(LIB_LIBDEC) $(LIB_LC3PLUS) $(LIB_LIBISAR)
	$(QUIET_LINK)$(CC) $(LDFLAGS) $(OBJS_CLI_APPREND) -L. -livasrend -lisar -livasdec -livasutil -livasdebug -livascom -llc3plus $(LDLIBS) -o $(CLI_APIREND)

$(CLI_APIPOSTREND): $(OBJS_CLI_APPPOSTREND) $(LIB_LIBISAR) $(LIB_LIBCOM) $(LIB_LIBUTIL) $(LIB_LIBDEBUG) $(LIB_LC3PLUS)
	$(QUIET_LINK)$(CC) $(LDFLAGS) $(OBJS_CLI_APPPOSTREND) -L. -lisar -livasutil -livasdebug -livascom -llc3plus $(LDLIBS) -o $(CLI_APIPOSTREND)

libs: $(LIB_LIBENC) $(LIB_LIBDEBUG) $(LIB_LIBCOM) $(LIB_LIBDEC) $(LIB_LIBREND) $(LIB_LIBISAR) $(LIB_LC3PLUS) $(LIB_LIBUTIL)

clean: 
	$(QUIET)$(RM) $(OBJS_LIBENC) $(OBJS_LIBDEC) $(DEPS)
	$(QUIET)$(RM) $(DEPS:.P=.d)
	$(QUIET)test ! -d $(OBJDIR) || rm -rf $(OBJDIR)
	$(QUIET)$(RM) $(CLI_APIENC) $(CLI_APIDEC) $(CLI_APIREND) $(CLI_APIPOSTREND) $(LIB_LIBENC) $(LIB_LIBDEBUG) $(LIB_LIBCOM) $(LIB_LIBDEC) $(LIB_LIBUTIL) $(LIB_LIBREND) $(LIB_LIBISAR) $(LIB_LC3PLUS)

$(OBJDIR)/%.o : %.c | $(OBJDIR)
	$(QUIET_CC)$(CC) $(CFLAGS) -c -MD -o $@ $<
	@cp $(OBJDIR)/$*.d $(OBJDIR)/$*.P; \
	sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
	    -e '/^$$/ d' -e 's/$$/ :/' < $(OBJDIR)/$*.d >> $(OBJDIR)/$*.P; \
	$(RM) $(OBJDIR)/$*.d

-include $(DEPS)
