blob: 3a07128eac28e1099b92313c3854f91a5273c086 [file] [log] [blame]
Liz Kammer2b8004b2021-10-04 13:55:44 -04001// Copyright 2021 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package bp2build
16
17import (
18 "android/soong/android"
19 "android/soong/cc"
20 "fmt"
21 "strings"
22 "testing"
23)
24
25const (
26 ccBinaryTypePlaceHolder = "{rule_name}"
27 compatibleWithPlaceHolder = "{target_compatible_with}"
28)
29
30func registerCcBinaryModuleTypes(ctx android.RegistrationContext) {
31 cc.RegisterCCBuildComponents(ctx)
32 ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
33 ctx.RegisterModuleType("cc_library_static", cc.LibraryStaticFactory)
34 ctx.RegisterModuleType("cc_library", cc.LibraryFactory)
35}
36
37var binaryReplacer = strings.NewReplacer(ccBinaryTypePlaceHolder, "cc_binary", compatibleWithPlaceHolder, "")
38var hostBinaryReplacer = strings.NewReplacer(ccBinaryTypePlaceHolder, "cc_binary_host", compatibleWithPlaceHolder, `
39 target_compatible_with = select({
40 "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
41 "//conditions:default": [],
42 }),`)
43
44func runCcBinaryTests(t *testing.T, tc bp2buildTestCase) {
45 t.Helper()
46 runCcBinaryTestCase(t, tc)
47 runCcHostBinaryTestCase(t, tc)
48}
49
50func runCcBinaryTestCase(t *testing.T, tc bp2buildTestCase) {
51 t.Helper()
52 testCase := tc
53 testCase.expectedBazelTargets = append([]string{}, tc.expectedBazelTargets...)
54 testCase.moduleTypeUnderTest = "cc_binary"
55 testCase.moduleTypeUnderTestFactory = cc.BinaryFactory
56 testCase.moduleTypeUnderTestBp2BuildMutator = cc.BinaryBp2build
57 testCase.description = fmt.Sprintf("%s %s", testCase.moduleTypeUnderTest, testCase.description)
58 testCase.blueprint = binaryReplacer.Replace(testCase.blueprint)
59 for i, et := range testCase.expectedBazelTargets {
60 testCase.expectedBazelTargets[i] = binaryReplacer.Replace(et)
61 }
62 t.Run(testCase.description, func(t *testing.T) {
63 runBp2BuildTestCase(t, registerCcBinaryModuleTypes, testCase)
64 })
65}
66
67func runCcHostBinaryTestCase(t *testing.T, tc bp2buildTestCase) {
68 t.Helper()
69 testCase := tc
70 testCase.expectedBazelTargets = append([]string{}, tc.expectedBazelTargets...)
71 testCase.moduleTypeUnderTest = "cc_binary_host"
72 testCase.moduleTypeUnderTestFactory = cc.BinaryHostFactory
73 testCase.moduleTypeUnderTestBp2BuildMutator = cc.BinaryHostBp2build
74 testCase.description = fmt.Sprintf("%s %s", testCase.moduleTypeUnderTest, testCase.description)
75 testCase.blueprint = hostBinaryReplacer.Replace(testCase.blueprint)
76 for i, et := range testCase.expectedBazelTargets {
77 testCase.expectedBazelTargets[i] = hostBinaryReplacer.Replace(et)
78 }
79 t.Run(testCase.description, func(t *testing.T) {
80 runBp2BuildTestCase(t, registerCcBinaryModuleTypes, testCase)
81 })
82}
83
84func TestBasicCcBinary(t *testing.T) {
85 runCcBinaryTests(t, bp2buildTestCase{
86 description: "basic -- properties -> attrs with little/no transformation",
87 blueprint: `
88{rule_name} {
89 name: "foo",
90 srcs: ["a.cc"],
91 local_include_dirs: ["dir"],
92 include_dirs: ["absolute_dir"],
93 cflags: ["-Dcopt"],
94 cppflags: ["-Dcppflag"],
95 conlyflags: ["-Dconlyflag"],
96 asflags: ["-Dasflag"],
97 ldflags: ["ld-flag"],
98 rtti: true,
99 strip: {
100 all: true,
101 keep_symbols: true,
102 keep_symbols_and_debug_frame: true,
103 keep_symbols_list: ["symbol"],
104 none: true,
105 },
106}
107`,
108 expectedBazelTargets: []string{`cc_binary(
109 name = "foo",
110 absolute_includes = ["absolute_dir"],
111 asflags = ["-Dasflag"],
112 conlyflags = ["-Dconlyflag"],
113 copts = ["-Dcopt"],
114 cppflags = ["-Dcppflag"],
115 linkopts = ["ld-flag"],
116 local_includes = [
117 "dir",
118 ".",
119 ],
120 rtti = True,
121 srcs = ["a.cc"],
122 strip = {
123 "all": True,
124 "keep_symbols": True,
125 "keep_symbols_and_debug_frame": True,
126 "keep_symbols_list": ["symbol"],
127 "none": True,
128 },{target_compatible_with}
129)`},
130 })
131}
132
133func TestCcBinaryWithSharedLdflagDisableFeature(t *testing.T) {
134 runCcBinaryTests(t, bp2buildTestCase{
135 description: `ldflag "-shared" disables static_flag feature`,
136 blueprint: `
137{rule_name} {
138 name: "foo",
139 ldflags: ["-shared"],
140 include_build_directory: false,
141}
142`,
143 expectedBazelTargets: []string{`cc_binary(
144 name = "foo",
145 features = ["-static_flag"],
146 linkopts = ["-shared"],{target_compatible_with}
147)`},
148 })
149}
150
151func TestCcBinaryWithLinkStatic(t *testing.T) {
152 runCcBinaryTests(t, bp2buildTestCase{
153 description: "link static",
154 blueprint: `
155{rule_name} {
156 name: "foo",
157 static_executable: true,
158 include_build_directory: false,
159}
160`,
161 expectedBazelTargets: []string{`cc_binary(
162 name = "foo",
163 linkshared = False,{target_compatible_with}
164)`},
165 })
166}
167
168func TestCcBinaryVersionScript(t *testing.T) {
169 runCcBinaryTests(t, bp2buildTestCase{
170 description: `version script`,
171 blueprint: `
172{rule_name} {
173 name: "foo",
174 include_build_directory: false,
175 version_script: "vs",
176}
177`,
178 expectedBazelTargets: []string{`cc_binary(
179 name = "foo",
180 additional_linker_inputs = ["vs"],
181 linkopts = ["-Wl,--version-script,$(location vs)"],{target_compatible_with}
182)`},
183 })
184}
185
186func TestCcBinarySplitSrcsByLang(t *testing.T) {
187 runCcHostBinaryTestCase(t, bp2buildTestCase{
188 description: "split srcs by lang",
189 blueprint: `
190{rule_name} {
191 name: "foo",
192 srcs: [
193 "asonly.S",
194 "conly.c",
195 "cpponly.cpp",
196 ":fg_foo",
197 ],
198 include_build_directory: false,
199}
200` + simpleModuleDoNotConvertBp2build("filegroup", "fg_foo"),
201 expectedBazelTargets: []string{`cc_binary(
202 name = "foo",
203 srcs = [
204 "cpponly.cpp",
205 ":fg_foo_cpp_srcs",
206 ],
207 srcs_as = [
208 "asonly.S",
209 ":fg_foo_as_srcs",
210 ],
211 srcs_c = [
212 "conly.c",
213 ":fg_foo_c_srcs",
214 ],{target_compatible_with}
215)`},
216 })
217}
218
219func TestCcBinaryDoNotDistinguishBetweenDepsAndImplementationDeps(t *testing.T) {
220 runCcBinaryTestCase(t, bp2buildTestCase{
221 description: "no implementation deps",
222 blueprint: `
223{rule_name} {
224 name: "foo",
225 shared_libs: ["implementation_shared_dep", "shared_dep"],
226 export_shared_lib_headers: ["shared_dep"],
227 static_libs: ["implementation_static_dep", "static_dep"],
228 export_static_lib_headers: ["static_dep", "whole_static_dep"],
229 whole_static_libs: ["not_explicitly_exported_whole_static_dep", "whole_static_dep"],
230 include_build_directory: false,
231}
232` +
233 simpleModuleDoNotConvertBp2build("cc_library_static", "static_dep") +
234 simpleModuleDoNotConvertBp2build("cc_library_static", "implementation_static_dep") +
235 simpleModuleDoNotConvertBp2build("cc_library_static", "whole_static_dep") +
236 simpleModuleDoNotConvertBp2build("cc_library_static", "not_explicitly_exported_whole_static_dep") +
237 simpleModuleDoNotConvertBp2build("cc_library", "shared_dep") +
238 simpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep"),
239 expectedBazelTargets: []string{`cc_binary(
240 name = "foo",
241 deps = [
242 ":implementation_static_dep",
243 ":static_dep",
244 ],
245 dynamic_deps = [
246 ":implementation_shared_dep",
247 ":shared_dep",
248 ],{target_compatible_with}
249 whole_archive_deps = [
250 ":not_explicitly_exported_whole_static_dep",
251 ":whole_static_dep",
252 ],
253)`},
254 })
255}
256
257func TestCcBinaryNocrtTests(t *testing.T) {
258 baseTestCases := []struct {
259 description string
260 soongProperty string
261 bazelAttr string
262 }{
263 {
264 description: "nocrt: true",
265 soongProperty: `nocrt: true,`,
266 bazelAttr: ` link_crt = False,`,
267 },
268 {
269 description: "nocrt: false",
270 soongProperty: `nocrt: false,`,
271 },
272 {
273 description: "nocrt: not set",
274 },
275 }
276
277 baseBlueprint := `{rule_name} {
278 name: "foo",%s
279 include_build_directory: false,
280}
281`
282
283 baseBazelTarget := `cc_binary(
284 name = "foo",%s{target_compatible_with}
285)`
286
287 for _, btc := range baseTestCases {
288 prop := btc.soongProperty
289 if len(prop) > 0 {
290 prop = "\n" + prop
291 }
292 attr := btc.bazelAttr
293 if len(attr) > 0 {
294 attr = "\n" + attr
295 }
296 runCcBinaryTests(t, bp2buildTestCase{
297 description: btc.description,
298 blueprint: fmt.Sprintf(baseBlueprint, prop),
299 expectedBazelTargets: []string{
300 fmt.Sprintf(baseBazelTarget, attr),
301 },
302 })
303 }
304}
305
306func TestCcBinaryNo_libcrtTests(t *testing.T) {
307 baseTestCases := []struct {
308 description string
309 soongProperty string
310 bazelAttr string
311 }{
312 {
313 description: "no_libcrt: true",
314 soongProperty: `no_libcrt: true,`,
315 bazelAttr: ` use_libcrt = False,`,
316 },
317 {
318 description: "no_libcrt: false",
319 soongProperty: `no_libcrt: false,`,
320 bazelAttr: ` use_libcrt = True,`,
321 },
322 {
323 description: "no_libcrt: not set",
324 },
325 }
326
327 baseBlueprint := `{rule_name} {
328 name: "foo",%s
329 include_build_directory: false,
330}
331`
332
333 baseBazelTarget := `cc_binary(
334 name = "foo",{target_compatible_with}%s
335)`
336
337 for _, btc := range baseTestCases {
338 prop := btc.soongProperty
339 if len(prop) > 0 {
340 prop = "\n" + prop
341 }
342 attr := btc.bazelAttr
343 if len(attr) > 0 {
344 attr = "\n" + attr
345 }
346 runCcBinaryTests(t, bp2buildTestCase{
347 description: btc.description,
348 blueprint: fmt.Sprintf(baseBlueprint, prop),
349 expectedBazelTargets: []string{
350 fmt.Sprintf(baseBazelTarget, attr),
351 },
352 })
353 }
354}
355
356func TestCcBinaryPropertiesToFeatures(t *testing.T) {
357 baseTestCases := []struct {
358 description string
359 soongProperty string
360 bazelAttr string
361 }{
362 {
363 description: "pack_relocation: true",
364 soongProperty: `pack_relocations: true,`,
365 },
366 {
367 description: "pack_relocations: false",
368 soongProperty: `pack_relocations: false,`,
369 bazelAttr: ` features = ["disable_pack_relocations"],`,
370 },
371 {
372 description: "pack_relocations: not set",
373 },
374 {
375 description: "pack_relocation: true",
376 soongProperty: `allow_undefined_symbols: true,`,
377 bazelAttr: ` features = ["-no_undefined_symbols"],`,
378 },
379 {
380 description: "allow_undefined_symbols: false",
381 soongProperty: `allow_undefined_symbols: false,`,
382 },
383 {
384 description: "allow_undefined_symbols: not set",
385 },
386 }
387
388 baseBlueprint := `{rule_name} {
389 name: "foo",%s
390 include_build_directory: false,
391}
392`
393
394 baseBazelTarget := `cc_binary(
395 name = "foo",%s{target_compatible_with}
396)`
397
398 for _, btc := range baseTestCases {
399 prop := btc.soongProperty
400 if len(prop) > 0 {
401 prop = "\n" + prop
402 }
403 attr := btc.bazelAttr
404 if len(attr) > 0 {
405 attr = "\n" + attr
406 }
407 runCcBinaryTests(t, bp2buildTestCase{
408 description: btc.description,
409 blueprint: fmt.Sprintf(baseBlueprint, prop),
410 expectedBazelTargets: []string{
411 fmt.Sprintf(baseBazelTarget, attr),
412 },
413 })
414 }
415}