xref: /linux/tools/perf/scripts/install-build-deps.sh (revision bc3fdd6adb9903b1f1fd85cd9532c7bfc961dcbc)
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3#
4# No 'set -e': the script uses explicit checks for its error paths, and
5# is also run via '$(SHELL) .../install-build-deps.sh' from the make
6# target in tools/perf/Makefile.perf, where a shebang option would be
7# ignored anyway, so direct and make-driven runs behave the same.
8#
9# Install the development packages needed to build tools/perf.
10#
11# The package set is derived from the feature tests in tools/build/feature/:
12# each feature test that perf may compile is mapped to the devel package
13# that provides the headers/libraries it checks, so that a subsequent
14# 'make -C tools/perf' build enables the corresponding perf features.
15#
16# This initial version installs the base toolchain needed by any build;
17# the per-feature package mapping is added, per supported distro, by the
18# follow-up patches in this series, which also validate each mapping in a
19# fresh container, so the host system is not modified.
20#
21# Usage: install-build-deps.sh [OPTIONS]
22#
23# Options:
24#    --list       list the packages that would be installed, then exit
25#    --dry-run    show the install command that would be run, without
26#                 running it
27#    --distro ID  force a distro: fedora, ubuntu (default: auto-detect)
28#    -h, --help   print this help message
29#
30# Requires root (or passwordless sudo) to actually install packages.
31
32set -u
33
34DISTRO=""
35
36help() {
37	cat <<EOF
38Usage: $(basename "$0") [--list] [--dry-run] [--distro ID] [-h|--help]
39
40Install the development packages needed to build tools/perf.
41
42Options:
43    --list      list the packages that would be installed, then exit
44    --dry-run   show the install command that would be run, without running it
45    --distro ID force a distro: fedora, ubuntu
46    -h, --help  print this help message
47EOF
48	exit 0
49}
50
51# ---------------------------------------------------------------------
52# Distro detection.  The install command that follows only differs in
53# the package manager, which here is keyed off the distro ID; the
54# per-feature package mapping is added per distro by the follow-up
55# patches.
56# ---------------------------------------------------------------------
57detect_distro() {
58	if [ -n "$DISTRO" ]; then
59		echo "$DISTRO"
60		return
61	fi
62	local id
63	id=$( . /etc/os-release 2>/dev/null && echo "${ID:-}" )
64	case "$id" in
65	fedora)			echo "fedora" ;;
66	ubuntu)			echo "ubuntu" ;;
67	# RHEL and its derivatives share most Fedora package names, but the
68	# mapping is only validated on Fedora, so don't auto-detect them.
69	rhel|centos|rocky|alma|ol) echo "" ;;
70	*)			echo "" ;;
71	esac
72}
73
74# Base packages needed by any perf build, regardless of feature tests:
75# compiler, libc headers, flex/bison for the parser, kernel headers
76# for UAPI headers with no in-tree copy, e.g. <linux/capability.h>, and
77# gcc-c++ (dnf) / g++ (apt) for the C++-based feature tests
78# (cxa-demangle, llvm, llvm-perf), compiled with $(CXX), and
79# pulls in libstdc++-devel / libstdc++-*-dev.
80# python3-setuptools is needed to build the python binding (perf's
81# util/setup.py uses it; without it binding is skipped with a warning).
82# rust is not a header-based feature test: test-rust.bin just checks
83# "$(RUSTC) --version" (tools/build/feature/Makefile), so it is mapped
84# here like the other toolchain packages.
85fedora_base_pkgs="gcc gcc-c++ make flex bison glibc-devel kernel-headers python3-setuptools rust"
86debian_base_pkgs="gcc g++ make flex bison libc6-dev linux-libc-dev python3-setuptools rustc"
87
88# ---------------------------------------------------------------------
89# Assemble the unique package list.  While the per-feature mapping is
90# being added per distro, only the base toolchain above is installed.
91# ---------------------------------------------------------------------
92package_set() {
93	local distro="$1" srcdir="$2"
94	case "$distro" in
95	fedora)	echo "$fedora_base_pkgs" ;;
96	ubuntu)	echo "$debian_base_pkgs" ;;
97	esac
98}
99
100# ---------------------------------------------------------------------
101# The install command proper for each supported package manager, plus
102# the command massaged for --dry-run.
103# ---------------------------------------------------------------------
104install_cmd() {
105	local distro="$1"; shift
106	case "$distro" in
107	fedora)
108		echo "dnf install -y $*"
109		;;
110	ubuntu)
111		# a fresh container has no package index, so update first.
112		echo "apt-get update && apt-get install -y $*"
113		;;
114	esac
115}
116
117main() {
118	local action="install"
119	local srcdir distro pkgs cmd
120
121	while [ $# -gt 0 ]; do
122		case "$1" in
123		--list)		action="list"; shift ;;
124		--dry-run)	action="dry-run"; shift ;;
125		--distro)
126			[ $# -ge 2 ] || {
127				echo "error: --distro requires an argument (fedora, rhel, ubuntu, debian)" >&2
128				exit 1
129			}
130			DISTRO="$2"; shift 2 ;;
131		-h|--help)	help ;;
132		*)		echo "error: unknown argument: $1" >&2; exit 1 ;;
133		esac
134	done
135
136	srcdir=$(cd "$(dirname "$0")/../../.." && pwd)
137	distro=$(detect_distro)
138	case "$distro" in
139	fedora|ubuntu) ;;
140	*)
141		echo "error: unsupported distro (got '$distro'); the package mapping is not validated on other distros." >&2
142		exit 1
143		;;
144	esac
145
146	pkgs=$(package_set "$distro" "$srcdir")
147
148	case "$action" in
149	list)
150		echo "$pkgs" | tr ' ' '\n' | grep -v '^$' | sort
151		exit 0
152		;;
153	dry-run)
154		install_cmd "$distro" $pkgs
155		exit 0
156		;;
157	esac
158
159	echo "The following packages will be installed to enable perf features:"
160	echo "$pkgs" | tr ' ' '\n' | grep -v '^$' | sort | sed 's/^/  /'
161	echo
162	cmd=$(install_cmd "$distro" $pkgs)
163	if [ "$(id -u)" -eq 0 ]; then
164		sh -c "$cmd"
165	else
166		sudo sh -c "$cmd"
167	fi || {
168		echo "error: the install command failed, see the output above" >&2
169		exit 1
170	}
171}
172
173main "$@"