xref: /aosp_15_r20/external/pigweed/pw_build/bazel_internal/pigweed_internal.bzl (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1#!/usr/bin/env python3
2
3# Copyright 2022 The Pigweed Authors
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may not
6# use this file except in compliance with the License. You may obtain a copy of
7# the License at
8#
9#     https://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations under
15# the License.
16""" An internal set of tools for creating embedded CC targets. """
17
18load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
19
20def _print_platform_impl(_, ctx):
21    if hasattr(ctx.rule.attr, "constraint_values"):
22        for cv in ctx.rule.attr.constraint_values:
23            # buildifier: disable=print
24            print(str(ctx.rule.attr.name) + " specifies " + str(cv))
25    return []
26
27print_platform = aspect(
28    implementation = _print_platform_impl,
29    attr_aspects = ["parents"],
30    doc = """
31        This is a little debug utility that traverses the platform inheritance
32        hierarchy and prints all the constraint values.
33
34        Example usage:
35
36        bazel build \
37          //pw_build/platforms:lm3s6965evb \
38          --aspects \
39          pw_build/bazel_internal/pigweed_internal.bzl%print_platform
40    """,
41)
42
43# TODO: https://github.com/bazelbuild/bazel/issues/16546 - Use
44# cc_helper.is_compilation_outputs_empty() if/when it's available for
45# end-users.
46def _is_compilation_outputs_empty(compilation_outputs):
47    return (len(compilation_outputs.pic_objects) == 0 and
48            len(compilation_outputs.objects) == 0)
49
50def compile_cc(
51        ctx,
52        srcs,
53        hdrs,
54        deps,
55        includes = [],
56        defines = [],
57        local_defines = [],
58        user_compile_flags = [],
59        alwayslink = False):
60    """Compiles a list C++ source files.
61
62    Args:
63        ctx: Rule context
64        srcs: List of C/C++ source files to compile
65        hdrs: List of C/C++ header files to compile with
66        deps: Dependencies to link with
67        includes: List of include paths
68        defines: List of preprocessor defines to use
69        local_defines: List of preprocessor defines to use only on this unit.
70        user_compile_flags: Extra compiler flags to pass when compiling.
71        alwayslink: Whether this library should always be linked.
72
73    Returns:
74      A CcInfo provider.
75    """
76    cc_toolchain = find_cpp_toolchain(ctx)
77    feature_configuration = cc_common.configure_features(
78        ctx = ctx,
79        cc_toolchain = cc_toolchain,
80        requested_features = ctx.features,
81        unsupported_features = ctx.disabled_features,
82    )
83
84    compilation_contexts = [dep[CcInfo].compilation_context for dep in deps]
85    compilation_context, compilation_outputs = cc_common.compile(
86        name = ctx.label.name,
87        actions = ctx.actions,
88        feature_configuration = feature_configuration,
89        cc_toolchain = cc_toolchain,
90        srcs = srcs,
91        includes = includes,
92        defines = defines,
93        local_defines = local_defines,
94        public_hdrs = hdrs,
95        user_compile_flags = user_compile_flags,
96        compilation_contexts = compilation_contexts,
97    )
98
99    linking_contexts = [dep[CcInfo].linking_context for dep in deps]
100
101    # If there's no compiled artifacts (i.e. the library is header-only), don't
102    # try and link a library.
103    #
104    # TODO: https://github.com/bazelbuild/bazel/issues/18095 - Remove this
105    # if create_linking_context_from_compilation_outputs() is changed to no
106    # longer require this workaround.
107    if not _is_compilation_outputs_empty(compilation_outputs):
108        linking_context, link_outputs = cc_common.create_linking_context_from_compilation_outputs(
109            actions = ctx.actions,
110            feature_configuration = feature_configuration,
111            cc_toolchain = cc_toolchain,
112            compilation_outputs = compilation_outputs,
113            linking_contexts = linking_contexts,
114            disallow_dynamic_library = True,
115            alwayslink = alwayslink,
116            name = ctx.label.name,
117        )
118
119        if link_outputs.library_to_link != None:
120            linking_contexts.append(linking_context)
121
122    return [
123        CcInfo(
124            compilation_context = compilation_context,
125            linking_context = cc_common.merge_linking_contexts(
126                linking_contexts = linking_contexts,
127            ),
128        ),
129    ]
130
131# From cc_helper.bzl. Feature names for static/dynamic linking.
132linker_mode = struct(
133    LINKING_DYNAMIC = "dynamic_linking_mode",
134    LINKING_STATIC = "static_linking_mode",
135)
136
137def link_cc(
138        ctx,
139        linking_contexts,
140        linkstatic,
141        stamp,
142        user_link_flags = [],
143        additional_outputs = []):
144    """Links a binary and allows custom linker output.
145
146    Args:
147        ctx: Rule context
148        linking_contexts: Dependencies to link with
149        linkstatic: True if binary should be linked statically.
150        stamp: Stamp behavior for linking.
151        user_link_flags: Extra linker flags to pass when linking
152        additional_outputs: Extra files generated by link
153
154    Returns:
155      DefaultInfo of output files
156    """
157    cc_toolchain = find_cpp_toolchain(ctx)
158    features = ctx.features
159    linking_mode = linker_mode.LINKING_STATIC
160    if not linkstatic:
161        linking_mode = linker_mode.LINKING_DYNAMIC
162    features.append(linking_mode)
163    feature_configuration = cc_common.configure_features(
164        ctx = ctx,
165        cc_toolchain = cc_toolchain,
166        requested_features = features,
167        unsupported_features = ctx.disabled_features,
168    )
169
170    linking_outputs = cc_common.link(
171        name = ctx.label.name,
172        actions = ctx.actions,
173        stamp = stamp,
174        feature_configuration = feature_configuration,
175        cc_toolchain = cc_toolchain,
176        linking_contexts = linking_contexts,
177        user_link_flags = user_link_flags,
178        output_type = "executable",
179        additional_outputs = additional_outputs,
180    )
181
182    output_files = depset(
183        [linking_outputs.executable] + additional_outputs,
184        transitive = [],
185    )
186    return [DefaultInfo(files = output_files, executable = linking_outputs.executable)]
187