llvm-mt.cpp 5.7 KB

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