Skip to content

Commit e53da29

Browse files
Merge pull request #70724 from cachemeifyoucan/eng/PR-basic-macro-support-caching
[Caching] Preliminary simple macro support for caching
2 parents 01d891a + daa1065 commit e53da29

File tree

6 files changed

+268
-4
lines changed

6 files changed

+268
-4
lines changed

lib/AST/ModuleDependencies.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "swift/Frontend/Frontend.h"
2222
#include "llvm/CAS/CASProvidingFileSystem.h"
2323
#include "llvm/CAS/CachingOnDiskFileSystem.h"
24+
#include "llvm/Config/config.h"
2425
#include "llvm/Support/FileSystem.h"
2526
#include "llvm/Support/Path.h"
2627
#include "llvm/Support/PrefixMapper.h"
@@ -480,6 +481,58 @@ void SwiftDependencyTracker::addCommonSearchPathDeps(
480481
// Add VFSOverlay file.
481482
for (auto &Overlay: Opts.VFSOverlayFiles)
482483
FS->status(Overlay);
484+
485+
// Add plugin dylibs from the toolchain only by look through the plugin search
486+
// directory.
487+
auto recordFiles = [&](StringRef Path) {
488+
std::error_code EC;
489+
for (auto I = FS->dir_begin(Path, EC);
490+
!EC && I != llvm::vfs::directory_iterator(); I = I.increment(EC)) {
491+
if (I->type() != llvm::sys::fs::file_type::regular_file)
492+
continue;
493+
#if defined(_WIN32)
494+
constexpr StringRef libPrefix{};
495+
constexpr StringRef libSuffix = ".dll";
496+
#else
497+
constexpr StringRef libPrefix = "lib";
498+
constexpr StringRef libSuffix = LTDL_SHLIB_EXT;
499+
#endif
500+
StringRef filename = llvm::sys::path::filename(I->path());
501+
if (filename.starts_with(libPrefix) && filename.ends_with(libSuffix))
502+
FS->status(I->path());
503+
}
504+
};
505+
for (auto &entry : Opts.PluginSearchOpts) {
506+
switch (entry.getKind()) {
507+
508+
// '-load-plugin-library <library path>'.
509+
case PluginSearchOption::Kind::LoadPluginLibrary: {
510+
auto &val = entry.get<PluginSearchOption::LoadPluginLibrary>();
511+
FS->status(val.LibraryPath);
512+
break;
513+
}
514+
515+
// '-load-plugin-executable <executable path>#<module name>, ...'.
516+
case PluginSearchOption::Kind::LoadPluginExecutable: {
517+
// We don't have executable plugin in toolchain.
518+
break;
519+
}
520+
521+
// '-plugin-path <library search path>'.
522+
case PluginSearchOption::Kind::PluginPath: {
523+
auto &val = entry.get<PluginSearchOption::PluginPath>();
524+
recordFiles(val.SearchPath);
525+
break;
526+
}
527+
528+
// '-external-plugin-path <library search path>#<server path>'.
529+
case PluginSearchOption::Kind::ExternalPluginPath: {
530+
auto &val = entry.get<PluginSearchOption::ExternalPluginPath>();
531+
recordFiles(val.SearchPath);
532+
break;
533+
}
534+
}
535+
}
483536
}
484537

