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