1""" 2THIS IS THE EXTERNAL-ONLY VERSION OF THIS FILE. G3 HAS ITS OWN. 3 4This file contains macros which require no third-party dependencies. 5Using these where possible makes it easier for clients to use Skia 6without needing to download a bunch of unnecessary dependencies 7in their WORKSPACE.bazel file. 8""" 9 10load("@skia_user_config//:copts.bzl", "DEFAULT_COPTS", "DEFAULT_OBJC_COPTS") 11load("@skia_user_config//:linkopts.bzl", "DEFAULT_LINKOPTS") 12load( 13 "//bazel:generate_cpp_files_for_headers.bzl", 14 _generate_cpp_files_for_headers = "generate_cpp_files_for_headers", 15) 16 17generate_cpp_files_for_headers = _generate_cpp_files_for_headers 18 19def select_multi(values_map, default_cases = None): 20 """select() but allowing multiple matches of the keys. 21 22 select_multi works around a restriction in native select() that prevents multiple 23 keys from being matched unless one is a strict subset of another. For some features, 24 we allow multiple of that component to be active. For example, with codecs, we let 25 the clients mix and match anywhere from 0 built in codecs to all of them. 26 27 select_multi takes a given map and turns it into several distinct select statements 28 that have the effect of using any values associated with any active keys. 29 For example, if the following parameter is passed in: 30 values_map = { 31 ":alpha": ["apple", "apricot"], 32 ":beta": ["banana"], 33 ":gamma": ["grapefruit"], 34 } 35 it will be unrolled into the following select statements 36 [] + select({ 37 ":apple": ["apple", "apricot"], 38 "//conditions:default": [], 39 }) + select({ 40 ":beta": ["banana"], 41 "//conditions:default": [], 42 }) + select({ 43 ":gamma": ["grapefruit"], 44 "//conditions:default": [], 45 }) 46 47 Args: 48 values_map: dictionary of labels to a list of labels, just like select() 49 default_cases: dictionary of labels to a list of labels to be used in the default case. 50 If not provided or a key is not mentioned, an empty list will be used. 51 52 Returns: 53 A list of values that is filled in by the generated select statements. 54 """ 55 if len(values_map) == 0: 56 return [] 57 rv = [] 58 if not default_cases: 59 default_cases = {} 60 for key, value in values_map.items(): 61 rv += select({ 62 key: value, 63 "//conditions:default": default_cases.get(key, []), 64 }) 65 return rv 66 67def supports_platforms(*platforms): 68 """Convenience macro to set the "target_compatible_with" argument of binary and test targets. 69 70 The example below shows a binary that is compatible with all desktop OSes: 71 72 skia_cc_binary( 73 name = "my_binary", 74 target_compatible_with = supports_platforms( 75 "@platforms//os:linux", 76 "@platforms//os:windows", 77 "@platforms//os:macos", 78 ), 79 ... 80 ) 81 82 Args: 83 *platforms: One or more supported platforms, e.g. "@platforms//os:linux". 84 Returns: 85 A select() statement with an empty list for each provided platform, and 86 ["@platforms//:incompatible"] as the default condition. 87 """ 88 if len(platforms) == 0: 89 fail("Please provide at least one platform.") 90 91 platforms_map = { 92 "//conditions:default": ["@platforms//:incompatible"], 93 } 94 for platform in platforms: 95 platforms_map[platform] = [] 96 return select(platforms_map) 97 98def skia_cc_binary(name, copts = DEFAULT_COPTS, linkopts = DEFAULT_LINKOPTS, **kwargs): 99 """A wrapper around cc_library for Skia C++ executables (e.g. tools). 100 101 This lets us provide compiler flags (copts) and global linker flags (linkopts) consistently 102 to Skia built executables. These executables are almost always things like dev tools. 103 104 Args: 105 name: the name of the underlying executable. 106 copts: Flags which should be passed to the C++ compiler. By default, we use DEFAULT_COPTS 107 from @skia_user_config//:copts.bzl. 108 linkopts: Global flags which should be passed to the C++ linker. By default, we use 109 DEFAULT_LINKOPTS from @skia_user_config//:linkopts.bzl. Other linker flags will be 110 passed in via deps (see deps_and_linkopts below). 111 **kwargs: All the normal arguments that cc_binary takes. 112 """ 113 native.cc_binary(name = name, copts = copts, linkopts = linkopts, **kwargs) 114 115def skia_cc_test(name, copts = DEFAULT_COPTS, linkopts = DEFAULT_LINKOPTS, **kwargs): 116 """A wrapper around cc_test for Skia C++ executables (e.g. tests). 117 118 This lets us provide compiler flags (copts) and global linker flags (linkopts) consistently 119 to Skia built executables, that is, tests. 120 121 Args: 122 name: the name of the underlying executable. 123 copts: Flags which should be passed to the C++ compiler. By default, we use DEFAULT_COPTS 124 from @skia_user_config//:copts.bzl. 125 linkopts: Global flags which should be passed to the C++ linker. By default, we use 126 DEFAULT_LINKOPTS from @skia_user_config//:linkopts.bzl. Other linker flags will be 127 passed in via deps (see deps_and_linkopts below). 128 **kwargs: All the normal arguments that cc_binary takes. 129 """ 130 native.cc_test(name = name, copts = copts, linkopts = linkopts, **kwargs) 131 132def skia_cc_library(name, copts = DEFAULT_COPTS, local_defines = [], **kwargs): 133 """A wrapper around cc_library for Skia C++ libraries. 134 135 This lets us provide compiler flags (copts) consistently to the Skia build. By default, 136 copts do not flow up the dependency stack. Additionally, in G3, this allows us to set 137 some options universally. 138 139 It also lets us easily tweak these settings when being built in G3. 140 141 Third party libraries should *not* use this directly, as there are likely some flags used 142 by Skia (e.g. warnings) that we do not want to have to fix for third party code. 143 144 Args: 145 name: the name of the underlying library. 146 copts: Flags which should be passed to the C++ compiler. By default, we use DEFAULT_COPTS 147 from @skia_user_config//:copts.bzl. 148 local_defines: Defines set when compiling this library, but not dependents. We 149 add a define to all our libraries to correctly export/import symbols. 150 **kwargs: All the normal arguments that cc_library takes. 151 """ 152 153 # This allows us to mark APIs as exported when building this 154 # as a library, but the APIs will be marked as an import 155 # (the default) when clients try to use our headers. See SkAPI.h for more. 156 # We have to create a new (mutable) list since if the client passes in a list 157 # it will be immutable ("frozen"). 158 ld = [] 159 ld.extend(local_defines) 160 ld.append("SKIA_IMPLEMENTATION=1") 161 native.cc_library(name = name, copts = copts, local_defines = ld, **kwargs) 162 163def skia_filegroup(**kwargs): 164 """A wrapper around filegroup allowing us to customize visibility in G3.""" 165 native.filegroup(**kwargs) 166 167def skia_objc_library( 168 name, 169 copts = DEFAULT_OBJC_COPTS, 170 deps = [], 171 ios_frameworks = [], 172 mac_frameworks = [], 173 sdk_frameworks = [], 174 **kwargs): 175 """A wrapper around objc_library for Skia Objective C libraries. 176 177 This lets us provide compiler flags (copts) consistently to the Skia build (e.g. //:core) 178 and builds which depend on those targets (e.g. things in //tools or //modules). 179 180 It also lets us easily tweak these settings when being built in G3. 181 Args: 182 name: the name of the underlying target. 183 copts: Flags which should be passed to the C++ compiler. By default, we use 184 DEFAULT_OBJC_COPTS from @skia_user_config//:copts.bzl. 185 deps: https://bazel.build/reference/be/objective-c#objc_library.deps 186 ios_frameworks: A list (not select) of iOS-specific Frameworks. 187 mac_frameworks: A list (not select) of Mac-specific Frameworks. 188 sdk_frameworks: https://bazel.build/reference/be/objective-c#objc_library.sdk_frameworks 189 except this should only be a list, not a select. 190 **kwargs: Normal arguments to objc_library 191 """ 192 if len(ios_frameworks) > 0 or len(mac_frameworks) > 0: 193 sdk_frameworks += select({ 194 "@platforms//os:ios": ios_frameworks, 195 "@platforms//os:macos": mac_frameworks, 196 "//conditions:default": [], 197 }) 198 199 native.objc_library( 200 name = name, 201 copts = copts, 202 deps = deps, 203 sdk_frameworks = sdk_frameworks, 204 **kwargs 205 ) 206 207def split_srcs_and_hdrs(name, files, visibility = None): 208 """Take a list of files and creates filegroups for C++ sources and headers. 209 210 The "_srcs" and "_hdrs" filegroups will only be created if there are a non-zero amount 211 of files of both types. Otherwise, it will fail because we do not need the macro. 212 213 Args: 214 name: The prefix of the generated filegroups. One will have the suffix "_srcs" and 215 the other "_hdrs". 216 files: List of file names, e.g. ["SkAAClip.cpp", "SkAAClip.h"] 217 visibility: Optional list of visibility rules 218 """ 219 srcs = [] 220 hdrs = [] 221 for f in files: 222 if f.endswith(".cpp"): 223 srcs.append(f) 224 elif f.endswith(".mm"): 225 srcs.append(f) 226 elif f.endswith(".h"): 227 hdrs.append(f) 228 else: 229 fail("Neither .cpp, .mm, nor .h file " + f) 230 231 if len(srcs) == 0 or len(hdrs) == 0: 232 fail("The list consist of either only source or header files. No need to use this macro.") 233 234 skia_filegroup( 235 name = name + "_srcs", 236 srcs = srcs, 237 visibility = visibility, 238 ) 239 skia_filegroup( 240 name = name + "_hdrs", 241 srcs = hdrs, 242 visibility = visibility, 243 ) 244