Merge "Convert preview sdkVersion to int for target-api" into main
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index ee63bb4..c935101 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -434,7 +434,6 @@
"external/bazelbuild-rules_java":/* recursive = */ true,
"external/bazelbuild-rules_license":/* recursive = */ true,
"external/bazelbuild-rules_go":/* recursive = */ true,
- "external/bazelbuild-rules_python":/* recursive = */ true,
"external/bazelbuild-kotlin-rules":/* recursive = */ true,
"external/bazel-skylib":/* recursive = */ true,
"external/protobuf":/* recursive = */ false,
@@ -1644,4 +1643,14 @@
"art_": DEFAULT_PRIORITIZED_WEIGHT,
"ndk_library": DEFAULT_PRIORITIZED_WEIGHT,
}
+
+ BazelSandwichTargets = []struct {
+ Label string
+ Host bool
+ }{
+ {
+ Label: "//build/bazel/examples/partitions:system_image",
+ Host: false,
+ },
+ }
)
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 94bc88b..4c03ae6 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -186,6 +186,8 @@
// Returns the depsets defined in Bazel's aquery response.
AqueryDepsets() []bazel.AqueryDepset
+
+ QueueBazelSandwichCqueryRequests(config Config) error
}
type bazelRunner interface {
@@ -264,6 +266,10 @@
m.BazelRequests[key] = true
}
+func (m MockBazelContext) QueueBazelSandwichCqueryRequests(config Config) error {
+ panic("unimplemented")
+}
+
func (m MockBazelContext) GetOutputFiles(label string, _ configKey) ([]string, error) {
result, ok := m.LabelToOutputFiles[label]
if !ok {
@@ -424,6 +430,10 @@
panic("unimplemented")
}
+func (n noopBazelContext) QueueBazelSandwichCqueryRequests(config Config) error {
+ panic("unimplemented")
+}
+
func (n noopBazelContext) GetOutputFiles(_ string, _ configKey) ([]string, error) {
panic("unimplemented")
}
@@ -1042,6 +1052,45 @@
allBazelCommands = []bazelCommand{aqueryCmd, cqueryCmd, buildCmd}
)
+func GetBazelSandwichCqueryRequests(config Config) ([]cqueryKey, error) {
+ result := make([]cqueryKey, 0, len(allowlists.BazelSandwichTargets))
+ // Note that bazel "targets" are different from soong "targets", the bazel targets are
+ // synonymous with soong modules, and soong targets are a configuration a module is built in.
+ for _, target := range allowlists.BazelSandwichTargets {
+ var soongTarget Target
+ if target.Host {
+ soongTarget = config.BuildOSTarget
+ } else {
+ soongTarget = config.AndroidCommonTarget
+ }
+
+ result = append(result, cqueryKey{
+ label: target.Label,
+ requestType: cquery.GetOutputFiles,
+ configKey: configKey{
+ arch: soongTarget.Arch.String(),
+ osType: soongTarget.Os,
+ },
+ })
+ }
+ return result, nil
+}
+
+// QueueBazelSandwichCqueryRequests queues cquery requests for all the bazel labels in
+// bazel_sandwich_targets. These will later be given phony targets so that they can be built on the
+// command line.
+func (context *mixedBuildBazelContext) QueueBazelSandwichCqueryRequests(config Config) error {
+ requests, err := GetBazelSandwichCqueryRequests(config)
+ if err != nil {
+ return err
+ }
+ for _, request := range requests {
+ context.QueueBazelRequest(request.label, request.requestType, request.configKey)
+ }
+
+ return nil
+}
+
// Issues commands to Bazel to receive results for all cquery requests
// queued in the BazelContext.
func (context *mixedBuildBazelContext) InvokeBazel(config Config, ctx invokeBazelContext) error {
@@ -1255,6 +1304,11 @@
executionRoot := path.Join(ctx.Config().BazelContext.OutputBase(), "execroot", "__main__")
bazelOutDir := path.Join(executionRoot, "bazel-out")
+ rel, err := filepath.Rel(ctx.Config().OutDir(), executionRoot)
+ if err != nil {
+ ctx.Errorf("%s", err.Error())
+ }
+ dotdotsToOutRoot := strings.Repeat("../", strings.Count(rel, "/")+1)
for index, buildStatement := range ctx.Config().BazelContext.BuildStatementsToRegister() {
// nil build statements are a valid case where we do not create an action because it is
// unnecessary or handled by other processing
@@ -1286,7 +1340,8 @@
})
}
}
- createCommand(rule.Command(), buildStatement, executionRoot, bazelOutDir, ctx, depsetHashToDepset)
+ createCommand(rule.Command(), buildStatement, executionRoot, bazelOutDir, ctx, depsetHashToDepset, dotdotsToOutRoot)
+
desc := fmt.Sprintf("%s: %s", buildStatement.Mnemonic, buildStatement.OutputPaths)
rule.Build(fmt.Sprintf("bazel %d", index), desc)
continue
@@ -1331,6 +1386,24 @@
panic(fmt.Sprintf("unhandled build statement: %v", buildStatement))
}
}
+
+ // Create phony targets for all the bazel sandwich output files
+ requests, err := GetBazelSandwichCqueryRequests(ctx.Config())
+ if err != nil {
+ ctx.Errorf(err.Error())
+ }
+ for _, request := range requests {
+ files, err := ctx.Config().BazelContext.GetOutputFiles(request.label, request.configKey)
+ if err != nil {
+ ctx.Errorf(err.Error())
+ }
+ filesAsPaths := make([]Path, 0, len(files))
+ for _, file := range files {
+ filesAsPaths = append(filesAsPaths, PathForBazelOut(ctx, file))
+ }
+ ctx.Phony("bazel_sandwich", filesAsPaths...)
+ }
+ ctx.Phony("checkbuild", PathForPhony(ctx, "bazel_sandwich"))
}
// Returns a out dir path for a sandboxed mixed build action
@@ -1344,7 +1417,7 @@
}
// Register bazel-owned build statements (obtained from the aquery invocation).
-func createCommand(cmd *RuleBuilderCommand, buildStatement *bazel.BuildStatement, executionRoot string, bazelOutDir string, ctx BuilderContext, depsetHashToDepset map[string]bazel.AqueryDepset) {
+func createCommand(cmd *RuleBuilderCommand, buildStatement *bazel.BuildStatement, executionRoot string, bazelOutDir string, ctx BuilderContext, depsetHashToDepset map[string]bazel.AqueryDepset, dotdotsToOutRoot string) {
// executionRoot is the action cwd.
if buildStatement.ShouldRunInSbox {
// mkdir -p ensures that the directory exists when run via sbox
@@ -1367,14 +1440,17 @@
cmd.Flag(pair.Key + "=" + pair.Value)
}
+ command := buildStatement.Command
+ command = strings.ReplaceAll(command, "{DOTDOTS_TO_OUTPUT_ROOT}", dotdotsToOutRoot)
+
// The actual Bazel action.
- if len(buildStatement.Command) > 16*1024 {
+ if len(command) > 16*1024 {
commandFile := PathForBazelOut(ctx, buildStatement.OutputPaths[0]+".sh")
- WriteFileRule(ctx, commandFile, buildStatement.Command)
+ WriteFileRule(ctx, commandFile, command)
cmd.Text("bash").Text(buildStatement.OutputPaths[0] + ".sh").Implicit(commandFile)
} else {
- cmd.Text(buildStatement.Command)
+ cmd.Text(command)
}
for _, outputPath := range buildStatement.OutputPaths {
@@ -1403,6 +1479,9 @@
cmd.Implicit(PathForPhony(ctx, otherDepsetName))
}
}
+ for _, implicitPath := range buildStatement.ImplicitDeps {
+ cmd.Implicit(PathForArbitraryOutput(ctx, implicitPath))
+ }
if depfile := buildStatement.Depfile; depfile != nil {
// The paths in depfile are relative to `executionRoot`.
diff --git a/android/bazel_handler_test.go b/android/bazel_handler_test.go
index e08a471..9a3c8fc 100644
--- a/android/bazel_handler_test.go
+++ b/android/bazel_handler_test.go
@@ -181,7 +181,7 @@
cmd := RuleBuilderCommand{}
ctx := builderContextForTests{PathContextForTesting(TestConfig("out", nil, "", nil))}
- createCommand(&cmd, got[0], "test/exec_root", "test/bazel_out", ctx, map[string]bazel.AqueryDepset{})
+ createCommand(&cmd, got[0], "test/exec_root", "test/bazel_out", ctx, map[string]bazel.AqueryDepset{}, "")
if actual, expected := cmd.buf.String(), testCase.command; expected != actual {
t.Errorf("expected: [%s], actual: [%s]", expected, actual)
}
@@ -224,7 +224,7 @@
cmd := RuleBuilderCommand{}
ctx := builderContextForTests{PathContextForTesting(TestConfig("out", nil, "", nil))}
- createCommand(&cmd, statement, "test/exec_root", "test/bazel_out", ctx, map[string]bazel.AqueryDepset{})
+ createCommand(&cmd, statement, "test/exec_root", "test/bazel_out", ctx, map[string]bazel.AqueryDepset{}, "")
// Assert that the output is generated in an intermediate directory
// fe05bcdcdc4928012781a5f1a2a77cbb5398e106 is the sha1 checksum of "one"
if actual, expected := cmd.outputs[0].String(), "out/soong/mixed_build_sbox_intermediates/fe05bcdcdc4928012781a5f1a2a77cbb5398e106/test/exec_root/one"; expected != actual {
diff --git a/android/config.go b/android/config.go
index 30be7d6..72ff224 100644
--- a/android/config.go
+++ b/android/config.go
@@ -170,6 +170,19 @@
return c.config.TestProductVariables != nil
}
+// DisableHiddenApiChecks returns true if hiddenapi checks have been disabled.
+// For 'eng' target variant hiddenapi checks are disabled by default for performance optimisation,
+// but can be enabled by setting environment variable ENABLE_HIDDENAPI_FLAGS=true.
+// For other target variants hiddenapi check are enabled by default but can be disabled by
+// setting environment variable UNSAFE_DISABLE_HIDDENAPI_FLAGS=true.
+// If both ENABLE_HIDDENAPI_FLAGS=true and UNSAFE_DISABLE_HIDDENAPI_FLAGS=true, then
+// ENABLE_HIDDENAPI_FLAGS=true will be triggered and hiddenapi checks will be considered enabled.
+func (c Config) DisableHiddenApiChecks() bool {
+ return !c.IsEnvTrue("ENABLE_HIDDENAPI_FLAGS") &&
+ (c.IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") ||
+ Bool(c.productVariables.Eng))
+}
+
// MaxPageSizeSupported returns the max page size supported by the device. This
// value will define the ELF segment alignment for binaries (executables and
// shared libraries).
diff --git a/android/paths.go b/android/paths.go
index e16cb37..325a953 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -1029,16 +1029,16 @@
return p
}
+func (p basePath) RelativeToTop() Path {
+ ensureTestOnly()
+ return p
+}
+
// SourcePath is a Path representing a file path rooted from SrcDir
type SourcePath struct {
basePath
}
-func (p SourcePath) RelativeToTop() Path {
- ensureTestOnly()
- return p
-}
-
var _ Path = SourcePath{}
func (p SourcePath) withRel(rel string) SourcePath {
@@ -1126,6 +1126,16 @@
return path
}
+// PathForArbitraryOutput creates a path for the given components. Unlike PathForOutput,
+// the path is relative to the root of the output folder, not the out/soong folder.
+func PathForArbitraryOutput(ctx PathContext, pathComponents ...string) Path {
+ p, err := validatePath(pathComponents...)
+ if err != nil {
+ reportPathError(ctx, err)
+ }
+ return basePath{path: filepath.Join(ctx.Config().OutDir(), p)}
+}
+
// MaybeExistentPathForSource joins the provided path components and validates that the result
// neither escapes the source dir nor is in the out dir.
// It does not validate whether the path exists.
diff --git a/apex/apex_test.go b/apex/apex_test.go
index ed78033..9dba08e 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -6794,6 +6794,10 @@
public_key: "testkey.avbpubkey",
private_key: "testkey.pem",
}
+ override_apex {
+ name: "myoverrideapex",
+ base: "bar",
+ }
`)
fooManifestRule := result.ModuleForTests("foo", "android_common_foo_image").Rule("apexManifestRule")
@@ -6810,6 +6814,12 @@
if barActualDefaultVersion != barExpectedDefaultVersion {
t.Errorf("expected to find defaultVersion %q; got %q", barExpectedDefaultVersion, barActualDefaultVersion)
}
+
+ overrideBarManifestRule := result.ModuleForTests("bar", "android_common_myoverrideapex_bar_image").Rule("apexManifestRule")
+ overrideBarActualDefaultVersion := overrideBarManifestRule.Args["default_version"]
+ if overrideBarActualDefaultVersion != barExpectedDefaultVersion {
+ t.Errorf("expected to find defaultVersion %q; got %q", barExpectedDefaultVersion, barActualDefaultVersion)
+ }
}
func TestApexAvailable_ApexAvailableName(t *testing.T) {
diff --git a/bazel/aquery.go b/bazel/aquery.go
index 2c080a1..d77d59a 100644
--- a/bazel/aquery.go
+++ b/bazel/aquery.go
@@ -17,15 +17,15 @@
import (
"crypto/sha256"
"encoding/base64"
+ "encoding/json"
"fmt"
"path/filepath"
+ analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2"
"reflect"
"sort"
"strings"
"sync"
- analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2"
-
"github.com/google/blueprint/metrics"
"github.com/google/blueprint/proptools"
"google.golang.org/protobuf/proto"
@@ -119,6 +119,10 @@
// If ShouldRunInSbox is true, Soong will use sbox to created an isolated environment
// and run the mixed build action there
ShouldRunInSbox bool
+ // A list of files to add as implicit deps to the outputs of this BuildStatement.
+ // Unlike most properties in BuildStatement, these paths must be relative to the root of
+ // the whole out/ folder, instead of relative to ctx.Config().BazelContext.OutputBase()
+ ImplicitDeps []string
}
// A helper type for aquery processing which facilitates retrieval of path IDs from their
@@ -581,6 +585,72 @@
}, nil
}
+type bazelSandwichJson struct {
+ Target string `json:"target"`
+ DependOnTarget *bool `json:"depend_on_target,omitempty"`
+ ImplicitDeps []string `json:"implicit_deps"`
+}
+
+func (a *aqueryArtifactHandler) unresolvedSymlinkActionBuildStatement(actionEntry *analysis_v2_proto.Action) (*BuildStatement, error) {
+ outputPaths, depfile, err := a.getOutputPaths(actionEntry)
+ if err != nil {
+ return nil, err
+ }
+ if len(actionEntry.InputDepSetIds) != 0 || len(outputPaths) != 1 {
+ return nil, fmt.Errorf("expected 0 inputs and 1 output to symlink action, got: input %q, output %q", actionEntry.InputDepSetIds, outputPaths)
+ }
+ target := actionEntry.UnresolvedSymlinkTarget
+ if target == "" {
+ return nil, fmt.Errorf("expected an unresolved_symlink_target, but didn't get one")
+ }
+ if filepath.Clean(target) != target {
+ return nil, fmt.Errorf("expected %q, got %q", filepath.Clean(target), target)
+ }
+ if strings.HasPrefix(target, "/") {
+ return nil, fmt.Errorf("no absolute symlinks allowed: %s", target)
+ }
+
+ out := outputPaths[0]
+ outDir := filepath.Dir(out)
+ var implicitDeps []string
+ if strings.HasPrefix(target, "bazel_sandwich:") {
+ j := bazelSandwichJson{}
+ err := json.Unmarshal([]byte(target[len("bazel_sandwich:"):]), &j)
+ if err != nil {
+ return nil, err
+ }
+ if proptools.BoolDefault(j.DependOnTarget, true) {
+ implicitDeps = append(implicitDeps, j.Target)
+ }
+ implicitDeps = append(implicitDeps, j.ImplicitDeps...)
+ dotDotsToReachCwd := ""
+ if outDir != "." {
+ dotDotsToReachCwd = strings.Repeat("../", strings.Count(outDir, "/")+1)
+ }
+ target = proptools.ShellEscapeIncludingSpaces(j.Target)
+ target = "{DOTDOTS_TO_OUTPUT_ROOT}" + dotDotsToReachCwd + target
+ } else {
+ target = proptools.ShellEscapeIncludingSpaces(target)
+ }
+
+ outDir = proptools.ShellEscapeIncludingSpaces(outDir)
+ out = proptools.ShellEscapeIncludingSpaces(out)
+ // Use absolute paths, because some soong actions don't play well with relative paths (for example, `cp -d`).
+ command := fmt.Sprintf("mkdir -p %[1]s && rm -f %[2]s && ln -sf %[3]s %[2]s", outDir, out, target)
+ symlinkPaths := outputPaths[:]
+
+ buildStatement := &BuildStatement{
+ Command: command,
+ Depfile: depfile,
+ OutputPaths: outputPaths,
+ Env: actionEntry.EnvironmentVariables,
+ Mnemonic: actionEntry.Mnemonic,
+ SymlinkPaths: symlinkPaths,
+ ImplicitDeps: implicitDeps,
+ }
+ return buildStatement, nil
+}
+
func (a *aqueryArtifactHandler) symlinkActionBuildStatement(actionEntry *analysis_v2_proto.Action) (*BuildStatement, error) {
outputPaths, depfile, err := a.getOutputPaths(actionEntry)
if err != nil {
@@ -690,6 +760,8 @@
return a.fileWriteActionBuildStatement(actionEntry)
case "SymlinkTree":
return a.symlinkTreeActionBuildStatement(actionEntry)
+ case "UnresolvedSymlink":
+ return a.unresolvedSymlinkActionBuildStatement(actionEntry)
}
if len(actionEntry.Arguments) < 1 {
diff --git a/bazel/aquery_test.go b/bazel/aquery_test.go
index 19a584f..32c87a0 100644
--- a/bazel/aquery_test.go
+++ b/bazel/aquery_test.go
@@ -357,9 +357,11 @@
actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
if err != nil {
t.Errorf("Unexpected error %q", err)
+ return
}
if expected := 1; len(actual) != expected {
t.Fatalf("Expected %d build statements, got %d", expected, len(actual))
+ return
}
bs := actual[0]
@@ -544,6 +546,7 @@
actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
if err != nil {
t.Errorf("Unexpected error %q", err)
+ return
}
assertBuildStatements(t, []*BuildStatement{
&BuildStatement{
@@ -756,9 +759,11 @@
actualBuildStatements, actualDepsets, err := AqueryBuildStatements(data, &metrics.EventHandler{})
if err != nil {
t.Errorf("Unexpected error %q", err)
+ return
}
if expected := 2; len(actualBuildStatements) != expected {
t.Fatalf("Expected %d build statements, got %d %#v", expected, len(actualBuildStatements), actualBuildStatements)
+ return
}
expectedDepsetFiles := [][]string{
@@ -859,6 +864,7 @@
if err != nil {
t.Errorf("Unexpected error %q", err)
+ return
}
expectedBuildStatements := []*BuildStatement{
@@ -907,6 +913,7 @@
actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
if err != nil {
t.Errorf("Unexpected error %q", err)
+ return
}
expectedBuildStatements := []*BuildStatement{
@@ -1017,6 +1024,7 @@
actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
if err != nil {
t.Errorf("Unexpected error %q", err)
+ return
}
expectedBuildStatements := []*BuildStatement{
@@ -1088,6 +1096,7 @@
actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
if err != nil {
t.Errorf("Unexpected error %q", err)
+ return
}
assertBuildStatements(t, []*BuildStatement{
&BuildStatement{
@@ -1126,6 +1135,7 @@
actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
if err != nil {
t.Errorf("Unexpected error %q", err)
+ return
}
assertBuildStatements(t, []*BuildStatement{
&BuildStatement{
@@ -1136,6 +1146,126 @@
}, actual)
}
+func TestUnresolvedSymlink(t *testing.T) {
+ const inputString = `
+{
+ "artifacts": [
+ { "id": 1, "path_fragment_id": 1 }
+ ],
+ "actions": [{
+ "target_id": 1,
+ "action_key": "x",
+ "mnemonic": "UnresolvedSymlink",
+ "configuration_id": 1,
+ "output_ids": [1],
+ "primary_output_id": 1,
+ "execution_platform": "//build/bazel/platforms:linux_x86_64",
+ "unresolved_symlink_target": "symlink/target"
+ }],
+ "path_fragments": [
+ { "id": 1, "label": "path/to/symlink" }
+ ]
+}
+`
+ data, err := JsonToActionGraphContainer(inputString)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
+ if err != nil {
+ t.Errorf("Unexpected error %q", err)
+ return
+ }
+ assertBuildStatements(t, []*BuildStatement{{
+ Command: "mkdir -p path/to && rm -f path/to/symlink && ln -sf symlink/target path/to/symlink",
+ OutputPaths: []string{"path/to/symlink"},
+ Mnemonic: "UnresolvedSymlink",
+ SymlinkPaths: []string{"path/to/symlink"},
+ }}, actual)
+}
+
+func TestUnresolvedSymlinkBazelSandwich(t *testing.T) {
+ const inputString = `
+{
+ "artifacts": [
+ { "id": 1, "path_fragment_id": 1 }
+ ],
+ "actions": [{
+ "target_id": 1,
+ "action_key": "x",
+ "mnemonic": "UnresolvedSymlink",
+ "configuration_id": 1,
+ "output_ids": [1],
+ "primary_output_id": 1,
+ "execution_platform": "//build/bazel/platforms:linux_x86_64",
+ "unresolved_symlink_target": "bazel_sandwich:{\"target\":\"target/product/emulator_x86_64/system\"}"
+ }],
+ "path_fragments": [
+ { "id": 1, "label": "path/to/symlink" }
+ ]
+}
+`
+ data, err := JsonToActionGraphContainer(inputString)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
+ if err != nil {
+ t.Errorf("Unexpected error %q", err)
+ return
+ }
+ assertBuildStatements(t, []*BuildStatement{{
+ Command: "mkdir -p path/to && rm -f path/to/symlink && ln -sf {DOTDOTS_TO_OUTPUT_ROOT}../../target/product/emulator_x86_64/system path/to/symlink",
+ OutputPaths: []string{"path/to/symlink"},
+ Mnemonic: "UnresolvedSymlink",
+ SymlinkPaths: []string{"path/to/symlink"},
+ ImplicitDeps: []string{"target/product/emulator_x86_64/system"},
+ }}, actual)
+}
+
+func TestUnresolvedSymlinkBazelSandwichWithAlternativeDeps(t *testing.T) {
+ const inputString = `
+{
+ "artifacts": [
+ { "id": 1, "path_fragment_id": 1 }
+ ],
+ "actions": [{
+ "target_id": 1,
+ "action_key": "x",
+ "mnemonic": "UnresolvedSymlink",
+ "configuration_id": 1,
+ "output_ids": [1],
+ "primary_output_id": 1,
+ "execution_platform": "//build/bazel/platforms:linux_x86_64",
+ "unresolved_symlink_target": "bazel_sandwich:{\"depend_on_target\":false,\"implicit_deps\":[\"target/product/emulator_x86_64/obj/PACKAGING/systemimage_intermediates/staging_dir.stamp\"],\"target\":\"target/product/emulator_x86_64/system\"}"
+ }],
+ "path_fragments": [
+ { "id": 1, "label": "path/to/symlink" }
+ ]
+}
+`
+ data, err := JsonToActionGraphContainer(inputString)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
+ if err != nil {
+ t.Errorf("Unexpected error %q", err)
+ return
+ }
+ assertBuildStatements(t, []*BuildStatement{{
+ Command: "mkdir -p path/to && rm -f path/to/symlink && ln -sf {DOTDOTS_TO_OUTPUT_ROOT}../../target/product/emulator_x86_64/system path/to/symlink",
+ OutputPaths: []string{"path/to/symlink"},
+ Mnemonic: "UnresolvedSymlink",
+ SymlinkPaths: []string{"path/to/symlink"},
+ // Note that the target of the symlink, target/product/emulator_x86_64/system, is not listed here
+ ImplicitDeps: []string{"target/product/emulator_x86_64/obj/PACKAGING/systemimage_intermediates/staging_dir.stamp"},
+ }}, actual)
+}
+
func assertError(t *testing.T, err error, expected string) {
t.Helper()
if err == nil {
@@ -1201,6 +1331,9 @@
if !reflect.DeepEqual(sortedStrings(first.SymlinkPaths), sortedStrings(second.SymlinkPaths)) {
return "SymlinkPaths"
}
+ if !reflect.DeepEqual(sortedStrings(first.ImplicitDeps), sortedStrings(second.ImplicitDeps)) {
+ return "ImplicitDeps"
+ }
if first.Depfile != second.Depfile {
return "Depfile"
}
diff --git a/bp2build/bp2build_product_config.go b/bp2build/bp2build_product_config.go
index f56e6d8..2513af8 100644
--- a/bp2build/bp2build_product_config.go
+++ b/bp2build/bp2build_product_config.go
@@ -97,6 +97,7 @@
android_product(
name = "mixed_builds_product-{VARIANT}",
soong_variables = _soong_variables,
+ extra_constraints = ["@//build/bazel/platforms:mixed_builds"],
)
`)),
newFile(
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index 8084a5d..03e9cd0 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -1003,6 +1003,38 @@
})
}
+func TestCcLibraryStaticGeneratedHeadersMultipleExports(t *testing.T) {
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Blueprint: soongCcLibraryStaticPreamble + `
+genrule {
+ name: "generated_hdr",
+ cmd: "nothing to see here",
+ export_include_dirs: ["foo", "bar"],
+ bazel_module: { bp2build_available: false },
+}
+
+genrule {
+ name: "export_generated_hdr",
+ cmd: "nothing to see here",
+ export_include_dirs: ["a", "b"],
+ bazel_module: { bp2build_available: false },
+}
+
+cc_library_static {
+ name: "foo_static",
+ generated_headers: ["generated_hdr", "export_generated_hdr"],
+ export_generated_headers: ["export_generated_hdr"],
+ include_build_directory: false,
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
+ "deps": `[":export_generated_hdr__header_library"]`,
+ "implementation_deps": `[":generated_hdr__header_library"]`,
+ }),
+ },
+ })
+}
+
// generated_headers has "variant_prepend" tag. In bp2build output,
// variant info(select) should go before general info.
func TestCcLibraryStaticArchSrcsExcludeSrcsGeneratedFiles(t *testing.T) {
diff --git a/bp2build/genrule_conversion_test.go b/bp2build/genrule_conversion_test.go
index 5cf4fb2..5a73969 100644
--- a/bp2build/genrule_conversion_test.go
+++ b/bp2build/genrule_conversion_test.go
@@ -16,6 +16,7 @@
import (
"fmt"
+ "path/filepath"
"testing"
"android/soong/android"
@@ -695,3 +696,79 @@
})
})
}
+
+func TestGenruleWithExportIncludeDirs(t *testing.T) {
+ testCases := []struct {
+ moduleType string
+ factory android.ModuleFactory
+ hod android.HostOrDeviceSupported
+ }{
+ {
+ moduleType: "genrule",
+ factory: genrule.GenRuleFactory,
+ },
+ {
+ moduleType: "cc_genrule",
+ factory: cc.GenRuleFactory,
+ hod: android.DeviceSupported,
+ },
+ {
+ moduleType: "java_genrule",
+ factory: java.GenRuleFactory,
+ hod: android.DeviceSupported,
+ },
+ {
+ moduleType: "java_genrule_host",
+ factory: java.GenRuleFactoryHost,
+ hod: android.HostSupported,
+ },
+ }
+
+ dir := "baz"
+
+ bp := `%s {
+ name: "foo",
+ out: ["foo.out.h"],
+ srcs: ["foo.in"],
+ cmd: "cp $(in) $(out)",
+ export_include_dirs: ["foo", "bar", "."],
+ bazel_module: { bp2build_available: true },
+}`
+
+ for _, tc := range testCases {
+ moduleAttrs := AttrNameToString{
+ "cmd": `"cp $(SRCS) $(OUTS)"`,
+ "outs": `["foo.out.h"]`,
+ "srcs": `["foo.in"]`,
+ }
+
+ expectedBazelTargets := []string{
+ makeBazelTargetHostOrDevice("genrule", "foo", moduleAttrs, tc.hod),
+ makeBazelTargetHostOrDevice("cc_library_headers", "foo__header_library", AttrNameToString{
+ "hdrs": `[":foo"]`,
+ "export_includes": `[
+ "foo",
+ "baz/foo",
+ "bar",
+ "baz/bar",
+ ".",
+ "baz",
+ ]`,
+ },
+ tc.hod),
+ }
+
+ t.Run(tc.moduleType, func(t *testing.T) {
+ RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
+ Bp2buildTestCase{
+ ModuleTypeUnderTest: tc.moduleType,
+ ModuleTypeUnderTestFactory: tc.factory,
+ Filesystem: map[string]string{
+ filepath.Join(dir, "Android.bp"): fmt.Sprintf(bp, tc.moduleType),
+ },
+ Dir: dir,
+ ExpectedBazelTargets: expectedBazelTargets,
+ })
+ })
+ }
+}
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 9895a20..9e485d6 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -22,6 +22,7 @@
"android/soong/android"
"android/soong/bazel"
"android/soong/cc/config"
+ "android/soong/genrule"
"github.com/google/blueprint"
@@ -45,6 +46,8 @@
xsdSrcPartition = "xsd"
+ genrulePartition = "genrule"
+
hdrPartition = "hdr"
stubsSuffix = "_stub_libs_current"
@@ -172,8 +175,9 @@
func partitionHeaders(ctx android.BazelConversionPathContext, hdrs bazel.LabelListAttribute) bazel.PartitionToLabelListAttribute {
labels := bazel.LabelPartitions{
- xsdSrcPartition: bazel.LabelPartition{LabelMapper: android.XsdLabelMapper(xsdConfigCppTarget)},
- hdrPartition: bazel.LabelPartition{Keep_remainder: true},
+ xsdSrcPartition: bazel.LabelPartition{LabelMapper: android.XsdLabelMapper(xsdConfigCppTarget)},
+ genrulePartition: bazel.LabelPartition{LabelMapper: genrule.GenruleCcHeaderLabelMapper},
+ hdrPartition: bazel.LabelPartition{Keep_remainder: true},
}
return bazel.PartitionLabelListAttribute(ctx, &hdrs, labels)
}
@@ -419,6 +423,10 @@
xsdSrcs bazel.LabelListAttribute
exportXsdSrcs bazel.LabelListAttribute
+ // genrule headers
+ genruleHeaders bazel.LabelListAttribute
+ exportGenruleHeaders bazel.LabelListAttribute
+
// Lex sources and options
lSrcs bazel.LabelListAttribute
llSrcs bazel.LabelListAttribute
@@ -606,6 +614,9 @@
ca.exportXsdSrcs = partitionedHdrs[xsdSrcPartition]
ca.xsdSrcs = bazel.FirstUniqueBazelLabelListAttribute(xsdSrcs)
+ ca.genruleHeaders = partitionedImplHdrs[genrulePartition]
+ ca.exportGenruleHeaders = partitionedHdrs[genrulePartition]
+
ca.srcs = partitionedSrcs[cppSrcPartition]
ca.cSrcs = partitionedSrcs[cSrcPartition]
ca.asSrcs = partitionedSrcs[asSrcPartition]
@@ -900,6 +911,9 @@
(&compilerAttrs.srcs).Add(bp2BuildYasm(ctx, module, compilerAttrs))
+ (&linkerAttrs).deps.Append(compilerAttrs.exportGenruleHeaders)
+ (&linkerAttrs).implementationDeps.Append(compilerAttrs.genruleHeaders)
+
(&linkerAttrs).wholeArchiveDeps.Append(compilerAttrs.exportXsdSrcs)
(&linkerAttrs).implementationWholeArchiveDeps.Append(compilerAttrs.xsdSrcs)
diff --git a/cc/coverage.go b/cc/coverage.go
index c0f6973..cbd8a6f 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -48,6 +48,7 @@
func getGcovProfileLibraryName(ctx ModuleContextIntf) string {
// This function should only ever be called for a cc.Module, so the
// following statement should always succeed.
+ // LINT.IfChange
if ctx.useSdk() {
return "libprofile-extras_ndk"
} else {
@@ -63,6 +64,7 @@
} else {
return "libprofile-clang-extras"
}
+ // LINT.ThenChange(library.go)
}
func (cov *coverage) deps(ctx DepsContext, deps Deps) Deps {
diff --git a/cc/library.go b/cc/library.go
index 266fa75..df1dbc5 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -32,6 +32,20 @@
"github.com/google/blueprint/proptools"
)
+var (
+ alwaysLinkLibraries = map[string]bool{
+ // Coverage libraries are _always_ added as a whole_static_dep. By converting as these as
+ // alwayslink = True, we can add these as to deps (e.g. as a regular static dep) in Bazel
+ // without any extra complications in cc_shared_library roots to prevent linking the same
+ // library repeatedly.
+ "libprofile-extras_ndk": true,
+ "libprofile-extras": true,
+ "libprofile-clang-extras_ndk": true,
+ "libprofile-clang-extras_cfi_support": true,
+ "libprofile-clang-extras": true,
+ }
+)
+
// LibraryProperties is a collection of properties shared by cc library rules/cc.
type LibraryProperties struct {
// local file name to pass to the linker as -unexported_symbols_list
@@ -435,6 +449,10 @@
Bzl_load_location: "//build/bazel/rules/cc:cc_library_shared.bzl",
}
+ if _, ok := alwaysLinkLibraries[m.Name()]; ok {
+ staticTargetAttrs.Alwayslink = proptools.BoolPtr(true)
+ }
+
var tagsForStaticVariant bazel.StringListAttribute
if compilerAttrs.stubsSymbolFile == nil && len(compilerAttrs.stubsVersions.Value) == 0 {
tagsForStaticVariant = android.ApexAvailableTagsWithoutTestApexes(ctx, m)
@@ -2951,6 +2969,10 @@
var attrs interface{}
if isStatic {
commonAttrs.Deps.Add(baseAttributes.protoDependency)
+ var alwayslink *bool
+ if _, ok := alwaysLinkLibraries[module.Name()]; ok && isStatic {
+ alwayslink = proptools.BoolPtr(true)
+ }
attrs = &bazelCcLibraryStaticAttributes{
staticOrSharedAttributes: commonAttrs,
Rtti: compilerAttrs.rtti,
@@ -2964,8 +2986,10 @@
Conlyflags: compilerAttrs.conlyFlags,
Asflags: asFlags,
- Features: *features,
+ Alwayslink: alwayslink,
+ Features: *features,
}
+
} else {
commonAttrs.Dynamic_deps.Add(baseAttributes.protoDependency)
@@ -3047,7 +3071,8 @@
Conlyflags bazel.StringListAttribute
Asflags bazel.StringListAttribute
- Features bazel.StringListAttribute
+ Alwayslink *bool
+ Features bazel.StringListAttribute
}
// TODO(b/199902614): Can this be factored to share with the other Attributes?
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 6c38355..c1ef970 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -56,10 +56,6 @@
// higher number of "optimized out" stack variables.
// b/112437883.
"-instcombine-lower-dbg-declare=0",
- // TODO(b/159343917): HWASan and GlobalISel don't play nicely, and
- // GlobalISel is the default at -O0 on aarch64.
- "--aarch64-enable-global-isel-at-O=-1",
- "-fast-isel=false",
"-hwasan-use-after-scope=1",
"-dom-tree-reachability-max-bbs-to-explore=128",
}
@@ -675,6 +671,12 @@
s.Integer_overflow = nil
}
+ // TODO(b/254713216): CFI doesn't work for riscv64 yet because LTO doesn't work.
+ if ctx.Arch().ArchType == android.Riscv64 {
+ s.Cfi = nil
+ s.Diag.Cfi = nil
+ }
+
// Disable CFI for musl
if ctx.toolchain().Musl() {
s.Cfi = nil
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 5ea84bc..62b3333 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -121,6 +121,10 @@
defer ctx.EventHandler.End("mixed_build")
bazelHook := func() error {
+ err := ctx.Config().BazelContext.QueueBazelSandwichCqueryRequests(ctx.Config())
+ if err != nil {
+ return err
+ }
return ctx.Config().BazelContext.InvokeBazel(ctx.Config(), ctx)
}
ctx.SetBeforePrepareBuildActionsHook(bazelHook)
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 6306c27..69ba1e9 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -994,6 +994,7 @@
tags := android.ApexAvailableTagsWithoutTestApexes(ctx, m)
+ bazelName := m.Name()
if ctx.ModuleType() == "gensrcs" {
props := bazel.BazelTargetModuleProperties{
Rule_class: "gensrcs",
@@ -1021,7 +1022,6 @@
break
}
}
- bazelName := m.Name()
for _, out := range outs {
if out == bazelName {
// This is a workaround to circumvent a Bazel warning where a genrule's
@@ -1046,6 +1046,54 @@
Tags: tags,
}, attrs)
}
+
+ if m.needsCcLibraryHeadersBp2build() {
+ includeDirs := make([]string, len(m.properties.Export_include_dirs)*2)
+ for i, dir := range m.properties.Export_include_dirs {
+ includeDirs[i*2] = dir
+ includeDirs[i*2+1] = filepath.Clean(filepath.Join(ctx.ModuleDir(), dir))
+ }
+ attrs := &ccHeaderLibraryAttrs{
+ Hdrs: []string{":" + bazelName},
+ Export_includes: includeDirs,
+ }
+ props := bazel.BazelTargetModuleProperties{
+ Rule_class: "cc_library_headers",
+ Bzl_load_location: "//build/bazel/rules/cc:cc_library_headers.bzl",
+ }
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{
+ Name: m.Name() + genruleHeaderLibrarySuffix,
+ Tags: tags,
+ }, attrs)
+
+ }
+}
+
+const genruleHeaderLibrarySuffix = "__header_library"
+
+func (m *Module) needsCcLibraryHeadersBp2build() bool {
+ return len(m.properties.Export_include_dirs) > 0
+}
+
+// GenruleCcHeaderMapper is a bazel.LabelMapper function to map genrules to a cc_library_headers
+// target when they export multiple include directories.
+func GenruleCcHeaderLabelMapper(ctx bazel.OtherModuleContext, label bazel.Label) (string, bool) {
+ mod, exists := ctx.ModuleFromName(label.OriginalModuleName)
+ if !exists {
+ return label.Label, false
+ }
+ if m, ok := mod.(*Module); ok {
+ if m.needsCcLibraryHeadersBp2build() {
+ return label.Label + genruleHeaderLibrarySuffix, true
+ }
+ }
+ return label.Label, false
+}
+
+type ccHeaderLibraryAttrs struct {
+ Hdrs []string
+
+ Export_includes []string
}
var Bool = proptools.Bool
@@ -1099,6 +1147,7 @@
}
}).(*sandboxingAllowlistSets)
}
+
func getSandboxedRuleBuilder(ctx android.ModuleContext, r *android.RuleBuilder) *android.RuleBuilder {
if !ctx.DeviceConfig().GenruleSandboxing() {
return r.SandboxTools()
diff --git a/java/app_builder.go b/java/app_builder.go
index e241adb..d397ff7 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -268,12 +268,24 @@
Args: args,
})
if len(prebuiltJniPackages) > 0 {
+ var mergeJniJarPath android.WritablePath = android.PathForModuleOut(ctx, "mergeJniJarOutput.zip")
+ if !uncompressJNI {
+ mergeJniJarPath = outputFile
+ }
ctx.Build(pctx, android.BuildParams{
Rule: mergeAssetsRule,
Description: "merge prebuilt JNI packages",
Inputs: append(prebuiltJniPackages, jniJarPath),
- Output: outputFile,
+ Output: mergeJniJarPath,
})
+
+ if uncompressJNI {
+ ctx.Build(pctx, android.BuildParams{
+ Rule: uncompressEmbeddedJniLibsRule,
+ Input: mergeJniJarPath,
+ Output: outputFile,
+ })
+ }
}
}
diff --git a/java/core-libraries/Android.bp b/java/core-libraries/Android.bp
index eadd9c6..de9a82d 100644
--- a/java/core-libraries/Android.bp
+++ b/java/core-libraries/Android.bp
@@ -146,12 +146,43 @@
],
}
+java_defaults {
+ name: "core.module_lib.stubs.defaults",
+ visibility: ["//visibility:private"],
+ sdk_version: "none",
+ system_modules: "none",
+}
+
+
// A stubs target containing the parts of the public SDK & @SystemApi(MODULE_LIBRARIES) API
// provided by the core libraries.
//
// Don't use this directly, use "sdk_version: module_current".
java_library {
name: "core.module_lib.stubs",
+ defaults: [
+ "core.module_lib.stubs.defaults",
+ ],
+ static_libs: [
+ "core.module_lib.stubs.from-source",
+ ],
+ product_variables: {
+ build_from_text_stub: {
+ static_libs: [
+ "core.module_lib.stubs.from-text",
+ ],
+ exclude_static_libs: [
+ "core.module_lib.stubs.from-source",
+ ],
+ },
+ },
+}
+
+java_library {
+ name: "core.module_lib.stubs.from-source",
+ defaults: [
+ "core.module_lib.stubs.defaults",
+ ],
static_libs: [
"art.module.public.api.stubs.module_lib",
@@ -161,9 +192,6 @@
"conscrypt.module.public.api.stubs",
"i18n.module.public.api.stubs",
],
- sdk_version: "none",
- system_modules: "none",
- visibility: ["//visibility:private"],
}
// Produces a dist file that is used by the
@@ -249,10 +277,10 @@
product_variables: {
build_from_text_stub: {
static_libs: [
- "stable.core.platform.api.stubs.from-text",
+ "legacy.core.platform.api.stubs.from-text",
],
exclude_static_libs: [
- "stable.core.platform.api.stubs.from-source",
+ "legacy.core.platform.api.stubs.from-source",
],
},
},
diff --git a/java/core-libraries/TxtStubLibraries.bp b/java/core-libraries/TxtStubLibraries.bp
index 0cf0f36..c46f8b8 100644
--- a/java/core-libraries/TxtStubLibraries.bp
+++ b/java/core-libraries/TxtStubLibraries.bp
@@ -57,19 +57,23 @@
],
}
-java_library {
+java_api_library {
name: "core.module_lib.stubs.from-text",
- static_libs: [
- "art.module.public.api.stubs.module_lib.from-text",
+ api_surface: "module-lib",
+ api_contributions: [
+ "art.module.public.api.stubs.source.api.contribution",
+ "art.module.public.api.stubs.source.system.api.contribution",
+ "art.module.public.api.stubs.source.module_lib.api.contribution",
- // Replace the following with the module-lib correspondence when Conscrypt or i18N module
+ // Add the module-lib correspondence when Conscrypt or i18N module
// provides @SystemApi(MODULE_LIBRARIES). Currently, assume that only ART module provides
// @SystemApi(MODULE_LIBRARIES).
- "conscrypt.module.public.api.stubs.from-text",
- "i18n.module.public.api.stubs.from-text",
+ "conscrypt.module.public.api.stubs.source.api.contribution",
+ "i18n.module.public.api.stubs.source.api.contribution",
],
- sdk_version: "none",
- system_modules: "none",
+ libs: [
+ "stub-annotations",
+ ],
visibility: ["//visibility:private"],
}
diff --git a/java/hiddenapi.go b/java/hiddenapi.go
index d25096b..4d08b83 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -106,7 +106,7 @@
h.uncompressDexState = uncompressedDexState
// If hiddenapi processing is disabled treat this as inactive.
- if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
+ if ctx.Config().DisableHiddenApiChecks() {
return
}
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index 714634f..8ec1797 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -121,8 +121,8 @@
// hiddenAPI singleton rules
func (h *hiddenAPISingleton) GenerateBuildActions(ctx android.SingletonContext) {
- // Don't run any hiddenapi rules if UNSAFE_DISABLE_HIDDENAPI_FLAGS=true
- if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
+ // Don't run any hiddenapi rules if hiddenapi checks are disabled
+ if ctx.Config().DisableHiddenApiChecks() {
return
}
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index a4bba48..ade7395 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -113,7 +113,7 @@
}
func (b *platformBootclasspathModule) hiddenAPIDepsMutator(ctx android.BottomUpMutatorContext) {
- if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
+ if ctx.Config().DisableHiddenApiChecks() {
return
}
@@ -275,10 +275,10 @@
bootDexJarByModule := extractBootDexJarsFromModules(ctx, modules)
- // Don't run any hiddenapi rules if UNSAFE_DISABLE_HIDDENAPI_FLAGS=true. This is a performance
+ // Don't run any hiddenapi rules if hidden api checks are disabled. This is a performance
// optimization that can be used to reduce the incremental build time but as its name suggests it
// can be unsafe to use, e.g. when the changes affect anything that goes on the bootclasspath.
- if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
+ if ctx.Config().DisableHiddenApiChecks() {
paths := android.OutputPaths{b.hiddenAPIFlagsCSV, b.hiddenAPIIndexCSV, b.hiddenAPIMetadataCSV}
for _, path := range paths {
ctx.Build(pctx, android.BuildParams{
diff --git a/rust/bindgen.go b/rust/bindgen.go
index 59585aa..c2bf6af 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -61,15 +61,18 @@
"${cc_config.ClangBase}/${bindgenHostPrebuiltTag}/${bindgenClangVersion}/${bindgenClangLibdir}")
//TODO(ivanlozano) Switch this to RuleBuilder
+ //
+ //TODO Pass the flag files directly to bindgen e.g. with @file when it supports that.
+ //See https://github.com/rust-lang/rust-bindgen/issues/2508.
bindgen = pctx.AndroidStaticRule("bindgen",
blueprint.RuleParams{
Command: "CLANG_PATH=$bindgenClang LIBCLANG_PATH=$bindgenLibClang RUSTFMT=${config.RustBin}/rustfmt " +
- "$cmd $flags $in -o $out -- -MD -MF $out.d $cflags",
+ "$cmd $flags $$(cat $flagfiles) $in -o $out -- -MD -MF $out.d $cflags",
CommandDeps: []string{"$cmd"},
Deps: blueprint.DepsGCC,
Depfile: "$out.d",
},
- "cmd", "flags", "cflags")
+ "cmd", "flags", "flagfiles", "cflags")
)
func init() {
@@ -90,6 +93,9 @@
// list of bindgen-specific flags and options
Bindgen_flags []string `android:"arch_variant"`
+ // list of files containing extra bindgen flags
+ Bindgen_flag_files []string `android:"arch_variant"`
+
// module name of a custom binary/script which should be used instead of the 'bindgen' binary. This custom
// binary must expect arguments in a similar fashion to bindgen, e.g.
//
@@ -216,6 +222,14 @@
bindgenFlags := defaultBindgenFlags
bindgenFlags = append(bindgenFlags, esc(b.Properties.Bindgen_flags)...)
+ // cat reads from stdin if its command line is empty,
+ // so we pass in /dev/null if there are no other flag files
+ bindgenFlagFiles := []string{"/dev/null"}
+ for _, flagFile := range b.Properties.Bindgen_flag_files {
+ bindgenFlagFiles = append(bindgenFlagFiles, android.PathForModuleSrc(ctx, flagFile).String())
+ implicits = append(implicits, android.PathForModuleSrc(ctx, flagFile))
+ }
+
wrapperFile := android.OptionalPathForModuleSrc(ctx, b.Properties.Wrapper_src)
if !wrapperFile.Valid() {
ctx.PropertyErrorf("wrapper_src", "invalid path to wrapper source")
@@ -261,9 +275,10 @@
Input: wrapperFile.Path(),
Implicits: implicits,
Args: map[string]string{
- "cmd": cmd,
- "flags": strings.Join(bindgenFlags, " "),
- "cflags": strings.Join(cflags, " "),
+ "cmd": cmd,
+ "flags": strings.Join(bindgenFlags, " "),
+ "flagfiles": strings.Join(bindgenFlagFiles, " "),
+ "cflags": strings.Join(cflags, " "),
},
})
diff --git a/rust/bindgen_test.go b/rust/bindgen_test.go
index af04cfc..12cdb3c 100644
--- a/rust/bindgen_test.go
+++ b/rust/bindgen_test.go
@@ -168,3 +168,28 @@
}
`)
}
+
+func TestBindgenFlagFile(t *testing.T) {
+ ctx := testRust(t, `
+ rust_bindgen {
+ name: "libbindgen",
+ wrapper_src: "src/any.h",
+ crate_name: "bindgen",
+ stem: "libbindgen",
+ source_stem: "bindings",
+ bindgen_flag_files: [
+ "flag_file.txt",
+ ],
+ }
+ `)
+ libbindgen := ctx.ModuleForTests("libbindgen", "android_arm64_armv8-a_source").Output("bindings.rs")
+
+ if !strings.Contains(libbindgen.Args["flagfiles"], "/dev/null") {
+ t.Errorf("missing /dev/null in rust_bindgen rule: flags %#v", libbindgen.Args["flagfiles"])
+ }
+ if !strings.Contains(libbindgen.Args["flagfiles"], "flag_file.txt") {
+ t.Errorf("missing bindgen flags file in rust_bindgen rule: flags %#v", libbindgen.Args["flagfiles"])
+ }
+ // TODO: The best we can do right now is check $flagfiles. Once bindgen.go switches to RuleBuilder,
+ // we may be able to check libbinder.RuleParams.Command to see if it contains $(cat /dev/null flag_file.txt)
+}
diff --git a/rust/builder.go b/rust/builder.go
index c31bc88..fbceecc 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -228,6 +228,17 @@
pkgVersion := ctx.RustModule().compiler.CargoPkgVersion()
if pkgVersion != "" {
envVars = append(envVars, "CARGO_PKG_VERSION="+pkgVersion)
+
+ // Ensure the version is in the form of "x.y.z" (approximately semver compliant).
+ //
+ // For our purposes, we don't care to enforce that these are integers since they may
+ // include other characters at times (e.g. sometimes the patch version is more than an integer).
+ if strings.Count(pkgVersion, ".") == 2 {
+ var semver_parts = strings.Split(pkgVersion, ".")
+ envVars = append(envVars, "CARGO_PKG_VERSION_MAJOR="+semver_parts[0])
+ envVars = append(envVars, "CARGO_PKG_VERSION_MINOR="+semver_parts[1])
+ envVars = append(envVars, "CARGO_PKG_VERSION_PATCH="+semver_parts[2])
+ }
}
}
diff --git a/rust/sanitize.go b/rust/sanitize.go
index 0f7cf6e..862baf7 100644
--- a/rust/sanitize.go
+++ b/rust/sanitize.go
@@ -223,11 +223,16 @@
if !sanitize.Properties.SanitizerEnabled {
return flags, deps
}
+
if Bool(sanitize.Properties.Sanitize.Fuzzer) {
flags.RustFlags = append(flags.RustFlags, fuzzerFlags...)
- } else if Bool(sanitize.Properties.Sanitize.Hwaddress) {
+ }
+
+ if Bool(sanitize.Properties.Sanitize.Hwaddress) {
flags.RustFlags = append(flags.RustFlags, hwasanFlags...)
- } else if Bool(sanitize.Properties.Sanitize.Address) {
+ }
+
+ if Bool(sanitize.Properties.Sanitize.Address) {
flags.RustFlags = append(flags.RustFlags, asanFlags...)
}
return flags, deps
@@ -267,14 +272,12 @@
var depTag blueprint.DependencyTag
var deps []string
- if mod.IsSanitizerEnabled(cc.Asan) ||
- (mod.IsSanitizerEnabled(cc.Fuzzer) && (mctx.Arch().ArchType != android.Arm64 || !mctx.Os().Bionic())) {
+ if mod.IsSanitizerEnabled(cc.Asan) {
variations = append(variations,
blueprint.Variation{Mutator: "link", Variation: "shared"})
depTag = cc.SharedDepTag()
deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "asan")}
- } else if mod.IsSanitizerEnabled(cc.Hwasan) ||
- (mod.IsSanitizerEnabled(cc.Fuzzer) && mctx.Arch().ArchType == android.Arm64 && mctx.Os().Bionic()) {
+ } else if mod.IsSanitizerEnabled(cc.Hwasan) {
// TODO(b/204776996): HWASan for static Rust binaries isn't supported yet.
if binary, ok := mod.compiler.(binaryInterface); ok {
if binary.staticallyLinked() {