Merge "Initial kotlin support"
am: c37e1018c7
Change-Id: If90452afd9643b37e40687b73190d3e53388b134
This commit is contained in:
@@ -229,6 +229,7 @@ bootstrap_go_package {
|
|||||||
srcs: [
|
srcs: [
|
||||||
"java/config/config.go",
|
"java/config/config.go",
|
||||||
"java/config/error_prone.go",
|
"java/config/error_prone.go",
|
||||||
|
"java/config/kotlin.go",
|
||||||
"java/config/makevars.go",
|
"java/config/makevars.go",
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
@@ -303,6 +303,39 @@ outer:
|
|||||||
return list[:k]
|
return list[:k]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HasExt returns true of any of the paths have extension ext, otherwise false
|
||||||
|
func (p Paths) HasExt(ext string) bool {
|
||||||
|
for _, path := range p {
|
||||||
|
if path.Ext() == ext {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// FilterByExt returns the subset of the paths that have extension ext
|
||||||
|
func (p Paths) FilterByExt(ext string) Paths {
|
||||||
|
ret := make(Paths, 0, len(p))
|
||||||
|
for _, path := range p {
|
||||||
|
if path.Ext() == ext {
|
||||||
|
ret = append(ret, path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// FilterOutByExt returns the subset of the paths that do not have extension ext
|
||||||
|
func (p Paths) FilterOutByExt(ext string) Paths {
|
||||||
|
ret := make(Paths, 0, len(p))
|
||||||
|
for _, path := range p {
|
||||||
|
if path.Ext() != ext {
|
||||||
|
ret = append(ret, path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
// WritablePaths is a slice of WritablePaths, used for multiple outputs.
|
// WritablePaths is a slice of WritablePaths, used for multiple outputs.
|
||||||
type WritablePaths []WritablePath
|
type WritablePaths []WritablePath
|
||||||
|
|
||||||
|
@@ -50,6 +50,22 @@ var (
|
|||||||
},
|
},
|
||||||
"javacFlags", "sourcepath", "bootClasspath", "classpath", "outDir", "annoDir", "javaVersion")
|
"javacFlags", "sourcepath", "bootClasspath", "classpath", "outDir", "annoDir", "javaVersion")
|
||||||
|
|
||||||
|
kotlinc = pctx.AndroidGomaStaticRule("kotlinc",
|
||||||
|
blueprint.RuleParams{
|
||||||
|
// TODO(ccross): kotlinc doesn't support @ file for arguments, which will limit the
|
||||||
|
// maximum number of input files, especially on darwin.
|
||||||
|
Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
|
||||||
|
`${config.KotlincCmd} $classpath $kotlincFlags ` +
|
||||||
|
`-jvm-target $javaVersion -d $outDir $in && ` +
|
||||||
|
`${config.SoongZipCmd} -jar -o $out -C $outDir -D $outDir`,
|
||||||
|
CommandDeps: []string{
|
||||||
|
"${config.KotlincCmd}",
|
||||||
|
"${config.KotlinCompilerJar}",
|
||||||
|
"${config.SoongZipCmd}",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"kotlincFlags", "classpath", "outDir", "javaVersion")
|
||||||
|
|
||||||
errorprone = pctx.AndroidStaticRule("errorprone",
|
errorprone = pctx.AndroidStaticRule("errorprone",
|
||||||
blueprint.RuleParams{
|
blueprint.RuleParams{
|
||||||
Command: `rm -rf "$outDir" "$annoDir" && mkdir -p "$outDir" "$annoDir" && ` +
|
Command: `rm -rf "$outDir" "$annoDir" && mkdir -p "$outDir" "$annoDir" && ` +
|
||||||
@@ -131,10 +147,36 @@ type javaBuilderFlags struct {
|
|||||||
aidlFlags string
|
aidlFlags string
|
||||||
javaVersion string
|
javaVersion string
|
||||||
|
|
||||||
|
kotlincFlags string
|
||||||
|
kotlincClasspath classpath
|
||||||
|
|
||||||
protoFlags string
|
protoFlags string
|
||||||
protoOutFlag string
|
protoOutFlag string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TransformKotlinToClasses(ctx android.ModuleContext, outputFile android.WritablePath,
|
||||||
|
srcFiles android.Paths, srcJars classpath,
|
||||||
|
flags javaBuilderFlags) {
|
||||||
|
|
||||||
|
classDir := android.PathForModuleOut(ctx, "classes-kt")
|
||||||
|
|
||||||
|
inputs := append(android.Paths(nil), srcFiles...)
|
||||||
|
inputs = append(inputs, srcJars...)
|
||||||
|
|
||||||
|
ctx.ModuleBuild(pctx, android.ModuleBuildParams{
|
||||||
|
Rule: kotlinc,
|
||||||
|
Description: "kotlinc",
|
||||||
|
Output: outputFile,
|
||||||
|
Inputs: inputs,
|
||||||
|
Args: map[string]string{
|
||||||
|
"classpath": flags.kotlincClasspath.JavaClasspath(),
|
||||||
|
"kotlincFlags": flags.kotlincFlags,
|
||||||
|
"outDir": classDir.String(),
|
||||||
|
"javaVersion": flags.javaVersion,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TransformJavaToClasses(ctx android.ModuleContext, outputFile android.WritablePath,
|
func TransformJavaToClasses(ctx android.ModuleContext, outputFile android.WritablePath,
|
||||||
srcFiles android.Paths, srcJars classpath,
|
srcFiles android.Paths, srcJars classpath,
|
||||||
flags javaBuilderFlags, deps android.Paths) {
|
flags javaBuilderFlags, deps android.Paths) {
|
||||||
|
25
java/config/kotlin.go
Normal file
25
java/config/kotlin.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// 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 config
|
||||||
|
|
||||||
|
var (
|
||||||
|
KotlinStdlibJar = "external/kotlinc/lib/kotlin-stdlib.jar"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
pctx.SourcePathVariable("KotlincCmd", "external/kotlinc/bin/kotlinc")
|
||||||
|
pctx.SourcePathVariable("KotlinCompilerJar", "external/kotlinc/lib/kotlin-compiler.jar")
|
||||||
|
pctx.SourcePathVariable("KotlinStdlibJar", KotlinStdlibJar)
|
||||||
|
}
|
42
java/java.go
42
java/java.go
@@ -198,6 +198,7 @@ var (
|
|||||||
bootClasspathTag = dependencyTag{name: "bootclasspath"}
|
bootClasspathTag = dependencyTag{name: "bootclasspath"}
|
||||||
systemModulesTag = dependencyTag{name: "system modules"}
|
systemModulesTag = dependencyTag{name: "system modules"}
|
||||||
frameworkResTag = dependencyTag{name: "framework-res"}
|
frameworkResTag = dependencyTag{name: "framework-res"}
|
||||||
|
kotlinStdlibTag = dependencyTag{name: "kotlin-stdlib"}
|
||||||
)
|
)
|
||||||
|
|
||||||
type sdkDep struct {
|
type sdkDep struct {
|
||||||
@@ -326,6 +327,12 @@ func (j *Module) deps(ctx android.BottomUpMutatorContext) {
|
|||||||
if j.hasSrcExt(".proto") {
|
if j.hasSrcExt(".proto") {
|
||||||
protoDeps(ctx, &j.protoProperties)
|
protoDeps(ctx, &j.protoProperties)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if j.hasSrcExt(".kt") {
|
||||||
|
// TODO(ccross): move this to a mutator pass that can tell if generated sources contain
|
||||||
|
// Kotlin files
|
||||||
|
ctx.AddDependency(ctx.Module(), kotlinStdlibTag, "kotlin-stdlib")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func hasSrcExt(srcs []string, ext string) bool {
|
func hasSrcExt(srcs []string, ext string) bool {
|
||||||
@@ -373,6 +380,7 @@ type deps struct {
|
|||||||
srcJars android.Paths
|
srcJars android.Paths
|
||||||
systemModules android.Path
|
systemModules android.Path
|
||||||
aidlPreprocess android.OptionalPath
|
aidlPreprocess android.OptionalPath
|
||||||
|
kotlinStdlib android.Paths
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *Module) collectDeps(ctx android.ModuleContext) deps {
|
func (j *Module) collectDeps(ctx android.ModuleContext) deps {
|
||||||
@@ -424,6 +432,8 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps {
|
|||||||
// generated by framework-res.apk
|
// generated by framework-res.apk
|
||||||
// TODO(ccross): aapt java files should go in a src jar
|
// TODO(ccross): aapt java files should go in a src jar
|
||||||
}
|
}
|
||||||
|
case kotlinStdlibTag:
|
||||||
|
deps.kotlinStdlib = dep.ClasspathFiles()
|
||||||
default:
|
default:
|
||||||
panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName()))
|
panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName()))
|
||||||
}
|
}
|
||||||
@@ -492,7 +502,33 @@ func (j *Module) compile(ctx android.ModuleContext) {
|
|||||||
|
|
||||||
var jars android.Paths
|
var jars android.Paths
|
||||||
|
|
||||||
if len(srcFiles) > 0 {
|
if srcFiles.HasExt(".kt") {
|
||||||
|
// If there are kotlin files, compile them first but pass all the kotlin and java files
|
||||||
|
// kotlinc will use the java files to resolve types referenced by the kotlin files, but
|
||||||
|
// won't emit any classes for them.
|
||||||
|
|
||||||
|
flags.kotlincFlags = "-no-stdlib"
|
||||||
|
if ctx.Device() {
|
||||||
|
flags.kotlincFlags += " -no-jdk"
|
||||||
|
}
|
||||||
|
|
||||||
|
flags.kotlincClasspath = append(flags.kotlincClasspath, deps.kotlinStdlib...)
|
||||||
|
flags.kotlincClasspath = append(flags.kotlincClasspath, deps.classpath...)
|
||||||
|
|
||||||
|
kotlinJar := android.PathForModuleOut(ctx, "classes-kt.jar")
|
||||||
|
TransformKotlinToClasses(ctx, kotlinJar, srcFiles, srcJars, flags)
|
||||||
|
if ctx.Failed() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make javac rule depend on the kotlinc rule
|
||||||
|
flags.classpath = append(flags.classpath, kotlinJar)
|
||||||
|
// Jar kotlin classes into the final jar after javac
|
||||||
|
jars = append(jars, kotlinJar)
|
||||||
|
jars = append(jars, deps.kotlinStdlib...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if javaSrcFiles := srcFiles.FilterByExt(".java"); len(javaSrcFiles) > 0 {
|
||||||
var extraJarDeps android.Paths
|
var extraJarDeps android.Paths
|
||||||
if ctx.AConfig().IsEnvTrue("RUN_ERROR_PRONE") {
|
if ctx.AConfig().IsEnvTrue("RUN_ERROR_PRONE") {
|
||||||
// If error-prone is enabled, add an additional rule to compile the java files into
|
// If error-prone is enabled, add an additional rule to compile the java files into
|
||||||
@@ -501,13 +537,13 @@ func (j *Module) compile(ctx android.ModuleContext) {
|
|||||||
// TODO(ccross): Once we always compile with javac9 we may be able to conditionally
|
// TODO(ccross): Once we always compile with javac9 we may be able to conditionally
|
||||||
// enable error-prone without affecting the output class files.
|
// enable error-prone without affecting the output class files.
|
||||||
errorprone := android.PathForModuleOut(ctx, "classes-errorprone.list")
|
errorprone := android.PathForModuleOut(ctx, "classes-errorprone.list")
|
||||||
RunErrorProne(ctx, errorprone, srcFiles, srcJars, flags)
|
RunErrorProne(ctx, errorprone, javaSrcFiles, srcJars, flags)
|
||||||
extraJarDeps = append(extraJarDeps, errorprone)
|
extraJarDeps = append(extraJarDeps, errorprone)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compile java sources into .class files
|
// Compile java sources into .class files
|
||||||
classes := android.PathForModuleOut(ctx, "classes-compiled.jar")
|
classes := android.PathForModuleOut(ctx, "classes-compiled.jar")
|
||||||
TransformJavaToClasses(ctx, classes, srcFiles, srcJars, flags, extraJarDeps)
|
TransformJavaToClasses(ctx, classes, javaSrcFiles, srcJars, flags, extraJarDeps)
|
||||||
if ctx.Failed() {
|
if ctx.Failed() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@@ -80,6 +80,7 @@ func testJavaWithEnv(t *testing.T, bp string, env map[string]string) *android.Te
|
|||||||
"android_stubs_current",
|
"android_stubs_current",
|
||||||
"android_system_stubs_current",
|
"android_system_stubs_current",
|
||||||
"android_test_stubs_current",
|
"android_test_stubs_current",
|
||||||
|
"kotlin-stdlib",
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, extra := range extraModules {
|
for _, extra := range extraModules {
|
||||||
@@ -115,6 +116,7 @@ func testJavaWithEnv(t *testing.T, bp string, env map[string]string) *android.Te
|
|||||||
"a.java": nil,
|
"a.java": nil,
|
||||||
"b.java": nil,
|
"b.java": nil,
|
||||||
"c.java": nil,
|
"c.java": nil,
|
||||||
|
"b.kt": nil,
|
||||||
"a.jar": nil,
|
"a.jar": nil,
|
||||||
"b.jar": nil,
|
"b.jar": nil,
|
||||||
"res/a": nil,
|
"res/a": nil,
|
||||||
@@ -613,6 +615,38 @@ func TestGeneratedSources(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestKotlin(t *testing.T) {
|
||||||
|
ctx := testJava(t, `
|
||||||
|
java_library {
|
||||||
|
name: "foo",
|
||||||
|
srcs: ["a.java", "b.kt"],
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
kotlinc := ctx.ModuleForTests("foo", "android_common").Rule("kotlinc")
|
||||||
|
javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
|
||||||
|
jar := ctx.ModuleForTests("foo", "android_common").Output("classes.jar")
|
||||||
|
|
||||||
|
if len(kotlinc.Inputs) != 2 || kotlinc.Inputs[0].String() != "a.java" ||
|
||||||
|
kotlinc.Inputs[1].String() != "b.kt" {
|
||||||
|
t.Errorf(`foo kotlinc inputs %v != ["a.java", "b.kt"]`, kotlinc.Inputs)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" {
|
||||||
|
t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(javac.Args["classpath"], kotlinc.Output.String()) {
|
||||||
|
t.Errorf("foo classpath %v does not contain %q",
|
||||||
|
javac.Args["classpath"], kotlinc.Output.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
if !inList(kotlinc.Output.String(), jar.Inputs.Strings()) {
|
||||||
|
t.Errorf("foo jar inputs %v does not contain %q",
|
||||||
|
jar.Inputs.Strings(), kotlinc.Output.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func fail(t *testing.T, errs []error) {
|
func fail(t *testing.T, errs []error) {
|
||||||
if len(errs) > 0 {
|
if len(errs) > 0 {
|
||||||
for _, err := range errs {
|
for _, err := range errs {
|
||||||
|
Reference in New Issue
Block a user