diff --git a/toolchain/driver/clang_runner_test.cpp b/toolchain/driver/clang_runner_test.cpp index e746ae6994f4..2b56671cf5c7 100644 --- a/toolchain/driver/clang_runner_test.cpp +++ b/toolchain/driver/clang_runner_test.cpp @@ -181,5 +181,38 @@ TEST(ClangRunnerTest, DashC) { EXPECT_THAT(err, StrEq("")); } +TEST(ClangRunnerTest, BuitinHeaders) { + std::filesystem::path test_file = WriteTestFile("test.c", R"cpp( +#include + +#ifndef alignas +#error included the wrong header +#endif + )cpp"); + std::filesystem::path test_output = WriteTestFile("test.o", ""); + + const auto install_paths = + InstallPaths::MakeForBazelRunfiles(Testing::GetExePath()); + RawStringOstream verbose_out; + std::string target = llvm::sys::getDefaultTargetTriple(); + auto vfs = llvm::vfs::getRealFileSystem(); + ClangRunner runner(&install_paths, target, vfs, &verbose_out); + std::string out; + std::string err; + EXPECT_TRUE(RunWithCapturedOutput(out, err, + [&] { + return runner.Run( + {"-c", test_file.string(), "-o", + test_output.string()}); + })) + << "Verbose output from runner:\n" + << verbose_out.TakeStr() << "\n"; + verbose_out.clear(); + + // No output should be produced. + EXPECT_THAT(out, StrEq("")); + EXPECT_THAT(err, StrEq("")); +} + } // namespace } // namespace Carbon diff --git a/toolchain/install/BUILD b/toolchain/install/BUILD index 0e85002cce97..6c520478f6fb 100644 --- a/toolchain/install/BUILD +++ b/toolchain/install/BUILD @@ -2,6 +2,10 @@ # Exceptions. See /LICENSE for license information. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +load( + "@llvm-project//:vars.bzl", + "LLVM_VERSION_MAJOR", +) load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test") load("//bazel/cc_toolchains:defs.bzl", "cc_env") load("//bazel/manifest:defs.bzl", "manifest") @@ -119,6 +123,11 @@ lld_aliases = [ "wasm-ld", ] +filegroup( + name = "clang_headers", + srcs = ["@llvm-project//clang:builtin_headers_gen"], +) + # Given a root `prefix_root`, the hierarchy looks like: # # - prefix_root/bin: Binaries intended for direct use. @@ -158,6 +167,9 @@ install_dirs = { is_driver = True, ), ] + [install_symlink(name, "lld") for name in lld_aliases], + "lib/carbon/llvm/lib/clang/" + LLVM_VERSION_MAJOR: [ + install_filegroup("include", ":clang_headers", "staging/include/"), + ], } make_install_filegroups( diff --git a/toolchain/install/install_filegroups.bzl b/toolchain/install/install_filegroups.bzl index eb938af81e40..1cafe4f3cdf2 100644 --- a/toolchain/install/install_filegroups.bzl +++ b/toolchain/install/install_filegroups.bzl @@ -7,7 +7,7 @@ load("@rules_pkg//pkg:mappings.bzl", "pkg_attributes", "pkg_filegroup", "pkg_files", "pkg_mklink", "strip_prefix") load("symlink_helpers.bzl", "symlink_file", "symlink_filegroup") -def install_filegroup(name, filegroup_target): +def install_filegroup(name, filegroup_target, remove_prefix = ""): """Adds a filegroup for install. Used in the `install_dirs` dict. @@ -20,6 +20,7 @@ def install_filegroup(name, filegroup_target): "filegroup": filegroup_target, "is_driver": False, "name": name, + "remove_prefix": remove_prefix, } def install_symlink(name, symlink_to, is_driver = False): @@ -111,6 +112,7 @@ def make_install_filegroups(name, no_driver_name, pkg_name, install_dirs, prefix name = prefixed_path, out_prefix = prefixed_path, srcs = [entry["filegroup"]], + remove_prefix = entry["remove_prefix"], ) pkg_files( name = pkg_path, diff --git a/toolchain/install/symlink_helpers.bzl b/toolchain/install/symlink_helpers.bzl index 01284cc70014..19fd722a29f5 100644 --- a/toolchain/install/symlink_helpers.bzl +++ b/toolchain/install/symlink_helpers.bzl @@ -46,14 +46,24 @@ symlink_file = rule( def _symlink_filegroup_impl(ctx): prefix = ctx.attr.out_prefix + remove_prefix = ctx.attr.remove_prefix outputs = [] for f in ctx.files.srcs: # We normalize the path to be package-relative in order to ensure - # consistent paths across possible repositories. - relative_path = f.short_path.removeprefix(f.owner.package) + # consistent paths across possible repositories. After experimenting, + # incrementally removing these path fragments, in this order, + # effectively handles the full permutation of files across different + # repositories and both generated and source files. + relative_path = f.path + relative_path = relative_path.removeprefix(f.root.path + "/") + relative_path = relative_path.removeprefix(f.owner.workspace_root + "/") + relative_path = relative_path.removeprefix(f.owner.package + "/") + if not relative_path.startswith(remove_prefix): + fail("Missing `{0}` in `{1}`".format(remove_prefix, relative_path)) + relative_path = relative_path.removeprefix(remove_prefix) - out = ctx.actions.declare_file(prefix + relative_path) + out = ctx.actions.declare_file(prefix + "/" + relative_path) outputs.append(out) ctx.actions.symlink(output = out, target_file = f) @@ -72,6 +82,7 @@ symlink_filegroup = rule( implementation = _symlink_filegroup_impl, attrs = { "out_prefix": attr.string(mandatory = True), + "remove_prefix": attr.string(), "srcs": attr.label_list(mandatory = True), }, )