1#!/bin/bash
2# Copyright 2015 gRPC authors.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#     http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16set -ex
17
18# change to grpc repo root
19cd "$(dirname "$0")/../../.."
20
21##########################
22# Portability operations #
23##########################
24
25PLATFORM=$(uname -s)
26
27function is_msys() {
28  if [ "${PLATFORM/MSYS}" != "$PLATFORM" ]; then
29    echo true
30  else
31    exit 1
32  fi
33}
34
35function is_mingw() {
36  if [ "${PLATFORM/MINGW}" != "$PLATFORM" ]; then
37    echo true
38  else
39    exit 1
40  fi
41}
42
43function is_darwin() {
44  if [ "${PLATFORM/Darwin}" != "$PLATFORM" ]; then
45    echo true
46  else
47    exit 1
48  fi
49}
50
51function is_linux() {
52  if [ "${PLATFORM/Linux}" != "$PLATFORM" ]; then
53    echo true
54  else
55    exit 1
56  fi
57}
58
59function inside_venv() {
60  if [[ -n "${VIRTUAL_ENV}" ]]; then
61    echo true
62  fi
63}
64
65# Associated virtual environment name for the given python command.
66function venv() {
67  $1 -c "import sys; print('py{}{}'.format(*sys.version_info[:2]))"
68}
69
70# Path to python executable within a virtual environment depending on the
71# system.
72function venv_relative_python() {
73  if [ "$(is_mingw)" ]; then
74    echo 'Scripts/python.exe'
75  else
76    echo 'bin/python'
77  fi
78}
79
80# Distutils toolchain to use depending on the system.
81function toolchain() {
82  if [ "$(is_mingw)" ]; then
83    echo 'mingw32'
84  else
85    echo 'unix'
86  fi
87}
88
89####################
90# Script Arguments #
91####################
92
93PYTHON=${1:-python2.7}
94VENV=${2:-$(venv "$PYTHON")}
95VENV_RELATIVE_PYTHON=${3:-$(venv_relative_python)}
96TOOLCHAIN=${4:-$(toolchain)}
97
98if [ "$(is_msys)" ]; then
99  echo "MSYS doesn't directly provide the right compiler(s);"
100  echo "switch to a MinGW shell."
101  exit 1
102fi
103
104ROOT=$(pwd)
105export CFLAGS="-I$ROOT/include -fno-wrapv $CFLAGS"
106export GRPC_PYTHON_BUILD_WITH_CYTHON=1
107export LANG=en_US.UTF-8
108
109# Allow build_ext to build C/C++ files in parallel
110# by enabling a monkeypatch. It speeds up the build a lot.
111DEFAULT_PARALLEL_JOBS=$(nproc) || DEFAULT_PARALLEL_JOBS=4
112export GRPC_PYTHON_BUILD_EXT_COMPILER_JOBS=${GRPC_PYTHON_BUILD_EXT_COMPILER_JOBS:-$DEFAULT_PARALLEL_JOBS}
113
114# activate ccache if desired
115# shellcheck disable=SC1091
116source tools/internal_ci/helper_scripts/prepare_ccache_symlinks_rc
117
118############################
119# Perform build operations #
120############################
121
122if [[ "$(inside_venv)" ]]; then
123  VENV_PYTHON="$PYTHON"
124else
125  # Instantiate the virtualenv from the Python version passed in.
126  $PYTHON -m pip install --user virtualenv==20.0.23
127  $PYTHON -m virtualenv "$VENV"
128  VENV_PYTHON="$(pwd)/$VENV/$VENV_RELATIVE_PYTHON"
129fi
130
131
132# On library/version/platforms combo that do not have a binary
133# published, we may end up building a dependency from source. In that
134# case, several of our build environment variables may disrupt the
135# third-party build process. This function pipes through only the
136# minimal environment necessary.
137pip_install() {
138  /usr/bin/env -i PATH="$PATH" "$VENV_PYTHON" -m pip install "$@"
139}
140
141# Pin setuptools to < 60.0.0 to restore the distutil installation, see:
142# https://github.com/pypa/setuptools/pull/2896
143export SETUPTOOLS_USE_DISTUTILS=stdlib
144pip_install --upgrade pip==21.3.1
145pip_install --upgrade setuptools==59.6.0
146
147# pip-installs the directory specified. Used because on MSYS the vanilla Windows
148# Python gets confused when parsing paths.
149pip_install_dir() {
150  PWD=$(pwd)
151  cd "$1"
152  ($VENV_PYTHON setup.py build_ext -c "$TOOLCHAIN" || true)
153  $VENV_PYTHON -m pip install --no-deps .
154  cd "$PWD"
155}
156
157pip_install_dir_and_deps() {
158  PWD=$(pwd)
159  cd "$1"
160  ($VENV_PYTHON setup.py build_ext -c "$TOOLCHAIN" || true)
161  $VENV_PYTHON -m pip install .
162  cd "$PWD"
163}
164
165pip_install -U gevent
166
167pip_install --upgrade cython
168pip_install --upgrade six 'protobuf>=4.21.3rc1,!=4.22.0.*'
169
170if [ "$("$VENV_PYTHON" -c "import sys; print(sys.version_info[0])")" == "2" ]
171then
172  pip_install --upgrade futures enum34
173fi
174
175pip_install_dir "$ROOT"
176
177$VENV_PYTHON "$ROOT/tools/distrib/python/make_grpcio_tools.py"
178pip_install_dir_and_deps "$ROOT/tools/distrib/python/grpcio_tools"
179
180# Build/install Channelz
181$VENV_PYTHON "$ROOT/src/python/grpcio_channelz/setup.py" preprocess
182$VENV_PYTHON "$ROOT/src/python/grpcio_channelz/setup.py" build_package_protos
183pip_install_dir "$ROOT/src/python/grpcio_channelz"
184
185# Build/install health checking
186$VENV_PYTHON "$ROOT/src/python/grpcio_health_checking/setup.py" preprocess
187$VENV_PYTHON "$ROOT/src/python/grpcio_health_checking/setup.py" build_package_protos
188pip_install_dir "$ROOT/src/python/grpcio_health_checking"
189
190# Build/install reflection
191$VENV_PYTHON "$ROOT/src/python/grpcio_reflection/setup.py" preprocess
192$VENV_PYTHON "$ROOT/src/python/grpcio_reflection/setup.py" build_package_protos
193pip_install_dir "$ROOT/src/python/grpcio_reflection"
194
195# Build/install status proto mapping
196$VENV_PYTHON "$ROOT/src/python/grpcio_status/setup.py" preprocess
197$VENV_PYTHON "$ROOT/src/python/grpcio_status/setup.py" build_package_protos
198pip_install_dir "$ROOT/src/python/grpcio_status"
199
200# Build/install csds
201pip_install_dir "$ROOT/src/python/grpcio_csds"
202
203# Build/install admin
204pip_install_dir "$ROOT/src/python/grpcio_admin"
205
206# Install testing
207pip_install_dir "$ROOT/src/python/grpcio_testing"
208
209# Build/install tests
210pip_install coverage==4.4 oauth2client==4.1.0 \
211            google-auth>=1.17.2 requests==2.14.2 \
212            googleapis-common-protos>=1.5.5 rsa==4.0
213$VENV_PYTHON "$ROOT/src/python/grpcio_tests/setup.py" preprocess
214$VENV_PYTHON "$ROOT/src/python/grpcio_tests/setup.py" build_package_protos
215pip_install_dir "$ROOT/src/python/grpcio_tests"
216