github.com/johnnyeven/libtools@v0.0.0-20191126065708-61829c1adf46/third_party/systemlibs/protobuf.bzl (about)

     1  def _GetPath(ctx, path):
     2      if ctx.label.workspace_root:
     3          return ctx.label.workspace_root + "/" + path
     4      else:
     5          return path
     6  
     7  def _IsNewExternal(ctx):
     8      # Bazel 0.4.4 and older have genfiles paths that look like:
     9      #   bazel-out/local-fastbuild/genfiles/external/repo/foo
    10      # After the exec root rearrangement, they look like:
    11      #   ../repo/bazel-out/local-fastbuild/genfiles/foo
    12      return ctx.label.workspace_root.startswith("../")
    13  
    14  def _GenDir(ctx):
    15      if _IsNewExternal(ctx):
    16          # We are using the fact that Bazel 0.4.4+ provides repository-relative paths
    17          # for ctx.genfiles_dir.
    18          return ctx.genfiles_dir.path + (
    19              "/" + ctx.attr.includes[0] if ctx.attr.includes and ctx.attr.includes[0] else ""
    20          )
    21  
    22      # This means that we're either in the old version OR the new version in the local repo.
    23      # Either way, appending the source path to the genfiles dir works.
    24      return ctx.var["GENDIR"] + "/" + _SourceDir(ctx)
    25  
    26  def _SourceDir(ctx):
    27      if not ctx.attr.includes:
    28          return ctx.label.workspace_root
    29      if not ctx.attr.includes[0]:
    30          return _GetPath(ctx, ctx.label.package)
    31      if not ctx.label.package:
    32          return _GetPath(ctx, ctx.attr.includes[0])
    33      return _GetPath(ctx, ctx.label.package + "/" + ctx.attr.includes[0])
    34  
    35  def _CcHdrs(srcs, use_grpc_plugin = False):
    36      ret = [s[:-len(".proto")] + ".pb.h" for s in srcs]
    37      if use_grpc_plugin:
    38          ret += [s[:-len(".proto")] + ".grpc.pb.h" for s in srcs]
    39      return ret
    40  
    41  def _CcSrcs(srcs, use_grpc_plugin = False):
    42      ret = [s[:-len(".proto")] + ".pb.cc" for s in srcs]
    43      if use_grpc_plugin:
    44          ret += [s[:-len(".proto")] + ".grpc.pb.cc" for s in srcs]
    45      return ret
    46  
    47  def _CcOuts(srcs, use_grpc_plugin = False):
    48      return _CcHdrs(srcs, use_grpc_plugin) + _CcSrcs(srcs, use_grpc_plugin)
    49  
    50  def _PyOuts(srcs, use_grpc_plugin = False):
    51      ret = [s[:-len(".proto")] + "_pb2.py" for s in srcs]
    52      if use_grpc_plugin:
    53          ret += [s[:-len(".proto")] + "_pb2_grpc.py" for s in srcs]
    54      return ret
    55  
    56  def _RelativeOutputPath(path, include, dest = ""):
    57      if include == None:
    58          return path
    59  
    60      if not path.startswith(include):
    61          fail("Include path %s isn't part of the path %s." % (include, path))
    62  
    63      if include and include[-1] != "/":
    64          include = include + "/"
    65      if dest and dest[-1] != "/":
    66          dest = dest + "/"
    67  
    68      path = path[len(include):]
    69      return dest + path
    70  
    71  def _proto_gen_impl(ctx):
    72      """General implementation for generating protos"""
    73      srcs = ctx.files.srcs
    74      deps = []
    75      deps += ctx.files.srcs
    76      source_dir = _SourceDir(ctx)
    77      gen_dir = _GenDir(ctx)
    78      if source_dir:
    79          import_flags = ["-I" + source_dir, "-I" + gen_dir]
    80      else:
    81          import_flags = ["-I."]
    82  
    83      for dep in ctx.attr.deps:
    84          import_flags += dep.proto.import_flags
    85          deps += dep.proto.deps
    86  
    87      args = []
    88      if ctx.attr.gen_cc:
    89          args += ["--cpp_out=" + gen_dir]
    90      if ctx.attr.gen_py:
    91          args += ["--python_out=" + gen_dir]
    92  
    93      inputs = srcs + deps
    94      if ctx.executable.plugin:
    95          plugin = ctx.executable.plugin
    96          lang = ctx.attr.plugin_language
    97          if not lang and plugin.basename.startswith("protoc-gen-"):
    98              lang = plugin.basename[len("protoc-gen-"):]
    99          if not lang:
   100              fail("cannot infer the target language of plugin", "plugin_language")
   101  
   102          outdir = gen_dir
   103          if ctx.attr.plugin_options:
   104              outdir = ",".join(ctx.attr.plugin_options) + ":" + outdir
   105          args += ["--plugin=protoc-gen-%s=%s" % (lang, plugin.path)]
   106          args += ["--%s_out=%s" % (lang, outdir)]
   107          inputs += [plugin]
   108  
   109      if args:
   110          ctx.actions.run(
   111              inputs = inputs,
   112              outputs = ctx.outputs.outs,
   113              arguments = args + import_flags + [s.path for s in srcs],
   114              executable = ctx.executable.protoc,
   115              mnemonic = "ProtoCompile",
   116              use_default_shell_env = True,
   117          )
   118  
   119      return struct(
   120          proto = struct(
   121              srcs = srcs,
   122              import_flags = import_flags,
   123              deps = deps,
   124          ),
   125      )
   126  
   127  proto_gen = rule(
   128      attrs = {
   129          "srcs": attr.label_list(allow_files = True),
   130          "deps": attr.label_list(providers = ["proto"]),
   131          "includes": attr.string_list(),
   132          "protoc": attr.label(
   133              cfg = "host",
   134              executable = True,
   135              allow_single_file = True,
   136              mandatory = True,
   137          ),
   138          "plugin": attr.label(
   139              cfg = "host",
   140              allow_files = True,
   141              executable = True,
   142          ),
   143          "plugin_language": attr.string(),
   144          "plugin_options": attr.string_list(),
   145          "gen_cc": attr.bool(),
   146          "gen_py": attr.bool(),
   147          "outs": attr.output_list(),
   148      },
   149      output_to_genfiles = True,
   150      implementation = _proto_gen_impl,
   151  )
   152  """Generates codes from Protocol Buffers definitions.
   153  
   154  This rule helps you to implement Skylark macros specific to the target
   155  language. You should prefer more specific `cc_proto_library `,
   156  `py_proto_library` and others unless you are adding such wrapper macros.
   157  
   158  Args:
   159    srcs: Protocol Buffers definition files (.proto) to run the protocol compiler
   160      against.
   161    deps: a list of dependency labels; must be other proto libraries.
   162    includes: a list of include paths to .proto files.
   163    protoc: the label of the protocol compiler to generate the sources.
   164    plugin: the label of the protocol compiler plugin to be passed to the protocol
   165      compiler.
   166    plugin_language: the language of the generated sources
   167    plugin_options: a list of options to be passed to the plugin
   168    gen_cc: generates C++ sources in addition to the ones from the plugin.
   169    gen_py: generates Python sources in addition to the ones from the plugin.
   170    outs: a list of labels of the expected outputs from the protocol compiler.
   171  """
   172  
   173  def cc_proto_library(
   174          name,
   175          srcs = [],
   176          deps = [],
   177          cc_libs = [],
   178          include = None,
   179          protoc = "@com_google_protobuf//:protoc",
   180          internal_bootstrap_hack = False,
   181          use_grpc_plugin = False,
   182          default_runtime = "@com_google_protobuf//:protobuf",
   183          **kargs):
   184      """Bazel rule to create a C++ protobuf library from proto source files
   185  
   186      NOTE: the rule is only an internal workaround to generate protos. The
   187      interface may change and the rule may be removed when bazel has introduced
   188      the native rule.
   189  
   190      Args:
   191        name: the name of the cc_proto_library.
   192        srcs: the .proto files of the cc_proto_library.
   193        deps: a list of dependency labels; must be cc_proto_library.
   194        cc_libs: a list of other cc_library targets depended by the generated
   195            cc_library.
   196        include: a string indicating the include path of the .proto files.
   197        protoc: the label of the protocol compiler to generate the sources.
   198        internal_bootstrap_hack: a flag indicate the cc_proto_library is used only
   199            for bootstraping. When it is set to True, no files will be generated.
   200            The rule will simply be a provider for .proto files, so that other
   201            cc_proto_library can depend on it.
   202        use_grpc_plugin: a flag to indicate whether to call the grpc C++ plugin
   203            when processing the proto files.
   204        default_runtime: the implicitly default runtime which will be depended on by
   205            the generated cc_library target.
   206        **kargs: other keyword arguments that are passed to cc_library.
   207  
   208      """
   209  
   210      includes = []
   211      if include != None:
   212          includes = [include]
   213  
   214      if internal_bootstrap_hack:
   215          # For pre-checked-in generated files, we add the internal_bootstrap_hack
   216          # which will skip the codegen action.
   217          proto_gen(
   218              name = name + "_genproto",
   219              srcs = srcs,
   220              deps = [s + "_genproto" for s in deps],
   221              includes = includes,
   222              protoc = protoc,
   223              visibility = ["//visibility:public"],
   224          )
   225  
   226          # An empty cc_library to make rule dependency consistent.
   227          native.cc_library(
   228              name = name,
   229              **kargs
   230          )
   231          return
   232  
   233      grpc_cpp_plugin = None
   234      if use_grpc_plugin:
   235          grpc_cpp_plugin = "//external:grpc_cpp_plugin"
   236  
   237      gen_srcs = _CcSrcs(srcs, use_grpc_plugin)
   238      gen_hdrs = _CcHdrs(srcs, use_grpc_plugin)
   239      outs = gen_srcs + gen_hdrs
   240  
   241      proto_gen(
   242          name = name + "_genproto",
   243          srcs = srcs,
   244          deps = [s + "_genproto" for s in deps],
   245          includes = includes,
   246          protoc = protoc,
   247          plugin = grpc_cpp_plugin,
   248          plugin_language = "grpc",
   249          gen_cc = 1,
   250          outs = outs,
   251          visibility = ["//visibility:public"],
   252      )
   253  
   254      if default_runtime and not default_runtime in cc_libs:
   255          cc_libs = cc_libs + [default_runtime]
   256      if use_grpc_plugin:
   257          cc_libs = cc_libs + ["//external:grpc_lib"]
   258  
   259      native.cc_library(
   260          name = name,
   261          srcs = gen_srcs,
   262          hdrs = gen_hdrs,
   263          deps = cc_libs + deps,
   264          includes = includes,
   265          **kargs
   266      )
   267  
   268  def internal_gen_well_known_protos_java(srcs):
   269      """Bazel rule to generate the gen_well_known_protos_java genrule
   270  
   271      Args:
   272        srcs: the well known protos
   273      """
   274      root = Label("%s//protobuf_java" % (REPOSITORY_NAME)).workspace_root
   275      pkg = PACKAGE_NAME + "/" if PACKAGE_NAME else ""
   276      if root == "":
   277          include = " -I%ssrc " % pkg
   278      else:
   279          include = " -I%s/%ssrc " % (root, pkg)
   280      native.genrule(
   281          name = "gen_well_known_protos_java",
   282          srcs = srcs,
   283          outs = [
   284              "wellknown.srcjar",
   285          ],
   286          cmd = "$(location :protoc) --java_out=$(@D)/wellknown.jar" +
   287                " %s $(SRCS) " % include +
   288                " && mv $(@D)/wellknown.jar $(@D)/wellknown.srcjar",
   289          tools = [":protoc"],
   290      )
   291  
   292  def internal_copied_filegroup(name, srcs, strip_prefix, dest, **kwargs):
   293      """Macro to copy files to a different directory and then create a filegroup.
   294  
   295      This is used by the //:protobuf_python py_proto_library target to work around
   296      an issue caused by Python source files that are part of the same Python
   297      package being in separate directories.
   298  
   299      Args:
   300        srcs: The source files to copy and add to the filegroup.
   301        strip_prefix: Path to the root of the files to copy.
   302        dest: The directory to copy the source files into.
   303        **kwargs: extra arguments that will be passesd to the filegroup.
   304      """
   305      outs = [_RelativeOutputPath(s, strip_prefix, dest) for s in srcs]
   306  
   307      native.genrule(
   308          name = name + "_genrule",
   309          srcs = srcs,
   310          outs = outs,
   311          cmd = " && ".join(
   312              ["cp $(location %s) $(location %s)" %
   313               (s, _RelativeOutputPath(s, strip_prefix, dest)) for s in srcs],
   314          ),
   315      )
   316  
   317      native.filegroup(
   318          name = name,
   319          srcs = outs,
   320          **kwargs
   321      )
   322  
   323  def py_proto_library(
   324          name,
   325          srcs = [],
   326          deps = [],
   327          py_libs = [],
   328          py_extra_srcs = [],
   329          include = None,
   330          default_runtime = "@com_google_protobuf//:protobuf_python",
   331          protoc = "@com_google_protobuf//:protoc",
   332          use_grpc_plugin = False,
   333          **kargs):
   334      """Bazel rule to create a Python protobuf library from proto source files
   335  
   336      NOTE: the rule is only an internal workaround to generate protos. The
   337      interface may change and the rule may be removed when bazel has introduced
   338      the native rule.
   339  
   340      Args:
   341        name: the name of the py_proto_library.
   342        srcs: the .proto files of the py_proto_library.
   343        deps: a list of dependency labels; must be py_proto_library.
   344        py_libs: a list of other py_library targets depended by the generated
   345            py_library.
   346        py_extra_srcs: extra source files that will be added to the output
   347            py_library. This attribute is used for internal bootstrapping.
   348        include: a string indicating the include path of the .proto files.
   349        default_runtime: the implicitly default runtime which will be depended on by
   350            the generated py_library target.
   351        protoc: the label of the protocol compiler to generate the sources.
   352        use_grpc_plugin: a flag to indicate whether to call the Python C++ plugin
   353            when processing the proto files.
   354        **kargs: other keyword arguments that are passed to cc_library.
   355  
   356      """
   357      outs = _PyOuts(srcs, use_grpc_plugin)
   358  
   359      includes = []
   360      if include != None:
   361          includes = [include]
   362  
   363      grpc_python_plugin = None
   364      if use_grpc_plugin:
   365          grpc_python_plugin = "//external:grpc_python_plugin"
   366          # Note: Generated grpc code depends on Python grpc module. This dependency
   367          # is not explicitly listed in py_libs. Instead, host system is assumed to
   368          # have grpc installed.
   369  
   370      proto_gen(
   371          name = name + "_genproto",
   372          srcs = srcs,
   373          deps = [s + "_genproto" for s in deps],
   374          includes = includes,
   375          protoc = protoc,
   376          gen_py = 1,
   377          outs = outs,
   378          visibility = ["//visibility:public"],
   379          plugin = grpc_python_plugin,
   380          plugin_language = "grpc",
   381      )
   382  
   383      if default_runtime and not default_runtime in py_libs + deps:
   384          py_libs = py_libs + [default_runtime]
   385  
   386      native.py_library(
   387          name = name,
   388          srcs = outs + py_extra_srcs,
   389          deps = py_libs + deps,
   390          imports = includes,
   391          **kargs
   392      )
   393  
   394  def internal_protobuf_py_tests(
   395          name,
   396          modules = [],
   397          **kargs):
   398      """Bazel rules to create batch tests for protobuf internal.
   399  
   400      Args:
   401        name: the name of the rule.
   402        modules: a list of modules for tests. The macro will create a py_test for
   403            each of the parameter with the source "google/protobuf/%s.py"
   404        kargs: extra parameters that will be passed into the py_test.
   405  
   406      """
   407      for m in modules:
   408          s = "python/google/protobuf/internal/%s.py" % m
   409          native.py_test(
   410              name = "py_%s" % m,
   411              srcs = [s],
   412              main = s,
   413              **kargs
   414          )
   415  
   416  def check_protobuf_required_bazel_version():
   417      """For WORKSPACE files, to check the installed version of bazel.
   418  
   419      This ensures bazel supports our approach to proto_library() depending on a
   420      copied filegroup. (Fixed in bazel 0.5.4)
   421      """
   422      expected = apple_common.dotted_version("0.5.4")
   423      current = apple_common.dotted_version(native.bazel_version)
   424      if current.compare_to(expected) < 0:
   425          fail("Bazel must be newer than 0.5.4")