mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[NFC] Add Compilation::Result
In order to extract the module dependency graph from the compilation the driver just ran, define a separate semantic type to hold a result code and the graph itself.
This commit is contained in:
@@ -24,6 +24,7 @@
|
|||||||
#include "swift/Basic/OutputFileMap.h"
|
#include "swift/Basic/OutputFileMap.h"
|
||||||
#include "swift/Basic/Statistic.h"
|
#include "swift/Basic/Statistic.h"
|
||||||
#include "swift/Driver/Driver.h"
|
#include "swift/Driver/Driver.h"
|
||||||
|
#include "swift/Driver/FineGrainedDependencyDriverGraph.h"
|
||||||
#include "swift/Driver/Job.h"
|
#include "swift/Driver/Job.h"
|
||||||
#include "swift/Driver/Util.h"
|
#include "swift/Driver/Util.h"
|
||||||
#include "llvm/ADT/StringRef.h"
|
#include "llvm/ADT/StringRef.h"
|
||||||
@@ -78,6 +79,11 @@ using CommandSet = llvm::SmallPtrSet<const Job *, 16>;
|
|||||||
|
|
||||||
class Compilation {
|
class Compilation {
|
||||||
public:
|
public:
|
||||||
|
struct Result {
|
||||||
|
int exitCode;
|
||||||
|
fine_grained_dependencies::ModuleDepGraph depGraph;
|
||||||
|
};
|
||||||
|
|
||||||
class IncrementalSchemeComparator {
|
class IncrementalSchemeComparator {
|
||||||
const bool EnableIncrementalBuildWhenConstructed;
|
const bool EnableIncrementalBuildWhenConstructed;
|
||||||
const bool &EnableIncrementalBuild;
|
const bool &EnableIncrementalBuild;
|
||||||
@@ -490,7 +496,7 @@ public:
|
|||||||
///
|
///
|
||||||
/// \returns result code for the Compilation's Jobs; 0 indicates success and
|
/// \returns result code for the Compilation's Jobs; 0 indicates success and
|
||||||
/// -2 indicates that one of the Compilation's Jobs crashed during execution
|
/// -2 indicates that one of the Compilation's Jobs crashed during execution
|
||||||
int performJobs(std::unique_ptr<sys::TaskQueue> &&TQ);
|
Compilation::Result performJobs(std::unique_ptr<sys::TaskQueue> &&TQ);
|
||||||
|
|
||||||
/// Returns whether the callee is permitted to pass -emit-loaded-module-trace
|
/// Returns whether the callee is permitted to pass -emit-loaded-module-trace
|
||||||
/// to a frontend job.
|
/// to a frontend job.
|
||||||
@@ -540,7 +546,8 @@ private:
|
|||||||
///
|
///
|
||||||
/// \returns exit code of the first failed Job, or 0 on success. If a Job
|
/// \returns exit code of the first failed Job, or 0 on success. If a Job
|
||||||
/// crashes during execution, a negative value will be returned.
|
/// crashes during execution, a negative value will be returned.
|
||||||
int performJobsImpl(bool &abnormalExit, std::unique_ptr<sys::TaskQueue> &&TQ);
|
Compilation::Result performJobsImpl(bool &abnormalExit,
|
||||||
|
std::unique_ptr<sys::TaskQueue> &&TQ);
|
||||||
|
|
||||||
/// Performs a single Job by executing in place, if possible.
|
/// Performs a single Job by executing in place, if possible.
|
||||||
///
|
///
|
||||||
@@ -550,7 +557,7 @@ private:
|
|||||||
/// will no longer exist, or it will call exit() if the program was
|
/// will no longer exist, or it will call exit() if the program was
|
||||||
/// successfully executed. In the event of an error, this function will return
|
/// successfully executed. In the event of an error, this function will return
|
||||||
/// a negative value indicating a failure to execute.
|
/// a negative value indicating a failure to execute.
|
||||||
int performSingleCommand(const Job *Cmd);
|
Compilation::Result performSingleCommand(const Job *Cmd);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace driver
|
} // end namespace driver
|
||||||
|
|||||||
@@ -244,7 +244,7 @@ namespace driver {
|
|||||||
std::unique_ptr<TaskQueue> TQ;
|
std::unique_ptr<TaskQueue> TQ;
|
||||||
|
|
||||||
/// Cumulative result of PerformJobs(), accumulated from subprocesses.
|
/// Cumulative result of PerformJobs(), accumulated from subprocesses.
|
||||||
int Result = EXIT_SUCCESS;
|
int ResultCode = EXIT_SUCCESS;
|
||||||
|
|
||||||
/// True if any Job crashed.
|
/// True if any Job crashed.
|
||||||
bool AnyAbnormalExit = false;
|
bool AnyAbnormalExit = false;
|
||||||
@@ -719,8 +719,8 @@ namespace driver {
|
|||||||
// Store this task's ReturnCode as our Result if we haven't stored
|
// Store this task's ReturnCode as our Result if we haven't stored
|
||||||
// anything yet.
|
// anything yet.
|
||||||
|
|
||||||
if (Result == EXIT_SUCCESS)
|
if (ResultCode == EXIT_SUCCESS)
|
||||||
Result = ReturnCode;
|
ResultCode = ReturnCode;
|
||||||
|
|
||||||
if (!isa<CompileJobAction>(FinishedCmd->getSource()) ||
|
if (!isa<CompileJobAction>(FinishedCmd->getSource()) ||
|
||||||
ReturnCode != EXIT_FAILURE) {
|
ReturnCode != EXIT_FAILURE) {
|
||||||
@@ -825,7 +825,7 @@ namespace driver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Since the task signalled, unconditionally set result to -2.
|
// Since the task signalled, unconditionally set result to -2.
|
||||||
Result = -2;
|
ResultCode = -2;
|
||||||
AnyAbnormalExit = true;
|
AnyAbnormalExit = true;
|
||||||
|
|
||||||
return TaskFinishedResponse::StopExecution;
|
return TaskFinishedResponse::StopExecution;
|
||||||
@@ -1536,7 +1536,7 @@ namespace driver {
|
|||||||
_3, _4, _5, _6),
|
_3, _4, _5, _6),
|
||||||
std::bind(&PerformJobsState::taskSignalled, this, _1,
|
std::bind(&PerformJobsState::taskSignalled, this, _1,
|
||||||
_2, _3, _4, _5, _6, _7))) {
|
_2, _3, _4, _5, _6, _7))) {
|
||||||
if (Result == EXIT_SUCCESS) {
|
if (ResultCode == EXIT_SUCCESS) {
|
||||||
// FIXME: Error from task queue while Result == EXIT_SUCCESS most
|
// FIXME: Error from task queue while Result == EXIT_SUCCESS most
|
||||||
// likely means some fork/exec or posix_spawn failed; TaskQueue saw
|
// likely means some fork/exec or posix_spawn failed; TaskQueue saw
|
||||||
// "an error" at some stage before even calling us with a process
|
// "an error" at some stage before even calling us with a process
|
||||||
@@ -1546,7 +1546,7 @@ namespace driver {
|
|||||||
Comp.getDiags().diagnose(SourceLoc(),
|
Comp.getDiags().diagnose(SourceLoc(),
|
||||||
diag::error_unable_to_execute_command,
|
diag::error_unable_to_execute_command,
|
||||||
"<unknown>");
|
"<unknown>");
|
||||||
Result = -2;
|
ResultCode = -2;
|
||||||
AnyAbnormalExit = true;
|
AnyAbnormalExit = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1554,13 +1554,13 @@ namespace driver {
|
|||||||
|
|
||||||
// Returning without error from TaskQueue::execute should mean either an
|
// Returning without error from TaskQueue::execute should mean either an
|
||||||
// empty TaskQueue or a failed subprocess.
|
// empty TaskQueue or a failed subprocess.
|
||||||
assert(!(Result == 0 && TQ->hasRemainingTasks()));
|
assert(!(ResultCode == 0 && TQ->hasRemainingTasks()));
|
||||||
|
|
||||||
// Task-exit callbacks from TaskQueue::execute may have unblocked jobs,
|
// Task-exit callbacks from TaskQueue::execute may have unblocked jobs,
|
||||||
// which means there might be PendingExecution jobs to enqueue here. If
|
// which means there might be PendingExecution jobs to enqueue here. If
|
||||||
// there are, we need to continue trying to make progress on the
|
// there are, we need to continue trying to make progress on the
|
||||||
// TaskQueue before we start marking deferred jobs as skipped, below.
|
// TaskQueue before we start marking deferred jobs as skipped, below.
|
||||||
if (!PendingExecution.empty() && Result == 0) {
|
if (!PendingExecution.empty() && ResultCode == 0) {
|
||||||
formBatchJobsAndAddPendingJobsToTaskQueue();
|
formBatchJobsAndAddPendingJobsToTaskQueue();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1585,11 +1585,11 @@ namespace driver {
|
|||||||
|
|
||||||
// If we added jobs to the TaskQueue, and we are not in an error state,
|
// If we added jobs to the TaskQueue, and we are not in an error state,
|
||||||
// we want to give the TaskQueue another run.
|
// we want to give the TaskQueue another run.
|
||||||
} while (Result == 0 && TQ->hasRemainingTasks());
|
} while (ResultCode == 0 && TQ->hasRemainingTasks());
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkUnfinishedJobs() {
|
void checkUnfinishedJobs() {
|
||||||
if (Result == 0) {
|
if (ResultCode == 0) {
|
||||||
assert(BlockingCommands.empty() &&
|
assert(BlockingCommands.empty() &&
|
||||||
"some blocking commands never finished properly");
|
"some blocking commands never finished properly");
|
||||||
} else {
|
} else {
|
||||||
@@ -1693,10 +1693,12 @@ namespace driver {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
int getResult() {
|
Compilation::Result takeResult() && {
|
||||||
if (Result == 0)
|
if (ResultCode == 0)
|
||||||
Result = Comp.getDiags().hadAnyError();
|
ResultCode = Comp.getDiags().hadAnyError();
|
||||||
return Result;
|
const bool forRanges = Comp.getEnableSourceRangeDependencies();
|
||||||
|
return Compilation::Result{
|
||||||
|
ResultCode, std::move(*this).takeFineGrainedDepGraph(forRanges)};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hadAnyAbnormalExit() {
|
bool hadAnyAbnormalExit() {
|
||||||
@@ -1756,6 +1758,12 @@ namespace driver {
|
|||||||
getFineGrainedDepGraph(const bool forRanges) const {
|
getFineGrainedDepGraph(const bool forRanges) const {
|
||||||
return forRanges ? FineGrainedDepGraphForRanges : FineGrainedDepGraph;
|
return forRanges ? FineGrainedDepGraphForRanges : FineGrainedDepGraph;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fine_grained_dependencies::ModuleDepGraph &&
|
||||||
|
takeFineGrainedDepGraph(const bool forRanges) && {
|
||||||
|
return forRanges ? std::move(FineGrainedDepGraphForRanges)
|
||||||
|
: std::move(FineGrainedDepGraph);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
} // namespace driver
|
} // namespace driver
|
||||||
} // namespace swift
|
} // namespace swift
|
||||||
@@ -1936,8 +1944,9 @@ static bool writeFilelistIfNecessary(const Job *job, const ArgList &args,
|
|||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Compilation::performJobsImpl(bool &abnormalExit,
|
Compilation::Result
|
||||||
std::unique_ptr<TaskQueue> &&TQ) {
|
Compilation::performJobsImpl(bool &abnormalExit,
|
||||||
|
std::unique_ptr<TaskQueue> &&TQ) {
|
||||||
PerformJobsState State(*this, std::move(TQ));
|
PerformJobsState State(*this, std::move(TQ));
|
||||||
|
|
||||||
State.runJobs();
|
State.runJobs();
|
||||||
@@ -1946,20 +1955,25 @@ int Compilation::performJobsImpl(bool &abnormalExit,
|
|||||||
InputInfoMap InputInfo;
|
InputInfoMap InputInfo;
|
||||||
State.populateInputInfoMap(InputInfo);
|
State.populateInputInfoMap(InputInfo);
|
||||||
checkForOutOfDateInputs(Diags, InputInfo);
|
checkForOutOfDateInputs(Diags, InputInfo);
|
||||||
|
|
||||||
|
abnormalExit = State.hadAnyAbnormalExit();
|
||||||
|
auto result = std::move(State).takeResult();
|
||||||
writeCompilationRecord(CompilationRecordPath, ArgsHash, BuildStartTime,
|
writeCompilationRecord(CompilationRecordPath, ArgsHash, BuildStartTime,
|
||||||
InputInfo);
|
InputInfo);
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
abnormalExit = State.hadAnyAbnormalExit();
|
||||||
|
return std::move(State).takeResult();
|
||||||
}
|
}
|
||||||
abnormalExit = State.hadAnyAbnormalExit();
|
|
||||||
return State.getResult();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int Compilation::performSingleCommand(const Job *Cmd) {
|
Compilation::Result Compilation::performSingleCommand(const Job *Cmd) {
|
||||||
assert(Cmd->getInputs().empty() &&
|
assert(Cmd->getInputs().empty() &&
|
||||||
"This can only be used to run a single command with no inputs");
|
"This can only be used to run a single command with no inputs");
|
||||||
|
|
||||||
switch (Cmd->getCondition()) {
|
switch (Cmd->getCondition()) {
|
||||||
case Job::Condition::CheckDependencies:
|
case Job::Condition::CheckDependencies:
|
||||||
return 0;
|
return Compilation::Result{0, fine_grained_dependencies::ModuleDepGraph()};
|
||||||
case Job::Condition::RunWithoutCascading:
|
case Job::Condition::RunWithoutCascading:
|
||||||
case Job::Condition::Always:
|
case Job::Condition::Always:
|
||||||
case Job::Condition::NewlyAdded:
|
case Job::Condition::NewlyAdded:
|
||||||
@@ -1967,7 +1981,7 @@ int Compilation::performSingleCommand(const Job *Cmd) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!writeFilelistIfNecessary(Cmd, *TranslatedArgs.get(), Diags))
|
if (!writeFilelistIfNecessary(Cmd, *TranslatedArgs.get(), Diags))
|
||||||
return 1;
|
return Compilation::Result{1, fine_grained_dependencies::ModuleDepGraph()};
|
||||||
|
|
||||||
switch (Level) {
|
switch (Level) {
|
||||||
case OutputLevel::Normal:
|
case OutputLevel::Normal:
|
||||||
@@ -1975,7 +1989,7 @@ int Compilation::performSingleCommand(const Job *Cmd) {
|
|||||||
break;
|
break;
|
||||||
case OutputLevel::PrintJobs:
|
case OutputLevel::PrintJobs:
|
||||||
Cmd->printCommandLineAndEnvironment(llvm::outs());
|
Cmd->printCommandLineAndEnvironment(llvm::outs());
|
||||||
return 0;
|
return Compilation::Result{0, fine_grained_dependencies::ModuleDepGraph()};
|
||||||
case OutputLevel::Verbose:
|
case OutputLevel::Verbose:
|
||||||
Cmd->printCommandLine(llvm::errs());
|
Cmd->printCommandLine(llvm::errs());
|
||||||
break;
|
break;
|
||||||
@@ -1999,11 +2013,14 @@ int Compilation::performSingleCommand(const Job *Cmd) {
|
|||||||
"expected environment variable to be set successfully");
|
"expected environment variable to be set successfully");
|
||||||
// Bail out early in release builds.
|
// Bail out early in release builds.
|
||||||
if (envResult != 0) {
|
if (envResult != 0) {
|
||||||
return envResult;
|
return Compilation::Result{envResult,
|
||||||
|
fine_grained_dependencies::ModuleDepGraph()};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ExecuteInPlace(ExecPath, argv);
|
const auto returnCode = ExecuteInPlace(ExecPath, argv);
|
||||||
|
return Compilation::Result{returnCode,
|
||||||
|
fine_grained_dependencies::ModuleDepGraph()};
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool writeAllSourcesFile(DiagnosticEngine &diags, StringRef path,
|
static bool writeAllSourcesFile(DiagnosticEngine &diags, StringRef path,
|
||||||
@@ -2026,10 +2043,11 @@ static bool writeAllSourcesFile(DiagnosticEngine &diags, StringRef path,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Compilation::performJobs(std::unique_ptr<TaskQueue> &&TQ) {
|
Compilation::Result Compilation::performJobs(std::unique_ptr<TaskQueue> &&TQ) {
|
||||||
if (AllSourceFilesPath)
|
if (AllSourceFilesPath)
|
||||||
if (!writeAllSourcesFile(Diags, AllSourceFilesPath, getInputFiles()))
|
if (!writeAllSourcesFile(Diags, AllSourceFilesPath, getInputFiles()))
|
||||||
return EXIT_FAILURE;
|
return Compilation::Result{EXIT_FAILURE,
|
||||||
|
fine_grained_dependencies::ModuleDepGraph()};
|
||||||
|
|
||||||
// If we don't have to do any cleanup work, just exec the subprocess.
|
// If we don't have to do any cleanup work, just exec the subprocess.
|
||||||
if (Level < OutputLevel::Parseable &&
|
if (Level < OutputLevel::Parseable &&
|
||||||
@@ -2045,7 +2063,7 @@ int Compilation::performJobs(std::unique_ptr<TaskQueue> &&TQ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool abnormalExit;
|
bool abnormalExit;
|
||||||
int result = performJobsImpl(abnormalExit, std::move(TQ));
|
auto result = performJobsImpl(abnormalExit, std::move(TQ));
|
||||||
|
|
||||||
if (IncrementalComparator)
|
if (IncrementalComparator)
|
||||||
IncrementalComparator->outputComparison();
|
IncrementalComparator->outputComparison();
|
||||||
@@ -2057,7 +2075,7 @@ int Compilation::performJobs(std::unique_ptr<TaskQueue> &&TQ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Stats)
|
if (Stats)
|
||||||
Stats->noteCurrentProcessExitStatus(result);
|
Stats->noteCurrentProcessExitStatus(result.exitCode);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -248,7 +248,7 @@ static int run_driver(StringRef ExecName,
|
|||||||
std::unique_ptr<sys::TaskQueue> TQ = TheDriver.buildTaskQueue(*C);
|
std::unique_ptr<sys::TaskQueue> TQ = TheDriver.buildTaskQueue(*C);
|
||||||
if (!TQ)
|
if (!TQ)
|
||||||
return 1;
|
return 1;
|
||||||
return C->performJobs(std::move(TQ));
|
return C->performJobs(std::move(TQ)).exitCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user