Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a174d2e9 authored by Colin Cross's avatar Colin Cross
Browse files

Support static_libs for java_import modules

Remove the need to wrap java_import modules with a java_library
just to include static dependencies.

Bug: 288358614
Test: TestJavaImport
Change-Id: I888aecc6c0efc696a397fc1dd5d0ef5fd644bebc
parent 81794967
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -211,7 +211,7 @@ func (prebuilt *Import) AndroidMkEntries() []android.AndroidMkEntries {
	return []android.AndroidMkEntries{android.AndroidMkEntries{
		Class:        "JAVA_LIBRARIES",
		OverrideName: prebuilt.BaseModuleName(),
		OutputFile:   android.OptionalPathForPath(prebuilt.combinedClasspathFile),
		OutputFile:   android.OptionalPathForPath(prebuilt.combinedImplementationFile),
		Include:      "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
@@ -219,8 +219,8 @@ func (prebuilt *Import) AndroidMkEntries() []android.AndroidMkEntries {
				if prebuilt.dexJarFile.IsSet() {
					entries.SetPath("LOCAL_SOONG_DEX_JAR", prebuilt.dexJarFile.Path())
				}
				entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.combinedClasspathFile)
				entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.combinedClasspathFile)
				entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.combinedHeaderFile)
				entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.combinedImplementationFile)
				entries.SetString("LOCAL_SDK_VERSION", prebuilt.sdkVersion.String())
				entries.SetString("LOCAL_MODULE_STEM", prebuilt.Stem())
				// TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts
