<html><head><meta http-equiv="Content-Type" content="text/html charset=iso-8859-1"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;">Apparently, that is not fixing the problem :(.<div><a href="http://lab.llvm.org:8013/builders/clang-x86_64-darwin11-nobootstrap-RAincremental/builds/4317">http://lab.llvm.org:8013/builders/clang-x86_64-darwin11-nobootstrap-RAincremental/builds/4317</a><br><div><pre style="font-family: 'Courier New', courier, monotype; font-size: medium;"><span class="stdout">llvm[2]: Linking Release+Asserts executable llvm-ar
</span><span class="stderr" style="color: red;">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)</span></pre><div><br></div><div apple-content-edited="true">
<div style="color: rgb(0, 0, 0); font-family: Helvetica;  font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: -webkit-auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; ">-Quentin</div>

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