Home | History | Annotate | Download | only in llvm-mt
      1 //===- llvm-mt.cpp - Merge .manifest files ---------------------*- C++ -*-===//
      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 // Merge .manifest files.  This is intended to be a platform-independent port
     11 // of Microsoft's mt.exe.
     12 //
     13 //===---------------------------------------------------------------------===//
     14 
     15 #include "llvm/Option/Arg.h"
     16 #include "llvm/Option/ArgList.h"
     17 #include "llvm/Option/Option.h"
     18 #include "llvm/Support/Error.h"
     19 #include "llvm/Support/FileOutputBuffer.h"
     20 #include "llvm/Support/InitLLVM.h"
     21 #include "llvm/Support/ManagedStatic.h"
     22 #include "llvm/Support/MemoryBuffer.h"
     23 #include "llvm/Support/Path.h"
     24 #include "llvm/Support/PrettyStackTrace.h"
     25 #include "llvm/Support/Process.h"
     26 #include "llvm/Support/Signals.h"
     27 #include "llvm/Support/WithColor.h"
     28 #include "llvm/Support/raw_ostream.h"
     29 #include "llvm/WindowsManifest/WindowsManifestMerger.h"
     30 
     31 #include <system_error>
     32 
     33 using namespace llvm;
     34 
     35 namespace {
     36 
     37 enum ID {
     38   OPT_INVALID = 0, // This is not an option ID.
     39 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
     40                HELPTEXT, METAVAR, VALUES)                                      \
     41   OPT_##ID,
     42 #include "Opts.inc"
     43 #undef OPTION
     44 };
     45 
     46 #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
     47 #include "Opts.inc"
     48 #undef PREFIX
     49 
     50 static const opt::OptTable::Info InfoTable[] = {
     51 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
     52                HELPTEXT, METAVAR, VALUES)                                      \
     53 {                                                                              \
     54       PREFIX,      NAME,      HELPTEXT,                                        \
     55       METAVAR,     OPT_##ID,  opt::Option::KIND##Class,                        \
     56       PARAM,       FLAGS,     OPT_##GROUP,                                     \
     57       OPT_##ALIAS, ALIASARGS, VALUES},
     58 #include "Opts.inc"
     59 #undef OPTION
     60 };
     61 
     62 class CvtResOptTable : public opt::OptTable {
     63 public:
     64   CvtResOptTable() : OptTable(InfoTable, true) {}
     65 };
     66 } // namespace
     67 
     68 LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg) {
     69   WithColor::error(errs(), "llvm-mt") << Msg << '\n';
     70   exit(1);
     71 }
     72 
     73 static void reportError(StringRef Input, std::error_code EC) {
     74   reportError(Twine(Input) + ": " + EC.message());
     75 }
     76 
     77 void error(std::error_code EC) {
     78   if (EC)
     79     reportError(EC.message());
     80 }
     81 
     82 void error(Error EC) {
     83   if (EC)
     84     handleAllErrors(std::move(EC), [&](const ErrorInfoBase &EI) {
     85       reportError(EI.message());
     86     });
     87 }
     88 
     89 int main(int Argc, const char **Argv) {
     90   InitLLVM X(Argc, Argv);
     91 
     92   CvtResOptTable T;
     93   unsigned MAI, MAC;
     94   ArrayRef<const char *> ArgsArr = makeArrayRef(Argv + 1, Argc - 1);
     95   opt::InputArgList InputArgs = T.ParseArgs(ArgsArr, MAI, MAC);
     96 
     97   for (auto *Arg : InputArgs.filtered(OPT_INPUT)) {
     98     auto ArgString = Arg->getAsString(InputArgs);
     99     std::string Diag;
    100     raw_string_ostream OS(Diag);
    101     OS << "invalid option '" << ArgString << "'";
    102 
    103     std::string Nearest;
    104     if (T.findNearest(ArgString, Nearest) < 2)
    105       OS << ", did you mean '" << Nearest << "'?";
    106 
    107     reportError(OS.str());
    108   }
    109 
    110   for (auto &Arg : InputArgs) {
    111     if (Arg->getOption().matches(OPT_unsupported)) {
    112       outs() << "llvm-mt: ignoring unsupported '" << Arg->getOption().getName()
    113              << "' option\n";
    114     }
    115   }
    116 
    117   if (InputArgs.hasArg(OPT_help)) {
    118     T.PrintHelp(outs(), "mt", "Manifest Tool", false);
    119     return 0;
    120   }
    121 
    122   std::vector<std::string> InputFiles = InputArgs.getAllArgValues(OPT_manifest);
    123 
    124   if (InputFiles.size() == 0) {
    125     reportError("no input file specified");
    126   }
    127 
    128   StringRef OutputFile;
    129   if (InputArgs.hasArg(OPT_out)) {
    130     OutputFile = InputArgs.getLastArgValue(OPT_out);
    131   } else if (InputFiles.size() == 1) {
    132     OutputFile = InputFiles[0];
    133   } else {
    134     reportError("no output file specified");
    135   }
    136 
    137   windows_manifest::WindowsManifestMerger Merger;
    138 
    139   for (const auto &File : InputFiles) {
    140     ErrorOr<std::unique_ptr<MemoryBuffer>> ManifestOrErr =
    141         MemoryBuffer::getFile(File);
    142     if (!ManifestOrErr)
    143       reportError(File, ManifestOrErr.getError());
    144     MemoryBuffer &Manifest = *ManifestOrErr.get();
    145     error(Merger.merge(Manifest));
    146   }
    147 
    148   std::unique_ptr<MemoryBuffer> OutputBuffer = Merger.getMergedManifest();
    149   if (!OutputBuffer)
    150     reportError("empty manifest not written");
    151   Expected<std::unique_ptr<FileOutputBuffer>> FileOrErr =
    152       FileOutputBuffer::create(OutputFile, OutputBuffer->getBufferSize());
    153   if (!FileOrErr)
    154     reportError(OutputFile, errorToErrorCode(FileOrErr.takeError()));
    155   std::unique_ptr<FileOutputBuffer> FileBuffer = std::move(*FileOrErr);
    156   std::copy(OutputBuffer->getBufferStart(), OutputBuffer->getBufferEnd(),
    157             FileBuffer->getBufferStart());
    158   error(FileBuffer->commit());
    159   return 0;
    160 }
    161