1# SPDX-License-Identifier: GPL-2.0-only 2feature_dir := $(srctree)/tools/build/feature 3 4ifneq ($(OUTPUT),) 5 OUTPUT_FEATURES = $(OUTPUT)feature/ 6 $(shell mkdir -p $(OUTPUT_FEATURES)) 7endif 8 9feature_check = $(eval $(feature_check_code)) 10define feature_check_code 11 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) 12endef 13 14feature_set = $(eval $(feature_set_code)) 15define feature_set_code 16 feature-$(1) := 1 17endef 18 19# 20# Build the feature check binaries in parallel, ignore errors, ignore return value and suppress output: 21# 22 23# 24# Note that this is not a complete list of all feature tests, just 25# those that are typically built on a fully configured system. 26# 27# [ Feature tests not mentioned here have to be built explicitly in 28# the rule that uses them - an example for that is the 'bionic' 29# feature check. ] 30# 31# These + the ones in FEATURE_TESTS_EXTRA are included in 32# tools/build/feature/test-all.c and we try to build it all together 33# then setting all those features to '1' meaning they are all enabled. 34# 35# There are things like fortify-source that will be set to 1 because test-all 36# is built with the flags needed to test if its enabled, resulting in 37# 38# $ rm -rf /tmp/b ; mkdir /tmp/b ; make -C tools/perf O=/tmp/b feature-dump 39# $ grep fortify-source /tmp/b/FEATURE-DUMP 40# feature-fortify-source=1 41# $ 42# 43# All the others should have lines in tools/build/feature/test-all.c like: 44# 45# #define main main_test_disassembler_init_styled 46# # include "test-disassembler-init-styled.c" 47# #undef main 48# 49# #define main main_test_libzstd 50# # include "test-libzstd.c" 51# #undef main 52# 53# int main(int argc, char *argv[]) 54# { 55# main_test_disassembler_four_args(); 56# main_test_libzstd(); 57# return 0; 58# } 59# 60# If the sample above works, then we end up with these lines in the FEATURE-DUMP 61# file: 62# 63# feature-disassembler-four-args=1 64# feature-libzstd=1 65# 66FEATURE_TESTS_BASIC := \ 67 backtrace \ 68 libdw \ 69 eventfd \ 70 fortify-source \ 71 get_current_dir_name \ 72 gettid \ 73 glibc \ 74 libbfd \ 75 libbfd-buildid \ 76 libcap \ 77 libelf \ 78 libelf-getphdrnum \ 79 libelf-gelf_getnote \ 80 libelf-getshdrstrndx \ 81 libnuma \ 82 numa_num_possible_cpus \ 83 libperl \ 84 libpython \ 85 libslang \ 86 libslang-include-subdir \ 87 libtraceevent \ 88 libtracefs \ 89 libcpupower \ 90 libcrypto \ 91 libunwind \ 92 pthread-attr-setaffinity-np \ 93 pthread-barrier \ 94 reallocarray \ 95 stackprotector-all \ 96 timerfd \ 97 zlib \ 98 lzma \ 99 get_cpuid \ 100 bpf \ 101 scandirat \ 102 sched_getcpu \ 103 sdt \ 104 setns \ 105 libaio \ 106 libzstd \ 107 disassembler-four-args \ 108 disassembler-init-styled \ 109 file-handle 110 111# FEATURE_TESTS_BASIC + FEATURE_TESTS_EXTRA is the complete list 112# of all feature tests 113FEATURE_TESTS_EXTRA := \ 114 bionic \ 115 compile-32 \ 116 compile-x32 \ 117 cplus-demangle \ 118 cxa-demangle \ 119 gtk2 \ 120 gtk2-infobar \ 121 hello \ 122 libbabeltrace \ 123 libcapstone \ 124 libbfd-liberty \ 125 libbfd-liberty-z \ 126 libopencsd \ 127 cxx \ 128 llvm \ 129 clang \ 130 libbpf \ 131 libbpf-btf__load_from_kernel_by_id \ 132 libbpf-bpf_prog_load \ 133 libbpf-bpf_object__next_program \ 134 libbpf-bpf_object__next_map \ 135 libbpf-bpf_program__set_insns \ 136 libbpf-bpf_create_map \ 137 libpfm4 \ 138 libdebuginfod \ 139 clang-bpf-co-re 140 141 142FEATURE_TESTS ?= $(FEATURE_TESTS_BASIC) 143 144ifeq ($(FEATURE_TESTS),all) 145 FEATURE_TESTS := $(FEATURE_TESTS_BASIC) $(FEATURE_TESTS_EXTRA) 146endif 147 148FEATURE_DISPLAY ?= \ 149 libdw \ 150 glibc \ 151 libbfd \ 152 libbfd-buildid \ 153 libcap \ 154 libelf \ 155 libnuma \ 156 numa_num_possible_cpus \ 157 libperl \ 158 libpython \ 159 libcrypto \ 160 libunwind \ 161 libcapstone \ 162 llvm-perf \ 163 zlib \ 164 lzma \ 165 get_cpuid \ 166 bpf \ 167 libaio \ 168 libzstd 169 170# 171# Declare group members of a feature to display the logical OR of the detection 172# result instead of each member result. 173# 174FEATURE_GROUP_MEMBERS-libbfd = libbfd-liberty libbfd-liberty-z 175 176# 177# Declare list of feature dependency packages that provide pkg-config files. 178# 179FEATURE_PKG_CONFIG ?= \ 180 libtraceevent \ 181 libtracefs 182 183feature_pkg_config = $(eval $(feature_pkg_config_code)) 184define feature_pkg_config_code 185 FEATURE_CHECK_CFLAGS-$(1) := $(shell $(PKG_CONFIG) --cflags $(1) 2>/dev/null) 186 FEATURE_CHECK_LDFLAGS-$(1) := $(shell $(PKG_CONFIG) --libs $(1) 2>/dev/null) 187endef 188 189# Set FEATURE_CHECK_(C|LD)FLAGS-$(package) for packages using pkg-config. 190ifneq ($(PKG_CONFIG),) 191 $(foreach package,$(FEATURE_PKG_CONFIG),$(call feature_pkg_config,$(package))) 192endif 193 194# Set FEATURE_CHECK_(C|LD)FLAGS-all for all FEATURE_TESTS features. 195# If in the future we need per-feature checks/flags for features not 196# mentioned in this list we need to refactor this ;-). 197set_test_all_flags = $(eval $(set_test_all_flags_code)) 198define set_test_all_flags_code 199 FEATURE_CHECK_CFLAGS-all += $(FEATURE_CHECK_CFLAGS-$(1)) 200 FEATURE_CHECK_LDFLAGS-all += $(FEATURE_CHECK_LDFLAGS-$(1)) 201endef 202 203$(foreach feat,$(FEATURE_TESTS),$(call set_test_all_flags,$(feat))) 204 205# 206# Special fast-path for the 'all features are available' case: 207# 208$(call feature_check,all,$(MSG)) 209 210# 211# Just in case the build freshly failed, make sure we print the 212# feature matrix: 213# 214ifeq ($(feature-all), 1) 215 # 216 # test-all.c passed - just set all the core feature flags to 1: 217 # 218 $(foreach feat,$(FEATURE_TESTS),$(call feature_set,$(feat))) 219 # 220 # test-all.c does not comprise these tests, so we need to 221 # for this case to get features proper values 222 # 223 $(call feature_check,compile-32) 224 $(call feature_check,compile-x32) 225 $(call feature_check,bionic) 226 $(call feature_check,libbabeltrace) 227else 228 $(foreach feat,$(FEATURE_TESTS),$(call feature_check,$(feat))) 229endif 230 231# 232# Print the result of the feature test: 233# 234feature_print_status = $(eval $(feature_print_status_code)) 235 236feature_group = $(eval $(feature_gen_group)) $(GROUP) 237 238define feature_gen_group 239 GROUP := $(1) 240 ifneq ($(feature_verbose),1) 241 GROUP += $(FEATURE_GROUP_MEMBERS-$(1)) 242 endif 243endef 244 245define feature_print_status_code 246 ifneq (,$(filter 1,$(foreach feat,$(call feature_group,$(feat)),$(feature-$(feat))))) 247 MSG = $(shell printf '...%40s: [ \033[32mon\033[m ]' $(1)) 248 else 249 MSG = $(shell printf '...%40s: [ \033[31mOFF\033[m ]' $(1)) 250 endif 251endef 252 253feature_print_text = $(eval $(feature_print_text_code)) 254define feature_print_text_code 255 MSG = $(shell printf '...%40s: %s' $(1) $(2)) 256endef 257 258# 259# generates feature value assignment for name, like: 260# $(call feature_assign,libdw) == feature-libdw=1 261# 262feature_assign = feature-$(1)=$(feature-$(1)) 263 264FEATURE_DUMP_FILENAME = $(OUTPUT)FEATURE-DUMP$(FEATURE_USER) 265FEATURE_DUMP := $(shell touch $(FEATURE_DUMP_FILENAME); cat $(FEATURE_DUMP_FILENAME)) 266 267feature_dump_check = $(eval $(feature_dump_check_code)) 268define feature_dump_check_code 269 ifeq ($(findstring $(1),$(FEATURE_DUMP)),) 270 $(2) := 1 271 endif 272endef 273 274# 275# First check if any test from FEATURE_DISPLAY 276# and set feature_display := 1 if it does 277$(foreach feat,$(FEATURE_DISPLAY),$(call feature_dump_check,$(call feature_assign,$(feat)),feature_display)) 278 279# 280# Now also check if any other test changed, 281# so we force FEATURE-DUMP generation 282$(foreach feat,$(FEATURE_TESTS),$(call feature_dump_check,$(call feature_assign,$(feat)),feature_dump_changed)) 283 284# The $(feature_display) controls the default detection message 285# output. It's set if: 286# - detected features differes from stored features from 287# last build (in $(FEATURE_DUMP_FILENAME) file) 288# - one of the $(FEATURE_DISPLAY) is not detected 289# - VF is enabled 290 291ifeq ($(feature_dump_changed),1) 292 $(shell rm -f $(FEATURE_DUMP_FILENAME)) 293 $(foreach feat,$(FEATURE_TESTS),$(shell echo "$(call feature_assign,$(feat))" >> $(FEATURE_DUMP_FILENAME))) 294endif 295 296feature_display_check = $(eval $(feature_check_display_code)) 297define feature_check_display_code 298 ifneq ($(feature-$(1)), 1) 299 feature_display := 1 300 endif 301endef 302 303$(foreach feat,$(FEATURE_DISPLAY),$(call feature_display_check,$(feat))) 304 305ifeq ($(VF),1) 306 feature_display := 1 307 feature_verbose := 1 308endif 309 310ifneq ($(feature_verbose),1) 311 # 312 # Determine the features to omit from the displayed message, as only the 313 # logical OR of the detection result will be shown. 314 # 315 FEATURE_OMIT := $(foreach feat,$(FEATURE_DISPLAY),$(FEATURE_GROUP_MEMBERS-$(feat))) 316endif 317 318feature_display_entries = $(eval $(feature_display_entries_code)) 319define feature_display_entries_code 320 ifeq ($(feature_display),1) 321 $$(info ) 322 $$(info Auto-detecting system features:) 323 $(foreach feat,$(filter-out $(FEATURE_OMIT),$(FEATURE_DISPLAY)),$(call feature_print_status,$(feat),) $$(info $(MSG))) 324 endif 325 326 ifeq ($(feature_verbose),1) 327 $(eval TMP := $(filter-out $(FEATURE_DISPLAY),$(FEATURE_TESTS))) 328 $(foreach feat,$(TMP),$(call feature_print_status,$(feat),) $$(info $(MSG))) 329 endif 330endef 331 332ifeq ($(FEATURE_DISPLAY_DEFERRED),) 333 $(call feature_display_entries) 334 $(info ) 335endif 336