12
12
#include " common/ostream.h"
13
13
#include " llvm/ADT/ArrayRef.h"
14
14
#include " llvm/ADT/StringRef.h"
15
+ #include " llvm/Support/ThreadPool.h"
15
16
#include " llvm/Support/VirtualFileSystem.h"
16
17
#include " llvm/TargetParser/Triple.h"
17
18
#include " toolchain/driver/runtimes_cache.h"
@@ -25,11 +26,15 @@ namespace Carbon {
25
26
// incorporating custom command line flags from user invocations that we don't
26
27
// parse, but will pass transparently along to Clang itself.
27
28
//
29
+ // This class is thread safe, allowing multiple threads to share a single runner
30
+ // and concurrently invoke Clang.
31
+ //
28
32
// This doesn't literally use a subprocess to invoke Clang; it instead tries to
29
33
// directly use the Clang command line driver library. We also work to simplify
30
34
// how that driver operates and invoke it in an opinionated way to get the best
31
35
// behavior for our expected use cases in the Carbon driver:
32
36
//
37
+ // - Ensure thread-safe invocation of Clang to enable concurrent usage.
33
38
// - Minimize canonicalization of file names to try to preserve the paths as
34
39
// users type them.
35
40
// - Minimize the use of subprocess invocations which are expensive on some
@@ -42,43 +47,57 @@ namespace Carbon {
42
47
// standard output and standard error, and otherwise can only read and write
43
48
// files based on their names described in the arguments. It doesn't provide any
44
49
// higher-level abstraction such as streams for inputs or outputs.
50
+ //
51
+ // TODO: Switch the diagnostic machinery to buffer and do locked output so that
52
+ // concurrent invocations of Clang don't intermingle their diagnostic output.
53
+ //
54
+ // TODO: If support for thread-local overrides of `llvm::errs` and `llvm::outs`
55
+ // becomes available upstream, also buffer and synchronize those streams to
56
+ // further improve the behavior of concurrent invocations.
45
57
class ClangRunner : ToolRunnerBase {
46
58
public:
47
- // Build a Clang runner that uses the provided `exe_name` and `err_stream` .
59
+ // Build a Clang runner that uses the provided installation and filesystem .
48
60
//
49
- // If `verbose` is passed as true, will enable verbose logging to the
50
- // `err_stream` both from the runner and Clang itself .
61
+ // Optionally accepts a `vlog_stream` to enable verbose logging from Carbon to
62
+ // that stream. The verbose output from Clang goes to stderr regardless .
51
63
ClangRunner (const InstallPaths* install_paths,
52
- Runtimes::Cache* on_demand_runtimes_cache,
53
64
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
54
- llvm::raw_ostream* vlog_stream = nullptr ,
55
- bool build_runtimes_on_demand = false );
65
+ llvm::raw_ostream* vlog_stream = nullptr );
56
66
57
- // Run Clang with the provided arguments.
67
+ // Run Clang with the provided arguments and a runtime cache for on-demand
68
+ // runtime building.
58
69
//
59
70
// This works to support all of the Clang commandline, including commands that
60
71
// use target-dependent resources like linking. When it detects such commands,
61
- // it will either use the provided target resource-dir path, or if building
62
- // runtimes on demand is enabled it will build the needed resource-dir.
72
+ // it will use runtimes from the provided cache. If not available in the
73
+ // cache, it will build the necessary runtimes using the provided thread pool
74
+ // both to use and incorporate into the cache.
63
75
//
64
76
// Returns an error only if unable to successfully run Clang with the
65
77
// arguments. If able to run Clang, no error is returned a bool indicating
66
78
// whether than Clang invocation succeeded is returned.
67
- //
68
- // TODO: Eventually, this will need to accept an abstraction that can
69
- // represent multiple different pre-built runtimes.
70
79
auto Run (llvm::ArrayRef<llvm::StringRef> args,
71
- Runtimes* prebuilt_runtimes = nullptr ) -> ErrorOr<bool>;
80
+ Runtimes::Cache& runtimes_cache,
81
+ llvm::ThreadPoolInterface& runtimes_build_thread_pool)
82
+ -> ErrorOr<bool>;
83
+
84
+ // Run Clang with the provided arguments and prebuilt runtimes.
85
+ //
86
+ // Similar to `Run`, but requires and uses pre-built runtimes rather than a
87
+ // cache or building them on demand.
88
+ auto RunWithPrebuiltRuntimes (llvm::ArrayRef<llvm::StringRef> args,
89
+ Runtimes& prebuilt_runtimes) -> ErrorOr<bool>;
72
90
73
- // Run Clang with the provided arguments and without any target-dependent
74
- // resources.
91
+ // Run Clang with the provided arguments and without any target runtimes.
75
92
//
76
93
// This method can be used to avoid building target-dependent resources when
77
94
// unnecessary, but not all Clang command lines will work correctly.
78
95
// Specifically, compile-only commands will typically work, while linking will
79
96
// not.
80
- auto RunTargetIndependentCommand (llvm::ArrayRef<llvm::StringRef> args)
81
- -> bool;
97
+ //
98
+ // This function simply returns true or false depending on whether Clang runs
99
+ // successfully, as it should display any needed error messages.
100
+ auto RunWithNoRuntimes (llvm::ArrayRef<llvm::StringRef> args) -> bool;
82
101
83
102
// Builds the target-specific resource directory for Clang.
84
103
//
@@ -88,7 +107,8 @@ class ClangRunner : ToolRunnerBase {
88
107
// return the path.
89
108
auto BuildTargetResourceDir (const Runtimes::Cache::Features& features,
90
109
Runtimes& runtimes,
91
- const std::filesystem::path& tmp_path)
110
+ const std::filesystem::path& tmp_path,
111
+ llvm::ThreadPoolInterface& threads)
92
112
-> ErrorOr<std::filesystem::path>;
93
113
94
114
// Enable leaking memory.
@@ -103,6 +123,14 @@ class ClangRunner : ToolRunnerBase {
103
123
auto EnableLeakingMemory () -> void { enable_leaking_ = true ; }
104
124
105
125
private:
126
+ // Emulates `cc1_main` but in a way that doesn't assume it is running in the
127
+ // main thread and can more easily fit into library calls to do compiles.
128
+ //
129
+ // TODO: Much of the logic here should be factored out of the CC1
130
+ // implementation in Clang's driver and into a reusable part of its libraries.
131
+ // That should allow reducing the code here to a minimal amount.
132
+ auto RunCC1 (llvm::SmallVectorImpl<const char *>& cc1_args) -> int;
133
+
106
134
// Handles building the Clang driver and passing the arguments down to it.
107
135
auto RunInternal (llvm::ArrayRef<llvm::StringRef> args, llvm::StringRef target,
108
136
std::optional<llvm::StringRef> target_resource_dir_path)
@@ -125,16 +153,11 @@ class ClangRunner : ToolRunnerBase {
125
153
auto BuildBuiltinsLib (llvm::StringRef target,
126
154
const llvm::Triple& target_triple,
127
155
const std::filesystem::path& tmp_path,
128
- Filesystem::DirRef lib_dir) -> ErrorOr<Success>;
129
-
130
- Runtimes::Cache* runtimes_cache_;
156
+ Filesystem::DirRef lib_dir,
157
+ llvm::ThreadPoolInterface& threads) -> ErrorOr<Success>;
131
158
132
159
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs_;
133
- llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagnostic_ids_;
134
-
135
- std::optional<std::filesystem::path> prebuilt_runtimes_path_;
136
160
137
- bool build_runtimes_on_demand_;
138
161
bool enable_leaking_ = false ;
139
162
};
140
163
0 commit comments