
#########################################################################
#
#  $Id: Makefile 1.46 2024/12/13 16:24:36Z martin.burnicki REL_M $
#
#  Makefile for mbgtools-lx which recurses into the subdirectories.
#
# -----------------------------------------------------------------------
#  $Log: Makefile $
#  Revision 1.46  2024/12/13 16:24:36Z  martin.burnicki
#  Optional ability to allow all modifications on install to avoid
#  interactive queries, e.g. 'make install ALWAYS_ANSWER_YES=1'.
#  Revision 1.45  2024/11/26 15:50:32Z  martin.burnicki
#  Support new preprocessor symbol KERNEL_HAS_LINUX_UNALIGNED_H.
#  Revision 1.44  2024/10/15 14:57:27Z  martin.burnicki
#  Account for a sub-makefile moved to an mbglib directory.
#  Revision 1.43  2024/09/16 12:53:12Z  martin.burnicki
#  Only use -Wexpansion-to-defined if CC supports  this.
#  Removed obsolete usage of PRELIMINARY_CODE.
#  Revision 1.42  2024/07/23 14:38:08Z  martin.burnicki
#  Added compiler flags to show portability problems.
#  Revision 1.41  2024/05/13 14:11:39  martin.burnicki
#  New make parameters KERNEL_CLASS_WITHOUT_OWNER and
#  KERNEL_HAS_VMA_VM_FLAGS_WRAPPER_FUNCTIONS to allow
#  overriding the defaults determined by the kernel driver.
#  Revision 1.40  2023/12/04 14:49:57  martin.burnicki
#  Better support for staged builds, and cleanup.
#  Revision 1.39  2022/09/07 16:55:49  martin.burnicki
#  Updated name of sub-makefile to be included.
#  Revision 1.38  2022/07/25 16:42:04  martin.burnicki
#  Support getting full version string from git.
#  Revision 1.37  2022/03/23 15:38:20  martin.burnicki
#  Fixed a build error that occurred when building a package in a sandbox.
#  Revision 1.36  2022/02/18 16:40:10  martin.burnicki
#  Moved most SYN1588 stuff to an extra Makefile that is included.
#  Revision 1.35  2021/12/01 21:23:28  martin.burnicki
#  Fixed conditional build without optional features.
#  Revision 1.34  2021/12/01 10:29:34  martin.burnicki
#  Added a note about the timepps.h file.
#  Revision 1.33  2021/11/16 21:07:57  martin.burnicki
#  Added PPS support option, disabled by default.
#  Revision 1.32  2021/11/15 17:07:34  martin.burnicki
#  Build without SYN1588 support by default.
#  Build without SYN1588 SHM by default.
#  Revision 1.31  2021/09/08 15:11:25  martin
#  Unified and cleaned up makefile syntax.
#  Cleaned up handling of the static library.
#  Revision 1.30  2021/09/06 16:14:24  martin
#  Add target syn1588_dist which can be used to update
#  the required SYN1588 API files from the git repo,
#  if the repo is available.
#  Revision 1.29  2021/09/06 16:06:59  martin
#  Added a common SYN1588 API file list, and derive
#  all build flags from that list.
#  Revision 1.28  2021/08/12 13:12:03  martin
#  Cleaned up and simplified SYN1588 support.
#  Revision 1.27  2021/05/04 19:28:34  martin
#  Prepared basic support for serial devices.
#  Revision 1.26  2021/03/24 10:04:17  martin
#  Made the 'make install' messages more readable.
#  Revision 1.25  2021/03/15 17:47:23  martin
#  Automatically detect if SYN1588 support is to be included.
#  Also updated a bunch of comments.
#  Revision 1.24  2020/10/20 11:04:40  martin
#  Also remove files '*.ipa-clones' on 'make clean' for kernel driver.
#  Revision 1.23  2020/10/20 10:34:11  martin
#  Preliminary support for SYN1588, disabled by default because it's
#  still inclomplete.
#  Revision 1.22  2020/10/15 09:24:11  martin
#  Fix building with 'make -j'. Recursive call to make wasn't done
#  using $(MAKE) when the mbg_static_lib target was added.
#  Patch provided by Jean-Yves Faye <jean-yves.faye@csgroup.eu>.
#  Revision 1.21  2020/10/15 09:17:54  martin
#  Cleanup and simplifications.
#  Revision 1.20  2020/09/04 11:14:25  martin
#  Test for target 'modules_add' only for kernels prior to 3.x., where
#  this target might be required.
#  Due to changes in the kernel build system, this test could mess up
#  the kernel source configuration in kernels 5.8 from some distros.
#  In fact, the file autoconf.h was deleted, so no extra kernel modules
#  could be built afterwards.
#  Revision 1.19  2020/05/14 11:37:03  martin
#  Improved the way the major kernel version is determined.
#  The previous approach failed e.g. on Debian 10 with a backport kernel.
#  Revision 1.18  2020/03/31 15:13:57  martin
#  Also remove file $(MODULE).mod on clean.
#  Revision 1.17  2020/03/11 16:27:54  martin
#  Account for the $(prefix) when determining the installation
#  directory for shared object libraries.
#  Revision 1.16  2020/02/27 12:13:04  martin
#  Use a local static library to speed up the build process.
#  Cleanup.
#  Revision 1.15  2020/02/24 17:03:06  martin
#  When calling the kernel build system, check the kernel major version
#  to distinguish whether to use the 'SUBDIRS=' or 'M=' parameter to
#  specify the directory where where to build our out-of-tree module.
#  Use LDLIBS to specify libraries to be linked against.
#  Added lan_util.o to the OBJS list here as a start to specify
#  commonly used object files in the top level makefile.
#  Revision 1.14  2018/12/14 10:16:47  martin
#  Subprojects mbgcmptime and mbgtcrcal were moved
#  to the base directory and are now included by default.
#  Revision 1.13  2018/11/23 08:17:47  martin
#  Unset PAGER environment variable to prevent scripts from
#  potentially hanging if they used this variable.
#  If SElinux is used, install mbgsvcd with -Z to set SElinux default context.
#  Renamed symbol TARGET to MBGTOOLS_TARGET to avoid name
#  clashes in some build environments.
#  Cleaned up makefile debugging.
#  Revision 1.12  2018/06/25 08:17:09  martin
#  Improved search for system binaries.
#  New make parameters KERNEL_HAS_BOOL, KERNEL_HAS_TRUE_FALSE,
#  MBG_PRI_64_PREFIX_L, MBG_PRI_64_PREFIX_LL.
#  Control several debug options from the make command line.
#  Conditionally support DEBUG_MSG_SLEEP.
#  Moved handling of some mbgclock-specific make parameters
#  to mbgclock/Makefile.
#  Modified build messages when calling kernel build system.
#  Use reduced optimization level on Sparc since gcc for Sparc
#  may produce faulty code resulting in bus errors.
#  Added LDFLAGS -lrt.
#  Don't build GUI by default.
#  Removed usage of obsolete symbol MBGDEVIO_SIMPLE.
#  Removed obsolete code.
#  Revision 1.11  2017/07/06 07:11:23  martin
#  Unified build system.
#  Updated the list of sub-projects.
#  Simplified Makefile syntax for kernel modules.
#  Made build output quiet by default.
#  Support building shared libraries and GUI programs.
#  Replaced CFLAGS by CPPFLAGS which are also applied
#  when the C++ compiler is used.
#  Support KERNEL_HAS_BOOL define.
#  Revision 1.10  2009/09/29 08:54:09  martin
#  Added target test/mbgchksystime.
#  Revision 1.9  2009/07/24 14:07:31  martin
#  Added target kernel_config.
#  Revision 1.8  2008/12/22 12:52:32  martin
#  Added new target subdirs.
#  Check if target subdir exists before trying to
#  recurse into it.
#  Revision 1.7  2008/04/11 11:07:25  martin
#  Added target "refclocks" for the kernel module.
#  Revision 1.6  2004/11/09 10:09:34  martin
#  Support new target "check" for the kernel module.
#  Revision 1.5  2003/04/25 10:39:41  martin
#  Updated list of subdirectories to recurse into.
#  Revision 1.4  2002/11/21 15:03:11  martin
#  New target install, uninstall, and dev-clean.
#  Use a list of subdirs to recurse into.
#  Revision 1.3  2001/09/17 13:54:00  MARTIN
#  Updated list of subdirectories to recurse into.
#  Revision 1.2  2001/03/05 17:25:54  MARTIN
#  Renamed/reordered targets for mbgclock.
#  Revision 1.1  2001/02/02 15:04:03  MARTIN
#
#########################################################################

