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

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


Fixed in r186198.

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



More information about the llvm-commits mailing list