mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -43,8 +43,6 @@ void InputAction::anchor() {}
|
||||
|
||||
void JobAction::anchor() {}
|
||||
|
||||
void IncrementalJobAction::anchor() {}
|
||||
|
||||
void CompileJobAction::anchor() {}
|
||||
|
||||
void InterpretJobAction::anchor() {}
|
||||
|
||||
@@ -5,7 +5,6 @@ set(swiftDriver_sources
|
||||
Compilation.cpp
|
||||
DarwinToolChains.cpp
|
||||
Driver.cpp
|
||||
FineGrainedDependencyDriverGraph.cpp
|
||||
FrontendUtil.cpp
|
||||
Job.cpp
|
||||
PrettyStackTrace.cpp
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 ¤tPath = 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 ¤tPath = 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");
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
...
|
||||
@@ -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
|
||||
...
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
...
|
||||
@@ -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
|
||||
...
|
||||
@@ -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
|
||||
...
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
...
|
||||
@@ -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
|
||||
...
|
||||
Binary file not shown.
@@ -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
|
||||
...
|
||||
Binary file not shown.
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
...
|
||||
Binary file not shown.
@@ -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
|
||||
...
|
||||
@@ -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
|
||||
...
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
...
|
||||
@@ -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
|
||||
...
|
||||
Binary file not shown.
@@ -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
|
||||
...
|
||||
Binary file not shown.
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
...
|
||||
Binary file not shown.
@@ -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
|
||||
...
|
||||
Binary file not shown.
@@ -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
|
||||
...
|
||||
Binary file not shown.
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
...
|
||||
Binary file not shown.
@@ -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
|
||||
...
|
||||
Binary file not shown.
@@ -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
|
||||
...
|
||||
Binary file not shown.
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
...
|
||||
Binary file not shown.
@@ -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
|
||||
|
||||
...
|
||||
@@ -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
|
||||
...
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
...
|
||||
@@ -1,3 +0,0 @@
|
||||
# Dependencies after compilation:
|
||||
depends-top-level: [a]
|
||||
provides-nominal: [z]
|
||||
@@ -1,2 +0,0 @@
|
||||
# Dependencies after compilation:
|
||||
provides-top-level: [a]
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
# Dependencies after compilation:
|
||||
depends-nominal: [z]
|
||||
@@ -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
|
||||
...
|
||||
@@ -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
|
||||
...
|
||||
@@ -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
|
||||
...
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
...
|
||||
@@ -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
|
||||
...
|
||||
@@ -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
|
||||
...
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
...
|
||||
Binary file not shown.
@@ -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
|
||||
...
|
||||
Binary file not shown.
@@ -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
|
||||
...
|
||||
Binary file not shown.
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
...
|
||||
@@ -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
|
||||
...
|
||||
@@ -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
|
||||
...
|
||||
@@ -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
|
||||
...
|
||||
@@ -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
|
||||
...
|
||||
@@ -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
|
||||
...
|
||||
@@ -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
|
||||
...
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
...
|
||||
|
||||
Binary file not shown.
@@ -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
|
||||
...
|
||||
|
||||
Binary file not shown.
@@ -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
|
||||
...
|
||||
Binary file not shown.
@@ -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
Reference in New Issue
Block a user