Commit dc1254ed authored by yonghong-song's avatar yonghong-song Committed by GitHub

Merge pull request #2149 from iovisor/yhs_dev

use kernel libbpf in bcc
parents d01f4593 16de581c
[submodule "src/cc/libbpf"]
path = src/cc/libbpf
url = https://github.com/libbpf/libbpf.git
......@@ -9,6 +9,12 @@ endif()
enable_testing()
# populate submodules (libbpf)
if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/src/cc/libbpf/src)
execute_process(COMMAND git submodule update --init --recursive
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
endif()
include(cmake/GetGitRevisionDescription.cmake)
include(cmake/version.cmake)
include(CMakeDependentOption)
......
......@@ -15,3 +15,16 @@ else()
endif()
set(CMAKE_REQUIRED_FLAGS "${_backup_c_flags}")
endif()
# check whether reallocarray availability
# this is used to satisfy reallocarray usage under src/cc/libbpf/
CHECK_CXX_SOURCE_COMPILES(
"
#define _GNU_SOURCE
#include <stdlib.h>
int main(void)
{
return !!reallocarray(NULL, 1, 1);
}
" HAVE_REALLOCARRAY_SUPPORT)
......@@ -3,6 +3,7 @@
include_directories(${CMAKE_SOURCE_DIR}/src/cc)
include_directories(${CMAKE_SOURCE_DIR}/src/cc/api)
include_directories(${CMAKE_SOURCE_DIR}/src/cc/libbpf/include/uapi)
option(INSTALL_CPP_EXAMPLES "Install C++ examples. Those binaries are statically linked and can take plenty of disk space" OFF)
......
......@@ -2,7 +2,7 @@
* UseExternalMap shows how to access an external map through
* C++ interface. The external map could be a pinned map.
* This example simulates the pinned map through a locally
* created map by calling libbpf bpf_create_map.
* created map by calling libbpf bcc_create_map.
*
* Copyright (c) Facebook, Inc.
* Licensed under the Apache License, Version 2.0 (the "License")
......@@ -79,10 +79,10 @@ int main() {
int ctrl_map_fd;
uint32_t val;
// create a map through bpf_create_map, bcc knows nothing about this map.
ctrl_map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, "control", sizeof(uint32_t),
// create a map through bcc_create_map, bcc knows nothing about this map.
ctrl_map_fd = bcc_create_map(BPF_MAP_TYPE_ARRAY, "control", sizeof(uint32_t),
sizeof(uint32_t), 1, 0);
CHECK(ctrl_map_fd < 0, "bpf_create_map failure");
CHECK(ctrl_map_fd < 0, "bcc_create_map failure");
// populate control map into TableStorage
std::unique_ptr<ebpf::TableStorage> local_ts =
......
......@@ -3,6 +3,7 @@
include_directories(${CMAKE_SOURCE_DIR}/src/cc)
include_directories(${CMAKE_SOURCE_DIR}/src/cc/api)
include_directories(${CMAKE_SOURCE_DIR}/src/cc/libbpf/include/uapi)
option(INSTALL_INTROSPECTION "Install BPF introspection tools" ON)
......
......@@ -16,11 +16,24 @@ function cleanup() {
}
trap cleanup EXIT
# populate submodules
git submodule update --init --recursive
. scripts/git-tag.sh
git archive HEAD --prefix=bcc/ --format=tar.gz -o $TMP/bcc_$revision.orig.tar.gz
git archive HEAD --prefix=bcc/ --format=tar -o $TMP/bcc_$revision.orig.tar
# archive submodules
pushd src/cc/libbpf
git archive HEAD --prefix=bcc/src/cc/libbpf/ --format=tar -o $TMP/bcc_libbpf_$revision.orig.tar
popd
pushd $TMP
# merge all archives into bcc_$revision.orig.tar.gz
tar -A -f bcc_$revision.orig.tar bcc_libbpf_$revision.orig.tar
gzip bcc_$revision.orig.tar
tar xf bcc_$revision.orig.tar.gz
cd bcc
......
......@@ -14,9 +14,24 @@ mkdir $TMP/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
llvmver=3.7.1
# populate submodules
git submodule update --init --recursive
. scripts/git-tag.sh
git archive HEAD --prefix=bcc/ --format=tar.gz -o $TMP/SOURCES/$git_tag_latest.tar.gz
git archive HEAD --prefix=bcc/ --format=tar -o $TMP/SOURCES/bcc.tar
# archive submodules
pushd src/cc/libbpf
git archive HEAD --prefix=bcc/src/cc/libbpf/ --format=tar -o $TMP/SOURCES/bcc_libbpf.tar
popd
# merge all archives into $git_tag_latest.tar.gz
pushd $TMP/SOURCES
tar -A -f bcc.tar bcc_libbpf.tar
gzip -c bcc.tar > $git_tag_latest.tar.gz
popd
wget -P $TMP/SOURCES http://llvm.org/releases/$llvmver/{cfe,llvm}-$llvmver.src.tar.xz
sed \
......
......@@ -14,9 +14,23 @@ mkdir $TMP/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
llvmver=3.7.1
# populate submodules
git submodule update --init --recursive
. scripts/git-tag.sh
git archive HEAD --prefix=bcc/ --format=tar.gz -o $TMP/SOURCES/bcc.tar.gz
git archive HEAD --prefix=bcc/ --format=tar -o $TMP/SOURCES/bcc.tar
# archive submodules
pushd src/cc/libbpf
git archive HEAD --prefix=bcc/src/cc/libbpf/ --format=tar -o $TMP/SOURCES/bcc_libbpf.tar
popd
# merge all archives into bcc.tar.gz
pushd $TMP/SOURCES
tar -A -f bcc.tar bcc_libbpf.tar
gzip bcc.tar
popd
sed \
-e "s/^\(Version:\s*\)@REVISION@/\1$revision/" \
......
......@@ -10,7 +10,8 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/frontends/clang)
include_directories(${LLVM_INCLUDE_DIRS})
include_directories(${LIBELF_INCLUDE_DIRS})
# todo: if check for kernel version
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/compat)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/libbpf/include)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/libbpf/include/uapi)
add_definitions(${LLVM_DEFINITIONS})
configure_file(libbcc.pc.in ${CMAKE_CURRENT_BINARY_DIR}/libbcc.pc @ONLY)
......@@ -18,14 +19,19 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -DBCC_PROG_TAG_DIR='\"${BCC_PROG_T
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-result")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -Wno-unused-result")
if (NOT HAVE_REALLOCARRAY_SUPPORT)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DCOMPAT_NEED_REALLOCARRAY")
endif()
string(REGEX MATCH "^([0-9]+).*" _ ${LLVM_PACKAGE_VERSION})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DLLVM_MAJOR_VERSION=${CMAKE_MATCH_1}")
include(static_libstdc++)
add_library(bpf-static STATIC libbpf.c perf_reader.c)
file(GLOB libbpf_sources "libbpf/src/*.c")
add_library(bpf-static STATIC libbpf.c perf_reader.c ${libbpf_sources})
set_target_properties(bpf-static PROPERTIES OUTPUT_NAME bpf)
add_library(bpf-shared SHARED libbpf.c perf_reader.c)
add_library(bpf-shared SHARED libbpf.c perf_reader.c ${libbpf_sources})
set_target_properties(bpf-shared PROPERTIES VERSION ${REVISION_LAST} SOVERSION 0)
set_target_properties(bpf-shared PROPERTIES OUTPUT_NAME bpf)
......@@ -105,7 +111,7 @@ set(bcc-lua-static ${bcc-lua-static} ${bcc_common_libs_for_lua})
install(TARGETS bcc-shared LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(FILES ${bcc_table_headers} DESTINATION include/bcc)
install(FILES ${bcc_api_headers} DESTINATION include/bcc)
install(DIRECTORY compat/linux/ DESTINATION include/bcc/compat/linux FILES_MATCHING PATTERN "*.h")
install(DIRECTORY libbpf/include/uapi/linux/ DESTINATION include/bcc/compat/linux FILES_MATCHING PATTERN "*.h")
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libbcc.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
endif(ENABLE_CLANG_JIT)
install(FILES ${bcc_common_headers} DESTINATION include/bcc)
......
The libbpf directory is a git submodule for repository
https://github.com/libbpf/libbpf
If you have any change in libbpf directory, please upstream to linux
first as libbpf repo is a mirror of linux/tools/lib/bpf directory.
If any top-commit update of libbpf submodule contains a uapi header
change, the following are necessary steps to sync properly with
rest of bcc:
1. sync compat/linux/virtual_bpf.h with libbpf/include/uapi/linux/bpf.h
as virtual_bpf.h has an extra string wrapper for bpf.h.
2. if new bpf.h has new helpers, add corresponding helper func define
in bcc:src/cc/export/helpers.h and helper entry for error reporting
in bcc:src/cc/libbpf.c.
3. if new bpf.h has new map types, program types, update
bcc:introspection/bps.c for these new map/program types.
......@@ -550,7 +550,7 @@ StatusTuple BPF::load_func(const std::string& func_name, bpf_prog_type type,
else if (flag_ & DEBUG_BPF)
log_level = 1;
fd = bpf_prog_load(type, func_name.c_str(),
fd = bcc_prog_load(type, func_name.c_str(),
reinterpret_cast<struct bpf_insn*>(func_start), func_size,
bpf_module_->license(), bpf_module_->kern_version(),
log_level, nullptr, 0);
......
......@@ -26,7 +26,7 @@
#include "bcc_exception.h"
#include "bcc_syms.h"
#include "bpf_module.h"
#include "compat/linux/bpf.h"
#include "linux/bpf.h"
#include "libbpf.h"
#include "table_storage.h"
......
......@@ -21,7 +21,7 @@ extern "C" {
#endif
#include <stdint.h>
#include "compat/linux/bpf.h"
#include "linux/bpf.h"
struct bcc_symbol {
const char *name;
......
This source diff could not be displayed because it is too large. You can view the blob instead.
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _UAPI__LINUX_BPF_COMMON_H__
#define _UAPI__LINUX_BPF_COMMON_H__
/* Instruction classes */
#define BPF_CLASS(code) ((code) & 0x07)
#define BPF_LD 0x00
#define BPF_LDX 0x01
#define BPF_ST 0x02
#define BPF_STX 0x03
#define BPF_ALU 0x04
#define BPF_JMP 0x05
#define BPF_RET 0x06
#define BPF_MISC 0x07
/* ld/ldx fields */
#define BPF_SIZE(code) ((code) & 0x18)
#define BPF_W 0x00 /* 32-bit */
#define BPF_H 0x08 /* 16-bit */
#define BPF_B 0x10 /* 8-bit */
/* eBPF BPF_DW 0x18 64-bit */
#define BPF_MODE(code) ((code) & 0xe0)
#define BPF_IMM 0x00
#define BPF_ABS 0x20
#define BPF_IND 0x40
#define BPF_MEM 0x60
#define BPF_LEN 0x80
#define BPF_MSH 0xa0
/* alu/jmp fields */
#define BPF_OP(code) ((code) & 0xf0)
#define BPF_ADD 0x00
#define BPF_SUB 0x10
#define BPF_MUL 0x20
#define BPF_DIV 0x30
#define BPF_OR 0x40
#define BPF_AND 0x50
#define BPF_LSH 0x60
#define BPF_RSH 0x70
#define BPF_NEG 0x80
#define BPF_MOD 0x90
#define BPF_XOR 0xa0
#define BPF_JA 0x00
#define BPF_JEQ 0x10
#define BPF_JGT 0x20
#define BPF_JGE 0x30
#define BPF_JSET 0x40
#define BPF_SRC(code) ((code) & 0x08)
#define BPF_K 0x00
#define BPF_X 0x08
#ifndef BPF_MAXINSNS
#define BPF_MAXINSNS 4096
#endif
#endif /* _UAPI__LINUX_BPF_COMMON_H__ */
......@@ -1108,7 +1108,7 @@ StatusTuple CodegenLLVM::visit_table_decl_stmt_node(TableDeclStmtNode *n) {
decl_gvar->setSection("maps");
tables_[n] = decl_gvar;
int map_fd = bpf_create_map(map_type, n->id_->name_.c_str(),
int map_fd = bcc_create_map(map_type, n->id_->name_.c_str(),
key->bit_width_ / 8, leaf->bit_width_ / 8,
n->size_, 0);
if (map_fd >= 0)
......
......@@ -1230,7 +1230,7 @@ bool BTypeVisitor::VisitVarDecl(VarDecl *Decl) {
}
table.type = map_type;
table.fd = bpf_create_map(map_type, table.name.c_str(),
table.fd = bcc_create_map(map_type, table.name.c_str(),
table.key_size, table.leaf_size,
table.max_entries, table.flags);
}
......
Subproject commit d5b146fec50d7aa126fe98323aeaee688d4af289
......@@ -51,6 +51,8 @@
// TODO: Remove this when CentOS 6 support is not needed anymore
#include "setns.h"
#include "libbpf/src/bpf.h"
// TODO: remove these defines when linux-libc-dev exports them properly
#ifndef __NR_bpf
......@@ -82,7 +84,9 @@
#define AF_ALG 38
#endif
#ifndef min
#define min(x, y) ((x) < (y) ? (x) : (y))
#endif
#define UNUSED(expr) do { (void)(expr); } while (0)
......@@ -191,25 +195,19 @@ static uint64_t ptr_to_u64(void *ptr)
return (uint64_t) (unsigned long) ptr;
}
int bpf_create_map(enum bpf_map_type map_type, const char *name,
int bcc_create_map(enum bpf_map_type map_type, const char *name,
int key_size, int value_size,
int max_entries, int map_flags)
{
size_t name_len = name ? strlen(name) : 0;
union bpf_attr attr;
memset(&attr, 0, sizeof(attr));
attr.map_type = map_type;
attr.key_size = key_size;
attr.value_size = value_size;
attr.max_entries = max_entries;
attr.map_flags = map_flags;
memcpy(attr.map_name, name, min(name_len, BPF_OBJ_NAME_LEN - 1));
int ret = syscall(__NR_bpf, BPF_MAP_CREATE, &attr, sizeof(attr));
char map_name[BPF_OBJ_NAME_LEN];
memcpy(map_name, name, min(name_len, BPF_OBJ_NAME_LEN - 1));
int ret = bpf_create_map_name(map_type, map_name, key_size, value_size,
max_entries, map_flags);
if (ret < 0 && name_len && (errno == E2BIG || errno == EINVAL)) {
memset(attr.map_name, 0, BPF_OBJ_NAME_LEN);
ret = syscall(__NR_bpf, BPF_MAP_CREATE, &attr, sizeof(attr));
ret = bpf_create_map(map_type, key_size, value_size,
max_entries, map_flags);
}
if (ret < 0 && errno == EPERM) {
......@@ -220,7 +218,8 @@ int bpf_create_map(enum bpf_map_type map_type, const char *name,
rl.rlim_max = RLIM_INFINITY;
rl.rlim_cur = rl.rlim_max;
if (setrlimit(RLIMIT_MEMLOCK, &rl) == 0)
ret = syscall(__NR_bpf, BPF_MAP_CREATE, &attr, sizeof(attr));
ret = bpf_create_map(map_type, key_size, value_size,
max_entries, map_flags);
}
}
return ret;
......@@ -483,7 +482,7 @@ int bpf_prog_get_tag(int fd, unsigned long long *ptag)
return 0;
}
int bpf_prog_load(enum bpf_prog_type prog_type, const char *name,
int bcc_prog_load(enum bpf_prog_type prog_type, const char *name,
const struct bpf_insn *insns, int prog_len,
const char *license, unsigned kern_version,
int log_level, char *log_buf, unsigned log_buf_size)
......@@ -1426,59 +1425,3 @@ int bpf_close_perf_event_fd(int fd) {
}
return error;
}
int bpf_obj_pin(int fd, const char *pathname)
{
union bpf_attr attr;
memset(&attr, 0, sizeof(attr));
attr.pathname = ptr_to_u64((void *)pathname);
attr.bpf_fd = fd;
return syscall(__NR_bpf, BPF_OBJ_PIN, &attr, sizeof(attr));
}
int bpf_obj_get(const char *pathname)
{
union bpf_attr attr;
memset(&attr, 0, sizeof(attr));
attr.pathname = ptr_to_u64((void *)pathname);
return syscall(__NR_bpf, BPF_OBJ_GET, &attr, sizeof(attr));
}
int bpf_prog_get_next_id(uint32_t start_id, uint32_t *next_id)
{
union bpf_attr attr;
int err;
memset(&attr, 0, sizeof(attr));
attr.start_id = start_id;
err = syscall(__NR_bpf, BPF_PROG_GET_NEXT_ID, &attr, sizeof(attr));
if (!err)
*next_id = attr.next_id;
return err;
}
int bpf_prog_get_fd_by_id(uint32_t id)
{
union bpf_attr attr;
memset(&attr, 0, sizeof(attr));
attr.prog_id = id;
return syscall(__NR_bpf, BPF_PROG_GET_FD_BY_ID, &attr, sizeof(attr));
}
int bpf_map_get_fd_by_id(uint32_t id)
{
union bpf_attr attr;
memset(&attr, 0, sizeof(attr));
attr.map_id = id;
return syscall(__NR_bpf, BPF_MAP_GET_FD_BY_ID, &attr, sizeof(attr));
}
......@@ -18,7 +18,7 @@
#ifndef LIBBPF_H
#define LIBBPF_H
#include "compat/linux/bpf.h"
#include "linux/bpf.h"
#include <stdint.h>
#include <sys/types.h>
......@@ -31,7 +31,7 @@ enum bpf_probe_attach_type {
BPF_PROBE_RETURN
};
int bpf_create_map(enum bpf_map_type map_type, const char *name,
int bcc_create_map(enum bpf_map_type map_type, const char *name,
int key_size, int value_size, int max_entries,
int map_flags);
int bpf_update_elem(int fd, void *key, void *value, unsigned long long flags);
......@@ -56,7 +56,7 @@ int bpf_get_next_key(int fd, void *key, void *next_key);
* printing, and continue to attempt increase that allocated buffer size if
* initial attemp was insufficient in size.
*/
int bpf_prog_load(enum bpf_prog_type prog_type, const char *name,
int bcc_prog_load(enum bpf_prog_type prog_type, const char *name,
const struct bpf_insn *insns, int insn_len,
const char *license, unsigned kern_version,
int log_level, char *log_buf, unsigned log_buf_size);
......
......@@ -18,7 +18,7 @@
#include <iostream>
#include "common.h"
#include "compat/linux/bpf.h"
#include "linux/bpf.h"
#include "table_storage.h"
#include "table_storage_impl.h"
......
......@@ -162,7 +162,7 @@ function Bpf:load_func(fn_name, prog_type)
assert(libbcc.bpf_function_start(self.module, fn_name) ~= nil,
"unknown program: "..fn_name)
local fd = libbcc.bpf_prog_load(prog_type,
local fd = libbcc.bcc_prog_load(prog_type,
fn_name,
libbcc.bpf_function_start(self.module, fn_name),
libbcc.bpf_function_size(self.module, fn_name),
......
......@@ -24,13 +24,13 @@ enum bpf_prog_type {
BPF_PROG_TYPE_SCHED_ACT,
};
int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size, int max_entries, int map_flags);
int bcc_create_map(enum bpf_map_type map_type, int key_size, int value_size, int max_entries, int map_flags);
int bpf_update_elem(int fd, void *key, void *value, unsigned long long flags);
int bpf_lookup_elem(int fd, void *key, void *value);
int bpf_delete_elem(int fd, void *key);
int bpf_get_next_key(int fd, void *key, void *next_key);
int bpf_prog_load(enum bpf_prog_type prog_type, const char *name,
int bcc_prog_load(enum bpf_prog_type prog_type, const char *name,
const struct bpf_insn *insns, int insn_len,
const char *license, unsigned kern_version,
int log_level, char *log_buf, unsigned log_buf_size);
......
......@@ -1475,7 +1475,7 @@ local tracepoint_mt = {
prog = compile(prog, {proto.type(t.type, {source='ptr_to_probe'})})
end
-- Load the BPF program
local prog_fd, err, log = S.bpf_prog_load(S.c.BPF_PROG.TRACEPOINT, prog.insn, prog.pc)
local prog_fd, err, log = S.bcc_prog_load(S.c.BPF_PROG.TRACEPOINT, prog.insn, prog.pc)
assert(prog_fd, tostring(err)..': '..tostring(log))
-- Open tracepoint and attach
t.reader:setbpf(prog_fd:getfd())
......@@ -1499,7 +1499,7 @@ local function trace_bpf(ptype, pname, pdef, retprobe, prog, pid, cpu, group_fd)
if type(prog) ~= 'table' then
prog = compile(prog, {proto.pt_regs})
end
local prog_fd, err, log = S.bpf_prog_load(S.c.BPF_PROG.KPROBE, prog.insn, prog.pc)
local prog_fd, err, log = S.bcc_prog_load(S.c.BPF_PROG.KPROBE, prog.insn, prog.pc)
assert(prog_fd, tostring(err)..': '..tostring(log))
-- Open tracepoint and attach
local tp, err = S.perf_probe(ptype, pname, pdef, retprobe)
......@@ -1580,7 +1580,7 @@ return setmetatable({
if type(prog) ~= 'table' then
prog = compile(prog, {proto.skb})
end
local prog_fd, err, log = S.bpf_prog_load(S.c.BPF_PROG.SOCKET_FILTER, prog.insn, prog.pc)
local prog_fd, err, log = S.bcc_prog_load(S.c.BPF_PROG.SOCKET_FILTER, prog.insn, prog.pc)
assert(prog_fd, tostring(err)..': '..tostring(log))
assert(sock:setsockopt('socket', 'attach_bpf', prog_fd:getfd()))
return prog_fd, err
......
......@@ -365,7 +365,7 @@ class BPF(object):
log_level = 2
elif (self.debug & DEBUG_BPF):
log_level = 1
fd = lib.bpf_prog_load(prog_type, func_name,
fd = lib.bcc_prog_load(prog_type, func_name,
lib.bpf_function_start(self.module, func_name),
lib.bpf_function_size(self.module, func_name),
lib.bpf_module_license(self.module),
......
......@@ -82,8 +82,8 @@ lib.bpf_open_raw_sock.restype = ct.c_int
lib.bpf_open_raw_sock.argtypes = [ct.c_char_p]
lib.bpf_attach_socket.restype = ct.c_int
lib.bpf_attach_socket.argtypes = [ct.c_int, ct.c_int]
lib.bpf_prog_load.restype = ct.c_int
lib.bpf_prog_load.argtypes = [ct.c_int, ct.c_char_p, ct.c_void_p,
lib.bcc_prog_load.restype = ct.c_int
lib.bcc_prog_load.argtypes = [ct.c_int, ct.c_char_p, ct.c_void_p,
ct.c_size_t, ct.c_char_p, ct.c_uint, ct.c_int, ct.c_char_p, ct.c_uint]
_RAW_CB_TYPE = ct.CFUNCTYPE(None, ct.py_object, ct.c_void_p, ct.c_int)
_LOST_CB_TYPE = ct.CFUNCTYPE(None, ct.py_object, ct.c_ulonglong)
......
......@@ -3,6 +3,7 @@
include_directories(${CMAKE_SOURCE_DIR}/src/cc)
include_directories(${CMAKE_SOURCE_DIR}/src/cc/api)
include_directories(${CMAKE_SOURCE_DIR}/src/cc/libbpf/include/uapi)
add_executable(test_static test_static.c)
target_link_libraries(test_static bcc-static)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment