summaryrefslogtreecommitdiffstats
path: root/tools/build
diff options
context:
space:
mode:
authorNiklas Cassel <cassel@kernel.org>2026-09-16 15:00:32 +0200
committerNiklas Cassel <cassel@kernel.org>2026-09-16 16:18:00 +0200
commit8d836581f9b1f57ceaa2b47654754ef1260b410b (patch)
tree1dbd4d0dfb99c2e238356cbe947e5b0be3e3a571 /tools/build
downloadlinux-stable-8d836581f9b1f57ceaa2b47654754ef1260b410b.tar.gz
linux-stable-8d836581f9b1f57ceaa2b47654754ef1260b410b.zip
ata: libata-scsi: fix ata_dsm_trim_pages() kernel-docgrafted
make htmldocs fails with: Documentation/driver-api/libata:604: ./drivers/ata/libata-scsi.c:2301: ERROR: Unexpected indentation. [docutils] The Return: section of ata_dsm_trim_pages() ends its first sentence with a colon and continues with an indented bullet list. reStructuredText requires a blank line before an indented block, so docutils chokes on the list. Simply adding the missing blank line does not work either: Return: is a kernel-doc "special section", which is terminated by the first blank line, so the bullet list would end up in the Description section, detached from the sentence introducing it. Spell the two bounds out as prose instead, so that the Return: section stays self-contained. Documentation-only change. Fixes: e64e6b5dc867 ("ata: libata-scsi: scale DSM TRIM payload by MAX PAGES PER DSM COMMAND") Reported-by: Thomas Huth <thuth@redhat.com> Closes: https://lore.kernel.org/linux-ide/b0a0b8e8-cc4f-4c7b-8bc5-fee0712d405a@redhat.com/ Reviewed-by: Damien Le Moal <dlemoal@kernel.org> Reviewed-by: Thomas Huth <thuth@redhat.com> Link: https://lore.kernel.org/r/20260916130031.29990-2-cassel@kernel.org Signed-off-by: Niklas Cassel <cassel@kernel.org>
Diffstat (limited to 'tools/build')
-rw-r--r--tools/build/.gitignore2
-rw-r--r--tools/build/Build2
-rw-r--r--tools/build/Build.include137
-rw-r--r--tools/build/Documentation/Build.txt168
-rw-r--r--tools/build/Makefile58
-rw-r--r--tools/build/Makefile.build181
-rw-r--r--tools/build/Makefile.feature334
-rw-r--r--tools/build/Makefile.include20
-rw-r--r--tools/build/feature/.gitignore4
-rw-r--r--tools/build/feature/Makefile397
-rw-r--r--tools/build/feature/test-all.c183
-rw-r--r--tools/build/feature/test-babeltrace2-ctf-writer.c9
-rw-r--r--tools/build/feature/test-backtrace.c14
-rw-r--r--tools/build/feature/test-bionic.c7
-rw-r--r--tools/build/feature/test-bpf.c50
-rw-r--r--tools/build/feature/test-clang-bpf-co-re.c9
-rw-r--r--tools/build/feature/test-compile.c7
-rw-r--r--tools/build/feature/test-cplus-demangle.c15
-rw-r--r--tools/build/feature/test-cxa-demangle.cpp17
-rw-r--r--tools/build/feature/test-disassembler-four-args.c15
-rw-r--r--tools/build/feature/test-disassembler-init-styled.c13
-rw-r--r--tools/build/feature/test-eventfd.c9
-rw-r--r--tools/build/feature/test-file-handle.c17
-rw-r--r--tools/build/feature/test-fortify-source.c7
-rw-r--r--tools/build/feature/test-gettid.c11
-rw-r--r--tools/build/feature/test-glibc.c20
-rw-r--r--tools/build/feature/test-gtk2-infobar.c12
-rw-r--r--tools/build/feature/test-gtk2.c11
-rw-r--r--tools/build/feature/test-hello.c7
-rw-r--r--tools/build/feature/test-jvmti-cmlr.c11
-rw-r--r--tools/build/feature/test-jvmti.c13
-rw-r--r--tools/build/feature/test-libaio.c16
-rw-r--r--tools/build/feature/test-libbfd-threadsafe.c18
-rw-r--r--tools/build/feature/test-libbfd.c16
-rw-r--r--tools/build/feature/test-libbpf.c11
-rw-r--r--tools/build/feature/test-libcap.c20
-rw-r--r--tools/build/feature/test-libcapstone.c11
-rw-r--r--tools/build/feature/test-libcheck.c8
-rw-r--r--tools/build/feature/test-libcpupower.c8
-rw-r--r--tools/build/feature/test-libdebuginfod.c8
-rw-r--r--tools/build/feature/test-libdw.c56
-rw-r--r--tools/build/feature/test-libelf-gelf_getnote.c8
-rw-r--r--tools/build/feature/test-libelf-getphdrnum.c9
-rw-r--r--tools/build/feature/test-libelf-getshdrstrndx.c9
-rw-r--r--tools/build/feature/test-libelf-zstd.c9
-rw-r--r--tools/build/feature/test-libelf.c9
-rw-r--r--tools/build/feature/test-libnuma.c10
-rw-r--r--tools/build/feature/test-libopencsd.c16
-rw-r--r--tools/build/feature/test-libopenssl.c7
-rw-r--r--tools/build/feature/test-libperl.c10
-rw-r--r--tools/build/feature/test-libpfm4.c9
-rw-r--r--tools/build/feature/test-libpython.c10
-rw-r--r--tools/build/feature/test-libslang.c7
-rw-r--r--tools/build/feature/test-libtraceevent.c12
-rw-r--r--tools/build/feature/test-libtracefs.c10
-rw-r--r--tools/build/feature/test-libunwind-debug-frame.c16
-rw-r--r--tools/build/feature/test-libunwind.c27
-rw-r--r--tools/build/feature/test-libzstd.c12
-rw-r--r--tools/build/feature/test-llvm-perf.cpp14
-rw-r--r--tools/build/feature/test-llvm.cpp14
-rw-r--r--tools/build/feature/test-lzma.c11
-rw-r--r--tools/build/feature/test-numa_num_possible_cpus.c7
-rw-r--r--tools/build/feature/test-pthread-attr-setaffinity-np.c18
-rw-r--r--tools/build/feature/test-pthread-barrier.c12
-rw-r--r--tools/build/feature/test-reallocarray.c10
-rw-r--r--tools/build/feature/test-scandirat.c13
-rw-r--r--tools/build/feature/test-sched_getcpu.c12
-rw-r--r--tools/build/feature/test-sdt.c8
-rw-r--r--tools/build/feature/test-setns.c9
-rw-r--r--tools/build/feature/test-stackprotector-all.c7
-rw-r--r--tools/build/feature/test-timerfd.c19
-rw-r--r--tools/build/feature/test-zlib.c10
-rw-r--r--tools/build/fixdep.c170
-rw-r--r--tools/build/tests/ex/Build11
-rw-r--r--tools/build/tests/ex/Makefile27
-rw-r--r--tools/build/tests/ex/a.c6
-rw-r--r--tools/build/tests/ex/arch/Build2
-rw-r--r--tools/build/tests/ex/arch/e.c6
-rw-r--r--tools/build/tests/ex/arch/f.c6
-rw-r--r--tools/build/tests/ex/b.c6
-rw-r--r--tools/build/tests/ex/c.c6
-rw-r--r--tools/build/tests/ex/d.c6
-rw-r--r--tools/build/tests/ex/empty/Build0
-rw-r--r--tools/build/tests/ex/empty2/README2
-rw-r--r--tools/build/tests/ex/ex.c22
-rw-r--r--tools/build/tests/ex/inc.c9
-rwxr-xr-xtools/build/tests/run.sh70
87 files changed, 2635 insertions, 0 deletions
diff --git a/tools/build/.gitignore b/tools/build/.gitignore
new file mode 100644
index 000000000..98ae1f509
--- /dev/null
+++ b/tools/build/.gitignore
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+fixdep
diff --git a/tools/build/Build b/tools/build/Build
new file mode 100644
index 000000000..1c7e598e9
--- /dev/null
+++ b/tools/build/Build
@@ -0,0 +1,2 @@
+hostprogs := fixdep
+fixdep-y := fixdep.o
diff --git a/tools/build/Build.include b/tools/build/Build.include
new file mode 100644
index 000000000..cd0baa7a1
--- /dev/null
+++ b/tools/build/Build.include
@@ -0,0 +1,137 @@
+###
+# build: Generic definitions
+#
+# Lots of this code have been borrowed or heavily inspired from parts
+# of kbuild code, which is not credited, but mostly developed by:
+#
+# Copyright (C) Sam Ravnborg <sam@mars.ravnborg.org>, 2015
+# Copyright (C) Linus Torvalds <torvalds@linux-foundation.org>, 2015
+#
+
+###
+# Convenient variables
+comma := ,
+squote := '
+pound := \#
+empty :=
+space := $(empty) $(empty)
+
+###
+# Name of target with a '.' as filename prefix. foo/bar.o => foo/.bar.o
+dot-target = $(dir $@).$(notdir $@)
+
+###
+# filename of target with directory and extension stripped
+basetarget = $(basename $(notdir $@))
+
+###
+# The temporary file to save gcc -MD generated dependencies must not
+# contain a comma
+depfile = $(subst $(comma),_,$(dot-target).d)
+
+###
+# Check if both arguments has same arguments. Result is empty string if equal.
+arg-check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
+ $(filter-out $(cmd_$@), $(cmd_$(1))) )
+
+###
+# Escape single quote for use in echo statements
+escsq = $(subst $(squote),'\$(squote)',$1)
+
+# Echo command
+# Short version is used, if $(quiet) equals `quiet_', otherwise full one.
+echo-cmd = $(if $($(quiet)cmd_$(1)),\
+ echo ' $(call escsq,$($(quiet)cmd_$(1)))';)
+
+###
+# Replace >$< with >$$< to preserve $ when reloading the .cmd file
+# (needed for make)
+# Replace >#< with >$(pound)< to avoid starting a comment in the .cmd file
+# (needed for make)
+# Replace >'< with >'\''< to be able to enclose the whole string in '...'
+# (needed for the shell)
+make-cmd = $(call escsq,$(subst $(pound),$$(pound),$(subst $$,$$$$,$(cmd_$(1)))))
+
+###
+# Find any prerequisites that is newer than target or that does not exist.
+# PHONY targets skipped in both cases.
+any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^)
+
+###
+# Copy dependency data into .cmd file
+# - gcc -M dependency info
+# - command line to create object 'cmd_object :='
+dep-cmd = $(if $(wildcard $(fixdep)), \
+ $(fixdep) $(depfile) $@ '$(make-cmd)' > $(dot-target).tmp; \
+ rm -f $(depfile); \
+ mv -f $(dot-target).tmp $(dot-target).cmd, \
+ printf '$(pound) cannot find fixdep (%s)\n' $(fixdep) > $(dot-target).cmd; \
+ printf '$(pound) using basic dep data\n\n' >> $(dot-target).cmd; \
+ cat $(depfile) >> $(dot-target).cmd; \
+ printf '\n%s\n' 'cmd_$@ := $(make-cmd)' >> $(dot-target).cmd)
+
+###
+# if_changed_dep - execute command if any prerequisite is newer than
+# target, or command line has changed and update
+# dependencies in the cmd file
+if_changed_dep = $(if $(strip $(any-prereq) $(arg-check)), \
+ @set -e; \
+ $(echo-cmd) $(cmd_$(1)); \
+ $(dep-cmd))
+
+# if_changed - execute command if any prerequisite is newer than
+# target, or command line has changed
+if_changed = $(if $(strip $(any-prereq) $(arg-check)), \
+ @set -e; \
+ $(echo-cmd) $(cmd_$(1)); \
+ printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd)
+
+###
+# C flags to be used in rule definitions, includes:
+# - depfile generation
+# - global $(CFLAGS)
+# - per target C flags
+# - per object C flags
+# - BUILD_STR macro to allow '-D"$(variable)"' constructs
+c_flags_1 = -Wp,-MD,$(depfile) -Wp,-MT,$@ $(CFLAGS) -D"BUILD_STR(s)=\#s" $(CFLAGS_$(basetarget).o) $(CFLAGS_$(obj))
+c_flags_2 = $(filter-out $(CFLAGS_REMOVE_$(basetarget).o), $(c_flags_1))
+c_flags = $(filter-out $(CFLAGS_REMOVE_$(obj)), $(c_flags_2))
+cxx_flags = -Wp,-MD,$(depfile) -Wp,-MT,$@ $(CXXFLAGS) -D"BUILD_STR(s)=\#s" $(CXXFLAGS_$(basetarget).o) $(CXXFLAGS_$(obj))
+
+###
+# Rust flags to be used on rule definition, includes:
+# - global $(RUST_FLAGS)
+# - per target Rust flags
+# - per object Rust flags
+rust_flags_1 = $(RUST_FLAGS) $(RUST_FLAGS_$(basetarget).o) $(RUST_FLAGS_$(obj))
+rust_flags_2 = $(filter-out $(RUST_FLAGS_REMOVE_$(basetarget).o), $(rust_flags_1))
+rust_flags = $(filter-out $(RUST_FLAGS_REMOVE_$(obj)), $(rust_flags_2))
+
+###
+## HOSTCC C flags
+
+host_c_flags = -Wp,-MD,$(depfile) -Wp,-MT,$@ $(HOSTCFLAGS) -D"BUILD_STR(s)=\#s" $(HOSTCFLAGS_$(basetarget).o) $(HOSTCFLAGS_$(obj))
+
+# output directory for tests below
+TMPOUT = .tmp_$$$$
+
+# try-run
+# Usage: option = $(call try-run, $(CC)...-o "$$TMP",option-ok,otherwise)
+# Exit code chooses option. "$$TMP" serves as a temporary file and is
+# automatically cleaned up.
+try-run = $(shell set -e; \
+ TMP=$(TMPOUT)/tmp; \
+ mkdir -p $(TMPOUT); \
+ trap "rm -rf $(TMPOUT)" EXIT; \
+ if ($(1)) >/dev/null 2>&1; \
+ then echo "$(2)"; \
+ else echo "$(3)"; \
+ fi)
+
+# cc-option
+# Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586)
+cc-option = $(call try-run, \
+ $(CC) -Werror $(1) -c -x c /dev/null -o "$$TMP",$(1),$(2))
+
+# delete partially updated (i.e. corrupted) files on error
+.DELETE_ON_ERROR:
diff --git a/tools/build/Documentation/Build.txt b/tools/build/Documentation/Build.txt
new file mode 100644
index 000000000..a22587475
--- /dev/null
+++ b/tools/build/Documentation/Build.txt
@@ -0,0 +1,168 @@
+Build Framework
+===============
+
+The perf build framework was adopted from the kernel build system, hence the
+idea and the way how objects are built is the same.
+
+Basically the user provides set of 'Build' files that list objects and
+directories to nest for specific target to be build.
+
+Unlike the kernel we don't have a single build object 'obj-y' list that where
+we setup source objects, but we support more. This allows one 'Build' file to
+carry a sources list for multiple build objects.
+
+
+Build framework makefiles
+-------------------------
+
+The build framework consists of 2 Makefiles:
+
+ Build.include
+ Makefile.build
+
+While the 'Build.include' file contains just some generic definitions, the
+'Makefile.build' file is the makefile used from the outside. It's
+interface/usage is following:
+
+ $ make -f tools/build/Makefile.build srctree=$(KSRC) dir=$(DIR) obj=$(OBJECT)
+
+where:
+
+ KSRC - is the path to kernel sources
+ DIR - is the path to the project to be built
+ OBJECT - is the name of the build object
+
+When succefully finished the $(DIR) directory contains the final object file
+called $(OBJECT)-in.o:
+
+ $ ls $(DIR)/$(OBJECT)-in.o
+
+which includes all compiled sources described in 'Build' makefiles.
+
+
+Build makefiles
+---------------
+
+The user supplies 'Build' makefiles that contains a objects list, and connects
+the build to nested directories.
+
+Assume we have the following project structure:
+
+ ex/a.c
+ /b.c
+ /c.c
+ /d.c
+ /arch/e.c
+ /arch/f.c
+
+Out of which you build the 'ex' binary ' and the 'libex.a' library:
+
+ 'ex' - consists of 'a.o', 'b.o' and libex.a
+ 'libex.a' - consists of 'c.o', 'd.o', 'e.o' and 'f.o'
+
+The build framework does not create the 'ex' and 'libex.a' binaries for you, it
+only prepares proper objects to be compiled and grouped together.
+
+To follow the above example, the user provides following 'Build' files:
+
+ ex/Build:
+ ex-y += a.o
+ ex-y += b.o
+ ex-y += b.o # duplicates in the lists are allowed
+
+ libex-y += c.o
+ libex-y += d.o
+ libex-y += arch/
+
+ ex/arch/Build:
+ libex-y += e.o
+ libex-y += f.o
+
+and runs:
+
+ $ make -f tools/build/Makefile.build dir=. obj=ex
+ $ make -f tools/build/Makefile.build dir=. obj=libex
+
+which creates the following objects:
+
+ ex/ex-in.o
+ ex/libex-in.o
+
+that contain request objects names in Build files.
+
+It's only a matter of 2 single commands to create the final binaries:
+
+ $ ar rcs libex.a libex-in.o
+ $ gcc -o ex ex-in.o libex.a
+
+You can check the 'ex' example in 'tools/build/tests/ex' for more details.
+
+
+Makefile.include
+----------------
+
+The tools/build/Makefile.include makefile could be included
+via user makefiles to get usefull definitions.
+
+It defines following interface:
+
+ - build macro definition:
+ build := -f $(srctree)/tools/build/Makefile.build dir=. obj
+
+ to make it easier to invoke build like:
+ make $(build)=ex
+
+
+Fixdep
+------
+It is necessary to build the fixdep helper before invoking the build.
+The Makefile.include file adds the fixdep target, that could be
+invoked by the user.
+
+
+Rules
+-----
+
+The build framework provides standard compilation rules to handle .S and .c
+compilation.
+
+It's possible to include special rule if needed (like we do for flex or bison
+code generation).
+
+
+CFLAGS
+------
+
+It's possible to alter the standard object C flags in the following way:
+
+ CFLAGS_perf.o += '...' - adds CFLAGS for perf.o object
+ CFLAGS_gtk += '...' - adds CFLAGS for gtk build object
+ CFLAGS_REMOVE_perf.o += '...' - removes CFLAGS for perf.o object
+ CFLAGS_REMOVE_gtk += '...' - removes CFLAGS for gtk build object
+
+This C flags changes has the scope of the Build makefile they are defined in.
+
+
+Dependencies
+------------
+
+For each built object file 'a.o' the '.a.cmd' is created and holds:
+
+ - Command line used to built that object
+ (for each object)
+
+ - Dependency rules generated by 'gcc -Wp,-MD,...'
+ (for compiled object)
+
+All existing '.cmd' files are included in the Build process to follow properly
+the dependencies and trigger a rebuild when necessary.
+
+
+Single rules
+------------
+
+It's possible to build single object file by choice, like:
+
+ $ make util/map.o # objects
+ $ make util/map.i # preprocessor
+ $ make util/map.s # assembly
diff --git a/tools/build/Makefile b/tools/build/Makefile
new file mode 100644
index 000000000..3a5a3808a
--- /dev/null
+++ b/tools/build/Makefile
@@ -0,0 +1,58 @@
+# SPDX-License-Identifier: GPL-2.0
+ifeq ($(srctree),)
+srctree := $(patsubst %/,%,$(dir $(CURDIR)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+endif
+
+include $(srctree)/tools//scripts/Makefile.include
+
+define allow-override
+ $(if $(or $(findstring environment,$(origin $(1))),\
+ $(findstring command line,$(origin $(1)))),,\
+ $(eval $(1) = $(2)))
+endef
+
+$(call allow-override,CC,$(CROSS_COMPILE)gcc)
+$(call allow-override,LD,$(CROSS_COMPILE)ld)
+
+export HOSTCC HOSTLD HOSTAR
+
+export srctree CC LD
+
+MAKEFLAGS := --no-print-directory
+build := -f $(srctree)/tools/build/Makefile.build dir=. obj
+
+all: $(OUTPUT)fixdep
+
+# Make sure there's anything to clean,
+# feature contains check for existing OUTPUT
+TMP_O := $(if $(OUTPUT),$(OUTPUT)feature/,./)
+
+clean:
+ $(call QUIET_CLEAN, fixdep)
+ $(Q)find $(or $(OUTPUT),.) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
+ $(Q)rm -f $(OUTPUT)fixdep
+ $(call QUIET_CLEAN, feature-detect)
+ifneq ($(wildcard $(TMP_O)),)
+ $(Q)$(MAKE) -C feature OUTPUT=$(TMP_O) clean >/dev/null
+endif
+
+FIXDEP := $(OUTPUT)fixdep
+FIXDEP_IN := $(OUTPUT)fixdep-in.o
+
+# To track fixdep's dependencies properly, fixdep needs to run on itself.
+# Build it twice the first time.
+$(FIXDEP_IN): FORCE
+ $(Q)if [ ! -f $(FIXDEP) ]; then \
+ $(MAKE) $(build)=fixdep HOSTCFLAGS="$(KBUILD_HOSTCFLAGS)"; \
+ rm -f $(FIXDEP).o; \
+ fi
+ $(Q)$(MAKE) $(build)=fixdep HOSTCFLAGS="$(KBUILD_HOSTCFLAGS)"
+
+
+$(FIXDEP): $(FIXDEP_IN)
+ $(QUIET_LINK)$(HOSTCC) $(FIXDEP_IN) $(KBUILD_HOSTLDFLAGS) -o $@
+
+FORCE:
+
+.PHONY: FORCE
diff --git a/tools/build/Makefile.build b/tools/build/Makefile.build
new file mode 100644
index 000000000..ad69efdd4
--- /dev/null
+++ b/tools/build/Makefile.build
@@ -0,0 +1,181 @@
+# SPDX-License-Identifier: GPL-2.0
+###
+# Main build makefile.
+#
+# Lots of this code have been borrowed or heavily inspired from parts
+# of kbuild code, which is not credited, but mostly developed by:
+#
+# Copyright (C) Sam Ravnborg <sam@mars.ravnborg.org>, 2015
+# Copyright (C) Linus Torvalds <torvalds@linux-foundation.org>, 2015
+#
+
+PHONY := __build
+__build:
+
+build-dir := $(srctree)/tools/build
+
+# Define $(fixdep) for dep-cmd function
+ifeq ($(OUTPUT),)
+ fixdep := $(build-dir)/fixdep
+else
+ fixdep := $(OUTPUT)/fixdep
+endif
+
+# Generic definitions
+include $(build-dir)/Build.include
+
+# do not force detected configuration
+-include $(OUTPUT).config-detected
+
+# Init all relevant variables used in build files so
+# 1) they have correct type
+# 2) they do not inherit any value from the environment
+subdir-y :=
+obj-y :=
+subdir-y :=
+subdir-obj-y :=
+
+# Build definitions
+build-file := $(dir)/Build
+-include $(build-file)
+
+quiet_cmd_flex = FLEX $@
+quiet_cmd_bison = BISON $@
+quiet_cmd_test = TEST $@
+
+# Create directory unless it exists
+quiet_cmd_mkdir = MKDIR $(dir $@)
+ cmd_mkdir = mkdir -p $(dir $@)
+ rule_mkdir = $(if $(wildcard $(dir $@)),,@$(call echo-cmd,mkdir) $(cmd_mkdir))
+
+# Compile command
+quiet_cmd_cc_o_c = CC $@
+ cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
+
+quiet_cmd_host_cc_o_c = HOSTCC $@
+ cmd_host_cc_o_c = $(HOSTCC) $(host_c_flags) -c -o $@ $<
+
+quiet_cmd_cxx_o_c = CXX $@
+ cmd_cxx_o_c = $(CXX) $(cxx_flags) -c -o $@ $<
+
+quiet_cmd_cpp_i_c = CPP $@
+ cmd_cpp_i_c = $(CC) $(c_flags) -E -o $@ $<
+
+quiet_cmd_cc_s_c = AS $@
+ cmd_cc_s_c = $(CC) $(c_flags) -S -o $@ $<
+
+quiet_cmd_gen = GEN $@
+
+# Link agregate command
+# If there's nothing to link, create empty $@ object.
+quiet_cmd_ld_multi = LD $@
+ cmd_ld_multi = $(if $(strip $(obj-y)),\
+ printf "$(objprefix)%s " $(patsubst $(objprefix)%,%,$(filter $(obj-y),$^)) | \
+ xargs $(LD) -r -o $@,rm -f $@; $(AR) rcs $@)
+
+quiet_cmd_host_ld_multi = HOSTLD $@
+ cmd_host_ld_multi = $(if $(strip $(obj-y)),\
+ printf "$(objprefix)%s " $(patsubst $(objprefix)%,%,$(filter $(obj-y),$^)) | \
+ xargs $(HOSTLD) -r -o $@,rm -f $@; $(HOSTAR) rcs $@)
+
+rust_common_cmd = \
+ $(RUSTC) $(rust_flags) \
+ --crate-type staticlib -L $(objtree)/rust/ \
+ --emit=dep-info=$(depfile),link
+
+quiet_cmd_rustc_a_rs = $(RUSTC) $(quiet_modtag) $@
+ cmd_rustc_a_rs = $(rust_common_cmd) -o $@ -g $< $(cmd_objtool)
+
+ifneq ($(filter $(obj),$(hostprogs)),)
+ host = host_
+endif
+
+# Build rules
+$(OUTPUT)%.o: %.c FORCE
+ $(call rule_mkdir)
+ $(call if_changed_dep,$(host)cc_o_c)
+
+$(OUTPUT)%.o: %.cpp FORCE
+ $(call rule_mkdir)
+ $(call if_changed_dep,cxx_o_c)
+
+$(OUTPUT)%.o: %.S FORCE
+ $(call rule_mkdir)
+ $(call if_changed_dep,$(host)cc_o_c)
+
+$(OUTPUT)%.i: %.c FORCE
+ $(call rule_mkdir)
+ $(call if_changed_dep,cpp_i_c)
+
+$(OUTPUT)%.s: %.S FORCE
+ $(call rule_mkdir)
+ $(call if_changed_dep,cpp_i_c)
+
+$(OUTPUT)%.s: %.c FORCE
+ $(call rule_mkdir)
+ $(call if_changed_dep,cc_s_c)
+
+# it's recommended to build a static rust library, when a foreight (to rust)
+# linker is used.
+$(OUTPUT)%.a: %.rs FORCE
+ $(call rule_mkdir)
+ $(call if_changed_dep,rustc_a_rs)
+
+# bison and flex files are generated in the OUTPUT directory
+# so it needs a separate rule to depend on them properly
+$(OUTPUT)%-bison.o: $(OUTPUT)%-bison.c FORCE
+ $(call rule_mkdir)
+ $(call if_changed_dep,$(host)cc_o_c)
+
+$(OUTPUT)%-flex.o: $(OUTPUT)%-flex.c FORCE
+ $(call rule_mkdir)
+ $(call if_changed_dep,$(host)cc_o_c)
+
+# Gather build data:
+# obj-y - list of build objects
+# subdir-y - list of directories to nest
+# subdir-obj-y - list of directories objects 'dir/$(obj)-in.o'
+obj-y := $($(obj)-y)
+subdir-y := $(patsubst %/,%,$(filter %/, $(obj-y)))
+obj-y := $(patsubst %/, %/$(obj)-in.o, $(obj-y))
+subdir-obj-y := $(filter %/$(obj)-in.o, $(obj-y))
+
+# '$(OUTPUT)/dir' prefix to all objects
+objprefix := $(subst ./,,$(OUTPUT)$(dir)/)
+obj-y := $(addprefix $(objprefix),$(obj-y))
+subdir-obj-y := $(addprefix $(objprefix),$(subdir-obj-y))
+
+# Separate out test log files from real build objects.
+test-y := $(filter %_log, $(obj-y))
+obj-y := $(filter-out %_log, $(obj-y))
+
+# Final '$(obj)-in.o' object
+in-target := $(objprefix)$(obj)-in.o
+
+PHONY += $(subdir-y)
+
+$(subdir-y):
+ $(Q)$(MAKE) -f $(build-dir)/Makefile.build dir=$(dir)/$@ obj=$(obj)
+
+$(sort $(subdir-obj-y)): $(subdir-y) ;
+
+$(in-target): $(obj-y) $(test-y) FORCE
+ $(call rule_mkdir)
+ $(call if_changed,$(host)ld_multi)
+
+__build: $(in-target)
+ @:
+
+PHONY += FORCE
+FORCE:
+
+# Include all cmd files to get all the dependency rules
+# for all objects included
+targets := $(wildcard $(sort $(obj-y) $(in-target) $(MAKECMDGOALS)))
+cmd_files := $(wildcard $(foreach f,$(targets),$(dir $(f)).$(notdir $(f)).cmd))
+
+ifneq ($(cmd_files),)
+ include $(cmd_files)
+endif
+
+.PHONY: $(PHONY)
diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
new file mode 100644
index 000000000..99eb0ea09
--- /dev/null
+++ b/tools/build/Makefile.feature
@@ -0,0 +1,334 @@
+# SPDX-License-Identifier: GPL-2.0-only
+feature_dir := $(srctree)/tools/build/feature
+
+ifneq ($(OUTPUT),)
+ OUTPUT_FEATURES = $(OUTPUT)feature/
+ $(shell mkdir -p $(OUTPUT_FEATURES))
+endif
+
+feature_check = $(eval $(feature_check_code))
+define feature_check_code
+ feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CC="$(CC)" CXX="$(CXX)" CFLAGS="$(EXTRA_CFLAGS) $(FEATURE_CHECK_CFLAGS-$(1))" CXXFLAGS="$(EXTRA_CXXFLAGS) $(FEATURE_CHECK_CXXFLAGS-$(1))" LDFLAGS="$(LDFLAGS) $(FEATURE_CHECK_LDFLAGS-$(1))" -C $(feature_dir) $(OUTPUT_FEATURES)test-$1.bin >/dev/null 2>/dev/null && echo 1 || echo 0)
+endef
+
+feature_set = $(eval $(feature_set_code))
+define feature_set_code
+ feature-$(1) := 1
+endef
+
+#
+# Build the feature check binaries in parallel, ignore errors, ignore return value and suppress output:
+#
+
+#
+# Note that this is not a complete list of all feature tests, just
+# those that are typically built on a fully configured system.
+#
+# [ Feature tests not mentioned here have to be built explicitly in
+# the rule that uses them - an example for that is the 'bionic'
+# feature check. ]
+#
+# These + the ones in FEATURE_TESTS_EXTRA are included in
+# tools/build/feature/test-all.c and we try to build it all together
+# then setting all those features to '1' meaning they are all enabled.
+#
+# There are things like fortify-source that will be set to 1 because test-all
+# is built with the flags needed to test if its enabled, resulting in
+#
+# $ rm -rf /tmp/b ; mkdir /tmp/b ; make -C tools/perf O=/tmp/b feature-dump
+# $ grep fortify-source /tmp/b/FEATURE-DUMP
+# feature-fortify-source=1
+# $
+#
+# All the others should have lines in tools/build/feature/test-all.c like:
+#
+# #define main main_test_disassembler_init_styled
+# # include "test-disassembler-init-styled.c"
+# #undef main
+#
+# #define main main_test_libzstd
+# # include "test-libzstd.c"
+# #undef main
+#
+# int main(int argc, char *argv[])
+# {
+# main_test_disassembler_four_args();
+# main_test_libzstd();
+# return 0;
+# }
+#
+# If the sample above works, then we end up with these lines in the FEATURE-DUMP
+# file:
+#
+# feature-disassembler-four-args=1
+# feature-libzstd=1
+#
+FEATURE_TESTS_BASIC := \
+ backtrace \
+ libdw \
+ eventfd \
+ fortify-source \
+ gettid \
+ glibc \
+ libbfd \
+ libbfd-threadsafe \
+ libelf \
+ libelf-getphdrnum \
+ libelf-gelf_getnote \
+ libelf-getshdrstrndx \
+ libelf-zstd \
+ libnuma \
+ numa_num_possible_cpus \
+ libpython \
+ libslang \
+ libtraceevent \
+ libcpupower \
+ pthread-attr-setaffinity-np \
+ pthread-barrier \
+ reallocarray \
+ stackprotector-all \
+ timerfd \
+ zlib \
+ lzma \
+ bpf \
+ scandirat \
+ sched_getcpu \
+ sdt \
+ setns \
+ libaio \
+ libzstd \
+ disassembler-four-args \
+ disassembler-init-styled \
+ file-handle \
+ libopenssl
+
+# FEATURE_TESTS_BASIC + FEATURE_TESTS_EXTRA is the complete list
+# of all feature tests
+
+LIBUNWIND_ARCHS:=aarch64 arm loongarch64 mips ppc32 ppc64 riscv s390x x86 x86_64
+
+FEATURE_TESTS_EXTRA := \
+ bionic \
+ compile-32 \
+ compile-x32 \
+ cplus-demangle \
+ cxa-demangle \
+ gtk2 \
+ gtk2-infobar \
+ hello \
+ babeltrace2-ctf-writer \
+ libcapstone \
+ libcheck \
+ libbfd-liberty \
+ libbfd-liberty-z \
+ libopencsd \
+ libperl \
+ llvm \
+ libbpf \
+ libpfm4 \
+ libdebuginfod \
+ clang-bpf-co-re \
+ bpftool-skeletons \
+ libunwind \
+ libunwind-debug-frame \
+ $(foreach arch,$(LIBUNWIND_ARCHS),libunwind-$(arch) libunwind-debug-frame-$(arch))
+
+
+FEATURE_TESTS ?= $(FEATURE_TESTS_BASIC)
+
+ifeq ($(FEATURE_TESTS),all)
+ FEATURE_TESTS := $(FEATURE_TESTS_BASIC) $(FEATURE_TESTS_EXTRA)
+endif
+
+FEATURE_DISPLAY ?= \
+ libdw \
+ glibc \
+ libelf \
+ libnuma \
+ numa_num_possible_cpus \
+ libpython \
+ libcapstone \
+ llvm-perf \
+ zlib \
+ lzma \
+ bpf \
+ libaio \
+ libzstd \
+ libopenssl \
+ rust
+
+#
+# Declare group members of a feature to display the logical OR of the detection
+# result instead of each member result.
+#
+FEATURE_GROUP_MEMBERS-libbfd = libbfd-liberty libbfd-liberty-z
+
+#
+# Declare list of feature dependency packages that provide pkg-config files.
+#
+FEATURE_PKG_CONFIG ?= \
+ babeltrace2-ctf-writer \
+ libtraceevent \
+ libtracefs
+
+feature_pkg_config = $(eval $(feature_pkg_config_code))
+define feature_pkg_config_code
+ FEATURE_CHECK_CFLAGS-$(1) := $(shell $(PKG_CONFIG) --cflags $(1) 2>/dev/null)
+ FEATURE_CHECK_LDFLAGS-$(1) := $(shell $(PKG_CONFIG) --libs $(1) 2>/dev/null)
+endef
+
+# Set FEATURE_CHECK_(C|LD)FLAGS-$(package) for packages using pkg-config.
+ifneq ($(PKG_CONFIG),)
+ $(foreach package,$(FEATURE_PKG_CONFIG),$(call feature_pkg_config,$(package)))
+endif
+
+FEATURE_CHECK_LDFLAGS-libcheck = -lcheck
+
+# Set FEATURE_CHECK_(C|LD)FLAGS-all for all FEATURE_TESTS features.
+# If in the future we need per-feature checks/flags for features not
+# mentioned in this list we need to refactor this ;-).
+set_test_all_flags = $(eval $(set_test_all_flags_code))
+define set_test_all_flags_code
+ FEATURE_CHECK_CFLAGS-all += $(FEATURE_CHECK_CFLAGS-$(1))
+ FEATURE_CHECK_LDFLAGS-all += $(FEATURE_CHECK_LDFLAGS-$(1))
+endef
+
+$(foreach feat,$(FEATURE_TESTS),$(call set_test_all_flags,$(feat)))
+
+#
+# Special fast-path for the 'all features are available' case:
+#
+$(call feature_check,all,$(MSG))
+
+#
+# Just in case the build freshly failed, make sure we print the
+# feature matrix:
+#
+ifeq ($(feature-all), 1)
+ #
+ # test-all.c passed - just set all the core feature flags to 1:
+ #
+ $(foreach feat,$(FEATURE_TESTS),$(call feature_set,$(feat)))
+ #
+ # test-all.c does not comprise these tests, so we need to
+ # for this case to get features proper values
+ #
+ $(call feature_check,compile-32)
+ $(call feature_check,compile-x32)
+ $(call feature_check,bionic)
+ $(call feature_check,babeltrace2-ctf-writer)
+ $(call feature_check,libunwind)
+ $(call feature_check,libunwind-debug-frame)
+ $(foreach arch,$(LIBUNWIND_ARCHS),$(call feature_check,libunwind-$(arch)))
+ $(foreach arch,$(LIBUNWIND_ARCHS),$(call feature_check,libunwind-debug-frame-$(arch)))
+else
+ $(foreach feat,$(FEATURE_TESTS),$(call feature_check,$(feat)))
+endif
+
+#
+# Print the result of the feature test:
+#
+feature_print_status = $(eval $(feature_print_status_code))
+
+feature_group = $(eval $(feature_gen_group)) $(GROUP)
+
+define feature_gen_group
+ GROUP := $(1)
+ ifneq ($(feature_verbose),1)
+ GROUP += $(FEATURE_GROUP_MEMBERS-$(1))
+ endif
+endef
+
+define feature_print_status_code
+ ifneq (,$(filter 1,$(foreach feat,$(call feature_group,$(feat)),$(feature-$(feat)))))
+ MSG = $(shell printf '...%40s: [ \033[32mon\033[m ]' $(1))
+ else
+ MSG = $(shell printf '...%40s: [ \033[31mOFF\033[m ]' $(1))
+ endif
+endef
+
+feature_print_text = $(eval $(feature_print_text_code))
+define feature_print_text_code
+ MSG = $(shell printf '...%40s: %s' $(1) $(2))
+endef
+
+#
+# generates feature value assignment for name, like:
+# $(call feature_assign,libdw) == feature-libdw=1
+#
+feature_assign = feature-$(1)=$(feature-$(1))
+
+FEATURE_DUMP_FILENAME = $(OUTPUT)FEATURE-DUMP$(FEATURE_USER)
+FEATURE_DUMP := $(shell touch $(FEATURE_DUMP_FILENAME); cat $(FEATURE_DUMP_FILENAME))
+
+feature_dump_check = $(eval $(feature_dump_check_code))
+define feature_dump_check_code
+ ifeq ($(findstring $(1),$(FEATURE_DUMP)),)
+ $(2) := 1
+ endif
+endef
+
+#
+# First check if any test from FEATURE_DISPLAY
+# and set feature_display := 1 if it does
+$(foreach feat,$(FEATURE_DISPLAY),$(call feature_dump_check,$(call feature_assign,$(feat)),feature_display))
+
+#
+# Now also check if any other test changed,
+# so we force FEATURE-DUMP generation
+$(foreach feat,$(FEATURE_TESTS),$(call feature_dump_check,$(call feature_assign,$(feat)),feature_dump_changed))
+
+# The $(feature_display) controls the default detection message
+# output. It's set if:
+# - detected features differes from stored features from
+# last build (in $(FEATURE_DUMP_FILENAME) file)
+# - one of the $(FEATURE_DISPLAY) is not detected
+# - VF is enabled
+
+ifeq ($(feature_dump_changed),1)
+ $(shell rm -f $(FEATURE_DUMP_FILENAME))
+ $(foreach feat,$(FEATURE_TESTS),$(shell echo "$(call feature_assign,$(feat))" >> $(FEATURE_DUMP_FILENAME)))
+endif
+
+feature_display_check = $(eval $(feature_check_display_code))
+define feature_check_display_code
+ ifneq ($(feature-$(1)), 1)
+ feature_display := 1
+ endif
+endef
+
+$(foreach feat,$(FEATURE_DISPLAY),$(call feature_display_check,$(feat)))
+
+ifeq ($(VF),1)
+ feature_display := 1
+ feature_verbose := 1
+endif
+
+ifneq ($(feature_verbose),1)
+ #
+ # Determine the features to omit from the displayed message, as only the
+ # logical OR of the detection result will be shown.
+ #
+ FEATURE_OMIT := $(foreach feat,$(FEATURE_DISPLAY),$(FEATURE_GROUP_MEMBERS-$(feat)))
+endif
+
+feature_display_entries = $(eval $(feature_display_entries_code))
+define feature_display_entries_code
+ ifeq ($(feature_display),1)
+ $$(info )
+ $$(info Auto-detecting system features:)
+ $(foreach feat,$(filter-out $(FEATURE_OMIT),$(FEATURE_DISPLAY)),$(call feature_print_status,$(feat),) $$(info $(MSG)))
+ endif
+
+ ifeq ($(feature_verbose),1)
+ $(eval TMP := $(filter-out $(FEATURE_DISPLAY),$(FEATURE_TESTS)))
+ $(foreach feat,$(TMP),$(call feature_print_status,$(feat),) $$(info $(MSG)))
+ endif
+endef
+
+ifeq ($(FEATURE_DISPLAY_DEFERRED),)
+ $(call feature_display_entries)
+ ifeq ($(feature_display),1)
+ $(info )
+ endif
+endif
diff --git a/tools/build/Makefile.include b/tools/build/Makefile.include
new file mode 100644
index 000000000..0e4de8340
--- /dev/null
+++ b/tools/build/Makefile.include
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: GPL-2.0-only
+build := -f $(srctree)/tools/build/Makefile.build dir=. obj
+
+# More than just $(Q), we sometimes want to suppress all command output from a
+# recursive make -- even the 'up to date' printout.
+ifeq ($(V),1)
+ Q ?=
+ SILENT_MAKE = +$(Q)$(MAKE)
+else
+ Q ?= @
+ SILENT_MAKE = +$(Q)$(MAKE) --silent
+endif
+
+fixdep:
+ $(SILENT_MAKE) -C $(srctree)/tools/build CFLAGS= LDFLAGS= $(OUTPUT)fixdep
+
+fixdep-clean:
+ $(Q)$(MAKE) -C $(srctree)/tools/build clean
+
+.PHONY: fixdep
diff --git a/tools/build/feature/.gitignore b/tools/build/feature/.gitignore
new file mode 100644
index 000000000..15fcd34ac
--- /dev/null
+++ b/tools/build/feature/.gitignore
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+*.d
+*.bin
+*.output
diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile
new file mode 100644
index 000000000..7d1650181
--- /dev/null
+++ b/tools/build/feature/Makefile
@@ -0,0 +1,397 @@
+# SPDX-License-Identifier: GPL-2.0
+include ../../scripts/Makefile.include
+
+LIBUNWIND_ARCHS:=aarch64 arm loongarch64 mips ppc32 ppc64 riscv s390x x86 x86_64
+
+FILES= \
+ test-all.bin \
+ test-backtrace.bin \
+ test-bionic.bin \
+ test-libdw.bin \
+ test-eventfd.bin \
+ test-fortify-source.bin \
+ test-glibc.bin \
+ test-gtk2.bin \
+ test-gtk2-infobar.bin \
+ test-hello.bin \
+ test-libbfd.bin \
+ test-libbfd-threadsafe.bin \
+ test-disassembler-four-args.bin \
+ test-disassembler-init-styled.bin \
+ test-reallocarray.bin \
+ test-libbfd-liberty.bin \
+ test-libbfd-liberty-z.bin \
+ test-cplus-demangle.bin \
+ test-cxa-demangle.bin \
+ test-libcap.bin \
+ test-libelf.bin \
+ test-libelf-getphdrnum.bin \
+ test-libelf-gelf_getnote.bin \
+ test-libelf-getshdrstrndx.bin \
+ test-libelf-zstd.bin \
+ test-libdebuginfod.bin \
+ test-libnuma.bin \
+ test-numa_num_possible_cpus.bin \
+ test-libperl.bin \
+ test-libpython.bin \
+ test-libslang.bin \
+ test-libtraceevent.bin \
+ test-libcpupower.bin \
+ test-libtracefs.bin \
+ test-libunwind.bin \
+ test-libunwind-debug-frame.bin \
+ $(foreach arch,$(LIBUNWIND_ARCHS),test-libunwind-$(arch).bin test-libunwind-debug-frame-$(arch).bin) \
+ test-pthread-attr-setaffinity-np.bin \
+ test-pthread-barrier.bin \
+ test-stackprotector-all.bin \
+ test-timerfd.bin \
+ test-babeltrace2-ctf-writer.bin \
+ test-libcapstone.bin \
+ test-libcheck.bin \
+ test-compile-32.bin \
+ test-compile-x32.bin \
+ test-zlib.bin \
+ test-lzma.bin \
+ test-bpf.bin \
+ test-libbpf.bin \
+ test-sdt.bin \
+ test-gettid.bin \
+ test-jvmti.bin \
+ test-jvmti-cmlr.bin \
+ test-scandirat.bin \
+ test-sched_getcpu.bin \
+ test-setns.bin \
+ test-libopencsd.bin \
+ test-llvm.bin \
+ test-llvm-perf.bin \
+ test-libaio.bin \
+ test-libzstd.bin \
+ test-clang-bpf-co-re.bin \
+ test-file-handle.bin \
+ test-libpfm4.bin \
+ test-rust.bin \
+ test-libopenssl.bin \
+ test-bpftool-skeletons.bin
+
+FILES := $(addprefix $(OUTPUT),$(FILES))
+
+# Some distros provide the command $(CROSS_COMPILE)pkg-config for
+# searching packges installed with Multiarch. Use it for cross
+# compilation if it is existed.
+ifneq (, $(shell which $(CROSS_COMPILE)pkg-config))
+ PKG_CONFIG ?= $(CROSS_COMPILE)pkg-config
+else
+ PKG_CONFIG ?= pkg-config
+
+ # PKG_CONFIG_PATH or PKG_CONFIG_LIBDIR, alongside PKG_CONFIG_SYSROOT_DIR
+ # for modified system root, are required for the cross compilation.
+ # If these PKG_CONFIG environment variables are not set, Multiarch library
+ # paths are used instead.
+ ifdef CROSS_COMPILE
+ ifeq ($(PKG_CONFIG_LIBDIR)$(PKG_CONFIG_PATH)$(PKG_CONFIG_SYSROOT_DIR),)
+ CROSS_ARCH = $(notdir $(CROSS_COMPILE:%-=%))
+ PKG_CONFIG_LIBDIR := /usr/local/$(CROSS_ARCH)/lib/pkgconfig/
+ PKG_CONFIG_LIBDIR := $(PKG_CONFIG_LIBDIR):/usr/local/lib/$(CROSS_ARCH)/pkgconfig/
+ PKG_CONFIG_LIBDIR := $(PKG_CONFIG_LIBDIR):/usr/lib/$(CROSS_ARCH)/pkgconfig/
+ PKG_CONFIG_LIBDIR := $(PKG_CONFIG_LIBDIR):/usr/local/share/pkgconfig/
+ PKG_CONFIG_LIBDIR := $(PKG_CONFIG_LIBDIR):/usr/share/pkgconfig/
+ export PKG_CONFIG_LIBDIR
+ endif
+ endif
+endif
+
+ifeq ($(findstring -static,${LDFLAGS}),-static)
+ PKG_CONFIG += --static
+endif
+
+all: $(FILES)
+
+__BUILD = $(CC) $(CFLAGS) -MD -Wall -Werror -o $@ $(patsubst %.bin,%.c,$(@F)) $(LDFLAGS)
+ BUILD = $(__BUILD) > $(@:.bin=.make.output) 2>&1
+ BUILD_BFD = $(BUILD) -DPACKAGE='"perf"' -lbfd -ldl
+ BUILD_ALL = $(BUILD) -fstack-protector-all -O2 -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -lslang \
+ $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -ldl -lz -llzma -lzstd \
+ $(shell $(PKG_CONFIG) --libs --cflags openssl 2>/dev/null)
+
+__BUILDXX = $(CXX) $(CXXFLAGS) -MD -Wall -Werror -o $@ $(patsubst %.bin,%.cpp,$(@F)) $(LDFLAGS)
+ BUILDXX = $(__BUILDXX) > $(@:.bin=.make.output) 2>&1
+
+###############################
+
+$(OUTPUT)test-all.bin:
+ $(BUILD_ALL)
+
+$(OUTPUT)test-hello.bin:
+ $(BUILD)
+
+$(OUTPUT)test-pthread-attr-setaffinity-np.bin:
+ $(BUILD) -D_GNU_SOURCE -lpthread
+
+$(OUTPUT)test-pthread-barrier.bin:
+ $(BUILD) -lpthread
+
+$(OUTPUT)test-stackprotector-all.bin:
+ $(BUILD) -fstack-protector-all
+
+$(OUTPUT)test-fortify-source.bin:
+ $(BUILD) -O2 -D_FORTIFY_SOURCE=2
+
+$(OUTPUT)test-bionic.bin:
+ $(BUILD)
+
+$(OUTPUT)test-libcap.bin:
+ $(BUILD) -lcap
+
+$(OUTPUT)test-libelf.bin:
+ $(BUILD) -lelf
+
+$(OUTPUT)test-eventfd.bin:
+ $(BUILD)
+
+$(OUTPUT)test-glibc.bin:
+ $(BUILD)
+
+$(OUTPUT)test-scandirat.bin:
+ $(BUILD)
+
+$(OUTPUT)test-sched_getcpu.bin:
+ $(BUILD)
+
+$(OUTPUT)test-setns.bin:
+ $(BUILD)
+
+$(OUTPUT)test-libopencsd.bin:
+ $(BUILD) # -lopencsd_c_api -lopencsd provided by
+ # $(FEATURE_CHECK_LDFLAGS-libopencsd)
+
+DWLIBS := -ldw
+ifeq ($(findstring -static,${LDFLAGS}),-static)
+ DWLIBS += -lelf -lz -llzma -lbz2 -lzstd
+
+ LIBDW_VERSION := $(shell $(PKG_CONFIG) --modversion libdw).0.0
+ LIBDW_VERSION_1 := $(word 1, $(subst ., ,$(LIBDW_VERSION)))
+ LIBDW_VERSION_2 := $(word 2, $(subst ., ,$(LIBDW_VERSION)))
+
+ # Elfutils merged libebl.a into libdw.a starting from version 0.177,
+ # Link libebl.a only if libdw is older than this version.
+ ifeq ($(shell test $(LIBDW_VERSION_2) -lt 177; echo $$?),0)
+ DWLIBS += -lebl
+ endif
+
+ # Must put -ldl after -lebl for dependency
+ DWARFLIBS += -ldl
+endif
+
+$(OUTPUT)test-libdw.bin:
+ $(BUILD) $(DWLIBS)
+
+$(OUTPUT)test-libelf-getphdrnum.bin:
+ $(BUILD) -lelf
+
+$(OUTPUT)test-libelf-gelf_getnote.bin:
+ $(BUILD) -lelf
+
+$(OUTPUT)test-libelf-getshdrstrndx.bin:
+ $(BUILD) -lelf
+
+$(OUTPUT)test-libelf-zstd.bin:
+ $(BUILD) -lelf -lz -lzstd
+
+$(OUTPUT)test-libdebuginfod.bin:
+ $(BUILD) -ldebuginfod
+
+$(OUTPUT)test-libnuma.bin:
+ $(BUILD) -lnuma
+
+$(OUTPUT)test-numa_num_possible_cpus.bin:
+ $(BUILD) -lnuma
+
+$(OUTPUT)test-libunwind.bin:
+ $(BUILD) -include libunwind.h -lelf -llzma -lunwind
+
+$(OUTPUT)test-libunwind-debug-frame.bin:
+ $(BUILD) -include libunwind.h -lelf -llzma -lunwind
+
+define LIBUNWIND_RULE
+$$(OUTPUT)test-libunwind-$(1).bin:
+ $$(CC) $$(CFLAGS) -MD -Wall -Werror -include libunwind-$(1).h -o $$@ \
+ test-libunwind.c $$(LDFLAGS) -lelf -llzma -lunwind-$(1) \
+ > $$(@:.bin=.make.output) 2>&1
+
+$$(OUTPUT)test-libunwind-debug-frame-$(1).bin:
+ $$(CC) $$(CFLAGS) -MD -Wall -Werror -include libunwind-$(1).h -o $$@ \
+ test-libunwind-debug-frame.c $$(LDFLAGS) -lelf -llzma -lunwind-$(1) \
+ > $$(@:.bin=.make.output) 2>&1
+
+endef
+$(foreach arch,$(LIBUNWIND_ARCHS), \
+ $(eval $(call LIBUNWIND_RULE,$(arch))) \
+)
+
+$(OUTPUT)test-libslang.bin:
+ $(BUILD) -lslang
+
+$(OUTPUT)test-libtraceevent.bin:
+ $(BUILD) -ltraceevent
+
+$(OUTPUT)test-libcpupower.bin:
+ $(BUILD) -lcpupower
+
+$(OUTPUT)test-libtracefs.bin:
+ $(BUILD) $(shell $(PKG_CONFIG) --cflags libtracefs 2>/dev/null) -ltracefs
+
+$(OUTPUT)test-gtk2.bin:
+ $(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) -Wno-deprecated-declarations
+
+$(OUTPUT)test-gtk2-infobar.bin:
+ $(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null)
+
+grep-libs = $(filter -l%,$(1))
+strip-libs = $(filter-out -l%,$(1))
+
+PERL_EMBED_LDOPTS = $(shell perl -MExtUtils::Embed -e ldopts 2>/dev/null)
+PERL_EMBED_LDFLAGS = $(call strip-libs,$(PERL_EMBED_LDOPTS))
+PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS))
+PERL_EMBED_CCOPTS = $(shell perl -MExtUtils::Embed -e ccopts 2>/dev/null)
+FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
+
+ifeq ($(CC_NO_CLANG), 0)
+ PERL_EMBED_LDOPTS := $(filter-out -specs=%,$(PERL_EMBED_LDOPTS))
+ PERL_EMBED_CCOPTS := $(filter-out -flto=auto -ffat-lto-objects, $(PERL_EMBED_CCOPTS))
+ PERL_EMBED_CCOPTS := $(filter-out -specs=%,$(PERL_EMBED_CCOPTS))
+ FLAGS_PERL_EMBED += -Wno-compound-token-split-by-macro
+endif
+
+$(OUTPUT)test-libperl.bin:
+ $(BUILD) $(FLAGS_PERL_EMBED)
+
+$(OUTPUT)test-libpython.bin:
+ $(BUILD) $(FLAGS_PYTHON_EMBED)
+
+$(OUTPUT)test-libbfd.bin:
+ $(BUILD_BFD)
+
+$(OUTPUT)test-libbfd-threadsafe.bin:
+ $(BUILD_BFD) || $(BUILD_BFD) -liberty || $(BUILD_BFD) -liberty -lz
+
+$(OUTPUT)test-disassembler-four-args.bin:
+ $(BUILD_BFD) -lopcodes || $(BUILD_BFD) -lopcodes -liberty || \
+ $(BUILD_BFD) -lopcodes -liberty -lz
+
+$(OUTPUT)test-disassembler-init-styled.bin:
+ $(BUILD_BFD) -lopcodes || $(BUILD_BFD) -lopcodes -liberty || \
+ $(BUILD_BFD) -lopcodes -liberty -lz
+
+$(OUTPUT)test-reallocarray.bin:
+ $(BUILD)
+
+$(OUTPUT)test-libbfd-liberty.bin:
+ $(CC) $(CFLAGS) -Wall -Werror -o $@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty
+
+$(OUTPUT)test-libbfd-liberty-z.bin:
+ $(CC) $(CFLAGS) -Wall -Werror -o $@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty -lz
+
+$(OUTPUT)test-cplus-demangle.bin:
+ $(BUILD) -liberty
+
+$(OUTPUT)test-cxa-demangle.bin:
+ $(BUILDXX)
+
+$(OUTPUT)test-backtrace.bin:
+ $(BUILD)
+
+$(OUTPUT)test-timerfd.bin:
+ $(BUILD)
+
+$(OUTPUT)test-babeltrace2-ctf-writer.bin:
+ $(BUILD) # -lbabeltrace2-ctf-writer provided by $(FEATURE_CHECK_LDFLAGS-babeltrace2-ctf-writer)
+
+$(OUTPUT)test-libcapstone.bin:
+ $(BUILD) # -lcapstone provided by $(FEATURE_CHECK_LDFLAGS-libcapstone)
+
+$(OUTPUT)test-libcheck.bin:
+ $(BUILD) # -lcheck is provided by $(FEATURE_CHECK_LDFLAGS-libcheck)
+
+$(OUTPUT)test-compile-32.bin:
+ $(CC) -m32 -Wall -Werror -o $@ test-compile.c
+
+$(OUTPUT)test-compile-x32.bin:
+ $(CC) -mx32 -Wall -Werror -o $@ test-compile.c
+
+$(OUTPUT)test-zlib.bin:
+ $(BUILD) -lz
+
+$(OUTPUT)test-lzma.bin:
+ $(BUILD) -llzma
+
+$(OUTPUT)test-bpf.bin:
+ $(BUILD)
+
+$(OUTPUT)test-libbpf.bin:
+ $(BUILD) -lbpf
+
+$(OUTPUT)test-sdt.bin:
+ $(BUILD)
+
+$(OUTPUT)test-gettid.bin:
+ $(BUILD)
+
+$(OUTPUT)test-jvmti.bin:
+ $(BUILD)
+
+$(OUTPUT)test-jvmti-cmlr.bin:
+ $(BUILD)
+
+$(OUTPUT)test-llvm.bin:
+ $(BUILDXX) -std=gnu++17 \
+ -I$(shell $(LLVM_CONFIG) --includedir) \
+ -L$(shell $(LLVM_CONFIG) --libdir) \
+ $(shell $(LLVM_CONFIG) --libs Core BPF) \
+ $(shell $(LLVM_CONFIG) --system-libs) \
+ > $(@:.bin=.make.output) 2>&1
+
+$(OUTPUT)test-llvm-perf.bin:
+ $(BUILDXX) -std=gnu++17 \
+ -I$(shell $(LLVM_CONFIG) --includedir) \
+ -L$(shell $(LLVM_CONFIG) --libdir) \
+ $(shell $(LLVM_CONFIG) --libs Core BPF) \
+ $(shell $(LLVM_CONFIG) --system-libs) \
+ > $(@:.bin=.make.output) 2>&1
+
+-include $(OUTPUT)*.d
+
+$(OUTPUT)test-libaio.bin:
+ $(BUILD) -lrt
+
+$(OUTPUT)test-libzstd.bin:
+ $(BUILD) -lzstd
+
+$(OUTPUT)test-clang-bpf-co-re.bin: test-clang-bpf-co-re.c
+ { $(CLANG) -S -g --target=bpf -o - $< | \
+ grep BTF_KIND_VAR; } > $(@:.bin=.make.output) 2>&1 && touch $@
+
+$(OUTPUT)test-file-handle.bin:
+ $(BUILD)
+
+$(OUTPUT)test-libpfm4.bin:
+ $(BUILD) -lpfm
+
+$(OUTPUT)test-libopenssl.bin:
+ $(BUILD) $(shell $(PKG_CONFIG) --libs --cflags openssl 2>/dev/null)
+
+$(OUTPUT)test-bpftool-skeletons.bin:
+ { $(SYSTEM_BPFTOOL) version | grep '^features:.*skeletons'; } \
+ > $(@:.bin=.make.output) 2>&1 && touch $@
+
+# Testing Rust is special: we don't compile anything, it's enough to check the
+# compiler presence. Compiling a test code for this purposes is problematic,
+# because Rust will emit a dependency file without any external references,
+# meaning that if rustc will be removed the build process will still think it's
+# there.
+$(OUTPUT)test-rust.bin:
+ $(RUSTC) --version > /dev/null 2>&1
+
+###############################
+
+clean:
+ rm -f $(FILES) $(OUTPUT)*.d $(FILES:.bin=.make.output)
diff --git a/tools/build/feature/test-all.c b/tools/build/feature/test-all.c
new file mode 100644
index 000000000..544563d62
--- /dev/null
+++ b/tools/build/feature/test-all.c
@@ -0,0 +1,183 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * test-all.c: Try to build all the main testcases at once.
+ *
+ * A well-configured system will have all the prereqs installed, so we can speed
+ * up auto-detection on such systems.
+ */
+
+/*
+ * Quirk: Python headers cannot be in arbitrary places, so keep this testcase at
+ * the top:
+ */
+#define main main_test_libpython
+# include "test-libpython.c"
+#undef main
+
+#define main main_test_hello
+# include "test-hello.c"
+#undef main
+
+#define main main_test_libelf
+# include "test-libelf.c"
+#undef main
+
+#define main main_test_gettid
+# include "test-gettid.c"
+#undef main
+
+#define main main_test_glibc
+# include "test-glibc.c"
+#undef main
+
+#define main main_test_libdw
+# include "test-libdw.c"
+#undef main
+
+#define main main_test_eventfd
+# include "test-eventfd.c"
+#undef main
+
+#define main main_test_libelf_getphdrnum
+# include "test-libelf-getphdrnum.c"
+#undef main
+
+#define main main_test_libelf_gelf_getnote
+# include "test-libelf-gelf_getnote.c"
+#undef main
+
+#define main main_test_libelf_getshdrstrndx
+# include "test-libelf-getshdrstrndx.c"
+#undef main
+
+#define main main_test_libelf_zstd
+# include "test-libelf-zstd.c"
+#undef main
+
+#define main main_test_libslang
+# include "test-libslang.c"
+#undef main
+
+#define main main_test_backtrace
+# include "test-backtrace.c"
+#undef main
+
+#define main main_test_libnuma
+# include "test-libnuma.c"
+#undef main
+
+#define main main_test_numa_num_possible_cpus
+# include "test-numa_num_possible_cpus.c"
+#undef main
+
+#define main main_test_timerfd
+# include "test-timerfd.c"
+#undef main
+
+#define main main_test_stackprotector_all
+# include "test-stackprotector-all.c"
+#undef main
+
+#define main main_test_zlib
+# include "test-zlib.c"
+#undef main
+
+#define main main_test_pthread_attr_setaffinity_np
+# include "test-pthread-attr-setaffinity-np.c"
+#undef main
+
+#define main main_test_pthread_barrier
+# include "test-pthread-barrier.c"
+#undef main
+
+#define main main_test_scandirat
+# include "test-scandirat.c"
+#undef main
+
+#define main main_test_sched_getcpu
+# include "test-sched_getcpu.c"
+#undef main
+
+# if 0
+/*
+ * Disable babeltrace2-ctf-writer check for test-all, because the requested
+ * library version is not released yet in most distributions. Will
+ * reenable later.
+ */
+
+#define main main_test_babeltrace2_ctf_writer
+# include "test-babeltrace2-ctf-writer.c"
+#undef main
+#endif
+
+#define main main_test_lzma
+# include "test-lzma.c"
+#undef main
+
+#define main main_test_bpf
+# include "test-bpf.c"
+#undef main
+
+#define main main_test_sdt
+# include "test-sdt.c"
+#undef main
+
+#define main main_test_setns
+# include "test-setns.c"
+#undef main
+
+#define main main_test_libaio
+# include "test-libaio.c"
+#undef main
+
+#define main main_test_reallocarray
+# include "test-reallocarray.c"
+#undef main
+
+#define main main_test_libzstd
+# include "test-libzstd.c"
+#undef main
+
+#define main main_test_libtraceevent
+# include "test-libtraceevent.c"
+#undef main
+
+#define main main_test_libopenssl
+# include "test-libopenssl.c"
+#undef main
+
+int main(int argc, char *argv[])
+{
+ main_test_libpython();
+ main_test_hello();
+ main_test_libelf();
+ main_test_gettid();
+ main_test_glibc();
+ main_test_libdw();
+ main_test_eventfd();
+ main_test_libelf_getphdrnum();
+ main_test_libelf_gelf_getnote();
+ main_test_libelf_getshdrstrndx();
+ main_test_libslang();
+ main_test_backtrace();
+ main_test_libnuma();
+ main_test_numa_num_possible_cpus();
+ main_test_timerfd();
+ main_test_stackprotector_all();
+ main_test_zlib();
+ main_test_pthread_attr_setaffinity_np();
+ main_test_pthread_barrier();
+ main_test_lzma();
+ main_test_bpf();
+ main_test_scandirat();
+ main_test_sched_getcpu();
+ main_test_sdt();
+ main_test_setns();
+ main_test_libaio();
+ main_test_reallocarray();
+ main_test_libzstd();
+ main_test_libtraceevent();
+ main_test_libopenssl();
+
+ return 0;
+}
diff --git a/tools/build/feature/test-babeltrace2-ctf-writer.c b/tools/build/feature/test-babeltrace2-ctf-writer.c
new file mode 100644
index 000000000..9c89082e9
--- /dev/null
+++ b/tools/build/feature/test-babeltrace2-ctf-writer.c
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <babeltrace2-ctf-writer/writer.h>
+
+int main(void)
+{
+ bt_ctf_stream_class_get_packet_context_type((void *) 0);
+ return 0;
+}
diff --git a/tools/build/feature/test-backtrace.c b/tools/build/feature/test-backtrace.c
new file mode 100644
index 000000000..7962fbad6
--- /dev/null
+++ b/tools/build/feature/test-backtrace.c
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <execinfo.h>
+#include <stdio.h>
+
+int main(void)
+{
+ void *backtrace_fns[10];
+ int entries;
+
+ entries = backtrace(backtrace_fns, 10);
+ backtrace_symbols_fd(backtrace_fns, entries, 1);
+
+ return 0;
+}
diff --git a/tools/build/feature/test-bionic.c b/tools/build/feature/test-bionic.c
new file mode 100644
index 000000000..4bcc97765
--- /dev/null
+++ b/tools/build/feature/test-bionic.c
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <android/api-level.h>
+
+int main(void)
+{
+ return __ANDROID_API__;
+}
diff --git a/tools/build/feature/test-bpf.c b/tools/build/feature/test-bpf.c
new file mode 100644
index 000000000..89d59674f
--- /dev/null
+++ b/tools/build/feature/test-bpf.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <asm/unistd.h>
+#include <linux/bpf.h>
+#include <unistd.h>
+
+#ifndef __NR_bpf
+# if defined(__i386__)
+# define __NR_bpf 357
+# elif defined(__x86_64__)
+# define __NR_bpf 321
+# elif defined(__aarch64__)
+# define __NR_bpf 280
+# elif defined(__sparc__)
+# define __NR_bpf 349
+# elif defined(__s390__)
+# define __NR_bpf 351
+# elif defined(__mips__) && defined(_ABIO32)
+# define __NR_bpf 4355
+# elif defined(__mips__) && defined(_ABIN32)
+# define __NR_bpf 6319
+# elif defined(__mips__) && defined(_ABI64)
+# define __NR_bpf 5315
+# elif defined(__loongarch__)
+# define __NR_bpf 280
+# else
+# error __NR_bpf not defined. libbpf does not support your arch.
+# endif
+#endif
+
+int main(void)
+{
+ union bpf_attr attr;
+
+ /* Check fields in attr */
+ attr.prog_type = BPF_PROG_TYPE_KPROBE;
+ attr.insn_cnt = 0;
+ attr.insns = 0;
+ attr.license = 0;
+ attr.log_buf = 0;
+ attr.log_size = 0;
+ attr.log_level = 0;
+ attr.kern_version = 0;
+ attr.prog_flags = 0;
+
+ /*
+ * Test existence of __NR_bpf and BPF_PROG_LOAD.
+ * This call should fail if we run the testcase.
+ */
+ return syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr)) == 0;
+}
diff --git a/tools/build/feature/test-clang-bpf-co-re.c b/tools/build/feature/test-clang-bpf-co-re.c
new file mode 100644
index 000000000..cb5265bfd
--- /dev/null
+++ b/tools/build/feature/test-clang-bpf-co-re.c
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2020 Facebook
+
+struct test {
+ int a;
+ int b;
+} __attribute__((preserve_access_index));
+
+volatile struct test global_value_for_test = {};
diff --git a/tools/build/feature/test-compile.c b/tools/build/feature/test-compile.c
new file mode 100644
index 000000000..9821b8271
--- /dev/null
+++ b/tools/build/feature/test-compile.c
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stdio.h>
+int main(void)
+{
+ printf("Hello World!\n");
+ return 0;
+}
diff --git a/tools/build/feature/test-cplus-demangle.c b/tools/build/feature/test-cplus-demangle.c
new file mode 100644
index 000000000..2ba56474a
--- /dev/null
+++ b/tools/build/feature/test-cplus-demangle.c
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
+extern int printf(const char *format, ...);
+extern char *cplus_demangle(const char *, int);
+
+int main(void)
+{
+ char symbol[4096] = "FieldName__9ClassNameFd";
+ char *tmp;
+
+ tmp = cplus_demangle(symbol, 0);
+
+ printf("demangled symbol: {%s}\n", tmp);
+
+ return 0;
+}
diff --git a/tools/build/feature/test-cxa-demangle.cpp b/tools/build/feature/test-cxa-demangle.cpp
new file mode 100644
index 000000000..a3e712f65
--- /dev/null
+++ b/tools/build/feature/test-cxa-demangle.cpp
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stdio.h>
+#include <stdlib.h>
+#include <cxxabi.h>
+
+int main(void)
+{
+ size_t len = 256;
+ char *output = (char*)malloc(len);
+ int status;
+
+ output = abi::__cxa_demangle("FieldName__9ClassNameFd", output, &len, &status);
+
+ printf("demangled symbol: {%s}\n", output);
+
+ return 0;
+}
diff --git a/tools/build/feature/test-disassembler-four-args.c b/tools/build/feature/test-disassembler-four-args.c
new file mode 100644
index 000000000..45ce65cfd
--- /dev/null
+++ b/tools/build/feature/test-disassembler-four-args.c
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <bfd.h>
+#include <dis-asm.h>
+
+int main(void)
+{
+ bfd *abfd = bfd_openr(NULL, NULL);
+
+ disassembler(bfd_get_arch(abfd),
+ bfd_big_endian(abfd),
+ bfd_get_mach(abfd),
+ abfd);
+
+ return 0;
+}
diff --git a/tools/build/feature/test-disassembler-init-styled.c b/tools/build/feature/test-disassembler-init-styled.c
new file mode 100644
index 000000000..f1ce0ec3b
--- /dev/null
+++ b/tools/build/feature/test-disassembler-init-styled.c
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stdio.h>
+#include <dis-asm.h>
+
+int main(void)
+{
+ struct disassemble_info info;
+
+ init_disassemble_info(&info, stdout,
+ NULL, NULL);
+
+ return 0;
+}
diff --git a/tools/build/feature/test-eventfd.c b/tools/build/feature/test-eventfd.c
new file mode 100644
index 000000000..f4de7ef00
--- /dev/null
+++ b/tools/build/feature/test-eventfd.c
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
+
+#include <sys/eventfd.h>
+
+int main(void)
+{
+ return eventfd(0, EFD_NONBLOCK);
+}
diff --git a/tools/build/feature/test-file-handle.c b/tools/build/feature/test-file-handle.c
new file mode 100644
index 000000000..4d3b03b27
--- /dev/null
+++ b/tools/build/feature/test-file-handle.c
@@ -0,0 +1,17 @@
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <inttypes.h>
+
+int main(void)
+{
+ struct {
+ struct file_handle fh;
+ uint64_t cgroup_id;
+ } handle;
+ int mount_id;
+
+ name_to_handle_at(AT_FDCWD, "/", &handle.fh, &mount_id, 0);
+ return 0;
+}
diff --git a/tools/build/feature/test-fortify-source.c b/tools/build/feature/test-fortify-source.c
new file mode 100644
index 000000000..c8a57194f
--- /dev/null
+++ b/tools/build/feature/test-fortify-source.c
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stdio.h>
+
+int main(void)
+{
+ return puts("hi");
+}
diff --git a/tools/build/feature/test-gettid.c b/tools/build/feature/test-gettid.c
new file mode 100644
index 000000000..ef24e42d3
--- /dev/null
+++ b/tools/build/feature/test-gettid.c
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2019, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
+#define _GNU_SOURCE
+#include <unistd.h>
+
+int main(void)
+{
+ return gettid();
+}
+
+#undef _GNU_SOURCE
diff --git a/tools/build/feature/test-glibc.c b/tools/build/feature/test-glibc.c
new file mode 100644
index 000000000..20a250419
--- /dev/null
+++ b/tools/build/feature/test-glibc.c
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stdlib.h>
+
+#if !defined(__UCLIBC__)
+#include <gnu/libc-version.h>
+#else
+#define XSTR(s) STR(s)
+#define STR(s) #s
+#endif
+
+int main(void)
+{
+#if !defined(__UCLIBC__)
+ const char *version = gnu_get_libc_version();
+#else
+ const char *version = XSTR(__GLIBC__) "." XSTR(__GLIBC_MINOR__);
+#endif
+
+ return version == NULL;
+}
diff --git a/tools/build/feature/test-gtk2-infobar.c b/tools/build/feature/test-gtk2-infobar.c
new file mode 100644
index 000000000..b1b716dd5
--- /dev/null
+++ b/tools/build/feature/test-gtk2-infobar.c
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+#pragma GCC diagnostic ignored "-Wstrict-prototypes"
+#include <gtk/gtk.h>
+#pragma GCC diagnostic error "-Wstrict-prototypes"
+
+int main(int argc, char *argv[])
+{
+ gtk_init(&argc, &argv);
+ gtk_info_bar_new();
+
+ return 0;
+}
diff --git a/tools/build/feature/test-gtk2.c b/tools/build/feature/test-gtk2.c
new file mode 100644
index 000000000..2aaf4bfc2
--- /dev/null
+++ b/tools/build/feature/test-gtk2.c
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0
+#pragma GCC diagnostic ignored "-Wstrict-prototypes"
+#include <gtk/gtk.h>
+#pragma GCC diagnostic error "-Wstrict-prototypes"
+
+int main(int argc, char *argv[])
+{
+ gtk_init(&argc, &argv);
+
+ return 0;
+}
diff --git a/tools/build/feature/test-hello.c b/tools/build/feature/test-hello.c
new file mode 100644
index 000000000..c8a57194f
--- /dev/null
+++ b/tools/build/feature/test-hello.c
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stdio.h>
+
+int main(void)
+{
+ return puts("hi");
+}
diff --git a/tools/build/feature/test-jvmti-cmlr.c b/tools/build/feature/test-jvmti-cmlr.c
new file mode 100644
index 000000000..c27b5b71a
--- /dev/null
+++ b/tools/build/feature/test-jvmti-cmlr.c
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <jvmti.h>
+#include <jvmticmlr.h>
+
+int main(void)
+{
+ jvmtiCompiledMethodLoadInlineRecord rec __attribute__((unused));
+ jvmtiCompiledMethodLoadRecordHeader hdr __attribute__((unused));
+ PCStackInfo p __attribute__((unused));
+ return 0;
+}
diff --git a/tools/build/feature/test-jvmti.c b/tools/build/feature/test-jvmti.c
new file mode 100644
index 000000000..799916d2e
--- /dev/null
+++ b/tools/build/feature/test-jvmti.c
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <jvmti.h>
+
+int main(void)
+{
+ JavaVM jvm __attribute__((unused));
+ jvmtiEventCallbacks cb __attribute__((unused));
+ jvmtiCapabilities caps __attribute__((unused));
+ jvmtiJlocationFormat format __attribute__((unused));
+ jvmtiEnv jvmti __attribute__((unused));
+
+ return 0;
+}
diff --git a/tools/build/feature/test-libaio.c b/tools/build/feature/test-libaio.c
new file mode 100644
index 000000000..932133c9a
--- /dev/null
+++ b/tools/build/feature/test-libaio.c
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <aio.h>
+
+int main(void)
+{
+ struct aiocb aiocb;
+
+ aiocb.aio_fildes = 0;
+ aiocb.aio_offset = 0;
+ aiocb.aio_buf = 0;
+ aiocb.aio_nbytes = 0;
+ aiocb.aio_reqprio = 0;
+ aiocb.aio_sigevent.sigev_notify = 1 /*SIGEV_NONE*/;
+
+ return (int)aio_return(&aiocb);
+}
diff --git a/tools/build/feature/test-libbfd-threadsafe.c b/tools/build/feature/test-libbfd-threadsafe.c
new file mode 100644
index 000000000..fe97f95f6
--- /dev/null
+++ b/tools/build/feature/test-libbfd-threadsafe.c
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <bfd.h>
+
+static bool lock(void *unused)
+{
+ return true;
+}
+
+static bool unlock(void *unused)
+{
+ return true;
+}
+
+int main(void)
+{
+ /* Check for presence of new thread safety API (version 2.42) */
+ return !bfd_thread_init(lock, unlock, NULL);
+}
diff --git a/tools/build/feature/test-libbfd.c b/tools/build/feature/test-libbfd.c
new file mode 100644
index 000000000..afa46b046
--- /dev/null
+++ b/tools/build/feature/test-libbfd.c
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <bfd.h>
+
+extern int printf(const char *format, ...);
+
+int main(void)
+{
+ char symbol[4096] = "FieldName__9ClassNameFd";
+ char *tmp;
+
+ tmp = bfd_demangle(0, symbol, 0);
+
+ printf("demangled symbol: {%s}\n", tmp);
+
+ return 0;
+}
diff --git a/tools/build/feature/test-libbpf.c b/tools/build/feature/test-libbpf.c
new file mode 100644
index 000000000..cd9989f52
--- /dev/null
+++ b/tools/build/feature/test-libbpf.c
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <bpf/libbpf.h>
+
+#if !defined(LIBBPF_MAJOR_VERSION) || (LIBBPF_MAJOR_VERSION < 1)
+#error At least libbpf 1.0 is required for Linux tools.
+#endif
+
+int main(void)
+{
+ return bpf_object__open("test") ? 0 : -1;
+}
diff --git a/tools/build/feature/test-libcap.c b/tools/build/feature/test-libcap.c
new file mode 100644
index 000000000..d2a2e1521
--- /dev/null
+++ b/tools/build/feature/test-libcap.c
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <sys/capability.h>
+#include <linux/capability.h>
+
+int main(void)
+{
+ cap_flag_value_t val;
+ cap_t caps = cap_get_proc();
+
+ if (!caps)
+ return 1;
+
+ if (cap_get_flag(caps, CAP_SYS_ADMIN, CAP_EFFECTIVE, &val) != 0)
+ return 1;
+
+ if (cap_free(caps) != 0)
+ return 1;
+
+ return 0;
+}
diff --git a/tools/build/feature/test-libcapstone.c b/tools/build/feature/test-libcapstone.c
new file mode 100644
index 000000000..fbe8dba18
--- /dev/null
+++ b/tools/build/feature/test-libcapstone.c
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <capstone/capstone.h>
+
+int main(void)
+{
+ csh handle;
+
+ cs_open(CS_ARCH_X86, CS_MODE_64, &handle);
+ return 0;
+}
diff --git a/tools/build/feature/test-libcheck.c b/tools/build/feature/test-libcheck.c
new file mode 100644
index 000000000..cfb8d452e
--- /dev/null
+++ b/tools/build/feature/test-libcheck.c
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <check.h>
+
+int main(void)
+{
+ Suite *s = suite_create("test");
+ return s == 0;
+}
diff --git a/tools/build/feature/test-libcpupower.c b/tools/build/feature/test-libcpupower.c
new file mode 100644
index 000000000..a346aa332
--- /dev/null
+++ b/tools/build/feature/test-libcpupower.c
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <cpuidle.h>
+
+int main(void)
+{
+ int rv = cpuidle_state_count(0);
+ return rv;
+}
diff --git a/tools/build/feature/test-libdebuginfod.c b/tools/build/feature/test-libdebuginfod.c
new file mode 100644
index 000000000..823f9fa93
--- /dev/null
+++ b/tools/build/feature/test-libdebuginfod.c
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <elfutils/debuginfod.h>
+
+int main(void)
+{
+ debuginfod_client* c = debuginfod_begin();
+ return !!c;
+}
diff --git a/tools/build/feature/test-libdw.c b/tools/build/feature/test-libdw.c
new file mode 100644
index 000000000..aabd63ca7
--- /dev/null
+++ b/tools/build/feature/test-libdw.c
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stdlib.h>
+#include <dwarf.h>
+#include <elfutils/libdw.h>
+#include <elfutils/libdwfl.h>
+#include <elfutils/version.h>
+
+int test_libdw(void)
+{
+ Dwarf *dbg = dwarf_begin(0, DWARF_C_READ);
+
+ return dbg == NULL;
+}
+
+int test_libdw_unwind(void)
+{
+ /*
+ * This function is guarded via: __nonnull_attribute__ (1, 2).
+ * Passing '1' as arguments value. This code is never executed,
+ * only compiled.
+ */
+ dwfl_thread_getframes((void *) 1, (void *) 1, NULL);
+ return 0;
+}
+
+int test_libdw_getlocations(void)
+{
+ Dwarf_Addr base, start, end;
+ Dwarf_Attribute attr;
+ Dwarf_Op *op;
+ size_t nops;
+ ptrdiff_t offset = 0;
+
+ return (int)dwarf_getlocations(&attr, offset, &base, &start, &end, &op, &nops);
+}
+
+int test_libdw_getcfi(void)
+{
+ Dwarf *dwarf = NULL;
+
+ return dwarf_getcfi(dwarf) == NULL;
+}
+
+int test_elfutils(void)
+{
+ Dwarf_CFI *cfi = NULL;
+
+ dwarf_cfi_end(cfi);
+ return 0;
+}
+
+int main(void)
+{
+ return test_libdw() + test_libdw_unwind() + test_libdw_getlocations() +
+ test_libdw_getcfi() + test_elfutils();
+}
diff --git a/tools/build/feature/test-libelf-gelf_getnote.c b/tools/build/feature/test-libelf-gelf_getnote.c
new file mode 100644
index 000000000..e06121161
--- /dev/null
+++ b/tools/build/feature/test-libelf-gelf_getnote.c
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stdlib.h>
+#include <gelf.h>
+
+int main(void)
+{
+ return gelf_getnote(NULL, 0, NULL, NULL, NULL) == 0;
+}
diff --git a/tools/build/feature/test-libelf-getphdrnum.c b/tools/build/feature/test-libelf-getphdrnum.c
new file mode 100644
index 000000000..96a7f8d30
--- /dev/null
+++ b/tools/build/feature/test-libelf-getphdrnum.c
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <libelf.h>
+
+int main(void)
+{
+ size_t dst;
+
+ return elf_getphdrnum(0, &dst);
+}
diff --git a/tools/build/feature/test-libelf-getshdrstrndx.c b/tools/build/feature/test-libelf-getshdrstrndx.c
new file mode 100644
index 000000000..ae9f2fff5
--- /dev/null
+++ b/tools/build/feature/test-libelf-getshdrstrndx.c
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <libelf.h>
+
+int main(void)
+{
+ size_t dst;
+
+ return elf_getshdrstrndx(0, &dst);
+}
diff --git a/tools/build/feature/test-libelf-zstd.c b/tools/build/feature/test-libelf-zstd.c
new file mode 100644
index 000000000..a1324a1db
--- /dev/null
+++ b/tools/build/feature/test-libelf-zstd.c
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stddef.h>
+#include <libelf.h>
+
+int main(void)
+{
+ elf_compress(NULL, ELFCOMPRESS_ZSTD, 0);
+ return 0;
+}
diff --git a/tools/build/feature/test-libelf.c b/tools/build/feature/test-libelf.c
new file mode 100644
index 000000000..2dbb6ea87
--- /dev/null
+++ b/tools/build/feature/test-libelf.c
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <libelf.h>
+
+int main(void)
+{
+ Elf *elf = elf_begin(0, ELF_C_READ, 0);
+
+ return !!elf;
+}
diff --git a/tools/build/feature/test-libnuma.c b/tools/build/feature/test-libnuma.c
new file mode 100644
index 000000000..b3aa59f8b
--- /dev/null
+++ b/tools/build/feature/test-libnuma.c
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <numa.h>
+#include <numaif.h>
+
+int main(void)
+{
+ numa_available();
+
+ return 0;
+}
diff --git a/tools/build/feature/test-libopencsd.c b/tools/build/feature/test-libopencsd.c
new file mode 100644
index 000000000..4cfcef9da
--- /dev/null
+++ b/tools/build/feature/test-libopencsd.c
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <opencsd/c_api/opencsd_c_api.h>
+
+/*
+ * Check OpenCSD library version is sufficient to provide required features
+ */
+#define OCSD_MIN_VER ((1 << 16) | (2 << 8) | (1))
+#if !defined(OCSD_VER_NUM) || (OCSD_VER_NUM < OCSD_MIN_VER)
+#error "OpenCSD >= 1.2.1 is required"
+#endif
+
+int main(void)
+{
+ (void)ocsd_get_version();
+ return 0;
+}
diff --git a/tools/build/feature/test-libopenssl.c b/tools/build/feature/test-libopenssl.c
new file mode 100644
index 000000000..168c45894
--- /dev/null
+++ b/tools/build/feature/test-libopenssl.c
@@ -0,0 +1,7 @@
+#include <openssl/ssl.h>
+#include <openssl/opensslv.h>
+
+int main(void)
+{
+ return SSL_library_init();
+}
diff --git a/tools/build/feature/test-libperl.c b/tools/build/feature/test-libperl.c
new file mode 100644
index 000000000..0415f437e
--- /dev/null
+++ b/tools/build/feature/test-libperl.c
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <EXTERN.h>
+#include <perl.h>
+
+int main(void)
+{
+ perl_alloc();
+
+ return 0;
+}
diff --git a/tools/build/feature/test-libpfm4.c b/tools/build/feature/test-libpfm4.c
new file mode 100644
index 000000000..af49b2594
--- /dev/null
+++ b/tools/build/feature/test-libpfm4.c
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <sys/types.h>
+#include <perfmon/pfmlib.h>
+
+int main(void)
+{
+ pfm_initialize();
+ return 0;
+}
diff --git a/tools/build/feature/test-libpython.c b/tools/build/feature/test-libpython.c
new file mode 100644
index 000000000..371c9113e
--- /dev/null
+++ b/tools/build/feature/test-libpython.c
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <Python.h>
+
+int main(void)
+{
+ Py_Initialize();
+
+ return 0;
+}
+#undef _GNU_SOURCE
diff --git a/tools/build/feature/test-libslang.c b/tools/build/feature/test-libslang.c
new file mode 100644
index 000000000..9cbff8d1d
--- /dev/null
+++ b/tools/build/feature/test-libslang.c
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <slang.h>
+
+int main(void)
+{
+ return SLsmg_init_smg();
+}
diff --git a/tools/build/feature/test-libtraceevent.c b/tools/build/feature/test-libtraceevent.c
new file mode 100644
index 000000000..804ad80db
--- /dev/null
+++ b/tools/build/feature/test-libtraceevent.c
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <trace-seq.h>
+
+int main(void)
+{
+ int rv = 0;
+ struct trace_seq s;
+ trace_seq_init(&s);
+ rv += !(s.state == TRACE_SEQ__GOOD);
+ trace_seq_destroy(&s);
+ return rv;
+}
diff --git a/tools/build/feature/test-libtracefs.c b/tools/build/feature/test-libtracefs.c
new file mode 100644
index 000000000..29a757a7d
--- /dev/null
+++ b/tools/build/feature/test-libtracefs.c
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <tracefs.h>
+
+int main(void)
+{
+ struct tracefs_instance *inst = tracefs_instance_create("dummy");
+
+ tracefs_instance_destroy(inst);
+ return 0;
+}
diff --git a/tools/build/feature/test-libunwind-debug-frame.c b/tools/build/feature/test-libunwind-debug-frame.c
new file mode 100644
index 000000000..4c57e3700
--- /dev/null
+++ b/tools/build/feature/test-libunwind-debug-frame.c
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stdlib.h>
+
+extern int
+UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug,
+ unw_word_t ip, unw_word_t segbase,
+ const char *obj_name, unw_word_t start,
+ unw_word_t end);
+
+#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame)
+
+int main(void)
+{
+ dwarf_find_debug_frame(0, NULL, 0, 0, NULL, 0, 0);
+ return 0;
+}
diff --git a/tools/build/feature/test-libunwind.c b/tools/build/feature/test-libunwind.c
new file mode 100644
index 000000000..5af5dc3a7
--- /dev/null
+++ b/tools/build/feature/test-libunwind.c
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stdlib.h>
+
+extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
+ unw_word_t ip,
+ unw_dyn_info_t *di,
+ unw_proc_info_t *pi,
+ int need_unwind_info, void *arg);
+
+
+#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
+
+static unw_accessors_t accessors;
+
+int main(void)
+{
+ unw_addr_space_t addr_space;
+
+ addr_space = unw_create_addr_space(&accessors, 0);
+ if (addr_space)
+ return 0;
+
+ unw_init_remote(NULL, addr_space, NULL);
+ dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL);
+
+ return 0;
+}
diff --git a/tools/build/feature/test-libzstd.c b/tools/build/feature/test-libzstd.c
new file mode 100644
index 000000000..55268c01b
--- /dev/null
+++ b/tools/build/feature/test-libzstd.c
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <zstd.h>
+
+int main(void)
+{
+ ZSTD_CStream *cstream;
+
+ cstream = ZSTD_createCStream();
+ ZSTD_freeCStream(cstream);
+
+ return 0;
+}
diff --git a/tools/build/feature/test-llvm-perf.cpp b/tools/build/feature/test-llvm-perf.cpp
new file mode 100644
index 000000000..a8cbb67e3
--- /dev/null
+++ b/tools/build/feature/test-llvm-perf.cpp
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/raw_ostream.h"
+
+#if LLVM_VERSION_MAJOR < 13
+# error "Perf requires llvm-devel/llvm-dev version 13 or greater"
+#endif
+
+int main()
+{
+ llvm::errs() << "Hello World!\n";
+ llvm::llvm_shutdown();
+ return 0;
+}
diff --git a/tools/build/feature/test-llvm.cpp b/tools/build/feature/test-llvm.cpp
new file mode 100644
index 000000000..88a3d1bdd
--- /dev/null
+++ b/tools/build/feature/test-llvm.cpp
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/raw_ostream.h"
+#define NUM_VERSION (((LLVM_VERSION_MAJOR) << 16) + (LLVM_VERSION_MINOR << 8) + LLVM_VERSION_PATCH)
+
+#if NUM_VERSION < 0x030900
+# error "LLVM version too low"
+#endif
+int main()
+{
+ llvm::errs() << "Hello World!\n";
+ llvm::llvm_shutdown();
+ return 0;
+}
diff --git a/tools/build/feature/test-lzma.c b/tools/build/feature/test-lzma.c
new file mode 100644
index 000000000..b57103774
--- /dev/null
+++ b/tools/build/feature/test-lzma.c
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <lzma.h>
+
+int main(void)
+{
+ lzma_stream strm = LZMA_STREAM_INIT;
+ lzma_ret ret;
+
+ ret = lzma_stream_decoder(&strm, UINT64_MAX, LZMA_CONCATENATED);
+ return ret ? -1 : 0;
+}
diff --git a/tools/build/feature/test-numa_num_possible_cpus.c b/tools/build/feature/test-numa_num_possible_cpus.c
new file mode 100644
index 000000000..573d07b9c
--- /dev/null
+++ b/tools/build/feature/test-numa_num_possible_cpus.c
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <numa.h>
+
+int main(void)
+{
+ return numa_num_possible_cpus();
+}
diff --git a/tools/build/feature/test-pthread-attr-setaffinity-np.c b/tools/build/feature/test-pthread-attr-setaffinity-np.c
new file mode 100644
index 000000000..38c71131c
--- /dev/null
+++ b/tools/build/feature/test-pthread-attr-setaffinity-np.c
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stdint.h>
+#include <pthread.h>
+#include <sched.h>
+
+int main(void)
+{
+ int ret = 0;
+ pthread_attr_t thread_attr;
+ cpu_set_t cs;
+
+ pthread_attr_init(&thread_attr);
+ CPU_ZERO(&cs);
+
+ ret = pthread_attr_setaffinity_np(&thread_attr, sizeof(cs), &cs);
+
+ return ret;
+}
diff --git a/tools/build/feature/test-pthread-barrier.c b/tools/build/feature/test-pthread-barrier.c
new file mode 100644
index 000000000..0558d9334
--- /dev/null
+++ b/tools/build/feature/test-pthread-barrier.c
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stdint.h>
+#include <pthread.h>
+
+int main(void)
+{
+ pthread_barrier_t barrier;
+
+ pthread_barrier_init(&barrier, NULL, 1);
+ pthread_barrier_wait(&barrier);
+ return pthread_barrier_destroy(&barrier);
+}
diff --git a/tools/build/feature/test-reallocarray.c b/tools/build/feature/test-reallocarray.c
new file mode 100644
index 000000000..8f6743e31
--- /dev/null
+++ b/tools/build/feature/test-reallocarray.c
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
+#define _GNU_SOURCE
+#include <stdlib.h>
+
+int main(void)
+{
+ return !!reallocarray(NULL, 1, 1);
+}
+
+#undef _GNU_SOURCE
diff --git a/tools/build/feature/test-scandirat.c b/tools/build/feature/test-scandirat.c
new file mode 100644
index 000000000..d7e19e185
--- /dev/null
+++ b/tools/build/feature/test-scandirat.c
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <dirent.h>
+
+int main(void)
+{
+ // expects non-NULL, arg3 is 'restrict' so "pointers" have to be different
+ return scandirat(/*dirfd=*/ 0, /*dirp=*/ (void *)1, /*namelist=*/ (void *)2, /*filter=*/ (void *)3, /*compar=*/ (void *)4);
+}
+
+#undef _GNU_SOURCE
diff --git a/tools/build/feature/test-sched_getcpu.c b/tools/build/feature/test-sched_getcpu.c
new file mode 100644
index 000000000..48995ac79
--- /dev/null
+++ b/tools/build/feature/test-sched_getcpu.c
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <sched.h>
+
+int main(void)
+{
+ return sched_getcpu();
+}
+
+#undef _GNU_SOURCE
diff --git a/tools/build/feature/test-sdt.c b/tools/build/feature/test-sdt.c
new file mode 100644
index 000000000..22737b0da
--- /dev/null
+++ b/tools/build/feature/test-sdt.c
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <sys/sdt.h>
+
+int main(void)
+{
+ DTRACE_PROBE(provider, name);
+ return 0;
+}
diff --git a/tools/build/feature/test-setns.c b/tools/build/feature/test-setns.c
new file mode 100644
index 000000000..2757c201e
--- /dev/null
+++ b/tools/build/feature/test-setns.c
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
+#define _GNU_SOURCE
+#include <sched.h>
+
+int main(void)
+{
+ return setns(0, 0);
+}
+#undef _GNU_SOURCE
diff --git a/tools/build/feature/test-stackprotector-all.c b/tools/build/feature/test-stackprotector-all.c
new file mode 100644
index 000000000..c8a57194f
--- /dev/null
+++ b/tools/build/feature/test-stackprotector-all.c
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stdio.h>
+
+int main(void)
+{
+ return puts("hi");
+}
diff --git a/tools/build/feature/test-timerfd.c b/tools/build/feature/test-timerfd.c
new file mode 100644
index 000000000..9c72c697a
--- /dev/null
+++ b/tools/build/feature/test-timerfd.c
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * test for timerfd functions used by perf-kvm-stat-live
+ */
+#include <sys/timerfd.h>
+
+int main(void)
+{
+ struct itimerspec new_value;
+
+ int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
+ if (fd < 0)
+ return 1;
+
+ if (timerfd_settime(fd, 0, &new_value, NULL) != 0)
+ return 1;
+
+ return 0;
+}
diff --git a/tools/build/feature/test-zlib.c b/tools/build/feature/test-zlib.c
new file mode 100644
index 000000000..da6c35794
--- /dev/null
+++ b/tools/build/feature/test-zlib.c
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <zlib.h>
+
+int main(void)
+{
+ z_stream zs;
+
+ inflateInit(&zs);
+ return 0;
+}
diff --git a/tools/build/fixdep.c b/tools/build/fixdep.c
new file mode 100644
index 000000000..2501fea7a
--- /dev/null
+++ b/tools/build/fixdep.c
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * "Optimize" a list of dependencies as spit out by gcc -MD
+ * for the build framework.
+ *
+ * Original author:
+ * Copyright 2002 by Kai Germaschewski <kai.germaschewski@gmx.de>
+ *
+ * This code has been borrowed from kbuild's fixdep (scripts/basic/fixdep.c),
+ * Please check it for detailed explanation. This fixdep borow only the
+ * base transformation of dependecies without the CONFIG mangle.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+
+char *target;
+char *depfile;
+char *cmdline;
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: fixdep <depfile> <target> <cmdline>\n");
+ exit(1);
+}
+
+/*
+ * Print out the commandline prefixed with cmd_<target filename> :=
+ */
+static void print_cmdline(void)
+{
+ printf("cmd_%s := %s\n\n", target, cmdline);
+}
+
+/*
+ * Important: The below generated source_foo.o and deps_foo.o variable
+ * assignments are parsed not only by make, but also by the rather simple
+ * parser in scripts/mod/sumversion.c.
+ */
+static void parse_dep_file(void *map, size_t len)
+{
+ char *m = map;
+ char *end = m + len;
+ char *p;
+ char s[PATH_MAX];
+ int is_target, has_target = 0;
+ int saw_any_target = 0;
+ int is_first_dep = 0;
+
+ while (m < end) {
+ /* Skip any "white space" */
+ while (m < end && (*m == ' ' || *m == '\\' || *m == '\n'))
+ m++;
+ /* Find next "white space" */
+ p = m;
+ while (p < end && *p != ' ' && *p != '\\' && *p != '\n')
+ p++;
+ /* Is the token we found a target name? */
+ is_target = (*(p-1) == ':');
+ /* Don't write any target names into the dependency file */
+ if (is_target) {
+ /* The /next/ file is the first dependency */
+ is_first_dep = 1;
+ has_target = 1;
+ } else if (has_target) {
+ /* Save this token/filename */
+ memcpy(s, m, p-m);
+ s[p - m] = 0;
+
+ /*
+ * Do not list the source file as dependency,
+ * so that kbuild is not confused if a .c file
+ * is rewritten into .S or vice versa. Storing
+ * it in source_* is needed for modpost to
+ * compute srcversions.
+ */
+ if (is_first_dep) {
+ /*
+ * If processing the concatenation of
+ * multiple dependency files, only
+ * process the first target name, which
+ * will be the original source name,
+ * and ignore any other target names,
+ * which will be intermediate temporary
+ * files.
+ */
+ if (!saw_any_target) {
+ saw_any_target = 1;
+ printf("source_%s := %s\n\n",
+ target, s);
+ printf("deps_%s := \\\n",
+ target);
+ }
+ is_first_dep = 0;
+ } else
+ printf(" %s \\\n", s);
+ }
+ /*
+ * Start searching for next token immediately after the first
+ * "whitespace" character that follows this token.
+ */
+ m = p + 1;
+ }
+
+ if (!saw_any_target) {
+ fprintf(stderr, "fixdep: parse error; no targets found\n");
+ exit(1);
+ }
+
+ printf("\n%s: $(deps_%s)\n\n", target, target);
+ printf("$(deps_%s):\n", target);
+}
+
+static void print_deps(void)
+{
+ struct stat st;
+ int fd;
+ void *map;
+
+ fd = open(depfile, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "fixdep: error opening depfile: ");
+ perror(depfile);
+ exit(2);
+ }
+ if (fstat(fd, &st) < 0) {
+ fprintf(stderr, "fixdep: error fstat'ing depfile: ");
+ perror(depfile);
+ exit(2);
+ }
+ if (st.st_size == 0) {
+ fprintf(stderr, "fixdep: %s is empty\n", depfile);
+ close(fd);
+ return;
+ }
+ map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if ((long) map == -1) {
+ perror("fixdep: mmap");
+ close(fd);
+ return;
+ }
+
+ parse_dep_file(map, st.st_size);
+
+ munmap(map, st.st_size);
+
+ close(fd);
+}
+
+int main(int argc, char **argv)
+{
+ if (argc != 4)
+ usage();
+
+ depfile = argv[1];
+ target = argv[2];
+ cmdline = argv[3];
+
+ print_cmdline();
+ print_deps();
+
+ return 0;
+}
diff --git a/tools/build/tests/ex/Build b/tools/build/tests/ex/Build
new file mode 100644
index 000000000..4d502f9b1
--- /dev/null
+++ b/tools/build/tests/ex/Build
@@ -0,0 +1,11 @@
+ex-y += ex.o
+ex-y += a.o
+ex-y += b.o
+ex-y += b.o
+ex-y += empty/
+ex-y += empty2/
+ex-y += inc.o
+
+libex-y += c.o
+libex-y += d.o
+libex-y += arch/
diff --git a/tools/build/tests/ex/Makefile b/tools/build/tests/ex/Makefile
new file mode 100644
index 000000000..fee032e06
--- /dev/null
+++ b/tools/build/tests/ex/Makefile
@@ -0,0 +1,27 @@
+# SPDX-License-Identifier: GPL-2.0
+export srctree := $(abspath ../../../..)
+export CC := gcc
+export LD := ld
+export AR := ar
+
+ex:
+
+include $(srctree)/tools/build/Makefile.include
+
+ex: ex-in.o libex-in.o
+ $(CC) -o $@ $^
+
+ex.%: fixdep FORCE
+ make -f $(srctree)/tools/build/Makefile.build dir=. $@
+
+ex-in.o: fixdep FORCE
+ make $(build)=ex
+
+libex-in.o: fixdep FORCE
+ make $(build)=libex
+
+clean:
+ find . -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
+ rm -f ex ex.i ex.s
+
+.PHONY: FORCE
diff --git a/tools/build/tests/ex/a.c b/tools/build/tests/ex/a.c
new file mode 100644
index 000000000..66017a9f4
--- /dev/null
+++ b/tools/build/tests/ex/a.c
@@ -0,0 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
+
+int a(void)
+{
+ return 0;
+}
diff --git a/tools/build/tests/ex/arch/Build b/tools/build/tests/ex/arch/Build
new file mode 100644
index 000000000..55506189e
--- /dev/null
+++ b/tools/build/tests/ex/arch/Build
@@ -0,0 +1,2 @@
+libex-y += e.o
+libex-y += f.o
diff --git a/tools/build/tests/ex/arch/e.c b/tools/build/tests/ex/arch/e.c
new file mode 100644
index 000000000..f6ef585b5
--- /dev/null
+++ b/tools/build/tests/ex/arch/e.c
@@ -0,0 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
+
+int e(void)
+{
+ return 0;
+}
diff --git a/tools/build/tests/ex/arch/f.c b/tools/build/tests/ex/arch/f.c
new file mode 100644
index 000000000..bffd9c67e
--- /dev/null
+++ b/tools/build/tests/ex/arch/f.c
@@ -0,0 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
+
+int f(void)
+{
+ return 0;
+}
diff --git a/tools/build/tests/ex/b.c b/tools/build/tests/ex/b.c
new file mode 100644
index 000000000..2b29fb4d3
--- /dev/null
+++ b/tools/build/tests/ex/b.c
@@ -0,0 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
+
+int b(void)
+{
+ return 0;
+}
diff --git a/tools/build/tests/ex/c.c b/tools/build/tests/ex/c.c
new file mode 100644
index 000000000..a63b20ab8
--- /dev/null
+++ b/tools/build/tests/ex/c.c
@@ -0,0 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
+
+int c(void)
+{
+ return 0;
+}
diff --git a/tools/build/tests/ex/d.c b/tools/build/tests/ex/d.c
new file mode 100644
index 000000000..e114e8dca
--- /dev/null
+++ b/tools/build/tests/ex/d.c
@@ -0,0 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
+
+int d(void)
+{
+ return 0;
+}
diff --git a/tools/build/tests/ex/empty/Build b/tools/build/tests/ex/empty/Build
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tools/build/tests/ex/empty/Build
diff --git a/tools/build/tests/ex/empty2/README b/tools/build/tests/ex/empty2/README
new file mode 100644
index 000000000..2107cc5bf
--- /dev/null
+++ b/tools/build/tests/ex/empty2/README
@@ -0,0 +1,2 @@
+This directory is left intentionally without Build file
+to test proper nesting into Build-less directories.
diff --git a/tools/build/tests/ex/ex.c b/tools/build/tests/ex/ex.c
new file mode 100644
index 000000000..3c02756ef
--- /dev/null
+++ b/tools/build/tests/ex/ex.c
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0
+
+int a(void);
+int b(void);
+int c(void);
+int d(void);
+int e(void);
+int f(void);
+int inc(void);
+
+int main(void)
+{
+ a();
+ b();
+ c();
+ d();
+ e();
+ f();
+ inc();
+
+ return 0;
+}
diff --git a/tools/build/tests/ex/inc.c b/tools/build/tests/ex/inc.c
new file mode 100644
index 000000000..3636ab5bf
--- /dev/null
+++ b/tools/build/tests/ex/inc.c
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
+#ifdef INCLUDE
+#include "krava.h"
+#endif
+
+int inc(void)
+{
+ return 0;
+}
diff --git a/tools/build/tests/run.sh b/tools/build/tests/run.sh
new file mode 100755
index 000000000..2c54e4d43
--- /dev/null
+++ b/tools/build/tests/run.sh
@@ -0,0 +1,70 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+
+function test_ex {
+ make -C ex V=1 clean > ex.out 2>&1
+ make -C ex V=1 >> ex.out 2>&1
+
+ if [ ! -x ./ex/ex ]; then
+ echo FAILED
+ exit -1
+ fi
+
+ make -C ex V=1 clean > /dev/null 2>&1
+ rm -f ex.out
+}
+
+function test_ex_suffix {
+ make -C ex V=1 clean > ex.out 2>&1
+
+ # use -rR to disable make's builtin rules
+ make -rR -C ex V=1 ex.o >> ex.out 2>&1
+ make -rR -C ex V=1 ex.i >> ex.out 2>&1
+ make -rR -C ex V=1 ex.s >> ex.out 2>&1
+
+ if [ -x ./ex/ex ]; then
+ echo FAILED
+ exit -1
+ fi
+
+ if [ ! -f ./ex/ex.o -o ! -f ./ex/ex.i -o ! -f ./ex/ex.s ]; then
+ echo FAILED
+ exit -1
+ fi
+
+ make -C ex V=1 clean > /dev/null 2>&1
+ rm -f ex.out
+}
+
+function test_ex_include {
+ make -C ex V=1 clean > ex.out 2>&1
+
+ # build with krava.h include
+ touch ex/krava.h
+ make -C ex V=1 CFLAGS=-DINCLUDE >> ex.out 2>&1
+
+ if [ ! -x ./ex/ex ]; then
+ echo FAILED
+ exit -1
+ fi
+
+ # build without the include
+ rm -f ex/krava.h ex/ex
+ make -C ex V=1 >> ex.out 2>&1
+
+ if [ ! -x ./ex/ex ]; then
+ echo FAILED
+ exit -1
+ fi
+
+ make -C ex V=1 clean > /dev/null 2>&1
+ rm -f ex.out
+}
+
+echo -n Testing..
+
+test_ex
+test_ex_suffix
+test_ex_include
+
+echo OK