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
;
121 static Slice
createSliceFromArchive(LLVMContext
&LLVMCtx
, const Archive
&A
) {
122 Expected
<Slice
> ArchiveOrSlice
= Slice::create(A
, &LLVMCtx
);
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
);
131 reportError(IRO
.getFileName(), IROrErr
.takeError());
137 static void validateArchitectureName(StringRef ArchitectureName
) {
138 if (!MachOObjectFile::isValidArch(ArchitectureName
)) {
140 raw_string_ostream
OS(Buf
);
141 OS
<< "Invalid architecture: " << ArchitectureName
142 << "\nValid architecture names are:";
143 for (auto arch
: MachOObjectFile::getValidArchs())
145 reportError(OS
.str());
149 static Config
parseLipoOptions(ArrayRef
<const char *> ArgsArr
) {
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
)) +
161 if (InputArgs
.size() == 0) {
162 // printHelp does not accept Twine.
163 T
.printHelp(errs(), "llvm-lipo input[s] option[s]", "llvm-lipo");
167 if (InputArgs
.hasArg(LIPO_help
)) {
168 // printHelp does not accept Twine.
169 T
.printHelp(outs(), "llvm-lipo input[s] option[s]", "llvm-lipo");
173 if (InputArgs
.hasArg(LIPO_version
)) {
174 outs() << ToolName
+ "\n";
175 cl::PrintVersionMessage();
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
)
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
));
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 &&
235 static_cast<size_t>(std::distance(ReplacementArgsRange
.begin(),
236 ReplacementArgsRange
.end()))) {
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())
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
;
258 if (C
.InputFiles
.size() > 1)
259 reportError("archs expects a single input file");
260 C
.ActionToPerform
= LipoAction::PrintArchs
;
264 C
.ActionToPerform
= LipoAction::PrintInfo
;
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
;
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
;
288 if (C
.OutputFile
.empty())
289 reportError("create expects a single output file to be specified");
290 C
.ActionToPerform
= LipoAction::CreateUniversal
;
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
;
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
);
320 reportError(IF
.FileName
, BinaryOrErr
.takeError());
321 const Binary
*B
= BinaryOrErr
->getBinary();
322 if (!B
->isArchive() && !B
->isMachO() && !B
->isMachOUniversalBinary() &&
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
))
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()))
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
);
358 dyn_cast
<MachOUniversalBinary
>(InputBinaries
.front().getBinary())) {
359 for (StringRef Arch
: VerifyArchList
) {
360 Expected
<MachOUniversalBinary::ObjectForArch
> Obj
=
361 UO
->getObjectForArch(Arch
);
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())
372 llvm_unreachable("Unexpected binary format");
377 static void printBinaryArchs(LLVMContext
&LLVMCtx
, const Binary
*Binary
,
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
=
386 if (MachOObjOrError
) {
387 OS
<< Slice(*(MachOObjOrError
->get())).getArchString() << " ";
390 Expected
<std::unique_ptr
<IRObjectFile
>> IROrError
=
391 O
.getAsIRObject(LLVMCtx
);
393 consumeError(MachOObjOrError
.takeError());
394 Expected
<Slice
> SliceOrErr
= Slice::create(**IROrError
, O
.getAlign());
396 reportError(Binary
->getFileName(), SliceOrErr
.takeError());
399 OS
<< SliceOrErr
.get().getArchString() << " ";
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()
410 consumeError(ArchiveOrError
.takeError());
411 reportError(Binary
->getFileName(), MachOObjOrError
.takeError());
412 reportError(Binary
->getFileName(), IROrError
.takeError());
418 if (const auto *MachO
= dyn_cast
<MachOObjectFile
>(Binary
)) {
419 OS
<< Slice(*MachO
).getArchString() << " \n";
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);
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());
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()
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());
462 [[noreturn
]] static void thinSlice(LLVMContext
&LLVMCtx
,
463 ArrayRef
<OwningBinary
<Binary
>> InputBinaries
,
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");
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
+
488 // Order here is important, because both Obj and IRObj will be valid with a
489 // binary that has embedded bitcode.
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
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
));
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());
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())
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
=
564 Slices
.emplace_back(*(BinaryOrError
.get()), O
.getAlign());
565 ExtractedObjects
.push_back(std::move(BinaryOrError
.get()));
568 Expected
<std::unique_ptr
<IRObjectFile
>> IROrError
=
569 O
.getAsIRObject(LLVMCtx
);
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
));
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);
587 reportError(InputBinary
->getFileName(), SliceOrErr
.takeError());
590 Slices
.emplace_back(std::move(SliceOrErr
.get()));
592 llvm_unreachable("Unexpected binary format");
595 updateAlignments(Slices
, Alignments
);
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
));
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();
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
));
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
);
661 reportError("replacement file: " + ReplacementBinary
->getFileName() +
662 " is a fat file (must be a thin file)");
664 auto Entry
= Slices
.try_emplace(S
.getArchString(), S
);
666 reportError("-replace " + S
.getArchString() +
667 " <file_name> specified multiple times: " +
668 Entry
.first
->second
.getBinary()->getFileName() + ", " +
671 auto SlicesMapRange
= map_range(
672 Slices
, [](StringMapEntry
<Slice
> &E
) -> Slice
& { return E
.getValue(); });
673 updateAlignments(SlicesMapRange
, Alignments
);
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()) {
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
));
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));
729 SmallVector
<OwningBinary
<Binary
>, 1> InputBinaries
=
730 readInputBinaries(LLVMCtx
, C
.InputFiles
);
732 switch (C
.ActionToPerform
) {
733 case LipoAction::VerifyArch
:
734 verifyArch(InputBinaries
, C
.VerifyArchList
);
736 case LipoAction::PrintArchs
:
737 printArchs(LLVMCtx
, InputBinaries
);
739 case LipoAction::PrintInfo
:
740 printInfo(LLVMCtx
, InputBinaries
);
742 case LipoAction::ThinArch
:
743 thinSlice(LLVMCtx
, InputBinaries
, C
.ArchType
, C
.OutputFile
);
745 case LipoAction::ExtractArch
:
746 extractSlice(LLVMCtx
, InputBinaries
, C
.SegmentAlignments
, C
.ArchType
,
749 case LipoAction::CreateUniversal
:
750 createUniversalBinary(LLVMCtx
, InputBinaries
, C
.SegmentAlignments
,
753 case LipoAction::ReplaceArch
:
754 replaceSlices(LLVMCtx
, InputBinaries
, C
.SegmentAlignments
, C
.OutputFile
,