[llvm] r186197 - Change llvm-ar to use lib/Object.
Rafael EspĂndola
rafael.espindola at gmail.com
Fri Jul 12 14:02:50 PDT 2013
Fixed in r186198.
On 12 July 2013 16:55, David Dean <david_dean at apple.com> wrote:
> This commit is causing one of the bots to fail:
> http://lab.llvm.org:8013/builders/clang-x86_64-darwin11-nobootstrap-RAincremental/builds/4315
>
> /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin11-nobootstrap-RAincremental/llvm/tools/llvm-ar/llvm-ar.cpp:383:37: error: union member 'OldI' has a non-trivial constructor
> object::Archive::child_iterator OldI;
> ^
> /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin11-nobootstrap-RAincremental/llvm/include/llvm/Object/Archive.h:100:5: note: because type 'llvm::object::Archive::child_iterator' has a user-provided default constructor
> child_iterator() : child(Child(0, 0)) {}
> ^
> /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin11-nobootstrap-RAincremental/llvm/tools/llvm-ar/llvm-ar.cpp:384:46: error: union member 'NewI' has a non-trivial constructor
> std::vector<std::string>::const_iterator NewI;
> ^
> /usr/include/c++/4.2.1/bits/stl_iterator.h:650:7: note: because type '__gnu_cxx::__normal_iterator<const std::basic_string<char> *, std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > >' has a user-provided default constructor
> __normal_iterator() : _M_current(_Iterator()) { }
> ^
> /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin11-nobootstrap-RAincremental/llvm/tools/llvm-ar/llvm-ar.cpp:399:27: error: member initializer 'OldI' does not name a non-static data member or base class
> : IsNewMember(false), OldI(I) {
> ^~~~~~~
> /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin11-nobootstrap-RAincremental/llvm/tools/llvm-ar/llvm-ar.cpp:405:26: error: member initializer 'NewI' does not name a non-static data member or base class
> : IsNewMember(true), NewI(I) {
> ^~~~~~~
> /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin11-nobootstrap-RAincremental/llvm/tools/llvm-ar/llvm-ar.cpp:413:10: error: use of undeclared identifier 'OldI'
> return OldI;
> ^
> /Users/buildslave/zorg/buildbot/smooshlab/slave-0.8/build.clang-x86_64-darwin11-nobootstrap-RAincremental/llvm/tools/llvm-ar/llvm-ar.cpp:418:11: error: use of undeclared identifier 'NewI'
> return *NewI;
> ^
> 6 errors generated.
>
>
> On 12 Jul 2013, at 1:21 PM, Rafael Espindola <rafael.espindola at gmail.com> wrote:
>
>> Author: rafael
>> Date: Fri Jul 12 15:21:39 2013
>> New Revision: 186197
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=186197&view=rev
>> Log:
>> Change llvm-ar to use lib/Object.
>>
>> This fixes two bugs is lib/Object that the use in llvm-ar found:
>> * In OS X created archives, the name can be padded with nulls. Strip them.
>> * In the constructor, remember the first non special member and use that in
>> begin_children. This makes sure we skip all special members, not just the
>> first one.
>>
>> The change to llvm-ar itself consist of
>> * Using lib/Object for reading archives instead of ArchiveReader.cpp.
>> * Writing the modified archive directly, instead of creating an in memory
>> representation.
>>
>> The old Archive library was way more general than what is needed, as can
>> be seen by the diffstat of this patch.
>>
>> Having llvm-ar using lib/Object now opens the way for creating regular symbol
>> tables for both native objects and bitcode files so that we can use those
>> archives for LTO.
>>
>> Removed:
>> llvm/trunk/tools/llvm-ar/Archive.cpp
>> llvm/trunk/tools/llvm-ar/ArchiveInternals.h
>> llvm/trunk/tools/llvm-ar/ArchiveReader.cpp
>> llvm/trunk/tools/llvm-ar/ArchiveWriter.cpp
>> Modified:
>> llvm/trunk/include/llvm/Object/Archive.h
>> llvm/trunk/lib/Object/Archive.cpp
>> llvm/trunk/test/Object/archive-toc.test
>> llvm/trunk/test/Object/directory.ll
>> llvm/trunk/tools/llvm-ar/CMakeLists.txt
>> llvm/trunk/tools/llvm-ar/llvm-ar.cpp
>>
>> Modified: llvm/trunk/include/llvm/Object/Archive.h
>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Object/Archive.h?rev=186197&r1=186196&r2=186197&view=diff
>> ==============================================================================
>> --- llvm/trunk/include/llvm/Object/Archive.h (original)
>> +++ llvm/trunk/include/llvm/Object/Archive.h Fri Jul 12 15:21:39 2013
>> @@ -174,7 +174,7 @@ public:
>> return Format;
>> }
>>
>> - child_iterator begin_children(bool skip_internal = true) const;
>> + child_iterator begin_children(bool SkipInternal = true) const;
>> child_iterator end_children() const;
>>
>> symbol_iterator begin_symbols() const;
>> @@ -191,6 +191,7 @@ public:
>> private:
>> child_iterator SymbolTable;
>> child_iterator StringTable;
>> + child_iterator FirstRegular;
>> Kind Format;
>> };
>>
>>
>> Modified: llvm/trunk/lib/Object/Archive.cpp
>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Object/Archive.cpp?rev=186197&r1=186196&r2=186197&view=diff
>> ==============================================================================
>> --- llvm/trunk/lib/Object/Archive.cpp (original)
>> +++ llvm/trunk/lib/Object/Archive.cpp Fri Jul 12 15:21:39 2013
>> @@ -23,20 +23,6 @@ using namespace object;
>>
>> static const char *Magic = "!<arch>\n";
>>
>> -static bool isInternalMember(const ArchiveMemberHeader &amh) {
>> - static const char *const internals[] = {
>> - "/",
>> - "//"
>> - };
>> -
>> - StringRef name = amh.getName();
>> - for (std::size_t i = 0; i < sizeof(internals) / sizeof(*internals); ++i) {
>> - if (name == internals[i])
>> - return true;
>> - }
>> - return false;
>> -}
>> -
>> void Archive::anchor() { }
>>
>> StringRef ArchiveMemberHeader::getName() const {
>> @@ -93,16 +79,13 @@ unsigned ArchiveMemberHeader::getGID() c
>> return Ret;
>> }
>>
>> -static const ArchiveMemberHeader *toHeader(const char *base) {
>> - return reinterpret_cast<const ArchiveMemberHeader *>(base);
>> -}
>> -
>> Archive::Child::Child(const Archive *Parent, const char *Start)
>> : Parent(Parent) {
>> if (!Start)
>> return;
>>
>> - const ArchiveMemberHeader *Header = toHeader(Start);
>> + const ArchiveMemberHeader *Header =
>> + reinterpret_cast<const ArchiveMemberHeader *>(Start);
>> Data = StringRef(Start, sizeof(ArchiveMemberHeader) + Header->getSize());
>>
>> // Setup StartOfFile and PaddingBytes.
>> @@ -173,7 +156,8 @@ error_code Archive::Child::getName(Strin
>> uint64_t name_size;
>> if (name.substr(3).rtrim(" ").getAsInteger(10, name_size))
>> llvm_unreachable("Long name length is not an ingeter");
>> - Result = Data.substr(sizeof(ArchiveMemberHeader), name_size);
>> + Result = Data.substr(sizeof(ArchiveMemberHeader), name_size)
>> + .rtrim(StringRef("\0", 1));
>> return object_error::success;
>> }
>> // It's a simple name.
>> @@ -252,6 +236,8 @@ Archive::Archive(MemoryBuffer *source, e
>> if (Name == "__.SYMDEF") {
>> Format = K_BSD;
>> SymbolTable = i;
>> + ++i;
>> + FirstRegular = i;
>> ec = object_error::success;
>> return;
>> }
>> @@ -262,8 +248,11 @@ Archive::Archive(MemoryBuffer *source, e
>> ec = i->getName(Name);
>> if (ec)
>> return;
>> - if (Name == StringRef("__.SYMDEF SORTED\0\0\0", 20))
>> + if (Name == "__.SYMDEF SORTED") {
>> SymbolTable = i;
>> + ++i;
>> + }
>> + FirstRegular = i;
>> return;
>> }
>>
>> @@ -281,12 +270,15 @@ Archive::Archive(MemoryBuffer *source, e
>> if (Name == "//") {
>> Format = K_GNU;
>> StringTable = i;
>> + ++i;
>> + FirstRegular = i;
>> ec = object_error::success;
>> return;
>> }
>>
>> if (Name[0] != '/') {
>> Format = K_GNU;
>> + FirstRegular = i;
>> ec = object_error::success;
>> return;
>> }
>> @@ -301,26 +293,31 @@ Archive::Archive(MemoryBuffer *source, e
>>
>> ++i;
>> if (i == e) {
>> + FirstRegular = i;
>> ec = object_error::success;
>> return;
>> }
>>
>> Name = i->getRawName();
>>
>> - if (Name == "//")
>> + if (Name == "//") {
>> StringTable = i;
>> + ++i;
>> + }
>>
>> + FirstRegular = i;
>> ec = object_error::success;
>> }
>>
>> -Archive::child_iterator Archive::begin_children(bool skip_internal) const {
>> +Archive::child_iterator Archive::begin_children(bool SkipInternal) const {
>> if (Data->getBufferSize() == 8) // empty archive.
>> return end_children();
>> +
>> + if (SkipInternal)
>> + return FirstRegular;
>> +
>> const char *Loc = Data->getBufferStart() + strlen(Magic);
>> Child c(this, Loc);
>> - // Skip internals at the beginning of an archive.
>> - if (skip_internal && isInternalMember(*toHeader(Loc)))
>> - return c.getNext();
>> return c;
>> }
>>
>>
>> Modified: llvm/trunk/test/Object/archive-toc.test
>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/archive-toc.test?rev=186197&r1=186196&r2=186197&view=diff
>> ==============================================================================
>> --- llvm/trunk/test/Object/archive-toc.test (original)
>> +++ llvm/trunk/test/Object/archive-toc.test Fri Jul 12 15:21:39 2013
>> @@ -10,6 +10,7 @@ GNU-NEXT: rw-r--r-- 500/500 2280 Nov 1
>> Test reading an archive createdy by Mac OS X ar
>> RUN: env TZ=GMT llvm-ar tv %p/Inputs/MacOSX.a | FileCheck %s --check-prefix=OSX -strict-whitespace
>>
>> +OSX-NOT: __.SYMDEF
>> OSX: rw-r--r-- 501/501 8 Nov 19 02:57 2004 evenlen
>> OSX-NEXT: rw-r--r-- 501/501 8 Nov 19 02:57 2004 oddlen
>> OSX-NEXT: rw-r--r-- 502/502 1465 Feb 4 06:59 2010 very_long_bytecode_file_name.bc
>>
>> Modified: llvm/trunk/test/Object/directory.ll
>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/directory.ll?rev=186197&r1=186196&r2=186197&view=diff
>> ==============================================================================
>> --- llvm/trunk/test/Object/directory.ll (original)
>> +++ llvm/trunk/test/Object/directory.ll Fri Jul 12 15:21:39 2013
>> @@ -1,12 +1,13 @@
>> +;RUN: rm -f %T/test.a
>> ;RUN: not llvm-ar r %T/test.a . 2>&1 | FileCheck %s
>> -;CHECK: . Is a directory
>> +;CHECK: .: Is a directory
>>
>> ;RUN: rm -f %T/test.a
>> ;RUN: touch %T/a-very-long-file-name
>> ;RUN: llvm-ar r %T/test.a %s %T/a-very-long-file-name
>> ;RUN: llvm-ar r %T/test.a %T/a-very-long-file-name
>> -;RUN: llvm-ar t %T/test.a | sort | FileCheck -check-prefix=MEMBERS %s
>> +;RUN: llvm-ar t %T/test.a | FileCheck -check-prefix=MEMBERS %s
>> ;MEMBERS-NOT: /
>> -;MEMBERS: a-very-long-file-name
>> ;MEMBERS: directory.ll
>> +;MEMBERS: a-very-long-file-name
>> ;MEMBERS-NOT: a-very-long-file-name
>>
>> Removed: llvm/trunk/tools/llvm-ar/Archive.cpp
>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-ar/Archive.cpp?rev=186196&view=auto
>> ==============================================================================
>> --- llvm/trunk/tools/llvm-ar/Archive.cpp (original)
>> +++ llvm/trunk/tools/llvm-ar/Archive.cpp (removed)
>> @@ -1,171 +0,0 @@
>> -//===-- Archive.cpp - Generic LLVM archive functions ------------*- C++ -*-===//
>> -//
>> -// The LLVM Compiler Infrastructure
>> -//
>> -// This file is distributed under the University of Illinois Open Source
>> -// License. See LICENSE.TXT for details.
>> -//
>> -//===----------------------------------------------------------------------===//
>> -//
>> -// This file contains the implementation of the Archive and ArchiveMember
>> -// classes that is common to both reading and writing archives..
>> -//
>> -//===----------------------------------------------------------------------===//
>> -
>> -#include "Archive.h"
>> -#include "ArchiveInternals.h"
>> -#include "llvm/Bitcode/ReaderWriter.h"
>> -#include "llvm/IR/Module.h"
>> -#include "llvm/Support/FileSystem.h"
>> -#include "llvm/Support/MemoryBuffer.h"
>> -#include "llvm/Support/Process.h"
>> -#include "llvm/Support/system_error.h"
>> -#include <cstring>
>> -#include <memory>
>> -using namespace llvm;
>> -
>> -// getMemberSize - compute the actual physical size of the file member as seen
>> -// on disk. This isn't the size of member's payload. Use getSize() for that.
>> -unsigned
>> -ArchiveMember::getMemberSize() const {
>> - // Basically its the file size plus the header size
>> - unsigned result = Size + sizeof(ArchiveMemberHeader);
>> -
>> - // If it has a long filename, include the name length
>> - if (hasLongFilename())
>> - result += path.length() + 1;
>> -
>> - // If its now odd lengthed, include the padding byte
>> - if (result % 2 != 0 )
>> - result++;
>> -
>> - return result;
>> -}
>> -
>> -// This default constructor is only use by the ilist when it creates its
>> -// sentry node. We give it specific static values to make it stand out a bit.
>> -ArchiveMember::ArchiveMember()
>> - : parent(0), path("--invalid--"), flags(0), data(0)
>> -{
>> - User = sys::Process::GetCurrentUserId();
>> - Group = sys::Process::GetCurrentGroupId();
>> - Mode = 0777;
>> - Size = 0;
>> - ModTime = sys::TimeValue::now();
>> -}
>> -
>> -// This is the constructor that the Archive class uses when it is building or
>> -// reading an archive. It just defaults a few things and ensures the parent is
>> -// set for the iplist. The Archive class fills in the ArchiveMember's data.
>> -// This is required because correctly setting the data may depend on other
>> -// things in the Archive.
>> -ArchiveMember::ArchiveMember(Archive* PAR)
>> - : parent(PAR), path(), flags(0), data(0)
>> -{
>> -}
>> -
>> -// This method allows an ArchiveMember to be replaced with the data for a
>> -// different file, presumably as an update to the member. It also makes sure
>> -// the flags are reset correctly.
>> -bool ArchiveMember::replaceWith(StringRef newFile, std::string* ErrMsg) {
>> - bool Exists;
>> - if (sys::fs::exists(newFile.str(), Exists) || !Exists) {
>> - if (ErrMsg)
>> - *ErrMsg = "Can not replace an archive member with a non-existent file";
>> - return true;
>> - }
>> -
>> - data = 0;
>> - path = newFile.str();
>> -
>> - // SVR4 symbol tables have an empty name
>> - if (path == ARFILE_SVR4_SYMTAB_NAME)
>> - flags |= SVR4SymbolTableFlag;
>> - else
>> - flags &= ~SVR4SymbolTableFlag;
>> -
>> - // BSD4.4 symbol tables have a special name
>> - if (path == ARFILE_BSD4_SYMTAB_NAME)
>> - flags |= BSD4SymbolTableFlag;
>> - else
>> - flags &= ~BSD4SymbolTableFlag;
>> -
>> - // String table name
>> - if (path == ARFILE_STRTAB_NAME)
>> - flags |= StringTableFlag;
>> - else
>> - flags &= ~StringTableFlag;
>> -
>> - // If it has a slash or its over 15 chars then its a long filename format
>> - if (path.length() > 15)
>> - flags |= HasLongFilenameFlag;
>> - else
>> - flags &= ~HasLongFilenameFlag;
>> -
>> - // Get the signature and status info
>> - const char* signature = (const char*) data;
>> - SmallString<4> magic;
>> - if (!signature) {
>> - sys::fs::get_magic(path, magic.capacity(), magic);
>> - signature = magic.c_str();
>> -
>> - sys::fs::file_status Status;
>> - error_code EC = sys::fs::status(path, Status);
>> - if (EC)
>> - return true;
>> -
>> - User = Status.getUser();
>> - Group = Status.getGroup();
>> - Mode = Status.permissions();
>> - ModTime = Status.getLastModificationTime();
>> -
>> - // FIXME: On posix this is a second stat.
>> - EC = sys::fs::file_size(path, Size);
>> - if (EC)
>> - return true;
>> - }
>> -
>> - return false;
>> -}
>> -
>> -// Archive constructor - this is the only constructor that gets used for the
>> -// Archive class. Everything else (default,copy) is deprecated. This just
>> -// initializes and maps the file into memory, if requested.
>> -Archive::Archive(StringRef filename, LLVMContext &C)
>> - : archPath(filename), members(), mapfile(0), base(0), strtab(),
>> - firstFileOffset(0), modules(), Context(C) {}
>> -
>> -bool
>> -Archive::mapToMemory(std::string* ErrMsg) {
>> - OwningPtr<MemoryBuffer> File;
>> - if (error_code ec = MemoryBuffer::getFile(archPath.c_str(), File)) {
>> - if (ErrMsg)
>> - *ErrMsg = ec.message();
>> - return true;
>> - }
>> - mapfile = File.take();
>> - base = mapfile->getBufferStart();
>> - return false;
>> -}
>> -
>> -void Archive::cleanUpMemory() {
>> - // Shutdown the file mapping
>> - delete mapfile;
>> - mapfile = 0;
>> - base = 0;
>> -
>> - firstFileOffset = 0;
>> -
>> - // Delete any Modules and ArchiveMember's we've allocated as a result of
>> - // symbol table searches.
>> - for (ModuleMap::iterator I=modules.begin(), E=modules.end(); I != E; ++I ) {
>> - delete I->second.first;
>> - delete I->second.second;
>> - }
>> -}
>> -
>> -// Archive destructor - just clean up memory
>> -Archive::~Archive() {
>> - cleanUpMemory();
>> -}
>> -
>>
>> Removed: llvm/trunk/tools/llvm-ar/ArchiveInternals.h
>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-ar/ArchiveInternals.h?rev=186196&view=auto
>> ==============================================================================
>> --- llvm/trunk/tools/llvm-ar/ArchiveInternals.h (original)
>> +++ llvm/trunk/tools/llvm-ar/ArchiveInternals.h (removed)
>> @@ -1,75 +0,0 @@
>> -//===-- lib/Archive/ArchiveInternals.h -------------------------*- C++ -*-===//
>> -//
>> -// The LLVM Compiler Infrastructure
>> -//
>> -// This file is distributed under the University of Illinois Open Source
>> -// License. See LICENSE.TXT for details.
>> -//
>> -//===----------------------------------------------------------------------===//
>> -//
>> -// Internal implementation header for LLVM Archive files.
>> -//
>> -//===----------------------------------------------------------------------===//
>> -
>> -#ifndef TOOLS_LLVM_AR_ARCHIVEINTERNALS_H
>> -#define TOOLS_LLVM_AR_ARCHIVEINTERNALS_H
>> -
>> -#include "Archive.h"
>> -#include "llvm/ADT/StringExtras.h"
>> -#include "llvm/Support/TimeValue.h"
>> -#include <cstring>
>> -
>> -#define ARFILE_MAGIC "!<arch>\n" ///< magic string
>> -#define ARFILE_MAGIC_LEN (sizeof(ARFILE_MAGIC)-1) ///< length of magic string
>> -#define ARFILE_SVR4_SYMTAB_NAME "/ " ///< SVR4 symtab entry name
>> -#define ARFILE_BSD4_SYMTAB_NAME "__.SYMDEF SORTED" ///< BSD4 symtab entry name
>> -#define ARFILE_STRTAB_NAME "// " ///< Name of string table
>> -#define ARFILE_PAD "\n" ///< inter-file align padding
>> -#define ARFILE_MEMBER_MAGIC "`\n" ///< fmag field magic #
>> -
>> -namespace llvm {
>> -
>> - class LLVMContext;
>> -
>> - /// The ArchiveMemberHeader structure is used internally for bitcode
>> - /// archives.
>> - /// The header precedes each file member in the archive. This structure is
>> - /// defined using character arrays for direct and correct interpretation
>> - /// regardless of the endianess of the machine that produced it.
>> - /// @brief Archive File Member Header
>> - class ArchiveMemberHeader {
>> - /// @name Data
>> - /// @{
>> - public:
>> - char name[16]; ///< Name of the file member.
>> - char date[12]; ///< File date, decimal seconds since Epoch
>> - char uid[6]; ///< user id in ASCII decimal
>> - char gid[6]; ///< group id in ASCII decimal
>> - char mode[8]; ///< file mode in ASCII octal
>> - char size[10]; ///< file size in ASCII decimal
>> - char fmag[2]; ///< Always contains ARFILE_MAGIC_TERMINATOR
>> -
>> - /// @}
>> - /// @name Methods
>> - /// @{
>> - public:
>> - void init() {
>> - memset(name,' ',16);
>> - memset(date,' ',12);
>> - memset(uid,' ',6);
>> - memset(gid,' ',6);
>> - memset(mode,' ',8);
>> - memset(size,' ',10);
>> - fmag[0] = '`';
>> - fmag[1] = '\n';
>> - }
>> -
>> - bool checkSignature() const {
>> - return 0 == memcmp(fmag, ARFILE_MEMBER_MAGIC,2);
>> - }
>> - };
>> -}
>> -
>> -#endif
>> -
>> -// vim: sw=2 ai
>>
>> Removed: llvm/trunk/tools/llvm-ar/ArchiveReader.cpp
>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-ar/ArchiveReader.cpp?rev=186196&view=auto
>> ==============================================================================
>> --- llvm/trunk/tools/llvm-ar/ArchiveReader.cpp (original)
>> +++ llvm/trunk/tools/llvm-ar/ArchiveReader.cpp (removed)
>> @@ -1,317 +0,0 @@
>> -//===-- ArchiveReader.cpp - Read LLVM archive files -------------*- C++ -*-===//
>> -//
>> -// The LLVM Compiler Infrastructure
>> -//
>> -// This file is distributed under the University of Illinois Open Source
>> -// License. See LICENSE.TXT for details.
>> -//
>> -//===----------------------------------------------------------------------===//
>> -//
>> -// Builds up standard unix archive files (.a) containing LLVM bitcode.
>> -//
>> -//===----------------------------------------------------------------------===//
>> -
>> -#include "Archive.h"
>> -#include "ArchiveInternals.h"
>> -#include "llvm/ADT/OwningPtr.h"
>> -#include "llvm/ADT/SmallPtrSet.h"
>> -#include "llvm/Bitcode/ReaderWriter.h"
>> -#include "llvm/IR/Module.h"
>> -#include "llvm/Support/FileSystem.h"
>> -#include "llvm/Support/MemoryBuffer.h"
>> -#include <cstdio>
>> -#include <cstdlib>
>> -using namespace llvm;
>> -
>> -/// Read a variable-bit-rate encoded unsigned integer
>> -static inline unsigned readInteger(const char*&At, const char*End) {
>> - unsigned Shift = 0;
>> - unsigned Result = 0;
>> -
>> - do {
>> - if (At == End)
>> - return Result;
>> - Result |= (unsigned)((*At++) & 0x7F) << Shift;
>> - Shift += 7;
>> - } while (At[-1] & 0x80);
>> - return Result;
>> -}
>> -
>> -// This member parses an ArchiveMemberHeader that is presumed to be pointed to
>> -// by At. The At pointer is updated to the byte just after the header, which
>> -// can be variable in size.
>> -ArchiveMember*
>> -Archive::parseMemberHeader(const char*& At, const char* End, std::string* error)
>> -{
>> - if (At + sizeof(ArchiveMemberHeader) >= End) {
>> - if (error)
>> - *error = "Unexpected end of file";
>> - return 0;
>> - }
>> -
>> - // Cast archive member header
>> - const ArchiveMemberHeader* Hdr = (const ArchiveMemberHeader*)At;
>> - At += sizeof(ArchiveMemberHeader);
>> -
>> - int flags = 0;
>> - int MemberSize = atoi(Hdr->size);
>> - assert(MemberSize >= 0);
>> -
>> - // Check the size of the member for sanity
>> - if (At + MemberSize > End) {
>> - if (error)
>> - *error = "invalid member length in archive file";
>> - return 0;
>> - }
>> -
>> - // Check the member signature
>> - if (!Hdr->checkSignature()) {
>> - if (error)
>> - *error = "invalid file member signature";
>> - return 0;
>> - }
>> -
>> - // Convert and check the member name
>> - // The empty name ( '/' and 15 blanks) is for a foreign (non-LLVM) symbol
>> - // table. The special name "//" and 14 blanks is for a string table, used
>> - // for long file names. This library doesn't generate either of those but
>> - // it will accept them. If the name starts with #1/ and the remainder is
>> - // digits, then those digits specify the length of the name that is
>> - // stored immediately following the header. Anything else is a regular, short
>> - // filename that is terminated with a '/' and blanks.
>> -
>> - std::string pathname;
>> - switch (Hdr->name[0]) {
>> - case '#':
>> - if (Hdr->name[1] == '1' && Hdr->name[2] == '/') {
>> - if (isdigit(Hdr->name[3])) {
>> - unsigned len = atoi(&Hdr->name[3]);
>> - const char *nulp = (const char *)memchr(At, '\0', len);
>> - pathname.assign(At, nulp != 0 ? (uintptr_t)(nulp - At) : len);
>> - At += len;
>> - MemberSize -= len;
>> - flags |= ArchiveMember::HasLongFilenameFlag;
>> - } else {
>> - if (error)
>> - *error = "invalid long filename";
>> - return 0;
>> - }
>> - }
>> - break;
>> - case '/':
>> - if (Hdr->name[1]== '/') {
>> - if (0 == memcmp(Hdr->name, ARFILE_STRTAB_NAME, 16)) {
>> - pathname.assign(ARFILE_STRTAB_NAME);
>> - flags |= ArchiveMember::StringTableFlag;
>> - } else {
>> - if (error)
>> - *error = "invalid string table name";
>> - return 0;
>> - }
>> - } else if (Hdr->name[1] == ' ') {
>> - if (0 == memcmp(Hdr->name, ARFILE_SVR4_SYMTAB_NAME, 16)) {
>> - pathname.assign(ARFILE_SVR4_SYMTAB_NAME);
>> - flags |= ArchiveMember::SVR4SymbolTableFlag;
>> - } else {
>> - if (error)
>> - *error = "invalid SVR4 symbol table name";
>> - return 0;
>> - }
>> - } else if (isdigit(Hdr->name[1])) {
>> - unsigned index = atoi(&Hdr->name[1]);
>> - if (index < strtab.length()) {
>> - const char* namep = strtab.c_str() + index;
>> - const char* endp = strtab.c_str() + strtab.length();
>> - const char* p = namep;
>> - const char* last_p = p;
>> - while (p < endp) {
>> - if (*p == '\n' && *last_p == '/') {
>> - pathname.assign(namep, last_p - namep);
>> - flags |= ArchiveMember::HasLongFilenameFlag;
>> - break;
>> - }
>> - last_p = p;
>> - p++;
>> - }
>> - if (p >= endp) {
>> - if (error)
>> - *error = "missing name terminator in string table";
>> - return 0;
>> - }
>> - } else {
>> - if (error)
>> - *error = "name index beyond string table";
>> - return 0;
>> - }
>> - }
>> - break;
>> - case '_':
>> - if (Hdr->name[1] == '_' &&
>> - (0 == memcmp(Hdr->name, ARFILE_BSD4_SYMTAB_NAME, 16))) {
>> - pathname.assign(ARFILE_BSD4_SYMTAB_NAME);
>> - flags |= ArchiveMember::BSD4SymbolTableFlag;
>> - break;
>> - }
>> - /* FALL THROUGH */
>> -
>> - default:
>> - const char* slash = (const char*) memchr(Hdr->name, '/', 16);
>> - if (slash == 0)
>> - slash = Hdr->name + 16;
>> - pathname.assign(Hdr->name, slash - Hdr->name);
>> - break;
>> - }
>> -
>> - // Instantiate the ArchiveMember to be filled
>> - ArchiveMember* member = new ArchiveMember(this);
>> -
>> - // Fill in fields of the ArchiveMember
>> - member->parent = this;
>> - member->path = pathname;
>> - member->Size = MemberSize;
>> - member->ModTime.fromEpochTime(atoi(Hdr->date));
>> - unsigned int mode;
>> - sscanf(Hdr->mode, "%o", &mode);
>> - member->Mode = mode;
>> - member->User = atoi(Hdr->uid);
>> - member->Group = atoi(Hdr->gid);
>> - member->flags = flags;
>> - member->data = At;
>> -
>> - return member;
>> -}
>> -
>> -bool
>> -Archive::checkSignature(std::string* error) {
>> - // Check the magic string at file's header
>> - if (mapfile->getBufferSize() < 8 || memcmp(base, ARFILE_MAGIC, 8)) {
>> - if (error)
>> - *error = "invalid signature for an archive file";
>> - return false;
>> - }
>> - return true;
>> -}
>> -
>> -// This function loads the entire archive and fully populates its ilist with
>> -// the members of the archive file. This is typically used in preparation for
>> -// editing the contents of the archive.
>> -bool
>> -Archive::loadArchive(std::string* error) {
>> -
>> - // Set up parsing
>> - members.clear();
>> - const char *At = base;
>> - const char *End = mapfile->getBufferEnd();
>> -
>> - if (!checkSignature(error))
>> - return false;
>> -
>> - At += 8; // Skip the magic string.
>> -
>> - bool foundFirstFile = false;
>> - while (At < End) {
>> - // parse the member header
>> - const char* Save = At;
>> - OwningPtr<ArchiveMember> mbr(parseMemberHeader(At, End, error));
>> - if (!mbr)
>> - return false;
>> -
>> - // check if this is the foreign symbol table
>> - if (mbr->isSVR4SymbolTable() || mbr->isBSD4SymbolTable()) {
>> - At += mbr->getSize();
>> - if ((intptr_t(At) & 1) == 1)
>> - At++;
>> - } else if (mbr->isStringTable()) {
>> - // Simply suck the entire string table into a string
>> - // variable. This will be used to get the names of the
>> - // members that use the "/ddd" format for their names
>> - // (SVR4 style long names).
>> - strtab.assign(At, mbr->getSize());
>> - At += mbr->getSize();
>> - if ((intptr_t(At) & 1) == 1)
>> - At++;
>> - } else {
>> - // This is just a regular file. If its the first one, save its offset.
>> - // Otherwise just push it on the list and move on to the next file.
>> - if (!foundFirstFile) {
>> - firstFileOffset = Save - base;
>> - foundFirstFile = true;
>> - }
>> - At += mbr->getSize();
>> - members.push_back(mbr.take());
>> - if ((intptr_t(At) & 1) == 1)
>> - At++;
>> - }
>> - }
>> - return true;
>> -}
>> -
>> -// Open and completely load the archive file.
>> -Archive*
>> -Archive::OpenAndLoad(StringRef File, LLVMContext& C,
>> - std::string* ErrorMessage) {
>> - OwningPtr<Archive> result(new Archive(File, C));
>> - if (result->mapToMemory(ErrorMessage))
>> - return NULL;
>> - if (!result->loadArchive(ErrorMessage))
>> - return NULL;
>> - return result.take();
>> -}
>> -
>> -// Load just the symbol table from the archive file
>> -bool
>> -Archive::loadSymbolTable(std::string* ErrorMsg) {
>> -
>> - // Set up parsing
>> - members.clear();
>> - const char *At = base;
>> - const char *End = mapfile->getBufferEnd();
>> -
>> - // Make sure we're dealing with an archive
>> - if (!checkSignature(ErrorMsg))
>> - return false;
>> -
>> - At += 8; // Skip signature
>> -
>> - // Parse the first file member header
>> - const char* FirstFile = At;
>> - OwningPtr<ArchiveMember> mbr(parseMemberHeader(At, End, ErrorMsg));
>> - if (!mbr)
>> - return false;
>> -
>> - if (mbr->isSVR4SymbolTable() || mbr->isBSD4SymbolTable()) {
>> - // Skip the foreign symbol table, we don't do anything with it
>> - At += mbr->getSize();
>> - if ((intptr_t(At) & 1) == 1)
>> - At++;
>> -
>> - // Read the next one
>> - FirstFile = At;
>> - mbr.reset(parseMemberHeader(At, End, ErrorMsg));
>> - if (!mbr)
>> - return false;
>> - }
>> -
>> - if (mbr->isStringTable()) {
>> - // Process the string table entry
>> - strtab.assign((const char*)mbr->getData(), mbr->getSize());
>> - At += mbr->getSize();
>> - if ((intptr_t(At) & 1) == 1)
>> - At++;
>> -
>> - // Get the next one
>> - FirstFile = At;
>> - mbr.reset(parseMemberHeader(At, End, ErrorMsg));
>> - if (!mbr)
>> - return false;
>> - }
>> -
>> - // There's no symbol table in the file. We have to rebuild it from scratch
>> - // because the intent of this method is to get the symbol table loaded so
>> - // it can be searched efficiently.
>> - // Add the member to the members list
>> - members.push_back(mbr.take());
>> -
>> - firstFileOffset = FirstFile - base;
>> - return true;
>> -}
>>
>> Removed: llvm/trunk/tools/llvm-ar/ArchiveWriter.cpp
>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-ar/ArchiveWriter.cpp?rev=186196&view=auto
>> ==============================================================================
>> --- llvm/trunk/tools/llvm-ar/ArchiveWriter.cpp (original)
>> +++ llvm/trunk/tools/llvm-ar/ArchiveWriter.cpp (removed)
>> @@ -1,288 +0,0 @@
>> -//===-- ArchiveWriter.cpp - Write LLVM archive files ----------------------===//
>> -//
>> -// The LLVM Compiler Infrastructure
>> -//
>> -// This file is distributed under the University of Illinois Open Source
>> -// License. See LICENSE.TXT for details.
>> -//
>> -//===----------------------------------------------------------------------===//
>> -//
>> -// Builds up an LLVM archive file (.a) containing LLVM bitcode.
>> -//
>> -//===----------------------------------------------------------------------===//
>> -
>> -#include "Archive.h"
>> -#include "ArchiveInternals.h"
>> -#include "llvm/ADT/OwningPtr.h"
>> -#include "llvm/Bitcode/ReaderWriter.h"
>> -#include "llvm/IR/Module.h"
>> -#include "llvm/Support/FileSystem.h"
>> -#include "llvm/Support/MemoryBuffer.h"
>> -#include "llvm/Support/Process.h"
>> -#include "llvm/Support/Signals.h"
>> -#include "llvm/Support/system_error.h"
>> -#include <fstream>
>> -#include <iomanip>
>> -#include <ostream>
>> -using namespace llvm;
>> -
>> -// Write an integer using variable bit rate encoding. This saves a few bytes
>> -// per entry in the symbol table.
>> -static inline void writeInteger(unsigned num, std::ofstream& ARFile) {
>> - while (1) {
>> - if (num < 0x80) { // done?
>> - ARFile << (unsigned char)num;
>> - return;
>> - }
>> -
>> - // Nope, we are bigger than a character, output the next 7 bits and set the
>> - // high bit to say that there is more coming...
>> - ARFile << (unsigned char)(0x80 | ((unsigned char)num & 0x7F));
>> - num >>= 7; // Shift out 7 bits now...
>> - }
>> -}
>> -
>> -// Compute how many bytes are taken by a given VBR encoded value. This is needed
>> -// to pre-compute the size of the symbol table.
>> -static inline unsigned numVbrBytes(unsigned num) {
>> -
>> - // Note that the following nested ifs are somewhat equivalent to a binary
>> - // search. We split it in half by comparing against 2^14 first. This allows
>> - // most reasonable values to be done in 2 comparisons instead of 1 for
>> - // small ones and four for large ones. We expect this to access file offsets
>> - // in the 2^10 to 2^24 range and symbol lengths in the 2^0 to 2^8 range,
>> - // so this approach is reasonable.
>> - if (num < 1<<14) {
>> - if (num < 1<<7)
>> - return 1;
>> - else
>> - return 2;
>> - }
>> - if (num < 1<<21)
>> - return 3;
>> -
>> - if (num < 1<<28)
>> - return 4;
>> - return 5; // anything >= 2^28 takes 5 bytes
>> -}
>> -
>> -// Create an empty archive.
>> -Archive* Archive::CreateEmpty(StringRef FilePath, LLVMContext& C) {
>> - Archive* result = new Archive(FilePath, C);
>> - return result;
>> -}
>> -
>> -// Fill the ArchiveMemberHeader with the information from a member. If
>> -// TruncateNames is true, names are flattened to 15 chars or less. The sz field
>> -// is provided here instead of coming from the mbr because the member might be
>> -// stored compressed and the compressed size is not the ArchiveMember's size.
>> -// Furthermore compressed files have negative size fields to identify them as
>> -// compressed.
>> -bool
>> -Archive::fillHeader(const ArchiveMember &mbr, ArchiveMemberHeader& hdr,
>> - int sz) const {
>> -
>> - // Set the permissions mode, uid and gid
>> - hdr.init();
>> - char buffer[32];
>> - sprintf(buffer, "%-8o", mbr.getMode());
>> - memcpy(hdr.mode,buffer,8);
>> - sprintf(buffer, "%-6u", mbr.getUser());
>> - memcpy(hdr.uid,buffer,6);
>> - sprintf(buffer, "%-6u", mbr.getGroup());
>> - memcpy(hdr.gid,buffer,6);
>> -
>> - // Set the last modification date
>> - uint64_t secondsSinceEpoch = mbr.getModTime().toEpochTime();
>> - sprintf(buffer,"%-12u", unsigned(secondsSinceEpoch));
>> - memcpy(hdr.date,buffer,12);
>> -
>> - std::string mbrPath = sys::path::filename(mbr.getPath());
>> -
>> - // Set the name field in one of its various flavors.
>> - bool writeLongName = false;
>> - if (mbr.isStringTable()) {
>> - memcpy(hdr.name,ARFILE_STRTAB_NAME,16);
>> - } else if (mbr.isSVR4SymbolTable()) {
>> - memcpy(hdr.name,ARFILE_SVR4_SYMTAB_NAME,16);
>> - } else if (mbr.isBSD4SymbolTable()) {
>> - memcpy(hdr.name,ARFILE_BSD4_SYMTAB_NAME,16);
>> - } else if (mbrPath.length() < 16 && mbrPath.find('/') == std::string::npos) {
>> - memcpy(hdr.name,mbrPath.c_str(),mbrPath.length());
>> - hdr.name[mbrPath.length()] = '/';
>> - } else {
>> - std::string nm = "#1/";
>> - nm += utostr(mbrPath.length());
>> - memcpy(hdr.name,nm.data(),nm.length());
>> - if (sz < 0)
>> - sz -= mbrPath.length();
>> - else
>> - sz += mbrPath.length();
>> - writeLongName = true;
>> - }
>> -
>> - // Set the size field
>> - if (sz < 0) {
>> - buffer[0] = '-';
>> - sprintf(&buffer[1],"%-9u",(unsigned)-sz);
>> - } else {
>> - sprintf(buffer, "%-10u", (unsigned)sz);
>> - }
>> - memcpy(hdr.size,buffer,10);
>> -
>> - return writeLongName;
>> -}
>> -
>> -// Insert a file into the archive before some other member. This also takes care
>> -// of extracting the necessary flags and information from the file.
>> -bool Archive::addFileBefore(StringRef filePath, iterator where,
>> - std::string *ErrMsg) {
>> - if (!sys::fs::exists(filePath)) {
>> - if (ErrMsg)
>> - *ErrMsg = "Can not add a non-existent file to archive";
>> - return true;
>> - }
>> -
>> - ArchiveMember* mbr = new ArchiveMember(this);
>> -
>> - mbr->data = 0;
>> - mbr->path = filePath;
>> - sys::fs::file_status Status;
>> - error_code EC = sys::fs::status(filePath, Status);
>> - if (EC) {
>> - delete mbr;
>> - return true;
>> - }
>> - mbr->User = Status.getUser();
>> - mbr->Group = Status.getGroup();
>> - mbr->Mode = Status.permissions();
>> - mbr->ModTime = Status.getLastModificationTime();
>> - // FIXME: On posix this is a second stat.
>> - EC = sys::fs::file_size(filePath, mbr->Size);
>> - if (EC) {
>> - delete mbr;
>> - return true;
>> - }
>> -
>> - unsigned flags = 0;
>> - if (sys::path::filename(filePath).size() > 15)
>> - flags |= ArchiveMember::HasLongFilenameFlag;
>> -
>> - sys::fs::file_magic type;
>> - if (sys::fs::identify_magic(mbr->path, type))
>> - type = sys::fs::file_magic::unknown;
>> - mbr->flags = flags;
>> - members.insert(where,mbr);
>> - return false;
>> -}
>> -
>> -// Write one member out to the file.
>> -bool
>> -Archive::writeMember(
>> - const ArchiveMember& member,
>> - raw_fd_ostream& ARFile,
>> - std::string* ErrMsg
>> -) {
>> -
>> - uint64_t filepos = ARFile.tell();
>> - filepos -= 8;
>> -
>> - // Get the data and its size either from the
>> - // member's in-memory data or directly from the file.
>> - size_t fSize = member.getSize();
>> - const char *data = (const char*)member.getData();
>> - MemoryBuffer *mFile = 0;
>> - if (!data) {
>> - OwningPtr<MemoryBuffer> File;
>> - if (error_code ec = MemoryBuffer::getFile(member.getPath(), File)) {
>> - if (ErrMsg)
>> - *ErrMsg = ec.message();
>> - return true;
>> - }
>> - mFile = File.take();
>> - data = mFile->getBufferStart();
>> - fSize = mFile->getBufferSize();
>> - }
>> -
>> - int hdrSize = fSize;
>> -
>> - // Compute the fields of the header
>> - ArchiveMemberHeader Hdr;
>> - bool writeLongName = fillHeader(member,Hdr,hdrSize);
>> -
>> - // Write header to archive file
>> - ARFile.write((char*)&Hdr, sizeof(Hdr));
>> -
>> - // Write the long filename if its long
>> - if (writeLongName) {
>> - StringRef Name = sys::path::filename(member.getPath());
>> - ARFile.write(Name.data(), Name.size());
>> - }
>> -
>> - // Write the (possibly compressed) member's content to the file.
>> - ARFile.write(data,fSize);
>> -
>> - // Make sure the member is an even length
>> - if ((ARFile.tell() & 1) == 1)
>> - ARFile << ARFILE_PAD;
>> -
>> - // Close the mapped file if it was opened
>> - delete mFile;
>> - return false;
>> -}
>> -
>> -// Write the entire archive to the file specified when the archive was created.
>> -// This writes to a temporary file first. Options are for creating a symbol
>> -// table, flattening the file names (no directories, 15 chars max) and
>> -// compressing each archive member.
>> -bool Archive::writeToDisk(std::string *ErrMsg) {
>> - // Make sure they haven't opened up the file, not loaded it,
>> - // but are now trying to write it which would wipe out the file.
>> - if (members.empty() && mapfile && mapfile->getBufferSize() > 8) {
>> - if (ErrMsg)
>> - *ErrMsg = "Can't write an archive not opened for writing";
>> - return true;
>> - }
>> -
>> - // Create a temporary file to store the archive in
>> - int TmpArchiveFD;
>> - SmallString<128> TmpArchive;
>> - error_code EC = sys::fs::createUniqueFile(
>> - archPath + ".temp-archive-%%%%%%%.a", TmpArchiveFD, TmpArchive);
>> - if (EC)
>> - return true;
>> -
>> - // Make sure the temporary gets removed if we crash
>> - sys::RemoveFileOnSignal(TmpArchive);
>> -
>> - // Create archive file for output.
>> - raw_fd_ostream ArchiveFile(TmpArchiveFD, true);
>> -
>> - // Write magic string to archive.
>> - ArchiveFile << ARFILE_MAGIC;
>> -
>> - // Loop over all member files, and write them out. Note that this also
>> - // builds the symbol table, symTab.
>> - for (MembersList::iterator I = begin(), E = end(); I != E; ++I) {
>> - if (writeMember(*I, ArchiveFile, ErrMsg)) {
>> - sys::fs::remove(Twine(TmpArchive));
>> - ArchiveFile.close();
>> - return true;
>> - }
>> - }
>> -
>> - // Close archive file.
>> - ArchiveFile.close();
>> -
>> - // Before we replace the actual archive, we need to forget all the
>> - // members, since they point to data in that old archive. We need to do
>> - // this because we cannot replace an open file on Windows.
>> - cleanUpMemory();
>> -
>> - if (sys::fs::rename(Twine(TmpArchive), archPath)) {
>> - *ErrMsg = EC.message();
>> - return true;
>> - }
>> -
>> - return false;
>> -}
>>
>> Modified: llvm/trunk/tools/llvm-ar/CMakeLists.txt
>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-ar/CMakeLists.txt?rev=186197&r1=186196&r2=186197&view=diff
>> ==============================================================================
>> --- llvm/trunk/tools/llvm-ar/CMakeLists.txt (original)
>> +++ llvm/trunk/tools/llvm-ar/CMakeLists.txt Fri Jul 12 15:21:39 2013
>> @@ -1,10 +1,7 @@
>> -set(LLVM_LINK_COMPONENTS support bitreader)
>> +set(LLVM_LINK_COMPONENTS support object bitreader)
>>
>> add_llvm_tool(llvm-ar
>> llvm-ar.cpp
>> - ArchiveWriter.cpp
>> - ArchiveReader.cpp
>> - Archive.cpp
>> )
>>
>> # TODO: Support check-local.
>>
>> Modified: llvm/trunk/tools/llvm-ar/llvm-ar.cpp
>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-ar/llvm-ar.cpp?rev=186197&r1=186196&r2=186197&view=diff
>> ==============================================================================
>> --- llvm/trunk/tools/llvm-ar/llvm-ar.cpp (original)
>> +++ llvm/trunk/tools/llvm-ar/llvm-ar.cpp Fri Jul 12 15:21:39 2013
>> @@ -12,15 +12,17 @@
>> //
>> //===----------------------------------------------------------------------===//
>>
>> -#include "Archive.h"
>> #include "llvm/IR/LLVMContext.h"
>> #include "llvm/IR/Module.h"
>> +#include "llvm/Object/Archive.h"
>> #include "llvm/Support/CommandLine.h"
>> #include "llvm/Support/FileSystem.h"
>> #include "llvm/Support/Format.h"
>> #include "llvm/Support/ManagedStatic.h"
>> +#include "llvm/Support/MemoryBuffer.h"
>> #include "llvm/Support/PrettyStackTrace.h"
>> #include "llvm/Support/Signals.h"
>> +#include "llvm/Support/ToolOutputFile.h"
>> #include "llvm/Support/raw_ostream.h"
>> #include <algorithm>
>> #include <cstdlib>
>> @@ -35,6 +37,29 @@
>>
>> using namespace llvm;
>>
>> +// The name this program was invoked as.
>> +static StringRef ToolName;
>> +
>> +static const char *TemporaryOutput;
>> +
>> +// fail - Show the error message and exit.
>> +LLVM_ATTRIBUTE_NORETURN static void fail(Twine Error) {
>> + outs() << ToolName << ": " << Error << ".\n";
>> + if (TemporaryOutput)
>> + sys::fs::remove(TemporaryOutput);
>> + exit(1);
>> +}
>> +
>> +static void failIfError(error_code EC, Twine Context = "") {
>> + if (!EC)
>> + return;
>> +
>> + std::string ContextStr = Context.str();
>> + if (ContextStr == "")
>> + fail(EC.message());
>> + fail(Context + ": " + EC.message());
>> +}
>> +
>> // Option for compatibility with AIX, not used but must allow it to be present.
>> static cl::opt<bool>
>> X32Option ("X32_64", cl::Hidden,
>> @@ -109,32 +134,11 @@ static std::string ArchiveName;
>> // on the command line.
>> static std::vector<std::string> Members;
>>
>> -// This variable holds the (possibly expanded) list of path objects that
>> -// correspond to files we will
>> -static std::set<std::string> Paths;
>> -
>> -// The Archive object to which all the editing operations will be sent.
>> -static Archive *TheArchive = 0;
>> -
>> -// The name this program was invoked as.
>> -static const char *program_name;
>> -
>> // show_help - Show the error message, the help message and exit.
>> LLVM_ATTRIBUTE_NORETURN static void
>> show_help(const std::string &msg) {
>> - errs() << program_name << ": " << msg << "\n\n";
>> + errs() << ToolName << ": " << msg << "\n\n";
>> cl::PrintHelpMessage();
>> - if (TheArchive)
>> - delete TheArchive;
>> - std::exit(1);
>> -}
>> -
>> -// fail - Show the error message and exit.
>> -LLVM_ATTRIBUTE_NORETURN static void
>> -fail(const std::string &msg) {
>> - errs() << program_name << ": " << msg << "\n\n";
>> - if (TheArchive)
>> - delete TheArchive;
>> std::exit(1);
>> }
>>
>> @@ -243,53 +247,14 @@ static ArchiveOperation parseCommandLine
>> return Operation;
>> }
>>
>> -// buildPaths - Convert the strings in the Members vector to sys::Path objects
>> -// and make sure they are valid and exist exist. This check is only needed for
>> -// the operations that add/replace files to the archive ('q' and 'r')
>> -static bool buildPaths(bool checkExistence, std::string *ErrMsg) {
>> - for (unsigned i = 0; i < Members.size(); i++) {
>> - std::string aPath = Members[i];
>> - if (checkExistence) {
>> - bool IsDirectory;
>> - error_code EC = sys::fs::is_directory(aPath, IsDirectory);
>> - if (EC)
>> - fail(aPath + ": " + EC.message());
>> - if (IsDirectory)
>> - fail(aPath + " Is a directory");
>> +// Implements the 'p' operation. This function traverses the archive
>> +// looking for members that match the path list.
>> +static void doPrint(StringRef Name, object::Archive::child_iterator I) {
>> + if (Verbose)
>> + outs() << "Printing " << Name << "\n";
>>
>> - Paths.insert(aPath);
>> - } else {
>> - Paths.insert(aPath);
>> - }
>> - }
>> - return false;
>> -}
>> -
>> -// doPrint - Implements the 'p' operation. This function traverses the archive
>> -// looking for members that match the path list. It is careful to uncompress
>> -// things that should be and to skip bitcode files unless the 'k' modifier was
>> -// given.
>> -static bool doPrint(std::string *ErrMsg) {
>> - if (buildPaths(false, ErrMsg))
>> - return true;
>> - for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end();
>> - I != E; ++I ) {
>> - if (Paths.empty() ||
>> - (std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end())) {
>> - const char *data = reinterpret_cast<const char *>(I->getData());
>> -
>> - // Skip things that don't make sense to print
>> - if (I->isSVR4SymbolTable() || I->isBSD4SymbolTable())
>> - continue;
>> -
>> - if (Verbose)
>> - outs() << "Printing " << I->getPath().str() << "\n";
>> -
>> - unsigned len = I->getSize();
>> - outs().write(data, len);
>> - }
>> - }
>> - return false;
>> + StringRef Data = I->getBuffer();
>> + outs().write(Data.data(), Data.size());
>> }
>>
>> // putMode - utility function for printing out the file mode when the 't'
>> @@ -309,291 +274,356 @@ static void printMode(unsigned mode) {
>> outs() << "-";
>> }
>>
>> -// doDisplayTable - Implement the 't' operation. This function prints out just
>> +// Implement the 't' operation. This function prints out just
>> // the file names of each of the members. However, if verbose mode is requested
>> // ('v' modifier) then the file type, permission mode, user, group, size, and
>> // modification time are also printed.
>> -static bool doDisplayTable(std::string *ErrMsg) {
>> - if (buildPaths(false, ErrMsg))
>> - return true;
>> - for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end();
>> - I != E; ++I ) {
>> - if (Paths.empty() ||
>> - (std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end())) {
>> - if (Verbose) {
>> - unsigned mode = I->getMode();
>> - printMode((mode >> 6) & 007);
>> - printMode((mode >> 3) & 007);
>> - printMode(mode & 007);
>> - outs() << ' ' << I->getUser();
>> - outs() << "/" << I->getGroup();
>> - outs() << ' ' << format("%6llu", I->getSize());
>> - sys::TimeValue ModTime = I->getModTime();
>> - outs() << " " << ModTime.str();
>> - outs() << " " << I->getPath().str() << "\n";
>> - } else {
>> - outs() << I->getPath().str() << "\n";
>> - }
>> - }
>> - }
>> - return false;
>> -}
>> -
>> -// doExtract - Implement the 'x' operation. This function extracts files back to
>> -// the file system.
>> -static bool doExtract(std::string *ErrMsg) {
>> - if (buildPaths(false, ErrMsg))
>> - return true;
>> - for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end();
>> - I != E; ++I ) {
>> - if (Paths.empty() ||
>> - (std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end())) {
>> -
>> - // Open up a file stream for writing
>> - int OpenFlags = O_TRUNC | O_WRONLY | O_CREAT;
>> +static void doDisplayTable(StringRef Name, object::Archive::child_iterator I) {
>> + if (Verbose) {
>> + sys::fs::perms Mode = I->getAccessMode();
>> + printMode((Mode >> 6) & 007);
>> + printMode((Mode >> 3) & 007);
>> + printMode(Mode & 007);
>> + outs() << ' ' << I->getUID();
>> + outs() << '/' << I->getGID();
>> + outs() << ' ' << format("%6llu", I->getSize());
>> + outs() << ' ' << I->getLastModified().str();
>> + outs() << ' ';
>> + }
>> + outs() << Name << "\n";
>> +}
>> +
>> +// Implement the 'x' operation. This function extracts files back to the file
>> +// system.
>> +static void doExtract(StringRef Name, object::Archive::child_iterator I) {
>> + // Open up a file stream for writing
>> + // FIXME: we should abstract this, O_BINARY in particular.
>> + int OpenFlags = O_TRUNC | O_WRONLY | O_CREAT;
>> #ifdef O_BINARY
>> - OpenFlags |= O_BINARY;
>> + OpenFlags |= O_BINARY;
>> #endif
>>
>> - // Retain the original mode.
>> - sys::fs::perms Mode = sys::fs::perms(I->getMode());
>> + // Retain the original mode.
>> + sys::fs::perms Mode = I->getAccessMode();
>>
>> - int FD = open(I->getPath().str().c_str(), OpenFlags, Mode);
>> - if (FD < 0)
>> - return true;
>> -
>> - {
>> - raw_fd_ostream file(FD, false);
>> -
>> - // Get the data and its length
>> - const char* data = reinterpret_cast<const char*>(I->getData());
>> - unsigned len = I->getSize();
>> + int FD = open(Name.str().c_str(), OpenFlags, Mode);
>> + if (FD < 0)
>> + fail("Could not open output file");
>>
>> - // Write the data.
>> - file.write(data, len);
>> - }
>> + {
>> + raw_fd_ostream file(FD, false);
>>
>> - // If we're supposed to retain the original modification times, etc. do so
>> - // now.
>> - if (OriginalDates) {
>> - error_code EC =
>> - sys::fs::setLastModificationAndAccessTime(FD, I->getModTime());
>> - if (EC)
>> - fail(EC.message());
>> - }
>> - if (close(FD))
>> - return true;
>> - }
>> + // Get the data and its length
>> + StringRef Data = I->getBuffer();
>> +
>> + // Write the data.
>> + file.write(Data.data(), Data.size());
>> }
>> - return false;
>> +
>> + // If we're supposed to retain the original modification times, etc. do so
>> + // now.
>> + if (OriginalDates)
>> + failIfError(
>> + sys::fs::setLastModificationAndAccessTime(FD, I->getLastModified()));
>> +
>> + if (close(FD))
>> + fail("Could not close the file");
>> }
>>
>> -// doDelete - Implement the delete operation. This function deletes zero or more
>> -// members from the archive. Note that if the count is specified, there should
>> -// be no more than one path in the Paths list or else this algorithm breaks.
>> -// That check is enforced in parseCommandLine (above).
>> -static bool doDelete(std::string *ErrMsg) {
>> - if (buildPaths(false, ErrMsg))
>> - return true;
>> - if (Paths.empty())
>> +static bool shouldCreateArchive(ArchiveOperation Op) {
>> + switch (Op) {
>> + case Print:
>> + case Delete:
>> + case Move:
>> + case DisplayTable:
>> + case Extract:
>> return false;
>> - for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end();
>> - I != E; ) {
>> - if (std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end()) {
>> - Archive::iterator J = I;
>> - ++I;
>> - TheArchive->erase(J);
>> - } else {
>> - ++I;
>> - }
>> - }
>>
>> - // We're done editting, reconstruct the archive.
>> - if (TheArchive->writeToDisk(ErrMsg))
>> + case QuickAppend:
>> + case ReplaceOrInsert:
>> return true;
>> - return false;
>> + }
>> +
>> + llvm_unreachable("Missing entry in covered switch.");
>> }
>>
>> -// doMore - Implement the move operation. This function re-arranges just the
>> -// order of the archive members so that when the archive is written the move
>> -// of the members is accomplished. Note the use of the RelPos variable to
>> -// determine where the items should be moved to.
>> -static bool doMove(std::string *ErrMsg) {
>> - if (buildPaths(false, ErrMsg))
>> - return true;
>> +static void performReadOperation(ArchiveOperation Operation,
>> + object::Archive *OldArchive) {
>> + for (object::Archive::child_iterator I = OldArchive->begin_children(),
>> + E = OldArchive->end_children();
>> + I != E; ++I) {
>> + StringRef Name;
>> + failIfError(I->getName(Name));
>> +
>> + if (!Members.empty() &&
>> + std::find(Members.begin(), Members.end(), Name) == Members.end())
>> + continue;
>>
>> - // By default and convention the place to move members to is the end of the
>> - // archive.
>> - Archive::iterator moveto_spot = TheArchive->end();
>> -
>> - // However, if the relative positioning modifiers were used, we need to scan
>> - // the archive to find the member in question. If we don't find it, its no
>> - // crime, we just move to the end.
>> - if (AddBefore || AddAfter) {
>> - for (Archive::iterator I = TheArchive->begin(), E= TheArchive->end();
>> - I != E; ++I ) {
>> - if (RelPos == I->getPath().str()) {
>> - if (AddAfter) {
>> - moveto_spot = I;
>> - moveto_spot++;
>> - } else {
>> - moveto_spot = I;
>> - }
>> - break;
>> - }
>> + switch (Operation) {
>> + default:
>> + llvm_unreachable("Not a read operation");
>> + case Print:
>> + doPrint(Name, I);
>> + break;
>> + case DisplayTable:
>> + doDisplayTable(Name, I);
>> + break;
>> + case Extract:
>> + doExtract(Name, I);
>> + break;
>> }
>> }
>> +}
>>
>> - // Keep a list of the paths remaining to be moved
>> - std::set<std::string> remaining(Paths);
>> -
>> - // Scan the archive again, this time looking for the members to move to the
>> - // moveto_spot.
>> - for (Archive::iterator I = TheArchive->begin(), E= TheArchive->end();
>> - I != E && !remaining.empty(); ++I ) {
>> - std::set<std::string>::iterator found =
>> - std::find(remaining.begin(),remaining.end(), I->getPath());
>> - if (found != remaining.end()) {
>> - if (I != moveto_spot)
>> - TheArchive->splice(moveto_spot,*TheArchive,I);
>> - remaining.erase(found);
>> - }
>> - }
>> +namespace {
>> +class NewArchiveIterator {
>> + bool IsNewMember;
>> + SmallString<16> MemberName;
>> + union {
>> + object::Archive::child_iterator OldI;
>> + std::vector<std::string>::const_iterator NewI;
>> + };
>> +
>> +public:
>> + NewArchiveIterator(object::Archive::child_iterator I, Twine Name);
>> + NewArchiveIterator(std::vector<std::string>::const_iterator I, Twine Name);
>> + bool isNewMember() const;
>> + object::Archive::child_iterator getOld() const;
>> + StringRef getNew() const;
>> + StringRef getMemberName() const { return MemberName; }
>> +};
>> +}
>>
>> - // We're done editting, reconstruct the archive.
>> - if (TheArchive->writeToDisk(ErrMsg))
>> - return true;
>> - return false;
>> +NewArchiveIterator::NewArchiveIterator(object::Archive::child_iterator I,
>> + Twine Name)
>> + : IsNewMember(false), OldI(I) {
>> + Name.toVector(MemberName);
>> }
>>
>> -// doQuickAppend - Implements the 'q' operation. This function just
>> -// indiscriminantly adds the members to the archive and rebuilds it.
>> -static bool doQuickAppend(std::string *ErrMsg) {
>> - // Get the list of paths to append.
>> - if (buildPaths(true, ErrMsg))
>> - return true;
>> - if (Paths.empty())
>> - return false;
>> +NewArchiveIterator::NewArchiveIterator(
>> + std::vector<std::string>::const_iterator I, Twine Name)
>> + : IsNewMember(true), NewI(I) {
>> + Name.toVector(MemberName);
>> +}
>>
>> - // Append them quickly.
>> - for (std::set<std::string>::iterator PI = Paths.begin(), PE = Paths.end();
>> - PI != PE; ++PI) {
>> - if (TheArchive->addFileBefore(*PI, TheArchive->end(), ErrMsg))
>> - return true;
>> - }
>> +bool NewArchiveIterator::isNewMember() const { return IsNewMember; }
>>
>> - // We're done editting, reconstruct the archive.
>> - if (TheArchive->writeToDisk(ErrMsg))
>> - return true;
>> - return false;
>> +object::Archive::child_iterator NewArchiveIterator::getOld() const {
>> + assert(!IsNewMember);
>> + return OldI;
>> }
>>
>> -// doReplaceOrInsert - Implements the 'r' operation. This function will replace
>> -// any existing files or insert new ones into the archive.
>> -static bool doReplaceOrInsert(std::string *ErrMsg) {
>> +StringRef NewArchiveIterator::getNew() const {
>> + assert(IsNewMember);
>> + return *NewI;
>> +}
>>
>> - // Build the list of files to be added/replaced.
>> - if (buildPaths(true, ErrMsg))
>> - return true;
>> - if (Paths.empty())
>> - return false;
>> +template <typename T>
>> +void addMember(std::vector<NewArchiveIterator> &Members,
>> + std::string &StringTable, T I, StringRef Name) {
>> + if (Name.size() < 15) {
>> + NewArchiveIterator NI(I, Twine(Name) + "/");
>> + Members.push_back(NI);
>> + } else {
>> + int MapIndex = StringTable.size();
>> + NewArchiveIterator NI(I, Twine("/") + Twine(MapIndex));
>> + Members.push_back(NI);
>> + StringTable += Name;
>> + StringTable += "/\n";
>> + }
>> +}
>>
>> - // Keep track of the paths that remain to be inserted.
>> - std::set<std::string> remaining(Paths);
>> +namespace {
>> +class HasName {
>> + StringRef Name;
>>
>> - // Default the insertion spot to the end of the archive
>> - Archive::iterator insert_spot = TheArchive->end();
>> +public:
>> + HasName(StringRef Name) : Name(Name) {}
>> + bool operator()(StringRef Path) { return Name == sys::path::filename(Path); }
>> +};
>> +}
>>
>> - // Iterate over the archive contents
>> - for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end();
>> - I != E && !remaining.empty(); ++I ) {
>> -
>> - // Determine if this archive member matches one of the paths we're trying
>> - // to replace.
>> -
>> - std::set<std::string>::iterator found = remaining.end();
>> - for (std::set<std::string>::iterator RI = remaining.begin(),
>> - RE = remaining.end(); RI != RE; ++RI ) {
>> - std::string compare(sys::path::filename(*RI));
>> - if (compare == I->getPath().str()) {
>> - found = RI;
>> - break;
>> +// We have to walk this twice and computing it is not trivial, so creating an
>> +// explicit std::vector is actually fairly efficient.
>> +static std::vector<NewArchiveIterator>
>> +computeNewArchiveMembers(ArchiveOperation Operation,
>> + object::Archive *OldArchive,
>> + std::string &StringTable) {
>> + std::vector<NewArchiveIterator> Ret;
>> + std::vector<NewArchiveIterator> Moved;
>> + int InsertPos = -1;
>> + StringRef PosName = sys::path::filename(RelPos);
>> + if (OldArchive) {
>> + int Pos = 0;
>> + for (object::Archive::child_iterator I = OldArchive->begin_children(),
>> + E = OldArchive->end_children();
>> + I != E; ++I, ++Pos) {
>> + StringRef Name;
>> + failIfError(I->getName(Name));
>> + if (Name == PosName) {
>> + assert(AddAfter || AddBefore);
>> + if (AddBefore)
>> + InsertPos = Pos;
>> + else
>> + InsertPos = Pos + 1;
>> + }
>> + if (Operation != QuickAppend && !Members.empty()) {
>> + std::vector<std::string>::iterator MI =
>> + std::find_if(Members.begin(), Members.end(), HasName(Name));
>> + if (MI != Members.end()) {
>> + if (Operation == Move) {
>> + addMember(Moved, StringTable, I, Name);
>> + continue;
>> + }
>> + if (Operation != ReplaceOrInsert || !OnlyUpdate)
>> + continue;
>> + // Ignore if the file if it is older than the member.
>> + sys::fs::file_status Status;
>> + failIfError(sys::fs::status(*MI, Status));
>> + if (Status.getLastModificationTime() < I->getLastModified())
>> + Members.erase(MI);
>> + else
>> + continue;
>> + }
>> }
>> + addMember(Ret, StringTable, I, Name);
>> }
>> + }
>>
>> - if (found != remaining.end()) {
>> + if (Operation == Delete)
>> + return Ret;
>> +
>> + if (Operation == Move) {
>> + if (RelPos.empty()) {
>> + Ret.insert(Ret.end(), Moved.begin(), Moved.end());
>> + return Ret;
>> + }
>> + if (InsertPos == -1)
>> + fail("Insertion point not found");
>> + assert(unsigned(InsertPos) <= Ret.size());
>> + Ret.insert(Ret.begin() + InsertPos, Moved.begin(), Moved.end());
>> + return Ret;
>> + }
>> +
>> + for (std::vector<std::string>::iterator I = Members.begin(),
>> + E = Members.end();
>> + I != E; ++I) {
>> + StringRef Name = sys::path::filename(*I);
>> + addMember(Ret, StringTable, I, Name);
>> + }
>> +
>> + return Ret;
>> +}
>> +
>> +template <typename T>
>> +static void printWithSpacePadding(raw_ostream &OS, T Data, unsigned Size) {
>> + uint64_t OldPos = OS.tell();
>> + OS << Data;
>> + unsigned SizeSoFar = OS.tell() - OldPos;
>> + assert(Size >= SizeSoFar && "Data doesn't fit in Size");
>> + unsigned Remaining = Size - SizeSoFar;
>> + for (unsigned I = 0; I < Remaining; ++I)
>> + OS << ' ';
>> +}
>> +
>> +static void performWriteOperation(ArchiveOperation Operation,
>> + object::Archive *OldArchive) {
>> + int TmpArchiveFD;
>> + SmallString<128> TmpArchive;
>> + failIfError(sys::fs::createUniqueFile(ArchiveName + ".temp-archive-%%%%%%%.a",
>> + TmpArchiveFD, TmpArchive));
>> +
>> + TemporaryOutput = TmpArchive.c_str();
>> + tool_output_file Output(TemporaryOutput, TmpArchiveFD);
>> + raw_fd_ostream &Out = Output.os();
>> + Out << "!<arch>\n";
>> +
>> + std::string StringTable;
>> + std::vector<NewArchiveIterator> NewMembers =
>> + computeNewArchiveMembers(Operation, OldArchive, StringTable);
>> + if (!StringTable.empty()) {
>> + if (StringTable.size() % 2)
>> + StringTable += '\n';
>> + printWithSpacePadding(Out, "//", 48);
>> + printWithSpacePadding(Out, StringTable.size(), 10);
>> + Out << "`\n";
>> + Out << StringTable;
>> + }
>> +
>> + for (std::vector<NewArchiveIterator>::iterator I = NewMembers.begin(),
>> + E = NewMembers.end();
>> + I != E; ++I) {
>> + StringRef Name = I->getMemberName();
>> + printWithSpacePadding(Out, Name, 16);
>> +
>> + if (I->isNewMember()) {
>> + // FIXME: we do a stat + open. We should do a open + fstat.
>> + StringRef FileName = I->getNew();
>> sys::fs::file_status Status;
>> - error_code EC = sys::fs::status(*found, Status);
>> - if (EC)
>> - return true;
>> - if (!sys::fs::is_directory(Status)) {
>> - if (OnlyUpdate) {
>> - // Replace the item only if it is newer.
>> - if (Status.getLastModificationTime() > I->getModTime())
>> - if (I->replaceWith(*found, ErrMsg))
>> - return true;
>> - } else {
>> - // Replace the item regardless of time stamp
>> - if (I->replaceWith(*found, ErrMsg))
>> - return true;
>> - }
>> - } else {
>> - // We purposefully ignore directories.
>> - }
>> + failIfError(sys::fs::status(FileName, Status), FileName);
>>
>> - // Remove it from our "to do" list
>> - remaining.erase(found);
>> - }
>> + uint64_t secondsSinceEpoch =
>> + Status.getLastModificationTime().toEpochTime();
>> + printWithSpacePadding(Out, secondsSinceEpoch, 12);
>> +
>> + printWithSpacePadding(Out, Status.getUser(), 6);
>> + printWithSpacePadding(Out, Status.getGroup(), 6);
>> + printWithSpacePadding(Out, format("%o", Status.permissions()), 8);
>> + printWithSpacePadding(Out, Status.getSize(), 10);
>> + Out << "`\n";
>> +
>> + OwningPtr<MemoryBuffer> File;
>> + failIfError(MemoryBuffer::getFile(FileName, File), FileName);
>> + Out << File->getBuffer();
>> + } else {
>> + object::Archive::child_iterator OldMember = I->getOld();
>>
>> - // Determine if this is the place where we should insert
>> - if (AddBefore && RelPos == I->getPath().str())
>> - insert_spot = I;
>> - else if (AddAfter && RelPos == I->getPath().str()) {
>> - insert_spot = I;
>> - insert_spot++;
>> - }
>> - }
>> + uint64_t secondsSinceEpoch = OldMember->getLastModified().toEpochTime();
>> + printWithSpacePadding(Out, secondsSinceEpoch, 12);
>>
>> - // If we didn't replace all the members, some will remain and need to be
>> - // inserted at the previously computed insert-spot.
>> - if (!remaining.empty()) {
>> - for (std::set<std::string>::iterator PI = remaining.begin(),
>> - PE = remaining.end(); PI != PE; ++PI) {
>> - if (TheArchive->addFileBefore(*PI, insert_spot, ErrMsg))
>> - return true;
>> + printWithSpacePadding(Out, OldMember->getUID(), 6);
>> + printWithSpacePadding(Out, OldMember->getGID(), 6);
>> + printWithSpacePadding(Out, format("%o", OldMember->getAccessMode()), 8);
>> + printWithSpacePadding(Out, OldMember->getSize(), 10);
>> + Out << "`\n";
>> +
>> + Out << OldMember->getBuffer();
>> }
>> - }
>>
>> - // We're done editting, reconstruct the archive.
>> - if (TheArchive->writeToDisk(ErrMsg))
>> - return true;
>> - return false;
>> + if (Out.tell() % 2)
>> + Out << '\n';
>> + }
>> + Output.keep();
>> + Out.close();
>> + sys::fs::rename(TemporaryOutput, ArchiveName);
>> + TemporaryOutput = NULL;
>> }
>>
>> -static bool shouldCreateArchive(ArchiveOperation Op) {
>> - switch (Op) {
>> +static void performOperation(ArchiveOperation Operation,
>> + object::Archive *OldArchive) {
>> + switch (Operation) {
>> case Print:
>> - case Delete:
>> - case Move:
>> case DisplayTable:
>> case Extract:
>> - return false;
>> + performReadOperation(Operation, OldArchive);
>> + return;
>>
>> + case Delete:
>> + case Move:
>> case QuickAppend:
>> case ReplaceOrInsert:
>> - return true;
>> + performWriteOperation(Operation, OldArchive);
>> + return;
>> }
>> -
>> - llvm_unreachable("Missing entry in covered switch.");
>> + llvm_unreachable("Unknown operation.");
>> }
>>
>> // main - main program for llvm-ar .. see comments in the code
>> int main(int argc, char **argv) {
>> - program_name = argv[0];
>> + ToolName = argv[0];
>> // Print a stack trace if we signal out.
>> sys::PrintStackTraceOnErrorSignal();
>> PrettyStackTraceProgram X(argc, argv);
>> - LLVMContext &Context = getGlobalContext();
>> llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
>>
>> // Have the command line options parsed and handle things
>> @@ -603,54 +633,42 @@ int main(int argc, char **argv) {
>> " This program archives bitcode files into single libraries\n"
>> );
>>
>> - int exitCode = 0;
>> -
>> // Do our own parsing of the command line because the CommandLine utility
>> // can't handle the grouped positional parameters without a dash.
>> ArchiveOperation Operation = parseCommandLine();
>>
>> // Create or open the archive object.
>> - if (shouldCreateArchive(Operation) && !llvm::sys::fs::exists(ArchiveName)) {
>> - // Produce a warning if we should and we're creating the archive
>> - if (!Create)
>> - errs() << argv[0] << ": creating " << ArchiveName << "\n";
>> - TheArchive = Archive::CreateEmpty(ArchiveName, Context);
>> - TheArchive->writeToDisk();
>> + OwningPtr<MemoryBuffer> Buf;
>> + error_code EC = MemoryBuffer::getFile(ArchiveName, Buf, -1, false);
>> + if (EC && EC != llvm::errc::no_such_file_or_directory) {
>> + errs() << argv[0] << ": error opening '" << ArchiveName
>> + << "': " << EC.message() << "!\n";
>> + return 1;
>> }
>>
>> - if (!TheArchive) {
>> - std::string Error;
>> - TheArchive = Archive::OpenAndLoad(ArchiveName, Context, &Error);
>> - if (TheArchive == 0) {
>> - errs() << argv[0] << ": error loading '" << ArchiveName << "': "
>> - << Error << "!\n";
>> + if (!EC) {
>> + object::Archive Archive(Buf.take(), EC);
>> +
>> + if (EC) {
>> + errs() << argv[0] << ": error loading '" << ArchiveName
>> + << "': " << EC.message() << "!\n";
>> return 1;
>> }
>> + performOperation(Operation, &Archive);
>> + return 0;
>> }
>>
>> - // Make sure we're not fooling ourselves.
>> - assert(TheArchive && "Unable to instantiate the archive");
>> + assert(EC == llvm::errc::no_such_file_or_directory);
>>
>> - // Perform the operation
>> - std::string ErrMsg;
>> - bool haveError = false;
>> - switch (Operation) {
>> - case Print: haveError = doPrint(&ErrMsg); break;
>> - case Delete: haveError = doDelete(&ErrMsg); break;
>> - case Move: haveError = doMove(&ErrMsg); break;
>> - case QuickAppend: haveError = doQuickAppend(&ErrMsg); break;
>> - case ReplaceOrInsert: haveError = doReplaceOrInsert(&ErrMsg); break;
>> - case DisplayTable: haveError = doDisplayTable(&ErrMsg); break;
>> - case Extract: haveError = doExtract(&ErrMsg); break;
>> - }
>> - if (haveError) {
>> - errs() << argv[0] << ": " << ErrMsg << "\n";
>> - return 1;
>> + if (!shouldCreateArchive(Operation)) {
>> + failIfError(EC, Twine("error loading '") + ArchiveName + "'");
>> + } else {
>> + if (!Create) {
>> + // Produce a warning if we should and we're creating the archive
>> + errs() << argv[0] << ": creating " << ArchiveName << "\n";
>> + }
>> }
>>
>> - delete TheArchive;
>> - TheArchive = 0;
>> -
>> - // Return result code back to operating system.
>> - return exitCode;
>> + performOperation(Operation, NULL);
>> + return 0;
>> }
>>
>>
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>
> -David
>
>
More information about the llvm-commits
mailing list