Skip to content

Commit 93e25d2

Browse files
authored
Merge pull request #64376 from rintaro/macros-plugin-server
2 parents 24a38fc + b2542a7 commit 93e25d2

27 files changed

+857
-109
lines changed

cmake/modules/AddPureSwift.cmake

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ function(add_pure_swift_host_library name)
137137
add_library(${name} ${libkind} ${APSHL_SOURCES})
138138
_add_host_swift_compile_options(${name})
139139

140+
set_property(TARGET ${name}
141+
PROPERTY BUILD_WITH_INSTALL_RPATH YES)
142+
140143
# Respect LLVM_COMMON_DEPENDS if it is set.
141144
#
142145
# LLVM_COMMON_DEPENDS if a global variable set in ./lib that provides targets
@@ -257,6 +260,13 @@ function(add_pure_swift_host_tool name)
257260
add_executable(${name} ${APSHT_SOURCES})
258261
_add_host_swift_compile_options(${name})
259262

263+
set_property(TARGET ${name}
264+
APPEND PROPERTY INSTALL_RPATH
265+
"@executable_path/../lib/swift/host")
266+
267+
set_property(TARGET ${name}
268+
PROPERTY BUILD_WITH_INSTALL_RPATH YES)
269+
260270
# Respect LLVM_COMMON_DEPENDS if it is set.
261271
#
262272
# LLVM_COMMON_DEPENDS if a global variable set in ./lib that provides targets

include/swift/AST/ASTContext.h

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1467,8 +1467,25 @@ class ASTContext final {
14671467

14681468
Type getNamedSwiftType(ModuleDecl *module, StringRef name);
14691469

1470-
LoadedExecutablePlugin *
1471-
lookupExecutablePluginByModuleName(Identifier moduleName);
1470+
/// Lookup an executable plugin that is declared to handle \p moduleName
1471+
/// module by '-load-plugin-executable'.
1472+
/// The path is valid within the VFS, use `FS.getRealPath()` for the
1473+
/// underlying path.
1474+
Optional<StringRef> lookupExecutablePluginByModuleName(Identifier moduleName);
1475+
1476+
/// Look for dynamic libraries in paths from `-external-plugin-path` and
1477+
/// return a pair of `(library path, plugin server executable)` if found.
1478+
/// These paths are valid within the VFS, use `FS.getRealPath()` for their
1479+
/// underlying path.
1480+
Optional<std::pair<std::string, std::string>>
1481+
lookupExternalLibraryPluginByModuleName(Identifier moduleName);
1482+
1483+
/// Launch the specified executable plugin path resolving the path with the
1484+
/// current VFS. If it fails to load the plugin, a diagnostic is emitted, and
1485+
/// returns a nullptr.
1486+
/// NOTE: This method is idempotent. If the plugin is already loaded, the same
1487+
/// instance is simply returned.
1488+
LoadedExecutablePlugin *loadExecutablePlugin(StringRef path);
14721489

14731490
/// Get the plugin registry this ASTContext is using.
14741491
PluginRegistry *getPluginRegistry() const;

include/swift/AST/SearchPathOptions.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,13 @@ class ModuleSearchPathLookup {
174174
llvm::vfs::FileSystem *FS, bool IsOSDarwin);
175175
};
176176

