# -*- Makefile -*-
# vim:set ft=make:
#
# DROPS (Dresden Realtime OPerating System) Component
#
# Make configuration file
#
# $Id: Makeconf 27602 2007-01-11 13:11:14Z adam $
#
# $Author: adam $
#
# This file is included by all Makefile-templates. This file defines macros
# for div commands, sets general DROPS-Makefile variables, ensures the
# dependencies from the various Makeconf.locals, defines the messages for
# div actions, and permits the dependency-creation on clean-rules.
#
# The macros BUILD_MULTIPLE_ARCHITECTURES and BUILD_ONE_ARCHITECTURE are
# defined here.
#
# BUILD_MULTIPLE_ARCHITECTURES is set if ARCHS is set to multiple
# architectures in the Makefile. If ARCHS is not set, the default value
# l4_i386 will be assumed, not defining BUILD_MULTIPLE_ARCHITECTURES.
# In the muli-arch case, binary.inc triggers build the files into subdirs,
# dir-name is the architecture. Then, make is called recursively with ARCH
# set to one architecture.
#
# BUILD_ONE_ARCHITECTURE is set if ARCH contains one architecture, and we
# actually build files (in subdirs for multi-arch case, in the same dir in
# the single-arch case).

ifeq ($(origin _L4DIR_MK_MAKECONF),undefined)
_L4DIR_MK_MAKECONF=y

# the default target is all
all::

# make .general.d dependent on the role-file
$(if $(ROLE),$(OBJ_DIR)/.general.d: $(L4DIR)/mk/$(ROLE))

SYSTEM_TARGET	= $(SYSTEM_TARGET_$(ARCH))
SYSTEM_TARGET_arm = arm-linux-
SYSTEM_TARGET_ia64 = /usr/local/ia64-linux/bin/
CARCHFLAGS_amd64 = -m64
IDL_SYSTEMS 	= x86-l4v2 x86-l4x0

AR		= $(SYSTEM_TARGET)ar
AS		= $(SYSTEM_TARGET)as
AWKP		= gawk --posix
CVS		= cvs -q
SVN		= svn --quiet
CP		= cp
DICEDIR		?= $(L4DIR)/../dice
DICE		= $(firstword $(wildcard $(DICEDIR)/src/dice \
				$(DROPS_STDDIR)/tool/bin/dice \
				 $(shell which dice 2>/dev/null) ) false )
DICE_CPP_NAME	= cpp0

DICE_INCDIR	?= $(DICEDIR)/include

DROPS_CC	= L4DIR=$(L4DIR) $(firstword $(wildcard \
					$(L4DIR)/tool/gcc-wrap/drops-gcc \
					$(DROPS_STDDIR)/tool/bin/drops-gcc) \
                                 false )
DROPS_CXX	= L4DIR=$(L4DIR) $(firstword $(wildcard \
					$(L4DIR)/tool/gcc-wrap/drops-c++ \
					$(DROPS_STDDIR)/tool/bin/drops-c++) \
                                 false )
ECHO		= echo

GENOFFSETS	= $(L4DIR)/tool/bin/genoffsets.pl
GOSH		= $(firstword $(wildcard $(L4DIR)/tool/gosh/gosh \
				$(DROPS_STDDIR)/tool/bin/gosh \
				 $(shell which gosh 2>/dev/null) ) false )
