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 13 #include "DependencyInfo.h" 14 #include "llvm/ADT/MapVector.h" 15 #include "llvm/BinaryFormat/Magic.h" 16 #include "llvm/IR/LLVMContext.h" 17 #include "llvm/Object/ArchiveWriter.h" 18 #include "llvm/Object/IRObjectFile.h" 19 #include "llvm/Object/MachO.h" 20 #include "llvm/Object/MachOUniversal.h" 21 #include "llvm/Object/MachOUniversalWriter.h" 22 #include "llvm/Object/ObjectFile.h" 23 #include "llvm/Option/ArgList.h" 24 #include "llvm/Option/Option.h" 25 #include "llvm/Support/CommandLine.h" 26 #include "llvm/Support/LLVMDriver.h" 27 #include "llvm/Support/LineIterator.h" 28 #include "llvm/Support/TargetSelect.h" 29 #include "llvm/Support/VirtualFileSystem.h" 30 #include "llvm/Support/WithColor.h" 31 #include "llvm/Support/YAMLTraits.h" 32 #include "llvm/Support/raw_ostream.h" 33 #include "llvm/TextAPI/Architecture.h" 34 #include <cstdlib> 35 #include <map> 36 #include <type_traits> 37 38 using namespace llvm; 39 using namespace llvm::object; 40 using namespace llvm::opt; 41 42 // Command-line option boilerplate. 43 namespace { 44 enum ID { 45 OPT_INVALID = 0, // This is not an option ID. 46 #define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__), 47 #include "Opts.inc" 48 #undef OPTION 49 }; 50 51 #define OPTTABLE_STR_TABLE_CODE 52 #include "Opts.inc" 53 #undef OPTTABLE_STR_TABLE_CODE 54 55 #define OPTTABLE_PREFIXES_TABLE_CODE 56 #include "Opts.inc" 57 #undef OPTTABLE_PREFIXES_TABLE_CODE 58 59 static constexpr opt::OptTable::Info InfoTable[] = { 60 #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__), 61 #include "Opts.inc" 62 #undef OPTION 63 }; 64 65 class LibtoolDarwinOptTable : public opt::GenericOptTable { 66 public: 67 LibtoolDarwinOptTable() 68 : GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {} 69 }; 70 } // end anonymous namespace 71 72 class NewArchiveMemberList; 73 typedef std::map<uint64_t, NewArchiveMemberList> MembersPerArchitectureMap; 74 75 static std::string OutputFile; 76 static std::vector<std::string> InputFiles; 77 static std::optional<std::string> ArchType; 78 79 enum class Operation { None, Static }; 80 static Operation LibraryOperation = Operation::None; 81 82 static bool DeterministicOption; 83 static bool NonDeterministicOption; 84 static std::string FileList; 85 static std::vector<std::string> Libraries; 86 static std::vector<std::string> LibrarySearchDirs; 87 static std::string DependencyInfoPath; 88 static bool VersionOption; 89 static bool NoWarningForNoSymbols; 90 static bool WarningsAsErrors; 91 static std::string IgnoredSyslibRoot; 92 93 static const std::array<std::string, 3> StandardSearchDirs{ 94 "/lib", 95 "/usr/lib", 96 "/usr/local/lib", 97 }; 98 99 std::unique_ptr<DependencyInfo> GlobalDependencyInfo; 100 101 struct Config { 102 bool Deterministic = true; // Updated by 'D' and 'U' modifiers. 103 uint32_t ArchCPUType; 104 uint32_t ArchCPUSubtype; 105 }; 106 107 static Expected<std::string> searchForFile(const Twine &FileName) { 108 auto FindLib = 109 [FileName]( 110 ArrayRef<std::string> SearchDirs) -> std::optional<std::string> { 111 for (StringRef Dir : SearchDirs) { 112 SmallString<128> Path; 113 sys::path::append(Path, Dir, FileName); 114 115 if (sys::fs::exists(Path)) 116 return std::string(Path); 117 118 GlobalDependencyInfo->addMissingInput(Path); 119 } 120 return std::nullopt; 121 }; 122 123 std::optional<std::string> Found = FindLib(LibrarySearchDirs); 124 if (!Found) 125 Found = FindLib(StandardSearchDirs); 126 if (Found) 127 return *Found; 128 129 return createStringError(std::errc::invalid_argument, 130 "cannot locate file '%s'", FileName.str().c_str()); 131 } 132 133 static Error processCommandLineLibraries() { 134 for (StringRef BaseName : Libraries) { 135 Expected<std::string> FullPath = searchForFile( 136 BaseName.ends_with(".o") ? BaseName.str() : "lib" + BaseName + ".a"); 137 if (!FullPath) 138 return FullPath.takeError(); 139 InputFiles.push_back(FullPath.get()); 140 } 141 142 return Error::success(); 143 } 144 145 static Error processFileList() { 146 StringRef FileName, DirName; 147 std::tie(FileName, DirName) = StringRef(FileList).rsplit(","); 148 149 ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr = 150 MemoryBuffer::getFileOrSTDIN(FileName, /*IsText=*/false, 151 /*RequiresNullTerminator=*/false); 152 if (std::error_code EC = FileOrErr.getError()) 153 return createFileError(FileName, errorCodeToError(EC)); 154 const MemoryBuffer &Ref = *FileOrErr.get(); 155 156 line_iterator I(Ref, /*SkipBlanks=*/false); 157 if (I.is_at_eof()) 158 return createStringError(std::errc::invalid_argument, 159 "file list file: '%s' is empty", 160 FileName.str().c_str()); 161 for (; !I.is_at_eof(); ++I) { 162 StringRef Line = *I; 163 if (Line.empty()) 164 return createStringError(std::errc::invalid_argument, 165 "file list file: '%s': filename cannot be empty", 166 FileName.str().c_str()); 167 168 SmallString<128> Path; 169 if (!DirName.empty()) 170 sys::path::append(Path, DirName, Line); 171 else 172 sys::path::append(Path, Line); 173 InputFiles.push_back(static_cast<std::string>(Path)); 174 } 175 return Error::success(); 176 } 177 178 static Error validateArchitectureName(StringRef ArchitectureName) { 179 if (!MachOObjectFile::isValidArch(ArchitectureName)) { 180 std::string Buf; 181 raw_string_ostream OS(Buf); 182 for (StringRef Arch : MachOObjectFile::getValidArchs()) 183 OS << Arch << " "; 184 185 return createStringError( 186 std::errc::invalid_argument, 187 "invalid architecture '%s': valid architecture names are %s", 188 ArchitectureName.str().c_str(), Buf.c_str()); 189 } 190 return Error::success(); 191 } 192 193 static uint64_t getCPUID(uint32_t CPUType, uint32_t CPUSubtype) { 194 switch (CPUType) { 195 case MachO::CPU_TYPE_ARM: 196 case MachO::CPU_TYPE_ARM64: 197 case MachO::CPU_TYPE_ARM64_32: 198 case MachO::CPU_TYPE_X86_64: 199 // We consider CPUSubtype only for the above 4 CPUTypes to match cctools' 200 // libtool behavior. 201 return static_cast<uint64_t>(CPUType) << 32 | CPUSubtype; 202 default: 203 return CPUType; 204 } 205 } 206 207 // MembersData is an organized collection of members. 208 struct MembersData { 209 // MembersPerArchitectureMap is a mapping from CPU architecture to a list of 210 // members. 211 MembersPerArchitectureMap MembersPerArchitecture; 212 std::vector<std::unique_ptr<MemoryBuffer>> FileBuffers; 213 }; 214 215 // NewArchiveMemberList instances serve as collections of archive members and 216 // information about those members. 217 class NewArchiveMemberList { 218 std::vector<NewArchiveMember> Members; 219 // This vector contains the file that each NewArchiveMember from Members came 220 // from. Therefore, it has the same size as Members. 221 std::vector<StringRef> Files; 222 223 public: 224 // Add a NewArchiveMember and the file it came from to the list. 225 void push_back(NewArchiveMember &&Member, StringRef File) { 226 Members.push_back(std::move(Member)); 227 Files.push_back(File); 228 } 229 230 ArrayRef<NewArchiveMember> getMembers() const { return Members; } 231 232 ArrayRef<StringRef> getFiles() const { return Files; } 233 234 static_assert( 235 std::is_same<decltype(MembersData::MembersPerArchitecture)::mapped_type, 236 NewArchiveMemberList>(), 237 "This test makes sure NewArchiveMemberList is used by MembersData since " 238 "the following asserts test invariants required for MembersData."); 239 static_assert( 240 !std::is_copy_constructible_v< 241 decltype(NewArchiveMemberList::Members)::value_type>, 242 "MembersData::MembersPerArchitecture has a dependency on " 243 "MembersData::FileBuffers so it should not be able to " 244 "be copied on its own without FileBuffers. Unfortunately, " 245 "is_copy_constructible does not detect whether the container (ie vector) " 246 "of a non-copyable type is itself non-copyable so we have to test the " 247 "actual type of the stored data (ie, value_type)."); 248 static_assert( 249 !std::is_copy_assignable_v< 250 decltype(NewArchiveMemberList::Members)::value_type>, 251 "MembersData::MembersPerArchitecture has a dependency on " 252 "MembersData::FileBuffers so it should not be able to " 253 "be copied on its own without FileBuffers. Unfortunately, " 254 "is_copy_constructible does not detect whether the container (ie vector) " 255 "of a non-copyable type is itself non-copyable so we have to test the " 256 "actual type of the stored data (ie, value_type)."); 257 }; 258 259 // MembersBuilder collects and organizes all members from the files provided by 260 // the user. 261 class MembersBuilder { 262 public: 263 MembersBuilder(LLVMContext &LLVMCtx, const Config &C) 264 : LLVMCtx(LLVMCtx), C(C) {} 265 266 Expected<MembersData> build() { 267 for (StringRef FileName : InputFiles) 268 if (Error E = AddMember(*this, FileName)()) 269 return std::move(E); 270 271 std::string Arch = ArchType.value_or(""); 272 if (!Arch.empty()) { 273 uint64_t ArchCPUID = getCPUID(C.ArchCPUType, C.ArchCPUSubtype); 274 if (Data.MembersPerArchitecture.find(ArchCPUID) == 275 Data.MembersPerArchitecture.end()) 276 return createStringError(std::errc::invalid_argument, 277 "no library created (no object files in input " 278 "files matching -arch_only %s)", 279 Arch.c_str()); 280 } 281 return std::move(Data); 282 } 283 284 private: 285 class AddMember { 286 MembersBuilder &Builder; 287 StringRef FileName; 288 289 public: 290 AddMember(MembersBuilder &Builder, StringRef FileName) 291 : Builder(Builder), FileName(FileName) {} 292 293 Error operator()() { 294 Expected<NewArchiveMember> NewMemberOrErr = 295 NewArchiveMember::getFile(FileName, Builder.C.Deterministic); 296 if (!NewMemberOrErr) 297 return createFileError(FileName, NewMemberOrErr.takeError()); 298 auto &NewMember = *NewMemberOrErr; 299 300 // For regular archives, use the basename of the object path for the 301 // member name. 302 NewMember.MemberName = sys::path::filename(NewMember.MemberName); 303 file_magic Magic = identify_magic(NewMember.Buf->getBuffer()); 304 305 // Flatten archives. 306 if (Magic == file_magic::archive) 307 return addArchiveMembers(std::move(NewMember)); 308 309 // Flatten universal files. 310 if (Magic == file_magic::macho_universal_binary) 311 return addUniversalMembers(std::move(NewMember)); 312 313 // Bitcode files. 314 if (Magic == file_magic::bitcode) 315 return verifyAndAddIRObject(std::move(NewMember)); 316 317 return verifyAndAddMachOObject(std::move(NewMember)); 318 } 319 320 private: 321 // Check that a file's architecture [FileCPUType, FileCPUSubtype] 322 // matches the architecture specified under -arch_only flag. 323 bool acceptFileArch(uint32_t FileCPUType, uint32_t FileCPUSubtype) { 324 if (Builder.C.ArchCPUType != FileCPUType) 325 return false; 326 327 switch (Builder.C.ArchCPUType) { 328 case MachO::CPU_TYPE_ARM: 329 case MachO::CPU_TYPE_ARM64_32: 330 case MachO::CPU_TYPE_X86_64: 331 return Builder.C.ArchCPUSubtype == FileCPUSubtype; 332 333 case MachO::CPU_TYPE_ARM64: 334 if (Builder.C.ArchCPUSubtype == MachO::CPU_SUBTYPE_ARM64_ALL) 335 return FileCPUSubtype == MachO::CPU_SUBTYPE_ARM64_ALL || 336 FileCPUSubtype == MachO::CPU_SUBTYPE_ARM64_V8; 337 else 338 return Builder.C.ArchCPUSubtype == FileCPUSubtype; 339 340 default: 341 return true; 342 } 343 } 344 345 Error verifyAndAddMachOObject(NewArchiveMember Member) { 346 auto MBRef = Member.Buf->getMemBufferRef(); 347 Expected<std::unique_ptr<object::ObjectFile>> ObjOrErr = 348 object::ObjectFile::createObjectFile(MBRef); 349 350 // Throw error if not a valid object file. 351 if (!ObjOrErr) 352 return createFileError(Member.MemberName, ObjOrErr.takeError()); 353 354 // Throw error if not in Mach-O format. 355 if (!isa<object::MachOObjectFile>(**ObjOrErr)) 356 return createStringError(std::errc::invalid_argument, 357 "'%s': format not supported", 358 Member.MemberName.data()); 359 360 auto *O = cast<MachOObjectFile>(ObjOrErr->get()); 361 uint32_t FileCPUType, FileCPUSubtype; 362 std::tie(FileCPUType, FileCPUSubtype) = MachO::getCPUTypeFromArchitecture( 363 MachO::getArchitectureFromName(O->getArchTriple().getArchName())); 364 365 // If -arch_only is specified then skip this file if it doesn't match 366 // the architecture specified. 367 if (ArchType && !acceptFileArch(FileCPUType, FileCPUSubtype)) { 368 return Error::success(); 369 } 370 371 if (!NoWarningForNoSymbols && O->symbols().empty()) { 372 Error E = createFileError( 373 Member.MemberName, 374 createStringError(std::errc::invalid_argument, 375 "has no symbols for architecture %s", 376 O->getArchTriple().getArchName().str().c_str())); 377 378 if (WarningsAsErrors) 379 return E; 380 WithColor::defaultWarningHandler(std::move(E)); 381 } 382 383 uint64_t FileCPUID = getCPUID(FileCPUType, FileCPUSubtype); 384 Builder.Data.MembersPerArchitecture[FileCPUID].push_back( 385 std::move(Member), FileName); 386 return Error::success(); 387 } 388 389 Error verifyAndAddIRObject(NewArchiveMember Member) { 390 auto MBRef = Member.Buf->getMemBufferRef(); 391 Expected<std::unique_ptr<object::IRObjectFile>> IROrErr = 392 object::IRObjectFile::create(MBRef, Builder.LLVMCtx); 393 394 // Throw error if not a valid IR object file. 395 if (!IROrErr) 396 return createFileError(Member.MemberName, IROrErr.takeError()); 397 398 Triple TT = Triple(IROrErr->get()->getTargetTriple()); 399 400 Expected<uint32_t> FileCPUTypeOrErr = MachO::getCPUType(TT); 401 if (!FileCPUTypeOrErr) 402 return FileCPUTypeOrErr.takeError(); 403 404 Expected<uint32_t> FileCPUSubTypeOrErr = MachO::getCPUSubType(TT); 405 if (!FileCPUSubTypeOrErr) 406 return FileCPUSubTypeOrErr.takeError(); 407 408 // If -arch_only is specified then skip this file if it doesn't match 409 // the architecture specified. 410 if (ArchType && 411 !acceptFileArch(*FileCPUTypeOrErr, *FileCPUSubTypeOrErr)) { 412 return Error::success(); 413 } 414 415 uint64_t FileCPUID = getCPUID(*FileCPUTypeOrErr, *FileCPUSubTypeOrErr); 416 Builder.Data.MembersPerArchitecture[FileCPUID].push_back( 417 std::move(Member), FileName); 418 return Error::success(); 419 } 420 421 Error addChildMember(const object::Archive::Child &M) { 422 Expected<NewArchiveMember> NewMemberOrErr = 423 NewArchiveMember::getOldMember(M, Builder.C.Deterministic); 424 if (!NewMemberOrErr) 425 return NewMemberOrErr.takeError(); 426 auto &NewMember = *NewMemberOrErr; 427 428 file_magic Magic = identify_magic(NewMember.Buf->getBuffer()); 429 430 if (Magic == file_magic::bitcode) 431 return verifyAndAddIRObject(std::move(NewMember)); 432 433 return verifyAndAddMachOObject(std::move(NewMember)); 434 } 435 436 Error processArchive(object::Archive &Lib) { 437 Error Err = Error::success(); 438 for (const object::Archive::Child &Child : Lib.children(Err)) 439 if (Error E = addChildMember(Child)) 440 return createFileError(FileName, std::move(E)); 441 if (Err) 442 return createFileError(FileName, std::move(Err)); 443 444 return Error::success(); 445 } 446 447 Error addArchiveMembers(NewArchiveMember NewMember) { 448 Expected<std::unique_ptr<Archive>> LibOrErr = 449 object::Archive::create(NewMember.Buf->getMemBufferRef()); 450 if (!LibOrErr) 451 return createFileError(FileName, LibOrErr.takeError()); 452 453 if (Error E = processArchive(**LibOrErr)) 454 return E; 455 456 // Update vector FileBuffers with the MemoryBuffers to transfer 457 // ownership. 458 Builder.Data.FileBuffers.push_back(std::move(NewMember.Buf)); 459 return Error::success(); 460 } 461 462 Error addUniversalMembers(NewArchiveMember NewMember) { 463 Expected<std::unique_ptr<MachOUniversalBinary>> BinaryOrErr = 464 MachOUniversalBinary::create(NewMember.Buf->getMemBufferRef()); 465 if (!BinaryOrErr) 466 return createFileError(FileName, BinaryOrErr.takeError()); 467 468 auto *UO = BinaryOrErr->get(); 469 for (const MachOUniversalBinary::ObjectForArch &O : UO->objects()) { 470 471 Expected<std::unique_ptr<MachOObjectFile>> MachOObjOrErr = 472 O.getAsObjectFile(); 473 if (MachOObjOrErr) { 474 NewArchiveMember NewMember = 475 NewArchiveMember(MachOObjOrErr->get()->getMemoryBufferRef()); 476 NewMember.MemberName = sys::path::filename(NewMember.MemberName); 477 478 if (Error E = verifyAndAddMachOObject(std::move(NewMember))) 479 return E; 480 continue; 481 } 482 483 Expected<std::unique_ptr<IRObjectFile>> IRObjectOrError = 484 O.getAsIRObject(Builder.LLVMCtx); 485 if (IRObjectOrError) { 486 // A universal file member can be a MachOObjectFile, an IRObject or an 487 // Archive. In case we can successfully cast the member as an 488 // IRObject, it is safe to throw away the error generated due to 489 // casting the object as a MachOObjectFile. 490 consumeError(MachOObjOrErr.takeError()); 491 492 NewArchiveMember NewMember = 493 NewArchiveMember(IRObjectOrError->get()->getMemoryBufferRef()); 494 NewMember.MemberName = sys::path::filename(NewMember.MemberName); 495 496 if (Error E = verifyAndAddIRObject(std::move(NewMember))) 497 return E; 498 continue; 499 } 500 501 Expected<std::unique_ptr<Archive>> ArchiveOrError = O.getAsArchive(); 502 if (ArchiveOrError) { 503 // A universal file member can be a MachOObjectFile, an IRObject or an 504 // Archive. In case we can successfully cast the member as an Archive, 505 // it is safe to throw away the error generated due to casting the 506 // object as a MachOObjectFile. 507 consumeError(MachOObjOrErr.takeError()); 508 consumeError(IRObjectOrError.takeError()); 509 510 if (Error E = processArchive(**ArchiveOrError)) 511 return E; 512 continue; 513 } 514 515 Error CombinedError = joinErrors( 516 ArchiveOrError.takeError(), 517 joinErrors(IRObjectOrError.takeError(), MachOObjOrErr.takeError())); 518 return createFileError(FileName, std::move(CombinedError)); 519 } 520 521 // Update vector FileBuffers with the MemoryBuffers to transfer 522 // ownership. 523 Builder.Data.FileBuffers.push_back(std::move(NewMember.Buf)); 524 return Error::success(); 525 } 526 }; 527 528 MembersData Data; 529 LLVMContext &LLVMCtx; 530 const Config &C; 531 }; 532 533 static Expected<SmallVector<Slice, 2>> 534 buildSlices(LLVMContext &LLVMCtx, 535 ArrayRef<OwningBinary<Archive>> OutputBinaries) { 536 SmallVector<Slice, 2> Slices; 537 538 for (const auto &OB : OutputBinaries) { 539 const Archive &A = *OB.getBinary(); 540 Expected<Slice> ArchiveSlice = Slice::create(A, &LLVMCtx); 541 if (!ArchiveSlice) 542 return ArchiveSlice.takeError(); 543 Slices.push_back(*ArchiveSlice); 544 } 545 return Slices; 546 } 547 548 static Error 549 checkForDuplicates(const MembersPerArchitectureMap &MembersPerArch) { 550 for (const auto &M : MembersPerArch) { 551 ArrayRef<NewArchiveMember> Members = M.second.getMembers(); 552 ArrayRef<StringRef> Files = M.second.getFiles(); 553 MapVector<StringRef, SmallVector<StringRef, 1>> MembersToFiles; 554 for (auto Iterators = std::make_pair(Members.begin(), Files.begin()); 555 Iterators.first != Members.end(); 556 ++Iterators.first, ++Iterators.second) { 557 assert(Iterators.second != Files.end() && 558 "Files should be the same size as Members."); 559 MembersToFiles[Iterators.first->MemberName].push_back(*Iterators.second); 560 } 561 562 std::string ErrorData; 563 raw_string_ostream ErrorStream(ErrorData); 564 for (const auto &[Key, Value] : MembersToFiles) { 565 if (Value.size() > 1) { 566 ErrorStream << "file '" << Key << "' was specified multiple times.\n"; 567 568 for (StringRef OriginalFile : Value) 569 ErrorStream << "in: " << OriginalFile.str() << '\n'; 570 571 ErrorStream << '\n'; 572 } 573 } 574 575 ErrorStream.flush(); 576 if (ErrorData.size() > 0) 577 return createStringError(std::errc::invalid_argument, ErrorData.c_str()); 578 } 579 return Error::success(); 580 } 581 582 static Error createStaticLibrary(LLVMContext &LLVMCtx, const Config &C) { 583 MembersBuilder Builder(LLVMCtx, C); 584 auto DataOrError = Builder.build(); 585 if (auto Error = DataOrError.takeError()) 586 return Error; 587 588 const auto &NewMembers = DataOrError->MembersPerArchitecture; 589 590 if (Error E = checkForDuplicates(NewMembers)) { 591 if (WarningsAsErrors) 592 return E; 593 WithColor::defaultWarningHandler(std::move(E)); 594 } 595 596 if (NewMembers.size() == 1) 597 return writeArchive(OutputFile, NewMembers.begin()->second.getMembers(), 598 SymtabWritingMode::NormalSymtab, 599 /*Kind=*/object::Archive::K_DARWIN, C.Deterministic, 600 /*Thin=*/false); 601 602 SmallVector<OwningBinary<Archive>, 2> OutputBinaries; 603 for (const std::pair<const uint64_t, NewArchiveMemberList> &M : NewMembers) { 604 Expected<std::unique_ptr<MemoryBuffer>> OutputBufferOrErr = 605 writeArchiveToBuffer( 606 M.second.getMembers(), SymtabWritingMode::NormalSymtab, 607 /*Kind=*/object::Archive::K_DARWIN, C.Deterministic, 608 /*Thin=*/false); 609 if (!OutputBufferOrErr) 610 return OutputBufferOrErr.takeError(); 611 std::unique_ptr<MemoryBuffer> &OutputBuffer = OutputBufferOrErr.get(); 612 613 Expected<std::unique_ptr<Archive>> ArchiveOrError = 614 Archive::create(OutputBuffer->getMemBufferRef()); 615 if (!ArchiveOrError) 616 return ArchiveOrError.takeError(); 617 std::unique_ptr<Archive> &A = ArchiveOrError.get(); 618 619 OutputBinaries.push_back( 620 OwningBinary<Archive>(std::move(A), std::move(OutputBuffer))); 621 } 622 623 Expected<SmallVector<Slice, 2>> Slices = buildSlices(LLVMCtx, OutputBinaries); 624 if (!Slices) 625 return Slices.takeError(); 626 627 llvm::stable_sort(*Slices); 628 return writeUniversalBinary(*Slices, OutputFile); 629 } 630 631 static void parseRawArgs(int Argc, char **Argv) { 632 LibtoolDarwinOptTable Tbl; 633 llvm::BumpPtrAllocator A; 634 llvm::StringSaver Saver{A}; 635 opt::InputArgList Args = 636 Tbl.parseArgs(Argc, Argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) { 637 llvm::errs() << Msg << '\n'; 638 std::exit(1); 639 }); 640 641 if (Args.hasArg(OPT_help)) { 642 Tbl.printHelp(llvm::outs(), "llvm-libtool-darwin [options] <input files>", 643 "llvm-libtool-darwin"); 644 std::exit(0); 645 } 646 647 InputFiles = Args.getAllArgValues(OPT_INPUT); 648 Libraries = Args.getAllArgValues(OPT_libraries); 649 LibrarySearchDirs = Args.getAllArgValues(OPT_librarySearchDirs); 650 651 if (const opt::Arg *A = Args.getLastArg(OPT_outputFile)) 652 OutputFile = A->getValue(); 653 654 if (const opt::Arg *A = Args.getLastArg(OPT_archType)) 655 ArchType = std::make_optional(A->getValue()); 656 657 if (const opt::Arg *A = Args.getLastArg(OPT_fileList)) 658 FileList = A->getValue(); 659 660 if (const opt::Arg *A = Args.getLastArg(OPT_dependencyInfoPath)) 661 DependencyInfoPath = A->getValue(); 662 663 if (const opt::Arg *A = Args.getLastArg(OPT_ignoredSyslibRoot)) 664 IgnoredSyslibRoot = A->getValue(); 665 666 LibraryOperation = 667 Args.hasArg(OPT_static) ? Operation::Static : Operation::None; 668 DeterministicOption = Args.hasArg(OPT_deterministicOption); 669 NonDeterministicOption = Args.hasArg(OPT_nonDeterministicOption); 670 VersionOption = Args.hasArg(OPT_version); 671 NoWarningForNoSymbols = Args.hasArg(OPT_noWarningForNoSymbols); 672 WarningsAsErrors = Args.hasArg(OPT_warningsAsErrors); 673 } 674 675 static Expected<Config> parseCommandLine(int Argc, char **Argv) { 676 Config C; 677 parseRawArgs(Argc, Argv); 678 679 if (LibraryOperation == Operation::None) { 680 if (!VersionOption) { 681 return createStringError(std::errc::invalid_argument, 682 "-static option: must be specified"); 683 } 684 return C; 685 } 686 687 GlobalDependencyInfo = 688 DependencyInfoPath.empty() 689 ? std::make_unique<DummyDependencyInfo>() 690 : std::make_unique<DependencyInfo>(DependencyInfoPath); 691 692 if (OutputFile.empty()) { 693 return createStringError(std::errc::invalid_argument, 694 "-o option: must be specified"); 695 } 696 697 if (DeterministicOption && NonDeterministicOption) 698 return createStringError(std::errc::invalid_argument, 699 "cannot specify both -D and -U flags"); 700 else if (NonDeterministicOption) 701 C.Deterministic = false; 702 703 if (!Libraries.empty()) 704 if (Error E = processCommandLineLibraries()) 705 return std::move(E); 706 707 if (!FileList.empty()) 708 if (Error E = processFileList()) 709 return std::move(E); 710 711 if (InputFiles.empty()) 712 return createStringError(std::errc::invalid_argument, 713 "no input files specified"); 714 715 if (ArchType) { 716 if (Error E = validateArchitectureName(ArchType.value())) 717 return std::move(E); 718 719 std::tie(C.ArchCPUType, C.ArchCPUSubtype) = 720 MachO::getCPUTypeFromArchitecture( 721 MachO::getArchitectureFromName(ArchType.value())); 722 } 723 724 GlobalDependencyInfo->write("llvm-libtool-darwin " LLVM_VERSION_STRING, 725 InputFiles, OutputFile); 726 727 return C; 728 } 729 730 int llvm_libtool_darwin_main(int Argc, char **Argv, const llvm::ToolContext &) { 731 Expected<Config> ConfigOrErr = parseCommandLine(Argc, Argv); 732 if (!ConfigOrErr) { 733 WithColor::defaultErrorHandler(ConfigOrErr.takeError()); 734 return EXIT_FAILURE; 735 } 736 737 if (VersionOption) 738 cl::PrintVersionMessage(); 739 740 llvm::InitializeAllTargetInfos(); 741 llvm::InitializeAllTargetMCs(); 742 llvm::InitializeAllAsmParsers(); 743 744 LLVMContext LLVMCtx; 745 Config C = *ConfigOrErr; 746 switch (LibraryOperation) { 747 case Operation::None: 748 break; 749 case Operation::Static: 750 if (Error E = createStaticLibrary(LLVMCtx, C)) { 751 WithColor::defaultErrorHandler(std::move(E)); 752 return EXIT_FAILURE; 753 } 754 break; 755 } 756 return EXIT_SUCCESS; 757 } 758