spack/var/spack/repos/builtin/packages/linux-perf/package.py
Bernhard Kaindl 831b4a3e4a linux-perf: If clang is in PATH, pass "CLANG=" + shutil.which("clang")
When clang is installed I get `clang: Permission denied`.
Setting CLANG to the full path of clang fixes this.

Signed-off-by: Bernhard Kaindl <bernhardkaindl7@gmail.com>
2024-08-07 13:34:07 +02:00

274 lines
9.3 KiB
Python

# Copyright 2013-2024 Lawrence Livermore National Security, LLC and other
# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import os.path
import re
import shutil
from textwrap import dedent
import llnl.util.tty as tty
from spack.package import *
class LinuxPerf(Package):
"""The Linux perf tool."""
homepage = "https://www.kernel.org/"
url = "https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.5.5.tar.xz"
executables = ["^perf$"]
maintainers("Jordan474")
version("6.9.10", sha256="efd12e335fa67d13a3eae30e4b7b7546e74b8ccc90682e4c3fffab0b22654da1")
version("6.6.41", sha256="9ec99c578158ab85d99b37791a76643d2ea4c3f72ecbef7b5eb6d60f3de032ef")
version("5.15.163", sha256="025fc7d8b1560cf456ccae50591fe1ca21c990645df9791aed25820fe78db302")
variant("libtraceevent", default=True, description="recommended dependency")
variant("python", default=True, description="Python support")
variant("perl", default=True, description="perl script extension")
variant("slang", default=True, description="TUI support")
variant("libpfm4", default=True, description="libpfm4 events extension")
variant("babeltrace", default=True, description="libbabeltrace support for CTF data format")
variant("libcap", default=True, description="process capabilities considered by perf")
variant("numactl", default=True, description="numa perf benchmark")
variant(
"libaudit",
default=False,
description=(
"get perf-trace syscall table from libaudit at runtime,"
" rather than unistd.h at buildtime"
),
)
variant("debuginfod", default=False, description="support debuginfod")
variant(
"zstd",
default=True,
description="Zstandard based runtime trace compression in record mode",
)
variant("xz", default=True, description="xz kernel module decompression")
variant(
"openssl",
default=True,
description="support generating build-ids for ELFs generated by jitdump",
)
variant("jvmti", default=False, description="build jvmti agent")
depends_on("c", type="build")
depends_on("gmake", type="build")
depends_on("pkgconfig", type="build")
depends_on("flex", type="build")
depends_on("bison", type="build")
depends_on("elfutils")
depends_on("elfutils +debuginfod", when="+debuginfod")
depends_on("libunwind components=ptrace")
depends_on("libiberty")
depends_on("binutils", type=("build", "link", "run"))
depends_on("zlib-api")
depends_on("libtraceevent", when="+libtraceevent")
# jevents requires python >= 3.6
depends_on("python@3.6:", type=("build", "link", "run"), when="+python")
depends_on("py-setuptools", type="build", when="+python")
depends_on("perl", when="+perl")
depends_on("slang", when="+slang")
depends_on("libpfm4", when="+libpfm4")
depends_on("babeltrace@1.5:", when="+babeltrace")
depends_on("libcap", when="+libcap")
depends_on("audit-userspace", when="+libaudit")
depends_on("numactl", when="+numactl")
depends_on("zstd", when="+zstd")
depends_on("xz", when="+xz")
depends_on("openssl", when="+openssl")
depends_on("openssl@1.1:", when="@5.19: +openssl")
depends_on("java", when="+jvmti")
depends_on("asciidoc", type="build")
depends_on("xmlto", type="build")
conflicts(
"~libtraceevent",
when="@6.2:",
msg="linux 6.2 removed internal libtraceevent, and it's highly recommended",
)
def url_for_version(self, version):
return f"https://cdn.kernel.org/pub/linux/kernel/v{version[0]}.x/linux-{version}.tar.xz"
def setup_build_environment(self, env):
# This variable is used in the Makefile. If it is defined on the
# system, it can break the build if there is no build recipe for
# that specific ARCH
env.unset("ARCH")
@property
def archive_files(self):
return [join_path(self.stage.source_path, "tools/perf/FEATURE-DUMP")]
def install(self, spec, prefix):
# TODO:
# - GTK2=
# - NO_LIBBPF=1 ?
# - d3 flamegraph resources (libexec/perf-core/scripts/python/flamegraph.py)
version = self.spec.version
args = [
"LIBDW_DIR={}".format(spec["elfutils"].prefix),
"LIBUNWIND_DIR={}".format(spec["libunwind"].prefix),
"NO_SHELLCHECK=1",
]
# Setup clang if found in the system's or env's PATH:
clang = shutil.which("clang")
if clang:
args.append("CLANG=" + clang)
# Features to check post-install against `perf version --build-options`
checks = {"dwarf", "libunwind", "libbfd", "zlib"}
if version >= Version("6.4"):
args.append("BUILD_NONDISTRO=1")
if "+libaudit" in spec:
checks.add("libaudit")
args.append("NO_SYSCALL_TABLE=1") # will look for libaudit
else:
checks.add("syscall_table")
args.append("NO_LIBAUDIT=1")
if "+debuginfod" in spec:
if version >= Version("5.19"): # Not in --build-options before that
checks.add("debuginfod")
else:
args.append("NO_LIBDEBUGINFOD=1")
if "+python" in spec:
checks.add("libpython")
args.extend(
[
"PYTHON={}".format(spec["python"].command),
"PYTHON_CONFIG={}".format(spec["python"].prefix.bin.join("python-config")),
]
)
else:
args.append("NO_LIBPYTHON=1")
if "+perl" in spec:
checks.add("libperl")
else:
args.append("NO_LIBPERL=1")
if "+openssl" in spec:
checks.add("libcrypto")
else:
args.append("NO_LIBCRYPTO=1")
if "+slang" in spec:
checks.add("libslang")
else:
args.append("NO_SLANG=1")
if "+libpfm4" in spec:
checks.add("libpfm4")
if version < Version("6.4"):
args.append("LIBPFM4=1")
else:
if version >= Version("6.4"):
args.append("NO_LIBPFM4=1")
if "+babeltrace" in spec:
# checks.add("babeltrace") # Not in --build-options ?
args.append("LIBBABELTRACE_DIR={}".format(spec["babeltrace"].prefix))
else:
args.append("NO_LIBBABELTRACE=1")
if "+libcap" in spec:
# checks.add("libcap") # Not in --build-options ?
pass
else:
args.append("NO_LIBCAP=1")
if "+numactl" in spec:
checks.add("libnuma")
else:
args.append("NO_LIBNUMA=1")
if "+xz" in spec:
checks.add("lzma")
else:
args.append("NO_LZMA=1")
if "+zstd" in spec:
checks.add("zstd")
args.append("LIBZSTD_DIR={}".format(spec["zstd"].prefix))
else:
args.append("NO_LIBZSTD=1")
if "+libtraceevent" in spec:
if version >= Version("6.2"): # Not in --build-options before that
checks.add("libtraceevent")
if version >= Version("6.10"):
args.append("LIBTRACEEVENT_DIR={}".format(spec["libtraceevent"].prefix))
if version < Version("6.2"):
args.append("LIBTRACEEVENT_DYNAMIC=1")
else:
if version >= Version("6.2"):
args.append("NO_LIBTRACEEVENT=1")
if "+jvmti" in spec:
# checks.add("jvmti") # Not in --build-options ?
args.append("JDIR={}".format(spec["java"].prefix))
else:
args.append("NO_JVMTI=1")
with working_dir("tools/perf"):
make(
"V=1",
f"JOBS={make_jobs}",
f"prefix={prefix}",
"DESTDIR=",
*args,
"all",
"install",
parallel=False,
)
# Create a perfconfig with binutils paths
perfconfig = str(prefix.join("etc/perfconfig"))
assert not os.path.exists(perfconfig)
mkdirp(os.path.dirname(perfconfig))
with open(perfconfig, "w") as f:
f.write(
dedent(
"""\
[annotate]
addr2line = {addr2line}
objdump = {objdump}
"""
).format(
addr2line=spec["binutils"].prefix.bin.join("addr2line"),
objdump=spec["binutils"].prefix.bin.join("objdump"),
)
)
# Post-install dependency check:
# $ perf version --build-options
# perf version 6.5.7
# dwarf: [ on ] # HAVE_DWARF_SUPPORT
# ...
perf = Executable(self.prefix.bin.perf)
output = perf("version", "--build-options", output=str, error=str)
tty.msg(output) # keep a trace in build log
enabled = set(re.findall(r"^\s*(\S+)\s*:\s*\[\s*on\s*\]", output, re.MULTILINE))
missing = set(checks) - enabled
tty.msg(f"detected features: {sorted(enabled)!r}")
tty.msg(f"expected features: {sorted(checks)!r}")
if missing:
raise InstallError(f"Perf is missing features {sorted(missing)!r}, see log")