1 //===-- llvm-lipo.cpp - a tool for manipulating universal binaries --------===//
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
7 //===----------------------------------------------------------------------===//
9 // A utility for creating / splitting / inspecting universal binaries.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/ADT/Triple.h"
14 #include "llvm/Object/Binary.h"
15 #include "llvm/Object/MachO.h"
16 #include "llvm/Object/MachOUniversal.h"
17 #include "llvm/Object/ObjectFile.h"
18 #include "llvm/Option/Arg.h"
19 #include "llvm/Option/ArgList.h"
20 #include "llvm/Support/CommandLine.h"
21 #include "llvm/Support/Error.h"
22 #include "llvm/Support/InitLLVM.h"
23 #include "llvm/Support/WithColor.h"
26 using namespace llvm::object;
28 static const StringRef ToolName = "llvm-lipo";
30 LLVM_ATTRIBUTE_NORETURN static void reportError(Twine Message) {
31 WithColor::error(errs(), ToolName) << Message << "\n";
36 LLVM_ATTRIBUTE_NORETURN static void reportError(StringRef File, Error E) {
39 raw_string_ostream OS(Buf);
40 logAllUnhandledErrors(std::move(E), OS);
42 WithColor::error(errs(), ToolName) << "'" << File << "': " << Buf;
48 LIPO_INVALID = 0, // This is not an option ID.
49 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
50 HELPTEXT, METAVAR, VALUES) \
52 #include "LipoOpts.inc"
56 // LipoInfoTable below references LIPO_##PREFIX. OptionGroup has prefix nullptr.
57 const char *const *LIPO_nullptr = nullptr;
58 #define PREFIX(NAME, VALUE) const char *const LIPO_##NAME[] = VALUE;
59 #include "LipoOpts.inc"
62 static const opt::OptTable::Info LipoInfoTable[] = {
63 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
64 HELPTEXT, METAVAR, VALUES) \
65 {LIPO_##PREFIX, NAME, HELPTEXT, \
66 METAVAR, LIPO_##ID, opt::Option::KIND##Class, \
67 PARAM, FLAGS, LIPO_##GROUP, \
68 LIPO_##ALIAS, ALIASARGS, VALUES},
69 #include "LipoOpts.inc"
73 class LipoOptTable : public opt::OptTable {
75 LipoOptTable() : OptTable(LipoInfoTable) {}
78 enum class LipoAction {
84 SmallVector<std::string, 1> InputFiles;
85 SmallVector<std::string, 1> VerifyArchList;
86 LipoAction ActionToPerform;
91 static Config parseLipoOptions(ArrayRef<const char *> ArgsArr) {
94 unsigned MissingArgumentIndex, MissingArgumentCount;
95 llvm::opt::InputArgList InputArgs =
96 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
98 if (InputArgs.size() == 0) {
99 // PrintHelp does not accept Twine.
100 T.PrintHelp(errs(), "llvm-lipo input[s] option[s]", "llvm-lipo");
104 if (InputArgs.hasArg(LIPO_help)) {
105 // PrintHelp does not accept Twine.
106 T.PrintHelp(outs(), "llvm-lipo input[s] option[s]", "llvm-lipo");
110 if (InputArgs.hasArg(LIPO_version)) {
111 outs() << ToolName + "\n";
112 cl::PrintVersionMessage();
116 for (auto Arg : InputArgs.filtered(LIPO_UNKNOWN))
117 reportError("unknown argument '" + Arg->getAsString(InputArgs) + "'");
119 for (auto Arg : InputArgs.filtered(LIPO_INPUT))
120 C.InputFiles.push_back(Arg->getValue());
121 if (C.InputFiles.empty())
122 reportError("at least one input file should be specified");
124 SmallVector<opt::Arg *, 1> ActionArgs(InputArgs.filtered(LIPO_action_group));
125 if (ActionArgs.empty())
126 reportError("at least one action should be specified");
127 if (ActionArgs.size() > 1) {
129 raw_string_ostream OS(Buf);
130 OS << "only one of the following actions can be specified:";
131 for (auto Arg : ActionArgs)
132 OS << " " << Arg->getSpelling();
133 reportError(OS.str());
136 switch (ActionArgs[0]->getOption().getID()) {
137 case LIPO_verify_arch:
138 for (auto A : InputArgs.getAllArgValues(LIPO_verify_arch))
139 C.VerifyArchList.push_back(A);
140 if (C.VerifyArchList.empty())
142 "verify_arch requires at least one architecture to be specified");
143 if (C.InputFiles.size() > 1)
144 reportError("verify_arch expects a single input file");
145 C.ActionToPerform = LipoAction::VerifyArch;
149 if (C.InputFiles.size() > 1)
150 reportError("archs expects a single input file");
151 C.ActionToPerform = LipoAction::PrintArchs;
155 reportError("llvm-lipo action unspecified");
159 static SmallVector<OwningBinary<Binary>, 1>
160 readInputBinaries(ArrayRef<std::string> InputFiles) {
161 SmallVector<OwningBinary<Binary>, 1> InputBinaries;
162 for (StringRef InputFile : InputFiles) {
163 Expected<OwningBinary<llvm::object::Binary>> BinaryOrErr =
164 createBinary(InputFile);
166 reportError(InputFile, BinaryOrErr.takeError());
167 if (!isa<MachOObjectFile>(BinaryOrErr->getBinary()) &&
168 !isa<MachOUniversalBinary>(BinaryOrErr->getBinary()))
169 reportError("File " + InputFile + " has unsupported binary format");
170 InputBinaries.push_back(std::move(*BinaryOrErr));
172 return InputBinaries;
175 LLVM_ATTRIBUTE_NORETURN
176 static void verifyArch(ArrayRef<OwningBinary<Binary>> InputBinaries,
177 ArrayRef<std::string> VerifyArchList) {
178 assert(!VerifyArchList.empty() &&
179 "The list of architectures should be non-empty");
180 assert(InputBinaries.size() == 1 && "Incorrect number of input binaries");
182 for (StringRef Arch : VerifyArchList)
183 if (Triple(Arch).getArch() == Triple::ArchType::UnknownArch)
184 reportError("Invalid architecture: " + Arch);
187 dyn_cast<MachOUniversalBinary>(InputBinaries.front().getBinary())) {
188 for (StringRef Arch : VerifyArchList) {
189 Expected<std::unique_ptr<MachOObjectFile>> Obj =
190 UO->getObjectForArch(Arch);
195 dyn_cast<MachOObjectFile>(InputBinaries.front().getBinary())) {
196 const Triple::ArchType ObjectArch = O->getArch();
197 for (StringRef Arch : VerifyArchList)
198 if (ObjectArch != Triple(Arch).getArch())
201 llvm_unreachable("Unexpected binary format");
206 static void printArchOrUnknown(const MachOObjectFile *ObjectFile) {
207 // Prints trailing space and unknown in this format for compatibility with
209 const std::string ObjectArch = ObjectFile->getArchTriple().getArchName();
210 if (ObjectArch.empty())
211 outs() << "unknown(" << ObjectFile->getHeader().cputype << ","
212 << ObjectFile->getHeader().cpusubtype << ") ";
214 outs() << ObjectArch + " ";
217 LLVM_ATTRIBUTE_NORETURN
218 static void printArchs(ArrayRef<OwningBinary<Binary>> InputBinaries) {
219 assert(InputBinaries.size() == 1 && "Incorrect number of input binaries");
220 const Binary *InputBinary = InputBinaries.front().getBinary();
221 if (auto UO = dyn_cast<MachOUniversalBinary>(InputBinary)) {
222 for (MachOUniversalBinary::object_iterator I = UO->begin_objects(),
223 E = UO->end_objects();
225 Expected<std::unique_ptr<MachOObjectFile>> BinaryOrError =
226 I->getAsObjectFile();
228 reportError(InputBinary->getFileName(), BinaryOrError.takeError());
229 printArchOrUnknown(BinaryOrError.get().get());
231 } else if (auto O = dyn_cast<MachOObjectFile>(InputBinary)) {
232 printArchOrUnknown(O);
234 llvm_unreachable("Unexpected binary format");
241 int main(int argc, char **argv) {
242 InitLLVM X(argc, argv);
243 Config C = parseLipoOptions(makeArrayRef(argv + 1, argc));
244 SmallVector<OwningBinary<Binary>, 1> InputBinaries =
245 readInputBinaries(C.InputFiles);
247 switch (C.ActionToPerform) {
248 case LipoAction::VerifyArch:
249 verifyArch(InputBinaries, C.VerifyArchList);
251 case LipoAction::PrintArchs:
252 printArchs(InputBinaries);