485538
void SwiftDependencyTracker::startTracking() {

lib/AST/PluginLoader.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "swift/Basic/SourceManager.h"
1818
#include "swift/Parse/Lexer.h"
1919
#include "llvm/Config/config.h"
20+
#include "llvm/Support/VirtualFileSystem.h"
2021

2122
using namespace swift;
2223

@@ -59,6 +60,15 @@ static StringRef pluginModuleNameStringFromPath(StringRef path) {
5960
return "";
6061
}
6162

63+
static llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
64+
getPluginLoadingFS(ASTContext &Ctx) {
65+
// If there is a clang include tree FS, using real file system to load plugin
66+
// as the FS in SourceMgr doesn't support directory iterator.
67+
if (Ctx.ClangImporterOpts.HasClangIncludeTreeRoot)
68+
return llvm::vfs::getRealFileSystem();
69+
return Ctx.SourceMgr.getFileSystem();
70+
}
71+
6272
llvm::DenseMap<Identifier, PluginLoader::PluginEntry> &
6373
PluginLoader::getPluginMap() {
6474
if (PluginMap.has_value()) {
@@ -86,7 +96,7 @@ PluginLoader::getPluginMap() {
8696
(void)result;
8797
};
8898

89-
auto fs = Ctx.SourceMgr.getFileSystem();
99+
auto fs = getPluginLoadingFS(Ctx);
90100
std::error_code ec;
91101

92102
for (auto &entry : Ctx.SearchPathOpts.PluginSearchOpts) {
@@ -162,7 +172,7 @@ PluginLoader::lookupPluginByModuleName(Identifier moduleName) {
162172

163173
llvm::Expected<LoadedLibraryPlugin *>
164174
PluginLoader::loadLibraryPlugin(StringRef path) {
165-
auto fs = Ctx.SourceMgr.getFileSystem();
175+
auto fs = getPluginLoadingFS(Ctx);
166176
SmallString<128> resolvedPath;
167177
if (auto err = fs->getRealPath(path, resolvedPath)) {
168178
return llvm::createStringError(err, err.message());
@@ -186,7 +196,7 @@ PluginLoader::loadLibraryPlugin(StringRef path) {
186196

187197
llvm::Expected<LoadedExecutablePlugin *>
188198
PluginLoader::loadExecutablePlugin(StringRef path) {
189-
auto fs = Ctx.SourceMgr.getFileSystem();
199+
auto fs = getPluginLoadingFS(Ctx);
190200
SmallString<128> resolvedPath;
191201
if (auto err = fs->getRealPath(path, resolvedPath)) {
192202
return llvm::createStringError(err, err.message());

lib/Sema/TypeCheckMacros.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,9 @@ initializeExecutablePlugin(ASTContext &ctx,
290290
if (!libraryPath.empty()) {
291291
#if SWIFT_BUILD_SWIFT_SYNTAX
292292
llvm::SmallString<128> resolvedLibraryPath;
293-
auto fs = ctx.SourceMgr.getFileSystem();
293+
auto fs = ctx.ClangImporterOpts.HasClangIncludeTreeRoot
294+
? llvm::vfs::getRealFileSystem()
295+
: ctx.SourceMgr.getFileSystem();
294296
if (auto err = fs->getRealPath(libraryPath, resolvedLibraryPath)) {
295297
return llvm::createStringError(err, err.message());
296298
}

test/CAS/macro_option_set.swift

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// REQUIRES: swift_swift_parser
2+
3+
// RUN: %empty-directory(%t)
4+
5+
// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-serialized -module-name MyApp -module-cache-path %t/clang-module-cache -O \
6+
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import \
7+
// RUN: %s -o %t/deps.json -swift-version 5 -cache-compile-job -cas-path %t/cas -plugin-path %swift-plugin-dir
8+
9+
// RUN: %S/Inputs/SwiftDepsExtractor.py %t/deps.json MyApp casFSRootID > %t/fs.casid
10+
// RUN: llvm-cas -cas %t/cas -ls-tree-recursive @%t/fs.casid | %FileCheck %s --check-prefix=FS
11+
12+
// FS: SwiftMacros
13+
14+
// RUN: %S/Inputs/BuildCommandExtractor.py %t/deps.json clang:SwiftShims > %t/SwiftShims.cmd
15+
// RUN: %swift_frontend_plain @%t/SwiftShims.cmd
16+
17+
// RUN: %S/Inputs/BuildCommandExtractor.py %t/deps.json MyApp > %t/MyApp.cmd
18+
// RUN: %{python} %S/Inputs/GenerateExplicitModuleMap.py %t/deps.json > %t/map.json
19+
// RUN: llvm-cas --cas %t/cas --make-blob --data %t/map.json > %t/map.casid
20+
21+
// RUN: %target-swift-frontend \
22+
// RUN: -typecheck -verify -cache-compile-job -cas-path %t/cas \
23+
// RUN: -swift-version 5 -disable-implicit-swift-modules \
24+
// RUN: -plugin-path %swift-plugin-dir \
25+
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import \
26+
// RUN: -module-name MyApp -explicit-swift-module-map-file @%t/map.casid \
27+
// RUN: %s @%t/MyApp.cmd
28+
29+
import Swift
30+
31+
@attached(member, names: named(RawValue), named(rawValue), named(`init`), arbitrary)
32+
@attached(extension, conformances: OptionSet)
33+
public macro OptionSet<RawType>() =
34+
#externalMacro(module: "SwiftMacros", type: "OptionSetMacro")
35+
36+
@OptionSet<UInt8>
37+
struct ShippingOptions {
38+
private enum Options: Int {
39+
case nextDay
40+
case secondDay
41+
case priority
42+
case standard
43+
}
44+
45+
static let express: ShippingOptions = [.nextDay, .secondDay]
46+
static let all: ShippingOptions = [.express, .priority, .standard]
47+
}
48+
49+
let options = ShippingOptions.express
50+
assert(options.contains(.nextDay))
51+
assert(options.contains(.secondDay))
52+
assert(!options.contains(.standard))
53+

test/CAS/macro_plugin.swift

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// REQUIRES: swift_swift_parser
2+
3+
/// Test loading and external library through `-load-plugin-library`
4+
/// TODO: switch this test case to use `-external-plugin-path`.
5+
6+
// RUN: %empty-directory(%t)
7+
// RUN: %empty-directory(%t/plugins)
8+
//
9+
//== Build the plugin library
10+
// RUN: %host-build-swift \
11+
// RUN: -swift-version 5 \
12+
// RUN: -emit-library \
13+
// RUN: -o %t/plugins/%target-library-name(MacroDefinition) \
14+
// RUN: -module-name=MacroDefinition \
15+
// RUN: %S/../Macros/Inputs/syntax_macro_definitions.swift \
16+
// RUN: -g -no-toolchain-stdlib-rpath
17+
18+
// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-serialized -module-name MyApp -module-cache-path %t/clang-module-cache -O \
19+
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import \
20+
// RUN: %s -o %t/deps.json -swift-version 5 -cache-compile-job -cas-path %t/cas -load-plugin-library %t/plugins/%target-library-name(MacroDefinition)
21+
22+
// RUN: %S/Inputs/SwiftDepsExtractor.py %t/deps.json MyApp casFSRootID > %t/fs.casid
23+
// RUN: llvm-cas -cas %t/cas -ls-tree-recursive @%t/fs.casid | %FileCheck %s --check-prefix=FS
24+
25+
// FS: MacroDefinition
26+
27+
// RUN: %S/Inputs/BuildCommandExtractor.py %t/deps.json clang:SwiftShims > %t/SwiftShims.cmd
28+
// RUN: %swift_frontend_plain @%t/SwiftShims.cmd
29+
30+
// RUN: %S/Inputs/BuildCommandExtractor.py %t/deps.json MyApp > %t/MyApp.cmd
31+
// RUN: %{python} %S/Inputs/GenerateExplicitModuleMap.py %t/deps.json > %t/map.json
32+
// RUN: llvm-cas --cas %t/cas --make-blob --data %t/map.json > %t/map.casid
33+
34+
// RUN: %target-swift-frontend \
35+
// RUN: -typecheck -verify -cache-compile-job -cas-path %t/cas \
36+
// RUN: -swift-version 5 -disable-implicit-swift-modules \
37+
// RUN: -load-plugin-library %t/plugins/%target-library-name(MacroDefinition) \
38+
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import \
39+
// RUN: -module-name MyApp -explicit-swift-module-map-file @%t/map.casid \
40+
// RUN: %s @%t/MyApp.cmd
41+
42+
@attached(extension, conformances: P, names: named(requirement))
43+
macro DelegatedConformance() = #externalMacro(module: "MacroDefinition", type: "DelegatedConformanceViaExtensionMacro")
44+
45+
protocol P {
46+
static func requirement()
47+
}
48+
49+
struct Wrapped: P {
50+
static func requirement() {
51+
print("Wrapped.requirement")
52+
}
53+
}
54+
55+
@DelegatedConformance
56+
struct Generic<Element> {}
57+
58+
// CHECK: {"expandMacroResult":{"diagnostics":[],"expandedSource":"extension Generic: P where Element: P {\n static func requirement() {\n Element.requirement()\n }\n}"}}
59+
60+
func requiresP(_ value: (some P).Type) {
61+
value.requirement()
62+
}
63+
64+
requiresP(Generic<Wrapped>.self)
65+
66+
struct Outer {
67+
@DelegatedConformance
68+
struct Nested<Element> {}
69+
}
70+
71+
// CHECK: {"expandMacroResult":{"diagnostics":[],"expandedSource":"extension Outer.Nested: P where Element: P {\n static func requirement() {\n Element.requirement()\n }\n}"}}
72+
73+
requiresP(Outer.Nested<Wrapped>.self)

test/CAS/macro_plugin_external.swift

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// REQUIRES: swift_swift_parser
2+
3+
/// Test loading and external library through `-load-plugin-library`
4+
/// TODO: switch this test case to use `-external-plugin-path`.
5+
6+
// RUN: %empty-directory(%t)
7+
// RUN: %empty-directory(%t/plugins)
8+
//
9+
//== Build the plugin library
10+
// RUN: %host-build-swift \
11+
// RUN: -swift-version 5 \
12+
// RUN: -emit-library \
13+
// RUN: -o %t/plugins/%target-library-name(MacroDefinition) \
14+
// RUN: -module-name=MacroDefinition \
15+
// RUN: %S/../Macros/Inputs/syntax_macro_definitions.swift \
16+
// RUN: -g -no-toolchain-stdlib-rpath
17+
18+
// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-serialized -module-name MyApp -module-cache-path %t/clang-module-cache -O \
19+
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import \
20+
// RUN: %s -o %t/deps.json -swift-version 5 -cache-compile-job -cas-path %t/cas -external-plugin-path %t/plugins#%swift-plugin-server
21+
22+
// RUN: %S/Inputs/SwiftDepsExtractor.py %t/deps.json MyApp casFSRootID > %t/fs.casid
23+
// RUN: llvm-cas -cas %t/cas -ls-tree-recursive @%t/fs.casid | %FileCheck %s --check-prefix=FS
24+
25+
// FS: MacroDefinition
26+
27+
// RUN: %S/Inputs/BuildCommandExtractor.py %t/deps.json clang:SwiftShims > %t/SwiftShims.cmd
28+
// RUN: %swift_frontend_plain @%t/SwiftShims.cmd
29+
30+
// RUN: %S/Inputs/BuildCommandExtractor.py %t/deps.json MyApp > %t/MyApp.cmd
31+
// RUN: %{python} %S/Inputs/GenerateExplicitModuleMap.py %t/deps.json > %t/map.json
32+
// RUN: llvm-cas --cas %t/cas --make-blob --data %t/map.json > %t/map.casid
33+
34+
// RUN: %target-swift-frontend \
35+
// RUN: -typecheck -verify -cache-compile-job -cas-path %t/cas \
36+
// RUN: -swift-version 5 -disable-implicit-swift-modules \
37+
// RUN: -external-plugin-path %t/plugins/#%swift-plugin-server \
38+
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import \
39+
// RUN: -module-name MyApp -explicit-swift-module-map-file @%t/map.casid \
40+
// RUN: %s @%t/MyApp.cmd
41+
42+
@attached(extension, conformances: P, names: named(requirement))
43+
macro DelegatedConformance() = #externalMacro(module: "MacroDefinition", type: "DelegatedConformanceViaExtensionMacro")
44+
45+
protocol P {
46+
static func requirement()
47+
}
48+
49+
struct Wrapped: P {
50+
static func requirement() {
51+
print("Wrapped.requirement")
52+
}
53+
}
54+
55+
@DelegatedConformance
56+
struct Generic<Element> {}
57+
58+
// CHECK: {"expandMacroResult":{"diagnostics":[],"expandedSource":"extension Generic: P where Element: P {\n static func requirement() {\n Element.requirement()\n }\n}"}}
59+
60+
func requiresP(_ value: (some P).Type) {
61+
value.requirement()
62+
}
63+
64+
requiresP(Generic<Wrapped>.self)
65+
66+
struct Outer {
67+
@DelegatedConformance
68+
struct Nested<Element> {}
69+
}
70+
71+
// CHECK: {"expandMacroResult":{"diagnostics":[],"expandedSource":"extension Outer.Nested: P where Element: P {\n static func requirement() {\n Element.requirement()\n }\n}"}}
72+
73+
requiresP(Outer.Nested<Wrapped>.self)

0 commit comments

Comments
 (0)