Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to get a more friendly error message in cc? #1260

Closed
mingerfan opened this issue Nov 2, 2024 · 20 comments · Fixed by #1303
Closed

How to get a more friendly error message in cc? #1260

mingerfan opened this issue Nov 2, 2024 · 20 comments · Fixed by #1303

Comments

@mingerfan
Copy link

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.
Image
Image

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?

@NobodyXu
Copy link
Collaborator

NobodyXu commented Nov 3, 2024

Does you code call Build::cargo_output(false)?

That disables compiler stdout forwarding

@mingerfan
Copy link
Author

Does you code call Build::cargo_output(false)?

That disables compiler stdout forwarding

No, I explicitly call cargo_output(true) in my build.rs;
Image

@madsmtm
Copy link
Collaborator

madsmtm commented Nov 3, 2024

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

@mingerfan
Copy link
Author

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

When I run this code in linux, cargo shows gcc error message.
Image
In windows(msvc), cargo doesn't.
Image

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.
Image

I change toolchains to gcc, and it is ok in windows.
Image
Image

So, is this because cargo warning or windows powershell doesn't support non-ASCII message?

@NobodyXu
Copy link
Collaborator

NobodyXu commented Nov 4, 2024

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...

@mingerfan
Copy link
Author

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 | }
      | ~  

@NobodyXu
Copy link
Collaborator

NobodyXu commented Nov 4, 2024

Hmm maybe we need to forward stdout as well as stderr for the cl.exe

@mingerfan
Copy link
Author

mingerfan commented Nov 5, 2024

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?

@NobodyXu
Copy link
Collaborator

NobodyXu commented Nov 5, 2024

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?

@ChrisDenton
Copy link
Member

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.

@ChrisDenton
Copy link
Member

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).

@ChrisDenton
Copy link
Member

The quick workaround would be to use String::from_utf8_lossy for non-unicode output.

@NobodyXu
Copy link
Collaborator

NobodyXu commented Nov 5, 2024

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

@mingerfan
Copy link
Author

@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 🤔.

@madsmtm
Copy link
Collaborator

madsmtm commented Nov 24, 2024

We could perhaps also consider setting LC_ALL=C VSLANG=1033 to force compiler messages to be in English? rustc already does this when invoking the linker.

@NobodyXu
Copy link
Collaborator

Thanks Mads, I think that'd be the best solution for this!

NobodyXu added a commit that referenced this issue Nov 24, 2024
NobodyXu added a commit that referenced this issue Nov 24, 2024
@ChrisDenton
Copy link
Member

ChrisDenton commented Nov 24, 2024

VSLANG=1033 may help in some situations but it won't work at all if the user doesn't have the Visual Studio English Language pack installed and it also won't fix it for paths or other user input that contains non ASCII characters. That's why I added a function to the compiler that converts non UTF-8 output from link.exe.

@NobodyXu
Copy link
Collaborator

NobodyXu commented Nov 24, 2024

Thanks, so cargo build -vv is still the best way to fix this, though I think the PR I opened can still fix it for some msvc environments.

@ChrisDenton
Copy link
Member

I don't think cargo build -vv is a fix. More of a workaround.

A better approach for developers with admin access to their dev machines is to set the system locale to UTF-8 (note: this is only available on recent versions of Windows and is still marked as beta, though it has worked well enough for me)

System UTF-8

There should be a tick box in Administrative language settings that enables the UTF-8 locale.

Image

Ideally I do think a) cc should convert non UTF-8 output and b) cargo shouldn't hide output without even a warning that it is doing so

@NobodyXu
Copy link
Collaborator

cc should convert non UTF-8 output

It's doable but it'd make our existing codebase a bit more complex.

It be great if it can done in cargo, but if there's no other way we can do this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants