Skip to content

Commit c11f7ff

Browse files
committed
[libclang][deps] Add initial support for compilation caching
Adds API to allow specifying the CAS + ActionCache to use in a DependencyScannerService, and test that this can be used to get cached module compilations. (cherry picked from commit 1305fe6)
1 parent ab3259c commit c11f7ff

File tree

9 files changed

+327
-5
lines changed

9 files changed

+327
-5
lines changed

clang/include/clang-c/CAS.h

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*==-- clang-c/CAS.h - CAS Interface ------------------------------*- C -*-===*\
2+
|* *|
3+
|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *|
4+
|* Exceptions. *|
5+
|* See https://llvm.org/LICENSE.txt for license information. *|
6+
|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *|
7+
|* *|
8+
|*===----------------------------------------------------------------------===*|
9+
|* *|
10+
|* This header provides interfaces for creating and working with CAS and *|
11+
|* ActionCache interfaces. *|
12+
|* *|
13+
|* An example of its usage is available in c-index-test/core_main.cpp. *|
14+
|* *|
15+
|* EXPERIMENTAL: These interfaces are experimental and will change. If you *|
16+
|* use these be prepared for them to change without notice on any commit. *|
17+
|* *|
18+
\*===----------------------------------------------------------------------===*/
19+
20+
#ifndef LLVM_CLANG_C_CAS_H
21+
#define LLVM_CLANG_C_CAS_H
22+
23+
#include "clang-c/CXString.h"
24+
#include "clang-c/Platform.h"
25+
26+
#ifdef __cplusplus
27+
extern "C" {
28+
#endif
29+
30+
/**
31+
* \defgroup CAS CAS and ActionCache interface.
32+
* @{
33+
*/
34+
35+
/**
36+
* Content-addressable storage for objects.
37+
*/
38+
typedef struct CXOpaqueCASObjectStore *CXCASObjectStore;
39+
40+
/**
41+
* A cache from a key describing an action to the result of doing it.
42+
*/
43+
typedef struct CXOpaqueCASActionCache *CXCASActionCache;
44+
45+
/**
46+
* Dispose of a \c CXCASObjectStore object.
47+
*/
48+
CINDEX_LINKAGE void
49+
clang_experimental_cas_ObjectStore_dispose(CXCASObjectStore CAS);
50+
51+
/**
52+
* Dispose of a \c CXCASActionCache object.
53+
*/
54+
CINDEX_LINKAGE void
55+
clang_experimental_cas_ActionCache_dispose(CXCASActionCache Cache);
56+
57+
/**
58+
* Gets or creates a persistent on-disk CAS object store at \p Path.
59+
*
60+
* \param Path The path to locate the object store.
61+
* \param[out] Error The error string to pass back to client (if any).
62+
*
63+
* \returns The resulting object store, or null if there was an error.
64+
*/
65+
CINDEX_LINKAGE CXCASObjectStore
66+
clang_experimental_cas_OnDiskObjectStore_create(
67+
const char *Path, CXString *Error);
68+
69+
/**
70+
* Gets or creates a persistent on-disk action cache at \p Path.
71+
*
72+
* \param Path The path to locate the object store.
73+
* \param[out] Error The error string to pass back to client (if any).
74+
*
75+
* \returns The resulting object store, or null if there was an error.
76+
*/
77+
CINDEX_LINKAGE CXCASActionCache
78+
clang_experimental_cas_OnDiskActionCache_create(
79+
const char *Path, CXString *Error);
80+
81+
/**
82+
* @}
83+
*/
84+
85+
#ifdef __cplusplus
86+
}
87+
#endif
88+
89+
#endif // LLVM_CLANG_C_CAS_H

clang/include/clang-c/Dependencies.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#define LLVM_CLANG_C_DEPENDENCIES_H
2222

2323
#include "clang-c/BuildSystem.h"
24+
#include "clang-c/CAS.h"
2425
#include "clang-c/CXDiagnostic.h"
2526
#include "clang-c/CXErrorCode.h"
2627
#include "clang-c/CXString.h"
@@ -201,6 +202,22 @@ CINDEX_LINKAGE void
201202
clang_experimental_DependencyScannerServiceOptions_setDependencyMode(
202203
CXDependencyScannerServiceOptions Opts, CXDependencyMode Mode);
203204

