Skip to content

Commit 3a55c3c

Browse files
committed
Front-end: teach the compiler to generate a .c file for $ld$add$os symbols.
When symbols are moved to this module, this module declares them as HIDE for the OS versions prior to when the move happened. On the other hand, the original module should declare ADD them for these OS versions. An executable can choose the right library to link against depending on the deployment target. This is a walk-around that linker directives cannot specify other install name per symbol, we should eventually remove this.
1 parent 66b4737 commit 3a55c3c

File tree

7 files changed

+93
-4
lines changed

7 files changed

+93
-4
lines changed

include/swift/Basic/SupplementaryOutputPaths.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,16 @@ struct SupplementaryOutputPaths {
149149
/// \sa swift::emitSwiftInterface
150150
std::string ModuleInterfaceOutputPath;
151151

152+
/// The path to a .c file where we should declare $ld$add symbols for those
153+
/// symbols moved to the current module.
154+
/// When symbols are moved to this module, this module declares them as HIDE
155+
/// for the OS versions prior to when the move happened. On the other hand, the
156+
/// original module should ADD them for these OS versions. An executable
157+
/// can choose the right library to link against depending on the deployment target.
158+
/// This is a walk-around that linker directives cannot specify other install
159+
/// name per symbol, we should eventually remove this.
160+
std::string LdAddCFilePath;
161+
152162
SupplementaryOutputPaths() = default;
153163
SupplementaryOutputPaths(const SupplementaryOutputPaths &) = default;
154164

@@ -158,7 +168,7 @@ struct SupplementaryOutputPaths {
158168
ReferenceDependenciesFilePath.empty() &&
159169
SerializedDiagnosticsPath.empty() && LoadedModuleTracePath.empty() &&
160170
TBDPath.empty() && ModuleInterfaceOutputPath.empty() &&
161-
ModuleSourceInfoOutputPath.empty();
171+
ModuleSourceInfoOutputPath.empty() && LdAddCFilePath.empty();
162172
}
163173
};
164174
} // namespace swift

include/swift/Frontend/Frontend.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,8 @@ class CompilerInvocation {
385385
/// fail an assert if not in that mode.
386386
std::string getModuleInterfaceOutputPathForWholeModule() const;
387387

388+
std::string getLdAddCFileOutputPathForWholeModule() const;
389+
388390
SerializationOptions
389391
computeSerializationOptions(const SupplementaryOutputPaths &outs,
390392
bool moduleIsPublic);

include/swift/Option/FrontendOptions.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,4 +640,7 @@ def type_info_dump_filter_EQ : Joined<["-"], "type-info-dump-filter=">,
640640
Flags<[FrontendOption]>,
641641
HelpText<"One of 'all', 'resilient' or 'fragile'">;
642642

643+
def emit_ldadd_cfile_path
644+
: Separate<["-"], "emit-ldadd-cfile-path">, MetaVarName<"<path>">,
645+
HelpText<"Generate .c file defining symbols to add back">;
643646
} // end let Flags = [FrontendOption, NoDriverOption, HelpHidden]

lib/Frontend/ArgsToFrontendOutputsConverter.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -302,11 +302,12 @@ SupplementaryOutputPathsComputer::getSupplementaryOutputPathsFromArguments()
302302
options::OPT_emit_module_interface_path);
303303
auto moduleSourceInfoOutput = getSupplementaryFilenamesFromArguments(
304304
options::OPT_emit_module_source_info_path);
305-
305+
auto ldAddCFileOutput = getSupplementaryFilenamesFromArguments(
306+
options::OPT_emit_ldadd_cfile_path);
306307
if (!objCHeaderOutput || !moduleOutput || !moduleDocOutput ||
307308
!dependenciesFile || !referenceDependenciesFile ||
308309
!serializedDiagnostics || !fixItsOutput || !loadedModuleTrace || !TBD ||
309-
!moduleInterfaceOutput || !moduleSourceInfoOutput) {
310+
!moduleInterfaceOutput || !moduleSourceInfoOutput || !ldAddCFileOutput) {
310311
return None;
311312
}
312313
std::vector<SupplementaryOutputPaths> result;
@@ -328,6 +329,7 @@ SupplementaryOutputPathsComputer::getSupplementaryOutputPathsFromArguments()
328329
sop.TBDPath = (*TBD)[i];
329330
sop.ModuleInterfaceOutputPath = (*moduleInterfaceOutput)[i];
330331
sop.ModuleSourceInfoOutputPath = (*moduleSourceInfoOutput)[i];
332+
sop.LdAddCFilePath = (*ldAddCFileOutput)[i];
331333
result.push_back(sop);
332334
}
333335
return result;
@@ -446,6 +448,7 @@ SupplementaryOutputPathsComputer::computeOutputPathsForOneInput(
446448
sop.TBDPath = tbdPath;
447449
sop.ModuleInterfaceOutputPath = ModuleInterfaceOutputPath;
448450
sop.ModuleSourceInfoOutputPath = moduleSourceInfoOutputPath;
451+
sop.LdAddCFilePath = pathsFromArguments.LdAddCFilePath;
449452
return sop;
450453
}
451454

