• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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