Merge "Pass pointer to dependencyTag instead of copying struct"
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index fa26fc8..c4eb0f3 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -825,14 +825,14 @@
for _, depset := range ctx.Config().BazelContext.AqueryDepsets() {
var outputs []Path
- for _, depsetDepId := range depset.TransitiveDepSetIds {
- otherDepsetName := bazelDepsetName(depsetDepId)
+ for _, depsetDepHash := range depset.TransitiveDepSetHashes {
+ otherDepsetName := bazelDepsetName(depsetDepHash)
outputs = append(outputs, PathForPhony(ctx, otherDepsetName))
}
for _, artifactPath := range depset.DirectArtifacts {
outputs = append(outputs, PathForBazelOut(ctx, artifactPath))
}
- thisDepsetName := bazelDepsetName(depset.Id)
+ thisDepsetName := bazelDepsetName(depset.ContentHash)
ctx.Build(pctx, BuildParams{
Rule: blueprint.Phony,
Outputs: []WritablePath{PathForPhony(ctx, thisDepsetName)},
@@ -874,8 +874,8 @@
for _, inputPath := range buildStatement.InputPaths {
cmd.Implicit(PathForBazelOut(ctx, inputPath))
}
- for _, inputDepsetId := range buildStatement.InputDepsetIds {
- otherDepsetName := bazelDepsetName(inputDepsetId)
+ for _, inputDepsetHash := range buildStatement.InputDepsetHashes {
+ otherDepsetName := bazelDepsetName(inputDepsetHash)
cmd.Implicit(PathForPhony(ctx, otherDepsetName))
}
@@ -924,6 +924,6 @@
}
}
-func bazelDepsetName(depsetId int) string {
- return fmt.Sprintf("bazel_depset_%d", depsetId)
+func bazelDepsetName(contentHash string) string {
+ return fmt.Sprintf("bazel_depset_%s", contentHash)
}
diff --git a/bazel/aquery.go b/bazel/aquery.go
index e05cbd6..fe0a390 100644
--- a/bazel/aquery.go
+++ b/bazel/aquery.go
@@ -15,10 +15,13 @@
package bazel
import (
+ "crypto/sha256"
"encoding/json"
"fmt"
"path/filepath"
+ "reflect"
"regexp"
+ "sort"
"strings"
"github.com/google/blueprint/proptools"
@@ -44,15 +47,16 @@
}
// AqueryDepset is a depset definition from Bazel's aquery response. This is
-// akin to the `depSetOfFiles` in the response proto, except that direct
-// artifacts are enumerated by full path instead of by ID.
+// akin to the `depSetOfFiles` in the response proto, except:
+// * direct artifacts are enumerated by full path instead of by ID
+// * has a hash of the depset contents, instead of an int ID (for determinism)
// A depset is a data structure for efficient transitive handling of artifact
// paths. A single depset consists of one or more artifact paths and one or
// more "child" depsets.
type AqueryDepset struct {
- Id int
- DirectArtifacts []string
- TransitiveDepSetIds []int
+ ContentHash string
+ DirectArtifacts []string
+ TransitiveDepSetHashes []string
}
// depSetOfFiles contains relevant portions of Bazel's aquery proto, DepSetOfFiles.
@@ -99,19 +103,24 @@
// input paths. There should be no overlap between these fields; an input
// path should either be included as part of an unexpanded depset or a raw
// input path string, but not both.
- InputDepsetIds []int
- InputPaths []string
+ InputDepsetHashes []string
+ InputPaths []string
}
// A helper type for aquery processing which facilitates retrieval of path IDs from their
// less readable Bazel structures (depset and path fragment).
type aqueryArtifactHandler struct {
- // Maps depset Id to depset struct.
- depsetIdToDepset map[int]depSetOfFiles
+ // Maps depset id to AqueryDepset, a representation of depset which is
+ // post-processed for middleman artifact handling, unhandled artifact
+ // dropping, content hashing, etc.
+ depsetIdToAqueryDepset map[int]AqueryDepset
+ // Maps content hash to AqueryDepset.
+ depsetHashToAqueryDepset map[string]AqueryDepset
+
// depsetIdToArtifactIdsCache is a memoization of depset flattening, because flattening
// may be an expensive operation.
- depsetIdToArtifactIdsCache map[int][]int
- // Maps artifact Id to fully expanded path.
+ depsetHashToArtifactPathsCache map[string][]string
+ // Maps artifact ContentHash to fully expanded path.
artifactIdToPath map[int]string
}
@@ -127,7 +136,7 @@
var manifestFilePattern = regexp.MustCompile(".*/.+\\.runfiles/MANIFEST$")
// The file name of py3wrapper.sh, which is used by py_binary targets.
-var py3wrapperFileName = "/py3wrapper.sh"
+const py3wrapperFileName = "/py3wrapper.sh"
func newAqueryHandler(aqueryResult actionGraphContainer) (*aqueryArtifactHandler, error) {
pathFragments := map[int]pathFragment{}
@@ -144,7 +153,7 @@
artifactIdToPath[artifact.Id] = artifactPath
}
- // Map middleman artifact Id to input artifact depset ID.
+ // Map middleman artifact ContentHash to input artifact depset ID.
// Middleman artifacts are treated as "substitute" artifacts for mixed builds. For example,
// if we find a middleman action which has outputs [foo, bar], and output [baz_middleman], then,
// for each other action which has input [baz_middleman], we add [foo, bar] to the inputs for
@@ -165,50 +174,84 @@
}
depsetIdToDepset := map[int]depSetOfFiles{}
- // Validate and adjust aqueryResult.DepSetOfFiles values.
for _, depset := range aqueryResult.DepSetOfFiles {
- filteredArtifactIds := []int{}
- for _, artifactId := range depset.DirectArtifactIds {
- path, pathExists := artifactIdToPath[artifactId]
- if !pathExists {
- return nil, fmt.Errorf("undefined input artifactId %d", artifactId)
- }
- // Filter out any inputs which are universally dropped, and swap middleman
- // artifacts with their corresponding depsets.
- if depsetsToUse, isMiddleman := middlemanIdToDepsetIds[artifactId]; isMiddleman {
- // Swap middleman artifacts with their corresponding depsets and drop the middleman artifacts.
- depset.TransitiveDepSetIds = append(depset.TransitiveDepSetIds, depsetsToUse...)
- } else if strings.HasSuffix(path, py3wrapperFileName) || manifestFilePattern.MatchString(path) {
- // Drop these artifacts.
- // See go/python-binary-host-mixed-build for more details.
- // 1) For py3wrapper.sh, there is no action for creating py3wrapper.sh in the aquery output of
- // Bazel py_binary targets, so there is no Ninja build statements generated for creating it.
- // 2) For MANIFEST file, SourceSymlinkManifest action is in aquery output of Bazel py_binary targets,
- // but it doesn't contain sufficient information so no Ninja build statements are generated
- // for creating it.
- // So in mixed build mode, when these two are used as input of some Ninja build statement,
- // since there is no build statement to create them, they should be removed from input paths.
- // TODO(b/197135294): Clean up this custom runfiles handling logic when
- // SourceSymlinkManifest and SymlinkTree actions are supported.
- } else {
- // TODO(b/216194240): Filter out bazel tools.
- filteredArtifactIds = append(filteredArtifactIds, artifactId)
- }
- }
- depset.DirectArtifactIds = filteredArtifactIds
- for _, childDepsetId := range depset.TransitiveDepSetIds {
- if _, exists := depsetIds[childDepsetId]; !exists {
- return nil, fmt.Errorf("undefined input depsetId %d (referenced by depsetId %d)", childDepsetId, depset.Id)
- }
- }
depsetIdToDepset[depset.Id] = depset
}
- return &aqueryArtifactHandler{
- depsetIdToDepset: depsetIdToDepset,
- depsetIdToArtifactIdsCache: map[int][]int{},
- artifactIdToPath: artifactIdToPath,
- }, nil
+ aqueryHandler := aqueryArtifactHandler{
+ depsetIdToAqueryDepset: map[int]AqueryDepset{},
+ depsetHashToAqueryDepset: map[string]AqueryDepset{},
+ depsetHashToArtifactPathsCache: map[string][]string{},
+ artifactIdToPath: artifactIdToPath,
+ }
+
+ // Validate and adjust aqueryResult.DepSetOfFiles values.
+ for _, depset := range aqueryResult.DepSetOfFiles {
+ _, err := aqueryHandler.populateDepsetMaps(depset, middlemanIdToDepsetIds, depsetIdToDepset)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return &aqueryHandler, nil
+}
+
+// Ensures that the handler's depsetIdToAqueryDepset map contains an entry for the given
+// depset.
+func (a *aqueryArtifactHandler) populateDepsetMaps(depset depSetOfFiles, middlemanIdToDepsetIds map[int][]int, depsetIdToDepset map[int]depSetOfFiles) (AqueryDepset, error) {
+ if aqueryDepset, containsDepset := a.depsetIdToAqueryDepset[depset.Id]; containsDepset {
+ return aqueryDepset, nil
+ }
+ transitiveDepsetIds := depset.TransitiveDepSetIds
+ directArtifactPaths := []string{}
+ for _, artifactId := range depset.DirectArtifactIds {
+ path, pathExists := a.artifactIdToPath[artifactId]
+ if !pathExists {
+ return AqueryDepset{}, fmt.Errorf("undefined input artifactId %d", artifactId)
+ }
+ // Filter out any inputs which are universally dropped, and swap middleman
+ // artifacts with their corresponding depsets.
+ if depsetsToUse, isMiddleman := middlemanIdToDepsetIds[artifactId]; isMiddleman {
+ // Swap middleman artifacts with their corresponding depsets and drop the middleman artifacts.
+ transitiveDepsetIds = append(transitiveDepsetIds, depsetsToUse...)
+ } else if strings.HasSuffix(path, py3wrapperFileName) || manifestFilePattern.MatchString(path) {
+ // Drop these artifacts.
+ // See go/python-binary-host-mixed-build for more details.
+ // 1) For py3wrapper.sh, there is no action for creating py3wrapper.sh in the aquery output of
+ // Bazel py_binary targets, so there is no Ninja build statements generated for creating it.
+ // 2) For MANIFEST file, SourceSymlinkManifest action is in aquery output of Bazel py_binary targets,
+ // but it doesn't contain sufficient information so no Ninja build statements are generated
+ // for creating it.
+ // So in mixed build mode, when these two are used as input of some Ninja build statement,
+ // since there is no build statement to create them, they should be removed from input paths.
+ // TODO(b/197135294): Clean up this custom runfiles handling logic when
+ // SourceSymlinkManifest and SymlinkTree actions are supported.
+ } else {
+ // TODO(b/216194240): Filter out bazel tools.
+ directArtifactPaths = append(directArtifactPaths, path)
+ }
+ }
+
+ childDepsetHashes := []string{}
+ for _, childDepsetId := range transitiveDepsetIds {
+ childDepset, exists := depsetIdToDepset[childDepsetId]
+ if !exists {
+ return AqueryDepset{}, fmt.Errorf("undefined input depsetId %d (referenced by depsetId %d)", childDepsetId, depset.Id)
+ }
+ childAqueryDepset, err := a.populateDepsetMaps(childDepset, middlemanIdToDepsetIds, depsetIdToDepset)
+ if err != nil {
+ return AqueryDepset{}, err
+ }
+ childDepsetHashes = append(childDepsetHashes, childAqueryDepset.ContentHash)
+ }
+ aqueryDepset := AqueryDepset{
+ ContentHash: depsetContentHash(directArtifactPaths, childDepsetHashes),
+ DirectArtifacts: directArtifactPaths,
+ TransitiveDepSetHashes: childDepsetHashes,
+ }
+ a.depsetIdToAqueryDepset[depset.Id] = aqueryDepset
+ a.depsetHashToAqueryDepset[aqueryDepset.ContentHash] = aqueryDepset
+ return aqueryDepset, nil
}
// getInputPaths flattens the depsets of the given IDs and returns all transitive
@@ -219,15 +262,12 @@
inputPaths := []string{}
for _, inputDepSetId := range depsetIds {
- inputArtifacts, err := a.artifactIdsFromDepsetId(inputDepSetId)
+ depset := a.depsetIdToAqueryDepset[inputDepSetId]
+ inputArtifacts, err := a.artifactPathsFromDepsetHash(depset.ContentHash)
if err != nil {
return nil, err
}
- for _, inputId := range inputArtifacts {
- inputPath, exists := a.artifactIdToPath[inputId]
- if !exists {
- return nil, fmt.Errorf("undefined input artifactId %d", inputId)
- }
+ for _, inputPath := range inputArtifacts {
inputPaths = append(inputPaths, inputPath)
}
}
@@ -235,23 +275,23 @@
return inputPaths, nil
}
-func (a *aqueryArtifactHandler) artifactIdsFromDepsetId(depsetId int) ([]int, error) {
- if result, exists := a.depsetIdToArtifactIdsCache[depsetId]; exists {
+func (a *aqueryArtifactHandler) artifactPathsFromDepsetHash(depsetHash string) ([]string, error) {
+ if result, exists := a.depsetHashToArtifactPathsCache[depsetHash]; exists {
return result, nil
}
- if depset, exists := a.depsetIdToDepset[depsetId]; exists {
- result := depset.DirectArtifactIds
- for _, childId := range depset.TransitiveDepSetIds {
- childArtifactIds, err := a.artifactIdsFromDepsetId(childId)
+ if depset, exists := a.depsetHashToAqueryDepset[depsetHash]; exists {
+ result := depset.DirectArtifacts
+ for _, childHash := range depset.TransitiveDepSetHashes {
+ childArtifactIds, err := a.artifactPathsFromDepsetHash(childHash)
if err != nil {
return nil, err
}
result = append(result, childArtifactIds...)
}
- a.depsetIdToArtifactIdsCache[depsetId] = result
+ a.depsetHashToArtifactPathsCache[depsetHash] = result
return result, nil
} else {
- return nil, fmt.Errorf("undefined input depsetId %d", depsetId)
+ return nil, fmt.Errorf("undefined input depset hash %d", depsetHash)
}
}
@@ -261,9 +301,6 @@
// BuildStatements are one-to-one with actions in the given action graph, and AqueryDepsets
// are one-to-one with Bazel's depSetOfFiles objects.
func AqueryBuildStatements(aqueryJsonProto []byte) ([]BuildStatement, []AqueryDepset, error) {
- buildStatements := []BuildStatement{}
- depsets := []AqueryDepset{}
-
var aqueryResult actionGraphContainer
err := json.Unmarshal(aqueryJsonProto, &aqueryResult)
if err != nil {
@@ -274,6 +311,8 @@
return nil, nil, err
}
+ var buildStatements []BuildStatement
+
for _, actionEntry := range aqueryResult.Actions {
if shouldSkipAction(actionEntry) {
continue
@@ -298,38 +337,75 @@
buildStatements = append(buildStatements, buildStatement)
}
- // Iterate over depset IDs in the initial aquery order to preserve determinism.
- for _, depset := range aqueryResult.DepSetOfFiles {
- // Use the depset in the aqueryHandler, as this contains the augmented depsets.
- depset = aqueryHandler.depsetIdToDepset[depset.Id]
- directPaths := []string{}
- for _, artifactId := range depset.DirectArtifactIds {
- pathString := aqueryHandler.artifactIdToPath[artifactId]
- directPaths = append(directPaths, pathString)
+ depsetsByHash := map[string]AqueryDepset{}
+ depsets := []AqueryDepset{}
+ for _, aqueryDepset := range aqueryHandler.depsetIdToAqueryDepset {
+ if prevEntry, hasKey := depsetsByHash[aqueryDepset.ContentHash]; hasKey {
+ // Two depsets collide on hash. Ensure that their contents are identical.
+ if !reflect.DeepEqual(aqueryDepset, prevEntry) {
+ return nil, nil, fmt.Errorf("Two different depsets have the same hash: %v, %v", prevEntry, aqueryDepset)
+ }
+ } else {
+ depsetsByHash[aqueryDepset.ContentHash] = aqueryDepset
+ depsets = append(depsets, aqueryDepset)
}
- aqueryDepset := AqueryDepset{
- Id: depset.Id,
- DirectArtifacts: directPaths,
- TransitiveDepSetIds: depset.TransitiveDepSetIds,
- }
- depsets = append(depsets, aqueryDepset)
}
+
+ // Build Statements and depsets must be sorted by their content hash to
+ // preserve determinism between builds (this will result in consistent ninja file
+ // output). Note they are not sorted by their original IDs nor their Bazel ordering,
+ // as Bazel gives nondeterministic ordering / identifiers in aquery responses.
+ sort.Slice(buildStatements, func(i, j int) bool {
+ // For build statements, compare output lists. In Bazel, each output file
+ // may only have one action which generates it, so this will provide
+ // a deterministic ordering.
+ outputs_i := buildStatements[i].OutputPaths
+ outputs_j := buildStatements[j].OutputPaths
+ if len(outputs_i) != len(outputs_j) {
+ return len(outputs_i) < len(outputs_j)
+ }
+ if len(outputs_i) == 0 {
+ // No outputs for these actions, so compare commands.
+ return buildStatements[i].Command < buildStatements[j].Command
+ }
+ // There may be multiple outputs, but the output ordering is deterministic.
+ return outputs_i[0] < outputs_j[0]
+ })
+ sort.Slice(depsets, func(i, j int) bool {
+ return depsets[i].ContentHash < depsets[j].ContentHash
+ })
return buildStatements, depsets, nil
}
-func (aqueryHandler *aqueryArtifactHandler) validateInputDepsets(inputDepsetIds []int) ([]int, error) {
- // Validate input depsets correspond to real depsets.
+// depsetContentHash computes and returns a SHA256 checksum of the contents of
+// the given depset. This content hash may serve as the depset's identifier.
+// Using a content hash for an identifier is superior for determinism. (For example,
+// using an integer identifier which depends on the order in which the depsets are
+// created would result in nondeterministic depset IDs.)
+func depsetContentHash(directPaths []string, transitiveDepsetHashes []string) string {
+ h := sha256.New()
+ // Use newline as delimiter, as paths cannot contain newline.
+ h.Write([]byte(strings.Join(directPaths, "\n")))
+ h.Write([]byte(strings.Join(transitiveDepsetHashes, "\n")))
+ fullHash := fmt.Sprintf("%016x", h.Sum(nil))
+ return fullHash
+}
+
+func (aqueryHandler *aqueryArtifactHandler) depsetContentHashes(inputDepsetIds []int) ([]string, error) {
+ hashes := []string{}
for _, depsetId := range inputDepsetIds {
- if _, exists := aqueryHandler.depsetIdToDepset[depsetId]; !exists {
+ if aqueryDepset, exists := aqueryHandler.depsetIdToAqueryDepset[depsetId]; !exists {
return nil, fmt.Errorf("undefined input depsetId %d", depsetId)
+ } else {
+ hashes = append(hashes, aqueryDepset.ContentHash)
}
}
- return inputDepsetIds, nil
+ return hashes, nil
}
func (aqueryHandler *aqueryArtifactHandler) normalActionBuildStatement(actionEntry action) (BuildStatement, error) {
command := strings.Join(proptools.ShellEscapeListIncludingSpaces(actionEntry.Arguments), " ")
- inputDepsetIds, err := aqueryHandler.validateInputDepsets(actionEntry.InputDepSetIds)
+ inputDepsetHashes, err := aqueryHandler.depsetContentHashes(actionEntry.InputDepSetIds)
if err != nil {
return BuildStatement{}, err
}
@@ -339,12 +415,12 @@
}
buildStatement := BuildStatement{
- Command: command,
- Depfile: depfile,
- OutputPaths: outputPaths,
- InputDepsetIds: inputDepsetIds,
- Env: actionEntry.EnvironmentVariables,
- Mnemonic: actionEntry.Mnemonic,
+ Command: command,
+ Depfile: depfile,
+ OutputPaths: outputPaths,
+ InputDepsetHashes: inputDepsetHashes,
+ Env: actionEntry.EnvironmentVariables,
+ Mnemonic: actionEntry.Mnemonic,
}
return buildStatement, nil
}
@@ -413,18 +489,18 @@
// See go/python-binary-host-mixed-build for more details.
command := fmt.Sprintf(`/bin/bash -c 'echo "%[1]s" | sed "s/\\\\n/\\n/g" > %[2]s && chmod a+x %[2]s'`,
escapeCommandlineArgument(expandedTemplateContent), outputPaths[0])
- inputDepsetIds, err := aqueryHandler.validateInputDepsets(actionEntry.InputDepSetIds)
+ inputDepsetHashes, err := aqueryHandler.depsetContentHashes(actionEntry.InputDepSetIds)
if err != nil {
return BuildStatement{}, err
}
buildStatement := BuildStatement{
- Command: command,
- Depfile: depfile,
- OutputPaths: outputPaths,
- InputDepsetIds: inputDepsetIds,
- Env: actionEntry.EnvironmentVariables,
- Mnemonic: actionEntry.Mnemonic,
+ Command: command,
+ Depfile: depfile,
+ OutputPaths: outputPaths,
+ InputDepsetHashes: inputDepsetHashes,
+ Env: actionEntry.EnvironmentVariables,
+ Mnemonic: actionEntry.Mnemonic,
}
return buildStatement, nil
}
diff --git a/bazel/aquery_test.go b/bazel/aquery_test.go
index 2328411..740a1f1 100644
--- a/bazel/aquery_test.go
+++ b/bazel/aquery_test.go
@@ -234,7 +234,6 @@
OutputPaths: []string{
fmt.Sprintf("bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-%s.S", arch),
},
- InputDepsetIds: []int{1},
Env: []KeyValuePair{
KeyValuePair{Key: "PATH", Value: "/bin:/usr/bin:/usr/local/bin"},
},
@@ -248,9 +247,12 @@
"../sourceroot/bionic/libc/tools/gensyscalls.py",
"../bazel_tools/tools/genrule/genrule-setup.sh",
}
- actualFlattenedInputs := flattenDepsets([]int{1}, actualDepsets)
- if !reflect.DeepEqual(actualFlattenedInputs, expectedFlattenedInputs) {
- t.Errorf("Expected flattened inputs %v, but got %v", expectedFlattenedInputs, actualFlattenedInputs)
+ // In this example, each depset should have the same expected inputs.
+ for _, actualDepset := range actualDepsets {
+ actualFlattenedInputs := flattenDepsets([]string{actualDepset.ContentHash}, actualDepsets)
+ if !reflect.DeepEqual(actualFlattenedInputs, expectedFlattenedInputs) {
+ t.Errorf("Expected flattened inputs %v, but got %v", expectedFlattenedInputs, actualFlattenedInputs)
+ }
}
}
@@ -746,10 +748,9 @@
expectedBuildStatements := []BuildStatement{
BuildStatement{
- Command: "/bin/bash -c 'touch bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out'",
- OutputPaths: []string{"bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out"},
- InputDepsetIds: []int{1},
- Mnemonic: "Action",
+ Command: "/bin/bash -c 'touch bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out'",
+ OutputPaths: []string{"bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out"},
+ Mnemonic: "Action",
},
}
assertBuildStatements(t, expectedBuildStatements, actualbuildStatements)
@@ -763,7 +764,8 @@
}
expectedFlattenedInputs = append(expectedFlattenedInputs, "bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_root")
- actualFlattenedInputs := flattenDepsets([]int{1}, actualDepsets)
+ actualDepsetHashes := actualbuildStatements[0].InputDepsetHashes
+ actualFlattenedInputs := flattenDepsets(actualDepsetHashes, actualDepsets)
if !reflect.DeepEqual(actualFlattenedInputs, expectedFlattenedInputs) {
t.Errorf("Expected flattened inputs %v, but got %v", expectedFlattenedInputs, actualFlattenedInputs)
}
@@ -844,38 +846,24 @@
t.Fatalf("Expected %d build statements, got %d", expected, len(actualBuildStatements))
}
+ expectedDepsetFiles := [][]string{
+ []string{"middleinput_one", "middleinput_two"},
+ []string{"middleinput_one", "middleinput_two", "maininput_one", "maininput_two"},
+ }
+ assertFlattenedDepsets(t, actualDepsets, expectedDepsetFiles)
+
bs := actualBuildStatements[0]
if len(bs.InputPaths) > 0 {
t.Errorf("Expected main action raw inputs to be empty, but got %q", bs.InputPaths)
}
- expectedInputDepsets := []int{2}
- if !reflect.DeepEqual(bs.InputDepsetIds, expectedInputDepsets) {
- t.Errorf("Expected main action depset IDs %v, but got %v", expectedInputDepsets, bs.InputDepsetIds)
- }
-
expectedOutputs := []string{"output"}
if !reflect.DeepEqual(bs.OutputPaths, expectedOutputs) {
t.Errorf("Expected main action outputs %q, but got %q", expectedOutputs, bs.OutputPaths)
}
- expectedAllDepsets := []AqueryDepset{
- {
- Id: 1,
- DirectArtifacts: []string{"middleinput_one", "middleinput_two"},
- },
- {
- Id: 2,
- DirectArtifacts: []string{"maininput_one", "maininput_two"},
- TransitiveDepSetIds: []int{1},
- },
- }
- if !reflect.DeepEqual(actualDepsets, expectedAllDepsets) {
- t.Errorf("Expected depsets %v, but got %v", expectedAllDepsets, actualDepsets)
- }
-
expectedFlattenedInputs := []string{"middleinput_one", "middleinput_two", "maininput_one", "maininput_two"}
- actualFlattenedInputs := flattenDepsets(bs.InputDepsetIds, actualDepsets)
+ actualFlattenedInputs := flattenDepsets(bs.InputDepsetHashes, actualDepsets)
if !reflect.DeepEqual(actualFlattenedInputs, expectedFlattenedInputs) {
t.Errorf("Expected flattened inputs %v, but got %v", expectedFlattenedInputs, actualFlattenedInputs)
@@ -883,29 +871,42 @@
}
// Returns the contents of given depsets in concatenated post order.
-func flattenDepsets(depsetIdsToFlatten []int, allDepsets []AqueryDepset) []string {
- depsetsById := map[int]AqueryDepset{}
+func flattenDepsets(depsetHashesToFlatten []string, allDepsets []AqueryDepset) []string {
+ depsetsByHash := map[string]AqueryDepset{}
for _, depset := range allDepsets {
- depsetsById[depset.Id] = depset
+ depsetsByHash[depset.ContentHash] = depset
}
result := []string{}
- for _, depsetId := range depsetIdsToFlatten {
- result = append(result, flattenDepset(depsetId, depsetsById)...)
+ for _, depsetId := range depsetHashesToFlatten {
+ result = append(result, flattenDepset(depsetId, depsetsByHash)...)
}
return result
}
// Returns the contents of a given depset in post order.
-func flattenDepset(depsetIdToFlatten int, allDepsets map[int]AqueryDepset) []string {
- depset := allDepsets[depsetIdToFlatten]
+func flattenDepset(depsetHashToFlatten string, allDepsets map[string]AqueryDepset) []string {
+ depset := allDepsets[depsetHashToFlatten]
result := []string{}
- for _, depsetId := range depset.TransitiveDepSetIds {
+ for _, depsetId := range depset.TransitiveDepSetHashes {
result = append(result, flattenDepset(depsetId, allDepsets)...)
}
result = append(result, depset.DirectArtifacts...)
return result
}
+func assertFlattenedDepsets(t *testing.T, actualDepsets []AqueryDepset, expectedDepsetFiles [][]string) {
+ t.Helper()
+ if len(actualDepsets) != len(expectedDepsetFiles) {
+ t.Errorf("Expected %d depsets, but got %d depsets", expectedDepsetFiles, actualDepsets)
+ }
+ for i, actualDepset := range actualDepsets {
+ actualFlattenedInputs := flattenDepsets([]string{actualDepset.ContentHash}, actualDepsets)
+ if !reflect.DeepEqual(actualFlattenedInputs, expectedDepsetFiles[i]) {
+ t.Errorf("Expected depset files: %v, but got %v", expectedDepsetFiles[i], actualFlattenedInputs)
+ }
+ }
+}
+
func TestSimpleSymlink(t *testing.T) {
const inputString = `
{
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index 2775a10..ab92981 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -1914,9 +1914,9 @@
{cpp_std: "gnu++17", gnu_extensions: "true", bazel_cpp_std: "gnu++17"},
// some c_std test cases
- {c_std: "experimental", gnu_extensions: "", bazel_c_std: "gnu11"},
- {c_std: "experimental", gnu_extensions: "false", bazel_cpp_std: "c++17", bazel_c_std: "c11"},
- {c_std: "experimental", gnu_extensions: "true", bazel_c_std: "gnu11"},
+ {c_std: "experimental", gnu_extensions: "", bazel_c_std: "gnu17"},
+ {c_std: "experimental", gnu_extensions: "false", bazel_cpp_std: "c++17", bazel_c_std: "c17"},
+ {c_std: "experimental", gnu_extensions: "true", bazel_c_std: "gnu17"},
{c_std: "gnu11", cpp_std: "gnu++17", gnu_extensions: "", bazel_cpp_std: "gnu++17", bazel_c_std: "gnu11"},
{c_std: "gnu11", cpp_std: "gnu++17", gnu_extensions: "false", bazel_cpp_std: "c++17", bazel_c_std: "c11"},
{c_std: "gnu11", cpp_std: "gnu++17", gnu_extensions: "true", bazel_cpp_std: "gnu++17", bazel_c_std: "gnu11"},
diff --git a/cc/config/global.go b/cc/config/global.go
index 2f00cfa..1c4ad7f 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -281,7 +281,7 @@
CStdVersion = "gnu11"
CppStdVersion = "gnu++17"
- ExperimentalCStdVersion = "gnu11"
+ ExperimentalCStdVersion = "gnu17"
ExperimentalCppStdVersion = "gnu++2a"
// prebuilts/clang default settings.
diff --git a/java/base.go b/java/base.go
index c6f859a..0900daa 100644
--- a/java/base.go
+++ b/java/base.go
@@ -1913,6 +1913,9 @@
case bootClasspathTag:
deps.bootClasspath = append(deps.bootClasspath, dep.HeaderJars...)
case libTag, instrumentationForTag:
+ if _, ok := module.(*Plugin); ok {
+ ctx.ModuleErrorf("a java_plugin (%s) cannot be used as a libs dependency", otherName)
+ }
deps.classpath = append(deps.classpath, dep.HeaderJars...)
deps.dexClasspath = append(deps.dexClasspath, dep.HeaderJars...)
deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs...)
@@ -1921,6 +1924,9 @@
case java9LibTag:
deps.java9Classpath = append(deps.java9Classpath, dep.HeaderJars...)
case staticLibTag:
+ if _, ok := module.(*Plugin); ok {
+ ctx.ModuleErrorf("a java_plugin (%s) cannot be used as a static_libs dependency", otherName)
+ }
deps.classpath = append(deps.classpath, dep.HeaderJars...)
deps.staticJars = append(deps.staticJars, dep.ImplementationJars...)
deps.staticHeaderJars = append(deps.staticHeaderJars, dep.HeaderJars...)