xref: /llvm-project/llvm/tools/llvm-libtool-darwin/llvm-libtool-darwin.cpp (revision dd647e3e608ed0b2bac7c588d5859b80ef4a5976)
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