# This Makefile wants GNU Make!

.SUFFIXES:
.SUFFIXES: .cxx .hxx .o .bin

# To be tuned from the outside.
# Not all are used yet.
PREFIX=/usr/local
# Those are fixed in relation to the prefix setting. The frontend scripts rely on that.
#SYSCONFDIR=$(PREFIX/etc)
BINDIR=$(PREFIX)/bin
LIBDIR=$(PREFIX)/lib
DOCDIR=$(PREFIX)/share/doc/dermixd

# We put Perl suff in there... it might be better to have that in the "proper" places instead.
# The frontend scripts themselves look for $BINDIR/../lib/dermixd/DerMixD/.
DMDLIBDIR=$(LIBDIR)/dermixd
DMDMODDIR=$(DMDLIBDIR)/DerMixD

# Does this hurt on other platforms than linux?
DEFINES:=-D_REENTRANT

ifneq ($(SKIP_CONFIG),yes)
  include config.mk
  # Things can be left blank in config for on-line auto detection.
  include autodetect.mk
endif

# Try automatic large file support.
LFS_CFLAGS=$(shell getconf LFS_CFLAGS 2>/dev/null)
LFS_LDFLAGS=$(shell getconf LFS_LDFLAGS 2>/dev/null)
LFS_LIBS=$(shell getconf LFS_LIBS 2>/dev/null)

# This enables debugging printouts in dermixd code only.
# Make sure to include -g or equivalent in your CXXFLAGS if you want debugging symbols.
ifeq ($(DEBUG),yes)
  DEFINES := $(DEFINES) -DDEBUG
endif
ifeq ($(XDEBUG),yes)
  DEFINES := $(DEFINES) -DXDEBUG
endif
ifeq ($(MEMDEBUG),yes)
  DEFINES := $(DEFINES) -DMEMDEBUG
endif

# Not just Linux needs POSIX thread lib, but it's differently named elsewhere.
# Fix that for portability.
# ... BSD build should be very similar to Linux build.
ifeq ($(shell uname -s),Linux)
  LDFLAGS:=$(LDFLAGS) -lpthread
  ifeq ($(OSS),)
    OSS:=yes
  endif
  ifeq ($(LINUX),)
    LINUX:=yes
  endif
endif
ifeq ($(shell uname -s),OSF1)
  LDFLAGS:=$(LDFLAGS) -lpthread  -lrt -lm
  #WANT_PORT_T enables use of type in_port_t for port number, otherwise it's u_int16_t; Tru64 wants it, GNU/Linux not
  DEFINES:=$(DEFINES) -I/usr/include/mme -D__USE_STD_IOSTREAM -DBAD_OSTRINGSTREAM -DWANT_PORT_T
  ifeq ($(CXX),)
    CXX=cxx
    CXXFLAGS=-std ansi -pthread $(CXXFLAGS)
  endif
  ifeq ($(MME),)
    MME:=yes
  endif
endif
ifeq ($(shell uname -s),SunOS)
  LDFLAGS:=$(LDFLAGS) -lpthread -lrt -lsocket -lnsl
endif

# Linux hacks, optional (but enabled by default above(.
ifeq ($(LINUX), yes)
  DEFINES := $(DEFINES) -DLINUX
endif

# List of optional objects/headers that are _not_ included in this build.
# The dependency generator uses that list to omit them.
BLACKLIST:= \
src/in/drv/in_sndfile \
src/in/drv/in_vorbisfile \
src/in/drv/in_libmpg123 \
src/out/drv/out_oss \
src/out/drv/out_alsa \
src/out/drv/out_mme \
src/module \
src/audio/effect/timepitch \
src/audio/effect/ladspa

ifeq ($(SNDFILE), yes)
  EXTRA_LIBS:=$(EXTRA_LIBS) $(shell pkg-config --libs sndfile)
  DEFINES:=$(DEFINES) -DIN_SNDFILE
  BLACKLIST:=$(filter-out src/in/drv/in_sndfile, $(BLACKLIST))
