15 #include "llvm_api/llvm_ar.h"
17 #include <llvm/ADT/StringSwitch.h>
18 #include <llvm/BinaryFormat/Magic.h>
19 #include <llvm/IR/LLVMContext.h>
20 #include <llvm/Object/Archive.h>
21 #include <llvm/Object/ArchiveWriter.h>
22 #include <llvm/Object/SymbolicFile.h>
23 #include <llvm/Support/Chrono.h>
24 #include <llvm/Support/CommandLine.h>
25 #include <llvm/Support/ConvertUTF.h>
26 #include <llvm/Support/Errc.h>
27 #include <llvm/Support/Format.h>
28 #include <llvm/Support/FormatVariadic.h>
29 #include <llvm/Support/MemoryBuffer.h>
30 #include <llvm/Support/Path.h>
31 #include <llvm/Support/TargetSelect.h>
32 #include <llvm/Support/WithColor.h>
33 #include <llvm/Support/raw_ostream.h>
34 #include <llvm/ToolDrivers/llvm-lib/LibDriver.h>
35 #include <llvm/Support/Casting.h>
36 #include <llvm/Object/ObjectFile.h>
37 #include <llvm/Object/MachO.h>
38 #include <llvm/Object/IRObjectFile.h>
39 #include <llvm/Support/Host.h>
41 #if !defined(_MSC_VER) && !defined(__MINGW32__)
45 #include <stringapiset.h>
52 static StringRef ToolName;
53 static unsigned MRILineNumber;
54 static bool ParsingMRIScript;
57 [[noreturn]]
static void fail(Twine Error) {
58 if (ParsingMRIScript) {
59 WithColor::error(errs(), ToolName) <<
"script line " << MRILineNumber <<
": " << Error <<
"\n";
61 WithColor::error(errs(), ToolName) << Error <<
"\n";
67 [[maybe_unused]]
static void failIfError(std::error_code EC, Twine Context =
"") {
71 std::string ContextStr = Context.str();
72 if (ContextStr.empty())
74 fail(Context +
": " + EC.message());
77 static void failIfError(Error E, Twine Context =
"") {
82 handleAllErrors(std::move(E), [&](
const llvm::ErrorInfoBase &EIB) {
83 std::string ContextStr = Context.str();
84 if (ContextStr.empty()) {
87 fail(Context +
": " + EIB.message());
91 static bool Symtab =
true;
92 static bool Deterministic =
true;
98 static std::string RelPos;
101 static std::string ArchiveName;
102 static std::vector<str> Members;
105 inline std::string normalizePath(StringRef Path) {
return std::string(sys::path::filename(Path)); }
107 static bool comparePaths(StringRef Path1, StringRef Path2) {
113 SmallVector<wchar_t, 128> WPath1, WPath2;
114 failIfError(sys::windows::UTF8ToUTF16(normalizePath(Path1), WPath1));
115 failIfError(sys::windows::UTF8ToUTF16(normalizePath(Path2), WPath2));
117 return CompareStringOrdinal(WPath1.data(), WPath1.size(), WPath2.data(), WPath2.size(),
true) == CSTR_EQUAL;
119 return normalizePath(Path1) == normalizePath(Path2);
123 static void addChildMember(std::vector<NewArchiveMember> &members,
const object::Archive::Child &M) {
124 Expected<NewArchiveMember> NMOrErr = NewArchiveMember::getOldMember(M, Deterministic);
125 failIfError(NMOrErr.takeError());
126 members.push_back(std::move(*NMOrErr));
129 static void addMember(std::vector<NewArchiveMember> &members, StringRef FileName) {
130 Expected<NewArchiveMember> NMOrErr = NewArchiveMember::getFile(FileName, Deterministic);
131 failIfError(NMOrErr.takeError(), FileName);
132 NMOrErr->MemberName = sys::path::filename(NMOrErr->MemberName);
133 members.push_back(std::move(*NMOrErr));
136 enum InsertAction { IA_AddOldMember, IA_AddNewMember, IA_MoveOldMember, IA_MoveNewMember };
138 static InsertAction computeInsertAction(StringRef Name, std::vector<str>::iterator &Pos) {
139 auto MI = find_if(Members, [Name](StringRef Path) {
return comparePaths(Name, Path); });
140 if (MI == Members.end()) {
141 return IA_AddOldMember;
144 if (RelPos.empty()) {
145 return IA_AddNewMember;
147 return IA_MoveNewMember;
150 static std::vector<NewArchiveMember> computeNewArchiveMembers(object::Archive *OldArchive) {
153 std::vector<NewArchiveMember> Ret;
154 std::vector<NewArchiveMember> Moved;
157 Error Err = Error::success();
158 for (
auto &Child : OldArchive->children(Err)) {
159 int Pos = (int)Ret.size();
160 Expected<StringRef> NameOrErr = Child.getName();
161 failIfError(NameOrErr.takeError());
162 std::string Name = std::string(NameOrErr.get());
163 if (comparePaths(Name, RelPos)) {
166 auto MemberI = Members.end();
167 InsertAction Action = computeInsertAction(Name, MemberI);
169 case IA_AddOldMember:
170 addChildMember(Ret, Child);
172 case IA_AddNewMember:
173 addMember(Ret, *MemberI);
175 case IA_MoveOldMember:
176 addChildMember(Moved, Child);
178 case IA_MoveNewMember:
179 addMember(Moved, *MemberI);
184 if (MemberI != Members.end()) {
185 Members.erase(MemberI);
188 failIfError(std::move(Err));
191 if (!RelPos.empty() && InsertPos == -1) {
192 fail(
"insertion point not found");
194 if (RelPos.empty()) {
195 InsertPos = (int)Ret.size();
198 assert(
unsigned(InsertPos) <= Ret.size());
200 for (
auto &M : Moved) {
201 Ret.insert(Ret.begin() + Pos, std::move(M));
205 std::vector<NewArchiveMember> NewMembers;
206 for (
auto &Member : Members) {
207 addMember(NewMembers, Member);
209 Ret.reserve(Ret.size() + NewMembers.size());
210 std::move(NewMembers.begin(), NewMembers.end(), std::inserter(Ret, std::next(Ret.begin(), InsertPos)));
214 static object::Archive::Kind getDefaultForHost() {
215 return Triple(sys::getProcessTriple()).isOSDarwin() ? object::Archive::K_DARWIN : object::Archive::K_GNU;
218 static object::Archive::Kind getKindFromMember(
const NewArchiveMember &Member) {
219 auto MemBufferRef = Member.Buf->getMemBufferRef();
220 Expected<std::unique_ptr<object::ObjectFile>> OptionalObject = object::ObjectFile::createObjectFile(MemBufferRef);
222 if (OptionalObject) {
223 return isa<object::MachOObjectFile>(**OptionalObject) ? object::Archive::K_DARWIN : object::Archive::K_GNU;
227 consumeError(OptionalObject.takeError());
232 if (identify_magic(MemBufferRef.getBuffer()) == file_magic::bitcode) {
233 if (
auto ObjOrErr = object::SymbolicFile::createSymbolicFile(MemBufferRef, file_magic::bitcode, &Context)) {
234 auto &IRObject = cast<object::IRObjectFile>(**ObjOrErr);
235 return Triple(IRObject.getTargetTriple()).isOSDarwin() ? object::Archive::K_DARWIN : object::Archive::K_GNU;
238 consumeError(ObjOrErr.takeError());
242 return getDefaultForHost();
245 static void performWriteOperation(object::Archive *OldArchive, std::unique_ptr<MemoryBuffer> OldArchiveBuf) {
246 std::vector<NewArchiveMember> NewMembers = computeNewArchiveMembers(OldArchive);
247 object::Archive::Kind Kind;
249 Kind = OldArchive->kind();
251 Kind = !NewMembers.empty() ? getKindFromMember(NewMembers.front()) : getDefaultForHost();
253 Error E = writeArchive(ArchiveName, NewMembers, Symtab, Kind, Deterministic,
false, std::move(OldArchiveBuf));
254 failIfError(std::move(E), ArchiveName);
257 extern void llvm_ar_create_static_lib(
const str &archive_name,
const vector<str> &objects) {
258 ArchiveName = archive_name;
260 llvm::InitializeAllTargetInfos();
261 llvm::InitializeAllTargetMCs();
262 llvm::InitializeAllAsmParsers();
264 ErrorOr<std::unique_ptr<MemoryBuffer>> Buf = MemoryBuffer::getFile(archive_name, -1,
false);
265 std::error_code EC = Buf.getError();
266 if (EC && EC != errc::no_such_file_or_directory) {
267 fail(
"error opening '" + archive_name +
"': " + EC.message());
270 Error Err = Error::success();
271 object::Archive Archive(Buf.get()->getMemBufferRef(), Err);
272 failIfError(std::move(Err),
"unable to load '" + archive_name +
"'");
273 performWriteOperation(&Archive, std::move(Buf.get()));
276 assert(EC == errc::no_such_file_or_directory);
277 performWriteOperation(
nullptr,
nullptr);