From b7717f15ef0f72f2225287d97e9be622b0060e7d Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Tue, 21 May 2024 12:56:52 -0700 Subject: [PATCH 1/5] [Macros] In-process plugin server Separate swift-syntax libs for the compiler and for the library plugins. Compiler communicates with library plugins using serialized messages just like executable plugins. * `lib/swift/host/compiler/lib_Compiler*.dylib`(`lib/CompilerSwiftSyntax`): swift-syntax libraries for compiler. Library evolution is disabled. * Compiler (`ASTGen` and `swiftIDEUtilsBridging`) only depends on `lib/swift/host/compiler` libraries. * `SwiftInProcPluginServer`: In-process plugin server shared library. This has one `swift_inproc_plugins_handle_message` entry point that receives a message and return the response. * In the compiler * Add `-in-process-plugin-server-path` front-end option, which specifies the `SwiftInProcPluginServer` shared library path. * Remove `LoadedLibraryPlugin`, because all library plugins are managed by `SwiftInProcPluginServer` * Introduce abstract `CompilerPlugin` class that has 2 subclasses: * `LoadedExecutablePlugin` existing class that represents an executable plugin * `InProcessPlugins` wraps `dlopen`ed `SwiftInProcPluginServer` * Unified the code path in `TypeCheckMacros.cpp` and `ASTGen`, the difference between executable plugins and library plugins are now abstracted by `CompilerPlugin` (cherry picked from commit 2f7aa428db2ab1f4b47eb4b0ffb14fb3be046b61) --- cmake/modules/AddPureSwift.cmake | 57 ++-- cmake/modules/AddSwift.cmake | 4 +- cmake/modules/AddSwiftUnittests.cmake | 4 +- include/swift/AST/ASTBridging.h | 3 - include/swift/AST/ASTContext.h | 2 - include/swift/AST/MacroDefinition.h | 32 +- include/swift/AST/PluginLoader.h | 5 +- include/swift/AST/PluginRegistry.h | 196 +++++++----- include/swift/AST/SearchPathOptions.h | 3 + include/swift/AST/TypeCheckRequests.h | 36 +-- include/swift/Bridging/ASTGen.h | 11 +- include/swift/Option/Options.td | 4 + lib/AST/ASTBridging.cpp | 19 +- lib/AST/PluginLoader.cpp | 29 +- lib/AST/PluginRegistry.cpp | 130 +++++--- lib/ASTGen/CMakeLists.txt | 30 +- lib/ASTGen/Package.swift | 2 - lib/ASTGen/Sources/ASTGen/Macros.swift | 294 ++---------------- lib/ASTGen/Sources/ASTGen/PluginHost.swift | 26 +- .../SourceManager+MacroExpansionContext.swift | 192 ------------ lib/ASTGen/Sources/ASTGen/SourceManager.swift | 1 - lib/CMakeLists.txt | 1 + lib/CompilerSwiftSyntax/CMakeLists.txt | 52 ++++ lib/Driver/DarwinToolChains.cpp | 10 +- lib/Driver/UnixToolChains.cpp | 10 +- lib/Driver/WindowsToolChains.cpp | 7 + lib/DriverTool/CMakeLists.txt | 11 + lib/Frontend/CMakeLists.txt | 11 + lib/Frontend/CompilerInvocation.cpp | 3 + lib/Parse/CMakeLists.txt | 16 - lib/Sema/TypeCheckMacros.cpp | 200 ++++-------- test/Macros/macro_expand.swift | 4 +- test/Macros/macro_plugin_broken_shlib.swift | 4 +- test/Macros/macro_plugin_error.swift | 2 +- test/lit.cfg | 19 +- .../cmake/modules/AddSwiftSourceKit.cmake | 4 +- tools/driver/CMakeLists.txt | 1 + tools/libSwiftScan/CMakeLists.txt | 12 +- tools/swift-ide-test/swift-ide-test.cpp | 9 + tools/swift-plugin-server/CMakeLists.txt | 28 ++ tools/swift-plugin-server/Package.swift | 12 + .../InProcPluginServer.swift | 88 ++++++ 42 files changed, 695 insertions(+), 889 deletions(-) delete mode 100644 lib/ASTGen/Sources/ASTGen/SourceManager+MacroExpansionContext.swift create mode 100644 lib/CompilerSwiftSyntax/CMakeLists.txt create mode 100644 tools/swift-plugin-server/Sources/SwiftInProcPluginServer/InProcPluginServer.swift diff --git a/cmake/modules/AddPureSwift.cmake b/cmake/modules/AddPureSwift.cmake index 47469796c86dd..1e6c769854c2b 100644 --- a/cmake/modules/AddPureSwift.cmake +++ b/cmake/modules/AddPureSwift.cmake @@ -4,13 +4,12 @@ include(macCatalystUtils) function(force_add_dependencies TARGET) foreach(DEPENDENCY ${ARGN}) string(REGEX REPLACE [<>:\"/\\|?*] _ sanitized ${DEPENDENCY}) - add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/forced-${sanitized}-dep.swift - COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/forced-${sanitized}-dep.swift + set(depfile "${CMAKE_CURRENT_BINARY_DIR}/forced-${sanitized}-dep.swift") + add_custom_command(OUTPUT ${depfile} + COMMAND ${CMAKE_COMMAND} -E touch ${depfile} DEPENDS ${DEPENDENCY} ) - target_sources(${TARGET} PRIVATE - ${CMAKE_CURRENT_BINARY_DIR}/forced-${sanitized}-dep.swift - ) + target_sources(${TARGET} PRIVATE ${depfile}) endforeach() endfunction() @@ -198,15 +197,6 @@ function(add_pure_swift_host_library name) # Depends on all '*.h' files in 'include/module.modulemap'. force_add_dependencies(${name} importedHeaderDependencies) - # Workaround to touch the library and its objects so that we don't - # continually rebuild (again, see corresponding change in swift-syntax). - add_custom_command( - TARGET ${name} - POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E touch_nocreate $ $ "${SWIFT_HOST_LIBRARIES_DEST_DIR}/${name}.swiftmodule" "${CMAKE_CURRENT_BINARY_DIR}/${name}.swiftmodule" - COMMAND_EXPAND_LISTS - COMMENT "Update mtime of library outputs workaround") - # Link against dependencies. target_link_libraries(${name} PUBLIC ${APSHL_DEPENDENCIES} @@ -216,15 +206,7 @@ function(add_pure_swift_host_library name) ${APSHL_SWIFT_DEPENDENCIES} ) - # Make sure we can use the host libraries. - target_include_directories(${name} PUBLIC - "${SWIFT_HOST_LIBRARIES_DEST_DIR}") - target_link_directories(${name} PUBLIC - "${SWIFT_HOST_LIBRARIES_DEST_DIR}") - if(APSHL_EMIT_MODULE) - # Determine where Swift modules will be built and installed. - set(module_triple "${SWIFT_HOST_MODULE_TRIPLE}") set(module_dir "${SWIFT_HOST_LIBRARIES_DEST_DIR}") set(module_base "${module_dir}/${name}.swiftmodule") @@ -233,14 +215,6 @@ function(add_pure_swift_host_library name) set(module_private_interface_file "${module_base}/${module_triple}.private.swiftinterface") set(module_sourceinfo_file "${module_base}/${module_triple}.swiftsourceinfo") - set_target_properties(${name} PROPERTIES - # Set the default module name to the target name. - Swift_MODULE_NAME ${name} - # Install the Swift module into the appropriate location. - Swift_MODULE_DIRECTORY ${module_dir} - # NOTE: workaround for CMake not setting up include flags. - INTERFACE_INCLUDE_DIRECTORIES ${module_dir}) - # Create the module directory. add_custom_command( TARGET ${name} @@ -260,12 +234,27 @@ function(add_pure_swift_host_library name) >) else() # Emit a swiftmodule in the current directory. - set_target_properties(${name} PROPERTIES - Swift_MODULE_NAME ${name} - Swift_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - set(module_file "${CMAKE_CURRENT_BINARY_DIR}/${name}.swiftmodule") + set(module_dir "${CMAKE_CURRENT_BINARY_DIR}/modules") + set(module_file "${module_dir}/${name}.swiftmodule") endif() + set_target_properties(${name} PROPERTIES + # Set the default module name to the target name. + Swift_MODULE_NAME ${name} + # Install the Swift module into the appropriate location. + Swift_MODULE_DIRECTORY ${module_dir} + # NOTE: workaround for CMake not setting up include flags. + INTERFACE_INCLUDE_DIRECTORIES ${module_dir}) + + # Workaround to touch the library and its objects so that we don't + # continually rebuild (again, see corresponding change in swift-syntax). + add_custom_command( + TARGET ${name} + POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E touch_nocreate $ $ "${module_file}" + COMMAND_EXPAND_LISTS + COMMENT "Update mtime of library outputs workaround") + # Downstream linking should include the swiftmodule in debug builds to allow lldb to # work correctly. Only do this on Darwin since neither gold (currently used by default # on Linux), nor the default Windows linker 'link' support '-add_ast_path'. diff --git a/cmake/modules/AddSwift.cmake b/cmake/modules/AddSwift.cmake index b7e56cdfaa4cd..9b2e7634ec9c0 100644 --- a/cmake/modules/AddSwift.cmake +++ b/cmake/modules/AddSwift.cmake @@ -1008,12 +1008,12 @@ function(add_swift_host_tool executable) set_property( TARGET ${executable} APPEND PROPERTY INSTALL_RPATH - "@executable_path/../${extra_relative_rpath}lib/swift/host") + "@executable_path/../${extra_relative_rpath}lib/swift/host/compiler") else() set_property( TARGET ${executable} APPEND PROPERTY INSTALL_RPATH - "$ORIGIN/../${extra_relative_rpath}lib/swift/host") + "$ORIGIN/../${extra_relative_rpath}lib/swift/host/compiler") endif() endif() diff --git a/cmake/modules/AddSwiftUnittests.cmake b/cmake/modules/AddSwiftUnittests.cmake index 6626fe8bcb68a..0979438fa032b 100644 --- a/cmake/modules/AddSwiftUnittests.cmake +++ b/cmake/modules/AddSwiftUnittests.cmake @@ -133,11 +133,11 @@ function(add_swift_unittest test_dirname) if(SWIFT_HOST_VARIANT_SDK IN_LIST SWIFT_DARWIN_PLATFORMS) set_property( TARGET ${test_dirname} - APPEND PROPERTY INSTALL_RPATH "@executable_path/${relative_lib_path}/swift/host") + APPEND PROPERTY INSTALL_RPATH "@executable_path/${relative_lib_path}/swift/host/compiler") elseif(SWIFT_HOST_VARIANT_SDK MATCHES "LINUX|ANDROID|OPENBSD|FREEBSD") set_property( TARGET ${test_dirname} - APPEND PROPERTY INSTALL_RPATH "$ORIGIN/${relative_lib_path}/swift/host") + APPEND PROPERTY INSTALL_RPATH "$ORIGIN/${relative_lib_path}/swift/host/compiler") endif() endif() endfunction() diff --git a/include/swift/AST/ASTBridging.h b/include/swift/AST/ASTBridging.h index 5a2783bb3e451..6f466cca6269d 100644 --- a/include/swift/AST/ASTBridging.h +++ b/include/swift/AST/ASTBridging.h @@ -1863,9 +1863,6 @@ void Plugin_setCapability(PluginHandle handle, /// Get a capability data set by \c Plugin_setCapability . PluginCapabilityPtr _Nullable Plugin_getCapability(PluginHandle handle); -/// Get the executable file path of the plugin. -const char *Plugin_getExecutableFilePath(PluginHandle handle); - /// Lock the plugin. Clients should lock it during sending and recving the /// response. void Plugin_lock(PluginHandle handle); diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index f0622adfcd0cf..09787818085a5 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -84,8 +84,6 @@ namespace swift { class DifferentiableAttr; class ExtensionDecl; struct ExternalSourceLocs; - class LoadedExecutablePlugin; - class LoadedLibraryPlugin; class ForeignRepresentationInfo; class FuncDecl; class GenericContext; diff --git a/include/swift/AST/MacroDefinition.h b/include/swift/AST/MacroDefinition.h index ac37b885eb36e..77ac17dc101d4 100644 --- a/include/swift/AST/MacroDefinition.h +++ b/include/swift/AST/MacroDefinition.h @@ -26,24 +26,38 @@ namespace swift { class ASTContext; /// A reference to an external macro definition that is understood by ASTGen. -struct ExternalMacroDefinition { - enum class PluginKind : int8_t { - InProcess = 0, - Executable = 1, - Error = -1, +class ExternalMacroDefinition { + enum class Status : int8_t { + Success = 0, + Error, }; - PluginKind kind; + Status status; /// ASTGen's notion of an macro definition, which is opaque to the C++ part /// of the compiler. If 'kind' is 'PluginKind::Error', this is a C-string to /// the error message - const void *opaqueHandle = nullptr; + const void *opaqueHandle; + + ExternalMacroDefinition(Status status, const void *opaqueHandle) + : status(status), opaqueHandle(opaqueHandle) {} + +public: + static ExternalMacroDefinition success(const void *opaqueHandle) { + return ExternalMacroDefinition{Status::Success, opaqueHandle}; + } static ExternalMacroDefinition error(NullTerminatedStringRef message) { - return ExternalMacroDefinition{PluginKind::Error, + return ExternalMacroDefinition{Status::Error, static_cast(message.data())}; } - bool isError() const { return kind == PluginKind::Error; } + + const void *get() { + if (status != Status::Success) + return nullptr; + return opaqueHandle; + } + bool isError() const { return status == Status::Error; } NullTerminatedStringRef getErrorMessage() const { + assert(isError()); return static_cast(opaqueHandle); } }; diff --git a/include/swift/AST/PluginLoader.h b/include/swift/AST/PluginLoader.h index f35d5adea7fb8..fdcd73f13ba97 100644 --- a/include/swift/AST/PluginLoader.h +++ b/include/swift/AST/PluginLoader.h @@ -78,15 +78,14 @@ class PluginLoader { /// returns a nullptr. /// NOTE: This method is idempotent. If the plugin is already loaded, the same /// instance is simply returned. - llvm::Expected loadLibraryPlugin(llvm::StringRef path); + llvm::Expected getInProcessPlugins(); /// Launch the specified executable plugin path resolving the path with the /// current VFS. If it fails to load the plugin, a diagnostic is emitted, and /// returns a nullptr. /// NOTE: This method is idempotent. If the plugin is already loaded, the same /// instance is simply returned. - llvm::Expected - loadExecutablePlugin(llvm::StringRef path); + llvm::Expected loadExecutablePlugin(llvm::StringRef path); /// Add the specified plugin associated with the module name to the dependency /// tracker if needed. diff --git a/include/swift/AST/PluginRegistry.h b/include/swift/AST/PluginRegistry.h index 74a323e520b80..3f417e1ad3d55 100644 --- a/include/swift/AST/PluginRegistry.h +++ b/include/swift/AST/PluginRegistry.h @@ -17,6 +17,7 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Chrono.h" +#include "llvm/Support/DynamicLibrary.h" #include "llvm/Support/Error.h" #include "llvm/Support/Program.h" @@ -25,26 +26,114 @@ namespace swift { -/// Represent a 'dlopen'ed plugin library. -class LoadedLibraryPlugin { - // Opaque handle used to interface with OS-specific dynamic library. - void *handle; +/// Base class for compiler plugins, or plugin servers. +class CompilerPlugin { + const std::string path; - /// Cache of loaded symbols. - llvm::StringMap resolvedSymbols; + std::mutex mtx; + + /// Opaque value of the protocol capability of the plugin. This is a + /// value from ASTGen. + const void *capability = nullptr; + + /// Cleanup function to call ASTGen. + std::function cleanup; + + /// Callbacks to be called when the connection is restored. + llvm::SmallVector *, 0> onReconnect; + + /// Flag to enable dumping of plugin messages. + bool dumpMessaging = false; - /// Path to the plugin library. - const std::string LibraryPath; +protected: + CompilerPlugin(llvm::StringRef path) : path(path) {} + + bool shouldDumpMessaging() const { return dumpMessaging; } public: - LoadedLibraryPlugin(void *handle, StringRef path) - : handle(handle), LibraryPath(path) {} + NullTerminatedStringRef getPath() const { + return {path.c_str(), path.size()}; + } + + void lock() { mtx.lock(); } + void unlock() { mtx.unlock(); } + + bool isInitialized() const { return bool(cleanup); } + void setCleanup(std::function cleanup) { + this->cleanup = cleanup; + } + + const void *getCapability() { return capability; }; + void setCapability(const void *newValue) { capability = newValue; }; + + void setDumpMessaging(bool flag) { dumpMessaging = flag; } + + virtual ~CompilerPlugin(); + + /// Launch the plugin if it's not already running, or it's stale. Return an + /// error if it's fails to execute it. + virtual llvm::Error spawnIfNeeded() = 0; + + /// Send a message to the plugin. + virtual llvm::Error sendMessage(llvm::StringRef message) = 0; + + /// Wait for a message from plugin and returns it. + virtual llvm::Expected waitForNextMessage() = 0; + + /// Add "on reconnect" callback. + /// These callbacks are called when `spawnIfNeeded()` relaunched the plugin. + void addOnReconnect(std::function *fn) { + onReconnect.push_back(fn); + } - /// Finds the address of the given symbol within the library. - void *getAddressOfSymbol(const char *symbolName); + /// Remove "on reconnect" callback. + void removeOnReconnect(std::function *fn) { + llvm::erase_value(onReconnect, fn); + } - NullTerminatedStringRef getLibraryPath() { - return {LibraryPath.c_str(), LibraryPath.size()}; + ArrayRef *> getOnReconnectCallbacks() { + return onReconnect; + } +}; + +/// Represents a in-process plugin server. +class InProcessPlugins : public CompilerPlugin { + /// PluginServer + llvm::sys::DynamicLibrary server; + + /// Entry point in the in-process plugin server. It receives the request + /// string and populate the response string. The return value indicates there + /// was an error. If true the returned string contains the error message. + /// 'free'ing the populated `responseDataPtr` is caller's responsibility. + using HandleMessageFunction = bool (*)(const char *requestData, + size_t requestLength, + char **responseDataPtr, + size_t *responseDataLengthPtr); + HandleMessageFunction handleMessageFn; + + /// Temporary storage for the response data from 'handleMessageFn'. + std::string receivedResponse; + + InProcessPlugins(llvm::StringRef serverPath, llvm::sys::DynamicLibrary server, + HandleMessageFunction handleMessageFn) + : CompilerPlugin(serverPath), server(server), + handleMessageFn(handleMessageFn) {} + +public: + /// Create an instance by loading the in-process plugin server at 'serverPath' + /// and return it. + static llvm::Expected> + create(const char *serverPath); + + /// Send a message to the plugin. + llvm::Error sendMessage(llvm::StringRef message) override; + + /// Wait for a message from plugin and returns it. + llvm::Expected waitForNextMessage() override; + + llvm::Error spawnIfNeeded() override { + // NOOP. It's always loaded. + return llvm::Error::success(); } }; @@ -56,7 +145,7 @@ class LoadedLibraryPlugin { /// launch it and manages the process. When the plugin process crashes, this /// should automatically relaunch the process so the clients can keep using this /// object as the interface. -class LoadedExecutablePlugin { +class LoadedExecutablePlugin : public CompilerPlugin { /// Represents the current process of the executable plugin. struct PluginProcess { @@ -76,38 +165,23 @@ class LoadedExecutablePlugin { /// Launched current process. std::unique_ptr Process; - /// Path to the plugin executable. - const std::string ExecutablePath; - /// Last modification time of the `ExecutablePath` when this is initialized. const llvm::sys::TimePoint<> LastModificationTime; - /// Opaque value of the protocol capability of the pluugin. This is a - /// value from ASTGen. - const void *capability = nullptr; - - /// Callbacks to be called when the connection is restored. - llvm::SmallVector *, 0> onReconnect; - /// Disable sandbox. bool disableSandbox = false; - /// Flag to dump plugin messagings. - bool dumpMessaging = false; - - /// Cleanup function to call ASTGen. - std::function cleanup; - - std::mutex mtx; + /// Mark the current process "stale" (not usable anymore for some reason, + /// probably crashed). + void setStale() { Process->isStale = true; } public: LoadedExecutablePlugin(llvm::StringRef ExecutablePath, llvm::sys::TimePoint<> LastModificationTime, bool disableSandbox) - : ExecutablePath(ExecutablePath), + : CompilerPlugin(ExecutablePath), LastModificationTime(LastModificationTime), disableSandbox(disableSandbox){}; - ~LoadedExecutablePlugin(); /// The last modification time of 'ExecutablePath' when this object is /// created. @@ -118,54 +192,23 @@ class LoadedExecutablePlugin { /// Indicates that the current process is usable. bool isAlive() const { return Process != nullptr && !Process->isStale; } - /// Mark the current process "stale". - void setStale() const { Process->isStale = true; } - - void lock() { mtx.lock(); } - void unlock() { mtx.unlock(); } - // Launch the plugin if it's not already running, or it's stale. Return an // error if it's fails to execute it. - llvm::Error spawnIfNeeded(); + llvm::Error spawnIfNeeded() override; /// Send a message to the plugin. - llvm::Error sendMessage(llvm::StringRef message) const; + llvm::Error sendMessage(llvm::StringRef message) override; /// Wait for a message from plugin and returns it. - llvm::Expected waitForNextMessage() const; - - bool isInitialized() const { return bool(cleanup); } - void setCleanup(std::function cleanup) { - this->cleanup = cleanup; - } - - /// Add "on reconnect" callback. - /// These callbacks are called when `spawnIfNeeded()` relaunched the plugin. - void addOnReconnect(std::function *fn) { - onReconnect.push_back(fn); - } - - /// Remove "on reconnect" callback. - void removeOnReconnect(std::function *fn) { - llvm::erase_value(onReconnect, fn); - } + llvm::Expected waitForNextMessage() override; llvm::sys::procid_t getPid() { return Process->process.Pid; } llvm::sys::process_t getProcess() { return Process->process.Process; } - - NullTerminatedStringRef getExecutablePath() { - return {ExecutablePath.c_str(), ExecutablePath.size()}; - } - - const void *getCapability() { return capability; }; - void setCapability(const void *newValue) { capability = newValue; }; - - void setDumpMessaging(bool flag) { dumpMessaging = flag; } }; class PluginRegistry { - /// Record of loaded plugin library modules. - llvm::StringMap> LoadedPluginLibraries; + /// The in-process plugin server. + std::unique_ptr inProcessPlugins; /// Record of loaded plugin executables. llvm::StringMap> @@ -179,14 +222,17 @@ class PluginRegistry { public: PluginRegistry(); - /// Load a dynamic link library specified by \p path. - /// If \p path plugin is already loaded, this returns the cached object. - llvm::Expected loadLibraryPlugin(llvm::StringRef path); + /// Get the in-process plugin server. + /// If it's loaded, returned the cached object. If the loaded instance is + /// from a different 'serverPath', returns an error as we don't support + /// multiple in-process plugin server in a host process. + llvm::Expected + getInProcessPlugins(llvm::StringRef serverPath); /// Load an executable plugin specified by \p path . /// If \p path plugin is already loaded, this returns the cached object. - llvm::Expected - loadExecutablePlugin(llvm::StringRef path, bool disableSandbox); + llvm::Expected loadExecutablePlugin(llvm::StringRef path, + bool disableSandbox); }; } // namespace swift diff --git a/include/swift/AST/SearchPathOptions.h b/include/swift/AST/SearchPathOptions.h index f58abedcd2e4b..5d21ca6f29217 100644 --- a/include/swift/AST/SearchPathOptions.h +++ b/include/swift/AST/SearchPathOptions.h @@ -469,6 +469,9 @@ class SearchPathOptions { /// Plugin search path options. std::vector PluginSearchOpts; + /// Path to in-process plugin server shared library. + std::string InProcessPluginServerPath; + /// Don't look in for compiler-provided modules. bool SkipRuntimeLibraryImportPaths = false; diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index 8451855a4e724..7973d19a1f539 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -50,7 +50,7 @@ class ContinueStmt; class DefaultArgumentExpr; class DefaultArgumentType; class DoCatchStmt; -struct ExternalMacroDefinition; +class ExternalMacroDefinition; class ClosureExpr; class GenericParamList; class InverseTypeRepr; @@ -4541,38 +4541,30 @@ class ExpandSynthesizedMemberMacroRequest /// Represent a loaded plugin either an in-process library or an executable. class CompilerPluginLoadResult { - enum class PluginKind : uint8_t { - Error = 0, - Library, - Executable, + enum class Status : uint8_t { + Success = 0, + Error, }; - PluginKind Kind; + Status status; void *opaqueHandle; - CompilerPluginLoadResult(PluginKind K, void *opaque) - : Kind(K), opaqueHandle(opaque) {} + CompilerPluginLoadResult(Status status, void *opaque) + : status(status), opaqueHandle(opaque) {} public: - CompilerPluginLoadResult(LoadedLibraryPlugin *ptr) - : CompilerPluginLoadResult(PluginKind::Library, ptr){}; - CompilerPluginLoadResult(LoadedExecutablePlugin *ptr) - : CompilerPluginLoadResult(PluginKind::Executable, ptr){}; + CompilerPluginLoadResult(CompilerPlugin *ptr) + : CompilerPluginLoadResult(Status::Success, ptr){}; static CompilerPluginLoadResult error(NullTerminatedStringRef message) { - return CompilerPluginLoadResult(PluginKind::Error, + return CompilerPluginLoadResult(Status::Error, const_cast(message.data())); } - LoadedLibraryPlugin *getAsLibraryPlugin() const { - if (Kind != PluginKind::Library) + CompilerPlugin *get() const { + if (status != Status::Success) return nullptr; - return static_cast(opaqueHandle); + return static_cast(opaqueHandle); } - LoadedExecutablePlugin *getAsExecutablePlugin() const { - if (Kind != PluginKind::Executable) - return nullptr; - return static_cast(opaqueHandle); - } - bool isError() const { return Kind == PluginKind::Error; } + bool isError() const { return status == Status::Error; } NullTerminatedStringRef getErrorMessage() const { assert(isError()); return static_cast(opaqueHandle); diff --git a/include/swift/Bridging/ASTGen.h b/include/swift/Bridging/ASTGen.h index be0ee055aea64..14eaae3cd3ccd 100644 --- a/include/swift/Bridging/ASTGen.h +++ b/include/swift/Bridging/ASTGen.h @@ -58,15 +58,12 @@ void swift_ASTGen_buildTopLevelASTNodes( BridgedLegacyParser legacyParser, void *_Nonnull outputContext, void (*_Nonnull)(void *_Nonnull, void *_Nonnull)); -void *_Nullable swift_ASTGen_resolveMacroType(const void *_Nonnull macroType); -void swift_ASTGen_destroyMacro(void *_Nonnull macro); - void swift_ASTGen_freeBridgedString(BridgedStringRef); -void *_Nonnull swift_ASTGen_resolveExecutableMacro( +void *_Nonnull swift_ASTGen_resolveExternalMacro( const char *_Nonnull moduleName, const char *_Nonnull typeName, void *_Nonnull opaquePluginHandle); -void swift_ASTGen_destroyExecutableMacro(void *_Nonnull macro); +void swift_ASTGen_destroyExternalMacro(void *_Nonnull macro); bool swift_ASTGen_checkDefaultArgumentMacroExpression( void *_Nonnull diagEngine, void *_Nonnull sourceFile, @@ -84,13 +81,13 @@ void swift_ASTGen_freeExpansionReplacements( ptrdiff_t *_Nullable replacementsPtr, ptrdiff_t numReplacements); ptrdiff_t swift_ASTGen_expandFreestandingMacro( - void *_Nonnull diagEngine, const void *_Nonnull macro, uint8_t externalKind, + void *_Nonnull diagEngine, const void *_Nonnull macro, const char *_Nonnull discriminator, uint8_t rawMacroRole, void *_Nonnull sourceFile, const void *_Nullable sourceLocation, BridgedStringRef *_Nonnull evaluatedSourceOut); ptrdiff_t swift_ASTGen_expandAttachedMacro( - void *_Nonnull diagEngine, const void *_Nonnull macro, uint8_t externalKind, + void *_Nonnull diagEngine, const void *_Nonnull macro, const char *_Nonnull discriminator, const char *_Nonnull qualifiedType, const char *_Nonnull conformances, uint8_t rawMacroRole, void *_Nonnull customAttrSourceFile, diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index 17716a6a2438a..534fa86ac915c 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -2002,6 +2002,10 @@ def load_plugin_executable: "of module names where the macro types are declared">, MetaVarName<"#">; +def in_process_plugin_server_path : Separate<["-"], "in-process-plugin-server-path">, + Flags<[FrontendOption, ArgumentIsPath]>, + HelpText<"Path to dynamic library plugin server">; + def disable_sandbox: Flag<["-"], "disable-sandbox">, Flags<[FrontendOption, DoesNotAffectIncrementalBuild]>, diff --git a/lib/AST/ASTBridging.cpp b/lib/AST/ASTBridging.cpp index 8b71b6c81d744..eec9c58568f75 100644 --- a/lib/AST/ASTBridging.cpp +++ b/lib/AST/ASTBridging.cpp @@ -2585,32 +2585,27 @@ void BridgedTypeRepr_dump(void *type) { static_cast(type)->dump(); } //===----------------------------------------------------------------------===// PluginCapabilityPtr Plugin_getCapability(PluginHandle handle) { - auto *plugin = static_cast(handle); + auto *plugin = static_cast(handle); return plugin->getCapability(); } void Plugin_setCapability(PluginHandle handle, PluginCapabilityPtr data) { - auto *plugin = static_cast(handle); + auto *plugin = static_cast(handle); plugin->setCapability(data); } -const char *Plugin_getExecutableFilePath(PluginHandle handle) { - auto *plugin = static_cast(handle); - return plugin->getExecutablePath().data(); -} - void Plugin_lock(PluginHandle handle) { - auto *plugin = static_cast(handle); + auto *plugin = static_cast(handle); plugin->lock(); } void Plugin_unlock(PluginHandle handle) { - auto *plugin = static_cast(handle); + auto *plugin = static_cast(handle); plugin->unlock(); } bool Plugin_spawnIfNeeded(PluginHandle handle) { - auto *plugin = static_cast(handle); + auto *plugin = static_cast(handle); auto error = plugin->spawnIfNeeded(); bool hadError(error); llvm::consumeError(std::move(error)); @@ -2618,7 +2613,7 @@ bool Plugin_spawnIfNeeded(PluginHandle handle) { } bool Plugin_sendMessage(PluginHandle handle, const BridgedData data) { - auto *plugin = static_cast(handle); + auto *plugin = static_cast(handle); StringRef message(data.BaseAddress, data.Length); auto error = plugin->sendMessage(message); if (error) { @@ -2634,7 +2629,7 @@ bool Plugin_sendMessage(PluginHandle handle, const BridgedData data) { } bool Plugin_waitForNextMessage(PluginHandle handle, BridgedData *out) { - auto *plugin = static_cast(handle); + auto *plugin = static_cast(handle); auto result = plugin->waitForNextMessage(); if (!result) { // FIXME: Pass the error message back to the caller. diff --git a/lib/AST/PluginLoader.cpp b/lib/AST/PluginLoader.cpp index 95f1b01ed24a8..18303c73c2373 100644 --- a/lib/AST/PluginLoader.cpp +++ b/lib/AST/PluginLoader.cpp @@ -170,31 +170,24 @@ PluginLoader::lookupPluginByModuleName(Identifier moduleName) { return found->second; } -llvm::Expected -PluginLoader::loadLibraryPlugin(StringRef path) { +llvm::Expected PluginLoader::getInProcessPlugins() { + auto inProcPluginServerPath = Ctx.SearchPathOpts.InProcessPluginServerPath; + if (inProcPluginServerPath.empty()) { + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "library plugins require -in-process-plugin-server-path"); + } + auto fs = getPluginLoadingFS(Ctx); SmallString<128> resolvedPath; - if (auto err = fs->getRealPath(path, resolvedPath)) { + if (auto err = fs->getRealPath(inProcPluginServerPath, resolvedPath)) { return llvm::createStringError(err, err.message()); } - // Load the plugin. - auto plugin = getRegistry()->loadLibraryPlugin(resolvedPath); - if (!plugin) { - resolvedPath.push_back(0); - return llvm::handleErrors( - plugin.takeError(), [&](const llvm::ErrorInfoBase &err) { - return llvm::createStringError( - err.convertToErrorCode(), - "compiler plugin '%s' could not be loaded; %s", - resolvedPath.data(), err.message().data()); - }); - } - - return plugin; + return getRegistry()->getInProcessPlugins(resolvedPath); } -llvm::Expected +llvm::Expected PluginLoader::loadExecutablePlugin(StringRef path) { auto fs = getPluginLoadingFS(Ctx); SmallString<128> resolvedPath; diff --git a/lib/AST/PluginRegistry.cpp b/lib/AST/PluginRegistry.cpp index 12a82ff9f36d9..60ba319e2c493 100644 --- a/lib/AST/PluginRegistry.cpp +++ b/lib/AST/PluginRegistry.cpp @@ -44,46 +44,96 @@ PluginRegistry::PluginRegistry() { dumpMessaging = ::getenv("SWIFT_DUMP_PLUGIN_MESSAGING") != nullptr; } -llvm::Expected -PluginRegistry::loadLibraryPlugin(StringRef path) { - std::lock_guard lock(mtx); - auto &storage = LoadedPluginLibraries[path]; - if (storage) { - // Already loaded. - return storage.get(); +CompilerPlugin::~CompilerPlugin() { + // Let ASTGen do cleanup things. + if (this->cleanup) + this->cleanup(); +} + +llvm::Expected> +InProcessPlugins::create(const char *serverPath) { + std::string err; + auto server = llvm::sys::DynamicLibrary::getLibrary(serverPath, &err); + if (!server.isValid()) { + return llvm::createStringError(llvm::inconvertibleErrorCode(), err); } - void *lib = nullptr; -#if defined(_WIN32) - lib = LoadLibraryA(path.str().c_str()); - if (!lib) { - std::error_code ec(GetLastError(), std::system_category()); - return llvm::errorCodeToError(ec); + auto funcPtr = + server.getAddressOfSymbol("swift_inproc_plugins_handle_message"); + if (!funcPtr) { + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "entry point not found in '%s'", serverPath); } -#else - lib = dlopen(path.str().c_str(), RTLD_LAZY | RTLD_LOCAL); - if (!lib) { - return llvm::createStringError(llvm::inconvertibleErrorCode(), dlerror()); + return std::unique_ptr(new InProcessPlugins( + serverPath, server, reinterpret_cast(funcPtr))); +} + +llvm::Error InProcessPlugins::sendMessage(llvm::StringRef message) { + assert(receivedResponse.empty() && + "sendMessage() called before consuming previous response?"); + + if (shouldDumpMessaging()) { + llvm::dbgs() << "->(plugin:0) " << message << '\n'; } -#endif - storage = std::make_unique(lib, path); - return storage.get(); + char *responseData = nullptr; + size_t responseLength = 0; + bool hadError = handleMessageFn(message.data(), message.size(), &responseData, + &responseLength); + + // 'responseData' now holds a response message or error message depending on + // 'hadError'. Either way, it's our responsibility to deallocate it. + SWIFT_DEFER { free(responseData); }; + if (hadError) { + return llvm::createStringError(llvm::inconvertibleErrorCode(), + StringRef(responseData, responseLength)); + } + + // Store the response and wait for 'waitForNextMessage()' call. + receivedResponse = std::string(responseData, responseLength); + + if (shouldDumpMessaging()) { + llvm::dbgs() << "<-(plugin:0) " << receivedResponse << "\n"; + } + + assert(!receivedResponse.empty() && "received empty response"); + return llvm::Error::success(); } -void *LoadedLibraryPlugin::getAddressOfSymbol(const char *symbolName) { - auto &cached = resolvedSymbols[symbolName]; - if (cached) - return cached; -#if defined(_WIN32) - cached = GetProcAddress(static_cast(handle), symbolName); -#else - cached = dlsym(handle, symbolName); -#endif - return cached; +llvm::Expected InProcessPlugins::waitForNextMessage() { + assert(!receivedResponse.empty() && + "waitForNextMessage() called without response data."); + SWIFT_DEFER { receivedResponse = ""; }; + return std::move(receivedResponse); } -llvm::Expected +llvm::Expected +PluginRegistry::getInProcessPlugins(llvm::StringRef serverPath) { + std::lock_guard lock(mtx); + if (!inProcessPlugins) { + auto server = InProcessPlugins::create(serverPath.str().c_str()); + if (!server) { + return llvm::handleErrors( + server.takeError(), [&](const llvm::ErrorInfoBase &err) { + return llvm::createStringError( + err.convertToErrorCode(), + "failed to load in-process plugin server: " + serverPath + + "; " + err.message()); + }); + } + inProcessPlugins = std::move(server.get()); + } else if (inProcessPlugins->getPath() != serverPath) { + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "loading multiple in-process servers are not supported: '%s' and '%s'", + inProcessPlugins->getPath().data(), serverPath.str().c_str()); + } + inProcessPlugins->setDumpMessaging(dumpMessaging); + + return inProcessPlugins.get(); +} + +llvm::Expected PluginRegistry::loadExecutablePlugin(StringRef path, bool disableSandbox) { llvm::sys::fs::file_status stat; if (auto err = llvm::sys::fs::status(path, stat)) { @@ -143,7 +193,7 @@ llvm::Error LoadedExecutablePlugin::spawnIfNeeded() { } // Create command line arguments. - SmallVector command{ExecutablePath}; + SmallVector command{getPath()}; // Apply sandboxing. llvm::BumpPtrAllocator Allocator; @@ -161,7 +211,7 @@ llvm::Error LoadedExecutablePlugin::spawnIfNeeded() { childInfo->Read, childInfo->Write); // Call "on reconnect" callbacks. - for (auto *callback : onReconnect) { + for (auto *callback : getOnReconnectCallbacks()) { (*callback)(); } @@ -179,12 +229,6 @@ LoadedExecutablePlugin::PluginProcess::~PluginProcess() { llvm::sys::Wait(process, /*SecondsToWait=*/0); } -LoadedExecutablePlugin::~LoadedExecutablePlugin() { - // Let ASTGen to cleanup things. - if (this->cleanup) - this->cleanup(); -} - ssize_t LoadedExecutablePlugin::PluginProcess::read(void *buf, size_t nbyte) const { #if defined(_WIN32) @@ -260,10 +304,10 @@ ssize_t LoadedExecutablePlugin::PluginProcess::write(const void *buf, #endif } -llvm::Error LoadedExecutablePlugin::sendMessage(llvm::StringRef message) const { +llvm::Error LoadedExecutablePlugin::sendMessage(llvm::StringRef message) { ssize_t writtenSize = 0; - if (dumpMessaging) { + if (shouldDumpMessaging()) { llvm::dbgs() << "->(plugin:" << Process->process.Pid << ") " << message << '\n'; } @@ -291,7 +335,7 @@ llvm::Error LoadedExecutablePlugin::sendMessage(llvm::StringRef message) const { return llvm::Error::success(); } -llvm::Expected LoadedExecutablePlugin::waitForNextMessage() const { +llvm::Expected LoadedExecutablePlugin::waitForNextMessage() { ssize_t readSize = 0; // Read header (message size). @@ -323,7 +367,7 @@ llvm::Expected LoadedExecutablePlugin::waitForNextMessage() const { message.append(buffer, readSize); } - if (dumpMessaging) { + if (shouldDumpMessaging()) { llvm::dbgs() << "<-(plugin:" << Process->process.Pid << ") " << message << "\n"; } diff --git a/lib/ASTGen/CMakeLists.txt b/lib/ASTGen/CMakeLists.txt index d5c227369439c..6897f14d59a2e 100644 --- a/lib/ASTGen/CMakeLists.txt +++ b/lib/ASTGen/CMakeLists.txt @@ -11,7 +11,7 @@ if(SWIFT_BUILD_REGEX_PARSER_IN_COMPILER) endforeach() message(STATUS "Using Experimental String Processing library for _CompilerRegexParser (${SWIFT_PATH_TO_STRING_PROCESSING_SOURCE}).") - add_pure_swift_host_library(_CompilerRegexParser STATIC EMIT_MODULE + add_pure_swift_host_library(_CompilerRegexParser STATIC "${COMPILER_REGEX_PARSER_SOURCES}" ) @@ -36,7 +36,6 @@ add_pure_swift_host_library(swiftASTGen STATIC Sources/ASTGen/Regex.swift Sources/ASTGen/SourceFile.swift Sources/ASTGen/SourceManager.swift - Sources/ASTGen/SourceManager+MacroExpansionContext.swift Sources/ASTGen/Stmts.swift Sources/ASTGen/TypeAttrs.swift Sources/ASTGen/Types.swift @@ -44,16 +43,15 @@ add_pure_swift_host_library(swiftASTGen STATIC DEPENDENCIES swiftAST SWIFT_DEPENDENCIES - SwiftBasicFormat - SwiftCompilerPluginMessageHandling - SwiftDiagnostics - SwiftOperators - SwiftParser - SwiftParserDiagnostics - SwiftSyntax - SwiftSyntaxBuilder - SwiftSyntaxMacros - SwiftSyntaxMacroExpansion + _CompilerSwiftSyntax + _CompilerSwiftOperators + _CompilerSwiftSyntaxBuilder + _CompilerSwiftParser + _CompilerSwiftParserDiagnostics + _CompilerSwiftCompilerPluginMessageHandling + _CompilerSwiftSyntaxMacroExpansion + _CompilerSwiftDiagnostics + _CompilerSwiftIDEUtils ${ASTGen_Swift_dependencies} ) @@ -62,14 +60,11 @@ add_pure_swift_host_library(swiftIDEUtilsBridging DEPENDENCIES swiftAST - swiftASTGen - SWIFT_DEPENDENCIES - SwiftIDEUtils - SwiftSyntax + _CompilerSwiftSyntax + swiftASTGen ) - set(c_include_paths # LLVM modules and headers. "${LLVM_MAIN_INCLUDE_DIR}" @@ -88,7 +83,6 @@ endforeach() set(compile_options ${c_include_paths_args} - "SHELL: -DRESILIENT_SWIFT_SYNTAX" "SHELL: -Xcc -std=c++17 -Xcc -DCOMPILED_WITH_SWIFT" # FIXME: Needed to work around an availability issue with CxxStdlib diff --git a/lib/ASTGen/Package.swift b/lib/ASTGen/Package.swift index 5c28d6dbb7c3a..8b83ca560115c 100644 --- a/lib/ASTGen/Package.swift +++ b/lib/ASTGen/Package.swift @@ -52,7 +52,6 @@ let package = Package( .target( name: "swiftASTGen", dependencies: [ - .product(name: "SwiftBasicFormat", package: "swift-syntax"), .product(name: "SwiftCompilerPluginMessageHandling", package: "swift-syntax"), .product(name: "SwiftDiagnostics", package: "swift-syntax"), .product(name: "SwiftOperators", package: "swift-syntax"), @@ -60,7 +59,6 @@ let package = Package( .product(name: "SwiftParserDiagnostics", package: "swift-syntax"), .product(name: "SwiftSyntax", package: "swift-syntax"), .product(name: "SwiftSyntaxBuilder", package: "swift-syntax"), - .product(name: "SwiftSyntaxMacros", package: "swift-syntax"), .product(name: "SwiftSyntaxMacroExpansion", package: "swift-syntax"), "_CompilerRegexParser", ], diff --git a/lib/ASTGen/Sources/ASTGen/Macros.swift b/lib/ASTGen/Sources/ASTGen/Macros.swift index 87163884ea1b7..5831b23dd89ac 100644 --- a/lib/ASTGen/Sources/ASTGen/Macros.swift +++ b/lib/ASTGen/Sources/ASTGen/Macros.swift @@ -19,25 +19,13 @@ import SwiftParser import SwiftSyntax import SwiftSyntaxBuilder @_spi(ExperimentalLanguageFeature) @_spi(Compiler) import SwiftSyntaxMacroExpansion -@_spi(ExperimentalLanguageFeature) import SwiftSyntaxMacros -/// Describes a macro that has been "exported" to the C++ part of the -/// compiler, with enough information to interface with the C++ layer. -struct ExportedMacro { - var macro: Macro.Type -} - -struct ExportedExecutableMacro { +struct ExportedExternalMacro { var moduleName: String var typeName: String var plugin: CompilerPlugin } -enum MacroPluginKind: UInt8 { - case InProcess = 0 - case Executable = 1 -} - extension MacroRole { init(rawMacroRole: UInt8) { switch rawMacroRole { @@ -58,40 +46,8 @@ extension MacroRole { } } -/// Resolve a reference to type metadata into a macro, if posible. -/// -/// Returns an unmanaged pointer to an ExportedMacro instance that describes -/// the specified macro. If there is no macro with the given name, produces -/// nil. -@_cdecl("swift_ASTGen_resolveMacroType") -public func resolveMacroType( - macroTypePtr: UnsafePointer -) -> UnsafeRawPointer? { - let macroType = unsafeBitCast(macroTypePtr, to: Any.Type.self) - - guard let macro = macroType as? Macro.Type else { - return nil - } - - // Allocate and initialize the exported macro. - let exportedPtr = UnsafeMutablePointer.allocate(capacity: 1) - exportedPtr.initialize(to: .init(macro: macro)) - return UnsafeRawPointer(exportedPtr) -} - -/// Destroys the given macro. -@_cdecl("swift_ASTGen_destroyMacro") -public func destroyMacro( - macroPtr: UnsafeMutablePointer -) { - macroPtr.withMemoryRebound(to: ExportedMacro.self, capacity: 1) { macro in - macro.deinitialize(count: 1) - macro.deallocate() - } -} - -@_cdecl("swift_ASTGen_resolveExecutableMacro") -public func resolveExecutableMacro( +@_cdecl("swift_ASTGen_resolveExternalMacro") +public func resolveExternalMacro( moduleName: UnsafePointer, typeName: UnsafePointer, pluginOpaqueHandle: UnsafeMutableRawPointer @@ -99,7 +55,7 @@ public func resolveExecutableMacro( // NOTE: This doesn't actually resolve anything. // Executable plugins is "trusted" to have the macro implementation. If not, // the actual expansion fails. - let exportedPtr = UnsafeMutablePointer.allocate(capacity: 1) + let exportedPtr = UnsafeMutablePointer.allocate(capacity: 1) exportedPtr.initialize( to: .init( moduleName: String(cString: moduleName), @@ -110,11 +66,11 @@ public func resolveExecutableMacro( return UnsafeRawPointer(exportedPtr) } -@_cdecl("swift_ASTGen_destroyExecutableMacro") -public func destroyExecutableMacro( +@_cdecl("swift_ASTGen_destroyExternalMacro") +public func destroyExternalMacro( macroPtr: UnsafeMutableRawPointer ) { - let macroPtr = macroPtr.assumingMemoryBound(to: ExportedExecutableMacro.self) + let macroPtr = macroPtr.assumingMemoryBound(to: ExportedExternalMacro.self) macroPtr.deinitialize(count: 1) macroPtr.deallocate() } @@ -470,7 +426,6 @@ func makeExpansionOutputResult( func expandFreestandingMacro( diagEnginePtr: UnsafeMutableRawPointer, macroPtr: UnsafeRawPointer, - macroKind: UInt8, discriminatorText: UnsafePointer, rawMacroRole: UInt8, sourceFilePtr: UnsafeRawPointer, @@ -508,27 +463,14 @@ func expandFreestandingMacro( let discriminator = String(cString: discriminatorText) let macroRole = MacroRole(rawMacroRole: rawMacroRole) - let expandedSource: String? - switch MacroPluginKind(rawValue: macroKind)! { - case .InProcess: - expandedSource = expandFreestandingMacroInProcess( - macroPtr: macroPtr, - macroRole: macroRole, - diagEnginePtr: diagEnginePtr, - expansionSyntax: expansion, - sourceFilePtr: sourceFilePtr, - discriminator: discriminator - ) - case .Executable: - expandedSource = expandFreestandingMacroIPC( - macroPtr: macroPtr, - macroRole: macroRole, - diagEnginePtr: diagEnginePtr, - expansionSyntax: expansion, - sourceFilePtr: sourceFilePtr, - discriminator: discriminator - ) - } + let expandedSource: String? = expandFreestandingMacroImpl( + macroPtr: macroPtr, + macroRole: macroRole, + diagEnginePtr: diagEnginePtr, + expansionSyntax: expansion, + sourceFilePtr: sourceFilePtr, + discriminator: discriminator + ) return makeExpansionOutputResult( expandedSource: expandedSource, @@ -536,7 +478,7 @@ func expandFreestandingMacro( ) } -func expandFreestandingMacroIPC( +func expandFreestandingMacroImpl( macroPtr: UnsafeRawPointer, macroRole: MacroRole, diagEnginePtr: UnsafeMutableRawPointer, @@ -554,7 +496,7 @@ func expandFreestandingMacroIPC( fatalError("unknown syntax") } - let macro = macroPtr.assumingMemoryBound(to: ExportedExecutableMacro.self).pointee + let macro = macroPtr.assumingMemoryBound(to: ExportedExternalMacro.self).pointee // Map the macro role. let pluginMacroRole: PluginMessage.MacroRole @@ -615,55 +557,6 @@ func expandFreestandingMacroIPC( } } -func expandFreestandingMacroInProcess( - macroPtr: UnsafeRawPointer, - macroRole: MacroRole, - diagEnginePtr: UnsafeMutableRawPointer, - expansionSyntax: FreestandingMacroExpansionSyntax, - sourceFilePtr: UnsafePointer, - discriminator: String -) -> String? { - // Get the macro. - let macroPtr = macroPtr.bindMemory(to: ExportedMacro.self, capacity: 1) - let macro = macroPtr.pointee.macro - - // Create a source manager. This should probably persist and be given to us. - let sourceManager = SourceManager(cxxDiagnosticEngine: diagEnginePtr) - sourceManager.insert(sourceFilePtr) - - let context = sourceManager.createMacroExpansionContext( - lexicalContext: lexicalContext(of: expansionSyntax), - discriminator: discriminator - ) - - let macroName = expansionSyntax.macroName.text - - // Make sure we emit all of the diagnostics from the context. - defer { - // Emit diagnostics accumulated in the context. - for diag in context.diagnostics { - sourceManager.diagnose( - diagnostic: diag, - messageSuffix: " (from macro '\(macroName)')" - ) - } - - context.diagnostics = [] - } - - let node = sourceManager.detach( - expansionSyntax, - foldingWith: OperatorTable.standardOperators - ) - - return SwiftSyntaxMacroExpansion.expandFreestandingMacro( - definition: macro, - macroRole: macroRole, - node: node, - in: context - ) -} - /// Retrieve a syntax node in the given source file, with the given type. func findSyntaxNodeInSourceFile( sourceFilePtr: UnsafeRawPointer, @@ -730,7 +623,6 @@ func findSyntaxNodeInSourceFile( func expandAttachedMacro( diagEnginePtr: UnsafeMutableRawPointer, macroPtr: UnsafeRawPointer, - macroKind: UInt8, discriminatorText: UnsafePointer, qualifiedTypeText: UnsafePointer, conformanceListText: UnsafePointer, @@ -786,39 +678,20 @@ func expandAttachedMacro( let qualifiedType = String(cString: qualifiedTypeText) let conformanceList = String(cString: conformanceListText) - let expandedSource: String? - switch MacroPluginKind(rawValue: macroKind)! { - case .Executable: - expandedSource = expandAttachedMacroIPC( - diagEnginePtr: diagEnginePtr, - macroPtr: macroPtr, - rawMacroRole: rawMacroRole, - discriminator: discriminator, - qualifiedType: qualifiedType, - conformanceList: conformanceList, - customAttrSourceFilePtr: customAttrSourceFilePtr, - customAttrNode: customAttrNode, - declarationSourceFilePtr: declarationSourceFilePtr, - attachedTo: declarationNode, - parentDeclSourceFilePtr: parentDeclSourceFilePtr, - parentDeclNode: parentDeclNode - ) - case .InProcess: - expandedSource = expandAttachedMacroInProcess( - diagEnginePtr: diagEnginePtr, - macroPtr: macroPtr, - rawMacroRole: rawMacroRole, - discriminator: discriminator, - qualifiedType: qualifiedType, - conformanceList: conformanceList, - customAttrSourceFilePtr: customAttrSourceFilePtr, - customAttrNode: customAttrNode, - declarationSourceFilePtr: declarationSourceFilePtr, - attachedTo: declarationNode, - parentDeclSourceFilePtr: parentDeclSourceFilePtr, - parentDeclNode: parentDeclNode - ) - } + let expandedSource: String? = expandAttachedMacroImpl( + diagEnginePtr: diagEnginePtr, + macroPtr: macroPtr, + rawMacroRole: rawMacroRole, + discriminator: discriminator, + qualifiedType: qualifiedType, + conformanceList: conformanceList, + customAttrSourceFilePtr: customAttrSourceFilePtr, + customAttrNode: customAttrNode, + declarationSourceFilePtr: declarationSourceFilePtr, + attachedTo: declarationNode, + parentDeclSourceFilePtr: parentDeclSourceFilePtr, + parentDeclNode: parentDeclNode + ) return makeExpansionOutputResult( expandedSource: expandedSource, @@ -840,7 +713,7 @@ private func pluginLexicalContext(of node: some SyntaxProtocol) -> [PluginMessag lexicalContext(of: node).compactMap { .init(syntax: $0) } } -func expandAttachedMacroIPC( +func expandAttachedMacroImpl( diagEnginePtr: UnsafeMutableRawPointer, macroPtr: UnsafeRawPointer, rawMacroRole: UInt8, @@ -855,7 +728,7 @@ func expandAttachedMacroIPC( parentDeclNode: DeclSyntax? ) -> String? { let macroName: String = customAttrNode.attributeName.description - let macro = macroPtr.assumingMemoryBound(to: ExportedExecutableMacro.self).pointee + let macro = macroPtr.assumingMemoryBound(to: ExportedExternalMacro.self).pointee // Map the macro role. let macroRole: PluginMessage.MacroRole @@ -988,104 +861,3 @@ func expandAttachedMacroIPC( } } -func expandAttachedMacroInProcess( - diagEnginePtr: UnsafeMutableRawPointer, - macroPtr: UnsafeRawPointer, - rawMacroRole: UInt8, - discriminator: String, - qualifiedType: String, - conformanceList: String, - customAttrSourceFilePtr: UnsafePointer, - customAttrNode: AttributeSyntax, - declarationSourceFilePtr: UnsafePointer, - attachedTo declarationNode: DeclSyntax, - parentDeclSourceFilePtr: UnsafePointer?, - parentDeclNode: DeclSyntax? -) -> String? { - // Get the macro. - let macroPtr = macroPtr.bindMemory(to: ExportedMacro.self, capacity: 1) - let macro = macroPtr.pointee.macro - - // Create a source manager covering the files we know about. - let sourceManager = SourceManager(cxxDiagnosticEngine: diagEnginePtr) - sourceManager.insert(customAttrSourceFilePtr) - sourceManager.insert(declarationSourceFilePtr) - if let parentDeclSourceFilePtr = parentDeclSourceFilePtr { - sourceManager.insert(parentDeclSourceFilePtr) - } - - // Create an expansion context - let context = sourceManager.createMacroExpansionContext( - lexicalContext: lexicalContext(of: declarationNode), - discriminator: discriminator - ) - - let macroName = customAttrNode.attributeName.trimmedDescription - - // Emit all of the accumulated diagnostics before we exit. - defer { - // Emit diagnostics accumulated in the context. - for diag in context.diagnostics { - sourceManager.diagnose( - diagnostic: diag, - messageSuffix: " (from macro '\(macroName)')" - ) - } - - context.diagnostics = [] - } - - let attributeNode = sourceManager.detach( - customAttrNode, - foldingWith: OperatorTable.standardOperators - ) - let declarationNode = sourceManager.detach(declarationNode) - let parentDeclNode = parentDeclNode.map { sourceManager.detach($0) } - let extendedType: TypeSyntax = "\(raw: qualifiedType)" - - let conformanceListSyntax: InheritedTypeListSyntax? - if (conformanceList.isEmpty) { - conformanceListSyntax = nil - } else { - let placeholderDecl: DeclSyntax = - """ - struct Placeholder: \(raw: conformanceList) {} - """ - let placeholderStruct = placeholderDecl.cast(StructDeclSyntax.self) - if let inheritanceClause = placeholderStruct.inheritanceClause { - conformanceListSyntax = inheritanceClause.inheritedTypes - } else { - conformanceListSyntax = nil - } - } - - return SwiftSyntaxMacroExpansion.expandAttachedMacro( - definition: macro, - macroRole: MacroRole(rawMacroRole: rawMacroRole), - attributeNode: attributeNode, - declarationNode: declarationNode, - parentDeclNode: parentDeclNode, - extendedType: extendedType, - conformanceList: conformanceListSyntax, - in: context - ) -} - -fileprivate extension SyntaxProtocol { - /// Perform a format if required and then trim any leading/trailing - /// whitespace. - func formattedExpansion(_ mode: FormatMode) -> String { - let formatted: Syntax - switch mode { - case .auto: - formatted = self.formatted() - case .disabled: - formatted = Syntax(self) -#if RESILIENT_SWIFT_SYNTAX - @unknown default: - fatalError() -#endif - } - return formatted.trimmedDescription(matching: { $0.isWhitespace }) - } -} diff --git a/lib/ASTGen/Sources/ASTGen/PluginHost.swift b/lib/ASTGen/Sources/ASTGen/PluginHost.swift index 2319d5146a703..0e522b54d961d 100644 --- a/lib/ASTGen/Sources/ASTGen/PluginHost.swift +++ b/lib/ASTGen/Sources/ASTGen/PluginHost.swift @@ -194,10 +194,6 @@ struct CompilerPlugin { } return nil } - - var executableFilePath: String { - return String(cString: Plugin_getExecutableFilePath(opaqueHandle)) - } } class PluginDiagnosticsEngine { @@ -319,7 +315,7 @@ class PluginDiagnosticsEngine { messageSuffix: String? = nil ) { for diagnostic in diagnostics { - self.emit(diagnostic) + self.emit(diagnostic, messageSuffix: messageSuffix) } } @@ -378,6 +374,26 @@ class PluginDiagnosticsEngine { } } +extension String { + /// Retrieve the base name of a string that represents a path, removing the + /// directory. + var basename: String { + guard + let lastSlash = lastIndex(where: { + #if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS) || os(Android) || os(Linux) + ["/"].contains($0) + #else + ["/", "\\"].contains($0) + #endif + }) + else { + return self + } + + return String(self[index(after: lastSlash)...]) + } +} + extension PluginMessage.Syntax { init?(syntax: Syntax, in sourceFilePtr: UnsafePointer) { let kind: PluginMessage.Syntax.Kind diff --git a/lib/ASTGen/Sources/ASTGen/SourceManager+MacroExpansionContext.swift b/lib/ASTGen/Sources/ASTGen/SourceManager+MacroExpansionContext.swift deleted file mode 100644 index 04953e284805a..0000000000000 --- a/lib/ASTGen/Sources/ASTGen/SourceManager+MacroExpansionContext.swift +++ /dev/null @@ -1,192 +0,0 @@ -//===--- SourceManager+MacroExpansionContext.swift ------------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2022-2023 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -import SwiftDiagnostics -import SwiftSyntax -import SwiftSyntaxMacros - -extension SourceManager { - class MacroExpansionContext { - /// The source manager. - private let sourceManager: SourceManager - - /// The lexical context for this expansion. - let lexicalContext: [Syntax] - - /// The set of diagnostics that were emitted as part of expanding the - /// macro. - var diagnostics: [Diagnostic] = [] - - /// The macro expansion discriminator, which is used to form unique names - /// when requested. - /// - /// The expansion discriminator is combined with the `uniqueNames` counters - /// to produce unique names. - private var discriminator: String - - /// Counter for each of the uniqued names. - /// - /// Used in conjunction with `expansionDiscriminator`. - private var uniqueNames: [String: Int] = [:] - - init( - sourceManager: SourceManager, - lexicalContext: [Syntax], - discriminator: String - ) { - self.sourceManager = sourceManager - self.lexicalContext = lexicalContext - self.discriminator = discriminator - } - } - - /// Create a new macro expansion context - func createMacroExpansionContext( - lexicalContext: [Syntax], - discriminator: String = "" - ) -> MacroExpansionContext { - return MacroExpansionContext( - sourceManager: self, - lexicalContext: lexicalContext, - discriminator: discriminator - ) - } -} - -extension String { - /// Retrieve the base name of a string that represents a path, removing the - /// directory. - var basename: String { - guard - let lastSlash = lastIndex(where: { - #if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(Android) || os(Linux) - ["/"].contains($0) - #else - ["/", "\\"].contains($0) - #endif - }) - else { - return self - } - - return String(self[index(after: lastSlash)...]) - } -} - -extension SourceManager.MacroExpansionContext: MacroExpansionContext { - /// Generate a unique name for use in the macro. - public func makeUniqueName(_ providedName: String) -> TokenSyntax { - // If provided with an empty name, substitute in something. - let name = providedName.isEmpty ? "__local" : providedName - - // Grab a unique index value for this name. - let uniqueIndex = uniqueNames[name, default: 0] - uniqueNames[name] = uniqueIndex + 1 - - // Start with the discriminator. - var resultString = discriminator - - // Mangle the name - resultString += "\(name.count)\(name)" - - // Mangle the operator for unique macro names. - resultString += "fMu" - - // Mangle the index. - if uniqueIndex > 0 { - resultString += "\(uniqueIndex - 1)" - } - resultString += "_" - - return TokenSyntax(.identifier(resultString), presence: .present) - } - - /// Produce a diagnostic while expanding the macro. - public func diagnose(_ diagnostic: Diagnostic) { - diagnostics.append(diagnostic) - } - - public func location( - of node: Node, - at position: PositionInSyntaxNode, - filePathMode: SourceLocationFilePathMode - ) -> AbstractSourceLocation? { - guard let (sourceFile, rootPosition) = sourceManager.rootSourceFile(of: node), - let exportedSourceFile = - sourceManager.exportedSourceFilesBySyntax[sourceFile]?.pointee - else { - return nil - } - - // Find the node's offset relative to its root. - let rawPosition: AbsolutePosition - switch position { - case .beforeLeadingTrivia: - rawPosition = node.position - - case .afterLeadingTrivia: - rawPosition = node.positionAfterSkippingLeadingTrivia - - case .beforeTrailingTrivia: - rawPosition = node.endPositionBeforeTrailingTrivia - - case .afterTrailingTrivia: - rawPosition = node.endPosition - -#if RESILIENT_SWIFT_SYNTAX - @unknown default: - fatalError() -#endif - } - - let offsetWithinSyntaxNode = - rawPosition.utf8Offset - node.position.utf8Offset - - var location = exportedSourceFile.sourceLocationConverter.location( - for: rootPosition.advanced(by: offsetWithinSyntaxNode) - ) - - switch filePathMode { - case .fileID: - // The `SourceLocationConverter` in `exportedSourceFile` uses `filePath` as the file mode. When the `fileID` mode - // is requested, we need to adjust the file and presumed file to the `fileID`. - let fileID = "\(exportedSourceFile.moduleName)/\(exportedSourceFile.fileName.basename)" - var adjustedFile = location.file - if adjustedFile == exportedSourceFile.fileName { - adjustedFile = fileID - } - var adjustedPresumedFile = location.presumedFile - if adjustedPresumedFile == exportedSourceFile.fileName { - adjustedPresumedFile = fileID - } - location = SourceLocation( - line: location.line, - column: location.column, - offset: location.offset, - file: adjustedFile, - presumedLine: location.presumedLine, - presumedFile: adjustedPresumedFile - ) - - case .filePath: - break - -#if RESILIENT_SWIFT_SYNTAX - @unknown default: - fatalError() -#endif - } - - // Do the location lookup. - return AbstractSourceLocation(location) - } -} diff --git a/lib/ASTGen/Sources/ASTGen/SourceManager.swift b/lib/ASTGen/Sources/ASTGen/SourceManager.swift index e1a13b7ddad07..2b8e2a1db62f5 100644 --- a/lib/ASTGen/Sources/ASTGen/SourceManager.swift +++ b/lib/ASTGen/Sources/ASTGen/SourceManager.swift @@ -14,7 +14,6 @@ import ASTBridging import BasicBridging import SwiftOperators import SwiftSyntax -import SwiftSyntaxMacros /// A source manager that keeps track of the source files in the program. class SourceManager { diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index dc942e5a54982..81d2b3fa03c04 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -40,6 +40,7 @@ add_subdirectory(AST) add_subdirectory(ASTGen) add_subdirectory(ASTSectionImporter) add_subdirectory(Basic) +add_subdirectory(CompilerSwiftSyntax) add_subdirectory(ConstExtract) add_subdirectory(ClangImporter) add_subdirectory(Demangling) diff --git a/lib/CompilerSwiftSyntax/CMakeLists.txt b/lib/CompilerSwiftSyntax/CMakeLists.txt new file mode 100644 index 0000000000000..79c1605d99324 --- /dev/null +++ b/lib/CompilerSwiftSyntax/CMakeLists.txt @@ -0,0 +1,52 @@ +if(NOT SWIFT_BUILD_SWIFT_SYNTAX) + return() +endif() +if(NOT EXISTS "${SWIFT_PATH_TO_SWIFT_SYNTAX_SOURCE}") + message(SEND_ERROR "swift-syntax is required to build the Swift compiler. Please run update-checkout or specify SWIFT_PATH_TO_SWIFT_SYNTAX_SOURCE") + return() +endif() + +# Build swift-syntax libraries with FetchContent. +function(includeSwiftSyntax) + set(CMAKE_Swift_COMPILER_TARGET ${SWIFT_HOST_TRIPLE}) + set(BUILD_SHARED_LIBS ON) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${SWIFT_HOST_LIBRARIES_DEST_DIR}/compiler") + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${SWIFT_HOST_LIBRARIES_DEST_DIR}/compiler") + if(SWIFT_HOST_VARIANT_SDK MATCHES "LINUX|ANDROID|OPENBSD|FREEBSD") + set(SWIFT_HOST_LIBRARIES_RPATH "$ORIGIN;$ORIGIN/../../${SWIFT_SDK_${SWIFT_HOST_VARIANT_SDK}_LIB_SUBDIR}") + endif() + + # Add unique ABI prefix to swift-syntax libraries so that compiler libraries (e.g. sourcekitdInProc) + # can be used from tools that has its own swift-syntax libraries as SwiftPM dependencies. + set(SWIFT_MODULE_ABI_NAME_PREFIX "_Compiler") + set(SWIFTSYNTAX_TARGET_NAMESPACE "_Compiler") + set(SWIFTSYNTAX_EMIT_MODULE OFF) + + file(TO_CMAKE_PATH "${SWIFT_PATH_TO_SWIFT_SYNTAX_SOURCE}" swift_syntax_path) + FetchContent_Declare(CompilerSwiftSyntax SOURCE_DIR "${swift_syntax_path}") + FetchContent_MakeAvailable(CompilerSwiftSyntax) +endfunction() +includeSwiftSyntax() + +set(compiler_swiftsyntax_libs + _CompilerSwiftSyntax + _CompilerSwiftOperators + _CompilerSwiftSyntaxBuilder + _CompilerSwiftParser + _CompilerSwiftParserDiagnostics + _CompilerSwiftCompilerPluginMessageHandling + _CompilerSwiftSyntaxMacroExpansion + _CompilerSwiftSyntaxMacros + _CompilerSwiftBasicFormat + _CompilerSwiftDiagnostics + _CompilerSwiftIDEUtils +) + +foreach(lib ${compiler_swiftsyntax_libs}) + target_compile_options(${lib} PRIVATE "SHELL:-module-link-name ${lib}") +endforeach() + +swift_install_in_component(TARGETS ${compiler_swiftsyntax_libs} + ARCHIVE DESTINATION "lib${LLVM_LIBDIR_SUFFIX}/swift/host/compiler" COMPONENT compiler + LIBRARY DESTINATION "lib${LLVM_LIBDIR_SUFFIX}/swift/host/compiler" COMPONENT compiler + RUNTIME DESTINATION "bin" COMPONENT compiler) diff --git a/lib/Driver/DarwinToolChains.cpp b/lib/Driver/DarwinToolChains.cpp index c7abfb36113b8..76158298ed9db 100644 --- a/lib/Driver/DarwinToolChains.cpp +++ b/lib/Driver/DarwinToolChains.cpp @@ -136,10 +136,16 @@ toolchains::Darwin::addPluginArguments(const ArgList &Args, CompilerInvocation::computeRuntimeResourcePathFromExecutablePath( programPath, /*shared=*/true, pluginPath); - auto defaultPluginPath = pluginPath; - llvm::sys::path::append(defaultPluginPath, "host", "plugins"); + // In-process plugin server path. + auto inProcPluginServerPath = pluginPath; + llvm::sys::path::append(inProcPluginServerPath, "host", + "libSwiftInProcPluginServer.dylib"); + Arguments.push_back("-in-process-plugin-server-path"); + Arguments.push_back(Args.MakeArgString(inProcPluginServerPath)); // Default plugin path. + auto defaultPluginPath = pluginPath; + llvm::sys::path::append(defaultPluginPath, "host", "plugins"); Arguments.push_back("-plugin-path"); Arguments.push_back(Args.MakeArgString(defaultPluginPath)); diff --git a/lib/Driver/UnixToolChains.cpp b/lib/Driver/UnixToolChains.cpp index 42f5e3e7ddfa8..12ccae8678d8f 100644 --- a/lib/Driver/UnixToolChains.cpp +++ b/lib/Driver/UnixToolChains.cpp @@ -55,10 +55,16 @@ toolchains::GenericUnix::addPluginArguments(const ArgList &Args, CompilerInvocation::computeRuntimeResourcePathFromExecutablePath( programPath, /*shared=*/true, pluginPath); - auto defaultPluginPath = pluginPath; - llvm::sys::path::append(defaultPluginPath, "host", "plugins"); + // In-process plugin server path. + auto inProcPluginServerPath = pluginPath; + llvm::sys::path::append(inProcPluginServerPath, "host", + "libSwiftInProcPluginServer.so"); + Arguments.push_back("-in-process-plugin-server-path"); + Arguments.push_back(Args.MakeArgString(inProcPluginServerPath)); // Default plugin path. + auto defaultPluginPath = pluginPath; + llvm::sys::path::append(defaultPluginPath, "host", "plugins"); Arguments.push_back("-plugin-path"); Arguments.push_back(Args.MakeArgString(defaultPluginPath)); diff --git a/lib/Driver/WindowsToolChains.cpp b/lib/Driver/WindowsToolChains.cpp index d18408d660718..fc006299dd787 100644 --- a/lib/Driver/WindowsToolChains.cpp +++ b/lib/Driver/WindowsToolChains.cpp @@ -49,6 +49,13 @@ toolchains::Windows::addPluginArguments(const ArgList &Args, SmallString<261> LibraryPath = StringRef(getDriver().getSwiftProgramPath()); llvm::sys::path::remove_filename(LibraryPath); // Remove `swift` + // In-process plugin server path. + SmallString<261> InProcPluginServerPath = LibraryPath; + llvm::sys::path::append(InProcPluginServerPath, + "SwiftInProcPluginServer.dll"); + Arguments.push_back("-in-process-plugin-server-path"); + Arguments.push_back(Args.MakeArgString(InProcPluginServerPath)); + // Default plugin path. Arguments.push_back("-plugin-path"); Arguments.push_back(Args.MakeArgString(LibraryPath)); diff --git a/lib/DriverTool/CMakeLists.txt b/lib/DriverTool/CMakeLists.txt index c728f08399eeb..7e651d176b1a4 100644 --- a/lib/DriverTool/CMakeLists.txt +++ b/lib/DriverTool/CMakeLists.txt @@ -30,6 +30,17 @@ target_link_libraries(swiftDriverTool PUBLIC ${driver_common_libs}) +if (SWIFT_BUILD_SWIFT_SYNTAX) + target_link_libraries(swiftDriverTool + PRIVATE + swiftASTGen + ) + + add_dependencies(swiftDriverTool + swiftASTGen + ) +endif() + # If building as part of clang, make sure the headers are installed. if(NOT SWIFT_BUILT_STANDALONE) add_dependencies(swiftDriverTool clang-resource-headers) diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt index 4c928fcce0cd6..db63361d816c4 100644 --- a/lib/Frontend/CMakeLists.txt +++ b/lib/Frontend/CMakeLists.txt @@ -37,4 +37,15 @@ target_link_libraries(swiftFrontend PRIVATE swiftSerialization swiftSymbolGraphGen) +if (SWIFT_BUILD_SWIFT_SYNTAX) + target_link_libraries(swiftFrontend + PRIVATE + swiftASTGen + ) + + add_dependencies(swiftFrontend + swiftASTGen + ) +endif() + set_swift_llvm_is_available(swiftFrontend) diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index d73cb0fae3aa3..a3e39edad824d 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1971,6 +1971,9 @@ static bool ParseSearchPathArgs(SearchPathOptions &Opts, ArgList &Args, } Opts.setFrameworkSearchPaths(FrameworkSearchPaths); + if (const Arg *A = Args.getLastArg(OPT_in_process_plugin_server_path)) + Opts.InProcessPluginServerPath = A->getValue(); + // All plugin search options, i.e. '-load-plugin-library', // '-load-plugin-executable', '-plugin-path', and '-external-plugin-path' // are grouped, and plugins are searched by the order of these options. diff --git a/lib/Parse/CMakeLists.txt b/lib/Parse/CMakeLists.txt index 4b51d767fe362..68bde86b613ef 100644 --- a/lib/Parse/CMakeLists.txt +++ b/lib/Parse/CMakeLists.txt @@ -29,26 +29,10 @@ target_link_libraries(swiftParse PRIVATE if (SWIFT_BUILD_SWIFT_SYNTAX) target_link_libraries(swiftParse PRIVATE - SwiftBasicFormat - SwiftParser - SwiftParserDiagnostics - SwiftDiagnostics - SwiftSyntax - SwiftOperators - SwiftSyntaxBuilder - SwiftSyntaxMacros swiftASTGen ) add_dependencies(swiftParse - SwiftBasicFormat - SwiftParser - SwiftParserDiagnostics - SwiftDiagnostics - SwiftSyntax - SwiftOperators - SwiftSyntaxBuilder - SwiftSyntaxMacros swiftASTGen ) endif() diff --git a/lib/Sema/TypeCheckMacros.cpp b/lib/Sema/TypeCheckMacros.cpp index f18f4ce2e608f..8de53cd00a513 100644 --- a/lib/Sema/TypeCheckMacros.cpp +++ b/lib/Sema/TypeCheckMacros.cpp @@ -48,38 +48,6 @@ using namespace swift; -#if SWIFT_BUILD_SWIFT_SYNTAX -/// Look for macro's type metadata given its external module and type name. -static void const * -lookupMacroTypeMetadataByExternalName(ASTContext &ctx, StringRef moduleName, - StringRef typeName, - LoadedLibraryPlugin *plugin) { - // 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 = Demangle::mangledNameForTypeMetadataAccessor( - moduleName, typeName, typeKind); - accessorAddr = plugin->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(accessorAddr); - return accessor(MetadataRequest(MetadataState::Complete)); -} -#endif - /// Translate an argument provided as a string literal into an identifier, /// or return \c None and emit an error if it cannot be done. std::optional getIdentifierFromStringLiteralArgument( @@ -266,36 +234,31 @@ MacroDefinition MacroDefinitionRequest::evaluate( #endif } -static llvm::Expected -initializeExecutablePlugin(ASTContext &ctx, - LoadedExecutablePlugin *executablePlugin, - StringRef libraryPath, Identifier moduleName) { +static llvm::Expected +initializePlugin(ASTContext &ctx, CompilerPlugin *plugin, StringRef libraryPath, + Identifier moduleName) { // Lock the plugin while initializing. // Note that'executablePlugn' can be shared between multiple ASTContext. - executablePlugin->lock(); - SWIFT_DEFER { executablePlugin->unlock(); }; + plugin->lock(); + SWIFT_DEFER { plugin->unlock(); }; // FIXME: Ideally this should be done right after invoking the plugin. // But plugin loading is in libAST and it can't link ASTGen symbols. - if (!executablePlugin->isInitialized()) { + if (!plugin->isInitialized()) { #if SWIFT_BUILD_SWIFT_SYNTAX - if (!swift_ASTGen_initializePlugin(executablePlugin, &ctx.Diags)) { - return llvm::createStringError( - llvm::inconvertibleErrorCode(), "'%s' produced malformed response", - executablePlugin->getExecutablePath().data()); + if (!swift_ASTGen_initializePlugin(plugin, &ctx.Diags)) { + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "'%s' produced malformed response", + plugin->getPath().data()); } // Resend the compiler capability on reconnect. - auto *callback = new std::function( - [executablePlugin]() { - (void)swift_ASTGen_initializePlugin( - executablePlugin, /*diags=*/nullptr); - }); - executablePlugin->addOnReconnect(callback); - - executablePlugin->setCleanup([executablePlugin] { - swift_ASTGen_deinitializePlugin(executablePlugin); + auto *callback = new std::function([plugin]() { + (void)swift_ASTGen_initializePlugin(plugin, /*diags=*/nullptr); }); + plugin->addOnReconnect(callback); + + plugin->setCleanup([plugin] { swift_ASTGen_deinitializePlugin(plugin); }); #endif } @@ -315,7 +278,7 @@ initializeExecutablePlugin(ASTContext &ctx, BridgedStringRef bridgedErrorOut{nullptr, 0}; bool loaded = swift_ASTGen_pluginServerLoadLibraryPlugin( - executablePlugin, resolvedLibraryPathStr.c_str(), moduleNameStr.c_str(), + plugin, resolvedLibraryPathStr.c_str(), moduleNameStr.c_str(), &bridgedErrorOut); auto errorOut = bridgedErrorOut.unbridged(); @@ -324,31 +287,30 @@ initializeExecutablePlugin(ASTContext &ctx, return llvm::createStringError( llvm::inconvertibleErrorCode(), "failed to load library plugin '%s' in plugin server '%s'; %s", - resolvedLibraryPathStr.c_str(), - executablePlugin->getExecutablePath().data(), errorOut.data()); + resolvedLibraryPathStr.c_str(), plugin->getPath().data(), + errorOut.data()); } assert(errorOut.data() == nullptr); // Set a callback to load the library again on reconnections. auto *callback = new std::function( - [executablePlugin, resolvedLibraryPathStr, moduleNameStr]() { + [plugin, resolvedLibraryPathStr, moduleNameStr]() { (void)swift_ASTGen_pluginServerLoadLibraryPlugin( - executablePlugin, resolvedLibraryPathStr.c_str(), - moduleNameStr.c_str(), + plugin, resolvedLibraryPathStr.c_str(), moduleNameStr.c_str(), /*errorOut=*/nullptr); }); - executablePlugin->addOnReconnect(callback); + plugin->addOnReconnect(callback); // Remove the callback and deallocate it when this ASTContext is destructed. - ctx.addCleanup([executablePlugin, callback]() { - executablePlugin->removeOnReconnect(callback); + ctx.addCleanup([plugin, callback]() { + plugin->removeOnReconnect(callback); delete callback; }); #endif } - return executablePlugin; + return plugin; } CompilerPluginLoadResult @@ -360,21 +322,21 @@ CompilerPluginLoadRequest::evaluate(Evaluator &evaluator, ASTContext *ctx, SmallString<0> errorMessage; if (!entry.executablePath.empty()) { - llvm::Expected executablePlugin = + llvm::Expected plugin = loader.loadExecutablePlugin(entry.executablePath); - if (executablePlugin) { + if (plugin) { if (ctx->LangOpts.EnableMacroLoadingRemarks) { unsigned tag = entry.libraryPath.empty() ? 1 : 2; ctx->Diags.diagnose(SourceLoc(), diag::macro_loaded, moduleName, tag, entry.executablePath, entry.libraryPath); } - executablePlugin = initializeExecutablePlugin( - *ctx, executablePlugin.get(), entry.libraryPath, moduleName); + plugin = + initializePlugin(*ctx, plugin.get(), entry.libraryPath, moduleName); } - if (executablePlugin) - return executablePlugin.get(); - llvm::handleAllErrors(executablePlugin.takeError(), + if (plugin) + return plugin.get(); + llvm::handleAllErrors(plugin.takeError(), [&](const llvm::ErrorInfoBase &err) { if (!errorMessage.empty()) errorMessage += ", "; @@ -382,17 +344,21 @@ CompilerPluginLoadRequest::evaluate(Evaluator &evaluator, ASTContext *ctx, }); } else if (!entry.libraryPath.empty()) { - llvm::Expected libraryPlugin = - loader.loadLibraryPlugin(entry.libraryPath); - if (libraryPlugin) { - if (ctx->LangOpts.EnableMacroLoadingRemarks) { - ctx->Diags.diagnose(SourceLoc(), diag::macro_loaded, moduleName, 0, - entry.libraryPath, StringRef()); + llvm::Expected plugins = loader.getInProcessPlugins(); + if (plugins) { + plugins = + initializePlugin(*ctx, plugins.get(), entry.libraryPath, moduleName); + if (plugins) { + if (ctx->LangOpts.EnableMacroLoadingRemarks) { + ctx->Diags.diagnose(SourceLoc(), diag::macro_loaded, moduleName, 0, + entry.libraryPath, StringRef()); + } + return plugins.get(); } + } - return libraryPlugin.get(); - } else { - llvm::handleAllErrors(libraryPlugin.takeError(), + if (!plugins) { + llvm::handleAllErrors(plugins.takeError(), [&](const llvm::ErrorInfoBase &err) { if (!errorMessage.empty()) errorMessage += ", "; @@ -410,63 +376,23 @@ CompilerPluginLoadRequest::evaluate(Evaluator &evaluator, ASTContext *ctx, } } -static ExternalMacroDefinition -resolveInProcessMacro(ASTContext &ctx, Identifier moduleName, - Identifier typeName, LoadedLibraryPlugin *plugin) { +static ExternalMacroDefinition resolveExternalMacro(ASTContext &ctx, + CompilerPlugin *plugin, + Identifier moduleName, + Identifier typeName) { #if SWIFT_BUILD_SWIFT_SYNTAX - /// Look for the type metadata given the external module and type names. - auto macroMetatype = lookupMacroTypeMetadataByExternalName( - ctx, moduleName.str(), typeName.str(), plugin); - if (macroMetatype) { - // Check whether the macro metatype is in-process. - if (auto inProcess = swift_ASTGen_resolveMacroType(macroMetatype)) { - // Make sure we clean up after the macro. - ctx.addCleanup([inProcess]() { - swift_ASTGen_destroyMacro(inProcess); - }); - - return ExternalMacroDefinition{ - ExternalMacroDefinition::PluginKind::InProcess, inProcess}; - } else { - NullTerminatedStringRef err( - "'" + moduleName.str() + "." + typeName.str() + - "' is not a valid macro implementation type in library plugin '" + - StringRef(plugin->getLibraryPath()) + "'", - ctx); - - return ExternalMacroDefinition::error(err); - } - } - NullTerminatedStringRef err("'" + moduleName.str() + "." + typeName.str() + - "' could not be found in library plugin '" + - StringRef(plugin->getLibraryPath()) + "'", - ctx); - return ExternalMacroDefinition::error(err); -#endif - return ExternalMacroDefinition::error( - "the current compiler was not built with macro support"); -} - -static ExternalMacroDefinition -resolveExecutableMacro(ASTContext &ctx, - LoadedExecutablePlugin *executablePlugin, - Identifier moduleName, Identifier typeName) { -#if SWIFT_BUILD_SWIFT_SYNTAX - if (auto *execMacro = swift_ASTGen_resolveExecutableMacro( - moduleName.get(), typeName.get(), executablePlugin)) { + if (auto *macro = swift_ASTGen_resolveExternalMacro(moduleName.get(), + typeName.get(), plugin)) { // Make sure we clean up after the macro. - ctx.addCleanup( - [execMacro]() { swift_ASTGen_destroyExecutableMacro(execMacro); }); - return ExternalMacroDefinition{ - ExternalMacroDefinition::PluginKind::Executable, execMacro}; + ctx.addCleanup([macro]() { swift_ASTGen_destroyExternalMacro(macro); }); + return ExternalMacroDefinition::success(macro); } // NOTE: this is not reachable because executable macro resolution always // succeeds. - NullTerminatedStringRef err( - "'" + moduleName.str() + "." + typeName.str() + - "' could not be found in executable plugin" + - StringRef(executablePlugin->getExecutablePath()), - ctx); + NullTerminatedStringRef err("'" + moduleName.str() + "." + typeName.str() + + "' could not be found in executable plugin" + + StringRef(plugin->getPath()), + ctx); return ExternalMacroDefinition::error(err); #endif return ExternalMacroDefinition::error( @@ -483,12 +409,8 @@ ExternalMacroDefinitionRequest::evaluate(Evaluator &evaluator, ASTContext *ctx, CompilerPluginLoadResult loaded = evaluateOrDefault( evaluator, loadRequest, CompilerPluginLoadResult::error("request error")); - if (auto loadedLibrary = loaded.getAsLibraryPlugin()) { - return resolveInProcessMacro(*ctx, moduleName, typeName, loadedLibrary); - } - - if (auto *executablePlugin = loaded.getAsExecutablePlugin()) { - return resolveExecutableMacro(*ctx, executablePlugin, moduleName, typeName); + if (auto plugin = loaded.get()) { + return resolveExternalMacro(*ctx, plugin, moduleName, typeName); } return ExternalMacroDefinition::error(loaded.getErrorMessage()); @@ -1222,8 +1144,7 @@ evaluateFreestandingMacro(FreestandingMacroExpansion *expansion, BridgedStringRef evaluatedSourceOut{nullptr, 0}; assert(!externalDef.isError()); swift_ASTGen_expandFreestandingMacro( - &ctx.Diags, externalDef.opaqueHandle, - static_cast(externalDef.kind), discriminator->c_str(), + &ctx.Diags, externalDef.get(), discriminator->c_str(), getRawMacroRole(macroRole), astGenSourceFile, expansion->getSourceRange().Start.getOpaquePointerValue(), &evaluatedSourceOut); @@ -1547,8 +1468,7 @@ static SourceFile *evaluateAttachedMacro(MacroDecl *macro, Decl *attachedTo, BridgedStringRef evaluatedSourceOut{nullptr, 0}; assert(!externalDef.isError()); swift_ASTGen_expandAttachedMacro( - &ctx.Diags, externalDef.opaqueHandle, - static_cast(externalDef.kind), discriminator->c_str(), + &ctx.Diags, externalDef.get(), discriminator->c_str(), extendedType.c_str(), conformanceList.c_str(), getRawMacroRole(role), astGenAttrSourceFile, attr->AtLoc.getOpaquePointerValue(), astGenDeclSourceFile, searchDecl->getStartLoc().getOpaquePointerValue(), diff --git a/test/Macros/macro_expand.swift b/test/Macros/macro_expand.swift index 840020e7b7f02..48dbfd9e72573 100644 --- a/test/Macros/macro_expand.swift +++ b/test/Macros/macro_expand.swift @@ -631,8 +631,8 @@ struct HasNestedType { #if TEST_DIAGNOSTICS @freestanding(expression) macro missingMacro() = #externalMacro(module: "MacroDefinition", type: "BluhBlah") -// expected-warning@-1 {{external macro implementation type 'MacroDefinition.BluhBlah' could not be found for macro 'missingMacro()'; 'MacroDefinition.BluhBlah' could not be found in library plugin '}} +// FIXME: xpected-warning@-1 {{external macro implementation type 'MacroDefinition.BluhBlah' could not be found for macro 'missingMacro()'; 'MacroDefinition.BluhBlah' could not be found in library plugin '}} @freestanding(expression) macro notMacro() = #externalMacro(module: "MacroDefinition", type: "NotMacroStruct") -// expected-warning@-1 {{macro implementation type 'MacroDefinition.NotMacroStruct' could not be found for macro 'notMacro()'; 'MacroDefinition.NotMacroStruct' is not a valid macro implementation type in library plugin '}} +// FIXME: xpected-warning@-1 {{macro implementation type 'MacroDefinition.NotMacroStruct' could not be found for macro 'notMacro()'; 'MacroDefinition.NotMacroStruct' is not a valid macro implementation type in library plugin '}} #endif diff --git a/test/Macros/macro_plugin_broken_shlib.swift b/test/Macros/macro_plugin_broken_shlib.swift index 9b11627774112..eb5de20a97a9d 100644 --- a/test/Macros/macro_plugin_broken_shlib.swift +++ b/test/Macros/macro_plugin_broken_shlib.swift @@ -34,8 +34,8 @@ // RUN: c-index-test -read-diagnostics %t/macro_expand_inproc.dia 2>&1 | %FileCheck -check-prefix INPROC %s // INPROC-NOT: {{error|warning}} -// INPROC: test.swift:1:33: warning: external macro implementation type 'TestPlugin.FooMacro' could not be found for macro 'fooMacro'; compiler plugin 'BUILD_DIR/{{.*}}/libTestPlugin.dylib' could not be loaded; dlopen(BUILD_DIR/{{.*}}/libTestPlugin.dylib, 0x0005): tried: 'BUILD_DIR/{{.*}}/libTestPlugin.dylib' -// INPROC: test.swift:4:7: error: external macro implementation type 'TestPlugin.FooMacro' could not be found for macro 'fooMacro'; compiler plugin 'BUILD_DIR/{{.*}}/libTestPlugin.dylib' could not be loaded; dlopen(BUILD_DIR/{{.*}}/libTestPlugin.dylib, 0x0005): tried: 'BUILD_DIR/{{.*}}/libTestPlugin.dylib' +// INPROC: test.swift:1:33: warning: external macro implementation type 'TestPlugin.FooMacro' could not be found for macro 'fooMacro'; failed to load library plugin 'BUILD_DIR/{{.*}}/libTestPlugin.dylib' in plugin server 'BUILD_DIR/{{.*}}/libSwiftInProcPluginServer.dylib'; loader error: dlopen(BUILD_DIR/{{.*}}/libTestPlugin.dylib, 0x0005): tried: 'BUILD_DIR/{{.*}}/libTestPlugin.dylib' +// INPROC: test.swift:4:7: error: external macro implementation type 'TestPlugin.FooMacro' could not be found for macro 'fooMacro'; failed to load library plugin 'BUILD_DIR/{{.*}}/libTestPlugin.dylib' in plugin server 'BUILD_DIR/{{.*}}/libSwiftInProcPluginServer.dylib'; loader error: dlopen(BUILD_DIR/{{.*}}/libTestPlugin.dylib, 0x0005): tried: 'BUILD_DIR/{{.*}}/libTestPlugin.dylib' // INPROC: test.swift:1:33: note: 'fooMacro' declared here // INPROC-NOT: {{error|warning}} diff --git a/test/Macros/macro_plugin_error.swift b/test/Macros/macro_plugin_error.swift index f57d8272ccd55..52746e7ec70cb 100644 --- a/test/Macros/macro_plugin_error.swift +++ b/test/Macros/macro_plugin_error.swift @@ -35,7 +35,7 @@ func test() { // FIXME: -module-abi-name ABI name is leaking. let _: String = #fooMacro(1) - // expected-error @-1 {{typeMismatch(CompilerSwiftCompilerPluginMessageHandling.PluginToHostMessage}} + // expected-error @-1 {{typeMismatch(_CompilerSwiftCompilerPluginMessageHandling.PluginToHostMessage}} let _: String = #fooMacro(2) // expected-error @-1 {{failed to receive result from plugin (from macro 'fooMacro')}} let _: String = #fooMacro(3) diff --git a/test/lit.cfg b/test/lit.cfg index c327efdb9f7bd..003b745afd7ec 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -1263,6 +1263,9 @@ if run_vendor == 'apple': config.resource_dir_opt = "-resource-dir %s" % new_resource_dir lit_config.note('Using freestanding resource dir: ' + new_resource_dir) + config.swift_in_process_plugin_server_path = make_path(config.swift_lib_dir, 'swift', 'host', 'libSwiftInProcPluginServer.dylib') + config.swift_test_options += " -in-process-plugin-server-path %s" % shell_quote(config.swift_in_process_plugin_server_path) + # Auto-linking does not work when stdlib is built with LTO, because linked # libraries are discovered too late (after optimizations are applied), and # ld64 hits an assert and crashes, or worse, deadlocks. Until ld64 fixes @@ -1613,6 +1616,9 @@ elif run_os in ['windows-msvc']: config.target_msvc_runtime_opt += ' -D_DLL' config.target_env_prefix = '' + config.swift_in_process_plugin_server_path = make_path(config.swift_bin_dir, 'SwiftInProcPluginServer.dll') + config.swift_test_options += " -in-process-plugin-server-path %s" % shell_quote(config.swift_in_process_plugin_server_path) + config.target_build_swift = \ ('%r -target %s %s %s %s %s %s -libc %s' % \ (config.swiftc, config.variant_triple, \ @@ -1744,6 +1750,9 @@ elif (run_os in ['linux-gnu', 'linux-gnueabihf', 'freebsd', 'openbsd', 'windows- config.target_runtime = "native" config.target_swift_autolink_extract = inferSwiftBinary("swift-autolink-extract") + config.swift_in_process_plugin_server_path = make_path(config.swift_lib_dir, 'swift', 'host', 'libSwiftInProcPluginServer.so') + config.swift_test_options += " -in-process-plugin-server-path %s" % shell_quote(config.swift_in_process_plugin_server_path) + libdispatch_artifact_dir = config.libdispatch_build_path libdispatch_swift_module_dir = make_path(libdispatch_artifact_dir, 'src', 'swift', 'swift') libdispatch_source_dir = make_path(config.swift_src_root, os.pardir, 'swift-corelibs-libdispatch') @@ -2708,14 +2717,14 @@ config.substitutions.append(('%target-sil-nm', config.target_sil_nm)) config.substitutions.append(('%batch-code-completion', '%empty-directory(%t/batch-code-completion) && %target-swift-ide-test -batch-code-completion -source-filename %s -filecheck %raw-FileCheck -completion-output-dir %t/batch-code-completion')) config.substitutions.append(('%target-swift-ide-test\(mock-sdk:([^)]+)\)', - SubstituteCaptures(r'%s \1 %s -swift-version %s' % ( + SubstituteCaptures(r'%s \1 %s %s' % ( escape_for_substitute_captures(subst_target_swift_ide_test_mock_sdk), escape_for_substitute_captures(subst_target_swift_ide_test_mock_sdk_after), - escape_for_substitute_captures(swift_version))))) + escape_for_substitute_captures(config.swift_test_options))))) config.substitutions.append(('%target-swift-ide-test', - "%s -swift-version %s %s" % (config.target_swift_ide_test, - swift_version, - config.clang_system_overlay_opt))) + "%s %s %s" % (config.target_swift_ide_test, + config.swift_test_options, + config.clang_system_overlay_opt))) config.substitutions.append(('%target-swift-symbolgraph-extract', config.target_swift_symbolgraph_extract)) config.substitutions.append(('%target-swift-api-extract', config.target_swift_api_extract)) diff --git a/tools/SourceKit/cmake/modules/AddSwiftSourceKit.cmake b/tools/SourceKit/cmake/modules/AddSwiftSourceKit.cmake index 00fc913fe8682..a37d3383f73e6 100644 --- a/tools/SourceKit/cmake/modules/AddSwiftSourceKit.cmake +++ b/tools/SourceKit/cmake/modules/AddSwiftSourceKit.cmake @@ -150,11 +150,11 @@ function(add_sourcekit_swift_runtime_link_flags target path HAS_SWIFT_MODULES) if(SWIFT_BUILD_SWIFT_SYNTAX) if(SWIFT_HOST_VARIANT_SDK IN_LIST SWIFT_DARWIN_PLATFORMS) # Add rpath to the host Swift libraries. - file(RELATIVE_PATH relative_hostlib_path "${path}" "${SWIFTLIB_DIR}/host") + file(RELATIVE_PATH relative_hostlib_path "${path}" "${SWIFTLIB_DIR}/host/compiler") list(APPEND RPATH_LIST "@loader_path/${relative_hostlib_path}") elseif(SWIFT_HOST_VARIANT_SDK MATCHES "LINUX|ANDROID|OPENBSD") # Add rpath to the host Swift libraries. - file(RELATIVE_PATH relative_hostlib_path "${path}" "${SWIFTLIB_DIR}/host") + file(RELATIVE_PATH relative_hostlib_path "${path}" "${SWIFTLIB_DIR}/host/compiler") list(APPEND RPATH_LIST "$ORIGIN/${relative_hostlib_path}") else() target_link_directories(${target} PRIVATE diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt index 5f81c6cd17d70..a0d48d45450b6 100644 --- a/tools/driver/CMakeLists.txt +++ b/tools/driver/CMakeLists.txt @@ -12,6 +12,7 @@ function(add_swift_parser_link_libraries target) foreach(macrolib ${SWIFT_MACRO_PLUGINS}) add_dependencies(${target} ${macrolib}) endforeach() + add_dependencies(${target} SwiftInProcPluginServer) endif() endfunction() diff --git a/tools/libSwiftScan/CMakeLists.txt b/tools/libSwiftScan/CMakeLists.txt index b078db98f0dca..4ab7956061a3c 100644 --- a/tools/libSwiftScan/CMakeLists.txt +++ b/tools/libSwiftScan/CMakeLists.txt @@ -34,7 +34,7 @@ set_target_properties(libSwiftScan if(SWIFT_HOST_VARIANT_SDK MATCHES "LINUX|ANDROID|OPENBSD|FREEBSD" AND BOOTSTRAPPING_MODE STREQUAL "HOSTTOOLS") # Runtime INSTALL_RPATH are set by 'add_swift_host_library', but that expects # libSwiftScan be installed in 'lib'. But since it's actually installed in 'lib/swift/host', - # we need to have correct runtime path to 'lib/swift/{platform}'. + # we need to have correct swift runtime path to 'lib/swift/{platform}'. # FIXME: BUILD_RPATH and INSTALL_PATH should be different # FIXME: add_swift_host_library should accept 'DESTINATION' and handle installation # FIXME: Build this library into 'lib/swift/host/' instead of 'lib/' @@ -46,20 +46,20 @@ endif() if(SWIFT_BUILD_SWIFT_SYNTAX) if(SWIFT_HOST_VARIANT_SDK IN_LIST SWIFT_DARWIN_PLATFORMS) - # Ensure that we can find the host shared libraries. + # Ensure that we can find the shared swift-syntax libraries. set_property( TARGET libSwiftScan - APPEND PROPERTY INSTALL_RPATH "@loader_path/swift/host") + APPEND PROPERTY INSTALL_RPATH "@loader_path/swift/host/compiler") set_property( TARGET libSwiftScan - APPEND PROPERTY INSTALL_RPATH "@loader_path/../host") + APPEND PROPERTY INSTALL_RPATH "@loader_path/../host/compiler") elseif(SWIFT_HOST_VARIANT_SDK MATCHES "LINUX|ANDROID|OPENBSD|FREEBSD") set_property( TARGET libSwiftScan - APPEND PROPERTY INSTALL_RPATH "$ORIGIN/swift/host") + APPEND PROPERTY INSTALL_RPATH "$ORIGIN/swift/host/compiler") set_property( TARGET libSwiftScan - APPEND PROPERTY INSTALL_RPATH "$ORIGIN/../host") + APPEND PROPERTY INSTALL_RPATH "$ORIGIN/../host/compiler") endif() endif() diff --git a/tools/swift-ide-test/swift-ide-test.cpp b/tools/swift-ide-test/swift-ide-test.cpp index 3abb0b4a2e4d9..f02a9d7856660 100644 --- a/tools/swift-ide-test/swift-ide-test.cpp +++ b/tools/swift-ide-test/swift-ide-test.cpp @@ -332,6 +332,11 @@ ImportObjCHeader("import-objc-header", llvm::cl::desc("header to implicitly import"), llvm::cl::cat(Category)); +static llvm::cl::opt +InProcessPluginServerPath("in-process-plugin-server-path", + llvm::cl::desc("in-process plugin server"), + llvm::cl::cat(Category)); + static llvm::cl::list PluginPath("plugin-path", llvm::cl::desc("plugin-path"), @@ -4541,6 +4546,10 @@ int main(int argc, char *argv[]) { } } + if (!options::InProcessPluginServerPath.empty()) { + InitInvok.getSearchPathOptions().InProcessPluginServerPath = + options::InProcessPluginServerPath; + } if (!options::LoadPluginLibrary.empty()) { std::vector paths; for (auto path: options::LoadPluginLibrary) { diff --git a/tools/swift-plugin-server/CMakeLists.txt b/tools/swift-plugin-server/CMakeLists.txt index e1e7ffc6f93b5..1bedf2f0d9ee5 100644 --- a/tools/swift-plugin-server/CMakeLists.txt +++ b/tools/swift-plugin-server/CMakeLists.txt @@ -7,4 +7,32 @@ if (SWIFT_BUILD_SWIFT_SYNTAX) SwiftCompilerPluginMessageHandling SwiftLibraryPluginProvider ) + + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${SWIFT_HOST_LIBRARIES_DEST_DIR}") + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${SWIFT_HOST_LIBRARIES_DEST_DIR}") + add_pure_swift_host_library(SwiftInProcPluginServer SHARED + Sources/SwiftInProcPluginServer/InProcPluginServer.swift + SWIFT_DEPENDENCIES + SwiftCompilerPluginMessageHandling + SwiftLibraryPluginProvider + ) + + if(SWIFT_HOST_VARIANT_SDK IN_LIST SWIFT_DARWIN_PLATFORMS) + set_property(TARGET SwiftInProcPluginServer + APPEND PROPERTY INSTALL_RPATH + "@loader_path") + elseif(SWIFT_HOST_VARIANT_SDK MATCHES "LINUX|ANDROID|OPENBSD|FREEBSD") + set_property(TARGET SwiftInProcPluginServer + APPEND PROPERTY INSTALL_RPATH + "$ORIGIN") + endif() + + set_property(TARGET ${name} + PROPERTY BUILD_WITH_INSTALL_RPATH YES) + + add_dependencies(compiler SwiftInProcPluginServer) + swift_install_in_component(TARGETS SwiftInProcPluginServer + ARCHIVE DESTINATION "lib${LLVM_LIBDIR_SUFFIX}/swift/host" COMPONENT compiler + LIBRARY DESTINATION "lib${LLVM_LIBDIR_SUFFIX}/swift/host" COMPONENT compiler + RUNTIME DESTINATION "bin" COMPONENT compiler) endif() diff --git a/tools/swift-plugin-server/Package.swift b/tools/swift-plugin-server/Package.swift index a30a97a118bbf..543fca15a9293 100644 --- a/tools/swift-plugin-server/Package.swift +++ b/tools/swift-plugin-server/Package.swift @@ -7,6 +7,10 @@ let package = Package( platforms: [ .macOS(.v10_15) ], + products: [ + .executable(name: "swift-plugin-server", targets: ["swift-plugin-server"]), + .library(name: "SwiftInProcPluginServer", type: .dynamic, targets: ["SwiftInProcPluginServer"]), + ], dependencies: [ .package(path: "../../../swift-syntax"), ], @@ -15,6 +19,14 @@ let package = Package( name: "swift-plugin-server", dependencies: [ .product(name: "SwiftCompilerPluginMessageHandling", package: "swift-syntax"), + .product(name: "SwiftLibraryPluginProvider", package: "swift-syntax"), + ] + ), + .target( + name: "SwiftInProcPluginServer", + dependencies: [ + .product(name: "SwiftCompilerPluginMessageHandling", package: "swift-syntax"), + .product(name: "SwiftLibraryPluginProvider", package: "swift-syntax"), ] ), ], diff --git a/tools/swift-plugin-server/Sources/SwiftInProcPluginServer/InProcPluginServer.swift b/tools/swift-plugin-server/Sources/SwiftInProcPluginServer/InProcPluginServer.swift new file mode 100644 index 0000000000000..bf15260835e79 --- /dev/null +++ b/tools/swift-plugin-server/Sources/SwiftInProcPluginServer/InProcPluginServer.swift @@ -0,0 +1,88 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift open source project +// +// Copyright (c) 2024 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 +// +//===----------------------------------------------------------------------===// + +@_spi(PluginMessage) import SwiftCompilerPluginMessageHandling +@_spi(PluginMessage) import SwiftLibraryPluginProvider + +#if canImport(Darwin) +import Darwin +#elseif canImport(Glibc) +import Glibc +#elseif canImport(Musl) +import Musl +#elseif canImport(ucrt) +import ucrt +#else +#error("'malloc' not found") +#endif + +/// Entry point. +/// +/// Compiler 'dlopen' this 'SwiftInProcPluginServer' library, and 'dlsym' this +/// function. When the compiler wants to use dylib plugins, it calls this +/// function with the same message as `swift-plugin-server`. +/// +/// The caller must `free` the returned buffer +@_cdecl("swift_inproc_plugins_handle_message") +@MainActor +public func handleMessage( + _ inputData: UnsafePointer!, + _ inputLength: Int, + _ outputData: UnsafeMutablePointer?>!, + _ outputLength: UnsafeMutablePointer! +) -> Bool { + do { + let input = UnsafeBufferPointer(start: inputData, count: inputLength) + let output = try InProcPluginServer.shared.handleMessage(input) + output.withUnsafeBufferPointer(fillOutput(_:)) + return false // Success. + } catch { + var message = "Internal Error: \(error)" + message.withUTF8(fillOutput(_:)) + return true // Error. + } + + func fillOutput(_ responseData: UnsafeBufferPointer) { + // NOTE: Use 'malloc' instead of 'UnsafeMutablePointer.allocate()' so that + // C/C++ clients can deallocate it without using Swift. + let buffer = malloc(responseData.count)! + buffer.initializeMemory( + as: UInt8.self, + from: responseData.baseAddress!, + count: responseData.count + ) + outputData.pointee = buffer.assumingMemoryBound(to: UInt8.self) + outputLength.pointee = responseData.count + } +} + +/// Singleton "plugin server". +struct InProcPluginServer { + private let handler: CompilerPluginMessageHandler + + @MainActor + private init() { + self.handler = CompilerPluginMessageHandler( + provider: LibraryPluginProvider.shared + ) + } + + func handleMessage(_ input: UnsafeBufferPointer) throws -> [UInt8] { + let request = try JSON.decode(HostToPluginMessage.self, from: input) + let response = handler.handleMessage(request) + return try JSON.encode(response) + } + + @MainActor + static let shared = Self() +} + From 3a579137e6228a241ac32ca14cb282625b591779 Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Thu, 20 Jun 2024 10:38:39 -0700 Subject: [PATCH 2/5] [Macros] Infer in-process plugin server in swift-frontend Not all driver can send '-in-process-plugin-server-path'. To keep existing '-plugin-path' working, infer default server path in the frontend. (cherry picked from commit f08d69c6d7c30c8bd3027dd52d26af61a9377455) --- include/swift/Frontend/Frontend.h | 6 +++++ lib/Frontend/CompilerInvocation.cpp | 32 +++++++++++++++++++++++++ test/lit.cfg | 9 ------- tools/swift-ide-test/swift-ide-test.cpp | 1 + 4 files changed, 39 insertions(+), 9 deletions(-) diff --git a/include/swift/Frontend/Frontend.h b/include/swift/Frontend/Frontend.h index e8e97b06cb1fd..e60e228fe3e28 100644 --- a/include/swift/Frontend/Frontend.h +++ b/include/swift/Frontend/Frontend.h @@ -250,6 +250,12 @@ class CompilerInvocation { /// If we haven't explicitly passed -blocklist-paths, set it to the default value. void setDefaultBlocklistsIfNecessary(); + /// If we haven't explicitly passed '-in-process-plugin-server-path', infer + /// it as a default value. + /// + /// FIXME: Remove this after all the clients start sending it. + void setDefaultInProcessPluginServerPathIfNecessary(); + /// Computes the runtime resource path relative to the given Swift /// executable. static void computeRuntimeResourcePathFromExecutablePath( diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index a3e39edad824d..40ef0041050d2 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -186,6 +186,37 @@ void CompilerInvocation::setDefaultBlocklistsIfNecessary() { } } +void CompilerInvocation::setDefaultInProcessPluginServerPathIfNecessary() { + if (!SearchPathOpts.InProcessPluginServerPath.empty()) + return; + if (FrontendOpts.MainExecutablePath.empty()) + return; + + // '/usr/bin/swift' + SmallString<64> serverLibPath{FrontendOpts.MainExecutablePath}; + llvm::sys::path::remove_filename(serverLibPath); // remove 'swift' + +#if defined(_WIN32) + // Windows: usr\bin\SwiftInProcPluginServer.dll + llvm::sys::path::append(serverLibPath, "SwiftInProcPluginServer.dll"); + +#elif defined(__APPLE__) + // Darwin: usr/lib/swift/host/libSwiftInProcPluginServer.dylib + llvm::sys::path::remove_filename(serverLibPath); // remove 'bin' + llvm::sys::path::append(serverLibPath, "lib", "swift", "host"); + llvm::sys::path::append(serverLibPath, "libSwiftInProcPluginServer.dylib"); + +#else + // Other: usr/lib/swift/host/libSwiftInProcPluginServer.so + llvm::sys::path::remove_filename(serverLibPath); // remove 'bin' + llvm::sys::path::append(serverLibPath, "lib", "swift", "host"); + llvm::sys::path::append(serverLibPath, "libSwiftInProcPluginServer.so"); + +#endif + + SearchPathOpts.InProcessPluginServerPath = serverLibPath.str(); +} + static void updateRuntimeLibraryPaths(SearchPathOptions &SearchPathOpts, const FrontendOptions &FrontendOpts, const LangOptions &LangOpts) { @@ -3504,6 +3535,7 @@ bool CompilerInvocation::parseArgs( updateRuntimeLibraryPaths(SearchPathOpts, FrontendOpts, LangOpts); setDefaultPrebuiltCacheIfNecessary(); setDefaultBlocklistsIfNecessary(); + setDefaultInProcessPluginServerPathIfNecessary(); // Now that we've parsed everything, setup some inter-option-dependent state. setIRGenOutputOptsFromFrontendOptions(IRGenOpts, FrontendOpts); diff --git a/test/lit.cfg b/test/lit.cfg index 003b745afd7ec..29df86abd4327 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -1263,9 +1263,6 @@ if run_vendor == 'apple': config.resource_dir_opt = "-resource-dir %s" % new_resource_dir lit_config.note('Using freestanding resource dir: ' + new_resource_dir) - config.swift_in_process_plugin_server_path = make_path(config.swift_lib_dir, 'swift', 'host', 'libSwiftInProcPluginServer.dylib') - config.swift_test_options += " -in-process-plugin-server-path %s" % shell_quote(config.swift_in_process_plugin_server_path) - # Auto-linking does not work when stdlib is built with LTO, because linked # libraries are discovered too late (after optimizations are applied), and # ld64 hits an assert and crashes, or worse, deadlocks. Until ld64 fixes @@ -1616,9 +1613,6 @@ elif run_os in ['windows-msvc']: config.target_msvc_runtime_opt += ' -D_DLL' config.target_env_prefix = '' - config.swift_in_process_plugin_server_path = make_path(config.swift_bin_dir, 'SwiftInProcPluginServer.dll') - config.swift_test_options += " -in-process-plugin-server-path %s" % shell_quote(config.swift_in_process_plugin_server_path) - config.target_build_swift = \ ('%r -target %s %s %s %s %s %s -libc %s' % \ (config.swiftc, config.variant_triple, \ @@ -1750,9 +1744,6 @@ elif (run_os in ['linux-gnu', 'linux-gnueabihf', 'freebsd', 'openbsd', 'windows- config.target_runtime = "native" config.target_swift_autolink_extract = inferSwiftBinary("swift-autolink-extract") - config.swift_in_process_plugin_server_path = make_path(config.swift_lib_dir, 'swift', 'host', 'libSwiftInProcPluginServer.so') - config.swift_test_options += " -in-process-plugin-server-path %s" % shell_quote(config.swift_in_process_plugin_server_path) - libdispatch_artifact_dir = config.libdispatch_build_path libdispatch_swift_module_dir = make_path(libdispatch_artifact_dir, 'src', 'swift', 'swift') libdispatch_source_dir = make_path(config.swift_src_root, os.pardir, 'swift-corelibs-libdispatch') diff --git a/tools/swift-ide-test/swift-ide-test.cpp b/tools/swift-ide-test/swift-ide-test.cpp index f02a9d7856660..e7a244240d92a 100644 --- a/tools/swift-ide-test/swift-ide-test.cpp +++ b/tools/swift-ide-test/swift-ide-test.cpp @@ -4576,6 +4576,7 @@ int main(int argc, char *argv[]) { InitInvok.getSearchPathOptions().PluginSearchOpts.emplace_back( PluginSearchOption::PluginPath{path}); } + InitInvok.setDefaultInProcessPluginServerPathIfNecessary(); // Process the clang arguments last and allow them to override previously // set options. From b5bacff754b27af2b21d2d501083dae51b7dea15 Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Wed, 26 Jun 2024 09:32:44 -0700 Subject: [PATCH 3/5] [swift-syntax] Update for underscored product names (cherry picked from commit 3f8d13d491f8ec25a09330069cb00c9cdfb4a701) --- lib/ASTGen/Package.swift | 2 +- tools/swift-plugin-server/Package.swift | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/ASTGen/Package.swift b/lib/ASTGen/Package.swift index 8b83ca560115c..ac5120f307ef7 100644 --- a/lib/ASTGen/Package.swift +++ b/lib/ASTGen/Package.swift @@ -52,7 +52,7 @@ let package = Package( .target( name: "swiftASTGen", dependencies: [ - .product(name: "SwiftCompilerPluginMessageHandling", package: "swift-syntax"), + .product(name: "_SwiftCompilerPluginMessageHandling", package: "swift-syntax"), .product(name: "SwiftDiagnostics", package: "swift-syntax"), .product(name: "SwiftOperators", package: "swift-syntax"), .product(name: "SwiftParser", package: "swift-syntax"), diff --git a/tools/swift-plugin-server/Package.swift b/tools/swift-plugin-server/Package.swift index 543fca15a9293..5ad685b7b6ca1 100644 --- a/tools/swift-plugin-server/Package.swift +++ b/tools/swift-plugin-server/Package.swift @@ -18,15 +18,15 @@ let package = Package( .executableTarget( name: "swift-plugin-server", dependencies: [ - .product(name: "SwiftCompilerPluginMessageHandling", package: "swift-syntax"), - .product(name: "SwiftLibraryPluginProvider", package: "swift-syntax"), + .product(name: "_SwiftCompilerPluginMessageHandling", package: "swift-syntax"), + .product(name: "_SwiftLibraryPluginProvider", package: "swift-syntax"), ] ), .target( name: "SwiftInProcPluginServer", dependencies: [ - .product(name: "SwiftCompilerPluginMessageHandling", package: "swift-syntax"), - .product(name: "SwiftLibraryPluginProvider", package: "swift-syntax"), + .product(name: "_SwiftCompilerPluginMessageHandling", package: "swift-syntax"), + .product(name: "_SwiftLibraryPluginProvider", package: "swift-syntax"), ] ), ], From 10937430e0d30a30306612ec64721ddc93adff9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Rodr=C3=ADguez=20Troiti=C3=B1o?= Date: Wed, 26 Jun 2024 19:56:24 -0700 Subject: [PATCH 4/5] [Macros] In-process plugin server library tied to compiler host, not target PR #73725 introduced the in-process plugin server library, but the selection of the library depends on the selected toolchain, which depends on the compiler target, not the host. When cross-compiling (for example from macOS to a embedded Unix target), the compiler will incorrectly chose the `.so` file, not find it, and fail to compile things like the `@debugDescription` macro. Move the in-process plugin server library code from the platform toolchains into the parent type, and code it so it uses the right name depending on the compiler host at compilation time. This discards the target and only relies on the compiler host for selecting the right library. (cherry picked from commit 55d9e7438c70e7b39e0a77a72113b66c5342b3ac) --- include/swift/Driver/ToolChain.h | 6 +- lib/Driver/DarwinToolChains.cpp | 31 ---------- lib/Driver/ToolChains.cpp | 62 +++++++++++++++++++ lib/Driver/ToolChains.h | 9 --- lib/Driver/UnixToolChains.cpp | 31 ---------- lib/Driver/WindowsToolChains.cpp | 18 ------ test/Driver/compiler_plugin_path.swift | 7 +-- .../Driver/compiler_plugin_path_windows.swift | 5 ++ 8 files changed, 73 insertions(+), 96 deletions(-) create mode 100644 test/Driver/compiler_plugin_path_windows.swift diff --git a/include/swift/Driver/ToolChain.h b/include/swift/Driver/ToolChain.h index 16631c703b833..d438980d9a18e 100644 --- a/include/swift/Driver/ToolChain.h +++ b/include/swift/Driver/ToolChain.h @@ -253,6 +253,9 @@ class ToolChain { const InvocationInfo &invocationInfo, const JobContext &context) const; + void addPluginArguments(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &Arguments) const; + public: virtual ~ToolChain() = default; @@ -341,9 +344,6 @@ class ToolChain { llvm::opt::ArgStringList &Arguments, StringRef LibName) const; - virtual void addPluginArguments(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &Arguments) const {} - /// Validates arguments passed to the toolchain. /// /// An override point for platform-specific subclasses to customize the diff --git a/lib/Driver/DarwinToolChains.cpp b/lib/Driver/DarwinToolChains.cpp index 76158298ed9db..f7ee21dfe8f5f 100644 --- a/lib/Driver/DarwinToolChains.cpp +++ b/lib/Driver/DarwinToolChains.cpp @@ -128,37 +128,6 @@ std::string toolchains::Darwin::sanitizerRuntimeLibName(StringRef Sanitizer, .str(); } -void -toolchains::Darwin::addPluginArguments(const ArgList &Args, - ArgStringList &Arguments) const { - SmallString<64> pluginPath; - auto programPath = getDriver().getSwiftProgramPath(); - CompilerInvocation::computeRuntimeResourcePathFromExecutablePath( - programPath, /*shared=*/true, pluginPath); - - // In-process plugin server path. - auto inProcPluginServerPath = pluginPath; - llvm::sys::path::append(inProcPluginServerPath, "host", - "libSwiftInProcPluginServer.dylib"); - Arguments.push_back("-in-process-plugin-server-path"); - Arguments.push_back(Args.MakeArgString(inProcPluginServerPath)); - - // Default plugin path. - auto defaultPluginPath = pluginPath; - llvm::sys::path::append(defaultPluginPath, "host", "plugins"); - Arguments.push_back("-plugin-path"); - Arguments.push_back(Args.MakeArgString(defaultPluginPath)); - - // Local plugin path. - llvm::sys::path::remove_filename(pluginPath); // Remove "swift" - llvm::sys::path::remove_filename(pluginPath); // Remove "lib" - llvm::sys::path::append(pluginPath, "local", "lib"); - llvm::sys::path::append(pluginPath, "swift"); - llvm::sys::path::append(pluginPath, "host", "plugins"); - Arguments.push_back("-plugin-path"); - Arguments.push_back(Args.MakeArgString(pluginPath)); -} - static void addLinkRuntimeLibRPath(const ArgList &Args, ArgStringList &Arguments, StringRef DarwinLibName, diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index a945f376fa32d..cddc58b3056af 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -1466,6 +1466,68 @@ void ToolChain::addLinkRuntimeLib(const ArgList &Args, ArgStringList &Arguments, Arguments.push_back(Args.MakeArgString(P)); } +static void appendInProcPluginServerPath(StringRef PluginPathRoot, + llvm::SmallVectorImpl &InProcPluginServerPath) { + InProcPluginServerPath.append(PluginPathRoot.begin(), PluginPathRoot.end()); +#if defined(_WIN32) + llvm::sys::path::append(InProcPluginServerPath, "bin", "SwiftInProcPluginServer.dll"); +#elif defined(__APPLE__) + llvm::sys::path::append(InProcPluginServerPath, "lib", "swift", "host", "libSwiftInProcPluginServer.dylib"); +#elif defined(__unix__) + llvm::sys::path::append(InProcPluginServerPath, "lib", "swift", "host", "libSwiftInProcPluginServer.so"); +#else +#error Unknown compiler host +#endif +} + +static void appendPluginsPath(StringRef PluginPathRoot, + llvm::SmallVectorImpl &PluginsPath) { + PluginsPath.append(PluginPathRoot.begin(), PluginPathRoot.end()); +#if defined(_WIN32) + llvm::sys::path::append(PluginsPath, "bin"); +#elif defined(__APPLE__) || defined(__unix__) + llvm::sys::path::append(PluginsPath, "lib", "swift", "host", "plugins"); +#else +#error Unknown compiler host +#endif +} + +#if defined(__APPLE__) || defined(__unix__) +static void appendLocalPluginsPath(StringRef PluginPathRoot, + llvm::SmallVectorImpl &LocalPluginsPath) { + SmallString<261> localPluginPathRoot = PluginPathRoot; + llvm::sys::path::append(localPluginPathRoot, "local"); + appendPluginsPath(localPluginPathRoot, LocalPluginsPath); +} +#endif + +void ToolChain::addPluginArguments(const ArgList &Args, + ArgStringList &Arguments) const { + SmallString<261> pluginPathRoot = StringRef(getDriver().getSwiftProgramPath()); + llvm::sys::path::remove_filename(pluginPathRoot); // Remove `swift` + llvm::sys::path::remove_filename(pluginPathRoot); // Remove `bin` + + // In-process plugin server path. + SmallString<261> inProcPluginServerPath; + appendInProcPluginServerPath(pluginPathRoot, inProcPluginServerPath); + Arguments.push_back("-in-process-plugin-server-path"); + Arguments.push_back(Args.MakeArgString(inProcPluginServerPath)); + + // Default plugin path. + SmallString<261> defaultPluginPath; + appendPluginsPath(pluginPathRoot, defaultPluginPath); + Arguments.push_back("-plugin-path"); + Arguments.push_back(Args.MakeArgString(defaultPluginPath)); + + // Local plugin path. +#if defined(__APPLE__) || defined(__unix__) + SmallString<261> localPluginPath; + appendLocalPluginsPath(pluginPathRoot, localPluginPath); + Arguments.push_back("-plugin-path"); + Arguments.push_back(Args.MakeArgString(localPluginPath)); +#endif +} + void ToolChain::getClangLibraryPath(const ArgList &Args, SmallString<128> &LibPath) const { const llvm::Triple &T = getTriple(); diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h index 59b755e9f0d34..52adec85b49de 100644 --- a/lib/Driver/ToolChains.h +++ b/lib/Driver/ToolChains.h @@ -66,9 +66,6 @@ class LLVM_LIBRARY_VISIBILITY Darwin : public ToolChain { InvocationInfo constructInvocation(const StaticLinkJobAction &job, const JobContext &context) const override; - void addPluginArguments(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &Arguments) const override; - void validateArguments(DiagnosticEngine &diags, const llvm::opt::ArgList &args, StringRef defaultTarget) const override; @@ -117,9 +114,6 @@ class LLVM_LIBRARY_VISIBILITY Windows : public ToolChain { std::string sanitizerRuntimeLibName(StringRef Sanitizer, bool shared = true) const override; - - void addPluginArguments(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &Arguments) const override; }; class LLVM_LIBRARY_VISIBILITY WebAssembly : public ToolChain { @@ -173,9 +167,6 @@ class LLVM_LIBRARY_VISIBILITY GenericUnix : public ToolChain { ~GenericUnix() = default; std::string sanitizerRuntimeLibName(StringRef Sanitizer, bool shared = true) const override; - - void addPluginArguments(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &Arguments) const override; }; class LLVM_LIBRARY_VISIBILITY Android : public GenericUnix { diff --git a/lib/Driver/UnixToolChains.cpp b/lib/Driver/UnixToolChains.cpp index 12ccae8678d8f..e5ab5de94301b 100644 --- a/lib/Driver/UnixToolChains.cpp +++ b/lib/Driver/UnixToolChains.cpp @@ -47,37 +47,6 @@ toolchains::GenericUnix::sanitizerRuntimeLibName(StringRef Sanitizer, .str(); } -void -toolchains::GenericUnix::addPluginArguments(const ArgList &Args, - ArgStringList &Arguments) const { - SmallString<64> pluginPath; - auto programPath = getDriver().getSwiftProgramPath(); - CompilerInvocation::computeRuntimeResourcePathFromExecutablePath( - programPath, /*shared=*/true, pluginPath); - - // In-process plugin server path. - auto inProcPluginServerPath = pluginPath; - llvm::sys::path::append(inProcPluginServerPath, "host", - "libSwiftInProcPluginServer.so"); - Arguments.push_back("-in-process-plugin-server-path"); - Arguments.push_back(Args.MakeArgString(inProcPluginServerPath)); - - // Default plugin path. - auto defaultPluginPath = pluginPath; - llvm::sys::path::append(defaultPluginPath, "host", "plugins"); - Arguments.push_back("-plugin-path"); - Arguments.push_back(Args.MakeArgString(defaultPluginPath)); - - // Local plugin path. - llvm::sys::path::remove_filename(pluginPath); // Remove "swift" - llvm::sys::path::remove_filename(pluginPath); // Remove "lib" - llvm::sys::path::append(pluginPath, "local", "lib"); - llvm::sys::path::append(pluginPath, "swift"); - llvm::sys::path::append(pluginPath, "host", "plugins"); - Arguments.push_back("-plugin-path"); - Arguments.push_back(Args.MakeArgString(pluginPath)); -} - ToolChain::InvocationInfo toolchains::GenericUnix::constructInvocation(const InterpretJobAction &job, const JobContext &context) const { diff --git a/lib/Driver/WindowsToolChains.cpp b/lib/Driver/WindowsToolChains.cpp index fc006299dd787..e51a7d139e9f3 100644 --- a/lib/Driver/WindowsToolChains.cpp +++ b/lib/Driver/WindowsToolChains.cpp @@ -43,24 +43,6 @@ std::string toolchains::Windows::sanitizerRuntimeLibName(StringRef Sanitizer, .str(); } -void -toolchains::Windows::addPluginArguments(const ArgList &Args, - ArgStringList &Arguments) const { - SmallString<261> LibraryPath = StringRef(getDriver().getSwiftProgramPath()); - llvm::sys::path::remove_filename(LibraryPath); // Remove `swift` - - // In-process plugin server path. - SmallString<261> InProcPluginServerPath = LibraryPath; - llvm::sys::path::append(InProcPluginServerPath, - "SwiftInProcPluginServer.dll"); - Arguments.push_back("-in-process-plugin-server-path"); - Arguments.push_back(Args.MakeArgString(InProcPluginServerPath)); - - // Default plugin path. - Arguments.push_back("-plugin-path"); - Arguments.push_back(Args.MakeArgString(LibraryPath)); -} - ToolChain::InvocationInfo toolchains::Windows::constructInvocation(const DynamicLinkJobAction &job, const JobContext &context) const { diff --git a/test/Driver/compiler_plugin_path.swift b/test/Driver/compiler_plugin_path.swift index 535c52e1c8e45..3b539e92ff6f1 100644 --- a/test/Driver/compiler_plugin_path.swift +++ b/test/Driver/compiler_plugin_path.swift @@ -1,7 +1,6 @@ // RUN: %swiftc_driver -driver-print-jobs -target x86_64-apple-macosx10.9 %s 2>^1 | %FileCheck %s -// CHECK: -plugin-path -// CHECK-SAME: {{(/|\\\\)}}lib{{(/|\\\\)}}swift{{(/|\\\\)}}host{{(/|\\\\)}}plugins +// REQUIRES: OS=macosx || OS=linux-gnu -// CHECK-SAME: -plugin-path -// CHECK-SAME: {{(/|\\\\)}}local{{(/|\\\\)}}lib{{(/|\\\\)}}swift{{(/|\\\\)}}host{{(/|\\\\)}}plugins +// CHECK: -plugin-path {{[^ ]+}}/lib/swift/host/plugins +// CHECK-SAME: -plugin-path {{[^ ]+}}/local/lib/swift/host/plugins diff --git a/test/Driver/compiler_plugin_path_windows.swift b/test/Driver/compiler_plugin_path_windows.swift new file mode 100644 index 0000000000000..ed62e588114cb --- /dev/null +++ b/test/Driver/compiler_plugin_path_windows.swift @@ -0,0 +1,5 @@ +// RUN: %swiftc_driver -driver-print-jobs -target x86_64-apple-macosx10.9 %s 2>^1 | %FileCheck %s + +// REQUIRES: OS=windows + +// CHECK: -plugin-path {{[^ ]+}}\bin From 5fa203ea8d26a45d60cecd78f2470055de58191f Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Wed, 3 Jul 2024 09:51:07 -0700 Subject: [PATCH 5/5] [Macros] Fix memory leak A `std::function` instance remained in memory. rdar://131048379 (cherry picked from commit 432d5bb2fc51cabf6174e159073c1a5812f06853) --- lib/Sema/TypeCheckMacros.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/Sema/TypeCheckMacros.cpp b/lib/Sema/TypeCheckMacros.cpp index 8de53cd00a513..6a89256408183 100644 --- a/lib/Sema/TypeCheckMacros.cpp +++ b/lib/Sema/TypeCheckMacros.cpp @@ -258,7 +258,10 @@ initializePlugin(ASTContext &ctx, CompilerPlugin *plugin, StringRef libraryPath, }); plugin->addOnReconnect(callback); - plugin->setCleanup([plugin] { swift_ASTGen_deinitializePlugin(plugin); }); + plugin->setCleanup([plugin, callback] { + swift_ASTGen_deinitializePlugin(plugin); + delete callback; + }); #endif }