diff --git a/rust/Android.bp b/rust/Android.bp index ad2bbd86b..8618207a1 100644 --- a/rust/Android.bp +++ b/rust/Android.bp @@ -19,6 +19,7 @@ bootstrap_go_package { "prebuilt.go", "proc_macro.go", "project_json.go", + "protobuf.go", "rust.go", "strip.go", "source_provider.go", @@ -34,6 +35,7 @@ bootstrap_go_package { "coverage_test.go", "library_test.go", "project_json_test.go", + "protobuf_test.go", "rust_test.go", "source_provider_test.go", "test_test.go", diff --git a/rust/androidmk.go b/rust/androidmk.go index 10f10d86f..edae0e63d 100644 --- a/rust/androidmk.go +++ b/rust/androidmk.go @@ -165,14 +165,16 @@ func (sourceProvider *BaseSourceProvider) AndroidMk(ctx AndroidMkContext, ret *a stem, suffix, _ := android.SplitFileExt(file) fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix) fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem) + fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true") }) } func (bindgen *bindgenDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { ctx.SubAndroidMk(ret, bindgen.BaseSourceProvider) - ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) { - fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true") - }) +} + +func (proto *protobufDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { + ctx.SubAndroidMk(ret, proto.BaseSourceProvider) } func (compiler *baseCompiler) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { diff --git a/rust/protobuf.go b/rust/protobuf.go new file mode 100644 index 000000000..897300f19 --- /dev/null +++ b/rust/protobuf.go @@ -0,0 +1,109 @@ +// Copyright 2020 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rust + +import ( + "android/soong/android" +) + +var ( + defaultProtobufFlags = []string{""} +) + +func init() { + android.RegisterModuleType("rust_protobuf", RustProtobufFactory) + android.RegisterModuleType("rust_protobuf_host", RustProtobufHostFactory) +} + +var _ SourceProvider = (*protobufDecorator)(nil) + +type ProtobufProperties struct { + // Path to the proto file that will be used to generate the source + Proto *string `android:"path,arch_variant"` + + // List of additional flags to pass to aprotoc + Proto_flags []string `android:"arch_variant"` +} + +type protobufDecorator struct { + *BaseSourceProvider + + Properties ProtobufProperties +} + +func (proto *protobufDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) android.Path { + var protoFlags android.ProtoFlags + pluginPath := ctx.Config().HostToolPath(ctx, "protoc-gen-rust") + + protoFlags.OutTypeFlag = "--rust_out" + + protoFlags.Flags = append(protoFlags.Flags, " --plugin="+pluginPath.String()) + protoFlags.Flags = append(protoFlags.Flags, defaultProtobufFlags...) + protoFlags.Flags = append(protoFlags.Flags, proto.Properties.Proto_flags...) + + protoFlags.Deps = append(protoFlags.Deps, pluginPath) + + protoFile := android.OptionalPathForModuleSrc(ctx, proto.Properties.Proto) + if !protoFile.Valid() { + ctx.PropertyErrorf("proto", "invalid path to proto file") + } + + outDir := android.PathForModuleOut(ctx) + depFile := android.PathForModuleOut(ctx, proto.BaseSourceProvider.getStem(ctx)+".d") + outputs := android.WritablePaths{android.PathForModuleOut(ctx, proto.BaseSourceProvider.getStem(ctx)+".rs")} + + rule := android.NewRuleBuilder() + android.ProtoRule(ctx, rule, protoFile.Path(), protoFlags, protoFlags.Deps, outDir, depFile, outputs) + rule.Build(pctx, ctx, "protoc_"+protoFile.Path().Rel(), "protoc "+protoFile.Path().Rel()) + + proto.BaseSourceProvider.OutputFile = outputs[0] + return outputs[0] +} + +func (proto *protobufDecorator) SourceProviderProps() []interface{} { + return append(proto.BaseSourceProvider.SourceProviderProps(), &proto.Properties) +} + +func (proto *protobufDecorator) SourceProviderDeps(ctx DepsContext, deps Deps) Deps { + deps = proto.BaseSourceProvider.SourceProviderDeps(ctx, deps) + deps.Rustlibs = append(deps.Rustlibs, "libprotobuf") + return deps +} + +// rust_protobuf generates protobuf rust code from the provided proto file. This uses the protoc-gen-rust plugin for +// protoc. Additional flags to the protoc command can be passed via the proto_flags property. This module type will +// create library variants that can be used as a crate dependency by adding it to the rlibs, dylibs, and rustlibs +// properties of other modules. +func RustProtobufFactory() android.Module { + module, _ := NewRustProtobuf(android.HostAndDeviceSupported) + return module.Init() +} + +// A host-only variant of rust_protobuf. Refer to rust_protobuf for more details. +func RustProtobufHostFactory() android.Module { + module, _ := NewRustProtobuf(android.HostSupported) + return module.Init() +} + +func NewRustProtobuf(hod android.HostOrDeviceSupported) (*Module, *protobufDecorator) { + protobuf := &protobufDecorator{ + BaseSourceProvider: NewSourceProvider(), + Properties: ProtobufProperties{}, + } + + module := NewSourceProviderModule(hod, protobuf, false) + + return module, protobuf +} diff --git a/rust/protobuf_test.go b/rust/protobuf_test.go new file mode 100644 index 000000000..a9dbf397d --- /dev/null +++ b/rust/protobuf_test.go @@ -0,0 +1,39 @@ +// Copyright 2020 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rust + +import ( + "android/soong/android" + "testing" +) + +func TestRustProtobuf(t *testing.T) { + ctx := testRust(t, ` + rust_protobuf { + name: "librust_proto", + proto: "buf.proto", + crate_name: "rust_proto", + source_stem: "buf", + } + `) + // Check that there's a rule to generate the expected output + _ = ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_dylib").Output("buf.rs") + + // Check that libprotobuf is added as a dependency. + librust_proto := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_dylib").Module().(*Module) + if !android.InList("libprotobuf", librust_proto.Properties.AndroidMkDylibs) { + t.Errorf("libprotobuf dependency missing for rust_protobuf (dependency missing from AndroidMkDylibs)") + } +} diff --git a/rust/rust_test.go b/rust/rust_test.go index f1a08a805..89ce35919 100644 --- a/rust/rust_test.go +++ b/rust/rust_test.go @@ -62,6 +62,7 @@ func testConfig(bp string) android.Config { "foo.c": nil, "src/bar.rs": nil, "src/any.h": nil, + "buf.proto": nil, "liby.so": nil, "libz.so": nil, } diff --git a/rust/testing.go b/rust/testing.go index 80e414871..0144c8218 100644 --- a/rust/testing.go +++ b/rust/testing.go @@ -91,6 +91,12 @@ func GatherRequiredDepsForTest() string { host_supported: true, native_coverage: false, } + rust_library { + name: "libprotobuf", + crate_name: "protobuf", + srcs: ["foo.rs"], + host_supported: true, + } ` + cc.GatherRequiredDepsForTest(android.NoOsType) return bp @@ -120,6 +126,8 @@ func CreateTestContext() *android.TestContext { ctx.RegisterModuleType("rust_ffi_host_shared", RustFFISharedHostFactory) ctx.RegisterModuleType("rust_ffi_host_static", RustFFIStaticHostFactory) ctx.RegisterModuleType("rust_proc_macro", ProcMacroFactory) + ctx.RegisterModuleType("rust_protobuf", RustProtobufFactory) + ctx.RegisterModuleType("rust_protobuf_host", RustProtobufHostFactory) ctx.RegisterModuleType("rust_prebuilt_library", PrebuiltLibraryFactory) ctx.RegisterModuleType("rust_prebuilt_dylib", PrebuiltDylibFactory) ctx.RegisterModuleType("rust_prebuilt_rlib", PrebuiltRlibFactory)