xref: /spdk/rpmbuild/rpm.sh (revision 52e39fb7f10205d9e2e0e36ba31f353615ff3be9)
1#!/usr/bin/env bash
2#  SPDX-License-Identifier: BSD-3-Clause
3#  Copyright (C) 2021 Intel Corporation
4#  All rights reserved.
5#
6
7set -e
8
9specdir=$(readlink -f "$(dirname "$0")")
10rootdir=$(readlink -f "$specdir/../")
11
12[[ -e /etc/os-release ]]
13source /etc/os-release
14
15id_ok=no
16
17for id in $ID $ID_LIKE; do
18	[[ "$id" =~ ^(fedora|centos|rhel) ]] && id_ok=yes
19done
20
21if [[ "$id_ok" != "yes" ]]; then
22	printf '%s not supported\n' "$ID" >&2
23	exit 1
24fi
25
26get_config() {
27	# Intercept part of the ./configure's cmdline we are interested in
28	configure_opts=($(getopt -l "$1::" -o "" -- $configure 2> /dev/null)) || true
29	# If "--" is the first argument then either the cmdline is empty or doesn't
30	# match on what we are looking for. In either case simply return as there
31	# is nothing to check.
32	[[ ${configure_opts[0]} == "--" ]] && return 1
33
34	if [[ $2 == has-arg ]]; then
35		[[ -n ${configure_opts[1]} && ${configure_opts[1]} != "''" ]]
36	elif [[ $2 == print ]]; then
37		echo "${configure_opts[1]//\'/}"
38	fi
39}
40
41fedora_python_sys_path_workaround() {
42	[[ -z $NO_WORKAROUND ]] || return 0
43
44	# Fedora builds its python version with a patch which attempts to remove all
45	# "/usr/local" paths from sys.path in case it's run under RPM environment,
46	# i.e., when RPM_BUILD_ROOT variable is detected. This particular variable
47	# is set by the rpmbuild when it executes its sh wrappers built out of the
48	# .spec file.
49
50	# This is problematic in case meson and ninja were installed via rooted pip
51	# which had its working directory set to /usr/local. As a result, when the
52	# SPDK executes meson to build DPDK, from rpmbuild env, it fails as
53	# it's not able to find its mesonbuild module.
54
55	# To workaround this little hiccup we fetch the entire sys.path list and
56	# then export it via PYTHONPATH so when rpmbuild kicks in, python will be
57	# able to find all the modules regardless if the RPM_BUILD_ROOT is set or
58	# not.
59	# FIXME: The alternative is to unset RPM_BUILD_ROOT directly in the spec?
60	# It does work but it feels wrong.
61
62	PYTHONPATH="$(python3 -c "import sys; print('%s' % ':'.join(sys.path)[1:])")"
63	export PYTHONPATH
64}
65
66get_version() {
67	local version
68	version=$(git -C "$rootdir" describe --tags --abbrev=0)
69
70	echo "${version%%-*}"
71}
72
73build_macros() {
74	local -g macros=()
75	local dir _dir dpdk_req
76
77	macros+=(-D "configure ${configure:-"%{nil}"}")
78	macros+=(-D "make $make")
79	macros+=(-D "release $release")
80	macros+=(-D "version $version")
81
82	# Adjust dir macros to update the final location of the RPMS
83	for dir in build buildroot rpm source spec srcrpm; do
84		_dir=$(rpm --eval "%{_${dir}dir}")
85		if [[ -z $USE_DEFAULT_DIRS ]]; then
86			macros+=(-D "_${dir}dir $rpmbuild_dir/$dir")
87			_dir=$rpmbuild_dir/$dir
88		fi
89		local -g "_${dir}dir=$_dir"
90	done
91
92	if get_config with-shared; then
93		macros+=(-D "shared 1")
94	fi
95
96	if get_config with-dpdk; then
97		# spdk is requested to build against installed dpdk (i.e. provided by the dist).
98		# Don't build dpdk rpm rather define proper requirements for the spdk.
99		dpdk_req="dpdk-devel >= 22.11"
100		macros+=(-D "dpdk 0")
101		requirements=${requirements:+$requirements, }"$dpdk_req"
102		build_requirements=${build_requirements:+$build_requirements, }"$dpdk_req"
103	else
104		macros+=(-D "dpdk 1")
105	fi
106
107	if get_config with-fio; then
108		macros+=(-D "fio 1")
109	fi
110
111	if get_config with-rbd; then
112		macros+=(-D "rbd 1")
113		requirements=${requirements:+$requirements, }"librados2, librbd1"
114		build_requirements=${build_requirements:+$build_requirements, }"librados-devel, librbd-devel"
115	fi
116
117	if get_config libdir has-arg; then
118		macros+=(-D "libdir $(get_config libdir print)")
119	fi
120
121	if get_config with-vfio-user; then
122		macros+=(-D "vfio_user 1")
123	fi
124
125	if [[ $deps == no ]]; then
126		macros+=(-D "deps 0")
127	fi
128
129	if [[ -n $requirements ]]; then
130		macros+=(-D "requirements 1")
131		macros+=(-D "requirements_list $requirements")
132	fi
133
134	if [[ -n $build_requirements ]]; then
135		macros+=(-D "build_requirements 1")
136		macros+=(-D "build_requirements_list $build_requirements")
137	fi
138
139	build_macros_flags
140}
141
142build_macros_flags() {
143	local flags flag
144
145	flags=(CFLAGS CXXFLAGS LDFLAGS)
146
147	for flag in "${flags[@]}"; do
148		# If we are running in the environment where the flag is set, don't touch it -
149		# rpmbuild will use it as is during the build. If it's not set, make sure the
150		# rpmbuild won't set its defaults which may affect the build in an unpredictable
151		# manner.
152		[[ -n ${!flag} ]] && continue
153		macros+=(-D "build_${flag,,} %{nil}")
154	done
155}
156
157gen_spec() {
158	rpmspec "${macros[@]}" -P "$spec"
159}
160
161build_rpm() (
162	fedora_python_sys_path_workaround
163
164	mkdir -p \
165		"$_builddir" \
166		"$_buildrootdir" \
167		"$_rpmdir" \
168		"$_sourcedir" \
169		"$_specdir" \
170		"$_srcrpmdir"
171
172	# Despite building in-place, rpmbuild still looks under %{_sourcedir} as defined
173	# in Source:. Create a dummy file to fulfil its needs and to keep Source in
174	# the .spec.
175	: > "$_sourcedir/spdk-$version.tar.gz"
176
177	cd "$rootdir"
178
179	printf '* Starting rpmbuild...\n'
180	rpmbuild --clean --nodebuginfo "${macros[@]}" --build-in-place -ba "$spec"
181)
182
183# .spec defaults
184configure=$*
185deps=${DEPS:-yes}
186make="${MAKEFLAGS:--j $(nproc)}"
187release=${RPM_RELEASE:-1}
188requirements=${REQUIREMENTS:-}
189build_requirements=${BUILD_REQUIREMENTS:-}
190version=${SPDK_VERSION:-$(get_version)}
191
192rpmbuild_dir=${BUILDDIR:-"$HOME/rpmbuild"}
193spec=$specdir/spdk.spec
194
195build_macros
196if [[ -n $GEN_SPEC ]]; then
197	gen_spec
198	exit 0
199fi
200build_rpm
201