Files
solana/sdk/bpf/c/bpf.mk
mergify[bot] efc3c0d65f Add a make target to run the readelf utility on a compiled program (#17131)
The readelf utility (already shipped with the solana tools) shows meta-information about ELF files, such as symbol tables. It is useful for investigating "unresolved symbol" errors that crop up at runtime.

This commit also fixes the objdump flags (two dashes are required and there is no "color" option) as well as a few typos.

(cherry picked from commit ff95e2aaa6)

Co-authored-by: Christian Machacek <39452430+machacekch@users.noreply.github.com>
2021-05-09 02:46:49 +00:00

257 lines
7.0 KiB
Makefile

LOCAL_PATH := $(dir $(lastword $(MAKEFILE_LIST)))
INSTALL_SH := $(abspath $(LOCAL_PATH)/../scripts/install.sh)
all:
.PHONY: help all clean
ifneq ($(V),1)
_@ :=@
endif
INC_DIRS ?=
SRC_DIR ?= ./src
TEST_PREFIX ?= test_
OUT_DIR ?= ./out
OS := $(shell uname)
LLVM_DIR = $(LOCAL_PATH)../dependencies/bpf-tools/llvm
LLVM_SYSTEM_INC_DIRS := $(LLVM_DIR)/lib/clang/11.0.1/include
ifdef LLVM_DIR
CC := $(LLVM_DIR)/bin/clang
CXX := $(LLVM_DIR)/bin/clang++
LLD := $(LLVM_DIR)/bin/ld.lld
OBJ_DUMP := $(LLVM_DIR)/bin/llvm-objdump
READ_ELF := $(LLVM_DIR)/bin/llvm-readelf
endif
SYSTEM_INC_DIRS := \
$(LOCAL_PATH)inc \
$(LLVM_SYSTEM_INC_DIRS) \
C_FLAGS := \
-Werror \
-O2 \
-fno-builtin \
-std=c17 \
$(addprefix -isystem,$(SYSTEM_INC_DIRS)) \
$(addprefix -I,$(INC_DIRS))
CXX_FLAGS := \
$(C_FLAGS) \
-std=c++17 \
BPF_C_FLAGS := \
$(C_FLAGS) \
-target bpf \
-fPIC \
BPF_CXX_FLAGS := \
$(CXX_FLAGS) \
-target bpf \
-fPIC \
-fomit-frame-pointer \
-fno-exceptions \
-fno-asynchronous-unwind-tables \
-fno-unwind-tables \
BPF_LLD_FLAGS := \
-z notext \
-shared \
--Bdynamic \
$(LOCAL_PATH)bpf.ld \
--entry entrypoint \
OBJ_DUMP_FLAGS := \
--source \
--disassemble \
READ_ELF_FLAGS := \
--all \
TESTFRAMEWORK_RPATH := $(abspath $(LOCAL_PATH)../dependencies/criterion/lib)
TESTFRAMEWORK_FLAGS := \
-DSOL_TEST \
-isystem $(LOCAL_PATH)../dependencies/criterion/include \
-L $(LOCAL_PATH)../dependencies/criterion/lib \
-rpath $(TESTFRAMEWORK_RPATH) \
-lcriterion \
MACOS_ADJUST_TEST_DYLIB := \
$(if $(filter $(OS),Darwin),\
$(_@)install_name_tool -change libcriterion.3.dylib $(TESTFRAMEWORK_RPATH)/libcriterion.3.dylib, \
: \
)
TEST_C_FLAGS := \
$(C_FLAGS) \
$(TESTFRAMEWORK_FLAGS) \
TEST_CXX_FLAGS := \
$(CXX_FLAGS) \
$(TESTFRAMEWORK_FLAGS) \
help:
@echo ''
@echo 'BPF Program makefile'
@echo ''
@echo 'This makefile will build BPF Programs from C or C++ source files into ELFs'
@echo ''
@echo 'Assumptions:'
@echo ' - Programs are located in the source directory: $(SRC_DIR)/<program name>'
@echo ' - Programs are named by their directory name (eg. directory name:src/foo/ -> program name:foo)'
@echo ' - Tests are located in their corresponding program directory and must being with "test_"'
@echo ' - Output files will be placed in the directory: $(OUT_DIR)'
@echo ''
@echo 'User settings'
@echo ' - The following setting are overridable on the command line, default values shown:'
@echo ' - Show commands while building: V=1'
@echo ' V=$(V)'
@echo ' - List of include directories:'
@echo ' INC_DIRS=$(INC_DIRS)'
@echo ' - List of system include directories:'
@echo ' SYSTEM_INC_DIRS=$(SYSTEM_INC_DIRS)'
@echo ' - Location of source directories:'
@echo ' SRC_DIR=$(SRC_DIR)'
@echo ' - Location to place output files:'
@echo ' OUT_DIR=$(OUT_DIR)'
@echo ' - Location of LLVM:'
@echo ' LLVM_DIR=$(LLVM_DIR)'
@echo ''
@echo 'Usage:'
@echo ' - make help - This help message'
@echo ' - make all - Build all the programs and tests, run the tests'
@echo ' - make programs - Build all the programs'
@echo ' - make tests - Build and run all tests'
@echo ' - make dump_<program name> - Dump the contents of the program to stdout'
@echo ' - make readelf_<program name> - Display information about the ELF binary'
@echo ' - make <program name> - Build a single program by name'
@echo ' - make <test name> - Build and run a single test by name'
@echo ''
@echo 'Available programs:'
$(foreach name, $(PROGRAM_NAMES), @echo ' - $(name)'$(\n))
@echo ''
@echo 'Available tests:'
$(foreach name, $(TEST_NAMES), @echo ' - $(name)'$(\n))
@echo ''
@echo 'Example:'
@echo ' - Assuming a program named foo (src/foo/foo.c)'
@echo ' - make foo'
@echo ' - make dump_foo'
@echo ''
define C_RULE
$1: $2
@echo "[cc] $1 ($2)"
$(_@)mkdir -p $(dir $1)
$(_@)$(CC) $(BPF_C_FLAGS) -o $1 -c $2 -MD -MF $(1:.o=.d)
endef
define CC_RULE
$1: $2
@echo "[cxx] $1 ($2)"
$(_@)mkdir -p $(dir $1)
$(_@)$(CXX) $(BPF_CXX_FLAGS) -o $1 -c $2 -MD -MF $(1:.o=.d)
endef
define O_RULE
$1: $2
@echo "[llc] $1 ($2)"
$(_@)mkdir -p $(dir $1)
$(_@)$(LLC) $(BPF_LLC_FLAGS) -o $1 $2
endef
define SO_RULE
$1: $2
@echo "[lld] $1 ($2)"
$(_@)mkdir -p $(dir $1)
$(_@)$(LLD) $(BPF_LLD_FLAGS) -o $1 $2
ifeq (,$(wildcard $(subst .so,-keypair.json,$1)))
$(_@)solana-keygen new --no-passphrase --silent -o $(subst .so,-keypair.json,$1)
endif
@echo To deploy this program:
@echo $$$$ solana program deploy $(realpath $1)
endef
define TEST_C_RULE
$1: $2
@echo "[test cc] $1 ($2)"
$(_@)mkdir -p $(dir $1)
$(_@)$(CC) $(TEST_C_FLAGS) -o $1 $2 -MD -MF $(1:.o=.d)
$(_@)$(MACOS_ADJUST_TEST_DYLIB) $1
endef
define TEST_CC_RULE
$1: $2
@echo "[test cxx] $1 ($2)"
$(_@)mkdir -p $(dir $1)
$(_@)$(CXX) $(TEST_CXX_FLAGS) -o $1 $2 -MD -MF $(1:.o=.d)
$(_@)$(MACOS_ADJUST_TEST_DYLIB) $1
endef
define TEST_EXEC_RULE
$1: $2
$2$(\n)
endef
.PHONY: $(INSTALL_SH)
$(INSTALL_SH):
$(_@)$(INSTALL_SH)
PROGRAM_NAMES := $(notdir $(basename $(wildcard $(SRC_DIR)/*)))
define \n
endef
all: programs tests
$(foreach PROGRAM, $(PROGRAM_NAMES), \
$(eval -include $(wildcard $(OUT_DIR)/$(PROGRAM)/*.d)) \
\
$(eval $(PROGRAM): %: $(addprefix $(OUT_DIR)/, %.so)) \
$(eval $(PROGRAM)_SRCS := \
$(addprefix $(SRC_DIR)/$(PROGRAM)/, \
$(filter-out $(TEST_PREFIX)%,$(notdir $(wildcard $(SRC_DIR)/$(PROGRAM)/*.c $(SRC_DIR)/$(PROGRAM)/*.cc))))) \
$(eval $(PROGRAM)_OBJS := $(subst $(SRC_DIR), $(OUT_DIR), \
$(patsubst %.c,%.o, \
$(patsubst %.cc,%.o,$($(PROGRAM)_SRCS))))) \
$(eval $($(PROGRAM)_SRCS): $(INSTALL_SH)) \
$(eval $(call SO_RULE,$(OUT_DIR)/$(PROGRAM).so,$($(PROGRAM)_OBJS))) \
$(foreach _,$(filter %.c,$($(PROGRAM)_SRCS)), \
$(eval $(call C_RULE,$(subst $(SRC_DIR),$(OUT_DIR),$(_:%.c=%.o)),$_))) \
$(foreach _,$(filter %.cc,$($(PROGRAM)_SRCS)), \
$(eval $(call CC_RULE,$(subst $(SRC_DIR),$(OUT_DIR),$(_:%.cc=%.o)),$_))) \
\
$(eval TESTS := $(notdir $(basename $(wildcard $(SRC_DIR)/$(PROGRAM)/$(TEST_PREFIX)*.c)))) \
$(eval $(TESTS) : %: $(addprefix $(OUT_DIR)/$(PROGRAM)/, %)) \
$(eval TEST_NAMES := $(TEST_NAMES) $(TESTS)) \
$(foreach TEST, $(TESTS), \
$(eval $(TEST)_SRCS := \
$(addprefix $(SRC_DIR)/$(PROGRAM)/, \
$(notdir $(wildcard $(SRC_DIR)/$(PROGRAM)/$(TEST).c $(SRC_DIR)/$(PROGRAM)/$(TEST).cc)))) \
$(eval $($(TEST)_SRCS): $(INSTALL_SH)) \
$(foreach _,$(filter %.c,$($(TEST)_SRCS)), \
$(eval $(call TEST_C_RULE,$(subst $(SRC_DIR),$(OUT_DIR),$(_:%.c=%)),$_))) \
$(foreach _,$(filter %.cc, $($(TEST)_SRCS)), \
$(eval $(call TEST_CC_RULE,$(subst $(SRC_DIR),$(OUT_DIR),$(_:%.cc=%)),$_))) \
$(eval $(call TEST_EXEC_RULE,$(TEST),$(addprefix $(OUT_DIR)/$(PROGRAM)/, $(TEST)))) \
) \
)
.PHONY: $(PROGRAM_NAMES)
programs: $(PROGRAM_NAMES)
.PHONY: $(TEST_NAMES)
tests: $(TEST_NAMES)
dump_%: %
$(_@)$(OBJ_DUMP) $(OBJ_DUMP_FLAGS) $(addprefix $(OUT_DIR)/, $(addsuffix .so, $<))
readelf_%: %
$(_@)$(READ_ELF) $(READ_ELF_FLAGS) $(addprefix $(OUT_DIR)/, $(addsuffix .so, $<))
clean:
rm -rf $(OUT_DIR)