| From eddb2a96fcfdce9761268997392871d27ff361da Mon Sep 17 00:00:00 2001 |
| From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <martin@martin.st> |
| Date: Wed, 14 Apr 2021 16:23:50 +0300 |
| Subject: [PATCH 1/5] [llvm-rc] Simplify Opts.td to avoid repetition. NFC. |
| |
| Differential Revision: https://reviews.llvm.org/D100753 |
| --- |
| tools/llvm-rc/Opts.td | 70 +++++++++++++++++++++---------------------- |
| 1 file changed, 35 insertions(+), 35 deletions(-) |
| |
| diff --git a/tools/llvm-rc/Opts.td b/tools/llvm-rc/Opts.td |
| index 613f0a0db31e..7a39a71f5aa8 100644 |
| --- a/tools/llvm-rc/Opts.td |
| +++ b/tools/llvm-rc/Opts.td |
| @@ -4,55 +4,55 @@ include "llvm/Option/OptParser.td" |
| // These options seem to be important for the tool |
| // and should be implemented. |
| |
| -def fileout : JoinedOrSeparate<[ "/", "-" ], "FO">, |
| - HelpText<"Change the output file location.">; |
| +class S<string name, string help> : |
| + Separate<["/", "-"], name>, HelpText<help>; |
| |
| -def define : Separate<[ "/", "-" ], "D">, |
| - HelpText<"Define a symbol for the C preprocessor.">; |
| -def undef : Separate<[ "/", "-" ], "U">, |
| - HelpText<"Undefine a symbol for the C preprocessor.">; |
| +class JS<string name, string help> : |
| + JoinedOrSeparate<["/", "-"], name>, HelpText<help>; |
| |
| -def lang_id : JoinedOrSeparate<[ "/", "-" ], "L">, |
| - HelpText<"Set the default language identifier.">; |
| -def lang_name : Separate<[ "/", "-" ], "LN">, |
| - HelpText<"Set the default language name.">; |
| +class F<string name, string help> : Flag<["/", "-"], name>, HelpText<help>; |
| |
| -def includepath : Separate<[ "/", "-" ], "I">, HelpText<"Add an include path.">; |
| -def noinclude : Flag<[ "/", "-" ], "X">, HelpText<"Ignore 'include' variable.">; |
| +class F_nodoc<string name> : Flag<["/", "-"], name>; |
| +class S_nodoc<string name> : Separate<["/", "-"], name>; |
| |
| -def add_null : Flag<[ "/", "-" ], "N">, |
| - HelpText<"Null-terminate all strings in the string table.">; |
| +def fileout : JS<"FO", "Change the output file location.">; |
| |
| -def dupid_nowarn : Flag<[ "/", "-" ], "Y">, |
| - HelpText<"Suppress warnings on duplicate resource IDs.">; |
| +def define : S<"D", "Define a symbol for the C preprocessor.">; |
| +def undef : S<"U", "Undefine a symbol for the C preprocessor.">; |
| |
| -def verbose : Flag<[ "/", "-" ], "V">, HelpText<"Be verbose.">; |
| -def help : Flag<[ "/", "-" ], "?">, HelpText<"Display this help and exit.">; |
| -def h : Flag<[ "/", "-" ], "H">, |
| - Alias<help>, |
| - HelpText<"Display this help and exit.">; |
| +def lang_id : JS<"L", "Set the default language identifier.">; |
| +def lang_name : S<"LN", "Set the default language name.">; |
| |
| -def dry_run : Flag<[ "/", "-" ], "dry-run">, |
| - HelpText<"Don't compile the input; only try to parse it.">; |
| +def includepath : S<"I", "Add an include path.">; |
| +def noinclude : F<"X", "Ignore 'include' variable.">; |
| |
| -def codepage : JoinedOrSeparate<[ "/", "-" ], "C">, |
| - HelpText<"Set the codepage used for input strings.">; |
| +def add_null : F<"N", "Null-terminate all strings in the string table.">; |
| + |
| +def dupid_nowarn : F<"Y", "Suppress warnings on duplicate resource IDs.">; |
| + |
| +def verbose : F<"V", "Be verbose.">; |
| +def help : F<"?", "Display this help and exit.">; |
| +def h : F<"H", "Display this help and exit.">, Alias<help>; |
| + |
| +def dry_run : F<"dry-run", "Don't compile the input; only try to parse it.">; |
| + |
| +def codepage : JS<"C", "Set the codepage used for input strings.">; |
| |
| // Unused switches (at least for now). These will stay unimplemented |
| // in an early stage of development and can be ignored. However, we need to |
| // parse them in order to preserve the compatibility with the original tool. |
| |
| -def nologo : Flag<[ "/", "-" ], "NOLOGO">; |
| -def r : Flag<[ "/", "-" ], "R">; |
| -def sl : Flag<[ "/", "-" ], "SL">; |
| +def nologo : F_nodoc<"NOLOGO">; |
| +def r : F_nodoc<"R">; |
| +def sl : F_nodoc<"SL">; |
| |
| // (Codepages support.) |
| -def w : Flag<[ "/", "-" ], "W">; |
| +def w : F_nodoc<"W">; |
| |
| // (Support of MUI and similar.) |
| -def fm : Separate<[ "/", "-" ], "FM">; |
| -def q : Separate<[ "/", "-" ], "Q">; |
| -def g : Flag<[ "/", "-" ], "G">; |
| -def gn : Flag<[ "/", "-" ], "GN">; |
| -def g1 : Flag<[ "/", "-" ], "G1">; |
| -def g2 : Flag<[ "/", "-" ], "G2">; |
| +def fm : S_nodoc<"FM">; |
| +def q : S_nodoc<"Q">; |
| +def g : F_nodoc<"G">; |
| +def gn : F_nodoc<"GN">; |
| +def g1 : F_nodoc<"G1">; |
| +def g2 : F_nodoc<"G2">; |
| -- |
| 2.31.1.windows.1 |
| |
| |
| From f0a260089285701d51706df1cccdbf0c772c68f0 Mon Sep 17 00:00:00 2001 |
| From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <martin@martin.st> |
| Date: Fri, 16 Apr 2021 13:30:47 +0300 |
| Subject: [PATCH 2/5] [llvm-rc] Fix handling of the /X option to match its |
| documentation and rc.exe |
| |
| This matches how it's documented in the option listing. |
| |
| Differential Revision: https://reviews.llvm.org/D100754 |
| --- |
| test/tools/llvm-rc/include-paths.test | 10 ++++++++++ |
| tools/llvm-rc/ResourceFileWriter.cpp | 7 ++++--- |
| tools/llvm-rc/ResourceFileWriter.h | 2 +- |
| tools/llvm-rc/llvm-rc.cpp | 2 +- |
| 4 files changed, 16 insertions(+), 5 deletions(-) |
| |
| diff --git a/test/tools/llvm-rc/include-paths.test b/test/tools/llvm-rc/include-paths.test |
| index 6acc967af943..0097ae88e1db 100644 |
| --- a/test/tools/llvm-rc/include-paths.test |
| +++ b/test/tools/llvm-rc/include-paths.test |
| @@ -13,6 +13,16 @@ |
| ; RUN: llvm-rc /FO %t.nested-include.res /I %p/Inputs/nested -- %p/Inputs/deep-include.rc |
| ; RUN: llvm-readobj %t.nested-include.res | FileCheck --check-prefix=FOUND %s |
| |
| +; The include dir can be specified via the INCLUDE env var too. |
| +; RUN: rm -f %t.nested-include.res |
| +; RUN: env INCLUDE=%p/Inputs/nested llvm-rc /FO %t.nested-include.res -- %p/Inputs/deep-include.rc |
| +; RUN: llvm-readobj %t.nested-include.res | FileCheck --check-prefix=FOUND %s |
| + |
| +; Specifying the /X option should make it ignore the INCLUDE variable. |
| +; RUN: rm -f %t.nested-include.res |
| +; RUN: not env INCLUDE=%p/Inputs/nested llvm-rc /X /FO %t.nested-include.res -- %p/Inputs/deep-include.rc 2>&1 \ |
| +; RUN: | FileCheck --check-prefix=MISSING %s |
| + |
| ; Otherwise, it should not find the bitmap. |
| ; RUN: rm -f %t.nested-include.res |
| ; RUN: not llvm-rc /FO %t.nested-include.res -- %p/Inputs/deep-include.rc 2>&1 \ |
| diff --git a/tools/llvm-rc/ResourceFileWriter.cpp b/tools/llvm-rc/ResourceFileWriter.cpp |
| index 553bb754aea0..b0cb192d6a7e 100644 |
| --- a/tools/llvm-rc/ResourceFileWriter.cpp |
| +++ b/tools/llvm-rc/ResourceFileWriter.cpp |
| @@ -1549,9 +1549,10 @@ ResourceFileWriter::loadFile(StringRef File) const { |
| return errorOrToExpected(MemoryBuffer::getFile(Path, -1, false)); |
| } |
| |
| - if (auto Result = |
| - llvm::sys::Process::FindInEnvPath("INCLUDE", File, Params.NoInclude)) |
| - return errorOrToExpected(MemoryBuffer::getFile(*Result, -1, false)); |
| + if (!Params.NoInclude) { |
| + if (auto Result = llvm::sys::Process::FindInEnvPath("INCLUDE", File)) |
| + return errorOrToExpected(MemoryBuffer::getFile(*Result, -1, false)); |
| + } |
| |
| return make_error<StringError>("error : file not found : " + Twine(File), |
| inconvertibleErrorCode()); |
| diff --git a/tools/llvm-rc/ResourceFileWriter.h b/tools/llvm-rc/ResourceFileWriter.h |
| index d545a7a9cab1..0f3d5937259f 100644 |
| --- a/tools/llvm-rc/ResourceFileWriter.h |
| +++ b/tools/llvm-rc/ResourceFileWriter.h |
| @@ -35,7 +35,7 @@ enum CodePage { |
| |
| struct WriterParams { |
| std::vector<std::string> Include; // Additional folders to search for files. |
| - std::vector<std::string> NoInclude; // Folders to exclude from file search. |
| + bool NoInclude; // Ignore the INCLUDE variable. |
| StringRef InputFilePath; // The full path of the input file. |
| int CodePage = CpAcp; // The codepage for interpreting characters. |
| }; |
| diff --git a/tools/llvm-rc/llvm-rc.cpp b/tools/llvm-rc/llvm-rc.cpp |
| index e9027a21d46b..2007ef903c7d 100644 |
| --- a/tools/llvm-rc/llvm-rc.cpp |
| +++ b/tools/llvm-rc/llvm-rc.cpp |
| @@ -142,7 +142,7 @@ int main(int Argc, const char **Argv) { |
| llvm::sys::fs::make_absolute(InputFile); |
| Params.InputFilePath = InputFile; |
| Params.Include = InputArgs.getAllArgValues(OPT_includepath); |
| - Params.NoInclude = InputArgs.getAllArgValues(OPT_noinclude); |
| + Params.NoInclude = InputArgs.hasArg(OPT_noinclude); |
| |
| if (InputArgs.hasArg(OPT_codepage)) { |
| if (InputArgs.getLastArgValue(OPT_codepage) |
| -- |
| 2.31.1.windows.1 |
| |
| |
| From 1c324f10087ebac99783871c1aacd10d6bf24ccd Mon Sep 17 00:00:00 2001 |
| From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <martin@martin.st> |
| Date: Wed, 14 Apr 2021 16:24:30 +0300 |
| Subject: [PATCH 3/5] [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 |
| --- |
| test/tools/llvm-rc/absolute.test | 4 +- |
| test/tools/llvm-rc/codepage.test | 6 +- |
| test/tools/llvm-rc/cpp-output.test | 2 +- |
| test/tools/llvm-rc/flags.test | 4 +- |
| test/tools/llvm-rc/helpmsg.test | 1 + |
| test/tools/llvm-rc/include-paths.test | 14 +-- |
| test/tools/llvm-rc/language.test | 4 +- |
| .../llvm-rc/memoryflags-stringtable.test | 2 +- |
| test/tools/llvm-rc/memoryflags.test | 2 +- |
| test/tools/llvm-rc/not-expr.test | 2 +- |
| test/tools/llvm-rc/parser-expr.test | 16 +-- |
| test/tools/llvm-rc/parser.test | 64 +++++----- |
| test/tools/llvm-rc/preproc.test | 3 + |
| test/tools/llvm-rc/tag-accelerators.test | 28 ++--- |
| test/tools/llvm-rc/tag-dialog.test | 26 ++-- |
| test/tools/llvm-rc/tag-escape.test | 2 +- |
| test/tools/llvm-rc/tag-html.test | 2 +- |
| test/tools/llvm-rc/tag-icon-cursor.test | 6 +- |
| test/tools/llvm-rc/tag-menu.test | 8 +- |
| test/tools/llvm-rc/tag-stringtable.test | 6 +- |
| test/tools/llvm-rc/tag-user.test | 2 +- |
| test/tools/llvm-rc/tag-versioninfo.test | 6 +- |
| test/tools/llvm-rc/tokenizer.test | 2 +- |
| test/tools/llvm-rc/versioninfo-padding.test | 2 +- |
| tools/llvm-rc/Opts.td | 15 ++- |
| tools/llvm-rc/llvm-rc.cpp | 117 +++++++++++++++++- |
| 26 files changed, 236 insertions(+), 110 deletions(-) |
| create mode 100644 llvm/test/tools/llvm-rc/preproc.test |
| |
| diff --git a/test/tools/llvm-rc/absolute.test b/test/tools/llvm-rc/absolute.test |
| index fd8b2d68d41e..fd054536b3bf 100644 |
| --- a/test/tools/llvm-rc/absolute.test |
| +++ b/test/tools/llvm-rc/absolute.test |
| @@ -1,7 +1,7 @@ |
| ; RUN: touch %t.manifest |
| ; RUN: echo "1 24 \"%t.manifest\"" > %t.rc |
| -; RUN: llvm-rc -- %t.rc |
| +; RUN: llvm-rc -no-preprocess -- %t.rc |
| ;; On Windows, try stripping out the drive name from the absolute path, |
| ;; and make sure the path still is found. |
| ; RUN: cat %t.rc | sed 's/"[a-zA-Z]:/"/' > %t2.rc |
| -; RUN: llvm-rc -- %t2.rc |
| +; RUN: llvm-rc -no-preprocess -- %t2.rc |
| diff --git a/test/tools/llvm-rc/codepage.test b/test/tools/llvm-rc/codepage.test |
| index 5da7a5af8f2d..406ff00be53b 100644 |
| --- a/test/tools/llvm-rc/codepage.test |
| +++ b/test/tools/llvm-rc/codepage.test |
| @@ -1,4 +1,4 @@ |
| -; RUN: llvm-rc /C 65001 /FO %t.utf8.res -- %p/Inputs/utf8.rc |
| +; RUN: llvm-rc -no-preprocess /C 65001 /FO %t.utf8.res -- %p/Inputs/utf8.rc |
| ; RUN: llvm-readobj %t.utf8.res | FileCheck %s --check-prefix=UTF8 |
| |
| ; UTF8: Resource type (int): STRINGTABLE (ID 6) |
| @@ -18,11 +18,11 @@ |
| ; UTF8-NEXT: 0040: 00000000 |....| |
| ; UTF8-NEXT: ) |
| |
| -; RUN: not llvm-rc /C 65001 /FO %t.utf8-escape-narrow.res -- %p/Inputs/utf8-escape-narrow.rc 2>&1 | FileCheck %s --check-prefix UTF8_ESCAPE |
| +; RUN: not llvm-rc -no-preprocess /C 65001 /FO %t.utf8-escape-narrow.res -- %p/Inputs/utf8-escape-narrow.rc 2>&1 | FileCheck %s --check-prefix UTF8_ESCAPE |
| ; UTF8_ESCAPE: llvm-rc: Error in STRINGTABLE statement (ID 1): |
| ; UTF8_ESCAPE-NEXT: Unable to interpret single byte (195) as UTF-8 |
| |
| -; RUN: llvm-rc /C 1252 /FO %t.cp1252.res -- %p/Inputs/cp1252.rc |
| +; RUN: llvm-rc -no-preprocess /C 1252 /FO %t.cp1252.res -- %p/Inputs/cp1252.rc |
| ; RUN: llvm-readobj %t.cp1252.res | FileCheck %s --check-prefix=CP1252 |
| |
| ; CP1252: Resource type (int): STRINGTABLE (ID 6) |
| diff --git a/test/tools/llvm-rc/cpp-output.test b/test/tools/llvm-rc/cpp-output.test |
| index 6814187d5f69..00acfff4e960 100644 |
| --- a/test/tools/llvm-rc/cpp-output.test |
| +++ b/test/tools/llvm-rc/cpp-output.test |
| @@ -1,4 +1,4 @@ |
| -; RUN: llvm-rc /FO %t -- %p/Inputs/cpp-output.rc |
| +; RUN: llvm-rc -no-preprocess /FO %t -- %p/Inputs/cpp-output.rc |
| ; RUN: llvm-readobj %t | FileCheck %s |
| |
| ; CHECK: Resource type (int): STRINGTABLE (ID 6) |
| diff --git a/test/tools/llvm-rc/flags.test b/test/tools/llvm-rc/flags.test |
| index 5b71481af2df..d1bda51bcfa7 100644 |
| --- a/test/tools/llvm-rc/flags.test |
| +++ b/test/tools/llvm-rc/flags.test |
| @@ -1,4 +1,4 @@ |
| -; RUN: llvm-rc /dry-run /FO %t -- %p/Inputs/empty.rc 2>&1 | FileCheck %s --allow-empty --check-prefix=FO |
| -; RUN: llvm-rc /dry-run /FO%t -- %p/Inputs/empty.rc 2>&1 | FileCheck %s --allow-empty --check-prefix=FO |
| +; RUN: llvm-rc -no-preprocess /dry-run /FO %t -- %p/Inputs/empty.rc 2>&1 | FileCheck %s --allow-empty --check-prefix=FO |
| +; RUN: llvm-rc -no-preprocess /dry-run /FO%t -- %p/Inputs/empty.rc 2>&1 | FileCheck %s --allow-empty --check-prefix=FO |
| |
| ; FO-NOT: Exactly one input file should be provided. |
| diff --git a/test/tools/llvm-rc/helpmsg.test b/test/tools/llvm-rc/helpmsg.test |
| index b9a55f647268..60a99a472656 100644 |
| --- a/test/tools/llvm-rc/helpmsg.test |
| +++ b/test/tools/llvm-rc/helpmsg.test |
| @@ -15,6 +15,7 @@ |
| ; CHECK-NEXT: /I <value> Add an include path. |
| ; CHECK-NEXT: /LN <value> Set the default language name. |
| ; CHECK-NEXT: /L <value> Set the default language identifier. |
| +; CHECK-NEXT: /no-preprocess Don't try to preprocess the input file. |
| ; CHECK-NEXT: /N Null-terminate all strings in the string table. |
| ; CHECK-NEXT: /U <value> Undefine a symbol for the C preprocessor. |
| ; CHECK-NEXT: /V Be verbose. |
| diff --git a/test/tools/llvm-rc/include-paths.test b/test/tools/llvm-rc/include-paths.test |
| index 0097ae88e1db..932b2c288f0d 100644 |
| --- a/test/tools/llvm-rc/include-paths.test |
| +++ b/test/tools/llvm-rc/include-paths.test |
| @@ -1,31 +1,31 @@ |
| ; Should find the bitmap if it is in the same folder as the rc file. |
| ; RUN: rm -f %t.include.res |
| -; RUN: llvm-rc /FO %t.include.res -- %p/Inputs/include.rc |
| +; RUN: llvm-rc -no-preprocess /FO %t.include.res -- %p/Inputs/include.rc |
| ; RUN: llvm-readobj %t.include.res | FileCheck --check-prefix=FOUND %s |
| |
| ; Try including files without quotes. |
| ; RUN: rm -f %t.noquotes.res |
| -; RUN: llvm-rc /FO %t.noquotes.res -- %p/Inputs/include-noquotes.rc |
| +; RUN: llvm-rc -no-preprocess /FO %t.noquotes.res -- %p/Inputs/include-noquotes.rc |
| ; RUN: llvm-readobj %t.noquotes.res | FileCheck --check-prefix=FOUND %s |
| |
| ; Should find the bitmap if the folder is explicitly specified. |
| ; RUN: rm -f %t.nested-include.res |
| -; RUN: llvm-rc /FO %t.nested-include.res /I %p/Inputs/nested -- %p/Inputs/deep-include.rc |
| +; RUN: llvm-rc -no-preprocess /FO %t.nested-include.res /I %p/Inputs/nested -- %p/Inputs/deep-include.rc |
| ; RUN: llvm-readobj %t.nested-include.res | FileCheck --check-prefix=FOUND %s |
| |
| ; The include dir can be specified via the INCLUDE env var too. |
| ; RUN: rm -f %t.nested-include.res |
| -; RUN: env INCLUDE=%p/Inputs/nested llvm-rc /FO %t.nested-include.res -- %p/Inputs/deep-include.rc |
| +; RUN: env INCLUDE=%p/Inputs/nested llvm-rc -no-preprocess /FO %t.nested-include.res -- %p/Inputs/deep-include.rc |
| ; RUN: llvm-readobj %t.nested-include.res | FileCheck --check-prefix=FOUND %s |
| |
| ; Specifying the /X option should make it ignore the INCLUDE variable. |
| ; RUN: rm -f %t.nested-include.res |
| -; RUN: not env INCLUDE=%p/Inputs/nested llvm-rc /X /FO %t.nested-include.res -- %p/Inputs/deep-include.rc 2>&1 \ |
| +; RUN: not env INCLUDE=%p/Inputs/nested llvm-rc -no-preprocess /X /FO %t.nested-include.res -- %p/Inputs/deep-include.rc 2>&1 \ |
| ; RUN: | FileCheck --check-prefix=MISSING %s |
| |
| ; Otherwise, it should not find the bitmap. |
| ; RUN: rm -f %t.nested-include.res |
| -; RUN: not llvm-rc /FO %t.nested-include.res -- %p/Inputs/deep-include.rc 2>&1 \ |
| +; RUN: not llvm-rc -no-preprocess /FO %t.nested-include.res -- %p/Inputs/deep-include.rc 2>&1 \ |
| ; RUN: | FileCheck --check-prefix=MISSING %s |
| |
| ; Should find the bitmap if the process's current working directory |
| @@ -34,7 +34,7 @@ |
| ; failure of other tests if run first. |
| ; RUN: rm -f %t.nested-include.res |
| ; RUN: cd %p/Inputs/nested |
| -; RUN: llvm-rc /FO %t.nested-include.res -- %p/Inputs/include.rc |
| +; RUN: llvm-rc -no-preprocess /FO %t.nested-include.res -- %p/Inputs/include.rc |
| ; RUN: llvm-readobj %t.nested-include.res | FileCheck --check-prefix=FOUND %s |
| |
| FOUND: Resource type (int): BITMAP (ID 2) |
| diff --git a/test/tools/llvm-rc/language.test b/test/tools/llvm-rc/language.test |
| index e764cde05e7b..7e70ae1630a3 100644 |
| --- a/test/tools/llvm-rc/language.test |
| +++ b/test/tools/llvm-rc/language.test |
| @@ -1,6 +1,6 @@ |
| -; RUN: llvm-rc /l 40A /FO %t.res -- %p/Inputs/language.rc |
| +; RUN: llvm-rc -no-preprocess /l 40A /FO %t.res -- %p/Inputs/language.rc |
| ; RUN: llvm-readobj %t.res | FileCheck %s |
| -; RUN: llvm-rc /l40A /FO %t.res -- %p/Inputs/language.rc |
| +; RUN: llvm-rc -no-preprocess /l40A /FO %t.res -- %p/Inputs/language.rc |
| ; RUN: llvm-readobj %t.res | FileCheck %s |
| |
| ; CHECK: Resource name (int): 1 |
| diff --git a/test/tools/llvm-rc/memoryflags-stringtable.test b/test/tools/llvm-rc/memoryflags-stringtable.test |
| index 24f68cd09e7b..3236c500745f 100644 |
| --- a/test/tools/llvm-rc/memoryflags-stringtable.test |
| +++ b/test/tools/llvm-rc/memoryflags-stringtable.test |
| @@ -1,4 +1,4 @@ |
| -; RUN: llvm-rc /FO %t -- %p/Inputs/memoryflags-stringtable.rc |
| +; RUN: llvm-rc -no-preprocess /FO %t -- %p/Inputs/memoryflags-stringtable.rc |
| ; RUN: llvm-readobj %t | FileCheck %s |
| |
| ; CHECK: Resource type (int): STRINGTABLE (ID 6) |
| diff --git a/test/tools/llvm-rc/memoryflags.test b/test/tools/llvm-rc/memoryflags.test |
| index cd9e53c4ed59..3d1fe9a4e53c 100644 |
| --- a/test/tools/llvm-rc/memoryflags.test |
| +++ b/test/tools/llvm-rc/memoryflags.test |
| @@ -1,4 +1,4 @@ |
| -; RUN: llvm-rc /FO %t -- %p/Inputs/memoryflags.rc |
| +; RUN: llvm-rc -no-preprocess /FO %t -- %p/Inputs/memoryflags.rc |
| ; RUN: llvm-readobj %t | FileCheck %s |
| |
| ; CHECK: Resource type (int): CURSOR (ID 1) |
| diff --git a/test/tools/llvm-rc/not-expr.test b/test/tools/llvm-rc/not-expr.test |
| index f785ec78c069..db7fee42a248 100644 |
| --- a/test/tools/llvm-rc/not-expr.test |
| +++ b/test/tools/llvm-rc/not-expr.test |
| @@ -1,4 +1,4 @@ |
| -; RUN: llvm-rc /FO %t -- %p/Inputs/not-expr.rc |
| +; RUN: llvm-rc -no-preprocess /FO %t -- %p/Inputs/not-expr.rc |
| ; RUN: llvm-readobj %t | FileCheck %s --check-prefix=NOTEXPR |
| |
| ; NOTEXPR: Resource type (int): DIALOG (ID 5) |
| diff --git a/test/tools/llvm-rc/parser-expr.test b/test/tools/llvm-rc/parser-expr.test |
| index e16d29de3cbc..ed6796529fdf 100644 |
| --- a/test/tools/llvm-rc/parser-expr.test |
| +++ b/test/tools/llvm-rc/parser-expr.test |
| @@ -1,4 +1,4 @@ |
| -; RUN: llvm-rc /dry-run /V -- %p/Inputs/parser-expr.rc | FileCheck %s |
| +; RUN: llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-expr.rc | FileCheck %s |
| |
| ; CHECK: Language: 5, Sublanguage: 1 |
| ; CHECK-NEXT: Language: 3, Sublanguage: 2 |
| @@ -17,36 +17,36 @@ |
| ; CHECK-NEXT: Language: 5, Sublanguage: 7 |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-expr-bad-binary-1.rc 2>&1 | FileCheck %s --check-prefix BINARY1 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-expr-bad-binary-1.rc 2>&1 | FileCheck %s --check-prefix BINARY1 |
| |
| ; BINARY1: llvm-rc: Error parsing file: expected '-', '~', integer or '(', got & |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-expr-bad-binary-2.rc 2>&1 | FileCheck %s --check-prefix BINARY2 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-expr-bad-binary-2.rc 2>&1 | FileCheck %s --check-prefix BINARY2 |
| |
| ; BINARY2: llvm-rc: Error parsing file: expected '-', '~', integer or '(', got | |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-expr-bad-binary-3.rc 2>&1 | FileCheck %s --check-prefix BINARY3 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-expr-bad-binary-3.rc 2>&1 | FileCheck %s --check-prefix BINARY3 |
| |
| ; BINARY3: llvm-rc: Error parsing file: expected '-', '~', integer or '(', got + |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-expr-bad-unary.rc 2>&1 | FileCheck %s --check-prefix UNARY |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-expr-bad-unary.rc 2>&1 | FileCheck %s --check-prefix UNARY |
| |
| ; UNARY: llvm-rc: Error parsing file: expected ',', got ~ |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-expr-unbalanced-1.rc 2>&1 | FileCheck %s --check-prefix UNBALANCED1 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-expr-unbalanced-1.rc 2>&1 | FileCheck %s --check-prefix UNBALANCED1 |
| |
| ; UNBALANCED1: llvm-rc: Error parsing file: expected ')', got , |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-expr-unbalanced-2.rc 2>&1 | FileCheck %s --check-prefix UNBALANCED2 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-expr-unbalanced-2.rc 2>&1 | FileCheck %s --check-prefix UNBALANCED2 |
| |
| ; UNBALANCED2: llvm-rc: Error parsing file: expected ',', got ) |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-expr-unbalanced-3.rc 2>&1 | FileCheck %s --check-prefix UNBALANCED3 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-expr-unbalanced-3.rc 2>&1 | FileCheck %s --check-prefix UNBALANCED3 |
| |
| ; UNBALANCED3: llvm-rc: Error parsing file: expected ',', got ) |
| diff --git a/test/tools/llvm-rc/parser.test b/test/tools/llvm-rc/parser.test |
| index e9f8cb94c8c9..2e1d981418c3 100644 |
| --- a/test/tools/llvm-rc/parser.test |
| +++ b/test/tools/llvm-rc/parser.test |
| @@ -1,4 +1,4 @@ |
| -; RUN: llvm-rc /dry-run /V -- %p/Inputs/parser-correct-everything.rc | FileCheck %s --check-prefix PGOOD |
| +; RUN: llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-correct-everything.rc | FileCheck %s --check-prefix PGOOD |
| |
| ; PGOOD: Icon (meh): "hello.bmp" |
| ; PGOOD-NEXT: Icon (Icon): "Icon" |
| @@ -100,156 +100,156 @@ |
| |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-stringtable-no-string.rc 2>&1 | FileCheck %s --check-prefix PSTRINGTABLE1 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-stringtable-no-string.rc 2>&1 | FileCheck %s --check-prefix PSTRINGTABLE1 |
| |
| ; PSTRINGTABLE1: llvm-rc: Error parsing file: expected string, got } |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-stringtable-weird-option.rc 2>&1 | FileCheck %s --check-prefix PSTRINGTABLE2 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-stringtable-weird-option.rc 2>&1 | FileCheck %s --check-prefix PSTRINGTABLE2 |
| |
| ; PSTRINGTABLE2: llvm-rc: Error parsing file: expected optional statement type, BEGIN or '{', got NONSENSETYPE |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-eof.rc 2>&1 | FileCheck %s --check-prefix PEOF |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-eof.rc 2>&1 | FileCheck %s --check-prefix PEOF |
| |
| ; PEOF: llvm-rc: Error parsing file: expected '-', '~', integer or '(', got <EOF> |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-no-characteristics-arg.rc 2>&1 | FileCheck %s --check-prefix PCHARACTERISTICS1 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-no-characteristics-arg.rc 2>&1 | FileCheck %s --check-prefix PCHARACTERISTICS1 |
| |
| ; PCHARACTERISTICS1: llvm-rc: Error parsing file: expected '-', '~', integer or '(', got BEGIN |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-nonsense-token.rc 2>&1 | FileCheck %s --check-prefix PNONSENSE1 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-nonsense-token.rc 2>&1 | FileCheck %s --check-prefix PNONSENSE1 |
| |
| ; PNONSENSE1: llvm-rc: Error parsing file: expected int or identifier, got & |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-nonsense-type.rc 2>&1 | FileCheck %s --check-prefix PNONSENSE2 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-nonsense-type.rc 2>&1 | FileCheck %s --check-prefix PNONSENSE2 |
| |
| ; PNONSENSE2: llvm-rc: Error parsing file: expected filename, '{' or BEGIN, got <EOF> |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-nonsense-type-eof.rc 2>&1 | FileCheck %s --check-prefix PNONSENSE3 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-nonsense-type-eof.rc 2>&1 | FileCheck %s --check-prefix PNONSENSE3 |
| |
| ; PNONSENSE3: llvm-rc: Error parsing file: expected int or identifier, got <EOF> |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-language-no-comma.rc 2>&1 | FileCheck %s --check-prefix PLANGUAGE1 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-language-no-comma.rc 2>&1 | FileCheck %s --check-prefix PLANGUAGE1 |
| |
| ; PLANGUAGE1: llvm-rc: Error parsing file: expected ',', got 7 |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-language-too-many-commas.rc 2>&1 | FileCheck %s --check-prefix PLANGUAGE2 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-language-too-many-commas.rc 2>&1 | FileCheck %s --check-prefix PLANGUAGE2 |
| |
| ; PLANGUAGE2: llvm-rc: Error parsing file: expected '-', '~', integer or '(', got , |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-html-extra-comma.rc 2>&1 | FileCheck %s --check-prefix PHTML2 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-html-extra-comma.rc 2>&1 | FileCheck %s --check-prefix PHTML2 |
| |
| ; PHTML2: llvm-rc: Error parsing file: expected string, got , |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-accelerators-bad-flag.rc 2>&1 | FileCheck %s --check-prefix PACCELERATORS1 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-accelerators-bad-flag.rc 2>&1 | FileCheck %s --check-prefix PACCELERATORS1 |
| |
| ; PACCELERATORS1: llvm-rc: Error parsing file: expected ASCII/VIRTKEY/NOINVERT/ALT/SHIFT/CONTROL, got HELLO |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-accelerators-bad-int-or-string.rc 2>&1 | FileCheck %s --check-prefix PACCELERATORS2 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-accelerators-bad-int-or-string.rc 2>&1 | FileCheck %s --check-prefix PACCELERATORS2 |
| |
| ; PACCELERATORS2: llvm-rc: Error parsing file: expected int or string, got NotIntOrString |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-accelerators-no-comma.rc 2>&1 | FileCheck %s --check-prefix PACCELERATORS3 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-accelerators-no-comma.rc 2>&1 | FileCheck %s --check-prefix PACCELERATORS3 |
| |
| ; PACCELERATORS3: llvm-rc: Error parsing file: expected int or string, got CONTROL |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-accelerators-no-comma-2.rc 2>&1 | FileCheck %s --check-prefix PACCELERATORS4 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-accelerators-no-comma-2.rc 2>&1 | FileCheck %s --check-prefix PACCELERATORS4 |
| |
| ; PACCELERATORS4: llvm-rc: Error parsing file: expected ',', got 10 |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-menu-bad-id.rc 2>&1 | FileCheck %s --check-prefix PMENU1 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-menu-bad-id.rc 2>&1 | FileCheck %s --check-prefix PMENU1 |
| |
| ; PMENU1: llvm-rc: Error parsing file: expected '-', '~', integer or '(', got A |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-menu-bad-flag.rc 2>&1 | FileCheck %s --check-prefix PMENU2 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-menu-bad-flag.rc 2>&1 | FileCheck %s --check-prefix PMENU2 |
| |
| ; PMENU2: llvm-rc: Error parsing file: expected CHECKED/GRAYED/HELP/INACTIVE/MENUBARBREAK/MENUBREAK, got ERRONEOUS |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-menu-missing-block.rc 2>&1 | FileCheck %s --check-prefix PMENU3 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-menu-missing-block.rc 2>&1 | FileCheck %s --check-prefix PMENU3 |
| |
| ; PMENU3: llvm-rc: Error parsing file: expected '{', got POPUP |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-menu-misspelled-separator.rc 2>&1 | FileCheck %s --check-prefix PMENU4 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-menu-misspelled-separator.rc 2>&1 | FileCheck %s --check-prefix PMENU4 |
| |
| ; PMENU4: llvm-rc: Error parsing file: expected SEPARATOR or string, got NOTSEPARATOR |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-dialog-cant-give-helpid.rc 2>&1 | FileCheck %s --check-prefix PDIALOG1 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-dialog-cant-give-helpid.rc 2>&1 | FileCheck %s --check-prefix PDIALOG1 |
| |
| ; PDIALOG1: llvm-rc: Error parsing file: expected identifier, got , |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-dialog-too-few-args.rc 2>&1 | FileCheck %s --check-prefix PDIALOG2 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-dialog-too-few-args.rc 2>&1 | FileCheck %s --check-prefix PDIALOG2 |
| |
| ; PDIALOG2: llvm-rc: Error parsing file: expected ',', got } |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-dialog-too-many-args.rc 2>&1 | FileCheck %s --check-prefix PDIALOG3 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-dialog-too-many-args.rc 2>&1 | FileCheck %s --check-prefix PDIALOG3 |
| |
| ; PDIALOG3: llvm-rc: Error parsing file: expected identifier, got , |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-dialog-unknown-type.rc 2>&1 | FileCheck %s --check-prefix PDIALOG4 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-dialog-unknown-type.rc 2>&1 | FileCheck %s --check-prefix PDIALOG4 |
| |
| ; PDIALOG4: llvm-rc: Error parsing file: expected control type, END or '}', got UNKNOWN |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-dialog-unnecessary-string.rc 2>&1 | FileCheck %s --check-prefix PDIALOG5 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-dialog-unnecessary-string.rc 2>&1 | FileCheck %s --check-prefix PDIALOG5 |
| |
| ; PDIALOG5: llvm-rc: Error parsing file: expected '-', '~', integer or '(', got "This shouldn't be here" |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-dialog-simple-font.rc 2>&1 | FileCheck %s --check-prefix PDIALOG6 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-dialog-simple-font.rc 2>&1 | FileCheck %s --check-prefix PDIALOG6 |
| |
| ; PDIALOG6: llvm-rc: Error parsing file: expected identifier, got , |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-versioninfo-wrong-fixed.rc 2>&1 | FileCheck %s --check-prefix PVERSIONINFO1 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-versioninfo-wrong-fixed.rc 2>&1 | FileCheck %s --check-prefix PVERSIONINFO1 |
| |
| ; PVERSIONINFO1: llvm-rc: Error parsing file: expected fixed VERSIONINFO statement type, got WEIRDFIXED |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-versioninfo-named-main-block.rc 2>&1 | FileCheck %s --check-prefix PVERSIONINFO2 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-versioninfo-named-main-block.rc 2>&1 | FileCheck %s --check-prefix PVERSIONINFO2 |
| |
| ; PVERSIONINFO2: llvm-rc: Error parsing file: expected fixed VERSIONINFO statement type, got BLOCK |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-versioninfo-unnamed-inner-block.rc 2>&1 | FileCheck %s --check-prefix PVERSIONINFO3 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-versioninfo-unnamed-inner-block.rc 2>&1 | FileCheck %s --check-prefix PVERSIONINFO3 |
| |
| ; PVERSIONINFO3: llvm-rc: Error parsing file: expected string, got { |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-versioninfo-unnamed-value.rc 2>&1 | FileCheck %s --check-prefix PVERSIONINFO4 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-versioninfo-unnamed-value.rc 2>&1 | FileCheck %s --check-prefix PVERSIONINFO4 |
| |
| ; PVERSIONINFO4: llvm-rc: Error parsing file: expected string, got END |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-versioninfo-bad-type.rc 2>&1 | FileCheck %s --check-prefix PVERSIONINFO5 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-versioninfo-bad-type.rc 2>&1 | FileCheck %s --check-prefix PVERSIONINFO5 |
| |
| ; PVERSIONINFO5: llvm-rc: Error parsing file: expected BLOCK or VALUE, got INCORRECT |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-versioninfo-repeated-fixed.rc 2>&1 | FileCheck %s --check-prefix PVERSIONINFO6 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-versioninfo-repeated-fixed.rc 2>&1 | FileCheck %s --check-prefix PVERSIONINFO6 |
| |
| ; PVERSIONINFO6: llvm-rc: Error parsing file: expected yet unread fixed VERSIONINFO statement type, got FILEVERSION |
| |
| |
| -; RUN: not llvm-rc /dry-run /V -- %p/Inputs/parser-user-invalid-contents.rc 2>&1 | FileCheck %s --check-prefix PUSER1 |
| +; RUN: not llvm-rc -no-preprocess /dry-run /V -- %p/Inputs/parser-user-invalid-contents.rc 2>&1 | FileCheck %s --check-prefix PUSER1 |
| |
| ; PUSER1: llvm-rc: Error parsing file: expected int or string, got InvalidToken |
| diff --git a/test/tools/llvm-rc/preproc.test b/test/tools/llvm-rc/preproc.test |
| new file mode 100644 |
| index 000000000000..f55e5434dce3 |
| --- /dev/null |
| +++ b/test/tools/llvm-rc/preproc.test |
| @@ -0,0 +1,3 @@ |
| +; RUN: llvm-rc -### -i%p "-DFOO1=\"foo bar\"" -UFOO2 -D FOO3 -- %p/Inputs/empty.rc | FileCheck %s |
| + |
| +; CHECK: {{^}} "clang" "--driver-mode=gcc" "-target" "{{.*}}-pc-windows-msvc-coff" "-E" "-xc" "-DRC_INVOKED" "{{.*}}empty.rc" "-o" "{{.*}}preproc-{{.*}}.rc" "-I" "{{.*}}" "-D" "FOO1=\"foo bar\"" "-U" "FOO2" "-D" "FOO3"{{$}} |
| diff --git a/test/tools/llvm-rc/tag-accelerators.test b/test/tools/llvm-rc/tag-accelerators.test |
| index 73ce6ae08378..336727f61768 100644 |
| --- a/test/tools/llvm-rc/tag-accelerators.test |
| +++ b/test/tools/llvm-rc/tag-accelerators.test |
| @@ -1,4 +1,4 @@ |
| -; RUN: llvm-rc /FO %t -- %p/Inputs/tag-accelerators.rc |
| +; RUN: llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-accelerators.rc |
| ; RUN: llvm-readobj %t | FileCheck %s --check-prefix=ACCELERATORS |
| |
| ; ACCELERATORS: Resource type (int): ACCELERATOR (ID 9) |
| @@ -79,79 +79,79 @@ |
| ; ACCELERATORS-NEXT: ) |
| |
| |
| -; RUN: not llvm-rc /FO %t -- %p/Inputs/tag-accelerators-bad-id.rc 2>&1 | FileCheck %s --check-prefix BADID |
| +; RUN: not llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-accelerators-bad-id.rc 2>&1 | FileCheck %s --check-prefix BADID |
| |
| ; BADID: llvm-rc: Error in ACCELERATORS statement (ID 1): |
| ; BADID-NEXT: ACCELERATORS entry ID (1234567) does not fit in 16 bits. |
| |
| |
| -; RUN: not llvm-rc /FO %t -- %p/Inputs/tag-accelerators-ascii-virtkey.rc 2>&1 | FileCheck %s --check-prefix ASCII1 |
| +; RUN: not llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-accelerators-ascii-virtkey.rc 2>&1 | FileCheck %s --check-prefix ASCII1 |
| |
| ; ASCII1: llvm-rc: Error in ACCELERATORS statement (ID 2): |
| ; ASCII1-NEXT: Accelerator ID 15: Accelerator can't be both ASCII and VIRTKEY |
| |
| |
| -; RUN: not llvm-rc /FO %t -- %p/Inputs/tag-accelerators-ascii-control.rc 2>&1 | FileCheck %s --check-prefix ASCII2 |
| +; RUN: not llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-accelerators-ascii-control.rc 2>&1 | FileCheck %s --check-prefix ASCII2 |
| |
| ; ASCII2: llvm-rc: Error in ACCELERATORS statement (ID 2): |
| ; ASCII2-NEXT: Accelerator ID 15: Can only apply ALT, SHIFT or CONTROL to VIRTKEY accelerators |
| |
| |
| -; RUN: not llvm-rc /FO %t -- %p/Inputs/tag-accelerators-ascii-shift.rc 2>&1 | FileCheck %s --check-prefix ASCII3 |
| +; RUN: not llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-accelerators-ascii-shift.rc 2>&1 | FileCheck %s --check-prefix ASCII3 |
| |
| ; ASCII3: llvm-rc: Error in ACCELERATORS statement (ID 2): |
| ; ASCII3-NEXT: Accelerator ID 15: Can only apply ALT, SHIFT or CONTROL to VIRTKEY accelerators |
| |
| |
| -; RUN: not llvm-rc /FO %t -- %p/Inputs/tag-accelerators-ascii-alt.rc 2>&1 | FileCheck %s --check-prefix ASCII4 |
| +; RUN: not llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-accelerators-ascii-alt.rc 2>&1 | FileCheck %s --check-prefix ASCII4 |
| |
| ; ASCII4: llvm-rc: Error in ACCELERATORS statement (ID 2): |
| ; ASCII4-NEXT: Accelerator ID 15: Can only apply ALT, SHIFT or CONTROL to VIRTKEY accelerators |
| |
| |
| -; RUN: not llvm-rc /FO %t -- %p/Inputs/tag-accelerators-bad-key-id.rc 2>&1 | FileCheck %s --check-prefix BADKEYID |
| +; RUN: not llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-accelerators-bad-key-id.rc 2>&1 | FileCheck %s --check-prefix BADKEYID |
| |
| ; BADKEYID: llvm-rc: Error in ACCELERATORS statement (ID 9): |
| ; BADKEYID-NEXT: Numeric event key ID (1234567) does not fit in 16 bits. |
| |
| |
| -; RUN: not llvm-rc /FO %t -- %p/Inputs/tag-accelerators-too-short.rc 2>&1 | FileCheck %s --check-prefix LENGTH1 |
| +; RUN: not llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-accelerators-too-short.rc 2>&1 | FileCheck %s --check-prefix LENGTH1 |
| |
| ; LENGTH1: llvm-rc: Error in ACCELERATORS statement (ID 10): |
| ; LENGTH1-NEXT: Accelerator ID 12: Accelerator string events should have length 1 or 2 |
| |
| |
| -; RUN: not llvm-rc /FO %t -- %p/Inputs/tag-accelerators-too-long.rc 2>&1 | FileCheck %s --check-prefix LENGTH2 |
| +; RUN: not llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-accelerators-too-long.rc 2>&1 | FileCheck %s --check-prefix LENGTH2 |
| |
| ; LENGTH2: llvm-rc: Error in ACCELERATORS statement (ID 12): |
| ; LENGTH2-NEXT: Accelerator ID 5: Accelerator string events should have length 1 or 2 |
| |
| |
| -; RUN: not llvm-rc /FO %t -- %p/Inputs/tag-accelerators-only-caret.rc 2>&1 | FileCheck %s --check-prefix CARET1 |
| +; RUN: not llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-accelerators-only-caret.rc 2>&1 | FileCheck %s --check-prefix CARET1 |
| |
| ; CARET1: llvm-rc: Error in ACCELERATORS statement (ID 555): |
| ; CARET1-NEXT: Accelerator ID 100: No character following '^' in accelerator event |
| |
| |
| -; RUN: not llvm-rc /FO %t -- %p/Inputs/tag-accelerators-no-caret.rc 2>&1 | FileCheck %s --check-prefix CARET2 |
| +; RUN: not llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-accelerators-no-caret.rc 2>&1 | FileCheck %s --check-prefix CARET2 |
| |
| ; CARET2: llvm-rc: Error in ACCELERATORS statement (ID 50): |
| ; CARET2-NEXT: Accelerator ID 1: Event string should be one-character, possibly preceded by '^' |
| |
| |
| -; RUN: not llvm-rc /FO %t -- %p/Inputs/tag-accelerators-long-virtkey.rc 2>&1 | FileCheck %s --check-prefix CARET3 |
| +; RUN: not llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-accelerators-long-virtkey.rc 2>&1 | FileCheck %s --check-prefix CARET3 |
| |
| ; CARET3: llvm-rc: Error in ACCELERATORS statement (ID 100): |
| ; CARET3-NEXT: Accelerator ID 10: VIRTKEY accelerator events can't be preceded by '^' |
| |
| |
| -; RUN: not llvm-rc /FO %t -- %p/Inputs/tag-accelerators-control-nonalpha.rc 2>&1 | FileCheck %s --check-prefix NONALPHA1 |
| +; RUN: not llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-accelerators-control-nonalpha.rc 2>&1 | FileCheck %s --check-prefix NONALPHA1 |
| |
| ; NONALPHA1: llvm-rc: Error in ACCELERATORS statement (ID 100): |
| ; NONALPHA1-NEXT: Accelerator ID 1: Control character accelerator event should be alphabetic |
| |
| |
| -; RUN: not llvm-rc /FO %t -- %p/Inputs/tag-accelerators-virtual-nonalpha.rc 2>&1 | FileCheck %s --check-prefix NONALPHA2 |
| +; RUN: not llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-accelerators-virtual-nonalpha.rc 2>&1 | FileCheck %s --check-prefix NONALPHA2 |
| |
| ; NONALPHA2: llvm-rc: Error in ACCELERATORS statement (ID 42): |
| ; NONALPHA2-NEXT: Accelerator ID 1: Non-alphanumeric characters cannot describe virtual keys |
| diff --git a/test/tools/llvm-rc/tag-dialog.test b/test/tools/llvm-rc/tag-dialog.test |
| index 023deeb27583..7e081c414fc4 100644 |
| --- a/test/tools/llvm-rc/tag-dialog.test |
| +++ b/test/tools/llvm-rc/tag-dialog.test |
| @@ -1,4 +1,4 @@ |
| -; RUN: llvm-rc /FO %t -- %p/Inputs/tag-dialog.rc |
| +; RUN: llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-dialog.rc |
| ; RUN: llvm-readobj %t | FileCheck %s --check-prefix=DIALOG |
| |
| ; DIALOG: Resource type (int): DIALOG (ID 5) |
| @@ -163,7 +163,7 @@ |
| ; DIALOG-NEXT: ) |
| |
| |
| -; RUN: llvm-rc /FO %t -- %p/Inputs/tag-dialog-headers.rc |
| +; RUN: llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-dialog-headers.rc |
| ; RUN: llvm-readobj %t | FileCheck %s --check-prefix=HEADERS |
| |
| ; HEADERS: Resource type (int): DIALOG (ID 5) |
| @@ -636,73 +636,73 @@ |
| ; HEADERS-NEXT: ) |
| |
| |
| -; RUN: not llvm-rc /FO %t -- %p/Inputs/tag-dialog-large-coord.rc 2>&1 | FileCheck %s --check-prefix COORD1 |
| +; RUN: not llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-dialog-large-coord.rc 2>&1 | FileCheck %s --check-prefix COORD1 |
| |
| ; COORD1: llvm-rc: Error in DIALOGEX statement (ID 1): |
| ; COORD1-NEXT: Dialog x-coordinate (50000) does not fit in 16-bit signed integer type. |
| |
| |
| -; RUN: not llvm-rc /FO %t -- %p/Inputs/tag-dialog-large-coord-neg.rc 2>&1 | FileCheck %s --check-prefix COORD2 |
| +; RUN: not llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-dialog-large-coord-neg.rc 2>&1 | FileCheck %s --check-prefix COORD2 |
| |
| ; COORD2: llvm-rc: Error in DIALOG statement (ID 1): |
| ; COORD2-NEXT: Dialog y-coordinate (-40000) does not fit in 16-bit signed integer type. |
| |
| |
| -; RUN: not llvm-rc /FO %t -- %p/Inputs/tag-dialog-large-size.rc 2>&1 | FileCheck %s --check-prefix COORD3 |
| +; RUN: not llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-dialog-large-size.rc 2>&1 | FileCheck %s --check-prefix COORD3 |
| |
| ; COORD3: llvm-rc: Error in DIALOGEX statement (ID 1): |
| ; COORD3-NEXT: Dialog height (32768) does not fit in 16-bit signed integer type. |
| |
| |
| -; RUN: not llvm-rc /FO %t -- %p/Inputs/tag-dialog-negative-size.rc 2>&1 | FileCheck %s --check-prefix COORD4 |
| +; RUN: not llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-dialog-negative-size.rc 2>&1 | FileCheck %s --check-prefix COORD4 |
| |
| ; COORD4: llvm-rc: Error in DIALOGEX statement (ID 1): |
| ; COORD4-NEXT: Dialog width (-50) cannot be negative. |
| |
| |
| -; RUN: not llvm-rc /FO %t -- %p/Inputs/tag-dialog-ctl-large-coord.rc 2>&1 | FileCheck %s --check-prefix CTL-COORD1 |
| +; RUN: not llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-dialog-ctl-large-coord.rc 2>&1 | FileCheck %s --check-prefix CTL-COORD1 |
| |
| ; CTL-COORD1: llvm-rc: Error in DIALOGEX statement (ID 1): |
| ; CTL-COORD1-NEXT: Error in LTEXT control (ID 1): |
| ; CTL-COORD1-NEXT: Dialog control x-coordinate (44444) does not fit in 16-bit signed integer type. |
| |
| |
| -; RUN: not llvm-rc /FO %t -- %p/Inputs/tag-dialog-ctl-large-coord-neg.rc 2>&1 | FileCheck %s --check-prefix CTL-COORD2 |
| +; RUN: not llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-dialog-ctl-large-coord-neg.rc 2>&1 | FileCheck %s --check-prefix CTL-COORD2 |
| |
| ; CTL-COORD2: llvm-rc: Error in DIALOG statement (ID 1): |
| ; CTL-COORD2-NEXT: Error in LTEXT control (ID 1): |
| ; CTL-COORD2-NEXT: Dialog control y-coordinate (-32769) does not fit in 16-bit signed integer type. |
| |
| |
| -; RUN: not llvm-rc /FO %t -- %p/Inputs/tag-dialog-ctl-large-size.rc 2>&1 | FileCheck %s --check-prefix CTL-COORD3 |
| +; RUN: not llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-dialog-ctl-large-size.rc 2>&1 | FileCheck %s --check-prefix CTL-COORD3 |
| |
| ; CTL-COORD3: llvm-rc: Error in DIALOGEX statement (ID 1): |
| ; CTL-COORD3-NEXT: Error in LTEXT control (ID 1): |
| ; CTL-COORD3-NEXT: Dialog control width (40000) does not fit in 16-bit signed integer type. |
| |
| |
| -; RUN: not llvm-rc /FO %t -- %p/Inputs/tag-dialog-ctl-negative-size.rc 2>&1 | FileCheck %s --check-prefix CTL-COORD4 |
| +; RUN: not llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-dialog-ctl-negative-size.rc 2>&1 | FileCheck %s --check-prefix CTL-COORD4 |
| |
| ; CTL-COORD4: llvm-rc: Error in DIALOG statement (ID 1): |
| ; CTL-COORD4-NEXT: Error in LTEXT control (ID 1): |
| ; CTL-COORD4-NEXT: Dialog control height (-700) cannot be negative. |
| |
| |
| -; RUN: not llvm-rc /FO %t -- %p/Inputs/tag-dialog-ctl-large-id.rc 2>&1 | FileCheck %s --check-prefix CTL-ID |
| +; RUN: not llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-dialog-ctl-large-id.rc 2>&1 | FileCheck %s --check-prefix CTL-ID |
| |
| ; CTL-ID: llvm-rc: Error in DIALOG statement (ID 5): |
| ; CTL-ID-NEXT: Error in RTEXT control (ID 100000): |
| ; CTL-ID-NEXT: Control ID in simple DIALOG resource (100000) does not fit in 16 bits. |
| |
| |
| -; RUN: not llvm-rc /FO %t -- %p/Inputs/tag-dialog-ctl-large-ref-id.rc 2>&1 | FileCheck %s --check-prefix CTL-REF-ID |
| +; RUN: not llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-dialog-ctl-large-ref-id.rc 2>&1 | FileCheck %s --check-prefix CTL-REF-ID |
| |
| ; CTL-REF-ID: llvm-rc: Error in DIALOGEX statement (ID 1): |
| ; CTL-REF-ID-NEXT: Error in CTEXT control (ID 42): |
| ; CTL-REF-ID-NEXT: Control reference ID (65536) does not fit in 16 bits. |
| |
| |
| -; RUN: not llvm-rc /FO %t -- %p/Inputs/tag-dialog-bad-style.rc 2>&1 | FileCheck %s --check-prefix STYLE |
| +; RUN: not llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-dialog-bad-style.rc 2>&1 | FileCheck %s --check-prefix STYLE |
| |
| ; STYLE: llvm-rc: Error in DIALOG statement (ID 1): |
| ; STYLE-NEXT: 16 higher bits of DIALOG resource style cannot be equal to 0xFFFF |
| diff --git a/test/tools/llvm-rc/tag-escape.test b/test/tools/llvm-rc/tag-escape.test |
| index 667a7e6076ad..5c8beb680698 100644 |
| --- a/test/tools/llvm-rc/tag-escape.test |
| +++ b/test/tools/llvm-rc/tag-escape.test |
| @@ -1,4 +1,4 @@ |
| -; RUN: llvm-rc /FO %t -- %p/Inputs/tag-escape.rc |
| +; RUN: llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-escape.rc |
| ; RUN: llvm-readobj %t | FileCheck %s |
| |
| ; CHECK: Resource type (int): MENU (ID 4) |
| diff --git a/test/tools/llvm-rc/tag-html.test b/test/tools/llvm-rc/tag-html.test |
| index 30e873e04790..3620fe954ba1 100644 |
| --- a/test/tools/llvm-rc/tag-html.test |
| +++ b/test/tools/llvm-rc/tag-html.test |
| @@ -1,6 +1,6 @@ |
| ; RUN: rm -rf %t && mkdir %t && cd %t |
| ; RUN: cp %p/Inputs/webpage*.html . |
| -; RUN: llvm-rc /FO %t/tag-html.res -- %p/Inputs/tag-html.rc |
| +; RUN: llvm-rc -no-preprocess /FO %t/tag-html.res -- %p/Inputs/tag-html.rc |
| ; RUN: llvm-readobj %t/tag-html.res | FileCheck %s --check-prefix HTML |
| |
| ; HTML: Resource type (int): HTML (ID 23) |
| diff --git a/test/tools/llvm-rc/tag-icon-cursor.test b/test/tools/llvm-rc/tag-icon-cursor.test |
| index 1451c4a816ca..cfff79944bd8 100644 |
| --- a/test/tools/llvm-rc/tag-icon-cursor.test |
| +++ b/test/tools/llvm-rc/tag-icon-cursor.test |
| @@ -1,7 +1,7 @@ |
| ; RUN: rm -rf %t |
| ; RUN: mkdir %t |
| |
| -; RUN: llvm-rc /FO %t/tag-icon-cursor.res -- %p/Inputs/tag-icon-cursor.rc |
| +; RUN: llvm-rc -no-preprocess /FO %t/tag-icon-cursor.res -- %p/Inputs/tag-icon-cursor.rc |
| ; RUN: llvm-readobj %t/tag-icon-cursor.res | FileCheck %s |
| |
| ; CHECK: Resource type (int): CURSOR (ID 1) |
| @@ -320,12 +320,12 @@ |
| ; CHECK-NEXT: ) |
| |
| |
| -; RUN: not llvm-rc /FO %t/1 -- %p/Inputs/tag-icon-cursor-nonexistent.rc 2>&1 | FileCheck %s --check-prefix NOFILE |
| +; RUN: not llvm-rc -no-preprocess /FO %t/1 -- %p/Inputs/tag-icon-cursor-nonexistent.rc 2>&1 | FileCheck %s --check-prefix NOFILE |
| ; NOFILE: llvm-rc: Error in CURSOR statement (ID 500): |
| ; NOFILE-NEXT: file not found : this-file-does-not-exist.cur |
| |
| |
| -; RUN: not llvm-rc /FO %t/1 -- %p/Inputs/tag-icon-cursor-nonsense.rc 2>&1 | FileCheck %s --check-prefix NONSENSE |
| +; RUN: not llvm-rc -no-preprocess /FO %t/1 -- %p/Inputs/tag-icon-cursor-nonsense.rc 2>&1 | FileCheck %s --check-prefix NONSENSE |
| |
| ; NONSENSE: llvm-rc: Error in ICON statement (ID 1): |
| ; NONSENSE-NEXT: Incorrect icon/cursor Reserved field; should be 0. |
| diff --git a/test/tools/llvm-rc/tag-menu.test b/test/tools/llvm-rc/tag-menu.test |
| index 58c856b700f8..3a17b22f847b 100644 |
| --- a/test/tools/llvm-rc/tag-menu.test |
| +++ b/test/tools/llvm-rc/tag-menu.test |
| @@ -1,9 +1,9 @@ |
| -; RUN: llvm-rc /FO %t -- %p/Inputs/tag-menu.rc |
| +; RUN: llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-menu.rc |
| ; RUN: llvm-readobj %t | FileCheck %s --check-prefix=MENU |
| |
| -; Test running llvm-rc without an explicit output file. |
| +; Test running llvm-rc -no-preprocess without an explicit output file. |
| ; RUN: cp %p/Inputs/tag-menu.rc %t.implicit.rc |
| -; RUN: llvm-rc -- %t.implicit.rc |
| +; RUN: llvm-rc -no-preprocess -- %t.implicit.rc |
| ; RUN: llvm-readobj %t.implicit.res | FileCheck --check-prefix=MENU %s |
| |
| ; MENU: Resource type (int): MENU (ID 4) |
| @@ -74,7 +74,7 @@ |
| ; MENU-NEXT: ) |
| |
| |
| -; RUN: not llvm-rc /FO %t -- %p/Inputs/tag-menu-bad-menuitem-id.rc 2>&1 | FileCheck %s --check-prefix BADID |
| +; RUN: not llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-menu-bad-menuitem-id.rc 2>&1 | FileCheck %s --check-prefix BADID |
| |
| ; BADID: llvm-rc: Error in MENU statement (ID 1): |
| ; BADID-NEXT: MENUITEM action ID (100000) does not fit in 16 bits. |
| diff --git a/test/tools/llvm-rc/tag-stringtable.test b/test/tools/llvm-rc/tag-stringtable.test |
| index dd7946e326f5..f62215a6b013 100644 |
| --- a/test/tools/llvm-rc/tag-stringtable.test |
| +++ b/test/tools/llvm-rc/tag-stringtable.test |
| @@ -1,4 +1,4 @@ |
| -; RUN: llvm-rc /FO %t -- %p/Inputs/tag-stringtable-basic.rc |
| +; RUN: llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-stringtable-basic.rc |
| ; RUN: llvm-readobj %t | FileCheck %s |
| |
| ; CHECK: Resource type (int): STRINGTABLE (ID 6) |
| @@ -81,7 +81,7 @@ |
| ; CHECK-NEXT: ) |
| |
| |
| -; RUN: llvm-rc /N /FO %t0 -- %p/Inputs/tag-stringtable-basic.rc |
| +; RUN: llvm-rc -no-preprocess /N /FO %t0 -- %p/Inputs/tag-stringtable-basic.rc |
| ; RUN: llvm-readobj %t0 | FileCheck %s --check-prefix=NULL |
| |
| ; NULL: Resource type (int): STRINGTABLE (ID 6) |
| @@ -166,5 +166,5 @@ |
| ; NULL-NEXT: ) |
| |
| |
| -; RUN: not llvm-rc /FO %t -- %p/Inputs/tag-stringtable-same-ids.rc 2>&1 | FileCheck %s --check-prefix SAMEIDS |
| +; RUN: not llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-stringtable-same-ids.rc 2>&1 | FileCheck %s --check-prefix SAMEIDS |
| ; SAMEIDS: llvm-rc: Multiple STRINGTABLE strings located under ID 1 |
| diff --git a/test/tools/llvm-rc/tag-user.test b/test/tools/llvm-rc/tag-user.test |
| index 44c8b758fd50..fb17d93ee92d 100644 |
| --- a/test/tools/llvm-rc/tag-user.test |
| +++ b/test/tools/llvm-rc/tag-user.test |
| @@ -2,7 +2,7 @@ |
| ; RUN: mkdir %t |
| ; RUN: cd %t |
| ; RUN: cp %p/Inputs/bitmap.bmp . |
| -; RUN: llvm-rc /FO %t/tag-user.res -- %p/Inputs/tag-user.rc |
| +; RUN: llvm-rc -no-preprocess /FO %t/tag-user.res -- %p/Inputs/tag-user.rc |
| ; RUN: llvm-readobj %t/tag-user.res | FileCheck %s |
| |
| ; CHECK: Resource type (int): ID 500 |
| diff --git a/test/tools/llvm-rc/tag-versioninfo.test b/test/tools/llvm-rc/tag-versioninfo.test |
| index 3ce534b88096..472bc575463e 100644 |
| --- a/test/tools/llvm-rc/tag-versioninfo.test |
| +++ b/test/tools/llvm-rc/tag-versioninfo.test |
| @@ -1,4 +1,4 @@ |
| -; RUN: llvm-rc /FO %t -- %p/Inputs/tag-versioninfo.rc |
| +; RUN: llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-versioninfo.rc |
| ; RUN: llvm-readobj %t | FileCheck %s |
| |
| ; CHECK: Resource type (int): VERSIONINFO (ID 16) |
| @@ -56,11 +56,11 @@ |
| ; CHECK-NEXT: ) |
| |
| |
| -; RUN: not llvm-rc /FO %t -- %p/Inputs/tag-versioninfo-mixed-ints-strings.rc 2>&1 | FileCheck %s --check-prefix STRINT |
| +; RUN: not llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-versioninfo-mixed-ints-strings.rc 2>&1 | FileCheck %s --check-prefix STRINT |
| ; STRINT: llvm-rc: Error in VERSIONINFO statement (ID 1): |
| ; STRINT-NEXT: VALUE "FileDescription" cannot contain both strings and integers |
| |
| |
| -; RUN: not llvm-rc /FO %t -- %p/Inputs/tag-versioninfo-word-too-large.rc 2>&1 | FileCheck %s --check-prefix WORD |
| +; RUN: not llvm-rc -no-preprocess /FO %t -- %p/Inputs/tag-versioninfo-word-too-large.rc 2>&1 | FileCheck %s --check-prefix WORD |
| ; WORD: llvm-rc: Error in VERSIONINFO statement (ID 1): |
| ; WORD-NEXT: VERSIONINFO integer value (65536) does not fit in 16 bits. |
| diff --git a/test/tools/llvm-rc/tokenizer.test b/test/tools/llvm-rc/tokenizer.test |
| index 59164677bac8..eb2233c89d72 100644 |
| --- a/test/tools/llvm-rc/tokenizer.test |
| +++ b/test/tools/llvm-rc/tokenizer.test |
| @@ -1,4 +1,4 @@ |
| -; RUN: not llvm-rc /V /FO %t.res -- %p/Inputs/tokens.rc | FileCheck %s |
| +; RUN: not llvm-rc -no-preprocess /V /FO %t.res -- %p/Inputs/tokens.rc | FileCheck %s |
| ; llvm-rc fails now on this sample because it is an invalid resource file |
| ; script. We silence the error message and just analyze the output. |
| |
| diff --git a/test/tools/llvm-rc/versioninfo-padding.test b/test/tools/llvm-rc/versioninfo-padding.test |
| index 41f5df8bdc31..bd230f408648 100644 |
| --- a/test/tools/llvm-rc/versioninfo-padding.test |
| +++ b/test/tools/llvm-rc/versioninfo-padding.test |
| @@ -1,4 +1,4 @@ |
| -; RUN: llvm-rc /FO %t -- %p/Inputs/versioninfo-padding.rc |
| +; RUN: llvm-rc -no-preprocess /FO %t -- %p/Inputs/versioninfo-padding.rc |
| ; RUN: llvm-readobj %t | FileCheck %s |
| |
| ; CHECK: Resource type (int): VERSIONINFO (ID 16) |
| diff --git a/tools/llvm-rc/Opts.td b/tools/llvm-rc/Opts.td |
| index 7a39a71f5aa8..6d9c0e2601a4 100644 |
| --- a/tools/llvm-rc/Opts.td |
| +++ b/tools/llvm-rc/Opts.td |
| @@ -17,13 +17,13 @@ class S_nodoc<string name> : Separate<["/", "-"], name>; |
| |
| def fileout : JS<"FO", "Change the output file location.">; |
| |
| -def define : S<"D", "Define a symbol for the C preprocessor.">; |
| -def undef : S<"U", "Undefine a symbol for the C preprocessor.">; |
| +def define : JS<"D", "Define a symbol for the C preprocessor.">; |
| +def undef : JS<"U", "Undefine a symbol for the C preprocessor.">; |
| |
| def lang_id : JS<"L", "Set the default language identifier.">; |
| def lang_name : S<"LN", "Set the default language name.">; |
| |
| -def includepath : S<"I", "Add an include path.">; |
| +def includepath : JS<"I", "Add an include path.">; |
| def noinclude : F<"X", "Ignore 'include' variable.">; |
| |
| def add_null : F<"N", "Null-terminate all strings in the string table.">; |
| @@ -34,9 +34,16 @@ def verbose : F<"V", "Be verbose.">; |
| def help : F<"?", "Display this help and exit.">; |
| def h : F<"H", "Display this help and exit.">, Alias<help>; |
| |
| +def codepage : JS<"C", "Set the codepage used for input strings.">; |
| + |
| +// llvm-rc specific options: |
| + |
| def dry_run : F<"dry-run", "Don't compile the input; only try to parse it.">; |
| |
| -def codepage : JS<"C", "Set the codepage used for input strings.">; |
| +def no_preprocess : F<"no-preprocess", "Don't try to preprocess the input file.">; |
| + |
| +// Print (but do not run) the commands to run for preprocessing |
| +def _HASH_HASH_HASH : F_nodoc<"###">; |
| |
| // Unused switches (at least for now). These will stay unimplemented |
| // in an early stage of development and can be ignored. However, we need to |
| diff --git a/tools/llvm-rc/llvm-rc.cpp b/tools/llvm-rc/llvm-rc.cpp |
| index 2007ef903c7d..ab5ecb8fa3fd 100644 |
| --- a/tools/llvm-rc/llvm-rc.cpp |
| +++ b/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()); |
| -- |
| 2.31.1.windows.1 |
| |
| |
| From b5431e75033a3c4672c0a59ce1995cf842f5c21f Mon Sep 17 00:00:00 2001 |
| From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <martin@martin.st> |
| Date: Wed, 21 Apr 2021 12:40:39 +0300 |
| Subject: [PATCH 4/5] [llvm-rc] Try to fix the Preprocessor/llvm-rc.rc test on |
| non arm/x86 architectures |
| |
| When llvm-rc invokes clang for preprocessing, it uses a target |
| triple derived from the default target. The test verifies that |
| e.g. _WIN32 is defined when preprocessing. |
| |
| If running clang with e.g. -target ppc64le-windows-msvc, that |
| particular arch/OS combination isn't hooked up, so _WIN32 doesn't |
| get defined in that configuration. Therefore, the preprocessing |
| test fails. |
| |
| Instead make llvm-rc inspect the architecture of the default target. |
| If it's one of the known supported architectures, use it as such, |
| otherwise set a default one (x86_64). (Clang can run preprocessing |
| with an x86_64 target triple, even if the x86 backend isn't |
| enabled.) |
| |
| Also remove superfluous llvm:: specifications on enums in llvm-rc.cpp. |
| --- |
| tools/llvm-rc/llvm-rc.cpp | 23 +++++++++++++++++++---- |
| 1 file changed, 19 insertions(+), 4 deletions(-) |
| |
| diff --git a/tools/llvm-rc/llvm-rc.cpp b/tools/llvm-rc/llvm-rc.cpp |
| index ab5ecb8fa3fd..b61fba78ad01 100644 |
| --- a/tools/llvm-rc/llvm-rc.cpp |
| +++ b/tools/llvm-rc/llvm-rc.cpp |
| @@ -114,10 +114,25 @@ ErrorOr<std::string> findClang(const char *Argv0) { |
| |
| 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); |
| + switch (T.getArch()) { |
| + case Triple::x86: |
| + case Triple::x86_64: |
| + case Triple::arm: |
| + case Triple::thumb: |
| + case Triple::aarch64: |
| + // These work properly with the clang driver, setting the expected |
| + // defines such as _WIN32 etc. |
| + break; |
| + default: |
| + // Other archs aren't set up for use with windows as target OS, (clang |
| + // doesn't define e.g. _WIN32 etc), so set a reasonable default arch. |
| + T.setArch(Triple::x86_64); |
| + break; |
| + } |
| + T.setOS(Triple::Win32); |
| + T.setVendor(Triple::PC); |
| + T.setEnvironment(Triple::MSVC); |
| + T.setObjectFormat(Triple::COFF); |
| return T.str(); |
| } |
| |
| -- |
| 2.31.1.windows.1 |
| |
| |
| From 63eb28c43893427edbb2ff2d0eb66173d3d4e4a0 Mon Sep 17 00:00:00 2001 |
| From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <martin@martin.st> |
| Date: Thu, 15 Apr 2021 14:38:27 +0300 |
| Subject: [PATCH 5/5] [llvm-rc] Add a GNU windres-like frontend to llvm-rc |
| |
| This primarily parses a different set of options and invokes the same |
| resource compiler as llvm-rc normally. Additionally, it can convert |
| directly to an object file (which in MSVC style setups is done with the |
| separate cvtres tool, or by the linker). |
| |
| (GNU windres also supports other conversions; from coff object file back |
| to .res, and from .res or object file back to .rc form; that's not yet |
| implemented.) |
| |
| The other bigger complication lies in being able to imply or pass the |
| intended target triple, to let clang find the corresponding mingw sysroot |
| for finding include files, and for specifying the default output object |
| machine format. |
| |
| It can be implied from the tool triple prefix, like |
| `<triple>-[llvm-]windres` or picked up from the windres option e.g. |
| `-F pe-x86-64`. In GNU windres, that option takes BFD style format names |
| such as pe-i386 or pe-x86-64. As libbfd in binutils doesn't support |
| Windows on ARM, there's no such canonical name for the ARM targets. |
| Therefore, as an LLVM specific extension, this option is extended to |
| allow passing full triples, too. |
| |
| Differential Revision: https://reviews.llvm.org/D100756 |
| --- |
| test/CMakeLists.txt | 1 + |
| test/lit.cfg.py | 3 +- |
| test/tools/llvm-rc/codepage.test | 6 + |
| test/tools/llvm-rc/language.test | 4 + |
| test/tools/llvm-rc/windres-format.test | 40 ++ |
| test/tools/llvm-rc/windres-prefix.test | 18 + |
| test/tools/llvm-rc/windres-preproc.test | 4 + |
| test/tools/llvm-rc/windres-target.test | 34 ++ |
| test/tools/llvm-rc/windres-version.test | 6 + |
| tools/llvm-rc/CMakeLists.txt | 14 +- |
| tools/llvm-rc/WindresOpts.td | 62 +++ |
| tools/llvm-rc/llvm-rc.cpp | 608 ++++++++++++++++++++---- |
| 12 files changed, 696 insertions(+), 104 deletions(-) |
| create mode 100644 llvm/test/tools/llvm-rc/windres-format.test |
| create mode 100644 llvm/test/tools/llvm-rc/windres-prefix.test |
| create mode 100644 llvm/test/tools/llvm-rc/windres-preproc.test |
| create mode 100644 llvm/test/tools/llvm-rc/windres-target.test |
| create mode 100644 llvm/test/tools/llvm-rc/windres-version.test |
| create mode 100644 llvm/tools/llvm-rc/WindresOpts.td |
| |
| diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt |
| index 691a7e14b8ce..cf7564d11942 100644 |
| --- a/test/CMakeLists.txt |
| +++ b/test/CMakeLists.txt |
| @@ -116,6 +116,7 @@ set(LLVM_TEST_DEPENDS |
| llvm-symbolizer |
| llvm-tblgen |
| llvm-undname |
| + llvm-windres |
| llvm-xray |
| not |
| obj2yaml |
| diff --git a/test/lit.cfg.py b/test/lit.cfg.py |
| index 348ab62c7bb8..4b355314d79b 100644 |
| --- a/test/lit.cfg.py |
| +++ b/test/lit.cfg.py |
| @@ -171,7 +171,8 @@ tools.extend([ |
| 'llvm-modextract', 'llvm-nm', 'llvm-objcopy', 'llvm-objdump', |
| 'llvm-pdbutil', 'llvm-profdata', 'llvm-ranlib', 'llvm-rc', 'llvm-readelf', |
| 'llvm-readobj', 'llvm-rtdyld', 'llvm-size', 'llvm-split', 'llvm-strings', |
| - 'llvm-strip', 'llvm-tblgen', 'llvm-undname', 'llvm-c-test', 'llvm-cxxfilt', |
| + 'llvm-strip', 'llvm-tblgen', 'llvm-undname', 'llvm-windres', |
| + 'llvm-c-test', 'llvm-cxxfilt', |
| 'llvm-xray', 'yaml2obj', 'obj2yaml', 'yaml-bench', 'verify-uselistorder', |
| 'bugpoint', 'llc', 'llvm-symbolizer', 'opt', 'sancov', 'sanstats']) |
| |
| diff --git a/test/tools/llvm-rc/codepage.test b/test/tools/llvm-rc/codepage.test |
| index 406ff00be53b..20639d42ecb8 100644 |
| --- a/test/tools/llvm-rc/codepage.test |
| +++ b/test/tools/llvm-rc/codepage.test |
| @@ -1,5 +1,9 @@ |
| ; RUN: llvm-rc -no-preprocess /C 65001 /FO %t.utf8.res -- %p/Inputs/utf8.rc |
| ; RUN: llvm-readobj %t.utf8.res | FileCheck %s --check-prefix=UTF8 |
| +; RUN: llvm-windres --no-preprocess -c 65001 %p/Inputs/utf8.rc %t.utf8.res |
| +; RUN: llvm-readobj %t.utf8.res | FileCheck %s --check-prefix=UTF8 |
| +; RUN: llvm-windres --no-preprocess --codepage 65001 %p/Inputs/utf8.rc %t.utf8.res |
| +; RUN: llvm-readobj %t.utf8.res | FileCheck %s --check-prefix=UTF8 |
| |
| ; UTF8: Resource type (int): STRINGTABLE (ID 6) |
| ; UTF8-NEXT: Resource name (int): 1 |
| @@ -24,6 +28,8 @@ |
| |
| ; RUN: llvm-rc -no-preprocess /C 1252 /FO %t.cp1252.res -- %p/Inputs/cp1252.rc |
| ; RUN: llvm-readobj %t.cp1252.res | FileCheck %s --check-prefix=CP1252 |
| +; RUN: llvm-windres --no-preprocess -c 1252 %p/Inputs/cp1252.rc %t.cp1252.res |
| +; RUN: llvm-readobj %t.cp1252.res | FileCheck %s --check-prefix=CP1252 |
| |
| ; CP1252: Resource type (int): STRINGTABLE (ID 6) |
| ; CP1252-NEXT: Resource name (int): 1 |
| diff --git a/test/tools/llvm-rc/language.test b/test/tools/llvm-rc/language.test |
| index 7e70ae1630a3..9960ae108dfe 100644 |
| --- a/test/tools/llvm-rc/language.test |
| +++ b/test/tools/llvm-rc/language.test |
| @@ -2,6 +2,10 @@ |
| ; RUN: llvm-readobj %t.res | FileCheck %s |
| ; RUN: llvm-rc -no-preprocess /l40A /FO %t.res -- %p/Inputs/language.rc |
| ; RUN: llvm-readobj %t.res | FileCheck %s |
| +; RUN: llvm-windres --no-preprocess -l 40A %p/Inputs/language.rc %t.res |
| +; RUN: llvm-readobj %t.res | FileCheck %s |
| +; RUN: llvm-windres --no-preprocess --language 40A %p/Inputs/language.rc %t.res |
| +; RUN: llvm-readobj %t.res | FileCheck %s |
| |
| ; CHECK: Resource name (int): 1 |
| ; CHECK-NEXT: Data version: |
| diff --git a/test/tools/llvm-rc/windres-format.test b/test/tools/llvm-rc/windres-format.test |
| new file mode 100644 |
| index 000000000000..81e6147d94b4 |
| --- /dev/null |
| +++ b/test/tools/llvm-rc/windres-format.test |
| @@ -0,0 +1,40 @@ |
| +; Check that the various input/output formats (rc/res/coff) are implied |
| +; from file suffixes. |
| + |
| +; RUN: rm -f %t.res |
| +; RUN: llvm-windres --no-preprocess %p/Inputs/tag-stringtable-basic.rc %t.res |
| +; RUN: llvm-readobj %t.res | FileCheck %s --check-prefix=CHECK-RES |
| + |
| +; RUN: rm -f %t.o |
| +; RUN: llvm-windres --no-preprocess -F pe-x86-64 %p/Inputs/tag-stringtable-basic.rc %t.o |
| +; RUN: llvm-readobj --coff-resources %t.o | FileCheck %s --check-prefix=CHECK-OBJ |
| + |
| +; RUN: rm -f %t.obj |
| +; RUN: llvm-windres -F pe-x86-64 %t.res %t.obj |
| +; RUN: llvm-readobj --coff-resources %t.obj | FileCheck %s --check-prefix=CHECK-OBJ |
| + |
| +; Check that we can specify the input/output file types explicitly. |
| +; Also check options for specifying the input/output file names. |
| + |
| +; RUN: cat %p/Inputs/tag-stringtable-basic.rc > %t-anonymous |
| +; RUN: rm -f %t-anonymous2 |
| +; RUN: llvm-windres --no-preprocess -O res -J rc -o %t-anonymous2 -i %t-anonymous |
| +; RUN: llvm-readobj %t-anonymous2 | FileCheck %s --check-prefix=CHECK-RES |
| + |
| +; RUN: rm -f %t-anonymous3 |
| +; RUN: llvm-windres -F pe-x86-64 -J res -O coff -i%t-anonymous2 -o%t-anonymous3 |
| +; RUN: llvm-readobj --coff-resources %t-anonymous3 | FileCheck %s --check-prefix=CHECK-OBJ |
| + |
| +; CHECK-RES: Resource type (int): STRINGTABLE |
| + |
| +; CHECK-OBJ: Format: COFF-x86-64 |
| +; CHECK-OBJ: Resources [ |
| +; CHECK-OBJ: Total Number of Resources: |
| + |
| +; Check for format conversions that currently aren't supported. |
| + |
| +; RUN: not llvm-windres -F pe-x86-64 -J res -O rc -i%t-anonymous2 -o%t-anonymous 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-OUTPUT |
| +; RUN: not llvm-windres -F pe-x86-64 -J coff -O res -i%t-anonymous3 -o%t-anonymous2 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-INPUT |
| + |
| +; CHECK-ERROR-OUTPUT: Unsupported output format |
| +; CHECK-ERROR-INPUT: Unsupported input format |
| diff --git a/test/tools/llvm-rc/windres-prefix.test b/test/tools/llvm-rc/windres-prefix.test |
| new file mode 100644 |
| index 000000000000..ef85f681febd |
| --- /dev/null |
| +++ b/test/tools/llvm-rc/windres-prefix.test |
| @@ -0,0 +1,18 @@ |
| +; REQUIRES: shell |
| + |
| +; RUN: rm -rf %t && mkdir %t |
| + |
| +; Check that a triple prefix on the executable gets picked up as target triple. |
| + |
| +; RUN: ln -fs $(which llvm-windres) %t/aarch64-w64-mingw32-windres |
| +; RUN: %t/aarch64-w64-mingw32-windres -### %p/Inputs/empty.rc %t.res | FileCheck %s --check-prefix=CHECK-PREPROC |
| +; CHECK-PREPROC: "clang" "--driver-mode=gcc" "-target" "aarch64-w64-mingw32" |
| + |
| +; Check that the triple prefix also affects the output object file type. |
| + |
| +; RUN: %t/aarch64-w64-mingw32-windres --no-preprocess %p/Inputs/tag-stringtable-basic.rc %t.o |
| +; RUN: llvm-readobj --coff-resources %t.o | FileCheck %s --check-prefix=CHECK-OBJ |
| + |
| +; CHECK-OBJ: Format: COFF-ARM64 |
| +; CHECK-OBJ: Resources [ |
| +; CHECK-OBJ: Total Number of Resources: |
| diff --git a/test/tools/llvm-rc/windres-preproc.test b/test/tools/llvm-rc/windres-preproc.test |
| new file mode 100644 |
| index 000000000000..7bddcfde6c99 |
| --- /dev/null |
| +++ b/test/tools/llvm-rc/windres-preproc.test |
| @@ -0,0 +1,4 @@ |
| +; RUN: llvm-windres -### --include-dir %p/incdir1 --include %p/incdir2 "-DFOO1=\\\"foo bar\\\"" -UFOO2 -D FOO3 --preprocessor-arg "-DFOO4=\\\"baz baz\\\"" %p/Inputs/empty.rc %t.res | FileCheck %s --check-prefix=CHECK1 |
| +; CHECK1: {{^}} "clang" "--driver-mode=gcc" "-target" "{{.*}}-w64-mingw32" "-E" "-xc" "-DRC_INVOKED" "{{.*}}empty.rc" "-o" "{{.*}}preproc-{{.*}}.rc" "-I" "{{.*}}incdir1" "-I" "{{.*}}incdir2" "-D" "FOO1=\"foo bar\"" "-U" "FOO2" "-D" "FOO3" "-DFOO4=\"baz baz\""{{$}} |
| +; RUN: llvm-windres -### --preprocessor "i686-w64-mingw32-gcc -E -DFOO=\\\"foo\\ bar\\\"" %p/Inputs/empty.rc %t.res | FileCheck %s --check-prefix=CHECK2 |
| +; CHECK2: {{^}} "i686-w64-mingw32-gcc" "-E" "-DFOO=\"foo bar\"" "{{.*}}empty.rc" "-o" "{{.*}}preproc-{{.*}}.rc"{{$}} |
| diff --git a/test/tools/llvm-rc/windres-target.test b/test/tools/llvm-rc/windres-target.test |
| new file mode 100644 |
| index 000000000000..a832c038efcc |
| --- /dev/null |
| +++ b/test/tools/llvm-rc/windres-target.test |
| @@ -0,0 +1,34 @@ |
| +; Check handling of the -F/--target option for setting a specific BFD |
| +; target name. |
| + |
| +; RUN: llvm-windres -F pe-i386 -### %p/Inputs/empty.rc %t.res | FileCheck %s --check-prefix=CHECK-I686 |
| +; RUN: llvm-windres -Fpe-i386 -### %p/Inputs/empty.rc %t.res | FileCheck %s --check-prefix=CHECK-I686 |
| +; CHECK-I686: "clang" "--driver-mode=gcc" "-target" "i686-w64-mingw32" |
| +; RUN: llvm-windres --target pe-x86-64 -### %p/Inputs/empty.rc %t.res | FileCheck %s --check-prefix=CHECK-X86-64 |
| +; RUN: llvm-windres --target=pe-x86-64 -### %p/Inputs/empty.rc %t.res | FileCheck %s --check-prefix=CHECK-X86-64 |
| +; CHECK-X86-64: "clang" "--driver-mode=gcc" "-target" "x86_64-w64-mingw32" |
| + |
| +; LLVM windres specific: Check that we can pass a full triple via the |
| +; -F/--target option, if it doesn't match the BFD target names. |
| + |
| +; RUN: llvm-windres -F armv7-w64-mingw32 -### %p/Inputs/empty.rc %t.res | FileCheck %s --check-prefix=CHECK-ARMV7 |
| +; RUN: llvm-windres --target armv7-w64-mingw32 -### %p/Inputs/empty.rc %t.res | FileCheck %s --check-prefix=CHECK-ARMV7 |
| +; CHECK-ARMV7: "clang" "--driver-mode=gcc" "-target" "armv7-w64-mingw32" |
| + |
| +; Check the actual written object types. |
| + |
| +; RUN: llvm-windres --no-preprocess -F i686-w64-mingw32 %p/Inputs/tag-stringtable-basic.rc %t.o |
| +; RUN: llvm-readobj --coff-resources %t.o | FileCheck %s --check-prefixes=CHECK-OBJ,CHECK-OBJ-I686 |
| +; RUN: llvm-windres --no-preprocess -F x86_64-w64-mingw32 %p/Inputs/tag-stringtable-basic.rc %t.o |
| +; RUN: llvm-readobj --coff-resources %t.o | FileCheck %s --check-prefixes=CHECK-OBJ,CHECK-OBJ-X86-64 |
| +; RUN: llvm-windres --no-preprocess -F armv7-w64-mingw32 %p/Inputs/tag-stringtable-basic.rc %t.o |
| +; RUN: llvm-readobj --coff-resources %t.o | FileCheck %s --check-prefixes=CHECK-OBJ,CHECK-OBJ-ARMV7 |
| +; RUN: llvm-windres --no-preprocess -F aarch64-w64-mingw32 %p/Inputs/tag-stringtable-basic.rc %t.o |
| +; RUN: llvm-readobj --coff-resources %t.o | FileCheck %s --check-prefixes=CHECK-OBJ,CHECK-OBJ-AARCH64 |
| + |
| +; CHECK-OBJ-I686: Format: COFF-i386 |
| +; CHECK-OBJ-X86-64: Format: COFF-x86-64 |
| +; CHECK-OBJ-ARMV7: Format: COFF-ARM{{$}} |
| +; CHECK-OBJ-AARCH64: Format: COFF-ARM64 |
| +; CHECK-OBJ: Resources [ |
| +; CHECK-OBJ: Total Number of Resources: |
| diff --git a/test/tools/llvm-rc/windres-version.test b/test/tools/llvm-rc/windres-version.test |
| new file mode 100644 |
| index 000000000000..71ed40b3301b |
| --- /dev/null |
| +++ b/test/tools/llvm-rc/windres-version.test |
| @@ -0,0 +1,6 @@ |
| +; RUN: llvm-windres --version | FileCheck %s |
| + |
| +; Check that the printed version string contains the words "GNU windres", |
| +; which some build systems look for. |
| + |
| +; CHECK: GNU windres |
| diff --git a/tools/llvm-rc/CMakeLists.txt b/tools/llvm-rc/CMakeLists.txt |
| index 4cadc176691c..71b79942b41e 100644 |
| --- a/tools/llvm-rc/CMakeLists.txt |
| +++ b/tools/llvm-rc/CMakeLists.txt |
| @@ -1,12 +1,16 @@ |
| set(LLVM_LINK_COMPONENTS |
| + Object |
| Option |
| Support |
| ) |
| |
| set(LLVM_TARGET_DEFINITIONS Opts.td) |
| - |
| tablegen(LLVM Opts.inc -gen-opt-parser-defs) |
| -add_public_tablegen_target(RcTableGen) |
| +add_public_tablegen_target(RcOptsTableGen) |
| + |
| +set(LLVM_TARGET_DEFINITIONS WindresOpts.td) |
| +tablegen(LLVM WindresOpts.inc -gen-opt-parser-defs) |
| +add_public_tablegen_target(WindresOptsTableGen) |
| |
| add_llvm_tool(llvm-rc |
| llvm-rc.cpp |
| @@ -16,3 +20,9 @@ add_llvm_tool(llvm-rc |
| ResourceScriptStmt.cpp |
| ResourceScriptToken.cpp |
| ) |
| + |
| +add_llvm_tool_symlink(llvm-windres llvm-rc) |
| + |
| +if(LLVM_INSTALL_BINUTILS_SYMLINKS) |
| + add_llvm_tool_symlink(windres llvm-rc) |
| +endif() |
| diff --git a/tools/llvm-rc/WindresOpts.td b/tools/llvm-rc/WindresOpts.td |
| new file mode 100644 |
| index 000000000000..3c75c85ece0f |
| --- /dev/null |
| +++ b/tools/llvm-rc/WindresOpts.td |
| @@ -0,0 +1,62 @@ |
| +include "llvm/Option/OptParser.td" |
| + |
| +multiclass Long<string name, string help> { |
| + def NAME: Separate<["--"], name>; |
| + def NAME # _eq: Joined<["--"], name # "=">, Alias<!cast<Separate>(NAME)>, |
| + HelpText<help>; |
| +} |
| + |
| +multiclass LongAlias<string name, Option orig> { |
| + def NAME: Separate<["--"], name>, Alias<orig>; |
| + def NAME # _eq: Joined<["--"], name # "=">, Alias<orig>; |
| +} |
| + |
| +multiclass LongShort<string short, string long, string help> { |
| + def NAME: Separate<["--"], long>; |
| + def NAME # _eq: Joined<["--"], long # "=">, Alias<!cast<Separate>(NAME)>, |
| + HelpText<help>; |
| + def NAME # _short: JoinedOrSeparate<["-"], short>, Alias<!cast<Separate>(NAME)>; |
| +} |
| + |
| +multiclass F<string short, string long, string help> { |
| + def NAME: Flag<["-"], short>; |
| + def NAME # _long: Flag<["--"], long>, Alias<!cast<Flag>(NAME)>, |
| + HelpText<help>; |
| +} |
| + |
| +defm input : LongShort<"i", "input", "Input file">; |
| + |
| +defm output : LongShort<"o", "output", "Output file">; |
| + |
| +defm input_format : LongShort<"J", "input-format", "Input format">; |
| + |
| +defm output_format : LongShort<"O", "output-format", "Output format">; |
| + |
| +defm preprocessor : Long<"preprocessor", "Custom preprocessor command">; |
| +defm preprocessor_arg : Long<"preprocessor-arg", "Preprocessor command argument">; |
| + |
| +defm target : LongShort<"F", "target", "Target BFD format name">; |
| + |
| +defm include_dir : LongShort<"I", "include-dir", "Include directory">; |
| +defm include_alias : LongAlias<"include", include_dir>; |
| + |
| +defm define : LongShort<"D", "define", "Define to pass to the preprocessor">; |
| + |
| +defm undef : LongShort<"U", "undefine", "Undefine to pass to the preprocessor">; |
| + |
| +defm codepage : LongShort<"c", "codepage", "Default codepage to use">; |
| + |
| +defm language : LongShort<"l", "language", "Default language to use (0x0-0xffff)">; |
| + |
| +defm verbose : F<"v", "verbose", "Enable verbose output">; |
| +defm version : F<"V", "version", "Display version">; |
| + |
| +defm help : F<"h", "help", "Display this message and exit">; |
| + |
| +// Print (but do not run) the commands to run for preprocessing |
| +def _HASH_HASH_HASH : Flag<["-"], "###">; |
| + |
| +def no_preprocess : Flag<["--"], "no-preprocess">; |
| + |
| +// Unimplemented options for compatibility |
| +def use_temp_file: Flag<["--"], "use-temp-file">; |
| diff --git a/tools/llvm-rc/llvm-rc.cpp b/tools/llvm-rc/llvm-rc.cpp |
| index b61fba78ad01..8a4ef95cfabd 100644 |
| --- a/tools/llvm-rc/llvm-rc.cpp |
| +++ b/tools/llvm-rc/llvm-rc.cpp |
| @@ -18,8 +18,10 @@ |
| #include "ResourceScriptToken.h" |
| |
| #include "llvm/ADT/Triple.h" |
| +#include "llvm/Object/WindowsResource.h" |
| #include "llvm/Option/Arg.h" |
| #include "llvm/Option/ArgList.h" |
| +#include "llvm/Support/CommandLine.h" |
| #include "llvm/Support/Error.h" |
| #include "llvm/Support/FileSystem.h" |
| #include "llvm/Support/FileUtilities.h" |
| @@ -75,8 +77,39 @@ public: |
| RcOptTable() : OptTable(InfoTable, /* IgnoreCase = */ true) {} |
| }; |
| |
| +enum Windres_ID { |
| + WINDRES_INVALID = 0, // This is not a correct option ID. |
| +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ |
| + HELPTEXT, METAVAR, VALUES) \ |
| + WINDRES_##ID, |
| +#include "WindresOpts.inc" |
| +#undef OPTION |
| +}; |
| + |
| +#define PREFIX(NAME, VALUE) const char *const WINDRES_##NAME[] = VALUE; |
| +#include "WindresOpts.inc" |
| +#undef PREFIX |
| + |
| +static const opt::OptTable::Info WindresInfoTable[] = { |
| +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ |
| + HELPTEXT, METAVAR, VALUES) \ |
| + { \ |
| + WINDRES_##PREFIX, NAME, HELPTEXT, \ |
| + METAVAR, WINDRES_##ID, opt::Option::KIND##Class, \ |
| + PARAM, FLAGS, WINDRES_##GROUP, \ |
| + WINDRES_##ALIAS, ALIASARGS, VALUES}, |
| +#include "WindresOpts.inc" |
| +#undef OPTION |
| +}; |
| + |
| +class WindresOptTable : public opt::OptTable { |
| +public: |
| + WindresOptTable() : OptTable(WindresInfoTable, /* IgnoreCase = */ false) {} |
| +}; |
| + |
| static ExitOnError ExitOnErr; |
| static FileRemover TempPreprocFile; |
| +static FileRemover TempResFile; |
| |
| LLVM_ATTRIBUTE_NORETURN static void fatalError(const Twine &Message) { |
| errs() << Message << "\n"; |
| @@ -112,9 +145,8 @@ ErrorOr<std::string> findClang(const char *Argv0) { |
| return Path; |
| } |
| |
| -std::string getClangClTriple() { |
| - Triple T(sys::getDefaultTargetTriple()); |
| - switch (T.getArch()) { |
| +Triple::ArchType getDefaultArch(Triple::ArchType Arch) { |
| + switch (Arch) { |
| case Triple::x86: |
| case Triple::x86_64: |
| case Triple::arm: |
| @@ -122,13 +154,17 @@ std::string getClangClTriple() { |
| case Triple::aarch64: |
| // These work properly with the clang driver, setting the expected |
| // defines such as _WIN32 etc. |
| - break; |
| + return Arch; |
| default: |
| // Other archs aren't set up for use with windows as target OS, (clang |
| // doesn't define e.g. _WIN32 etc), so set a reasonable default arch. |
| - T.setArch(Triple::x86_64); |
| - break; |
| + return Triple::x86_64; |
| } |
| +} |
| + |
| +std::string getClangClTriple() { |
| + Triple T(sys::getDefaultTargetTriple()); |
| + T.setArch(getDefaultArch(T.getArch())); |
| T.setOS(Triple::Win32); |
| T.setVendor(Triple::PC); |
| T.setEnvironment(Triple::MSVC); |
| @@ -136,10 +172,44 @@ std::string getClangClTriple() { |
| return T.str(); |
| } |
| |
| -bool preprocess(StringRef Src, StringRef Dst, opt::InputArgList &InputArgs, |
| +std::string getMingwTriple() { |
| + Triple T(sys::getDefaultTargetTriple()); |
| + T.setArch(getDefaultArch(T.getArch())); |
| + if (T.isWindowsGNUEnvironment()) |
| + return T.str(); |
| + // Write out the literal form of the vendor/env here, instead of |
| + // constructing them with enum values (which end up with them in |
| + // normalized form). The literal form of the triple can matter for |
| + // finding include files. |
| + return (Twine(T.getArchName()) + "-w64-mingw32").str(); |
| +} |
| + |
| +enum Format { Rc, Res, Coff, Unknown }; |
| + |
| +struct RcOptions { |
| + bool Preprocess = true; |
| + bool PrintCmdAndExit = false; |
| + std::string Triple; |
| + std::vector<std::string> PreprocessCmd; |
| + std::vector<std::string> PreprocessArgs; |
| + |
| + std::string InputFile; |
| + Format InputFormat = Rc; |
| + std::string OutputFile; |
| + Format OutputFormat = Res; |
| + |
| + bool BeVerbose = false; |
| + WriterParams Params; |
| + bool AppendNull = false; |
| + bool IsDryRun = false; |
| + // Set the default language; choose en-US arbitrarily. |
| + unsigned LangId = (/*PrimaryLangId*/ 0x09) | (/*SubLangId*/ 0x01 << 10); |
| +}; |
| + |
| +bool preprocess(StringRef Src, StringRef Dst, const RcOptions &Opts, |
| const char *Argv0) { |
| std::string Clang; |
| - if (InputArgs.hasArg(OPT__HASH_HASH_HASH)) { |
| + if (Opts.PrintCmdAndExit) { |
| Clang = "clang"; |
| } else { |
| ErrorOr<std::string> ClangOrErr = findClang(Argv0); |
| @@ -154,40 +224,27 @@ bool preprocess(StringRef Src, StringRef Dst, opt::InputArgList &InputArgs, |
| 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()); |
| + Clang, "--driver-mode=gcc", "-target", Opts.Triple, "-E", |
| + "-xc", "-DRC_INVOKED"}; |
| + if (!Opts.PreprocessCmd.empty()) { |
| + Args.clear(); |
| + for (const auto &S : Opts.PreprocessCmd) |
| + Args.push_back(S); |
| } |
| - if (InputArgs.hasArg(OPT__HASH_HASH_HASH) || InputArgs.hasArg(OPT_verbose)) { |
| + Args.push_back(Src); |
| + Args.push_back("-o"); |
| + Args.push_back(Dst); |
| + for (const auto &S : Opts.PreprocessArgs) |
| + Args.push_back(S); |
| + if (Opts.PrintCmdAndExit || Opts.BeVerbose) { |
| for (const auto &A : Args) { |
| outs() << " "; |
| - sys::printArg(outs(), A, InputArgs.hasArg(OPT__HASH_HASH_HASH)); |
| + sys::printArg(outs(), A, Opts.PrintCmdAndExit); |
| } |
| outs() << "\n"; |
| - if (InputArgs.hasArg(OPT__HASH_HASH_HASH)) |
| + if (Opts.PrintCmdAndExit) |
| exit(0); |
| } |
| // The llvm Support classes don't handle reading from stdout of a child |
| @@ -199,40 +256,340 @@ bool preprocess(StringRef Src, StringRef Dst, opt::InputArgList &InputArgs, |
| return true; |
| } |
| |
| -} // anonymous namespace |
| +static bool consume_back_lower(StringRef &S, const char *Str) { |
| + if (!S.endswith_lower(Str)) |
| + return false; |
| + S = S.drop_back(strlen(Str)); |
| + return true; |
| +} |
| |
| -int main(int Argc, const char **Argv) { |
| - InitLLVM X(Argc, Argv); |
| - ExitOnErr.setBanner("llvm-rc: "); |
| +static std::pair<bool, std::string> isWindres(llvm::StringRef Argv0) { |
| + StringRef ProgName = llvm::sys::path::stem(Argv0); |
| + // x86_64-w64-mingw32-windres -> x86_64-w64-mingw32, windres |
| + // llvm-rc -> "", llvm-rc |
| + // aarch64-w64-mingw32-llvm-windres-10.exe -> aarch64-w64-mingw32, llvm-windres |
| + ProgName = ProgName.rtrim("0123456789.-"); |
| + if (!consume_back_lower(ProgName, "windres")) |
| + return std::make_pair<bool, std::string>(false, ""); |
| + consume_back_lower(ProgName, "llvm-"); |
| + consume_back_lower(ProgName, "-"); |
| + return std::make_pair<bool, std::string>(true, ProgName.str()); |
| +} |
| |
| - RcOptTable T; |
| +Format parseFormat(StringRef S) { |
| + Format F = StringSwitch<Format>(S.lower()) |
| + .Case("rc", Rc) |
| + .Case("res", Res) |
| + .Case("coff", Coff) |
| + .Default(Unknown); |
| + if (F == Unknown) |
| + fatalError("Unable to parse '" + Twine(S) + "' as a format"); |
| + return F; |
| +} |
| + |
| +void deduceFormat(Format &Dest, StringRef File) { |
| + Format F = StringSwitch<Format>(sys::path::extension(File.lower())) |
| + .Case(".rc", Rc) |
| + .Case(".res", Res) |
| + .Case(".o", Coff) |
| + .Case(".obj", Coff) |
| + .Default(Unknown); |
| + if (F != Unknown) |
| + Dest = F; |
| +} |
| + |
| +std::string unescape(StringRef S) { |
| + std::string Out; |
| + Out.reserve(S.size()); |
| + for (int I = 0, E = S.size(); I < E; I++) { |
| + if (S[I] == '\\') { |
| + if (I + 1 < E) |
| + Out.push_back(S[++I]); |
| + else |
| + fatalError("Unterminated escape"); |
| + continue; |
| + } |
| + Out.push_back(S[I]); |
| + } |
| + return Out; |
| +} |
| + |
| +std::vector<std::string> unescapeSplit(StringRef S) { |
| + std::vector<std::string> OutArgs; |
| + std::string Out; |
| + bool InQuote = false; |
| + for (int I = 0, E = S.size(); I < E; I++) { |
| + if (S[I] == '\\') { |
| + if (I + 1 < E) |
| + Out.push_back(S[++I]); |
| + else |
| + fatalError("Unterminated escape"); |
| + continue; |
| + } |
| + if (S[I] == '"') { |
| + InQuote = !InQuote; |
| + continue; |
| + } |
| + if (S[I] == ' ' && !InQuote) { |
| + OutArgs.push_back(Out); |
| + Out.clear(); |
| + continue; |
| + } |
| + Out.push_back(S[I]); |
| + } |
| + if (InQuote) |
| + fatalError("Unterminated quote"); |
| + if (!Out.empty()) |
| + OutArgs.push_back(Out); |
| + return OutArgs; |
| +} |
| + |
| +RcOptions parseWindresOptions(ArrayRef<const char *> ArgsArr, |
| + ArrayRef<const char *> InputArgsArray, |
| + std::string Prefix) { |
| + WindresOptTable T; |
| + RcOptions Opts; |
| unsigned MAI, MAC; |
| - const char **DashDash = std::find_if( |
| - Argv + 1, Argv + Argc, [](StringRef Str) { return Str == "--"; }); |
| - ArrayRef<const char *> ArgsArr = makeArrayRef(Argv + 1, DashDash); |
| + opt::InputArgList InputArgs = T.ParseArgs(ArgsArr, MAI, MAC); |
| + |
| + // The tool prints nothing when invoked with no command-line arguments. |
| + if (InputArgs.hasArg(WINDRES_help)) { |
| + T.PrintHelp(outs(), "windres [options] file...", |
| + "LLVM windres (GNU windres compatible)", false, true); |
| + exit(0); |
| + } |
| + |
| + if (InputArgs.hasArg(WINDRES_version)) { |
| + outs() << "llvm-windres, compatible with GNU windres\n"; |
| + cl::PrintVersionMessage(); |
| + exit(0); |
| + } |
| + |
| + std::vector<std::string> FileArgs = InputArgs.getAllArgValues(WINDRES_INPUT); |
| + FileArgs.insert(FileArgs.end(), InputArgsArray.begin(), InputArgsArray.end()); |
| + |
| + if (InputArgs.hasArg(WINDRES_input)) { |
| + Opts.InputFile = InputArgs.getLastArgValue(WINDRES_input).str(); |
| + } else if (!FileArgs.empty()) { |
| + Opts.InputFile = FileArgs.front(); |
| + FileArgs.erase(FileArgs.begin()); |
| + } else { |
| + // TODO: GNU windres takes input on stdin in this case. |
| + fatalError("Missing input file"); |
| + } |
| + |
| + if (InputArgs.hasArg(WINDRES_output)) { |
| + Opts.OutputFile = InputArgs.getLastArgValue(WINDRES_output).str(); |
| + } else if (!FileArgs.empty()) { |
| + Opts.OutputFile = FileArgs.front(); |
| + FileArgs.erase(FileArgs.begin()); |
| + } else { |
| + // TODO: GNU windres writes output in rc form to stdout in this case. |
| + fatalError("Missing output file"); |
| + } |
| + |
| + if (InputArgs.hasArg(WINDRES_input_format)) { |
| + Opts.InputFormat = |
| + parseFormat(InputArgs.getLastArgValue(WINDRES_input_format)); |
| + } else { |
| + deduceFormat(Opts.InputFormat, Opts.InputFile); |
| + } |
| + if (Opts.InputFormat == Coff) |
| + fatalError("Unsupported input format"); |
| + |
| + if (InputArgs.hasArg(WINDRES_output_format)) { |
| + Opts.OutputFormat = |
| + parseFormat(InputArgs.getLastArgValue(WINDRES_output_format)); |
| + } else { |
| + // The default in windres differs from the default in RcOptions |
| + Opts.OutputFormat = Coff; |
| + deduceFormat(Opts.OutputFormat, Opts.OutputFile); |
| + } |
| + if (Opts.OutputFormat == Rc) |
| + fatalError("Unsupported output format"); |
| + if (Opts.InputFormat == Opts.OutputFormat) { |
| + outs() << "Nothing to do.\n"; |
| + exit(0); |
| + } |
| + |
| + Opts.PrintCmdAndExit = InputArgs.hasArg(WINDRES__HASH_HASH_HASH); |
| + Opts.Preprocess = !InputArgs.hasArg(WINDRES_no_preprocess); |
| + Triple TT(Prefix); |
| + if (InputArgs.hasArg(WINDRES_target)) { |
| + StringRef Value = InputArgs.getLastArgValue(WINDRES_target); |
| + if (Value == "pe-i386") |
| + Opts.Triple = "i686-w64-mingw32"; |
| + else if (Value == "pe-x86-64") |
| + Opts.Triple = "x86_64-w64-mingw32"; |
| + else |
| + // Implicit extension; if the --target value isn't one of the known |
| + // BFD targets, allow setting the full triple string via this instead. |
| + Opts.Triple = Value.str(); |
| + } else if (TT.getArch() != Triple::UnknownArch) |
| + Opts.Triple = Prefix; |
| + else |
| + Opts.Triple = getMingwTriple(); |
| |
| + for (const auto *Arg : |
| + InputArgs.filtered(WINDRES_include_dir, WINDRES_define, WINDRES_undef, |
| + WINDRES_preprocessor_arg)) { |
| + // GNU windres passes the arguments almost as-is on to popen() (it only |
| + // backslash escapes spaces in the arguments), where a shell would |
| + // unescape backslash escapes for quotes and similar. This means that |
| + // when calling GNU windres, callers need to double escape chars like |
| + // quotes, e.g. as -DSTRING=\\\"1.2.3\\\". |
| + // |
| + // Exactly how the arguments are interpreted depends on the platform |
| + // though - but the cases where this matters (where callers would have |
| + // done this double escaping) probably is confined to cases like these |
| + // quoted string defines, and those happen to work the same across unix |
| + // and windows. |
| + std::string Unescaped = unescape(Arg->getValue()); |
| + switch (Arg->getOption().getID()) { |
| + case WINDRES_include_dir: |
| + // Technically, these are handled the same way as e.g. defines, but |
| + // the way we consistently unescape the unix way breaks windows paths |
| + // with single backslashes. Alternatively, our unescape function would |
| + // need to mimic the platform specific command line parsing/unescaping |
| + // logic. |
| + Opts.Params.Include.push_back(Arg->getValue()); |
| + Opts.PreprocessArgs.push_back("-I"); |
| + Opts.PreprocessArgs.push_back(Arg->getValue()); |
| + break; |
| + case WINDRES_define: |
| + Opts.PreprocessArgs.push_back("-D"); |
| + Opts.PreprocessArgs.push_back(Unescaped); |
| + break; |
| + case WINDRES_undef: |
| + Opts.PreprocessArgs.push_back("-U"); |
| + Opts.PreprocessArgs.push_back(Unescaped); |
| + break; |
| + case WINDRES_preprocessor_arg: |
| + Opts.PreprocessArgs.push_back(Unescaped); |
| + break; |
| + } |
| + } |
| + if (InputArgs.hasArg(WINDRES_preprocessor)) |
| + Opts.PreprocessCmd = |
| + unescapeSplit(InputArgs.getLastArgValue(WINDRES_preprocessor)); |
| + |
| + Opts.Params.CodePage = CpWin1252; // Different default |
| + if (InputArgs.hasArg(WINDRES_codepage)) { |
| + if (InputArgs.getLastArgValue(WINDRES_codepage) |
| + .getAsInteger(10, Opts.Params.CodePage)) |
| + fatalError("Invalid code page: " + |
| + InputArgs.getLastArgValue(WINDRES_codepage)); |
| + } |
| + if (InputArgs.hasArg(WINDRES_language)) { |
| + if (InputArgs.getLastArgValue(WINDRES_language) |
| + .getAsInteger(16, Opts.LangId)) |
| + fatalError("Invalid language id: " + |
| + InputArgs.getLastArgValue(WINDRES_language)); |
| + } |
| + |
| + Opts.BeVerbose = InputArgs.hasArg(WINDRES_verbose); |
| + |
| + return Opts; |
| +} |
| + |
| +RcOptions parseRcOptions(ArrayRef<const char *> ArgsArr, |
| + ArrayRef<const char *> InputArgsArray) { |
| + RcOptTable T; |
| + RcOptions Opts; |
| + unsigned MAI, MAC; |
| opt::InputArgList InputArgs = T.ParseArgs(ArgsArr, MAI, MAC); |
| |
| // The tool prints nothing when invoked with no command-line arguments. |
| if (InputArgs.hasArg(OPT_help)) { |
| T.PrintHelp(outs(), "rc [options] file...", "Resource Converter", false); |
| - return 0; |
| + exit(0); |
| } |
| |
| - const bool BeVerbose = InputArgs.hasArg(OPT_verbose); |
| - |
| std::vector<std::string> InArgsInfo = InputArgs.getAllArgValues(OPT_INPUT); |
| - if (DashDash != Argv + Argc) |
| - InArgsInfo.insert(InArgsInfo.end(), DashDash + 1, Argv + Argc); |
| + InArgsInfo.insert(InArgsInfo.end(), InputArgsArray.begin(), |
| + InputArgsArray.end()); |
| if (InArgsInfo.size() != 1) { |
| fatalError("Exactly one input file should be provided."); |
| } |
| |
| - std::string PreprocessedFile = InArgsInfo[0]; |
| - if (!InputArgs.hasArg(OPT_no_preprocess)) { |
| + Opts.PrintCmdAndExit = InputArgs.hasArg(OPT__HASH_HASH_HASH); |
| + Opts.Triple = getClangClTriple(); |
| + for (const auto *Arg : |
| + InputArgs.filtered(OPT_includepath, OPT_define, OPT_undef)) { |
| + switch (Arg->getOption().getID()) { |
| + case OPT_includepath: |
| + Opts.PreprocessArgs.push_back("-I"); |
| + break; |
| + case OPT_define: |
| + Opts.PreprocessArgs.push_back("-D"); |
| + break; |
| + case OPT_undef: |
| + Opts.PreprocessArgs.push_back("-U"); |
| + break; |
| + } |
| + Opts.PreprocessArgs.push_back(Arg->getValue()); |
| + } |
| + |
| + Opts.InputFile = InArgsInfo[0]; |
| + Opts.BeVerbose = InputArgs.hasArg(OPT_verbose); |
| + Opts.Preprocess = !InputArgs.hasArg(OPT_no_preprocess); |
| + Opts.Params.Include = InputArgs.getAllArgValues(OPT_includepath); |
| + Opts.Params.NoInclude = InputArgs.hasArg(OPT_noinclude); |
| + if (Opts.Params.NoInclude) { |
| + // Clear the INLCUDE variable for the external preprocessor |
| +#ifdef _WIN32 |
| + ::_putenv("INCLUDE="); |
| +#else |
| + ::unsetenv("INCLUDE"); |
| +#endif |
| + } |
| + if (InputArgs.hasArg(OPT_codepage)) { |
| + if (InputArgs.getLastArgValue(OPT_codepage) |
| + .getAsInteger(10, Opts.Params.CodePage)) |
| + fatalError("Invalid code page: " + |
| + InputArgs.getLastArgValue(OPT_codepage)); |
| + } |
| + Opts.IsDryRun = InputArgs.hasArg(OPT_dry_run); |
| + auto OutArgsInfo = InputArgs.getAllArgValues(OPT_fileout); |
| + if (OutArgsInfo.empty()) { |
| + SmallString<128> OutputFile(Opts.InputFile); |
| + llvm::sys::fs::make_absolute(OutputFile); |
| + llvm::sys::path::replace_extension(OutputFile, "res"); |
| + OutArgsInfo.push_back(std::string(OutputFile.str())); |
| + } |
| + if (!Opts.IsDryRun) { |
| + if (OutArgsInfo.size() != 1) |
| + fatalError( |
| + "No more than one output file should be provided (using /FO flag)."); |
| + Opts.OutputFile = OutArgsInfo[0]; |
| + } |
| + Opts.AppendNull = InputArgs.hasArg(OPT_add_null); |
| + if (InputArgs.hasArg(OPT_lang_id)) { |
| + if (InputArgs.getLastArgValue(OPT_lang_id).getAsInteger(16, Opts.LangId)) |
| + fatalError("Invalid language id: " + |
| + InputArgs.getLastArgValue(OPT_lang_id)); |
| + } |
| + return Opts; |
| +} |
| + |
| +RcOptions getOptions(const char *Argv0, ArrayRef<const char *> ArgsArr, |
| + ArrayRef<const char *> InputArgs) { |
| + std::string Prefix; |
| + bool IsWindres; |
| + std::tie(IsWindres, Prefix) = isWindres(Argv0); |
| + if (IsWindres) |
| + return parseWindresOptions(ArgsArr, InputArgs, Prefix); |
| + else |
| + return parseRcOptions(ArgsArr, InputArgs); |
| +} |
| + |
| +void doRc(std::string Src, std::string Dest, RcOptions &Opts, |
| + const char *Argv0) { |
| + std::string PreprocessedFile = Src; |
| + if (Opts.Preprocess) { |
| std::string OutFile = createTempFile("preproc", "rc"); |
| TempPreprocFile.setFile(OutFile); |
| - if (preprocess(InArgsInfo[0], OutFile, InputArgs, Argv[0])) |
| + if (preprocess(Src, OutFile, Opts, Argv0)) |
| PreprocessedFile = OutFile; |
| } |
| |
| @@ -240,7 +597,7 @@ int main(int Argc, const char **Argv) { |
| ErrorOr<std::unique_ptr<MemoryBuffer>> File = |
| MemoryBuffer::getFile(PreprocessedFile); |
| if (!File) { |
| - fatalError("Error opening file '" + Twine(InArgsInfo[0]) + |
| + fatalError("Error opening file '" + Twine(PreprocessedFile) + |
| "': " + File.getError().message()); |
| } |
| |
| @@ -250,7 +607,7 @@ int main(int Argc, const char **Argv) { |
| std::string FilteredContents = filterCppOutput(Contents); |
| std::vector<RCToken> Tokens = ExitOnErr(tokenizeRC(FilteredContents)); |
| |
| - if (BeVerbose) { |
| + if (Opts.BeVerbose) { |
| const Twine TokenNames[] = { |
| #define TOKEN(Name) #Name, |
| #define SHORT_TOKEN(Name, Ch) #Name, |
| @@ -267,80 +624,129 @@ int main(int Argc, const char **Argv) { |
| } |
| } |
| |
| - WriterParams Params; |
| - SmallString<128> InputFile(InArgsInfo[0]); |
| + WriterParams &Params = Opts.Params; |
| + SmallString<128> InputFile(Src); |
| llvm::sys::fs::make_absolute(InputFile); |
| Params.InputFilePath = InputFile; |
| - Params.Include = InputArgs.getAllArgValues(OPT_includepath); |
| - Params.NoInclude = InputArgs.hasArg(OPT_noinclude); |
| |
| - if (InputArgs.hasArg(OPT_codepage)) { |
| - if (InputArgs.getLastArgValue(OPT_codepage) |
| - .getAsInteger(10, Params.CodePage)) |
| - fatalError("Invalid code page: " + |
| - InputArgs.getLastArgValue(OPT_codepage)); |
| - switch (Params.CodePage) { |
| - case CpAcp: |
| - case CpWin1252: |
| - case CpUtf8: |
| - break; |
| - default: |
| - fatalError( |
| - "Unsupported code page, only 0, 1252 and 65001 are supported!"); |
| - } |
| + switch (Params.CodePage) { |
| + case CpAcp: |
| + case CpWin1252: |
| + case CpUtf8: |
| + break; |
| + default: |
| + fatalError("Unsupported code page, only 0, 1252 and 65001 are supported!"); |
| } |
| |
| std::unique_ptr<ResourceFileWriter> Visitor; |
| - bool IsDryRun = InputArgs.hasArg(OPT_dry_run); |
| - |
| - if (!IsDryRun) { |
| - auto OutArgsInfo = InputArgs.getAllArgValues(OPT_fileout); |
| - if (OutArgsInfo.empty()) { |
| - SmallString<128> OutputFile = InputFile; |
| - llvm::sys::path::replace_extension(OutputFile, "res"); |
| - OutArgsInfo.push_back(std::string(OutputFile.str())); |
| - } |
| - |
| - if (OutArgsInfo.size() != 1) |
| - fatalError( |
| - "No more than one output file should be provided (using /FO flag)."); |
| |
| + if (!Opts.IsDryRun) { |
| std::error_code EC; |
| auto FOut = std::make_unique<raw_fd_ostream>( |
| - OutArgsInfo[0], EC, sys::fs::FA_Read | sys::fs::FA_Write); |
| + Dest, EC, sys::fs::FA_Read | sys::fs::FA_Write); |
| if (EC) |
| - fatalError("Error opening output file '" + OutArgsInfo[0] + |
| - "': " + EC.message()); |
| + fatalError("Error opening output file '" + Dest + "': " + EC.message()); |
| Visitor = std::make_unique<ResourceFileWriter>(Params, std::move(FOut)); |
| - Visitor->AppendNull = InputArgs.hasArg(OPT_add_null); |
| + Visitor->AppendNull = Opts.AppendNull; |
| |
| ExitOnErr(NullResource().visit(Visitor.get())); |
| |
| - // Set the default language; choose en-US arbitrarily. |
| - unsigned PrimaryLangId = 0x09, SubLangId = 0x01; |
| - if (InputArgs.hasArg(OPT_lang_id)) { |
| - unsigned LangId; |
| - if (InputArgs.getLastArgValue(OPT_lang_id).getAsInteger(16, LangId)) |
| - fatalError("Invalid language id: " + |
| - InputArgs.getLastArgValue(OPT_lang_id)); |
| - PrimaryLangId = LangId & 0x3ff; |
| - SubLangId = LangId >> 10; |
| - } |
| + unsigned PrimaryLangId = Opts.LangId & 0x3ff; |
| + unsigned SubLangId = Opts.LangId >> 10; |
| ExitOnErr(LanguageResource(PrimaryLangId, SubLangId).visit(Visitor.get())); |
| } |
| |
| rc::RCParser Parser{std::move(Tokens)}; |
| while (!Parser.isEof()) { |
| auto Resource = ExitOnErr(Parser.parseSingleResource()); |
| - if (BeVerbose) |
| + if (Opts.BeVerbose) |
| Resource->log(outs()); |
| - if (!IsDryRun) |
| + if (!Opts.IsDryRun) |
| ExitOnErr(Resource->visit(Visitor.get())); |
| } |
| |
| // STRINGTABLE resources come at the very end. |
| - if (!IsDryRun) |
| + if (!Opts.IsDryRun) |
| ExitOnErr(Visitor->dumpAllStringTables()); |
| +} |
| + |
| +void doCvtres(std::string Src, std::string Dest, std::string TargetTriple) { |
| + object::WindowsResourceParser Parser; |
| + |
| + ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = |
| + MemoryBuffer::getFile(Src); |
| + if (!BufferOrErr) |
| + fatalError("Error opening file '" + Twine(Src) + |
| + "': " + BufferOrErr.getError().message()); |
| + std::unique_ptr<MemoryBuffer> &Buffer = BufferOrErr.get(); |
| + std::unique_ptr<object::WindowsResource> Binary = |
| + ExitOnErr(object::WindowsResource::createWindowsResource( |
| + Buffer->getMemBufferRef())); |
| + |
| + std::vector<std::string> Duplicates; |
| + ExitOnErr(Parser.parse(Binary.get(), Duplicates)); |
| + for (const auto &DupeDiag : Duplicates) |
| + fatalError("Duplicate resources: " + DupeDiag); |
| + |
| + Triple T(TargetTriple); |
| + COFF::MachineTypes MachineType; |
| + switch (T.getArch()) { |
| + case Triple::x86: |
| + MachineType = COFF::IMAGE_FILE_MACHINE_I386; |
| + break; |
| + case Triple::x86_64: |
| + MachineType = COFF::IMAGE_FILE_MACHINE_AMD64; |
| + break; |
| + case Triple::arm: |
| + case Triple::thumb: |
| + MachineType = COFF::IMAGE_FILE_MACHINE_ARMNT; |
| + break; |
| + case Triple::aarch64: |
| + MachineType = COFF::IMAGE_FILE_MACHINE_ARM64; |
| + break; |
| + default: |
| + fatalError("Unsupported architecture in target '" + Twine(TargetTriple) + |
| + "'"); |
| + } |
| + |
| + std::unique_ptr<MemoryBuffer> OutputBuffer = |
| + ExitOnErr(object::writeWindowsResourceCOFF(MachineType, Parser, |
| + /*DateTimeStamp*/ 0)); |
| + std::unique_ptr<FileOutputBuffer> FileBuffer = |
| + ExitOnErr(FileOutputBuffer::create(Dest, OutputBuffer->getBufferSize())); |
| + std::copy(OutputBuffer->getBufferStart(), OutputBuffer->getBufferEnd(), |
| + FileBuffer->getBufferStart()); |
| + ExitOnErr(FileBuffer->commit()); |
| +} |
| + |
| +} // anonymous namespace |
| + |
| +int main(int Argc, const char **Argv) { |
| + InitLLVM X(Argc, Argv); |
| + ExitOnErr.setBanner("llvm-rc: "); |
| + |
| + const char **DashDash = std::find_if( |
| + Argv + 1, Argv + Argc, [](StringRef Str) { return Str == "--"; }); |
| + ArrayRef<const char *> ArgsArr = makeArrayRef(Argv + 1, DashDash); |
| + ArrayRef<const char *> FileArgsArr; |
| + if (DashDash != Argv + Argc) |
| + FileArgsArr = makeArrayRef(DashDash + 1, Argv + Argc); |
| + |
| + RcOptions Opts = getOptions(Argv[0], ArgsArr, FileArgsArr); |
| + |
| + std::string ResFile = Opts.OutputFile; |
| + if (Opts.InputFormat == Rc) { |
| + if (Opts.OutputFormat == Coff) { |
| + ResFile = createTempFile("rc", "res"); |
| + TempResFile.setFile(ResFile); |
| + } |
| + doRc(Opts.InputFile, ResFile, Opts, Argv[0]); |
| + } else { |
| + ResFile = Opts.InputFile; |
| + } |
| + if (Opts.OutputFormat == Coff) { |
| + doCvtres(ResFile, Opts.OutputFile, Opts.Triple); |
| + } |
| |
| return 0; |
| } |
| -- |
| 2.31.1.windows.1 |
| |