Open mingerfan opened 2 weeks ago
Does you code call Build::cargo_output(false)
?
That disables compiler stdout forwarding
Does you code call
Build::cargo_output(false)
?That disables compiler stdout forwarding
No, I explicitly call cargo_output(true) in my build.rs;
Could you try to invoke the command that the commandline says that cc
ran (the line with error occurred: Command
)? Seems like cc
is trying to invoke cl.exe
, but you've only showed that gcc
works
Could you try to invoke the command that the commandline says that
cc
ran (the line witherror occurred: Command
)? Seems likecc
is trying to invokecl.exe
, but you've only showed thatgcc
works
When I run this code in linux, cargo shows gcc error message. In windows(msvc), cargo doesn't.
And msvc also reports error when I use it to compile the wrong c code(using command line). But the message is non-ASCII string.
I change toolchains to gcc, and it is ok in windows.
So, is this because cargo warning or windows powershell doesn't support non-ASCII message?
Hmm, does cl.exe print error to stderr or stdout?
For stdout we just set it to inherit the stdin of build-script, so it should work fine.
For stderr forward, cc simply just write cargo:warning={msg}\n
https://docs.rs/cc/latest/src/cc/command_helpers.rs.html#239
There's line splitting, but it also flushes the stderr at the end, and I think rust stdlib deal with the encoding stuff, so it should be fine...
Hmm, does cl.exe print error to stderr or stdout?
For stdout we just set it to inherit the stdin of build-script, so it should work fine.
For stderr forward, cc simply just write
cargo:warning={msg}\n
https://docs.rs/cc/latest/src/cc/command_helpers.rs.html#239
There's line splitting, but it also flushes the stderr at the end, and I think rust stdlib deal with the encoding stuff, so it should be fine...
In my experiment, cl.exe prints error to stdout.
# cl.exe
E:\\programme\\vs2019\\software\\VC\\Tools\\MSVC\\14.41.34120\\bin\\HostX64\\x64\\cl.exe src/test.c > stdout.log 2> stderr.log
## stdout.log
test.c
src/test.c(3): error C2143: 语法错误: 缺少“;”(在“}”的前面)
## stderr.log
E:\\programme\\vs2019\\software\\VC\\Tools\\MSVC\\14.41.34120\\bin\\HostX64\\x64\\cl.exe : 用于 x64 的 Microsoft (R) C/C++ 优化编译器 19.41.34123 版
所在位置 行:1 字符: 1
+ E:\\programme\\vs2019\\software\\VC\\Tools\\MSVC\\14.41.34120\\bin\\H ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (用于 x64 的 Micros...器 19.41.34123 版:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
版权所有(C) Microsoft Corporation。保留所有权利。
while gcc prints error to stderr
# gcc
gcc src/test.c > stdoutgcc.log 2> stderrgcc.log
## stdoutgcc.log
## stderrgcc.log
gcc : src/test.c: In function 'main':
所在位置 行:1 字符: 1
+ gcc src/test.c > stdoutgcc.log 2> stderrgcc.log
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (src/test.c: In function 'main'::String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
src/test.c:2:13: error: expected ';' before '}' token
2 | return 0
| ^
| ;
3 | }
| ~
Hmm maybe we need to forward stdout as well as stderr for the cl.exe
Hmm maybe we need to forward stdout as well as stderr for the
cl.exe
After my research, I found that there are two main difficulties in supporting error capture and output for MSVC.
Firstly, UTF-8 encoding support on Windows is an experimental feature that is not enabled by default (this seems to have been the case since Windows 10 and has persisted for quite some time). As a result, many users in non-English speaking countries use PowerShell or CMD programs that are not UTF-8 encoded. The MSVC output in these terminals is also not in UTF-8 format. This makes handling stdout and stderr using Rust's String
very difficult. Here is an example:
let mut s = String::new();
if let Err(e) = child.stdout.take().unwrap().read_to_string(&mut s) {
eprintln!("Failed to read child stdout: {}", e);
} else {
eprintln!("child stdout: {}", s);
}
This works well for UTF-8 encoded terminals. However, in non-UTF-8 encoded terminals, it enters the else branch and fails to correctly output MSVC errors.
The second difficulty is that the forward_available function in command_helpers.rs currently only supports capturing and outputting stderr. In the settings, stdout seems to be either forwarded or discarded in most cases (depending on the .cargo_output(bool) setting). To capture the output, these codes need to be modified.
Capturing MSVC's stdout and outputting it in a similar manner to stderr seems to be quite challenging, so I feel that directly forwarding the output is a simpler choice.
However, the problem then becomes, why does forwarding not work effectively on Windows? This is a very strange issue. Here is my experiment:
PS C:\Users\xs\Desktop\test_cc> cargo build
Compiling test_cc v0.1.0 (C:\Users\xs\Desktop\test_cc)
error: failed to run custom build command for `test_cc v0.1.0 (C:\Users\xs\Desktop\test_cc)`
Caused by:
process didn't exit successfully: `C:\Users\xs\Desktop\test_cc\target\debug\build\test_cc-fd694f9983ca928f\build-script-build` (exit code: 1)
--- stderr
error occurred: Command "E:\\programme\\vs2019\\software\\VC\\Tools\\MSVC\\14.41.34120\\bin\\HostX64\\x64\\cl.exe" "-nologo" "-MD" "-Z7" "-Brepro" "-W4" "-Fo./2e40c9e35e9506f4-test.o" "-c" "src/test.c" with args cl.exe did not execute successfully (status code exit code: 2).
PS C:\Users\xs\Desktop\test_cc> chcp
活动代码页: 936
// change encoding to utf-8
PS C:\Users\xs\Desktop\test_cc> chcp 65001
Active code page: 65001
PS C:\Users\xs\Desktop\test_cc> cargo build
Compiling test_cc v0.1.0 (C:\Users\xs\Desktop\test_cc)
error: failed to run custom build command for `test_cc v0.1.0 (C:\Users\xs\Desktop\test_cc)`
Caused by:
process didn't exit successfully: `C:\Users\xs\Desktop\test_cc\target\debug\build\test_cc-fd694f9983ca928f\build-script-build` (exit code: 1)
--- stdout
OPT_LEVEL = Some(0)
TARGET = Some(x86_64-pc-windows-msvc)
cargo:rerun-if-env-changed=VCINSTALLDIR
VCINSTALLDIR = None
cargo:rerun-if-env-changed=VSTEL_MSBuildProjectFullPath
.....
cargo:rerun-if-env-changed=CFLAGS
CFLAGS = None
cargo:rerun-if-env-changed=CC_ENABLE_DEBUG_OUTPUT
// print error here
**_test.c
src/test.c(3): error C2143: syntax error: missing ';' before '}'_**
--- stderr
error occurred: Command "E:\\programme\\vs2019\\software\\VC\\Tools\\MSVC\\14.41.34120\\bin\\HostX64\\x64\\cl.exe" "-nologo" "-MD" "-Z7" "-Brepro" "-W4" "-Fo./2e40c9e35e9506f4-test.o" "-c" "src/test.c" with args cl.exe did not execute successfully (status code exit code: 2).
So, what happened?
So it works if it is under utf-8?
😨 cc @ChrisDenton can you take a look please?
I have no idea why forwarding fail on Windows when not using utf-8?
I've not looked into it yet but this is almost certainly a Cargo issue. Or at least has nothing to do with cc directly. I suspect you can reproduce the issue just by having a build script that prints non UTF-8 to stdout. It might not even be a Windows specific issue if it's only being encountered because cl.exe
produces non-unicode output.
I've opened a Cargo issue about this. Let's see what they say.
As I mentioned in that issue, it'd be good if cc-rs could convert the output of cl.exe
so that it is output as UTF-8. I believe I wrote something similar for rustc but that was link.exe
. I'm not sure if cl.exe
uses the same code page (old tools with a long history have some weird inconsistencies, iirc).
The quick workaround would be to use String::from_utf8_lossy
for non-unicode output.
Yes, perhaps forwarding stdout as well is the right thing to do in cc.
It would take some time for it to happen though, quite a few places need to be updated to have it supported in cc
@ChrisDenton I saw the issue in Cargo. So the current best solution is to use cargo run -vv or cargo build -vv, right? Not outputting non-UTF-8 characters seems to be a feature 🤔.
I'm looking for a way to get more user-friendly error messages to help diagnose issues in my C/C++ code or the bridging code between Rust and C. How can I achieve this?
Here's a simple example of what I'm facing:
Suppose you have a C file intended for use in Rust. You would typically compile it in build.rs using the cc crate. If the C file is correct, everything works fine. However, in the example below, the error message is quite confusing.
You can see that cc simply reports "error occurred" without providing further details. In contrast, compiling the same file with gcc highlights the specific error line.Is there a way to configure the cc crate to provide detailed gcc or msvc error messages when there are issues in my C/C++ code? How can I set this up?