Skip to content

Commit 81cc2dc

Browse files
committed
[llvm-windres] Resolve the --preprocessor executable in $PATH
The llvm::sys::ExecuteAndWait function doesn't resolve the file to be executed from $PATH - i.e. it is similar to execv(), not execvp(). Due to this, specifying a --preprocessor argument to llvm-windres only worked if it specified an absolute path to the preprocessor executable. This was observed as one of the issues in msys2/MINGW-packages#19157. Before d2fa6b6, this usage of --preprocessor seemed to work, because the first argument of Args[] was ignored and llvm-windres just executed the autodetected clang executable regardless. Also improve the error messages printed if preprocessing failed. (If the preprocessor executable was started but itself returned an error, we don't get any error string.)
1 parent 10b78cc commit 81cc2dc

File tree

2 files changed

+30
-3
lines changed

2 files changed

+30
-3
lines changed

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,18 @@
77
; 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
88
; CHECK1: {{^}} "clang" "--driver-mode=gcc" "-target" "{{.*}}-{{.*}}{{mingw32|windows-gnu}}" "-E" "-xc" "-DRC_INVOKED" "-I" "{{.*}}incdir1" "-I" "{{.*}}incdir2" "-D" "FOO1=\"foo bar\"" "-U" "FOO2" "-D" "FOO3" "-DFOO4=\"baz baz\"" "-D" "FOO5=bar" "{{.*}}empty.rc" "-o" "{{.*}}preproc-{{.*}}.rc"{{$}}
99
; RUN: llvm-windres -### --preprocessor "i686-w64-mingw32-gcc -E -DFOO=\\\"foo\\ bar\\\"" %p/Inputs/empty.rc %t.res | FileCheck %s --check-prefix=CHECK2
10-
; CHECK2: {{^}} "i686-w64-mingw32-gcc" "-E" "-DFOO=\"foo bar\"" "{{.*}}empty.rc" "-o" "{{.*}}preproc-{{.*}}.rc"{{$}}
10+
; CHECK2: {{^}} "{{.*}}i686-w64-mingw32-gcc" "-E" "-DFOO=\"foo bar\"" "{{.*}}empty.rc" "-o" "{{.*}}preproc-{{.*}}.rc"{{$}}
11+
12+
;; Test resolving the --preprocessor executable from PATH
13+
14+
; RUN: rm -rf %t-bin/testbin
15+
; RUN: mkdir -p %t-bin/testbin
16+
; RUN: ln -s llvm-windres %t-bin/testbin/i686-w64-mingw32-gcc
17+
; RUN: env PATH=%t-bin/testbin llvm-windres -### --preprocessor i686-w64-mingw32-gcc --preprocessor-arg -E --preprocessor-arg -xc -DRC_INVOKED %p/Inputs/empty.rc %t.res | FileCheck %s --check-prefix=CHECK3
18+
; CHECK3: {{^}} "{{.*}}/testbin/i686-w64-mingw32-gcc" "-E" "-xc" "-D" "RC_INVOKED" "{{.*}}empty.rc" "-o" "{{.*}}preproc-{{.*}}.rc"{{$}}
19+
20+
21+
;; Test error messages when unable to execute the preprocessor.
22+
23+
; RUN: not llvm-windres --preprocessor intentionally-missing-executable %p/Inputs/empty.rc %t.res 2>&1 | FileCheck %s --check-prefix=CHECK4
24+
; CHECK4: llvm-rc: Preprocessing failed: Executable "intentionally-missing-executable" doesn't exist!

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

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,10 +248,17 @@ void preprocess(StringRef Src, StringRef Dst, const RcOptions &Opts,
248248
SmallVector<StringRef, 8> Args = {
249249
Clang, "--driver-mode=gcc", "-target", Opts.Triple, "-E",
250250
"-xc", "-DRC_INVOKED"};
251+
std::string PreprocessorExecutable;
251252
if (!Opts.PreprocessCmd.empty()) {
252253
Args.clear();
253254
for (const auto &S : Opts.PreprocessCmd)
254255
Args.push_back(S);
256+
if (!sys::fs::can_execute(Args[0])) {
257+
if (auto P = sys::findProgramByName(Args[0])) {
258+
PreprocessorExecutable = *P;
259+
Args[0] = PreprocessorExecutable;
260+
}
261+
}
255262
}
256263
for (const auto &S : Opts.PreprocessArgs)
257264
Args.push_back(S);
@@ -269,9 +276,15 @@ void preprocess(StringRef Src, StringRef Dst, const RcOptions &Opts,
269276
}
270277
// The llvm Support classes don't handle reading from stdout of a child
271278
// process; otherwise we could avoid using a temp file.
272-
int Res = sys::ExecuteAndWait(Args[0], Args);
279+
std::string ErrMsg;
280+
int Res =
281+
sys::ExecuteAndWait(Args[0], Args, /*Env=*/std::nullopt, /*Redirects=*/{},
282+
/*SecondsToWait=*/0, /*MemoryLimit=*/0, &ErrMsg);
273283
if (Res) {
274-
fatalError("llvm-rc: Preprocessing failed.");
284+
if (!ErrMsg.empty())
285+
fatalError("llvm-rc: Preprocessing failed: " + ErrMsg);
286+
else
287+
fatalError("llvm-rc: Preprocessing failed.");
275288
}
276289
}
277290

0 commit comments

Comments
 (0)