diff --git a/rpmbuild/rpm-deps.sh b/rpmbuild/rpm-deps.sh new file mode 100755 index 000000000..41092bacd --- /dev/null +++ b/rpmbuild/rpm-deps.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +# This script simply iterates over all libs SPDK binaries link +# to and returns a list of .rpm packages SPDK may depend on. At +# the end, the list strictly relates to how the SPDK build was +# ./configure'ed. + +shopt -s nullglob + +rpmdir=$(readlink -f "$(dirname "$0")") +rootdir=$(readlink -f "$rpmdir/../") +rc=0 + +bins=("$rootdir/"build/{bin,examples}/*) +(($#)) && bins=("$@") + +((${#bins[@]} > 0)) || exit 0 + +source /etc/os-release +[[ $ID == fedora || $ID == centos || $ID == rhel ]] || exit 0 + +declare -A deps=() +for bin in "${bins[@]}"; do + if ! type -P "$bin"; then + printf '%s is missing\n' "$bin" >&2 + rc=1 + continue + fi + while read -r name _ lib _; do + [[ -n $lib ]] || continue + [[ -z ${deps["$lib"]} ]] || continue + if [[ ! -e $lib ]]; then + lib=$name pkg="missing" + rc=1 + elif ! pkg=$(rpm -qf "$lib"); then + pkg=${lib##*/} + fi + deps["$lib"]=$pkg + done < <(LD_TRACE_LOADED_OBJECTS=1 "$bin") +done + +if [[ -n $LIST_LIBS ]]; then + for lib in "${!deps[@]}"; do + echo "$lib:${deps["$lib"]}" + done +else + printf '%s\n' "${deps[@]}" +fi | sort -u + +((rc == 0)) diff --git a/rpmbuild/rpm.sh b/rpmbuild/rpm.sh new file mode 100755 index 000000000..76b04ed9c --- /dev/null +++ b/rpmbuild/rpm.sh @@ -0,0 +1,105 @@ +#!/usr/bin/env bash + +set -e + +specdir=$(readlink -f "$(dirname "$0")") +rootdir=$(readlink -f "$specdir/../") + +[[ -e /etc/os-release ]] +source /etc/os-release + +if [[ $ID != fedora && $ID != centos && $ID != rhel ]]; then + printf '%s not supported\n' "$ID" >&2 + exit 1 +fi + +fedora_python_sys_path_workaround() { + [[ -z $NO_WORKAROUND ]] || return 0 + + # Fedora builds its python version with a patch which attempts to remove all + # "/usr/local" paths from sys.path in case it's run under RPM environment, + # i.e., when RPM_BUILD_ROOT variable is detected. This particular variable + # is set by the rpmbuild when it executes its sh wrappers built out of the + # .spec file. + + # This is problematic in case meson and ninja were installed via rooted pip + # which had its working directory set to /usr/local. As a result, when the + # SPDK executes meson to build DPDK, from rpmbuild env, it fails as + # it's not able to find its mesonbuild module. + + # To workaround this little hiccup we fetch the entire sys.path list and + # then export it via PYTHONPATH so when rpmbuild kicks in, python will be + # able to find all the modules regardless if the RPM_BUILD_ROOT is set or + # not. + # FIXME: The alternative is to unset RPM_BUILD_ROOT directly in the spec? + # It does work but it feels wrong. + + PYTHONPATH="$(python3 -c "import sys; print('%s' % ':'.join(sys.path)[1:])")" + export PYTHONPATH +} + +get_version() { + local version + version=$(git -C "$rootdir" describe --tags --abbrev=0) + + echo "${version%%-*}" +} + +build_rpm() ( + local macros=() + + macros+=(-D "configure $configure") + macros+=(-D "make $make") + macros+=(-D "release $release") + macros+=(-D "version $version") + + # Prepare default dir structure + mkdir -p "$HOME"/rpmbuild/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS} + + if [[ $configure == *"with-shared"* || $configure == *"with-dpdk"* ]]; then + macros+=(-D "dpdk 1") + macros+=(-D "shared 1") + fi + + if [[ $configure == *"with-dpdk"* ]]; then + dpdk_build_path=${configure#*with-dpdk=} + dpdk_build_path=${dpdk_build_path%% *} + dpdk_path=${dpdk_build_path%/*} + macros+=(-D "dpdk_build_path $dpdk_build_path") + macros+=(-D "dpdk_path $dpdk_path") + fi + + if [[ $deps == no ]]; then + macros+=(-D "deps 0") + fi + + if [[ -n $requirements ]]; then + macros+=(-D "requirements 1") + macros+=(-D "requirements_list $requirements") + fi + + cd "$rootdir" + + fedora_python_sys_path_workaround + + # Despite building in-place, rpmbuild still looks under SOURCES as defined + # in Source:. Create a dummy file to fulfil its needs and to keep Source in + # the .spec. + : > "$rpmbuild_dir/SOURCES/spdk-$version.tar.gz" + + printf '* Starting rpmbuild...\n' + rpmbuild --clean --nodebuginfo "${macros[@]}" --build-in-place -ba "$spec" +) + +# .spec defaults +configure=${*:-"%{nil}"} +deps=${DEPS:-yes} +make="${MAKEFLAGS:--j $(nproc)}" +release=${RPM_RELEASE:-1} +requirements=${REQUIREMENTS:-} +version=${SPDK_VERSION:-$(get_version)} + +rpmbuild_dir=$HOME/rpmbuild +spec=$specdir/spdk.spec + +build_rpm diff --git a/rpmbuild/spdk.spec b/rpmbuild/spdk.spec new file mode 100644 index 000000000..a8f1639e8 --- /dev/null +++ b/rpmbuild/spdk.spec @@ -0,0 +1,153 @@ +Name: spdk +Version: %{version} +Release: %{release} +Summary: Storage Performance Development Kit + +License: BSD +URL: https://spdk.io +Source: spdk-%{version}.tar.gz + +%description + +The Storage Performance Development Kit (SPDK) provides a set of tools and libraries for +writing high performance, scalable, user-mode storage applications. It achieves high +performance by moving all of the necessary drivers into userspace and operating in a +polled mode instead of relying on interrupts, which avoids kernel context switches and +eliminates interrupt handling overhead. + +%define debug_package %{nil} + +%{!?deps:%define deps 1} +%{!?dpdk:%define dpdk 0} +%{!?dpdk_build_path:%define dpdk_build_path "dpdk/build"} +%{!?dpdk_path:%define dpdk_path "dpdk"} +%{!?requirements:%define requirements 0} +%{!?shared:%define shared 0} + +# This is a minimal set of requirements needed for SPDK apps to run when built with +# default configuration. These are also predetermined by rpmbuild. Extra requirements +# can be defined through a comma-separated list passed via $requirements when building +# the spec. +Requires: glibc +Requires: libaio +Requires: libgcc +Requires: libstdc++ +Requires: libuuid +Requires: ncurses-libs +Requires: numactl-libs +Requires: openssl-libs +Requires: zlib + +%if %{requirements} +Requires: %{requirements_list} +%endif + +%prep +make clean &>/dev/null || : +%setup + +%build +%if %{deps} +./scripts/pkgdep.sh --docs --pmem --rdma --uring +%endif + +# Rely mainly on CONFIG +./configure --disable-unit-tests --disable-tests %{configure} +make %{make} +make DESTDIR=%{buildroot} install + +# Include DPDK libs in case --with-shared is in use. +%if %{dpdk} +mkdir -p %{buildroot}/usr/local/lib/dpdk +cp -a %{dpdk_build_path}/lib/* %{buildroot}/usr/local/lib/dpdk/ +# Special case for SPDK_RUN_EXTERNAL_DPDK setup +[[ -e %{dpdk_path}/intel-ipsec-mb ]] && cp -a %{dpdk_path}/intel-ipsec-mb/*.so* %{buildroot}/usr/local/lib/dpdk/ +[[ -e %{dpdk_path}/isa-l/build/lib ]] && cp -a %{dpdk_path}/isa-l/build/lib/*.so* %{buildroot}/usr/local/lib/dpdk/ +%endif + +# Try to include all the binaries that were potentially built +[[ -e build/examples ]] && cp -a build/examples/* %{buildroot}/usr/local/bin/ +[[ -e build/bin ]] && cp -a build/bin/* %{buildroot}/usr/local/bin/ + +# And some useful setup scripts SPDK uses +mkdir -p %{buildroot}/usr/libexec/spdk +mkdir -p %{buildroot}/etc/bash_completion.d +mkdir -p %{buildroot}/etc/profile.d +mkdir -p %{buildroot}/etc/ld.so.conf.d + +cat <<-EOF > %{buildroot}/etc/ld.so.conf.d/spdk.conf +/usr/local/lib +/usr/local/lib/dpdk +EOF + +cat <<-'EOF' > %{buildroot}/etc/profile.d/spdk_path.sh +PATH=$PATH:/usr/libexec/spdk/scripts +PATH=$PATH:/usr/libexec/spdk/scripts/vagrant +PATH=$PATH:/usr/libexec/spdk/test/common/config +export PATH +EOF + +cp -a scripts %{buildroot}/usr/libexec/spdk/scripts +ln -s /usr/libexec/spdk/scripts/bash-completion/spdk %{buildroot}/etc/bash_completion.d/ + +# We need to take into the account the fact that most of the scripts depend on being +# run directly from the repo. To workaround it, create common root space under dir +# like /usr/libexec/spdk and link all potential relative paths the script may try +# to reference. + +# setup.sh uses pci_ids.h +ln -s /usr/local/include %{buildroot}/usr/libexec/spdk + +%files +/etc/profile.d/* +/etc/bash_completion.d/* +/usr/libexec/spdk/* +/usr/local/bin/* + + +%package devel +Summary: SPDK development libraries and headers + +%description devel +SPDK development libraries and headers + +%files devel +/usr/local/include/* +%if %{shared} +/usr/local/lib/lib*.so +%endif + +%package libs +Summary: SPDK libraries + +%description libs +SPDK libraries + +%files libs +/etc/ld.so.conf.d/* +/usr/local/lib/lib*.a +/usr/local/lib/pkgconfig/*.pc +%if %{shared} +/usr/local/lib/lib*.so.* +%endif + +%post libs +ldconfig + +%if %{dpdk} +%package dpdk-libs +Summary: DPDK libraries + +%description dpdk-libs +DPDK libraries + +%files dpdk-libs +/usr/local/lib/dpdk + +%post dpdk-libs +ldconfig +%endif + +%changelog +* Tue Feb 16 2021 Michal Berger +- Initial RPM .spec for the SPDK