<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>