[clang] [llvm] [yaml2obj] Migrate to OptTable (PR #224964)
Fangrui Song via cfe-commits
cfe-commits at lists.llvm.org
Sun Sep 20 13:58:51 PDT 2026
https://github.com/MaskRay created https://github.com/llvm/llvm-project/pull/224964
yaml2obj is one of three tools that parse with
cl::ParseCommandLineOptions(LongOptionsUseDoubleDash=true). Parse its
options with an OptTable instead, so that the mode can be removed from
cl::. Spellings follow the other migrated tools: -D<macro>=<v> and
-D <macro>=<v>, -o<file> and -o <file>, --docnum=<n> and --docnum <n>,
--max-size likewise, -E, -h/--help and --version. `-o=<file>` is no
longer accepted; the tests that used it are updated. `--help` lists
only yaml2obj's options.
LLM-aided
>From d8b08e10da9d3fd934cf5934901aa937b4b67537 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Sun, 20 Sep 2026 12:28:10 -0700
Subject: [PATCH] [yaml2obj] Migrate to OptTable
yaml2obj is one of three tools that parse with
cl::ParseCommandLineOptions(LongOptionsUseDoubleDash=true). Parse its
options with an OptTable instead, so that the mode can be removed from
cl::. Spellings follow the other migrated tools: -D<macro>=<v> and
-D <macro>=<v>, -o<file> and -o <file>, --docnum=<n> and --docnum <n>,
--max-size likewise, -E, -h/--help and --version. `-o=<file>` is no
longer accepted; the tests that used it are updated. `--help` lists
only yaml2obj's options.
LLM-aided
---
.../InstallAPI/exclusive-passes-platform.test | 2 +-
.../export_trie_lc_dyld_exports_trie.yaml | 2 +-
.../MachO/export_trie_lc_dyld_info_only.yaml | 2 +-
.../ObjectYAML/MachO/function_starts.yaml | 2 +-
.../COFF/codeview-merging-ghash.test | 2 +-
llvm/test/tools/llvm-tli-checker/ifuncs.yaml | 2 +-
.../tools/llvm-tli-checker/ps4-tli-check.yaml | 4 +-
llvm/test/tools/yaml2obj/help.test | 9 +-
llvm/tools/yaml2obj/CMakeLists.txt | 7 ++
llvm/tools/yaml2obj/Opts.td | 18 ++++
llvm/tools/yaml2obj/yaml2obj.cpp | 101 +++++++++++-------
.../gn/secondary/llvm/tools/yaml2obj/BUILD.gn | 9 ++
.../llvm-project-overlay/llvm/BUILD.bazel | 11 ++
13 files changed, 121 insertions(+), 50 deletions(-)
create mode 100644 llvm/tools/yaml2obj/Opts.td
diff --git a/clang/test/InstallAPI/exclusive-passes-platform.test b/clang/test/InstallAPI/exclusive-passes-platform.test
index c5a79cf9a30d16..2428b5d54679c6 100644
--- a/clang/test/InstallAPI/exclusive-passes-platform.test
+++ b/clang/test/InstallAPI/exclusive-passes-platform.test
@@ -1,7 +1,7 @@
; RUN: rm -rf %t
; RUN: split-file %s %t
; RUN: sed -e "s|DSTROOT|%/t|g" %t/inputs.json.in > %t/inputs.json
-; RUN: yaml2obj %t/Xplatform.yaml -o=%t/Xplatform
+; RUN: yaml2obj %t/Xplatform.yaml -o %t/Xplatform
// Check that in zippered mode, a successful pass runs in both macos & maccatalyst.
; RUN: clang-installapi %t/inputs.json \
diff --git a/llvm/test/ObjectYAML/MachO/export_trie_lc_dyld_exports_trie.yaml b/llvm/test/ObjectYAML/MachO/export_trie_lc_dyld_exports_trie.yaml
index 4710bca2996514..d5857c8acbfed0 100644
--- a/llvm/test/ObjectYAML/MachO/export_trie_lc_dyld_exports_trie.yaml
+++ b/llvm/test/ObjectYAML/MachO/export_trie_lc_dyld_exports_trie.yaml
@@ -1,4 +1,4 @@
-# RUN: yaml2obj %s -o=%t
+# RUN: yaml2obj %s -o %t
# RUN: obj2yaml %t | FileCheck %s
# RUN: llvm-objdump --macho --exports-trie %t | FileCheck %s --check-prefix=OBJDUMP-VERIFY
diff --git a/llvm/test/ObjectYAML/MachO/export_trie_lc_dyld_info_only.yaml b/llvm/test/ObjectYAML/MachO/export_trie_lc_dyld_info_only.yaml
index 9c359db6b90d6a..1612295be1ce1c 100644
--- a/llvm/test/ObjectYAML/MachO/export_trie_lc_dyld_info_only.yaml
+++ b/llvm/test/ObjectYAML/MachO/export_trie_lc_dyld_info_only.yaml
@@ -1,4 +1,4 @@
-# RUN: yaml2obj %s -o=%t
+# RUN: yaml2obj %s -o %t
# RUN: obj2yaml %t | FileCheck %s
# RUN: llvm-objdump --macho --exports-trie %t | FileCheck %s --check-prefix=OBJDUMP-VERIFY
diff --git a/llvm/test/ObjectYAML/MachO/function_starts.yaml b/llvm/test/ObjectYAML/MachO/function_starts.yaml
index 0cdd6665dcfb9c..2331049ccee423 100644
--- a/llvm/test/ObjectYAML/MachO/function_starts.yaml
+++ b/llvm/test/ObjectYAML/MachO/function_starts.yaml
@@ -176,7 +176,7 @@ LinkEditData:
FunctionStarts: [ 0x3F80, 0x3F84 ]
...
-# RUN: yaml2obj %s -o=%t
+# RUN: yaml2obj %s -o %t
# RUN: obj2yaml %t | FileCheck %s
# CHECK: FunctionStarts: [ 0x3F80, 0x3F84 ]
diff --git a/llvm/test/tools/llvm-readobj/COFF/codeview-merging-ghash.test b/llvm/test/tools/llvm-readobj/COFF/codeview-merging-ghash.test
index 7c57cf0b5dc81f..31139c4cb3aad0 100644
--- a/llvm/test/tools/llvm-readobj/COFF/codeview-merging-ghash.test
+++ b/llvm/test/tools/llvm-readobj/COFF/codeview-merging-ghash.test
@@ -1,4 +1,4 @@
-# RUN: yaml2obj %s -o=%t.obj
+# RUN: yaml2obj %s -o %t.obj
# RUN: llvm-readobj --codeview-merged-types %t.obj | FileCheck %s --check-prefix=MERGED
# RUN: llvm-readobj --codeview-merged-types --codeview-ghash %t.obj | FileCheck %s --check-prefix=MERGED
diff --git a/llvm/test/tools/llvm-tli-checker/ifuncs.yaml b/llvm/test/tools/llvm-tli-checker/ifuncs.yaml
index 4eae66c3051a7f..dd76269dbe14df 100644
--- a/llvm/test/tools/llvm-tli-checker/ifuncs.yaml
+++ b/llvm/test/tools/llvm-tli-checker/ifuncs.yaml
@@ -4,7 +4,7 @@
# llvm-tli-checker won't be able to find it unless it knows how to check ifuncs.
# This test makes sure that llvm-tli-checker supports processing ifuncs.
#
-# RUN: yaml2obj %s -o=%t1
+# RUN: yaml2obj %s -o %t1
# RUN: llvm-tli-checker --triple=x86_64-unknown-freebsd %t1 | FileCheck %s
#
# CHECK: == Total TLI yes SDK yes: 1
diff --git a/llvm/test/tools/llvm-tli-checker/ps4-tli-check.yaml b/llvm/test/tools/llvm-tli-checker/ps4-tli-check.yaml
index 63520a0b98089e..70a44a3aab775a 100644
--- a/llvm/test/tools/llvm-tli-checker/ps4-tli-check.yaml
+++ b/llvm/test/tools/llvm-tli-checker/ps4-tli-check.yaml
@@ -1,12 +1,12 @@
# REQUIRES: x86-registered-target
#
## This produces a static object that matches expectations for PS4/PS5.
-# RUN: yaml2obj %s -DTYPE=ET_REL -DLABEL=Symbols -DZDAPV=_ZdaPv -o=%t1
+# RUN: yaml2obj %s -DTYPE=ET_REL -DLABEL=Symbols -DZDAPV=_ZdaPv -o %t1
# RUN: llvm-tli-checker --triple=x86_64-scei-ps4 %t1 | FileCheck %s
# RUN: llvm-tli-checker --triple=x86_64-sie-ps5 %t1 | FileCheck %s
#
## This produces a dynamic object that has _ZdaPvj instead of _ZdaPv.
-# RUN: yaml2obj %s -DTYPE=ET_DYN -DLABEL=DynamicSymbols -DZDAPV=_ZdaPvj -o=%t2
+# RUN: yaml2obj %s -DTYPE=ET_DYN -DLABEL=DynamicSymbols -DZDAPV=_ZdaPvj -o %t2
# RUN: llvm-tli-checker --triple x86_64-scei-ps4 %t2 | \
# RUN: FileCheck %s --check-prefixes=WRONG_SUMMARY,WRONG_DETAIL \
# RUN: --implicit-check-not="==" --implicit-check-not="<<" --implicit-check-not=">>"
diff --git a/llvm/test/tools/yaml2obj/help.test b/llvm/test/tools/yaml2obj/help.test
index 2e82c1278c4340..95564c47bc97ec 100644
--- a/llvm/test/tools/yaml2obj/help.test
+++ b/llvm/test/tools/yaml2obj/help.test
@@ -1,11 +1,8 @@
## Show that help text is printed correctly when requested.
-# RUN: yaml2obj -h | FileCheck %s --check-prefixes=CHECK,CATEG --implicit-check-not=Options:
-# RUN: yaml2obj --help | FileCheck %s --check-prefixes=CHECK,CATEG --implicit-check-not=Options:
-# RUN: yaml2obj --help-list | FileCheck %s --implicit-check-not=Options:
+# RUN: yaml2obj -h | FileCheck %s
+# RUN: yaml2obj --help | FileCheck %s
# CHECK: OVERVIEW: Create an object file from a YAML description
-# CHECK: USAGE: yaml2obj{{(.exe)?}} [options] <input file>{{$}}
+# CHECK: USAGE: yaml2obj [options] <input file>{{$}}
# CHECK: OPTIONS:
-# CATEG: Generic Options:
-# CATEG: yaml2obj Options:
diff --git a/llvm/tools/yaml2obj/CMakeLists.txt b/llvm/tools/yaml2obj/CMakeLists.txt
index ad413405255c66..d9d1796c555c65 100644
--- a/llvm/tools/yaml2obj/CMakeLists.txt
+++ b/llvm/tools/yaml2obj/CMakeLists.txt
@@ -1,10 +1,17 @@
set(LLVM_LINK_COMPONENTS
Object
ObjectYAML
+ Option
ProfileData
Support
)
+set(LLVM_TARGET_DEFINITIONS Opts.td)
+tablegen(LLVM Opts.inc -gen-opt-parser-defs)
+add_public_tablegen_target(Yaml2ObjOptsTableGen)
+
add_llvm_utility(yaml2obj
yaml2obj.cpp
+ DEPENDS
+ Yaml2ObjOptsTableGen
)
diff --git a/llvm/tools/yaml2obj/Opts.td b/llvm/tools/yaml2obj/Opts.td
new file mode 100644
index 00000000000000..02a7934c38b2fc
--- /dev/null
+++ b/llvm/tools/yaml2obj/Opts.td
@@ -0,0 +1,18 @@
+include "llvm/Option/OptParser.td"
+
+class F<string letter, string help> : Flag<["-"], letter>, HelpText<help>;
+class FF<string name, string help> : Flag<["--"], name>, HelpText<help>;
+
+multiclass Eq<string name, string help> {
+ def NAME #_EQ : Joined<["--"], name #"=">, HelpText<help>;
+ def : Separate<["--"], name>, Alias<!cast<Joined>(NAME #_EQ)>;
+}
+
+def D : JoinedOrSeparate<["-"], "D">, HelpText<"Define the specified macro to the specified definition">, MetaVarName<"<macro>=<definition>">;
+defm docnum : Eq<"docnum", "Read the specified document from the input (default = 1)">, MetaVarName<"<n>">;
+def E : F<"E", "Just print the preprocessed file">;
+def help : FF<"help", "Display this help">;
+def : F<"h", "Alias for --help">, Alias<help>;
+defm max_size : Eq<"max-size", "Set the maximum allowed output size (0 means no limit) [ELF and COFF only]">, MetaVarName<"<bytes>">;
+def o : JoinedOrSeparate<["-"], "o">, HelpText<"Output filename">, MetaVarName<"<filename>">;
+def version : FF<"version", "Display the version">;
diff --git a/llvm/tools/yaml2obj/yaml2obj.cpp b/llvm/tools/yaml2obj/yaml2obj.cpp
index 0cb3d5d61b126d..8fb5b0af0d3ab4 100644
--- a/llvm/tools/yaml2obj/yaml2obj.cpp
+++ b/llvm/tools/yaml2obj/yaml2obj.cpp
@@ -16,10 +16,14 @@
#include "llvm/ObjectYAML/yaml2obj.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ObjectYAML/ObjectYAML.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/OptTable.h"
+#include "llvm/Option/Option.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/StringSaver.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Support/WithColor.h"
#include "llvm/Support/YAMLTraits.h"
@@ -30,37 +34,25 @@
using namespace llvm;
namespace {
-cl::OptionCategory Cat("yaml2obj Options");
-
-cl::opt<std::string> Input(cl::Positional, cl::desc("<input file>"),
- cl::init("-"), cl::cat(Cat));
-
-static cl::list<std::string>
- D("D", cl::Prefix,
- cl::desc("Defined the specified macros to their specified "
- "definition. The syntax is <macro>=<definition>"),
- cl::cat(Cat));
-
-cl::opt<bool> PreprocessOnly("E", cl::desc("Just print the preprocessed file"),
- cl::cat(Cat));
-
-cl::opt<unsigned>
- DocNum("docnum", cl::init(1),
- cl::desc("Read specified document from input (default = 1)"),
- cl::cat(Cat));
-
-static cl::opt<uint64_t>
- MaxSize("max-size", cl::init(10 * 1024 * 1024),
- cl::desc("Sets the maximum allowed output size (0 means no limit) "
- "[ELF and COFF only]"),
- cl::cat(Cat));
-
-cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"),
- cl::value_desc("filename"), cl::init("-"),
- cl::Prefix, cl::cat(Cat));
+enum ID {
+ OPT_INVALID = 0, // This is not an option ID.
+#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
+#include "Opts.inc"
+#undef OPTION
+};
+
+using namespace llvm::opt;
+#define OPTTABLE_CODE
+#include "Opts.inc"
+
+class Yaml2ObjOptTable : public opt::OptTable {
+public:
+ Yaml2ObjOptTable() : OptTable(optionTables()) { setDashDashParsing(true); }
+};
} // namespace
static std::optional<std::string> preprocess(StringRef Buf,
+ ArrayRef<std::string> D,
yaml::ErrorHandler ErrHandler) {
DenseMap<StringRef, StringRef> Defines;
for (StringRef Define : D) {
@@ -110,18 +102,55 @@ static std::optional<std::string> preprocess(StringRef Buf,
return Preprocessed;
}
+template <class T>
+static void parseIntArg(const opt::InputArgList &Args, int ID, T &Value,
+ yaml::ErrorHandler ErrHandler) {
+ if (const opt::Arg *A = Args.getLastArg(ID)) {
+ StringRef V(A->getValue());
+ if (!to_integer(V, Value, 0)) {
+ ErrHandler("expected an integer, but got '" + V + "'");
+ exit(1);
+ }
+ }
+}
+
int main(int argc, char **argv) {
InitLLVM X(argc, argv);
- cl::HideUnrelatedOptions(Cat);
- cl::ParseCommandLineOptions(
- argc, argv, "Create an object file from a YAML description", nullptr,
- nullptr, nullptr, /*LongOptionsUseDoubleDash=*/true);
-
constexpr StringRef ProgName = "yaml2obj";
auto ErrHandler = [&](const Twine &Msg) {
WithColor::error(errs(), ProgName) << Msg << "\n";
};
+ BumpPtrAllocator A;
+ StringSaver Saver(A);
+ Yaml2ObjOptTable Tbl;
+ opt::InputArgList Args =
+ Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) {
+ ErrHandler(Msg);
+ exit(1);
+ });
+ if (Args.hasArg(OPT_help)) {
+ Tbl.printHelp(outs(), "yaml2obj [options] <input file>",
+ "Create an object file from a YAML description");
+ return 0;
+ }
+ if (Args.hasArg(OPT_version)) {
+ cl::PrintVersionMessage();
+ return 0;
+ }
+
+ std::vector<std::string> Inputs = Args.getAllArgValues(OPT_INPUT);
+ if (Inputs.size() > 1) {
+ ErrHandler("too many input files");
+ return 1;
+ }
+ StringRef Input = Inputs.empty() ? StringRef("-") : StringRef(Inputs[0]);
+ StringRef OutputFilename = Args.getLastArgValue(OPT_o, "-");
+ unsigned DocNum = 1;
+ parseIntArg(Args, OPT_docnum_EQ, DocNum, ErrHandler);
+ uint64_t MaxSize = 10 * 1024 * 1024;
+ parseIntArg(Args, OPT_max_size_EQ, MaxSize, ErrHandler);
+
std::error_code EC;
std::unique_ptr<ToolOutputFile> Out(
new ToolOutputFile(OutputFilename, EC, sys::fs::OF_None));
@@ -137,12 +166,12 @@ int main(int argc, char **argv) {
return 1;
}
- std::optional<std::string> Buffer =
- preprocess(Buf.get()->getBuffer(), ErrHandler);
+ std::optional<std::string> Buffer = preprocess(
+ Buf.get()->getBuffer(), Args.getAllArgValues(OPT_D), ErrHandler);
if (!Buffer)
return 1;
- if (PreprocessOnly) {
+ if (Args.hasArg(OPT_E)) {
Out->os() << Buffer;
} else {
yaml::Input YIn(*Buffer);
diff --git a/llvm/utils/gn/secondary/llvm/tools/yaml2obj/BUILD.gn b/llvm/utils/gn/secondary/llvm/tools/yaml2obj/BUILD.gn
index 7e4ba3be0d4799..47e45c9cca3dc4 100644
--- a/llvm/utils/gn/secondary/llvm/tools/yaml2obj/BUILD.gn
+++ b/llvm/utils/gn/secondary/llvm/tools/yaml2obj/BUILD.gn
@@ -1,6 +1,15 @@
+import("//llvm/utils/TableGen/tablegen.gni")
+
+tablegen("Opts") {
+ visibility = [ ":yaml2obj" ]
+ args = [ "-gen-opt-parser-defs" ]
+}
+
executable("yaml2obj") {
deps = [
+ ":Opts",
"//llvm/lib/ObjectYAML",
+ "//llvm/lib/Option",
"//llvm/lib/Support",
]
sources = [ "yaml2obj.cpp" ]
diff --git a/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel b/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel
index b7765075c72fb0..279d2d2cb37ce3 100644
--- a/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel
@@ -7183,6 +7183,15 @@ cc_binary(
],
)
+gentbl_cc_library(
+ name = "Yaml2ObjOptsTableGen",
+ strip_include_prefix = "tools/yaml2obj",
+ tbl_outs = {"tools/yaml2obj/Opts.inc": ["-gen-opt-parser-defs"]},
+ tblgen = ":llvm-tblgen",
+ td_file = "tools/yaml2obj/Opts.td",
+ deps = [":OptParserTdFiles"],
+)
+
cc_binary(
name = "yaml2obj",
testonly = True,
@@ -7197,7 +7206,9 @@ cc_binary(
":MC",
":Object",
":ObjectYAML",
+ ":Option",
":Support",
+ ":Yaml2ObjOptsTableGen",
],
)
More information about the cfe-commits
mailing list