[llvm] 38013ad - [TextAPI] Add option to filter out unsupported/unknown/invalid targets (#195161)
via llvm-commits
llvm-commits at lists.llvm.org
Mon May 4 08:56:31 PDT 2026
Author: Cyndy Ishida
Date: 2026-05-04T08:56:25-07:00
New Revision: 38013ad8fe94c62641e246079f74db0747fb4bf2
URL: https://github.com/llvm/llvm-project/commit/38013ad8fe94c62641e246079f74db0747fb4bf2
DIFF: https://github.com/llvm/llvm-project/commit/38013ad8fe94c62641e246079f74db0747fb4bf2.diff
LOG: [TextAPI] Add option to filter out unsupported/unknown/invalid targets (#195161)
Pipe `SkipUnknownTriples` flag through TBD file YAML and v5 JSON
parsers.
When set, target strings with an unknown architecture or platform are
dropped from the parsed `InterfaceFile` instead of producing a fatal
parse error.
Additionally, "unknown architecture"/"unknown platform" parse errors are
collapsed into a single "unknown target" message.
resolves: rdar://175690963
Added:
Modified:
llvm/include/llvm/Object/TapiUniversal.h
llvm/include/llvm/TextAPI/Target.h
llvm/include/llvm/TextAPI/TextAPIReader.h
llvm/lib/Object/TapiUniversal.cpp
llvm/lib/TextAPI/TextAPIContext.h
llvm/lib/TextAPI/TextStub.cpp
llvm/lib/TextAPI/TextStubV5.cpp
llvm/unittests/TextAPI/TextStubHelpers.h
llvm/unittests/TextAPI/TextStubV3Tests.cpp
llvm/unittests/TextAPI/TextStubV4Tests.cpp
llvm/unittests/TextAPI/TextStubV5Tests.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/Object/TapiUniversal.h b/llvm/include/llvm/Object/TapiUniversal.h
index 3cc2060dc46ec..92df5e3ed42a7 100644
--- a/llvm/include/llvm/Object/TapiUniversal.h
+++ b/llvm/include/llvm/Object/TapiUniversal.h
@@ -90,9 +90,9 @@ class LLVM_ABI TapiUniversal : public Binary {
}
};
- TapiUniversal(MemoryBufferRef Source, Error &Err);
+ TapiUniversal(MemoryBufferRef Source, bool SkipUnknownTriples, Error &Err);
static Expected<std::unique_ptr<TapiUniversal>>
- create(MemoryBufferRef Source);
+ create(MemoryBufferRef Source, bool SkipUnknownTriples = false);
~TapiUniversal() override;
object_iterator begin_objects() const { return ObjectForArch(this, 0); }
diff --git a/llvm/include/llvm/TextAPI/Target.h b/llvm/include/llvm/TextAPI/Target.h
index 5cc507fe21f78..5f2b4a1f02553 100644
--- a/llvm/include/llvm/TextAPI/Target.h
+++ b/llvm/include/llvm/TextAPI/Target.h
@@ -38,6 +38,10 @@ class Target {
LLVM_ABI static llvm::Expected<Target> create(StringRef Target);
+ LLVM_ABI bool isValid() const {
+ return Arch != AK_unknown && Platform != PLATFORM_UNKNOWN;
+ }
+
LLVM_ABI operator std::string() const;
Architecture Arch;
diff --git a/llvm/include/llvm/TextAPI/TextAPIReader.h b/llvm/include/llvm/TextAPI/TextAPIReader.h
index 603b24b47283d..b2de31d82ccbb 100644
--- a/llvm/include/llvm/TextAPI/TextAPIReader.h
+++ b/llvm/include/llvm/TextAPI/TextAPIReader.h
@@ -36,8 +36,9 @@ class TextAPIReader {
/// library.
///
/// \param InputBuffer Buffer holding contents of TAPI text file.
+ /// \param SkipUnknownTriples Whether to ignore unknown or invalid triples.
LLVM_ABI static Expected<std::unique_ptr<InterfaceFile>>
- get(MemoryBufferRef InputBuffer);
+ get(MemoryBufferRef InputBuffer, bool SkipUnknownTriples = false);
TextAPIReader() = delete;
};
diff --git a/llvm/lib/Object/TapiUniversal.cpp b/llvm/lib/Object/TapiUniversal.cpp
index 52f3a04d088f5..6ed7c27e0ce53 100644
--- a/llvm/lib/Object/TapiUniversal.cpp
+++ b/llvm/lib/Object/TapiUniversal.cpp
@@ -19,9 +19,11 @@ using namespace llvm;
using namespace MachO;
using namespace object;
-TapiUniversal::TapiUniversal(MemoryBufferRef Source, Error &Err)
+TapiUniversal::TapiUniversal(MemoryBufferRef Source, bool SkipUnknownTriples,
+ Error &Err)
: Binary(ID_TapiUniversal, Source) {
- Expected<std::unique_ptr<InterfaceFile>> Result = TextAPIReader::get(Source);
+ Expected<std::unique_ptr<InterfaceFile>> Result =
+ TextAPIReader::get(Source, SkipUnknownTriples);
ErrorAsOutParameter ErrAsOuParam(Err);
if (!Result) {
Err = Result.takeError();
@@ -60,9 +62,10 @@ TapiUniversal::ObjectForArch::getAsObjectFile() const {
}
Expected<std::unique_ptr<TapiUniversal>>
-TapiUniversal::create(MemoryBufferRef Source) {
+TapiUniversal::create(MemoryBufferRef Source, bool SkipUnknownTriples) {
Error Err = Error::success();
- std::unique_ptr<TapiUniversal> Ret(new TapiUniversal(Source, Err));
+ std::unique_ptr<TapiUniversal> Ret(
+ new TapiUniversal(Source, SkipUnknownTriples, Err));
if (Err)
return std::move(Err);
return std::move(Ret);
diff --git a/llvm/lib/TextAPI/TextAPIContext.h b/llvm/lib/TextAPI/TextAPIContext.h
index 3151db7b6b80e..a54553186775e 100644
--- a/llvm/lib/TextAPI/TextAPIContext.h
+++ b/llvm/lib/TextAPI/TextAPIContext.h
@@ -23,6 +23,7 @@ struct TextAPIContext {
std::string ErrorMessage;
std::string Path;
FileType FileKind;
+ bool SkipUnknownTriples;
};
} // end namespace MachO.
diff --git a/llvm/lib/TextAPI/TextStub.cpp b/llvm/lib/TextAPI/TextStub.cpp
index be9be07a2aa0f..e5b714ef88237 100644
--- a/llvm/lib/TextAPI/TextStub.cpp
+++ b/llvm/lib/TextAPI/TextStub.cpp
@@ -13,6 +13,7 @@
#include "TextAPIContext.h"
#include "TextStubCommon.h"
#include "llvm/ADT/BitmaskEnum.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Allocator.h"
@@ -313,6 +314,12 @@ template <> struct MappingTraits<UndefinedSection> {
template <> struct MappingTraits<SymbolSection> {
static void mapping(IO &IO, SymbolSection &Section) {
IO.mapRequired("targets", Section.Targets);
+ // With SkipUnknownTriples, ScalarTraits of Target accepts unknown
+ // arch/platform scalars without erroring, leaving invalid Targets in the
+ // vector. Drop them so downstream code only sees valid Targets.
+ if (!IO.outputting())
+ llvm::erase_if(Section.Targets,
+ [](const Target &T) { return !T.isValid(); });
IO.mapOptional("symbols", Section.Symbols);
IO.mapOptional("objc-classes", Section.Classes);
IO.mapOptional("objc-eh-types", Section.ClassEHs);
@@ -325,6 +332,9 @@ template <> struct MappingTraits<SymbolSection> {
template <> struct MappingTraits<UmbrellaSection> {
static void mapping(IO &IO, UmbrellaSection &Section) {
IO.mapRequired("targets", Section.Targets);
+ if (!IO.outputting())
+ llvm::erase_if(Section.Targets,
+ [](const Target &T) { return !T.isValid(); });
IO.mapRequired("umbrella", Section.Umbrella);
}
};
@@ -341,6 +351,9 @@ struct MappingContextTraits<MetadataSection, MetadataSection::Option> {
static void mapping(IO &IO, MetadataSection &Section,
MetadataSection::Option &OptionKind) {
IO.mapRequired("targets", Section.Targets);
+ if (!IO.outputting())
+ llvm::erase_if(Section.Targets,
+ [](const Target &T) { return !T.isValid(); });
switch (OptionKind) {
case MetadataSection::Option::Clients:
IO.mapRequired("clients", Section.Values);
@@ -377,7 +390,7 @@ template <> struct ScalarTraits<Target> {
}
}
- static StringRef input(StringRef Scalar, void *, Target &Value) {
+ static StringRef input(StringRef Scalar, void *Ctx, Target &Value) {
auto Result = Target::create(Scalar);
if (!Result) {
consumeError(Result.takeError());
@@ -385,10 +398,11 @@ template <> struct ScalarTraits<Target> {
}
Value = *Result;
- if (Value.Arch == AK_unknown)
- return "unknown architecture";
- if (Value.Platform == PLATFORM_UNKNOWN)
- return "unknown platform";
+
+ const bool SkipUnknownTriples =
+ reinterpret_cast<TextAPIContext *>(Ctx)->SkipUnknownTriples;
+ if (!Value.isValid() && !SkipUnknownTriples)
+ return "unknown target";
return {};
}
@@ -563,7 +577,10 @@ template <> struct MappingTraits<const InterfaceFile *> {
if ((Architecture == AK_i386) && (Platform == PLATFORM_MACCATALYST))
continue;
- Targets.emplace_back(Architecture, Platform);
+ Target T(Architecture, Platform);
+ if (!T.isValid())
+ continue;
+ Targets.push_back(T);
}
}
return Targets;
@@ -602,6 +619,8 @@ template <> struct MappingTraits<const InterfaceFile *> {
for (const auto &Section : Exports) {
const auto Targets =
synthesizeTargets(Section.Architectures, Platforms);
+ if (Targets.empty())
+ continue;
for (const auto &Lib : Section.AllowableClients)
for (const auto &Target : Targets)
@@ -646,6 +665,8 @@ template <> struct MappingTraits<const InterfaceFile *> {
for (const auto &Section : Undefineds) {
const auto Targets =
synthesizeTargets(Section.Architectures, Platforms);
+ if (Targets.empty())
+ continue;
for (auto &Symbol : Section.Symbols) {
if (Ctx->FileKind != FileType::TBD_V3 &&
Symbol.value.starts_with(ObjC2EHTypePrefix))
@@ -769,8 +790,9 @@ template <> struct MappingTraits<const InterfaceFile *> {
auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());
assert(Ctx);
TBDVersion = Ctx->FileKind >> 4;
- Targets.insert(Targets.begin(), File->targets().begin(),
- File->targets().end());
+ for (auto &T : File->targets())
+ if (T.isValid())
+ Targets.push_back(T);
InstallName = File->getInstallName();
CurrentVersion = File->getCurrentVersion();
CompatibilityVersion = File->getCompatibilityVersion();
@@ -789,7 +811,8 @@ template <> struct MappingTraits<const InterfaceFile *> {
{
std::map<std::string, TargetList> valueToTargetList;
for (const auto &it : File->umbrellas())
- valueToTargetList[it.second].emplace_back(it.first);
+ if (it.first.isValid())
+ valueToTargetList[it.second].emplace_back(it.first);
for (const auto &it : valueToTargetList) {
UmbrellaSection CurrentSection;
@@ -809,7 +832,11 @@ template <> struct MappingTraits<const InterfaceFile *> {
std::set<TargetList> TargetSet;
std::map<const Symbol *, TargetList> SymbolToTargetList;
for (const auto *Symbol : Symbols) {
- TargetList Targets(Symbol->targets());
+ TargetList Targets;
+ for (auto &T : Symbol->targets())
+ if (T.isValid())
+ Targets.push_back(T);
+
SymbolToTargetList[Symbol] = Targets;
TargetSet.emplace(std::move(Targets));
}
@@ -899,6 +926,9 @@ template <> struct MappingTraits<const InterfaceFile *> {
const SymbolFlags Flag = InputFlag | SymbolFlags::Data;
for (const auto &CurrentSection : CurrentSections) {
+ if (CurrentSection.Targets.empty())
+ continue;
+
for (auto &sym : CurrentSection.Symbols)
File->addSymbol(EncodeKind::GlobalSymbol, sym,
CurrentSection.Targets, Flag);
@@ -1019,6 +1049,9 @@ template <> struct MappingTraits<const InterfaceFile *> {
IO.mapTag("!tapi-tbd", true);
IO.mapRequired("tbd-version", Keys->TBDVersion);
IO.mapRequired("targets", Keys->Targets);
+ if (!IO.outputting())
+ llvm::erase_if(Keys->Targets,
+ [](const Target &T) { return !T.isValid(); });
IO.mapOptional("uuids", EmptyUUID);
IO.mapOptional("flags", Keys->Flags, TBDFlags::None);
IO.mapRequired("install-name", Keys->InstallName);
@@ -1095,8 +1128,10 @@ Expected<FileType> TextAPIReader::canRead(MemoryBufferRef InputBuffer) {
}
Expected<std::unique_ptr<InterfaceFile>>
-TextAPIReader::get(MemoryBufferRef InputBuffer) {
+TextAPIReader::get(MemoryBufferRef InputBuffer, bool SkipUnknownTriples) {
TextAPIContext Ctx;
+
+ Ctx.SkipUnknownTriples = SkipUnknownTriples;
Ctx.Path = std::string(InputBuffer.getBufferIdentifier());
if (auto FTOrErr = canRead(InputBuffer))
Ctx.FileKind = *FTOrErr;
diff --git a/llvm/lib/TextAPI/TextStubV5.cpp b/llvm/lib/TextAPI/TextStubV5.cpp
index de40d84f5e7a6..2fb74798bb72b 100644
--- a/llvm/lib/TextAPI/TextStubV5.cpp
+++ b/llvm/lib/TextAPI/TextStubV5.cpp
@@ -12,6 +12,7 @@
#include "TextStubCommon.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/JSON.h"
+#include <optional>
#include <utility>
// clang-format off
@@ -279,6 +280,15 @@ Expected<FileType> getVersion(const Object *File) {
return *VersionOrErr;
}
+Expected<std::optional<MachO::Target>> parseTargetStr(StringRef Str) {
+ auto TargetOrErr = MachO::Target::create(Str);
+ if (!TargetOrErr)
+ return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
+ if (!TargetOrErr->isValid())
+ return std::nullopt;
+ return *TargetOrErr;
+}
+
Expected<TargetList> getTargets(const Object *Section) {
const auto *Targets = Section->getArray(Keys[TBDKey::Targets]);
if (!Targets)
@@ -289,10 +299,12 @@ Expected<TargetList> getTargets(const Object *Section) {
auto TargetStr = JSONTarget.getAsString();
if (!TargetStr.has_value())
return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
- auto TargetOrErr = Target::create(TargetStr.value());
+ auto TargetOrErr = parseTargetStr(TargetStr.value());
if (!TargetOrErr)
- return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
- IFTargets.push_back(*TargetOrErr);
+ return TargetOrErr.takeError();
+ if (!TargetOrErr->has_value())
+ continue;
+ IFTargets.push_back(**TargetOrErr);
}
return std::move(IFTargets);
}
@@ -311,20 +323,22 @@ Expected<TargetList> getTargetsSection(const Object *Section) {
getRequiredValue<StringRef>(TBDKey::Target, Obj, &Object::getString);
if (!TargetStr)
return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
- auto TargetOrErr = Target::create(*TargetStr);
+ auto TargetOrErr = parseTargetStr(*TargetStr);
if (!TargetOrErr)
- return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
+ return TargetOrErr.takeError();
+ if (!TargetOrErr->has_value())
+ continue;
auto VersionStr = Obj->getString(Keys[TBDKey::Deployment]);
VersionTuple Version;
if (VersionStr && Version.tryParse(*VersionStr))
return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Deployment));
- TargetOrErr->MinDeployment = Version;
+ (*TargetOrErr)->MinDeployment = Version;
// Convert to LLVM::Triple to accurately compute minOS + platform + arch
// pairing.
IFTargets.push_back(
- MachO::Target(Triple(getTargetTripleName(*TargetOrErr))));
+ MachO::Target(Triple(getTargetTripleName(**TargetOrErr))));
}
return std::move(IFTargets);
}
@@ -701,15 +715,24 @@ Expected<IFPtr> parseToInterfaceFile(const Object *File) {
for (auto &[Path, Targets] : RPaths)
for (auto Target : Targets)
F->addRPath(Path, Target);
- for (auto &[Targets, Symbols] : Exports)
+ for (auto &[Targets, Symbols] : Exports) {
+ if (Targets.empty())
+ continue;
for (auto &Sym : Symbols)
F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);
- for (auto &[Targets, Symbols] : Reexports)
+ }
+ for (auto &[Targets, Symbols] : Reexports) {
+ if (Targets.empty())
+ continue;
for (auto &Sym : Symbols)
F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);
- for (auto &[Targets, Symbols] : Undefineds)
+ }
+ for (auto &[Targets, Symbols] : Undefineds) {
+ if (Targets.empty())
+ continue;
for (auto &Sym : Symbols)
F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);
+ }
return std::move(F);
}
diff --git a/llvm/unittests/TextAPI/TextStubHelpers.h b/llvm/unittests/TextAPI/TextStubHelpers.h
index 87ca7e1c0b4d4..74b6ec3fa3790 100644
--- a/llvm/unittests/TextAPI/TextStubHelpers.h
+++ b/llvm/unittests/TextAPI/TextStubHelpers.h
@@ -6,6 +6,7 @@
//
//===-----------------------------------------------------------------------===/
+#include "llvm/ADT/DenseSet.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/TextAPI/InterfaceFile.h"
#include <string>
diff --git a/llvm/unittests/TextAPI/TextStubV3Tests.cpp b/llvm/unittests/TextAPI/TextStubV3Tests.cpp
index 1da918f2df9e0..3c822b2188a41 100644
--- a/llvm/unittests/TextAPI/TextStubV3Tests.cpp
+++ b/llvm/unittests/TextAPI/TextStubV3Tests.cpp
@@ -937,4 +937,52 @@ TEST(TBDv3, InterfaceInequality) {
}));
}
+TEST(TBDv3, SkipUnknownArch) {
+ static const char TBDv3WithUnknownArch[] = "--- !tapi-tbd-v3\n"
+ "archs: [ arm64, foo ]\n"
+ "platform: ios\n"
+ "install-name: Test.dylib\n"
+ "exports:\n"
+ " - archs: [ arm64 ]\n"
+ " symbols: [ _knownSym ]\n"
+ " - archs: [ foo ]\n"
+ " symbols: [ _unknownSym ]\n"
+ " - archs: [ arm64, foo ]\n"
+ " symbols: [ _mixedSym ]\n"
+ "...\n";
+
+ Expected<TBDFile> Result =
+ TextAPIReader::get(MemoryBufferRef(TBDv3WithUnknownArch, "Test.tbd"),
+ /*SkipUnknownTriples=*/true);
+ EXPECT_TRUE(!!Result);
+ TBDFile File = std::move(Result.get());
+
+ EXPECT_EQ(ArchitectureSet(AK_arm64), File->getArchitectures());
+
+ llvm::DenseSet<StringRef> SymbolNames;
+ for (const auto *Sym : File->exports())
+ SymbolNames.insert(Sym->getName());
+
+ EXPECT_TRUE(SymbolNames.count("_knownSym"));
+ EXPECT_TRUE(SymbolNames.count("_mixedSym"));
+ EXPECT_FALSE(SymbolNames.count("_unknownSym"));
+}
+
+TEST(TBDv3, SkipAllUnknownArchs) {
+ static const char TBDv3AllUnknown[] = "--- !tapi-tbd-v3\n"
+ "archs: [ foo, bar ]\n"
+ "platform: ios\n"
+ "install-name: Test.dylib\n"
+ "...\n";
+
+ Expected<TBDFile> Result =
+ TextAPIReader::get(MemoryBufferRef(TBDv3AllUnknown, "Test.tbd"),
+ /*SkipUnknownTriples=*/true);
+ EXPECT_TRUE(!!Result);
+ TBDFile File = std::move(Result.get());
+
+ EXPECT_TRUE(File->getArchitectures().empty());
+ EXPECT_EQ(File->symbolsCount(), 0U);
+}
+
} // namespace TBDv3
diff --git a/llvm/unittests/TextAPI/TextStubV4Tests.cpp b/llvm/unittests/TextAPI/TextStubV4Tests.cpp
index 1a10c9119a43c..3f9d8d9b7deaa 100644
--- a/llvm/unittests/TextAPI/TextStubV4Tests.cpp
+++ b/llvm/unittests/TextAPI/TextStubV4Tests.cpp
@@ -896,7 +896,7 @@ TEST(TBDv4, InvalidArchitecture) {
EXPECT_FALSE(!!Result);
std::string ErrorMessage = toString(Result.takeError());
EXPECT_EQ("malformed file\nTest.tbd:3:12: error: unknown "
- "architecture\ntargets: [ foo-macos ]\n"
+ "target\ntargets: [ foo-macos ]\n"
" ^~~~~~~~~~\n",
ErrorMessage);
}
@@ -912,7 +912,7 @@ TEST(TBDv4, InvalidPlatform) {
TextAPIReader::get(MemoryBufferRef(TBDv4FInvalidPlatform, "Test.tbd"));
EXPECT_FALSE(!!Result);
std::string ErrorMessage = toString(Result.takeError());
- EXPECT_EQ("malformed file\nTest.tbd:3:12: error: unknown platform\ntargets: "
+ EXPECT_EQ("malformed file\nTest.tbd:3:12: error: unknown target\ntargets: "
"[ x86_64-maos ]\n"
" ^~~~~~~~~~~~\n",
ErrorMessage);
@@ -1175,4 +1175,174 @@ TEST(TBDv4, InterfaceInequality) {
}));
}
+TEST(TBDv4, SkipUnknownArch) {
+ static const char TBDv4WithUnknownArch[] =
+ "--- !tapi-tbd\n"
+ "tbd-version: 4\n"
+ "targets: [ x86_64-macos, foo-macos ]\n"
+ "install-name: Test.dylib\n"
+ "exports:\n"
+ " - targets: [ x86_64-macos ]\n"
+ " symbols: [ _knownSym ]\n"
+ " - targets: [ foo-bar ]\n"
+ " symbols: [ _unknownSym ]\n"
+ " - targets: [ x86_64-macos, foo-macos ]\n"
+ " symbols: [ _mixedSym ]\n"
+ "...\n";
+
+ Expected<TBDFile> Result =
+ TextAPIReader::get(MemoryBufferRef(TBDv4WithUnknownArch, "Test.tbd"),
+ /*SkipUnknownTriples=*/true);
+ EXPECT_TRUE(!!Result);
+ TBDFile File = std::move(Result.get());
+
+ EXPECT_EQ(1U, llvm::size(File->targets()));
+ EXPECT_EQ(Target(AK_x86_64, PLATFORM_MACOS), *File->targets().begin());
+
+ llvm::DenseSet<StringRef> SymbolNames;
+ for (const auto *Sym : File->exports())
+ SymbolNames.insert(Sym->getName());
+
+ EXPECT_TRUE(SymbolNames.count("_knownSym"));
+ EXPECT_TRUE(SymbolNames.count("_mixedSym"));
+ EXPECT_FALSE(SymbolNames.count("_unknownSym"));
+}
+
+TEST(TBDv4, SkipUnknownPlatform) {
+ static const char TBDv4WithUnknownPlatform[] =
+ "--- !tapi-tbd\n"
+ "tbd-version: 4\n"
+ "targets: [ x86_64-macos, x86_64-windows ]\n"
+ "install-name: Test.dylib\n"
+ "exports:\n"
+ " - targets: [ x86_64-macos ]\n"
+ " symbols: [ _knownSym ]\n"
+ " - targets: [ x86_64-unknownos ]\n"
+ " symbols: [ _unknownSym ]\n"
+ "...\n";
+
+ Expected<TBDFile> Result =
+ TextAPIReader::get(MemoryBufferRef(TBDv4WithUnknownPlatform, "Test.tbd"),
+ /*SkipUnknownTriples=*/true);
+ EXPECT_TRUE(!!Result);
+ TBDFile File = std::move(Result.get());
+
+ EXPECT_EQ(1U, llvm::size(File->targets()));
+ EXPECT_EQ(Target(AK_x86_64, PLATFORM_MACOS), *File->targets().begin());
+
+ DenseSet<StringRef> SymbolNames;
+ for (const auto *Sym : File->exports())
+ SymbolNames.insert(Sym->getName());
+
+ EXPECT_TRUE(SymbolNames.count("_knownSym"));
+ EXPECT_FALSE(SymbolNames.count("_unknownSym"));
+}
+
+TEST(TBDv4, SkipAllUnknownTargets) {
+ static const char TBDv4AllUnknown[] = "--- !tapi-tbd\n"
+ "tbd-version: 4\n"
+ "targets: [ foo-macos, bar-ios ]\n"
+ "install-name: Test.dylib\n"
+ "...\n";
+
+ Expected<TBDFile> Result =
+ TextAPIReader::get(MemoryBufferRef(TBDv4AllUnknown, "Test.tbd"),
+ /*SkipUnknownTriples=*/true);
+ EXPECT_TRUE(!!Result);
+ TBDFile File = std::move(Result.get());
+
+ // All targets should be filtered out.
+ EXPECT_EQ(0U, llvm::size(File->targets()));
+}
+
+TEST(TBDv4, SkipUnknownWithLoadCommands) {
+ static const char TBDv4WithMetadata[] =
+ "--- !tapi-tbd\n"
+ "tbd-version: 4\n"
+ "targets: [ x86_64-macos, foo-macos ]\n"
+ "install-name: Test.dylib\n"
+ "parent-umbrella:\n"
+ " - targets: [ x86_64-macos, foo-macos ]\n"
+ " umbrella: System\n"
+ "allowable-clients:\n"
+ " - targets: [ foo-macos ]\n"
+ " clients: [ UnknownClient ]\n"
+ " - targets: [ x86_64-macos ]\n"
+ " clients: [ KnownClient ]\n"
+ "...\n";
+
+ Expected<TBDFile> Result =
+ TextAPIReader::get(MemoryBufferRef(TBDv4WithMetadata, "Test.tbd"),
+ /*SkipUnknownTriples=*/true);
+ EXPECT_TRUE(!!Result);
+ TBDFile File = std::move(Result.get());
+
+ EXPECT_EQ(1U, llvm::size(File->targets()));
+
+ auto &Umbrellas = File->umbrellas();
+ EXPECT_EQ(1U, std::distance(Umbrellas.begin(), Umbrellas.end()));
+ EXPECT_EQ(Target(AK_x86_64, PLATFORM_MACOS), Umbrellas.begin()->first);
+
+ auto &Clients = File->allowableClients();
+ EXPECT_EQ(1U, Clients.size());
+ EXPECT_EQ("KnownClient", Clients.front().getInstallName());
+}
+
+TEST(TBDv4, SkipUnknownInFullFile) {
+ static const char TBDv4FullFile[] =
+ "--- !tapi-tbd\n"
+ "tbd-version: 4\n"
+ "targets: [ arm64-macos, x86_64-macos, arm64-linux ]\n"
+ "install-name: Test.dylib\n"
+ "current-version: 1.2.3\n"
+ "compatibility-version: 1.2\n"
+ "parent-umbrella:\n"
+ " - targets: [ arm64-macos, x86_64-macos, arm64-linux ]\n"
+ " umbrella: System\n"
+ "allowable-clients:\n"
+ " - targets: [ arm64-macos, x86_64-macos, arm64-linux ]\n"
+ " clients: [ ClientA ]\n"
+ "reexported-libraries:\n"
+ " - targets: [ arm64-macos, x86_64-macos, arm64-linux ]\n"
+ " libraries: [ /System/Library/Frameworks/A.framework/A ]\n"
+ "exports:\n"
+ " - targets: [ arm64-macos, x86_64-macos, arm64-linux ]\n"
+ " symbols: [ _sym ]\n"
+ "...\n";
+ Expected<TBDFile> Result = TextAPIReader::get(
+ MemoryBufferRef(TBDv4FullFile, "Test.tbd"), /*SkipUnknownTriples=*/true);
+ EXPECT_TRUE(!!Result);
+ TBDFile File = std::move(Result.get());
+
+ TargetList ExpectedTargets = {
+ Target(AK_x86_64, PLATFORM_MACOS),
+ Target(AK_arm64, PLATFORM_MACOS),
+ };
+ EXPECT_EQ(2U, llvm::size(File->targets()));
+ for (const auto &T : File->targets())
+ EXPECT_TRUE(llvm::is_contained(ExpectedTargets, T));
+
+ auto &Umbrellas = File->umbrellas();
+ EXPECT_EQ(2U, std::distance(Umbrellas.begin(), Umbrellas.end()));
+ for (const auto &U : Umbrellas)
+ EXPECT_TRUE(llvm::is_contained(ExpectedTargets, U.first));
+
+ InterfaceFileRef ExpectedClient("ClientA", ExpectedTargets);
+ EXPECT_EQ(1U, File->allowableClients().size());
+ EXPECT_EQ(ExpectedClient, File->allowableClients().front());
+
+ InterfaceFileRef ExpectedReexport("/System/Library/Frameworks/A.framework/A",
+ ExpectedTargets);
+ EXPECT_EQ(1U, File->reexportedLibraries().size());
+ EXPECT_EQ(ExpectedReexport, File->reexportedLibraries().front());
+
+ auto Exports = File->exports();
+ EXPECT_EQ(1, std::distance(Exports.begin(), Exports.end()));
+ const Symbol *Sym = *Exports.begin();
+ EXPECT_EQ("_sym", Sym->getName());
+ EXPECT_EQ(2U, llvm::size(Sym->targets()));
+ for (const auto &T : Sym->targets())
+ EXPECT_TRUE(llvm::is_contained(ExpectedTargets, T));
+}
+
} // end namespace TBDv4
diff --git a/llvm/unittests/TextAPI/TextStubV5Tests.cpp b/llvm/unittests/TextAPI/TextStubV5Tests.cpp
index f6689f7524a72..a5525fdb207ed 100644
--- a/llvm/unittests/TextAPI/TextStubV5Tests.cpp
+++ b/llvm/unittests/TextAPI/TextStubV5Tests.cpp
@@ -2478,4 +2478,164 @@ TEST(TBDv5, InlineIF) {
EXPECT_TRUE(
std::equal(Exports.begin(), Exports.end(), std::begin(ExpectedExports)));
}
+
+TEST(TBDv5, SkipUnknownArch) {
+ static const char TBDv5WithUnknownArch[] = R"({
+"tapi_tbd_version": 5,
+"main_library": {
+ "target_info": [
+ { "target": "x86_64-macos" },
+ { "target": "foo-macos" }
+ ],
+ "install_names": [
+ { "name": "Test.dylib" }
+ ],
+ "exported_symbols": [
+ {
+ "targets": [ "x86_64-macos" ],
+ "data": { "global": [ "_knownSym" ] }
+ },
+ {
+ "targets": [ "foo-macos" ],
+ "data": { "global": [ "_unknownSym" ] }
+ },
+ {
+ "targets": [ "x86_64-macos", "foo-macos" ],
+ "data": { "global": [ "_mixedSym" ] }
+ }
+ ]
+}})";
+
+ Expected<TBDFile> Result =
+ TextAPIReader::get(MemoryBufferRef(TBDv5WithUnknownArch, "Test.tbd"),
+ /*SkipUnknownTriples=*/true);
+ EXPECT_TRUE(!!Result);
+ TBDFile File = std::move(Result.get());
+
+ EXPECT_EQ(1U, llvm::size(File->targets()));
+ EXPECT_EQ(Target(AK_x86_64, PLATFORM_MACOS), *File->targets().begin());
+
+ llvm::DenseSet<StringRef> SymbolNames;
+ for (const auto *Sym : File->exports())
+ SymbolNames.insert(Sym->getName());
+
+ EXPECT_TRUE(SymbolNames.count("_knownSym"));
+ EXPECT_TRUE(SymbolNames.count("_mixedSym"));
+ EXPECT_FALSE(SymbolNames.count("_unknownSym"));
+}
+
+TEST(TBDv5, SkipUnknownPlatform) {
+ static const char TBDv5WithUnknownPlatform[] = R"({
+"tapi_tbd_version": 5,
+"main_library": {
+ "target_info": [
+ { "target": "x86_64-macos" },
+ { "target": "x86_64-unknownos" }
+ ],
+ "install_names": [
+ { "name": "Test.dylib" }
+ ],
+ "exported_symbols": [
+ {
+ "targets": [ "x86_64-macos" ],
+ "data": { "global": [ "_knownSym" ] }
+ },
+ {
+ "targets": [ "x86_64-unknownos" ],
+ "data": { "global": [ "_unknownSym" ] }
+ }
+ ]
+}})";
+
+ Expected<TBDFile> Result =
+ TextAPIReader::get(MemoryBufferRef(TBDv5WithUnknownPlatform, "Test.tbd"),
+ /*SkipUnknownTriples=*/true);
+ EXPECT_TRUE(!!Result);
+ TBDFile File = std::move(Result.get());
+
+ EXPECT_EQ(1U, llvm::size(File->targets()));
+ EXPECT_EQ(Target(AK_x86_64, PLATFORM_MACOS), *File->targets().begin());
+
+ llvm::DenseSet<StringRef> SymbolNames;
+ for (const auto *Sym : File->exports())
+ SymbolNames.insert(Sym->getName());
+
+ EXPECT_TRUE(SymbolNames.count("_knownSym"));
+ EXPECT_FALSE(SymbolNames.count("_unknownSym"));
+}
+
+TEST(TBDv5, SkipAllUnknownTargets) {
+ static const char TBDv5AllUnknown[] = R"({
+"tapi_tbd_version": 5,
+"main_library": {
+ "target_info": [
+ { "target": "foo-macos" },
+ { "target": "bar-ios" }
+ ],
+ "install_names": [
+ { "name": "Test.dylib" }
+ ]
+}})";
+
+ Expected<TBDFile> Result =
+ TextAPIReader::get(MemoryBufferRef(TBDv5AllUnknown, "Test.tbd"),
+ /*SkipUnknownTriples=*/true);
+ EXPECT_TRUE(!!Result);
+ TBDFile File = std::move(Result.get());
+
+ EXPECT_EQ(0U, llvm::size(File->targets()));
+}
+
+TEST(TBDv5, SkipUnknownWithInlinedLibs) {
+ static const char TBDv5WithInlined[] = R"({
+"tapi_tbd_version": 5,
+"main_library": {
+ "target_info": [
+ { "target": "x86_64-macos" },
+ { "target": "foo-macos" }
+ ],
+ "install_names": [
+ { "name": "/S/L/F/Umbrella.framework/Umbrella" }
+ ],
+ "reexported_libraries": [
+ { "names": [ "/S/L/F/A.framework/A" ] }
+ ]
+},
+"libraries": [
+ {
+ "target_info": [
+ { "target": "x86_64-macos" }
+ ],
+ "install_names": [
+ { "name": "/S/L/F/A.framework/A" }
+ ],
+ "exported_symbols": [
+ {
+ "data": { "global": [ "_inlinedSym" ] }
+ }
+ ]
+ }
+]
+})";
+
+ Expected<TBDFile> Result =
+ TextAPIReader::get(MemoryBufferRef(TBDv5WithInlined, "Test.tbd"),
+ /*SkipUnknownTriples=*/true);
+ EXPECT_TRUE(!!Result);
+ TBDFile File = std::move(Result.get());
+
+ EXPECT_EQ(1U, llvm::size(File->targets()));
+ EXPECT_EQ(Target(AK_x86_64, PLATFORM_MACOS), *File->targets().begin());
+
+ EXPECT_EQ(1U, File->documents().size());
+ TBDReexportFile Document = File->documents().front();
+ EXPECT_EQ(1U, llvm::size(Document->targets()));
+ EXPECT_EQ(Target(AK_x86_64, PLATFORM_MACOS), *Document->targets().begin());
+
+ llvm::DenseSet<StringRef> SymbolNames;
+ for (const auto *Sym : Document->exports())
+ SymbolNames.insert(Sym->getName());
+ EXPECT_TRUE(SymbolNames.count("_inlinedSym"));
+}
+
} // end namespace TBDv5
More information about the llvm-commits
mailing list