request_type.go 15 KB

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