diff --git a/llvm/test/tools/llvm-lipo/extract.test b/llvm/test/tools/llvm-lipo/extract.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-lipo/extract.test @@ -0,0 +1,14 @@ +# RUN: yaml2obj %p/Inputs/i386-x86_64-universal.yaml > %t-universal.o + +# RUN: not llvm-lipo %t-universal.o -extract arm64_32 -output /dev/null 2>&1 | FileCheck --check-prefix=ARCH_NOT_IN_FILE %s +# ARCH_NOT_IN_FILE: does not contain the specified architecture arm64_32 + +# RUN: yaml2obj %p/Inputs/i386-slice.yaml > %t-i386.o +# RUN: not llvm-lipo %t-i386.o -extract arm64_32 -output /dev/null 2>&1 | FileCheck --check-prefix=INPUT_NOT_A_FAT_FILE %s +# INPUT_NOT_A_FAT_FILE: must be a fat file when the -extract option is specified + +# RUN: llvm-lipo -create %t-i386.o -output %t-i386-universal.o +# RUN: llvm-lipo -extract i386 %t-universal.o -output %t-i386-universal-extracted.o +# RUN: cmp %t-i386-universal.o %t-i386-universal-extracted.o +# RUN: llvm-lipo -thin i386 %t-i386-universal-extracted.o -output %t-i386-thinned.o +# RUN: cmp %t-i386.o %t-i386-thinned.o diff --git a/llvm/tools/llvm-lipo/LipoOpts.td b/llvm/tools/llvm-lipo/LipoOpts.td --- a/llvm/tools/llvm-lipo/LipoOpts.td +++ b/llvm/tools/llvm-lipo/LipoOpts.td @@ -39,6 +39,11 @@ HelpText<"Create a thin output file of specified arch_type from the " "fat input file. Requires -output option">; +def extract : Option<["-", "--"], "extract", KIND_SEPARATE>, + Group, + HelpText<"Create a universal output file containing only the specified " + "arch_type from the fat input file. Requires -output option">; + def create : Option<["-", "--"], "create", KIND_FLAG>, Group, HelpText<"Create a universal binary output file from the input " diff --git a/llvm/tools/llvm-lipo/llvm-lipo.cpp b/llvm/tools/llvm-lipo/llvm-lipo.cpp --- a/llvm/tools/llvm-lipo/llvm-lipo.cpp +++ b/llvm/tools/llvm-lipo/llvm-lipo.cpp @@ -83,6 +83,7 @@ PrintInfo, VerifyArch, ThinArch, + ExtractArch, CreateUniversal, ReplaceArch, }; @@ -395,10 +396,19 @@ validateArchitectureName(C.ThinArchType); if (C.OutputFile.empty()) reportError("thin expects a single output file"); - C.ActionToPerform = LipoAction::ThinArch; return C; + case LIPO_extract: + if (C.InputFiles.size() > 1) + reportError("extract expects a single input file"); + C.ThinArchType = ActionArgs[0]->getValue(); + validateArchitectureName(C.ThinArchType); + if (C.OutputFile.empty()) + reportError("extract expects a single output file"); + C.ActionToPerform = LipoAction::ExtractArch; + return C; + case LIPO_create: if (C.OutputFile.empty()) reportError("create expects a single output file to be specified"); @@ -544,8 +554,8 @@ } LLVM_ATTRIBUTE_NORETURN -static void extractSlice(ArrayRef> InputBinaries, - StringRef ThinArchType, StringRef OutputFileName) { +static void thinSlice(ArrayRef> InputBinaries, + StringRef ThinArchType, StringRef OutputFileName) { assert(!ThinArchType.empty() && "The architecture type should be non-empty"); assert(InputBinaries.size() == 1 && "Incorrect number of input binaries"); assert(!OutputFileName.empty() && "Thin expects a single output file"); @@ -739,6 +749,37 @@ exit(EXIT_SUCCESS); } +LLVM_ATTRIBUTE_NORETURN +static void extractSlice(ArrayRef> InputBinaries, + const StringMap &Alignments, + StringRef ExtractArchType, StringRef OutputFileName) { + assert(!ExtractArchType.empty() && + "The architecture type should be non-empty"); + assert(InputBinaries.size() == 1 && "Incorrect number of input binaries"); + assert(!OutputFileName.empty() && "Thin expects a single output file"); + + if (InputBinaries.front().getBinary()->isMachO()) { + reportError("input file " + + InputBinaries.front().getBinary()->getFileName() + + " must be a fat file when the -extract option is specified"); + exit(EXIT_FAILURE); + } + + SmallVector, 2> ExtractedObjects; + SmallVector Slices = + buildSlices(InputBinaries, Alignments, ExtractedObjects); + erase_if(Slices, [ExtractArchType](const Slice &S) { + return ExtractArchType != S.getArchString(); + }); + + if (Slices.empty()) + reportError( + "fat input file " + InputBinaries.front().getBinary()->getFileName() + + " does not contain the specified architecture " + ExtractArchType); + createUniversalBinary(Slices, OutputFileName); + exit(EXIT_SUCCESS); +} + static StringMap buildReplacementSlices(ArrayRef> ReplacementBinaries, const StringMap &Alignments) { @@ -823,7 +864,10 @@ printInfo(InputBinaries); break; case LipoAction::ThinArch: - extractSlice(InputBinaries, C.ThinArchType, C.OutputFile); + thinSlice(InputBinaries, C.ThinArchType, C.OutputFile); + break; + case LipoAction::ExtractArch: + extractSlice(InputBinaries, C.SegmentAlignments, C.ThinArchType, C.OutputFile); break; case LipoAction::CreateUniversal: createUniversalBinary(InputBinaries, C.SegmentAlignments, C.OutputFile);