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