| #!/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. | |
| # | |
| # Currently supported distros, each validated in a fresh container: | |
| # | |
| # - Fedora, on dnf, validated on Fedora 44, in a toolbx container: | |
| # | |
| # toolbox create fedora:44 | |
| # toolbox enter fedora:44 | |
| # | |
| # - Ubuntu, on apt-get, validated on Ubuntu 26.04, in a distrobox | |
| # container: | |
| # | |
| # distrobox create --image ubuntu:26.04 | |
| # distrobox enter ubuntu-26-04 | |
| # | |
| # The apt-get install runs with a noninteractive debconf frontend: | |
| # default-jdk, needed by the jvmti feature tests, pulls in tzdata, | |
| # which prompts for the timezone on a terminal and would block the | |
| # install, e.g. in a container shared with an interactive session. | |
| # | |
| # - Debian, on apt-get, reusing the Ubuntu mapping, validated on | |
| # Debian 13 (trixie), in a distrobox container: | |
| # | |
| # distrobox create --image debian:trixie | |
| # distrobox enter debian-trixie | |
| # | |
| # - RHEL and its variants (RHEL, CentOS Stream, Rocky Linux, AlmaLinux, | |
| # Oracle Linux), on dnf (RHEL 8 and later), validated on CentOS | |
| # Stream 10, in a distrobox container: | |
| # | |
| # distrobox create --image quay.io/centos/centos:stream10 | |
| # distrobox enter centos-stream10 | |
| # | |
| # The RHEL family reuses most Fedora package names, with these | |
| # differences, handled by probing the enabled repos: | |
| # | |
| # - zlib.h comes from zlib-ng-compat-devel on the RHEL 10 family, | |
| # zlib-devel on RHEL 9 and earlier; | |
| # - the JDK devel package is versioned, there is no | |
| # java-latest-openjdk-devel: java-21-openjdk-devel on the RHEL | |
| # 10 family, java-17-openjdk-devel on RHEL 9, java-11-openjdk- | |
| # devel on RHEL 8; | |
| # - libbpf-devel and capstone-devel are in the CRB repo on RHEL | |
| # and CentOS Stream 10 ('dnf config-manager --set-enabled crb') | |
| # and in EPEL on RHEL 9 and earlier; | |
| # - libbabeltrace2-devel is not packaged on the RHEL 10 family. | |
| # | |
| # On the RHEL family, packages not available on the enabled repos | |
| # are skipped and listed at the end of the run, so that a distro | |
| # with CRB/EPEL enabled gets the full set, and a distro without | |
| # them still installs what it can. | |
| # | |
| # Running inside a container keeps the host system unmodified. | |
| # | |
| # 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, rhel, ubuntu, debian | |
| # (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. | |
| The package set is derived from the feature tests in tools/build/feature/, | |
| mapping each one with an external dependency to the devel package providing | |
| it, so the corresponding feature gets enabled on a build. | |
| 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, rhel, ubuntu, debian | |
| -h, --help print this help message | |
| Distros supported: Fedora (dnf), validated in a toolbx container on | |
| Fedora 44, Ubuntu (apt-get), validated in a distrobox container on | |
| Ubuntu 26.04, Debian (apt-get), reusing the Ubuntu mapping, validated | |
| in a distrobox container on Debian 13 (trixie), and the RHEL family | |
| (dnf, RHEL 8 and later), validated on CentOS Stream 10 in a distrobox | |
| container. On the RHEL family, packages not available on the enabled | |
| repos are skipped and listed at the end; some there, e.g. | |
| libbpf-devel and capstone-devel, come from the CRB repo on RHEL and | |
| CentOS Stream 10 ('dnf config-manager --set-enabled crb') and from | |
| EPEL on RHEL 9 and earlier. | |
| EOF | |
| exit 0 | |
| } | |
| # --------------------------------------------------------------------- | |
| # Return the Fedora package(s) providing the devel requirements of a | |
| # feature test in tools/build/feature/. Multiple packages are separated | |
| # by spaces; an empty result means the test has no external devel | |
| # dependency (pure toolchain/glibc, or no equivalent Fedora package). | |
| # | |
| # The mapping was built by checking, for each feature test, which Fedora | |
| # devel package provides the headers the test compiles against. | |
| # --------------------------------------------------------------------- | |
| fedora_pkg_for() { | |
| local feat="$1" | |
| case "$feat" in | |
| libelf|libelf-getphdrnum|libelf-gelf_getnote|libelf-getshdrstrndx) | |
| echo "elfutils-libelf-devel" | |
| ;; | |
| libelf-zstd) | |
| echo "elfutils-libelf-devel libzstd-devel" | |
| ;; | |
| libdw) | |
| echo "elfutils-devel" | |
| ;; | |
| # test-libdebuginfod.c includes <elfutils/debuginfod.h>, which is | |
| # provided by elfutils-debuginfod-client-devel, not elfutils-devel. | |
| libdebuginfod) | |
| echo "elfutils-debuginfod-client-devel" | |
| ;; | |
| libnuma|numa_num_possible_cpus) | |
| echo "numactl-devel" | |
| ;; | |
| libzstd) | |
| echo "libzstd-devel" | |
| ;; | |
| zlib) | |
| echo "zlib-devel" | |
| ;; | |
| lzma) | |
| echo "xz-devel" | |
| ;; | |
| libslang) | |
| echo "slang-devel" | |
| ;; | |
| libcapstone) | |
| echo "capstone-devel" | |
| ;; | |
| libpython) | |
| echo "python3-devel" | |
| ;; | |
| libtraceevent) | |
| echo "libtraceevent-devel" | |
| ;; | |
| cxa-demangle) | |
| echo "libstdc++-devel" | |
| ;; | |
| libbpf) | |
| echo "libbpf-devel" | |
| ;; | |
| babeltrace2-ctf-writer) | |
| echo "libbabeltrace2-devel" | |
| ;; | |
| libopenssl) | |
| echo "openssl-devel" | |
| ;; | |
| libpfm4) | |
| echo "libpfm-devel" | |
| ;; | |
| sdt) | |
| echo "systemtap-sdt-devel" | |
| ;; | |
| clang-bpf-co-re) | |
| echo "clang-devel" | |
| ;; | |
| llvm|llvm-perf) | |
| echo "llvm-devel" | |
| ;; | |
| jvmti|jvmti-cmlr) | |
| echo "java-latest-openjdk-devel" | |
| ;; | |
| esac | |
| # Pure toolchain/libc features (backtrace, eventfd, fortify-source, | |
| # gettid, glibc, hello, reallocarray, pthread-*, stackprotector-all, | |
| # timerfd, scandirat, sched_getcpu, setns, file-handle, | |
| # bionic...) need no external package: their | |
| # requirements are covered by the base packages below. Features that | |
| # perf's own build does not check (libcap, libcheck, libcpupower, | |
| # libtracefs, whose feature tests exist for rtla/bpftool/rv) and the | |
| # opt-in features, which a default build does not enable: the libbfd | |
| # disassembler family (libbfd, libbfd-threadsafe, libbfd-liberty, | |
| # disassembler-*, cplus-demangle), only linked on BUILD_NONDISTRO | |
| # builds and deprecated in favor of capstone, GTK2, LIBPERL and | |
| # LIBUNWIND support (ifdef GTK2 / ifdef LIBPERL / LIBUNWIND=1), | |
| # and CoreSight (ifdef CORESIGHT), are deliberately not mapped. | |
| # libaio is not mapped either: its | |
| # test uses the POSIX AIO API (aio.h, aio_*, -lrt), provided by | |
| # glibc headers (pulled in by the libc headers package) in the | |
| # base set, not the native libaio.h/io_submit API that | |
| # libaio-devel provides. | |
| } | |
| # --------------------------------------------------------------------- | |
| # Check whether the first argument is provided by the enabled repos, or | |
| # is already installed, returning 0 if so and printing nothing. | |
| # | |
| # dnf repoquery exits 0 even when the pattern does not match anything, | |
| # so availability is judged by the output being non-empty, not by the | |
| # exit code. | |
| # --------------------------------------------------------------------- | |
| pkg_available() { | |
| local p out | |
| for p in "$@"; do | |
| out=$(dnf repoquery --quiet --available "$p" 2>/dev/null) | |
| [ -n "$out" ] || out=$(dnf repoquery --quiet --installed "$p" 2>/dev/null) | |
| [ -n "$out" ] && return 0 | |
| done | |
| return 1 | |
| } | |
| # --------------------------------------------------------------------- | |
| # Return the first of its arguments that pkg_available() accepts. | |
| # --------------------------------------------------------------------- | |
| pick_available() { | |
| local p | |
| for p in "$@"; do | |
| if pkg_available "$p"; then | |
| echo "$p" | |
| return 0 | |
| fi | |
| done | |
| return 1 | |
| } | |
| # --------------------------------------------------------------------- | |
| # Return the RHEL-family package(s) providing the devel requirements of | |
| # a feature test. This family reuses the Fedora mapping, whose names | |
| # apply to it as well, except for the features whose Fedora package | |
| # does not exist there, kept in the case below. | |
| # | |
| # Whether the resulting package is actually installable is checked in | |
| # package_set(), as some of these names live in the CRB or EPEL repos, | |
| # which may not be enabled: on the RHEL 10 family libbpf-devel and | |
| # capstone-devel come from CRB, and libbabeltrace2-devel is not | |
| # packaged at all. | |
| # --------------------------------------------------------------------- | |
| rhel_pkg_for() { | |
| local feat="$1" | |
| case "$feat" in | |
| zlib) | |
| # zlib-ng-compat-devel on the RHEL 10 family, zlib-devel on | |
| # RHEL 9 and earlier. If neither is on the enabled repos, | |
| # fall back to the first candidate so that package_set() | |
| # reports it as missing instead of silently dropping the | |
| # feature from the end-of-run note. | |
| pick_available zlib-devel zlib-ng-compat-devel || echo "zlib-devel" | |
| ;; | |
| jvmti|jvmti-cmlr) | |
| # No java-latest-openjdk-devel on the RHEL family: the JDK | |
| # devel package is versioned per release. | |
| pick_available java-latest-openjdk-devel java-21-openjdk-devel java-17-openjdk-devel java-11-openjdk-devel || echo "java-latest-openjdk-devel" | |
| ;; | |
| *) | |
| fedora_pkg_for "$feat" | |
| ;; | |
| esac | |
| } | |
| # --------------------------------------------------------------------- | |
| # Return the Debian/Ubuntu package(s) providing the devel requirements | |
| # of a feature test in tools/build/feature/. This mapping is shared by | |
| # Debian and Ubuntu, whose package names for these devel packages match, | |
| # and is validated on Ubuntu 26.04 and Debian 13 (trixie). | |
| # --------------------------------------------------------------------- | |
| debian_pkg_for() { | |
| local feat="$1" | |
| case "$feat" in | |
| libelf|libelf-getphdrnum|libelf-gelf_getnote|libelf-getshdrstrndx) | |
| echo "libelf-dev" | |
| ;; | |
| libelf-zstd) | |
| echo "libelf-dev libzstd-dev" | |
| ;; | |
| libdw) | |
| echo "libdw-dev" | |
| ;; | |
| libdebuginfod) | |
| echo "libdebuginfod-dev" | |
| ;; | |
| libnuma|numa_num_possible_cpus) | |
| echo "libnuma-dev" | |
| ;; | |
| libzstd) | |
| echo "libzstd-dev" | |
| ;; | |
| zlib) | |
| echo "zlib1g-dev" | |
| ;; | |
| lzma) | |
| echo "liblzma-dev" | |
| ;; | |
| libslang) | |
| echo "libslang2-dev" | |
| ;; | |
| libcapstone) | |
| echo "libcapstone-dev" | |
| ;; | |
| libpython) | |
| echo "python3-dev" | |
| ;; | |
| libtraceevent) | |
| echo "libtraceevent-dev" | |
| ;; | |
| # The cxa-demangle feature test links against libstdc++ builtin | |
| # demangling, so on Debian-derived distros it is covered by the | |
| # g++ base package below, which pulls in libstdc++-*-dev. | |
| cxa-demangle) | |
| ;; | |
| libbpf) | |
| echo "libbpf-dev" | |
| ;; | |
| babeltrace2-ctf-writer) | |
| echo "libbabeltrace2-dev" | |
| ;; | |
| libopenssl) | |
| echo "libssl-dev" | |
| ;; | |
| libpfm4) | |
| echo "libpfm4-dev" | |
| ;; | |
| sdt) | |
| echo "systemtap-sdt-dev" | |
| ;; | |
| # test-clang-bpf-co-re.c invokes the clang binary (not libclang-cpp), | |
| # so clang suffices; llvm-dev brings llvm-config, needed by the | |
| # llvm/llvm-perf tests below. | |
| clang-bpf-co-re) | |
| echo "clang llvm-dev" | |
| ;; | |
| llvm|llvm-perf) | |
| echo "llvm-dev" | |
| ;; | |
| jvmti|jvmti-cmlr) | |
| echo "default-jdk" | |
| ;; | |
| esac | |
| # Same rationale as in fedora_pkg_for() above for unmapped tests. | |
| } | |
| # 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) is needed by 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" | |
| # pkg-config mirrors the pkgconf-pkg-config package that Fedora | |
| # installs by default, needed by the babeltrace2 feature test and | |
| # libopenssl's pkg-config checks. | |
| debian_base_pkgs="gcc g++ make pkg-config flex bison libc6-dev linux-libc-dev python3-setuptools rustc" | |
| # pkg-config: like Fedora, on pkgconf since Fedora 26 / RHEL 8, with | |
| # 'pkgconfig' live only as a virtual Provides of the pkgconf-pkg-config | |
| # subpackage. List it explicitly because, unlike Fedora, a minimal | |
| # RHEL-family container may not have it preinstalled. | |
| rhel_base_pkgs="gcc gcc-c++ make flex bison glibc-devel kernel-headers pkgconf-pkg-config python3-setuptools rust" | |
| # --------------------------------------------------------------------- | |
| # Distro detection | |
| # --------------------------------------------------------------------- | |
| 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" ;; | |
| rhel|centos|rocky|almalinux|ol) | |
| # All share the Fedora package names (with the exceptions | |
| # handled by rhel_pkg_for()) and dnf. | |
| echo "rhel" ;; | |
| ubuntu) echo "ubuntu" ;; | |
| debian) echo "debian" ;; | |
| *) echo "" ;; | |
| esac | |
| } | |
| # --------------------------------------------------------------------- | |
| # Feature test enumeration: mirror of the tests checked during a build, | |
| # from the actual test-*.c / test-*.cpp sources in tools/build/feature/. | |
| # --------------------------------------------------------------------- | |
| feature_tests() { | |
| local srcdir="$1" | |
| local f | |
| for f in "$srcdir"/tools/build/feature/test-*.c "$srcdir"/tools/build/feature/test-*.cpp; do | |
| [ -e "$f" ] || continue | |
| basename "$f" | sed -e 's/^test-//' -e 's/\.c$//' -e 's/\.cpp$//' | |
| done | |
| } | |
| # --------------------------------------------------------------------- | |
| # Assemble the unique package list. Since the full feature set is mapped | |
| # unconditionally, this installs the complete devel environment; installing | |
| # an already-present package is a no-op for both dnf and apt-get, making | |
| # this idempotent. On the RHEL family, packages not available on the | |
| # enabled repos are skipped and echoed on stderr, reported at the end of | |
| # the run by the caller (package_set() runs in a subshell, so a variable | |
| # would not survive it). | |
| # --------------------------------------------------------------------- | |
| package_set() { | |
| local distro="$1" srcdir="$2" | |
| local feat pkg pkgs base_pkgs missing_pkgs="" | |
| case "$distro" in | |
| fedora) pkgs="$fedora_base_pkgs" ;; | |
| rhel) pkgs="$rhel_base_pkgs" ;; | |
| ubuntu|debian) pkgs="$debian_base_pkgs" ;; | |
| esac | |
| # The base set must be checked against the enabled repos as well: | |
| # e.g. 'rust' is only shipped as the rust-toolset AppStream module | |
| # on RHEL 8 and 9, where dnf would abort the whole transaction | |
| # with "No match for argument: rust" instead of skipping it, so | |
| # unavailable base packages are skipped and noted like the mapped | |
| # ones below. | |
| if [ "$distro" = "rhel" ]; then | |
| base_pkgs="$pkgs" | |
| pkgs="" | |
| for pkg in $base_pkgs; do | |
| if pkg_available "$pkg"; then | |
| pkgs="$pkgs $pkg" | |
| else | |
| missing_pkgs="$missing_pkgs $pkg" | |
| fi | |
| done | |
| fi | |
| for feat in $(feature_tests "$srcdir"); do | |
| case "$distro" in | |
| fedora) pkg=$(fedora_pkg_for "$feat") ;; | |
| rhel) pkg=$(rhel_pkg_for "$feat") ;; | |
| *) pkg=$(debian_pkg_for "$feat") ;; | |
| esac | |
| # An empty result means the feature test has no external devel | |
| # dependency (see the unmapped list in fedora_pkg_for()), so | |
| # there is nothing to install and nothing to report as missing: | |
| # packages that are genuinely unavailable on the RHEL family | |
| # surface through rhel_pkg_for() falling back to its first | |
| # candidate, so that the pkg_available() check below catches | |
| # them and adds them to missing_pkgs. | |
| [ -n "$pkg" ] || continue | |
| for pkg in $pkg; do | |
| if [ "$distro" = "rhel" ] && ! pkg_available "$pkg"; then | |
| missing_pkgs="$missing_pkgs $pkg" | |
| continue | |
| fi | |
| case " $pkgs " in | |
| *" $pkg "*) ;; | |
| *) pkgs="$pkgs $pkg" ;; | |
| esac | |
| done | |
| done | |
| [ -n "$missing_pkgs" ] && echo "$missing_pkgs" >&2 | |
| echo "$pkgs" | |
| } | |
| # --------------------------------------------------------------------- | |
| # Report the RHEL-family packages that were skipped because the enabled | |
| # repos do not provide them. | |
| # --------------------------------------------------------------------- | |
| note_missing() { | |
| [ -n "$1" ] || return 0 | |
| echo "Note: these packages are not available on the enabled repos" >&2 | |
| echo "and were not installed, so the features they enable will stay" >&2 | |
| echo "off in a perf build:" >&2 | |
| echo "$1" | tr ' ' '\n' | grep -v '^$' | sort -u | sed 's/^/ /' >&2 | |
| echo >&2 | |
| } | |
| # --------------------------------------------------------------------- | |
| # 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|rhel) | |
| echo "dnf install -y $*" | |
| ;; | |
| ubuntu|debian) | |
| # a fresh container has no package index, so update first; run | |
| # with a noninteractive debconf frontend: default-jdk, used by | |
| # the jvmti feature tests, pulls in tzdata, which prompts for | |
| # the timezone on a terminal and would block the install. The | |
| # env var prefix works with the 'sh -c' invocation below, and | |
| # shows up in --dry-run. | |
| echo "DEBIAN_FRONTEND=noninteractive apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y $*" | |
| ;; | |
| esac | |
| } | |
| main() { | |
| local action="install" | |
| # Package accumulation happens in package_set(), which, together | |
| # with the *_pkg_for() helpers, declares the per-feature 'pkg' | |
| # locals; main() holds no per-feature package state, just the | |
| # distro-wide list assembled by package_set(). | |
| local srcdir distro pkgs cmd missing_file missing_pkgs | |
| 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|rhel|ubuntu|debian) ;; | |
| *) | |
| echo "error: unsupported distro (got '$distro'); the package mapping is not validated on other distros." >&2 | |
| echo "Supported and validated: Fedora 44 (toolbx container), Ubuntu 26.04 and Debian 13 (distrobox containers), and CentOS Stream 10 (distrobox container)." >&2 | |
| exit 1 | |
| ;; | |
| esac | |
| # The RHEL family mapping probes the enabled repos with dnf | |
| # repoquery and installs with dnf, so reject the yum-only members of | |
| # the family (RHEL 7 and earlier, e.g. Oracle Linux 7) with a clear | |
| # error instead of silently judging every package as unavailable. | |
| if [ "$distro" = "rhel" ] && ! command -v dnf >/dev/null 2>&1; then | |
| echo "error: dnf not found, the RHEL family package mapping requires dnf (RHEL 8 and later)." >&2 | |
| exit 1 | |
| fi | |
| missing_file=$(mktemp) || { | |
| echo "error: cannot create a temporary file (mktemp failed)" >&2 | |
| exit 1 | |
| } | |
| # package_set() runs in a subshell, doing dnf repoquery loops that | |
| # may be interrupted: a Ctrl-C during those loops hits these traps, | |
| # turning SIGINT/SIGTERM into an exit that triggers the EXIT trap, | |
| # removing the temp file, so the script terminates instead of | |
| # resuming after the interrupted command, leaving no file behind. | |
| trap 'rm -f "$missing_file"' EXIT | |
| trap 'exit 1' INT TERM | |
| pkgs=$(package_set "$distro" "$srcdir" 2>"$missing_file") | |
| missing_pkgs=$(cat "$missing_file") | |
| rm -f "$missing_file" | |
| trap - EXIT INT TERM | |
| case "$action" in | |
| list) | |
| echo "$pkgs" | tr ' ' '\n' | grep -v '^$' | sort | |
| note_missing "$missing_pkgs" | |
| exit 0 | |
| ;; | |
| dry-run) | |
| install_cmd "$distro" $pkgs | |
| note_missing "$missing_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 | |
| } | |
| note_missing "$missing_pkgs" | |
| } | |
| main "$@" |