blob: 253384d6909ddeca92e45ad216db14eec26b0810 [file] [log] [blame]
Chris Lattnerce8781c2003-12-30 07:45:46 +00001//===-- llvm-ar.cpp - LLVM archive librarian utility ----------------------===//
John Criswell09344dc2003-10-20 17:47:21 +00002//
3// The LLVM Compiler Infrastructure
4//
Tanya Lattner8213dae2004-11-15 19:21:49 +00005// This file was developed by the LLVM research group and is distributed under
6// the University of Illinois Open Source License. See LICENSE.TXT for details.
John Criswell09344dc2003-10-20 17:47:21 +00007//
8//===----------------------------------------------------------------------===//
Tanya Lattner57c70a62003-08-28 15:22:38 +00009//
Reid Spencer84a12bf2004-11-14 22:20:07 +000010// Builds up (relatively) standard unix archive files (.a) containing LLVM
11// bytecode or other files.
Tanya Lattner57c70a62003-08-28 15:22:38 +000012//
13//===----------------------------------------------------------------------===//
Brian Gaeke81d153e2003-10-10 18:47:08 +000014
Tanya Lattner57c70a62003-08-28 15:22:38 +000015#include "llvm/Module.h"
Reid Spencer84a12bf2004-11-14 22:20:07 +000016#include "llvm/Bytecode/Archive.h"
Reid Spencer7c16caa2004-09-01 22:55:40 +000017#include "llvm/Support/CommandLine.h"
Reid Spencer84a12bf2004-11-14 22:20:07 +000018#include "llvm/Support/Compressor.h"
Reid Spencer7c16caa2004-09-01 22:55:40 +000019#include "llvm/Support/FileUtilities.h"
Chris Lattner278f5152004-05-27 05:41:36 +000020#include "llvm/System/Signals.h"
Reid Spencerf0ebb252004-07-04 12:20:55 +000021#include <iostream>
Reid Spencer84a12bf2004-11-14 22:20:07 +000022#include <algorithm>
23#include <iomanip>
24
Brian Gaeke960707c2003-11-11 22:41:34 +000025using namespace llvm;
26
Reid Spencer84a12bf2004-11-14 22:20:07 +000027// Option for compatibility with ASIX, not used but must allow it to be present.
28cl::opt<bool>
29X32Option ("X32_64", cl::desc("Ignored option for compatibility with AIX"));
Tanya Lattner57c70a62003-08-28 15:22:38 +000030
Reid Spencer84a12bf2004-11-14 22:20:07 +000031// llvm-ar operation code and modifier flags. This must come first
32cl::opt<std::string>
33Options(cl::Positional, cl::Required, cl::desc("{operation}[modifiers]..."));
Tanya Lattner57c70a62003-08-28 15:22:38 +000034
Reid Spencer84a12bf2004-11-14 22:20:07 +000035// llvm-ar remaining positional arguments
36cl::list<std::string>
37RestOfArgs(cl::Positional, cl::OneOrMore,
38 cl::desc("[relpos] [count] <archive-file> [members]..."));
Tanya Lattner57c70a62003-08-28 15:22:38 +000039
Reid Spencer84a12bf2004-11-14 22:20:07 +000040// This enumeration delineates the kinds of operations on an archive
41// that are permitted.
42enum ArchiveOperation {
43 NoOperation, ///< An operation hasn't been specified
44 Print, ///< Print the contents of the archive
45 Delete, ///< Delete the specified members
46 Move, ///< Move members to end or as given by {a,b,i} modifiers
47 QuickAppend, ///< Quickly append to end of archive
48 ReplaceOrInsert, ///< Replace or Insert members
49 DisplayTable, ///< Display the table of contents
50 Extract, ///< Extract files back to file system
Tanya Lattnerc970a382003-12-06 23:01:25 +000051};
Tanya Lattner57c70a62003-08-28 15:22:38 +000052
Reid Spencer84a12bf2004-11-14 22:20:07 +000053// Modifiers to follow operation to vary behavior
54bool AddAfter = false; ///< 'a' modifier
55bool AddBefore = false; ///< 'b' modifier
56bool Create = false; ///< 'c' modifier
57bool TruncateNames = false; ///< 'f' modifier
58bool InsertBefore = false; ///< 'i' modifier
59bool DontSkipBytecode = false; ///< 'k' modifier
60bool UseCount = false; ///< 'N' modifier
61bool OriginalDates = false; ///< 'o' modifier
62bool FullPath = false; ///< 'P' modifier
63bool RecurseDirectories = false; ///< 'R' modifier
64bool SymTable = true; ///< 's' & 'S' modifiers
65bool OnlyUpdate = false; ///< 'u' modifier
66bool Verbose = false; ///< 'v' modifier
67bool ReallyVerbose = false; ///< 'V' modifier
68bool Compression = false; ///< 'z' modifier
Tanya Lattner57c70a62003-08-28 15:22:38 +000069
Reid Spencer84a12bf2004-11-14 22:20:07 +000070// Relative Positional Argument (for insert/move). This variable holds
71// the name of the archive member to which the 'a', 'b' or 'i' modifier
72// refers. Only one of 'a', 'b' or 'i' can be specified so we only need
73// one variable.
74std::string RelPos;
Tanya Lattnerc970a382003-12-06 23:01:25 +000075
Reid Spencer84a12bf2004-11-14 22:20:07 +000076// Select which of multiple entries in the archive with the same name should be
77// used (specified with -N) for the delete and extract operations.
78int Count = 1;
Tanya Lattnerc970a382003-12-06 23:01:25 +000079
Reid Spencer84a12bf2004-11-14 22:20:07 +000080// This variable holds the name of the archive file as given on the
81// command line.
82std::string ArchiveName;
Tanya Lattnerc970a382003-12-06 23:01:25 +000083
Reid Spencer84a12bf2004-11-14 22:20:07 +000084// This variable holds the list of member files to proecess, as given
85// on the command line.
86std::vector<std::string> Members;
Tanya Lattnerc970a382003-12-06 23:01:25 +000087
Reid Spencer84a12bf2004-11-14 22:20:07 +000088// This variable holds the (possibly expanded) list of path objects that
89// correspond to files we will
90sys::Path::Vector Paths;
Tanya Lattnerc970a382003-12-06 23:01:25 +000091
Reid Spencer84a12bf2004-11-14 22:20:07 +000092// The Archive object to which all the editing operations will be sent.
93Archive* TheArchive = 0;
Tanya Lattnerc970a382003-12-06 23:01:25 +000094
Reid Spencer84a12bf2004-11-14 22:20:07 +000095// printMoreHelp - Provide additional help output explaining the operations and
96// modifiers of llvm-ar. This function is called by the CommandLine library
97// when the --help option is given because we set the global cl::MoreHelp
98// variable to the address of this function.
99void printMoreHelp() {
100 std::cout
101 << "\nOPERATIONS:\n"
102 << " d[NsS] - delete file(s) from the archive\n"
103 << " m[abiSs] - move file(s) in the archive\n"
104 << " p[kN] - print file(s) found in the archive\n"
105 << " q[ufsS] - quick append file(s) to the archive\n"
106 << " r[abfiuzRsS] - replace or insert file(s) into the archive\n"
107 << " t - display contents of archive\n"
108 << " x[No] - extract file(s) from the archive\n";
Tanya Lattnerc970a382003-12-06 23:01:25 +0000109
Reid Spencer84a12bf2004-11-14 22:20:07 +0000110 std::cout
111 << "\nMODIFIERS (operation specific):\n"
112 << " [a] - put file(s) after [relpos]\n"
113 << " [b] - put file(s) before [relpos] (same as [i])\n"
114 << " [f] - truncate inserted file names\n"
115 << " [i] - put file(s) before [relpos] (same as [b])\n"
116 << " [k] - always print bytecode files (default is to skip them)\n"
117 << " [N] - use instance [count] of name\n"
118 << " [o] - preserve original dates\n"
119 << " [P] - use full path names when matching\n"
120 << " [R] - recurse through directories when inserting\n"
121 << " [s] - create an archive index (cf. ranlib)\n"
122 << " [S] - do not build a symbol table\n"
123 << " [u] - update only files newer than archive contents\n"
124 << " [z] - compress files before inserting/extracting\n";
Tanya Lattnerc970a382003-12-06 23:01:25 +0000125
Reid Spencer84a12bf2004-11-14 22:20:07 +0000126 std::cout
127 << "\nMODIFIERS (generic):\n"
128 << " [c] - do not warn if the library had to be created\n"
129 << " [v] - be verbose about actions taken\n"
130 << " [V] - be *really* verbose about actions taken\n";
Tanya Lattner57c70a62003-08-28 15:22:38 +0000131}
132
Reid Spencer84a12bf2004-11-14 22:20:07 +0000133// printUse - Print out our usage information. This is used in cases where the
134// user has made a mistake on the command line syntax.
Tanya Lattnerc970a382003-12-06 23:01:25 +0000135void printUse() {
Reid Spencer84a12bf2004-11-14 22:20:07 +0000136 std::cout
137 << "OVERVIEW: LLVM Archiver (llvm-ar)\n\n"
138 << " This program archives bytecode files into single libraries\n\n"
139 << "USAGE: llvm-ar [-X32_64] [-]{operation}[modifiers]... "
140 << "[relpos] [count] archive-file [files..]\n";
Tanya Lattnerc970a382003-12-06 23:01:25 +0000141
Reid Spencer84a12bf2004-11-14 22:20:07 +0000142 printMoreHelp();
Tanya Lattnerc970a382003-12-06 23:01:25 +0000143 exit(1);
144}
145
Reid Spencer84a12bf2004-11-14 22:20:07 +0000146// getRelPos - Extract the member filename from the command line for
147// the [relpos] argument associated with a, b, and i modifiers
Tanya Lattnerc970a382003-12-06 23:01:25 +0000148void getRelPos() {
Reid Spencer84a12bf2004-11-14 22:20:07 +0000149 if(RestOfArgs.size() > 0) {
150 RelPos = RestOfArgs[0];
151 RestOfArgs.erase(RestOfArgs.begin());
Tanya Lattnerc970a382003-12-06 23:01:25 +0000152 }
Tanya Lattnerc970a382003-12-06 23:01:25 +0000153 else
Reid Spencer84a12bf2004-11-14 22:20:07 +0000154 throw "Expected [relpos] for a, b, or i modifier";
Tanya Lattnerc970a382003-12-06 23:01:25 +0000155}
156
Reid Spencer84a12bf2004-11-14 22:20:07 +0000157// getCount - Extract the [count] argument associated with the N modifier
158// from the command line and check its value.
Tanya Lattnerc970a382003-12-06 23:01:25 +0000159void getCount() {
Reid Spencer84a12bf2004-11-14 22:20:07 +0000160 if(RestOfArgs.size() > 0) {
161 Count = atoi(RestOfArgs[0].c_str());
162 RestOfArgs.erase(RestOfArgs.begin());
Tanya Lattnerc970a382003-12-06 23:01:25 +0000163 }
Tanya Lattnerc970a382003-12-06 23:01:25 +0000164 else
Reid Spencer84a12bf2004-11-14 22:20:07 +0000165 throw "Expected [count] value with N modifier";
166
167 // Non-positive counts are not allowed
168 if (Count < 1)
169 throw "Invalid [count] value (not a positive integer)";
Tanya Lattnerc970a382003-12-06 23:01:25 +0000170}
171
Reid Spencer84a12bf2004-11-14 22:20:07 +0000172// getArchive - Get the archive file name from the command line
Tanya Lattnerc970a382003-12-06 23:01:25 +0000173void getArchive() {
Reid Spencer84a12bf2004-11-14 22:20:07 +0000174 if(RestOfArgs.size() > 0) {
175 ArchiveName = RestOfArgs[0];
176 RestOfArgs.erase(RestOfArgs.begin());
Tanya Lattnerc970a382003-12-06 23:01:25 +0000177 }
Tanya Lattnerc970a382003-12-06 23:01:25 +0000178 else
Reid Spencer84a12bf2004-11-14 22:20:07 +0000179 throw "An archive name must be specified.";
Tanya Lattnerc970a382003-12-06 23:01:25 +0000180}
181
Reid Spencer84a12bf2004-11-14 22:20:07 +0000182// getMembers - Copy over remaining items in RestOfArgs to our Members vector
183// This is just for clarity.
Tanya Lattnerc970a382003-12-06 23:01:25 +0000184void getMembers() {
Reid Spencer84a12bf2004-11-14 22:20:07 +0000185 if(RestOfArgs.size() > 0)
186 Members = std::vector<std::string>(RestOfArgs);
Tanya Lattnerc970a382003-12-06 23:01:25 +0000187}
188
Reid Spencer84a12bf2004-11-14 22:20:07 +0000189// parseCommandLine - Parse the command line options as presented and return the
190// operation specified. Process all modifiers and check to make sure that
191// constraints on modifier/operation pairs have not been violated.
192ArchiveOperation parseCommandLine() {
Tanya Lattnerc970a382003-12-06 23:01:25 +0000193
Reid Spencer84a12bf2004-11-14 22:20:07 +0000194 // Keep track of number of operations. We can only specify one
195 // per execution.
Tanya Lattnerc970a382003-12-06 23:01:25 +0000196 unsigned NumOperations = 0;
197
Reid Spencer84a12bf2004-11-14 22:20:07 +0000198 // Keep track of the number of positional modifiers (a,b,i). Only
199 // one can be specified.
200 unsigned NumPositional = 0;
201
202 // Keep track of which operation was requested
203 ArchiveOperation Operation = NoOperation;
204
Tanya Lattnerc970a382003-12-06 23:01:25 +0000205 for(unsigned i=0; i<Options.size(); ++i) {
206 switch(Options[i]) {
Reid Spencer84a12bf2004-11-14 22:20:07 +0000207 case 'd': ++NumOperations; Operation = Delete; break;
208 case 'm': ++NumOperations; Operation = Move ; break;
209 case 'p': ++NumOperations; Operation = Print; break;
210 case 'r': ++NumOperations; Operation = ReplaceOrInsert; break;
211 case 't': ++NumOperations; Operation = DisplayTable; break;
212 case 'x': ++NumOperations; Operation = Extract; break;
213 case 'c': Create = true; break;
214 case 'f': TruncateNames = true; break;
215 case 'k': DontSkipBytecode = true; break;
216 case 'l': /* accepted but unused */ break;
217 case 'o': OriginalDates = true; break;
218 case 'P': FullPath = true; break;
219 case 'R': RecurseDirectories = true; break;
220 case 's': SymTable = true; break;
221 case 'S': SymTable = false; break;
222 case 'u': OnlyUpdate = true; break;
223 case 'v': Verbose = true; break;
224 case 'V': Verbose = ReallyVerbose = true; break;
225 case 'z': Compression = true; break;
Tanya Lattnerc970a382003-12-06 23:01:25 +0000226 case 'a':
Tanya Lattnerc970a382003-12-06 23:01:25 +0000227 getRelPos();
Reid Spencer84a12bf2004-11-14 22:20:07 +0000228 AddAfter = true;
229 NumPositional++;
Tanya Lattnerc970a382003-12-06 23:01:25 +0000230 break;
231 case 'b':
Tanya Lattnerc970a382003-12-06 23:01:25 +0000232 getRelPos();
Reid Spencer84a12bf2004-11-14 22:20:07 +0000233 AddBefore = true;
234 NumPositional++;
Tanya Lattnerc970a382003-12-06 23:01:25 +0000235 break;
236 case 'i':
Tanya Lattnerc970a382003-12-06 23:01:25 +0000237 getRelPos();
Reid Spencer84a12bf2004-11-14 22:20:07 +0000238 InsertBefore = true;
239 NumPositional++;
Tanya Lattnerc970a382003-12-06 23:01:25 +0000240 break;
241 case 'N':
Reid Spencer84a12bf2004-11-14 22:20:07 +0000242 getCount();
Tanya Lattnerc970a382003-12-06 23:01:25 +0000243 UseCount = true;
Tanya Lattnerc970a382003-12-06 23:01:25 +0000244 break;
245 default:
246 printUse();
247 }
248 }
249
Reid Spencer84a12bf2004-11-14 22:20:07 +0000250 // At this point, the next thing on the command line must be
251 // the archive name.
Tanya Lattnerc970a382003-12-06 23:01:25 +0000252 getArchive();
Reid Spencer84a12bf2004-11-14 22:20:07 +0000253
254 // Everything on the command line at this point is a member.
Tanya Lattnerc970a382003-12-06 23:01:25 +0000255 getMembers();
256
Reid Spencer84a12bf2004-11-14 22:20:07 +0000257 // Perform various checks on the operation/modifier specification
258 // to make sure we are dealing with a legal request.
259 if (NumOperations == 0)
260 throw "You must specify at least one of the operations";
261 if (NumOperations > 1)
262 throw "Only one operation may be specified";
263 if (NumPositional > 1)
264 throw "You may only specify one of a, b, and i modifiers";
265 if (AddAfter || AddBefore || InsertBefore)
266 if (Operation != Move && Operation != ReplaceOrInsert)
267 throw "The 'a', 'b' and 'i' modifiers can only be specified with "
268 "the 'm' or 'r' operations";
269 if (RecurseDirectories && Operation != ReplaceOrInsert)
270 throw "The 'R' modifiers is only applicabe to the 'r' operation";
271 if (OriginalDates && Operation != Extract)
272 throw "The 'o' modifier is only applicable to the 'x' operation";
273 if (TruncateNames && Operation!=QuickAppend && Operation!=ReplaceOrInsert)
274 throw "The 'f' modifier is only applicable to the 'q' and 'r' operations";
275 if (OnlyUpdate && Operation != ReplaceOrInsert)
276 throw "The 'u' modifier is only applicable to the 'r' operation";
277 if (Compression && Operation!=ReplaceOrInsert && Operation!=Extract)
278 throw "The 'z' modifier is only applicable to the 'r' and 'x' operations";
279 if (Count > 1 && Members.size() > 1)
280 throw "Only one member name may be specified with the 'N' modifier";
281
282 // Return the parsed operation to the caller
283 return Operation;
Tanya Lattnerc970a382003-12-06 23:01:25 +0000284}
Tanya Lattner57c70a62003-08-28 15:22:38 +0000285
Reid Spencer84a12bf2004-11-14 22:20:07 +0000286// recurseDirectories - Implements the "R" modifier. This function scans through
287// the Paths vector (built by buildPaths, below) and replaces any directories it
288// finds with all the files in that directory (recursively). It uses the
289// sys::Path::getDirectoryContent method to perform the actual directory scans.
290sys::Path::Vector recurseDirectories(const sys::Path& path) {
291 assert(path.isDirectory() && "Oops, can't recurse a file");
292 sys::Path::Vector result;
293 if (RecurseDirectories) {
294 sys::Path::Vector content;
295 path.getDirectoryContents(content);
296 for (sys::Path::Vector::iterator I = content.begin(), E = content.end();
297 I != E; ++I) {
298 if (I->isDirectory()) {
299 sys::Path::Vector moreResults = recurseDirectories(*I);
300 result.insert(result.begin(), moreResults.begin(), moreResults.end());
301 } else {
302 result.push_back(*I);
303 }
304 }
305 }
306 return result;
307}
308
309// buildPaths - Convert the strings in the Members vector to sys::Path objects
310// and make sure they are valid and exist exist. This check is only needed for
311// the operations that add/replace files to the archive ('q' and 'r')
312void buildPaths(bool checkExistence = true) {
313 for (unsigned i = 0; i < Members.size(); i++) {
314 sys::Path aPath;
315 if (!aPath.setFile(Members[i]))
316 throw std::string("File member name invalid: ") + Members[i];
317 if (checkExistence) {
318 if (!aPath.exists())
319 throw std::string("File does not exist: ") + Members[i];
320 sys::Path::StatusInfo si;
321 aPath.getStatusInfo(si);
322 if (si.isDir) {
323 sys::Path::Vector dirpaths = recurseDirectories(aPath);
324 Paths.insert(Paths.end(),dirpaths.begin(),dirpaths.end());
325 } else {
326 Paths.push_back(aPath);
327 }
328 } else {
329 Paths.push_back(aPath);
330 }
331 }
332}
333
334// doPrint - Implements the 'p' operation. This function traverses the archive
335// looking for members that match the path list. It is careful to uncompress
336// things that should be and to skip bytecode files unless the 'k' modifier was
337// given.
338void doPrint() {
339 buildPaths(false);
340 unsigned countDown = Count;
341 for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end();
342 I != E; ++I ) {
343 if (Paths.empty() ||
344 (std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end())) {
345 if (countDown == 1) {
346 const char* data = reinterpret_cast<const char*>(I->getData());
347
348 // Skip things that don't make sense to print
349 if (I->isLLVMSymbolTable() || I->isForeignSymbolTable() ||
350 (!DontSkipBytecode &&
351 (I->isBytecode() || I->isCompressedBytecode())))
352 continue;
353
354 if (Verbose)
355 std::cout << "Printing " << I->getPath().get() << "\n";
356
357 if (I->isCompressedBytecode())
Reid Spencerb3eaba62004-11-14 23:17:41 +0000358 Compressor::decompressToStream(data+4,I->getSize()-4,std::cout);
Reid Spencer84a12bf2004-11-14 22:20:07 +0000359 else if (I->isCompressed()) {
Reid Spencerb3eaba62004-11-14 23:17:41 +0000360 Compressor::decompressToStream(data,I->getSize(),std::cout);
Reid Spencer84a12bf2004-11-14 22:20:07 +0000361 } else {
362 unsigned len = I->getSize();
363 std::cout.write(data, len);
364 }
365 } else {
366 countDown--;
367 }
368 }
369 }
370}
371
372// putMode - utility function for printing out the file mode when the 't'
373// operation is in verbose mode.
374void putMode(unsigned mode) {
375 if (mode & 004)
376 std::cout << "r";
377 else
378 std::cout << "-";
379 if (mode & 002)
380 std::cout << "w";
381 else
382 std::cout << "-";
383 if (mode & 001)
384 std::cout << "x";
385 else
386 std::cout << "-";
387}
388
389// doDisplayTable - Implement the 't' operation. This function prints out just
390// the file names of each of the members. However, if verbose mode is requested
391// ('v' modifier) then the file type, permission mode, user, group, size, and
392// modification time are also printed.
393void doDisplayTable() {
394 buildPaths(false);
395 for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end();
396 I != E; ++I ) {
397 if (Paths.empty() ||
398 (std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end())) {
399 if (Verbose) {
400 // FIXME: Output should be this format:
401 // Zrw-r--r-- 500/ 500 525 Nov 8 17:42 2004 Makefile
402 if (I->isBytecode())
403 std::cout << "b";
404 else if (I->isCompressedBytecode())
405 std::cout << "B";
406 else if (I->isForeignSymbolTable())
407 std::cout << "s";
408 else if (I->isLLVMSymbolTable())
409 std::cout << "S";
410 else if (I->isCompressed())
411 std::cout << "Z";
412 else
413 std::cout << " ";
414 unsigned mode = I->getMode();
415 putMode((mode >> 6) & 007);
416 putMode((mode >> 3) & 007);
417 putMode(mode & 007);
418 std::cout << " " << std::setw(4) << I->getUser();
419 std::cout << "/" << std::setw(4) << I->getGroup();
420 std::cout << " " << std::setw(8) << I->getSize();
421 std::cout << " " << std::setw(20) <<
Reid Spencerb3eaba62004-11-14 23:17:41 +0000422 I->getModTime().toString().substr(4);
Reid Spencer84a12bf2004-11-14 22:20:07 +0000423 std::cout << " " << I->getPath().get() << "\n";
424 } else {
425 std::cout << I->getPath().get() << "\n";
426 }
427 }
428 }
429 if (ReallyVerbose) {
430 std::cout << "\nArchive Symbol Table:\n";
431 const Archive::SymTabType& symtab = TheArchive->getSymbolTable();
432 for (Archive::SymTabType::const_iterator I=symtab.begin(), E=symtab.end();
433 I != E; ++I ) {
434 unsigned offset = TheArchive->getFirstFileOffset() + I->second;
435 std::cout << " " << std::setw(9) << offset << "\t" << I->first <<"\n";
436 }
437 }
438}
439
440// doExtract - Implement the 'x' operation. This function extracts files back to
441// the file system, making sure to uncompress any that were compressed.
442void doExtract() {
443 buildPaths(false);
444 unsigned countDown = Count;
445 for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end();
446 I != E; ++I ) {
447 if (Paths.empty() ||
448 (std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end())) {
449
450 // Make sure the intervening directories are created
451 if (I->hasPath()) {
452 sys::Path dirs(I->getPath());
453 dirs.elideFile();
454 dirs.createDirectory(/*create_parents=*/true);
455 }
456
457 // Open up a file stream for writing
458 std::ofstream file(I->getPath().c_str());
459
460 // Get the data and its length
461 const char* data = reinterpret_cast<const char*>(I->getData());
462 unsigned len = I->getSize();
463
464 // Write the data, making sure to uncompress things first
465 if (I->isCompressed()) {
Reid Spencerb3eaba62004-11-14 23:17:41 +0000466 Compressor::decompressToStream(data,len,file);
Reid Spencer84a12bf2004-11-14 22:20:07 +0000467 } else {
468 file.write(data,len);
469 }
470 file.close();
471
472 // If we're supposed to retain the original modification times, etc. do so
473 // now.
474 if (OriginalDates)
475 I->getPath().setStatusInfo(I->getStatusInfo());
476 }
477 }
478}
479
480// doDelete - Implement the delete operation. This function deletes zero or more
481// members from the archive. Note that if the count is specified, there should
482// be no more than one path in the Paths list or else this algorithm breaks.
483// That check is enforced in parseCommandLine (above).
484void doDelete() {
485 buildPaths(false);
486 if (Paths.empty()) return;
487 unsigned countDown = Count;
488 for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end();
489 I != E; ) {
490 if (std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end()) {
491 if (countDown == 1) {
492 Archive::iterator J = I;
493 ++I;
494 TheArchive->remove(J);
495 } else
496 countDown--;
497 } else {
498 ++I;
499 }
500 }
501
502 // We're done editting, reconstruct the archive.
503 TheArchive->writeToDisk(SymTable,TruncateNames,Compression,ReallyVerbose);
504}
505
506// doMore - Implement the move operation. This function re-arranges just the
507// order of the archive members so that when the archive is written the move
508// of the members is accomplished. Note the use of the RelPos variable to
509// determine where the items should be moved to.
510void doMove() {
511
512 buildPaths(false);
513
514 // By default and convention the place to move members to is the end of the
515 // archive.
516 Archive::iterator moveto_spot = TheArchive->end();
517
518 // However, if the relative positioning modifiers were used, we need to scan
519 // the archive to find the member in question. If we don't find it, its no
520 // crime, we just move to the end.
521 if (AddBefore || InsertBefore || AddAfter) {
522 for (Archive::iterator I = TheArchive->begin(), E= TheArchive->end();
523 I != E; ++I ) {
524 if (RelPos == I->getPath().get()) {
525 if (AddAfter) {
526 moveto_spot = I;
527 moveto_spot++;
528 } else {
529 moveto_spot = I;
530 }
531 break;
532 }
533 }
534 }
535
536 // Keep a list of the paths remaining to be moved
537 sys::Path::Vector remaining(Paths);
538
539 // Scan the archive again, this time looking for the members to move to the
540 // moveto_spot.
541 for (Archive::iterator I = TheArchive->begin(), E= TheArchive->end();
542 I != E && !remaining.empty(); ++I ) {
543 sys::Path::Vector::iterator found =
544 std::find(remaining.begin(),remaining.end(),I->getPath());
545 if (found != remaining.end()) {
546 if (I != moveto_spot)
547 TheArchive->moveMemberBefore(I,moveto_spot);
548 remaining.erase(found);
549 }
550 }
551
552 // We're done editting, reconstruct the archive.
553 TheArchive->writeToDisk(SymTable,TruncateNames,Compression,ReallyVerbose);
554}
555
556// doQuickAppend - Implements the 'q' operation. This function just
557// indiscriminantly adds the members to the archive and rebuilds it.
558void doQuickAppend() {
559 // Get the list of paths to append.
560 buildPaths(true);
561 if (Paths.empty()) return;
562
563 // Append them quickly.
564 for (sys::Path::Vector::iterator PI = Paths.begin(), PE = Paths.end();
565 PI != PE; ++PI) {
566 TheArchive->addFileBefore(*PI,TheArchive->end());
567 }
568
569 // We're done editting, reconstruct the archive.
570 TheArchive->writeToDisk(SymTable,TruncateNames,Compression,ReallyVerbose);
571}
572
573// doReplaceOrInsert - Implements the 'r' operation. This function will replace
574// any existing files or insert new ones into the archive.
575void doReplaceOrInsert() {
576
577 // Build the list of files to be added/replaced.
578 buildPaths(true);
579 if (Paths.empty()) return;
580
581 // Keep track of the paths that remain to be inserted.
582 sys::Path::Vector remaining(Paths);
583
584 // Default the insertion spot to the end of the archive
585 Archive::iterator insert_spot = TheArchive->end();
586
587 // Iterate over the archive contents
588 for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end();
589 I != E && !remaining.empty(); ++I ) {
590
591 // Determine if this archive member matches one of the paths we're trying
592 // to replace.
593 sys::Path::Vector::iterator found =
594 std::find(remaining.begin(),remaining.end(), I->getPath());
595 if (found != remaining.end()) {
596 if (OnlyUpdate) {
597 // Replace the item only if it is newer.
598 sys::Path::StatusInfo si;
599 found->getStatusInfo(si);
600 if (si.modTime > I->getModTime())
601 I->replaceWith(*found);
602 } else {
603 // Replace the item regardless of time stamp
604 I->replaceWith(*found);
605 }
606
607 // Remove it from our "to do" list
608 remaining.erase(found);
609 }
610
611 // Determine if this is the place where we should insert
612 if ((AddBefore || InsertBefore) && (RelPos == I->getPath().get()))
613 insert_spot = I;
614 else if (AddAfter && (RelPos == I->getPath().get())) {
615 insert_spot = I;
616 insert_spot++;
617 }
618 }
619
620 // If we didn't replace all the members, some will remain and need to be
621 // inserted at the previously computed insert-spot.
622 if (!remaining.empty()) {
623 for (sys::Path::Vector::iterator PI = remaining.begin(),
624 PE = remaining.end(); PI != PE; ++PI) {
625 TheArchive->addFileBefore(*PI,insert_spot);
626 }
627 }
628
629 // We're done editting, reconstruct the archive.
630 TheArchive->writeToDisk(SymTable,TruncateNames,Compression,ReallyVerbose);
631}
632
633// main - main program for llvm-ar .. see comments in the code
Tanya Lattner57c70a62003-08-28 15:22:38 +0000634int main(int argc, char **argv) {
Reid Spencer84a12bf2004-11-14 22:20:07 +0000635
636 // Ensure we initialize the global MoreHelp to tell the command line utility
637 // that we have a MoreHelp function. This function is called to print more
638 // help if the --help option is given on the command line
639 cl::MoreHelp = printMoreHelp;
640
641 // Have the command line options parsed and handle things
642 // like --help and --version.
643 cl::ParseCommandLineOptions(argc, argv,
644 " LLVM Archiver (llvm-ar)\n\n"
645 " This program archives bytecode files into single libraries\n"
646 );
647
648 // Print a stack trace if we signal out.
Reid Spencere3263ec2004-08-29 19:28:55 +0000649 sys::PrintStackTraceOnErrorSignal();
Chris Lattner12439ff2004-02-19 20:32:12 +0000650
Reid Spencer84a12bf2004-11-14 22:20:07 +0000651 int exitCode = 0;
Tanya Lattner57c70a62003-08-28 15:22:38 +0000652
Reid Spencer84a12bf2004-11-14 22:20:07 +0000653 // Make sure we don't exit with "unhandled exception".
654 try {
655 // Do our own parsing of the command line because the CommandLine utility
656 // can't handle the grouped positional parameters without a dash.
657 ArchiveOperation Operation = parseCommandLine();
Tanya Lattner57c70a62003-08-28 15:22:38 +0000658
Reid Spencer84a12bf2004-11-14 22:20:07 +0000659 // Check the path name of the archive
660 sys::Path ArchivePath;
661 if (!ArchivePath.setFile(ArchiveName))
662 throw std::string("Archive name invalid: ") + ArchiveName;
663
664 // Create or open the archive object.
665 if (!ArchivePath.exists()) {
666 // Produce a warning if we should and we're creating the archive
667 if (!Create)
668 std::cerr << argv[0] << ": creating " << ArchivePath.get() << "\n";
669 TheArchive = Archive::CreateEmpty(ArchivePath);
670 } else {
671 TheArchive = Archive::OpenAndLoad(ArchivePath);
672 }
673
674 // Make sure we're not fooling ourselves.
675 assert(TheArchive && "Unable to instantiate the archive");
676
677 // Perform the operation
678 switch (Operation) {
679 case Print: doPrint(); break;
680 case Delete: doDelete(); break;
681 case Move: doMove(); break;
682 case QuickAppend: /* FALL THROUGH */
683 case ReplaceOrInsert: doReplaceOrInsert(); break;
684 case DisplayTable: doDisplayTable(); break;
685 case Extract: doExtract(); break;
686 case NoOperation:
687 std::cerr << argv[0] << ": No operation was selected.\n";
688 break;
689 }
690
691 // Close up shop
692 delete TheArchive;
693
694 } catch (const char*msg) {
695 // These errors are usage errors, thrown only by the various checks in the
696 // code above.
697 std::cerr << argv[0] << ": " << msg << "\n\n";
698 printUse();
699 exitCode = 1;
700 } catch (const std::string& msg) {
701 // These errors are thrown by LLVM libraries (e.g. lib System) and represent
702 // a more serious error so we bump the exitCode and don't print the usage.
703 std::cerr << argv[0] << ": " << msg << "\n";
704 exitCode = 2;
705 } catch (...) {
706 // This really shouldn't happen, but just in case ....
707 std::cerr << argv[0] << ": An nexpected unknown exception occurred.\n";
708 exitCode = 3;
709 }
710
711 // Return result code back to operating system.
712 return exitCode;
Tanya Lattner57c70a62003-08-28 15:22:38 +0000713}