ifdef DEBUG_MAKE
define debug_msg
$(info make[$(MAKELEVEL)] $(1))
endef
endif


# If the output of some commands was piped through a pager with certain
# options, e.g. "PAGER=less LESS=-ie", the command might hang, so we
# make sure the default PAGER setting is discarded.
PAGER =
export PAGER


## SEPARATOR_1 := "++"
SEPARATOR_2 := "========================================================================"

INFO = top common:

# Set V to 1 to build verbosely.
V ?= 0

# The lines below make the build output non-verbose by default.
# Call make with parameter "V=1" to get verbose output.
ifneq ("$(V)","0")
  Q :=
  QM :=
  vecho = @true
else
  Q := @
  QM := -s
  vecho = @echo
endif


# STAGED_BUILD means that binaries are build locally
# and later installed to local directories rather than
# system directories.
# Formerly we used the symbol CALLED_FROM_SPEC for this
# purpose, so for now we keep a backward-compatible alias.
ifndef STAGED_BUILD
  ifdef CALLED_FROM_SPEC
    STAGED_BUILD = $(CALLED_FROM_SPEC)
  endif
endif


# A macro that tries to find a specific program anywhere
# on the program search path. Returns the path to the program,
# if it can be found, else an empty string.
ifndef STAGED_BUILD
  chk_which_exec = $(shell which $(1) 2>/dev/null || whereis -b $(1) | awk ' { print $$2 }' )
else
  chk_which_exec = $(shell echo $(1) )
endif


# A macro that tests if a specific directory exists.
# Returns the path if it exists, else an empty string.
chk_exist_dir = $(shell if test -d $(1); then echo "$(1)"; fi )

# A macro that tests if a specific file exists.
# Returns the path if it exists, else an empty string.
chk_exist_file = $(shell if test -f $(1); then echo "$(1)"; fi )

# Test if the compiler supports a specific option.
chk_cc_option = $(shell echo "int main() { return 0; }" | \
                        $(CC) -x c - $(1) -o /dev/null >/dev/null 2>&1 && \
                        echo 1 || echo 0)


# A variable indicating whether compiler warning "expansion-to-defined" is supported.
CC_SUPPORTS_WEXPANSION_TO_DEFINED ?= $(call chk_cc_option,-Wexpansion-to-defined)


# Unless a BASEDIR has been specified, we assume
# mbglib is located below the current dir.
ifneq ($(BASEDIR),)
  TOPDIR = $(BASEDIR)
else
  TOPDIR = .
endif

ifndef MBGLIB
  MBGLIB := $(TOPDIR)/mbglib
  $(call debug_msg,$(INFO) MBGLIB: $(MBGLIB))
endif

MBGLIB_MAKEFILES ?= $(MBGLIB)/makefiles


# Support serial devices in mbgsvcd.
SUPP_SERIAL ?= 0
export SUPP_SERIAL

# Support PPS in mbgsvcd.
# By default, enable this if serial support is enabled, too.
#
# PPS support requires a timepps.h file to be available
# in one of the system include paths. Unless the file is
# already available, it can be be provided e.g. by cloning
# the pps-tools repo from github
#
#   https://github.com/redlab-i/pps-tools.git
#
# and creating a symbolic link in /usr/local/include
# which points to the timepps.h file in the repo.
SUPP_PPS ?= $(SUPP_SERIAL)
export SUPP_PPS

$(call debug_msg,$(INFO) SUPP_SERIAL: $(SUPP_SERIAL))
$(call debug_msg,$(INFO) SUPP_PPS:    $(SUPP_PPS))


# If the installation would overwrite an existing
# configuration file with different content, an
# interactive query usually appears asking whether
# the corresponding file should be overwritten.
#
# The variable ALWAYS_ANSWER_YES can be specified
# e.g. on the make command line to explicitly allow
# this to simplify automated installation.
#
# For now, this only affects the secondary variable
# ALLOW_UDEV_UPDATE, which controls whether overwriting
# the udev rule file is allowed or forbidden.
ifdef ALWAYS_ANSWER_YES
  export ALWAYS_ANSWER_YES

  ALLOW_UDEV_UPDATE ?= $(ALWAYS_ANSWER_YES)
  export ALLOW_UDEV_UPDATE
endif


# The macros below are used to specify file paths that
# depend on the target system.
# TGT_SYSTEM is the system for which we actually build the
# binaries, used to specify paths to files that need to
# be available.
# ALT_SYSTEM specifies an alternate target system and is used
# to specify paths to files that aren't required for build, but
# are included for completeness in multi-target projects.

SYSTEM_LINUX = linux
SYSTEM_WIN32 = win32

TGT_SYSTEM = $(SYSTEM_LINUX)
ALT_SYSTEM = $(SYSTEM_WIN32)

# The file included here provides definitions
# for SYN1588 support and uses TGT_SYSTEM and
# ALT_SYSTEM defined above.
include $(MBGLIB_MAKEFILES)/makefile-mbg-supp-syn1588.mk


# Macros useful to run individual commands as root:
ifdef STAGED_BUILD
  # Fake running as root.
  UID = 0
else
  # Used to really run as root.
  UID = $(shell id -u)
  SUDO ?= $(call chk_which_exec,"sudo")
  SU ?= $(call chk_which_exec,"su")
endif  # STAGED_BUILD

$(call debug_msg,$(INFO) UID:  $(UID))
$(call debug_msg,$(INFO) SUDO: $(SUDO))
$(call debug_msg,$(INFO) SU:   $(SU))


ifneq ($(SUDO),)
  run_as_root = $(Q)$(shell echo "$(SUDO) $(1)" )
else
  ifneq ($(SU),)
    run_as_root = $(Q)$(shell echo "$(SU) -c \"$(1)\"" )
  endif
endif
make_as_root = $(call run_as_root, $(MAKE) $(QM) $(INSTALL_PATHS) $(1))


MACHINE_TYPE ?= $(shell uname -m)

