# RUN: not llvm-lipo %t-universal.o -replace %t-32.o 2>&1 | FileCheck --check-prefix=MISSING_ARG %s
# MISSING_ARG: error: replace is missing an argument: expects -replace arch_type file_name
-# RUN: not llvm-lipo %t-universal.o -replace %t-32.o i386 2>&1 | FileCheck --check-prefix=OUTPUT_FILE %s
+# RUN: not llvm-lipo %t-universal.o -replace i386 %t-32.o 2>&1 | FileCheck --check-prefix=OUTPUT_FILE %s
# OUTPUT_FILE: error: replace expects a single output file to be specified
-# RUN: not llvm-lipo %t-universal.o %t-universal.o -replace %t-32.o i386 -o %t.o 2>&1 | FileCheck --check-prefix=INPUT_ARGS %s
+# RUN: not llvm-lipo %t-universal.o %t-universal.o -replace i386 %t-32.o -o %t.o 2>&1 | FileCheck --check-prefix=INPUT_ARGS %s
# INPUT_ARGS: error: replace expects a single input file
-# RUN: not llvm-lipo %t-universal.o -replace %t-32.o i386 -o %t.o 2>&1 | FileCheck --check-prefix=INVALID_FILE %s
-# INVALID_FILE: error: 'i386': {{[nN]}}o such file or directory
+# RUN: not llvm-lipo %t-universal.o -replace i386 %t-33.o -o %t.o 2>&1 | FileCheck --check-prefix=INVALID_FILE %s
+# INVALID_FILE: {{[nN]}}o such file or directory
# RUN: not llvm-lipo %t-universal.o -replace i3866 %t-32.o -o %t.o 2>&1 | FileCheck --check-prefix=INVALID_ARCH %s
# INVALID_ARCH: error: Invalid architecture: i3866
# RUN: not llvm-lipo %t-universal.o -replace arm64 %t-32.o -o %t.o 2>&1 | FileCheck --check-prefix=ARCH_NOT_MATCHED %s
-# ARCH_NOT_MATCHED: error: specified architecture: arm64 for replacement file: {{.*}} does not match the file's architecture
+# ARCH_NOT_MATCHED: error: specified architecture: arm64 for file: {{.*}} does not match the file's architecture (i386)
# RUN: not llvm-lipo %t-universal.o -replace arm64 %t-arm64.o -o %t.o 2>&1 | FileCheck --check-prefix=ARCH_NOT_IN_INPUT %s
# ARCH_NOT_IN_INPUT: error: -replace arm64 <file_name> specified but fat file: {{.*}} does not contain that architecture
ReplaceArch,
};
-struct Replacement {
- StringRef ArchType;
+struct InputFile {
+ Optional<StringRef> ArchType;
StringRef FileName;
};
struct Config {
- SmallVector<std::string, 1> InputFiles;
+ SmallVector<InputFile, 1> InputFiles;
SmallVector<std::string, 1> VerifyArchList;
- SmallVector<Replacement, 1> Replacements;
+ SmallVector<InputFile, 1> ReplacementFiles;
StringMap<const uint32_t> SegmentAlignments;
std::string ThinArchType;
std::string OutputFile;
reportError("unknown argument '" + Arg->getAsString(InputArgs) + "'");
for (auto Arg : InputArgs.filtered(LIPO_INPUT))
- C.InputFiles.push_back(Arg->getValue());
+ C.InputFiles.push_back({None, Arg->getValue()});
+ for (auto Arg : InputArgs.filtered(LIPO_arch)) {
+ validateArchitectureName(Arg->getValue(0));
+ if (!Arg->getValue(1))
+ reportError(
+ "arch is missing an argument: expects -arch arch_type file_name");
+ C.InputFiles.push_back({StringRef(Arg->getValue(0)), Arg->getValue(1)});
+ }
+
if (C.InputFiles.empty())
reportError("at least one input file should be specified");
reportError(
"replace is missing an argument: expects -replace arch_type "
"file_name");
- C.Replacements.push_back(
- Replacement{Action->getValue(0), Action->getValue(1)});
+ validateArchitectureName(Action->getValue(0));
+ C.ReplacementFiles.push_back(
+ {StringRef(Action->getValue(0)), Action->getValue(1)});
}
if (C.OutputFile.empty())
}
static SmallVector<OwningBinary<Binary>, 1>
-readInputBinaries(ArrayRef<std::string> InputFiles) {
+readInputBinaries(ArrayRef<InputFile> InputFiles) {
SmallVector<OwningBinary<Binary>, 1> InputBinaries;
- for (StringRef InputFile : InputFiles) {
- Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(InputFile);
+ for (const InputFile &IF : InputFiles) {
+ Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(IF.FileName);
if (!BinaryOrErr)
- reportError(InputFile, BinaryOrErr.takeError());
- if (!BinaryOrErr->getBinary()->isArchive() &&
- !BinaryOrErr->getBinary()->isMachO() &&
- !BinaryOrErr->getBinary()->isMachOUniversalBinary())
- reportError("File " + InputFile + " has unsupported binary format");
+ reportError(IF.FileName, BinaryOrErr.takeError());
+ const Binary *B = BinaryOrErr->getBinary();
+ if (!B->isArchive() && !B->isMachO() && !B->isMachOUniversalBinary())
+ reportError("File " + IF.FileName + " has unsupported binary format");
+ if (IF.ArchType && (B->isMachO() || B->isArchive())) {
+ const auto ArchType =
+ B->isMachO() ? Slice(cast<MachOObjectFile>(B)).getArchString()
+ : Slice(cast<Archive>(B)).getArchString();
+ if (Triple(*IF.ArchType).getArch() != Triple(ArchType).getArch())
+ reportError("specified architecture: " + *IF.ArchType +
+ " for file: " + B->getFileName() +
+ " does not match the file's architecture (" + ArchType +
+ ")");
+ }
InputBinaries.push_back(std::move(*BinaryOrErr));
}
return InputBinaries;
static StringMap<Slice>
buildReplacementSlices(ArrayRef<OwningBinary<Binary>> ReplacementBinaries,
- const StringMap<const uint32_t> &Alignments,
- ArrayRef<Replacement> Replacements) {
- assert(ReplacementBinaries.size() == Replacements.size() &&
- "Number of replacment binaries does not match the number of "
- "replacements");
+ const StringMap<const uint32_t> &Alignments) {
StringMap<Slice> Slices;
// populates StringMap of slices to replace with; error checks for mismatched
// replace flag args, fat files, and duplicate arch_types
- for (size_t Index = 0, Size = Replacements.size(); Index < Size; ++Index) {
- StringRef ReplacementArch = Replacements[Index].ArchType;
- const Binary *ReplacementBinary = ReplacementBinaries[Index].getBinary();
- validateArchitectureName(ReplacementArch);
-
+ for (const auto &OB : ReplacementBinaries) {
+ const Binary *ReplacementBinary = OB.getBinary();
auto O = dyn_cast<MachOObjectFile>(ReplacementBinary);
if (!O)
reportError("replacement file: " + ReplacementBinary->getFileName() +
" is a fat file (must be a thin file)");
-
- if (O->getArch() != Triple(ReplacementArch).getArch())
- reportError("specified architecture: " + ReplacementArch +
- " for replacement file: " + ReplacementBinary->getFileName() +
- " does not match the file's architecture");
-
- auto Entry = Slices.try_emplace(ReplacementArch, Slice(O));
+ Slice S(O);
+ auto Entry = Slices.try_emplace(S.getArchString(), S);
if (!Entry.second)
- reportError("-replace " + ReplacementArch +
+ reportError("-replace " + S.getArchString() +
" <file_name> specified multiple times: " +
Entry.first->second.getBinary()->getFileName() + ", " +
O->getFileName());
static void replaceSlices(ArrayRef<OwningBinary<Binary>> InputBinaries,
const StringMap<const uint32_t> &Alignments,
StringRef OutputFileName,
- ArrayRef<Replacement> Replacements) {
+ ArrayRef<InputFile> ReplacementFiles) {
assert(InputBinaries.size() == 1 && "Incorrect number of input binaries");
assert(!OutputFileName.empty() && "Replace expects a single output file");
InputBinaries.front().getBinary()->getFileName() +
" must be a fat file when the -replace option is specified");
- SmallVector<std::string, 1> ReplacementFiles;
- for (const auto &R : Replacements)
- ReplacementFiles.push_back(R.FileName);
SmallVector<OwningBinary<Binary>, 1> ReplacementBinaries =
readInputBinaries(ReplacementFiles);
StringMap<Slice> ReplacementSlices =
- buildReplacementSlices(ReplacementBinaries, Alignments, Replacements);
+ buildReplacementSlices(ReplacementBinaries, Alignments);
SmallVector<std::unique_ptr<MachOObjectFile>, 2> ExtractedObjects;
SmallVector<Slice, 2> Slices =
buildSlices(InputBinaries, Alignments, ExtractedObjects);
break;
case LipoAction::ReplaceArch:
replaceSlices(InputBinaries, C.SegmentAlignments, C.OutputFile,
- C.Replacements);
+ C.ReplacementFiles);
break;
}
return EXIT_SUCCESS;