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

Rafael EspĂ­ndola rafael.espindola at gmail.com
Fri Jul 12 14:22:11 PDT 2013


This one should be fixed by 186200.

On 12 July 2013 17:17, Quentin Colombet <qcolombet at apple.com> wrote:
> 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
>
>




More information about the llvm-commits mailing list