# Determine the path where shared object libraries are to
# be installed. Expects $(prefix) as parameter.
find_libdir = $(shell \
  if [ $(MACHINE_TYPE) = "ia64" -o $(MACHINE_TYPE) = "x86_64" ]; then \
    if test -d $(1)/lib64; \
      then echo "$(1)/lib64"; \
      else echo "$(1)/lib"; \
    fi \
  else \
    if test -d $(1)/lib32; \
      then echo "$(1)/lib32"; \
      else echo "$(1)/lib"; \
    fi \
  fi \
)


# A destination dir for staged installation, as
# suggested by GNU conventions.
# Prepended to the installations paths specified below,
# but empty by default.
DESTDIR ?=

# Default installation paths according to GNU conventions.
prefix ?= /usr/local
exec_prefix ?= $(prefix)
bindir ?= $(exec_prefix)/bin
sbindir ?= $(exec_prefix)/sbin
includedir ?= $(prefix)/include
# The final part of the libdir path can be lib, lib32, or lib64,
# so we call a function to determine the most appropriate.
libdir ?= $(call find_libdir,$(exec_prefix))
# The next one is non-standard, but most appropriate.
sysconfdir ?= /etc


$(call debug_msg,$(INFO) prefix: $(prefix))
$(call debug_msg,$(INFO) libdir: $(libdir) MACHINE_TYPE: $(MACHINE_TYPE))


# A macro that combines all the installation paths specified above.
# Used to pass the settings to a sub-make.
INSTALL_PATHS = DESTDIR=$(DESTDIR)
INSTALL_PATHS += prefix=$(prefix)
INSTALL_PATHS += exec_prefix=$(exec_prefix)
INSTALL_PATHS += bindir=$(bindir)
INSTALL_PATHS += sbindir=$(sbindir)
INSTALL_PATHS += libdir=$(libdir)
INSTALL_PATHS += includedir=$(includedir)
INSTALL_PATHS += sysconfdir=$(sysconfdir)


ifndef SO_BASENAMES
  SO_BASENAMES += devio
  SO_BASENAMES += util
  ## SO_BASENAMES += serio
  ## SO_BASENAMES += extio
endif

SO_SUBDIRS ?= $(foreach dir,$(SO_BASENAMES), libmbg_so/mbg$(dir) )
$(call debug_msg,$(INFO) SO_SUBDIRS: $(SO_SUBDIRS))

# Definitions for the static library used when building.
MBGTOOLS_STATIC_LIB_DIR = libmbg
MBGTOOLS_STATIC_LIB_BASENAME = mbg
MBGTOOLS_STATIC_LIB_FILE = lib$(MBGTOOLS_STATIC_LIB_BASENAME).a



ifndef BASEDIR # ======================================================

# This section is evaluated if BASEDIR is not yet defined,
# i.e. if this makefile is first read by the top-level make.
# It specifies some common targets and some subdirs inside
# which a recursive make will be executed, which may include
# this make file again and evaluate the second part for the
# case where BASEDIR is defined.

INFO = top 1st:
$(call debug_msg,$(INFO) reading top level part)


.DEFAULT_GOAL := all
MAKECMDGOALS ?= $(.DEFAULT_GOAL)


ifdef DONT_BUILD_LIBS
  ifdef DONT_BUILD_TOOLS
    DONT_BUILD_USERSPACE ?= 1
  endif
endif

ifdef DONT_BUILD_USERSPACE
  DONT_BUILD_LIBS ?= 1
  DONT_BUILD_TOOLS ?= 1
endif


# A routine that can be called to check if a Makefile exists
# in a specific subdirectory. It returns the subdirectory name
# if it does, or an empty string if it does not.
chk_subdir = $(shell test -f $(strip $(1))/Makefile && echo "$(1)" )


# List of subdirectories that are only built/cleaned,
# but not installed/uninstalled.
ifndef DONT_BUILD_USERSPACE
  SUBDIRS_BUILD_ONLY ?= $(MBGTOOLS_STATIC_LIB_DIR)
endif


# List of subdirectories that don't need to be built/cleaned,
# but installed/uninstalled.
ifndef DONT_BUILD_USERSPACE
  SUBDIRS_INST_ONLY ?= $(call chk_subdir, "libmbg_so/devel" )
endif

# Udev dirs are special and don't need to be built/cleaned,
# but installed/uninstalled.
ifndef DONT_BUILD_USERSPACE
  SUBDIRS_UDEV += $(call chk_subdir, "udev" )
endif


# List of subdirectories that are built/cleaned
# as well as installed/uninstalled.
ifndef SUBDIRS_COMMON

  ifndef DONT_BUILD_LIBS
    SUBDIRS_COMMON += $(SO_SUBDIRS)
  endif

  ifndef DONT_BUILD_TOOLS
    SUBDIRS_COMMON += $(call chk_subdir, "mbgstatus")
    SUBDIRS_COMMON += $(call chk_subdir, "mbgsetsystime")
    SUBDIRS_COMMON += $(call chk_subdir, "mbgctrl")
    SUBDIRS_COMMON += $(call chk_subdir, "mbgirigcfg")
    SUBDIRS_COMMON += $(call chk_subdir, "mbgshowsignal")
    SUBDIRS_COMMON += $(call chk_subdir, "mbggpscap")
    SUBDIRS_COMMON += $(call chk_subdir, "mbghrtime")
    SUBDIRS_COMMON += $(call chk_subdir, "mbgfasttstamp")
    SUBDIRS_COMMON += $(call chk_subdir, "mbgsvcd")
    SUBDIRS_COMMON += $(call chk_subdir, "mbgxhrtime")
    SUBDIRS_COMMON += $(call chk_subdir, "mbgcmptime")
    SUBDIRS_COMMON += $(call chk_subdir, "mbgtcrcal")
    SUBDIRS_COMMON += $(call chk_subdir, "test/mbgreadtime")
    SUBDIRS_COMMON += $(call chk_subdir, "test/mbgtestio")
    SUBDIRS_COMMON += $(call chk_subdir, "test/mbgtestmmio")
    SUBDIRS_COMMON += $(call chk_subdir, "test/mbgtestxhrt")
    SUBDIRS_COMMON += $(call chk_subdir, "test/mbgchksystime")
    SUBDIRS_COMMON += $(call chk_subdir, "test/mbgtestsettime")
    SUBDIRS_COMMON += $(call chk_subdir, "test/mbg_test_app")
    SUBDIRS_COMMON += $(call chk_subdir, "test/mbg_test_drvr")
    SUBDIRS_COMMON += $(call chk_subdir, "test/readcont")
    SUBDIRS_COMMON += $(call chk_subdir, "test/mbg_ucap")
    SUBDIRS_COMMON += $(call chk_subdir, "test/mbg_pout")
    SUBDIRS_COMMON += $(call chk_subdir, "test/tmapitst")
  endif


  ifndef DONT_BUILD_GUI
    ifdef BUILD_MBGMON
      SUBDIRS_COMMON += $(call chk_subdir, "wxwidgets/mbgmon")
    endif
    ifndef BUILD_MBGSTATSVIEWER
      SUBDIRS_COMMON += $(call chk_subdir, "wxwidgets/mbgstatsviewer")
    endif
  endif  # DONT_BUILD_GUI


  ifndef DONT_BUILD_DRIVER
    SUBDIRS_COMMON += $(call chk_subdir, "mbgclock")
    ## SUBDIRS_COMMON += $(call chk_subdir, "test/mbgclock-test" )
  endif  # DONT_BUILD_DRIVER

endif  # SUBDIRS_COMMON


