diff --git a/llvm/include/llvm/TextAPI/InterfaceFile.h b/llvm/include/llvm/TextAPI/InterfaceFile.h --- a/llvm/include/llvm/TextAPI/InterfaceFile.h +++ b/llvm/include/llvm/TextAPI/InterfaceFile.h @@ -348,6 +348,18 @@ return Documents; } + /// Set the runpath search paths. + /// \param InputTarget The target applicable to runpath search path. + /// \param RPath The name of runpath. + void addRPath(const Target &InputTarget, StringRef RPath); + + /// Get the list of runpath search paths. + /// + /// \return Returns a list of the rpaths per target. + const std::vector> &rpaths() const { + return RPaths; + } + /// Add a symbol to the symbols list or extend an existing one. void addSymbol(SymbolKind Kind, StringRef Name, const TargetList &Targets, SymbolFlags Flags = SymbolFlags::None); @@ -435,6 +447,7 @@ std::vector ReexportedLibraries; std::vector> Documents; std::vector> UUIDs; + std::vector> RPaths; SymbolMapType Symbols; InterfaceFile *Parent = nullptr; }; diff --git a/llvm/include/llvm/TextAPI/Symbol.h b/llvm/include/llvm/TextAPI/Symbol.h --- a/llvm/include/llvm/TextAPI/Symbol.h +++ b/llvm/include/llvm/TextAPI/Symbol.h @@ -40,7 +40,13 @@ /// Rexported Rexported = 1U << 4, - LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/Rexported), + /// Data Segment + Data = 1U << 5, + + /// Text Segment + Text = 1U << 6, + + LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/Text), }; // clang-format on @@ -93,6 +99,14 @@ return (Flags & SymbolFlags::Rexported) == SymbolFlags::Rexported; } + bool isData() const { + return (Flags & SymbolFlags::Data) == SymbolFlags::Data; + } + + bool isText() const { + return (Flags & SymbolFlags::Text) == SymbolFlags::Text; + } + using const_target_iterator = TargetList::const_iterator; using const_target_range = llvm::iterator_range; const_target_range targets() const { return {Targets}; } diff --git a/llvm/include/llvm/TextAPI/Target.h b/llvm/include/llvm/TextAPI/Target.h --- a/llvm/include/llvm/TextAPI/Target.h +++ b/llvm/include/llvm/TextAPI/Target.h @@ -10,6 +10,8 @@ #define LLVM_TEXTAPI_TARGET_H #include "llvm/Support/Error.h" +#include "llvm/Support/VersionTuple.h" +#include "llvm/TargetParser/Triple.h" #include "llvm/TextAPI/Architecture.h" #include "llvm/TextAPI/ArchitectureSet.h" #include "llvm/TextAPI/Platform.h" @@ -26,10 +28,12 @@ class Target { public: Target() = default; - Target(Architecture Arch, PlatformType Platform) - : Arch(Arch), Platform(Platform) {} + Target(Architecture Arch, PlatformType Platform, + VersionTuple MinDeployment = {}) + : Arch(Arch), Platform(Platform), MinDeployment(MinDeployment) {} explicit Target(const llvm::Triple &Triple) - : Arch(mapToArchitecture(Triple)), Platform(mapToPlatformType(Triple)) {} + : Arch(mapToArchitecture(Triple)), Platform(mapToPlatformType(Triple)), + MinDeployment(Triple.getOSVersion()) {} static llvm::Expected create(StringRef Target); @@ -37,6 +41,7 @@ Architecture Arch; PlatformType Platform; + VersionTuple MinDeployment; }; inline bool operator==(const Target &LHS, const Target &RHS) { diff --git a/llvm/lib/TextAPI/InterfaceFile.cpp b/llvm/lib/TextAPI/InterfaceFile.cpp --- a/llvm/lib/TextAPI/InterfaceFile.cpp +++ b/llvm/lib/TextAPI/InterfaceFile.cpp @@ -71,6 +71,19 @@ ParentUmbrellas.emplace(Iter, Target_, std::string(Parent)); } +void InterfaceFile::addRPath(const Target &InputTarget, StringRef RPath) { + auto Iter = lower_bound(RPaths, InputTarget, + [](const std::pair &LHS, + Target RHS) { return LHS.first < RHS; }); + + if ((Iter != RPaths.end()) && !(InputTarget < Iter->first)) { + Iter->second = std::string(RPath); + return; + } + + RPaths.emplace(Iter, InputTarget, std::string(RPath)); +} + void InterfaceFile::addUUID(const Target &Target_, StringRef UUID) { auto Iter = lower_bound(UUIDs, Target_, [](const std::pair &LHS, diff --git a/llvm/lib/TextAPI/Target.cpp b/llvm/lib/TextAPI/Target.cpp --- a/llvm/lib/TextAPI/Target.cpp +++ b/llvm/lib/TextAPI/Target.cpp @@ -46,7 +46,10 @@ } Target::operator std::string() const { - return (getArchitectureName(Arch) + " (" + getPlatformName(Platform) + ")") + auto Version = MinDeployment.empty() ? "" : MinDeployment.getAsString(); + + return (getArchitectureName(Arch) + " (" + getPlatformName(Platform) + + Version + ")") .str(); } @@ -70,8 +73,11 @@ } std::string getTargetTripleName(const Target &Targ) { + auto Version = + Targ.MinDeployment.empty() ? "" : Targ.MinDeployment.getAsString(); + return (getArchitectureName(Targ.Arch) + "-apple-" + - getOSAndEnvironmentName(Targ.Platform)) + getOSAndEnvironmentName(Targ.Platform, Version)) .str(); } diff --git a/llvm/lib/TextAPI/TextStubV5.cpp b/llvm/lib/TextAPI/TextStubV5.cpp --- a/llvm/lib/TextAPI/TextStubV5.cpp +++ b/llvm/lib/TextAPI/TextStubV5.cpp @@ -115,6 +115,8 @@ ObjCClass, ObjCEHType, ObjCIvar, + RPath, + Paths, }; std::array Keys = { @@ -151,6 +153,8 @@ "objc_class", "objc_eh_type", "objc_ivar", + "rpaths", + "paths", }; static llvm::SmallString<128> getParseErrorMsg(TBDKey Key) { @@ -273,11 +277,19 @@ getRequiredValue(TBDKey::Target, Obj, &Object::getString); if (!TargetStr) return make_error(getParseErrorMsg(TBDKey::Target)); + auto VersionStr = getRequiredValue(TBDKey::Deployment, Obj, + &Object::getString); + if (!VersionStr) + return make_error(getParseErrorMsg(TBDKey::Deployment)); + VersionTuple Version; + if (Version.tryParse(*VersionStr)) + return make_error(getParseErrorMsg(TBDKey::Deployment)); auto TargetOrErr = Target::create(*TargetStr); if (!TargetOrErr) return make_error(getParseErrorMsg(TBDKey::Target)); + TargetOrErr->MinDeployment = Version; + IFTargets.push_back(*TargetOrErr); - // TODO: Implement Deployment Version. } return std::move(IFTargets); } @@ -321,15 +333,11 @@ SymbolFlags WeakFlag = SectionFlag | (SectionFlag == SymbolFlags::Undefined ? SymbolFlags::WeakReferenced : SymbolFlags::WeakDefined); - Err = collectFromArray(TBDKey::Weak, Segment, - [&Result, WeakFlag](StringRef Name) { - JSONSymbol Sym = { - SymbolKind::GlobalSymbol, - Name.str(), - WeakFlag, - }; - Result.back().second.emplace_back(Sym); - }); + Err = collectFromArray( + TBDKey::Weak, Segment, [&Result, WeakFlag](StringRef Name) { + JSONSymbol Sym = {SymbolKind::GlobalSymbol, Name.str(), WeakFlag}; + Result.back().second.emplace_back(Sym); + }); if (Err) return Err; @@ -402,12 +410,14 @@ return make_error(getParseErrorMsg(Key)); if (DataSection) { - auto Err = collectSymbolsFromSegment(DataSection, Result, SectionFlag); + auto Err = collectSymbolsFromSegment(DataSection, Result, + SectionFlag | SymbolFlags::Data); if (Err) return std::move(Err); } if (TextSection) { - auto Err = collectSymbolsFromSegment(TextSection, Result, SectionFlag); + auto Err = collectSymbolsFromSegment(TextSection, Result, + SectionFlag | SymbolFlags::Text); if (Err) return std::move(Err); } @@ -605,6 +615,11 @@ return RLOrErr.takeError(); AttrToTargets ReexportLibs = std::move(*RLOrErr); + auto RPathsOrErr = getLibSection(File, TBDKey::RPath, TBDKey::Paths, Targets); + if (!RPathsOrErr) + return RPathsOrErr.takeError(); + AttrToTargets RPaths = std::move(*RPathsOrErr); + auto ExportsOrErr = getSymbolSection(File, TBDKey::Exports, Targets); if (!ExportsOrErr) return ExportsOrErr.takeError(); @@ -639,6 +654,9 @@ for (auto &[Lib, Targets] : Umbrellas) for (auto Target : Targets) F->addParentUmbrella(Target, Lib); + for (auto &[Path, Targets] : RPaths) + for (auto Target : Targets) + F->addRPath(Target, Path); for (auto &[Targets, Symbols] : Exports) for (auto &Sym : Symbols) F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags); diff --git a/llvm/unittests/TextAPI/TextStubHelpers.h b/llvm/unittests/TextAPI/TextStubHelpers.h --- a/llvm/unittests/TextAPI/TextStubHelpers.h +++ b/llvm/unittests/TextAPI/TextStubHelpers.h @@ -20,11 +20,12 @@ std::string Name = {}; bool Weak = false; bool ThreadLocalValue = false; + bool isData = false; MachO::TargetList Targets = {}; }; using ExportedSymbolSeq = std::vector; -using UUIDs = std::vector>; +using TargetToAttr = std::vector>; using TBDFile = std::unique_ptr; using TBDReexportFile = std::shared_ptr; diff --git a/llvm/unittests/TextAPI/TextStubV3Tests.cpp b/llvm/unittests/TextAPI/TextStubV3Tests.cpp --- a/llvm/unittests/TextAPI/TextStubV3Tests.cpp +++ b/llvm/unittests/TextAPI/TextStubV3Tests.cpp @@ -81,10 +81,10 @@ for (auto &&arch : Archs) Targets.emplace_back(Target(arch, Platform)); EXPECT_EQ(Archs, File->getArchitectures()); - UUIDs Uuids = {{Target(AK_armv7, PLATFORM_UNKNOWN), - "00000000-0000-0000-0000-000000000000"}, - {Target(AK_arm64, PLATFORM_UNKNOWN), - "11111111-1111-1111-1111-111111111111"}}; + TargetToAttr Uuids = {{Target(AK_armv7, PLATFORM_UNKNOWN), + "00000000-0000-0000-0000-000000000000"}, + {Target(AK_arm64, PLATFORM_UNKNOWN), + "11111111-1111-1111-1111-111111111111"}}; EXPECT_EQ(Uuids, File->uuids()); EXPECT_EQ(File->getPlatforms().size(), 1U); EXPECT_EQ(Platform, *File->getPlatforms().begin()); @@ -171,10 +171,10 @@ for (auto &&arch : Archs) Targets.emplace_back(Target(arch, Platform)); EXPECT_EQ(Archs, File->getArchitectures()); - UUIDs Uuids = {{Target(AK_armv7, PLATFORM_UNKNOWN), - "00000000-0000-0000-0000-000000000000"}, - {Target(AK_arm64, PLATFORM_UNKNOWN), - "11111111-1111-1111-1111-111111111111"}}; + TargetToAttr Uuids = {{Target(AK_armv7, PLATFORM_UNKNOWN), + "00000000-0000-0000-0000-000000000000"}, + {Target(AK_arm64, PLATFORM_UNKNOWN), + "11111111-1111-1111-1111-111111111111"}}; EXPECT_EQ(Uuids, File->uuids()); EXPECT_EQ(File->getPlatforms().size(), 1U); EXPECT_EQ(Platform, *File->getPlatforms().begin()); diff --git a/llvm/unittests/TextAPI/TextStubV4Tests.cpp b/llvm/unittests/TextAPI/TextStubV4Tests.cpp --- a/llvm/unittests/TextAPI/TextStubV4Tests.cpp +++ b/llvm/unittests/TextAPI/TextStubV4Tests.cpp @@ -90,9 +90,9 @@ Target(AK_x86_64, PLATFORM_MACOS), Target(AK_x86_64, PLATFORM_IOS), }; - UUIDs uuids = {{Targets[0], "00000000-0000-0000-0000-000000000000"}, - {Targets[1], "11111111-1111-1111-1111-111111111111"}, - {Targets[2], "11111111-1111-1111-1111-111111111111"}}; + TargetToAttr uuids = {{Targets[0], "00000000-0000-0000-0000-000000000000"}, + {Targets[1], "11111111-1111-1111-1111-111111111111"}, + {Targets[2], "11111111-1111-1111-1111-111111111111"}}; EXPECT_EQ(Archs, File->getArchitectures()); EXPECT_EQ(uuids, File->uuids()); EXPECT_EQ(Platforms.size(), File->getPlatforms().size()); @@ -225,7 +225,7 @@ for (auto &&Arch : Archs) for (auto &&Platform : Platforms) Targets.emplace_back(Target(Arch, Platform)); - UUIDs Uuids = { + TargetToAttr Uuids = { {Targets[0], "00000000-0000-0000-0000-000000000000"}, {Targets[1], "00000000-0000-0000-0000-000000000002"}, {Targets[2], "11111111-1111-1111-1111-111111111111"}, @@ -356,8 +356,8 @@ Target(AK_i386, PLATFORM_MACOS), Target(AK_x86_64, PLATFORM_IOSSIMULATOR), }; - UUIDs uuids = {{Targets[0], "00000000-0000-0000-0000-000000000000"}, - {Targets[1], "11111111-1111-1111-1111-111111111111"}}; + TargetToAttr uuids = {{Targets[0], "00000000-0000-0000-0000-000000000000"}, + {Targets[1], "11111111-1111-1111-1111-111111111111"}}; File.setInstallName("Umbrella.framework/Umbrella"); File.setFileType(FileType::TBD_V4); File.addTargets(Targets); @@ -424,8 +424,8 @@ Target(AK_i386, Platform), Target(AK_x86_64, Platform), }; - UUIDs Uuids = {{Targets[0], "00000000-0000-0000-0000-000000000002"}, - {Targets[1], "11111111-1111-1111-1111-111111111112"}}; + TargetToAttr Uuids = {{Targets[0], "00000000-0000-0000-0000-000000000002"}, + {Targets[1], "11111111-1111-1111-1111-111111111112"}}; File.setInstallName("/System/Library/Frameworks/Umbrella.framework/Umbrella"); File.setFileType(FileType::TBD_V4); File.addTargets(Targets); diff --git a/llvm/unittests/TextAPI/TextStubV5Tests.cpp b/llvm/unittests/TextAPI/TextStubV5Tests.cpp --- a/llvm/unittests/TextAPI/TextStubV5Tests.cpp +++ b/llvm/unittests/TextAPI/TextStubV5Tests.cpp @@ -191,9 +191,9 @@ EXPECT_EQ(std::string("/S/L/F/Foo.framework/Foo"), File->getInstallName()); TargetList AllTargets = { - Target(AK_x86_64, PLATFORM_MACOS), - Target(AK_arm64, PLATFORM_MACOS), - Target(AK_arm64, PLATFORM_MACCATALYST), + Target(AK_x86_64, PLATFORM_MACOS, VersionTuple(10, 14)), + Target(AK_arm64, PLATFORM_MACOS, VersionTuple(10, 14)), + Target(AK_arm64, PLATFORM_MACCATALYST, VersionTuple(12, 1)), }; EXPECT_EQ(mapToPlatformSet(AllTargets), File->getPlatforms()); EXPECT_EQ(mapToArchitectureSet(AllTargets), File->getArchitectures()); @@ -216,19 +216,26 @@ EXPECT_EQ(ReexportA, File->reexportedLibraries().at(0)); EXPECT_EQ(ReexportB, File->reexportedLibraries().at(1)); - std::vector> Umbrellas = { - {Target(AK_x86_64, PLATFORM_MACOS), "System"}, - {Target(AK_arm64, PLATFORM_MACOS), "System"}, - {Target(AK_arm64, PLATFORM_MACCATALYST), "System"}}; + TargetToAttr RPaths = { + {Target(AK_x86_64, PLATFORM_MACOS), "@executable_path/.../Frameworks"}, + }; + EXPECT_EQ(RPaths, File->rpaths()); + + TargetToAttr Umbrellas = {{Target(AK_x86_64, PLATFORM_MACOS), "System"}, + {Target(AK_arm64, PLATFORM_MACOS), "System"}, + {Target(AK_arm64, PLATFORM_MACCATALYST), "System"}}; EXPECT_EQ(Umbrellas, File->umbrellas()); ExportedSymbolSeq Exports, Reexports, Undefineds; for (const auto *Sym : File->symbols()) { TargetList SymTargets{Sym->targets().begin(), Sym->targets().end()}; ExportedSymbol Temp = - ExportedSymbol{Sym->getKind(), std::string(Sym->getName()), + ExportedSymbol{Sym->getKind(), + std::string(Sym->getName()), Sym->isWeakDefined() || Sym->isWeakReferenced(), - Sym->isThreadLocalValue(), SymTargets}; + Sym->isThreadLocalValue(), + Sym->isData(), + SymTargets}; if (Sym->isUndefined()) Undefineds.emplace_back(std::move(Temp)); else @@ -243,54 +250,63 @@ Target(AK_arm64, PLATFORM_MACOS)}; std::vector ExpectedExportedSymbols = { - {SymbolKind::GlobalSymbol, "_func", false, false, MacOSTargets}, + {SymbolKind::GlobalSymbol, "_func", false, false, false, MacOSTargets}, {SymbolKind::GlobalSymbol, "_funcFoo", false, false, + false, {Target(AK_x86_64, PLATFORM_MACOS)}}, - {SymbolKind::GlobalSymbol, "_global", false, false, MacOSTargets}, + {SymbolKind::GlobalSymbol, "_global", false, false, true, MacOSTargets}, {SymbolKind::GlobalSymbol, "_globalVar", false, false, + true, {Target(AK_x86_64, PLATFORM_MACOS)}}, - {SymbolKind::ObjectiveCClass, "ClassA", false, false, MacOSTargets}, + {SymbolKind::ObjectiveCClass, "ClassA", false, false, true, MacOSTargets}, {SymbolKind::ObjectiveCClass, "ClassData", false, false, + true, {Target(AK_x86_64, PLATFORM_MACOS)}}, {SymbolKind::ObjectiveCClassEHType, "ClassA", false, false, + true, {Target(AK_x86_64, PLATFORM_MACOS)}}, {SymbolKind::ObjectiveCClassEHType, "ClassB", false, false, + true, {Target(AK_x86_64, PLATFORM_MACOS)}}, {SymbolKind::ObjectiveCInstanceVariable, "ClassA.ivar1", false, false, + true, {Target(AK_x86_64, PLATFORM_MACOS)}}, {SymbolKind::ObjectiveCInstanceVariable, "ClassA.ivar2", false, false, + true, {Target(AK_x86_64, PLATFORM_MACOS)}}, {SymbolKind::ObjectiveCInstanceVariable, "ClassC.ivar1", false, false, + true, {Target(AK_x86_64, PLATFORM_MACOS)}}, }; std::vector ExpectedReexportedSymbols = { - {SymbolKind::GlobalSymbol, "_funcA", false, false, MacOSTargets}, - {SymbolKind::GlobalSymbol, "_globalRe", false, false, MacOSTargets}, - {SymbolKind::ObjectiveCClass, "ClassRexport", false, false, MacOSTargets}, + {SymbolKind::GlobalSymbol, "_funcA", false, false, false, MacOSTargets}, + {SymbolKind::GlobalSymbol, "_globalRe", false, false, true, MacOSTargets}, + {SymbolKind::ObjectiveCClass, "ClassRexport", false, false, true, + MacOSTargets}, }; std::vector ExpectedUndefinedSymbols = { @@ -298,11 +314,13 @@ "_globalBind", false, false, + true, {Target(AK_x86_64, PLATFORM_MACOS)}}, {SymbolKind::GlobalSymbol, "referenced_sym", true, false, + true, {Target(AK_x86_64, PLATFORM_MACOS)}}, }; @@ -368,9 +386,9 @@ EXPECT_EQ(8U, File->getSwiftABIVersion()); TargetList AllTargets = { - Target(AK_x86_64, PLATFORM_MACOS), - Target(AK_arm64, PLATFORM_MACOS), - Target(AK_arm64, PLATFORM_MACCATALYST), + Target(AK_x86_64, PLATFORM_MACOS, VersionTuple(10, 14)), + Target(AK_arm64, PLATFORM_MACOS, VersionTuple(10, 14)), + Target(AK_arm64, PLATFORM_MACCATALYST, VersionTuple(12, 1)), }; EXPECT_EQ(mapToPlatformSet(AllTargets), File->getPlatforms()); EXPECT_EQ(mapToArchitectureSet(AllTargets), File->getArchitectures()); @@ -443,7 +461,7 @@ EXPECT_TRUE(File->isApplicationExtensionSafe()); TargetList Targets(File->targets().begin(), File->targets().end()); - Target iOSTarget(AK_armv7, PLATFORM_IOS); + Target iOSTarget(AK_armv7, PLATFORM_IOS, VersionTuple(11, 0)); EXPECT_EQ(TargetList{iOSTarget}, Targets); std::vector Symbols(File->symbols().begin(), File->symbols().end()); @@ -470,15 +488,31 @@ std::string(Sym->getName()), Sym->isWeakDefined() || Sym->isWeakReferenced(), Sym->isThreadLocalValue(), + Sym->isData(), {iOSTarget}}); llvm::sort(Exports); ExportedSymbolSeq ExpectedExports = { - {SymbolKind::GlobalSymbol, "_funcFoo", false, false, {iOSTarget}}, - {SymbolKind::GlobalSymbol, "_globalVar", false, true, {iOSTarget}}, - {SymbolKind::ObjectiveCClass, "ClassData", false, false, {iOSTarget}}, - {SymbolKind::ObjectiveCClassEHType, "ClassA", false, false, {iOSTarget}}, - {SymbolKind::ObjectiveCClassEHType, "ClassB", false, false, {iOSTarget}}, + {SymbolKind::GlobalSymbol, "_funcFoo", false, false, false, {iOSTarget}}, + {SymbolKind::GlobalSymbol, "_globalVar", false, true, true, {iOSTarget}}, + {SymbolKind::ObjectiveCClass, + "ClassData", + false, + false, + true, + {iOSTarget}}, + {SymbolKind::ObjectiveCClassEHType, + "ClassA", + false, + false, + true, + {iOSTarget}}, + {SymbolKind::ObjectiveCClassEHType, + "ClassB", + false, + false, + true, + {iOSTarget}}, }; EXPECT_EQ(ExpectedExports.size(), Exports.size());