[clang][DependencyScanning] Relocate CompilerInstanceWithContext to DependencyScanningWorker.cpp (#211407)
This PR relocates all `CompilerInstanceWithContext` code to `DependencyScanningWorker.cpp` and hides them as implementation details, since no public APIs should use `CompilerInstanceWithContext` directly. --- <sub>Stack created with <a href="https://github.com/github/gh-stack">GitHub Stacks CLI</a> • <a href="https://gh.io/stacks-feedback">Give Feedback 💬</a></sub>
This commit is contained in:
parent
5f4d725bca
commit
6109006676
4 changed files with 276 additions and 287 deletions
|
|
@ -28,10 +28,6 @@ namespace clang {
|
|||
|
||||
class DependencyOutputOptions;
|
||||
|
||||
namespace tooling {
|
||||
class CompilerInstanceWithContext;
|
||||
}
|
||||
|
||||
namespace dependencies {
|
||||
|
||||
class DependencyConsumer;
|
||||
|
|
@ -64,6 +60,18 @@ public:
|
|||
DiagnosticConsumer &DiagConsumer,
|
||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> OverlayFS = nullptr);
|
||||
|
||||
/// By-name scanning over a single cc1 command line. Builds a scanning session
|
||||
/// local to this call, then pulls module names from \p getNextName until it
|
||||
/// returns std::nullopt. Results flow to \p DepConsumer (per-name status via
|
||||
/// finishQuery); diagnostics flow to \p DiagConsumer.
|
||||
/// \returns false if session setup failed, true otherwise.
|
||||
bool computeDependenciesByName(
|
||||
StringRef CWD, ArrayRef<std::string> CC1CommandLine,
|
||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> OverlayFS,
|
||||
DiagnosticConsumer &DiagConsumer, DependencyActionController &Controller,
|
||||
llvm::function_ref<std::optional<std::string>()> getNextName,
|
||||
DependencyConsumer &DepConsumer);
|
||||
|
||||
/// Creates the effective VFS that will be used for the scan.
|
||||
///
|
||||
/// If provided, OverlayFS will be overlaid on top of the Worker's dependency
|
||||
|
|
@ -79,6 +87,15 @@ public:
|
|||
return TracingFS.get();
|
||||
}
|
||||
|
||||
// MaxNumOfByNameQueries is the upper limit of the number of names the by-name
|
||||
// scanning API (computeDependenciesByName) can drain per call. At the time of
|
||||
// this commit, the estimated number of total unique importable names is
|
||||
// around 3000 from Apple's SDKs. We usually import them in parallel, so it is
|
||||
// unlikely that all names are scanned by the same worker. Therefore the 64k
|
||||
// (20x our estimate) size is sufficient to hold the unique source locations
|
||||
// to report diagnostics per worker.
|
||||
static const int32_t MaxNumOfByNameQueries = 1 << 16;
|
||||
|
||||
private:
|
||||
/// The parent dependency scanning service.
|
||||
DependencyScanningService &Service;
|
||||
|
|
@ -89,7 +106,7 @@ private:
|
|||
/// The tracing VFS overlaid on top of the base VFS.
|
||||
IntrusiveRefCntPtr<llvm::vfs::TracingFileSystem> TracingFS;
|
||||
|
||||
friend tooling::CompilerInstanceWithContext;
|
||||
friend class CompilerInstanceWithContext;
|
||||
};
|
||||
} // end namespace dependencies
|
||||
} // end namespace clang
|
||||
|
|
|
|||
|
|
@ -124,8 +124,6 @@ public:
|
|||
|
||||
private:
|
||||
dependencies::DependencyScanningWorker Worker;
|
||||
|
||||
friend class CompilerInstanceWithContext;
|
||||
};
|
||||
|
||||
/// Run the dependency scanning worker for the given driver or frontend
|
||||
|
|
@ -146,79 +144,6 @@ bool computeDependencies(
|
|||
dependencies::DependencyActionController &Controller,
|
||||
DiagnosticConsumer &DiagConsumer,
|
||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> OverlayFS = nullptr);
|
||||
|
||||
class CompilerInstanceWithContext {
|
||||
// Context
|
||||
dependencies::DependencyScanningWorker &Worker;
|
||||
llvm::StringRef CWD;
|
||||
std::vector<std::string> CommandLine;
|
||||
|
||||
// Context - Diagnostics engine.
|
||||
DiagnosticConsumer *DiagConsumer = nullptr;
|
||||
std::unique_ptr<dependencies::DiagnosticsEngineWithDiagOpts>
|
||||
DiagEngineWithCmdAndOpts;
|
||||
|
||||
// Context - compiler invocation
|
||||
std::unique_ptr<CompilerInvocation> OriginalInvocation;
|
||||
|
||||
// Context - output options
|
||||
std::unique_ptr<DependencyOutputOptions> OutputOpts;
|
||||
|
||||
// Context - stable directory handling
|
||||
llvm::SmallVector<StringRef> StableDirs;
|
||||
dependencies::PrebuiltModulesAttrsMap PrebuiltModuleASTMap;
|
||||
|
||||
// Compiler Instance
|
||||
std::unique_ptr<CompilerInstance> CIPtr;
|
||||
|
||||
// Source location offset.
|
||||
int32_t SrcLocOffset = 0;
|
||||
|
||||
CompilerInstanceWithContext(dependencies::DependencyScanningWorker &Worker,
|
||||
StringRef CWD, ArrayRef<std::string> CMD)
|
||||
: Worker(Worker), CWD(CWD), CommandLine(CMD.begin(), CMD.end()) {}
|
||||
|
||||
bool initialize(dependencies::DependencyActionController &Controller,
|
||||
std::unique_ptr<dependencies::DiagnosticsEngineWithDiagOpts>
|
||||
DiagEngineWithDiagOpts,
|
||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> OverlayFS);
|
||||
|
||||
public:
|
||||
/// @brief Initialize the compiler instance from an already-lowered cc1
|
||||
/// commandline (driver-free).
|
||||
/// @param Worker The dependency scanning worker to initialize the compiler
|
||||
/// instance.
|
||||
/// @param CWD The current working directory.
|
||||
/// @param CC1CommandLine A cc1 command.
|
||||
/// @param DiagEngineWithDiagOpts The diagnostic engine used during scan.
|
||||
/// @param OverlayFS An overlay FS containing the input file, which may be
|
||||
/// from an in-memory buffer.
|
||||
/// @param Controller A dependency action controller to gather some results.
|
||||
static std::optional<CompilerInstanceWithContext>
|
||||
initializeFromCC1Commandline(
|
||||
dependencies::DependencyScanningWorker &Worker, StringRef CWD,
|
||||
ArrayRef<std::string> CC1CommandLine,
|
||||
std::unique_ptr<dependencies::DiagnosticsEngineWithDiagOpts>
|
||||
DiagEngineWithDiagOpts,
|
||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> OverlayFS,
|
||||
dependencies::DependencyActionController &Controller);
|
||||
|
||||
bool
|
||||
computeDependencies(StringRef ModuleName,
|
||||
dependencies::DependencyConsumer &Consumer,
|
||||
dependencies::DependencyActionController &Controller);
|
||||
|
||||
// MaxNumOfQueries is the upper limit of the number of names the by-name
|
||||
// scanning API (computeDependencies) can support after a
|
||||
// CompilerInstanceWithContext is initialized. At the time of this commit, the
|
||||
// estimated number of total unique importable names is around 3000 from
|
||||
// Apple's SDKs. We usually import them in parallel, so it is unlikely that
|
||||
// all names are all scanned by the same dependency scanning worker. Therefore
|
||||
// the 64k (20x bigger than our estimate) size is sufficient to hold the
|
||||
// unique source locations to report diagnostics per worker.
|
||||
static const int32_t MaxNumOfQueries = 1 << 16;
|
||||
};
|
||||
|
||||
} // end namespace tooling
|
||||
} // end namespace clang
|
||||
|
||||
|
|
|
|||
|
|
@ -9,8 +9,11 @@
|
|||
#include "clang/DependencyScanning/DependencyScanningWorker.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/DiagnosticFrontend.h"
|
||||
#include "clang/DependencyScanning/DependencyActionController.h"
|
||||
#include "clang/DependencyScanning/DependencyConsumer.h"
|
||||
#include "clang/DependencyScanning/DependencyScannerImpl.h"
|
||||
#include "clang/Frontend/FrontendActions.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Serialization/ObjectFilePCHContainerReader.h"
|
||||
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
||||
#include "llvm/ADT/ScopeExit.h"
|
||||
|
|
@ -19,6 +22,227 @@
|
|||
using namespace clang;
|
||||
using namespace dependencies;
|
||||
|
||||
namespace clang {
|
||||
namespace dependencies {
|
||||
class CompilerInstanceWithContext {
|
||||
// Context
|
||||
DependencyScanningWorker &Worker;
|
||||
llvm::StringRef CWD;
|
||||
std::vector<std::string> CommandLine;
|
||||
|
||||
// Context - Diagnostics engine.
|
||||
DiagnosticConsumer *DiagConsumer = nullptr;
|
||||
std::unique_ptr<DiagnosticsEngineWithDiagOpts> DiagEngineWithCmdAndOpts;
|
||||
|
||||
// Context - compiler invocation
|
||||
std::unique_ptr<CompilerInvocation> OriginalInvocation;
|
||||
|
||||
// Context - output options
|
||||
std::unique_ptr<DependencyOutputOptions> OutputOpts;
|
||||
|
||||
// Context - stable directory handling
|
||||
llvm::SmallVector<StringRef> StableDirs;
|
||||
PrebuiltModulesAttrsMap PrebuiltModuleASTMap;
|
||||
|
||||
// Compiler Instance
|
||||
std::unique_ptr<CompilerInstance> CIPtr;
|
||||
|
||||
// Source location offset.
|
||||
int32_t SrcLocOffset = 0;
|
||||
|
||||
CompilerInstanceWithContext(DependencyScanningWorker &Worker, StringRef CWD,
|
||||
ArrayRef<std::string> CMD)
|
||||
: Worker(Worker), CWD(CWD), CommandLine(CMD.begin(), CMD.end()) {}
|
||||
|
||||
bool initialize(
|
||||
DependencyActionController &Controller,
|
||||
std::unique_ptr<DiagnosticsEngineWithDiagOpts> DiagEngineWithDiagOpts,
|
||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> OverlayFS) {
|
||||
{
|
||||
auto LogLine = Worker.Service.getLogger().log();
|
||||
LogLine.logArray("init_compiler_instance_with_context:", " ",
|
||||
CommandLine);
|
||||
}
|
||||
assert(DiagEngineWithDiagOpts && "Valid diagnostics engine required!");
|
||||
DiagEngineWithCmdAndOpts = std::move(DiagEngineWithDiagOpts);
|
||||
DiagConsumer = DiagEngineWithCmdAndOpts->DiagEngine->getClient();
|
||||
|
||||
assert(OverlayFS && "OverlayFS required!");
|
||||
auto FS = Worker.makeEffectiveVFS(CWD, std::move(OverlayFS));
|
||||
|
||||
OriginalInvocation = createCompilerInvocation(
|
||||
CommandLine, *DiagEngineWithCmdAndOpts->DiagEngine);
|
||||
if (!OriginalInvocation) {
|
||||
DiagEngineWithCmdAndOpts->DiagEngine->Report(
|
||||
diag::err_fe_expected_compiler_job)
|
||||
<< llvm::join(CommandLine, " ");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (any(Worker.Service.getOpts().OptimizeArgs &
|
||||
ScanningOptimizations::Macros))
|
||||
canonicalizeDefines(OriginalInvocation->getPreprocessorOpts());
|
||||
|
||||
// Create the CompilerInstance.
|
||||
std::shared_ptr<ModuleCache> ModCache = makeInProcessModuleCache(
|
||||
Worker.Service.getModuleCacheEntries(), Worker.Service.getLogger());
|
||||
CIPtr = std::make_unique<CompilerInstance>(
|
||||
createScanCompilerInvocation(*OriginalInvocation, Worker.Service,
|
||||
Controller),
|
||||
Worker.PCHContainerOps, std::move(ModCache));
|
||||
auto &CI = *CIPtr;
|
||||
|
||||
initializeScanCompilerInstance(
|
||||
CI, std::move(FS), DiagEngineWithCmdAndOpts->DiagEngine->getClient(),
|
||||
Worker.Service, Worker.DepFS);
|
||||
|
||||
StableDirs = getInitialStableDirs(CI);
|
||||
auto MaybePrebuiltModulesASTMap =
|
||||
computePrebuiltModulesASTMap(CI, StableDirs);
|
||||
if (!MaybePrebuiltModulesASTMap)
|
||||
return false;
|
||||
|
||||
PrebuiltModuleASTMap = std::move(*MaybePrebuiltModulesASTMap);
|
||||
OutputOpts = createDependencyOutputOptions(*OriginalInvocation);
|
||||
|
||||
// We do not create the target in initializeScanCompilerInstance because
|
||||
// setting it here is unique for by-name lookups. We create the target only
|
||||
// once here, and the information is reused for all computeDependencies
|
||||
// calls. We do not need to call createTarget explicitly if we go through
|
||||
// CompilerInstance::ExecuteAction to perform scanning.
|
||||
return CI.createTarget();
|
||||
}
|
||||
|
||||
public:
|
||||
static std::optional<CompilerInstanceWithContext>
|
||||
initializeFromCC1Commandline(
|
||||
DependencyScanningWorker &Worker, StringRef CWD,
|
||||
ArrayRef<std::string> CC1CommandLine,
|
||||
std::unique_ptr<DiagnosticsEngineWithDiagOpts> DiagEngineWithDiagOpts,
|
||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> OverlayFS,
|
||||
DependencyActionController &Controller) {
|
||||
CompilerInstanceWithContext CIWC(Worker, CWD, CC1CommandLine);
|
||||
if (!CIWC.initialize(Controller, std::move(DiagEngineWithDiagOpts),
|
||||
std::move(OverlayFS)))
|
||||
return std::nullopt;
|
||||
return std::move(CIWC);
|
||||
}
|
||||
|
||||
bool computeDependencies(StringRef ModuleName, DependencyConsumer &Consumer,
|
||||
DependencyActionController &Controller) {
|
||||
Worker.Service.getLogger().log() << "start scan_by_name: " << ModuleName;
|
||||
llvm::scope_exit ExitLogging([&] {
|
||||
Worker.Service.getLogger().log() << "finish scan_by_name: " << ModuleName;
|
||||
});
|
||||
if (SrcLocOffset >= DependencyScanningWorker::MaxNumOfByNameQueries)
|
||||
llvm::report_fatal_error("exceeded maximum by-name scans for worker");
|
||||
|
||||
assert(CIPtr && "CIPtr must be initialized before calling this method");
|
||||
auto &CI = *CIPtr;
|
||||
|
||||
// We need to reset the diagnostics, so that the diagnostics issued
|
||||
// during a previous computeDependencies call do not affect the current
|
||||
// call. If we do not reset, we may inherit fatal errors from a previous
|
||||
// call.
|
||||
CI.getDiagnostics().Reset();
|
||||
|
||||
// We create this cleanup object because computeDependencies may exit
|
||||
// early with errors.
|
||||
llvm::scope_exit CleanUp([&]() {
|
||||
CI.clearDependencyCollectors();
|
||||
// The preprocessor may not be created at the entry of this method,
|
||||
// but it must have been created when this method returns, whether
|
||||
// there are errors during scanning or not.
|
||||
CI.getPreprocessor().removePPCallbacks();
|
||||
});
|
||||
|
||||
auto MDC = initializeScanInstanceDependencyCollector(
|
||||
CI, std::make_unique<DependencyOutputOptions>(*OutputOpts),
|
||||
Worker.Service,
|
||||
/* The MDC's constructor makes a copy of the OriginalInvocation, so
|
||||
we can pass it in without worrying that it might be changed across
|
||||
invocations of computeDependencies. */
|
||||
*OriginalInvocation, Controller, PrebuiltModuleASTMap, StableDirs);
|
||||
|
||||
CompilerInvocation ModuleInvocation(*OriginalInvocation);
|
||||
if (!Controller.initialize(CI, ModuleInvocation))
|
||||
return false;
|
||||
|
||||
if (!SrcLocOffset) {
|
||||
// When SrcLocOffset is zero, we are at the beginning of the fake source
|
||||
// file. In this case, we call BeginSourceFile to initialize.
|
||||
std::unique_ptr<FrontendAction> Action =
|
||||
std::make_unique<PreprocessOnlyAction>();
|
||||
auto *InputFile = CI.getFrontendOpts().Inputs.begin();
|
||||
bool ActionBeginSucceeded = Action->BeginSourceFile(CI, *InputFile);
|
||||
assert(ActionBeginSucceeded && "Action BeginSourceFile must succeed");
|
||||
(void)ActionBeginSucceeded;
|
||||
}
|
||||
|
||||
Preprocessor &PP = CI.getPreprocessor();
|
||||
SourceManager &SM = PP.getSourceManager();
|
||||
FileID MainFileID = SM.getMainFileID();
|
||||
SourceLocation FileStart = SM.getLocForStartOfFile(MainFileID);
|
||||
SourceLocation IDLocation = FileStart.getLocWithOffset(SrcLocOffset);
|
||||
PPCallbacks *CB = nullptr;
|
||||
if (!SrcLocOffset) {
|
||||
// We need to call EnterSourceFile when SrcLocOffset is zero to initialize
|
||||
// the preprocessor.
|
||||
bool PPFailed = PP.EnterSourceFile(MainFileID, nullptr, SourceLocation());
|
||||
assert(!PPFailed && "Preprocess must be able to enter the main file.");
|
||||
(void)PPFailed;
|
||||
CB = MDC->getPPCallbacks();
|
||||
} else {
|
||||
// When SrcLocOffset is non-zero, the preprocessor has already been
|
||||
// initialized through a previous call of computeDependencies. We want to
|
||||
// preserve the PP's state, hence we do not call EnterSourceFile again.
|
||||
MDC->attachToPreprocessor(PP);
|
||||
CB = MDC->getPPCallbacks();
|
||||
|
||||
FileID PrevFID;
|
||||
SrcMgr::CharacteristicKind FileType =
|
||||
SM.getFileCharacteristic(IDLocation);
|
||||
CB->LexedFileChanged(MainFileID,
|
||||
PPChainedCallbacks::LexedFileChangeReason::EnterFile,
|
||||
FileType, PrevFID, IDLocation);
|
||||
}
|
||||
|
||||
// FIXME: Scan modules asynchronously here as well.
|
||||
|
||||
SrcLocOffset++;
|
||||
SmallVector<IdentifierLoc, 2> Path;
|
||||
IdentifierInfo *ModuleID = PP.getIdentifierInfo(ModuleName);
|
||||
Path.emplace_back(IDLocation, ModuleID);
|
||||
auto ModResult = CI.loadModule(IDLocation, Path, Module::Hidden, false);
|
||||
|
||||
assert(CB && "Must have PPCallbacks after module loading");
|
||||
CB->moduleImport(SourceLocation(), Path, ModResult);
|
||||
|
||||
if (!ModResult)
|
||||
return false;
|
||||
|
||||
if (CI.getDiagnostics().hasErrorOccurred())
|
||||
return false;
|
||||
|
||||
MDC->run(Consumer);
|
||||
MDC->applyDiscoveredDependencies(ModuleInvocation);
|
||||
|
||||
bool Success = ModuleInvocation.withCowRef<bool>(
|
||||
[&](CowCompilerInvocation &CowModuleInvocation) {
|
||||
return Controller.finalize(CI, CowModuleInvocation);
|
||||
});
|
||||
if (!Success)
|
||||
return false;
|
||||
|
||||
Consumer.handleBuildCommand(
|
||||
{CommandLine[0], ModuleInvocation.getCC1CommandLine()});
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
} // namespace dependencies
|
||||
} // namespace clang
|
||||
|
||||
DependencyScanningWorker::DependencyScanningWorker(
|
||||
DependencyScanningService &Service)
|
||||
: Service(Service) {
|
||||
|
|
@ -108,3 +332,29 @@ bool DependencyScanningWorker::computeDependencies(
|
|||
|
||||
return Success && Action.hasScanned();
|
||||
}
|
||||
|
||||
bool DependencyScanningWorker::computeDependenciesByName(
|
||||
StringRef CWD, ArrayRef<std::string> CC1CommandLine,
|
||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> OverlayFS,
|
||||
DiagnosticConsumer &DiagConsumer, DependencyActionController &Controller,
|
||||
llvm::function_ref<std::optional<std::string>()> getNextName,
|
||||
DependencyConsumer &DepConsumer) {
|
||||
auto FS = makeEffectiveVFS(CWD, OverlayFS);
|
||||
auto DiagEngine = std::make_unique<DiagnosticsEngineWithDiagOpts>(
|
||||
CC1CommandLine, FS, DiagConsumer);
|
||||
std::optional<CompilerInstanceWithContext> CIWC =
|
||||
CompilerInstanceWithContext::initializeFromCC1Commandline(
|
||||
*this, CWD, CC1CommandLine, std::move(DiagEngine),
|
||||
std::move(OverlayFS), Controller);
|
||||
if (!CIWC)
|
||||
return false;
|
||||
|
||||
bool AllScansSucceeded = true;
|
||||
while (std::optional<std::string> NextName = getNextName()) {
|
||||
bool Success =
|
||||
CIWC->computeDependencies(*NextName, DepConsumer, Controller);
|
||||
DepConsumer.finishQuery(*NextName, Success);
|
||||
AllScansSucceeded = AllScansSucceeded && Success;
|
||||
}
|
||||
return AllScansSucceeded;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,10 +13,7 @@
|
|||
#include "clang/Driver/Compilation.h"
|
||||
#include "clang/Driver/Driver.h"
|
||||
#include "clang/Driver/Tool.h"
|
||||
#include "clang/Frontend/FrontendActions.h"
|
||||
#include "clang/Frontend/Utils.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "llvm/ADT/ScopeExit.h"
|
||||
#include "llvm/ADT/SmallVectorExtras.h"
|
||||
#include "llvm/ADT/iterator.h"
|
||||
#include "llvm/TargetParser/Host.h"
|
||||
|
|
@ -280,7 +277,7 @@ initVFSForByNameScanning(ArrayRef<std::string> CommandLine) {
|
|||
// locations for the diagnostics. Therefore, sharing this global buffer across
|
||||
// threads is ok.
|
||||
static const std::string FakeInput(
|
||||
CompilerInstanceWithContext::MaxNumOfQueries, ' ');
|
||||
DependencyScanningWorker::MaxNumOfByNameQueries, ' ');
|
||||
|
||||
StringRef InputPath =
|
||||
llvm::sys::path::is_style_windows(llvm::sys::path::Style::native)
|
||||
|
|
@ -367,207 +364,7 @@ bool DependencyScanningTool::getByNameDependencies(
|
|||
CC1CommandLine.assign(MaybeFirstCC1->begin(), MaybeFirstCC1->end());
|
||||
}
|
||||
|
||||
// Build one scanning session (a CIWC reused across all input names) and pull
|
||||
// names until getNextName is exhausted.
|
||||
auto DiagEngineWithOpts = std::make_unique<DiagnosticsEngineWithDiagOpts>(
|
||||
CC1CommandLine, FS, DiagConsumer);
|
||||
std::optional<CompilerInstanceWithContext> CIWC =
|
||||
CompilerInstanceWithContext::initializeFromCC1Commandline(
|
||||
Worker, CWD, CC1CommandLine, std::move(DiagEngineWithOpts),
|
||||
std::move(OverlayFS), Controller);
|
||||
if (!CIWC)
|
||||
return false;
|
||||
|
||||
bool AllScansSucceeded = true;
|
||||
while (std::optional<std::string> NextName = getNextName()) {
|
||||
bool Success =
|
||||
CIWC->computeDependencies(*NextName, DepConsumer, Controller);
|
||||
DepConsumer.finishQuery(*NextName, Success);
|
||||
AllScansSucceeded = AllScansSucceeded && Success;
|
||||
}
|
||||
return AllScansSucceeded;
|
||||
}
|
||||
|
||||
std::optional<CompilerInstanceWithContext>
|
||||
CompilerInstanceWithContext::initializeFromCC1Commandline(
|
||||
DependencyScanningWorker &Worker, StringRef CWD,
|
||||
ArrayRef<std::string> CC1CommandLine,
|
||||
std::unique_ptr<dependencies::DiagnosticsEngineWithDiagOpts>
|
||||
DiagEngineWithDiagOpts,
|
||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> OverlayFS,
|
||||
DependencyActionController &Controller) {
|
||||
CompilerInstanceWithContext CIWC(Worker, CWD, CC1CommandLine);
|
||||
if (!CIWC.initialize(Controller, std::move(DiagEngineWithDiagOpts),
|
||||
std::move(OverlayFS)))
|
||||
return std::nullopt;
|
||||
return std::move(CIWC);
|
||||
}
|
||||
|
||||
bool CompilerInstanceWithContext::initialize(
|
||||
DependencyActionController &Controller,
|
||||
std::unique_ptr<DiagnosticsEngineWithDiagOpts> DiagEngineWithDiagOpts,
|
||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> OverlayFS) {
|
||||
{
|
||||
auto LogLine = Worker.Service.getLogger().log();
|
||||
LogLine.logArray("init_compiler_instance_with_context:", " ", CommandLine);
|
||||
}
|
||||
assert(DiagEngineWithDiagOpts && "Valid diagnostics engine required!");
|
||||
DiagEngineWithCmdAndOpts = std::move(DiagEngineWithDiagOpts);
|
||||
DiagConsumer = DiagEngineWithCmdAndOpts->DiagEngine->getClient();
|
||||
|
||||
assert(OverlayFS && "OverlayFS required!");
|
||||
auto FS = Worker.makeEffectiveVFS(CWD, std::move(OverlayFS));
|
||||
|
||||
OriginalInvocation = createCompilerInvocation(
|
||||
CommandLine, *DiagEngineWithCmdAndOpts->DiagEngine);
|
||||
if (!OriginalInvocation) {
|
||||
DiagEngineWithCmdAndOpts->DiagEngine->Report(
|
||||
diag::err_fe_expected_compiler_job)
|
||||
<< llvm::join(CommandLine, " ");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (any(Worker.Service.getOpts().OptimizeArgs &
|
||||
ScanningOptimizations::Macros))
|
||||
canonicalizeDefines(OriginalInvocation->getPreprocessorOpts());
|
||||
|
||||
// Create the CompilerInstance.
|
||||
std::shared_ptr<ModuleCache> ModCache = makeInProcessModuleCache(
|
||||
Worker.Service.getModuleCacheEntries(), Worker.Service.getLogger());
|
||||
CIPtr = std::make_unique<CompilerInstance>(
|
||||
createScanCompilerInvocation(*OriginalInvocation, Worker.Service,
|
||||
Controller),
|
||||
Worker.PCHContainerOps, std::move(ModCache));
|
||||
auto &CI = *CIPtr;
|
||||
|
||||
initializeScanCompilerInstance(
|
||||
CI, std::move(FS), DiagEngineWithCmdAndOpts->DiagEngine->getClient(),
|
||||
Worker.Service, Worker.DepFS);
|
||||
|
||||
StableDirs = getInitialStableDirs(CI);
|
||||
auto MaybePrebuiltModulesASTMap =
|
||||
computePrebuiltModulesASTMap(CI, StableDirs);
|
||||
if (!MaybePrebuiltModulesASTMap)
|
||||
return false;
|
||||
|
||||
PrebuiltModuleASTMap = std::move(*MaybePrebuiltModulesASTMap);
|
||||
OutputOpts = createDependencyOutputOptions(*OriginalInvocation);
|
||||
|
||||
// We do not create the target in initializeScanCompilerInstance because
|
||||
// setting it here is unique for by-name lookups. We create the target only
|
||||
// once here, and the information is reused for all computeDependencies calls.
|
||||
// We do not need to call createTarget explicitly if we go through
|
||||
// CompilerInstance::ExecuteAction to perform scanning.
|
||||
return CI.createTarget();
|
||||
}
|
||||
|
||||
bool CompilerInstanceWithContext::computeDependencies(
|
||||
StringRef ModuleName, DependencyConsumer &Consumer,
|
||||
DependencyActionController &Controller) {
|
||||
Worker.Service.getLogger().log() << "start scan_by_name: " << ModuleName;
|
||||
llvm::scope_exit ExitLogging([&] {
|
||||
Worker.Service.getLogger().log() << "finish scan_by_name: " << ModuleName;
|
||||
});
|
||||
if (SrcLocOffset >= MaxNumOfQueries)
|
||||
llvm::report_fatal_error("exceeded maximum by-name scans for worker");
|
||||
|
||||
assert(CIPtr && "CIPtr must be initialized before calling this method");
|
||||
auto &CI = *CIPtr;
|
||||
|
||||
// We need to reset the diagnostics, so that the diagnostics issued
|
||||
// during a previous computeDependencies call do not affect the current call.
|
||||
// If we do not reset, we may inherit fatal errors from a previous call.
|
||||
CI.getDiagnostics().Reset();
|
||||
|
||||
// We create this cleanup object because computeDependencies may exit
|
||||
// early with errors.
|
||||
llvm::scope_exit CleanUp([&]() {
|
||||
CI.clearDependencyCollectors();
|
||||
// The preprocessor may not be created at the entry of this method,
|
||||
// but it must have been created when this method returns, whether
|
||||
// there are errors during scanning or not.
|
||||
CI.getPreprocessor().removePPCallbacks();
|
||||
});
|
||||
|
||||
auto MDC = initializeScanInstanceDependencyCollector(
|
||||
CI, std::make_unique<DependencyOutputOptions>(*OutputOpts),
|
||||
Worker.Service,
|
||||
/* The MDC's constructor makes a copy of the OriginalInvocation, so
|
||||
we can pass it in without worrying that it might be changed across
|
||||
invocations of computeDependencies. */
|
||||
*OriginalInvocation, Controller, PrebuiltModuleASTMap, StableDirs);
|
||||
|
||||
CompilerInvocation ModuleInvocation(*OriginalInvocation);
|
||||
if (!Controller.initialize(CI, ModuleInvocation))
|
||||
return false;
|
||||
|
||||
if (!SrcLocOffset) {
|
||||
// When SrcLocOffset is zero, we are at the beginning of the fake source
|
||||
// file. In this case, we call BeginSourceFile to initialize.
|
||||
std::unique_ptr<FrontendAction> Action =
|
||||
std::make_unique<PreprocessOnlyAction>();
|
||||
auto *InputFile = CI.getFrontendOpts().Inputs.begin();
|
||||
bool ActionBeginSucceeded = Action->BeginSourceFile(CI, *InputFile);
|
||||
assert(ActionBeginSucceeded && "Action BeginSourceFile must succeed");
|
||||
(void)ActionBeginSucceeded;
|
||||
}
|
||||
|
||||
Preprocessor &PP = CI.getPreprocessor();
|
||||
SourceManager &SM = PP.getSourceManager();
|
||||
FileID MainFileID = SM.getMainFileID();
|
||||
SourceLocation FileStart = SM.getLocForStartOfFile(MainFileID);
|
||||
SourceLocation IDLocation = FileStart.getLocWithOffset(SrcLocOffset);
|
||||
PPCallbacks *CB = nullptr;
|
||||
if (!SrcLocOffset) {
|
||||
// We need to call EnterSourceFile when SrcLocOffset is zero to initialize
|
||||
// the preprocessor.
|
||||
bool PPFailed = PP.EnterSourceFile(MainFileID, nullptr, SourceLocation());
|
||||
assert(!PPFailed && "Preprocess must be able to enter the main file.");
|
||||
(void)PPFailed;
|
||||
CB = MDC->getPPCallbacks();
|
||||
} else {
|
||||
// When SrcLocOffset is non-zero, the preprocessor has already been
|
||||
// initialized through a previous call of computeDependencies. We want to
|
||||
// preserve the PP's state, hence we do not call EnterSourceFile again.
|
||||
MDC->attachToPreprocessor(PP);
|
||||
CB = MDC->getPPCallbacks();
|
||||
|
||||
FileID PrevFID;
|
||||
SrcMgr::CharacteristicKind FileType = SM.getFileCharacteristic(IDLocation);
|
||||
CB->LexedFileChanged(MainFileID,
|
||||
PPChainedCallbacks::LexedFileChangeReason::EnterFile,
|
||||
FileType, PrevFID, IDLocation);
|
||||
}
|
||||
|
||||
// FIXME: Scan modules asynchronously here as well.
|
||||
|
||||
SrcLocOffset++;
|
||||
SmallVector<IdentifierLoc, 2> Path;
|
||||
IdentifierInfo *ModuleID = PP.getIdentifierInfo(ModuleName);
|
||||
Path.emplace_back(IDLocation, ModuleID);
|
||||
auto ModResult = CI.loadModule(IDLocation, Path, Module::Hidden, false);
|
||||
|
||||
assert(CB && "Must have PPCallbacks after module loading");
|
||||
CB->moduleImport(SourceLocation(), Path, ModResult);
|
||||
|
||||
if (!ModResult)
|
||||
return false;
|
||||
|
||||
if (CI.getDiagnostics().hasErrorOccurred())
|
||||
return false;
|
||||
|
||||
MDC->run(Consumer);
|
||||
MDC->applyDiscoveredDependencies(ModuleInvocation);
|
||||
|
||||
bool Success = ModuleInvocation.withCowRef<bool>(
|
||||
[&](CowCompilerInvocation &CowModuleInvocation) {
|
||||
return Controller.finalize(CI, CowModuleInvocation);
|
||||
});
|
||||
if (!Success)
|
||||
return false;
|
||||
|
||||
Consumer.handleBuildCommand(
|
||||
{CommandLine[0], ModuleInvocation.getCC1CommandLine()});
|
||||
|
||||
return true;
|
||||
return Worker.computeDependenciesByName(CWD, CC1CommandLine,
|
||||
std::move(OverlayFS), DiagConsumer,
|
||||
Controller, getNextName, DepConsumer);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue