Skip to content

Commit c5a63f8

Browse files
committed
[clang][clang-scan-deps] Add an experimental C API for returning the list of
module and file dependencies of a module for a particular compiler invocation rdar://64538073
1 parent 872ec70 commit c5a63f8

File tree

9 files changed

+209
-10
lines changed

9 files changed

+209
-10
lines changed

clang/include/clang-c/Dependencies.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,14 @@ CINDEX_LINKAGE CXDependencyScannerWorker
169169
clang_experimental_DependencyScannerWorker_create_v0(
170170
CXDependencyScannerService);
171171

172+
/**
173+
* Same as \c clang_experimental_DependencyScannerWorker_create_v0 except that
174+
* module name is passed.
175+
*/
176+
CINDEX_LINKAGE CXDependencyScannerWorker
177+
clang_experimental_DependencyScannerWorkerByModName_create_v0(
178+
CXDependencyScannerService, const char *LookedUpModuleName);
179+
172180
CINDEX_LINKAGE void clang_experimental_DependencyScannerWorker_dispose_v0(
173181
CXDependencyScannerWorker);
174182

@@ -222,6 +230,19 @@ clang_experimental_DependencyScannerWorker_getFileDependencies_v1(
222230
CXDependencyScannerWorker Worker, int argc, const char *const *argv,
223231
const char *WorkingDirectory, CXModuleDiscoveredCallback *MDC,
224232
void *Context, CXString *error);
233+
234+
/**
235+
* Same as \c clang_experimental_DependencyScannerWorker_getFileDependencies_v1,
236+
* but \c Worker must have been created with
237+
* \c clang_experimental_DependencyScannerWorkerByModName_create_v0 and the
238+
* source file name shouldn't be passed in the argument list.
239+
*/
240+
CINDEX_LINKAGE CXFileDependencies *
241+
clang_experimental_DependencyScannerWorkerByModName_getFileDependencies_v1(
242+
CXDependencyScannerWorker Worker, int argc, const char *const *argv,
243+
const char *WorkingDirectory, CXModuleDiscoveredCallback *MDC,
244+
void *Context, CXString *error);
245+
225246
/**
226247
* @}
227248
*/

clang/include/clang/Frontend/CompilerInstance.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -749,6 +749,8 @@ class CompilerInstance : public ModuleLoader {
749749
bool RemoveFileOnSignal, bool UseTemporary,
750750
bool CreateMissingDirectories);
751751

752+
const char *LookedUpModuleName = nullptr;
753+
752754
public:
753755
std::unique_ptr<raw_pwrite_stream> createNullOutputFile();
754756

