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/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"
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";
48 [[noreturn
]] static void reportError(Error E
) {
51 raw_string_ostream
OS(Buf
);
52 logAllUnhandledErrors(std::move(E
), OS
);
57 [[noreturn
]] static void reportError(StringRef File
, Error E
) {
60 raw_string_ostream
OS(Buf
);
61 logAllUnhandledErrors(std::move(E
), OS
);
63 WithColor::error(errs(), ToolName
) << "'" << File
<< "': " << Buf
;
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"
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"
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
{
93 LipoOptTable() : opt::GenericOptTable(lipo::LipoInfoTable
) {}
96 enum class LipoAction
{
107 std::optional
<StringRef
> ArchType
;
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
;
122 static Slice
createSliceFromArchive(LLVMContext
&LLVMCtx
, const Archive
&A
) {
123 Expected
<Slice
> ArchiveOrSlice
= Slice::create(A
, &LLVMCtx
);
125 reportError(A
.getFileName(), ArchiveOrSlice
.takeError());
126 return *ArchiveOrSlice
;
129 static Slice
createSliceFromIR(const IRObjectFile
&IRO
, unsigned Align
) {
130 Expected
<Slice
> IROrErr
= Slice::create(IRO
, Align
);
132 reportError(IRO
.getFileName(), IROrErr
.takeError());
138 static void validateArchitectureName(StringRef ArchitectureName
) {
139 if (!MachOObjectFile::isValidArch(ArchitectureName
)) {
141 raw_string_ostream
OS(Buf
);
142 OS
<< "Invalid architecture: " << ArchitectureName
143 << "\nValid architecture names are:";
144 for (auto arch
: MachOObjectFile::getValidArchs())
146 reportError(OS
.str());
150 static Config
parseLipoOptions(ArrayRef
<const char *> ArgsArr
) {
153 unsigned MissingArgumentIndex
, MissingArgumentCount
;
154 opt::InputArgList InputArgs
=
155 T
.ParseArgs(ArgsArr
, MissingArgumentIndex
, MissingArgumentCount
);
157 if (MissingArgumentCount
)
158 reportError("missing argument to " +
159 StringRef(InputArgs
.getArgString(MissingArgumentIndex
)) +
162 if (InputArgs
.size() == 0) {
163 // printHelp does not accept Twine.
164 T
.printHelp(errs(), "llvm-lipo input[s] option[s]", "llvm-lipo");
168 if (InputArgs
.hasArg(LIPO_help
)) {
169 // printHelp does not accept Twine.
170 T
.printHelp(outs(), "llvm-lipo input[s] option[s]", "llvm-lipo");
174 if (InputArgs
.hasArg(LIPO_version
)) {
175 outs() << ToolName
+ "\n";
176 cl::PrintVersionMessage();
180 for (auto *Arg
: InputArgs
.filtered(LIPO_UNKNOWN
))
181 reportError("unknown argument '" + Arg
->getAsString(InputArgs
) + "'");
183 for (auto *Arg
: InputArgs
.filtered(LIPO_INPUT
))
184 C
.InputFiles
.push_back({std::nullopt
, Arg
->getValue()});
185 for (auto *Arg
: InputArgs
.filtered(LIPO_arch
)) {
186 validateArchitectureName(Arg
->getValue(0));
187 assert(Arg
->getValue(1) && "file_name is missing");
188 C
.InputFiles
.push_back({StringRef(Arg
->getValue(0)), Arg
->getValue(1)});
191 if (C
.InputFiles
.empty())
192 reportError("at least one input file should be specified");
194 if (InputArgs
.hasArg(LIPO_output
))
195 C
.OutputFile
= std::string(InputArgs
.getLastArgValue(LIPO_output
));
197 for (auto *Segalign
: InputArgs
.filtered(LIPO_segalign
)) {
198 if (!Segalign
->getValue(1))
199 reportError("segalign is missing an argument: expects -segalign "
200 "arch_type alignment_value");
202 validateArchitectureName(Segalign
->getValue(0));
204 uint32_t AlignmentValue
;
205 if (!to_integer
<uint32_t>(Segalign
->getValue(1), AlignmentValue
, 16))
206 reportError("argument to -segalign <arch_type> " +
207 Twine(Segalign
->getValue(1)) +
208 " (hex) is not a proper hexadecimal number");
209 if (!isPowerOf2_32(AlignmentValue
))
210 reportError("argument to -segalign <arch_type> " +
211 Twine(Segalign
->getValue(1)) +
212 " (hex) must be a non-zero power of two");
213 if (Log2_32(AlignmentValue
) > MachOUniversalBinary::MaxSectionAlignment
)
215 "argument to -segalign <arch_type> " + Twine(Segalign
->getValue(1)) +
216 " (hex) must be less than or equal to the maximum section align 2^" +
217 Twine(MachOUniversalBinary::MaxSectionAlignment
));
218 auto Entry
= C
.SegmentAlignments
.try_emplace(Segalign
->getValue(0),
219 Log2_32(AlignmentValue
));
221 reportError("-segalign " + Twine(Segalign
->getValue(0)) +
222 " <alignment_value> specified multiple times: " +
223 Twine(1 << Entry
.first
->second
) + ", " +
224 Twine(AlignmentValue
));
227 C
.UseFat64
= InputArgs
.hasArg(LIPO_fat64
);
229 SmallVector
<opt::Arg
*, 1> ActionArgs(InputArgs
.filtered(LIPO_action_group
));
230 if (ActionArgs
.empty())
231 reportError("at least one action should be specified");
232 // errors if multiple actions specified other than replace
233 // multiple replace flags may be specified, as long as they are not mixed with
234 // other action flags
235 auto ReplacementArgsRange
= InputArgs
.filtered(LIPO_replace
);
236 if (ActionArgs
.size() > 1 &&
238 static_cast<size_t>(std::distance(ReplacementArgsRange
.begin(),
239 ReplacementArgsRange
.end()))) {
241 raw_string_ostream
OS(Buf
);
242 OS
<< "only one of the following actions can be specified:";
243 for (auto *Arg
: ActionArgs
)
244 OS
<< " " << Arg
->getSpelling();
245 reportError(OS
.str());
248 switch (ActionArgs
[0]->getOption().getID()) {
249 case LIPO_verify_arch
:
250 for (auto A
: InputArgs
.getAllArgValues(LIPO_verify_arch
))
251 C
.VerifyArchList
.push_back(A
);
252 if (C
.VerifyArchList
.empty())
254 "verify_arch requires at least one architecture to be specified");
255 if (C
.InputFiles
.size() > 1)
256 reportError("verify_arch expects a single input file");
257 C
.ActionToPerform
= LipoAction::VerifyArch
;
261 if (C
.InputFiles
.size() > 1)
262 reportError("archs expects a single input file");
263 C
.ActionToPerform
= LipoAction::PrintArchs
;
267 C
.ActionToPerform
= LipoAction::PrintInfo
;
271 if (C
.InputFiles
.size() > 1)
272 reportError("thin expects a single input file");
273 if (C
.OutputFile
.empty())
274 reportError("thin expects a single output file");
275 C
.ArchType
= ActionArgs
[0]->getValue();
276 validateArchitectureName(C
.ArchType
);
277 C
.ActionToPerform
= LipoAction::ThinArch
;
281 if (C
.InputFiles
.size() > 1)
282 reportError("extract expects a single input file");
283 if (C
.OutputFile
.empty())
284 reportError("extract expects a single output file");
285 C
.ArchType
= ActionArgs
[0]->getValue();
286 validateArchitectureName(C
.ArchType
);
287 C
.ActionToPerform
= LipoAction::ExtractArch
;
291 if (C
.OutputFile
.empty())
292 reportError("create expects a single output file to be specified");
293 C
.ActionToPerform
= LipoAction::CreateUniversal
;
297 for (auto *Action
: ActionArgs
) {
298 assert(Action
->getValue(1) && "file_name is missing");
299 validateArchitectureName(Action
->getValue(0));
300 C
.ReplacementFiles
.push_back(
301 {StringRef(Action
->getValue(0)), Action
->getValue(1)});
304 if (C
.OutputFile
.empty())
305 reportError("replace expects a single output file to be specified");
306 if (C
.InputFiles
.size() > 1)
307 reportError("replace expects a single input file");
308 C
.ActionToPerform
= LipoAction::ReplaceArch
;
312 reportError("llvm-lipo action unspecified");
316 static SmallVector
<OwningBinary
<Binary
>, 1>
317 readInputBinaries(LLVMContext
&LLVMCtx
, ArrayRef
<InputFile
> InputFiles
) {
318 SmallVector
<OwningBinary
<Binary
>, 1> InputBinaries
;
319 for (const InputFile
&IF
: InputFiles
) {
320 Expected
<OwningBinary
<Binary
>> BinaryOrErr
=
321 createBinary(IF
.FileName
, &LLVMCtx
);
323 reportError(IF
.FileName
, BinaryOrErr
.takeError());
324 const Binary
*B
= BinaryOrErr
->getBinary();
325 if (!B
->isArchive() && !B
->isMachO() && !B
->isMachOUniversalBinary() &&
327 reportError("File " + IF
.FileName
+ " has unsupported binary format");
328 if (IF
.ArchType
&& (B
->isMachO() || B
->isArchive() || B
->isIR())) {
329 const auto S
= B
->isMachO() ? Slice(*cast
<MachOObjectFile
>(B
))
331 ? createSliceFromArchive(LLVMCtx
, *cast
<Archive
>(B
))
332 : createSliceFromIR(*cast
<IRObjectFile
>(B
), 0);
333 const auto SpecifiedCPUType
= MachO::getCPUTypeFromArchitecture(
334 MachO::getArchitectureFromName(
335 Triple(*IF
.ArchType
).getArchName()))
337 // For compatibility with cctools' lipo the comparison is relaxed just to
338 // checking cputypes.
339 if (S
.getCPUType() != SpecifiedCPUType
)
340 reportError("specified architecture: " + *IF
.ArchType
+
341 " for file: " + B
->getFileName() +
342 " does not match the file's architecture (" +
343 S
.getArchString() + ")");
345 InputBinaries
.push_back(std::move(*BinaryOrErr
));
347 return InputBinaries
;
350 [[noreturn
]] static void
351 verifyArch(ArrayRef
<OwningBinary
<Binary
>> InputBinaries
,
352 ArrayRef
<std::string
> VerifyArchList
) {
353 assert(!VerifyArchList
.empty() &&
354 "The list of architectures should be non-empty");
355 assert(InputBinaries
.size() == 1 && "Incorrect number of input binaries");
357 for (StringRef Arch
: VerifyArchList
)
358 validateArchitectureName(Arch
);
361 dyn_cast
<MachOUniversalBinary
>(InputBinaries
.front().getBinary())) {
362 for (StringRef Arch
: VerifyArchList
) {
363 Expected
<MachOUniversalBinary::ObjectForArch
> Obj
=
364 UO
->getObjectForArch(Arch
);
369 dyn_cast
<MachOObjectFile
>(InputBinaries
.front().getBinary())) {
370 const Triple::ArchType ObjectArch
= O
->getArch();
371 for (StringRef Arch
: VerifyArchList
)
372 if (ObjectArch
!= Triple(Arch
).getArch())
375 llvm_unreachable("Unexpected binary format");
380 static void printBinaryArchs(LLVMContext
&LLVMCtx
, const Binary
*Binary
,
382 // Prints trailing space for compatibility with cctools lipo.
383 if (auto UO
= dyn_cast
<MachOUniversalBinary
>(Binary
)) {
384 for (const auto &O
: UO
->objects()) {
385 // Order here is important, because both MachOObjectFile and
386 // IRObjectFile can be created with a binary that has embedded bitcode.
387 Expected
<std::unique_ptr
<MachOObjectFile
>> MachOObjOrError
=
389 if (MachOObjOrError
) {
390 OS
<< Slice(*(MachOObjOrError
->get())).getArchString() << " ";
393 Expected
<std::unique_ptr
<IRObjectFile
>> IROrError
=
394 O
.getAsIRObject(LLVMCtx
);
396 consumeError(MachOObjOrError
.takeError());
397 Expected
<Slice
> SliceOrErr
= Slice::create(**IROrError
, O
.getAlign());
399 reportError(Binary
->getFileName(), SliceOrErr
.takeError());
402 OS
<< SliceOrErr
.get().getArchString() << " ";
405 Expected
<std::unique_ptr
<Archive
>> ArchiveOrError
= O
.getAsArchive();
406 if (ArchiveOrError
) {
407 consumeError(MachOObjOrError
.takeError());
408 consumeError(IROrError
.takeError());
409 OS
<< createSliceFromArchive(LLVMCtx
, **ArchiveOrError
).getArchString()
413 consumeError(ArchiveOrError
.takeError());
414 reportError(Binary
->getFileName(), MachOObjOrError
.takeError());
415 reportError(Binary
->getFileName(), IROrError
.takeError());
421 if (const auto *MachO
= dyn_cast
<MachOObjectFile
>(Binary
)) {
422 OS
<< Slice(*MachO
).getArchString() << " \n";
426 // This should be always the case, as this is tested in readInputBinaries
427 const auto *IR
= cast
<IRObjectFile
>(Binary
);
428 Expected
<Slice
> SliceOrErr
= createSliceFromIR(*IR
, 0);
430 reportError(IR
->getFileName(), SliceOrErr
.takeError());
432 OS
<< SliceOrErr
->getArchString() << " \n";
435 [[noreturn
]] static void
436 printArchs(LLVMContext
&LLVMCtx
, ArrayRef
<OwningBinary
<Binary
>> InputBinaries
) {
437 assert(InputBinaries
.size() == 1 && "Incorrect number of input binaries");
438 printBinaryArchs(LLVMCtx
, InputBinaries
.front().getBinary(), outs());
442 [[noreturn
]] static void
443 printInfo(LLVMContext
&LLVMCtx
, ArrayRef
<OwningBinary
<Binary
>> InputBinaries
) {
444 // Group universal and thin files together for compatibility with cctools lipo
445 for (auto &IB
: InputBinaries
) {
446 const Binary
*Binary
= IB
.getBinary();
447 if (Binary
->isMachOUniversalBinary()) {
448 outs() << "Architectures in the fat file: " << Binary
->getFileName()
450 printBinaryArchs(LLVMCtx
, Binary
, outs());
453 for (auto &IB
: InputBinaries
) {
454 const Binary
*Binary
= IB
.getBinary();
455 if (!Binary
->isMachOUniversalBinary()) {
456 assert(Binary
->isMachO() && "expected MachO binary");
457 outs() << "Non-fat file: " << Binary
->getFileName()
458 << " is architecture: ";
459 printBinaryArchs(LLVMCtx
, Binary
, outs());
465 [[noreturn
]] static void thinSlice(LLVMContext
&LLVMCtx
,
466 ArrayRef
<OwningBinary
<Binary
>> InputBinaries
,
468 StringRef OutputFileName
) {
469 assert(!ArchType
.empty() && "The architecture type should be non-empty");
470 assert(InputBinaries
.size() == 1 && "Incorrect number of input binaries");
471 assert(!OutputFileName
.empty() && "Thin expects a single output file");
473 if (InputBinaries
.front().getBinary()->isMachO()) {
474 reportError("input file " +
475 InputBinaries
.front().getBinary()->getFileName() +
476 " must be a fat file when the -thin option is specified");
480 auto *UO
= cast
<MachOUniversalBinary
>(InputBinaries
.front().getBinary());
481 Expected
<std::unique_ptr
<MachOObjectFile
>> Obj
=
482 UO
->getMachOObjectForArch(ArchType
);
483 Expected
<std::unique_ptr
<IRObjectFile
>> IRObj
=
484 UO
->getIRObjectForArch(ArchType
, LLVMCtx
);
485 Expected
<std::unique_ptr
<Archive
>> Ar
= UO
->getArchiveForArch(ArchType
);
486 if (!Obj
&& !IRObj
&& !Ar
)
487 reportError("fat input file " + UO
->getFileName() +
488 " does not contain the specified architecture " + ArchType
+
491 // Order here is important, because both Obj and IRObj will be valid with a
492 // binary that has embedded bitcode.
500 Expected
<std::unique_ptr
<FileOutputBuffer
>> OutFileOrError
=
501 FileOutputBuffer::create(OutputFileName
,
502 B
->getMemoryBufferRef().getBufferSize(),
503 sys::fs::can_execute(UO
->getFileName())
504 ? FileOutputBuffer::F_executable
507 reportError(OutputFileName
, OutFileOrError
.takeError());
508 std::copy(B
->getMemoryBufferRef().getBufferStart(),
509 B
->getMemoryBufferRef().getBufferEnd(),
510 OutFileOrError
.get()->getBufferStart());
511 if (Error E
= OutFileOrError
.get()->commit())
512 reportError(OutputFileName
, std::move(E
));
516 static void checkArchDuplicates(ArrayRef
<Slice
> Slices
) {
517 DenseMap
<uint64_t, const Binary
*> CPUIds
;
518 for (const auto &S
: Slices
) {
519 auto Entry
= CPUIds
.try_emplace(S
.getCPUID(), S
.getBinary());
521 reportError(Entry
.first
->second
->getFileName() + " and " +
522 S
.getBinary()->getFileName() +
523 " have the same architecture " + S
.getArchString() +
524 " and therefore cannot be in the same universal binary");
528 template <typename Range
>
529 static void updateAlignments(Range
&Slices
,
530 const StringMap
<const uint32_t> &Alignments
) {
531 for (auto &Slice
: Slices
) {
532 auto Alignment
= Alignments
.find(Slice
.getArchString());
533 if (Alignment
!= Alignments
.end())
534 Slice
.setP2Alignment(Alignment
->second
);
538 static void checkUnusedAlignments(ArrayRef
<Slice
> Slices
,
539 const StringMap
<const uint32_t> &Alignments
) {
540 auto HasArch
= [&](StringRef Arch
) {
541 return llvm::any_of(Slices
,
542 [Arch
](Slice S
) { return S
.getArchString() == Arch
; });
544 for (StringRef Arch
: Alignments
.keys())
546 reportError("-segalign " + Arch
+
547 " <value> specified but resulting fat file does not contain "
548 "that architecture ");
551 // Updates vector ExtractedObjects with the MachOObjectFiles extracted from
552 // Universal Binary files to transfer ownership.
553 static SmallVector
<Slice
, 2>
554 buildSlices(LLVMContext
&LLVMCtx
, ArrayRef
<OwningBinary
<Binary
>> InputBinaries
,
555 const StringMap
<const uint32_t> &Alignments
,
556 SmallVectorImpl
<std::unique_ptr
<SymbolicFile
>> &ExtractedObjects
) {
557 SmallVector
<Slice
, 2> Slices
;
558 for (auto &IB
: InputBinaries
) {
559 const Binary
*InputBinary
= IB
.getBinary();
560 if (auto UO
= dyn_cast
<MachOUniversalBinary
>(InputBinary
)) {
561 for (const auto &O
: UO
->objects()) {
562 // Order here is important, because both MachOObjectFile and
563 // IRObjectFile can be created with a binary that has embedded bitcode.
564 Expected
<std::unique_ptr
<MachOObjectFile
>> BinaryOrError
=
567 Slices
.emplace_back(*(BinaryOrError
.get()), O
.getAlign());
568 ExtractedObjects
.push_back(std::move(BinaryOrError
.get()));
571 Expected
<std::unique_ptr
<IRObjectFile
>> IROrError
=
572 O
.getAsIRObject(LLVMCtx
);
574 consumeError(BinaryOrError
.takeError());
575 Slice S
= createSliceFromIR(**IROrError
, O
.getAlign());
576 ExtractedObjects
.emplace_back(std::move(IROrError
.get()));
577 Slices
.emplace_back(std::move(S
));
580 reportError(InputBinary
->getFileName(), BinaryOrError
.takeError());
582 } else if (const auto *O
= dyn_cast
<MachOObjectFile
>(InputBinary
)) {
583 Slices
.emplace_back(*O
);
584 } else if (const auto *A
= dyn_cast
<Archive
>(InputBinary
)) {
585 Slices
.push_back(createSliceFromArchive(LLVMCtx
, *A
));
586 } else if (const auto *IRO
= dyn_cast
<IRObjectFile
>(InputBinary
)) {
587 // Original Apple's lipo set the alignment to 0
588 Expected
<Slice
> SliceOrErr
= Slice::create(*IRO
, 0);
590 reportError(InputBinary
->getFileName(), SliceOrErr
.takeError());
593 Slices
.emplace_back(std::move(SliceOrErr
.get()));
595 llvm_unreachable("Unexpected binary format");
598 updateAlignments(Slices
, Alignments
);
602 [[noreturn
]] static void
603 createUniversalBinary(LLVMContext
&LLVMCtx
,
604 ArrayRef
<OwningBinary
<Binary
>> InputBinaries
,
605 const StringMap
<const uint32_t> &Alignments
,
606 StringRef OutputFileName
, FatHeaderType HeaderType
) {
607 assert(InputBinaries
.size() >= 1 && "Incorrect number of input binaries");
608 assert(!OutputFileName
.empty() && "Create expects a single output file");
610 SmallVector
<std::unique_ptr
<SymbolicFile
>, 1> ExtractedObjects
;
611 SmallVector
<Slice
, 1> Slices
=
612 buildSlices(LLVMCtx
, InputBinaries
, Alignments
, ExtractedObjects
);
613 checkArchDuplicates(Slices
);
614 checkUnusedAlignments(Slices
, Alignments
);
616 llvm::stable_sort(Slices
);
617 if (Error E
= writeUniversalBinary(Slices
, OutputFileName
, HeaderType
))
618 reportError(std::move(E
));
623 [[noreturn
]] static void
624 extractSlice(LLVMContext
&LLVMCtx
, ArrayRef
<OwningBinary
<Binary
>> InputBinaries
,
625 const StringMap
<const uint32_t> &Alignments
, StringRef ArchType
,
626 StringRef OutputFileName
) {
627 assert(!ArchType
.empty() &&
628 "The architecture type should be non-empty");
629 assert(InputBinaries
.size() == 1 && "Incorrect number of input binaries");
630 assert(!OutputFileName
.empty() && "Thin expects a single output file");
632 if (InputBinaries
.front().getBinary()->isMachO()) {
633 reportError("input file " +
634 InputBinaries
.front().getBinary()->getFileName() +
635 " must be a fat file when the -extract option is specified");
638 SmallVector
<std::unique_ptr
<SymbolicFile
>, 2> ExtractedObjects
;
639 SmallVector
<Slice
, 2> Slices
=
640 buildSlices(LLVMCtx
, InputBinaries
, Alignments
, ExtractedObjects
);
641 erase_if(Slices
, [ArchType
](const Slice
&S
) {
642 return ArchType
!= S
.getArchString();
647 "fat input file " + InputBinaries
.front().getBinary()->getFileName() +
648 " does not contain the specified architecture " + ArchType
);
650 llvm::stable_sort(Slices
);
651 if (Error E
= writeUniversalBinary(Slices
, OutputFileName
))
652 reportError(std::move(E
));
656 static StringMap
<Slice
>
657 buildReplacementSlices(ArrayRef
<OwningBinary
<Binary
>> ReplacementBinaries
,
658 const StringMap
<const uint32_t> &Alignments
) {
659 StringMap
<Slice
> Slices
;
660 // populates StringMap of slices to replace with; error checks for mismatched
661 // replace flag args, fat files, and duplicate arch_types
662 for (const auto &OB
: ReplacementBinaries
) {
663 const Binary
*ReplacementBinary
= OB
.getBinary();
664 auto O
= dyn_cast
<MachOObjectFile
>(ReplacementBinary
);
666 reportError("replacement file: " + ReplacementBinary
->getFileName() +
667 " is a fat file (must be a thin file)");
669 auto Entry
= Slices
.try_emplace(S
.getArchString(), S
);
671 reportError("-replace " + S
.getArchString() +
672 " <file_name> specified multiple times: " +
673 Entry
.first
->second
.getBinary()->getFileName() + ", " +
676 auto SlicesMapRange
= map_range(
677 Slices
, [](StringMapEntry
<Slice
> &E
) -> Slice
& { return E
.getValue(); });
678 updateAlignments(SlicesMapRange
, Alignments
);
682 [[noreturn
]] static void
683 replaceSlices(LLVMContext
&LLVMCtx
,
684 ArrayRef
<OwningBinary
<Binary
>> InputBinaries
,
685 const StringMap
<const uint32_t> &Alignments
,
686 StringRef OutputFileName
, ArrayRef
<InputFile
> ReplacementFiles
) {
687 assert(InputBinaries
.size() == 1 && "Incorrect number of input binaries");
688 assert(!OutputFileName
.empty() && "Replace expects a single output file");
690 if (InputBinaries
.front().getBinary()->isMachO())
691 reportError("input file " +
692 InputBinaries
.front().getBinary()->getFileName() +
693 " must be a fat file when the -replace option is specified");
695 SmallVector
<OwningBinary
<Binary
>, 1> ReplacementBinaries
=
696 readInputBinaries(LLVMCtx
, ReplacementFiles
);
698 StringMap
<Slice
> ReplacementSlices
=
699 buildReplacementSlices(ReplacementBinaries
, Alignments
);
700 SmallVector
<std::unique_ptr
<SymbolicFile
>, 2> ExtractedObjects
;
701 SmallVector
<Slice
, 2> Slices
=
702 buildSlices(LLVMCtx
, InputBinaries
, Alignments
, ExtractedObjects
);
704 for (auto &Slice
: Slices
) {
705 auto It
= ReplacementSlices
.find(Slice
.getArchString());
706 if (It
!= ReplacementSlices
.end()) {
708 ReplacementSlices
.erase(It
); // only keep remaining replacing arch_types
712 if (!ReplacementSlices
.empty())
713 reportError("-replace " + ReplacementSlices
.begin()->first() +
714 " <file_name> specified but fat file: " +
715 InputBinaries
.front().getBinary()->getFileName() +
716 " does not contain that architecture");
718 checkUnusedAlignments(Slices
, Alignments
);
720 llvm::stable_sort(Slices
);
721 if (Error E
= writeUniversalBinary(Slices
, OutputFileName
))
722 reportError(std::move(E
));
726 int llvm_lipo_main(int argc
, char **argv
, const llvm::ToolContext
&) {
727 InitLLVM
X(argc
, argv
);
728 llvm::InitializeAllTargetInfos();
729 llvm::InitializeAllTargetMCs();
730 llvm::InitializeAllAsmParsers();
732 Config C
= parseLipoOptions(ArrayRef(argv
+ 1, argc
- 1));
734 SmallVector
<OwningBinary
<Binary
>, 1> InputBinaries
=
735 readInputBinaries(LLVMCtx
, C
.InputFiles
);
737 switch (C
.ActionToPerform
) {
738 case LipoAction::VerifyArch
:
739 verifyArch(InputBinaries
, C
.VerifyArchList
);
741 case LipoAction::PrintArchs
:
742 printArchs(LLVMCtx
, InputBinaries
);
744 case LipoAction::PrintInfo
:
745 printInfo(LLVMCtx
, InputBinaries
);
747 case LipoAction::ThinArch
:
748 thinSlice(LLVMCtx
, InputBinaries
, C
.ArchType
, C
.OutputFile
);
750 case LipoAction::ExtractArch
:
751 extractSlice(LLVMCtx
, InputBinaries
, C
.SegmentAlignments
, C
.ArchType
,
754 case LipoAction::CreateUniversal
:
755 createUniversalBinary(
756 LLVMCtx
, InputBinaries
, C
.SegmentAlignments
, C
.OutputFile
,
757 C
.UseFat64
? FatHeaderType::Fat64Header
: FatHeaderType::FatHeader
);
759 case LipoAction::ReplaceArch
:
760 replaceSlices(LLVMCtx
, InputBinaries
, C
.SegmentAlignments
, C
.OutputFile
,