14
14
#include < string>
15
15
#include < system_error>
16
16
#include < utility>
17
+ #include < variant>
17
18
18
19
#include " clang/Basic/Diagnostic.h"
19
20
#include " clang/Basic/DiagnosticOptions.h"
@@ -51,10 +52,12 @@ auto clang_main(int Argc, char** Argv, const llvm::ToolContext& ToolContext)
51
52
namespace Carbon {
52
53
53
54
ClangRunner::ClangRunner (const InstallPaths* install_paths,
55
+ Runtimes::Cache* runtimes_cache,
54
56
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
55
57
llvm::raw_ostream* vlog_stream,
56
58
bool build_runtimes_on_demand)
57
59
: ToolRunnerBase(install_paths, vlog_stream),
60
+ runtimes_cache_ (runtimes_cache),
58
61
fs_(std::move(fs)),
59
62
diagnostic_ids_(new clang::DiagnosticIDs()),
60
63
build_runtimes_on_demand_(build_runtimes_on_demand) {}
@@ -130,47 +133,44 @@ static auto IsNonLinkCommand(llvm::ArrayRef<llvm::StringRef> args) -> bool {
130
133
});
131
134
}
132
135
133
- auto ClangRunner::Run (
134
- llvm::ArrayRef<llvm::StringRef> args,
135
- std::optional<std::filesystem::path> prebuilt_resource_dir_path)
136
- -> ErrorOr<bool> {
136
+ auto ClangRunner::Run (llvm::ArrayRef<llvm::StringRef> args,
137
+ Runtimes* prebuilt_runtimes) -> ErrorOr<bool> {
137
138
// Check the args to see if we have a known target-independent command. If so,
138
139
// directly dispatch it to avoid the cost of building the target resource
139
140
// directory.
140
141
// TODO: Maybe handle response file expansion similar to the Clang CLI?
141
142
if (args.empty () || args[0 ].starts_with (" -cc1" ) || IsNonLinkCommand (args) ||
142
- (!build_runtimes_on_demand_ && !prebuilt_resource_dir_path )) {
143
+ (!build_runtimes_on_demand_ && !prebuilt_runtimes )) {
143
144
return RunTargetIndependentCommand (args);
144
145
}
145
146
146
147
std::string target = ComputeClangTarget (args);
147
148
148
149
// If we have pre-built runtimes, use them rather than building on demand.
149
- if (prebuilt_resource_dir_path) {
150
- return RunInternal (args, target, prebuilt_resource_dir_path->native ());
150
+ if (prebuilt_runtimes) {
151
+ CARBON_ASSIGN_OR_RETURN (std::filesystem::path prebuilt_resource_dir_path,
152
+ prebuilt_runtimes->Get (Runtimes::ClangResourceDir));
153
+ return RunInternal (args, target, prebuilt_resource_dir_path.native ());
151
154
}
152
155
CARBON_CHECK (build_runtimes_on_demand_);
153
156
154
157
// Otherwise, we need to build a target resource directory.
155
- //
156
- // TODO: Currently, this builds the runtimes in a temporary directory that is
157
- // removed after the Clang invocation. That requires building them on each
158
- // execution which is expensive and slow. Eventually, we want to replace this
159
- // with using an on-disk cache so that only the first execution has to build
160
- // the runtimes and subsequently the cached build can be used.
161
158
CARBON_VLOG (" Building target resource dir...\n " );
162
- CARBON_ASSIGN_OR_RETURN (Filesystem::RemovingDir tmp_dir,
163
- Filesystem::MakeTmpDir ());
164
-
165
- // Hard code the subdirectory for the resource-dir runtimes.
166
- //
167
- // TODO: This should be replaced with an abstraction that manages the layout
168
- // of a built runtimes tree.
169
- std::filesystem::path resource_dir_path =
170
- tmp_dir.abs_path () / " clang_resource_dir" ;
171
-
172
- CARBON_RETURN_IF_ERROR (
173
- BuildTargetResourceDir (target, resource_dir_path, tmp_dir.abs_path ()));
159
+ Runtimes::Cache::Features features = {.target = target};
160
+ CARBON_ASSIGN_OR_RETURN (Runtimes runtimes, runtimes_cache_->Lookup (features));
161
+
162
+ // We need to build the Clang resource directory for these runtimes. This
163
+ // requires a temporary directory as well as the destination directory for
164
+ // the build. The temporary directory should only be used during the build,
165
+ // not once we are running Clang with the built runtime.
166
+ std::filesystem::path resource_dir_path;
167
+ {
168
+ CARBON_ASSIGN_OR_RETURN (Filesystem::RemovingDir tmp_dir,
169
+ Filesystem::MakeTmpDir ());
170
+ CARBON_ASSIGN_OR_RETURN (
171
+ resource_dir_path,
172
+ BuildTargetResourceDir (features, runtimes, tmp_dir.abs_path ()));
173
+ }
174
174
175
175
// Note that this function always successfully runs `clang` and returns a bool
176
176
// to indicate whether `clang` itself succeeded, not whether the runner was
@@ -186,32 +186,37 @@ auto ClangRunner::RunTargetIndependentCommand(
186
186
}
187
187
188
188
auto ClangRunner::BuildTargetResourceDir (
189
- llvm::StringRef target, const std::filesystem::path& resource_dir_path ,
190
- const std::filesystem::path& tmp_path) -> ErrorOr<Success > {
189
+ const Runtimes::Cache::Features& features, Runtimes& runtimes ,
190
+ const std::filesystem::path& tmp_path) -> ErrorOr<std::filesystem::path > {
191
191
// Disable any leaking of memory while building the target resource dir, and
192
192
// restore the previous setting at the end.
193
193
auto restore_leak_flag = llvm::make_scope_exit (
194
194
[&, orig_flag = enable_leaking_] { enable_leaking_ = orig_flag; });
195
195
enable_leaking_ = false ;
196
196
197
- // Create the destination directory if needed.
198
- CARBON_ASSIGN_OR_RETURN (
199
- Filesystem::Dir resource_dir,
200
- Filesystem::Cwd ().CreateDirectories (resource_dir_path));
197
+ CARBON_ASSIGN_OR_RETURN (auto build_dir,
198
+ runtimes.Build (Runtimes::ClangResourceDir));
199
+ if (std::holds_alternative<std::filesystem::path>(build_dir)) {
200
+ // Found cached build.
201
+ return std::get<std::filesystem::path>(std::move (build_dir));
202
+ }
203
+
204
+ auto builder = std::get<Runtimes::Builder>(std::move (build_dir));
205
+ std::string target = features.target ;
201
206
202
207
// Symlink the installation's `include` and `share` directories.
203
208
std::filesystem::path install_resource_path =
204
209
installation_->clang_resource_path ();
205
210
CARBON_RETURN_IF_ERROR (
206
- resource_dir .Symlink (" include" , install_resource_path / " include" ));
211
+ builder. dir () .Symlink (" include" , install_resource_path / " include" ));
207
212
CARBON_RETURN_IF_ERROR (
208
- resource_dir .Symlink (" share" , install_resource_path / " share" ));
213
+ builder. dir () .Symlink (" share" , install_resource_path / " share" ));
209
214
210
215
// Create the target's `lib` directory.
211
216
std::filesystem::path lib_path =
212
217
std::filesystem::path (" lib" ) / std::string_view (target);
213
218
CARBON_ASSIGN_OR_RETURN (Filesystem::Dir lib_dir,
214
- resource_dir .CreateDirectories (lib_path));
219
+ builder. dir () .CreateDirectories (lib_path));
215
220
216
221
llvm::Triple target_triple (target);
217
222
if (target_triple.isOSWindows ()) {
@@ -222,15 +227,15 @@ auto ClangRunner::BuildTargetResourceDir(
222
227
// provide the CRT begin/end files, and so we need to build them.
223
228
if (target_triple.isOSLinux ()) {
224
229
BuildCrtFile (target, RuntimeSources::CrtBegin,
225
- resource_dir_path / lib_path / " clang_rt.crtbegin.o" );
230
+ builder. path () / lib_path / " clang_rt.crtbegin.o" );
226
231
BuildCrtFile (target, RuntimeSources::CrtEnd,
227
- resource_dir_path / lib_path / " clang_rt.crtend.o" );
232
+ builder. path () / lib_path / " clang_rt.crtend.o" );
228
233
}
229
234
230
235
CARBON_RETURN_IF_ERROR (
231
236
BuildBuiltinsLib (target, target_triple, tmp_path, lib_dir));
232
237
233
- return Success ();
238
+ return std::move (builder). Commit ();
234
239
}
235
240
236
241
auto ClangRunner::RunInternal (
@@ -508,11 +513,13 @@ auto ClangRunner::BuildBuiltinsLib(llvm::StringRef target,
508
513
objs.push_back (std::move (*obj));
509
514
}
510
515
511
- // Now build an archive out of the `.o` files for the builtins.
516
+ // Now build an archive out of the `.o` files for the builtins. Note that we
517
+ // build this directly into the `lib_dir` as this is expected to be a staging
518
+ // directory and cleaned up on errors.
512
519
std::filesystem::path builtins_a_path = " libclang_rt.builtins.a" ;
513
520
CARBON_ASSIGN_OR_RETURN (
514
521
Filesystem::WriteFile builtins_a_file,
515
- tmp_dir .OpenWriteOnly (builtins_a_path, Filesystem::CreateAlways));
522
+ lib_dir .OpenWriteOnly (builtins_a_path, Filesystem::CreateAlways));
516
523
{
517
524
llvm::raw_fd_ostream builtins_a_os = builtins_a_file.WriteStream ();
518
525
@@ -528,10 +535,6 @@ auto ClangRunner::BuildBuiltinsLib(llvm::StringRef target,
528
535
}
529
536
CARBON_RETURN_IF_ERROR (std::move (builtins_a_file).Close ());
530
537
531
- // Move it into the lib directory.
532
- CARBON_RETURN_IF_ERROR (
533
- tmp_dir.Rename (builtins_a_path, lib_dir, builtins_a_path));
534
-
535
538
return Success ();
536
539
}
537
540
0 commit comments