[AIX] support write operation of big archive.
SUMMARY 1. Enable supporting the write operation of big archive. 2. the first commit come from https://reviews.llvm.org/D104367 3. refactor the first commit and implement writing symbol table. 4. fixed the bugs and add more test cases in the second commit. Reviewers: James Henderson Differential Revision: https://reviews.llvm.org/D123949
This commit is contained in:
parent
98f82d69bd
commit
fe3b621f05
|
@ -391,6 +391,7 @@ private:
|
|||
};
|
||||
|
||||
class BigArchive : public Archive {
|
||||
public:
|
||||
/// Fixed-Length Header.
|
||||
struct FixLenHdr {
|
||||
char Magic[sizeof(BigArchiveMagic) - 1]; ///< Big archive magic string.
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "llvm/Support/Errc.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/SmallVectorMemoryBuffer.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
@ -127,16 +128,20 @@ static bool isDarwin(object::Archive::Kind Kind) {
|
|||
Kind == object::Archive::K_DARWIN64;
|
||||
}
|
||||
|
||||
static bool isAIXBigArchive(object::Archive::Kind Kind) {
|
||||
return Kind == object::Archive::K_AIXBIG;
|
||||
}
|
||||
|
||||
static bool isBSDLike(object::Archive::Kind Kind) {
|
||||
switch (Kind) {
|
||||
case object::Archive::K_GNU:
|
||||
case object::Archive::K_GNU64:
|
||||
case object::Archive::K_AIXBIG:
|
||||
return false;
|
||||
case object::Archive::K_BSD:
|
||||
case object::Archive::K_DARWIN:
|
||||
case object::Archive::K_DARWIN64:
|
||||
return true;
|
||||
case object::Archive::K_AIXBIG:
|
||||
case object::Archive::K_COFF:
|
||||
break;
|
||||
}
|
||||
|
@ -189,6 +194,31 @@ printBSDMemberHeader(raw_ostream &Out, uint64_t Pos, StringRef Name,
|
|||
Out.write(uint8_t(0));
|
||||
}
|
||||
|
||||
static void
|
||||
printBigArchiveMemberHeader(raw_ostream &Out, StringRef Name,
|
||||
const sys::TimePoint<std::chrono::seconds> &ModTime,
|
||||
unsigned UID, unsigned GID, unsigned Perms,
|
||||
uint64_t Size, unsigned PrevOffset,
|
||||
unsigned NextOffset) {
|
||||
unsigned NameLen = Name.size();
|
||||
|
||||
printWithSpacePadding(Out, Size, 20); // File member size
|
||||
printWithSpacePadding(Out, NextOffset, 20); // Next member header offset
|
||||
printWithSpacePadding(Out, PrevOffset, 20); // Previous member header offset
|
||||
printWithSpacePadding(Out, sys::toTimeT(ModTime), 12); // File member date
|
||||
// The big archive format has 12 chars for uid and gid.
|
||||
printWithSpacePadding(Out, UID % 1000000000000, 12); // UID
|
||||
printWithSpacePadding(Out, GID % 1000000000000, 12); // GID
|
||||
printWithSpacePadding(Out, format("%o", Perms), 12); // Permission
|
||||
printWithSpacePadding(Out, NameLen, 4); // Name length
|
||||
if (NameLen) {
|
||||
printWithSpacePadding(Out, Name, NameLen); // Name
|
||||
if (NameLen % 2)
|
||||
Out.write(uint8_t(0)); // Null byte padding
|
||||
}
|
||||
Out << "`\n"; // Terminator
|
||||
}
|
||||
|
||||
static bool useStringTable(bool Thin, StringRef Name) {
|
||||
return Thin || Name.size() >= 16 || Name.contains('/');
|
||||
}
|
||||
|
@ -199,8 +229,8 @@ static bool is64BitKind(object::Archive::Kind Kind) {
|
|||
case object::Archive::K_BSD:
|
||||
case object::Archive::K_DARWIN:
|
||||
case object::Archive::K_COFF:
|
||||
case object::Archive::K_AIXBIG:
|
||||
return false;
|
||||
case object::Archive::K_AIXBIG:
|
||||
case object::Archive::K_DARWIN64:
|
||||
case object::Archive::K_GNU64:
|
||||
return true;
|
||||
|
@ -304,7 +334,11 @@ static uint64_t computeSymbolTableSize(object::Archive::Kind Kind,
|
|||
// least 4-byte aligned for 32-bit content. Opt for the larger encoding
|
||||
// uniformly.
|
||||
// We do this for all bsd formats because it simplifies aligning members.
|
||||
uint32_t Pad = offsetToAlignment(Size, Align(isBSDLike(Kind) ? 8 : 2));
|
||||
// For the big archive format, the symbol table is the last member, so there
|
||||
// is no need to align.
|
||||
uint32_t Pad = isAIXBigArchive(Kind)
|
||||
? 0
|
||||
: offsetToAlignment(Size, Align(isBSDLike(Kind) ? 8 : 2));
|
||||
Size += Pad;
|
||||
if (Padding)
|
||||
*Padding = Pad;
|
||||
|
@ -312,11 +346,15 @@ static uint64_t computeSymbolTableSize(object::Archive::Kind Kind,
|
|||
}
|
||||
|
||||
static void writeSymbolTableHeader(raw_ostream &Out, object::Archive::Kind Kind,
|
||||
bool Deterministic, uint64_t Size) {
|
||||
bool Deterministic, uint64_t Size,
|
||||
uint64_t PrevMemberOffset = 0) {
|
||||
if (isBSDLike(Kind)) {
|
||||
const char *Name = is64BitKind(Kind) ? "__.SYMDEF_64" : "__.SYMDEF";
|
||||
printBSDMemberHeader(Out, Out.tell(), Name, now(Deterministic), 0, 0, 0,
|
||||
Size);
|
||||
} else if (isAIXBigArchive(Kind)) {
|
||||
printBigArchiveMemberHeader(Out, "", now(Deterministic), 0, 0,
|
||||
0, Size, PrevMemberOffset, 0);
|
||||
} else {
|
||||
const char *Name = is64BitKind(Kind) ? "/SYM64" : "";
|
||||
printGNUSmallMemberHeader(Out, Name, now(Deterministic), 0, 0, 0, Size);
|
||||
|
@ -325,7 +363,8 @@ static void writeSymbolTableHeader(raw_ostream &Out, object::Archive::Kind Kind,
|
|||
|
||||
static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind,
|
||||
bool Deterministic, ArrayRef<MemberData> Members,
|
||||
StringRef StringTable) {
|
||||
StringRef StringTable,
|
||||
uint64_t PrevMemberOffset = 0) {
|
||||
// We don't write a symbol table on an archive with no members -- except on
|
||||
// Darwin, where the linker will abort unless the archive has a symbol table.
|
||||
if (StringTable.empty() && !isDarwin(Kind))
|
||||
|
@ -338,9 +377,10 @@ static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind,
|
|||
uint64_t OffsetSize = is64BitKind(Kind) ? 8 : 4;
|
||||
uint32_t Pad;
|
||||
uint64_t Size = computeSymbolTableSize(Kind, NumSyms, OffsetSize, StringTable, &Pad);
|
||||
writeSymbolTableHeader(Out, Kind, Deterministic, Size);
|
||||
writeSymbolTableHeader(Out, Kind, Deterministic, Size, PrevMemberOffset);
|
||||
|
||||
uint64_t Pos = Out.tell() + Size;
|
||||
uint64_t Pos = isAIXBigArchive(Kind) ? sizeof(object::BigArchive::FixLenHdr)
|
||||
: Out.tell() + Size;
|
||||
|
||||
if (isBSDLike(Kind))
|
||||
printNBits(Out, Kind, NumSyms * 2 * OffsetSize);
|
||||
|
@ -409,9 +449,8 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
|
|||
bool NeedSymbols, ArrayRef<NewArchiveMember> NewMembers) {
|
||||
static char PaddingData[8] = {'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'};
|
||||
|
||||
// This ignores the symbol table, but we only need the value mod 8 and the
|
||||
// symbol table is aligned to be a multiple of 8 bytes
|
||||
uint64_t Pos = 0;
|
||||
uint64_t Pos =
|
||||
isAIXBigArchive(Kind) ? sizeof(object::BigArchive::FixLenHdr) : 0;
|
||||
|
||||
std::vector<MemberData> Ret;
|
||||
bool HasObject = false;
|
||||
|
@ -471,6 +510,9 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
|
|||
Entry.second = Entry.second > 1 ? 1 : 0;
|
||||
}
|
||||
|
||||
// The big archive format needs to know the offset of the previous member
|
||||
// header.
|
||||
unsigned PrevOffset = 0;
|
||||
for (const NewArchiveMember &M : NewMembers) {
|
||||
std::string Header;
|
||||
raw_string_ostream Out(Header);
|
||||
|
@ -503,8 +545,16 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
|
|||
std::move(StringMsg), object::object_error::parse_failed);
|
||||
}
|
||||
|
||||
printMemberHeader(Out, Pos, StringTable, MemberNames, Kind, Thin, M,
|
||||
ModTime, Size);
|
||||
if (isAIXBigArchive(Kind)) {
|
||||
unsigned NextOffset = Pos + sizeof(object::BigArMemHdrType) +
|
||||
alignTo(M.MemberName.size(), 2) + alignTo(Size, 2);
|
||||
printBigArchiveMemberHeader(Out, M.MemberName, ModTime, M.UID, M.GID,
|
||||
M.Perms, Size, PrevOffset, NextOffset);
|
||||
PrevOffset = Pos;
|
||||
} else {
|
||||
printMemberHeader(Out, Pos, StringTable, MemberNames, Kind, Thin, M,
|
||||
ModTime, Size);
|
||||
}
|
||||
Out.flush();
|
||||
|
||||
std::vector<unsigned> Symbols;
|
||||
|
@ -588,22 +638,25 @@ static Error writeArchiveToStream(raw_ostream &Out,
|
|||
return E;
|
||||
std::vector<MemberData> &Data = *DataOrErr;
|
||||
|
||||
if (!StringTableBuf.empty())
|
||||
if (!StringTableBuf.empty() && !isAIXBigArchive(Kind))
|
||||
Data.insert(Data.begin(), computeStringTable(StringTableBuf));
|
||||
|
||||
// We would like to detect if we need to switch to a 64-bit symbol table.
|
||||
if (WriteSymtab) {
|
||||
uint64_t MaxOffset = 8; // For the file signature.
|
||||
uint64_t LastOffset = MaxOffset;
|
||||
uint64_t NumSyms = 0;
|
||||
for (const auto &M : Data) {
|
||||
// Record the start of the member's offset
|
||||
LastOffset = MaxOffset;
|
||||
// Account for the size of each part associated with the member.
|
||||
MaxOffset += M.Header.size() + M.Data.size() + M.Padding.size();
|
||||
NumSyms += M.Symbols.size();
|
||||
}
|
||||
uint64_t LastMemberEndOffset =
|
||||
isAIXBigArchive(Kind) ? sizeof(object::BigArchive::FixLenHdr) : 8;
|
||||
uint64_t LastMemberHeaderOffset = LastMemberEndOffset;
|
||||
uint64_t NumSyms = 0;
|
||||
for (const auto &M : Data) {
|
||||
// Record the start of the member's offset
|
||||
LastMemberHeaderOffset = LastMemberEndOffset;
|
||||
// Account for the size of each part associated with the member.
|
||||
LastMemberEndOffset += M.Header.size() + M.Data.size() + M.Padding.size();
|
||||
NumSyms += M.Symbols.size();
|
||||
}
|
||||
|
||||
// The symbol table is put at the end of the big archive file. The symbol
|
||||
// table is at the start of the archive file for other archive formats.
|
||||
if (WriteSymtab && !isAIXBigArchive(Kind)) {
|
||||
// We assume 32-bit offsets to see if 32-bit symbols are possible or not.
|
||||
uint64_t SymtabSize = computeSymbolTableSize(Kind, NumSyms, 4, SymNamesBuf);
|
||||
auto computeSymbolTableHeaderSize =
|
||||
|
@ -613,7 +666,7 @@ static Error writeArchiveToStream(raw_ostream &Out,
|
|||
writeSymbolTableHeader(Tmp, Kind, Deterministic, SymtabSize);
|
||||
return TmpBuf.size();
|
||||
};
|
||||
LastOffset += computeSymbolTableHeaderSize() + SymtabSize;
|
||||
LastMemberHeaderOffset += computeSymbolTableHeaderSize() + SymtabSize;
|
||||
|
||||
// The SYM64 format is used when an archive's member offsets are larger than
|
||||
// 32-bits can hold. The need for this shift in format is detected by
|
||||
|
@ -627,10 +680,10 @@ static Error writeArchiveToStream(raw_ostream &Out,
|
|||
if (Sym64Env)
|
||||
StringRef(Sym64Env).getAsInteger(10, Sym64Threshold);
|
||||
|
||||
// If LastOffset isn't going to fit in a 32-bit varible we need to switch
|
||||
// to 64-bit. Note that the file can be larger than 4GB as long as the last
|
||||
// member starts before the 4GB offset.
|
||||
if (LastOffset >= Sym64Threshold) {
|
||||
// If LastMemberHeaderOffset isn't going to fit in a 32-bit varible we need
|
||||
// to switch to 64-bit. Note that the file can be larger than 4GB as long as
|
||||
// the last member starts before the 4GB offset.
|
||||
if (LastMemberHeaderOffset >= Sym64Threshold) {
|
||||
if (Kind == object::Archive::K_DARWIN)
|
||||
Kind = object::Archive::K_DARWIN64;
|
||||
else
|
||||
|
@ -640,15 +693,92 @@ static Error writeArchiveToStream(raw_ostream &Out,
|
|||
|
||||
if (Thin)
|
||||
Out << "!<thin>\n";
|
||||
else if (isAIXBigArchive(Kind))
|
||||
Out << "<bigaf>\n";
|
||||
else
|
||||
Out << "!<arch>\n";
|
||||
|
||||
if (WriteSymtab)
|
||||
writeSymbolTable(Out, Kind, Deterministic, Data, SymNamesBuf);
|
||||
if (!isAIXBigArchive(Kind)) {
|
||||
if (WriteSymtab)
|
||||
writeSymbolTable(Out, Kind, Deterministic, Data, SymNamesBuf);
|
||||
for (const MemberData &M : Data)
|
||||
Out << M.Header << M.Data << M.Padding;
|
||||
} else {
|
||||
// For the big archive (AIX) format, compute a table of member names and
|
||||
// offsets, used in the member table.
|
||||
uint64_t MemberTableNameStrTblSize = 0;
|
||||
std::vector<size_t> MemberOffsets;
|
||||
std::vector<StringRef> MemberNames;
|
||||
// Loop across object to find offset and names.
|
||||
uint64_t MemberEndOffset = sizeof(object::BigArchive::FixLenHdr);
|
||||
for (size_t I = 0, Size = NewMembers.size(); I != Size; ++I) {
|
||||
const NewArchiveMember &Member = NewMembers[I];
|
||||
MemberTableNameStrTblSize += Member.MemberName.size() + 1;
|
||||
MemberOffsets.push_back(MemberEndOffset);
|
||||
MemberNames.push_back(Member.MemberName);
|
||||
// File member name ended with "`\n". The length is included in
|
||||
// BigArMemHdrType.
|
||||
MemberEndOffset += sizeof(object::BigArMemHdrType) +
|
||||
alignTo(Data[I].Data.size(), 2) +
|
||||
alignTo(Member.MemberName.size(), 2);
|
||||
}
|
||||
|
||||
for (const MemberData &M : Data)
|
||||
Out << M.Header << M.Data << M.Padding;
|
||||
// AIX member table size.
|
||||
unsigned MemberTableSize = 20 + // Number of members field
|
||||
20 * MemberOffsets.size() +
|
||||
MemberTableNameStrTblSize;
|
||||
|
||||
unsigned GlobalSymbolOffset =
|
||||
(WriteSymtab && NumSyms > 0)
|
||||
? LastMemberEndOffset +
|
||||
alignTo(sizeof(object::BigArMemHdrType) + MemberTableSize, 2)
|
||||
: 0;
|
||||
|
||||
// Fixed Sized Header.
|
||||
printWithSpacePadding(Out, NewMembers.size() ? LastMemberEndOffset : 0,
|
||||
20); // Offset to member table
|
||||
// If there are no file members in the archive, there will be no global
|
||||
// symbol table.
|
||||
printWithSpacePadding(Out, NewMembers.size() ? GlobalSymbolOffset : 0, 20);
|
||||
printWithSpacePadding(
|
||||
Out, 0,
|
||||
20); // Offset to 64 bits global symbol table - Not supported yet
|
||||
printWithSpacePadding(
|
||||
Out, NewMembers.size() ? sizeof(object::BigArchive::FixLenHdr) : 0,
|
||||
20); // Offset to first archive member
|
||||
printWithSpacePadding(Out, NewMembers.size() ? LastMemberHeaderOffset : 0,
|
||||
20); // Offset to last archive member
|
||||
printWithSpacePadding(
|
||||
Out, 0,
|
||||
20); // Offset to first member of free list - Not supported yet
|
||||
|
||||
for (const MemberData &M : Data) {
|
||||
Out << M.Header << M.Data;
|
||||
if (M.Data.size() % 2)
|
||||
Out << '\0';
|
||||
}
|
||||
|
||||
if (NewMembers.size()) {
|
||||
// Member table.
|
||||
printBigArchiveMemberHeader(Out, "", sys::toTimePoint(0), 0, 0, 0,
|
||||
MemberTableSize, LastMemberHeaderOffset,
|
||||
GlobalSymbolOffset);
|
||||
printWithSpacePadding(Out, MemberOffsets.size(), 20); // Number of members
|
||||
for (uint64_t MemberOffset : MemberOffsets)
|
||||
printWithSpacePadding(Out, MemberOffset,
|
||||
20); // Offset to member file header.
|
||||
for (StringRef MemberName : MemberNames)
|
||||
Out << MemberName << '\0'; // Member file name, null byte padding.
|
||||
|
||||
if (MemberTableNameStrTblSize % 2)
|
||||
Out << '\0'; // Name table must be tail padded to an even number of
|
||||
// bytes.
|
||||
|
||||
if (WriteSymtab && NumSyms > 0)
|
||||
writeSymbolTable(Out, Kind, Deterministic, Data, SymNamesBuf,
|
||||
LastMemberEndOffset);
|
||||
}
|
||||
}
|
||||
Out.flush();
|
||||
return Error::success();
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
XFAIL: system-aix
|
||||
Test which operations create an archive and which don't.
|
||||
|
||||
RUN: touch %t
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
XFAIL: system-aix
|
||||
|
||||
RUN: mkdir -p %t
|
||||
RUN: cd %t
|
||||
RUN: rm -rf foo
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# XFAIL: system-aix
|
||||
## Show that the archive library emits error messages when adding malformed
|
||||
## objects.
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
XFAIL: system-aix
|
||||
|
||||
Test adding a member to a particular position
|
||||
|
||||
RUN: touch %t.foo
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# XFAIL: system-aix
|
||||
## Show that the archive library does not emit an error or add any symbols to
|
||||
## the archive symbol table, when it encounters an unknown file type, but still
|
||||
## adds the file to the archive.
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
XFAIL: system-aix
|
||||
|
||||
Test the 'u' option of llvm-ar
|
||||
|
||||
RUN: rm -rf %t && mkdir -p %t && cd %t
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
; XFAIL: system-aix
|
||||
|
||||
;RUN: rm -rf %t && mkdir -p %t
|
||||
;RUN: not llvm-ar r %t/test.a . 2>&1 | FileCheck -DMSG=%errc_EISDIR %s
|
||||
;CHECK: .: [[MSG]]
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# XFAIL: system-aix
|
||||
# Test the 'N' count parameter.
|
||||
|
||||
# Get a temp clean cwd to extract into.
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
XFAIL: system-aix
|
||||
## Test the creation warning and supression of that warning.
|
||||
|
||||
RUN: touch %t1.txt
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
XFAIL: system-aix
|
||||
# Test the use of dash before key letters.
|
||||
|
||||
RUN: touch %t1.txt
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
; REQUIRES: system-aix
|
||||
;; Test llvm-ar does not support Big AIX archive write operation.
|
||||
|
||||
;; Test llvm-ar uses the big archive format for XCOFF object files by default.
|
||||
; RUN: yaml2obj %S/Inputs/xcoff.yaml -o %t.obj
|
||||
; RUN: rm -f %t.ar
|
||||
; RUN: not llvm-ar cr %t.ar %t.obj 2>&1 | FileCheck %s
|
||||
; RUN: echo "test big archive" > %t.txt
|
||||
; RUN: not llvm-ar cr %t.ar %t.txt 2>&1 | FileCheck %s
|
||||
; RUN: llvm-ar cr %t.ar %t.obj
|
||||
; RUN: FileCheck %s --input-file=%t.ar
|
||||
|
||||
; CHECK: big archive writer operation on AIX not yet supported
|
||||
; CHECK: bigaf
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
# XFAIL: system-aix
|
||||
## Test Display of empty archives.
|
||||
|
||||
# RUN: rm -rf %t && mkdir -p %t
|
||||
|
||||
## Display empty archive:
|
||||
# RUN: llvm-ar cr %t/empty.a
|
||||
# RUN: llvm-ar cr --format=gnu %t/empty.a
|
||||
# RUN: llvm-ar tv %t/empty.a 2>&1 | count 0
|
||||
|
||||
## Display empty thin archive:
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# XFAIL: system-aix
|
||||
## Test the use of "--" on the commandline
|
||||
|
||||
# RUN: echo contents > %t.txt
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# XFAIL: system-aix
|
||||
## Unsupported on windows as marking files "unreadable"
|
||||
## is non-trivial on windows.
|
||||
# UNSUPPORTED: system-windows
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
## Test extract operation.
|
||||
# XFAIL: system-darwin,system-aix
|
||||
# XFAIL: system-darwin
|
||||
|
||||
# RUN: rm -rf %t && mkdir -p %t/extracted/
|
||||
|
||||
## Extracting from an empty archive should not warn or error:
|
||||
# RUN: llvm-ar cr %t/empty.a
|
||||
# RUN: llvm-ar cr --format=gnu %t/empty.a
|
||||
# RUN: llvm-ar xv %t/empty.a 2>&1 | count 0
|
||||
|
||||
# RUN: echo filea > %t/a.txt
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# XFAIL: system-aix
|
||||
## This test creates a thin archive that contains a thin archive, a regular
|
||||
## archive, and a file.
|
||||
##
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
XFAIL: system-aix
|
||||
# Note: many of these tests depend on relative paths, so we have to cd to a
|
||||
# test directory first.
|
||||
RUN: mkdir -p %t && cd %t
|
||||
|
@ -28,7 +27,7 @@ DISPLAY-NOT-FOUND: 'a/foo.txt' was not found
|
|||
|
||||
# Deleting will fail with P because the members exist as foo.txt, not a/foo.txt.
|
||||
RUN: rm -f del1.a
|
||||
RUN: llvm-ar rcS del1.a foo.txt
|
||||
RUN: llvm-ar rcS --format=gnu del1.a foo.txt
|
||||
RUN: llvm-ar dP del1.a a/foo.txt
|
||||
RUN: llvm-ar t del1.a a/foo.txt | FileCheck %s --check-prefix=DISPLAY-FOUND --match-full-lines
|
||||
RUN: llvm-ar d del1.a a/foo.txt
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
XFAIL: system-aix
|
||||
## Test inserting files after a file.
|
||||
|
||||
RUN: touch %t1.txt
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
XFAIL: system-aix
|
||||
## Test inserting files before a file.
|
||||
|
||||
RUN: touch %t1.txt
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
XFAIL: system-aix
|
||||
## Test moving files after a file.
|
||||
|
||||
RUN: touch %t1.txt
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
XFAIL: system-aix
|
||||
## Test moving files after a file.
|
||||
|
||||
RUN: touch %t1.txt
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
XFAIL: system-aix
|
||||
RUN: yaml2obj %S/Inputs/elf.yaml -o %t.o
|
||||
RUN: rm -f %t.ar
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
XFAIL: system-aix
|
||||
# Test non-ascii archive members
|
||||
|
||||
RUN: rm -rf %t && mkdir -p %t/extracted
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# XFAIL: system-aix
|
||||
## Test that on windows, members are case insensitive.
|
||||
# UNSUPPORTED: system-windows
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# XFAIL: system-aix
|
||||
## Test that --plugin is ignored.
|
||||
|
||||
# RUN: rm -f %t.a
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
## Test Print output
|
||||
# XFAIL: system-darwin,system-aix
|
||||
# XFAIL: system-darwin
|
||||
|
||||
# RUN: rm -rf %t && mkdir -p %t
|
||||
# RUN: echo file1 > %t/1.txt
|
||||
|
@ -9,7 +9,7 @@
|
|||
# RUN: llvm-ar -rc %t/archive.a %t/1.txt %t/2.txt %t/3.txt
|
||||
|
||||
## Print empty archive:
|
||||
# RUN: llvm-ar cr %t/empty.a
|
||||
# RUN: llvm-ar --format=gnu cr %t/empty.a
|
||||
# RUN: llvm-ar p %t/empty.a 2>&1 | count 0
|
||||
# RUN: llvm-ar pv %t/empty.a 2>&1 | count 0
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# XFAIL: system-aix
|
||||
## Test that read-only archives cannot be edited
|
||||
|
||||
# RUN: rm -rf %t && mkdir -p %t
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# XFAIL: system-aix
|
||||
## Check that response files can cope with non-ascii characters.
|
||||
|
||||
# RUN: echo 'contents' > %t-£.txt
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# XFAIL: system-aix
|
||||
## llvm-ar should be able to consume response files.
|
||||
|
||||
# RUN: echo 'contents' > %t.txt
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# XFAIL: system-aix
|
||||
## This test checks that an archive is flattened correctly.
|
||||
|
||||
# RUN: yaml2obj %S/Inputs/input1.yaml -o %t-input1.o
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# RUN: llvm-as %S/Inputs/f.ll -o %t.f.bc
|
||||
# RUN: llvm-as %S/Inputs/g.ll -o %t.g.bc
|
||||
# RUN: llvm-ar cr --format=gnu %t.fg.a %t.f.bc %t.g.bc
|
||||
# RUN: llvm-ar cr --format=gnu %t.empty.lib
|
||||
# RUN: llvm-ar cr %t.fg.a %t.f.bc %t.g.bc
|
||||
# RUN: llvm-ar cr --format=gnu %t.empty.lib
|
||||
# RUN: llvm-link %S/Inputs/h.ll %t.fg.a %t.empty.lib -o %t.linked.bc
|
||||
|
||||
# RUN: llvm-nm %t.linked.bc | FileCheck %s
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# RUN: llvm-ar --format=gnu cr %t.fg.a %S/Inputs/f.ll %S/Inputs/g.ll
|
||||
# XFAIL: system-aix
|
||||
# RUN: llvm-ar cr %t.fg.a %S/Inputs/f.ll %S/Inputs/g.ll
|
||||
# RUN: not llvm-link %S/Inputs/h.ll %t.fg.a -o %t.linked.bc 2>&1 | FileCheck %s
|
||||
|
||||
# RUN: rm -f %t.fg.a
|
||||
|
|
|
@ -4,16 +4,16 @@
|
|||
# RUN: llvm-as %p/Inputs/armv7-ios.ll -o %t-ir-armv7.o
|
||||
# RUN: llvm-as %p/Inputs/x64-osx.ll -o %t-ir-x86_64.o
|
||||
|
||||
# RUN: llvm-ar --format=gnu cr %t.empty.a
|
||||
# RUN: llvm-ar cr --format=gnu %t.empty.a
|
||||
# RUN: not llvm-lipo %t.empty.a -create -output /dev/null 2>&1 | FileCheck --check-prefix=EMPTY-ARCHIVE %s
|
||||
|
||||
# RUN: llvm-ar --format=gnu cr %t.different_architectures.a %t-i386.o %t-x86_64.o
|
||||
# RUN: llvm-ar cr %t.different_architectures.a %t-i386.o %t-x86_64.o
|
||||
# RUN: not llvm-lipo %t.different_architectures.a -create -output /dev/null 2>&1 | FileCheck --check-prefix=ARCHIVE-WITH-DIFFERENT-ARCHS %s
|
||||
|
||||
# RUN: llvm-ar --format=gnu cr %t.contains_fat_binary.a %t-universal.o
|
||||
# RUN: llvm-ar cr %t.contains_fat_binary.a %t-universal.o
|
||||
# RUN: not llvm-lipo %t.contains_fat_binary.a -create -output /dev/null 2>&1 | FileCheck --check-prefix=ARCHIVE-WITH-FAT-BINARY %s
|
||||
|
||||
# RUN: llvm-ar --format=gnu cr %t-i386-lib.a %t-i386.o
|
||||
# RUN: llvm-ar cr %t-i386-lib.a %t-i386.o
|
||||
# RUN: llvm-lipo %t-i386-lib.a %t-x86_64.o -create -output %t-i386-x86_64-universal.o
|
||||
# RUN: llvm-lipo %t-i386-x86_64-universal.o -info | FileCheck --check-prefix=INFO-i386-x86_64 %s
|
||||
# RUN: llvm-lipo %t-i386-x86_64-universal.o -thin i386 -output %t-extracted-i386-lib.a
|
||||
|
@ -21,18 +21,18 @@
|
|||
# RUN: llvm-lipo %t-i386-x86_64-universal.o -thin x86_64 -output %t-extracted-x86_64.o
|
||||
# RUN: cmp %t-extracted-x86_64.o %t-x86_64.o
|
||||
|
||||
# RUN: llvm-ar --format=gnu cr %t-ir-armv7-lib.a %t-ir-armv7.o
|
||||
# RUN: llvm-ar cr %t-ir-armv7-lib.a %t-ir-armv7.o
|
||||
# RUN: llvm-lipo %t-ir-armv7-lib.a %t-ir-x86_64.o -create -output %t-ir-armv7-x86_64-universal.o
|
||||
# RUN: llvm-lipo %t-ir-armv7-x86_64-universal.o -thin armv7 -output %t-ir-extracted-armv7-lib.a
|
||||
# RUN: cmp %t-ir-extracted-armv7-lib.a %t-ir-armv7-lib.a
|
||||
# RUN: llvm-lipo %t-ir-armv7-x86_64-universal.o -thin x86_64 -output %t-ir-extracted-x86_64.o
|
||||
# RUN: cmp %t-ir-extracted-x86_64.o %t-ir-x86_64.o
|
||||
|
||||
# RUN: llvm-ar --format=gnu cr %t.different_types0.a %t-i386.o %t-ir-x86_64.o
|
||||
# RUN: llvm-ar cr %t.different_types0.a %t-i386.o %t-ir-x86_64.o
|
||||
# RUN: not llvm-lipo -create %t.different_types0.a -output /dev/null 2>&1 | FileCheck --check-prefix=ARCHIVE-WITH-MACHO-AND-IR %s
|
||||
# RUN: llvm-ar --format=gnu cr %t.different_types1.a %t-ir-x86_64.o %t-i386.o
|
||||
# RUN: llvm-ar cr %t.different_types1.a %t-ir-x86_64.o %t-i386.o
|
||||
# RUN: not llvm-lipo -create %t.different_types1.a -output /dev/null 2>&1 | FileCheck --check-prefix=ARCHIVE-WITH-IR-AND-MACHO %s
|
||||
# RUN: llvm-ar --format=gnu cr %t.different_architectures_ir.a %t-ir-x86_64.o %t-ir-armv7.o
|
||||
# RUN: llvm-ar cr %t.different_architectures_ir.a %t-ir-x86_64.o %t-ir-armv7.o
|
||||
# RUN: not llvm-lipo -create %t.different_architectures_ir.a -output /dev/null 2>&1 | FileCheck --check-prefix=ARCHIVE-WITH-DIFFERENT-ARCHS %s
|
||||
|
||||
# EMPTY-ARCHIVE: empty archive
|
||||
|
|
|
@ -56,7 +56,7 @@ Symbols:
|
|||
# RUN: yaml2obj --docnum=2 -DFLAG=0x1DF %s -o %t_xcoff32.o
|
||||
# RUN: yaml2obj --docnum=2 -DFLAG=0x1F7 %s -o %t_xcoff64.o
|
||||
# RUN: rm -f %t.a
|
||||
# RUN: llvm-ar --format=gnu -q -c %t.a %t_xcoff32.o %t_xcoff64.o
|
||||
# RUN: llvm-ar -q -c %t.a %t_xcoff32.o %t_xcoff64.o
|
||||
|
||||
# RUN: llvm-nm --format=just-symbols -X32 %t_xcoff32.o | \
|
||||
# RUN: FileCheck --check-prefixes=XCOFF32 %s --implicit-check-not={{.}}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
## Case 2: copy a universal object file containing an archive.
|
||||
# RUN: rm -f %t.archive.i386
|
||||
# RUN: llvm-ar --format=gnu cr %t.archive.i386 %t.i386
|
||||
# RUN: llvm-ar cr %t.archive.i386 %t.i386
|
||||
# RUN: llvm-lipo %t.archive.i386 %t.x86_64 -create -output %t.universal.containing.archive
|
||||
# RUN: llvm-objcopy %t.universal.containing.archive %t.universal.containing.archive.copy
|
||||
# RUN: llvm-lipo %t.universal.containing.archive.copy -archs | FileCheck --check-prefix=VERIFY_ARCHS %s
|
||||
|
@ -24,7 +24,7 @@
|
|||
# RUN: cmp %t.x86_64 %t.archive.x86_64.copy
|
||||
|
||||
## Case 3: copy an archive containing a universal object.
|
||||
# RUN: llvm-ar --format=gnu cr %t.archive.containing.universal %t.universal
|
||||
# RUN: llvm-ar cr %t.archive.containing.universal %t.universal
|
||||
# RUN: llvm-objcopy %t.archive.containing.universal %t.archive.containing.universal.copy
|
||||
|
||||
## Case 4: try to copy a universal object file contaning a bitcode slice.
|
||||
|
@ -34,7 +34,7 @@
|
|||
# RUN: | FileCheck --check-prefix=UNSUPPORTED_UNIVERSAL_OBJECT %s
|
||||
|
||||
## Case 5: try to copy an archive containing an unsupported universal object.
|
||||
# RUN: llvm-ar --format=gnu cr %t.archive.universal.bitcode %t.universal.containing.bitcode
|
||||
# RUN: llvm-ar cr %t.archive.universal.bitcode %t.universal.containing.bitcode
|
||||
# RUN: not llvm-objcopy %t.archive.universal.bitcode %t.archive.universal.bitcode.copy 2>&1 \
|
||||
# RUN: | FileCheck --check-prefix=UNSUPPORTED_UNIVERSAL_OBJECT %s
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ EMPTY: '{{.*}}.empty': The file was not recognized as a valid object file
|
|||
|
||||
# Test that unrecognised files in archives are ignored.
|
||||
RUN: rm -f %t.a
|
||||
RUN: llvm-ar --format=gnu rc %t.a %t.empty
|
||||
RUN: llvm-ar rc %t.a %t.empty
|
||||
RUN: llvm-readobj --all %t.a 2>&1 | FileCheck --check-prefix=NO-OUTPUT --allow-empty %s
|
||||
NO-OUTPUT-NOT: {{.}}
|
||||
|
||||
|
|
|
@ -5,21 +5,21 @@
|
|||
|
||||
## Case 1: Empty archive. No output expected.
|
||||
# RUN: rm -f %t1.a
|
||||
# RUN: llvm-ar --format=gnu rc %t1.a
|
||||
# RUN: llvm-ar rc --format=gnu %t1.a
|
||||
|
||||
# RUN: llvm-size -B %t1.a | count 0
|
||||
# RUN: llvm-size -A %t1.a | count 0
|
||||
|
||||
## Case 2: Single member.
|
||||
# RUN: rm -f %t2.a
|
||||
# RUN: llvm-ar --format=gnu rc %t2.a %t1
|
||||
# RUN: llvm-ar rc %t2.a %t1
|
||||
|
||||
# RUN: llvm-size -B %t2.a | FileCheck %s -DARCHIVE=%t2.a --check-prefix=BERKELEY-1
|
||||
# RUN: llvm-size -A %t2.a | FileCheck %s -DARCHIVE=%t2.a --check-prefix=SYSV-1
|
||||
|
||||
## Case 3: Multiple members.
|
||||
# RUN: rm -f %t3.a
|
||||
# RUN: llvm-ar --format=gnu rc %t3.a %t1 %t2
|
||||
# RUN: llvm-ar rc %t3.a %t1 %t2
|
||||
|
||||
# RUN: llvm-size -B %t3.a | FileCheck %s -DARCHIVE=%t3.a --check-prefixes=BERKELEY-1,BERKELEY-2
|
||||
# RUN: llvm-size -A %t3.a | FileCheck %s -DARCHIVE=%t3.a --check-prefixes=SYSV-1,SYSV-2
|
||||
|
|
|
@ -82,6 +82,7 @@ static void printArHelp(StringRef ToolName) {
|
|||
=gnu - gnu
|
||||
=darwin - darwin
|
||||
=bsd - bsd
|
||||
=aix - aix (big archive)
|
||||
--plugin=<string> - ignored for compatibility
|
||||
-h --help - display this help and exit
|
||||
--rsp-quoting - quoting style for response files
|
||||
|
@ -187,7 +188,7 @@ static SmallVector<const char *, 256> PositionalArgs;
|
|||
static bool MRI;
|
||||
|
||||
namespace {
|
||||
enum Format { Default, GNU, BSD, DARWIN, Unknown };
|
||||
enum Format { Default, GNU, BSD, DARWIN, BIGARCHIVE, Unknown };
|
||||
}
|
||||
|
||||
static Format FormatType = Default;
|
||||
|
@ -950,8 +951,6 @@ static void performWriteOperation(ArchiveOperation Operation,
|
|||
else
|
||||
Kind = !NewMembers.empty() ? getKindFromMember(NewMembers.front())
|
||||
: getDefaultForHost();
|
||||
if (Kind == object::Archive::K_AIXBIG)
|
||||
fail("big archive writer operation on AIX not yet supported");
|
||||
break;
|
||||
case GNU:
|
||||
Kind = object::Archive::K_GNU;
|
||||
|
@ -966,6 +965,11 @@ static void performWriteOperation(ArchiveOperation Operation,
|
|||
fail("only the gnu format has a thin mode");
|
||||
Kind = object::Archive::K_DARWIN;
|
||||
break;
|
||||
case BIGARCHIVE:
|
||||
if (Thin)
|
||||
fail("only the gnu format has a thin mode");
|
||||
Kind = object::Archive::K_AIXBIG;
|
||||
break;
|
||||
case Unknown:
|
||||
llvm_unreachable("");
|
||||
}
|
||||
|
@ -1237,6 +1241,7 @@ static int ar_main(int argc, char **argv) {
|
|||
.Case("gnu", GNU)
|
||||
.Case("darwin", DARWIN)
|
||||
.Case("bsd", BSD)
|
||||
.Case("bigarchive", BIGARCHIVE)
|
||||
.Default(Unknown);
|
||||
if (FormatType == Unknown)
|
||||
fail(std::string("Invalid format ") + Match);
|
||||
|
|
Loading…
Reference in New Issue
Block a user