16c43ed60SSameer Arora //===-- llvm-libtool-darwin.cpp - a tool for creating libraries -----------===// 26c43ed60SSameer Arora // 36c43ed60SSameer Arora // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 46c43ed60SSameer Arora // See https://llvm.org/LICENSE.txt for license information. 56c43ed60SSameer Arora // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 66c43ed60SSameer Arora // 76c43ed60SSameer Arora //===----------------------------------------------------------------------===// 86c43ed60SSameer Arora // 96c43ed60SSameer Arora // A utility for creating static and dynamic libraries for Darwin. 106c43ed60SSameer Arora // 116c43ed60SSameer Arora //===----------------------------------------------------------------------===// 126c43ed60SSameer Arora 1310f22335SKeith Smiley #include "DependencyInfo.h" 14fc5dcb0cSFangrui Song #include "llvm/ADT/MapVector.h" 159e783716SSameer Arora #include "llvm/BinaryFormat/Magic.h" 1605f7b682SPaul-Antoine Arras #include "llvm/IR/LLVMContext.h" 17303a7f7aSSameer Arora #include "llvm/Object/ArchiveWriter.h" 1805f7b682SPaul-Antoine Arras #include "llvm/Object/IRObjectFile.h" 19303a7f7aSSameer Arora #include "llvm/Object/MachO.h" 20bd2853f7SSameer Arora #include "llvm/Object/MachOUniversal.h" 218f6f6f40SSameer Arora #include "llvm/Object/MachOUniversalWriter.h" 22303a7f7aSSameer Arora #include "llvm/Object/ObjectFile.h" 23939c0351SAndres Villegas #include "llvm/Option/ArgList.h" 24939c0351SAndres Villegas #include "llvm/Option/Option.h" 256c43ed60SSameer Arora #include "llvm/Support/CommandLine.h" 26668e33c6SAndrés Villegas #include "llvm/Support/LLVMDriver.h" 27d9a91929SSameer Arora #include "llvm/Support/LineIterator.h" 28dbed14d2SKeith Smiley #include "llvm/Support/TargetSelect.h" 29ba7a92c0SNico Weber #include "llvm/Support/VirtualFileSystem.h" 306c43ed60SSameer Arora #include "llvm/Support/WithColor.h" 31939c0351SAndres Villegas #include "llvm/Support/YAMLTraits.h" 32f4744e9aSShoaib Meenai #include "llvm/Support/raw_ostream.h" 330116d04dSCyndy Ishida #include "llvm/TextAPI/Architecture.h" 34668e33c6SAndrés Villegas #include <cstdlib> 358f6f6f40SSameer Arora #include <map> 36e9b5b815SRoger Kim #include <type_traits> 376c43ed60SSameer Arora 386c43ed60SSameer Arora using namespace llvm; 39303a7f7aSSameer Arora using namespace llvm::object; 40939c0351SAndres Villegas using namespace llvm::opt; 41939c0351SAndres Villegas 42939c0351SAndres Villegas // Command-line option boilerplate. 43939c0351SAndres Villegas namespace { 44939c0351SAndres Villegas enum ID { 45939c0351SAndres Villegas OPT_INVALID = 0, // This is not an option ID. 463f092f37SJan Svoboda #define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__), 47939c0351SAndres Villegas #include "Opts.inc" 48939c0351SAndres Villegas #undef OPTION 49939c0351SAndres Villegas }; 50939c0351SAndres Villegas 51*dd647e3eSChandler Carruth #define OPTTABLE_STR_TABLE_CODE 52939c0351SAndres Villegas #include "Opts.inc" 53*dd647e3eSChandler Carruth #undef OPTTABLE_STR_TABLE_CODE 54*dd647e3eSChandler Carruth 55*dd647e3eSChandler Carruth #define OPTTABLE_PREFIXES_TABLE_CODE 56*dd647e3eSChandler Carruth #include "Opts.inc" 57*dd647e3eSChandler Carruth #undef OPTTABLE_PREFIXES_TABLE_CODE 58939c0351SAndres Villegas 59939c0351SAndres Villegas static constexpr opt::OptTable::Info InfoTable[] = { 603f092f37SJan Svoboda #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__), 61939c0351SAndres Villegas #include "Opts.inc" 62939c0351SAndres Villegas #undef OPTION 63939c0351SAndres Villegas }; 64939c0351SAndres Villegas 65939c0351SAndres Villegas class LibtoolDarwinOptTable : public opt::GenericOptTable { 66939c0351SAndres Villegas public: 67*dd647e3eSChandler Carruth LibtoolDarwinOptTable() 68*dd647e3eSChandler Carruth : GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {} 69939c0351SAndres Villegas }; 70939c0351SAndres Villegas } // end anonymous namespace 716c43ed60SSameer Arora 72f4744e9aSShoaib Meenai class NewArchiveMemberList; 73f4744e9aSShoaib Meenai typedef std::map<uint64_t, NewArchiveMemberList> MembersPerArchitectureMap; 748f6f6f40SSameer Arora 75939c0351SAndres Villegas static std::string OutputFile; 76939c0351SAndres Villegas static std::vector<std::string> InputFiles; 77939c0351SAndres Villegas static std::optional<std::string> ArchType; 78bd2853f7SSameer Arora 7968bae34cSShoaib Meenai enum class Operation { None, Static }; 80939c0351SAndres Villegas static Operation LibraryOperation = Operation::None; 81303a7f7aSSameer Arora 82939c0351SAndres Villegas static bool DeterministicOption; 83939c0351SAndres Villegas static bool NonDeterministicOption; 84939c0351SAndres Villegas static std::string FileList; 85939c0351SAndres Villegas static std::vector<std::string> Libraries; 86939c0351SAndres Villegas static std::vector<std::string> LibrarySearchDirs; 87939c0351SAndres Villegas static std::string DependencyInfoPath; 88939c0351SAndres Villegas static bool VersionOption; 89939c0351SAndres Villegas static bool NoWarningForNoSymbols; 90939c0351SAndres Villegas static bool WarningsAsErrors; 91939c0351SAndres Villegas static std::string IgnoredSyslibRoot; 92e8c10fc1SKeith Smiley 931aed1e72SSameer Arora static const std::array<std::string, 3> StandardSearchDirs{ 941aed1e72SSameer Arora "/lib", 951aed1e72SSameer Arora "/usr/lib", 961aed1e72SSameer Arora "/usr/local/lib", 971aed1e72SSameer Arora }; 981aed1e72SSameer Arora 9910f22335SKeith Smiley std::unique_ptr<DependencyInfo> GlobalDependencyInfo; 10010f22335SKeith Smiley 10171a1f135SSameer Arora struct Config { 10271a1f135SSameer Arora bool Deterministic = true; // Updated by 'D' and 'U' modifiers. 1038f6f6f40SSameer Arora uint32_t ArchCPUType; 1048f6f6f40SSameer Arora uint32_t ArchCPUSubtype; 10571a1f135SSameer Arora }; 10671a1f135SSameer Arora 1071aed1e72SSameer Arora static Expected<std::string> searchForFile(const Twine &FileName) { 1081aed1e72SSameer Arora auto FindLib = 109da2f5d0aSFangrui Song [FileName]( 110da2f5d0aSFangrui Song ArrayRef<std::string> SearchDirs) -> std::optional<std::string> { 1111aed1e72SSameer Arora for (StringRef Dir : SearchDirs) { 1121aed1e72SSameer Arora SmallString<128> Path; 1131aed1e72SSameer Arora sys::path::append(Path, Dir, FileName); 1141aed1e72SSameer Arora 1151aed1e72SSameer Arora if (sys::fs::exists(Path)) 1161aed1e72SSameer Arora return std::string(Path); 11710f22335SKeith Smiley 11810f22335SKeith Smiley GlobalDependencyInfo->addMissingInput(Path); 1191aed1e72SSameer Arora } 120b4482f7cSKazu Hirata return std::nullopt; 1211aed1e72SSameer Arora }; 1221aed1e72SSameer Arora 123da2f5d0aSFangrui Song std::optional<std::string> Found = FindLib(LibrarySearchDirs); 12493c761f5SShoaib Meenai if (!Found) 1251aed1e72SSameer Arora Found = FindLib(StandardSearchDirs); 12693c761f5SShoaib Meenai if (Found) 12793c761f5SShoaib Meenai return *Found; 1281aed1e72SSameer Arora 1291aed1e72SSameer Arora return createStringError(std::errc::invalid_argument, 1301aed1e72SSameer Arora "cannot locate file '%s'", FileName.str().c_str()); 1311aed1e72SSameer Arora } 1321aed1e72SSameer Arora 1331aed1e72SSameer Arora static Error processCommandLineLibraries() { 1341aed1e72SSameer Arora for (StringRef BaseName : Libraries) { 1351aed1e72SSameer Arora Expected<std::string> FullPath = searchForFile( 136586ecdf2SKazu Hirata BaseName.ends_with(".o") ? BaseName.str() : "lib" + BaseName + ".a"); 1371aed1e72SSameer Arora if (!FullPath) 1381aed1e72SSameer Arora return FullPath.takeError(); 1391aed1e72SSameer Arora InputFiles.push_back(FullPath.get()); 1401aed1e72SSameer Arora } 1411aed1e72SSameer Arora 1421aed1e72SSameer Arora return Error::success(); 1431aed1e72SSameer Arora } 1441aed1e72SSameer Arora 145d9a91929SSameer Arora static Error processFileList() { 146d9a91929SSameer Arora StringRef FileName, DirName; 147d9a91929SSameer Arora std::tie(FileName, DirName) = StringRef(FileList).rsplit(","); 148d9a91929SSameer Arora 149d9a91929SSameer Arora ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr = 150c83cd8feSAbhina Sreeskantharajan MemoryBuffer::getFileOrSTDIN(FileName, /*IsText=*/false, 151d9a91929SSameer Arora /*RequiresNullTerminator=*/false); 152d9a91929SSameer Arora if (std::error_code EC = FileOrErr.getError()) 153d9a91929SSameer Arora return createFileError(FileName, errorCodeToError(EC)); 154d9a91929SSameer Arora const MemoryBuffer &Ref = *FileOrErr.get(); 155d9a91929SSameer Arora 156d9a91929SSameer Arora line_iterator I(Ref, /*SkipBlanks=*/false); 157d9a91929SSameer Arora if (I.is_at_eof()) 158d9a91929SSameer Arora return createStringError(std::errc::invalid_argument, 159d9a91929SSameer Arora "file list file: '%s' is empty", 160d9a91929SSameer Arora FileName.str().c_str()); 161d9a91929SSameer Arora for (; !I.is_at_eof(); ++I) { 162d9a91929SSameer Arora StringRef Line = *I; 163d9a91929SSameer Arora if (Line.empty()) 164d9a91929SSameer Arora return createStringError(std::errc::invalid_argument, 165d9a91929SSameer Arora "file list file: '%s': filename cannot be empty", 166d9a91929SSameer Arora FileName.str().c_str()); 167d9a91929SSameer Arora 168d9a91929SSameer Arora SmallString<128> Path; 169d9a91929SSameer Arora if (!DirName.empty()) 170d9a91929SSameer Arora sys::path::append(Path, DirName, Line); 171d9a91929SSameer Arora else 172d9a91929SSameer Arora sys::path::append(Path, Line); 173d9a91929SSameer Arora InputFiles.push_back(static_cast<std::string>(Path)); 174d9a91929SSameer Arora } 175d9a91929SSameer Arora return Error::success(); 176d9a91929SSameer Arora } 177d9a91929SSameer Arora 178bd2853f7SSameer Arora static Error validateArchitectureName(StringRef ArchitectureName) { 179bd2853f7SSameer Arora if (!MachOObjectFile::isValidArch(ArchitectureName)) { 180bd2853f7SSameer Arora std::string Buf; 181bd2853f7SSameer Arora raw_string_ostream OS(Buf); 182bd2853f7SSameer Arora for (StringRef Arch : MachOObjectFile::getValidArchs()) 183bd2853f7SSameer Arora OS << Arch << " "; 184bd2853f7SSameer Arora 185bd2853f7SSameer Arora return createStringError( 186bd2853f7SSameer Arora std::errc::invalid_argument, 187bd2853f7SSameer Arora "invalid architecture '%s': valid architecture names are %s", 1886c0b1e75SJOE1994 ArchitectureName.str().c_str(), Buf.c_str()); 189bd2853f7SSameer Arora } 190bd2853f7SSameer Arora return Error::success(); 191bd2853f7SSameer Arora } 192bd2853f7SSameer Arora 1938f6f6f40SSameer Arora static uint64_t getCPUID(uint32_t CPUType, uint32_t CPUSubtype) { 1948f6f6f40SSameer Arora switch (CPUType) { 1958f6f6f40SSameer Arora case MachO::CPU_TYPE_ARM: 1968f6f6f40SSameer Arora case MachO::CPU_TYPE_ARM64: 1978f6f6f40SSameer Arora case MachO::CPU_TYPE_ARM64_32: 1988f6f6f40SSameer Arora case MachO::CPU_TYPE_X86_64: 1998f6f6f40SSameer Arora // We consider CPUSubtype only for the above 4 CPUTypes to match cctools' 2008f6f6f40SSameer Arora // libtool behavior. 2018f6f6f40SSameer Arora return static_cast<uint64_t>(CPUType) << 32 | CPUSubtype; 2028f6f6f40SSameer Arora default: 2038f6f6f40SSameer Arora return CPUType; 2048f6f6f40SSameer Arora } 2058f6f6f40SSameer Arora } 2068f6f6f40SSameer Arora 207e9b5b815SRoger Kim // MembersData is an organized collection of members. 208e9b5b815SRoger Kim struct MembersData { 209e9b5b815SRoger Kim // MembersPerArchitectureMap is a mapping from CPU architecture to a list of 210e9b5b815SRoger Kim // members. 211e9b5b815SRoger Kim MembersPerArchitectureMap MembersPerArchitecture; 212e9b5b815SRoger Kim std::vector<std::unique_ptr<MemoryBuffer>> FileBuffers; 213f4744e9aSShoaib Meenai }; 214e9b5b815SRoger Kim 215f4744e9aSShoaib Meenai // NewArchiveMemberList instances serve as collections of archive members and 216f4744e9aSShoaib Meenai // information about those members. 217f4744e9aSShoaib Meenai class NewArchiveMemberList { 218f4744e9aSShoaib Meenai std::vector<NewArchiveMember> Members; 219f4744e9aSShoaib Meenai // This vector contains the file that each NewArchiveMember from Members came 220f4744e9aSShoaib Meenai // from. Therefore, it has the same size as Members. 221f4744e9aSShoaib Meenai std::vector<StringRef> Files; 222f4744e9aSShoaib Meenai 223f4744e9aSShoaib Meenai public: 224f4744e9aSShoaib Meenai // Add a NewArchiveMember and the file it came from to the list. 225f4744e9aSShoaib Meenai void push_back(NewArchiveMember &&Member, StringRef File) { 226f4744e9aSShoaib Meenai Members.push_back(std::move(Member)); 227f4744e9aSShoaib Meenai Files.push_back(File); 228f4744e9aSShoaib Meenai } 229f4744e9aSShoaib Meenai 230f4744e9aSShoaib Meenai ArrayRef<NewArchiveMember> getMembers() const { return Members; } 231f4744e9aSShoaib Meenai 232f4744e9aSShoaib Meenai ArrayRef<StringRef> getFiles() const { return Files; } 233f4744e9aSShoaib Meenai 234f4744e9aSShoaib Meenai static_assert( 235f4744e9aSShoaib Meenai std::is_same<decltype(MembersData::MembersPerArchitecture)::mapped_type, 236f4744e9aSShoaib Meenai NewArchiveMemberList>(), 237f4744e9aSShoaib Meenai "This test makes sure NewArchiveMemberList is used by MembersData since " 238f4744e9aSShoaib Meenai "the following asserts test invariants required for MembersData."); 239f4744e9aSShoaib Meenai static_assert( 2406aa050a6SNathan James !std::is_copy_constructible_v< 2416aa050a6SNathan James decltype(NewArchiveMemberList::Members)::value_type>, 242f4744e9aSShoaib Meenai "MembersData::MembersPerArchitecture has a dependency on " 243f4744e9aSShoaib Meenai "MembersData::FileBuffers so it should not be able to " 244f4744e9aSShoaib Meenai "be copied on its own without FileBuffers. Unfortunately, " 245f4744e9aSShoaib Meenai "is_copy_constructible does not detect whether the container (ie vector) " 246f4744e9aSShoaib Meenai "of a non-copyable type is itself non-copyable so we have to test the " 247f4744e9aSShoaib Meenai "actual type of the stored data (ie, value_type)."); 248f4744e9aSShoaib Meenai static_assert( 2496aa050a6SNathan James !std::is_copy_assignable_v< 2506aa050a6SNathan James decltype(NewArchiveMemberList::Members)::value_type>, 251f4744e9aSShoaib Meenai "MembersData::MembersPerArchitecture has a dependency on " 252f4744e9aSShoaib Meenai "MembersData::FileBuffers so it should not be able to " 253f4744e9aSShoaib Meenai "be copied on its own without FileBuffers. Unfortunately, " 254f4744e9aSShoaib Meenai "is_copy_constructible does not detect whether the container (ie vector) " 255f4744e9aSShoaib Meenai "of a non-copyable type is itself non-copyable so we have to test the " 256f4744e9aSShoaib Meenai "actual type of the stored data (ie, value_type)."); 257e9b5b815SRoger Kim }; 258e9b5b815SRoger Kim 259e9b5b815SRoger Kim // MembersBuilder collects and organizes all members from the files provided by 260e9b5b815SRoger Kim // the user. 261e9b5b815SRoger Kim class MembersBuilder { 262e9b5b815SRoger Kim public: 2633210647eSArthur Eubanks MembersBuilder(LLVMContext &LLVMCtx, const Config &C) 2643210647eSArthur Eubanks : LLVMCtx(LLVMCtx), C(C) {} 265e9b5b815SRoger Kim 266e9b5b815SRoger Kim Expected<MembersData> build() { 267e9b5b815SRoger Kim for (StringRef FileName : InputFiles) 268f4744e9aSShoaib Meenai if (Error E = AddMember(*this, FileName)()) 269e9b5b815SRoger Kim return std::move(E); 270e9b5b815SRoger Kim 271939c0351SAndres Villegas std::string Arch = ArchType.value_or(""); 272939c0351SAndres Villegas if (!Arch.empty()) { 273e9b5b815SRoger Kim uint64_t ArchCPUID = getCPUID(C.ArchCPUType, C.ArchCPUSubtype); 274e9b5b815SRoger Kim if (Data.MembersPerArchitecture.find(ArchCPUID) == 275e9b5b815SRoger Kim Data.MembersPerArchitecture.end()) 276e9b5b815SRoger Kim return createStringError(std::errc::invalid_argument, 277e9b5b815SRoger Kim "no library created (no object files in input " 278e9b5b815SRoger Kim "files matching -arch_only %s)", 279939c0351SAndres Villegas Arch.c_str()); 280e9b5b815SRoger Kim } 281e9b5b815SRoger Kim return std::move(Data); 282e9b5b815SRoger Kim } 283e9b5b815SRoger Kim 284e9b5b815SRoger Kim private: 285f4744e9aSShoaib Meenai class AddMember { 286f4744e9aSShoaib Meenai MembersBuilder &Builder; 287f4744e9aSShoaib Meenai StringRef FileName; 288f4744e9aSShoaib Meenai 289f4744e9aSShoaib Meenai public: 290f4744e9aSShoaib Meenai AddMember(MembersBuilder &Builder, StringRef FileName) 291f4744e9aSShoaib Meenai : Builder(Builder), FileName(FileName) {} 292f4744e9aSShoaib Meenai 293f4744e9aSShoaib Meenai Error operator()() { 294f4744e9aSShoaib Meenai Expected<NewArchiveMember> NewMemberOrErr = 295f4744e9aSShoaib Meenai NewArchiveMember::getFile(FileName, Builder.C.Deterministic); 296f4744e9aSShoaib Meenai if (!NewMemberOrErr) 297f4744e9aSShoaib Meenai return createFileError(FileName, NewMemberOrErr.takeError()); 298f4744e9aSShoaib Meenai auto &NewMember = *NewMemberOrErr; 299f4744e9aSShoaib Meenai 300f4744e9aSShoaib Meenai // For regular archives, use the basename of the object path for the 301f4744e9aSShoaib Meenai // member name. 302f4744e9aSShoaib Meenai NewMember.MemberName = sys::path::filename(NewMember.MemberName); 303f4744e9aSShoaib Meenai file_magic Magic = identify_magic(NewMember.Buf->getBuffer()); 304f4744e9aSShoaib Meenai 305f4744e9aSShoaib Meenai // Flatten archives. 306f4744e9aSShoaib Meenai if (Magic == file_magic::archive) 307f4744e9aSShoaib Meenai return addArchiveMembers(std::move(NewMember)); 308f4744e9aSShoaib Meenai 309f4744e9aSShoaib Meenai // Flatten universal files. 310f4744e9aSShoaib Meenai if (Magic == file_magic::macho_universal_binary) 311f4744e9aSShoaib Meenai return addUniversalMembers(std::move(NewMember)); 312f4744e9aSShoaib Meenai 313f4744e9aSShoaib Meenai // Bitcode files. 314f4744e9aSShoaib Meenai if (Magic == file_magic::bitcode) 315f4744e9aSShoaib Meenai return verifyAndAddIRObject(std::move(NewMember)); 316f4744e9aSShoaib Meenai 317f4744e9aSShoaib Meenai return verifyAndAddMachOObject(std::move(NewMember)); 318f4744e9aSShoaib Meenai } 319f4744e9aSShoaib Meenai 320f4744e9aSShoaib Meenai private: 321bd2853f7SSameer Arora // Check that a file's architecture [FileCPUType, FileCPUSubtype] 322bd2853f7SSameer Arora // matches the architecture specified under -arch_only flag. 323e9b5b815SRoger Kim bool acceptFileArch(uint32_t FileCPUType, uint32_t FileCPUSubtype) { 324f4744e9aSShoaib Meenai if (Builder.C.ArchCPUType != FileCPUType) 325bd2853f7SSameer Arora return false; 326bd2853f7SSameer Arora 327f4744e9aSShoaib Meenai switch (Builder.C.ArchCPUType) { 328bd2853f7SSameer Arora case MachO::CPU_TYPE_ARM: 329bd2853f7SSameer Arora case MachO::CPU_TYPE_ARM64_32: 330bd2853f7SSameer Arora case MachO::CPU_TYPE_X86_64: 331f4744e9aSShoaib Meenai return Builder.C.ArchCPUSubtype == FileCPUSubtype; 332bd2853f7SSameer Arora 333bd2853f7SSameer Arora case MachO::CPU_TYPE_ARM64: 334f4744e9aSShoaib Meenai if (Builder.C.ArchCPUSubtype == MachO::CPU_SUBTYPE_ARM64_ALL) 335bd2853f7SSameer Arora return FileCPUSubtype == MachO::CPU_SUBTYPE_ARM64_ALL || 336bd2853f7SSameer Arora FileCPUSubtype == MachO::CPU_SUBTYPE_ARM64_V8; 337bd2853f7SSameer Arora else 338f4744e9aSShoaib Meenai return Builder.C.ArchCPUSubtype == FileCPUSubtype; 339bd2853f7SSameer Arora 340bd2853f7SSameer Arora default: 341bd2853f7SSameer Arora return true; 342bd2853f7SSameer Arora } 343bd2853f7SSameer Arora } 344bd2853f7SSameer Arora 345e9b5b815SRoger Kim Error verifyAndAddMachOObject(NewArchiveMember Member) { 346303a7f7aSSameer Arora auto MBRef = Member.Buf->getMemBufferRef(); 347303a7f7aSSameer Arora Expected<std::unique_ptr<object::ObjectFile>> ObjOrErr = 348303a7f7aSSameer Arora object::ObjectFile::createObjectFile(MBRef); 349303a7f7aSSameer Arora 350303a7f7aSSameer Arora // Throw error if not a valid object file. 351303a7f7aSSameer Arora if (!ObjOrErr) 352303a7f7aSSameer Arora return createFileError(Member.MemberName, ObjOrErr.takeError()); 353303a7f7aSSameer Arora 354303a7f7aSSameer Arora // Throw error if not in Mach-O format. 355303a7f7aSSameer Arora if (!isa<object::MachOObjectFile>(**ObjOrErr)) 356303a7f7aSSameer Arora return createStringError(std::errc::invalid_argument, 357303a7f7aSSameer Arora "'%s': format not supported", 358303a7f7aSSameer Arora Member.MemberName.data()); 359303a7f7aSSameer Arora 36046359424SSimon Pilgrim auto *O = cast<MachOObjectFile>(ObjOrErr->get()); 361bd2853f7SSameer Arora uint32_t FileCPUType, FileCPUSubtype; 362bd2853f7SSameer Arora std::tie(FileCPUType, FileCPUSubtype) = MachO::getCPUTypeFromArchitecture( 363ecf132deSKeith Smiley MachO::getArchitectureFromName(O->getArchTriple().getArchName())); 364bd2853f7SSameer Arora 365bd2853f7SSameer Arora // If -arch_only is specified then skip this file if it doesn't match 366bd2853f7SSameer Arora // the architecture specified. 367939c0351SAndres Villegas if (ArchType && !acceptFileArch(FileCPUType, FileCPUSubtype)) { 368bd2853f7SSameer Arora return Error::success(); 369bd2853f7SSameer Arora } 370bd2853f7SSameer Arora 3714c12a75eSKeith Smiley if (!NoWarningForNoSymbols && O->symbols().empty()) { 3724c12a75eSKeith Smiley Error E = createFileError( 3734c12a75eSKeith Smiley Member.MemberName, 3744c12a75eSKeith Smiley createStringError(std::errc::invalid_argument, 3754c12a75eSKeith Smiley "has no symbols for architecture %s", 3764c12a75eSKeith Smiley O->getArchTriple().getArchName().str().c_str())); 3774c12a75eSKeith Smiley 3784c12a75eSKeith Smiley if (WarningsAsErrors) 3794c12a75eSKeith Smiley return E; 3804c12a75eSKeith Smiley WithColor::defaultWarningHandler(std::move(E)); 3814c12a75eSKeith Smiley } 382cdcb60a8SAlexander Shaposhnikov 3838f6f6f40SSameer Arora uint64_t FileCPUID = getCPUID(FileCPUType, FileCPUSubtype); 384f4744e9aSShoaib Meenai Builder.Data.MembersPerArchitecture[FileCPUID].push_back( 385f4744e9aSShoaib Meenai std::move(Member), FileName); 386303a7f7aSSameer Arora return Error::success(); 387303a7f7aSSameer Arora } 388303a7f7aSSameer Arora 389e9b5b815SRoger Kim Error verifyAndAddIRObject(NewArchiveMember Member) { 39005f7b682SPaul-Antoine Arras auto MBRef = Member.Buf->getMemBufferRef(); 39105f7b682SPaul-Antoine Arras Expected<std::unique_ptr<object::IRObjectFile>> IROrErr = 3923210647eSArthur Eubanks object::IRObjectFile::create(MBRef, Builder.LLVMCtx); 39305f7b682SPaul-Antoine Arras 39405f7b682SPaul-Antoine Arras // Throw error if not a valid IR object file. 39505f7b682SPaul-Antoine Arras if (!IROrErr) 39605f7b682SPaul-Antoine Arras return createFileError(Member.MemberName, IROrErr.takeError()); 39705f7b682SPaul-Antoine Arras 39805f7b682SPaul-Antoine Arras Triple TT = Triple(IROrErr->get()->getTargetTriple()); 39905f7b682SPaul-Antoine Arras 40005f7b682SPaul-Antoine Arras Expected<uint32_t> FileCPUTypeOrErr = MachO::getCPUType(TT); 40105f7b682SPaul-Antoine Arras if (!FileCPUTypeOrErr) 40205f7b682SPaul-Antoine Arras return FileCPUTypeOrErr.takeError(); 40305f7b682SPaul-Antoine Arras 40405f7b682SPaul-Antoine Arras Expected<uint32_t> FileCPUSubTypeOrErr = MachO::getCPUSubType(TT); 40505f7b682SPaul-Antoine Arras if (!FileCPUSubTypeOrErr) 40605f7b682SPaul-Antoine Arras return FileCPUSubTypeOrErr.takeError(); 40705f7b682SPaul-Antoine Arras 40805f7b682SPaul-Antoine Arras // If -arch_only is specified then skip this file if it doesn't match 40905f7b682SPaul-Antoine Arras // the architecture specified. 410939c0351SAndres Villegas if (ArchType && 411e9b5b815SRoger Kim !acceptFileArch(*FileCPUTypeOrErr, *FileCPUSubTypeOrErr)) { 41205f7b682SPaul-Antoine Arras return Error::success(); 41305f7b682SPaul-Antoine Arras } 41405f7b682SPaul-Antoine Arras 41505f7b682SPaul-Antoine Arras uint64_t FileCPUID = getCPUID(*FileCPUTypeOrErr, *FileCPUSubTypeOrErr); 416f4744e9aSShoaib Meenai Builder.Data.MembersPerArchitecture[FileCPUID].push_back( 417f4744e9aSShoaib Meenai std::move(Member), FileName); 41805f7b682SPaul-Antoine Arras return Error::success(); 41905f7b682SPaul-Antoine Arras } 42005f7b682SPaul-Antoine Arras 421e9b5b815SRoger Kim Error addChildMember(const object::Archive::Child &M) { 4221658980aSRoger Kim Expected<NewArchiveMember> NewMemberOrErr = 423f4744e9aSShoaib Meenai NewArchiveMember::getOldMember(M, Builder.C.Deterministic); 4241658980aSRoger Kim if (!NewMemberOrErr) 4251658980aSRoger Kim return NewMemberOrErr.takeError(); 4261658980aSRoger Kim auto &NewMember = *NewMemberOrErr; 4279e783716SSameer Arora 4281658980aSRoger Kim file_magic Magic = identify_magic(NewMember.Buf->getBuffer()); 42905f7b682SPaul-Antoine Arras 43005f7b682SPaul-Antoine Arras if (Magic == file_magic::bitcode) 431e9b5b815SRoger Kim return verifyAndAddIRObject(std::move(NewMember)); 43205f7b682SPaul-Antoine Arras 433e9b5b815SRoger Kim return verifyAndAddMachOObject(std::move(NewMember)); 434bd2853f7SSameer Arora } 435bd2853f7SSameer Arora 436f4744e9aSShoaib Meenai Error processArchive(object::Archive &Lib) { 437bd2853f7SSameer Arora Error Err = Error::success(); 438bd2853f7SSameer Arora for (const object::Archive::Child &Child : Lib.children(Err)) 439e9b5b815SRoger Kim if (Error E = addChildMember(Child)) 440bd2853f7SSameer Arora return createFileError(FileName, std::move(E)); 441bd2853f7SSameer Arora if (Err) 442bd2853f7SSameer Arora return createFileError(FileName, std::move(Err)); 443bd2853f7SSameer Arora 4449e783716SSameer Arora return Error::success(); 4459e783716SSameer Arora } 4469e783716SSameer Arora 447f4744e9aSShoaib Meenai Error addArchiveMembers(NewArchiveMember NewMember) { 448bd2853f7SSameer Arora Expected<std::unique_ptr<Archive>> LibOrErr = 4491658980aSRoger Kim object::Archive::create(NewMember.Buf->getMemBufferRef()); 450bd2853f7SSameer Arora if (!LibOrErr) 451bd2853f7SSameer Arora return createFileError(FileName, LibOrErr.takeError()); 452bd2853f7SSameer Arora 453f4744e9aSShoaib Meenai if (Error E = processArchive(**LibOrErr)) 454bd2853f7SSameer Arora return E; 455bd2853f7SSameer Arora 456e9b5b815SRoger Kim // Update vector FileBuffers with the MemoryBuffers to transfer 457bd2853f7SSameer Arora // ownership. 458f4744e9aSShoaib Meenai Builder.Data.FileBuffers.push_back(std::move(NewMember.Buf)); 459bd2853f7SSameer Arora return Error::success(); 460bd2853f7SSameer Arora } 461bd2853f7SSameer Arora 462f4744e9aSShoaib Meenai Error addUniversalMembers(NewArchiveMember NewMember) { 463bd2853f7SSameer Arora Expected<std::unique_ptr<MachOUniversalBinary>> BinaryOrErr = 4641658980aSRoger Kim MachOUniversalBinary::create(NewMember.Buf->getMemBufferRef()); 465bd2853f7SSameer Arora if (!BinaryOrErr) 466bd2853f7SSameer Arora return createFileError(FileName, BinaryOrErr.takeError()); 467bd2853f7SSameer Arora 468bd2853f7SSameer Arora auto *UO = BinaryOrErr->get(); 469bd2853f7SSameer Arora for (const MachOUniversalBinary::ObjectForArch &O : UO->objects()) { 470bd2853f7SSameer Arora 471bd2853f7SSameer Arora Expected<std::unique_ptr<MachOObjectFile>> MachOObjOrErr = 472bd2853f7SSameer Arora O.getAsObjectFile(); 473bd2853f7SSameer Arora if (MachOObjOrErr) { 474bd2853f7SSameer Arora NewArchiveMember NewMember = 475bd2853f7SSameer Arora NewArchiveMember(MachOObjOrErr->get()->getMemoryBufferRef()); 476bd2853f7SSameer Arora NewMember.MemberName = sys::path::filename(NewMember.MemberName); 477bd2853f7SSameer Arora 478e9b5b815SRoger Kim if (Error E = verifyAndAddMachOObject(std::move(NewMember))) 479bd2853f7SSameer Arora return E; 480bd2853f7SSameer Arora continue; 481bd2853f7SSameer Arora } 482bd2853f7SSameer Arora 48305f7b682SPaul-Antoine Arras Expected<std::unique_ptr<IRObjectFile>> IRObjectOrError = 4843210647eSArthur Eubanks O.getAsIRObject(Builder.LLVMCtx); 48505f7b682SPaul-Antoine Arras if (IRObjectOrError) { 48605f7b682SPaul-Antoine Arras // A universal file member can be a MachOObjectFile, an IRObject or an 487f4744e9aSShoaib Meenai // Archive. In case we can successfully cast the member as an 488f4744e9aSShoaib Meenai // IRObject, it is safe to throw away the error generated due to 489f4744e9aSShoaib Meenai // casting the object as a MachOObjectFile. 49005f7b682SPaul-Antoine Arras consumeError(MachOObjOrErr.takeError()); 49105f7b682SPaul-Antoine Arras 49205f7b682SPaul-Antoine Arras NewArchiveMember NewMember = 49305f7b682SPaul-Antoine Arras NewArchiveMember(IRObjectOrError->get()->getMemoryBufferRef()); 49405f7b682SPaul-Antoine Arras NewMember.MemberName = sys::path::filename(NewMember.MemberName); 49505f7b682SPaul-Antoine Arras 496e9b5b815SRoger Kim if (Error E = verifyAndAddIRObject(std::move(NewMember))) 49705f7b682SPaul-Antoine Arras return E; 49805f7b682SPaul-Antoine Arras continue; 49905f7b682SPaul-Antoine Arras } 50005f7b682SPaul-Antoine Arras 501bd2853f7SSameer Arora Expected<std::unique_ptr<Archive>> ArchiveOrError = O.getAsArchive(); 502bd2853f7SSameer Arora if (ArchiveOrError) { 50305f7b682SPaul-Antoine Arras // A universal file member can be a MachOObjectFile, an IRObject or an 504e9b5b815SRoger Kim // Archive. In case we can successfully cast the member as an Archive, 505e9b5b815SRoger Kim // it is safe to throw away the error generated due to casting the 506e9b5b815SRoger Kim // object as a MachOObjectFile. 507bd2853f7SSameer Arora consumeError(MachOObjOrErr.takeError()); 50805f7b682SPaul-Antoine Arras consumeError(IRObjectOrError.takeError()); 509bd2853f7SSameer Arora 510f4744e9aSShoaib Meenai if (Error E = processArchive(**ArchiveOrError)) 511bd2853f7SSameer Arora return E; 512bd2853f7SSameer Arora continue; 513bd2853f7SSameer Arora } 514bd2853f7SSameer Arora 51505f7b682SPaul-Antoine Arras Error CombinedError = joinErrors( 51605f7b682SPaul-Antoine Arras ArchiveOrError.takeError(), 51705f7b682SPaul-Antoine Arras joinErrors(IRObjectOrError.takeError(), MachOObjOrErr.takeError())); 518bd2853f7SSameer Arora return createFileError(FileName, std::move(CombinedError)); 519bd2853f7SSameer Arora } 520bd2853f7SSameer Arora 521e9b5b815SRoger Kim // Update vector FileBuffers with the MemoryBuffers to transfer 522bd2853f7SSameer Arora // ownership. 523f4744e9aSShoaib Meenai Builder.Data.FileBuffers.push_back(std::move(NewMember.Buf)); 524bd2853f7SSameer Arora return Error::success(); 525bd2853f7SSameer Arora } 526f4744e9aSShoaib Meenai }; 527303a7f7aSSameer Arora 528e9b5b815SRoger Kim MembersData Data; 5293210647eSArthur Eubanks LLVMContext &LLVMCtx; 530e9b5b815SRoger Kim const Config &C; 531e9b5b815SRoger Kim }; 532e9b5b815SRoger Kim 5338f6f6f40SSameer Arora static Expected<SmallVector<Slice, 2>> 5343210647eSArthur Eubanks buildSlices(LLVMContext &LLVMCtx, 5353210647eSArthur Eubanks ArrayRef<OwningBinary<Archive>> OutputBinaries) { 5368f6f6f40SSameer Arora SmallVector<Slice, 2> Slices; 5378f6f6f40SSameer Arora 5388f6f6f40SSameer Arora for (const auto &OB : OutputBinaries) { 53997702c3dSAlexander Shaposhnikov const Archive &A = *OB.getBinary(); 54005f7b682SPaul-Antoine Arras Expected<Slice> ArchiveSlice = Slice::create(A, &LLVMCtx); 5418f6f6f40SSameer Arora if (!ArchiveSlice) 5428f6f6f40SSameer Arora return ArchiveSlice.takeError(); 5438f6f6f40SSameer Arora Slices.push_back(*ArchiveSlice); 5448f6f6f40SSameer Arora } 5458f6f6f40SSameer Arora return Slices; 5468f6f6f40SSameer Arora } 5478f6f6f40SSameer Arora 548f4744e9aSShoaib Meenai static Error 549f4744e9aSShoaib Meenai checkForDuplicates(const MembersPerArchitectureMap &MembersPerArch) { 550f4744e9aSShoaib Meenai for (const auto &M : MembersPerArch) { 551f4744e9aSShoaib Meenai ArrayRef<NewArchiveMember> Members = M.second.getMembers(); 552f4744e9aSShoaib Meenai ArrayRef<StringRef> Files = M.second.getFiles(); 553fc5dcb0cSFangrui Song MapVector<StringRef, SmallVector<StringRef, 1>> MembersToFiles; 554f4744e9aSShoaib Meenai for (auto Iterators = std::make_pair(Members.begin(), Files.begin()); 555f4744e9aSShoaib Meenai Iterators.first != Members.end(); 556f4744e9aSShoaib Meenai ++Iterators.first, ++Iterators.second) { 557f4744e9aSShoaib Meenai assert(Iterators.second != Files.end() && 558f4744e9aSShoaib Meenai "Files should be the same size as Members."); 559f4744e9aSShoaib Meenai MembersToFiles[Iterators.first->MemberName].push_back(*Iterators.second); 560f4744e9aSShoaib Meenai } 561f4744e9aSShoaib Meenai 562f4744e9aSShoaib Meenai std::string ErrorData; 563f4744e9aSShoaib Meenai raw_string_ostream ErrorStream(ErrorData); 564fc5dcb0cSFangrui Song for (const auto &[Key, Value] : MembersToFiles) { 565fc5dcb0cSFangrui Song if (Value.size() > 1) { 566fc5dcb0cSFangrui Song ErrorStream << "file '" << Key << "' was specified multiple times.\n"; 567f4744e9aSShoaib Meenai 568fc5dcb0cSFangrui Song for (StringRef OriginalFile : Value) 569f4744e9aSShoaib Meenai ErrorStream << "in: " << OriginalFile.str() << '\n'; 570f4744e9aSShoaib Meenai 571f4744e9aSShoaib Meenai ErrorStream << '\n'; 572f4744e9aSShoaib Meenai } 573f4744e9aSShoaib Meenai } 574f4744e9aSShoaib Meenai 575f4744e9aSShoaib Meenai ErrorStream.flush(); 576f4744e9aSShoaib Meenai if (ErrorData.size() > 0) 577f4744e9aSShoaib Meenai return createStringError(std::errc::invalid_argument, ErrorData.c_str()); 578f4744e9aSShoaib Meenai } 579f4744e9aSShoaib Meenai return Error::success(); 580f4744e9aSShoaib Meenai } 581f4744e9aSShoaib Meenai 5823210647eSArthur Eubanks static Error createStaticLibrary(LLVMContext &LLVMCtx, const Config &C) { 5833210647eSArthur Eubanks MembersBuilder Builder(LLVMCtx, C); 584e9b5b815SRoger Kim auto DataOrError = Builder.build(); 585e9b5b815SRoger Kim if (auto Error = DataOrError.takeError()) 586e9b5b815SRoger Kim return Error; 587303a7f7aSSameer Arora 588e9b5b815SRoger Kim const auto &NewMembers = DataOrError->MembersPerArchitecture; 589bd2853f7SSameer Arora 5904c12a75eSKeith Smiley if (Error E = checkForDuplicates(NewMembers)) { 5914c12a75eSKeith Smiley if (WarningsAsErrors) 5924c12a75eSKeith Smiley return E; 593f4744e9aSShoaib Meenai WithColor::defaultWarningHandler(std::move(E)); 5944c12a75eSKeith Smiley } 595f4744e9aSShoaib Meenai 596f4744e9aSShoaib Meenai if (NewMembers.size() == 1) 597f4744e9aSShoaib Meenai return writeArchive(OutputFile, NewMembers.begin()->second.getMembers(), 598f740bcb3Szhijian SymtabWritingMode::NormalSymtab, 59971a1f135SSameer Arora /*Kind=*/object::Archive::K_DARWIN, C.Deterministic, 600c51f947aSRoger Kim /*Thin=*/false); 601c51f947aSRoger Kim 6028f6f6f40SSameer Arora SmallVector<OwningBinary<Archive>, 2> OutputBinaries; 603f4744e9aSShoaib Meenai for (const std::pair<const uint64_t, NewArchiveMemberList> &M : NewMembers) { 6048f6f6f40SSameer Arora Expected<std::unique_ptr<MemoryBuffer>> OutputBufferOrErr = 605f740bcb3Szhijian writeArchiveToBuffer( 606f740bcb3Szhijian M.second.getMembers(), SymtabWritingMode::NormalSymtab, 607f740bcb3Szhijian /*Kind=*/object::Archive::K_DARWIN, C.Deterministic, 6088f6f6f40SSameer Arora /*Thin=*/false); 6098f6f6f40SSameer Arora if (!OutputBufferOrErr) 6108f6f6f40SSameer Arora return OutputBufferOrErr.takeError(); 6118f6f6f40SSameer Arora std::unique_ptr<MemoryBuffer> &OutputBuffer = OutputBufferOrErr.get(); 6128f6f6f40SSameer Arora 6138f6f6f40SSameer Arora Expected<std::unique_ptr<Archive>> ArchiveOrError = 6148f6f6f40SSameer Arora Archive::create(OutputBuffer->getMemBufferRef()); 6158f6f6f40SSameer Arora if (!ArchiveOrError) 6168f6f6f40SSameer Arora return ArchiveOrError.takeError(); 6178f6f6f40SSameer Arora std::unique_ptr<Archive> &A = ArchiveOrError.get(); 6188f6f6f40SSameer Arora 6198f6f6f40SSameer Arora OutputBinaries.push_back( 6208f6f6f40SSameer Arora OwningBinary<Archive>(std::move(A), std::move(OutputBuffer))); 6218f6f6f40SSameer Arora } 6228f6f6f40SSameer Arora 6233210647eSArthur Eubanks Expected<SmallVector<Slice, 2>> Slices = buildSlices(LLVMCtx, OutputBinaries); 6248f6f6f40SSameer Arora if (!Slices) 6258f6f6f40SSameer Arora return Slices.takeError(); 6268f6f6f40SSameer Arora 6278f6f6f40SSameer Arora llvm::stable_sort(*Slices); 628c51f947aSRoger Kim return writeUniversalBinary(*Slices, OutputFile); 629303a7f7aSSameer Arora } 630303a7f7aSSameer Arora 631939c0351SAndres Villegas static void parseRawArgs(int Argc, char **Argv) { 632939c0351SAndres Villegas LibtoolDarwinOptTable Tbl; 633939c0351SAndres Villegas llvm::BumpPtrAllocator A; 634939c0351SAndres Villegas llvm::StringSaver Saver{A}; 635939c0351SAndres Villegas opt::InputArgList Args = 636939c0351SAndres Villegas Tbl.parseArgs(Argc, Argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) { 637939c0351SAndres Villegas llvm::errs() << Msg << '\n'; 638939c0351SAndres Villegas std::exit(1); 639939c0351SAndres Villegas }); 640939c0351SAndres Villegas 641939c0351SAndres Villegas if (Args.hasArg(OPT_help)) { 642939c0351SAndres Villegas Tbl.printHelp(llvm::outs(), "llvm-libtool-darwin [options] <input files>", 643939c0351SAndres Villegas "llvm-libtool-darwin"); 644939c0351SAndres Villegas std::exit(0); 645939c0351SAndres Villegas } 646939c0351SAndres Villegas 647939c0351SAndres Villegas InputFiles = Args.getAllArgValues(OPT_INPUT); 648939c0351SAndres Villegas Libraries = Args.getAllArgValues(OPT_libraries); 649939c0351SAndres Villegas LibrarySearchDirs = Args.getAllArgValues(OPT_librarySearchDirs); 650939c0351SAndres Villegas 651939c0351SAndres Villegas if (const opt::Arg *A = Args.getLastArg(OPT_outputFile)) 652939c0351SAndres Villegas OutputFile = A->getValue(); 653939c0351SAndres Villegas 654939c0351SAndres Villegas if (const opt::Arg *A = Args.getLastArg(OPT_archType)) 655939c0351SAndres Villegas ArchType = std::make_optional(A->getValue()); 656939c0351SAndres Villegas 657939c0351SAndres Villegas if (const opt::Arg *A = Args.getLastArg(OPT_fileList)) 658939c0351SAndres Villegas FileList = A->getValue(); 659939c0351SAndres Villegas 660939c0351SAndres Villegas if (const opt::Arg *A = Args.getLastArg(OPT_dependencyInfoPath)) 661939c0351SAndres Villegas DependencyInfoPath = A->getValue(); 662939c0351SAndres Villegas 663939c0351SAndres Villegas if (const opt::Arg *A = Args.getLastArg(OPT_ignoredSyslibRoot)) 664939c0351SAndres Villegas IgnoredSyslibRoot = A->getValue(); 665939c0351SAndres Villegas 666939c0351SAndres Villegas LibraryOperation = 667939c0351SAndres Villegas Args.hasArg(OPT_static) ? Operation::Static : Operation::None; 668939c0351SAndres Villegas DeterministicOption = Args.hasArg(OPT_deterministicOption); 669939c0351SAndres Villegas NonDeterministicOption = Args.hasArg(OPT_nonDeterministicOption); 670939c0351SAndres Villegas VersionOption = Args.hasArg(OPT_version); 671939c0351SAndres Villegas NoWarningForNoSymbols = Args.hasArg(OPT_noWarningForNoSymbols); 672939c0351SAndres Villegas WarningsAsErrors = Args.hasArg(OPT_warningsAsErrors); 673939c0351SAndres Villegas } 674939c0351SAndres Villegas 67571a1f135SSameer Arora static Expected<Config> parseCommandLine(int Argc, char **Argv) { 67671a1f135SSameer Arora Config C; 677939c0351SAndres Villegas parseRawArgs(Argc, Argv); 67871a1f135SSameer Arora 67968bae34cSShoaib Meenai if (LibraryOperation == Operation::None) { 68068bae34cSShoaib Meenai if (!VersionOption) { 681939c0351SAndres Villegas return createStringError(std::errc::invalid_argument, 682939c0351SAndres Villegas "-static option: must be specified"); 68368bae34cSShoaib Meenai } 68468bae34cSShoaib Meenai return C; 68568bae34cSShoaib Meenai } 68668bae34cSShoaib Meenai 68710f22335SKeith Smiley GlobalDependencyInfo = 68810f22335SKeith Smiley DependencyInfoPath.empty() 68910f22335SKeith Smiley ? std::make_unique<DummyDependencyInfo>() 69010f22335SKeith Smiley : std::make_unique<DependencyInfo>(DependencyInfoPath); 69110f22335SKeith Smiley 69268bae34cSShoaib Meenai if (OutputFile.empty()) { 693939c0351SAndres Villegas return createStringError(std::errc::invalid_argument, 694939c0351SAndres Villegas "-o option: must be specified"); 69568bae34cSShoaib Meenai } 69668bae34cSShoaib Meenai 69771a1f135SSameer Arora if (DeterministicOption && NonDeterministicOption) 69871a1f135SSameer Arora return createStringError(std::errc::invalid_argument, 69971a1f135SSameer Arora "cannot specify both -D and -U flags"); 70071a1f135SSameer Arora else if (NonDeterministicOption) 70171a1f135SSameer Arora C.Deterministic = false; 70271a1f135SSameer Arora 7031aed1e72SSameer Arora if (!Libraries.empty()) 7041aed1e72SSameer Arora if (Error E = processCommandLineLibraries()) 7051aed1e72SSameer Arora return std::move(E); 7061aed1e72SSameer Arora 70771a1f135SSameer Arora if (!FileList.empty()) 70871a1f135SSameer Arora if (Error E = processFileList()) 70971a1f135SSameer Arora return std::move(E); 71071a1f135SSameer Arora 71171a1f135SSameer Arora if (InputFiles.empty()) 71271a1f135SSameer Arora return createStringError(std::errc::invalid_argument, 71371a1f135SSameer Arora "no input files specified"); 71471a1f135SSameer Arora 715939c0351SAndres Villegas if (ArchType) { 716939c0351SAndres Villegas if (Error E = validateArchitectureName(ArchType.value())) 717bd2853f7SSameer Arora return std::move(E); 718bd2853f7SSameer Arora 7198f6f6f40SSameer Arora std::tie(C.ArchCPUType, C.ArchCPUSubtype) = 7208f6f6f40SSameer Arora MachO::getCPUTypeFromArchitecture( 721939c0351SAndres Villegas MachO::getArchitectureFromName(ArchType.value())); 7228f6f6f40SSameer Arora } 7238f6f6f40SSameer Arora 72410f22335SKeith Smiley GlobalDependencyInfo->write("llvm-libtool-darwin " LLVM_VERSION_STRING, 72510f22335SKeith Smiley InputFiles, OutputFile); 72610f22335SKeith Smiley 72771a1f135SSameer Arora return C; 72871a1f135SSameer Arora } 72971a1f135SSameer Arora 730668e33c6SAndrés Villegas int llvm_libtool_darwin_main(int Argc, char **Argv, const llvm::ToolContext &) { 73171a1f135SSameer Arora Expected<Config> ConfigOrErr = parseCommandLine(Argc, Argv); 73271a1f135SSameer Arora if (!ConfigOrErr) { 73371a1f135SSameer Arora WithColor::defaultErrorHandler(ConfigOrErr.takeError()); 734d9a91929SSameer Arora return EXIT_FAILURE; 735d9a91929SSameer Arora } 736303a7f7aSSameer Arora 73768bae34cSShoaib Meenai if (VersionOption) 73868bae34cSShoaib Meenai cl::PrintVersionMessage(); 73968bae34cSShoaib Meenai 740dbed14d2SKeith Smiley llvm::InitializeAllTargetInfos(); 741dbed14d2SKeith Smiley llvm::InitializeAllTargetMCs(); 742dbed14d2SKeith Smiley llvm::InitializeAllAsmParsers(); 743dbed14d2SKeith Smiley 7443210647eSArthur Eubanks LLVMContext LLVMCtx; 74571a1f135SSameer Arora Config C = *ConfigOrErr; 746303a7f7aSSameer Arora switch (LibraryOperation) { 74768bae34cSShoaib Meenai case Operation::None: 74868bae34cSShoaib Meenai break; 749303a7f7aSSameer Arora case Operation::Static: 7503210647eSArthur Eubanks if (Error E = createStaticLibrary(LLVMCtx, C)) { 751303a7f7aSSameer Arora WithColor::defaultErrorHandler(std::move(E)); 752d9a91929SSameer Arora return EXIT_FAILURE; 753303a7f7aSSameer Arora } 754303a7f7aSSameer Arora break; 755303a7f7aSSameer Arora } 756668e33c6SAndrés Villegas return EXIT_SUCCESS; 7576c43ed60SSameer Arora } 758