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