perf build: Add install-build-deps framework to install devel packages

Installing the development packages needed to build perf is
error-prone on a fresh distro install: the packages are scattered
across the feature tests in tools/build/feature/, each checking for a
specific header/library, and the build only tells you what's missing
after failing a check.

This series adds a 'make -C tools/perf install-build-deps' target to
install them in one go, deriving the package list from the feature tests
themselves.

This commit adds the framework, on top of the parse-time compiler
probe guard from the previous commit:

- the install-build-deps target in tools/perf/Makefile.perf, exempted
  from the config/feature detection pass, since it must run in a fresh
  container, before gcc or pkg-config exist, to install them;
- the install-build-deps.sh script, with --list, --dry-run and
  --distro options, distro detection (Fedora and Ubuntu), dnf and
  apt-get drivers, root/passwordless-sudo handling, and the base
  packages common to any build: compiler, C++ compiler, make, flex,
  bison, libc and kernel headers, python3-setuptools (needed by the
  python binding) and rust (checked by the rust feature test);
- the parse-time probes for optional tools, like pkg-config, use
  'command -v' with stderr discarded, so a fresh container without
  them gets no 'which: no pkg-config in (...)' spew from make;
- the script does not rely on 'set -e': its error paths are explicit,
  since the make target runs it via $(SHELL), where a shebang option
  would be ignored anyway, so direct and make-driven runs behave the
  same.

The per-feature mappings, from each feature test to the devel package
providing its headers on a given distro, are added by the follow-up
patches, one per distro, together with the validation of each mapping
in a fresh container: until then the target installs just the base
toolchain.

Assisted-by: opencode:deepseek-v4-flash-free
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
This commit is contained in:
Arnaldo Carvalho de Melo 2026-08-11 15:28:55 -03:00 committed by Namhyung Kim
parent 380e3f23bb
commit bc3fdd6adb
2 changed files with 190 additions and 3 deletions

View File

@ -177,7 +177,7 @@ LD += $(EXTRA_LDFLAGS)
# 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))
ifneq (, $(shell command -v $(CROSS_COMPILE)pkg-config 2>/dev/null))
PKG_CONFIG ?= $(CROSS_COMPILE)pkg-config
else
PKG_CONFIG ?= pkg-config
@ -214,7 +214,12 @@ AWK = awk
# non-config cases
config := 1
NON_CONFIG_TARGETS := clean python-clean TAGS tags cscope help
# install-build-deps runs the install-build-deps.sh script, which
# derives the package list from the feature test sources in
# tools/build/feature/, so it needs neither the fixdep build nor a
# config/feature detection pass: in a fresh container without gcc or
# pkg-config those would fail before the script could install them.
NON_CONFIG_TARGETS := clean python-clean TAGS tags cscope help install-build-deps
ifdef MAKECMDGOALS
ifeq ($(filter-out $(NON_CONFIG_TARGETS),$(MAKECMDGOALS)),)
@ -748,6 +753,7 @@ help:
@echo ' HINT: use "prefix" or "DESTDIR" to install to a particular'
@echo ' path like "make prefix=/usr/local install install-doc"'
@echo ' install - install compiled binaries'
@echo ' install-build-deps - install the development packages needed to build'
@echo ' install-doc - install *all* documentation'
@echo ' install-man - install manpage documentation'
@echo ' install-html - install html documentation'
@ -892,6 +898,14 @@ install-bin: install-tools install-tests
install: install-bin try-install-man
# Install the development packages needed to build perf, derived from the
# feature tests in tools/build/feature/. This first installs just the
# base toolchain; per-distro package mappings are added by the follow-up
# commits. INSTALL_BUILD_DEPS_ARGS, when set, is passed to the script, so
# extra options like --list, --dry-run or --distro can be given from make.
install-build-deps:
$(Q)$(SHELL) $(srctree)/tools/perf/scripts/install-build-deps.sh $(INSTALL_BUILD_DEPS_ARGS)
install-python_ext:
$(PYTHON_WORD) util/setup.py $(python_setup_quiet) install --root='/$(DESTDIR_SQ)'
@ -960,7 +974,7 @@ endif
FORCE:
.PHONY: all install clean config-clean strip install-gtk
.PHONY: all install install-build-deps clean config-clean strip install-gtk
.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope FORCE prepare bpf-skel-prepare
.PHONY: python_perf_target

View File

