diff --git a/llvm/test/tools/llvm-ifs/help.test b/llvm/test/tools/llvm-ifs/help.test index 1cfdbd25cca4..76c15bdf7b66 100644 --- a/llvm/test/tools/llvm-ifs/help.test +++ b/llvm/test/tools/llvm-ifs/help.test @@ -1,6 +1,5 @@ # RUN: llvm-ifs --help | FileCheck %s --check-prefix HELP --implicit-check-not='{{[Oo]}}ptions:' -# HELP: USAGE -# HELP: Color Options -# HELP: Generic Options -# HELP: Ifs Options +# HELP: OVERVIEW: +# HELP: USAGE: +# HELP: OPTIONS: diff --git a/llvm/tools/llvm-ifs/CMakeLists.txt b/llvm/tools/llvm-ifs/CMakeLists.txt index 5a0cfb913838..483610dce94a 100644 --- a/llvm/tools/llvm-ifs/CMakeLists.txt +++ b/llvm/tools/llvm-ifs/CMakeLists.txt @@ -5,9 +5,17 @@ set(LLVM_LINK_COMPONENTS Support TextAPI ObjectYAML + Option ) +set(LLVM_TARGET_DEFINITIONS Opts.td) +tablegen(LLVM Opts.inc -gen-opt-parser-defs) +add_public_tablegen_target(IFSOptsTableGen) + add_llvm_tool(llvm-ifs ErrorCollector.cpp llvm-ifs.cpp + +DEPENDS + IFSOptsTableGen ) diff --git a/llvm/tools/llvm-ifs/Opts.td b/llvm/tools/llvm-ifs/Opts.td new file mode 100644 index 000000000000..7288cf0123a7 --- /dev/null +++ b/llvm/tools/llvm-ifs/Opts.td @@ -0,0 +1,37 @@ +include "llvm/Option/OptParser.td" + +class F : Flag<["-"], letter>, HelpText; +class FF : Flag<["--"], name>, HelpText; + +multiclass Eq { + def NAME #_EQ : Joined<["--"], name #"=">, HelpText; + def : Separate<["--"], name>, Alias(NAME #_EQ)>; +} + +defm arch : Eq<"arch", "Specify the architecture, e.g. x86_64">; +defm bitwidth : Eq<"bitwidth", "Specify the bit width">; +defm endianness : Eq<"endianness", "Specify the endianness">; +defm exclude : Eq<"exclude", "Remove symbols which match the pattern. Can be specified multiple times">; +def help : FF<"help", "Display this help">; +def : F<"h", "Alias for --help">, Alias; +defm hint_ifs_target : Eq<"hint-ifs-target", "When --output-format is 'IFS', this flag will hint the expected target triple for IFS output">; +defm input : Eq<"input", "input">; +defm input_format : Eq<"input-format", "Specify the input file format">; +defm output : Eq<"output", "Output file **DEPRECATED**">; +def : Separate<["-"], "o">, HelpText<"Alias for --output">, Alias; +defm output_elf : Eq<"output-elf", "Output path for ELF file">; +defm output_format : Eq<"output-format", "Specify the output file format **DEPRECATED**">; +defm output_ifs : Eq<"output-ifs", "Output path for IFS file">; +defm output_tbd : Eq<"output-tbd", "Output path for TBD file">; +defm soname : Eq<"soname", "name">; +def strip_ifs_arch : FF<"strip-ifs-arch", "Strip target architecture information away from IFS output">; +def strip_ifs_bitwidth : FF<"strip-ifs-bitwidth", "Strip target bit width information away from IFS output">; +def strip_ifs_endianness : FF<"strip-ifs-endianness", "Strip target endianness information away from IFS output">; +def strip_ifs_target : FF<"strip-ifs-target", "Strip all target information away from IFS output">; +def strip_needed : FF<"strip-needed", "Strip needed libs from output">; +def strip_size : FF<"strip-size", "Remove object size from the output">; +def strip_undefined : FF<"strip-undefined", "Strip undefined symbols from IFS output">; +defm target : Eq<"target", "Specify the target triple, e.g. x86_64-linux-gnu">; +def version : FF<"version", "Display the version">; +def : F<"V", "Alias for --version">, Alias; +def write_if_changed : FF<"write-if-changed", "Write the output file only if it is new or has changed">; diff --git a/llvm/tools/llvm-ifs/llvm-ifs.cpp b/llvm/tools/llvm-ifs/llvm-ifs.cpp index 444a6d2dd58a..b1026042e23e 100644 --- a/llvm/tools/llvm-ifs/llvm-ifs.cpp +++ b/llvm/tools/llvm-ifs/llvm-ifs.cpp @@ -15,6 +15,9 @@ #include "llvm/InterfaceStub/IFSHandler.h" #include "llvm/InterfaceStub/IFSStub.h" #include "llvm/ObjectYAML/yaml2obj.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/Option.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Errc.h" @@ -46,100 +49,68 @@ const VersionTuple IfsVersionCurrent(3, 0); enum class FileFormat { IFS, ELF, TBD }; } // end anonymous namespace -cl::OptionCategory IfsCategory("Ifs Options"); +using namespace llvm::opt; +enum ID { + OPT_INVALID = 0, // This is not an option ID. +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ + OPT_##ID, +#include "Opts.inc" +#undef OPTION +}; -// TODO: Use OptTable for option parsing in the future. -// Command line flags: -cl::list InputFilePaths(cl::Positional, cl::desc("input"), - cl::ZeroOrMore, cl::cat(IfsCategory)); -cl::opt InputFormat( - "input-format", cl::desc("Specify the input file format"), - cl::values(clEnumValN(FileFormat::IFS, "IFS", "Text based ELF stub file"), - clEnumValN(FileFormat::ELF, "ELF", "ELF object file")), - cl::cat(IfsCategory)); -cl::opt OutputFormat( - "output-format", cl::desc("Specify the output file format **DEPRECATED**"), - cl::values(clEnumValN(FileFormat::IFS, "IFS", "Text based ELF stub file"), - clEnumValN(FileFormat::ELF, "ELF", "ELF stub file"), - clEnumValN(FileFormat::TBD, "TBD", "Apple TBD text stub file")), - cl::cat(IfsCategory)); -cl::opt OptArch("arch", - cl::desc("Specify the architecture, e.g. x86_64"), - cl::cat(IfsCategory)); -cl::opt - OptBitWidth("bitwidth", cl::desc("Specify the bit width"), - cl::values(clEnumValN(IFSBitWidthType::IFS32, "32", "32 bits"), - clEnumValN(IFSBitWidthType::IFS64, "64", "64 bits")), - cl::cat(IfsCategory)); -cl::opt OptEndianness( - "endianness", cl::desc("Specify the endianness"), - cl::values(clEnumValN(IFSEndiannessType::Little, "little", "Little Endian"), - clEnumValN(IFSEndiannessType::Big, "big", "Big Endian")), - cl::cat(IfsCategory)); -cl::opt OptTargetTriple( - "target", cl::desc("Specify the target triple, e.g. x86_64-linux-gnu"), - cl::cat(IfsCategory)); -cl::opt OptTargetTripleHint( - "hint-ifs-target", - cl::desc("When --output-format is 'IFS', this flag will hint the expected " - "target triple for IFS output"), - cl::cat(IfsCategory)); -cl::opt StripIFSArch( - "strip-ifs-arch", - cl::desc("Strip target architecture information away from IFS output"), - cl::cat(IfsCategory)); -cl::opt StripIFSBitWidth( - "strip-ifs-bitwidth", - cl::desc("Strip target bit width information away from IFS output"), - cl::cat(IfsCategory)); -cl::opt StripIFSEndiannessWidth( - "strip-ifs-endianness", - cl::desc("Strip target endianness information away from IFS output"), - cl::cat(IfsCategory)); -cl::opt StripIFSTarget( - "strip-ifs-target", - cl::desc("Strip all target information away from IFS output"), - cl::cat(IfsCategory)); -cl::opt - StripUndefined("strip-undefined", - cl::desc("Strip undefined symbols from IFS output"), - cl::cat(IfsCategory)); -cl::opt StripNeededLibs("strip-needed", - cl::desc("Strip needed libs from output"), - cl::cat(IfsCategory)); -cl::opt StripSize("strip-size", - cl::desc("Remove object size from the output"), - cl::cat(IfsCategory)); +#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; +#include "Opts.inc" +#undef PREFIX -cl::list - ExcludeSyms("exclude", - cl::desc("Remove symbols which match the pattern. Can be " - "specified multiple times"), - cl::cat(IfsCategory)); +const opt::OptTable::Info InfoTable[] = { +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ + { \ + PREFIX, NAME, HELPTEXT, \ + METAVAR, OPT_##ID, opt::Option::KIND##Class, \ + PARAM, FLAGS, OPT_##GROUP, \ + OPT_##ALIAS, ALIASARGS, VALUES}, +#include "Opts.inc" +#undef OPTION +}; -cl::opt - SoName("soname", - cl::desc("Manually set the DT_SONAME entry of any emitted files"), - cl::value_desc("name"), cl::cat(IfsCategory)); -cl::opt OutputFilePath("output", - cl::desc("Output file **DEPRECATED**"), - cl::cat(IfsCategory)); -cl::alias OutputFilePathA("o", cl::desc("Alias for --output"), - cl::aliasopt(OutputFilePath), cl::cat(IfsCategory)); -cl::opt OutputELFFilePath("output-elf", - cl::desc("Output path for ELF file"), - cl::cat(IfsCategory)); -cl::opt OutputIFSFilePath("output-ifs", - cl::desc("Output path for IFS file"), - cl::cat(IfsCategory)); -cl::opt OutputTBDFilePath("output-tbd", - cl::desc("Output path for TBD file"), - cl::cat(IfsCategory)); +class IFSOptTable : public opt::OptTable { +public: + IFSOptTable() : OptTable(InfoTable) { setGroupedShortOptions(true); } +}; -cl::opt WriteIfChanged( - "write-if-changed", - cl::desc("Write the output file only if it is new or has changed."), - cl::cat(IfsCategory)); +struct DriverConfig { + std::vector InputFilePaths; + + Optional InputFormat; + Optional OutputFormat; + + Optional HintIfsTarget; + Optional OptTargetTriple; + Optional OverrideArch; + Optional OverrideBitWidth; + Optional OverrideEndianness; + + bool StripIfsArch = false; + bool StripIfsBitwidth = false; + bool StripIfsEndianness = false; + bool StripIfsTarget = false; + bool StripNeeded = false; + bool StripSize = false; + bool StripUndefined = false; + + std::vector Exclude; + + Optional SoName; + + Optional Output; + Optional OutputElf; + Optional OutputIfs; + Optional OutputTbd; + + bool WriteIfChanged = false; +}; static std::string getTypeName(IFSSymbolType Type) { switch (Type) { @@ -157,7 +128,8 @@ static std::string getTypeName(IFSSymbolType Type) { llvm_unreachable("Unexpected ifs symbol type."); } -static Expected> readInputFile(StringRef FilePath) { +static Expected> +readInputFile(Optional &InputFormat, StringRef FilePath) { // Read in file. ErrorOr> BufOrError = MemoryBuffer::getFileOrSTDIN(FilePath, /*IsText=*/true); @@ -169,10 +141,11 @@ static Expected> readInputFile(StringRef FilePath) { ErrorCollector EC(/*UseFatalErrors=*/false); // First try to read as a binary (fails fast if not binary). - if (InputFormat.getNumOccurrences() == 0 || InputFormat == FileFormat::ELF) { + if (!InputFormat || *InputFormat == FileFormat::ELF) { Expected> StubFromELF = readELFFile(FileReadBuffer->getMemBufferRef()); if (StubFromELF) { + InputFormat = FileFormat::ELF; (*StubFromELF)->IfsVersion = IfsVersionCurrent; return std::move(*StubFromELF); } @@ -180,10 +153,11 @@ static Expected> readInputFile(StringRef FilePath) { } // Fall back to reading as a ifs. - if (InputFormat.getNumOccurrences() == 0 || InputFormat == FileFormat::IFS) { + if (!InputFormat || *InputFormat == FileFormat::IFS) { Expected> StubFromIFS = readIFSFromBuffer(FileReadBuffer->getBuffer()); if (StubFromIFS) { + InputFormat = FileFormat::IFS; if ((*StubFromIFS)->IfsVersion > IfsVersionCurrent) EC.addError( createStringError(errc::not_supported, @@ -271,9 +245,14 @@ static void fatalError(Error Err) { exit(1); } +static void fatalError(Twine T) { + WithColor::error() << T.str() << '\n'; + exit(1); +} + /// writeIFS() writes a Text-Based ELF stub to a file using the latest version /// of the YAML parser. -static Error writeIFS(StringRef FilePath, IFSStub &Stub) { +static Error writeIFS(StringRef FilePath, IFSStub &Stub, bool WriteIfChanged) { // Write IFS to memory first. std::string IFSStr; raw_string_ostream OutStr(IFSStr); @@ -285,7 +264,8 @@ static Error writeIFS(StringRef FilePath, IFSStub &Stub) { if (WriteIfChanged) { if (ErrorOr> BufOrError = MemoryBuffer::getFile(FilePath)) { - // Compare IFS output with the existing IFS file. If unchanged, avoid changing the file. + // Compare IFS output with the existing IFS file. If unchanged, avoid + // changing the file. if ((*BufOrError)->getBuffer() == IFSStr) return Error::success(); } @@ -300,24 +280,119 @@ static Error writeIFS(StringRef FilePath, IFSStub &Stub) { return Error::success(); } -int main(int argc, char *argv[]) { - // Parse arguments. - cl::HideUnrelatedOptions({&IfsCategory, &getColorCategory()}); - cl::ParseCommandLineOptions(argc, argv); +static DriverConfig parseArgs(int argc, char *const *argv) { + BumpPtrAllocator A; + StringSaver Saver(A); + IFSOptTable Tbl; + StringRef ToolName = argv[0]; + llvm::opt::InputArgList Args = Tbl.parseArgs( + argc, argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) { fatalError(Msg); }); + if (Args.hasArg(OPT_help)) { + Tbl.printHelp(llvm::outs(), + (Twine(ToolName) + " [options]") + .str() + .c_str(), + "shared object stubbing tool"); + std::exit(0); + } + if (Args.hasArg(OPT_version)) { + llvm::outs() << ToolName << '\n'; + cl::PrintVersionMessage(); + std::exit(0); + } - if (InputFilePaths.empty()) - InputFilePaths.push_back("-"); + DriverConfig Config; + for (const opt::Arg *A : Args.filtered(OPT_INPUT)) + Config.InputFilePaths.push_back(A->getValue()); + if (const opt::Arg *A = Args.getLastArg(OPT_input_format_EQ)) { + Config.InputFormat = StringSwitch>(A->getValue()) + .Case("IFS", FileFormat::IFS) + .Case("ELF", FileFormat::ELF) + .Default(None); + if (!Config.InputFormat) + fatalError(Twine("invalid argument '") + A->getValue()); + } + + auto OptionNotFound = [ToolName](StringRef FlagName, StringRef OptionName) { + fatalError(Twine(ToolName) + ": for the " + FlagName + + " option: Cannot find option named '" + OptionName + "'!"); + }; + if (const opt::Arg *A = Args.getLastArg(OPT_output_format_EQ)) { + Config.OutputFormat = StringSwitch>(A->getValue()) + .Case("IFS", FileFormat::IFS) + .Case("ELF", FileFormat::ELF) + .Case("TBD", FileFormat::TBD) + .Default(None); + if (!Config.OutputFormat) + OptionNotFound("--output-format", A->getValue()); + } + if (const opt::Arg *A = Args.getLastArg(OPT_arch_EQ)) + Config.OverrideArch = ELF::convertArchNameToEMachine(A->getValue()); + + if (const opt::Arg *A = Args.getLastArg(OPT_bitwidth_EQ)) { + size_t Width; + llvm::StringRef S(A->getValue()); + if (!S.getAsInteger(10, Width) || Width == 64 || Width == 32) + Config.OverrideBitWidth = + Width == 64 ? IFSBitWidthType::IFS64 : IFSBitWidthType::IFS32; + else + OptionNotFound("--bitwidth", A->getValue()); + } + if (const opt::Arg *A = Args.getLastArg(OPT_endianness_EQ)) { + Config.OverrideEndianness = + StringSwitch>(A->getValue()) + .Case("little", IFSEndiannessType::Little) + .Case("big", IFSEndiannessType::Big) + .Default(None); + if (!Config.OverrideEndianness) + OptionNotFound("--endianness", A->getValue()); + } + if (const opt::Arg *A = Args.getLastArg(OPT_target_EQ)) + Config.OptTargetTriple = A->getValue(); + if (const opt::Arg *A = Args.getLastArg(OPT_hint_ifs_target_EQ)) + Config.HintIfsTarget = A->getValue(); + + Config.StripIfsArch = Args.hasArg(OPT_strip_ifs_arch); + Config.StripIfsBitwidth = Args.hasArg(OPT_strip_ifs_bitwidth); + Config.StripIfsEndianness = Args.hasArg(OPT_strip_ifs_endianness); + Config.StripIfsTarget = Args.hasArg(OPT_strip_ifs_target); + Config.StripUndefined = Args.hasArg(OPT_strip_undefined); + Config.StripNeeded = Args.hasArg(OPT_strip_needed); + Config.StripSize = Args.hasArg(OPT_strip_size); + + for (const opt::Arg *A : Args.filtered(OPT_exclude_EQ)) + Config.Exclude.push_back(A->getValue()); + if (const opt::Arg *A = Args.getLastArg(OPT_soname_EQ)) + Config.SoName = A->getValue(); + if (const opt::Arg *A = Args.getLastArg(OPT_output_EQ)) + Config.Output = A->getValue(); + if (const opt::Arg *A = Args.getLastArg(OPT_output_elf_EQ)) + Config.OutputElf = A->getValue(); + if (const opt::Arg *A = Args.getLastArg(OPT_output_ifs_EQ)) + Config.OutputIfs = A->getValue(); + if (const opt::Arg *A = Args.getLastArg(OPT_output_tbd_EQ)) + Config.OutputTbd = A->getValue(); + Config.WriteIfChanged = Args.hasArg(OPT_write_if_changed); + return Config; +} + +int main(int argc, char *argv[]) { + DriverConfig Config = parseArgs(argc, argv); + + if (Config.InputFilePaths.empty()) + Config.InputFilePaths.push_back("-"); // If input files are more than one, they can only be IFS files. - if (InputFilePaths.size() > 1) - InputFormat.setValue(FileFormat::IFS); + if (Config.InputFilePaths.size() > 1) + Config.InputFormat = FileFormat::IFS; // Attempt to merge input. IFSStub Stub; std::map SymbolMap; std::string PreviousInputFilePath; - for (const std::string &InputFilePath : InputFilePaths) { - Expected> StubOrErr = readInputFile(InputFilePath); + for (const std::string &InputFilePath : Config.InputFilePaths) { + Expected> StubOrErr = + readInputFile(Config.InputFormat, InputFilePath); if (!StubOrErr) fatalError(StubOrErr.takeError()); @@ -411,57 +486,45 @@ int main(int argc, char *argv[]) { Stub.Symbols.push_back(Entry.second); // Change SoName before emitting stubs. - if (SoName.getNumOccurrences() == 1) - Stub.SoName = SoName; - Optional OverrideArch; - Optional OverrideEndianness; - Optional OverrideBitWidth; - Optional OverrideTriple; - if (OptArch.getNumOccurrences() == 1) - OverrideArch = ELF::convertArchNameToEMachine(OptArch.getValue()); - if (OptEndianness.getNumOccurrences() == 1) - OverrideEndianness = OptEndianness.getValue(); - if (OptBitWidth.getNumOccurrences() == 1) - OverrideBitWidth = OptBitWidth.getValue(); - if (OptTargetTriple.getNumOccurrences() == 1) - OverrideTriple = OptTargetTriple.getValue(); - Error OverrideError = overrideIFSTarget( - Stub, OverrideArch, OverrideEndianness, OverrideBitWidth, OverrideTriple); + if (Config.SoName) + Stub.SoName = *Config.SoName; + + Error OverrideError = + overrideIFSTarget(Stub, Config.OverrideArch, Config.OverrideEndianness, + Config.OverrideBitWidth, Config.OptTargetTriple); if (OverrideError) fatalError(std::move(OverrideError)); - if (StripNeededLibs) + if (Config.StripNeeded) Stub.NeededLibs.clear(); - if (Error E = filterIFSSyms(Stub, StripUndefined, ExcludeSyms)) + if (Error E = filterIFSSyms(Stub, Config.StripUndefined, Config.Exclude)) fatalError(std::move(E)); - if (StripSize) + if (Config.StripSize) for (IFSSymbol &Sym : Stub.Symbols) Sym.Size.reset(); - if (OutputELFFilePath.getNumOccurrences() == 0 && - OutputIFSFilePath.getNumOccurrences() == 0 && - OutputTBDFilePath.getNumOccurrences() == 0) { - if (OutputFormat.getNumOccurrences() == 0) { + if (!Config.OutputElf && !Config.OutputIfs && !Config.OutputTbd) { + if (!Config.OutputFormat) { WithColor::error() << "at least one output should be specified."; return -1; } - } else if (OutputFormat.getNumOccurrences() == 1) { + } else if (Config.OutputFormat) { WithColor::error() << "'--output-format' cannot be used with " "'--output-{FILE_FORMAT}' options at the same time"; return -1; } - if (OutputFormat.getNumOccurrences() == 1) { + if (Config.OutputFormat) { // TODO: Remove OutputFormat flag in the next revision. WithColor::warning() << "--output-format option is deprecated, please use " "--output-{FILE_FORMAT} options instead\n"; - switch (OutputFormat.getValue()) { + switch (Config.OutputFormat.getValue()) { case FileFormat::TBD: { std::error_code SysErr; - raw_fd_ostream Out(OutputFilePath, SysErr); + raw_fd_ostream Out(*Config.Output, SysErr); if (SysErr) { - WithColor::error() << "Couldn't open " << OutputFilePath + WithColor::error() << "Couldn't open " << *Config.Output << " for writing.\n"; return -1; } @@ -475,10 +538,10 @@ int main(int argc, char *argv[]) { } case FileFormat::IFS: { Stub.IfsVersion = IfsVersionCurrent; - if (InputFormat.getValue() == FileFormat::ELF && - OptTargetTripleHint.getNumOccurrences() == 1) { + if (Config.InputFormat.getValue() == FileFormat::ELF && + Config.HintIfsTarget) { std::error_code HintEC(1, std::generic_category()); - IFSTarget HintTarget = parseTriple(OptTargetTripleHint); + IFSTarget HintTarget = parseTriple(*Config.HintIfsTarget); if (Stub.Target.Arch.getValue() != HintTarget.Arch.getValue()) fatalError(make_error( "Triple hint does not match the actual architecture", HintEC)); @@ -491,12 +554,13 @@ int main(int argc, char *argv[]) { "Triple hint does not match the actual bit width", HintEC)); stripIFSTarget(Stub, true, false, false, false); - Stub.Target.Triple = OptTargetTripleHint.getValue(); + Stub.Target.Triple = Config.HintIfsTarget.getValue(); } else { - stripIFSTarget(Stub, StripIFSTarget, StripIFSArch, - StripIFSEndiannessWidth, StripIFSBitWidth); + stripIFSTarget(Stub, Config.StripIfsTarget, Config.StripIfsArch, + Config.StripIfsEndianness, Config.StripIfsBitwidth); } - Error IFSWriteError = writeIFS(OutputFilePath.getValue(), Stub); + Error IFSWriteError = + writeIFS(Config.Output.getValue(), Stub, Config.WriteIfChanged); if (IFSWriteError) fatalError(std::move(IFSWriteError)); break; @@ -506,7 +570,7 @@ int main(int argc, char *argv[]) { if (TargetError) fatalError(std::move(TargetError)); Error BinaryWriteError = - writeBinaryStub(OutputFilePath, Stub, WriteIfChanged); + writeBinaryStub(*Config.Output, Stub, Config.WriteIfChanged); if (BinaryWriteError) fatalError(std::move(BinaryWriteError)); break; @@ -514,21 +578,21 @@ int main(int argc, char *argv[]) { } } else { // Check if output path for individual format. - if (OutputELFFilePath.getNumOccurrences() == 1) { + if (Config.OutputElf) { Error TargetError = validateIFSTarget(Stub, true); if (TargetError) fatalError(std::move(TargetError)); Error BinaryWriteError = - writeBinaryStub(OutputELFFilePath, Stub, WriteIfChanged); + writeBinaryStub(*Config.OutputElf, Stub, Config.WriteIfChanged); if (BinaryWriteError) fatalError(std::move(BinaryWriteError)); } - if (OutputIFSFilePath.getNumOccurrences() == 1) { + if (Config.OutputIfs) { Stub.IfsVersion = IfsVersionCurrent; - if (InputFormat.getValue() == FileFormat::ELF && - OptTargetTripleHint.getNumOccurrences() == 1) { + if (Config.InputFormat.getValue() == FileFormat::ELF && + Config.HintIfsTarget) { std::error_code HintEC(1, std::generic_category()); - IFSTarget HintTarget = parseTriple(OptTargetTripleHint); + IFSTarget HintTarget = parseTriple(*Config.HintIfsTarget); if (Stub.Target.Arch.getValue() != HintTarget.Arch.getValue()) fatalError(make_error( "Triple hint does not match the actual architecture", HintEC)); @@ -541,20 +605,21 @@ int main(int argc, char *argv[]) { "Triple hint does not match the actual bit width", HintEC)); stripIFSTarget(Stub, true, false, false, false); - Stub.Target.Triple = OptTargetTripleHint.getValue(); + Stub.Target.Triple = Config.HintIfsTarget.getValue(); } else { - stripIFSTarget(Stub, StripIFSTarget, StripIFSArch, - StripIFSEndiannessWidth, StripIFSBitWidth); + stripIFSTarget(Stub, Config.StripIfsTarget, Config.StripIfsArch, + Config.StripIfsEndianness, Config.StripIfsBitwidth); } - Error IFSWriteError = writeIFS(OutputIFSFilePath.getValue(), Stub); + Error IFSWriteError = + writeIFS(Config.OutputIfs.getValue(), Stub, Config.WriteIfChanged); if (IFSWriteError) fatalError(std::move(IFSWriteError)); } - if (OutputTBDFilePath.getNumOccurrences() == 1) { + if (Config.OutputTbd) { std::error_code SysErr; - raw_fd_ostream Out(OutputTBDFilePath, SysErr); + raw_fd_ostream Out(*Config.OutputTbd, SysErr); if (SysErr) { - WithColor::error() << "Couldn't open " << OutputTBDFilePath + WithColor::error() << "Couldn't open " << *Config.OutputTbd << " for writing.\n"; return -1; }