Skip to content

Commit 413bbab

Browse files
authored
Merge pull request swiftlang#33032 from artemcm/ExplicitPackageBuilds
[Dependency Scanner] Add a scanner for explicit placeholder module dependencies
2 parents 73f07a6 + 965ca69 commit 413bbab

15 files changed

+541
-153
lines changed

include/swift/AST/DiagnosticsDriver.def

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
@@ -122,6 +122,9 @@ ERROR(error_conflicting_options, none,
122122
ERROR(error_option_not_supported, none,
123123
"'%0' is not supported with '%1'",
124124
(StringRef, StringRef))
125+
ERROR(error_requirement_not_met, none,
126+
"'%0' requires '%1'",
127+
(StringRef, StringRef))
125128

126129
WARNING(warn_ignore_embed_bitcode, none,
127130
"ignoring -embed-bitcode since no object file is being generated", ())

include/swift/AST/DiagnosticsFrontend.def

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,14 @@ ERROR(explicit_swift_module_map_corrupted,none,
266266
"explicit Swift module map from %0 is malformed",
267267
(StringRef))
268268

269+
ERROR(placeholder_dependency_module_map_missing,none,
270+
"cannot open Swift placeholder dependency module map from %0",
271+
(StringRef))
272+
273+
ERROR(placeholder_dependency_module_map_corrupted,none,
274+
"Swift placeholder dependency module map from %0 is malformed",
275+
(StringRef))
276+
269277
REMARK(default_previous_install_name, none,
270278
"default previous install name for %0 is %1", (StringRef, StringRef))
271279

include/swift/AST/ModuleDependencies.h

Lines changed: 80 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,29 @@ class Identifier;
3535
/// Which kind of module dependencies we are looking for.
3636
enum class ModuleDependenciesKind : int8_t {
3737
Swift,
38+
// Placeholder dependencies are a kind of dependencies used only by the
39+
// dependency scanner. They are swift modules that the scanner will not be
40+
// able to locate in its search paths and which are the responsibility of the
41+
// scanner's client to ensure are provided.
42+
//
43+
// Placeholder dependencies will be specified in the scanner's output
44+
// dependency graph where it is the responsibility of the scanner's client to
45+
// ensure required post-processing takes place to "resolve" them. In order to
46+
// do so, the client (swift driver, or any other client build system) is
47+
// expected to have access to a full dependency graph of all placeholder
48+
// dependencies and be able to replace placeholder nodes in the dependency
49+
// graph with their full dependency trees, `uniquing` common dependency module
50+
// nodes in the process.
51+
//
52+
// One example where placeholder dependencies are employed is when using
53+
// SwiftPM in Explicit Module Build mode. SwiftPM constructs a build plan for
54+
// all targets ahead-of-time. When planning a build for a target that depends
55+
// on other targets, the dependency scanning action is not able to locate
56+
// dependency target modules, because they have not yet been built. Instead,
57+
// the build system treats them as placeholder dependencies and resolves them
58+
// with `actual` dependencies in a post-processing step once dependency graphs
59+
// of all targets, individually, have been computed.
60+
SwiftPlaceholder,
3861
Clang,
3962
};
4063

@@ -43,11 +66,11 @@ enum class ModuleDependenciesKind : int8_t {
4366
/// This class is mostly an implementation detail for \c ModuleDependencies.
4467
class ModuleDependenciesStorageBase {
4568
public:
46-
const bool isSwiftModule;
69+
const ModuleDependenciesKind dependencyKind;
4770

48-
ModuleDependenciesStorageBase(bool isSwiftModule,
71+
ModuleDependenciesStorageBase(ModuleDependenciesKind dependencyKind,
4972
const std::string &compiledModulePath)
50-
: isSwiftModule(isSwiftModule),
73+
: dependencyKind(dependencyKind),
5174
compiledModulePath(compiledModulePath) { }
5275

5376
virtual ModuleDependenciesStorageBase *clone() const = 0;
@@ -103,7 +126,8 @@ class SwiftModuleDependenciesStorage : public ModuleDependenciesStorageBase {
103126
ArrayRef<StringRef> buildCommandLine,
104127
ArrayRef<StringRef> extraPCMArgs,
105128
StringRef contextHash
106-
) : ModuleDependenciesStorageBase(/*isSwiftModule=*/true, compiledModulePath),
129+
) : ModuleDependenciesStorageBase(ModuleDependenciesKind::Swift,
130+
compiledModulePath),
107131
swiftInterfaceFile(swiftInterfaceFile),
108132
compiledModuleCandidates(compiledModuleCandidates.begin(),
109133
compiledModuleCandidates.end()),
@@ -116,7 +140,7 @@ class SwiftModuleDependenciesStorage : public ModuleDependenciesStorageBase {
116140
}
117141

118142
static bool classof(const ModuleDependenciesStorageBase *base) {
119-
return base->isSwiftModule;
143+
return base->dependencyKind == ModuleDependenciesKind::Swift;
120144
}
121145
};
122146

@@ -143,7 +167,7 @@ class ClangModuleDependenciesStorage : public ModuleDependenciesStorageBase {
143167
const std::string &contextHash,
144168
const std::vector<std::string> &nonPathCommandLine,
145169
const std::vector<std::string> &fileDependencies
146-
) : ModuleDependenciesStorageBase(/*isSwiftModule=*/false,
170+
) : ModuleDependenciesStorageBase(ModuleDependenciesKind::Clang,
147171
compiledModulePath),
148172
moduleMapFile(moduleMapFile),
149173
contextHash(contextHash),
@@ -155,7 +179,35 @@ class ClangModuleDependenciesStorage : public ModuleDependenciesStorageBase {
155179
}
156180

157181
static bool classof(const ModuleDependenciesStorageBase *base) {
158-
return !base->isSwiftModule;
182+
return base->dependencyKind == ModuleDependenciesKind::Clang;
183+
}
184+
};
185+
186+
/// Describes an placeholder Swift module dependency module stub.
187+
///
188+
/// This class is mostly an implementation detail for \c ModuleDependencies.
189+
class PlaceholderSwiftModuleDependencyStorage : public ModuleDependenciesStorageBase {
190+
public:
191+
PlaceholderSwiftModuleDependencyStorage(const std::string &compiledModulePath,
192+
const std::string &moduleDocPath,
193+
const std::string &sourceInfoPath)
194+
: ModuleDependenciesStorageBase(ModuleDependenciesKind::SwiftPlaceholder,
195+
compiledModulePath),
196+
moduleDocPath(moduleDocPath),
197+
sourceInfoPath(sourceInfoPath) {}
198+
199+
ModuleDependenciesStorageBase *clone() const override {
200+
return new PlaceholderSwiftModuleDependencyStorage(*this);
201+
}
202+
203+
/// The path to the .swiftModuleDoc file.
204+
const std::string moduleDocPath;
205+
206+
/// The path to the .swiftSourceInfo file.
207+
const std::string sourceInfoPath;
208+
209+
static bool classof(const ModuleDependenciesStorageBase *base) {
210+
return base->dependencyKind == ModuleDependenciesKind::SwiftPlaceholder;
159211
}
160212
};
161213

@@ -230,6 +282,16 @@ class ModuleDependencies {
230282
fileDependencies));
231283
}
232284