@@ -546,7 +549,8 @@ SupplementaryOutputPathsComputer::readSupplementaryOutputFileMap() const {
546549
options::OPT_emit_loaded_module_trace_path,
547550
options::OPT_emit_module_interface_path,
548551
options::OPT_emit_module_source_info_path,
549-
options::OPT_emit_tbd_path)) {
552+
options::OPT_emit_tbd_path,
553+
options::OPT_emit_ldadd_cfile_path)) {
550554
Diags.diagnose(SourceLoc(),
551555
diag::error_cannot_have_supplementary_outputs,
552556
A->getSpelling(), "-supplementary-output-file-map");

lib/Frontend/Frontend.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,14 @@ std::string CompilerInvocation::getTBDPathForWholeModule() const {
124124
.SupplementaryOutputs.TBDPath;
125125
}
126126

127+
std::string
128+
CompilerInvocation::getLdAddCFileOutputPathForWholeModule() const {
129+
assert(getFrontendOptions().InputsAndOutputs.isWholeModule() &&
130+
"LdAdd cfile only makes sense when the whole module can be seen");
131+
return getPrimarySpecificPathsForAtMostOnePrimary()
132+
.SupplementaryOutputs.LdAddCFilePath;
133+
}
134+
127135
std::string
128136
CompilerInvocation::getModuleInterfaceOutputPathForWholeModule() const {
129137
assert(getFrontendOptions().InputsAndOutputs.isWholeModule() &&

lib/FrontendTool/FrontendTool.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,6 +1047,59 @@ static bool writeTBDIfNeeded(CompilerInvocation &Invocation,
10471047
return writeTBD(Instance.getMainModule(), TBDPath, tbdOpts);
10481048
}
10491049

1050+
static std::string changeToLdAdd(StringRef ldHide) {
1051+
SmallString<64> SymbolBuffer;
1052+
llvm::raw_svector_ostream OS(SymbolBuffer);
1053+
auto Parts = ldHide.split("$hide$");
1054+
assert(!Parts.first.empty());
1055+
assert(!Parts.second.empty());
1056+
OS << Parts.first << "$add$" << Parts.second;
1057+
return OS.str().str();
1058+
}
1059+
1060+
static bool writeLdAddCFileIfNeeded(CompilerInvocation &Invocation,
1061+
CompilerInstance &Instance) {
1062+
auto frontendOpts = Invocation.getFrontendOptions();
1063+
if (!frontendOpts.InputsAndOutputs.isWholeModule())
1064+
return false;
1065+
auto Path = Invocation.getLdAddCFileOutputPathForWholeModule();
1066+
if (Path.empty())
1067+
return false;
1068+
if (!frontendOpts.InputsAndOutputs.isWholeModule()) {
1069+
Instance.getDiags().diagnose(SourceLoc(),
1070+
diag::tbd_only_supported_in_whole_module);
1071+
return true;
1072+
}
1073+
auto tbdOpts = Invocation.getTBDGenOptions();
1074+
tbdOpts.LinkerDirectivesOnly = true;
1075+
llvm::StringSet<> ldSymbols;
1076+
auto *module = Instance.getMainModule();
1077+
enumeratePublicSymbols(module, ldSymbols, tbdOpts);
1078+
std::error_code EC;
1079+
llvm::raw_fd_ostream OS(Path, EC, llvm::sys::fs::F_None);
1080+
if (EC) {
1081+
module->getASTContext().Diags.diagnose(SourceLoc(),
1082+
diag::error_opening_output,
1083+
Path, EC.message());
1084+
return true;
1085+
}
1086+
OS << "// Automatically generated C source file from the Swift compiler \n"
1087+
<< "// to add removed symbols back to the high-level framework for deployment\n"
1088+
<< "// targets prior to the OS version when these symbols were moved to\n"
1089+
<< "// a low-level framework " << module->getName().str() << ".\n\n";
1090+
unsigned Idx = 0;
1091+
for (auto &S: ldSymbols) {
1092+
SmallString<32> NameBuffer;
1093+
llvm::raw_svector_ostream NameOS(NameBuffer);
1094+
NameOS << "ldAdd_" << Idx;
1095+
OS << "extern const char " << NameOS.str() << " __asm(\"" <<
1096+
changeToLdAdd(S.getKey()) << "\");\n";
1097+
OS << "const char " << NameOS.str() << " = 0;\n";
1098+
++ Idx;
1099+
}
1100+
return false;
1101+
}
1102+
10501103
static bool performCompileStepsPostSILGen(
10511104
CompilerInstance &Instance, CompilerInvocation &Invocation,
10521105
std::unique_ptr<SILModule> SM, bool astGuaranteedToCorrespondToSIL,
@@ -1172,6 +1225,9 @@ static bool emitAnyWholeModulePostTypeCheckSupplementaryOutputs(
11721225
{
11731226
hadAnyError |= writeTBDIfNeeded(Invocation, Instance);
11741227
}
1228+
{
1229+
hadAnyError |= writeLdAddCFileIfNeeded(Invocation, Instance);
1230+
}
11751231

11761232
return hadAnyError;
11771233
}

test/TBD/linker-directives.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,9 @@ public func toast() {}
1515

1616
// CHECK-HAS-NOT-NOT: $ld$hide$os10.15$_$s10ToasterKit5toastyyF
1717
// CHECK-HAS-NOT-NOT: $ld$hide$os10.7$_$s10ToasterKit5toastyyF
18+
19+
// RUN: %target-swift-frontend -typecheck %s -emit-tbd -emit-tbd-path %t/linker_directives.tbd -emit-ldadd-cfile-path %t/ldAdd.c -module-name AppKit
20+
// RUN: %FileCheck %s --check-prefix CHECK-C-SYMBOL < %t/ldAdd.c
21+
22+
// CHECK-C-SYMBOL: $ld$add$os10.14$_$s10ToasterKit5toastyyF
23+
// CHECK-C-SYMBOL: $ld$add$os10.8$_$s10ToasterKit5toastyyF

0 commit comments

Comments
 (0)