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