diff --git a/meson.build b/meson.build index 4a114ed51b..62c605129f 100644 --- a/meson.build +++ b/meson.build @@ -1020,58 +1020,74 @@ conf.set10('HAVE_LIBBPF', libbpf.found()) if want_bpf_framework == 'false' or not libbpf.found() or skip_deps conf.set10('BPF_FRAMEWORK', false) else - # 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', required : bpf_framework_required, version : '>= 10.0.0') - clang_found = r.found() - if clang_found - clang = r.path() + bpf_compiler = get_option('bpf-compiler') + clang_found = false + clang_supports_bpf = false + bpf_gcc_found = false + deps_found = false + + if bpf_compiler == 'clang' + # 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', required : bpf_framework_required, version : '>= 10.0.0') + clang_found = r.found() + if clang_found + clang = r.path() + endif + # Assume that the required flags are supported by the found clang. + clang_supports_flags = clang_found + else + clang_found = true + clang = cc.cmd_array() + clang_supports_flags = cc.has_argument('-Wno-compare-distinct-pointer-types') endif - # Assume that the required flags are supported by the found clang. - clang_supports_flags = clang_found - else - clang_found = true - clang = cc.cmd_array() - clang_supports_flags = cc.has_argument('-Wno-compare-distinct-pointer-types') + + 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' + warning('GCC BPF Compiler support is experimental and not recommended.') + bpf_gcc = find_program('bpf-gcc', + required : true, + version : '>= 12.1.0') + bpf_gcc_found = bpf_gcc.found() 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 - else - clang_supports_bpf = false - endif - - # 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' subcommand, it was added by 985ead416df39d6fe8e89580cc1db6aa273e0175 (v5.6). - bpftool = find_program('bpftool', - '/usr/sbin/bpftool', - required : false, - version : '>= 5.13.0') - - if bpftool.found() - bpftool_strip = true - else - bpftool_strip = false + 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_framework_required, - version : '>= 5.6.0') - endif + required : false, + version : '>= 5.13.0') - if not bpftool_strip - if not meson.is_cross_build() and clang_found - llvm_strip_bin = run_command(clang, '--print-prog-name', 'llvm-strip', - check : true).stdout().strip() + if bpftool.found() + bpftool_strip = true + deps_found = true else - llvm_strip_bin = 'llvm-strip' + bpftool_strip = false + # We require the 'bpftool gen skeleton' subcommand, it was added by 985ead416df39d6fe8e89580cc1db6aa273e0175 (v5.6). + bpftool = find_program('bpftool', + '/usr/sbin/bpftool', + required : bpf_framework_required, + version : '>= 5.6.0') endif - llvm_strip = find_program(llvm_strip_bin, required : bpf_framework_required, version : '>= 10.0.0') - endif - deps_found = clang_found and clang_supports_bpf and clang_supports_flags and (bpftool_strip or llvm_strip.found()) and bpftool.found() + # 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 : bpf_framework_required, version : '>= 10.0.0') + deps_found = llvm_strip.found() + endif + endif # Can build BPF program from source code in restricted C conf.set10('BPF_FRAMEWORK', deps_found) diff --git a/meson_options.txt b/meson_options.txt index 3bb25c6f76..3a1d7ce0ec 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -496,6 +496,8 @@ option('kernel-install', type: 'boolean', value: 'true', option('analyze', type: 'boolean', value: 'true', description : 'install systemd-analyze') +option('bpf-compiler', type : 'combo', choices : ['clang', 'gcc'], + description: 'compiler used to build BPF programs, note: gcc is experimental') option('bpf-framework', type : 'combo', choices : ['auto', 'true', 'false'], description: 'build BPF programs from source code in restricted C') diff --git a/src/core/bpf/meson.build b/src/core/bpf/meson.build index c88e457716..c2f9b5ac42 100644 --- a/src/core/bpf/meson.build +++ b/src/core/bpf/meson.build @@ -4,7 +4,7 @@ if conf.get('BPF_FRAMEWORK') != 1 subdir_done() endif -clang_flags = [ +bpf_clang_flags = [ '-Wno-compare-distinct-pointer-types', '-O2', '-target', @@ -13,6 +13,14 @@ clang_flags = [ '-c', ] +bpf_gcc_flags = [ + '-O2', + '-mkernel=5.2', + '-mcpu=v3', + '-mco-re', + '-gbtf', +] + # 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 ____. # This dictionary contains the exceptions where this doesn't work. @@ -30,19 +38,32 @@ cpu_arch_defines = { 'arm' : ['-D__arm__', '-D__ARM_PCS_VFP'], } -clang_arch_flags = cpu_arch_defines.get(host_machine.cpu_family(), - ['-D__@0@__'.format(host_machine.cpu_family())]) +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 libbpf_include_dir = libbpf.get_variable(pkgconfig : 'includedir') -bpf_o_unstripped_cmd = [ - clang, - clang_flags, - clang_arch_flags, - '-I.' -] +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 -if not meson.is_cross_build() +bpf_o_unstripped_cmd += ['-I.'] + +if not meson.is_cross_build() and bpf_compiler == 'clang' target_triplet_cmd = run_command('gcc', '-dumpmachine', check: false) if target_triplet_cmd.returncode() == 0 target_triplet = target_triplet_cmd.stdout().strip() @@ -69,7 +90,7 @@ if bpftool_strip '@OUTPUT@', '@INPUT@' ] -else +elif bpf_compiler == 'clang' bpf_o_cmd = [ llvm_strip, '-g',