1# Copyright (C) 2022 The Android Open Source Project
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
15load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
16load("//build/bazel/rules/cc:cc_library_shared.bzl", "cc_library_shared")
17load("//build/bazel/rules/cc:cc_library_static.bzl", "cc_library_static")
18load("//build/bazel/rules/cc:cc_stub_library.bzl", "cc_stub_suite")
19load(
20    "//build/bazel/rules/cc/testing:transitions.bzl",
21    "ActionArgsInfo",
22    "compile_action_argv_aspect_generator",
23)
24load("//build/bazel/rules/fdo:fdo_profile.bzl", "fdo_profile")
25load("//build/bazel/rules/test_common:flags.bzl", "action_flags_present_only_for_mnemonic_test")
26load("//build/bazel/rules/test_common:paths.bzl", "get_output_and_package_dir_based_path", "get_package_dir_based_path")
27load(":cc_binary_test.bzl", "cc_bad_linkopts_test")
28load(":cc_library_common_test.bzl", "target_provides_androidmk_info_test")
29
30def _cc_library_shared_suffix_test_impl(ctx):
31    env = analysistest.begin(ctx)
32    target = analysistest.target_under_test(env)
33    info = target[DefaultInfo]
34
35    # NB: There may be more than 1 output file (if e.g. including a TOC)
36    outputs = [so for so in info.files.to_list() if so.path.endswith(".so")]
37    asserts.true(
38        env,
39        len(outputs) == 1,
40        "Expected only 1 output file; got %s" % outputs,
41    )
42    out = outputs[0]
43    asserts.equals(
44        env,
45        ctx.attr.expected_output_filename_with_ext,
46        out.basename,
47        "Expected output filename to be `%s`; it was instead %s" % (ctx.attr.expected_output_filename_with_ext, out.basename),
48    )
49
50    return analysistest.end(env)
51
52cc_library_shared_suffix_test = analysistest.make(
53    _cc_library_shared_suffix_test_impl,
54    attrs = {
55        "expected_output_filename_with_ext": attr.string(),
56    },
57)
58
59def _cc_library_shared_suffix():
60    name = "cc_library_shared_suffix"
61    test_name = name + "_test"
62    suffix = "-suf"
63
64    cc_library_shared(
65        name,
66        srcs = ["foo.cc"],
67        tags = ["manual"],
68        suffix = suffix,
69    )
70    cc_library_shared_suffix_test(
71        name = test_name,
72        target_under_test = name,
73        expected_output_filename_with_ext = name + suffix + ".so",
74    )
75    return test_name
76
77def _cc_library_shared_empty_suffix():
78    name = "cc_library_shared_empty_suffix"
79    test_name = name + "_test"
80
81    cc_library_shared(
82        name,
83        srcs = ["foo.cc"],
84        tags = ["manual"],
85    )
86    cc_library_shared_suffix_test(
87        name = test_name,
88        target_under_test = name,
89        expected_output_filename_with_ext = name + ".so",
90    )
91    return test_name
92
93def _cc_library_with_stem():
94    name = "cc_library_with_stem"
95    test_name = name + "_test"
96
97    cc_library_shared(
98        name,
99        srcs = ["foo.cc"],
100        stem = "bar",
101        tags = ["manual"],
102    )
103    cc_library_shared_suffix_test(
104        name = test_name,
105        target_under_test = name,
106        expected_output_filename_with_ext = "bar.so",
107    )
108    return test_name
109
110def _cc_library_shared_propagating_compilation_context_test_impl(ctx):
111    env = analysistest.begin(ctx)
112    target = analysistest.target_under_test(env)
113    cc_info = target[CcInfo]
114    compilation_context = cc_info.compilation_context
115
116    header_paths = [f.short_path for f in compilation_context.headers.to_list()]
117    for hdr in ctx.files.expected_hdrs:
118        asserts.true(
119            env,
120            hdr.short_path in header_paths,
121            "Did not find {hdr} in includes: {hdrs}.".format(hdr = hdr, hdrs = compilation_context.headers),
122        )
123
124    for hdr in ctx.files.expected_absent_hdrs:
125        asserts.true(
126            env,
127            hdr not in header_paths,
128            "Found {hdr} in includes: {hdrs}, should not be present.".format(hdr = hdr, hdrs = compilation_context.headers),
129        )
130
131    for include in ctx.attr.expected_includes:
132        absolute_include = get_package_dir_based_path(env, include)
133        asserts.true(
134            env,
135            absolute_include in compilation_context.includes.to_list(),
136            "Did not find {include} in includes: {includes}.".format(include = include, includes = compilation_context.includes),
137        )
138
139    for include in ctx.attr.expected_absent_includes:
140        absolute_include = get_package_dir_based_path(env, include)
141        asserts.true(
142            env,
143            absolute_include not in compilation_context.includes.to_list(),
144            "Found {include} in includes: {includes}, was expected to be absent".format(include = include, includes = compilation_context.includes),
145        )
146
147    for include in ctx.attr.expected_system_includes:
148        absolute_include = get_package_dir_based_path(env, include)
149        asserts.true(
150            env,
151            absolute_include in compilation_context.system_includes.to_list(),
152            "Did not find {include} in system includes: {includes}.".format(include = include, includes = compilation_context.system_includes),
153        )
154
155    for include in ctx.attr.expected_absent_system_includes:
156        absolute_include = get_package_dir_based_path(env, include)
157        asserts.true(
158            env,
159            absolute_include not in compilation_context.system_includes.to_list(),
160            "Found {include} in system includes: {includes}, was expected to be absent".format(include = include, includes = compilation_context.system_includes),
161        )
162
163    return analysistest.end(env)
164
165_cc_library_shared_propagating_compilation_context_test = analysistest.make(
166    _cc_library_shared_propagating_compilation_context_test_impl,
167    attrs = {
168        "expected_hdrs": attr.label_list(),
169        "expected_absent_hdrs": attr.label_list(),
170        "expected_includes": attr.string_list(),
171        "expected_absent_includes": attr.string_list(),
172        "expected_system_includes": attr.string_list(),
173        "expected_absent_system_includes": attr.string_list(),
174    },
175)
176
177def _cc_library_shared_propagates_deps():
178    name = "_cc_library_shared_propagates_deps"
179    dep_name = name + "_dep"
180    test_name = name + "_test"
181
182    cc_library_static(
183        name = dep_name,
184        hdrs = [":cc_library_shared_hdr"],
185        export_includes = ["a/b/c"],
186        export_system_includes = ["d/e/f"],
187        tags = ["manual"],
188    )
189
190    cc_library_shared(
191        name = name,
192        deps = [dep_name],
193        tags = ["manual"],
194    )
195
196    _cc_library_shared_propagating_compilation_context_test(
197        name = test_name,
198        target_under_test = name,
199        expected_hdrs = [":cc_library_shared_hdr"],
200        expected_includes = ["a/b/c"],
201        expected_system_includes = ["d/e/f"],
202    )
203
204    return test_name
205
206def _cc_library_shared_propagates_whole_archive_deps():
207    name = "_cc_library_shared_propagates_whole_archive_deps"
208    dep_name = name + "_dep"
209    test_name = name + "_test"
210
211    cc_library_static(
212        name = dep_name,
213        hdrs = [":cc_library_shared_hdr"],
214        export_includes = ["a/b/c"],
215        export_system_includes = ["d/e/f"],
216        tags = ["manual"],
217    )
218
219    cc_library_shared(
220        name = name,
221        whole_archive_deps = [dep_name],
222        tags = ["manual"],
223    )
224
225    _cc_library_shared_propagating_compilation_context_test(
226        name = test_name,
227        target_under_test = name,
228        expected_hdrs = [":cc_library_shared_hdr"],
229        expected_includes = ["a/b/c"],
230        expected_system_includes = ["d/e/f"],
231    )
232
233    return test_name
234
235def _cc_library_shared_propagates_dynamic_deps():
236    name = "_cc_library_shared_propagates_dynamic_deps"
237    dep_name = name + "_dep"
238    test_name = name + "_test"
239
240    cc_library_shared(
241        name = dep_name,
242        hdrs = [":cc_library_shared_hdr"],
243        export_includes = ["a/b/c"],
244        export_system_includes = ["d/e/f"],
245        tags = ["manual"],
246    )
247
248    cc_library_shared(
249        name = name,
250        dynamic_deps = [dep_name],
251        tags = ["manual"],
252    )
253
254    _cc_library_shared_propagating_compilation_context_test(
255        name = test_name,
256        target_under_test = name,
257        expected_hdrs = [":cc_library_shared_hdr"],
258        expected_includes = ["a/b/c"],
259        expected_system_includes = ["d/e/f"],
260    )
261
262    return test_name
263
264def _cc_library_shared_does_not_propagate_implementation_deps():
265    name = "_cc_library_shared_does_not_propagate_implementation_deps"
266    dep_name = name + "_dep"
267    test_name = name + "_test"
268
269    cc_library_static(
270        name = dep_name,
271        hdrs = [":cc_library_shared_hdr"],
272        export_includes = ["a/b/c"],
273        export_system_includes = ["d/e/f"],
274        tags = ["manual"],
275    )
276
277    cc_library_shared(
278        name = name,
279        implementation_deps = [dep_name],
280        tags = ["manual"],
281    )
282
283    _cc_library_shared_propagating_compilation_context_test(
284        name = test_name,
285        target_under_test = name,
286        expected_absent_hdrs = [":cc_library_shared_hdr"],
287        expected_absent_includes = ["a/b/c"],
288        expected_absent_system_includes = ["d/e/f"],
289    )
290
291    return test_name
292
293def _cc_library_shared_does_not_propagate_implementation_whole_archive_deps():
294    name = "_cc_library_shared_does_not_propagate_implementation_whole_archive_deps"
295    dep_name = name + "_dep"
296    test_name = name + "_test"
297
298    cc_library_static(
299        name = dep_name,
300        hdrs = [":cc_library_shared_hdr"],
301        export_includes = ["a/b/c"],
302        export_system_includes = ["d/e/f"],
303        tags = ["manual"],
304    )
305
306    cc_library_shared(
307        name = name,
308        implementation_whole_archive_deps = [dep_name],
309        tags = ["manual"],
310    )
311
312    _cc_library_shared_propagating_compilation_context_test(
313        name = test_name,
314        target_under_test = name,
315        expected_absent_hdrs = [":cc_library_shared_hdr"],
316        expected_absent_includes = ["a/b/c"],
317        expected_absent_system_includes = ["d/e/f"],
318    )
319
320    return test_name
321
322def _cc_library_shared_does_not_propagate_implementation_dynamic_deps():
323    name = "_cc_library_shared_does_not_propagate_implementation_dynamic_deps"
324    dep_name = name + "_dep"
325    test_name = name + "_test"
326
327    cc_library_shared(
328        name = dep_name,
329        hdrs = [":cc_library_shared_hdr"],
330        export_includes = ["a/b/c"],
331        export_system_includes = ["d/e/f"],
332        tags = ["manual"],
333    )
334
335    cc_library_shared(
336        name = name,
337        implementation_dynamic_deps = [dep_name],
338        tags = ["manual"],
339    )
340
341    _cc_library_shared_propagating_compilation_context_test(
342        name = test_name,
343        target_under_test = name,
344        expected_absent_hdrs = [":cc_library_shared_hdr"],
345        expected_absent_includes = ["a/b/c"],
346        expected_absent_system_includes = ["d/e/f"],
347    )
348
349    return test_name
350
351def _cc_library_shared_propagating_fdo_profile_test_impl(ctx):
352    env = analysistest.begin(ctx)
353    target_under_test = analysistest.target_under_test(env)
354    argv_map = target_under_test[ActionArgsInfo].argv_map
355
356    for label in ctx.attr.deps_labels_to_check_fdo_profile:
357        asserts.true(
358            env,
359            label in argv_map,
360            "can't find {} in argv map".format(label),
361        )
362        argv = argv_map[label]
363        asserts.true(
364            env,
365            _has_fdo_profile(argv, ctx.attr.fdo_profile),
366            "can't find {} in compile action of {}".format(
367                ctx.attr.fdo_profile,
368                label,
369            ),
370        )
371    for label in ctx.attr.deps_labels_to_check_no_fdo_profile:
372        asserts.true(
373            env,
374            label in argv_map,
375            "can't find {} in argv_map".format(label),
376        )
377        argv = argv_map[label]
378        asserts.true(
379            env,
380            not _has_fdo_profile(argv, ctx.attr.fdo_profile),
381            "{} should not have {} in compile action".format(
382                ctx.attr.fdo_profile,
383                label,
384            ),
385        )
386
387    return analysistest.end(env)
388
389_compile_action_argv_aspect = compile_action_argv_aspect_generator({
390    "_cc_library_combiner": ["deps", "roots", "includes"],
391    "_cc_includes": ["deps"],
392    "_cc_library_shared_proxy": ["deps"],
393})
394
395cc_library_shared_propagating_fdo_profile_test = analysistest.make(
396    _cc_library_shared_propagating_fdo_profile_test_impl,
397    attrs = {
398        # FdoProfileInfo isn't exposed to Starlark so we need to test against
399        # the path basename directly
400        "fdo_profile": attr.string(),
401        # This has to be a string_list() instead of label_list(). If the deps
402        # are given as labels, the deps are analyzed because transition is attached
403        "deps_labels_to_check_fdo_profile": attr.string_list(),
404        "deps_labels_to_check_no_fdo_profile": attr.string_list(),
405    },
406    # We need to use aspect to examine the dependencies' actions of the apex
407    # target as the result of the transition, checking the dependencies directly
408    # using names will give you the info before the transition takes effect.
409    extra_target_under_test_aspects = [_compile_action_argv_aspect],
410)
411
412# _has_fdo_profile checks whether afdo-specific flag is present in actions.argv
413def _has_fdo_profile(argv, fdo_profile_name):
414    for arg in argv:
415        if "-fprofile-sample-use=" in arg and fdo_profile_name in arg:
416            return True
417
418    return False
419
420def _cc_libary_shared_propagate_fdo_profile_to_whole_archive_deps():
421    name = "_cc_libary_shared_propagate_fdo_profile_to_whole_archive_deps"
422    fdo_profile_name = name + "_fdo_profile"
423    dep_name = name + "_dep"
424    transitive_dep_name = name + "_transitive_dep"
425    unexported_dep_name = name + "_exported_dep"
426    transitive_unexported_dep_name = name + "_transitive_unexported_dep"
427    test_name = name + "_test"
428
429    native.genrule(
430        name = "{}.afdo".format(fdo_profile_name),
431        outs = ["{}.afdo".format(fdo_profile_name)],
432        cmd = "touch $(OUTS)",
433    )
434
435    fdo_profile(
436        name = fdo_profile_name,
437        profile = ":" + fdo_profile_name + ".afdo",
438    )
439
440    cc_library_static(
441        name = transitive_dep_name,
442        srcs = ["foo.cpp"],
443        tags = ["manual"],
444    )
445    cc_library_static(
446        name = transitive_unexported_dep_name,
447        srcs = ["foo.cpp"],
448        tags = ["manual"],
449    )
450    cc_library_static(
451        name = dep_name,
452        whole_archive_deps = [transitive_dep_name],
453        implementation_whole_archive_deps = [transitive_unexported_dep_name],
454        srcs = ["foo.cpp", "bar.cpp"],
455        tags = ["manual"],
456    )
457    cc_library_static(
458        name = unexported_dep_name,
459        srcs = ["foo.cpp"],
460        tags = ["manual"],
461    )
462
463    cc_library_shared(
464        name = name,
465        whole_archive_deps = [dep_name],
466        implementation_whole_archive_deps = [unexported_dep_name],
467        fdo_profile = ":" + fdo_profile_name,
468        tags = ["manual"],
469    )
470
471    cc_library_shared_propagating_fdo_profile_test(
472        name = test_name,
473        target_under_test = name,
474        deps_labels_to_check_fdo_profile = [
475            dep_name + "_cpp",
476            transitive_dep_name + "_cpp",
477            unexported_dep_name + "_cpp",
478            transitive_unexported_dep_name + "_cpp",
479        ],
480        fdo_profile = fdo_profile_name,
481    )
482
483    return test_name
484
485def _cc_library_shared_does_not_propagate_fdo_profile_to_dynamic_deps():
486    name = "_cc_library_shared_does_not_propagate_fdo_profile_to_dynamic_deps"
487    fdo_profile_name = name + "_fdo_profile"
488    dep_name = name + "_dep"
489    transitive_shared_dep_name = name + "_transitive_shared_dep"
490    unexported_transitive_shared_dep_name = name + "_unexported_transitive_shared_dep"
491    test_name = name + "_test"
492
493    cc_library_shared(
494        name = transitive_shared_dep_name,
495        srcs = ["foo.cpp"],
496        tags = ["manual"],
497    )
498    cc_library_shared(
499        name = unexported_transitive_shared_dep_name,
500        srcs = ["foo.cpp"],
501        tags = ["manual"],
502    )
503    cc_library_static(
504        name = dep_name,
505        srcs = ["foo.cpp"],
506        dynamic_deps = [transitive_shared_dep_name],
507        implementation_dynamic_deps = [unexported_transitive_shared_dep_name],
508        tags = ["manual"],
509    )
510    native.genrule(
511        name = "{}.afdo".format(fdo_profile_name),
512        outs = ["{}.afdo".format(fdo_profile_name)],
513        cmd = "touch $(OUTS)",
514    )
515    fdo_profile(
516        name = fdo_profile_name,
517        profile = fdo_profile_name + ".afdo",
518    )
519    cc_library_shared(
520        name = name,
521        whole_archive_deps = [dep_name],
522        fdo_profile = fdo_profile_name,
523        stl = "",
524        tags = ["manual"],
525    )
526
527    cc_library_shared_propagating_fdo_profile_test(
528        name = test_name,
529        target_under_test = name,
530        deps_labels_to_check_fdo_profile = [
531            dep_name + "_cpp",
532        ],
533        # make sure dynamic deps don't build with afdo profiles from rdeps
534        deps_labels_to_check_no_fdo_profile = [
535            transitive_shared_dep_name + "__internal_root_cpp",
536            unexported_transitive_shared_dep_name + "__internal_root_cpp",
537        ],
538        fdo_profile = fdo_profile_name,
539    )
540
541    return test_name
542
543def _fdo_profile_transition_correctly_set_and_unset_fdo_profile():
544    name = "_fdo_profile_transition_set_and_unset_fdo_profile_correctly"
545    fdo_profile_name = name + "_fdo_profile"
546    dep_with_fdo_profile = name + "_dep_with_fdo_profile"
547    transitive_dep_without_fdo_profile = name + "_transitive_dep_without_fdo_profile"
548    test_name = name + "_test"
549
550    native.genrule(
551        name = "{}.afdo".format(fdo_profile_name),
552        outs = ["{}.afdo".format(fdo_profile_name)],
553        cmd = "touch $(OUTS)",
554    )
555    fdo_profile(
556        name = fdo_profile_name,
557        profile = fdo_profile_name + ".afdo",
558    )
559
560    cc_library_shared(
561        name = name,
562        srcs = ["foo.cpp"],
563        tags = ["manual"],
564        dynamic_deps = [dep_with_fdo_profile],
565    )
566
567    cc_library_shared(
568        name = dep_with_fdo_profile,
569        fdo_profile = fdo_profile_name,
570        srcs = ["foo.cpp"],
571        tags = ["manual"],
572        dynamic_deps = [transitive_dep_without_fdo_profile],
573    )
574
575    cc_library_shared(
576        name = transitive_dep_without_fdo_profile,
577        srcs = ["foo.cpp"],
578        tags = ["manual"],
579    )
580
581    cc_library_shared_propagating_fdo_profile_test(
582        name = test_name,
583        target_under_test = name,
584        deps_labels_to_check_fdo_profile = [
585            dep_with_fdo_profile + "__internal_root_cpp",
586        ],
587        # make sure dynamic deps don't build with afdo profiles from rdeps
588        deps_labels_to_check_no_fdo_profile = [
589            name + "__internal_root_cpp",
590            transitive_dep_without_fdo_profile + "__internal_root_cpp",
591        ],
592        fdo_profile = fdo_profile_name,
593    )
594
595    return test_name
596
597def _cc_library_link_flags_test_impl(ctx):
598    env = analysistest.begin(ctx)
599    target = analysistest.target_under_test(env)
600
601    for action in target.actions:
602        if action.mnemonic == "CppLink":
603            for flag in ctx.attr.expected_link_flags:
604                if flag not in action.argv:
605                    fail("{} is not in list of flags for linking {}".format(flag, action.argv))
606
607    return analysistest.end(env)
608
609cc_library_link_flags_test = analysistest.make(
610    _cc_library_link_flags_test_impl,
611    attrs = {
612        "expected_link_flags": attr.string_list(),
613    },
614)
615
616def _cc_library_with_fdo_profile_link_flags():
617    name = "_cc_library_with_fdo_profile_link_flags"
618    test_name = name + "_test"
619    cc_library_shared(
620        name = name,
621        fdo_profile = name + "_fdo_profile",
622        tags = ["manual"],
623    )
624    cc_library_link_flags_test(
625        name = test_name,
626        target_under_test = name + "_unstripped",
627        expected_link_flags = [
628            "-funique-internal-linkage-names",
629            "-fprofile-sample-accurate",
630            "-fprofile-sample-use=build/bazel/rules/cc/_cc_library_with_fdo_profile_link_flags_fdo_profile_file",
631            "-Wl,-mllvm,-no-warn-sample-unused=true",
632        ],
633    )
634    return test_name
635
636def _cc_library_disable_fdo_optimization_if_coverage_is_enabled_impl(ctx):
637    env = analysistest.begin(ctx)
638    target = analysistest.target_under_test(env)
639
640    for action in target.actions:
641        if action.mnemonic == "CppCompile":
642            for arg in action.argv:
643                if "-fprofile-sample-use" in arg:
644                    fail("fdo optimization can not be enabled when coverage is enabled")
645
646    return analysistest.end(env)
647
648cc_library_disable_fdo_optimization_if_coverage_is_enabled_test = analysistest.make(
649    _cc_library_disable_fdo_optimization_if_coverage_is_enabled_impl,
650    config_settings = {
651        "//command_line_option:collect_code_coverage": True,
652    },
653)
654
655def _cc_library_disable_fdo_optimization_if_coverage_is_enabled_test():
656    name = "_cc_library_disable_fdo_optimization_if_coverage_is_enabled_test"
657    test_name = name + "_test"
658    cc_library_shared(
659        name = name,
660        fdo_profile = name + "_fdo_profile",
661        srcs = ["foo.cpp"],
662        # Coverage will add an extra lib to all the shared libs, we try to avoid
663        # that by clearing the system_dynamic_deps and stl.
664        system_dynamic_deps = [],
665        stl = "none",
666        tags = ["manual"],
667    )
668    cc_library_disable_fdo_optimization_if_coverage_is_enabled_test(
669        name = test_name,
670        target_under_test = name + "__internal_root_cpp",
671    )
672    return test_name
673
674def _cc_library_set_defines_for_stubs():
675    name = "cc_library_set_defines_for_stubs"
676    test_name = name + "_test"
677
678    cc_library_shared(
679        name = name + "_libfoo",
680        system_dynamic_deps = [],
681        stl = "none",
682        tags = ["manual"],
683        stubs_symbol_file = name + "_libfoo.map.txt",
684    )
685
686    cc_stub_suite(
687        name = name + "_libfoo_stub_libs",
688        soname = name + "_libfoo.so",
689        source_library_label = ":" + name + "_libfoo",
690        symbol_file = name + "_libfoo.map.txt",
691        versions = ["30", "40"],
692    )
693
694    cc_library_shared(
695        name = name + "_libbar",
696        system_dynamic_deps = [],
697        stl = "none",
698        tags = ["manual"],
699        stubs_symbol_file = name + "_libbar.map.txt",
700    )
701
702    cc_stub_suite(
703        name = name + "_libbar_stub_libs",
704        soname = name + "_libbar.so",
705        source_library_label = ":" + name + "_libbar",
706        symbol_file = name + "_libbar.map.txt",
707        versions = ["current"],
708    )
709
710    cc_library_shared(
711        name = name + "_libbaz",
712        system_dynamic_deps = [],
713        stl = "none",
714        tags = ["manual"],
715        stubs_symbol_file = name + "_libbaz.map.txt",
716    )
717
718    cc_stub_suite(
719        name = name + "_libbaz_stub_libs",
720        soname = name + "_libbaz.so",
721        source_library_label = ":" + name + "_libbaz",
722        symbol_file = name + "_libbaz.map.txt",
723        versions = ["30"],
724    )
725
726    cc_library_shared(
727        name = name + "_lib_with_stub_deps",
728        srcs = ["foo.cpp"],
729        implementation_dynamic_deps = [
730            name + "_libfoo_stub_libs_current",
731            name + "_libbar_stub_libs_current",
732            name + "_libbaz_stub_libs-30",  # depend on an old version explicitly
733        ],
734        tags = ["manual"],
735    )
736
737    action_flags_present_only_for_mnemonic_test(
738        name = test_name,
739        target_under_test = name + "_lib_with_stub_deps__internal_root_cpp",
740        mnemonics = ["CppCompile"],
741        expected_flags = [
742            "-D__CC_LIBRARY_SET_DEFINES_FOR_STUBS_LIBFOO_API__=10000",
743            "-D__CC_LIBRARY_SET_DEFINES_FOR_STUBS_LIBBAR_API__=10000",
744            "-D__CC_LIBRARY_SET_DEFINES_FOR_STUBS_LIBBAZ_API__=30",
745        ],
746    )
747    return test_name
748
749def _cc_library_shared_provides_androidmk_info():
750    name = "cc_library_shared_provides_androidmk_info"
751    dep_name = name + "_static_dep"
752    whole_archive_dep_name = name + "_whole_archive_dep"
753    dynamic_dep_name = name + "_dynamic_dep"
754    test_name = name + "_test"
755
756    cc_library_static(
757        name = dep_name,
758        srcs = ["foo.c"],
759        tags = ["manual"],
760    )
761    cc_library_static(
762        name = whole_archive_dep_name,
763        srcs = ["foo.c"],
764        tags = ["manual"],
765    )
766    cc_library_shared(
767        name = dynamic_dep_name,
768        srcs = ["foo.c"],
769        tags = ["manual"],
770    )
771    cc_library_shared(
772        name = name,
773        srcs = ["foo.cc"],
774        deps = [dep_name],
775        whole_archive_deps = [whole_archive_dep_name],
776        dynamic_deps = [dynamic_dep_name],
777        tags = ["manual"],
778    )
779    android_test_name = test_name + "_android"
780    linux_test_name = test_name + "_linux"
781    target_provides_androidmk_info_test(
782        name = android_test_name,
783        target_under_test = name,
784        expected_static_libs = [dep_name, "libc++demangle"],
785        expected_whole_static_libs = [whole_archive_dep_name],
786        expected_shared_libs = [dynamic_dep_name, "libc++", "libc_stub_libs-current", "libdl_stub_libs-current", "libm_stub_libs-current"],
787        target_compatible_with = ["//build/bazel_common_rules/platforms/os:android"],
788    )
789    target_provides_androidmk_info_test(
790        name = linux_test_name,
791        target_under_test = name,
792        expected_static_libs = [dep_name],
793        expected_whole_static_libs = [whole_archive_dep_name],
794        expected_shared_libs = [dynamic_dep_name, "libc++"],
795        target_compatible_with = ["//build/bazel_common_rules/platforms/os:linux"],
796    )
797    return [
798        android_test_name,
799        linux_test_name,
800    ]
801
802def _cc_library_minimal_runtime_linked_impl(ctx):
803    env = analysistest.begin(ctx)
804    libraries = [
805        lib
806        for input in ctx.attr._ubsan_library[CcInfo].linking_context.linker_inputs.to_list()
807        for lib in input.libraries
808    ]
809    ubsan_lib_path = libraries[0].static_library.path
810
811    actions = analysistest.target_actions(env)
812    found_minimal_runtime = False
813    for action in actions:
814        if action.mnemonic != "CppLink":
815            continue
816        for i in range(len(action.argv)):
817            arg = action.argv[i]
818            if ubsan_lib_path in arg:
819                found_minimal_runtime = True
820                if i > 0:
821                    prev_arg = action.argv[i - 1]
822                asserts.true(
823                    env,
824                    "-Wl,--whole-archive" != prev_arg,
825                    "expected %s to not be a whole archive but it was" % [prev_arg, arg],
826                )
827
828    asserts.true(
829        env,
830        found_minimal_runtime,
831        "Expected to find ubsan minimal runtime, but did not.",
832    )
833
834    return analysistest.end(env)
835
836_cc_library_minimal_runtime_linked_test = analysistest.make(
837    _cc_library_minimal_runtime_linked_impl,
838    attrs = {
839        "_ubsan_library": attr.label(
840            default = "//prebuilts/clang/host/linux-x86:libclang_rt.ubsan_minimal",
841            doc = "The library target corresponding to the undefined " +
842                  "behavior sanitizer library to be used",
843        ),
844    },
845)
846
847def _cc_library_minimal_runtime_linked_from_dep():
848    name = "cc_library_minimal_runtime_linked_from_dep"
849    dep_name = "dep_" + name
850    test_name = name + "_test"
851
852    cc_library_static(
853        name = dep_name,
854        srcs = ["foo.cc"],
855        tags = ["manual"],
856        features = ["ubsan_undefined"],
857    )
858    cc_library_shared(
859        name = name,
860        srcs = ["bar.cc"],
861        implementation_deps = [dep_name],
862        tags = ["manual"],
863    )
864    _cc_library_minimal_runtime_linked_test(
865        name = test_name,
866        target_under_test = name + "_unstripped",
867    )
868    return test_name
869
870def _cc_library_minimal_runtime_linked():
871    name = "cc_library_minimal_runtime_linked"
872    test_name = name + "_test"
873
874    cc_library_shared(
875        name = name,
876        srcs = ["bar.cc"],
877        features = ["ubsan_undefined"],
878        tags = ["manual"],
879    )
880    _cc_library_minimal_runtime_linked_test(
881        name = test_name,
882        target_under_test = name + "_unstripped",
883    )
884    return test_name
885
886def _cc_library_link_as_whole_archive_test_impl(ctx):
887    env = analysistest.begin(ctx)
888    actions = [a for a in analysistest.target_actions(env) if a.mnemonic == "CppLink"]
889    asserts.true(
890        env,
891        len(actions) == 1,
892        "Cpp link action not found: %s" % actions,
893    )
894    action = actions[0]
895    whole_arch_libs = []
896    argv_len = len(action.argv)
897    whole_archive_start = False
898    for i in range(argv_len):
899        if action.argv[i] == "-Wl,--whole-archive":
900            whole_archive_start = True
901        elif action.argv[i] == "-Wl,--no-whole-archive":
902            whole_archive_start = False
903        elif whole_archive_start:
904            whole_arch_libs.append(action.argv[i])
905
906    for lib in ctx.attr.expected_libs:
907        full_path = get_output_and_package_dir_based_path(env, lib)
908        if full_path not in whole_arch_libs:
909            fail("{} is not in list of libs for linking as whole archive deps {}".format(lib, action.argv))
910
911    return analysistest.end(env)
912
913cc_library_link_as_whole_archive_test = analysistest.make(
914    _cc_library_link_as_whole_archive_test_impl,
915    attrs = {
916        "expected_libs": attr.string_list(),
917    },
918)
919
920def _cc_library_shared_links_whole_archive_deps_separately():
921    name = "cc_library_shared_links_whole_archive_deps_separately"
922    dep_name = name + "_dep"
923    test_name = name + "_test"
924
925    cc_library_static(
926        name = dep_name,
927        tags = ["manual"],
928    )
929
930    cc_library_shared(
931        name = name,
932        whole_archive_deps = [dep_name],
933        tags = ["manual"],
934    )
935
936    cc_library_link_as_whole_archive_test(
937        name = test_name,
938        target_under_test = name + "_unstripped",
939        expected_libs = ["libcc_library_shared_links_whole_archive_deps_separately_dep.a"],
940    )
941
942    return test_name
943
944# Test that an error is raised if a user requests a library that is not available in the toolchain.
945def _cc_library_shared_bad_linkopts_test():
946    subject_name = "cc_library_shared_bad_linkopts"
947    test_name = subject_name + "_test"
948
949    cc_library_shared(
950        name = subject_name,
951        linkopts = ["-lunknown"],
952        tags = ["manual"],
953    )
954    cc_bad_linkopts_test(
955        name = test_name,
956        target_under_test = subject_name,
957    )
958    return test_name
959
960def cc_library_shared_test_suite(name):
961    native.genrule(name = "cc_library_shared_hdr", cmd = "null", outs = ["cc_shared_f.h"], tags = ["manual"])
962
963    native.test_suite(
964        name = name,
965        tests = [
966            _cc_library_shared_suffix(),
967            _cc_library_shared_empty_suffix(),
968            _cc_library_with_stem(),
969            _cc_library_shared_propagates_deps(),
970            _cc_library_shared_propagates_whole_archive_deps(),
971            _cc_library_shared_propagates_dynamic_deps(),
972            _cc_library_shared_does_not_propagate_implementation_deps(),
973            _cc_library_shared_does_not_propagate_implementation_whole_archive_deps(),
974            _cc_library_shared_does_not_propagate_implementation_dynamic_deps(),
975            _cc_libary_shared_propagate_fdo_profile_to_whole_archive_deps(),
976            _cc_library_shared_does_not_propagate_fdo_profile_to_dynamic_deps(),
977            _fdo_profile_transition_correctly_set_and_unset_fdo_profile(),
978            _cc_library_with_fdo_profile_link_flags(),
979            _cc_library_disable_fdo_optimization_if_coverage_is_enabled_test(),
980            _cc_library_set_defines_for_stubs(),
981            _cc_library_minimal_runtime_linked_from_dep(),
982            _cc_library_minimal_runtime_linked(),
983            _cc_library_shared_links_whole_archive_deps_separately(),
984            _cc_library_shared_bad_linkopts_test(),
985        ] + _cc_library_shared_provides_androidmk_info(),
986    )
987