HOST_CC		= gcc
HOST_CXX	= g++
INDENT		= indent -sob
INSTALL		= install
# the following two variables should be overwritten in Makeconf.bid.local
LD		= $(SYSTEM_TARGET)ld
LATEX		= latex
PDFLATEX	= pdflatex
GREP		= grep
LN		= ln
MKDIR		= mkdir -p
MKFLAGS		+=$(MKFLAGS_$@)
NM		= $(SYSTEM_TARGET)nm
OBJCOPY		= $(SYSTEM_TARGET)objcopy
PWDCMD		= sh -c pwd
RANLIB		= $(SYSTEM_TARGET)ranlib
RM		= rm -f
SCRUB		= $(RM) $(wildcard *.old) $(wildcard *~) $(wildcard *.bak) \
                        $(wildcard \#*\#)
SED		= sed
SHELL		= /bin/bash
SIZE		= $(SYSTEM_TARGET)size
STRIP		= $(SYSTEM_TARGET)strip
TR		= tr
GEN_DOPECODE	= $(L4DIR)/tool/gen_dopecode/gen_dopecode
ABS2REL		= $(L4DIR)/tool/bin/abs2rel.sh
# it's optional to be able to set it as environment variable
FIASCOUX	?= $(L4DIR)/../kernel/fiasco/build-ux/fiasco

# per arch DEFAULT_RELOC handling
RAM_BASE_arm_int = 0x00000000
RAM_BASE_arm_sa  = 0xc0000000
RAM_BASE_arm_pxa = 0xa0000000
RAM_BASE         = $(firstword  $(RAM_BASE_$(ARCH)_$(CPU)) \
				$(RAM_BASE_$(ARCH)) 0x0)

DEFINES         += -DRAM_BASE=$(RAM_BASE)

ifneq ($(DEFAULT_RELOC),)
  DEFAULT_RELOC := $(shell printf "0x%x" $$(($(RAM_BASE) + $(DEFAULT_RELOC))))
endif

ifneq ($(ARCH),)
 ifneq ($(CPU),)
   ifneq ($(DEFAULT_RELOC_$(ARCH)),)
     DEFAULT_RELOC := $(shell printf "0x%x" $$(($(RAM_BASE) + $(DEFAULT_RELOC_$(ARCH)))))
   endif
 endif
endif

# functions that are handy
absfilename_target_dir_needs_to_exist = $(foreach w,$(1),$(addsuffix /$(notdir $(w)),$(shell cd $(dir $(w)) 2>/dev/null&&$(PWDCMD))))
absfilename     = $(shell $(L4DIR)/mk/rel2abs.sh $(1))
findfile	= $(firstword $(wildcard $(addsuffix /$(1),$(2))) $(1)_NOT_FOUND)

# include this one early to be able to set OBJ_BASE
-include $(L4DIR)/Makeconf.local

ifeq ($(filter $(IGNORE_OBJDIR_TARGETS),$(MAKECMDGOALS)),)
# output directory
ifeq ($(O)$(OBJ_BASE),)
$(error need to give builddir with O=.../builddir)
else
ifneq ($(O),)
ifeq ($(origin OBJ_BASE),undefined)
OBJ_BASE := $(call absfilename, $(O))
export OBJ_BASE
endif
endif
endif
endif

ifeq ($(origin L4DIR_ABS),undefined)
L4DIR_ABS      := $(call absfilename,$(L4DIR))
endif
ifeq ($(origin PKGDIR_ABS),undefined)
PKGDIR_ABS     := $(call absfilename,$(PKGDIR))
endif
ifeq ($(origin SRC_DIR),undefined)
SRC_DIR        := $(shell pwd)
endif
ifeq ($(origin SRC_BASE_ABS),undefined)
SRC_BASE     ?= $(L4DIR)
SRC_BASE_ABS := $(call absfilename,$(SRC_BASE))
export SRC_BASE_ABS
endif
ifeq ($(origin OBJ_DIR),undefined)
OBJ_DIR        := $(subst $(SRC_BASE_ABS),$(OBJ_BASE),$(SRC_DIR))
endif
ifeq ($(origin PKGDIR_OBJ),undefined)
PKGDIR_OBJ     := $(call absfilename,$(OBJ_DIR)/$(PKGDIR))
endif

#$(warning PKGDIR: $(PKGDIR))
#$(warning OBJ_BASE: $(OBJ_BASE))
#$(warning L4DIR_ABS: $(L4DIR_ABS))
#$(warning SRC_BASE_ABS: $(SRC_BASE_ABS))
#$(warning PKGDIR_ABS: $(PKGDIR_ABS))
#$(warning SRC_DIR: $(SRC_DIR))
#$(warning OBJ_DIR: $(OBJ_DIR))
##$(warning PKGDIR_OBJ: $(PKGDIR_OBJ))

OBJ_DIR_EXPORT = $(OBJ_DIR)
export OBJ_DIR_EXPORT

VPATH_SRC_BASE ?= $(SRC_DIR)

# Makeconf.local handling
# dont use -include here, as we have special build conditions in $(L4DIR)/
ifeq ($(origin BID_ROOT_CONF),undefined)
BID_ROOT_CONF := $(call absfilename, $(OBJ_BASE))/Makeconf.bid.local
endif
ifeq ($(filter $(IGNORE_OBJDIR_TARGETS),$(MAKECMDGOALS)),)
ifeq ($(wildcard $(BID_ROOT_CONF)),)
ifeq ($(BID_IGN_ROOT_CONF),)
$(error Please run "make O=/path/to/objdir config" in "$(L4DIR)")
endif
else
include $(BID_ROOT_CONF)
endif
endif

-include $(OBJ_BASE)/Makeconf.local
ifneq ($(PKGDIR),)
-include $(PKGDIR)/Makeconf.local
endif
# if it is not already set, we use this in the local dir
MAKECONFLOCAL ?= Makeconf.local
-include $(MAKECONFLOCAL)

DROPS_STDDIR	?= /home/drops
STATICFILE	?= $(L4DIR)/pkg/STATIC

# a nasty workaround for make-3.79/make-3.80. The former needs an additional
# $$ for $-quotation when calling a function.
BID_IDENT	= $(1)
ifeq ($(call BID_IDENT,$$),)
BID_DOLLARQUOTE	= $$
endif
BID_COMMA	= ,

ifneq ($(PL),)
PL_j := -j $(PL)
export PL
endif

include $(L4DIR)/mk/config.inc

ifneq ($(HAVE_LDSO),)
# MAKEDEP-call:
# arg1 - compiler binary name
# arg2 - [opt] compiler target. Will be written as target within the
# 	       dependency file
# arg3 - [opt] name of the dependency file. If unset, .<arg2>.d will be used.
ifeq ($(origin BID_LIBGENDEP), undefined)
BID_LIBGENDEP := $(firstword $(wildcard $(call absfilename, \
				$(L4DIR)/tool/gendep/libgendep.so \
				$(DROPS_STDDIR)/tool/lib/libgendep.so )))
endif
MAKEDEP=LD_PRELOAD=$(BID_LIBGENDEP) GENDEP_TARGET=$(if $(2),$(2),$@) \
		    GENDEP_BINARY=$(1) $(if $(3),GENDEP_DEPFILE=$(3))
endif

# the gcc specific variables: version, base dir, include dir, gcc lib
# note: determining these variables is slow, and the values should
#       be set in Makeconf.bid.local. However, this is the place were
#       they are determined on a 'make config' in $(L4DIR)
GCCVERSION_f	= $(shell $(CC) -dumpversion | sed -e 's/\(.*\)\..*/\1/')
GCCMAJORVERSION_f=$(shell $(CC) -dumpversion | sed -e 's/\([^.]*\).*/\1/')
GCCMINORVERSION_f=$(shell $(CC) -dumpversion | sed -e 's/[^.]*\.\([^.]*\).*/\1/')
GCCSUBVERSION_f	= $(shell $(CC) -dumpversion | sed -e 's/.*\.\(.*\)/\1/')
GCCDIR_f	= $(shell LC_ALL=C $(CC) -print-search-dirs|sed -ne 's+^install: \(.*[^/][^/]*\)/+\1+p' )
GCCLIB_f	= $(shell $(CC) -print-libgcc-file-name)
GCCLIB_EH_f	= $(filter /%,$(shell $(CC) -print-file-name=libgcc_eh.a))
GCCINCDIR_f	= $(call GCCDIR_f)/include

# some ld-versions support the "--nostdlib" switch, others do not.
LDNOSTDLIB_f	= $(if $(shell echo -e '\
	                  asm\050".globl _start; _start:"\051;\
	                  int main\050void\051{return 0;}\
	                  '|gcc -xc -o/dev/null -nostdlib -Wl,--nostdlib - \
	                  2>/dev/null && echo yes),--nostdlib)
GCCLDNOSTDLIB_f	= $(addprefix -Wl$(BID_COMMA),$(LDNOSTDLIB_f))

GCCINCDIR	= $(GCCDIR)/include

ifneq ($(PKGDIR),)
  ifeq ($(origin PKGNAME),undefined)
    PKGNAME := $(notdir $(shell cd $(PKGDIR);pwd))
  endif
endif

ifeq ($(V),1)
  VERBOSE =
endif
ifeq ($(V),0)
  VERBOSE = @
endif

# indicate if we are using dietlibc or uClibc
ifeq ($(USE_DIETLIBC),y)
# dietlibc explicitly set for all architectures
  DEFINES	+= -DUSE_DIETLIBC=y
  USE_DIETLIBC	= y
  LIBC_TYPE	= diet
else
  # uClibc explicitly set for all architectures
  DEFINES	+= -DUSE_UCLIBC=y
  USE_UCLIBC	= y
  LIBC_TYPE	= uc
endif

ifeq ($(RELEASE_MODE),y)
DEFINES		+= -DL4BID_RELEASE_MODE
endif

#
# SUBDIR handling, not within the OBJ-*/ dirs
#
ifeq ($(SYSTEM),)
ifneq ($(SUBDIRS),)
.PHONY: $(SUBDIRS)
$(SUBDIRS):
	$(VERBOSE)PWD=$(PWD)/$@ $(MAKE) -C $@ all

# we know that SUBDIRS isn't empty, hence we can avoid the dir-test
scrub clean cleanall::
	$(VERBOSE)set -e; $(foreach i,$(SUBDIRS), \
		PWD=$(PWD)/$$i $(MAKE) -C $i $@ $(MKFLAGS) $(MKFLAGS_$i);)

install:: $(SUBDIRS)
	$(VERBOSE)set -e; $(foreach i,$(SUBDIRS), \
		PWD=$(PWD)/$$i $(MAKE) -C $i $@ $(MKFLAGS) $(MKFLAGS_$i);)

endif

all:: $(OBJ_DIR)/Makefile

$(OBJ_DIR)/Makefile:
	$(VERBOSE)install -d $(dir $@)
	$(VERBOSE)echo '# automatically created -- modifications will be lost' > $@
	$(VERBOSE)echo 'SRC := $(SRC_DIR)'                                    >> $@
	$(VERBOSE)echo 'OBJ := $(OBJ_BASE)'                                   >> $@
	$(VERBOSE)echo 'x:'                                                   >> $@
	$(VERBOSE)echo '	$$(MAKE) -C $$(SRC) O=$$(OBJ)'                >> $@
	$(VERBOSE)echo '%:'                                                   >> $@
	$(VERBOSE)echo '	$$(MAKE) -C $$(SRC) O=$$(OBJ) $$@'            >> $@

else
# we are within an OBJ-*/ dir, create dummy target
$(SUBDIRS):
endif

#
# Dependency section
#
#

# the general dependencies: All generated files depend on ".general.d".
# ".general.d" itself depends on the mk-Makeconf, the optional
# Makeconf.local, the Makeconf.bid.local, the packet-Makeconf.local and the
# Makeconf.local. This ensures a rebuilt if any of the configuration-
# or make-files changes.
#
# We have this nasty if-readable-magic to allow the files to disappear
# or to appear. Depending on if the according makeconf exists now, the
# if-readable magic .general.d is used on existance or non-existence.

BID_DEPEND_GENERAL_D_COND = \
	if [ -r $(1) ] ; then echo -e '$@: $(1)\n$(1):\n' >>$@ ; \
	  else echo '$$(if $$(wildcard $(1)), $@: FORCE)' >>$@; fi

ifeq ($(SYSTEM),)
GENERAL_D_LOC := $(OBJ_DIR)/.general.d
else
GENERAL_D_LOC := .general.d
endif

$(GENERAL_D_LOC): $(L4DIR)/mk/Makeconf
	@$(BUILD_MESSAGE)
	@install -d $(dir $@)
	$(DEPEND_VERBOSE)echo '$@: $(SRC_DIR)/Makefile ' > $@
	$(DEPEND_VERBOSE)$(call BID_DEPEND_GENERAL_D_COND,\
		$(OBJ_BASE)/Makeconf.bid.local)
	$(DEPEND_VERBOSE)$(call BID_DEPEND_GENERAL_D_COND,\
		$(OBJ_BASE)/Makeconf.local)
	$(if $(PKGDIR),$(DEPEND_VERBOSE)$(call BID_DEPEND_GENERAL_D_COND,\
		$(PKGDIR)/Makeconf.local))
	$(DEPEND_VERBOSE)$(call BID_DEPEND_GENERAL_D_COND,\
		$(MAKECONFLOCAL))

DEPS	+= $(GENERAL_D_LOC)

ifneq ($(DEPENDS_PKGS),)
DEPENDS_PKGS_MISSING := $(strip $(foreach i,$(DEPENDS_PKGS),		\
	                          $(if $(wildcard $(L4DIR)/pkg/$i),,$i)))

ifneq ($(DEPENDS_PKGS_MISSING),)
# clear TARGET to prevent building anything
TARGET =
all::
	@echo -e "\033[32mPackage dependencies missing: \033[1m$(DEPENDS_PKGS_MISSING)\033[22m, skipping.\033[0m"
endif
endif

#
# Messages
#

# set SHOWMESSAGES=true or 'y' to print textual action descriptions
SHOWMESSAGES ?= true

# coloring on vt100-, xterm-, linux- and console-consoles
# enbaled by setting BID_COLORED_PHASES to y
ifeq ($(BID_COLORED_PHASES),y)
ifneq (,$(findstring ${TERM},vt100 xterm linux console))
  EMPHSTART = '\033[34m'
  EMPHSTOP  = '\033[0m'
else
  EMPHSTART =
  EMPHSTOP  =
endif
endif


ifneq (,$(filter y true, $(SHOWMESSAGES)))
AR_MESSAGE?=	echo -e "  ==> Archiving into $@"
BUILD_MESSAGE?=	echo -e "  ... Building $@"
BUILT_MESSAGE?= echo -e $(EMPHSTART)'  ==> "$@" built'$(EMPHSTOP)
COMP_MESSAGE?=	echo -e "  ... Compiling $@"
COMP_P_MESSAGE?=echo -e "  ... Compiling PIC $@"
COMP_PR_MESSAGE?=echo -e "  ... Compiling PROFILE $@"
GEN_MESSAGE?=	echo -e "  ... Generating $@"
LINK_MESSAGE?=	echo -e "  ==> Linking $@"
DEP_MESSAGE?=	echo -e "  ... Building dependencies for $<"
CLEAN_MESSAGE?=	echo -e "  ... Removing created files"
CLEANALL_MESSAGE?=echo -e "  ... Removing all created files"
INSTALL_LINK_MESSAGE?=echo -e "  ==> Updating symlinks"
INSTALL_DOC_MESSAGE?=echo -e "  ==> Installing $(<) documentation"
INSTALL_DOC_LOCAL_MESSAGE?= echo -e "  ==> Installing $(<) documentation locally"
INSTALL_MESSAGE?=echo -e "  ==> Installing $^"
INSTALL_LOCAL_MESSAGE?=echo -e "  ==> Installing $(<) to local build-tree"
UPDATE_HTML_MESSAGE?=echo -e "  ! You should remake your doc directory in $(1)"
endif


# allows an include $(DEPSVAR) at the end of the makefile
# but prevents rebuilding them on a scrub, clean, cleanall and help
ifneq ($(filter scrub clean cleanall help,$(MAKECMDGOALS)),)
DEPSNULL = /dev/null
DEPSVAR	= $(DEPSNULL)
else
DEPSVAR	= $(DEPS)
endif

#
# Some rules
#

# addfileheader-rule: allows "make addfileheader main.c server.c"-like
# commands and automatically inserts the path within the package
# options may be passed with $(ADDFILEHEADER_OPTIONS)
ADDFILEHEADER_PREFIX = $(patsubst $(call absfilename,$(PKGDIR)/)%,\
				  $(PKGNAME)/%,$(call absfilename,./))
ADDFILEHEADER_FILES = $(filter-out addfileheader,$(MAKECMDGOALS))
addfileheader:
	addfileheader $(ADDFILEHEADER_OPTIONS) -p $(ADDFILEHEADER_PREFIX) $(ADDFILEHEADER_FILES)
        

.PHONY: FORCE

endif	# _L4DIR_MK_MAKECONF undefined
