""" Based on https://skia.googlesource.com/skia/+/773abacc15810af28f45ea234efdf6a96b5f16cf/toolchain/download_mac_toolchain.bzl. This file assembles a toolchain for a Mac host (either M1 or Intel) using the Clang Compiler and a locally-installed XCode. It downloads the necessary executables and creates symlinks in the external subfolder of the Bazel cache (the same place third party deps are downloaded with http_archive or similar functions in WORKSPACE.bazel). These will be able to be used via our custom c++ toolchain configuration (see //toolchain/mac_toolchain_config.bzl) The destination folder for these files and symlinks are: [outputRoot (aka Bazel cache)]/[outputUserRoot]/[outputBase]/external/clang_mac (See https://bazel.build/docs/output_directories#layout-diagram) """ load(":clang_layering_check.bzl", "generate_system_module_map") load(":utils.bzl", "gcs_mirror_url") # From https://github.com/llvm/llvm-project/releases/tag/llvmorg-15.0.1 # When updating this, don't forget to use //bazel/gcs_mirror to upload a new version. # go run bazel/gcs_mirror/gcs_mirror.go --url [clang_url] --sha256 [clang_sha256] clang_prefix_arm64 = "clang+llvm-15.0.1-arm64-apple-darwin21.0" clang_sha256_arm64 = "858f86d96b5e4880f69f7a583daddbf97ee94e7cffce0d53aa05cba6967f13b8" clang_url_arm64 = "https://github.com/llvm/llvm-project/releases/download/llvmorg-15.0.1/clang+llvm-15.0.1-arm64-apple-darwin21.0.tar.xz" clang_prefix_amd64 = "clang+llvm-15.0.1-x86_64-apple-darwin" clang_sha256_amd64 = "0b2f1a811e68d011344103274733b7670c15bbe08b2a3a5140ccad8e19d9311e" clang_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" def _get_system_xcode_path(ctx): # https://developer.apple.com/library/archive/technotes/tn2339/_index.html res = ctx.execute(["xcode-select", "-p"]) if res.return_code != 0: fail("Error Getting XCode path: " + res.stderr) return res.stdout.rstrip() def _delete_macos_sdk_symlinks(ctx): ctx.delete("./symlinks/xcode/MacSDK/usr") ctx.delete("./symlinks/xcode/MacSDK/Frameworks") def _create_macos_sdk_symlinks(ctx): system_xcode_path = _get_system_xcode_path(ctx) # https://bazel.build/rules/lib/actions#symlink ctx.symlink( # from = system_xcode_path + "/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr", # to = "./symlinks/xcode/MacSDK/usr", ) ctx.symlink( # from = system_xcode_path + "/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks", # to = "./symlinks/xcode/MacSDK/Frameworks", ) def _download_mac_toolchain_impl(ctx): # Abort if the host OS is not macOS. This rule fails on non-macOS platforms because it depends # on the xcode-select command, which is only available on macOS. # # Note that as of 2023-10-25, this is not necessary in the Skia repository, from which this # rule was copied almost verbatim. That is, Bazel somehow knows not to execute this rule. It # might be due to the fact that this and Skia use different Bazel versions. if "mac" not in ctx.os.name: # https://bazel.build/rules/lib/repository_ctx#file ctx.file( "BUILD.bazel", content = """ # DO NOT EDIT THIS BAZEL FILE DIRECTLY # Generated from ctx.file action in download_mac_toolchain.bzl filegroup( name = "generated_module_map", srcs = [], visibility = ["//visibility:public"], ) filegroup( name = "archive_files", srcs = [], visibility = ["//visibility:public"], ) filegroup( name = "compile_files", srcs = [], visibility = ["//visibility:public"], ) filegroup( name = "link_files", srcs = [], visibility = ["//visibility:public"], ) """, executable = False, ) return # https://bazel.build/rules/lib/repository_ctx#os # https://bazel.build/rules/lib/repository_os if ctx.os.arch == "aarch64": clang_url = clang_url_arm64 clang_sha256 = clang_sha256_arm64 clang_prefix = clang_prefix_arm64 else: clang_url = clang_url_amd64 clang_sha256 = clang_sha256_amd64 clang_prefix = clang_prefix_amd64 # Download the clang toolchain (the extraction can take a while) # https://bazel.build/rules/lib/repository_ctx#download_and_extract ctx.download_and_extract( url = gcs_mirror_url(clang_url, clang_sha256), output = "", stripPrefix = clang_prefix, sha256 = clang_sha256, ) # Some std library headers use #include_next to include system specific headers, and # some skia source files require Xcode headers when compiling, (see SkTypes.h and look # for TargetedConditionals.h)) All of these are located in Xcode, stopping the Mac # builds from being purely hermetic. # For now, we can grab the user's Xcode path by calling xcode-select and create a symlink in # our toolchain directory to refer to during compilation. _delete_macos_sdk_symlinks(ctx) _create_macos_sdk_symlinks(ctx) # This list of files lines up with _make_default_flags() in mac_toolchain_config.bzl # It is all locations that our toolchain could find a system header. builtin_include_directories = [ "include/c++/v1", "lib/clang/15.0.1/include", "symlinks/xcode/MacSDK/Frameworks", "symlinks/xcode/MacSDK/usr/include", ] generate_system_module_map( ctx, module_file = "toolchain_system_headers.modulemap", folders = builtin_include_directories, ) # Create a BUILD.bazel file that makes the files necessary for compiling, # linking and creating archive files visible to Bazel. # The smaller the globs are, the more performant the sandboxed builds will be. # Additionally, globs that are too wide can pick up infinite symlink loops, # and be difficult to quash: https://github.com/bazelbuild/bazel/issues/13950 # https://bazel.build/rules/lib/repository_ctx#file ctx.file( "BUILD.bazel", content = """ # DO NOT EDIT THIS BAZEL FILE DIRECTLY # Generated from ctx.file action in download_mac_toolchain.bzl filegroup( name = "generated_module_map", srcs = ["toolchain_system_headers.modulemap"], visibility = ["//visibility:public"], ) filegroup( name = "archive_files", srcs = [ "bin/llvm-ar", ], visibility = ["//visibility:public"], ) filegroup( name = "compile_files", srcs = [ "bin/clang", ] + glob( include = [ "include/c++/v1/**", "lib/clang/15.0.1/include/**", "symlinks/xcode/MacSDK/Frameworks/AppKit.Framework/**", "symlinks/xcode/MacSDK/Frameworks/ApplicationServices.Framework/**", "symlinks/xcode/MacSDK/Frameworks/Carbon.Framework/**", "symlinks/xcode/MacSDK/Frameworks/CFNetwork.Framework/**", "symlinks/xcode/MacSDK/Frameworks/CloudKit.Framework/**", "symlinks/xcode/MacSDK/Frameworks/Cocoa.Framework/**", "symlinks/xcode/MacSDK/Frameworks/ColorSync.Framework/**", "symlinks/xcode/MacSDK/Frameworks/CoreData.Framework/**", "symlinks/xcode/MacSDK/Frameworks/CoreFoundation.Framework/**", "symlinks/xcode/MacSDK/Frameworks/CoreGraphics.Framework/**", "symlinks/xcode/MacSDK/Frameworks/CoreImage.Framework/**", "symlinks/xcode/MacSDK/Frameworks/CoreLocation.Framework/**", "symlinks/xcode/MacSDK/Frameworks/CoreServices.Framework/**", "symlinks/xcode/MacSDK/Frameworks/CoreText.Framework/**", "symlinks/xcode/MacSDK/Frameworks/CoreVideo.Framework/**", "symlinks/xcode/MacSDK/Frameworks/DiskArbitration.Framework/**", "symlinks/xcode/MacSDK/Frameworks/Foundation.Framework/**", "symlinks/xcode/MacSDK/Frameworks/ImageIO.Framework/**", "symlinks/xcode/MacSDK/Frameworks/IOKit.Framework/**", "symlinks/xcode/MacSDK/Frameworks/IOSurface.Framework/**", "symlinks/xcode/MacSDK/Frameworks/Metal.Framework/**", "symlinks/xcode/MacSDK/Frameworks/OpenGL.Framework/**", "symlinks/xcode/MacSDK/Frameworks/QuartzCore.Framework/**", "symlinks/xcode/MacSDK/Frameworks/Security.Framework/**", "symlinks/xcode/MacSDK/usr/include/**", ], allow_empty = False, ), visibility = ["//visibility:public"], ) filegroup( name = "link_files", srcs = [ "bin/clang", "bin/ld.lld", "bin/lld", "lib/libc++.a", "lib/libc++abi.a", "lib/libunwind.a", ] + glob( include = [ # libc++.tbd and libSystem.tbd live here. "symlinks/xcode/MacSDK/usr/lib/*", ], allow_empty = False, ), visibility = ["//visibility:public"], ) """, executable = False, ) # https://bazel.build/rules/repository_rules download_mac_toolchain = repository_rule( implementation = _download_mac_toolchain_impl, attrs = {}, doc = "Downloads clang to build Skia with." + "Assumes you have xcode located on your device and have" + "xcode-select in your $PATH.", )