# Determine properties of the system and write a config.h.
#
# 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.

# The configuration header file.

CONFIG_H = $(objdir)/config.h
CONFIG_MK = $(objdir)/config.mk

# Emit a help rule for an override.
#
# Syntax: $(call make-override-help,var,help-string)
define make-override-help
help-overrides::
	width=$$$$(printf '$(1)=[yes/no]' | wc -c); \
	tabs="\t\t\t\t"; \
	if [[ $$$${width} -gt 31 ]]; then \
	    tabs=' '; \
	elif [[ $$$${width} -gt 23 ]]; then \
	    tabs='\t'; \
	elif [[ $$$${width} -gt 15 ]]; then \
	    tabs='\t\t'; \
	elif [[ $$$${width} -gt 7 ]]; then \
	    tabs='\t\t\t'; \
	fi; \
	printf "$(1)=[yes/no]$$$${tabs}Override check for%s\n" \
	       "$$$$(printf "%s" "$(2)" | sed 's,(.*),,g')" >&2
endef

# Emit a help rule for an override's config option.
#
# Syntax: $(call make-overrride-option-help,var,help-string)
define make-override-option-help
help-overrides-option::
	width=$$$$(printf -- '--with-$(1)=[yes/no]' | wc -c); \
	tabs=""; \
	if [[ $$$${width} -gt 31 ]]; then \
	    tabs=' '; \
	elif [[ $$$${width} -gt 23 ]]; then \
	    tabs='\t'; \
	elif [[ $$$${width} -gt 15 ]]; then \
	    tabs='\t\t'; \
	fi; \
	printf -- "--with-%s=[yes/no]$$$${tabs}Override check for$(2)\n" "$$$$(printf -- '$(1)' | LC_COLLATE=C tr '[A-Z_]' '[a-z-]')" >&2
endef

# Generate a makefile rule to check for the presence of FUNCTION
# in HEADER and emit an appropriate header file fragment into a
# file under $(objdir)/.config.
#
# The first argument must be suitable for a filename fragment,
# for a makefile rule name and for a #define.
#
# Syntax: $(call check-header-rule,name,function,header)
define check-header-rule
$(objdir)/.config/config.$(1).h $(objdir)/.config/config.$(1).mk: $(objdir)/.config/.dir.stamp
	val="$(HAVE_$(1))"; \
	if [[ x$(HAVE_$(1)) = x ]]; then \
	    if printf '#include <%s.h>\nint main(void) { %s; }' "$(3)" "$(2)" | \
	       $(CC) $(filter-out --coverage,$(CFLAGS) $(LDFLAGS)) -Iinclude -D_GNU_SOURCE -Werror=implicit-function-declaration -c -o /dev/null -x c - >/dev/null 2>&1; then \
	       val=yes; \
	   else \
	       val=no; \
	   fi; \
	fi; \
	case $$$$val in \
	yes) echo '#define HAVE_$(1) 1' > $(objdir)/.config/config.$(1).h; \
	     echo 'HAVE_$(1)=y' > $(objdir)/.config/config.$(1).mk;; \
	no) echo '/* #undef HAVE_$(1) */' > $(objdir)/.config/config.$(1).h; \
	    echo '# HAVE_$(1) undefined' > $(objdir)/.config/config.$(1).mk;; \
	*) echo "HAVE_$(1) must be yes or no, not $(HAVE_$(1))" >&2; \
	   false;; \
	esac
	rm -f $(CONFIG_H)
	rm -f $(CONFIG_MK)

$(eval $(call make-override-help,HAVE_$(1), presence of $(2) in $(3).h))

$(CONFIG_H): $(objdir)/.config/config.$(1).h
$(CONFIG_MK): $(objdir)/.config/config.$(1).mk
endef

# Generate a makefile rule to check for the presence of SYMBOL
# in LIBRARY and emit an appropriate header file fragment into
# a file under $(objdir)/.config.
#
# The first argument must be suitable for a filename fragment,
# for a makefile rule name and for a #define.
#
# Also emit a rule to print help for this override to standard
# error, and (if OPTION) is set, a rule to print help for
# this override in standard configure --with-* form.  (This is
# used for options relating to things for which we do not have
# compatibility fallbacks, for which configure-style --with-*
# options seem particularly desirable.)
#
# Syntax: $(call check-symbol-rule,name,symbol,library,option)
define check-symbol-rule
$(objdir)/.config/config.$(1).h $(objdir)/.config/config.$(1).mk: $(objdir)/.config/.dir.stamp
	val="$(HAVE_$(1))"; \
	if [[ x$(HAVE_$(1)) = x ]]; then \
	    if echo 'void $(2)(); int main(void) { $(2)(); }' | \
	       $(CC) $(filter-out --coverage,$(CFLAGS) $(LDFLAGS)) -Iinclude -o /dev/null -x c - -l$(3) >/dev/null 2>&1; then \
	       val=yes; \
	   else \
	       val=no; \
	   fi; \
	fi; \
	case $$$$val in \
	yes) echo '#define HAVE_$(1) 1' > $(objdir)/.config/config.$(1).h; \
	     echo 'HAVE_$(1)=y' > $(objdir)/.config/config.$(1).mk;; \
	no) echo '/* #undef HAVE_$(1) */' > $(objdir)/.config/config.$(1).h; \
	    echo '# HAVE_$(1) undefined' > $(objdir)/.config/config.$(1).mk;; \
	*) echo "HAVE_$(1) must be yes or no, not $(HAVE_$(1))" >&2; \
	   false;; \
	esac
	rm -f $(CONFIG_H)
	rm -f $(CONFIG_MK)

