Skip to content

Commit 2bcc0fd

Browse files
committed
[llvm-windres] Implement the windres flag --use-temp-file
Whether a temp file or a pipe is used for preprocessing is an internal detail, this flag has a notable effect on the preprocessing in GNU windres. Without this flag, GNU windres passes command arguments as-is to popen(), which means they get evaluated by a shell without being re-escaped for this case. To mimic this, llvm-windres has manually tried to unescape arguments. When GNU windres is given the --use-temp-file flag, it uses a different API for invoking the preprocessor, and this API takes care of preserving special characters in the command line arguments. For users of GNU windres, this means that by using --use-temp-file, they don't need to do the (quite terrible) double escaping of quotes/spaces etc. The xz project uses the --use-temp-file flag when invoking GNU windres, see tukaani-project/xz@6b117d3. However as llvm-windres didn't implement this flag and just assumed the GNU windres popen() behaviour, they had to use a different codepath for llvm-windres. That separate codepath for llvm-windres broke later when llvm-windres got slightly more accurate unescaping of lone quotes in 0f4c6b1 / https://reviews.llvm.org/D146848 (fixing a discrepancy to GNU windres as found in llvm#57334), and this was reported in mstorsjo/llvm-mingw#363. Not touching the implementation of the --preprocessor option with respect to the --use-temp-file flag; that option is doubly tricky as GNU windres changed its behaviour in a backwards incompatible way recently (and llvm-windres currently matches the old behaviour). (See https://sourceware.org/git/?p=binutils-gdb.git;a=commitdiff;h=21c33bcbe36377abf01614fb1b9be439a3b6de20, https://sourceware.org/bugzilla/show_bug.cgi?id=27594 and https://sourceware.org/git/?p=binutils-gdb.git;a=commitdiff;h=5edb8e3f5ad8d74a83fc0df7f6e4514eed0aa77f;hp=3abbafc2aacc6706fea3e3e326e2f08d107c3672 for the behaviour change.) Differential Revision: https://reviews.llvm.org/D159223
1 parent 79d06eb commit 2bcc0fd

File tree

3 files changed

+18
-7
lines changed

3 files changed

+18
-7
lines changed

llvm/test/tools/llvm-rc/windres-preproc.test

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
; REQUIRES: shell
55

66
; RUN: llvm-windres -### --include-dir %p/incdir1 --include %p/incdir2 "-DFOO1=\\\"foo bar\\\"" -UFOO2 -D FOO3 --preprocessor-arg "-DFOO4=\\\"baz baz\\\"" -DFOO5=\"bar\" %p/Inputs/empty.rc %t.res | FileCheck %s --check-prefix=CHECK1
7+
; RUN: llvm-windres -### --include-dir %p/incdir1 --include %p/incdir2 "-DFOO1=\"foo bar\"" -UFOO2 -D FOO3 --preprocessor-arg "-DFOO4=\"baz baz\"" "-DFOO5=bar" %p/Inputs/empty.rc %t.res --use-temp-file | FileCheck %s --check-prefix=CHECK1
78
; CHECK1: {{^}} "clang" "--driver-mode=gcc" "-target" "{{.*}}-{{.*}}{{mingw32|windows-gnu}}" "-E" "-xc" "-DRC_INVOKED" "{{.*}}empty.rc" "-o" "{{.*}}preproc-{{.*}}.rc" "-I" "{{.*}}incdir1" "-I" "{{.*}}incdir2" "-D" "FOO1=\"foo bar\"" "-U" "FOO2" "-D" "FOO3" "-DFOO4=\"baz baz\"" "-D" "FOO5=bar"{{$}}
89
; RUN: llvm-windres -### --preprocessor "i686-w64-mingw32-gcc -E -DFOO=\\\"foo\\ bar\\\"" %p/Inputs/empty.rc %t.res | FileCheck %s --check-prefix=CHECK2
910
; CHECK2: {{^}} "i686-w64-mingw32-gcc" "-E" "-DFOO=\"foo bar\"" "{{.*}}empty.rc" "-o" "{{.*}}preproc-{{.*}}.rc"{{$}}

llvm/tools/llvm-rc/WindresOpts.td

+4-3
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ defm codepage : LongShort<"c", "codepage", "Default codepage to use">;
4848

4949
defm language : LongShort<"l", "language", "Default language to use (0x0-0xffff)">;
5050

51+
def use_temp_file: Flag<["--"], "use-temp-file">,
52+
HelpText<"Mimic GNU windres preprocessor option handling "
53+
"(don't unescape preprocessor options)">;
54+
5155
defm verbose : F<"v", "verbose", "Enable verbose output">;
5256
defm version : F<"V", "version", "Display version">;
5357

@@ -57,6 +61,3 @@ defm help : F<"h", "help", "Display this message and exit">;
5761
def _HASH_HASH_HASH : Flag<["-"], "###">;
5862

5963
def no_preprocess : Flag<["--"], "no-preprocess">;
60-
61-
// Unimplemented options for compatibility
62-
def use_temp_file: Flag<["--"], "use-temp-file">;

llvm/tools/llvm-rc/llvm-rc.cpp

+13-4
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,14 @@ RcOptions parseWindresOptions(ArrayRef<const char *> ArgsArr,
461461
// done this double escaping) probably is confined to cases like these
462462
// quoted string defines, and those happen to work the same across unix
463463
// and windows.
464-
std::string Unescaped = unescape(Arg->getValue());
464+
//
465+
// If GNU windres is executed with --use-temp-file, it doesn't use
466+
// popen() to invoke the preprocessor, but uses another function which
467+
// actually preserves tricky characters better. To mimic this behaviour,
468+
// don't unescape arguments here.
469+
std::string Value = Arg->getValue();
470+
if (!InputArgs.hasArg(WINDRES_use_temp_file))
471+
Value = unescape(Value);
465472
switch (Arg->getOption().getID()) {
466473
case WINDRES_include_dir:
467474
// Technically, these are handled the same way as e.g. defines, but
@@ -475,17 +482,19 @@ RcOptions parseWindresOptions(ArrayRef<const char *> ArgsArr,
475482
break;
476483
case WINDRES_define:
477484
Opts.PreprocessArgs.push_back("-D");
478-
Opts.PreprocessArgs.push_back(Unescaped);
485+
Opts.PreprocessArgs.push_back(Value);
479486
break;
480487
case WINDRES_undef:
481488
Opts.PreprocessArgs.push_back("-U");
482-
Opts.PreprocessArgs.push_back(Unescaped);
489+
Opts.PreprocessArgs.push_back(Value);
483490
break;
484491
case WINDRES_preprocessor_arg:
485-
Opts.PreprocessArgs.push_back(Unescaped);
492+
Opts.PreprocessArgs.push_back(Value);
486493
break;
487494
}
488495
}
496+
// TODO: If --use-temp-file is set, we shouldn't be unescaping
497+
// the --preprocessor argument either, only splitting it.
489498
if (InputArgs.hasArg(WINDRES_preprocessor))
490499
Opts.PreprocessCmd =
491500
unescapeSplit(InputArgs.getLastArgValue(WINDRES_preprocessor));

0 commit comments

Comments
 (0)