[AMDGPU] Test codegen'ing True16 additions.
[llvm-project.git] / llvm / tools / llvm-lipo / llvm-lipo.cpp
blobb1f202877b15e8d342248e76082d3826e1aa8a4e
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.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/ADT/STLExtras.h"
14 #include "llvm/BinaryFormat/MachO.h"
15 #include "llvm/IR/LLVMContext.h"
16 #include "llvm/IR/Module.h"
17 #include "llvm/Object/Archive.h"
18 #include "llvm/Object/Binary.h"
19 #include "llvm/Object/IRObjectFile.h"
20 #include "llvm/Object/MachO.h"
21 #include "llvm/Object/MachOUniversal.h"
22 #include "llvm/Object/MachOUniversalWriter.h"
23 #include "llvm/Object/ObjectFile.h"
24 #include "llvm/Option/Arg.h"
25 #include "llvm/Option/ArgList.h"
26 #include "llvm/Support/CommandLine.h"
27 #include "llvm/Support/Error.h"
28 #include "llvm/Support/FileOutputBuffer.h"
29 #include "llvm/Support/InitLLVM.h"
30 #include "llvm/Support/LLVMDriver.h"
31 #include "llvm/Support/TargetSelect.h"
32 #include "llvm/Support/WithColor.h"
33 #include "llvm/TargetParser/Triple.h"
34 #include "llvm/TextAPI/Architecture.h"
35 #include <optional>
37 using namespace llvm;
38 using namespace llvm::object;
40 static const StringRef ToolName = "llvm-lipo";
42 [[noreturn]] static void reportError(Twine Message) {
43 WithColor::error(errs(), ToolName) << Message << "\n";
44 errs().flush();
45 exit(EXIT_FAILURE);
48 [[noreturn]] static void reportError(Error E) {
49 assert(E);
50 std::string Buf;
51 raw_string_ostream OS(Buf);
52 logAllUnhandledErrors(std::move(E), OS);
53 OS.flush();
54 reportError(Buf);
57 [[noreturn]] static void reportError(StringRef File, Error E) {
58 assert(E);
59 std::string Buf;
60 raw_string_ostream OS(Buf);
61 logAllUnhandledErrors(std::move(E), OS);
62 OS.flush();
63 WithColor::error(errs(), ToolName) << "'" << File << "': " << Buf;
64 exit(EXIT_FAILURE);
67 namespace {
68 enum LipoID {
69 LIPO_INVALID = 0, // This is not an option ID.
70 #define OPTION(...) LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(LIPO_, __VA_ARGS__),
71 #include "LipoOpts.inc"
72 #undef OPTION
75 namespace lipo {
76 #define PREFIX(NAME, VALUE) \
77 static constexpr llvm::StringLiteral NAME##_init[] = VALUE; \
78 static constexpr llvm::ArrayRef<llvm::StringLiteral> NAME( \
79 NAME##_init, std::size(NAME##_init) - 1);
80 #include "LipoOpts.inc"
81 #undef PREFIX
83 using namespace llvm::opt;
84 static constexpr opt::OptTable::Info LipoInfoTable[] = {
85 #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(LIPO_, __VA_ARGS__),
86 #include "LipoOpts.inc"
87 #undef OPTION
89 } // namespace lipo
91 class LipoOptTable : public opt::GenericOptTable {
92 public:
93 LipoOptTable() : opt::GenericOptTable(lipo::LipoInfoTable) {}
96 enum class LipoAction {
97 PrintArchs,
98 PrintInfo,
99 VerifyArch,
100 ThinArch,
101 ExtractArch,
102 CreateUniversal,
103 ReplaceArch,
106 struct InputFile {
107 std::optional<StringRef> ArchType;
108 StringRef FileName;
111 struct Config {
112 SmallVector<InputFile, 1> InputFiles;
113 SmallVector<std::string, 1> VerifyArchList;
114 SmallVector<InputFile, 1> ReplacementFiles;
115 StringMap<const uint32_t> SegmentAlignments;
116 std::string ArchType;
117 std::string OutputFile;
118 LipoAction ActionToPerform;
121 static Slice createSliceFromArchive(LLVMContext &LLVMCtx, const Archive &A) {
122 Expected<Slice> ArchiveOrSlice = Slice::create(A, &LLVMCtx);
123 if (!ArchiveOrSlice)
124 reportError(A.getFileName(), ArchiveOrSlice.takeError());
125 return *ArchiveOrSlice;
128 static Slice createSliceFromIR(const IRObjectFile &IRO, unsigned Align) {
129 Expected<Slice> IROrErr = Slice::create(IRO, Align);
130 if (!IROrErr)
131 reportError(IRO.getFileName(), IROrErr.takeError());
132 return *IROrErr;
135 } // end namespace
137 static void validateArchitectureName(StringRef ArchitectureName) {
138 if (!MachOObjectFile::isValidArch(ArchitectureName)) {
139 std::string Buf;
140 raw_string_ostream OS(Buf);
141 OS << "Invalid architecture: " << ArchitectureName
142 << "\nValid architecture names are:";
143 for (auto arch : MachOObjectFile::getValidArchs())
144 OS << " " << arch;
145 reportError(OS.str());
149 static Config parseLipoOptions(ArrayRef<const char *> ArgsArr) {
150 Config C;
151 LipoOptTable T;
152 unsigned MissingArgumentIndex, MissingArgumentCount;
153 opt::InputArgList InputArgs =
154 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
156 if (MissingArgumentCount)
157 reportError("missing argument to " +
158 StringRef(InputArgs.getArgString(MissingArgumentIndex)) +
159 " option");
161 if (InputArgs.size() == 0) {
162 // printHelp does not accept Twine.
163 T.printHelp(errs(), "llvm-lipo input[s] option[s]", "llvm-lipo");
164 exit(EXIT_FAILURE);
167 if (InputArgs.hasArg(LIPO_help)) {
168 // printHelp does not accept Twine.
169 T.printHelp(outs(), "llvm-lipo input[s] option[s]", "llvm-lipo");
170 exit(EXIT_SUCCESS);
173 if (InputArgs.hasArg(LIPO_version)) {
174 outs() << ToolName + "\n";
175 cl::PrintVersionMessage();
176 exit(EXIT_SUCCESS);
179 for (auto *Arg : InputArgs.filtered(LIPO_UNKNOWN))
180 reportError("unknown argument '" + Arg->getAsString(InputArgs) + "'");
182 for (auto *Arg : InputArgs.filtered(LIPO_INPUT))
183 C.InputFiles.push_back({std::nullopt, Arg->getValue()});
184 for (auto *Arg : InputArgs.filtered(LIPO_arch)) {
185 validateArchitectureName(Arg->getValue(0));
186 assert(Arg->getValue(1) && "file_name is missing");
187 C.InputFiles.push_back({StringRef(Arg->getValue(0)), Arg->getValue(1)});
190 if (C.InputFiles.empty())
191 reportError("at least one input file should be specified");
193 if (InputArgs.hasArg(LIPO_output))
194 C.OutputFile = std::string(InputArgs.getLastArgValue(LIPO_output));
196 for (auto *Segalign : InputArgs.filtered(LIPO_segalign)) {
197 if (!Segalign->getValue(1))
198 reportError("segalign is missing an argument: expects -segalign "
199 "arch_type alignment_value");
201 validateArchitectureName(Segalign->getValue(0));
203 uint32_t AlignmentValue;
204 if (!to_integer<uint32_t>(Segalign->getValue(1), AlignmentValue, 16))
205 reportError("argument to -segalign <arch_type> " +
206 Twine(Segalign->getValue(1)) +
207 " (hex) is not a proper hexadecimal number");
208 if (!isPowerOf2_32(AlignmentValue))
209 reportError("argument to -segalign <arch_type> " +
210 Twine(Segalign->getValue(1)) +
211 " (hex) must be a non-zero power of two");
212 if (Log2_32(AlignmentValue) > MachOUniversalBinary::MaxSectionAlignment)
213 reportError(
214 "argument to -segalign <arch_type> " + Twine(Segalign->getValue(1)) +
215 " (hex) must be less than or equal to the maximum section align 2^" +
216 Twine(MachOUniversalBinary::MaxSectionAlignment));
217 auto Entry = C.SegmentAlignments.try_emplace(Segalign->getValue(0),
218 Log2_32(AlignmentValue));
219 if (!Entry.second)
220 reportError("-segalign " + Twine(Segalign->getValue(0)) +
221 " <alignment_value> specified multiple times: " +
222 Twine(1 << Entry.first->second) + ", " +
223 Twine(AlignmentValue));
226 SmallVector<opt::Arg *, 1> ActionArgs(InputArgs.filtered(LIPO_action_group));
227 if (ActionArgs.empty())
228 reportError("at least one action should be specified");
229 // errors if multiple actions specified other than replace
230 // multiple replace flags may be specified, as long as they are not mixed with
231 // other action flags
232 auto ReplacementArgsRange = InputArgs.filtered(LIPO_replace);
233 if (ActionArgs.size() > 1 &&
234 ActionArgs.size() !=
235 static_cast<size_t>(std::distance(ReplacementArgsRange.begin(),
236 ReplacementArgsRange.end()))) {
237 std::string Buf;
238 raw_string_ostream OS(Buf);
239 OS << "only one of the following actions can be specified:";
240 for (auto *Arg : ActionArgs)
241 OS << " " << Arg->getSpelling();
242 reportError(OS.str());
245 switch (ActionArgs[0]->getOption().getID()) {
246 case LIPO_verify_arch:
247 for (auto A : InputArgs.getAllArgValues(LIPO_verify_arch))
248 C.VerifyArchList.push_back(A);
249 if (C.VerifyArchList.empty())
250 reportError(
251 "verify_arch requires at least one architecture to be specified");
252 if (C.InputFiles.size() > 1)
253 reportError("verify_arch expects a single input file");
254 C.ActionToPerform = LipoAction::VerifyArch;
255 return C;
257 case LIPO_archs:
258 if (C.InputFiles.size() > 1)
259 reportError("archs expects a single input file");
260 C.ActionToPerform = LipoAction::PrintArchs;
261 return C;
263 case LIPO_info:
264 C.ActionToPerform = LipoAction::PrintInfo;
265 return C;
267 case LIPO_thin:
268 if (C.InputFiles.size() > 1)
269 reportError("thin expects a single input file");
270 if (C.OutputFile.empty())
271 reportError("thin expects a single output file");
272 C.ArchType = ActionArgs[0]->getValue();
273 validateArchitectureName(C.ArchType);
274 C.ActionToPerform = LipoAction::ThinArch;
275 return C;
277 case LIPO_extract:
278 if (C.InputFiles.size() > 1)
279 reportError("extract expects a single input file");
280 if (C.OutputFile.empty())
281 reportError("extract expects a single output file");
282 C.ArchType = ActionArgs[0]->getValue();
283 validateArchitectureName(C.ArchType);
284 C.ActionToPerform = LipoAction::ExtractArch;
285 return C;
287 case LIPO_create:
288 if (C.OutputFile.empty())
289 reportError("create expects a single output file to be specified");
290 C.ActionToPerform = LipoAction::CreateUniversal;
291 return C;
293 case LIPO_replace:
294 for (auto *Action : ActionArgs) {
295 assert(Action->getValue(1) && "file_name is missing");
296 validateArchitectureName(Action->getValue(0));
297 C.ReplacementFiles.push_back(
298 {StringRef(Action->getValue(0)), Action->getValue(1)});
301 if (C.OutputFile.empty())
302 reportError("replace expects a single output file to be specified");
303 if (C.InputFiles.size() > 1)
304 reportError("replace expects a single input file");
305 C.ActionToPerform = LipoAction::ReplaceArch;
306 return C;
308 default:
309 reportError("llvm-lipo action unspecified");
313 static SmallVector<OwningBinary<Binary>, 1>
314 readInputBinaries(LLVMContext &LLVMCtx, ArrayRef<InputFile> InputFiles) {
315 SmallVector<OwningBinary<Binary>, 1> InputBinaries;
316 for (const InputFile &IF : InputFiles) {
317 Expected<OwningBinary<Binary>> BinaryOrErr =
318 createBinary(IF.FileName, &LLVMCtx);
319 if (!BinaryOrErr)
320 reportError(IF.FileName, BinaryOrErr.takeError());
321 const Binary *B = BinaryOrErr->getBinary();
322 if (!B->isArchive() && !B->isMachO() && !B->isMachOUniversalBinary() &&
323 !B->isIR())
324 reportError("File " + IF.FileName + " has unsupported binary format");
325 if (IF.ArchType && (B->isMachO() || B->isArchive() || B->isIR())) {
326 const auto S = B->isMachO() ? Slice(*cast<MachOObjectFile>(B))
327 : B->isArchive()
328 ? createSliceFromArchive(LLVMCtx, *cast<Archive>(B))
329 : createSliceFromIR(*cast<IRObjectFile>(B), 0);
330 const auto SpecifiedCPUType = MachO::getCPUTypeFromArchitecture(
331 MachO::getArchitectureFromName(
332 Triple(*IF.ArchType).getArchName()))
333 .first;
334 // For compatibility with cctools' lipo the comparison is relaxed just to
335 // checking cputypes.
336 if (S.getCPUType() != SpecifiedCPUType)
337 reportError("specified architecture: " + *IF.ArchType +
338 " for file: " + B->getFileName() +
339 " does not match the file's architecture (" +
340 S.getArchString() + ")");
342 InputBinaries.push_back(std::move(*BinaryOrErr));
344 return InputBinaries;
347 [[noreturn]] static void
348 verifyArch(ArrayRef<OwningBinary<Binary>> InputBinaries,
349 ArrayRef<std::string> VerifyArchList) {
350 assert(!VerifyArchList.empty() &&
351 "The list of architectures should be non-empty");
352 assert(InputBinaries.size() == 1 && "Incorrect number of input binaries");
354 for (StringRef Arch : VerifyArchList)
355 validateArchitectureName(Arch);
357 if (auto UO =
358 dyn_cast<MachOUniversalBinary>(InputBinaries.front().getBinary())) {
359 for (StringRef Arch : VerifyArchList) {
360 Expected<MachOUniversalBinary::ObjectForArch> Obj =
361 UO->getObjectForArch(Arch);
362 if (!Obj)
363 exit(EXIT_FAILURE);
365 } else if (auto O =
366 dyn_cast<MachOObjectFile>(InputBinaries.front().getBinary())) {
367 const Triple::ArchType ObjectArch = O->getArch();
368 for (StringRef Arch : VerifyArchList)
369 if (ObjectArch != Triple(Arch).getArch())
370 exit(EXIT_FAILURE);
371 } else {
372 llvm_unreachable("Unexpected binary format");
374 exit(EXIT_SUCCESS);
377 static void printBinaryArchs(LLVMContext &LLVMCtx, const Binary *Binary,
378 raw_ostream &OS) {
379 // Prints trailing space for compatibility with cctools lipo.
380 if (auto UO = dyn_cast<MachOUniversalBinary>(Binary)) {
381 for (const auto &O : UO->objects()) {
382 // Order here is important, because both MachOObjectFile and
383 // IRObjectFile can be created with a binary that has embedded bitcode.
384 Expected<std::unique_ptr<MachOObjectFile>> MachOObjOrError =
385 O.getAsObjectFile();
386 if (MachOObjOrError) {
387 OS << Slice(*(MachOObjOrError->get())).getArchString() << " ";
388 continue;
390 Expected<std::unique_ptr<IRObjectFile>> IROrError =
391 O.getAsIRObject(LLVMCtx);
392 if (IROrError) {
393 consumeError(MachOObjOrError.takeError());
394 Expected<Slice> SliceOrErr = Slice::create(**IROrError, O.getAlign());
395 if (!SliceOrErr) {
396 reportError(Binary->getFileName(), SliceOrErr.takeError());
397 continue;
399 OS << SliceOrErr.get().getArchString() << " ";
400 continue;
402 Expected<std::unique_ptr<Archive>> ArchiveOrError = O.getAsArchive();
403 if (ArchiveOrError) {
404 consumeError(MachOObjOrError.takeError());
405 consumeError(IROrError.takeError());
406 OS << createSliceFromArchive(LLVMCtx, **ArchiveOrError).getArchString()
407 << " ";
408 continue;
410 consumeError(ArchiveOrError.takeError());
411 reportError(Binary->getFileName(), MachOObjOrError.takeError());
412 reportError(Binary->getFileName(), IROrError.takeError());
414 OS << "\n";
415 return;
418 if (const auto *MachO = dyn_cast<MachOObjectFile>(Binary)) {
419 OS << Slice(*MachO).getArchString() << " \n";
420 return;
423 // This should be always the case, as this is tested in readInputBinaries
424 const auto *IR = cast<IRObjectFile>(Binary);
425 Expected<Slice> SliceOrErr = createSliceFromIR(*IR, 0);
426 if (!SliceOrErr)
427 reportError(IR->getFileName(), SliceOrErr.takeError());
429 OS << SliceOrErr->getArchString() << " \n";
432 [[noreturn]] static void
433 printArchs(LLVMContext &LLVMCtx, ArrayRef<OwningBinary<Binary>> InputBinaries) {
434 assert(InputBinaries.size() == 1 && "Incorrect number of input binaries");
435 printBinaryArchs(LLVMCtx, InputBinaries.front().getBinary(), outs());
436 exit(EXIT_SUCCESS);
439 [[noreturn]] static void
440 printInfo(LLVMContext &LLVMCtx, ArrayRef<OwningBinary<Binary>> InputBinaries) {
441 // Group universal and thin files together for compatibility with cctools lipo
442 for (auto &IB : InputBinaries) {
443 const Binary *Binary = IB.getBinary();
444 if (Binary->isMachOUniversalBinary()) {
445 outs() << "Architectures in the fat file: " << Binary->getFileName()
446 << " are: ";
447 printBinaryArchs(LLVMCtx, Binary, outs());
450 for (auto &IB : InputBinaries) {
451 const Binary *Binary = IB.getBinary();
452 if (!Binary->isMachOUniversalBinary()) {
453 assert(Binary->isMachO() && "expected MachO binary");
454 outs() << "Non-fat file: " << Binary->getFileName()
455 << " is architecture: ";
456 printBinaryArchs(LLVMCtx, Binary, outs());
459 exit(EXIT_SUCCESS);
462 [[noreturn]] static void thinSlice(LLVMContext &LLVMCtx,
463 ArrayRef<OwningBinary<Binary>> InputBinaries,
464 StringRef ArchType,
465 StringRef OutputFileName) {
466 assert(!ArchType.empty() && "The architecture type should be non-empty");
467 assert(InputBinaries.size() == 1 && "Incorrect number of input binaries");
468 assert(!OutputFileName.empty() && "Thin expects a single output file");
470 if (InputBinaries.front().getBinary()->isMachO()) {
471 reportError("input file " +
472 InputBinaries.front().getBinary()->getFileName() +
473 " must be a fat file when the -thin option is specified");
474 exit(EXIT_FAILURE);
477 auto *UO = cast<MachOUniversalBinary>(InputBinaries.front().getBinary());
478 Expected<std::unique_ptr<MachOObjectFile>> Obj =
479 UO->getMachOObjectForArch(ArchType);
480 Expected<std::unique_ptr<IRObjectFile>> IRObj =
481 UO->getIRObjectForArch(ArchType, LLVMCtx);
482 Expected<std::unique_ptr<Archive>> Ar = UO->getArchiveForArch(ArchType);
483 if (!Obj && !IRObj && !Ar)
484 reportError("fat input file " + UO->getFileName() +
485 " does not contain the specified architecture " + ArchType +
486 " to thin it to");
487 Binary *B;
488 // Order here is important, because both Obj and IRObj will be valid with a
489 // binary that has embedded bitcode.
490 if (Obj)
491 B = Obj->get();
492 else if (IRObj)
493 B = IRObj->get();
494 else
495 B = Ar->get();
497 Expected<std::unique_ptr<FileOutputBuffer>> OutFileOrError =
498 FileOutputBuffer::create(OutputFileName,
499 B->getMemoryBufferRef().getBufferSize(),
500 sys::fs::can_execute(UO->getFileName())
501 ? FileOutputBuffer::F_executable
502 : 0);
503 if (!OutFileOrError)
504 reportError(OutputFileName, OutFileOrError.takeError());
505 std::copy(B->getMemoryBufferRef().getBufferStart(),
506 B->getMemoryBufferRef().getBufferEnd(),
507 OutFileOrError.get()->getBufferStart());
508 if (Error E = OutFileOrError.get()->commit())
509 reportError(OutputFileName, std::move(E));
510 exit(EXIT_SUCCESS);
513 static void checkArchDuplicates(ArrayRef<Slice> Slices) {
514 DenseMap<uint64_t, const Binary *> CPUIds;
515 for (const auto &S : Slices) {
516 auto Entry = CPUIds.try_emplace(S.getCPUID(), S.getBinary());
517 if (!Entry.second)
518 reportError(Entry.first->second->getFileName() + " and " +
519 S.getBinary()->getFileName() +
520 " have the same architecture " + S.getArchString() +
521 " and therefore cannot be in the same universal binary");
525 template <typename Range>
526 static void updateAlignments(Range &Slices,
527 const StringMap<const uint32_t> &Alignments) {
528 for (auto &Slice : Slices) {
529 auto Alignment = Alignments.find(Slice.getArchString());
530 if (Alignment != Alignments.end())
531 Slice.setP2Alignment(Alignment->second);
535 static void checkUnusedAlignments(ArrayRef<Slice> Slices,
536 const StringMap<const uint32_t> &Alignments) {
537 auto HasArch = [&](StringRef Arch) {
538 return llvm::any_of(Slices,
539 [Arch](Slice S) { return S.getArchString() == Arch; });
541 for (StringRef Arch : Alignments.keys())
542 if (!HasArch(Arch))
543 reportError("-segalign " + Arch +
544 " <value> specified but resulting fat file does not contain "
545 "that architecture ");
548 // Updates vector ExtractedObjects with the MachOObjectFiles extracted from
549 // Universal Binary files to transfer ownership.
550 static SmallVector<Slice, 2>
551 buildSlices(LLVMContext &LLVMCtx, ArrayRef<OwningBinary<Binary>> InputBinaries,
552 const StringMap<const uint32_t> &Alignments,
553 SmallVectorImpl<std::unique_ptr<SymbolicFile>> &ExtractedObjects) {
554 SmallVector<Slice, 2> Slices;
555 for (auto &IB : InputBinaries) {
556 const Binary *InputBinary = IB.getBinary();
557 if (auto UO = dyn_cast<MachOUniversalBinary>(InputBinary)) {
558 for (const auto &O : UO->objects()) {
559 // Order here is important, because both MachOObjectFile and
560 // IRObjectFile can be created with a binary that has embedded bitcode.
561 Expected<std::unique_ptr<MachOObjectFile>> BinaryOrError =
562 O.getAsObjectFile();
563 if (BinaryOrError) {
564 Slices.emplace_back(*(BinaryOrError.get()), O.getAlign());
565 ExtractedObjects.push_back(std::move(BinaryOrError.get()));
566 continue;
568 Expected<std::unique_ptr<IRObjectFile>> IROrError =
569 O.getAsIRObject(LLVMCtx);
570 if (IROrError) {
571 consumeError(BinaryOrError.takeError());
572 Slice S = createSliceFromIR(**IROrError, O.getAlign());
573 ExtractedObjects.emplace_back(std::move(IROrError.get()));
574 Slices.emplace_back(std::move(S));
575 continue;
577 reportError(InputBinary->getFileName(), BinaryOrError.takeError());
579 } else if (const auto *O = dyn_cast<MachOObjectFile>(InputBinary)) {
580 Slices.emplace_back(*O);
581 } else if (const auto *A = dyn_cast<Archive>(InputBinary)) {
582 Slices.push_back(createSliceFromArchive(LLVMCtx, *A));
583 } else if (const auto *IRO = dyn_cast<IRObjectFile>(InputBinary)) {
584 // Original Apple's lipo set the alignment to 0
585 Expected<Slice> SliceOrErr = Slice::create(*IRO, 0);
586 if (!SliceOrErr) {
587 reportError(InputBinary->getFileName(), SliceOrErr.takeError());
588 continue;
590 Slices.emplace_back(std::move(SliceOrErr.get()));
591 } else {
592 llvm_unreachable("Unexpected binary format");
595 updateAlignments(Slices, Alignments);
596 return Slices;
599 [[noreturn]] static void createUniversalBinary(
600 LLVMContext &LLVMCtx, ArrayRef<OwningBinary<Binary>> InputBinaries,
601 const StringMap<const uint32_t> &Alignments, StringRef OutputFileName) {
602 assert(InputBinaries.size() >= 1 && "Incorrect number of input binaries");
603 assert(!OutputFileName.empty() && "Create expects a single output file");
605 SmallVector<std::unique_ptr<SymbolicFile>, 1> ExtractedObjects;
606 SmallVector<Slice, 1> Slices =
607 buildSlices(LLVMCtx, InputBinaries, Alignments, ExtractedObjects);
608 checkArchDuplicates(Slices);
609 checkUnusedAlignments(Slices, Alignments);
611 llvm::stable_sort(Slices);
612 if (Error E = writeUniversalBinary(Slices, OutputFileName))
613 reportError(std::move(E));
615 exit(EXIT_SUCCESS);
618 [[noreturn]] static void
619 extractSlice(LLVMContext &LLVMCtx, ArrayRef<OwningBinary<Binary>> InputBinaries,
620 const StringMap<const uint32_t> &Alignments, StringRef ArchType,
621 StringRef OutputFileName) {
622 assert(!ArchType.empty() &&
623 "The architecture type should be non-empty");
624 assert(InputBinaries.size() == 1 && "Incorrect number of input binaries");
625 assert(!OutputFileName.empty() && "Thin expects a single output file");
627 if (InputBinaries.front().getBinary()->isMachO()) {
628 reportError("input file " +
629 InputBinaries.front().getBinary()->getFileName() +
630 " must be a fat file when the -extract option is specified");
633 SmallVector<std::unique_ptr<SymbolicFile>, 2> ExtractedObjects;
634 SmallVector<Slice, 2> Slices =
635 buildSlices(LLVMCtx, InputBinaries, Alignments, ExtractedObjects);
636 erase_if(Slices, [ArchType](const Slice &S) {
637 return ArchType != S.getArchString();
640 if (Slices.empty())
641 reportError(
642 "fat input file " + InputBinaries.front().getBinary()->getFileName() +
643 " does not contain the specified architecture " + ArchType);
645 llvm::stable_sort(Slices);
646 if (Error E = writeUniversalBinary(Slices, OutputFileName))
647 reportError(std::move(E));
648 exit(EXIT_SUCCESS);
651 static StringMap<Slice>
652 buildReplacementSlices(ArrayRef<OwningBinary<Binary>> ReplacementBinaries,
653 const StringMap<const uint32_t> &Alignments) {
654 StringMap<Slice> Slices;
655 // populates StringMap of slices to replace with; error checks for mismatched
656 // replace flag args, fat files, and duplicate arch_types
657 for (const auto &OB : ReplacementBinaries) {
658 const Binary *ReplacementBinary = OB.getBinary();
659 auto O = dyn_cast<MachOObjectFile>(ReplacementBinary);
660 if (!O)
661 reportError("replacement file: " + ReplacementBinary->getFileName() +
662 " is a fat file (must be a thin file)");
663 Slice S(*O);
664 auto Entry = Slices.try_emplace(S.getArchString(), S);
665 if (!Entry.second)
666 reportError("-replace " + S.getArchString() +
667 " <file_name> specified multiple times: " +
668 Entry.first->second.getBinary()->getFileName() + ", " +
669 O->getFileName());
671 auto SlicesMapRange = map_range(
672 Slices, [](StringMapEntry<Slice> &E) -> Slice & { return E.getValue(); });
673 updateAlignments(SlicesMapRange, Alignments);
674 return Slices;
677 [[noreturn]] static void
678 replaceSlices(LLVMContext &LLVMCtx,
679 ArrayRef<OwningBinary<Binary>> InputBinaries,
680 const StringMap<const uint32_t> &Alignments,
681 StringRef OutputFileName, ArrayRef<InputFile> ReplacementFiles) {
682 assert(InputBinaries.size() == 1 && "Incorrect number of input binaries");
683 assert(!OutputFileName.empty() && "Replace expects a single output file");
685 if (InputBinaries.front().getBinary()->isMachO())
686 reportError("input file " +
687 InputBinaries.front().getBinary()->getFileName() +
688 " must be a fat file when the -replace option is specified");
690 SmallVector<OwningBinary<Binary>, 1> ReplacementBinaries =
691 readInputBinaries(LLVMCtx, ReplacementFiles);
693 StringMap<Slice> ReplacementSlices =
694 buildReplacementSlices(ReplacementBinaries, Alignments);
695 SmallVector<std::unique_ptr<SymbolicFile>, 2> ExtractedObjects;
696 SmallVector<Slice, 2> Slices =
697 buildSlices(LLVMCtx, InputBinaries, Alignments, ExtractedObjects);
699 for (auto &Slice : Slices) {
700 auto It = ReplacementSlices.find(Slice.getArchString());
701 if (It != ReplacementSlices.end()) {
702 Slice = It->second;
703 ReplacementSlices.erase(It); // only keep remaining replacing arch_types
707 if (!ReplacementSlices.empty())
708 reportError("-replace " + ReplacementSlices.begin()->first() +
709 " <file_name> specified but fat file: " +
710 InputBinaries.front().getBinary()->getFileName() +
711 " does not contain that architecture");
713 checkUnusedAlignments(Slices, Alignments);
715 llvm::stable_sort(Slices);
716 if (Error E = writeUniversalBinary(Slices, OutputFileName))
717 reportError(std::move(E));
718 exit(EXIT_SUCCESS);
721 int llvm_lipo_main(int argc, char **argv, const llvm::ToolContext &) {
722 InitLLVM X(argc, argv);
723 llvm::InitializeAllTargetInfos();
724 llvm::InitializeAllTargetMCs();
725 llvm::InitializeAllAsmParsers();
727 Config C = parseLipoOptions(ArrayRef(argv + 1, argc - 1));
728 LLVMContext LLVMCtx;
729 SmallVector<OwningBinary<Binary>, 1> InputBinaries =
730 readInputBinaries(LLVMCtx, C.InputFiles);
732 switch (C.ActionToPerform) {
733 case LipoAction::VerifyArch:
734 verifyArch(InputBinaries, C.VerifyArchList);
735 break;
736 case LipoAction::PrintArchs:
737 printArchs(LLVMCtx, InputBinaries);
738 break;
739 case LipoAction::PrintInfo:
740 printInfo(LLVMCtx, InputBinaries);
741 break;
742 case LipoAction::ThinArch:
743 thinSlice(LLVMCtx, InputBinaries, C.ArchType, C.OutputFile);
744 break;
745 case LipoAction::ExtractArch:
746 extractSlice(LLVMCtx, InputBinaries, C.SegmentAlignments, C.ArchType,
747 C.OutputFile);
748 break;
749 case LipoAction::CreateUniversal:
750 createUniversalBinary(LLVMCtx, InputBinaries, C.SegmentAlignments,
751 C.OutputFile);
752 break;
753 case LipoAction::ReplaceArch:
754 replaceSlices(LLVMCtx, InputBinaries, C.SegmentAlignments, C.OutputFile,
755 C.ReplacementFiles);
756 break;
758 return EXIT_SUCCESS;