2017-07-17 23:35:12 +02:00
|
|
|
//===- llvm-mt.cpp - Merge .manifest files ---------------------*- C++ -*-===//
|
|
|
|
//
|
2019-01-19 09:50:56 +01:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2017-07-17 23:35:12 +02:00
|
|
|
//
|
|
|
|
//===---------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// Merge .manifest files. This is intended to be a platform-independent port
|
|
|
|
// of Microsoft's mt.exe.
|
|
|
|
//
|
|
|
|
//===---------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "llvm/Option/Arg.h"
|
|
|
|
#include "llvm/Option/ArgList.h"
|
|
|
|
#include "llvm/Option/Option.h"
|
|
|
|
#include "llvm/Support/Error.h"
|
2017-07-20 23:42:04 +02:00
|
|
|
#include "llvm/Support/FileOutputBuffer.h"
|
2018-04-13 20:26:06 +02:00
|
|
|
#include "llvm/Support/InitLLVM.h"
|
2017-07-17 23:35:12 +02:00
|
|
|
#include "llvm/Support/ManagedStatic.h"
|
2017-11-17 02:00:35 +01:00
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
2017-07-17 23:35:12 +02:00
|
|
|
#include "llvm/Support/Path.h"
|
|
|
|
#include "llvm/Support/PrettyStackTrace.h"
|
|
|
|
#include "llvm/Support/Process.h"
|
|
|
|
#include "llvm/Support/Signals.h"
|
2018-06-23 18:49:07 +02:00
|
|
|
#include "llvm/Support/WithColor.h"
|
2017-07-17 23:35:12 +02:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2017-07-26 03:21:55 +02:00
|
|
|
#include "llvm/WindowsManifest/WindowsManifestMerger.h"
|
2017-07-17 23:35:12 +02:00
|
|
|
|
|
|
|
#include <system_error>
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
enum ID {
|
|
|
|
OPT_INVALID = 0, // This is not an option ID.
|
|
|
|
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
|
|
|
|
HELPTEXT, METAVAR, VALUES) \
|
|
|
|
OPT_##ID,
|
|
|
|
#include "Opts.inc"
|
|
|
|
#undef OPTION
|
|
|
|
};
|
|
|
|
|
|
|
|
#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
|
|
|
|
#include "Opts.inc"
|
|
|
|
#undef PREFIX
|
|
|
|
|
|
|
|
static const opt::OptTable::Info InfoTable[] = {
|
|
|
|
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
|
|
|
|
HELPTEXT, METAVAR, VALUES) \
|
|
|
|
{ \
|
|
|
|
PREFIX, NAME, HELPTEXT, \
|
|
|
|
METAVAR, OPT_##ID, opt::Option::KIND##Class, \
|
|
|
|
PARAM, FLAGS, OPT_##GROUP, \
|
|
|
|
OPT_##ALIAS, ALIASARGS, VALUES},
|
|
|
|
#include "Opts.inc"
|
|
|
|
#undef OPTION
|
|
|
|
};
|
|
|
|
|
|
|
|
class CvtResOptTable : public opt::OptTable {
|
|
|
|
public:
|
|
|
|
CvtResOptTable() : OptTable(InfoTable, true) {}
|
|
|
|
};
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg) {
|
2018-06-23 18:49:07 +02:00
|
|
|
WithColor::error(errs(), "llvm-mt") << Msg << '\n';
|
2017-07-17 23:35:12 +02:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2017-07-20 23:42:04 +02:00
|
|
|
static void reportError(StringRef Input, std::error_code EC) {
|
|
|
|
reportError(Twine(Input) + ": " + EC.message());
|
|
|
|
}
|
|
|
|
|
|
|
|
void error(std::error_code EC) {
|
|
|
|
if (EC)
|
|
|
|
reportError(EC.message());
|
|
|
|
}
|
|
|
|
|
|
|
|
void error(Error EC) {
|
|
|
|
if (EC)
|
|
|
|
handleAllErrors(std::move(EC), [&](const ErrorInfoBase &EI) {
|
|
|
|
reportError(EI.message());
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-04-13 20:26:06 +02:00
|
|
|
int main(int Argc, const char **Argv) {
|
|
|
|
InitLLVM X(Argc, Argv);
|
2017-07-18 05:37:34 +02:00
|
|
|
|
2017-07-17 23:35:12 +02:00
|
|
|
CvtResOptTable T;
|
|
|
|
unsigned MAI, MAC;
|
2018-04-13 20:26:06 +02:00
|
|
|
ArrayRef<const char *> ArgsArr = makeArrayRef(Argv + 1, Argc - 1);
|
2017-07-17 23:35:12 +02:00
|
|
|
opt::InputArgList InputArgs = T.ParseArgs(ArgsArr, MAI, MAC);
|
|
|
|
|
[Option] Add 'findNearest' method to catch typos
Summary:
Add a method `OptTable::findNearest`, which allows users of OptTable to
check user input for misspelled options. In addition, have llvm-mt
check for misspelled options. For example, if a user invokes
`llvm-mt /oyt:foo`, the error message will indicate that while an
option named `/oyt:` does not exist, `/out:` does.
The method ports the functionality of the `LookupNearestOption` method
from LLVM CommandLine to libLLVMOption. This allows tools like Clang
and Swift, which do not use CommandLine, to use this functionality to
suggest similarly spelled options.
As room for future improvement, the new method as-is cannot yet properly suggest
nearby "joined" options -- that is, for an option string "-FozBar", where
"-Foo" is the correct option name and "Bar" is the value being passed along
with the misspelled option, this method will calculate an edit distance of 4,
by deleting "Bar" and changing "z" to "o". It should instead calculate an edit
distance of just 1, by changing "z" to "o" and recognizing "Bar" as a
value. This commit includes a disabled test that expresses this limitation.
Test Plan: `check-llvm`
Reviewers: yamaguchi, v.g.vassilev, teemperor, ruiu, jroelofs
Reviewed By: jroelofs
Subscribers: jroelofs, llvm-commits
Differential Revision: https://reviews.llvm.org/D41732
llvm-svn: 321877
2018-01-05 18:10:39 +01:00
|
|
|
for (auto *Arg : InputArgs.filtered(OPT_INPUT)) {
|
|
|
|
auto ArgString = Arg->getAsString(InputArgs);
|
|
|
|
std::string Diag;
|
|
|
|
raw_string_ostream OS(Diag);
|
|
|
|
OS << "invalid option '" << ArgString << "'";
|
|
|
|
|
|
|
|
std::string Nearest;
|
|
|
|
if (T.findNearest(ArgString, Nearest) < 2)
|
|
|
|
OS << ", did you mean '" << Nearest << "'?";
|
|
|
|
|
|
|
|
reportError(OS.str());
|
|
|
|
}
|
2017-08-19 02:37:41 +02:00
|
|
|
|
2017-07-17 23:35:12 +02:00
|
|
|
for (auto &Arg : InputArgs) {
|
|
|
|
if (Arg->getOption().matches(OPT_unsupported)) {
|
|
|
|
outs() << "llvm-mt: ignoring unsupported '" << Arg->getOption().getName()
|
|
|
|
<< "' option\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (InputArgs.hasArg(OPT_help)) {
|
2018-10-10 02:15:31 +02:00
|
|
|
T.PrintHelp(outs(), "llvm-mt [options] file...", "Manifest Tool", false);
|
2017-07-17 23:35:12 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::string> InputFiles = InputArgs.getAllArgValues(OPT_manifest);
|
|
|
|
|
|
|
|
if (InputFiles.size() == 0) {
|
|
|
|
reportError("no input file specified");
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef OutputFile;
|
|
|
|
if (InputArgs.hasArg(OPT_out)) {
|
|
|
|
OutputFile = InputArgs.getLastArgValue(OPT_out);
|
|
|
|
} else if (InputFiles.size() == 1) {
|
|
|
|
OutputFile = InputFiles[0];
|
|
|
|
} else {
|
|
|
|
reportError("no output file specified");
|
|
|
|
}
|
|
|
|
|
2017-08-19 02:37:41 +02:00
|
|
|
windows_manifest::WindowsManifestMerger Merger;
|
2017-07-20 23:42:04 +02:00
|
|
|
|
|
|
|
for (const auto &File : InputFiles) {
|
|
|
|
ErrorOr<std::unique_ptr<MemoryBuffer>> ManifestOrErr =
|
|
|
|
MemoryBuffer::getFile(File);
|
|
|
|
if (!ManifestOrErr)
|
|
|
|
reportError(File, ManifestOrErr.getError());
|
|
|
|
MemoryBuffer &Manifest = *ManifestOrErr.get();
|
|
|
|
error(Merger.merge(Manifest));
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<MemoryBuffer> OutputBuffer = Merger.getMergedManifest();
|
|
|
|
if (!OutputBuffer)
|
|
|
|
reportError("empty manifest not written");
|
2017-11-08 02:05:44 +01:00
|
|
|
Expected<std::unique_ptr<FileOutputBuffer>> FileOrErr =
|
2017-07-20 23:42:04 +02:00
|
|
|
FileOutputBuffer::create(OutputFile, OutputBuffer->getBufferSize());
|
|
|
|
if (!FileOrErr)
|
2017-11-08 02:05:44 +01:00
|
|
|
reportError(OutputFile, errorToErrorCode(FileOrErr.takeError()));
|
2017-07-20 23:42:04 +02:00
|
|
|
std::unique_ptr<FileOutputBuffer> FileBuffer = std::move(*FileOrErr);
|
|
|
|
std::copy(OutputBuffer->getBufferStart(), OutputBuffer->getBufferEnd(),
|
|
|
|
FileBuffer->getBufferStart());
|
|
|
|
error(FileBuffer->commit());
|
2017-07-17 23:35:12 +02:00
|
|
|
return 0;
|
|
|
|
}
|