@@ -785,6 +787,8 @@ class CompilerInstance : public ModuleLoader {
785787

786788
bool loadModuleFile(StringRef FileName);
787789

790+
void setLookedUpModuleName(const char *N) { LookedUpModuleName = N; }
791+
788792
private:
789793
/// Find a module, potentially compiling it, before reading its AST. This is
790794
/// the guts of loadModule.

clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ class DependencyConsumer {
5454
/// using the regular processing run.
5555
class DependencyScanningWorker {
5656
public:
57-
DependencyScanningWorker(DependencyScanningService &Service);
57+
DependencyScanningWorker(DependencyScanningService &Service,
58+
const char *LookedUpModuleName = nullptr);
5859

5960
/// Run the dependency scanning tool for a given clang driver invocation (as
6061
/// specified for the given Input in the CDB), and report the discovered
@@ -90,6 +91,8 @@ class DependencyScanningWorker {
9091
/// worker. If null, the file manager will not be reused.
9192
llvm::IntrusiveRefCntPtr<FileManager> Files;
9293
ScanningOutputFormat Format;
94+
95+
const char *LookedUpModuleName = nullptr;
9396
};
9497

9598
} // end namespace dependencies

clang/lib/Frontend/CompilerInstance.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -994,8 +994,19 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
994994
getSourceManager().clearIDTables();
995995

996996
if (Act.BeginSourceFile(*this, FIF)) {
997-
if (llvm::Error Err = Act.Execute()) {
998-
consumeError(std::move(Err)); // FIXME this drops errors on the floor.
997+
if (LookedUpModuleName) {
998+
FileID MainFileID = SourceMgr->getMainFileID();
999+
SourceLocation FileStart = SourceMgr->getLocForStartOfFile(MainFileID);
1000+
SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path;
1001+
IdentifierInfo *ModuleID = PP->getIdentifierInfo(LookedUpModuleName);
1002+
Path.push_back(std::make_pair(ModuleID, FileStart));
1003+
auto ModResult = loadModule(FileStart, Path, Module::Hidden, false);
1004+
PPCallbacks *CB = PP->getPPCallbacks();
1005+
CB->moduleImport(SourceLocation(), Path, ModResult);
1006+
} else {
1007+
if (llvm::Error Err = Act.Execute()) {
1008+
consumeError(std::move(Err)); // FIXME this drops errors on the floor.
1009+
}
9991010
}
10001011
Act.EndSourceFile();
10011012
}

clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,10 @@ class DependencyScanningAction : public tooling::ToolAction {
9393
StringRef WorkingDirectory, DependencyConsumer &Consumer,
9494
llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS,
9595
ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings,
96-
ScanningOutputFormat Format)
96+
ScanningOutputFormat Format, const char *LookedUpModuleName)
9797
: WorkingDirectory(WorkingDirectory), Consumer(Consumer),
98-
DepFS(std::move(DepFS)), PPSkipMappings(PPSkipMappings),
99-
Format(Format) {}
98+
DepFS(std::move(DepFS)), PPSkipMappings(PPSkipMappings), Format(Format),
99+
LookedUpModuleName(LookedUpModuleName) {}
100100

101101
bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation,
102102
FileManager *FileMgr,
@@ -108,6 +108,7 @@ class DependencyScanningAction : public tooling::ToolAction {
108108
// Create a compiler instance to handle the actual work.
109109
CompilerInstance Compiler(std::move(PCHContainerOps));
110110
Compiler.setInvocation(std::move(Invocation));
111+
Compiler.setLookedUpModuleName(LookedUpModuleName);
111112

112113
// Don't print 'X warnings and Y errors generated'.
113114
Compiler.getDiagnosticOpts().ShowCarets = false;
@@ -212,13 +213,14 @@ class DependencyScanningAction : public tooling::ToolAction {
212213
llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS;
213214
ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings;
214215
ScanningOutputFormat Format;
216+
const char *LookedUpModuleName;
215217
};
216218

217219
} // end anonymous namespace
218220

219221
DependencyScanningWorker::DependencyScanningWorker(
220-
DependencyScanningService &Service)
221-
: Format(Service.getFormat()) {
222+
DependencyScanningService &Service, const char *LookedUpModuleName)
223+
: Format(Service.getFormat()), LookedUpModuleName(LookedUpModuleName) {
222224
DiagOpts = new DiagnosticOptions();
223225

224226
PCHContainerOps = std::make_shared<PCHContainerOperations>();
@@ -269,7 +271,8 @@ llvm::Error DependencyScanningWorker::computeDependencies(
269271
Tool.setPrintErrorMessage(false);
270272
Tool.setDiagnosticConsumer(&DC);
271273
DependencyScanningAction Action(WorkingDirectory, Consumer, DepFS,
272-
PPSkipMappings.get(), Format);
274+
PPSkipMappings.get(), Format,
275+
LookedUpModuleName);
273276
return !Tool.run(&Action);
274277
});
275278
}
@@ -290,7 +293,8 @@ llvm::Error DependencyScanningWorker::computeDependenciesForClangInvocation(
290293
newInvocation(&Diags, CC1Args, /*BinaryName=*/nullptr));
291294

292295
DependencyScanningAction Action(WorkingDirectory, Consumer, DepFS,
293-
PPSkipMappings.get(), Format);
296+
PPSkipMappings.get(), Format,
297+
LookedUpModuleName);
294298

