• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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