parent
92509cc3b2
commit
e18541a9dd
3 changed files with 258 additions and 0 deletions
@ -0,0 +1,116 @@ |
||||
|
||||
load("@bazel_skylib//lib:paths.bzl", "paths") |
||||
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain") |
||||
|
||||
# copybara:strip_for_google3_begin |
||||
load("@bazel_skylib//lib:versions.bzl", "versions") |
||||
load("@bazel_version//:bazel_version.bzl", "bazel_version") |
||||
# copybara:strip_end |
||||
|
||||
# Generic support code ######################################################### |
||||
|
||||
_is_bazel = not hasattr(native, "genmpm") |
||||
|
||||
def _get_real_short_path(file): |
||||
# For some reason, files from other archives have short paths that look like: |
||||
# ../com_google_protobuf/google/protobuf/descriptor.proto |
||||
short_path = file.short_path |
||||
if short_path.startswith("../"): |
||||
second_slash = short_path.index("/", 3) |
||||
short_path = short_path[second_slash + 1:] |
||||
# Sometimes it has another few prefixes like: |
||||
# _virtual_imports/any_proto/google/protobuf/any.proto |
||||
# We want just google/protobuf/any.proto. |
||||
if short_path.startswith("_virtual_imports"): |
||||
short_path = short_path.split("/", 2)[-1] |
||||
return short_path |
||||
|
||||
def _get_real_root(file): |
||||
real_short_path = _get_real_short_path(file) |
||||
return file.path[:-len(real_short_path) - 1] |
||||
|
||||
def _generate_output_file(ctx, src, extension): |
||||
real_short_path = _get_real_short_path(src) |
||||
real_short_path = paths.relativize(real_short_path, ctx.label.package) |
||||
output_filename = paths.replace_extension(real_short_path, extension) |
||||
ret = ctx.actions.declare_file(output_filename) |
||||
return ret |
||||
|
||||
# upb_proto_library / upb_proto_reflection_library shared code ################# |
||||
|
||||
_LuaFiles = provider(fields = ["files"]) |
||||
|
||||
def _compile_upb_protos(ctx, proto_info, proto_sources): |
||||
files = [_generate_output_file(ctx, name, "_pb.lua") for name in proto_sources] |
||||
transitive_sets = proto_info.transitive_descriptor_sets.to_list() |
||||
ctx.actions.run( |
||||
inputs = depset( |
||||
direct = [proto_info.direct_descriptor_set], |
||||
transitive = [proto_info.transitive_descriptor_sets], |
||||
), |
||||
tools = [ctx.executable._upbc], |
||||
outputs = files, |
||||
executable = ctx.executable._protoc, |
||||
arguments = [ |
||||
"--lua_out=" + _get_real_root(files[0]), |
||||
"--plugin=protoc-gen-lua=" + ctx.executable._upbc.path, |
||||
"--descriptor_set_in=" + ctx.configuration.host_path_separator.join([f.path for f in transitive_sets]), |
||||
] + |
||||
[_get_real_short_path(file) for file in proto_sources], |
||||
progress_message = "Generating Lua protos for :" + ctx.label.name, |
||||
) |
||||
return files |
||||
|
||||
def _lua_proto_rule_impl(ctx): |
||||
if len(ctx.attr.deps) != 1: |
||||
fail("only one deps dependency allowed.") |
||||
dep = ctx.attr.deps[0] |
||||
if _LuaFiles not in dep: |
||||
fail("proto_library rule must generate _LuaFiles (aspect should have handled this).") |
||||
files = dep[_LuaFiles].files |
||||
print(files) |
||||
return [ |
||||
DefaultInfo( |
||||
files = files, |
||||
data_runfiles = ctx.runfiles(files = files.to_list())), |
||||
] |
||||
|
||||
def _lua_proto_library_aspect_impl(target, ctx): |
||||
proto_info = target[ProtoInfo] |
||||
files = _compile_upb_protos(ctx, proto_info, proto_info.direct_sources) |
||||
deps = ctx.rule.attr.deps |
||||
transitive = [dep[_LuaFiles].files for dep in deps if _LuaFiles in dep] |
||||
return [_LuaFiles(files = depset(direct = files, transitive = transitive))] |
||||
|
||||
# lua_proto_library() ########################################################## |
||||
|
||||
_lua_proto_library_aspect = aspect( |
||||
attrs = { |
||||
"_upbc": attr.label( |
||||
executable = True, |
||||
cfg = "host", |
||||
default = "//:protoc-gen-lua", |
||||
), |
||||
"_protoc": attr.label( |
||||
executable = True, |
||||
cfg = "host", |
||||
default = "@com_google_protobuf//:protoc", |
||||
), |
||||
}, |
||||
implementation = _lua_proto_library_aspect_impl, |
||||
provides = [_LuaFiles], |
||||
attr_aspects = ["deps"], |
||||
fragments = ["cpp"], |
||||
) |
||||
|
||||
lua_proto_library = rule( |
||||
output_to_genfiles = True, |
||||
implementation = _lua_proto_rule_impl, |
||||
attrs = { |
||||
"deps": attr.label_list( |
||||
aspects = [_lua_proto_library_aspect], |
||||
allow_rules = ["proto_library"], |
||||
providers = [ProtoInfo], |
||||
), |
||||
}, |
||||
) |
@ -0,0 +1,30 @@ |
||||
|
||||
local upb = require("lupb") |
||||
|
||||
upb.generated_pool = upb.SymbolTable() |
||||
|
||||
local module_metatable = { |
||||
__index = function(t, k) |
||||
local package = t._filedef:package() |
||||
if package then |
||||
k = package .. "." .. k |
||||
end |
||||
local pool = upb.generated_pool |
||||
local def = pool:lookup_msg(k) or pool:lookup_enum(k) |
||||
local v = nil |
||||
if def and def:file():name() == t._filedef:name() then |
||||
v = def |
||||
t[k] = v |
||||
end |
||||
return v |
||||
end |
||||
} |
||||
|
||||
function upb._generated_module(desc_string) |
||||
local file = upb.generated_pool:add_file(desc_string) |
||||
local module = {_filedef = file} |
||||
setmetatable(module, module_metatable) |
||||
return module |
||||
end |
||||
|
||||
return upb |
@ -0,0 +1,112 @@ |
||||
|
||||
#include "absl/strings/string_view.h" |
||||
#include "absl/strings/substitute.h" |
||||
#include "absl/strings/str_replace.h" |
||||
#include "google/protobuf/compiler/code_generator.h" |
||||
#include "google/protobuf/descriptor.h" |
||||
#include "google/protobuf/descriptor.pb.h" |
||||
#include <google/protobuf/compiler/plugin.h> |
||||
#include <google/protobuf/io/printer.h> |
||||
|
||||
namespace protoc = ::google::protobuf::compiler; |
||||
namespace protobuf = ::google::protobuf; |
||||
|
||||
class LuaGenerator : public protoc::CodeGenerator { |
||||
bool Generate(const protobuf::FileDescriptor* file, |
||||
const std::string& parameter, protoc::GeneratorContext* context, |
||||
std::string* error) const override; |
||||
|
||||
}; |
||||
|
||||
static std::string StripExtension(absl::string_view fname) { |
||||
size_t lastdot = fname.find_last_of("."); |
||||
if (lastdot == std::string::npos) { |
||||
return std::string(fname); |
||||
} |
||||
return std::string(fname.substr(0, lastdot)); |
||||
} |
||||
|
||||
static std::string Filename(const protobuf::FileDescriptor* file) { |
||||
return StripExtension(file->name()) + "_pb.lua"; |
||||
} |
||||
|
||||
static std::string ModuleName(const protobuf::FileDescriptor* file) { |
||||
std::string ret = StripExtension(file->name()) + "_pb"; |
||||
return absl::StrReplaceAll(ret, {{"/", "."}}); |
||||
} |
||||
|
||||
static void PrintHexDigit(char digit, protobuf::io::Printer* printer) { |
||||
char text; |
||||
if (digit < 10) { |
||||
text = '0' + digit; |
||||
} else { |
||||
text = 'A' + (digit - 10); |
||||
} |
||||
printer->WriteRaw(&text, 1); |
||||
} |
||||
|
||||
static void PrintString(int max_cols, absl::string_view* str, |
||||
protobuf::io::Printer* printer) { |
||||
printer->Print("\'"); |
||||
while (max_cols > 0 && !str->empty()) { |
||||
char ch = (*str)[0]; |
||||
if (ch == '\\') { |
||||
printer->PrintRaw("\\\\"); |
||||
max_cols--; |
||||
} else if (ch == '\'') { |
||||
printer->PrintRaw("\\'"); |
||||
max_cols--; |
||||
} else if (isprint(ch)) { |
||||
printer->WriteRaw(&ch, 1); |
||||
max_cols--; |
||||
} else { |
||||
unsigned char byte = ch; |
||||
printer->PrintRaw("\\x"); |
||||
PrintHexDigit(byte >> 4, printer); |
||||
PrintHexDigit(byte & 15, printer); |
||||
max_cols -= 4; |
||||
} |
||||
str->remove_prefix(1); |
||||
} |
||||
printer->Print("\'"); |
||||
} |
||||
|
||||
bool LuaGenerator::Generate( |
||||
const protobuf::FileDescriptor* file, |
||||
const std::string& parameter, |
||||
protoc::GeneratorContext* context, |
||||
std::string* error) const { |
||||
std::string filename = Filename(file); |
||||
protobuf::io::ZeroCopyOutputStream* out = context->Open(filename); |
||||
protobuf::io::Printer printer(out, '$'); |
||||
|
||||
for (int i = 0; i < file->dependency_count(); i++) { |
||||
const protobuf::FileDescriptor* dep = file->dependency(i); |
||||
printer.Print("require('$name$')\n", "name", ModuleName(dep)); |
||||
} |
||||
|
||||
printer.Print("local upb = require('upb')\n"); |
||||
|
||||
protobuf::FileDescriptorProto file_proto; |
||||
file->CopyTo(&file_proto); |
||||
std::string file_data; |
||||
file_proto.SerializeToString(&file_data); |
||||
|
||||
printer.Print("local descriptor = table.concat({\n"); |
||||
absl::string_view data(file_data); |
||||
while (!data.empty()) { |
||||
printer.Print(" "); |
||||
PrintString(72, &data, &printer); |
||||
printer.Print(",\n"); |
||||
} |
||||
printer.Print("})\n"); |
||||
|
||||
printer.Print("return upb._generated_module(descriptor)\n"); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
int main(int argc, char** argv) { |
||||
LuaGenerator generator; |
||||
return google::protobuf::compiler::PluginMain(argc, argv, &generator); |
||||
} |
Loading…
Reference in new issue