LibDriver.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. //===- LibDriver.cpp - lib.exe-compatible driver --------------------------===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. //
  10. // Defines an interface to a lib.exe-compatible driver that also understands
  11. // bitcode files. Used by llvm-lib and lld-link /lib.
  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. using namespace llvm;
  27. namespace {
  28. enum {
  29. OPT_INVALID = 0,
  30. #define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID,
  31. #include "Options.inc"
  32. #undef OPTION
  33. };
  34. #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
  35. #include "Options.inc"
  36. #undef PREFIX
  37. static const llvm::opt::OptTable::Info InfoTable[] = {
  38. #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \
  39. {X1, X2, X10, X11, OPT_##ID, llvm::opt::Option::KIND##Class, \
  40. X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12},
  41. #include "Options.inc"
  42. #undef OPTION
  43. };
  44. class LibOptTable : public llvm::opt::OptTable {
  45. public:
  46. LibOptTable() : OptTable(InfoTable, true) {}
  47. };
  48. }
  49. static std::string getOutputPath(llvm::opt::InputArgList *Args,
  50. const llvm::NewArchiveMember &FirstMember) {
  51. if (auto *Arg = Args->getLastArg(OPT_out))
  52. return Arg->getValue();
  53. SmallString<128> Val = StringRef(FirstMember.Buf->getBufferIdentifier());
  54. llvm::sys::path::replace_extension(Val, ".lib");
  55. return Val.str();
  56. }
  57. static std::vector<StringRef> getSearchPaths(llvm::opt::InputArgList *Args,
  58. StringSaver &Saver) {
  59. std::vector<StringRef> Ret;
  60. // Add current directory as first item of the search path.
  61. Ret.push_back("");
  62. // Add /libpath flags.
  63. for (auto *Arg : Args->filtered(OPT_libpath))
  64. Ret.push_back(Arg->getValue());
  65. // Add $LIB.
  66. Optional<std::string> EnvOpt = sys::Process::GetEnv("LIB");
  67. if (!EnvOpt.hasValue())
  68. return Ret;
  69. StringRef Env = Saver.save(*EnvOpt);
  70. while (!Env.empty()) {
  71. StringRef Path;
  72. std::tie(Path, Env) = Env.split(';');
  73. Ret.push_back(Path);
  74. }
  75. return Ret;
  76. }
  77. static Optional<std::string> findInputFile(StringRef File,
  78. ArrayRef<StringRef> Paths) {
  79. for (auto Dir : Paths) {
  80. SmallString<128> Path = Dir;
  81. sys::path::append(Path, File);
  82. if (sys::fs::exists(Path))
  83. return Path.str().str();
  84. }
  85. return Optional<std::string>();
  86. }
  87. int llvm::libDriverMain(llvm::ArrayRef<const char*> ArgsArr) {
  88. SmallVector<const char *, 20> NewArgs(ArgsArr.begin(), ArgsArr.end());
  89. BumpPtrAllocator Alloc;
  90. StringSaver Saver(Alloc);
  91. cl::ExpandResponseFiles(Saver, cl::TokenizeWindowsCommandLine, NewArgs);
  92. ArgsArr = NewArgs;
  93. LibOptTable Table;
  94. unsigned MissingIndex;
  95. unsigned MissingCount;
  96. llvm::opt::InputArgList Args =
  97. Table.ParseArgs(ArgsArr.slice(1), MissingIndex, MissingCount);
  98. if (MissingCount) {
  99. llvm::errs() << "missing arg value for \""
  100. << Args.getArgString(MissingIndex) << "\", expected "
  101. << MissingCount
  102. << (MissingCount == 1 ? " argument.\n" : " arguments.\n");
  103. return 1;
  104. }
  105. for (auto *Arg : Args.filtered(OPT_UNKNOWN))
  106. llvm::errs() << "ignoring unknown argument: " << Arg->getSpelling() << "\n";
  107. if (!Args.hasArgNoClaim(OPT_INPUT)) {
  108. // No input files. To match lib.exe, silently do nothing.
  109. return 0;
  110. }
  111. std::vector<StringRef> SearchPaths = getSearchPaths(&Args, Saver);
  112. std::vector<llvm::NewArchiveMember> Members;
  113. for (auto *Arg : Args.filtered(OPT_INPUT)) {
  114. Optional<std::string> Path = findInputFile(Arg->getValue(), SearchPaths);
  115. if (!Path.hasValue()) {
  116. llvm::errs() << Arg->getValue() << ": no such file or directory\n";
  117. return 1;
  118. }
  119. Expected<NewArchiveMember> MOrErr =
  120. NewArchiveMember::getFile(Saver.save(*Path), /*Deterministic=*/true);
  121. if (!MOrErr) {
  122. handleAllErrors(MOrErr.takeError(), [&](const llvm::ErrorInfoBase &EIB) {
  123. llvm::errs() << Arg->getValue() << ": " << EIB.message() << "\n";
  124. });
  125. return 1;
  126. }
  127. llvm::file_magic Magic = llvm::identify_magic(MOrErr->Buf->getBuffer());
  128. if (Magic != llvm::file_magic::coff_object &&
  129. Magic != llvm::file_magic::bitcode &&
  130. Magic != llvm::file_magic::windows_resource) {
  131. llvm::errs() << Arg->getValue()
  132. << ": not a COFF object, bitcode or resource file\n";
  133. return 1;
  134. }
  135. Members.emplace_back(std::move(*MOrErr));
  136. }
  137. std::string OutputPath = getOutputPath(&Args, Members[0]);
  138. std::error_code EC =
  139. llvm::writeArchive(OutputPath, Members,
  140. /*WriteSymtab=*/true, object::Archive::K_GNU,
  141. /*Deterministic*/ true, Args.hasArg(OPT_llvmlibthin));
  142. if (EC) {
  143. llvm::errs() << OutputPath << ": " << EC.message() << "\n";
  144. return 1;
  145. }
  146. return 0;
  147. }