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:paths.bzl", "paths")
16load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
17load("//build/bazel/rules/cc:cc_binary.bzl", "cc_binary")
18load("//build/bazel/rules/cc:cc_library_headers.bzl", "cc_library_headers")
19load("//build/bazel/rules/cc:cc_library_shared.bzl", "cc_library_shared")
20load("//build/bazel/rules/cc:cc_library_static.bzl", "cc_library_static")
21load("//build/bazel/rules/cc:cc_prebuilt_library_static.bzl", "cc_prebuilt_library_static")
22load(
23    "//build/bazel/rules/test_common:flags.bzl",
24    "action_flags_absent_for_mnemonic_test",
25    "action_flags_present_only_for_mnemonic_test",
26)
27load("//build/bazel/rules/test_common:paths.bzl", "get_output_and_package_dir_based_path", "get_package_dir_based_path")
28load("//build/bazel/rules/test_common:rules.bzl", "expect_failure_test")
29load(":cc_library_common_test.bzl", "target_provides_androidmk_info_test", "target_sdk_variant_provides_androidmk_info_test")
30
31def _cc_library_static_propagating_compilation_context_test_impl(ctx):
32    env = analysistest.begin(ctx)
33    target = analysistest.target_under_test(env)
34    cc_info = target[CcInfo]
35    compilation_context = cc_info.compilation_context
36
37    header_paths = [f.short_path for f in compilation_context.headers.to_list()]
38    for hdr in ctx.files.expected_hdrs:
39        asserts.true(
40            env,
41            hdr.short_path in header_paths,
42            "Did not find {hdr} in includes: {hdrs}.".format(hdr = hdr, hdrs = compilation_context.headers),
43        )
44
45    for hdr in ctx.files.expected_absent_hdrs:
46        asserts.true(
47            env,
48            hdr not in header_paths,
49            "Found {hdr} in includes: {hdrs}, should not be present.".format(hdr = hdr, hdrs = compilation_context.headers),
50        )
51
52    for include in ctx.attr.expected_includes:
53        absolute_include = get_package_dir_based_path(env, include)
54        asserts.true(
55            env,
56            absolute_include in compilation_context.includes.to_list(),
57            "Did not find {include} in includes: {includes}.".format(include = include, includes = compilation_context.includes),
58        )
59
60    for include in ctx.attr.expected_absent_includes:
61        absolute_include = get_package_dir_based_path(env, include)
62        asserts.true(
63            env,
64            absolute_include not in compilation_context.includes.to_list(),
65            "Found {include} in includes: {includes}, was expected to be absent".format(include = include, includes = compilation_context.includes),
66        )
67
68    for include in ctx.attr.expected_system_includes:
69        absolute_include = get_package_dir_based_path(env, include)
70        asserts.true(
71            env,
72            absolute_include in compilation_context.system_includes.to_list(),
73            "Did not find {include} in system includes: {includes}.".format(include = include, includes = compilation_context.system_includes),
74        )
75
76    for include in ctx.attr.expected_absent_system_includes:
77        absolute_include = get_package_dir_based_path(env, include)
78        asserts.true(
79            env,
80            absolute_include not in compilation_context.system_includes.to_list(),
81            "Found {include} in system includes: {includes}, was expected to be absent".format(include = include, includes = compilation_context.system_includes),
82        )
83
84    return analysistest.end(env)
85
86_cc_library_static_propagating_compilation_context_test = analysistest.make(
87    _cc_library_static_propagating_compilation_context_test_impl,
88    attrs = {
89        "expected_hdrs": attr.label_list(),
90        "expected_absent_hdrs": attr.label_list(),
91        "expected_includes": attr.string_list(),
92        "expected_absent_includes": attr.string_list(),
93        "expected_system_includes": attr.string_list(),
94        "expected_absent_system_includes": attr.string_list(),
95    },
96)
97
98def _cc_library_static_propagates_deps():
99    name = "_cc_library_static_propagates_deps"
100    dep_name = name + "_dep"
101    test_name = name + "_test"
102
103    cc_library_static(
104        name = dep_name,
105        hdrs = [":hdr"],
106        export_includes = ["a/b/c"],
107        export_system_includes = ["d/e/f"],
108        tags = ["manual"],
109    )
110
111    cc_library_static(
112        name = name,
113        deps = [dep_name],
114        tags = ["manual"],
115    )
116
117    _cc_library_static_propagating_compilation_context_test(
118        name = test_name,
119        target_under_test = name,
120        expected_hdrs = [":hdr"],
121        expected_includes = ["a/b/c"],
122        expected_system_includes = ["d/e/f"],
123    )
124
125    return test_name
126
127def _cc_library_static_propagates_whole_archive_deps():
128    name = "_cc_library_static_propagates_whole_archive_deps"
129    dep_name = name + "_dep"
130    test_name = name + "_test"
131
132    cc_library_static(
133        name = dep_name,
134        hdrs = [":hdr"],
135        export_includes = ["a/b/c"],
136        export_system_includes = ["d/e/f"],
137        tags = ["manual"],
138    )
139
140    cc_library_static(
141        name = name,
142        whole_archive_deps = [dep_name],
143        tags = ["manual"],
144    )
145
146    _cc_library_static_propagating_compilation_context_test(
147        name = test_name,
148        target_under_test = name,
149        expected_hdrs = [":hdr"],
150        expected_includes = ["a/b/c"],
151        expected_system_includes = ["d/e/f"],
152    )
153
154    return test_name
155
156def _cc_library_static_propagates_dynamic_deps():
157    name = "_cc_library_static_propagates_dynamic_deps"
158    dep_name = name + "_dep"
159    test_name = name + "_test"
160
161    cc_library_shared(
162        name = dep_name,
163        hdrs = [":hdr"],
164        export_includes = ["a/b/c"],
165        export_system_includes = ["d/e/f"],
166        tags = ["manual"],
167    )
168
169    cc_library_static(
170        name = name,
171        dynamic_deps = [dep_name],
172        tags = ["manual"],
173    )
174
175    _cc_library_static_propagating_compilation_context_test(
176        name = test_name,
177        target_under_test = name,
178        expected_hdrs = [":hdr"],
179        expected_includes = ["a/b/c"],
180        expected_system_includes = ["d/e/f"],
181    )
182
183    return test_name
184
185def _cc_library_static_does_not_propagate_implementation_deps():
186    name = "_cc_library_static_does_not_propagate_implementation_deps"
187    dep_name = name + "_dep"
188    test_name = name + "_test"
189
190    cc_library_static(
191        name = dep_name,
192        hdrs = [":hdr"],
193        export_includes = ["a/b/c"],
194        export_system_includes = ["d/e/f"],
195        tags = ["manual"],
196    )
197
198    cc_library_static(
199        name = name,
200        implementation_deps = [dep_name],
201        tags = ["manual"],
202    )
203
204    _cc_library_static_propagating_compilation_context_test(
205        name = test_name,
206        target_under_test = name,
207        expected_absent_hdrs = [":hdr"],
208        expected_absent_includes = ["a/b/c"],
209        expected_absent_system_includes = ["d/e/f"],
210    )
211
212    return test_name
213
214def _cc_library_static_does_not_propagate_implementation_whole_archive_deps():
215    name = "_cc_library_static_does_not_propagate_implementation_whole_archive_deps"
216    dep_name = name + "_dep"
217    test_name = name + "_test"
218
219    cc_library_static(
220        name = dep_name,
221        hdrs = [":hdr"],
222        export_includes = ["a/b/c"],
223        export_system_includes = ["d/e/f"],
224        tags = ["manual"],
225    )
226
227    cc_library_static(
228        name = name,
229        implementation_whole_archive_deps = [dep_name],
230        tags = ["manual"],
231    )
232
233    _cc_library_static_propagating_compilation_context_test(
234        name = test_name,
235        target_under_test = name,
236        expected_absent_hdrs = [":hdr"],
237        expected_absent_includes = ["a/b/c"],
238        expected_absent_system_includes = ["d/e/f"],
239    )
240
241    return test_name
242
243def _cc_library_static_does_not_propagate_implementation_dynamic_deps():
244    name = "_cc_library_static_does_not_propagate_implementation_dynamic_deps"
245    dep_name = name + "_dep"
246    test_name = name + "_test"
247
248    cc_library_shared(
249        name = dep_name,
250        hdrs = [":hdr"],
251        export_includes = ["a/b/c"],
252        export_system_includes = ["d/e/f"],
253        tags = ["manual"],
254    )
255
256    cc_library_static(
257        name = name,
258        implementation_dynamic_deps = [dep_name],
259        tags = ["manual"],
260    )
261
262    _cc_library_static_propagating_compilation_context_test(
263        name = test_name,
264        target_under_test = name,
265        expected_absent_hdrs = [":hdr"],
266        expected_absent_includes = ["a/b/c"],
267        expected_absent_system_includes = ["d/e/f"],
268    )
269
270    return test_name
271
272def _cc_rules_do_not_allow_absolute_includes():
273    name = "cc_rules_do_not_allow_absolute_includes"
274    test_names = []
275
276    DISALLOWED_INCLUDE_DIRS = [
277        "art",
278        "art/libnativebridge",
279        "art/libnativeloader",
280        "libcore",
281        "libnativehelper",
282        "external/apache-harmony",
283        "external/apache-xml",
284        "external/boringssl",
285        "external/bouncycastle",
286        "external/conscrypt",
287        "external/icu",
288        "external/okhttp",
289        "external/vixl",
290        "external/wycheproof",
291    ]
292
293    for include_dir in DISALLOWED_INCLUDE_DIRS:
294        binary_name = name + "_binary" + "_" + include_dir
295        library_headers_name = name + "_library_headers" + "_" + include_dir
296        library_shared_name = name + "_library_shared" + "_" + include_dir
297        library_static_name = name + "_library_static" + "_" + include_dir
298
299        cc_binary(
300            name = binary_name,
301            absolute_includes = [include_dir],
302            tags = ["manual"],
303        )
304        cc_library_headers(
305            name = library_headers_name,
306            export_absolute_includes = [include_dir],
307            tags = ["manual"],
308        )
309        cc_library_shared(
310            name = library_shared_name,
311            absolute_includes = [include_dir],
312            tags = ["manual"],
313        )
314        cc_library_static(
315            name = library_static_name,
316            absolute_includes = [include_dir],
317            tags = ["manual"],
318        )
319
320        for target in [
321            binary_name,
322            library_headers_name,
323            library_static_name,
324            library_shared_name,
325        ]:
326            test_name = target + "_" + include_dir + "_test"
327            test_names.append(test_name)
328            expect_failure_test(
329                name = test_name,
330                target_under_test = target,
331            )
332
333    return test_names
334
335def _cc_library_static_links_against_prebuilt_library_test_impl(ctx):
336    env = analysistest.begin(ctx)
337    actions = analysistest.target_actions(env)
338
339    asserts.equals(env, 2, len(actions), "Expected actions, got %s" % actions)
340
341    argv = actions[0].argv
342    expected_output_action1 = get_output_and_package_dir_based_path(env, "libcc_library_static_links_against_prebuilt_library_objs_only.a")
343    asserts.equals(env, 5, len(argv))
344    asserts.equals(env, "crsPD", argv[1])
345    asserts.equals(env, expected_output_action1, argv[2])
346    asserts.equals(env, get_output_and_package_dir_based_path(env, paths.join("_objs", "cc_library_static_links_against_prebuilt_library_cpp", "bar.o")), argv[3])
347    asserts.equals(env, "--format=gnu", argv[4])
348
349    argv = actions[1].argv
350    asserts.equals(env, 6, len(argv))
351    asserts.equals(env, "cqsL", argv[1])
352    asserts.equals(env, get_output_and_package_dir_based_path(env, "libcc_library_static_links_against_prebuilt_library.a"), argv[2])
353    asserts.equals(env, "--format=gnu", argv[3])
354    asserts.equals(env, expected_output_action1, argv[4])
355    asserts.equals(env, get_package_dir_based_path(env, "foo.a"), argv[5])
356
357    return analysistest.end(env)
358
359_cc_library_static_links_against_prebuilt_library_test = analysistest.make(_cc_library_static_links_against_prebuilt_library_test_impl)
360
361def _cc_library_static_links_against_prebuilt_library():
362    name = "cc_library_static_links_against_prebuilt_library"
363    test_name = name + "_test"
364    dep_name = name + "_dep"
365
366    cc_prebuilt_library_static(
367        name = dep_name,
368        static_library = "foo.a",
369        tags = ["manual"],
370    )
371
372    cc_library_static(
373        name = name,
374        srcs = ["bar.c"],
375        whole_archive_deps = [dep_name],
376        tags = ["manual"],
377    )
378
379    _cc_library_static_links_against_prebuilt_library_test(
380        name = test_name,
381        target_under_test = name,
382    )
383
384    return test_name
385
386def _cc_library_static_linking_object_ordering_test_impl(ctx):
387    env = analysistest.begin(ctx)
388    actions = analysistest.target_actions(env)
389
390    asserts.equals(env, 1, len(actions), "Expected actions, got %s" % actions)
391
392    outputs = actions[0].outputs.to_list()
393    argv = actions[0].argv
394    asserts.equals(env, 4 + len(ctx.attr.expected_objects_in_order), len(argv))
395    asserts.equals(env, "crsPD", argv[1])
396    asserts.equals(env, outputs[0].path, argv[2])
397
398    for i in range(len(ctx.attr.expected_objects_in_order)):
399        obj = ctx.attr.expected_objects_in_order[i]
400        asserts.equals(env, obj, paths.basename(argv[3 + i]))
401
402    asserts.equals(env, "--format=gnu", argv[-1])
403
404    return analysistest.end(env)
405
406_cc_library_static_linking_object_ordering_test = analysistest.make(
407    _cc_library_static_linking_object_ordering_test_impl,
408    attrs = {
409        "expected_objects_in_order": attr.string_list(),
410    },
411)
412
413def _cc_library_static_whole_archive_deps_objects_precede_target_objects():
414    name = "_cc_library_static_whole_archive_deps_objects_precede_target_objects"
415    dep_name = name + "_dep"
416    test_name = name + "_test"
417
418    cc_library_static(
419        name = dep_name,
420        srcs = ["first.c"],
421        tags = ["manual"],
422    )
423
424    cc_library_static(
425        name = name,
426        srcs = ["second.c"],
427        whole_archive_deps = [dep_name],
428        tags = ["manual"],
429    )
430
431    _cc_library_static_linking_object_ordering_test(
432        name = test_name,
433        target_under_test = name,
434        expected_objects_in_order = [
435            "first.o",
436            "second.o",
437        ],
438    )
439
440    return test_name
441
442def _cc_library_static_whole_archive_deps_objects_excluded_when_shared_linking():
443    name = "cc_library_static_whole_archive_deps_objects_excluded_when_shared_linking"
444    dep_name = name + "_dep"
445    test_name = name + "_test"
446
447    cc_library_static(
448        name = dep_name,
449        srcs = ["first.c"],
450        tags = ["manual"],
451    )
452
453    cc_library_static(
454        name = name,
455        shared_linking = True,
456        srcs = ["second.c"],
457        whole_archive_deps = [dep_name],
458        tags = ["manual"],
459    )
460
461    _cc_library_static_linking_object_ordering_test(
462        name = test_name,
463        target_under_test = name,
464        expected_objects_in_order = [
465            "second.o",
466        ],
467    )
468
469    return test_name
470
471def _cc_library_static_provides_androidmk_info():
472    name = "cc_library_static_provides_androidmk_info"
473    dep_name = name + "_static_dep"
474    whole_archive_dep_name = name + "_whole_archive_dep"
475    dynamic_dep_name = name + "_dynamic_dep"
476    test_name = name + "_test"
477
478    cc_library_static(
479        name = dep_name,
480        srcs = ["foo.c"],
481        tags = ["manual"],
482    )
483    cc_library_static(
484        name = whole_archive_dep_name,
485        srcs = ["foo.c"],
486        tags = ["manual"],
487    )
488    cc_library_shared(
489        name = dynamic_dep_name,
490        srcs = ["foo.c"],
491        tags = ["manual"],
492    )
493    cc_library_static(
494        name = name,
495        srcs = ["foo.cc"],
496        deps = [dep_name],
497        whole_archive_deps = [whole_archive_dep_name],
498        dynamic_deps = [dynamic_dep_name],
499        tags = ["manual"],
500    )
501    android_test_name = test_name + "_android"
502    android_sdk_variant_test_name = test_name + "_android_sdk_variant"
503    linux_test_name = test_name + "_linux"
504    target_provides_androidmk_info_test(
505        name = android_test_name,
506        target_under_test = name,
507        expected_static_libs = [dep_name, "libc++_static", "libc++demangle"],
508        expected_whole_static_libs = [whole_archive_dep_name],
509        expected_shared_libs = [dynamic_dep_name, "libc_stub_libs-current", "libdl_stub_libs-current", "libm_stub_libs-current"],
510        target_compatible_with = ["//build/bazel_common_rules/platforms/os:android"],
511    )
512    target_sdk_variant_provides_androidmk_info_test(
513        name = android_sdk_variant_test_name,
514        target_under_test = name,
515        expected_static_libs = [dep_name],
516        expected_whole_static_libs = [whole_archive_dep_name],
517        expected_shared_libs = [
518            dynamic_dep_name,
519            # bionic NDK stubs from system_dynamic_dep_defaults
520            "libc.ndk_stub_libs-current",
521            "libdl.ndk_stub_libs-current",
522            "libm.ndk_stub_libs-current",
523            # from STL: "ndk_system".
524            # sdk variants default to system STL.
525            "libstdc++",
526        ],
527        target_compatible_with = ["//build/bazel_common_rules/platforms/os:android"],
528    )
529    target_provides_androidmk_info_test(
530        name = linux_test_name,
531        target_under_test = name,
532        expected_static_libs = [dep_name, "libc++_static"],
533        expected_whole_static_libs = [whole_archive_dep_name],
534        expected_shared_libs = [dynamic_dep_name],
535        target_compatible_with = ["//build/bazel_common_rules/platforms/os:linux"],
536    )
537    return [
538        android_test_name,
539        android_sdk_variant_test_name,
540        linux_test_name,
541    ]
542
543def _cc_library_static_link_action_should_not_have_arch_cflags():
544    name = "cc_library_static_link_action_should_not_have_cflags"
545    cpp_compile_test_name = name + "_CppCompile_test"
546    cpp_link_test_name = name + "_CppLink_test"
547
548    # https://cs.android.com/android/platform/build/soong/+/master:cc/config/arm_device.go;l=57-59;drc=de7c7847e7e028d46fdff8268689f30163c4c231
549    arm_armv7_a_cflags = ["-march=armv7-a", "-mfloat-abi=softfp"]
550
551    cc_library_static(
552        name = name,
553        srcs = ["foo.cpp"],
554        tags = ["manual"],
555    )
556
557    action_flags_present_only_for_mnemonic_test(
558        name = cpp_compile_test_name,
559        target_under_test = name + "_cpp",
560        mnemonics = ["CppCompile"],
561        expected_flags = arm_armv7_a_cflags,
562        target_compatible_with = [
563            "//build/bazel_common_rules/platforms/os:android",
564            "//build/bazel/platforms/arch/variants:armv7-a-neon",
565        ],
566    )
567
568    action_flags_absent_for_mnemonic_test(
569        name = cpp_link_test_name,
570        target_under_test = name,
571        mnemonics = ["CppLink"],
572        expected_absent_flags = arm_armv7_a_cflags,
573        target_compatible_with = [
574            "//build/bazel_common_rules/platforms/os:android",
575            "//build/bazel/platforms/arch/variants:armv7-a-neon",
576        ],
577    )
578
579    return [
580        cpp_compile_test_name,
581        cpp_link_test_name,
582    ]
583
584def _cc_library_static_defines_do_not_check_manual_binder_interfaces():
585    name = "_cc_library_static_defines_do_not_check_manual_binder_interfaces"
586    cpp_lib_name = name + "_cpp"
587    cpp_test_name = cpp_lib_name + "_test"
588    c_lib_name = name + "_c"
589    c_test_name = c_lib_name + "_test"
590
591    cc_library_static(
592        name = name,
593        srcs = ["a.cpp"],
594        srcs_c = ["b.c"],
595        tags = ["manual"],
596    )
597    action_flags_present_only_for_mnemonic_test(
598        name = cpp_test_name,
599        target_under_test = cpp_lib_name,
600        mnemonics = ["CppCompile"],
601        expected_flags = [
602            "-DDO_NOT_CHECK_MANUAL_BINDER_INTERFACES",
603        ],
604    )
605    action_flags_present_only_for_mnemonic_test(
606        name = c_test_name,
607        target_under_test = c_lib_name,
608        mnemonics = ["CppCompile"],
609        expected_flags = [
610            "-DDO_NOT_CHECK_MANUAL_BINDER_INTERFACES",
611        ],
612    )
613
614    non_allowlisted_package_cpp_name = name + "_non_allowlisted_package_cpp"
615    action_flags_absent_for_mnemonic_test(
616        name = non_allowlisted_package_cpp_name,
617        target_under_test = "//build/bazel/examples/cc:foo_static_cpp",
618        mnemonics = ["CppCompile"],
619        expected_absent_flags = [
620            "-DDO_NOT_CHECK_MANUAL_BINDER_INTERFACES",
621        ],
622    )
623
624    return [
625        cpp_test_name,
626        c_test_name,
627        non_allowlisted_package_cpp_name,
628    ]
629
630def cc_library_static_test_suite(name):
631    native.genrule(name = "hdr", cmd = "null", outs = ["f.h"], tags = ["manual"])
632
633    native.test_suite(
634        name = name,
635        tests = [
636            _cc_library_static_propagates_deps(),
637            _cc_library_static_propagates_whole_archive_deps(),
638            _cc_library_static_propagates_dynamic_deps(),
639            _cc_library_static_does_not_propagate_implementation_deps(),
640            _cc_library_static_does_not_propagate_implementation_whole_archive_deps(),
641            _cc_library_static_does_not_propagate_implementation_dynamic_deps(),
642            _cc_library_static_links_against_prebuilt_library(),
643            _cc_library_static_whole_archive_deps_objects_precede_target_objects(),
644            _cc_library_static_whole_archive_deps_objects_excluded_when_shared_linking(),
645        ] + (
646            _cc_rules_do_not_allow_absolute_includes() +
647            _cc_library_static_provides_androidmk_info() +
648            _cc_library_static_link_action_should_not_have_arch_cflags() +
649            _cc_library_static_defines_do_not_check_manual_binder_interfaces()
650        ),
651    )
652