Skip to content
Snippets Groups Projects
driver.makefile 28.3 KiB
Newer Older
zimoch's avatar
zimoch committed
# driver.makefile
#
Dirk Zimoch's avatar
Dirk Zimoch committed
# This generic makefile compiles EPICS modules (drivers, records, snl, ...)
# for all installed EPICS versions.
zimoch's avatar
zimoch committed
# Read this documentation and the inline comments carefully before
# changing anything in this file.
#
# Usage: Create a Makefile containig the line:
#        include /ioc/tool/driver.makefile
zimoch's avatar
zimoch committed
#        Optionally add variable definitions below that line.
#
# This makefile automatically finds the source file (unless overwritten with
# the SOURCES variable in your Makefile) and generates a module consisting
# of a library and .dbd file for each EPICS version and each target architecture.
# Therefore, it calls itself recursively.
zimoch's avatar
zimoch committed
#
# - First run: (see comment ## RUN 1)
#   Find the sources etc.
Simon Rose's avatar
Simon Rose committed
#   Include EPICS configuration files for ${EPICSVERSION}, determined by ${EPICS_BASE}
#   Iterate over all target architectures (${T_A}) defined.
zimoch's avatar
zimoch committed
#
Simon Rose's avatar
Simon Rose committed
# - Second run: (see comment ## RUN 2)
Dirk Zimoch's avatar
Dirk Zimoch committed
#   Check which target architectures to build.
#   Create O.${EPICSVERSION}_${T_A} subdirectories if necessary.
#   Change to O.${EPICSVERSION}_${T_A} subdirectories.
#
Simon Rose's avatar
Simon Rose committed
# - Third run: (see comment ## RUN 3)
Dirk Zimoch's avatar
Dirk Zimoch committed
#   Compile everything.
zimoch's avatar
zimoch committed
#
# Module names are derived from the directory name (unless overwritten
# with the MODULE variable in your Makefile).
# A LIBVERSION number is generated from the latest CVS or GIT tag of the sources.
# If any file is not up-to-date in CVS/GIT, not tagged, or tagged differently from the
# other files, the version is a test version and labelled with the user name.
# The library is installed to ${EPICS_MODULES}/${MODULE}/${LIBVERSION}/lib/${T_A}/.
# A module can be loaded with  require "<module>" [,"<version>"] [,"<variable>=<substitution>, ..."]
zimoch's avatar
zimoch committed
#
# User variables (add them to your Makefile, none is required):
# MODULE
#    Name of the built module.
zimoch's avatar
zimoch committed
#    If not defined, it is derived from the directory name.
# SOURCES
#    All source files to compile.
zimoch's avatar
zimoch committed
#    If not defined, default is all *.c *.cc *.cpp *.st *.stt in
#    the source directory (where you run make).
zimoch's avatar
zimoch committed
#    If you define this, you must list ALL sources.
# DBDS
#    All dbd files of the project.
#    If not defined, default is all *.dbd files in the source directory.
# HEADERS
#    Header files to install (e.g. to be included by other drivers)
#    If not defined, all headers are for local use only.
# ARCH_FILTER
#    Sub set of architectures to build for, e.g. %-ppc604
zimoch's avatar
zimoch committed

zimoch's avatar
zimoch committed
MAKEHOME:=$(dir $(lastword ${MAKEFILE_LIST}))
# Get the name of the Makefile that included this file.
zimoch's avatar
zimoch committed
USERMAKEFILE:=$(lastword $(filter-out $(lastword ${MAKEFILE_LIST}), ${MAKEFILE_LIST}))

Simon Rose's avatar
Simon Rose committed
##---## In E3, We only use one version of EPICS base when compiling modules.
##---## EPICS_LOCATION is (by default) /epics/base-${EPICSVERSION}
EPICS_LOCATION =
EPICS_BASE=${EPICS_LOCATION}
CONFIG=${EPICS_BASE}/configure

##---## In E3, we extract BASE_VERSION from EPICS_LOCATION
Simon Rose's avatar
Simon Rose committed
EPICSVERSION:=$(patsubst base-%,%,$(notdir $(EPICS_LOCATION)))
BUILDCLASSES = Linux
EPICS_MODULES =
OS_CLASS_LIST = $(BUILDCLASSES)

MODULE=
PROJECT=
PRJ := $(strip $(or ${MODULE},${PROJECT}))

MODULE_LOCATION =${EPICS_MODULES}/$(or ${PRJ},$(error PRJ not defined))/$(or ${LIBVERSION},$(error LIBVERSION not defined))

zimoch's avatar
zimoch committed
-include ${MAKEHOME}/config

Simon Rose's avatar
Simon Rose committed
RMDIR = rm -rf
zimoch's avatar
zimoch committed
LN = ln -s
zimoch's avatar
zimoch committed
RM = rm -f
Dirk Zimoch's avatar
Dirk Zimoch committed
CP = cp
Simon Rose's avatar
Simon Rose committed
MKDIR = mkdir -p -m 775
zimoch's avatar
zimoch committed

Simon Rose's avatar
Simon Rose committed
# This is to allow for build numbers in recognized versions.
VERSIONREGEX = [0-9]+\.[0-9]+\.[0-9]+(\+[0-9]+)?
Dirk Zimoch's avatar
Dirk Zimoch committed
VERSIONFILE = ${PRJ}_version_${LIBVERSION}.c
zimoch's avatar
zimoch committed
REGISTRYFILE = ${PRJ}_registerRecordDeviceDriver.cpp
Dirk Zimoch's avatar
Dirk Zimoch committed
DEPFILE = ${PRJ}.dep
METAFILE = ${PRJ}_meta.yaml
zimoch's avatar
zimoch committed

# Clear potential environment variables.
Jeong Han Lee's avatar
Jeong Han Lee committed
BASH_ENV=
ENV=
zimoch's avatar
zimoch committed
# Default target is "build" for all versions.
# Don't install anything (different from default EPICS make rules).
zimoch's avatar
zimoch committed
default: build

clean:
	$(RMDIR) O.*

O.%:
	+$(MKDIR) $@

uninstall:
	$(RMDIR) ${MODULE_LOCATION}

