[fuchsia_clang] Symlink clang install directory.

Use top-level symlinks instead of recursive hard-links or copies when
creating the content of the @fuchsia_clang repository. This is made
possible by our change in the 'dependency_file' feature in a previous
CL [1], which allows such paths to work correctly with the paths found
in compiler-generated dependency (.d) files.

This is also an attempt to remove flaky hard-linking issues that
appear when trying to update to Bazel 6, see [2] for an example.

+ Add llvm-strip to the list of compiler prebuilts. Otherwise, some
  C++ compile actions would fail with Bazel6.

Bug: 116108

[1] https://fuchsia-review.git.corp.google.com/c/sdk-integration/+/786962
[2] tqr/645770 patchset 2

Change-Id: I87d970560ba30723f44437e9f09244e298951ad0
Reviewed-on: https://fuchsia-review.googlesource.com/c/sdk-integration/+/786964
Reviewed-by: Renato Mangini Dias <mangini@google.com>
Commit-Queue: David Turner <digit@google.com>
diff --git a/bazel_rules_fuchsia/fuchsia/workspace/clang_templates/crosstool_template.BUILD b/bazel_rules_fuchsia/fuchsia/workspace/clang_templates/crosstool_template.BUILD
index a8f225d..c761599 100644
--- a/bazel_rules_fuchsia/fuchsia/workspace/clang_templates/crosstool_template.BUILD
+++ b/bazel_rules_fuchsia/fuchsia/workspace/clang_templates/crosstool_template.BUILD
@@ -36,6 +36,7 @@
         "//:bin/clang++",
         "//:bin/clang-%{CLANG_VERSION}",
         "//:bin/clang-cpp",
+        "//:bin/llvm-strip",
     ],
 )
 
diff --git a/bazel_rules_fuchsia/fuchsia/workspace/fuchsia_clang_repository.bzl b/bazel_rules_fuchsia/fuchsia/workspace/fuchsia_clang_repository.bzl
index 5c18db9..ce8d428 100644
--- a/bazel_rules_fuchsia/fuchsia/workspace/fuchsia_clang_repository.bzl
+++ b/bazel_rules_fuchsia/fuchsia/workspace/fuchsia_clang_repository.bzl
@@ -22,7 +22,7 @@
     ctx.report_progress("Extracting local clang archive")
     ctx.extract(archive = ctx.attr.local_archive)
 
-def _instantiate_from_local_dir(ctx, local_clang, fuchsia_tools_dir):
+def _instantiate_from_local_dir(ctx, local_clang):
     # buildifier: disable=print
     # local_path can be either a string or Path object.
     if type(local_clang) == type("str"):
@@ -30,42 +30,13 @@
 
     ctx.report_progress("Copying local clang from %s" % local_clang)
 
-    # Generate a Python script to hard-link the content of the Clang installation
-    # to the repository directory itself.
-    #
-    # NOTE: hard-linking is not ideal, if the Fuchsia platform checkout
-    # changes (e.g. with a `jiri update`, Bazel will not detect changes
-    # in the source files used here and will keep using the old toolchain.
-    #
-    # However, symlinking introduces other issues, because then Bazel C++
-    # compile actions will complain about unlisted header dependencies
-    # from /path/to/fuchsia/prebuilt/third_party/clang/linux-x64/...
-    # paths (not that these are absolute paths to the FUCHSIA_DIR checkout,
-    # and not relative to the Bazel execroot).
-    #
-    # This is because these paths are listed in Clang-generated .d files that
-    # are consumed by Bazel, which then verifies that they belong to the
-    # directories listed in cxx_builtin_include_directories, and this only
-    # contains absolute file paths to the @fuchsia_clang repository directory.
-    try_hardlink = True
-    _cp_tool = fuchsia_tools_dir + "/cp.sh"
+    # Symlink top-level items from Clang prebuilt install to repository directory
+    # Note that this is possible because our C++ toolchain configuration redefine
+    # the "dependency_file" feature to use relative file paths.
     for f in local_clang.readdir():
-        # For performance reasons, if a single hardlink operation fails, we
-        # switch to regular copy for all the remaining destination directories.
-        if try_hardlink:
-            result = ctx.execute([_cp_tool, f, ".", "-l", "-n"], quiet = True)
-            if result.return_code != 0:
-                print("WARNING: cannot create hardlink to local clang files, falling back to regular copy")
-                try_hardlink = False
+        ctx.symlink(f, f.basename)
 
-        # This is not an "else" intentionally, since we want to execute regular
-        # copy if we couldn't hardlink.
-        if not try_hardlink:
-            result = ctx.execute([_cp_tool, f, ".", "-n"], quiet = False)
-            if result.return_code != 0:
-                fail("Cannot copy clang files from %s" % f)
-
-def _instantiate_from_local_fuchsia_tree(ctx, fuchsia_tools_dir):
+def _instantiate_from_local_fuchsia_tree(ctx):
     # Copies clang prebuilt from a local Fuchsia platform tree.
     local_fuchsia_dir = ctx.os.environ[_LOCAL_FUCHSIA_PLATFORM_BUILD]
     local_clang = ctx.path("%s/%s" % (local_fuchsia_dir, _LOCAL_FUCHSIA_CLANG_DIR))
@@ -76,7 +47,7 @@
         fail("Expected a single host architecture subdirectory in local clang: %s" % str(local_clang))
 
     local_clang_arch = local_clang_archs[0]
-    _instantiate_from_local_dir(ctx, local_clang_arch, fuchsia_tools_dir)
+    _instantiate_from_local_dir(ctx, local_clang_arch)
 
 def _fuchsia_clang_repository_impl(ctx):
     # Pre-evaluate paths of templated output files so that the repository does not need to be
@@ -84,8 +55,6 @@
     ctx.path("BUILD.bazel")
     ctx.path("cc_toolchain_config.bzl")
 
-    fuchsia_tools_dir = str(ctx.path(Label("//fuchsia/tools:BUILD.bazel")).dirname)
-
     crosstool_template = Label("//fuchsia/workspace/clang_templates:crosstool_template.BUILD")
     toolchain_config_template = Label("//fuchsia/workspace/clang_templates:cc_toolchain_config_template.bzl")
 
@@ -112,9 +81,9 @@
     normalized_os = normalize_os(ctx)
     if ctx.attr.local_path:
         local_clang = workspace_path(ctx, ctx.attr.local_path)
-        _instantiate_from_local_dir(ctx, local_clang, fuchsia_tools_dir)
+        _instantiate_from_local_dir(ctx, local_clang)
     elif _LOCAL_FUCHSIA_PLATFORM_BUILD in ctx.os.environ:
-        _instantiate_from_local_fuchsia_tree(ctx, fuchsia_tools_dir)
+        _instantiate_from_local_fuchsia_tree(ctx)
     elif ctx.attr.local_archive:
         _instantiate_local_archive(ctx)
     elif ctx.attr.cipd_tag: