Skip to content

Commit d6484c8

Browse files
committed
[Dependency scanning] Scan and record bridging header dependencies.
When there is a bridging header associated with the module, scan and record its dependencies. Note them in a separate structure to capture the specific dependencies of the bridging header.
1 parent 08ec878 commit d6484c8

File tree

11 files changed

+309
-77
lines changed

11 files changed

+309
-77
lines changed

include/swift/AST/ModuleDependencies.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ class SwiftModuleDependenciesStorage : public ModuleDependenciesStorageBase {
7171
/// Source files on which the bridging header depends.
7272
std::vector<std::string> bridgingSourceFiles;
7373

74+
/// (Clang) modules on which the bridging header depends.
75+
std::vector<std::string> bridgingModuleDependencies;
76+
7477
SwiftModuleDependenciesStorage(
7578
const std::string &compiledModulePath,
7679
const Optional<std::string> &swiftInterfaceFile
@@ -194,8 +197,18 @@ class ModuleDependencies {
194197
void addModuleDependencies(const SourceFile &sf,
195198
llvm::StringSet<> &alreadyAddedModules);
196199

200+
/// Get the bridging header.
201+
Optional<std::string> getBridgingHeader() const;
202+
197203
/// Add a bridging header to a Swift module's dependencies.
198204
void addBridgingHeader(StringRef bridgingHeader);
205+
206+
/// Add source files that the bridging header depends on.
207+
void addBridgingSourceFile(StringRef bridgingSourceFile);
208+
209+
/// Add (Clang) module on which the bridging header depends.
210+
void addBridgingModuleDependency(StringRef module,
211+
llvm::StringSet<> &alreadyAddedModules);
199212
};
200213

201214
using ModuleDependencyID = std::pair<std::string, ModuleDependenciesKind>;
@@ -273,6 +286,10 @@ class ModuleDependenciesCache {
273286
ModuleDependencies dependencies,
274287
ModuleDependenciesKind kind);
275288

289+
/// Update stored dependencies for the given module.
290+
void updateDependencies(ModuleDependencyID moduleID,
291+
ModuleDependencies dependencies);
292+
276293
/// Reference the list of all module dependencies.
277294
const std::vector<ModuleDependencyID> &getAllModules() const {
278295
return AllModules;

include/swift/ClangImporter/ClangImporter.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,19 @@ class ClangImporter final : public ClangModuleLoader {
372372
Optional<ModuleDependencies> getModuleDependencies(
373373
StringRef moduleName, ModuleDependenciesCache &cache) override;
374374

375+
/// Add dependency information for the bridging header.
376+
///
377+
/// \param moduleName the name of the Swift module whose dependency
378+
/// information will be augmented with information about the given
379+
/// bridging header.
380+
///
381+
/// \param cache The module dependencies cache to update, with information
382+
/// about new Clang modules discovered along the way.
383+
///
384+
/// \returns \c true if an error occurred, \c false otherwise
385+
bool addBridgingHeaderDependencies(
386+
StringRef moduleName, ModuleDependenciesCache &cache);
387+
375388
clang::TargetInfo &getTargetInfo() const override;
376389
clang::ASTContext &getClangASTContext() const override;
377390
clang::Preprocessor &getClangPreprocessor() const override;

lib/AST/ModuleDependencies.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,31 @@ void ModuleDependencies::addModuleDependencies(
7272
swiftStorage->sourceFiles.push_back(fileName);
7373
}
7474

75+
Optional<std::string> ModuleDependencies::getBridgingHeader() const {
76+
auto swiftStorage = cast<SwiftModuleDependenciesStorage>(storage.get());
77+
return swiftStorage->bridgingHeaderFile;
78+
}
79+
7580
void ModuleDependencies::addBridgingHeader(StringRef bridgingHeader) {
7681
auto swiftStorage = cast<SwiftModuleDependenciesStorage>(storage.get());
7782
assert(!swiftStorage->bridgingHeaderFile);
7883
swiftStorage->bridgingHeaderFile = bridgingHeader;
7984
}
8085

86+
/// Add source files that the bridging header depends on.
87+
void ModuleDependencies::addBridgingSourceFile(StringRef bridgingSourceFile) {
88+
auto swiftStorage = cast<SwiftModuleDependenciesStorage>(storage.get());
89+
swiftStorage->bridgingSourceFiles.push_back(bridgingSourceFile);
90+
}
91+
92+
/// Add (Clang) module on which the bridging header depends.
93+
void ModuleDependencies::addBridgingModuleDependency(
94+
StringRef module, llvm::StringSet<> &alreadyAddedModules) {
95+
auto swiftStorage = cast<SwiftModuleDependenciesStorage>(storage.get());
96+
if (alreadyAddedModules.insert(module).second)
97+
swiftStorage->bridgingModuleDependencies.push_back(module);
98+
}
99+
81100
llvm::StringMap<ModuleDependencies> &
82101
ModuleDependenciesCache::getDependenciesMap(ModuleDependenciesKind kind) {
83102
switch (kind) {
@@ -141,3 +160,11 @@ void ModuleDependenciesCache::recordDependencies(
141160

142161
AllModules.push_back({moduleName, kind});
143162
}
163+
164+
void ModuleDependenciesCache::updateDependencies(
165+
ModuleDependencyID moduleID, ModuleDependencies dependencies) {
166+
auto &map = getDependenciesMap(moduleID.second);
167+
auto known = map.find(moduleID.first);
168+
assert(known != map.end() && "Not yet added to map");
169+
known->second = std::move(dependencies);
170+
}

lib/ClangImporter/ClangModuleDependencyScanner.cpp

Lines changed: 166 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -97,61 +97,44 @@ namespace {
9797
};
9898
}
9999

100-
Optional<ModuleDependencies> ClangImporter::getModuleDependencies(
101-
StringRef moduleName, ModuleDependenciesCache &cache) {
102-
// Check whether there is already a cached result.
103-
if (auto found = cache.findDependencies(
104-
moduleName, ModuleDependenciesKind::Clang))
105-
return found;
106-
107-
// Retrieve or create the shared state.
108-
auto clangImpl = cache.getClangImpl();
109-
if (!clangImpl) {
110-
clangImpl = new ClangModuleDependenciesCacheImpl();
111-
cache.setClangImpl(clangImpl,
112-
[](ClangModuleDependenciesCacheImpl *ptr) {
113-
delete ptr;
114-
});
115-
}
116-
117-
// Reform the Clang importer options.
118-
// FIXME: Just save a reference or copy so we can get this back.
119-
ClangImporterOptions importerOpts;
120-
121-
// Determine the command-line arguments for dependency scanning.
122-
auto &ctx = Impl.SwiftContext;
123-
std::vector<std::string> commandLineArgs;
124-
commandLineArgs.push_back("clang");
125-
importer::getNormalInvocationArguments(commandLineArgs, ctx, importerOpts);
126-
importer::addCommonInvocationArguments(commandLineArgs, ctx, importerOpts);
127-
128-
// Add search paths.
129-
// Note: This is handled differently for the Clang importer itself, which
130-
// adds search paths to Clang's data structures rather than to its
131-
// command line.
100+
// Add search paths.
101+
// Note: This is handled differently for the Clang importer itself, which
102+
// adds search paths to Clang's data structures rather than to its
103+
// command line.
104+
static void addSearchPathInvocationArguments(
105+
std::vector<std::string> &invocationArgStrs,
106+
ASTContext &ctx,
107+
const ClangImporterOptions &importerOpts) {
132108
SearchPathOptions &searchPathOpts = ctx.SearchPathOpts;
133109
for (const auto &framepath : searchPathOpts.FrameworkSearchPaths) {
134-
commandLineArgs.push_back(framepath.IsSystem ? "-iframework" : "-F");
135-
commandLineArgs.push_back(framepath.Path);
110+
invocationArgStrs.push_back(framepath.IsSystem ? "-iframework" : "-F");
111+
invocationArgStrs.push_back(framepath.Path);
136112
}
137113

138114
for (auto path : searchPathOpts.ImportSearchPaths) {
139-
commandLineArgs.push_back("-I");
140-
commandLineArgs.push_back(path);
115+
invocationArgStrs.push_back("-I");
116+
invocationArgStrs.push_back(path);
141117
}
118+
}
142119

143-
// HACK! Replace the module import buffer name with the source file hack.
144-
auto importHackFile = clangImpl->getImportHackFile();
145-
if (!importHackFile) {
146-
// FIXME: Emit a diagnostic here.
147-
return None;
148-
}
120+
/// Create the command line for Clang dependency scanning.
121+
static std::vector<std::string> getClangDepScanningInvocationArguments(
122+
ASTContext &ctx,
123+
const ClangImporterOptions &importerOpts,
124+
StringRef sourceFileName) {
125+
std::vector<std::string> commandLineArgs;
126+
127+
// Form the basic command line.
128+
commandLineArgs.push_back("clang");
129+
importer::getNormalInvocationArguments(commandLineArgs, ctx, importerOpts);
130+
importer::addCommonInvocationArguments(commandLineArgs, ctx, importerOpts);
131+
addSearchPathInvocationArguments(commandLineArgs, ctx, importerOpts);
149132

150133
auto sourceFilePos = std::find(
151134
commandLineArgs.begin(), commandLineArgs.end(),
152135
"<swift-imported-modules>");
153136
assert(sourceFilePos != commandLineArgs.end());
154-
*sourceFilePos = *importHackFile;
137+
*sourceFilePos = sourceFileName;
155138

156139
// HACK! Drop the -fmodule-format= argument and the one that
157140
// precedes it.
@@ -187,34 +170,36 @@ Optional<ModuleDependencies> ClangImporter::getModuleDependencies(
187170
commandLineArgs.push_back("-sys-header-deps");
188171
commandLineArgs.push_back("-Wno-error");
189172

190-
// HACK! Trick out a .m file to use to import the module we name.
191-
std::string moduleNameHackDefine =
192-
("-DHACK_MODULE_NAME=" + moduleName).str();
193-
commandLineArgs.push_back(moduleNameHackDefine);
194-
commandLineArgs.push_back("-fmodules-ignore-macro=HACK_MODULE_NAME");
195-
196-
std::string workingDir =
197-
ctx.SourceMgr.getFileSystem()->getCurrentWorkingDirectory().get();
198-
CompileCommand command(workingDir, *importHackFile, commandLineArgs, "-");
199-
SingleCommandCompilationDatabase database(command);
200-
201-
auto clangDependencies = clangImpl->tool.getFullDependencies(
202-
database, workingDir, clangImpl->alreadySeen);
173+
return commandLineArgs;
174+
}
203175

204-
if (!clangDependencies) {
205-
// FIXME: Route this to a normal diagnostic.
206-
llvm::logAllUnhandledErrors(clangDependencies.takeError(), llvm::errs());
207-
return None;
176+
/// Get or create the Clang-specific
177+
static ClangModuleDependenciesCacheImpl *getOrCreateClangImpl(
178+
ModuleDependenciesCache &cache) {
179+
auto clangImpl = cache.getClangImpl();
180+
if (!clangImpl) {
181+
clangImpl = new ClangModuleDependenciesCacheImpl();
182+
cache.setClangImpl(clangImpl,
183+
[](ClangModuleDependenciesCacheImpl *ptr) {
184+
delete ptr;
185+
});
208186
}
209187

210-
// Record module dependencies for each module we found.
211-
llvm::StringSet<> alreadyAddedModules;
212-
for (const auto &clangModuleDep : clangDependencies->DiscoveredModules) {
188+
return clangImpl;
189+
}
190+
191+
/// Record the module dependencies we found by scanning Clang modules into
192+
/// the module dependencies cache.
193+
static void recordModuleDependencies(
194+
ModuleDependenciesCache &cache,
195+
const FullDependenciesResult &clangDependencies) {
196+
for (const auto &clangModuleDep : clangDependencies.DiscoveredModules) {
213197
// If we've already cached this information, we're done.
214198
if (cache.hasDependencies(clangModuleDep.ModuleName,
215199
ModuleDependenciesKind::Clang))
216200
continue;
217201

202+
// File dependencies for this module.
218203
std::vector<std::string> fileDeps;
219204
for (const auto &fileDep : clangModuleDep.FileDeps) {
220205
fileDeps.push_back(fileDep.getKey());
@@ -223,9 +208,11 @@ Optional<ModuleDependencies> ClangImporter::getModuleDependencies(
223208
// Create a module filename.
224209
// FIXME: Query Clang to determine an appropriate hashed name for the
225210
// module file.
226-
llvm::SmallString<32> modulePath = moduleName;
211+
llvm::SmallString<32> modulePath(clangModuleDep.ModuleName);
227212
llvm::sys::path::replace_extension(modulePath, "pcm");
228213

214+
// Module-level dependencies.
215+
llvm::StringSet<> alreadyAddedModules;
229216
auto dependencies = ModuleDependencies::forClangModule(
230217
modulePath.str(), clangModuleDep.ClangModuleMapFile, fileDeps);
231218
for (const auto &moduleName : clangModuleDep.ClangModuleDeps) {
@@ -236,6 +223,121 @@ Optional<ModuleDependencies> ClangImporter::getModuleDependencies(
236223
std::move(dependencies),
237224
ModuleDependenciesKind::Clang);
238225
}
226+
}
227+
228+
Optional<ModuleDependencies> ClangImporter::getModuleDependencies(
229+
StringRef moduleName, ModuleDependenciesCache &cache) {
230+
// Check whether there is already a cached result.
231+
if (auto found = cache.findDependencies(
232+
moduleName, ModuleDependenciesKind::Clang))
233+
return found;
234+
235+
// Retrieve or create the shared state.
236+
auto clangImpl = getOrCreateClangImpl(cache);
237+
238+
// HACK! Replace the module import buffer name with the source file hack.
239+
auto importHackFile = clangImpl->getImportHackFile();
240+
if (!importHackFile) {
241+
// FIXME: Emit a diagnostic here.
242+
return None;
243+
}
244+
245+
// Reform the Clang importer options.
246+
// FIXME: Just save a reference or copy so we can get this back.
247+
ClangImporterOptions importerOpts;
248+
249+
// Determine the command-line arguments for dependency scanning.
250+
auto &ctx = Impl.SwiftContext;
251+
std::vector<std::string> commandLineArgs =
252+
getClangDepScanningInvocationArguments(
253+
ctx, importerOpts, *importHackFile);
254+
255+
// HACK! Trick out a .m file to use to import the module we name.
256+
std::string moduleNameHackDefine =
257+
("-DHACK_MODULE_NAME=" + moduleName).str();
258+
commandLineArgs.push_back(moduleNameHackDefine);
259+
commandLineArgs.push_back("-fmodules-ignore-macro=HACK_MODULE_NAME");
260+
261+
std::string workingDir =
262+
ctx.SourceMgr.getFileSystem()->getCurrentWorkingDirectory().get();
263+
CompileCommand command(workingDir, *importHackFile, commandLineArgs, "-");
264+
SingleCommandCompilationDatabase database(command);
265+
266+
auto clangDependencies = clangImpl->tool.getFullDependencies(
267+
database, workingDir, clangImpl->alreadySeen);
268+
269+
if (!clangDependencies) {
270+
// FIXME: Route this to a normal diagnostic.
271+
llvm::logAllUnhandledErrors(clangDependencies.takeError(), llvm::errs());
272+
return None;
273+
}
274+
275+
// Record module dependencies for each module we found.
276+
recordModuleDependencies(cache, *clangDependencies);
239277

240278
return cache.findDependencies(moduleName, ModuleDependenciesKind::Clang);
241279
}
280+
281+
bool ClangImporter::addBridgingHeaderDependencies(
282+
StringRef moduleName,
283+
ModuleDependenciesCache &cache) {
284+
auto targetModule = *cache.findDependencies(
285+
moduleName, ModuleDependenciesKind::Swift);
286+
287+
// If we've already recorded bridging header dependencies, we're done.
288+
auto swiftDeps = targetModule.getAsSwiftModule();
289+
if (!swiftDeps->bridgingSourceFiles.empty() ||
290+
!swiftDeps->bridgingModuleDependencies.empty())
291+
return false;
292+
293+
// Retrieve or create the shared state.
294+
auto clangImpl = getOrCreateClangImpl(cache);
295+
296+
// Reform the Clang importer options.
297+
// FIXME: Just save a reference or copy so we can get this back.
298+
ClangImporterOptions importerOpts;
299+
300+
// Retrieve the bridging header.
301+
std::string bridgingHeader = *targetModule.getBridgingHeader();
302+
303+
// Determine the command-line arguments for dependency scanning.
304+
auto &ctx = Impl.SwiftContext;
305+
std::vector<std::string> commandLineArgs =
306+
getClangDepScanningInvocationArguments(
307+
ctx, importerOpts, bridgingHeader);
308+
309+
std::string workingDir =
310+
ctx.SourceMgr.getFileSystem()->getCurrentWorkingDirectory().get();
311+
CompileCommand command(workingDir, bridgingHeader, commandLineArgs, "-");
312+
SingleCommandCompilationDatabase database(command);
313+
314+
auto clangDependencies = clangImpl->tool.getFullDependencies(
315+
database, workingDir, clangImpl->alreadySeen);
316+
317+
if (!clangDependencies) {
318+
// FIXME: Route this to a normal diagnostic.
319+
llvm::logAllUnhandledErrors(clangDependencies.takeError(), llvm::errs());
320+
return true;
321+
}
322+
323+
// Record module dependencies for each module we found.
324+
recordModuleDependencies(cache, *clangDependencies);
325+
326+
// Record dependencies for the source files the bridging header includes.
327+
for (const auto &fileDep : clangDependencies->FullDeps.FileDeps)
328+
targetModule.addBridgingSourceFile(fileDep);
329+
330+
// ... and all module dependencies.
331+
llvm::StringSet<> alreadyAddedModules;
332+
for (const auto &moduleDep : clangDependencies->FullDeps.ClangModuleDeps) {
333+
targetModule.addBridgingModuleDependency(
334+
moduleDep.ModuleName, alreadyAddedModules);
335+
}
336+
337+
// Update the cache with the new information for the module.
338+
cache.updateDependencies(
339+
{moduleName, ModuleDependenciesKind::Swift},
340+
std::move(targetModule));
341+
342+
return false;
343+
}

0 commit comments

Comments
 (0)