endif
ifeq ($(VORBISFILE), yes)
  EXTRA_LIBS:=$(EXTRA_LIBS) $(shell pkg-config --libs vorbisfile)
  DEFINES:=$(DEFINES) -DIN_VORBISFILE
  BLACKLIST:=$(filter-out src/in/drv/in_vorbisfile, $(BLACKLIST))
endif
ifeq ($(MPG123), yes)
  EXTRA_LIBS:=$(EXTRA_LIBS) $(shell pkg-config --libs libmpg123)
  DEFINES:=$(DEFINES) -DIN_LIBMPG123
  BLACKLIST:=$(filter-out src/in/drv/in_libmpg123, $(BLACKLIST))
endif
ifeq ($(SOUNDTOUCH), yes)
  EXTRA_LIBS:=$(EXTRA_LIBS) $(shell pkg-config --libs soundtouch-1.4)
  DEFINES:=$(DEFINES) -DEFFECT_TIMEPITCH
  BLACKLIST:=$(filter-out src/audio/effect/timepitch, $(BLACKLIST))
endif
ifeq ($(LADSPA), yes)
  MODULES:=yes
  DEFINES:=$(DEFINES) -DEFFECT_LADSPA
  BLACKLIST:=$(filter-out src/audio/effect/ladspa, $(BLACKLIST))
endif
# That is rather platform specific ... module means using libdl.
ifeq ($(MODULES), yes)
  EXTRA_LIBS:=$(EXTRA_LIBS) -ldl
  BLACKLIST:=$(filter-out src/module, $(BLACKLIST))
endif

ifeq ($(MAGIC), yes)
  DEFINES:=$(DEFINES) -DHAVE_MAGIC
  EXTRA_LIBS:=$(EXTRA_LIBS) -lmagic
endif

ifeq ($(OSS),yes)
  DEFINES:=$(DEFINES) -DOUT_OSS
  BLACKLIST:=$(filter-out src/out/drv/out_oss, $(BLACKLIST))
endif
ifeq ($(ALSA),yes)
  EXTRA_LIBS:=$(EXTRA_LIBS) $(shell pkg-config --libs alsa)
  DEFINES:=$(DEFINES) -DOUT_ALSA $(shell pkg-config --cflags alsa)
  BLACKLIST:=$(filter-out src/out/drv/out_alsa, $(BLACKLIST))
endif
ifeq ($(MME),yes)
  DEFINES:=$(DEFINES) -DOUT_MME
  BLACKLIST:=$(filter-out src/out/drv/out_mme, $(BLACKLIST))
endif

# You specify CXX / CXXFLAGS, usually.
ifeq ($(CXX),)
  CXX=c++
endif
ifeq ($(CXX),g++)
  CXXFLAGS:= $(CXXFLAGS) -fno-exceptions
else
  $(info Make sure you have disabled exceptions in your CXXFLAGS!)
  $(info DerMixD does not use these and they break things badly.)
endif

COMPILE=$(CXX)  $(CXXFLAGS) $(LFS_CFLAGS) -I. -Isrc $(CPPFLAGS) $(DEFINES)

# The list of files for cleanup is added by depfiles.
cleanfiles =
# The automatic dependencies need to be included after the list of optionals, so that $^ works in the build rules!
depfiles = $(addprefix .deps/,$(filter-out .deps/% old_stuff/%, $(patsubst ./%, %, $(shell find . -name '*.cxx'))))

