llvm.org GIT mirror llvm / a8aac85
[llvm-ar] Strip trailing \r and format Reviewers: mstorsjo, rupprecht, gbreynoo Reviewed By: rupprecht Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D53769 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@345410 91177308-0d34-0410-b5e6-96231b3b80d8 Fangrui Song 9 months ago
1 changed file(s) with 1046 addition(s) and 1018 deletion(s). Raw diff Collapse all Expand all
None //===-- llvm-ar.cpp - LLVM archive librarian utility ----------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Builds up (relatively) standard unix archive files (.a) containing LLVM
10 // bitcode or other files.
11 //
12 //===----------------------------------------------------------------------===//
13
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/raw_ostream.h"
36 #include "llvm/ToolDrivers/llvm-dlltool/DlltoolDriver.h"
37 #include "llvm/ToolDrivers/llvm-lib/LibDriver.h"
38
39 #if !defined(_MSC_VER) && !defined(__MINGW32__)
40 #include
41 #else
42 #include
43 #endif
44
45 using namespace llvm;
46
47 // The name this program was invoked as.
48 static StringRef ToolName;
49
50 // The basename of this program.
51 static StringRef Stem;
52
53 const char RanlibHelp[] = R"(
54 OVERVIEW: LLVM Ranlib (llvm-ranlib)
55
56 This program generates an index to speed access to archives
57
58 USAGE: llvm-ranlib
59
60 OPTIONS:
61 -help - Display available options
62 -version - Display the version of this program
63 )";
64
65 const char ArHelp[] = R"(
66 OVERVIEW: LLVM Archiver
67
68 USAGE: llvm-ar [options] [-][modifiers] [relpos] [files]
69 llvm-ar -M [
70
71 OPTIONS:
72 --format - Archive format to create
73 =default - default
74 =gnu - gnu
75 =darwin - darwin
76 =bsd - bsd
77 --plugin= - Ignored for compatibility
78 --help - Display available options
79 --version - Display the version of this program
80
81 OPERATIONS:
82 d - delete [files] from the archive
83 m - move [files] in the archive
84 p - print [files] found in the archive
85 q - quick append [files] to the archive
86 r - replace or insert [files] into the archive
87 s - act as ranlib
88 t - display contents of archive
89 x - extract [files] from the archive
90
91 MODIFIERS:
92 [a] - put [files] after [relpos]
93 [b] - put [files] before [relpos] (same as [i])
94 [c] - do not warn if archive had to be created
95 [D] - use zero for timestamps and uids/gids (default)
96 [i] - put [files] before [relpos] (same as [b])
97 [l] - ignored for compatibility
98 [L] - add archive's contents
99 [o] - preserve original dates
100 [s] - create an archive index (cf. ranlib)
101 [S] - do not build a symbol table
102 [T] - create a thin archive
103 [u] - update only [files] newer than archive contents
104 [U] - use actual timestamps and uids/gids
105 [v] - be verbose about actions taken
106 )";
107
108 void printHelpMessage() {
109 if (Stem.contains_lower("ranlib"))
110 outs() << RanlibHelp;
111 else if (Stem.contains_lower("ar"))
112 outs() << ArHelp;
113 }
114
115 // Show the error message and exit.
116 LLVM_ATTRIBUTE_NORETURN static void fail(Twine Error) {
117 errs() << ToolName << ": " << Error << ".\n";
118 printHelpMessage();
119 exit(1);
120 }
121
122 static void failIfError(std::error_code EC, Twine Context = "") {
123 if (!EC)
124 return;
125
126 std::string ContextStr = Context.str();
127 if (ContextStr == "")
128 fail(EC.message());
129 fail(Context + ": " + EC.message());
130 }
131
132 static void failIfError(Error E, Twine Context = "") {
133 if (!E)
134 return;
135
136 handleAllErrors(std::move(E), [&](const llvm::ErrorInfoBase &EIB) {
137 std::string ContextStr = Context.str();
138 if (ContextStr == "")
139 fail(EIB.message());
140 fail(Context + ": " + EIB.message());
141 });
142 }
143
144 static SmallVector PositionalArgs;
145
146 static bool MRI;
147
148 namespace {
149 enum Format { Default, GNU, BSD, DARWIN, Unknown };
150 }
151
152 static Format FormatType = Default;
153
154 static std::string Options;
155
156 // This enumeration delineates the kinds of operations on an archive
157 // that are permitted.
158 enum ArchiveOperation {
159 Print, ///< Print the contents of the archive
160 Delete, ///< Delete the specified members
161 Move, ///< Move members to end or as given by {a,b,i} modifiers
162 QuickAppend, ///< Quickly append to end of archive
163 ReplaceOrInsert, ///< Replace or Insert members
164 DisplayTable, ///< Display the table of contents
165 Extract, ///< Extract files back to file system
166 CreateSymTab ///< Create a symbol table in an existing archive
167 };
168
169 // Modifiers to follow operation to vary behavior
170 static bool AddAfter = false; ///< 'a' modifier
171 static bool AddBefore = false; ///< 'b' modifier
172 static bool Create = false; ///< 'c' modifier
173 static bool OriginalDates = false; ///< 'o' modifier
174 static bool OnlyUpdate = false; ///< 'u' modifier
175 static bool Verbose = false; ///< 'v' modifier
176 static bool Symtab = true; ///< 's' modifier
177 static bool Deterministic = true; ///< 'D' and 'U' modifiers
178 static bool Thin = false; ///< 'T' modifier
179 static bool AddLibrary = false; ///< 'L' modifier
180
181 // Relative Positional Argument (for insert/move). This variable holds
182 // the name of the archive member to which the 'a', 'b' or 'i' modifier
183 // refers. Only one of 'a', 'b' or 'i' can be specified so we only need
184 // one variable.
185 static std::string RelPos;
186
187 // This variable holds the name of the archive file as given on the
188 // command line.
189 static std::string ArchiveName;
190
191 // This variable holds the list of member files to proecess, as given
192 // on the command line.
193 static std::vector Members;
194
195 // Extract the member filename from the command line for the [relpos] argument
196 // associated with a, b, and i modifiers
197 static void getRelPos() {
198 if (PositionalArgs.size() == 0)
199 fail("Expected [relpos] for a, b, or i modifier");
200 RelPos = PositionalArgs[0];
201 PositionalArgs.erase(PositionalArgs.begin());
202 }
203
204 // Get the archive file name from the command line
205 static void getArchive() {
206 if (PositionalArgs.size() == 0)
207 fail("An archive name must be specified");
208 ArchiveName = PositionalArgs[0];
209 PositionalArgs.erase(PositionalArgs.begin());
210 }
211
212 // Copy over remaining items in PositionalArgs to our Members vector
213 static void getMembers() {
214 for (auto &Arg : PositionalArgs)
215 Members.push_back(Arg);
216 }
217
218 std::vector> ArchiveBuffers;
219 std::vector> Archives;
220
221 static object::Archive &readLibrary(const Twine &Library) {
222 auto BufOrErr = MemoryBuffer::getFile(Library, -1, false);
223 failIfError(BufOrErr.getError(), "Could not open library");
224 ArchiveBuffers.push_back(std::move(*BufOrErr));
225 auto LibOrErr =
226 object::Archive::create(ArchiveBuffers.back()->getMemBufferRef());
227 failIfError(errorToErrorCode(LibOrErr.takeError()),
228 "Could not parse library");
229 Archives.push_back(std::move(*LibOrErr));
230 return *Archives.back();
231 }
232
233 static void runMRIScript();
234
235 // Parse the command line options as presented and return the operation
236 // specified. Process all modifiers and check to make sure that constraints on
237 // modifier/operation pairs have not been violated.
238 static ArchiveOperation parseCommandLine() {
239 if (MRI) {
240 if (!PositionalArgs.empty() || !Options.empty())
241 fail("Cannot mix -M and other options");
242 runMRIScript();
243 }
244
245 // Keep track of number of operations. We can only specify one
246 // per execution.
247 unsigned NumOperations = 0;
248
249 // Keep track of the number of positional modifiers (a,b,i). Only
250 // one can be specified.
251 unsigned NumPositional = 0;
252
253 // Keep track of which operation was requested
254 ArchiveOperation Operation;
255
256 bool MaybeJustCreateSymTab = false;
257
258 for(unsigned i=0; i
259 switch(Options[i]) {
260 case 'd': ++NumOperations; Operation = Delete; break;
261 case 'm': ++NumOperations; Operation = Move ; break;
262 case 'p': ++NumOperations; Operation = Print; break;
263 case 'q': ++NumOperations; Operation = QuickAppend; break;
264 case 'r': ++NumOperations; Operation = ReplaceOrInsert; break;
265 case 't': ++NumOperations; Operation = DisplayTable; break;
266 case 'x': ++NumOperations; Operation = Extract; break;
267 case 'c': Create = true; break;
268 case 'l': /* accepted but unused */ break;
269 case 'o': OriginalDates = true; break;
270 case 's':
271 Symtab = true;
272 MaybeJustCreateSymTab = true;
273 break;
274 case 'S':
275 Symtab = false;
276 break;
277 case 'u': OnlyUpdate = true; break;
278 case 'v': Verbose = true; break;
279 case 'a':
280 getRelPos();
281 AddAfter = true;
282 NumPositional++;
283 break;
284 case 'b':
285 getRelPos();
286 AddBefore = true;
287 NumPositional++;
288 break;
289 case 'i':
290 getRelPos();
291 AddBefore = true;
292 NumPositional++;
293 break;
294 case 'D':
295 Deterministic = true;
296 break;
297 case 'U':
298 Deterministic = false;
299 break;
300 case 'T':
301 Thin = true;
302 break;
303 case 'L':
304 AddLibrary = true;
305 break;
306 default:
307 fail(std::string("unknown option ") + Options[i]);
308 }
309 }
310
311 // At this point, the next thing on the command line must be
312 // the archive name.
313 getArchive();
314
315 // Everything on the command line at this point is a member.
316 getMembers();
317
318 if (NumOperations == 0 && MaybeJustCreateSymTab) {
319 NumOperations = 1;
320 Operation = CreateSymTab;
321 if (!Members.empty())
322 fail("The s operation takes only an archive as argument");
323 }
324
325 // Perform various checks on the operation/modifier specification
326 // to make sure we are dealing with a legal request.
327 if (NumOperations == 0)
328 fail("You must specify at least one of the operations");
329 if (NumOperations > 1)
330 fail("Only one operation may be specified");
331 if (NumPositional > 1)
332 fail("You may only specify one of a, b, and i modifiers");
333 if (AddAfter || AddBefore) {
334 if (Operation != Move && Operation != ReplaceOrInsert)
335 fail("The 'a', 'b' and 'i' modifiers can only be specified with "
336 "the 'm' or 'r' operations");
337 }
338 if (OriginalDates && Operation != Extract)
339 fail("The 'o' modifier is only applicable to the 'x' operation");
340 if (OnlyUpdate && Operation != ReplaceOrInsert)
341 fail("The 'u' modifier is only applicable to the 'r' operation");
342 if (AddLibrary && Operation != QuickAppend)
343 fail("The 'L' modifier is only applicable to the 'q' operation");
344
345 // Return the parsed operation to the caller
346 return Operation;
347 }
348
349 // Implements the 'p' operation. This function traverses the archive
350 // looking for members that match the path list.
351 static void doPrint(StringRef Name, const object::Archive::Child &C) {
352 if (Verbose)
353 outs() << "Printing " << Name << "\n";
354
355 Expected DataOrErr = C.getBuffer();
356 failIfError(DataOrErr.takeError());
357 StringRef Data = *DataOrErr;
358 outs().write(Data.data(), Data.size());
359 }
360
361 // Utility function for printing out the file mode when the 't' operation is in
362 // verbose mode.
363 static void printMode(unsigned mode) {
364 outs() << ((mode & 004) ? "r" : "-");
365 outs() << ((mode & 002) ? "w" : "-");
366 outs() << ((mode & 001) ? "x" : "-");
367 }
368
369 // Implement the 't' operation. This function prints out just
370 // the file names of each of the members. However, if verbose mode is requested
371 // ('v' modifier) then the file type, permission mode, user, group, size, and
372 // modification time are also printed.
373 static void doDisplayTable(StringRef Name, const object::Archive::Child &C) {
374 if (Verbose) {
375 Expected ModeOrErr = C.getAccessMode();
376 failIfError(ModeOrErr.takeError());
377 sys::fs::perms Mode = ModeOrErr.get();
378 printMode((Mode >> 6) & 007);
379 printMode((Mode >> 3) & 007);
380 printMode(Mode & 007);
381 Expected UIDOrErr = C.getUID();
382 failIfError(UIDOrErr.takeError());
383 outs() << ' ' << UIDOrErr.get();
384 Expected GIDOrErr = C.getGID();
385 failIfError(GIDOrErr.takeError());
386 outs() << '/' << GIDOrErr.get();
387 Expected Size = C.getSize();
388 failIfError(Size.takeError());
389 outs() << ' ' << format("%6llu", Size.get());
390 auto ModTimeOrErr = C.getLastModified();
391 failIfError(ModTimeOrErr.takeError());
392 // Note: formatv() only handles the default TimePoint<>, which is in
393 // nanoseconds.
394 // TODO: fix format_provider> to allow other units.
395 sys::TimePoint<> ModTimeInNs = ModTimeOrErr.get();
396 outs() << ' ' << formatv("{0:%b %e %H:%M %Y}", ModTimeInNs);
397 outs() << ' ';
398 }
399
400 if (C.getParent()->isThin()) {
401 outs() << sys::path::parent_path(ArchiveName);
402 outs() << '/';
403 }
404 outs() << Name << "\n";
405 }
406
407 // Implement the 'x' operation. This function extracts files back to the file
408 // system.
409 static void doExtract(StringRef Name, const object::Archive::Child &C) {
410 // Retain the original mode.
411 Expected ModeOrErr = C.getAccessMode();
412 failIfError(ModeOrErr.takeError());
413 sys::fs::perms Mode = ModeOrErr.get();
414
415 int FD;
416 failIfError(sys::fs::openFileForWrite(sys::path::filename(Name), FD,
417 sys::fs::CD_CreateAlways,
418 sys::fs::F_None, Mode),
419 Name);
420
421 {
422 raw_fd_ostream file(FD, false);
423
424 // Get the data and its length
425 Expected BufOrErr = C.getBuffer();
426 failIfError(BufOrErr.takeError());
427 StringRef Data = BufOrErr.get();
428
429 // Write the data.
430 file.write(Data.data(), Data.size());
431 }
432
433 // If we're supposed to retain the original modification times, etc. do so
434 // now.
435 if (OriginalDates) {
436 auto ModTimeOrErr = C.getLastModified();
437 failIfError(ModTimeOrErr.takeError());
438 failIfError(
439 sys::fs::setLastAccessAndModificationTime(FD, ModTimeOrErr.get()));
440 }
441
442 if (close(FD))
443 fail("Could not close the file");
444 }
445
446 static bool shouldCreateArchive(ArchiveOperation Op) {
447 switch (Op) {
448 case Print:
449 case Delete:
450 case Move:
451 case DisplayTable:
452 case Extract:
453 case CreateSymTab:
454 return false;
455
456 case QuickAppend:
457 case ReplaceOrInsert:
458 return true;
459 }
460
461 llvm_unreachable("Missing entry in covered switch.");
462 }
463
464 static void performReadOperation(ArchiveOperation Operation,
465 object::Archive *OldArchive) {
466 if (Operation == Extract && OldArchive->isThin())
467 fail("extracting from a thin archive is not supported");
468
469 bool Filter = !Members.empty();
470 {
471 Error Err = Error::success();
472 for (auto &C : OldArchive->children(Err)) {
473 Expected NameOrErr = C.getName();
474 failIfError(NameOrErr.takeError());
475 StringRef Name = NameOrErr.get();
476
477 if (Filter) {
478 auto I = find(Members, Name);
479 if (I == Members.end())
480 continue;
481 Members.erase(I);
482 }
483
484 switch (Operation) {
485 default:
486 llvm_unreachable("Not a read operation");
487 case Print:
488 doPrint(Name, C);
489 break;
490 case DisplayTable:
491 doDisplayTable(Name, C);
492 break;
493 case Extract:
494 doExtract(Name, C);
495 break;
496 }
497 }
498 failIfError(std::move(Err));
499 }
500
501 if (Members.empty())
502 return;
503 for (StringRef Name : Members)
504 errs() << Name << " was not found\n";
505 exit(1);
506 }
507
508 static void addMember(std::vector &Members,
509 StringRef FileName, int Pos = -1) {
510 Expected NMOrErr =
511 NewArchiveMember::getFile(FileName, Deterministic);
512 failIfError(NMOrErr.takeError(), FileName);
513
514 // Use the basename of the object path for the member name.
515 NMOrErr->MemberName = sys::path::filename(NMOrErr->MemberName);
516
517 if (Pos == -1)
518 Members.push_back(std::move(*NMOrErr));
519 else
520 Members[Pos] = std::move(*NMOrErr);
521 }
522
523 static void addMember(std::vector &Members,
524 const object::Archive::Child &M, int Pos = -1) {
525 if (Thin && !M.getParent()->isThin())
526 fail("Cannot convert a regular archive to a thin one");
527 Expected NMOrErr =
528 NewArchiveMember::getOldMember(M, Deterministic);
529 failIfError(NMOrErr.takeError());
530 if (Pos == -1)
531 Members.push_back(std::move(*NMOrErr));
532 else
533 Members[Pos] = std::move(*NMOrErr);
534 }
535
536 static void addLibMember(std::vector &Members,
537 StringRef FileName) {
538 Expected NMOrErr =
539 NewArchiveMember::getFile(FileName, Deterministic);
540 failIfError(NMOrErr.takeError(), FileName);
541 if (identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) {
542 object::Archive &Lib = readLibrary(FileName);
543 Error Err = Error::success();
544
545 for (auto &Child : Lib.children(Err))
546 addMember(Members, Child);
547
548 failIfError(std::move(Err));
549 } else {
550 // Use the basename of the object path for the member name.
551 NMOrErr->MemberName = sys::path::filename(NMOrErr->MemberName);
552 Members.push_back(std::move(*NMOrErr));
553 }
554 }
555
556 enum InsertAction {
557 IA_AddOldMember,
558 IA_AddNewMember,
559 IA_Delete,
560 IA_MoveOldMember,
561 IA_MoveNewMember
562 };
563
564 static InsertAction computeInsertAction(ArchiveOperation Operation,
565 const object::Archive::Child &Member,
566 StringRef Name,
567 std::vector::iterator &Pos) {
568 if (Operation == QuickAppend || Members.empty())
569 return IA_AddOldMember;
570
571 auto MI = find_if(Members, [Name](StringRef Path) {
572 return Name == sys::path::filename(Path);
573 });
574
575 if (MI == Members.end())
576 return IA_AddOldMember;
577
578 Pos = MI;
579
580 if (Operation == Delete)
581 return IA_Delete;
582
583 if (Operation == Move)
584 return IA_MoveOldMember;
585
586 if (Operation == ReplaceOrInsert) {
587 StringRef PosName = sys::path::filename(RelPos);
588 if (!OnlyUpdate) {
589 if (PosName.empty())
590 return IA_AddNewMember;
591 return IA_MoveNewMember;
592 }
593
594 // We could try to optimize this to a fstat, but it is not a common
595 // operation.
596 sys::fs::file_status Status;
597 failIfError(sys::fs::status(*MI, Status), *MI);
598 auto ModTimeOrErr = Member.getLastModified();
599 failIfError(ModTimeOrErr.takeError());
600 if (Status.getLastModificationTime() < ModTimeOrErr.get()) {
601 if (PosName.empty())
602 return IA_AddOldMember;
603 return IA_MoveOldMember;
604 }
605
606 if (PosName.empty())
607 return IA_AddNewMember;
608 return IA_MoveNewMember;
609 }
610 llvm_unreachable("No such operation");
611 }
612
613 // We have to walk this twice and computing it is not trivial, so creating an
614 // explicit std::vector is actually fairly efficient.
615 static std::vector
616 computeNewArchiveMembers(ArchiveOperation Operation,
617 object::Archive *OldArchive) {
618 std::vector Ret;
619 std::vector Moved;
620 int InsertPos = -1;
621 StringRef PosName = sys::path::filename(RelPos);
622 if (OldArchive) {
623 Error Err = Error::success();
624 for (auto &Child : OldArchive->children(Err)) {
625 int Pos = Ret.size();
626 Expected NameOrErr = Child.getName();
627 failIfError(NameOrErr.takeError());
628 StringRef Name = NameOrErr.get();
629 if (Name == PosName) {
630 assert(AddAfter || AddBefore);
631 if (AddBefore)
632 InsertPos = Pos;
633 else
634 InsertPos = Pos + 1;
635 }
636
637 std::vector::iterator MemberI = Members.end();
638 InsertAction Action =
639 computeInsertAction(Operation, Child, Name, MemberI);
640 switch (Action) {
641 case IA_AddOldMember:
642 addMember(Ret, Child);
643 break;
644 case IA_AddNewMember:
645 addMember(Ret, *MemberI);
646 break;
647 case IA_Delete:
648 break;
649 case IA_MoveOldMember:
650 addMember(Moved, Child);
651 break;
652 case IA_MoveNewMember:
653 addMember(Moved, *MemberI);
654 break;
655 }
656 if (MemberI != Members.end())
657 Members.erase(MemberI);
658 }
659 failIfError(std::move(Err));
660 }
661
662 if (Operation == Delete)
663 return Ret;
664
665 if (!RelPos.empty() && InsertPos == -1)
666 fail("Insertion point not found");
667
668 if (RelPos.empty())
669 InsertPos = Ret.size();
670
671 assert(unsigned(InsertPos) <= Ret.size());
672 int Pos = InsertPos;
673 for (auto &M : Moved) {
674 Ret.insert(Ret.begin() + Pos, std::move(M));
675 ++Pos;
676 }
677
678 if (AddLibrary) {
679 assert(Operation == QuickAppend);
680 for (auto &Member : Members)
681 addLibMember(Ret, Member);
682 return Ret;
683 }
684
685 for (unsigned I = 0; I != Members.size(); ++I)
686 Ret.insert(Ret.begin() + InsertPos, NewArchiveMember());
687 Pos = InsertPos;
688 for (auto &Member : Members) {
689 addMember(Ret, Member, Pos);
690 ++Pos;
691 }
692
693 return Ret;
694 }
695
696 static object::Archive::Kind getDefaultForHost() {
697 return Triple(sys::getProcessTriple()).isOSDarwin()
698 ? object::Archive::K_DARWIN
699 : object::Archive::K_GNU;
700 }
701
702 static object::Archive::Kind getKindFromMember(const NewArchiveMember &Member) {
703 Expected> OptionalObject =
704 object::ObjectFile::createObjectFile(Member.Buf->getMemBufferRef());
705
706 if (OptionalObject)
707 return isa(**OptionalObject)
708 ? object::Archive::K_DARWIN
709 : object::Archive::K_GNU;
710
711 // squelch the error in case we had a non-object file
712 consumeError(OptionalObject.takeError());
713 return getDefaultForHost();
714 }
715
716 static void
717 performWriteOperation(ArchiveOperation Operation,
718 object::Archive *OldArchive,
719 std::unique_ptr OldArchiveBuf,
720 std::vector *NewMembersP) {
721 std::vector NewMembers;
722 if (!NewMembersP)
723 NewMembers = computeNewArchiveMembers(Operation, OldArchive);
724
725 object::Archive::Kind Kind;
726 switch (FormatType) {
727 case Default:
728 if (Thin)
729 Kind = object::Archive::K_GNU;
730 else if (OldArchive)
731 Kind = OldArchive->kind();
732 else if (NewMembersP)
733 Kind = NewMembersP->size() ? getKindFromMember(NewMembersP->front())
734 : getDefaultForHost();
735 else
736 Kind = NewMembers.size() ? getKindFromMember(NewMembers.front())
737 : getDefaultForHost();
738 break;
739 case GNU:
740 Kind = object::Archive::K_GNU;
741 break;
742 case BSD:
743 if (Thin)
744 fail("Only the gnu format has a thin mode");
745 Kind = object::Archive::K_BSD;
746 break;
747 case DARWIN:
748 if (Thin)
749 fail("Only the gnu format has a thin mode");
750 Kind = object::Archive::K_DARWIN;
751 break;
752 case Unknown:
753 llvm_unreachable("");
754 }
755
756 Error E =
757 writeArchive(ArchiveName, NewMembersP ? *NewMembersP : NewMembers, Symtab,
758 Kind, Deterministic, Thin, std::move(OldArchiveBuf));
759 failIfError(std::move(E), ArchiveName);
760 }
761
762 static void createSymbolTable(object::Archive *OldArchive) {
763 // When an archive is created or modified, if the s option is given, the
764 // resulting archive will have a current symbol table. If the S option
765 // is given, it will have no symbol table.
766 // In summary, we only need to update the symbol table if we have none.
767 // This is actually very common because of broken build systems that think
768 // they have to run ranlib.
769 if (OldArchive->hasSymbolTable())
770 return;
771
772 performWriteOperation(CreateSymTab, OldArchive, nullptr, nullptr);
773 }
774
775 static void performOperation(ArchiveOperation Operation,
776 object::Archive *OldArchive,
777 std::unique_ptr OldArchiveBuf,
778 std::vector *NewMembers) {
779 switch (Operation) {
780 case Print:
781 case DisplayTable:
782 case Extract:
783 performReadOperation(Operation, OldArchive);
784 return;
785
786 case Delete:
787 case Move:
788 case QuickAppend:
789 case ReplaceOrInsert:
790 performWriteOperation(Operation, OldArchive, std::move(OldArchiveBuf),
791 NewMembers);
792 return;
793 case CreateSymTab:
794 createSymbolTable(OldArchive);
795 return;
796 }
797 llvm_unreachable("Unknown operation.");
798 }
799
800 static int performOperation(ArchiveOperation Operation,
801 std::vector *NewMembers) {
802 // Create or open the archive object.
803 ErrorOr> Buf =
804 MemoryBuffer::getFile(ArchiveName, -1, false);
805 std::error_code EC = Buf.getError();
806 if (EC && EC != errc::no_such_file_or_directory)
807 fail("error opening '" + ArchiveName + "': " + EC.message() + "!");
808
809 if (!EC) {
810 Error Err = Error::success();
811 object::Archive Archive(Buf.get()->getMemBufferRef(), Err);
812 EC = errorToErrorCode(std::move(Err));
813 failIfError(EC,
814 "error loading '" + ArchiveName + "': " + EC.message() + "!");
815 performOperation(Operation, &Archive, std::move(Buf.get()), NewMembers);
816 return 0;
817 }
818
819 assert(EC == errc::no_such_file_or_directory);
820
821 if (!shouldCreateArchive(Operation)) {
822 failIfError(EC, Twine("error loading '") + ArchiveName + "'");
823 } else {
824 if (!Create) {
825 // Produce a warning if we should and we're creating the archive
826 errs() << ToolName << ": creating " << ArchiveName << "\n";
827 }
828 }
829
830 performOperation(Operation, nullptr, nullptr, NewMembers);
831 return 0;
832 }
833
834 static void runMRIScript() {
835 enum class MRICommand { AddLib, AddMod, Create, Delete, Save, End, Invalid };
836
837 ErrorOr> Buf = MemoryBuffer::getSTDIN();
838 failIfError(Buf.getError());
839 const MemoryBuffer &Ref = *Buf.get();
840 bool Saved = false;
841 std::vector NewMembers;
842
843 for (line_iterator I(Ref, /*SkipBlanks*/ false), E; I != E; ++I) {
844 StringRef Line = *I;
845 Line = Line.split(';').first;
846 Line = Line.split('*').first;
847 Line = Line.trim();
848 if (Line.empty())
849 continue;
850 StringRef CommandStr, Rest;
851 std::tie(CommandStr, Rest) = Line.split(' ');
852 Rest = Rest.trim();
853 if (!Rest.empty() && Rest.front() == '"' && Rest.back() == '"')
854 Rest = Rest.drop_front().drop_back();
855 auto Command = StringSwitch(CommandStr.lower())
856 .Case("addlib", MRICommand::AddLib)
857 .Case("addmod", MRICommand::AddMod)
858 .Case("create", MRICommand::Create)
859 .Case("delete", MRICommand::Delete)
860 .Case("save", MRICommand::Save)
861 .Case("end", MRICommand::End)
862 .Default(MRICommand::Invalid);
863
864 switch (Command) {
865 case MRICommand::AddLib: {
866 object::Archive &Lib = readLibrary(Rest);
867 {
868 Error Err = Error::success();
869 for (auto &Member : Lib.children(Err))
870 addMember(NewMembers, Member);
871 failIfError(std::move(Err));
872 }
873 break;
874 }
875 case MRICommand::AddMod:
876 addMember(NewMembers, Rest);
877 break;
878 case MRICommand::Create:
879 Create = true;
880 if (!ArchiveName.empty())
881 fail("Editing multiple archives not supported");
882 if (Saved)
883 fail("File already saved");
884 ArchiveName = Rest;
885 break;
886 case MRICommand::Delete: {
887 StringRef Name = sys::path::filename(Rest);
888 llvm::erase_if(NewMembers,
889 [=](NewArchiveMember &M) { return M.MemberName == Name; });
890 break;
891 }
892 case MRICommand::Save:
893 Saved = true;
894 break;
895 case MRICommand::End:
896 break;
897 case MRICommand::Invalid:
898 fail("Unknown command: " + CommandStr);
899 }
900 }
901
902 // Nothing to do if not saved.
903 if (Saved)
904 performOperation(ReplaceOrInsert, &NewMembers);
905 exit(0);
906 }
907
908 static bool handleGenericOption(StringRef arg) {
909 if (arg == "-help" || arg == "--help") {
910 printHelpMessage();
911 return true;
912 }
913 if (arg == "-version" || arg == "--version") {
914 cl::PrintVersionMessage();
915 return true;
916 }
917 return false;
918 }
919
920 static int ar_main(int argc, char **argv) {
921 SmallVector Argv(argv, argv + argc);
922 BumpPtrAllocator Alloc;
923 StringSaver Saver(Alloc);
924 cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Argv);
925 for(size_t i = 1; i < Argv.size(); ++i) {
926 StringRef Arg = Argv[i];
927 const char *match;
928 auto MatchFlagWithArg = [&](const char *expected) {
929 size_t len = strlen(expected);
930 if (Arg == expected) {
931 if (++i >= Argv.size())
932 fail(std::string(expected) + " requires an argument");
933 match = Argv[i];
934 return true;
935 }
936 if (Arg.startswith(expected) && Arg.size() > len &&
937 Arg[len] == '=') {
938 match = Arg.data() + len + 1;
939 return true;
940 }
941 return false;
942 };
943 if (handleGenericOption(Argv[i]))
944 return 0;
945 if (Arg == "--") {
946 for(; i < Argv.size(); ++i)
947 PositionalArgs.push_back(Argv[i]);
948 break;
949 }
950 if (Arg[0] == '-') {
951 if (Arg.startswith("--"))
952 Arg = Argv[i] + 2;
953 else
954 Arg = Argv[i] + 1;
955 if (Arg == "M") {
956 MRI = true;
957 } else if (MatchFlagWithArg("format")) {
958 FormatType = StringSwitch(match)
959 .Case("default", Default)
960 .Case("gnu", GNU)
961 .Case("darwin", DARWIN)
962 .Case("bsd", BSD)
963 .Default(Unknown);
964 if (FormatType == Unknown)
965 fail(std::string("Invalid format ") + match);
966 } else if (MatchFlagWithArg("plugin")) {
967 // Ignored.
968 } else {
969 Options += Argv[i] + 1;
970 }
971 } else if (Options.empty()) {
972 Options += Argv[i];
973 } else {
974 PositionalArgs.push_back(Argv[i]);
975 }
976 }
977 ArchiveOperation Operation = parseCommandLine();
978 return performOperation(Operation, nullptr);
979 }
980
981 static int ranlib_main(int argc, char **argv) {
982 bool ArchiveSpecified = false;
983 for(int i = 1; i < argc; ++i) {
984 if (handleGenericOption(argv[i])) {
985 return 0;
986 } else {
987 if (ArchiveSpecified)
988 fail("Exactly one archive should be specified");
989 ArchiveSpecified = true;
990 ArchiveName = argv[i];
991 }
992 }
993 return performOperation(CreateSymTab, nullptr);
994 }
995
996 int main(int argc, char **argv) {
997 InitLLVM X(argc, argv);
998 ToolName = argv[0];
999
1000 llvm::InitializeAllTargetInfos();
1001 llvm::InitializeAllTargetMCs();
1002 llvm::InitializeAllAsmParsers();
1003
1004 Stem = sys::path::stem(ToolName);
1005 if (Stem.contains_lower("dlltool"))
1006 return dlltoolDriverMain(makeArrayRef(argv, argc));
1007
1008 if (Stem.contains_lower("ranlib"))
1009 return ranlib_main(argc, argv);
1010
1011 if (Stem.contains_lower("lib"))
1012 return libDriverMain(makeArrayRef(argv, argc));
1013
1014 if (Stem.contains_lower("ar"))
1015 return ar_main(argc, argv);
1016 fail("Not ranlib, ar, lib or dlltool!");
1017 }
0 //===-- llvm-ar.cpp - LLVM archive librarian utility ----------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Builds up (relatively) standard unix archive files (.a) containing LLVM
10 // bitcode or other files.
11 //
12 //===----------------------------------------------------------------------===//
13
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/raw_ostream.h"
36 #include "llvm/ToolDrivers/llvm-dlltool/DlltoolDriver.h"
37 #include "llvm/ToolDrivers/llvm-lib/LibDriver.h"
38
39 #if !defined(_MSC_VER) && !defined(__MINGW32__)
40 #include
41 #else
42 #include
43 #endif
44
45 using namespace llvm;
46
47 // The name this program was invoked as.
48 static StringRef ToolName;
49
50 // The basename of this program.
51 static StringRef Stem;
52
53 const char RanlibHelp[] = R"(
54 OVERVIEW: LLVM Ranlib (llvm-ranlib)
55
56 This program generates an index to speed access to archives
57
58 USAGE: llvm-ranlib
59
60 OPTIONS:
61 -help - Display available options
62 -version - Display the version of this program
63 )";
64
65 const char ArHelp[] = R"(
66 OVERVIEW: LLVM Archiver
67
68 USAGE: llvm-ar [options] [-][modifiers] [relpos] [files]
69 llvm-ar -M [
70
71 OPTIONS:
72 --format - Archive format to create
73 =default - default
74 =gnu - gnu
75 =darwin - darwin
76 =bsd - bsd
77 --plugin= - Ignored for compatibility
78 --help - Display available options
79 --version - Display the version of this program
80
81 OPERATIONS:
82 d - delete [files] from the archive
83 m - move [files] in the archive
84 p - print [files] found in the archive
85 q - quick append [files] to the archive
86 r - replace or insert [files] into the archive
87 s - act as ranlib
88 t - display contents of archive
89 x - extract [files] from the archive
90
91 MODIFIERS:
92 [a] - put [files] after [relpos]
93 [b] - put [files] before [relpos] (same as [i])
94 [c] - do not warn if archive had to be created
95 [D] - use zero for timestamps and uids/gids (default)
96 [i] - put [files] before [relpos] (same as [b])
97 [l] - ignored for compatibility
98 [L] - add archive's contents
99 [o] - preserve original dates
100 [s] - create an archive index (cf. ranlib)
101 [S] - do not build a symbol table
102 [T] - create a thin archive
103 [u] - update only [files] newer than archive contents
104 [U] - use actual timestamps and uids/gids
105 [v] - be verbose about actions taken
106 )";
107
108 void printHelpMessage() {
109 if (Stem.contains_lower("ranlib"))
110 outs() << RanlibHelp;
111 else if (Stem.contains_lower("ar"))
112 outs() << ArHelp;
113 }
114
115 // Show the error message and exit.
116 LLVM_ATTRIBUTE_NORETURN static void fail(Twine Error) {
117 errs() << ToolName << ": " << Error << ".\n";
118 printHelpMessage();
119 exit(1);
120 }
121
122 static void failIfError(std::error_code EC, Twine Context = "") {
123 if (!EC)
124 return;
125
126 std::string ContextStr = Context.str();
127 if (ContextStr == "")
128 fail(EC.message());
129 fail(Context + ": " + EC.message());
130 }
131
132 static void failIfError(Error E, Twine Context = "") {
133 if (!E)
134 return;
135
136 handleAllErrors(std::move(E), [&](const llvm::ErrorInfoBase &EIB) {
137 std::string ContextStr = Context.str();
138 if (ContextStr == "")
139 fail(EIB.message());
140 fail(Context + ": " + EIB.message());
141 });
142 }
143
144 static SmallVector PositionalArgs;
145
146 static bool MRI;
147
148 namespace {
149 enum Format { Default, GNU, BSD, DARWIN, Unknown };
150 }
151
152 static Format FormatType = Default;
153
154 static std::string Options;
155
156 // This enumeration delineates the kinds of operations on an archive
157 // that are permitted.
158 enum ArchiveOperation {
159 Print, ///< Print the contents of the archive
160 Delete, ///< Delete the specified members
161 Move, ///< Move members to end or as given by {a,b,i} modifiers
162 QuickAppend, ///< Quickly append to end of archive
163 ReplaceOrInsert, ///< Replace or Insert members
164 DisplayTable, ///< Display the table of contents
165 Extract, ///< Extract files back to file system
166 CreateSymTab ///< Create a symbol table in an existing archive
167 };
168
169 // Modifiers to follow operation to vary behavior
170 static bool AddAfter = false; ///< 'a' modifier
171 static bool AddBefore = false; ///< 'b' modifier
172 static bool Create = false; ///< 'c' modifier
173 static bool OriginalDates = false; ///< 'o' modifier
174 static bool OnlyUpdate = false; ///< 'u' modifier
175 static bool Verbose = false; ///< 'v' modifier
176 static bool Symtab = true; ///< 's' modifier
177 static bool Deterministic = true; ///< 'D' and 'U' modifiers
178 static bool Thin = false; ///< 'T' modifier
179 static bool AddLibrary = false; ///< 'L' modifier
180
181 // Relative Positional Argument (for insert/move). This variable holds
182 // the name of the archive member to which the 'a', 'b' or 'i' modifier
183 // refers. Only one of 'a', 'b' or 'i' can be specified so we only need
184 // one variable.
185 static std::string RelPos;
186
187 // This variable holds the name of the archive file as given on the
188 // command line.
189 static std::string ArchiveName;
190
191 // This variable holds the list of member files to proecess, as given
192 // on the command line.
193 static std::vector Members;
194
195 // Extract the member filename from the command line for the [relpos] argument
196 // associated with a, b, and i modifiers
197 static void getRelPos() {
198 if (PositionalArgs.size() == 0)
199 fail("Expected [relpos] for a, b, or i modifier");
200 RelPos = PositionalArgs[0];
201 PositionalArgs.erase(PositionalArgs.begin());
202 }
203
204 // Get the archive file name from the command line
205 static void getArchive() {
206 if (PositionalArgs.size() == 0)
207 fail("An archive name must be specified");
208 ArchiveName = PositionalArgs[0];
209 PositionalArgs.erase(PositionalArgs.begin());
210 }
211
212 // Copy over remaining items in PositionalArgs to our Members vector
213 static void getMembers() {
214 for (auto &Arg : PositionalArgs)
215 Members.push_back(Arg);
216 }
217
218 std::vector> ArchiveBuffers;
219 std::vector> Archives;
220
221 static object::Archive &readLibrary(const Twine &Library) {
222 auto BufOrErr = MemoryBuffer::getFile(Library, -1, false);
223 failIfError(BufOrErr.getError(), "Could not open library");
224 ArchiveBuffers.push_back(std::move(*BufOrErr));
225 auto LibOrErr =
226 object::Archive::create(ArchiveBuffers.back()->getMemBufferRef());
227 failIfError(errorToErrorCode(LibOrErr.takeError()),
228 "Could not parse library");
229 Archives.push_back(std::move(*LibOrErr));
230 return *Archives.back();
231 }
232
233 static void runMRIScript();
234
235 // Parse the command line options as presented and return the operation
236 // specified. Process all modifiers and check to make sure that constraints on
237 // modifier/operation pairs have not been violated.
238 static ArchiveOperation parseCommandLine() {
239 if (MRI) {
240 if (!PositionalArgs.empty() || !Options.empty())
241 fail("Cannot mix -M and other options");
242 runMRIScript();
243 }
244
245 // Keep track of number of operations. We can only specify one
246 // per execution.
247 unsigned NumOperations = 0;
248
249 // Keep track of the number of positional modifiers (a,b,i). Only
250 // one can be specified.
251 unsigned NumPositional = 0;
252
253 // Keep track of which operation was requested
254 ArchiveOperation Operation;
255
256 bool MaybeJustCreateSymTab = false;
257
258 for (unsigned i = 0; i < Options.size(); ++i) {
259 switch (Options[i]) {
260 case 'd':
261 ++NumOperations;
262 Operation = Delete;
263 break;
264 case 'm':
265 ++NumOperations;
266 Operation = Move;
267 break;
268 case 'p':
269 ++NumOperations;
270 Operation = Print;
271 break;
272 case 'q':
273 ++NumOperations;
274 Operation = QuickAppend;
275 break;
276 case 'r':
277 ++NumOperations;
278 Operation = ReplaceOrInsert;
279 break;
280 case 't':
281 ++NumOperations;
282 Operation = DisplayTable;
283 break;
284 case 'x':
285 ++NumOperations;
286 Operation = Extract;
287 break;
288 case 'c':
289 Create = true;
290 break;
291 case 'l': /* accepted but unused */
292 break;
293 case 'o':
294 OriginalDates = true;
295 break;
296 case 's':
297 Symtab = true;
298 MaybeJustCreateSymTab = true;
299 break;
300 case 'S':
301 Symtab = false;
302 break;
303 case 'u':
304 OnlyUpdate = true;
305 break;
306 case 'v':
307 Verbose = true;
308 break;
309 case 'a':
310 getRelPos();
311 AddAfter = true;
312 NumPositional++;
313 break;
314 case 'b':
315 getRelPos();
316 AddBefore = true;
317 NumPositional++;
318 break;
319 case 'i':
320 getRelPos();
321 AddBefore = true;
322 NumPositional++;
323 break;
324 case 'D':
325 Deterministic = true;
326 break;
327 case 'U':
328 Deterministic = false;
329 break;
330 case 'T':
331 Thin = true;
332 break;
333 case 'L':
334 AddLibrary = true;
335 break;
336 default:
337 fail(std::string("unknown option ") + Options[i]);
338 }
339 }
340
341 // At this point, the next thing on the command line must be
342 // the archive name.
343 getArchive();
344
345 // Everything on the command line at this point is a member.
346 getMembers();
347
348 if (NumOperations == 0 && MaybeJustCreateSymTab) {
349 NumOperations = 1;
350 Operation = CreateSymTab;
351 if (!Members.empty())
352 fail("The s operation takes only an archive as argument");
353 }
354
355 // Perform various checks on the operation/modifier specification
356 // to make sure we are dealing with a legal request.
357 if (NumOperations == 0)
358 fail("You must specify at least one of the operations");
359 if (NumOperations > 1)
360 fail("Only one operation may be specified");
361 if (NumPositional > 1)
362 fail("You may only specify one of a, b, and i modifiers");
363 if (AddAfter || AddBefore) {
364 if (Operation != Move && Operation != ReplaceOrInsert)
365 fail("The 'a', 'b' and 'i' modifiers can only be specified with "
366 "the 'm' or 'r' operations");
367 }
368 if (OriginalDates && Operation != Extract)
369 fail("The 'o' modifier is only applicable to the 'x' operation");
370 if (OnlyUpdate && Operation != ReplaceOrInsert)
371 fail("The 'u' modifier is only applicable to the 'r' operation");
372 if (AddLibrary && Operation != QuickAppend)
373 fail("The 'L' modifier is only applicable to the 'q' operation");
374
375 // Return the parsed operation to the caller
376 return Operation;
377 }
378
379 // Implements the 'p' operation. This function traverses the archive
380 // looking for members that match the path list.
381 static void doPrint(StringRef Name, const object::Archive::Child &C) {
382 if (Verbose)
383 outs() << "Printing " << Name << "\n";
384
385 Expected DataOrErr = C.getBuffer();
386 failIfError(DataOrErr.takeError());
387 StringRef Data = *DataOrErr;
388 outs().write(Data.data(), Data.size());
389 }
390
391 // Utility function for printing out the file mode when the 't' operation is in
392 // verbose mode.
393 static void printMode(unsigned mode) {
394 outs() << ((mode & 004) ? "r" : "-");
395 outs() << ((mode & 002) ? "w" : "-");
396 outs() << ((mode & 001) ? "x" : "-");
397 }
398
399 // 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.
403 static void doDisplayTable(StringRef Name, const object::Archive::Child &C) {
404 if (Verbose) {
405 Expected ModeOrErr = C.getAccessMode();
406 failIfError(ModeOrErr.takeError());
407 sys::fs::perms Mode = ModeOrErr.get();
408 printMode((Mode >> 6) & 007);
409 printMode((Mode >> 3) & 007);
410 printMode(Mode & 007);
411 Expected UIDOrErr = C.getUID();
412 failIfError(UIDOrErr.takeError());
413 outs() << ' ' << UIDOrErr.get();
414 Expected GIDOrErr = C.getGID();
415 failIfError(GIDOrErr.takeError());
416 outs() << '/' << GIDOrErr.get();
417 Expected Size = C.getSize();
418 failIfError(Size.takeError());
419 outs() << ' ' << format("%6llu", Size.get());
420 auto ModTimeOrErr = C.getLastModified();
421 failIfError(ModTimeOrErr.takeError());
422 // Note: formatv() only handles the default TimePoint<>, which is in
423 // nanoseconds.
424 // TODO: fix format_provider> to allow other units.
425 sys::TimePoint<> ModTimeInNs = ModTimeOrErr.get();
426 outs() << ' ' << formatv("{0:%b %e %H:%M %Y}", ModTimeInNs);
427 outs() << ' ';
428 }
429
430 if (C.getParent()->isThin()) {
431 outs() << sys::path::parent_path(ArchiveName);
432 outs() << '/';
433 }
434 outs() << Name << "\n";
435 }
436
437 // Implement the 'x' operation. This function extracts files back to the file
438 // system.
439 static void doExtract(StringRef Name, const object::Archive::Child &C) {
440 // Retain the original mode.
441 Expected ModeOrErr = C.getAccessMode();
442 failIfError(ModeOrErr.takeError());
443 sys::fs::perms Mode = ModeOrErr.get();
444
445 int FD;
446 failIfError(sys::fs::openFileForWrite(sys::path::filename(Name), FD,
447 sys::fs::CD_CreateAlways,
448 sys::fs::F_None, Mode),
449 Name);
450
451 {
452 raw_fd_ostream file(FD, false);
453
454 // Get the data and its length
455 Expected BufOrErr = C.getBuffer();
456 failIfError(BufOrErr.takeError());
457 StringRef Data = BufOrErr.get();
458
459 // Write the data.
460 file.write(Data.data(), Data.size());
461 }
462
463 // If we're supposed to retain the original modification times, etc. do so
464 // now.
465 if (OriginalDates) {
466 auto ModTimeOrErr = C.getLastModified();
467 failIfError(ModTimeOrErr.takeError());
468 failIfError(
469 sys::fs::setLastAccessAndModificationTime(FD, ModTimeOrErr.get()));
470 }
471
472 if (close(FD))
473 fail("Could not close the file");
474 }
475
476 static bool shouldCreateArchive(ArchiveOperation Op) {
477 switch (Op) {
478 case Print:
479 case Delete:
480 case Move:
481 case DisplayTable:
482 case Extract:
483 case CreateSymTab:
484 return false;
485
486 case QuickAppend:
487 case ReplaceOrInsert:
488 return true;
489 }
490
491 llvm_unreachable("Missing entry in covered switch.");
492 }
493
494 static void performReadOperation(ArchiveOperation Operation,
495 object::Archive *OldArchive) {
496 if (Operation == Extract && OldArchive->isThin())
497 fail("extracting from a thin archive is not supported");
498
499 bool Filter = !Members.empty();
500 {
501 Error Err = Error::success();
502 for (auto &C : OldArchive->children(Err)) {
503 Expected NameOrErr = C.getName();
504 failIfError(NameOrErr.takeError());
505 StringRef Name = NameOrErr.get();
506
507 if (Filter) {
508 auto I = find(Members, Name);
509 if (I == Members.end())
510 continue;
511 Members.erase(I);
512 }
513
514 switch (Operation) {
515 default:
516 llvm_unreachable("Not a read operation");
517 case Print:
518 doPrint(Name, C);
519 break;
520 case DisplayTable:
521 doDisplayTable(Name, C);
522 break;
523 case Extract:
524 doExtract(Name, C);
525 break;
526 }
527 }
528 failIfError(std::move(Err));
529 }
530
531 if (Members.empty())
532 return;
533 for (StringRef Name : Members)
534 errs() << Name << " was not found\n";
535 exit(1);
536 }
537
538 static void addMember(std::vector &Members,
539 StringRef FileName, int Pos = -1) {
540 Expected NMOrErr =
541 NewArchiveMember::getFile(FileName, Deterministic);
542 failIfError(NMOrErr.takeError(), FileName);
543
544 // Use the basename of the object path for the member name.
545 NMOrErr->MemberName = sys::path::filename(NMOrErr->MemberName);
546
547 if (Pos == -1)
548 Members.push_back(std::move(*NMOrErr));
549 else
550 Members[Pos] = std::move(*NMOrErr);
551 }
552
553 static void addMember(std::vector &Members,
554 const object::Archive::Child &M, int Pos = -1) {
555 if (Thin && !M.getParent()->isThin())
556 fail("Cannot convert a regular archive to a thin one");
557 Expected NMOrErr =
558 NewArchiveMember::getOldMember(M, Deterministic);
559 failIfError(NMOrErr.takeError());
560 if (Pos == -1)
561 Members.push_back(std::move(*NMOrErr));
562 else
563 Members[Pos] = std::move(*NMOrErr);
564 }
565
566 static void addLibMember(std::vector &Members,
567 StringRef FileName) {
568 Expected NMOrErr =
569 NewArchiveMember::getFile(FileName, Deterministic);
570 failIfError(NMOrErr.takeError(), FileName);
571 if (identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) {
572 object::Archive &Lib = readLibrary(FileName);
573 Error Err = Error::success();
574
575 for (auto &Child : Lib.children(Err))
576 addMember(Members, Child);
577
578 failIfError(std::move(Err));
579 } else {
580 // Use the basename of the object path for the member name.
581 NMOrErr->MemberName = sys::path::filename(NMOrErr->MemberName);
582 Members.push_back(std::move(*NMOrErr));
583 }
584 }
585
586 enum InsertAction {
587 IA_AddOldMember,
588 IA_AddNewMember,
589 IA_Delete,
590 IA_MoveOldMember,
591 IA_MoveNewMember
592 };
593
594 static InsertAction computeInsertAction(ArchiveOperation Operation,
595 const object::Archive::Child &Member,
596 StringRef Name,
597 std::vector::iterator &Pos) {
598 if (Operation == QuickAppend || Members.empty())
599 return IA_AddOldMember;
600
601 auto MI = find_if(Members, [Name](StringRef Path) {
602 return Name == sys::path::filename(Path);
603 });
604
605 if (MI == Members.end())
606 return IA_AddOldMember;
607
608 Pos = MI;
609
610 if (Operation == Delete)
611 return IA_Delete;
612
613 if (Operation == Move)
614 return IA_MoveOldMember;
615
616 if (Operation == ReplaceOrInsert) {
617 StringRef PosName = sys::path::filename(RelPos);
618 if (!OnlyUpdate) {
619 if (PosName.empty())
620 return IA_AddNewMember;
621 return IA_MoveNewMember;
622 }
623
624 // We could try to optimize this to a fstat, but it is not a common
625 // operation.
626 sys::fs::file_status Status;
627 failIfError(sys::fs::status(*MI, Status), *MI);
628 auto ModTimeOrErr = Member.getLastModified();
629 failIfError(ModTimeOrErr.takeError());
630 if (Status.getLastModificationTime() < ModTimeOrErr.get()) {
631 if (PosName.empty())
632 return IA_AddOldMember;
633 return IA_MoveOldMember;
634 }
635
636 if (PosName.empty())
637 return IA_AddNewMember;
638 return IA_MoveNewMember;
639 }
640 llvm_unreachable("No such operation");
641 }
642
643 // We have to walk this twice and computing it is not trivial, so creating an
644 // explicit std::vector is actually fairly efficient.
645 static std::vector
646 computeNewArchiveMembers(ArchiveOperation Operation,
647 object::Archive *OldArchive) {
648 std::vector Ret;
649 std::vector Moved;
650 int InsertPos = -1;
651 StringRef PosName = sys::path::filename(RelPos);
652 if (OldArchive) {
653 Error Err = Error::success();
654 for (auto &Child : OldArchive->children(Err)) {
655 int Pos = Ret.size();
656 Expected NameOrErr = Child.getName();
657 failIfError(NameOrErr.takeError());
658 StringRef Name = NameOrErr.get();
659 if (Name == PosName) {
660 assert(AddAfter || AddBefore);
661 if (AddBefore)
662 InsertPos = Pos;
663 else
664 InsertPos = Pos + 1;
665 }
666
667 std::vector::iterator MemberI = Members.end();
668 InsertAction Action =
669 computeInsertAction(Operation, Child, Name, MemberI);
670 switch (Action) {
671 case IA_AddOldMember:
672 addMember(Ret, Child);
673 break;
674 case IA_AddNewMember:
675 addMember(Ret, *MemberI);
676 break;
677 case IA_Delete:
678 break;
679 case IA_MoveOldMember:
680 addMember(Moved, Child);
681 break;
682 case IA_MoveNewMember:
683 addMember(Moved, *MemberI);
684 break;
685 }
686 if (MemberI != Members.end())
687 Members.erase(MemberI);
688 }
689 failIfError(std::move(Err));
690 }
691
692 if (Operation == Delete)
693 return Ret;
694
695 if (!RelPos.empty() && InsertPos == -1)
696 fail("Insertion point not found");
697
698 if (RelPos.empty())
699 InsertPos = Ret.size();
700
701 assert(unsigned(InsertPos) <= Ret.size());
702 int Pos = InsertPos;
703 for (auto &M : Moved) {
704 Ret.insert(Ret.begin() + Pos, std::move(M));
705 ++Pos;
706 }
707
708 if (AddLibrary) {
709 assert(Operation == QuickAppend);
710 for (auto &Member : Members)
711 addLibMember(Ret, Member);
712 return Ret;
713 }
714
715 for (unsigned I = 0; I != Members.size(); ++I)
716 Ret.insert(Ret.begin() + InsertPos, NewArchiveMember());
717 Pos = InsertPos;
718 for (auto &Member : Members) {
719 addMember(Ret, Member, Pos);
720 ++Pos;
721 }
722
723 return Ret;
724 }
725
726 static object::Archive::Kind getDefaultForHost() {
727 return Triple(sys::getProcessTriple()).isOSDarwin()
728 ? object::Archive::K_DARWIN
729 : object::Archive::K_GNU;
730 }
731
732 static object::Archive::Kind getKindFromMember(const NewArchiveMember &Member) {
733 Expected> OptionalObject =
734 object::ObjectFile::createObjectFile(Member.Buf->getMemBufferRef());
735
736 if (OptionalObject)
737 return isa(**OptionalObject)
738 ? object::Archive::K_DARWIN
739 : object::Archive::K_GNU;
740
741 // squelch the error in case we had a non-object file
742 consumeError(OptionalObject.takeError());
743 return getDefaultForHost();
744 }
745
746 static void performWriteOperation(ArchiveOperation Operation,
747 object::Archive *OldArchive,
748 std::unique_ptr OldArchiveBuf,
749 std::vector *NewMembersP) {
750 std::vector NewMembers;
751 if (!NewMembersP)
752 NewMembers = computeNewArchiveMembers(Operation, OldArchive);
753
754 object::Archive::Kind Kind;
755 switch (FormatType) {
756 case Default:
757 if (Thin)
758 Kind = object::Archive::K_GNU;
759 else if (OldArchive)
760 Kind = OldArchive->kind();
761 else if (NewMembersP)
762 Kind = NewMembersP->size() ? getKindFromMember(NewMembersP->front())
763 : getDefaultForHost();
764 else
765 Kind = NewMembers.size() ? getKindFromMember(NewMembers.front())
766 : getDefaultForHost();
767 break;
768 case GNU:
769 Kind = object::Archive::K_GNU;
770 break;
771 case BSD:
772 if (Thin)
773 fail("Only the gnu format has a thin mode");
774 Kind = object::Archive::K_BSD;
775 break;
776 case DARWIN:
777 if (Thin)
778 fail("Only the gnu format has a thin mode");
779 Kind = object::Archive::K_DARWIN;
780 break;
781 case Unknown:
782 llvm_unreachable("");
783 }
784
785 Error E =
786 writeArchive(ArchiveName, NewMembersP ? *NewMembersP : NewMembers, Symtab,
787 Kind, Deterministic, Thin, std::move(OldArchiveBuf));
788 failIfError(std::move(E), ArchiveName);
789 }
790
791 static void createSymbolTable(object::Archive *OldArchive) {
792 // When an archive is created or modified, if the s option is given, the
793 // resulting archive will have a current symbol table. If the S option
794 // is given, it will have no symbol table.
795 // In summary, we only need to update the symbol table if we have none.
796 // This is actually very common because of broken build systems that think
797 // they have to run ranlib.
798 if (OldArchive->hasSymbolTable())
799 return;
800
801 performWriteOperation(CreateSymTab, OldArchive, nullptr, nullptr);
802 }
803
804 static void performOperation(ArchiveOperation Operation,
805 object::Archive *OldArchive,
806 std::unique_ptr OldArchiveBuf,
807 std::vector *NewMembers) {
808 switch (Operation) {
809 case Print:
810 case DisplayTable:
811 case Extract:
812 performReadOperation(Operation, OldArchive);
813 return;
814
815 case Delete:
816 case Move:
817 case QuickAppend:
818 case ReplaceOrInsert:
819 performWriteOperation(Operation, OldArchive, std::move(OldArchiveBuf),
820 NewMembers);
821 return;
822 case CreateSymTab:
823 createSymbolTable(OldArchive);
824 return;
825 }
826 llvm_unreachable("Unknown operation.");
827 }
828
829 static int performOperation(ArchiveOperation Operation,
830 std::vector *NewMembers) {
831 // Create or open the archive object.
832 ErrorOr> Buf =
833 MemoryBuffer::getFile(ArchiveName, -1, false);
834 std::error_code EC = Buf.getError();
835 if (EC && EC != errc::no_such_file_or_directory)
836 fail("error opening '" + ArchiveName + "': " + EC.message() + "!");
837
838 if (!EC) {
839 Error Err = Error::success();
840 object::Archive Archive(Buf.get()->getMemBufferRef(), Err);
841 EC = errorToErrorCode(std::move(Err));
842 failIfError(EC,
843 "error loading '" + ArchiveName + "': " + EC.message() + "!");
844 performOperation(Operation, &Archive, std::move(Buf.get()), NewMembers);
845 return 0;
846 }
847
848 assert(EC == errc::no_such_file_or_directory);
849
850 if (!shouldCreateArchive(Operation)) {
851 failIfError(EC, Twine("error loading '") + ArchiveName + "'");
852 } else {
853 if (!Create) {
854 // Produce a warning if we should and we're creating the archive
855 errs() << ToolName << ": creating " << ArchiveName << "\n";
856 }
857 }
858
859 performOperation(Operation, nullptr, nullptr, NewMembers);
860 return 0;
861 }
862
863 static void runMRIScript() {
864 enum class MRICommand { AddLib, AddMod, Create, Delete, Save, End, Invalid };
865
866 ErrorOr> Buf = MemoryBuffer::getSTDIN();
867 failIfError(Buf.getError());
868 const MemoryBuffer &Ref = *Buf.get();
869 bool Saved = false;
870 std::vector NewMembers;
871
872 for (line_iterator I(Ref, /*SkipBlanks*/ false), E; I != E; ++I) {
873 StringRef Line = *I;
874 Line = Line.split(';').first;
875 Line = Line.split('*').first;
876 Line = Line.trim();
877 if (Line.empty())
878 continue;
879 StringRef CommandStr, Rest;
880 std::tie(CommandStr, Rest) = Line.split(' ');
881 Rest = Rest.trim();
882 if (!Rest.empty() && Rest.front() == '"' && Rest.back() == '"')
883 Rest = Rest.drop_front().drop_back();
884 auto Command = StringSwitch(CommandStr.lower())
885 .Case("addlib", MRICommand::AddLib)
886 .Case("addmod", MRICommand::AddMod)
887 .Case("create", MRICommand::Create)
888 .Case("delete", MRICommand::Delete)
889 .Case("save", MRICommand::Save)
890 .Case("end", MRICommand::End)
891 .Default(MRICommand::Invalid);
892
893 switch (Command) {
894 case MRICommand::AddLib: {
895 object::Archive &Lib = readLibrary(Rest);
896 {
897 Error Err = Error::success();
898 for (auto &Member : Lib.children(Err))
899 addMember(NewMembers, Member);
900 failIfError(std::move(Err));
901 }
902 break;
903 }
904 case MRICommand::AddMod:
905 addMember(NewMembers, Rest);
906 break;
907 case MRICommand::Create:
908 Create = true;
909 if (!ArchiveName.empty())
910 fail("Editing multiple archives not supported");
911 if (Saved)
912 fail("File already saved");
913 ArchiveName = Rest;
914 break;
915 case MRICommand::Delete: {
916 StringRef Name = sys::path::filename(Rest);
917 llvm::erase_if(NewMembers,
918 [=](NewArchiveMember &M) { return M.MemberName == Name; });
919 break;
920 }
921 case MRICommand::Save:
922 Saved = true;
923 break;
924 case MRICommand::End:
925 break;
926 case MRICommand::Invalid:
927 fail("Unknown command: " + CommandStr);
928 }
929 }
930
931 // Nothing to do if not saved.
932 if (Saved)
933 performOperation(ReplaceOrInsert, &NewMembers);
934 exit(0);
935 }
936
937 static bool handleGenericOption(StringRef arg) {
938 if (arg == "-help" || arg == "--help") {
939 printHelpMessage();
940 return true;
941 }
942 if (arg == "-version" || arg == "--version") {
943 cl::PrintVersionMessage();
944 return true;
945 }
946 return false;
947 }
948
949 static int ar_main(int argc, char **argv) {
950 SmallVector Argv(argv, argv + argc);
951 BumpPtrAllocator Alloc;
952 StringSaver Saver(Alloc);
953 cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Argv);
954 for (size_t i = 1; i < Argv.size(); ++i) {
955 StringRef Arg = Argv[i];
956 const char *match;
957 auto MatchFlagWithArg = [&](const char *expected) {
958 size_t len = strlen(expected);
959 if (Arg == expected) {
960 if (++i >= Argv.size())
961 fail(std::string(expected) + " requires an argument");
962 match = Argv[i];
963 return true;
964 }
965 if (Arg.startswith(expected) && Arg.size() > len && Arg[len] == '=') {
966 match = Arg.data() + len + 1;
967 return true;
968 }
969 return false;
970 };
971 if (handleGenericOption(Argv[i]))
972 return 0;
973 if (Arg == "--") {
974 for (; i < Argv.size(); ++i)
975 PositionalArgs.push_back(Argv[i]);
976 break;
977 }
978 if (Arg[0] == '-') {
979 if (Arg.startswith("--"))
980 Arg = Argv[i] + 2;
981 else
982 Arg = Argv[i] + 1;
983 if (Arg == "M") {
984 MRI = true;
985 } else if (MatchFlagWithArg("format")) {
986 FormatType = StringSwitch(match)
987 .Case("default", Default)
988 .Case("gnu", GNU)
989 .Case("darwin", DARWIN)
990 .Case("bsd", BSD)
991 .Default(Unknown);
992 if (FormatType == Unknown)
993 fail(std::string("Invalid format ") + match);
994 } else if (MatchFlagWithArg("plugin")) {
995 // Ignored.
996 } else {
997 Options += Argv[i] + 1;
998 }
999 } else if (Options.empty()) {
1000 Options += Argv[i];
1001 } else {
1002 PositionalArgs.push_back(Argv[i]);
1003 }
1004 }
1005 ArchiveOperation Operation = parseCommandLine();
1006 return performOperation(Operation, nullptr);
1007 }
1008
1009 static int ranlib_main(int argc, char **argv) {
1010 bool ArchiveSpecified = false;
1011 for (int i = 1; i < argc; ++i) {
1012 if (handleGenericOption(argv[i])) {
1013 return 0;
1014 } else {
1015 if (ArchiveSpecified)
1016 fail("Exactly one archive should be specified");
1017 ArchiveSpecified = true;
1018 ArchiveName = argv[i];
1019 }
1020 }
1021 return performOperation(CreateSymTab, nullptr);
1022 }
1023
1024 int main(int argc, char **argv) {
1025 InitLLVM X(argc, argv);
1026 ToolName = argv[0];
1027
1028 llvm::InitializeAllTargetInfos();
1029 llvm::InitializeAllTargetMCs();
1030 llvm::InitializeAllAsmParsers();
1031
1032 Stem = sys::path::stem(ToolName);
1033 if (Stem.contains_lower("dlltool"))
1034 return dlltoolDriverMain(makeArrayRef(argv, argc));
1035
1036 if (Stem.contains_lower("ranlib"))
1037 return ranlib_main(argc, argv);
1038
1039 if (Stem.contains_lower("lib"))
1040 return libDriverMain(makeArrayRef(argv, argc));
1041
1042 if (Stem.contains_lower("ar"))
1043 return ar_main(argc, argv);
1044 fail("Not ranlib, ar, lib or dlltool!");
1045 }