Skip to content

Commit 3930fb1

Browse files
authored
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.
1 parent 77808cd commit 3930fb1

File tree

11 files changed

+252
-1
lines changed

11 files changed

+252
-1
lines changed

MODULE.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ http_archive(
116116
"@carbon//bazel/llvm_project:0001_Patch_for_mallinfo2_when_using_Bazel_build_system.patch",
117117
"@carbon//bazel/llvm_project:0002_Added_Bazel_build_for_compiler_rt_fuzzer.patch",
118118
"@carbon//bazel/llvm_project:0003_Comment_out_unloaded_proto_library_dependencies.patch",
119+
"@carbon//bazel/llvm_project:0004_Introduce_basic_sources_exporting_for_libunwind.patch",
119120
],
120121
strip_prefix = "llvm-project-{0}".format(llvm_project_version),
121122
urls = ["https://github.com/llvm/llvm-project/archive/{0}.tar.gz".format(llvm_project_version)],
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
Commit ID: a79f1facf56cc5772557cdb09d811aa11a22e43b
2+
Change ID: sxspxmonsuvqzuvxvrvorlumwpwromsv
3+
Author : Chandler Carruth <[email protected]> (2025-09-25 22:55:26)
4+
Committer: Chandler Carruth <[email protected]> (2025-11-17 09:59:25)
5+
6+
Introduce basic sources exporting for libunwind
7+
8+
This exports the source files directly so that they can be used to build
9+
this runtime library on demand.
10+
11+
diff --git a/utils/bazel/llvm-project-overlay/libunwind/BUILD.bazel b/utils/bazel/llvm-project-overlay/libunwind/BUILD.bazel
12+
index c9fdc819c0..7d734c5a06 100644
13+
--- a/utils/bazel/llvm-project-overlay/libunwind/BUILD.bazel
14+
+++ b/utils/bazel/llvm-project-overlay/libunwind/BUILD.bazel
15+
@@ -21,3 +21,19 @@
16+
],
17+
strip_include_prefix = "include",
18+
)
19+
+
20+
+filegroup(
21+
+ name = "libunwind_hdrs",
22+
+ srcs = glob(["include/**/*.h"]),
23+
+)
24+
+
25+
+filegroup(
26+
+ name = "libunwind_srcs",
27+
+ srcs = glob([
28+
+ "src/*.cpp",
29+
+ "src/*.hpp",
30+
+ "src/*.c",
31+
+ "src/*.h",
32+
+ "src/*.S",
33+
+ ]),
34+
+)

toolchain/base/runtime_sources.bzl

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ BUILTINS_FILEGROUPS = {
3737
"x86_fp80_srcs": "@llvm-project//compiler-rt:builtins_x86_fp80_srcs",
3838
}
3939

