|
| 1 | +//===--- ParseableInterfaceModuleLoader.h - Loads .swiftinterface files ---===// |
| 2 | +// |
| 3 | +// This source file is part of the Swift.org open source project |
| 4 | +// |
| 5 | +// Copyright (c) 2019 Apple Inc. and the Swift project authors |
| 6 | +// Licensed under Apache License v2.0 with Runtime Library Exception |
| 7 | +// |
| 8 | +// See https://swift.org/LICENSE.txt for license information |
| 9 | +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| 10 | +// |
| 11 | +//===----------------------------------------------------------------------===// |
| 12 | +/// \file This implements the logic for loading and building parseable module |
| 13 | +/// interfaces. |
| 14 | +/// |
| 15 | +/// === Loading Parseable Modules === |
| 16 | +/// |
| 17 | +/// If there is a .swiftinterface file corresponding to a given module name |
| 18 | +/// present in the frontend's search paths, then this module loader will look in |
| 19 | +/// the following places for a module: |
| 20 | +/// |
| 21 | +/// - First, look in the module cache (specified by -module-cache-path) |
| 22 | +/// - We check here first because an existing .swiftmodule might be |
| 23 | +/// out-of-date, necessitating a rebuild. If a cached module is out-of-date, |
| 24 | +/// it's simply rebuilt. |
| 25 | +/// - Next, look adjacent to the .swiftinterface. If we find a module that's |
| 26 | +/// either loadable by this compiler, valid, and up-to-date, or totally |
| 27 | +/// unreadable, then delegate to the serialized module loader to either load |
| 28 | +/// or diagnose it. |
| 29 | +/// - Finally, look in the prebuilt module cache (specified |
| 30 | +/// by -prebuilt-module-cache-path) |
| 31 | +/// |
| 32 | +/// If we can't find an appropriate module to load, we can always fall back and |
| 33 | +/// recompile the .swiftinterface file. |
| 34 | +/// |
| 35 | +/// === Dependency Checking === |
| 36 | +/// |
| 37 | +/// Cached modules keep track of their dependencies' last modification time and |
| 38 | +/// file size. This means that checking if a module is up-to-date requires |
| 39 | +/// `stat`ing the dependencies and comparing the results from the filesystem |
| 40 | +/// with the results in the module. |
| 41 | +/// |
| 42 | +/// Prebuilt modules, on the other hand, won't have a reliable modification |
| 43 | +/// time, as their dependencies live in the SDK. Prebuilt modules will instead |
| 44 | +/// keep track of the size and content hash of their dependencies. |
| 45 | +/// In order to avoid constantly re-hashing the dependencies, however, we will |
| 46 | +/// install a "forwarding module" in the regular cache. |
| 47 | +/// This "forwarding module" |
| 48 | +/// - Points to the prebuilt module on disk, and |
| 49 | +/// - Lists modification times from the last time we verified the content |
| 50 | +/// |
| 51 | +/// So, to recap, there are 4 kinds of modules: |
| 52 | +/// ┌───────────────────────────────┐ |
| 53 | +/// │ ┌───┐ ┌───┐ │ |
| 54 | +/// │ │ I │ │ M │ │ |
| 55 | +/// │ └───┘ └───┘ │ |
| 56 | +/// │ .swiftinterface .swiftmodule │ |
| 57 | +/// │ ┌───┐ ┌───┐ │ |
| 58 | +/// │ │ P │ │ F │ │ |
| 59 | +/// │ └───┘ └───┘ │ |
| 60 | +/// │ Prebuilt Forwarding │ |
| 61 | +/// │ .swiftmodule .swiftmodule │ |
| 62 | +/// └───────────────────────────────┘ |
| 63 | +/// |
| 64 | +/// - Prebuilt modules have hash-based dependencies, cached modules have |
| 65 | +/// mod-time-based dependencies |
| 66 | +/// - Forwarding modules point to prebuilt modules and augment them with |
| 67 | +/// modification times |
| 68 | +/// |
| 69 | +/// === Example Cache === |
| 70 | +/// |
| 71 | +/// Here's an example of what's in a prebuilt cache or module cache. |
| 72 | +/// |
| 73 | +/// Say there are 4 frameworks, each exposing a .swiftinterface file. |
| 74 | +/// Then, we pre-build 2 of those frameworks and put them in the prebuilt cache. |
| 75 | +/// Finally, we import all 4 of those frameworks while building a project. |
| 76 | +/// |
| 77 | +/// For the 2 frameworks with modules in the prebuilt cache, we'll have |
| 78 | +/// installed 2 forwarding modules. For the other 2 frameworks, we'll have |
| 79 | +/// compiled the interfaces and put them in the module cache. |
| 80 | +/// |
| 81 | +/// ┌─────┐ |
| 82 | +/// ┌─────────────────────────────┤ SDK ├─────────────────────────┐ |
| 83 | +/// │ ┌────────────────┐ └─────┘ ┌────────────────┐ │ |
| 84 | +/// │ ┌───────┤ Framework Dirs ├────────┐ ┌┤ Prebuilt Cache ├┐ │ |
| 85 | +/// │ │ └────────────────┘ │ │└────────────────┘│ │ |
| 86 | +/// │ │ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │ │ ┌───┐ ┌───┐ │ │ |
| 87 | +/// │ │ │ I │ │ I │ │ I │ │ I │◀─┼───┼───│ P │ │ P │◀═╗│ │ |
| 88 | +/// │ │ └───┘ └───┘ └───┘ └───┘ │ │ └───┘ └───┘ ║│ │ |
| 89 | +/// │ │ ▲ ▲ ▲ │ │ ▲ │ ║│ │ |
| 90 | +/// │ └────┼───────┼───────┼────────────┘ └─────╫──────┼────╫┘ │ |
| 91 | +/// │ │ │ └──────────────────────╫──────┘ ║ │ |
| 92 | +/// └───────┼───────┼──────────────────────────────╫───────────╫──┘ |
| 93 | +/// │ │ ┌───────────────┐ ║ ║ |
| 94 | +/// │ ┌────┼───┤ Module Cache ├────────┐ ║ ║ |
| 95 | +/// │ │ │ └───────────────┘ │ ║ ║ |
| 96 | +/// │ │ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │ ║ ║ |
| 97 | +/// │ │ │ M │ │ M │ │ F │ │ F │ │ ║ ║ |
| 98 | +/// │ │ └───┘ └───┘ └───┘ └───┘ │ ║ ║ |
| 99 | +/// │ │ │ ║ ╚════╪═╝ ║ |
| 100 | +/// │ └────────────┼───────╫────────────┘ ║ |
| 101 | +/// └───────────────┘ ╚══════════════════════════╝ |
| 102 | +/// |
| 103 | +//===----------------------------------------------------------------------===// |
| 104 | + |
| 105 | +#include "swift/Basic/LLVM.h" |
| 106 | +#include "swift/Frontend/ParseableInterfaceSupport.h" |
| 107 | +#include "swift/Serialization/SerializedModuleLoader.h" |
| 108 | + |
| 109 | +namespace clang { |
| 110 | + class CompilerInstance; |
| 111 | +} |
| 112 | + |
| 113 | +namespace swift { |
| 114 | + |
| 115 | +/// A ModuleLoader that runs a subordinate \c CompilerInvocation and |
| 116 | +/// \c CompilerInstance to convert .swiftinterface files to .swiftmodule |
| 117 | +/// files on the fly, caching the resulting .swiftmodules in the module cache |
| 118 | +/// directory, and loading the serialized .swiftmodules from there. |
| 119 | +class ParseableInterfaceModuleLoader : public SerializedModuleLoaderBase { |
| 120 | + explicit ParseableInterfaceModuleLoader(ASTContext &ctx, StringRef cacheDir, |
| 121 | + StringRef prebuiltCacheDir, |
| 122 | + DependencyTracker *tracker, |
| 123 | + ModuleLoadingMode loadMode) |
| 124 | + : SerializedModuleLoaderBase(ctx, tracker, loadMode), |
| 125 | + CacheDir(cacheDir), PrebuiltCacheDir(prebuiltCacheDir) |
| 126 | + {} |
| 127 | + |
| 128 | + std::string CacheDir; |
| 129 | + std::string PrebuiltCacheDir; |
| 130 | + |
| 131 | + std::error_code findModuleFilesInDirectory( |
| 132 | + AccessPathElem ModuleID, StringRef DirPath, StringRef ModuleFilename, |
| 133 | + StringRef ModuleDocFilename, |
| 134 | + std::unique_ptr<llvm::MemoryBuffer> *ModuleBuffer, |
| 135 | + std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer) override; |
| 136 | + |
| 137 | + |
| 138 | +public: |
| 139 | + static std::unique_ptr<ParseableInterfaceModuleLoader> |
| 140 | + create(ASTContext &ctx, StringRef cacheDir, StringRef prebuiltCacheDir, |
| 141 | + DependencyTracker *tracker, ModuleLoadingMode loadMode) { |
| 142 | + return std::unique_ptr<ParseableInterfaceModuleLoader>( |
| 143 | + new ParseableInterfaceModuleLoader(ctx, cacheDir, prebuiltCacheDir, |
| 144 | + tracker, loadMode)); |
| 145 | + } |
| 146 | + |
| 147 | + /// Unconditionally build \p InPath (a swiftinterface file) to \p OutPath (as |
| 148 | + /// a swiftmodule file). |
| 149 | + /// |
| 150 | + /// A simplified version of the core logic in #openModuleFiles, mostly for |
| 151 | + /// testing purposes. |
| 152 | + static bool buildSwiftModuleFromSwiftInterface( |
| 153 | + ASTContext &Ctx, StringRef CacheDir, StringRef PrebuiltCacheDir, |
| 154 | + StringRef ModuleName, StringRef InPath, StringRef OutPath, |
| 155 | + bool SerializeDependencyHashes); |
| 156 | +}; |
| 157 | + |
| 158 | +/// Extract the specified-or-defaulted -module-cache-path that winds up in |
| 159 | +/// the clang importer, for reuse as the .swiftmodule cache path when |
| 160 | +/// building a ParseableInterfaceModuleLoader. |
| 161 | +std::string |
| 162 | +getModuleCachePathFromClang(const clang::CompilerInstance &Instance); |
| 163 | + |
| 164 | +} |
0 commit comments