Files
swift-mirror/include/swift/Frontend/ModuleInterfaceLoader.h
Xi Ge 0a396ab38f Front-end: add an option to ignore .swiftsourceinfo file for testing purposes
We generate .swiftsourceinfo for stdlib in the build directory because ABI checker
could issue diagnostics to the stdlib source. However, this may also change other
diagnostic tests. Both Brent and Jordan have raised concern about this. After
adding this flag, other diagnostic tests could ignore .swiftsourceinfo files even
though when they are present so our tests will reflect what most users experience
when sources for stdlib are unavailable.
2019-10-15 10:52:46 -07:00

202 lines
10 KiB
C++

//===-------- ModuleInterfaceLoader.h - Loads .swiftinterface files -------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2019 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
//
//===----------------------------------------------------------------------===//
///
/// \file This implements the logic for loading and building module
/// interfaces.
///
/// === Loading Module Interfaces ===
///
/// If there is a .swiftinterface file corresponding to a given module name
/// present in the frontend's search paths, then this module loader will look in
/// the following places for a module:
///
/// - First, look in the module cache (specified by -module-cache-path)
/// - We check here first because an existing .swiftmodule might be
/// out-of-date, necessitating a rebuild. If a cached module is out-of-date,
/// it's simply rebuilt.
/// - Next, look adjacent to the .swiftinterface. If we find a module that's
/// either loadable by this compiler, valid, and up-to-date, or totally
/// unreadable, then delegate to the serialized module loader to either load
/// or diagnose it.
/// - Finally, look in the prebuilt module cache (specified
/// by -prebuilt-module-cache-path)
///
/// If we can't find an appropriate module to load, we can always fall back and
/// recompile the .swiftinterface file.
///
/// === Dependency Checking ===
///
/// Cached modules keep track of their dependencies' last modification time and
/// file size. This means that checking if a module is up-to-date requires
/// `stat`ing the dependencies and comparing the results from the filesystem
/// with the results in the module.
///
/// Prebuilt modules, on the other hand, won't have a reliable modification
/// time, as their dependencies live in the SDK. Prebuilt modules will instead
/// keep track of the size and content hash of their dependencies.
/// In order to avoid constantly re-hashing the dependencies, however, we will
/// install a "forwarding module" in the regular cache.
/// This "forwarding module"
/// - Points to the prebuilt module on disk, and
/// - Lists modification times from the last time we verified the content
///
/// So, to recap, there are 4 kinds of modules:
/// ┌───────────────────────────────┐
/// │ ┌───┐ ┌───┐ │
/// │ │ I │ │ M │ │
/// │ └───┘ └───┘ │
/// │ .swiftinterface .swiftmodule │
/// │ ┌───┐ ┌───┐ │
/// │ │ P │ │ F │ │
/// │ └───┘ └───┘ │
/// │ Prebuilt Forwarding │
/// │ .swiftmodule .swiftmodule │
/// └───────────────────────────────┘
///
/// - Prebuilt modules have hash-based dependencies, cached modules have
/// mod-time-based dependencies
/// - Forwarding modules point to prebuilt modules and augment them with
/// modification times
///
/// === Example Cache ===
///
/// Here's an example of what's in a prebuilt cache or module cache.
///
/// Say there are 4 frameworks, each exposing a .swiftinterface file.
/// Then, we pre-build 2 of those frameworks and put them in the prebuilt cache.
/// Finally, we import all 4 of those frameworks while building a project.
///
/// For the 2 frameworks with modules in the prebuilt cache, we'll have
/// installed 2 forwarding modules. For the other 2 frameworks, we'll have
/// compiled the interfaces and put them in the module cache.
///
/// ┌─────┐
/// ┌────────────────┤ SDK ├───────────────┐
/// │ └─────┘ │
/// │ ┌────────────────┐ │ ┌────────────────┐
/// │ ┌───────┤ Framework Dirs ├────────┐ │ ┌┤ Prebuilt Cache ├┐
/// │ │ └────────────────┘ │ │ │└────────────────┘│
/// │ │ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │ │ │ ┌───┐ ┌───┐ │
/// │ │ │ I │ │ I │ │ I │ │ I │◀─┼─┼─┼───│ P │ │ P │◀═╗│
/// │ │ └───┘ └───┘ └───┘ └───┘ │ │ │ └───┘ └───┘ ║│
/// │ │ ▲ ▲ ▲ │ │ │ ▲ │ ║│
/// │ └────┼───────┼───────┼────────────┘ │ └─────╫──────┼────╫┘
/// │ │ │ └──────────────┼───────╫──────┘ ║
/// └───────┼───────┼──────────────────────┘ ║ ║
/// │ │ ┌───────────────┐ ║ ║
/// │ ┌────┼───┤ Module Cache ├────────┐ ║ ║
/// │ │ │ └───────────────┘ │ ║ ║
/// │ │ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │ ║ ║
/// │ │ │ M │ │ M │ │ F │ │ F │ │ ║ ║
/// │ │ └───┘ └───┘ └───┘ └───┘ │ ║ ║
/// │ │ │ ║ ╚════╪═╝ ║
/// │ └────────────┼───────╫────────────┘ ║
/// └───────────────┘ ╚══════════════════════════╝
///
//===----------------------------------------------------------------------===//
#ifndef SWIFT_FRONTEND_MODULEINTERFACELOADER_H
#define SWIFT_FRONTEND_MODULEINTERFACELOADER_H
#include "swift/Basic/LLVM.h"
#include "swift/Frontend/ModuleInterfaceSupport.h"
#include "swift/Serialization/SerializedModuleLoader.h"
namespace clang {
class CompilerInstance;
}
namespace unittest {
class ModuleInterfaceLoaderTest;
}
namespace swift {
class LangOptions;
class SearchPathOptions;
/// A ModuleLoader that runs a subordinate \c CompilerInvocation and
/// \c CompilerInstance to convert .swiftinterface files to .swiftmodule
/// files on the fly, caching the resulting .swiftmodules in the module cache
/// directory, and loading the serialized .swiftmodules from there.
class ModuleInterfaceLoader : public SerializedModuleLoaderBase {
friend class unittest::ModuleInterfaceLoaderTest;
explicit ModuleInterfaceLoader(
ASTContext &ctx, StringRef cacheDir, StringRef prebuiltCacheDir,
DependencyTracker *tracker, ModuleLoadingMode loadMode,
ArrayRef<std::string> PreferInterfaceForModules,
bool RemarkOnRebuildFromInterface, bool IgnoreSwiftSourceInfoFile)
: SerializedModuleLoaderBase(ctx, tracker, loadMode,
IgnoreSwiftSourceInfoFile),
CacheDir(cacheDir), PrebuiltCacheDir(prebuiltCacheDir),
RemarkOnRebuildFromInterface(RemarkOnRebuildFromInterface),
PreferInterfaceForModules(PreferInterfaceForModules)
{}
std::string CacheDir;
std::string PrebuiltCacheDir;
bool RemarkOnRebuildFromInterface;
ArrayRef<std::string> PreferInterfaceForModules;
std::error_code findModuleFilesInDirectory(
AccessPathElem ModuleID, StringRef DirPath, StringRef ModuleFilename,
StringRef ModuleDocFilename,
StringRef ModuleSourceInfoFilename,
std::unique_ptr<llvm::MemoryBuffer> *ModuleBuffer,
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer,
std::unique_ptr<llvm::MemoryBuffer> *ModuleSourceInfoBuffer) override;
bool isCached(StringRef DepPath) override;
public:
static std::unique_ptr<ModuleInterfaceLoader>
create(ASTContext &ctx, StringRef cacheDir, StringRef prebuiltCacheDir,
DependencyTracker *tracker, ModuleLoadingMode loadMode,
ArrayRef<std::string> PreferInterfaceForModules = {},
bool RemarkOnRebuildFromInterface = false,
bool IgnoreSwiftSourceInfoFile = false) {
return std::unique_ptr<ModuleInterfaceLoader>(
new ModuleInterfaceLoader(ctx, cacheDir, prebuiltCacheDir,
tracker, loadMode,
PreferInterfaceForModules,
RemarkOnRebuildFromInterface,
IgnoreSwiftSourceInfoFile));
}
/// Append visible module names to \p names. Note that names are possibly
/// duplicated, and not guaranteed to be ordered in any way.
void collectVisibleTopLevelModuleNames(
SmallVectorImpl<Identifier> &names) const override;
/// Unconditionally build \p InPath (a swiftinterface file) to \p OutPath (as
/// a swiftmodule file).
///
/// A simplified version of the core logic in #openModuleFiles.
static bool buildSwiftModuleFromSwiftInterface(
SourceManager &SourceMgr, DiagnosticEngine &Diags,
const SearchPathOptions &SearchPathOpts, const LangOptions &LangOpts,
StringRef CacheDir, StringRef PrebuiltCacheDir,
StringRef ModuleName, StringRef InPath, StringRef OutPath,
bool SerializeDependencyHashes, bool TrackSystemDependencies,
bool RemarkOnRebuildFromInterface);
};
/// Extract the specified-or-defaulted -module-cache-path that winds up in
/// the clang importer, for reuse as the .swiftmodule cache path when
/// building a ModuleInterfaceLoader.
std::string
getModuleCachePathFromClang(const clang::CompilerInstance &Instance);
}
#endif