request_type.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. package cquery
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "strings"
  6. )
  7. var (
  8. GetOutputFiles = &getOutputFilesRequestType{}
  9. GetCcInfo = &getCcInfoType{}
  10. GetApexInfo = &getApexInfoType{}
  11. GetCcUnstrippedInfo = &getCcUnstrippedInfoType{}
  12. GetPrebuiltFileInfo = &getPrebuiltFileInfo{}
  13. )
  14. type CcAndroidMkInfo struct {
  15. LocalStaticLibs []string
  16. LocalWholeStaticLibs []string
  17. LocalSharedLibs []string
  18. }
  19. type CcInfo struct {
  20. CcAndroidMkInfo
  21. OutputFiles []string
  22. CcObjectFiles []string
  23. CcSharedLibraryFiles []string
  24. CcStaticLibraryFiles []string
  25. Includes []string
  26. SystemIncludes []string
  27. Headers []string
  28. // Archives owned by the current target (not by its dependencies). These will
  29. // be a subset of OutputFiles. (or static libraries, this will be equal to OutputFiles,
  30. // but general cc_library will also have dynamic libraries in output files).
  31. RootStaticArchives []string
  32. // Dynamic libraries (.so files) created by the current target. These will
  33. // be a subset of OutputFiles. (or shared libraries, this will be equal to OutputFiles,
  34. // but general cc_library will also have dynamic libraries in output files).
  35. RootDynamicLibraries []string
  36. TidyFiles []string
  37. TocFile string
  38. UnstrippedOutput string
  39. AbiDiffFiles []string
  40. }
  41. type getOutputFilesRequestType struct{}
  42. // Name returns a string name for this request type. Such request type names must be unique,
  43. // and must only consist of alphanumeric characters.
  44. func (g getOutputFilesRequestType) Name() string {
  45. return "getOutputFiles"
  46. }
  47. // StarlarkFunctionBody returns a starlark function body to process this request type.
  48. // The returned string is the body of a Starlark function which obtains
  49. // all request-relevant information about a target and returns a string containing
  50. // this information.
  51. // The function should have the following properties:
  52. // - The arguments are `target` (a configured target) and `id_string` (the label + configuration).
  53. // - The return value must be a string.
  54. // - The function body should not be indented outside of its own scope.
  55. func (g getOutputFilesRequestType) StarlarkFunctionBody() string {
  56. return "return ', '.join([f.path for f in target.files.to_list()])"
  57. }
  58. // ParseResult returns a value obtained by parsing the result of the request's Starlark function.
  59. // The given rawString must correspond to the string output which was created by evaluating the
  60. // Starlark given in StarlarkFunctionBody.
  61. func (g getOutputFilesRequestType) ParseResult(rawString string) []string {
  62. return splitOrEmpty(rawString, ", ")
  63. }
  64. type getCcInfoType struct{}
  65. // Name returns a string name for this request type. Such request type names must be unique,
  66. // and must only consist of alphanumeric characters.
  67. func (g getCcInfoType) Name() string {
  68. return "getCcInfo"
  69. }
  70. // StarlarkFunctionBody returns a starlark function body to process this request type.
  71. // The returned string is the body of a Starlark function which obtains
  72. // all request-relevant information about a target and returns a string containing
  73. // this information.
  74. // The function should have the following properties:
  75. // - The arguments are `target` (a configured target) and `id_string` (the label + configuration).
  76. // - The return value must be a string.
  77. // - The function body should not be indented outside of its own scope.
  78. func (g getCcInfoType) StarlarkFunctionBody() string {
  79. return `
  80. outputFiles = [f.path for f in target.files.to_list()]
  81. p = providers(target)
  82. cc_info = p.get("CcInfo")
  83. if not cc_info:
  84. fail("%s did not provide CcInfo" % id_string)
  85. includes = cc_info.compilation_context.includes.to_list()
  86. system_includes = cc_info.compilation_context.system_includes.to_list()
  87. headers = [f.path for f in cc_info.compilation_context.headers.to_list()]
  88. ccObjectFiles = []
  89. staticLibraries = []
  90. rootStaticArchives = []
  91. linker_inputs = cc_info.linking_context.linker_inputs.to_list()
  92. static_info_tag = "//build/bazel/rules/cc:cc_library_static.bzl%CcStaticLibraryInfo"
  93. if static_info_tag in p:
  94. static_info = p[static_info_tag]
  95. ccObjectFiles = [f.path for f in static_info.objects]
  96. rootStaticArchives = [static_info.root_static_archive.path]
  97. else:
  98. for linker_input in linker_inputs:
  99. for library in linker_input.libraries:
  100. for object in library.objects:
  101. ccObjectFiles += [object.path]
  102. if library.static_library:
  103. staticLibraries.append(library.static_library.path)
  104. if linker_input.owner == target.label:
  105. rootStaticArchives.append(library.static_library.path)
  106. sharedLibraries = []
  107. rootSharedLibraries = []
  108. shared_info_tag = "//build/bazel/rules/cc:cc_library_shared.bzl%CcSharedLibraryOutputInfo"
  109. stubs_tag = "//build/bazel/rules/cc:cc_stub_library.bzl%CcStubInfo"
  110. unstripped_tag = "//build/bazel/rules/cc:stripped_cc_common.bzl%CcUnstrippedInfo"
  111. unstripped = ""
  112. if shared_info_tag in p:
  113. shared_info = p[shared_info_tag]
  114. path = shared_info.output_file.path
  115. sharedLibraries.append(path)
  116. rootSharedLibraries += [path]
  117. unstripped = path
  118. if unstripped_tag in p:
  119. unstripped = p[unstripped_tag].unstripped.path
  120. elif stubs_tag in p:
  121. rootSharedLibraries.extend([f.path for f in target.files.to_list()])
  122. else:
  123. for linker_input in linker_inputs:
  124. for library in linker_input.libraries:
  125. if library.dynamic_library:
  126. path = library.dynamic_library.path
  127. sharedLibraries.append(path)
  128. if linker_input.owner == target.label:
  129. rootSharedLibraries.append(path)
  130. toc_file = ""
  131. toc_file_tag = "//build/bazel/rules/cc:generate_toc.bzl%CcTocInfo"
  132. if toc_file_tag in p:
  133. toc_file = p[toc_file_tag].toc.path
  134. else:
  135. # NOTE: It's OK if there's no ToC, as Soong just uses it for optimization
  136. pass
  137. tidy_files = []
  138. clang_tidy_info = p.get("//build/bazel/rules/cc:clang_tidy.bzl%ClangTidyInfo")
  139. if clang_tidy_info:
  140. tidy_files = [v.path for v in clang_tidy_info.transitive_tidy_files.to_list()]
  141. abi_diff_files = []
  142. abi_diff_info = p.get("//build/bazel/rules/abi:abi_dump.bzl%AbiDiffInfo")
  143. if abi_diff_info:
  144. abi_diff_files = [f.path for f in abi_diff_info.diff_files.to_list()]
  145. local_static_libs = []
  146. local_whole_static_libs = []
  147. local_shared_libs = []
  148. androidmk_tag = "//build/bazel/rules/cc:cc_library_common.bzl%CcAndroidMkInfo"
  149. if androidmk_tag in p:
  150. androidmk_info = p[androidmk_tag]
  151. local_static_libs = androidmk_info.local_static_libs
  152. local_whole_static_libs = androidmk_info.local_whole_static_libs
  153. local_shared_libs = androidmk_info.local_shared_libs
  154. return json.encode({
  155. "OutputFiles": outputFiles,
  156. "CcObjectFiles": ccObjectFiles,
  157. "CcSharedLibraryFiles": sharedLibraries,
  158. "CcStaticLibraryFiles": staticLibraries,
  159. "Includes": includes,
  160. "SystemIncludes": system_includes,
  161. "Headers": headers,
  162. "RootStaticArchives": rootStaticArchives,
  163. "RootDynamicLibraries": rootSharedLibraries,
  164. "TidyFiles": [t for t in tidy_files],
  165. "TocFile": toc_file,
  166. "UnstrippedOutput": unstripped,
  167. "AbiDiffFiles": abi_diff_files,
  168. "LocalStaticLibs": [l for l in local_static_libs],
  169. "LocalWholeStaticLibs": [l for l in local_whole_static_libs],
  170. "LocalSharedLibs": [l for l in local_shared_libs],
  171. })`
  172. }
  173. // ParseResult returns a value obtained by parsing the result of the request's Starlark function.
  174. // The given rawString must correspond to the string output which was created by evaluating the
  175. // Starlark given in StarlarkFunctionBody.
  176. func (g getCcInfoType) ParseResult(rawString string) (CcInfo, error) {
  177. var ccInfo CcInfo
  178. if err := parseJson(rawString, &ccInfo); err != nil {
  179. return ccInfo, err
  180. }
  181. return ccInfo, nil
  182. }
  183. // Query Bazel for the artifacts generated by the apex modules.
  184. type getApexInfoType struct{}
  185. // Name returns a string name for this request type. Such request type names must be unique,
  186. // and must only consist of alphanumeric characters.
  187. func (g getApexInfoType) Name() string {
  188. return "getApexInfo"
  189. }
  190. // StarlarkFunctionBody returns a starlark function body to process this request type.
  191. // The returned string is the body of a Starlark function which obtains
  192. // all request-relevant information about a target and returns a string containing
  193. // this information. The function should have the following properties:
  194. // - The arguments are `target` (a configured target) and `id_string` (the label + configuration).
  195. // - The return value must be a string.
  196. // - The function body should not be indented outside of its own scope.
  197. func (g getApexInfoType) StarlarkFunctionBody() string {
  198. return `
  199. info = providers(target).get("//build/bazel/rules/apex:apex_info.bzl%ApexInfo")
  200. if not info:
  201. fail("%s did not provide ApexInfo" % id_string)
  202. bundle_key_info = info.bundle_key_info
  203. container_key_info = info.container_key_info
  204. signed_compressed_output = "" # no .capex if the apex is not compressible, cannot be None as it needs to be json encoded.
  205. if info.signed_compressed_output:
  206. signed_compressed_output = info.signed_compressed_output.path
  207. mk_info = providers(target).get("//build/bazel/rules/apex:apex_info.bzl%ApexMkInfo")
  208. if not mk_info:
  209. fail("%s did not provide ApexMkInfo" % id_string)
  210. tidy_files = []
  211. clang_tidy_info = providers(target).get("//build/bazel/rules/cc:clang_tidy.bzl%ClangTidyInfo")
  212. if clang_tidy_info:
  213. tidy_files = [v.path for v in clang_tidy_info.transitive_tidy_files.to_list()]
  214. return json.encode({
  215. "signed_output": info.signed_output.path,
  216. "signed_compressed_output": signed_compressed_output,
  217. "unsigned_output": info.unsigned_output.path,
  218. "provides_native_libs": [str(lib) for lib in info.provides_native_libs],
  219. "requires_native_libs": [str(lib) for lib in info.requires_native_libs],
  220. "bundle_key_info": [bundle_key_info.public_key.path, bundle_key_info.private_key.path],
  221. "container_key_info": [container_key_info.pem.path, container_key_info.pk8.path, container_key_info.key_name],
  222. "package_name": info.package_name,
  223. "symbols_used_by_apex": info.symbols_used_by_apex.path,
  224. "java_symbols_used_by_apex": info.java_symbols_used_by_apex.path,
  225. "backing_libs": info.backing_libs.path,
  226. "bundle_file": info.base_with_config_zip.path,
  227. "installed_files": info.installed_files.path,
  228. "make_modules_to_install": mk_info.make_modules_to_install,
  229. "files_info": mk_info.files_info,
  230. "tidy_files": [t for t in tidy_files],
  231. })`
  232. }
  233. type ApexInfo struct {
  234. // From the ApexInfo provider
  235. SignedOutput string `json:"signed_output"`
  236. SignedCompressedOutput string `json:"signed_compressed_output"`
  237. UnsignedOutput string `json:"unsigned_output"`
  238. ProvidesLibs []string `json:"provides_native_libs"`
  239. RequiresLibs []string `json:"requires_native_libs"`
  240. BundleKeyInfo []string `json:"bundle_key_info"`
  241. ContainerKeyInfo []string `json:"container_key_info"`
  242. PackageName string `json:"package_name"`
  243. SymbolsUsedByApex string `json:"symbols_used_by_apex"`
  244. JavaSymbolsUsedByApex string `json:"java_symbols_used_by_apex"`
  245. BackingLibs string `json:"backing_libs"`
  246. BundleFile string `json:"bundle_file"`
  247. InstalledFiles string `json:"installed_files"`
  248. TidyFiles []string `json:"tidy_files"`
  249. // From the ApexMkInfo provider
  250. MakeModulesToInstall []string `json:"make_modules_to_install"`
  251. PayloadFilesInfo []map[string]string `json:"files_info"`
  252. }
  253. // ParseResult returns a value obtained by parsing the result of the request's Starlark function.
  254. // The given rawString must correspond to the string output which was created by evaluating the
  255. // Starlark given in StarlarkFunctionBody.
  256. func (g getApexInfoType) ParseResult(rawString string) (ApexInfo, error) {
  257. var info ApexInfo
  258. err := parseJson(rawString, &info)
  259. return info, err
  260. }
  261. // getCcUnstrippedInfoType implements cqueryRequest interface. It handles the
  262. // interaction with `bazel cquery` to retrieve CcUnstrippedInfo provided
  263. // by the` cc_binary` and `cc_shared_library` rules.
  264. type getCcUnstrippedInfoType struct{}
  265. func (g getCcUnstrippedInfoType) Name() string {
  266. return "getCcUnstrippedInfo"
  267. }
  268. func (g getCcUnstrippedInfoType) StarlarkFunctionBody() string {
  269. return `
  270. p = providers(target)
  271. output_path = target.files.to_list()[0].path
  272. unstripped = output_path
  273. unstripped_tag = "//build/bazel/rules/cc:stripped_cc_common.bzl%CcUnstrippedInfo"
  274. if unstripped_tag in p:
  275. unstripped_info = p[unstripped_tag]
  276. unstripped = unstripped_info.unstripped[0].files.to_list()[0].path
  277. local_static_libs = []
  278. local_whole_static_libs = []
  279. local_shared_libs = []
  280. androidmk_tag = "//build/bazel/rules/cc:cc_library_common.bzl%CcAndroidMkInfo"
  281. if androidmk_tag in p:
  282. androidmk_info = p[androidmk_tag]
  283. local_static_libs = androidmk_info.local_static_libs
  284. local_whole_static_libs = androidmk_info.local_whole_static_libs
  285. local_shared_libs = androidmk_info.local_shared_libs
  286. tidy_files = []
  287. clang_tidy_info = p.get("//build/bazel/rules/cc:clang_tidy.bzl%ClangTidyInfo")
  288. if clang_tidy_info:
  289. tidy_files = [v.path for v in clang_tidy_info.transitive_tidy_files.to_list()]
  290. return json.encode({
  291. "OutputFile": output_path,
  292. "UnstrippedOutput": unstripped,
  293. "LocalStaticLibs": [l for l in local_static_libs],
  294. "LocalWholeStaticLibs": [l for l in local_whole_static_libs],
  295. "LocalSharedLibs": [l for l in local_shared_libs],
  296. "TidyFiles": [t for t in tidy_files],
  297. })
  298. `
  299. }
  300. // ParseResult returns a value obtained by parsing the result of the request's Starlark function.
  301. // The given rawString must correspond to the string output which was created by evaluating the
  302. // Starlark given in StarlarkFunctionBody.
  303. func (g getCcUnstrippedInfoType) ParseResult(rawString string) (CcUnstrippedInfo, error) {
  304. var info CcUnstrippedInfo
  305. err := parseJson(rawString, &info)
  306. return info, err
  307. }
  308. type CcUnstrippedInfo struct {
  309. CcAndroidMkInfo
  310. OutputFile string
  311. UnstrippedOutput string
  312. TidyFiles []string
  313. }
  314. // splitOrEmpty is a modification of strings.Split() that returns an empty list
  315. // if the given string is empty.
  316. func splitOrEmpty(s string, sep string) []string {
  317. if len(s) < 1 {
  318. return []string{}
  319. } else {
  320. return strings.Split(s, sep)
  321. }
  322. }
  323. // parseJson decodes json string into the fields of the receiver.
  324. // Unknown attribute name causes panic.
  325. func parseJson(jsonString string, info interface{}) error {
  326. decoder := json.NewDecoder(strings.NewReader(jsonString))
  327. decoder.DisallowUnknownFields() //useful to detect typos, e.g. in unit tests
  328. err := decoder.Decode(info)
  329. if err != nil {
  330. return fmt.Errorf("cannot parse cquery result '%s': %s", jsonString, err)
  331. }
  332. return nil
  333. }
  334. type getPrebuiltFileInfo struct{}
  335. // Name returns a string name for this request type. Such request type names must be unique,
  336. // and must only consist of alphanumeric characters.
  337. func (g getPrebuiltFileInfo) Name() string {
  338. return "getPrebuiltFileInfo"
  339. }
  340. // StarlarkFunctionBody returns a starlark function body to process this request type.
  341. // The returned string is the body of a Starlark function which obtains
  342. // all request-relevant information about a target and returns a string containing
  343. // this information.
  344. // The function should have the following properties:
  345. // - The arguments are `target` (a configured target) and `id_string` (the label + configuration).
  346. // - The return value must be a string.
  347. // - The function body should not be indented outside of its own scope.
  348. func (g getPrebuiltFileInfo) StarlarkFunctionBody() string {
  349. return `
  350. p = providers(target)
  351. prebuilt_file_info = p.get("//build/bazel/rules:prebuilt_file.bzl%PrebuiltFileInfo")
  352. if not prebuilt_file_info:
  353. fail("%s did not provide PrebuiltFileInfo" % id_string)
  354. return json.encode({
  355. "Src": prebuilt_file_info.src.path,
  356. "Dir": prebuilt_file_info.dir,
  357. "Filename": prebuilt_file_info.filename,
  358. "Installable": prebuilt_file_info.installable,
  359. })`
  360. }
  361. type PrebuiltFileInfo struct {
  362. // TODO: b/207489266 - Fully support all properties in prebuilt_file
  363. Src string
  364. Dir string
  365. Filename string
  366. Installable bool
  367. }
  368. // ParseResult returns a value obtained by parsing the result of the request's Starlark function.
  369. // The given rawString must correspond to the string output which was created by evaluating the
  370. // Starlark given in StarlarkFunctionBody.
  371. func (g getPrebuiltFileInfo) ParseResult(rawString string) (PrebuiltFileInfo, error) {
  372. var info PrebuiltFileInfo
  373. err := parseJson(rawString, &info)
  374. return info, err
  375. }