1 //===- LibDriver.cpp - lib.exe-compatible driver --------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Defines an interface to a lib.exe-compatible driver that also understands 10 // bitcode files. Used by llvm-lib and lld-link /lib. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/ToolDrivers/llvm-lib/LibDriver.h" 15 #include "llvm/ADT/STLExtras.h" 16 #include "llvm/BinaryFormat/Magic.h" 17 #include "llvm/Object/ArchiveWriter.h" 18 #include "llvm/Option/Arg.h" 19 #include "llvm/Option/ArgList.h" 20 #include "llvm/Option/Option.h" 21 #include "llvm/Support/CommandLine.h" 22 #include "llvm/Support/Path.h" 23 #include "llvm/Support/Process.h" 24 #include "llvm/Support/StringSaver.h" 25 #include "llvm/Support/raw_ostream.h" 26 27 using namespace llvm; 28 29 namespace { 30 31 enum { 32 OPT_INVALID = 0, 33 #define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID, 34 #include "Options.inc" 35 #undef OPTION 36 }; 37 38 #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; 39 #include "Options.inc" 40 #undef PREFIX 41 42 static const opt::OptTable::Info InfoTable[] = { 43 #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \ 44 {X1, X2, X10, X11, OPT_##ID, opt::Option::KIND##Class, \ 45 X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12}, 46 #include "Options.inc" 47 #undef OPTION 48 }; 49 50 class LibOptTable : public opt::OptTable { 51 public: 52 LibOptTable() : OptTable(InfoTable, true) {} 53 }; 54 55 } 56 57 static std::string getOutputPath(opt::InputArgList *Args, 58 const NewArchiveMember &FirstMember) { 59 if (auto *Arg = Args->getLastArg(OPT_out)) 60 return Arg->getValue(); 61 SmallString<128> Val = StringRef(FirstMember.Buf->getBufferIdentifier()); 62 sys::path::replace_extension(Val, ".lib"); 63 return Val.str(); 64 } 65 66 static std::vector<StringRef> getSearchPaths(opt::InputArgList *Args, 67 StringSaver &Saver) { 68 std::vector<StringRef> Ret; 69 // Add current directory as first item of the search path. 70 Ret.push_back(""); 71 72 // Add /libpath flags. 73 for (auto *Arg : Args->filtered(OPT_libpath)) 74 Ret.push_back(Arg->getValue()); 75 76 // Add $LIB. 77 Optional<std::string> EnvOpt = sys::Process::GetEnv("LIB"); 78 if (!EnvOpt.hasValue()) 79 return Ret; 80 StringRef Env = Saver.save(*EnvOpt); 81 while (!Env.empty()) { 82 StringRef Path; 83 std::tie(Path, Env) = Env.split(';'); 84 Ret.push_back(Path); 85 } 86 return Ret; 87 } 88 89 static std::string findInputFile(StringRef File, ArrayRef<StringRef> Paths) { 90 for (StringRef Dir : Paths) { 91 SmallString<128> Path = Dir; 92 sys::path::append(Path, File); 93 if (sys::fs::exists(Path)) 94 return Path.str().str(); 95 } 96 return ""; 97 } 98 99 int llvm::libDriverMain(ArrayRef<const char *> ArgsArr) { 100 BumpPtrAllocator Alloc; 101 StringSaver Saver(Alloc); 102 103 // Parse command line arguments. 104 SmallVector<const char *, 20> NewArgs(ArgsArr.begin(), ArgsArr.end()); 105 cl::ExpandResponseFiles(Saver, cl::TokenizeWindowsCommandLine, NewArgs); 106 ArgsArr = NewArgs; 107 108 LibOptTable Table; 109 unsigned MissingIndex; 110 unsigned MissingCount; 111 opt::InputArgList Args = 112 Table.ParseArgs(ArgsArr.slice(1), MissingIndex, MissingCount); 113 if (MissingCount) { 114 llvm::errs() << "missing arg value for \"" 115 << Args.getArgString(MissingIndex) << "\", expected " 116 << MissingCount 117 << (MissingCount == 1 ? " argument.\n" : " arguments.\n"); 118 return 1; 119 } 120 for (auto *Arg : Args.filtered(OPT_UNKNOWN)) 121 llvm::errs() << "ignoring unknown argument: " << Arg->getSpelling() << "\n"; 122 123 // Handle /help 124 if (Args.hasArg(OPT_help)) { 125 Table.PrintHelp(outs(), "llvm-lib [options] file...", "LLVM Lib"); 126 return 0; 127 } 128 129 // If no input files, silently do nothing to match lib.exe. 130 if (!Args.hasArgNoClaim(OPT_INPUT)) 131 return 0; 132 133 std::vector<StringRef> SearchPaths = getSearchPaths(&Args, Saver); 134 135 // Create a NewArchiveMember for each input file. 136 std::vector<NewArchiveMember> Members; 137 for (auto *Arg : Args.filtered(OPT_INPUT)) { 138 std::string Path = findInputFile(Arg->getValue(), SearchPaths); 139 if (Path.empty()) { 140 llvm::errs() << Arg->getValue() << ": no such file or directory\n"; 141 return 1; 142 } 143 144 Expected<NewArchiveMember> MOrErr = 145 NewArchiveMember::getFile(Saver.save(Path), /*Deterministic=*/true); 146 if (!MOrErr) { 147 handleAllErrors(MOrErr.takeError(), [&](const ErrorInfoBase &EIB) { 148 llvm::errs() << Arg->getValue() << ": " << EIB.message() << "\n"; 149 }); 150 return 1; 151 } 152 153 file_magic Magic = identify_magic(MOrErr->Buf->getBuffer()); 154 if (Magic != file_magic::coff_object && Magic != file_magic::bitcode && 155 Magic != file_magic::windows_resource) { 156 llvm::errs() << Arg->getValue() 157 << ": not a COFF object, bitcode or resource file\n"; 158 return 1; 159 } 160 Members.emplace_back(std::move(*MOrErr)); 161 } 162 163 // Create an archive file. 164 std::string OutputPath = getOutputPath(&Args, Members[0]); 165 if (Error E = 166 writeArchive(OutputPath, Members, 167 /*WriteSymtab=*/true, object::Archive::K_GNU, 168 /*Deterministic*/ true, Args.hasArg(OPT_llvmlibthin))) { 169 handleAllErrors(std::move(E), [&](const ErrorInfoBase &EI) { 170 llvm::errs() << OutputPath << ": " << EI.message() << "\n"; 171 }); 172 return 1; 173 } 174 175 return 0; 176 } 177