xref: /aosp_15_r20/external/skia/toolchain/windows_toolchain_config.bzl (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1"""
2This file specifies a clang toolchain that can run on a Windows host.
3
4See download_windows_toolchain.bzl for more details on the creation of the toolchain.
5
6It uses the usr subfolder of the built toolchain as a sysroot
7
8It follows the example of:
9 - linux_amd64_toolchain_config.bzl
10"""
11
12# https://github.com/bazelbuild/bazel/blob/master/tools/build_defs/cc/action_names.bzl
13load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES")
14
15# https://github.com/bazelbuild/bazel/blob/master/tools/cpp/cc_toolchain_config_lib.bzl
16load(
17    "@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl",
18    "action_config",
19    "feature",
20    "flag_group",
21    "flag_set",
22    "tool",
23    "variable_with_value",
24)
25
26# TODO(borenet): These variables were copied from the automatically-generated
27# @clang_windows_amd64//:vars.bzl file. They are available to be directly
28# used here, but in order to do so, Bazel needs access to both the Clang and
29# MSVC archives, even when we aren't going to use this toolchain. Due to the
30# time required to download and extract these archives, we've opted to hard-code
31# the versions and paths here.
32#load("@clang_windows_amd64//:vars.bzl", "MSVC_INCLUDE", "MSVC_LIB", "WIN_SDK_INCLUDE", "WIN_SDK_LIB")
33MSVC_VERSION = "14.39.33519"
34MSVC_INCLUDE = "VC/Tools/MSVC/" + MSVC_VERSION + "/include"
35MSVC_LIB = "VC/Tools/MSVC/" + MSVC_VERSION + "/lib"
36WIN_SDK_VERSION = "10.0.22621.0"
37WIN_SDK_INCLUDE = "win_sdk/Include/" + WIN_SDK_VERSION
38WIN_SDK_LIB = "win_sdk/Lib/" + WIN_SDK_VERSION
39
40# The location of the downloaded clang toolchain.
41CLANG_TOOLCHAIN = "external/clang_windows_amd64"
42
43# Paths inside the win_toolchain CIPD package.
44FULL_MSVC_INCLUDE = CLANG_TOOLCHAIN + "/" + MSVC_INCLUDE
45FULL_MSVC_LIB = CLANG_TOOLCHAIN + "/" + MSVC_LIB
46FULL_WIN_SDK_INCLUDE = CLANG_TOOLCHAIN + "/" + WIN_SDK_INCLUDE
47FULL_WIN_SDK_LIB = CLANG_TOOLCHAIN + "/" + WIN_SDK_LIB
48
49def _windows_amd64_toolchain_info(ctx):
50    action_configs = _make_action_configs()
51    features = [
52        feature(
53            name = "archive_param_file",
54            enabled = True,
55        ),
56    ]
57    features += _make_default_flags()
58    features += _make_diagnostic_flags()
59
60    # https://bazel.build/rules/lib/cc_common#create_cc_toolchain_config_info
61    # Note, this rule is defined in Java code, not Starlark
62    # https://cs.opensource.google/bazel/bazel/+/master:src/main/java/com/google/devtools/build/lib/starlarkbuildapi/cpp/CcModuleApi.java
63    return cc_common.create_cc_toolchain_config_info(
64        ctx = ctx,
65        features = features,
66        action_configs = action_configs,
67        # These are required, but do nothing
68        compiler = "",
69        target_cpu = "",
70        target_libc = "",
71        target_system_name = "",
72        toolchain_identifier = "",
73    )
74
75provide_windows_amd64_toolchain_config = rule(
76    attrs = {},
77    provides = [CcToolchainConfigInfo],
78    implementation = _windows_amd64_toolchain_info,
79)
80
81def _make_action_configs():
82    """
83    This function sets up the tools needed to perform the various compile/link actions.
84
85    Bazel normally restricts us to referring to (and therefore running) executables/scripts
86    that are in this directory (That is EXEC_ROOT/toolchain). However, the executables we want
87    to run are brought in via WORKSPACE.bazel and are located in EXEC_ROOT/external/clang....
88    Therefore, we make use of "trampoline scripts" that will call the binaries from the
89    toolchain directory.
90
91    These action_configs also let us dynamically specify arguments from the Bazel
92    environment if necessary (see cpp_link_static_library_action).
93    """
94
95    # https://cs.opensource.google/bazel/bazel/+/master:tools/cpp/cc_toolchain_config_lib.bzl;l=435;drc=3b9e6f201a9a3465720aad8712ab7bcdeaf2e5da
96    clang_tool = tool(path = "windows_trampolines/clang_trampoline_windows.bat")
97    ar_tool = tool(path = "windows_trampolines/ar_trampoline_windows.bat")
98
99    # https://cs.opensource.google/bazel/bazel/+/master:tools/cpp/cc_toolchain_config_lib.bzl;l=488;drc=3b9e6f201a9a3465720aad8712ab7bcdeaf2e5da
100    assemble_action = action_config(
101        action_name = ACTION_NAMES.assemble,
102        tools = [clang_tool],
103    )
104    c_compile_action = action_config(
105        action_name = ACTION_NAMES.c_compile,
106        tools = [clang_tool],
107    )
108    cpp_compile_action = action_config(
109        action_name = ACTION_NAMES.cpp_compile,
110        tools = [clang_tool],
111    )
112    linkstamp_compile_action = action_config(
113        action_name = ACTION_NAMES.linkstamp_compile,
114        tools = [clang_tool],
115    )
116    preprocess_assemble_action = action_config(
117        action_name = ACTION_NAMES.preprocess_assemble,
118        tools = [clang_tool],
119    )
120
121    cpp_link_dynamic_library_action = action_config(
122        action_name = ACTION_NAMES.cpp_link_dynamic_library,
123        tools = [clang_tool],
124    )
125    cpp_link_executable_action = action_config(
126        action_name = ACTION_NAMES.cpp_link_executable,
127        # Bazel assumes it is talking to clang when building an executable. There are
128        # "-Wl" flags on the command: https://releases.llvm.org/6.0.1/tools/clang/docs/ClangCommandLineReference.html#cmdoption-clang-Wl
129        tools = [clang_tool],
130    )
131    cpp_link_nodeps_dynamic_library_action = action_config(
132        action_name = ACTION_NAMES.cpp_link_nodeps_dynamic_library,
133        tools = [clang_tool],
134    )
135
136    # By default, there are no flags or libraries passed to the llvm-ar tool, so
137    # we need to specify them. The variables mentioned by expand_if_available are defined
138    # https://bazel.build/docs/cc-toolchain-config-reference#cctoolchainconfiginfo-build-variables
139    cpp_link_static_library_action = action_config(
140        action_name = ACTION_NAMES.cpp_link_static_library,
141        flag_sets = [
142            flag_set(
143                flag_groups = [
144                    flag_group(
145                        # https://llvm.org/docs/CommandGuide/llvm-ar.html
146                        # replace existing files or insert them if they already exist,
147                        # create the file if it doesn't already exist
148                        # symbol table should be added
149                        # Deterministic timestamps should be used
150                        flags = ["rcsD", "%{output_execpath}"],
151                        # Despite the name, output_execpath just refers to linker output,
152                        # e.g. libFoo.a
153                        expand_if_available = "output_execpath",
154                    ),
155                ],
156            ),
157            flag_set(
158                flag_groups = [
159                    flag_group(
160                        iterate_over = "libraries_to_link",
161                        flag_groups = [
162                            flag_group(
163                                flags = ["%{libraries_to_link.name}"],
164                                expand_if_equal = variable_with_value(
165                                    name = "libraries_to_link.type",
166                                    value = "object_file",
167                                ),
168                            ),
169                            flag_group(
170                                flags = ["%{libraries_to_link.object_files}"],
171                                iterate_over = "libraries_to_link.object_files",
172                                expand_if_equal = variable_with_value(
173                                    name = "libraries_to_link.type",
174                                    value = "object_file_group",
175                                ),
176                            ),
177                        ],
178                        expand_if_available = "libraries_to_link",
179                    ),
180                ],
181            ),
182            flag_set(
183                flag_groups = [
184                    flag_group(
185                        flags = ["@%{archive_param_file}"],
186                        expand_if_available = "archive_param_file",
187                    ),
188                ],
189            ),
190        ],
191        tools = [ar_tool],
192    )
193
194    action_configs = [
195        assemble_action,
196        c_compile_action,
197        cpp_compile_action,
198        cpp_link_dynamic_library_action,
199        cpp_link_executable_action,
200        cpp_link_nodeps_dynamic_library_action,
201        cpp_link_static_library_action,
202        linkstamp_compile_action,
203        preprocess_assemble_action,
204    ]
205    return action_configs
206
207def _make_default_flags():
208    """Here we define the flags for certain actions that are always applied.
209
210    For any flag that might be conditionally applied, it should be defined in //bazel/copts.bzl.
211
212    Flags that are set here will be unconditionally applied to everything we compile with
213    this toolchain, even third_party deps.
214    """
215
216    # Note: These values must be kept in sync with those defined in cmake_exporter.go.
217    cxx_compile_includes = flag_set(
218        actions = [
219            ACTION_NAMES.c_compile,
220            ACTION_NAMES.cpp_compile,
221        ],
222        flag_groups = [
223            flag_group(
224                flags = [
225                    # THIS ORDER MATTERS GREATLY. If these are in the wrong order, the
226                    # #include_next directives will fail to find the files, causing a compilation
227                    # error (or, without -no-canonical-prefixes, a mysterious case where files
228                    # are included with an absolute path and fail the build).
229                    "-isystem",
230                    CLANG_TOOLCHAIN + "/include/clang",
231                    "-isystem",
232                    CLANG_TOOLCHAIN + "/include/clang-c",
233                    "-isystem",
234                    CLANG_TOOLCHAIN + "/include/clang-tidy",
235                    "-isystem",
236                    CLANG_TOOLCHAIN + "/include/lld",
237                    "-isystem",
238                    CLANG_TOOLCHAIN + "/include/lldb",
239                    "-isystem",
240                    CLANG_TOOLCHAIN + "/include/llvm",
241                    "-isystem",
242                    CLANG_TOOLCHAIN + "/include/llvm-c",
243                    "-isystem",
244                    CLANG_TOOLCHAIN + "/lib/clang/18/include",
245                    "-isystem",
246                    FULL_WIN_SDK_INCLUDE + "/shared",
247                    "-isystem",
248                    FULL_WIN_SDK_INCLUDE + "/ucrt",
249                    "-isystem",
250                    FULL_WIN_SDK_INCLUDE + "/um",
251                    "-isystem",
252                    FULL_WIN_SDK_INCLUDE + "/winrt",
253                    "-isystem",
254                    FULL_WIN_SDK_INCLUDE + "/cppwinrt",
255                    "-isystem",
256                    FULL_MSVC_INCLUDE,
257                    # We do not want clang to search in absolute paths for files. This makes
258                    # Bazel think we are using an outside resource and fail the compile.
259                    "-no-canonical-prefixes",
260                ],
261            ),
262        ],
263    )
264
265    cpp_compile_flags = flag_set(
266        actions = [
267            ACTION_NAMES.cpp_compile,
268        ],
269        flag_groups = [
270            flag_group(
271                flags = [
272                    "-std=c++17",
273                ],
274            ),
275        ],
276    )
277
278    link_exe_flags = flag_set(
279        actions = [
280            ACTION_NAMES.cpp_link_executable,
281            ACTION_NAMES.cpp_link_dynamic_library,
282            ACTION_NAMES.cpp_link_nodeps_dynamic_library,
283        ],
284        flag_groups = [
285            flag_group(
286                flags = [
287                    "-fuse-ld=lld",
288                    # We chose to use the llvm runtime, not the gcc one because it is already
289                    # included in the clang binary
290                    "--rtlib=compiler-rt",
291                    "-std=c++17",
292                    "-L" + FULL_MSVC_LIB + "/x64",
293                    "-L" + FULL_WIN_SDK_LIB + "/ucrt/x64",
294                    "-L" + FULL_WIN_SDK_LIB + "/um/x64",
295                ],
296            ),
297        ],
298    )
299    return [feature(
300        "default_flags",
301        enabled = True,
302        flag_sets = [
303            cxx_compile_includes,
304            cpp_compile_flags,
305            link_exe_flags,
306        ],
307    )]
308
309def _make_diagnostic_flags():
310    """Here we define the flags that can be turned on via features to yield debug info."""
311    cxx_diagnostic = flag_set(
312        actions = [
313            ACTION_NAMES.c_compile,
314            ACTION_NAMES.cpp_compile,
315        ],
316        flag_groups = [
317            flag_group(
318                flags = [
319                    "--trace-includes",
320                    "-v",
321                ],
322            ),
323        ],
324    )
325
326    link_diagnostic = flag_set(
327        actions = [ACTION_NAMES.cpp_link_executable],
328        flag_groups = [
329            flag_group(
330                flags = [
331                    "-Wl,-verbose",
332                    "-v",
333                ],
334            ),
335        ],
336    )
337
338    link_search_dirs = flag_set(
339        actions = [ACTION_NAMES.cpp_link_executable],
340        flag_groups = [
341            flag_group(
342                flags = [
343                    "--print-search-dirs",
344                ],
345            ),
346        ],
347    )
348    return [
349        # Running a Bazel command with --features diagnostic will cause the compilation and
350        # link steps to be more verbose.
351        feature(
352            "diagnostic",
353            enabled = False,
354            flag_sets = [
355                cxx_diagnostic,
356                link_diagnostic,
357            ],
358        ),
359        feature(
360            "diagnostic_link",
361            enabled = False,
362            flag_sets = [
363                link_diagnostic,
364            ],
365        ),
366        # Running a Bazel command with --features print_search_dirs will cause the link to fail
367        # but directories searched for libraries, etc will be displayed.
368        feature(
369            "print_search_dirs",
370            enabled = False,
371            flag_sets = [
372                link_search_dirs,
373            ],
374        ),
375    ]
376