Skip to content

[Macros] Plugin search options group #66650

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 15, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 13 additions & 24 deletions include/swift/AST/PluginLoader.h
Original file line number Diff line number Diff line change
@@ -52,30 +52,19 @@ class PluginLoader {
void setRegistry(PluginRegistry *newValue);
PluginRegistry *getRegistry();

/// Lookup a library plugin that can handle \p moduleName and return the path
/// to it from `-load-plugin-library`.
/// The path returned can be loaded by 'loadLibraryPlugin' method.
llvm::Optional<std::string>
lookupExplicitLibraryPluginByModuleName(Identifier moduleName);

/// Lookup a library plugin that can handle \p moduleName and return the path
/// to it from `-plugin-path`.
/// The path returned can be loaded by 'loadLibraryPlugin' method.
llvm::Optional<std::string>
lookupLibraryPluginInSearchPathByModuleName(Identifier moduleName);

/// Lookup an executable plugin that is declared to handle \p moduleName
/// module by '-load-plugin-executable'.
/// The path returned can be loaded by 'loadExecutablePlugin' method.
llvm::Optional<StringRef>
lookupExecutablePluginByModuleName(Identifier moduleName);

/// Look for dynamic libraries in paths from `-external-plugin-path` and
/// return a pair of `(library path, plugin server executable)` if found.
/// These paths are valid within the VFS, use `FS.getRealPath()` for their
/// underlying path.
llvm::Optional<std::pair<std::string, std::string>>
lookupExternalLibraryPluginByModuleName(Identifier moduleName);
/// Lookup a plugin that can handle \p moduleName and return the path(s) to
/// it. The path returned can be loaded by 'load(Library|Executable)Plugin()'.
/// The return value is a pair of a "library path" and a "executable path".
///
/// * (libPath: empty, execPath: empty) - plugin not found.
/// * (libPath: some, execPath: empty) - load the library path by
/// 'loadLibraryPlugin()'.
/// * (libPath: empty, execPath: some) - load the executable path by
/// 'loadExecutablePlugin()'.
/// * (libPath: some, execPath: some) - load the executable path by
/// 'loadExecutablePlugin()' and let the plugin load the libPath via IPC.
std::pair<std::string, std::string>
lookupPluginByModuleName(Identifier moduleName);

/// Load the specified dylib plugin path resolving the path with the
/// current VFS. If it fails to load the plugin, a diagnostic is emitted, and
62 changes: 23 additions & 39 deletions include/swift/AST/SearchPathOptions.h
Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@

#include "swift/Basic/ArrayRefView.h"
#include "swift/Basic/PathRemapper.h"
#include "swift/Basic/TaggedUnion.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/StringMap.h"
@@ -34,7 +35,6 @@ enum class ModuleSearchPathKind {
Framework,
DarwinImplicitFramework,
RuntimeLibrary,
CompilerPlugin,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ModuleSearchPathKind::CompilePlugin was incomplete (only set for -load-plugin-library), and was not actually used.

};

/// A single module search path that can come from different sources, e.g.
@@ -187,6 +187,26 @@ struct ExternalPluginSearchPathAndServerPath {
std::string ServerPath;
};

namespace PluginSearchOption {
struct LoadPluginLibrary {
std::string LibraryPath;
};
struct LoadPluginExecutable {
std::string ExecutablePath;
std::vector<std::string> ModuleNames;
};
struct PluginPath {
std::string SearchPath;
};
struct ExternalPluginPath {
std::string SearchPath;
std::string ServerPath;
};

using Value = TaggedUnion<LoadPluginLibrary, LoadPluginExecutable, PluginPath,
ExternalPluginPath>;
} // namespace PluginSearchOption

/// Options for controlling search path behavior.
class SearchPathOptions {
/// To call \c addImportSearchPath and \c addFrameworkSearchPath from
@@ -259,14 +279,6 @@ class SearchPathOptions {
ImportSearchPaths.size() - 1);
}

void addCompilerPluginLibraryPath(StringRef Path, llvm::vfs::FileSystem *FS) {
CompilerPluginLibraryPaths.push_back(Path.str());
Lookup.searchPathAdded(FS, CompilerPluginLibraryPaths.back(),
ModuleSearchPathKind::CompilerPlugin,
/*isSystem=*/false,
CompilerPluginLibraryPaths.size() - 1);
}

/// Add a single framework search path. Must only be called from
/// \c ASTContext::addSearchPath.
void addFrameworkSearchPath(FrameworkSearchPath NewPath,
@@ -355,27 +367,6 @@ class SearchPathOptions {
Lookup.searchPathsDidChange();
}

void setCompilerPluginLibraryPaths(
std::vector<std::string> NewCompilerPluginLibraryPaths) {
CompilerPluginLibraryPaths = NewCompilerPluginLibraryPaths;
Lookup.searchPathsDidChange();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Plugin search doesn't use Lookup, and adding plugin search path won't affect import module search path. So we don't need to call Lookup.searchPathsDidChange() when updating PluginSearchOpts.

}

ArrayRef<std::string> getCompilerPluginLibraryPaths() const {
return CompilerPluginLibraryPaths;
}

void setCompilerPluginExecutablePaths(
std::vector<PluginExecutablePathAndModuleNames> &&newValue) {
CompilerPluginExecutablePaths = std::move(newValue);
Lookup.searchPathsDidChange();
}

ArrayRef<PluginExecutablePathAndModuleNames>
getCompilerPluginExecutablePaths() const {
return CompilerPluginExecutablePaths;
}

/// Path(s) to virtual filesystem overlay YAML files.
std::vector<std::string> VFSOverlayFiles;

@@ -391,15 +382,8 @@ class SearchPathOptions {
/// preference.
std::vector<std::string> RuntimeLibraryPaths;

/// Paths that contain compiler plugins loaded on demand for, e.g.,
/// macro implementations.
std::vector<std::string> PluginSearchPaths;

/// Pairs of external compiler plugin search paths and the corresponding
/// plugin server executables.
/// e.g. {"/path/to/usr/lib/swift/host/plugins",
/// "/path/to/usr/bin/plugin-server"}
std::vector<ExternalPluginSearchPathAndServerPath> ExternalPluginSearchPaths;
/// Plugin search path options.
std::vector<PluginSearchOption::Value> PluginSearchOpts;

/// Don't look in for compiler-provided modules.
bool SkipRuntimeLibraryImportPaths = false;
8 changes: 0 additions & 8 deletions include/swift/Frontend/Frontend.h
Original file line number Diff line number Diff line change
@@ -198,14 +198,6 @@ class CompilerInvocation {
SearchPathOpts.VFSOverlayFiles = Overlays;
}

void setCompilerPluginLibraryPaths(const std::vector<std::string> &Paths) {
SearchPathOpts.setCompilerPluginLibraryPaths(Paths);
}

ArrayRef<std::string> getCompilerPluginLibraryPaths() {
return SearchPathOpts.getCompilerPluginLibraryPaths();
}

void setExtraClangArgs(const std::vector<std::string> &Args) {
ClangImporterOpts.ExtraArgs = Args;
}
25 changes: 14 additions & 11 deletions include/swift/Option/Options.td
Original file line number Diff line number Diff line change
@@ -304,15 +304,6 @@ def I : JoinedOrSeparate<["-"], "I">,
def I_EQ : Joined<["-"], "I=">, Flags<[FrontendOption, ArgumentIsPath]>,
Alias<I>;

def plugin_path : Separate<["-"], "plugin-path">,
Flags<[FrontendOption, ArgumentIsPath, SwiftAPIExtractOption, SwiftSymbolGraphExtractOption, SwiftAPIDigesterOption]>,
HelpText<"Add directory to the plugin search path">;

def external_plugin_path : Separate<["-"], "external-plugin-path">,
Flags<[FrontendOption, ArgumentIsPath, SwiftAPIExtractOption, SwiftSymbolGraphExtractOption, SwiftAPIDigesterOption]>,
HelpText<"Add directory to the plugin search path with a plugin server executable">,
MetaVarName<"<path>#<plugin-server-path>">;

def import_underlying_module : Flag<["-"], "import-underlying-module">,
Flags<[FrontendOption, NoInteractiveOption]>,
HelpText<"Implicitly imports the Objective-C half of a module">;
@@ -1852,15 +1843,27 @@ def clang_include_tree_root: Separate<["-"], "clang-include-tree-root">,
Flags<[FrontendOption, NoDriverOption]>,
HelpText<"Clang Include Tree CASID">, MetaVarName<"<cas-id>">;


def plugin_search_Group : OptionGroup<"<plugin search options>">;

def plugin_path : Separate<["-"], "plugin-path">, Group<plugin_search_Group>,
Flags<[FrontendOption, ArgumentIsPath, SwiftAPIExtractOption, SwiftSymbolGraphExtractOption, SwiftAPIDigesterOption]>,
HelpText<"Add directory to the plugin search path">;

def external_plugin_path : Separate<["-"], "external-plugin-path">, Group<plugin_search_Group>,
Flags<[FrontendOption, ArgumentIsPath, SwiftAPIExtractOption, SwiftSymbolGraphExtractOption, SwiftAPIDigesterOption]>,
HelpText<"Add directory to the plugin search path with a plugin server executable">,
MetaVarName<"<path>#<plugin-server-path>">;

def load_plugin_library:
Separate<["-"], "load-plugin-library">,
Separate<["-"], "load-plugin-library">, Group<plugin_search_Group>,
Flags<[FrontendOption, DoesNotAffectIncrementalBuild, ArgumentIsPath]>,
HelpText<"Path to a dynamic library containing compiler plugins such as "
"macros">,
MetaVarName<"<path>">;

def load_plugin_executable:
Separate<["-"], "load-plugin-executable">,
Separate<["-"], "load-plugin-executable">, Group<plugin_search_Group>,
Flags<[FrontendOption, DoesNotAffectIncrementalBuild, ArgumentIsPath]>,
HelpText<"Path to an executable compiler plugins and providing module names "
"such as macros">,
11 changes: 4 additions & 7 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
@@ -103,11 +103,10 @@ llvm::StringRef swift::getProtocolName(KnownProtocolKind kind) {
}

namespace {
enum class SearchPathKind : uint8_t {
Import = 1 << 0,
Framework = 1 << 1,
CompilerPlugin = 1 << 2
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto: SearchPathKind::CompilerPlugin wasn't actually used.

};
enum class SearchPathKind : uint8_t {
Import = 1 << 0,
Framework = 1 << 1,
};
} // end anonymous namespace

using AssociativityCacheType =
@@ -694,8 +693,6 @@ ASTContext::ASTContext(
getImpl().SearchPathsSet[path] |= SearchPathKind::Import;
for (const auto &framepath : SearchPathOpts.getFrameworkSearchPaths())
getImpl().SearchPathsSet[framepath.Path] |= SearchPathKind::Framework;
for (StringRef path : SearchPathOpts.getCompilerPluginLibraryPaths())
getImpl().SearchPathsSet[path] |= SearchPathKind::CompilerPlugin;

// Register any request-evaluator functions available at the AST layer.
registerAccessRequestFunctions(evaluator);
112 changes: 52 additions & 60 deletions lib/AST/PluginLoader.cpp
Original file line number Diff line number Diff line change
@@ -20,12 +20,14 @@
using namespace swift;

void PluginLoader::createModuleToExecutablePluginMap() {
for (auto &arg : Ctx.SearchPathOpts.getCompilerPluginExecutablePaths()) {
// Create a moduleName -> pluginPath mapping.
assert(!arg.ExecutablePath.empty() && "empty plugin path");
StringRef pathStr = Ctx.AllocateCopy(arg.ExecutablePath);
for (auto moduleName : arg.ModuleNames) {
ExecutablePluginPaths[Ctx.getIdentifier(moduleName)] = pathStr;
for (auto &elem : Ctx.SearchPathOpts.PluginSearchOpts) {
if (auto *arg = elem.dyn_cast<PluginSearchOption::LoadPluginExecutable>()) {
// Create a moduleName -> pluginPath mapping.
assert(!arg->ExecutablePath.empty() && "empty plugin path");
StringRef pathStr = Ctx.AllocateCopy(arg->ExecutablePath);
for (auto moduleName : arg->ModuleNames) {
ExecutablePluginPaths[Ctx.getIdentifier(moduleName)] = pathStr;
}
}
}
}
@@ -46,69 +48,59 @@ PluginRegistry *PluginLoader::getRegistry() {
return Registry;
}

llvm::Optional<std::string>
PluginLoader::lookupExplicitLibraryPluginByModuleName(Identifier moduleName) {
// Look for 'lib${module name}(.dylib|.so)'.
SmallString<64> expectedBasename;
expectedBasename.append("lib");
expectedBasename.append(moduleName.str());
expectedBasename.append(LTDL_SHLIB_EXT);

// Try '-load-plugin-library'.
for (const auto &libPath :
Ctx.SearchPathOpts.getCompilerPluginLibraryPaths()) {
if (llvm::sys::path::filename(libPath) == expectedBasename) {
return libPath;
}
}
return None;
}
std::pair<std::string, std::string>
PluginLoader::lookupPluginByModuleName(Identifier moduleName) {
auto fs = Ctx.SourceMgr.getFileSystem();

llvm::Optional<std::string>
PluginLoader::lookupLibraryPluginInSearchPathByModuleName(
Identifier moduleName) {
// Look for 'lib${module name}(.dylib|.so)'.
SmallString<64> expectedBasename;
expectedBasename.append("lib");
expectedBasename.append(moduleName.str());
expectedBasename.append(LTDL_SHLIB_EXT);

// Try '-plugin-path'.
auto fs = Ctx.SourceMgr.getFileSystem();
for (const auto &searchPath : Ctx.SearchPathOpts.PluginSearchPaths) {
SmallString<128> fullPath(searchPath);
llvm::sys::path::append(fullPath, expectedBasename);
if (fs->exists(fullPath)) {
return std::string(fullPath);
// FIXME: Shared library prefix might be different between platforms.
SmallString<64> pluginLibBasename;
pluginLibBasename.append("lib");
pluginLibBasename.append(moduleName.str());
pluginLibBasename.append(LTDL_SHLIB_EXT);

// FIXME: Should we create a lookup table keyed by module name?
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently we create a lookup table for -load-plugin-executable only. But we could lazily create a lookup table for all keyed by module names. But that's need to scan (iterate directory entries) all search paths, so I'm not sure it worth it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's probably better to do the one scan rather than the continual exists checks, but not doing that in this PR is fine IMO.

for (auto &entry : Ctx.SearchPathOpts.PluginSearchOpts) {
using namespace PluginSearchOption;
// Try '-load-plugin-library'.
if (auto *val = entry.dyn_cast<LoadPluginLibrary>()) {
if (llvm::sys::path::filename(val->LibraryPath) == pluginLibBasename) {
return {val->LibraryPath, ""};
}
continue;
}
}

return None;
}

Optional<std::pair<std::string, std::string>>
PluginLoader::lookupExternalLibraryPluginByModuleName(Identifier moduleName) {
auto fs = Ctx.SourceMgr.getFileSystem();
// Try '-load-plugin-executable'.
if (auto *v = entry.dyn_cast<LoadPluginExecutable>()) {
auto found = ExecutablePluginPaths.find(moduleName);
if (found != ExecutablePluginPaths.end()) {
return {"", std::string(found->second)};
}
continue;
}

for (auto &pair : Ctx.SearchPathOpts.ExternalPluginSearchPaths) {
SmallString<128> fullPath(pair.SearchPath);
llvm::sys::path::append(fullPath,
"lib" + moduleName.str() + LTDL_SHLIB_EXT);
// Try '-plugin-path'.
if (auto *v = entry.dyn_cast<PluginPath>()) {
SmallString<128> fullPath(v->SearchPath);
llvm::sys::path::append(fullPath, pluginLibBasename);
if (fs->exists(fullPath)) {
return {std::string(fullPath), ""};
}
continue;
}

if (fs->exists(fullPath)) {
return {{std::string(fullPath), pair.ServerPath}};
// Try '-external-plugin-path'.
if (auto *v = entry.dyn_cast<ExternalPluginPath>()) {
SmallString<128> fullPath(v->SearchPath);
llvm::sys::path::append(fullPath, pluginLibBasename);
if (fs->exists(fullPath)) {
return {std::string(fullPath), v->ServerPath};
}
continue;
}
}
return None;
}

Optional<StringRef>
PluginLoader::lookupExecutablePluginByModuleName(Identifier moduleName) {
auto &execPluginPaths = ExecutablePluginPaths;
auto found = execPluginPaths.find(moduleName);
if (found == execPluginPaths.end())
return None;
return found->second;
return {};
}

LoadedLibraryPlugin *PluginLoader::loadLibraryPlugin(StringRef path) {
6 changes: 0 additions & 6 deletions lib/AST/SearchPathOptions.cpp
Original file line number Diff line number Diff line change
@@ -73,12 +73,6 @@ void ModuleSearchPathLookup::rebuildLookupTable(const SearchPathOptions *Opts,
/*isSystem=*/true, Entry.index());
}

for (auto Entry : llvm::enumerate(Opts->getCompilerPluginLibraryPaths())) {
addFilesInPathToLookupTable(FS, Entry.value(),
ModuleSearchPathKind::CompilerPlugin,
/*isSystem=*/false, Entry.index());
}

State.FileSystem = FS;
State.IsOSDarwin = IsOSDarwin;
State.Opts = Opts;
Loading