Skip to content

Commit c7da2a6

Browse files
committed
[TextAPI] Track RPaths in the order its provided via command line.
RPaths are basically search paths for how to load dependent libraries. The order they appear is the order the linker will search, we should preserve that order in tbd files. * Additionally add this level of detection to llvm-readtapi. resolves: rdar://145603347
1 parent f6a7306 commit c7da2a6

File tree

4 files changed

+74
-15
lines changed

4 files changed

+74
-15
lines changed

llvm/lib/TextAPI/InterfaceFile.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,11 @@ void InterfaceFile::addRPath(StringRef RPath, const Target &InputTarget) {
5959
return;
6060
using RPathEntryT = const std::pair<Target, std::string>;
6161
RPathEntryT Entry(InputTarget, RPath);
62-
auto Iter =
63-
lower_bound(RPaths, Entry,
64-
[](RPathEntryT &LHS, RPathEntryT &RHS) { return LHS < RHS; });
6562

66-
if ((Iter != RPaths.end()) && (*Iter == Entry))
63+
if (is_contained(RPaths, Entry))
6764
return;
6865

69-
RPaths.emplace(Iter, Entry);
66+
RPaths.emplace_back(Entry);
7067
}
7168

7269
void InterfaceFile::addTarget(const Target &Target) {

llvm/lib/TextAPI/TextStubV5.cpp

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,33 @@ using AttrToTargets = std::map<std::string, TargetList>;
8383
using TargetsToSymbols =
8484
SmallVector<std::pair<TargetList, std::vector<JSONSymbol>>>;
8585

86+
/// Wrapper over a vector for handling textstub attributes, mapped to target
87+
/// triples, that require insertion order to be intact in the resulting \c
88+
/// InterfaceFile.
89+
class InOrderAttrToTargets {
90+
using EntryT = std::pair<std::string, TargetList>;
91+
92+
public:
93+
void insert(EntryT &&Entry) {
94+
auto &Element = get(Entry.first);
95+
Element.second = Entry.second;
96+
}
97+
98+
const EntryT *begin() { return Container.begin(); }
99+
const EntryT *end() { return Container.end(); }
100+
101+
private:
102+
EntryT &get(std::string &Key) {
103+
auto *It = find_if(Container,
104+
[&Key](EntryT &Input) { return Input.first == Key; });
105+
if (It != Container.end())
106+
return *It;
107+
Container.push_back(EntryT(Key, {}));
108+
return Container.back();
109+
}
110+
llvm::SmallVector<EntryT> Container;
111+
};
112+
86113
enum TBDKey : size_t {
87114
TBDVersion = 0U,
88115
MainLibrary,
@@ -437,14 +464,14 @@ Expected<TargetsToSymbols> getSymbolSection(const Object *File, TBDKey Key,
437464
return std::move(Result);
438465
}
439466

440-
Expected<AttrToTargets> getLibSection(const Object *File, TBDKey Key,
441-
TBDKey SubKey,
442-
const TargetList &Targets) {
467+
template <typename ReturnT = AttrToTargets>
468+
Expected<ReturnT> getLibSection(const Object *File, TBDKey Key, TBDKey SubKey,
469+
const TargetList &Targets) {
443470
auto *Section = File->getArray(Keys[Key]);
444471
if (!Section)
445-
return AttrToTargets();
472+
return ReturnT();
446473

447-
AttrToTargets Result;
474+
ReturnT Result;
448475
TargetList MappedTargets;
449476
for (auto Val : *Section) {
450477
auto *Obj = Val.getAsObject();
@@ -460,7 +487,7 @@ Expected<AttrToTargets> getLibSection(const Object *File, TBDKey Key,
460487
}
461488
auto Err =
462489
collectFromArray(SubKey, Obj, [&Result, &MappedTargets](StringRef Key) {
463-
Result[Key.str()] = MappedTargets;
490+
Result.insert({Key.str(), MappedTargets});
464491
});
465492
if (Err)
466493
return std::move(Err);
@@ -629,10 +656,11 @@ Expected<IFPtr> parseToInterfaceFile(const Object *File) {
629656
return RLOrErr.takeError();
630657
AttrToTargets ReexportLibs = std::move(*RLOrErr);
631658

632-
auto RPathsOrErr = getLibSection(File, TBDKey::RPath, TBDKey::Paths, Targets);
659+
auto RPathsOrErr = getLibSection<InOrderAttrToTargets>(
660+
File, TBDKey::RPath, TBDKey::Paths, Targets);
633661
if (!RPathsOrErr)
634662
return RPathsOrErr.takeError();
635-
AttrToTargets RPaths = std::move(*RPathsOrErr);
663+
InOrderAttrToTargets RPaths = std::move(*RPathsOrErr);
636664

637665
auto ExportsOrErr = getSymbolSection(File, TBDKey::Exports, Targets);
638666
if (!ExportsOrErr)
@@ -802,6 +830,8 @@ Array serializeAttrToTargets(AggregateT &Entries, TBDKey Key) {
802830
return Container;
803831
}
804832

833+
/// When there is no significance in order, the common case, serialize all
834+
/// attributes in a stable order.
805835
template <typename ValueT = std::string,
806836
typename AggregateT = std::vector<std::pair<MachO::Target, ValueT>>>
807837
Array serializeField(TBDKey Key, const AggregateT &Values,
@@ -834,6 +864,21 @@ Array serializeField(TBDKey Key, const std::vector<InterfaceFileRef> &Values,
834864
return serializeAttrToTargets(FinalEntries, Key);
835865
}
836866

867+
template <
868+
typename AggregateT = std::vector<std::pair<MachO::Target, std::string>>>
869+
Array serializeFieldInInsertionOrder(TBDKey Key, const AggregateT &Values,
870+
const TargetList &ActiveTargets) {
871+
MapVector<StringRef, std::set<MachO::Target>> Entries;
872+
for (const auto &[Target, Val] : Values)
873+
Entries[Val].insert(Target);
874+
875+
TargetsToValuesMap FinalEntries;
876+
for (const auto &[Val, Targets] : Entries)
877+
FinalEntries[serializeTargets(Targets, ActiveTargets)].emplace_back(
878+
Val.str());
879+
return serializeAttrToTargets(FinalEntries, Key);
880+
}
881+
837882
struct SymbolFields {
838883
struct SymbolTypes {
839884
std::vector<StringRef> Weaks;
@@ -963,7 +1008,8 @@ Expected<Object> serializeIF(const InterfaceFile *File) {
9631008
TBDKey::ABI, File->getSwiftABIVersion(), 0u);
9641009
insertNonEmptyValues(Library, TBDKey::SwiftABI, std::move(SwiftABI));
9651010

966-
Array RPaths = serializeField(TBDKey::Paths, File->rpaths(), ActiveTargets);
1011+
Array RPaths = serializeFieldInInsertionOrder(TBDKey::Paths, File->rpaths(),
1012+
ActiveTargets);
9671013
insertNonEmptyValues(Library, TBDKey::RPath, std::move(RPaths));
9681014

9691015
Array Umbrellas = serializeField(TBDKey::Umbrella, File->umbrellas(),
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
; RUN: rm -rf %t
2+
; RUN: split-file %s %t
3+
; RUN: not llvm-readtapi --compare %t/rpaths_diff_order.tbd %t/rpaths.tbd 2>&1 | FileCheck %s
4+
5+
; CHECK: < {{.*}}rpaths_diff_order.tbd
6+
; CHECK: > {{.*}}rpaths.tbd
7+
8+
; CHECK: 'Run Path Search Paths' differ by order
9+
10+
//--- rpaths_diff_order.tbd
11+
{"main_library":{"exported_symbols":[{"text":{"global":["_foo"]}}],"rpaths": [{"paths": ["/usr/lib/swift", "@loader_path/../../../"]}], "flags":[{"attributes":["not_app_extension_safe"]}],"install_names":[{"name":"@rpath/libFake.dylib"}],"target_info":[{"min_deployment":"13","target":"x86_64-macos"},{"min_deployment":"13","target":"arm64-macos"}]},"tapi_tbd_version":5}
12+
13+
//--- rpaths.tbd
14+
{"main_library":{"exported_symbols":[{"text":{"global":["_foo"]}}],"rpaths": [{"paths": [ "@loader_path/../../../", "/usr/lib/swift"]}], "flags":[{"attributes":["not_app_extension_safe"]}],"install_names":[{"name":"@rpath/libFake.dylib"}],"target_info":[{"min_deployment":"13","target":"x86_64-macos"},{"min_deployment":"13","target":"arm64-macos"}]},"tapi_tbd_version":5}

llvm/tools/llvm-readtapi/DiffEngine.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -449,8 +449,10 @@ template <typename T> void sortTargetValues(std::vector<T> &TargValues) {
449449

450450
template <typename T>
451451
void printVecVal(std::string Indent, const DiffOutput &Attr, raw_ostream &OS) {
452-
if (Attr.Values.empty())
452+
if (Attr.Values.empty()) {
453+
OS << Indent << "'" << Attr.Name << "' differ by order\n";
453454
return;
455+
}
454456

455457
OS << Indent << Attr.Name << "\n";
456458

0 commit comments

Comments
 (0)