Loading android/bazel_handler.go +64 −10 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ type CqueryRequestType int const ( getAllFiles CqueryRequestType = iota getCcObjectFiles getAllFilesAndCcObjectFiles ) // Map key to describe bazel cquery requests. Loading @@ -58,7 +59,9 @@ type BazelContext interface { // Retrieves these files from Bazel's CcInfo provider. GetCcObjectFiles(label string, archType ArchType) ([]string, bool) // TODO(cparsons): Other cquery-related methods should be added here. // Returns the results of GetAllFiles and GetCcObjectFiles in a single query (in that order). GetAllFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) // ** End cquery methods // Issues commands to Bazel to receive results for all cquery requests Loading Loading @@ -116,6 +119,11 @@ func (m MockBazelContext) GetCcObjectFiles(label string, archType ArchType) ([]s return result, ok } func (m MockBazelContext) GetAllFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) { result, ok := m.AllFiles[label] return result, result, ok } func (m MockBazelContext) InvokeBazel() error { panic("unimplemented") } Loading Loading @@ -154,6 +162,22 @@ func (bazelCtx *bazelContext) GetCcObjectFiles(label string, archType ArchType) } } func (bazelCtx *bazelContext) GetAllFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) { var allFiles []string var ccObjects []string result, ok := bazelCtx.cquery(label, getAllFilesAndCcObjectFiles, archType) if ok { bazelOutput := strings.TrimSpace(result) splitString := strings.Split(bazelOutput, "|") allFilesString := splitString[0] ccObjectsString := splitString[1] allFiles = strings.Split(allFilesString, ", ") ccObjects = strings.Split(ccObjectsString, ", ") } return allFiles, ccObjects, ok } func (n noopBazelContext) GetAllFiles(label string, archType ArchType) ([]string, bool) { panic("unimplemented") } Loading @@ -162,6 +186,10 @@ func (n noopBazelContext) GetCcObjectFiles(label string, archType ArchType) ([]s panic("unimplemented") } func (n noopBazelContext) GetAllFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) { panic("unimplemented") } func (n noopBazelContext) InvokeBazel() error { panic("unimplemented") } Loading Loading @@ -253,8 +281,12 @@ func pwdPrefix() string { return "" } // Issues the given bazel command with given build label and additional flags. // Returns (stdout, stderr, error). The first and second return values are strings // containing the stdout and stderr of the run command, and an error is returned if // the invocation returned an error code. func (context *bazelContext) issueBazelCommand(runName bazel.RunName, command string, labels []string, extraFlags ...string) (string, error) { extraFlags ...string) (string, string, error) { cmdFlags := []string{"--output_base=" + context.outputBase, command} cmdFlags = append(cmdFlags, labels...) Loading @@ -281,9 +313,10 @@ func (context *bazelContext) issueBazelCommand(runName bazel.RunName, command st bazelCmd.Stderr = stderr if output, err := bazelCmd.Output(); err != nil { return "", fmt.Errorf("bazel command failed. command: [%s], env: [%s], error [%s]", bazelCmd, bazelCmd.Env, stderr) return "", string(stderr.Bytes()), fmt.Errorf("bazel command failed. command: [%s], env: [%s], error [%s]", bazelCmd, bazelCmd.Env, stderr) } else { return string(output), nil return string(output), string(stderr.Bytes()), nil } } Loading Loading @@ -452,6 +485,11 @@ phony_root(name = "phonyroot", strings.Join(deps_arm, ",\n "))) } // Returns the file contents of the buildroot.cquery file that should be used for the cquery // expression in order to obtain information about buildroot and its dependencies. // The contents of this file depend on the bazelContext's requests; requests are enumerated // and grouped by their request type. The data retrieved for each label depends on its // request type. func (context *bazelContext) cqueryStarlarkFileContents() []byte { formatString := ` # This file is generated by soong_build. Do not edit. Loading @@ -463,6 +501,13 @@ getCcObjectFilesLabels = { %s } getAllFilesAndCcObjectFilesLabels = { %s } def get_all_files(target): return [f.path for f in target.files.to_list()] def get_cc_object_files(target): result = [] linker_inputs = providers(target)["CcInfo"].linking_context.linker_inputs.to_list() Loading Loading @@ -492,9 +537,11 @@ def get_arch(target): def format(target): id_string = str(target.label) + "|" + get_arch(target) if id_string in getAllFilesLabels: return id_string + ">>" + ', '.join([f.path for f in target.files.to_list()]) return id_string + ">>" + ', '.join(get_all_files(target)) elif id_string in getCcObjectFilesLabels: return id_string + ">>" + ', '.join(get_cc_object_files(target)) elif id_string in getAllFilesAndCcObjectFilesLabels: return id_string + ">>" + ', '.join(get_all_files(target)) + "|" + ', '.join(get_cc_object_files(target)) else: # This target was not requested via cquery, and thus must be a dependency # of a requested target. Loading @@ -502,6 +549,7 @@ def format(target): ` var getAllFilesDeps []string = nil var getCcObjectFilesDeps []string = nil var getAllFilesAndCcObjectFilesDeps []string = nil for val, _ := range context.requests { labelWithArch := getCqueryId(val) Loading @@ -511,12 +559,16 @@ def format(target): getAllFilesDeps = append(getAllFilesDeps, mapEntryString) case getCcObjectFiles: getCcObjectFilesDeps = append(getCcObjectFilesDeps, mapEntryString) case getAllFilesAndCcObjectFiles: getAllFilesAndCcObjectFilesDeps = append(getAllFilesAndCcObjectFilesDeps, mapEntryString) } } getAllFilesDepsString := strings.Join(getAllFilesDeps, ",\n ") getCcObjectFilesDepsString := strings.Join(getCcObjectFilesDeps, ",\n ") getAllFilesAndCcObjectFilesDepsString := strings.Join(getAllFilesAndCcObjectFilesDeps, ",\n ") return []byte(fmt.Sprintf(formatString, getAllFilesDepsString, getCcObjectFilesDepsString)) return []byte(fmt.Sprintf(formatString, getAllFilesDepsString, getCcObjectFilesDepsString, getAllFilesAndCcObjectFilesDepsString)) } // Returns a workspace-relative path containing build-related metadata required Loading @@ -531,6 +583,7 @@ func (context *bazelContext) InvokeBazel() error { context.results = make(map[cqueryKey]string) var cqueryOutput string var cqueryErr string var err error intermediatesDirPath := absolutePath(context.intermediatesDir()) Loading Loading @@ -568,7 +621,7 @@ func (context *bazelContext) InvokeBazel() error { return err } buildrootLabel := "//:buildroot" cqueryOutput, err = context.issueBazelCommand(bazel.CqueryBuildRootRunName, "cquery", cqueryOutput, cqueryErr, err = context.issueBazelCommand(bazel.CqueryBuildRootRunName, "cquery", []string{fmt.Sprintf("kind(rule, deps(%s))", buildrootLabel)}, "--output=starlark", "--starlark:file="+cqueryFileRelpath) Loading @@ -595,7 +648,8 @@ func (context *bazelContext) InvokeBazel() error { if cqueryResult, ok := cqueryResults[getCqueryId(val)]; ok { context.results[val] = string(cqueryResult) } else { return fmt.Errorf("missing result for bazel target %s. query output: [%s]", getCqueryId(val), cqueryOutput) return fmt.Errorf("missing result for bazel target %s. query output: [%s], cquery err: [%s]", getCqueryId(val), cqueryOutput, cqueryErr) } } Loading @@ -603,7 +657,7 @@ func (context *bazelContext) InvokeBazel() error { // // TODO(cparsons): Use --target_pattern_file to avoid command line limits. var aqueryOutput string aqueryOutput, err = context.issueBazelCommand(bazel.AqueryBuildRootRunName, "aquery", aqueryOutput, _, err = context.issueBazelCommand(bazel.AqueryBuildRootRunName, "aquery", []string{fmt.Sprintf("deps(%s)", buildrootLabel), // Use jsonproto instead of proto; actual proto parsing would require a dependency on Bazel's // proto sources, which would add a number of unnecessary dependencies. Loading @@ -621,7 +675,7 @@ func (context *bazelContext) InvokeBazel() error { // Issue a build command of the phony root to generate symlink forests for dependencies of the // Bazel build. This is necessary because aquery invocations do not generate this symlink forest, // but some of symlinks may be required to resolve source dependencies of the build. _, err = context.issueBazelCommand(bazel.BazelBuildPhonyRootRunName, "build", _, _, err = context.issueBazelCommand(bazel.BazelBuildPhonyRootRunName, "build", []string{"//:phonyroot"}) if err != nil { Loading cc/library.go +44 −0 Original line number Diff line number Diff line Loading @@ -230,6 +230,7 @@ func LibraryStaticFactory() android.Module { module, library := NewLibrary(android.HostAndDeviceSupported) library.BuildOnlyStatic() module.sdkMemberTypes = []android.SdkMemberType{staticLibrarySdkMemberType} module.bazelHandler = &staticLibraryBazelHandler{module: module} return module.Init() } Loading Loading @@ -406,6 +407,49 @@ type libraryDecorator struct { collectedSnapshotHeaders android.Paths } type staticLibraryBazelHandler struct { bazelHandler module *Module } func (handler *staticLibraryBazelHandler) generateBazelBuildActions(ctx android.ModuleContext, label string) bool { bazelCtx := ctx.Config().BazelContext outputPaths, objPaths, ok := bazelCtx.GetAllFilesAndCcObjectFiles(label, ctx.Arch().ArchType) if ok { if len(outputPaths) != 1 { // TODO(cparsons): This is actually expected behavior for static libraries with no srcs. // We should support this. ctx.ModuleErrorf("expected exactly one output file for '%s', but got %s", label, objPaths) return false } outputFilePath := android.PathForBazelOut(ctx, outputPaths[0]) handler.module.outputFile = android.OptionalPathForPath(outputFilePath) objFiles := make(android.Paths, len(objPaths)) for i, objPath := range objPaths { objFiles[i] = android.PathForBazelOut(ctx, objPath) } objects := Objects{ objFiles: objFiles, } ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{ StaticLibrary: outputFilePath, ReuseObjects: objects, Objects: objects, // TODO(cparsons): Include transitive static libraries in this provider to support // static libraries with deps. TransitiveStaticLibrariesForOrdering: android.NewDepSetBuilder(android.TOPOLOGICAL). Direct(outputFilePath). Build(), }) handler.module.outputFile = android.OptionalPathForPath(android.PathForBazelOut(ctx, objPaths[0])) } return ok } // collectHeadersForSnapshot collects all exported headers from library. // It globs header files in the source tree for exported include directories, // and tracks generated header files separately. Loading Loading
android/bazel_handler.go +64 −10 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ type CqueryRequestType int const ( getAllFiles CqueryRequestType = iota getCcObjectFiles getAllFilesAndCcObjectFiles ) // Map key to describe bazel cquery requests. Loading @@ -58,7 +59,9 @@ type BazelContext interface { // Retrieves these files from Bazel's CcInfo provider. GetCcObjectFiles(label string, archType ArchType) ([]string, bool) // TODO(cparsons): Other cquery-related methods should be added here. // Returns the results of GetAllFiles and GetCcObjectFiles in a single query (in that order). GetAllFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) // ** End cquery methods // Issues commands to Bazel to receive results for all cquery requests Loading Loading @@ -116,6 +119,11 @@ func (m MockBazelContext) GetCcObjectFiles(label string, archType ArchType) ([]s return result, ok } func (m MockBazelContext) GetAllFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) { result, ok := m.AllFiles[label] return result, result, ok } func (m MockBazelContext) InvokeBazel() error { panic("unimplemented") } Loading Loading @@ -154,6 +162,22 @@ func (bazelCtx *bazelContext) GetCcObjectFiles(label string, archType ArchType) } } func (bazelCtx *bazelContext) GetAllFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) { var allFiles []string var ccObjects []string result, ok := bazelCtx.cquery(label, getAllFilesAndCcObjectFiles, archType) if ok { bazelOutput := strings.TrimSpace(result) splitString := strings.Split(bazelOutput, "|") allFilesString := splitString[0] ccObjectsString := splitString[1] allFiles = strings.Split(allFilesString, ", ") ccObjects = strings.Split(ccObjectsString, ", ") } return allFiles, ccObjects, ok } func (n noopBazelContext) GetAllFiles(label string, archType ArchType) ([]string, bool) { panic("unimplemented") } Loading @@ -162,6 +186,10 @@ func (n noopBazelContext) GetCcObjectFiles(label string, archType ArchType) ([]s panic("unimplemented") } func (n noopBazelContext) GetAllFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) { panic("unimplemented") } func (n noopBazelContext) InvokeBazel() error { panic("unimplemented") } Loading Loading @@ -253,8 +281,12 @@ func pwdPrefix() string { return "" } // Issues the given bazel command with given build label and additional flags. // Returns (stdout, stderr, error). The first and second return values are strings // containing the stdout and stderr of the run command, and an error is returned if // the invocation returned an error code. func (context *bazelContext) issueBazelCommand(runName bazel.RunName, command string, labels []string, extraFlags ...string) (string, error) { extraFlags ...string) (string, string, error) { cmdFlags := []string{"--output_base=" + context.outputBase, command} cmdFlags = append(cmdFlags, labels...) Loading @@ -281,9 +313,10 @@ func (context *bazelContext) issueBazelCommand(runName bazel.RunName, command st bazelCmd.Stderr = stderr if output, err := bazelCmd.Output(); err != nil { return "", fmt.Errorf("bazel command failed. command: [%s], env: [%s], error [%s]", bazelCmd, bazelCmd.Env, stderr) return "", string(stderr.Bytes()), fmt.Errorf("bazel command failed. command: [%s], env: [%s], error [%s]", bazelCmd, bazelCmd.Env, stderr) } else { return string(output), nil return string(output), string(stderr.Bytes()), nil } } Loading Loading @@ -452,6 +485,11 @@ phony_root(name = "phonyroot", strings.Join(deps_arm, ",\n "))) } // Returns the file contents of the buildroot.cquery file that should be used for the cquery // expression in order to obtain information about buildroot and its dependencies. // The contents of this file depend on the bazelContext's requests; requests are enumerated // and grouped by their request type. The data retrieved for each label depends on its // request type. func (context *bazelContext) cqueryStarlarkFileContents() []byte { formatString := ` # This file is generated by soong_build. Do not edit. Loading @@ -463,6 +501,13 @@ getCcObjectFilesLabels = { %s } getAllFilesAndCcObjectFilesLabels = { %s } def get_all_files(target): return [f.path for f in target.files.to_list()] def get_cc_object_files(target): result = [] linker_inputs = providers(target)["CcInfo"].linking_context.linker_inputs.to_list() Loading Loading @@ -492,9 +537,11 @@ def get_arch(target): def format(target): id_string = str(target.label) + "|" + get_arch(target) if id_string in getAllFilesLabels: return id_string + ">>" + ', '.join([f.path for f in target.files.to_list()]) return id_string + ">>" + ', '.join(get_all_files(target)) elif id_string in getCcObjectFilesLabels: return id_string + ">>" + ', '.join(get_cc_object_files(target)) elif id_string in getAllFilesAndCcObjectFilesLabels: return id_string + ">>" + ', '.join(get_all_files(target)) + "|" + ', '.join(get_cc_object_files(target)) else: # This target was not requested via cquery, and thus must be a dependency # of a requested target. Loading @@ -502,6 +549,7 @@ def format(target): ` var getAllFilesDeps []string = nil var getCcObjectFilesDeps []string = nil var getAllFilesAndCcObjectFilesDeps []string = nil for val, _ := range context.requests { labelWithArch := getCqueryId(val) Loading @@ -511,12 +559,16 @@ def format(target): getAllFilesDeps = append(getAllFilesDeps, mapEntryString) case getCcObjectFiles: getCcObjectFilesDeps = append(getCcObjectFilesDeps, mapEntryString) case getAllFilesAndCcObjectFiles: getAllFilesAndCcObjectFilesDeps = append(getAllFilesAndCcObjectFilesDeps, mapEntryString) } } getAllFilesDepsString := strings.Join(getAllFilesDeps, ",\n ") getCcObjectFilesDepsString := strings.Join(getCcObjectFilesDeps, ",\n ") getAllFilesAndCcObjectFilesDepsString := strings.Join(getAllFilesAndCcObjectFilesDeps, ",\n ") return []byte(fmt.Sprintf(formatString, getAllFilesDepsString, getCcObjectFilesDepsString)) return []byte(fmt.Sprintf(formatString, getAllFilesDepsString, getCcObjectFilesDepsString, getAllFilesAndCcObjectFilesDepsString)) } // Returns a workspace-relative path containing build-related metadata required Loading @@ -531,6 +583,7 @@ func (context *bazelContext) InvokeBazel() error { context.results = make(map[cqueryKey]string) var cqueryOutput string var cqueryErr string var err error intermediatesDirPath := absolutePath(context.intermediatesDir()) Loading Loading @@ -568,7 +621,7 @@ func (context *bazelContext) InvokeBazel() error { return err } buildrootLabel := "//:buildroot" cqueryOutput, err = context.issueBazelCommand(bazel.CqueryBuildRootRunName, "cquery", cqueryOutput, cqueryErr, err = context.issueBazelCommand(bazel.CqueryBuildRootRunName, "cquery", []string{fmt.Sprintf("kind(rule, deps(%s))", buildrootLabel)}, "--output=starlark", "--starlark:file="+cqueryFileRelpath) Loading @@ -595,7 +648,8 @@ func (context *bazelContext) InvokeBazel() error { if cqueryResult, ok := cqueryResults[getCqueryId(val)]; ok { context.results[val] = string(cqueryResult) } else { return fmt.Errorf("missing result for bazel target %s. query output: [%s]", getCqueryId(val), cqueryOutput) return fmt.Errorf("missing result for bazel target %s. query output: [%s], cquery err: [%s]", getCqueryId(val), cqueryOutput, cqueryErr) } } Loading @@ -603,7 +657,7 @@ func (context *bazelContext) InvokeBazel() error { // // TODO(cparsons): Use --target_pattern_file to avoid command line limits. var aqueryOutput string aqueryOutput, err = context.issueBazelCommand(bazel.AqueryBuildRootRunName, "aquery", aqueryOutput, _, err = context.issueBazelCommand(bazel.AqueryBuildRootRunName, "aquery", []string{fmt.Sprintf("deps(%s)", buildrootLabel), // Use jsonproto instead of proto; actual proto parsing would require a dependency on Bazel's // proto sources, which would add a number of unnecessary dependencies. Loading @@ -621,7 +675,7 @@ func (context *bazelContext) InvokeBazel() error { // Issue a build command of the phony root to generate symlink forests for dependencies of the // Bazel build. This is necessary because aquery invocations do not generate this symlink forest, // but some of symlinks may be required to resolve source dependencies of the build. _, err = context.issueBazelCommand(bazel.BazelBuildPhonyRootRunName, "build", _, _, err = context.issueBazelCommand(bazel.BazelBuildPhonyRootRunName, "build", []string{"//:phonyroot"}) if err != nil { Loading
cc/library.go +44 −0 Original line number Diff line number Diff line Loading @@ -230,6 +230,7 @@ func LibraryStaticFactory() android.Module { module, library := NewLibrary(android.HostAndDeviceSupported) library.BuildOnlyStatic() module.sdkMemberTypes = []android.SdkMemberType{staticLibrarySdkMemberType} module.bazelHandler = &staticLibraryBazelHandler{module: module} return module.Init() } Loading Loading @@ -406,6 +407,49 @@ type libraryDecorator struct { collectedSnapshotHeaders android.Paths } type staticLibraryBazelHandler struct { bazelHandler module *Module } func (handler *staticLibraryBazelHandler) generateBazelBuildActions(ctx android.ModuleContext, label string) bool { bazelCtx := ctx.Config().BazelContext outputPaths, objPaths, ok := bazelCtx.GetAllFilesAndCcObjectFiles(label, ctx.Arch().ArchType) if ok { if len(outputPaths) != 1 { // TODO(cparsons): This is actually expected behavior for static libraries with no srcs. // We should support this. ctx.ModuleErrorf("expected exactly one output file for '%s', but got %s", label, objPaths) return false } outputFilePath := android.PathForBazelOut(ctx, outputPaths[0]) handler.module.outputFile = android.OptionalPathForPath(outputFilePath) objFiles := make(android.Paths, len(objPaths)) for i, objPath := range objPaths { objFiles[i] = android.PathForBazelOut(ctx, objPath) } objects := Objects{ objFiles: objFiles, } ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{ StaticLibrary: outputFilePath, ReuseObjects: objects, Objects: objects, // TODO(cparsons): Include transitive static libraries in this provider to support // static libraries with deps. TransitiveStaticLibrariesForOrdering: android.NewDepSetBuilder(android.TOPOLOGICAL). Direct(outputFilePath). Build(), }) handler.module.outputFile = android.OptionalPathForPath(android.PathForBazelOut(ctx, objPaths[0])) } return ok } // collectHeadersForSnapshot collects all exported headers from library. // It globs header files in the source tree for exported include directories, // and tracks generated header files separately. Loading