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