Skip to content

Commit 47b3efd

Browse files
[Macro] Add a new macro loading option that do not involve searching
Add flag `-load-resolved-plugin` to load macro plugin, which provides a pre-resolved entry into PluginLoader so the plugins can be loaded based on module name without searching the file system. The option is mainly intended to be used by explicitly module build and the flag is supplied by dependency scanner.
1 parent 56ec625 commit 47b3efd

File tree

11 files changed

+112
-8
lines changed

11 files changed

+112
-8
lines changed

include/swift/AST/DiagnosticsFrontend.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,9 @@ ERROR(error_no_source_location_scope_map,none,
127127
ERROR(error_load_plugin_executable,none,
128128
"invalid value '%0' in '-load-plugin-executable'; "
129129
"make sure to use format '<plugin path>#<module names>'", (StringRef))
130+
ERROR(error_load_resolved_plugin,none,
131+
"invalid value '%0' in '-load-resolved-plugin'; "
132+
"make sure to use format '<library path>#<plugin path>#<module names>' where library and plugin path can't both be empty", (StringRef))
130133

131134
NOTE(note_valid_swift_versions, none,
132135
"valid arguments to '-swift-version' are %0", (StringRef))

include/swift/AST/SearchPathOptions.h

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,17 +214,24 @@ class PluginSearchOption {
214214
std::string SearchPath;
215215
std::string ServerPath;
216216
};
217+
struct ResolvedPluginConfig {
218+
std::string LibraryPath;
219+
std::string ExecutablePath;
220+
std::vector<std::string> ModuleNames;
221+
};
217222

218223
enum class Kind : uint8_t {
219224
LoadPluginLibrary,
220225
LoadPluginExecutable,
221226
PluginPath,
222227
ExternalPluginPath,
228+
ResolvedPluginConfig,
223229
};
224230

225231
private:
226-
using Members = ExternalUnionMembers<LoadPluginLibrary, LoadPluginExecutable,
227-
PluginPath, ExternalPluginPath>;
232+
using Members =
233+
ExternalUnionMembers<LoadPluginLibrary, LoadPluginExecutable, PluginPath,
234+
ExternalPluginPath, ResolvedPluginConfig>;
228235
static Members::Index getIndexForKind(Kind kind) {
229236
switch (kind) {
230237
case Kind::LoadPluginLibrary:
@@ -235,6 +242,8 @@ class PluginSearchOption {
235242
return Members::indexOf<PluginPath>();
236243
case Kind::ExternalPluginPath:
237244
return Members::indexOf<ExternalPluginPath>();
245+
case Kind::ResolvedPluginConfig:
246+
return Members::indexOf<ResolvedPluginConfig>();
238247
}
239248
};
240249
using Storage = ExternalUnion<Kind, Members, getIndexForKind>;
@@ -258,6 +267,10 @@ class PluginSearchOption {
258267
: kind(Kind::ExternalPluginPath) {
259268
storage.emplace<ExternalPluginPath>(kind, v);
260269
}
270+
PluginSearchOption(const ResolvedPluginConfig &v)
271+
: kind(Kind::ResolvedPluginConfig) {
272+
storage.emplace<ResolvedPluginConfig>(kind, v);
273+
}
261274
PluginSearchOption(const PluginSearchOption &o) : kind(o.kind) {
262275
storage.copyConstruct(o.kind, o.storage);
263276
}

include/swift/Option/Options.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2095,6 +2095,14 @@ def load_plugin_executable:
20952095
"of module names where the macro types are declared">,
20962096
MetaVarName<"<path>#<module-names>">;
20972097

2098+
def load_resolved_plugin:
2099+
Separate<["-"], "load-resolved-plugin">, Group<plugin_search_Group>,
2100+
Flags<[FrontendOption, DoesNotAffectIncrementalBuild, ArgumentIsPath]>,
2101+
HelpText<"Path to resolved plugin configuration and a comma-separated list "
2102+
"of module names where the macro types are declared. Library path "
2103+
"and exectuable path can be empty if not used">,
2104+
MetaVarName<"<library-path>#<executable-path>#<module-names>">;
2105+
20982106
def in_process_plugin_server_path : Separate<["-"], "in-process-plugin-server-path">,
20992107
Flags<[FrontendOption, ArgumentIsPath]>,
21002108
HelpText<"Path to dynamic library plugin server">;

lib/AST/PluginLoader.cpp

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,18 +83,17 @@ PluginLoader::getPluginMap() {
8383
// Helper function to try inserting an entry if there's no existing entry
8484
// associated with the module name.
8585
auto try_emplace = [&](StringRef moduleName, StringRef libPath,
86-
StringRef execPath) {
86+
StringRef execPath, bool overwrite = false) {
8787
auto moduleNameIdentifier = Ctx.getIdentifier(moduleName);
88-
if (map.find(moduleNameIdentifier) != map.end()) {
89-
// Specified module name is already in the map.
88+
if (map.find(moduleNameIdentifier) != map.end() && !overwrite) {
89+
// Specified module name is already in the map and no need to overwrite
90+
// the current value.
9091
return;
9192
}
9293

9394
libPath = libPath.empty() ? "" : Ctx.AllocateCopy(libPath);
9495
execPath = execPath.empty() ? "" : Ctx.AllocateCopy(execPath);
95-
auto result = map.insert({moduleNameIdentifier, {libPath, execPath}});
96-
assert(result.second);
97-
(void)result;
96+
map[moduleNameIdentifier] = {libPath, execPath};
9897
};
9998

10099
auto fs = getPluginLoadingFS(Ctx);
@@ -150,6 +149,18 @@ PluginLoader::getPluginMap() {
150149
}
151150
continue;
152151
}
152+
153+
// '-load-resolved-plugin <library path>#<server path>#<module name>,...'.
154+
case PluginSearchOption::Kind::ResolvedPluginConfig: {
155+
auto &val = entry.get<PluginSearchOption::ResolvedPluginConfig>();
156+
// Respect resolved plugin config above other search path, and it can
157+
// overwrite plugins found by other options or previous resolved
158+
// configuration.
159+
for (auto &moduleName : val.ModuleNames)
160+
try_emplace(moduleName, val.LibraryPath, val.ExecutablePath,
161+
/*overwrite*/ true);
162+
continue;
163+
}
153164
}
154165
llvm_unreachable("unhandled PluginSearchOption::Kind");
155166
}

lib/Frontend/CompilerInvocation.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2169,6 +2169,27 @@ static bool ParseSearchPathArgs(SearchPathOptions &Opts, ArgList &Args,
21692169
resolveSearchPath(dylibPath), resolveSearchPath(serverPath)});
21702170
break;
21712171
}
2172+
case OPT_load_resolved_plugin: {
2173+
StringRef libraryPath;
2174+
StringRef executablePath;
2175+
StringRef modulesStr;
2176+
std::tie(libraryPath, executablePath) =
2177+
StringRef(A->getValue()).split('#');
2178+
std::tie(executablePath, modulesStr) = executablePath.split('#');
2179+
if (modulesStr.empty() ||
2180+
(libraryPath.empty() && executablePath.empty())) {
2181+
Diags.diagnose(SourceLoc(), diag::error_load_resolved_plugin,
2182+
A->getValue());
2183+
}
2184+
std::vector<std::string> moduleNames;
2185+
for (auto name : llvm::split(modulesStr, ',')) {
2186+
moduleNames.emplace_back(name);
2187+
}
2188+
Opts.PluginSearchOpts.emplace_back(
2189+
PluginSearchOption::ResolvedPluginConfig{
2190+
libraryPath.str(), executablePath.str(), std::move(moduleNames)});
2191+
break;
2192+
}
21722193
default:
21732194
llvm_unreachable("unhandled plugin search option");
21742195
}

