# Functions used by the individual Build files.
#
# Oracle Linux DTrace.
# Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at
# http://oss.oracle.com/licenses/upl.

# A variable expanding to the directory of the currently included makefile
# fragment.

current-dir = $(dir $(lastword $(MAKEFILE_LIST)))

# Functions to generate the name of an object file and source file for a
# given primary.  If called with an absolute pathname, return it unchanged.
# Syntax: $(call *-name,primary,filename)

obj-name = $(addprefix $(objdir)/$(subst /,-,$($(1)_DIR))-,$(subst /,-,$(patsubst %.S,%.o,$(2:.c=.o))))
src-name = $(if $(filter-out $(abspath $(2)),$(2)),$(addprefix $($(1)_DIR),$(2)),$(2))

# Functions to generate the name of a header file and DOF object file for a
# given primary.  If called with an absolute pathname, return it unchanged.
# Syntax: $(call *-name,primary,filename)

hdr-name = $(addprefix $($(1)_DIR)/,$(subst /,-,$(2:.d=.h)))
dof-name = $(addprefix $(objdir)/$(subst /,-,$($(1)_DIR))-,$(subst /,-,$(2:.d=.o)))

# If 'verbose' is not set, this echoes a description and truncated target (or
# other identifier) for this rule.
# Syntax: $(call describe-target,description,optional names)
define describe-target
$(if $(filter-out $(verbose),no),,$(foreach name,$(2),printf '%s: %s\n' '$(1)' '$(name)';))
endef

# Describe an installation target. All paths on the 'names' are stripped.
# Syntax: $(call describe-install-target,directory,names)
define describe-install-target
$(call describe-target,INSTALL,$(addprefix $(1)/,$(notdir $(2))))
endef

# Like 'describe-target', but with shell expansion on the names.
# Syntax: $(call describe-expanded-target,description,optional names)
define describe-expanded-target
$(if $(filter-out $(verbose),no),,$(foreach name,$(2),printf '%s: %s\n' '$(1)' $(name);))
endef

# Like 'describe-install-target', but with shell expansion on the names.
# Syntax: $(call describe-install-target,directory,names)
define describe-expanded-install-target
$(call describe-expanded-target,INSTALL,$(addprefix $(1)/,$(notdir $(2))))
endef

# Rule to build a C source file.
# Syntax: $(call cc-template,primary,filename-without-dir,optional flags)

cc-dependencies = -MP -MMD -MF $(obj-name).deps -MT $(obj-name)

define cc-template
$(obj-name): $(src-name) $(foreach dep,$($(1)_SRCDEPS),$(call src-name,$(1),$(dep))) $(foreach prov,$($(1)_PROV),$(call hdr-name,$(1),$(prov))) $(CONFIG_H)
	$(call describe-target,CC,$(src-name))
	$(CC) $(CPPFLAGS) $($(1)_CPPFLAGS) $(filter-out $($(1)_NOCFLAGS) $($(2)_NOCFLAGS),$(CFLAGS) $($(1)_CFLAGS) $($(2)_CFLAGS) $(3)) $(cc-dependencies) -c -o $(obj-name) $(src-name)
endef

# Rule to build a BPF C source file.
# Syntax: $(call bpf-template,primary,filename-without-dir,optional flags)

define bpf-template
$(obj-name): $(src-name) $(foreach dep,$($(1)_SRCDEPS),$(call src-name,$(1),$(dep))) $(CONFIG_H)
	$(call describe-target,BPF-CC,$(src-name))
	$(BPFC) $(BPFCPPFLAGS) $($(1)_CPPFLAGS) $(filter-out $($(1)_NOCFLAGS) $($(2)_NOCFLAGS),$(BPFCFLAGS) $($(1)_CFLAGS) $($(2)_CFLAGS) $(3)) $(cc-dependencies) -c -o $(obj-name) $(src-name)
endef

# Rule to build a DTrace USDT header file.
# Syntax: $(call hdr-template,primary,filename-without-dir)

define hdr-template
$(hdr-name): $(src-name) $(objdir)/run-dtrace
	$(call describe-target,GENHDR,$(src-name))
	$(objdir)/run-dtrace -h -o $(hdr-name) -x nolibs -s $(src-name)
endef

# Rule to clean up a DTrace USDT header file.
# Syntax: $(call hdr-clean-template,primary,filename-without-dir)

define hdr-clean-template
clean::
	rm -f $(hdr-name)
endef

# Rule to build a DOF object file.
# Syntax: $(call dof-template,primary,filename-without-dir)

define dof-template
$(dof-name): $(src-name) $(objdir)/run-dtrace $(foreach source,$($(1)_SOURCES),$(call obj-name,$(1),$(source))) $(filter-out $(dof-name),$(foreach dep,$(filter %.o,$($(1)_DEPS)),$(call obj-name,$(1),$(dep)))) $(DRTI_OBJ)
	$(call describe-target,GENDOF,$(src-name))
	$(objdir)/run-dtrace -x nolibs -G -o $(dof-name) -s $(src-name) $(foreach source,$($(1)_SOURCES),$(call obj-name,$(1),$(source))) $(filter-out $(dof-name),$(foreach dep,$(filter %.o,$($(1)_DEPS)),$(call obj-name,$(1),$(dep))))
endef

# Rule to build a build library, and all its sources.
# Syntax: $(call build-lib-template,primary)

define build-lib-template
$(objdir)/build-$($(1)_TARGET).a: $(foreach source,$($(1)_SOURCES),$(call obj-name,$(1),$(source))) \
                                  $(foreach dep,$(filter-out %.o,$($(1)_DEPS)),$(addprefix $(objdir)/,$(dep))) \
                                  $(foreach dep,$(filter %.o,$($(1)_DEPS)),$(call obj-name,$(1),$(dep)))
	$(call describe-target,BUILD-AR,$($(1)_TARGET).a)
	$(AR) rc $(objdir)/build-$($(1)_TARGET).a $(foreach source,$($(1)_SOURCES),$(call obj-name,$(1),$(source)))
	$(foreach post,$($(1)_POST),$(call $(post),$(objdir)/build-$($(1)_TARGET).a))

$(foreach file,$(filter-out $($(1)_EXPLICIT),$($(1)_SOURCES)),$(eval $(call cc-template,$(1),$(file),-fPIC)))
endef

# Rule to build an installable static library from a set of build libraries.
# Syntax: $(call lib-template,primary)

define lib-template
$(objdir)/$($(1)_TARGET).a: $(foreach build-lib,$($(1)_LIBSOURCES),$(objdir)/build-$($(build-lib)_TARGET).a)
	$(call describe-target,AR,$($(1)_TARGET).a)
	$(AR) rc $(objdir)/$($(1)_TARGET).a $(foreach build-lib,$($(1)_LIBSOURCES),$(foreach source,$($(build-lib)_SOURCES),$(call obj-name,$(build-lib),$(source))))
	$(foreach post,$($(1)_POST),$(call $(post),$(objdir)/$($(1)_TARGET).a))
endef

# Rule to build an installable shared library from a set of build libraries.
# Syntax: $(call shlib-template,primary)