40+
RUNTIMES_FILEGROUPS = {
41+
"libunwind_srcs": "@llvm-project//libunwind:libunwind_srcs",
42+
}
43+
4044
_TEMPLATE = """
4145
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
4246
// Exceptions. See /LICENSE for license information.
@@ -85,6 +89,10 @@ inline constexpr llvm::StringLiteral BuiltinsI386Srcs[] = {{
8589
{i386_srcs}
8690
}};
8791
92+
constexpr inline llvm::StringLiteral LibunwindSrcs[] = {{
93+
{libunwind_srcs}
94+
}};
95+
8896
}} // namespace Carbon::RuntimeSources
8997
9098
#endif // CARBON_TOOLCHAIN_BASE_RUNTIME_SOURCES_H_
@@ -99,6 +107,10 @@ def _builtins_path(file):
99107
# label name.
100108
return file.owner.name.removeprefix("lib/")
101109

110+
def _runtimes_path(file):
111+
"""Returns the runtime install path for a file in a normal runtimes library."""
112+
return file.owner.name
113+
102114
def _get_path(file_attr, to_path_fn):
103115
files = file_attr[DefaultInfo].files.to_list()
104116
if len(files) > 1:
@@ -125,6 +137,9 @@ def _generate_runtime_sources_h_rule(ctx):
125137
} | {
126138
k: _get_paths(getattr(ctx.attr, "_" + k), _builtins_path)
127139
for k in BUILTINS_FILEGROUPS.keys()
140+
} | {
141+
k: _get_paths(getattr(ctx.attr, "_" + k), _runtimes_path)
142+
for k in RUNTIMES_FILEGROUPS.keys()
128143
})))
129144
return [DefaultInfo(files = depset([h_file]))]
130145

@@ -135,7 +150,8 @@ generate_runtime_sources_h = rule(
135150
for k, v in CRT_FILES.items()
136151
} | {
137152
"_" + k: attr.label_list(default = [v], allow_files = True)
138-
for k, v in BUILTINS_FILEGROUPS.items()
153+
for k, v in BUILTINS_FILEGROUPS.items() + RUNTIMES_FILEGROUPS.items()
154+
} | {
139155
},
140156
)
141157

toolchain/driver/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ cc_library(
3737
"//common:latch",
3838
"//common:ostream",
3939
"//common:vlog",
40+
"//toolchain/base:kind_switch",
4041
"//toolchain/base:runtime_sources",
4142
"//toolchain/install:install_paths",
4243
"@llvm-project//clang:basic",

toolchain/driver/build_runtimes_subcommand.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,12 @@ auto BuildRuntimesSubcommand::RunInternal(DriverEnv& driver_env)
9494
ClangResourceDirBuilder resource_dir_builder(&runner, driver_env.thread_pool,
9595
llvm::Triple(features.target),
9696
&runtimes);
97+
ClangArchiveRuntimesBuilder<Runtimes::LibUnwind> lib_unwind_builder(
98+
&runner, driver_env.thread_pool, llvm::Triple(features.target),
99+
&runtimes);
97100

98101
CARBON_RETURN_IF_ERROR(std::move(resource_dir_builder).Wait());
102+
CARBON_RETURN_IF_ERROR(std::move(lib_unwind_builder).Wait());
99103

100104
return runtimes.base_path();
101105
}

toolchain/driver/clang_runtimes.cpp

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "llvm/Support/raw_ostream.h"
3535
#include "llvm/TargetParser/Host.h"
3636
#include "llvm/TargetParser/Triple.h"
37+
#include "toolchain/base/kind_switch.h"
3738
#include "toolchain/base/runtime_sources.h"
3839
#include "toolchain/driver/clang_runner.h"
3940
#include "toolchain/driver/runtimes_cache.h"
@@ -210,6 +211,126 @@ auto ClangRuntimesBuilderBase::ArchiveBuilder::CompileMember(
210211
return std::move(*obj_result);
211212
}
212213

214+
template <Runtimes::Component Component>
215+
requires(Component == Runtimes::LibUnwind)
216+
ClangArchiveRuntimesBuilder<Component>::ClangArchiveRuntimesBuilder(
217+
ClangRunner* clang, llvm::ThreadPoolInterface* threads,
218+
llvm::Triple target_triple, Runtimes* runtimes)
219+
: ClangRuntimesBuilderBase(clang, threads, std::move(target_triple)) {
220+
// Ensure we're on a platform where we _can_ build a working runtime.
221+
if (target_triple_.isOSWindows()) {
222+
result_ =
223+
Error("TODO: Windows runtimes are untested and not yet supported.");
224+
return;
225+
}
226+
227+
auto build_dir_or_error = runtimes->Build(Component);
228+
if (!build_dir_or_error.ok()) {
229+
result_ = std::move(build_dir_or_error).error();
230+
return;
231+
}
232+
auto build_dir = *(std::move(build_dir_or_error));
233+
CARBON_KIND_SWITCH(std::move(build_dir)) {
234+
case CARBON_KIND(std::filesystem::path build_dir_path): {
235+
// Found cached build.
236+
result_ = std::move(build_dir_path);
237+
return;
238+
}
239+
case CARBON_KIND(Runtimes::Builder builder): {
240+
runtimes_builder_ = std::move(builder);
241+
// Building the runtimes is handled below.
242+
break;
243+
}
244+
}
245+
246+
if constexpr (Component == Runtimes::LibUnwind) {
247+
srcs_path_ = installation().libunwind_path();
248+
include_path_ = installation().libunwind_path() / "include";
249+
archive_path_ = std::filesystem::path("lib") / "libunwind.a";
250+
} else {
251+
static_assert(false,
252+
"Invalid runtimes component for an archive runtime builder.");
253+
}
254+
255+
archive_.emplace(this, archive_path_, srcs_path_, CollectSrcFiles(),
256+
CollectCflags());
257+
tasks_.async([this]() mutable { Setup(); });
258+
}
259+
260+
template <Runtimes::Component Component>
261+
requires(Component == Runtimes::LibUnwind)
262+
auto ClangArchiveRuntimesBuilder<Component>::CollectSrcFiles()
263+
-> llvm::SmallVector<llvm::StringRef> {
264+
if constexpr (Component == Runtimes::LibUnwind) {
265+
return llvm::SmallVector<llvm::StringRef>(llvm::make_filter_range(
266+
RuntimeSources::LibunwindSrcs, [](llvm::StringRef src) {
267+
return src.ends_with(".c") || src.ends_with(".cpp") ||
268+
src.ends_with(".S");
269+
}));
270+
} else {
271+
static_assert(false,
272+
"Invalid runtimes component for an archive runtime builder.");
273+
}
274+
}
275+
276+
template <Runtimes::Component Component>
277+
requires(Component == Runtimes::LibUnwind)
278+
auto ClangArchiveRuntimesBuilder<Component>::CollectCflags()
279+
-> llvm::SmallVector<llvm::StringRef> {
280+
if constexpr (Component == Runtimes::LibUnwind) {
281+
return {
282+
"-no-canonical-prefixes",
283+
"-O3",
284+
"-fPIC",
285+
"-funwind-tables",
286+
"-fno-exceptions",
287+
"-fno-rtti",
288+
"-nostdinc++",
289+
"-I",
290+
include_path_.native(),
291+
"-D_LIBUNWIND_IS_NATIVE_ONLY",
292+
"-w",
293+
};
294+
} else {
295+
static_assert(false,
296+
"Invalid runtimes component for an archive runtime builder.");
297+
}
298+
}
299+
300+
template <Runtimes::Component Component>
301+
requires(Component == Runtimes::LibUnwind)
302+
auto ClangArchiveRuntimesBuilder<Component>::Setup() -> void {
303+
// Symlink the installation's `include` into the runtime.
304+
CARBON_CHECK(include_path_.is_absolute(),
305+
"Unexpected relative include path: {0}", include_path_);
306+
if (auto result = runtimes_builder_->dir().Symlink("include", include_path_);
307+
!result.ok()) {
308+
result_ = std::move(result).error();
309+
return;
310+
}
311+
312+
// Finish building the runtime once the archive is built.
313+
Latch::Handle latch_handle = step_counter_.Init(
314+
[this]() mutable { tasks_.async([this]() mutable { Finish(); }); });
315+
316+
// Start building the archive itself with a handle to detect when complete.
317+
archive_->Setup(std::move(latch_handle));
318+
}
319+
320+
template <Runtimes::Component Component>
321+
requires(Component == Runtimes::LibUnwind)
322+
auto ClangArchiveRuntimesBuilder<Component>::Finish() -> void {
323+
CARBON_VLOG("Finished building {0}...\n", archive_path_);
324+
if (!archive_->result().ok()) {
325+
result_ = std::move(archive_->result()).error();
326+
return;
327+
}
328+
329+
result_ = (*std::move(runtimes_builder_)).Commit();
330+
}
331+
332+
template class ClangArchiveRuntimesBuilder<Runtimes::LibUnwind>;
333+
213334
ClangResourceDirBuilder::ClangResourceDirBuilder(
214335
ClangRunner* clang, llvm::ThreadPoolInterface* threads,
215336
llvm::Triple target_triple, Runtimes* runtimes)

toolchain/driver/clang_runtimes.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,60 @@ class ClangRuntimesBuilderBase::ArchiveBuilder {
203203
ErrorOr<Success> result_ = Error("No archive built!");
204204
};
205205

206+
// A class template to build runtimes consisting of a single archive.
207+
//
208+
// The template argument comes from the `Runtimes::Component` enum, but is only
209+
// intended for Clang-runtimes that consist of a single archive. We use a
210+
// requires to enforce that the components used are exactly one of those
211+
// supported so we can also move instantiation into the `.cpp` file.
212+
template <Runtimes::Component Component>
213+
requires(Component == Runtimes::LibUnwind)
214+
class ClangArchiveRuntimesBuilder : public ClangRuntimesBuilderBase {
215+
public:
216+
// Constructing this class will attempt to build the `Component` archive into
217+
// `runtimes`.
218+
//
219+
// If an existing build is found, it will immediately be available.
220+
// Otherwise, constructing this class will schedule asynchronous work on
221+
// `threads` to build the archive on-demand using `clang`.
222+
//
223+
// Once constructed, callers may call `Wait` (from the base class) to wait
224+
// until the asynchronous work is complete and the runtimes are available. If
225+
// they were already available, the call to `Wait` will not block.
226+
ClangArchiveRuntimesBuilder(ClangRunner* clang,
227+
llvm::ThreadPoolInterface* threads,
228+
llvm::Triple target_triple, Runtimes* runtimes);
229+
230+
private:
231+
// Helpers to compute the list of source files and compile flags for a
232+
// particular archive. The implementations of these are expected to be
233+
// specialized for each different `Component`.
234+
auto CollectSrcFiles() -> llvm::SmallVector<llvm::StringRef>;
235+
auto CollectCflags() -> llvm::SmallVector<llvm::StringRef>;
236+
237+
// Helper to encapsulate the initial, but still asynchronous setup work.
238+
auto Setup() -> void;
239+
240+
// Helper to encapsulate the final asynchronous step in building the resource
241+
// directory.
242+
auto Finish() -> void;
243+
244+
// The root path used for any of the source files.
245+
std::filesystem::path srcs_path_;
246+
247+
// The (absolute) include path used during the compilation of the source
248+
// files.
249+
std::filesystem::path include_path_;
250+
251+
// The relative archive path within the runtimes' build directory.
252+
std::filesystem::path archive_path_;
253+
254+
// The archive builder if it is necessary to build the archive.
255+
std::optional<ArchiveBuilder> archive_;
256+
};
257+
258+
extern template class ClangArchiveRuntimesBuilder<Runtimes::LibUnwind>;
259+
206260
// Builds the target-specific resource directory for Clang.
207261
//
208262
// There is a resource directory installed along side the Clang binary that

toolchain/driver/runtimes_cache.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class Runtimes {
4646

4747
enum Component {
4848
ClangResourceDir,
49+
LibUnwind,
4950

5051
NumComponents,
5152
};
@@ -136,6 +137,8 @@ class Runtimes {
136137
switch (component) {
137138
case ClangResourceDir:
138139
return "clang_resource_dir";
140+
case LibUnwind:
141+
return "libunwind";
139142
case NumComponents:
140143
CARBON_FATAL("Invalid component");
141144
}

toolchain/install/BUILD

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,14 @@ filegroup(
162162
srcs = CRT_FILES.values() + BUILTINS_FILEGROUPS.values(),
163163
)
164164

165+
filegroup(
166+
name = "libunwind",
167+
srcs = [
168+
"@llvm-project//libunwind:libunwind_hdrs",
169+
"@llvm-project//libunwind:libunwind_srcs",
170+
],
171+
)
172+
165173
# Given a root `prefix_root`, the hierarchy looks like:
166174
#
167175
# - prefix_root/bin: Binaries intended for direct use.
@@ -195,6 +203,7 @@ install_dirs = {
195203
is_driver = True,
196204
),
197205
install_filegroup("core", "//core:prelude"),
206+
install_filegroup("libunwind", ":libunwind"),
198207
],
199208
"lib/carbon/llvm/bin": [install_symlink(
200209
name,

toolchain/install/install_paths.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,11 @@ auto InstallPaths::llvm_runtime_srcs() const -> std::filesystem::path {
225225
"/src";
226226
}
227227

228+
auto InstallPaths::libunwind_path() const -> std::filesystem::path {
229+
// TODO: Adjust this to work equally well on Windows.
230+
return prefix_ / "lib/carbon/libunwind";
231+
}
232+
228233
auto InstallPaths::digest_path() const -> std::filesystem::path {
229234
// TODO: Adjust this to work equally well on Windows.
230235
return prefix_ / "lib/carbon/install_digest.txt";

0 commit comments

Comments
 (0)