build: generate pkg-config files for SPDK

Users can now generate the necessary linker args for their
own applications using something like:

PKG_CONFIG_PATH=build/lib/pkgconfig pkg-config --libs spdk_nvme

Dependencies between libraries are included in the generated
.pc files, so the user only needs to pass the top-level subsystems
or individual SPDK libraries they are using in their application.

Modules will automatically be added to the output if the associated
library is specified.  For example, specifying "spdk_bdev" will include
the libraries not only for spdk_bdev, but also all of the bdev modules.

Users still need to supply the -Wl,--no-as-needed or -Wl,--whole-archive
flags. They cannot be added to the .pc files without increasing the length
of the argument string by a factor of 15x to 20x.

Modify the test/external_code/hello_world Makefile to use pkg-config to
ensure this gets tested at some level in our autotest environment.

Signed-off-by: Jim Harris <james.r.harris@intel.com>
Change-Id: Ie48a75f11969d5d775d514cf10bcb82d197eabfd
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/4371
Community-CI: Broadcom CI
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Tomasz Zawadzki <tomasz.zawadzki@intel.com>
Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
This commit is contained in:
Jim Harris 2020-09-24 00:06:02 +00:00 committed by Tomasz Zawadzki
parent 3ff9c13614
commit 79f9a7f572
13 changed files with 161 additions and 21 deletions

View File

@ -83,6 +83,11 @@ parameter is added into `spdk_app_opts_init` function.
Change the return type of function `spdk_nbd_stop` from void to int. And update the
`spdk_nbd_fini` with two parameters to make its behavior from sync to async.
### build
SPDK now generates pkg-config files to simplify the process of determining which
libraries must be linked into an SPDK application.
### nvmf
nvmf_fc_lld_fini() now takes callback and hence updating FC Broadcom LLD driver

View File

@ -91,6 +91,7 @@ clean: $(DIRS-y)
$(Q)rm -rf build/fio
$(Q)rm -rf build/examples
$(Q)rm -rf build/include
$(Q)rm -rf build/lib/pkgconfig
$(Q)find build/lib ! -name .gitignore -type f -delete
install: all
@ -119,7 +120,7 @@ mk/cc.mk:
false
build_dir: mk/cc.mk
$(Q)mkdir -p build/lib
$(Q)mkdir -p build/lib/pkgconfig
$(Q)mkdir -p build/bin
$(Q)mkdir -p build/fio
$(Q)mkdir -p build/examples

View File

@ -833,6 +833,7 @@ INPUT += \
nvmf_tracing.md \
overview.md \
peer_2_peer.md \
pkgconfig.md \
porting.md \
shfmt.md \
spdkcli.md \

55
doc/pkgconfig.md Normal file
View File

