Begin building libunwind.a as part of the runtimes (#6381)

This is the first real step towards building libc++ itself, and fleshes
out both the core runtimes management logic and the archive-based
runtimes logic for a quite simple runtime.

Nothing here causes us to _use_ libunwind, and in fact this doesn't
include even the "on-demand" aspect of building `libunwind`. Instead,
this just wires it up to the explicit `build-runtimes` subcommand for
simple testing. The full integration along side the target directory is
future work.
This commit is contained in:
Chandler Carruth
2025-11-18 08:23:29 +00:00
committed by GitHub
parent 77808cd5d7
commit 3930fb13a5
11 changed files with 252 additions and 1 deletions
+1
View File
@@ -116,6 +116,7 @@ http_archive(
"@carbon//bazel/llvm_project:0001_Patch_for_mallinfo2_when_using_Bazel_build_system.patch",
"@carbon//bazel/llvm_project:0002_Added_Bazel_build_for_compiler_rt_fuzzer.patch",
"@carbon//bazel/llvm_project:0003_Comment_out_unloaded_proto_library_dependencies.patch",
"@carbon//bazel/llvm_project:0004_Introduce_basic_sources_exporting_for_libunwind.patch",
],
strip_prefix = "llvm-project-{0}".format(llvm_project_version),
urls = ["https://github.com/llvm/llvm-project/archive/{0}.tar.gz".format(llvm_project_version)],
@@ -0,0 +1,34 @@
Commit ID: a79f1facf56cc5772557cdb09d811aa11a22e43b
Change ID: sxspxmonsuvqzuvxvrvorlumwpwromsv
Author : Chandler Carruth <chandlerc@gmail.com> (2025-09-25 22:55:26)
Committer: Chandler Carruth <chandlerc@gmail.com> (2025-11-17 09:59:25)
Introduce basic sources exporting for libunwind
This exports the source files directly so that they can be used to build
this runtime library on demand.
diff --git a/utils/bazel/llvm-project-overlay/libunwind/BUILD.bazel b/utils/bazel/llvm-project-overlay/libunwind/BUILD.bazel
index c9fdc819c0..7d734c5a06 100644
--- a/utils/bazel/llvm-project-overlay/libunwind/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libunwind/BUILD.bazel
@@ -21,3 +21,19 @@
],
strip_include_prefix = "include",
)
+
+filegroup(
+ name = "libunwind_hdrs",
+ srcs = glob(["include/**/*.h"]),
+)
+
+filegroup(
+ name = "libunwind_srcs",
+ srcs = glob([
+ "src/*.cpp",
+ "src/*.hpp",
+ "src/*.c",
+ "src/*.h",
+ "src/*.S",
+ ]),
+)
+17 -1
View File
@@ -37,6 +37,10 @@ BUILTINS_FILEGROUPS = {
"x86_fp80_srcs": "@llvm-project//compiler-rt:builtins_x86_fp80_srcs",
}
RUNTIMES_FILEGROUPS = {
"libunwind_srcs": "@llvm-project//libunwind:libunwind_srcs",
}
_TEMPLATE = """
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
@@ -85,6 +89,10 @@ inline constexpr llvm::StringLiteral BuiltinsI386Srcs[] = {{
{i386_srcs}
}};
constexpr inline llvm::StringLiteral LibunwindSrcs[] = {{
{libunwind_srcs}
}};
}} // namespace Carbon::RuntimeSources
#endif // CARBON_TOOLCHAIN_BASE_RUNTIME_SOURCES_H_
@@ -99,6 +107,10 @@ def _builtins_path(file):
# label name.
return file.owner.name.removeprefix("lib/")
def _runtimes_path(file):
"""Returns the runtime install path for a file in a normal runtimes library."""
return file.owner.name
def _get_path(file_attr, to_path_fn):
files = file_attr[DefaultInfo].files.to_list()
if len(files) > 1:
@@ -125,6 +137,9 @@ def _generate_runtime_sources_h_rule(ctx):
} | {
k: _get_paths(getattr(ctx.attr, "_" + k), _builtins_path)
for k in BUILTINS_FILEGROUPS.keys()
} | {
k: _get_paths(getattr(ctx.attr, "_" + k), _runtimes_path)
for k in RUNTIMES_FILEGROUPS.keys()
})))
return [DefaultInfo(files = depset([h_file]))]
@@ -135,7 +150,8 @@ generate_runtime_sources_h = rule(
for k, v in CRT_FILES.items()
} | {
"_" + k: attr.label_list(default = [v], allow_files = True)
for k, v in BUILTINS_FILEGROUPS.items()
for k, v in BUILTINS_FILEGROUPS.items() + RUNTIMES_FILEGROUPS.items()
} | {
},
)
+1
View File
@@ -37,6 +37,7 @@ cc_library(
"//common:latch",
"//common:ostream",
"//common:vlog",
"//toolchain/base:kind_switch",
"//toolchain/base:runtime_sources",
"//toolchain/install:install_paths",
"@llvm-project//clang:basic",
@@ -94,8 +94,12 @@ auto BuildRuntimesSubcommand::RunInternal(DriverEnv& driver_env)
ClangResourceDirBuilder resource_dir_builder(&runner, driver_env.thread_pool,
llvm::Triple(features.target),
&runtimes);
ClangArchiveRuntimesBuilder<Runtimes::LibUnwind> lib_unwind_builder(
&runner, driver_env.thread_pool, llvm::Triple(features.target),
&runtimes);
CARBON_RETURN_IF_ERROR(std::move(resource_dir_builder).Wait());
CARBON_RETURN_IF_ERROR(std::move(lib_unwind_builder).Wait());
return runtimes.base_path();
}
+121
View File
@@ -34,6 +34,7 @@
#include "llvm/Support/raw_ostream.h"
#include "llvm/TargetParser/Host.h"
#include "llvm/TargetParser/Triple.h"
#include "toolchain/base/kind_switch.h"
#include "toolchain/base/runtime_sources.h"
#include "toolchain/driver/clang_runner.h"
#include "toolchain/driver/runtimes_cache.h"
@@ -210,6 +211,126 @@ auto ClangRuntimesBuilderBase::ArchiveBuilder::CompileMember(
return std::move(*obj_result);
}
template <Runtimes::Component Component>
requires(Component == Runtimes::LibUnwind)
ClangArchiveRuntimesBuilder<Component>::ClangArchiveRuntimesBuilder(
ClangRunner* clang, llvm::ThreadPoolInterface* threads,
llvm::Triple target_triple, Runtimes* runtimes)
: ClangRuntimesBuilderBase(clang, threads, std::move(target_triple)) {
// Ensure we're on a platform where we _can_ build a working runtime.
if (target_triple_.isOSWindows()) {
result_ =
Error("TODO: Windows runtimes are untested and not yet supported.");
return;
}
auto build_dir_or_error = runtimes->Build(Component);
if (!build_dir_or_error.ok()) {
result_ = std::move(build_dir_or_error).error();
return;
}
auto build_dir = *(std::move(build_dir_or_error));
CARBON_KIND_SWITCH(std::move(build_dir)) {
case CARBON_KIND(std::filesystem::path build_dir_path): {
// Found cached build.
result_ = std::move(build_dir_path);
return;
}
case CARBON_KIND(Runtimes::Builder builder): {
runtimes_builder_ = std::move(builder);
// Building the runtimes is handled below.
break;
}
}
if constexpr (Component == Runtimes::LibUnwind) {
srcs_path_ = installation().libunwind_path();
include_path_ = installation().libunwind_path() / "include";
archive_path_ = std::filesystem::path("lib") / "libunwind.a";
} else {
static_assert(false,
"Invalid runtimes component for an archive runtime builder.");
}
archive_.emplace(this, archive_path_, srcs_path_, CollectSrcFiles(),
CollectCflags());
tasks_.async([this]() mutable { Setup(); });
}
template <Runtimes::Component Component>
requires(Component == Runtimes::LibUnwind)
auto ClangArchiveRuntimesBuilder<Component>::CollectSrcFiles()
-> llvm::SmallVector<llvm::StringRef> {
if constexpr (Component == Runtimes::LibUnwind) {
return llvm::SmallVector<llvm::StringRef>(llvm::make_filter_range(
RuntimeSources::LibunwindSrcs, [](llvm::StringRef src) {
return src.ends_with(".c") || src.ends_with(".cpp") ||
src.ends_with(".S");
}));
} else {
static_assert(false,
"Invalid runtimes component for an archive runtime builder.");
}
}
template <Runtimes::Component Component>
requires(Component == Runtimes::LibUnwind)
auto ClangArchiveRuntimesBuilder<Component>::CollectCflags()
-> llvm::SmallVector<llvm::StringRef> {
if constexpr (Component == Runtimes::LibUnwind) {
return {
"-no-canonical-prefixes",
"-O3",
"-fPIC",
"-funwind-tables",
"-fno-exceptions",
"-fno-rtti",
"-nostdinc++",
"-I",
include_path_.native(),
"-D_LIBUNWIND_IS_NATIVE_ONLY",
"-w",
};
} else {
static_assert(false,
"Invalid runtimes component for an archive runtime builder.");
}
}
template <Runtimes::Component Component>
requires(Component == Runtimes::LibUnwind)
auto ClangArchiveRuntimesBuilder<Component>::Setup() -> void {
// Symlink the installation's `include` into the runtime.
CARBON_CHECK(include_path_.is_absolute(),
"Unexpected relative include path: {0}", include_path_);
if (auto result = runtimes_builder_->dir().Symlink("include", include_path_);
!result.ok()) {
result_ = std::move(result).error();
return;
}
// Finish building the runtime once the archive is built.
Latch::Handle latch_handle = step_counter_.Init(
[this]() mutable { tasks_.async([this]() mutable { Finish(); }); });
// Start building the archive itself with a handle to detect when complete.
archive_->Setup(std::move(latch_handle));
}
template <Runtimes::Component Component>
requires(Component == Runtimes::LibUnwind)
auto ClangArchiveRuntimesBuilder<Component>::Finish() -> void {
CARBON_VLOG("Finished building {0}...\n", archive_path_);
if (!archive_->result().ok()) {
result_ = std::move(archive_->result()).error();
return;
}
result_ = (*std::move(runtimes_builder_)).Commit();
}
template class ClangArchiveRuntimesBuilder<Runtimes::LibUnwind>;
ClangResourceDirBuilder::ClangResourceDirBuilder(
ClangRunner* clang, llvm::ThreadPoolInterface* threads,
llvm::Triple target_triple, Runtimes* runtimes)
+54
View File
@@ -203,6 +203,60 @@ class ClangRuntimesBuilderBase::ArchiveBuilder {
ErrorOr<Success> result_ = Error("No archive built!");
};
// A class template to build runtimes consisting of a single archive.
//
// The template argument comes from the `Runtimes::Component` enum, but is only
// intended for Clang-runtimes that consist of a single archive. We use a
// requires to enforce that the components used are exactly one of those
// supported so we can also move instantiation into the `.cpp` file.
template <Runtimes::Component Component>
requires(Component == Runtimes::LibUnwind)
class ClangArchiveRuntimesBuilder : public ClangRuntimesBuilderBase {
public:
// Constructing this class will attempt to build the `Component` archive into
// `runtimes`.
//
// If an existing build is found, it will immediately be available.
// Otherwise, constructing this class will schedule asynchronous work on
// `threads` to build the archive on-demand using `clang`.
//
// Once constructed, callers may call `Wait` (from the base class) to wait
// until the asynchronous work is complete and the runtimes are available. If
// they were already available, the call to `Wait` will not block.
ClangArchiveRuntimesBuilder(ClangRunner* clang,
llvm::ThreadPoolInterface* threads,
llvm::Triple target_triple, Runtimes* runtimes);
private:
// Helpers to compute the list of source files and compile flags for a
// particular archive. The implementations of these are expected to be
// specialized for each different `Component`.
auto CollectSrcFiles() -> llvm::SmallVector<llvm::StringRef>;
auto CollectCflags() -> llvm::SmallVector<llvm::StringRef>;
// Helper to encapsulate the initial, but still asynchronous setup work.
auto Setup() -> void;
// Helper to encapsulate the final asynchronous step in building the resource
// directory.
auto Finish() -> void;
// The root path used for any of the source files.
std::filesystem::path srcs_path_;
// The (absolute) include path used during the compilation of the source
// files.
std::filesystem::path include_path_;
// The relative archive path within the runtimes' build directory.
std::filesystem::path archive_path_;
// The archive builder if it is necessary to build the archive.
std::optional<ArchiveBuilder> archive_;
};
extern template class ClangArchiveRuntimesBuilder<Runtimes::LibUnwind>;
// Builds the target-specific resource directory for Clang.
//
// There is a resource directory installed along side the Clang binary that
+3
View File
@@ -46,6 +46,7 @@ class Runtimes {
enum Component {
ClangResourceDir,
LibUnwind,
NumComponents,
};
@@ -136,6 +137,8 @@ class Runtimes {
switch (component) {
case ClangResourceDir:
return "clang_resource_dir";
case LibUnwind:
return "libunwind";
case NumComponents:
CARBON_FATAL("Invalid component");
}
+9
View File
@@ -162,6 +162,14 @@ filegroup(
srcs = CRT_FILES.values() + BUILTINS_FILEGROUPS.values(),
)
filegroup(
name = "libunwind",
srcs = [
"@llvm-project//libunwind:libunwind_hdrs",
"@llvm-project//libunwind:libunwind_srcs",
],
)
# Given a root `prefix_root`, the hierarchy looks like:
#
# - prefix_root/bin: Binaries intended for direct use.
@@ -195,6 +203,7 @@ install_dirs = {
is_driver = True,
),
install_filegroup("core", "//core:prelude"),
install_filegroup("libunwind", ":libunwind"),
],
"lib/carbon/llvm/bin": [install_symlink(
name,
+5
View File
@@ -225,6 +225,11 @@ auto InstallPaths::llvm_runtime_srcs() const -> std::filesystem::path {
"/src";
}
auto InstallPaths::libunwind_path() const -> std::filesystem::path {
// TODO: Adjust this to work equally well on Windows.
return prefix_ / "lib/carbon/libunwind";
}
auto InstallPaths::digest_path() const -> std::filesystem::path {
// TODO: Adjust this to work equally well on Windows.
return prefix_ / "lib/carbon/install_digest.txt";
+3
View File
@@ -111,6 +111,9 @@ class InstallPaths {
// The path to the root of LLVM runtime sources.
auto llvm_runtime_srcs() const -> std::filesystem::path;
// The path to `libunwind` runtime.
auto libunwind_path() const -> std::filesystem::path;
// The installation digest path.
//
// This file contains a digest of the installation.