cython_library.bzl 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. # Copyright 2021 The 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. """Custom rules for gRPC Python"""
  15. # Adapted with modifications from
  16. # tensorflow/tensorflow/core/platform/default/build_config.bzl
  17. # Native Bazel rules don't exist yet to compile Cython code, but rules have
  18. # been written at cython/cython and tensorflow/tensorflow. We branch from
  19. # Tensorflow's version as it is more actively maintained and works for gRPC
  20. # Python's needs.
  21. def pyx_library(name, deps = [], py_deps = [], srcs = [], **kwargs):
  22. """Compiles a group of .pyx / .pxd / .py files.
  23. First runs Cython to create .cpp files for each input .pyx or .py + .pxd
  24. pair. Then builds a shared object for each, passing "deps" to each cc_binary
  25. rule (includes Python headers by default). Finally, creates a py_library rule
  26. with the shared objects and any pure Python "srcs", with py_deps as its
  27. dependencies; the shared objects can be imported like normal Python files.
  28. Args:
  29. name: Name for the rule.
  30. deps: C/C++ dependencies of the Cython (e.g. Numpy headers).
  31. py_deps: Pure Python dependencies of the final library.
  32. srcs: .py, .pyx, or .pxd files to either compile or pass through.
  33. **kwargs: Extra keyword arguments passed to the py_library.
  34. """
  35. # First filter out files that should be run compiled vs. passed through.
  36. py_srcs = []
  37. pyx_srcs = []
  38. pxd_srcs = []
  39. for src in srcs:
  40. if src.endswith(".pyx") or (src.endswith(".py") and
  41. src[:-3] + ".pxd" in srcs):
  42. pyx_srcs.append(src)
  43. elif src.endswith(".py"):
  44. py_srcs.append(src)
  45. else:
  46. pxd_srcs.append(src)
  47. if src.endswith("__init__.py"):
  48. pxd_srcs.append(src)
  49. # Invoke cython to produce the shared object libraries.
  50. for filename in pyx_srcs:
  51. native.genrule(
  52. name = filename + "_cython_translation",
  53. srcs = [filename],
  54. outs = [filename.split(".")[0] + ".cpp"],
  55. # Optionally use PYTHON_BIN_PATH on Linux platforms so that python 3
  56. # works. Windows has issues with cython_binary so skip PYTHON_BIN_PATH.
  57. cmd =
  58. "PYTHONHASHSEED=0 $(location @cython//:cython_binary) --cplus $(SRCS) --output-file $(OUTS)",
  59. tools = ["@cython//:cython_binary"] + pxd_srcs,
  60. )
  61. shared_objects = []
  62. for src in pyx_srcs:
  63. stem = src.split(".")[0]
  64. shared_object_name = stem + ".so"
  65. native.cc_binary(
  66. name = shared_object_name,
  67. srcs = [stem + ".cpp"],
  68. deps = deps + ["@local_config_python//:python_headers"],
  69. linkshared = 1,
  70. )
  71. shared_objects.append(shared_object_name)
  72. data = shared_objects[:]
  73. data += kwargs.pop("data", [])
  74. # Now create a py_library with these shared objects as data.
  75. native.py_library(
  76. name = name,
  77. srcs = py_srcs,
  78. deps = py_deps,
  79. srcs_version = "PY2AND3",
  80. data = data,
  81. **kwargs
  82. )