$(eval $(call make-override-help,HAVE_$(1), presence of $(2) in lib$(3)))
$(if $(4),
  $(eval $(call make-override-option-help,$(1), presence of $(2) in $(3).h)),)

$(CONFIG_H): $(objdir)/.config/config.$(1).h
$(CONFIG_MK): $(objdir)/.config/config.$(1).mk
endef

# Generate a makefile rule to check for the presence of SYMBOL
# in HEADER and LIBRARY and emit an appropriate header file
# fragment into a file under $(objdir)/.config.
#
# The first argument must be suitable for a filename fragment,
# for a makefile rule name and for a #define.
#
# Syntax: $(call check-header-symbol-rule,name,symbol,library,header)
define check-header-symbol-rule
$(objdir)/.config/config.$(1).h $(objdir)/.config/config.$(1).mk: $(objdir)/.config/.dir.stamp
	case x$(HAVE_$(1)) in \
	xyes) echo '#define HAVE_$(1) 1' > $(objdir)/.config/config.$(1).h; \
	     echo 'HAVE_$(1)=y' > $(objdir)/.config/config.$(1).mk;; \
	xno) echo '/* #undef HAVE_$(1) */' > $(objdir)/.config/config.$(1).h; \
	     echo '# HAVE_$(1) undefined' > $(objdir)/.config/config.$(1).mk;; \
	*) if printf '#include <%s.h>\nint main(void) { %s; }' "$(4)" "$(2)" | \
	       $(CC) $(filter-out --coverage,$(CFLAGS) $(LDFLAGS)) -Iinclude -D_GNU_SOURCE -Werror=implicit-function-declaration -o /dev/null -x c - -l$(3) >/dev/null 2>&1; then \
	       echo '#define HAVE_$(1) 1' > $(objdir)/.config/config.$(1).h; \
	       echo 'HAVE_$(1)=y' > $(objdir)/.config/config.$(1).mk; \
	   else \
	       echo '/* #undef HAVE_$(1) */' > $(objdir)/.config/config.$(1).h; \
	       echo '# HAVE_$(1) undefined' > $(objdir)/.config/config.$(1).mk; \
	   fi;; \
	*) echo "HAVE_$(1) must be yes or no, not $(HAVE_$(1))" >&2; \
	   false;; \
	esac
	rm -f $(CONFIG_H)
	rm -f $(CONFIG_MK)

$(eval $(call make-override-help,HAVE_$(1), presence of $(2) in lib$(3) and $(4).h))

$(CONFIG_H): $(objdir)/.config/config.$(1).h
$(CONFIG_MK): $(objdir)/.config/config.$(1).mk
endef

# Generate a makefile rule to check for the presence of MACRO
# in HEADER and emit an appropriate header file fragment into a file
# under $(objdir)/.config.
#
# The first argument must be suitable for a filename fragment,
# for a makefile rule name and for a #define.
#
# Syntax: $(call check-header-macro-rule,name,macro,header)
define check-header-macro-rule
$(objdir)/.config/config.$(1).h $(objdir)/.config/config.$(1).mk: $(objdir)/.config/.dir.stamp
	case x$(HAVE_$(1)) in \
	xyes) echo '#define HAVE_$(1) 1' > $(objdir)/.config/config.$(1).h; \
	     echo 'HAVE_$(1)=y' > $(objdir)/.config/config.$(1).mk;; \
	xno) echo '/* #undef HAVE_$(1) */' > $(objdir)/.config/config.$(1).h; \
	     echo '# HAVE_$(1) undefined' > $(objdir)/.config/config.$(1).mk;; \
	*) if printf '#include <%s.h>\n#ifndef %s\n#error %s not found.\n#endif' "$(3)" "$(2)" "$(2)" | \
	       $(CC) $(filter-out --coverage,$(CFLAGS) $(LDFLAGS)) -Iinclude -D_GNU_SOURCE -Werror=implicit-function-declaration -c -o /dev/null -x c - >/dev/null 2>&1; then \
	       echo '#define HAVE_$(1) 1' > $(objdir)/.config/config.$(1).h; \
	       echo 'HAVE_$(1)=y' > $(objdir)/.config/config.$(1).mk; \
	   else \
	       echo '/* #undef HAVE_$(1) */' > $(objdir)/.config/config.$(1).h; \
	       echo '# HAVE_$(1) undefined' > $(objdir)/.config/config.$(1).mk; \
	   fi;; \
	*) echo "HAVE_$(1) must be yes or no, not $(HAVE_$(1))" >&2; \
	   false;; \
	esac
	rm -f $(CONFIG_H)
	rm -f $(CONFIG_MK)

