• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// 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	"fmt"
19	"strings"
20	"testing"
21
22	"android/soong/android"
23	"android/soong/cc"
24	"android/soong/genrule"
25)
26
27const (
28	ccBinaryTypePlaceHolder = "{rule_name}"
29)
30
31type testBazelTarget struct {
32	typ   string
33	name  string
34	attrs AttrNameToString
35}
36
37func generateBazelTargetsForTest(targets []testBazelTarget, hod android.HostOrDeviceSupported) []string {
38	ret := make([]string, 0, len(targets))
39	for _, t := range targets {
40		attrs := t.attrs.clone()
41		ret = append(ret, makeBazelTargetHostOrDevice(t.typ, t.name, attrs, hod))
42	}
43	return ret
44}
45
46type ccBinaryBp2buildTestCase struct {
47	description string
48	filesystem  map[string]string
49	blueprint   string
50	targets     []testBazelTarget
51}
52
53func registerCcBinaryModuleTypes(ctx android.RegistrationContext) {
54	cc.RegisterCCBuildComponents(ctx)
55	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
56	ctx.RegisterModuleType("cc_library_static", cc.LibraryStaticFactory)
57	ctx.RegisterModuleType("cc_library", cc.LibraryFactory)
58	ctx.RegisterModuleType("genrule", genrule.GenRuleFactory)
59}
60
61var binaryReplacer = strings.NewReplacer(ccBinaryTypePlaceHolder, "cc_binary")
62var hostBinaryReplacer = strings.NewReplacer(ccBinaryTypePlaceHolder, "cc_binary_host")
63
64func runCcBinaryTests(t *testing.T, tc ccBinaryBp2buildTestCase) {
65	t.Helper()
66	runCcBinaryTestCase(t, tc)
67	runCcHostBinaryTestCase(t, tc)
68}
69
70func runCcBinaryTestCase(t *testing.T, testCase ccBinaryBp2buildTestCase) {
71	t.Helper()
72	moduleTypeUnderTest := "cc_binary"
73
74	description := fmt.Sprintf("%s %s", moduleTypeUnderTest, testCase.description)
75	t.Run(description, func(t *testing.T) {
76		t.Helper()
77		RunBp2BuildTestCase(t, registerCcBinaryModuleTypes, Bp2buildTestCase{
78			ExpectedBazelTargets:       generateBazelTargetsForTest(testCase.targets, android.DeviceSupported),
79			ModuleTypeUnderTest:        moduleTypeUnderTest,
80			ModuleTypeUnderTestFactory: cc.BinaryFactory,
81			Description:                description,
82			Blueprint:                  binaryReplacer.Replace(testCase.blueprint),
83			Filesystem:                 testCase.filesystem,
84		})
85	})
86}
87
88func runCcHostBinaryTestCase(t *testing.T, testCase ccBinaryBp2buildTestCase) {
89	t.Helper()
90	moduleTypeUnderTest := "cc_binary_host"
91	description := fmt.Sprintf("%s %s", moduleTypeUnderTest, testCase.description)
92	t.Run(description, func(t *testing.T) {
93		RunBp2BuildTestCase(t, registerCcBinaryModuleTypes, Bp2buildTestCase{
94			ExpectedBazelTargets:       generateBazelTargetsForTest(testCase.targets, android.HostSupported),
95			ModuleTypeUnderTest:        moduleTypeUnderTest,
96			ModuleTypeUnderTestFactory: cc.BinaryHostFactory,
97			Description:                description,
98			Blueprint:                  hostBinaryReplacer.Replace(testCase.blueprint),
99			Filesystem:                 testCase.filesystem,
100		})
101	})
102}
103
104func TestBasicCcBinary(t *testing.T) {
105	runCcBinaryTests(t, ccBinaryBp2buildTestCase{
106		description: "basic -- properties -> attrs with little/no transformation",
107		filesystem: map[string]string{
108			soongCcVersionLibBpPath: soongCcVersionLibBp,
109		},
110		blueprint: `
111{rule_name} {
112    name: "foo",
113    srcs: ["a.cc"],
114    local_include_dirs: ["dir"],
115    include_dirs: ["absolute_dir"],
116    cflags: ["-Dcopt"],
117    cppflags: ["-Dcppflag"],
118    conlyflags: ["-Dconlyflag"],
119    asflags: ["-Dasflag"],
120    ldflags: ["ld-flag"],
121    rtti: true,
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    },
129    sdk_version: "current",
130    min_sdk_version: "29",
131    use_version_lib: true,
132}
133`,
134		targets: []testBazelTarget{
135			{"cc_binary", "foo", AttrNameToString{
136				"absolute_includes": `["absolute_dir"]`,
137				"asflags":           `["-Dasflag"]`,
138				"conlyflags":        `["-Dconlyflag"]`,
139				"copts":             `["-Dcopt"]`,
140				"cppflags":          `["-Dcppflag"]`,
141				"linkopts":          `["ld-flag"]`,
142				"local_includes": `[
143        "dir",
144        ".",
145    ]`,
146				"rtti": `True`,
147				"srcs": `["a.cc"]`,
148				"strip": `{
149        "all": True,
150        "keep_symbols": True,
151        "keep_symbols_and_debug_frame": True,
152        "keep_symbols_list": ["symbol"],
153        "none": True,
154    }`,
155				"sdk_version":        `"current"`,
156				"min_sdk_version":    `"29"`,
157				"use_version_lib":    `True`,
158				"whole_archive_deps": `["//build/soong/cc/libbuildversion:libbuildversion"]`,
159			},
160			},
161		},
162	})
163}
164
165func TestCcBinaryWithSharedLdflagDisableFeature(t *testing.T) {
166	runCcBinaryTests(t, ccBinaryBp2buildTestCase{
167		description: `ldflag "-shared" disables static_flag feature`,
168		blueprint: `
169{rule_name} {
170    name: "foo",
171    ldflags: ["-shared"],
172    include_build_directory: false,
173}
174`,
175		targets: []testBazelTarget{
176			{"cc_binary", "foo", AttrNameToString{
177				"features": `["-static_flag"]`,
178				"linkopts": `["-shared"]`,
179			},
180			},
181		},
182	})
183}
184
185func TestCcBinaryWithLinkStatic(t *testing.T) {
186	runCcBinaryTests(t, ccBinaryBp2buildTestCase{
187		description: "link static",
188		blueprint: `
189{rule_name} {
190    name: "foo",
191    static_executable: true,
192    include_build_directory: false,
193}
194`,
195		targets: []testBazelTarget{
196			{"cc_binary", "foo", AttrNameToString{
197				"linkshared": `False`,
198			},
199			},
200		},
201	})
202}
203
204func TestCcBinaryVersionScriptAndDynamicList(t *testing.T) {
205	runCcBinaryTests(t, ccBinaryBp2buildTestCase{
206		description: `version script and dynamic list`,
207		blueprint: `
208{rule_name} {
209    name: "foo",
210    include_build_directory: false,
211    version_script: "vs",
212    dynamic_list: "dynamic.list",
213}
214`,
215		targets: []testBazelTarget{
216			{"cc_binary", "foo", AttrNameToString{
217				"additional_linker_inputs": `[
218        "vs",
219        "dynamic.list",
220    ]`,
221				"linkopts": `[
222        "-Wl,--version-script,$(location vs)",
223        "-Wl,--dynamic-list,$(location dynamic.list)",
224    ]`,
225			},
226			},
227		},
228	})
229}
230
231func TestCcBinaryLdflagsSplitBySpaceExceptSoongAdded(t *testing.T) {
232	runCcBinaryTests(t, ccBinaryBp2buildTestCase{
233		description: "ldflags are split by spaces except for the ones added by soong (version script and dynamic list)",
234		blueprint: `
235{rule_name} {
236    name: "foo",
237		ldflags: [
238			"--nospace_flag",
239			"-z spaceflag",
240		],
241		version_script: "version_script",
242		dynamic_list: "dynamic.list",
243    include_build_directory: false,
244}
245`,
246		targets: []testBazelTarget{
247			{"cc_binary", "foo", AttrNameToString{
248				"additional_linker_inputs": `[
249        "version_script",
250        "dynamic.list",
251    ]`,
252				"linkopts": `[
253        "--nospace_flag",
254        "-z",
255        "spaceflag",
256        "-Wl,--version-script,$(location version_script)",
257        "-Wl,--dynamic-list,$(location dynamic.list)",
258    ]`,
259			}}},
260	})
261}
262
263func TestCcBinarySplitSrcsByLang(t *testing.T) {
264	runCcHostBinaryTestCase(t, ccBinaryBp2buildTestCase{
265		description: "split srcs by lang",
266		blueprint: `
267{rule_name} {
268    name: "foo",
269    srcs: [
270        "asonly.S",
271        "conly.c",
272        "cpponly.cpp",
273        ":fg_foo",
274    ],
275    include_build_directory: false,
276}
277` + simpleModuleDoNotConvertBp2build("filegroup", "fg_foo"),
278		targets: []testBazelTarget{
279			{"cc_binary", "foo", AttrNameToString{
280				"srcs": `[
281        "cpponly.cpp",
282        ":fg_foo_cpp_srcs",
283    ]`,
284				"srcs_as": `[
285        "asonly.S",
286        ":fg_foo_as_srcs",
287    ]`,
288				"srcs_c": `[
289        "conly.c",
290        ":fg_foo_c_srcs",
291    ]`,
292			},
293			},
294		},
295	})
296}
297
298func TestCcBinaryDoNotDistinguishBetweenDepsAndImplementationDeps(t *testing.T) {
299	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
300		description: "no implementation deps",
301		blueprint: `
302genrule {
303    name: "generated_hdr",
304    cmd: "nothing to see here",
305    bazel_module: { bp2build_available: false },
306}
307
308genrule {
309    name: "export_generated_hdr",
310    cmd: "nothing to see here",
311    bazel_module: { bp2build_available: false },
312}
313
314{rule_name} {
315    name: "foo",
316    srcs: ["foo.cpp"],
317    shared_libs: ["implementation_shared_dep", "shared_dep"],
318    export_shared_lib_headers: ["shared_dep"],
319    static_libs: ["implementation_static_dep", "static_dep"],
320    export_static_lib_headers: ["static_dep", "whole_static_dep"],
321    whole_static_libs: ["not_explicitly_exported_whole_static_dep", "whole_static_dep"],
322    include_build_directory: false,
323    generated_headers: ["generated_hdr", "export_generated_hdr"],
324    export_generated_headers: ["export_generated_hdr"],
325}
326` +
327			simpleModuleDoNotConvertBp2build("cc_library_static", "static_dep") +
328			simpleModuleDoNotConvertBp2build("cc_library_static", "implementation_static_dep") +
329			simpleModuleDoNotConvertBp2build("cc_library_static", "whole_static_dep") +
330			simpleModuleDoNotConvertBp2build("cc_library_static", "not_explicitly_exported_whole_static_dep") +
331			simpleModuleDoNotConvertBp2build("cc_library", "shared_dep") +
332			simpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep"),
333		targets: []testBazelTarget{
334			{"cc_binary", "foo", AttrNameToString{
335				"deps": `[
336        ":implementation_static_dep",
337        ":static_dep",
338    ]`,
339				"dynamic_deps": `[
340        ":implementation_shared_dep",
341        ":shared_dep",
342    ]`,
343				"srcs": `[
344        "foo.cpp",
345        ":generated_hdr",
346        ":export_generated_hdr",
347    ]`,
348				"whole_archive_deps": `[
349        ":not_explicitly_exported_whole_static_dep",
350        ":whole_static_dep",
351    ]`,
352				"local_includes": `["."]`,
353			},
354			},
355		},
356	})
357}
358
359func TestCcBinaryNocrtTests(t *testing.T) {
360	baseTestCases := []struct {
361		description   string
362		soongProperty string
363		bazelAttr     AttrNameToString
364	}{
365		{
366			description:   "nocrt: true",
367			soongProperty: `nocrt: true,`,
368			bazelAttr:     AttrNameToString{"features": `["-link_crt"]`},
369		},
370		{
371			description:   "nocrt: false",
372			soongProperty: `nocrt: false,`,
373			bazelAttr:     AttrNameToString{},
374		},
375		{
376			description: "nocrt: not set",
377			bazelAttr:   AttrNameToString{},
378		},
379	}
380
381	baseBlueprint := `{rule_name} {
382    name: "foo",%s
383    include_build_directory: false,
384}
385`
386
387	for _, btc := range baseTestCases {
388		prop := btc.soongProperty
389		if len(prop) > 0 {
390			prop = "\n" + prop
391		}
392		runCcBinaryTests(t, ccBinaryBp2buildTestCase{
393			description: btc.description,
394			blueprint:   fmt.Sprintf(baseBlueprint, prop),
395			targets: []testBazelTarget{
396				{"cc_binary", "foo", btc.bazelAttr},
397			},
398		})
399	}
400}
401
402func TestCcBinaryNo_libcrtTests(t *testing.T) {
403	baseTestCases := []struct {
404		description   string
405		soongProperty string
406		bazelAttr     AttrNameToString
407	}{
408		{
409			description:   "no_libcrt: true",
410			soongProperty: `no_libcrt: true,`,
411			bazelAttr:     AttrNameToString{"features": `["-use_libcrt"]`},
412		},
413		{
414			description:   "no_libcrt: false",
415			soongProperty: `no_libcrt: false,`,
416			bazelAttr:     AttrNameToString{},
417		},
418		{
419			description: "no_libcrt: not set",
420			bazelAttr:   AttrNameToString{},
421		},
422	}
423
424	baseBlueprint := `{rule_name} {
425    name: "foo",%s
426    include_build_directory: false,
427}
428`
429
430	for _, btc := range baseTestCases {
431		prop := btc.soongProperty
432		if len(prop) > 0 {
433			prop = "\n" + prop
434		}
435		runCcBinaryTests(t, ccBinaryBp2buildTestCase{
436			description: btc.description,
437			blueprint:   fmt.Sprintf(baseBlueprint, prop),
438			targets: []testBazelTarget{
439				{"cc_binary", "foo", btc.bazelAttr},
440			},
441		})
442	}
443}
444
445func TestCcBinaryPropertiesToFeatures(t *testing.T) {
446	baseTestCases := []struct {
447		description   string
448		soongProperty string
449		bazelAttr     AttrNameToString
450	}{
451		{
452			description:   "pack_relocation: true",
453			soongProperty: `pack_relocations: true,`,
454			bazelAttr:     AttrNameToString{},
455		},
456		{
457			description:   "pack_relocations: false",
458			soongProperty: `pack_relocations: false,`,
459			bazelAttr:     AttrNameToString{"features": `["disable_pack_relocations"]`},
460		},
461		{
462			description: "pack_relocations: not set",
463			bazelAttr:   AttrNameToString{},
464		},
465		{
466			description:   "pack_relocation: true",
467			soongProperty: `allow_undefined_symbols: true,`,
468			bazelAttr:     AttrNameToString{"features": `["-no_undefined_symbols"]`},
469		},
470		{
471			description:   "allow_undefined_symbols: false",
472			soongProperty: `allow_undefined_symbols: false,`,
473			bazelAttr:     AttrNameToString{},
474		},
475		{
476			description: "allow_undefined_symbols: not set",
477			bazelAttr:   AttrNameToString{},
478		},
479	}
480
481	baseBlueprint := `{rule_name} {
482    name: "foo",%s
483    include_build_directory: false,
484}
485`
486	for _, btc := range baseTestCases {
487		prop := btc.soongProperty
488		if len(prop) > 0 {
489			prop = "\n" + prop
490		}
491		runCcBinaryTests(t, ccBinaryBp2buildTestCase{
492			description: btc.description,
493			blueprint:   fmt.Sprintf(baseBlueprint, prop),
494			targets: []testBazelTarget{
495				{"cc_binary", "foo", btc.bazelAttr},
496			},
497		})
498	}
499}
500
501func TestCcBinarySharedProto(t *testing.T) {
502	runCcBinaryTests(t, ccBinaryBp2buildTestCase{
503		blueprint: soongCcProtoLibraries + `{rule_name} {
504	name: "foo",
505	srcs: ["foo.proto"],
506	proto: {
507	},
508	include_build_directory: false,
509}`,
510		targets: []testBazelTarget{
511			{"proto_library", "foo_proto", AttrNameToString{
512				"srcs": `["foo.proto"]`,
513			}}, {"cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
514				"deps": `[":foo_proto"]`,
515			}}, {"cc_binary", "foo", AttrNameToString{
516				"dynamic_deps":       `[":libprotobuf-cpp-lite"]`,
517				"whole_archive_deps": `[":foo_cc_proto_lite"]`,
518			}},
519		},
520	})
521}
522
523func TestCcBinaryStaticProto(t *testing.T) {
524	runCcBinaryTests(t, ccBinaryBp2buildTestCase{
525		blueprint: soongCcProtoLibraries + `{rule_name} {
526	name: "foo",
527	srcs: ["foo.proto"],
528	static_executable: true,
529	proto: {
530	},
531	include_build_directory: false,
532}`,
533		targets: []testBazelTarget{
534			{"proto_library", "foo_proto", AttrNameToString{
535				"srcs": `["foo.proto"]`,
536			}}, {"cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
537				"deps": `[":foo_proto"]`,
538			}}, {"cc_binary", "foo", AttrNameToString{
539				"deps":               `[":libprotobuf-cpp-lite"]`,
540				"whole_archive_deps": `[":foo_cc_proto_lite"]`,
541				"linkshared":         `False`,
542			}},
543		},
544	})
545}
546
547func TestCcBinaryConvertLex(t *testing.T) {
548	runCcBinaryTests(t, ccBinaryBp2buildTestCase{
549		description: `.l and .ll sources converted to .c and .cc`,
550		blueprint: `
551{rule_name} {
552    name: "foo",
553		srcs: ["foo.c", "bar.cc", "foo1.l", "foo2.l", "bar1.ll", "bar2.ll"],
554		lex: { flags: ["--foo_opt", "--bar_opt"] },
555		include_build_directory: false,
556}
557`,
558		targets: []testBazelTarget{
559			{"genlex", "foo_genlex_l", AttrNameToString{
560				"srcs": `[
561        "foo1.l",
562        "foo2.l",
563    ]`,
564				"lexopts": `[
565        "--foo_opt",
566        "--bar_opt",
567    ]`,
568			}},
569			{"genlex", "foo_genlex_ll", AttrNameToString{
570				"srcs": `[
571        "bar1.ll",
572        "bar2.ll",
573    ]`,
574				"lexopts": `[
575        "--foo_opt",
576        "--bar_opt",
577    ]`,
578			}},
579			{"cc_binary", "foo", AttrNameToString{
580				"srcs": `[
581        "bar.cc",
582        ":foo_genlex_ll",
583    ]`,
584				"srcs_c": `[
585        "foo.c",
586        ":foo_genlex_l",
587    ]`,
588			}},
589		},
590	})
591}
592
593func TestCcBinaryRuntimeLibs(t *testing.T) {
594	runCcBinaryTests(t, ccBinaryBp2buildTestCase{
595		description: "cc_binary with runtime libs",
596		blueprint: `
597cc_library {
598    name: "bar",
599    srcs: ["b.cc"],
600}
601
602{rule_name} {
603    name: "foo",
604    srcs: ["a.cc"],
605    runtime_libs: ["bar"],
606}
607`,
608		targets: []testBazelTarget{
609			{"cc_library_static", "bar_bp2build_cc_library_static", AttrNameToString{
610				"local_includes":         `["."]`,
611				"srcs":                   `["b.cc"]`,
612				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
613			},
614			},
615			{"cc_library_shared", "bar", AttrNameToString{
616				"local_includes":         `["."]`,
617				"srcs":                   `["b.cc"]`,
618				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
619			},
620			},
621			{"cc_binary", "foo", AttrNameToString{
622				"local_includes": `["."]`,
623				"srcs":           `["a.cc"]`,
624				"runtime_deps":   `[":bar"]`,
625			},
626			},
627		},
628	})
629}
630
631func TestCcBinaryWithInstructionSet(t *testing.T) {
632	runCcBinaryTests(t, ccBinaryBp2buildTestCase{
633		description: "instruction set",
634		blueprint: `
635{rule_name} {
636    name: "foo",
637    arch: {
638      arm: {
639        instruction_set: "arm",
640      }
641    }
642}
643`,
644		targets: []testBazelTarget{
645			{"cc_binary", "foo", AttrNameToString{
646				"features": `select({
647        "//build/bazel/platforms/arch:arm": [
648            "arm_isa_arm",
649            "-arm_isa_thumb",
650        ],
651        "//conditions:default": [],
652    })`,
653				"local_includes": `["."]`,
654			}},
655		},
656	})
657}
658
659func TestCcBinaryEmptySuffix(t *testing.T) {
660	runCcBinaryTests(t, ccBinaryBp2buildTestCase{
661		description: "binary with empty suffix",
662		blueprint: `
663{rule_name} {
664    name: "foo",
665    suffix: "",
666}`,
667		targets: []testBazelTarget{
668			{"cc_binary", "foo", AttrNameToString{
669				"local_includes": `["."]`,
670				"suffix":         `""`,
671			}},
672		},
673	})
674}
675
676func TestCcBinarySuffix(t *testing.T) {
677	runCcBinaryTests(t, ccBinaryBp2buildTestCase{
678		description: "binary with suffix",
679		blueprint: `
680{rule_name} {
681    name: "foo",
682    suffix: "-suf",
683}
684`,
685		targets: []testBazelTarget{
686			{"cc_binary", "foo", AttrNameToString{
687				"local_includes": `["."]`,
688				"suffix":         `"-suf"`,
689			}},
690		},
691	})
692}
693
694func TestCcArchVariantBinarySuffix(t *testing.T) {
695	runCcBinaryTests(t, ccBinaryBp2buildTestCase{
696		description: "binary with suffix",
697		blueprint: `
698{rule_name} {
699    name: "foo",
700    arch: {
701        arm64: { suffix: "-64" },
702        arm:   { suffix: "-32" },
703		},
704}
705`,
706		targets: []testBazelTarget{
707			{"cc_binary", "foo", AttrNameToString{
708				"local_includes": `["."]`,
709				"suffix": `select({
710        "//build/bazel/platforms/arch:arm": "-32",
711        "//build/bazel/platforms/arch:arm64": "-64",
712        "//conditions:default": None,
713    })`,
714			}},
715		},
716	})
717}
718
719func TestCcBinaryWithSyspropSrcs(t *testing.T) {
720	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
721		description: "cc_binary with sysprop sources",
722		blueprint: `
723{rule_name} {
724	name: "foo",
725	srcs: [
726		"bar.sysprop",
727		"baz.sysprop",
728		"blah.cpp",
729	],
730	min_sdk_version: "5",
731}`,
732		targets: []testBazelTarget{
733			{"sysprop_library", "foo_sysprop_library", AttrNameToString{
734				"srcs": `[
735        "bar.sysprop",
736        "baz.sysprop",
737    ]`,
738			}},
739			{"cc_sysprop_library_static", "foo_cc_sysprop_library_static", AttrNameToString{
740				"dep":             `":foo_sysprop_library"`,
741				"min_sdk_version": `"5"`,
742			}},
743			{"cc_binary", "foo", AttrNameToString{
744				"srcs":               `["blah.cpp"]`,
745				"local_includes":     `["."]`,
746				"min_sdk_version":    `"5"`,
747				"whole_archive_deps": `[":foo_cc_sysprop_library_static"]`,
748			}},
749		},
750	})
751}
752
753func TestCcBinaryWithSyspropSrcsSomeConfigs(t *testing.T) {
754	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
755		description: "cc_binary with sysprop sources in some configs but not others",
756		blueprint: `
757{rule_name} {
758	name: "foo",
759	srcs: [
760		"blah.cpp",
761	],
762	target: {
763		android: {
764			srcs: ["bar.sysprop"],
765		},
766	},
767	min_sdk_version: "5",
768}`,
769		targets: []testBazelTarget{
770			{"sysprop_library", "foo_sysprop_library", AttrNameToString{
771				"srcs": `select({
772        "//build/bazel/platforms/os:android": ["bar.sysprop"],
773        "//conditions:default": [],
774    })`,
775			}},
776			{"cc_sysprop_library_static", "foo_cc_sysprop_library_static", AttrNameToString{
777				"dep":             `":foo_sysprop_library"`,
778				"min_sdk_version": `"5"`,
779			}},
780			{"cc_binary", "foo", AttrNameToString{
781				"srcs":            `["blah.cpp"]`,
782				"local_includes":  `["."]`,
783				"min_sdk_version": `"5"`,
784				"whole_archive_deps": `select({
785        "//build/bazel/platforms/os:android": [":foo_cc_sysprop_library_static"],
786        "//conditions:default": [],
787    })`,
788			}},
789		},
790	})
791}
792
793func TestCcBinaryWithIntegerOverflowProperty(t *testing.T) {
794	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
795		description: "cc_binary with integer overflow property specified",
796		blueprint: `
797{rule_name} {
798	name: "foo",
799	sanitize: {
800		integer_overflow: true,
801	},
802}`,
803		targets: []testBazelTarget{
804			{"cc_binary", "foo", AttrNameToString{
805				"local_includes": `["."]`,
806				"features":       `["ubsan_integer_overflow"]`,
807			}},
808		},
809	})
810}
811
812func TestCcBinaryWithMiscUndefinedProperty(t *testing.T) {
813	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
814		description: "cc_binary with miscellaneous properties specified",
815		blueprint: `
816{rule_name} {
817	name: "foo",
818	sanitize: {
819		misc_undefined: ["undefined", "nullability"],
820	},
821}`,
822		targets: []testBazelTarget{
823			{"cc_binary", "foo", AttrNameToString{
824				"local_includes": `["."]`,
825				"features": `[
826        "ubsan_undefined",
827        "ubsan_nullability",
828    ]`,
829			}},
830		},
831	})
832}
833
834func TestCcBinaryWithUBSanPropertiesArchSpecific(t *testing.T) {
835	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
836		description: "cc_binary has correct feature select when UBSan props are specified in arch specific blocks",
837		blueprint: `
838{rule_name} {
839	name: "foo",
840	sanitize: {
841		misc_undefined: ["undefined", "nullability"],
842	},
843	target: {
844			android: {
845					sanitize: {
846							misc_undefined: ["alignment"],
847					},
848			},
849			linux_glibc: {
850					sanitize: {
851							integer_overflow: true,
852					},
853			},
854	},
855}`,
856		targets: []testBazelTarget{
857			{"cc_binary", "foo", AttrNameToString{
858				"local_includes": `["."]`,
859				"features": `[
860        "ubsan_undefined",
861        "ubsan_nullability",
862    ] + select({
863        "//build/bazel/platforms/os:android": ["ubsan_alignment"],
864        "//build/bazel/platforms/os:linux_glibc": ["ubsan_integer_overflow"],
865        "//conditions:default": [],
866    })`,
867			}},
868		},
869	})
870}
871
872func TestCcBinaryWithThinLto(t *testing.T) {
873	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
874		description: "cc_binary has correct features when thin LTO is enabled",
875		blueprint: `
876{rule_name} {
877	name: "foo",
878	lto: {
879		thin: true,
880	},
881}`,
882		targets: []testBazelTarget{
883			{"cc_binary", "foo", AttrNameToString{
884				"local_includes": `["."]`,
885				"features":       `["android_thin_lto"]`,
886			}},
887		},
888	})
889}
890
891func TestCcBinaryWithLtoNever(t *testing.T) {
892	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
893		description: "cc_binary has correct features when LTO is explicitly disabled",
894		blueprint: `
895{rule_name} {
896	name: "foo",
897	lto: {
898		never: true,
899	},
900}`,
901		targets: []testBazelTarget{
902			{"cc_binary", "foo", AttrNameToString{
903				"local_includes": `["."]`,
904				"features":       `["-android_thin_lto"]`,
905			}},
906		},
907	})
908}
909
910func TestCcBinaryWithThinLtoArchSpecific(t *testing.T) {
911	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
912		description: "cc_binary has correct features when LTO differs across arch and os variants",
913		blueprint: `
914{rule_name} {
915	name: "foo",
916	target: {
917		android: {
918			lto: {
919				thin: true,
920			},
921		},
922	},
923	arch: {
924		riscv64: {
925			lto: {
926				thin: false,
927			},
928		},
929	},
930}`,
931		targets: []testBazelTarget{
932			{"cc_binary", "foo", AttrNameToString{
933				"local_includes": `["."]`,
934				"features": `select({
935        "//build/bazel/platforms/os_arch:android_arm": ["android_thin_lto"],
936        "//build/bazel/platforms/os_arch:android_arm64": ["android_thin_lto"],
937        "//build/bazel/platforms/os_arch:android_riscv64": ["-android_thin_lto"],
938        "//build/bazel/platforms/os_arch:android_x86": ["android_thin_lto"],
939        "//build/bazel/platforms/os_arch:android_x86_64": ["android_thin_lto"],
940        "//conditions:default": [],
941    })`,
942			}},
943		},
944	})
945}
946
947func TestCcBinaryWithThinLtoDisabledDefaultEnabledVariant(t *testing.T) {
948	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
949		description: "cc_binary has correct features when LTO disabled by default but enabled on a particular variant",
950		blueprint: `
951{rule_name} {
952	name: "foo",
953	lto: {
954		never: true,
955	},
956	target: {
957		android: {
958			lto: {
959				thin: true,
960				never: false,
961			},
962		},
963	},
964}`,
965		targets: []testBazelTarget{
966			{"cc_binary", "foo", AttrNameToString{
967				"local_includes": `["."]`,
968				"features": `select({
969        "//build/bazel/platforms/os:android": ["android_thin_lto"],
970        "//conditions:default": ["-android_thin_lto"],
971    })`,
972			}},
973		},
974	})
975}
976
977func TestCcBinaryWithThinLtoAndWholeProgramVtables(t *testing.T) {
978	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
979		description: "cc_binary has correct features when thin LTO is enabled with whole_program_vtables",
980		blueprint: `
981{rule_name} {
982	name: "foo",
983	lto: {
984		thin: true,
985	},
986	whole_program_vtables: true,
987}`,
988		targets: []testBazelTarget{
989			{"cc_binary", "foo", AttrNameToString{
990				"local_includes": `["."]`,
991				"features": `[
992        "android_thin_lto",
993        "android_thin_lto_whole_program_vtables",
994    ]`,
995			}},
996		},
997	})
998}
999