std::pair<StringRef, std::error_code>
writeArchive(StringRef ArcName, std::vector<NewArchiveIterator> &NewMembers,
- bool WriteSymtab, object::Archive::Kind Kind);
+ bool WriteSymtab, object::Archive::Kind Kind, bool Deterministic);
}
#endif
std::pair<StringRef, std::error_code> Result =
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.first.empty())
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.
static ErrorOr<unsigned>
writeSymbolTable(raw_fd_ostream &Out, object::Archive::Kind Kind,
ArrayRef<NewArchiveIterator> Members,
ArrayRef<MemoryBufferRef> Buffers,
- std::vector<unsigned> &MemberOffsetRefs) {
+ std::vector<unsigned> &MemberOffsetRefs, bool Deterministic) {
unsigned HeaderStartOffset = 0;
unsigned BodyStartOffset = 0;
SmallString<128> NameBuf;
if (!HeaderStartOffset) {
HeaderStartOffset = Out.tell();
if (Kind == object::Archive::K_GNU)
- printGNUSmallMemberHeader(Out, "", sys::TimeValue::now(), 0, 0, 0, 0);
+ printGNUSmallMemberHeader(Out, "", now(Deterministic), 0, 0, 0, 0);
else
- printBSDMemberHeader(Out, "__.SYMDEF", sys::TimeValue::now(), 0, 0, 0,
- 0);
+ printBSDMemberHeader(Out, "__.SYMDEF", now(Deterministic), 0, 0, 0, 0);
BodyStartOffset = Out.tell();
print32(Out, Kind, 0); // number of entries or bytes
}
return BodyStartOffset + 4;
}
-std::pair<StringRef, std::error_code>
-llvm::writeArchive(StringRef ArcName,
- std::vector<NewArchiveIterator> &NewMembers,
- bool WriteSymtab, object::Archive::Kind Kind) {
+std::pair<StringRef, std::error_code> llvm::writeArchive(
+ StringRef ArcName, std::vector<NewArchiveIterator> &NewMembers,
+ bool WriteSymtab, object::Archive::Kind Kind, bool Deterministic) {
SmallString<128> TmpArchive;
int TmpArchiveFD;
if (auto EC = sys::fs::createUniqueFile(ArcName + ".temp-archive-%%%%%%%.a",
unsigned MemberReferenceOffset = 0;
if (WriteSymtab) {
- ErrorOr<unsigned> MemberReferenceOffsetOrErr =
- writeSymbolTable(Out, Kind, NewMembers, Members, MemberOffsetRefs);
+ ErrorOr<unsigned> MemberReferenceOffsetOrErr = writeSymbolTable(
+ Out, Kind, NewMembers, Members, MemberOffsetRefs, Deterministic);
if (auto EC = MemberReferenceOffsetOrErr.getError())
return std::make_pair(ArcName, EC);
MemberReferenceOffset = MemberReferenceOffsetOrErr.get();
unsigned Pos = Out.tell();
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()) {
StringRef FileName = I.getNew();
const sys::fs::file_status &Status = NewMemberStatus[NewMemberNum++];
printMemberHeader(Out, Kind, sys::path::filename(FileName),
- StringMapIndexIter, Status.getLastModificationTime(),
- Status.getUser(), Status.getGroup(),
- Status.permissions(), Status.getSize());
+ StringMapIndexIter, ModTime, UID, GID, Perms,
+ Status.getSize());
} else {
object::Archive::child_iterator OldMember = I.getOld();
- printMemberHeader(Out, Kind, I.getName(), StringMapIndexIter,
- OldMember->getLastModified(), OldMember->getUID(),
- OldMember->getGID(), OldMember->getAccessMode(),
- OldMember->getSize());
+ printMemberHeader(Out, Kind, I.getName(), StringMapIndexIter, ModTime,
+ UID, GID, Perms, OldMember->getSize());
}
Out << File.getBuffer();
RUN: echo -n bar. > 0123456789abcde
RUN: echo -n zed. > 0123456789abcdef
-RUN: rm -f test.a
-RUN: llvm-ar --format=gnu rc test.a 0123456789abcde 0123456789abcdef
-RUN: cat test.a | FileCheck -strict-whitespace %s
+RUN: rm -f %t.a
+RUN: llvm-ar --format=gnu rc %t.a 0123456789abcde 0123456789abcdef
+RUN: cat %t.a | FileCheck -strict-whitespace %s
CHECK: !<arch>
CHECK-NEXT: // 18 `
CHECK-NEXT: 0123456789abcdef/
-CHECK-NEXT: 0123456789abcde/{{................................}}4 `
-CHECK-NEXT: bar./0 {{................................}}4 `
+CHECK-NEXT: 0123456789abcde/0 0 0 644 4 `
+CHECK-NEXT: bar./0 0 0 0 644 4 `
CHECK-NEXT: zed.
-RUN: rm -f test-bsd.a
-RUN: llvm-ar --format=bsd rc test-bsd.a 0123456789abcde 0123456789abcdef
-RUN: cat test-bsd.a | FileCheck -strict-whitespace --check-prefix=BSD %s
+RUN: rm -f %t.a
+RUN: llvm-ar --format=bsd rc %t.a 0123456789abcde 0123456789abcdef
+RUN: cat %t.a | FileCheck -strict-whitespace --check-prefix=BSD %s
BSD: !<arch>
-BSD-NEXT: #1/20 {{..............................}} 24 `
+BSD-NEXT: #1/20 0 0 0 644 24 `
BSD-NEXT: 0123456789abcde{{.....}}bar.
-BSD-SAME: #1/16 {{..............................}} 20 `
+BSD-SAME: #1/16 0 0 0 644 20 `
BSD-NEXT: 0123456789abcdefzed.
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: Archive map
CHECK-NEXT: 0000000000000016 T main
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
NOMAP-NOT: Archive map
repeate the test with llvm-ranlib
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-ranlib %t.a
BSD-MachO: _foo in foo.o
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
MACHO: Archive map
Test that we pad the symbol table so that it ends in a multiple of 4 bytes:
8 + 60 + 36 == 104
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
MACHO-SYMTAB-ALIGN: !<arch>
MACHO-SYMTAB-ALIGN-NEXT: #1/12 {{..........}} 0 0 0 36 `
RUN: touch %t.newer/evenlen
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
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
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
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
NEWER: newer
; RUN: rm -f 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: 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
CHECK: 1465 2004-11-19 03:01:31.000000000 very_long_bytecode_file_name.bc
static bool OnlyUpdate = false; ///< 'u' modifier
static bool Verbose = false; ///< 'v' modifier
static bool Symtab = true; ///< 's' modifier
+static bool Deterministic = true; ///< 'D' and 'U' modifiers
// Relative Positional Argument (for insert/move). This variable holds
// the name of the archive member to which the 'a', 'b' or 'i' modifier
AddBefore = true;
NumPositional++;
break;
+ case 'D':
+ Deterministic = true;
+ break;
+ case 'U':
+ Deterministic = false;
+ break;
default:
cl::PrintHelpMessage();
}
}
if (NewMembersP) {
std::pair<StringRef, std::error_code> Result =
- writeArchive(ArchiveName, *NewMembersP, Symtab, Kind);
+ writeArchive(ArchiveName, *NewMembersP, Symtab, Kind, Deterministic);
failIfError(Result.second, Result.first);
return;
}
std::vector<NewArchiveIterator> NewMembers =
computeNewArchiveMembers(Operation, OldArchive);
- auto Result = writeArchive(ArchiveName, NewMembers, Symtab, Kind);
+ auto Result =
+ writeArchive(ArchiveName, NewMembers, Symtab, Kind, Deterministic);
failIfError(Result.second, Result.first);
}