| //===- Archive.cpp --------------------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "Archive.h" |
| #include "llvm/ObjCopy/CommonConfig.h" |
| #include "llvm/ObjCopy/MultiFormatConfig.h" |
| #include "llvm/ObjCopy/ObjCopy.h" |
| #include "llvm/Object/Error.h" |
| #include "llvm/Object/MachO.h" |
| #include "llvm/Support/FileOutputBuffer.h" |
| #include "llvm/Support/SmallVectorMemoryBuffer.h" |
| |
| namespace llvm { |
| namespace objcopy { |
| |
| using namespace llvm::object; |
| |
| Expected<std::vector<NewArchiveMember>> |
| createNewArchiveMembers(const MultiFormatConfig &Config, const Archive &Ar) { |
| std::vector<NewArchiveMember> NewArchiveMembers; |
| Error Err = Error::success(); |
| for (const Archive::Child &Child : Ar.children(Err)) { |
| Expected<StringRef> ChildNameOrErr = Child.getName(); |
| if (!ChildNameOrErr) |
| return createFileError(Ar.getFileName(), ChildNameOrErr.takeError()); |
| |
| Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary(); |
| if (!ChildOrErr) |
| return createFileError(Ar.getFileName() + "(" + *ChildNameOrErr + ")", |
| ChildOrErr.takeError()); |
| |
| SmallVector<char, 0> Buffer; |
| raw_svector_ostream MemStream(Buffer); |
| |
| if (Error E = executeObjcopyOnBinary(Config, *ChildOrErr->get(), MemStream)) |
| return std::move(E); |
| |
| Expected<NewArchiveMember> Member = NewArchiveMember::getOldMember( |
| Child, Config.getCommonConfig().DeterministicArchives); |
| if (!Member) |
| return createFileError(Ar.getFileName(), Member.takeError()); |
| |
| Member->Buf = std::make_unique<SmallVectorMemoryBuffer>( |
| std::move(Buffer), ChildNameOrErr.get()); |
| Member->MemberName = Member->Buf->getBufferIdentifier(); |
| NewArchiveMembers.push_back(std::move(*Member)); |
| } |
| if (Err) |
| return createFileError(Config.getCommonConfig().InputFilename, |
| std::move(Err)); |
| return std::move(NewArchiveMembers); |
| } |
| |
| // For regular archives this function simply calls llvm::writeArchive, |
| // For thin archives it writes the archive file itself as well as its members. |
| static Error deepWriteArchive(StringRef ArcName, |
| ArrayRef<NewArchiveMember> NewMembers, |
| bool WriteSymtab, object::Archive::Kind Kind, |
| bool Deterministic, bool Thin) { |
| if (Kind == object::Archive::K_BSD && !NewMembers.empty() && |
| NewMembers.front().detectKindFromObject() == object::Archive::K_DARWIN) |
| Kind = object::Archive::K_DARWIN; |
| |
| if (Error E = writeArchive(ArcName, NewMembers, WriteSymtab, Kind, |
| Deterministic, Thin)) |
| return createFileError(ArcName, std::move(E)); |
| |
| if (!Thin) |
| return Error::success(); |
| |
| for (const NewArchiveMember &Member : NewMembers) { |
| // For regular files (as is the case for deepWriteArchive), |
| // FileOutputBuffer::create will return OnDiskBuffer. |
| // OnDiskBuffer uses a temporary file and then renames it. So in reality |
| // there is no inefficiency / duplicated in-memory buffers in this case. For |
| // now in-memory buffers can not be completely avoided since |
| // NewArchiveMember still requires them even though writeArchive does not |
| // write them on disk. |
| Expected<std::unique_ptr<FileOutputBuffer>> FB = |
| FileOutputBuffer::create(Member.MemberName, Member.Buf->getBufferSize(), |
| FileOutputBuffer::F_executable); |
| if (!FB) |
| return FB.takeError(); |
| std::copy(Member.Buf->getBufferStart(), Member.Buf->getBufferEnd(), |
| (*FB)->getBufferStart()); |
| if (Error E = (*FB)->commit()) |
| return E; |
| } |
| return Error::success(); |
| } |
| |
| Error executeObjcopyOnArchive(const MultiFormatConfig &Config, |
| const object::Archive &Ar) { |
| Expected<std::vector<NewArchiveMember>> NewArchiveMembersOrErr = |
| createNewArchiveMembers(Config, Ar); |
| if (!NewArchiveMembersOrErr) |
| return NewArchiveMembersOrErr.takeError(); |
| const CommonConfig &CommonConfig = Config.getCommonConfig(); |
| return deepWriteArchive(CommonConfig.OutputFilename, *NewArchiveMembersOrErr, |
| Ar.hasSymbolTable(), Ar.kind(), |
| CommonConfig.DeterministicArchives, Ar.isThin()); |
| } |
| |
| } // end namespace objcopy |
| } // end namespace llvm |