Bigcheese created this revision.
Bigcheese added reviewers: arphaman, kousikk.
Herald added subscribers: llvm-commits, cfe-commits, tschuett, dexonsmith,
mgorny.
Herald added projects: clang, LLVM.
Bigcheese added a parent revision: D70268: [clang][clang-scan-deps] Aggregate
the full dependency information..
This adds an experimental C API for clang-scan-deps. It provides both
the full module dependency graph along with a flattened list of
dependencies.
See clang/include/clang-c/Dependencies.h for the API and documentation.
You can test it out using:
c-index-test core --scan-deps <working-directory> -- clang --cc1 <args>
This will output a list of modules and then the direct dependencies of
the main translation unit.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D70351
Files:
clang/include/clang-c/Dependencies.h
clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
clang/tools/c-index-test/CMakeLists.txt
clang/tools/c-index-test/core_main.cpp
clang/tools/libclang/CDependencies.cpp
clang/tools/libclang/CMakeLists.txt
clang/tools/libclang/CXString.cpp
clang/tools/libclang/CXString.h
clang/tools/libclang/libclang.exports
llvm/include/llvm/ADT/FunctionExtras.h
Index: llvm/include/llvm/ADT/FunctionExtras.h
===================================================================
--- llvm/include/llvm/ADT/FunctionExtras.h
+++ llvm/include/llvm/ADT/FunctionExtras.h
@@ -287,6 +287,37 @@
}
};
+template <typename CallTy> struct FunctionObjectCallback {
+ void *Context;
+ CallTy *Callback;
+};
+
+namespace detail {
+template <typename FuncTy, typename CallTy>
+struct functionObjectToCCallbackRefImpl;
+
+template <typename FuncTy, typename Ret, typename... Args>
+struct functionObjectToCCallbackRefImpl<FuncTy, Ret(Args...)> {
+ static FunctionObjectCallback<Ret(void *, Args...)> impl(FuncTy &F) {
+ auto Func = +[](void *C, Args... V) -> Ret {
+ return (*reinterpret_cast<std::decay_t<FuncTy> *>(C))(
+ std::forward<Args>(V)...);
+ };
+
+ return {&F, Func};
+ }
+};
+} // namespace detail
+
+/// Returns a function pointer and context pair suitable for use as a C
+/// callback.
+///
+/// \param F the function object to turn into a C callback. The returned
+/// callback has the same lifetime as F.
+template <typename CallTy, typename FuncTy>
+auto functionObjectToCCallbackRef(FuncTy &F) {
+ return detail::functionObjectToCCallbackRefImpl<FuncTy, CallTy>::impl(F);
+}
} // end namespace llvm
#endif // LLVM_ADT_FUNCTION_H
Index: clang/tools/libclang/libclang.exports
===================================================================
--- clang/tools/libclang/libclang.exports
+++ clang/tools/libclang/libclang.exports
@@ -157,6 +157,13 @@
clang_equalRanges
clang_equalTypes
clang_executeOnThread
+clang_experimental_DependencyScannerService_create_v0
+clang_experimental_DependencyScannerService_dispose_v0
+clang_experimental_DependencyScannerWorker_create_v0
+clang_experimental_DependencyScannerWorker_dispose_v0
+clang_experimental_DependencyScannerWorker_getFileDependencies_v0
+clang_experimental_FileDependencies_dispose
+clang_experimental_ModuleDependencySet_dispose
clang_findIncludesInFile
clang_findIncludesInFileWithBlock
clang_findReferencesInFile
Index: clang/tools/libclang/CXString.h
===================================================================
--- clang/tools/libclang/CXString.h
+++ clang/tools/libclang/CXString.h
@@ -17,6 +17,7 @@
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Compiler.h"
#include <string>
#include <vector>
@@ -69,6 +70,8 @@
CXStringSet *createSet(const std::vector<std::string> &Strings);
+CXStringSet *createSet(const llvm::StringSet<> &Strings);
+
/// A string pool used for fast allocation/deallocation of strings.
class CXStringPool {
public:
Index: clang/tools/libclang/CXString.cpp
===================================================================
--- clang/tools/libclang/CXString.cpp
+++ clang/tools/libclang/CXString.cpp
@@ -119,6 +119,15 @@
return Set;
}
+CXStringSet *createSet(const llvm::StringSet<> &Strings) {
+ CXStringSet *Set = new CXStringSet;
+ Set->Count = Strings.size();
+ Set->Strings = new CXString[Set->Count];
+ int I = 0;
+ for (auto SI = Strings.begin(), SE = Strings.end(); SI != SE; ++SI)
+ Set->Strings[I++] = createDup(SI->getKey());
+ return Set;
+}
//===----------------------------------------------------------------------===//
// String pools.
Index: clang/tools/libclang/CMakeLists.txt
===================================================================
--- clang/tools/libclang/CMakeLists.txt
+++ clang/tools/libclang/CMakeLists.txt
@@ -1,6 +1,7 @@
set(SOURCES
ARCMigrate.cpp
BuildSystem.cpp
+ CDependencies.cpp
CIndex.cpp
CIndexCXX.cpp
CIndexCodeCompletion.cpp
@@ -37,6 +38,7 @@
set(LIBS
clangAST
clangBasic
+ clangDependencyScanning
clangDriver
clangFrontend
clangIndex
Index: clang/tools/libclang/CDependencies.cpp
===================================================================
--- /dev/null
+++ clang/tools/libclang/CDependencies.cpp
@@ -0,0 +1,212 @@
+//===- CDependencies.cpp - Dependency Discovery C Interface ---------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Implements the dependency discovery interface. It provides a C library for
+// the functionality that clang-scan-deps provides.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CXString.h"
+
+#include "clang-c/Dependencies.h"
+
+#include "clang/Tooling/DependencyScanning/DependencyScanningService.h"
+#include "clang/Tooling/DependencyScanning/DependencyScanningTool.h"
+#include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h"
+
+using namespace clang;
+using namespace clang::tooling::dependencies;
+
+DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DependencyScanningService,
+ CXDependencyScannerService)
+DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DependencyScanningWorker,
+ CXDependencyScannerWorker)
+
+inline ScanningOutputFormat unwrap(CXDependencyMode Format) {
+ switch (Format) {
+ case CXDependencyMode_Flat:
+ return ScanningOutputFormat::Make;
+ case CXDependencyMode_Full:
+ return ScanningOutputFormat::Full;
+ }
+}
+
+void clang_experimental_ModuleDependencySet_dispose(
+ CXModuleDependencySet *MDS) {
+ for (int I = 0; I < MDS->Count; ++I) {
+ CXModuleDependency &MD = MDS->Modules[I];
+ clang_disposeString(MD.Name);
+ clang_disposeString(MD.ContextHash);
+ clang_disposeString(MD.ModuleMapPath);
+ clang_disposeStringSet(MD.FileDeps);
+ clang_disposeStringSet(MD.ModuleDeps);
+ }
+ delete[] MDS->Modules;
+ delete MDS;
+}
+
+CXDependencyScannerService
+clang_experimental_DependencyScannerService_create_v0(CXDependencyMode Format) {
+ return wrap(new DependencyScanningService(
+ ScanningMode::MinimizedSourcePreprocessing, unwrap(Format),
+ /*ReuseFilemanager=*/false));
+}
+
+void clang_experimental_DependencyScannerService_dispose_v0(
+ CXDependencyScannerService Service) {
+ delete unwrap(Service);
+}
+
+void clang_experimental_FileDependencies_dispose(CXFileDependencies *ID) {
+ clang_disposeString(ID->ContextHash);
+ clang_disposeStringSet(ID->FileDeps);
+ clang_disposeStringSet(ID->ModuleDeps);
+ delete ID;
+}
+
+CXDependencyScannerWorker clang_experimental_DependencyScannerWorker_create_v0(
+ CXDependencyScannerService Service) {
+ return wrap(new DependencyScanningWorker(*unwrap(Service)));
+}
+
+void clang_experimental_DependencyScannerWorker_dispose_v0(
+ CXDependencyScannerWorker Worker) {
+ delete unwrap(Worker);
+}
+
+static CXFileDependencies *
+getFlatDependencies(DependencyScanningWorker *Worker,
+ ArrayRef<std::string> Compilation,
+ const char *WorkingDirectory, CXString *error) {
+ // TODO: Implement flat deps.
+ return nullptr;
+}
+
+namespace {
+class FullDependencyConsumer : public DependencyConsumer {
+public:
+ FullDependencyConsumer(const llvm::StringSet<> &AlreadySeen)
+ : AlreadySeen(AlreadySeen) {}
+
+ void handleFileDependency(const DependencyOutputOptions &Opts,
+ StringRef File) override {
+ if (OutputPaths.empty())
+ OutputPaths = Opts.Targets;
+ Dependencies.push_back(File);
+ }
+
+ void handleModuleDependency(ModuleDeps MD) override {
+ ClangModuleDeps[MD.ContextHash + MD.ModuleName] = std::move(MD);
+ }
+
+ void handleContextHash(std::string Hash) override {
+ ContextHash = std::move(Hash);
+ }
+
+ FullDependencies getFullDependencies() const {
+ FullDependencies FD;
+
+ FD.ContextHash = std::move(ContextHash);
+
+ FD.DirectFileDependencies.assign(Dependencies.begin(), Dependencies.end());
+
+ FD.OutputPaths = std::move(OutputPaths);
+
+ for (auto &&M : ClangModuleDeps) {
+ auto &MD = M.second;
+ if (MD.ImportedByMainFile)
+ FD.DirectModuleDependencies.push_back(MD.ModuleName);
+ }
+
+ for (auto &&M : ClangModuleDeps) {
+ // TODO: Avoid handleModuleDependency even being called for modules
+ // we've already seen.
+ if (AlreadySeen.count(M.first))
+ continue;
+ FD.ClangModuleDeps.push_back(std::move(M.second));
+ }
+
+ return FD;
+ }
+
+private:
+ std::vector<std::string> Dependencies;
+ std::unordered_map<std::string, ModuleDeps> ClangModuleDeps;
+ std::string ContextHash;
+ std::vector<std::string> OutputPaths;
+ const llvm::StringSet<> &AlreadySeen;
+};
+} // namespace
+
+static CXFileDependencies *getFullDependencies(
+ DependencyScanningWorker *Worker, ArrayRef<std::string> Compilation,
+ const char *WorkingDirectory, CXModuleDiscoveredCallback *MDC,
+ void *Context, CXString *error) {
+ FullDependencyConsumer Consumer(Worker->AlreadySeen);
+ llvm::Error Result = Worker->computeDependenciesForClangInvocation(
+ WorkingDirectory, Compilation, Consumer);
+
+ if (Result) {
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+ llvm::handleAllErrors(std::move(Result),
+ [&](const llvm::ErrorInfoBase &EI) { EI.log(OS); });
+ *error = cxstring::createDup(OS.str());
+ return nullptr;
+ }
+
+ FullDependencies FD = Consumer.getFullDependencies();
+
+ if (!FD.ClangModuleDeps.empty()) {
+ CXModuleDependencySet *MDS = new CXModuleDependencySet;
+ MDS->Count = FD.ClangModuleDeps.size();
+ MDS->Modules = new CXModuleDependency[MDS->Count];
+ for (int I = 0; I < MDS->Count; ++I) {
+ CXModuleDependency &M = MDS->Modules[I];
+ ModuleDeps &MD = FD.ClangModuleDeps[I];
+ M.Name = cxstring::createDup(MD.ModuleName);
+ M.ContextHash = cxstring::createDup(MD.ContextHash);
+ M.ModuleMapPath = cxstring::createDup(MD.ClangModuleMapFile);
+ M.FileDeps = cxstring::createSet(MD.FileDeps);
+ M.ModuleDeps = cxstring::createSet(MD.ClangModuleDeps);
+ }
+ MDC(Context, MDS);
+ }
+
+ CXFileDependencies *FDeps = new CXFileDependencies;
+ FDeps->ContextHash = cxstring::createDup(FD.ContextHash);
+ FDeps->FileDeps = cxstring::createSet(FD.DirectFileDependencies);
+ FDeps->ModuleDeps = cxstring::createSet(FD.DirectModuleDependencies);
+ return FDeps;
+}
+
+CXFileDependencies *
+clang_experimental_DependencyScannerWorker_getFileDependencies_v0(
+ CXDependencyScannerWorker W, int argc, const char *const *argv,
+ const char *WorkingDirectory, CXModuleDiscoveredCallback *MDC,
+ void *Context, CXString *error) {
+ if (!W || argc < 2)
+ return nullptr;
+ if (error)
+ *error = cxstring::createEmpty();
+
+ DependencyScanningWorker *Worker = unwrap(W);
+
+ std::vector<std::string> Compilation;
+ if (StringRef(argv[1]) == "-cc1")
+ for (int i = 2; i < argc; ++i)
+ Compilation.push_back(argv[i]);
+ else {
+ return nullptr; // TODO: Run the driver to get -cc1 args.
+ }
+
+ if (Worker->getFormat() == ScanningOutputFormat::Full)
+ return getFullDependencies(Worker, Compilation, WorkingDirectory, MDC,
+ Context, error);
+ return getFlatDependencies(Worker, Compilation, WorkingDirectory, error);
+}
Index: clang/tools/c-index-test/core_main.cpp
===================================================================
--- clang/tools/c-index-test/core_main.cpp
+++ clang/tools/c-index-test/core_main.cpp
@@ -6,6 +6,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang-c/Dependencies.h"
#include "clang/AST/Mangle.h"
#include "clang/Basic/LangOptions.h"
#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
@@ -13,16 +14,17 @@
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/FrontendAction.h"
-#include "clang/Index/IndexingAction.h"
#include "clang/Index/IndexDataConsumer.h"
+#include "clang/Index/IndexingAction.h"
#include "clang/Index/USRGeneration.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Serialization/ASTReader.h"
+#include "llvm/ADT/FunctionExtras.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/PrettyStackTrace.h"
using namespace clang;
using namespace clang::index;
@@ -35,18 +37,23 @@
enum class ActionType {
None,
PrintSourceSymbols,
+ ScanDeps,
};
namespace options {
static cl::OptionCategory IndexTestCoreCategory("index-test-core options");
-static cl::opt<ActionType>
-Action(cl::desc("Action:"), cl::init(ActionType::None),
- cl::values(
- clEnumValN(ActionType::PrintSourceSymbols,
- "print-source-symbols", "Print symbols from source")),
- cl::cat(IndexTestCoreCategory));
+static cl::opt<ActionType> Action(
+ cl::desc("Action:"), cl::init(ActionType::None),
+ cl::values(clEnumValN(ActionType::PrintSourceSymbols,
+ "print-source-symbols", "Print symbols from source"),
+ clEnumValN(ActionType::ScanDeps, "scan-deps",
+ "Get file dependencies")),
+ cl::cat(IndexTestCoreCategory));
+
+static cl::list<std::string> InputFiles(cl::Positional,
+ cl::desc("<filename>..."));
static cl::extrahelp MoreHelp(
"\nAdd \"-- <compiler arguments>\" at the end to setup the compiler "
@@ -315,6 +322,65 @@
generateFullUSRForModule(Mod, OS);
}
+static int scanDeps(ArrayRef<const char *> Args, std::string WorkingDirectory) {
+ CXDependencyScannerService Service =
+ clang_experimental_DependencyScannerService_create_v0(
+ CXDependencyMode_Full);
+ CXDependencyScannerWorker Worker =
+ clang_experimental_DependencyScannerWorker_create_v0(Service);
+ CXString Error;
+
+ auto Callback = [&](CXModuleDependencySet *MDS) {
+ for (const auto &M : llvm::makeArrayRef(MDS->Modules, MDS->Count)) {
+ llvm::outs() << "module:\n"
+ << " name: " << clang_getCString(M.Name) << "\n"
+ << " context-hash: " << clang_getCString(M.ContextHash)
+ << "\n"
+ << " module-map-path: " << clang_getCString(M.ModuleMapPath)
+ << "\n"
+ << " module-deps:\n";
+ for (const auto &ModuleName :
+ llvm::makeArrayRef(M.ModuleDeps->Strings, M.ModuleDeps->Count))
+ llvm::outs() << " " << clang_getCString(ModuleName) << "\n";
+ llvm::outs() << " file-deps:\n";
+ for (const auto &FileName :
+ llvm::makeArrayRef(M.FileDeps->Strings, M.FileDeps->Count))
+ llvm::outs() << " " << clang_getCString(FileName) << "\n";
+ }
+ clang_experimental_ModuleDependencySet_dispose(MDS);
+ };
+
+ auto CB =
+ functionObjectToCCallbackRef<void(CXModuleDependencySet *)>(Callback);
+
+ CXFileDependencies *Result =
+ clang_experimental_DependencyScannerWorker_getFileDependencies_v0(
+ Worker, Args.size(), Args.data(), WorkingDirectory.c_str(),
+ CB.Callback, CB.Context, &Error);
+ if (!Result) {
+ llvm::errs() << "error: failed to get dependencies\n";
+ llvm::errs() << clang_getCString(Error) << "\n";
+ clang_disposeString(Error);
+ return 1;
+ }
+ llvm::outs() << "dependencies:\n";
+ llvm::outs() << " context-hash: " << clang_getCString(Result->ContextHash)
+ << "\n"
+ << " module-deps:\n";
+ for (const auto &ModuleName : llvm::makeArrayRef(Result->ModuleDeps->Strings,
+ Result->ModuleDeps->Count))
+ llvm::outs() << " " << clang_getCString(ModuleName) << "\n";
+ llvm::outs() << " file-deps:\n";
+ for (const auto &FileName :
+ llvm::makeArrayRef(Result->FileDeps->Strings, Result->FileDeps->Count))
+ llvm::outs() << " " << clang_getCString(FileName) << "\n";
+
+ clang_experimental_FileDependencies_dispose(Result);
+ clang_experimental_DependencyScannerWorker_dispose_v0(Worker);
+ clang_experimental_DependencyScannerService_dispose_v0(Service);
+ return 0;
+}
+
//===----------------------------------------------------------------------===//
// Command line processing.
//===----------------------------------------------------------------------===//
@@ -358,5 +424,13 @@
options::IncludeLocals);
}
+ if (options::Action == ActionType::ScanDeps) {
+ if (options::InputFiles.empty()) {
+ errs() << "error: missing working directory\n";
+ return 1;
+ }
+ return scanDeps(CompArgs, options::InputFiles[0]);
+ }
+
return 0;
}
Index: clang/tools/c-index-test/CMakeLists.txt
===================================================================
--- clang/tools/c-index-test/CMakeLists.txt
+++ clang/tools/c-index-test/CMakeLists.txt
@@ -28,6 +28,7 @@
clangAST
clangBasic
clangCodeGen
+ clangDependencyScanning
clangFrontend
clangIndex
clangSerialization
Index: clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
===================================================================
--- clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
+++ clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
@@ -222,3 +222,29 @@
return !Tool.run(&Action);
});
}
+
+llvm::Error DependencyScanningWorker::computeDependenciesForClangInvocation(
+ StringRef WorkingDirectory, ArrayRef<std::string> Arguments,
+ DependencyConsumer &Consumer) {
+ RealFS->setCurrentWorkingDirectory(WorkingDirectory);
+ return runWithDiags(DiagOpts.get(), [&](DiagnosticConsumer &DC) {
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID = new DiagnosticIDs();
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+ DiagnosticsEngine Diags(DiagID, &*DiagOpts, &DC, /*ShouldOwnClient=*/false);
+
+ llvm::opt::ArgStringList CC1Args;
+ for (const auto &Arg : Arguments)
+ CC1Args.push_back(Arg.c_str());
+ std::unique_ptr<CompilerInvocation> Invocation(
+ newInvocation(&Diags, CC1Args));
+
+ DependencyScanningAction Action(WorkingDirectory, Consumer, DepFS,
+ PPSkipMappings.get(), Format);
+
+ llvm::IntrusiveRefCntPtr<FileManager> FM = Files;
+ if (!FM)
+ FM = new FileManager(FileSystemOptions(), RealFS);
+ return Action.runInvocation(std::move(Invocation), FM.get(),
+ PCHContainerOps, &DC);
+ });
+}
Index: clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
===================================================================
--- clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
+++ clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
@@ -63,6 +63,15 @@
const CompilationDatabase &CDB,
DependencyConsumer &Consumer);
+ llvm::Error
+ computeDependenciesForClangInvocation(StringRef WorkingDirectory,
+ ArrayRef<std::string> Arguments,
+ DependencyConsumer &Consumer);
+
+ ScanningOutputFormat getFormat() const { return Format; }
+
+ llvm::StringSet<> AlreadySeen;
+
private:
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
std::shared_ptr<PCHContainerOperations> PCHContainerOps;
Index: clang/include/clang-c/Dependencies.h
===================================================================
--- /dev/null
+++ clang/include/clang-c/Dependencies.h
@@ -0,0 +1,216 @@
+/*==-- clang-c/Dependencies.h - Dependency Discovery C Interface --*- C -*-===*\
+|* *|
+|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *|
+|* Exceptions. *|
+|* See https://llvm.org/LICENSE.txt for license information. *|
+|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *|
+|* *|
+|*===----------------------------------------------------------------------===*|
+|* *|
+|* This header provides a dependency discovery interface similar to *|
+|* clang-scan-deps. *|
+|* *|
+|* An example of its usage is available in c-index-test/core_main.cpp. *|
+|* *|
+|* EXPERIMENTAL: These interfaces are experimental and will change. If you *|
+|* use these be prepared for them to change without notice on any commit. *|
+|* *|
+\*===----------------------------------------------------------------------===*/
+
+#ifndef LLVM_CLANG_C_DEPENDENCIES_H
+#define LLVM_CLANG_C_DEPENDENCIES_H
+
+#include "clang-c/BuildSystem.h"
+#include "clang-c/CXErrorCode.h"
+#include "clang-c/CXString.h"
+#include "clang-c/Platform.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \defgroup SCAN_DEPS Dependency scanning service.
+ * @{
+ */
+
+typedef struct {
+ CXString Name;
+ /**
+ * The context hash of a module represents the set of compiler options that
+ * may make one version of a module incompatible from another. This includes
+ * things like language mode, predefined macros, header search paths, etc...
+ *
+ * Modules with the same name but a different \c ContextHash should be treated
+ * as separate modules for the purpose of a build.
+ */
+ CXString ContextHash;
+
+ /**
+ * The path to the modulemap file which defines this module.
+ *
+ * This can be used to explicitly build this module. This file will
+ * additionally appear in \c FileDeps as a dependency.
+ */
+ CXString ModuleMapPath;
+
+ /**
+ * The list of files which this module directly depends on.
+ *
+ * If any of these change then the module needs to be rebuilt.
+ */
+ CXStringSet *FileDeps;
+
+ /**
+ * The list of modules which this module direct depends on.
+ *
+ * This does not include the \c ContextHash, as all modules in a single
+ * translation unit all have the same context hash.
+ */
+ CXStringSet *ModuleDeps;
+} CXModuleDependency;
+
+typedef struct {
+ int Count;
+ CXModuleDependency *Modules;
+} CXModuleDependencySet;
+
+/**
+ * See \c CXModuleDependency for the meaning of these fields, with the addition
+ * that they represent only the direct dependencies for \c CXDependencyMode_Full
+ * mode.
+ */
+typedef struct {
+ CXString ContextHash;
+ CXStringSet *FileDeps;
+ CXStringSet *ModuleDeps;
+} CXFileDependencies;
+
+CINDEX_LINKAGE void
+clang_experimental_ModuleDependencySet_dispose(CXModuleDependencySet *MD);
+
+CINDEX_LINKAGE void
+clang_experimental_FileDependencies_dispose(CXFileDependencies *ID);
+
+/**
+ * Object encapsulating instance of a dependency scanner service.
+ *
+ * The dependency scanner service is a global instance that owns the
+ * global cache and other global state that's shared between the dependency
+ * scanner workers. The service APIs are thread safe.
+ */
+typedef struct CXOpaqueDependencyScannerService *CXDependencyScannerService;
+
+/**
+ * The mode to report module dependencies in.
+ */
+typedef enum {
+ /**
+ * Flatten all module dependencies. This reports the full transitive set of
+ * header and module map dependencies needed to do an implicit module build.
+ */
+ CXDependencyMode_Flat,
+
+ /**
+ * Report the full module graph. This reports only the direct dependencies of
+ * each file, and calls a callback for each module that is discovered.
+ */
+ CXDependencyMode_Full,
+} CXDependencyMode;
+
+/**
+ * Create a \c CXDependencyScannerService object.
+ * Must be disposed with \c clang_DependencyScannerService_dispose().
+ */
+CINDEX_LINKAGE CXDependencyScannerService
+clang_experimental_DependencyScannerService_create_v0(CXDependencyMode Format);
+
+/**
+ * Dispose of a \c CXDependencyScannerService object.
+ *
+ * The service object must be disposed of after the workers are disposed of.
+ */
+CINDEX_LINKAGE void clang_experimental_DependencyScannerService_dispose_v0(
+ CXDependencyScannerService);
+
+/**
+ * Object encapsulating instance of a dependency scanner worker.
+ *
+ * The dependency scanner workers are expected to be used in separate worker
+ * threads. An individual worker is not thread safe.
+ *
+ * Operations on a worker are not thread-safe and should only be used from a
+ * single thread at a time. They are intended to be used by a single dedicated
+ * thread in a thread pool, but they are not inherently pinned to a thread.
+ */
+typedef struct CXOpaqueDependencyScannerWorker *CXDependencyScannerWorker;
+
+/**
+ * Create a \c CXDependencyScannerWorker object.
+ * Must be disposed with
+ * \c clang_experimental_DependencyScannerWorker_dispose_v0().
+ */
+CINDEX_LINKAGE CXDependencyScannerWorker
+ clang_experimental_DependencyScannerWorker_create_v0(
+ CXDependencyScannerService);
+
+CINDEX_LINKAGE void clang_experimental_DependencyScannerWorker_dispose_v0(
+ CXDependencyScannerWorker);
+
+/**
+ * A callback that is called whenever a module is discovered when in
+ * \c CXDependencyMode_Full mode.
+ *
+ * \param Context the context that was passed to
+ * \c clang_experimental_DependencyScannerWorker_getFileDependencies_v0.
+ * \param MDS the list of discovered modules. Must be freed by calling
+ * \c clang_experimental_ModuleDependencySet_dispose.
+ */
+typedef void CXModuleDiscoveredCallback(void *Context,
+ CXModuleDependencySet *MDS);
+
+/**
+ * Returns the list of file dependencies for a particular compiler invocation.
+ *
+ * \param argc the number of compiler invocation arguments (including argv[0]).
+ * \param argv the compiler invocation arguments (including argv[0]).
+ * the invocation may be a -cc1 clang invocation or a driver
+ * invocation.
+ * \param WorkingDirectory the directory in which the invocation runs.
+ * \param MDC a callback that is called whenever a new module is discovered.
+ * This may receive the same module on different workers. This should
+ * be NULL if
+ * \c clang_experimental_DependencyScannerService_create_v0 was
+ * called with \c CXDependencyMode_Flat. This callback will be called
+ * on the same thread that called this function.
+ * \param Context the context that will be passed to \c MDC each time it is
+ * called.
+ * \param [out] error the error string to pass back to client (if any).
+ *
+ * \returns A pointer to a CXFileDependencies on success, NULL otherwise. The
+ * CXFileDependencies must be freed by calling
+ * \c clang_experimental_FileDependencies_dispose.
+ */
+CINDEX_LINKAGE CXFileDependencies *
+clang_experimental_DependencyScannerWorker_getFileDependencies_v0(
+ CXDependencyScannerWorker Worker, int argc, const char *const *argv,
+ const char *WorkingDirectory, CXModuleDiscoveredCallback *MDC,
+ void *Context, CXString *error);
+
+/**
+ * Dispose of a \c CXDependencyScannerWorker object.
+ *
+ * The worker objects must be disposed of before the service is disposed of.
+ */
+CINDEX_LINKAGE void clang_experimental_DependencyScannerWorker_dispose_v0(
+ CXDependencyScannerWorker);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LLVM_CLANG_C_DEPENDENCIES_H
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits