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.
14load(":cc_constants.bzl", "transition_constants")
15load(":cfi_transitions.bzl", "CFI_ASSEMBLY_FEATURE", "CFI_FEATURE", "apply_cfi_deps", "apply_drop_cfi")
16load(
17    ":fdo_profile_transitions.bzl",
18    "CLI_CODECOV_KEY",
19    "CLI_FDO_KEY",
20    "FDO_PROFILE_ATTR_KEY",
21    "apply_drop_fdo_profile",
22    "apply_fdo_profile",
23)
24load(":lto_transitions.bzl", "apply_drop_lto", "apply_lto_deps")
25load(":memtag_heap_transitions.bzl", "apply_drop_memtag_heap", "apply_memtag_heap_transition")
26load(
27    ":sanitizer_enablement_transition.bzl",
28    "apply_sanitizer_enablement_transition",
29)
30
31# LTO, sanitizers, and FDO require an incoming transition on cc_library_shared
32# FDO is applied, while LTO and sanitizers are dropped.
33def _lto_and_fdo_profile_incoming_transition_impl(settings, attr):
34    new_fdo_settings = apply_fdo_profile(
35        settings[CLI_CODECOV_KEY],
36        getattr(attr, FDO_PROFILE_ATTR_KEY),
37    )
38
39    new_cli_features = apply_drop_lto(
40        settings[transition_constants.cli_features_key],
41    )
42    new_cli_features = apply_drop_cfi(new_cli_features)
43    new_cli_setting = {
44        transition_constants.cli_features_key: new_cli_features,
45    }
46
47    return new_fdo_settings | new_cli_setting | {
48        transition_constants.cfi_assembly_key: False,
49        # TODO: b/294868620 - This can be removed when completing the bug
50        transition_constants.sanitizers_enabled_key: False,
51    }
52
53lto_and_fdo_profile_incoming_transition = transition(
54    implementation = _lto_and_fdo_profile_incoming_transition_impl,
55    inputs = [
56        CLI_CODECOV_KEY,
57        transition_constants.cli_features_key,
58    ],
59    outputs = [
60        CLI_FDO_KEY,
61        transition_constants.cli_features_key,
62        transition_constants.cfi_assembly_key,
63        # TODO: b/294868620 - This can be removed when completing the bug
64        transition_constants.sanitizers_enabled_key,
65    ],
66)
67
68# This transition applies LTO and sanitizer propagation down static dependencies
69def _lto_and_sanitizer_deps_transition_impl(settings, attr):
70    features = getattr(attr, transition_constants.features_attr_key)
71    old_cli_features = settings[transition_constants.cli_features_key]
72    new_cli_features = apply_lto_deps(features, old_cli_features)
73    new_cli_features = apply_memtag_heap_transition(settings, attr, new_cli_features)
74    cfi_include_paths = settings[transition_constants.cfi_include_paths_key]
75    cfi_exclude_paths = settings[transition_constants.cfi_exclude_paths_key]
76    new_cli_features = apply_cfi_deps(
77        features,
78        new_cli_features,
79        attr.package_name,
80        cfi_include_paths,
81        cfi_exclude_paths,
82        settings[transition_constants.enable_cfi_key],
83        settings[transition_constants.cli_platforms_key],
84    )
85    cfi_assembly = CFI_FEATURE in new_cli_features and CFI_ASSEMBLY_FEATURE in features
86
87    # TODO: b/294868620 - This can be removed when completing the bug
88    sanitizers_enabled = apply_sanitizer_enablement_transition(
89        features + new_cli_features,
90    )
91    return {
92        transition_constants.cli_features_key: new_cli_features,
93        transition_constants.cfi_assembly_key: cfi_assembly,
94        # TODO: b/294868620 - This can be removed when completing the bug
95        transition_constants.sanitizers_enabled_key: sanitizers_enabled,
96    }
97
98lto_and_sanitizer_deps_transition = transition(
99    implementation = _lto_and_sanitizer_deps_transition_impl,
100    inputs = [
101        transition_constants.cli_features_key,
102        transition_constants.cfi_include_paths_key,
103        transition_constants.cfi_exclude_paths_key,
104        transition_constants.enable_cfi_key,
105        transition_constants.cli_platforms_key,
106        transition_constants.memtag_heap_async_include_paths_key,
107        transition_constants.memtag_heap_sync_include_paths_key,
108        transition_constants.memtag_heap_exclude_paths_key,
109    ],
110    outputs = [
111        transition_constants.cli_features_key,
112        transition_constants.cfi_assembly_key,
113        # TODO: b/294868620 - This can be removed when completing the bug
114        transition_constants.sanitizers_enabled_key,
115    ],
116)
117
118# TODO: b/294868620 - This can be removed when completing the bug
119def _lto_and_sanitizer_static_transition_impl(settings, attr):
120    features = getattr(attr, transition_constants.features_attr_key)
121    old_cli_features = settings[transition_constants.cli_features_key]
122    return {
123        transition_constants.cli_features_key: apply_lto_deps(
124            features,
125            old_cli_features,
126        ),
127        transition_constants.sanitizers_enabled_key: (
128            apply_sanitizer_enablement_transition(features + old_cli_features)
129        ),
130    }
131
132# TODO: b/294868620 - This can be removed when completing the bug
133lto_and_sanitizer_static_transition = transition(
134    implementation = _lto_and_sanitizer_static_transition_impl,
135    inputs = [
136        transition_constants.cli_features_key,
137    ],
138    outputs = [
139        transition_constants.cli_features_key,
140        transition_constants.sanitizers_enabled_key,
141    ],
142)
143
144def _apply_drop_lto_and_sanitizers(old_cli_features):
145    new_cli_features = apply_drop_lto(old_cli_features)
146    new_cli_features = apply_drop_cfi(new_cli_features)
147    new_cli_features = apply_drop_memtag_heap(new_cli_features)
148
149    return {
150        transition_constants.cli_features_key: new_cli_features,
151    }
152
153# This transition drops LTO and sanitizer enablement from cc_binary
154def _drop_lto_and_sanitizer_transition_impl(settings, _):
155    return _apply_drop_lto_and_sanitizers(
156        settings[transition_constants.cli_features_key],
157    ) | {transition_constants.cfi_assembly_key: False}
158
159drop_lto_and_sanitizer_transition = transition(
160    implementation = _drop_lto_and_sanitizer_transition_impl,
161    inputs = [transition_constants.cli_features_key],
162    outputs = [
163        transition_constants.cli_features_key,
164        transition_constants.cfi_assembly_key,
165    ],
166)
167
168# Drop lto, sanitizer, and fdo transitions in order to avoid duplicate
169# dependency error.
170# Currently used for cc stub libraries.
171def _drop_lto_sanitizer_and_fdo_profile_transition_impl(settings, _):
172    new_cli_features = _apply_drop_lto_and_sanitizers(
173        settings[transition_constants.cli_features_key],
174    )
175
176    new_fdo_setting = apply_drop_fdo_profile()
177
178    return (
179        new_cli_features |
180        new_fdo_setting |
181        {
182            transition_constants.cfi_assembly_key: False,
183            # TODO: b/294868620 - This can be removed when completing the bug
184            transition_constants.sanitizers_enabled_key: False,
185        }
186    )
187
188drop_lto_sanitizer_and_fdo_profile_incoming_transition = transition(
189    implementation = _drop_lto_sanitizer_and_fdo_profile_transition_impl,
190    inputs = [
191        transition_constants.cli_features_key,
192        CLI_FDO_KEY,
193    ],
194    outputs = [
195        transition_constants.cli_features_key,
196        CLI_FDO_KEY,
197        transition_constants.cfi_assembly_key,
198        # TODO: b/294868620 - This can be removed when completing the bug
199        transition_constants.sanitizers_enabled_key,
200    ],
201)
202
203def _drop_sanitizer_transition_impl(settings, _):
204    return {
205        transition_constants.cli_features_key: apply_drop_cfi(
206            settings[transition_constants.cli_features_key],
207        ),
208    }
209
210drop_sanitizer_transition = transition(
211    implementation = _drop_sanitizer_transition_impl,
212    inputs = [transition_constants.cli_features_key],
213    outputs = [transition_constants.cli_features_key],
214)
215