Skip to content

[libclang] Add C interface for querying against ModuleDeps #10323

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions clang/include/clang-c/Dependencies.h
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,27 @@ typedef struct CXOpaqueDepGraphTUCommand *CXDepGraphTUCommand;
typedef struct CXOpaqueDependencyScannerWorkerScanSettings
*CXDependencyScannerWorkerScanSettings;

/**
* A callback that is called to determine the paths of output files for each
* module dependency. The ModuleFile (pcm) path mapping is mandatory.
*
* \param Context the MLOContext that was passed to
* \c clang_experimental_DependencyScannerWorker_getFileDependencies_vX.
* \param CXDepMod the ModuleDep that represents the dependent module.
* \param OutputKind the kind of module output to lookup.
* \param[out] Output the output path(s) or name, whose total size must be <=
* \p MaxLen. In the case of multiple outputs of the same
* kind, this can be a null-separated list.
* \param MaxLen the maximum size of Output.
*
* \returns the actual length of Output. If the return value is > \p MaxLen,
* the callback will be repeated with a larger buffer.
*/
typedef size_t CXModuleLookupOutputCallback_v2(void *Context,
CXDepGraphModule CXDepMod,
CXOutputKind OutputKind,
char *Output, size_t MaxLen);

/**
* Creates a set of settings for
* \c clang_experimental_DependencyScannerWorker_getDepGraph action.
Expand Down Expand Up @@ -280,6 +301,23 @@ clang_experimental_DependencyScannerWorkerScanSettings_create(
const char *WorkingDirectory, void *MLOContext,
CXModuleLookupOutputCallback *MLO);

/**
* Override the ModuleLookupOutputCallback with \c
* CXModuleLookupOutputCallback_v2 in the scanner settings for queries of module
* dependencies. This is required for handling output paths of modules that
* depend on attributes encoded in
* \c CXDepGraphModule.
*
* \param Settings object created via
* \c clang_experimental_DependencyScannerWorkerScanSettings_create.
* \param MLO a callback that is called to determine the paths of output files
* for each module dependency. This may receive the same module on
* different workers.
*/
CINDEX_LINKAGE void
clang_experimental_DependencyScannerWorkerScanSettings_setModuleLookupCallback(
CXDependencyScannerWorkerScanSettings, CXModuleLookupOutputCallback_v2 *);

/**
* Dispose of a \c CXDependencyScannerWorkerScanSettings object.
*/
Expand Down Expand Up @@ -398,6 +436,13 @@ CINDEX_LINKAGE CXCStringArray
CINDEX_LINKAGE CXCStringArray
clang_experimental_DepGraphModule_getModuleDeps(CXDepGraphModule);

/**
* \returns whether the provided module is comprised of
* inputs that resolve into stable directories.
*/
CINDEX_LINKAGE bool
clang_experimental_DepGraphModule_isInStableDirs(CXDepGraphModule);