comma := ,
define shlib-template
$(objdir)/$($(1)_TARGET).so $(if $($(1)_VERSION),$(objdir)/$($(1)_TARGET).so.$($(1)_VERSION)) $(if $($(1)_SONAME),$(objdir)/$($(1)_SONAME)): \
                $(foreach build-lib,$($(1)_LIBSOURCES),$(objdir)/build-$($(build-lib)_TARGET).a) \
		$(call src-name,$(1),$($(1)_VERSCRIPT))
	$(call describe-target,SHLINK,$($(1)_TARGET).so)
	$(CC) -o $(objdir)/$($(1)_TARGET).so$(if $($(1)_VERSION),.$($(1)_VERSION)) \
	      -shared $(filter-out $($(1)_NOLDFLAGS),$(LDFLAGS) $($(1)_LDFLAGS)) $(if $($(1)_SONAME),-Wl$(comma)-soname$(comma)$($(1)_SONAME)) \
	      $(if $($(1)_VERSCRIPT),-Wl$(comma)--version-script=$(call src-name,$(1), $($(1)_VERSCRIPT))) \
	      -Wl,--whole-archive $(foreach primary,$(filter-out $($(1)_SECONDARY),$($(1)_LIBSOURCES)),$(objdir)/build-$($(primary)_TARGET).a) -Wl,--no-whole-archive \
	      $(foreach secondary,$($(1)_SECONDARY),$(objdir)/build-$($(secondary)_TARGET).a) -L$(objdir) $($(1)_LIBS)
	$(if $($(1)_VERSION),ln -sf $($(1)_TARGET).so.$($(1)_VERSION) $(objdir)/$($(1)_TARGET).so)
	$(if $($(1)_SONAME),ln -sf $($(1)_TARGET).so.$($(1)_VERSION) $(objdir)/$($(1)_SONAME))
	$(foreach post,$($(1)_POST),$(call $(post),$(objdir)/$($(1)_TARGET).so$(if $($(1)_VERSION),.$($(1)_VERSION))))
endef

# Rule to build a BPF library, and all its sources.
# Syntax: $(call bpflib-template,primary)

define bpflib-template
$(objdir)/$($(1)_TARGET).o: $(foreach source,$($(1)_SOURCES),$(call obj-name,$(1),$(source))) \
                                  $(foreach dep,$(filter-out %.o,$($(1)_DEPS)),$(addprefix $(objdir)/,$(dep))) \
                                  $(foreach dep,$(filter %.o,$($(1)_DEPS)),$(call obj-name,$(1),$(dep)))
	$(call describe-target,BPF-LD,$($(1)_TARGET).o)
	$(BPFLD) -o $(objdir)/$($(1)_TARGET).o -r $(foreach source,$($(1)_SOURCES),$(call obj-name,$(1),$(source)))
	$(foreach post,$($(1)_POST),$(call $(post),$(objdir)/build-$($(1)_TARGET).o))

$(foreach file,$(filter-out $($(1)_EXPLICIT),$($(1)_SOURCES)),$(eval $(call bpf-template,$(1),$(file))))
endef

# Rule to build a binary, and all its sources.
# Syntax: $(call cmd-template,primary)

define cmd-template
$(objdir)/$($(1)_TARGET): $(foreach prov,$($(1)_PROV),$(call hdr-name,$(1),$(prov))) \
			  $(foreach source,$($(1)_SOURCES),$(call obj-name,$(1),$(source))) \
                          $(foreach dep,$(filter-out %.o,$($(1)_DEPS)),$(addprefix $(objdir)/,$(dep))) \
                          $(foreach dep,$(filter %.o,$($(1)_DEPS)),$(call obj-name,$(1),$(dep))) \
                          $(foreach prov,$($(1)_PROV),$(call dof-name,$(1),$(prov)))
	$(call describe-target,LINK,$($(1)_TARGET))
	$(CC) $(filter-out $($(1)_NOCFLAGS),$(CFLAGS) $($(1)_CFLAGS)) \
	      $(filter-out $($(1)_NOLDFLAGS),$(LDFLAGS) $($(1)_LDFLAGS)) -o $(objdir)/$($(1)_TARGET) \
	      $(foreach source,$($(1)_SOURCES),$(call obj-name,$(1),$(source))) \
              $(foreach prov,$($(1)_PROV),$(call dof-name,$(1),$(prov))) \
	      -L$(objdir) $($(1)_LIBS)
	$(foreach post,$($(1)_POST),$(call $(post),$(objdir)/$($(1)_TARGET)))

$(foreach file,$(filter-out $($(1)_EXPLICIT),$($(1)_SOURCES)),$(eval $(call cc-template,$(1),$(file))))
$(foreach prov,$($(1)_PROV),$(call hdr-template,$(1),$(prov)))
$(foreach prov,$($(1)_PROV),$(call hdr-clean-template,$(1),$(prov)))
$(foreach prov,$($(1)_PROV),$(call dof-template,$(1),$(prov)))
endef
