Skip to content

Commit 2ed023c

Browse files
committed
[clang-installapi] Store dylib attributes in the order they are passed
on the command line. With the introduction of tbd-v5 holding rpaths, the order in which attributes are passed to `clang-installapi` must be represented in tbd files. Previously all of these attributes were stored in a non-determinisic StringMap. Instead, hold them in custom container that holds an underlying container to continue supporting searching by attribute.
1 parent 282af2d commit 2ed023c

File tree

6 files changed

+87
-46
lines changed

6 files changed

+87
-46
lines changed

clang/include/clang/InstallAPI/DylibVerifier.h

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,31 @@ enum class VerificationMode {
2525
Pedantic,
2626
};
2727

28-
using LibAttrs = llvm::StringMap<ArchitectureSet>;
2928
using ReexportedInterfaces = llvm::SmallVector<llvm::MachO::InterfaceFile, 8>;
3029

30+
/// Represents dynamic library specific attributes that are tied to
31+
/// architecture slices. It is commonly used for comparing options
32+
/// passed on the command line to installapi and what exists in dylib load
33+
/// commands.
34+
class LibAttrs {
35+
public:
36+
using Entry = std::pair<std::string, ArchitectureSet>;
37+
using AttrsToArchs = llvm::SmallVector<Entry, 10>;
38+
39+
// Mutable access to architecture set tied to the input attribute.
40+
ArchitectureSet &getArchSet(StringRef Attr);
41+
// Get entry based on the attribute.
42+
std::optional<Entry> find(StringRef Attr) const;
43+
// Immutable access to underlying container.
44+
const AttrsToArchs &get() const { return LibraryAttributes; };
45+
// Mutable access to underlying container.
46+
AttrsToArchs &get() { return LibraryAttributes; };
47+
bool operator==(const LibAttrs &Other) const { return Other.get() == get(); };
48+
49+
private:
50+
AttrsToArchs LibraryAttributes;
51+
};
52+
3153
// Pointers to information about a zippered declaration used for
3254
// querying and reporting violations against different
3355
// declarations that all map to the same symbol.

clang/lib/InstallAPI/DiagnosticBuilderWrappers.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,12 @@ const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
9797

9898
const clang::DiagnosticBuilder &
9999
operator<<(const clang::DiagnosticBuilder &DB,
100-
const StringMapEntry<ArchitectureSet> &LibAttr) {
101-
std::string IFAsString;
102-
raw_string_ostream OS(IFAsString);
100+
const clang::installapi::LibAttrs::Entry &LibAttr) {
101+
std::string Entry;
102+
raw_string_ostream OS(Entry);
103103

104-
OS << LibAttr.getKey() << " [ " << LibAttr.getValue() << " ]";
105-
DB.AddString(IFAsString);
104+
OS << LibAttr.first << " [ " << LibAttr.second << " ]";
105+
DB.AddString(Entry);
106106
return DB;
107107
}
108108

clang/lib/InstallAPI/DiagnosticBuilderWrappers.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#define LLVM_CLANG_INSTALLAPI_DIAGNOSTICBUILDER_WRAPPER_H
1515

1616
#include "clang/Basic/Diagnostic.h"
17+
#include "clang/InstallAPI/DylibVerifier.h"
1718
#include "llvm/TextAPI/Architecture.h"
1819
#include "llvm/TextAPI/ArchitectureSet.h"
1920
#include "llvm/TextAPI/InterfaceFile.h"
@@ -42,7 +43,7 @@ const clang::DiagnosticBuilder &operator<<(const clang::DiagnosticBuilder &DB,
4243

4344
const clang::DiagnosticBuilder &
4445
operator<<(const clang::DiagnosticBuilder &DB,
45-
const StringMapEntry<ArchitectureSet> &LibAttr);
46+
const clang::installapi::LibAttrs::Entry &LibAttr);
4647

4748
} // namespace MachO
4849
} // namespace llvm

