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