CC ?= gcc
CXX ?= g++

PLATFORM ?= OS_LINUX
SUPPORT_MODULES ?= yes
TARGET ?= mrd
PREFIX ?= /usr/local
STATIC_STDCXX ?= no
FULL_STATIC ?= no
NO_INLINE ?= no
NO_INET6_OPTION ?= no

GENERATED_MODULE_LIST ?= no
EXTERNAL_MODULES ?= bgp.so

INCLUDES = -I../include

NOW = $(shell date -u)

CFLAGS += -ansi -Wall -Wno-multichar

MLD_SOURCES = mld/mld_def.cpp mld/mld_router.cpp mld/mld_conf.cpp mld/mld_module.cpp
PIM_SOURCES = pim/pim_def.cpp pim/pim_router.cpp pim/pim_interface.cpp \
	      pim/pim_group.cpp pim/pim_source.cpp pim/pim_oif.cpp \
	      pim/pim_neighbour.cpp pim/pim_conf.cpp pim/pim_bsr.cpp \
	      pim/pim_module.cpp
CONSOLE_SOURCES = console/console.cpp console/telnet_console.cpp \
		  console/unix_console.cpp
BGP_SOURCES = bgp/bgp.cpp bgp/bgp_def.cpp
MSNIP_SOURCES = msnip/msnip_module.cpp
MRDISC_SOURCES = mrdisc/mrdisc_module.cpp
RIPNG_SOURCES = ripng/ripng.cpp

MLD_EXT_SOURCES = mld/mld_def.cpp mld/mld_router.cpp mld/mld_conf.cpp extra/mld_ext.cpp

-include Makefile.options

ifeq ($(FULL_STATIC),yes)
	SUPPORT_MODULES = no
endif

ifeq ($(NO_INET6_OPTION),yes)
	CFLAGS += -DNO_INET6_OPTION
endif

DEST_PREFIX = $(DESTDIR)$(PREFIX)

ifeq ($(OPTIMIZE),yes)
	ifeq ($(SPACE_OPTIMIZE),yes)
		CFLAGS += -O3 -Os
	else
		CFLAGS += -O3
	endif
else
	CFLAGS += -g
	ifeq ($(NO_INLINE),yes)
		CFLAGS += -O0 -fno-inline
	else
		CFLAGS += -O2
	endif
endif

MRD_CXXFLAGS = -fno-rtti -fno-exceptions -fPIC -D$(PLATFORM)

MODULE_OPTIONS_CXXFLAGS = $(addprefix -D,$(MODULE_OPTIONS))

CXXFLAGS = $(INCLUDES) $(CFLAGS) $(MRD_CXXFLAGS) $(MODULE_OPTIONS_CXXFLAGS)

MLD_OBJECTS = $(MLD_SOURCES:.cpp=.o)
PIM_OBJECTS = $(PIM_SOURCES:.cpp=.o)
CONSOLE_OBJECTS = $(CONSOLE_SOURCES:.cpp=.o)
BGP_OBJECTS = $(BGP_SOURCES:.cpp=.o)
MSNIP_OBJECTS = $(MSNIP_SOURCES:.cpp=.o)
MRDISC_OBJECTS = $(MRDISC_SOURCES:.cpp=.o)
RIPNG_OBJECTS = $(RIPNG_SOURCES:.cpp=.o)

MLD_EXT_OBJECTS = $(MLD_EXT_SOURCES:.cpp=.o)

STATIC_MODULES_CPP = modules.cpp

ifeq ($(GENERATED_MODULE_LIST),no)
	CXXFLAGS += -DMRD_STATIC_MLD -DMRD_STATIC_PIM -DMRD_STATIC_CONSOLE
	STATIC_MODULE_SOURCES = $(MLD_SOURCES) $(PIM_SOURCES) $(CONSOLE_SOURCES)
else
	STATIC_MODULES_CPP = modules.generated.cpp
endif

ifeq ($(SUPPORT_MODULES),no)
	CXXFLAGS += -DMRD_NO_DYNAMIC_MODULE_LOADING
endif

ifeq ($(FULL_STATIC),yes)
	LDCMD = -static
else
	ifeq ($(SUPPORT_MODULES),yes)
		LDCMD = -rdynamic
	endif
endif

LDFLAGS += -lm
ifeq ($(PLATFORM),OS_LINUX)
	LDFLAGS += -ldl
endif

ifeq ($(STATIC_STDCXX),no)
	LDFLAGS += -lstdc++
