Home | History | Annotate | Download | only in LibDriver
      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 
     15 #include "llvm/LibDriver/LibDriver.h"
     16 #include "llvm/ADT/STLExtras.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/StringSaver.h"
     23 #include "llvm/Support/Path.h"
     24 #include "llvm/Support/Process.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) 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 llvm::opt::OptTable::Info infoTable[] = {
     43 #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X6, X7, X8, X9, X10)    \
     44   {                                                                    \
     45     X1, X2, X9, X10, OPT_##ID, llvm::opt::Option::KIND##Class, X8, X7, \
     46     OPT_##GROUP, OPT_##ALIAS, X6                                       \
     47   },
     48 #include "Options.inc"
     49 #undef OPTION
     50 };
     51 
     52 class LibOptTable : public llvm::opt::OptTable {
     53 public:
     54   LibOptTable() : OptTable(infoTable, true) {}
     55 };
     56 
     57 }
     58 
     59 static std::string getOutputPath(llvm::opt::InputArgList *Args,
     60                                  const llvm::NewArchiveIterator &FirstMember) {
     61   if (auto *Arg = Args->getLastArg(OPT_out))
     62     return Arg->getValue();
     63   SmallString<128> Val = FirstMember.getNew();
     64   llvm::sys::path::replace_extension(Val, ".lib");
     65   return Val.str();
     66 }
     67 
     68 static std::vector<StringRef> getSearchPaths(llvm::opt::InputArgList *Args,
     69                                              StringSaver &Saver) {
     70   std::vector<StringRef> Ret;
     71   // Add current directory as first item of the search path.
     72   Ret.push_back("");
     73 
     74   // Add /libpath flags.
     75   for (auto *Arg : Args->filtered(OPT_libpath))
     76     Ret.push_back(Arg->getValue());
     77 
     78   // Add $LIB.
     79   Optional<std::string> EnvOpt = sys::Process::GetEnv("LIB");
     80   if (!EnvOpt.hasValue())
     81     return Ret;
     82   StringRef Env = Saver.save(*EnvOpt);
     83   while (!Env.empty()) {
     84     StringRef Path;
     85     std::tie(Path, Env) = Env.split(';');
     86     Ret.push_back(Path);
     87   }
     88   return Ret;
     89 }
     90 
     91 static Optional<std::string> findInputFile(StringRef File,
     92                                            ArrayRef<StringRef> Paths) {
     93   for (auto Dir : Paths) {
     94     SmallString<128> Path = Dir;
     95     sys::path::append(Path, File);
     96     if (sys::fs::exists(Path))
     97       return Path.str().str();
     98   }
     99   return Optional<std::string>();
    100 }
    101 
    102 int llvm::libDriverMain(llvm::ArrayRef<const char*> ArgsArr) {
    103   SmallVector<const char *, 20> NewArgs(ArgsArr.begin(), ArgsArr.end());
    104   BumpPtrAllocator Alloc;
    105   StringSaver Saver(Alloc);
    106   cl::ExpandResponseFiles(Saver, cl::TokenizeWindowsCommandLine, NewArgs);
    107   ArgsArr = NewArgs;
    108 
    109   LibOptTable Table;
    110   unsigned MissingIndex;
    111   unsigned MissingCount;
    112   llvm::opt::InputArgList Args =
    113       Table.ParseArgs(ArgsArr.slice(1), MissingIndex, MissingCount);
    114   if (MissingCount) {
    115     llvm::errs() << "missing arg value for \""
    116                  << Args.getArgString(MissingIndex) << "\", expected "
    117                  << MissingCount
    118                  << (MissingCount == 1 ? " argument.\n" : " arguments.\n");
    119     return 1;
    120   }
    121   for (auto *Arg : Args.filtered(OPT_UNKNOWN))
    122     llvm::errs() << "ignoring unknown argument: " << Arg->getSpelling() << "\n";
    123 
    124   if (Args.filtered_begin(OPT_INPUT) == Args.filtered_end()) {
    125     llvm::errs() << "no input files.\n";
    126     return 1;
    127   }
    128 
    129   std::vector<StringRef> SearchPaths = getSearchPaths(&Args, Saver);
    130 
    131   std::vector<llvm::NewArchiveIterator> Members;
    132   for (auto *Arg : Args.filtered(OPT_INPUT)) {
    133     Optional<std::string> Path = findInputFile(Arg->getValue(), SearchPaths);
    134     if (!Path.hasValue()) {
    135       llvm::errs() << Arg->getValue() << ": no such file or directory\n";
    136       return 1;
    137     }
    138     Members.emplace_back(Saver.save(*Path));
    139   }
    140 
    141   std::pair<StringRef, std::error_code> Result =
    142       llvm::writeArchive(getOutputPath(&Args, Members[0]), Members,
    143                          /*WriteSymtab=*/true, object::Archive::K_GNU,
    144                          /*Deterministic*/ true, Args.hasArg(OPT_llvmlibthin));
    145 
    146   if (Result.second) {
    147     if (Result.first.empty())
    148       Result.first = ArgsArr[0];
    149     llvm::errs() << Result.first << ": " << Result.second.message() << "\n";
    150     return 1;
    151   }
    152 
    153   return 0;
    154 }
    155