sysroot.py: add support for darwin

This is a tiny bit messy because compiler-rt needs different sysroots for
macOS, iOS, etc. We want sysroot.py to create something that is a hermetic
representation of all build deps, so it needs to create a directory that
contains all needed SDKs, and these subdirectories are then passed to
cmake which passes each of these _subdirectories_ as different -isysroot
flags while building the runtime libraries.

Differential Revision: https://reviews.llvm.org/D96958

GitOrigin-RevId: 0ec448194e2928a3d1dc2eceeb764c6e19bcec3e
diff --git a/utils/gn/build/BUILD.gn b/utils/gn/build/BUILD.gn
index 1829631..6f63592 100644
--- a/utils/gn/build/BUILD.gn
+++ b/utils/gn/build/BUILD.gn
@@ -43,24 +43,6 @@
   cflags = target_flags
   ldflags = target_flags + target_ldflags
 
-  if ((current_os == "ios" || current_os == "mac") && clang_base_path != "") {
-    if (current_os == "ios" && current_cpu == "arm64") {
-      sdk_path = ios_sdk_path
-    } else if (current_os == "ios" && current_cpu == "x64") {
-      sdk_path = iossim_sdk_path
-    } else if (current_os == "mac") {
-      sdk_path = mac_sdk_path
-    }
-    cflags += [
-      "-isysroot",
-      sdk_path,
-    ]
-    ldflags += [
-      "-isysroot",
-      sdk_path,
-    ]
-  }
-
   # Mostly for compiler-rt, see compiler-rt/cmake/config-ix.cmake
   if (current_os == "ios") {
     asmflags += [ "-miphoneos-version-min=8.0" ]
@@ -283,18 +265,34 @@
     }
   }
   if (sysroot != "") {
-    assert(current_os != "mac" && current_os != "ios",
-           "FIXME: Make sysroot work on darwin")
     if (current_os == "win") {
       assert(is_clang, "sysroot only works with clang-cl as host compiler")
       cflags += [ "/winsysroot" + rebase_path(sysroot, root_build_dir) ]
-    } else {
+    } else if (current_os != "ios" && current_os != "mac") {
       cflags += [ "--sysroot=" + rebase_path(sysroot, root_build_dir) ]
-      if (is_clang) {
-        cflags += [ "-Wpoison-system-directories"]
-      }
     }
   }
+  if ((current_os == "ios" || current_os == "mac") &&
+      (clang_base_path != "" || sysroot != "")) {
+    if (current_os == "ios" && current_cpu == "arm64") {
+      sdk_path = ios_sdk_path
+    } else if (current_os == "ios" && current_cpu == "x64") {
+      sdk_path = iossim_sdk_path
+    } else if (current_os == "mac") {
+      sdk_path = mac_sdk_path
+    }
+    cflags += [
+      "-isysroot",
+      sdk_path,
+    ]
+    ldflags += [
+      "-isysroot",
+      sdk_path,
+    ]
+  }
+  if (sysroot != "" && current_os != "win" && is_clang) {
+    cflags += [ "-Wpoison-system-directories" ]
+  }
 
   if (use_ubsan) {
     assert(is_clang && current_os == "linux",
diff --git a/utils/gn/build/mac_sdk.gni b/utils/gn/build/mac_sdk.gni
index b6c9baa..46249bf 100644
--- a/utils/gn/build/mac_sdk.gni
+++ b/utils/gn/build/mac_sdk.gni
@@ -1,20 +1,33 @@
-declare_args() {
-  # Set to true if you don't have Xcode installed, but do have the commandline
-  # tools.
-  mac_use_commandline_tools_sdk = false
-}
+import("//llvm/utils/gn/build/sysroot.gni")
 
-# Location of the mac sdk.
-# The correct way to do this is to call xcrun (https://reviews.llvm.org/D70835),
-# but that makes `gn gen` take twice as long and almost everyone has Xcode
-# installed.  So require that people who don't have it installed set a gn arg.
-if (mac_use_commandline_tools_sdk) {
-  ios_sdk_path = "/Library/Developer/CommandLineTools/SDKs/iPhoneOS.sdk"
-  iossim_sdk_path =
-      "/Library/Developer/CommandLineTools/SDKs/iPhoneSimulator.sdk"
-  mac_sdk_path = "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk"
+have_ios_sdks = true
+
+if (sysroot == "") {
+  declare_args() {
+    # Set to true if you don't have Xcode installed, but do have the commandline
+    # tools.
+    mac_use_commandline_tools_sdk = false
+  }
+
+  # Location of the mac sdk.
+  # The correct way to do this is to call xcrun
+  # (https://reviews.llvm.org/D70835), but that makes `gn gen` take twice as
+  # long and almost everyone has Xcode installed.  So require that people who
+  # don't have it installed set a gn arg.
+  if (mac_use_commandline_tools_sdk) {
+    ios_sdk_path = "/Library/Developer/CommandLineTools/SDKs/iPhoneOS.sdk"
+    iossim_sdk_path =
+        "/Library/Developer/CommandLineTools/SDKs/iPhoneSimulator.sdk"
+    mac_sdk_path = "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk"
+  } else {
+    mac_sdk_path = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk"
+
+    # iOS SDKs aren't available in the commandline tools SDK.
+    have_ios_sdks = true
+  }
 } else {
-  ios_sdk_path = "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk"
-  iossim_sdk_path = "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk"
-  mac_sdk_path = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk"
+  ios_sdk_path = rebase_path(sysroot, root_build_dir) + "/iPhoneOS.sdk"
+  iossim_sdk_path =
+      rebase_path(sysroot, root_build_dir) + "/iPhoneSimulator.sdk"
+  mac_sdk_path = rebase_path(sysroot, root_build_dir) + "/MacOSX.sdk"
 }
diff --git a/utils/gn/secondary/compiler-rt/BUILD.gn b/utils/gn/secondary/compiler-rt/BUILD.gn
index af23e33..31c3c7266 100644
--- a/utils/gn/secondary/compiler-rt/BUILD.gn
+++ b/utils/gn/secondary/compiler-rt/BUILD.gn
@@ -20,8 +20,7 @@
 
   # FIXME: Do this only if a gn arg compiler_rt_enable_ios is set?
   # That would match the cmake build.
-  # iOS SDKs aren't available in the commandline tools SDK.
-  if (host_os == "mac" && !mac_use_commandline_tools_sdk) {
+  if (host_os == "mac" && have_ios_sdks) {
     if (llvm_build_AArch64) {
       deps += [ "//compiler-rt/lib/builtins(//llvm/utils/gn/build/toolchain:stage2_ios_aarch64)" ]
     }
diff --git a/utils/sysroot.py b/utils/sysroot.py
index fb832e6..48b52ec 100755
--- a/utils/sysroot.py
+++ b/utils/sysroot.py
@@ -36,18 +36,47 @@
         os.mkdir(os.path.join(out_dir, 'Windows Kits'))
         mkjunction(os.path.join(out_dir, 'Windows Kits', '10'), winsdk)
     elif sys.platform == 'darwin':
-        assert False, "FIXME: Implement on darwin"
+        # The SDKs used by default in compiler-rt/cmake/base-config-ix.cmake.
+        # COMPILER_RT_ENABLE_IOS defaults to on.
+        # COMPILER_RT_ENABLE_WATCHOS and COMPILER_RT_ENABLE_TV default to off.
+        # compiler-rt/cmake/config-ix.cmake sets DARWIN_EMBEDDED_PLATFORMS
+        # depending on these.
+        sdks = ['macosx', 'iphoneos', 'iphonesimulator']
+        os.mkdir(out_dir)
+        for sdk in sdks:
+          sdkpath = cmdout(['xcrun', '-sdk', sdk, '-show-sdk-path'])
+          # sdkpath is something like /.../SDKs/MacOSX11.1.sdk, which is a
+          # symlink to MacOSX.sdk in the same directory. Resolve the symlink,
+          # to make the symlink in out_dir less likely to break when the SDK
+          # is updated (which will bump the number on xcrun's output, but not
+          # on the symlink destination).
+          sdkpath = os.path.realpath(sdkpath)
+          os.symlink(sdkpath, os.path.join(out_dir, os.path.basename(sdkpath)))
     else:
         os.symlink('/', out_dir)
 
-    print('Done.')
+    print('Done. Pass these flags to cmake:')
     abs_out_dir = os.path.abspath(out_dir)
     if sys.platform == 'win32':
         # CMake doesn't like backslashes in commandline args.
         abs_out_dir = abs_out_dir.replace(os.path.sep, '/')
-        print('Pass -DLLVM_WINSYSROOT=' + abs_out_dir + ' to cmake.')
+        print('  -DLLVM_WINSYSROOT=' + abs_out_dir)
+    elif sys.platform == 'darwin':
+        flags = [
+          '-DCMAKE_OSX_SYSROOT=' + os.path.join(abs_out_dir, 'MacOSX.sdk'),
+
+          # For find_darwin_sdk_dir() in
+          # compiler-rt/cmake/Modules/CompilerRTDarwinUtils.cmake
+          '-DDARWIN_macosx_CACHED_SYSROOT=' +
+              os.path.join(abs_out_dir, 'MacOSX.sdk'),
+          '-DDARWIN_iphoneos_CACHED_SYSROOT=' +
+              os.path.join(abs_out_dir, 'iPhoneOS.sdk'),
+          '-DDARWIN_iphonesimulator_CACHED_SYSROOT=' +
+              os.path.join(abs_out_dir, 'iPhoneSimulator.sdk'),
+        ]
+        print('  ' + ' '.join(flags))
     else:
-        print('Pass -DCMAKE_SYSROOT=' + abs_out_dir + ' to cmake.')
+        print('  -DCMAKE_SYSROOT=' + abs_out_dir + ' to cmake.')
 
 
 def main():