+59 −27
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ package java
import (
	"fmt"
	"path/filepath"
	"slices"
	"sort"
	"strings"

@@ -2337,6 +2338,9 @@ type ImportProperties struct {
	// List of shared java libs that this module has dependencies to
	Libs []string

	// List of static java libs that this module has dependencies to
	Static_libs []string

	// List of files to remove from the jar file(s)
	Exclude_files []string

@@ -2389,7 +2393,8 @@ type Import struct {
	dexJarFileErr     error
	dexJarInstallFile android.Path

	combinedClasspathFile android.Path
	combinedImplementationFile android.Path
	combinedHeaderFile         android.Path
	classLoaderContexts        dexpreopt.ClassLoaderContextMap
	exportAidlIncludeDirs      android.Paths

@@ -2475,6 +2480,7 @@ func (j *Import) setStrictUpdatabilityLinting(bool) {

func (j *Import) DepsMutator(ctx android.BottomUpMutatorContext) {
	ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...)
	ctx.AddVariationDependencies(nil, staticLibTag, j.properties.Static_libs...)

	if ctx.Device() && Bool(j.dexProperties.Compile_dex) {
		sdkDeps(ctx, android.SdkContext(j), j.dexer)
@@ -2504,23 +2510,13 @@ func (j *Import) commonBuildActions(ctx android.ModuleContext) {
func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
	j.commonBuildActions(ctx)

	jars := android.PathsForModuleSrc(ctx, j.properties.Jars)

	jarName := j.Stem() + ".jar"
	outputFile := android.PathForModuleOut(ctx, "combined", jarName)
	TransformJarsToJar(ctx, outputFile, "for prebuilts", jars, android.OptionalPath{},
		false, j.properties.Exclude_files, j.properties.Exclude_dirs)
	if Bool(j.properties.Jetifier) {
		inputFile := outputFile
		outputFile = android.PathForModuleOut(ctx, "jetifier", jarName)
		TransformJetifier(ctx, outputFile, inputFile)
	}
	j.combinedClasspathFile = outputFile
	j.classLoaderContexts = make(dexpreopt.ClassLoaderContextMap)

	var flags javaBuilderFlags

	j.collectTransitiveHeaderJars(ctx)
	var staticJars android.Paths
	var staticHeaderJars android.Paths
	ctx.VisitDirectDeps(func(module android.Module) {
		tag := ctx.OtherModuleDependencyTag(module)
		if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
@@ -2530,6 +2526,8 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
				flags.dexClasspath = append(flags.dexClasspath, dep.HeaderJars...)
			case staticLibTag:
				flags.classpath = append(flags.classpath, dep.HeaderJars...)
				staticJars = append(staticJars, dep.ImplementationAndResourcesJars...)
				staticHeaderJars = append(staticHeaderJars, dep.HeaderJars...)
			case bootClasspathTag:
				flags.bootClasspath = append(flags.bootClasspath, dep.HeaderJars...)
			}
@@ -2543,6 +2541,46 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
		addCLCFromDep(ctx, module, j.classLoaderContexts)
	})

	jars := android.PathsForModuleSrc(ctx, j.properties.Jars)
	jarName := j.Stem() + ".jar"

	// Always pass the input jars to TransformJarsToJar, even if there is only a single jar, we need the output
	// file of the module to be named jarName.
	outputFile := android.PathForModuleOut(ctx, "combined", jarName)
	implementationJars := append(slices.Clone(jars), staticJars...)
	TransformJarsToJar(ctx, outputFile, "combine prebuilt implementation jars", implementationJars, android.OptionalPath{},
		false, j.properties.Exclude_files, j.properties.Exclude_dirs)

	// If no dependencies have separate header jars then there is no need to create a separate
	// header jar for this module.
	reuseImplementationJarAsHeaderJar := slices.Equal(staticJars, staticHeaderJars)

	var headerOutputFile android.WritablePath
	if reuseImplementationJarAsHeaderJar {
		headerOutputFile = outputFile
	} else {
		headerJars := append(slices.Clone(jars), staticHeaderJars...)
		headerOutputFile = android.PathForModuleOut(ctx, "turbine-combined", jarName)
		TransformJarsToJar(ctx, headerOutputFile, "combine prebuilt header jars", headerJars, android.OptionalPath{},
			false, j.properties.Exclude_files, j.properties.Exclude_dirs)
	}

	if Bool(j.properties.Jetifier) {
		inputFile := outputFile
		outputFile = android.PathForModuleOut(ctx, "jetifier", jarName)
		TransformJetifier(ctx, outputFile, inputFile)

		if !reuseImplementationJarAsHeaderJar {
			headerInputFile := headerOutputFile
			headerOutputFile = android.PathForModuleOut(ctx, "jetifier-headers", jarName)
			TransformJetifier(ctx, headerOutputFile, headerInputFile)
		} else {
			headerOutputFile = outputFile
		}
	}
	j.combinedHeaderFile = headerOutputFile
	j.combinedImplementationFile = outputFile

	j.maybeInstall(ctx, jarName, outputFile)

	j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.properties.Aidl.Export_include_dirs)
@@ -2626,11 +2664,11 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
	}

	android.SetProvider(ctx, JavaInfoProvider, JavaInfo{
		HeaderJars:                     android.PathsIfNonNil(j.combinedClasspathFile),
		HeaderJars:                     android.PathsIfNonNil(j.combinedHeaderFile),
		TransitiveLibsHeaderJars:       j.transitiveLibsHeaderJars,
		TransitiveStaticLibsHeaderJars: j.transitiveStaticLibsHeaderJars,
		ImplementationAndResourcesJars: android.PathsIfNonNil(j.combinedClasspathFile),
		ImplementationJars:             android.PathsIfNonNil(j.combinedClasspathFile),
		ImplementationAndResourcesJars: android.PathsIfNonNil(j.combinedImplementationFile),
		ImplementationJars:             android.PathsIfNonNil(j.combinedImplementationFile),
		AidlIncludeDirs:                j.exportAidlIncludeDirs,
		StubsLinkType:                  j.stubsLinkType,
		// TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts
@@ -2658,7 +2696,7 @@ func (j *Import) maybeInstall(ctx android.ModuleContext, jarName string, outputF
func (j *Import) OutputFiles(tag string) (android.Paths, error) {
	switch tag {
	case "", ".jar":
		return android.Paths{j.combinedClasspathFile}, nil
		return android.Paths{j.combinedImplementationFile}, nil
	default:
		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
	}
@@ -2667,17 +2705,11 @@ func (j *Import) OutputFiles(tag string) (android.Paths, error) {
var _ android.OutputFileProducer = (*Import)(nil)

func (j *Import) HeaderJars() android.Paths {
	if j.combinedClasspathFile == nil {
		return nil
	}
	return android.Paths{j.combinedClasspathFile}
	return android.PathsIfNonNil(j.combinedHeaderFile)
}

func (j *Import) ImplementationAndResourcesJars() android.Paths {
	if j.combinedClasspathFile == nil {
		return nil
	}
	return android.Paths{j.combinedClasspathFile}
	return android.PathsIfNonNil(j.combinedImplementationFile)
}

func (j *Import) DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath {
+84 −4
Original line number Diff line number Diff line
@@ -588,10 +588,11 @@ func TestPrebuilts(t *testing.T) {
	javac := fooModule.Rule("javac")
	combineJar := ctx.ModuleForTests("foo", "android_common").Description("for javac")
	barModule := ctx.ModuleForTests("bar", "android_common")
	barJar := barModule.Rule("combineJar").Output
	barJar := barModule.Output("combined/bar.jar").Output
	bazModule := ctx.ModuleForTests("baz", "android_common")
	bazJar := bazModule.Rule("combineJar").Output
	sdklibStubsJar := ctx.ModuleForTests("sdklib.stubs", "android_common").Rule("combineJar").Output
	sdklibStubsJar := ctx.ModuleForTests("sdklib.stubs", "android_common").
		Output("combined/sdklib.stubs.jar").Output

	fooLibrary := fooModule.Module().(*Library)
	assertDeepEquals(t, "foo unique sources incorrect",
@@ -1035,7 +1036,7 @@ func TestExcludeFileGroupInSrcs(t *testing.T) {
	}
}

func TestJavaLibrary(t *testing.T) {
func TestJavaLibraryOutputFiles(t *testing.T) {
	testJavaWithFS(t, "", map[string][]byte{
		"libcore/Android.bp": []byte(`
				java_library {
@@ -1052,7 +1053,7 @@ func TestJavaLibrary(t *testing.T) {
	})
}

func TestJavaImport(t *testing.T) {
func TestJavaImportOutputFiles(t *testing.T) {
	testJavaWithFS(t, "", map[string][]byte{
		"libcore/Android.bp": []byte(`
				java_import {
@@ -1068,6 +1069,85 @@ func TestJavaImport(t *testing.T) {
	})
}

func TestJavaImport(t *testing.T) {
	bp := `
		java_library {
			name: "source_library",
			srcs: ["source.java"],
		}

		java_import {
			name: "import_with_no_deps",
			jars: ["no_deps.jar"],
		}

		java_import {
			name: "import_with_source_deps",
			jars: ["source_deps.jar"],
			static_libs: ["source_library"],
		}

		java_import {
			name: "import_with_import_deps",
			jars: ["import_deps.jar"],
			static_libs: ["import_with_no_deps"],
		}
	`
	ctx := android.GroupFixturePreparers(
		PrepareForTestWithJavaDefaultModules,
	).RunTestWithBp(t, bp)

	source := ctx.ModuleForTests("source_library", "android_common")
	sourceJar := source.Output("javac/source_library.jar")
	sourceHeaderJar := source.Output("turbine-combined/source_library.jar")
	sourceJavaInfo, _ := android.SingletonModuleProvider(ctx, source.Module(), JavaInfoProvider)

	// The source library produces separate implementation and header jars
	android.AssertPathsRelativeToTopEquals(t, "source library implementation jar",
		[]string{sourceJar.Output.String()}, sourceJavaInfo.ImplementationAndResourcesJars)
	android.AssertPathsRelativeToTopEquals(t, "source library header jar",
		[]string{sourceHeaderJar.Output.String()}, sourceJavaInfo.HeaderJars)

	importWithNoDeps := ctx.ModuleForTests("import_with_no_deps", "android_common")
	importWithNoDepsJar := importWithNoDeps.Output("combined/import_with_no_deps.jar")
	importWithNoDepsJavaInfo, _ := android.SingletonModuleProvider(ctx, importWithNoDeps.Module(), JavaInfoProvider)

	// An import with no deps produces a single jar used as both the header and implementation jar.
	android.AssertPathsRelativeToTopEquals(t, "import with no deps implementation jar",
		[]string{importWithNoDepsJar.Output.String()}, importWithNoDepsJavaInfo.ImplementationAndResourcesJars)
	android.AssertPathsRelativeToTopEquals(t, "import with no deps header jar",
		[]string{importWithNoDepsJar.Output.String()}, importWithNoDepsJavaInfo.HeaderJars)
	android.AssertPathsRelativeToTopEquals(t, "import with no deps combined inputs",
		[]string{"no_deps.jar"}, importWithNoDepsJar.Inputs)

	importWithSourceDeps := ctx.ModuleForTests("import_with_source_deps", "android_common")
	importWithSourceDepsJar := importWithSourceDeps.Output("combined/import_with_source_deps.jar")
	importWithSourceDepsHeaderJar := importWithSourceDeps.Output("turbine-combined/import_with_source_deps.jar")
	importWithSourceDepsJavaInfo, _ := android.SingletonModuleProvider(ctx, importWithSourceDeps.Module(), JavaInfoProvider)

	// An import with source deps produces separate header and implementation jars.
	android.AssertPathsRelativeToTopEquals(t, "import with source deps implementation jar",
		[]string{importWithSourceDepsJar.Output.String()}, importWithSourceDepsJavaInfo.ImplementationAndResourcesJars)
	android.AssertPathsRelativeToTopEquals(t, "import with source deps header jar",
		[]string{importWithSourceDepsHeaderJar.Output.String()}, importWithSourceDepsJavaInfo.HeaderJars)
	android.AssertPathsRelativeToTopEquals(t, "import with source deps combined implementation jar inputs",
		[]string{"source_deps.jar", sourceJar.Output.String()}, importWithSourceDepsJar.Inputs)
	android.AssertPathsRelativeToTopEquals(t, "import with source deps combined header jar inputs",
		[]string{"source_deps.jar", sourceHeaderJar.Output.String()}, importWithSourceDepsHeaderJar.Inputs)

	importWithImportDeps := ctx.ModuleForTests("import_with_import_deps", "android_common")
	importWithImportDepsJar := importWithImportDeps.Output("combined/import_with_import_deps.jar")
	importWithImportDepsJavaInfo, _ := android.SingletonModuleProvider(ctx, importWithImportDeps.Module(), JavaInfoProvider)

	// An import with only import deps produces a single jar used as both the header and implementation jar.
	android.AssertPathsRelativeToTopEquals(t, "import with import deps implementation jar",
		[]string{importWithImportDepsJar.Output.String()}, importWithImportDepsJavaInfo.ImplementationAndResourcesJars)
	android.AssertPathsRelativeToTopEquals(t, "import with import deps header jar",
		[]string{importWithImportDepsJar.Output.String()}, importWithImportDepsJavaInfo.HeaderJars)
	android.AssertPathsRelativeToTopEquals(t, "import with import deps combined implementation jar inputs",
		[]string{"import_deps.jar", importWithNoDepsJar.Output.String()}, importWithImportDepsJar.Inputs)
}

var compilerFlagsTestCases = []struct {
	in  string
	out bool