/**
* \returns the canonical command line to build this module.
*
Expand Down
25 changes: 25 additions & 0 deletions clang/test/ClangScanDeps/stable-dirs-c-api.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// REQUIRES: shell
// RUN: rm -rf %t
// RUN: split-file %s %t

// RUN: c-index-test core -scan-deps -working-dir %S -- %clang \
// RUN: -c %t/client.c -fmodules -fmodules-cache-path=%t/module-cache \
// RUN: -isysroot %t/Sysroot -I %t/Sysroot/usr/include 2>&1 | FileCheck %s \
// RUN: -implicit-check-not error: -implicit-check-not=warning:

//--- Sysroot/usr/include/A/module.modulemap
module A {
umbrella "."
}

//--- Sysroot/usr/include/A/A.h
typedef int A_t;

//--- client.c
#include <A/A.h>


// CHECK: module:
// CHECK-NEXT: name: A
// CHECK: is-in-stable-directories: 1

5 changes: 5 additions & 0 deletions clang/tools/c-index-test/core_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,8 @@ static int scanDeps(ArrayRef<const char *> Args, std::string WorkingDirectory,
const char *ContextHash =
clang_experimental_DepGraphModule_getContextHash(Mod);
int CwdIgnored = clang_experimental_DepGraphModule_isCWDIgnored(Mod);
bool IsInStableDir =
clang_experimental_DepGraphModule_isInStableDirs(Mod);
const char *ModuleMapPath =
clang_experimental_DepGraphModule_getModuleMapPath(Mod);
const char *ModuleFilesystemRootID =
Expand All @@ -844,6 +846,9 @@ static int scanDeps(ArrayRef<const char *> Args, std::string WorkingDirectory,
<< " cwd-ignored: " << CwdIgnored << "\n"
<< " module-map-path: "
<< (ModuleMapPath ? ModuleMapPath : "<none>") << "\n";
if (IsInStableDir)
llvm::outs() << " is-in-stable-directories: " << IsInStableDir
<< "\n";
if (ModuleFilesystemRootID)
llvm::outs() << " casfs-root-id: " << ModuleFilesystemRootID << "\n";
if (ModuleIncludeTreeID)
Expand Down
82 changes: 60 additions & 22 deletions clang/tools/libclang/CDependencies.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "clang/Tooling/DependencyScanning/DependencyScanningService.h"
#include "clang/Tooling/DependencyScanning/DependencyScanningTool.h"
#include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/CAS/CASProvidingFileSystem.h"
#include "llvm/CAS/CachingOnDiskFileSystem.h"
#include "llvm/Support/Process.h"
Expand Down Expand Up @@ -197,14 +198,18 @@ void clang_experimental_DependencyScannerWorker_dispose_v0(
namespace {
class OutputLookup {
public:
OutputLookup(void *MLOContext, CXModuleLookupOutputCallback *MLO)
OutputLookup(void *MLOContext, std::variant<CXModuleLookupOutputCallback *,
CXModuleLookupOutputCallback_v2 *>
MLO)
: MLOContext(MLOContext), MLO(MLO) {}
std::string lookupModuleOutput(const ModuleDeps &MD, ModuleOutputKind MOK);

private:
llvm::DenseMap<ModuleID, std::string> PCMPaths;
void *MLOContext;
CXModuleLookupOutputCallback *MLO;
std::variant<CXModuleLookupOutputCallback *,
CXModuleLookupOutputCallback_v2 *>
MLO;
};

struct DependencyScannerWorkerScanSettings {
Expand All @@ -213,7 +218,9 @@ struct DependencyScannerWorkerScanSettings {
const char *ModuleName;
const char *WorkingDirectory;
void *MLOContext;
CXModuleLookupOutputCallback *MLO;
std::variant<CXModuleLookupOutputCallback *,
CXModuleLookupOutputCallback_v2 *>
MLO;
};

struct CStringsManager {
Expand Down Expand Up @@ -273,7 +280,7 @@ struct DependencyGraph {
};

struct DependencyGraphModule {
ModuleDeps *ModDeps;
const ModuleDeps *ModDeps;
CStringsManager StrMgr{};
};

Expand Down Expand Up @@ -314,7 +321,9 @@ enum CXErrorCode clang_experimental_DependencyScannerWorker_getDepGraph(
const char *ModuleName = Settings.ModuleName;
const char *WorkingDirectory = Settings.WorkingDirectory;
void *MLOContext = Settings.MLOContext;
CXModuleLookupOutputCallback *MLO = Settings.MLO;
std::variant<CXModuleLookupOutputCallback *,
CXModuleLookupOutputCallback_v2 *>
MLO = Settings.MLO;

OutputLookup OL(MLOContext, MLO);
auto LookupOutputs = [&](const ModuleDeps &MD, ModuleOutputKind MOK) {
Expand Down Expand Up @@ -396,68 +405,73 @@ void clang_experimental_DepGraphModule_dispose(CXDepGraphModule CXDepMod) {

const char *
clang_experimental_DepGraphModule_getName(CXDepGraphModule CXDepMod) {
ModuleDeps &ModDeps = *unwrap(CXDepMod)->ModDeps;
const ModuleDeps &ModDeps = *unwrap(CXDepMod)->ModDeps;
return ModDeps.ID.ModuleName.c_str();
}

const char *
clang_experimental_DepGraphModule_getContextHash(CXDepGraphModule CXDepMod) {
ModuleDeps &ModDeps = *unwrap(CXDepMod)->ModDeps;
const ModuleDeps &ModDeps = *unwrap(CXDepMod)->ModDeps;
return ModDeps.ID.ContextHash.c_str();
}

const char *
clang_experimental_DepGraphModule_getModuleMapPath(CXDepGraphModule CXDepMod) {
ModuleDeps &ModDeps = *unwrap(CXDepMod)->ModDeps;
const ModuleDeps &ModDeps = *unwrap(CXDepMod)->ModDeps;
if (ModDeps.ClangModuleMapFile.empty())
return nullptr;
return ModDeps.ClangModuleMapFile.c_str();
}

CXCStringArray
clang_experimental_DepGraphModule_getFileDeps(CXDepGraphModule CXDepMod) {
ModuleDeps &ModDeps = *unwrap(CXDepMod)->ModDeps;
const ModuleDeps &ModDeps = *unwrap(CXDepMod)->ModDeps;
std::vector<std::string> FileDeps;
ModDeps.forEachFileDep([&](StringRef File) { FileDeps.emplace_back(File); });
return unwrap(CXDepMod)->StrMgr.createCStringsOwned(std::move(FileDeps));
}

CXCStringArray
clang_experimental_DepGraphModule_getModuleDeps(CXDepGraphModule CXDepMod) {
ModuleDeps &ModDeps = *unwrap(CXDepMod)->ModDeps;
const ModuleDeps &ModDeps = *unwrap(CXDepMod)->ModDeps;
std::vector<std::string> Modules;
Modules.reserve(ModDeps.ClangModuleDeps.size());
for (const ModuleID &MID : ModDeps.ClangModuleDeps)
Modules.push_back(MID.ModuleName + ":" + MID.ContextHash);
return unwrap(CXDepMod)->StrMgr.createCStringsOwned(std::move(Modules));
}

bool clang_experimental_DepGraphModule_isInStableDirs(
CXDepGraphModule CXDepMod) {
return unwrap(CXDepMod)->ModDeps->IsInStableDirectories;
}

CXCStringArray
clang_experimental_DepGraphModule_getBuildArguments(CXDepGraphModule CXDepMod) {
ModuleDeps &ModDeps = *unwrap(CXDepMod)->ModDeps;
const ModuleDeps &ModDeps = *unwrap(CXDepMod)->ModDeps;
return unwrap(CXDepMod)->StrMgr.createCStringsRef(
ModDeps.getBuildArguments());
}

const char *clang_experimental_DepGraphModule_getFileSystemRootID(
CXDepGraphModule CXDepMod) {
ModuleDeps &ModDeps = *unwrap(CXDepMod)->ModDeps;
const ModuleDeps &ModDeps = *unwrap(CXDepMod)->ModDeps;
if (ModDeps.CASFileSystemRootID)
return ModDeps.CASFileSystemRootID->c_str();
return nullptr;
}

const char *
clang_experimental_DepGraphModule_getIncludeTreeID(CXDepGraphModule CXDepMod) {
ModuleDeps &ModDeps = *unwrap(CXDepMod)->ModDeps;
const ModuleDeps &ModDeps = *unwrap(CXDepMod)->ModDeps;
if (ModDeps.IncludeTreeID)
return ModDeps.IncludeTreeID->c_str();
return nullptr;
}

const char *
clang_experimental_DepGraphModule_getCacheKey(CXDepGraphModule CXDepMod) {
ModuleDeps &ModDeps = *unwrap(CXDepMod)->ModDeps;
const ModuleDeps &ModDeps = *unwrap(CXDepMod)->ModDeps;
if (ModDeps.ModuleCacheKey)
return ModDeps.ModuleCacheKey->c_str();
return nullptr;
Expand Down Expand Up @@ -536,22 +550,46 @@ const char *clang_experimental_DepGraph_getTUContextHash(CXDepGraph Graph) {
return TUDeps.ID.ContextHash.c_str();
}

void clang_experimental_DependencyScannerWorkerScanSettings_setModuleLookupCallback(
CXDependencyScannerWorkerScanSettings CXSettings,
CXModuleLookupOutputCallback_v2 *MLO) {
DependencyScannerWorkerScanSettings &Settings = *unwrap(CXSettings);
Settings.MLO = MLO;
}

CXDiagnosticSet clang_experimental_DepGraph_getDiagnostics(CXDepGraph Graph) {
return unwrap(Graph)->getDiagnosticSet();
}

static std::string lookupModuleOutput(const ModuleDeps &MD,
ModuleOutputKind MOK, void *MLOContext,
CXModuleLookupOutputCallback *MLO) {
static std::string
lookupModuleOutput(const ModuleDeps &MD, ModuleOutputKind MOK, void *MLOContext,
std::variant<CXModuleLookupOutputCallback *,
CXModuleLookupOutputCallback_v2 *>
MLO) {
SmallVector<char, 256> Buffer(256);
size_t Len =
MLO(MLOContext, MD.ID.ModuleName.c_str(), MD.ID.ContextHash.c_str(),
wrap(MOK), Buffer.data(), Buffer.size());
auto GetLengthFromOutputCallback = [&]() {
return std::visit(llvm::makeVisitor(
[&](CXModuleLookupOutputCallback *) -> size_t {
return std::get<CXModuleLookupOutputCallback *>(
MLO)(MLOContext, MD.ID.ModuleName.c_str(),
MD.ID.ContextHash.c_str(), wrap(MOK),
Buffer.data(), Buffer.size());
},
[&](CXModuleLookupOutputCallback_v2 *) -> size_t {
return std::get<CXModuleLookupOutputCallback_v2 *>(
MLO)(MLOContext,
wrap(new DependencyGraphModule{&MD}),
wrap(MOK), Buffer.data(), Buffer.size());
}),
MLO);
};

size_t Len = GetLengthFromOutputCallback();
if (Len > Buffer.size()) {
Buffer.resize(Len);
Len = MLO(MLOContext, MD.ID.ModuleName.c_str(), MD.ID.ContextHash.c_str(),
wrap(MOK), Buffer.data(), Buffer.size());
Len = GetLengthFromOutputCallback();
}

return std::string(Buffer.begin(), Len);
}

Expand Down
1 change: 1 addition & 0 deletions clang/tools/libclang/libclang.map
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,7 @@ LLVM_21 {
global:
clang_experimental_DependencyScannerServiceOptions_setCWDOptimization;
clang_experimental_DepGraphModule_isCWDIgnored;
clang_experimental_DepGraphModule_isInStableDirs;
};

# Example of how to add a new symbol version entry. If you do add a new symbol
Expand Down