[clang] Build clang with pinned clang on all platforms

This is a reland of https://crrev.com/c/3590911.

Followup to https://crrev.com/c/3572241.

We can't use NamedTemporaryFile on Windows (can't read from it while having a handle to it): https://docs.python.org/3.9/library/tempfile.html. Use a consistent path for the pinned update.py instead.

Reason for previous revert should be fixed with https://crrev.com/c/3656302.

Bug: 1010466, 1013560
Change-Id: I578ae53afe33c657d48a4c3333e396f2c62eea89
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3656846
Reviewed-by: Nico Weber <thakis@chromium.org>
Commit-Queue: Arthur Eubanks <aeubanks@google.com>
Cr-Commit-Position: refs/heads/main@{#1006103}
NOKEYCHECK=True
GitOrigin-RevId: ad35291af36d609042e1d320adb1568daafef9a8
diff --git a/scripts/build.py b/scripts/build.py
index b0d403e..2df2392 100755
--- a/scripts/build.py
+++ b/scripts/build.py
@@ -392,16 +392,19 @@
   # The update.py in this current revision may have a patched revision while
   # building new clang packages. Get update.py off HEAD~ to pull the current
   # pinned clang.
-  with tempfile.NamedTemporaryFile() as f:
+  if not os.path.exists(PINNED_CLANG_DIR):
+    os.mkdir(os.path.join(PINNED_CLANG_DIR))
+
+  script_path = os.path.join(PINNED_CLANG_DIR, 'update.py')
+
+  with open(script_path, 'w') as f:
     subprocess.check_call(
         ['git', 'show', 'HEAD~:tools/clang/scripts/update.py'],
         stdout=f,
         cwd=CHROMIUM_DIR)
-    print("Running update.py")
-    # Without the flush, the subprocess call below doesn't work.
-    f.flush()
-    subprocess.check_call(
-        [sys.executable, f.name, '--output-dir=' + PINNED_CLANG_DIR])
+  print("Running pinned update.py")
+  subprocess.check_call(
+      [sys.executable, script_path, '--output-dir=' + PINNED_CLANG_DIR])
 
 
 # TODO(crbug.com/929645): Remove once we don't need gcc's libstdc++.
@@ -667,35 +670,49 @@
       # Build libclang.a as well as libclang.so
       '-DLIBCLANG_BUILD_STATIC=ON',
   ]
-
-  if sys.platform.startswith('linux'):
-    MaybeDownloadHostGcc(args)
-    if args.host_cc or args.host_cxx:
-      assert args.host_cc and args.host_cxx, \
-             "--host-cc and --host-cxx need to be used together"
-      cc = args.host_cc
-      cxx = args.host_cxx
+  if args.host_cc or args.host_cxx:
+    assert args.host_cc and args.host_cxx, \
+           "--host-cc and --host-cxx need to be used together"
+    cc = args.host_cc
+    cxx = args.host_cxx
+  else:
+    DownloadPinnedClang()
+    if sys.platform == 'win32':
+      cc = os.path.join(PINNED_CLANG_DIR, 'bin', 'clang-cl.exe')
+      cxx = os.path.join(PINNED_CLANG_DIR, 'bin', 'clang-cl.exe')
+      lld = os.path.join(PINNED_CLANG_DIR, 'bin', 'lld-link.exe')
+      # CMake has a hard time with backslashes in compiler paths:
+      # https://stackoverflow.com/questions/13050827
+      cc = cc.replace('\\', '/')
+      cxx = cxx.replace('\\', '/')
+      lld = lld.replace('\\', '/')
     else:
-      DownloadPinnedClang()
       cc = os.path.join(PINNED_CLANG_DIR, 'bin', 'clang')
       cxx = os.path.join(PINNED_CLANG_DIR, 'bin', 'clang++')
+
+    if sys.platform != 'darwin':
+      # The host clang has lld, but self-hosting with lld is still slightly
+      # broken on mac.
+      # TODO: check if this works now.
+      base_cmake_args.append('-DLLVM_ENABLE_LLD=ON')
+
+    if sys.platform.startswith('linux'):
+      MaybeDownloadHostGcc(args)
       # Use the libraries in the specified gcc installation for building.
       cflags.append('--gcc-toolchain=' + args.gcc_toolchain)
       cxxflags.append('--gcc-toolchain=' + args.gcc_toolchain)
-    base_cmake_args += [
-        # The host clang has lld.
-        '-DLLVM_ENABLE_LLD=ON',
-        '-DLLVM_STATIC_LINK_CXX_STDLIB=ON',
-        # Force compiler-rt tests to use our gcc toolchain
-        # because the one on the host may be too old.
-        # Even with -static-libstdc++ the compiler-rt tests add -lstdc++
-        # which adds a DT_NEEDED to libstdc++.so so we need to add RPATHs
-        # to the gcc toolchain.
-        '-DCOMPILER_RT_TEST_COMPILER_CFLAGS=--gcc-toolchain=' +
-        args.gcc_toolchain + ' -Wl,-rpath,' +
-        os.path.join(args.gcc_toolchain, 'lib64') + ' -Wl,-rpath,' +
-        os.path.join(args.gcc_toolchain, 'lib32')
-    ]
+      base_cmake_args += [
+          '-DLLVM_STATIC_LINK_CXX_STDLIB=ON',
+          # Force compiler-rt tests to use our gcc toolchain
+          # because the one on the host may be too old.
+          # Even with -static-libstdc++ the compiler-rt tests add -lstdc++
+          # which adds a DT_NEEDED to libstdc++.so so we need to add RPATHs
+          # to the gcc toolchain.
+          '-DCOMPILER_RT_TEST_COMPILER_CFLAGS=--gcc-toolchain=' +
+          args.gcc_toolchain + ' -Wl,-rpath,' +
+          os.path.join(args.gcc_toolchain, 'lib64') + ' -Wl,-rpath,' +
+          os.path.join(args.gcc_toolchain, 'lib32')
+      ]
 
   if sys.platform == 'darwin':
     # For libc++, we only want the headers.