IGNOREFILES = .gitignore
Dirk Zimoch's avatar
Dirk Zimoch committed
%: ${IGNOREFILES}
zimoch's avatar
zimoch committed
${IGNOREFILES}:
	@echo -e "O.*\n.gitignore" > $@

# Function that removes duplicates without re-ordering (unlike sort):
  $(eval seen :=) \
  $(foreach _,$1,$(if $(filter $_,${seen}),,$(eval seen += $_))) \
Simon Rose's avatar
Simon Rose committed
# Function that fetches the correct build number from the shared filesystem.
# Usage:
#
#   $(call FETCH_BUILD_NUMBER,$(E3_SITEMODS_PATH),module)
#
define FETCH_BUILD_NUMBER
$(shell $(MAKEHOME)/build_number.sh $(1) $(2) $($(2)_VERSION))
Simon Rose's avatar
Simon Rose committed
endef

# Functions used for recursive dependency fetching. These are modified from https://github.com/markpiffer/gmtt.git
space := $(strip) $(strip)#
comma := ,#
list2param = $(subst $(space),$(comma),$(strip $1))
exec = $(eval -exec=$1)$(eval -exec:=$$(call -exec,$(call list2param,$2)))$(-exec)
while = $(if $(call exec,$1),$(eval $2)$(call while,$1,$2,$3),$(eval $3))

# This simply assures that we fetch all of the rest of the table when we run $(wordlist n,$(max_int_size),$(table_data))
max_int_size := 2147483647

# Used to select from table-like data; syntax is SELECT what FROM where WHEN condition. This has been tailored to parse .dep files.
select = $(strip $(call -select,$(strip $2),$1,$3))
-select = $(if $1,$(if $(call exec,$3,$(call list2param,$(wordlist 1,2,$1))), $(word $2,$1))$(call -select,$(wordlist 3,$(max_int_size),$1),$2,$3))

str-eq = $(if $(subst x$1,,x$2),,t)
# End of functions from https://github.com/markpiffer/gmtt.git

# Some TOP and EPICS_BASE tweeking necessary to work around release check in 3.14.10+.
zimoch's avatar
zimoch committed
TOP:=${EPICS_BASE}
zimoch's avatar
zimoch committed
EPICS_BASE:=${EB}

${CONFIG}/CONFIG:
	$(error EPICS release ${EPICSVERSION} not installed on this host.)

# Variables that need to override data from ${CONFIG}/CONFIG
BASE_CPPFLAGS=

Jeong Han Lee's avatar
Jeong Han Lee committed
ifndef LEGACY_RSET
USR_CPPFLAGS+=-DUSE_TYPED_RSET
endif
Jeong Han Lee's avatar
Jeong Han Lee committed
SHRLIB_VERSION=
zimoch's avatar
zimoch committed
OBJ=.o

COMMON_DIR = O.${EPICSVERSION}_Common
zimoch's avatar
zimoch committed
ifndef T_A
Simon Rose's avatar
Simon Rose committed
## RUN 1
Simon Rose's avatar
Simon Rose committed
# Target achitecture not yet defined, but EPICSVERSION is already known.
zimoch's avatar
zimoch committed

Simon Rose's avatar
Simon Rose committed
# Look for sources etc., and select target architectures to build.
# Export everything for second run:
zimoch's avatar
zimoch committed

AUTOSRCS := $(filter-out ~%,$(wildcard *.c *.cc *.cpp *.st *.stt *.gt))
zimoch's avatar
zimoch committed
SRCS = $(if ${SOURCES},$(filter-out -none-,${SOURCES}),${AUTOSRCS})
export SRCS

DBD_SRCS = $(if ${DBDS},$(filter-out -none-,${DBDS}),$(wildcard menu*.dbd *Record.dbd) $(strip $(filter-out %Include.dbd dbCommon.dbd %Record.dbd,$(wildcard *.dbd)) ${BPTS}))
DBD_SRCS += ${DBDS_${EPICSVERSION}}
export DBD_SRCS
zimoch's avatar
zimoch committed

RECORDS1 = $(patsubst %Record.dbd, %, $(filter-out dev%, $(filter %Record.dbd, $(notdir ${DBD_SRCS}))))
#record dbd files included by files given in DBDS
RECORDS2 = $(filter-out dev%, $(shell ${MAKEHOME}/expandDBD.tcl -r $(addprefix -I, $(sort $(dir ${DBD_SRCS}))) $(realpath ${DBDS})))
zimoch's avatar
zimoch committed
RECORDS = $(sort ${RECORDS1} ${RECORDS2})
zimoch's avatar
zimoch committed
export RECORDS

MENUS = $(patsubst %.dbd,%.h,$(wildcard menu*.dbd))
export MENUS

BPTS = $(patsubst %.data,%.dbd,$(wildcard bpt*.data))
export BPTS

DBDINSTALLS = $(DBD_INSTALLS)
DBDINSTALLS += $(MENUS)
DBDINSTALLS += $(BPTS)
export DBDINSTALLS

zimoch's avatar
zimoch committed
HDRS = ${HEADERS} $(addprefix ${COMMON_DIR}/,$(addsuffix Record.h,${RECORDS}))
HDRS += ${HEADERS_${EPICSVERSION}}
zimoch's avatar
zimoch committed
export HDRS

HDR_SUBDIRS = $(KEEP_HEADER_SUBDIRS)
export HDR_SUBDIRS

