2020-11-14 04:02:50 +03:00
#!/usr/bin/env python3
2021-09-29 20:16:09 +03:00
# SPDX-License-Identifier: LGPL-2.1-or-later
2020-11-14 04:02:50 +03:00
import argparse
import logging
import pathlib
2021-05-23 15:04:53 +03:00
import re
2020-11-14 04:02:50 +03:00
import subprocess
import sys
def clang_arch_flag ( arch ) :
return ' -D__ {} __ ' . format ( arch )
def target_triplet ( ) :
gcc_exec = ' gcc '
try :
return subprocess . check_output ( [ gcc_exec , ' -dumpmachine ' ] ,
universal_newlines = True ) . strip ( )
except subprocess . CalledProcessError as e :
logging . error ( ' Failed to get target triplet: {} ' . format ( e ) )
except FileNotFoundError :
logging . error ( ' gcc not installed ' )
return None
def clang_compile ( clang_exec , clang_flags , src_c , out_file , target_arch ,
target_triplet ) :
clang_args = [ clang_exec , * clang_flags , target_arch , ' -I. ' ]
if target_triplet :
clang_args + = [
' -isystem ' ,
' /usr/include/ {} ' . format ( target_triplet ) ]
clang_args + = [
' -idirafter ' ,
' /usr/local/include ' ,
' -idirafter ' ,
' /usr/include ' ]
clang_args + = [ src_c , ' -o ' , out_file ]
logging . debug ( ' {} ' . format ( ' ' . join ( clang_args ) ) )
subprocess . check_call ( clang_args )
def llvm_strip ( llvm_strip_exec , in_file ) :
llvm_strip_args = [ llvm_strip_exec , ' -g ' , in_file ]
logging . debug ( ' Stripping useless DWARF info: ' )
logging . debug ( ' {} ' . format ( ' ' . join ( llvm_strip_args ) ) )
subprocess . check_call ( llvm_strip_args )
def gen_bpf_skeleton ( bpftool_exec , in_file , out_fd ) :
bpftool_args = [ bpftool_exec , ' g ' , ' s ' , in_file ]
logging . debug ( ' Generating BPF skeleton: ' )
logging . debug ( ' {} ' . format ( ' ' . join ( bpftool_args ) ) )
2021-05-23 15:04:53 +03:00
skel = subprocess . check_output ( bpftool_args , universal_newlines = True )
# libbpf is used via dlopen(), so rename symbols as defined
# in src/shared/bpf-dlopen.h
skel = re . sub ( r ' (bpf_object__ \ w+_skeleton) ' , r ' sym_ \ 1 ' , skel )
out_fd . write ( skel )
2020-11-14 04:02:50 +03:00
def bpf_build ( args ) :
clang_flags = [
' -Wno-compare-distinct-pointer-types ' ,
' -O2 ' ,
' -target ' ,
' bpf ' ,
' -g ' ,
' -c ' ,
]
clang_out_path = pathlib . Path ( args . bpf_src_c ) . with_suffix ( ' .o ' )
with clang_out_path . open ( mode = ' w ' ) as clang_out , \
open ( args . bpf_skel_h , mode = ' w ' ) as bpf_skel_h :
clang_compile ( clang_exec = args . clang_exec ,
clang_flags = clang_flags ,
src_c = args . bpf_src_c ,
out_file = clang_out . name ,
target_arch = clang_arch_flag ( args . arch ) ,
target_triplet = target_triplet ( ) )
llvm_strip ( llvm_strip_exec = args . llvm_strip_exec , in_file = clang_out . name )
gen_bpf_skeleton ( bpftool_exec = args . bpftool_exec ,
in_file = clang_out . name ,
out_fd = bpf_skel_h )
if __name__ == ' __main__ ' :
parser = argparse . ArgumentParser ( )
parser . add_argument (
' bpf_src_c ' ,
help = ' Path to *.c source of BPF program in systemd source tree \
relative to the work directory ' )
parser . add_argument (
' bpf_skel_h ' ,
help = ' Path to C header file ' )
parser . add_argument (
' --clang_exec ' ,
help = ' Path to clang exec ' )
parser . add_argument (
' --llvm_strip_exec ' ,
help = ' Path to llvm-strip exec ' )
parser . add_argument (
' --bpftool_exec ' ,
help = ' Path to bpftool exec ' )
parser . add_argument (
' --arch ' ,
help = ' Target CPU architecture ' ,
default = ' x86_64 ' )
args = parser . parse_args ( ) ;
logging . basicConfig ( stream = sys . stderr , level = logging . WARNING )
bpf_build ( args )