OSDN Git Service

[llvm-lipo] Drop unneeded braces. NFC
[android-x86/external-llvm.git] / tools / llvm-lipo / llvm-lipo.cpp
1 //===-- llvm-lipo.cpp - a tool for manipulating universal binaries --------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // A utility for creating / splitting / inspecting universal binaries.
10 //
11 //===----------------------------------------------------------------------===//
12
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"
24
25 using namespace llvm;
26 using namespace llvm::object;
27
28 static const StringRef ToolName = "llvm-lipo";
29
30 LLVM_ATTRIBUTE_NORETURN static void reportError(Twine Message) {
31   WithColor::error(errs(), ToolName) << Message << "\n";
32   errs().flush();
33   exit(EXIT_FAILURE);
34 }
35
36 LLVM_ATTRIBUTE_NORETURN static void reportError(StringRef File, Error E) {
37   assert(E);
38   std::string Buf;
39   raw_string_ostream OS(Buf);
40   logAllUnhandledErrors(std::move(E), OS);
41   OS.flush();
42   WithColor::error(errs(), ToolName) << "'" << File << "': " << Buf;
43   exit(EXIT_FAILURE);
44 }
45
46 namespace {
47 enum LipoID {
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)                                      \
51   LIPO_##ID,
52 #include "LipoOpts.inc"
53 #undef OPTION
54 };
55
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"
60 #undef PREFIX
61
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"
70 #undef OPTION
71 };
72
73 class LipoOptTable : public opt::OptTable {
74 public:
75   LipoOptTable() : OptTable(LipoInfoTable) {}
76 };
77
78 enum class LipoAction {
79   PrintArchs,
80   VerifyArch,
81 };
82
83 struct Config {
84   SmallVector<std::string, 1> InputFiles;
85   SmallVector<std::string, 1> VerifyArchList;
86   LipoAction ActionToPerform;
87 };
88
89 } // end namespace
90
91 static Config parseLipoOptions(ArrayRef<const char *> ArgsArr) {
92   Config C;
93   LipoOptTable T;
94   unsigned MissingArgumentIndex, MissingArgumentCount;
95   llvm::opt::InputArgList InputArgs =
96       T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
97
98   if (InputArgs.size() == 0) {
99     // PrintHelp does not accept Twine.
100     T.PrintHelp(errs(), "llvm-lipo input[s] option[s]", "llvm-lipo");
101     exit(EXIT_FAILURE);
102   }
103
104   if (InputArgs.hasArg(LIPO_help)) {
105     // PrintHelp does not accept Twine.
106     T.PrintHelp(outs(), "llvm-lipo input[s] option[s]", "llvm-lipo");
107     exit(EXIT_SUCCESS);
108   }
109
110   if (InputArgs.hasArg(LIPO_version)) {
111     outs() << ToolName + "\n";
112     cl::PrintVersionMessage();
113     exit(EXIT_SUCCESS);
114   }
115
116   for (auto Arg : InputArgs.filtered(LIPO_UNKNOWN))
117     reportError("unknown argument '" + Arg->getAsString(InputArgs) + "'");
118
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");
123
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) {
128     std::string Buf;
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());
134   }
135
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())
141       reportError(
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;
146     return C;
147
148   case LIPO_archs:
149     if (C.InputFiles.size() > 1)
150       reportError("archs expects a single input file");
151     C.ActionToPerform = LipoAction::PrintArchs;
152     return C;
153
154   default:
155     reportError("llvm-lipo action unspecified");
156   }
157 }
158
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);
165     if (!BinaryOrErr)
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));
171   }
172   return InputBinaries;
173 }
174
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");
181
182   for (StringRef Arch : VerifyArchList)
183     if (Triple(Arch).getArch() == Triple::ArchType::UnknownArch)
184       reportError("Invalid architecture: " + Arch);
185
186   if (auto UO =
187           dyn_cast<MachOUniversalBinary>(InputBinaries.front().getBinary())) {
188     for (StringRef Arch : VerifyArchList) {
189       Expected<std::unique_ptr<MachOObjectFile>> Obj =
190           UO->getObjectForArch(Arch);
191       if (!Obj)
192         exit(EXIT_FAILURE);
193     }
194   } else if (auto O =
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())
199         exit(EXIT_FAILURE);
200   } else {
201     llvm_unreachable("Unexpected binary format");
202   }
203   exit(EXIT_SUCCESS);
204 }
205
206 static void printArchOrUnknown(const MachOObjectFile *ObjectFile) {
207   // Prints trailing space and unknown in this format for compatibility with
208   // cctools lipo.
209   const std::string ObjectArch = ObjectFile->getArchTriple().getArchName();
210   if (ObjectArch.empty())
211     outs() << "unknown(" << ObjectFile->getHeader().cputype << ","
212            << ObjectFile->getHeader().cpusubtype << ") ";
213   else
214     outs() << ObjectArch + " ";
215 }
216
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();
224          I != E; ++I) {
225       Expected<std::unique_ptr<MachOObjectFile>> BinaryOrError =
226           I->getAsObjectFile();
227       if (!BinaryOrError)
228         reportError(InputBinary->getFileName(), BinaryOrError.takeError());
229       printArchOrUnknown(BinaryOrError.get().get());
230     }
231   } else if (auto O = dyn_cast<MachOObjectFile>(InputBinary)) {
232     printArchOrUnknown(O);
233   } else {
234     llvm_unreachable("Unexpected binary format");
235   }
236
237   outs() << "\n";
238   exit(EXIT_SUCCESS);
239 }
240
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);
246
247   switch (C.ActionToPerform) {
248   case LipoAction::VerifyArch:
249     verifyArch(InputBinaries, C.VerifyArchList);
250     break;
251   case LipoAction::PrintArchs:
252     printArchs(InputBinaries);
253     break;
254   }
255   return EXIT_SUCCESS;
256 }