1package cquery 2 3import ( 4 "fmt" 5 "strings" 6) 7 8var ( 9 GetOutputFiles = &getOutputFilesRequestType{} 10 GetPythonBinary = &getPythonBinaryRequestType{} 11 GetCcInfo = &getCcInfoType{} 12) 13 14type CcInfo struct { 15 OutputFiles []string 16 CcObjectFiles []string 17 CcSharedLibraryFiles []string 18 CcStaticLibraryFiles []string 19 Includes []string 20 SystemIncludes []string 21 Headers []string 22 // Archives owned by the current target (not by its dependencies). These will 23 // be a subset of OutputFiles. (or static libraries, this will be equal to OutputFiles, 24 // but general cc_library will also have dynamic libraries in output files). 25 RootStaticArchives []string 26 // Dynamic libraries (.so files) created by the current target. These will 27 // be a subset of OutputFiles. (or shared libraries, this will be equal to OutputFiles, 28 // but general cc_library will also have dynamic libraries in output files). 29 RootDynamicLibraries []string 30 TocFile string 31} 32 33type getOutputFilesRequestType struct{} 34 35type getPythonBinaryRequestType struct{} 36 37// Name returns a string name for this request type. Such request type names must be unique, 38// and must only consist of alphanumeric characters. 39func (g getOutputFilesRequestType) Name() string { 40 return "getOutputFiles" 41} 42 43// StarlarkFunctionBody returns a starlark function body to process this request type. 44// The returned string is the body of a Starlark function which obtains 45// all request-relevant information about a target and returns a string containing 46// this information. 47// The function should have the following properties: 48// - `target` is the only parameter to this function (a configured target). 49// - The return value must be a string. 50// - The function body should not be indented outside of its own scope. 51func (g getOutputFilesRequestType) StarlarkFunctionBody() string { 52 return "return ', '.join([f.path for f in target.files.to_list()])" 53} 54 55// ParseResult returns a value obtained by parsing the result of the request's Starlark function. 56// The given rawString must correspond to the string output which was created by evaluating the 57// Starlark given in StarlarkFunctionBody. 58func (g getOutputFilesRequestType) ParseResult(rawString string) []string { 59 return splitOrEmpty(rawString, ", ") 60} 61 62// Name returns a string name for this request type. Such request type names must be unique, 63// and must only consist of alphanumeric characters. 64func (g getPythonBinaryRequestType) Name() string { 65 return "getPythonBinary" 66} 67 68// StarlarkFunctionBody returns a starlark function body to process this request type. 69// The returned string is the body of a Starlark function which obtains 70// all request-relevant information about a target and returns a string containing 71// this information. 72// The function should have the following properties: 73// - `target` is the only parameter to this function (a configured target). 74// - The return value must be a string. 75// - The function body should not be indented outside of its own scope. 76func (g getPythonBinaryRequestType) StarlarkFunctionBody() string { 77 return "return providers(target)['FilesToRunProvider'].executable.path" 78} 79 80// ParseResult returns a value obtained by parsing the result of the request's Starlark function. 81// The given rawString must correspond to the string output which was created by evaluating the 82// Starlark given in StarlarkFunctionBody. 83func (g getPythonBinaryRequestType) ParseResult(rawString string) string { 84 return rawString 85} 86 87type getCcInfoType struct{} 88 89// Name returns a string name for this request type. Such request type names must be unique, 90// and must only consist of alphanumeric characters. 91func (g getCcInfoType) Name() string { 92 return "getCcInfo" 93} 94 95// StarlarkFunctionBody returns a starlark function body to process this request type. 96// The returned string is the body of a Starlark function which obtains 97// all request-relevant information about a target and returns a string containing 98// this information. 99// The function should have the following properties: 100// - `target` is the only parameter to this function (a configured target). 101// - The return value must be a string. 102// - The function body should not be indented outside of its own scope. 103func (g getCcInfoType) StarlarkFunctionBody() string { 104 return ` 105outputFiles = [f.path for f in target.files.to_list()] 106cc_info = providers(target)["CcInfo"] 107 108includes = cc_info.compilation_context.includes.to_list() 109system_includes = cc_info.compilation_context.system_includes.to_list() 110headers = [f.path for f in cc_info.compilation_context.headers.to_list()] 111 112ccObjectFiles = [] 113staticLibraries = [] 114rootStaticArchives = [] 115linker_inputs = cc_info.linking_context.linker_inputs.to_list() 116 117static_info_tag = "//build/bazel/rules/cc:cc_library_static.bzl%CcStaticLibraryInfo" 118if static_info_tag in providers(target): 119 static_info = providers(target)[static_info_tag] 120 ccObjectFiles = [f.path for f in static_info.objects] 121 rootStaticArchives = [static_info.root_static_archive.path] 122else: 123 for linker_input in linker_inputs: 124 for library in linker_input.libraries: 125 for object in library.objects: 126 ccObjectFiles += [object.path] 127 if library.static_library: 128 staticLibraries.append(library.static_library.path) 129 if linker_input.owner == target.label: 130 rootStaticArchives.append(library.static_library.path) 131 132sharedLibraries = [] 133rootSharedLibraries = [] 134 135shared_info_tag = "@rules_cc//examples:experimental_cc_shared_library.bzl%CcSharedLibraryInfo" 136if shared_info_tag in providers(target): 137 shared_info = providers(target)[shared_info_tag] 138 for lib in shared_info.linker_input.libraries: 139 path = lib.dynamic_library.path 140 rootSharedLibraries += [path] 141 sharedLibraries.append(path) 142else: 143 for linker_input in linker_inputs: 144 for library in linker_input.libraries: 145 if library.dynamic_library: 146 path = library.dynamic_library.path 147 sharedLibraries.append(path) 148 if linker_input.owner == target.label: 149 rootSharedLibraries.append(path) 150 151toc_file = "" 152toc_file_tag = "//build/bazel/rules/cc:generate_toc.bzl%CcTocInfo" 153if toc_file_tag in providers(target): 154 toc_file = providers(target)[toc_file_tag].toc.path 155else: 156 # NOTE: It's OK if there's no ToC, as Soong just uses it for optimization 157 pass 158 159returns = [ 160 outputFiles, 161 ccObjectFiles, 162 sharedLibraries, 163 staticLibraries, 164 includes, 165 system_includes, 166 headers, 167 rootStaticArchives, 168 rootSharedLibraries, 169 [toc_file] 170] 171 172return "|".join([", ".join(r) for r in returns])` 173} 174 175// ParseResult returns a value obtained by parsing the result of the request's Starlark function. 176// The given rawString must correspond to the string output which was created by evaluating the 177// Starlark given in StarlarkFunctionBody. 178func (g getCcInfoType) ParseResult(rawString string) (CcInfo, error) { 179 const expectedLen = 10 180 splitString := strings.Split(rawString, "|") 181 if len(splitString) != expectedLen { 182 return CcInfo{}, fmt.Errorf("Expected %d items, got %q", expectedLen, splitString) 183 } 184 outputFilesString := splitString[0] 185 ccObjectsString := splitString[1] 186 ccSharedLibrariesString := splitString[2] 187 ccStaticLibrariesString := splitString[3] 188 includesString := splitString[4] 189 systemIncludesString := splitString[5] 190 headersString := splitString[6] 191 rootStaticArchivesString := splitString[7] 192 rootDynamicLibrariesString := splitString[8] 193 tocFile := splitString[9] // NOTE: Will be the empty string if there wasn't 194 195 outputFiles := splitOrEmpty(outputFilesString, ", ") 196 ccObjects := splitOrEmpty(ccObjectsString, ", ") 197 ccSharedLibraries := splitOrEmpty(ccSharedLibrariesString, ", ") 198 ccStaticLibraries := splitOrEmpty(ccStaticLibrariesString, ", ") 199 includes := splitOrEmpty(includesString, ", ") 200 systemIncludes := splitOrEmpty(systemIncludesString, ", ") 201 headers := splitOrEmpty(headersString, ", ") 202 rootStaticArchives := splitOrEmpty(rootStaticArchivesString, ", ") 203 rootDynamicLibraries := splitOrEmpty(rootDynamicLibrariesString, ", ") 204 return CcInfo{ 205 OutputFiles: outputFiles, 206 CcObjectFiles: ccObjects, 207 CcSharedLibraryFiles: ccSharedLibraries, 208 CcStaticLibraryFiles: ccStaticLibraries, 209 Includes: includes, 210 SystemIncludes: systemIncludes, 211 Headers: headers, 212 RootStaticArchives: rootStaticArchives, 213 RootDynamicLibraries: rootDynamicLibraries, 214 TocFile: tocFile, 215 }, nil 216} 217 218// splitOrEmpty is a modification of strings.Split() that returns an empty list 219// if the given string is empty. 220func splitOrEmpty(s string, sep string) []string { 221 if len(s) < 1 { 222 return []string{} 223 } else { 224 return strings.Split(s, sep) 225 } 226} 227