blob: a1562c76a87ccd0f33d44c1667c6c9607c395fc4 [file] [log] [blame]
Jeff Vander Stoep3adfea82020-10-14 15:35:59 +02001# Copyright 2015 gRPC authors.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""A setup module for the GRPC Python package."""
16from distutils import cygwinccompiler
17from distutils import extension as _extension
18from distutils import util
19import os
20import os.path
21import pkg_resources
22import platform
23import re
24import shlex
25import shutil
26import sys
27import sysconfig
28
29import setuptools
30from setuptools.command import egg_info
31
32import subprocess
33from subprocess import PIPE
34
35# Redirect the manifest template from MANIFEST.in to PYTHON-MANIFEST.in.
36egg_info.manifest_maker.template = 'PYTHON-MANIFEST.in'
37
38PY3 = sys.version_info.major == 3
39PYTHON_STEM = os.path.join('src', 'python', 'grpcio')
40CORE_INCLUDE = ('include', '.',)
41ABSL_INCLUDE = (os.path.join('third_party', 'abseil-cpp'),)
42ADDRESS_SORTING_INCLUDE = (os.path.join('third_party', 'address_sorting', 'include'),)
43CARES_INCLUDE = (
44 os.path.join('third_party', 'cares'),
45 os.path.join('third_party', 'cares', 'cares'),)
46if 'darwin' in sys.platform:
47 CARES_INCLUDE += (os.path.join('third_party', 'cares', 'config_darwin'),)
48if 'freebsd' in sys.platform:
49 CARES_INCLUDE += (os.path.join('third_party', 'cares', 'config_freebsd'),)
50if 'linux' in sys.platform:
51 CARES_INCLUDE += (os.path.join('third_party', 'cares', 'config_linux'),)
52if 'openbsd' in sys.platform:
53 CARES_INCLUDE += (os.path.join('third_party', 'cares', 'config_openbsd'),)
54SSL_INCLUDE = (os.path.join('third_party', 'boringssl-with-bazel', 'src', 'include'),)
55UPB_INCLUDE = (os.path.join('third_party', 'upb'),)
56UPB_GRPC_GENERATED_INCLUDE = (os.path.join('src', 'core', 'ext', 'upb-generated'),)
57ZLIB_INCLUDE = (os.path.join('third_party', 'zlib'),)
58README = os.path.join(PYTHON_STEM, 'README.rst')
59
60# Ensure we're in the proper directory whether or not we're being used by pip.
61os.chdir(os.path.dirname(os.path.abspath(__file__)))
62sys.path.insert(0, os.path.abspath(PYTHON_STEM))
63
64# Break import-style to ensure we can actually find our in-repo dependencies.
65import _parallel_compile_patch
66import _spawn_patch
67import commands
68import grpc_core_dependencies
69import grpc_version
70
71_parallel_compile_patch.monkeypatch_compile_maybe()
72_spawn_patch.monkeypatch_spawn()
73
74LICENSE = 'Apache License 2.0'
75
76CLASSIFIERS = [
77 'Development Status :: 5 - Production/Stable',
78 'Programming Language :: Python',
79 'Programming Language :: Python :: 2',
80 'Programming Language :: Python :: 2.7',
81 'Programming Language :: Python :: 3',
82 'Programming Language :: Python :: 3.4',
83 'Programming Language :: Python :: 3.5',
84 'Programming Language :: Python :: 3.6',
85 'Programming Language :: Python :: 3.7',
86 'Programming Language :: Python :: 3.8',
87 'License :: OSI Approved :: Apache Software License',
88]
89
90# Environment variable to determine whether or not the Cython extension should
91# *use* Cython or use the generated C files. Note that this requires the C files
92# to have been generated by building first *with* Cython support. Even if this
93# is set to false, if the script detects that the generated `.c` file isn't
94# present, then it will still attempt to use Cython.
95BUILD_WITH_CYTHON = os.environ.get('GRPC_PYTHON_BUILD_WITH_CYTHON', False)
96
97
98# Export this variable to use the system installation of openssl. You need to
99# have the header files installed (in /usr/include/openssl) and during
100# runtime, the shared library must be installed
101BUILD_WITH_SYSTEM_OPENSSL = os.environ.get('GRPC_PYTHON_BUILD_SYSTEM_OPENSSL',
102 False)
103
104# Export this variable to use the system installation of zlib. You need to
105# have the header files installed (in /usr/include/) and during
106# runtime, the shared library must be installed
107BUILD_WITH_SYSTEM_ZLIB = os.environ.get('GRPC_PYTHON_BUILD_SYSTEM_ZLIB',
108 False)
109
110# Export this variable to use the system installation of cares. You need to
111# have the header files installed (in /usr/include/) and during
112# runtime, the shared library must be installed
113BUILD_WITH_SYSTEM_CARES = os.environ.get('GRPC_PYTHON_BUILD_SYSTEM_CARES',
114 False)
115
116# For local development use only: This skips building gRPC Core and its
117# dependencies, including protobuf and boringssl. This allows "incremental"
118# compilation by first building gRPC Core using make, then building only the
119# Python/Cython layers here.
120#
121# Note that this requires libboringssl.a in the libs/{dbg,opt}/ directory, which
122# may require configuring make to not use the system openssl implementation:
123#
124# make HAS_SYSTEM_OPENSSL_ALPN=0
125#
126# TODO(ericgribkoff) Respect the BUILD_WITH_SYSTEM_* flags alongside this option
127USE_PREBUILT_GRPC_CORE = os.environ.get(
128 'GRPC_PYTHON_USE_PREBUILT_GRPC_CORE', False)
129
130
131# If this environmental variable is set, GRPC will not try to be compatible with
132# libc versions old than the one it was compiled against.
133DISABLE_LIBC_COMPATIBILITY = os.environ.get('GRPC_PYTHON_DISABLE_LIBC_COMPATIBILITY', False)
134
135# Environment variable to determine whether or not to enable coverage analysis
136# in Cython modules.
137ENABLE_CYTHON_TRACING = os.environ.get(
138 'GRPC_PYTHON_ENABLE_CYTHON_TRACING', False)
139
140# Environment variable specifying whether or not there's interest in setting up
141# documentation building.
142ENABLE_DOCUMENTATION_BUILD = os.environ.get(
143 'GRPC_PYTHON_ENABLE_DOCUMENTATION_BUILD', False)
144
145def check_linker_need_libatomic():
146 """Test if linker on system needs libatomic."""
147 code_test = (b'#include <atomic>\n' +
148 b'int main() { return std::atomic<int64_t>{}; }')
149 cc_test = subprocess.Popen(['cc', '-x', 'c++', '-std=c++11', '-'],
150 stdin=PIPE,
151 stdout=PIPE,
152 stderr=PIPE)
153 cc_test.communicate(input=code_test)
154 return cc_test.returncode != 0
155
156# There are some situations (like on Windows) where CC, CFLAGS, and LDFLAGS are
157# entirely ignored/dropped/forgotten by distutils and its Cygwin/MinGW support.
158# We use these environment variables to thus get around that without locking
159# ourselves in w.r.t. the multitude of operating systems this ought to build on.
160# We can also use these variables as a way to inject environment-specific
161# compiler/linker flags. We assume GCC-like compilers and/or MinGW as a
162# reasonable default.
163EXTRA_ENV_COMPILE_ARGS = os.environ.get('GRPC_PYTHON_CFLAGS', None)
164EXTRA_ENV_LINK_ARGS = os.environ.get('GRPC_PYTHON_LDFLAGS', None)
165if EXTRA_ENV_COMPILE_ARGS is None:
166 EXTRA_ENV_COMPILE_ARGS = ' -std=c++11'
167 if 'win32' in sys.platform:
168 if sys.version_info < (3, 5):
169 EXTRA_ENV_COMPILE_ARGS += ' -D_hypot=hypot'
170 # We use define flags here and don't directly add to DEFINE_MACROS below to
171 # ensure that the expert user/builder has a way of turning it off (via the
172 # envvars) without adding yet more GRPC-specific envvars.
173 # See https://sourceforge.net/p/mingw-w64/bugs/363/
174 if '32' in platform.architecture()[0]:
175 EXTRA_ENV_COMPILE_ARGS += ' -D_ftime=_ftime32 -D_timeb=__timeb32 -D_ftime_s=_ftime32_s'
176 else:
177 EXTRA_ENV_COMPILE_ARGS += ' -D_ftime=_ftime64 -D_timeb=__timeb64'
178 else:
179 # We need to statically link the C++ Runtime, only the C runtime is
180 # available dynamically
181 EXTRA_ENV_COMPILE_ARGS += ' /MT'
182 elif "linux" in sys.platform:
183 EXTRA_ENV_COMPILE_ARGS += ' -std=gnu99 -fvisibility=hidden -fno-wrapv -fno-exceptions'
184 elif "darwin" in sys.platform:
185 EXTRA_ENV_COMPILE_ARGS += ' -stdlib=libc++ -fvisibility=hidden -fno-wrapv -fno-exceptions'
186
187if EXTRA_ENV_LINK_ARGS is None:
188 EXTRA_ENV_LINK_ARGS = ''
189 if "linux" in sys.platform or "darwin" in sys.platform:
190 EXTRA_ENV_LINK_ARGS += ' -lpthread'
191 if check_linker_need_libatomic():
192 EXTRA_ENV_LINK_ARGS += ' -latomic'
193 elif "win32" in sys.platform and sys.version_info < (3, 5):
194 msvcr = cygwinccompiler.get_msvcr()[0]
195 EXTRA_ENV_LINK_ARGS += (
196 ' -static-libgcc -static-libstdc++ -mcrtdll={msvcr}'
197 ' -static -lshlwapi'.format(msvcr=msvcr))
198 if "linux" in sys.platform:
199 EXTRA_ENV_LINK_ARGS += ' -Wl,-wrap,memcpy -static-libgcc'
200
201EXTRA_COMPILE_ARGS = shlex.split(EXTRA_ENV_COMPILE_ARGS)
202EXTRA_LINK_ARGS = shlex.split(EXTRA_ENV_LINK_ARGS)
203
204CYTHON_EXTENSION_PACKAGE_NAMES = ()
205
206CYTHON_EXTENSION_MODULE_NAMES = ('grpc._cython.cygrpc',)
207
208CYTHON_HELPER_C_FILES = ()
209
210CORE_C_FILES = tuple(grpc_core_dependencies.CORE_SOURCE_FILES)
211if "win32" in sys.platform:
212 CORE_C_FILES = filter(lambda x: 'third_party/cares' not in x, CORE_C_FILES)
213
214if BUILD_WITH_SYSTEM_OPENSSL:
215 CORE_C_FILES = filter(lambda x: 'third_party/boringssl' not in x, CORE_C_FILES)
216 CORE_C_FILES = filter(lambda x: 'src/boringssl' not in x, CORE_C_FILES)
217 SSL_INCLUDE = (os.path.join('/usr', 'include', 'openssl'),)
218
219if BUILD_WITH_SYSTEM_ZLIB:
220 CORE_C_FILES = filter(lambda x: 'third_party/zlib' not in x, CORE_C_FILES)
221 ZLIB_INCLUDE = (os.path.join('/usr', 'include'),)
222
223if BUILD_WITH_SYSTEM_CARES:
224 CORE_C_FILES = filter(lambda x: 'third_party/cares' not in x, CORE_C_FILES)
225 CARES_INCLUDE = (os.path.join('/usr', 'include'),)
226
227EXTENSION_INCLUDE_DIRECTORIES = (
228 (PYTHON_STEM,) +
229 CORE_INCLUDE +
230 ABSL_INCLUDE +
231 ADDRESS_SORTING_INCLUDE +
232 CARES_INCLUDE +
233 SSL_INCLUDE +
234 UPB_INCLUDE +
235 UPB_GRPC_GENERATED_INCLUDE +
236 ZLIB_INCLUDE)
237
238EXTENSION_LIBRARIES = ()
239if "linux" in sys.platform:
240 EXTENSION_LIBRARIES += ('rt',)
241if not "win32" in sys.platform:
242 EXTENSION_LIBRARIES += ('m',)
243if "win32" in sys.platform:
244 EXTENSION_LIBRARIES += ('advapi32', 'ws2_32', 'dbghelp',)
245if BUILD_WITH_SYSTEM_OPENSSL:
246 EXTENSION_LIBRARIES += ('ssl', 'crypto',)
247if BUILD_WITH_SYSTEM_ZLIB:
248 EXTENSION_LIBRARIES += ('z',)
249if BUILD_WITH_SYSTEM_CARES:
250 EXTENSION_LIBRARIES += ('cares',)
251
252DEFINE_MACROS = (('OPENSSL_NO_ASM', 1), ('_WIN32_WINNT', 0x600))
253if not DISABLE_LIBC_COMPATIBILITY:
254 DEFINE_MACROS += (('GPR_BACKWARDS_COMPATIBILITY_MODE', 1),)
255if "win32" in sys.platform:
256 # TODO(zyc): Re-enable c-ares on x64 and x86 windows after fixing the
257 # ares_library_init compilation issue
258 DEFINE_MACROS += (('WIN32_LEAN_AND_MEAN', 1), ('CARES_STATICLIB', 1),
259 ('GRPC_ARES', 0), ('NTDDI_VERSION', 0x06000000),
260 ('NOMINMAX', 1),)
261 if '64bit' in platform.architecture()[0]:
262 DEFINE_MACROS += (('MS_WIN64', 1),)
263 elif sys.version_info >= (3, 5):
264 # For some reason, this is needed to get access to inet_pton/inet_ntop
265 # on msvc, but only for 32 bits
266 DEFINE_MACROS += (('NTDDI_VERSION', 0x06000000),)
267else:
268 DEFINE_MACROS += (('HAVE_CONFIG_H', 1), ('GRPC_ENABLE_FORK_SUPPORT', 1),)
269
270LDFLAGS = tuple(EXTRA_LINK_ARGS)
271CFLAGS = tuple(EXTRA_COMPILE_ARGS)
272if "linux" in sys.platform or "darwin" in sys.platform:
273 pymodinit_type = 'PyObject*' if PY3 else 'void'
274 pymodinit = 'extern "C" __attribute__((visibility ("default"))) {}'.format(pymodinit_type)
275 DEFINE_MACROS += (('PyMODINIT_FUNC', pymodinit),)
276 DEFINE_MACROS += (('GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK', 1),)
277
278# By default, Python3 distutils enforces compatibility of
279# c plugins (.so files) with the OSX version Python3 was built with.
280# For Python3.4, this is OSX 10.6, but we need Thread Local Support (__thread)
281if 'darwin' in sys.platform and PY3:
282 mac_target = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET')
283 if mac_target and (pkg_resources.parse_version(mac_target) <
284 pkg_resources.parse_version('10.7.0')):
285 os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.7'
286 os.environ['_PYTHON_HOST_PLATFORM'] = re.sub(
287 r'macosx-[0-9]+\.[0-9]+-(.+)',
288 r'macosx-10.7-\1',
289 util.get_platform())
290
291
292def cython_extensions_and_necessity():
293 cython_module_files = [os.path.join(PYTHON_STEM,
294 name.replace('.', '/') + '.pyx')
295 for name in CYTHON_EXTENSION_MODULE_NAMES]
296 config = os.environ.get('CONFIG', 'opt')
297 prefix = 'libs/' + config + '/'
298 if USE_PREBUILT_GRPC_CORE:
299 extra_objects = [prefix + 'libares.a',
300 prefix + 'libboringssl.a',
301 prefix + 'libgpr.a',
302 prefix + 'libgrpc.a']
303 core_c_files = []
304 else:
305 core_c_files = list(CORE_C_FILES)
306 extra_objects = []
307 extensions = [
308 _extension.Extension(
309 name=module_name,
310 sources=[module_file] + list(CYTHON_HELPER_C_FILES) + core_c_files,
311 include_dirs=list(EXTENSION_INCLUDE_DIRECTORIES),
312 libraries=list(EXTENSION_LIBRARIES),
313 define_macros=list(DEFINE_MACROS),
314 extra_objects=extra_objects,
315 extra_compile_args=list(CFLAGS),
316 extra_link_args=list(LDFLAGS),
317 ) for (module_name, module_file) in zip(list(CYTHON_EXTENSION_MODULE_NAMES), cython_module_files)
318 ]
319 need_cython = BUILD_WITH_CYTHON
320 if not BUILD_WITH_CYTHON:
321 need_cython = need_cython or not commands.check_and_update_cythonization(extensions)
322 # TODO: the strategy for conditional compiling and exposing the aio Cython
323 # dependencies will be revisited by https://github.com/grpc/grpc/issues/19728
324 return commands.try_cythonize(extensions, linetracing=ENABLE_CYTHON_TRACING, mandatory=BUILD_WITH_CYTHON), need_cython
325
326CYTHON_EXTENSION_MODULES, need_cython = cython_extensions_and_necessity()
327
328PACKAGE_DIRECTORIES = {
329 '': PYTHON_STEM,
330}
331
332INSTALL_REQUIRES = (
333 "six>=1.5.2",
334 "futures>=2.2.0; python_version<'3.2'",
335 "enum34>=1.0.4; python_version<'3.4'",
336)
337
338SETUP_REQUIRES = INSTALL_REQUIRES + (
339 'Sphinx~=1.8.1',
340 'six>=1.10',
341 ) if ENABLE_DOCUMENTATION_BUILD else ()
342
343try:
344 import Cython
345except ImportError:
346 if BUILD_WITH_CYTHON:
347 sys.stderr.write(
348 "You requested a Cython build via GRPC_PYTHON_BUILD_WITH_CYTHON, "
349 "but do not have Cython installed. We won't stop you from using "
350 "other commands, but the extension files will fail to build.\n")
351 elif need_cython:
352 sys.stderr.write(
353 'We could not find Cython. Setup may take 10-20 minutes.\n')
354 SETUP_REQUIRES += ('cython>=0.23',)
355
356COMMAND_CLASS = {
357 'doc': commands.SphinxDocumentation,
358 'build_project_metadata': commands.BuildProjectMetadata,
359 'build_py': commands.BuildPy,
360 'build_ext': commands.BuildExt,
361 'gather': commands.Gather,
362}
363
364# Ensure that package data is copied over before any commands have been run:
365credentials_dir = os.path.join(PYTHON_STEM, 'grpc', '_cython', '_credentials')
366try:
367 os.mkdir(credentials_dir)
368except OSError:
369 pass
370shutil.copyfile(os.path.join('etc', 'roots.pem'),
371 os.path.join(credentials_dir, 'roots.pem'))
372
373PACKAGE_DATA = {
374 # Binaries that may or may not be present in the final installation, but are
375 # mentioned here for completeness.
376 'grpc._cython': [
377 '_credentials/roots.pem',
378 '_windows/grpc_c.32.python',
379 '_windows/grpc_c.64.python',
380 ],
381}
382PACKAGES = setuptools.find_packages(PYTHON_STEM)
383
384setuptools.setup(
385 name='grpcio',
386 version=grpc_version.VERSION,
387 description='HTTP/2-based RPC framework',
388 author='The gRPC Authors',
389 author_email='grpc-io@googlegroups.com',
390 url='https://grpc.io',
391 license=LICENSE,
392 classifiers=CLASSIFIERS,
393 long_description=open(README).read(),
394 ext_modules=CYTHON_EXTENSION_MODULES,
395 packages=list(PACKAGES),
396 package_dir=PACKAGE_DIRECTORIES,
397 package_data=PACKAGE_DATA,
398 install_requires=INSTALL_REQUIRES,
399 setup_requires=SETUP_REQUIRES,
400 cmdclass=COMMAND_CLASS,
401)