# Targets for which we recurse into specific subdirs
TARGETS_BUILD := all clean distclean
TARGETS_INST := install uninstall

# Determine the subdirectories to be recursed into
# depending on the current goal.
ifneq ($(filter $(MAKECMDGOALS),$(TARGETS_BUILD)),)
  SUBDIR_TARGETS += $(SUBDIRS_BUILD_ONLY) $(SUBDIRS_COMMON)
endif

ifneq ($(filter $(MAKECMDGOALS),$(TARGETS_INST)),)
  SUBDIR_TARGETS += $(SUBDIRS_INST_ONLY) $(SUBDIRS_COMMON) $(SUBDIRS_UDEV)
endif


ifndef STAGED_BUILD

  # For some targets we may also want to execute some additional
  # commands after the main targets have been made.
  ifeq ($(MAKECMDGOALS),all)
    PRE_TARGETS = pre_build_info
    POST_TARGETS = post_build_info
  endif

  ifeq ($(MAKECMDGOALS),install)
    POST_TARGETS = post_install_info
  endif

endif  # STAGED_BUILD


# If the current target is uninstall, we may also want to run
# some commands before uninstallation.
ifeq ($(MAKECMDGOALS),uninstall)
  PRE_TARGETS = pre_uninstall
  PRE_UNINSTALL_TARGETS = mbgsvcd_uninstall
endif


$(call debug_msg,$(INFO) MAKECMDGOALS: $(MAKECMDGOALS))
$(call debug_msg,$(INFO) SUBDIRS_BUILD_ONLY: $(SUBDIRS_BUILD_ONLY))
$(call debug_msg,$(INFO) SUBDIRS_INST_ONLY: $(SUBDIRS_INST_ONLY))
$(call debug_msg,$(INFO) SUBDIRS_COMMON: $(SUBDIRS_COMMON))


.PHONY: $(TARGETS_BUILD) $(TARGETS_INST)
$(TARGETS_BUILD) $(TARGETS_INST): $(PRE_TARGETS) $(SUBDIR_TARGETS) $(POST_TARGETS)


.PHONY: $(SUBDIR_TARGETS)
$(SUBDIR_TARGETS):
  ifdef SEPARATOR_1
	  @echo "$(SEPARATOR_1)"
  endif
	@echo "Making $(MAKECMDGOALS) in $@"
	$(Q)$(MAKE) $(QM) -C $@ $(INSTALL_PATHS) $(MAKECMDGOALS)


.PHONY: probe ins rm test reload
probe ins rm test reload:
	$(Q)$(MAKE) $(QM) -C mbgclock $@


.PHONY: install_svc
install_svc: mbgsvcd_install

.PHONY: uninstall_svc
uninstall_svc: mbgsvcd_uninstall


.PHONY: mbgsvcd_install mbgsvcd_uninstall
mbgsvcd_install mbgsvcd_uninstall:
	$(Q)@$(MAKE) $(QM) -C mbgsvcd $@


.PHONY: cleanreload
cleanreload: clean all install reload

else # ================================================================

# This section is evaluated if BASEDIR is already defined,
# i.e. if this makefile is included from a sub-level make.

INFO = top 2nd:
$(call debug_msg,$(INFO) reading second level definitions)

$(call debug_msg,$(INFO) MBGTOOLS_TARGET: $(MBGTOOLS_TARGET))
$(call debug_msg,$(INFO) BASEDIR: $(BASEDIR))
$(call debug_msg,$(INFO) MAKECMDGOALS: $(MAKECMDGOALS))

MBGLIB_DIRS += common
MBGLIB_DIRS += $(TGT_SYSTEM)

MBG_VERSION_FROM_GIT = $(shell git describe --tag --dirty 2>/dev/null)


ifndef MODULE  #===========================================================

# Not building a kernel module, but a user space program
# or a library or shared object library.

%.o: %.c
	$(vecho) "    $(CC)       $@"
	$(Q)$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<

%.o: %.cpp
	$(vecho) "    $(CC)       $@"
	$(Q)$(CC) $(CPPFLAGS) $(CXXLAGS) -c -o $@ $<


ifneq ($(MBG_VERSION_FROM_GIT),)
  CPPFLAGS += -DMBG_VERSION_FROM_GIT=$(MBG_VERSION_FROM_GIT)
endif

CPPFLAGS += -Wall
ifneq ($(CC_SUPPORTS_WEXPANSION_TO_DEFINED),0)
  CPPFLAGS += -Wexpansion-to-defined
endif
## CPPFLAGS += -Wextra
## CPPFLAGS += -Winline
## CPPFLAGS += -Wno-missing-field-initializers

CPPFLAGS += -DSUPP_SERIAL=$(SUPP_SERIAL)
CPPFLAGS += -DSUPP_PPS=$(SUPP_PPS)

MACHINE_TYPE = $(shell uname -m)

ifneq (,$(findstring sparc,$(MACHINE_TYPE)))
  # Some gcc versions on SPARC produce faulty code when doing
  # loop optimizations, which results in bus errors at run time.
  # See e.g. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78807
  # So we limit the optimization level on SPARC.
  OPT_FLAGS = -O1
else
  OPT_FLAGS = -O2
endif


ifdef DEBUG
  CPPFLAGS += -DDEBUG=$(DEBUG)
  CPPFLAGS += -g2
  ## CPPFLAGS += $(OPT_FLAGS)
else
  CPPFLAGS += $(OPT_FLAGS)
endif

CPPFLAGS += -D_USE_SOCKET_IO=1

CPPFLAGS += -D_USE_CHK_TSTR=1

CPPFLAGS += -I.
CPPFLAGS += -I$(BASEDIR)
CPPFLAGS += $(patsubst %,-I%,$(addprefix $(MBGLIB)/,$(MBGLIB_DIRS)))
CPPFLAGS += $(CPPFLAGS_SYN1588_INC)

# This is *required* for the shared object libraries, but
# we use it in general to simplify the build procedure.
CPPFLAGS += -fPIC


# Additional C++-only compiler flags.
## CXXFLAGS += -Wno-deprecated


LDFLAGS += $(foreach dir,$(SO_SUBDIRS),-L$(BASEDIR)/$(dir) )


# The path to the static library we use to
# simplify the build procedure.
MBGTOOLS_STATIC_LIB_PATH = $(BASEDIR)/$(MBGTOOLS_STATIC_LIB_DIR)
MBGTOOLS_STATIC_LIB_FILE_PATH = $(MBGTOOLS_STATIC_LIB_PATH)/$(MBGTOOLS_STATIC_LIB_FILE)

ifdef MBGTOOLS_STATIC_LIB_TARGET
  CURR_TARGET = $(MBGTOOLS_STATIC_LIB_TARGET)
  USE_STATIC_LIB = 0
endif


# We also need these version numbers for install.
SO_MAJOR_VERSION = 1
SO_MINOR_VERSION = 0

