| """ |
| Copyright (C) 2022 The Android Open Source Project |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| """ |
| |
| load("@bazel_skylib//lib:paths.bzl", "paths") |
| load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") |
| load("//build/bazel/rules/cc:cc_library_shared.bzl", "cc_library_shared") |
| load("//build/bazel/rules/cc:cc_library_static.bzl", "cc_library_static") |
| load("//build/bazel/rules/cc:cc_library_headers.bzl", "cc_library_headers") |
| load("//build/bazel/rules/cc:cc_prebuilt_library_static.bzl", "cc_prebuilt_library_static") |
| load("//build/bazel/rules/cc:cc_binary.bzl", "cc_binary") |
| load(":cc_library_common_test.bzl", "target_provides_androidmk_info_test") |
| load("//build/bazel/rules/test_common:paths.bzl", "get_output_and_package_dir_based_path", "get_package_dir_based_path") |
| load("//build/bazel/rules/test_common:rules.bzl", "expect_failure_test") |
| |
| def _cc_library_static_propagating_compilation_context_test_impl(ctx): |
| env = analysistest.begin(ctx) |
| target = analysistest.target_under_test(env) |
| cc_info = target[CcInfo] |
| compilation_context = cc_info.compilation_context |
| |
| header_paths = [f.path for f in compilation_context.headers.to_list()] |
| for hdr in ctx.files.expected_hdrs: |
| asserts.true( |
| env, |
| hdr.path in header_paths, |
| "Did not find {hdr} in includes: {hdrs}.".format(hdr = hdr, hdrs = compilation_context.headers), |
| ) |
| |
| for hdr in ctx.files.expected_absent_hdrs: |
| asserts.true( |
| env, |
| hdr not in header_paths, |
| "Found {hdr} in includes: {hdrs}, should not be present.".format(hdr = hdr, hdrs = compilation_context.headers), |
| ) |
| |
| for include in ctx.attr.expected_includes: |
| absolute_include = get_package_dir_based_path(env, include) |
| asserts.true( |
| env, |
| absolute_include in compilation_context.includes.to_list(), |
| "Did not find {include} in includes: {includes}.".format(include = include, includes = compilation_context.includes), |
| ) |
| |
| for include in ctx.attr.expected_absent_includes: |
| absolute_include = get_package_dir_based_path(env, include) |
| asserts.true( |
| env, |
| absolute_include not in compilation_context.includes.to_list(), |
| "Found {include} in includes: {includes}, was expected to be absent".format(include = include, includes = compilation_context.includes), |
| ) |
| |
| for include in ctx.attr.expected_system_includes: |
| absolute_include = get_package_dir_based_path(env, include) |
| asserts.true( |
| env, |
| absolute_include in compilation_context.system_includes.to_list(), |
| "Did not find {include} in system includes: {includes}.".format(include = include, includes = compilation_context.system_includes), |
| ) |
| |
| for include in ctx.attr.expected_absent_system_includes: |
| absolute_include = get_package_dir_based_path(env, include) |
| asserts.true( |
| env, |
| absolute_include not in compilation_context.system_includes.to_list(), |
| "Found {include} in system includes: {includes}, was expected to be absent".format(include = include, includes = compilation_context.system_includes), |
| ) |
| |
| return analysistest.end(env) |
| |
| _cc_library_static_propagating_compilation_context_test = analysistest.make( |
| _cc_library_static_propagating_compilation_context_test_impl, |
| attrs = { |
| "expected_hdrs": attr.label_list(), |
| "expected_absent_hdrs": attr.label_list(), |
| "expected_includes": attr.string_list(), |
| "expected_absent_includes": attr.string_list(), |
| "expected_system_includes": attr.string_list(), |
| "expected_absent_system_includes": attr.string_list(), |
| }, |
| ) |
| |
| def _cc_library_static_propagates_deps(): |
| name = "_cc_library_static_propagates_deps" |
| dep_name = name + "_dep" |
| test_name = name + "_test" |
| |
| cc_library_static( |
| name = dep_name, |
| hdrs = [":hdr"], |
| export_includes = ["a/b/c"], |
| export_system_includes = ["d/e/f"], |
| tags = ["manual"], |
| ) |
| |
| cc_library_static( |
| name = name, |
| deps = [dep_name], |
| tags = ["manual"], |
| ) |
| |
| _cc_library_static_propagating_compilation_context_test( |
| name = test_name, |
| target_under_test = name, |
| expected_hdrs = [":hdr"], |
| expected_includes = ["a/b/c"], |
| expected_system_includes = ["d/e/f"], |
| ) |
| |
| return test_name |
| |
| def _cc_library_static_propagates_whole_archive_deps(): |
| name = "_cc_library_static_propagates_whole_archive_deps" |
| dep_name = name + "_dep" |
| test_name = name + "_test" |
| |
| cc_library_static( |
| name = dep_name, |
| hdrs = [":hdr"], |
| export_includes = ["a/b/c"], |
| export_system_includes = ["d/e/f"], |
| tags = ["manual"], |
| ) |
| |
| cc_library_static( |
| name = name, |
| whole_archive_deps = [dep_name], |
| tags = ["manual"], |
| ) |
| |
| _cc_library_static_propagating_compilation_context_test( |
| name = test_name, |
| target_under_test = name, |
| expected_hdrs = [":hdr"], |
| expected_includes = ["a/b/c"], |
| expected_system_includes = ["d/e/f"], |
| ) |
| |
| return test_name |
| |
| def _cc_library_static_propagates_dynamic_deps(): |
| name = "_cc_library_static_propagates_dynamic_deps" |
| dep_name = name + "_dep" |
| test_name = name + "_test" |
| |
| cc_library_shared( |
| name = dep_name, |
| hdrs = [":hdr"], |
| export_includes = ["a/b/c"], |
| export_system_includes = ["d/e/f"], |
| tags = ["manual"], |
| ) |
| |
| cc_library_static( |
| name = name, |
| dynamic_deps = [dep_name], |
| tags = ["manual"], |
| ) |
| |
| _cc_library_static_propagating_compilation_context_test( |
| name = test_name, |
| target_under_test = name, |
| expected_hdrs = [":hdr"], |
| expected_includes = ["a/b/c"], |
| expected_system_includes = ["d/e/f"], |
| ) |
| |
| return test_name |
| |
| def _cc_library_static_does_not_propagate_implementation_deps(): |
| name = "_cc_library_static_does_not_propagate_implementation_deps" |
| dep_name = name + "_dep" |
| test_name = name + "_test" |
| |
| cc_library_static( |
| name = dep_name, |
| hdrs = [":hdr"], |
| export_includes = ["a/b/c"], |
| export_system_includes = ["d/e/f"], |
| tags = ["manual"], |
| ) |
| |
| cc_library_static( |
| name = name, |
| implementation_deps = [dep_name], |
| tags = ["manual"], |
| ) |
| |
| _cc_library_static_propagating_compilation_context_test( |
| name = test_name, |
| target_under_test = name, |
| expected_absent_hdrs = [":hdr"], |
| expected_absent_includes = ["a/b/c"], |
| expected_absent_system_includes = ["d/e/f"], |
| ) |
| |
| return test_name |
| |
| def _cc_library_static_does_not_propagate_implementation_whole_archive_deps(): |
| name = "_cc_library_static_does_not_propagate_implementation_whole_archive_deps" |
| dep_name = name + "_dep" |
| test_name = name + "_test" |
| |
| cc_library_static( |
| name = dep_name, |
| hdrs = [":hdr"], |
| export_includes = ["a/b/c"], |
| export_system_includes = ["d/e/f"], |
| tags = ["manual"], |
| ) |
| |
| cc_library_static( |
| name = name, |
| implementation_whole_archive_deps = [dep_name], |
| tags = ["manual"], |
| ) |
| |
| _cc_library_static_propagating_compilation_context_test( |
| name = test_name, |
| target_under_test = name, |
| expected_absent_hdrs = [":hdr"], |
| expected_absent_includes = ["a/b/c"], |
| expected_absent_system_includes = ["d/e/f"], |
| ) |
| |
| return test_name |
| |
| def _cc_library_static_does_not_propagate_implementation_dynamic_deps(): |
| name = "_cc_library_static_does_not_propagate_implementation_dynamic_deps" |
| dep_name = name + "_dep" |
| test_name = name + "_test" |
| |
| cc_library_shared( |
| name = dep_name, |
| hdrs = [":hdr"], |
| export_includes = ["a/b/c"], |
| export_system_includes = ["d/e/f"], |
| tags = ["manual"], |
| ) |
| |
| cc_library_static( |
| name = name, |
| implementation_dynamic_deps = [dep_name], |
| tags = ["manual"], |
| ) |
| |
| _cc_library_static_propagating_compilation_context_test( |
| name = test_name, |
| target_under_test = name, |
| expected_absent_hdrs = [":hdr"], |
| expected_absent_includes = ["a/b/c"], |
| expected_absent_system_includes = ["d/e/f"], |
| ) |
| |
| return test_name |
| |
| def _cc_rules_do_not_allow_absolute_includes(): |
| name = "cc_rules_do_not_allow_absolute_includes" |
| test_names = [] |
| |
| DISALLOWED_INCLUDE_DIRS = [ |
| "art", |
| "art/libnativebridge", |
| "art/libnativeloader", |
| "libcore", |
| "libnativehelper", |
| "external/apache-harmony", |
| "external/apache-xml", |
| "external/boringssl", |
| "external/bouncycastle", |
| "external/conscrypt", |
| "external/icu", |
| "external/okhttp", |
| "external/vixl", |
| "external/wycheproof", |
| ] |
| |
| for include_dir in DISALLOWED_INCLUDE_DIRS: |
| binary_name = name + "_binary" + "_" + include_dir |
| library_headers_name = name + "_library_headers" + "_" + include_dir |
| library_shared_name = name + "_library_shared" + "_" + include_dir |
| library_static_name = name + "_library_static" + "_" + include_dir |
| |
| cc_binary( |
| name = binary_name, |
| absolute_includes = [include_dir], |
| tags = ["manual"], |
| ) |
| cc_library_headers( |
| name = library_headers_name, |
| absolute_includes = [include_dir], |
| tags = ["manual"], |
| ) |
| cc_library_shared( |
| name = library_shared_name, |
| absolute_includes = [include_dir], |
| tags = ["manual"], |
| ) |
| cc_library_static( |
| name = library_static_name, |
| absolute_includes = [include_dir], |
| tags = ["manual"], |
| ) |
| |
| for target in [ |
| binary_name, |
| library_headers_name, |
| library_static_name, |
| library_shared_name, |
| ]: |
| test_name = target + "_" + include_dir + "_test" |
| test_names.append(test_name) |
| expect_failure_test( |
| name = test_name, |
| target_under_test = target, |
| ) |
| |
| return test_names |
| |
| def _cc_library_static_links_against_prebuilt_library_test_impl(ctx): |
| env = analysistest.begin(ctx) |
| actions = analysistest.target_actions(env) |
| |
| asserts.equals(env, 2, len(actions), "Expected actions, got %s" % actions) |
| |
| argv = actions[0].argv |
| expected_output_action1 = get_output_and_package_dir_based_path(env, "libcc_library_static_links_against_prebuilt_library_objs_only.a") |
| asserts.equals(env, 5, len(argv)) |
| asserts.equals(env, "crsPD", argv[1]) |
| asserts.equals(env, expected_output_action1, argv[2]) |
| 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]) |
| asserts.equals(env, "--format=gnu", argv[4]) |
| |
| argv = actions[1].argv |
| asserts.equals(env, 6, len(argv)) |
| asserts.equals(env, "cqsL", argv[1]) |
| asserts.equals(env, get_output_and_package_dir_based_path(env, "libcc_library_static_links_against_prebuilt_library.a"), argv[2]) |
| asserts.equals(env, "--format=gnu", argv[3]) |
| asserts.equals(env, expected_output_action1, argv[4]) |
| asserts.equals(env, get_package_dir_based_path(env, "foo.a"), argv[5]) |
| |
| return analysistest.end(env) |
| |
| _cc_library_static_links_against_prebuilt_library_test = analysistest.make(_cc_library_static_links_against_prebuilt_library_test_impl) |
| |
| def _cc_library_static_links_against_prebuilt_library(): |
| name = "cc_library_static_links_against_prebuilt_library" |
| test_name = name + "_test" |
| dep_name = name + "_dep" |
| |
| cc_prebuilt_library_static( |
| name = dep_name, |
| static_library = "foo.a", |
| tags = ["manual"], |
| ) |
| |
| cc_library_static( |
| name = name, |
| srcs = ["bar.c"], |
| whole_archive_deps = [dep_name], |
| tags = ["manual"], |
| ) |
| |
| _cc_library_static_links_against_prebuilt_library_test( |
| name = test_name, |
| target_under_test = name, |
| ) |
| |
| return test_name |
| |
| def _cc_library_static_linking_object_ordering_test_impl(ctx): |
| env = analysistest.begin(ctx) |
| actions = analysistest.target_actions(env) |
| |
| asserts.equals(env, 1, len(actions), "Expected actions, got %s" % actions) |
| |
| outputs = actions[0].outputs.to_list() |
| argv = actions[0].argv |
| asserts.equals(env, 4 + len(ctx.attr.expected_objects_in_order), len(argv)) |
| asserts.equals(env, "crsPD", argv[1]) |
| asserts.equals(env, outputs[0].path, argv[2]) |
| |
| for i in range(len(ctx.attr.expected_objects_in_order)): |
| obj = ctx.attr.expected_objects_in_order[i] |
| asserts.equals(env, obj, paths.basename(argv[3 + i])) |
| |
| asserts.equals(env, "--format=gnu", argv[-1]) |
| |
| return analysistest.end(env) |
| |
| _cc_library_static_linking_object_ordering_test = analysistest.make( |
| _cc_library_static_linking_object_ordering_test_impl, |
| attrs = { |
| "expected_objects_in_order": attr.string_list(), |
| }, |
| ) |
| |
| def _cc_library_static_whole_archive_deps_objects_precede_target_objects(): |
| name = "_cc_library_static_whole_archive_deps_objects_precede_target_objects" |
| dep_name = name + "_dep" |
| test_name = name + "_test" |
| |
| cc_library_static( |
| name = dep_name, |
| srcs = ["first.c"], |
| tags = ["manual"], |
| ) |
| |
| cc_library_static( |
| name = name, |
| srcs = ["second.c"], |
| whole_archive_deps = [dep_name], |
| tags = ["manual"], |
| ) |
| |
| _cc_library_static_linking_object_ordering_test( |
| name = test_name, |
| target_under_test = name, |
| expected_objects_in_order = [ |
| "first.o", |
| "second.o", |
| ], |
| ) |
| |
| return test_name |
| |
| def _cc_library_static_provides_androidmk_info(): |
| name = "cc_library_static_provides_androidmk_info" |
| dep_name = name + "_static_dep" |
| whole_archive_dep_name = name + "_whole_archive_dep" |
| dynamic_dep_name = name + "_dynamic_dep" |
| test_name = name + "_test" |
| |
| cc_library_static( |
| name = dep_name, |
| srcs = ["foo.c"], |
| tags = ["manual"], |
| ) |
| cc_library_static( |
| name = whole_archive_dep_name, |
| srcs = ["foo.c"], |
| tags = ["manual"], |
| ) |
| cc_library_shared( |
| name = dynamic_dep_name, |
| srcs = ["foo.c"], |
| tags = ["manual"], |
| ) |
| cc_library_static( |
| name = name, |
| srcs = ["foo.cc"], |
| deps = [dep_name], |
| whole_archive_deps = [whole_archive_dep_name], |
| dynamic_deps = [dynamic_dep_name], |
| tags = ["manual"], |
| ) |
| android_test_name = test_name + "_android" |
| linux_test_name = test_name + "_linux" |
| target_provides_androidmk_info_test( |
| name = android_test_name, |
| target_under_test = name, |
| expected_static_libs = [dep_name, "libc++_static", "libc++demangle"], |
| expected_whole_static_libs = [whole_archive_dep_name], |
| expected_shared_libs = [dynamic_dep_name, "libc", "libdl", "libm"], |
| target_compatible_with = ["//build/bazel/platforms/os:android"], |
| ) |
| target_provides_androidmk_info_test( |
| name = linux_test_name, |
| target_under_test = name, |
| expected_static_libs = [dep_name, "libc++_static"], |
| expected_whole_static_libs = [whole_archive_dep_name], |
| expected_shared_libs = [dynamic_dep_name], |
| target_compatible_with = ["//build/bazel/platforms/os:linux"], |
| ) |
| return [ |
| android_test_name, |
| linux_test_name, |
| ] |
| |
| def cc_library_static_test_suite(name): |
| native.genrule(name = "hdr", cmd = "null", outs = ["f.h"], tags = ["manual"]) |
| |
| native.test_suite( |
| name = name, |
| tests = [ |
| _cc_library_static_propagates_deps(), |
| _cc_library_static_propagates_whole_archive_deps(), |
| _cc_library_static_propagates_dynamic_deps(), |
| _cc_library_static_does_not_propagate_implementation_deps(), |
| _cc_library_static_does_not_propagate_implementation_whole_archive_deps(), |
| _cc_library_static_does_not_propagate_implementation_dynamic_deps(), |
| _cc_library_static_links_against_prebuilt_library(), |
| _cc_library_static_whole_archive_deps_objects_precede_target_objects(), |
| ] + ( |
| _cc_rules_do_not_allow_absolute_includes() + |
| _cc_library_static_provides_androidmk_info() |
| ), |
| ) |