Start adding support for writing archives in BSD format.
authorRafael Espindola <rafael.espindola@gmail.com>
Wed, 8 Jul 2015 20:47:32 +0000 (20:47 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Wed, 8 Jul 2015 20:47:32 +0000 (20:47 +0000)
No support for the symbol table yet (but will hopefully add it today).
We always use the long filename format so that we can align the member,
which is an advantage of the BSD format.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@241721 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Object/ArchiveWriter.h
lib/LibDriver/LibDriver.cpp
lib/Object/ArchiveWriter.cpp
test/Object/archive-format.test
tools/llvm-ar/llvm-ar.cpp

index 1616e46d3e6fb9a63569645d775f8fcf6c115b09..b6edf5882dbf6494b41f82644b3c93ff64466446 100644 (file)
@@ -44,8 +44,7 @@ public:
 
 std::pair<StringRef, std::error_code>
 writeArchive(StringRef ArcName, std::vector<NewArchiveIterator> &NewMembers,
-             bool WriteSymtab);
-
+             bool WriteSymtab, object::Archive::Kind Kind);
 }
 
 #endif
index bc3ed46040ceae9f2662ebeb6600c3205ec6cc9d..4a9fa28c84a348b18edb1e1be5c137dbab093478 100644 (file)
@@ -139,8 +139,10 @@ int llvm::libDriverMain(llvm::ArrayRef<const char*> ArgsArr) {
                          llvm::sys::path::filename(Arg->getValue()));
   }
 