TEMPLS = $(if ${TEMPLATES},$(filter-out -none-,${TEMPLATES}),$(wildcard *.template *.db *.subs))
TEMPLS += ${TEMPLATES_${EPICSVERSION}}
TEMPLS += $(wildcard $(COMMON_DIR)/*.db)
zimoch's avatar
zimoch committed
export TEMPLS

Jeong Han Lee's avatar
Jeong Han Lee committed
SCR = $(if ${SCRIPTS},$(filter-out -none-,${SCRIPTS}),$(wildcard *.cmd *.iocsh))
Dirk Zimoch's avatar
Dirk Zimoch committed
export SCR

# Filter architectures to build using EXCLUDE_ARCHS and ARCH_FILTER.
ALL_ARCHS = ${EPICS_HOST_ARCH} ${CROSS_COMPILER_TARGET_ARCHS}
BUILD_ARCHS = $(filter-out $(addprefix %,${EXCLUDE_ARCHS}),$(filter-out $(addsuffix %,${EXCLUDE_ARCHS}),\
        $(if ${ARCH_FILTER},$(filter ${ARCH_FILTER},${ALL_ARCHS}),${ALL_ARCHS})))
zimoch's avatar
zimoch committed

SRCS_Linux = ${SOURCES_Linux}
export SRCS_Linux

# Perform default database expansion of .substitions/.templates into $(COMMON_DIR)
db_internal: $(COMMON_DIR)

-include $(COMMON_DIR)/*.db.d

VPATH += $(dir $(TMPS))
VPATH += $(dir $(SUBS))
$(COMMON_DIR)/%.db: %.template
	@printf "Inflating database ... %44s >>> %40s \n" "$^" "$@"
	$(QUIET)$(MSI) -D $(USR_DBFLAGS) -o $(COMMON_DIR)/$(notdir $(basename $@).db) $^ > $(COMMON_DIR)/$(notdir $(basename $@).db).d
	$(QUIET)$(MSI)    $(USR_DBFLAGS) -o $(COMMON_DIR)/$(notdir $(basename $@).db) $^
$(COMMON_DIR)/%.db: %.substitutions
	@printf "Inflating database ... %44s >>> %40s \n" "$^" "$@"
	$(QUIET)$(MSI) -D $(USR_DBFLAGS) -o $(COMMON_DIR)/$(notdir $(basename $@).db) -S $^ > $(COMMON_DIR)/$(notdir $(basename $@).db).d
	$(QUIET)$(MSI)    $(USR_DBFLAGS) -o $(COMMON_DIR)/$(notdir $(basename $@).db) -S $^
Simon Rose's avatar
Simon Rose committed
install build debug::
	@echo "MAKING EPICS VERSION ${EPICSVERSION}"
zimoch's avatar
zimoch committed

zimoch's avatar
zimoch committed
debug::
Simon Rose's avatar
Simon Rose committed
	@echo "===================== Pass 1 ====================="
	@echo "BUILDCLASSES = ${BUILDCLASSES}"
	@echo "LIBVERSION = ${LIBVERSION}"
	@echo "PRJ = ${PRJ}"
zimoch's avatar
zimoch committed
	@echo "EPICS_BASE = ${EPICS_BASE}"
	@echo "BUILD_ARCHS = ${BUILD_ARCHS}"
Simon Rose's avatar
Simon Rose committed
	@echo "ARCH_FILTER = ${ARCH_FILTER}"
zimoch's avatar
zimoch committed
	@echo "EXCLUDE_ARCHS = ${EXCLUDE_ARCHS}"
zimoch's avatar
zimoch committed
	@echo "LIBVERSION = ${LIBVERSION}"
# Create e.g. build-$(T_A) rules for each architecture, so that we can just do
#   build: build-arch1 build-arch2
define target_rule
$1-%: | $(COMMON_DIR)
	$${MAKE} -f $${USERMAKEFILE} T_A=$$* $1
endef
$(foreach target,install build debug,$(eval $(call target_rule,$(target))))

.SECONDEXPANSION:
zimoch's avatar
zimoch committed

# This has to fit under .SECONDEXPANSION in order to catch TMPS and SUBS, which are typically defined
# _after_ driver.makefile is included.
db_internal: $$(addprefix $(COMMON_DIR)/,$$(notdir $$(patsubst %.template,%.db,$$(TMPS))))

db_internal: $$(addprefix $(COMMON_DIR)/,$$(notdir $$(patsubst %.substitutions,%.db,$$(SUBS))))
# This has to be after .SECONDEXPANSION since BUILD_ARCHS will be modified based on EXCLUDE_ARCHS
# and ARCH_FILTER, which are defined _after_ driver.makefile.
$(foreach target,install build debug,$(eval $(target):: $$$$(foreach arch,$$$${BUILD_ARCHS},$(target)-$$$${arch})))

zimoch's avatar
zimoch committed
else # T_A
Dirk Zimoch's avatar
Dirk Zimoch committed

ifeq ($(filter O.%,$(notdir ${CURDIR})),)
Simon Rose's avatar
Simon Rose committed
## RUN 2
Simon Rose's avatar
Simon Rose committed
# Still in source directory, second run.
# Add sources for specific epics types or architectures.
ARCH_PARTS = ${T_A} $(subst -, ,${T_A}) ${OS_CLASS}
VAR_EXTENSIONS = ${EPICSVERSION} ${ARCH_PARTS} ${ARCH_PARTS:%=${EPICSVERSION}_%}
export VAR_EXTENSIONS

MODULES :=
PROCESSED_MODULES :=
Simon Rose's avatar
Simon Rose committed
INSTALLED_MODULES := $(sort $(notdir $(wildcard $(E3_SITEMODS_PATH)/* $(EPICS_MODULES)/*)))
Simon Rose's avatar
Simon Rose committed

# Converts all of the X_DEP_VERSIONs to x_VERSION and records them

# Create the module_VERSION variables giving the module and check if the module
# is actually installed. Add the module to the MODULES and REQ variables. That
# will be used later.
Simon Rose's avatar
Simon Rose committed
define fetch_module_versions
  lm := $$(shell echo $1 | tr '[:upper:]' '[:lower:]')
  ifneq ($$(strip $$(filter $(INSTALLED_MODULES),$$(lm))),)
    $$(lm)_VERSION := $($1_DEP_VERSION$2)
    $$(lm)_VERSION := $$(lastword $$(call FETCH_BUILD_NUMBER,$(E3_SITEMODS_PATH),$$(lm)) $$(call FETCH_BUILD_NUMBER,$(EPICS_MODULES),$$(lm)))
    MODULES += $$(lm)
    REQ += $$(lm)
    $$(warning Invalid dependency "$1_DEP_VERSION$2"; pruning)
Simon Rose's avatar
Simon Rose committed
endef
# Calls fetch_module_version for each module that appears in a
# module_DEP_VERSION variable. This is defined on the wrapper CONFIG_MODULE
Simon Rose's avatar
Simon Rose committed
$(foreach m,$(patsubst %_DEP_VERSION,%,$(filter %_DEP_VERSION,$(.VARIABLES))),$(eval $(call fetch_module_versions,$m)))
# Look for dependencies on extension files the same way as above
$(foreach x,$(VAR_EXTENSIONS),\
  $(foreach m,$(patsubst %_DEP_VERSION_$(x),%,$(filter %_DEP_VERSION_$(x),$(.VARIABLES))),$(eval $(call fetch_module_versions,$m,_$(x))))\
)
Simon Rose's avatar
Simon Rose committed
# Fetches the data from .dep files to be parsed by the above
define fetch_deps
$(shell cat $(or \
  $(lastword $(wildcard $(addsuffix /$1/$($1_VERSION)/lib/$(T_A)/$1.dep,$(E3_SITEMODS_PATH) $(EPICS_MODULES)))),\
  $(error Module '$1' version '$($1_VERSION)' does not exist.)) \
  | sed '1d')
# Used to recurse through versions: recursively fetches all of the dependencies
# from the given module
define update_dep_versions
  m := $$(firstword $$(MODULES))
  PROCESSED_MODULES += $$m
  $$m_TBL := $$(call fetch_deps,$$m)
  $$m_DEPS := $$(call select,1,$$($$m_TBL),1)
  MODULES := $$(filter-out $$(PROCESSED_MODULES),$$(MODULES) $$($$m_DEPS))
  # Fetch dependency versions on the .dep table then check it agains already
  # processed requirements.
  # If module_VERSION don't exists create it with module_FETCHED_VERSION value.
  # If module_VERSION already exists fails if it doesn't matches
  # module_FETCHED_VERSION.
  $$(foreach mm,$$($$m_DEPS),\
    $$(eval\
      $$(mm)_FETCHED_VERSION := $$(call select,2,$$($$m_TBL),$$$$(call str-eq,$$$$1,$$(mm)))\
      )\
    $$(if $$($$(mm)_VERSION),\
       $$(if $$(filter-out $$($$(mm)_FETCHED_VERSION),$$($$(mm)_VERSION)),\
         $$(error "$$(m) depends on $$(mm),$$($$(mm)_FETCHED_VERSION) but $$(mm),$$($$(mm)_VERSION) is also needed"),\
         ),\
      $$(eval $$(mm)_VERSION := $$($$(mm)_FETCHED_VERSION))\
      )\
    )
$(call while,$$(MODULES),$(update_dep_versions))
$(foreach m,$(PROCESSED_MODULES),$(eval export $m_VERSION))
Simon Rose's avatar
Simon Rose committed
	@echo "===================== Pass 2: T_A = $(T_A) ====================="
	@echo "BINS = $(BINS)"
	@echo "REQ = $(REQ)"
	@echo "VLIBS = $(VLIBS)"
zimoch's avatar
zimoch committed

ifeq ($(filter ${OS_CLASS},${OS_CLASS_LIST}),)

Dirk Zimoch's avatar
Dirk Zimoch committed
install% build%: build
install build:
	@echo Skipping ${T_A} because $(if ${OS_CLASS},OS_CLASS=\"${OS_CLASS}\" is not in BUILDCLASSES=\"${BUILDCLASSES}\",it is not available for R$(EPICSVERSION).)
zimoch's avatar
zimoch committed
%:
	@true
zimoch's avatar
zimoch committed

else ifeq ($(shell which $(firstword ${CC})),)
zimoch's avatar
zimoch committed

Dirk Zimoch's avatar
Dirk Zimoch committed
install% build%: build
install build:
zimoch's avatar
zimoch committed
	@echo Warning: Skipping ${T_A} because cross compiler $(firstword ${CC}) is not installed.
zimoch's avatar
zimoch committed
%:
	@true

else
zimoch's avatar
zimoch committed

ifeq ($(shell echo "${LIBVERSION}" | grep -v -E "^$(VERSIONREGEX)\$$"),)
	$(if $(wildcard ${MODULE_LOCATION}/lib/${T_A}),$(error ${MODULE_LOCATION}/lib/${T_A} already exists. If you really want to overwrite then uninstall first.))

	$(if $(wildcard ${MODULE_LOCATION}/lib/${T_A}),\
      $(warning Re-installing ${MODULE_LOCATION}/lib/${T_A})\
      $(RMDIR) ${MODULE_LOCATION}/lib/${T_A}\
    )
Simon Rose's avatar
Simon Rose committed
install build debug:: O.${EPICSVERSION}_${T_A}
Dirk Zimoch's avatar
Dirk Zimoch committed
	@${MAKE} -C O.${EPICSVERSION}_${T_A} -f ../${USERMAKEFILE} $@

endif

SRCS += $(foreach x, ${VAR_EXTENSIONS}, ${SOURCES_$x})
USR_LIBOBJS += ${LIBOBJS} $(foreach x,${VAR_EXTENSIONS},${LIBOBJS_$x})
export USR_LIBOBJS
BINS += $(foreach x, ${VAR_EXTENSIONS}, ${BINS_$x})
export BINS

VLIBS = $(VENDOR_LIBS) $(foreach x,$(VAR_EXTENSIONS),$(VENDOR_LIBS_$x))
export VLIBS

# These variables are written into a .yaml file in the installed module directory to keep track of
# metadata for which module was compiled.

${PRJ}_GIT_DESC := $(shell git rev-parse HEAD 2> /dev/null)
export ${PRJ}_GIT_DESC
# The formatting here is just to make sure this is properly parseable .yaml data
Simon Rose's avatar
Simon Rose committed
${PRJ}_GIT_STATUS := [ $(shell git status --porcelain 2> /dev/null | grep -v "\.Makefile" | sed 's/^/\\\"/' | sed 's/$$/\\\", /')]
export ${PRJ}_GIT_STATUS

Dirk Zimoch's avatar
Dirk Zimoch committed
else # in O.*
Simon Rose's avatar
Simon Rose committed
## RUN 3
Simon Rose's avatar
Simon Rose committed
# In build directory.
# Add macros like USR_CFLAGS_Linux.
EXTENDED_VARS=INCLUDES CFLAGS CXXFLAGS CPPFLAGS CODE_CXXFLAGS LDFLAGS
$(foreach v,${EXTENDED_VARS},$(foreach x,${VAR_EXTENSIONS},$(eval $v+=$${$v_$x}) $(eval USR_$v+=$${USR_$v_$x})))
zimoch's avatar
zimoch committed
CFLAGS += ${EXTRA_CFLAGS}
zimoch's avatar
zimoch committed

COMMON_DIR = ../O.${EPICSVERSION}_Common
zimoch's avatar
zimoch committed

# Remove include directory for this module from search path.
Dirk Zimoch's avatar
Dirk Zimoch committed
INSTALL_INCLUDES =

# Add include directory of foreign modules to include file search path.
#
# The default behaviour is to start with <module>_VERSION and to select the highest
# available build number, unless a build no. is specified. This is determined with the
# shell script build_number.sh included with require.
define ADD_INCLUDES_TEMPLATE
INSTALL_INCLUDES += $$(patsubst %,-I${2}/${1}/%/include,$${${1}_VERSION})
$(foreach m,$(filter-out $(PRJ),$(notdir $(wildcard ${E3_SITEMODS_PATH}/*))),$(eval $(call ADD_INCLUDES_TEMPLATE,$m,$(E3_SITEMODS_PATH))))
Simon Rose's avatar
Simon Rose committed
$(foreach m,$(filter-out $(PRJ),$(notdir $(wildcard ${EPICS_MODULES}/*)))   ,$(eval $(call ADD_INCLUDES_TEMPLATE,$m,$(EPICS_MODULES))))
zimoch's avatar
zimoch committed
BASERULES=${EPICS_BASE}/configure/RULES
zimoch's avatar
zimoch committed

INSTALL_REV     = ${MODULE_LOCATION}
Dirk Zimoch's avatar
Dirk Zimoch committed
INSTALL_BIN     = ${INSTALL_REV}/bin/$(T_A)
INSTALL_LIB     = ${INSTALL_REV}/lib/$(T_A)
Simon Rose's avatar
Simon Rose committed
INSTALL_VLIB    = ${INSTALL_REV}/lib/$(T_A)/vendor
Dirk Zimoch's avatar
Dirk Zimoch committed
INSTALL_INCLUDE = ${INSTALL_REV}/include
INSTALL_DBD     = ${INSTALL_REV}/dbd
INSTALL_DB      = ${INSTALL_REV}/db
INSTALL_CFG     = ${INSTALL_REV}/cfg
INSTALL_DOC     = ${MODULE_LOCATION}/doc
INSTALL_SCR     = ${INSTALL_REV}
LIBRARY_OBJS = $(strip ${LIBOBJS} $(foreach l,${USR_LIBOBJS},$(addprefix ../,$(filter-out /%,$l))$(filter /%,$l)))

MODULELIB = $(if ${LIBRARY_OBJS},${LIB_PREFIX}${PRJ}${SHRLIB_SUFFIX},)
zimoch's avatar
zimoch committed

LIBOBJS += $(addsuffix $(OBJ),$(notdir $(basename $(filter-out %.$(OBJ) %$(LIB_SUFFIX),$(sort ${SRCS})))))
LIBOBJS += $(filter /%.$(OBJ) /%$(LIB_SUFFIX),${SRCS})
Dirk Zimoch's avatar
Dirk Zimoch committed
LIBOBJS += ${LIBRARIES:%=${INSTALL_LIB}/%Lib}
zimoch's avatar
zimoch committed
LIBS = -L ${EPICS_BASE_LIB} ${BASELIBS:%=-l%}
LINK.cpp += ${LIBS}
PRODUCT_OBJS = ${LIBRARY_OBJS}
zimoch's avatar
zimoch committed

# Linux
LOADABLE_LIBRARY=$(if ${LIBRARY_OBJS},${PRJ},)
zimoch's avatar
zimoch committed

# Handle registry stuff automagically if we have a dbd file.
# See ${REGISTRYFILE} rule below.
LIBOBJS += $(if $(MODULEDBD), $(addsuffix $(OBJ),$(basename ${REGISTRYFILE})))
zimoch's avatar
zimoch committed

# Create and include dependency files.
HDEPENDS =
Dirk Zimoch's avatar
Dirk Zimoch committed
HDEPENDS_METHOD = COMP
HDEPENDS_COMPFLAGS = -c
MKMF = DO_NOT_USE_MKMF
zimoch's avatar
zimoch committed
-include *.d

# Need to find source dbd files relative to one dir up but generated dbd files in this dir.
DBD_PATH = $(sort $(dir ${DBDFILES}))
zimoch's avatar
zimoch committed

DBDEXPANDPATH = $(addprefix -I , ${DBD_PATH} ${EPICS_BASE}/dbd)
zimoch's avatar
zimoch committed
USR_DBDFLAGS += $(DBDEXPANDPATH)

# Search all directories where sources or headers come from, plus existing os dependend subdirectories.
Dirk Zimoch's avatar
Dirk Zimoch committed
SRC_INCLUDES = $(addprefix -I, $(wildcard $(foreach d,$(call uniq, $(filter-out /%,$(dir ${SRCS:%=../%} ${HDRS:%=../%}))), $d $(addprefix $d/, os/${OS_CLASS} $(POSIX_$(POSIX)) os/default))))
# Look for includes from standard locations relative to vendor libraries
USR_INCLUDES += $(addprefix -I,$(wildcard $(patsubst %/lib/$(T_A)/,../%/include,$(call uniq,$(dir $(VLIBS))) $(patsubst %/lib/,../%/include,$(call uniq,$(dir $(VLIBS)))))))

Dirk Zimoch's avatar
Dirk Zimoch committed
DBDFILES += $(patsubst %.st,%_snl.dbd,$(notdir $(filter %.st,${SRCS})))
DBDFILES += $(patsubst %.stt,%_snl.dbd,$(notdir $(filter %.stt,${SRCS})))
DBDFILES += $(patsubst %.gt,%.dbd,$(notdir $(filter %.gt,${SRCS})))

Wayne Lewis's avatar
Wayne Lewis committed
# snc location
SNCALL=$(shell ls  -dv $(E3_SITEMODS_PATH)/sequencer/$(sequencer_VERSION)/bin/$(EPICS_HOST_ARCH) 2> /dev/null))
SNC=$(lastword $(SNCALL))/snc
ifneq (,$(strip $(VLIBS)))
USR_LDFLAGS_$(T_A) += $(foreach l,$(VLIBS),-L../$(dir $(l)))
USR_LDFLAGS_$(T_A) += -Wl,-rpath,"\$$ORIGIN/vendor"
endif
zimoch's avatar
zimoch committed

ifneq ($(strip ${DBDFILES}),)
MODULEDBD=${PRJ}.dbd
endif

# If we build a library, provide a version variable.
ifneq ($(MODULELIB),)
LIBOBJS += $(addsuffix $(OBJ),$(basename ${VERSIONFILE}))
endif # MODULELIB

Simon Rose's avatar
Simon Rose committed
	@echo "===================== Pass 3: Build directory ====================="
	@echo "BUILDCLASSES = ${BUILDCLASSES}"
	@echo "OS_CLASS = ${OS_CLASS}"
	@echo "MODULEDBD = ${MODULEDBD}"
	@echo "RECORDS = ${RECORDS}"
	@echo "MENUS = ${MENUS}"
	@echo "BPTS = ${BPTS}"
	@echo "DBDINSTALLS = ${DBDINSTALLS}"
	@echo "SOURCES = ${SOURCES}"
	@echo "SOURCES_${OS_CLASS} = ${SOURCES_${OS_CLASS}}"
	@echo "SRCS = ${SRCS}"
	@echo "REQ = ${REQ}"
	@echo "LIBOBJS = ${LIBOBJS}"
	@echo "DBDS = ${DBDS}"
	@echo "DBDS_${OS_CLASS} = ${DBDS_${OS_CLASS}}"
	@echo "DBD_SRCS = ${DBD_SRCS}"
	@echo "DBDFILES = ${DBDFILES}"
	@echo "TEMPLS = ${TEMPLS}"
	@echo "LIBVERSION = ${LIBVERSION}"
	@echo "MODULE_LOCATION = ${MODULE_LOCATION}"

build: MODULEINFOS
build: ${MODULEDBD}
build: $(addprefix ${COMMON_DIR}/,$(addsuffix Record.h,${RECORDS}))
build: ${DEPFILE}
# Include default EPICS Makefiles (version dependent).
# Avoid library installation when doing 'make build'.
Dirk Zimoch's avatar
Dirk Zimoch committed
INSTALL_LOADABLE_SHRLIBS=

# We ony want to include ${BASERULES} from EPICS base if we are /not/ in debug
# mode. Including this causes all of the source files to be compiled!
ifeq (,$(findstring debug,${MAKECMDGOALS}))
include ${BASERULES}
Dirk Zimoch's avatar
Dirk Zimoch committed
RELEASE_DBDFLAGS = -I ${EPICS_BASE}/dbd
RELEASE_INCLUDES = -I${EPICS_BASE}/include
# For EPICS 3.15+:
Dirk Zimoch's avatar
Dirk Zimoch committed
RELEASE_INCLUDES += -I${EPICS_BASE}/include/compiler/${CMPLR_CLASS}
RELEASE_INCLUDES += -I${EPICS_BASE}/include/os/${OS_CLASS}

# Find all sources and set vpath accordingly.
$(foreach file, ${SRCS} ${TEMPLS} ${DBDINSTALLS} ${SCR}, $(eval vpath $(notdir ${file}) ../$(dir ${file})))
$(foreach file,${VLIBS},$(eval vpath $(notdir ${file}) ../$(dir ${file})))
# Do not treat %.dbd the same way because it creates a circular dependency
# if a source dbd has the same name as the project dbd. Have to clear %.dbd and not use ../ path.
# But the %Record.h and menu%.h rules need to find their dbd files (example: asyn).
vpath %.dbd
vpath %Record.dbd ${DBD_PATH}
vpath menu%.dbd ${DBD_PATH}
vpath %.h $(addprefix ../,$(sort $(dir $(filter-out /%,${HDRS}) ${SRCS}))) $(sort $(dir $(filter /%,${HDRS})))
vpath %.hpp $(addprefix ../,$(sort $(dir $(filter-out /%,${HDRS}) ${SRCS}))) $(sort $(dir $(filter /%,${HDRS})))
vpath %.hh $(addprefix ../,$(sort $(dir $(filter-out /%,${HDRS}) ${SRCS}))) $(sort $(dir $(filter /%,${HDRS})))
vpath %.hxx $(addprefix ../,$(sort $(dir $(filter-out /%,${HDRS}) ${SRCS}))) $(sort $(dir $(filter /%,${HDRS})))

PRODUCTS = ${MODULELIB} ${MODULEDBD} ${DEPFILE} ${METAFILE}
MODULEINFOS:
	@echo ${PRJ} > MODULENAME
Dirk Zimoch's avatar
Dirk Zimoch committed
	@echo ${PRODUCTS} > PRODUCTS
	@echo ${LIBVERSION} > LIBVERSION
zimoch's avatar
zimoch committed

# Build one module dbd file by expanding all source dbd files.
zimoch's avatar
zimoch committed
# We can't use dbExpand (from the default EPICS make rules)
# because it has too strict checks to be used for a loadable module.
${MODULEDBD}: ${DBDFILES}
zimoch's avatar
zimoch committed
	@echo "Expanding $@"
	${MAKEHOME}expandDBD.tcl -$(basename ${EPICSVERSION}) ${DBDEXPANDPATH} $^ > $@
zimoch's avatar
zimoch committed

INSTALL_LIBS = ${MODULELIB:%=${INSTALL_LIB}/%}
INSTALL_VLIBS = $(addprefix ${INSTALL_VLIB}/,$(notdir ${VLIBS}))
Dirk Zimoch's avatar
Dirk Zimoch committed
INSTALL_DEPS = ${DEPFILE:%=${INSTALL_LIB}/%}
INSTALL_META = ${METAFILE:%=${INSTALL_REV}/%}
INSTALL_DBDS = ${MODULEDBD:%=${INSTALL_DBD}/%}
INSTALL_DBDS += $(addprefix $(INSTALL_DBD)/,$(notdir ${DBDINSTALLS}))
ifneq ($(strip $(HDR_SUBDIRS)),)
  INSTALL_HDRS = $(addprefix ${INSTALL_INCLUDE}/,$(notdir $(filter-out $(addsuffix /%,$(HDR_SUBDIRS)),${HDRS})))
else
  INSTALL_HDRS = $(addprefix ${INSTALL_INCLUDE}/,$(notdir ${HDRS}))
endif
Dirk Zimoch's avatar
Dirk Zimoch committed
INSTALL_DBS  = $(addprefix ${INSTALL_DB}/,$(notdir ${TEMPLS}))
INSTALL_SCRS = $(addprefix ${INSTALL_SCR}/,$(notdir ${SCR}))
INSTALL_BINS = $(addprefix ${INSTALL_BIN}/,$(notdir ${BINS}))
INSTALL_CFGS = $(CFG:%=${INSTALL_CFG}/%)
zimoch's avatar
zimoch committed

debug::
	@echo "INSTALL_LIB = $(INSTALL_LIB)"
	@echo "INSTALL_LIBS = $(INSTALL_LIBS)"
	@echo "INSTALL_VLIBS = $(INSTALL_VLIBS)"
	@echo "INSTALL_DEPS = $(INSTALL_DEPS)"
	@echo "INSTALL_META = $(INSTALL_META)"
	@echo "INSTALL_DBD = $(INSTALL_DBD)"
	@echo "INSTALL_DBDS = $(INSTALL_DBDS)"
	@echo "INSTALL_INCLUDE = $(INSTALL_INCLUDE)"
	@echo "INSTALL_HDRS = $(INSTALL_HDRS)"
	@echo "INSTALL_DB = $(INSTALL_DB)"
	@echo "INSTALL_DBS = $(INSTALL_DBS)"
	@echo "INSTALL_SCR = $(INSTALL_SCR)"
	@echo "INSTALL_SCRS = $(INSTALL_SCRS)"
	@echo "INSTALL_CFG = $(INSTALL_CFG)"
	@echo "INSTALL_CFGS = $(INSTALL_CFGS)"
	@echo "INSTALL_BIN = $(INSTALL_BIN)"
	@echo "INSTALL_BINS = $(INSTALL_BINS)"
	@echo "HDR_SUBDIRS = $(HDR_SUBDIRS)"
define install_subdirs
$1_HDRS = $$(filter $1/%,$$(HDRS))
INSTALL_HDRS += $$(addprefix $$(INSTALL_INCLUDE)/,$$($1_HDRS:$1/%=%))
vpath %.h ../$1
vpath %.hpp ../$1
vpath %.hh ../$1
vpath %.hxx ../$1
debug::
	@echo "$1_HDRS = $$($1_HDRS)"
endef
$(foreach d,$(HDR_SUBDIRS),$(eval $(call install_subdirs,$d)))

INSTALLS += ${INSTALL_CFGS} ${INSTALL_SCRS} ${INSTALL_HDRS} ${INSTALL_DBDS} ${INSTALL_DBS} ${INSTALL_LIBS} ${INSTALL_VLIBS} ${INSTALL_BINS} ${INSTALL_DEPS} ${INSTALL_META}
zimoch's avatar
zimoch committed

zimoch's avatar
zimoch committed

Dirk Zimoch's avatar
Dirk Zimoch committed
${INSTALL_DBDS}: $(notdir ${INSTALL_DBDS})
	@echo "Installing module dbd file(s) $^ to $(@D)"
	$(INSTALL) -d -m$(INSTALL_PERMISSIONS) $^ $(@D)
zimoch's avatar
zimoch committed

Dirk Zimoch's avatar
Dirk Zimoch committed
${INSTALL_LIBS}: $(notdir ${INSTALL_LIBS})
	@echo "Installing module library $@"
	$(INSTALL) -d -m$(SHRLIB_PERMISSIONS) $< $(@D)

${INSTALL_VLIBS}: $(notdir ${INSTALL_VLIBS})
	@echo "Installing vendor library $^ to $(@D)"
	$(INSTALL) -d -m$(SHRLIB_PERMISSIONS) $^ $(@D)
zimoch's avatar
zimoch committed

Dirk Zimoch's avatar
Dirk Zimoch committed
${INSTALL_DEPS}: $(notdir ${INSTALL_DEPS})
	@echo "Installing module dependency file $@"
	$(INSTALL) -d -m$(INSTALL_PERMISSIONS) $< $(@D)
zimoch's avatar
zimoch committed

${INSTALL_META}: $(notdir ${INSTALL_META})
	@echo "Installing metadata file $@"
	$(INSTALL) -d -m$(INSTALL_PERMISSIONS) $< $(@D)
Dirk Zimoch's avatar
Dirk Zimoch committed
${INSTALL_DBS}: $(notdir ${INSTALL_DBS})
	@echo "Installing module template files $^ to $(@D)"
	$(INSTALL) -d -m$(INSTALL_PERMISSIONS) $^ $(@D)
zimoch's avatar
zimoch committed

	@echo "Installing scripts $^ to $(@D)"
	$(INSTALL) -d -m$(BIN_PERMISSIONS) $^ $(@D)
${INSTALL_CFGS}: ${CFGS}
	@echo "Installing configuration files $^ to $(@D)"
	$(INSTALL) -d -m$(INSTALL_PERMISSIONS) $^ $(@D)
${INSTALL_BINS}: $(addprefix ../,$(filter-out /%,${BINS})) $(filter /%,${BINS})
	@echo "Installing binaries $^ to $(@D)"
	$(INSTALL) -d -m$(BIN_PERMISSIONS) $^ $(@D)
# Create SNL code from st/stt file.
zimoch's avatar
zimoch committed
# Important to have %.o: %.st and %.o: %.stt rule before %.o: %.c rule!
# Preprocess in any case because docu and implemented EPICS rules mismatch here.
zimoch's avatar
zimoch committed

CPPSNCFLAGS1  = $(filter -D%, ${OP_SYS_CFLAGS})
CPPSNCFLAGS1 += $(filter-out ${OP_SYS_INCLUDE_CPPFLAGS} ,${CPPFLAGS}) ${CPPSNCFLAGS}
Dirk Zimoch's avatar
Dirk Zimoch committed
CPPSNCFLAGS1 += -I $(dir $(SNC))../../include
zimoch's avatar
zimoch committed
SNCFLAGS += -r

# 1) ESS uses 7.0.3.1 as the minimal EPICS BASE, so we don't need to check 3.13,
# 2) We also need -c option in $(COMPILE.c) in order to compile generated source file properly
# 3) SNC (2.1.21) should use -o, because without them, snc returns $(*F).i.c instead of $(*F).c
#    With the EPICS standard building rule, -o and mv are used.
# Tuesday, November 28 15:59:37 CET 2017, Jeong Han Lee

zimoch's avatar
zimoch committed
%$(OBJ) %_snl.dbd: %.st
	@echo ""
	@echo ">> SNC building process .... "
	@echo ">> SNC                  : $(SNC)"
	@echo ">> SNC_VERSION          : $(sequencer_VERSION)"
	@echo ">> Preprocessing $(<F)"
zimoch's avatar
zimoch committed
	$(RM) $(*F).i
	$(CPP) ${CPPSNCFLAGS1} $< > $(*F).i
	@echo ">> Converting $(*F).i to $(*F).c"
zimoch's avatar
zimoch committed
	$(RM) $@
	@echo ">> SNC is defined as $(SNC)"
	$(SNC) $(TARGET_SNCFLAGS) $(SNCFLAGS) $(*F).i -o $(*F).c.tmp
	@mv $(*F).c.tmp $(*F).c
	@echo ">> Compiling $(*F).c"
zimoch's avatar
zimoch committed
	$(RM) $@
	$(COMPILE.c) -c ${SNC_CFLAGS} $(*F).c
	@echo ">> Building $(*F)_snl.dbd"
	awk -F [\(\)]  '/epicsExportRegistrar/ { print "registrar (" $$2 ")"}' $(*F).c > $(*F)_snl.dbd
zimoch's avatar
zimoch committed

zimoch's avatar
zimoch committed
%$(OBJ) %_snl.dbd: %.stt
	@echo ""
	@echo ">> SNC building process .... "
	@echo ">> SNC                  : $(SNC)"
	@echo ">> SNC_VERSION          : $(sequencer_VERSION)"
	@echo ">> Preprocessing $(<F)"
zimoch's avatar
zimoch committed
	$(RM) $(*F).i
	$(CPP) ${CPPSNCFLAGS1} $< > $(*F).i
	@echo ">> Converting $(*F).i to $(*F).c"
zimoch's avatar
zimoch committed
	$(RM) $@
	@echo ">> SNC is defined as $(SNC)"
	$(SNC) $(TARGET_SNCFLAGS) $(SNCFLAGS) $(*F).i -o $(*F).c.tmp
	@mv $(*F).c.tmp $(*F).c
	@echo ">> Compiling $(*F).c"
zimoch's avatar
zimoch committed
	$(RM) $@
	$(COMPILE.c) -c ${SNC_CFLAGS} $(*F).c
zimoch's avatar
zimoch committed
	@echo "Building $(*F)_snl.dbd"
	awk -F [\(\)]  '/epicsExportRegistrar/ { print "registrar(" $$2 ")"}' $(*F).c > $(*F)_snl.dbd
zimoch's avatar
zimoch committed

zimoch's avatar
zimoch committed
%.c %.dbd %.list: %.gt
	@echo "Converting $*.gt"
	${LN} $< $(*F).gt
	gdc $(*F).gt

${VERSIONFILE}:
	echo "char _${PRJ}LibRelease[] = \"${LIBVERSION}\";" >> $@

# Create file to fill registry from dbd file.
${REGISTRYFILE}: ${MODULEDBD}
	$(PERL) $(EPICS_BASE_HOST_BIN)/registerRecordDeviceDriver.pl $< $(basename $@) | grep -v 'iocshRegisterCommon();' > $@
zimoch's avatar
zimoch committed

${METAFILE}:
	@echo "wrapper_url: '$(${PRJ}_E3_GIT_URL)'" > $@
	@echo "wrapper_git_desc: '$(${PRJ}_E3_GIT_DESC)'" >> $@
	@echo "wrapper_diffs: $(${PRJ}_E3_GIT_STATUS)" >> $@
	@echo "module_git_desc: '$(${PRJ}_GIT_DESC)'" >> $@
	@echo "module_diffs: $(${PRJ}_GIT_STATUS)" >> $@

define DEP_PARSER
s%$(E3_SITEMODS_PATH)/*\([^/]*\)/\([^/]*\)/.*%\1 \2%p; \
s%$(EPICS_MODULES)/*\([^/]*\)/\([^/]*\)/.*%\1 \2%p
endef

# Create dependency file for recursive requires.
Simon Rose's avatar
Simon Rose committed
.PHONY: ${DEPFILE}
${DEPFILE}: ${LIBOBJS} $(USERMAKEFILE)
zimoch's avatar
zimoch committed
	@echo "Collecting dependencies"
Simon Rose's avatar
Simon Rose committed
	$(RM) $@.tmp
	@echo "# Generated file. Do not edit." > $@
# Check dependencies on other module headers.
	cat *.d 2>/dev/null | sed 's/ /\n/g' | grep -v '$(EPICS_BASE)/include' | sed -n '$(DEP_PARSER)' > $@.tmp
# Manully added dependencies: ${REQ}
	@$(foreach m,${REQ},echo "$m $($m_VERSION)" >> $@.tmp;)
	cat $@.tmp | sort -u >> $@
zimoch's avatar
zimoch committed

zimoch's avatar
zimoch committed
endif # T_A defined