285+
/// Describe a placeholder dependency swift module.
286+
static ModuleDependencies forPlaceholderSwiftModuleStub(
287+
const std::string &compiledModulePath,
288+
const std::string &moduleDocPath,
289+
const std::string &sourceInfoPath) {
290+
return ModuleDependencies(
291+
std::make_unique<PlaceholderSwiftModuleDependencyStorage>(
292+
compiledModulePath, moduleDocPath, sourceInfoPath));
293+
}
294+
233295
/// Retrieve the path to the compiled module.
234296
const std::string getCompiledModulePath() const {
235297
return storage->compiledModulePath;
@@ -243,16 +305,22 @@ class ModuleDependencies {
243305
/// Whether the dependencies are for a Swift module.
244306
bool isSwiftModule() const;
245307

308+
/// Whether this represents a placeholder module stub
309+
bool isPlaceholderSwiftModule() const;
310+
246311
ModuleDependenciesKind getKind() const {
247-
return isSwiftModule() ? ModuleDependenciesKind::Swift
248-
: ModuleDependenciesKind::Clang;
312+
return storage->dependencyKind;
249313
}
250314
/// Retrieve the dependencies for a Swift module.
251315
const SwiftModuleDependenciesStorage *getAsSwiftModule() const;
252316

253317
/// Retrieve the dependencies for a Clang module.
254318
const ClangModuleDependenciesStorage *getAsClangModule() const;
255319

320+
/// Retrieve the dependencies for a placeholder dependency module stub.
321+
const PlaceholderSwiftModuleDependencyStorage *
322+
getAsPlaceholderDependencyModule() const;
323+
256324
/// Add a dependency on the given module, if it was not already in the set.
257325
void addModuleDependency(StringRef module,
258326
llvm::StringSet<> *alreadyAddedModules = nullptr);
@@ -293,6 +361,9 @@ class ModuleDependenciesCache {
293361
/// Dependencies for Swift modules that have already been computed.
294362
llvm::StringMap<ModuleDependencies> SwiftModuleDependencies;
295363

364+
/// Dependencies for Swift placeholder dependency modules.
365+
llvm::StringMap<ModuleDependencies> PlaceholderSwiftModuleDependencies;
366+
296367
/// Dependencies for Clang modules that have already been computed.
297368
llvm::StringMap<ModuleDependencies> ClangModuleDependencies;
298369

include/swift/AST/SearchPathOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ class SearchPathOptions {
9090

9191
/// A map of explict Swift module information.
9292
std::string ExplicitSwiftModuleMap;
93+
94+
/// A map of placeholder Swift module dependency information.
95+
std::string PlaceholderDependencyModuleMap;
9396
private:
9497
static StringRef
9598
pathStringFromFrameworkSearchPath(const FrameworkSearchPath &next) {

include/swift/Frontend/ModuleInterfaceLoader.h

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,106 @@ class ExplicitSwiftModuleLoader: public SerializedModuleLoaderBase {
162162
~ExplicitSwiftModuleLoader();
163163
};
164164

165+
/// Information about explicitly specified Swift module files.
166+
struct ExplicitModuleInfo {
167+
// Path of the .swiftmodule file.
168+
StringRef modulePath;
169+
// Path of the .swiftmoduledoc file.
170+
StringRef moduleDocPath;
171+
// Path of the .swiftsourceinfo file.
172+
StringRef moduleSourceInfoPath;
173+
// Opened buffer for the .swiftmodule file.
174+
std::unique_ptr<llvm::MemoryBuffer> moduleBuffer;
175+
};
176+
177+
/// Parser of explicit module maps passed into the compiler.
178+
// [
179+
// {
180+
// "moduleName": "A",
181+
// "modulePath": "A.swiftmodule",
182+
// "docPath": "A.swiftdoc",
183+
// "sourceInfoPath": "A.swiftsourceinfo"
184+
// },
185+
// {
186+
// "moduleName": "B",
187+
// "modulePath": "B.swiftmodule",
188+
// "docPath": "B.swiftdoc",
189+
// "sourceInfoPath": "B.swiftsourceinfo"
190+
// }
191+
// ]
192+
class ExplicitModuleMapParser {
193+
public:
194+
ExplicitModuleMapParser(llvm::BumpPtrAllocator &Allocator) : Saver(Allocator) {}
195+
196+
std::error_code
197+
parseSwiftExplicitModuleMap(llvm::StringRef fileName,
198+
llvm::StringMap<ExplicitModuleInfo> &moduleMap) {
199+
using namespace llvm::yaml;
200+
// Load the input file.
201+
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> fileBufOrErr =
202+
llvm::MemoryBuffer::getFile(fileName);
203+
if (!fileBufOrErr) {
204+
return std::make_error_code(std::errc::no_such_file_or_directory);
205+
}
206+
StringRef Buffer = fileBufOrErr->get()->getBuffer();
207+
// Use a new source manager instead of the one from ASTContext because we
208+
// don't want the JSON file to be persistent.
209+
llvm::SourceMgr SM;
210+
Stream Stream(llvm::MemoryBufferRef(Buffer, fileName), SM);
211+
for (auto DI = Stream.begin(); DI != Stream.end(); ++DI) {
212+
assert(DI != Stream.end() && "Failed to read a document");
213+
if (auto *MN = dyn_cast_or_null<SequenceNode>(DI->getRoot())) {
214+
for (auto &entry : *MN) {
215+
if (parseSingleModuleEntry(entry, moduleMap)) {
216+
return std::make_error_code(std::errc::invalid_argument);
217+
}
218+
}
219+
} else {
220+
return std::make_error_code(std::errc::invalid_argument);
221+
}
222+
}
223+
return std::error_code{}; // success
224+
}
225+
226+
private:
227+
StringRef getScalaNodeText(llvm::yaml::Node *N) {
228+
SmallString<32> Buffer;
229+
return Saver.save(cast<llvm::yaml::ScalarNode>(N)->getValue(Buffer));
230+
}
231+
232+
bool parseSingleModuleEntry(llvm::yaml::Node &node,
233+
llvm::StringMap<ExplicitModuleInfo> &moduleMap) {
234+
using namespace llvm::yaml;
235+
auto *mapNode = dyn_cast<MappingNode>(&node);
236+
if (!mapNode)
237+
return true;
238+
StringRef moduleName;
239+
ExplicitModuleInfo result;
240+
for (auto &entry : *mapNode) {
241+
auto key = getScalaNodeText(entry.getKey());
242+
auto val = getScalaNodeText(entry.getValue());
243+
if (key == "moduleName") {
244+
moduleName = val;
245+
} else if (key == "modulePath") {
246+
result.modulePath = val;
247+
} else if (key == "docPath") {
248+
result.moduleDocPath = val;
249+
} else if (key == "sourceInfoPath") {
250+
result.moduleSourceInfoPath = val;
251+
} else {
252+
// Being forgiving for future fields.
253+
continue;
254+
}
255+
}
256+
if (moduleName.empty())
257+
return true;
258+
moduleMap[moduleName] = std::move(result);
259+
return false;
260+
}
261+
262+
llvm::StringSaver Saver;
263+
};
264+
165265
struct ModuleInterfaceLoaderOptions {
166266
bool remarkOnRebuildFromInterface = false;
167267
bool disableInterfaceLock = false;

include/swift/Option/FrontendOptions.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,10 @@ def swift_module_file
224224
def explict_swift_module_map
225225
: Separate<["-"], "explicit-swift-module-map-file">, MetaVarName<"<path>">,
226226
HelpText<"Specify a JSON file containing information of explict Swift modules">;
227+
228+
def placeholder_dependency_module_map
229+
: Separate<["-"], "placeholder-dependency-module-map-file">, MetaVarName<"<path>">,
230+
HelpText<"Specify a JSON file containing information of external Swift module dependencies">;
227231
}
228232

229233

lib/AST/ModuleDependencies.cpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ bool ModuleDependencies::isSwiftModule() const {
2424
return isa<SwiftModuleDependenciesStorage>(storage.get());
2525
}
2626

27+
bool ModuleDependencies::isPlaceholderSwiftModule() const {
28+
return isa<PlaceholderSwiftModuleDependencyStorage>(storage.get());
29+
}
30+
2731
/// Retrieve the dependencies for a Swift module.
2832
const SwiftModuleDependenciesStorage *
2933
ModuleDependencies::getAsSwiftModule() const {
@@ -36,6 +40,12 @@ ModuleDependencies::getAsClangModule() const {
3640
return dyn_cast<ClangModuleDependenciesStorage>(storage.get());
3741
}
3842

43+
/// Retrieve the dependencies for a placeholder dependency module stub.
44+
const PlaceholderSwiftModuleDependencyStorage *
45+
ModuleDependencies::getAsPlaceholderDependencyModule() const {
46+
return dyn_cast<PlaceholderSwiftModuleDependencyStorage>(storage.get());
47+
}
48+
3949
void ModuleDependencies::addModuleDependency(
4050
StringRef module, llvm::StringSet<> *alreadyAddedModules) {
4151
if (!alreadyAddedModules || alreadyAddedModules->insert(module).second)
@@ -102,7 +112,8 @@ ModuleDependenciesCache::getDependenciesMap(ModuleDependenciesKind kind) {
102112
switch (kind) {
103113
case ModuleDependenciesKind::Swift:
104114
return SwiftModuleDependencies;
105-
115+
case ModuleDependenciesKind::SwiftPlaceholder:
116+
return PlaceholderSwiftModuleDependencies;
106117
case ModuleDependenciesKind::Clang:
107118
return ClangModuleDependencies;
108119
}
@@ -114,7 +125,8 @@ ModuleDependenciesCache::getDependenciesMap(ModuleDependenciesKind kind) const {
114125
switch (kind) {
115126
case ModuleDependenciesKind::Swift:
116127
return SwiftModuleDependencies;
117-
128+
case ModuleDependenciesKind::SwiftPlaceholder:
129+
return PlaceholderSwiftModuleDependencies;
118130
case ModuleDependenciesKind::Clang:
119131
return ClangModuleDependencies;
120132
}
@@ -126,6 +138,7 @@ bool ModuleDependenciesCache::hasDependencies(
126138
Optional<ModuleDependenciesKind> kind) const {
127139
if (!kind) {
128140
return hasDependencies(moduleName, ModuleDependenciesKind::Swift) ||
141+
hasDependencies(moduleName, ModuleDependenciesKind::SwiftPlaceholder) ||
129142
hasDependencies(moduleName, ModuleDependenciesKind::Clang);
130143
}
131144

@@ -140,8 +153,11 @@ Optional<ModuleDependencies> ModuleDependenciesCache::findDependencies(
140153
if (auto swiftDep = findDependencies(
141154
moduleName, ModuleDependenciesKind::Swift))
142155
return swiftDep;
143-
144-
return findDependencies(moduleName, ModuleDependenciesKind::Clang);
156+
else if (auto swiftPlaceholderDep = findDependencies(
157+
moduleName, ModuleDependenciesKind::SwiftPlaceholder))
158+
return swiftPlaceholderDep;
159+
else
160+
return findDependencies(moduleName, ModuleDependenciesKind::Clang);
145161
}
146162

147163
const auto &map = getDependenciesMap(*kind);

0 commit comments

Comments
 (0)