• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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")
19load("@rules_cc//cc/common:cc_common.bzl", "cc_common")
20load("@rules_cc//cc/common:cc_info.bzl", "CcInfo")
21
22def _print_platform_impl(_, ctx):
23    if hasattr(ctx.rule.attr, "constraint_values"):
24        for cv in ctx.rule.attr.constraint_values:
25            # buildifier: disable=print
26            print(str(ctx.rule.attr.name) + " specifies " + str(cv))
27    return []
28
29print_platform = aspect(
30    implementation = _print_platform_impl,
31    attr_aspects = ["parents"],
32    doc = """
33        This is a little debug utility that traverses the platform inheritance
34        hierarchy and prints all the constraint values.
35
36        Example usage:
37
38        bazel build \
39          //targets/lm3s6965evb \
40          --aspects \
41          pw_build/bazel_internal/pigweed_internal.bzl%print_platform
42    """,
43)
44
45# TODO: https://github.com/bazelbuild/bazel/issues/16546 - Use
46# cc_helper.is_compilation_outputs_empty() if/when it's available for
47# end-users.
48def _is_compilation_outputs_empty(compilation_outputs):
49    return (len(compilation_outputs.pic_objects) == 0 and
50            len(compilation_outputs.objects) == 0)
51
52def compile_cc(
53        ctx,
54        srcs,
55        hdrs,
56        deps,
57        includes = [],
58        defines = [],
59        local_defines = [],
60        user_compile_flags = [],
61        alwayslink = False):
62    """Compiles a list C++ source files.
63
64    Args:
65        ctx: Rule context
66        srcs: List of C/C++ source files to compile
67        hdrs: List of C/C++ header files to compile with
68        deps: Dependencies to link with
69        includes: List of include paths
70        defines: List of preprocessor defines to use
71        local_defines: List of preprocessor defines to use only on this unit.
72        user_compile_flags: Extra compiler flags to pass when compiling.
73        alwayslink: Whether this library should always be linked.
74
75    Returns:
76      A CcInfo provider.
77    """
78    cc_toolchain = find_cpp_toolchain(ctx)
79    feature_configuration = cc_common.configure_features(
80        ctx = ctx,
81        cc_toolchain = cc_toolchain,
82        requested_features = ctx.features,
83        unsupported_features = ctx.disabled_features,
84    )
85
86    compilation_contexts = [dep[CcInfo].compilation_context for dep in deps]
87    compilation_context, compilation_outputs = cc_common.compile(
88        name = ctx.label.name,
89        actions = ctx.actions,
90        feature_configuration = feature_configuration,
91        cc_toolchain = cc_toolchain,
92        srcs = srcs,
93        includes = includes,
94        defines = defines,
95        local_defines = local_defines,
96        public_hdrs = hdrs,
97        user_compile_flags = user_compile_flags,
98        compilation_contexts = compilation_contexts,
99    )
100
101    linking_contexts = [dep[CcInfo].linking_context for dep in deps]
102
103    # If there's no compiled artifacts (i.e. the library is header-only), don't
104    # try and link a library.
105    #
106    # TODO: https://github.com/bazelbuild/bazel/issues/18095 - Remove this
107    # if create_linking_context_from_compilation_outputs() is changed to no
108    # longer require this workaround.
109    if not _is_compilation_outputs_empty(compilation_outputs):
110        linking_context, link_outputs = cc_common.create_linking_context_from_compilation_outputs(
111            actions = ctx.actions,
112            feature_configuration = feature_configuration,
113            cc_toolchain = cc_toolchain,
114            compilation_outputs = compilation_outputs,
115            linking_contexts = linking_contexts,
116            disallow_dynamic_library = True,
117            alwayslink = alwayslink,
118            name = ctx.label.name,
119        )
120
121        if link_outputs.library_to_link != None:
122            linking_contexts.append(linking_context)
123
124    return [
125        CcInfo(
126            compilation_context = compilation_context,
127            linking_context = cc_common.merge_linking_contexts(
128                linking_contexts = linking_contexts,
129            ),
130        ),
131    ]
132
133# From cc_helper.bzl. Feature names for static/dynamic linking.
134linker_mode = struct(
135    LINKING_DYNAMIC = "dynamic_linking_mode",
136    LINKING_STATIC = "static_linking_mode",
137)
138
139def link_cc(
140        ctx,
141        linking_contexts,
142        linkstatic,
143        stamp,
144        user_link_flags = [],
145        additional_outputs = []):
146    """Links a binary and allows custom linker output.
147
148    Args:
149        ctx: Rule context
150        linking_contexts: Dependencies to link with
151        linkstatic: True if binary should be linked statically.
152        stamp: Stamp behavior for linking.
153        user_link_flags: Extra linker flags to pass when linking
154        additional_outputs: Extra files generated by link
155
156    Returns:
157      DefaultInfo of output files
158    """
159    cc_toolchain = find_cpp_toolchain(ctx)
160    features = ctx.features
161    linking_mode = linker_mode.LINKING_STATIC
162    if not linkstatic:
163        linking_mode = linker_mode.LINKING_DYNAMIC
164    features.append(linking_mode)
165    feature_configuration = cc_common.configure_features(
166        ctx = ctx,
167        cc_toolchain = cc_toolchain,
168        requested_features = features,
169        unsupported_features = ctx.disabled_features,
170    )
171
172    linking_outputs = cc_common.link(
173        name = ctx.label.name,
174        actions = ctx.actions,
175        stamp = stamp,
176        feature_configuration = feature_configuration,
177        cc_toolchain = cc_toolchain,
178        linking_contexts = linking_contexts,
179        user_link_flags = user_link_flags,
180        output_type = "executable",
181        additional_outputs = additional_outputs,
182    )
183
184    output_files = depset(
185        [linking_outputs.executable] + additional_outputs,
186        transitive = [],
187    )
188    return [DefaultInfo(files = output_files, executable = linking_outputs.executable)]
189