1//===-- TextStubV5Tests.cpp - TBD V5 File Test ----------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===-----------------------------------------------------------------------===/
8
9#include "TextStubHelpers.h"
10#include "llvm/TextAPI/InterfaceFile.h"
11#include "llvm/TextAPI/TextAPIReader.h"
12#include "llvm/TextAPI/TextAPIWriter.h"
13#include "gtest/gtest.h"
14#include <string>
15#include <vector>
16
17using namespace llvm;
18using namespace llvm::MachO;
19
20namespace TBDv5 {
21
22TEST(TBDv5, ReadFile) {
23 static const char TBDv5File[] = R"({
24"tapi_tbd_version": 5,
25"main_library": {
26 "target_info": [
27 {
28 "target": "x86_64-macos",
29 "min_deployment": "10.14"
30 },
31 {
32 "target": "arm64-macos",
33 "min_deployment": "10.14"
34 },
35 {
36 "target": "arm64-maccatalyst",
37 "min_deployment": "12.1"
38 }
39 ],
40 "flags": [
41 {
42 "targets": [
43 "x86_64-macos"
44 ],
45 "attributes": [
46 "flat_namespace"
47 ]
48 }
49 ],
50 "install_names": [
51 {
52 "name": "/S/L/F/Foo.framework/Foo"
53 }
54 ],
55 "current_versions": [
56 {
57 "version": "1.2"
58 }
59 ],
60 "compatibility_versions": [
61 { "version": "1.1" }
62 ],
63 "rpaths": [
64 {
65 "targets": [
66 "x86_64-macos"
67 ],
68 "paths": [
69 "@executable_path/.../Frameworks"
70 ]
71 }
72 ],
73 "parent_umbrellas": [
74 {
75 "umbrella": "System"
76 }
77 ],
78 "allowable_clients": [
79 {
80 "clients": [
81 "ClientA",
82 "ClientB"
83 ]
84 }
85 ],
86 "reexported_libraries": [
87 {
88 "names": [
89 "/u/l/l/libfoo.dylib",
90 "/u/l/l/libbar.dylib"
91 ]
92 }
93 ],
94 "exported_symbols": [
95 {
96 "targets": [
97 "x86_64-macos",
98 "arm64-macos"
99 ],
100 "data": {
101 "global": [
102 "_global"
103 ],
104 "objc_class": [
105 "ClassA"
106 ],
107 "weak": [],
108 "thread_local": []
109 },
110 "text": {
111 "global": [
112 "_func"
113 ],
114 "weak": [],
115 "thread_local": []
116 }
117 },
118 {
119 "targets": [
120 "x86_64-macos"
121 ],
122 "data": {
123 "global": [
124 "_globalVar"
125 ],
126 "objc_class": [
127 "ClassA",
128 "ClassB",
129 "ClassData"
130 ],
131 "objc_eh_type": [
132 "ClassA",
133 "ClassB"
134 ],
135 "objc_ivar": [
136 "ClassA.ivar1",
137 "ClassA.ivar2",
138 "ClassC.ivar1"
139 ]
140 },
141 "text": {
142 "global": [
143 "_funcFoo"
144 ]
145 }
146 }
147 ],
148 "reexported_symbols": [
149 {
150 "targets": [
151 "x86_64-macos",
152 "arm64-macos"
153 ],
154 "data": {
155 "global": [
156 "_globalRe"
157 ],
158 "objc_class": [
159 "ClassRexport"
160 ]
161 },
162 "text": {
163 "global": [
164 "_funcA"
165 ]
166 }
167 }
168 ],
169 "undefined_symbols": [
170 {
171 "targets": [
172 "x86_64-macos"
173 ],
174 "data": {
175 "global": [
176 "_globalBind"
177 ],
178 "weak": [
179 "referenced_sym"
180 ]
181 }
182 }
183 ]
184},
185"libraries": []
186})";
187
188 MemoryBufferRef InputBuf = MemoryBufferRef(TBDv5File, "Test.tbd");
189 Expected<FileType> ExpectedFT = TextAPIReader::canRead(InputBuffer: InputBuf);
190 EXPECT_TRUE(!!ExpectedFT);
191
192 Expected<TBDFile> Result = TextAPIReader::get(InputBuffer: InputBuf);
193 EXPECT_TRUE(!!Result);
194 TBDFile File = std::move(Result.get());
195 EXPECT_EQ(FileType::TBD_V5, File->getFileType());
196 EXPECT_EQ(*ExpectedFT, File->getFileType());
197 EXPECT_EQ(std::string("/S/L/F/Foo.framework/Foo"), File->getInstallName());
198
199 TargetList AllTargets = {
200 Target(AK_x86_64, PLATFORM_MACOS, VersionTuple(10, 14)),
201 Target(AK_arm64, PLATFORM_MACOS, VersionTuple(11, 0, 0)),
202 Target(AK_arm64, PLATFORM_MACCATALYST, VersionTuple(14, 0)),
203 };
204 std::set<Target> FileTargets{File->targets().begin(), File->targets().end()};
205 EXPECT_EQ(mapToPlatformSet(AllTargets), File->getPlatforms());
206 EXPECT_EQ(mapToArchitectureSet(AllTargets), File->getArchitectures());
207 EXPECT_EQ(FileTargets.size(), AllTargets.size());
208 for (const auto &Targ : AllTargets) {
209 auto FileTarg = FileTargets.find(x: Targ);
210 EXPECT_FALSE(FileTarg == FileTargets.end());
211 EXPECT_EQ(*FileTarg, Targ);
212 PackedVersion MD = Targ.MinDeployment;
213 PackedVersion FileMD = FileTarg->MinDeployment;
214 EXPECT_EQ(MD, FileMD);
215 }
216
217 EXPECT_EQ(PackedVersion(1, 2, 0), File->getCurrentVersion());
218 EXPECT_EQ(PackedVersion(1, 1, 0), File->getCompatibilityVersion());
219 EXPECT_TRUE(File->isApplicationExtensionSafe());
220 EXPECT_FALSE(File->isTwoLevelNamespace());
221 EXPECT_FALSE(File->isOSLibNotForSharedCache());
222 EXPECT_EQ(0U, File->documents().size());
223
224 InterfaceFileRef ClientA("ClientA", AllTargets);
225 InterfaceFileRef ClientB("ClientB", AllTargets);
226 EXPECT_EQ(2U, File->allowableClients().size());
227 EXPECT_EQ(ClientA, File->allowableClients().at(0));
228 EXPECT_EQ(ClientB, File->allowableClients().at(1));
229
230 InterfaceFileRef ReexportA("/u/l/l/libbar.dylib", AllTargets);
231 InterfaceFileRef ReexportB("/u/l/l/libfoo.dylib", AllTargets);
232 EXPECT_EQ(2U, File->reexportedLibraries().size());
233 EXPECT_EQ(ReexportA, File->reexportedLibraries().at(0));
234 EXPECT_EQ(ReexportB, File->reexportedLibraries().at(1));
235
236 TargetToAttr RPaths = {
237 {Target(AK_x86_64, PLATFORM_MACOS), "@executable_path/.../Frameworks"},
238 };
239 EXPECT_EQ(RPaths, File->rpaths());
240
241 TargetToAttr Umbrellas = {{Target(AK_x86_64, PLATFORM_MACOS), "System"},
242 {Target(AK_arm64, PLATFORM_MACOS), "System"},
243 {Target(AK_arm64, PLATFORM_MACCATALYST), "System"}};
244 EXPECT_EQ(Umbrellas, File->umbrellas());
245
246 ExportedSymbolSeq Exports, Reexports, Undefineds;
247 for (const auto *Sym : File->symbols()) {
248 TargetList SymTargets{Sym->targets().begin(), Sym->targets().end()};
249 ExportedSymbol Temp =
250 ExportedSymbol{.Kind: Sym->getKind(),
251 .Name: std::string(Sym->getName()),
252 .Weak: Sym->isWeakDefined() || Sym->isWeakReferenced(),
253 .ThreadLocalValue: Sym->isThreadLocalValue(),
254 .isData: Sym->isData(),
255 .Targets: SymTargets};
256 if (Sym->isUndefined())
257 Undefineds.emplace_back(args: std::move(Temp));
258 else
259 Sym->isReexported() ? Reexports.emplace_back(args: std::move(Temp))
260 : Exports.emplace_back(args: std::move(Temp));
261 }
262 llvm::sort(C&: Exports);
263 llvm::sort(C&: Reexports);
264 llvm::sort(C&: Undefineds);
265
266 TargetList MacOSTargets = {Target(AK_x86_64, PLATFORM_MACOS),
267 Target(AK_arm64, PLATFORM_MACOS)};
268
269 std::vector<ExportedSymbol> ExpectedExportedSymbols = {
270 {.Kind: EncodeKind::GlobalSymbol, .Name: "_func", .Weak: false, .ThreadLocalValue: false, .isData: false, .Targets: MacOSTargets},
271 {.Kind: EncodeKind::GlobalSymbol,
272 .Name: "_funcFoo",
273 .Weak: false,
274 .ThreadLocalValue: false,
275 .isData: false,
276 .Targets: {Target(AK_x86_64, PLATFORM_MACOS)}},
277 {.Kind: EncodeKind::GlobalSymbol, .Name: "_global", .Weak: false, .ThreadLocalValue: false, .isData: true, .Targets: MacOSTargets},
278 {.Kind: EncodeKind::GlobalSymbol,
279 .Name: "_globalVar",
280 .Weak: false,
281 .ThreadLocalValue: false,
282 .isData: true,
283 .Targets: {Target(AK_x86_64, PLATFORM_MACOS)}},
284 {.Kind: EncodeKind::ObjectiveCClass,
285 .Name: "ClassA",
286 .Weak: false,
287 .ThreadLocalValue: false,
288 .isData: true,
289 .Targets: {Target(AK_x86_64, PLATFORM_MACOS)}},
290 {.Kind: EncodeKind::ObjectiveCClass,
291 .Name: "ClassB",
292 .Weak: false,
293 .ThreadLocalValue: false,
294 .isData: true,
295 .Targets: {Target(AK_x86_64, PLATFORM_MACOS)}},
296 {.Kind: EncodeKind::ObjectiveCClass,
297 .Name: "ClassData",
298 .Weak: false,
299 .ThreadLocalValue: false,
300 .isData: true,
301 .Targets: {Target(AK_x86_64, PLATFORM_MACOS)}},
302 {.Kind: EncodeKind::ObjectiveCClassEHType,
303 .Name: "ClassA",
304 .Weak: false,
305 .ThreadLocalValue: false,
306 .isData: true,
307 .Targets: {Target(AK_x86_64, PLATFORM_MACOS)}},
308 {.Kind: EncodeKind::ObjectiveCClassEHType,
309 .Name: "ClassB",
310 .Weak: false,
311 .ThreadLocalValue: false,
312 .isData: true,
313 .Targets: {Target(AK_x86_64, PLATFORM_MACOS)}},
314 {.Kind: EncodeKind::ObjectiveCInstanceVariable,
315 .Name: "ClassA.ivar1",
316 .Weak: false,
317 .ThreadLocalValue: false,
318 .isData: true,
319 .Targets: {Target(AK_x86_64, PLATFORM_MACOS)}},
320 {.Kind: EncodeKind::ObjectiveCInstanceVariable,
321 .Name: "ClassA.ivar2",
322 .Weak: false,
323 .ThreadLocalValue: false,
324 .isData: true,
325 .Targets: {Target(AK_x86_64, PLATFORM_MACOS)}},
326 {.Kind: EncodeKind::ObjectiveCInstanceVariable,
327 .Name: "ClassC.ivar1",
328 .Weak: false,
329 .ThreadLocalValue: false,
330 .isData: true,
331 .Targets: {Target(AK_x86_64, PLATFORM_MACOS)}},
332 };
333 std::vector<ExportedSymbol> ExpectedReexportedSymbols = {
334 {.Kind: EncodeKind::GlobalSymbol, .Name: "_funcA", .Weak: false, .ThreadLocalValue: false, .isData: false, .Targets: MacOSTargets},
335 {.Kind: EncodeKind::GlobalSymbol, .Name: "_globalRe", .Weak: false, .ThreadLocalValue: false, .isData: true, .Targets: MacOSTargets},
336 {.Kind: EncodeKind::ObjectiveCClass, .Name: "ClassRexport", .Weak: false, .ThreadLocalValue: false, .isData: true,
337 .Targets: MacOSTargets},
338 };
339
340 std::vector<ExportedSymbol> ExpectedUndefinedSymbols = {
341 {.Kind: EncodeKind::GlobalSymbol,
342 .Name: "_globalBind",
343 .Weak: false,
344 .ThreadLocalValue: false,
345 .isData: true,
346 .Targets: {Target(AK_x86_64, PLATFORM_MACOS)}},
347 {.Kind: EncodeKind::GlobalSymbol,
348 .Name: "referenced_sym",
349 .Weak: true,
350 .ThreadLocalValue: false,
351 .isData: true,
352 .Targets: {Target(AK_x86_64, PLATFORM_MACOS)}},
353 };
354
355 EXPECT_EQ(ExpectedExportedSymbols.size(), Exports.size());
356 EXPECT_EQ(ExpectedReexportedSymbols.size(), Reexports.size());
357 EXPECT_EQ(ExpectedUndefinedSymbols.size(), Undefineds.size());
358 EXPECT_TRUE(std::equal(Exports.begin(), Exports.end(),
359 std::begin(ExpectedExportedSymbols)));
360 EXPECT_TRUE(std::equal(Reexports.begin(), Reexports.end(),
361 std::begin(ExpectedReexportedSymbols)));
362 EXPECT_TRUE(std::equal(Undefineds.begin(), Undefineds.end(),
363 std::begin(ExpectedUndefinedSymbols)));
364
365 EXPECT_TRUE(
366 File->getSymbol(EncodeKind::GlobalSymbol, "_globalBind").has_value());
367}
368
369TEST(TBDv5, ReadMultipleTargets) {
370 static const char TBDv5File[] = R"({
371"tapi_tbd_version": 5,
372"main_library": {
373 "target_info": [
374 {
375 "target": "x86_64-macos",
376 "min_deployment": "10.14"
377 },
378 {
379 "target": "arm64-macos",
380 "min_deployment": "10.14"
381 },
382 {
383 "target": "arm64-maccatalyst",
384 "min_deployment": "12.1"
385 }
386 ],
387 "install_names":[
388 { "name":"/usr/lib/libFoo.dylib" }
389 ],
390 "swift_abi":[ { "abi":8 } ],
391 "reexported_libraries": [
392 {
393 "targets": [ "x86_64-maccatalyst" ],
394 "names": [
395 "/u/l/l/libfoo.dylib",
396 "/u/l/l/libbar.dylib"
397 ]
398 },
399 {
400 "targets": [ "arm64-maccatalyst" ],
401 "names": [ "/u/l/l/libArmOnly.dylib" ]
402 }
403 ]
404}
405})";
406
407 Expected<TBDFile> Result =
408 TextAPIReader::get(InputBuffer: MemoryBufferRef(TBDv5File, "Test.tbd"));
409 EXPECT_TRUE(!!Result);
410 TBDFile File = std::move(Result.get());
411 EXPECT_EQ(FileType::TBD_V5, File->getFileType());
412 EXPECT_EQ(std::string("/usr/lib/libFoo.dylib"), File->getInstallName());
413 EXPECT_TRUE(File->isApplicationExtensionSafe());
414 EXPECT_TRUE(File->isTwoLevelNamespace());
415 EXPECT_EQ(PackedVersion(1, 0, 0), File->getCurrentVersion());
416 EXPECT_EQ(PackedVersion(1, 0, 0), File->getCompatibilityVersion());
417 EXPECT_EQ(8U, File->getSwiftABIVersion());
418
419 TargetList AllTargets = {
420 Target(AK_x86_64, PLATFORM_MACOS, VersionTuple(10, 14)),
421 Target(AK_arm64, PLATFORM_MACOS, VersionTuple(10, 14)),
422 Target(AK_arm64, PLATFORM_MACCATALYST, VersionTuple(12, 1)),
423 };
424 EXPECT_EQ(mapToPlatformSet(AllTargets), File->getPlatforms());
425 EXPECT_EQ(mapToArchitectureSet(AllTargets), File->getArchitectures());
426
427 InterfaceFileRef ReexportA("/u/l/l/libArmOnly.dylib",
428 {Target(AK_arm64, PLATFORM_MACCATALYST)});
429 InterfaceFileRef ReexportB("/u/l/l/libbar.dylib",
430 {Target(AK_x86_64, PLATFORM_MACCATALYST)});
431 InterfaceFileRef ReexportC("/u/l/l/libfoo.dylib",
432 {Target(AK_x86_64, PLATFORM_MACCATALYST)});
433 EXPECT_EQ(3U, File->reexportedLibraries().size());
434 EXPECT_EQ(ReexportA, File->reexportedLibraries().at(0));
435 EXPECT_EQ(ReexportB, File->reexportedLibraries().at(1));
436 EXPECT_EQ(ReexportC, File->reexportedLibraries().at(2));
437}
438
439TEST(TBDv5, ReadMultipleDocuments) {
440 static const char TBDv5File[] = R"({
441"tapi_tbd_version": 5,
442"main_library": {
443 "target_info": [
444 {
445 "target": "armv7-ios",
446 "min_deployment": "11.0"
447 }
448 ],
449 "install_names":[
450 { "name":"/S/L/F/Foo.framework/Foo" }
451 ],
452 "reexported_libraries": [
453 { "names": ["/u/l/l/libfoo.dylib"] }
454 ]
455},
456"libraries": [
457 {
458 "target_info": [
459 {
460 "target": "armv7-ios",
461 "min_deployment": "11.0"
462 }
463 ],
464 "install_names":[
465 { "name":"/u/l/l/libfoo.dylib" }
466 ],
467 "flags":[
468 { "attributes": ["not_app_extension_safe"] }
469 ],
470 "exported_symbols": [
471 {
472 "data": {
473 "thread_local": [ "_globalVar" ],
474 "objc_class": [ "ClassData", "ClassA", "ClassB"],
475 "objc_eh_type": [ "ClassA", "ClassB" ]
476 },
477 "text": {
478 "global": [ "_funcFoo" ]
479 }
480 }
481 ]
482 }
483]})";
484
485 Expected<TBDFile> Result =
486 TextAPIReader::get(InputBuffer: MemoryBufferRef(TBDv5File, "Test.tbd"));
487 EXPECT_TRUE(!!Result);
488 TBDFile File = std::move(Result.get());
489 EXPECT_EQ(FileType::TBD_V5, File->getFileType());
490 EXPECT_EQ(std::string("/S/L/F/Foo.framework/Foo"), File->getInstallName());
491 EXPECT_TRUE(File->isTwoLevelNamespace());
492 EXPECT_TRUE(File->isApplicationExtensionSafe());
493
494 TargetList Targets(File->targets().begin(), File->targets().end());
495 Target iOSTarget(AK_armv7, PLATFORM_IOS, VersionTuple(11, 0));
496 EXPECT_EQ(TargetList{iOSTarget}, Targets);
497 std::vector<const Symbol *> Symbols(File->symbols().begin(),
498 File->symbols().end());
499 EXPECT_EQ(0U, Symbols.size());
500
501 InterfaceFileRef Reexport("/u/l/l/libfoo.dylib", {iOSTarget});
502 EXPECT_EQ(1U, File->reexportedLibraries().size());
503 EXPECT_EQ(Reexport, File->reexportedLibraries().at(0));
504
505 // Check inlined library.
506 EXPECT_EQ(1U, File->documents().size());
507 TBDReexportFile Document = File->documents().front();
508 Targets = {Document->targets().begin(), Document->targets().end()};
509 EXPECT_EQ(TargetList{iOSTarget}, Targets);
510 EXPECT_EQ(std::string("/u/l/l/libfoo.dylib"), Document->getInstallName());
511 EXPECT_EQ(0U, Document->getSwiftABIVersion());
512 EXPECT_TRUE(Document->isTwoLevelNamespace());
513 EXPECT_FALSE(Document->isApplicationExtensionSafe());
514
515 ExportedSymbolSeq Exports;
516 for (const auto *Sym : Document->symbols())
517 Exports.emplace_back(
518 args: ExportedSymbol{.Kind: Sym->getKind(),
519 .Name: std::string(Sym->getName()),
520 .Weak: Sym->isWeakDefined() || Sym->isWeakReferenced(),
521 .ThreadLocalValue: Sym->isThreadLocalValue(),
522 .isData: Sym->isData(),
523 .Targets: {iOSTarget}});
524
525 llvm::sort(C&: Exports);
526 ExportedSymbolSeq ExpectedExports = {
527 {.Kind: EncodeKind::GlobalSymbol, .Name: "_funcFoo", .Weak: false, .ThreadLocalValue: false, .isData: false, .Targets: {iOSTarget}},
528 {.Kind: EncodeKind::GlobalSymbol, .Name: "_globalVar", .Weak: false, .ThreadLocalValue: true, .isData: true, .Targets: {iOSTarget}},
529 {.Kind: EncodeKind::ObjectiveCClass, .Name: "ClassA", .Weak: false, .ThreadLocalValue: false, .isData: true, .Targets: {iOSTarget}},
530 {.Kind: EncodeKind::ObjectiveCClass, .Name: "ClassB", .Weak: false, .ThreadLocalValue: false, .isData: true, .Targets: {iOSTarget}},
531 {.Kind: EncodeKind::ObjectiveCClass,
532 .Name: "ClassData",
533 .Weak: false,
534 .ThreadLocalValue: false,
535 .isData: true,
536 .Targets: {iOSTarget}},
537 {.Kind: EncodeKind::ObjectiveCClassEHType,
538 .Name: "ClassA",
539 .Weak: false,
540 .ThreadLocalValue: false,
541 .isData: true,
542 .Targets: {iOSTarget}},
543 {.Kind: EncodeKind::ObjectiveCClassEHType,
544 .Name: "ClassB",
545 .Weak: false,
546 .ThreadLocalValue: false,
547 .isData: true,
548 .Targets: {iOSTarget}},
549 };
550
551 EXPECT_EQ(ExpectedExports.size(), Exports.size());
552 EXPECT_TRUE(
553 std::equal(Exports.begin(), Exports.end(), std::begin(ExpectedExports)));
554}
555
556TEST(TBDv5, WriteFile) {
557 static const char TBDv5File[] = R"({
558"tapi_tbd_version": 5,
559"main_library": {
560 "target_info": [
561 {
562 "target": "x86_64-macos",
563 "min_deployment": "10.14"
564 },
565 {
566 "target": "arm64-macos",
567 "min_deployment": "10.14"
568 },
569 {
570 "target": "arm64-maccatalyst",
571 "min_deployment": "12.1"
572 }
573 ],
574 "install_names": [
575 {
576 "name": "@rpath/S/L/F/Foo.framework/Foo"
577 }
578 ],
579 "current_versions": [
580 {
581 "version": "1.2"
582 }
583 ],
584 "compatibility_versions": [
585 { "version": "1.1" }
586 ],
587 "flags": [
588 {
589 "attributes": [
590 "flat_namespace"
591 ]
592 }
593 ],
594 "rpaths": [
595 {
596 "targets": [
597 "x86_64-macos"
598 ],
599 "paths": [
600 "@executable_path/.../Frameworks"
601 ]
602 }
603 ],
604 "parent_umbrellas": [
605 {
606 "umbrella": "System"
607 }
608 ],
609 "allowable_clients": [
610 {
611 "clients": [
612 "ClientA",
613 "ClientB"
614 ]
615 }
616 ],
617 "reexported_libraries": [
618 {
619 "names": [
620 "/u/l/l/libfoo.dylib",
621 "/u/l/l/libbar.dylib"
622 ]
623 }
624 ],
625 "exported_symbols": [
626 {
627 "targets": [
628 "x86_64-macos",
629 "arm64-macos"
630 ],
631 "data": {
632 "global": [
633 "_global"
634 ],
635 "objc_class": [
636 "ClassA"
637 ],
638 "weak": [],
639 "thread_local": []
640 },
641 "text": {
642 "global": [
643 "_func"
644 ],
645 "weak": [],
646 "thread_local": []
647 }
648 },
649 {
650 "targets": [
651 "x86_64-macos"
652 ],
653 "data": {
654 "global": [
655 "_globalVar"
656 ],
657 "objc_class": [
658 "ClassA",
659 "ClassB",
660 "ClassData"
661 ],
662 "objc_eh_type": [
663 "ClassA",
664 "ClassB"
665 ],
666 "objc_ivar": [
667 "ClassA.ivar1",
668 "ClassA.ivar2",
669 "ClassC.ivar1"
670 ]
671 },
672 "text": {
673 "global": [
674 "_funcFoo"
675 ]
676 }
677 }
678 ],
679 "reexported_symbols": [
680 {
681 "data": {
682 "global": [
683 "_globalRe"
684 ],
685 "objc_class": [
686 "ClassRexport"
687 ]
688 },
689 "text": {
690 "global": [
691 "_funcA"
692 ]
693 }
694 }
695 ],
696 "undefined_symbols": [
697 {
698 "targets": [
699 "x86_64-macos"
700 ],
701 "data": {
702 "global": [
703 "_globalBind"
704 ],
705 "weak": [
706 "referenced_sym"
707 ]
708 }
709 }
710 ]
711}})";
712
713 InterfaceFile File;
714 File.setFileType(FileType::TBD_V5);
715
716 TargetList AllTargets = {
717 Target(AK_x86_64, PLATFORM_MACOS, VersionTuple(10, 14)),
718 Target(AK_arm64, PLATFORM_MACOS, VersionTuple(10, 14)),
719 Target(AK_arm64, PLATFORM_MACCATALYST, VersionTuple(12, 1)),
720 };
721 File.addTargets(Targets&: AllTargets);
722 File.setInstallName("@rpath/S/L/F/Foo.framework/Foo");
723 File.setCurrentVersion(PackedVersion(1, 2, 0));
724 File.setCompatibilityVersion(PackedVersion(1, 1, 0));
725 File.addRPath(RPath: "@executable_path/.../Frameworks", InputTarget: AllTargets[0]);
726
727 for (const auto &Targ : AllTargets) {
728 File.addParentUmbrella(Target_: Targ, Parent: "System");
729 File.addAllowableClient(InstallName: "ClientA", Target: Targ);
730 File.addAllowableClient(InstallName: "ClientB", Target: Targ);
731 File.addReexportedLibrary(InstallName: "/u/l/l/libfoo.dylib", Target: Targ);
732 File.addReexportedLibrary(InstallName: "/u/l/l/libbar.dylib", Target: Targ);
733 }
734
735 SymbolFlags Flags = SymbolFlags::None;
736 // Exports.
737 File.addSymbol(Kind: EncodeKind::GlobalSymbol, Name: "_global",
738 Targets: {AllTargets[0], AllTargets[1]}, Flags: Flags | SymbolFlags::Data);
739 File.addSymbol(Kind: EncodeKind::GlobalSymbol, Name: "_func",
740 Targets: {AllTargets[0], AllTargets[1]}, Flags: Flags | SymbolFlags::Text);
741 File.addSymbol(Kind: EncodeKind::ObjectiveCClass, Name: "ClassA",
742 Targets: {AllTargets[0], AllTargets[1]}, Flags: Flags | SymbolFlags::Data);
743 File.addSymbol(Kind: EncodeKind::GlobalSymbol, Name: "_funcFoo", Target&: {AllTargets[0]},
744 Flags: Flags | SymbolFlags::Text);
745 File.addSymbol(Kind: EncodeKind::GlobalSymbol, Name: "_globalVar", Target&: {AllTargets[0]},
746 Flags: Flags | SymbolFlags::Data);
747 File.addSymbol(Kind: EncodeKind::ObjectiveCClass, Name: "ClassData", Target&: {AllTargets[0]},
748 Flags: Flags | SymbolFlags::Data);
749 File.addSymbol(Kind: EncodeKind::ObjectiveCClassEHType, Name: "ClassA", Target&: {AllTargets[0]},
750 Flags: Flags | SymbolFlags::Data);
751 File.addSymbol(Kind: EncodeKind::ObjectiveCClassEHType, Name: "ClassB", Target&: {AllTargets[0]},
752 Flags: Flags | SymbolFlags::Data);
753 File.addSymbol(Kind: EncodeKind::ObjectiveCInstanceVariable, Name: "ClassA.ivar1",
754 Target&: {AllTargets[0]}, Flags: Flags | SymbolFlags::Data);
755 File.addSymbol(Kind: EncodeKind::ObjectiveCInstanceVariable, Name: "ClassA.ivar2",
756 Target&: {AllTargets[0]}, Flags: Flags | SymbolFlags::Data);
757 File.addSymbol(Kind: EncodeKind::ObjectiveCInstanceVariable, Name: "ClassC.ivar1",
758 Target&: {AllTargets[0]}, Flags: Flags | SymbolFlags::Data);
759
760 // Reexports.
761 Flags = SymbolFlags::Rexported;
762 File.addSymbol(Kind: EncodeKind::GlobalSymbol, Name: "_globalRe", Targets&: AllTargets,
763 Flags: Flags | SymbolFlags::Data);
764 File.addSymbol(Kind: EncodeKind::GlobalSymbol, Name: "_funcA", Targets&: AllTargets,
765 Flags: Flags | SymbolFlags::Text);
766 File.addSymbol(Kind: EncodeKind::ObjectiveCClass, Name: "ClassRexport", Targets&: AllTargets,
767 Flags: Flags | SymbolFlags::Data);
768
769 // Undefineds.
770 Flags = SymbolFlags::Undefined;
771 File.addSymbol(Kind: EncodeKind::GlobalSymbol, Name: "_globalBind", Target&: {AllTargets[0]},
772 Flags: Flags | SymbolFlags::Data);
773 File.addSymbol(Kind: EncodeKind::GlobalSymbol, Name: "referenced_sym", Target&: {AllTargets[0]},
774 Flags: Flags | SymbolFlags::Data | SymbolFlags::WeakReferenced);
775
776 File.setTwoLevelNamespace(false);
777 File.setApplicationExtensionSafe(true);
778
779 // Write out file then process it back into IF and compare equality
780 // against TBDv5File.
781 SmallString<4096> Buffer;
782 raw_svector_ostream OS(Buffer);
783 Error Result = TextAPIWriter::writeToStream(OS, File);
784 EXPECT_FALSE(Result);
785
786 Expected<TBDFile> Input =
787 TextAPIReader::get(InputBuffer: MemoryBufferRef(TBDv5File, "Input.tbd"));
788 EXPECT_TRUE(!!Input);
789 TBDFile InputFile = std::move(Input.get());
790
791 Expected<TBDFile> Output =
792 TextAPIReader::get(InputBuffer: MemoryBufferRef(Buffer, "Output.tbd"));
793 EXPECT_TRUE(!!Output);
794 TBDFile OutputFile = std::move(Output.get());
795 EXPECT_EQ(*InputFile, *OutputFile);
796}
797
798TEST(TBDv5, WriteMultipleDocuments) {
799 static const char TBDv5File[] = R"({
800"tapi_tbd_version": 5,
801"main_library": {
802 "target_info": [
803 {
804 "target": "armv7-ios",
805 "min_deployment": "11.0"
806 }
807 ],
808 "install_names":[
809 { "name":"/S/L/F/Foo.framework/Foo" }
810 ],
811 "reexported_libraries": [
812 { "names": ["/u/l/l/libfoo.dylib"]
813 }
814 ]
815},
816"libraries": [
817 {
818 "target_info": [
819 {
820 "target": "armv7-ios",
821 "min_deployment": "11.0"
822 },
823 {
824 "target": "armv7s-ios",
825 "min_deployment": "11.0"
826 }
827 ],
828 "install_names":[
829 { "name":"/u/l/l/libfoo.dylib" }
830 ],
831 "current_versions": [
832 {
833 "version": "2.1.1"
834 }
835 ],
836 "rpaths": [
837 {
838 "targets": [
839 "armv7-ios"
840 ],
841 "paths": [
842 "@executable_path/.../Frameworks"
843 ]
844 }],
845 "reexported_libraries": [ { "names": ["@rpath/libfoo.dylib"] } ],
846 "flags":[
847 { "attributes": ["not_app_extension_safe"] }
848 ],
849 "exported_symbols": [
850 {
851 "text": {
852 "global": [ "_funcFoo" ]
853 }
854 }
855 ]
856 },
857 {
858 "target_info": [
859 {
860 "target": "armv7-ios",
861 "min_deployment": "11.0"
862 }
863 ],
864 "install_names":[
865 { "name":"@rpath/libfoo.dylib" }
866 ],
867 "exported_symbols": [
868 {
869 "data": {
870 "global": [ "_varFooBaz" ]
871 }
872 }
873 ]
874 }
875]})";
876
877 InterfaceFile File;
878 File.setFileType(FileType::TBD_V5);
879
880 TargetList AllTargets = {
881 Target(AK_armv7, PLATFORM_IOS, VersionTuple(11, 0)),
882 Target(AK_armv7s, PLATFORM_IOS, VersionTuple(11, 0)),
883 };
884 File.setInstallName("/S/L/F/Foo.framework/Foo");
885 File.addTarget(Target: AllTargets[0]);
886 File.setCurrentVersion(PackedVersion(1, 0, 0));
887 File.setCompatibilityVersion(PackedVersion(1, 0, 0));
888 File.addReexportedLibrary(InstallName: "/u/l/l/libfoo.dylib", Target: AllTargets[0]);
889 File.setTwoLevelNamespace();
890 File.setApplicationExtensionSafe(true);
891
892 InterfaceFile NestedFile;
893 NestedFile.setFileType(FileType::TBD_V5);
894 NestedFile.setInstallName("/u/l/l/libfoo.dylib");
895 NestedFile.addTargets(Targets&: AllTargets);
896 NestedFile.setCompatibilityVersion(PackedVersion(1, 0, 0));
897 NestedFile.setTwoLevelNamespace();
898 NestedFile.setApplicationExtensionSafe(false);
899 NestedFile.setCurrentVersion(PackedVersion(2, 1, 1));
900 NestedFile.addRPath(RPath: "@executable_path/.../Frameworks", InputTarget: AllTargets[0]);
901 for (const auto &Targ : AllTargets)
902 NestedFile.addReexportedLibrary(InstallName: "@rpath/libfoo.dylib", Target: Targ);
903 NestedFile.addSymbol(Kind: EncodeKind::GlobalSymbol, Name: "_funcFoo", Targets&: AllTargets,
904 Flags: SymbolFlags::Text);
905 File.addDocument(Document: std::make_shared<InterfaceFile>(args: std::move(NestedFile)));
906
907 InterfaceFile NestedFileB;
908 NestedFileB.setFileType(FileType::TBD_V5);
909 NestedFileB.setInstallName("@rpath/libfoo.dylib");
910 NestedFileB.addTarget(Target: AllTargets[0]);
911 NestedFileB.setCompatibilityVersion(PackedVersion(1, 0, 0));
912 NestedFileB.setCurrentVersion(PackedVersion(1, 0, 0));
913 NestedFileB.setTwoLevelNamespace();
914 NestedFileB.setApplicationExtensionSafe(true);
915 NestedFileB.addSymbol(Kind: EncodeKind::GlobalSymbol, Name: "_varFooBaz", Target&: {AllTargets[0]},
916 Flags: SymbolFlags::Data);
917 File.addDocument(Document: std::make_shared<InterfaceFile>(args: std::move(NestedFileB)));
918
919 // Write out file then process it back into IF and compare equality
920 // against TBDv5File.
921 SmallString<4096> Buffer;
922 raw_svector_ostream OS(Buffer);
923 Error Result = TextAPIWriter::writeToStream(OS, File, FileKind: FileType::Invalid,
924 /*Compact=*/true);
925 EXPECT_FALSE(Result);
926
927 Expected<TBDFile> Input =
928 TextAPIReader::get(InputBuffer: MemoryBufferRef(TBDv5File, "Input.tbd"));
929 EXPECT_TRUE(!!Input);
930 TBDFile InputFile = std::move(Input.get());
931
932 Expected<TBDFile> Output =
933 TextAPIReader::get(InputBuffer: MemoryBufferRef(Buffer, "Output.tbd"));
934 EXPECT_TRUE(!!Output);
935 TBDFile OutputFile = std::move(Output.get());
936 EXPECT_EQ(*InputFile, *OutputFile);
937}
938
939TEST(TBDv5, Target_Simulator) {
940 static const char TBDv5File[] = R"({
941"tapi_tbd_version": 5,
942"main_library": {
943 "target_info": [
944 {
945 "target": "arm64-ios-simulator",
946 "min_deployment": "11.0"
947 },
948 {
949 "target": "x86_64-ios-simulator",
950 "min_deployment": "11.3"
951 }
952 ],
953 "install_names":[
954 { "name":"/S/L/F/Foo.framework/Foo" }
955 ]
956}})";
957
958 Expected<TBDFile> Result =
959 TextAPIReader::get(InputBuffer: MemoryBufferRef(TBDv5File, "Test.tbd"));
960 EXPECT_TRUE(!!Result);
961 TBDFile File = std::move(Result.get());
962 EXPECT_EQ(FileType::TBD_V5, File->getFileType());
963 TargetList ExpectedTargets = {
964 Target(AK_x86_64, PLATFORM_IOSSIMULATOR, VersionTuple(11, 3)),
965 Target(AK_arm64, PLATFORM_IOSSIMULATOR, VersionTuple(14, 0)),
966 };
967 TargetList Targets{File->targets().begin(), File->targets().end()};
968 llvm::sort(C&: Targets);
969 EXPECT_EQ(Targets, ExpectedTargets);
970
971 SmallString<4096> Buffer;
972 raw_svector_ostream OS(Buffer);
973 Error WriteResult = TextAPIWriter::writeToStream(OS, File: *File);
974 EXPECT_TRUE(!WriteResult);
975
976 Expected<TBDFile> Output =
977 TextAPIReader::get(InputBuffer: MemoryBufferRef(Buffer, "Output.tbd"));
978 EXPECT_TRUE(!!Output);
979 TBDFile WriteResultFile = std::move(Output.get());
980 EXPECT_EQ(*File, *WriteResultFile);
981}
982
983TEST(TBDv5, Target_UnsupportedMinOS) {
984 static const char TBDv5File[] = R"({
985"tapi_tbd_version": 5,
986"main_library": {
987 "target_info": [
988 {
989 "target": "arm64-macos",
990 "min_deployment": "10.14"
991 },
992 {
993 "target": "x86_64-macos",
994 "min_deployment": "10.14"
995 }
996 ],
997 "install_names":[
998 { "name":"/S/L/F/Foo.framework/Foo" }
999 ]
1000}})";
1001
1002 Expected<TBDFile> Result =
1003 TextAPIReader::get(InputBuffer: MemoryBufferRef(TBDv5File, "Test.tbd"));
1004 EXPECT_TRUE(!!Result);
1005 TBDFile File = std::move(Result.get());
1006 EXPECT_EQ(FileType::TBD_V5, File->getFileType());
1007 TargetList ExpectedTargets = {
1008 Target(AK_x86_64, PLATFORM_MACOS, VersionTuple(10, 14)),
1009 Target(AK_arm64, PLATFORM_MACOS, VersionTuple(11, 0)),
1010 };
1011 TargetList Targets{File->targets().begin(), File->targets().end()};
1012 llvm::sort(C&: Targets);
1013 EXPECT_EQ(Targets, ExpectedTargets);
1014
1015 SmallString<4096> Buffer;
1016 raw_svector_ostream OS(Buffer);
1017 Error WriteResult = TextAPIWriter::writeToStream(OS, File: *File);
1018 EXPECT_TRUE(!WriteResult);
1019
1020 Expected<TBDFile> Output =
1021 TextAPIReader::get(InputBuffer: MemoryBufferRef(Buffer, "Output.tbd"));
1022 EXPECT_TRUE(!!Output);
1023 TBDFile WriteResultFile = std::move(Output.get());
1024 EXPECT_EQ(*File, *WriteResultFile);
1025}
1026
1027TEST(TBDv5, MisspelledKey) {
1028 static const char TBDv5File[] = R"({
1029"tapi_tbd_version": 5,
1030"main_library": {
1031 "target_info": [
1032 {
1033 "target": "arm64-ios-simulator",
1034 "min_deployment": "11.0"
1035 }
1036 ],
1037 "intall_names":[
1038 { "name":"/S/L/F/Foo.framework/Foo" }
1039 ]
1040}})";
1041
1042 Expected<TBDFile> Result =
1043 TextAPIReader::get(InputBuffer: MemoryBufferRef(TBDv5File, "Test.tbd"));
1044 EXPECT_FALSE(!!Result);
1045 std::string ErrorMessage = toString(E: Result.takeError());
1046 EXPECT_EQ("invalid install_names section\n", ErrorMessage);
1047}
1048
1049TEST(TBDv5, InvalidVersion) {
1050 static const char TBDv5File[] = R"({
1051"tapi_tbd_version": 11,
1052"main_library": {
1053 "target_info": [
1054 {
1055 "target": "arm64-ios-simulator",
1056 "min_deployment": "11.0"
1057 }
1058 ],
1059 "install_names":[
1060 { "name":"/S/L/F/Foo.framework/Foo" }
1061 ]
1062}})";
1063
1064 Expected<TBDFile> Result =
1065 TextAPIReader::get(InputBuffer: MemoryBufferRef(TBDv5File, "Test.tbd"));
1066 EXPECT_FALSE(!!Result);
1067 std::string ErrorMessage = toString(E: Result.takeError());
1068 EXPECT_EQ("invalid tapi_tbd_version section\n", ErrorMessage);
1069}
1070
1071TEST(TBDv5, MissingRequiredKey) {
1072 static const char TBDv5File[] = R"({
1073"main_library": {
1074 "target_info": [
1075 {
1076 "target": "arm64-ios-simulator",
1077 "min_deployment": "11.0"
1078 }
1079 ],
1080 "install_names":[
1081 { "name":"/S/L/F/Foo.framework/Foo" }
1082 ]
1083}})";
1084
1085 Expected<TBDFile> Result =
1086 TextAPIReader::get(InputBuffer: MemoryBufferRef(TBDv5File, "Test.tbd"));
1087 EXPECT_FALSE(!!Result);
1088 std::string ErrorMessage = toString(E: Result.takeError());
1089 EXPECT_EQ("invalid tapi_tbd_version section\n", ErrorMessage);
1090}
1091
1092TEST(TBDv5, InvalidSymbols) {
1093 static const char TBDv5File[] = R"({
1094"tapi_tbd_version": 5,
1095"main_library": {
1096 "target_info": [
1097 {
1098 "target": "arm64-driverkit",
1099 "min_deployment": "11.0"
1100 }
1101 ],
1102 "install_names":[
1103 { "name":"/S/L/F/Foo.framework/Foo" }
1104 ],
1105 "exported_symbols": [
1106 {
1107 "daa": {
1108 "global": {
1109 "weak": []
1110 }
1111 }
1112 }
1113 ]
1114}})";
1115
1116 Expected<TBDFile> Result =
1117 TextAPIReader::get(InputBuffer: MemoryBufferRef(TBDv5File, "Test.tbd"));
1118 EXPECT_FALSE(!!Result);
1119 std::string ErrorMessage = toString(E: Result.takeError());
1120 EXPECT_EQ("invalid exported_symbols section\n", ErrorMessage);
1121}
1122
1123TEST(TBDv5, DefaultMinOS) {
1124 static const char TBDv5File[] = R"({
1125"tapi_tbd_version": 5,
1126"main_library": {
1127 "target_info": [
1128 {
1129 "target": "arm64-ios-simulator"
1130 }
1131 ],
1132 "install_names":[
1133 { "name":"/S/L/F/Foo.framework/Foo" }
1134 ]
1135}})";
1136
1137 Expected<TBDFile> Result =
1138 TextAPIReader::get(InputBuffer: MemoryBufferRef(TBDv5File, "Test.tbd"));
1139 EXPECT_TRUE(!!Result);
1140 TBDFile File = std::move(Result.get());
1141 EXPECT_EQ(FileType::TBD_V5, File->getFileType());
1142 EXPECT_EQ(std::string("/S/L/F/Foo.framework/Foo"), File->getInstallName());
1143 EXPECT_TRUE(File->targets().begin() != File->targets().end());
1144 EXPECT_EQ(*File->targets().begin(),
1145 Target(AK_arm64, PLATFORM_IOSSIMULATOR, VersionTuple(0, 0)));
1146}
1147
1148TEST(TBDv5, InvalidMinOS) {
1149 static const char TBDv5File[] = R"({
1150"tapi_tbd_version": 5,
1151"main_library": {
1152 "target_info": [
1153 {
1154 "target": "arm64-ios-simulator",
1155 "min_deployment": "swift-abi"
1156 }
1157 ],
1158 "install_names":[
1159 { "name":"/S/L/F/Foo.framework/Foo" }
1160 ]
1161}})";
1162
1163 Expected<TBDFile> Result =
1164 TextAPIReader::get(InputBuffer: MemoryBufferRef(TBDv5File, "Test.tbd"));
1165 EXPECT_FALSE(!!Result);
1166 std::string ErrorMessage = toString(E: Result.takeError());
1167 EXPECT_EQ("invalid min_deployment section\n", ErrorMessage);
1168}
1169
1170TEST(TBDv5, SimSupport) {
1171 static const char TBDv5File[] = R"({
1172"tapi_tbd_version": 5,
1173"main_library": {
1174 "target_info": [
1175 {
1176 "target": "arm64-macos",
1177 "min_deployment": "11.1"
1178 }
1179 ],
1180 "install_names":[
1181 { "name":"/S/L/F/Foo.framework/Foo" }
1182 ],
1183 "flags":[
1184 { "attributes": ["sim_support"] }
1185 ]
1186}})";
1187
1188 Expected<TBDFile> Result =
1189 TextAPIReader::get(InputBuffer: MemoryBufferRef(TBDv5File, "Test.tbd"));
1190 EXPECT_TRUE(!!Result);
1191 Target ExpectedTarget = Target(AK_arm64, PLATFORM_MACOS, VersionTuple(11, 1));
1192 TBDFile ReadFile = std::move(Result.get());
1193 EXPECT_EQ(FileType::TBD_V5, ReadFile->getFileType());
1194 EXPECT_EQ(std::string("/S/L/F/Foo.framework/Foo"),
1195 ReadFile->getInstallName());
1196 EXPECT_TRUE(ReadFile->targets().begin() != ReadFile->targets().end());
1197 EXPECT_EQ(*ReadFile->targets().begin(), ExpectedTarget);
1198 EXPECT_TRUE(ReadFile->hasSimulatorSupport());
1199}
1200
1201TEST(TBDv5, NotForSharedCache) {
1202 static const char TBDv5File[] = R"({
1203"tapi_tbd_version": 5,
1204"main_library": {
1205 "target_info": [
1206 {
1207 "target": "arm64-macos",
1208 "min_deployment": "11.1"
1209 }
1210 ],
1211 "install_names":[
1212 { "name":"/S/L/F/Foo.framework/Foo" }
1213 ],
1214 "flags":[
1215 { "attributes": ["not_for_dyld_shared_cache"] }
1216 ]
1217}})";
1218
1219 Expected<TBDFile> Result =
1220 TextAPIReader::get(InputBuffer: MemoryBufferRef(TBDv5File, "Test.tbd"));
1221 EXPECT_TRUE(!!Result);
1222 Target ExpectedTarget = Target(AK_arm64, PLATFORM_MACOS, VersionTuple(11, 1));
1223 TBDFile ReadFile = std::move(Result.get());
1224 EXPECT_EQ(FileType::TBD_V5, ReadFile->getFileType());
1225 EXPECT_EQ(std::string("/S/L/F/Foo.framework/Foo"),
1226 ReadFile->getInstallName());
1227 EXPECT_TRUE(ReadFile->targets().begin() != ReadFile->targets().end());
1228 EXPECT_EQ(*ReadFile->targets().begin(), ExpectedTarget);
1229 EXPECT_FALSE(ReadFile->hasSimulatorSupport());
1230 EXPECT_TRUE(ReadFile->isOSLibNotForSharedCache());
1231}
1232
1233TEST(TBDv5, ObjCInterfaces) {
1234 static const char TBDv5File[] = R"({
1235"tapi_tbd_version": 5,
1236"main_library": {
1237 "target_info": [
1238 {
1239 "target": "arm64-ios-simulator",
1240 "min_deployment": "14.0"
1241 }
1242 ],
1243 "install_names":[
1244 { "name":"/S/L/F/Foo.framework/Foo" }
1245 ],
1246 "exported_symbols": [
1247 {
1248 "data": {
1249 "global": [
1250 "_global",
1251 "_OBJC_METACLASS_$_Standalone",
1252 "_OBJC_CLASS_$_Standalone2"
1253 ],
1254 "weak": ["_OBJC_EHTYPE_$_NSObject"],
1255 "objc_class": [
1256 "ClassA",
1257 "ClassB"
1258 ],
1259 "objc_eh_type": ["ClassA"]
1260 }
1261 }]
1262}})";
1263
1264 Expected<TBDFile> Result =
1265 TextAPIReader::get(InputBuffer: MemoryBufferRef(TBDv5File, "Test.tbd"));
1266 EXPECT_TRUE(!!Result);
1267 TBDFile File = std::move(Result.get());
1268 EXPECT_EQ(FileType::TBD_V5, File->getFileType());
1269 Target ExpectedTarget =
1270 Target(AK_arm64, PLATFORM_IOSSIMULATOR, VersionTuple(14, 0));
1271 EXPECT_EQ(*File->targets().begin(), ExpectedTarget);
1272
1273 // Check Symbols.
1274 ExportedSymbolSeq Exports;
1275 for (const auto *Sym : File->symbols()) {
1276 ExportedSymbol Temp =
1277 ExportedSymbol{.Kind: Sym->getKind(), .Name: std::string(Sym->getName()),
1278 .Weak: Sym->isWeakDefined() || Sym->isWeakReferenced(),
1279 .ThreadLocalValue: Sym->isThreadLocalValue(), .isData: Sym->isData()};
1280 Exports.emplace_back(args: std::move(Temp));
1281 }
1282 llvm::sort(C&: Exports);
1283
1284 std::vector<ExportedSymbol> ExpectedExports = {
1285 {.Kind: EncodeKind::GlobalSymbol, .Name: "_OBJC_CLASS_$_Standalone2", .Weak: false, .ThreadLocalValue: false,
1286 .isData: true},
1287 {.Kind: EncodeKind::GlobalSymbol, .Name: "_OBJC_EHTYPE_$_NSObject", .Weak: true, .ThreadLocalValue: false, .isData: true},
1288 {.Kind: EncodeKind::GlobalSymbol, .Name: "_OBJC_METACLASS_$_Standalone", .Weak: false, .ThreadLocalValue: false,
1289 .isData: true},
1290 {.Kind: EncodeKind::GlobalSymbol, .Name: "_global", .Weak: false, .ThreadLocalValue: false, .isData: true},
1291 {.Kind: EncodeKind::ObjectiveCClass, .Name: "ClassA", .Weak: false, .ThreadLocalValue: false, .isData: true},
1292 {.Kind: EncodeKind::ObjectiveCClass, .Name: "ClassB", .Weak: false, .ThreadLocalValue: false, .isData: true},
1293 {.Kind: EncodeKind::ObjectiveCClassEHType, .Name: "ClassA", .Weak: false, .ThreadLocalValue: false, .isData: true}};
1294
1295 EXPECT_EQ(ExpectedExports.size(), Exports.size());
1296 EXPECT_TRUE(
1297 std::equal(Exports.begin(), Exports.end(), std::begin(ExpectedExports)));
1298
1299 SmallString<4096> Buffer;
1300 raw_svector_ostream OS(Buffer);
1301 Error WriteResult = TextAPIWriter::writeToStream(OS, File: *File);
1302 EXPECT_TRUE(!WriteResult);
1303
1304 Expected<TBDFile> Output =
1305 TextAPIReader::get(InputBuffer: MemoryBufferRef(Buffer, "Output.tbd"));
1306 EXPECT_TRUE(!!Output);
1307 TBDFile WriteResultFile = std::move(Output.get());
1308 EXPECT_EQ(*File, *WriteResultFile);
1309}
1310
1311TEST(TBDv5, MergeIF) {
1312 static const char TBDv5FileA[] = R"({
1313"tapi_tbd_version": 5,
1314"main_library": {
1315 "target_info": [
1316 {
1317 "target": "x86_64-macos",
1318 "min_deployment": "10.14"
1319 },
1320 {
1321 "target": "arm64-macos",
1322 "min_deployment": "10.14"
1323 },
1324 {
1325 "target": "arm64-maccatalyst",
1326 "min_deployment": "12.1"
1327 }
1328 ],
1329 "flags": [
1330 {
1331 "targets": [
1332 "x86_64-macos"
1333 ],
1334 "attributes": [
1335 "flat_namespace"
1336 ]
1337 }
1338 ],
1339 "install_names": [
1340 {
1341 "name": "/S/L/F/Foo.framework/Foo"
1342 }
1343 ],
1344 "current_versions": [
1345 {
1346 "version": "1.2"
1347 }
1348 ],
1349 "compatibility_versions": [
1350 { "version": "1.1" }
1351 ],
1352 "rpaths": [
1353 {
1354 "targets": [
1355 "x86_64-macos"
1356 ],
1357 "paths": [
1358 "@executable_path/.../Frameworks"
1359 ]
1360 }
1361 ],
1362 "parent_umbrellas": [
1363 {
1364 "umbrella": "System"
1365 }
1366 ],
1367 "allowable_clients": [
1368 {
1369 "clients": [
1370 "ClientA",
1371 "ClientB"
1372 ]
1373 }
1374 ],
1375 "reexported_libraries": [
1376 {
1377 "names": [
1378 "/u/l/l/libfoo.dylib",
1379 "/u/l/l/libbar.dylib"
1380 ]
1381 }
1382 ],
1383 "exported_symbols": [
1384 {
1385 "targets": [
1386 "x86_64-macos",
1387 "arm64-macos"
1388 ],
1389 "data": {
1390 "global": [
1391 "_global"
1392 ],
1393 "objc_class": [
1394 "ClassA"
1395 ],
1396 "weak": [],
1397 "thread_local": []
1398 },
1399 "text": {
1400 "global": [
1401 "_func"
1402 ],
1403 "weak": [],
1404 "thread_local": []
1405 }
1406 },
1407 {
1408 "targets": [
1409 "x86_64-macos"
1410 ],
1411 "data": {
1412 "global": [
1413 "_globalVar"
1414 ],
1415 "objc_class": [
1416 "ClassA",
1417 "ClassB",
1418 "ClassData"
1419 ],
1420 "objc_eh_type": [
1421 "ClassA",
1422 "ClassB"
1423 ],
1424 "objc_ivar": [
1425 "ClassA.ivar1",
1426 "ClassA.ivar2",
1427 "ClassC.ivar1"
1428 ]
1429 },
1430 "text": {
1431 "global": [
1432 "_funcFoo"
1433 ]
1434 }
1435 }
1436 ],
1437 "reexported_symbols": [
1438 {
1439 "targets": [
1440 "x86_64-macos",
1441 "arm64-macos"
1442 ],
1443 "data": {
1444 "global": [
1445 "_globalRe"
1446 ],
1447 "objc_class": [
1448 "ClassRexport"
1449 ]
1450 },
1451 "text": {
1452 "global": [
1453 "_funcA"
1454 ]
1455 }
1456 }
1457 ],
1458 "undefined_symbols": [
1459 {
1460 "targets": [
1461 "x86_64-macos"
1462 ],
1463 "data": {
1464 "global": [
1465 "_globalBind"
1466 ],
1467 "weak": [
1468 "referenced_sym"
1469 ]
1470 }
1471 }
1472 ]
1473},
1474"libraries": []
1475})";
1476
1477 static const char TBDv5FileB[] = R"({
1478"tapi_tbd_version": 5,
1479"main_library": {
1480 "target_info": [
1481 {
1482 "target": "x86_64-macos",
1483 "min_deployment": "10.14"
1484 },
1485 {
1486 "target": "arm64-macos",
1487 "min_deployment": "10.14"
1488 },
1489 {
1490 "target": "arm64-maccatalyst",
1491 "min_deployment": "12.1"
1492 }
1493 ],
1494 "flags": [
1495 {
1496 "targets": [
1497 "x86_64-macos"
1498 ],
1499 "attributes": [
1500 "flat_namespace"
1501 ]
1502 }
1503 ],
1504 "install_names": [
1505 {
1506 "name": "/S/L/F/Foo.framework/Foo"
1507 }
1508 ],
1509 "current_versions": [
1510 {
1511 "version": "1.2"
1512 }
1513 ],
1514 "compatibility_versions": [
1515 { "version": "1.1" }
1516 ],
1517 "exported_symbols": [
1518 {
1519 "targets": [
1520 "x86_64-macos",
1521 "arm64-macos"
1522 ],
1523 "data": {
1524 "global": [
1525 "_globalZ"
1526 ],
1527 "objc_class": [
1528 "ClassZ"
1529 ],
1530 "weak": [],
1531 "thread_local": []
1532 },
1533 "text": {
1534 "global": [
1535 "_funcZ"
1536 ],
1537 "weak": [],
1538 "thread_local": []
1539 }
1540 },
1541 {
1542 "targets": [
1543 "x86_64-macos"
1544 ],
1545 "data": {
1546 "global": [
1547 "_globalVarZ"
1548 ],
1549 "objc_class": [
1550 "ClassZ",
1551 "ClassF"
1552 ],
1553 "objc_eh_type": [
1554 "ClassZ",
1555 "ClassF"
1556 ],
1557 "objc_ivar": [
1558 "ClassZ.ivar1",
1559 "ClassZ.ivar2",
1560 "ClassF.ivar1"
1561 ]
1562 },
1563 "text": {
1564 "global": [
1565 "_funcFooZ"
1566 ]
1567 }
1568 }
1569 ]
1570},
1571"libraries": []
1572})";
1573
1574 Expected<TBDFile> ResultA =
1575 TextAPIReader::get(InputBuffer: MemoryBufferRef(TBDv5FileA, "Test.tbd"));
1576 EXPECT_TRUE(!!ResultA);
1577 TBDFile FileA = std::move(ResultA.get());
1578
1579 Expected<TBDFile> ResultB =
1580 TextAPIReader::get(InputBuffer: MemoryBufferRef(TBDv5FileB, "Test.tbd"));
1581 EXPECT_TRUE(!!ResultB);
1582 TBDFile FileB = std::move(ResultB.get());
1583
1584 Expected<TBDFile> MergedResult = FileA->merge(O: FileB.get());
1585 EXPECT_TRUE(!!MergedResult);
1586 TBDFile MergedFile = std::move(MergedResult.get());
1587
1588 EXPECT_EQ(FileType::TBD_V5, MergedFile->getFileType());
1589 EXPECT_EQ(std::string("/S/L/F/Foo.framework/Foo"),
1590 MergedFile->getInstallName());
1591 TargetList AllTargets = {
1592 Target(AK_x86_64, PLATFORM_MACOS, VersionTuple(10, 14)),
1593 Target(AK_arm64, PLATFORM_MACOS, VersionTuple(11, 0, 0)),
1594 Target(AK_arm64, PLATFORM_MACCATALYST, VersionTuple(14, 0)),
1595 };
1596 EXPECT_EQ(mapToPlatformSet(AllTargets), MergedFile->getPlatforms());
1597 EXPECT_EQ(mapToArchitectureSet(AllTargets), MergedFile->getArchitectures());
1598 EXPECT_EQ(PackedVersion(1, 2, 0), MergedFile->getCurrentVersion());
1599 EXPECT_EQ(PackedVersion(1, 1, 0), MergedFile->getCompatibilityVersion());
1600 EXPECT_TRUE(MergedFile->isApplicationExtensionSafe());
1601 EXPECT_FALSE(MergedFile->isTwoLevelNamespace());
1602 EXPECT_EQ(0U, MergedFile->documents().size());
1603 InterfaceFileRef ClientA("ClientA", AllTargets);
1604 InterfaceFileRef ClientB("ClientB", AllTargets);
1605 EXPECT_EQ(2U, MergedFile->allowableClients().size());
1606 EXPECT_EQ(ClientA, MergedFile->allowableClients().at(0));
1607 EXPECT_EQ(ClientB, MergedFile->allowableClients().at(1));
1608
1609 InterfaceFileRef ReexportA("/u/l/l/libbar.dylib", AllTargets);
1610 InterfaceFileRef ReexportB("/u/l/l/libfoo.dylib", AllTargets);
1611 EXPECT_EQ(2U, MergedFile->reexportedLibraries().size());
1612 EXPECT_EQ(ReexportA, MergedFile->reexportedLibraries().at(0));
1613 EXPECT_EQ(ReexportB, MergedFile->reexportedLibraries().at(1));
1614
1615 TargetToAttr RPaths = {
1616 {Target(AK_x86_64, PLATFORM_MACOS), "@executable_path/.../Frameworks"},
1617 };
1618 EXPECT_EQ(RPaths, MergedFile->rpaths());
1619
1620 TargetToAttr Umbrellas = {{Target(AK_x86_64, PLATFORM_MACOS), "System"},
1621 {Target(AK_arm64, PLATFORM_MACOS), "System"},
1622 {Target(AK_arm64, PLATFORM_MACCATALYST), "System"}};
1623 EXPECT_EQ(Umbrellas, MergedFile->umbrellas());
1624
1625 ExportedSymbolSeq Exports, Reexports, Undefineds;
1626 for (const auto *Sym : MergedFile->symbols()) {
1627 TargetList SymTargets{Sym->targets().begin(), Sym->targets().end()};
1628 ExportedSymbol Temp =
1629 ExportedSymbol{.Kind: Sym->getKind(),
1630 .Name: std::string(Sym->getName()),
1631 .Weak: Sym->isWeakDefined() || Sym->isWeakReferenced(),
1632 .ThreadLocalValue: Sym->isThreadLocalValue(),
1633 .isData: Sym->isData(),
1634 .Targets: SymTargets};
1635 if (Sym->isUndefined())
1636 Undefineds.emplace_back(args: std::move(Temp));
1637 else
1638 Sym->isReexported() ? Reexports.emplace_back(args: std::move(Temp))
1639 : Exports.emplace_back(args: std::move(Temp));
1640 }
1641 llvm::sort(C&: Exports);
1642 llvm::sort(C&: Reexports);
1643 llvm::sort(C&: Undefineds);
1644
1645 TargetList MacOSTargets = {Target(AK_x86_64, PLATFORM_MACOS),
1646 Target(AK_arm64, PLATFORM_MACOS)};
1647
1648 std::vector<ExportedSymbol> ExpectedExportedSymbols = {
1649 {.Kind: EncodeKind::GlobalSymbol, .Name: "_func", .Weak: false, .ThreadLocalValue: false, .isData: false, .Targets: MacOSTargets},
1650 {.Kind: EncodeKind::GlobalSymbol,
1651 .Name: "_funcFoo",
1652 .Weak: false,
1653 .ThreadLocalValue: false,
1654 .isData: false,
1655 .Targets: {Target(AK_x86_64, PLATFORM_MACOS)}},
1656 {.Kind: EncodeKind::GlobalSymbol,
1657 .Name: "_funcFooZ",
1658 .Weak: false,
1659 .ThreadLocalValue: false,
1660 .isData: false,
1661 .Targets: {Target(AK_x86_64, PLATFORM_MACOS)}},
1662 {.Kind: EncodeKind::GlobalSymbol, .Name: "_funcZ", .Weak: false, .ThreadLocalValue: false, .isData: false, .Targets: MacOSTargets},
1663 {.Kind: EncodeKind::GlobalSymbol, .Name: "_global", .Weak: false, .ThreadLocalValue: false, .isData: true, .Targets: MacOSTargets},
1664 {.Kind: EncodeKind::GlobalSymbol,
1665 .Name: "_globalVar",
1666 .Weak: false,
1667 .ThreadLocalValue: false,
1668 .isData: true,
1669 .Targets: {Target(AK_x86_64, PLATFORM_MACOS)}},
1670 {.Kind: EncodeKind::GlobalSymbol,
1671 .Name: "_globalVarZ",
1672 .Weak: false,
1673 .ThreadLocalValue: false,
1674 .isData: true,
1675 .Targets: {Target(AK_x86_64, PLATFORM_MACOS)}},
1676 {.Kind: EncodeKind::GlobalSymbol, .Name: "_globalZ", .Weak: false, .ThreadLocalValue: false, .isData: true, .Targets: MacOSTargets},
1677 {.Kind: EncodeKind::ObjectiveCClass,
1678 .Name: "ClassA",
1679 .Weak: false,
1680 .ThreadLocalValue: false,
1681 .isData: true,
1682 .Targets: {Target(AK_x86_64, PLATFORM_MACOS)}},
1683 {.Kind: EncodeKind::ObjectiveCClass,
1684 .Name: "ClassB",
1685 .Weak: false,
1686 .ThreadLocalValue: false,
1687 .isData: true,
1688 .Targets: {Target(AK_x86_64, PLATFORM_MACOS)}},
1689 {.Kind: EncodeKind::ObjectiveCClass,
1690 .Name: "ClassData",
1691 .Weak: false,
1692 .ThreadLocalValue: false,
1693 .isData: true,
1694 .Targets: {Target(AK_x86_64, PLATFORM_MACOS)}},
1695 {.Kind: EncodeKind::ObjectiveCClass,
1696 .Name: "ClassF",
1697 .Weak: false,
1698 .ThreadLocalValue: false,
1699 .isData: true,
1700 .Targets: {Target(AK_x86_64, PLATFORM_MACOS)}},
1701 {.Kind: EncodeKind::ObjectiveCClass,
1702 .Name: "ClassZ",
1703 .Weak: false,
1704 .ThreadLocalValue: false,
1705 .isData: true,
1706 .Targets: {Target(AK_x86_64, PLATFORM_MACOS)}},
1707 {.Kind: EncodeKind::ObjectiveCClassEHType,
1708 .Name: "ClassA",
1709 .Weak: false,
1710 .ThreadLocalValue: false,
1711 .isData: true,
1712 .Targets: {Target(AK_x86_64, PLATFORM_MACOS)}},
1713 {.Kind: EncodeKind::ObjectiveCClassEHType,
1714 .Name: "ClassB",
1715 .Weak: false,
1716 .ThreadLocalValue: false,
1717 .isData: true,
1718 .Targets: {Target(AK_x86_64, PLATFORM_MACOS)}},
1719 {.Kind: EncodeKind::ObjectiveCClassEHType,
1720 .Name: "ClassF",
1721 .Weak: false,
1722 .ThreadLocalValue: false,
1723 .isData: true,
1724 .Targets: {Target(AK_x86_64, PLATFORM_MACOS)}},
1725 {.Kind: EncodeKind::ObjectiveCClassEHType,
1726 .Name: "ClassZ",
1727 .Weak: false,
1728 .ThreadLocalValue: false,
1729 .isData: true,
1730 .Targets: {Target(AK_x86_64, PLATFORM_MACOS)}},
1731 {.Kind: EncodeKind::ObjectiveCInstanceVariable,
1732 .Name: "ClassA.ivar1",
1733 .Weak: false,
1734 .ThreadLocalValue: false,
1735 .isData: true,
1736 .Targets: {Target(AK_x86_64, PLATFORM_MACOS)}},
1737 {.Kind: EncodeKind::ObjectiveCInstanceVariable,
1738 .Name: "ClassA.ivar2",
1739 .Weak: false,
1740 .ThreadLocalValue: false,
1741 .isData: true,
1742 .Targets: {Target(AK_x86_64, PLATFORM_MACOS)}},
1743 {.Kind: EncodeKind::ObjectiveCInstanceVariable,
1744 .Name: "ClassC.ivar1",
1745 .Weak: false,
1746 .ThreadLocalValue: false,
1747 .isData: true,
1748 .Targets: {Target(AK_x86_64, PLATFORM_MACOS)}},
1749 {.Kind: EncodeKind::ObjectiveCInstanceVariable,
1750 .Name: "ClassF.ivar1",
1751 .Weak: false,
1752 .ThreadLocalValue: false,
1753 .isData: true,
1754 .Targets: {Target(AK_x86_64, PLATFORM_MACOS)}},
1755 {.Kind: EncodeKind::ObjectiveCInstanceVariable,
1756 .Name: "ClassZ.ivar1",
1757 .Weak: false,
1758 .ThreadLocalValue: false,
1759 .isData: true,
1760 .Targets: {Target(AK_x86_64, PLATFORM_MACOS)}},
1761 {.Kind: EncodeKind::ObjectiveCInstanceVariable,
1762 .Name: "ClassZ.ivar2",
1763 .Weak: false,
1764 .ThreadLocalValue: false,
1765 .isData: true,
1766 .Targets: {Target(AK_x86_64, PLATFORM_MACOS)}},
1767 };
1768
1769 std::vector<ExportedSymbol> ExpectedReexportedSymbols = {
1770 {.Kind: EncodeKind::GlobalSymbol, .Name: "_funcA", .Weak: false, .ThreadLocalValue: false, .isData: false, .Targets: MacOSTargets},
1771 {.Kind: EncodeKind::GlobalSymbol, .Name: "_globalRe", .Weak: false, .ThreadLocalValue: false, .isData: true, .Targets: MacOSTargets},
1772 {.Kind: EncodeKind::ObjectiveCClass, .Name: "ClassRexport", .Weak: false, .ThreadLocalValue: false, .isData: true,
1773 .Targets: MacOSTargets},
1774 };
1775
1776 std::vector<ExportedSymbol> ExpectedUndefinedSymbols = {
1777 {.Kind: EncodeKind::GlobalSymbol,
1778 .Name: "_globalBind",
1779 .Weak: false,
1780 .ThreadLocalValue: false,
1781 .isData: true,
1782 .Targets: {Target(AK_x86_64, PLATFORM_MACOS)}},
1783 {.Kind: EncodeKind::GlobalSymbol,
1784 .Name: "referenced_sym",
1785 .Weak: true,
1786 .ThreadLocalValue: false,
1787 .isData: true,
1788 .Targets: {Target(AK_x86_64, PLATFORM_MACOS)}},
1789 };
1790
1791 EXPECT_EQ(ExpectedExportedSymbols.size(), Exports.size());
1792 EXPECT_EQ(ExpectedReexportedSymbols.size(), Reexports.size());
1793 EXPECT_EQ(ExpectedUndefinedSymbols.size(), Undefineds.size());
1794 EXPECT_TRUE(std::equal(Exports.begin(), Exports.end(),
1795 std::begin(ExpectedExportedSymbols)));
1796 EXPECT_TRUE(std::equal(Reexports.begin(), Reexports.end(),
1797 std::begin(ExpectedReexportedSymbols)));
1798 EXPECT_TRUE(std::equal(Undefineds.begin(), Undefineds.end(),
1799 std::begin(ExpectedUndefinedSymbols)));
1800}
1801
1802TEST(TBDv5, ExtractIF) {
1803 static const char TBDv5File[] = R"({
1804"tapi_tbd_version": 5,
1805"main_library": {
1806 "target_info": [
1807 {
1808 "target": "x86_64-macos",
1809 "min_deployment": "10.14"
1810 },
1811 {
1812 "target": "arm64-macos",
1813 "min_deployment": "10.14"
1814 },
1815 {
1816 "target": "arm64-maccatalyst",
1817 "min_deployment": "12.1"
1818 }
1819 ],
1820 "flags": [
1821 {
1822 "targets": [
1823 "x86_64-macos"
1824 ],
1825 "attributes": [
1826 "flat_namespace"
1827 ]
1828 }
1829 ],
1830 "install_names": [
1831 {
1832 "name": "/S/L/F/Foo.framework/Foo"
1833 }
1834 ],
1835 "current_versions": [
1836 {
1837 "version": "1.2"
1838 }
1839 ],
1840 "compatibility_versions": [
1841 { "version": "1.1" }
1842 ],
1843 "rpaths": [
1844 {
1845 "targets": [
1846 "x86_64-macos"
1847 ],
1848 "paths": [
1849 "@executable_path/.../Frameworks"
1850 ]
1851 }
1852 ],
1853 "parent_umbrellas": [
1854 {
1855 "umbrella": "System"
1856 }
1857 ],
1858 "allowable_clients": [
1859 {
1860 "clients": [
1861 "ClientA",
1862 "ClientB"
1863 ]
1864 }
1865 ],
1866 "reexported_libraries": [
1867 {
1868 "names": [
1869 "/u/l/l/libfoo.dylib",
1870 "/u/l/l/libbar.dylib"
1871 ]
1872 }
1873 ],
1874 "exported_symbols": [
1875 {
1876 "targets": [
1877 "x86_64-macos",
1878 "arm64-macos"
1879 ],
1880 "data": {
1881 "global": [
1882 "_global"
1883 ],
1884 "objc_class": [
1885 "ClassA"
1886 ],
1887 "weak": [],
1888 "thread_local": []
1889 },
1890 "text": {
1891 "global": [
1892 "_func"
1893 ],
1894 "weak": [],
1895 "thread_local": []
1896 }
1897 },
1898 {
1899 "targets": [
1900 "x86_64-macos"
1901 ],
1902 "data": {
1903 "global": [
1904 "_globalVar"
1905 ],
1906 "objc_class": [
1907 "ClassA",
1908 "ClassB",
1909 "ClassData"
1910 ],
1911 "objc_eh_type": [
1912 "ClassA",
1913 "ClassB"
1914 ],
1915 "objc_ivar": [
1916 "ClassA.ivar1",
1917 "ClassA.ivar2",
1918 "ClassC.ivar1"
1919 ]
1920 },
1921 "text": {
1922 "global": [
1923 "_funcFoo"
1924 ]
1925 }
1926 }
1927 ],
1928 "reexported_symbols": [
1929 {
1930 "targets": [
1931 "x86_64-macos",
1932 "arm64-macos"
1933 ],
1934 "data": {
1935 "global": [
1936 "_globalRe"
1937 ],
1938 "objc_class": [
1939 "ClassRexport"
1940 ]
1941 },
1942 "text": {
1943 "global": [
1944 "_funcA"
1945 ]
1946 }
1947 }
1948 ],
1949 "undefined_symbols": [
1950 {
1951 "targets": [
1952 "x86_64-macos"
1953 ],
1954 "data": {
1955 "global": [
1956 "_globalBind"
1957 ],
1958 "weak": [
1959 "referenced_sym"
1960 ]
1961 }
1962 }
1963 ]
1964},
1965"libraries": []
1966})";
1967
1968 Expected<TBDFile> Result =
1969 TextAPIReader::get(InputBuffer: MemoryBufferRef(TBDv5File, "Test.tbd"));
1970 EXPECT_TRUE(!!Result);
1971 TBDFile File = std::move(Result.get());
1972
1973 Expected<TBDFile> ExtractedResult = File->extract(Arch: AK_arm64);
1974 EXPECT_TRUE(!!ExtractedResult);
1975 TBDFile ExtractedFile = std::move(ExtractedResult.get());
1976
1977 EXPECT_EQ(FileType::TBD_V5, ExtractedFile->getFileType());
1978 EXPECT_EQ(std::string("/S/L/F/Foo.framework/Foo"),
1979 ExtractedFile->getInstallName());
1980
1981 TargetList AllTargets = {
1982 Target(AK_arm64, PLATFORM_MACOS, VersionTuple(11, 0, 0)),
1983 Target(AK_arm64, PLATFORM_MACCATALYST, VersionTuple(14, 0)),
1984 };
1985 EXPECT_EQ(mapToPlatformSet(AllTargets), ExtractedFile->getPlatforms());
1986 EXPECT_EQ(mapToArchitectureSet(AllTargets),
1987 ExtractedFile->getArchitectures());
1988
1989 EXPECT_EQ(PackedVersion(1, 2, 0), ExtractedFile->getCurrentVersion());
1990 EXPECT_EQ(PackedVersion(1, 1, 0), ExtractedFile->getCompatibilityVersion());
1991 EXPECT_TRUE(ExtractedFile->isApplicationExtensionSafe());
1992 EXPECT_FALSE(ExtractedFile->isTwoLevelNamespace());
1993 EXPECT_EQ(0U, ExtractedFile->documents().size());
1994
1995 InterfaceFileRef ClientA("ClientA", AllTargets);
1996 InterfaceFileRef ClientB("ClientB", AllTargets);
1997 EXPECT_EQ(2U, ExtractedFile->allowableClients().size());
1998 EXPECT_EQ(ClientA, ExtractedFile->allowableClients().at(0));
1999 EXPECT_EQ(ClientB, ExtractedFile->allowableClients().at(1));
2000
2001 InterfaceFileRef ReexportA("/u/l/l/libbar.dylib", AllTargets);
2002 InterfaceFileRef ReexportB("/u/l/l/libfoo.dylib", AllTargets);
2003 EXPECT_EQ(2U, ExtractedFile->reexportedLibraries().size());
2004 EXPECT_EQ(ReexportA, ExtractedFile->reexportedLibraries().at(0));
2005 EXPECT_EQ(ReexportB, ExtractedFile->reexportedLibraries().at(1));
2006
2007 EXPECT_EQ(0u, ExtractedFile->rpaths().size());
2008
2009 TargetToAttr Umbrellas = {{Target(AK_arm64, PLATFORM_MACOS), "System"},
2010 {Target(AK_arm64, PLATFORM_MACCATALYST), "System"}};
2011 EXPECT_EQ(Umbrellas, ExtractedFile->umbrellas());
2012
2013 ExportedSymbolSeq Exports, Reexports, Undefineds;
2014 for (const auto *Sym : ExtractedFile->symbols()) {
2015 TargetList SymTargets{Sym->targets().begin(), Sym->targets().end()};
2016 ExportedSymbol Temp =
2017 ExportedSymbol{.Kind: Sym->getKind(),
2018 .Name: std::string(Sym->getName()),
2019 .Weak: Sym->isWeakDefined() || Sym->isWeakReferenced(),
2020 .ThreadLocalValue: Sym->isThreadLocalValue(),
2021 .isData: Sym->isData(),
2022 .Targets: SymTargets};
2023 if (Sym->isUndefined())
2024 Undefineds.emplace_back(args: std::move(Temp));
2025 else
2026 Sym->isReexported() ? Reexports.emplace_back(args: std::move(Temp))
2027 : Exports.emplace_back(args: std::move(Temp));
2028 }
2029 llvm::sort(C&: Exports);
2030 llvm::sort(C&: Reexports);
2031 llvm::sort(C&: Undefineds);
2032
2033 TargetList MacOSTargets = {Target(AK_arm64, PLATFORM_MACOS)};
2034
2035 std::vector<ExportedSymbol> ExpectedExportedSymbols = {
2036 {.Kind: EncodeKind::GlobalSymbol, .Name: "_func", .Weak: false, .ThreadLocalValue: false, .isData: false, .Targets: MacOSTargets},
2037 {.Kind: EncodeKind::GlobalSymbol, .Name: "_global", .Weak: false, .ThreadLocalValue: false, .isData: true, .Targets: MacOSTargets},
2038 {.Kind: EncodeKind::ObjectiveCClass, .Name: "ClassA", .Weak: false, .ThreadLocalValue: false, .isData: true, .Targets: MacOSTargets},
2039 };
2040 std::vector<ExportedSymbol> ExpectedReexportedSymbols = {
2041 {.Kind: EncodeKind::GlobalSymbol, .Name: "_funcA", .Weak: false, .ThreadLocalValue: false, .isData: false, .Targets: MacOSTargets},
2042 {.Kind: EncodeKind::GlobalSymbol, .Name: "_globalRe", .Weak: false, .ThreadLocalValue: false, .isData: true, .Targets: MacOSTargets},
2043 {.Kind: EncodeKind::ObjectiveCClass, .Name: "ClassRexport", .Weak: false, .ThreadLocalValue: false, .isData: true,
2044 .Targets: MacOSTargets},
2045 };
2046
2047 EXPECT_EQ(ExpectedExportedSymbols.size(), Exports.size());
2048 EXPECT_EQ(ExpectedReexportedSymbols.size(), Reexports.size());
2049 EXPECT_EQ(0U, Undefineds.size());
2050 EXPECT_TRUE(std::equal(Exports.begin(), Exports.end(),
2051 std::begin(ExpectedExportedSymbols)));
2052 EXPECT_TRUE(std::equal(Reexports.begin(), Reexports.end(),
2053 std::begin(ExpectedReexportedSymbols)));
2054}
2055
2056TEST(TBDv5, RemoveIF) {
2057 static const char TBDv5File[] = R"({
2058"tapi_tbd_version": 5,
2059"main_library": {
2060 "target_info": [
2061 {
2062 "target": "x86_64-macos",
2063 "min_deployment": "10.14"
2064 },
2065 {
2066 "target": "arm64-macos",
2067 "min_deployment": "10.14"
2068 },
2069 {
2070 "target": "arm64-maccatalyst",
2071 "min_deployment": "12.1"
2072 }
2073 ],
2074 "flags": [
2075 {
2076 "targets": [
2077 "x86_64-macos"
2078 ],
2079 "attributes": [
2080 "flat_namespace"
2081 ]
2082 }
2083 ],
2084 "install_names": [
2085 {
2086 "name": "/S/L/F/Foo.framework/Foo"
2087 }
2088 ],
2089 "current_versions": [
2090 {
2091 "version": "1.2"
2092 }
2093 ],
2094 "compatibility_versions": [
2095 { "version": "1.1" }
2096 ],
2097 "rpaths": [
2098 {
2099 "targets": [
2100 "x86_64-macos"
2101 ],
2102 "paths": [
2103 "@executable_path/.../Frameworks"
2104 ]
2105 }
2106 ],
2107 "parent_umbrellas": [
2108 {
2109 "umbrella": "System"
2110 }
2111 ],
2112 "allowable_clients": [
2113 {
2114 "clients": [
2115 "ClientA",
2116 "ClientB"
2117 ]
2118 }
2119 ],
2120 "reexported_libraries": [
2121 {
2122 "names": [
2123 "/u/l/l/libfoo.dylib",
2124 "/u/l/l/libbar.dylib"
2125 ]
2126 }
2127 ],
2128 "exported_symbols": [
2129 {
2130 "targets": [
2131 "x86_64-macos",
2132 "arm64-macos"
2133 ],
2134 "data": {
2135 "global": [
2136 "_global"
2137 ],
2138 "objc_class": [
2139 "ClassA"
2140 ],
2141 "weak": [],
2142 "thread_local": []
2143 },
2144 "text": {
2145 "global": [
2146 "_func"
2147 ],
2148 "weak": [],
2149 "thread_local": []
2150 }
2151 },
2152 {
2153 "targets": [
2154 "x86_64-macos"
2155 ],
2156 "data": {
2157 "global": [
2158 "_globalVar"
2159 ],
2160 "objc_class": [
2161 "ClassA",
2162 "ClassB",
2163 "ClassData"
2164 ],
2165 "objc_eh_type": [
2166 "ClassA",
2167 "ClassB"
2168 ],
2169 "objc_ivar": [
2170 "ClassA.ivar1",
2171 "ClassA.ivar2",
2172 "ClassC.ivar1"
2173 ]
2174 },
2175 "text": {
2176 "global": [
2177 "_funcFoo"
2178 ]
2179 }
2180 }
2181 ],
2182 "reexported_symbols": [
2183 {
2184 "targets": [
2185 "x86_64-macos",
2186 "arm64-macos"
2187 ],
2188 "data": {
2189 "global": [
2190 "_globalRe"
2191 ],
2192 "objc_class": [
2193 "ClassRexport"
2194 ]
2195 },
2196 "text": {
2197 "global": [
2198 "_funcA"
2199 ]
2200 }
2201 }
2202 ],
2203 "undefined_symbols": [
2204 {
2205 "targets": [
2206 "x86_64-macos"
2207 ],
2208 "data": {
2209 "global": [
2210 "_globalBind"
2211 ],
2212 "weak": [
2213 "referenced_sym"
2214 ]
2215 }
2216 }
2217 ]
2218},
2219"libraries": []
2220})";
2221
2222 Expected<TBDFile> Result =
2223 TextAPIReader::get(InputBuffer: MemoryBufferRef(TBDv5File, "Test.tbd"));
2224 EXPECT_TRUE(!!Result);
2225 TBDFile File = std::move(Result.get());
2226
2227 Expected<TBDFile> RemovedResult = File->remove(Arch: AK_x86_64);
2228 EXPECT_TRUE(!!RemovedResult);
2229 TBDFile RemovedFile = std::move(RemovedResult.get());
2230
2231 EXPECT_EQ(FileType::TBD_V5, RemovedFile->getFileType());
2232 EXPECT_EQ(std::string("/S/L/F/Foo.framework/Foo"),
2233 RemovedFile->getInstallName());
2234
2235 TargetList AllTargets = {
2236 Target(AK_arm64, PLATFORM_MACOS, VersionTuple(11, 0, 0)),
2237 Target(AK_arm64, PLATFORM_MACCATALYST, VersionTuple(14, 0)),
2238 };
2239 EXPECT_EQ(mapToPlatformSet(AllTargets), RemovedFile->getPlatforms());
2240 EXPECT_EQ(mapToArchitectureSet(AllTargets), RemovedFile->getArchitectures());
2241
2242 EXPECT_EQ(PackedVersion(1, 2, 0), RemovedFile->getCurrentVersion());
2243 EXPECT_EQ(PackedVersion(1, 1, 0), RemovedFile->getCompatibilityVersion());
2244 EXPECT_TRUE(RemovedFile->isApplicationExtensionSafe());
2245 EXPECT_FALSE(RemovedFile->isTwoLevelNamespace());
2246 EXPECT_EQ(0U, RemovedFile->documents().size());
2247
2248 InterfaceFileRef ClientA("ClientA", AllTargets);
2249 InterfaceFileRef ClientB("ClientB", AllTargets);
2250 EXPECT_EQ(2U, RemovedFile->allowableClients().size());
2251 EXPECT_EQ(ClientA, RemovedFile->allowableClients().at(0));
2252 EXPECT_EQ(ClientB, RemovedFile->allowableClients().at(1));
2253
2254 InterfaceFileRef ReexportA("/u/l/l/libbar.dylib", AllTargets);
2255 InterfaceFileRef ReexportB("/u/l/l/libfoo.dylib", AllTargets);
2256 EXPECT_EQ(2U, RemovedFile->reexportedLibraries().size());
2257 EXPECT_EQ(ReexportA, RemovedFile->reexportedLibraries().at(0));
2258 EXPECT_EQ(ReexportB, RemovedFile->reexportedLibraries().at(1));
2259
2260 EXPECT_EQ(0u, RemovedFile->rpaths().size());
2261
2262 TargetToAttr Umbrellas = {{Target(AK_arm64, PLATFORM_MACOS), "System"},
2263 {Target(AK_arm64, PLATFORM_MACCATALYST), "System"}};
2264 EXPECT_EQ(Umbrellas, RemovedFile->umbrellas());
2265
2266 ExportedSymbolSeq Exports, Reexports, Undefineds;
2267 for (const auto *Sym : RemovedFile->symbols()) {
2268 TargetList SymTargets{Sym->targets().begin(), Sym->targets().end()};
2269 ExportedSymbol Temp =
2270 ExportedSymbol{.Kind: Sym->getKind(),
2271 .Name: std::string(Sym->getName()),
2272 .Weak: Sym->isWeakDefined() || Sym->isWeakReferenced(),
2273 .ThreadLocalValue: Sym->isThreadLocalValue(),
2274 .isData: Sym->isData(),
2275 .Targets: SymTargets};
2276 if (Sym->isUndefined())
2277 Undefineds.emplace_back(args: std::move(Temp));
2278 else
2279 Sym->isReexported() ? Reexports.emplace_back(args: std::move(Temp))
2280 : Exports.emplace_back(args: std::move(Temp));
2281 }
2282 llvm::sort(C&: Exports);
2283 llvm::sort(C&: Reexports);
2284 llvm::sort(C&: Undefineds);
2285
2286 TargetList MacOSTargets = {Target(AK_arm64, PLATFORM_MACOS)};
2287
2288 std::vector<ExportedSymbol> ExpectedExportedSymbols = {
2289 {.Kind: EncodeKind::GlobalSymbol, .Name: "_func", .Weak: false, .ThreadLocalValue: false, .isData: false, .Targets: MacOSTargets},
2290 {.Kind: EncodeKind::GlobalSymbol, .Name: "_global", .Weak: false, .ThreadLocalValue: false, .isData: true, .Targets: MacOSTargets},
2291 {.Kind: EncodeKind::ObjectiveCClass, .Name: "ClassA", .Weak: false, .ThreadLocalValue: false, .isData: true, .Targets: MacOSTargets},
2292 };
2293 std::vector<ExportedSymbol> ExpectedReexportedSymbols = {
2294 {.Kind: EncodeKind::GlobalSymbol, .Name: "_funcA", .Weak: false, .ThreadLocalValue: false, .isData: false, .Targets: MacOSTargets},
2295 {.Kind: EncodeKind::GlobalSymbol, .Name: "_globalRe", .Weak: false, .ThreadLocalValue: false, .isData: true, .Targets: MacOSTargets},
2296 {.Kind: EncodeKind::ObjectiveCClass, .Name: "ClassRexport", .Weak: false, .ThreadLocalValue: false, .isData: true,
2297 .Targets: MacOSTargets},
2298 };
2299
2300 EXPECT_EQ(ExpectedExportedSymbols.size(), Exports.size());
2301 EXPECT_EQ(ExpectedReexportedSymbols.size(), Reexports.size());
2302 EXPECT_EQ(0U, Undefineds.size());
2303 EXPECT_TRUE(std::equal(Exports.begin(), Exports.end(),
2304 std::begin(ExpectedExportedSymbols)));
2305 EXPECT_TRUE(std::equal(Reexports.begin(), Reexports.end(),
2306 std::begin(ExpectedReexportedSymbols)));
2307}
2308
2309TEST(TBDv5, InlineIF) {
2310 static const char UmbrellaFile[] = R"({
2311"tapi_tbd_version": 5,
2312"main_library": {
2313 "target_info": [
2314 {
2315 "target": "x86_64-macos",
2316 "min_deployment": "10.14"
2317 },
2318 {
2319 "target": "arm64-macos",
2320 "min_deployment": "10.14"
2321 }
2322 ],
2323 "install_names": [
2324 {
2325 "name": "/S/L/F/Foo.framework/Foo"
2326 }
2327 ],
2328 "current_versions": [
2329 {
2330 "version": "1.2"
2331 }
2332 ],
2333 "reexported_libraries": [
2334 {
2335 "names": [
2336 "/u/l/l/libfoo.dylib",
2337 "/u/l/l/libbar.dylib"
2338 ]
2339 }
2340 ]
2341}})";
2342
2343 static const char ReexportFile[] = R"({
2344"tapi_tbd_version": 5,
2345"main_library": {
2346 "target_info": [
2347 {
2348 "target": "x86_64-macos",
2349 "min_deployment": "10.14"
2350 },
2351 {
2352 "target": "arm64-macos",
2353 "min_deployment": "10.14"
2354 }
2355 ],
2356 "install_names": [
2357 {
2358 "name" : "/u/l/l/libfoo.dylib"
2359 }
2360 ],
2361 "current_versions": [
2362 {
2363 "version": "1"
2364 }
2365 ],
2366 "rpaths": [
2367 {
2368 "targets": [
2369 "x86_64-macos"
2370 ],
2371 "paths": [
2372 "@executable_path/.../Frameworks"
2373 ]
2374 }
2375 ],
2376 "exported_symbols": [
2377 {
2378 "targets": [
2379 "x86_64-macos",
2380 "arm64-macos"
2381 ],
2382 "data": {
2383 "global": [
2384 "_global"
2385 ],
2386 "objc_class": [
2387 "ClassA"
2388 ],
2389 "weak": [],
2390 "thread_local": []
2391 }
2392 }
2393 ]}})";
2394
2395 Expected<TBDFile> UmbrellaResult =
2396 TextAPIReader::get(InputBuffer: MemoryBufferRef(UmbrellaFile, "Test.tbd"));
2397 EXPECT_TRUE(!!UmbrellaResult);
2398 TBDFile Umbrella = std::move(UmbrellaResult.get());
2399
2400 Expected<TBDFile> ReexportResult =
2401 TextAPIReader::get(InputBuffer: MemoryBufferRef(ReexportFile, "Test.tbd"));
2402 EXPECT_TRUE(!!ReexportResult);
2403 TBDReexportFile Reexport = std::move(ReexportResult.get());
2404 Umbrella->inlineLibrary(Library: Reexport);
2405
2406 EXPECT_EQ(FileType::TBD_V5, Umbrella->getFileType());
2407 EXPECT_EQ(std::string("/S/L/F/Foo.framework/Foo"),
2408 Umbrella->getInstallName());
2409
2410 TargetList AllTargets = {
2411 Target(AK_x86_64, PLATFORM_MACOS, VersionTuple(10, 14)),
2412 Target(AK_arm64, PLATFORM_MACOS, VersionTuple(11, 0, 0)),
2413 };
2414 EXPECT_EQ(mapToPlatformSet(AllTargets), Umbrella->getPlatforms());
2415 EXPECT_EQ(mapToArchitectureSet(AllTargets), Umbrella->getArchitectures());
2416
2417 EXPECT_EQ(PackedVersion(1, 2, 0), Umbrella->getCurrentVersion());
2418 EXPECT_EQ(PackedVersion(1, 0, 0), Umbrella->getCompatibilityVersion());
2419 InterfaceFileRef ReexportA("/u/l/l/libbar.dylib", AllTargets);
2420 InterfaceFileRef ReexportB("/u/l/l/libfoo.dylib", AllTargets);
2421 EXPECT_EQ(2U, Umbrella->reexportedLibraries().size());
2422 EXPECT_EQ(ReexportA, Umbrella->reexportedLibraries().at(0));
2423 EXPECT_EQ(ReexportB, Umbrella->reexportedLibraries().at(1));
2424 EXPECT_EQ(1U, Umbrella->documents().size());
2425
2426 TBDReexportFile Document = Umbrella->documents().front();
2427 EXPECT_EQ(std::string("/u/l/l/libfoo.dylib"), Document->getInstallName());
2428 EXPECT_EQ(0U, Document->getSwiftABIVersion());
2429 EXPECT_TRUE(Document->isTwoLevelNamespace());
2430 EXPECT_TRUE(Document->isApplicationExtensionSafe());
2431 EXPECT_EQ(PackedVersion(1, 0, 0), Document->getCurrentVersion());
2432 EXPECT_EQ(PackedVersion(1, 0, 0), Document->getCompatibilityVersion());
2433
2434 ExportedSymbolSeq Exports;
2435 for (const auto *Sym : Document->symbols()) {
2436 TargetList SymTargets{Sym->targets().begin(), Sym->targets().end()};
2437 Exports.emplace_back(
2438 args: ExportedSymbol{.Kind: Sym->getKind(), .Name: std::string(Sym->getName()),
2439 .Weak: Sym->isWeakDefined() || Sym->isWeakReferenced(),
2440 .ThreadLocalValue: Sym->isThreadLocalValue(), .isData: Sym->isData(), .Targets: SymTargets});
2441 }
2442 llvm::sort(C&: Exports);
2443
2444 ExportedSymbolSeq ExpectedExports = {
2445 {.Kind: EncodeKind::GlobalSymbol, .Name: "_global", .Weak: false, .ThreadLocalValue: false, .isData: true, .Targets: AllTargets},
2446 {.Kind: EncodeKind::ObjectiveCClass, .Name: "ClassA", .Weak: false, .ThreadLocalValue: false, .isData: true, .Targets: AllTargets},
2447 };
2448 EXPECT_EQ(ExpectedExports.size(), Exports.size());
2449 EXPECT_TRUE(
2450 std::equal(Exports.begin(), Exports.end(), std::begin(ExpectedExports)));
2451}
2452} // end namespace TBDv5
2453

source code of llvm/unittests/TextAPI/TextStubV5Tests.cpp