diff --git a/Android.bp b/Android.bp index 0e57c1228..ae31a60a8 100644 --- a/Android.bp +++ b/Android.bp @@ -209,6 +209,7 @@ bootstrap_go_package { "java/builder.go", "java/gen.go", "java/java.go", + "java/proto.go", "java/resources.go", ], testSrcs: [ diff --git a/android/proto.go b/android/proto.go index 9bb9cfbb5..1c70656e2 100644 --- a/android/proto.go +++ b/android/proto.go @@ -14,22 +14,6 @@ package android -import ( - "github.com/google/blueprint" -) - -func init() { - pctx.HostBinToolVariable("protocCmd", "aprotoc") -} - -var ( - proto = pctx.AndroidStaticRule("protoc", - blueprint.RuleParams{ - Command: "$protocCmd $protoOut=$protoOutFlags:$outDir $protoFlags $in", - CommandDeps: []string{"$protocCmd"}, - }, "protoFlags", "protoOut", "protoOutFlags", "outDir") -) - // TODO(ccross): protos are often used to communicate between multiple modules. If the only // way to convert a proto to source is to reference it as a source file, and external modules cannot // reference source files in other modules, then every module that owns a proto file will need to @@ -38,30 +22,6 @@ var ( // and then external modules could depend on the proto module but use their own settings to // generate the source. -func GenProto(ctx ModuleContext, protoFile Path, - protoFlags string, protoOut, protoOutFlags string, extensions []string) WritablePaths { - - var outFiles WritablePaths - for _, ext := range extensions { - outFiles = append(outFiles, GenPathWithExt(ctx, "proto", protoFile, ext)) - } - - ctx.ModuleBuild(pctx, ModuleBuildParams{ - Rule: proto, - Description: "protoc " + protoFile.Rel(), - Outputs: outFiles, - Input: protoFile, - Args: map[string]string{ - "outDir": ProtoDir(ctx).String(), - "protoOut": protoOut, - "protoOutFlags": protoOutFlags, - "protoFlags": protoFlags, - }, - }) - - return outFiles -} - func ProtoFlags(ctx ModuleContext, p *ProtoProperties) []string { var protoFlags []string if len(p.Proto.Local_include_dirs) > 0 { diff --git a/cc/gen.go b/cc/gen.go index 9fc14c50c..2280e0f77 100644 --- a/cc/gen.go +++ b/cc/gen.go @@ -153,10 +153,9 @@ func genSources(ctx android.ModuleContext, srcFiles android.Paths, srcFiles[i] = cppFile genLex(ctx, srcFile, cppFile) case ".proto": - protoFiles := android.GenProto(ctx, srcFile, buildFlags.protoFlags, - "--cpp_out", "", []string{"pb.cc", "pb.h"}) - srcFiles[i] = protoFiles[0] - deps = append(deps, protoFiles[1]) + ccFile, headerFile := genProto(ctx, srcFile, buildFlags.protoFlags) + srcFiles[i] = ccFile + deps = append(deps, headerFile) case ".aidl": cppFile := android.GenPathWithExt(ctx, "aidl", srcFile, "cpp") srcFiles[i] = cppFile diff --git a/cc/proto.go b/cc/proto.go index 6049d44ad..a01951fe6 100644 --- a/cc/proto.go +++ b/cc/proto.go @@ -15,11 +15,46 @@ package cc import ( + "github.com/google/blueprint" "github.com/google/blueprint/proptools" "android/soong/android" ) +func init() { + pctx.HostBinToolVariable("protocCmd", "aprotoc") +} + +var ( + proto = pctx.AndroidStaticRule("protoc", + blueprint.RuleParams{ + Command: "$protocCmd --cpp_out=$outDir $protoFlags $in", + CommandDeps: []string{"$protocCmd"}, + }, "protoFlags", "outDir") +) + +// genProto creates a rule to convert a .proto file to generated .pb.cc and .pb.h files and returns +// the paths to the generated files. +func genProto(ctx android.ModuleContext, protoFile android.Path, + protoFlags string) (ccFile, headerFile android.WritablePath) { + + ccFile = android.GenPathWithExt(ctx, "proto", protoFile, "pb.cc") + headerFile = android.GenPathWithExt(ctx, "proto", protoFile, "pb.h") + + ctx.ModuleBuild(pctx, android.ModuleBuildParams{ + Rule: proto, + Description: "protoc " + protoFile.Rel(), + Outputs: android.WritablePaths{ccFile, headerFile}, + Input: protoFile, + Args: map[string]string{ + "outDir": android.ProtoDir(ctx).String(), + "protoFlags": protoFlags, + }, + }) + + return ccFile, headerFile +} + func protoDeps(ctx BaseModuleContext, deps Deps, p *android.ProtoProperties, static bool) Deps { var lib string diff --git a/java/builder.go b/java/builder.go index 95345d40f..b924d6540 100644 --- a/java/builder.go +++ b/java/builder.go @@ -127,6 +127,9 @@ type javaBuilderFlags struct { desugarFlags string aidlFlags string javaVersion string + + protoFlags string + protoOutFlag string } func TransformJavaToClasses(ctx android.ModuleContext, srcFiles, srcFileLists android.Paths, @@ -136,7 +139,10 @@ func TransformJavaToClasses(ctx android.ModuleContext, srcFiles, srcFileLists an annoDir := android.PathForModuleOut(ctx, "anno") classJar := android.PathForModuleOut(ctx, "classes-compiled.jar") - javacFlags := flags.javacFlags + android.JoinWithPrefix(srcFileLists.Strings(), "@") + javacFlags := flags.javacFlags + if len(srcFileLists) > 0 { + javacFlags += " " + android.JoinWithPrefix(srcFileLists.Strings(), "@") + } deps = append(deps, srcFileLists...) deps = append(deps, flags.bootClasspath...) @@ -161,8 +167,8 @@ func TransformJavaToClasses(ctx android.ModuleContext, srcFiles, srcFileLists an return classJar } -func RunErrorProne(ctx android.ModuleContext, srcFiles android.Paths, srcFileLists android.Paths, - flags javaBuilderFlags, deps android.Paths) android.Path { +func RunErrorProne(ctx android.ModuleContext, srcFiles, srcFileLists android.Paths, + flags javaBuilderFlags) android.Path { if config.ErrorProneJar == "" { ctx.ModuleErrorf("cannot build with Error Prone, missing external/error_prone?") @@ -173,7 +179,12 @@ func RunErrorProne(ctx android.ModuleContext, srcFiles android.Paths, srcFileLis annoDir := android.PathForModuleOut(ctx, "anno-errorprone") classFileList := android.PathForModuleOut(ctx, "classes-errorprone.list") - javacFlags := flags.javacFlags + android.JoinWithPrefix(srcFileLists.Strings(), "@") + javacFlags := flags.javacFlags + if len(srcFileLists) > 0 { + javacFlags += " " + android.JoinWithPrefix(srcFileLists.Strings(), "@") + } + + var deps android.Paths deps = append(deps, srcFileLists...) deps = append(deps, flags.bootClasspath...) diff --git a/java/gen.go b/java/gen.go index e473859f6..e55be9167 100644 --- a/java/gen.go +++ b/java/gen.go @@ -85,21 +85,37 @@ func genLogtags(ctx android.ModuleContext, logtagsFile android.Path) android.Pat } func (j *Module) genSources(ctx android.ModuleContext, srcFiles android.Paths, - flags javaBuilderFlags) android.Paths { + flags javaBuilderFlags) (android.Paths, android.Paths) { - for i, srcFile := range srcFiles { + var protoFiles android.Paths + outSrcFiles := make(android.Paths, 0, len(srcFiles)) + + for _, srcFile := range srcFiles { switch srcFile.Ext() { case ".aidl": javaFile := genAidl(ctx, srcFile, flags.aidlFlags) - srcFiles[i] = javaFile + outSrcFiles = append(outSrcFiles, javaFile) case ".logtags": j.logtagsSrcs = append(j.logtagsSrcs, srcFile) javaFile := genLogtags(ctx, srcFile) - srcFiles[i] = javaFile + outSrcFiles = append(outSrcFiles, javaFile) + case ".proto": + protoFiles = append(protoFiles, srcFile) + default: + outSrcFiles = append(outSrcFiles, srcFile) } } - return srcFiles + var outSrcFileLists android.Paths + + if len(protoFiles) > 0 { + protoFileList := genProto(ctx, protoFiles, + flags.protoFlags, flags.protoOutFlag, "") + + outSrcFileLists = append(outSrcFileLists, protoFileList) + } + + return outSrcFiles, outSrcFileLists } func LogtagsSingleton() blueprint.Singleton { diff --git a/java/java.go b/java/java.go index d8bc0c2cb..eb9480619 100644 --- a/java/java.go +++ b/java/java.go @@ -49,7 +49,6 @@ func init() { // TODO: // Autogenerated files: -// Proto // Renderscript // Post-jar passes: // Proguard @@ -145,6 +144,7 @@ type Module struct { android.DefaultableModuleBase properties CompilerProperties + protoProperties android.ProtoProperties deviceProperties CompilerDeviceProperties // output file suitable for inserting into the classpath of another compile @@ -296,6 +296,24 @@ func (j *Module) deps(ctx android.BottomUpMutatorContext) { android.ExtractSourcesDeps(ctx, j.properties.Srcs) android.ExtractSourcesDeps(ctx, j.properties.Java_resources) + + if j.hasSrcExt(".proto") { + protoDeps(ctx, &j.protoProperties) + } +} + +func hasSrcExt(srcs []string, ext string) bool { + for _, src := range srcs { + if filepath.Ext(src) == ext { + return true + } + } + + return false +} + +func (j *Module) hasSrcExt(ext string) bool { + return hasSrcExt(j.properties.Srcs, ext) } func (j *Module) aidlFlags(ctx android.ModuleContext, aidlPreprocess android.OptionalPath, @@ -416,7 +434,15 @@ func (j *Module) compile(ctx android.ModuleContext) { srcFiles := ctx.ExpandSources(j.properties.Srcs, j.properties.Exclude_srcs) - srcFiles = j.genSources(ctx, srcFiles, flags) + if hasSrcExt(srcFiles.Strings(), ".proto") { + flags = protoFlags(ctx, &j.protoProperties, flags) + } + + var srcFileLists android.Paths + + srcFiles, srcFileLists = j.genSources(ctx, srcFiles, flags) + + srcFileLists = append(srcFileLists, deps.srcFileLists...) ctx.VisitDirectDeps(func(module blueprint.Module) { if gen, ok := module.(genrule.SourceFileGenerator); ok { @@ -424,7 +450,7 @@ func (j *Module) compile(ctx android.ModuleContext) { } }) - deps.srcFileLists = append(deps.srcFileLists, j.ExtraSrcLists...) + srcFileLists = append(srcFileLists, j.ExtraSrcLists...) var jars android.Paths @@ -436,12 +462,12 @@ func (j *Module) compile(ctx android.ModuleContext) { // a rebuild when error-prone is turned off). // TODO(ccross): Once we always compile with javac9 we may be able to conditionally // enable error-prone without affecting the output class files. - errorprone := RunErrorProne(ctx, srcFiles, deps.srcFileLists, flags, nil) + errorprone := RunErrorProne(ctx, srcFiles, srcFileLists, flags) extraJarDeps = append(extraJarDeps, errorprone) } // Compile java sources into .class files - classes := TransformJavaToClasses(ctx, srcFiles, deps.srcFileLists, flags, extraJarDeps) + classes := TransformJavaToClasses(ctx, srcFiles, srcFileLists, flags, extraJarDeps) if ctx.Failed() { return } @@ -629,7 +655,8 @@ func LibraryFactory(installable bool) func() android.Module { module.AddProperties( &module.Module.properties, - &module.Module.deviceProperties) + &module.Module.deviceProperties, + &module.Module.protoProperties) InitJavaModule(module, android.HostAndDeviceSupported) return module @@ -639,7 +666,9 @@ func LibraryFactory(installable bool) func() android.Module { func LibraryHostFactory() android.Module { module := &Library{} - module.AddProperties(&module.Module.properties) + module.AddProperties( + &module.Module.properties, + &module.Module.protoProperties) InitJavaModule(module, android.HostSupported) return module @@ -685,6 +714,7 @@ func BinaryFactory() android.Module { module.AddProperties( &module.Module.properties, &module.Module.deviceProperties, + &module.Module.protoProperties, &module.binaryProperties) InitJavaModule(module, android.HostAndDeviceSupported) @@ -697,6 +727,7 @@ func BinaryHostFactory() android.Module { module.AddProperties( &module.Module.properties, &module.Module.deviceProperties, + &module.Module.protoProperties, &module.binaryProperties) InitJavaModule(module, android.HostSupported) diff --git a/java/proto.go b/java/proto.go new file mode 100644 index 000000000..324868ac0 --- /dev/null +++ b/java/proto.go @@ -0,0 +1,98 @@ +// Copyright 2017 Google Inc. All rights reserved. +// +// 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 java + +import ( + "github.com/google/blueprint" + "github.com/google/blueprint/proptools" + + "android/soong/android" +) + +func init() { + pctx.HostBinToolVariable("protocCmd", "aprotoc") +} + +var ( + proto = pctx.AndroidStaticRule("protoc", + blueprint.RuleParams{ + Command: `rm -rf $outDir && mkdir -p $outDir && ` + + `$protocCmd $protoOut=$protoOutFlags:$outDir $protoFlags $in && ` + + `find $outDir -name "*.java" > $out`, + CommandDeps: []string{"$protocCmd"}, + }, "protoFlags", "protoOut", "protoOutFlags", "outDir") +) + +func genProto(ctx android.ModuleContext, protoFiles android.Paths, + protoFlags string, protoOut, protoOutFlags string) android.WritablePath { + + protoFileList := android.PathForModuleGen(ctx, "proto.filelist") + + ctx.ModuleBuild(pctx, android.ModuleBuildParams{ + Rule: proto, + Description: "protoc " + protoFiles[0].Rel(), + Output: protoFileList, + Inputs: protoFiles, + Args: map[string]string{ + "outDir": android.ProtoDir(ctx).String(), + "protoOut": protoOut, + "protoOutFlags": protoOutFlags, + "protoFlags": protoFlags, + }, + }) + + return protoFileList +} + +func protoDeps(ctx android.BottomUpMutatorContext, p *android.ProtoProperties) { + switch proptools.String(p.Proto.Type) { + case "micro": + ctx.AddDependency(ctx.Module(), staticLibTag, "libprotobuf-java-micro") + case "nano": + ctx.AddDependency(ctx.Module(), staticLibTag, "libprotobuf-java-nano") + case "stream": + // TODO(ccross): add dependency on protoc-gen-java-stream binary + ctx.PropertyErrorf("proto.type", `"stream" not supported yet`) + // No library for stream protobufs + case "lite", "": + ctx.AddDependency(ctx.Module(), staticLibTag, "libprotobuf-java-lite") + case "full": + if ctx.Host() { + ctx.AddDependency(ctx.Module(), staticLibTag, "libprotobuf-java-full") + } else { + ctx.PropertyErrorf("proto.type", "full java protos only supported on the host") + } + default: + ctx.PropertyErrorf("proto.type", "unknown proto type %q", + proptools.String(p.Proto.Type)) + } +} + +func protoFlags(ctx android.ModuleContext, p *android.ProtoProperties, flags javaBuilderFlags) javaBuilderFlags { + switch proptools.String(p.Proto.Type) { + case "micro": + flags.protoOutFlag = "--javamicro_out" + case "nano": + flags.protoOutFlag = "--javanano_out" + case "stream": + flags.protoOutFlag = "--javastream_out" + case "lite", "": + flags.protoOutFlag = "--java_out" + default: + ctx.PropertyErrorf("proto.type", "unknown proto type %q", + proptools.String(p.Proto.Type)) + } + return flags +}