llvm-libtool-darwin.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  1. //===-- llvm-libtool-darwin.cpp - a tool for creating libraries -----------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // A utility for creating static and dynamic libraries for Darwin.
  10. //
  11. //===----------------------------------------------------------------------===//
  12. #include "llvm/BinaryFormat/Magic.h"
  13. #include "llvm/IR/LLVMContext.h"
  14. #include "llvm/Object/ArchiveWriter.h"
  15. #include "llvm/Object/IRObjectFile.h"
  16. #include "llvm/Object/MachO.h"
  17. #include "llvm/Object/MachOUniversal.h"
  18. #include "llvm/Object/MachOUniversalWriter.h"
  19. #include "llvm/Object/ObjectFile.h"
  20. #include "llvm/Support/CommandLine.h"
  21. #include "llvm/Support/InitLLVM.h"
  22. #include "llvm/Support/LineIterator.h"
  23. #include "llvm/Support/WithColor.h"
  24. #include "llvm/TextAPI/MachO/Architecture.h"
  25. #include <map>
  26. using namespace llvm;
  27. using namespace llvm::object;
  28. static LLVMContext LLVMCtx;
  29. typedef std::map<uint64_t, std::vector<NewArchiveMember>>
  30. MembersPerArchitectureMap;
  31. cl::OptionCategory LibtoolCategory("llvm-libtool-darwin Options");
  32. static cl::opt<std::string> OutputFile("o", cl::desc("Specify output filename"),
  33. cl::value_desc("filename"),
  34. cl::cat(LibtoolCategory));
  35. static cl::list<std::string> InputFiles(cl::Positional,
  36. cl::desc("<input files>"),
  37. cl::ZeroOrMore,
  38. cl::cat(LibtoolCategory));
  39. static cl::opt<std::string> ArchType(
  40. "arch_only", cl::desc("Specify architecture type for output library"),
  41. cl::value_desc("arch_type"), cl::ZeroOrMore, cl::cat(LibtoolCategory));
  42. enum class Operation { None, Static };
  43. static cl::opt<Operation> LibraryOperation(
  44. cl::desc("Library Type: "),
  45. cl::values(
  46. clEnumValN(Operation::Static, "static",
  47. "Produce a statically linked library from the input files")),
  48. cl::init(Operation::None), cl::cat(LibtoolCategory));
  49. static cl::opt<bool> DeterministicOption(
  50. "D", cl::desc("Use zero for timestamps and UIDs/GIDs (Default)"),
  51. cl::init(false), cl::cat(LibtoolCategory));
  52. static cl::opt<bool>
  53. NonDeterministicOption("U", cl::desc("Use actual timestamps and UIDs/GIDs"),
  54. cl::init(false), cl::cat(LibtoolCategory));
  55. static cl::opt<std::string>
  56. FileList("filelist",
  57. cl::desc("Pass in file containing a list of filenames"),
  58. cl::value_desc("listfile[,dirname]"), cl::cat(LibtoolCategory));
  59. static cl::list<std::string> Libraries(
  60. "l",
  61. cl::desc(
  62. "l<x> searches for the library libx.a in the library search path. If"
  63. " the string 'x' ends with '.o', then the library 'x' is searched for"
  64. " without prepending 'lib' or appending '.a'"),
  65. cl::ZeroOrMore, cl::Prefix, cl::cat(LibtoolCategory));
  66. static cl::list<std::string> LibrarySearchDirs(
  67. "L",
  68. cl::desc(
  69. "L<dir> adds <dir> to the list of directories in which to search for"
  70. " libraries"),
  71. cl::ZeroOrMore, cl::Prefix, cl::cat(LibtoolCategory));
  72. static cl::opt<bool>
  73. VersionOption("V", cl::desc("Print the version number and exit"),
  74. cl::cat(LibtoolCategory));
  75. static const std::array<std::string, 3> StandardSearchDirs{
  76. "/lib",
  77. "/usr/lib",
  78. "/usr/local/lib",
  79. };
  80. struct Config {
  81. bool Deterministic = true; // Updated by 'D' and 'U' modifiers.
  82. uint32_t ArchCPUType;
  83. uint32_t ArchCPUSubtype;
  84. };
  85. static Expected<std::string> searchForFile(const Twine &FileName) {
  86. auto FindLib =
  87. [FileName](ArrayRef<std::string> SearchDirs) -> Optional<std::string> {
  88. for (StringRef Dir : SearchDirs) {
  89. SmallString<128> Path;
  90. sys::path::append(Path, Dir, FileName);
  91. if (sys::fs::exists(Path))
  92. return std::string(Path);
  93. }
  94. return None;
  95. };
  96. Optional<std::string> Found = FindLib(LibrarySearchDirs);
  97. if (!Found)
  98. Found = FindLib(StandardSearchDirs);
  99. if (Found)
  100. return *Found;
  101. return createStringError(std::errc::invalid_argument,
  102. "cannot locate file '%s'", FileName.str().c_str());
  103. }
  104. static Error processCommandLineLibraries() {
  105. for (StringRef BaseName : Libraries) {
  106. Expected<std::string> FullPath = searchForFile(
  107. BaseName.endswith(".o") ? BaseName.str() : "lib" + BaseName + ".a");
  108. if (!FullPath)
  109. return FullPath.takeError();
  110. InputFiles.push_back(FullPath.get());
  111. }
  112. return Error::success();
  113. }
  114. static Error processFileList() {
  115. StringRef FileName, DirName;
  116. std::tie(FileName, DirName) = StringRef(FileList).rsplit(",");
  117. ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr =
  118. MemoryBuffer::getFileOrSTDIN(FileName, /*FileSize=*/-1,
  119. /*RequiresNullTerminator=*/false);
  120. if (std::error_code EC = FileOrErr.getError())
  121. return createFileError(FileName, errorCodeToError(EC));
  122. const MemoryBuffer &Ref = *FileOrErr.get();
  123. line_iterator I(Ref, /*SkipBlanks=*/false);
  124. if (I.is_at_eof())
  125. return createStringError(std::errc::invalid_argument,
  126. "file list file: '%s' is empty",
  127. FileName.str().c_str());
  128. for (; !I.is_at_eof(); ++I) {
  129. StringRef Line = *I;
  130. if (Line.empty())
  131. return createStringError(std::errc::invalid_argument,
  132. "file list file: '%s': filename cannot be empty",
  133. FileName.str().c_str());
  134. SmallString<128> Path;
  135. if (!DirName.empty())
  136. sys::path::append(Path, DirName, Line);
  137. else
  138. sys::path::append(Path, Line);
  139. InputFiles.push_back(static_cast<std::string>(Path));
  140. }
  141. return Error::success();
  142. }
  143. static Error validateArchitectureName(StringRef ArchitectureName) {
  144. if (!MachOObjectFile::isValidArch(ArchitectureName)) {
  145. std::string Buf;
  146. raw_string_ostream OS(Buf);
  147. for (StringRef Arch : MachOObjectFile::getValidArchs())
  148. OS << Arch << " ";
  149. return createStringError(
  150. std::errc::invalid_argument,
  151. "invalid architecture '%s': valid architecture names are %s",
  152. ArchitectureName.str().c_str(), OS.str().c_str());
  153. }
  154. return Error::success();
  155. }
  156. static uint64_t getCPUID(uint32_t CPUType, uint32_t CPUSubtype) {
  157. switch (CPUType) {
  158. case MachO::CPU_TYPE_ARM:
  159. case MachO::CPU_TYPE_ARM64:
  160. case MachO::CPU_TYPE_ARM64_32:
  161. case MachO::CPU_TYPE_X86_64:
  162. // We consider CPUSubtype only for the above 4 CPUTypes to match cctools'
  163. // libtool behavior.
  164. return static_cast<uint64_t>(CPUType) << 32 | CPUSubtype;
  165. default:
  166. return CPUType;
  167. }
  168. }
  169. // Check that a file's architecture [FileCPUType, FileCPUSubtype]
  170. // matches the architecture specified under -arch_only flag.
  171. static bool acceptFileArch(uint32_t FileCPUType, uint32_t FileCPUSubtype,
  172. const Config &C) {
  173. if (C.ArchCPUType != FileCPUType)
  174. return false;
  175. switch (C.ArchCPUType) {
  176. case MachO::CPU_TYPE_ARM:
  177. case MachO::CPU_TYPE_ARM64_32:
  178. case MachO::CPU_TYPE_X86_64:
  179. return C.ArchCPUSubtype == FileCPUSubtype;
  180. case MachO::CPU_TYPE_ARM64:
  181. if (C.ArchCPUSubtype == MachO::CPU_SUBTYPE_ARM64_ALL)
  182. return FileCPUSubtype == MachO::CPU_SUBTYPE_ARM64_ALL ||
  183. FileCPUSubtype == MachO::CPU_SUBTYPE_ARM64_V8;
  184. else
  185. return C.ArchCPUSubtype == FileCPUSubtype;
  186. default:
  187. return true;
  188. }
  189. }
  190. static Error verifyAndAddMachOObject(MembersPerArchitectureMap &Members,
  191. NewArchiveMember Member, const Config &C) {
  192. auto MBRef = Member.Buf->getMemBufferRef();
  193. Expected<std::unique_ptr<object::ObjectFile>> ObjOrErr =
  194. object::ObjectFile::createObjectFile(MBRef);
  195. // Throw error if not a valid object file.
  196. if (!ObjOrErr)
  197. return createFileError(Member.MemberName, ObjOrErr.takeError());
  198. // Throw error if not in Mach-O format.
  199. if (!isa<object::MachOObjectFile>(**ObjOrErr))
  200. return createStringError(std::errc::invalid_argument,
  201. "'%s': format not supported",
  202. Member.MemberName.data());
  203. auto *O = dyn_cast<MachOObjectFile>(ObjOrErr->get());
  204. uint32_t FileCPUType, FileCPUSubtype;
  205. std::tie(FileCPUType, FileCPUSubtype) = MachO::getCPUTypeFromArchitecture(
  206. MachO::getArchitectureFromName(O->getArchTriple().getArchName()));
  207. // If -arch_only is specified then skip this file if it doesn't match
  208. // the architecture specified.
  209. if (!ArchType.empty() && !acceptFileArch(FileCPUType, FileCPUSubtype, C)) {
  210. return Error::success();
  211. }
  212. uint64_t FileCPUID = getCPUID(FileCPUType, FileCPUSubtype);
  213. Members[FileCPUID].push_back(std::move(Member));
  214. return Error::success();
  215. }
  216. static Error verifyAndAddIRObject(MembersPerArchitectureMap &Members,
  217. NewArchiveMember Member, const Config &C) {
  218. auto MBRef = Member.Buf->getMemBufferRef();
  219. Expected<std::unique_ptr<object::IRObjectFile>> IROrErr =
  220. object::IRObjectFile::create(MBRef, LLVMCtx);
  221. // Throw error if not a valid IR object file.
  222. if (!IROrErr)
  223. return createFileError(Member.MemberName, IROrErr.takeError());
  224. Triple TT = Triple(IROrErr->get()->getTargetTriple());
  225. Expected<uint32_t> FileCPUTypeOrErr = MachO::getCPUType(TT);
  226. if (!FileCPUTypeOrErr)
  227. return FileCPUTypeOrErr.takeError();
  228. Expected<uint32_t> FileCPUSubTypeOrErr = MachO::getCPUSubType(TT);
  229. if (!FileCPUSubTypeOrErr)
  230. return FileCPUSubTypeOrErr.takeError();
  231. // If -arch_only is specified then skip this file if it doesn't match
  232. // the architecture specified.
  233. if (!ArchType.empty() &&
  234. !acceptFileArch(*FileCPUTypeOrErr, *FileCPUSubTypeOrErr, C)) {
  235. return Error::success();
  236. }
  237. uint64_t FileCPUID = getCPUID(*FileCPUTypeOrErr, *FileCPUSubTypeOrErr);
  238. Members[FileCPUID].push_back(std::move(Member));
  239. return Error::success();
  240. }
  241. static Error addChildMember(MembersPerArchitectureMap &Members,
  242. const object::Archive::Child &M, const Config &C) {
  243. Expected<NewArchiveMember> NMOrErr =
  244. NewArchiveMember::getOldMember(M, C.Deterministic);
  245. if (!NMOrErr)
  246. return NMOrErr.takeError();
  247. file_magic Magic = identify_magic(NMOrErr->Buf->getBuffer());
  248. if (Magic == file_magic::bitcode)
  249. return verifyAndAddIRObject(Members, std::move(*NMOrErr), C);
  250. if (Error E = verifyAndAddMachOObject(Members, std::move(*NMOrErr), C))
  251. return E;
  252. return Error::success();
  253. }
  254. static Error processArchive(MembersPerArchitectureMap &Members,
  255. object::Archive &Lib, StringRef FileName,
  256. const Config &C) {
  257. Error Err = Error::success();
  258. for (const object::Archive::Child &Child : Lib.children(Err))
  259. if (Error E = addChildMember(Members, Child, C))
  260. return createFileError(FileName, std::move(E));
  261. if (Err)
  262. return createFileError(FileName, std::move(Err));
  263. return Error::success();
  264. }
  265. static Error
  266. addArchiveMembers(MembersPerArchitectureMap &Members,
  267. std::vector<std::unique_ptr<MemoryBuffer>> &ArchiveBuffers,
  268. NewArchiveMember NM, StringRef FileName, const Config &C) {
  269. Expected<std::unique_ptr<Archive>> LibOrErr =
  270. object::Archive::create(NM.Buf->getMemBufferRef());
  271. if (!LibOrErr)
  272. return createFileError(FileName, LibOrErr.takeError());
  273. if (Error E = processArchive(Members, **LibOrErr, FileName, C))
  274. return E;
  275. // Update vector ArchiveBuffers with the MemoryBuffers to transfer
  276. // ownership.
  277. ArchiveBuffers.push_back(std::move(NM.Buf));
  278. return Error::success();
  279. }
  280. static Error addUniversalMembers(
  281. MembersPerArchitectureMap &Members,
  282. std::vector<std::unique_ptr<MemoryBuffer>> &UniversalBuffers,
  283. NewArchiveMember NM, StringRef FileName, const Config &C) {
  284. Expected<std::unique_ptr<MachOUniversalBinary>> BinaryOrErr =
  285. MachOUniversalBinary::create(NM.Buf->getMemBufferRef());
  286. if (!BinaryOrErr)
  287. return createFileError(FileName, BinaryOrErr.takeError());
  288. auto *UO = BinaryOrErr->get();
  289. for (const MachOUniversalBinary::ObjectForArch &O : UO->objects()) {
  290. Expected<std::unique_ptr<MachOObjectFile>> MachOObjOrErr =
  291. O.getAsObjectFile();
  292. if (MachOObjOrErr) {
  293. NewArchiveMember NewMember =
  294. NewArchiveMember(MachOObjOrErr->get()->getMemoryBufferRef());
  295. NewMember.MemberName = sys::path::filename(NewMember.MemberName);
  296. if (Error E = verifyAndAddMachOObject(Members, std::move(NewMember), C))
  297. return E;
  298. continue;
  299. }
  300. Expected<std::unique_ptr<IRObjectFile>> IRObjectOrError =
  301. O.getAsIRObject(LLVMCtx);
  302. if (IRObjectOrError) {
  303. // A universal file member can be a MachOObjectFile, an IRObject or an
  304. // Archive. In case we can successfully cast the member as an IRObject, it
  305. // is safe to throw away the error generated due to casting the object as
  306. // a MachOObjectFile.
  307. consumeError(MachOObjOrErr.takeError());
  308. NewArchiveMember NewMember =
  309. NewArchiveMember(IRObjectOrError->get()->getMemoryBufferRef());
  310. NewMember.MemberName = sys::path::filename(NewMember.MemberName);
  311. if (Error E = verifyAndAddIRObject(Members, std::move(NewMember), C))
  312. return E;
  313. continue;
  314. }
  315. Expected<std::unique_ptr<Archive>> ArchiveOrError = O.getAsArchive();
  316. if (ArchiveOrError) {
  317. // A universal file member can be a MachOObjectFile, an IRObject or an
  318. // Archive. In case we can successfully cast the member as an Archive, it
  319. // is safe to throw away the error generated due to casting the object as
  320. // a MachOObjectFile.
  321. consumeError(MachOObjOrErr.takeError());
  322. consumeError(IRObjectOrError.takeError());
  323. if (Error E = processArchive(Members, **ArchiveOrError, FileName, C))
  324. return E;
  325. continue;
  326. }
  327. Error CombinedError = joinErrors(
  328. ArchiveOrError.takeError(),
  329. joinErrors(IRObjectOrError.takeError(), MachOObjOrErr.takeError()));
  330. return createFileError(FileName, std::move(CombinedError));
  331. }
  332. // Update vector UniversalBuffers with the MemoryBuffers to transfer
  333. // ownership.
  334. UniversalBuffers.push_back(std::move(NM.Buf));
  335. return Error::success();
  336. }
  337. static Error addMember(MembersPerArchitectureMap &Members,
  338. std::vector<std::unique_ptr<MemoryBuffer>> &FileBuffers,
  339. StringRef FileName, const Config &C) {
  340. Expected<NewArchiveMember> NMOrErr =
  341. NewArchiveMember::getFile(FileName, C.Deterministic);
  342. if (!NMOrErr)
  343. return createFileError(FileName, NMOrErr.takeError());
  344. // For regular archives, use the basename of the object path for the member
  345. // name.
  346. NMOrErr->MemberName = sys::path::filename(NMOrErr->MemberName);
  347. file_magic Magic = identify_magic(NMOrErr->Buf->getBuffer());
  348. // Flatten archives.
  349. if (Magic == file_magic::archive)
  350. return addArchiveMembers(Members, FileBuffers, std::move(*NMOrErr),
  351. FileName, C);
  352. // Flatten universal files.
  353. if (Magic == file_magic::macho_universal_binary)
  354. return addUniversalMembers(Members, FileBuffers, std::move(*NMOrErr),
  355. FileName, C);
  356. // Bitcode files.
  357. if (Magic == file_magic::bitcode)
  358. return verifyAndAddIRObject(Members, std::move(*NMOrErr), C);
  359. if (Error E = verifyAndAddMachOObject(Members, std::move(*NMOrErr), C))
  360. return E;
  361. return Error::success();
  362. }
  363. static Expected<SmallVector<Slice, 2>>
  364. buildSlices(ArrayRef<OwningBinary<Archive>> OutputBinaries) {
  365. SmallVector<Slice, 2> Slices;
  366. for (const auto &OB : OutputBinaries) {
  367. const Archive &A = *OB.getBinary();
  368. Expected<Slice> ArchiveSlice = Slice::create(A, &LLVMCtx);
  369. if (!ArchiveSlice)
  370. return ArchiveSlice.takeError();
  371. Slices.push_back(*ArchiveSlice);
  372. }
  373. return Slices;
  374. }
  375. static Error createStaticLibrary(const Config &C) {
  376. MembersPerArchitectureMap NewMembers;
  377. std::vector<std::unique_ptr<MemoryBuffer>> FileBuffers;
  378. for (StringRef FileName : InputFiles)
  379. if (Error E = addMember(NewMembers, FileBuffers, FileName, C))
  380. return E;
  381. if (!ArchType.empty()) {
  382. uint64_t ArchCPUID = getCPUID(C.ArchCPUType, C.ArchCPUSubtype);
  383. if (NewMembers.find(ArchCPUID) == NewMembers.end())
  384. return createStringError(std::errc::invalid_argument,
  385. "no library created (no object files in input "
  386. "files matching -arch_only %s)",
  387. ArchType.c_str());
  388. }
  389. if (NewMembers.size() == 1) {
  390. if (Error E =
  391. writeArchive(OutputFile, NewMembers.begin()->second,
  392. /*WriteSymtab=*/true,
  393. /*Kind=*/object::Archive::K_DARWIN, C.Deterministic,
  394. /*Thin=*/false))
  395. return E;
  396. } else {
  397. SmallVector<OwningBinary<Archive>, 2> OutputBinaries;
  398. for (const std::pair<const uint64_t, std::vector<NewArchiveMember>> &M :
  399. NewMembers) {
  400. Expected<std::unique_ptr<MemoryBuffer>> OutputBufferOrErr =
  401. writeArchiveToBuffer(M.second,
  402. /*WriteSymtab=*/true,
  403. /*Kind=*/object::Archive::K_DARWIN,
  404. C.Deterministic,
  405. /*Thin=*/false);
  406. if (!OutputBufferOrErr)
  407. return OutputBufferOrErr.takeError();
  408. std::unique_ptr<MemoryBuffer> &OutputBuffer = OutputBufferOrErr.get();
  409. Expected<std::unique_ptr<Archive>> ArchiveOrError =
  410. Archive::create(OutputBuffer->getMemBufferRef());
  411. if (!ArchiveOrError)
  412. return ArchiveOrError.takeError();
  413. std::unique_ptr<Archive> &A = ArchiveOrError.get();
  414. OutputBinaries.push_back(
  415. OwningBinary<Archive>(std::move(A), std::move(OutputBuffer)));
  416. }
  417. Expected<SmallVector<Slice, 2>> Slices = buildSlices(OutputBinaries);
  418. if (!Slices)
  419. return Slices.takeError();
  420. llvm::stable_sort(*Slices);
  421. if (Error E = writeUniversalBinary(*Slices, OutputFile))
  422. return E;
  423. }
  424. return Error::success();
  425. }
  426. static Expected<Config> parseCommandLine(int Argc, char **Argv) {
  427. Config C;
  428. cl::ParseCommandLineOptions(Argc, Argv, "llvm-libtool-darwin\n");
  429. if (LibraryOperation == Operation::None) {
  430. if (!VersionOption) {
  431. std::string Error;
  432. raw_string_ostream Stream(Error);
  433. LibraryOperation.error("must be specified", "", Stream);
  434. return createStringError(std::errc::invalid_argument, Error.c_str());
  435. }
  436. return C;
  437. }
  438. if (OutputFile.empty()) {
  439. std::string Error;
  440. raw_string_ostream Stream(Error);
  441. OutputFile.error("must be specified", "o", Stream);
  442. return createStringError(std::errc::invalid_argument, Error.c_str());
  443. }
  444. if (DeterministicOption && NonDeterministicOption)
  445. return createStringError(std::errc::invalid_argument,
  446. "cannot specify both -D and -U flags");
  447. else if (NonDeterministicOption)
  448. C.Deterministic = false;
  449. if (!Libraries.empty())
  450. if (Error E = processCommandLineLibraries())
  451. return std::move(E);
  452. if (!FileList.empty())
  453. if (Error E = processFileList())
  454. return std::move(E);
  455. if (InputFiles.empty())
  456. return createStringError(std::errc::invalid_argument,
  457. "no input files specified");
  458. if (ArchType.getNumOccurrences()) {
  459. if (Error E = validateArchitectureName(ArchType))
  460. return std::move(E);
  461. std::tie(C.ArchCPUType, C.ArchCPUSubtype) =
  462. MachO::getCPUTypeFromArchitecture(
  463. MachO::getArchitectureFromName(ArchType));
  464. }
  465. return C;
  466. }
  467. int main(int Argc, char **Argv) {
  468. InitLLVM X(Argc, Argv);
  469. cl::HideUnrelatedOptions({&LibtoolCategory, &ColorCategory});
  470. Expected<Config> ConfigOrErr = parseCommandLine(Argc, Argv);
  471. if (!ConfigOrErr) {
  472. WithColor::defaultErrorHandler(ConfigOrErr.takeError());
  473. return EXIT_FAILURE;
  474. }
  475. if (VersionOption)
  476. cl::PrintVersionMessage();
  477. Config C = *ConfigOrErr;
  478. switch (LibraryOperation) {
  479. case Operation::None:
  480. break;
  481. case Operation::Static:
  482. if (Error E = createStaticLibrary(C)) {
  483. WithColor::defaultErrorHandler(std::move(E));
  484. return EXIT_FAILURE;
  485. }
  486. break;
  487. }
  488. }