ifdef MBGTOOLS_SO_TARGET_BASENAME

  ifndef SO_POINT_RELEASE
    SO_POINT_RELEASE = 0
  endif

  SO_TARGET_NAME = libmbg$(MBGTOOLS_SO_TARGET_BASENAME)
  SO_TARGET_LIBNAME = $(SO_TARGET_NAME).so
  SO_TARGET_SONAME = $(SO_TARGET_LIBNAME).$(SO_MAJOR_VERSION)
  CURR_TARGET = $(SO_TARGET_SONAME).$(SO_MINOR_VERSION).$(SO_POINT_RELEASE)
  USE_STATIC_LIB = 1

  OBJS += mbg$(MBGTOOLS_SO_TARGET_BASENAME).o

  CLEAN_FILES += $(SO_TARGET_LIBNAME)

  # Flag -fPIC is *required* when compiling for shared objects, so
  # we add this unless it has already been globally added before.
  ifeq ($(filter $(CPPFLAGS),-fPIC),)
    CPPFLAGS += -fPIC
  endif

  CPPFLAGS += -c

  LDFLAGS += -shared
  LDFLAGS += -Wl,-soname,$(SO_TARGET_SONAME)

  LDLIBS += -lc
endif  # MBGTOOLS_SO_TARGET_BASENAME


ifdef MBGTOOLS_TARGET
  CURR_TARGET = $(MBGTOOLS_TARGET)
  USE_STATIC_LIB = 1

  OBJS = $(CURR_TARGET).o
endif  # MBGTOOLS_TARGET


ifneq ($(USE_STATIC_LIB),0)
  LDFLAGS += -L$(MBGTOOLS_STATIC_LIB_PATH)
  LDLIBS += -l$(MBGTOOLS_STATIC_LIB_BASENAME)

  $(CURR_TARGET): $(MBGTOOLS_STATIC_LIB_FILE_PATH)
endif


CPPFLAGS += $(CPPFLAGS_SYN1588)

LDLIBS += $(LDLIBS_SYN1588)


$(call debug_msg,$(INFO) MBGTOOLS_STATIC_LIB_FILE_PATH: $(MBGTOOLS_STATIC_LIB_FILE_PATH))
$(call debug_msg,$(INFO) USE_STATIC_LIB: $(USE_STATIC_LIB))
$(call debug_msg,$(INFO) CURR_TARGET: $(CURR_TARGET))


.PHONY: all
all: $(CURR_TARGET)

VPATH += $(foreach dir,$(MBGLIB_DIRS),$(MBGLIB)/$(dir))
VPATH += $(SYN1588_SRC_DIRS)

USE_THREAD_API = 1

ifdef USE_THREAD_API

  # Check whether thread affinity is supported by the installed pthread library.
  # Newer versions of glibc/pthread (at least glibc 2.5) supports this natively.
  # Older versions of glibc/pthread (e.g. glibc 2.3) may not support this natively
  # but may provide a NPTL (New Posix Thread Library) library located under separate
  # include and lib paths. We try to detect NPTL and add those paths to the search
  # paths only if USE_NTPL has been defined e.g. on the make command line.

  # Check whether pthread_getaffinity is supported by the standard pthread.h
  USE_THREAD_AFFINITY := $(shell grep -q pthread_getaffinity /usr/include/pthread.h && echo 1)

  # If it is not, check nptl/pthread.h
  ifndef USE_THREAD_AFFINITY
    ifdef USE_NPTL
      USE_THREAD_AFFINITY := $(shell grep -q pthread_getaffinity /usr/include/nptl/pthread.h && echo 1)
    endif

    ifndef USE_THREAD_AFFINITY
      # If not found either, don't support thread affinity.
      USE_THREAD_AFFINITY=0
    else
      # If supported via nptl, add the associated search paths.
      CPPFLAGS += -I/usr/include/nptl -L/usr/lib/nptl
    endif
  endif

  # May want to use the result for our program.
  ## CPPFLAGS += -DUSE_THREAD_AFFINITY=$(USE_THREAD_AFFINITY)

  CPPFLAGS += -DMBGDEVIO_USE_THREAD_API=1

  # LDLIBS += -lpthread
  LDFLAGS += -pthread
endif  # USE_THREAD_API

# On some older Linux systems, clock_gettime() and friends are only
# provided by the real time extension library librt.
LDLIBS += -lrt

ifdef INST_TO_BIN
  INST_DIR = $(DESTDIR)$(bindir)
else
  ifdef INST_TO_SBIN
    INST_DIR = $(DESTDIR)$(sbindir)
  else
    ifdef INST_TO_LIB
      INST_DIR = $(DESTDIR)$(libdir)
    else
      ifdef INST_TO_INCLUDE
        INST_DIR = $(DESTDIR)$(includedir)/mbglib
      endif
    endif
  endif
endif


$(MBGTOOLS_STATIC_LIB_FILE_PATH):
	$(MAKE) -C $(MBGTOOLS_STATIC_LIB_PATH) $(MBGTOOLS_STATIC_LIB_FILE)

# Options for the archiver to build a static library.
ARFLAGS := rcs
ifneq ("$(V)","0")
  # In verbose mode we also make the archiver verbose.
  ARFLAGS := $(ARFLAGS)v
endif


$(call debug_msg,$(INFO) CPPFLAGS: $(CPPFLAGS))
$(call debug_msg,$(INFO) EXTRA_CFLAGS: $(EXTRA_CFLAGS))
$(call debug_msg,$(INFO) MAKECMDGOALS: $(MAKECMDGOALS))


$(CURR_TARGET): $(OBJS)
ifdef MBGTOOLS_STATIC_LIB_TARGET
	$(vecho) "    $(AR)       $@"
	$(Q)$(AR) $(ARFLAGS) $@ $(OBJS)
else
	$(vecho) "    Linking $@"
	$(Q)$(CC) -o $@ $(LDFLAGS) $^ $(LDLIBS)
  ifdef SO_TARGET_LIBNAME
	  ln -sf $(CURR_TARGET) $(SO_TARGET_LIBNAME)
  endif
endif  # MBGTOOLS_STATIC_LIB_TARGET


.PHONY: install
install:
ifneq ($(INST_DIR),)
  ifneq ($(UID),0)
	  $(call make_as_root, $@)
  else
    ifdef INCLUDE_FILES        # Install header files.
	    for incfile in $(INCLUDE_FILES); do \
	      install -m 644 -D $(BASEDIR)/mbglib/common/$$incfile $(INST_DIR)/$$incfile; \
	    done;
	    for basename in $(SO_BASENAMES); do \
	      (mkdir -p $(DESTDIR)$(libdir); cd $(DESTDIR)$(libdir); ln -sf libmbg$$basename.so.$(SO_MAJOR_VERSION) libmbg$$basename.so;) \
	    done;
    else                       # Usual installation.
	    install -s -m 755 -D $(CURR_TARGET) $(INST_DIR)/$(CURR_TARGET)

      ifndef STAGED_BUILD
        ifdef INST_TO_LIB
	        $(LDCONFIG) $(INST_DIR)
        endif
      endif
    endif
  endif
endif


.PHONY: uninstall
uninstall:
ifneq ($(INST_DIR),)
  ifneq ($(UID),0)
	  $(call make_as_root, $@)
  else
    ifdef INCLUDE_FILES        # Remove header files.
	    rm -rf $(INST_DIR)
      ifndef STAGED_BUILD  # Remove symbolic links.
	      for basename in $(SO_BASENAMES); do \
	        rm -f $(libdir)/libmbg$$basename.so; \
	      done;
      endif
    else
	    rm -f $(INST_DIR)/$(CURR_TARGET)
      ifndef STAGED_BUILD
        ifdef INST_TO_LIB
	        $(LDCONFIG) $(INST_DIR)
        endif
      endif
    endif
  endif
endif