295299
llvm::IntrusiveRefCntPtr<FileManager> FM = Files;
296300
if (!FM)
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: rm -rf %t.mcp
2+
// RUN: echo %S > %t.result
3+
// RUN: c-index-test core --scan-deps-by-mod-name -module-name=ModA %S -- %clang -cc1 -I %S/Inputs/module \
4+
// RUN: -fmodules -fmodules-cache-path=%t.mcp -fimplicit-module-maps \
5+
// RUN: -o FoE.o -x objective-c >> %t.result
6+
// RUN: cat %t.result | sed 's/\\/\//g' | FileCheck %s
7+
8+
// Use driver arguments.
9+
// RUN: rm -rf %t.mcp
10+
// RUN: echo %S > %t.result
11+
// RUN: c-index-test core --scan-deps-by-mod-name -module-name=ModA %S -- %clang -c -I %S/Inputs/module \
12+
// RUN: -fmodules -fmodules-cache-path=%t.mcp \
13+
// RUN: -o FoE.o -x objective-c >> %t.result
14+
// RUN: cat %t.result | sed 's/\\/\//g' | FileCheck %s
15+
16+
// CHECK: [[PREFIX:.*]]
17+
// CHECK-NEXT: modules:
18+
// CHECK-NEXT: module:
19+
// CHECK-NEXT: name: ModA
20+
// CHECK-NEXT: context-hash: [[HASH_MOD_A:[A-Z0-9]+]]
21+
// CHECK-NEXT: module-map-path: [[PREFIX]]/Inputs/module/module.modulemap
22+
// CHECK-NEXT: module-deps:
23+
// CHECK-NEXT: file-deps:
24+
// CHECK-NEXT: [[PREFIX]]/Inputs/module/ModA.h
25+
// CHECK-NEXT: [[PREFIX]]/Inputs/module/SubModA.h
26+
// CHECK-NEXT: [[PREFIX]]/Inputs/module/SubSubModA.h
27+
// CHECK-NEXT: [[PREFIX]]/Inputs/module/module.modulemap
28+
// CHECK-NEXT: build-args: {{.*}} -emit-module {{.*}} -fmodule-name=ModA -fno-implicit-modules {{.*}}
29+
// CHECK-NEXT: dependencies:
30+
// CHECK-NEXT: context-hash:
31+
// CHECK-NEXT: module-deps:
32+
// CHECK-NEXT: ModA:[[HASH_MOD_A]]
33+
// CHECK-NEXT: file-deps:
34+
// CHECK-NEXT: additional-build-args: -fno-implicit-modules -fno-implicit-module-maps

clang/tools/c-index-test/core_main.cpp

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ enum class ActionType {
5353
PrintStoreFormatVersion,
5454
AggregateAsJSON,
5555
ScanDeps,
56+
ScanDepsByModName,
5657
WatchDir,
5758
};
5859

@@ -75,6 +76,8 @@ Action(cl::desc("Action:"), cl::init(ActionType::None),
7576
"aggregate-json", "Aggregate index data in JSON format"),
7677
clEnumValN(ActionType::ScanDeps, "scan-deps",
7778
"Get file dependencies"),
79+
clEnumValN(ActionType::ScanDepsByModName, "scan-deps-by-mod-name",
80+
"Get file dependencies by module name alone"),
7881
clEnumValN(ActionType::WatchDir,
7982
"watch-dir", "Watch directory for file events")),
8083
cl::cat(IndexTestCoreCategory));
@@ -112,6 +115,9 @@ static cl::opt<std::string>
112115
FilePathAndRange("filepath",
113116
cl::desc("File path that can optionally include a line range"));
114117

118+
static cl::opt<std::string>
119+
ModuleName("module-name", cl::desc("name of the module, of which we are "
120+
"getting file and module dependencies"));
115121
}
116122
} // anonymous namespace
117123

@@ -715,6 +721,80 @@ static int scanDeps(ArrayRef<const char *> Args, std::string WorkingDirectory) {
715721
return 0;
716722
}
717723