205+
/**
206+
* Specify a \c CXCASObjectStore in the given options. If an object store and
207+
* action cache are available, the scanner will produce cached commands.
208+
*/
209+
CINDEX_LINKAGE void
210+
clang_experimental_DependencyScannerServiceOptions_setObjectStore(
211+
CXDependencyScannerServiceOptions Opts, CXCASObjectStore CAS);
212+
213+
/**
214+
* Specify a \c CXCASActionCache in the given options. If an object store and
215+
* action cache are available, the scanner will produce cached commands.
216+
*/
217+
CINDEX_LINKAGE void
218+
clang_experimental_DependencyScannerServiceOptions_setActionCache(
219+
CXDependencyScannerServiceOptions Opts, CXCASActionCache Cache);
220+
204221
/**
205222
* See \c clang_experimental_DependencyScannerService_create_v1.
206223
*/

clang/test/Index/Core/scan-deps-cas.m

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// RUN: rm -rf %t.mcp %t
2+
// RUN: echo %S > %t.result
3+
//
4+
// RUN: c-index-test core --scan-deps %S -output-dir=%t \
5+
// RUN: -cas-path %t/cas -action-cache-path %t/cache \
6+
// RUN: -- %clang -c -I %S/Inputs/module \
7+
// RUN: -fmodules -fmodules-cache-path=%t.mcp \
8+
// RUN: -o FoE.o -x objective-c %s >> %t.result
9+
// RUN: cat %t.result | sed 's/\\/\//g' | FileCheck %s -DOUTPUTS=%/t
10+
11+
// RUN: c-index-test core --scan-deps %S -output-dir=%t \
12+
// RUN: -- %clang -c -I %S/Inputs/module \
13+
// RUN: -fmodules -fmodules-cache-path=%t.mcp \
14+
// RUN: -o FoE.o -x objective-c %s | FileCheck %s -check-prefix=NO_CAS
15+
// NO_CAS-NOT: fcas
16+
// NO_CAS-NOT: faction-cache
17+
// NO_CAS-NOT: fcache-compile-job
18+
19+
@import ModA;
20+
21+
// CHECK: [[PREFIX:.*]]
22+
// CHECK-NEXT: modules:
23+
// CHECK-NEXT: module:
24+
// CHECK-NEXT: name: ModA
25+
// CHECK-NEXT: context-hash: [[HASH_MOD_A:[A-Z0-9]+]]
26+
// CHECK-NEXT: module-map-path: [[PREFIX]]/Inputs/module/module.modulemap
27+
// CHECK-NEXT: module-deps:
28+
// CHECK-NEXT: file-deps:
29+
// CHECK-NEXT: [[PREFIX]]/Inputs/module/ModA.h
30+
// CHECK-NEXT: [[PREFIX]]/Inputs/module/SubModA.h
31+
// CHECK-NEXT: [[PREFIX]]/Inputs/module/SubSubModA.h
32+
// CHECK-NEXT: [[PREFIX]]/Inputs/module/module.modulemap
33+
// CHECK-NEXT: build-args:
34+
// CHECK-SAME: -cc1
35+
// CHECK-SAME: -fcas-path
36+
// CHECK-SAME: -faction-cache-path
37+
// CHECK-SAME: -fcas-fs llvmcas://{{[[:xdigit:]]+}}
38+
// CHECK-SAME: -fcache-compile-job
39+
// CHECK-SAME: -emit-module
40+
// CHECK-SAME: -fmodule-name=ModA
41+
// CHECK-SAME: -fno-implicit-modules
42+
43+
// CHECK-NEXT: dependencies:
44+
// CHECK-NEXT: command 0:
45+
// CHECK-NEXT: context-hash: [[HASH_TU:[A-Z0-9]+]]
46+
// CHECK-NEXT: module-deps:
47+
// CHECK-NEXT: ModA:[[HASH_MOD_A]]
48+
// CHECK-NEXT: file-deps:
49+
// CHECK-NEXT: [[PREFIX]]/scan-deps-cas.m
50+
// CHECK-NEXT: build-args:
51+
// CHECK-SAME: -cc1
52+
// CHECK-SAME: -fcas-path
53+
// CHECK-SAME: -faction-cache-path
54+
// CHECK-SAME: -fcas-fs llvmcas://{{[[:xdigit:]]+}}
55+
// CHECK-SAME: -fcache-compile-job
56+
// CHECK-SAME: -fmodule-file-cache-key=[[PCM:.*ModA_.*pcm]]=llvmcas://{{[[:xdigit:]]+}}
57+
// CHECK-SAME: -fmodule-file={{(ModA=)?}}[[PCM]]

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

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,11 @@ static cl::list<std::string> DependencyTargets(
139139
static cl::opt<bool> DeprecatedDriverCommand(
140140
"deprecated-driver-command",
141141
cl::desc("use a single driver command to build the tu (deprecated)"));
142+
static llvm::cl::opt<std::string>
143+
CASPath("cas-path", llvm::cl::desc("Path for on-disk CAS."));
144+
static llvm::cl::opt<std::string>
145+
CachePath("action-cache-path",
146+
llvm::cl::desc("Path for on-disk action cache."));
142147
}
143148
} // anonymous namespace
144149