CLEAN_FILES += *.o
CLEAN_FILES += *~
CLEAN_FILES += $(foreach dir,$(MBGLIB_DIRS),$(MBGLIB)/$(dir)/*~)
CLEAN_FILES += core
CLEAN_FILES += $(CURR_TARGET)

.PHONY: clean
clean:
ifneq ($(CLEAN_FILES),)
	rm -f $(CLEAN_FILES)
endif
ifneq ($(CLEAN_DIRS),)
	rm -rf $(CLEAN_DIRS)
endif


else  # ===== Building a kernel module =============================================

ifndef MBGTOOLS_TARGET
  MBGTOOLS_TARGET = $(MODULE).ko
endif

ifeq ($(KERNELRELEASE),)
# ===== Building module for kernel 2.6 or newer, not yet called from kernel build system ====

INFO = kbuild initial:
KERNEL_BUILD_MSG = "Calling kernel build system to make"
KERNEL_BUILD_FINISHED_MSG = "Kernel build system finished making"

.PHONY: all
all: modules


PWD := $(shell pwd)

ifneq ($(MBG_VERSION_FROM_GIT),)
  EXTRA_CFLAGS += -DMBG_VERSION_FROM_GIT=$(MBG_VERSION_FROM_GIT)
endif

EXTRA_CFLAGS += -Wall
ifneq ($(CC_SUPPORTS_WEXPANSION_TO_DEFINED),0)
  EXTRA_CFLAGS += -Wexpansion-to-defined
endif
EXTRA_CFLAGS += -I.
EXTRA_CFLAGS += -I$(BASEDIR)
EXTRA_CFLAGS += $(foreach dir,$(MBGLIB_DIRS),-I$(MBGLIB)/$(dir))

ifdef MBG_PRI_64_PREFIX_L
  EXTRA_CFLAGS += -DMBG_PRI_64_PREFIX_L
else
  ifdef MBG_PRI_64_PREFIX_LL
    EXTRA_CFLAGS += -DMBG_PRI_64_PREFIX_LL
  endif
endif

ifdef DEBUG
  EXTRA_CFLAGS += -DDEBUG=$(DEBUG)
else
  ifdef MUST_DEBUG_DRVR  # maybe from a sub-Makefile
    EXTRA_CFLAGS += -DDEBUG=$(MUST_DEBUG_DRVR)
  endif
endif

# The definitions below can be used to override the default detection
# of kernel API changes. Can be required, for example, to override the
# detection by the driver code in case a distibutor broke compatibility
# by backporting new changes to older kernels.

# The 'bool' type is supported by the vanilla Linux kernel 2.6.19 and later.
# However, looks like the RedHat folks have backported this to 2.6.18,
# so this can be defined to avoid a compiler error.
ifdef KERNEL_HAS_BOOL
  EXTRA_CFLAGS += -DKERNEL_HAS_BOOL=$(KERNEL_HAS_BOOL)
endif

# Same for 'true' and 'false'.
ifdef KERNEL_HAS_TRUE_FALSE
  EXTRA_CFLAGS += -DKERNEL_HAS_TRUE_FALSE=$(KERNEL_HAS_TRUE_FALSE)
endif

# Vanilla kernels 6.3.0 and newer provide inline functions
# to set VMA VM flags. For older kernels, the flags usually
# need to be set directly.
ifdef KERNEL_HAS_VMA_VM_FLAGS_WRAPPER_FUNCTIONS
  EXTRA_CFLAGS += -DKERNEL_HAS_VMA_VM_FLAGS_WRAPPER_FUNCTIONS=$(KERNEL_HAS_VMA_VM_FLAGS_WRAPPER_FUNCTIONS)
endif

# Vanilla kernels 6.4.0 and newer have dropped the 'owner' field in the device class.
# to set VMA VM flags. For older kernels, the flags usually
# need to be set directly.
ifdef KERNEL_CLASS_WITHOUT_OWNER
  EXTRA_CFLAGS += -DKERNEL_CLASS_WITHOUT_OWNER=$(KERNEL_CLASS_WITHOUT_OWNER)
endif

# Vanilla kernels 6.12.0 and newer have moved asm/unaligned.h
# to linux/unaligned.h
ifdef KERNEL_HAS_LINUX_UNALIGNED_H
  EXTRA_CFLAGS += -DKERNEL_HAS_LINUX_UNALIGNED_H=$(KERNEL_HAS_LINUX_UNALIGNED_H)
endif


# Specify our current working directory and the kernel source directory,
# and call the kernel build system.

ifndef TARGET_KERNEL
  # Unless the target version has been defined before e.g. on the command line using
  #   TARGET_KERNEL=2.6.12 make
  # we are building for the version of the currently running kernel.
  TARGET_KERNEL := $(shell uname -r)
endif

ifndef BUILD_DIR
  BUILD_DIR := /lib/modules/$(TARGET_KERNEL)/build
endif


# We need to know the major kernel version to call the
# kernel build environment appropriately.
# Try to determine that number from the Makefile of the kernel source,
# unless it already has been specified e.g. on the command line.
ifeq ($(KERNEL_MAJOR_VERSION),)
  # Try to determine the major kernel version from a line like
  #   VERSION = 3
  # at the top of the Makefile in the kernel build directory.
  KERNEL_MAJOR_VERSION = $(shell grep '^VERSION =' $(BUILD_DIR)/Makefile | cut -d= -f2)
  $(call debug_msg,$(INFO) Kernel major version: $(KERNEL_MAJOR_VERSION))

  # If the kernel version couldn't be determined above, we let it
  # default to 3, which is most likely correct, and also appropriate
  # for later kernels.
  ifeq ($(KERNEL_MAJOR_VERSION),)
    KERNEL_MAJOR_VERSION = 3
  endif
endif


# Depending on the major kernel version we decide how to call
# the kernel build system to build our module out-of-tree.
#
# Kernels 2.6 up to 5.3 support the 'SUBDIRS=' syntax, but kernels 5.4
# and later don't. On the other hand, at least kernels 3.x and later
# support the 'M=' parameter, so we use this for kernels 3.x and later.
ifeq ($(shell test $(KERNEL_MAJOR_VERSION) -ge 3; echo $$?),0)
  MBGCLOCK_DIR_ARG := M=$(PWD)
else
  MBGCLOCK_DIR_ARG := SUBDIRS=$(PWD)
endif
$(call debug_msg,$(INFO) MBGCLOCK_DIR_ARG: $(MBGCLOCK_DIR_ARG))


MODPROBE ?= $(call chk_which_exec, "modprobe" )
INSMOD ?= $(call chk_which_exec, "insmod" )
RMMOD ?= $(call chk_which_exec, "rmmod" )
DEPMOD ?= $(call chk_which_exec, "depmod")
DEPMOD_ARGS = -a $(TARGET_KERNEL)


$(call debug_msg,$(INFO) CPPFLAGS: $(CPPFLAGS))
$(call debug_msg,$(INFO) EXTRA_CFLAGS: $(EXTRA_CFLAGS))
$(call debug_msg,$(INFO) MAKECMDGOALS: $(MAKECMDGOALS))
$(call debug_msg,$(INFO) DEPMOD: $(DEPMOD))



# The revision control system used at Meinberg puts the library
# source files into the library directory. However, customized
# VPATH may not be supported by the kernel build system, so all
# source files should be located in the current directory.
# As a workaround we create links for the couple of files:

.PHONY: src_links
src_links: $(MBGLIB_OBJS_COMMON:.o=.c) $(MBGLIB_OBJS_LINUX:.o=.c)

MBGLIB_COMMON = $(MBGLIB)/common
MBGLIB_LINUX = $(MBGLIB)/linux

$(MBGLIB_OBJS_COMMON:.o=.c):
	$(Q)ln -sf $(MBGLIB_COMMON)/$@ $@

$(MBGLIB_OBJS_LINUX:.o=.c):
	$(Q)ln -sf $(MBGLIB_LINUX)/$@ $@


.PHONY: modules
modules: src_links
	@echo $(KERNEL_BUILD_MSG) \"$@\"
	$(Q)$(MAKE) $(QM) -C $(BUILD_DIR) $(MBGCLOCK_DIR_ARG) BASEDIR=$(BASEDIR) V=$(V) EXTRA_CFLAGS="$(EXTRA_CFLAGS)" $@
	@echo $(KERNEL_BUILD_FINISHED_MSG) \"$@\"



# On early 2.6.x kernels, the make target "modules_add" MUST be used
# to install our kernel module.
# If we ran "make modules_install" for those kernels, this would install
# ONLY our module, but would DELETE ALL OTHER kernel modules, leaving
# the system unusable after the next reboot.
#
# On systems where target "modules_add" does NOT exist, it's safe to run
# "make modules_install".
#
# On kernels 5.8, the kernel build system can even be messed up (e.g. the
# autoconf.h file be deleted) by only running the check, so we do the
# check only for kernels prior to 3.x.

ifeq ($(shell test $(KERNEL_MAJOR_VERSION) -lt 3; echo $$?),0)

  # This macro function returns an empty string if the kernel Makefile
  # supports a specified target, or "NOT ", if it does not:
  src_tgt_nsupp = $(shell make -C $(BUILD_DIR) -n $(1) >/dev/null 2>/dev/null || echo "NOT ")

  # This macro function prints an info string whether a target
  # is supported by the kernel Makefile
  prt_if_src_tgt_supp = $(shell echo -e "make $(strip $(1)):\t  $(call src_tgt_nsupp, $(1))supported")

  ifeq ($(call src_tgt_nsupp,"modules_add"),)
    $(call debug_msg,$(INFO) make target "modules_add" exists)
    MAKECMDGOALS = modules_add
  else
    $(call debug_msg,$(INFO) make target "modules_add" doesn't exist)
    MAKECMDGOALS = modules_install
  endif
else
  $(call debug_msg,$(INFO) Skipping test for modules_add)
  MAKECMDGOALS = modules_install
endif


.PHONY: install_module
install_module:
ifneq ($(UID),0)
	$(Q)$(call make_as_root, $@ V=$(V))
else
	@echo
	@echo $(KERNEL_BUILD_MSG) \"$(MAKECMDGOALS)\"
	$(Q)$(MAKE) $(QMK) -C $(BUILD_DIR) $(MBGCLOCK_DIR_ARG) V=$(V) $(MAKECMDGOALS)
	@echo $(KERNEL_BUILD_FINISHED_MSG) \"$(MAKECMDGOALS)\"
  ifndef STAGED_BUILD
	  @echo
	  @echo Explicitly running \"$(DEPMOD) $(DEPMOD_ARGS)\"
	  $(DEPMOD) $(DEPMOD_ARGS)
	  @echo
  endif
endif


.PHONY: install
install: install_module


.PHONY: uninstall
uninstall:
ifndef STAGED_BUILD
  ifneq ($(UID),0)
	  $(Q)$(call make_as_root, $@)
  else
	  $(Q)rm -f /lib/modules/`uname -r`/extra/$(MBGTOOLS_TARGET)
  endif
endif

CLEAN_FILES += *.o
CLEAN_FILES += *.ko
CLEAN_FILES += *~
CLEAN_FILES += core
CLEAN_FILES += Module.symvers
CLEAN_FILES += .*.cmd
CLEAN_FILES += *.mod.c
CLEAN_FILES += $(MBGLIB_OBJS:.o=.c)
CLEAN_FILES += $(MBGLIB_OBJS:.o=.o.d)
CLEAN_FILES += .*.o.d
CLEAN_FILES += modules.order
CLEAN_FILES += Module.markers
CLEAN_FILES += $(MODULE).mod
CLEAN_FILES += *.ipa-clones

CLEAN_DIRS += .tmp_versions


.PHONY: clean
clean:
	@echo $(KERNEL_BUILD_MSG) \"$@\"
	$(Q)$(MAKE) $(QM) -C $(BUILD_DIR) $(MBGCLOCK_DIR_ARG) BASEDIR=$(BASEDIR) V=$(V) clean
	@echo $(KERNEL_BUILD_FINISHED_MSG) \"clean\"
  ifneq ($(CLEAN_FILES),)
	  $(Q)rm -f $(CLEAN_FILES)
  endif
  ifneq ($(CLEAN_DIRS),)
	  $(Q)rm -rf $(CLEAN_DIRS)
  endif


else  # !$(KERNELRELEASE)

# ===== Building module for kernel 2.6, called back from kernel build system =======

INFO = kbuild callback:

# Our own additional compiler flags have already been specified,
# so just specify the files required to build the kernel module.

$(call debug_msg,$(INFO) CPPFLAGS: $(CPPFLAGS))
$(call debug_msg,$(INFO) EXTRA_CFLAGS: $(EXTRA_CFLAGS))
$(call debug_msg,$(INFO) MAKECMDGOALS: $(MAKECMDGOALS))

obj-m := $(MODULE).o
$(MODULE)-objs := $(MODULE_OBJS) $(MBGLIB_OBJS)

endif  # $(KERNELRELEASE)

endif  # building kernel module
#==================================================================================

INFO = bottom 2nd:

LDCONFIG ?= $(call chk_which_exec, "ldconfig")

SYSTEMCTL = systemctl
SYSTEMCTL_BIN = $(call chk_which_exec, $(SYSTEMCTL))

GETENFORCE = getenforce
GETENFORCE_BIN = $(call chk_which_exec, $(GETENFORCE))

ifneq ($(GETENFORCE_BIN),)
  # Install option to set the SELinux security context to default.
  INST_OPT_SELINUX = -Z
endif

ifndef STAGED_BUILD
  # Install option to set root ownership.
  INST_OPT_CHOWN_ROOT = -o root
endif

CONF_FILE_SYSTEMD = $(MBGTOOLS_TARGET).service
SRC_DIR_SYSTEMD = $(BASEDIR)/rc-scripts/systemd/
DST_DIR_SYSTEMD ?= $(DESTDIR)/etc/systemd/system/
ifndef STAGED_BUILD
  DST_DIR_SYSTEMD_EXISTS = $(call chk_exist_dir, $(DST_DIR_SYSTEMD))
else
  DST_DIR_SYSTEMD_EXISTS = $(DST_DIR_SYSTEMD)
endif

INITCTL = initctl
INITCTL_BIN = $(call chk_which_exec, $(INITCTL))

CONF_FILE_UPSTART = $(MBGTOOLS_TARGET).conf
SRC_DIR_UPSTART = $(BASEDIR)/rc-scripts/upstart/
DST_DIR_UPSTART ?= $(DESTDIR)/etc/init/
ifndef STAGED_BUILD
  DST_DIR_UPSTART_EXISTS = $(call chk_exist_dir, $(DST_DIR_UPSTART))
else
  # Nothing to do here since by default we don't
  # support upstart in staged builds.
  # If required, DST_DIR_UPSTART_EXISTS can be
  # specified on the command line.
endif

$(MBGTOOLS_TARGET)_install:
  ifneq ($(UID),0)
	  $(call make_as_root, $@)
  else
    ifneq ($(DST_DIR_SYSTEMD_EXISTS),)
	    @echo "Installing $(CONF_FILE_SYSTEMD) to systemd configuration directory $(DST_DIR_SYSTEMD)"
      ifdef STAGED_BUILD
	      mkdir -p $(DST_DIR_SYSTEMD)
      endif
	    install $(INST_OPT_CHOWN_ROOT) $(INST_OPT_SELINUX) -m 644 -t $(DST_DIR_SYSTEMD) $(SRC_DIR_SYSTEMD)$(CONF_FILE_SYSTEMD)
	    sed -i -e 's?@prefix@?$(prefix)?g' $(DST_DIR_SYSTEMD)$(CONF_FILE_SYSTEMD)
      ifneq ($(SYSTEMCTL_BIN),)
        ifndef STAGED_BUILD
	        @echo "Registering $(MBGTOOLS_TARGET) with systemd"
	        $(SYSTEMCTL_BIN) daemon-reload
	        $(SYSTEMCTL_BIN) enable $(CONF_FILE_SYSTEMD)
	        -$(SYSTEMCTL_BIN) stop $(CONF_FILE_SYSTEMD)
	        -$(SYSTEMCTL_BIN) start $(CONF_FILE_SYSTEMD)
	        $(SYSTEMCTL_BIN) -l status $(CONF_FILE_SYSTEMD)
        endif # STAGED_BUILD
      else
	      @echo "Command $(SYSTEMCTL) not found, unable to register $(MBGTOOLS_TARGET) with systemd"
      endif
    else
	    @echo "systemd configuration directory $(DST_DIR_SYSTEMD) not found, skipping registering $(MBGTOOLS_TARGET) for systemd"
    endif
    ifneq ($(DST_DIR_UPSTART_EXISTS),)
	    @echo "Installing $(CONF_FILE_UPSTART) to upstart configuration directory $(DST_DIR_UPSTART)"
      ifdef STAGED_BUILD
	      mkdir -p $(DST_DIR_UPSTART)
      endif
	    install $(INST_OPT_CHOWN_ROOT) -m 644 -t $(DST_DIR_UPSTART) $(SRC_DIR_UPSTART)$(CONF_FILE_UPSTART)
      ifneq ($(INITCTL_BIN),)
	      @echo "Registering $(MBGTOOLS_TARGET) with upstart init system"
	        $(INITCTL_BIN) reload-configuration
	        $(INITCTL_BIN) status $(MBGTOOLS_TARGET) | grep "running" || $(INITCTL_BIN) start $(MBGTOOLS_TARGET)
      else
	      @echo "Command $(INITCTL) not found, unable to register $(MBGTOOLS_TARGET) with upstart"
      endif
    else
      ifndef STAGED_BUILD
	      @echo "upstart configuration directory $(DST_DIR_UPSTART) not found, skipping registering $(MBGTOOLS_TARGET) for upstart"
      endif
    endif
  endif


$(MBGTOOLS_TARGET)_uninstall:
  ifneq ($(UID),0)
	  $(call make_as_root, $@)
  else
    ifneq ($(SYSTEMCTL_BIN),)
	    @echo "Unregistering $(MBGTOOLS_TARGET) from systemd"
	    -$(SYSTEMCTL_BIN) stop $(CONF_FILE_SYSTEMD)
	    -$(SYSTEMCTL_BIN) disable $(CONF_FILE_SYSTEMD)
	    -$(SYSTEMCTL_BIN) daemon-reload
    endif
	  rm -f $(DST_DIR_SYSTEMD)$(CONF_FILE_SYSTEMD)
    ifneq ($(INITCTL_BIN),)
	    @echo "Unregistering $(MBGTOOLS_TARGET) from upstart init system"
	    -$(INITCTL_BIN) stop $(MBGTOOLS_TARGET)
    endif
	  rm -f $(DST_DIR_UPSTART)$(CONF_FILE_UPSTART)
    ifneq ($(INITCTL_BIN),)
	    $(INITCTL_BIN) reload-configuration
    endif
  endif


# Common targets:

.PHONY: distclean
distclean: clean

endif
#==================================================================================

INFO = bottom common:

AA_STATUS_BIN ?= $(call chk_which_exec, "aa-status")


show_syn1588_info = @echo ""; echo "$(1) $(2) support for $(3)."; echo ""

syn1588_info = SYN1588 PCI cards

ifeq ($(SUPP_SYN1588),0)
  build_info = without
else
  build_info = with
  ifneq ($(SYN1588_DIR),$(SYN1588_DIST_DIR))
    syn1588_info += from $(SYN1588_DIR)
  endif
endif


.PHONY: pre_build_info
pre_build_info:
	$(call show_syn1588_info,Building,$(build_info),$(syn1588_info))

.PHONY: post_build_info
post_build_info:
  ifdef SEPARATOR_2
	  @echo "$(SEPARATOR_2)"
  endif
	$(call show_syn1588_info,Built,$(build_info),$(syn1588_info))
  ifeq ($(SUPP_SYN1588),0)
	  @echo "If support for SYN1588NIC PCI cards is required,"
	  @echo "run 'make clean; make SUPP_SYN1588=1'."
	  @echo ""
  endif
	@echo "For the next step, type"
	@echo ""
	@echo "  make install"
	@echo ""
	@echo "to install the executable files."
	@echo ""


.PHONY: post_install_info
post_install_info:
  ifdef SEPARATOR_2
	  @echo "$(SEPARATOR_2)"
  endif
	@echo ""
	@echo "Installation of the executables completed successfully. Now type"
	@echo ""
	@echo "  sudo /sbin/modprobe mbgclock"
	@echo ""
	@echo "to load the kernel module for the first time."
	@echo "After this the kernel module should be loaded automatically"
	@echo "whenever a supported device is detected by the kernel."
	@echo ""
	@echo "Once the kernel module has been loaded, run"
	@echo ""
	@echo "  make install_svc"
	@echo ""
	@echo "to register the mbgsvcd service so the service will be"
	@echo "started automatically after reboot, and can be controlled"
	@echo "via the usual commands."
	@echo ""
	@echo "See the README file how to configure ntpd."
	@echo ""
  ifneq ($(AA_STATUS_BIN),)
	  @echo "WARNING: AppArmor is installed. If ntpd is unable to use any Meinberg device"
	  @echo "as expected, see the AppArmor section in the README file for help."
	  @echo ""
  endif
  ifneq ($(GETENFORCE_BIN),)
	  @echo "WARNING: SElinux is installed. If ntpd is unable to use any Meinberg device"
	  @echo "as expected, see the SElinux/README file for help."
	  @echo ""
  endif

.PHONY: pre_uninstall_intro
pre_uninstall_intro:
  ifdef SEPARATOR_2
	  @echo "$(SEPARATOR_2)"
  endif
	@echo "Making pre-uninstall targets"

.PHONY: pre_uninstall
pre_uninstall: pre_uninstall_intro $(PRE_UNINSTALL_TARGETS)
	@echo "Finished pre-uninstall targets"