else
	LDFLAGS += `$(CXX) -print-file-name=libstdc++.a`
endif

LINUX_SOURCES = linux/us_mfa.cpp linux/linux_icmp_raw.cpp \
		linux/linux_unicast_route.cpp linux/mrd_components.cpp

BSD_SOURCES = bsd/bsd_rib.cpp bsd/bsd_mfa.cpp bsd/mrd_components.cpp

SOURCES = address.cpp address_set.cpp group.cpp icmp_inet6.cpp icmp.cpp \
	  interface.cpp log.cpp main.cpp mfa.cpp mrd.cpp mrib.cpp node.cpp \
	  parser.cpp rib.cpp router.cpp timers.cpp support/objpool.cpp \
	  $(STATIC_MODULES_CPP)

ifeq ($(PLATFORM),OS_LINUX)
	SOURCES += $(LINUX_SOURCES)
endif

ifeq ($(PLATFORM),OS_BSD)
	SOURCES += $(BSD_SOURCES)
endif

BASE_OBJECTS = $(SOURCES:.cpp=.o)

MRD_SOURCES = $(SOURCES) $(STATIC_MODULE_SOURCES) mrd.version.cpp

MRD_OBJECTS = $(MRD_SOURCES:.cpp=.o)

MODULE_CXX = $(CXX) -shared $(CXXFLAGS)

all: $(TARGET) $(EXTERNAL_MODULES)

$(TARGET): $(OBJECTS) $(MRD_OBJECTS)
	@echo "Linking $(TARGET)"
	@$(CC) $(LDCMD) $(CXXFLAGS) -o $@ $(MRD_OBJECTS) $(LDFLAGS)

install: $(TARGET) $(EXTERNAL_MODULES)
	install -D $(TARGET) $(DEST_PREFIX)/sbin/$(TARGET)
	install -D ../tools/mrd6sh $(DEST_PREFIX)/bin/mrd6sh
	install -D $(EXTERNAL_MODULES) $(DEST_PREFIX)/lib/mrd6/

mrd.version.cpp: $(SOURCES) Makefile
	@echo '/* This file is automatically generated */' > mrd.version.cpp
	@echo 'const char *BuildDate = "$(NOW)";' >> mrd.version.cpp

mld.so: $(MLD_OBJECTS)
	@echo "Module $@"
	@$(MODULE_CXX) -o $@ $+

pim.so: $(PIM_OBJECTS)
	@echo "Module $@"
	@$(MODULE_CXX) -o $@ $+

console.so: $(CONSOLE_OBJECTS)
	@echo "Module $@"
	@$(MODULE_CXX) -o $@ $+

bgp.so: $(BGP_OBJECTS)
	@echo "Module $@"
	@$(MODULE_CXX) -o $@ $+

msnip.so: $(MSNIP_OBJECTS)
	@echo "Module $@"
	@$(MODULE_CXX) -o $@ $+

mrdisc.so: $(MRDISC_OBJECTS)
	@echo "Module $@"
	@$(MODULE_CXX) -o $@ $+

ripng.so: $(RIPNG_OBJECTS)
	@echo "Module $@"
	@$(MODULE_CXX) -o $@ $+

mld_ext.so: $(MLD_EXT_OBJECTS)
	@echo "Module $@"
	@$(MODULE_CXX) -o $@ $+

OPTIONS = Makefile.options

$(OPTIONS):
	@touch $@

.deps/%.d: %.cpp $(OPTIONS)
	@echo "Deps $<"
	@set -e; mkdir -p $(dir $@); rm -f $@; \
	$(CXX) -MM $(CXXFLAGS) $< > $@.$$$$; \
	echo -n "$@ $(dir $<)" > $@; cat $@.$$$$ >> $@; \
	rm -f $@.$$$$

DEPENDENCIES = $(addprefix .deps/,$(MRD_SOURCES:.cpp=.d))

ifneq ($(MAKECMDGOALS),clean)
	-include $(DEPENDENCIES)
endif

%.o: %.cpp $(OPTIONS)
	@echo "C++ $<"
	@$(CXX) -c $(CXXFLAGS) $< -o $@

clean:
	rm -rf $(TARGET) $(MRD_OBJECTS) \
	$(MLD_OBJECTS) $(PIM_OBJECTS) $(CONSOLE_OBJECTS) \
	$(BGP_OBJECTS) $(MSNIP_OBJECTS) $(MRDISC_OBJECTS) \
	$(RIPNG_OBJECTS) *.so

.PHONY: install clean

