[llvm] [readtapi] Add Extract & Remove architecture functionality (PR #72657)

Cyndy Ishida via llvm-commits llvm-commits at lists.llvm.org
Fri Nov 17 15:29:01 PST 2023


https://github.com/cyndyishida updated https://github.com/llvm/llvm-project/pull/72657

>From 2edc9bf1eef85b59323ad366ddbdc9f949a4cf2e Mon Sep 17 00:00:00 2001
From: Cyndy Ishida <cyndy_ishida at apple.com>
Date: Thu, 16 Nov 2023 12:58:09 -0800
Subject: [PATCH 1/2] [readtapi] Add Extract & Remove architecture
 functionality

This adds functionality to tbd files similiar to what `lipo -extract`
and `lipo -remove` does for binaries.
---
 .../tools/llvm-readtapi/command-line.test     |   2 +-
 .../tools/llvm-readtapi/extract-invalid.test  |  53 ++++
 llvm/test/tools/llvm-readtapi/extract.test    | 201 +++++++++++++
 .../tools/llvm-readtapi/remove-invalid.test   |  57 ++++
 llvm/test/tools/llvm-readtapi/remove.test     | 274 ++++++++++++++++++
 llvm/tools/llvm-readtapi/TapiOpts.td          |   3 +
 llvm/tools/llvm-readtapi/llvm-readtapi.cpp    |  36 ++-
 7 files changed, 623 insertions(+), 3 deletions(-)
 create mode 100644 llvm/test/tools/llvm-readtapi/extract-invalid.test
 create mode 100644 llvm/test/tools/llvm-readtapi/extract.test
 create mode 100644 llvm/test/tools/llvm-readtapi/remove-invalid.test
 create mode 100644 llvm/test/tools/llvm-readtapi/remove.test

diff --git a/llvm/test/tools/llvm-readtapi/command-line.test b/llvm/test/tools/llvm-readtapi/command-line.test
index 400e0670e5aa067..67e485ddd7ef501 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] <inputs>
+CHECK: llvm-readtapi [options]* [-arch <arch>]* <inputs> [-o <output>]*
 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 000000000000000..026b782eb00c122
--- /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 <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 000000000000000..175efcda2d7cba1
--- /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 000000000000000..e9de48c9745bfb6
--- /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 000000000000000..673634762f3823f
--- /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 1efa86ea3ae48d6..8fda035142a2ea0 100644
--- a/llvm/tools/llvm-readtapi/TapiOpts.td
+++ b/llvm/tools/llvm-readtapi/TapiOpts.td
@@ -13,6 +13,8 @@ multiclass JS<string name, string help, string var = ""> {
 def action_group : OptionGroup<"action group">;
 def compare : FF<"compare", "compare tapi files for library differences">, Group<action_group>;
 def merge : FF<"merge", "merge the input files that represent the same library">, Group<action_group>;
+def extract: FF<"extract", "extract architecture from input file">, Group<action_group>;
+def remove: FF<"remove", "remove architecture from input file">, Group<action_group>;
 
 //
 // General Driver options 
@@ -21,3 +23,4 @@ def help : FF<"help", "display this help">;
 defm output: JS<"o", "write output to <file>","<file>">;
 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)","<value>">;
+defm arch: JS<"arch", "specify the architecture", "<architecture>">;
diff --git a/llvm/tools/llvm-readtapi/llvm-readtapi.cpp b/llvm/tools/llvm-readtapi/llvm-readtapi.cpp
index 3e0bcc49d19cc4c..2527d1f143b4b43 100644
--- a/llvm/tools/llvm-readtapi/llvm-readtapi.cpp
+++ b/llvm/tools/llvm-readtapi/llvm-readtapi.cpp
@@ -69,6 +69,7 @@ struct Context {
   std::unique_ptr<llvm::raw_fd_stream> OutStream;
   FileType WriteFT = FileType::TBD_V5;
   bool Compact = false;
+  Architecture Arch = AK_unknown;
 };
 
 std::unique_ptr<InterfaceFile> getInterfaceFile(const StringRef Filename,
@@ -137,6 +138,25 @@ bool handleMergeAction(const Context &Ctx) {
   return handleWriteAction(Ctx, std::move(Out));
 }
 
+using IFOperation =
+    std::function<llvm::Expected<std::unique_ptr<InterfaceFile>>(
+        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 <arch>");
+
+  ExitOnError ExitOnErr("error: ");
+  auto IF = getInterfaceFile(Ctx.Inputs.front(), ExitOnErr);
+  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,8 +171,10 @@ int main(int Argc, char **Argv) {
         exit(1);
       });
   if (Args.hasArg(OPT_help)) {
-    Tbl.printHelp(outs(), "llvm-readtapi [options] <inputs>",
-                  "LLVM TAPI file reader and manipulator");
+    Tbl.printHelp(
+        outs(),
+        "llvm-readtapi [options]* [-arch <arch>]* <inputs> [-o <output>]*",
+        "LLVM TAPI file reader and manipulator");
     return EXIT_SUCCESS;
   }
 
@@ -181,6 +203,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<opt::Arg *, 1> ActionArgs(Args.filtered(OPT_action_group));
 
@@ -202,6 +230,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;

>From 94ca1526cb2cad36aae3bd388fcc5eb94657a3a1 Mon Sep 17 00:00:00 2001
From: Cyndy Ishida <cyndy_ishida at apple.com>
Date: Fri, 17 Nov 2023 15:27:51 -0800
Subject: [PATCH 2/2] Remove '*' from help Usage label.

---
 llvm/test/tools/llvm-readtapi/command-line.test | 2 +-
 llvm/tools/llvm-readtapi/llvm-readtapi.cpp      | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/test/tools/llvm-readtapi/command-line.test b/llvm/test/tools/llvm-readtapi/command-line.test
index 67e485ddd7ef501..b13d0bb4533ae85 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: llvm-readtapi [options]* [-arch <arch>]* <inputs> [-o <output>]*
+CHECK: llvm-readtapi [options] [-arch <arch>]* <inputs> [-o <output>]*
 CHECK: OPTIONS:
 CHECK:   -help    display this help
 
diff --git a/llvm/tools/llvm-readtapi/llvm-readtapi.cpp b/llvm/tools/llvm-readtapi/llvm-readtapi.cpp
index 2527d1f143b4b43..d365951d75b0567 100644
--- a/llvm/tools/llvm-readtapi/llvm-readtapi.cpp
+++ b/llvm/tools/llvm-readtapi/llvm-readtapi.cpp
@@ -173,7 +173,7 @@ int main(int Argc, char **Argv) {
   if (Args.hasArg(OPT_help)) {
     Tbl.printHelp(
         outs(),
-        "llvm-readtapi [options]* [-arch <arch>]* <inputs> [-o <output>]*",
+        "llvm-readtapi [options] [-arch <arch>]* <inputs> [-o <output>]*",
         "LLVM TAPI file reader and manipulator");
     return EXIT_SUCCESS;
   }



More information about the llvm-commits mailing list