Files
ortools-clone/tools/docker/python/build-manylinux.sh
2021-10-05 22:04:53 +02:00

232 lines
6.1 KiB
Bash
Executable File

#!/usr/bin/env bash
# Build all the wheel artifacts for the platforms supported by manylinux2014 and
# export them to the specified location.
set -exo pipefail
function assert_defined(){
if [[ -z "${!1}" ]]; then
>&2 echo "Variable '${1}' must be defined"
exit 1
fi
}
function usage() {
local -r NAME=$(basename "$0")
echo -e "$NAME - Build using a cross toolchain.
SYNOPSIS
\t$NAME [-h|--help] [build|test|all]
DESCRIPTION
\tBuild wheel artifacts.
\tYou MUST define the following variables before running this script:
\t* PLATFORM: x86_64 aarch64
\t* PYTHON_VERSION: 3 36 37 38 39 310
note: PYTHON_VERSION=3 will generate for all pythons which could take time...
OPTIONS
\t-h --help: show this help text
\tbuild: build the project using each python (note: remove previous build dir)
\ttest: install each wheel in a venv then test it (note: don't build !)
\tall: build + test (default)
EXAMPLES
* Using export
export PLATFORM=x86_64
export PYTHON_VERSION=39
$0 build
* One-liner:
PLATFORM=x86_64 PYTHON_VERSION=39 $0 build"
}
function contains_element() {
# Look for the presence of an element in an array. Echoes '0' if found,
# '1' otherwise.
# Arguments:
# $1 the element to be searched
# $2 the array to search into
local e match="$1"
shift
for e; do
[[ "$e" == "$match" ]] && return 0
done
return 1
}
function build_wheel() {
assert_defined BUILD_DIR
assert_defined VENV_DIR
# Build the wheel artifact
# Arguments:
# $1 the python root directory
if [[ "$#" -ne 1 ]]; then
echo "$0 called with an illegal number of parameters"
exit 1
fi
# Create and activate virtualenv
# this is needed so protoc can call the correct python executable
local -r PYBIN="$1/bin"
"${PYBIN}/pip" install virtualenv
"${PYBIN}/virtualenv" -p "${PYBIN}/python" "${VENV_DIR}"
# shellcheck source=/dev/null
source "${VENV_DIR}/bin/activate"
pip install -U pip setuptools wheel absl-py # absl-py is needed by make test_python
pip install -U mypy-protobuf # need to generate protobuf mypy files
echo "current dir: $(pwd)"
if [[ ! -e "CMakeLists.txt" ]] || [[ ! -d "cmake" ]]; then
>&2 echo "Can't find project's CMakeLists.txt or cmake"
exit 2
fi
cmake -S. -B"${BUILD_DIR}" -DCMAKE_BUILD_TYPE=Release -DBUILD_DEPS=ON -DBUILD_PYTHON=ON -DPython3_ROOT_DIR="$1" -DBUILD_TESTING=OFF #--debug-find
cmake --build "${BUILD_DIR}" -v -j4
# Restore environment
deactivate
}
function check_wheel() {
assert_defined BUILD_DIR
# Check the wheel artifact
# Arguments:
# $1 the python root directory
if [[ "$#" -ne 1 ]]; then
echo "$0 called with an illegal number of parameters"
exit 1
fi
# Check all generated wheel packages
pushd "${BUILD_DIR}/python/dist"
for FILE in *.whl; do
# if no files found do nothing
[[ -e "$FILE" ]] || continue
auditwheel show "$FILE" || true
auditwheel -v repair --plat "manylinux2014_$PLATFORM" "$FILE" -w "$export_root"
#auditwheel -v repair --plat manylinux2014_x86_64 "$FILE" -w "$export_root"
#auditwheel -v repair --plat manylinux2014_aarch64 "$FILE" -w "$export_root"
done
popd
}
function test_wheel() {
assert_defined BUILD_DIR
assert_defined TEST_DIR
# Test the wheel artifacts
# Arguments:
# $1 the python root directory
if [[ "$#" -ne 1 ]]; then
echo "$0 called with an illegal number of parameters"
exit 1
fi
# Create and activate virtualenv
local -r PYBIN="$1/bin"
"${PYBIN}/pip" install virtualenv
"${PYBIN}/virtualenv" -p "${PYBIN}/python" "${TEST_DIR}"
# shellcheck source=/dev/null
source "${TEST_DIR}/bin/activate"
pip install -U pip setuptools wheel
# Install the wheel artifact
#pwd
local -r WHEEL_FILE=$(find "${BUILD_DIR}"/python/dist/*.whl | head -1)
echo "WHEEL file: ${WHEEL_FILE}"
pip install --no-cache-dir "$WHEEL_FILE"
pip show ortools
# Run all the specified test scripts using the current environment.
local -r ROOT_DIR=$(pwd)
pushd "$(mktemp -d)" # ensure we are not importing something from $PWD
python --version
for TEST in "${TESTS[@]}"; do
python "${ROOT_DIR}/${TEST}"
done
popd
# Restore environment
deactivate
}
function build() {
# For each python platform provided by manylinux, build and test artifacts.
for PYROOT in /opt/python/cp"${PYTHON_VERSION}"*-cp"${PYTHON_VERSION}"*; do
# shellcheck disable=SC2155
PYTAG=$(basename "$PYROOT")
echo "Python: $PYTAG"
# Check for platforms to be skipped
if contains_element "$PYTAG" "${SKIPS[@]}"; then
>&2 echo "skipping deprecated platform $PYTAG"
continue
fi
BUILD_DIR="build_${PYTAG}"
VENV_DIR="env_${PYTAG}"
build_wheel "$PYROOT"
check_wheel "$PYROOT"
done
}
function tests() {
# For each python platform provided by manylinux, build and test artifacts.
for PYROOT in /opt/python/cp"${PYTHON_VERSION}"*-cp"${PYTHON_VERSION}"*; do
# shellcheck disable=SC2155
PYTAG=$(basename "$PYROOT")
echo "Python: $PYTAG"
# Check for platforms to be skipped
if contains_element "$PYTAG" "${SKIPS[@]}"; then
>&2 echo "skipping deprecated platform $PYTAG"
continue
fi
BUILD_DIR="build_${PYTAG}"
TEST_DIR="test_${PYTAG}"
test_wheel "$PYROOT"
done
}
# Main
function main() {
case ${1} in
-h | --help)
usage; exit ;;
esac
assert_defined PLATFORM
assert_defined PYTHON_VERSION
# Setup
# Python scripts to be used as tests for the installed wheel. This list of files
# has been taken from the 'test_python' make target.
declare -a TESTS=(
"ortools/algorithms/samples/simple_knapsack_program.py"
"ortools/graph/samples/simple_max_flow_program.py"
"ortools/graph/samples/simple_min_cost_flow_program.py"
"ortools/linear_solver/samples/simple_lp_program.py"
"ortools/linear_solver/samples/simple_mip_program.py"
"ortools/sat/samples/simple_sat_program.py"
"ortools/constraint_solver/samples/tsp.py"
"ortools/constraint_solver/samples/vrp.py"
"ortools/constraint_solver/samples/cvrptw_break.py"
)
declare -a SKIPS=( "pp37-pypy37_pp73" )
case ${1} in
build)
build ;;
test)
tests ;;
*)
build
tests ;;
esac
}
main "${1:-all}"