summaryrefslogtreecommitdiff
path: root/tools/perf/util/setup.py
blob: cb14554454a2168e301518916744511b431bf0dc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
from os import getenv, path
from subprocess import Popen, PIPE
from re import sub
import shlex
import shutil

cc = getenv("CC")
assert cc, "Environment variable CC not set"

# Check if CC has options, as is the case in yocto, where it uses CC="cc --sysroot..."
cc_tokens = cc.split()
if len(cc_tokens) > 1:
    cc = cc_tokens[0]
    cc_options = " ".join([str(e) for e in cc_tokens[1:]]) + " "
else:
    cc_options = ""

# ignore optional stderr could be None as it is set to PIPE to avoid that.
# mypy: disable-error-code="union-attr"
cc_is_clang = b"clang version" in Popen([cc, "-v"], stderr=PIPE).stderr.readline()

srctree = getenv('srctree')
assert srctree, "Environment variable srctree, for the Linux sources, not set"
src_feature_tests  = f'{srctree}/tools/build/feature'

def clang_has_option(option):
    error_substrings = (
        b"unknown argument",
        b"is not supported",
        b"unknown warning option"
    )
    cmd = shlex.split(f"{cc} {cc_options} {option}") + [
        "-o", "/dev/null",
        path.join(src_feature_tests, "test-hello.c")
    ]
    cc_output = Popen(cmd, stderr=PIPE).stderr.readlines()
    return not any(any(error in line for error in error_substrings) for line in cc_output)

if cc_is_clang:
    from sysconfig import get_config_vars
    vars = get_config_vars()
    for var in ('CFLAGS', 'OPT'):
        vars[var] = sub("-specs=[^ ]+", "", vars[var])
        if not clang_has_option("-mcet"):
            vars[var] = sub("-mcet", "", vars[var])
        if not clang_has_option("-fcf-protection"):
            vars[var] = sub("-fcf-protection", "", vars[var])
        if not clang_has_option("-fstack-clash-protection"):
            vars[var] = sub("-fstack-clash-protection", "", vars[var])
        if not clang_has_option("-fstack-protector-strong"):
            vars[var] = sub("-fstack-protector-strong", "", vars[var])
        if not clang_has_option("-fno-semantic-interposition"):
            vars[var] = sub("-fno-semantic-interposition", "", vars[var])
        if not clang_has_option("-ffat-lto-objects"):
            vars[var] = sub("-ffat-lto-objects", "", vars[var])
        if not clang_has_option("-ftree-loop-distribute-patterns"):
            vars[var] = sub("-ftree-loop-distribute-patterns", "", vars[var])
        if not clang_has_option("-gno-variable-location-views"):
            vars[var] = sub("-gno-variable-location-views", "", vars[var])

from setuptools import setup, Extension

from setuptools.command.build_ext   import build_ext   as _build_ext
from setuptools.command.install_lib import install_lib as _install_lib

class build_ext(_build_ext):
    def finalize_options(self):
        _build_ext.finalize_options(self)
        self.build_lib  = build_lib
        self.build_temp = build_tmp

class install_lib(_install_lib):
    def finalize_options(self):
        _install_lib.finalize_options(self)
        self.build_dir = build_lib

    def run(self):
        _install_lib.run(self)
        shutil.copy2(f'{src_perf}/python/perf.pyi', self.install_dir)


# switch off several checks (need to be at the end of cflags list)
extra_cflags = ['-fno-strict-aliasing', '-Wno-write-strings', '-Wno-unused-parameter', '-Wno-redundant-decls' ]
if cc_is_clang:
    extra_cflags += ["-Wno-unused-command-line-argument" ]
    if clang_has_option("-Wno-cast-function-type-mismatch"):
        extra_cflags += ["-Wno-cast-function-type-mismatch" ]
else:
    extra_cflags += ['-Wno-cast-function-type' ]

# The python headers have mixed code with declarations (decls after asserts, for instance)
extra_cflags += [ "-Wno-declaration-after-statement" ]

src_perf  = f'{srctree}/tools/perf'
build_lib = getenv('PYTHON_EXTBUILD_LIB')
build_tmp = getenv('PYTHON_EXTBUILD_TMP')

perf = Extension('perf',
                 sources = [ src_perf + '/util/python.c' ],
		         include_dirs = ['util/include'],
		         extra_compile_args = extra_cflags,
                 )

setup(name='perf',
      version='0.1',
      description='Interface with the Linux profiling infrastructure',
      author='Arnaldo Carvalho de Melo',
      author_email='acme@redhat.com',
      license='GPLv2',
      url='http://perf.wiki.kernel.org',
      ext_modules=[perf],
      cmdclass={'build_ext': build_ext, 'install_lib': install_lib})