[Frontend] -frontend -emit-loaded-module-trace.

The -frontend jobs can output a JSON file summarizing the
swiftmodules (etc.) they load during compilation.
This commit is contained in:
Huon Wilson
2017-04-19 16:49:37 -07:00
parent acf4f6e27e
commit 87aa3e6935
13 changed files with 203 additions and 1 deletions

View File

@@ -25,6 +25,7 @@
#include "ReferenceDependencies.h"
#include "TBD.h"
#include "swift/Strings.h"
#include "swift/Subsystems.h"
#include "swift/AST/ASTScope.h"
#include "swift/AST/DiagnosticsFrontend.h"
@@ -36,10 +37,12 @@
#include "swift/Basic/Dwarf.h"
#include "swift/Basic/Edit.h"
#include "swift/Basic/FileSystem.h"
#include "swift/Basic/JSONSerialization.h"
#include "swift/Basic/LLVMContext.h"
#include "swift/Basic/SourceManager.h"
#include "swift/Basic/Statistic.h"
#include "swift/Basic/Timer.h"
#include "swift/Basic/UUID.h"
#include "swift/Frontend/DiagnosticVerifier.h"
#include "swift/Frontend/Frontend.h"
#include "swift/Frontend/PrintingDiagnosticConsumer.h"
@@ -54,6 +57,7 @@
// FIXME: We're just using CompilerInstance::createOutputFile.
// This API should be sunk down to LLVM.
#include "clang/Frontend/CompilerInstance.h"
#include "clang/APINotes/Types.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/IR/LLVMContext.h"
@@ -71,6 +75,12 @@
#include <memory>
#include <unordered_set>
#if !defined(_MSC_VER) && !defined(__MINGW32__)
#include <unistd.h>
#else
#include <io.h>
#endif
using namespace swift;
static std::string displayName(StringRef MainExecutablePath) {
@@ -132,6 +142,78 @@ static bool emitMakeDependencies(DiagnosticEngine &diags,
return false;
}
namespace {
struct LoadedModuleTraceFormat {
std::string Name;
std::string Arch;
std::vector<std::string> SwiftModules;
};
}
namespace swift {
namespace json {
template <> struct ObjectTraits<LoadedModuleTraceFormat> {
static void mapping(Output &out, LoadedModuleTraceFormat &contents) {
out.mapRequired("name", contents.Name);
out.mapRequired("arch", contents.Arch);
out.mapRequired("swiftmodules", contents.SwiftModules);
}
};
}
}
static bool emitLoadedModuleTrace(ASTContext &ctxt,
DependencyTracker &depTracker,
const FrontendOptions &opts) {
std::error_code EC;
llvm::raw_fd_ostream out(opts.LoadedModuleTracePath, EC,
llvm::sys::fs::F_None);
if (out.has_error() || EC) {
ctxt.Diags.diagnose(SourceLoc(), diag::error_opening_output,
opts.LoadedModuleTracePath, EC.message());
out.clear_error();
return true;
}
llvm::SmallVector<std::string, 16> swiftModules;
// Canonicalise all the paths by opening them.
for (auto &dep : depTracker.getDependencies()) {
llvm::SmallString<256> buffer;
StringRef realPath;
int FD;
// FIXME: appropriate error handling
if (llvm::sys::fs::openFileForRead(dep, FD, &buffer)) {
// Couldn't open the file now, so let's just assume the old path was
// canonical (enough).
realPath = dep;
} else {
realPath = buffer.str();
// Not much we can do about failing to close.
(void)close(FD);
}
// Decide if this is a swiftmodule based on the extension of the raw
// dependency path, as the true file may have a different one.
auto ext = llvm::sys::path::extension(dep);
if (ext.startswith(".") &&
ext.drop_front() == SERIALIZED_MODULE_EXTENSION) {
swiftModules.push_back(realPath);
}
}
LoadedModuleTraceFormat trace = {
/*name=*/opts.ModuleName,
/*arch=*/ctxt.LangOpts.Target.getArchName(),
/*swiftmodules=*/reversePathSortedFilenames(swiftModules)};
json::Output jsonOutput(out, /*PrettyPrint=*/false);
json::jsonize(jsonOutput, trace, /*Required=*/true);
return true;
}
/// Writes SIL out to the given file.
static bool writeSIL(SILModule &SM, ModuleDecl *M, bool EmitVerboseSIL,
StringRef OutputFilename, bool SortSIL) {
@@ -539,6 +621,10 @@ static bool performCompile(std::unique_ptr<CompilerInstance> &Instance,
emitReferenceDependencies(Context.Diags, Instance->getPrimarySourceFile(),
*Instance->getDependencyTracker(), opts);
if (!opts.LoadedModuleTracePath.empty())
(void)emitLoadedModuleTrace(Context, *Instance->getDependencyTracker(),
opts);
if (Context.hadError())
return true;
@@ -1081,7 +1167,8 @@ int swift::performFrontend(ArrayRef<const char *> Args,
DependencyTracker depTracker;
if (!Invocation.getFrontendOptions().DependenciesFilePath.empty() ||
!Invocation.getFrontendOptions().ReferenceDependenciesFilePath.empty()) {
!Invocation.getFrontendOptions().ReferenceDependenciesFilePath.empty() ||
!Invocation.getFrontendOptions().LoadedModuleTracePath.empty()) {
Instance->setDependencyTracker(&depTracker);
}