clang/lib/InstallAPI/DylibVerifier.cpp

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,25 @@ using namespace llvm::MachO;
1818
namespace clang {
1919
namespace installapi {
2020

21+
ArchitectureSet &LibAttrs::getArchSet(StringRef Attr) {
22+
auto *It = llvm::find_if(LibraryAttributes, [&Attr](const auto &Input) {
23+
return Attr == Input.first;
24+
});
25+
if (It != LibraryAttributes.end())
26+
return It->second;
27+
LibraryAttributes.push_back({Attr.str(), ArchitectureSet()});
28+
return LibraryAttributes.back().second;
29+
}
30+
31+
std::optional<LibAttrs::Entry> LibAttrs::find(StringRef Attr) const {
32+
auto *It = llvm::find_if(LibraryAttributes, [&Attr](const auto &Input) {
33+
return Attr == Input.first;
34+
});
35+
if (It == LibraryAttributes.end())
36+
return std::nullopt;
37+
return *It;
38+
}
39+
2140
/// Metadata stored about a mapping of a declaration to a symbol.
2241
struct DylibVerifier::SymbolContext {
2342
// Name to use for all querying and verification
@@ -825,13 +844,13 @@ bool DylibVerifier::verifyBinaryAttrs(const ArrayRef<Target> ProvidedTargets,
825844
DylibTargets.push_back(RS->getTarget());
826845
const BinaryAttrs &BinInfo = RS->getBinaryAttrs();
827846
for (const StringRef LibName : BinInfo.RexportedLibraries)
828-
DylibReexports[LibName].set(DylibTargets.back().Arch);
847+
DylibReexports.getArchSet(LibName).set(DylibTargets.back().Arch);
829848
for (const StringRef LibName : BinInfo.AllowableClients)
830-
DylibClients[LibName].set(DylibTargets.back().Arch);
849+
DylibClients.getArchSet(LibName).set(DylibTargets.back().Arch);
831850
// Compare attributes that are only representable in >= TBD_V5.
832851
if (FT >= FileType::TBD_V5)
833852
for (const StringRef Name : BinInfo.RPaths)
834-
DylibRPaths[Name].set(DylibTargets.back().Arch);
853+
DylibRPaths.getArchSet(Name).set(DylibTargets.back().Arch);
835854
}
836855

837856
// Check targets first.
@@ -923,31 +942,33 @@ bool DylibVerifier::verifyBinaryAttrs(const ArrayRef<Target> ProvidedTargets,
923942
if (Provided == Dylib)
924943
return true;
925944

926-
for (const llvm::StringMapEntry<ArchitectureSet> &PAttr : Provided) {
927-
const auto DAttrIt = Dylib.find(PAttr.getKey());
928-
if (DAttrIt == Dylib.end()) {
929-
Ctx.Diag->Report(DiagID_missing) << "binary file" << PAttr;
945+
for (const LibAttrs::Entry &PEntry : Provided.get()) {
946+
const auto &[PAttr, PArchSet] = PEntry;
947+
auto DAttrEntry = Dylib.find(PAttr);
948+
if (!DAttrEntry) {
949+
Ctx.Diag->Report(DiagID_missing) << "binary file" << PEntry;
930950
if (Fatal)
931951
return false;
932952
}
933953

934-
if (PAttr.getValue() != DAttrIt->getValue()) {
935-
Ctx.Diag->Report(DiagID_mismatch) << PAttr << *DAttrIt;
954+
if (PArchSet != DAttrEntry->second) {
955+
Ctx.Diag->Report(DiagID_mismatch) << PEntry << *DAttrEntry;
936956
if (Fatal)
937957
return false;
938958
}
939959
}
940960

941-
for (const llvm::StringMapEntry<ArchitectureSet> &DAttr : Dylib) {
942-
const auto PAttrIt = Provided.find(DAttr.getKey());
943-
if (PAttrIt == Provided.end()) {
944-
Ctx.Diag->Report(DiagID_missing) << "installAPI option" << DAttr;
961+
for (const LibAttrs::Entry &DEntry : Dylib.get()) {
962+
const auto &[DAttr, DArchSet] = DEntry;
963+
const auto &PAttrEntry = Provided.find(DAttr);
964+
if (!PAttrEntry) {
965+
Ctx.Diag->Report(DiagID_missing) << "installAPI option" << DEntry;
945966
if (!Fatal)
946967
continue;
947968
return false;
948969
}
949970

950-
if (PAttrIt->getValue() != DAttr.getValue()) {
971+
if (PAttrEntry->second != DArchSet) {
951972
if (Fatal)
952973
llvm_unreachable("this case was already covered above.");
953974
}

clang/tools/clang-installapi/ClangInstallAPI.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,9 +170,9 @@ static bool run(ArrayRef<const char *> Args, const char *ProgName) {
170170
[&IF](
171171
const auto &Attrs,
172172
std::function<void(InterfaceFile *, StringRef, const Target &)> Add) {
173-
for (const auto &Lib : Attrs)
174-
for (const auto &T : IF.targets(Lib.getValue()))
175-
Add(&IF, Lib.getKey(), T);
173+
for (const auto &[Attr, ArchSet] : Attrs.get())
174+
for (const auto &T : IF.targets(ArchSet))
175+
Add(&IF, Attr, T);
176176
};
177177

178178
assignLibAttrs(Opts.LinkerOpts.AllowableClients,

clang/tools/clang-installapi/Options.cpp

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -610,35 +610,35 @@ Options::processAndFilterOutInstallAPIOptions(ArrayRef<const char *> Args) {
610610

611611
for (const Arg *A : ParsedArgs.filtered(OPT_allowable_client)) {
612612
auto It = ArgToArchMap.find(A);
613-
LinkerOpts.AllowableClients[A->getValue()] =
613+
LinkerOpts.AllowableClients.getArchSet(A->getValue()) =
614614
It != ArgToArchMap.end() ? It->second : ArchitectureSet();
615615
A->claim();
616616
}
617617

618618
for (const Arg *A : ParsedArgs.filtered(OPT_reexport_l)) {
619619
auto It = ArgToArchMap.find(A);
620-
LinkerOpts.ReexportedLibraries[A->getValue()] =
620+
LinkerOpts.ReexportedLibraries.getArchSet(A->getValue()) =
621621
It != ArgToArchMap.end() ? It->second : ArchitectureSet();
622622
A->claim();
623623
}
624624

625625
for (const Arg *A : ParsedArgs.filtered(OPT_reexport_library)) {
626626
auto It = ArgToArchMap.find(A);
627-
LinkerOpts.ReexportedLibraryPaths[A->getValue()] =
627+
LinkerOpts.ReexportedLibraryPaths.getArchSet(A->getValue()) =
628628
It != ArgToArchMap.end() ? It->second : ArchitectureSet();
629629
A->claim();
630630
}
631631

632632
for (const Arg *A : ParsedArgs.filtered(OPT_reexport_framework)) {
633633
auto It = ArgToArchMap.find(A);
634-
LinkerOpts.ReexportedFrameworks[A->getValue()] =
634+
LinkerOpts.ReexportedFrameworks.getArchSet(A->getValue()) =
635635
It != ArgToArchMap.end() ? It->second : ArchitectureSet();
636636
A->claim();
637637
}
638638

639639
for (const Arg *A : ParsedArgs.filtered(OPT_rpath)) {
640640
auto It = ArgToArchMap.find(A);
641-
LinkerOpts.RPaths[A->getValue()] =
641+
LinkerOpts.RPaths.getArchSet(A->getValue()) =
642642
It != ArgToArchMap.end() ? It->second : ArchitectureSet();
643643
A->claim();
644644
}
@@ -733,9 +733,9 @@ Options::Options(DiagnosticsEngine &Diag, FileManager *FM,
733733
llvm::for_each(DriverOpts.Targets,
734734
[&AllArchs](const auto &T) { AllArchs.set(T.first.Arch); });
735735
auto assignDefaultLibAttrs = [&AllArchs](LibAttrs &Attrs) {
736-
for (StringMapEntry<ArchitectureSet> &Entry : Attrs)
737-
if (Entry.getValue().empty())
738-
Entry.setValue(AllArchs);
736+
for (auto &[_, Archs] : Attrs.get())
737+
if (Archs.empty())
738+
Archs = AllArchs;
739739
};
740740
assignDefaultLibAttrs(LinkerOpts.AllowableClients);
741741
assignDefaultLibAttrs(LinkerOpts.ReexportedFrameworks);
@@ -789,7 +789,7 @@ std::pair<LibAttrs, ReexportedInterfaces> Options::getReexportedLibraries() {
789789
std::unique_ptr<InterfaceFile> Reexport = std::move(*ReexportIFOrErr);
790790
StringRef InstallName = Reexport->getInstallName();
791791
assert(!InstallName.empty() && "Parse error for install name");
792-
Reexports.insert({InstallName, Archs});
792+
Reexports.getArchSet(InstallName) = Archs;
793793
ReexportIFs.emplace_back(std::move(*Reexport));
794794
return true;
795795
};
@@ -802,39 +802,36 @@ std::pair<LibAttrs, ReexportedInterfaces> Options::getReexportedLibraries() {
802802
for (const PlatformType P : Platforms) {
803803
PathSeq PlatformSearchPaths = getPathsForPlatform(FEOpts.SystemFwkPaths, P);
804804
llvm::append_range(FwkSearchPaths, PlatformSearchPaths);
805-
for (const StringMapEntry<ArchitectureSet> &Lib :
806-
LinkerOpts.ReexportedFrameworks) {
807-
std::string Name = (Lib.getKey() + ".framework/" + Lib.getKey()).str();
805+
for (const auto &[Lib, Archs] : LinkerOpts.ReexportedFrameworks.get()) {
806+
std::string Name = (Lib + ".framework/" + Lib);
808807
std::string Path = findLibrary(Name, *FM, FwkSearchPaths, {}, {});
809808
if (Path.empty()) {
810-
Diags->Report(diag::err_cannot_find_reexport) << false << Lib.getKey();
809+
Diags->Report(diag::err_cannot_find_reexport) << false << Lib;
811810
return {};
812811
}
813812
if (DriverOpts.TraceLibraryLocation)
814813
errs() << Path << "\n";
815814

816-
AccumulateReexports(Path, Lib.getValue());
815+
AccumulateReexports(Path, Archs);
817816
}
818817
FwkSearchPaths.resize(FwkSearchPaths.size() - PlatformSearchPaths.size());
819818
}
820819

821-
for (const StringMapEntry<ArchitectureSet> &Lib :
822-
LinkerOpts.ReexportedLibraries) {
823-
std::string Name = "lib" + Lib.getKey().str() + ".dylib";
820+
for (const auto &[Lib, Archs] : LinkerOpts.ReexportedLibraries.get()) {
821+
std::string Name = "lib" + Lib + ".dylib";
824822
std::string Path = findLibrary(Name, *FM, {}, LinkerOpts.LibPaths, {});
825823
if (Path.empty()) {
826-
Diags->Report(diag::err_cannot_find_reexport) << true << Lib.getKey();
824+
Diags->Report(diag::err_cannot_find_reexport) << true << Lib;
827825
return {};
828826
}
829827
if (DriverOpts.TraceLibraryLocation)
830828
errs() << Path << "\n";
831829

832-
AccumulateReexports(Path, Lib.getValue());
830+
AccumulateReexports(Path, Archs);
833831
}
834832

835-
for (const StringMapEntry<ArchitectureSet> &Lib :
836-
LinkerOpts.ReexportedLibraryPaths)
837-
AccumulateReexports(Lib.getKey(), Lib.getValue());
833+
for (const auto &[Lib, Archs] : LinkerOpts.ReexportedLibraryPaths.get())
834+
AccumulateReexports(Lib, Archs);
838835

839836
return {std::move(Reexports), std::move(ReexportIFs)};
840837
}

0 commit comments

Comments
 (0)