xref: /llvm-project/llvm/lib/ObjCopy/Archive.cpp (revision 54dad9e269f365d0eff2f63c5ee843564eecca7e)
1f75da0c8SAlexey Lapshin //===- Archive.cpp --------------------------------------------------------===//
2f75da0c8SAlexey Lapshin //
3f75da0c8SAlexey Lapshin // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4f75da0c8SAlexey Lapshin // See https://llvm.org/LICENSE.txt for license information.
5f75da0c8SAlexey Lapshin // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f75da0c8SAlexey Lapshin //
7f75da0c8SAlexey Lapshin //===----------------------------------------------------------------------===//
8f75da0c8SAlexey Lapshin 
9f75da0c8SAlexey Lapshin #include "Archive.h"
10f75da0c8SAlexey Lapshin #include "llvm/ObjCopy/CommonConfig.h"
11f75da0c8SAlexey Lapshin #include "llvm/ObjCopy/MultiFormatConfig.h"
12f75da0c8SAlexey Lapshin #include "llvm/ObjCopy/ObjCopy.h"
13f75da0c8SAlexey Lapshin #include "llvm/Object/Error.h"
14f75da0c8SAlexey Lapshin #include "llvm/Support/FileOutputBuffer.h"
15f75da0c8SAlexey Lapshin #include "llvm/Support/SmallVectorMemoryBuffer.h"
16f75da0c8SAlexey Lapshin 
17f75da0c8SAlexey Lapshin namespace llvm {
18f75da0c8SAlexey Lapshin namespace objcopy {
19f75da0c8SAlexey Lapshin 
20f75da0c8SAlexey Lapshin using namespace llvm::object;
21f75da0c8SAlexey Lapshin 
22f75da0c8SAlexey Lapshin Expected<std::vector<NewArchiveMember>>
23f75da0c8SAlexey Lapshin createNewArchiveMembers(const MultiFormatConfig &Config, const Archive &Ar) {
24f75da0c8SAlexey Lapshin   std::vector<NewArchiveMember> NewArchiveMembers;
25f75da0c8SAlexey Lapshin   Error Err = Error::success();
26f75da0c8SAlexey Lapshin   for (const Archive::Child &Child : Ar.children(Err)) {
27f75da0c8SAlexey Lapshin     Expected<StringRef> ChildNameOrErr = Child.getName();
28f75da0c8SAlexey Lapshin     if (!ChildNameOrErr)
29f75da0c8SAlexey Lapshin       return createFileError(Ar.getFileName(), ChildNameOrErr.takeError());
30f75da0c8SAlexey Lapshin 
31f75da0c8SAlexey Lapshin     Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary();
32f75da0c8SAlexey Lapshin     if (!ChildOrErr)
33f75da0c8SAlexey Lapshin       return createFileError(Ar.getFileName() + "(" + *ChildNameOrErr + ")",
34f75da0c8SAlexey Lapshin                              ChildOrErr.takeError());
35f75da0c8SAlexey Lapshin 
36f75da0c8SAlexey Lapshin     SmallVector<char, 0> Buffer;
37f75da0c8SAlexey Lapshin     raw_svector_ostream MemStream(Buffer);
38f75da0c8SAlexey Lapshin 
39f75da0c8SAlexey Lapshin     if (Error E = executeObjcopyOnBinary(Config, *ChildOrErr->get(), MemStream))
40f75da0c8SAlexey Lapshin       return std::move(E);
41f75da0c8SAlexey Lapshin 
42f75da0c8SAlexey Lapshin     Expected<NewArchiveMember> Member = NewArchiveMember::getOldMember(
43f75da0c8SAlexey Lapshin         Child, Config.getCommonConfig().DeterministicArchives);
44f75da0c8SAlexey Lapshin     if (!Member)
45f75da0c8SAlexey Lapshin       return createFileError(Ar.getFileName(), Member.takeError());
46f75da0c8SAlexey Lapshin 
47f75da0c8SAlexey Lapshin     Member->Buf = std::make_unique<SmallVectorMemoryBuffer>(
48f75da0c8SAlexey Lapshin         std::move(Buffer), ChildNameOrErr.get());
49f75da0c8SAlexey Lapshin     Member->MemberName = Member->Buf->getBufferIdentifier();
50f75da0c8SAlexey Lapshin     NewArchiveMembers.push_back(std::move(*Member));
51f75da0c8SAlexey Lapshin   }
52f75da0c8SAlexey Lapshin   if (Err)
53f75da0c8SAlexey Lapshin     return createFileError(Config.getCommonConfig().InputFilename,
54f75da0c8SAlexey Lapshin                            std::move(Err));
55f75da0c8SAlexey Lapshin   return std::move(NewArchiveMembers);
56f75da0c8SAlexey Lapshin }
57f75da0c8SAlexey Lapshin 
58f75da0c8SAlexey Lapshin // For regular archives this function simply calls llvm::writeArchive,
59f75da0c8SAlexey Lapshin // For thin archives it writes the archive file itself as well as its members.
60f75da0c8SAlexey Lapshin static Error deepWriteArchive(StringRef ArcName,
61f75da0c8SAlexey Lapshin                               ArrayRef<NewArchiveMember> NewMembers,
62*f740bcb3Szhijian                               SymtabWritingMode WriteSymtab,
63*f740bcb3Szhijian                               object::Archive::Kind Kind, bool Deterministic,
64*f740bcb3Szhijian                               bool Thin) {
6506624305SKeith Smiley   if (Kind == object::Archive::K_BSD && !NewMembers.empty() &&
6606624305SKeith Smiley       NewMembers.front().detectKindFromObject() == object::Archive::K_DARWIN)
6706624305SKeith Smiley     Kind = object::Archive::K_DARWIN;
6806624305SKeith Smiley 
69f75da0c8SAlexey Lapshin   if (Error E = writeArchive(ArcName, NewMembers, WriteSymtab, Kind,
70f75da0c8SAlexey Lapshin                              Deterministic, Thin))
71f75da0c8SAlexey Lapshin     return createFileError(ArcName, std::move(E));
72f75da0c8SAlexey Lapshin 
73f75da0c8SAlexey Lapshin   if (!Thin)
74f75da0c8SAlexey Lapshin     return Error::success();
75f75da0c8SAlexey Lapshin 
76f75da0c8SAlexey Lapshin   for (const NewArchiveMember &Member : NewMembers) {
77f75da0c8SAlexey Lapshin     // For regular files (as is the case for deepWriteArchive),
78f75da0c8SAlexey Lapshin     // FileOutputBuffer::create will return OnDiskBuffer.
79f75da0c8SAlexey Lapshin     // OnDiskBuffer uses a temporary file and then renames it. So in reality
80f75da0c8SAlexey Lapshin     // there is no inefficiency / duplicated in-memory buffers in this case. For
81f75da0c8SAlexey Lapshin     // now in-memory buffers can not be completely avoided since
82f75da0c8SAlexey Lapshin     // NewArchiveMember still requires them even though writeArchive does not
83f75da0c8SAlexey Lapshin     // write them on disk.
84f75da0c8SAlexey Lapshin     Expected<std::unique_ptr<FileOutputBuffer>> FB =
85f75da0c8SAlexey Lapshin         FileOutputBuffer::create(Member.MemberName, Member.Buf->getBufferSize(),
86f75da0c8SAlexey Lapshin                                  FileOutputBuffer::F_executable);
87f75da0c8SAlexey Lapshin     if (!FB)
88f75da0c8SAlexey Lapshin       return FB.takeError();
89f75da0c8SAlexey Lapshin     std::copy(Member.Buf->getBufferStart(), Member.Buf->getBufferEnd(),
90f75da0c8SAlexey Lapshin               (*FB)->getBufferStart());
91f75da0c8SAlexey Lapshin     if (Error E = (*FB)->commit())
92f75da0c8SAlexey Lapshin       return E;
93f75da0c8SAlexey Lapshin   }
94f75da0c8SAlexey Lapshin   return Error::success();
95f75da0c8SAlexey Lapshin }
96f75da0c8SAlexey Lapshin 
97f75da0c8SAlexey Lapshin Error executeObjcopyOnArchive(const MultiFormatConfig &Config,
98f75da0c8SAlexey Lapshin                               const object::Archive &Ar) {
99f75da0c8SAlexey Lapshin   Expected<std::vector<NewArchiveMember>> NewArchiveMembersOrErr =
100f75da0c8SAlexey Lapshin       createNewArchiveMembers(Config, Ar);
101f75da0c8SAlexey Lapshin   if (!NewArchiveMembersOrErr)
102f75da0c8SAlexey Lapshin     return NewArchiveMembersOrErr.takeError();
103f75da0c8SAlexey Lapshin   const CommonConfig &CommonConfig = Config.getCommonConfig();
104f75da0c8SAlexey Lapshin   return deepWriteArchive(CommonConfig.OutputFilename, *NewArchiveMembersOrErr,
105*f740bcb3Szhijian                           Ar.hasSymbolTable() ? SymtabWritingMode::NormalSymtab
106*f740bcb3Szhijian                                               : SymtabWritingMode::NoSymtab,
107*f740bcb3Szhijian                           Ar.kind(), CommonConfig.DeterministicArchives,
108*f740bcb3Szhijian                           Ar.isThin());
109f75da0c8SAlexey Lapshin }
110f75da0c8SAlexey Lapshin 
111f75da0c8SAlexey Lapshin } // end namespace objcopy
112f75da0c8SAlexey Lapshin } // end namespace llvm
113