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);