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.
This commit is contained in:
Xi Ge
2019-12-13 16:07:03 -08:00
parent 66b4737ddc
commit 3a55c3c96e
7 changed files with 93 additions and 4 deletions

View File

@@ -1047,6 +1047,59 @@ static bool writeTBDIfNeeded(CompilerInvocation &Invocation,
return writeTBD(Instance.getMainModule(), TBDPath, tbdOpts);
}
static std::string changeToLdAdd(StringRef ldHide) {
SmallString<64> SymbolBuffer;
llvm::raw_svector_ostream OS(SymbolBuffer);
auto Parts = ldHide.split("$hide$");
assert(!Parts.first.empty());
assert(!Parts.second.empty());
OS << Parts.first << "$add$" << Parts.second;
return OS.str().str();
}
static bool writeLdAddCFileIfNeeded(CompilerInvocation &Invocation,
CompilerInstance &Instance) {
auto frontendOpts = Invocation.getFrontendOptions();
if (!frontendOpts.InputsAndOutputs.isWholeModule())
return false;
auto Path = Invocation.getLdAddCFileOutputPathForWholeModule();
if (Path.empty())
return false;
if (!frontendOpts.InputsAndOutputs.isWholeModule()) {
Instance.getDiags().diagnose(SourceLoc(),
diag::tbd_only_supported_in_whole_module);
return true;
}
auto tbdOpts = Invocation.getTBDGenOptions();
tbdOpts.LinkerDirectivesOnly = true;
llvm::StringSet<> ldSymbols;
auto *module = Instance.getMainModule();
enumeratePublicSymbols(module, ldSymbols, tbdOpts);
std::error_code EC;
llvm::raw_fd_ostream OS(Path, EC, llvm::sys::fs::F_None);
if (EC) {
module->getASTContext().Diags.diagnose(SourceLoc(),
diag::error_opening_output,
Path, EC.message());
return true;
}
OS << "// Automatically generated C source file from the Swift compiler \n"
<< "// to add removed symbols back to the high-level framework for deployment\n"
<< "// targets prior to the OS version when these symbols were moved to\n"
<< "// a low-level framework " << module->getName().str() << ".\n\n";
unsigned Idx = 0;
for (auto &S: ldSymbols) {
SmallString<32> NameBuffer;
llvm::raw_svector_ostream NameOS(NameBuffer);
NameOS << "ldAdd_" << Idx;
OS << "extern const char " << NameOS.str() << " __asm(\"" <<
changeToLdAdd(S.getKey()) << "\");\n";
OS << "const char " << NameOS.str() << " = 0;\n";
++ Idx;
}
return false;
}
static bool performCompileStepsPostSILGen(
CompilerInstance &Instance, CompilerInvocation &Invocation,
std::unique_ptr<SILModule> SM, bool astGuaranteedToCorrespondToSIL,
@@ -1172,6 +1225,9 @@ static bool emitAnyWholeModulePostTypeCheckSupplementaryOutputs(
{
hadAnyError |= writeTBDIfNeeded(Invocation, Instance);
}
{
hadAnyError |= writeLdAddCFileIfNeeded(Invocation, Instance);
}
return hadAnyError;
}