Merge "Initial support for converting jars to java9 system modules"
This commit is contained in:
commit
8c71d16652
9 changed files with 421 additions and 69 deletions
|
@ -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",
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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}")
|
||||
}
|
||||
|
|
96
java/java.go
96
java/java.go
|
@ -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"
|
||||
|
|
|
@ -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
144
java/system_modules.go
Normal 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)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
20
scripts/jars-to-module-info-java.sh
Executable file
20
scripts/jars-to-module-info-java.sh
Executable 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 "}"
|
Loading…
Reference in a new issue