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("//bazel:cc_binary_with_flags.bzl", "cc_binary_with_flags") 13load( 14 "//bazel:generate_cpp_files_for_headers.bzl", 15 _generate_cpp_files_for_headers = "generate_cpp_files_for_headers", 16) 17 18generate_cpp_files_for_headers = _generate_cpp_files_for_headers 19 20def select_multi(values_map, default_cases = None): 21 """select() but allowing multiple matches of the keys. 22 23 select_multi works around a restriction in native select() that prevents multiple 24 keys from being matched unless one is a strict subset of another. For some features, 25 we allow multiple of that component to be active. For example, with codecs, we let 26 the clients mix and match anywhere from 0 built in codecs to all of them. 27 28 select_multi takes a given map and turns it into several distinct select statements 29 that have the effect of using any values associated with any active keys. 30 For example, if the following parameter is passed in: 31 values_map = { 32 ":alpha": ["apple", "apricot"], 33 ":beta": ["banana"], 34 ":gamma": ["grapefruit"], 35 } 36 it will be unrolled into the following select statements 37 [] + select({ 38 ":apple": ["apple", "apricot"], 39 "//conditions:default": [], 40 }) + select({ 41 ":beta": ["banana"], 42 "//conditions:default": [], 43 }) + select({ 44 ":gamma": ["grapefruit"], 45 "//conditions:default": [], 46 }) 47 48 Args: 49 values_map: dictionary of labels to a list of labels, just like select() 50 default_cases: dictionary of labels to a list of labels to be used in the default case. 51 If not provided or a key is not mentioned, an empty list will be used. 52 53 Returns: 54 A list of values that is filled in by the generated select statements. 55 """ 56 if len(values_map) == 0: 57 return [] 58 rv = [] 59 if not default_cases: 60 default_cases = {} 61 for key, value in values_map.items(): 62 rv += select({ 63 key: value, 64 "//conditions:default": default_cases.get(key, []), 65 }) 66 return rv 67 68def supports_platforms(*platforms): 69 """Convenience macro to set the "target_compatible_with" argument of binary and test targets. 70 71 The example below shows a binary that is compatible with all desktop OSes: 72 73 skia_cc_binary( 74 name = "my_binary", 75 target_compatible_with = supports_platforms( 76 "@platforms//os:linux", 77 "@platforms//os:windows", 78 "@platforms//os:macos", 79 ), 80 ... 81 ) 82 83 Args: 84 *platforms: One or more supported platforms, e.g. "@platforms//os:linux". 85 Returns: 86 A select() statement with an empty list for each provided platform, and 87 ["@platforms//:incompatible"] as the default condition. 88 """ 89 if len(platforms) == 0: 90 fail("Please provide at least one platform.") 91 92 platforms_map = { 93 "//conditions:default": ["@platforms//:incompatible"], 94 } 95 for platform in platforms: 96 platforms_map[platform] = [] 97 return select(platforms_map) 98 99def skia_cc_binary(name, copts = DEFAULT_COPTS, linkopts = DEFAULT_LINKOPTS, **kwargs): 100 """A wrapper around cc_library for Skia C++ executables (e.g. tools). 101 102 This lets us provide compiler flags (copts) and global linker flags (linkopts) consistently 103 to Skia built executables. These executables are almost always things like dev tools. 104 105 Args: 106 name: the name of the underlying executable. 107 copts: Flags which should be passed to the C++ compiler. By default, we use DEFAULT_COPTS 108 from @skia_user_config//:copts.bzl. 109 linkopts: Global flags which should be passed to the C++ linker. By default, we use 110 DEFAULT_LINKOPTS from @skia_user_config//:linkopts.bzl. Other linker flags will be 111 passed in via deps (see deps_and_linkopts below). 112 **kwargs: All the normal arguments that cc_binary takes. 113 """ 114 native.cc_binary(name = name, copts = copts, linkopts = linkopts, **kwargs) 115 116def skia_cc_test(name, copts = DEFAULT_COPTS, linkopts = DEFAULT_LINKOPTS, **kwargs): 117 """A wrapper around cc_test for Skia C++ executables (e.g. tests). 118 119 This lets us provide compiler flags (copts) and global linker flags (linkopts) consistently 120 to Skia built executables, that is, tests. 121 122 Args: 123 name: the name of the underlying executable. 124 copts: Flags which should be passed to the C++ compiler. By default, we use DEFAULT_COPTS 125 from @skia_user_config//:copts.bzl. 126 linkopts: Global flags which should be passed to the C++ linker. By default, we use 127 DEFAULT_LINKOPTS from @skia_user_config//:linkopts.bzl. Other linker flags will be 128 passed in via deps (see deps_and_linkopts below). 129 **kwargs: All the normal arguments that cc_binary takes. 130 """ 131 native.cc_test(name = name, copts = copts, linkopts = linkopts, **kwargs) 132 133def skia_cc_binary_with_flags( 134 name, 135 copts = DEFAULT_COPTS, 136 linkopts = DEFAULT_LINKOPTS, 137 set_flags = None, 138 **kwargs): 139 cc_binary_with_flags( 140 name = name, 141 copts = copts, 142 linkopts = linkopts, 143 set_flags = set_flags, 144 **kwargs 145 ) 146 147def skia_cc_library(name, copts = DEFAULT_COPTS, local_defines = [], **kwargs): 148 """A wrapper around cc_library for Skia C++ libraries. 149 150 This lets us provide compiler flags (copts) consistently to the Skia build (e.g. //:skia_public) 151 and builds which depend on those targets (e.g. things in //tools or //modules). 152 153 It also lets us easily tweak these settings when being built in G3. 154 155 Third party libraries should *not* use this directly, as there are likely some flags used 156 by Skia (e.g. warnings) that we do not want to have to fix for third party code. 157 158 Args: 159 name: the name of the underlying library. 160 copts: Flags which should be passed to the C++ compiler. By default, we use DEFAULT_COPTS 161 from @skia_user_config//:copts.bzl. 162 local_defines: Defines set when compiling this library, but not dependents. We 163 add a define to all our libraries to correctly export/import symbols. 164 **kwargs: All the normal arguments that cc_library takes. 165 """ 166 167 # This allows us to mark APIs as exported when building this 168 # as a library, but the APIs will be marked as an import 169 # (the default) when clients try to use our headers. See SkAPI.h for more. 170 # We have to create a new (mutable) list since if the client passes in a list 171 # it will be immutable ("frozen"). 172 ld = [] 173 ld.extend(local_defines) 174 ld.append("SKIA_IMPLEMENTATION=1") 175 native.cc_library(name = name, copts = copts, local_defines = ld, **kwargs) 176 177def skia_cc_deps(name, visibility, deps = [], linkopts = [], textual_hdrs = [], testonly = False): 178 """A self-documenting wrapper around cc_library for things to pass to the top skia_cc_library. 179 180 It lets us have third_party deps, linkopts, etc be set close to where they impact, 181 and trickle up the file hierarchy to //:skia_public and //:skia_internal 182 183 Args: 184 name: the name of the underlying target. By convention, this is usually called "deps". 185 visibility: To prevent this rule from being used where it should not, we have the 186 convention of setting the visibility to just the parent package. 187 deps: A list of labels or select statements to collect third_party dependencies. 188 linkopts: A list of strings or select statements to collect linker flags. 189 textual_hdrs: A list of labels or select statements to collect files which are included, but 190 do not have a suffix of .h, like a typical C++ header does. 191 testonly: A boolean that, if true, will enforce all targets who depend on this are also 192 marked as testonly. 193 """ 194 native.cc_library( 195 name = name, 196 visibility = visibility, 197 deps = deps, 198 linkopts = linkopts, 199 textual_hdrs = textual_hdrs, 200 testonly = testonly, 201 ) 202 203def skia_filegroup(**kwargs): 204 """A wrapper around filegroup allowing us to customize visibility in G3.""" 205 native.filegroup(**kwargs) 206 207def skia_objc_library( 208 name, 209 copts = DEFAULT_OBJC_COPTS, 210 deps = [], 211 ios_frameworks = [], 212 mac_frameworks = [], 213 sdk_frameworks = [], 214 **kwargs): 215 """A wrapper around objc_library for Skia Objective C libraries. 216 217 This lets us provide compiler flags (copts) consistently to the Skia build (e.g. //:skia_public) 218 and builds which depend on those targets (e.g. things in //tools or //modules). 219 220 It also lets us easily tweak these settings when being built in G3. 221 Args: 222 name: the name of the underlying target. 223 copts: Flags which should be passed to the C++ compiler. By default, we use 224 DEFAULT_OBJC_COPTS from @skia_user_config//:copts.bzl. 225 deps: https://bazel.build/reference/be/objective-c#objc_library.deps 226 ios_frameworks: A list (not select) of iOS-specific Frameworks. 227 mac_frameworks: A list (not select) of Mac-specific Frameworks. 228 sdk_frameworks: https://bazel.build/reference/be/objective-c#objc_library.sdk_frameworks 229 except this should only be a list, not a select. 230 **kwargs: Normal arguments to objc_library 231 """ 232 if len(ios_frameworks) > 0 or len(mac_frameworks) > 0: 233 sdk_frameworks += select({ 234 "@platforms//os:ios": ios_frameworks, 235 "@platforms//os:macos": mac_frameworks, 236 "//conditions:default": [], 237 }) 238 239 native.objc_library( 240 name = name, 241 copts = copts, 242 deps = deps, 243 sdk_frameworks = sdk_frameworks, 244 **kwargs 245 ) 246 247# buildifier: disable=unnamed-macro 248def exports_files_legacy(label_list = None, visibility = None): 249 """A self-annotating macro to export all files in this package for legacy G3 rules. 250 251 Args: 252 label_list: If provided, this will act like a normal exports_files rule. If not 253 provided, nothing happens. 254 visibility: Should be provided if label_list is set 255 """ 256 if label_list: 257 native.exports_files(label_list, visibility = visibility) 258 259def split_srcs_and_hdrs(name, files): 260 """Take a list of files and creates filegroups for C++ sources and headers. 261 262 The reason we make filegroups is that they are more friendly towards a file being 263 listed twice than just returning a sorted list of files. 264 265 For example, in //src/codecs, "SkEncodedInfo.cpp" is needed for some, but not all 266 the codecs. It is easier for devs to list the file for the codecs that need it 267 rather than making a complicated select statement to make sure it is only in the 268 list of files once. 269 270 Bazel is smart enough to not compile the same file twice, even if it shows up in 271 multiple filegroups. 272 273 The "_srcs" and "_hdrs" filegroups will only be created if there are a non-zero amount 274 of files of both types. Otherwise, it will fail because we do not need the macro. 275 276 Args: 277 name: The prefix of the generated filegroups. One will have the suffix "_srcs" and 278 the other "_hdrs". 279 files: List of file names, e.g. ["SkAAClip.cpp", "SkAAClip.h"] 280 """ 281 srcs = [] 282 hdrs = [] 283 for f in files: 284 if f.endswith(".cpp"): 285 srcs.append(f) 286 elif f.endswith(".mm"): 287 srcs.append(f) 288 elif f.endswith(".h"): 289 hdrs.append(f) 290 else: 291 fail("Neither .cpp, .mm, nor .h file " + f) 292 293 if len(srcs) == 0 or len(hdrs) == 0: 294 fail("The list consist of either only source or header files. No need to use this macro.") 295 296 skia_filegroup( 297 name = name + "_srcs", 298 srcs = srcs, 299 ) 300 skia_filegroup( 301 name = name + "_hdrs", 302 srcs = hdrs, 303 ) 304