Skip to content

Commit d095c68

Browse files
cyndyishidaZijunZhaoCCK
authored andcommitted
[TextAPI] Consolidate TextAPI Reader/Writer APIs. (llvm#66108)
Both Swift & LLD use TextAPI reader/writer apis to interface with TBD files. Add doc strings to document what each API does. Also, add shortcut APIs for validating input is a TBD file. This reduces the differences between downstream and how tapi calls into these APIs.
1 parent 2ba27e4 commit d095c68

File tree

9 files changed

+87
-45
lines changed

9 files changed

+87
-45
lines changed

llvm/include/llvm/Object/TapiFile.h

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,12 @@
2020
#include "llvm/Support/Error.h"
2121
#include "llvm/Support/MemoryBufferRef.h"
2222
#include "llvm/TextAPI/Architecture.h"
23+
#include "llvm/TextAPI/InterfaceFile.h"
2324

2425
namespace llvm {
2526

2627
class raw_ostream;
2728

28-
namespace MachO {
29-
30-
class InterfaceFile;
31-
32-
}
33-
3429
namespace object {
3530

3631
class TapiFile : public SymbolicFile {
@@ -51,6 +46,8 @@ class TapiFile : public SymbolicFile {
5146

5247
Expected<SymbolRef::Type> getSymbolType(DataRefImpl DRI) const;
5348

49+
bool hasSegmentInfo() { return FileKind >= MachO::FileType::TBD_V5; }
50+
5451
static bool classof(const Binary *v) { return v->isTapiFile(); }
5552

5653
bool is64Bit() const override { return MachO::is64Bit(Arch); }
@@ -69,6 +66,7 @@ class TapiFile : public SymbolicFile {
6966

7067
std::vector<Symbol> Symbols;
7168
MachO::Architecture Arch;
69+
MachO::FileType FileKind;
7270
};
7371

7472
} // end namespace object.

llvm/include/llvm/TextAPI/TextAPIReader.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,23 @@ class MemoryBufferRef;
1818
namespace MachO {
1919

2020
class InterfaceFile;
21+
enum FileType : unsigned;
2122

2223
class TextAPIReader {
2324
public:
25+
/// Determine whether input can be interpreted as TAPI text file.
26+
/// This allows one to exit early when file is not recognized as TAPI file
27+
/// as opposed to `get` which attempts to full parse and load of library
28+
/// attributes.
29+
///
30+
/// \param InputBuffer Buffer holding contents of TAPI text file.
31+
/// \return The file format version of TAPI text file.
32+
static Expected<FileType> canRead(MemoryBufferRef InputBuffer);
33+
34+
/// Parse and get an InterfaceFile that represents the full
35+
/// library.
36+
///
37+
/// \param InputBuffer Buffer holding contents of TAPI text file.
2438
static Expected<std::unique_ptr<InterfaceFile>>
2539
get(MemoryBufferRef InputBuffer);
2640

llvm/include/llvm/TextAPI/TextAPIWriter.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,28 @@
99
#ifndef LLVM_TEXTAPI_TEXTAPIWRITER_H
1010
#define LLVM_TEXTAPI_TEXTAPIWRITER_H
1111

12+
#include "llvm/TextAPI/InterfaceFile.h"
13+
1214
namespace llvm {
1315

1416
class Error;
1517
class raw_ostream;
1618

1719
namespace MachO {
1820

19-
class InterfaceFile;
20-
2121
class TextAPIWriter {
2222
public:
2323
TextAPIWriter() = delete;
2424

25+
/// Write TAPI text file contents into stream.
26+
///
27+
/// \param OS Stream to write to.
28+
/// \param File Library attributes to write as text file.
29+
/// \param FileKind File format to write text file as. If not specified, it
30+
/// will read from File.
31+
/// \param Compact Whether to limit whitespace in text file.
2532
static Error writeToStream(raw_ostream &OS, const InterfaceFile &File,
33+
const FileType FileKind = FileType::Invalid,
2634
bool Compact = false);
2735
};
2836

llvm/lib/Object/TapiFile.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ static SymbolRef::Type getType(const Symbol *Sym) {
4949

5050
TapiFile::TapiFile(MemoryBufferRef Source, const InterfaceFile &Interface,
5151
Architecture Arch)
52-
: SymbolicFile(ID_TapiFile, Source), Arch(Arch) {
52+
: SymbolicFile(ID_TapiFile, Source), Arch(Arch),
53+
FileKind(Interface.getFileType()) {
5354
for (const auto *Symbol : Interface.symbols()) {
5455
if (!Symbol->getArchitectures().has(Arch))
5556
continue;

llvm/lib/TextAPI/TextStub.cpp

Lines changed: 40 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,11 @@ template <> struct MappingTraits<const InterfaceFile *> {
620620
!(Flags & TBDFlags::NotApplicationExtensionSafe));
621621
}
622622

623+
// For older file formats, the segment where the symbol
624+
// comes from is unknown, treat all symbols as Data
625+
// in these cases.
626+
const auto Flags = SymbolFlags::Data;
627+
623628
for (const auto &Section : Exports) {
624629
const auto Targets =
625630
synthesizeTargets(Section.Architectures, Platforms);
@@ -634,26 +639,27 @@ template <> struct MappingTraits<const InterfaceFile *> {
634639

635640
for (const auto &Symbol : Section.Symbols) {
636641
if (Ctx->FileKind != FileType::TBD_V3 &&
637-
Symbol.value.startswith("_OBJC_EHTYPE_$_"))
642+
Symbol.value.startswith(ObjC2EHTypePrefix))
638643
File->addSymbol(SymbolKind::ObjectiveCClassEHType,
639-
Symbol.value.drop_front(15), Targets);
644+
Symbol.value.drop_front(15), Targets, Flags);
640645
else
641-
File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets);
646+
File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets, Flags);
642647
}
643648
for (auto &Symbol : Section.Classes) {
644649
auto Name = Symbol.value;
645650
if (Ctx->FileKind != FileType::TBD_V3)
646651
Name = Name.drop_front();
647-
File->addSymbol(SymbolKind::ObjectiveCClass, Name, Targets);
652+
File->addSymbol(SymbolKind::ObjectiveCClass, Name, Targets, Flags);
648653
}
649654
for (auto &Symbol : Section.ClassEHs)
650-
File->addSymbol(SymbolKind::ObjectiveCClassEHType, Symbol, Targets);
655+
File->addSymbol(SymbolKind::ObjectiveCClassEHType, Symbol, Targets,
656+
Flags);
651657
for (auto &Symbol : Section.IVars) {
652658
auto Name = Symbol.value;
653659
if (Ctx->FileKind != FileType::TBD_V3)
654660
Name = Name.drop_front();
655-
File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, Name,
656-
Targets);
661+
File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, Name, Targets,
662+
Flags);
657663
}
658664
for (auto &Symbol : Section.WeakDefSymbols)
659665
File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets,
@@ -668,34 +674,35 @@ template <> struct MappingTraits<const InterfaceFile *> {
668674
synthesizeTargets(Section.Architectures, Platforms);
669675
for (auto &Symbol : Section.Symbols) {
670676
if (Ctx->FileKind != FileType::TBD_V3 &&
671-
Symbol.value.startswith("_OBJC_EHTYPE_$_"))
677+
Symbol.value.startswith(ObjC2EHTypePrefix))
672678
File->addSymbol(SymbolKind::ObjectiveCClassEHType,
673679
Symbol.value.drop_front(15), Targets,
674-
SymbolFlags::Undefined);
680+
SymbolFlags::Undefined | Flags);
675681
else
676682
File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets,
677-
SymbolFlags::Undefined);
683+
SymbolFlags::Undefined | Flags);
678684
}
679685
for (auto &Symbol : Section.Classes) {
680686
auto Name = Symbol.value;
681687
if (Ctx->FileKind != FileType::TBD_V3)
682688
Name = Name.drop_front();
683689
File->addSymbol(SymbolKind::ObjectiveCClass, Name, Targets,
684-
SymbolFlags::Undefined);
690+
SymbolFlags::Undefined | Flags);
685691
}
686692
for (auto &Symbol : Section.ClassEHs)
687693
File->addSymbol(SymbolKind::ObjectiveCClassEHType, Symbol, Targets,
688-
SymbolFlags::Undefined);
694+
SymbolFlags::Undefined | Flags);
689695
for (auto &Symbol : Section.IVars) {
690696
auto Name = Symbol.value;
691697
if (Ctx->FileKind != FileType::TBD_V3)
692698
Name = Name.drop_front();
693699
File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, Name, Targets,
694-
SymbolFlags::Undefined);
700+
SymbolFlags::Undefined | Flags);
695701
}
696702
for (auto &Symbol : Section.WeakRefSymbols)
697703
File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets,
698-
SymbolFlags::Undefined | SymbolFlags::WeakReferenced);
704+
SymbolFlags::Undefined | SymbolFlags::WeakReferenced |
705+
Flags);
699706
}
700707

