Skip to content

Commit 4d8a657

Browse files
authored
Merge pull request #73469 from apple/revert-69236-macros-library-provider
Revert "[Macros] Use 'LibraryPluginProvider' in swift-plugin-server"
2 parents db7580f + 9a38072 commit 4d8a657

File tree

7 files changed

+239
-5
lines changed

7 files changed

+239
-5
lines changed

test/Macros/macro_plugin_server.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ func testStringify(a: Int, b: Int) {
8787
let s3: String = #stringify(b + a).1
8888
print(s3)
8989

90-
// expected-error @+1 {{type 'MacroDefinition.TypeDoesNotExist' could not be found in library plugin '}}
90+
// expected-error @+1 {{macro implementation type 'MacroDefinition.TypeDoesNotExist' could not be found in library plugin '}}
9191
_ = #missing()
9292

9393
// expected-error @+1 {{type 'MacroDefinition.NotMacroStruct' is not a valid macro implementation type in library plugin '}}
Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,29 @@
11
if (SWIFT_BUILD_SWIFT_SYNTAX)
2+
# _swiftCSwiftPluginServer is just a C support library for swift-plugin-server
3+
# Don't bother to create '.a' for that.
4+
add_swift_host_library(_swiftCSwiftPluginServer STATIC
5+
Sources/CSwiftPluginServer/PluginServer.cpp
6+
LLVM_LINK_COMPONENTS support
7+
)
8+
target_link_libraries(_swiftCSwiftPluginServer PRIVATE
9+
swiftDemangling
10+
)
11+
target_include_directories(_swiftCSwiftPluginServer PUBLIC
12+
Sources/CSwiftPluginServer/include
13+
)
14+
215
add_pure_swift_host_tool(swift-plugin-server
316
Sources/swift-plugin-server/swift-plugin-server.swift
17+
DEPENDENCIES
18+
_swiftCSwiftPluginServer
419
SWIFT_COMPONENT
520
compiler
621
SWIFT_DEPENDENCIES
22+
SwiftSyntaxMacros
23+
SwiftSyntaxMacroExpansion
724
SwiftCompilerPluginMessageHandling
8-
SwiftLibraryPluginProvider
25+
)
26+
target_include_directories(swift-plugin-server PRIVATE
27+
Sources/CSwiftPluginServer/include
928
)
1029
endif()

tools/swift-plugin-server/Package.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,25 @@ let package = Package(
1111
.package(path: "../../../swift-syntax"),
1212
],
1313
targets: [
14+
.target(
15+
name: "CSwiftPluginServer",
16+
cxxSettings: [
17+
.unsafeFlags([
18+
"-I", "../../include",
19+
"-I", "../../../llvm-project/llvm/include",
20+
])
21+
]
22+
),
1423
.executableTarget(
1524
name: "swift-plugin-server",
1625
dependencies: [
1726
.product(name: "SwiftCompilerPluginMessageHandling", package: "swift-syntax"),
27+
.product(name: "SwiftDiagnostics", package: "swift-syntax"),
28+
.product(name: "SwiftSyntax", package: "swift-syntax"),
29+
.product(name: "SwiftOperators", package: "swift-syntax"),
30+
.product(name: "SwiftParser", package: "swift-syntax"),
31+
.product(name: "SwiftSyntaxMacros", package: "swift-syntax"),
32+
"CSwiftPluginServer"
1833
]
1934
),
2035
],
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift open source project
4+
//
5+
// Copyright (c) 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "PluginServer.h"
14+
#include "swift/ABI/MetadataValues.h"
15+
#include "swift/Demangling/Demangle.h"
16+
#include "llvm/Support/DynamicLibrary.h"
17+
18+
#if defined(_WIN32)
19+
#include <io.h>
20+
#elif defined(__unix__) || defined(__APPLE__)
21+
#include <dlfcn.h>
22+
#include <unistd.h>
23+
#endif
24+
25+
#include <string>
26+
#include <errno.h>
27+
#include <string.h>
28+
29+
using namespace swift;
30+
31+
void *PluginServer_load(const char *plugin, const char **errorMessage) {
32+
// Use a static allocation for the error as the client will not release the
33+
// string. POSIX 2008 (IEEE-1003.1-2008) specifies that it is implementation
34+
// defined if `dlerror` is re-entrant. Take advantage of that and make it
35+
// thread-unsafe. This ensures that the string outlives the call permitting
36+
// the client to duplicate it.
37+
static std::string error;
38+
auto library = llvm::sys::DynamicLibrary::getLibrary(plugin, &error);
39+
if (library.isValid())
40+
return library.getOSSpecificHandle();
41+
*errorMessage = error.c_str();
42+
return nullptr;
43+
}
44+
45+
const void *PluginServer_lookupMacroTypeMetadataByExternalName(
46+
const char *moduleName, const char *typeName, void *libraryHint,
47+
const char **errorMessage) {
48+
// Look up the type metadata accessor as a struct, enum, or class.
49+
const Demangle::Node::Kind typeKinds[] = {
50+
Demangle::Node::Kind::Structure,
51+
Demangle::Node::Kind::Enum,
52+
Demangle::Node::Kind::Class,
53+
};
54+
55+
void *accessorAddr = nullptr;
56+
for (auto typeKind : typeKinds) {
57+
auto symbolName =
58+
mangledNameForTypeMetadataAccessor(moduleName, typeName, typeKind);
59+
60+
#if !defined(_WIN32)
61+
if (libraryHint == nullptr)
62+
libraryHint = RTLD_DEFAULT;
63+
#endif
64+
accessorAddr = llvm::sys::DynamicLibrary{libraryHint}
65+
.getAddressOfSymbol(symbolName.c_str());
66+
if (accessorAddr)
67+
break;
68+
}
69+
70+
if (!accessorAddr)
71+
return nullptr;
72+
73+
// Call the accessor to form type metadata.
74+
using MetadataAccessFunc = const void *(MetadataRequest);
75+
auto accessor = reinterpret_cast<MetadataAccessFunc*>(accessorAddr);
76+
return accessor(MetadataRequest(MetadataState::Complete));
77+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift open source project
4+
//
5+
// Copyright (c) 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef SWIFT_PLUGINSERVER_PLUGINSERVER_H
14+
#define SWIFT_PLUGINSERVER_PLUGINSERVER_H
15+
16+
#include <stddef.h>
17+
18+
#ifdef __cplusplus
19+
extern "C" {
20+
#endif
21+
22+
//===----------------------------------------------------------------------===//
23+
// Dynamic link
24+
//===----------------------------------------------------------------------===//
25+
26+
/// Load a dynamic link library, and return the handle.
27+
void *PluginServer_load(const char *filename, const char **errorMessage);
28+
29+
/// Resolve a type metadata by a pair of the module name and the type name.
30+
/// 'libraryHint' is a
31+
const void *PluginServer_lookupMacroTypeMetadataByExternalName(
32+
const char *moduleName, const char *typeName, void *libraryHint,
33+
const char **errorMessage);
34+
35+
#ifdef __cplusplus
36+
}
37+
#endif
38+
39+
#endif /* SWIFT_PLUGINSERVER_PLUGINSERVER_H */
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module CSwiftPluginServer {
2+
header "PluginServer.h"
3+
export *
4+
}

tools/swift-plugin-server/Sources/swift-plugin-server/swift-plugin-server.swift

Lines changed: 83 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,96 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
@_spi(PluginMessage) import SwiftCompilerPluginMessageHandling
14-
@_spi(PluginMessage) import SwiftLibraryPluginProvider
14+
import SwiftSyntaxMacros
15+
import CSwiftPluginServer
1516

1617
@main
1718
final class SwiftPluginServer {
19+
struct MacroRef: Hashable {
20+
var moduleName: String
21+
var typeName: String
22+
init(_ moduleName: String, _ typeName: String) {
23+
self.moduleName = moduleName
24+
self.typeName = typeName
25+
}
26+
}
27+
28+
struct LoadedLibraryPlugin {
29+
var libraryPath: String
30+
var handle: UnsafeMutableRawPointer
31+
}
32+
33+
/// Loaded dylib handles associated with the module name.
34+
var loadedLibraryPlugins: [String: LoadedLibraryPlugin] = [:]
35+
36+
/// Resolved cached macros.
37+
var resolvedMacros: [MacroRef: Macro.Type] = [:]
38+
39+
/// @main entry point.
1840
static func main() throws {
1941
let connection = try StandardIOMessageConnection()
2042
let listener = CompilerPluginMessageListener(
2143
connection: connection,
22-
provider: LibraryPluginProvider.shared
44+
provider: self.init()
2345
)
24-
listener.main()
46+
try listener.main()
47+
}
48+
}
49+
50+
extension SwiftPluginServer: PluginProvider {
51+
/// Load a macro implementation from the dynamic link library.
52+
func loadPluginLibrary(libraryPath: String, moduleName: String) throws {
53+
var errorMessage: UnsafePointer<CChar>?
54+
guard let dlHandle = PluginServer_load(libraryPath, &errorMessage) else {
55+
throw PluginServerError(message: "loader error: " + String(cString: errorMessage!))
56+
}
57+
loadedLibraryPlugins[moduleName] = LoadedLibraryPlugin(
58+
libraryPath: libraryPath,
59+
handle: dlHandle
60+
)
61+
}
62+
63+
/// Lookup a loaded macro by a pair of module name and type name.
64+
func resolveMacro(moduleName: String, typeName: String) throws -> Macro.Type {
65+
if let resolved = resolvedMacros[.init(moduleName, typeName)] {
66+
return resolved
67+
}
68+
69+
// Find 'dlopen'ed library for the module name.
70+
guard let plugin = loadedLibraryPlugins[moduleName] else {
71+
// NOTE: This should be unreachable. Compiler should not use this server
72+
// unless the plugin loading succeeded.
73+
throw PluginServerError(message: "(plugin-server) plugin not loaded for module '\(moduleName)'")
74+
}
75+
76+
// Lookup the type metadata.
77+
var errorMessage: UnsafePointer<CChar>?
78+
guard let macroTypePtr = PluginServer_lookupMacroTypeMetadataByExternalName(
79+
moduleName, typeName, plugin.handle, &errorMessage
80+
) else {
81+
throw PluginServerError(message: "macro implementation type '\(moduleName).\(typeName)' could not be found in library plugin '\(plugin.libraryPath)'")
82+
}
83+
84+
// THe type must be a 'Macro' type.
85+
let macroType = unsafeBitCast(macroTypePtr, to: Any.Type.self)
86+
guard let macro = macroType as? Macro.Type else {
87+
throw PluginServerError(message: "type '\(moduleName).\(typeName)' is not a valid macro implementation type in library plugin '\(plugin.libraryPath)'")
88+
}
89+
90+
// Cache the resolved type.
91+
resolvedMacros[.init(moduleName, typeName)] = macro
92+
return macro
93+
}
94+
95+
/// This 'PluginProvider' implements 'loadLibraryMacro()'.
96+
var features: [SwiftCompilerPluginMessageHandling.PluginFeature] {
97+
[.loadPluginLibrary]
98+
}
99+
}
100+
101+
struct PluginServerError: Error, CustomStringConvertible {
102+
var description: String
103+
init(message: String) {
104+
self.description = message
25105
}
26106
}

0 commit comments

Comments
 (0)