tests = $(patsubst tests/%.cxx, bin/tests/%, $(wildcard tests/*.cxx))
human-tests = $(patsubst human-tests/%.cxx, bin/human-tests/%, $(wildcard human-tests/*.cxx))
ifneq ($(LADSPA),yes)
  # Need to filter out the ladspa test program.
  human-tests := $(filter-out bin/human-tests/ladspa, $(human-tests))
endif

# wrap text paragraphs to terminal
format := $(shell scripts/wrap.sh)

.PHONY: all help info config check clean allclean install

#all: bin/dermixd
all: $(human-tests) check bin/dermixd

config: config.mk
	@echo "This is your DerMixD build configuration, stored in $<:"
	@echo
	@cat $<

# That's quite rough and inefficient ... but a proof of concept:
# Store the current config so that it's a default for further make runs.
# Would be cool if I could trigger recreation of stuff to changes in this file (not every touch, just real changes).
# Missing the g to be able to create configwhatever.mk for getting at parameter description without modifying current config.
confi%.mk:
	@echo "# Attempt at storing first make run configuration - you might hack around here if you know what you're doing." > $@
	@for line in \
	'$$(info )' \
	'$$(info *******************************)' \
	'$$(info Including stored configuration.)' \
	'$$(info *******************************)' \
	'$$(info )' \
	"# internal marker for stored config" \
	"FIXED_CONFIG := yes" \
	"# directory prefix" \
	"PREFIX := $(PREFIX)" \
	"# enable/disable debugging messages" \
	"DEBUG      := $(DEBUG)" \
	"# enable/disable extreme debugging messages" \
	"XDEBUG     := $(XDEBUG)" \
	"# enable/disable memory debugging messages" \
	"MEMDEBUG   := $(MEMDEBUG)" \
	"# enable/disable use of Linux specifics, namely a hack to get thread priorities that works with NPTL (proper thread priorities are not implemented, but trivial to add)" \
	"LINUX      := $(LINUX)" \
	"# enable/disable use of sndfile"  \
	"SNDFILE    := $(SNDFILE)" \
	"# enable/disable use of vorbisfile" \
	"VORBISFILE := $(VORBISFILE)" \
	"# enable/disable use of mpg123 library" \
	"MPG123     := $(MPG123)" \
	"# enable/disable use of soundtouch" \
	"SOUNDTOUCH := $(SOUNDTOUCH)" \
	"# enable/disable use of dynamic loading (leave untouched, please)" \
	"MODULES    := $(MODULES)" \
	"# enable/disable use of LADSPA plugins" \
	"LADSPA     := $(LADSPA)" \
	"# enable/disable use of OSS output" \
	"OSS        := $(OSS)" \
	"# enable/disable use of MME output" \
	"MME        := $(MME)" \
	"# enable/disable use of ALSA output" \
	"ALSA       := $(ALSA)" \
	"# enable/disable use of libmagic" \
	"MAGIC       := $(MAGIC)" \
	; do echo "$$line"; done >> $@

help:
	@echo
	@echo "This Makefile for GNU Make includes (auto)configuration, dynamic dependency generation and build. Stuff happens automatically to give you the main build of DerMixD after calling simply 'make'. You are encouraged to provide the compiler and flags to use via standard CXX, CXXFLAGS, CPPFLAGS and LDFLAGS environment variables." | $(format)
	@echo
	@echo "Build configuration happens via make variables, set in the command line or via a mix of defaults and auto detection. See config.mk for variables and their current (detected) settings. Also note that an existing config.mk will skip the auto detection step." | $(format)
	@echo
	@echo Example:
	@echo "	make DEBUG=yes ALSA=no"
	@echo
	@echo "will prepare a full build with debugging messages enabled but without usage of the ALSA library, even if  it is present." | $(format)
	@echo
	@echo "There are several variables to tune, have a look at config.mk (build and review it via 'make config' if not present). Note that changes in this file trigger rebuild of all things, but overrides to the variables set there via command line are in effect only for things that are going to be built regardless. This is useful, since you can delete some objects of a complete build and re-build only those with DEBUG=yes." | $(format)
	@echo
	@echo "Targets:"
	@echo
	@for t in \
	"all (or none at all):" "	Do a full build including tests (execution of automatic tests and preparing of interactive tests in bin/human-tests)" \
	"config:" "	build config.mk and display it" \
	"check:" "	build/run the automatic tests" \
	"clean:" "	delete objects and binaries" \
	"allclean:" "	clean up (hopefully) everything (also dependency files)" \
	"help:" "	this help text" \
	"info:" "	some info about internal workings" \
	"bin/dermixd:" "	the main thing; also any other object file or binary works as target, too, of course" \
	"install:" "	install stuff to configured directories (use DESTDIR=DIR to relocate)" \
	"uninstall:" "	try to remove installed stuff (will not remove all directories, but the files therein)" \
	; do echo "$$t" | $(format) ; done
	@echo
	@echo
	@echo "Have fun!" | $(format)
	@echo

info:
	@echo Dependency files:
	@for i in $(depfiles); do echo "	$$i"; done
	@echo Test programs:
	@for i in $(tests); do echo "	$$i"; done
	@echo "Blacklist: "
	@for i in $(BLACKLIST); do echo "	$$i"; done

check: $(tests)
	perl scripts/test.pl $(tests)

# could one
%.o: %.cxx
	@echo '# COMPILE $@'
	$(COMPILE) -c -o $@ $<

# All end-user programs land in bin/
# Dependencies (source and object) are included in .deps/%
# Optinonal binary dependencies need to be provided in $(ADDOBJ).
bin/%:
	@echo "# LINK $@"
	@mkdir -p $(dir $@)
	@echo -n "	"
	@if test -z "$^"; then echo "Nothing to link! You gave an invalid target?!"; false; else echo '$(COMPILE) -o $@ $^ $(LDFLAGS) $(EXTRA_LIBS) '; $(COMPILE) -o $@ $^  $(LDFLAGS) $(EXTRA_LIBS) $(LFS_LDFLAGS) $(LFS_LIBS); fi

.deps/%: %
	@echo '# DEP $@'
	@mkdir -p $(shell dirname "$@")
	perl scripts/cxxdep.pl .deps/ $< '$(BLACKLIST)' 'config.mk' > $@

clean:
	rm -f $(cleanfiles)

allclean: clean
	rm -rf .deps config.mk

bins=bin/dermixd frontend/dermixd-control frontend/dermixd-player
docs=README BUGS TODO LICENSE CHANGES
dmdmods=lib/dermixd/DerMixD/Base.pm lib/dermixd/DerMixD/Control.pm

install: $(bins) $(docs) $(dmdlibs) $(dmdmods)
	install -v -d "$(DESTDIR)$(BINDIR)"
	install -v -d "$(DESTDIR)$(DOCDIR)"
	install -v -d "$(DESTDIR)$(DMDLIBDIR)"
	install -v -d "$(DESTDIR)$(DMDMODDIR)"
	install -v $(bins) "$(DESTDIR)$(BINDIR)"
	install -v $(docs) "$(DESTDIR)$(DOCDIR)"
	install -v $(dmdmods) "$(DESTDIR)$(DMDMODDIR)"

uninstall:
	for i in $(notdir $(bins)); do rm -f "$(DESTDIR)$(BINDIR)/$$i"; done
	for i in $(notdir $(docs)); do rm -f "$(DESTDIR)$(DOCDIR)/$$i"; done
	test -z "$(DMDLIBDIR)" || rm -rf "$(DESTDIR)$(DMDLIBDIR)"
	@echo "You might want to check if you want to delete those (empty?) directories (but I will not dare to guess at that!)"
	@echo
	@for i in $(DESTDIR)$(BINDIR) $(DESTDIR)$(DOCDIR) $(DESTDIR)$(LIBDIR) $(DESTDIR)$(PREFIX); do echo "$$i"; done

ifneq ($(DRY_RUN),yes) # when not going to extract parameters only
  include $(depfiles)
endif
