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