Separate dependency tracking from Make-style .d file generation.

This refactoring is groundwork for saving the cross-module dependencies
in the swiftdeps files as well, so that we know to rebuild files if an
outside file changes (such as a bridging header, another framework's
headers, or another framework's swiftmodule).

Part of rdar://problem/19270920

Swift SVN r24258
This commit is contained in:
Jordan Rose
2015-01-08 03:02:17 +00:00
parent c87a359107
commit 1d3bdfae7f
6 changed files with 62 additions and 111 deletions

View File

@@ -20,6 +20,7 @@
#include "swift/AST/Identifier.h"
#include "swift/Basic/LLVM.h"
#include "swift/Basic/SourceLoc.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/TinyPtrVector.h"
namespace swift {
@@ -31,13 +32,28 @@ class NominalTypeDecl;
enum class KnownProtocolKind : uint8_t;
/// Records dependencies on files outside of the current module.
class DependencyTracker {
virtual void anchor();
protected:
DependencyTracker() = default;
llvm::SetVector<std::string, std::vector<std::string>> paths;
public:
virtual ~DependencyTracker() = default;
virtual void addDependency(StringRef file) {}
/// Adds a file as a dependency.
///
/// The contents of \p file are taken literally, and should be appropriate
/// for appearing in a list of dependencies suitable for tooling like Make.
/// No path canonicalization is done.
void addDependency(StringRef file) {
paths.insert(file);
}
/// Fetches the list of dependencies.
ArrayRef<std::string> getDependencies() const {
if (paths.empty())
return None;
assert((&paths[0]) + (paths.size() - 1) == &paths.back() &&
"elements not stored contiguously");
return llvm::makeArrayRef(&paths[0], paths.size());
}
};
/// \brief Abstract interface that loads named modules into the AST.

View File

@@ -1,34 +0,0 @@
//===- DependencyFileGenerator.h - .d file generation -----------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_FRONTEND_DEPENDENCYFILEGENERATOR_H
#define SWIFT_FRONTEND_DEPENDENCYFILEGENERATOR_H
#include "swift/AST/ModuleLoader.h"
#include "swift/Basic/LLVM.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/StringSet.h"
#include <vector>
namespace swift {
class DependencyFileGenerator : public DependencyTracker {
std::vector<std::string> targets;
llvm::SetVector<std::string, std::vector<std::string>> paths;
public:
virtual void addDependency(StringRef file) override;
void addTarget(StringRef targetName);
void writeToStream(llvm::raw_ostream &os) const;
};
}
#endif

View File

@@ -39,7 +39,6 @@ using namespace swift;
LazyResolver::~LazyResolver() = default;
void ModuleLoader::anchor() {}
void DependencyTracker::anchor() {}
llvm::StringRef swift::getProtocolName(KnownProtocolKind kind) {
switch (kind) {

View File

@@ -1,6 +1,5 @@
add_swift_library(swiftFrontend
CompilerInvocation.cpp
DependencyFileGenerator.cpp
DiagnosticVerifier.cpp
Frontend.cpp
FrontendOptions.cpp

View File

@@ -1,57 +0,0 @@
//===- DependencyFileGenerator.cpp - .d file generation -------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "swift/Frontend/DependencyFileGenerator.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
using namespace swift;
void DependencyFileGenerator::addDependency(StringRef file) {
paths.insert(file);
}
void DependencyFileGenerator::addTarget(StringRef targetName) {
if (!targetName.empty())
targets.push_back(targetName);
}
void DependencyFileGenerator::writeToStream(llvm::raw_ostream &os) const {
// Declare a helper for escaping file names for use in Makefiles.
llvm::SmallString<256> pathBuf;
auto escape = [&](StringRef raw) -> StringRef {
pathBuf.clear();
static const char badChars[] = " $#:\n";
size_t prev = 0;
for (auto index = raw.find_first_of(badChars); index != StringRef::npos;
index = raw.find_first_of(badChars, index+1)) {
pathBuf.append(raw.slice(prev, index));
if (raw[index] == '$')
pathBuf.push_back('$');
else
pathBuf.push_back('\\');
prev = index;
}
pathBuf.append(raw.substr(prev));
return pathBuf;
};
// FIXME: Xcode can't currently handle multiple targets in a single
// dependency line.
for (StringRef targetName : targets) {
os << targetName << " :";
for (StringRef path : paths)
os << ' ' << escape(path);
os << '\n';
}
}

View File

@@ -25,7 +25,6 @@
#include "swift/AST/ReferencedNameTracker.h"
#include "swift/Basic/Fallthrough.h"
#include "swift/Basic/SourceManager.h"
#include "swift/Frontend/DependencyFileGenerator.h"
#include "swift/Frontend/DiagnosticVerifier.h"
#include "swift/Frontend/Frontend.h"
#include "swift/Frontend/PrintingDiagnosticConsumer.h"
@@ -57,23 +56,54 @@ static std::string displayName(StringRef MainExecutablePath) {
}
/// Emits a Make-style dependencies file.
static bool emitMakeDependencies(DiagnosticEngine &Diags,
DependencyFileGenerator &DFG,
static bool emitMakeDependencies(DiagnosticEngine &diags,
DependencyTracker &depTracker,
const FrontendOptions &opts) {
opts.forAllOutputPaths([&DFG](StringRef target) { DFG.addTarget(target); });
std::error_code EC;
llvm::raw_fd_ostream out(opts.DependenciesFilePath, EC,
llvm::sys::fs::F_None);
if (out.has_error() || EC) {
Diags.diagnose(SourceLoc(), diag::error_opening_output,
diags.diagnose(SourceLoc(), diag::error_opening_output,
opts.DependenciesFilePath, EC.message());
out.clear_error();
return true;
}
DFG.writeToStream(out);
// Declare a helper for escaping file names for use in Makefiles.
llvm::SmallString<256> pathBuf;
auto escape = [&](StringRef raw) -> StringRef {
pathBuf.clear();
static const char badChars[] = " $#:\n";
size_t prev = 0;
for (auto index = raw.find_first_of(badChars); index != StringRef::npos;
index = raw.find_first_of(badChars, index+1)) {
pathBuf.append(raw.slice(prev, index));
if (raw[index] == '$')
pathBuf.push_back('$');
else
pathBuf.push_back('\\');
prev = index;
}
pathBuf.append(raw.substr(prev));
return pathBuf;
};
// FIXME: Xcode can't currently handle multiple targets in a single
// dependency line.
opts.forAllOutputPaths([&](StringRef targetName) {
out << targetName << " :";
// Print dependencies we've picked up during compilation.
for (StringRef path : depTracker.getDependencies())
out << ' ' << escape(path);
// Also include all other files in the module. Make-style dependencies
// need to be conservative!
for (StringRef path : opts.InputFilenames)
out << ' ' << escape(path);
out << '\n';
});
return false;
}
@@ -342,10 +372,8 @@ static bool performCompile(CompilerInstance &Instance,
if (opts.PrintClangStats && Context.getClangModuleLoader())
Context.getClangModuleLoader()->printStatistics();
if (DependencyTracker *DT = Instance.getDependencyTracker()) {
auto &DFG = *static_cast<DependencyFileGenerator*>(DT);
(void)emitMakeDependencies(Context.Diags, DFG, opts);
}
if (DependencyTracker *DT = Instance.getDependencyTracker())
(void)emitMakeDependencies(Context.Diags, *DT, opts);
if (shouldTrackReferences)
emitReferenceDependencies(Context.Diags, Instance.getPrimarySourceFile(),
@@ -594,9 +622,9 @@ int frontend_main(ArrayRef<const char *>Args,
enableDiagnosticVerifier(Instance.getSourceMgr());
}
DependencyFileGenerator DFG;
DependencyTracker depTracker;
if (!Invocation.getFrontendOptions().DependenciesFilePath.empty())
Instance.setDependencyTracker(&DFG);
Instance.setDependencyTracker(&depTracker);
if (Instance.setup(Invocation)) {
return 1;