Merge "Initial support for converting jars to java9 system modules"

This commit is contained in:
Colin Cross 2017-10-17 18:37:35 +00:00 committed by Gerrit Code Review
commit 8c71d16652
9 changed files with 421 additions and 69 deletions

View file

@ -211,6 +211,7 @@ bootstrap_go_package {
"java/java.go",
"java/proto.go",
"java/resources.go",
"java/system_modules.go",
],
testSrcs: [
"java/java_test.go",

View file

@ -88,6 +88,9 @@ type config struct {
captureBuild bool // true for tests, saves build parameters for each module
ignoreEnvironment bool // true for tests, returns empty from all Getenv calls
useOpenJDK9 bool // Use OpenJDK9, but possibly target 1.8
targetOpenJDK9 bool // Use OpenJDK9 and target 1.9
OncePer
}
@ -183,6 +186,10 @@ func TestConfig(buildDir string, env map[string]string) Config {
config: config,
}
if err := config.fromEnv(); err != nil {
panic(err)
}
return Config{config}
}
@ -273,9 +280,31 @@ func NewConfig(srcDir, buildDir string) (Config, error) {
config.Targets = targets
config.BuildOsVariant = targets[Host][0].String()
if err := config.fromEnv(); err != nil {
return Config{}, err
}
return Config{config}, nil
}
func (c *config) fromEnv() error {
switch c.Getenv("EXPERIMENTAL_USE_OPENJDK9") {
case "":
// Use OpenJDK8
case "1.8":
// Use OpenJDK9, but target 1.8
c.useOpenJDK9 = true
case "true":
// Use OpenJDK9 and target 1.9
c.useOpenJDK9 = true
c.targetOpenJDK9 = true
default:
return fmt.Errorf(`Invalid value for EXPERIMENTAL_USE_OPENJDK9, should be "", "1.8", or "true"`)
}
return nil
}
func (c *config) RemoveAbandonedFiles() bool {
return false
}
@ -518,6 +547,16 @@ func (c *config) UseGoma() bool {
return Bool(c.ProductVariables.UseGoma)
}
// Returns true if OpenJDK9 prebuilts are being used
func (c *config) UseOpenJDK9() bool {
return c.useOpenJDK9
}
// Returns true if -source 1.9 -target 1.9 is being passed to javac
func (c *config) TargetOpenJDK9() bool {
return c.targetOpenJDK9
}
func (c *config) ClangTidy() bool {
return Bool(c.ProductVariables.ClangTidy)
}

View file

