Add support deterministic output in llvm-ar and make it the default.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@242061 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Rafael Espindola
2015-07-13 20:38:09 +00:00
parent 7d41350722
commit 168b1bebf0
8 changed files with 76 additions and 41 deletions

View File

@@ -43,7 +43,7 @@ public:
std::pair<StringRef, std::error_code> std::pair<StringRef, std::error_code>
writeArchive(StringRef ArcName, std::vector<NewArchiveIterator> &NewMembers, writeArchive(StringRef ArcName, std::vector<NewArchiveIterator> &NewMembers,
bool WriteSymtab, object::Archive::Kind Kind); bool WriteSymtab, object::Archive::Kind Kind, bool Deterministic);
} }
#endif #endif

View File

@@ -141,7 +141,8 @@ int llvm::libDriverMain(llvm::ArrayRef<const char*> ArgsArr) {
std::pair<StringRef, std::error_code> Result = std::pair<StringRef, std::error_code> Result =
llvm::writeArchive(getOutputPath(&Args, Members[0]), Members, llvm::writeArchive(getOutputPath(&Args, Members[0]), Members,
/*WriteSymtab=*/true, object::Archive::K_GNU); /*WriteSymtab=*/true, object::Archive::K_GNU,
/*Deterministic*/ true);
if (Result.second) { if (Result.second) {
if (Result.first.empty()) if (Result.first.empty())

View File

@@ -178,12 +178,20 @@ static void writeStringTable(raw_fd_ostream &Out,
Out.seek(Pos); Out.seek(Pos);
} }
static sys::TimeValue now(bool Deterministic) {
if (!Deterministic)
return sys::TimeValue::now();
sys::TimeValue TV;
TV.fromEpochTime(0);
return TV;
}
// Returns the offset of the first reference to a member offset. // Returns the offset of the first reference to a member offset.
static ErrorOr<unsigned> static ErrorOr<unsigned>
writeSymbolTable(raw_fd_ostream &Out, object::Archive::Kind Kind, writeSymbolTable(raw_fd_ostream &Out, object::Archive::Kind Kind,
ArrayRef<NewArchiveIterator> Members, ArrayRef<NewArchiveIterator> Members,
ArrayRef<MemoryBufferRef> Buffers, ArrayRef<MemoryBufferRef> Buffers,
std::vector<unsigned> &MemberOffsetRefs) { std::vector<unsigned> &MemberOffsetRefs, bool Deterministic) {
unsigned HeaderStartOffset = 0; unsigned HeaderStartOffset = 0;
unsigned BodyStartOffset = 0; unsigned BodyStartOffset = 0;
SmallString<128> NameBuf; SmallString<128> NameBuf;
@@ -201,10 +209,9 @@ writeSymbolTable(raw_fd_ostream &Out, object::Archive::Kind Kind,
if (!HeaderStartOffset) { if (!HeaderStartOffset) {
HeaderStartOffset = Out.tell(); HeaderStartOffset = Out.tell();
if (Kind == object::Archive::K_GNU) if (Kind == object::Archive::K_GNU)
printGNUSmallMemberHeader(Out, "", sys::TimeValue::now(), 0, 0, 0, 0); printGNUSmallMemberHeader(Out, "", now(Deterministic), 0, 0, 0, 0);
else else
printBSDMemberHeader(Out, "__.SYMDEF", sys::TimeValue::now(), 0, 0, 0, printBSDMemberHeader(Out, "__.SYMDEF", now(Deterministic), 0, 0, 0, 0);
0);
BodyStartOffset = Out.tell(); BodyStartOffset = Out.tell();
print32(Out, Kind, 0); // number of entries or bytes print32(Out, Kind, 0); // number of entries or bytes
} }
@@ -261,10 +268,9 @@ writeSymbolTable(raw_fd_ostream &Out, object::Archive::Kind Kind,
return BodyStartOffset + 4; return BodyStartOffset + 4;
} }
std::pair<StringRef, std::error_code> std::pair<StringRef, std::error_code> llvm::writeArchive(
llvm::writeArchive(StringRef ArcName, StringRef ArcName, std::vector<NewArchiveIterator> &NewMembers,
std::vector<NewArchiveIterator> &NewMembers, bool WriteSymtab, object::Archive::Kind Kind, bool Deterministic) {
bool WriteSymtab, object::Archive::Kind Kind) {
SmallString<128> TmpArchive; SmallString<128> TmpArchive;
int TmpArchiveFD; int TmpArchiveFD;
if (auto EC = sys::fs::createUniqueFile(ArcName + ".temp-archive-%%%%%%%.a", if (auto EC = sys::fs::createUniqueFile(ArcName + ".temp-archive-%%%%%%%.a",
@@ -315,8 +321,8 @@ llvm::writeArchive(StringRef ArcName,
unsigned MemberReferenceOffset = 0; unsigned MemberReferenceOffset = 0;
if (WriteSymtab) { if (WriteSymtab) {
ErrorOr<unsigned> MemberReferenceOffsetOrErr = ErrorOr<unsigned> MemberReferenceOffsetOrErr = writeSymbolTable(
writeSymbolTable(Out, Kind, NewMembers, Members, MemberOffsetRefs); Out, Kind, NewMembers, Members, MemberOffsetRefs, Deterministic);
if (auto EC = MemberReferenceOffsetOrErr.getError()) if (auto EC = MemberReferenceOffsetOrErr.getError())
return std::make_pair(ArcName, EC); return std::make_pair(ArcName, EC);
MemberReferenceOffset = MemberReferenceOffsetOrErr.get(); MemberReferenceOffset = MemberReferenceOffsetOrErr.get();
@@ -336,19 +342,39 @@ llvm::writeArchive(StringRef ArcName,
unsigned Pos = Out.tell(); unsigned Pos = Out.tell();
MemberOffset.push_back(Pos); MemberOffset.push_back(Pos);
sys::TimeValue ModTime;
unsigned UID;
unsigned GID;
unsigned Perms;
if (Deterministic) {
ModTime.fromEpochTime(0);
UID = 0;
GID = 0;
Perms = 0644;
} else if (I.isNewMember()) {
const sys::fs::file_status &Status = NewMemberStatus[NewMemberNum];
ModTime = Status.getLastModificationTime();
UID = Status.getUser();
GID = Status.getGroup();
Perms = Status.permissions();
} else {
object::Archive::child_iterator OldMember = I.getOld();
ModTime = OldMember->getLastModified();
UID = OldMember->getUID();
GID = OldMember->getGID();
Perms = OldMember->getAccessMode();
}
if (I.isNewMember()) { if (I.isNewMember()) {
StringRef FileName = I.getNew(); StringRef FileName = I.getNew();
const sys::fs::file_status &Status = NewMemberStatus[NewMemberNum++]; const sys::fs::file_status &Status = NewMemberStatus[NewMemberNum++];
printMemberHeader(Out, Kind, sys::path::filename(FileName), printMemberHeader(Out, Kind, sys::path::filename(FileName),
StringMapIndexIter, Status.getLastModificationTime(), StringMapIndexIter, ModTime, UID, GID, Perms,
Status.getUser(), Status.getGroup(), Status.getSize());
Status.permissions(), Status.getSize());
} else { } else {
object::Archive::child_iterator OldMember = I.getOld(); object::Archive::child_iterator OldMember = I.getOld();
printMemberHeader(Out, Kind, I.getName(), StringMapIndexIter, printMemberHeader(Out, Kind, I.getName(), StringMapIndexIter, ModTime,
OldMember->getLastModified(), OldMember->getUID(), UID, GID, Perms, OldMember->getSize());
OldMember->getGID(), OldMember->getAccessMode(),
OldMember->getSize());
} }
Out << File.getBuffer(); Out << File.getBuffer();

View File

@@ -7,23 +7,23 @@ RUN: cd %t
RUN: echo -n bar. > 0123456789abcde RUN: echo -n bar. > 0123456789abcde
RUN: echo -n zed. > 0123456789abcdef RUN: echo -n zed. > 0123456789abcdef
RUN: rm -f test.a RUN: rm -f %t.a
RUN: llvm-ar --format=gnu rc test.a 0123456789abcde 0123456789abcdef RUN: llvm-ar --format=gnu rc %t.a 0123456789abcde 0123456789abcdef
RUN: cat test.a | FileCheck -strict-whitespace %s RUN: cat %t.a | FileCheck -strict-whitespace %s
CHECK: !<arch> CHECK: !<arch>
CHECK-NEXT: // 18 ` CHECK-NEXT: // 18 `
CHECK-NEXT: 0123456789abcdef/ CHECK-NEXT: 0123456789abcdef/
CHECK-NEXT: 0123456789abcde/{{................................}}4 ` CHECK-NEXT: 0123456789abcde/0 0 0 644 4 `
CHECK-NEXT: bar./0 {{................................}}4 ` CHECK-NEXT: bar./0 0 0 0 644 4 `
CHECK-NEXT: zed. CHECK-NEXT: zed.
RUN: rm -f test-bsd.a RUN: rm -f %t.a
RUN: llvm-ar --format=bsd rc test-bsd.a 0123456789abcde 0123456789abcdef RUN: llvm-ar --format=bsd rc %t.a 0123456789abcde 0123456789abcdef
RUN: cat test-bsd.a | FileCheck -strict-whitespace --check-prefix=BSD %s RUN: cat %t.a | FileCheck -strict-whitespace --check-prefix=BSD %s
BSD: !<arch> BSD: !<arch>
BSD-NEXT: #1/20 {{..............................}} 24 ` BSD-NEXT: #1/20 0 0 0 644 24 `
BSD-NEXT: 0123456789abcde{{.....}}bar. BSD-NEXT: 0123456789abcde{{.....}}bar.
BSD-SAME: #1/16 {{..............................}} 20 ` BSD-SAME: #1/16 0 0 0 644 20 `
BSD-NEXT: 0123456789abcdefzed. BSD-NEXT: 0123456789abcdefzed.

View File

@@ -1,5 +1,5 @@
RUN: rm -f %t.a RUN: rm -f %t.a
RUN: llvm-ar rcs %t.a %p/Inputs/trivial-object-test.elf-x86-64 %p/Inputs/trivial-object-test2.elf-x86-64 RUN: llvm-ar rcsU %t.a %p/Inputs/trivial-object-test.elf-x86-64 %p/Inputs/trivial-object-test2.elf-x86-64
RUN: llvm-nm -M %t.a | FileCheck %s RUN: llvm-nm -M %t.a | FileCheck %s
CHECK: Archive map CHECK: Archive map
@@ -19,7 +19,7 @@ CHECK-NEXT: 0000000000000006 T foo
CHECK-NEXT: 0000000000000016 T main CHECK-NEXT: 0000000000000016 T main
RUN: rm -f %t.a RUN: rm -f %t.a
RUN: llvm-ar rcS %t.a %p/Inputs/trivial-object-test.elf-x86-64 %p/Inputs/trivial-object-test2.elf-x86-64 RUN: llvm-ar rcSU %t.a %p/Inputs/trivial-object-test.elf-x86-64 %p/Inputs/trivial-object-test2.elf-x86-64
RUN: llvm-nm -M %t.a | FileCheck %s --check-prefix=NOMAP RUN: llvm-nm -M %t.a | FileCheck %s --check-prefix=NOMAP
NOMAP-NOT: Archive map NOMAP-NOT: Archive map
@@ -54,7 +54,7 @@ RUN: llvm-nm -M %t.a | FileCheck %s --check-prefix=CORRUPT
repeate the test with llvm-ranlib repeate the test with llvm-ranlib
RUN: rm -f %t.a RUN: rm -f %t.a
RUN: llvm-ar rcS %t.a %p/Inputs/trivial-object-test.elf-x86-64 %p/Inputs/trivial-object-test2.elf-x86-64 RUN: llvm-ar rcSU %t.a %p/Inputs/trivial-object-test.elf-x86-64 %p/Inputs/trivial-object-test2.elf-x86-64
RUN: llvm-nm -M %t.a | FileCheck %s --check-prefix=NOMAP RUN: llvm-nm -M %t.a | FileCheck %s --check-prefix=NOMAP
RUN: llvm-ranlib %t.a RUN: llvm-ranlib %t.a
@@ -68,7 +68,7 @@ BSD-MachO: _bar in bar.o
BSD-MachO: _foo in foo.o BSD-MachO: _foo in foo.o
RUN: rm -f %t.a RUN: rm -f %t.a
RUN: llvm-ar --format=bsd rcs %t.a %p/Inputs/trivial-object-test.macho-x86-64 %p/Inputs/trivial-object-test2.macho-x86-64 RUN: llvm-ar --format=bsd rcsU %t.a %p/Inputs/trivial-object-test.macho-x86-64 %p/Inputs/trivial-object-test2.macho-x86-64
RUN: llvm-nm -M %t.a | FileCheck --check-prefix=MACHO %s RUN: llvm-nm -M %t.a | FileCheck --check-prefix=MACHO %s
MACHO: Archive map MACHO: Archive map
@@ -91,7 +91,7 @@ MACHO-NEXT: 0000000000000002 T _main
Test that we pad the symbol table so that it ends in a multiple of 4 bytes: Test that we pad the symbol table so that it ends in a multiple of 4 bytes:
8 + 60 + 36 == 104 8 + 60 + 36 == 104
RUN: rm -f %t.a RUN: rm -f %t.a
RUN: llvm-ar --format=bsd rcs %t.a %p/Inputs/trivial-object-test.macho-x86-64 RUN: llvm-ar --format=bsd rcsU %t.a %p/Inputs/trivial-object-test.macho-x86-64
RUN: FileCheck --check-prefix=MACHO-SYMTAB-ALIGN %s < %t.a RUN: FileCheck --check-prefix=MACHO-SYMTAB-ALIGN %s < %t.a
MACHO-SYMTAB-ALIGN: !<arch> MACHO-SYMTAB-ALIGN: !<arch>
MACHO-SYMTAB-ALIGN-NEXT: #1/12 {{..........}} 0 0 0 36 ` MACHO-SYMTAB-ALIGN-NEXT: #1/12 {{..........}} 0 0 0 36 `

View File

@@ -16,19 +16,19 @@ RUN: echo newer > %t.newer/evenlen
RUN: touch %t.newer/evenlen RUN: touch %t.newer/evenlen
Create an achive with the newest file Create an achive with the newest file
RUN: llvm-ar r %t.a %t.newer/evenlen RUN: llvm-ar rU %t.a %t.newer/evenlen
RUN: llvm-ar p %t.a | FileCheck --check-prefix=NEWER %s RUN: llvm-ar p %t.a | FileCheck --check-prefix=NEWER %s
Check that without the 'u' option the member is replaced with an older file. Check that without the 'u' option the member is replaced with an older file.
RUN: llvm-ar r %t.a %t.older/evenlen RUN: llvm-ar rU %t.a %t.older/evenlen
RUN: llvm-ar p %t.a | FileCheck --check-prefix=OLDER %s RUN: llvm-ar p %t.a | FileCheck --check-prefix=OLDER %s
Check that with the 'u' option the member is replaced with a newer file. Check that with the 'u' option the member is replaced with a newer file.
RUN: llvm-ar ru %t.a %t.newer/evenlen RUN: llvm-ar ruU %t.a %t.newer/evenlen
RUN: llvm-ar p %t.a | FileCheck --check-prefix=NEWER %s RUN: llvm-ar p %t.a | FileCheck --check-prefix=NEWER %s
Check that with the 'u' option the member is not replaced with an older file. Check that with the 'u' option the member is not replaced with an older file.
RUN: llvm-ar ru %t.a %t.older/evenlen RUN: llvm-ar ruU %t.a %t.older/evenlen
RUN: llvm-ar p %t.a | FileCheck --check-prefix=NEWER %s RUN: llvm-ar p %t.a | FileCheck --check-prefix=NEWER %s
NEWER: newer NEWER: newer

View File

@@ -39,7 +39,7 @@
; RUN: rm -f very_long_bytecode_file_name.bc ; RUN: rm -f very_long_bytecode_file_name.bc
; RUN: llvm-ar xo %p/Inputs/GNU.a very_long_bytecode_file_name.bc ; RUN: llvm-ar xo %p/Inputs/GNU.a very_long_bytecode_file_name.bc
; RUN: rm -f %t.a ; RUN: rm -f %t.a
; RUN: llvm-ar rc %t.a very_long_bytecode_file_name.bc ; RUN: llvm-ar rcU %t.a very_long_bytecode_file_name.bc
; RUN: env TZ=GMT llvm-ar tv %t.a | FileCheck %s ; RUN: env TZ=GMT llvm-ar tv %t.a | FileCheck %s
CHECK: 1465 2004-11-19 03:01:31.000000000 very_long_bytecode_file_name.bc CHECK: 1465 2004-11-19 03:01:31.000000000 very_long_bytecode_file_name.bc

View File

@@ -129,6 +129,7 @@ static bool OriginalDates = false; ///< 'o' modifier
static bool OnlyUpdate = false; ///< 'u' modifier static bool OnlyUpdate = false; ///< 'u' modifier
static bool Verbose = false; ///< 'v' modifier static bool Verbose = false; ///< 'v' modifier
static bool Symtab = true; ///< 's' modifier static bool Symtab = true; ///< 's' modifier
static bool Deterministic = true; ///< 'D' and 'U' modifiers
// Relative Positional Argument (for insert/move). This variable holds // Relative Positional Argument (for insert/move). This variable holds
// the name of the archive member to which the 'a', 'b' or 'i' modifier // the name of the archive member to which the 'a', 'b' or 'i' modifier
@@ -245,6 +246,12 @@ static ArchiveOperation parseCommandLine() {
AddBefore = true; AddBefore = true;
NumPositional++; NumPositional++;
break; break;
case 'D':
Deterministic = true;
break;
case 'U':
Deterministic = false;
break;
default: default:
cl::PrintHelpMessage(); cl::PrintHelpMessage();
} }
@@ -570,13 +577,14 @@ performWriteOperation(ArchiveOperation Operation, object::Archive *OldArchive,
} }
if (NewMembersP) { if (NewMembersP) {
std::pair<StringRef, std::error_code> Result = std::pair<StringRef, std::error_code> Result =
writeArchive(ArchiveName, *NewMembersP, Symtab, Kind); writeArchive(ArchiveName, *NewMembersP, Symtab, Kind, Deterministic);
failIfError(Result.second, Result.first); failIfError(Result.second, Result.first);
return; return;
} }
std::vector<NewArchiveIterator> NewMembers = std::vector<NewArchiveIterator> NewMembers =
computeNewArchiveMembers(Operation, OldArchive); computeNewArchiveMembers(Operation, OldArchive);
auto Result = writeArchive(ArchiveName, NewMembers, Symtab, Kind); auto Result =
writeArchive(ArchiveName, NewMembers, Symtab, Kind, Deterministic);
failIfError(Result.second, Result.first); failIfError(Result.second, Result.first);
} }