@@ -677,6 +682,8 @@ static void printSymbolNameAndUSR(const clang::Module *Mod, raw_ostream &OS) {
677682
static int scanDeps(ArrayRef<const char *> Args, std::string WorkingDirectory,
678683
bool SerializeDiags, bool DependencyFile,
679684
ArrayRef<std::string> DepTargets, std::string OutputPath,
685+
Optional<std::string> CASPath,
686+
Optional<std::string> CachePath,
680687
Optional<std::string> ModuleName = None) {
681688
CXDependencyScannerServiceOptions Opts =
682689
clang_experimental_DependencyScannerServiceOptions_create();
@@ -686,6 +693,36 @@ static int scanDeps(ArrayRef<const char *> Args, std::string WorkingDirectory,
686693
clang_experimental_DependencyScannerServiceOptions_setDependencyMode(
687694
Opts, CXDependencyMode_Full);
688695

696+
CXString Error;
697+
if (CASPath) {
698+
CXCASObjectStore CAS = clang_experimental_cas_OnDiskObjectStore_create(
699+
CASPath->c_str(), &Error);
700+
auto CleanupCache = llvm::make_scope_exit(
701+
[&] { clang_experimental_cas_ObjectStore_dispose(CAS); });
702+
if (!CAS) {
703+
llvm::errs() << "error: failed to create ObjectStore\n";
704+
llvm::errs() << clang_getCString(Error) << "\n";
705+
clang_disposeString(Error);
706+
return 1;
707+
}
708+
clang_experimental_DependencyScannerServiceOptions_setObjectStore(Opts,
709+
CAS);
710+
if (CachePath) {
711+
CXCASActionCache Cache = clang_experimental_cas_OnDiskActionCache_create(
712+
CachePath->c_str(), &Error);
713+
auto CleanupCache = llvm::make_scope_exit(
714+
[&] { clang_experimental_cas_ActionCache_dispose(Cache); });
715+
if (!Cache) {
716+
llvm::errs() << "error: failed to create ActionCache\n";
717+
llvm::errs() << clang_getCString(Error) << "\n";
718+
clang_disposeString(Error);
719+
return 1;
720+
}
721+
clang_experimental_DependencyScannerServiceOptions_setActionCache(Opts,
722+
Cache);
723+
}
724+
}
725+
689726
CXDependencyScannerService Service =
690727
clang_experimental_DependencyScannerService_create_v1(Opts);
691728
CXDependencyScannerWorker Worker =
@@ -1129,15 +1166,21 @@ int indextest_core_main(int argc, const char **argv) {
11291166
}
11301167
return aggregateDataAsJSON(storePath, PathRemapper, OS);
11311168
}
1132-
1169+
1170+
Optional<std::string> CASPath =
1171+
options::CASPath.empty() ? None : Optional<std::string>(options::CASPath);
1172+
Optional<std::string> CachePath =
1173+
options::CachePath.empty() ? None
1174+
: Optional<std::string>(options::CachePath);
1175+
11331176
if (options::Action == ActionType::ScanDeps) {
11341177
if (options::InputFiles.empty()) {
11351178
errs() << "error: missing working directory\n";
11361179
return 1;
11371180
}
11381181
return scanDeps(CompArgs, options::InputFiles[0], options::SerializeDiags,
11391182
options::DependencyFile, options::DependencyTargets,
1140-
options::OutputDir);
1183+
options::OutputDir, CASPath, CachePath);
11411184
}
11421185

11431186
if (options::Action == ActionType::ScanDepsByModuleName) {
@@ -1152,7 +1195,8 @@ int indextest_core_main(int argc, const char **argv) {
11521195
}
11531196
return scanDeps(CompArgs, options::InputFiles[0], options::SerializeDiags,
11541197
options::DependencyFile, options::DependencyTargets,
1155-
options::OutputDir, options::ModuleName);
1198+
options::OutputDir, CASPath, CachePath,
1199+
options::ModuleName);
11561200
}
11571201

