1 //===-- llvm-ar.cpp - LLVM archive librarian utility ----------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // Builds up (relatively) standard unix archive files (.a) containing LLVM
11 // bitcode or other files.
13 //===----------------------------------------------------------------------===//
15 #include "llvm/LLVMContext.h"
16 #include "llvm/Module.h"
17 #include "llvm/Bitcode/Archive.h"
18 #include "llvm/Support/CommandLine.h"
19 #include "llvm/Support/FileSystem.h"
20 #include "llvm/Support/ManagedStatic.h"
21 #include "llvm/Support/PrettyStackTrace.h"
22 #include "llvm/Support/Format.h"
23 #include "llvm/Support/raw_ostream.h"
24 #include "llvm/Support/Signals.h"
30 // Option for compatibility with AIX, not used but must allow it to be present.
32 X32Option ("X32_64", cl::Hidden
,
33 cl::desc("Ignored option for compatibility with AIX"));
35 // llvm-ar operation code and modifier flags. This must come first.
36 static cl::opt
<std::string
>
37 Options(cl::Positional
, cl::Required
, cl::desc("{operation}[modifiers]..."));
39 // llvm-ar remaining positional arguments.
40 static cl::list
<std::string
>
41 RestOfArgs(cl::Positional
, cl::OneOrMore
,
42 cl::desc("[relpos] [count] <archive-file> [members]..."));
44 // MoreHelp - Provide additional help output explaining the operations and
45 // modifiers of llvm-ar. This object instructs the CommandLine library
46 // to print the text of the constructor when the --help option is given.
47 static cl::extrahelp
MoreHelp(
49 " d[NsS] - delete file(s) from the archive\n"
50 " m[abiSs] - move file(s) in the archive\n"
51 " p[kN] - print file(s) found in the archive\n"
52 " q[ufsS] - quick append file(s) to the archive\n"
53 " r[abfiuzRsS] - replace or insert file(s) into the archive\n"
54 " t - display contents of archive\n"
55 " x[No] - extract file(s) from the archive\n"
56 "\nMODIFIERS (operation specific):\n"
57 " [a] - put file(s) after [relpos]\n"
58 " [b] - put file(s) before [relpos] (same as [i])\n"
59 " [f] - truncate inserted file names\n"
60 " [i] - put file(s) before [relpos] (same as [b])\n"
61 " [k] - always print bitcode files (default is to skip them)\n"
62 " [N] - use instance [count] of name\n"
63 " [o] - preserve original dates\n"
64 " [P] - use full path names when matching\n"
65 " [R] - recurse through directories when inserting\n"
66 " [s] - create an archive index (cf. ranlib)\n"
67 " [S] - do not build a symbol table\n"
68 " [u] - update only files newer than archive contents\n"
69 " [z] - compress files before inserting/extracting\n"
70 "\nMODIFIERS (generic):\n"
71 " [c] - do not warn if the library had to be created\n"
72 " [v] - be verbose about actions taken\n"
73 " [V] - be *really* verbose about actions taken\n"
76 // This enumeration delineates the kinds of operations on an archive
77 // that are permitted.
78 enum ArchiveOperation
{
79 NoOperation
, ///< An operation hasn't been specified
80 Print
, ///< Print the contents of the archive
81 Delete
, ///< Delete the specified members
82 Move
, ///< Move members to end or as given by {a,b,i} modifiers
83 QuickAppend
, ///< Quickly append to end of archive
84 ReplaceOrInsert
, ///< Replace or Insert members
85 DisplayTable
, ///< Display the table of contents
86 Extract
///< Extract files back to file system
89 // Modifiers to follow operation to vary behavior
90 bool AddAfter
= false; ///< 'a' modifier
91 bool AddBefore
= false; ///< 'b' modifier
92 bool Create
= false; ///< 'c' modifier
93 bool TruncateNames
= false; ///< 'f' modifier
94 bool InsertBefore
= false; ///< 'i' modifier
95 bool DontSkipBitcode
= false; ///< 'k' modifier
96 bool UseCount
= false; ///< 'N' modifier
97 bool OriginalDates
= false; ///< 'o' modifier
98 bool FullPath
= false; ///< 'P' modifier
99 bool RecurseDirectories
= false; ///< 'R' modifier
100 bool SymTable
= true; ///< 's' & 'S' modifiers
101 bool OnlyUpdate
= false; ///< 'u' modifier
102 bool Verbose
= false; ///< 'v' modifier
103 bool ReallyVerbose
= false; ///< 'V' modifier
104 bool Compression
= false; ///< 'z' modifier
106 // Relative Positional Argument (for insert/move). This variable holds
107 // the name of the archive member to which the 'a', 'b' or 'i' modifier
108 // refers. Only one of 'a', 'b' or 'i' can be specified so we only need
112 // Select which of multiple entries in the archive with the same name should be
113 // used (specified with -N) for the delete and extract operations.
116 // This variable holds the name of the archive file as given on the
118 std::string ArchiveName
;
120 // This variable holds the list of member files to proecess, as given
121 // on the command line.
122 std::vector
<std::string
> Members
;
124 // This variable holds the (possibly expanded) list of path objects that
125 // correspond to files we will
126 std::set
<sys::Path
> Paths
;
128 // The Archive object to which all the editing operations will be sent.
129 Archive
* TheArchive
= 0;
131 // getRelPos - Extract the member filename from the command line for
132 // the [relpos] argument associated with a, b, and i modifiers
134 if(RestOfArgs
.size() > 0) {
135 RelPos
= RestOfArgs
[0];
136 RestOfArgs
.erase(RestOfArgs
.begin());
139 throw "Expected [relpos] for a, b, or i modifier";
142 // getCount - Extract the [count] argument associated with the N modifier
143 // from the command line and check its value.
145 if(RestOfArgs
.size() > 0) {
146 Count
= atoi(RestOfArgs
[0].c_str());
147 RestOfArgs
.erase(RestOfArgs
.begin());
150 throw "Expected [count] value with N modifier";
152 // Non-positive counts are not allowed
154 throw "Invalid [count] value (not a positive integer)";
157 // getArchive - Get the archive file name from the command line
159 if(RestOfArgs
.size() > 0) {
160 ArchiveName
= RestOfArgs
[0];
161 RestOfArgs
.erase(RestOfArgs
.begin());
164 throw "An archive name must be specified.";
167 // getMembers - Copy over remaining items in RestOfArgs to our Members vector
168 // This is just for clarity.
170 if(RestOfArgs
.size() > 0)
171 Members
= std::vector
<std::string
>(RestOfArgs
);
174 // parseCommandLine - Parse the command line options as presented and return the
175 // operation specified. Process all modifiers and check to make sure that
176 // constraints on modifier/operation pairs have not been violated.
177 ArchiveOperation
parseCommandLine() {
179 // Keep track of number of operations. We can only specify one
181 unsigned NumOperations
= 0;
183 // Keep track of the number of positional modifiers (a,b,i). Only
184 // one can be specified.
185 unsigned NumPositional
= 0;
187 // Keep track of which operation was requested
188 ArchiveOperation Operation
= NoOperation
;
190 for(unsigned i
=0; i
<Options
.size(); ++i
) {
192 case 'd': ++NumOperations
; Operation
= Delete
; break;
193 case 'm': ++NumOperations
; Operation
= Move
; break;
194 case 'p': ++NumOperations
; Operation
= Print
; break;
195 case 'q': ++NumOperations
; Operation
= QuickAppend
; break;
196 case 'r': ++NumOperations
; Operation
= ReplaceOrInsert
; break;
197 case 't': ++NumOperations
; Operation
= DisplayTable
; break;
198 case 'x': ++NumOperations
; Operation
= Extract
; break;
199 case 'c': Create
= true; break;
200 case 'f': TruncateNames
= true; break;
201 case 'k': DontSkipBitcode
= true; break;
202 case 'l': /* accepted but unused */ break;
203 case 'o': OriginalDates
= true; break;
204 case 'P': FullPath
= true; break;
205 case 'R': RecurseDirectories
= true; break;
206 case 's': SymTable
= true; break;
207 case 'S': SymTable
= false; break;
208 case 'u': OnlyUpdate
= true; break;
209 case 'v': Verbose
= true; break;
210 case 'V': Verbose
= ReallyVerbose
= true; break;
211 case 'z': Compression
= true; break;
232 cl::PrintHelpMessage();
236 // At this point, the next thing on the command line must be
240 // Everything on the command line at this point is a member.
243 // Perform various checks on the operation/modifier specification
244 // to make sure we are dealing with a legal request.
245 if (NumOperations
== 0)
246 throw "You must specify at least one of the operations";
247 if (NumOperations
> 1)
248 throw "Only one operation may be specified";
249 if (NumPositional
> 1)
250 throw "You may only specify one of a, b, and i modifiers";
251 if (AddAfter
|| AddBefore
|| InsertBefore
)
252 if (Operation
!= Move
&& Operation
!= ReplaceOrInsert
)
253 throw "The 'a', 'b' and 'i' modifiers can only be specified with "
254 "the 'm' or 'r' operations";
255 if (RecurseDirectories
&& Operation
!= ReplaceOrInsert
)
256 throw "The 'R' modifiers is only applicabe to the 'r' operation";
257 if (OriginalDates
&& Operation
!= Extract
)
258 throw "The 'o' modifier is only applicable to the 'x' operation";
259 if (TruncateNames
&& Operation
!=QuickAppend
&& Operation
!=ReplaceOrInsert
)
260 throw "The 'f' modifier is only applicable to the 'q' and 'r' operations";
261 if (OnlyUpdate
&& Operation
!= ReplaceOrInsert
)
262 throw "The 'u' modifier is only applicable to the 'r' operation";
263 if (Compression
&& Operation
!=ReplaceOrInsert
&& Operation
!=Extract
)
264 throw "The 'z' modifier is only applicable to the 'r' and 'x' operations";
265 if (Count
> 1 && Members
.size() > 1)
266 throw "Only one member name may be specified with the 'N' modifier";
268 // Return the parsed operation to the caller
272 // recurseDirectories - Implements the "R" modifier. This function scans through
273 // the Paths vector (built by buildPaths, below) and replaces any directories it
274 // finds with all the files in that directory (recursively). It uses the
275 // sys::Path::getDirectoryContent method to perform the actual directory scans.
277 recurseDirectories(const sys::Path
& path
,
278 std::set
<sys::Path
>& result
, std::string
* ErrMsg
) {
280 if (RecurseDirectories
) {
281 std::set
<sys::Path
> content
;
282 if (path
.getDirectoryContents(content
, ErrMsg
))
285 for (std::set
<sys::Path
>::iterator I
= content
.begin(), E
= content
.end();
287 // Make sure it exists and is a directory
288 sys::PathWithStatus
PwS(*I
);
289 const sys::FileStatus
*Status
= PwS
.getFileStatus(false, ErrMsg
);
293 std::set
<sys::Path
> moreResults
;
294 if (recurseDirectories(*I
, moreResults
, ErrMsg
))
296 result
.insert(moreResults
.begin(), moreResults
.end());
305 // buildPaths - Convert the strings in the Members vector to sys::Path objects
306 // and make sure they are valid and exist exist. This check is only needed for
307 // the operations that add/replace files to the archive ('q' and 'r')
308 bool buildPaths(bool checkExistence
, std::string
* ErrMsg
) {
309 for (unsigned i
= 0; i
< Members
.size(); i
++) {
311 if (!aPath
.set(Members
[i
]))
312 throw std::string("File member name invalid: ") + Members
[i
];
313 if (checkExistence
) {
315 if (sys::fs::exists(aPath
.str(), Exists
) || !Exists
)
316 throw std::string("File does not exist: ") + Members
[i
];
318 sys::PathWithStatus
PwS(aPath
);
319 const sys::FileStatus
*si
= PwS
.getFileStatus(false, &Err
);
323 std::set
<sys::Path
> dirpaths
;
324 if (recurseDirectories(aPath
, dirpaths
, ErrMsg
))
326 Paths
.insert(dirpaths
.begin(),dirpaths
.end());
337 // printSymbolTable - print out the archive's symbol table.
338 void printSymbolTable() {
339 outs() << "\nArchive Symbol Table:\n";
340 const Archive::SymTabType
& symtab
= TheArchive
->getSymbolTable();
341 for (Archive::SymTabType::const_iterator I
=symtab
.begin(), E
=symtab
.end();
343 unsigned offset
= TheArchive
->getFirstFileOffset() + I
->second
;
344 outs() << " " << format("%9u", offset
) << "\t" << I
->first
<<"\n";
348 // doPrint - Implements the 'p' operation. This function traverses the archive
349 // looking for members that match the path list. It is careful to uncompress
350 // things that should be and to skip bitcode files unless the 'k' modifier was
352 bool doPrint(std::string
* ErrMsg
) {
353 if (buildPaths(false, ErrMsg
))
355 unsigned countDown
= Count
;
356 for (Archive::iterator I
= TheArchive
->begin(), E
= TheArchive
->end();
359 (std::find(Paths
.begin(), Paths
.end(), I
->getPath()) != Paths
.end())) {
360 if (countDown
== 1) {
361 const char* data
= reinterpret_cast<const char*>(I
->getData());
363 // Skip things that don't make sense to print
364 if (I
->isLLVMSymbolTable() || I
->isSVR4SymbolTable() ||
365 I
->isBSD4SymbolTable() || (!DontSkipBitcode
&& I
->isBitcode()))
369 outs() << "Printing " << I
->getPath().str() << "\n";
371 unsigned len
= I
->getSize();
372 outs().write(data
, len
);
381 // putMode - utility function for printing out the file mode when the 't'
382 // operation is in verbose mode.
384 printMode(unsigned mode
) {
399 // doDisplayTable - Implement the 't' operation. This function prints out just
400 // the file names of each of the members. However, if verbose mode is requested
401 // ('v' modifier) then the file type, permission mode, user, group, size, and
402 // modification time are also printed.
404 doDisplayTable(std::string
* ErrMsg
) {
405 if (buildPaths(false, ErrMsg
))
407 for (Archive::iterator I
= TheArchive
->begin(), E
= TheArchive
->end();
410 (std::find(Paths
.begin(), Paths
.end(), I
->getPath()) != Paths
.end())) {
412 // FIXME: Output should be this format:
413 // Zrw-r--r-- 500/ 500 525 Nov 8 17:42 2004 Makefile
416 else if (I
->isCompressed())
420 unsigned mode
= I
->getMode();
421 printMode((mode
>> 6) & 007);
422 printMode((mode
>> 3) & 007);
423 printMode(mode
& 007);
424 outs() << " " << format("%4u", I
->getUser());
425 outs() << "/" << format("%4u", I
->getGroup());
426 outs() << " " << format("%8u", I
->getSize());
427 outs() << " " << format("%20s", I
->getModTime().str().substr(4).c_str());
428 outs() << " " << I
->getPath().str() << "\n";
430 outs() << I
->getPath().str() << "\n";
439 // doExtract - Implement the 'x' operation. This function extracts files back to
440 // the file system, making sure to uncompress any that were compressed
442 doExtract(std::string
* ErrMsg
) {
443 if (buildPaths(false, ErrMsg
))
445 for (Archive::iterator I
= TheArchive
->begin(), E
= TheArchive
->end();
448 (std::find(Paths
.begin(), Paths
.end(), I
->getPath()) != Paths
.end())) {
450 // Make sure the intervening directories are created
452 sys::Path
dirs(I
->getPath());
453 dirs
.eraseComponent();
454 if (dirs
.createDirectoryOnDisk(/*create_parents=*/true, ErrMsg
))
458 // Open up a file stream for writing
459 std::ios::openmode io_mode
= std::ios::out
| std::ios::trunc
|
461 std::ofstream
file(I
->getPath().c_str(), io_mode
);
463 // Get the data and its length
464 const char* data
= reinterpret_cast<const char*>(I
->getData());
465 unsigned len
= I
->getSize();
468 file
.write(data
,len
);
471 // If we're supposed to retain the original modification times, etc. do so
474 I
->getPath().setStatusInfoOnDisk(I
->getFileStatus());
480 // doDelete - Implement the delete operation. This function deletes zero or more
481 // members from the archive. Note that if the count is specified, there should
482 // be no more than one path in the Paths list or else this algorithm breaks.
483 // That check is enforced in parseCommandLine (above).
485 doDelete(std::string
* ErrMsg
) {
486 if (buildPaths(false, ErrMsg
))
490 unsigned countDown
= Count
;
491 for (Archive::iterator I
= TheArchive
->begin(), E
= TheArchive
->end();
493 if (std::find(Paths
.begin(), Paths
.end(), I
->getPath()) != Paths
.end()) {
494 if (countDown
== 1) {
495 Archive::iterator J
= I
;
497 TheArchive
->erase(J
);
505 // We're done editting, reconstruct the archive.
506 if (TheArchive
->writeToDisk(SymTable
,TruncateNames
,Compression
,ErrMsg
))
513 // doMore - Implement the move operation. This function re-arranges just the
514 // order of the archive members so that when the archive is written the move
515 // of the members is accomplished. Note the use of the RelPos variable to
516 // determine where the items should be moved to.
518 doMove(std::string
* ErrMsg
) {
519 if (buildPaths(false, ErrMsg
))
522 // By default and convention the place to move members to is the end of the
524 Archive::iterator moveto_spot
= TheArchive
->end();
526 // However, if the relative positioning modifiers were used, we need to scan
527 // the archive to find the member in question. If we don't find it, its no
528 // crime, we just move to the end.
529 if (AddBefore
|| InsertBefore
|| AddAfter
) {
530 for (Archive::iterator I
= TheArchive
->begin(), E
= TheArchive
->end();
532 if (RelPos
== I
->getPath().str()) {
544 // Keep a list of the paths remaining to be moved
545 std::set
<sys::Path
> remaining(Paths
);
547 // Scan the archive again, this time looking for the members to move to the
549 for (Archive::iterator I
= TheArchive
->begin(), E
= TheArchive
->end();
550 I
!= E
&& !remaining
.empty(); ++I
) {
551 std::set
<sys::Path
>::iterator found
=
552 std::find(remaining
.begin(),remaining
.end(),I
->getPath());
553 if (found
!= remaining
.end()) {
554 if (I
!= moveto_spot
)
555 TheArchive
->splice(moveto_spot
,*TheArchive
,I
);
556 remaining
.erase(found
);
560 // We're done editting, reconstruct the archive.
561 if (TheArchive
->writeToDisk(SymTable
,TruncateNames
,Compression
,ErrMsg
))
568 // doQuickAppend - Implements the 'q' operation. This function just
569 // indiscriminantly adds the members to the archive and rebuilds it.
571 doQuickAppend(std::string
* ErrMsg
) {
572 // Get the list of paths to append.
573 if (buildPaths(true, ErrMsg
))
578 // Append them quickly.
579 for (std::set
<sys::Path
>::iterator PI
= Paths
.begin(), PE
= Paths
.end();
581 if (TheArchive
->addFileBefore(*PI
,TheArchive
->end(),ErrMsg
))
585 // We're done editting, reconstruct the archive.
586 if (TheArchive
->writeToDisk(SymTable
,TruncateNames
,Compression
,ErrMsg
))
593 // doReplaceOrInsert - Implements the 'r' operation. This function will replace
594 // any existing files or insert new ones into the archive.
596 doReplaceOrInsert(std::string
* ErrMsg
) {
598 // Build the list of files to be added/replaced.
599 if (buildPaths(true, ErrMsg
))
604 // Keep track of the paths that remain to be inserted.
605 std::set
<sys::Path
> remaining(Paths
);
607 // Default the insertion spot to the end of the archive
608 Archive::iterator insert_spot
= TheArchive
->end();
610 // Iterate over the archive contents
611 for (Archive::iterator I
= TheArchive
->begin(), E
= TheArchive
->end();
612 I
!= E
&& !remaining
.empty(); ++I
) {
614 // Determine if this archive member matches one of the paths we're trying
617 std::set
<sys::Path
>::iterator found
= remaining
.end();
618 for (std::set
<sys::Path
>::iterator RI
= remaining
.begin(),
619 RE
= remaining
.end(); RI
!= RE
; ++RI
) {
620 std::string
compare(RI
->str());
621 if (TruncateNames
&& compare
.length() > 15) {
622 const char* nm
= compare
.c_str();
623 unsigned len
= compare
.length();
624 size_t slashpos
= compare
.rfind('/');
625 if (slashpos
!= std::string::npos
) {
631 compare
.assign(nm
,len
);
633 if (compare
== I
->getPath().str()) {
639 if (found
!= remaining
.end()) {
641 sys::PathWithStatus
PwS(*found
);
642 const sys::FileStatus
*si
= PwS
.getFileStatus(false, &Err
);
647 // Replace the item only if it is newer.
648 if (si
->modTime
> I
->getModTime())
649 if (I
->replaceWith(*found
, ErrMsg
))
652 // Replace the item regardless of time stamp
653 if (I
->replaceWith(*found
, ErrMsg
))
657 // We purposefully ignore directories.
660 // Remove it from our "to do" list
661 remaining
.erase(found
);
664 // Determine if this is the place where we should insert
665 if ((AddBefore
|| InsertBefore
) && RelPos
== I
->getPath().str())
667 else if (AddAfter
&& RelPos
== I
->getPath().str()) {
673 // If we didn't replace all the members, some will remain and need to be
674 // inserted at the previously computed insert-spot.
675 if (!remaining
.empty()) {
676 for (std::set
<sys::Path
>::iterator PI
= remaining
.begin(),
677 PE
= remaining
.end(); PI
!= PE
; ++PI
) {
678 if (TheArchive
->addFileBefore(*PI
,insert_spot
, ErrMsg
))
683 // We're done editting, reconstruct the archive.
684 if (TheArchive
->writeToDisk(SymTable
,TruncateNames
,Compression
,ErrMsg
))
691 // main - main program for llvm-ar .. see comments in the code
692 int main(int argc
, char **argv
) {
693 // Print a stack trace if we signal out.
694 sys::PrintStackTraceOnErrorSignal();
695 PrettyStackTraceProgram
X(argc
, argv
);
696 LLVMContext
&Context
= getGlobalContext();
697 llvm_shutdown_obj Y
; // Call llvm_shutdown() on exit.
699 // Have the command line options parsed and handle things
700 // like --help and --version.
701 cl::ParseCommandLineOptions(argc
, argv
,
702 "LLVM Archiver (llvm-ar)\n\n"
703 " This program archives bitcode files into single libraries\n"
708 // Make sure we don't exit with "unhandled exception".
710 // Do our own parsing of the command line because the CommandLine utility
711 // can't handle the grouped positional parameters without a dash.
712 ArchiveOperation Operation
= parseCommandLine();
714 // Check the path name of the archive
715 sys::Path ArchivePath
;
716 if (!ArchivePath
.set(ArchiveName
))
717 throw std::string("Archive name invalid: ") + ArchiveName
;
719 // Create or open the archive object.
721 if (llvm::sys::fs::exists(ArchivePath
.str(), Exists
) || !Exists
) {
722 // Produce a warning if we should and we're creating the archive
724 errs() << argv
[0] << ": creating " << ArchivePath
.str() << "\n";
725 TheArchive
= Archive::CreateEmpty(ArchivePath
, Context
);
726 TheArchive
->writeToDisk();
729 TheArchive
= Archive::OpenAndLoad(ArchivePath
, Context
, &Error
);
730 if (TheArchive
== 0) {
731 errs() << argv
[0] << ": error loading '" << ArchivePath
.str() << "': "
737 // Make sure we're not fooling ourselves.
738 assert(TheArchive
&& "Unable to instantiate the archive");
740 // Make sure we clean up the archive even on failure.
741 std::auto_ptr
<Archive
> AutoArchive(TheArchive
);
743 // Perform the operation
745 bool haveError
= false;
747 case Print
: haveError
= doPrint(&ErrMsg
); break;
748 case Delete
: haveError
= doDelete(&ErrMsg
); break;
749 case Move
: haveError
= doMove(&ErrMsg
); break;
750 case QuickAppend
: haveError
= doQuickAppend(&ErrMsg
); break;
751 case ReplaceOrInsert
: haveError
= doReplaceOrInsert(&ErrMsg
); break;
752 case DisplayTable
: haveError
= doDisplayTable(&ErrMsg
); break;
753 case Extract
: haveError
= doExtract(&ErrMsg
); break;
755 errs() << argv
[0] << ": No operation was selected.\n";
759 errs() << argv
[0] << ": " << ErrMsg
<< "\n";
762 } catch (const char*msg
) {
763 // These errors are usage errors, thrown only by the various checks in the
765 errs() << argv
[0] << ": " << msg
<< "\n\n";
766 cl::PrintHelpMessage();
768 } catch (const std::string
& msg
) {
769 // These errors are thrown by LLVM libraries (e.g. lib System) and represent
770 // a more serious error so we bump the exitCode and don't print the usage.
771 errs() << argv
[0] << ": " << msg
<< "\n";
774 // This really shouldn't happen, but just in case ....
775 errs() << argv
[0] << ": An unexpected unknown exception occurred.\n";
779 // Return result code back to operating system.