Skip to content

Commit f80a0ea

Browse files
committed
[clang][deps] Split translation units into individual -cc1 or other commands
Instead of trying to "fix" the original driver invocation by appending arguments to it, split it into multiple commands, and for each -cc1 command use a CompilerInvocation to give precise control over the invocation. This change should make it easier to (in the future) canonicalize the command-line (e.g. to improve hits in something like ccache), apply optimizations, or start supporting multi-arch builds, which would require different modules for each arch. In the long run it may make sense to treat the TU commands as a dependency graph, each with their own dependencies on modules or earlier TU commands, but for now they are simply a list that is executed in order, and the dependencies are simply duplicated. Since we currently only support single-arch builds, there is no parallelism available in the execution. Differential Revision: https://reviews.llvm.org/D132405
1 parent 260fb2b commit f80a0ea

27 files changed

+650
-207
lines changed

clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,16 @@ struct FullDependencies {
4949
/// determined that the differences are benign for this compilation.
5050
std::vector<ModuleID> ClangModuleDeps;
5151

52-
/// The command line of the TU (excluding the compiler executable).
53-
std::vector<std::string> CommandLine;
52+
/// The sequence of commands required to build the translation unit. Commands
53+
/// should be executed in order.
54+
///
55+
/// FIXME: If we add support for multi-arch builds in clang-scan-deps, we
56+
/// should make the dependencies between commands explicit to enable parallel
57+
/// builds of each architecture.
58+
std::vector<Command> Commands;
59+
60+
/// Deprecated driver command-line. This will be removed in a future version.
61+
std::vector<std::string> DriverCommandLine;
5462
};
5563

