about summary refs log tree commit diff
path: root/src/core/bpf/meson.build
blob: 39b978dd75834f5eda641df58f2cd87474012f65 (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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# SPDX-License-Identifier: LGPL-2.1+

# Ripped from systemd: https://github.com/systemd/systemd/pull/20429

if not enable_clat
  subdir_done()
endif

bpf_compiler = get_option('bpf-compiler')
clang_found = false
clang_supports_bpf = false
bpf_gcc_found = false
bpftool_strip = false

if bpf_compiler == 'clang' or bpf_compiler == 'auto'
  # Support 'versioned' clang/llvm-strip binaries, as seen on Debian/Ubuntu
  # (like clang-10/llvm-strip-10)
  if meson.is_cross_build() or cc.get_id() != 'clang' or cc.cmd_array()[0].contains('afl-clang') or cc.cmd_array()[0].contains('hfuzz-clang')
    r = find_program('clang',
                     version : '>= 10.0.0')
    clang_found = r.found()
    if clang_found
      if meson.version().version_compare('>= 0.55')
        clang = r.full_path()
      else
        clang = r.path()
      endif
    endif
  else
    clang_found = true
    clang = cc.cmd_array()
  endif

  if clang_found
    # Check if 'clang -target bpf' is supported.
    clang_supports_bpf = run_command(clang, '-target', 'bpf', '--print-supported-cpus', check : false).returncode() == 0
  endif
elif bpf_compiler == 'gcc' or bpf_compiler == 'auto'
  bpf_gcc = find_program('bpf-gcc',
                         'bpf-none-gcc',
                         'bpf-unknown-none-gcc',
                         version : '>= 13.1.0')
  bpf_gcc_found = bpf_gcc.found()
endif

if bpf_compiler == 'auto'
  if clang_supports_bpf and bpf_gcc_found
    # Both supported, prefer the one matching our compiler:
    if cc.get_id() == 'gcc'
      bpf_compiler = 'gcc'
    else
      # Default to clang if we don't know this compiler
      bpf_compiler = 'clang'
    endif
  elif clang_supports_bpf
    bpf_compiler = 'clang'
  elif bpf_gcc_found
    bpf_compiler = 'clang'
  endif
endif

if clang_supports_bpf or bpf_gcc_found
  # Debian installs this in /usr/sbin/ which is not in $PATH.
  # We check for 'bpftool' first, honouring $PATH, and in /usr/sbin/ for Debian.
  # We use 'bpftool gen object' subcommand for bpftool strip, it was added by d80b2fcbe0a023619e0fc73112f2a02c2662f6ab (v5.13).
  bpftool = find_program('bpftool',
                         '/usr/sbin/bpftool',
                         required : bpf_compiler == 'gcc',
                         version : bpf_compiler == 'gcc' ? '>= 7.0.0' : '>= 5.13.0')

  if bpftool.found()
    bpftool_strip = true
  elif bpf_compiler == 'clang'
    # We require the 'bpftool gen skeleton' subcommand, it was added by 985ead416df39d6fe8e89580cc1db6aa273e0175 (v5.6).
    bpftool = find_program('bpftool',
                           '/usr/sbin/bpftool',
                           required : true,
                           version : '>= 5.6.0')
  endif

  # We use `llvm-strip` as a fallback if `bpftool gen object` strip support is not available.
  if not bpftool_strip and bpftool.found() and clang_supports_bpf
    if not meson.is_cross_build()
      llvm_strip_bin = run_command(clang, '--print-prog-name', 'llvm-strip',
                                   check : true).stdout().strip()
    else
      llvm_strip_bin = 'llvm-strip'
    endif
    llvm_strip = find_program(llvm_strip_bin,
                              required : true,
                              version : '>= 10.0.0')
  endif
else
  error('clat support was enabled but couldn\'t find a suitable BPF compiler!')
endif

bpf_clang_flags = [
  '-std=gnu17',
  '-Wunused',
  '-Wimplicit-fallthrough',
  '-Wno-compare-distinct-pointer-types',
  '-fno-stack-protector',
  '-O2',
  '-target',
  'bpf',
  '-g',
  '-c',
]

bpf_gcc_flags = [
  '-std=gnu17',
  '-Wunused',
  '-Wimplicit-fallthrough',
  '-fno-stack-protector',
  '-fno-ssa-phiopt',
  '-O2',
  '-mcpu=v3',
  '-mco-re',
  '-gbtf',
  '-c',
]

clang_arch_flag = '-D__@0@__'.format(host_machine.cpu_family())

libbpf_include_dir = dependency('libbpf').get_variable(pkgconfig : 'includedir')

# Generate defines that are appropriate to tell the compiler what architecture
# we're compiling for. By default we just map meson's cpu_family to __<cpu_family>__.
# This dictionary contains the exceptions where this doesn't work.
#
# C.f. https://mesonbuild.com/Reference-tables.html#cpu-families
# and src/basic/missing_syscall_def.h.
cpu_arch_defines = {
  'ppc'         : ['-D__powerpc__', '-D__TARGET_ARCH_powerpc'],
  'ppc64'       : ['-D__powerpc64__', '-D__TARGET_ARCH_powerpc', '-D_CALL_ELF=2'],
  'riscv32'     : ['-D__riscv', '-D__riscv_xlen=32', '-D__TARGET_ARCH_riscv'],
  'riscv64'     : ['-D__riscv', '-D__riscv_xlen=64', '-D__TARGET_ARCH_riscv'],
  'x86'         : ['-D__i386__', '-D__TARGET_ARCH_x86'],
  's390x'       : ['-D__s390__', '-D__s390x__', '-D__TARGET_ARCH_s390'],

  # For arm, assume hardware fp is available.
  'arm'         : ['-D__arm__', '-D__ARM_PCS_VFP', '-D__TARGET_ARCH_arm'],
  'loongarch64' : ['-D__loongarch__', '-D__loongarch_grlen=64', '-D__TARGET_ARCH_loongarch']
}

bpf_arch_flags = cpu_arch_defines.get(host_machine.cpu_family(),
                                      ['-D__@0@__'.format(host_machine.cpu_family())])
if bpf_compiler == 'gcc'
  bpf_arch_flags += ['-m' + host_machine.endian() + '-endian']
endif

bpf_o_unstripped_cmd = []
if bpf_compiler == 'clang'
  bpf_o_unstripped_cmd += [
    clang,
    bpf_clang_flags,
    bpf_arch_flags,
  ]
elif bpf_compiler == 'gcc'
  bpf_o_unstripped_cmd += [
    bpf_gcc,
    bpf_gcc_flags,
    bpf_arch_flags,
  ]
endif

bpf_o_unstripped_cmd += ['-I.']

if cc.get_id() == 'gcc' or meson.is_cross_build()
  if cc.get_id() != 'gcc'
    warning('Cross compiler is not gcc. Guessing the target triplet for bpf likely fails.')
  endif
  target_triplet_cmd = run_command(cc.cmd_array(), '-print-multiarch', check: false)
else
  # clang does not support -print-multiarch (D133170) and its -dump-machine
  # does not match multiarch. Query gcc instead.
  target_triplet_cmd = run_command('gcc', '-print-multiarch', check: false)
endif

if target_triplet_cmd.returncode() == 0
  target_triplet = target_triplet_cmd.stdout().strip()
  bpf_o_unstripped_cmd += [
    '-isystem',
    '/usr/include/@0@'.format(target_triplet)
  ]
endif

bpf_o_unstripped_cmd += [
  '-idirafter',
  libbpf_include_dir,
  '@INPUT@',
  '-o',
  '@OUTPUT@'
]

if bpftool_strip
  bpf_o_cmd = [
    bpftool,
    'gen',
    'object',
    '@OUTPUT@',
    '@INPUT@'
  ]
elif bpf_compiler == 'clang'
  bpf_o_cmd = [
    llvm_strip,
    '-g',
    '@INPUT@',
    '-o',
    '@OUTPUT@'
  ]
endif

skel_h_cmd = [
  bpftool,
  'g',
  's',
  '@INPUT@'
]

clat_bpf_o_unstripped = custom_target(
  'clat.bpf.unstripped.o',
  input : 'clat.bpf.c',
  output : 'clat.bpf.unstripped.o',
  command : bpf_o_unstripped_cmd)

clat_bpf_o = custom_target(
  'clat.bpf.o',
  input : clat_bpf_o_unstripped,
  output : 'clat.bpf.o',
  command : bpf_o_cmd)

clat_skel_h = custom_target(
  'clat.skel.h',
  input : clat_bpf_o,
  output : 'clat.skel.h',
  command : skel_h_cmd,
  capture : true)