@ -0,0 +1,173 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# No 'set -e': the script uses explicit checks for its error paths, and
# is also run via '$(SHELL) .../install-build-deps.sh' from the make
# target in tools/perf/Makefile.perf, where a shebang option would be
# ignored anyway, so direct and make-driven runs behave the same.
#
# Install the development packages needed to build tools/perf.
#
# The package set is derived from the feature tests in tools/build/feature/:
# each feature test that perf may compile is mapped to the devel package
# that provides the headers/libraries it checks, so that a subsequent
# 'make -C tools/perf' build enables the corresponding perf features.
#
# This initial version installs the base toolchain needed by any build;
# the per-feature package mapping is added, per supported distro, by the
# follow-up patches in this series, which also validate each mapping in a
# fresh container, so the host system is not modified.
#
# Usage: install-build-deps.sh [OPTIONS]
#
# Options:
# --list list the packages that would be installed, then exit
# --dry-run show the install command that would be run, without
# running it
# --distro ID force a distro: fedora, ubuntu (default: auto-detect)
# -h, --help print this help message
#
# Requires root (or passwordless sudo) to actually install packages.
set -u
DISTRO=""
help() {
cat <<EOF
Usage: $(basename "$0") [--list] [--dry-run] [--distro ID] [-h|--help]
Install the development packages needed to build tools/perf.
Options:
--list list the packages that would be installed, then exit
--dry-run show the install command that would be run, without running it
--distro ID force a distro: fedora, ubuntu
-h, --help print this help message
EOF
exit 0
}
# ---------------------------------------------------------------------
# Distro detection. The install command that follows only differs in
# the package manager, which here is keyed off the distro ID; the
# per-feature package mapping is added per distro by the follow-up
# patches.
# ---------------------------------------------------------------------
detect_distro() {
if [ -n "$DISTRO" ]; then
echo "$DISTRO"
return
fi
local id
id=$( . /etc/os-release 2>/dev/null && echo "${ID:-}" )
case "$id" in
fedora) echo "fedora" ;;
ubuntu) echo "ubuntu" ;;
# RHEL and its derivatives share most Fedora package names, but the
# mapping is only validated on Fedora, so don't auto-detect them.
rhel|centos|rocky|alma|ol) echo "" ;;
*) echo "" ;;
esac
}
# Base packages needed by any perf build, regardless of feature tests:
# compiler, libc headers, flex/bison for the parser, kernel headers
# for UAPI headers with no in-tree copy, e.g. <linux/capability.h>, and
# gcc-c++ (dnf) / g++ (apt) for the C++-based feature tests
# (cxa-demangle, llvm, llvm-perf), compiled with $(CXX), and
# pulls in libstdc++-devel / libstdc++-*-dev.
# python3-setuptools is needed to build the python binding (perf's
# util/setup.py uses it; without it binding is skipped with a warning).
# rust is not a header-based feature test: test-rust.bin just checks
# "$(RUSTC) --version" (tools/build/feature/Makefile), so it is mapped
# here like the other toolchain packages.
fedora_base_pkgs="gcc gcc-c++ make flex bison glibc-devel kernel-headers python3-setuptools rust"
debian_base_pkgs="gcc g++ make flex bison libc6-dev linux-libc-dev python3-setuptools rustc"
# ---------------------------------------------------------------------
# Assemble the unique package list. While the per-feature mapping is
# being added per distro, only the base toolchain above is installed.
# ---------------------------------------------------------------------
package_set() {
local distro="$1" srcdir="$2"
case "$distro" in
fedora) echo "$fedora_base_pkgs" ;;
ubuntu) echo "$debian_base_pkgs" ;;
esac
}
# ---------------------------------------------------------------------
# The install command proper for each supported package manager, plus
# the command massaged for --dry-run.
# ---------------------------------------------------------------------
install_cmd() {
local distro="$1"; shift
case "$distro" in
fedora)
echo "dnf install -y $*"
;;
ubuntu)
# a fresh container has no package index, so update first.
echo "apt-get update && apt-get install -y $*"
;;
esac
}
main() {
local action="install"
local srcdir distro pkgs cmd
while [ $# -gt 0 ]; do
case "$1" in
--list) action="list"; shift ;;
--dry-run) action="dry-run"; shift ;;
--distro)
[ $# -ge 2 ] || {
echo "error: --distro requires an argument (fedora, rhel, ubuntu, debian)" >&2
exit 1
}
DISTRO="$2"; shift 2 ;;
-h|--help) help ;;
*) echo "error: unknown argument: $1" >&2; exit 1 ;;
esac
done
srcdir=$(cd "$(dirname "$0")/../../.." && pwd)
distro=$(detect_distro)
case "$distro" in
fedora|ubuntu) ;;
*)
echo "error: unsupported distro (got '$distro'); the package mapping is not validated on other distros." >&2
exit 1
;;
esac
pkgs=$(package_set "$distro" "$srcdir")
case "$action" in
list)
echo "$pkgs" | tr ' ' '\n' | grep -v '^$' | sort
exit 0
;;
dry-run)
install_cmd "$distro" $pkgs
exit 0
;;
esac
echo "The following packages will be installed to enable perf features:"
echo "$pkgs" | tr ' ' '\n' | grep -v '^$' | sort | sed 's/^/ /'
echo
cmd=$(install_cmd "$distro" $pkgs)
if [ "$(id -u)" -eq 0 ]; then
sh -c "$cmd"
else
sudo sh -c "$cmd"
fi || {
echo "error: the install command failed, see the output above" >&2
exit 1
}
}
main "$@"