Merge "Remove unnecessary `android:"path"` tags in rust"
diff --git a/android/bazel.go b/android/bazel.go
index 1f7f7e6..6e87d57 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -126,6 +126,42 @@
)
var (
+ // Do not write BUILD files for these directories
+ // NOTE: this is not recursive
+ bp2buildDoNotWriteBuildFileList = []string{
+ // Don't generate these BUILD files - because external BUILD files already exist
+ "external/boringssl",
+ "external/brotli",
+ "external/dagger2",
+ "external/flatbuffers",
+ "external/gflags",
+ "external/google-fruit",
+ "external/grpc-grpc",
+ "external/grpc-grpc/test/core/util",
+ "external/grpc-grpc/test/cpp/common",
+ "external/grpc-grpc/third_party/address_sorting",
+ "external/nanopb-c",
+ "external/nos/host/generic",
+ "external/nos/host/generic/libnos",
+ "external/nos/host/generic/libnos/generator",
+ "external/nos/host/generic/libnos_datagram",
+ "external/nos/host/generic/libnos_transport",
+ "external/nos/host/generic/nugget/proto",
+ "external/perfetto",
+ "external/protobuf",
+ "external/rust/cxx",
+ "external/rust/cxx/demo",
+ "external/ruy",
+ "external/tensorflow",
+ "external/tensorflow/tensorflow/lite",
+ "external/tensorflow/tensorflow/lite/java",
+ "external/tensorflow/tensorflow/lite/kernels",
+ "external/tflite-support",
+ "external/tinyalsa_new",
+ "external/wycheproof",
+ "external/libyuv",
+ }
+
// Configure modules in these directories to enable bp2build_available: true or false by default.
bp2buildDefaultConfig = Bp2BuildConfig{
"bionic": Bp2BuildDefaultTrueRecursively,
@@ -190,11 +226,16 @@
}
// Used for quicker lookups
- bp2buildModuleDoNotConvert = map[string]bool{}
- mixedBuildsDisabled = map[string]bool{}
+ bp2buildDoNotWriteBuildFile = map[string]bool{}
+ bp2buildModuleDoNotConvert = map[string]bool{}
+ mixedBuildsDisabled = map[string]bool{}
)
func init() {
+ for _, moduleName := range bp2buildDoNotWriteBuildFileList {
+ bp2buildDoNotWriteBuildFile[moduleName] = true
+ }
+
for _, moduleName := range bp2buildModuleDoNotConvertList {
bp2buildModuleDoNotConvert[moduleName] = true
}
@@ -204,6 +245,14 @@
}
}
+func ShouldWriteBuildFileForDir(dir string) bool {
+ if _, ok := bp2buildDoNotWriteBuildFile[dir]; ok {
+ return false
+ } else {
+ return true
+ }
+}
+
// MixedBuildsEnabled checks that a module is ready to be replaced by a
// converted or handcrafted Bazel target.
func (b *BazelModuleBase) MixedBuildsEnabled(ctx BazelConversionPathContext) bool {
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 8d561d2..4598995 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -321,9 +321,8 @@
// the invocation returned an error code.
func (r *builtinBazelRunner) issueBazelCommand(paths *bazelPaths, runName bazel.RunName, command bazelCommand,
extraFlags ...string) (string, string, error) {
- cmdFlags := []string{"--output_base=" + paths.outputBase, command.command}
+ cmdFlags := []string{"--output_base=" + absolutePath(paths.outputBase), command.command}
cmdFlags = append(cmdFlags, command.expression)
- cmdFlags = append(cmdFlags, "--package_path=%workspace%/"+paths.intermediatesDir())
cmdFlags = append(cmdFlags, "--profile="+shared.BazelMetricsFilename(paths, runName))
// Set default platforms to canonicalized values for mixed builds requests.
@@ -334,20 +333,20 @@
// The actual platform values here may be overridden by configuration
// transitions from the buildroot.
cmdFlags = append(cmdFlags,
- fmt.Sprintf("--platforms=%s", canonicalizeLabel("//build/bazel/platforms:android_x86_64")))
+ fmt.Sprintf("--platforms=%s", "//build/bazel/platforms:android_x86_64"))
cmdFlags = append(cmdFlags,
- fmt.Sprintf("--extra_toolchains=%s", canonicalizeLabel("//prebuilts/clang/host/linux-x86:all")))
+ fmt.Sprintf("--extra_toolchains=%s", "//prebuilts/clang/host/linux-x86:all"))
// This should be parameterized on the host OS, but let's restrict to linux
// to keep things simple for now.
cmdFlags = append(cmdFlags,
- fmt.Sprintf("--host_platform=%s", canonicalizeLabel("//build/bazel/platforms:linux_x86_64")))
+ fmt.Sprintf("--host_platform=%s", "//build/bazel/platforms:linux_x86_64"))
// Explicitly disable downloading rules (such as canonical C++ and Java rules) from the network.
cmdFlags = append(cmdFlags, "--experimental_repository_disable_download")
cmdFlags = append(cmdFlags, extraFlags...)
bazelCmd := exec.Command(paths.bazelPath, cmdFlags...)
- bazelCmd.Dir = paths.workspaceDir
+ bazelCmd.Dir = absolutePath(paths.syntheticWorkspaceDir())
bazelCmd.Env = append(os.Environ(), "HOME="+paths.homeDir, pwdPrefix(),
// Disables local host detection of gcc; toolchain information is defined
// explicitly in BUILD files.
@@ -363,31 +362,6 @@
}
}
-// Returns the string contents of a workspace file that should be output
-// adjacent to the main bzl file and build file.
-// This workspace file allows, via local_repository rule, sourcetree-level
-// BUILD targets to be referenced via @sourceroot.
-func (context *bazelContext) workspaceFileContents() []byte {
- formatString := `
-# This file is generated by soong_build. Do not edit.
-local_repository(
- name = "sourceroot",
- path = "%[1]s",
-)
-
-local_repository(
- name = "rules_cc",
- path = "%[1]s/build/bazel/rules_cc",
-)
-
-local_repository(
- name = "bazel_skylib",
- path = "%[1]s/build/bazel/bazel_skylib",
-)
-`
- return []byte(fmt.Sprintf(formatString, context.paths.workspaceDir))
-}
-
func (context *bazelContext) mainBzlFileContents() []byte {
// TODO(cparsons): Define configuration transitions programmatically based
// on available archs.
@@ -398,7 +372,7 @@
def _config_node_transition_impl(settings, attr):
return {
- "//command_line_option:platforms": "@sourceroot//build/bazel/platforms:android_%s" % attr.arch,
+ "//command_line_option:platforms": "@//build/bazel/platforms:android_%s" % attr.arch,
}
_config_node_transition = transition(
@@ -447,18 +421,6 @@
return []byte(contents)
}
-// Returns a "canonicalized" corresponding to the given sourcetree-level label.
-// This abstraction is required because a sourcetree label such as //foo/bar:baz
-// must be referenced via the local repository prefix, such as
-// @sourceroot//foo/bar:baz.
-func canonicalizeLabel(label string) string {
- if strings.HasPrefix(label, "//") {
- return "@sourceroot" + label
- } else {
- return "@sourceroot//" + label
- }
-}
-
func (context *bazelContext) mainBuildFileContents() []byte {
// TODO(cparsons): Map label to attribute programmatically; don't use hard-coded
// architecture mapping.
@@ -487,7 +449,7 @@
labelsByArch := map[string][]string{}
for val, _ := range context.requests {
- labelString := fmt.Sprintf("\"%s\"", canonicalizeLabel(val.label))
+ labelString := fmt.Sprintf("\"@%s\"", val.label)
archString := getArchString(val)
labelsByArch[archString] = append(labelsByArch[archString], labelString)
}
@@ -593,12 +555,24 @@
mainSwitchSection))
}
-// Returns a workspace-relative path containing build-related metadata required
-// for interfacing with Bazel. Example: out/soong/bazel.
+// Returns a path containing build-related metadata required for interfacing
+// with Bazel. Example: out/soong/bazel.
func (p *bazelPaths) intermediatesDir() string {
return filepath.Join(p.buildDir, "bazel")
}
+// Returns the path where the contents of the @soong_injection repository live.
+// It is used by Soong to tell Bazel things it cannot over the command line.
+func (p *bazelPaths) injectedFilesDir() string {
+ return filepath.Join(p.buildDir, "soong_injection")
+}
+
+// Returns the path of the synthetic Bazel workspace that contains a symlink
+// forest composed the whole source tree and BUILD files generated by bp2build.
+func (p *bazelPaths) syntheticWorkspaceDir() string {
+ return filepath.Join(p.buildDir, "workspace")
+}
+
// Issues commands to Bazel to receive results for all cquery requests
// queued in the BazelContext.
func (context *bazelContext) InvokeBazel() error {
@@ -608,47 +582,47 @@
var cqueryErr string
var err error
- intermediatesDirPath := absolutePath(context.paths.intermediatesDir())
- if _, err := os.Stat(intermediatesDirPath); os.IsNotExist(err) {
- err = os.Mkdir(intermediatesDirPath, 0777)
+ soongInjectionPath := absolutePath(context.paths.injectedFilesDir())
+ if _, err := os.Stat(soongInjectionPath); os.IsNotExist(err) {
+ err = os.Mkdir(soongInjectionPath, 0777)
}
-
if err != nil {
return err
}
+
+ err = ioutil.WriteFile(filepath.Join(soongInjectionPath, "WORKSPACE.bazel"), []byte{}, 0666)
+ if err != nil {
+ return err
+ }
+
err = ioutil.WriteFile(
- filepath.Join(intermediatesDirPath, "main.bzl"),
+ filepath.Join(soongInjectionPath, "main.bzl"),
context.mainBzlFileContents(), 0666)
if err != nil {
return err
}
+
err = ioutil.WriteFile(
- filepath.Join(intermediatesDirPath, "BUILD.bazel"),
+ filepath.Join(soongInjectionPath, "BUILD.bazel"),
context.mainBuildFileContents(), 0666)
if err != nil {
return err
}
- cqueryFileRelpath := filepath.Join(context.paths.intermediatesDir(), "buildroot.cquery")
+ cqueryFileRelpath := filepath.Join(context.paths.injectedFilesDir(), "buildroot.cquery")
err = ioutil.WriteFile(
absolutePath(cqueryFileRelpath),
context.cqueryStarlarkFileContents(), 0666)
if err != nil {
return err
}
- err = ioutil.WriteFile(
- filepath.Join(intermediatesDirPath, "WORKSPACE.bazel"),
- context.workspaceFileContents(), 0666)
- if err != nil {
- return err
- }
- buildrootLabel := "//:buildroot"
+ buildrootLabel := "@soong_injection//:buildroot"
cqueryOutput, cqueryErr, err = context.issueBazelCommand(
context.paths,
bazel.CqueryBuildRootRunName,
bazelCommand{"cquery", fmt.Sprintf("kind(rule, deps(%s))", buildrootLabel)},
"--output=starlark",
- "--starlark:file="+cqueryFileRelpath)
- err = ioutil.WriteFile(filepath.Join(intermediatesDirPath, "cquery.out"),
+ "--starlark:file="+absolutePath(cqueryFileRelpath))
+ err = ioutil.WriteFile(filepath.Join(soongInjectionPath, "cquery.out"),
[]byte(cqueryOutput), 0666)
if err != nil {
return err
@@ -702,7 +676,7 @@
_, _, err = context.issueBazelCommand(
context.paths,
bazel.BazelBuildPhonyRootRunName,
- bazelCommand{"build", "//:phonyroot"})
+ bazelCommand{"build", "@soong_injection//:phonyroot"})
if err != nil {
return err
@@ -781,7 +755,7 @@
}
func getCqueryId(key cqueryKey) string {
- return canonicalizeLabel(key.label) + "|" + getArchString(key)
+ return key.label + "|" + getArchString(key)
}
func getArchString(key cqueryKey) string {
diff --git a/android/bazel_handler_test.go b/android/bazel_handler_test.go
index 85f701f..cb25fee 100644
--- a/android/bazel_handler_test.go
+++ b/android/bazel_handler_test.go
@@ -11,7 +11,7 @@
label := "//foo:bar"
arch := Arm64
bazelContext, _ := testBazelContext(t, map[bazelCommand]string{
- bazelCommand{command: "cquery", expression: "kind(rule, deps(//:buildroot))"}: `@sourceroot//foo:bar|arm64>>out/foo/bar.txt`,
+ bazelCommand{command: "cquery", expression: "kind(rule, deps(@soong_injection//:buildroot))"}: `//foo:bar|arm64>>out/foo/bar.txt`,
})
g, ok := bazelContext.GetOutputFiles(label, arch)
if ok {
@@ -35,19 +35,19 @@
if err != nil {
t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
}
- if _, err := os.Stat(filepath.Join(baseDir, "bazel", "main.bzl")); os.IsNotExist(err) {
+ if _, err := os.Stat(filepath.Join(baseDir, "soong_injection", "main.bzl")); os.IsNotExist(err) {
t.Errorf("Expected main.bzl to exist, but it does not")
} else if err != nil {
t.Errorf("Unexpected error stating main.bzl %s", err)
}
- if _, err := os.Stat(filepath.Join(baseDir, "bazel", "BUILD.bazel")); os.IsNotExist(err) {
+ if _, err := os.Stat(filepath.Join(baseDir, "soong_injection", "BUILD.bazel")); os.IsNotExist(err) {
t.Errorf("Expected BUILD.bazel to exist, but it does not")
} else if err != nil {
t.Errorf("Unexpected error stating BUILD.bazel %s", err)
}
- if _, err := os.Stat(filepath.Join(baseDir, "bazel", "WORKSPACE.bazel")); os.IsNotExist(err) {
+ if _, err := os.Stat(filepath.Join(baseDir, "soong_injection", "WORKSPACE.bazel")); os.IsNotExist(err) {
t.Errorf("Expected WORKSPACE.bazel to exist, but it does not")
} else if err != nil {
t.Errorf("Unexpected error stating WORKSPACE.bazel %s", err)
@@ -56,7 +56,7 @@
func TestInvokeBazelPopulatesBuildStatements(t *testing.T) {
bazelContext, _ := testBazelContext(t, map[bazelCommand]string{
- bazelCommand{command: "aquery", expression: "deps(//:buildroot)"}: `
+ bazelCommand{command: "aquery", expression: "deps(@soong_injection//:buildroot)"}: `
{
"artifacts": [{
"id": 1,
@@ -105,7 +105,7 @@
outputBase: "outputbase",
workspaceDir: "workspace_dir",
}
- aqueryCommand := bazelCommand{command: "aquery", expression: "deps(//:buildroot)"}
+ aqueryCommand := bazelCommand{command: "aquery", expression: "deps(@soong_injection//:buildroot)"}
if _, exists := bazelCommandResults[aqueryCommand]; !exists {
bazelCommandResults[aqueryCommand] = "{}\n"
}
diff --git a/android/bazel_paths.go b/android/bazel_paths.go
index 13f4949..9727cc7 100644
--- a/android/bazel_paths.go
+++ b/android/bazel_paths.go
@@ -91,7 +91,7 @@
}
if m, t := SrcIsModuleWithTag(module); m != "" {
l := getOtherModuleLabel(ctx, m, t)
- l.Bp_text = bpText
+ l.OriginalModuleName = bpText
labels.Includes = append(labels.Includes, l)
} else {
ctx.ModuleErrorf("%q, is not a module reference", module)
@@ -156,8 +156,8 @@
func transformSubpackagePath(ctx BazelConversionPathContext, path bazel.Label) bazel.Label {
var newPath bazel.Label
- // Don't transform Bp_text
- newPath.Bp_text = path.Bp_text
+ // Don't transform OriginalModuleName
+ newPath.OriginalModuleName = path.OriginalModuleName
if strings.HasPrefix(path.Label, "//") {
// Assume absolute labels are already correct (e.g. //path/to/some/package:foo.h)
@@ -247,7 +247,7 @@
if m, tag := SrcIsModuleWithTag(p); m != "" {
l := getOtherModuleLabel(ctx, m, tag)
if !InList(l.Label, expandedExcludes) {
- l.Bp_text = fmt.Sprintf(":%s", m)
+ l.OriginalModuleName = fmt.Sprintf(":%s", m)
labels.Includes = append(labels.Includes, l)
}
} else {
diff --git a/android/filegroup.go b/android/filegroup.go
index 2f13ab8..fc6850e 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -105,9 +105,34 @@
return module
}
-func (fg *fileGroup) GenerateAndroidBuildActions(ctx ModuleContext) {
- fg.srcs = PathsForModuleSrcExcludes(ctx, fg.properties.Srcs, fg.properties.Exclude_srcs)
+func (fg *fileGroup) generateBazelBuildActions(ctx ModuleContext) bool {
+ if !fg.MixedBuildsEnabled(ctx) {
+ return false
+ }
+ bazelCtx := ctx.Config().BazelContext
+ filePaths, ok := bazelCtx.GetOutputFiles(fg.GetBazelLabel(ctx, fg), ctx.Arch().ArchType)
+ if !ok {
+ return false
+ }
+
+ bazelOuts := make(Paths, 0, len(filePaths))
+ for _, p := range filePaths {
+ src := PathForBazelOut(ctx, p)
+ bazelOuts = append(bazelOuts, src)
+ }
+
+ fg.srcs = bazelOuts
+
+ return true
+}
+
+func (fg *fileGroup) GenerateAndroidBuildActions(ctx ModuleContext) {
+ if fg.generateBazelBuildActions(ctx) {
+ return
+ }
+
+ fg.srcs = PathsForModuleSrcExcludes(ctx, fg.properties.Srcs, fg.properties.Exclude_srcs)
if fg.properties.Path != nil {
fg.srcs = PathsWithModuleSrcSubDir(ctx, fg.srcs, String(fg.properties.Path))
}
diff --git a/apex/apex.go b/apex/apex.go
index f5e6fa9..6f02c47 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -92,12 +92,6 @@
Multilib apexMultilibProperties
- // List of boot images that are embedded inside this APEX bundle.
- //
- // deprecated: Use Bootclasspath_fragments
- // TODO(b/177892522): Remove after has been replaced by Bootclasspath_fragments
- Boot_images []string
-
// List of bootclasspath fragments that are embedded inside this APEX bundle.
Bootclasspath_fragments []string
@@ -573,7 +567,7 @@
certificateTag = dependencyTag{name: "certificate"}
executableTag = dependencyTag{name: "executable", payload: true}
fsTag = dependencyTag{name: "filesystem", payload: true}
- bootImageTag = dependencyTag{name: "bootImage", payload: true, sourceOnly: true}
+ bcpfTag = dependencyTag{name: "bootclasspathFragment", payload: true, sourceOnly: true}
compatConfigTag = dependencyTag{name: "compatConfig", payload: true, sourceOnly: true}
javaLibTag = dependencyTag{name: "javaLib", payload: true}
jniLibTag = dependencyTag{name: "jniLib", payload: true}
@@ -753,8 +747,7 @@
// Common-arch dependencies come next
commonVariation := ctx.Config().AndroidCommonTarget.Variations()
- ctx.AddFarVariationDependencies(commonVariation, bootImageTag, a.properties.Boot_images...)
- ctx.AddFarVariationDependencies(commonVariation, bootImageTag, a.properties.Bootclasspath_fragments...)
+ ctx.AddFarVariationDependencies(commonVariation, bcpfTag, a.properties.Bootclasspath_fragments...)
ctx.AddFarVariationDependencies(commonVariation, javaLibTag, a.properties.Java_libs...)
ctx.AddFarVariationDependencies(commonVariation, bpfTag, a.properties.Bpfs...)
ctx.AddFarVariationDependencies(commonVariation, fsTag, a.properties.Filesystems...)
@@ -1700,10 +1693,10 @@
} else {
ctx.PropertyErrorf("binaries", "%q is neither cc_binary, rust_binary, (embedded) py_binary, (host) blueprint_go_binary, (host) bootstrap_go_binary, nor sh_binary", depName)
}
- case bootImageTag:
+ case bcpfTag:
{
if _, ok := child.(*java.BootImageModule); !ok {
- ctx.PropertyErrorf("boot_images", "%q is not a boot_image module", depName)
+ ctx.PropertyErrorf("bootclasspath_fragments", "%q is not a boot_image module", depName)
return false
}
bootImageInfo := ctx.OtherModuleProvider(child, java.BootImageInfoProvider).(java.BootImageInfo)
@@ -1711,7 +1704,7 @@
dirInApex := filepath.Join("javalib", arch.String())
for _, f := range files {
androidMkModuleName := "javalib_" + arch.String() + "_" + filepath.Base(f.String())
- // TODO(b/177892522) - consider passing in the boot image module here instead of nil
+ // TODO(b/177892522) - consider passing in the bootclasspath fragment module here instead of nil
af := newApexFile(ctx, f, androidMkModuleName, dirInApex, etc, nil)
filesInfo = append(filesInfo, af)
}
@@ -1932,18 +1925,18 @@
// dependencies. Track them.
return true
} else if java.IsbootImageContentDepTag(depTag) {
- // Add the contents of the boot image to the apex.
+ // Add the contents of the bootclasspath fragment to the apex.
switch child.(type) {
case *java.Library, *java.SdkLibrary:
af := apexFileForJavaModule(ctx, child.(javaModule))
if !af.ok() {
- ctx.PropertyErrorf("boot_images", "boot image content %q is not configured to be compiled into dex", depName)
+ ctx.PropertyErrorf("bootclasspath_fragments", "bootclasspath_fragment content %q is not configured to be compiled into dex", depName)
return false
}
filesInfo = append(filesInfo, af)
return true // track transitive dependencies
default:
- ctx.PropertyErrorf("boot_images", "boot image content %q of type %q is not supported", depName, ctx.OtherModuleType(child))
+ ctx.PropertyErrorf("bootclasspath_fragments", "bootclasspath_fragment content %q of type %q is not supported", depName, ctx.OtherModuleType(child))
}
} else if _, ok := depTag.(android.CopyDirectlyInAnyApexTag); ok {
diff --git a/apex/boot_image_test.go b/apex/boot_image_test.go
index d447d70..e18c2ea 100644
--- a/apex/boot_image_test.go
+++ b/apex/boot_image_test.go
@@ -25,7 +25,7 @@
// Contains tests for boot_image logic from java/boot_image.go as the ART boot image requires
// modules from the ART apex.
-var prepareForTestWithBootImage = android.GroupFixturePreparers(
+var prepareForTestWithBootclasspathFragment = android.GroupFixturePreparers(
java.PrepareForTestWithDexpreopt,
PrepareForTestWithApexBuildComponents,
)
@@ -37,9 +37,9 @@
"system/sepolicy/apex/com.android.art-file_contexts": nil,
})
-func TestBootImages(t *testing.T) {
+func TestBootclasspathFragments(t *testing.T) {
result := android.GroupFixturePreparers(
- prepareForTestWithBootImage,
+ prepareForTestWithBootclasspathFragment,
// Configure some libraries in the art and framework boot images.
java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz", "platform:foo", "platform:bar"),
prepareForTestWithArtApex,
@@ -90,23 +90,23 @@
srcs: ["b.java"],
}
- boot_image {
- name: "art-boot-image",
+ bootclasspath_fragment {
+ name: "art-bootclasspath-fragment",
image_name: "art",
apex_available: [
"com.android.art",
],
}
- boot_image {
- name: "framework-boot-image",
+ bootclasspath_fragment {
+ name: "framework-bootclasspath-fragment",
image_name: "boot",
}
`,
)
- // Make sure that the framework-boot-image is using the correct configuration.
- checkBootImage(t, result, "framework-boot-image", "platform:foo,platform:bar", `
+ // Make sure that the framework-bootclasspath-fragment is using the correct configuration.
+ checkBootclasspathFragment(t, result, "framework-bootclasspath-fragment", "platform:foo,platform:bar", `
test_device/dex_bootjars/android/system/framework/arm/boot-foo.art
test_device/dex_bootjars/android/system/framework/arm/boot-foo.oat
test_device/dex_bootjars/android/system/framework/arm/boot-foo.vdex
@@ -121,8 +121,8 @@
test_device/dex_bootjars/android/system/framework/arm64/boot-bar.vdex
`)
- // Make sure that the art-boot-image is using the correct configuration.
- checkBootImage(t, result, "art-boot-image", "com.android.art:baz,com.android.art:quuz", `
+ // Make sure that the art-bootclasspath-fragment is using the correct configuration.
+ checkBootclasspathFragment(t, result, "art-bootclasspath-fragment", "com.android.art:baz,com.android.art:quuz", `
test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art
test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat
test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex
@@ -138,7 +138,7 @@
`)
}
-func checkBootImage(t *testing.T, result *android.TestResult, moduleName string, expectedConfiguredModules string, expectedBootImageFiles string) {
+func checkBootclasspathFragment(t *testing.T, result *android.TestResult, moduleName string, expectedConfiguredModules string, expectedBootclasspathFragmentFiles string) {
t.Helper()
bootImage := result.ModuleForTests(moduleName, "android_common").Module().(*java.BootImageModule)
@@ -158,12 +158,12 @@
}
}
- android.AssertTrimmedStringEquals(t, "invalid paths for "+moduleName, expectedBootImageFiles, strings.Join(allPaths, "\n"))
+ android.AssertTrimmedStringEquals(t, "invalid paths for "+moduleName, expectedBootclasspathFragmentFiles, strings.Join(allPaths, "\n"))
}
-func TestBootImageInArtApex(t *testing.T) {
+func TestBootclasspathFragmentInArtApex(t *testing.T) {
result := android.GroupFixturePreparers(
- prepareForTestWithBootImage,
+ prepareForTestWithBootclasspathFragment,
prepareForTestWithArtApex,
// Configure some libraries in the art boot image.
@@ -172,11 +172,11 @@
apex {
name: "com.android.art",
key: "com.android.art.key",
- boot_images: [
- "mybootimage",
+ bootclasspath_fragments: [
+ "mybootclasspathfragment",
],
// bar (like foo) should be transitively included in this apex because it is part of the
- // mybootimage boot_image. However, it is kept here to ensure that the apex dedups the files
+ // mybootclasspathfragment boot_image. However, it is kept here to ensure that the apex dedups the files
// correctly.
java_libs: [
"bar",
@@ -209,7 +209,7 @@
}
boot_image {
- name: "mybootimage",
+ name: "mybootclasspathfragment",
image_name: "art",
apex_available: [
"com.android.art",
@@ -218,7 +218,7 @@
// Make sure that a preferred prebuilt doesn't affect the apex.
prebuilt_boot_image {
- name: "mybootimage",
+ name: "mybootclasspathfragment",
image_name: "art",
prefer: true,
apex_available: [
@@ -247,13 +247,13 @@
java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
`bar`,
`com.android.art.key`,
- `mybootimage`,
+ `mybootclasspathfragment`,
})
}
-func TestBootImageInPrebuiltArtApex(t *testing.T) {
+func TestBootclasspathFragmentInPrebuiltArtApex(t *testing.T) {
result := android.GroupFixturePreparers(
- prepareForTestWithBootImage,
+ prepareForTestWithBootclasspathFragment,
prepareForTestWithArtApex,
android.FixtureMergeMockFs(android.MockFS{
@@ -294,7 +294,7 @@
}
prebuilt_boot_image {
- name: "mybootimage",
+ name: "mybootclasspathfragment",
image_name: "art",
apex_available: [
"com.android.art",
@@ -308,23 +308,23 @@
`prebuilt_foo`,
})
- java.CheckModuleDependencies(t, result.TestContext, "mybootimage", "android_common", []string{
+ java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common", []string{
`dex2oatd`,
`prebuilt_bar`,
`prebuilt_foo`,
})
}
-func TestBootImageContentsNoName(t *testing.T) {
+func TestBootclasspathFragmentContentsNoName(t *testing.T) {
result := android.GroupFixturePreparers(
- prepareForTestWithBootImage,
+ prepareForTestWithBootclasspathFragment,
prepareForTestWithMyapex,
).RunTestWithBp(t, `
apex {
name: "myapex",
key: "myapex.key",
- boot_images: [
- "mybootimage",
+ bootclasspath_fragments: [
+ "mybootclasspathfragment",
],
updatable: false,
}
@@ -354,7 +354,7 @@
}
boot_image {
- name: "mybootimage",
+ name: "mybootclasspathfragment",
contents: [
"foo",
"bar",
@@ -374,7 +374,7 @@
java.CheckModuleDependencies(t, result.TestContext, "myapex", "android_common_myapex_image", []string{
`myapex.key`,
- `mybootimage`,
+ `mybootclasspathfragment`,
})
}
diff --git a/bazel/properties.go b/bazel/properties.go
index 4bb2391..5d3299b 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -35,11 +35,27 @@
var productVariableSubstitutionPattern = regexp.MustCompile("%(d|s)")
-// Label is used to represent a Bazel compatible Label. Also stores the original bp text to support
-// string replacement.
+// Label is used to represent a Bazel compatible Label. Also stores the original
+// bp text to support string replacement.
type Label struct {
- Bp_text string
- Label string
+ // The string representation of a Bazel target label. This can be a relative
+ // or fully qualified label. These labels are used for generating BUILD
+ // files with bp2build.
+ Label string
+
+ // The original Soong/Blueprint module name that the label was derived from.
+ // This is used for replacing references to the original name with the new
+ // label, for example in genrule cmds.
+ //
+ // While there is a reversible 1:1 mapping from the module name to Bazel
+ // label with bp2build that could make computing the original module name
+ // from the label automatic, it is not the case for handcrafted targets,
+ // where modules can have a custom label mapping through the { bazel_module:
+ // { label: <label> } } property.
+ //
+ // With handcrafted labels, those modules don't go through bp2build
+ // conversion, but relies on handcrafted targets in the source tree.
+ OriginalModuleName string
}
// LabelList is used to represent a list of Bazel labels.
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index d2a8729..abd79f5 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -14,6 +14,7 @@
"constants.go",
"conversion.go",
"metrics.go",
+ "symlink_forest.go",
],
deps: [
"soong-android",
diff --git a/bp2build/bp2build.go b/bp2build/bp2build.go
index 007d6d8..f1bf648 100644
--- a/bp2build/bp2build.go
+++ b/bp2build/bp2build.go
@@ -28,7 +28,7 @@
outputDir := android.PathForOutput(ctx, "bp2build")
android.RemoveAllOutputDir(outputDir)
- buildToTargets, metrics := GenerateBazelTargets(ctx)
+ buildToTargets, metrics := GenerateBazelTargets(ctx, true)
filesToWrite := CreateBazelFiles(nil, buildToTargets, ctx.mode)
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index b7a2810..08790d1 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -176,7 +176,7 @@
return attributes
}
-func GenerateBazelTargets(ctx *CodegenContext) (map[string]BazelTargets, CodegenMetrics) {
+func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (map[string]BazelTargets, CodegenMetrics) {
buildFileToTargets := make(map[string]BazelTargets)
buildFileToAppend := make(map[string]bool)
@@ -185,9 +185,13 @@
RuleClassCount: make(map[string]int),
}
+ dirs := make(map[string]bool)
+
bpCtx := ctx.Context()
bpCtx.VisitAllModules(func(m blueprint.Module) {
dir := bpCtx.ModuleDir(m)
+ dirs[dir] = true
+
var t BazelTarget
switch ctx.Mode() {
@@ -230,6 +234,17 @@
buildFileToTargets[dir] = append(buildFileToTargets[dir], t)
})
+ if generateFilegroups {
+ // Add a filegroup target that exposes all sources in the subtree of this package
+ // NOTE: This also means we generate a BUILD file for every Android.bp file (as long as it has at least one module)
+ for dir, _ := range dirs {
+ buildFileToTargets[dir] = append(buildFileToTargets[dir], BazelTarget{
+ name: "bp2build_all_srcs",
+ content: `filegroup(name = "bp2build_all_srcs", srcs = glob(["**/*"]))`,
+ ruleClass: "filegroup",
+ })
+ }
+ }
return buildFileToTargets, metrics
}
diff --git a/bp2build/conversion.go b/bp2build/conversion.go
index 6b47cd1..114b668 100644
--- a/bp2build/conversion.go
+++ b/bp2build/conversion.go
@@ -2,6 +2,7 @@
import (
"android/soong/android"
+ "fmt"
"reflect"
"sort"
"strings"
@@ -48,6 +49,10 @@
func createBuildFiles(buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile {
files := make([]BazelFile, 0, len(buildToTargets))
for _, dir := range android.SortedStringKeys(buildToTargets) {
+ if !android.ShouldWriteBuildFileForDir(dir) {
+ fmt.Printf("[bp2build] Not writing generated BUILD file for dir: '%s'\n", dir)
+ continue
+ }
targets := buildToTargets[dir]
sort.Slice(targets, func(i, j int) bool {
// this will cover all bp2build generated targets
diff --git a/bp2build/conversion_test.go b/bp2build/conversion_test.go
index 9fd6817..262a488 100644
--- a/bp2build/conversion_test.go
+++ b/bp2build/conversion_test.go
@@ -19,14 +19,14 @@
"testing"
)
-type filepath struct {
+type bazelFilepath struct {
dir string
basename string
}
func TestCreateBazelFiles_QueryView_AddsTopLevelFiles(t *testing.T) {
files := CreateBazelFiles(map[string]RuleShim{}, map[string]BazelTargets{}, QueryView)
- expectedFilePaths := []filepath{
+ expectedFilePaths := []bazelFilepath{
{
dir: "",
basename: "BUILD",
diff --git a/bp2build/symlink_forest.go b/bp2build/symlink_forest.go
new file mode 100644
index 0000000..15a6335
--- /dev/null
+++ b/bp2build/symlink_forest.go
@@ -0,0 +1,199 @@
+package bp2build
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+
+ "android/soong/shared"
+)
+
+// A tree structure that describes what to do at each directory in the created
+// symlink tree. Currently it is used to enumerate which files/directories
+// should be excluded from symlinking. Each instance of "node" represents a file
+// or a directory. If excluded is true, then that file/directory should be
+// excluded from symlinking. Otherwise, the node is not excluded, but one of its
+// descendants is (otherwise the node in question would not exist)
+type node struct {
+ name string
+ excluded bool // If false, this is just an intermediate node
+ children map[string]*node
+}
+
+// Ensures that the a node for the given path exists in the tree and returns it.
+func ensureNodeExists(root *node, path string) *node {
+ if path == "" {
+ return root
+ }
+
+ if path[len(path)-1] == '/' {
+ path = path[:len(path)-1] // filepath.Split() leaves a trailing slash
+ }
+
+ dir, base := filepath.Split(path)
+
+ // First compute the parent node...
+ dn := ensureNodeExists(root, dir)
+
+ // then create the requested node as its direct child, if needed.
+ if child, ok := dn.children[base]; ok {
+ return child
+ } else {
+ dn.children[base] = &node{base, false, make(map[string]*node)}
+ return dn.children[base]
+ }
+}
+
+// Turns a list of paths to be excluded into a tree made of "node" objects where
+// the specified paths are marked as excluded.
+func treeFromExcludePathList(paths []string) *node {
+ result := &node{"", false, make(map[string]*node)}
+
+ for _, p := range paths {
+ ensureNodeExists(result, p).excluded = true
+ }
+
+ return result
+}
+
+// Calls readdir() and returns it as a map from the basename of the files in dir
+// to os.FileInfo.
+func readdirToMap(dir string) map[string]os.FileInfo {
+ entryList, err := ioutil.ReadDir(dir)
+ result := make(map[string]os.FileInfo)
+
+ if err != nil {
+ if os.IsNotExist(err) {
+ // It's okay if a directory doesn't exist; it just means that one of the
+ // trees to be merged contains parts the other doesn't
+ return result
+ } else {
+ fmt.Fprintf(os.Stderr, "Cannot readdir '%s': %s\n", dir, err)
+ os.Exit(1)
+ }
+ }
+
+ for _, fi := range entryList {
+ result[fi.Name()] = fi
+ }
+
+ return result
+}
+
+// Creates a symbolic link at dst pointing to src
+func symlinkIntoForest(topdir, dst, src string) {
+ err := os.Symlink(shared.JoinPath(topdir, src), shared.JoinPath(topdir, dst))
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Cannot create symlink at '%s' pointing to '%s': %s", dst, src, err)
+ os.Exit(1)
+ }
+}
+
+// Recursively plants a symlink forest at forestDir. The symlink tree will
+// contain every file in buildFilesDir and srcDir excluding the files in
+// exclude. Collects every directory encountered during the traversal of srcDir
+// into acc.
+func plantSymlinkForestRecursive(topdir string, forestDir string, buildFilesDir string, srcDir string, exclude *node, acc *[]string, okay *bool) {
+ if exclude != nil && exclude.excluded {
+ // This directory is not needed, bail out
+ return
+ }
+
+ *acc = append(*acc, srcDir)
+ srcDirMap := readdirToMap(shared.JoinPath(topdir, srcDir))
+ buildFilesMap := readdirToMap(shared.JoinPath(topdir, buildFilesDir))
+
+ allEntries := make(map[string]bool)
+ for n, _ := range srcDirMap {
+ allEntries[n] = true
+ }
+
+ for n, _ := range buildFilesMap {
+ allEntries[n] = true
+ }
+
+ err := os.MkdirAll(shared.JoinPath(topdir, forestDir), 0777)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Cannot mkdir '%s': %s\n", forestDir, err)
+ os.Exit(1)
+ }
+
+ for f, _ := range allEntries {
+ if f[0] == '.' {
+ continue // Ignore dotfiles
+ }
+
+ // The full paths of children in the input trees and in the output tree
+ forestChild := shared.JoinPath(forestDir, f)
+ srcChild := shared.JoinPath(srcDir, f)
+ buildFilesChild := shared.JoinPath(buildFilesDir, f)
+
+ // Descend in the exclusion tree, if there are any excludes left
+ var excludeChild *node
+ if exclude == nil {
+ excludeChild = nil
+ } else {
+ excludeChild = exclude.children[f]
+ }
+
+ srcChildEntry, sExists := srcDirMap[f]
+ buildFilesChildEntry, bExists := buildFilesMap[f]
+ excluded := excludeChild != nil && excludeChild.excluded
+
+ if excluded {
+ continue
+ }
+
+ if !sExists {
+ if buildFilesChildEntry.IsDir() && excludeChild != nil {
+ // Not in the source tree, but we have to exclude something from under
+ // this subtree, so descend
+ plantSymlinkForestRecursive(topdir, forestChild, buildFilesChild, srcChild, excludeChild, acc, okay)
+ } else {
+ // Not in the source tree, symlink BUILD file
+ symlinkIntoForest(topdir, forestChild, buildFilesChild)
+ }
+ } else if !bExists {
+ if srcChildEntry.IsDir() && excludeChild != nil {
+ // Not in the build file tree, but we have to exclude something from
+ // under this subtree, so descend
+ plantSymlinkForestRecursive(topdir, forestChild, buildFilesChild, srcChild, excludeChild, acc, okay)
+ } else {
+ // Not in the build file tree, symlink source tree, carry on
+ symlinkIntoForest(topdir, forestChild, srcChild)
+ }
+ } else if srcChildEntry.IsDir() && buildFilesChildEntry.IsDir() {
+ // Both are directories. Descend.
+ plantSymlinkForestRecursive(topdir, forestChild, buildFilesChild, srcChild, excludeChild, acc, okay)
+ } else if !srcChildEntry.IsDir() && !buildFilesChildEntry.IsDir() {
+ // Neither is a directory. Prioritize BUILD files generated by bp2build
+ // over any BUILD file imported into external/.
+ fmt.Fprintf(os.Stderr, "Both '%s' and '%s' exist, symlinking the former to '%s'\n",
+ buildFilesChild, srcChild, forestChild)
+ symlinkIntoForest(topdir, forestChild, buildFilesChild)
+ } else {
+ // Both exist and one is a file. This is an error.
+ fmt.Fprintf(os.Stderr,
+ "Conflict in workspace symlink tree creation: both '%s' and '%s' exist and exactly one is a directory\n",
+ srcChild, buildFilesChild)
+ *okay = false
+ }
+ }
+}
+
+// Creates a symlink forest by merging the directory tree at "buildFiles" and
+// "srcDir" while excluding paths listed in "exclude". Returns the set of paths
+// under srcDir on which readdir() had to be called to produce the symlink
+// forest.
+func PlantSymlinkForest(topdir string, forest string, buildFiles string, srcDir string, exclude []string) []string {
+ deps := make([]string, 0)
+ os.RemoveAll(shared.JoinPath(topdir, forest))
+ excludeTree := treeFromExcludePathList(exclude)
+ okay := true
+ plantSymlinkForestRecursive(topdir, forest, buildFiles, srcDir, excludeTree, &deps, &okay)
+ if !okay {
+ os.Exit(1)
+ }
+ return deps
+}
diff --git a/bp2build/testing.go b/bp2build/testing.go
index ef3a78f..c4661ea 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -183,6 +183,7 @@
// Helper method for tests to easily access the targets in a dir.
func generateBazelTargetsForDir(codegenCtx *CodegenContext, dir string) BazelTargets {
- buildFileToTargets, _ := GenerateBazelTargets(codegenCtx)
+ // TODO: Set generateFilegroups to true and/or remove the generateFilegroups argument completely
+ buildFileToTargets, _ := GenerateBazelTargets(codegenCtx, false)
return buildFileToTargets[dir]
}
diff --git a/cc/builder.go b/cc/builder.go
index da8501c..ad7e1e6 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -968,7 +968,7 @@
func transformBinaryPrefixSymbols(ctx android.ModuleContext, prefix string, inputFile android.Path,
flags builderFlags, outputFile android.WritablePath) {
- objcopyCmd := gccCmd(flags.toolchain, "objcopy")
+ objcopyCmd := "${config.ClangBin}/llvm-objcopy"
ctx.Build(pctx, android.BuildParams{
Rule: prefixSymbols,
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 26d1f8e..db696ef 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -3778,59 +3778,6 @@
android.AssertStringDoesContain(t, "min sdk version", cFlags, "-target aarch64-linux-android29")
}
-func TestMinSdkVersionsOfCrtObjects(t *testing.T) {
- ctx := testCc(t, `
- cc_object {
- name: "crt_foo",
- srcs: ["foo.c"],
- crt: true,
- stl: "none",
- min_sdk_version: "28",
-
- }`)
-
- arch := "android_arm64_armv8-a"
- for _, v := range []string{"", "28", "29", "30", "current"} {
- var variant string
- if v == "" {
- variant = arch
- } else {
- variant = arch + "_sdk_" + v
- }
- cflags := ctx.ModuleForTests("crt_foo", variant).Rule("cc").Args["cFlags"]
- vNum := v
- if v == "current" || v == "" {
- vNum = "10000"
- }
- expected := "-target aarch64-linux-android" + vNum + " "
- android.AssertStringDoesContain(t, "cflag", cflags, expected)
- }
-}
-
-func TestUseCrtObjectOfCorrectVersion(t *testing.T) {
- ctx := testCc(t, `
- cc_binary {
- name: "bin",
- srcs: ["foo.c"],
- stl: "none",
- min_sdk_version: "29",
- sdk_version: "current",
- }
- `)
-
- // Sdk variant uses the crt object of the matching min_sdk_version
- variant := "android_arm64_armv8-a_sdk"
- crt := ctx.ModuleForTests("bin", variant).Rule("ld").Args["crtBegin"]
- android.AssertStringDoesContain(t, "crt dep of sdk variant", crt,
- variant+"_29/crtbegin_dynamic.o")
-
- // platform variant uses the crt object built for platform
- variant = "android_arm64_armv8-a"
- crt = ctx.ModuleForTests("bin", variant).Rule("ld").Args["crtBegin"]
- android.AssertStringDoesContain(t, "crt dep of platform variant", crt,
- variant+"/crtbegin_dynamic.o")
-}
-
type MemtagNoteType int
const (
diff --git a/cc/object_test.go b/cc/object_test.go
index f82d544..0e5508a 100644
--- a/cc/object_test.go
+++ b/cc/object_test.go
@@ -19,6 +19,60 @@
"testing"
)
+func TestMinSdkVersionsOfCrtObjects(t *testing.T) {
+ ctx := testCc(t, `
+ cc_object {
+ name: "crt_foo",
+ srcs: ["foo.c"],
+ crt: true,
+ stl: "none",
+ min_sdk_version: "28",
+
+ }`)
+
+ arch := "android_arm64_armv8-a"
+ for _, v := range []string{"", "28", "29", "30", "current"} {
+ var variant string
+ // platform variant
+ if v == "" {
+ variant = arch
+ } else {
+ variant = arch + "_sdk_" + v
+ }
+ cflags := ctx.ModuleForTests("crt_foo", variant).Rule("cc").Args["cFlags"]
+ vNum := v
+ if v == "current" || v == "" {
+ vNum = "10000"
+ }
+ expected := "-target aarch64-linux-android" + vNum + " "
+ android.AssertStringDoesContain(t, "cflag", cflags, expected)
+ }
+}
+
+func TestUseCrtObjectOfCorrectVersion(t *testing.T) {
+ ctx := testCc(t, `
+ cc_binary {
+ name: "bin",
+ srcs: ["foo.c"],
+ stl: "none",
+ min_sdk_version: "29",
+ sdk_version: "current",
+ }
+ `)
+
+ // Sdk variant uses the crt object of the matching min_sdk_version
+ variant := "android_arm64_armv8-a_sdk"
+ crt := ctx.ModuleForTests("bin", variant).Rule("ld").Args["crtBegin"]
+ android.AssertStringDoesContain(t, "crt dep of sdk variant", crt,
+ variant+"_29/crtbegin_dynamic.o")
+
+ // platform variant uses the crt object built for platform
+ variant = "android_arm64_armv8-a"
+ crt = ctx.ModuleForTests("bin", variant).Rule("ld").Args["crtBegin"]
+ android.AssertStringDoesContain(t, "crt dep of platform variant", crt,
+ variant+"/crtbegin_dynamic.o")
+}
+
func TestLinkerScript(t *testing.T) {
t.Run("script", func(t *testing.T) {
testCc(t, `
diff --git a/cc/stub_library.go b/cc/stub_library.go
index 76d236c..81c8be7 100644
--- a/cc/stub_library.go
+++ b/cc/stub_library.go
@@ -30,7 +30,7 @@
}
// Check if the module defines stub, or itself is stub
-func isStubTarget(m *Module) bool {
+func IsStubTarget(m *Module) bool {
if m.IsStubs() || m.HasStubsVariants() {
return true
}
@@ -61,7 +61,7 @@
// Visit all generated soong modules and store stub library file names.
ctx.VisitAllModules(func(module android.Module) {
if m, ok := module.(*Module); ok {
- if isStubTarget(m) {
+ if IsStubTarget(m) {
if name := getInstalledFileName(m); name != "" {
s.stubLibraryMap[name] = true
}
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index c9cab13..044689e 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -25,6 +25,7 @@
"android/soong/bp2build"
"android/soong/shared"
+
"github.com/google/blueprint/bootstrap"
"github.com/google/blueprint/deptools"
@@ -174,7 +175,7 @@
}
func doChosenActivity(configuration android.Config, extraNinjaDeps []string) string {
- bazelConversionRequested := configuration.IsEnvTrue("GENERATE_BAZEL_FILES") || bp2buildMarker != ""
+ bazelConversionRequested := bp2buildMarker != ""
mixedModeBuild := configuration.BazelContext.BazelEnabled()
generateQueryView := bazelQueryViewDir != ""
jsonModuleFile := configuration.Getenv("SOONG_DUMP_JSON_MODULE_GRAPH")
@@ -392,10 +393,39 @@
ninjaDeps := bootstrap.RunBlueprint(blueprintArgs, bp2buildCtx.Context, configuration)
ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
- for _, globPath := range bp2buildCtx.Globs() {
- ninjaDeps = append(ninjaDeps, globPath.FileListFile(configuration.BuildDir()))
+ ninjaDeps = append(ninjaDeps, bootstrap.GlobFileListFiles(configuration)...)
+
+ // Run the code-generation phase to convert BazelTargetModules to BUILD files
+ // and print conversion metrics to the user.
+ codegenContext := bp2build.NewCodegenContext(configuration, *bp2buildCtx, bp2build.Bp2Build)
+ metrics := bp2build.Codegen(codegenContext)
+
+ generatedRoot := shared.JoinPath(configuration.BuildDir(), "bp2build")
+ workspaceRoot := shared.JoinPath(configuration.BuildDir(), "workspace")
+
+ excludes := []string{
+ "bazel-bin",
+ "bazel-genfiles",
+ "bazel-out",
+ "bazel-testlogs",
+ "bazel-" + filepath.Base(topDir),
}
+ if bootstrap.CmdlineArgs.NinjaBuildDir[0] != '/' {
+ excludes = append(excludes, bootstrap.CmdlineArgs.NinjaBuildDir)
+ }
+
+ symlinkForestDeps := bp2build.PlantSymlinkForest(
+ topDir, workspaceRoot, generatedRoot, configuration.SrcDir(), excludes)
+
+ // Only report metrics when in bp2build mode. The metrics aren't relevant
+ // for queryview, since that's a total repo-wide conversion and there's a
+ // 1:1 mapping for each module.
+ metrics.Print()
+
+ ninjaDeps = append(ninjaDeps, codegenContext.AdditionalNinjaDeps()...)
+ ninjaDeps = append(ninjaDeps, symlinkForestDeps...)
+
depFile := bp2buildMarker + ".d"
err = deptools.WriteDepFile(shared.JoinPath(topDir, depFile), bp2buildMarker, ninjaDeps)
if err != nil {
@@ -403,17 +433,6 @@
os.Exit(1)
}
- // Run the code-generation phase to convert BazelTargetModules to BUILD files
- // and print conversion metrics to the user.
- codegenContext := bp2build.NewCodegenContext(configuration, *bp2buildCtx, bp2build.Bp2Build)
- metrics := bp2build.Codegen(codegenContext)
-
- // Only report metrics when in bp2build mode. The metrics aren't relevant
- // for queryview, since that's a total repo-wide conversion and there's a
- // 1:1 mapping for each module.
- metrics.Print()
-
- extraNinjaDeps = append(extraNinjaDeps, codegenContext.AdditionalNinjaDeps()...)
if bp2buildMarker != "" {
touch(shared.JoinPath(topDir, bp2buildMarker))
} else {
diff --git a/cmd/soong_build/queryview.go b/cmd/soong_build/queryview.go
index edc8a42..e2ce772 100644
--- a/cmd/soong_build/queryview.go
+++ b/cmd/soong_build/queryview.go
@@ -27,7 +27,7 @@
// Ignore metrics reporting for queryview, since queryview is already a full-repo
// conversion and can use data from bazel query directly.
- buildToTargets, _ := bp2build.GenerateBazelTargets(ctx)
+ buildToTargets, _ := bp2build.GenerateBazelTargets(ctx, true)
filesToWrite := bp2build.CreateBazelFiles(ruleShims, buildToTargets, bp2build.QueryView)
for _, f := range filesToWrite {
diff --git a/filesystem/Android.bp b/filesystem/Android.bp
index 3cdaa64..38684d3 100644
--- a/filesystem/Android.bp
+++ b/filesystem/Android.bp
@@ -9,11 +9,13 @@
"blueprint",
"soong",
"soong-android",
+ "soong-linkerconfig",
],
srcs: [
"bootimg.go",
"filesystem.go",
"logical_partition.go",
+ "system_image.go",
"vbmeta.go",
"testing.go",
],
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index cf98717..b2caa51 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -31,6 +31,7 @@
func registerBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("android_filesystem", filesystemFactory)
+ ctx.RegisterModuleType("android_system_image", systemImageFactory)
}
type filesystem struct {
@@ -39,6 +40,9 @@
properties filesystemProperties
+ // Function that builds extra files under the root directory and returns the files
+ buildExtraFiles func(ctx android.ModuleContext, root android.OutputPath) android.OutputPaths
+
output android.OutputPath
installDir android.InstallPath
}
@@ -87,10 +91,14 @@
// partitions like system.img. For example, cc_library modules are placed under ./lib[64] directory.
func filesystemFactory() android.Module {
module := &filesystem{}
+ initFilesystemModule(module)
+ return module
+}
+
+func initFilesystemModule(module *filesystem) {
module.AddProperties(&module.properties)
android.InitPackageModule(module)
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
- return module
}
var dependencyTag = struct {
@@ -148,7 +156,7 @@
ctx.InstallFile(f.installDir, f.installFileName(), f.output)
}
-// root zip will contain stuffs like dirs or symlinks.
+// root zip will contain extra files/dirs that are not from the `deps` property.
func (f *filesystem) buildRootZip(ctx android.ModuleContext) android.OutputPath {
rootDir := android.PathForModuleGen(ctx, "root").OutputPath
builder := android.NewRuleBuilder(pctx, ctx)
@@ -182,15 +190,34 @@
builder.Command().Text("ln -sf").Text(proptools.ShellEscape(target)).Text(dst.String())
}
- zipOut := android.PathForModuleGen(ctx, "root.zip").OutputPath
+ // create extra files if there's any
+ rootForExtraFiles := android.PathForModuleGen(ctx, "root-extra").OutputPath
+ var extraFiles android.OutputPaths
+ if f.buildExtraFiles != nil {
+ extraFiles = f.buildExtraFiles(ctx, rootForExtraFiles)
+ for _, f := range extraFiles {
+ rel, _ := filepath.Rel(rootForExtraFiles.String(), f.String())
+ if strings.HasPrefix(rel, "..") {
+ panic(fmt.Errorf("%q is not under %q\n", f, rootForExtraFiles))
+ }
+ }
+ }
- builder.Command().
- BuiltTool("soong_zip").
- FlagWithOutput("-o ", zipOut).
+ // Zip them all
+ zipOut := android.PathForModuleGen(ctx, "root.zip").OutputPath
+ zipCommand := builder.Command().BuiltTool("soong_zip")
+ zipCommand.FlagWithOutput("-o ", zipOut).
FlagWithArg("-C ", rootDir.String()).
Flag("-L 0"). // no compression because this will be unzipped soon
FlagWithArg("-D ", rootDir.String()).
Flag("-d") // include empty directories
+ if len(extraFiles) > 0 {
+ zipCommand.FlagWithArg("-C ", rootForExtraFiles.String())
+ for _, f := range extraFiles {
+ zipCommand.FlagWithInput("-f ", f)
+ }
+ }
+
builder.Command().Text("rm -rf").Text(rootDir.String())
builder.Build("zip_root", fmt.Sprintf("zipping root contents for %s", ctx.ModuleName()))
diff --git a/filesystem/filesystem_test.go b/filesystem/filesystem_test.go
index 880b177..e78fdff 100644
--- a/filesystem/filesystem_test.go
+++ b/filesystem/filesystem_test.go
@@ -19,6 +19,7 @@
"testing"
"android/soong/android"
+ "android/soong/cc"
)
func TestMain(m *testing.M) {
@@ -27,6 +28,7 @@
var fixture = android.GroupFixturePreparers(
android.PrepareForIntegrationTestWithAndroid,
+ cc.PrepareForIntegrationTestWithCc,
PrepareForTestWithFilesystemBuildComponents,
)
@@ -40,3 +42,35 @@
// produces "myfilesystem.img"
result.ModuleForTests("myfilesystem", "android_common").Output("myfilesystem.img")
}
+
+func TestFileSystemFillsLinkerConfigWithStubLibs(t *testing.T) {
+ result := fixture.RunTestWithBp(t, `
+ android_system_image {
+ name: "myfilesystem",
+ deps: [
+ "libfoo",
+ "libbar",
+ ],
+ linker_config_src: "linker.config.json",
+ }
+
+ cc_library {
+ name: "libfoo",
+ stubs: {
+ symbol_file: "libfoo.map.txt",
+ },
+ }
+
+ cc_library {
+ name: "libbar",
+ }
+ `)
+
+ module := result.ModuleForTests("myfilesystem", "android_common")
+ output := module.Output("system/etc/linker.config.pb")
+
+ android.AssertStringDoesContain(t, "linker.config.pb should have libfoo",
+ output.RuleParams.Command, "libfoo.so")
+ android.AssertStringDoesNotContain(t, "linker.config.pb should not have libbar",
+ output.RuleParams.Command, "libbar.so")
+}
diff --git a/filesystem/system_image.go b/filesystem/system_image.go
new file mode 100644
index 0000000..a7c9143
--- /dev/null
+++ b/filesystem/system_image.go
@@ -0,0 +1,68 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// 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 filesystem
+
+import (
+ "android/soong/android"
+ "android/soong/linkerconfig"
+)
+
+type systemImage struct {
+ filesystem
+
+ properties systemImageProperties
+}
+
+type systemImageProperties struct {
+ // Path to the input linker config json file.
+ Linker_config_src *string
+}
+
+// android_system_image is a specialization of android_filesystem for the 'system' partition.
+// Currently, the only difference is the inclusion of linker.config.pb file which specifies
+// the provided and the required libraries to and from APEXes.
+func systemImageFactory() android.Module {
+ module := &systemImage{}
+ module.AddProperties(&module.properties)
+ module.filesystem.buildExtraFiles = module.buildExtraFiles
+ initFilesystemModule(&module.filesystem)
+ return module
+}
+
+func (s *systemImage) buildExtraFiles(ctx android.ModuleContext, root android.OutputPath) android.OutputPaths {
+ lc := s.buildLinkerConfigFile(ctx, root)
+ // Add more files if needed
+ return []android.OutputPath{lc}
+}
+
+func (s *systemImage) buildLinkerConfigFile(ctx android.ModuleContext, root android.OutputPath) android.OutputPath {
+ input := android.PathForModuleSrc(ctx, android.String(s.properties.Linker_config_src))
+ output := root.Join(ctx, "system", "etc", "linker.config.pb")
+ var otherModules []android.Module
+ ctx.WalkDeps(func(child, parent android.Module) bool {
+ // Don't track direct dependencies that aren't not packaged
+ if parent == s {
+ if pi, ok := ctx.OtherModuleDependencyTag(child).(android.PackagingItem); !ok || !pi.IsPackagingItem() {
+ return false
+ }
+ }
+ otherModules = append(otherModules, child)
+ return true
+ })
+ builder := android.NewRuleBuilder(pctx, ctx)
+ linkerconfig.BuildLinkerConfig(ctx, builder, input, otherModules, output)
+ builder.Build("conv_linker_config", "Generate linker config protobuf "+output.String())
+ return output
+}
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 3a9aecc..77dae75 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -856,8 +856,8 @@
cmd = strings.Replace(cmd, "$(locations)", fmt.Sprintf("$(locations %s)", tools.Value.Includes[0].Label), -1)
}
for _, l := range allReplacements.Includes {
- bpLoc := fmt.Sprintf("$(location %s)", l.Bp_text)
- bpLocs := fmt.Sprintf("$(locations %s)", l.Bp_text)
+ bpLoc := fmt.Sprintf("$(location %s)", l.OriginalModuleName)
+ bpLocs := fmt.Sprintf("$(locations %s)", l.OriginalModuleName)
bazelLoc := fmt.Sprintf("$(location %s)", l.Label)
bazelLocs := fmt.Sprintf("$(locations %s)", l.Label)
cmd = strings.Replace(cmd, bpLoc, bazelLoc, -1)
diff --git a/java/boot_image.go b/java/boot_image.go
index 0c47976..78215f0 100644
--- a/java/boot_image.go
+++ b/java/boot_image.go
@@ -84,6 +84,8 @@
//
// The order of this list matters as it is the order that is used in the bootclasspath.
Contents []string
+
+ Hidden_api HiddenAPIFlagFileProperties
}
type BootImageModule struct {
@@ -213,6 +215,9 @@
}
func (b *BootImageModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ // Perform hidden API processing.
+ b.generateHiddenAPIBuildActions(ctx)
+
// Nothing to do if skipping the dexpreopt of boot image jars.
if SkipDexpreoptBootJars(ctx) {
return
@@ -253,6 +258,15 @@
return imageConfig
}
+// generateHiddenAPIBuildActions generates all the hidden API related build rules.
+func (b *BootImageModule) generateHiddenAPIBuildActions(ctx android.ModuleContext) {
+ // Resolve the properties to paths.
+ flagFileInfo := b.properties.Hidden_api.hiddenAPIFlagFileInfo(ctx)
+
+ // Store the information for use by platform_bootclasspath.
+ ctx.SetProvider(hiddenAPIFlagFileInfoProvider, flagFileInfo)
+}
+
type bootImageMemberType struct {
android.SdkMemberTypeBase
}
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index 7cf082b..ebf541d 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -16,6 +16,7 @@
import (
"android/soong/android"
+ "github.com/google/blueprint"
)
// Contains support for processing hiddenAPI in a modular fashion.
@@ -63,7 +64,7 @@
func (p *HiddenAPIFlagFileProperties) hiddenAPIFlagFileInfo(ctx android.ModuleContext) hiddenAPIFlagFileInfo {
info := hiddenAPIFlagFileInfo{categoryToPaths: map[*hiddenAPIFlagFileCategory]android.Paths{}}
for _, category := range hiddenAPIFlagFileCategories {
- paths := android.PathsForModuleSrc(ctx, category.propertyAccessor(p))
+ paths := android.PathsForModuleSrc(ctx, category.propertyValueReader(p))
info.categoryToPaths[category] = paths
}
return info
@@ -73,9 +74,9 @@
// propertyName is the name of the property for this category.
propertyName string
- // propertyAccessor retrieves the value of the property for this category from the set of
+ // propertyValueReader retrieves the value of the property for this category from the set of
// properties.
- propertyAccessor func(properties *HiddenAPIFlagFileProperties) []string
+ propertyValueReader func(properties *HiddenAPIFlagFileProperties) []string
// commandMutator adds the appropriate command line options for this category to the supplied
// command
@@ -86,7 +87,7 @@
// See HiddenAPIFlagFileProperties.Unsupported
{
propertyName: "unsupported",
- propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string {
+ propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
return properties.Unsupported
},
commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
@@ -96,7 +97,7 @@
// See HiddenAPIFlagFileProperties.Removed
{
propertyName: "removed",
- propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string {
+ propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
return properties.Removed
},
commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
@@ -106,7 +107,7 @@
// See HiddenAPIFlagFileProperties.Max_target_r_low_priority
{
propertyName: "max_target_r_low_priority",
- propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string {
+ propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
return properties.Max_target_r_low_priority
},
commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
@@ -116,7 +117,7 @@
// See HiddenAPIFlagFileProperties.Max_target_q
{
propertyName: "max_target_q",
- propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string {
+ propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
return properties.Max_target_q
},
commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
@@ -126,7 +127,7 @@
// See HiddenAPIFlagFileProperties.Max_target_p
{
propertyName: "max_target_p",
- propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string {
+ propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
return properties.Max_target_p
},
commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
@@ -136,7 +137,7 @@
// See HiddenAPIFlagFileProperties.Max_target_o_low_priority
{
propertyName: "max_target_o_low_priority",
- propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string {
+ propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
return properties.Max_target_o_low_priority
},
commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
@@ -146,7 +147,7 @@
// See HiddenAPIFlagFileProperties.Blocked
{
propertyName: "blocked",
- propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string {
+ propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
return properties.Blocked
},
commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
@@ -156,7 +157,7 @@
// See HiddenAPIFlagFileProperties.Unsupported_packages
{
propertyName: "unsupported_packages",
- propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string {
+ propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
return properties.Unsupported_packages
},
commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
@@ -172,6 +173,14 @@
categoryToPaths map[*hiddenAPIFlagFileCategory]android.Paths
}
+func (i *hiddenAPIFlagFileInfo) append(other hiddenAPIFlagFileInfo) {
+ for _, category := range hiddenAPIFlagFileCategories {
+ i.categoryToPaths[category] = append(i.categoryToPaths[category], other.categoryToPaths[category]...)
+ }
+}
+
+var hiddenAPIFlagFileInfoProvider = blueprint.NewProvider(hiddenAPIFlagFileInfo{})
+
// ruleToGenerateHiddenApiFlags creates a rule to create the monolithic hidden API flags from the
// flags from all the modules, the stub flags, augmented with some additional configuration files.
//
diff --git a/java/java.go b/java/java.go
index ee4f2eb..adb0c56 100644
--- a/java/java.go
+++ b/java/java.go
@@ -27,6 +27,7 @@
"github.com/google/blueprint/proptools"
"android/soong/android"
+ "android/soong/cc"
"android/soong/dexpreopt"
"android/soong/java/config"
"android/soong/tradefed"
@@ -708,6 +709,9 @@
// Test options.
Test_options TestOptions
+
+ // Names of modules containing JNI libraries that should be installed alongside the test.
+ Jni_libs []string
}
type hostTestProperties struct {
@@ -769,6 +773,13 @@
}
}
+ if len(j.testProperties.Jni_libs) > 0 {
+ for _, target := range ctx.MultiTargets() {
+ sharedLibVariations := append(target.Variations(), blueprint.Variation{Mutator: "link", Variation: "shared"})
+ ctx.AddFarVariationDependencies(sharedLibVariations, jniLibTag, j.testProperties.Jni_libs...)
+ }
+ }
+
j.deps(ctx)
}
@@ -793,6 +804,29 @@
j.data = append(j.data, android.OutputFileForModule(ctx, dep, ""))
})
+ ctx.VisitDirectDepsWithTag(jniLibTag, func(dep android.Module) {
+ sharedLibInfo := ctx.OtherModuleProvider(dep, cc.SharedLibraryInfoProvider).(cc.SharedLibraryInfo)
+ if sharedLibInfo.SharedLibrary != nil {
+ // Copy to an intermediate output directory to append "lib[64]" to the path,
+ // so that it's compatible with the default rpath values.
+ var relPath string
+ if sharedLibInfo.Target.Arch.ArchType.Multilib == "lib64" {
+ relPath = filepath.Join("lib64", sharedLibInfo.SharedLibrary.Base())
+ } else {
+ relPath = filepath.Join("lib", sharedLibInfo.SharedLibrary.Base())
+ }
+ relocatedLib := android.PathForModuleOut(ctx, "relocated").Join(ctx, relPath)
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Input: sharedLibInfo.SharedLibrary,
+ Output: relocatedLib,
+ })
+ j.data = append(j.data, relocatedLib)
+ } else {
+ ctx.PropertyErrorf("jni_libs", "%q of type %q is not supported", dep.Name(), ctx.OtherModuleType(dep))
+ }
+ })
+
j.Library.GenerateAndroidBuildActions(ctx)
}
diff --git a/java/java_test.go b/java/java_test.go
index 0523458..e7ea4ef 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -20,6 +20,7 @@
"path/filepath"
"reflect"
"regexp"
+ "runtime"
"strconv"
"strings"
"testing"
@@ -462,6 +463,38 @@
}
}
+func TestTest(t *testing.T) {
+ ctx, _ := testJava(t, `
+ java_test_host {
+ name: "foo",
+ srcs: ["a.java"],
+ jni_libs: ["libjni"],
+ }
+
+ cc_library_shared {
+ name: "libjni",
+ host_supported: true,
+ device_supported: false,
+ stl: "none",
+ }
+ `)
+
+ buildOS := android.BuildOs.String()
+
+ foo := ctx.ModuleForTests("foo", buildOS+"_common").Module().(*TestHost)
+
+ expected := "lib64/libjni.so"
+ if runtime.GOOS == "darwin" {
+ expected = "lib64/libjni.dylib"
+ }
+
+ fooTestData := foo.data
+ if len(fooTestData) != 1 || fooTestData[0].Rel() != expected {
+ t.Errorf(`expected foo test data relative path [%q], got %q`,
+ expected, fooTestData.Strings())
+ }
+}
+
func TestHostBinaryNoJavaDebugInfoOverride(t *testing.T) {
bp := `
java_library {
diff --git a/java/lint.go b/java/lint.go
index aa308e6..a77daa8 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -200,7 +200,7 @@
srcJarList := zipSyncCmd(ctx, rule, srcJarDir, l.srcJars)
cmd := rule.Command().
- BuiltTool("lint-project-xml").
+ BuiltTool("lint_project_xml").
FlagWithOutput("--project_out ", projectXMLPath).
FlagWithOutput("--config_out ", configXMLPath).
FlagWithArg("--name ", ctx.ModuleName())
@@ -279,6 +279,19 @@
return manifestPath
}
+func (l *linter) getBaselineFilepath(ctx android.ModuleContext) android.OptionalPath {
+ var lintBaseline android.OptionalPath
+ if lintFilename := proptools.StringDefault(l.properties.Lint.Baseline_filename, "lint-baseline.xml"); lintFilename != "" {
+ if String(l.properties.Lint.Baseline_filename) != "" {
+ // if manually specified, we require the file to exist
+ lintBaseline = android.OptionalPathForPath(android.PathForModuleSrc(ctx, lintFilename))
+ } else {
+ lintBaseline = android.ExistentPathForSource(ctx, ctx.ModuleDir(), lintFilename)
+ }
+ }
+ return lintBaseline
+}
+
func (l *linter) lint(ctx android.ModuleContext) {
if !l.enabled() {
return
@@ -381,17 +394,9 @@
cmd.FlagWithArg("--check ", checkOnly)
}
- if lintFilename := proptools.StringDefault(l.properties.Lint.Baseline_filename, "lint-baseline.xml"); lintFilename != "" {
- var lintBaseline android.OptionalPath
- if String(l.properties.Lint.Baseline_filename) != "" {
- // if manually specified, we require the file to exist
- lintBaseline = android.OptionalPathForPath(android.PathForModuleSrc(ctx, lintFilename))
- } else {
- lintBaseline = android.ExistentPathForSource(ctx, ctx.ModuleDir(), lintFilename)
- }
- if lintBaseline.Valid() {
- cmd.FlagWithInput("--baseline ", lintBaseline.Path())
- }
+ lintBaseline := l.getBaselineFilepath(ctx)
+ if lintBaseline.Valid() {
+ cmd.FlagWithInput("--baseline ", lintBaseline.Path())
}
cmd.Text("|| (").Text("if [ -e").Input(text).Text("]; then cat").Input(text).Text("; fi; exit 7)")
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index cb8ad68..ba758dd 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -258,7 +258,7 @@
}
})
- b.generateHiddenAPIBuildActions(ctx, b.configuredModules)
+ b.generateHiddenAPIBuildActions(ctx, b.configuredModules, b.fragments)
// Nothing to do if skipping the dexpreopt of boot image jars.
if SkipDexpreoptBootJars(ctx) {
@@ -286,7 +286,7 @@
}
// generateHiddenAPIBuildActions generates all the hidden API related build rules.
-func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, modules []android.Module) {
+func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, modules []android.Module, fragments []android.Module) {
// Save the paths to the monolithic files for retrieval via OutputFiles().
b.hiddenAPIFlagsCSV = hiddenAPISingletonPaths(ctx).flags
@@ -338,11 +338,20 @@
moduleSpecificFlagsPaths = append(moduleSpecificFlagsPaths, module.flagsCSV())
}
- augmentationInfo := b.properties.Hidden_api.hiddenAPIFlagFileInfo(ctx)
+ flagFileInfo := b.properties.Hidden_api.hiddenAPIFlagFileInfo(ctx)
+ for _, fragment := range fragments {
+ if ctx.OtherModuleHasProvider(fragment, hiddenAPIFlagFileInfoProvider) {
+ info := ctx.OtherModuleProvider(fragment, hiddenAPIFlagFileInfoProvider).(hiddenAPIFlagFileInfo)
+ flagFileInfo.append(info)
+ }
+ }
+
+ // Store the information for testing.
+ ctx.SetProvider(hiddenAPIFlagFileInfoProvider, flagFileInfo)
outputPath := hiddenAPISingletonPaths(ctx).flags
baseFlagsPath := hiddenAPISingletonPaths(ctx).stubFlags
- ruleToGenerateHiddenApiFlags(ctx, outputPath, baseFlagsPath, moduleSpecificFlagsPaths, augmentationInfo)
+ ruleToGenerateHiddenApiFlags(ctx, outputPath, baseFlagsPath, moduleSpecificFlagsPaths, flagFileInfo)
b.generateHiddenAPIIndexRules(ctx, hiddenAPISupportingModules)
b.generatedHiddenAPIMetadataRules(ctx, hiddenAPISupportingModules)
diff --git a/java/platform_bootclasspath_test.go b/java/platform_bootclasspath_test.go
index e51b049..955e387 100644
--- a/java/platform_bootclasspath_test.go
+++ b/java/platform_bootclasspath_test.go
@@ -15,6 +15,8 @@
package java
import (
+ "fmt"
+ "strings"
"testing"
"android/soong/android"
@@ -132,6 +134,96 @@
})
}
+func TestPlatformBootclasspath_Fragments(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForTestWithPlatformBootclasspath,
+ android.FixtureWithRootAndroidBp(`
+ platform_bootclasspath {
+ name: "platform-bootclasspath",
+ fragments: [
+ {module:"bar-fragment"},
+ ],
+ hidden_api: {
+ unsupported: [
+ "unsupported.txt",
+ ],
+ removed: [
+ "removed.txt",
+ ],
+ max_target_r_low_priority: [
+ "max-target-r-low-priority.txt",
+ ],
+ max_target_q: [
+ "max-target-q.txt",
+ ],
+ max_target_p: [
+ "max-target-p.txt",
+ ],
+ max_target_o_low_priority: [
+ "max-target-o-low-priority.txt",
+ ],
+ blocked: [
+ "blocked.txt",
+ ],
+ unsupported_packages: [
+ "unsupported-packages.txt",
+ ],
+ },
+ }
+
+ bootclasspath_fragment {
+ name: "bar-fragment",
+ contents: ["bar"],
+ hidden_api: {
+ unsupported: [
+ "bar-unsupported.txt",
+ ],
+ removed: [
+ "bar-removed.txt",
+ ],
+ max_target_r_low_priority: [
+ "bar-max-target-r-low-priority.txt",
+ ],
+ max_target_q: [
+ "bar-max-target-q.txt",
+ ],
+ max_target_p: [
+ "bar-max-target-p.txt",
+ ],
+ max_target_o_low_priority: [
+ "bar-max-target-o-low-priority.txt",
+ ],
+ blocked: [
+ "bar-blocked.txt",
+ ],
+ unsupported_packages: [
+ "bar-unsupported-packages.txt",
+ ],
+ },
+ }
+
+ java_library {
+ name: "bar",
+ srcs: ["a.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ compile_dex: true,
+ }
+ `),
+ ).RunTest(t)
+
+ pbcp := result.Module("platform-bootclasspath", "android_common")
+ info := result.ModuleProvider(pbcp, hiddenAPIFlagFileInfoProvider).(hiddenAPIFlagFileInfo)
+
+ for _, category := range hiddenAPIFlagFileCategories {
+ name := category.propertyName
+ message := fmt.Sprintf("category %s", name)
+ filename := strings.ReplaceAll(name, "_", "-")
+ expected := []string{fmt.Sprintf("%s.txt", filename), fmt.Sprintf("bar-%s.txt", filename)}
+ android.AssertPathsRelativeToTopEquals(t, message, expected, info.categoryToPaths[category])
+ }
+}
+
func TestPlatformBootclasspathVariant(t *testing.T) {
result := android.GroupFixturePreparers(
prepareForTestWithPlatformBootclasspath,
diff --git a/java/sdk_library.go b/java/sdk_library.go
index e5ee397..223be5c 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -534,6 +534,11 @@
// This is not the implementation jar, it still only contains stubs.
stubsImplPath android.Paths
+ // The dex jar for the stubs.
+ //
+ // This is not the implementation jar, it still only contains stubs.
+ stubsDexJarPath android.Path
+
// The API specification file, e.g. system_current.txt.
currentApiFilePath android.OptionalPath
@@ -549,6 +554,9 @@
lib := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo)
paths.stubsHeaderPath = lib.HeaderJars
paths.stubsImplPath = lib.ImplementationJars
+
+ libDep := dep.(UsesLibraryDependency)
+ paths.stubsDexJarPath = libDep.DexJarBuildPath()
return nil
} else {
return fmt.Errorf("expected module that has JavaInfoProvider, e.g. java_library")
@@ -825,8 +833,22 @@
return PrebuiltJars(ctx, c.moduleBase.BaseModuleName(), sdkVersion)
}
+ paths := c.selectScopePaths(ctx, sdkVersion.Kind)
+ if paths == nil {
+ return nil
+ }
+
+ return paths.stubsHeaderPath
+}
+
+// selectScopePaths returns the *scopePaths appropriate for the specific kind.
+//
+// If the module does not support the specific kind then it will return the *scopePaths for the
+// closest kind which is a subset of the requested kind. e.g. if requesting android.SdkModule then
+// it will return *scopePaths for android.SdkSystem if available or android.SdkPublic of not.
+func (c *commonToSdkLibraryAndImport) selectScopePaths(ctx android.BaseModuleContext, kind android.SdkKind) *scopePaths {
var apiScope *apiScope
- switch sdkVersion.Kind {
+ switch kind {
case android.SdkSystem:
apiScope = apiScopeSystem
case android.SdkModule:
@@ -851,7 +873,17 @@
return nil
}
- return paths.stubsHeaderPath
+ return paths
+}
+
+// to satisfy SdkLibraryDependency interface
+func (c *commonToSdkLibraryAndImport) SdkApiStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) android.Path {
+ paths := c.selectScopePaths(ctx, kind)
+ if paths == nil {
+ return nil
+ }
+
+ return paths.stubsDexJarPath
}
func (c *commonToSdkLibraryAndImport) sdkComponentPropertiesForChildLibrary() interface{} {
@@ -944,6 +976,10 @@
// jars for the stubs. The latter should only be needed when generating JavaDoc as otherwise
// they are identical to the corresponding header jars.
SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths
+
+ // SdkApiStubDexJar returns the dex jar for the stubs. It is needed by the hiddenapi processing
+ // tool which processes dex files.
+ SdkApiStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) android.Path
}
type SdkLibrary struct {
@@ -1781,6 +1817,9 @@
// List of shared java libs, common to all scopes, that this module has
// dependencies to
Libs []string
+
+ // If set to true, compile dex files for the stubs. Defaults to false.
+ Compile_dex *bool
}
type SdkLibraryImport struct {
@@ -1916,6 +1955,7 @@
Libs []string
Jars []string
Prefer *bool
+ Compile_dex *bool
}{}
props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope))
props.Sdk_version = scopeProperties.Sdk_version
@@ -1927,6 +1967,9 @@
// The imports are preferred if the java_sdk_library_import is preferred.
props.Prefer = proptools.BoolPtr(module.prebuilt.Prefer())
+ // The imports need to be compiled to dex if the java_sdk_library_import requests it.
+ props.Compile_dex = module.properties.Compile_dex
+
mctx.CreateModule(ImportFactory, &props, module.sdkComponentPropertiesForChildLibrary())
}
@@ -2348,6 +2391,9 @@
// otherwise.
Shared_library *bool
+ // True if the stub imports should produce dex jars.
+ Compile_dex *bool
+
// The paths to the doctag files to add to the prebuilt.
Doctag_paths android.Paths
}
@@ -2389,6 +2435,7 @@
s.Libs = sdk.properties.Libs
s.Naming_scheme = sdk.commonSdkLibraryProperties.Naming_scheme
s.Shared_library = proptools.BoolPtr(sdk.sharedLibrary())
+ s.Compile_dex = sdk.dexProperties.Compile_dex
s.Doctag_paths = sdk.doctagPaths
}
@@ -2399,6 +2446,9 @@
if s.Shared_library != nil {
propertySet.AddProperty("shared_library", *s.Shared_library)
}
+ if s.Compile_dex != nil {
+ propertySet.AddProperty("compile_dex", *s.Compile_dex)
+ }
for _, apiScope := range allApiScopes {
if properties, ok := s.Scopes[apiScope]; ok {
diff --git a/linkerconfig/Android.bp b/linkerconfig/Android.bp
index 9161f0e..76a6325 100644
--- a/linkerconfig/Android.bp
+++ b/linkerconfig/Android.bp
@@ -9,6 +9,7 @@
"blueprint",
"soong",
"soong-android",
+ "soong-cc",
"soong-etc",
],
srcs: [
diff --git a/linkerconfig/linkerconfig.go b/linkerconfig/linkerconfig.go
index 241cac6..8d0ad7c 100644
--- a/linkerconfig/linkerconfig.go
+++ b/linkerconfig/linkerconfig.go
@@ -15,11 +15,15 @@
package linkerconfig
import (
- "android/soong/android"
- "android/soong/etc"
"fmt"
+ "sort"
+ "strings"
"github.com/google/blueprint/proptools"
+
+ "android/soong/android"
+ "android/soong/cc"
+ "android/soong/etc"
)
var (
@@ -81,24 +85,59 @@
}
func (l *linkerConfig) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- inputFile := android.PathForModuleSrc(ctx, android.String(l.properties.Src))
- l.outputFilePath = android.PathForModuleOut(ctx, "linker.config.pb").OutputPath
- l.installDirPath = android.PathForModuleInstall(ctx, "etc")
- linkerConfigRule := android.NewRuleBuilder(pctx, ctx)
- linkerConfigRule.Command().
- BuiltTool("conv_linker_config").
- Flag("proto").
- FlagWithInput("-s ", inputFile).
- FlagWithOutput("-o ", l.outputFilePath)
- linkerConfigRule.Build("conv_linker_config",
- "Generate linker config protobuf "+l.outputFilePath.String())
+ input := android.PathForModuleSrc(ctx, android.String(l.properties.Src))
+ output := android.PathForModuleOut(ctx, "linker.config.pb").OutputPath
+ builder := android.NewRuleBuilder(pctx, ctx)
+ BuildLinkerConfig(ctx, builder, input, nil, output)
+ builder.Build("conv_linker_config", "Generate linker config protobuf "+output.String())
+
+ l.outputFilePath = output
+ l.installDirPath = android.PathForModuleInstall(ctx, "etc")
if !proptools.BoolDefault(l.properties.Installable, true) {
l.SkipInstall()
}
ctx.InstallFile(l.installDirPath, l.outputFilePath.Base(), l.outputFilePath)
}
+func BuildLinkerConfig(ctx android.ModuleContext, builder *android.RuleBuilder,
+ input android.Path, otherModules []android.Module, output android.OutputPath) {
+
+ // First, convert the input json to protobuf format
+ interimOutput := android.PathForModuleOut(ctx, "temp.pb")
+ builder.Command().
+ BuiltTool("conv_linker_config").
+ Flag("proto").
+ FlagWithInput("-s ", input).
+ FlagWithOutput("-o ", interimOutput)
+
+ // Secondly, if there's provideLibs gathered from otherModules, append them
+ var provideLibs []string
+ for _, m := range otherModules {
+ if c, ok := m.(*cc.Module); ok && cc.IsStubTarget(c) {
+ for _, ps := range c.PackagingSpecs() {
+ provideLibs = append(provideLibs, ps.FileName())
+ }
+ }
+ }
+ provideLibs = android.FirstUniqueStrings(provideLibs)
+ sort.Strings(provideLibs)
+ if len(provideLibs) > 0 {
+ builder.Command().
+ BuiltTool("conv_linker_config").
+ Flag("append").
+ FlagWithInput("-s ", interimOutput).
+ FlagWithOutput("-o ", output).
+ FlagWithArg("--key ", "provideLibs").
+ FlagWithArg("--value ", proptools.ShellEscapeIncludingSpaces(strings.Join(provideLibs, " ")))
+ } else {
+ // If nothing to add, just cp to the final output
+ builder.Command().Text("cp").Input(interimOutput).Output(output)
+ }
+ builder.Temporary(interimOutput)
+ builder.DeleteTemporaryFiles()
+}
+
// linker_config generates protobuf file from json file. This protobuf file will be used from
// linkerconfig while generating ld.config.txt. Format of this file can be found from
// https://android.googlesource.com/platform/system/linkerconfig/+/master/README.md
diff --git a/python/tests/Android.bp b/python/tests/Android.bp
index 0e8eef6..a656859 100644
--- a/python/tests/Android.bp
+++ b/python/tests/Android.bp
@@ -23,7 +23,10 @@
"par_test.py",
"testpkg/par_test.py",
],
-
+ // Is not implemented as a python unittest
+ test_options: {
+ unit_test: false,
+ },
version: {
py2: {
enabled: true,
@@ -43,7 +46,10 @@
"par_test.py",
"testpkg/par_test.py",
],
-
+ // Is not implemented as a python unittest
+ test_options: {
+ unit_test: false,
+ },
version: {
py3: {
embedded_launcher: true,
diff --git a/rust/Android.bp b/rust/Android.bp
index a6c4e07..f45404f 100644
--- a/rust/Android.bp
+++ b/rust/Android.bp
@@ -21,6 +21,7 @@
"clippy.go",
"compiler.go",
"coverage.go",
+ "doc.go",
"fuzz.go",
"image.go",
"library.go",
diff --git a/rust/binary.go b/rust/binary.go
index dfe8744..ffc0413 100644
--- a/rust/binary.go
+++ b/rust/binary.go
@@ -122,7 +122,7 @@
flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...)
flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...)
- TransformSrcToBinary(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+ TransformSrcToBinary(ctx, srcPath, deps, flags, outputFile)
if binary.stripper.NeedsStrip(ctx) {
strippedOutputFile := android.PathForModuleOut(ctx, "stripped", fileName)
diff --git a/rust/bindgen.go b/rust/bindgen.go
index 9198e6d..ba0ab93 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -29,7 +29,7 @@
defaultBindgenFlags = []string{""}
// bindgen should specify its own Clang revision so updating Clang isn't potentially blocked on bindgen failures.
- bindgenClangVersion = "clang-r412851"
+ bindgenClangVersion = "clang-r416183b"
_ = pctx.VariableFunc("bindgenClangVersion", func(ctx android.PackageVarContext) string {
if override := ctx.Config().Getenv("LLVM_BINDGEN_PREBUILTS_VERSION"); override != "" {
diff --git a/rust/builder.go b/rust/builder.go
index 208b734..1fcce38 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -44,6 +44,16 @@
},
"rustcFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd", "envVars")
+ _ = pctx.SourcePathVariable("rustdocCmd", "${config.RustBin}/rustdoc")
+ rustdoc = pctx.AndroidStaticRule("rustdoc",
+ blueprint.RuleParams{
+ Command: "rm -rf $outDir && " +
+ "$envVars $rustdocCmd $rustdocFlags $in -o $outDir && " +
+ "touch $out",
+ CommandDeps: []string{"$rustdocCmd"},
+ },
+ "rustdocFlags", "outDir", "envVars")
+
_ = pctx.SourcePathVariable("clippyCmd", "${config.RustBin}/clippy-driver")
clippyDriver = pctx.AndroidStaticRule("clippy",
blueprint.RuleParams{
@@ -85,37 +95,37 @@
}
func TransformSrcToBinary(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
- outputFile android.WritablePath, linkDirs []string) buildOutput {
+ outputFile android.WritablePath) buildOutput {
flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto")
- return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "bin", linkDirs)
+ return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "bin")
}
func TransformSrctoRlib(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
- outputFile android.WritablePath, linkDirs []string) buildOutput {
- return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "rlib", linkDirs)
+ outputFile android.WritablePath) buildOutput {
+ return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "rlib")
}
func TransformSrctoDylib(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
- outputFile android.WritablePath, linkDirs []string) buildOutput {
- return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "dylib", linkDirs)
+ outputFile android.WritablePath) buildOutput {
+ return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "dylib")
}
func TransformSrctoStatic(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
- outputFile android.WritablePath, linkDirs []string) buildOutput {
+ outputFile android.WritablePath) buildOutput {
flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto")
- return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "staticlib", linkDirs)
+ return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "staticlib")
}
func TransformSrctoShared(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
- outputFile android.WritablePath, linkDirs []string) buildOutput {
+ outputFile android.WritablePath) buildOutput {
flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto")
- return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "cdylib", linkDirs)
+ return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "cdylib")
}
func TransformSrctoProcMacro(ctx ModuleContext, mainSrc android.Path, deps PathDeps,
- flags Flags, outputFile android.WritablePath, linkDirs []string) buildOutput {
- return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "proc-macro", linkDirs)
+ flags Flags, outputFile android.WritablePath) buildOutput {
+ return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "proc-macro")
}
func rustLibsToPaths(libs RustLibraries) android.Paths {
@@ -126,26 +136,69 @@
return paths
}
+func makeLibFlags(deps PathDeps) []string {
+ var libFlags []string
+
+ // Collect library/crate flags
+ for _, lib := range deps.RLibs {
+ libFlags = append(libFlags, "--extern "+lib.CrateName+"="+lib.Path.String())
+ }
+ for _, lib := range deps.DyLibs {
+ libFlags = append(libFlags, "--extern "+lib.CrateName+"="+lib.Path.String())
+ }
+ for _, proc_macro := range deps.ProcMacros {
+ libFlags = append(libFlags, "--extern "+proc_macro.CrateName+"="+proc_macro.Path.String())
+ }
+
+ for _, path := range deps.linkDirs {
+ libFlags = append(libFlags, "-L "+path)
+ }
+
+ return libFlags
+}
+
+func rustEnvVars(ctx ModuleContext, deps PathDeps) []string {
+ var envVars []string
+
+ // libstd requires a specific environment variable to be set. This is
+ // not officially documented and may be removed in the future. See
+ // https://github.com/rust-lang/rust/blob/master/library/std/src/env.rs#L866.
+ if ctx.RustModule().CrateName() == "std" {
+ envVars = append(envVars, "STD_ENV_ARCH="+config.StdEnvArch[ctx.RustModule().Arch().ArchType])
+ }
+
+ if len(deps.SrcDeps) > 0 {
+ moduleGenDir := ctx.RustModule().compiler.CargoOutDir()
+ // We must calculate an absolute path for OUT_DIR since Rust's include! macro (which normally consumes this)
+ // assumes that paths are relative to the source file.
+ var outDirPrefix string
+ if !filepath.IsAbs(moduleGenDir.String()) {
+ // If OUT_DIR is not absolute, we use $$PWD to generate an absolute path (os.Getwd() returns '/')
+ outDirPrefix = "$$PWD/"
+ } else {
+ // If OUT_DIR is absolute, then moduleGenDir will be an absolute path, so we don't need to set this to anything.
+ outDirPrefix = ""
+ }
+ envVars = append(envVars, "OUT_DIR="+filepath.Join(outDirPrefix, moduleGenDir.String()))
+ }
+
+ return envVars
+}
+
func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, flags Flags,
- outputFile android.WritablePath, crate_type string, linkDirs []string) buildOutput {
+ outputFile android.WritablePath, crate_type string) buildOutput {
var inputs android.Paths
var implicits android.Paths
- var envVars []string
var output buildOutput
- var libFlags, rustcFlags, linkFlags []string
+ var rustcFlags, linkFlags []string
var implicitOutputs android.WritablePaths
output.outputFile = outputFile
crateName := ctx.RustModule().CrateName()
targetTriple := ctx.toolchain().RustTriple()
- // libstd requires a specific environment variable to be set. This is
- // not officially documented and may be removed in the future. See
- // https://github.com/rust-lang/rust/blob/master/library/std/src/env.rs#L866.
- if crateName == "std" {
- envVars = append(envVars, "STD_ENV_ARCH="+config.StdEnvArch[ctx.RustModule().Arch().ArchType])
- }
+ envVars := rustEnvVars(ctx, deps)
inputs = append(inputs, main)
@@ -168,20 +221,7 @@
linkFlags = append(linkFlags, flags.GlobalLinkFlags...)
linkFlags = append(linkFlags, flags.LinkFlags...)
- // Collect library/crate flags
- for _, lib := range deps.RLibs {
- libFlags = append(libFlags, "--extern "+lib.CrateName+"="+lib.Path.String())
- }
- for _, lib := range deps.DyLibs {
- libFlags = append(libFlags, "--extern "+lib.CrateName+"="+lib.Path.String())
- }
- for _, proc_macro := range deps.ProcMacros {
- libFlags = append(libFlags, "--extern "+proc_macro.CrateName+"="+proc_macro.Path.String())
- }
-
- for _, path := range linkDirs {
- libFlags = append(libFlags, "-L "+path)
- }
+ libFlags := makeLibFlags(deps)
// Collect dependencies
implicits = append(implicits, rustLibsToPaths(deps.RLibs)...)
@@ -217,18 +257,6 @@
},
})
implicits = append(implicits, outputs.Paths()...)
-
- // We must calculate an absolute path for OUT_DIR since Rust's include! macro (which normally consumes this)
- // assumes that paths are relative to the source file.
- var outDirPrefix string
- if !filepath.IsAbs(moduleGenDir.String()) {
- // If OUT_DIR is not absolute, we use $$PWD to generate an absolute path (os.Getwd() returns '/')
- outDirPrefix = "$$PWD/"
- } else {
- // If OUT_DIR is absolute, then moduleGenDir will be an absolute path, so we don't need to set this to anything.
- outDirPrefix = ""
- }
- envVars = append(envVars, "OUT_DIR="+filepath.Join(outDirPrefix, moduleGenDir.String()))
}
envVars = append(envVars, "ANDROID_RUST_VERSION="+config.RustDefaultVersion)
@@ -272,3 +300,41 @@
return output
}
+
+func Rustdoc(ctx ModuleContext, main android.Path, deps PathDeps,
+ flags Flags) android.ModuleOutPath {
+
+ rustdocFlags := append([]string{}, flags.RustdocFlags...)
+ rustdocFlags = append(rustdocFlags, "--sysroot=/dev/null")
+
+ targetTriple := ctx.toolchain().RustTriple()
+
+ // Collect rustc flags
+ if targetTriple != "" {
+ rustdocFlags = append(rustdocFlags, "--target="+targetTriple)
+ }
+
+ crateName := ctx.RustModule().CrateName()
+ if crateName != "" {
+ rustdocFlags = append(rustdocFlags, "--crate-name "+crateName)
+ }
+
+ rustdocFlags = append(rustdocFlags, makeLibFlags(deps)...)
+ docTimestampFile := android.PathForModuleOut(ctx, "rustdoc.timestamp")
+ docDir := android.PathForOutput(ctx, "rustdoc", ctx.ModuleName())
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: rustdoc,
+ Description: "rustdoc " + main.Rel(),
+ Output: docTimestampFile,
+ Input: main,
+ Implicit: ctx.RustModule().unstrippedOutputFile.Path(),
+ Args: map[string]string{
+ "rustdocFlags": strings.Join(rustdocFlags, " "),
+ "outDir": docDir.String(),
+ "envVars": strings.Join(rustEnvVars(ctx, deps), " "),
+ },
+ })
+
+ return docTimestampFile
+}
diff --git a/rust/compiler.go b/rust/compiler.go
index 1091585..a3f02c0 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -239,7 +239,10 @@
flags.RustFlags = append(flags.RustFlags, compiler.Properties.Flags...)
flags.RustFlags = append(flags.RustFlags, compiler.cfgsToFlags()...)
flags.RustFlags = append(flags.RustFlags, compiler.featuresToFlags()...)
+ flags.RustdocFlags = append(flags.RustdocFlags, compiler.cfgsToFlags()...)
+ flags.RustdocFlags = append(flags.RustdocFlags, compiler.featuresToFlags()...)
flags.RustFlags = append(flags.RustFlags, "--edition="+compiler.edition())
+ flags.RustdocFlags = append(flags.RustdocFlags, "--edition="+compiler.edition())
flags.LinkFlags = append(flags.LinkFlags, compiler.Properties.Ld_flags...)
flags.GlobalRustFlags = append(flags.GlobalRustFlags, config.GlobalRustFlags...)
flags.GlobalRustFlags = append(flags.GlobalRustFlags, ctx.toolchain().ToolchainRustFlags())
@@ -272,6 +275,12 @@
panic(fmt.Errorf("baseCrater doesn't know how to crate things!"))
}
+func (compiler *baseCompiler) rustdoc(ctx ModuleContext, flags Flags,
+ deps PathDeps) android.OptionalPath {
+
+ return android.OptionalPath{}
+}
+
func (compiler *baseCompiler) initialize(ctx ModuleContext) {
compiler.cargoOutDir = android.PathForModuleOut(ctx, genSubDir)
}
diff --git a/rust/doc.go b/rust/doc.go
new file mode 100644
index 0000000..e7f1371
--- /dev/null
+++ b/rust/doc.go
@@ -0,0 +1,43 @@
+// Copyright 2021 The Android Open Source Project
+//
+// 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 rust
+
+import (
+ "android/soong/android"
+)
+
+func init() {
+ android.RegisterSingletonType("rustdoc", RustdocSingleton)
+}
+
+func RustdocSingleton() android.Singleton {
+ return &rustdocSingleton{}
+}
+
+type rustdocSingleton struct{}
+
+func (n *rustdocSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+ ctx.VisitAllModules(func(module android.Module) {
+ if !module.Enabled() {
+ return
+ }
+
+ if m, ok := module.(*Module); ok {
+ if m.docTimestampFile.Valid() {
+ ctx.Phony("rustdoc", m.docTimestampFile.Path())
+ }
+ }
+ })
+}
diff --git a/rust/library.go b/rust/library.go
index 052fb3a..1bdf83a 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -432,14 +432,10 @@
func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
var outputFile android.ModuleOutPath
var fileName string
- var srcPath android.Path
+ srcPath := library.srcPath(ctx, deps)
if library.sourceProvider != nil {
- // Assume the first source from the source provider is the library entry point.
- srcPath = library.sourceProvider.Srcs()[0]
deps.srcProviderFiles = append(deps.srcProviderFiles, library.sourceProvider.Srcs()...)
- } else {
- srcPath, _ = srcPathFromModuleSrcs(ctx, library.baseCompiler.Properties.Srcs)
}
flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
@@ -457,22 +453,22 @@
fileName = library.getStem(ctx) + ctx.toolchain().RlibSuffix()
outputFile = android.PathForModuleOut(ctx, fileName)
- TransformSrctoRlib(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+ TransformSrctoRlib(ctx, srcPath, deps, flags, outputFile)
} else if library.dylib() {
fileName = library.getStem(ctx) + ctx.toolchain().DylibSuffix()
outputFile = android.PathForModuleOut(ctx, fileName)
- TransformSrctoDylib(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+ TransformSrctoDylib(ctx, srcPath, deps, flags, outputFile)
} else if library.static() {
fileName = library.getStem(ctx) + ctx.toolchain().StaticLibSuffix()
outputFile = android.PathForModuleOut(ctx, fileName)
- TransformSrctoStatic(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+ TransformSrctoStatic(ctx, srcPath, deps, flags, outputFile)
} else if library.shared() {
fileName = library.sharedLibFilename(ctx)
outputFile = android.PathForModuleOut(ctx, fileName)
- TransformSrctoShared(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+ TransformSrctoShared(ctx, srcPath, deps, flags, outputFile)
}
if !library.rlib() && !library.static() && library.stripper.NeedsStrip(ctx) {
@@ -514,6 +510,31 @@
return outputFile
}
+func (library *libraryDecorator) srcPath(ctx ModuleContext, deps PathDeps) android.Path {
+ if library.sourceProvider != nil {
+ // Assume the first source from the source provider is the library entry point.
+ return library.sourceProvider.Srcs()[0]
+ } else {
+ path, _ := srcPathFromModuleSrcs(ctx, library.baseCompiler.Properties.Srcs)
+ return path
+ }
+}
+
+func (library *libraryDecorator) rustdoc(ctx ModuleContext, flags Flags,
+ deps PathDeps) android.OptionalPath {
+ // rustdoc has builtin support for documenting config specific information
+ // regardless of the actual config it was given
+ // (https://doc.rust-lang.org/rustdoc/advanced-features.html#cfgdoc-documenting-platform-specific-or-feature-specific-information),
+ // so we generate the rustdoc for only the primary module so that we have a
+ // single set of docs to refer to.
+ if ctx.Module() != ctx.PrimaryModule() {
+ return android.OptionalPath{}
+ }
+
+ return android.OptionalPathForPath(Rustdoc(ctx, library.srcPath(ctx, deps),
+ deps, flags))
+}
+
func (library *libraryDecorator) getStem(ctx ModuleContext) string {
stem := library.baseCompiler.getStemWithoutSuffix(ctx)
validateLibraryStem(ctx, stem, library.crateName())
diff --git a/rust/prebuilt.go b/rust/prebuilt.go
index 94fe1e5..49f3c0f 100644
--- a/rust/prebuilt.go
+++ b/rust/prebuilt.go
@@ -103,6 +103,12 @@
return srcPath
}
+func (prebuilt *prebuiltLibraryDecorator) rustdoc(ctx ModuleContext, flags Flags,
+ deps PathDeps) android.OptionalPath {
+
+ return android.OptionalPath{}
+}
+
func (prebuilt *prebuiltLibraryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps {
deps = prebuilt.baseCompiler.compilerDeps(ctx, deps)
return deps
diff --git a/rust/proc_macro.go b/rust/proc_macro.go
index 115045a..4eead32 100644
--- a/rust/proc_macro.go
+++ b/rust/proc_macro.go
@@ -68,7 +68,7 @@
outputFile := android.PathForModuleOut(ctx, fileName)
srcPath, _ := srcPathFromModuleSrcs(ctx, procMacro.baseCompiler.Properties.Srcs)
- TransformSrctoProcMacro(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+ TransformSrctoProcMacro(ctx, srcPath, deps, flags, outputFile)
return outputFile
}
diff --git a/rust/rust.go b/rust/rust.go
index 9738b46..78a793d 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -58,6 +58,7 @@
RustFlags []string // Flags that apply to rust
LinkFlags []string // Flags that apply to linker
ClippyFlags []string // Flags that apply to clippy-driver, during the linting
+ RustdocFlags []string // Flags that apply to rustdoc
Toolchain config.Toolchain
Coverage bool
Clippy bool
@@ -124,6 +125,7 @@
// as a library. The stripped output which is used for installation can be found via
// compiler.strippedOutputFile if it exists.
unstrippedOutputFile android.OptionalPath
+ docTimestampFile android.OptionalPath
hideApexVariantFromMake bool
}
@@ -355,10 +357,12 @@
compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path
compilerDeps(ctx DepsContext, deps Deps) Deps
crateName() string
+ rustdoc(ctx ModuleContext, flags Flags, deps PathDeps) android.OptionalPath
// Output directory in which source-generated code from dependencies is
// copied. This is equivalent to Cargo's OUT_DIR variable.
CargoOutDir() android.OptionalPath
+
inData() bool
install(ctx ModuleContext)
relativeInstallPath() string
@@ -755,6 +759,8 @@
mod.unstrippedOutputFile = android.OptionalPathForPath(unstrippedOutputFile)
bloaty.MeasureSizeForPaths(ctx, mod.compiler.strippedOutputFilePath(), mod.unstrippedOutputFile)
+ mod.docTimestampFile = mod.compiler.rustdoc(ctx, flags, deps)
+
apexInfo := actx.Provider(android.ApexInfoProvider).(android.ApexInfo)
if mod.installable(apexInfo) {
mod.compiler.install(ctx)
diff --git a/scripts/Android.bp b/scripts/Android.bp
index c54b2bc..b0a8669 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -219,14 +219,25 @@
}
python_binary_host {
- name: "lint-project-xml",
- main: "lint-project-xml.py",
+ name: "lint_project_xml",
+ main: "lint_project_xml.py",
srcs: [
- "lint-project-xml.py",
+ "lint_project_xml.py",
],
libs: ["ninja_rsp"],
}
+python_test_host {
+ name: "lint_project_xml_test",
+ main: "lint_project_xml_test.py",
+ srcs: [
+ "lint_project_xml_test.py",
+ "lint_project_xml.py",
+ ],
+ libs: ["ninja_rsp"],
+ test_suites: ["general-tests"],
+}
+
python_binary_host {
name: "gen-kotlin-build-file.py",
main: "gen-kotlin-build-file.py",
diff --git a/scripts/lint-project-xml.py b/scripts/lint_project_xml.py
similarity index 85%
rename from scripts/lint-project-xml.py
rename to scripts/lint_project_xml.py
index f1ef85d..74aebc1 100755
--- a/scripts/lint-project-xml.py
+++ b/scripts/lint_project_xml.py
@@ -18,6 +18,7 @@
"""This file generates project.xml and lint.xml files used to drive the Android Lint CLI tool."""
import argparse
+from xml.dom import minidom
from ninja_rsp import NinjaRspFileReader
@@ -73,6 +74,8 @@
help='file containing the module\'s manifest.')
parser.add_argument('--merged_manifest', dest='merged_manifest',
help='file containing merged manifest for the module and its dependencies.')
+ parser.add_argument('--baseline', dest='baseline_path',
+ help='file containing baseline lint issues.')
parser.add_argument('--library', dest='library', action='store_true',
help='mark the module as a library.')
parser.add_argument('--test', dest='test', action='store_true',
@@ -90,6 +93,8 @@
help='treat a lint issue as a warning.')
group.add_argument('--disable_check', dest='checks', action=check_action('ignore'), default=[],
help='disable a lint issue.')
+ group.add_argument('--disallowed_issues', dest='disallowed_issues', default=[],
+ help='lint issues disallowed in the baseline file')
return parser.parse_args()
@@ -134,10 +139,30 @@
f.write("</lint>\n")
+def check_baseline_for_disallowed_issues(baseline, forced_checks):
+ issues_element = baseline.documentElement
+ if issues_element.tagName != 'issues':
+ raise RuntimeError('expected issues tag at root')
+ issues = issues_element.getElementsByTagName('issue')
+ disallwed = set()
+ for issue in issues:
+ id = issue.getAttribute('id')
+ if id in forced_checks:
+ disallwed.add(id)
+ return disallwed
+
+
def main():
"""Program entry point."""
args = parse_args()
+ if args.baseline_path:
+ baseline = minidom.parse(args.baseline_path)
+ diallowed_issues = check_baseline_for_disallowed_issues(baseline, args.disallowed_issues)
+ if bool(diallowed_issues):
+ raise RuntimeError('disallowed issues %s found in lint baseline file %s for module %s'
+ % (diallowed_issues, args.baseline_path, args.name))
+
if args.project_out:
with open(args.project_out, 'w') as f:
write_project_xml(f, args)
diff --git a/scripts/lint_project_xml_test.py b/scripts/lint_project_xml_test.py
new file mode 100644
index 0000000..344691d
--- /dev/null
+++ b/scripts/lint_project_xml_test.py
@@ -0,0 +1,52 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 The Android Open Source Project
+#
+# 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.
+#
+
+"""Unit tests for lint_project_xml.py."""
+
+import unittest
+from xml.dom import minidom
+
+import lint_project_xml
+
+
+class CheckBaselineForDisallowedIssuesTest(unittest.TestCase):
+ """Unit tests for check_baseline_for_disallowed_issues function."""
+
+ baseline_xml = minidom.parseString(
+ '<?xml version="1.0" encoding="utf-8"?>\n'
+ '<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">\n'
+ ' <issue id="foo" message="foo is evil" errorLine1="foo()">\n'
+ ' <location file="a/b/c.java" line="3" column="10"/>\n'
+ ' </issue>\n'
+ ' <issue id="bar" message="bar is known to be evil" errorLine1="bar()">\n'
+ ' <location file="a/b/c.java" line="5" column="12"/>\n'
+ ' </issue>\n'
+ ' <issue id="baz" message="baz may be evil" errorLine1="a = baz()">\n'
+ ' <location file="a/b/c.java" line="10" column="10"/>\n'
+ ' </issue>\n'
+ ' <issue id="foo" message="foo is evil" errorLine1="b = foo()">\n'
+ ' <location file="a/d/e.java" line="100" column="4"/>\n'
+ ' </issue>\n'
+ '</issues>\n')
+
+ def test_check_baseline_for_disallowed_issues(self):
+ disallowed_issues = lint_project_xml.check_baseline_for_disallowed_issues(self.baseline_xml, ["foo", "bar", "qux"])
+ self.assertEqual({"foo", "bar"}, disallowed_issues)
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index 54916d8..6016981 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -1089,6 +1089,80 @@
)
}
+func TestSnapshotWithJavaSdkLibrary_CompileDex(t *testing.T) {
+ result := android.GroupFixturePreparers(prepareForSdkTestWithJavaSdkLibrary).RunTestWithBp(t, `
+ sdk {
+ name: "mysdk",
+ java_sdk_libs: ["myjavalib"],
+ }
+
+ java_sdk_library {
+ name: "myjavalib",
+ srcs: ["Test.java"],
+ sdk_version: "current",
+ shared_library: false,
+ compile_dex: true,
+ public: {
+ enabled: true,
+ },
+ system: {
+ enabled: true,
+ },
+ }
+ `)
+
+ CheckSnapshot(t, result, "mysdk", "",
+ checkUnversionedAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_sdk_library_import {
+ name: "myjavalib",
+ prefer: false,
+ visibility: ["//visibility:public"],
+ apex_available: ["//apex_available:platform"],
+ shared_library: false,
+ compile_dex: true,
+ public: {
+ jars: ["sdk_library/public/myjavalib-stubs.jar"],
+ stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
+ current_api: "sdk_library/public/myjavalib.txt",
+ removed_api: "sdk_library/public/myjavalib-removed.txt",
+ sdk_version: "current",
+ },
+ system: {
+ jars: ["sdk_library/system/myjavalib-stubs.jar"],
+ stub_srcs: ["sdk_library/system/myjavalib_stub_sources"],
+ current_api: "sdk_library/system/myjavalib.txt",
+ removed_api: "sdk_library/system/myjavalib-removed.txt",
+ sdk_version: "system_current",
+ },
+}
+`),
+ snapshotTestChecker(checkSnapshotWithSourcePreferred, func(t *testing.T, result *android.TestResult) {
+ ctx := android.ModuleInstallPathContextForTesting(result.Config)
+ dexJarBuildPath := func(name string, kind android.SdkKind) string {
+ dep := result.Module(name, "android_common").(java.SdkLibraryDependency)
+ path := dep.SdkApiStubDexJar(ctx, kind)
+ return path.RelativeToTop().String()
+ }
+
+ dexJarPath := dexJarBuildPath("myjavalib", android.SdkPublic)
+ android.AssertStringEquals(t, "source dex public stubs jar build path", "out/soong/.intermediates/myjavalib.stubs/android_common/dex/myjavalib.stubs.jar", dexJarPath)
+
+ dexJarPath = dexJarBuildPath("myjavalib", android.SdkSystem)
+ systemDexJar := "out/soong/.intermediates/myjavalib.stubs.system/android_common/dex/myjavalib.stubs.system.jar"
+ android.AssertStringEquals(t, "source dex system stubs jar build path", systemDexJar, dexJarPath)
+
+ // This should fall back to system as module is not available.
+ dexJarPath = dexJarBuildPath("myjavalib", android.SdkModule)
+ android.AssertStringEquals(t, "source dex module stubs jar build path", systemDexJar, dexJarPath)
+
+ dexJarPath = dexJarBuildPath(android.PrebuiltNameFromSource("myjavalib"), android.SdkPublic)
+ android.AssertStringEquals(t, "prebuilt dex public stubs jar build path", "out/soong/.intermediates/snapshot/prebuilt_myjavalib.stubs/android_common/dex/myjavalib.stubs.jar", dexJarPath)
+ }),
+ )
+}
+
func TestSnapshotWithJavaSdkLibrary_SdkVersion_None(t *testing.T) {
result := android.GroupFixturePreparers(prepareForSdkTestWithJavaSdkLibrary).RunTestWithBp(t, `
sdk {
diff --git a/sdk/update.go b/sdk/update.go
index 522a888..da76fb4 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -103,7 +103,7 @@
rb.Command().
Implicits(implicits).
- Text("echo").Text(proptools.ShellEscape(content)).
+ Text("echo -n").Text(proptools.ShellEscape(content)).
// convert \\n to \n
Text("| sed 's/\\\\n/\\n/g' >").Output(gf.path)
rb.Command().
diff --git a/tests/bootstrap_test.sh b/tests/bootstrap_test.sh
index 7265ac5..3f51114 100755
--- a/tests/bootstrap_test.sh
+++ b/tests/bootstrap_test.sh
@@ -1,5 +1,7 @@
#!/bin/bash -eu
+set -o pipefail
+
# This test exercises the bootstrapping process of the build system
# in a source tree that only contains enough files for Bazel and Soong to work.
@@ -140,7 +142,7 @@
run_soong
local ninja_mtime1=$(stat -c "%y" out/soong/build.ninja)
- local glob_deps_file=out/soong/.glob/a/__py.glob.d
+ local glob_deps_file=out/soong/.primary/globs/0.d
if [ -e "$glob_deps_file" ]; then
fail "Glob deps file unexpectedly written on first build"
@@ -482,15 +484,14 @@
fi
}
-function test_integrated_bp2build_smoke {
+function test_bp2build_smoke {
setup
- INTEGRATED_BP2BUILD=1 run_soong
- if [[ ! -e out/soong/.bootstrap/bp2build_workspace_marker ]]; then
- fail "bp2build marker file not created"
- fi
+ GENERATE_BAZEL_FILES=1 run_soong
+ [[ -e out/soong/.bootstrap/bp2build_workspace_marker ]] || fail "bp2build marker file not created"
+ [[ -e out/soong/workspace ]] || fail "Bazel workspace not created"
}
-function test_integrated_bp2build_add_android_bp {
+function test_bp2build_add_android_bp {
setup
mkdir -p a
@@ -503,10 +504,9 @@
}
EOF
- INTEGRATED_BP2BUILD=1 run_soong
- if [[ ! -e out/soong/bp2build/a/BUILD ]]; then
- fail "a/BUILD not created";
- fi
+ GENERATE_BAZEL_FILES=1 run_soong
+ [[ -e out/soong/bp2build/a/BUILD ]] || fail "a/BUILD not created"
+ [[ -L out/soong/workspace/a/BUILD ]] || fail "a/BUILD not symlinked"
mkdir -p b
touch b/b.txt
@@ -518,19 +518,18 @@
}
EOF
- INTEGRATED_BP2BUILD=1 run_soong
- if [[ ! -e out/soong/bp2build/b/BUILD ]]; then
- fail "b/BUILD not created";
- fi
+ GENERATE_BAZEL_FILES=1 run_soong
+ [[ -e out/soong/bp2build/b/BUILD ]] || fail "a/BUILD not created"
+ [[ -L out/soong/workspace/b/BUILD ]] || fail "a/BUILD not symlinked"
}
-function test_integrated_bp2build_null_build {
+function test_bp2build_null_build {
setup
- INTEGRATED_BP2BUILD=1 run_soong
+ GENERATE_BAZEL_FILES=1 run_soong
local mtime1=$(stat -c "%y" out/soong/build.ninja)
- INTEGRATED_BP2BUILD=1 run_soong
+ GENERATE_BAZEL_FILES=1 run_soong
local mtime2=$(stat -c "%y" out/soong/build.ninja)
if [[ "$mtime1" != "$mtime2" ]]; then
@@ -538,7 +537,7 @@
fi
}
-function test_integrated_bp2build_add_to_glob {
+function test_bp2build_add_to_glob {
setup
mkdir -p a
@@ -551,11 +550,11 @@
}
EOF
- INTEGRATED_BP2BUILD=1 run_soong
+ GENERATE_BAZEL_FILES=1 run_soong
grep -q a1.txt out/soong/bp2build/a/BUILD || fail "a1.txt not in BUILD file"
touch a/a2.txt
- INTEGRATED_BP2BUILD=1 run_soong
+ GENERATE_BAZEL_FILES=1 run_soong
grep -q a2.txt out/soong/bp2build/a/BUILD || fail "a2.txt not in BUILD file"
}
@@ -567,6 +566,102 @@
fi
}
+function test_bp2build_bazel_workspace_structure {
+ setup
+
+ mkdir -p a/b
+ touch a/a.txt
+ touch a/b/b.txt
+ cat > a/b/Android.bp <<'EOF'
+filegroup {
+ name: "b",
+ srcs: ["b.txt"],
+ bazel_module: { bp2build_available: true },
+}
+EOF
+
+ GENERATE_BAZEL_FILES=1 run_soong
+ [[ -e out/soong/workspace ]] || fail "Bazel workspace not created"
+ [[ -d out/soong/workspace/a/b ]] || fail "module directory not a directory"
+ [[ -L out/soong/workspace/a/b/BUILD ]] || fail "BUILD file not symlinked"
+ [[ "$(readlink -f out/soong/workspace/a/b/BUILD)" =~ bp2build/a/b/BUILD$ ]] \
+ || fail "BUILD files symlinked at the wrong place"
+ [[ -L out/soong/workspace/a/b/b.txt ]] || fail "a/b/b.txt not symlinked"
+ [[ -L out/soong/workspace/a/a.txt ]] || fail "a/b/a.txt not symlinked"
+ [[ ! -e out/soong/workspace/out ]] || fail "out directory symlinked"
+}
+
+function test_bp2build_bazel_workspace_add_file {
+ setup
+
+ mkdir -p a
+ touch a/a.txt
+ cat > a/Android.bp <<EOF
+filegroup {
+ name: "a",
+ srcs: ["a.txt"],
+ bazel_module: { bp2build_available: true },
+}
+EOF
+
+ GENERATE_BAZEL_FILES=1 run_soong
+
+ touch a/a2.txt # No reference in the .bp file needed
+ GENERATE_BAZEL_FILES=1 run_soong
+ [[ -L out/soong/workspace/a/a2.txt ]] || fail "a/a2.txt not symlinked"
+}
+
+function test_bp2build_build_file_precedence {
+ setup
+
+ mkdir -p a
+ touch a/a.txt
+ touch a/BUILD
+ cat > a/Android.bp <<EOF
+filegroup {
+ name: "a",
+ srcs: ["a.txt"],
+ bazel_module: { bp2build_available: true },
+}
+EOF
+
+ GENERATE_BAZEL_FILES=1 run_soong
+ [[ -L out/soong/workspace/a/BUILD ]] || fail "BUILD file not symlinked"
+ [[ "$(readlink -f out/soong/workspace/a/BUILD)" =~ bp2build/a/BUILD$ ]] \
+ || fail "BUILD files symlinked to the wrong place"
+}
+
+function test_bp2build_reports_multiple_errors {
+ setup
+
+ mkdir -p a/BUILD
+ touch a/a.txt
+ cat > a/Android.bp <<EOF
+filegroup {
+ name: "a",
+ srcs: ["a.txt"],
+ bazel_module: { bp2build_available: true },
+}
+EOF
+
+ mkdir -p b/BUILD
+ touch b/b.txt
+ cat > b/Android.bp <<EOF
+filegroup {
+ name: "b",
+ srcs: ["b.txt"],
+ bazel_module: { bp2build_available: true },
+}
+EOF
+
+ if GENERATE_BAZEL_FILES=1 run_soong >& "$MOCK_TOP/errors"; then
+ fail "Build should have failed"
+ fi
+
+ grep -q "a/BUILD' exist" "$MOCK_TOP/errors" || fail "Error for a/BUILD not found"
+ grep -q "b/BUILD' exist" "$MOCK_TOP/errors" || fail "Error for b/BUILD not found"
+}
+
test_smoke
test_null_build
test_null_build_after_docs
@@ -580,6 +675,11 @@
test_glob_during_bootstrapping
test_soong_build_rerun_iff_environment_changes
test_dump_json_module_graph
-test_integrated_bp2build_smoke
-test_integrated_bp2build_null_build
-test_integrated_bp2build_add_to_glob
+test_bp2build_smoke
+test_bp2build_null_build
+test_bp2build_add_android_bp
+test_bp2build_add_to_glob
+test_bp2build_bazel_workspace_structure
+test_bp2build_bazel_workspace_add_file
+test_bp2build_build_file_precedence
+test_bp2build_reports_multiple_errors
diff --git a/tests/bp2build_bazel_test.sh b/tests/bp2build_bazel_test.sh
new file mode 100755
index 0000000..082cd06
--- /dev/null
+++ b/tests/bp2build_bazel_test.sh
@@ -0,0 +1,75 @@
+#!/bin/bash -eu
+
+set -o pipefail
+
+# Test that bp2build and Bazel can play nicely together
+
+source "$(dirname "$0")/lib.sh"
+
+function test_bp2build_generates_all_buildfiles {
+ setup
+ create_mock_bazel
+
+ mkdir -p foo/convertible_soong_module
+ cat > foo/convertible_soong_module/Android.bp <<'EOF'
+genrule {
+ name: "the_answer",
+ cmd: "echo '42' > $(out)",
+ out: [
+ "the_answer.txt",
+ ],
+ bazel_module: {
+ bp2build_available: true,
+ },
+ }
+EOF
+
+ mkdir -p foo/unconvertible_soong_module
+ cat > foo/unconvertible_soong_module/Android.bp <<'EOF'
+genrule {
+ name: "not_the_answer",
+ cmd: "echo '43' > $(out)",
+ out: [
+ "not_the_answer.txt",
+ ],
+ bazel_module: {
+ bp2build_available: false,
+ },
+ }
+EOF
+
+ run_bp2build
+
+ if [[ ! -f "./out/soong/workspace/foo/convertible_soong_module/BUILD" ]]; then
+ fail "./out/soong/workspace/foo/convertible_soong_module/BUILD was not generated"
+ fi
+
+ if [[ ! -f "./out/soong/workspace/foo/unconvertible_soong_module/BUILD" ]]; then
+ fail "./out/soong/workspace/foo/unconvertible_soong_module/BUILD was not generated"
+ fi
+
+ if ! grep "the_answer" "./out/soong/workspace/foo/convertible_soong_module/BUILD"; then
+ fail "missing BUILD target the_answer in convertible_soong_module/BUILD"
+ fi
+
+ if grep "not_the_answer" "./out/soong/workspace/foo/unconvertible_soong_module/BUILD"; then
+ fail "found unexpected BUILD target not_the_answer in unconvertible_soong_module/BUILD"
+ fi
+
+ if ! grep "filegroup" "./out/soong/workspace/foo/unconvertible_soong_module/BUILD"; then
+ fail "missing filegroup in unconvertible_soong_module/BUILD"
+ fi
+
+ # NOTE: We don't actually use the extra BUILD file for anything here
+ run_bazel build --package_path=out/soong/workspace //foo/...
+
+ local the_answer_file="bazel-out/k8-fastbuild/bin/foo/convertible_soong_module/the_answer.txt"
+ if [[ ! -f "${the_answer_file}" ]]; then
+ fail "Expected '${the_answer_file}' to be generated, but was missing"
+ fi
+ if ! grep 42 "${the_answer_file}"; then
+ fail "Expected to find 42 in '${the_answer_file}'"
+ fi
+}
+
+test_bp2build_generates_all_buildfiles
diff --git a/tests/lib.sh b/tests/lib.sh
index 3795dfc..e561a3d 100644
--- a/tests/lib.sh
+++ b/tests/lib.sh
@@ -1,5 +1,7 @@
#!/bin/bash -eu
+set -o pipefail
+
HARDWIRED_MOCK_TOP=
# Uncomment this to be able to view the source tree after a test is run
# HARDWIRED_MOCK_TOP=/tmp/td
@@ -102,7 +104,25 @@
}
function run_soong() {
- build/soong/soong_ui.bash --make-mode --skip-ninja --skip-make --skip-soong-tests
+ build/soong/soong_ui.bash --make-mode --skip-ninja --skip-make --skip-soong-tests "$@"
+}
+
+function create_mock_bazel() {
+ copy_directory build/bazel
+
+ symlink_directory prebuilts/bazel
+ symlink_directory prebuilts/jdk
+
+ symlink_file WORKSPACE
+ symlink_file tools/bazel
+}
+
+run_bazel() {
+ tools/bazel "$@"
+}
+
+run_bp2build() {
+ GENERATE_BAZEL_FILES=true build/soong/soong_ui.bash --make-mode --skip-ninja --skip-make --skip-soong-tests nothing
}
info "Starting Soong integration test suite $(basename $0)"
diff --git a/tests/mixed_mode_test.sh b/tests/mixed_mode_test.sh
index 7dbafea..80774bf 100755
--- a/tests/mixed_mode_test.sh
+++ b/tests/mixed_mode_test.sh
@@ -1,5 +1,7 @@
#!/bin/bash -eu
+set -o pipefail
+
# This test exercises mixed builds where Soong and Bazel cooperate in building
# Android.
#
@@ -8,21 +10,11 @@
source "$(dirname "$0")/lib.sh"
-function create_mock_bazel() {
- copy_directory build/bazel
-
- symlink_directory prebuilts/bazel
- symlink_directory prebuilts/jdk
-
- symlink_file WORKSPACE
- symlink_file tools/bazel
-}
-
function test_bazel_smoke {
setup
create_mock_bazel
- tools/bazel info
+ run_bazel info
}
test_bazel_smoke
diff --git a/tests/run_integration_tests.sh b/tests/run_integration_tests.sh
index 76b324b..8399573 100755
--- a/tests/run_integration_tests.sh
+++ b/tests/run_integration_tests.sh
@@ -1,6 +1,8 @@
#!/bin/bash -eu
+set -o pipefail
+
TOP="$(readlink -f "$(dirname "$0")"/../../..)"
"$TOP/build/soong/tests/bootstrap_test.sh"
"$TOP/build/soong/tests/mixed_mode_test.sh"
-
+"$TOP/build/soong/tests/bp2build_bazel_test.sh"
diff --git a/ui/build/build.go b/ui/build/build.go
index 3692f4f..c2ad057 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -258,8 +258,8 @@
// Run Soong
runSoong(ctx, config)
- if config.Environment().IsEnvTrue("GENERATE_BAZEL_FILES") {
- // Return early, if we're using Soong as the bp2build converter.
+ if config.bazelBuildMode() == generateBuildFiles {
+ // Return early, if we're using Soong as solely the generator of BUILD files.
return
}
}
diff --git a/ui/build/config.go b/ui/build/config.go
index 4816d1f..1d1f71f 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -93,6 +93,21 @@
BUILD_MODULES
)
+type bazelBuildMode int
+
+// Bazel-related build modes.
+const (
+ // Don't use bazel at all.
+ noBazel bazelBuildMode = iota
+
+ // Only generate build files (in a subdirectory of the out directory) and exit.
+ generateBuildFiles
+
+ // Generate synthetic build files and incorporate these files into a build which
+ // partially uses Bazel. Build metadata may come from Android.bp or BUILD files.
+ mixedBuild
+)
+
// checkTopDir validates that the current directory is at the root directory of the source tree.
func checkTopDir(ctx Context) {
if _, err := os.Stat(srcDirFileCheck); err != nil {
@@ -897,6 +912,16 @@
return c.useBazel
}
+func (c *configImpl) bazelBuildMode() bazelBuildMode {
+ if c.Environment().IsEnvTrue("USE_BAZEL_ANALYSIS") {
+ return mixedBuild
+ } else if c.Environment().IsEnvTrue("GENERATE_BAZEL_FILES") {
+ return generateBuildFiles
+ } else {
+ return noBazel
+ }
+}
+
func (c *configImpl) StartRBE() bool {
if !c.UseRBE() {
return false
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 7e94b25..a41dbe1 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -206,7 +206,8 @@
}
}
- integratedBp2Build := config.Environment().IsEnvTrue("INTEGRATED_BP2BUILD")
+ buildMode := config.bazelBuildMode()
+ integratedBp2Build := (buildMode == mixedBuild) || (buildMode == generateBuildFiles)
// This is done unconditionally, but does not take a measurable amount of time
bootstrapBlueprint(ctx, config, integratedBp2Build)
@@ -312,7 +313,7 @@
func shouldCollectBuildSoongMetrics(config Config) bool {
// Do not collect metrics protobuf if the soong_build binary ran as the bp2build converter.
- return config.Environment().IsFalse("GENERATE_BAZEL_FILES")
+ return config.bazelBuildMode() != generateBuildFiles
}
func loadSoongBuildMetrics(ctx Context, config Config) *soong_metrics_proto.SoongBuildMetrics {