-  std::pair<StringRef, std::error_code> Result = llvm::writeArchive(
-      getOutputPath(&Args, Members[0]), Members, /*WriteSymtab=*/true);
+  std::pair<StringRef, std::error_code> Result =
+      llvm::writeArchive(getOutputPath(&Args, Members[0]), Members,
+                         /*WriteSymtab=*/true, object::Archive::K_GNU);
+
   if (Result.second) {
     if (Result.first.empty())
       Result.first = ArgsArr[0];
index 41c82e7da74da8b6354fe906ba4908b93fb6bbb2..99706a9bd5bbac07f683412906d2da32c1436f2b 100644 (file)
@@ -117,10 +117,25 @@ static void printMemberHeader(raw_fd_ostream &Out, StringRef Name,
 }
 
 static void
-printMemberHeader(raw_fd_ostream &Out, StringRef Name,
+printMemberHeader(raw_fd_ostream &Out, object::Archive::Kind Kind,
+                  StringRef Name,
                   std::vector<unsigned>::iterator &StringMapIndexIter,
                   const sys::TimeValue &ModTime, unsigned UID, unsigned GID,
                   unsigned Perms, unsigned Size) {
+  if (Kind == object::Archive::K_BSD) {
+    uint64_t PosAfterHeader = Out.tell() + 60 + Name.size();
+    // Pad so that even 64 bit object files are aligned.
+    unsigned Pad = OffsetToAlignment(PosAfterHeader, 8);
+    unsigned NameWithPadding = Name.size() + Pad;
+    printWithSpacePadding(Out, Twine("#1/") + Twine(NameWithPadding), 16);
+    printRestOfMemberHeader(Out, ModTime, UID, GID, Perms,
+                            NameWithPadding + Size);
+    Out << Name;
+    assert(PosAfterHeader == Out.tell());
+    while (Pad--)
+      Out.write(uint8_t(0));
+    return;
+  }
   if (Name.size() < 16) {
     printMemberHeader(Out, Name, ModTime, UID, GID, Perms, Size);
     return;
@@ -160,9 +175,13 @@ static void writeStringTable(raw_fd_ostream &Out,
 
 // Returns the offset of the first reference to a member offset.
 static ErrorOr<unsigned>
-writeSymbolTable(raw_fd_ostream &Out, ArrayRef<NewArchiveIterator> Members,
+writeSymbolTable(raw_fd_ostream &Out, object::Archive::Kind Kind,
+                 ArrayRef<NewArchiveIterator> Members,
                  ArrayRef<MemoryBufferRef> Buffers,
                  std::vector<unsigned> &MemberOffsetRefs) {
+  if (Kind != object::Archive::K_GNU)
+    return 0;
+
   unsigned StartOffset = 0;
   unsigned MemberNum = 0;
   std::string NameBuf;
@@ -222,7 +241,7 @@ writeSymbolTable(raw_fd_ostream &Out, ArrayRef<NewArchiveIterator> Members,
 std::pair<StringRef, std::error_code>
 llvm::writeArchive(StringRef ArcName,
                    std::vector<NewArchiveIterator> &NewMembers,
-                   bool WriteSymtab) {
+                   bool WriteSymtab, object::Archive::Kind Kind) {
   SmallString<128> TmpArchive;
   int TmpArchiveFD;
   if (auto EC = sys::fs::createUniqueFile(ArcName + ".temp-archive-%%%%%%%.a",
@@ -274,14 +293,15 @@ llvm::writeArchive(StringRef ArcName,
   unsigned MemberReferenceOffset = 0;
   if (WriteSymtab) {
     ErrorOr<unsigned> MemberReferenceOffsetOrErr =
-        writeSymbolTable(Out, NewMembers, Members, MemberOffsetRefs);
+        writeSymbolTable(Out, Kind, NewMembers, Members, MemberOffsetRefs);
     if (auto EC = MemberReferenceOffsetOrErr.getError())
       return std::make_pair(ArcName, EC);
     MemberReferenceOffset = MemberReferenceOffsetOrErr.get();
   }
 
   std::vector<unsigned> StringMapIndexes;
-  writeStringTable(Out, NewMembers, StringMapIndexes);
+  if (Kind != object::Archive::K_BSD)
+    writeStringTable(Out, NewMembers, StringMapIndexes);
 
   unsigned MemberNum = 0;
   unsigned NewMemberNum = 0;
@@ -296,13 +316,13 @@ llvm::writeArchive(StringRef ArcName,
     if (I.isNewMember()) {
       StringRef FileName = I.getNew();
       const sys::fs::file_status &Status = NewMemberStatus[NewMemberNum++];
-      printMemberHeader(Out, sys::path::filename(FileName), StringMapIndexIter,
-                        Status.getLastModificationTime(), Status.getUser(),
-                        Status.getGroup(), Status.permissions(),
-                        Status.getSize());
+      printMemberHeader(Out, Kind, sys::path::filename(FileName),
+                        StringMapIndexIter, Status.getLastModificationTime(),
+                        Status.getUser(), Status.getGroup(),
+                        Status.permissions(), Status.getSize());
     } else {
       object::Archive::child_iterator OldMember = I.getOld();
-      printMemberHeader(Out, I.getName(), StringMapIndexIter,
+      printMemberHeader(Out, Kind, I.getName(), StringMapIndexIter,
                         OldMember->getLastModified(), OldMember->getUID(),
                         OldMember->getGID(), OldMember->getAccessMode(),
                         OldMember->getSize());
index f076123d2ea18feb362deb6d956525bf751423f6..951177256b6dbfce8deb7bae585cdfa7a099155a 100644 (file)
@@ -17,3 +17,13 @@ CHECK-NEXT: 0123456789abcdef/
 CHECK-NEXT: 0123456789abcde/{{................................}}4         `
 CHECK-NEXT: bar./0              {{................................}}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
+
+BSD:      !<arch>
+BSD-NEXT: #1/20           {{..............................}}  24        `
+BSD-NEXT: 0123456789abcde{{.....}}bar.
+BSD-SAME: #1/16           {{..............................}}  20        `
+BSD-NEXT: 0123456789abcdefzed.
index 0fd2df4f5aa92eae7e539d92e8fc229ca5046ffe..872c548454ee2686f17290af46e3df39733082a5 100644 (file)
@@ -70,6 +70,16 @@ static cl::list<std::string>
 
 static cl::opt<bool> MRI("M", cl::desc(""));
 
+namespace {
+enum Format { Default, GNU, BSD };
+}
+
+static cl::opt<Format>
+    FormatOpt("format", cl::desc("Archive format to create"),
+              cl::values(clEnumValN(Default, "defalut", "default"),
+                         clEnumValN(GNU, "gnu", "gnu"),
+                         clEnumValN(BSD, "bsd", "bsd"), clEnumValEnd));
+
 std::string Options;
 
 // Provide additional help output explaining the operations and modifiers of
@@ -539,15 +549,27 @@ computeNewArchiveMembers(ArchiveOperation Operation,
 static void
 performWriteOperation(ArchiveOperation Operation, object::Archive *OldArchive,
                       std::vector<NewArchiveIterator> *NewMembersP) {
+  object::Archive::Kind Kind;
+  switch (FormatOpt) {
+  case Default:
+    // FIXME: change as the support for other formats improve.
+    Kind = object::Archive::K_GNU;
+  case GNU:
+    Kind = object::Archive::K_GNU;
+    break;
+  case BSD:
+    Kind = object::Archive::K_BSD;
+    break;
+  }
   if (NewMembersP) {
     std::pair<StringRef, std::error_code> Result =
-        writeArchive(ArchiveName, *NewMembersP, Symtab);
+        writeArchive(ArchiveName, *NewMembersP, Symtab, Kind);
     failIfError(Result.second, Result.first);
     return;
   }
   std::vector<NewArchiveIterator> NewMembers =
       computeNewArchiveMembers(Operation, OldArchive);
-  auto Result = writeArchive(ArchiveName, NewMembers, Symtab);
+  auto Result = writeArchive(ArchiveName, NewMembers, Symtab, Kind);
   failIfError(Result.second, Result.first);
 }