Please use GitHub pull requests for new patches. Avoid migrating existing patches. Phabricator shutdown timeline
Changeset View
Changeset View
Standalone View
Standalone View
llvm/tools/llvm-lipo/llvm-lipo.cpp
//===-- llvm-lipo.cpp - a tool for manipulating universal binaries --------===// | //===-- llvm-lipo.cpp - a tool for manipulating universal binaries --------===// | ||||
// | // | ||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||||
// See https://llvm.org/LICENSE.txt for license information. | // See https://llvm.org/LICENSE.txt for license information. | ||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||||
// | // | ||||
//===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// | ||||
// | // | ||||
// A utility for creating / splitting / inspecting universal binaries. | // A utility for creating / splitting / inspecting universal binaries. | ||||
// | // | ||||
//===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// | ||||
#include "llvm/ADT/STLExtras.h" | #include "llvm/ADT/STLExtras.h" | ||||
#include "llvm/ADT/Triple.h" | #include "llvm/ADT/Triple.h" | ||||
#include "llvm/BinaryFormat/MachO.h" | |||||
#include "llvm/IR/LLVMContext.h" | |||||
#include "llvm/IR/Module.h" | |||||
#include "llvm/Object/Binary.h" | #include "llvm/Object/Binary.h" | ||||
#include "llvm/Object/IRObjectFile.h" | |||||
#include "llvm/Object/MachO.h" | #include "llvm/Object/MachO.h" | ||||
#include "llvm/Object/MachOUniversal.h" | #include "llvm/Object/MachOUniversal.h" | ||||
#include "llvm/Object/MachOUniversalWriter.h" | #include "llvm/Object/MachOUniversalWriter.h" | ||||
#include "llvm/Object/ObjectFile.h" | #include "llvm/Object/ObjectFile.h" | ||||
#include "llvm/Option/Arg.h" | #include "llvm/Option/Arg.h" | ||||
#include "llvm/Option/ArgList.h" | #include "llvm/Option/ArgList.h" | ||||
#include "llvm/Support/CommandLine.h" | #include "llvm/Support/CommandLine.h" | ||||
#include "llvm/Support/Error.h" | #include "llvm/Support/Error.h" | ||||
#include "llvm/Support/FileOutputBuffer.h" | #include "llvm/Support/FileOutputBuffer.h" | ||||
#include "llvm/Support/InitLLVM.h" | #include "llvm/Support/InitLLVM.h" | ||||
#include "llvm/Support/WithColor.h" | #include "llvm/Support/WithColor.h" | ||||
#include "llvm/TextAPI/MachO/Architecture.h" | #include "llvm/TextAPI/MachO/Architecture.h" | ||||
using namespace llvm; | using namespace llvm; | ||||
alexander-shaposhnikov: nit: these includes need to be moved up (if i remember correctly we usually try to sort… | |||||
using namespace llvm::object; | using namespace llvm::object; | ||||
static const StringRef ToolName = "llvm-lipo"; | static const StringRef ToolName = "llvm-lipo"; | ||||
static LLVMContext LLVMCtx; | |||||
LLVM_ATTRIBUTE_NORETURN static void reportError(Twine Message) { | LLVM_ATTRIBUTE_NORETURN static void reportError(Twine Message) { | ||||
WithColor::error(errs(), ToolName) << Message << "\n"; | WithColor::error(errs(), ToolName) << Message << "\n"; | ||||
errs().flush(); | errs().flush(); | ||||
exit(EXIT_FAILURE); | exit(EXIT_FAILURE); | ||||
} | } | ||||
LLVM_ATTRIBUTE_NORETURN static void reportError(Error E) { | LLVM_ATTRIBUTE_NORETURN static void reportError(Error E) { | ||||
▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | struct Config { | ||||
SmallVector<std::string, 1> VerifyArchList; | SmallVector<std::string, 1> VerifyArchList; | ||||
SmallVector<InputFile, 1> ReplacementFiles; | SmallVector<InputFile, 1> ReplacementFiles; | ||||
StringMap<const uint32_t> SegmentAlignments; | StringMap<const uint32_t> SegmentAlignments; | ||||
std::string ArchType; | std::string ArchType; | ||||
std::string OutputFile; | std::string OutputFile; | ||||
LipoAction ActionToPerform; | LipoAction ActionToPerform; | ||||
}; | }; | ||||
static Slice archiveSlice(const Archive *A, StringRef File) { | static Slice createSliceFromArchive(const Archive *A) { | ||||
Expected<Slice> ArchiveOrSlice = Slice::create(A); | Expected<Slice> ArchiveOrSlice = Slice::create(A, &LLVMCtx); | ||||
if (!ArchiveOrSlice) | if (!ArchiveOrSlice) | ||||
reportError(File, ArchiveOrSlice.takeError()); | reportError(A->getFileName(), ArchiveOrSlice.takeError()); | ||||
return *ArchiveOrSlice; | return *ArchiveOrSlice; | ||||
} | } | ||||
static Slice createSliceFromIR(const IRObjectFile *IRO, unsigned Align) { | |||||
what would you say to the following renaming: irSlice -> createSliceFromIR archiveSlice -> createSliceFromArchive alexander-shaposhnikov: what would you say to the following renaming:
irSlice -> createSliceFromIR
archiveSlice… | |||||
I'm wondering if we really need to pass the name of the file here - can't it be extracted from the first argument (IRO->getFileName()) ? (if yes - then probably it can be removed from archiveSlice as well) P.S. https://llvm.org/doxygen/MachOUniversal_8cpp_source.html#l00078 alexander-shaposhnikov: I'm wondering if we really need to pass the name of the file here - can't it be extracted from… | |||||
Probably. I will test and let you know :) No problem for me for the renaming you propose, will put it in the new diff. aguinet: Probably. I will test and let you know :)
No problem for me for the renaming you propose, will… | |||||
Expected<Slice> IROrErr = Slice::create(IRO, Align); | |||||
if (!IROrErr) | |||||
reportError(IRO->getFileName(), IROrErr.takeError()); | |||||
return *IROrErr; | |||||
} | |||||
} // end namespace | } // end namespace | ||||
static void validateArchitectureName(StringRef ArchitectureName) { | static void validateArchitectureName(StringRef ArchitectureName) { | ||||
if (!MachOObjectFile::isValidArch(ArchitectureName)) { | if (!MachOObjectFile::isValidArch(ArchitectureName)) { | ||||
std::string Buf; | std::string Buf; | ||||
raw_string_ostream OS(Buf); | raw_string_ostream OS(Buf); | ||||
OS << "Invalid architecture: " << ArchitectureName | OS << "Invalid architecture: " << ArchitectureName | ||||
<< "\nValid architecture names are:"; | << "\nValid architecture names are:"; | ||||
▲ Show 20 Lines • Show All 171 Lines • ▼ Show 20 Lines | default: | ||||
reportError("llvm-lipo action unspecified"); | reportError("llvm-lipo action unspecified"); | ||||
} | } | ||||
} | } | ||||
static SmallVector<OwningBinary<Binary>, 1> | static SmallVector<OwningBinary<Binary>, 1> | ||||
readInputBinaries(ArrayRef<InputFile> InputFiles) { | readInputBinaries(ArrayRef<InputFile> InputFiles) { | ||||
SmallVector<OwningBinary<Binary>, 1> InputBinaries; | SmallVector<OwningBinary<Binary>, 1> InputBinaries; | ||||
for (const InputFile &IF : InputFiles) { | for (const InputFile &IF : InputFiles) { | ||||
Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(IF.FileName); | Expected<OwningBinary<Binary>> BinaryOrErr = | ||||
createBinary(IF.FileName, &LLVMCtx); | |||||
if (!BinaryOrErr) | if (!BinaryOrErr) | ||||
reportError(IF.FileName, BinaryOrErr.takeError()); | reportError(IF.FileName, BinaryOrErr.takeError()); | ||||
const Binary *B = BinaryOrErr->getBinary(); | const Binary *B = BinaryOrErr->getBinary(); | ||||
if (!B->isArchive() && !B->isMachO() && !B->isMachOUniversalBinary()) | if (!B->isArchive() && !B->isMachO() && !B->isMachOUniversalBinary() && | ||||
!B->isIR()) | |||||
reportError("File " + IF.FileName + " has unsupported binary format"); | reportError("File " + IF.FileName + " has unsupported binary format"); | ||||
if (IF.ArchType && (B->isMachO() || B->isArchive())) { | if (IF.ArchType && (B->isMachO() || B->isArchive() || B->isIR())) { | ||||
const auto S = B->isMachO() ? Slice(*cast<MachOObjectFile>(B)) | const auto S = B->isMachO() | ||||
: archiveSlice(cast<Archive>(B), IF.FileName); | ? Slice(*cast<MachOObjectFile>(B)) | ||||
: B->isArchive() | |||||
? createSliceFromArchive(cast<Archive>(B)) | |||||
: createSliceFromIR(cast<IRObjectFile>(B), 0); | |||||
const auto SpecifiedCPUType = MachO::getCPUTypeFromArchitecture( | const auto SpecifiedCPUType = MachO::getCPUTypeFromArchitecture( | ||||
MachO::getArchitectureFromName( | MachO::getArchitectureFromName( | ||||
Triple(*IF.ArchType).getArchName())) | Triple(*IF.ArchType).getArchName())) | ||||
.first; | .first; | ||||
// For compatibility with cctools' lipo the comparison is relaxed just to | // For compatibility with cctools' lipo the comparison is relaxed just to | ||||
// checking cputypes. | // checking cputypes. | ||||
if (S.getCPUType() != SpecifiedCPUType) | if (S.getCPUType() != SpecifiedCPUType) | ||||
reportError("specified architecture: " + *IF.ArchType + | reportError("specified architecture: " + *IF.ArchType + | ||||
Show All 35 Lines | static void verifyArch(ArrayRef<OwningBinary<Binary>> InputBinaries, | ||||
} | } | ||||
exit(EXIT_SUCCESS); | exit(EXIT_SUCCESS); | ||||
} | } | ||||
static void printBinaryArchs(const Binary *Binary, raw_ostream &OS) { | static void printBinaryArchs(const Binary *Binary, raw_ostream &OS) { | ||||
// Prints trailing space for compatibility with cctools lipo. | // Prints trailing space for compatibility with cctools lipo. | ||||
if (auto UO = dyn_cast<MachOUniversalBinary>(Binary)) { | if (auto UO = dyn_cast<MachOUniversalBinary>(Binary)) { | ||||
for (const auto &O : UO->objects()) { | for (const auto &O : UO->objects()) { | ||||
// Order here is important, because both MachOObjectFile and | |||||
// IRObjectFile can be created with a binary that has embedded bitcode. | |||||
Expected<std::unique_ptr<MachOObjectFile>> MachOObjOrError = | Expected<std::unique_ptr<MachOObjectFile>> MachOObjOrError = | ||||
O.getAsObjectFile(); | O.getAsObjectFile(); | ||||
if (MachOObjOrError) { | if (MachOObjOrError) { | ||||
OS << Slice(*(MachOObjOrError->get())).getArchString() << " "; | OS << Slice(*(MachOObjOrError->get())).getArchString() << " "; | ||||
continue; | continue; | ||||
} | } | ||||
Expected<std::unique_ptr<IRObjectFile>> IROrError = | |||||
O.getAsIRObject(LLVMCtx); | |||||
if (IROrError) { | |||||
consumeError(MachOObjOrError.takeError()); | |||||
Expected<Slice> SliceOrErr = | |||||
nit: explicit type alexander-shaposhnikov: nit: explicit type | |||||
Slice::create(IROrError->get(), O.getAlign()); | |||||
if (!SliceOrErr) { | |||||
reportError(Binary->getFileName(), SliceOrErr.takeError()); | |||||
continue; | |||||
} | |||||
OS << SliceOrErr.get().getArchString() << " "; | |||||
continue; | |||||
} | |||||
Expected<std::unique_ptr<Archive>> ArchiveOrError = O.getAsArchive(); | Expected<std::unique_ptr<Archive>> ArchiveOrError = O.getAsArchive(); | ||||
if (ArchiveOrError) { | if (ArchiveOrError) { | ||||
consumeError(MachOObjOrError.takeError()); | consumeError(MachOObjOrError.takeError()); | ||||
OS << archiveSlice(ArchiveOrError->get(), Binary->getFileName()) | consumeError(IROrError.takeError()); | ||||
.getArchString() | OS << createSliceFromArchive(ArchiveOrError->get()).getArchString() | ||||
<< " "; | << " "; | ||||
continue; | continue; | ||||
} | } | ||||
consumeError(ArchiveOrError.takeError()); | consumeError(ArchiveOrError.takeError()); | ||||
reportError(Binary->getFileName(), MachOObjOrError.takeError()); | reportError(Binary->getFileName(), MachOObjOrError.takeError()); | ||||
reportError(Binary->getFileName(), IROrError.takeError()); | |||||
} | } | ||||
OS << "\n"; | OS << "\n"; | ||||
return; | return; | ||||
} | } | ||||
OS << Slice(*cast<MachOObjectFile>(Binary)).getArchString() << " \n"; | |||||
if (const auto *MachO = dyn_cast<MachOObjectFile>(Binary)) { | |||||
OS << Slice(*MachO).getArchString() << " \n"; | |||||
return; | |||||
} | |||||
// This should be always the case, as this is tested in readInputBinaries | |||||
const auto *IR = cast<IRObjectFile>(Binary); | |||||
Expected<Slice> SliceOrErr = createSliceFromIR(IR, 0); | |||||
if (!SliceOrErr) | |||||
reportError(IR->getFileName(), SliceOrErr.takeError()); | |||||
OS << SliceOrErr->getArchString() << " \n"; | |||||
} | } | ||||
LLVM_ATTRIBUTE_NORETURN | LLVM_ATTRIBUTE_NORETURN | ||||
static void printArchs(ArrayRef<OwningBinary<Binary>> InputBinaries) { | static void printArchs(ArrayRef<OwningBinary<Binary>> InputBinaries) { | ||||
assert(InputBinaries.size() == 1 && "Incorrect number of input binaries"); | assert(InputBinaries.size() == 1 && "Incorrect number of input binaries"); | ||||
printBinaryArchs(InputBinaries.front().getBinary(), outs()); | printBinaryArchs(InputBinaries.front().getBinary(), outs()); | ||||
exit(EXIT_SUCCESS); | exit(EXIT_SUCCESS); | ||||
} | } | ||||
Show All 33 Lines | reportError("input file " + | ||||
InputBinaries.front().getBinary()->getFileName() + | InputBinaries.front().getBinary()->getFileName() + | ||||
" must be a fat file when the -thin option is specified"); | " must be a fat file when the -thin option is specified"); | ||||
exit(EXIT_FAILURE); | exit(EXIT_FAILURE); | ||||
} | } | ||||
auto *UO = cast<MachOUniversalBinary>(InputBinaries.front().getBinary()); | auto *UO = cast<MachOUniversalBinary>(InputBinaries.front().getBinary()); | ||||
Expected<std::unique_ptr<MachOObjectFile>> Obj = | Expected<std::unique_ptr<MachOObjectFile>> Obj = | ||||
UO->getMachOObjectForArch(ArchType); | UO->getMachOObjectForArch(ArchType); | ||||
Expected<std::unique_ptr<IRObjectFile>> IRObj = | |||||
UO->getIRObjectForArch(ArchType, LLVMCtx); | |||||
Expected<std::unique_ptr<Archive>> Ar = UO->getArchiveForArch(ArchType); | Expected<std::unique_ptr<Archive>> Ar = UO->getArchiveForArch(ArchType); | ||||
if (!Obj && !Ar) | if (!Obj && !IRObj && !Ar) | ||||
reportError("fat input file " + UO->getFileName() + | reportError("fat input file " + UO->getFileName() + | ||||
" does not contain the specified architecture " + ArchType + | " does not contain the specified architecture " + ArchType + | ||||
" to thin it to"); | " to thin it to"); | ||||
Binary *B = Obj ? static_cast<Binary *>(Obj->get()) | Binary *B; | ||||
: static_cast<Binary *>(Ar->get()); | // Order here is important, because both Obj and IRObj will be valid with a | ||||
// binary that has embedded bitcode. | |||||
if (Obj) | |||||
B = Obj->get(); | |||||
else if (IRObj) | |||||
B = IRObj->get(); | |||||
else | |||||
B = Ar->get(); | |||||
Expected<std::unique_ptr<FileOutputBuffer>> OutFileOrError = | Expected<std::unique_ptr<FileOutputBuffer>> OutFileOrError = | ||||
FileOutputBuffer::create(OutputFileName, | FileOutputBuffer::create(OutputFileName, | ||||
B->getMemoryBufferRef().getBufferSize(), | B->getMemoryBufferRef().getBufferSize(), | ||||
sys::fs::can_execute(UO->getFileName()) | sys::fs::can_execute(UO->getFileName()) | ||||
? FileOutputBuffer::F_executable | ? FileOutputBuffer::F_executable | ||||
: 0); | : 0); | ||||
if (!OutFileOrError) | if (!OutFileOrError) | ||||
reportError(OutputFileName, OutFileOrError.takeError()); | reportError(OutputFileName, OutFileOrError.takeError()); | ||||
Show All 38 Lines | for (StringRef Arch : Alignments.keys()) | ||||
if (!HasArch(Arch)) | if (!HasArch(Arch)) | ||||
reportError("-segalign " + Arch + | reportError("-segalign " + Arch + | ||||
" <value> specified but resulting fat file does not contain " | " <value> specified but resulting fat file does not contain " | ||||
"that architecture "); | "that architecture "); | ||||
} | } | ||||
// Updates vector ExtractedObjects with the MachOObjectFiles extracted from | // Updates vector ExtractedObjects with the MachOObjectFiles extracted from | ||||
// Universal Binary files to transfer ownership. | // Universal Binary files to transfer ownership. | ||||
static SmallVector<Slice, 2> buildSlices( | static SmallVector<Slice, 2> | ||||
ArrayRef<OwningBinary<Binary>> InputBinaries, | buildSlices(ArrayRef<OwningBinary<Binary>> InputBinaries, | ||||
const StringMap<const uint32_t> &Alignments, | const StringMap<const uint32_t> &Alignments, | ||||
SmallVectorImpl<std::unique_ptr<MachOObjectFile>> &ExtractedObjects) { | SmallVectorImpl<std::unique_ptr<SymbolicFile>> &ExtractedObjects) { | ||||
SmallVector<Slice, 2> Slices; | SmallVector<Slice, 2> Slices; | ||||
for (auto &IB : InputBinaries) { | for (auto &IB : InputBinaries) { | ||||
const Binary *InputBinary = IB.getBinary(); | const Binary *InputBinary = IB.getBinary(); | ||||
if (auto UO = dyn_cast<MachOUniversalBinary>(InputBinary)) { | if (auto UO = dyn_cast<MachOUniversalBinary>(InputBinary)) { | ||||
for (const auto &O : UO->objects()) { | for (const auto &O : UO->objects()) { | ||||
// Order here is important, because both MachOObjectFile and | |||||
// IRObjectFile can be created with a binary that has embedded bitcode. | |||||
Expected<std::unique_ptr<MachOObjectFile>> BinaryOrError = | Expected<std::unique_ptr<MachOObjectFile>> BinaryOrError = | ||||
O.getAsObjectFile(); | O.getAsObjectFile(); | ||||
if (!BinaryOrError) | if (BinaryOrError) { | ||||
reportError(InputBinary->getFileName(), BinaryOrError.takeError()); | Slices.emplace_back(*(BinaryOrError.get()), O.getAlign()); | ||||
ExtractedObjects.push_back(std::move(BinaryOrError.get())); | ExtractedObjects.push_back(std::move(BinaryOrError.get())); | ||||
Slices.emplace_back(*(ExtractedObjects.back().get()), O.getAlign()); | continue; | ||||
} | |||||
Expected<std::unique_ptr<IRObjectFile>> IROrError = | |||||
O.getAsIRObject(LLVMCtx); | |||||
if (IROrError) { | |||||
consumeError(BinaryOrError.takeError()); | |||||
Slice S = createSliceFromIR( | |||||
nit: explicit type alexander-shaposhnikov: nit: explicit type | |||||
static_cast<IRObjectFile *>(IROrError.get().get()), O.getAlign()); | |||||
ExtractedObjects.emplace_back(std::move(IROrError.get())); | |||||
Slices.emplace_back(std::move(S)); | |||||
continue; | |||||
} | |||||
reportError(InputBinary->getFileName(), BinaryOrError.takeError()); | |||||
} | } | ||||
} else if (auto O = dyn_cast<MachOObjectFile>(InputBinary)) { | } else if (auto O = dyn_cast<MachOObjectFile>(InputBinary)) { | ||||
Slices.emplace_back(*O); | Slices.emplace_back(*O); | ||||
} else if (auto A = dyn_cast<Archive>(InputBinary)) { | } else if (auto A = dyn_cast<Archive>(InputBinary)) { | ||||
Slices.push_back(archiveSlice(A, InputBinary->getFileName())); | Slices.push_back(createSliceFromArchive(A)); | ||||
} else if (const auto *IRO = dyn_cast<IRObjectFile>(InputBinary)) { | |||||
// Original Apple's lipo set the alignment to 0 | |||||
Expected<Slice> SliceOrErr = Slice::create(IRO, 0); | |||||
nit: explicit type alexander-shaposhnikov: nit: explicit type | |||||
if (!SliceOrErr) { | |||||
reportError(InputBinary->getFileName(), SliceOrErr.takeError()); | |||||
continue; | |||||
} | |||||
Slices.emplace_back(std::move(SliceOrErr.get())); | |||||
} else { | } else { | ||||
llvm_unreachable("Unexpected binary format"); | llvm_unreachable("Unexpected binary format"); | ||||
} | } | ||||
} | } | ||||
updateAlignments(Slices, Alignments); | updateAlignments(Slices, Alignments); | ||||
return Slices; | return Slices; | ||||
} | } | ||||
LLVM_ATTRIBUTE_NORETURN | LLVM_ATTRIBUTE_NORETURN | ||||
static void createUniversalBinary(ArrayRef<OwningBinary<Binary>> InputBinaries, | static void createUniversalBinary(ArrayRef<OwningBinary<Binary>> InputBinaries, | ||||
const StringMap<const uint32_t> &Alignments, | const StringMap<const uint32_t> &Alignments, | ||||
StringRef OutputFileName) { | StringRef OutputFileName) { | ||||
assert(InputBinaries.size() >= 1 && "Incorrect number of input binaries"); | assert(InputBinaries.size() >= 1 && "Incorrect number of input binaries"); | ||||
assert(!OutputFileName.empty() && "Create expects a single output file"); | assert(!OutputFileName.empty() && "Create expects a single output file"); | ||||
SmallVector<std::unique_ptr<MachOObjectFile>, 1> ExtractedObjects; | SmallVector<std::unique_ptr<SymbolicFile>, 1> ExtractedObjects; | ||||
SmallVector<Slice, 1> Slices = | SmallVector<Slice, 1> Slices = | ||||
buildSlices(InputBinaries, Alignments, ExtractedObjects); | buildSlices(InputBinaries, Alignments, ExtractedObjects); | ||||
checkArchDuplicates(Slices); | checkArchDuplicates(Slices); | ||||
checkUnusedAlignments(Slices, Alignments); | checkUnusedAlignments(Slices, Alignments); | ||||
llvm::stable_sort(Slices); | llvm::stable_sort(Slices); | ||||
if (Error E = writeUniversalBinary(Slices, OutputFileName)) | if (Error E = writeUniversalBinary(Slices, OutputFileName)) | ||||
reportError(std::move(E)); | reportError(std::move(E)); | ||||
Show All 11 Lines | static void extractSlice(ArrayRef<OwningBinary<Binary>> InputBinaries, | ||||
assert(!OutputFileName.empty() && "Thin expects a single output file"); | assert(!OutputFileName.empty() && "Thin expects a single output file"); | ||||
if (InputBinaries.front().getBinary()->isMachO()) { | if (InputBinaries.front().getBinary()->isMachO()) { | ||||
reportError("input file " + | reportError("input file " + | ||||
InputBinaries.front().getBinary()->getFileName() + | InputBinaries.front().getBinary()->getFileName() + | ||||
" must be a fat file when the -extract option is specified"); | " must be a fat file when the -extract option is specified"); | ||||
} | } | ||||
SmallVector<std::unique_ptr<MachOObjectFile>, 2> ExtractedObjects; | SmallVector<std::unique_ptr<SymbolicFile>, 2> ExtractedObjects; | ||||
SmallVector<Slice, 2> Slices = | SmallVector<Slice, 2> Slices = | ||||
buildSlices(InputBinaries, Alignments, ExtractedObjects); | buildSlices(InputBinaries, Alignments, ExtractedObjects); | ||||
erase_if(Slices, [ArchType](const Slice &S) { | erase_if(Slices, [ArchType](const Slice &S) { | ||||
return ArchType != S.getArchString(); | return ArchType != S.getArchString(); | ||||
}); | }); | ||||
if (Slices.empty()) | if (Slices.empty()) | ||||
reportError( | reportError( | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | reportError("input file " + | ||||
InputBinaries.front().getBinary()->getFileName() + | InputBinaries.front().getBinary()->getFileName() + | ||||
" must be a fat file when the -replace option is specified"); | " must be a fat file when the -replace option is specified"); | ||||
SmallVector<OwningBinary<Binary>, 1> ReplacementBinaries = | SmallVector<OwningBinary<Binary>, 1> ReplacementBinaries = | ||||
readInputBinaries(ReplacementFiles); | readInputBinaries(ReplacementFiles); | ||||
StringMap<Slice> ReplacementSlices = | StringMap<Slice> ReplacementSlices = | ||||
buildReplacementSlices(ReplacementBinaries, Alignments); | buildReplacementSlices(ReplacementBinaries, Alignments); | ||||
SmallVector<std::unique_ptr<MachOObjectFile>, 2> ExtractedObjects; | SmallVector<std::unique_ptr<SymbolicFile>, 2> ExtractedObjects; | ||||
SmallVector<Slice, 2> Slices = | SmallVector<Slice, 2> Slices = | ||||
buildSlices(InputBinaries, Alignments, ExtractedObjects); | buildSlices(InputBinaries, Alignments, ExtractedObjects); | ||||
for (auto &Slice : Slices) { | for (auto &Slice : Slices) { | ||||
auto It = ReplacementSlices.find(Slice.getArchString()); | auto It = ReplacementSlices.find(Slice.getArchString()); | ||||
if (It != ReplacementSlices.end()) { | if (It != ReplacementSlices.end()) { | ||||
Slice = It->second; | Slice = It->second; | ||||
ReplacementSlices.erase(It); // only keep remaining replacing arch_types | ReplacementSlices.erase(It); // only keep remaining replacing arch_types | ||||
▲ Show 20 Lines • Show All 49 Lines • Show Last 20 Lines |
nit: these includes need to be moved up (if i remember correctly we usually try to sort includes alphabetically)