701708
return File;
@@ -906,7 +913,12 @@ template <> struct MappingTraits<const InterfaceFile *> {
906913
}
907914

908915
auto handleSymbols = [File](const SectionList &CurrentSections,
909-
SymbolFlags Flag = SymbolFlags::None) {
916+
SymbolFlags InputFlag = SymbolFlags::None) {
917+
// For older file formats, the segment where the symbol
918+
// comes from is unknown, treat all symbols as Data
919+
// in these cases.
920+
const SymbolFlags Flag = InputFlag | SymbolFlags::Data;
921+
910922
for (const auto &CurrentSection : CurrentSections) {
911923
for (auto &sym : CurrentSection.Symbols)
912924
File->addSymbol(SymbolKind::GlobalSymbol, sym,
@@ -924,9 +936,10 @@ template <> struct MappingTraits<const InterfaceFile *> {
924936
File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, sym,
925937
CurrentSection.Targets, Flag);
926938

927-
SymbolFlags SymFlag = (Flag == SymbolFlags::Undefined)
928-
? SymbolFlags::WeakReferenced
929-
: SymbolFlags::WeakDefined;
939+
SymbolFlags SymFlag =
940+
((Flag & SymbolFlags::Undefined) == SymbolFlags::Undefined)
941+
? SymbolFlags::WeakReferenced
942+
: SymbolFlags::WeakDefined;
930943
for (auto &sym : CurrentSection.WeakSymbols) {
931944
File->addSymbol(SymbolKind::GlobalSymbol, sym,
932945
CurrentSection.Targets, Flag | SymFlag);
@@ -1078,9 +1091,7 @@ static void DiagHandler(const SMDiagnostic &Diag, void *Context) {
10781091
File->ErrorMessage = ("malformed file\n" + Message).str();
10791092
}
10801093

1081-
namespace {
1082-
1083-
Expected<FileType> canReadFileType(MemoryBufferRef InputBuffer) {
1094+
Expected<FileType> TextAPIReader::canRead(MemoryBufferRef InputBuffer) {
10841095
auto TAPIFile = InputBuffer.getBuffer().trim();
10851096
if (TAPIFile.startswith("{") && TAPIFile.endswith("}"))
10861097
return FileType::TBD_V5;
@@ -1103,13 +1114,12 @@ Expected<FileType> canReadFileType(MemoryBufferRef InputBuffer) {
11031114

11041115
return createStringError(std::errc::not_supported, "unsupported file type");
11051116
}
1106-
} // namespace
11071117

11081118
Expected<std::unique_ptr<InterfaceFile>>
11091119
TextAPIReader::get(MemoryBufferRef InputBuffer) {
11101120
TextAPIContext Ctx;
11111121
Ctx.Path = std::string(InputBuffer.getBufferIdentifier());
1112-
if (auto FTOrErr = canReadFileType(InputBuffer))
1122+
if (auto FTOrErr = canRead(InputBuffer))
11131123
Ctx.FileKind = *FTOrErr;
11141124
else
11151125
return FTOrErr.takeError();
@@ -1145,14 +1155,18 @@ TextAPIReader::get(MemoryBufferRef InputBuffer) {
11451155
}
11461156

11471157
Error TextAPIWriter::writeToStream(raw_ostream &OS, const InterfaceFile &File,
1148-
bool Compact) {
1158+
const FileType FileKind, bool Compact) {
11491159
TextAPIContext Ctx;
11501160
Ctx.Path = std::string(File.getPath());
1151-
Ctx.FileKind = File.getFileType();
1161+
1162+
// Prefer parameter for format if passed, otherwise fallback to the File
1163+
// FileType.
1164+
Ctx.FileKind =
1165+
(FileKind == FileType::Invalid) ? File.getFileType() : FileKind;
11521166

11531167
// Write out in JSON format.
11541168
if (Ctx.FileKind >= FileType::TBD_V5) {
1155-
return serializeInterfaceFileToJSON(OS, File, Compact);
1169+
return serializeInterfaceFileToJSON(OS, File, Ctx.FileKind, Compact);
11561170
}
11571171

11581172
llvm::yaml::Output YAMLOut(OS, &Ctx, /*WrapColumn=*/80);

llvm/lib/TextAPI/TextStubCommon.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ Expected<std::unique_ptr<InterfaceFile>>
4848
getInterfaceFileFromJSON(StringRef JSON);
4949

5050
Error serializeInterfaceFileToJSON(raw_ostream &OS, const InterfaceFile &File,
51-
bool Compact);
51+
const FileType FileKind, bool Compact);
5252
} // namespace MachO
5353

5454
namespace yaml {

llvm/lib/TextAPI/TextStubV5.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -986,9 +986,8 @@ Expected<Object> serializeIF(const InterfaceFile *File) {
986986
return std::move(Library);
987987
}
988988

989-
Expected<Object> getJSON(const InterfaceFile *File) {
990-
assert(File->getFileType() == FileType::TBD_V5 &&
991-
"unexpected json file format version");
989+
Expected<Object> getJSON(const InterfaceFile *File, const FileType FileKind) {
990+
assert(FileKind == FileType::TBD_V5 && "unexpected json file format version");
992991
Object Root;
993992

994993
auto MainLibOrErr = serializeIF(File);
@@ -1012,8 +1011,9 @@ Expected<Object> getJSON(const InterfaceFile *File) {
10121011

10131012
Error MachO::serializeInterfaceFileToJSON(raw_ostream &OS,
10141013
const InterfaceFile &File,
1014+
const FileType FileKind,
10151015
bool Compact) {
1016-
auto TextFile = getJSON(&File);
1016+
auto TextFile = getJSON(&File, FileKind);
10171017
if (!TextFile)
10181018
return TextFile.takeError();
10191019
if (Compact)

llvm/tools/llvm-nm/llvm-nm.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,10 +1023,12 @@ static char getSymbolNMTypeChar(MachOObjectFile &Obj, basic_symbol_iterator I) {
10231023
static char getSymbolNMTypeChar(TapiFile &Obj, basic_symbol_iterator I) {
10241024
auto Type = cantFail(Obj.getSymbolType(I->getRawDataRefImpl()));
10251025
switch (Type) {
1026-
case SymbolRef::ST_Data:
1027-
return 'd';
10281026
case SymbolRef::ST_Function:
10291027
return 't';
1028+
case SymbolRef::ST_Data:
1029+
if (Obj.hasSegmentInfo())
1030+
return 'd';
1031+
[[fallthrough]];
10301032
default:
10311033
return 's';
10321034
}

llvm/unittests/TextAPI/TextStubV5Tests.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -185,11 +185,15 @@ TEST(TBDv5, ReadFile) {
185185
"libraries": []
186186
})";
187187

188-
Expected<TBDFile> Result =
189-
TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd"));
188+
MemoryBufferRef InputBuf = MemoryBufferRef(TBDv5File, "Test.tbd");
189+
Expected<FileType> ExpectedFT = TextAPIReader::canRead(InputBuf);
190+
EXPECT_TRUE(!!ExpectedFT);
191+
192+
Expected<TBDFile> Result = TextAPIReader::get(InputBuf);
190193
EXPECT_TRUE(!!Result);
191194
TBDFile File = std::move(Result.get());
192195
EXPECT_EQ(FileType::TBD_V5, File->getFileType());
196+
EXPECT_EQ(*ExpectedFT, File->getFileType());
193197
EXPECT_EQ(std::string("/S/L/F/Foo.framework/Foo"), File->getInstallName());
194198

195199
TargetList AllTargets = {
@@ -915,7 +919,8 @@ TEST(TBDv5, WriteMultipleDocuments) {
915919
// against TBDv5File.
916920
SmallString<4096> Buffer;
917921
raw_svector_ostream OS(Buffer);
918-
Error Result = TextAPIWriter::writeToStream(OS, File, /*Compact=*/true);
922+
Error Result = TextAPIWriter::writeToStream(OS, File, FileType::Invalid,
923+
/*Compact=*/true);
919924
EXPECT_FALSE(Result);
920925

921926
Expected<TBDFile> Input =

0 commit comments

Comments
 (0)