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/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/LLVMDriver.h"
30 #include "llvm/Support/TargetSelect.h"
31 #include "llvm/Support/WithColor.h"
32 #include "llvm/TargetParser/Triple.h"
33 #include "llvm/TextAPI/Architecture.h"
37 using namespace llvm::object
;
39 static const StringRef ToolName
= "llvm-lipo";
41 [[noreturn
]] static void reportError(Twine Message
) {
42 WithColor::error(errs(), ToolName
) << Message
<< "\n";
47 [[noreturn
]] static void reportError(Error E
) {
50 raw_string_ostream
OS(Buf
);
51 logAllUnhandledErrors(std::move(E
), OS
);
56 [[noreturn
]] static void reportError(StringRef File
, Error E
) {
59 raw_string_ostream
OS(Buf
);
60 logAllUnhandledErrors(std::move(E
), OS
);
62 WithColor::error(errs(), ToolName
) << "'" << File
<< "': " << Buf
;
68 LIPO_INVALID
= 0, // This is not an option ID.
69 #define OPTION(...) LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(LIPO_, __VA_ARGS__),
70 #include "LipoOpts.inc"
75 #define OPTTABLE_STR_TABLE_CODE
76 #include "LipoOpts.inc"
77 #undef OPTTABLE_STR_TABLE_CODE
79 #define OPTTABLE_PREFIXES_TABLE_CODE
80 #include "LipoOpts.inc"
81 #undef OPTTABLE_PREFIXES_TABLE_CODE
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"
91 class LipoOptTable
: public opt::GenericOptTable
{
94 : opt::GenericOptTable(lipo::OptionStrTable
, lipo::OptionPrefixesTable
,
95 lipo::LipoInfoTable
) {}
98 enum class LipoAction
{
109 std::optional
<StringRef
> ArchType
;
114 SmallVector
<InputFile
, 1> InputFiles
;
115 SmallVector
<std::string
, 1> VerifyArchList
;
116 SmallVector
<InputFile
, 1> ReplacementFiles
;
117 StringMap
<const uint32_t> SegmentAlignments
;
118 std::string ArchType
;
119 std::string OutputFile
;
120 LipoAction ActionToPerform
;
124 static Slice
createSliceFromArchive(LLVMContext
&LLVMCtx
, const Archive
&A
) {
125 Expected
<Slice
> ArchiveOrSlice
= Slice::create(A
, &LLVMCtx
);
127 reportError(A
.getFileName(), ArchiveOrSlice
.takeError());
128 return *ArchiveOrSlice
;
131 static Slice
createSliceFromIR(const IRObjectFile
&IRO
, unsigned Align
) {
132 Expected
<Slice
> IROrErr
= Slice::create(IRO
, Align
);
134 reportError(IRO
.getFileName(), IROrErr
.takeError());
140 static void validateArchitectureName(StringRef ArchitectureName
) {
141 if (!MachOObjectFile::isValidArch(ArchitectureName
)) {
143 raw_string_ostream
OS(Buf
);
144 OS
<< "Invalid architecture: " << ArchitectureName
145 << "\nValid architecture names are:";
146 for (auto arch
: MachOObjectFile::getValidArchs())
152 static Config
parseLipoOptions(ArrayRef
<const char *> ArgsArr
) {
155 unsigned MissingArgumentIndex
, MissingArgumentCount
;
156 opt::InputArgList InputArgs
=
157 T
.ParseArgs(ArgsArr
, MissingArgumentIndex
, MissingArgumentCount
);
159 if (MissingArgumentCount
)
160 reportError("missing argument to " +
161 StringRef(InputArgs
.getArgString(MissingArgumentIndex
)) +
164 if (InputArgs
.size() == 0) {
165 // printHelp does not accept Twine.
166 T
.printHelp(errs(), "llvm-lipo input[s] option[s]", "llvm-lipo");
170 if (InputArgs
.hasArg(LIPO_help
)) {
171 // printHelp does not accept Twine.
172 T
.printHelp(outs(), "llvm-lipo input[s] option[s]", "llvm-lipo");
176 if (InputArgs
.hasArg(LIPO_version
)) {
177 outs() << ToolName
+ "\n";
178 cl::PrintVersionMessage();
182 for (auto *Arg
: InputArgs
.filtered(LIPO_UNKNOWN
))
183 reportError("unknown argument '" + Arg
->getAsString(InputArgs
) + "'");
185 for (auto *Arg
: InputArgs
.filtered(LIPO_INPUT
))
186 C
.InputFiles
.push_back({std::nullopt
, Arg
->getValue()});
187 for (auto *Arg
: InputArgs
.filtered(LIPO_arch
)) {
188 validateArchitectureName(Arg
->getValue(0));
189 assert(Arg
->getValue(1) && "file_name is missing");
190 C
.InputFiles
.push_back({StringRef(Arg
->getValue(0)), Arg
->getValue(1)});
193 if (C
.InputFiles
.empty())
194 reportError("at least one input file should be specified");
196 if (InputArgs
.hasArg(LIPO_output
))
197 C
.OutputFile
= std::string(InputArgs
.getLastArgValue(LIPO_output
));
199 for (auto *Segalign
: InputArgs
.filtered(LIPO_segalign
)) {
200 if (!Segalign
->getValue(1))
201 reportError("segalign is missing an argument: expects -segalign "
202 "arch_type alignment_value");
204 validateArchitectureName(Segalign
->getValue(0));
206 uint32_t AlignmentValue
;
207 if (!to_integer
<uint32_t>(Segalign
->getValue(1), AlignmentValue
, 16))
208 reportError("argument to -segalign <arch_type> " +
209 Twine(Segalign
->getValue(1)) +
210 " (hex) is not a proper hexadecimal number");
211 if (!isPowerOf2_32(AlignmentValue
))
212 reportError("argument to -segalign <arch_type> " +
213 Twine(Segalign
->getValue(1)) +
214 " (hex) must be a non-zero power of two");
215 if (Log2_32(AlignmentValue
) > MachOUniversalBinary::MaxSectionAlignment
)
217 "argument to -segalign <arch_type> " + Twine(Segalign
->getValue(1)) +
218 " (hex) must be less than or equal to the maximum section align 2^" +
219 Twine(MachOUniversalBinary::MaxSectionAlignment
));
220 auto Entry
= C
.SegmentAlignments
.try_emplace(Segalign
->getValue(0),
221 Log2_32(AlignmentValue
));
223 reportError("-segalign " + Twine(Segalign
->getValue(0)) +
224 " <alignment_value> specified multiple times: " +
225 Twine(1 << Entry
.first
->second
) + ", " +
226 Twine(AlignmentValue
));
229 C
.UseFat64
= InputArgs
.hasArg(LIPO_fat64
);
231 SmallVector
<opt::Arg
*, 1> ActionArgs(InputArgs
.filtered(LIPO_action_group
));
232 if (ActionArgs
.empty())
233 reportError("at least one action should be specified");
234 // errors if multiple actions specified other than replace
235 // multiple replace flags may be specified, as long as they are not mixed with
236 // other action flags
237 auto ReplacementArgsRange
= InputArgs
.filtered(LIPO_replace
);
238 if (ActionArgs
.size() > 1 &&
240 static_cast<size_t>(std::distance(ReplacementArgsRange
.begin(),
241 ReplacementArgsRange
.end()))) {
243 raw_string_ostream
OS(Buf
);
244 OS
<< "only one of the following actions can be specified:";
245 for (auto *Arg
: ActionArgs
)
246 OS
<< " " << Arg
->getSpelling();
250 switch (ActionArgs
[0]->getOption().getID()) {
251 case LIPO_verify_arch
:
252 for (auto A
: InputArgs
.getAllArgValues(LIPO_verify_arch
))
253 C
.VerifyArchList
.push_back(A
);
254 if (C
.VerifyArchList
.empty())
256 "verify_arch requires at least one architecture to be specified");
257 if (C
.InputFiles
.size() > 1)
258 reportError("verify_arch expects a single input file");
259 C
.ActionToPerform
= LipoAction::VerifyArch
;
263 if (C
.InputFiles
.size() > 1)
264 reportError("archs expects a single input file");
265 C
.ActionToPerform
= LipoAction::PrintArchs
;
269 C
.ActionToPerform
= LipoAction::PrintInfo
;
273 if (C
.InputFiles
.size() > 1)
274 reportError("thin expects a single input file");
275 if (C
.OutputFile
.empty())
276 reportError("thin expects a single output file");
277 C
.ArchType
= ActionArgs
[0]->getValue();
278 validateArchitectureName(C
.ArchType
);
279 C
.ActionToPerform
= LipoAction::ThinArch
;
283 if (C
.InputFiles
.size() > 1)
284 reportError("extract expects a single input file");
285 if (C
.OutputFile
.empty())
286 reportError("extract expects a single output file");
287 C
.ArchType
= ActionArgs
[0]->getValue();
288 validateArchitectureName(C
.ArchType
);
289 C
.ActionToPerform
= LipoAction::ExtractArch
;
293 if (C
.OutputFile
.empty())
294 reportError("create expects a single output file to be specified");
295 C
.ActionToPerform
= LipoAction::CreateUniversal
;
299 for (auto *Action
: ActionArgs
) {
300 assert(Action
->getValue(1) && "file_name is missing");
301 validateArchitectureName(Action
->getValue(0));
302 C
.ReplacementFiles
.push_back(
303 {StringRef(Action
->getValue(0)), Action
->getValue(1)});
306 if (C
.OutputFile
.empty())
307 reportError("replace expects a single output file to be specified");
308 if (C
.InputFiles
.size() > 1)
309 reportError("replace expects a single input file");
310 C
.ActionToPerform
= LipoAction::ReplaceArch
;
314 reportError("llvm-lipo action unspecified");
318 static SmallVector
<OwningBinary
<Binary
>, 1>
319 readInputBinaries(LLVMContext
&LLVMCtx
, ArrayRef
<InputFile
> InputFiles
) {
320 SmallVector
<OwningBinary
<Binary
>, 1> InputBinaries
;
321 for (const InputFile
&IF
: InputFiles
) {
322 Expected
<OwningBinary
<Binary
>> BinaryOrErr
=
323 createBinary(IF
.FileName
, &LLVMCtx
);
325 reportError(IF
.FileName
, BinaryOrErr
.takeError());
326 const Binary
*B
= BinaryOrErr
->getBinary();
327 if (!B
->isArchive() && !B
->isMachO() && !B
->isMachOUniversalBinary() &&
329 reportError("File " + IF
.FileName
+ " has unsupported binary format");
330 if (IF
.ArchType
&& (B
->isMachO() || B
->isArchive() || B
->isIR())) {
331 const auto S
= B
->isMachO() ? Slice(*cast
<MachOObjectFile
>(B
))
333 ? createSliceFromArchive(LLVMCtx
, *cast
<Archive
>(B
))
334 : createSliceFromIR(*cast
<IRObjectFile
>(B
), 0);
335 const auto SpecifiedCPUType
= MachO::getCPUTypeFromArchitecture(
336 MachO::getArchitectureFromName(
337 Triple(*IF
.ArchType
).getArchName()))
339 // For compatibility with cctools' lipo the comparison is relaxed just to
340 // checking cputypes.
341 if (S
.getCPUType() != SpecifiedCPUType
)
342 reportError("specified architecture: " + *IF
.ArchType
+
343 " for file: " + B
->getFileName() +
344 " does not match the file's architecture (" +
345 S
.getArchString() + ")");
347 InputBinaries
.push_back(std::move(*BinaryOrErr
));
349 return InputBinaries
;
352 [[noreturn
]] static void
353 verifyArch(ArrayRef
<OwningBinary
<Binary
>> InputBinaries
,
354 ArrayRef
<std::string
> VerifyArchList
) {
355 assert(!VerifyArchList
.empty() &&
356 "The list of architectures should be non-empty");
357 assert(InputBinaries
.size() == 1 && "Incorrect number of input binaries");
359 for (StringRef Arch
: VerifyArchList
)
360 validateArchitectureName(Arch
);
363 dyn_cast
<MachOUniversalBinary
>(InputBinaries
.front().getBinary())) {
364 for (StringRef Arch
: VerifyArchList
) {
365 Expected
<MachOUniversalBinary::ObjectForArch
> Obj
=
366 UO
->getObjectForArch(Arch
);
371 dyn_cast
<MachOObjectFile
>(InputBinaries
.front().getBinary())) {
372 const Triple::ArchType ObjectArch
= O
->getArch();
373 for (StringRef Arch
: VerifyArchList
)
374 if (ObjectArch
!= Triple(Arch
).getArch())
377 llvm_unreachable("Unexpected binary format");
382 static void printBinaryArchs(LLVMContext
&LLVMCtx
, const Binary
*Binary
,
384 // Prints trailing space for compatibility with cctools lipo.
385 if (auto UO
= dyn_cast
<MachOUniversalBinary
>(Binary
)) {
386 for (const auto &O
: UO
->objects()) {
387 // Order here is important, because both MachOObjectFile and
388 // IRObjectFile can be created with a binary that has embedded bitcode.
389 Expected
<std::unique_ptr
<MachOObjectFile
>> MachOObjOrError
=
391 if (MachOObjOrError
) {
392 OS
<< Slice(*(MachOObjOrError
->get())).getArchString() << " ";
395 Expected
<std::unique_ptr
<IRObjectFile
>> IROrError
=
396 O
.getAsIRObject(LLVMCtx
);
398 consumeError(MachOObjOrError
.takeError());
399 Expected
<Slice
> SliceOrErr
= Slice::create(**IROrError
, O
.getAlign());
401 reportError(Binary
->getFileName(), SliceOrErr
.takeError());
404 OS
<< SliceOrErr
.get().getArchString() << " ";
407 Expected
<std::unique_ptr
<Archive
>> ArchiveOrError
= O
.getAsArchive();
408 if (ArchiveOrError
) {
409 consumeError(MachOObjOrError
.takeError());
410 consumeError(IROrError
.takeError());
411 OS
<< createSliceFromArchive(LLVMCtx
, **ArchiveOrError
).getArchString()
415 consumeError(ArchiveOrError
.takeError());
416 reportError(Binary
->getFileName(), MachOObjOrError
.takeError());
417 reportError(Binary
->getFileName(), IROrError
.takeError());
423 if (const auto *MachO
= dyn_cast
<MachOObjectFile
>(Binary
)) {
424 OS
<< Slice(*MachO
).getArchString() << " \n";
428 // This should be always the case, as this is tested in readInputBinaries
429 const auto *IR
= cast
<IRObjectFile
>(Binary
);
430 Expected
<Slice
> SliceOrErr
= createSliceFromIR(*IR
, 0);
432 reportError(IR
->getFileName(), SliceOrErr
.takeError());
434 OS
<< SliceOrErr
->getArchString() << " \n";
437 [[noreturn
]] static void
438 printArchs(LLVMContext
&LLVMCtx
, ArrayRef
<OwningBinary
<Binary
>> InputBinaries
) {
439 assert(InputBinaries
.size() == 1 && "Incorrect number of input binaries");
440 printBinaryArchs(LLVMCtx
, InputBinaries
.front().getBinary(), outs());
444 [[noreturn
]] static void
445 printInfo(LLVMContext
&LLVMCtx
, ArrayRef
<OwningBinary
<Binary
>> InputBinaries
) {
446 // Group universal and thin files together for compatibility with cctools lipo
447 for (auto &IB
: InputBinaries
) {
448 const Binary
*Binary
= IB
.getBinary();
449 if (Binary
->isMachOUniversalBinary()) {
450 outs() << "Architectures in the fat file: " << Binary
->getFileName()
452 printBinaryArchs(LLVMCtx
, Binary
, outs());
455 for (auto &IB
: InputBinaries
) {
456 const Binary
*Binary
= IB
.getBinary();
457 if (!Binary
->isMachOUniversalBinary()) {
458 assert(Binary
->isMachO() && "expected MachO binary");
459 outs() << "Non-fat file: " << Binary
->getFileName()
460 << " is architecture: ";
461 printBinaryArchs(LLVMCtx
, Binary
, outs());
467 [[noreturn
]] static void thinSlice(LLVMContext
&LLVMCtx
,
468 ArrayRef
<OwningBinary
<Binary
>> InputBinaries
,
470 StringRef OutputFileName
) {
471 assert(!ArchType
.empty() && "The architecture type should be non-empty");
472 assert(InputBinaries
.size() == 1 && "Incorrect number of input binaries");
473 assert(!OutputFileName
.empty() && "Thin expects a single output file");
475 if (InputBinaries
.front().getBinary()->isMachO()) {
476 reportError("input file " +
477 InputBinaries
.front().getBinary()->getFileName() +
478 " must be a fat file when the -thin option is specified");
482 auto *UO
= cast
<MachOUniversalBinary
>(InputBinaries
.front().getBinary());
483 Expected
<std::unique_ptr
<MachOObjectFile
>> Obj
=
484 UO
->getMachOObjectForArch(ArchType
);
485 Expected
<std::unique_ptr
<IRObjectFile
>> IRObj
=
486 UO
->getIRObjectForArch(ArchType
, LLVMCtx
);
487 Expected
<std::unique_ptr
<Archive
>> Ar
= UO
->getArchiveForArch(ArchType
);
488 if (!Obj
&& !IRObj
&& !Ar
)
489 reportError("fat input file " + UO
->getFileName() +
490 " does not contain the specified architecture " + ArchType
+
493 // Order here is important, because both Obj and IRObj will be valid with a
494 // binary that has embedded bitcode.
502 Expected
<std::unique_ptr
<FileOutputBuffer
>> OutFileOrError
=
503 FileOutputBuffer::create(OutputFileName
,
504 B
->getMemoryBufferRef().getBufferSize(),
505 sys::fs::can_execute(UO
->getFileName())
506 ? FileOutputBuffer::F_executable
509 reportError(OutputFileName
, OutFileOrError
.takeError());
510 std::copy(B
->getMemoryBufferRef().getBufferStart(),
511 B
->getMemoryBufferRef().getBufferEnd(),
512 OutFileOrError
.get()->getBufferStart());
513 if (Error E
= OutFileOrError
.get()->commit())
514 reportError(OutputFileName
, std::move(E
));
518 static void checkArchDuplicates(ArrayRef
<Slice
> Slices
) {
519 DenseMap
<uint64_t, const Binary
*> CPUIds
;
520 for (const auto &S
: Slices
) {
521 auto Entry
= CPUIds
.try_emplace(S
.getCPUID(), S
.getBinary());
523 reportError(Entry
.first
->second
->getFileName() + " and " +
524 S
.getBinary()->getFileName() +
525 " have the same architecture " + S
.getArchString() +
526 " and therefore cannot be in the same universal binary");
530 template <typename Range
>
531 static void updateAlignments(Range
&Slices
,
532 const StringMap
<const uint32_t> &Alignments
) {
533 for (auto &Slice
: Slices
) {
534 auto Alignment
= Alignments
.find(Slice
.getArchString());
535 if (Alignment
!= Alignments
.end())
536 Slice
.setP2Alignment(Alignment
->second
);
540 static void checkUnusedAlignments(ArrayRef
<Slice
> Slices
,
541 const StringMap
<const uint32_t> &Alignments
) {
542 auto HasArch
= [&](StringRef Arch
) {
543 return llvm::any_of(Slices
,
544 [Arch
](Slice S
) { return S
.getArchString() == Arch
; });
546 for (StringRef Arch
: Alignments
.keys())
548 reportError("-segalign " + Arch
+
549 " <value> specified but resulting fat file does not contain "
550 "that architecture ");
553 // Updates vector ExtractedObjects with the MachOObjectFiles extracted from
554 // Universal Binary files to transfer ownership.
555 static SmallVector
<Slice
, 2>
556 buildSlices(LLVMContext
&LLVMCtx
, ArrayRef
<OwningBinary
<Binary
>> InputBinaries
,
557 const StringMap
<const uint32_t> &Alignments
,
558 SmallVectorImpl
<std::unique_ptr
<SymbolicFile
>> &ExtractedObjects
) {
559 SmallVector
<Slice
, 2> Slices
;
560 for (auto &IB
: InputBinaries
) {
561 const Binary
*InputBinary
= IB
.getBinary();
562 if (auto UO
= dyn_cast
<MachOUniversalBinary
>(InputBinary
)) {
563 for (const auto &O
: UO
->objects()) {
564 // Order here is important, because both MachOObjectFile and
565 // IRObjectFile can be created with a binary that has embedded bitcode.
566 Expected
<std::unique_ptr
<MachOObjectFile
>> BinaryOrError
=
569 Slices
.emplace_back(*(BinaryOrError
.get()), O
.getAlign());
570 ExtractedObjects
.push_back(std::move(BinaryOrError
.get()));
573 Expected
<std::unique_ptr
<IRObjectFile
>> IROrError
=
574 O
.getAsIRObject(LLVMCtx
);
576 consumeError(BinaryOrError
.takeError());
577 Slice S
= createSliceFromIR(**IROrError
, O
.getAlign());
578 ExtractedObjects
.emplace_back(std::move(IROrError
.get()));
579 Slices
.emplace_back(std::move(S
));
582 reportError(InputBinary
->getFileName(), BinaryOrError
.takeError());
584 } else if (const auto *O
= dyn_cast
<MachOObjectFile
>(InputBinary
)) {
585 Slices
.emplace_back(*O
);
586 } else if (const auto *A
= dyn_cast
<Archive
>(InputBinary
)) {
587 Slices
.push_back(createSliceFromArchive(LLVMCtx
, *A
));
588 } else if (const auto *IRO
= dyn_cast
<IRObjectFile
>(InputBinary
)) {
589 // Original Apple's lipo set the alignment to 0
590 Expected
<Slice
> SliceOrErr
= Slice::create(*IRO
, 0);
592 reportError(InputBinary
->getFileName(), SliceOrErr
.takeError());
595 Slices
.emplace_back(std::move(SliceOrErr
.get()));
597 llvm_unreachable("Unexpected binary format");
600 updateAlignments(Slices
, Alignments
);
604 [[noreturn
]] static void
605 createUniversalBinary(LLVMContext
&LLVMCtx
,
606 ArrayRef
<OwningBinary
<Binary
>> InputBinaries
,
607 const StringMap
<const uint32_t> &Alignments
,
608 StringRef OutputFileName
, FatHeaderType HeaderType
) {
609 assert(InputBinaries
.size() >= 1 && "Incorrect number of input binaries");
610 assert(!OutputFileName
.empty() && "Create expects a single output file");
612 SmallVector
<std::unique_ptr
<SymbolicFile
>, 1> ExtractedObjects
;
613 SmallVector
<Slice
, 1> Slices
=
614 buildSlices(LLVMCtx
, InputBinaries
, Alignments
, ExtractedObjects
);
615 checkArchDuplicates(Slices
);
616 checkUnusedAlignments(Slices
, Alignments
);
618 llvm::stable_sort(Slices
);
619 if (Error E
= writeUniversalBinary(Slices
, OutputFileName
, HeaderType
))
620 reportError(std::move(E
));
625 [[noreturn
]] static void
626 extractSlice(LLVMContext
&LLVMCtx
, ArrayRef
<OwningBinary
<Binary
>> InputBinaries
,
627 const StringMap
<const uint32_t> &Alignments
, StringRef ArchType
,
628 StringRef OutputFileName
) {
629 assert(!ArchType
.empty() &&
630 "The architecture type should be non-empty");
631 assert(InputBinaries
.size() == 1 && "Incorrect number of input binaries");
632 assert(!OutputFileName
.empty() && "Thin expects a single output file");
634 if (InputBinaries
.front().getBinary()->isMachO()) {
635 reportError("input file " +
636 InputBinaries
.front().getBinary()->getFileName() +
637 " must be a fat file when the -extract option is specified");
640 SmallVector
<std::unique_ptr
<SymbolicFile
>, 2> ExtractedObjects
;
641 SmallVector
<Slice
, 2> Slices
=
642 buildSlices(LLVMCtx
, InputBinaries
, Alignments
, ExtractedObjects
);
643 erase_if(Slices
, [ArchType
](const Slice
&S
) {
644 return ArchType
!= S
.getArchString();
649 "fat input file " + InputBinaries
.front().getBinary()->getFileName() +
650 " does not contain the specified architecture " + ArchType
);
652 llvm::stable_sort(Slices
);
653 if (Error E
= writeUniversalBinary(Slices
, OutputFileName
))
654 reportError(std::move(E
));
658 static StringMap
<Slice
>
659 buildReplacementSlices(ArrayRef
<OwningBinary
<Binary
>> ReplacementBinaries
,
660 const StringMap
<const uint32_t> &Alignments
) {
661 StringMap
<Slice
> Slices
;
662 // populates StringMap of slices to replace with; error checks for mismatched
663 // replace flag args, fat files, and duplicate arch_types
664 for (const auto &OB
: ReplacementBinaries
) {
665 const Binary
*ReplacementBinary
= OB
.getBinary();
666 auto O
= dyn_cast
<MachOObjectFile
>(ReplacementBinary
);
668 reportError("replacement file: " + ReplacementBinary
->getFileName() +
669 " is a fat file (must be a thin file)");
671 auto Entry
= Slices
.try_emplace(S
.getArchString(), S
);
673 reportError("-replace " + S
.getArchString() +
674 " <file_name> specified multiple times: " +
675 Entry
.first
->second
.getBinary()->getFileName() + ", " +
678 auto SlicesMapRange
= map_range(
679 Slices
, [](StringMapEntry
<Slice
> &E
) -> Slice
& { return E
.getValue(); });
680 updateAlignments(SlicesMapRange
, Alignments
);
684 [[noreturn
]] static void
685 replaceSlices(LLVMContext
&LLVMCtx
,
686 ArrayRef
<OwningBinary
<Binary
>> InputBinaries
,
687 const StringMap
<const uint32_t> &Alignments
,
688 StringRef OutputFileName
, ArrayRef
<InputFile
> ReplacementFiles
) {
689 assert(InputBinaries
.size() == 1 && "Incorrect number of input binaries");
690 assert(!OutputFileName
.empty() && "Replace expects a single output file");
692 if (InputBinaries
.front().getBinary()->isMachO())
693 reportError("input file " +
694 InputBinaries
.front().getBinary()->getFileName() +
695 " must be a fat file when the -replace option is specified");
697 SmallVector
<OwningBinary
<Binary
>, 1> ReplacementBinaries
=
698 readInputBinaries(LLVMCtx
, ReplacementFiles
);
700 StringMap
<Slice
> ReplacementSlices
=
701 buildReplacementSlices(ReplacementBinaries
, Alignments
);
702 SmallVector
<std::unique_ptr
<SymbolicFile
>, 2> ExtractedObjects
;
703 SmallVector
<Slice
, 2> Slices
=
704 buildSlices(LLVMCtx
, InputBinaries
, Alignments
, ExtractedObjects
);
706 for (auto &Slice
: Slices
) {
707 auto It
= ReplacementSlices
.find(Slice
.getArchString());
708 if (It
!= ReplacementSlices
.end()) {
710 ReplacementSlices
.erase(It
); // only keep remaining replacing arch_types
714 if (!ReplacementSlices
.empty())
715 reportError("-replace " + ReplacementSlices
.begin()->first() +
716 " <file_name> specified but fat file: " +
717 InputBinaries
.front().getBinary()->getFileName() +
718 " does not contain that architecture");
720 checkUnusedAlignments(Slices
, Alignments
);
722 llvm::stable_sort(Slices
);
723 if (Error E
= writeUniversalBinary(Slices
, OutputFileName
))
724 reportError(std::move(E
));
728 int llvm_lipo_main(int argc
, char **argv
, const llvm::ToolContext
&) {
729 llvm::InitializeAllTargetInfos();
730 llvm::InitializeAllTargetMCs();
731 llvm::InitializeAllAsmParsers();
733 Config C
= parseLipoOptions(ArrayRef(argv
+ 1, argc
- 1));
735 SmallVector
<OwningBinary
<Binary
>, 1> InputBinaries
=
736 readInputBinaries(LLVMCtx
, C
.InputFiles
);
738 switch (C
.ActionToPerform
) {
739 case LipoAction::VerifyArch
:
740 verifyArch(InputBinaries
, C
.VerifyArchList
);
742 case LipoAction::PrintArchs
:
743 printArchs(LLVMCtx
, InputBinaries
);
745 case LipoAction::PrintInfo
:
746 printInfo(LLVMCtx
, InputBinaries
);
748 case LipoAction::ThinArch
:
749 thinSlice(LLVMCtx
, InputBinaries
, C
.ArchType
, C
.OutputFile
);
751 case LipoAction::ExtractArch
:
752 extractSlice(LLVMCtx
, InputBinaries
, C
.SegmentAlignments
, C
.ArchType
,
755 case LipoAction::CreateUniversal
:
756 createUniversalBinary(
757 LLVMCtx
, InputBinaries
, C
.SegmentAlignments
, C
.OutputFile
,
758 C
.UseFat64
? FatHeaderType::Fat64Header
: FatHeaderType::FatHeader
);
760 case LipoAction::ReplaceArch
:
761 replaceSlices(LLVMCtx
, InputBinaries
, C
.SegmentAlignments
, C
.OutputFile
,