177+
/// Pair of a plugin search path and the corresponding plugin server executable
178+
/// path.
179+
struct ExternalPluginSearchPathAndServerPath {
180+
std::string SearchPath;
181+
std::string ServerPath;
182+
};
183+
177184
/// Options for controlling search path behavior.
178185
class SearchPathOptions {
179186
/// To call \c addImportSearchPath and \c addFrameworkSearchPath from
@@ -382,6 +389,12 @@ class SearchPathOptions {
382389
/// macro implementations.
383390
std::vector<std::string> PluginSearchPaths;
384391

392+
/// Pairs of external compiler plugin search paths and the corresponding
393+
/// plugin server executables.
394+
/// e.g. {"/path/to/usr/lib/swift/host/plugins",
395+
/// "/path/to/usr/bin/plugin-server"}
396+
std::vector<ExternalPluginSearchPathAndServerPath> ExternalPluginSearchPaths;
397+
385398
/// Don't look in for compiler-provided modules.
386399
bool SkipRuntimeLibraryImportPaths = false;
387400

include/swift/AST/TypeCheckRequests.h

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ struct ExternalMacroDefinition;
4949
class ClosureExpr;
5050
class GenericParamList;
5151
class LabeledStmt;
52+
class LoadedExecutablePlugin;
5253
class MacroDefinition;
5354
class PrecedenceGroupDecl;
5455
class PropertyWrapperInitializerInfo;
@@ -4000,19 +4001,51 @@ class ExpandSynthesizedMemberMacroRequest
40004001
/// Load a plugin module with the given name.
40014002
///
40024003
///
4004+
class LoadedCompilerPlugin {
4005+
enum class PluginKind : uint8_t {
4006+
None,
4007+
InProcess,
4008+
Executable,
4009+
};
4010+
PluginKind kind;
4011+
void *ptr;
4012+
4013+
LoadedCompilerPlugin(PluginKind kind, void *ptr) : kind(kind), ptr(ptr) {
4014+
assert(ptr != nullptr || kind == PluginKind::None);
4015+
}
4016+
4017+
public:
4018+
LoadedCompilerPlugin(std::nullptr_t) : kind(PluginKind::None), ptr(nullptr) {}
4019+
4020+
static LoadedCompilerPlugin inProcess(void *ptr) {
4021+
return {PluginKind::InProcess, ptr};
4022+
}
4023+
static LoadedCompilerPlugin executable(LoadedExecutablePlugin *ptr) {
4024+
return {PluginKind::Executable, ptr};
4025+
}
4026+
4027+
void *getAsInProcessPlugin() const {
4028+
return kind == PluginKind::InProcess ? ptr : nullptr;
4029+
}
4030+
LoadedExecutablePlugin *getAsExecutablePlugin() const {
4031+
return kind == PluginKind::Executable
4032+
? static_cast<LoadedExecutablePlugin *>(ptr)
4033+
: nullptr;
4034+
}
4035+
};
4036+
40034037
class CompilerPluginLoadRequest
4004-
: public SimpleRequest<CompilerPluginLoadRequest,
4005-
void *(ASTContext *, Identifier),
4006-
RequestFlags::Cached> {
4038+
: public SimpleRequest<CompilerPluginLoadRequest,
4039+
LoadedCompilerPlugin(ASTContext *, Identifier),
4040+
RequestFlags::Cached> {
40074041
public:
40084042
using SimpleRequest::SimpleRequest;
40094043

40104044
private:
40114045
friend SimpleRequest;
40124046

4013-
void *evaluate(
4014-
Evaluator &evaluator, ASTContext *ctx, Identifier moduleName
4015-
) const;
4047+
LoadedCompilerPlugin evaluate(Evaluator &evaluator, ASTContext *ctx,
4048+
Identifier moduleName) const;
40164049

40174050
public:
40184051
// Source location

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ SWIFT_REQUEST(TypeChecker, MacroDefinitionRequest,
431431
MacroDefinition(MacroDecl *),
432432
Cached, NoLocationInfo)
433433
SWIFT_REQUEST(TypeChecker, CompilerPluginLoadRequest,
434-
void *(ASTContext *, Identifier),
434+
LoadedCompilerPlugin(ASTContext *, Identifier),
435435
Cached, NoLocationInfo)
436436
SWIFT_REQUEST(TypeChecker, ExternalMacroDefinitionRequest,
437437
Optional<ExternalMacroDefinition>(ASTContext *, Identifier, Identifier),

include/swift/Demangling/Demangle.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,12 @@ bool isFunctionAttr(Node::Kind kind);
725725
/// contain symbolic references.
726726
llvm::StringRef makeSymbolicMangledNameStringRef(const char *base);
727727

728+
/// Produce the mangled name for the nominal type descriptor of a type
729+
/// referenced by its module and type name.
730+
std::string mangledNameForTypeMetadataAccessor(llvm::StringRef moduleName,
731+
llvm::StringRef typeName,
732+
Node::Kind typeKind);
733+
728734
SWIFT_END_INLINE_NAMESPACE
729735
} // end namespace Demangle
730736
} // end namespace swift

include/swift/Option/Options.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,11 @@ def plugin_path : Separate<["-"], "plugin-path">,
303303
Flags<[FrontendOption, ArgumentIsPath, SwiftAPIExtractOption, SwiftSymbolGraphExtractOption, SwiftAPIDigesterOption]>,
304304
HelpText<"Add directory to the plugin search path">;
305305

306+
def external_plugin_path : Separate<["-"], "external-plugin-path">,
307+
Flags<[FrontendOption, ArgumentIsPath, SwiftAPIExtractOption, SwiftSymbolGraphExtractOption, SwiftAPIDigesterOption]>,
308+
HelpText<"Add directory to the plugin search path with a plugin server executable">,
309+
MetaVarName<"<path>#<plugin-server-path>">;
310+
306311
def import_underlying_module : Flag<["-"], "import-underlying-module">,
307312
Flags<[FrontendOption, NoInteractiveOption]>,
308313
HelpText<"Implicitly imports the Objective-C half of a module">;

lib/AST/ASTContext.cpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
#include "llvm/ADT/Statistic.h"
6868
#include "llvm/ADT/StringMap.h"
6969
#include "llvm/ADT/StringSwitch.h"
70+
#include "llvm/Config/config.h"
7071
#include "llvm/IR/LLVMContext.h"
7172
#include "llvm/Support/Allocator.h"
7273
#include "llvm/Support/Compiler.h"
@@ -6348,15 +6349,30 @@ Type ASTContext::getNamedSwiftType(ModuleDecl *module, StringRef name) {
63486349
return decl->getDeclaredInterfaceType();
63496350
}
63506351

6351-
LoadedExecutablePlugin *
6352+
Optional<StringRef>
63526353
ASTContext::lookupExecutablePluginByModuleName(Identifier moduleName) {
63536354
auto &execPluginPaths = getImpl().ExecutablePluginPaths;
63546355
auto found = execPluginPaths.find(moduleName);
63556356
if (found == execPluginPaths.end())
6356-
return nullptr;
6357+
return None;
6358+
return found->second;
6359+
}
6360+
6361+
Optional<std::pair<std::string, std::string>>
6362+
ASTContext::lookupExternalLibraryPluginByModuleName(Identifier moduleName) {
6363+
auto fs = this->SourceMgr.getFileSystem();
6364+
for (auto &pair : SearchPathOpts.ExternalPluginSearchPaths) {
6365+
SmallString<128> fullPath(pair.SearchPath);
6366+
llvm::sys::path::append(fullPath, "lib" + moduleName.str() + LTDL_SHLIB_EXT);
6367+
6368+
if (fs->exists(fullPath)) {
6369+
return {{std::string(fullPath), pair.ServerPath}};
6370+
}
6371+
}
6372+
return None;
6373+
}
63576374

6358-
// Let the VFS to map the path.
6359-
auto &path = found->second;
6375+
LoadedExecutablePlugin *ASTContext::loadExecutablePlugin(StringRef path) {
63606376
SmallString<128> resolvedPath;
63616377
auto fs = this->SourceMgr.getFileSystem();
63626378
if (auto err = fs->getRealPath(path, resolvedPath)) {

lib/ASTGen/Package.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ let package = Package(
2222
.macOS(.v10_15)
2323
],
2424
products: [
25-
.library(name: "swiftASTGen", targets: ["swiftASTGen"])
25+
.library(name: "swiftASTGen", targets: ["swiftASTGen"]),
26+
.library(name: "swiftLLVMJSON", targets: ["swiftLLVMJSON"]),
2627
],
2728
dependencies: [
2829
.package(path: "../../../swift-syntax")

lib/ASTGen/Sources/ASTGen/Macros.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ public func resolveExecutableMacro(
112112
typeNameLength: Int,
113113
pluginOpaqueHandle: UnsafeMutableRawPointer
114114
) -> UnsafeRawPointer {
115+
// NOTE: This doesn't actually resolve anything.
116+
// Executable plugins is "trusted" to have the macro implementation. If not,
117+
// the actual expansion fails.
115118
let exportedPtr = UnsafeMutablePointer<ExportedExecutableMacro>.allocate(capacity: 1)
116119
exportedPtr.initialize(to: .init(
117120
moduleName: String(bufferStart: moduleName, count: moduleNameLength),

lib/ASTGen/Sources/ASTGen/PluginHost.swift

Lines changed: 73 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,54 @@ public func _deinitializePlugin(
3737
plugin.deinitialize()
3838
}
3939

40+
/// Load the library plugin in the plugin server.
41+
@_cdecl("swift_ASTGen_pluginServerLoadLibraryPlugin")
42+
func swift_ASTGen_pluginServerLoadLibraryPlugin(
43+
opaqueHandle: UnsafeMutableRawPointer,
44+
libraryPath: UnsafePointer<Int8>,
45+
moduleName: UnsafePointer<Int8>,
46+
cxxDiagnosticEngine: UnsafeMutablePointer<UInt8>
47+
) -> Bool {
48+
let plugin = CompilerPlugin(opaqueHandle: opaqueHandle)
49+
assert(plugin.capability?.features.contains(.loadPluginLibrary) == true)
50+
let libraryPath = String(cString: libraryPath)
51+
let moduleName = String(cString: moduleName)
52+
let diagEngine = PluginDiagnosticsEngine(cxxDiagnosticEngine: cxxDiagnosticEngine)
53+
54+
do {
55+
let result = try plugin.sendMessageAndWait(
56+
.loadPluginLibrary(libraryPath: libraryPath, moduleName: moduleName)
57+
)
58+
guard case .loadPluginLibraryResult(let loaded, let diagnostics) = result else {
59+
throw PluginError.invalidReponseKind
60+
}
61+
diagEngine.emit(diagnostics);
62+
return loaded
63+
} catch {
64+
diagEngine.diagnose(error: error)
65+
return false
66+
}
67+
}
68+
4069
struct CompilerPlugin {
70+
struct Capability {
71+
enum Feature: String {
72+
case loadPluginLibrary = "load-plugin-library"
73+
}
74+
75+
var protocolVersion: Int
76+
var features: Set<Feature>
77+
78+
init(_ message: PluginMessage.PluginCapability) {
79+
self.protocolVersion = message.protocolVersion
80+
if let features = message.features {
81+
self.features = Set(features.compactMap(Feature.init(rawValue:)))
82+
} else {
83+
self.features = []
84+
}
85+
}
86+
}
87+
4188
let opaqueHandle: UnsafeMutableRawPointer
4289

4390
private func withLock<R>(_ body: () throws -> R) rethrows -> R {
@@ -82,26 +129,26 @@ struct CompilerPlugin {
82129
}
83130

84131
func initialize() {
85-
self.withLock {
86-
// Get capability.
87-
let response: PluginToHostMessage
88-
do {
132+
// Don't use `sendMessageAndWait` because we want to keep the lock until
133+
// setting the returned value.
134+
do {
135+
try self.withLock {
136+
// Get capability.
89137
try self.sendMessage(.getCapability)
90-
response = try self.waitForNextMessage()
91-
} catch {
92-
assertionFailure(String(describing: error))
93-
return
94-
}
95-
switch response {
96-
case .getCapabilityResult(capability: let capability):
97-
let ptr = UnsafeMutablePointer<PluginMessage.PluginCapability>.allocate(capacity: 1)
98-
ptr.initialize(to: capability)
138+
let response = try self.waitForNextMessage()
139+
guard case .getCapabilityResult(let capability) = response else {
140+
throw PluginError.invalidReponseKind
141+
}
142+
let ptr = UnsafeMutablePointer<Capability>.allocate(capacity: 1)
143+
ptr.initialize(to: .init(capability))
99144
Plugin_setCapability(opaqueHandle, UnsafeRawPointer(ptr))
100-
default:
101-
assertionFailure("invalid response")
102145
}
146+
} catch {
147+
assertionFailure(String(describing: error))
148+
return
103149
}
104150
}
151+
105152
func deinitialize() {
106153
self.withLock {
107154
if let ptr = Plugin_getCapability(opaqueHandle) {
@@ -113,11 +160,11 @@ struct CompilerPlugin {
113160
}
114161
}
115162

116-
var capability: PluginMessage.PluginCapability {
163+
var capability: Capability? {
117164
if let ptr = Plugin_getCapability(opaqueHandle) {
118-
return ptr.assumingMemoryBound(to: PluginMessage.PluginCapability.self).pointee
165+
return ptr.assumingMemoryBound(to: Capability.self).pointee
119166
}
120-
return PluginMessage.PluginCapability(protocolVersion: 0)
167+
return nil
121168
}
122169
}
123170

@@ -224,6 +271,14 @@ class PluginDiagnosticsEngine {
224271
}
225272
}
226273

274+
func diagnose(error: Error) {
275+
self.emitSingle(
276+
message: String(describing: error),
277+
severity: .error,
278+
position: .invalid
279+
)
280+
}
281+
227282
/// Produce the C++ source location for a given position based on a
228283
/// syntax node.
229284
private func cxxSourceLocation(

0 commit comments

Comments
 (0)