Index: test/tools/llvm-lipo/verify-arch-macho-binary.test =================================================================== --- test/tools/llvm-lipo/verify-arch-macho-binary.test +++ test/tools/llvm-lipo/verify-arch-macho-binary.test @@ -0,0 +1,29 @@ +# RUN: yaml2obj %s > %t + +# RUN: llvm-lipo %t -verify_arch i386 +# RUN: llvm-lipo %t --verify_arch i386 +# RUN: llvm-lipo %t --verify_arch=i386 + +# RUN: not llvm-lipo %t -verify_arch aarch64 +# RUN: not llvm-lipo %t -verify_arch aarch64 -verify_arch i386 + +# INVALID_ARCH: Invalid architecture: aarch101 +# RUN: not llvm-lipo %t -verify_arch aarch101 2>&1 | FileCheck --check-prefix=INVALID_ARCH %s + +# INVALID_OBJ: The file was not recognized as a valid object file +# RUN: touch %t.empty +# RUN: not llvm-lipo %t.empty -verify_arch aarch101 2>&1 | FileCheck --check-prefix=INVALID_OBJ %s + +# MULTIPLE_INPUT_OBJ: verify_arch expects a single input file +# RUN: not llvm-lipo %t %t -verify_arch i386 2>&1 | FileCheck --check-prefix=MULTIPLE_INPUT_OBJ %s + +--- !mach-o +FileHeader: + magic: 0xFEEDFACE + cputype: 0x00000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 0 + sizeofcmds: 0 + flags: 0x00002000 +... Index: test/tools/llvm-lipo/verify-arch-universal-binary.test =================================================================== --- test/tools/llvm-lipo/verify-arch-universal-binary.test +++ test/tools/llvm-lipo/verify-arch-universal-binary.test @@ -0,0 +1,44 @@ +# RUN: yaml2obj %s > %t + +# RUN: llvm-lipo %t -verify_arch i386 +# RUN: llvm-lipo %t -verify_arch i386 -verify_arch x86_64 + +# RUN: not llvm-lipo %t -verify_arch aarch64 +# RUN: not llvm-lipo %t -verify_arch aarch64 -verify_arch i386 + +--- !fat-mach-o +FatHeader: + magic: 0xCAFEBABE + nfat_arch: 2 +FatArchs: + - cputype: 0x00000007 + cpusubtype: 0x00000003 + offset: 0x0000000000001000 + size: 28 + align: 12 + - cputype: 0x01000007 + cpusubtype: 0x00000003 + offset: 0x0000000000002000 + size: 32 + align: 12 +Slices: + - !mach-o + FileHeader: + magic: 0xFEEDFACE + cputype: 0x00000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 0 + sizeofcmds: 0 + flags: 0x00002000 + - !mach-o + FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 0 + sizeofcmds: 0 + flags: 0x00002000 + reserved: 0x00000000 +... Index: tools/llvm-lipo/CMakeLists.txt =================================================================== --- tools/llvm-lipo/CMakeLists.txt +++ tools/llvm-lipo/CMakeLists.txt @@ -0,0 +1,9 @@ +set(LLVM_LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} + Object + Support +) + +add_llvm_tool(llvm-lipo + llvm-lipo.cpp +) Index: tools/llvm-lipo/LLVMBuild.txt =================================================================== --- tools/llvm-lipo/LLVMBuild.txt +++ tools/llvm-lipo/LLVMBuild.txt @@ -0,0 +1,20 @@ +;===- ./tools/llvm-lipo/LLVMBuild.txt --------------------------*- Conf -*--===; +; +; Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +; See https://llvm.org/LICENSE.txt for license information. +; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; +[component_0] +type = Tool +name = llvm-lipo +parent = Tools +required_libraries = Object Option Support Index: tools/llvm-lipo/llvm-lipo.cpp =================================================================== --- tools/llvm-lipo/llvm-lipo.cpp +++ tools/llvm-lipo/llvm-lipo.cpp @@ -0,0 +1,113 @@ +//===-- llvm-lipo.cpp - a tool for manipulating universal binaries --------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// A utility for creating / splitting / inspecting universal binaries. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/Triple.h" +#include "llvm/Object/Binary.h" +#include "llvm/Object/MachO.h" +#include "llvm/Object/MachOUniversal.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/InitLLVM.h" +#include "llvm/Support/WithColor.h" + +using namespace llvm; +using namespace llvm::object; + +cl::OptionCategory LipoCategory("Specific Options"); + +static cl::list InputFiles(cl::Positional, cl::OneOrMore, + cl::desc(""), + cl::cat(LipoCategory)); + +static cl::list VerifyArch( + "verify_arch", cl::ZeroOrMore, + cl::desc( + "Verify the specified architectures are present in the input files"), + cl::value_desc("architecture"), cl::cat(LipoCategory)); + +static const StringRef ToolName = "llvm-lipo"; + +LLVM_ATTRIBUTE_NORETURN static void reportError(Twine Message) { + WithColor::error(errs(), ToolName) << Message << "\n"; + errs().flush(); + exit(EXIT_FAILURE); +} + +LLVM_ATTRIBUTE_NORETURN static void reportError(StringRef File, Error E) { + assert(E); + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(std::move(E), OS); + OS.flush(); + WithColor::error(errs(), ToolName) << "'" << File << "': " << Buf; + exit(EXIT_FAILURE); +} + +static SmallVector, 1> readInputBinaries() { + SmallVector, 1> InputBinaries; + for (StringRef InputFile : InputFiles) { + Expected> BinaryOrErr = + createBinary(InputFile); + if (!BinaryOrErr) + reportError(InputFile, BinaryOrErr.takeError()); + if (!isa(BinaryOrErr->getBinary()) && + !isa(BinaryOrErr->getBinary())) + reportError("File " + InputFile + " has unsupported binary format"); + InputBinaries.push_back(std::move(*BinaryOrErr)); + } + return InputBinaries; +} + +LLVM_ATTRIBUTE_NORETURN +static void verifyArch(ArrayRef> InputBinaries) { + assert(!InputBinaries.empty() && + "The list of input binaries should be non-empty"); + if (InputBinaries.size() > 1) + reportError("verify_arch expects a single input file"); + + for (StringRef Arch : VerifyArch) + if (Triple(Arch).getArch() == Triple::ArchType::UnknownArch) + reportError("Invalid architecture: " + Arch); + + if (auto UO = + dyn_cast(InputBinaries.front().getBinary())) { + for (StringRef Arch : VerifyArch) { + Expected> Obj = + UO->getObjectForArch(Arch); + if (!Obj) + exit(EXIT_FAILURE); + } + } else if (auto O = + dyn_cast(InputBinaries.front().getBinary())) { + const Triple::ArchType ObjectArch = O->getArch(); + for (StringRef Arch : VerifyArch) + if (ObjectArch != Triple(Arch).getArch()) + exit(EXIT_FAILURE); + } else { + llvm_unreachable("Unexpected binary format"); + } + exit(EXIT_SUCCESS); +} + +int main(int argc, char **argv) { + InitLLVM X(argc, argv); + cl::ParseCommandLineOptions( + argc, argv, + "A tool for creating/splitting/inspecting universal binaries\n"); + + SmallVector, 1> InputBinaries = readInputBinaries(); + if (!VerifyArch.empty()) + verifyArch(InputBinaries); + + return EXIT_SUCCESS; +}