lib/Frontend/ModuleInterfaceLoader.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1753,6 +1753,15 @@ void InterfaceSubContextDelegateImpl::inheritOptionsForBuildingInterface(
17531753
ArgSaver.save(val.SearchPath + "#" + val.ServerPath));
17541754
break;
17551755
}
1756+
case PluginSearchOption::Kind::ResolvedPluginConfig: {
1757+
auto &val = entry.get<PluginSearchOption::ResolvedPluginConfig>();
1758+
for (auto &moduleName : val.ModuleNames) {
1759+
GenericArgs.push_back("-load-plugin-executable");
1760+
GenericArgs.push_back(ArgSaver.save(
1761+
val.LibraryPath + "#" + val.ExecutablePath + "#" + moduleName));
1762+
}
1763+
break;
1764+
}
17561765
}
17571766
}
17581767

lib/Serialization/ModuleFileSharedCore.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,9 @@ static bool readOptionsBlock(llvm::BitstreamCursor &cursor,
148148
case PluginSearchOptionKind::LoadPluginExecutable:
149149
optKind = PluginSearchOption::Kind::LoadPluginExecutable;
150150
break;
151+
case PluginSearchOptionKind::ResolvedPluginConfig:
152+
optKind = PluginSearchOption::Kind::ResolvedPluginConfig;
153+
break;
151154
}
152155
extendedInfo.addPluginSearchOption({optKind, blobData});
153156
break;

