1 //===-- llvm-ar.cpp - LLVM archive librarian utility ----------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // Builds up (relatively) standard unix archive files (.a) containing LLVM
10 // bitcode or other files.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/ADT/StringSwitch.h"
15 #include "llvm/ADT/Triple.h"
16 #include "llvm/IR/LLVMContext.h"
17 #include "llvm/Object/Archive.h"
18 #include "llvm/Object/ArchiveWriter.h"
19 #include "llvm/Object/MachO.h"
20 #include "llvm/Object/ObjectFile.h"
21 #include "llvm/Support/Chrono.h"
22 #include "llvm/Support/CommandLine.h"
23 #include "llvm/Support/Errc.h"
24 #include "llvm/Support/FileSystem.h"
25 #include "llvm/Support/Format.h"
26 #include "llvm/Support/FormatVariadic.h"
27 #include "llvm/Support/InitLLVM.h"
28 #include "llvm/Support/LineIterator.h"
29 #include "llvm/Support/MemoryBuffer.h"
30 #include "llvm/Support/Path.h"
31 #include "llvm/Support/Process.h"
32 #include "llvm/Support/StringSaver.h"
33 #include "llvm/Support/TargetSelect.h"
34 #include "llvm/Support/ToolOutputFile.h"
35 #include "llvm/Support/WithColor.h"
36 #include "llvm/Support/raw_ostream.h"
37 #include "llvm/ToolDrivers/llvm-dlltool/DlltoolDriver.h"
38 #include "llvm/ToolDrivers/llvm-lib/LibDriver.h"
40 #if !defined(_MSC_VER) && !defined(__MINGW32__)
48 // The name this program was invoked as.
49 static StringRef ToolName
;
51 // The basename of this program.
52 static StringRef Stem
;
54 const char RanlibHelp
[] = R
"(
55 OVERVIEW: LLVM Ranlib (llvm-ranlib)
57 This program generates an index to speed access to archives
59 USAGE: llvm-ranlib <archive-file>
62 -help - Display available options
63 -version - Display the version of this program
66 const char ArHelp
[] = R
"(
67 OVERVIEW: LLVM Archiver
69 USAGE: llvm-ar [options] [-]<operation>[modifiers] [relpos] [count] <archive> [files]
70 llvm-ar -M [<mri-script]
73 --format - archive format to create
78 --plugin=<string> - ignored for compatibility
79 -h --help - display this help and exit
80 --version - print the version and exit
81 @<file> - read options from <file>
84 d - delete [files] from the archive
85 m - move [files] in the archive
86 p - print [files] found in the archive
87 q - quick append [files] to the archive
88 r - replace or insert [files] into the archive
90 t - display contents of archive
91 x - extract [files] from the archive
94 [a] - put [files] after [relpos]
95 [b] - put [files] before [relpos] (same as [i])
96 [c] - do not warn if archive had to be created
97 [D] - use zero for timestamps and uids/gids (default)
98 [i] - put [files] before [relpos] (same as [b])
99 [l] - ignored for compatibility
100 [L] - add archive's contents
101 [N] - use instance [count] of name
102 [o] - preserve original dates
103 [P] - use full names when matching (implied for thin archives)
104 [s] - create an archive index (cf. ranlib)
105 [S] - do not build a symbol table
106 [T] - create a thin archive
107 [u] - update only [files] newer than archive contents
108 [U] - use actual timestamps and uids/gids
109 [v] - be verbose about actions taken
112 void printHelpMessage() {
113 if (Stem
.contains_lower("ranlib"))
114 outs() << RanlibHelp
;
115 else if (Stem
.contains_lower("ar"))
119 static unsigned MRILineNumber
;
120 static bool ParsingMRIScript
;
122 // Show the error message and exit.
123 LLVM_ATTRIBUTE_NORETURN
static void fail(Twine Error
) {
124 if (ParsingMRIScript
) {
125 WithColor::error(errs(), ToolName
)
126 << "script line " << MRILineNumber
<< ": " << Error
<< "\n";
128 WithColor::error(errs(), ToolName
) << Error
<< "\n";
135 static void failIfError(std::error_code EC
, Twine Context
= "") {
139 std::string ContextStr
= Context
.str();
140 if (ContextStr
.empty())
142 fail(Context
+ ": " + EC
.message());
145 static void failIfError(Error E
, Twine Context
= "") {
149 handleAllErrors(std::move(E
), [&](const llvm::ErrorInfoBase
&EIB
) {
150 std::string ContextStr
= Context
.str();
151 if (ContextStr
.empty())
153 fail(Context
+ ": " + EIB
.message());
157 static SmallVector
<const char *, 256> PositionalArgs
;
162 enum Format
{ Default
, GNU
, BSD
, DARWIN
, Unknown
};
165 static Format FormatType
= Default
;
167 static std::string Options
;
169 // This enumeration delineates the kinds of operations on an archive
170 // that are permitted.
171 enum ArchiveOperation
{
172 Print
, ///< Print the contents of the archive
173 Delete
, ///< Delete the specified members
174 Move
, ///< Move members to end or as given by {a,b,i} modifiers
175 QuickAppend
, ///< Quickly append to end of archive
176 ReplaceOrInsert
, ///< Replace or Insert members
177 DisplayTable
, ///< Display the table of contents
178 Extract
, ///< Extract files back to file system
179 CreateSymTab
///< Create a symbol table in an existing archive
182 // Modifiers to follow operation to vary behavior
183 static bool AddAfter
= false; ///< 'a' modifier
184 static bool AddBefore
= false; ///< 'b' modifier
185 static bool Create
= false; ///< 'c' modifier
186 static bool OriginalDates
= false; ///< 'o' modifier
187 static bool CompareFullPath
= false; ///< 'P' modifier
188 static bool OnlyUpdate
= false; ///< 'u' modifier
189 static bool Verbose
= false; ///< 'v' modifier
190 static bool Symtab
= true; ///< 's' modifier
191 static bool Deterministic
= true; ///< 'D' and 'U' modifiers
192 static bool Thin
= false; ///< 'T' modifier
193 static bool AddLibrary
= false; ///< 'L' modifier
195 // Relative Positional Argument (for insert/move). This variable holds
196 // the name of the archive member to which the 'a', 'b' or 'i' modifier
197 // refers. Only one of 'a', 'b' or 'i' can be specified so we only need
199 static std::string RelPos
;
201 // Count parameter for 'N' modifier. This variable specifies which file should
202 // match for extract/delete operations when there are multiple matches. This is
203 // 1-indexed. A value of 0 is invalid, and implies 'N' is not used.
204 static int CountParam
= 0;
206 // This variable holds the name of the archive file as given on the
208 static std::string ArchiveName
;
210 // This variable holds the list of member files to proecess, as given
211 // on the command line.
212 static std::vector
<StringRef
> Members
;
214 // Static buffer to hold StringRefs.
215 static BumpPtrAllocator Alloc
;
217 // Extract the member filename from the command line for the [relpos] argument
218 // associated with a, b, and i modifiers
219 static void getRelPos() {
220 if (PositionalArgs
.empty())
221 fail("expected [relpos] for 'a', 'b', or 'i' modifier");
222 RelPos
= PositionalArgs
[0];
223 PositionalArgs
.erase(PositionalArgs
.begin());
226 // Extract the parameter from the command line for the [count] argument
227 // associated with the N modifier
228 static void getCountParam() {
229 if (PositionalArgs
.empty())
230 fail("expected [count] for 'N' modifier");
231 auto CountParamArg
= StringRef(PositionalArgs
[0]);
232 if (CountParamArg
.getAsInteger(10, CountParam
))
233 fail("value for [count] must be numeric, got: " + CountParamArg
);
235 fail("value for [count] must be positive, got: " + CountParamArg
);
236 PositionalArgs
.erase(PositionalArgs
.begin());
239 // Get the archive file name from the command line
240 static void getArchive() {
241 if (PositionalArgs
.empty())
242 fail("an archive name must be specified");
243 ArchiveName
= PositionalArgs
[0];
244 PositionalArgs
.erase(PositionalArgs
.begin());
247 // Copy over remaining items in PositionalArgs to our Members vector
248 static void getMembers() {
249 for (auto &Arg
: PositionalArgs
)
250 Members
.push_back(Arg
);
253 std::vector
<std::unique_ptr
<MemoryBuffer
>> ArchiveBuffers
;
254 std::vector
<std::unique_ptr
<object::Archive
>> Archives
;
256 static object::Archive
&readLibrary(const Twine
&Library
) {
257 auto BufOrErr
= MemoryBuffer::getFile(Library
, -1, false);
258 failIfError(BufOrErr
.getError(), "could not open library " + Library
);
259 ArchiveBuffers
.push_back(std::move(*BufOrErr
));
261 object::Archive::create(ArchiveBuffers
.back()->getMemBufferRef());
262 failIfError(errorToErrorCode(LibOrErr
.takeError()),
263 "could not parse library");
264 Archives
.push_back(std::move(*LibOrErr
));
265 return *Archives
.back();
268 static void runMRIScript();
270 // Parse the command line options as presented and return the operation
271 // specified. Process all modifiers and check to make sure that constraints on
272 // modifier/operation pairs have not been violated.
273 static ArchiveOperation
parseCommandLine() {
275 if (!PositionalArgs
.empty() || !Options
.empty())
276 fail("cannot mix -M and other options");
280 // Keep track of number of operations. We can only specify one
282 unsigned NumOperations
= 0;
284 // Keep track of the number of positional modifiers (a,b,i). Only
285 // one can be specified.
286 unsigned NumPositional
= 0;
288 // Keep track of which operation was requested
289 ArchiveOperation Operation
;
291 bool MaybeJustCreateSymTab
= false;
293 for (unsigned i
= 0; i
< Options
.size(); ++i
) {
294 switch (Options
[i
]) {
309 Operation
= QuickAppend
;
313 Operation
= ReplaceOrInsert
;
317 Operation
= DisplayTable
;
326 case 'l': /* accepted but unused */
329 OriginalDates
= true;
332 CompareFullPath
= true;
336 MaybeJustCreateSymTab
= true;
363 Deterministic
= true;
366 Deterministic
= false;
373 // Thin archives store path names, so P should be forced.
374 CompareFullPath
= true;
380 fail(std::string("unknown option ") + Options
[i
]);
384 // At this point, the next thing on the command line must be
388 // Everything on the command line at this point is a member.
391 if (NumOperations
== 0 && MaybeJustCreateSymTab
) {
393 Operation
= CreateSymTab
;
394 if (!Members
.empty())
395 fail("the 's' operation takes only an archive as argument");
398 // Perform various checks on the operation/modifier specification
399 // to make sure we are dealing with a legal request.
400 if (NumOperations
== 0)
401 fail("you must specify at least one of the operations");
402 if (NumOperations
> 1)
403 fail("only one operation may be specified");
404 if (NumPositional
> 1)
405 fail("you may only specify one of 'a', 'b', and 'i' modifiers");
406 if (AddAfter
|| AddBefore
)
407 if (Operation
!= Move
&& Operation
!= ReplaceOrInsert
)
408 fail("the 'a', 'b' and 'i' modifiers can only be specified with "
409 "the 'm' or 'r' operations");
411 if (Operation
!= Extract
&& Operation
!= Delete
)
412 fail("the 'N' modifier can only be specified with the 'x' or 'd' "
414 if (OriginalDates
&& Operation
!= Extract
)
415 fail("the 'o' modifier is only applicable to the 'x' operation");
416 if (OnlyUpdate
&& Operation
!= ReplaceOrInsert
)
417 fail("the 'u' modifier is only applicable to the 'r' operation");
418 if (AddLibrary
&& Operation
!= QuickAppend
)
419 fail("the 'L' modifier is only applicable to the 'q' operation");
421 // Return the parsed operation to the caller
425 // Implements the 'p' operation. This function traverses the archive
426 // looking for members that match the path list.
427 static void doPrint(StringRef Name
, const object::Archive::Child
&C
) {
429 outs() << "Printing " << Name
<< "\n";
431 Expected
<StringRef
> DataOrErr
= C
.getBuffer();
432 failIfError(DataOrErr
.takeError());
433 StringRef Data
= *DataOrErr
;
434 outs().write(Data
.data(), Data
.size());
437 // Utility function for printing out the file mode when the 't' operation is in
439 static void printMode(unsigned mode
) {
440 outs() << ((mode
& 004) ? "r" : "-");
441 outs() << ((mode
& 002) ? "w" : "-");
442 outs() << ((mode
& 001) ? "x" : "-");
445 // Implement the 't' operation. This function prints out just
446 // the file names of each of the members. However, if verbose mode is requested
447 // ('v' modifier) then the file type, permission mode, user, group, size, and
448 // modification time are also printed.
449 static void doDisplayTable(StringRef Name
, const object::Archive::Child
&C
) {
451 Expected
<sys::fs::perms
> ModeOrErr
= C
.getAccessMode();
452 failIfError(ModeOrErr
.takeError());
453 sys::fs::perms Mode
= ModeOrErr
.get();
454 printMode((Mode
>> 6) & 007);
455 printMode((Mode
>> 3) & 007);
456 printMode(Mode
& 007);
457 Expected
<unsigned> UIDOrErr
= C
.getUID();
458 failIfError(UIDOrErr
.takeError());
459 outs() << ' ' << UIDOrErr
.get();
460 Expected
<unsigned> GIDOrErr
= C
.getGID();
461 failIfError(GIDOrErr
.takeError());
462 outs() << '/' << GIDOrErr
.get();
463 Expected
<uint64_t> Size
= C
.getSize();
464 failIfError(Size
.takeError());
465 outs() << ' ' << format("%6llu", Size
.get());
466 auto ModTimeOrErr
= C
.getLastModified();
467 failIfError(ModTimeOrErr
.takeError());
468 // Note: formatv() only handles the default TimePoint<>, which is in
470 // TODO: fix format_provider<TimePoint<>> to allow other units.
471 sys::TimePoint
<> ModTimeInNs
= ModTimeOrErr
.get();
472 outs() << ' ' << formatv("{0:%b %e %H:%M %Y}", ModTimeInNs
);
476 if (C
.getParent()->isThin()) {
477 if (!sys::path::is_absolute(Name
)) {
478 StringRef ParentDir
= sys::path::parent_path(ArchiveName
);
479 if (!ParentDir
.empty())
480 outs() << sys::path::convert_to_slash(ParentDir
) << '/';
483 outs() << Name
<< "\n";
486 static std::string
normalizePath(StringRef Path
) {
487 return CompareFullPath
? sys::path::convert_to_slash(Path
)
488 : std::string(sys::path::filename(Path
));
491 // Implement the 'x' operation. This function extracts files back to the file
493 static void doExtract(StringRef Name
, const object::Archive::Child
&C
) {
494 // Retain the original mode.
495 Expected
<sys::fs::perms
> ModeOrErr
= C
.getAccessMode();
496 failIfError(ModeOrErr
.takeError());
497 sys::fs::perms Mode
= ModeOrErr
.get();
500 failIfError(sys::fs::openFileForWrite(sys::path::filename(Name
), FD
,
501 sys::fs::CD_CreateAlways
,
502 sys::fs::OF_None
, Mode
),
506 raw_fd_ostream
file(FD
, false);
508 // Get the data and its length
509 Expected
<StringRef
> BufOrErr
= C
.getBuffer();
510 failIfError(BufOrErr
.takeError());
511 StringRef Data
= BufOrErr
.get();
514 file
.write(Data
.data(), Data
.size());
517 // If we're supposed to retain the original modification times, etc. do so
520 auto ModTimeOrErr
= C
.getLastModified();
521 failIfError(ModTimeOrErr
.takeError());
523 sys::fs::setLastAccessAndModificationTime(FD
, ModTimeOrErr
.get()));
527 fail("Could not close the file");
530 static bool shouldCreateArchive(ArchiveOperation Op
) {
541 case ReplaceOrInsert
:
545 llvm_unreachable("Missing entry in covered switch.");
548 static void performReadOperation(ArchiveOperation Operation
,
549 object::Archive
*OldArchive
) {
550 if (Operation
== Extract
&& OldArchive
->isThin())
551 fail("extracting from a thin archive is not supported");
553 bool Filter
= !Members
.empty();
554 StringMap
<int> MemberCount
;
556 Error Err
= Error::success();
557 for (auto &C
: OldArchive
->children(Err
)) {
558 Expected
<StringRef
> NameOrErr
= C
.getName();
559 failIfError(NameOrErr
.takeError());
560 StringRef Name
= NameOrErr
.get();
563 auto I
= find_if(Members
, [Name
](StringRef Path
) {
564 return Name
== normalizePath(Path
);
566 if (I
== Members
.end())
568 if (CountParam
&& ++MemberCount
[Name
] != CountParam
)
575 llvm_unreachable("Not a read operation");
580 doDisplayTable(Name
, C
);
587 failIfError(std::move(Err
));
592 for (StringRef Name
: Members
)
593 WithColor::error(errs(), ToolName
) << "'" << Name
<< "' was not found\n";
597 static void addChildMember(std::vector
<NewArchiveMember
> &Members
,
598 const object::Archive::Child
&M
,
599 bool FlattenArchive
= false) {
600 if (Thin
&& !M
.getParent()->isThin())
601 fail("cannot convert a regular archive to a thin one");
602 Expected
<NewArchiveMember
> NMOrErr
=
603 NewArchiveMember::getOldMember(M
, Deterministic
);
604 failIfError(NMOrErr
.takeError());
605 // If the child member we're trying to add is thin, use the path relative to
606 // the archive it's in, so the file resolves correctly.
607 if (Thin
&& FlattenArchive
) {
608 StringSaver
Saver(Alloc
);
609 Expected
<std::string
> FileNameOrErr
= M
.getName();
610 failIfError(FileNameOrErr
.takeError());
611 if (sys::path::is_absolute(*FileNameOrErr
)) {
612 NMOrErr
->MemberName
= Saver
.save(sys::path::convert_to_slash(*FileNameOrErr
));
614 FileNameOrErr
= M
.getFullName();
615 failIfError(FileNameOrErr
.takeError());
616 Expected
<std::string
> PathOrErr
=
617 computeArchiveRelativePath(ArchiveName
, *FileNameOrErr
);
618 NMOrErr
->MemberName
= Saver
.save(
619 PathOrErr
? *PathOrErr
: sys::path::convert_to_slash(*FileNameOrErr
));
622 if (FlattenArchive
&&
623 identify_magic(NMOrErr
->Buf
->getBuffer()) == file_magic::archive
) {
624 Expected
<std::string
> FileNameOrErr
= M
.getFullName();
625 failIfError(FileNameOrErr
.takeError());
626 object::Archive
&Lib
= readLibrary(*FileNameOrErr
);
627 // When creating thin archives, only flatten if the member is also thin.
628 if (!Thin
|| Lib
.isThin()) {
629 Error Err
= Error::success();
630 // Only Thin archives are recursively flattened.
631 for (auto &Child
: Lib
.children(Err
))
632 addChildMember(Members
, Child
, /*FlattenArchive=*/Thin
);
633 failIfError(std::move(Err
));
637 Members
.push_back(std::move(*NMOrErr
));
640 static void addMember(std::vector
<NewArchiveMember
> &Members
,
641 StringRef FileName
, bool FlattenArchive
= false) {
642 Expected
<NewArchiveMember
> NMOrErr
=
643 NewArchiveMember::getFile(FileName
, Deterministic
);
644 failIfError(NMOrErr
.takeError(), FileName
);
645 StringSaver
Saver(Alloc
);
646 // For regular archives, use the basename of the object path for the member
647 // name. For thin archives, use the full relative paths so the file resolves
650 NMOrErr
->MemberName
= sys::path::filename(NMOrErr
->MemberName
);
652 if (sys::path::is_absolute(FileName
))
653 NMOrErr
->MemberName
= Saver
.save(sys::path::convert_to_slash(FileName
));
655 Expected
<std::string
> PathOrErr
=
656 computeArchiveRelativePath(ArchiveName
, FileName
);
657 NMOrErr
->MemberName
= Saver
.save(
658 PathOrErr
? *PathOrErr
: sys::path::convert_to_slash(FileName
));
662 if (FlattenArchive
&&
663 identify_magic(NMOrErr
->Buf
->getBuffer()) == file_magic::archive
) {
664 object::Archive
&Lib
= readLibrary(FileName
);
665 // When creating thin archives, only flatten if the member is also thin.
666 if (!Thin
|| Lib
.isThin()) {
667 Error Err
= Error::success();
668 // Only Thin archives are recursively flattened.
669 for (auto &Child
: Lib
.children(Err
))
670 addChildMember(Members
, Child
, /*FlattenArchive=*/Thin
);
671 failIfError(std::move(Err
));
675 Members
.push_back(std::move(*NMOrErr
));
686 static InsertAction
computeInsertAction(ArchiveOperation Operation
,
687 const object::Archive::Child
&Member
,
689 std::vector
<StringRef
>::iterator
&Pos
,
690 StringMap
<int> &MemberCount
) {
691 if (Operation
== QuickAppend
|| Members
.empty())
692 return IA_AddOldMember
;
694 Members
, [Name
](StringRef Path
) { return Name
== normalizePath(Path
); });
696 if (MI
== Members
.end())
697 return IA_AddOldMember
;
701 if (Operation
== Delete
) {
702 if (CountParam
&& ++MemberCount
[Name
] != CountParam
)
703 return IA_AddOldMember
;
707 if (Operation
== Move
)
708 return IA_MoveOldMember
;
710 if (Operation
== ReplaceOrInsert
) {
713 return IA_AddNewMember
;
714 return IA_MoveNewMember
;
717 // We could try to optimize this to a fstat, but it is not a common
719 sys::fs::file_status Status
;
720 failIfError(sys::fs::status(*MI
, Status
), *MI
);
721 auto ModTimeOrErr
= Member
.getLastModified();
722 failIfError(ModTimeOrErr
.takeError());
723 if (Status
.getLastModificationTime() < ModTimeOrErr
.get()) {
725 return IA_AddOldMember
;
726 return IA_MoveOldMember
;
730 return IA_AddNewMember
;
731 return IA_MoveNewMember
;
733 llvm_unreachable("No such operation");
736 // We have to walk this twice and computing it is not trivial, so creating an
737 // explicit std::vector is actually fairly efficient.
738 static std::vector
<NewArchiveMember
>
739 computeNewArchiveMembers(ArchiveOperation Operation
,
740 object::Archive
*OldArchive
) {
741 std::vector
<NewArchiveMember
> Ret
;
742 std::vector
<NewArchiveMember
> Moved
;
745 std::string PosName
= normalizePath(RelPos
);
746 Error Err
= Error::success();
747 StringMap
<int> MemberCount
;
748 for (auto &Child
: OldArchive
->children(Err
)) {
749 int Pos
= Ret
.size();
750 Expected
<StringRef
> NameOrErr
= Child
.getName();
751 failIfError(NameOrErr
.takeError());
752 StringRef Name
= NameOrErr
.get();
753 if (Name
== PosName
) {
754 assert(AddAfter
|| AddBefore
);
761 std::vector
<StringRef
>::iterator MemberI
= Members
.end();
762 InsertAction Action
=
763 computeInsertAction(Operation
, Child
, Name
, MemberI
, MemberCount
);
765 case IA_AddOldMember
:
766 addChildMember(Ret
, Child
, /*FlattenArchive=*/Thin
);
768 case IA_AddNewMember
:
769 addMember(Ret
, *MemberI
);
773 case IA_MoveOldMember
:
774 addChildMember(Moved
, Child
, /*FlattenArchive=*/Thin
);
776 case IA_MoveNewMember
:
777 addMember(Moved
, *MemberI
);
780 // When processing elements with the count param, we need to preserve the
781 // full members list when iterating over all archive members. For
782 // instance, "llvm-ar dN 2 archive.a member.o" should delete the second
783 // file named member.o it sees; we are not done with member.o the first
784 // time we see it in the archive.
785 if (MemberI
!= Members
.end() && !CountParam
)
786 Members
.erase(MemberI
);
788 failIfError(std::move(Err
));
791 if (Operation
== Delete
)
794 if (!RelPos
.empty() && InsertPos
== -1)
795 fail("insertion point not found");
798 InsertPos
= Ret
.size();
800 assert(unsigned(InsertPos
) <= Ret
.size());
802 for (auto &M
: Moved
) {
803 Ret
.insert(Ret
.begin() + Pos
, std::move(M
));
808 assert(Operation
== QuickAppend
);
809 for (auto &Member
: Members
)
810 addMember(Ret
, Member
, /*FlattenArchive=*/true);
814 std::vector
<NewArchiveMember
> NewMembers
;
815 for (auto &Member
: Members
)
816 addMember(NewMembers
, Member
, /*FlattenArchive=*/Thin
);
817 Ret
.reserve(Ret
.size() + NewMembers
.size());
818 std::move(NewMembers
.begin(), NewMembers
.end(),
819 std::inserter(Ret
, std::next(Ret
.begin(), InsertPos
)));
824 static object::Archive::Kind
getDefaultForHost() {
825 return Triple(sys::getProcessTriple()).isOSDarwin()
826 ? object::Archive::K_DARWIN
827 : object::Archive::K_GNU
;
830 static object::Archive::Kind
getKindFromMember(const NewArchiveMember
&Member
) {
831 Expected
<std::unique_ptr
<object::ObjectFile
>> OptionalObject
=
832 object::ObjectFile::createObjectFile(Member
.Buf
->getMemBufferRef());
835 return isa
<object::MachOObjectFile
>(**OptionalObject
)
836 ? object::Archive::K_DARWIN
837 : object::Archive::K_GNU
;
839 // squelch the error in case we had a non-object file
840 consumeError(OptionalObject
.takeError());
841 return getDefaultForHost();
844 static void performWriteOperation(ArchiveOperation Operation
,
845 object::Archive
*OldArchive
,
846 std::unique_ptr
<MemoryBuffer
> OldArchiveBuf
,
847 std::vector
<NewArchiveMember
> *NewMembersP
) {
848 std::vector
<NewArchiveMember
> NewMembers
;
850 NewMembers
= computeNewArchiveMembers(Operation
, OldArchive
);
852 object::Archive::Kind Kind
;
853 switch (FormatType
) {
856 Kind
= object::Archive::K_GNU
;
858 Kind
= OldArchive
->kind();
859 else if (NewMembersP
)
860 Kind
= !NewMembersP
->empty() ? getKindFromMember(NewMembersP
->front())
861 : getDefaultForHost();
863 Kind
= !NewMembers
.empty() ? getKindFromMember(NewMembers
.front())
864 : getDefaultForHost();
867 Kind
= object::Archive::K_GNU
;
871 fail("only the gnu format has a thin mode");
872 Kind
= object::Archive::K_BSD
;
876 fail("only the gnu format has a thin mode");
877 Kind
= object::Archive::K_DARWIN
;
880 llvm_unreachable("");
884 writeArchive(ArchiveName
, NewMembersP
? *NewMembersP
: NewMembers
, Symtab
,
885 Kind
, Deterministic
, Thin
, std::move(OldArchiveBuf
));
886 failIfError(std::move(E
), ArchiveName
);
889 static void createSymbolTable(object::Archive
*OldArchive
) {
890 // When an archive is created or modified, if the s option is given, the
891 // resulting archive will have a current symbol table. If the S option
892 // is given, it will have no symbol table.
893 // In summary, we only need to update the symbol table if we have none.
894 // This is actually very common because of broken build systems that think
895 // they have to run ranlib.
896 if (OldArchive
->hasSymbolTable())
899 performWriteOperation(CreateSymTab
, OldArchive
, nullptr, nullptr);
902 static void performOperation(ArchiveOperation Operation
,
903 object::Archive
*OldArchive
,
904 std::unique_ptr
<MemoryBuffer
> OldArchiveBuf
,
905 std::vector
<NewArchiveMember
> *NewMembers
) {
910 performReadOperation(Operation
, OldArchive
);
916 case ReplaceOrInsert
:
917 performWriteOperation(Operation
, OldArchive
, std::move(OldArchiveBuf
),
921 createSymbolTable(OldArchive
);
924 llvm_unreachable("Unknown operation.");
927 static int performOperation(ArchiveOperation Operation
,
928 std::vector
<NewArchiveMember
> *NewMembers
) {
929 // Create or open the archive object.
930 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> Buf
=
931 MemoryBuffer::getFile(ArchiveName
, -1, false);
932 std::error_code EC
= Buf
.getError();
933 if (EC
&& EC
!= errc::no_such_file_or_directory
)
934 fail("error opening '" + ArchiveName
+ "': " + EC
.message());
937 Error Err
= Error::success();
938 object::Archive
Archive(Buf
.get()->getMemBufferRef(), Err
);
939 failIfError(std::move(Err
), "unable to load '" + ArchiveName
+ "'");
940 if (Archive
.isThin())
941 CompareFullPath
= true;
942 performOperation(Operation
, &Archive
, std::move(Buf
.get()), NewMembers
);
946 assert(EC
== errc::no_such_file_or_directory
);
948 if (!shouldCreateArchive(Operation
)) {
949 failIfError(EC
, Twine("error loading '") + ArchiveName
+ "'");
952 // Produce a warning if we should and we're creating the archive
953 WithColor::warning(errs(), ToolName
)
954 << "creating " << ArchiveName
<< "\n";
958 performOperation(Operation
, nullptr, nullptr, NewMembers
);
962 static void runMRIScript() {
963 enum class MRICommand
{ AddLib
, AddMod
, Create
, CreateThin
, Delete
, Save
, End
, Invalid
};
965 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> Buf
= MemoryBuffer::getSTDIN();
966 failIfError(Buf
.getError());
967 const MemoryBuffer
&Ref
= *Buf
.get();
969 std::vector
<NewArchiveMember
> NewMembers
;
970 ParsingMRIScript
= true;
972 for (line_iterator
I(Ref
, /*SkipBlanks*/ false), E
; I
!= E
; ++I
) {
975 Line
= Line
.split(';').first
;
976 Line
= Line
.split('*').first
;
980 StringRef CommandStr
, Rest
;
981 std::tie(CommandStr
, Rest
) = Line
.split(' ');
983 if (!Rest
.empty() && Rest
.front() == '"' && Rest
.back() == '"')
984 Rest
= Rest
.drop_front().drop_back();
985 auto Command
= StringSwitch
<MRICommand
>(CommandStr
.lower())
986 .Case("addlib", MRICommand::AddLib
)
987 .Case("addmod", MRICommand::AddMod
)
988 .Case("create", MRICommand::Create
)
989 .Case("createthin", MRICommand::CreateThin
)
990 .Case("delete", MRICommand::Delete
)
991 .Case("save", MRICommand::Save
)
992 .Case("end", MRICommand::End
)
993 .Default(MRICommand::Invalid
);
996 case MRICommand::AddLib
: {
997 object::Archive
&Lib
= readLibrary(Rest
);
999 Error Err
= Error::success();
1000 for (auto &Member
: Lib
.children(Err
))
1001 addChildMember(NewMembers
, Member
, /*FlattenArchive=*/Thin
);
1002 failIfError(std::move(Err
));
1006 case MRICommand::AddMod
:
1007 addMember(NewMembers
, Rest
);
1009 case MRICommand::CreateThin
:
1012 case MRICommand::Create
:
1014 if (!ArchiveName
.empty())
1015 fail("editing multiple archives not supported");
1017 fail("file already saved");
1020 case MRICommand::Delete
: {
1021 std::string Name
= normalizePath(Rest
);
1022 llvm::erase_if(NewMembers
,
1023 [=](NewArchiveMember
&M
) { return M
.MemberName
== Name
; });
1026 case MRICommand::Save
:
1029 case MRICommand::End
:
1031 case MRICommand::Invalid
:
1032 fail("unknown command: " + CommandStr
);
1036 ParsingMRIScript
= false;
1038 // Nothing to do if not saved.
1040 performOperation(ReplaceOrInsert
, &NewMembers
);
1044 static bool handleGenericOption(StringRef arg
) {
1045 if (arg
== "h" || arg
.startswith("-h") || arg
== "--help") {
1049 if (arg
== "-version" || arg
== "--version") {
1050 cl::PrintVersionMessage();
1056 static int ar_main(int argc
, char **argv
) {
1057 SmallVector
<const char *, 0> Argv(argv
, argv
+ argc
);
1058 StringSaver
Saver(Alloc
);
1059 cl::ExpandResponseFiles(Saver
, cl::TokenizeGNUCommandLine
, Argv
);
1060 for (size_t i
= 1; i
< Argv
.size(); ++i
) {
1061 StringRef Arg
= Argv
[i
];
1063 auto MatchFlagWithArg
= [&](const char *expected
) {
1064 size_t len
= strlen(expected
);
1065 if (Arg
== expected
) {
1066 if (++i
>= Argv
.size())
1067 fail(std::string(expected
) + " requires an argument");
1071 if (Arg
.startswith(expected
) && Arg
.size() > len
&& Arg
[len
] == '=') {
1072 match
= Arg
.data() + len
+ 1;
1077 if (handleGenericOption(Argv
[i
]))
1080 for (; i
< Argv
.size(); ++i
)
1081 PositionalArgs
.push_back(Argv
[i
]);
1084 if (Arg
[0] == '-') {
1085 if (Arg
.startswith("--"))
1091 } else if (MatchFlagWithArg("format")) {
1092 FormatType
= StringSwitch
<Format
>(match
)
1093 .Case("default", Default
)
1095 .Case("darwin", DARWIN
)
1098 if (FormatType
== Unknown
)
1099 fail(std::string("Invalid format ") + match
);
1100 } else if (MatchFlagWithArg("plugin")) {
1103 Options
+= Argv
[i
] + 1;
1105 } else if (Options
.empty()) {
1108 PositionalArgs
.push_back(Argv
[i
]);
1111 ArchiveOperation Operation
= parseCommandLine();
1112 return performOperation(Operation
, nullptr);
1115 static int ranlib_main(int argc
, char **argv
) {
1116 bool ArchiveSpecified
= false;
1117 for (int i
= 1; i
< argc
; ++i
) {
1118 if (handleGenericOption(argv
[i
])) {
1121 if (ArchiveSpecified
)
1122 fail("exactly one archive should be specified");
1123 ArchiveSpecified
= true;
1124 ArchiveName
= argv
[i
];
1127 return performOperation(CreateSymTab
, nullptr);
1130 int main(int argc
, char **argv
) {
1131 InitLLVM
X(argc
, argv
);
1134 llvm::InitializeAllTargetInfos();
1135 llvm::InitializeAllTargetMCs();
1136 llvm::InitializeAllAsmParsers();
1138 Stem
= sys::path::stem(ToolName
);
1139 if (Stem
.contains_lower("dlltool"))
1140 return dlltoolDriverMain(makeArrayRef(argv
, argc
));
1142 if (Stem
.contains_lower("ranlib"))
1143 return ranlib_main(argc
, argv
);
1145 if (Stem
.contains_lower("lib"))
1146 return libDriverMain(makeArrayRef(argv
, argc
));
1148 if (Stem
.contains_lower("ar"))
1149 return ar_main(argc
, argv
);
1150 fail("not ranlib, ar, lib or dlltool");