Skip to content

Build CompatibilitySpan shim #79703

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 6 commits into from
Mar 25, 2025
Merged
Show file tree
Hide file tree
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
26 changes: 20 additions & 6 deletions include/swift/AST/Attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -2050,17 +2050,29 @@ class ProjectedValuePropertyAttr : public DeclAttribute {
class OriginallyDefinedInAttr: public DeclAttribute {
public:
OriginallyDefinedInAttr(SourceLoc AtLoc, SourceRange Range,
StringRef OriginalModuleName, PlatformKind Platform,
StringRef OriginalModuleName,
PlatformKind Platform,
const llvm::VersionTuple MovedVersion, bool Implicit);

OriginallyDefinedInAttr(SourceLoc AtLoc, SourceRange Range,
StringRef ManglingModuleName,
StringRef LinkerModuleName,
PlatformKind Platform,
const llvm::VersionTuple MovedVersion, bool Implicit)
: DeclAttribute(DeclAttrKind::OriginallyDefinedIn, AtLoc, Range,
Implicit),
OriginalModuleName(OriginalModuleName), Platform(Platform),
ManglingModuleName(ManglingModuleName),
LinkerModuleName(LinkerModuleName),
Platform(Platform),
MovedVersion(MovedVersion) {}

OriginallyDefinedInAttr *clone(ASTContext &C, bool implicit) const;

// The original module name.
const StringRef OriginalModuleName;
// The original module name for mangling.
const StringRef ManglingModuleName;

// The original module name for linker directives.
const StringRef LinkerModuleName;

/// The platform of the symbol.
const PlatformKind Platform;
Expand All @@ -2069,7 +2081,8 @@ class OriginallyDefinedInAttr: public DeclAttribute {
const llvm::VersionTuple MovedVersion;

struct ActiveVersion {
StringRef ModuleName;
StringRef ManglingModuleName;
StringRef LinkerModuleName;
PlatformKind Platform;
llvm::VersionTuple Version;
bool ForTargetVariant = false;
Expand All @@ -2085,7 +2098,8 @@ class OriginallyDefinedInAttr: public DeclAttribute {
/// Create a copy of this attribute.
OriginallyDefinedInAttr *clone(ASTContext &ctx) const {
return new (ctx) OriginallyDefinedInAttr(
AtLoc, Range, OriginalModuleName, Platform, MovedVersion, isImplicit());
AtLoc, Range, ManglingModuleName, LinkerModuleName,
Platform, MovedVersion, isImplicit());
}
};

Expand Down
3 changes: 2 additions & 1 deletion lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5214,7 +5214,8 @@ class PrintAttribute : public AttributeVisitor<PrintAttribute, void, Label>,
void visitOriginallyDefinedInAttr(OriginallyDefinedInAttr *Attr,
Label label) {
printCommon(Attr, "originally_defined_in_attr", label);
printField(Attr->OriginalModuleName, Label::always("original_module"));
printField(Attr->ManglingModuleName, Label::always("mangling_module"));
printField(Attr->LinkerModuleName, Label::always("linker_module"));
printField(Attr->Platform, Label::always("platform"));
printFieldRaw([&](auto &out) { out << Attr->MovedVersion.getAsString(); },
Label::always("moved_version"));
Expand Down
2 changes: 1 addition & 1 deletion lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2781,7 +2781,7 @@ void ASTMangler::appendModule(const ModuleDecl *module,

// Try the special 'swift' substitution.
if (ModName == STDLIB_NAME) {
if (useModuleName.empty()) {
if (useModuleName.empty() || useModuleName == STDLIB_NAME) {
appendOperator("s");
} else if (!RespectOriginallyDefinedIn) {
appendOperator("s");
Expand Down
2 changes: 1 addition & 1 deletion lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5986,7 +5986,7 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
for (auto attr: D->getAttrs().getAttributes<OriginallyDefinedInAttr>()) {
Name = Mod->getASTContext()
.getIdentifier(const_cast<OriginallyDefinedInAttr*>(attr)
->OriginalModuleName);
->ManglingModuleName);
break;
}
}
Expand Down
46 changes: 42 additions & 4 deletions lib/AST/Attr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1078,6 +1078,13 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
}
break;
}
case DeclAttrKind::OriginallyDefinedIn: {
auto Attr = cast<OriginallyDefinedInAttr>(this);
auto Name = D->getDeclContext()->getParentModule()->getName().str();
if (Options.IsForSwiftInterface && Attr->ManglingModuleName == Name)
return false;
break;
}
default:
break;
}
Expand Down Expand Up @@ -1175,8 +1182,12 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
Printer.printAttrName("@_originallyDefinedIn");
Printer << "(module: ";
auto Attr = cast<OriginallyDefinedInAttr>(this);
Printer << "\"" << Attr->OriginalModuleName << "\", ";
Printer << platformString(Attr->Platform) << " " <<
Printer << "\"" << Attr->ManglingModuleName;
ASSERT(!Attr->ManglingModuleName.empty());
ASSERT(!Attr->LinkerModuleName.empty());
if (Attr->LinkerModuleName != Attr->ManglingModuleName)
Printer << ";" << Attr->LinkerModuleName;
Printer << "\", " << platformString(Attr->Platform) << " " <<
Attr->MovedVersion.getAsString();
Printer << ")";
break;
Expand Down Expand Up @@ -2235,12 +2246,39 @@ AvailableAttr *AvailableAttr::clone(ASTContext &C, bool implicit) const {
implicit ? SourceRange() : ObsoletedRange, implicit, isSPI());
}

static StringRef getManglingModuleName(StringRef OriginalModuleName) {
auto index = OriginalModuleName.find(";");
return index == StringRef::npos
? OriginalModuleName
: OriginalModuleName.slice(0, index);
}

static StringRef getLinkerModuleName(StringRef OriginalModuleName) {
auto index = OriginalModuleName.find(";");
return index == StringRef::npos
? OriginalModuleName
: OriginalModuleName.slice(index + 1, OriginalModuleName.size());
}

OriginallyDefinedInAttr::OriginallyDefinedInAttr(
SourceLoc AtLoc, SourceRange Range,
StringRef OriginalModuleName,
PlatformKind Platform,
const llvm::VersionTuple MovedVersion, bool Implicit)
: DeclAttribute(DeclAttrKind::OriginallyDefinedIn, AtLoc, Range,
Implicit),
ManglingModuleName(getManglingModuleName(OriginalModuleName)),
LinkerModuleName(getLinkerModuleName(OriginalModuleName)),
Platform(Platform),
MovedVersion(MovedVersion) {}

std::optional<OriginallyDefinedInAttr::ActiveVersion>
OriginallyDefinedInAttr::isActivePlatform(const ASTContext &ctx) const {
OriginallyDefinedInAttr::ActiveVersion Result;
Result.Platform = Platform;
Result.Version = MovedVersion;
Result.ModuleName = OriginalModuleName;
Result.ManglingModuleName = ManglingModuleName;
Result.LinkerModuleName = LinkerModuleName;
if (isPlatformActive(Platform, ctx.LangOpts, /*TargetVariant*/false)) {
return Result;
}
Expand All @@ -2260,7 +2298,7 @@ OriginallyDefinedInAttr *OriginallyDefinedInAttr::clone(ASTContext &C,
bool implicit) const {
return new (C) OriginallyDefinedInAttr(
implicit ? SourceLoc() : AtLoc, implicit ? SourceRange() : getRange(),
OriginalModuleName, Platform, MovedVersion, implicit);
ManglingModuleName, LinkerModuleName, Platform, MovedVersion, implicit);
}

bool AvailableAttr::isUnconditionallyUnavailable() const {
Expand Down
2 changes: 1 addition & 1 deletion lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1101,7 +1101,7 @@ StringRef Decl::getAlternateModuleName() const {
for (auto *Att: Attrs) {
if (auto *OD = dyn_cast<OriginallyDefinedInAttr>(Att)) {
if (!OD->isInvalid() && OD->isActivePlatform(getASTContext())) {
return OD->OriginalModuleName;
return OD->ManglingModuleName;
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions lib/IRGen/IRGenDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2541,10 +2541,10 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
if (auto Attribute =
ND->getAttrs().getAttribute<OriginallyDefinedInAttr>()) {
auto Identifier = IGM.getSILModule().getASTContext().getIdentifier(
Attribute->OriginalModuleName);
Attribute->ManglingModuleName);
void *Key = (void *)Identifier.get();
Scope =
getOrCreateModule(Key, TheCU, Attribute->OriginalModuleName, {});
getOrCreateModule(Key, TheCU, Attribute->ManglingModuleName, {});
} else {
Context = ND->getParent();
}
Expand Down
11 changes: 7 additions & 4 deletions lib/IRGen/TBDGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,15 +88,18 @@ void TBDGenVisitor::addSymbolInternal(StringRef name, EncodeKind kind,

static std::vector<OriginallyDefinedInAttr::ActiveVersion>
getAllMovedPlatformVersions(Decl *D) {
StringRef Name = D->getDeclContext()->getParentModule()->getName().str();

std::vector<OriginallyDefinedInAttr::ActiveVersion> Results;
for (auto *attr: D->getAttrs()) {
if (auto *ODA = dyn_cast<OriginallyDefinedInAttr>(attr)) {
auto Active = ODA->isActivePlatform(D->getASTContext());
if (Active.has_value()) {
if (Active.has_value() && Active->LinkerModuleName != Name) {
Results.push_back(*Active);
}
}
}

return Results;
}

Expand Down Expand Up @@ -324,16 +327,16 @@ void TBDGenVisitor::addLinkerDirectiveSymbolsLdPrevious(
if (*IntroVer >= Ver.Version)
continue;
auto PlatformNumber = getLinkerPlatformId(Ver, Ctx);
auto It = previousInstallNameMap->find(Ver.ModuleName.str());
auto It = previousInstallNameMap->find(Ver.LinkerModuleName.str());
if (It == previousInstallNameMap->end()) {
Ctx.Diags.diagnose(SourceLoc(), diag::cannot_find_install_name,
Ver.ModuleName, getLinkerPlatformName(Ver, Ctx));
Ver.LinkerModuleName, getLinkerPlatformName(Ver, Ctx));
continue;
}
auto InstallName = It->second.getInstallName(PlatformNumber);
if (InstallName.empty()) {
Ctx.Diags.diagnose(SourceLoc(), diag::cannot_find_install_name,
Ver.ModuleName, getLinkerPlatformName(Ver, Ctx));
Ver.LinkerModuleName, getLinkerPlatformName(Ver, Ctx));
continue;
}
llvm::SmallString<64> Buffer;
Expand Down
20 changes: 16 additions & 4 deletions lib/Serialization/Deserialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6043,11 +6043,23 @@ llvm::Error DeclDeserializer::deserializeDeclCommon() {
Platform);
llvm::VersionTuple MovedVer;
DECODE_VER_TUPLE(MovedVer)
auto ModuleNameEnd = blobData.find('\0');
assert(ModuleNameEnd != StringRef::npos);
auto ModuleName = blobData.slice(0, ModuleNameEnd);

auto ManglingModuleNameEnd = blobData.find('\0');
assert(ManglingModuleNameEnd != StringRef::npos);
auto ManglingModuleName = blobData.slice(0, ManglingModuleNameEnd);

blobData = blobData.slice(ManglingModuleNameEnd + 1, blobData.size());

auto LinkerModuleNameEnd = blobData.find('\0');
assert(LinkerModuleNameEnd != StringRef::npos);
auto LinkerModuleName = blobData.slice(0, LinkerModuleNameEnd);

ASSERT(!ManglingModuleName.empty());
ASSERT(!LinkerModuleName.empty());

Attr = new (ctx) OriginallyDefinedInAttr(SourceLoc(), SourceRange(),
ModuleName,
ManglingModuleName,
LinkerModuleName,
(PlatformKind)Platform,
MovedVer,
isImplicit);
Expand Down
2 changes: 1 addition & 1 deletion lib/Serialization/ModuleFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
/// Don't worry about adhering to the 80-column limit for this line.
const uint16_t SWIFTMODULE_VERSION_MINOR = 928; // abstract conforming type
const uint16_t SWIFTMODULE_VERSION_MINOR = 929; // OriginallyDefinedInAttr::LinkerModuleName

/// A standard hash seed used for all string hashes in a serialized module.
///
Expand Down
4 changes: 3 additions & 1 deletion lib/Serialization/Serialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3094,7 +3094,9 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
Moved, std::optional<llvm::VersionTuple>(theAttr->MovedVersion));
auto abbrCode = S.DeclTypeAbbrCodes[OriginallyDefinedInDeclAttrLayout::Code];
llvm::SmallString<32> blob;
blob.append(theAttr->OriginalModuleName.str());
blob.append(theAttr->ManglingModuleName.str());
blob.push_back('\0');
blob.append(theAttr->LinkerModuleName.str());
blob.push_back('\0');
OriginallyDefinedInDeclAttrLayout::emitRecord(
S.Out, S.ScratchRecord, abbrCode,
Expand Down
51 changes: 51 additions & 0 deletions stdlib/public/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,19 @@ if(SWIFT_STDLIB_HAS_COMMANDLINE)
list(APPEND swift_core_incorporate_object_libraries swiftCommandLineSupport)
endif()

# Backward deployment of Span on Apple platforms is implemented via the
# libswiftCompatibilitySpan.dylib shim.
#
# This flag ensures we emit the correct $ld$previous$ symbols in the standard
# library. When building a binary for an older deployment target, we
# pretend certain symbols are actually in libswiftCompatibilitySpan.dylib.
#
# Further discussion of libswiftCompatibilitySpan.dylib appears below.
#
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
list(APPEND swift_stdlib_compile_flags "-Xfrontend" "-previous-module-installname-map-file" "-Xfrontend" "${CMAKE_CURRENT_SOURCE_DIR}/PreviousModuleInstallName.json")
endif()

set(swiftCore_common_options
IS_STDLIB IS_STDLIB_CORE
${SWIFTLIB_SOURCES}
Expand Down Expand Up @@ -424,6 +437,44 @@ add_swift_target_library(swiftCore
zippered
)

# When a binary built with an older deployment target is run with a new
# standard library, the symbols that were previously in the backward
# compatibility shim are now in the standard library. To ensure the
# dynamic linker continues to find these symbols, the compatibility
# shim must be replaced by a symlink to the standard library.
#
# Since we're building the "new" standard library here, we create this
# symlink in the same directory, from libswiftCompatibilitySpan.dylib to
# libswiftCore.dylib.
#
# The sources for the real libswiftCompatibilitySpan.dylib are found in
# stdlib/toolchain/CompatibilitySpan. When running a binary with an old
# standard library, this dynamic library must be present at run time.
#
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
Copy link
Member

Choose a reason for hiding this comment

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

You should sync up with @etcwilde about also building this with the newer build system

Copy link
Member

Choose a reason for hiding this comment

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

The compatibility libraries will be split out in the new build since they need to be built exactly as they were to match the original version. We don't want changes to the Swift or C++ version to impact them.

foreach(sdk ${SWIFT_SDKS})
set(lib_dir "${SWIFT_SDK_${sdk}_LIB_SUBDIR}")
set(lib_path "${SWIFTLIB_DIR}/${lib_dir}")
set(compat_lib_name "${lib_path}/libswiftCompatibilitySpan.dylib")

# This doesn't depend on libswiftCore.dylib because we don't actually need
# for it to exist to create the symlink, nor is there any need to recreate
# the symlink if the dylib changes.
add_custom_command_target(unused_var
CUSTOM_TARGET_NAME "swiftCompatibilitySpan-symlink-${lib_dir}"
OUTPUT "${compat_lib_name}"
COMMAND ${CMAKE_COMMAND} "-E" "create_symlink" "${lib_path}/libswiftCore.dylib" "${compat_lib_name}")
foreach(ARCH ${SWIFT_SDK_${sdk}_ARCHITECTURES})
add_dependencies("swiftCore-${lib_dir}-${ARCH}" "swiftCompatibilitySpan-symlink-${lib_dir}")
endforeach()

swift_install_symlink_component(stdlib
LINK_NAME libswiftCompatibilitySpan.dylib
TARGET libswiftCore.dylib
DESTINATION "lib/swift/${lib_dir}")
endforeach()
endif()

# Embedded standard library - embedded libraries are built as .swiftmodule only,
# i.e. there is no .o or .a file produced (no binary code is actually produced)
# and only users of a library are going to actually compile any needed code.
Expand Down
6 changes: 6 additions & 0 deletions stdlib/public/core/PreviousModuleInstallName.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[
{
"module": "CompatibilitySpan",
"install_name": "/usr/lib/swift/libswiftCompatibilitySpan.dylib"
}
]
4 changes: 4 additions & 0 deletions stdlib/public/core/Span/RawSpan.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
//
//===----------------------------------------------------------------------===//

#if SPAN_COMPATIBILITY_STUB
import Swift
#endif

/// `RawSpan` represents a contiguous region of memory
/// which contains initialized bytes.
///
Expand Down
4 changes: 4 additions & 0 deletions stdlib/public/core/Span/Span.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
//
//===----------------------------------------------------------------------===//

#if SPAN_COMPATIBILITY_STUB
import Swift
#endif

/// `Span<Element>` represents a contiguous region of memory
/// which contains initialized instances of `Element`.
///
Expand Down
1 change: 1 addition & 0 deletions stdlib/toolchain/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ if(SWIFT_STDLIB_SUPPORT_BACK_DEPLOYMENT)
add_subdirectory(Compatibility50)
add_subdirectory(Compatibility51)
add_subdirectory(Compatibility56)
add_subdirectory(CompatibilitySpan)
add_subdirectory(CompatibilityDynamicReplacements)
add_subdirectory(CompatibilityConcurrency)
add_subdirectory(CompatibilityThreading)
Expand Down
Loading