######################################################################### # # $Id: Makefile 1.40 2023/12/04 14:49:57 martin.burnicki REL_M $ # # Makefile for mbgtools-lx which recurses into the subdirectories. # # ----------------------------------------------------------------------- # $Log: Makefile $ # 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 . # 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 ) # 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 # 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)) # This should be enabled if preliminary code # is to be included for testing. PRELIMINARY_CODE ?= 0 # 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 $(TOPDIR)/makefile-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 ## CPPFLAGS += -Wextra ## CPPFLAGS += -Winline ifneq ($(PRELIMINARY_CODE),0) CPPFLAGS += -D_PRELIMINARY_CODE=$(PRELIMINARY_CODE) endif 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 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 '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 # 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"