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