xref: /aosp_15_r20/external/skia/bazel/skia_rules.bzl (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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