@ -0,0 +1,55 @@
# Linking SPDK applications with pkg-config {#pkgconfig}
The SPDK build system generates pkg-config files to facilitate linking
applications with the correct set of SPDK and DPDK libraries. Using pkg-config
in your build system will ensure you do not need to make modifications
when SPDK adds or modifies library dependencies.
If your application is using the SPDK nvme library, you would use the following
to get the list of required SPDK libraries:
~~~
PKG_CONFIG_PATH=/path/to/spdk/build/lib/pkgconfig pkg-config --libs spdk_nvme
~~~
To get the list of required SPDK and DPDK libraries to use the DPDK-based
environment layer:
~~~
PKG_CONFIG_PATH=/path/to/spdk/build/lib/pkgconfig pkg-config --libs spdk_env_dpdk
~~~
When linking with static libraries, the dependent system libraries must also be
specified. To get the list of required system libraries:
~~~
PKG_CONFIG_PATH=/path/to/spdk/build/lib/pkgconfig pkg-config --libs spdk_syslibs
~~~
Note that SPDK libraries use constructor functions liberally, so you must surround
the library list with extra linker options to ensure these functions are not dropped
from the resulting application binary. Here is an example Makefile snippet that
shows how to use pkg-config to link an application that uses the SPDK nvme shared
library:
~~~
PKG_CONFIG_PATH = $(SPDK_DIR)/build/lib/pkgconfig
SPDK_LIB := $(shell PKG_CONFIG_PATH="$(PKG_CONFIG_PATH)" pkg-config --libs spdk_nvme
DPDK_LIB := $(shell PKG_CONFIG_PATH="$(PKG_CONFIG_PATH)" pkg-config --libs spdk_env_dpdk
app:
$(CC) -o app app.o -pthread -Wl,--no-as-needed $(SPDK_LIB) $(DPDK_LIB) -Wl,--as-needed
~~~
If using the SPDK nvme static library:
~~~
PKG_CONFIG_PATH = $(SPDK_DIR)/build/lib/pkgconfig
SPDK_LIB := $(shell PKG_CONFIG_PATH="$(PKG_CONFIG_PATH)" pkg-config --libs spdk_nvme
DPDK_LIB := $(shell PKG_CONFIG_PATH="$(PKG_CONFIG_PATH)" pkg-config --libs spdk_env_dpdk
SYS_LIB := $(shell PKG_CONFIG_PATH="$(PKG_CONFIG_PATH)" pkg-config --libs --static spdk_syslibs
app:
$(CC) -o app app.o -pthread -Wl,--whole-archive $(SPDK_LIB) $(DPDK_LIB) -Wl,--no-whole-archive \
$(SYS_LIB)
~~~

View File

@ -2,6 +2,7 @@
- @subpage system_configuration
- @subpage libraries
- @subpage pkgconfig
- @subpage app_overview
- @subpage iscsi
- @subpage nvmf

View File

@ -45,3 +45,12 @@ LIBNAME = env_dpdk
SPDK_MAP_FILE = $(abspath $(CURDIR)/spdk_env_dpdk.map)
include $(SPDK_ROOT_DIR)/mk/spdk.lib.mk
LIBDPDK_PKGCONFIG = $(call pkgconfig_filename,spdk_dpdklibs)
$(LIBDPDK_PKGCONFIG): $(PKGCONFIG)
$(Q)$(SPDK_ROOT_DIR)/scripts/pc_libs.sh \
"-L$(DPDK_ABS_DIR)/lib $(DPDK_LIB_LIST:%=-l%)" "" DPDK spdk_dpdklibs > $@
$(Q)echo Requires: spdk_dpdklibs >> $(PKGCONFIG)
all : $(LIBDPDK_PKGCONFIG)

View File

@ -413,3 +413,7 @@ endef
define add_whole_archive
-Wl,--whole-archive $(1) -Wl,--no-whole-archive
endef
define pkgconfig_filename
$(SPDK_ROOT_DIR)/build/lib/pkgconfig/$(1).pc
endef

View File

@ -33,7 +33,7 @@
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
include $(SPDK_ROOT_DIR)/mk/spdk.lib_deps.mk
include $(SPDK_ROOT_DIR)/mk/spdk.modules.mk
ifeq ($(SPDK_MAP_FILE),)
$(error SPDK_MAP_FILE is not set for lib $(LIBNAME))
@ -53,10 +53,12 @@ LIB := $(call spdk_lib_list_to_static_libs,$(LIBNAME))
SHARED_LINKED_LIB := $(LIB:.a=.so)
SHARED_REALNAME_LIB := $(SHARED_LINKED_LIB:.so=.so.$(SO_SUFFIX))
PKGCONFIG = $(call pkgconfig_filename,spdk_$(LIBNAME))
ifeq ($(CONFIG_SHARED),y)
DEP := $(SHARED_LINKED_LIB)
DEP := $(SHARED_LINKED_LIB) $(PKGCONFIG)
else
DEP := $(LIB)
DEP := $(LIB) $(PKGCONFIG)
endif
ifeq ($(OS),FreeBSD)
@ -80,6 +82,13 @@ ifeq ($(SPDK_NO_LIB_DEPS),)
SPDK_DEP_LIBS = $(call spdk_lib_list_to_shared_libs,$(DEPDIRS-$(LIBNAME)))
endif
MODULES-bdev = spdk_bdev_modules
MODULES-sock = spdk_sock_modules
MODULES-accel = spdk_accel_modules
ifeq ($(SPDK_ROOT_DIR)/lib/env_dpdk,$(CONFIG_ENV))
MODULES-event = spdk_env_dpdk_rpc
endif
.PHONY: all clean $(DIRS-y)
all: $(BUILD_DEP)
@ -95,6 +104,11 @@ $(SHARED_REALNAME_LIB): $(LIB)
$(Q)echo " SO $(notdir $@)"; \
$(call spdk_build_realname_shared_lib,$^,$(SPDK_MAP_FILE),$(LOCAL_SYS_LIBS),$(SPDK_DEP_LIBS))
$(PKGCONFIG): $(LIB)
$(Q)$(SPDK_ROOT_DIR)/scripts/pc.sh $(SPDK_ROOT_DIR) $(LIBNAME) $(SO_SUFFIX) \
"$(DEPDIRS-$(LIBNAME):%=spdk_%) $(MODULES-$(LIBNAME))" \
"" > $@
$(LIB): $(OBJS)
$(LIB_C)

View File

@ -33,6 +33,7 @@
SPDK_ROOT_DIR := $(abspath $(CURDIR)/..)
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
include $(SPDK_ROOT_DIR)/mk/spdk.modules.mk
DIRS-y = bdev blob blobfs accel event sock
ifeq ($(SPDK_ROOT_DIR)/lib/env_dpdk,$(CONFIG_ENV))
@ -49,7 +50,33 @@ DEPDIRS-event := bdev blob
.PHONY: all clean $(DIRS-y)
all: $(DIRS-y)
BDEV_MODULES_PKGCONFIG = $(call pkgconfig_filename,spdk_bdev_modules)
ACCEL_MODULES_PKGCONFIG = $(call pkgconfig_filename,spdk_accel_modules)
SOCK_MODULES_PKGCONFIG = $(call pkgconfig_filename,spdk_sock_modules)
SYSLIBS_PKGCONFIG = $(call pkgconfig_filename,spdk_syslibs)
PRIVATE_SYSLIBS = $(SYS_LIBS)
ifeq ($(SPDK_ROOT_DIR)/lib/env_dpdk,$(CONFIG_ENV))
PRIVATE_SYSLIBS += $(DPDK_PRIVATE_LINKER_ARGS)
endif
MODULES_PKGCONFIG = $(BDEV_MODULES_PKGCONFIG) $(ACCEL_MODULES_PKGCONFIG)
MODULES_PKGCONFIG += $(SOCK_MODULES_PKGCONFIG) $(SYSLIBS_PKGCONFIG)
$(BDEV_MODULES_PKGCONFIG):
$(Q)$(SPDK_ROOT_DIR)/scripts/pc_modules.sh bdev "$(BLOCKDEV_MODULES_LIST:%=spdk_%)" > $@
$(ACCEL_MODULES_PKGCONFIG):
$(Q)$(SPDK_ROOT_DIR)/scripts/pc_modules.sh accel "$(ACCEL_MODULES_LIST:%=spdk_%)" > $@
$(SOCK_MODULES_PKGCONFIG):
$(Q)$(SPDK_ROOT_DIR)/scripts/pc_modules.sh sock "$(SOCK_MODULES_LIST:%=spdk_%)" > $@
$(SYSLIBS_PKGCONFIG):
$(Q)$(SPDK_ROOT_DIR)/scripts/pc_libs.sh "" "$(PRIVATE_SYSLIBS)" System spdk_syslibs > $@
all: $(DIRS-y) $(MODULES_PKGCONFIG)
clean: $(DIRS-y)
include $(SPDK_ROOT_DIR)/mk/spdk.subdirs.mk

10
scripts/pc.sh Executable file
View File

@ -0,0 +1,10 @@
#!/usr/bin/env bash
cat << EOF
Description: SPDK $2 library
Name: spdk_$2
Version: $3
Libs: -L$1/build/lib -lspdk_$2
Requires: $4
Libs.private: $5
Cflags: -I$1/build/include
EOF

8
scripts/pc_libs.sh Executable file
View File

@ -0,0 +1,8 @@
#!/usr/bin/env bash
cat << EOF
Description: $3 libraries used by SPDK
Name: $4
Version: 1.0
Libs: $1
Libs.private: $2
EOF

7
scripts/pc_modules.sh Executable file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env bash
cat << EOF
Description: SPDK $1 modules
Name: spdk_$1_modules
Version: 1.0
Requires: $2
EOF

View File

@ -31,9 +31,11 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
DPDK_LIB = -lspdk_env_dpdk -lrte_eal -lrte_mempool -lrte_ring -lrte_mbuf -lrte_mempool_ring -lrte_pci
DPDK_LIB += -lrte_bus_pci -lrte_kvargs -lrte_vhost -lrte_net -lrte_hash -lrte_telemetry
DPDK_LIB += -lrte_cryptodev -lrte_power -lrte_rcu
PKG_CONFIG_PATH = $(SPDK_LIB_DIR)/pkgconfig
DPDK_LIB := $(shell PKG_CONFIG_PATH="$(PKG_CONFIG_PATH)" pkg-config --libs spdk_env_dpdk)
SPDK_BDEV_LIB := $(shell PKG_CONFIG_PATH="$(PKG_CONFIG_PATH)" pkg-config --libs spdk_event_bdev)
SYS_LIB := $(shell PKG_CONFIG_PATH="$(PKG_CONFIG_PATH)" pkg-config --libs --static spdk_syslibs)
# Shows how to compile both an external bdev and an external application against the SPDK combined shared object and dpdk shared objects.
bdev_shared_combo:
@ -42,9 +44,9 @@ bdev_shared_combo:
# Shows how to compile both an external bdev and an external application against the SPDK individual shared objects and dpdk shared objects.
bdev_shared_iso:
$(CC) $(COMMON_CFLAGS) -L../passthru -Wl,-rpath=$(SPDK_LIB_DIR),--no-as-needed -o hello_bdev ./hello_bdev.c \
-lpassthru_external -lspdk_event_bdev -lspdk_event_accel -lspdk_event_vmd -lspdk_bdev -lspdk_bdev_malloc -lspdk_log -lspdk_thread -lspdk_util -lspdk_event \
$(DPDK_LIB) -Wl,--no-whole-archive -lnuma
$(CC) $(COMMON_CFLAGS) -L../passthru -Wl,--no-as-needed -o hello_bdev ./hello_bdev.c \
-lpassthru_external $(SPDK_BDEV_LIB) \
$(DPDK_LIB)
# Shows how to compile an external application against the SPDK combined shared object and dpdk shared objects.
alone_shared_combo:
@ -52,19 +54,15 @@ alone_shared_combo:
# Shows how to compile an external application against the SPDK individual shared objects and dpdk shared objects.
alone_shared_iso:
$(CC) $(COMMON_CFLAGS) -Wl,-rpath=$(SPDK_LIB_DIR),--no-as-needed -o hello_bdev ./hello_bdev.c -lspdk_event_bdev \
-lspdk_event_accel -lspdk_event_vmd -lspdk_bdev -lspdk_bdev_malloc -lspdk_log -lspdk_thread -lspdk_util -lspdk_event $(DPDK_LIB)
$(CC) $(COMMON_CFLAGS) -Wl,-rpath=$(SPDK_LIB_DIR),--no-as-needed -o hello_bdev ./hello_bdev.c \
$(SPDK_BDEV_LIB) $(DPDK_LIB)
# Shows how to compile an external application against the SPDK archives.
alone_static:
$(CC) $(COMMON_CFLAGS) -o hello_bdev ./hello_bdev.c -pthread -Wl,--whole-archive,-Bstatic -lspdk_bdev_malloc -lspdk_event_bdev -lspdk_event_accel -lspdk_event_vmd \
-lspdk_event_sock -lspdk_bdev -lspdk_accel -lspdk_event -lspdk_thread -lspdk_util -lspdk_conf -lspdk_trace -lspdk_log -lspdk_json \
-lspdk_jsonrpc -lspdk_rpc -lspdk_sock -lspdk_notify -lspdk_vmd \
$(DPDK_LIB) -Wl,--no-whole-archive,-Bdynamic -lnuma -luuid -ldl -lrt
$(CC) $(COMMON_CFLAGS) -o hello_bdev ./hello_bdev.c -pthread -Wl,--whole-archive,-Bstatic $(SPDK_BDEV_LIB) \
$(DPDK_LIB) -Wl,--no-whole-archive,-Bdynamic $(SYS_LIB)
# Shows how to compile and external bdev and application sgainst the SPDK archives.
bdev_static:
$(CC) $(COMMON_CFLAGS) -L../passthru -o hello_bdev ./hello_bdev.c -pthread -Wl,--whole-archive,-Bstatic -lpassthru_external -lspdk_bdev_malloc -lspdk_event_bdev \
-lspdk_event_accel -lspdk_event_vmd -lspdk_event_sock -lspdk_bdev -lspdk_accel -lspdk_event -lspdk_thread -lspdk_util -lspdk_conf -lspdk_trace \
-lspdk_log -lspdk_json -lspdk_jsonrpc -lspdk_rpc -lspdk_sock -lspdk_notify -lspdk_vmd $(DPDK_LIB) \
-Wl,--no-whole-archive,-Bdynamic -lnuma -luuid -ldl -lrt
$(CC) $(COMMON_CFLAGS) -L../passthru -o hello_bdev ./hello_bdev.c -pthread -Wl,--whole-archive,-Bstatic -lpassthru_external $(SPDK_BDEV_LIB) $(DPDK_LIB) \
-Wl,--no-whole-archive,-Bdynamic $(SYS_LIB)