5664
struct FullDependenciesResult {
@@ -99,6 +107,12 @@ class DependencyScanningTool {
99107
LookupModuleOutputCallback LookupModuleOutput,
100108
llvm::Optional<StringRef> ModuleName = None);
101109

110+
llvm::Expected<FullDependenciesResult> getFullDependenciesLegacyDriverCommand(
111+
const std::vector<std::string> &CommandLine, StringRef CWD,
112+
const llvm::StringSet<> &AlreadySeen,
113+
LookupModuleOutputCallback LookupModuleOutput,
114+
llvm::Optional<StringRef> ModuleName = None);
115+
102116
private:
103117
DependencyScanningWorker Worker;
104118
};
@@ -111,6 +125,10 @@ class FullDependencyConsumer : public DependencyConsumer {
111125
: AlreadySeen(AlreadySeen), LookupModuleOutput(LookupModuleOutput),
112126
EagerLoadModules(EagerLoadModules) {}
113127

128+
void handleBuildCommand(Command Cmd) override {
129+
Commands.push_back(std::move(Cmd));
130+
}
131+
114132
void handleDependencyOutputOpts(const DependencyOutputOptions &) override {}
115133

116134
void handleFileDependency(StringRef File) override {
@@ -134,14 +152,17 @@ class FullDependencyConsumer : public DependencyConsumer {
134152
return LookupModuleOutput(ID, Kind);
135153
}
136154

137-
FullDependenciesResult getFullDependencies(
155+
FullDependenciesResult getFullDependenciesLegacyDriverCommand(
138156
const std::vector<std::string> &OriginalCommandLine) const;
139157

158+
FullDependenciesResult takeFullDependencies();
159+
140160
private:
141161
std::vector<std::string> Dependencies;
142162
std::vector<PrebuiltModuleDep> PrebuiltModuleDeps;
143163
llvm::MapVector<std::string, ModuleDeps, llvm::StringMap<unsigned>>
144164
ClangModuleDeps;
165+
std::vector<Command> Commands;
145166
std::string ContextHash;
146167
std::vector<std::string> OutputPaths;
147168
const llvm::StringSet<> &AlreadySeen;

clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,20 @@ namespace dependencies {
2828

2929
class DependencyScanningWorkerFilesystem;
3030

31+
/// A command-line tool invocation that is part of building a TU.
32+
///
33+
/// \see FullDependencies::Commands.
34+
struct Command {
35+
std::string Executable;
36+
std::vector<std::string> Arguments;
37+
};
38+
3139
class DependencyConsumer {
3240
public:
3341
virtual ~DependencyConsumer() {}
3442

43+
virtual void handleBuildCommand(Command Cmd) = 0;
44+
3545
virtual void
3646
handleDependencyOutputOpts(const DependencyOutputOptions &Opts) = 0;
3747

clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,12 +181,16 @@ class ModuleDepCollector final : public DependencyCollector {
181181
public:
182182
ModuleDepCollector(std::unique_ptr<DependencyOutputOptions> Opts,
183183
CompilerInstance &ScanInstance, DependencyConsumer &C,
184-
CompilerInvocation &&OriginalCI, bool OptimizeArgs,
184+
CompilerInvocation OriginalCI, bool OptimizeArgs,
185185
bool EagerLoadModules);
186186

187187
void attachToPreprocessor(Preprocessor &PP) override;
188188
void attachToASTReader(ASTReader &R) override;
189189

190+
/// Apply any changes implied by the discovered dependencies to the given
191+
/// invocation, (e.g. disable implicit modules, add explicit module paths).
192+
void applyDiscoveredDependencies(CompilerInvocation &CI);
193+
190194
private:
191195
friend ModuleDepCollectorPP;
192196

clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ llvm::Expected<std::string> DependencyScanningTool::getDependencyFile(
4545
/// Prints out all of the gathered dependencies into a string.
4646
class MakeDependencyPrinterConsumer : public DependencyConsumer {
4747
public:
48+
void handleBuildCommand(Command) override {}
49+
4850
void
4951
handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override {
5052
this->Opts = std::make_unique<DependencyOutputOptions>(Opts);
@@ -120,34 +122,74 @@ DependencyScanningTool::getFullDependencies(
120122
Worker.computeDependencies(CWD, CommandLine, Consumer, ModuleName);
121123
if (Result)
122124
return std::move(Result);
123-
return Consumer.getFullDependencies(CommandLine);
125+
return Consumer.takeFullDependencies();
126+
}
127+
128+
llvm::Expected<FullDependenciesResult>
129+
DependencyScanningTool::getFullDependenciesLegacyDriverCommand(
130+
const std::vector<std::string> &CommandLine, StringRef CWD,
131+
const llvm::StringSet<> &AlreadySeen,
132+
LookupModuleOutputCallback LookupModuleOutput,
133+
llvm::Optional<StringRef> ModuleName) {
134+
FullDependencyConsumer Consumer(AlreadySeen, LookupModuleOutput,
135+
Worker.shouldEagerLoadModules());
136+
llvm::Error Result =
137+
Worker.computeDependencies(CWD, CommandLine, Consumer, ModuleName);
138+
if (Result)
139+
return std::move(Result);
140+
return Consumer.getFullDependenciesLegacyDriverCommand(CommandLine);
141+
}
142+
143+
FullDependenciesResult FullDependencyConsumer::takeFullDependencies() {
144+
FullDependenciesResult FDR;
145+
FullDependencies &FD = FDR.FullDeps;
146+
147+
FD.ID.ContextHash = std::move(ContextHash);
148+
FD.FileDeps = std::move(Dependencies);
149+
FD.PrebuiltModuleDeps = std::move(PrebuiltModuleDeps);
150+
FD.Commands = std::move(Commands);
151+
152+
for (auto &&M : ClangModuleDeps) {
153+
auto &MD = M.second;
154+
if (MD.ImportedByMainFile)
155+
FD.ClangModuleDeps.push_back(MD.ID);
156+
// TODO: Avoid handleModuleDependency even being called for modules
157+
// we've already seen.
158+
if (AlreadySeen.count(M.first))
159+
continue;
160+
FDR.DiscoveredModules.push_back(std::move(MD));
161+
}
162+
163+
return FDR;
124164
}
125165

126-
FullDependenciesResult FullDependencyConsumer::getFullDependencies(
166+
FullDependenciesResult
167+
FullDependencyConsumer::getFullDependenciesLegacyDriverCommand(
127168
const std::vector<std::string> &OriginalCommandLine) const {
128169
FullDependencies FD;
129170

130-
FD.CommandLine = makeTUCommandLineWithoutPaths(
171+
FD.DriverCommandLine = makeTUCommandLineWithoutPaths(
131172
ArrayRef<std::string>(OriginalCommandLine).slice(1));
132173

133174
FD.ID.ContextHash = std::move(ContextHash);
134175

135176
FD.FileDeps.assign(Dependencies.begin(), Dependencies.end());
136177

137178
for (const PrebuiltModuleDep &PMD : PrebuiltModuleDeps)
138-
FD.CommandLine.push_back("-fmodule-file=" + PMD.PCMFile);
179+
FD.DriverCommandLine.push_back("-fmodule-file=" + PMD.PCMFile);
139180

140181
for (auto &&M : ClangModuleDeps) {
141182
auto &MD = M.second;
142183
if (MD.ImportedByMainFile) {
143184
FD.ClangModuleDeps.push_back(MD.ID);
144185
auto PCMPath = LookupModuleOutput(MD.ID, ModuleOutputKind::ModuleFile);
145186
if (EagerLoadModules) {
146-
FD.CommandLine.push_back("-fmodule-file=" + PCMPath);
187+
FD.DriverCommandLine.push_back("-fmodule-file=" + PCMPath);
147188
} else {
148-
FD.CommandLine.push_back("-fmodule-map-file=" + MD.ClangModuleMapFile);
149-
FD.CommandLine.push_back("-fmodule-file=" + MD.ID.ModuleName + "=" +
150-
PCMPath);
189+
FD.DriverCommandLine.push_back("-fmodule-map-file=" +
190+
MD.ClangModuleMapFile);
191+
FD.DriverCommandLine.push_back("-fmodule-file=" + MD.ID.ModuleName +
192+
"=" + PCMPath);
151193
}
152194
}
153195
}

0 commit comments

Comments
 (0)