diff options
author | Martin Storsjö <martin@martin.st> | 2021-04-14 16:24:30 +0300 |
---|---|---|
committer | Martin Storsjö <martin@martin.st> | 2021-04-21 11:50:10 +0300 |
commit | 64bc44f5ddfb6da4b6a8b51ea9a03f8772b3ae95 (patch) | |
tree | eb60984d8a593b3784e9c5a83f63533888de2d09 /llvm/tools/llvm-rc/llvm-rc.cpp | |
parent | ee34ca34c6675531c0d86709ebf99beef2ee7db1 (diff) | |
download | llvm-64bc44f5ddfb6da4b6a8b51ea9a03f8772b3ae95.zip llvm-64bc44f5ddfb6da4b6a8b51ea9a03f8772b3ae95.tar.gz llvm-64bc44f5ddfb6da4b6a8b51ea9a03f8772b3ae95.tar.bz2 |
[llvm-rc] Run clang to preprocess input files
Allow opting out from preprocessing with a command line argument.
Update tests to pass -no-preprocess to make it not try to use clang
(which isn't a build level dependency of llvm-rc), but add a test that
does preprocessing under clang/test/Preprocessor.
Update a few options to allow them both joined (as -DFOO) and separate
(-D BR), as rc.exe allows both forms of them.
With the verbose flag set, this prints the preprocessing command
used (which differs from what rc.exe does).
Tests under llvm/test/tools/llvm-rc only test constructing the
preprocessor commands, while tests under clang/test/Preprocessor test
actually running the preprocessor.
Differential Revision: https://reviews.llvm.org/D100755
Diffstat (limited to 'llvm/tools/llvm-rc/llvm-rc.cpp')
-rw-r--r-- | llvm/tools/llvm-rc/llvm-rc.cpp | 117 |
1 files changed, 116 insertions, 1 deletions
diff --git a/llvm/tools/llvm-rc/llvm-rc.cpp b/llvm/tools/llvm-rc/llvm-rc.cpp index 2007ef9..ab5ecb8 100644 --- a/llvm/tools/llvm-rc/llvm-rc.cpp +++ b/llvm/tools/llvm-rc/llvm-rc.cpp @@ -17,17 +17,22 @@ #include "ResourceScriptStmt.h" #include "ResourceScriptToken.h" +#include "llvm/ADT/Triple.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/FileUtilities.h" +#include "llvm/Support/Host.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Process.h" +#include "llvm/Support/Program.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/StringSaver.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> @@ -71,12 +76,114 @@ public: }; static ExitOnError ExitOnErr; +static FileRemover TempPreprocFile; LLVM_ATTRIBUTE_NORETURN static void fatalError(const Twine &Message) { errs() << Message << "\n"; exit(1); } +std::string createTempFile(const Twine &Prefix, StringRef Suffix) { + std::error_code EC; + SmallString<128> FileName; + if ((EC = sys::fs::createTemporaryFile(Prefix, Suffix, FileName))) + fatalError("Unable to create temp file: " + EC.message()); + return static_cast<std::string>(FileName); +} + +ErrorOr<std::string> findClang(const char *Argv0) { + StringRef Parent = llvm::sys::path::parent_path(Argv0); + ErrorOr<std::string> Path = std::error_code(); + if (!Parent.empty()) { + // First look for the tool with all potential names in the specific + // directory of Argv0, if known + for (const auto *Name : {"clang", "clang-cl"}) { + Path = sys::findProgramByName(Name, Parent); + if (Path) + return Path; + } + } + // If no parent directory known, or not found there, look everywhere in PATH + for (const auto *Name : {"clang", "clang-cl"}) { + Path = sys::findProgramByName(Name); + if (Path) + return Path; + } + return Path; +} + +std::string getClangClTriple() { + Triple T(sys::getDefaultTargetTriple()); + T.setOS(llvm::Triple::Win32); + T.setVendor(llvm::Triple::PC); + T.setEnvironment(llvm::Triple::MSVC); + T.setObjectFormat(llvm::Triple::COFF); + return T.str(); +} + +bool preprocess(StringRef Src, StringRef Dst, opt::InputArgList &InputArgs, + const char *Argv0) { + std::string Clang; + if (InputArgs.hasArg(OPT__HASH_HASH_HASH)) { + Clang = "clang"; + } else { + ErrorOr<std::string> ClangOrErr = findClang(Argv0); + if (ClangOrErr) { + Clang = *ClangOrErr; + } else { + errs() << "llvm-rc: Unable to find clang, skipping preprocessing." + << "\n"; + errs() << "Pass -no-cpp to disable preprocessing. This will be an error " + "in the future." + << "\n"; + return false; + } + } + std::string PreprocTriple = getClangClTriple(); + + SmallVector<StringRef, 8> Args = { + Clang, "--driver-mode=gcc", "-target", PreprocTriple, "-E", + "-xc", "-DRC_INVOKED", Src, "-o", Dst}; + if (InputArgs.hasArg(OPT_noinclude)) { +#ifdef _WIN32 + ::_putenv("INCLUDE="); +#else + ::unsetenv("INCLUDE"); +#endif + } + for (const auto *Arg : + InputArgs.filtered(OPT_includepath, OPT_define, OPT_undef)) { + switch (Arg->getOption().getID()) { + case OPT_includepath: + Args.push_back("-I"); + break; + case OPT_define: + Args.push_back("-D"); + break; + case OPT_undef: + Args.push_back("-U"); + break; + } + Args.push_back(Arg->getValue()); + } + if (InputArgs.hasArg(OPT__HASH_HASH_HASH) || InputArgs.hasArg(OPT_verbose)) { + for (const auto &A : Args) { + outs() << " "; + sys::printArg(outs(), A, InputArgs.hasArg(OPT__HASH_HASH_HASH)); + } + outs() << "\n"; + if (InputArgs.hasArg(OPT__HASH_HASH_HASH)) + exit(0); + } + // The llvm Support classes don't handle reading from stdout of a child + // process; otherwise we could avoid using a temp file. + int Res = sys::ExecuteAndWait(Clang, Args); + if (Res) { + fatalError("llvm-rc: Preprocessing failed."); + } + return true; +} + } // anonymous namespace int main(int Argc, const char **Argv) { @@ -106,9 +213,17 @@ int main(int Argc, const char **Argv) { fatalError("Exactly one input file should be provided."); } + std::string PreprocessedFile = InArgsInfo[0]; + if (!InputArgs.hasArg(OPT_no_preprocess)) { + std::string OutFile = createTempFile("preproc", "rc"); + TempPreprocFile.setFile(OutFile); + if (preprocess(InArgsInfo[0], OutFile, InputArgs, Argv[0])) + PreprocessedFile = OutFile; + } + // Read and tokenize the input file. ErrorOr<std::unique_ptr<MemoryBuffer>> File = - MemoryBuffer::getFile(InArgsInfo[0]); + MemoryBuffer::getFile(PreprocessedFile); if (!File) { fatalError("Error opening file '" + Twine(InArgsInfo[0]) + "': " + File.getError().message()); |