Skip to content

Revert "[Macros] Use 'LibraryPluginProvider' in swift-plugin-server" #73469

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion test/Macros/macro_plugin_server.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func testStringify(a: Int, b: Int) {
let s3: String = #stringify(b + a).1
print(s3)

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

// expected-error @+1 {{type 'MacroDefinition.NotMacroStruct' is not a valid macro implementation type in library plugin '}}
Expand Down
21 changes: 20 additions & 1 deletion tools/swift-plugin-server/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,29 @@
if (SWIFT_BUILD_SWIFT_SYNTAX)
# _swiftCSwiftPluginServer is just a C support library for swift-plugin-server
# Don't bother to create '.a' for that.
add_swift_host_library(_swiftCSwiftPluginServer STATIC
Sources/CSwiftPluginServer/PluginServer.cpp
LLVM_LINK_COMPONENTS support
)
target_link_libraries(_swiftCSwiftPluginServer PRIVATE
swiftDemangling
)
target_include_directories(_swiftCSwiftPluginServer PUBLIC
Sources/CSwiftPluginServer/include
)

add_pure_swift_host_tool(swift-plugin-server
Sources/swift-plugin-server/swift-plugin-server.swift
DEPENDENCIES
_swiftCSwiftPluginServer
SWIFT_COMPONENT
compiler
SWIFT_DEPENDENCIES
SwiftSyntaxMacros
SwiftSyntaxMacroExpansion
SwiftCompilerPluginMessageHandling
SwiftLibraryPluginProvider
)
target_include_directories(swift-plugin-server PRIVATE
Sources/CSwiftPluginServer/include
)
endif()
15 changes: 15 additions & 0 deletions tools/swift-plugin-server/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,25 @@ let package = Package(
.package(path: "../../../swift-syntax"),
],
targets: [
.target(
name: "CSwiftPluginServer",
cxxSettings: [
.unsafeFlags([
"-I", "../../include",
"-I", "../../../llvm-project/llvm/include",
])
]
),
.executableTarget(
name: "swift-plugin-server",
dependencies: [
.product(name: "SwiftCompilerPluginMessageHandling", package: "swift-syntax"),
.product(name: "SwiftDiagnostics", package: "swift-syntax"),
.product(name: "SwiftSyntax", package: "swift-syntax"),
.product(name: "SwiftOperators", package: "swift-syntax"),
.product(name: "SwiftParser", package: "swift-syntax"),
.product(name: "SwiftSyntaxMacros", package: "swift-syntax"),
"CSwiftPluginServer"
]
),
],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "PluginServer.h"
#include "swift/ABI/MetadataValues.h"
#include "swift/Demangling/Demangle.h"
#include "llvm/Support/DynamicLibrary.h"

#if defined(_WIN32)
#include <io.h>
#elif defined(__unix__) || defined(__APPLE__)
#include <dlfcn.h>
#include <unistd.h>
#endif

#include <string>
#include <errno.h>
#include <string.h>

using namespace swift;

void *PluginServer_load(const char *plugin, const char **errorMessage) {
// Use a static allocation for the error as the client will not release the
// string. POSIX 2008 (IEEE-1003.1-2008) specifies that it is implementation
// defined if `dlerror` is re-entrant. Take advantage of that and make it
// thread-unsafe. This ensures that the string outlives the call permitting
// the client to duplicate it.
static std::string error;
auto library = llvm::sys::DynamicLibrary::getLibrary(plugin, &error);
if (library.isValid())
return library.getOSSpecificHandle();
*errorMessage = error.c_str();
return nullptr;
}

const void *PluginServer_lookupMacroTypeMetadataByExternalName(
const char *moduleName, const char *typeName, void *libraryHint,
const char **errorMessage) {
// Look up the type metadata accessor as a struct, enum, or class.
const Demangle::Node::Kind typeKinds[] = {
Demangle::Node::Kind::Structure,
Demangle::Node::Kind::Enum,
Demangle::Node::Kind::Class,
};

void *accessorAddr = nullptr;
for (auto typeKind : typeKinds) {
auto symbolName =
mangledNameForTypeMetadataAccessor(moduleName, typeName, typeKind);

#if !defined(_WIN32)
if (libraryHint == nullptr)
libraryHint = RTLD_DEFAULT;
#endif
accessorAddr = llvm::sys::DynamicLibrary{libraryHint}
.getAddressOfSymbol(symbolName.c_str());
if (accessorAddr)
break;
}

if (!accessorAddr)
return nullptr;

// Call the accessor to form type metadata.
using MetadataAccessFunc = const void *(MetadataRequest);
auto accessor = reinterpret_cast<MetadataAccessFunc*>(accessorAddr);
return accessor(MetadataRequest(MetadataState::Complete));
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_PLUGINSERVER_PLUGINSERVER_H
#define SWIFT_PLUGINSERVER_PLUGINSERVER_H

#include <stddef.h>

#ifdef __cplusplus
extern "C" {
#endif

//===----------------------------------------------------------------------===//
// Dynamic link
//===----------------------------------------------------------------------===//

/// Load a dynamic link library, and return the handle.
void *PluginServer_load(const char *filename, const char **errorMessage);

/// Resolve a type metadata by a pair of the module name and the type name.
/// 'libraryHint' is a
const void *PluginServer_lookupMacroTypeMetadataByExternalName(
const char *moduleName, const char *typeName, void *libraryHint,
const char **errorMessage);

#ifdef __cplusplus
}
#endif

#endif /* SWIFT_PLUGINSERVER_PLUGINSERVER_H */
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module CSwiftPluginServer {
header "PluginServer.h"
export *
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,96 @@
//===----------------------------------------------------------------------===//

@_spi(PluginMessage) import SwiftCompilerPluginMessageHandling
@_spi(PluginMessage) import SwiftLibraryPluginProvider
import SwiftSyntaxMacros
import CSwiftPluginServer

@main
final class SwiftPluginServer {
struct MacroRef: Hashable {
var moduleName: String
var typeName: String
init(_ moduleName: String, _ typeName: String) {
self.moduleName = moduleName
self.typeName = typeName
}
}

struct LoadedLibraryPlugin {
var libraryPath: String
var handle: UnsafeMutableRawPointer
}

/// Loaded dylib handles associated with the module name.
var loadedLibraryPlugins: [String: LoadedLibraryPlugin] = [:]

/// Resolved cached macros.
var resolvedMacros: [MacroRef: Macro.Type] = [:]

/// @main entry point.
static func main() throws {
let connection = try StandardIOMessageConnection()
let listener = CompilerPluginMessageListener(
connection: connection,
provider: LibraryPluginProvider.shared
provider: self.init()
)
listener.main()
try listener.main()
}
}

extension SwiftPluginServer: PluginProvider {
/// Load a macro implementation from the dynamic link library.
func loadPluginLibrary(libraryPath: String, moduleName: String) throws {
var errorMessage: UnsafePointer<CChar>?
guard let dlHandle = PluginServer_load(libraryPath, &errorMessage) else {
throw PluginServerError(message: "loader error: " + String(cString: errorMessage!))
}
loadedLibraryPlugins[moduleName] = LoadedLibraryPlugin(
libraryPath: libraryPath,
handle: dlHandle
)
}

/// Lookup a loaded macro by a pair of module name and type name.
func resolveMacro(moduleName: String, typeName: String) throws -> Macro.Type {
if let resolved = resolvedMacros[.init(moduleName, typeName)] {
return resolved
}

// Find 'dlopen'ed library for the module name.
guard let plugin = loadedLibraryPlugins[moduleName] else {
// NOTE: This should be unreachable. Compiler should not use this server
// unless the plugin loading succeeded.
throw PluginServerError(message: "(plugin-server) plugin not loaded for module '\(moduleName)'")
}

// Lookup the type metadata.
var errorMessage: UnsafePointer<CChar>?
guard let macroTypePtr = PluginServer_lookupMacroTypeMetadataByExternalName(
moduleName, typeName, plugin.handle, &errorMessage
) else {
throw PluginServerError(message: "macro implementation type '\(moduleName).\(typeName)' could not be found in library plugin '\(plugin.libraryPath)'")
}

// THe type must be a 'Macro' type.
let macroType = unsafeBitCast(macroTypePtr, to: Any.Type.self)
guard let macro = macroType as? Macro.Type else {
throw PluginServerError(message: "type '\(moduleName).\(typeName)' is not a valid macro implementation type in library plugin '\(plugin.libraryPath)'")
}

// Cache the resolved type.
resolvedMacros[.init(moduleName, typeName)] = macro
return macro
}

/// This 'PluginProvider' implements 'loadLibraryMacro()'.
var features: [SwiftCompilerPluginMessageHandling.PluginFeature] {
[.loadPluginLibrary]
}
}

struct PluginServerError: Error, CustomStringConvertible {
var description: String
init(message: String) {
self.description = message
}
}