• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""
2This file assembles a toolchain for a Mac host (either M1 or Intel) using the Clang Compiler
3and a locally-installed XCode.
4
5It downloads the necessary executables and creates symlinks in the external subfolder of the Bazel
6cache (the same place third party deps are downloaded with http_archive or similar functions in
7WORKSPACE.bazel). These will be able to be used via our
8custom c++ toolchain configuration (see //toolchain/mac_toolchain_config.bzl)
9
10The destination folder for these files and symlinks are:
11  [outputRoot (aka Bazel cache)]/[outputUserRoot]/[outputBase]/external/clang_mac
12  (See https://bazel.build/docs/output_directories#layout-diagram)
13"""
14
15load(":clang_layering_check.bzl", "generate_system_module_map")
16load(":utils.bzl", "gcs_mirror_url")
17
18# From https://github.com/llvm/llvm-project/releases/tag/llvmorg-17.0.6
19# When updating this, don't forget to use //bazel/gcs_mirror to upload a new version.
20# go run bazel/gcs_mirror/gcs_mirror.go --url [clang_url] --sha256 [clang_sha256]
21clang_prefix_arm64 = "clang+llvm-17.0.6-arm64-apple-darwin22.0"
22clang_sha256_arm64 = "1264eb3c2a4a6d5e9354c3e5dc5cb6c6481e678f6456f36d2e0e566e9400fcad"
23clang_url_arm64 = "https://github.com/llvm/llvm-project/releases/download/llvmorg-17.0.6/clang+llvm-17.0.6-arm64-apple-darwin22.0.tar.xz"
24clang_ver_arm64 = "17"
25
26# No x86_64-apple binaries published by llvm-project beyond 15.
27# TODO: find a different toolchain source.
28clang_prefix_amd64 = "clang+llvm-15.0.1-x86_64-apple-darwin"
29clang_sha256_amd64 = "0b2f1a811e68d011344103274733b7670c15bbe08b2a3a5140ccad8e19d9311e"
30clang_url_amd64 = "https://github.com/llvm/llvm-project/releases/download/llvmorg-15.0.1/clang+llvm-15.0.1-x86_64-apple-darwin.tar.xz"
31clang_ver_amd64 = "15.0.1"
32
33def _get_system_sdk_path(ctx):
34    res = ctx.execute(["xcrun", "--sdk", "macosx", "--show-sdk-path"])
35    if res.return_code != 0:
36        fail("Error Getting SDK path: " + res.stderr)
37    return res.stdout.rstrip()
38
39def _delete_macos_sdk_symlinks(ctx):
40    ctx.delete("./symlinks/xcode/MacSDK/usr")
41    ctx.delete("./symlinks/xcode/MacSDK/System/Library/Frameworks")
42
43def _create_macos_sdk_symlinks(ctx):
44    system_sdk_path = _get_system_sdk_path(ctx)
45
46    # https://bazel.build/rules/lib/actions#symlink
47    ctx.symlink(
48        # from =
49        system_sdk_path + "/usr",
50        # to =
51        "./symlinks/xcode/MacSDK/usr",
52    )
53
54    # It is very important to symlink the frameworks directory to [sysroot]/System/Library/Frameworks
55    # because some Frameworks "re-export" other frameworks. These framework paths are relative to
56    # the sysroot (which on a typical machine is /), and it is difficult to change these paths.
57    # By making the symlinks emulate the original path structure, we can keep those re-exports
58    # from breaking.
59    ctx.symlink(
60        # from =
61        system_sdk_path + "/System/Library/Frameworks",
62        # to =
63        "./symlinks/xcode/MacSDK/System/Library/Frameworks",
64    )
65
66def _download_mac_toolchain_impl(ctx):
67    # https://bazel.build/rules/lib/repository_ctx#os
68    # https://bazel.build/rules/lib/repository_os
69    if ctx.os.arch == "aarch64":
70        clang_ver = clang_ver_arm64
71        clang_url = clang_url_arm64
72        clang_sha256 = clang_sha256_arm64
73        clang_prefix = clang_prefix_arm64
74    else:
75        clang_ver = clang_ver_amd64
76        clang_url = clang_url_amd64
77        clang_sha256 = clang_sha256_amd64
78        clang_prefix = clang_prefix_amd64
79
80    # Download the clang toolchain (the extraction can take a while)
81    # https://bazel.build/rules/lib/repository_ctx#download_and_extract
82    ctx.download_and_extract(
83        url = gcs_mirror_url(clang_url, clang_sha256),
84        output = "",
85        stripPrefix = clang_prefix,
86        sha256 = clang_sha256,
87    )
88
89    # Some std library headers use #include_next to include system specific headers, and
90    # some skia source files require Xcode headers when compiling, (see SkTypes.h and look
91    # for TargetedConditionals.h)) All of these are located in Xcode, stopping the Mac
92    # builds from being purely hermetic.
93    # For now, we can grab the user's Xcode path by calling xcode-select and create a symlink in
94    # our toolchain directory to refer to during compilation.
95
96    _delete_macos_sdk_symlinks(ctx)
97    _create_macos_sdk_symlinks(ctx)
98
99    # This list of files lines up with _make_default_flags() in mac_toolchain_config.bzl
100    # It is all locations that our toolchain could find a system header.
101    builtin_include_directories = [
102        "include/c++/v1",
103        "lib/clang/" + clang_ver + "/include",
104        # Frameworks is a symlink, and the trailing slash is intentional
105        # (to ensure traversal in generate_system_module_map.sh's find).
106        "symlinks/xcode/MacSDK/System/Library/Frameworks/",
107        "symlinks/xcode/MacSDK/usr/include",
108    ]
109
110    generate_system_module_map(
111        ctx,
112        module_file = "toolchain_system_headers.modulemap",
113        folders = builtin_include_directories,
114    )
115
116    # Create a BUILD.bazel file that makes the files necessary for compiling,
117    # linking and creating archive files visible to Bazel.
118    # The smaller the globs are, the more performant the sandboxed builds will be.
119    # Additionally, globs that are too wide can pick up infinite symlink loops,
120    # and be difficult to quash: https://github.com/bazelbuild/bazel/issues/13950
121    # https://bazel.build/rules/lib/repository_ctx#file
122    ctx.file(
123        "BUILD.bazel",
124        content = """
125# DO NOT EDIT THIS BAZEL FILE DIRECTLY
126# Generated from ctx.file action in download_mac_toolchain.bzl
127filegroup(
128    name = "generated_module_map",
129    srcs = ["toolchain_system_headers.modulemap"],
130    visibility = ["//visibility:public"],
131)
132
133filegroup(
134    name = "archive_files",
135    srcs = [
136        "bin/llvm-ar",
137    ],
138    visibility = ["//visibility:public"],
139)
140
141# Any framework that Skia depends on directly or indirectly needs to be listed here.
142FRAMEWORK_GLOB = [
143    "symlinks/xcode/MacSDK/System/Library/Frameworks/AppKit.Framework/**",
144    "symlinks/xcode/MacSDK/System/Library/Frameworks/ApplicationServices.Framework/**",
145    "symlinks/xcode/MacSDK/System/Library/Frameworks/AVFAudio.Framework/**",
146    "symlinks/xcode/MacSDK/System/Library/Frameworks/AVFoundation.Framework/**",
147    "symlinks/xcode/MacSDK/System/Library/Frameworks/Carbon.Framework/**",
148    "symlinks/xcode/MacSDK/System/Library/Frameworks/CFNetwork.Framework/**",
149    "symlinks/xcode/MacSDK/System/Library/Frameworks/CloudKit.Framework/**",
150    "symlinks/xcode/MacSDK/System/Library/Frameworks/Cocoa.Framework/**",
151    "symlinks/xcode/MacSDK/System/Library/Frameworks/ColorSync.Framework/**",
152    "symlinks/xcode/MacSDK/System/Library/Frameworks/CoreData.Framework/**",
153    "symlinks/xcode/MacSDK/System/Library/Frameworks/CoreAudio.Framework/**",
154    "symlinks/xcode/MacSDK/System/Library/Frameworks/CoreAudioTypes.Framework/**",
155    "symlinks/xcode/MacSDK/System/Library/Frameworks/CoreFoundation.Framework/**",
156    "symlinks/xcode/MacSDK/System/Library/Frameworks/CoreGraphics.Framework/**",
157    "symlinks/xcode/MacSDK/System/Library/Frameworks/CoreImage.Framework/**",
158    "symlinks/xcode/MacSDK/System/Library/Frameworks/CoreLocation.Framework/**",
159    "symlinks/xcode/MacSDK/System/Library/Frameworks/CoreMedia.Framework/**",
160    "symlinks/xcode/MacSDK/System/Library/Frameworks/CoreMIDI.Framework/**",
161    "symlinks/xcode/MacSDK/System/Library/Frameworks/CoreServices.Framework/**",
162    "symlinks/xcode/MacSDK/System/Library/Frameworks/CoreText.Framework/**",
163    "symlinks/xcode/MacSDK/System/Library/Frameworks/CoreVideo.Framework/**",
164    "symlinks/xcode/MacSDK/System/Library/Frameworks/DiskArbitration.Framework/**",
165    "symlinks/xcode/MacSDK/System/Library/Frameworks/Foundation.Framework/**",
166    "symlinks/xcode/MacSDK/System/Library/Frameworks/ImageIO.Framework/**",
167    "symlinks/xcode/MacSDK/System/Library/Frameworks/IOKit.Framework/**",
168    "symlinks/xcode/MacSDK/System/Library/Frameworks/IOSurface.Framework/**",
169    "symlinks/xcode/MacSDK/System/Library/Frameworks/Metal.Framework/**",
170    "symlinks/xcode/MacSDK/System/Library/Frameworks/MetalKit.Framework/**",
171    "symlinks/xcode/MacSDK/System/Library/Frameworks/ModelIO.Framework/**",
172    "symlinks/xcode/MacSDK/System/Library/Frameworks/OpenGL.Framework/**",
173    "symlinks/xcode/MacSDK/System/Library/Frameworks/QuartzCore.Framework/**",
174    "symlinks/xcode/MacSDK/System/Library/Frameworks/Security.Framework/**",
175    "symlinks/xcode/MacSDK/System/Library/Frameworks/Symbols.Framework/**",
176    "symlinks/xcode/MacSDK/System/Library/Frameworks/UniformTypeIdentifiers.framework/**",
177]
178
179filegroup(
180    name = "compile_files",
181    srcs = [
182        "bin/clang",
183    ] + glob(
184        include = [
185            "include/c++/v1/**",
186            "lib/clang/*/include/**",
187            "symlinks/xcode/MacSDK/usr/include/**",
188        ],
189        allow_empty = False,
190    ) + glob(
191        # Frameworks are SDK-dependent, and can vary between releases.
192        # We attempt to capture a super-set.
193        include = FRAMEWORK_GLOB,
194        allow_empty = True,
195    ),
196    visibility = ["//visibility:public"],
197)
198
199filegroup(
200    name = "link_files",
201    srcs = [
202        "bin/clang",
203        "bin/ld.lld",
204        "bin/lld",
205        "lib/libc++.a",
206        "lib/libc++abi.a",
207        "lib/libunwind.a",
208    ] + glob(
209        include = [
210            # libc++.tbd and libSystem.tbd live here.
211            "symlinks/xcode/MacSDK/usr/lib/*",
212        ],
213        allow_empty = False,
214    ) + glob(
215        # Frameworks are SDK-dependent, and can vary between releases.
216        # We attempt to capture a super-set.
217        include = FRAMEWORK_GLOB,
218        allow_empty = True,
219    ),
220    visibility = ["//visibility:public"],
221)
222""",
223        executable = False,
224    )
225
226# https://bazel.build/rules/repository_rules
227download_mac_toolchain = repository_rule(
228    implementation = _download_mac_toolchain_impl,
229    attrs = {},
230    doc = "Downloads clang to build Skia with." +
231          "Assumes you have xcode located on your device and have" +
232          "xcode-select in your $PATH.",
233)
234