Index: test/tools/llvm-ar/Inputs/add-lib1.yaml =================================================================== --- test/tools/llvm-ar/Inputs/add-lib1.yaml +++ test/tools/llvm-ar/Inputs/add-lib1.yaml @@ -0,0 +1,30 @@ +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x0000000000000004 + Content: '' + - Name: .comment + Type: SHT_PROGBITS + Flags: [ SHF_MERGE, SHF_STRINGS ] + AddressAlign: 0x0000000000000001 + Content: 00636C616E672076657273696F6E20332E392E3020287472756E6B203237333632342920286C6C766D2F7472756E6B203237333633362900 + - Name: .note.GNU-stack + Type: SHT_PROGBITS + AddressAlign: 0x0000000000000001 + Content: '' +Symbols: + Global: + - Name: lib1 + Index: SHN_ABS + Value: 0x1234 + Local: + - Name: '-' + Type: STT_FILE +... Index: test/tools/llvm-ar/Inputs/add-lib2.yaml =================================================================== --- test/tools/llvm-ar/Inputs/add-lib2.yaml +++ test/tools/llvm-ar/Inputs/add-lib2.yaml @@ -0,0 +1,30 @@ +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x0000000000000004 + Content: '' + - Name: .comment + Type: SHT_PROGBITS + Flags: [ SHF_MERGE, SHF_STRINGS ] + AddressAlign: 0x0000000000000001 + Content: 00636C616E672076657273696F6E20332E392E3020287472756E6B203237333632342920286C6C766D2F7472756E6B203237333633362900 + - Name: .note.GNU-stack + Type: SHT_PROGBITS + AddressAlign: 0x0000000000000001 + Content: '' +Symbols: + Global: + - Name: lib2 + Index: SHN_ABS + Value: 0x1234 + Local: + - Name: '-' + Type: STT_FILE +... Index: test/tools/llvm-ar/Inputs/add-lib3.yaml =================================================================== --- test/tools/llvm-ar/Inputs/add-lib3.yaml +++ test/tools/llvm-ar/Inputs/add-lib3.yaml @@ -0,0 +1,30 @@ +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x0000000000000004 + Content: '' + - Name: .comment + Type: SHT_PROGBITS + Flags: [ SHF_MERGE, SHF_STRINGS ] + AddressAlign: 0x0000000000000001 + Content: 00636C616E672076657273696F6E20332E392E3020287472756E6B203237333632342920286C6C766D2F7472756E6B203237333633362900 + - Name: .note.GNU-stack + Type: SHT_PROGBITS + AddressAlign: 0x0000000000000001 + Content: '' +Symbols: + Global: + - Name: lib3 + Index: SHN_ABS + Value: 0x1234 + Local: + - Name: '-' + Type: STT_FILE +... Index: test/tools/llvm-ar/add-library.test =================================================================== --- test/tools/llvm-ar/add-library.test +++ test/tools/llvm-ar/add-library.test @@ -0,0 +1,43 @@ +RUN: yaml2obj %S/Inputs/add-lib1.yaml -o %t-add-lib1.o +RUN: yaml2obj %S/Inputs/add-lib2.yaml -o %t-add-lib2.o +RUN: yaml2obj %S/Inputs/add-lib2.yaml -o %t-add-lib3.o + +RUN: rm -f %t.ar +RUN: llvm-ar crs %t.ar %t-add-lib1.o +RUN: llvm-ar cqs %t.ar %t-add-lib2.o + +RUN: llvm-ar tv %t.ar | FileCheck %s --check-prefix=CHECK-NAMES-NO-ADDLIB +CHECK-NAMES-NO-ADDLIB: add-library.test.tmp-add-lib1.o +CHECK-NAMES-NO-ADDLIB: add-library.test.tmp-add-lib2.o + +RUN: llvm-nm %t.ar | FileCheck %s --check-prefix=CHECK-SYMBOLS-NO-ADDLIB +CHECK-SYMBOLS-NO-ADDLIB: add-lib1 +CHECK-SYMBOLS-NO-ADDLIB: add-lib2 + +RUN: rm -f %t1.ar +RUN: llvm-ar crs %t1.ar %t-add-lib3.o +RUN: llvm-ar cqLs %t1.ar %t.ar + +RUN: llvm-ar tv %t1.ar | FileCheck %s --check-prefix=CHECK-NAMES-ADDLIB +CHECK-NAMES-ADDLIB: add-library.test.tmp-add-lib3.o +CHECK-NAMES-ADDLIB: add-library.test.tmp-add-lib1.o +CHECK-NAMES-ADDLIB: add-library.test.tmp-add-lib2.o + +RUN: llvm-nm %t1.ar | FileCheck %s --check-prefix=CHECK-SYMBOLS-ADDLIB +CHECK-SYMBOLS-ADDLIB: add-lib3 +CHECK-SYMBOLS-ADDLIB: add-lib1 +CHECK-SYMBOLS-ADDLIB: add-lib2 + +RUN: llvm-ar cqLs %t1.ar %t-add-lib1.o + +RUN: llvm-ar tv %t1.ar | FileCheck %s --check-prefix=CHECK-NAMES-DUPLICATE +CHECK-NAMES-DUPLICATE: add-library.test.tmp-add-lib3.o +CHECK-NAMES-DUPLICATE: add-library.test.tmp-add-lib1.o +CHECK-NAMES-DUPLICATE: add-library.test.tmp-add-lib2.o +CHECK-NAMES-DUPLICATE: add-library.test.tmp-add-lib1.o + +RUN: llvm-nm %t1.ar | FileCheck %s --check-prefix=CHECK-SYMBOLS-DUPLICATE +CHECK-SYMBOLS-DUPLICATE: add-lib3 +CHECK-SYMBOLS-DUPLICATE: add-lib1 +CHECK-SYMBOLS-DUPLICATE: add-lib2 +CHECK-SYMBOLS-DUPLICATE: add-lib1 Index: tools/llvm-ar/llvm-ar.cpp =================================================================== --- tools/llvm-ar/llvm-ar.cpp +++ tools/llvm-ar/llvm-ar.cpp @@ -96,6 +96,7 @@ [D] - use zero for timestamps and uids/gids (default) [i] - put [files] before [relpos] (same as [b]) [l] - ignored for compatibility + [L] - add archive's contents [o] - preserve original dates [s] - create an archive index (cf. ranlib) [S] - do not build a symbol table @@ -176,6 +177,7 @@ static bool Symtab = true; ///< 's' modifier static bool Deterministic = true; ///< 'D' and 'U' modifiers static bool Thin = false; ///< 'T' modifier +static bool AddLibrary = false; ///< 'L' modifier // Relative Positional Argument (for insert/move). This variable holds // the name of the archive member to which the 'a', 'b' or 'i' modifier @@ -214,6 +216,21 @@ Members.push_back(Arg); } +std::vector> ArchiveBuffers; +std::vector> Archives; + +static object::Archive &readLibrary(const Twine &Library) { + auto BufOrErr = MemoryBuffer::getFile(Library, -1, false); + failIfError(BufOrErr.getError(), "Could not open library"); + ArchiveBuffers.push_back(std::move(*BufOrErr)); + auto LibOrErr = + object::Archive::create(ArchiveBuffers.back()->getMemBufferRef()); + failIfError(errorToErrorCode(LibOrErr.takeError()), + "Could not parse library"); + Archives.push_back(std::move(*LibOrErr)); + return *Archives.back(); +} + static void runMRIScript(); // Parse the command line options as presented and return the operation @@ -284,6 +301,9 @@ case 'T': Thin = true; break; + case 'L': + AddLibrary = true; + break; default: fail(std::string("unknown option ") + Options[i]); } @@ -320,6 +340,8 @@ fail("The 'o' modifier is only applicable to the 'x' operation"); if (OnlyUpdate && Operation != ReplaceOrInsert) fail("The 'u' modifier is only applicable to the 'r' operation"); + if (AddLibrary && Operation != QuickAppend) + fail("The 'L' modifier is only applicable to the 'q' operation"); // Return the parsed operation to the caller return Operation; @@ -512,6 +534,26 @@ Members[Pos] = std::move(*NMOrErr); } +static void addLibMember(std::vector &Members, + StringRef FileName) { + Expected NMOrErr = + NewArchiveMember::getFile(FileName, Deterministic); + failIfError(NMOrErr.takeError(), FileName); + if (identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) { + object::Archive &Lib = readLibrary(FileName); + Error Err = Error::success(); + + for (auto &Child : Lib.children(Err)) + addMember(Members, Child); + + failIfError(std::move(Err)); + } else { + // Use the basename of the object path for the member name. + NMOrErr->MemberName = sys::path::filename(NMOrErr->MemberName); + Members.push_back(std::move(*NMOrErr)); + } +} + enum InsertAction { IA_AddOldMember, IA_AddNewMember, @@ -634,6 +676,14 @@ ++Pos; } + if (AddLibrary) { + assert(Operation == QuickAppend); + for (auto &Member : Members) { + addLibMember(Ret, Member); + } + return Ret; + } + for (unsigned I = 0; I != Members.size(); ++I) Ret.insert(Ret.begin() + InsertPos, NewArchiveMember()); Pos = InsertPos; @@ -791,8 +841,6 @@ const MemoryBuffer &Ref = *Buf.get(); bool Saved = false; std::vector NewMembers; - std::vector> ArchiveBuffers; - std::vector> Archives; for (line_iterator I(Ref, /*SkipBlanks*/ false), E; I != E; ++I) { StringRef Line = *I; @@ -817,15 +865,7 @@ switch (Command) { case MRICommand::AddLib: { - auto BufOrErr = MemoryBuffer::getFile(Rest, -1, false); - failIfError(BufOrErr.getError(), "Could not open library"); - ArchiveBuffers.push_back(std::move(*BufOrErr)); - auto LibOrErr = - object::Archive::create(ArchiveBuffers.back()->getMemBufferRef()); - failIfError(errorToErrorCode(LibOrErr.takeError()), - "Could not parse library"); - Archives.push_back(std::move(*LibOrErr)); - object::Archive &Lib = *Archives.back(); + object::Archive &Lib = readLibrary(Rest); { Error Err = Error::success(); for (auto &Member : Lib.children(Err))