lib/Serialization/ModuleFormat.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,7 @@ enum class PluginSearchOptionKind : uint8_t {
694694
ExternalPluginPath,
695695
LoadPluginLibrary,
696696
LoadPluginExecutable,
697+
ResolvedPluginConfig,
697698
};
698699
using PluginSearchOptionKindField = BCFixed<3>;
699700

lib/Serialization/Serialization.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,6 +1245,18 @@ void Serializer::writeHeader() {
12451245
uint8_t(PluginSearchOptionKind::LoadPluginExecutable), optStr);
12461246
continue;
12471247
}
1248+
case PluginSearchOption::Kind::ResolvedPluginConfig: {
1249+
auto &opt = elem.get<PluginSearchOption::ResolvedPluginConfig>();
1250+
std::string optStr =
1251+
opt.LibraryPath + "#" + opt.ExecutablePath + "#";
1252+
llvm::interleave(
1253+
opt.ModuleNames, [&](auto &name) { optStr += name; },
1254+
[&]() { optStr += ","; });
1255+
PluginSearchOpt.emit(
1256+
ScratchRecord,
1257+
uint8_t(PluginSearchOptionKind::ResolvedPluginConfig), optStr);
1258+
continue;
1259+
}
12481260
}
12491261
}
12501262
}

test/Macros/macro_plugin_server.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,26 @@
3131

3232
// RUN: %FileCheck -strict-whitespace %s < %t/macro-expansions.txt
3333

34+
/// Create file with matching name in alt directories and test
35+
/// `-load-resolved-plugin` takes the priority over other options.
36+
// RUN: %empty-directory(%t/alt)
37+
// RUN: touch %t/alt/%target-library-name(MacroDefinition)
38+
39+
// RUN: env SWIFT_DUMP_PLUGIN_MESSAGING=1 %target-swift-frontend \
40+
// RUN: -typecheck -verify \
41+
// RUN: -swift-version 5 -enable-experimental-feature Macros \
42+
// RUN: -external-plugin-path %t/alt#%swift-plugin-server \
43+
// RUN: -load-resolved-plugin lib-do-not-exist.dylib##MacroDefinition \
44+
// RUN: -load-resolved-plugin %t/plugins/%target-library-name(MacroDefinition)#%swift-plugin-server#MacroDefinition \
45+
// RUN: -load-resolved-plugin %t/plugins/%target-library-name(EvilMacros)#%swift-plugin-server#EvilMacros \
46+
// RUN: -external-plugin-path %t/alt#%swift-plugin-server \
47+
// RUN: -Rmacro-loading -verify-ignore-unknown \
48+
// RUN: -module-name MyApp \
49+
// RUN: %s \
50+
// RUN: 2>&1 | tee %t/macro-expansions-2.txt
51+
52+
// RUN: %FileCheck -strict-whitespace %s < %t/macro-expansions-2.txt
53+
3454
// RUN: not %target-swift-frontend \
3555
// RUN: -typecheck \
3656
// RUN: -swift-version 5 \

0 commit comments

Comments
 (0)