[clang][modules] Don't prevent translation of FW_Private includes when explicitly...
[llvm-project.git] / llvm / tools / llvm-mt / llvm-mt.cpp
blob246e092898b3bd9e2d4574dfe0bad87b7579a0fc
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.
12 //===---------------------------------------------------------------------===//
14 #include "llvm/Option/Arg.h"
15 #include "llvm/Option/ArgList.h"
16 #include "llvm/Option/Option.h"
17 #include "llvm/Support/Error.h"
18 #include "llvm/Support/FileOutputBuffer.h"
19 #include "llvm/Support/InitLLVM.h"
20 #include "llvm/Support/LLVMDriver.h"
21 #include "llvm/Support/MemoryBuffer.h"
22 #include "llvm/Support/Path.h"
23 #include "llvm/Support/PrettyStackTrace.h"
24 #include "llvm/Support/Process.h"
25 #include "llvm/Support/Signals.h"
26 #include "llvm/Support/WithColor.h"
27 #include "llvm/Support/raw_ostream.h"
28 #include "llvm/WindowsManifest/WindowsManifestMerger.h"
30 #include <system_error>
32 using namespace llvm;
34 namespace {
36 enum ID {
37 OPT_INVALID = 0, // This is not an option ID.
38 #define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
39 #include "Opts.inc"
40 #undef OPTION
43 #define PREFIX(NAME, VALUE) \
44 static constexpr StringLiteral NAME##_init[] = VALUE; \
45 static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \
46 std::size(NAME##_init) - 1);
47 #include "Opts.inc"
48 #undef PREFIX
50 using namespace llvm::opt;
51 static constexpr opt::OptTable::Info InfoTable[] = {
52 #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
53 #include "Opts.inc"
54 #undef OPTION
57 class CvtResOptTable : public opt::GenericOptTable {
58 public:
59 CvtResOptTable() : opt::GenericOptTable(InfoTable, true) {}
61 } // namespace
63 [[noreturn]] static void reportError(Twine Msg) {
64 WithColor::error(errs(), "llvm-mt") << Msg << '\n';
65 exit(1);
68 static void reportError(StringRef Input, std::error_code EC) {
69 reportError(Twine(Input) + ": " + EC.message());
72 static void error(Error EC) {
73 if (EC)
74 handleAllErrors(std::move(EC), [&](const ErrorInfoBase &EI) {
75 reportError(EI.message());
76 });
79 int llvm_mt_main(int Argc, char **Argv, const llvm::ToolContext &) {
80 InitLLVM X(Argc, Argv);
82 CvtResOptTable T;
83 unsigned MAI, MAC;
84 ArrayRef<const char *> ArgsArr = ArrayRef(Argv + 1, Argc - 1);
85 opt::InputArgList InputArgs = T.ParseArgs(ArgsArr, MAI, MAC);
87 for (auto *Arg : InputArgs.filtered(OPT_INPUT)) {
88 auto ArgString = Arg->getAsString(InputArgs);
89 std::string Diag;
90 raw_string_ostream OS(Diag);
91 OS << "invalid option '" << ArgString << "'";
93 std::string Nearest;
94 if (T.findNearest(ArgString, Nearest) < 2)
95 OS << ", did you mean '" << Nearest << "'?";
97 reportError(OS.str());
100 for (auto &Arg : InputArgs) {
101 if (Arg->getOption().matches(OPT_unsupported)) {
102 outs() << "llvm-mt: ignoring unsupported '" << Arg->getOption().getName()
103 << "' option\n";
107 if (InputArgs.hasArg(OPT_help)) {
108 T.printHelp(outs(), "llvm-mt [options] file...", "Manifest Tool", false);
109 return 0;
112 std::vector<std::string> InputFiles = InputArgs.getAllArgValues(OPT_manifest);
114 if (InputFiles.size() == 0) {
115 reportError("no input file specified");
118 StringRef OutputFile;
119 if (InputArgs.hasArg(OPT_out)) {
120 OutputFile = InputArgs.getLastArgValue(OPT_out);
121 } else if (InputFiles.size() == 1) {
122 OutputFile = InputFiles[0];
123 } else {
124 reportError("no output file specified");
127 windows_manifest::WindowsManifestMerger Merger;
129 for (const auto &File : InputFiles) {
130 ErrorOr<std::unique_ptr<MemoryBuffer>> ManifestOrErr =
131 MemoryBuffer::getFile(File);
132 if (!ManifestOrErr)
133 reportError(File, ManifestOrErr.getError());
134 error(Merger.merge(*ManifestOrErr.get()));
137 std::unique_ptr<MemoryBuffer> OutputBuffer = Merger.getMergedManifest();
138 if (!OutputBuffer)
139 reportError("empty manifest not written");
141 int ExitCode = 0;
142 if (InputArgs.hasArg(OPT_notify_update)) {
143 ErrorOr<std::unique_ptr<MemoryBuffer>> OutBuffOrErr =
144 MemoryBuffer::getFile(OutputFile);
145 // Assume if we couldn't open the output file then it doesn't exist meaning
146 // there was a change.
147 bool Same = false;
148 if (OutBuffOrErr) {
149 const std::unique_ptr<MemoryBuffer> &FileBuffer = *OutBuffOrErr;
150 Same = std::equal(
151 OutputBuffer->getBufferStart(), OutputBuffer->getBufferEnd(),
152 FileBuffer->getBufferStart(), FileBuffer->getBufferEnd());
154 if (!Same) {
155 #if LLVM_ON_UNIX
156 ExitCode = 0xbb;
157 #elif defined(_WIN32)
158 ExitCode = 0x41020001;
159 #endif
163 Expected<std::unique_ptr<FileOutputBuffer>> FileOrErr =
164 FileOutputBuffer::create(OutputFile, OutputBuffer->getBufferSize());
165 if (!FileOrErr)
166 reportError(OutputFile, errorToErrorCode(FileOrErr.takeError()));
167 std::unique_ptr<FileOutputBuffer> FileBuffer = std::move(*FileOrErr);
168 std::copy(OutputBuffer->getBufferStart(), OutputBuffer->getBufferEnd(),
169 FileBuffer->getBufferStart());
170 error(FileBuffer->commit());
171 return ExitCode;