# Build libfec on Linux and on/for 64-bit Windows with MinGW-w64.
#
#   make                 build for the host platform
#   make linux           build Linux libraries
#   make windows         build Windows libraries (cross-build on Linux)
#   make static          build only the static library
#   make shared          build only the shared library
#   make clean           remove obj/ and lib/

ifeq ($(OS),Windows_NT)
  HOST_OS := windows
else
  HOST_OS := linux
endif

BUILD ?= $(HOST_OS)

OBJROOT := obj
OUTROOT := lib
OBJDIR  := $(OBJROOT)/$(BUILD)
OUTDIR  := $(OUTROOT)/$(BUILD)
GENDIR  := $(OBJDIR)/generated
TOOLDIR := $(OBJROOT)/tools/$(HOST_OS)

# Command-line assignments (for example CC=clang) still take precedence.
ifeq ($(BUILD),windows)
  ifeq ($(HOST_OS),windows)
    CROSS_PREFIX ?=
  else
    CROSS_PREFIX ?= x86_64-w64-mingw32-
  endif
  ifeq ($(origin CC),default)
    CC := $(CROSS_PREFIX)gcc
  endif
  ifeq ($(origin AR),default)
    AR := $(CROSS_PREFIX)ar
  endif
  ifeq ($(origin RANLIB),undefined)
    RANLIB := $(CROSS_PREFIX)ranlib
  endif
  SHARED_LIB := $(OUTDIR)/libfec.dll
  IMPORT_LIB := $(OUTDIR)/libfec.dll.a
  SHARED_FLAGS := -shared -Wl,--out-implib,$(IMPORT_LIB)
  PIC_CFLAGS :=
else ifeq ($(BUILD),linux)
  ifeq ($(origin CC),default)
    CC := gcc
  endif
  ifeq ($(origin AR),default)
    AR := ar
  endif
  ifeq ($(origin RANLIB),undefined)
    RANLIB := ranlib
  endif
  SHARED_LIB := $(OUTDIR)/libfec.so
  IMPORT_LIB :=
  SHARED_FLAGS := -shared -Wl,-soname,libfec.so
  PIC_CFLAGS := -fPIC
else
  $(error Unsupported BUILD='$(BUILD)'; use BUILD=linux or BUILD=windows)
endif

ifeq ($(origin HOSTCC),undefined)
  HOSTCC := gcc
endif

CPPFLAGS ?=
CFLAGS ?= -O2 -Wall -Wno-implicit-int -Wno-implicit-function-declaration -Wno-int-conversion
LDFLAGS ?=
LDLIBS ?= -lm
HOSTCFLAGS ?= -O2

STATIC_LIB := $(OUTDIR)/libfec.a

SOURCES := \
	cpu_mode_generic.c fec.c sim.c \
	viterbi27.c viterbi27_port.c \
	viterbi29.c viterbi29_port.c \
	viterbi615.c viterbi615_port.c \
	encode_rs_char.c encode_rs_int.c encode_rs_8.c \
	decode_rs_char.c decode_rs_int.c decode_rs_8.c \
	init_rs_char.c init_rs_int.c \
	encode_rs_ccsds.c decode_rs_ccsds.c \
	dotprod.c dotprod_port.c \
	peakval.c peakval_port.c \
	sumsq.c sumsq_port.c

GENERATED_SOURCES := $(GENDIR)/ccsds_tab.c $(GENDIR)/ccsds_tal.c
OBJECTS := $(addprefix $(OBJDIR)/,$(SOURCES:.c=.o)) \
	$(OBJDIR)/ccsds_tab.o $(OBJDIR)/ccsds_tal.o
DEPS := $(OBJECTS:.o=.d)

GEN_CCSDS := $(TOOLDIR)/gen_ccsds$(if $(filter windows,$(HOST_OS)),.exe)
GEN_TAL   := $(TOOLDIR)/gen_ccsds_tal$(if $(filter windows,$(HOST_OS)),.exe)
HOST_GEN_OBJECTS := $(TOOLDIR)/gen_ccsds.o $(TOOLDIR)/init_rs_char.o

.DEFAULT_GOAL := all
.PHONY: all build linux windows static shared check-tools clean

all: build
build: check-tools static shared
static: $(STATIC_LIB)
shared: $(SHARED_LIB)

# Explicit platform aliases are recursive so their toolchains and paths are
# resolved with the requested BUILD value from the start.
linux:
	$(MAKE) BUILD=linux build

windows:
	$(MAKE) BUILD=windows build

check-tools:
	@command -v $(CC) >/dev/null 2>&1 || { \
		echo "Error: compiler '$(CC)' was not found."; \
		echo "On Linux install MinGW-w64; on Windows run this from an MSYS2 MinGW 64-bit shell."; \
		exit 1; \
	}

$(STATIC_LIB): $(OBJECTS) | $(OUTDIR)
	$(AR) rcs $@ $^
	$(RANLIB) $@

$(SHARED_LIB): $(OBJECTS) | $(OUTDIR)
	$(CC) $(SHARED_FLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)

$(OBJDIR)/%.o: %.c | $(OBJDIR)
	$(CC) $(CPPFLAGS) $(CFLAGS) $(PIC_CFLAGS) -MMD -MP -I. -c -o $@ $<

$(OBJDIR)/ccsds_tab.o: $(GENDIR)/ccsds_tab.c | $(OBJDIR)
	$(CC) $(CPPFLAGS) $(CFLAGS) $(PIC_CFLAGS) -MMD -MP -I. -c -o $@ $<

$(OBJDIR)/ccsds_tal.o: $(GENDIR)/ccsds_tal.c | $(OBJDIR)
	$(CC) $(CPPFLAGS) $(CFLAGS) $(PIC_CFLAGS) -MMD -MP -I. -c -o $@ $<

$(GENDIR)/ccsds_tab.c: $(GEN_CCSDS) | $(GENDIR)
	$(GEN_CCSDS) > $@

$(GENDIR)/ccsds_tal.c: $(GEN_TAL) | $(GENDIR)
	$(GEN_TAL) > $@

$(GEN_CCSDS): $(HOST_GEN_OBJECTS) | $(TOOLDIR)
	$(HOSTCC) -o $@ $^

$(GEN_TAL): gen_ccsds_tal.c | $(TOOLDIR)
	$(HOSTCC) $(HOSTCFLAGS) -I. -o $@ $<

$(TOOLDIR)/gen_ccsds.o: gen_ccsds.c char.h rs-common.h fec.h | $(TOOLDIR)
	$(HOSTCC) $(HOSTCFLAGS) -I. -c -o $@ $<

$(TOOLDIR)/init_rs_char.o: init_rs_char.c char.h rs-common.h init_rs.h fec.h | $(TOOLDIR)
	$(HOSTCC) $(HOSTCFLAGS) -I. -c -o $@ $<

$(OBJDIR) $(OUTDIR) $(GENDIR) $(TOOLDIR):
	mkdir -p $@

clean:
	-rm -rf $(OBJROOT) $(OUTROOT)

-include $(DEPS)
