Commit 66e3a6d0 authored by Jisi Liu's avatar Jisi Liu

Merge pull request #867 from pherl/master

Python bazel support
parents 32fb7dda 8f54026d
...@@ -18,7 +18,13 @@ COPTS = [ ...@@ -18,7 +18,13 @@ COPTS = [
# Bazel should provide portable link_opts for pthread. # Bazel should provide portable link_opts for pthread.
LINK_OPTS = ["-lpthread"] LINK_OPTS = ["-lpthread"]
load("protobuf", "cc_proto_library") load(
"protobuf",
"cc_proto_library",
"py_proto_library",
"internal_copied_filegroup",
"internal_protobuf_py_tests",
)
cc_library( cc_library(
name = "protobuf_lite", name = "protobuf_lite",
...@@ -126,7 +132,7 @@ objc_library( ...@@ -126,7 +132,7 @@ objc_library(
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
) )
WELL_KNOWN_PROTOS = [ RELATIVE_WELL_KNOWN_PROTOS = [
# AUTOGEN(well_known_protos) # AUTOGEN(well_known_protos)
"google/protobuf/any.proto", "google/protobuf/any.proto",
"google/protobuf/api.proto", "google/protobuf/api.proto",
...@@ -142,12 +148,15 @@ WELL_KNOWN_PROTOS = [ ...@@ -142,12 +148,15 @@ WELL_KNOWN_PROTOS = [
"google/protobuf/wrappers.proto", "google/protobuf/wrappers.proto",
] ]
WELL_KNOWN_PROTOS = ["src/" + s for s in RELATIVE_WELL_KNOWN_PROTOS]
cc_proto_library( cc_proto_library(
name = "cc_wkt_protos", name = "cc_wkt_protos",
srcs = ["src/" + s for s in WELL_KNOWN_PROTOS], srcs = WELL_KNOWN_PROTOS,
internal_bootstrap_hack = 1,
include = "src", include = "src",
cc_libs = [":protobuf"], cc_libs = [":protobuf"],
internal_bootstrap_hack = 1,
protoc = ":protoc",
) )
################################################################################ ################################################################################
...@@ -263,32 +272,11 @@ cc_binary( ...@@ -263,32 +272,11 @@ cc_binary(
deps = [":protoc_lib"], deps = [":protoc_lib"],
) )
################################################################################
# Java support
################################################################################
genrule(
name = "generate_java_descriptor_proto",
srcs = ["src/google/protobuf/descriptor.proto"],
outs = ["com/google/protobuf/DescriptorProtos.java"],
cmd = "$(location :protoc) --java_out=$(@D)/../../.. $<",
tools = [":protoc"],
)
java_library(
name = "java_proto",
srcs = glob([
"java/src/main/java/com/google/protobuf/*.java",
]) + [
":generate_java_descriptor_proto",
],
visibility = ["//visibility:public"],
)
################################################################################ ################################################################################
# Tests # Tests
################################################################################ ################################################################################
LITE_TEST_PROTOS = [ RELATIVE_LITE_TEST_PROTOS = [
# AUTOGEN(lite_test_protos) # AUTOGEN(lite_test_protos)
"google/protobuf/map_lite_unittest.proto", "google/protobuf/map_lite_unittest.proto",
"google/protobuf/unittest_import_lite.proto", "google/protobuf/unittest_import_lite.proto",
...@@ -297,7 +285,9 @@ LITE_TEST_PROTOS = [ ...@@ -297,7 +285,9 @@ LITE_TEST_PROTOS = [
"google/protobuf/unittest_no_arena_lite.proto", "google/protobuf/unittest_no_arena_lite.proto",
] ]
TEST_PROTOS = [ LITE_TEST_PROTOS = ["src/" + s for s in RELATIVE_LITE_TEST_PROTOS]
RELATIVE_TEST_PROTOS = [
# AUTOGEN(test_protos) # AUTOGEN(test_protos)
"google/protobuf/any_test.proto", "google/protobuf/any_test.proto",
"google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto", "google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto",
...@@ -337,10 +327,13 @@ TEST_PROTOS = [ ...@@ -337,10 +327,13 @@ TEST_PROTOS = [
"google/protobuf/util/json_format_proto3.proto", "google/protobuf/util/json_format_proto3.proto",
] ]
TEST_PROTOS = ["src/" + s for s in RELATIVE_TEST_PROTOS]
cc_proto_library( cc_proto_library(
name = "cc_test_protos", name = "cc_test_protos",
srcs = ["src/" + s for s in (LITE_TEST_PROTOS + TEST_PROTOS)], srcs = LITE_TEST_PROTOS + TEST_PROTOS,
include = "src", include = "src",
protoc = ":protoc",
deps = [":cc_wkt_protos"], deps = [":cc_wkt_protos"],
) )
...@@ -445,9 +438,134 @@ cc_test( ...@@ -445,9 +438,134 @@ cc_test(
], ],
linkopts = LINK_OPTS, linkopts = LINK_OPTS,
deps = [ deps = [
":cc_test_protos",
":protobuf", ":protobuf",
":protoc_lib", ":protoc_lib",
":cc_test_protos",
"//external:gtest_main", "//external:gtest_main",
], ],
) )
################################################################################
# Java support
################################################################################
genrule(
name = "generate_java_descriptor_proto",
srcs = ["src/google/protobuf/descriptor.proto"],
outs = ["com/google/protobuf/DescriptorProtos.java"],
cmd = "$(location :protoc) --java_out=$(@D)/../../.. $<",
tools = [":protoc"],
)
java_library(
name = "java_proto",
srcs = glob([
"java/src/main/java/com/google/protobuf/*.java",
]) + [
":generate_java_descriptor_proto",
],
visibility = ["//visibility:public"],
)
################################################################################
# Python support
################################################################################
# Requires: six for python 2/3 compatibility. `pip install six`
# Hack:
# protoc generated files contain imports like:
# "from google.protobuf.xxx import yyy"
# However, the sources files of the python runtime are not directly under
# "google/protobuf" (they are under python/google/protobuf). We workaround
# this by copying runtime source files into the desired location to workaround
# the import issue. Ideally py_library should support something similiar to the
# "include" attribute in cc_library to inject the PYTHON_PATH for all libraries
# that depend on the target.
#
# If you use python protobuf as a third_party library in your bazel managed
# project, please import the whole package to //google/protobuf in your
# project. Otherwise, bazel disallows generated files out of the current
# package, thus we won't be able to copy protobuf runtime files into
# //google/protobuf/.
internal_copied_filegroup(
name = "python_srcs",
srcs = glob(
[
"python/google/protobuf/*.py",
"python/google/protobuf/**/*.py",
],
exclude = [
"python/google/protobuf/internal/*_test.py",
"python/google/protobuf/internal/test_util.py",
],
),
include = "python",
)
py_proto_library(
name = "python_proto",
srcs = WELL_KNOWN_PROTOS,
include = "src",
protoc = ":protoc",
py_extra_srcs = [":python_srcs"],
visibility = ["//visibility:public"],
)
internal_copied_filegroup(
name = "python_test_srcs",
srcs = glob(
[
"python/google/protobuf/internal/*_test.py",
"python/google/protobuf/internal/test_util.py",
],
),
include = "python",
)
py_proto_library(
name = "python_common_test_protos",
srcs = LITE_TEST_PROTOS + TEST_PROTOS,
include = "src",
protoc = ":protoc",
deps = [":python_proto"],
)
py_proto_library(
name = "python_specific_test_protos",
srcs = glob(["python/google/protobuf/internal/*.proto"]),
include = "python",
protoc = ":protoc",
deps = [":python_common_test_protos"],
)
py_library(
name = "python_tests",
srcs = [":python_test_srcs"],
deps = [
":python_common_test_protos",
":python_proto",
":python_specific_test_protos",
],
)
internal_protobuf_py_tests(
name = "python_tests_batch",
modules = [
"descriptor_database_test",
"descriptor_pool_test",
"descriptor_test",
"generator_test",
"json_format_test",
"message_factory_test",
# "message_test", # failed due to testdata path
"proto_builder_test",
# "reflection_test", # failed due to testdata path
"service_reflection_test",
"symbol_database_test",
"text_encoding_test",
# "text_format_test", # failed due to testdata path
"unknown_fields_test",
"wire_format_test",
],
deps = [":python_tests"],
)
# -*- mode: python; -*- PYTHON-PREPROCESSING-REQUIRED # -*- mode: python; -*- PYTHON-PREPROCESSING-REQUIRED
def _gen_dir(ctx): def _GenDir(ctx):
if ctx.attr.include == None: if not ctx.attr.includes:
return "" return ""
if not ctx.attr.include: if not ctx.attr.includes[0]:
return ctx.label.package return ctx.label.package
if not ctx.label.package: if not ctx.label.package:
return ctx.attr.include return ctx.attr.includes[0]
return ctx.label.package + '/' + ctx.attr.include return ctx.label.package + '/' + ctx.attr.includes[0]
def _cc_outs(srcs): def _CcOuts(srcs):
return [s[:-len(".proto")] + ".pb.h" for s in srcs] + \ return [s[:-len(".proto")] + ".pb.h" for s in srcs] + \
[s[:-len(".proto")] + ".pb.cc" for s in srcs] [s[:-len(".proto")] + ".pb.cc" for s in srcs]
def _py_outs(srcs): def _PyOuts(srcs):
return [s[:-len(".proto")] + "_pb2.py" for s in srcs] return [s[:-len(".proto")] + "_pb2.py" for s in srcs]
def _RelativeOutputPath(path, include):
if include == None:
return path
if not path.startswith(include):
fail("Include path %s isn't part of the path %s." % (include, path))
if include and include[-1] != '/':
include = include + '/'
path = path[len(include):]
if not path.startswith(PACKAGE_NAME):
fail("The package %s is not within the path %s" % (PACKAGE_NAME, path))
if not PACKAGE_NAME:
return path
return path[len(PACKAGE_NAME)+1:]
def _proto_gen_impl(ctx): def _proto_gen_impl(ctx):
"""General implementation for generating protos""" """General implementation for generating protos"""
srcs = ctx.files.srcs srcs = ctx.files.srcs
deps = [] deps = []
deps += ctx.files.srcs deps += ctx.files.srcs
gen_dir = _gen_dir(ctx) gen_dir = _GenDir(ctx)
if gen_dir:
import_flags = ["-I" + gen_dir] import_flags = ["-I" + gen_dir]
else:
import_flags = ["-I."]
for dep in ctx.attr.deps: for dep in ctx.attr.deps:
import_flags += dep.proto.import_flags import_flags += dep.proto.import_flags
deps += dep.proto.deps deps += dep.proto.deps
...@@ -53,7 +79,7 @@ _proto_gen = rule( ...@@ -53,7 +79,7 @@ _proto_gen = rule(
attrs = { attrs = {
"srcs": attr.label_list(allow_files = True), "srcs": attr.label_list(allow_files = True),
"deps": attr.label_list(providers = ["proto"]), "deps": attr.label_list(providers = ["proto"]),
"include": attr.string(), "includes": attr.string_list(),
"protoc": attr.label( "protoc": attr.label(
executable = True, executable = True,
single_file = True, single_file = True,
...@@ -73,7 +99,7 @@ def cc_proto_library( ...@@ -73,7 +99,7 @@ def cc_proto_library(
deps=[], deps=[],
cc_libs=[], cc_libs=[],
include=None, include=None,
protoc=":protoc", protoc="//google/protobuf:protoc",
internal_bootstrap_hack=False, internal_bootstrap_hack=False,
**kargs): **kargs):
"""Bazel rule to create a C++ protobuf library from proto source files """Bazel rule to create a C++ protobuf library from proto source files
...@@ -94,6 +120,10 @@ def cc_proto_library( ...@@ -94,6 +120,10 @@ def cc_proto_library(
""" """
includes = []
if include != None:
includes = [include]
if internal_bootstrap_hack: if internal_bootstrap_hack:
# For pre-checked-in generated files, we add the internal_bootstrap_hack # For pre-checked-in generated files, we add the internal_bootstrap_hack
# which will skip the codegen action. # which will skip the codegen action.
...@@ -101,7 +131,7 @@ def cc_proto_library( ...@@ -101,7 +131,7 @@ def cc_proto_library(
name=name + "_genproto", name=name + "_genproto",
srcs=srcs, srcs=srcs,
deps=[s + "_genproto" for s in deps], deps=[s + "_genproto" for s in deps],
include=include, includes=includes,
protoc=protoc, protoc=protoc,
) )
# An empty cc_library to make rule dependency consistent. # An empty cc_library to make rule dependency consistent.
...@@ -110,20 +140,17 @@ def cc_proto_library( ...@@ -110,20 +140,17 @@ def cc_proto_library(
**kargs) **kargs)
return return
outs = _cc_outs(srcs) outs = _CcOuts(srcs)
_proto_gen( _proto_gen(
name=name + "_genproto", name=name + "_genproto",
srcs=srcs, srcs=srcs,
deps=[s + "_genproto" for s in deps], deps=[s + "_genproto" for s in deps],
include=include, includes=includes,
protoc=protoc, protoc=protoc,
gen_cc=1, gen_cc=1,
outs=outs, outs=outs,
) )
includes = []
if include != None:
includes = [include]
native.cc_library( native.cc_library(
name=name, name=name,
...@@ -131,3 +158,111 @@ def cc_proto_library( ...@@ -131,3 +158,111 @@ def cc_proto_library(
deps=cc_libs + deps, deps=cc_libs + deps,
includes=includes, includes=includes,
**kargs) **kargs)
def internal_copied_filegroup(
name,
srcs,
include,
**kargs):
"""Bazel rule to fix sources file to workaround with python path issues.
Args:
name: the name of the internal_copied_filegroup rule, which will be the
name of the generated filegroup.
srcs: the source files to be copied.
include: the expected import root of the source.
**kargs: extra arguments that will be passed into the filegroup.
"""
outs = [_RelativeOutputPath(s, include) for s in srcs]
native.genrule(
name=name+"_genrule",
srcs=srcs,
outs=outs,
cmd=";".join(["cp $(location %s) $(location %s)" % \
(s, _RelativeOutputPath(s, include)) \
for s in srcs]))
native.filegroup(
name=name,
srcs=outs,
**kargs)
def py_proto_library(
name,
srcs=[],
deps=[],
py_libs=[],
py_extra_srcs=[],
include=None,
protoc="//google/protobuf:protoc",
**kargs):
"""Bazel rule to create a Python protobuf library from proto source files
Args:
name: the name of the py_proto_library.
srcs: the .proto files of the py_proto_library.
deps: a list of dependency labels; must be py_proto_library.
py_libs: a list of other py_library targets depended by the generated
py_library.
py_extra_srcs: extra source files that will be added to the output
py_library. This attribute is used for internal bootstrapping.
include: a string indicating the include path of the .proto files.
protoc: the label of the protocol compiler to generate the sources.
**kargs: other keyword arguments that are passed to cc_library.
"""
outs = _PyOuts(srcs)
includes = []
if include != None:
includes = [include]
_proto_gen(
name=name + "_genproto",
srcs=srcs,
deps=[s + "_genproto" for s in deps],
includes=includes,
protoc=protoc,
gen_py=1,
outs=outs,
)
if include != None:
# Copy the output files to the desired location to make the import work.
internal_copied_filegroup_name=name + "_internal_copied_filegroup"
internal_copied_filegroup(
name=internal_copied_filegroup_name,
srcs=outs,
include=include)
outs=[internal_copied_filegroup_name]
native.py_library(
name=name,
srcs=outs+py_extra_srcs,
deps=py_libs+deps,
**kargs)
def internal_protobuf_py_tests(
name,
modules=[],
**kargs):
"""Bazel rules to create batch tests for protobuf internal.
Args:
name: the name of the rule.
modules: a list of modules for tests. The macro will create a py_test for
each of the parameter with the source "google/protobuf/%s.py"
kargs: extra parameters that will be passed into the py_test.
"""
for m in modules:
s = _RelativeOutputPath(
"python/google/protobuf/internal/%s.py" % m, "python")
native.py_test(
name="py_%s" % m,
srcs=[s],
main=s,
**kargs)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment