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/StringExtras.h"
15 #include "llvm/ADT/StringSwitch.h"
16 #include "llvm/BinaryFormat/Magic.h"
17 #include "llvm/IR/LLVMContext.h"
18 #include "llvm/Object/Archive.h"
19 #include "llvm/Object/ArchiveWriter.h"
20 #include "llvm/Object/SymbolicFile.h"
21 #include "llvm/Support/Chrono.h"
22 #include "llvm/Support/CommandLine.h"
23 #include "llvm/Support/ConvertUTF.h"
24 #include "llvm/Support/Errc.h"
25 #include "llvm/Support/FileSystem.h"
26 #include "llvm/Support/Format.h"
27 #include "llvm/Support/FormatVariadic.h"
28 #include "llvm/Support/LLVMDriver.h"
29 #include "llvm/Support/LineIterator.h"
30 #include "llvm/Support/MemoryBuffer.h"
31 #include "llvm/Support/Path.h"
32 #include "llvm/Support/Process.h"
33 #include "llvm/Support/StringSaver.h"
34 #include "llvm/Support/TargetSelect.h"
35 #include "llvm/Support/ToolOutputFile.h"
36 #include "llvm/Support/WithColor.h"
37 #include "llvm/Support/raw_ostream.h"
38 #include "llvm/TargetParser/Host.h"
39 #include "llvm/TargetParser/Triple.h"
40 #include "llvm/ToolDrivers/llvm-dlltool/DlltoolDriver.h"
41 #include "llvm/ToolDrivers/llvm-lib/LibDriver.h"
43 #if !defined(_MSC_VER) && !defined(__MINGW32__)
50 #include "llvm/Support/Windows/WindowsSupport.h"
54 using namespace llvm::object
;
56 // The name this program was invoked as.
57 static StringRef ToolName
;
59 // The basename of this program.
60 static StringRef Stem
;
62 static void printRanLibHelp(StringRef ToolName
) {
63 outs() << "OVERVIEW: LLVM ranlib\n\n"
64 << "Generate an index for archives\n\n"
65 << "USAGE: " + ToolName
+ " archive...\n\n"
67 << " -h --help - Display available options\n"
68 << " -V --version - Display the version of this program\n"
69 << " -D - Use zero for timestamps and uids/gids "
71 << " -U - Use actual timestamps and uids/gids\n"
72 << " -X{32|64|32_64|any} - Specify which archive symbol tables "
73 "should be generated if they do not already exist (AIX OS only)\n";
76 static void printArHelp(StringRef ToolName
) {
77 const char ArOptions
[] =
79 --format - archive format to create
84 =bigarchive - big archive (AIX OS)
86 --plugin=<string> - ignored for compatibility
87 -h --help - display this help and exit
88 --output - the directory to extract archive members to
89 --rsp-quoting - quoting style for response files
92 --thin - create a thin archive
93 --version - print the version and exit
94 -X{32|64|32_64|any} - object mode (only for AIX OS)
95 @<file> - read options from <file>
98 d - delete [files] from the archive
99 m - move [files] in the archive
100 p - print contents of [files] found in the archive
101 q - quick append [files] to the archive
102 r - replace or insert [files] into the archive
104 t - display list of files in archive
105 x - extract [files] from the archive
108 [a] - put [files] after [relpos]
109 [b] - put [files] before [relpos] (same as [i])
110 [c] - do not warn if archive had to be created
111 [D] - use zero for timestamps and uids/gids (default)
112 [h] - display this help and exit
113 [i] - put [files] before [relpos] (same as [b])
114 [l] - ignored for compatibility
115 [L] - add archive's contents
116 [N] - use instance [count] of name
117 [o] - preserve original dates
118 [O] - display member offsets
119 [P] - use full names when matching (implied for thin archives)
120 [s] - create an archive index (cf. ranlib)
121 [S] - do not build a symbol table
122 [T] - deprecated, use --thin instead
123 [u] - update only [files] newer than archive contents
124 [U] - use actual timestamps and uids/gids
125 [v] - be verbose about actions taken
126 [V] - display the version and exit
129 outs() << "OVERVIEW: LLVM Archiver\n\n"
130 << "USAGE: " + ToolName
+
131 " [options] [-]<operation>[modifiers] [relpos] "
132 "[count] <archive> [files]\n"
133 << " " + ToolName
+ " -M [<mri-script]\n\n";
138 static void printHelpMessage() {
139 if (Stem
.contains_insensitive("ranlib"))
140 printRanLibHelp(Stem
);
141 else if (Stem
.contains_insensitive("ar"))
145 static unsigned MRILineNumber
;
146 static bool ParsingMRIScript
;
148 // Show the error plus the usage message, and exit.
149 [[noreturn
]] static void badUsage(Twine Error
) {
150 WithColor::error(errs(), ToolName
) << Error
<< "\n";
155 // Show the error message and exit.
156 [[noreturn
]] static void fail(Twine Error
) {
157 if (ParsingMRIScript
) {
158 WithColor::error(errs(), ToolName
)
159 << "script line " << MRILineNumber
<< ": " << Error
<< "\n";
161 WithColor::error(errs(), ToolName
) << Error
<< "\n";
166 static void failIfError(std::error_code EC
, Twine Context
= "") {
170 std::string ContextStr
= Context
.str();
171 if (ContextStr
.empty())
173 fail(Context
+ ": " + EC
.message());
176 static void failIfError(Error E
, Twine Context
= "") {
180 handleAllErrors(std::move(E
), [&](const llvm::ErrorInfoBase
&EIB
) {
181 std::string ContextStr
= Context
.str();
182 if (ContextStr
.empty())
184 fail(Context
+ ": " + EIB
.message());
188 static void warn(Twine Message
) {
189 WithColor::warning(errs(), ToolName
) << Message
<< "\n";
192 static SmallVector
<const char *, 256> PositionalArgs
;
197 enum Format
{ Default
, GNU
, COFF
, BSD
, DARWIN
, BIGARCHIVE
, Unknown
};
200 static Format FormatType
= Default
;
202 static std::string Options
;
204 // This enumeration delineates the kinds of operations on an archive
205 // that are permitted.
206 enum ArchiveOperation
{
207 Print
, ///< Print the contents of the archive
208 Delete
, ///< Delete the specified members
209 Move
, ///< Move members to end or as given by {a,b,i} modifiers
210 QuickAppend
, ///< Quickly append to end of archive
211 ReplaceOrInsert
, ///< Replace or Insert members
212 DisplayTable
, ///< Display the table of contents
213 Extract
, ///< Extract files back to file system
214 CreateSymTab
///< Create a symbol table in an existing archive
217 enum class BitModeTy
{ Bit32
, Bit64
, Bit32_64
, Any
, Unknown
};
219 static BitModeTy BitMode
= BitModeTy::Bit32
;
221 // Modifiers to follow operation to vary behavior
222 static bool AddAfter
= false; ///< 'a' modifier
223 static bool AddBefore
= false; ///< 'b' modifier
224 static bool Create
= false; ///< 'c' modifier
225 static bool OriginalDates
= false; ///< 'o' modifier
226 static bool DisplayMemberOffsets
= false; ///< 'O' modifier
227 static bool CompareFullPath
= false; ///< 'P' modifier
228 static bool OnlyUpdate
= false; ///< 'u' modifier
229 static bool Verbose
= false; ///< 'v' modifier
230 static SymtabWritingMode Symtab
=
231 SymtabWritingMode::NormalSymtab
; ///< 's' modifier
232 static bool Deterministic
= true; ///< 'D' and 'U' modifiers
233 static bool Thin
= false; ///< 'T' modifier
234 static bool AddLibrary
= false; ///< 'L' modifier
236 // Relative Positional Argument (for insert/move). This variable holds
237 // the name of the archive member to which the 'a', 'b' or 'i' modifier
238 // refers. Only one of 'a', 'b' or 'i' can be specified so we only need
240 static std::string RelPos
;
242 // Count parameter for 'N' modifier. This variable specifies which file should
243 // match for extract/delete operations when there are multiple matches. This is
244 // 1-indexed. A value of 0 is invalid, and implies 'N' is not used.
245 static int CountParam
= 0;
247 // This variable holds the name of the archive file as given on the
249 static std::string ArchiveName
;
251 // Output directory specified by --output.
252 static std::string OutputDir
;
254 static std::vector
<std::unique_ptr
<MemoryBuffer
>> ArchiveBuffers
;
255 static std::vector
<std::unique_ptr
<object::Archive
>> Archives
;
257 // This variable holds the list of member files to proecess, as given
258 // on the command line.
259 static std::vector
<StringRef
> Members
;
261 // Static buffer to hold StringRefs.
262 static BumpPtrAllocator Alloc
;
264 // Extract the member filename from the command line for the [relpos] argument
265 // associated with a, b, and i modifiers
266 static void getRelPos() {
267 if (PositionalArgs
.empty())
268 fail("expected [relpos] for 'a', 'b', or 'i' modifier");
269 RelPos
= PositionalArgs
[0];
270 PositionalArgs
.erase(PositionalArgs
.begin());
273 // Extract the parameter from the command line for the [count] argument
274 // associated with the N modifier
275 static void getCountParam() {
276 if (PositionalArgs
.empty())
277 badUsage("expected [count] for 'N' modifier");
278 auto CountParamArg
= StringRef(PositionalArgs
[0]);
279 if (CountParamArg
.getAsInteger(10, CountParam
))
280 badUsage("value for [count] must be numeric, got: " + CountParamArg
);
282 badUsage("value for [count] must be positive, got: " + CountParamArg
);
283 PositionalArgs
.erase(PositionalArgs
.begin());
286 // Get the archive file name from the command line
287 static void getArchive() {
288 if (PositionalArgs
.empty())
289 badUsage("an archive name must be specified");
290 ArchiveName
= PositionalArgs
[0];
291 PositionalArgs
.erase(PositionalArgs
.begin());
294 static object::Archive
&readLibrary(const Twine
&Library
) {
295 auto BufOrErr
= MemoryBuffer::getFile(Library
, /*IsText=*/false,
296 /*RequiresNullTerminator=*/false);
297 failIfError(BufOrErr
.getError(), "could not open library " + Library
);
298 ArchiveBuffers
.push_back(std::move(*BufOrErr
));
300 object::Archive::create(ArchiveBuffers
.back()->getMemBufferRef());
301 failIfError(errorToErrorCode(LibOrErr
.takeError()),
302 "could not parse library");
303 Archives
.push_back(std::move(*LibOrErr
));
304 return *Archives
.back();
307 static void runMRIScript();
309 // Parse the command line options as presented and return the operation
310 // specified. Process all modifiers and check to make sure that constraints on
311 // modifier/operation pairs have not been violated.
312 static ArchiveOperation
parseCommandLine() {
314 if (!PositionalArgs
.empty() || !Options
.empty())
315 badUsage("cannot mix -M and other options");
319 // Keep track of number of operations. We can only specify one
321 unsigned NumOperations
= 0;
323 // Keep track of the number of positional modifiers (a,b,i). Only
324 // one can be specified.
325 unsigned NumPositional
= 0;
327 // Keep track of which operation was requested
328 ArchiveOperation Operation
;
330 bool MaybeJustCreateSymTab
= false;
332 for (unsigned i
= 0; i
< Options
.size(); ++i
) {
333 switch (Options
[i
]) {
348 Operation
= QuickAppend
;
352 Operation
= ReplaceOrInsert
;
356 Operation
= DisplayTable
;
365 case 'l': /* accepted but unused */
368 OriginalDates
= true;
371 DisplayMemberOffsets
= true;
374 CompareFullPath
= true;
377 Symtab
= SymtabWritingMode::NormalSymtab
;
378 MaybeJustCreateSymTab
= true;
381 Symtab
= SymtabWritingMode::NoSymtab
;
405 Deterministic
= true;
408 Deterministic
= false;
420 cl::PrintVersionMessage();
426 badUsage(std::string("unknown option ") + Options
[i
]);
430 // Thin archives store path names, so P should be forced.
432 CompareFullPath
= true;
434 // At this point, the next thing on the command line must be
438 // Everything on the command line at this point is a member.
439 Members
.assign(PositionalArgs
.begin(), PositionalArgs
.end());
441 if (NumOperations
== 0 && MaybeJustCreateSymTab
) {
443 Operation
= CreateSymTab
;
444 if (!Members
.empty())
445 badUsage("the 's' operation takes only an archive as argument");
448 // Perform various checks on the operation/modifier specification
449 // to make sure we are dealing with a legal request.
450 if (NumOperations
== 0)
451 badUsage("you must specify at least one of the operations");
452 if (NumOperations
> 1)
453 badUsage("only one operation may be specified");
454 if (NumPositional
> 1)
455 badUsage("you may only specify one of 'a', 'b', and 'i' modifiers");
456 if (AddAfter
|| AddBefore
)
457 if (Operation
!= Move
&& Operation
!= ReplaceOrInsert
)
458 badUsage("the 'a', 'b' and 'i' modifiers can only be specified with "
459 "the 'm' or 'r' operations");
461 if (Operation
!= Extract
&& Operation
!= Delete
)
462 badUsage("the 'N' modifier can only be specified with the 'x' or 'd' "
464 if (OriginalDates
&& Operation
!= Extract
)
465 badUsage("the 'o' modifier is only applicable to the 'x' operation");
466 if (OnlyUpdate
&& Operation
!= ReplaceOrInsert
)
467 badUsage("the 'u' modifier is only applicable to the 'r' operation");
468 if (AddLibrary
&& Operation
!= QuickAppend
)
469 badUsage("the 'L' modifier is only applicable to the 'q' operation");
471 if (!OutputDir
.empty()) {
472 if (Operation
!= Extract
)
473 badUsage("--output is only applicable to the 'x' operation");
475 // If OutputDir is not a directory, create_directories may still succeed if
476 // all components of the path prefix are directories. Test is_directory as
478 if (!sys::fs::create_directories(OutputDir
))
479 sys::fs::is_directory(OutputDir
, IsDir
);
481 fail("'" + OutputDir
+ "' is not a directory");
484 // Return the parsed operation to the caller
488 // Implements the 'p' operation. This function traverses the archive
489 // looking for members that match the path list.
490 static void doPrint(StringRef Name
, const object::Archive::Child
&C
) {
492 outs() << "Printing " << Name
<< "\n";
494 Expected
<StringRef
> DataOrErr
= C
.getBuffer();
495 failIfError(DataOrErr
.takeError());
496 StringRef Data
= *DataOrErr
;
497 outs().write(Data
.data(), Data
.size());
500 // Utility function for printing out the file mode when the 't' operation is in
502 static void printMode(unsigned mode
) {
503 outs() << ((mode
& 004) ? "r" : "-");
504 outs() << ((mode
& 002) ? "w" : "-");
505 outs() << ((mode
& 001) ? "x" : "-");
508 // Implement the 't' operation. This function prints out just
509 // the file names of each of the members. However, if verbose mode is requested
510 // ('v' modifier) then the file type, permission mode, user, group, size, and
511 // modification time are also printed.
512 static void doDisplayTable(StringRef Name
, const object::Archive::Child
&C
) {
514 Expected
<sys::fs::perms
> ModeOrErr
= C
.getAccessMode();
515 failIfError(ModeOrErr
.takeError());
516 sys::fs::perms Mode
= ModeOrErr
.get();
517 printMode((Mode
>> 6) & 007);
518 printMode((Mode
>> 3) & 007);
519 printMode(Mode
& 007);
520 Expected
<unsigned> UIDOrErr
= C
.getUID();
521 failIfError(UIDOrErr
.takeError());
522 outs() << ' ' << UIDOrErr
.get();
523 Expected
<unsigned> GIDOrErr
= C
.getGID();
524 failIfError(GIDOrErr
.takeError());
525 outs() << '/' << GIDOrErr
.get();
526 Expected
<uint64_t> Size
= C
.getSize();
527 failIfError(Size
.takeError());
528 outs() << ' ' << format("%6llu", Size
.get());
529 auto ModTimeOrErr
= C
.getLastModified();
530 failIfError(ModTimeOrErr
.takeError());
531 // Note: formatv() only handles the default TimePoint<>, which is in
533 // TODO: fix format_provider<TimePoint<>> to allow other units.
534 sys::TimePoint
<> ModTimeInNs
= ModTimeOrErr
.get();
535 outs() << ' ' << formatv("{0:%b %e %H:%M %Y}", ModTimeInNs
);
539 if (C
.getParent()->isThin()) {
540 if (!sys::path::is_absolute(Name
)) {
541 StringRef ParentDir
= sys::path::parent_path(ArchiveName
);
542 if (!ParentDir
.empty())
543 outs() << sys::path::convert_to_slash(ParentDir
) << '/';
548 if (DisplayMemberOffsets
)
549 outs() << " 0x" << utohexstr(C
.getDataOffset(), true);
554 static std::string
normalizePath(StringRef Path
) {
555 return CompareFullPath
? sys::path::convert_to_slash(Path
)
556 : std::string(sys::path::filename(Path
));
559 static bool comparePaths(StringRef Path1
, StringRef Path2
) {
560 // When on Windows this function calls CompareStringOrdinal
561 // as Windows file paths are case-insensitive.
562 // CompareStringOrdinal compares two Unicode strings for
563 // binary equivalence and allows for case insensitivity.
565 SmallVector
<wchar_t, 128> WPath1
, WPath2
;
566 failIfError(sys::windows::UTF8ToUTF16(normalizePath(Path1
), WPath1
));
567 failIfError(sys::windows::UTF8ToUTF16(normalizePath(Path2
), WPath2
));
569 return CompareStringOrdinal(WPath1
.data(), WPath1
.size(), WPath2
.data(),
570 WPath2
.size(), true) == CSTR_EQUAL
;
572 return normalizePath(Path1
) == normalizePath(Path2
);
576 // Implement the 'x' operation. This function extracts files back to the file
578 static void doExtract(StringRef Name
, const object::Archive::Child
&C
) {
579 // Retain the original mode.
580 Expected
<sys::fs::perms
> ModeOrErr
= C
.getAccessMode();
581 failIfError(ModeOrErr
.takeError());
582 sys::fs::perms Mode
= ModeOrErr
.get();
584 StringRef outputFilePath
;
585 SmallString
<128> path
;
586 if (OutputDir
.empty()) {
587 outputFilePath
= sys::path::filename(Name
);
589 sys::path::append(path
, OutputDir
, sys::path::filename(Name
));
590 outputFilePath
= path
.str();
594 outs() << "x - " << outputFilePath
<< '\n';
597 failIfError(sys::fs::openFileForWrite(outputFilePath
, FD
,
598 sys::fs::CD_CreateAlways
,
599 sys::fs::OF_None
, Mode
),
603 raw_fd_ostream
file(FD
, false);
605 // Get the data and its length
606 Expected
<StringRef
> BufOrErr
= C
.getBuffer();
607 failIfError(BufOrErr
.takeError());
608 StringRef Data
= BufOrErr
.get();
611 file
.write(Data
.data(), Data
.size());
614 // If we're supposed to retain the original modification times, etc. do so
617 auto ModTimeOrErr
= C
.getLastModified();
618 failIfError(ModTimeOrErr
.takeError());
620 sys::fs::setLastAccessAndModificationTime(FD
, ModTimeOrErr
.get()));
624 fail("Could not close the file");
627 static bool shouldCreateArchive(ArchiveOperation Op
) {
638 case ReplaceOrInsert
:
642 llvm_unreachable("Missing entry in covered switch.");
645 static bool isValidInBitMode(Binary
&Bin
) {
646 if (BitMode
== BitModeTy::Bit32_64
|| BitMode
== BitModeTy::Any
)
649 if (SymbolicFile
*SymFile
= dyn_cast
<SymbolicFile
>(&Bin
)) {
650 bool Is64Bit
= SymFile
->is64Bit();
651 if ((Is64Bit
&& (BitMode
== BitModeTy::Bit32
)) ||
652 (!Is64Bit
&& (BitMode
== BitModeTy::Bit64
)))
655 // In AIX "ar", non-object files are always considered to have a valid bit
660 Expected
<std::unique_ptr
<Binary
>> getAsBinary(const NewArchiveMember
&NM
,
661 LLVMContext
*Context
) {
662 auto BinaryOrErr
= createBinary(NM
.Buf
->getMemBufferRef(), Context
);
664 return std::move(*BinaryOrErr
);
665 return BinaryOrErr
.takeError();
668 Expected
<std::unique_ptr
<Binary
>> getAsBinary(const Archive::Child
&C
,
669 LLVMContext
*Context
) {
670 return C
.getAsBinary(Context
);
673 template <class A
> static bool isValidInBitMode(const A
&Member
) {
674 if (object::Archive::getDefaultKind() != object::Archive::K_AIXBIG
)
677 Expected
<std::unique_ptr
<Binary
>> BinOrErr
= getAsBinary(Member
, &Context
);
678 // In AIX "ar", if there is a non-object file member, it is never ignored due
679 // to the bit mode setting.
681 consumeError(BinOrErr
.takeError());
684 return isValidInBitMode(*BinOrErr
.get());
687 static void warnInvalidObjectForFileMode(Twine Name
) {
688 warn("'" + Name
+ "' is not valid with the current object file mode");
691 static void performReadOperation(ArchiveOperation Operation
,
692 object::Archive
*OldArchive
) {
693 if (Operation
== Extract
&& OldArchive
->isThin())
694 fail("extracting from a thin archive is not supported");
696 bool Filter
= !Members
.empty();
697 StringMap
<int> MemberCount
;
699 Error Err
= Error::success();
700 for (auto &C
: OldArchive
->children(Err
)) {
701 Expected
<StringRef
> NameOrErr
= C
.getName();
702 failIfError(NameOrErr
.takeError());
703 StringRef Name
= NameOrErr
.get();
705 // Check whether to ignore this object due to its bitness.
706 if (!isValidInBitMode(C
))
710 auto I
= find_if(Members
, [Name
](StringRef Path
) {
711 return comparePaths(Name
, Path
);
713 if (I
== Members
.end())
715 if (CountParam
&& ++MemberCount
[Name
] != CountParam
)
722 llvm_unreachable("Not a read operation");
727 doDisplayTable(Name
, C
);
734 failIfError(std::move(Err
));
739 for (StringRef Name
: Members
)
740 WithColor::error(errs(), ToolName
) << "'" << Name
<< "' was not found\n";
744 static void addChildMember(std::vector
<NewArchiveMember
> &Members
,
745 const object::Archive::Child
&M
,
746 bool FlattenArchive
= false) {
747 Expected
<NewArchiveMember
> NMOrErr
=
748 NewArchiveMember::getOldMember(M
, Deterministic
);
749 failIfError(NMOrErr
.takeError());
750 // If the child member we're trying to add is thin, use the path relative to
751 // the archive it's in, so the file resolves correctly.
752 if (Thin
&& FlattenArchive
) {
753 StringSaver
Saver(Alloc
);
754 Expected
<std::string
> FileNameOrErr(M
.getName());
755 failIfError(FileNameOrErr
.takeError());
756 if (sys::path::is_absolute(*FileNameOrErr
)) {
757 NMOrErr
->MemberName
= Saver
.save(sys::path::convert_to_slash(*FileNameOrErr
));
759 FileNameOrErr
= M
.getFullName();
760 failIfError(FileNameOrErr
.takeError());
761 Expected
<std::string
> PathOrErr
=
762 computeArchiveRelativePath(ArchiveName
, *FileNameOrErr
);
763 NMOrErr
->MemberName
= Saver
.save(
764 PathOrErr
? *PathOrErr
: sys::path::convert_to_slash(*FileNameOrErr
));
767 if (FlattenArchive
&&
768 identify_magic(NMOrErr
->Buf
->getBuffer()) == file_magic::archive
) {
769 Expected
<std::string
> FileNameOrErr
= M
.getFullName();
770 failIfError(FileNameOrErr
.takeError());
771 object::Archive
&Lib
= readLibrary(*FileNameOrErr
);
772 // When creating thin archives, only flatten if the member is also thin.
773 if (!Thin
|| Lib
.isThin()) {
774 Error Err
= Error::success();
775 // Only Thin archives are recursively flattened.
776 for (auto &Child
: Lib
.children(Err
))
777 addChildMember(Members
, Child
, /*FlattenArchive=*/Thin
);
778 failIfError(std::move(Err
));
782 Members
.push_back(std::move(*NMOrErr
));
785 static NewArchiveMember
getArchiveMember(StringRef FileName
) {
786 Expected
<NewArchiveMember
> NMOrErr
=
787 NewArchiveMember::getFile(FileName
, Deterministic
);
788 failIfError(NMOrErr
.takeError(), FileName
);
789 StringSaver
Saver(Alloc
);
790 // For regular archives, use the basename of the object path for the member
791 // name. For thin archives, use the full relative paths so the file resolves
794 NMOrErr
->MemberName
= sys::path::filename(NMOrErr
->MemberName
);
796 if (sys::path::is_absolute(FileName
))
797 NMOrErr
->MemberName
= Saver
.save(sys::path::convert_to_slash(FileName
));
799 Expected
<std::string
> PathOrErr
=
800 computeArchiveRelativePath(ArchiveName
, FileName
);
801 NMOrErr
->MemberName
= Saver
.save(
802 PathOrErr
? *PathOrErr
: sys::path::convert_to_slash(FileName
));
805 return std::move(*NMOrErr
);
808 static void addMember(std::vector
<NewArchiveMember
> &Members
,
809 NewArchiveMember
&NM
) {
810 Members
.push_back(std::move(NM
));
813 static void addMember(std::vector
<NewArchiveMember
> &Members
,
814 StringRef FileName
, bool FlattenArchive
= false) {
815 NewArchiveMember NM
= getArchiveMember(FileName
);
816 if (!isValidInBitMode(NM
)) {
817 warnInvalidObjectForFileMode(FileName
);
821 if (FlattenArchive
&&
822 identify_magic(NM
.Buf
->getBuffer()) == file_magic::archive
) {
823 object::Archive
&Lib
= readLibrary(FileName
);
824 // When creating thin archives, only flatten if the member is also thin.
825 if (!Thin
|| Lib
.isThin()) {
826 Error Err
= Error::success();
827 // Only Thin archives are recursively flattened.
828 for (auto &Child
: Lib
.children(Err
))
829 addChildMember(Members
, Child
, /*FlattenArchive=*/Thin
);
830 failIfError(std::move(Err
));
834 Members
.push_back(std::move(NM
));
845 static InsertAction
computeInsertAction(ArchiveOperation Operation
,
846 const object::Archive::Child
&Member
,
848 std::vector
<StringRef
>::iterator
&Pos
,
849 StringMap
<int> &MemberCount
) {
850 if (!isValidInBitMode(Member
))
851 return IA_AddOldMember
;
853 if (Operation
== QuickAppend
|| Members
.empty())
854 return IA_AddOldMember
;
856 auto MI
= find_if(Members
, [Name
](StringRef Path
) {
857 if (Thin
&& !sys::path::is_absolute(Path
)) {
858 Expected
<std::string
> PathOrErr
=
859 computeArchiveRelativePath(ArchiveName
, Path
);
860 return comparePaths(Name
, PathOrErr
? *PathOrErr
: Path
);
862 return comparePaths(Name
, Path
);
866 if (MI
== Members
.end())
867 return IA_AddOldMember
;
871 if (Operation
== Delete
) {
872 if (CountParam
&& ++MemberCount
[Name
] != CountParam
)
873 return IA_AddOldMember
;
877 if (Operation
== Move
)
878 return IA_MoveOldMember
;
880 if (Operation
== ReplaceOrInsert
) {
883 return IA_AddNewMember
;
884 return IA_MoveNewMember
;
887 // We could try to optimize this to a fstat, but it is not a common
889 sys::fs::file_status Status
;
890 failIfError(sys::fs::status(*MI
, Status
), *MI
);
891 auto ModTimeOrErr
= Member
.getLastModified();
892 failIfError(ModTimeOrErr
.takeError());
893 if (Status
.getLastModificationTime() < ModTimeOrErr
.get()) {
895 return IA_AddOldMember
;
896 return IA_MoveOldMember
;
900 return IA_AddNewMember
;
901 return IA_MoveNewMember
;
903 llvm_unreachable("No such operation");
906 // We have to walk this twice and computing it is not trivial, so creating an
907 // explicit std::vector is actually fairly efficient.
908 static std::vector
<NewArchiveMember
>
909 computeNewArchiveMembers(ArchiveOperation Operation
,
910 object::Archive
*OldArchive
) {
911 std::vector
<NewArchiveMember
> Ret
;
912 std::vector
<NewArchiveMember
> Moved
;
915 Error Err
= Error::success();
916 StringMap
<int> MemberCount
;
917 for (auto &Child
: OldArchive
->children(Err
)) {
918 int Pos
= Ret
.size();
919 Expected
<StringRef
> NameOrErr
= Child
.getName();
920 failIfError(NameOrErr
.takeError());
921 std::string Name
= std::string(NameOrErr
.get());
922 if (comparePaths(Name
, RelPos
) && isValidInBitMode(Child
)) {
923 assert(AddAfter
|| AddBefore
);
930 std::vector
<StringRef
>::iterator MemberI
= Members
.end();
931 InsertAction Action
=
932 computeInsertAction(Operation
, Child
, Name
, MemberI
, MemberCount
);
934 auto HandleNewMember
= [](auto Member
, auto &Members
, auto &Child
) {
935 NewArchiveMember NM
= getArchiveMember(*Member
);
936 if (isValidInBitMode(NM
))
937 addMember(Members
, NM
);
939 // If a new member is not a valid object for the bit mode, add
940 // the old member back.
941 warnInvalidObjectForFileMode(*Member
);
942 addChildMember(Members
, Child
, /*FlattenArchive=*/Thin
);
947 case IA_AddOldMember
:
948 addChildMember(Ret
, Child
, /*FlattenArchive=*/Thin
);
950 case IA_AddNewMember
:
951 HandleNewMember(MemberI
, Ret
, Child
);
955 case IA_MoveOldMember
:
956 addChildMember(Moved
, Child
, /*FlattenArchive=*/Thin
);
958 case IA_MoveNewMember
:
959 HandleNewMember(MemberI
, Moved
, Child
);
962 // When processing elements with the count param, we need to preserve the
963 // full members list when iterating over all archive members. For
964 // instance, "llvm-ar dN 2 archive.a member.o" should delete the second
965 // file named member.o it sees; we are not done with member.o the first
966 // time we see it in the archive.
967 if (MemberI
!= Members
.end() && !CountParam
)
968 Members
.erase(MemberI
);
970 failIfError(std::move(Err
));
973 if (Operation
== Delete
)
976 if (!RelPos
.empty() && InsertPos
== -1)
977 fail("insertion point not found");
980 InsertPos
= Ret
.size();
982 assert(unsigned(InsertPos
) <= Ret
.size());
984 for (auto &M
: Moved
) {
985 Ret
.insert(Ret
.begin() + Pos
, std::move(M
));
990 assert(Operation
== QuickAppend
);
991 for (auto &Member
: Members
)
992 addMember(Ret
, Member
, /*FlattenArchive=*/true);
996 std::vector
<NewArchiveMember
> NewMembers
;
997 for (auto &Member
: Members
)
998 addMember(NewMembers
, Member
, /*FlattenArchive=*/Thin
);
999 Ret
.reserve(Ret
.size() + NewMembers
.size());
1000 std::move(NewMembers
.begin(), NewMembers
.end(),
1001 std::inserter(Ret
, std::next(Ret
.begin(), InsertPos
)));
1006 static void performWriteOperation(ArchiveOperation Operation
,
1007 object::Archive
*OldArchive
,
1008 std::unique_ptr
<MemoryBuffer
> OldArchiveBuf
,
1009 std::vector
<NewArchiveMember
> *NewMembersP
) {
1011 if (Thin
&& !OldArchive
->isThin())
1012 fail("cannot convert a regular archive to a thin one");
1014 if (OldArchive
->isThin())
1018 std::vector
<NewArchiveMember
> NewMembers
;
1020 NewMembers
= computeNewArchiveMembers(Operation
, OldArchive
);
1022 object::Archive::Kind Kind
;
1023 switch (FormatType
) {
1026 Kind
= object::Archive::K_GNU
;
1027 else if (OldArchive
) {
1028 Kind
= OldArchive
->kind();
1029 std::optional
<object::Archive::Kind
> AltKind
;
1030 if (Kind
== object::Archive::K_BSD
)
1031 AltKind
= object::Archive::K_DARWIN
;
1032 else if (Kind
== object::Archive::K_GNU
&& !OldArchive
->hasSymbolTable())
1033 // If there is no symbol table, we can't tell GNU from COFF format
1034 // from the old archive type.
1035 AltKind
= object::Archive::K_COFF
;
1037 auto InferredKind
= Kind
;
1038 if (NewMembersP
&& !NewMembersP
->empty())
1039 InferredKind
= NewMembersP
->front().detectKindFromObject();
1040 else if (!NewMembers
.empty())
1041 InferredKind
= NewMembers
.front().detectKindFromObject();
1042 if (InferredKind
== AltKind
)
1045 } else if (NewMembersP
)
1046 Kind
= !NewMembersP
->empty() ? NewMembersP
->front().detectKindFromObject()
1047 : object::Archive::getDefaultKind();
1049 Kind
= !NewMembers
.empty() ? NewMembers
.front().detectKindFromObject()
1050 : object::Archive::getDefaultKind();
1053 Kind
= object::Archive::K_GNU
;
1056 Kind
= object::Archive::K_COFF
;
1060 fail("only the gnu format has a thin mode");
1061 Kind
= object::Archive::K_BSD
;
1065 fail("only the gnu format has a thin mode");
1066 Kind
= object::Archive::K_DARWIN
;
1070 fail("only the gnu format has a thin mode");
1071 Kind
= object::Archive::K_AIXBIG
;
1074 llvm_unreachable("");
1078 writeArchive(ArchiveName
, NewMembersP
? *NewMembersP
: NewMembers
, Symtab
,
1079 Kind
, Deterministic
, Thin
, std::move(OldArchiveBuf
));
1080 failIfError(std::move(E
), ArchiveName
);
1083 static void createSymbolTable(object::Archive
*OldArchive
) {
1084 // When an archive is created or modified, if the s option is given, the
1085 // resulting archive will have a current symbol table. If the S option
1086 // is given, it will have no symbol table.
1087 // In summary, we only need to update the symbol table if we have none.
1088 // This is actually very common because of broken build systems that think
1089 // they have to run ranlib.
1090 if (OldArchive
->hasSymbolTable()) {
1091 if (OldArchive
->kind() != object::Archive::K_AIXBIG
)
1094 // For archives in the Big Archive format, the bit mode option specifies
1095 // which symbol table to generate. The presence of a symbol table that does
1096 // not match the specified bit mode does not prevent creation of the symbol
1097 // table that has been requested.
1098 if (OldArchive
->kind() == object::Archive::K_AIXBIG
) {
1099 BigArchive
*BigArc
= dyn_cast
<BigArchive
>(OldArchive
);
1100 if (BigArc
->has32BitGlobalSymtab() &&
1101 Symtab
== SymtabWritingMode::BigArchive32
)
1104 if (BigArc
->has64BitGlobalSymtab() &&
1105 Symtab
== SymtabWritingMode::BigArchive64
)
1108 if (BigArc
->has32BitGlobalSymtab() && BigArc
->has64BitGlobalSymtab() &&
1109 Symtab
== SymtabWritingMode::NormalSymtab
)
1112 Symtab
= SymtabWritingMode::NormalSymtab
;
1115 if (OldArchive
->isThin())
1117 performWriteOperation(CreateSymTab
, OldArchive
, nullptr, nullptr);
1120 static void performOperation(ArchiveOperation Operation
,
1121 object::Archive
*OldArchive
,
1122 std::unique_ptr
<MemoryBuffer
> OldArchiveBuf
,
1123 std::vector
<NewArchiveMember
> *NewMembers
) {
1124 switch (Operation
) {
1128 performReadOperation(Operation
, OldArchive
);
1134 case ReplaceOrInsert
:
1135 performWriteOperation(Operation
, OldArchive
, std::move(OldArchiveBuf
),
1139 createSymbolTable(OldArchive
);
1142 llvm_unreachable("Unknown operation.");
1145 static int performOperation(ArchiveOperation Operation
) {
1146 // Create or open the archive object.
1147 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> Buf
= MemoryBuffer::getFile(
1148 ArchiveName
, /*IsText=*/false, /*RequiresNullTerminator=*/false);
1149 std::error_code EC
= Buf
.getError();
1150 if (EC
&& EC
!= errc::no_such_file_or_directory
)
1151 fail("unable to open '" + ArchiveName
+ "': " + EC
.message());
1154 Expected
<std::unique_ptr
<object::Archive
>> ArchiveOrError
=
1155 object::Archive::create(Buf
.get()->getMemBufferRef());
1156 if (!ArchiveOrError
)
1157 failIfError(ArchiveOrError
.takeError(),
1158 "unable to load '" + ArchiveName
+ "'");
1160 std::unique_ptr
<object::Archive
> Archive
= std::move(ArchiveOrError
.get());
1161 if (Archive
->isThin())
1162 CompareFullPath
= true;
1163 performOperation(Operation
, Archive
.get(), std::move(Buf
.get()),
1164 /*NewMembers=*/nullptr);
1168 assert(EC
== errc::no_such_file_or_directory
);
1170 if (!shouldCreateArchive(Operation
)) {
1171 failIfError(EC
, Twine("unable to load '") + ArchiveName
+ "'");
1174 // Produce a warning if we should and we're creating the archive
1175 warn("creating " + ArchiveName
);
1179 performOperation(Operation
, nullptr, nullptr, /*NewMembers=*/nullptr);
1183 static void runMRIScript() {
1184 enum class MRICommand
{ AddLib
, AddMod
, Create
, CreateThin
, Delete
, Save
, End
, Invalid
};
1186 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> Buf
= MemoryBuffer::getSTDIN();
1187 failIfError(Buf
.getError());
1188 const MemoryBuffer
&Ref
= *Buf
.get();
1190 std::vector
<NewArchiveMember
> NewMembers
;
1191 ParsingMRIScript
= true;
1193 for (line_iterator
I(Ref
, /*SkipBlanks*/ false), E
; I
!= E
; ++I
) {
1195 StringRef Line
= *I
;
1196 Line
= Line
.split(';').first
;
1197 Line
= Line
.split('*').first
;
1201 StringRef CommandStr
, Rest
;
1202 std::tie(CommandStr
, Rest
) = Line
.split(' ');
1204 if (!Rest
.empty() && Rest
.front() == '"' && Rest
.back() == '"')
1205 Rest
= Rest
.drop_front().drop_back();
1206 auto Command
= StringSwitch
<MRICommand
>(CommandStr
.lower())
1207 .Case("addlib", MRICommand::AddLib
)
1208 .Case("addmod", MRICommand::AddMod
)
1209 .Case("create", MRICommand::Create
)
1210 .Case("createthin", MRICommand::CreateThin
)
1211 .Case("delete", MRICommand::Delete
)
1212 .Case("save", MRICommand::Save
)
1213 .Case("end", MRICommand::End
)
1214 .Default(MRICommand::Invalid
);
1217 case MRICommand::AddLib
: {
1219 fail("no output archive has been opened");
1220 object::Archive
&Lib
= readLibrary(Rest
);
1222 if (Thin
&& !Lib
.isThin())
1223 fail("cannot add a regular archive's contents to a thin archive");
1224 Error Err
= Error::success();
1225 for (auto &Member
: Lib
.children(Err
))
1226 addChildMember(NewMembers
, Member
, /*FlattenArchive=*/Thin
);
1227 failIfError(std::move(Err
));
1231 case MRICommand::AddMod
:
1233 fail("no output archive has been opened");
1234 addMember(NewMembers
, Rest
);
1236 case MRICommand::CreateThin
:
1239 case MRICommand::Create
:
1241 if (!ArchiveName
.empty())
1242 fail("editing multiple archives not supported");
1244 fail("file already saved");
1245 ArchiveName
= std::string(Rest
);
1246 if (ArchiveName
.empty())
1247 fail("missing archive name");
1249 case MRICommand::Delete
: {
1250 llvm::erase_if(NewMembers
, [=](NewArchiveMember
&M
) {
1251 return comparePaths(M
.MemberName
, Rest
);
1255 case MRICommand::Save
:
1258 case MRICommand::End
:
1260 case MRICommand::Invalid
:
1261 fail("unknown command: " + CommandStr
);
1265 ParsingMRIScript
= false;
1267 // Nothing to do if not saved.
1269 performOperation(ReplaceOrInsert
, /*OldArchive=*/nullptr,
1270 /*OldArchiveBuf=*/nullptr, &NewMembers
);
1274 static bool handleGenericOption(StringRef arg
) {
1275 if (arg
== "--help" || arg
== "-h") {
1279 if (arg
== "--version") {
1280 cl::PrintVersionMessage();
1286 static BitModeTy
getBitMode(const char *RawBitMode
) {
1287 return StringSwitch
<BitModeTy
>(RawBitMode
)
1288 .Case("32", BitModeTy::Bit32
)
1289 .Case("64", BitModeTy::Bit64
)
1290 .Case("32_64", BitModeTy::Bit32_64
)
1291 .Case("any", BitModeTy::Any
)
1292 .Default(BitModeTy::Unknown
);
1295 static const char *matchFlagWithArg(StringRef Expected
,
1296 ArrayRef
<const char *>::iterator
&ArgIt
,
1297 ArrayRef
<const char *> Args
) {
1298 StringRef Arg
= *ArgIt
;
1300 Arg
.consume_front("--");
1302 size_t len
= Expected
.size();
1303 if (Arg
== Expected
) {
1304 if (++ArgIt
== Args
.end())
1305 fail(std::string(Expected
) + " requires an argument");
1309 if (Arg
.starts_with(Expected
) && Arg
.size() > len
&& Arg
[len
] == '=')
1310 return Arg
.data() + len
+ 1;
1315 static cl::TokenizerCallback
getRspQuoting(ArrayRef
<const char *> ArgsArr
) {
1316 cl::TokenizerCallback Ret
=
1317 Triple(sys::getProcessTriple()).getOS() == Triple::Win32
1318 ? cl::TokenizeWindowsCommandLine
1319 : cl::TokenizeGNUCommandLine
;
1321 for (ArrayRef
<const char *>::iterator ArgIt
= ArgsArr
.begin();
1322 ArgIt
!= ArgsArr
.end(); ++ArgIt
) {
1323 if (const char *Match
= matchFlagWithArg("rsp-quoting", ArgIt
, ArgsArr
)) {
1324 StringRef MatchRef
= Match
;
1325 if (MatchRef
== "posix")
1326 Ret
= cl::TokenizeGNUCommandLine
;
1327 else if (MatchRef
== "windows")
1328 Ret
= cl::TokenizeWindowsCommandLine
;
1330 fail(std::string("Invalid response file quoting style ") + Match
);
1337 static int ar_main(int argc
, char **argv
) {
1338 SmallVector
<const char *, 0> Argv(argv
+ 1, argv
+ argc
);
1339 StringSaver
Saver(Alloc
);
1341 cl::ExpandResponseFiles(Saver
, getRspQuoting(ArrayRef(argv
, argc
)), Argv
);
1343 // Get BitMode from enviorment variable "OBJECT_MODE" for AIX OS, if
1345 if (object::Archive::getDefaultKind() == object::Archive::K_AIXBIG
) {
1346 BitMode
= getBitMode(getenv("OBJECT_MODE"));
1347 if (BitMode
== BitModeTy::Unknown
)
1348 BitMode
= BitModeTy::Bit32
;
1351 for (ArrayRef
<const char *>::iterator ArgIt
= Argv
.begin();
1352 ArgIt
!= Argv
.end(); ++ArgIt
) {
1353 const char *Match
= nullptr;
1355 if (handleGenericOption(*ArgIt
))
1357 if (strcmp(*ArgIt
, "--") == 0) {
1359 for (; ArgIt
!= Argv
.end(); ++ArgIt
)
1360 PositionalArgs
.push_back(*ArgIt
);
1364 if (*ArgIt
[0] != '-') {
1365 if (Options
.empty())
1368 PositionalArgs
.push_back(*ArgIt
);
1372 if (strcmp(*ArgIt
, "-M") == 0) {
1377 if (strcmp(*ArgIt
, "--thin") == 0) {
1382 Match
= matchFlagWithArg("format", ArgIt
, Argv
);
1384 FormatType
= StringSwitch
<Format
>(Match
)
1385 .Case("default", Default
)
1387 .Case("darwin", DARWIN
)
1389 .Case("bigarchive", BIGARCHIVE
)
1392 if (FormatType
== Unknown
)
1393 fail(std::string("Invalid format ") + Match
);
1397 if ((Match
= matchFlagWithArg("output", ArgIt
, Argv
))) {
1402 if (matchFlagWithArg("plugin", ArgIt
, Argv
) ||
1403 matchFlagWithArg("rsp-quoting", ArgIt
, Argv
))
1406 if (strncmp(*ArgIt
, "-X", 2) == 0) {
1407 if (object::Archive::getDefaultKind() == object::Archive::K_AIXBIG
) {
1408 Match
= *(*ArgIt
+ 2) != '\0' ? *ArgIt
+ 2 : *(++ArgIt
);
1409 BitMode
= getBitMode(Match
);
1410 if (BitMode
== BitModeTy::Unknown
)
1411 fail(Twine("invalid bit mode: ") + Match
);
1414 fail(Twine(*ArgIt
) + " option not supported on non AIX OS");
1418 Options
+= *ArgIt
+ 1;
1421 return performOperation(parseCommandLine());
1424 static int ranlib_main(int argc
, char **argv
) {
1425 std::vector
<StringRef
> Archives
;
1426 bool HasAIXXOption
= false;
1428 for (int i
= 1; i
< argc
; ++i
) {
1429 StringRef
arg(argv
[i
]);
1430 if (handleGenericOption(arg
)) {
1432 } else if (arg
.consume_front("-")) {
1433 // Handle the -D/-U flag
1434 while (!arg
.empty()) {
1435 if (arg
.front() == 'D') {
1436 Deterministic
= true;
1437 } else if (arg
.front() == 'U') {
1438 Deterministic
= false;
1439 } else if (arg
.front() == 'h') {
1442 } else if (arg
.front() == 'V') {
1443 cl::PrintVersionMessage();
1445 } else if (arg
.front() == 'X') {
1446 if (object::Archive::getDefaultKind() == object::Archive::K_AIXBIG
) {
1447 HasAIXXOption
= true;
1448 arg
.consume_front("X");
1449 const char *Xarg
= arg
.data();
1450 if (Xarg
[0] == '\0') {
1451 if (argv
[i
+ 1][0] != '-')
1452 BitMode
= getBitMode(argv
[++i
]);
1454 BitMode
= BitModeTy::Unknown
;
1456 BitMode
= getBitMode(arg
.data());
1458 if (BitMode
== BitModeTy::Unknown
)
1459 fail("the specified object mode is not valid. Specify -X32, "
1460 "-X64, -X32_64, or -Xany");
1462 fail(Twine("-") + Twine(arg
) +
1463 " option not supported on non AIX OS");
1467 // TODO: GNU ranlib also supports a -t flag
1468 fail("Invalid option: '-" + arg
+ "'");
1470 arg
= arg
.drop_front(1);
1473 Archives
.push_back(arg
);
1477 if (object::Archive::getDefaultKind() == object::Archive::K_AIXBIG
) {
1478 // If not specify -X option, get BitMode from enviorment variable
1479 // "OBJECT_MODE" for AIX OS if specify.
1480 if (!HasAIXXOption
) {
1481 if (char *EnvObjectMode
= getenv("OBJECT_MODE")) {
1482 BitMode
= getBitMode(EnvObjectMode
);
1483 if (BitMode
== BitModeTy::Unknown
)
1484 fail("the OBJECT_MODE environment variable has an invalid value. "
1485 "OBJECT_MODE must be 32, 64, 32_64, or any");
1490 case BitModeTy::Bit32
:
1491 Symtab
= SymtabWritingMode::BigArchive32
;
1493 case BitModeTy::Bit64
:
1494 Symtab
= SymtabWritingMode::BigArchive64
;
1497 Symtab
= SymtabWritingMode::NormalSymtab
;
1502 for (StringRef Archive
: Archives
) {
1503 ArchiveName
= Archive
.str();
1504 performOperation(CreateSymTab
);
1506 if (Archives
.empty())
1507 badUsage("an archive name must be specified");
1511 int llvm_ar_main(int argc
, char **argv
, const llvm::ToolContext
&) {
1514 llvm::InitializeAllTargetInfos();
1515 llvm::InitializeAllTargetMCs();
1516 llvm::InitializeAllAsmParsers();
1518 Stem
= sys::path::stem(ToolName
);
1519 auto Is
= [](StringRef Tool
) {
1520 // We need to recognize the following filenames.
1522 // Lib.exe -> lib (see D44808, MSBuild runs Lib.exe)
1523 // dlltool.exe -> dlltool
1524 // arm-pokymllib32-linux-gnueabi-llvm-ar-10 -> ar
1525 auto I
= Stem
.rfind_insensitive(Tool
);
1526 return I
!= StringRef::npos
&&
1527 (I
+ Tool
.size() == Stem
.size() || !isAlnum(Stem
[I
+ Tool
.size()]));
1531 return dlltoolDriverMain(ArrayRef(argv
, argc
));
1533 return ranlib_main(argc
, argv
);
1535 return libDriverMain(ArrayRef(argv
, argc
));
1537 return ar_main(argc
, argv
);
1539 fail("not ranlib, ar, lib or dlltool");