diff --git a/llvm/test/tools/llvm-readtapi/command-line.test b/llvm/test/tools/llvm-readtapi/command-line.test index 400e0670e5aa0..f12e1da70ec42 100644 --- a/llvm/test/tools/llvm-readtapi/command-line.test +++ b/llvm/test/tools/llvm-readtapi/command-line.test @@ -4,7 +4,7 @@ ; RUN: not llvm-readtapi -merge -compact %t/tmp.tbd %t/tmp2.tbd --filetype=tbd-v2 2>&1 | FileCheck %s --check-prefix FILE_FORMAT CHECK: OVERVIEW: LLVM TAPI file reader and manipulator -CHECK: USAGE: llvm-readtapi [options] +CHECK: USAGE: llvm-readtapi [options] [-arch ]* [-o ]* CHECK: OPTIONS: CHECK: -help display this help diff --git a/llvm/test/tools/llvm-readtapi/extract-invalid.test b/llvm/test/tools/llvm-readtapi/extract-invalid.test new file mode 100644 index 0000000000000..026b782eb00c1 --- /dev/null +++ b/llvm/test/tools/llvm-readtapi/extract-invalid.test @@ -0,0 +1,53 @@ +; RUN: rm -rf %t +; RUN: split-file %s %t +; RUN: not llvm-readtapi -extract %t/libfoo.tbd %t/libbar.tbd 2>&1 | FileCheck %s --allow-empty --check-prefix EXTRA +; RUN: not llvm-readtapi -extract %t/libfoo.tbd 2>&1 | FileCheck %s --allow-empty --check-prefix MISSING +; RUN: not llvm-readtapi -arch x86_64 -extract %t/libfoo.tbd 2>&1 | FileCheck %s --allow-empty --check-prefix MISMATCH + +; EXTRA: error: extract only supports one input file +; MISSING: extract requires -arch +; MISMATCH: error: {{.*}}libfoo.tbd' file doesn't have architecture 'x86_64' + +;--- libfoo.tbd +--- !tapi-tbd +tbd-version: 4 +targets: [ arm64-ios ] +flags: [ not_app_extension_safe ] +install-name: '/usr/lib/libfoo.dylib' +exports: + - targets: [ arm64-ios ] + symbols: [ _bar ] +... + +;--- libbar.tbd +{ + "main_library": { + "exported_symbols": [ + { + "data": { + "global": [ + "_bar" + ] + } + } + ], + "flags": [ + { + "attributes": [ + "not_app_extension_safe" + ] + } + ], + "install_names": [ + { + "name": "/usr/lib/libbar.dylib" + } + ], + "target_info": [ + { + "target": "arm64-ios" + } + ] + }, + "tapi_tbd_version": 5 +} diff --git a/llvm/test/tools/llvm-readtapi/extract.test b/llvm/test/tools/llvm-readtapi/extract.test new file mode 100644 index 0000000000000..175efcda2d7cb --- /dev/null +++ b/llvm/test/tools/llvm-readtapi/extract.test @@ -0,0 +1,201 @@ +; RUN: rm -rf %t +; RUN: split-file %s %t +; RUN: llvm-readtapi -arch x86_64 -extract %t/libfat.tbd -compact -o %t/libslim.tbd 2>&1 | FileCheck --allow-empty %s +; RUN: llvm-readtapi --compare %t/libslim.tbd %t/libslim_expected.tbd 2>&1 | FileCheck --allow-empty %s + +; RUN: llvm-readtapi -arch armv7s --extract %t/libfat2.tbd 2>&1 | FileCheck %s --check-prefix OUTPUT + +; CHECK-NOT: error +; CHECK-NOT: warning + +; OUTPUT: { +; OUTPUT-NEXT: "main_library": { +; OUTPUT-NEXT: "install_names": [ +; OUTPUT-NEXT: { +; OUTPUT-NEXT: "name": "/usr/lib/libfat.dylib" +; OUTPUT-NEXT: } +; OUTPUT-NEXT: ], +; OUTPUT-NEXT: "target_info": [ +; OUTPUT-NEXT: { +; OUTPUT-NEXT: "target": "armv7s-ios" +; OUTPUT-NEXT: } +; OUTPUT-NEXT: ] +; OUTPUT-NEXT: }, +; OUTPUT-NEXT: "tapi_tbd_version": 5 +; OUTPUT-NEXT: } + +//--- libfat.tbd +{ + "libraries": [ + { + "exported_symbols": [ + { + "data": { + "global": [ + "_sym1" + ] + }, + "targets": [ + "x86_64-macos" + ] + }, + { + "data": { + "global": [ + "_sym2" + ] + }, + "targets": [ + "x86_64h-macos" + ] + } + ], + "install_names": [ + { + "name": "/usr/lib/internal/libfat.dylib" + } + ], + "parent_umbrellas": [ + { + "umbrella": "fat" + } + ], + "target_info": [ + { + "target": "x86_64-macos" + }, + { + "target": "x86_64h-macos" + } + ] + } + ], + "main_library": { + "install_names": [ + { + "name": "/usr/lib/libfat.dylib" + } + ], + "reexported_libraries": [ + { + "names": [ + "/usr/lib/internal/libfat.dylib" + ] + } + ], + "target_info": [ + { + "target": "x86_64-macos" + }, + { + "target": "x86_64h-macos" + } + ] + }, + "tapi_tbd_version": 5 +} + +//--- libfat2.tbd +{ + "libraries": [ + { + "exported_symbols": [ + { + "data": { + "global": [ + "_sym1" + ] + } + } + ], + "install_names": [ + { + "name": "/usr/lib/internal/libfat.dylib" + } + ], + "target_info": [ + { + "target": "arm64-ios" + } + ] + } + ], + "main_library": { + "install_names": [ + { + "name": "/usr/lib/libfat.dylib" + } + ], + "reexported_libraries": [ + { + "names": [ + "/usr/lib/internal/libfat.dylib" + ], + "targets": [ + "arm64-ios" + ] + } + ], + "target_info": [ + { + "target": "armv7s-ios" + }, + { + "target": "arm64-ios" + } + ] + }, + "tapi_tbd_version": 5 +} + +//--- libslim_expected.tbd +{ + "libraries": [ + { + "exported_symbols": [ + { + "data": { + "global": [ + "_sym1" + ] + } + } + ], + "install_names": [ + { + "name": "/usr/lib/internal/libfat.dylib" + } + ], + "parent_umbrellas": [ + { + "umbrella": "fat" + } + ], + "target_info": [ + { + "target": "x86_64-macos" + } + ] + } + ], + "main_library": { + "install_names": [ + { + "name": "/usr/lib/libfat.dylib" + } + ], + "reexported_libraries": [ + { + "names": [ + "/usr/lib/internal/libfat.dylib" + ] + } + ], + "target_info": [ + { + "target": "x86_64-macos" + } + ] + }, + "tapi_tbd_version": 5 +} diff --git a/llvm/test/tools/llvm-readtapi/remove-invalid.test b/llvm/test/tools/llvm-readtapi/remove-invalid.test new file mode 100644 index 0000000000000..e9de48c9745bf --- /dev/null +++ b/llvm/test/tools/llvm-readtapi/remove-invalid.test @@ -0,0 +1,57 @@ +; RUN: rm -rf %t +; RUN: split-file %s %t +; RUN: not llvm-readtapi --remove -arch arm64 %t/libslim.tbd 2>&1 | FileCheck %s + +CHECK: {{.*}}libslim.tbd' cannot remove last architecture slice 'arm64' + +//--- libslim.tbd +{ + "libraries": [ + { + "exported_symbols": [ + { + "data": { + "global": [ + "_sym1" + ] + } + } + ], + "install_names": [ + { + "name": "/usr/lib/internal/libfat.dylib" + } + ], + "parent_umbrellas": [ + { + "umbrella": "fat" + } + ], + "target_info": [ + { + "target": "arm64-macos" + } + ] + } + ], + "main_library": { + "install_names": [ + { + "name": "/usr/lib/libfat.dylib" + } + ], + "reexported_libraries": [ + { + "names": [ + "/usr/lib/internal/libfat.dylib" + ] + } + ], + "target_info": [ + { + "target": "arm64-macos" + } + ] + }, + "tapi_tbd_version": 5 +} diff --git a/llvm/test/tools/llvm-readtapi/remove.test b/llvm/test/tools/llvm-readtapi/remove.test new file mode 100644 index 0000000000000..673634762f382 --- /dev/null +++ b/llvm/test/tools/llvm-readtapi/remove.test @@ -0,0 +1,274 @@ +; RUN: rm -rf %t +; RUN: split-file %s %t +; RUN: llvm-readtapi --remove -arch x86_64h %t/libfat.tbd -o %t/libslim.tbd 2>&1 | FileCheck --allow-empty %s +; RUN: llvm-readtapi --compare %t/libslim.tbd %t/libslim_expected.tbd + +; RUN: llvm-readtapi --remove -arch x86_64h %t/libfat2.tbd -o %t/libslim2.tbd 2>&1 | FileCheck --allow-empty %s +; RUN: llvm-readtapi --compare %t/libslim2.tbd %t/libslim_expected.tbd + +; RUN: llvm-readtapi --remove -arch x86_64 %t/libfat3.tbd -o %t/libslim3.tbd 2>&1 | FileCheck --allow-empty %s +; RUN: llvm-readtapi --compare %t/libslim3.tbd %t/libslim3_expected.tbd + +; CHECK-NOT: error +; CHECK-NOT: warning + +//--- libfat.tbd +{ + "libraries": [ + { + "exported_symbols": [ + { + "data": { + "global": [ + "_sym1" + ] + }, + "targets": [ + "x86_64-macos" + ] + }, + { + "data": { + "global": [ + "_sym2" + ] + }, + "targets": [ + "x86_64h-macos" + ] + } + ], + "install_names": [ + { + "name": "/usr/lib/internal/libfat.dylib" + } + ], + "parent_umbrellas": [ + { + "umbrella": "fat" + } + ], + "target_info": [ + { + "target": "x86_64-macos" + }, + { + "target": "x86_64h-macos" + } + ] + } + ], + "main_library": { + "install_names": [ + { + "name": "/usr/lib/libfat.dylib" + } + ], + "reexported_libraries": [ + { + "names": [ + "/usr/lib/internal/libfat.dylib" + ] + } + ], + "target_info": [ + { + "target": "x86_64-macos" + }, + { + "target": "x86_64h-macos" + } + ] + }, + "tapi_tbd_version": 5 +} + +//--- libfat2.tbd +{ + "libraries": [ + { + "exported_symbols": [ + { + "data": { + "global": [ + "_sym1" + ] + }, + "targets": [ + "x86_64-macos" + ] + }, + { + "data": { + "global": [ + "_sym2" + ] + }, + "targets": [ + "x86_64h-macos" + ] + } + ], + "install_names": [ + { + "name": "/usr/lib/internal/libfat.dylib" + } + ], + "parent_umbrellas": [ + { + "umbrella": "fat" + } + ], + "target_info": [ + { + "target": "x86_64-macos" + }, + { + "target": "x86_64h-macos" + } + ] + } + ], + "main_library": { + "install_names": [ + { + "name": "/usr/lib/libfat.dylib" + } + ], + "reexported_libraries": [ + { + "names": [ + "/usr/lib/internal/libfat.dylib" + ] + } + ], + "target_info": [ + { + "target": "x86_64-macos" + } + ] + }, + "tapi_tbd_version": 5 +} + +//--- libfat3.tbd +{ + "libraries": [ + { + "exported_symbols": [ + { + "data": { + "global": [ + "_sym1" + ] + } + } + ], + "install_names": [ + { + "name": "/usr/lib/internal/libfat.dylib" + } + ], + "target_info": [ + { + "target": "x86_64-macos" + } + ] + } + ], + "main_library": { + "install_names": [ + { + "name": "/usr/lib/libfat.dylib" + } + ], + "reexported_libraries": [ + { + "names": [ + "/usr/lib/internal/libfat.dylib" + ], + "targets": [ + "x86_64-macos" + ] + } + ], + "target_info": [ + { + "target": "x86_64-macos" + }, + { + "target": "x86_64h-macos" + } + ] + }, + "tapi_tbd_version": 5 +} + +//--- libslim_expected.tbd +{ + "libraries": [ + { + "exported_symbols": [ + { + "data": { + "global": [ + "_sym1" + ] + } + } + ], + "install_names": [ + { + "name": "/usr/lib/internal/libfat.dylib" + } + ], + "parent_umbrellas": [ + { + "umbrella": "fat" + } + ], + "target_info": [ + { + "target": "x86_64-macos" + } + ] + } + ], + "main_library": { + "install_names": [ + { + "name": "/usr/lib/libfat.dylib" + } + ], + "reexported_libraries": [ + { + "names": [ + "/usr/lib/internal/libfat.dylib" + ] + } + ], + "target_info": [ + { + "target": "x86_64-macos" + } + ] + }, + "tapi_tbd_version": 5 +} + +//--- libslim3_expected.tbd +{ + "main_library": { + "install_names": [ + { + "name": "/usr/lib/libfat.dylib" + } + ], + "target_info": [ + { + "target": "x86_64h-macos" + } + ] + }, + "tapi_tbd_version": 5 +} diff --git a/llvm/tools/llvm-readtapi/TapiOpts.td b/llvm/tools/llvm-readtapi/TapiOpts.td index 1efa86ea3ae48..8fda035142a2e 100644 --- a/llvm/tools/llvm-readtapi/TapiOpts.td +++ b/llvm/tools/llvm-readtapi/TapiOpts.td @@ -13,6 +13,8 @@ multiclass JS { def action_group : OptionGroup<"action group">; def compare : FF<"compare", "compare tapi files for library differences">, Group; def merge : FF<"merge", "merge the input files that represent the same library">, Group; +def extract: FF<"extract", "extract architecture from input file">, Group; +def remove: FF<"remove", "remove architecture from input file">, Group; // // General Driver options @@ -21,3 +23,4 @@ def help : FF<"help", "display this help">; defm output: JS<"o", "write output to ","">; def compact: FF<"compact", "write compact tapi output file">; defm filetype: JS<"filetype", "specify the output file type (tbd-v3, tbd-v4 or tbd-v5)","">; +defm arch: JS<"arch", "specify the architecture", "">; diff --git a/llvm/tools/llvm-readtapi/llvm-readtapi.cpp b/llvm/tools/llvm-readtapi/llvm-readtapi.cpp index 44419e8c5c2fc..cb2b36072a552 100644 --- a/llvm/tools/llvm-readtapi/llvm-readtapi.cpp +++ b/llvm/tools/llvm-readtapi/llvm-readtapi.cpp @@ -75,9 +75,11 @@ struct Context { std::unique_ptr OutStream; FileType WriteFT = FileType::TBD_V5; bool Compact = false; + Architecture Arch = AK_unknown; }; -std::unique_ptr getInterfaceFile(const StringRef Filename) { +std::unique_ptr getInterfaceFile(const StringRef Filename, + bool ResetBanner = true) { ExitOnErr.setBanner(TOOLNAME + ": error: '" + Filename.str() + "' "); ErrorOr> BufferOrErr = MemoryBuffer::getFile(Filename); @@ -87,8 +89,8 @@ std::unique_ptr getInterfaceFile(const StringRef Filename) { TextAPIReader::get((*BufferOrErr)->getMemBufferRef()); if (!IF) ExitOnErr(IF.takeError()); - // Set Banner back. - ExitOnErr.setBanner(TOOLNAME + ": error: "); + if (ResetBanner) + ExitOnErr.setBanner(TOOLNAME + ": error: "); return std::move(*IF); } @@ -139,6 +141,24 @@ bool handleMergeAction(const Context &Ctx) { return handleWriteAction(Ctx, std::move(Out)); } +using IFOperation = + std::function>( + const llvm::MachO::InterfaceFile &, Architecture)>; +bool handleSingleFileAction(const Context &Ctx, const StringRef Action, + IFOperation act) { + if (Ctx.Inputs.size() != 1) + reportError(Action + " only supports one input file"); + if (Ctx.Arch == AK_unknown) + reportError(Action + " requires -arch "); + + auto IF = getInterfaceFile(Ctx.Inputs.front(), /*ResetBanner=*/false); + auto OutIF = act(*IF, Ctx.Arch); + if (!OutIF) + ExitOnErr(OutIF.takeError()); + + return handleWriteAction(Ctx, std::move(*OutIF)); +} + } // anonymous namespace int main(int Argc, char **Argv) { @@ -151,7 +171,9 @@ int main(int Argc, char **Argv) { opt::InputArgList Args = Tbl.parseArgs( Argc, Argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) { reportError(Msg); }); if (Args.hasArg(OPT_help)) { - Tbl.printHelp(outs(), "llvm-readtapi [options] ", + Tbl.printHelp(outs(), + "USAGE: llvm-readtapi [options] [-arch ]* [-o " + "]*", "LLVM TAPI file reader and manipulator"); return EXIT_SUCCESS; } @@ -179,6 +201,12 @@ int main(int Argc, char **Argv) { reportError("unsupported filetype '" + FT + "'"); } + if (opt::Arg *A = Args.getLastArg(OPT_arch_EQ)) { + StringRef Arch = A->getValue(); + Ctx.Arch = getArchitectureFromName(Arch); + if (Ctx.Arch == AK_unknown) + reportError("unsupported architecture '" + Arch); + } // Handle top level and exclusive operation. SmallVector ActionArgs(Args.filtered(OPT_action_group)); @@ -200,6 +228,10 @@ int main(int Argc, char **Argv) { return handleCompareAction(Ctx); case OPT_merge: return handleMergeAction(Ctx); + case OPT_extract: + return handleSingleFileAction(Ctx, "extract", &InterfaceFile::extract); + case OPT_remove: + return handleSingleFileAction(Ctx, "remove", &InterfaceFile::remove); } return EXIT_SUCCESS;