@ -126,6 +126,7 @@ type javaBuilderFlags struct {
dxFlags string
bootClasspath classpath
classpath classpath
systemModules classpath
desugarFlags string
aidlFlags string
javaVersion string
@ -177,7 +178,16 @@ func transformJavaToClasses(ctx android.ModuleContext, srcFiles, srcFileLists an
}
deps = append(deps, srcFileLists...)
deps = append(deps, flags.bootClasspath...)
var bootClasspath string
if flags.javaVersion == "1.9" {
deps = append(deps, flags.systemModules...)
bootClasspath = flags.systemModules.JavaSystemModules(ctx.Device())
} else {
deps = append(deps, flags.bootClasspath...)
bootClasspath = flags.bootClasspath.JavaBootClasspath(ctx.Device())
}
deps = append(deps, flags.classpath...)
ctx.ModuleBuild(pctx, android.ModuleBuildParams{
@ -188,7 +198,7 @@ func transformJavaToClasses(ctx android.ModuleContext, srcFiles, srcFileLists an
Implicits: deps,
Args: map[string]string{
"javacFlags": javacFlags,
"bootClasspath": flags.bootClasspath.JavaBootClasspath(ctx.Device()),
"bootClasspath": bootClasspath,
"classpath": flags.classpath.JavaClasspath(),
"outDir": android.PathForModuleOut(ctx, "classes"+suffix).String(),
"annoDir": android.PathForModuleOut(ctx, "anno"+suffix).String(),
@ -259,7 +269,7 @@ func TransformDesugar(ctx android.ModuleContext, classesJar android.Path,
dumpDir := android.PathForModuleOut(ctx, "desugar_dumped_classes")
javaFlags := ""
if ctx.AConfig().Getenv("EXPERIMENTAL_USE_OPENJDK9") != "" {
if ctx.AConfig().UseOpenJDK9() {
javaFlags = "--add-opens java.base/java.lang.invoke=ALL-UNNAMED"
}
@ -359,6 +369,21 @@ func (x *classpath) JavaBootClasspath(forceEmpty bool) string {
}
}
// Returns a --system argument in the form javac expects with -source 1.9. If forceEmpty is true,
// returns --system=none if the list is empty to ensure javac does not fall back to the default
// system modules.
func (x *classpath) JavaSystemModules(forceEmpty bool) string {
if len(*x) > 1 {
panic("more than one system module")
} else if len(*x) == 1 {
return "--system=" + strings.TrimSuffix((*x)[0].String(), "lib/modules")
} else if forceEmpty {
return "--system=none"
} else {
return ""
}
}
func (x *classpath) DesugarBootClasspath() []string {
if x == nil || *x == nil {
return nil

View file

@ -27,6 +27,7 @@ var (
pctx = android.NewPackageContext("android/soong/java/config")
DefaultBootclasspathLibraries = []string{"core-oj", "core-libart"}
DefaultSystemModules = "core-system-modules"
DefaultLibraries = []string{"ext", "framework", "okhttp"}
)
@ -47,9 +48,10 @@ func init() {
// If a different javac is used the flag will be ignored and extra bridges will be inserted.
// The flag is implemented by https://android-review.googlesource.com/c/486427
`-XDskipDuplicateBridges=true`,
}, " "))
pctx.StaticVariable("DefaultJavaVersion", "1.8")
// b/65004097: prevent using java.lang.invoke.StringConcatFactory when using -target 1.9
`-XDstringConcat=inline`,
}, " "))
pctx.VariableConfigMethod("hostPrebuiltTag", android.Config.PrebuiltOS)
@ -57,7 +59,7 @@ func init() {
if override := config.(android.Config).Getenv("OVERRIDE_ANDROID_JAVA_HOME"); override != "" {
return override, nil
}
if jdk9 := config.(android.Config).Getenv("EXPERIMENTAL_USE_OPENJDK9"); jdk9 != "" {
if config.(android.Config).UseOpenJDK9() {
return "prebuilts/jdk/jdk9/${hostPrebuiltTag}", nil
}
return "prebuilts/jdk/jdk8/${hostPrebuiltTag}", nil
@ -71,6 +73,7 @@ func init() {
pctx.SourcePathVariable("JavadocCmd", "${JavaToolchain}/javadoc")
pctx.SourcePathVariable("JlinkCmd", "${JavaToolchain}/jlink")
pctx.SourcePathVariable("JmodCmd", "${JavaToolchain}/jmod")
pctx.SourcePathVariable("JrtFsJar", "${JavaHome}/lib/jrt-fs.jar")
pctx.SourcePathVariable("JarArgsCmd", "build/soong/scripts/jar-args.sh")
pctx.StaticVariable("SoongZipCmd", filepath.Join("${bootstrap.ToolDir}", "soong_zip"))
@ -86,17 +89,3 @@ func init() {
return "", nil
})
}
func StripJavac9Flags(flags []string) []string {
var ret []string
for _, f := range flags {
switch {
case strings.HasPrefix(f, "-J--add-modules="):
// drop
default:
ret = append(ret, f)
}
}
return ret
}

View file

@ -27,8 +27,13 @@ func init() {
func makeVarsProvider(ctx android.MakeVarsContext) {
ctx.Strict("TARGET_DEFAULT_JAVA_LIBRARIES", strings.Join(DefaultLibraries, " "))
ctx.Strict("TARGET_DEFAULT_BOOTCLASSPATH_LIBRARIES", strings.Join(DefaultBootclasspathLibraries, " "))
ctx.Strict("DEFAULT_SYSTEM_MODULES", DefaultSystemModules)
ctx.Strict("DEFAULT_JAVA_LANGUAGE_VERSION", "${DefaultJavaVersion}")
if ctx.Config().TargetOpenJDK9() {
ctx.Strict("DEFAULT_JAVA_LANGUAGE_VERSION", "1.9")
} else {
ctx.Strict("DEFAULT_JAVA_LANGUAGE_VERSION", "1.8")
}
ctx.Strict("ANDROID_JAVA_HOME", "${JavaHome}")
ctx.Strict("ANDROID_JAVA_TOOLCHAIN", "${JavaToolchain}")
@ -47,7 +52,7 @@ func makeVarsProvider(ctx android.MakeVarsContext) {
ctx.Strict("HOST_JAVAC", "${JavacCmd} ${CommonJdkFlags}")
}
if ctx.Config().IsEnvTrue("EXPERIMENTAL_USE_OPENJDK9") {
if ctx.Config().UseOpenJDK9() {
ctx.Strict("JLINK", "${JlinkCmd}")
ctx.Strict("JMOD", "${JmodCmd}")
}

View file

@ -116,6 +116,14 @@ type CompilerProperties struct {
// List of classes to pass to javac to use as annotation processors
Annotation_processor_classes []string
Openjdk9 struct {
// List of source files that should only be used when passing -source 1.9
Srcs []string
// List of javac flags that should only be used when passing -source 1.9
Javacflags []string
}
}
type CompilerDeviceProperties struct {
@ -134,6 +142,9 @@ type CompilerDeviceProperties struct {
// If true, export a copy of the module as a -hostdex module for host testing.
Hostdex *bool
// When targeting 1.9, override the modules to use with --system
System_modules *string
}
// Module contains the properties and members used by all java module types
@ -185,26 +196,39 @@ var (
staticLibTag = dependencyTag{name: "staticlib"}
libTag = dependencyTag{name: "javalib"}
bootClasspathTag = dependencyTag{name: "bootclasspath"}
systemModulesTag = dependencyTag{name: "system modules"}
frameworkResTag = dependencyTag{name: "framework-res"}
)
type sdkDep struct {
useModule, useFiles, useDefaultLibs, invalidVersion bool
module string
jar android.Path
aidl android.Path
module string
systemModules string
jar android.Path
aidl android.Path
}
func sdkStringToNumber(ctx android.BaseContext, v string) int {
switch v {
case "", "current", "system_current", "test_current":
return 10000
default:
if i, err := strconv.Atoi(v); err != nil {
ctx.PropertyErrorf("sdk_version", "invalid sdk version")
return -1
} else {
return i
}
}
}
func decodeSdkDep(ctx android.BaseContext, v string) sdkDep {
switch v {
case "", "current", "system_current", "test_current":
// OK
default:
if _, err := strconv.Atoi(v); err != nil {
ctx.PropertyErrorf("sdk_version", "invalid sdk version")
return sdkDep{}
}
i := sdkStringToNumber(ctx, v)
if i == -1 {
// Invalid sdk version, error handled by sdkStringToNumber.
return sdkDep{}
}
toFile := func(v string) sdkDep {
@ -240,8 +264,9 @@ func decodeSdkDep(ctx android.BaseContext, v string) sdkDep {
toModule := func(m string) sdkDep {
return sdkDep{
useModule: true,
module: m,
useModule: true,
module: m,
systemModules: m + "_system_modules",
}
}
@ -266,20 +291,31 @@ func decodeSdkDep(ctx android.BaseContext, v string) sdkDep {
}
func (j *Module) deps(ctx android.BottomUpMutatorContext) {
if !proptools.Bool(j.properties.No_standard_libs) {
if ctx.Device() {
if ctx.Device() {
if !proptools.Bool(j.properties.No_standard_libs) {
sdkDep := decodeSdkDep(ctx, j.deviceProperties.Sdk_version)
if sdkDep.useDefaultLibs {
ctx.AddDependency(ctx.Module(), bootClasspathTag, config.DefaultBootclasspathLibraries...)
if ctx.AConfig().TargetOpenJDK9() {
ctx.AddDependency(ctx.Module(), systemModulesTag, config.DefaultSystemModules)
}
if !proptools.Bool(j.properties.No_framework_libs) {
ctx.AddDependency(ctx.Module(), libTag, config.DefaultLibraries...)
}
}
if sdkDep.useModule {
} else if sdkDep.useModule {
if ctx.AConfig().TargetOpenJDK9() {
ctx.AddDependency(ctx.Module(), systemModulesTag, sdkDep.systemModules)
}
ctx.AddDependency(ctx.Module(), bootClasspathTag, sdkDep.module)
}
} else if j.deviceProperties.System_modules == nil {
ctx.PropertyErrorf("no_standard_libs",
"system_modules is required to be set when no_standard_libs is true, did you mean no_framework_libs?")
} else if *j.deviceProperties.System_modules != "none" && ctx.AConfig().TargetOpenJDK9() {
ctx.AddDependency(ctx.Module(), systemModulesTag, *j.deviceProperties.System_modules)
}
}
ctx.AddDependency(ctx.Module(), libTag, j.properties.Libs...)
ctx.AddDependency(ctx.Module(), staticLibTag, j.properties.Static_libs...)
ctx.AddDependency(ctx.Module(), libTag, j.properties.Annotation_processors...)
@ -335,6 +371,7 @@ type deps struct {
staticJarResources android.Paths
aidlIncludeDirs android.Paths
srcFileLists android.Paths
systemModules android.Path
aidlPreprocess android.OptionalPath
}
@ -358,6 +395,15 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps {
switch tag {
case android.DefaultsDepTag, android.SourceDepTag:
// Nothing to do
case systemModulesTag:
if deps.systemModules != nil {
panic("Found two system module dependencies")
}
sm := module.(*SystemModules)
if sm.outputFile == nil {
panic("Missing directory for system module dependency")
}
deps.systemModules = sm.outputFile
default:
ctx.ModuleErrorf("depends on non-java module %q", otherName)
}
@ -397,19 +443,29 @@ func (j *Module) compile(ctx android.ModuleContext) {
var flags javaBuilderFlags
javacFlags := j.properties.Javacflags
if ctx.AConfig().Getenv("EXPERIMENTAL_USE_OPENJDK9") == "" {
javacFlags = config.StripJavac9Flags(javacFlags)
if ctx.AConfig().TargetOpenJDK9() {
javacFlags = append(javacFlags, j.properties.Openjdk9.Javacflags...)
j.properties.Srcs = append(j.properties.Srcs, j.properties.Openjdk9.Srcs...)
}
sdk := sdkStringToNumber(ctx, j.deviceProperties.Sdk_version)
if j.properties.Java_version != nil {
flags.javaVersion = *j.properties.Java_version
} else if ctx.Device() && sdk <= 23 {
flags.javaVersion = "1.7"
} else if ctx.Device() && sdk <= 26 || !ctx.AConfig().TargetOpenJDK9() {
flags.javaVersion = "1.8"
} else {
flags.javaVersion = "${config.DefaultJavaVersion}"
flags.javaVersion = "1.9"
}
flags.bootClasspath.AddPaths(deps.bootClasspath)
flags.classpath.AddPaths(deps.classpath)
if deps.systemModules != nil {
flags.systemModules = append(flags.systemModules, deps.systemModules)
}
if len(javacFlags) > 0 {
ctx.Variable(pctx, "javacFlags", strings.Join(javacFlags, " "))
flags.javacFlags = "$javacFlags"

View file

@ -50,9 +50,12 @@ func TestMain(m *testing.M) {
os.Exit(run())
}
func testJava(t *testing.T, bp string) *android.TestContext {
config := android.TestArchConfig(buildDir, nil)
return testJavaWithEnv(t, bp, nil)
}
func testJavaWithEnv(t *testing.T, bp string, env map[string]string) *android.TestContext {
config := android.TestArchConfig(buildDir, env)
ctx := android.NewTestArchContext()
ctx.RegisterModuleType("android_app", android.ModuleFactoryAdaptor(AndroidAppFactory))
@ -60,6 +63,7 @@ func testJava(t *testing.T, bp string) *android.TestContext {
ctx.RegisterModuleType("java_library_host", android.ModuleFactoryAdaptor(LibraryHostFactory))
ctx.RegisterModuleType("java_import", android.ModuleFactoryAdaptor(ImportFactory))
ctx.RegisterModuleType("java_defaults", android.ModuleFactoryAdaptor(defaultsFactory))
ctx.RegisterModuleType("java_system_modules", android.ModuleFactoryAdaptor(SystemModulesFactory))
ctx.RegisterModuleType("filegroup", android.ModuleFactoryAdaptor(genrule.FileGroupFactory))
ctx.RegisterModuleType("genrule", android.ModuleFactoryAdaptor(genrule.GenRuleFactory))
ctx.PreArchMutators(android.RegisterPrebuiltsPreArchMutators)
@ -84,10 +88,28 @@ func testJava(t *testing.T, bp string) *android.TestContext {
name: "%s",
srcs: ["a.java"],
no_standard_libs: true,
system_modules: "core-system-modules",
}
`, extra)
}
if config.TargetOpenJDK9() {
systemModules := []string{
"core-system-modules",
"android_stubs_current_system_modules",
"android_system_stubs_current_system_modules",
"android_test_stubs_current_system_modules",
}
for _, extra := range systemModules {
bp += fmt.Sprintf(`
java_system_modules {
name: "%s",
}
`, extra)
}
}
ctx.MockFileSystem(map[string][]byte{
"Android.bp": []byte(bp),
"a.java": nil,
@ -190,17 +212,20 @@ var classpathTestcases = []struct {
host android.OsClass
properties string
bootclasspath []string
system string
classpath []string
}{
{
name: "default",
bootclasspath: []string{"core-oj", "core-libart"},
system: "core-system-modules",
classpath: []string{"ext", "framework", "okhttp"},
},
{
name: "blank sdk version",
properties: `sdk_version: "",`,
bootclasspath: []string{"core-oj", "core-libart"},
system: "core-system-modules",
classpath: []string{"ext", "framework", "okhttp"},
},
{
@ -208,6 +233,7 @@ var classpathTestcases = []struct {
name: "sdk v14",
properties: `sdk_version: "14",`,
bootclasspath: []string{`""`},
system: "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
classpath: []string{"prebuilts/sdk/14/android.jar"},
},
{
@ -215,6 +241,7 @@ var classpathTestcases = []struct {
name: "current",
properties: `sdk_version: "current",`,
bootclasspath: []string{"android_stubs_current"},
system: "android_stubs_current_system_modules",
classpath: []string{},
},
{
@ -222,6 +249,7 @@ var classpathTestcases = []struct {
name: "system_current",
properties: `sdk_version: "system_current",`,
bootclasspath: []string{"android_system_stubs_current"},
system: "android_system_stubs_current_system_modules",
classpath: []string{},
},
{
@ -229,12 +257,22 @@ var classpathTestcases = []struct {
name: "test_current",
properties: `sdk_version: "test_current",`,
bootclasspath: []string{"android_test_stubs_current"},
system: "android_test_stubs_current_system_modules",
classpath: []string{},
},
{
name: "nostdlib",
properties: `no_standard_libs: true`,
properties: `no_standard_libs: true, system_modules: "none"`,
system: "none",
bootclasspath: []string{`""`},
classpath: []string{},
},
{
name: "nostdlib system_modules",
properties: `no_standard_libs: true, system_modules: "core-system-modules"`,
system: "core-system-modules",
bootclasspath: []string{`""`},
classpath: []string{},
},
@ -263,7 +301,7 @@ var classpathTestcases = []struct {
{
name: "host supported nostdlib",
host: android.Host,
properties: `host_supported: true, no_standard_libs: true`,
properties: `host_supported: true, no_standard_libs: true, system_modules: "none"`,
classpath: []string{},
},
}
@ -275,12 +313,17 @@ func TestClasspath(t *testing.T) {
if testcase.moduleType != "" {
moduleType = testcase.moduleType
}
ctx := testJava(t, moduleType+` {
bp := moduleType + ` {
name: "foo",
srcs: ["a.java"],
`+testcase.properties+`
` + testcase.properties + `
}`
variant := "android_common"
if testcase.host == android.Host {
variant = android.BuildOs.String() + "_common"
}
`)
convertModulesToPaths := func(cp []string) []string {
ret := make([]string, len(cp))
@ -293,33 +336,63 @@ func TestClasspath(t *testing.T) {
bootclasspath := convertModulesToPaths(testcase.bootclasspath)
classpath := convertModulesToPaths(testcase.classpath)
variant := "android_common"
if testcase.host == android.Host {
variant = android.BuildOs.String() + "_common"
}
javac := ctx.ModuleForTests("foo", variant).Rule("javac")
got := strings.TrimPrefix(javac.Args["bootClasspath"], "-bootclasspath ")
bc := strings.Join(bootclasspath, ":")
if got != bc {
t.Errorf("bootclasspath expected %q != got %q", bc, got)
if bc != "" {
bc = "-bootclasspath " + bc
}
got = strings.TrimPrefix(javac.Args["classpath"], "-classpath ")
c := strings.Join(classpath, ":")
if got != c {
t.Errorf("classpath expected %q != got %q", c, got)
if c != "" {
c = "-classpath " + c
}
system := ""
if testcase.system == "none" {
system = "--system=none"
} else if testcase.system != "" {
system = "--system=" + filepath.Join(buildDir, ".intermediates", testcase.system, "android_common", "system") + "/"
}
var deps []string
if len(bootclasspath) > 0 && bootclasspath[0] != `""` {
deps = append(deps, bootclasspath...)
}
deps = append(deps, classpath...)
t.Run("1.8", func(t *testing.T) {
// Test default javac 1.8
ctx := testJava(t, bp)
if !reflect.DeepEqual(javac.Implicits.Strings(), deps) {
t.Errorf("implicits expected %q != got %q", deps, javac.Implicits.Strings())
}
javac := ctx.ModuleForTests("foo", variant).Rule("javac")
got := javac.Args["bootClasspath"]
if got != bc {
t.Errorf("bootclasspath expected %q != got %q", bc, got)
}
got = javac.Args["classpath"]
if got != c {
t.Errorf("classpath expected %q != got %q", c, got)
}
var deps []string
if len(bootclasspath) > 0 && bootclasspath[0] != `""` {
deps = append(deps, bootclasspath...)
}
deps = append(deps, classpath...)
if !reflect.DeepEqual(javac.Implicits.Strings(), deps) {
t.Errorf("implicits expected %q != got %q", deps, javac.Implicits.Strings())
}
})
// Test again with javac 1.9
t.Run("1.9", func(t *testing.T) {
ctx := testJavaWithEnv(t, bp, map[string]string{"EXPERIMENTAL_USE_OPENJDK9": "true"})
javac := ctx.ModuleForTests("foo", variant).Rule("javac")
got := javac.Args["bootClasspath"]
expected := system
if testcase.system == "bootclasspath" {
expected = bc
}
if got != expected {
t.Errorf("bootclasspath expected %q != got %q", expected, got)
}
})
})
}

144
java/system_modules.go Normal file
View file

@ -0,0 +1,144 @@
// 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 (
"fmt"
"io"
"strings"
"github.com/google/blueprint"
"android/soong/android"
)
// OpenJDK 9 introduces the concept of "system modules", which replace the bootclasspath. This
// file will produce the rules necessary to convert each unique set of bootclasspath jars into
// system modules in a runtime image using the jmod and jlink tools.
func init() {
android.RegisterModuleType("java_system_modules", SystemModulesFactory)
pctx.SourcePathVariable("moduleInfoJavaPath", "build/soong/scripts/jars-to-module-info-java.sh")
}
var (
jarsTosystemModules = pctx.AndroidStaticRule("jarsTosystemModules", blueprint.RuleParams{
Command: `rm -rf ${outDir} ${workDir} && mkdir -p ${workDir}/jmod && ` +
`${moduleInfoJavaPath} ${moduleName} $in > ${workDir}/module-info.java && ` +
`${config.JavacCmd} --system=none --patch-module=java.base=${classpath} ${workDir}/module-info.java && ` +
`${config.SoongZipCmd} -jar -o ${workDir}/classes.jar -C ${workDir} -f ${workDir}/module-info.class && ` +
`${config.MergeZipsCmd} -j ${workDir}/module.jar ${workDir}/classes.jar $in && ` +
`${config.JmodCmd} create --module-version 9 --target-platform android ` +
` --class-path ${workDir}/module.jar ${workDir}/jmod/${moduleName}.jmod && ` +
`${config.JlinkCmd} --module-path ${workDir}/jmod --add-modules ${moduleName} --output ${outDir} && ` +
`cp ${config.JrtFsJar} ${outDir}/lib/`,
CommandDeps: []string{
"${moduleInfoJavaPath}",
"${config.JavacCmd}",
"${config.SoongZipCmd}",
"${config.MergeZipsCmd}",
"${config.JmodCmd}",
"${config.JlinkCmd}",
"${config.JrtFsJar}",
},
},
"moduleName", "classpath", "outDir", "workDir")
)
func TransformJarsToSystemModules(ctx android.ModuleContext, moduleName string, jars android.Paths) android.WritablePath {
outDir := android.PathForModuleOut(ctx, "system")
workDir := android.PathForModuleOut(ctx, "modules")
outputFile := android.PathForModuleOut(ctx, "system/lib/modules")
outputs := android.WritablePaths{
outputFile,
android.PathForModuleOut(ctx, "system/lib/jrt-fs.jar"),
android.PathForModuleOut(ctx, "system/release"),
}
ctx.ModuleBuild(pctx, android.ModuleBuildParams{
Rule: jarsTosystemModules,
Description: "system modules",
Outputs: outputs,
Inputs: jars,
Args: map[string]string{
"moduleName": moduleName,
"classpath": strings.Join(jars.Strings(), ":"),
"workDir": workDir.String(),
"outDir": outDir.String(),
},
})
return outputFile
}
func SystemModulesFactory() android.Module {
module := &SystemModules{}
module.AddProperties(&module.properties)
android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
return module
}
type SystemModules struct {
android.ModuleBase
properties SystemModulesProperties
outputFile android.Path
}
type SystemModulesProperties struct {
// List of java library modules that should be included in the system modules
Libs []string
// List of prebuilt jars that should be included in the system modules
Jars []string
// Sdk version that should be included in the system modules
Sdk_version *string
}
func (system *SystemModules) GenerateAndroidBuildActions(ctx android.ModuleContext) {
var jars android.Paths
ctx.VisitDirectDeps(func(module blueprint.Module) {
if ctx.OtherModuleDependencyTag(module) == libTag {
dep, _ := module.(Dependency)
jars = append(jars, dep.ClasspathFiles()...)
}
})
jars = append(jars, android.PathsForModuleSrc(ctx, system.properties.Jars)...)
if ctx.AConfig().TargetOpenJDK9() {
system.outputFile = TransformJarsToSystemModules(ctx, "java.base", jars)
}
}
func (system *SystemModules) DepsMutator(ctx android.BottomUpMutatorContext) {
ctx.AddDependency(ctx.Module(), libTag, system.properties.Libs...)
}
func (system *SystemModules) AndroidMk() android.AndroidMkData {
return android.AndroidMkData{
Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
if system.outputFile != nil {
makevar := "SOONG_SYSTEM_MODULES_" + name
fmt.Fprintln(w)
fmt.Fprintln(w, makevar, ":=", system.outputFile.String())
fmt.Fprintln(w, ".KATI_READONLY", ":=", makevar)
}
},
}
}

View file

@ -0,0 +1,20 @@
#!/bin/bash -e
# Extracts the Java package names of all classes in the .jar files and writes a module-info.java
# file to stdout that exports all of those packages.
if [ -z "$1" ]; then
echo "usage: $0 <module name> <jar1> [<jar2> ...]" >&2
exit 1
fi
module_name=$1
shift
echo "module ${module_name} {"
for j in "$@"; do zipinfo -1 $j ; done \
| grep -E '/[^/]*\.class$' \
| sed 's|\(.*\)/[^/]*\.class$| exports \1;|g' \
| sed 's|/|.|g' \
| sort -u
echo "}"