setup.py 21 KB

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