724+
static int scanDepsByModName(ArrayRef<const char *> Args,
725+
std::string WorkingDirectory,
726+
std::string ModName) {
727+
CXDependencyScannerService Service =
728+
clang_experimental_DependencyScannerService_create_v0(
729+
CXDependencyMode_Full);
730+
CXDependencyScannerWorker Worker =
731+
clang_experimental_DependencyScannerWorkerByModName_create_v0(
732+
Service, ModName.c_str());
733+
CXString Error;
734+
735+
auto Callback = [&](CXModuleDependencySet *MDS) {
736+
llvm::outs() << "modules:\n";
737+
for (const auto &M : llvm::makeArrayRef(MDS->Modules, MDS->Count)) {
738+
llvm::outs() << " module:\n"
739+
<< " name: " << clang_getCString(M.Name) << "\n"
740+
<< " context-hash: " << clang_getCString(M.ContextHash)
741+
<< "\n"
742+
<< " module-map-path: "
743+
<< clang_getCString(M.ModuleMapPath) << "\n"
744+
<< " module-deps:\n";
745+
for (const auto &ModuleName :
746+
llvm::makeArrayRef(M.ModuleDeps->Strings, M.ModuleDeps->Count))
747+
llvm::outs() << " " << clang_getCString(ModuleName) << "\n";
748+
llvm::outs() << " file-deps:\n";
749+
for (const auto &FileName :
750+
llvm::makeArrayRef(M.FileDeps->Strings, M.FileDeps->Count))
751+
llvm::outs() << " " << clang_getCString(FileName) << "\n";
752+
llvm::outs() << " build-args:";
753+
for (const auto &Arg : llvm::makeArrayRef(M.BuildArguments->Strings,
754+
M.BuildArguments->Count))
755+
llvm::outs() << " " << clang_getCString(Arg);
756+
llvm::outs() << "\n";
757+
}
758+
clang_experimental_ModuleDependencySet_dispose(MDS);
759+
};
760+
761+
auto CB =
762+
functionObjectToCCallbackRef<void(CXModuleDependencySet *)>(Callback);
763+
764+
CXFileDependencies *Result =
765+
clang_experimental_DependencyScannerWorkerByModName_getFileDependencies_v1(
766+
Worker, Args.size(), Args.data(), WorkingDirectory.c_str(),
767+
CB.Callback, CB.Context, &Error);
768+
if (!Result) {
769+
llvm::errs() << "error: failed to get dependencies\n";
770+
llvm::errs() << clang_getCString(Error) << "\n";
771+
clang_disposeString(Error);
772+
return 1;
773+
}
774+
llvm::outs() << "dependencies:\n";
775+
llvm::outs() << " context-hash: " << clang_getCString(Result->ContextHash)
776+
<< "\n"
777+
<< " module-deps:\n";
778+
for (const auto &ModuleName : llvm::makeArrayRef(Result->ModuleDeps->Strings,
779+
Result->ModuleDeps->Count))
780+
llvm::outs() << " " << clang_getCString(ModuleName) << "\n";
781+
llvm::outs() << " file-deps:\n";
782+
for (const auto &FileName :
783+
llvm::makeArrayRef(Result->FileDeps->Strings, Result->FileDeps->Count))
784+
llvm::outs() << " " << clang_getCString(FileName) << "\n";
785+
llvm::outs() << " additional-build-args:";
786+
for (const auto &Arg :
787+
llvm::makeArrayRef(Result->AdditionalArguments->Strings,
788+
Result->AdditionalArguments->Count))
789+
llvm::outs() << " " << clang_getCString(Arg);
790+
llvm::outs() << "\n";
791+
792+
clang_experimental_FileDependencies_dispose(Result);
793+
clang_experimental_DependencyScannerWorker_dispose_v0(Worker);
794+
clang_experimental_DependencyScannerService_dispose_v0(Service);
795+
return 0;
796+
}
797+
718798
static void printSymbol(const IndexRecordDecl &Rec, raw_ostream &OS) {
719799
printSymbolInfo(Rec.SymInfo, OS);
720800
OS << " | ";
@@ -1011,6 +1091,19 @@ int indextest_core_main(int argc, const char **argv) {
10111091
return scanDeps(CompArgs, options::InputFiles[0]);
10121092
}
10131093

1094+
if (options::Action == ActionType::ScanDepsByModName) {
1095+
if (options::InputFiles.empty()) {
1096+
errs() << "error: missing working directory\n";
1097+
return 1;
1098+
}
1099+
if (options::ModuleName.empty()) {
1100+
errs() << "error: missing module name\n";
1101+
return 1;
1102+
}
1103+
return scanDepsByModName(CompArgs, options::InputFiles[0],
1104+
options::ModuleName);
1105+
}
1106+
10141107
if (options::Action == ActionType::WatchDir) {
10151108
if (options::InputFiles.empty()) {
10161109
errs() << "error: missing directory path\n";

clang/tools/libclang/CDependencies.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "clang/Tooling/DependencyScanning/DependencyScanningService.h"
2020
#include "clang/Tooling/DependencyScanning/DependencyScanningTool.h"
2121
#include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h"
22+
#include "llvm/Support/FileUtilities.h"
2223

2324
using namespace clang;
2425
using namespace clang::tooling::dependencies;
@@ -75,6 +76,13 @@ CXDependencyScannerWorker clang_experimental_DependencyScannerWorker_create_v0(
7576
return wrap(new DependencyScanningWorker(*unwrap(Service)));
7677
}
7778

79+
CXDependencyScannerWorker
80+
clang_experimental_DependencyScannerWorkerByModName_create_v0(
81+
CXDependencyScannerService Service, const char *LookedUpModuleName) {
82+
return wrap(
83+
new DependencyScanningWorker(*unwrap(Service), LookedUpModuleName));
84+
}
85+
7886
void clang_experimental_DependencyScannerWorker_dispose_v0(
7987
CXDependencyScannerWorker Worker) {
8088
delete unwrap(Worker);
@@ -267,3 +275,22 @@ clang_experimental_DependencyScannerWorker_getFileDependencies_v1(
267275
return MD.getCanonicalCommandLineWithoutModulePaths();
268276
});
269277
}
278+
279+
CXFileDependencies *
280+
clang_experimental_DependencyScannerWorkerByModName_getFileDependencies_v1(
281+
CXDependencyScannerWorker W, int argc, const char *const *argv,
282+
const char *WorkingDirectory, CXModuleDiscoveredCallback *MDC,
283+
void *Context, CXString *error) {
284+
llvm::SmallString<64> OutputFile;
285+
llvm::sys::fs::createTemporaryFile("lookUpModName", "" /*no-suffix*/,
286+
OutputFile);
287+
llvm::FileRemover OutputRemover(OutputFile.c_str());
288+
llvm::SmallVector<const char *, 16> NewArgs(argv, argv + argc);
289+
NewArgs.push_back(OutputFile.c_str());
290+
291+
return getFileDependencies(
292+
W, NewArgs.size(), NewArgs.data(), WorkingDirectory, MDC, Context, error,
293+
[](const ModuleDeps &MD) {
294+
return MD.getCanonicalCommandLineWithoutModulePaths();
295+
});
296+
}

clang/tools/libclang/libclang.exports

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,9 +163,11 @@ clang_executeOnThread
163163
clang_experimental_DependencyScannerService_create_v0
164164
clang_experimental_DependencyScannerService_dispose_v0
165165
clang_experimental_DependencyScannerWorker_create_v0
166+
clang_experimental_DependencyScannerWorkerByModName_create_v0
166167
clang_experimental_DependencyScannerWorker_dispose_v0
167168
clang_experimental_DependencyScannerWorker_getFileDependencies_v0
168169
clang_experimental_DependencyScannerWorker_getFileDependencies_v1
170+
clang_experimental_DependencyScannerWorkerByModName_getFileDependencies_v1
169171
clang_experimental_FileDependencies_dispose
170172
clang_experimental_ModuleDependencySet_dispose
171173
clang_findIncludesInFile

0 commit comments

Comments
 (0)