$(eval $(call make-override-help,HAVE_$(1), presence of preprocessor macro $(2) in $(3).h))

$(CONFIG_H): $(objdir)/.config/config.$(1).h
$(CONFIG_MK): $(objdir)/.config/config.$(1).mk
endef

# Generate a makefile rule to check for support for OPTION in BPFC and emit an
# appropriate header file fragment into a file under $(objdir)/.config.
#
# The first argument must be suitable for a filename fragment, for a makefile
# rule name and for a #define.
#
# Syntax: $(call check-bpfc-option-rule,name,option)
define check-bpfc-option-rule
$(objdir)/.config/config.$(1).h $(objdir)/.config/config.$(1).mk: $(objdir)/.config/.dir.stamp
	case x$(HAVE_$(1)) in \
	xyes) echo '#define HAVE_$(1) 1' > $(objdir)/.config/config.$(1).h; \
	     echo 'HAVE_$(1)=y' > $(objdir)/.config/config.$(1).mk;; \
	xno) echo '/* #undef HAVE_$(1) */' > $(objdir)/.config/config.$(1).h; \
	     echo '# HAVE_$(1) undefined' > $(objdir)/.config/config.$(1).mk;; \
	*) if $(BPFC) --help $(2) 2>&1 >/dev/null | grep -q error; then \
	       echo '/* #undef HAVE_$(1) */' > $(objdir)/.config/config.$(1).h; \
	       echo '# HAVE_$(1) undefined' > $(objdir)/.config/config.$(1).mk; \
	   else \
	       echo '#define HAVE_$(1) 1' > $(objdir)/.config/config.$(1).h; \
	       echo 'HAVE_$(1)=y' > $(objdir)/.config/config.$(1).mk; \
	   fi;; \
	*) echo "HAVE_$(1) must be yes or no, not $(HAVE_$(1))" >&2; \
	   false;; \
	esac
	rm -f $(CONFIG_H)
	rm -f $(CONFIG_MK)

$(eval $(call make-override-help,HAVE_$(1), presence of option $(2) in $(BPFC)))

$(CONFIG_H): $(objdir)/.config/config.$(1).h
$(CONFIG_MK): $(objdir)/.config/config.$(1).mk
endef

$(objdir)/.config/.dir.stamp:
	if [[ ! -f $(objdir)/.config/.dir.stamp ]]; then \
	    mkdir -p $(objdir)/.config; \
	    touch $(objdir)/.config/.dir.stamp; \
	fi

$(CONFIG_H):
	echo '/* This file is automatically generated. */' > $(objdir)/config.h
	cat $(objdir)/.config/*.h >> $(objdir)/config.h 2>/dev/null || true

$(CONFIG_MK):
	echo '# This file is automatically generated.' > $(objdir)/config.mk
	echo 'CONFIGURED := yes' >> $(objdir)/config.mk
	cat $(objdir)/.config/*.mk >> $(objdir)/config.mk 2>/dev/null || true

help-overrides-header::
	printf "Overrides for library and symbol searches:\n\n" >&2

$(eval $(call check-symbol-rule,ELF_GETSHDRSTRNDX,elf_getshdrstrndx,elf))
$(eval $(call check-symbol-rule,LIBCTF,ctf_open,ctf,t))
$(eval $(call check-symbol-rule,STRRSTR,strrstr,c))
$(eval $(call check-symbol-rule,PTHREAD_ATFORK,pthread_atfork,c))
ifndef WANTS_LIBFUSE2
$(eval $(call check-symbol-rule,FUSE_LOG,fuse_set_log_func,fuse3))
$(eval $(call check-symbol-rule,LIBFUSE3,fuse_session_receive_buf,fuse3,t))
endif
$(eval $(call check-header-rule,FUSE_NUMA,fuse_set_numa,fuse/fuse_lowlevel))
$(eval $(call check-header-symbol-rule,CLOSE_RANGE,close_range(3,~0U,0),c,unistd))
$(eval $(call check-header-rule,GETTID,gettid,unistd))
$(eval $(call check-header-rule,DIS1,disassembler(NULL),disasm))
$(eval $(call check-header-rule,DIS4,disassembler(0,0,0,NULL),disasm))
$(eval $(call check-header-rule,INITDISINFO3,init_disassemble_info(NULL,NULL,NULL),disasm))
$(eval $(call check-header-rule,INITDISINFO4,init_disassemble_info(NULL,NULL,NULL,NULL),disasm))
$(eval $(call check-header-macro-rule,VALGRIND,VALGRIND_NON_SIMD_CALL0,valgrind/valgrind))
$(eval $(call check-bpfc-option-rule,BPFV3,-mcpu=v3))
$(eval $(call check-bpfc-option-rule,BPFMASM,-masm=normal))

help-overrides::
	printf "\n" >&2

help:: help-overrides-header help-overrides
