Skip to content
Snippets Groups Projects
Commit 38388a2c authored by Guilhem Saurel's avatar Guilhem Saurel
Browse files

manylinux: eigenpy + hpp-fcl + pinocchio

parent bd24b00a
No related branches found
No related tags found
No related merge requests found
Showing
with 174 additions and 153 deletions
dist
wheelhouse
FROM memmos.laas.fr:5000/gepetto/buildfarm/robotpkg:centos7 as build
ADD config/robotpkg /
RUN while read pkg ; do make -C $pkg install; done < /robotpkg; \
rm -rf $(find . -name work.$HOSTNAME)
FROM quay.io/pypa/manylinux2014_x86_64:latest
ENV PLAT manylinux2014_x86_64
......@@ -9,6 +15,12 @@ RUN ./install_boost.sh
COPY build/setup_python.sh ./
RUN ./setup_python.sh
ADD config/packages /
RUN yum install -y $(cat /packages)
WORKDIR /src
ADD scripts /scripts
CMD ["/bin/bash"]
COPY --from=build /opt/openrobots /opt/openrobots
......@@ -4,92 +4,39 @@ This is set of scripts to help build manylinux2014 wheels, the wheels are built
python 2.7, 3.5, 3.6, 3.7 and 3.8.
## Config
In the `config/config` file, set the variables for your project.
The `config/packages` file need to be edited with the packages needed to build the
wheels, they need to be specified one per line and will be installed with `yum`.
You can also edit `scripts/pre_builds.sh` if needed, it will be run before building the wheels.
## Build the wheels
To build the wheels run:
```
docker build . -t manylinux
docker run -it -v `pwd`:/io manylinux /io/scripts/setup.sh
```
Then you need to verify that the generated `setup.py` is as you want,
and run `./build_wheels.sh`.
When the build is finished, you can exit docker. All the wheels can be found in `wheelhouse/`.
## Upload the wheels on PyPi
```
twine upload wheelhouse/*
docker build -t manylinux .
docker run -v (pwd -P):/io -it manylinux /scripts/setup.sh eigenpy
docker run -v (pwd -P):/io -it manylinux /scripts/setup.sh hpp-fcl
docker run -v (pwd -P):/io -it manylinux /scripts/setup.sh pinocchio
```
## Examples
## Test'em
### eigenpy 2.4.3:
`config/config`:
```
PACKAGE_NAME=eigenpy
TARGET_NAME=eigenpy
VERSION=2.4.3
GIT_URL=https://github.com/stack-of-tasks/eigenpy.git
INSTALL_REQUIRES='["numpy"]'
NPROC=8
```
`config/packages`:
```
eigen3-devel
docker build -f test.Dockerfile -t manylinux-test .
docker run --rm -it manylinux-test
```
### hppfcl 1.5.1:
`config/config`:
```
PACKAGE_NAME=hppfcl
TARGET_NAME=hppfcl
VERSION=1.5.1
GIT_URL=https://github.com/humanoid-path-planner/hpp-fcl.git
INSTALL_REQUIRES='["numpy"]'
NPROC=8
```
## Upload the wheels on PyPi
`config/packages`:
```
eigen3-devel
assimp-devel
poly2tri-devel
minizip-devel
irrXML-devel
zlib-devel
```
`script/pre_build.sh`:
twine upload wheelhouse/*
```
#!/bin/bash -eux
source "/io/config/config"
for PYBIN in /opt/python/*/bin; do
"$PYBIN"/pip install numpy
"$PYBIN"/pip install -i https://test.pypi.org/simple/ eigenpy-test==2.4.3
done
## TODO
git clone -j"$NPROC" git://github.com/OctoMap/octomap.git
cd octomap/
mkdir build && cd build
cmake ..
make -j"$NPROC" install
cd /src
rm -rf octomap
```
- use TARGET instead of PACKAGE_NAME: hpp-fcl on PyPI
- use robotpkg to build, instead of downloading the sources: could build all non-python stuff in the docker image
- pyproject.toml in skbuild doc
- lib/pythonX.Y/site-packages/foo.cpython\*.so links to libfoo.so and has RPATH: $ORIGIN/../../../foo.libs
foo.libs/libfoo.so RPATH: $ORIGIN:$ORIGIN/../bar.libs:$ORIGIN/../baz.libs
To test the wheels make sure `libgl1` is installed.
```cmake
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
set(CMAKE_INSTALL_RPATH "\$ORIGIN;\$ORIGIN/../bar.libs;\$ORIGIN/../baz.libs")
set_target_properties(foo_pywrap POPERTIES INSTALL_RPATH "\$ORIGIN/../../../foo.libs")
```
#!/bin/bash -eux
sudo touch dist wheelhouse
sudo rm -rf dist wheelhouse
docker build -t manylinux .
docker run -v "$(pwd -P):/io" -t manylinux /scripts/setup.sh eigenpy
docker run -v "$(pwd -P):/io" -t manylinux /scripts/setup.sh hpp-fcl
docker run -v "$(pwd -P):/io" -t manylinux /scripts/setup.sh pinocchio
docker build -f test.Dockerfile -t manylinux-test .
docker run --rm -t manylinux-test
# Name of the package
PACKAGE_NAME=
# Name of the package uploaded on PyPi
TARGET_NAME=
# Release version
VERSION=
# Git repo url
GIT_URL=
# List of python packages needed to build and install the wheel (ex: '["foo", "bar"]')
INSTALL_REQUIRES=''
# Maximum number of parallel jobs
NPROC=
PACKAGE_NAME=eigenpy
GITHUB_ORG=stack-of-tasks
VERSION=2.4.3
INSTALL_REQUIRES='["numpy"]'
NPROC=8
import unittest
import eigenpy
class TestEigenpy(unittest.TestCase):
def test_trivial(self):
self.assertLess(abs(eigenpy.Quaternion(1, 2, 3, 4).norm() - 5.47722557505), 1e-7)
if __name__ == '__main__':
unittest.main()
PACKAGE_NAME=hppfcl
GITHUB_ORG=humanoid-path-planner
VERSION=1.5.1
INSTALL_REQUIRES='["eigenpy"]'
NPROC=8
#!/bin/bash -eux
source "/io/config/hpp-fcl/config"
for PYBIN in /opt/python/*/bin; do
CP_VERSION="cp$("$PYBIN"/python -c "import sys; print(''.join(sys.version.split('.')[:2]))")"
#"$PYBIN"/pip install numpy
"$PYBIN"/pip install /io/dist/eigenpy-*-"$CP_VERSION"-*.whl
done
import unittest
import hppfcl
class TestHPPFCL(unittest.TestCase):
def test_trivial(self):
self.assertLess(abs(hppfcl.Capsule(2, 3).computeVolume() - 71.2094334814), 1e-7)
if __name__ == '__main__':
unittest.main()
assimp-devel
eigen3-devel
tinyxml
tinyxml2
tinyxml2-devel
tinyxml-devel
PACKAGE_NAME=pinocchio
GITHUB_ORG=stack-of-tasks
VERSION=2.4.7
INSTALL_REQUIRES='["hppfcl"]'
NPROC=8
#!/bin/bash -eux
source "/io/config/hpp-fcl/config"
for PYBIN in /opt/python/*/bin; do
CP_VERSION="cp$("$PYBIN"/python -c "import sys; print(''.join(sys.version.split('.')[:2]))")"
#"$PYBIN"/pip install numpy
"$PYBIN"/pip install /io/dist/eigenpy-*-"$CP_VERSION"-*.whl
"$PYBIN"/pip install /io/dist/hppfcl-*-"$CP_VERSION"-*.whl
done
import unittest
import pinocchio
class TestPinocchio(unittest.TestCase):
def test_trivial(self):
self.assertEqual(str(pinocchio.SE3.Identity().inverse()), ' R =\n1 0 0\n0 1 0\n0 0 1\n p = -0 -0 -0\n')
if __name__ == '__main__':
unittest.main()
mapping/octomap
graphics/urdfdom-headers
graphics/urdfdom
eigenpy
hpp-fcl
pinocchio
#!/bin/bash -eux
export LD_LIBRARY_PATH=/opt/openrobots/lib:$LD_LIBRARY_PATH
TARGET=${1:-eigenpy}
function repair_wheel {
wheel="$1"
if ! auditwheel show "$wheel"; then
......@@ -9,54 +13,35 @@ function repair_wheel {
fi
}
TEST_DIR=$(echo *test*) # Either 'unittest' or 'test' depending on the project
PYTHON_TEST_DIR=$(echo "$TEST_DIR"/python*) # Either 'python' or 'python_unit' depending on the project
SKIP_TESTS=$(grep -l BOOST_PYTHON_MODULE "$TEST_DIR"/*.cpp | cut -d'/' -f2 | sed 's/\.cpp/\.py/' | sed 's/^/test_/')
function test {
python="$1"
for f in /src/"$PYTHON_TEST_DIR"/*.py; do
if ! echo "$SKIP_TESTS" | grep "$(basename "$f")" > /dev/null; then
printf "\nTesting %s\n" "$f"
"$python" "$f"
printf "Ok\n"
fi
done
printf "\n"
}
source config
## Install dependencies
[ -s packages ] && xargs -a packages yum -y install
source "/io/config/$TARGET/config"
# Build wheels
for PYBIN in /opt/python/*/bin; do
[ -n "$INSTALL_REQUIRES" ] && "$PYBIN/pip" install "$(echo "$INSTALL_REQUIRES" | sed -E 's/"|\[|\]|,//g')"
PYVERSION=$(find "$PYBIN" -type f -name 'python*.*' | head -1 | grep -Eo "[0-9]\.[0-9]")
CMAKE_PREFIX_PATH=$(find / -path "*$PYVERSION*" -type d -name cmake | tr '\n' ';')
"$PYBIN/python" setup.py bdist_wheel -DCMAKE_PREFIX_PATH="$CMAKE_PREFIX_PATH" -DBUILD_TESTING=OFF -j"$NPROC"
export CMAKE_PREFIX_PATH="$(find / -path "*$PYVERSION*" -type d -name cmake | tr '\n' ':')/opt/openrobots"
"$PYBIN/python" setup.py bdist_wheel -j"$NPROC" -DBUILD_TESTING=OFF -DINSTALL_DOCUMENTATION=OFF \
-DCMAKE_INSTALL_LIBDIR=lib -DPYTHON_STANDARD_LAYOUT=ON -DENFORCE_MINIMAL_CXX_STANDARD=ON
# Bundle external shared libraries into the wheels
MAIN_LIB=$(find _skbuild/*/cmake-build -type f ! -path '*test/*' -name 'lib*.so*')
MAIN_LIB_DIR=$(pwd)/$(dirname "$MAIN_LIB")
MAIN_LIB_DIR="$PWD/_skbuild/linux-x86_64-$PYVERSION/cmake-install/lib"
OTHER_LIB_DIRS=$(find / -path "*$PYVERSION*.libs/*" -name *.so | xargs dirname | tr '\n' ':')
WHEEL_NAME=$(ls -Art dist/ | tail -n 1)
LD_LIBRARY_PATH="$MAIN_LIB_DIR:$OTHER_LIB_DIRS$LD_LIBRARY_PATH" \
repair_wheel "dist/$WHEEL_NAME"
auditwheel repair "dist/$WHEEL_NAME" --plat "$PLAT" -w /io/wheelhouse/
#repair_wheel "dist/$WHEEL_NAME"
rm -rf _skbuild
done
for whl in /io/wheelhouse/*.whl; do
wheel unpack "$whl"
MAIN_LIB=$(find . -type f ! -path '*.libs/*' ! -path '*lib64/*' -name '*.so*')
MAIN_LIB=$(find . -type f ! -path '*.libs/*' -name '*.so' | grep 'lib/python' | head -1)
LIB_DIR=$(find . -type d -name '*.libs')
PACKAGE_DIR=$(dirname "$MAIN_LIB")
LIB64_DIR=$(find . -type d -name 'lib64')
WHEEL_DIR=$(find . -name *.so | head -1 | cut -d'/' -f2)
WHEEL_DIR=$(find . -name '*.so' | head -1 | cut -d'/' -f2)
# Put the libs inside the package directory so the relative path to the libs is always the same
mv "$LIB_DIR" "$PACKAGE_DIR"/
......@@ -70,17 +55,14 @@ for whl in /io/wheelhouse/*.whl; do
patchelf --set-rpath '$ORIGIN' "$lib"
done
# Remove libraries that are present twice (auditwheel already copied them in the .libs directory)
rm -f "$LIB64_DIR"/*.so*
wheel pack "$WHEEL_DIR" -d /io/wheelhouse
rm -rf "${WHEEL_DIR:?}"/
done
# Install packages and test
for PYBIN in /opt/python/*/bin; do
"$PYBIN/pip" install "$TARGET_NAME" --no-index --find-links=/io/wheelhouse/
(cd "$HOME"; test "$PYBIN/python")
"$PYBIN/pip" install "$PACKAGE_NAME" --no-index --find-links=/io/wheelhouse/
(cd "$HOME"; "$PYBIN/python" "/io/config/$TARGET/test.py")
done
# TODO: Fix generated .cmake files (need to be done after installing the wheels so we know where the shared libraries are installed)
......@@ -88,23 +70,24 @@ for whl in /io/wheelhouse/*.whl; do
wheel unpack "$whl"
WHEEL_DIR=$(find . -name *.so | head -1 | cut -d'/' -f2)
PYVERSION=$(find "$WHEEL_DIR" -type d -name 'python*' | tail -c4)
MAIN_LIB=$(find / ! -path "*$WHEEL_DIR*" -path "*$PYVERSION*$PACKAGE_NAME*.libs/*" -name "*$PACKAGE_NAME*.so")
PYVERSION=$(find "$WHEEL_DIR" -type d -name 'python*' | grep 'lib/python' | tail -c4)
MAIN_LIB=$(find / ! -path "*$WHEEL_DIR*" -path "*$PYVERSION*$PACKAGE_NAME*.libs/*" -name "*$PACKAGE_NAME*.so*")
MAIN_LIB_NAME=$(basename "$MAIN_LIB") # libeigenpy-[hash].so
MAIN_LIB_NAME_NO_HASH=$(echo $MAIN_LIB_NAME | sed 's/-.*\.so/\.so/') # libeigenpy.so
#TODO: .cmake files should not have references to _skbuild, this is only a temporary fix to be able to build hpp-fcl
find "$WHEEL_DIR" -name '*.cmake' | while read -r file; do
sed -i 's:/src/_skbuild/linux-x86_64-.*/cmake-install/include:/usr/local/include:' "$file" || true
sed -i "s:/src/_skbuild/linux-x86_64-.*/cmake-install/lib64/.*\.so:$MAIN_LIB:" "$file" || true
sed -i "s:/src/_skbuild/linux-x86_64-.*/cmake-install/lib/.*\.so:$MAIN_LIB:" "$file" || true
sed -i "s:$MAIN_LIB_NAME_NO_HASH:$MAIN_LIB_NAME:" "$file" || true
sed -i 's:/src/_skbuild/linux-x86_64-.*/cmake-install/lib64:/usr/local/lib64:' "$file" || true
sed -i 's:/src/_skbuild/linux-x86_64-.*/cmake-install/lib:/usr/local/lib:' "$file" || true
done
wheel pack "$WHEEL_DIR" -d /io/wheelhouse
rm -rf "${WHEEL_DIR:?}"/
done
rm -rf "$TARGET_NAME".egg-info/ dist/
rm -rf "$PACKAGE_NAME".egg-info/ dist/
ls /io/wheelhouse
mkdir -p /io/dist
mv /io/wheelhouse/* /io/dist/
#!/bin/bash
......@@ -7,18 +7,16 @@ except FileNotFoundError:
long_description = ""
setup(
name=TARGET_NAME,
version=VERSION,
description=DESCRIPTION,
name="PACKAGE_NAME",
version="VERSION",
description="DESCRIPTION",
long_description=long_description,
long_description_content_type="text/markdown",
url=GIT_URL,
url="https://github.com/GITHUB_ORG/TARGET",
install_requires=INSTALL_REQUIRES,
classifiers=[
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 3",
"License :: OSI Approved :: BSD License",
"Operating System :: POSIX :: Linux"
"Programming Language :: Python :: 2", "Programming Language :: Python :: 3",
"License :: OSI Approved :: BSD License", "Operating System :: POSIX :: Linux"
],
python_requires='>=2.7',
)
#!/bin/bash -eu
#!/bin/bash -eux
TARGET=${1:-eigenpy}
# Verify that variables are set properly
source "/io/config/config"
for var in TARGET_NAME PACKAGE_NAME GIT_URL VERSION NPROC; do
source "/io/config/$TARGET/config"
for var in PACKAGE_NAME GITHUB_ORG VERSION NPROC; do
[ -z "${!var}" ] && { echo "$var is not set."; exit; }
done
mkdir -p /io/wheelhouse
[ "$(ls -A /io/wheelhouse)" ] && { echo "./wheelhouse should be empty before running this script."; exit; }
git clone --recursive -j"$NPROC" -b v"$VERSION" "$GIT_URL" /src
cp /io/scripts/* /src
cp /io/config/* /src
curl -sSL "https://github.com/$GITHUB_ORG/$TARGET/releases/download/v$VERSION/$TARGET-$VERSION.tar.gz" \
| tar xz --strip-components=1 2> /dev/null
cp /scripts/setup.py .
# Fix CMake for scikit-build
find . -name CMakeLists.txt | xargs sed -i 's/PYTHON_INCLUDE_DIRS/PYTHON_INCLUDE_DIR/'
sed -i 's/REQUIRED COMPONENTS Interpreter Development/REQUIRED COMPONENTS Interpreter/' cmake/python.cmake
# Write setup.py
DESCRIPTION=$(grep PROJECT_DESCRIPTION CMakeLists.txt | cut -d'"' -f2) # TODO: Not working if description on multiple lines
for var in TARGET_NAME VERSION DESCRIPTION GIT_URL; do
sed -i "s~$var~\"${!var}\"~" setup.py
DESCRIPTION=$(grep PROJECT_DESCRIPTION CMakeLists.txt | cut -d'"' -f2) # TODO: Not working on multiple lines
for var in PACKAGE_NAME GITHUB_ORG TARGET VERSION DESCRIPTION; do
sed -i "s~$var~${!var}~" setup.py
done
[ -z "$INSTALL_REQUIRES" ] && sed -i '/INSTALL_REQUIRES/d' setup.py
sed -i "s/INSTALL_REQUIRES/$INSTALL_REQUIRES/" setup.py
python setup.py --help > /dev/null 2>&1 || { echo "Syntax error in config/setup.py, please edit this file."; exit; }
cat setup.py
python setup.py --help || { echo "Syntax error in config/setup.py, please edit this file."; exit; }
./pre_build.sh
echo -e "\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"
echo -e "\nCurrent setup.py: \n"
cat setup.py
echo -e "\nMake sure that setup.py has the right values before continuing. Then run ./build_wheels.sh\n"
[ -x "/io/config/$TARGET/pre_build.sh" ] && "/io/config/$TARGET/pre_build.sh" "$TARGET"
echo -e "\n=========================================================================================================\n"
bash
/scripts/build_wheels.sh "$TARGET"
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment