From 8e14d45ffac9f86c19ac0aac8d3cee0bf3be5b15 Mon Sep 17 00:00:00 2001 From: Qiongsi Wu Date: Fri, 11 Jul 2025 18:39:03 -0700 Subject: [PATCH 1/5] C-APIs to report a module's link libraries. --- clang/include/clang-c/Dependencies.h | 48 +++++++++++++++++++ .../Index/Core/Inputs/module/module.modulemap | 3 ++ clang/test/Index/Core/scan-deps.m | 3 ++ clang/tools/c-index-test/core_main.cpp | 19 ++++++++ clang/tools/libclang/CDependencies.cpp | 42 ++++++++++++++++ clang/tools/libclang/libclang.map | 5 ++ 6 files changed, 120 insertions(+) diff --git a/clang/include/clang-c/Dependencies.h b/clang/include/clang-c/Dependencies.h index 827b1bef3ed4b..c51f6384dc223 100644 --- a/clang/include/clang-c/Dependencies.h +++ b/clang/include/clang-c/Dependencies.h @@ -733,6 +733,54 @@ CINDEX_LINKAGE enum CXErrorCode clang_experimental_DependencyScanner_generateReproducer( CXDependencyScannerReproducerOptions CXOptions, CXString *MessageOut); +/** + * An opaque object that contains a \c CXDepGraphModule 'st link library + * information. + */ +typedef struct CXOpaqueDepGraphModuleLinkLibrarySet + *CXDepGraphModuleLinkLibrarySet; + +/** + * An opaque object that contains information about a link library. + */ +typedef struct CXOpaqueDepGraphModuleLinkLibrary *CXDepGraphModuleLinkLibrary; + +/** + * Get the set of link libraries given a \c CXDepGraphModule intance. + * The returned set is a pointer into memory that \c CXDepGraphModule + * owns. Therefore the set does not need to be disposed. + */ +CINDEX_LINKAGE CXDepGraphModuleLinkLibrarySet + clang_experimental_DepGraphModule_getLinkLibrarySet(CXDepGraphModule); + +/** + * Get the size of \c CXDepGraphModuleLinkLibrarySet . + */ +CINDEX_LINKAGE size_t clang_experimental_DepGraphModuleLinkLibrarySet_getSize( + CXDepGraphModuleLinkLibrarySet); + +/** + * Retrieve the \c CXDepGraphModuleLinkLibrary at index \p Idx from \c + * CXDepGraphModuleLinkLibrarySet . + */ +CINDEX_LINKAGE CXDepGraphModuleLinkLibrary +clang_experimental_DepGraphModuleLinkLibrarySet_getLinkLibrary( + CXDepGraphModuleLinkLibrarySet, size_t Idx); + +/** + * Get the `Library` string from the \c CXDepGraphModuleLinkLibrary. + * `Library` could be the library name, or an absolute path to a library or a + * framework. + */ +CINDEX_LINKAGE CXString clang_experimental_DepGraphModuleLinkLibrary_getLibrary( + CXDepGraphModuleLinkLibrary); + +/** + * Returns 1 if the \c CXDepGraphModuleLinkLibrary is a framework, 0 otherwise. + */ +CINDEX_LINKAGE int clang_experimental_DepGraphModuleLinkLibrary_isFramework( + CXDepGraphModuleLinkLibrary); + /** * @} */ diff --git a/clang/test/Index/Core/Inputs/module/module.modulemap b/clang/test/Index/Core/Inputs/module/module.modulemap index 180a4aad36dcd..6a08dde8f115a 100644 --- a/clang/test/Index/Core/Inputs/module/module.modulemap +++ b/clang/test/Index/Core/Inputs/module/module.modulemap @@ -8,4 +8,7 @@ module ModA { header "SubSubModA.h" } } + + link framework "libModA" + link "libModB" } diff --git a/clang/test/Index/Core/scan-deps.m b/clang/test/Index/Core/scan-deps.m index f9dd2c4d07152..50c31bf6c1568 100644 --- a/clang/test/Index/Core/scan-deps.m +++ b/clang/test/Index/Core/scan-deps.m @@ -29,6 +29,9 @@ // CHECK-NEXT: [[PREFIX]]/Inputs/module/ModA.h // CHECK-NEXT: [[PREFIX]]/Inputs/module/SubModA.h // CHECK-NEXT: [[PREFIX]]/Inputs/module/SubSubModA.h +// CHECK-NEXT: link libraries: +// CHECK-NEXT: libModA(framework) +// CHECK-NEXT: libModB // CHECK-NEXT: build-args: {{.*}} -emit-module {{.*}} -fmodule-name=ModA {{.*}} -fno-implicit-modules {{.*}} // CHECK-NEXT: dependencies: diff --git a/clang/tools/c-index-test/core_main.cpp b/clang/tools/c-index-test/core_main.cpp index 0d24df3a67955..7a6f05bd95a3a 100644 --- a/clang/tools/c-index-test/core_main.cpp +++ b/clang/tools/c-index-test/core_main.cpp @@ -870,6 +870,25 @@ static int scanDeps(ArrayRef Args, std::string WorkingDirectory, // (mostly) platform-agnostic. if (!StringRef(FileName).ends_with("SDKSettings.json")) llvm::outs() << " " << FileName << "\n"; + CXDepGraphModuleLinkLibrarySet LinkLibs = + clang_experimental_DepGraphModule_getLinkLibrarySet(Mod); + size_t NumLinkLibs = + clang_experimental_DepGraphModuleLinkLibrarySet_getSize(LinkLibs); + if (NumLinkLibs) { + llvm::outs() << " link libraries:\n"; + for (size_t Idx = 0; Idx < NumLinkLibs; Idx++) { + CXDepGraphModuleLinkLibrary Lib = + clang_experimental_DepGraphModuleLinkLibrarySet_getLinkLibrary( + LinkLibs, Idx); + CXString Library = + clang_experimental_DepGraphModuleLinkLibrary_getLibrary(Lib); + int IsFramework = + clang_experimental_DepGraphModuleLinkLibrary_isFramework(Lib); + const char *IsFrameworkStr = IsFramework ? "(framework)" : ""; + llvm::outs() << " " << clang_getCString(Library) + << IsFrameworkStr << "\n"; + } + } llvm::outs() << " build-args:"; for (const auto &Arg : ArrayRef(BuildArguments.Strings, BuildArguments.Count)) diff --git a/clang/tools/libclang/CDependencies.cpp b/clang/tools/libclang/CDependencies.cpp index fc3ad283a13b1..89296243cbab1 100644 --- a/clang/tools/libclang/CDependencies.cpp +++ b/clang/tools/libclang/CDependencies.cpp @@ -882,3 +882,45 @@ enum CXErrorCode clang_experimental_DependencyScanner_generateReproducer( "located at:\n " << FileCachePath << "\n " << ReproScriptPath; } + +namespace { +typedef llvm::SmallVectorImpl + DepGraphModuleLinkLibrarySet; +typedef clang::Module::LinkLibrary DepGraphModuleLinkLibrary; +} // namespace + +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DepGraphModuleLinkLibrarySet, + CXDepGraphModuleLinkLibrarySet) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DepGraphModuleLinkLibrary, + CXDepGraphModuleLinkLibrary) + +CXDepGraphModuleLinkLibrarySet +clang_experimental_DepGraphModule_getLinkLibrarySet(CXDepGraphModule CXDepMod) { + const ModuleDeps &ModDeps = *unwrap(CXDepMod)->ModDeps; + return wrap(&ModDeps.LinkLibraries); +} + +size_t clang_experimental_DepGraphModuleLinkLibrarySet_getSize( + CXDepGraphModuleLinkLibrarySet S) { + const DepGraphModuleLinkLibrarySet *LinkLibraries = unwrap(S); + return LinkLibraries->size(); +} + +CXDepGraphModuleLinkLibrary +clang_experimental_DepGraphModuleLinkLibrarySet_getLinkLibrary( + CXDepGraphModuleLinkLibrarySet S, size_t Idx) { + const DepGraphModuleLinkLibrarySet *LinkLibraries = unwrap(S); + return wrap(&(*LinkLibraries)[Idx]); +} + +CXString clang_experimental_DepGraphModuleLinkLibrary_getLibrary( + CXDepGraphModuleLinkLibrary L) { + const DepGraphModuleLinkLibrary *Lib = unwrap(L); + return cxstring::createRef(Lib->Library.c_str()); +} + +int clang_experimental_DepGraphModuleLinkLibrary_isFramework( + CXDepGraphModuleLinkLibrary L) { + const DepGraphModuleLinkLibrary *Lib = unwrap(L); + return Lib->IsFramework ? 1 : 0; +} diff --git a/clang/tools/libclang/libclang.map b/clang/tools/libclang/libclang.map index 21a61c9d9fa28..fabacecab50c9 100644 --- a/clang/tools/libclang/libclang.map +++ b/clang/tools/libclang/libclang.map @@ -597,6 +597,11 @@ LLVM_21 { clang_experimental_DepScanFSCacheOutOfDateEntry_getCachedSize; clang_experimental_DepScanFSCacheOutOfDateEntry_getActualSize; clang_experimental_DepScanFSCacheOutOfDateEntrySet_disposeSet; + clang_experimental_DepGraphModule_getLinkLibrarySet; + clang_experimental_DepGraphModuleLinkLibrarySet_getSize; + clang_experimental_DepGraphModuleLinkLibrarySet_getLinkLibrary; + clang_experimental_DepGraphModuleLinkLibrary_getLibrary; + clang_experimental_DepGraphModuleLinkLibrary_isFramework; }; # Example of how to add a new symbol version entry. If you do add a new symbol From f9764e1a4df0401bce4b1a9bcd44d4944b14b1ac Mon Sep 17 00:00:00 2001 From: Qiongsi Wu Date: Fri, 11 Jul 2025 21:14:13 -0700 Subject: [PATCH 2/5] Fixing two failing tests. --- clang/test/Index/Core/scan-deps-by-mod-name.m | 3 +++ clang/test/Index/Core/scan-deps-cas.m | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/clang/test/Index/Core/scan-deps-by-mod-name.m b/clang/test/Index/Core/scan-deps-by-mod-name.m index 805c7069029b1..466ad60f04ff2 100644 --- a/clang/test/Index/Core/scan-deps-by-mod-name.m +++ b/clang/test/Index/Core/scan-deps-by-mod-name.m @@ -21,6 +21,9 @@ // CHECK-NEXT: [[PREFIX]]/Inputs/module/ModA.h // CHECK-NEXT: [[PREFIX]]/Inputs/module/SubModA.h // CHECK-NEXT: [[PREFIX]]/Inputs/module/SubSubModA.h +// CHECK-NEXT: link libraries: +// CHECK-NEXT: libModA(framework) +// CHECK-NEXT: libModB // CHECK-NEXT: build-args: {{.*}} -emit-module {{.*}} -fmodule-name=ModA {{.*}} -fno-implicit-modules {{.*}} // CHECK-NEXT: dependencies: // CHECK-NEXT: command 0: diff --git a/clang/test/Index/Core/scan-deps-cas.m b/clang/test/Index/Core/scan-deps-cas.m index cfbf1974b547f..3f7eecb8a5fe1 100644 --- a/clang/test/Index/Core/scan-deps-cas.m +++ b/clang/test/Index/Core/scan-deps-cas.m @@ -44,6 +44,9 @@ // CHECK-NEXT: [[PREFIX]]/Inputs/module/ModA.h // CHECK-NEXT: [[PREFIX]]/Inputs/module/SubModA.h // CHECK-NEXT: [[PREFIX]]/Inputs/module/SubSubModA.h +// CHECK-NEXT: link libraries: +// CHECK-NEXT: libModA(framework) +// CHECK-NEXT: libModB // CHECK-NEXT: build-args: // CHECK-SAME: -cc1 // CHECK-SAME: -fcas-path @@ -85,6 +88,9 @@ // INCLUDE_TREE-NEXT: [[PREFIX]]/Inputs/module/ModA.h // INCLUDE_TREE-NEXT: [[PREFIX]]/Inputs/module/SubModA.h // INCLUDE_TREE-NEXT: [[PREFIX]]/Inputs/module/SubSubModA.h +// INCLUDE_TREE-NEXT: link libraries: +// INCLUDE_TREE-NEXT: libModA(framework) +// INCLUDE_TREE-NEXT: libModB // INCLUDE_TREE-NEXT: build-args: // INCLUDE_TREE-SAME: -cc1 // INCLUDE_TREE-SAME: -fcas-path From 87b886b400001eace91944f0fc56b59d9aa19664 Mon Sep 17 00:00:00 2001 From: Qiongsi Wu Date: Mon, 14 Jul 2025 10:01:59 -0700 Subject: [PATCH 3/5] Address code review - use bool as function's return type. --- clang/include/clang-c/Dependencies.h | 5 +++-- clang/tools/libclang/CDependencies.cpp | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/clang/include/clang-c/Dependencies.h b/clang/include/clang-c/Dependencies.h index c51f6384dc223..1409fd7d30536 100644 --- a/clang/include/clang-c/Dependencies.h +++ b/clang/include/clang-c/Dependencies.h @@ -776,9 +776,10 @@ CINDEX_LINKAGE CXString clang_experimental_DepGraphModuleLinkLibrary_getLibrary( CXDepGraphModuleLinkLibrary); /** - * Returns 1 if the \c CXDepGraphModuleLinkLibrary is a framework, 0 otherwise. + * Returns true if the \c CXDepGraphModuleLinkLibrary is a framework, false + * otherwise. */ -CINDEX_LINKAGE int clang_experimental_DepGraphModuleLinkLibrary_isFramework( +CINDEX_LINKAGE bool clang_experimental_DepGraphModuleLinkLibrary_isFramework( CXDepGraphModuleLinkLibrary); /** diff --git a/clang/tools/libclang/CDependencies.cpp b/clang/tools/libclang/CDependencies.cpp index 89296243cbab1..6f765c281c07d 100644 --- a/clang/tools/libclang/CDependencies.cpp +++ b/clang/tools/libclang/CDependencies.cpp @@ -919,8 +919,8 @@ CXString clang_experimental_DepGraphModuleLinkLibrary_getLibrary( return cxstring::createRef(Lib->Library.c_str()); } -int clang_experimental_DepGraphModuleLinkLibrary_isFramework( +bool clang_experimental_DepGraphModuleLinkLibrary_isFramework( CXDepGraphModuleLinkLibrary L) { const DepGraphModuleLinkLibrary *Lib = unwrap(L); - return Lib->IsFramework ? 1 : 0; + return Lib->IsFramework; } From f7f590c1308b02e4cd8609815ee936ef3b25575f Mon Sep 17 00:00:00 2001 From: Qiongsi Wu Date: Mon, 14 Jul 2025 13:49:49 -0700 Subject: [PATCH 4/5] Minor code comment editing. --- clang/include/clang-c/Dependencies.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/include/clang-c/Dependencies.h b/clang/include/clang-c/Dependencies.h index 1409fd7d30536..4c53d7ddbe3e4 100644 --- a/clang/include/clang-c/Dependencies.h +++ b/clang/include/clang-c/Dependencies.h @@ -734,8 +734,8 @@ clang_experimental_DependencyScanner_generateReproducer( CXDependencyScannerReproducerOptions CXOptions, CXString *MessageOut); /** - * An opaque object that contains a \c CXDepGraphModule 'st link library - * information. + * An opaque object that contains a \c CXDepGraphModule 's list of link + * libraries. */ typedef struct CXOpaqueDepGraphModuleLinkLibrarySet *CXDepGraphModuleLinkLibrarySet; @@ -768,7 +768,7 @@ clang_experimental_DepGraphModuleLinkLibrarySet_getLinkLibrary( CXDepGraphModuleLinkLibrarySet, size_t Idx); /** - * Get the `Library` string from the \c CXDepGraphModuleLinkLibrary. + * Get the `Library` string from the \c CXDepGraphModuleLinkLibrary instance. * `Library` could be the library name, or an absolute path to a library or a * framework. */ From 6dd74f486090366c750b6c24613d5ff53260b9b6 Mon Sep 17 00:00:00 2001 From: Qiongsi Wu Date: Mon, 14 Jul 2025 16:46:15 -0700 Subject: [PATCH 5/5] Addressing code review. --- clang/include/clang-c/Dependencies.h | 17 +++++++++-------- .../Index/Core/Inputs/module/module.modulemap | 1 + clang/test/Index/Core/scan-deps-by-mod-name.m | 1 + clang/test/Index/Core/scan-deps-cas.m | 2 ++ clang/test/Index/Core/scan-deps.m | 1 + clang/tools/c-index-test/core_main.cpp | 2 +- 6 files changed, 15 insertions(+), 9 deletions(-) diff --git a/clang/include/clang-c/Dependencies.h b/clang/include/clang-c/Dependencies.h index 4c53d7ddbe3e4..cdf1e6624e8ed 100644 --- a/clang/include/clang-c/Dependencies.h +++ b/clang/include/clang-c/Dependencies.h @@ -746,9 +746,9 @@ typedef struct CXOpaqueDepGraphModuleLinkLibrarySet typedef struct CXOpaqueDepGraphModuleLinkLibrary *CXDepGraphModuleLinkLibrary; /** - * Get the set of link libraries given a \c CXDepGraphModule intance. - * The returned set is a pointer into memory that \c CXDepGraphModule - * owns. Therefore the set does not need to be disposed. + * Get the set of link libraries given a \c CXDepGraphModule instance. + * The returned set is a pointer into memory that the \c CXDepGraphModule + * instance owns. Therefore the set does not need to be disposed. */ CINDEX_LINKAGE CXDepGraphModuleLinkLibrarySet clang_experimental_DepGraphModule_getLinkLibrarySet(CXDepGraphModule); @@ -760,17 +760,18 @@ CINDEX_LINKAGE size_t clang_experimental_DepGraphModuleLinkLibrarySet_getSize( CXDepGraphModuleLinkLibrarySet); /** - * Retrieve the \c CXDepGraphModuleLinkLibrary at index \p Idx from \c - * CXDepGraphModuleLinkLibrarySet . + * Retrieve the \c CXDepGraphModuleLinkLibrary instance at index \p Idx from the + * \c CXDepGraphModuleLinkLibrarySet instance. */ CINDEX_LINKAGE CXDepGraphModuleLinkLibrary clang_experimental_DepGraphModuleLinkLibrarySet_getLinkLibrary( CXDepGraphModuleLinkLibrarySet, size_t Idx); /** - * Get the `Library` string from the \c CXDepGraphModuleLinkLibrary instance. - * `Library` could be the library name, or an absolute path to a library or a - * framework. + * Get the `Library` string from the \c CXDepGraphModuleLinkLibrary instance. + * `Library` could be a library name, or an absolute path to a library or a + * framework, as specified in the corresponding \c CXDepGraphModule instance's + * modulemap. */ CINDEX_LINKAGE CXString clang_experimental_DepGraphModuleLinkLibrary_getLibrary( CXDepGraphModuleLinkLibrary); diff --git a/clang/test/Index/Core/Inputs/module/module.modulemap b/clang/test/Index/Core/Inputs/module/module.modulemap index 6a08dde8f115a..bb3cf022b61ad 100644 --- a/clang/test/Index/Core/Inputs/module/module.modulemap +++ b/clang/test/Index/Core/Inputs/module/module.modulemap @@ -11,4 +11,5 @@ module ModA { link framework "libModA" link "libModB" + link "/absolute/path/to/a/lib/file" } diff --git a/clang/test/Index/Core/scan-deps-by-mod-name.m b/clang/test/Index/Core/scan-deps-by-mod-name.m index 466ad60f04ff2..b809352e4fe8f 100644 --- a/clang/test/Index/Core/scan-deps-by-mod-name.m +++ b/clang/test/Index/Core/scan-deps-by-mod-name.m @@ -24,6 +24,7 @@ // CHECK-NEXT: link libraries: // CHECK-NEXT: libModA(framework) // CHECK-NEXT: libModB +// CHECK-NEXT: /absolute/path/to/a/lib/file // CHECK-NEXT: build-args: {{.*}} -emit-module {{.*}} -fmodule-name=ModA {{.*}} -fno-implicit-modules {{.*}} // CHECK-NEXT: dependencies: // CHECK-NEXT: command 0: diff --git a/clang/test/Index/Core/scan-deps-cas.m b/clang/test/Index/Core/scan-deps-cas.m index 3f7eecb8a5fe1..07e737a5864d2 100644 --- a/clang/test/Index/Core/scan-deps-cas.m +++ b/clang/test/Index/Core/scan-deps-cas.m @@ -47,6 +47,7 @@ // CHECK-NEXT: link libraries: // CHECK-NEXT: libModA(framework) // CHECK-NEXT: libModB +// CHECK-NEXT: /absolute/path/to/a/lib/file // CHECK-NEXT: build-args: // CHECK-SAME: -cc1 // CHECK-SAME: -fcas-path @@ -91,6 +92,7 @@ // INCLUDE_TREE-NEXT: link libraries: // INCLUDE_TREE-NEXT: libModA(framework) // INCLUDE_TREE-NEXT: libModB +// INCLUDE_TREE-NEXT: /absolute/path/to/a/lib/file // INCLUDE_TREE-NEXT: build-args: // INCLUDE_TREE-SAME: -cc1 // INCLUDE_TREE-SAME: -fcas-path diff --git a/clang/test/Index/Core/scan-deps.m b/clang/test/Index/Core/scan-deps.m index 50c31bf6c1568..673863f005ac9 100644 --- a/clang/test/Index/Core/scan-deps.m +++ b/clang/test/Index/Core/scan-deps.m @@ -32,6 +32,7 @@ // CHECK-NEXT: link libraries: // CHECK-NEXT: libModA(framework) // CHECK-NEXT: libModB +// CHECK-NEXT: /absolute/path/to/a/lib/file // CHECK-NEXT: build-args: {{.*}} -emit-module {{.*}} -fmodule-name=ModA {{.*}} -fno-implicit-modules {{.*}} // CHECK-NEXT: dependencies: diff --git a/clang/tools/c-index-test/core_main.cpp b/clang/tools/c-index-test/core_main.cpp index 7a6f05bd95a3a..100e708feb721 100644 --- a/clang/tools/c-index-test/core_main.cpp +++ b/clang/tools/c-index-test/core_main.cpp @@ -882,7 +882,7 @@ static int scanDeps(ArrayRef Args, std::string WorkingDirectory, LinkLibs, Idx); CXString Library = clang_experimental_DepGraphModuleLinkLibrary_getLibrary(Lib); - int IsFramework = + bool IsFramework = clang_experimental_DepGraphModuleLinkLibrary_isFramework(Lib); const char *IsFrameworkStr = IsFramework ? "(framework)" : ""; llvm::outs() << " " << clang_getCString(Library)