1# Copyright (C) 2023 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(":cc_object.bzl", "cc_object")
17
18def _min_sdk_version_target_flag_test_impl(ctx):
19    env = analysistest.begin(ctx)
20    actions = analysistest.target_actions(env)
21    cpp_link_actions = [a for a in actions if a.mnemonic == "CppLink"]
22
23    found = False
24    for action in cpp_link_actions:
25        for arg in action.argv:
26            if arg.startswith("--target="):
27                found = True
28                asserts.true(
29                    env,
30                    arg.endswith(ctx.attr.expected_min_sdk_version),
31                    "Incorrect --target flag %s. Expected sdk_version %s" % (arg, ctx.attr.expected_min_sdk_version),
32                )
33    asserts.true(
34        env,
35        found,
36        "No --target flag found in CppLink actions: %s" % (
37            [a.argv for a in cpp_link_actions],
38        ),
39    )
40
41    return analysistest.end(env)
42
43def _create_min_sdk_version_target_flag_test(config_settings = {}):
44    return analysistest.make(
45        _min_sdk_version_target_flag_test_impl,
46        attrs = {
47            "expected_min_sdk_version": attr.string(mandatory = True),
48        },
49        config_settings = config_settings,
50    )
51
52_min_sdk_version_target_flag_test = _create_min_sdk_version_target_flag_test()
53
54_apex_min_sdk_version = "25"
55
56_min_sdk_version_target_flag_with_apex_test = _create_min_sdk_version_target_flag_test({
57    "@//build/bazel/rules/apex:min_sdk_version": _apex_min_sdk_version,
58})
59
60def _crt_cc_object_min_sdk_version_overriden_by_apex_min_sdk_version():
61    name = "crt_cc_object_min_sdk_version_overriden_by_apex_min_sdk_version"
62    test_name = name + "_test"
63    crt_apex_test_name = test_name + "_crt_apex"
64    not_crt_apex_test_name = test_name + "_not_crt_apex"
65    crt_not_apex_test_name = test_name + "_crt_not_apex"
66    not_crt_not_apex_test_name = test_name + "_not_crt_not_apex"
67    crt_obj_name = name + "_crt"
68    not_crt_obj_name = name + "_not_crt"
69    obj_dep_name = name + "_dep"
70    obj_min_sdk_version = "16"
71
72    cc_object(
73        name = obj_dep_name,
74        srcs = ["a.cc"],
75        tags = ["manual"],
76    )
77    cc_object(
78        name = crt_obj_name,
79        crt = True,
80        objs = [obj_dep_name],
81        srcs = ["a.cc"],
82        min_sdk_version = obj_min_sdk_version,
83        tags = ["manual"],
84    )
85    cc_object(
86        name = not_crt_obj_name,
87        objs = [obj_dep_name],
88        srcs = ["a.cc"],
89        min_sdk_version = obj_min_sdk_version,
90        tags = ["manual"],
91    )
92    _min_sdk_version_target_flag_with_apex_test(
93        name = crt_apex_test_name,
94        target_under_test = crt_obj_name,
95        expected_min_sdk_version = _apex_min_sdk_version,
96        target_compatible_with = ["@//build/bazel_common_rules/platforms/os:android"],
97    )
98    _min_sdk_version_target_flag_with_apex_test(
99        name = not_crt_apex_test_name,
100        target_under_test = not_crt_obj_name,
101        expected_min_sdk_version = obj_min_sdk_version,
102        target_compatible_with = ["@//build/bazel_common_rules/platforms/os:android"],
103    )
104    _min_sdk_version_target_flag_test(
105        name = crt_not_apex_test_name,
106        target_under_test = crt_obj_name,
107        expected_min_sdk_version = obj_min_sdk_version,
108        target_compatible_with = ["@//build/bazel_common_rules/platforms/os:android"],
109    )
110    _min_sdk_version_target_flag_test(
111        name = not_crt_not_apex_test_name,
112        target_under_test = not_crt_obj_name,
113        expected_min_sdk_version = obj_min_sdk_version,
114        target_compatible_with = ["@//build/bazel_common_rules/platforms/os:android"],
115    )
116
117    return [
118        crt_apex_test_name,
119        not_crt_apex_test_name,
120        crt_not_apex_test_name,
121        not_crt_not_apex_test_name,
122    ]
123
124def _cc_object_partial_linking_test_impl(ctx):
125    env = analysistest.begin(ctx)
126    actions = analysistest.target_actions(env)
127    cpp_link_actions = [a for a in actions if a.mnemonic == "CppLink"]
128    noaddrsig_actions = [a for a in actions if a.mnemonic == "CppObjcopyNoAddrsig"]
129    asserts.true(
130        env,
131        len(cpp_link_actions) > 0,
132        "No CppLink actions found in : %s" % (
133            [a.mnemonic for a in actions],
134        ),
135    )
136
137    # Verify multiple objects results in a partial link command line
138    asserts.true(
139        env,
140        " ".join(cpp_link_actions[0].argv).find(" -Wl,-r ") != -1,
141        "CppLink action missing -r : %s" % (
142            cpp_link_actions[0].argv
143        ),
144    )
145
146    # Verify partial linking also triggers CppObjcopyNoAddrsig
147    asserts.true(
148        env,
149        len(noaddrsig_actions) > 0,
150        "No CppObjcopyNoAddrsig actions found in : %s" % (
151            actions,
152        ),
153    )
154
155    return analysistest.end(env)
156
157_cc_object_partial_linking_test = analysistest.make(
158    _cc_object_partial_linking_test_impl,
159    attrs = {
160    },
161)
162
163def _cc_object_partial_linking():
164    name = "cc_object_partial_linking"
165    test_name = name + "_test"
166
167    dep1_name = name + "_dep1"
168    dep2_name = name + "_dep2"
169
170    cc_object(
171        name = dep1_name,
172        srcs = ["a.cc"],
173        tags = ["manual"],
174    )
175    cc_object(
176        name = dep2_name,
177        srcs = ["b.cc"],
178        tags = ["manual"],
179    )
180    cc_object(
181        name = name,
182        objs = [dep1_name, dep2_name],
183        tags = ["manual"],
184    )
185
186    _cc_object_partial_linking_test(
187        name = test_name,
188        target_under_test = name,
189        target_compatible_with = ["@//build/bazel_common_rules/platforms/os:android"],
190    )
191
192    return test_name
193
194def cc_object_test_suite(name):
195    native.test_suite(
196        name = name,
197        tests = _crt_cc_object_min_sdk_version_overriden_by_apex_min_sdk_version() + [
198            _cc_object_partial_linking(),
199        ],
200    )
201