xapian-haystack/xapian_wheel_builder.sh

243 lines
6.5 KiB
Bash
Executable File

#!/bin/sh
uname_sysname="$(uname -s)"
case "${uname_sysname}" in
Linux)
;;
Darwin)
;;
FreeBSD)
;;
*)
echo "Platform ${uname_sysname} is not supported"
exit 1
esac
PYTHON=$(command -v python3)
# shellcheck disable=SC2046
set -- $(getopt p: "$@")
for opt; do
case "$opt" in
-p)
PYTHON="$2"; shift 2 ;;
--)
shift ; break ;;
esac
done
usage() {
echo "usage: $0 [-p <path-to-python3>] version_number" 1>&2
}
version_at_least() {
test "$(printf "%s\\n%s" "${VERSION}" "${1}" | sort -V | head -n1)" = "${1}"
return $?
}
VERSION=${1-${XAPIAN_VERSION}}
if [ -z "${VERSION}" ]; then
usage
exit 1
fi
if [ -z "${PYTHON}" ] || [ ! -x "${PYTHON}" ]; then
usage
echo "error: could not find python3, please specify with -p" 1>&2
exit 1
fi
exittrap() { :; }
sigtrap() {
# Whether or not exittrap runs on EXIT due to a signal is not defined.
# We use it for cleanup, and cleaning up twice is not a problem,
# so let's do that.
exittrap
exit $(($1 + 128))
}
for sig in 1 2 13 15; do
# shellcheck disable=SC2064
trap "sigtrap $sig" $sig
done
trap 'exittrap' EXIT
WHL_DEST=$(pwd)
TMPDIR=$(mktemp -d -t "xapian-builder-XXXXXX") || die "Unable to mktemp"
exittrap() { rm -rf "${TMPDIR}"; }
set -e
echo "Building in ${TMPDIR}."
cd "${TMPDIR}"
echo "Preparing build virtualenv..."
VE="${TMPDIR}/ve"
"${PYTHON}" -m venv "${VE}"
"${VE}/bin/python" -m pip install --upgrade pip wheel setuptools
# xapian before 1.4.12 had issues building with sphinx>=2
if version_at_least "1.4.12"; then
"${VE}/bin/pip" install sphinx
else
"${VE}/bin/pip" install "sphinx<2"
fi
BASE_URI="https://oligarchy.co.uk/xapian/"
CORE="xapian-core-${VERSION}"
BINDINGS="xapian-bindings-${VERSION}"
CORE_URI="${BASE_URI}${VERSION}/${CORE}.tar.xz"
BINDINGS_URI="${BASE_URI}${VERSION}/${BINDINGS}.tar.xz"
echo "Downloading source..."
curl -O "${CORE_URI}"
curl -O "${BINDINGS_URI}"
echo "Extracting source..."
mkdir src
tar -C src -xf "${CORE}.tar.xz"
tar -C src -xf "${BINDINGS}.tar.xz"
# building xapian-core
mkdir target
prefix=${TMPDIR}/target
pprefix=${prefix}
case "${uname_sysname}" in
Linux|FreeBSD)
while [ ${#pprefix} -lt 7 ]; do
# add padding as needed
pprefix=${pprefix}/.
done
;;
esac
echo "Building xapian core..."
(
cd "src/${CORE}"
./configure --prefix="${pprefix}"
make
make install
)
XAPIAN_CONFIG="${prefix}/bin/xapian-config*"
echo "Building xapian python3 bindings..."
(
cd "src/${BINDINGS}"
# We're building python3 bindings here, and we need to contort things to make it work.
# We want the xapian-config we just built.
# We want the sphinx we just put in a virtualenv because the xapian bindings insist on making their docs.
# We use the python3 from that same virtualenv, because the xapian bindings don't use the shebang line of sphinx-build.
# We override PYTHON3_LIB because if we don't then the bindings will be installed in the virutalenv, despite what we set prefix to.
case "${uname_sysname}" in
FreeBSD)
sed -i '' -e 's|-lstdc++||' configure
;;
esac
./configure --prefix="$prefix" --with-python3 XAPIAN_CONFIG="${XAPIAN_CONFIG}" SPHINX_BUILD="${VE}/bin/sphinx-build" PYTHON3="${VE}/bin/python3" PYTHON3_LIB="${prefix}"
make
make install
)
binary_patch_rpath() {
file="${1}"
case "${uname_sysname}" in
Linux|FreeBSD)
# Binary patch rpath to be '$ORIGIN' as needed.
rpath_offset=$(strings -t d "${file}" | grep "${pprefix}/lib" | awk '{ printf $1; }')
printf "\$ORIGIN\\000" | dd of="${file}" obs=1 seek="${rpath_offset}" conv=notrunc 2>/dev/null
# Verify
readelf -d "${file}" | grep RUNPATH | grep -q ORIGIN
libxapian_name=$(ldd "${file}" | grep libxapian | awk '{ printf $1; }')
;;
Darwin)
libxapian_name=$(otool -L "${file}" | grep -o 'libxapian.*' | awk '{ printf $1; }')
install_name_tool -change "${prefix}/lib/${libxapian_name}" "@loader_path/${libxapian_name}" "${file}"
;;
esac
}
echo "preparing xapian wheel..."
for file in "${prefix}"/xapian/*.so; do
binary_patch_rpath "${file}"
done
# Copy libxapian into place alongside the python bindings.
cp "${prefix}/lib/${libxapian_name}" "${prefix}/xapian"
case "${uname_sysname}" in
Darwin)
install_name_tool -id "@loader_path/${libxapian_name}" "${prefix}/xapian/${libxapian_name}"
;;
esac
for file in "${prefix}"/bin/xapian-delve*; do
binary_patch_rpath "${file}"
cp "${file}" "${prefix}/xapian"
done
# Prepare the scaffolding for the wheel
cat > "${prefix}/setup.py" <<EOF
from pathlib import Path
from setuptools import setup
try:
from wheel.bdist_wheel import bdist_wheel as _bdist_wheel
class bdist_wheel(_bdist_wheel):
def finalize_options(self):
_bdist_wheel.finalize_options(self)
# Really, this is not pure python
self.root_is_pure = False
except ImportError:
bdist_wheel = None
cwd = Path(__file__).parent
readme = (cwd / 'README').read_text()
setup(name='xapian',
version='${VERSION}',
description='Xapian Library and Bindings for Python as packaged for local use by xapian-haystack',
long_description=readme,
long_description_content_type='text/plain',
license='GPL2',
classifiers=[
'License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)',
'Programming Language :: Python :: 3 :: Only',
],
packages=['xapian'],
cmdclass={'bdist_wheel': bdist_wheel},
include_package_data=True,
zip_safe=False)
EOF
cat > "${prefix}/MANIFEST.in" <<EOF
include xapian/*
EOF
cat > "${prefix}/README" <<EOF
This wheel contains the xapian library and python bindings.
It was built using \`xapian_wheel_builder.sh\` from the Xapian Haystack project.
Xapian Haystack is a Xapian backend for Django-Haystack.
https://github.com/notanumber/xapian-haystack
The Xapian version used in this wheel is: ${VERSION}
The sources were downloaded from the xapian upstream:
- ${CORE_URI}
- ${BINDINGS_URI}
Xapian's homepage can be found at https://xapian.org/
You can find the script used to build this specific wheel inside of itself.
EOF
(cd "${WHL_DEST}"; cp "$0" "${prefix}/xapian/xapian_wheel_builder.sh")
cp "src/${CORE}/COPYING" "${prefix}/LICENSE.txt"
(
cd target
"${VE}/bin/python" setup.py bdist_wheel
cp dist/*.whl "${WHL_DEST}"
)
cd "${WHL_DEST}"
rm -rf "${TMPDIR}"
exittrap() { :; }