aboutsummaryrefslogtreecommitdiff
path: root/llvm/tools/llvm-rc/llvm-rc.cpp
diff options
context:
space:
mode:
authorMartin Storsjö <martin@martin.st>2021-04-14 16:24:30 +0300
committerMartin Storsjö <martin@martin.st>2021-04-21 11:50:10 +0300
commit64bc44f5ddfb6da4b6a8b51ea9a03f8772b3ae95 (patch)
treeeb60984d8a593b3784e9c5a83f63533888de2d09 /llvm/tools/llvm-rc/llvm-rc.cpp
parentee34ca34c6675531c0d86709ebf99beef2ee7db1 (diff)
downloadllvm-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.cpp117
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());