11581202
if (options::Action == ActionType::WatchDir) {

clang/tools/libclang/CASUtils.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//===- CASUtils.h - libclang CAS utilities --------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_CLANG_TOOLS_LIBCLANG_CASUTILS_H
10+
#define LLVM_CLANG_TOOLS_LIBCLANG_CASUTILS_H
11+
12+
#include "clang-c/CAS.h"
13+
#include "clang/Basic/LLVM.h"
14+
#include "llvm/CAS/ActionCache.h"
15+
#include "llvm/CAS/ObjectStore.h"
16+
#include "llvm/Support/CBindingWrapping.h"
17+
#include <string>
18+
19+
namespace clang {
20+
namespace cas {
21+
22+
struct WrappedObjectStore {
23+
std::shared_ptr<ObjectStore> CAS;
24+
std::string CASPath;
25+
};
26+
27+
struct WrappedActionCache {
28+
std::shared_ptr<ActionCache> Cache;
29+
std::string CachePath;
30+
};
31+
32+
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(WrappedObjectStore, CXCASObjectStore)
33+
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(WrappedActionCache, CXCASActionCache)
34+
35+
} // namespace cas
36+
} // namespace clang
37+
38+
#endif // LLVM_CLANG_TOOLS_LIBCLANG_CASUTILS_H

clang/tools/libclang/CCAS.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//===- CCAS.cpp -----------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "clang-c/CAS.h"
10+
11+
#include "CASUtils.h"
12+
#include "CXString.h"
13+
14+
#include "clang/Basic/LLVM.h"
15+
#include "clang/CAS/CASOptions.h"
16+
#include "llvm/CAS/ActionCache.h"
17+
#include "llvm/CAS/ObjectStore.h"
18+
19+
using namespace clang;
20+
using namespace clang::cas;
21+
22+
void clang_experimental_cas_ObjectStore_dispose(CXCASObjectStore CAS) {
23+
delete unwrap(CAS);
24+
}
25+
void clang_experimental_cas_ActionCache_dispose(CXCASActionCache Cache) {
26+
delete unwrap(Cache);
27+
}
28+
29+
CXCASObjectStore
30+
clang_experimental_cas_OnDiskObjectStore_create(const char *Path,
31+
CXString *Error) {
32+
auto CAS = llvm::cas::createOnDiskCAS(Path);
33+
if (!CAS) {
34+
if (Error)
35+
*Error = cxstring::createDup(llvm::toString(CAS.takeError()));
36+
return nullptr;
37+
}
38+
return wrap(new WrappedObjectStore{std::move(*CAS), Path});
39+
}
40+
41+
CXCASActionCache
42+
clang_experimental_cas_OnDiskActionCache_create(const char *Path,
43+
CXString *Error) {
44+
auto Cache = llvm::cas::createOnDiskActionCache(Path);
45+
if (!Cache) {
46+
if (Error)
47+
*Error = cxstring::createDup(llvm::toString(Cache.takeError()));
48+
return nullptr;
49+
}
50+
return wrap(new WrappedActionCache{std::move(*Cache), Path});
51+
}

0 commit comments

Comments
 (0)