]>
Commit | Line | Data |
---|---|---|
cf4f9a57 | 1 | #!/usr/bin/env python3 |
948def4a | 2 | # SPDX-License-Identifier: LGPL-2.1-or-later |
cf4f9a57 JK |
3 | |
4 | import argparse | |
5 | import logging | |
6 | import pathlib | |
c5fd89ad | 7 | import re |
cf4f9a57 JK |
8 | import subprocess |
9 | import sys | |
10 | ||
11 | def clang_arch_flag(arch): | |
12 | return '-D__{}__'.format(arch) | |
13 | ||
14 | ||
15 | def target_triplet(): | |
16 | gcc_exec = 'gcc' | |
17 | ||
18 | try: | |
19 | return subprocess.check_output([gcc_exec, '-dumpmachine'], | |
20 | universal_newlines=True).strip() | |
21 | except subprocess.CalledProcessError as e: | |
22 | logging.error('Failed to get target triplet: {}'.format(e)) | |
23 | except FileNotFoundError: | |
24 | logging.error('gcc not installed') | |
25 | return None | |
26 | ||
27 | ||
28 | def clang_compile(clang_exec, clang_flags, src_c, out_file, target_arch, | |
29 | target_triplet): | |
30 | clang_args = [clang_exec, *clang_flags, target_arch, '-I.'] | |
31 | ||
32 | if target_triplet: | |
33 | clang_args += [ | |
34 | '-isystem', | |
35 | '/usr/include/{}'.format(target_triplet)] | |
36 | ||
37 | clang_args += [ | |
38 | '-idirafter', | |
39 | '/usr/local/include', | |
40 | '-idirafter', | |
41 | '/usr/include'] | |
42 | ||
43 | clang_args += [src_c, '-o', out_file] | |
44 | ||
45 | logging.debug('{}'.format(' '.join(clang_args))) | |
46 | subprocess.check_call(clang_args) | |
47 | ||
48 | ||
49 | def llvm_strip(llvm_strip_exec, in_file): | |
50 | llvm_strip_args = [llvm_strip_exec, '-g', in_file] | |
51 | ||
52 | logging.debug('Stripping useless DWARF info:') | |
53 | logging.debug('{}'.format(' '.join(llvm_strip_args))) | |
54 | ||
55 | subprocess.check_call(llvm_strip_args) | |
56 | ||
57 | ||
58 | def gen_bpf_skeleton(bpftool_exec, in_file, out_fd): | |
59 | bpftool_args = [bpftool_exec, 'g', 's', in_file] | |
60 | ||
61 | logging.debug('Generating BPF skeleton:') | |
62 | logging.debug('{}'.format(' '.join(bpftool_args))) | |
c5fd89ad LB |
63 | skel = subprocess.check_output(bpftool_args, universal_newlines=True) |
64 | # libbpf is used via dlopen(), so rename symbols as defined | |
65 | # in src/shared/bpf-dlopen.h | |
66 | skel = re.sub(r'(bpf_object__\w+_skeleton)', r'sym_\1', skel) | |
67 | out_fd.write(skel) | |
cf4f9a57 JK |
68 | |
69 | ||
70 | def bpf_build(args): | |
71 | clang_flags = [ | |
72 | '-Wno-compare-distinct-pointer-types', | |
73 | '-O2', | |
74 | '-target', | |
75 | 'bpf', | |
76 | '-g', | |
77 | '-c', | |
78 | ] | |
79 | ||
80 | clang_out_path = pathlib.Path(args.bpf_src_c).with_suffix('.o') | |
81 | with clang_out_path.open(mode='w') as clang_out, \ | |
82 | open(args.bpf_skel_h, mode='w') as bpf_skel_h: | |
83 | clang_compile(clang_exec=args.clang_exec, | |
84 | clang_flags=clang_flags, | |
85 | src_c=args.bpf_src_c, | |
86 | out_file=clang_out.name, | |
87 | target_arch=clang_arch_flag(args.arch), | |
88 | target_triplet=target_triplet()) | |
89 | ||
90 | llvm_strip(llvm_strip_exec=args.llvm_strip_exec, in_file=clang_out.name) | |
91 | ||
92 | gen_bpf_skeleton(bpftool_exec=args.bpftool_exec, | |
93 | in_file=clang_out.name, | |
94 | out_fd=bpf_skel_h) | |
95 | ||
96 | if __name__ == '__main__': | |
97 | parser = argparse.ArgumentParser() | |
98 | ||
99 | parser.add_argument( | |
100 | 'bpf_src_c', | |
101 | help='Path to *.c source of BPF program in systemd source tree \ | |
102 | relative to the work directory') | |
103 | ||
104 | parser.add_argument( | |
105 | 'bpf_skel_h', | |
106 | help='Path to C header file') | |
107 | ||
108 | parser.add_argument( | |
109 | '--clang_exec', | |
110 | help='Path to clang exec') | |
111 | ||
112 | parser.add_argument( | |
113 | '--llvm_strip_exec', | |
114 | help='Path to llvm-strip exec') | |
115 | ||
116 | parser.add_argument( | |
117 | '--bpftool_exec', | |
118 | help='Path to bpftool exec') | |
119 | ||
120 | parser.add_argument( | |
121 | '--arch', | |
122 | help='Target CPU architecture', | |
123 | default='x86_64') | |
124 | ||
125 | args = parser.parse_args(); | |
126 | ||
127 | logging.basicConfig(stream=sys.stderr, level=logging.WARNING) | |
128 | bpf_build(args) |