Remove incremental builds from the Legacy driver

The C++-based driver is deprecated and this will help reduce the code surface that requires maintenance as the legacy driver is fully sunset.
This commit is contained in:
Artem Chikin
2023-03-27 15:02:55 -07:00
parent 47803aad3b
commit 73b01dccfc
401 changed files with 40 additions and 14016 deletions

View File

@@ -188,6 +188,9 @@ WARNING(warn_drv_darwin_sdk_invalid_settings, none,
WARNING(warning_unsupported_driver_option,none,
"option '%0' is only supported in swift-driver", (StringRef))
WARNING(new_driver_not_found,none,
"using (deprecated) legacy driver, Swift installation does not contain swift-driver at: '%0'", (StringRef))
WARNING(old_driver_deprecated,none,
"legacy driver is now deprecated; consider avoiding specifying '%0'", (StringRef))
#define UNDEFINE_DIAGNOSTIC_MACROS

View File

@@ -128,78 +128,16 @@ public:
}
};
class IncrementalJobAction : public JobAction {
public:
struct InputInfo {
/// The status of an input known to the driver. These are used to affect
/// the scheduling decisions made during an incremental build.
///
/// \Note The order of cases matters. They are ordered from least to
/// greatest impact on the incremental build schedule.
enum class Status {
/// The input to this job is up to date.
UpToDate,
/// The input to this job has changed in a way that requires this job to
/// be rerun, but not in such a way that it requires a cascading rebuild.
NeedsNonCascadingBuild,
/// The input to this job has changed in a way that requires this job to
/// be rerun, and in such a way that all jobs dependent upon this one
/// must be scheduled as well.
NeedsCascadingBuild,
/// The input to this job was not known to the driver when it was last
/// run.
NewlyAdded
};
public:
Status status = Status::UpToDate;
llvm::sys::TimePoint<> previousModTime;
InputInfo() = default;
InputInfo(Status stat, llvm::sys::TimePoint<> time)
: status(stat), previousModTime(time) {}
static InputInfo makeNewlyAdded() {
return {Status::NewlyAdded, llvm::sys::TimePoint<>::max()};
}
static InputInfo makeNeedsCascadingRebuild() {
return {Status::NeedsCascadingBuild, llvm::sys::TimePoint<>::min()};
}
};
private:
virtual void anchor() override;
InputInfo inputInfo;
public:
IncrementalJobAction(Kind Kind, ArrayRef<const Action *> Inputs,
file_types::ID Type, InputInfo info)
: JobAction(Kind, Inputs, Type), inputInfo(info) {}
public:
InputInfo getInputInfo() const {
return inputInfo;
}
public:
static bool classof(const Action *A) {
return A->getKind() == Action::Kind::CompileJob ||
A->getKind() == Action::Kind::MergeModuleJob;
}
};
class CompileJobAction : public IncrementalJobAction {
class CompileJobAction : public JobAction {
private:
virtual void anchor() override;
public:
CompileJobAction(file_types::ID OutputType)
: IncrementalJobAction(Action::Kind::CompileJob, llvm::None, OutputType,
{}) {}
CompileJobAction(Action *Input, file_types::ID OutputType, InputInfo info)
: IncrementalJobAction(Action::Kind::CompileJob, Input, OutputType,
info) {}
: JobAction(Action::Kind::CompileJob, llvm::None, OutputType) {}
CompileJobAction(Action *Input, file_types::ID OutputType)
: JobAction(Action::Kind::CompileJob, Input, OutputType) {}
static bool classof(const Action *A) {
return A->getKind() == Action::Kind::CompileJob;
@@ -283,12 +221,12 @@ public:
}
};
class MergeModuleJobAction : public IncrementalJobAction {
class MergeModuleJobAction : public JobAction {
virtual void anchor() override;
public:
MergeModuleJobAction(ArrayRef<const Action *> Inputs, InputInfo input)
: IncrementalJobAction(Action::Kind::MergeModuleJob, Inputs,
file_types::TY_SwiftModuleFile, input) {}
MergeModuleJobAction(ArrayRef<const Action *> Inputs)
: JobAction(Action::Kind::MergeModuleJob, Inputs,
file_types::TY_SwiftModuleFile) {}
static bool classof(const Action *A) {
return A->getKind() == Action::Kind::MergeModuleJob;

View File

@@ -24,7 +24,6 @@
#include "swift/Basic/OutputFileMap.h"
#include "swift/Basic/Statistic.h"
#include "swift/Driver/Driver.h"
#include "swift/Driver/FineGrainedDependencyDriverGraph.h"
#include "swift/Driver/Job.h"
#include "swift/Driver/Util.h"
#include "llvm/ADT/StringRef.h"
@@ -84,15 +83,9 @@ public:
bool hadAbnormalExit;
/// The exit code of this driver process.
int exitCode;
/// The dependency graph built up during the compilation of this module.
///
/// This data is used for cross-module module dependencies.
fine_grained_dependencies::ModuleDepGraph depGraph;
Result(bool hadAbnormalExit, int exitCode,
fine_grained_dependencies::ModuleDepGraph depGraph)
: hadAbnormalExit(hadAbnormalExit), exitCode(exitCode),
depGraph(std::move(depGraph)) {}
Result(bool hadAbnormalExit, int exitCode)
: hadAbnormalExit(hadAbnormalExit), exitCode(exitCode) {}
Result(const Result &) = delete;
Result &operator=(const Result &) = delete;
@@ -102,8 +95,7 @@ public:
/// Construct a \c Compilation::Result from just an exit code.
static Result code(int code) {
return Compilation::Result{false, code,
fine_grained_dependencies::ModuleDepGraph()};
return Compilation::Result{false, code};
}
};
@@ -171,33 +163,10 @@ private:
/// These apply whether the compilation succeeds or fails. If the
llvm::StringMap<PreserveOnSignal> TempFilePaths;
/// Write information about this compilation to this file.
///
/// This is used for incremental builds.
std::string CompilationRecordPath;
/// A hash representing all the arguments that could trigger a full rebuild.
std::string ArgsHash;
/// When the build was started.
///
/// This should be as close as possible to when the driver was invoked, since
/// it's used as a lower bound.
llvm::sys::TimePoint<> BuildStartTime;
/// The time of the last build.
///
/// If unknown, this will be some time in the past.
llvm::sys::TimePoint<> LastBuildTime = llvm::sys::TimePoint<>::min();
/// Indicates whether this Compilation should continue execution of subtasks
/// even if they returned an error status.
bool ContinueBuildingAfterErrors = false;
/// Indicates whether tasks should only be executed if their output is out
/// of date.
bool EnableIncrementalBuild;
/// Indicates whether groups of parallel frontend jobs should be merged
/// together and run in composite "batch jobs" when possible, to reduce
/// redundant work.
@@ -256,17 +225,6 @@ public:
/// -disable-only-one-dependency-file on the command line.
const bool OnlyOneDependencyFile;
private:
/// Helpful for debugging, but slows down the driver. So, only turn on when
/// needed.
const bool VerifyFineGrainedDependencyGraphAfterEveryImport;
/// Helpful for debugging, but slows down the driver. So, only turn on when
/// needed.
const bool EmitFineGrainedDependencyDotFileAfterEveryImport;
/// (experimental) Enable cross-module incremental build scheduling.
const bool EnableCrossModuleIncrementalBuild;
private:
template <typename T>
static T *unwrap(const std::unique_ptr<T> &p) {
@@ -285,11 +243,7 @@ public:
std::unique_ptr<llvm::opt::InputArgList> InputArgs,
std::unique_ptr<llvm::opt::DerivedArgList> TranslatedArgs,
InputFileList InputsWithTypes,
std::string CompilationRecordPath,
StringRef ArgsHash, llvm::sys::TimePoint<> StartTime,
llvm::sys::TimePoint<> LastBuildTime,
size_t FilelistThreshold,
bool EnableIncrementalBuild = false,
bool EnableBatchMode = false,
unsigned BatchSeed = 0,
llvm::Optional<unsigned> BatchCount = llvm::None,
@@ -297,10 +251,7 @@ public:
bool SaveTemps = false,
bool ShowDriverTimeCompilation = false,
std::unique_ptr<UnifiedStatsReporter> Stats = nullptr,
bool OnlyOneDependencyFile = false,
bool VerifyFineGrainedDependencyGraphAfterEveryImport = false,
bool EmitFineGrainedDependencyDotFileAfterEveryImport = false,
bool EnableCrossModuleIncrementalBuild = false);
bool OnlyOneDependencyFile = false);
// clang-format on
~Compilation();
@@ -353,19 +304,6 @@ public:
return DerivedOutputFileMap;
}
bool getIncrementalBuildEnabled() const {
return EnableIncrementalBuild;
}
void disableIncrementalBuild(Twine why);
bool getVerifyFineGrainedDependencyGraphAfterEveryImport() const {
return VerifyFineGrainedDependencyGraphAfterEveryImport;
}
bool getEmitFineGrainedDependencyDotFileAfterEveryImport() const {
return EmitFineGrainedDependencyDotFileAfterEveryImport;
}
bool getBatchModeEnabled() const {
return EnableBatchMode;
}
@@ -377,13 +315,6 @@ public:
ContinueBuildingAfterErrors = Value;
}
bool getShowIncrementalBuildDecisions() const {
return ShowIncrementalBuildDecisions;
}
void setShowIncrementalBuildDecisions(bool value = true) {
ShowIncrementalBuildDecisions = value;
}
bool getShowJobLifecycle() const {
return ShowJobLifecycle;
}
@@ -395,10 +326,6 @@ public:
return ShowDriverTimeCompilation;
}
bool getEnableCrossModuleIncrementalBuild() const {
return EnableCrossModuleIncrementalBuild;
}
size_t getFilelistThreshold() const {
return FilelistThreshold;
}
@@ -420,7 +347,7 @@ public:
/// True if extra work has to be done when tracing through the dependency
/// graph, either in order to print dependencies or to collect statistics.
bool getTraceDependencies() const {
return getShowIncrementalBuildDecisions() || getStatsReporter();
return getStatsReporter();
}
OutputLevel getOutputLevel() const {
@@ -431,12 +358,10 @@ public:
return BatchSeed;
}
llvm::sys::TimePoint<> getLastBuildTime() const {
return LastBuildTime;
llvm::Optional<unsigned> getBatchCount() const {
return BatchCount;
}
llvm::Optional<unsigned> getBatchCount() const { return BatchCount; }
llvm::Optional<unsigned> getBatchSizeLimit() const { return BatchSizeLimit; }
/// Requests the path to a file containing all input source files. This can
@@ -448,17 +373,6 @@ public:
/// \sa types::isPartOfSwiftCompilation
const char *getAllSourcesPath() const;
/// Retrieve the path to the external swift deps file.
///
/// For cross-module incremental builds, this file contains the dependencies
/// from all the modules integrated over the prior build.
///
/// Currently this patch is relative to the build record, but we may want
/// to allow the output file map to customize this at some point.
std::string getExternalSwiftDepsFilePath() const {
return CompilationRecordPath + ".external";
}
/// Asks the Compilation to perform the Jobs which it knows about.
///
/// \param TQ The TaskQueue used to schedule jobs for execution.

View File

@@ -329,12 +329,9 @@ public:
/// \param[out] TopLevelActions The main Actions to build Jobs for.
/// \param TC the default host tool chain.
/// \param OI The OutputInfo for which Actions should be generated.
/// \param OutOfDateMap If present, information used to decide which files
/// need to be rebuilt.
/// \param C The Compilation to which Actions should be added.
void buildActions(SmallVectorImpl<const Action *> &TopLevelActions,
const ToolChain &TC, const OutputInfo &OI,
const InputInfoMap *OutOfDateMap,
Compilation &C) const;
/// Construct the OutputFileMap for the driver from the given arguments.

View File

@@ -1,597 +0,0 @@
//===---- FineGrainedDependencyModuleDepGraph.h ------------------*- C++-*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_DRIVER_FINE_GRAINED_DEPENDENCY_DRIVER_GRAPH_H
#define SWIFT_DRIVER_FINE_GRAINED_DEPENDENCY_DRIVER_GRAPH_H
#include "swift/AST/FineGrainedDependencies.h"
#include "swift/Basic/Debug.h"
#include "swift/Basic/Fingerprint.h"
#include "swift/Basic/LLVM.h"
#include "swift/Basic/OptionSet.h"
#include "swift/Driver/Job.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/PointerLikeTypeTraits.h"
#include "llvm/Support/VirtualOutputBackend.h"
#include "llvm/Support/VirtualOutputBackends.h"
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
// Declarations for the portion fine-grained dependency system used by the
// driver.
namespace swift {
class UnifiedStatsReporter;
namespace fine_grained_dependencies {
//==============================================================================
// MARK: ModuleDepGraphNode
//==============================================================================
/// A node in the DriverDependencyGraph
/// Keep separate type from Node for type-checking.
class ModuleDepGraphNode : public DepGraphNode {
/// The swiftDeps file that holds this entity iff this is a provides node.
/// If more than one source file has the same DependencyKey, then there
/// will be one node for each in the driver, distinguished by this field.
llvm::Optional<std::string> swiftDeps;
/// When finding transitive dependents, this node has been traversed.
bool hasBeenTracedAsADependent = false;
public:
ModuleDepGraphNode(const DependencyKey &key,
llvm::Optional<Fingerprint> fingerprint,
llvm::Optional<std::string> swiftDeps)
: DepGraphNode(key, fingerprint), swiftDeps(swiftDeps) {}
bool getHasBeenTraced() const { return hasBeenTracedAsADependent; }
void setHasBeenTraced() { hasBeenTracedAsADependent = true; }
void clearHasBeenTraced() { hasBeenTracedAsADependent = false; }
/// Integrate \p integrand's fingerprint into \p dn.
/// \returns true if there was a change requiring recompilation.
bool integrateFingerprintFrom(const SourceFileDepGraphNode *integrand) {
if (getFingerprint() == integrand->getFingerprint())
return false;
setFingerprint(integrand->getFingerprint());
return true;
}
bool operator==(const ModuleDepGraphNode &other) const {
return static_cast<DepGraphNode>(*this) ==
static_cast<DepGraphNode>(other) &&
getSwiftDeps() == other.getSwiftDeps();
}
const llvm::Optional<std::string> &getSwiftDeps() const { return swiftDeps; }
std::string getSwiftDepsOrEmpty() const {
return getSwiftDeps().value_or(std::string());
}
std::string getSwiftDepsForMapKey() const {
// Use the empty string for nodes whose source file is unknown,
// i.e. depends. (Known depends are represented by arcs, not nodes.)
return getSwiftDepsOrEmpty();
}
const std::string &getSwiftDepsOfProvides() const {
return getSwiftDeps().value();
}
/// Nodes can move from file to file when the driver reads the result of a
/// compilation.
void setSwiftDeps(llvm::Optional<std::string> s) { swiftDeps = s; }
bool getIsProvides() const { return getSwiftDeps().has_value(); }
/// Return true if this node describes a definition for which the job is known
bool isDefinedInAKnownFile() const { return getIsProvides(); }
bool doesNodeProvideAnInterface() const {
return getKey().isInterface() && getIsProvides();
}
bool assertImplementationMustBeInAFile() const {
assert((isDefinedInAKnownFile() || !getKey().isImplementation()) &&
"Implementations must be in some file.");
return true;
}
std::string humanReadableName() const {
StringRef where = !getIsProvides()
? ""
: llvm::sys::path::filename(getSwiftDepsOfProvides());
return DepGraphNode::humanReadableName(where);
}
void dump(raw_ostream &) const;
SWIFT_DEBUG_DUMP;
};
//==============================================================================
// MARK: ModuleDepGraph
//==============================================================================
/// See \ref Node in FineGrainedDependencies.h
class ModuleDepGraph {
/// Find nodes, first by the swiftDeps file, then by key.
/// Supports searching specific files for a node matching a key.
/// Such a search is useful when integrating nodes from a given source file to
/// see which nodes were there before integration and so might have
/// disappeared.
///
/// Some nodes are in no file, for instance a dependency on a Decl in a source
/// file whose swiftdeps has not been read yet. For these, the filename is the
/// empty string.
///
/// Don't add to this collection directly; use \ref addToMap
/// instead because it enforces the correspondence with the swiftFileDeps
/// field of the node.
/// TODO: Fix above comment
///
/// Sadly, cannot use an optional string for a key.
using NodeMap =
BiIndexedTwoStageMap<std::string, DependencyKey, ModuleDepGraphNode *>;
NodeMap nodeMap;
/// Since dependency keys use baseNames, they are coarser than individual
/// decls. So two decls might map to the same key. Given a use, which is
/// denoted by a node, the code needs to find the files to recompile. So, the
/// key indexes into the nodeMap, and that yields a submap of nodes keyed by
/// file. The set of keys in the submap are the files that must be recompiled
/// for the use.
/// (In a given file, only one node exists with a given key, but in the future
/// that would need to change if/when we can recompile a smaller unit than a
/// source file.)
/// Tracks def-use relationships by DependencyKey.
std::unordered_map<DependencyKey, std::unordered_set<ModuleDepGraphNode *>>
usesByDef;
// Supports requests from the driver to getExternalDependencies.
std::unordered_set<std::string> externalDependencies;
/// Keyed by swiftdeps filename, so we can get back to Jobs.
std::unordered_map<std::string, const driver::Job *> jobsBySwiftDeps;
/// For debugging, a dot file can be emitted. This file can be read into
/// various graph-drawing programs.
/// The driver emits this file into the same directory as the swiftdeps
/// files it reads, so when reading a file compute the base path here.
/// Initialize to empty in case no swiftdeps file has been read.
SmallString<128> driverDotFileBasePath = StringRef("");
/// For debugging, the driver can write out a dot file, for instance when a
/// Frontend swiftdeps is read and integrated. In order to keep subsequent
/// files for the same name distinct, keep a sequence number for each name.
std::unordered_map<std::string, unsigned> dotFileSequenceNumber;
public:
bool verifyFineGrainedDependencyGraphAfterEveryImport;
bool emitFineGrainedDependencyDotFileAfterEveryImport;
private:
/// If tracing dependencies, holds a vector used to hold the current path
/// def - use/def - use/def - ...
llvm::Optional<std::vector<const ModuleDepGraphNode *>> currentPathIfTracing;
/// If tracing dependencies, holds the sequence of defs used to get to the job
/// that is the key
std::unordered_multimap<const driver::Job *,
std::vector<const ModuleDepGraphNode *>>
dependencyPathsToJobs;
/// VirtualOutputBackend for emitting graphs.
llvm::IntrusiveRefCntPtr<llvm::vfs::OutputBackend> backend;
/// For helping with performance tuning, may be null:
UnifiedStatsReporter *stats;
//==============================================================================
// MARK: ModuleDepGraph - mutating dependencies
//==============================================================================
/// Encapsulate the invariant between where the node resides in
/// nodesBySwiftDepsFile and the swiftDeps node instance variable here.
void addToMap(ModuleDepGraphNode *n) {
nodeMap.insert(n->getSwiftDepsForMapKey(), n->getKey(), n);
}
/// When integrating a SourceFileDepGraph, there might be a node representing
/// a Decl that had previously been read as an expat, that is a node
/// representing a Decl in no known file (to that point). (Recall the the
/// Frontend processes name lookups as dependencies, but does not record in
/// which file the name was found.) In such a case, it is necessary to move
/// the node to the proper collection.
void moveNodeToDifferentFile(ModuleDepGraphNode *n,
llvm::Optional<std::string> newFile) {
eraseNodeFromMap(n);
n->setSwiftDeps(newFile);
addToMap(n);
}
/// Remove node from nodeMap, check invariants.
ModuleDepGraphNode *eraseNodeFromMap(ModuleDepGraphNode *nodeToErase) {
ModuleDepGraphNode *nodeActuallyErased = nodeMap.findAndErase(
nodeToErase->getSwiftDepsForMapKey(), nodeToErase->getKey());
(void)nodeActuallyErased;
assert(
nodeToErase == nodeActuallyErased ||
mapCorruption("Node found from key must be same as node holding key."));
return nodeToErase;
}
void eraseUsesOfNode(ModuleDepGraphNode *nodeToErase) {
for (auto &defAndUses : usesByDef)
defAndUses.second.erase(nodeToErase);
}
void eraseNodeFromCurrentPathIfTracing(ModuleDepGraphNode *nodeToErase) {
if (currentPathIfTracing)
eraseNodeFromVector(currentPathIfTracing.value(), nodeToErase);
}
void eraseNodeFromDependencyPathToJobs(ModuleDepGraphNode *nodeToErase) {
for (auto &jobAndPath : dependencyPathsToJobs)
eraseNodeFromVector(jobAndPath.second, nodeToErase);
}
static void eraseNodeFromVector(std::vector<const ModuleDepGraphNode *> &v,
const ModuleDepGraphNode *n) {
const auto where = std::find(v.begin(), v.end(), n);
if (where != v.end())
v.erase(where);
}
void eraseNodeFromGraphAndFreeIt(ModuleDepGraphNode *);
/// If the programmer removes a Decl from a source file, the corresponding
/// ModuleDepGraphNode needs to be removed.
void eraseNodeFromJob(ModuleDepGraphNode *);
//============================================================================
// MARK: ModuleDepGraph - utilities for Job and swiftdeps
//============================================================================
private:
static StringRef getSwiftDeps(const driver::Job *cmd) {
return cmd->getOutput().getAdditionalOutputForType(
file_types::TY_SwiftDeps);
}
const driver::Job *getJob(llvm::Optional<std::string> swiftDeps) const {
assert(swiftDeps.has_value() && "Don't call me for expats.");
auto iter = jobsBySwiftDeps.find(swiftDeps.value());
assert(iter != jobsBySwiftDeps.end() && "All jobs should be tracked.");
return iter->second;
}
//============================================================================
// MARK: ModuleDepGraph - creation
//============================================================================
public:
/// For templates such as DotFileEmitter.
using NodeType = ModuleDepGraphNode;
/// \p stats may be null
ModuleDepGraph(const bool verifyFineGrainedDependencyGraphAfterEveryImport,
const bool emitFineGrainedDependencyDotFileAfterEveryImport,
const bool shouldTraceDependencies,
UnifiedStatsReporter *stats)
: verifyFineGrainedDependencyGraphAfterEveryImport(
verifyFineGrainedDependencyGraphAfterEveryImport),
emitFineGrainedDependencyDotFileAfterEveryImport(
emitFineGrainedDependencyDotFileAfterEveryImport),
currentPathIfTracing(
shouldTraceDependencies
? llvm::Optional<std::vector<const ModuleDepGraphNode *>>(
std::vector<const ModuleDepGraphNode *>())
: llvm::None),
stats(stats) {
assert(verify() && "ModuleDepGraph should be fine when created");
// Create a OnDiskOutputBackend for emitting graphs. Currently, this is
// only used by driver so the backend is not shared with a CompilerInstance.
backend = llvm::makeIntrusiveRefCnt<llvm::vfs::OnDiskOutputBackend>();
}
/// For unit tests.
ModuleDepGraph(const bool EmitDotFilesForDebugging = false)
: ModuleDepGraph(
true, /*emitFineGrainedDependencyDotFileAfterEveryImport=*/
EmitDotFilesForDebugging, false, nullptr) {}
//============================================================================
// MARK: ModuleDepGraph - updating from a switdeps file
//============================================================================
public:
using Changes = llvm::Optional<std::unordered_set<ModuleDepGraphNode *>>;
/// Unlike the standard \c CoarseGrainedDependencyGraph, returns \c
/// CoarseGrainedDependencyGraphImpl::LoadResult::AffectsDownstream when
/// loading a new file, i.e. when determining the initial set. Caller
/// compensates.
Changes loadFromPath(const driver::Job *, StringRef, DiagnosticEngine &);
Changes loadFromSourceFileDepGraph(const driver::Job *cmd,
const SourceFileDepGraph &,
DiagnosticEngine &);
Changes loadFromSwiftModuleBuffer(const driver::Job *, llvm::MemoryBuffer &,
DiagnosticEngine &);
private:
/// Read a SourceFileDepGraph belonging to \p job from \p buffer
/// and integrate it into the ModuleDepGraph.
/// Used both the first time, and to reload the SourceFileDepGraph.
/// If any changes were observed, indicate same in the return vale.
Changes loadFromBuffer(const driver::Job *, llvm::MemoryBuffer &,
DiagnosticEngine &);
/// Integrate a SourceFileDepGraph into the receiver.
/// Integration happens when the driver needs to read SourceFileDepGraph.
Changes
integrate(const SourceFileDepGraph &, StringRef swiftDepsOfJob);
enum class LocationOfPreexistingNode { nowhere, here, elsewhere };
typedef llvm::Optional<
std::pair<LocationOfPreexistingNode, ModuleDepGraphNode *>>
PreexistingNodeIfAny;
/// Find the preexisting node here that best matches the integrand.
PreexistingNodeIfAny
findPreexistingMatch(StringRef swiftDepsOfCompilationToBeIntegrated,
const SourceFileDepGraphNode *integrand) const;
/// Integrate the \p integrand into the receiver.
/// If an illegal value was found, return \c None, otherwise
/// return the changed node if any..
llvm::Optional<NullablePtr<ModuleDepGraphNode>>
integrateSourceFileDepGraphNode(const SourceFileDepGraph &g,
const SourceFileDepGraphNode *integrand,
const PreexistingNodeIfAny preexistingMatch,
StringRef swiftDepsOfJob);
/// Integrate the \p integrand, a node that represents a Decl in the swiftDeps
/// file being integrated. \p preexistingNodeInPlace holds the node
/// representing the same Decl that already exists, if there is one. \p
/// preexistingExpat holds a node with the same key that already exists, but was
/// not known to reside in any swiftDeps file. Return a bool indicating if
/// this node represents a change that must be propagated, and the integrated
/// ModuleDepGraphNode.
std::pair<bool, ModuleDepGraphNode *>
integrateSourceFileDeclNode(const SourceFileDepGraphNode *integrand,
StringRef swiftDepsOfJob,
const PreexistingNodeIfAny preexistingMatch);
/// Create a brand-new ModuleDepGraphNode to integrate \p integrand.
ModuleDepGraphNode *
integrateByCreatingANewNode(const SourceFileDepGraphNode *integrand,
llvm::Optional<std::string> swiftDepsForNewNode);
/// After importing a provides node from the frontend, record its
/// dependencies.
/// Return true if moduleUseNode picks up a new external-dependency
///
/// \param g The source file graph being integrated into the module graph
/// \param sourceFileUseNode The source file node just integrated, which may
/// also be a use (i.e. a "depends", a declaration used by something else)
/// \param moduleUseNode The module file node corresponding to the \c
/// sourceFileUseNode
bool recordWhatUseDependsUpon(const SourceFileDepGraph &g,
const SourceFileDepGraphNode *sourceFileUseNode,
ModuleDepGraphNode *moduleUseNode);
//============================================================================
// MARK: ModuleDepGraph - dot file support
//============================================================================
public:
/// For the dot file.
std::string getGraphID() const { return "driver"; }
/// Don't want to do this after every integration--too slow--
/// So export this hook to the driver.
bool emitDotFileAndVerify(DiagnosticEngine &) const;
/// Use the known swiftDeps to find a directory for
/// the job-independent dot file.
std::string computePathForDotFile() const;
/// For debugging and visualization, write out the graph to a dot file.
/// \p diags may be null if no diagnostics are needed.
void emitDotFileForJob(DiagnosticEngine &, const driver::Job *);
void emitDotFile(DiagnosticEngine &, StringRef baseName);
void emitDotFile() { emitDotFile(llvm::errs()); }
void emitDotFile(llvm::raw_ostream &);
//============================================================================
// MARK: ModuleDepGraph - traversal
//============================================================================
public:
void forCorrespondingImplementationOfProvidedInterface(
const ModuleDepGraphNode *,
function_ref<void(ModuleDepGraphNode *)>) const;
void forEachUseOf(const ModuleDepGraphNode *def,
function_ref<void(ModuleDepGraphNode *use)>) const;
void forEachNode(function_ref<void(ModuleDepGraphNode *)>) const;
void forEachArc(function_ref<void(const ModuleDepGraphNode *def,
const ModuleDepGraphNode *use)>) const;
/// Call \p fn for each node whose key matches \p key.
void
forEachMatchingNode(const DependencyKey &key,
function_ref<void(ModuleDepGraphNode *)>) const;
void forEachNodeInJob(StringRef swiftDeps,
function_ref<void(ModuleDepGraphNode *)>) const;
/// Given a definition node, transitively find all previous untraced
/// dependents and add them to the array. Also returns definition if that is
/// untraced.
void findPreviouslyUntracedDependents(
std::vector<ModuleDepGraphNode *> &foundDependents,
ModuleDepGraphNode *definition);
/// Given a set of nodes, return the set of swiftDeps for the jobs those
/// nodes are in.
std::vector<std::string>
computeSwiftDepsFromNodes(ArrayRef<const ModuleDepGraphNode *> nodes) const;
/// Record a visit to this node for later dependency printing
size_t traceArrival(const ModuleDepGraphNode *visitedNode);
/// Record end of visit to this node.
void traceDeparture(size_t pathLengthAfterArrival);
/// For printing why a Job was compiled, record how it was found.
void recordDependencyPathToJob(
const std::vector<const ModuleDepGraphNode *> &pathToJob,
const driver::Job *dependentJob);
/// Dump the path that led to \p node.
void printPath(raw_ostream &out, const driver::Job *node) const;
/// Get a printable filename, given a node's swiftDeps.
StringRef
getProvidingFilename(const llvm::Optional<std::string> &swiftDeps) const;
/// Print one node on the dependency path.
static void printOneNodeOfPath(raw_ostream &out, const DependencyKey &key,
const StringRef filename);
bool isCurrentPathForTracingEmpty() const {
return !currentPathIfTracing.has_value() || currentPathIfTracing->empty();
}
//============================================================================
// MARK: ModuleDepGraph - job-level queries and operations
//============================================================================
public:
// This section contains the interface to the status quo code in the driver.
bool haveAnyNodesBeenTraversedIn(const driver::Job *) const;
/// Find all jobs (possibly including the argument) requiring recompilation
/// assuming that every entity in \p jobToBeRecompiled has changed.
std::vector<const driver::Job *>
findJobsToRecompileWhenWholeJobChanges(const driver::Job *jobToBeRecompiled);
template <typename Nodes>
std::vector<const driver::Job *>
findJobsToRecompileWhenNodesChange(const Nodes &nodes) {
std::vector<ModuleDepGraphNode *> foundDependents;
for (ModuleDepGraphNode *n : nodes)
findPreviouslyUntracedDependents(foundDependents, n);
return jobsContaining(foundDependents);
}
private:
std::vector<const driver::Job *>
jobsContaining(const ArrayRef<const ModuleDepGraphNode *> uses) const;
public:
/// Record a new (to this graph) Job.
void registerJob(const driver::Job *);
std::vector<const driver::Job *> getAllJobs() const;
/// Find jobs that were previously not known to need compilation but that
/// depend on \c externalDependency.
std::vector<const driver::Job *>
findExternallyDependentUntracedJobs(StringRef externalDependency);
//============================================================================
// MARK: ModuleDepGraph - External dependencies
//============================================================================
public:
std::vector<StringRef> getExternalDependencies() const;
void forEachUntracedJobDirectlyDependentOnExternalSwiftDeps(
StringRef externalDependency, function_ref<void(const driver::Job *)> fn);
void forEachUntracedJobDirectlyDependentOnExternalIncrementalSwiftDeps(
StringRef externalDependency, function_ref<void(const driver::Job *)> fn);
//============================================================================
// MARK: ModuleDepGraph - verification
//============================================================================
private:
/// Return true or abort
bool verify() const;
void verifyNodeMapEntries() const;
/// Called for each \ref nodeMap entry during verification.
/// \p nodesSeenInNodeMap ensures that nodes are unique in each submap
/// \p swiftDepsString is the swiftdeps file name in the map
/// \p key is the DependencyKey in the map
/// \p n is the node for that map entry
void verifyNodeMapEntry(
std::array<std::unordered_map<
DependencyKey,
std::unordered_map<std::string, ModuleDepGraphNode *>>,
2> &nodesSeenInNodeMap,
const std::string &swiftDepsString, const DependencyKey &,
ModuleDepGraphNode *, unsigned submapIndex) const;
/// See ModuleDepGraph::verifyNodeMapEntry for argument descriptions
void verifyNodeIsUniqueWithinSubgraph(
std::array<std::unordered_map<
DependencyKey,
std::unordered_map<std::string, ModuleDepGraphNode *>>,
2> &nodesSeenInNodeMap,
const std::string &swiftDepsString, const DependencyKey &,
ModuleDepGraphNode *, unsigned submapIndex) const;
/// See ModuleDepGraph::verifyNodeMapEntry for argument descriptions
void verifyNodeIsInRightEntryInNodeMap(const std::string &swiftDepsString,
const DependencyKey &,
const ModuleDepGraphNode *) const;
void verifyExternalDependencyUniqueness(const DependencyKey &) const;
void verifyCanFindEachJob() const;
void verifyEachJobInGraphIsTracked() const;
static bool mapCorruption(const char *msg) { llvm_unreachable(msg); }
bool ensureJobIsTracked(const std::string &swiftDeps) const {
assert(swiftDeps.empty() || getJob(swiftDeps));
return true;
}
static std::vector<const driver::Job *>
printJobsForDebugging(const std::vector<const driver::Job *> &jobs);
};
} // namespace fine_grained_dependencies
} // namespace swift
#endif // SWIFT_DRIVER_FINE_GRAINED_DEPENDENCY_DRIVER_GRAPH_H

View File

@@ -317,22 +317,6 @@ private:
/// The modification time of the main input file, if any.
llvm::sys::TimePoint<> InputModTime = llvm::sys::TimePoint<>::max();
#ifndef NDEBUG
/// The "wave" of incremental jobs that this \c Job was scheduled into.
///
/// The first "wave" of jobs is computed by the driver from the set of inputs
/// and external files that have been mutated by the user. From there, as
/// jobs from the first wave finish executing, we reload their \c swiftdeps
/// files and re-integrate them into the dependency graph to discover
/// the jobs for the second "wave".
///
/// In +asserts builds, we ensure that no more than two "waves" occur for
/// any given incremental compilation session. This is a consequence of
/// 1) transitivity in dependency arcs
/// 2) dependency tracing from uses that affect a def's interfaces to that
/// def's uses.
mutable unsigned Wave = 1;
#endif
public:
Job(const JobAction &Source, SmallVectorImpl<const Job *> &&Inputs,
@@ -425,11 +409,6 @@ public:
/// Assumes that, if a compile job, has one primary swift input
/// May return empty if none.
StringRef getFirstSwiftPrimaryInput() const;
#ifndef NDEBUG
unsigned getWave() const { return Wave; }
void setWave(unsigned WaveNum) const { Wave = WaveNum; }
#endif
};
/// A BatchJob comprises a _set_ of jobs, each of which is sufficiently similar

View File

@@ -43,8 +43,6 @@ void InputAction::anchor() {}
void JobAction::anchor() {}
void IncrementalJobAction::anchor() {}
void CompileJobAction::anchor() {}
void InterpretJobAction::anchor() {}

View File

@@ -5,7 +5,6 @@ set(swiftDriver_sources
Compilation.cpp
DarwinToolChains.cpp
Driver.cpp
FineGrainedDependencyDriverGraph.cpp
FrontendUtil.cpp
Job.cpp
PrettyStackTrace.cpp

View File

@@ -26,7 +26,6 @@
#include "swift/Basic/type_traits.h"
#include "swift/Driver/Action.h"
#include "swift/Driver/Driver.h"
#include "swift/Driver/FineGrainedDependencyDriverGraph.h"
#include "swift/Driver/Job.h"
#include "swift/Driver/ToolChain.h"
#include "swift/Option/Options.h"
@@ -45,8 +44,6 @@
#include "llvm/Support/YAMLParser.h"
#include "llvm/Support/raw_ostream.h"
#include "CompilationRecord.h"
#include <fstream>
#include <signal.h>
#if defined(_WIN32)
@@ -112,12 +109,7 @@ Compilation::Compilation(DiagnosticEngine &Diags,
std::unique_ptr<InputArgList> InputArgs,
std::unique_ptr<DerivedArgList> TranslatedArgs,
InputFileList InputsWithTypes,
std::string CompilationRecordPath,
StringRef ArgsHash,
llvm::sys::TimePoint<> StartTime,
llvm::sys::TimePoint<> LastBuildTime,
size_t FilelistThreshold,
bool EnableIncrementalBuild,
bool EnableBatchMode,
unsigned BatchSeed,
llvm::Optional<unsigned> BatchCount,
@@ -125,21 +117,13 @@ Compilation::Compilation(DiagnosticEngine &Diags,
bool SaveTemps,
bool ShowDriverTimeCompilation,
std::unique_ptr<UnifiedStatsReporter> StatsReporter,
bool OnlyOneDependencyFile,
bool VerifyFineGrainedDependencyGraphAfterEveryImport,
bool EmitFineGrainedDependencyDotFileAfterEveryImport,
bool EnableCrossModuleIncrementalBuild)
bool OnlyOneDependencyFile)
: Diags(Diags), TheToolChain(TC),
TheOutputInfo(OI),
Level(Level),
RawInputArgs(std::move(InputArgs)),
TranslatedArgs(std::move(TranslatedArgs)),
InputFilesWithTypes(std::move(InputsWithTypes)),
CompilationRecordPath(CompilationRecordPath),
ArgsHash(ArgsHash),
BuildStartTime(StartTime),
LastBuildTime(LastBuildTime),
EnableIncrementalBuild(EnableIncrementalBuild),
EnableBatchMode(EnableBatchMode),
BatchSeed(BatchSeed),
BatchCount(BatchCount),
@@ -148,13 +132,7 @@ Compilation::Compilation(DiagnosticEngine &Diags,
ShowDriverTimeCompilation(ShowDriverTimeCompilation),
Stats(std::move(StatsReporter)),
FilelistThreshold(FilelistThreshold),
OnlyOneDependencyFile(OnlyOneDependencyFile),
VerifyFineGrainedDependencyGraphAfterEveryImport(
VerifyFineGrainedDependencyGraphAfterEveryImport),
EmitFineGrainedDependencyDotFileAfterEveryImport(
EmitFineGrainedDependencyDotFileAfterEveryImport),
EnableCrossModuleIncrementalBuild(EnableCrossModuleIncrementalBuild)
{ }
OnlyOneDependencyFile(OnlyOneDependencyFile) { }
// clang-format on
static bool writeFilelistIfNecessary(const Job *job, const ArgList &args,
@@ -163,9 +141,6 @@ static bool writeFilelistIfNecessary(const Job *job, const ArgList &args,
using CommandSetVector = llvm::SetVector<const Job*>;
using BatchPartition = std::vector<std::vector<const Job*>>;
using InputInfoMap = llvm::SmallMapVector<const llvm::opt::Arg *,
CompileJobAction::InputInfo, 16>;
namespace {
static DetailedTaskDescription
constructDetailedTaskDescription(const driver::Job &Cmd) {
@@ -265,13 +240,6 @@ namespace driver {
/// Only intended for source files.
llvm::SmallDenseMap<const Job *, bool, 16> UnfinishedCommands;
/// Jobs that incremental-mode has decided it can skip.
CommandSet DeferredCommands;
public:
/// Dependency graphs for deciding which jobs are dirty (need running)
/// or clean (can be skipped).
fine_grained_dependencies::ModuleDepGraph FineGrainedDepGraph;
private:
/// TaskQueue for execution.
std::unique_ptr<TaskQueue> TQ;
@@ -287,35 +255,6 @@ namespace driver {
llvm::SmallDenseMap<const Job *, std::unique_ptr<llvm::Timer>, 16>
DriverTimers;
void noteBuilding(const Job *cmd, const bool willBeBuilding,
StringRef reason) const {
if (!Comp.getShowIncrementalBuildDecisions())
return;
if (ScheduledCommands.count(cmd))
return;
if (!willBeBuilding)
return;
llvm::outs() << "Queuing " << reason << ": " << LogJob(cmd) << "\n";
getFineGrainedDepGraph().printPath(llvm::outs(), cmd);
}
template <typename JobsCollection>
void noteBuildingJobs(const JobsCollection &unsortedJobsArg,
const StringRef reason) const {
if (!Comp.getShowIncrementalBuildDecisions() &&
!Comp.getShowJobLifecycle())
return;
// Sigh, must manually convert SmallPtrSet to ArrayRef-able container
llvm::SmallVector<const Job *, 16> unsortedJobs;
for (const Job *j : unsortedJobsArg)
unsortedJobs.push_back(j);
llvm::SmallVector<const Job *, 16> sortedJobs;
Comp.sortJobsToMatchCompilationInputs(unsortedJobs, sortedJobs);
for (const Job *j : sortedJobs)
noteBuilding(j, /*willBeBuilding=*/true, reason);
}
const Job *findUnfinishedJob(ArrayRef<const Job *> JL) {
for (const Job *Cmd : JL) {
if (!FinishedCommands.count(Cmd))
@@ -344,17 +283,6 @@ namespace driver {
return;
}
#ifndef NDEBUG
// If we can, assert that no compile jobs are scheduled beyond the second
// wave. If this assertion fails, it indicates one of:
// 1) A failure of the driver's job tracing machinery to follow a
// dependency arc.
// 2) A failure of the frontend to emit a dependency arc.
if (isa<CompileJobAction>(Cmd->getSource()) && Cmd->getWave() > 2) {
llvm_unreachable("Scheduled a command into a third wave!");
}
#endif
// Adding to scheduled means we've committed to its completion (not
// distinguished from skipping). We never remove it once inserted.
ScheduledCommands.insert(Cmd);
@@ -461,115 +389,6 @@ namespace driver {
}
}
/// Note that a .swiftdeps file failed to load and take corrective actions:
/// disable incremental logic and schedule all existing deferred commands.
void
dependencyLoadFailed(StringRef DependenciesFile, bool Warn=true) {
if (Warn && Comp.getShowIncrementalBuildDecisions())
Comp.getDiags().diagnose(SourceLoc(),
diag::warn_unable_to_load_dependencies,
DependenciesFile);
Comp.disableIncrementalBuild(
Twine("malformed swift dependencies file '") + DependenciesFile +
"'");
}
/// Helper that attempts to reload a job's .swiftdeps file after the job
/// exits, and re-run transitive marking to ensure everything is properly
/// invalidated by any new dependency edges introduced by it. If reloading
/// fails, this can cause deferred jobs to be immediately scheduled.
std::vector<const Job*>
reloadAndRemarkDeps(const Job *FinishedCmd, int ReturnCode) {
const CommandOutput &Output = FinishedCmd->getOutput();
StringRef DependenciesFile =
Output.getAdditionalOutputForType(file_types::TY_SwiftDeps);
if (DependenciesFile.empty()) {
// If this job doesn't track dependencies, it must always be run.
// Note: In theory CheckDependencies makes sense as well (for a leaf
// node in the dependency graph), and maybe even NewlyAdded (for very
// coarse dependencies that always affect downstream nodes), but we're
// not using either of those right now, and this logic should probably
// be revisited when we are.
assert(isa<MergeModuleJobAction>(FinishedCmd->getSource()) ||
FinishedCmd->getCondition() == Job::Condition::Always);
return {};
}
const bool compileExitedNormally =
ReturnCode == EXIT_SUCCESS || ReturnCode == EXIT_FAILURE;
return !compileExitedNormally
? reloadAndRemarkDepsOnAbnormalExit(FinishedCmd)
: reloadAndRemarkDepsOnNormalExit(FinishedCmd, /*cmdFailed=*/
ReturnCode != EXIT_SUCCESS,
DependenciesFile);
}
// If we have a dependency file /and/ the frontend task exited normally,
// we can be discerning about what downstream files to rebuild.
std::vector<const Job *>
reloadAndRemarkDepsOnNormalExit(const Job *FinishedCmd,
const bool cmdFailed,
StringRef DependenciesFile) {
const auto changedNodes = getFineGrainedDepGraph().loadFromPath(
FinishedCmd, DependenciesFile, Comp.getDiags());
const bool loadFailed = !changedNodes;
if (loadFailed) {
handleDependenciesReloadFailure(cmdFailed, DependenciesFile);
return {};
}
return getFineGrainedDepGraph()
.findJobsToRecompileWhenNodesChange(changedNodes.value());
}
void handleDependenciesReloadFailure(const bool cmdFailed,
const StringRef DependenciesFile) {
if (cmdFailed) {
// let the next build handle it.
return;
}
dependencyLoadFailed(DependenciesFile);
// Better try compiling whatever was waiting on more info.
for (const Job *Cmd : DeferredCommands)
scheduleCommandIfNecessaryAndPossible(Cmd);
DeferredCommands.clear();
};
std::vector<const Job *>
reloadAndRemarkDepsOnAbnormalExit(const Job *FinishedCmd) {
// If there's an abnormal exit (a crash), assume the worst.
switch (FinishedCmd->getCondition()) {
case Job::Condition::NewlyAdded:
// The job won't be treated as newly added next time. Conservatively
// mark it as affecting other jobs, because some of them may have
// completed already.
return findJobsToRecompileWhenWholeJobChanges(FinishedCmd);
case Job::Condition::Always:
// Any incremental task that shows up here has already been marked;
// we didn't need to wait for it to finish to start downstream
// tasks.
break;
case Job::Condition::RunWithoutCascading:
// If this file changed, it might have been a non-cascading change
// and it might not. Unfortunately, the interface hash has been
// updated or compromised, so we don't actually know anymore; we
// have to conservatively assume the changes could affect other
// files.
return findJobsToRecompileWhenWholeJobChanges(FinishedCmd);
case Job::Condition::CheckDependencies:
// If the only reason we're running this is because something else
// changed, then we can trust the dependency graph as to whether
// it's a cascading or non-cascading change. That is, if whatever
// /caused/ the error isn't supposed to affect other files, and
// whatever /fixes/ the error isn't supposed to affect other files,
// then there's no need to recompile any other inputs. If either of
// those are false, we /do/ need to recompile other inputs.
break;
}
return {};
}
/// Check to see if a job produced a zero-length serialized diagnostics
/// file, which is used to indicate batch-constituents that were batched
/// together with a failing constituent but did not, themselves, produce any
@@ -675,30 +494,12 @@ namespace driver {
static_cast<const BatchJob *>(FinishedCmd));
}
CommandSet DependentsInEffect =
subsequentJobsNeeded(FinishedCmd, ReturnCode);
if (ReturnCode != EXIT_SUCCESS)
return taskFailed(FinishedCmd, ReturnCode);
// When a task finishes, we need to reevaluate the other commands that
// might have been blocked.
markFinished(FinishedCmd);
noteBuildingJobs(DependentsInEffect,
"because of dependencies discovered later");
scheduleCommandsInSortedOrder(DependentsInEffect);
for (const Job *Cmd : DependentsInEffect) {
if (DeferredCommands.erase(Cmd)) {
#ifndef NDEBUG
if (isa<CompileJobAction>(FinishedCmd->getSource()))
Cmd->setWave(FinishedCmd->getWave() + 1);
#else
continue;
#endif
}
}
return TaskFinishedResponse::ContinueExecution;
}
@@ -776,23 +577,6 @@ namespace driver {
}
}
/// In order to handle both old dependencies that have disappeared and new
/// dependencies that have arisen, we need to reload the dependency file.
/// Do this whether or not the build succeeded.
///
/// FIXME: too much global state floating around, e.g.
/// getIncrementalBuildEnabled
CommandSet subsequentJobsNeeded(const Job *FinishedCmd,
const int ReturnCode) {
if (!Comp.getIncrementalBuildEnabled())
return {};
auto Dependents = reloadAndRemarkDeps(FinishedCmd, ReturnCode);
CommandSet DepSet;
for (const Job *Cmd : Dependents)
DepSet.insert(Cmd);
return DepSet;
}
TaskFinishedResponse taskSignalled(ProcessId Pid, StringRef ErrorMsg,
StringRef Output, StringRef Errors,
void *Context,
@@ -850,11 +634,6 @@ namespace driver {
public:
PerformJobsState(Compilation &Comp, std::unique_ptr<TaskQueue> &&TaskQueue)
: Comp(Comp),
FineGrainedDepGraph(
Comp.getVerifyFineGrainedDependencyGraphAfterEveryImport(),
Comp.getEmitFineGrainedDependencyDotFileAfterEveryImport(),
Comp.getTraceDependencies(),
Comp.getStatsReporter()),
TQ(std::move(TaskQueue)) {}
/// Schedule and run initial, additional, and batch jobs.
@@ -862,15 +641,11 @@ namespace driver {
scheduleJobsBeforeBatching();
formBatchJobsAndAddPendingJobsToTaskQueue();
runTaskQueueToCompletion();
checkUnfinishedJobs();
}
private:
void scheduleJobsBeforeBatching() {
if (Comp.getIncrementalBuildEnabled())
scheduleFirstRoundJobsForIncrementalCompilation();
else
scheduleJobsForNonIncrementalCompilation();
scheduleJobsForNonIncrementalCompilation();
}
void scheduleJobsForNonIncrementalCompilation() {
@@ -878,226 +653,6 @@ namespace driver {
scheduleCommandIfNecessaryAndPossible(Cmd);
}
void scheduleFirstRoundJobsForIncrementalCompilation() {
CommandSet compileJobsToSchedule =
computeFirstRoundCompileJobsForIncrementalCompilation();
for (const Job *Cmd : Comp.getJobs()) {
if (!isa<IncrementalJobAction>(Cmd->getSource()) ||
compileJobsToSchedule.count(Cmd)) {
scheduleCommandIfNecessaryAndPossible(Cmd);
noteBuilding(Cmd, /*willBeBuilding*/ true, "");
} else {
DeferredCommands.insert(Cmd);
noteBuilding(Cmd, /*willBeBuilding*/ false, "");
}
}
}
/// Figure out the best strategy and return those jobs. May return
/// duplicates.
CommandSet computeFirstRoundCompileJobsForIncrementalCompilation() {
auto getEveryCompileJob = [&] {
CommandSet everyIncrementalJob;
for (const Job *Cmd : Comp.getJobs()) {
if (isa<IncrementalJobAction>(Cmd->getSource()))
everyIncrementalJob.insert(Cmd);
}
return everyIncrementalJob;
};
bool sawModuleWrapJob = false;
const Job *mergeModulesJob = nullptr;
CommandSet jobsToSchedule;
CommandSet initialCascadingCommands;
for (const Job *cmd : Comp.getJobs()) {
// A modulewrap job consumes the output of merge-modules. If it is
// in the queue, we must run merge-modules or empty temporary files
// will be consumed by the job instead.
// FIXME: We should be able to ditch this if we compare the timestamps
// of the temporary file to the build record, if it exists.
sawModuleWrapJob |= isa<ModuleWrapJobAction>(cmd->getSource());
// Skip jobs that have no associated incremental info.
if (!isa<IncrementalJobAction>(cmd->getSource())) {
continue;
}
if (isa<MergeModuleJobAction>(cmd->getSource())) {
assert(!mergeModulesJob && "multiple scheduled merge-modules jobs?");
mergeModulesJob = cmd;
}
const llvm::Optional<std::pair<bool, bool>> shouldSchedAndIsCascading =
computeShouldInitiallyScheduleJobAndDependents(cmd);
if (!shouldSchedAndIsCascading)
return getEveryCompileJob(); // Load error, just run them all
const bool &shouldSchedule = shouldSchedAndIsCascading->first;
const bool &isCascading = shouldSchedAndIsCascading->second;
if (shouldSchedule)
jobsToSchedule.insert(cmd);
if (isCascading)
initialCascadingCommands.insert(cmd);
}
for (const auto *cmd : collectCascadedJobsFromDependencyGraph(
initialCascadingCommands))
jobsToSchedule.insert(cmd);
for (const auto cmd :
collectExternallyDependentJobsFromDependencyGraph())
jobsToSchedule.insert(cmd);
// The merge-modules job is special: it *must* be scheduled if any other
// job has been scheduled because any other job can influence the
// structure of the resulting module. Additionally, the initial scheduling
// predicate above is only aware of intra-module changes. External
// dependencies changing *must* cause merge-modules to be scheduled.
if ((!jobsToSchedule.empty() || sawModuleWrapJob) && mergeModulesJob) {
jobsToSchedule.insert(mergeModulesJob);
}
return jobsToSchedule;
}
/// Return whether \p Cmd should be scheduled when using dependencies, and if
/// the job is cascading. Or if there was a dependency-read error, return
/// \c None to indicate don't-know.
llvm::Optional<std::pair<bool, bool>>
computeShouldInitiallyScheduleJobAndDependents(const Job *Cmd) {
auto CondAndHasDepsIfNoError =
loadDependenciesAndComputeCondition(Cmd);
if (!CondAndHasDepsIfNoError)
return llvm::None; // swiftdeps read error, abandon dependencies
Job::Condition Cond;
bool HasDependenciesFileName;
std::tie(Cond, HasDependenciesFileName) =
CondAndHasDepsIfNoError.value();
const bool shouldSched = shouldScheduleCompileJobAccordingToCondition(
Cmd, Cond, HasDependenciesFileName);
const bool isCascading = isCascadingJobAccordingToCondition(
Cmd, Cond, HasDependenciesFileName);
return std::make_pair(shouldSched, isCascading);
}
/// Returns job condition, and whether a dependency file was specified.
/// But returns None if there was a dependency read error.
llvm::Optional<std::pair<Job::Condition, bool>>
loadDependenciesAndComputeCondition(const Job *const Cmd) {
// merge-modules Jobs do not have .swiftdeps files associated with them,
// however, their compilation condition is computed as a function of their
// inputs, so their condition can be used as normal.
if (isa<MergeModuleJobAction>(Cmd->getSource())) {
return std::make_pair(Cmd->getCondition(), true);
}
// Try to load the dependencies file for this job. If there isn't one, we
// always have to run the job, but it doesn't affect any other jobs. If
// there should be one but it's not present or can't be loaded, we have to
// run all the jobs.
// FIXME: We can probably do better here!
const StringRef DependenciesFile =
Cmd->getOutput().getAdditionalOutputForType(file_types::TY_SwiftDeps);
if (DependenciesFile.empty())
return std::make_pair(Job::Condition::Always, false);
if (Cmd->getCondition() == Job::Condition::NewlyAdded) {
registerJobToDepGraph(Cmd);
return std::make_pair(Job::Condition::NewlyAdded, true);
}
const bool depGraphLoadError =
loadDepGraphFromPath(Cmd, DependenciesFile);
if (depGraphLoadError) {
dependencyLoadFailed(DependenciesFile, /*Warn=*/true);
return llvm::None;
}
return std::make_pair(Cmd->getCondition(), true);
}
bool shouldScheduleCompileJobAccordingToCondition(
const Job *const Cmd, const Job::Condition Condition,
const bool hasDependenciesFileName) {
switch (Condition) {
case Job::Condition::Always:
case Job::Condition::NewlyAdded:
if (Comp.getIncrementalBuildEnabled() && hasDependenciesFileName) {
// No need to do anything since after this jos is run and its
// dependencies reloaded, they will show up as changed nodes
}
LLVM_FALLTHROUGH;
case Job::Condition::RunWithoutCascading:
noteBuilding(Cmd, /*willBeBuilding=*/true,
"(initial)");
return true;
case Job::Condition::CheckDependencies:
noteBuilding(Cmd, /*willBeBuilding=*/false,
"file is up-to-date and output exists");
return false;
}
llvm_unreachable("invalid job condition");
}
bool isCascadingJobAccordingToCondition(
const Job *const Cmd, const Job::Condition Condition,
const bool hasDependenciesFileName) const {
switch (Condition) {
case Job::Condition::Always:
case Job::Condition::NewlyAdded:
return Comp.getIncrementalBuildEnabled() && hasDependenciesFileName;
case Job::Condition::RunWithoutCascading:
case Job::Condition::CheckDependencies:
return false;
}
llvm_unreachable("invalid job condition");
}
void forEachOutOfDateExternalDependency(
function_ref<void(StringRef)> consumeExternalSwiftDeps) {
for (StringRef dependency : getExternalDependencies()) {
// If the dependency has been modified since the oldest built file,
// or if we can't stat it for some reason (perhaps it's been
// deleted?), trigger rebuilds through the dependency graph.
llvm::sys::fs::file_status depStatus;
if (llvm::sys::fs::status(dependency, depStatus) ||
Comp.getLastBuildTime() < depStatus.getLastModificationTime())
consumeExternalSwiftDeps(dependency);
}
}
CommandSet collectCascadedJobsFromDependencyGraph(
const CommandSet &InitialCascadingCommands) {
CommandSet CascadedJobs;
// We scheduled all of the files that have actually changed. Now add the
// files that haven't changed, so that they'll get built in parallel if
// possible and after the first set of files if it's not.
for (auto *Cmd : InitialCascadingCommands) {
for (const auto *transitiveCmd : findJobsToRecompileWhenWholeJobChanges(
Cmd))
CascadedJobs.insert(transitiveCmd);
}
noteBuildingJobs(CascadedJobs, "because of the initial set");
return CascadedJobs;
}
/// Return jobs dependent on other modules, and jobs dependent on those jobs
SmallVector<const Job *, 16>
collectExternallyDependentJobsFromDependencyGraph() {
SmallVector<const Job *, 16> ExternallyDependentJobs;
// Check all cross-module dependencies as well.
forEachOutOfDateExternalDependency([&](StringRef dependency) {
// If the dependency has been modified since the oldest built file,
// or if we can't stat it for some reason (perhaps it's been
// deleted?), trigger rebuilds through the dependency graph.
for (const Job * marked: markExternalInDepGraph(dependency))
ExternallyDependentJobs.push_back(marked);
});
noteBuildingJobs(ExternallyDependentJobs,
"because of external dependencies");
return ExternallyDependentJobs;
}
/// Insert all jobs in \p Cmds (of descriptive name \p Kind) to the \c
/// TaskQueue, and clear \p Cmds.
template <typename Container>
@@ -1407,22 +962,6 @@ namespace driver {
continue;
}
// If we got here, all the queued and pending work we know about is
// done; mark anything still in deferred state as skipped.
for (const Job *Cmd : DeferredCommands) {
if (Comp.getOutputLevel() == OutputLevel::Parseable) {
// Provide output indicating this command was skipped if parseable
// output was requested.
auto TaskDesc = constructDetailedTaskDescription(*Cmd);
parseable_output::emitSkippedMessage(llvm::errs(),
Cmd->getSource().getClassName(),
TaskDesc);
}
ScheduledCommands.insert(Cmd);
markFinished(Cmd, /*Skipped=*/true);
}
DeferredCommands.clear();
// It's possible that by marking some jobs as skipped, we unblocked
// some jobs and thus have entries in PendingExecution again; push
// those through to the TaskQueue.
@@ -1433,165 +972,18 @@ namespace driver {
} while (ResultCode == 0 && TQ->hasRemainingTasks());
}
void checkUnfinishedJobs() {
if (ResultCode == 0) {
assert(BlockingCommands.empty() &&
"some blocking commands never finished properly");
} else {
// Make sure we record any files that still need to be rebuilt.
for (const Job *Cmd : Comp.getJobs()) {
// Skip files that don't use dependency analysis.
bool shouldHaveOutput = false;
file_types::forEachIncrementalOutputType(
[&](const file_types::ID type) {
shouldHaveOutput |=
!Cmd->getOutput().getAdditionalOutputForType(type).empty();
});
if (!shouldHaveOutput)
continue;
// Don't worry about commands that finished or weren't going to run.
if (FinishedCommands.count(Cmd))
continue;
if (!ScheduledCommands.count(Cmd))
continue;
const bool needsCascadingBuild =
computeNeedsCascadingBuildForUnfinishedCommand(Cmd);
UnfinishedCommands.insert({Cmd, needsCascadingBuild});
}
}
}
/// When the driver next runs, it will read the build record, and the
/// unfinished job status will be set to either \c NeedsCascading... or
/// \c NeedsNonCascading...
/// Decide which it will be.
/// As far as I can tell, the only difference the result of this function
/// makes is how soon
/// required dependents are recompiled. Here's my reasoning:
///
/// When the driver next runs, the condition will be filtered through
/// \c loadDependenciesAndComputeCondition .
/// Then, the cascading predicate is returned from
/// \c isCompileJobInitiallyNeededForDependencyBasedIncrementalCompilation.
/// Then, in \c computeShouldInitiallyScheduleJobAndDependents
/// if the job needs a cascading build, it's dependents will be scheduled
/// immediately. After the job finishes, it's dependencies will be processed
/// again. If a non-cascading job failed, the driver will schedule all of
/// its dependents. (All of its dependents are assumed to have already been
/// scheduled.) If the job succeeds, the revised dependencies are consulted
/// to schedule any needed jobs.
bool computeNeedsCascadingBuildForUnfinishedCommand(const Job *Cmd) {
if (!Comp.getIncrementalBuildEnabled())
return true;
// See the comment on the whole function above
return false;
}
public:
void populateInputInfoMap(InputInfoMap &inputs) const {
for (auto &entry : UnfinishedCommands) {
for (auto *action : entry.first->getSource().getInputs()) {
auto inputFile = dyn_cast<InputAction>(action);
if (!inputFile)
continue;
CompileJobAction::InputInfo info;
info.previousModTime = entry.first->getInputModTime();
info.status = entry.second ?
CompileJobAction::InputInfo::Status::NeedsCascadingBuild :
CompileJobAction::InputInfo::Status::NeedsNonCascadingBuild;
inputs[&inputFile->getInputArg()] = info;
}
}
for (const Job *entry : FinishedCommands) {
const auto *compileAction = dyn_cast<CompileJobAction>(&entry->getSource());
if (!compileAction)
continue;
for (auto *action : compileAction->getInputs()) {
auto inputFile = dyn_cast<InputAction>(action);
if (!inputFile)
continue;
CompileJobAction::InputInfo info;
info.previousModTime = entry->getInputModTime();
info.status = CompileJobAction::InputInfo::Status::UpToDate;
inputs[&inputFile->getInputArg()] = info;
}
}
// Sort the entries by input order.
static_assert(IsTriviallyCopyable<CompileJobAction::InputInfo>::value,
"llvm::array_pod_sort relies on trivially-copyable data");
using InputInfoEntry = std::decay<decltype(inputs.front())>::type;
llvm::array_pod_sort(inputs.begin(), inputs.end(),
[](const InputInfoEntry *lhs,
const InputInfoEntry *rhs) -> int {
auto lhsIndex = lhs->first->getIndex();
auto rhsIndex = rhs->first->getIndex();
return (lhsIndex < rhsIndex) ? -1 : (lhsIndex > rhsIndex) ? 1 : 0;
});
}
Compilation::Result takeResult() && {
if (ResultCode == 0)
ResultCode = Comp.getDiags().hadAnyError();
const bool hadAbnormalExit = hadAnyAbnormalExit();
const auto resultCode = ResultCode;
auto &&graph = std::move(*this).takeFineGrainedDepGraph();
return Compilation::Result{hadAbnormalExit, resultCode, std::move(graph)};
return Compilation::Result{hadAbnormalExit, resultCode};
}
bool hadAnyAbnormalExit() {
return AnyAbnormalExit;
}
// MARK: dependency graph interface
std::vector<StringRef> getExternalDependencies() const {
return getFineGrainedDepGraph().getExternalDependencies();
}
std::vector<const Job*>
markExternalInDepGraph(StringRef externalDependency) {
return getFineGrainedDepGraph()
.findExternallyDependentUntracedJobs(externalDependency);
}
std::vector<const Job *> findJobsToRecompileWhenWholeJobChanges(const Job *Cmd) {
return getFineGrainedDepGraph()
.findJobsToRecompileWhenWholeJobChanges(Cmd);
}
void registerJobToDepGraph(const Job *Cmd) {
getFineGrainedDepGraph().registerJob(Cmd);
}
/// Return hadError
bool loadDepGraphFromPath(const Job *Cmd, const StringRef DependenciesFile) {
const auto changes = getFineGrainedDepGraph().loadFromPath(
Cmd, DependenciesFile, Comp.getDiags());
const bool didDependencyLoadSucceed = changes.has_value();
return !didDependencyLoadSucceed;
}
fine_grained_dependencies::ModuleDepGraph &
getFineGrainedDepGraph() {
return FineGrainedDepGraph;
}
const fine_grained_dependencies::ModuleDepGraph &
getFineGrainedDepGraph() const {
return FineGrainedDepGraph;
}
fine_grained_dependencies::ModuleDepGraph &&
takeFineGrainedDepGraph() && {
return std::move(FineGrainedDepGraph);
}
};
} // namespace driver
} // namespace swift
@@ -1610,83 +1002,6 @@ Job *Compilation::addExternalJob(std::unique_ptr<Job> J) {
return result;
}
static void checkForOutOfDateInputs(DiagnosticEngine &diags,
const InputInfoMap &inputs) {
for (const auto &inputPair : inputs) {
auto recordedModTime = inputPair.second.previousModTime;
if (recordedModTime == llvm::sys::TimePoint<>::max())
continue;
const char *input = inputPair.first->getValue();
llvm::sys::fs::file_status inputStatus;
if (auto statError = llvm::sys::fs::status(input, inputStatus)) {
diags.diagnose(SourceLoc(), diag::warn_cannot_stat_input,
llvm::sys::path::filename(input), statError.message());
continue;
}
if (recordedModTime != inputStatus.getLastModificationTime()) {
diags.diagnose(SourceLoc(), diag::error_input_changed_during_build,
llvm::sys::path::filename(input));
}
}
}
static void writeCompilationRecord(StringRef path, StringRef argsHash,
llvm::sys::TimePoint<> buildTime,
const InputInfoMap &inputs) {
// Before writing to the dependencies file path, preserve any previous file
// that may have been there. No error handling -- this is just a nicety, it
// doesn't matter if it fails.
llvm::sys::fs::rename(path, path + "~");
std::error_code error;
llvm::raw_fd_ostream out(path, error, llvm::sys::fs::OF_None);
if (out.has_error()) {
// FIXME: How should we report this error?
out.clear_error();
return;
}
auto writeTimeValue = [](llvm::raw_ostream &out,
llvm::sys::TimePoint<> time) {
using namespace std::chrono;
auto secs = time_point_cast<seconds>(time);
time -= secs.time_since_epoch(); // remainder in nanoseconds
out << "[" << secs.time_since_epoch().count()
<< ", " << time.time_since_epoch().count() << "]";
};
using compilation_record::TopLevelKey;
// NB: We calculate effective version from getCurrentLanguageVersion()
// here because any -swift-version argument is handled in the
// argsHash that follows.
out << compilation_record::getName(TopLevelKey::Version) << ": \""
<< llvm::yaml::escape(version::getSwiftFullVersion(
swift::version::Version::getCurrentLanguageVersion()))
<< "\"\n";
out << compilation_record::getName(TopLevelKey::Options) << ": \""
<< llvm::yaml::escape(argsHash) << "\"\n";
out << compilation_record::getName(TopLevelKey::BuildTime) << ": ";
writeTimeValue(out, buildTime);
out << "\n";
out << compilation_record::getName(TopLevelKey::Inputs) << ":\n";
for (auto &entry : inputs) {
out << " \"" << llvm::yaml::escape(entry.first->getValue()) << "\": ";
using compilation_record::getIdentifierForInputInfoStatus;
auto Name = getIdentifierForInputInfoStatus(entry.second.status);
if (!Name.empty()) {
out << Name << " ";
}
writeTimeValue(out, entry.second.previousModTime);
out << "\n";
}
}
static void writeInputJobsToFilelist(llvm::raw_fd_ostream &out, const Job *job,
const file_types::ID infoType) {
// FIXME: Duplicated from ToolChains.cpp.
@@ -1783,17 +1098,7 @@ static bool writeFilelistIfNecessary(const Job *job, const ArgList &args,
Compilation::Result
Compilation::performJobsImpl(std::unique_ptr<TaskQueue> &&TQ) {
PerformJobsState State(*this, std::move(TQ));
State.runJobs();
if (!CompilationRecordPath.empty()) {
InputInfoMap InputInfo;
State.populateInputInfoMap(InputInfo);
checkForOutOfDateInputs(Diags, InputInfo);
writeCompilationRecord(CompilationRecordPath, ArgsHash, BuildStartTime,
InputInfo);
}
return std::move(State).takeResult();
}
@@ -1880,7 +1185,6 @@ Compilation::Result Compilation::performJobs(std::unique_ptr<TaskQueue> &&TQ) {
if (Level < OutputLevel::Parseable &&
!ShowDriverTimeCompilation &&
(SaveTemps || TempFilePaths.empty()) &&
CompilationRecordPath.empty() &&
Jobs.size() == 1) {
return performSingleCommand(Jobs.front().get());
}
@@ -1923,13 +1227,6 @@ const char *Compilation::getAllSourcesPath() const {
return AllSourceFilesPath;
}
void Compilation::disableIncrementalBuild(Twine why) {
if (getShowIncrementalBuildDecisions())
llvm::outs() << "Disabling incremental build: " << why << "\n";
EnableIncrementalBuild = false;
}
unsigned Compilation::countSwiftInputs() const {
unsigned inputCount = 0;
for (const auto &p : InputFilesWithTypes)

View File

@@ -1,91 +0,0 @@
//===--- CompilationRecord.h ------------------------------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_DRIVER_COMPILATIONRECORD_H
#define SWIFT_DRIVER_COMPILATIONRECORD_H
#include "swift/Driver/Action.h"
namespace swift {
namespace driver {
namespace compilation_record {
/// Compilation record files (-master.swiftdeps files) are YAML files composed
/// of these top-level keys.
enum class TopLevelKey {
/// The key for the Swift compiler version used to produce the compilation
/// record.
Version,
/// The key for the list of arguments passed to the Swift compiler when
/// producing the compilation record.
Options,
/// The key for the time at which the build that produced the compilation
/// record started.
BuildTime,
/// The key for the list of inputs to the compilation that produced the
/// compilation record.
Inputs,
};
/// \returns A string representation of the given key.
inline static StringRef getName(TopLevelKey Key) {
switch (Key) {
case TopLevelKey::Version: return "version";
case TopLevelKey::Options: return "options";
case TopLevelKey::BuildTime: return "build_time";
case TopLevelKey::Inputs: return "inputs";
}
// Work around MSVC warning: not all control paths return a value
llvm_unreachable("All switch cases are covered");
}
/// \returns The string identifier used to represent the given status in a
/// compilation record file (.swiftdeps file).
///
/// \note Not every InputInfo::Status has a unique identifier. For example,
/// both NewlyAdded and NeedsCascadingBuild are represented as "!dirty".
/// Therefore, this will not cleanly round-trip between InputInfo::Status and
/// string identifiers.
inline static StringRef
getIdentifierForInputInfoStatus(CompileJobAction::InputInfo::Status Status) {
switch (Status) {
case CompileJobAction::InputInfo::Status::UpToDate:
return "";
case CompileJobAction::InputInfo::Status::NewlyAdded:
case CompileJobAction::InputInfo::Status::NeedsCascadingBuild:
return "!dirty";
case CompileJobAction::InputInfo::Status::NeedsNonCascadingBuild:
return "!private";
}
// Work around MSVC warning: not all control paths return a value
llvm_unreachable("All switch cases are covered");
}
/// \returns The status corresponding to the string identifier used in a
/// compilation record file (.swiftdeps file).
inline static llvm::Optional<CompileJobAction::InputInfo::Status>
getInfoStatusForIdentifier(StringRef Identifier) {
using InputStatus = CompileJobAction::InputInfo::Status;
return llvm::StringSwitch<llvm::Optional<InputStatus>>(Identifier)
.Case("", InputStatus::UpToDate)
.Case("!dirty", InputStatus::NeedsCascadingBuild)
.Case("!private", InputStatus::NeedsNonCascadingBuild)
.Default(llvm::None);
}
} // end namespace compilation_record
} // end namespace driver
} // end namespace swift
#endif

View File

@@ -57,8 +57,6 @@
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/raw_ostream.h"
#include "CompilationRecord.h"
#include <memory>
using namespace swift;
@@ -136,6 +134,14 @@ ArrayRef<const char *> Driver::getArgsWithoutProgramNameAndDriverMode(
return Args;
}
static void validateLegacyUnsupportedArgs(DiagnosticEngine &diags,
const ArgList &args) {
if (args.hasArg(options::OPT_incremental)) {
diags.diagnose({}, diag::warning_unsupported_driver_option, "-incremental");
}
return;
}
static void validateBridgingHeaderArgs(DiagnosticEngine &diags,
const ArgList &args) {
if (!args.hasArgNoClaim(options::OPT_import_objc_header))
@@ -246,24 +252,6 @@ static void validateDebugInfoArgs(DiagnosticEngine &diags,
}
}
static void validateVerifyIncrementalDependencyArgs(DiagnosticEngine &diags,
const ArgList &args) {
// No option? No problem!
if (!args.hasArg(options::OPT_verify_incremental_dependencies)) {
return;
}
// Make sure we see -incremental but not -wmo, no matter in what order they're
// in - the build systems can pass them both and just hope the last one wins.
if (args.hasArg(options::OPT_incremental) &&
!args.hasArg(options::OPT_whole_module_optimization)) {
return;
}
diags.diagnose(SourceLoc(),
diag::verify_incremental_dependencies_needs_incremental);
}
static void validateCompilationConditionArgs(DiagnosticEngine &diags,
const ArgList &args) {
for (const Arg *A : args.filtered(options::OPT_D)) {
@@ -318,6 +306,7 @@ static void validateLinkArgs(DiagnosticEngine &diags, const ArgList &args) {
/// Perform miscellaneous early validation of arguments.
static void validateArgs(DiagnosticEngine &diags, const ArgList &args,
const llvm::Triple &T) {
validateLegacyUnsupportedArgs(diags, args);
validateBridgingHeaderArgs(diags, args);
validateWarningControlArgs(diags, args);
validateProfilingArgs(diags, args);
@@ -325,7 +314,6 @@ static void validateArgs(DiagnosticEngine &diags, const ArgList &args,
validateDebugInfoArgs(diags, args);
validateCompilationConditionArgs(diags, args);
validateSearchPathArgs(diags, args);
validateVerifyIncrementalDependencyArgs(diags, args);
validateLinkArgs(diags, args);
}
@@ -416,325 +404,6 @@ std::unique_ptr<sys::TaskQueue> Driver::buildTaskQueue(const Compilation &C) {
}
}
static void computeArgsHash(SmallString<32> &out, const DerivedArgList &args) {
SmallVector<const Arg *, 32> interestingArgs;
interestingArgs.reserve(args.size());
std::copy_if(args.begin(), args.end(), std::back_inserter(interestingArgs),
[](const Arg *arg) {
return !arg->getOption().hasFlag(options::DoesNotAffectIncrementalBuild) &&
arg->getOption().getKind() != Option::InputClass;
});
llvm::array_pod_sort(interestingArgs.begin(), interestingArgs.end(),
[](const Arg * const *lhs, const Arg * const *rhs)->int {
auto cmpID = (*lhs)->getOption().getID() - (*rhs)->getOption().getID();
if (cmpID != 0)
return cmpID;
return (*lhs)->getIndex() - (*rhs)->getIndex();
});
llvm::MD5 hash;
for (const Arg *arg : interestingArgs) {
hash.update(arg->getOption().getID());
for (const char *value : const_cast<Arg *>(arg)->getValues())
hash.update(value);
}
llvm::MD5::MD5Result hashBuf;
hash.final(hashBuf);
llvm::MD5::stringifyResult(hashBuf, out);
}
class Driver::InputInfoMap
: public llvm::SmallDenseMap<const Arg *, CompileJobAction::InputInfo, 16> {
};
using InputInfoMap = Driver::InputInfoMap;
/// Get the filename for build record. Returns true if failed.
static bool getCompilationRecordPath(std::string &buildRecordPath,
const OutputInfo &OI,
const llvm::Optional<OutputFileMap> &OFM,
DiagnosticEngine *Diags) {
if (!OFM) {
// FIXME: This should work without an output file map. We should have
// another way to specify a build record and where to put intermediates.
if (Diags)
Diags->diagnose(SourceLoc(), diag::incremental_requires_output_file_map);
return true;
}
if (auto *masterOutputMap = OFM->getOutputMapForSingleOutput())
buildRecordPath = masterOutputMap->lookup(file_types::TY_SwiftDeps);
if (buildRecordPath.empty()) {
if (Diags)
Diags->diagnose(SourceLoc(),
diag::incremental_requires_build_record_entry,
file_types::getTypeName(file_types::TY_SwiftDeps));
return true;
}
return false;
}
static std::string failedToReadOutOfDateMap(bool ShowIncrementalBuildDecisions,
StringRef buildRecordPath,
StringRef reason = "") {
std::string why = "malformed build record file";
if (!reason.empty()) {
why += " ";
why += reason;
}
if (ShowIncrementalBuildDecisions) {
llvm::outs() << "Incremental compilation has been disabled due to " << why
<< " '" << buildRecordPath << "'.\n";
}
return why;
}
static SmallVector<StringRef, 8> findRemovedInputs(
const InputFileList &inputs,
const llvm::StringMap<CompileJobAction::InputInfo> &previousInputs);
static void dealWithRemovedInputs(ArrayRef<StringRef> removedInputs,
bool ShowIncrementalBuildDecisions);
/// Returns why ignore incrementality
static std::string
populateOutOfDateMap(InputInfoMap &map, llvm::sys::TimePoint<> &LastBuildTime,
StringRef argsHashStr, const InputFileList &inputs,
StringRef buildRecordPath,
const bool ShowIncrementalBuildDecisions) {
// Treat a missing file as "no previous build".
auto buffer = llvm::MemoryBuffer::getFile(buildRecordPath);
if (!buffer) {
if (ShowIncrementalBuildDecisions)
llvm::outs() << "Incremental compilation could not read build record.\n";
return "could not read build record";
}
namespace yaml = llvm::yaml;
using InputInfo = CompileJobAction::InputInfo;
llvm::SourceMgr SM;
yaml::Stream stream(buffer.get()->getMemBufferRef(), SM);
auto I = stream.begin();
if (I == stream.end() || !I->getRoot())
return failedToReadOutOfDateMap(ShowIncrementalBuildDecisions,
buildRecordPath);
auto *topLevelMap = dyn_cast<yaml::MappingNode>(I->getRoot());
if (!topLevelMap)
return failedToReadOutOfDateMap(ShowIncrementalBuildDecisions,
buildRecordPath);
SmallString<64> scratch;
llvm::StringMap<InputInfo> previousInputs;
bool versionValid = false;
bool optionsMatch = true;
auto readTimeValue = [&scratch](yaml::Node *node,
llvm::sys::TimePoint<> &timeValue) -> bool {
auto *seq = dyn_cast<yaml::SequenceNode>(node);
if (!seq)
return true;
auto seqI = seq->begin(), seqE = seq->end();
if (seqI == seqE)
return true;
auto *secondsRaw = dyn_cast<yaml::ScalarNode>(&*seqI);
if (!secondsRaw)
return true;
std::time_t parsedSeconds;
if (secondsRaw->getValue(scratch).getAsInteger(10, parsedSeconds))
return true;
++seqI;
if (seqI == seqE)
return true;
auto *nanosecondsRaw = dyn_cast<yaml::ScalarNode>(&*seqI);
if (!nanosecondsRaw)
return true;
std::chrono::system_clock::rep parsedNanoseconds;
if (nanosecondsRaw->getValue(scratch).getAsInteger(10, parsedNanoseconds))
return true;
++seqI;
if (seqI != seqE)
return true;
timeValue = llvm::sys::TimePoint<>(std::chrono::seconds(parsedSeconds));
timeValue += std::chrono::nanoseconds(parsedNanoseconds);
return false;
};
// FIXME: LLVM's YAML support does incremental parsing in such a way that
// for-range loops break.
SmallString<64> CompilationRecordSwiftVersion;
for (auto i = topLevelMap->begin(), e = topLevelMap->end(); i != e; ++i) {
auto *key = cast<yaml::ScalarNode>(i->getKey());
StringRef keyStr = key->getValue(scratch);
using compilation_record::TopLevelKey;
if (keyStr == compilation_record::getName(TopLevelKey::Version)) {
auto *value = dyn_cast<yaml::ScalarNode>(i->getValue());
if (!value) {
auto reason = ("Malformed value for key '" + keyStr + "'.")
.toStringRef(scratch);
return failedToReadOutOfDateMap(ShowIncrementalBuildDecisions,
buildRecordPath, reason);
}
// NB: We check against
// swift::version::Version::getCurrentLanguageVersion() here because any
// -swift-version argument is handled in the argsHashStr check that
// follows.
CompilationRecordSwiftVersion = value->getValue(scratch);
versionValid = (CompilationRecordSwiftVersion
== version::getSwiftFullVersion(
version::Version::getCurrentLanguageVersion()));
} else if (keyStr == compilation_record::getName(TopLevelKey::Options)) {
auto *value = dyn_cast<yaml::ScalarNode>(i->getValue());
if (!value)
return "no name node in build record";
optionsMatch = (argsHashStr == value->getValue(scratch));
} else if (keyStr == compilation_record::getName(TopLevelKey::BuildTime)) {
auto *value = dyn_cast<yaml::SequenceNode>(i->getValue());
if (!value) {
auto reason = ("Malformed value for key '" + keyStr + "'.")
.toStringRef(scratch);
return failedToReadOutOfDateMap(ShowIncrementalBuildDecisions,
buildRecordPath, reason);
}
llvm::sys::TimePoint<> timeVal;
if (readTimeValue(i->getValue(), timeVal))
return "could not read time value in build record";
LastBuildTime = timeVal;
} else if (keyStr == compilation_record::getName(TopLevelKey::Inputs)) {
auto *inputMap = dyn_cast<yaml::MappingNode>(i->getValue());
if (!inputMap) {
auto reason = ("Malformed value for key '" + keyStr + "'.")
.toStringRef(scratch);
return failedToReadOutOfDateMap(ShowIncrementalBuildDecisions,
buildRecordPath, reason);
}
// FIXME: LLVM's YAML support does incremental parsing in such a way that
// for-range loops break.
for (auto i = inputMap->begin(), e = inputMap->end(); i != e; ++i) {
auto *key = dyn_cast<yaml::ScalarNode>(i->getKey());
if (!key)
return "no input entry in build record";
auto *value = dyn_cast<yaml::SequenceNode>(i->getValue());
if (!value)
return "no sequence node for input entry in build record";
using compilation_record::getInfoStatusForIdentifier;
auto previousBuildState =
getInfoStatusForIdentifier(value->getRawTag());
if (!previousBuildState)
return "no previous build state in build record";
llvm::sys::TimePoint<> timeValue;
if (readTimeValue(value, timeValue))
return "could not read time value in build record";
auto inputName = key->getValue(scratch);
previousInputs[inputName] = { *previousBuildState, timeValue };
}
}
}
if (!versionValid) {
if (ShowIncrementalBuildDecisions) {
auto v = version::getSwiftFullVersion(
version::Version::getCurrentLanguageVersion());
llvm::outs() << "Incremental compilation has been disabled, due to a "
<< "compiler version mismatch.\n"
<< "\tCompiling with: " << v << "\n"
<< "\tPreviously compiled with: "
<< CompilationRecordSwiftVersion << "\n";
}
return "compiler version mismatch";
}
if (!optionsMatch) {
if (ShowIncrementalBuildDecisions) {
llvm::outs() << "Incremental compilation has been disabled, because "
<< "different arguments were passed to the compiler.\n";
}
return "different arguments passed to compiler";
}
unsigned numMatchingPreviouslyCompiledInputs = 0;
for (auto &inputPair : inputs) {
auto iter = previousInputs.find(inputPair.second->getValue());
if (iter == previousInputs.end())
map[inputPair.second] = CompileJobAction::InputInfo::makeNewlyAdded();
else {
map[inputPair.second] = iter->getValue();
++numMatchingPreviouslyCompiledInputs;
}
}
assert(numMatchingPreviouslyCompiledInputs <= previousInputs.size());
auto const wereAnyInputsRemoved =
numMatchingPreviouslyCompiledInputs < previousInputs.size();
if (!wereAnyInputsRemoved)
return "";
const auto removedInputs = findRemovedInputs(inputs, previousInputs);
assert(!removedInputs.empty());
dealWithRemovedInputs(removedInputs, ShowIncrementalBuildDecisions);
return "an input was removed"; // recompile everything; could do better
// someday
}
static SmallVector<StringRef, 8> findRemovedInputs(
const InputFileList &inputs,
const llvm::StringMap<CompileJobAction::InputInfo> &previousInputs) {
llvm::DenseSet<StringRef> inputArgs;
for (auto &inputPair : inputs) {
inputArgs.insert(inputPair.second->getValue());
}
SmallVector<StringRef, 8> missingInputs;
for (auto &previousInput : previousInputs) {
auto previousInputArg = previousInput.getKey();
if (!inputArgs.contains(previousInputArg)) {
missingInputs.push_back(previousInputArg);
}
}
return missingInputs;
}
static void showRemovedInputs(ArrayRef<StringRef> removedInputs);
/// Return true if hadError
static void dealWithRemovedInputs(ArrayRef<StringRef> removedInputs,
const bool ShowIncrementalBuildDecisions) {
// If a file was removed, we've lost its dependency info. Rebuild everything.
// FIXME: Can we do better?
if (ShowIncrementalBuildDecisions)
showRemovedInputs(removedInputs);
}
static void showRemovedInputs(ArrayRef<StringRef> removedInputs) {
llvm::outs() << "Incremental compilation has been disabled, because "
<< "the following inputs were used in the previous "
<< "compilation, but not in the current compilation:\n";
for (auto &missing : removedInputs)
llvm::outs() << "\t" << missing << "\n";
}
// warn if -embed-bitcode is set and the output type is not an object
static void validateEmbedBitcode(DerivedArgList &Args, const OutputInfo &OI,
DiagnosticEngine &Diags) {
@@ -803,31 +472,6 @@ getDriverBatchCount(llvm::opt::InputArgList &ArgList, DiagnosticEngine &Diags) {
return llvm::None;
}
static bool computeIncremental(const llvm::opt::InputArgList *ArgList,
const bool ShowIncrementalBuildDecisions) {
if (!ArgList->hasArg(options::OPT_incremental))
return false;
const char *ReasonToDisable =
ArgList->hasFlag(options::OPT_whole_module_optimization,
options::OPT_no_whole_module_optimization,
false)
? "is not compatible with whole module optimization."
: ArgList->hasArg(options::OPT_embed_bitcode)
? "is not currently compatible with embedding LLVM IR bitcode."
: nullptr;
if (!ReasonToDisable)
return true;
if (ShowIncrementalBuildDecisions) {
llvm::outs() << "Incremental compilation has been disabled, because it "
<< ReasonToDisable
<< "\n";
}
return false;
}
static std::string
computeWorkingDirectory(const llvm::opt::InputArgList *ArgList) {
if (auto *A = ArgList->getLastArg(options::OPT_working_directory)) {
@@ -907,8 +551,6 @@ Driver::buildCompilation(const ToolChain &TC,
bool AllowErrors) {
llvm::PrettyStackTraceString CrashInfo("Compilation construction");
llvm::sys::TimePoint<> StartTime = std::chrono::system_clock::now();
// Claim --driver-mode here, since it's already been handled.
(void) ArgList->hasArg(options::OPT_driver_mode);
@@ -976,29 +618,6 @@ Driver::buildCompilation(const ToolChain &TC,
}
}
const bool ShowIncrementalBuildDecisions =
ArgList->hasArg(options::OPT_driver_show_incremental);
const bool Incremental =
computeIncremental(ArgList.get(), ShowIncrementalBuildDecisions);
std::string buildRecordPath;
getCompilationRecordPath(buildRecordPath,
OI, OFM, Incremental ? &Diags : nullptr);
SmallString<32> ArgsHash;
computeArgsHash(ArgsHash, *TranslatedArgList);
llvm::sys::TimePoint<> LastBuildTime = llvm::sys::TimePoint<>::min();
InputInfoMap outOfDateMap;
std::string whyIgnoreIncrementality =
!Incremental
? ""
: buildRecordPath.empty()
? "no build record path"
: populateOutOfDateMap(outOfDateMap, LastBuildTime, ArgsHash,
Inputs, buildRecordPath,
ShowIncrementalBuildDecisions);
// FIXME: Distinguish errors from "file removed", which is benign.
size_t DriverFilelistThreshold;
if (getFilelistThreshold(*TranslatedArgList, DriverFilelistThreshold, Diags))
return nullptr;
@@ -1049,28 +668,13 @@ Driver::buildCompilation(const ToolChain &TC,
ArgList->hasFlag(options::OPT_enable_only_one_dependency_file,
options::OPT_disable_only_one_dependency_file, false);
const bool VerifyFineGrainedDependencyGraphAfterEveryImport = ArgList->hasArg(
options::
OPT_driver_verify_fine_grained_dependency_graph_after_every_import);
const bool EmitFineGrainedDependencyDotFileAfterEveryImport = ArgList->hasArg(
options::
OPT_driver_emit_fine_grained_dependency_dot_file_after_every_import);
const bool EnableCrossModuleDependencies
= ArgList->hasArg(options::OPT_enable_incremental_imports,
options::OPT_disable_incremental_imports, true);
// clang-format off
C = std::make_unique<Compilation>(
Diags, TC, OI, Level,
std::move(ArgList),
std::move(TranslatedArgList),
std::move(Inputs),
buildRecordPath,
ArgsHash,
StartTime,
LastBuildTime,
DriverFilelistThreshold,
Incremental,
BatchMode,
DriverBatchSeed,
DriverBatchCount,
@@ -1078,17 +682,13 @@ Driver::buildCompilation(const ToolChain &TC,
SaveTemps,
ShowDriverTimeCompilation,
std::move(StatsReporter),
OnlyOneDependencyFile,
VerifyFineGrainedDependencyGraphAfterEveryImport,
EmitFineGrainedDependencyDotFileAfterEveryImport,
EnableCrossModuleDependencies);
OnlyOneDependencyFile);
// clang-format on
}
// Construct the graph of Actions.
SmallVector<const Action *, 8> TopLevelActions;
buildActions(TopLevelActions, TC, OI,
whyIgnoreIncrementality.empty() ? &outOfDateMap : nullptr, *C);
buildActions(TopLevelActions, TC, OI, *C);
if (Diags.hadAnyError() && !AllowErrors)
return nullptr;
@@ -1111,17 +711,9 @@ Driver::buildCompilation(const ToolChain &TC,
if (ContinueBuildingAfterErrors)
C->setContinueBuildingAfterErrors();
if (ShowIncrementalBuildDecisions || ShowJobLifecycle)
C->setShowIncrementalBuildDecisions();
if (ShowJobLifecycle)
C->setShowJobLifecycle();
// This has to happen after building jobs, because otherwise we won't even
// emit .swiftdeps files for the next build.
if (!whyIgnoreIncrementality.empty())
C->disableIncrementalBuild(whyIgnoreIncrementality);
if (Diags.hadAnyError() && !AllowErrors)
return nullptr;
@@ -1936,32 +1528,13 @@ namespace {
/// mode.
class ModuleInputs final {
private:
using InputInfo = IncrementalJobAction::InputInfo;
SmallVector<const Action *, 2> AllModuleInputs;
InputInfo StatusBound;
public:
explicit ModuleInputs()
: StatusBound
{InputInfo::Status::UpToDate, llvm::sys::TimePoint<>::min()} {}
explicit ModuleInputs() {}
public:
void addInput(const Action *inputAction) {
if (auto *IJA = dyn_cast<IncrementalJobAction>(inputAction)) {
// Take the upper bound of the status of any incremental inputs to
// ensure that the merge-modules job gets run if *any* input job is run.
const auto conservativeStatus =
std::max(StatusBound.status, IJA->getInputInfo().status);
// The modification time here is not important to the rest of the
// incremental build. We take the upper bound in case an attempt to
// compare the swiftmodule output's mod time and any input files is
// made. If the compilation has been correctly scheduled, the
// swiftmodule's mod time will always strictly exceed the mod time of
// any of its inputs when we are able to skip it.
const auto conservativeModTime = std::max(
StatusBound.previousModTime, IJA->getInputInfo().previousModTime);
StatusBound = InputInfo{conservativeStatus, conservativeModTime};
}
AllModuleInputs.push_back(inputAction);
}
@@ -1973,14 +1546,13 @@ public:
/// Consumes this \c ModuleInputs instance and returns a merge-modules action
/// from the list of input actions and status it has computed thus far.
JobAction *intoAction(Compilation &C) && {
return C.createAction<MergeModuleJobAction>(AllModuleInputs, StatusBound);
return C.createAction<MergeModuleJobAction>(AllModuleInputs);
}
};
} // namespace
void Driver::buildActions(SmallVectorImpl<const Action *> &TopLevelActions,
const ToolChain &TC, const OutputInfo &OI,
const InputInfoMap *OutOfDateMap,
Compilation &C) const {
const DerivedArgList &Args = C.getArgs();
ArrayRef<InputPair> Inputs = C.getInputFiles();
@@ -2030,14 +1602,9 @@ void Driver::buildActions(SmallVectorImpl<const Action *> &TopLevelActions,
case file_types::TY_SIB: {
// Source inputs always need to be compiled.
assert(file_types::isPartOfSwiftCompilation(InputType));
auto previousBuildState =
IncrementalJobAction::InputInfo::makeNeedsCascadingRebuild();
if (OutOfDateMap)
previousBuildState = OutOfDateMap->lookup(InputArg);
if (Args.hasArg(options::OPT_embed_bitcode)) {
Current = C.createAction<CompileJobAction>(
Current, file_types::TY_LLVM_BC, previousBuildState);
Current, file_types::TY_LLVM_BC);
if (PCH)
cast<JobAction>(Current)->addInput(PCH);
AllModuleInputs.addInput(Current);
@@ -2045,8 +1612,7 @@ void Driver::buildActions(SmallVectorImpl<const Action *> &TopLevelActions,
OI.CompilerOutputType, 0);
} else {
Current = C.createAction<CompileJobAction>(Current,
OI.CompilerOutputType,
previousBuildState);
OI.CompilerOutputType);
if (PCH)
cast<JobAction>(Current)->addInput(PCH);
AllModuleInputs.addInput(Current);
@@ -2848,60 +2414,6 @@ static void addDiagFileOutputForPersistentPCHAction(
}
}
/// If the file at \p input has not been modified since the last build (i.e. its
/// mtime has not changed), adjust the Job's condition accordingly.
static void handleCompileJobCondition(Job *J,
CompileJobAction::InputInfo inputInfo,
llvm::Optional<StringRef> input,
bool alwaysRebuildDependents) {
using InputStatus = CompileJobAction::InputInfo::Status;
if (inputInfo.status == InputStatus::NewlyAdded) {
J->setCondition(Job::Condition::NewlyAdded);
return;
}
auto output = J->getOutput().getPrimaryOutputFilename();
bool hasValidModTime = false;
llvm::sys::fs::file_status inputStatus;
if (input.has_value() && !llvm::sys::fs::status(*input, inputStatus)) {
J->setInputModTime(inputStatus.getLastModificationTime());
hasValidModTime = J->getInputModTime() == inputInfo.previousModTime;
} else if (!llvm::sys::fs::status(output, inputStatus)) {
J->setInputModTime(inputStatus.getLastModificationTime());
hasValidModTime = true;
}
Job::Condition condition;
if (hasValidModTime) {
switch (inputInfo.status) {
case InputStatus::UpToDate:
if (llvm::sys::fs::exists(output))
condition = Job::Condition::CheckDependencies;
else
condition = Job::Condition::RunWithoutCascading;
break;
case InputStatus::NeedsCascadingBuild:
condition = Job::Condition::Always;
break;
case InputStatus::NeedsNonCascadingBuild:
condition = Job::Condition::RunWithoutCascading;
break;
case InputStatus::NewlyAdded:
llvm_unreachable("handled above");
}
} else {
if (alwaysRebuildDependents ||
inputInfo.status == InputStatus::NeedsCascadingBuild) {
condition = Job::Condition::Always;
} else {
condition = Job::Condition::RunWithoutCascading;
}
}
J->setCondition(condition);
}
Job *Driver::buildJobsForAction(Compilation &C, const JobAction *JA,
const OutputFileMap *OFM,
StringRef workingDirectory,
@@ -3053,23 +2565,6 @@ Job *Driver::buildJobsForAction(Compilation &C, const JobAction *JA,
std::move(Output), OI);
Job *J = C.addJob(std::move(ownedJob));
// If we track dependencies for this job, we may be able to avoid running it.
if (auto incrementalJob = dyn_cast<IncrementalJobAction>(JA)) {
const bool alwaysRebuildDependents =
C.getArgs().hasArg(options::OPT_driver_always_rebuild_dependents);
if (!J->getOutput()
.getAdditionalOutputForType(file_types::TY_SwiftDeps)
.empty()) {
if (InputActions.size() == 1) {
handleCompileJobCondition(J, incrementalJob->getInputInfo(), BaseInput,
alwaysRebuildDependents);
}
} else if (isa<MergeModuleJobAction>(JA)) {
handleCompileJobCondition(J, incrementalJob->getInputInfo(), llvm::None,
alwaysRebuildDependents);
}
}
// 5. Add it to the JobCache, so we don't construct the same Job multiple
// times.
JobCache[Key] = J;
@@ -3436,12 +2931,6 @@ void Driver::chooseDependenciesOutputPaths(Compilation &C,
workingDirectory);
});
}
if (C.getIncrementalBuildEnabled()) {
file_types::forEachIncrementalOutputType([&](file_types::ID type) {
if (type == file_types::TY_SwiftDeps)
addAuxiliaryOutput(C, *Output, type, OutputMap, workingDirectory);
});
}
chooseLoadedModuleTracePath(C, workingDirectory, Buf, Output);
}

View File

@@ -1,739 +0,0 @@
//===--- FineGrainedDependencyGraph.cpp ------------------------------------==//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "swift/Driver/FineGrainedDependencyDriverGraph.h"
// Next two includes needed for reporting errors opening dot file for writing.
#include "swift/AST/DiagnosticEngine.h"
#include "swift/AST/DiagnosticsFrontend.h"
#include "swift/AST/FileSystem.h"
#include "swift/Basic/PrettyStackTrace.h"
#include "swift/Basic/ReferenceDependencyKeys.h"
#include "swift/Basic/SourceManager.h"
#include "swift/Basic/Statistic.h"
#include "swift/Demangling/Demangle.h"
#include "swift/Driver/Job.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/VirtualOutputBackend.h"
#include "llvm/Support/YAMLParser.h"
#include "llvm/Support/raw_ostream.h"
#include <unordered_set>
// Definitions for the portion fine-grained dependency system used by the
// driver.
using namespace swift;
using namespace swift::fine_grained_dependencies;
using namespace swift::driver;
//==============================================================================
// MARK: Affordances to unit tests
//==============================================================================
LLVM_ATTRIBUTE_UNUSED
std::vector<const Job *>
ModuleDepGraph::printJobsForDebugging(const std::vector<const Job *> &jobs) {
llvm::errs() << "\nprintForDebugging: ";
for (auto *j : jobs) {
const auto swiftDeps =
j->getOutput().getAdditionalOutputForType(file_types::TY_SwiftDeps);
assert(!swiftDeps.empty());
llvm::errs() << "job" << swiftDeps << ", ";
}
llvm::errs() << "\n";
return jobs;
}
//==============================================================================
// MARK: Interfacing to Compilation
//==============================================================================
ModuleDepGraph::Changes ModuleDepGraph::loadFromPath(const Job *Cmd,
StringRef path,
DiagnosticEngine &diags) {
FrontendStatsTracer tracer(stats, "fine-grained-dependencies-loadFromPath");
PrettyStackTraceStringAction stackTrace("loading fine-grained dependency graph", path);
if (driverDotFileBasePath.empty()) {
driverDotFileBasePath = path;
llvm::sys::path::remove_filename(driverDotFileBasePath);
llvm::sys::path::append(driverDotFileBasePath, "driver");
}
auto buffer = llvm::MemoryBuffer::getFile(path);
if (!buffer)
return llvm::None;
auto r = loadFromBuffer(Cmd, *buffer.get(), diags);
assert(path == getSwiftDeps(Cmd) && "Should be reading the job's swiftdeps");
assert(!r || !nodeMap[path.str()].empty() &&
"Must have a node for the whole file");
return r;
}
/// Returns None for error or a set of changed keys
ModuleDepGraph::Changes
ModuleDepGraph::loadFromBuffer(const Job *job, llvm::MemoryBuffer &buffer,
DiagnosticEngine &diags) {
llvm::Optional<SourceFileDepGraph> sourceFileDepGraph =
SourceFileDepGraph::loadFromBuffer(buffer);
if (!sourceFileDepGraph)
return llvm::None;
return loadFromSourceFileDepGraph(job, sourceFileDepGraph.value(), diags);
}
ModuleDepGraph::Changes ModuleDepGraph::loadFromSourceFileDepGraph(
const Job *job, const SourceFileDepGraph &sourceFileDepGraph,
DiagnosticEngine &diags) {
registerJob(job);
auto changes = integrate(sourceFileDepGraph, getSwiftDeps(job));
if (verifyFineGrainedDependencyGraphAfterEveryImport)
verify();
if (emitFineGrainedDependencyDotFileAfterEveryImport)
emitDotFileForJob(diags, job);
return changes;
}
ModuleDepGraph::Changes ModuleDepGraph::loadFromSwiftModuleBuffer(
const Job *Cmd, llvm::MemoryBuffer &buffer, DiagnosticEngine &diags) {
FrontendStatsTracer tracer(
stats, "fine-grained-dependencies-loadFromSwiftModuleBuffer");
PrettyStackTraceStringAction stackTrace(
"loading fine-grained dependency graph from swiftmodule",
buffer.getBufferIdentifier());
llvm::Optional<SourceFileDepGraph> sourceFileDepGraph =
SourceFileDepGraph::loadFromSwiftModuleBuffer(buffer);
if (!sourceFileDepGraph)
return llvm::None;
jobsBySwiftDeps[buffer.getBufferIdentifier().str()] = Cmd;
auto changes = integrate(*sourceFileDepGraph, buffer.getBufferIdentifier());
if (verifyFineGrainedDependencyGraphAfterEveryImport)
verify();
if (emitFineGrainedDependencyDotFileAfterEveryImport)
emitDotFileForJob(diags, Cmd);
return changes;
}
bool ModuleDepGraph::haveAnyNodesBeenTraversedIn(const Job *cmd) const {
std::string swiftDeps = getSwiftDeps(cmd).str();
// optimization
const auto fileKey = DependencyKey::createKeyForWholeSourceFile(
DeclAspect::interface, swiftDeps);
if (const auto fileNode = nodeMap.find(swiftDeps, fileKey)) {
if (fileNode && fileNode.value()->getHasBeenTraced())
return true;
}
bool result = false;
forEachNodeInJob(swiftDeps, [&](const ModuleDepGraphNode *n) {
if (n->getHasBeenTraced())
result = true;
});
return result;
}
std::vector<const Job *> ModuleDepGraph::findJobsToRecompileWhenWholeJobChanges(
const Job *jobToBeRecompiled) {
std::vector<ModuleDepGraphNode *> allNodesInJob;
forEachNodeInJob(getSwiftDeps(jobToBeRecompiled),
[&](ModuleDepGraphNode *n) { allNodesInJob.push_back(n); });
return findJobsToRecompileWhenNodesChange(allNodesInJob);
}
std::vector<std::string> ModuleDepGraph::computeSwiftDepsFromNodes(
ArrayRef<const ModuleDepGraphNode *> nodes) const {
llvm::StringSet<> swiftDepsOfNodes;
for (const ModuleDepGraphNode *n : nodes) {
if (!n->getIsProvides())
continue;
const std::string &swiftDeps = n->getSwiftDepsOfProvides();
swiftDepsOfNodes.insert(swiftDeps);
}
std::vector<std::string> swiftDepsVec;
for (const auto &entry : swiftDepsOfNodes)
swiftDepsVec.push_back(entry.getKey().str());
return swiftDepsVec;
}
std::vector<const Job *> ModuleDepGraph::jobsContaining(
ArrayRef<const ModuleDepGraphNode *> nodes) const {
std::vector<const Job *> jobs;
for (StringRef swiftDeps : computeSwiftDepsFromNodes(nodes))
jobs.push_back(getJob(swiftDeps.str()));
return jobs;
}
void ModuleDepGraph::registerJob(const Job *job) {
// No need to create any nodes; that will happen when the swiftdeps file is
// read. Just record the correspondence.
jobsBySwiftDeps.insert(std::make_pair(getSwiftDeps(job).str(), job));
}
std::vector<const Job *> ModuleDepGraph::getAllJobs() const {
std::vector<const Job *> jobs;
for (auto const &entry : jobsBySwiftDeps)
jobs.push_back(entry.second);
return jobs;
}
std::vector<StringRef> ModuleDepGraph::getExternalDependencies() const {
return std::vector<StringRef>(externalDependencies.begin(),
externalDependencies.end());
}
// Add every (swiftdeps) use of the external dependency to foundJobs.
// Can return duplicates, but it doesn't break anything, and they will be
// canonicalized later.
std::vector<const Job *> ModuleDepGraph::findExternallyDependentUntracedJobs(
StringRef externalDependency) {
FrontendStatsTracer tracer(
stats, "fine-grained-dependencies-findExternallyDependentUntracedJobs");
std::vector<const Job *> foundJobs;
forEachUntracedJobDirectlyDependentOnExternalSwiftDeps(
externalDependency, [&](const Job *job) {
foundJobs.push_back(job);
for (const Job *marked : findJobsToRecompileWhenWholeJobChanges(job)) {
// findJobsToRecompileWhenWholeJobChanges is reflexive
// Don't return job twice.
if (marked != job)
foundJobs.push_back(marked);
}
});
return foundJobs;
}
void ModuleDepGraph::forEachUntracedJobDirectlyDependentOnExternalSwiftDeps(
StringRef externalSwiftDeps, function_ref<void(const Job *)> fn) {
// TODO move nameForDep into key
// These nodes will depend on the *interface* of the external Decl.
DependencyKey key(NodeKind::externalDepend, DeclAspect::interface, "",
externalSwiftDeps.str());
for (const ModuleDepGraphNode *useNode : usesByDef[key]) {
if (!useNode->getHasBeenTraced())
fn(getJob(useNode->getSwiftDepsOfProvides()));
}
}
//==============================================================================
// MARK: Integrating SourceFileDepGraph into ModuleDepGraph
//==============================================================================
ModuleDepGraph::Changes ModuleDepGraph::integrate(const SourceFileDepGraph &g,
StringRef swiftDepsOfJob) {
FrontendStatsTracer tracer(stats, "fine-grained-dependencies-integrate");
// When done, disappearedNodes contains the nodes which no longer exist.
auto disappearedNodes = nodeMap[swiftDepsOfJob.str()];
// When done, changeDependencyKeys contains a list of keys that changed
// as a result of this integration.
// Or if the integration failed, None.
llvm::Optional<std::unordered_set<ModuleDepGraphNode *>> changedNodes =
std::unordered_set<ModuleDepGraphNode *>();
g.forEachNode([&](const SourceFileDepGraphNode *integrand) {
const auto &key = integrand->getKey();
auto preexistingMatch = findPreexistingMatch(swiftDepsOfJob, integrand);
if (preexistingMatch.has_value() &&
preexistingMatch.value().first == LocationOfPreexistingNode::here)
disappearedNodes.erase(key); // Node was and still is. Do not erase it.
llvm::Optional<NullablePtr<ModuleDepGraphNode>> newNodeOrChangedNode =
integrateSourceFileDepGraphNode(g, integrand, preexistingMatch,
swiftDepsOfJob);
if (!newNodeOrChangedNode)
changedNodes = llvm::None;
else if (!changedNodes)
;
else if (auto *n = newNodeOrChangedNode.value().getPtrOrNull())
changedNodes.value().insert(n);
});
if (!changedNodes)
return llvm::None;
for (auto &p : disappearedNodes) {
changedNodes.value().insert(p.second);
eraseNodeFromJob(p.second);
}
// Make sure the changes can be retraced:
for (auto *n : changedNodes.value())
n->clearHasBeenTraced();
return changedNodes.value();
}
ModuleDepGraph::PreexistingNodeIfAny ModuleDepGraph::findPreexistingMatch(
StringRef swiftDepsOfCompilationToBeIntegrated,
const SourceFileDepGraphNode *integrand) const {
const auto *matches = nodeMap.find(integrand->getKey()).getPtrOrNull();
if (!matches)
return llvm::None;
const auto &expatsIter = matches->find("");
if (expatsIter != matches->end()) {
assert(matches->size() == 1 &&
"If an expat exists, then must not be any matches in other files");
return std::make_pair(LocationOfPreexistingNode::nowhere,
expatsIter->second);
}
if (integrand->getIsProvides()) {
const auto &preexistingNodeInPlaceIter =
matches->find(swiftDepsOfCompilationToBeIntegrated.str());
if (preexistingNodeInPlaceIter != matches->end())
return std::make_pair(LocationOfPreexistingNode::here,
preexistingNodeInPlaceIter->second);
}
if (!matches->empty())
return std::make_pair(LocationOfPreexistingNode::elsewhere,
matches->begin()->second);
return llvm::None;
}
llvm::Optional<NullablePtr<ModuleDepGraphNode>>
ModuleDepGraph::integrateSourceFileDepGraphNode(
const SourceFileDepGraph &g, const SourceFileDepGraphNode *integrand,
const PreexistingNodeIfAny preexistingMatch,
const StringRef swiftDepsOfJob) {
if (!integrand->getIsProvides())
return NullablePtr<ModuleDepGraphNode>(); // depends are captured by
// recordWhatUseDependsUpon below
auto changedAndIntegrationResultNode =
integrateSourceFileDeclNode(integrand, swiftDepsOfJob, preexistingMatch);
ModuleDepGraphNode *const integratedNode =
changedAndIntegrationResultNode.second;
const bool hasNewExternalDependency =
recordWhatUseDependsUpon(g, integrand, integratedNode);
NullablePtr<ModuleDepGraphNode> changedNode =
changedAndIntegrationResultNode.first || hasNewExternalDependency
? integratedNode
: nullptr;
return changedNode;
}
std::pair<bool, ModuleDepGraphNode *>
ModuleDepGraph::integrateSourceFileDeclNode(
const SourceFileDepGraphNode *integrand, StringRef swiftDepsOfJob,
const PreexistingNodeIfAny preexistingMatch) {
if (!preexistingMatch.has_value()) {
// The driver will be accessing nodes by the swiftDeps of the job,
// so pass that in.
auto *newNode =
integrateByCreatingANewNode(integrand, swiftDepsOfJob.str());
return std::make_pair(true, newNode); // New node
}
const auto where = preexistingMatch.value().first;
auto *match = preexistingMatch.value().second;
switch (where) {
case LocationOfPreexistingNode::here:
return std::make_pair(match->integrateFingerprintFrom(integrand), match);
case LocationOfPreexistingNode::nowhere:
// Some other file depended on this, but didn't know where it was.
moveNodeToDifferentFile(match, swiftDepsOfJob.str());
match->integrateFingerprintFrom(integrand);
return std::make_pair(true, match); // New Decl, assume changed
case LocationOfPreexistingNode::elsewhere:
auto *newNode =
integrateByCreatingANewNode(integrand, swiftDepsOfJob.str());
return std::make_pair(true, newNode); // New node;
}
llvm_unreachable("impossible");
}
ModuleDepGraphNode *ModuleDepGraph::integrateByCreatingANewNode(
const SourceFileDepGraphNode *integrand,
const llvm::Optional<std::string> swiftDepsForNewNode) {
assert(integrand->getIsProvides() &&
"Dependencies are arcs in the module graph");
const auto &key = integrand->getKey();
ModuleDepGraphNode *newNode = new ModuleDepGraphNode(
key, integrand->getFingerprint(), swiftDepsForNewNode);
addToMap(newNode);
return newNode;
}
bool ModuleDepGraph::recordWhatUseDependsUpon(
const SourceFileDepGraph &g,
const SourceFileDepGraphNode *sourceFileUseNode,
ModuleDepGraphNode *moduleUseNode) {
bool useHasNewExternalDependency = false;
g.forEachDefDependedUponBy(
sourceFileUseNode, [&](const SourceFileDepGraphNode *def) {
const bool isNewUse =
usesByDef[def->getKey()].insert(moduleUseNode).second;
if (isNewUse) {
StringRef externalSwiftDeps = def->getKey().getName();
if (def->getKey().getKind() == NodeKind::externalDepend) {
externalDependencies.insert(externalSwiftDeps.str());
useHasNewExternalDependency = true;
}
}
});
return useHasNewExternalDependency;
}
void ModuleDepGraph::eraseNodeFromGraphAndFreeIt(ModuleDepGraphNode *n) {
eraseNodeFromJob(n);
eraseNodeFromCurrentPathIfTracing(n);
eraseNodeFromDependencyPathToJobs(n);
delete n;
}
void ModuleDepGraph::eraseNodeFromJob(ModuleDepGraphNode *n) {
eraseNodeFromMap(n);
eraseUsesOfNode(n);
}
//==============================================================================
// MARK: ModuleDepGraph access
//==============================================================================
void ModuleDepGraph::forEachUseOf(
const ModuleDepGraphNode *def,
function_ref<void(ModuleDepGraphNode *)> fn) const {
auto iter = usesByDef.find(def->getKey());
if (iter == usesByDef.end())
return;
for (ModuleDepGraphNode *useNode : iter->second)
fn(useNode);
// Add in implicit interface->implementation dependency
forCorrespondingImplementationOfProvidedInterface(def, fn);
}
void ModuleDepGraph::forCorrespondingImplementationOfProvidedInterface(
const ModuleDepGraphNode *interfaceNode,
function_ref<void(ModuleDepGraphNode *)> fn) const {
if (!interfaceNode->getKey().isInterface() || !interfaceNode->getIsProvides())
return;
const auto swiftDeps = interfaceNode->getSwiftDeps().value();
const auto &interfaceKey = interfaceNode->getKey();
const DependencyKey implementationKey(
interfaceKey.getKind(), DeclAspect::implementation,
interfaceKey.getContext().str(), interfaceKey.getName().str());
if (const auto implementationNode =
nodeMap.find(swiftDeps, implementationKey))
fn(implementationNode.value());
}
void ModuleDepGraph::forEachNode(
function_ref<void(ModuleDepGraphNode *)> fn) const {
nodeMap.forEachEntry([&](const std::string &, const DependencyKey &,
ModuleDepGraphNode *n) { fn(n); });
}
void ModuleDepGraph::forEachMatchingNode(
const DependencyKey &key,
function_ref<void(ModuleDepGraphNode *)> fn) const {
nodeMap.forEachValueMatching(
key, [&](const std::string &, ModuleDepGraphNode *n) { fn(n); });
}
void ModuleDepGraph::forEachArc(
function_ref<void(const ModuleDepGraphNode *, const ModuleDepGraphNode *)>
fn) const {
forEachNode([&](const ModuleDepGraphNode *defNode) {
forEachUseOf(defNode, [&](const ModuleDepGraphNode *const useNode) {
fn(defNode, useNode);
});
});
}
void ModuleDepGraph::forEachNodeInJob(
StringRef swiftDeps, function_ref<void(ModuleDepGraphNode *)> fn) const {
if (const auto *nodesByKeys = nodeMap.find(swiftDeps.str()).getPtrOrNull()) {
for (const auto &keyAndNode : *nodesByKeys)
fn(keyAndNode.second);
}
}
//==============================================================================
// MARK: ModuleDepGraph traversal
//==============================================================================
void ModuleDepGraph::findPreviouslyUntracedDependents(
std::vector<ModuleDepGraphNode *> &foundDependents,
ModuleDepGraphNode *definition) {
if (definition->getHasBeenTraced())
return;
definition->setHasBeenTraced();
foundDependents.push_back(definition);
// If this use also provides something, follow it
if (!definition->getIsProvides())
return; // No need to look for uses; provides nothing
size_t pathLengthAfterArrival = traceArrival(definition);
forEachUseOf(definition, [&](ModuleDepGraphNode *u) {
// If this use also provides something, follow it
findPreviouslyUntracedDependents(foundDependents, u);
});
traceDeparture(pathLengthAfterArrival);
}
size_t ModuleDepGraph::traceArrival(const ModuleDepGraphNode *visitedNode) {
if (!currentPathIfTracing.has_value())
return 0;
auto &currentPath = currentPathIfTracing.value();
currentPath.push_back(visitedNode);
const auto visitedSwiftDepsIfAny = visitedNode->getSwiftDeps();
recordDependencyPathToJob(currentPath, getJob(visitedSwiftDepsIfAny));
return currentPath.size();
}
void ModuleDepGraph::recordDependencyPathToJob(
const std::vector<const ModuleDepGraphNode *> &pathToJob,
const driver::Job *dependentJob) {
dependencyPathsToJobs.insert(std::make_pair(dependentJob, pathToJob));
}
void ModuleDepGraph::traceDeparture(size_t pathLengthAfterArrival) {
if (!currentPathIfTracing)
return;
auto &currentPath = currentPathIfTracing.value();
assert(pathLengthAfterArrival == currentPath.size() &&
"Path must be maintained throughout recursive visits.");
currentPath.pop_back();
}
// =============================================================================
// MARK: Emitting Dot file for ModuleDepGraph
// =============================================================================
void ModuleDepGraph::emitDotFileForJob(DiagnosticEngine &diags,
const Job *job) {
emitDotFile(diags, getSwiftDeps(job));
}
void ModuleDepGraph::emitDotFile(DiagnosticEngine &diags,
StringRef baseName) {
unsigned seqNo = dotFileSequenceNumber[baseName.str()]++;
std::string fullName =
baseName.str() + "-post-integration." + std::to_string(seqNo) + ".dot";
withOutputPath(diags, *backend, fullName, [&](llvm::raw_ostream &out) {
emitDotFile(out);
return false;
});
}
void ModuleDepGraph::emitDotFile(llvm::raw_ostream &out) {
FrontendStatsTracer tracer(stats, "fine-grained-dependencies-emitDotFile");
DotFileEmitter<ModuleDepGraph>(out, *this, true, false).emit();
}
//==============================================================================
// MARK: ModuleDepGraph debugging
//==============================================================================
void ModuleDepGraphNode::dump(llvm::raw_ostream &out) const {
DepGraphNode::dump(out);
if (getIsProvides())
out << " swiftDeps: <" << getSwiftDepsOfProvides() << ">\n";
else
out << " no swiftDeps\n";
}
void ModuleDepGraphNode::dump() const {
DepGraphNode::dump();
if (getIsProvides())
llvm::errs() << " swiftDeps: <" << getSwiftDepsOfProvides() << ">\n";
else
llvm::errs() << " no swiftDeps\n";
}
bool ModuleDepGraph::verify() const {
FrontendStatsTracer tracer(stats, "fine-grained-dependencies-verify");
verifyNodeMapEntries();
verifyCanFindEachJob();
verifyEachJobInGraphIsTracked();
return true;
}
void ModuleDepGraph::verifyNodeMapEntries() const {
FrontendStatsTracer tracer(stats,
"fine-grained-dependencies-verifyNodeMapEntries");
// TODO: disable when not debugging
std::array<
std::unordered_map<DependencyKey,
std::unordered_map<std::string, ModuleDepGraphNode *>>,
2>
nodesSeenInNodeMap;
nodeMap.verify([&](const std::string &swiftDepsString,
const DependencyKey &key, ModuleDepGraphNode *n,
unsigned submapIndex) {
verifyNodeMapEntry(nodesSeenInNodeMap, swiftDepsString, key, n,
submapIndex);
});
}
void ModuleDepGraph::verifyNodeMapEntry(
std::array<std::unordered_map<
DependencyKey,
std::unordered_map<std::string, ModuleDepGraphNode *>>,
2> &nodesSeenInNodeMap,
const std::string &swiftDepsString, const DependencyKey &key,
ModuleDepGraphNode *n, const unsigned submapIndex) const {
verifyNodeIsUniqueWithinSubgraph(nodesSeenInNodeMap, swiftDepsString, key, n,
submapIndex);
verifyNodeIsInRightEntryInNodeMap(swiftDepsString, key, n);
key.verify();
verifyExternalDependencyUniqueness(key);
}
void ModuleDepGraph::verifyNodeIsUniqueWithinSubgraph(
std::array<std::unordered_map<
DependencyKey,
std::unordered_map<std::string, ModuleDepGraphNode *>>,
2> &nodesSeenInNodeMap,
const std::string &swiftDepsString, const DependencyKey &key,
ModuleDepGraphNode *const n, const unsigned submapIndex) const {
assert(submapIndex < nodesSeenInNodeMap.size() &&
"submapIndex is out of bounds.");
auto iterInserted = nodesSeenInNodeMap[submapIndex][n->getKey()].insert(
std::make_pair(n->getSwiftDepsForMapKey(), n));
if (!iterInserted.second) {
llvm_unreachable("duplicate driver keys");
}
}
void ModuleDepGraph::verifyNodeIsInRightEntryInNodeMap(
const std::string &swiftDepsString, const DependencyKey &key,
const ModuleDepGraphNode *const n) const {
const DependencyKey &nodeKey = n->getKey();
const llvm::Optional<std::string> swiftDeps =
swiftDepsString.empty() ? llvm::None
: llvm::Optional<std::string>(swiftDepsString);
(void)nodeKey;
(void)swiftDeps;
assert(n->getSwiftDeps() == swiftDeps ||
mapCorruption("Node misplaced for swiftDeps"));
assert(nodeKey == key || mapCorruption("Node misplaced for key"));
}
void ModuleDepGraph::verifyExternalDependencyUniqueness(
const DependencyKey &key) const {
assert((key.getKind() != NodeKind::externalDepend ||
externalDependencies.count(key.getName().str()) == 1) &&
"Ensure each external dependency is tracked exactly once");
}
void ModuleDepGraph::verifyCanFindEachJob() const {
FrontendStatsTracer tracer(stats,
"fine-grained-dependencies-verifyCanFindEachJob");
for (const auto &p : jobsBySwiftDeps) {
getJob(p.first);
}
}
void ModuleDepGraph::verifyEachJobInGraphIsTracked() const {
FrontendStatsTracer tracer(
stats, "fine-grained-dependencies-verifyEachJobIsTracked");
nodeMap.forEachKey1(
[&](const std::string &swiftDeps, const typename NodeMap::Key2Map &) {
ensureJobIsTracked(swiftDeps);
});
}
/// Dump the path(s) that led to \p node.
/// TODO: break up
void ModuleDepGraph::printPath(raw_ostream &out,
const driver::Job *jobToBeBuilt) const {
assert(currentPathIfTracing.has_value() &&
"Cannot print paths of paths weren't tracked.");
for (auto paths = dependencyPathsToJobs.find(jobToBeBuilt);
paths != dependencyPathsToJobs.end() && paths->first == jobToBeBuilt;
++paths) {
const auto &path = paths->second;
bool first = true;
out << "\t";
for (const ModuleDepGraphNode *n : path) {
if (first)
first = false;
else
out << " -> ";
const StringRef providerName = getProvidingFilename(n->getSwiftDeps());
printOneNodeOfPath(out, n->getKey(), providerName);
}
out << "\n";
}
}
StringRef ModuleDepGraph::getProvidingFilename(
const llvm::Optional<std::string> &swiftDeps) const {
if (!swiftDeps)
return "<unknown";
auto ext = llvm::sys::path::extension(*swiftDeps);
if (file_types::lookupTypeForExtension(ext) ==
file_types::TY_SwiftModuleFile) {
return *swiftDeps;
}
const StringRef inputName =
llvm::sys::path::filename(getJob(swiftDeps)->getFirstSwiftPrimaryInput());
// FineGrainedDependencyGraphTests work with simulated jobs with empty
// input names.
return !inputName.empty() ? inputName : StringRef(swiftDeps.value());
}
void ModuleDepGraph::printOneNodeOfPath(raw_ostream &out,
const DependencyKey &key,
const StringRef filename) {
switch (key.getKind()) {
case NodeKind::topLevel:
out << key.aspectName() << " of top-level name '" << key.humanReadableName()
<< "' in " << filename;
break;
case NodeKind::nominal:
out << key.aspectName() << " of type '" << key.humanReadableName()
<< "' in " << filename;
break;
case NodeKind::potentialMember:
out << key.aspectName() << " of non-private members '"
<< key.humanReadableName() << "' in " << filename;
break;
case NodeKind::member:
out << key.aspectName() << " of member '" << key.humanReadableName()
<< "' in " << filename;
break;
case NodeKind::dynamicLookup:
out << key.aspectName() << " of AnyObject member '"
<< key.humanReadableName() << "' in " << filename;
break;
case NodeKind::externalDepend:
out << filename << " depends on " << key.aspectName() << " of module '"
<< key.humanReadableName() << "'";
break;
case NodeKind::sourceFileProvide:
out << key.aspectName() << " of source file " << key.humanReadableName();
break;
default:
llvm_unreachable("unknown NodeKind");
}
}

View File

@@ -334,8 +334,6 @@ void ToolChain::addCommonFrontendArgs(const OutputInfo &OI,
inputArgs.AddLastArg(arguments, options::OPT_diagnostic_style);
inputArgs.AddLastArg(arguments,
options::OPT_enable_experimental_concise_pound_file);
inputArgs.AddLastArg(arguments,
options::OPT_verify_incremental_dependencies);
inputArgs.AddLastArg(arguments, options::OPT_access_notes_path);
inputArgs.AddLastArg(arguments, options::OPT_library_level);
inputArgs.AddLastArg(arguments, options::OPT_enable_bare_slash_regex);
@@ -1202,8 +1200,6 @@ ToolChain::constructInvocation(const MergeModuleJobAction &job,
context.Args.AddLastArg(Arguments, options::OPT_import_objc_header);
context.Args.AddLastArg(Arguments, options::OPT_disable_incremental_imports);
Arguments.push_back("-module-name");
Arguments.push_back(context.Args.MakeArgString(context.OI.ModuleName));

View File

@@ -357,7 +357,8 @@ static int run_driver(StringRef ExecName,
llvm::errs() << "error: unable to invoke subcommand: " << subCommandArgs[0]
<< " (" << ErrorString << ")\n";
return 2;
}
} else
Diags.diagnose(SourceLoc(), diag::new_driver_not_found, NewDriverPath);
}
// We are in the fallback to legacy driver mode.

View File

@@ -232,7 +232,6 @@ set(TEST_SUBSETS
only_validation
only_long
only_stress
only_early_swiftdriver
)
if(NOT "${COVERAGE_DB}" STREQUAL "")
@@ -426,7 +425,6 @@ foreach(SDK ${SWIFT_SDKS})
(test_subset STREQUAL "validation") OR
(test_subset STREQUAL "only_long") OR
(test_subset STREQUAL "only_stress") OR
(test_subset STREQUAL "only_early_swiftdriver") OR
(test_subset STREQUAL "all"))
list(APPEND directories "${test_bin_dir}")
endif()

View File

@@ -1,38 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: './main.swiftdeps'
fingerprint: d41d8cd98f00b204e9800998ecf8427e
sequenceNumber: 0
defsIDependUpon: [ ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: './main.swiftdeps'
fingerprint: d41d8cd98f00b204e9800998ecf8427e
sequenceNumber: 1
defsIDependUpon: [ 2, 3 ]
isProvides: true
- key:
kind: externalDepend
aspect: interface
context: ''
name: '/Volumes/AS/s/dec/build/Ninja-DebugAssert/swift-macosx-x86_64/lib/swift/macosx/Swift.swiftmodule/x86_64-apple-macos.swiftmodule'
sequenceNumber: 2
defsIDependUpon: [ ]
isProvides: false
- key:
kind: externalDepend
aspect: interface
context: ''
name: '/Volumes/AS/s/dec/build/Ninja-DebugAssert/swift-macosx-x86_64/lib/swift/macosx/SwiftOnoneSupport.swiftmodule/x86_64-apple-macos.swiftmodule'
sequenceNumber: 3
defsIDependUpon: [ ]
isProvides: false
...

View File

@@ -1,38 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: './other.swiftdeps'
fingerprint: d41d8cd98f00b204e9800998ecf8427e
sequenceNumber: 0
defsIDependUpon: [ ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: './other.swiftdeps'
fingerprint: d41d8cd98f00b204e9800998ecf8427e
sequenceNumber: 1
defsIDependUpon: [ 2, 3 ]
isProvides: true
- key:
kind: externalDepend
aspect: interface
context: ''
name: '/Volumes/AS/s/dec/build/Ninja-DebugAssert/swift-macosx-x86_64/lib/swift/macosx/Swift.swiftmodule/x86_64-apple-macos.swiftmodule'
sequenceNumber: 2
defsIDependUpon: [ ]
isProvides: false
- key:
kind: externalDepend
aspect: interface
context: ''
name: '/Volumes/AS/s/dec/build/Ninja-DebugAssert/swift-macosx-x86_64/lib/swift/macosx/SwiftOnoneSupport.swiftmodule/x86_64-apple-macos.swiftmodule'
sequenceNumber: 3
defsIDependUpon: [ ]
isProvides: false
...

View File

@@ -1,21 +0,0 @@
{
"./main.swift": {
"object": "./main.o",
"swift-dependencies": "./main.swiftdeps"
},
"./other.swift": {
"object": "./other.o",
"swift-dependencies": "./other.swiftdeps"
},
"./yet-another.swift": {
"object": "./yet-another.o",
"swift-dependencies": "./yet-another.swiftdeps"
},
"./added.swift": {
"object": "./added.o",
"swift-dependencies": "./added.swiftdeps"
},
"": {
"swift-dependencies": "./main~buildrecord.swiftdeps"
}
}

View File

@@ -1,38 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: './yet-another.swiftdeps'
fingerprint: d41d8cd98f00b204e9800998ecf8427e
sequenceNumber: 0
defsIDependUpon: [ ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: './yet-another.swiftdeps'
fingerprint: d41d8cd98f00b204e9800998ecf8427e
sequenceNumber: 1
defsIDependUpon: [ 2, 3 ]
isProvides: true
- key:
kind: externalDepend
aspect: interface
context: ''
name: '/Volumes/AS/s/dec/build/Ninja-DebugAssert/swift-macosx-x86_64/lib/swift/macosx/Swift.swiftmodule/x86_64-apple-macos.swiftmodule'
sequenceNumber: 2
defsIDependUpon: [ ]
isProvides: false
- key:
kind: externalDepend
aspect: interface
context: ''
name: '/Volumes/AS/s/dec/build/Ninja-DebugAssert/swift-macosx-x86_64/lib/swift/macosx/SwiftOnoneSupport.swiftmodule/x86_64-apple-macos.swiftmodule'
sequenceNumber: 3
defsIDependUpon: [ ]
isProvides: false
...

View File

@@ -1,46 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: main.swiftdeps
fingerprint: 8276a546203ebde599da50b466729230
sequenceNumber: 0
defsIDependUpon: [ 4, 2 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: main.swiftdeps
fingerprint: 8276a546203ebde599da50b466729230
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: dynamicLookup
aspect: interface
context: ''
name: z
sequenceNumber: 2
defsIDependUpon: [ 0 ]
isProvides: true
- key:
kind: dynamicLookup
aspect: implementation
context: ''
name: z
sequenceNumber: 3
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: a
sequenceNumber: 4
defsIDependUpon: [ ]
isProvides: false
...

View File

@@ -1,38 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: other.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 0
defsIDependUpon: [ 2 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: other.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: a
sequenceNumber: 2
defsIDependUpon: [ 0 ]
isProvides: true
- key:
kind: topLevel
aspect: implementation
context: ''
name: a
sequenceNumber: 3
defsIDependUpon: [ ]
isProvides: true
...

View File

@@ -1,17 +0,0 @@
{
"./main.swift": {
"object": "./main.o",
"swift-dependencies": "./main.swiftdeps"
},
"./other.swift": {
"object": "./other.o",
"swift-dependencies": "./other.swiftdeps"
},
"./yet-another.swift": {
"object": "./yet-another.o",
"swift-dependencies": "./yet-another.swiftdeps"
},
"": {
"swift-dependencies": "./main~buildrecord.swiftdeps"
}
}

View File

@@ -1,30 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: yet-another.swiftdeps
fingerprint: f0a22821b1bfd1d40363b3f89c7a7693
sequenceNumber: 0
defsIDependUpon: [ 2 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: yet-another.swiftdeps
fingerprint: f0a22821b1bfd1d40363b3f89c7a7693
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: dynamicLookup
aspect: interface
context: ''
name: z
sequenceNumber: 2
defsIDependUpon: [ ]
isProvides: false
...

View File

@@ -1,46 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: main.swiftdeps
fingerprint: 42e5bb8d6f23bfc1b055b85bd466a86c
sequenceNumber: 0
defsIDependUpon: [ 2, 4 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: main.swiftdeps
fingerprint: 42e5bb8d6f23bfc1b055b85bd466a86c
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: nominal
aspect: interface
context: 4main1zV
name: ''
sequenceNumber: 2
defsIDependUpon: [ 0 ]
isProvides: true
- key:
kind: nominal
aspect: implementation
context: 4main1zV
name: ''
sequenceNumber: 3
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: a
sequenceNumber: 4
defsIDependUpon: [ ]
isProvides: false
...

View File

@@ -1,38 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: other.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 0
defsIDependUpon: [ 2 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: other.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: a
sequenceNumber: 2
defsIDependUpon: [ 0 ]
isProvides: true
- key:
kind: topLevel
aspect: implementation
context: ''
name: a
sequenceNumber: 3
defsIDependUpon: [ ]
isProvides: true
...

View File

@@ -1,17 +0,0 @@
{
"./main.swift": {
"object": "./main.o",
"swift-dependencies": "./main.swiftdeps"
},
"./other.swift": {
"object": "./other.o",
"swift-dependencies": "./other.swiftdeps"
},
"./yet-another.swift": {
"object": "./yet-another.o",
"swift-dependencies": "./yet-another.swiftdeps"
},
"": {
"swift-dependencies": "./main~buildrecord.swiftdeps"
}
}

View File

@@ -1,30 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: yet-another.swiftdeps
fingerprint: aae342945c458d008a9989daac618092
sequenceNumber: 0
defsIDependUpon: [ 2 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: yet-another.swiftdeps
fingerprint: aae342945c458d008a9989daac618092
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: nominal
aspect: interface
context: 4main1zV
name: ''
sequenceNumber: 2
defsIDependUpon: [ ]
isProvides: false
...

View File

@@ -1,46 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: main.swiftdeps
fingerprint: 279f98f41b2fb1a907b1ce04fa09ce50
sequenceNumber: 0
defsIDependUpon: [ 2, 4 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: main.swiftdeps
fingerprint: 279f98f41b2fb1a907b1ce04fa09ce50
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: nominal
aspect: interface
context: 4main1zV
name: ''
sequenceNumber: 2
defsIDependUpon: [ 0 ]
isProvides: true
- key:
kind: nominal
aspect: implementation
context: 4main1zV
name: ''
sequenceNumber: 3
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: a
sequenceNumber: 4
defsIDependUpon: [ ]
isProvides: false
...

View File

@@ -1,38 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: other.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 0
defsIDependUpon: [ 2 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: other.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: a
sequenceNumber: 2
defsIDependUpon: [ 0 ]
isProvides: true
- key:
kind: topLevel
aspect: implementation
context: ''
name: a
sequenceNumber: 3
defsIDependUpon: [ ]
isProvides: true
...

View File

@@ -1,17 +0,0 @@
{
"./main.swift": {
"object": "./main.o",
"swift-dependencies": "./main.swiftdeps"
},
"./other.swift": {
"object": "./other.o",
"swift-dependencies": "./other.swiftdeps"
},
"./yet-another.swift": {
"object": "./yet-another.o",
"swift-dependencies": "./yet-another.swiftdeps"
},
"": {
"swift-dependencies": "./main~buildrecord.swiftdeps"
}
}

View File

@@ -1,30 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: yet-another.swiftdeps
fingerprint: 59c8ff39595b320cb70847063b7410b9
sequenceNumber: 0
defsIDependUpon: [ 2 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: yet-another.swiftdeps
fingerprint: 59c8ff39595b320cb70847063b7410b9
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: nominal
aspect: interface
context: 4main1zV
name: ''
sequenceNumber: 2
defsIDependUpon: [ ]
isProvides: false
...

View File

@@ -1,46 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: main.swiftdeps
fingerprint: 88888888888888888888888888888888
sequenceNumber: 0
defsIDependUpon: [ 2, 4 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: main.swiftdeps
fingerprint: 88888888888888888888888888888888
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: nominal
aspect: interface
context: 4main1bV
name: ''
sequenceNumber: 2
defsIDependUpon: [ 0 ]
isProvides: true
- key:
kind: nominal
aspect: implementation
context: 4main1bV
name: ''
sequenceNumber: 3
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: a
sequenceNumber: 4
defsIDependUpon: [ ]
isProvides: false
...

View File

@@ -1,38 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: other.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 0
defsIDependUpon: [ 2 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: other.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: a
sequenceNumber: 2
defsIDependUpon: [ 0 ]
isProvides: true
- key:
kind: topLevel
aspect: implementation
context: ''
name: a
sequenceNumber: 3
defsIDependUpon: [ ]
isProvides: true
...

View File

@@ -1,17 +0,0 @@
{
"./main.swift": {
"object": "./main.o",
"swift-dependencies": "./main.swiftdeps"
},
"./other.swift": {
"object": "./other.o",
"swift-dependencies": "./other.swiftdeps"
},
"./yet-another.swift": {
"object": "./yet-another.o",
"swift-dependencies": "./yet-another.swiftdeps"
},
"": {
"swift-dependencies": "./main~buildrecord.swiftdeps"
}
}

View File

@@ -1,30 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: yet-another.swiftdeps
fingerprint: 0435fef7d7170574edab927508293b15
sequenceNumber: 0
defsIDependUpon: [ 2 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: yet-another.swiftdeps
fingerprint: 0435fef7d7170574edab927508293b15
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: nominal
aspect: interface
context: 4main1bV
name: ''
sequenceNumber: 2
defsIDependUpon: [ ]
isProvides: false
...

View File

@@ -1,62 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: main.swiftdeps
fingerprint: a4e513b4b5693bf6f50d6c0d531b542b
sequenceNumber: 0
defsIDependUpon: [ 2, 4, 5, 6 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: main.swiftdeps
fingerprint: a4e513b4b5693bf6f50d6c0d531b542b
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: nominal
aspect: interface
context: 4main1bV
name: ''
sequenceNumber: 2
defsIDependUpon: [ 0 ]
isProvides: true
- key:
kind: nominal
aspect: implementation
context: 4main1bV
name: ''
sequenceNumber: 3
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: z
sequenceNumber: 4
defsIDependUpon: [ ]
isProvides: false
- key:
kind: topLevel
aspect: interface
context: ''
name: a
sequenceNumber: 5
defsIDependUpon: [ ]
isProvides: false
- key:
kind: topLevel
aspect: interface
context: ''
name: x
sequenceNumber: 6
defsIDependUpon: [ ]
isProvides: false
...

View File

@@ -1,38 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: other.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 0
defsIDependUpon: [ 2 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: other.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: a
sequenceNumber: 2
defsIDependUpon: [ 0 ]
isProvides: true
- key:
kind: topLevel
aspect: implementation
context: ''
name: a
sequenceNumber: 3
defsIDependUpon: [ ]
isProvides: true
...

View File

@@ -1,17 +0,0 @@
{
"./main.swift": {
"object": "./main.o",
"swift-dependencies": "./main.swiftdeps"
},
"./other.swift": {
"object": "./other.o",
"swift-dependencies": "./other.swiftdeps"
},
"./yet-another.swift": {
"object": "./yet-another.o",
"swift-dependencies": "./yet-another.swiftdeps"
},
"": {
"swift-dependencies": "./main~buildrecord.swiftdeps"
}
}

View File

@@ -1,30 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: yet-another.swiftdeps
fingerprint: 913de1b71ef48d4c730689fd99d7090e
sequenceNumber: 0
defsIDependUpon: [ 2 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: yet-another.swiftdeps
fingerprint: 913de1b71ef48d4c730689fd99d7090e
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: nominal
aspect: interface
context: 4main1bV
name: ''
sequenceNumber: 2
defsIDependUpon: [ ]
isProvides: false
...

View File

@@ -1,86 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: main.swiftdeps
fingerprint: d281713b8f6ef5935679e8b3cbe6d5ce
sequenceNumber: 0
defsIDependUpon: [ 2, 4, 5, 6, 7, 8, 9 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: main.swiftdeps
fingerprint: d281713b8f6ef5935679e8b3cbe6d5ce
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: nominal
aspect: interface
context: 4main1bV
name: ''
sequenceNumber: 2
defsIDependUpon: [ 0 ]
isProvides: true
- key:
kind: nominal
aspect: implementation
context: 4main1bV
name: ''
sequenceNumber: 3
defsIDependUpon: [ ]
isProvides: true
- key:
kind: nominal
aspect: interface
context: 4main1aV
name: ''
sequenceNumber: 4
defsIDependUpon: [ ]
isProvides: false
- key:
kind: nominal
aspect: interface
context: 4main1zV
name: ''
sequenceNumber: 5
defsIDependUpon: [ ]
isProvides: false
- key:
kind: member
aspect: interface
context: 4main1zV
name: z
sequenceNumber: 6
defsIDependUpon: [ ]
isProvides: false
- key:
kind: nominal
aspect: interface
context: 4main1xV
name: ''
sequenceNumber: 7
defsIDependUpon: [ ]
isProvides: false
- key:
kind: member
aspect: interface
context: 4main1aV
name: a
sequenceNumber: 8
defsIDependUpon: [ ]
isProvides: false
- key:
kind: member
aspect: interface
context: 4main1xV
name: x
sequenceNumber: 9
defsIDependUpon: [ ]
isProvides: false
...

View File

@@ -1,38 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: other.swiftdeps
fingerprint: 2221cd1a52ad1f50cba3610cd9d80d45
sequenceNumber: 0
defsIDependUpon: [ 2 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: other.swiftdeps
fingerprint: 2221cd1a52ad1f50cba3610cd9d80d45
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: member
aspect: interface
context: 4main1aV
name: a
sequenceNumber: 2
defsIDependUpon: [ 0 ]
isProvides: true
- key:
kind: member
aspect: implementation
context: 4main1aV
name: a
sequenceNumber: 3
defsIDependUpon: [ ]
isProvides: true
...

View File

@@ -1,17 +0,0 @@
{
"./main.swift": {
"object": "./main.o",
"swift-dependencies": "./main.swiftdeps"
},
"./other.swift": {
"object": "./other.o",
"swift-dependencies": "./other.swiftdeps"
},
"./yet-another.swift": {
"object": "./yet-another.o",
"swift-dependencies": "./yet-another.swiftdeps"
},
"": {
"swift-dependencies": "./main~buildrecord.swiftdeps"
}
}

View File

@@ -1,30 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: yet-another.swiftdeps
fingerprint: d7ad1a83584a3d3976404bcb830d57d1
sequenceNumber: 0
defsIDependUpon: [ 2 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: yet-another.swiftdeps
fingerprint: d7ad1a83584a3d3976404bcb830d57d1
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: nominal
aspect: interface
context: 4main1bV
name: ''
sequenceNumber: 2
defsIDependUpon: [ ]
isProvides: false
...

View File

@@ -1,47 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: main.swiftdeps
fingerprint: ea2e880fb7f4944d6f6093dad31c2ff9
sequenceNumber: 0
defsIDependUpon: [ 2 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: main.swiftdeps
fingerprint: ea2e880fb7f4944d6f6093dad31c2ff9
sequenceNumber: 1
defsIDependUpon: [ 4 ]
isProvides: true
- key:
kind: nominal
aspect: interface
context: 4main1zV
name: ''
sequenceNumber: 2
defsIDependUpon: [ 0 ]
isProvides: true
- key:
kind: nominal
aspect: implementation
context: 4main1zV
name: ''
sequenceNumber: 3
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: a
sequenceNumber: 4
defsIDependUpon: [ ]
isProvides: false
...

View File

@@ -1,38 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: other.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 0
defsIDependUpon: [ 2 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: other.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: a
sequenceNumber: 2
defsIDependUpon: [ 0 ]
isProvides: true
- key:
kind: topLevel
aspect: implementation
context: ''
name: a
sequenceNumber: 3
defsIDependUpon: [ ]
isProvides: true
...

View File

@@ -1,17 +0,0 @@
{
"./main.swift": {
"object": "./main.o",
"swift-dependencies": "./main.swiftdeps"
},
"./other.swift": {
"object": "./other.o",
"swift-dependencies": "./other.swiftdeps"
},
"./yet-another.swift": {
"object": "./yet-another.o",
"swift-dependencies": "./yet-another.swiftdeps"
},
"": {
"swift-dependencies": "./main~buildrecord.swiftdeps"
}
}

View File

@@ -1,30 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: yet-another.swiftdeps
fingerprint: 59c8ff39595b320cb70847063b7410b9
sequenceNumber: 0
defsIDependUpon: [ 2 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: yet-another.swiftdeps
fingerprint: 59c8ff39595b320cb70847063b7410b9
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: nominal
aspect: interface
context: 4main1zV
name: ''
sequenceNumber: 2
defsIDependUpon: [ ]
isProvides: false
...

View File

@@ -1,3 +0,0 @@
# Dependencies after compilation:
depends-top-level: [a]
provides-nominal: [z]

View File

@@ -1,2 +0,0 @@
# Dependencies after compilation:
provides-top-level: [a]

View File

@@ -1,17 +0,0 @@
{
"./main.swift": {
"object": "./main.o",
"swift-dependencies": "./main.swiftdeps"
},
"./other.swift": {
"object": "./other.o",
"swift-dependencies": "./other.swiftdeps"
},
"./yet-another.swift": {
"object": "./yet-another.o",
"swift-dependencies": "./yet-another.swiftdeps"
},
"": {
"swift-dependencies": "./main~buildrecord.swiftdeps"
}
}

View File

@@ -1,2 +0,0 @@
# Dependencies after compilation:
depends-nominal: [z]

View File

@@ -1,38 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: a.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 0
defsIDependUpon: [ 2 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: a.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: a
sequenceNumber: 2
defsIDependUpon: [ 0 ]
isProvides: true
- key:
kind: topLevel
aspect: implementation
context: ''
name: a
sequenceNumber: 3
defsIDependUpon: [ ]
isProvides: true
...

View File

@@ -1,46 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: b.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 0
defsIDependUpon: [ 2, 4 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: b.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: b
sequenceNumber: 2
defsIDependUpon: [ 0 ]
isProvides: true
- key:
kind: topLevel
aspect: implementation
context: ''
name: b
sequenceNumber: 3
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: implementation
context: ''
name: a
sequenceNumber: 4
defsIDependUpon: [ ]
isProvides: false
...

View File

@@ -1,46 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: c.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 0
defsIDependUpon: [ 2, 4 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: c.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: c
sequenceNumber: 2
defsIDependUpon: [ 0 ]
isProvides: true
- key:
kind: topLevel
aspect: implementation
context: ''
name: c
sequenceNumber: 3
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: implementation
context: ''
name: b
sequenceNumber: 4
defsIDependUpon: [ ]
isProvides: false
...

View File

@@ -1,33 +0,0 @@
{
"./a.swift": {
"object": "./a.o",
"swift-dependencies": "./a.swiftdeps"
},
"./b.swift": {
"object": "./b.o",
"swift-dependencies": "./b.swiftdeps"
},
"./c.swift": {
"object": "./c.o",
"swift-dependencies": "./c.swiftdeps"
},
"./d.swift": {
"object": "./d.o",
"swift-dependencies": "./d.swiftdeps"
},
"./e.swift": {
"object": "./e.o",
"swift-dependencies": "./e.swiftdeps"
},
"./f.swift": {
"object": "./f.o",
"swift-dependencies": "./f.swiftdeps"
},
"./bad.swift": {
"object": "./bad.o",
"swift-dependencies": "./bad.swiftdeps"
},
"": {
"swift-dependencies": "./main~buildrecord.swiftdeps"
}
}

View File

@@ -1,54 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: './crash.swiftdeps'
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 0
defsIDependUpon: [ 5, 4, 2 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: './crash.swiftdeps'
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: a
sequenceNumber: 2
defsIDependUpon: [ 0 ]
isProvides: true
- key:
kind: topLevel
aspect: implementation
context: ''
name: a
sequenceNumber: 3
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: IntegerLiteralType
sequenceNumber: 4
defsIDependUpon: [ ]
isProvides: false
- key:
kind: topLevel
aspect: interface
context: ''
name: FloatLiteralType
sequenceNumber: 5
defsIDependUpon: [ ]
isProvides: false
...

View File

@@ -1,46 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: './main.swiftdeps'
fingerprint: 316328d5be8544f05f3cc73c32cea2d2
sequenceNumber: 0
defsIDependUpon: [ 4, 2 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: './main.swiftdeps'
fingerprint: 316328d5be8544f05f3cc73c32cea2d2
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: M
sequenceNumber: 2
defsIDependUpon: [ 0 ]
isProvides: true
- key:
kind: topLevel
aspect: implementation
context: ''
name: M
sequenceNumber: 3
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: a
sequenceNumber: 4
defsIDependUpon: [ ]
isProvides: false
...

View File

@@ -1,54 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: './other.swiftdeps'
fingerprint: 0665c1c79514536cfd19ee3359008f19
sequenceNumber: 0
defsIDependUpon: [ 2, 4 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: './other.swiftdeps'
fingerprint: 0665c1c79514536cfd19ee3359008f19
sequenceNumber: 1
defsIDependUpon: [ 5 ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: F
sequenceNumber: 2
defsIDependUpon: [ 0 ]
isProvides: true
- key:
kind: topLevel
aspect: implementation
context: ''
name: F
sequenceNumber: 3
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: AssignmentPrecedence
sequenceNumber: 4
defsIDependUpon: [ ]
isProvides: false
- key:
kind: topLevel
aspect: interface
context: ''
name: a
sequenceNumber: 5
defsIDependUpon: [ ]
isProvides: false
...

View File

@@ -1,17 +0,0 @@
{
"./main.swift": {
"object": "./main.o",
"swift-dependencies": "./main.swiftdeps"
},
"./crash.swift": {
"object": "./crash.o",
"swift-dependencies": "./crash.swiftdeps"
},
"./other.swift": {
"object": "./other.o",
"swift-dependencies": "./other.swiftdeps"
},
"": {
"swift-dependencies": "./main~buildrecord.swiftdeps"
}
}

View File

@@ -1,38 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: crash.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 0
defsIDependUpon: [ 2 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: crash.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: a
sequenceNumber: 2
defsIDependUpon: [ 0 ]
isProvides: true
- key:
kind: topLevel
aspect: implementation
context: ''
name: a
sequenceNumber: 3
defsIDependUpon: [ ]
isProvides: true
...

View File

@@ -1,30 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: main.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 0
defsIDependUpon: [ 2 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: main.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: a
sequenceNumber: 2
defsIDependUpon: [ 0 ]
isProvides: false
...

View File

@@ -1,30 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: other.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 0
defsIDependUpon: [ ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: other.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 1
defsIDependUpon: [ 2 ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: a
sequenceNumber: 2
defsIDependUpon: [ 0 ]
isProvides: false
...

View File

@@ -1,17 +0,0 @@
{
"./main.swift": {
"object": "./main.o",
"swift-dependencies": "./main.swiftdeps"
},
"./crash.swift": {
"object": "./crash.o",
"swift-dependencies": "./crash.swiftdeps"
},
"./other.swift": {
"object": "./other.o",
"swift-dependencies": "./other.swiftdeps"
},
"": {
"swift-dependencies": "./main~buildrecord.swiftdeps"
}
}

View File

@@ -1,38 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: a.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 0
defsIDependUpon: [ 2 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: a.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: a
sequenceNumber: 2
defsIDependUpon: [ 0 ]
isProvides: true
- key:
kind: topLevel
aspect: implementation
context: ''
name: a
sequenceNumber: 3
defsIDependUpon: [ ]
isProvides: true
...

View File

@@ -1,38 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: b.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 0
defsIDependUpon: [ 2 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: b.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: b
sequenceNumber: 2
defsIDependUpon: [ 0 ]
isProvides: true
- key:
kind: topLevel
aspect: implementation
context: ''
name: b
sequenceNumber: 3
defsIDependUpon: [ ]
isProvides: true
...

View File

@@ -1,54 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: bad.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 0
defsIDependUpon: [ 2, 4 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: bad.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 1
defsIDependUpon: [ 5 ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: bad
sequenceNumber: 2
defsIDependUpon: [ 0 ]
isProvides: true
- key:
kind: topLevel
aspect: implementation
context: ''
name: bad
sequenceNumber: 3
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: a
sequenceNumber: 4
defsIDependUpon: [ ]
isProvides: false
- key:
kind: topLevel
aspect: interface
context: ''
name: b
sequenceNumber: 5
defsIDependUpon: [ ]
isProvides: false
...

View File

@@ -1,46 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: c.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 0
defsIDependUpon: [ 2, 4 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: c.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: c
sequenceNumber: 2
defsIDependUpon: [ 0 ]
isProvides: true
- key:
kind: topLevel
aspect: implementation
context: ''
name: c
sequenceNumber: 3
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: implementation
context: ''
name: bad
sequenceNumber: 4
defsIDependUpon: [ ]
isProvides: false
...

View File

@@ -1,46 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: d.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 0
defsIDependUpon: [ 2, 4 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: d.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: d
sequenceNumber: 2
defsIDependUpon: [ 0 ]
isProvides: true
- key:
kind: topLevel
aspect: implementation
context: ''
name: d
sequenceNumber: 3
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: implementation
context: ''
name: c
sequenceNumber: 4
defsIDependUpon: [ ]
isProvides: false
...

View File

@@ -1,46 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: e.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 0
defsIDependUpon: [ 2 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: e.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 1
defsIDependUpon: [ 4 ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: e
sequenceNumber: 2
defsIDependUpon: [ 0 ]
isProvides: true
- key:
kind: topLevel
aspect: implementation
context: ''
name: e
sequenceNumber: 3
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: implementation
context: ''
name: bad
sequenceNumber: 4
defsIDependUpon: [ ]
isProvides: false
...

View File

@@ -1,46 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: f.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 0
defsIDependUpon: [ 2, 4 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: f.swiftdeps
fingerprint: 72e95f4a11b98227c1f6ad6ea7f6cdba
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: f
sequenceNumber: 2
defsIDependUpon: [ 0 ]
isProvides: true
- key:
kind: topLevel
aspect: implementation
context: ''
name: f
sequenceNumber: 3
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: implementation
context: ''
name: e
sequenceNumber: 4
defsIDependUpon: [ ]
isProvides: false
...

View File

@@ -1,33 +0,0 @@
{
"./a.swift": {
"object": "./a.o",
"swift-dependencies": "./a.swiftdeps"
},
"./b.swift": {
"object": "./b.o",
"swift-dependencies": "./b.swiftdeps"
},
"./c.swift": {
"object": "./c.o",
"swift-dependencies": "./c.swiftdeps"
},
"./d.swift": {
"object": "./d.o",
"swift-dependencies": "./d.swiftdeps"
},
"./e.swift": {
"object": "./e.o",
"swift-dependencies": "./e.swiftdeps"
},
"./f.swift": {
"object": "./f.o",
"swift-dependencies": "./f.swiftdeps"
},
"./bad.swift": {
"object": "./bad.o",
"swift-dependencies": "./bad.swiftdeps"
},
"": {
"swift-dependencies": "./main~buildrecord.swiftdeps"
}
}

View File

@@ -1,39 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: bad.swiftdeps
fingerprint: 22222222222222222222222222222222
sequenceNumber: 0
defsIDependUpon: [ 2 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: bad.swiftdeps
fingerprint: 22222222222222222222222222222222
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: bad
sequenceNumber: 2
defsIDependUpon: [ 0 ]
isProvides: true
- key:
kind: topLevel
aspect: implementation
context: ''
name: bad
sequenceNumber: 3
defsIDependUpon: [ ]
isProvides: true
...

View File

@@ -1,31 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: dependsonbad.swiftdeps
fingerprint: 22222222222222222222222222222222
sequenceNumber: 0
defsIDependUpon: [ 2 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: dependsonbad.swiftdeps
fingerprint: 22222222222222222222222222222222
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: bad
sequenceNumber: 2
defsIDependUpon: [ ]
isProvides: false
...

View File

@@ -1,30 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: dependsonmain.swiftdeps
fingerprint: 22222222222222222222222222222222
sequenceNumber: 0
defsIDependUpon: [ 2 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: dependsonmain.swiftdeps
fingerprint: 22222222222222222222222222222222
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: main
sequenceNumber: 2
defsIDependUpon: [ ]
isProvides: false
...

View File

@@ -1,39 +0,0 @@
# Fine-grained v0
---
allNodes:
- key:
kind: sourceFileProvide
aspect: interface
context: ''
name: main.swiftdeps
fingerprint: 22222222222222222222222222222222
sequenceNumber: 0
defsIDependUpon: [ 2 ]
isProvides: true
- key:
kind: sourceFileProvide
aspect: implementation
context: ''
name: main.swiftdeps
fingerprint: 22222222222222222222222222222222
sequenceNumber: 1
defsIDependUpon: [ ]
isProvides: true
- key:
kind: topLevel
aspect: interface
context: ''
name: main
sequenceNumber: 2
defsIDependUpon: [ 0 ]
isProvides: true
- key:
kind: topLevel
aspect: implementation
context: ''
name: main
sequenceNumber: 3
defsIDependUpon: [ ]
isProvides: true
...

Some files were not shown because too many files have changed in this diff Show More