[llvm] r186197 - Change llvm-ar to use lib/Object.

Quentin Colombet qcolombet at apple.com
Fri Jul 12 14:17:02 PDT 2013


Apparently, that is not fixing the problem :(.
http://lab.llvm.org:8013/builders/clang-x86_64-darwin11-nobootstrap-RAincremental/builds/4317
llvm[2]: Linking Release+Asserts executable llvm-ar
Undefined symbols for architecture x86_64:
  "llvm::object::Binary::~Binary()", referenced from:
      _main in llvm-ar.o
  "llvm::object::Archive::Child::Child(llvm::object::Archive const*, char const*)", referenced from:
      __ZL16performOperation16ArchiveOperationPN4llvm6object7ArchiveE in llvm-ar.o
  "llvm::object::Archive::Archive(llvm::MemoryBuffer*, llvm::error_code&)", referenced from:
      _main in llvm-ar.o
  "llvm::object::ArchiveMemberHeader::getAccessMode() const", referenced from:
      __ZL16performOperation16ArchiveOperationPN4llvm6object7ArchiveE in llvm-ar.o
  "llvm::object::ArchiveMemberHeader::getLastModified() const", referenced from:
      __ZL16performOperation16ArchiveOperationPN4llvm6object7ArchiveE in llvm-ar.o
  "llvm::object::ArchiveMemberHeader::getGID() const", referenced from:
      __ZL16performOperation16ArchiveOperationPN4llvm6object7ArchiveE in llvm-ar.o
  "llvm::object::ArchiveMemberHeader::getUID() const", referenced from:
      __ZL16performOperation16ArchiveOperationPN4llvm6object7ArchiveE in llvm-ar.o
  "llvm::object::Archive::end_children() const", referenced from:
      __ZL16performOperation16ArchiveOperationPN4llvm6object7ArchiveE in llvm-ar.o
  "llvm::object::Archive::begin_children(bool) const", referenced from:
      __ZL16performOperation16ArchiveOperationPN4llvm6object7ArchiveE in llvm-ar.o
  "llvm::object::Archive::Child::getName(llvm::StringRef&) const", referenced from:
      __ZL16performOperation16ArchiveOperationPN4llvm6object7ArchiveE in llvm-ar.o
  "llvm::object::Archive::Child::getNext() const", referenced from:
      __ZL16performOperation16ArchiveOperationPN4llvm6object7ArchiveE in llvm-ar.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

-Quentin

On Jul 12, 2013, at 2:02 PM, Rafael EspĂ­ndola <rafael.espindola at gmail.com> wrote:

> 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

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20130712/ab24f4c2/attachment.html>


More information about the llvm-commits mailing list