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

fix llvm-ar as archiver for msvc targets; fix clang-cl detection; fix assembler output flag detection; add clang/clang-cl windows CI #1015

Merged
merged 32 commits into from
Apr 7, 2024

Conversation

russelltg
Copy link
Contributor

@russelltg russelltg commented Mar 19, 2024

This PR contains several clang on windows improvements:

  1. properly detect clang vs clang-cl by invoking with -?, instead of checking for _MSC_VER. This is what cmake does, and _MSC_VER is always defined for msvc ABI targets, regardless of the frontend variant used
  2. Fix detection of which output assembler flag to use. It used to use complex logic, including if the C compiler is clang, which was incorrect. Use the flag based on if it's using the msvc assembler
  3. Add clang-cl/clang CI for windows
  4. Detect usage of llvm-ar and pass GNU style flags to it

Original description:

this is somewhat a nasty hack here, but it does work. when (cross) compiling for msvc and you use llvm-ar as the archiver, then you need to use gnu-style flags.

currently it attemps to run llvm-ar like:

running: "/usr/bin/llvm-ar" "-out:/workspaces/ars/build_windows_clang_x86_64_relnoopt/./cargo/build/x86_64-pc-windows-msvc/release/build/link-cplusplus-b04e59fc086748c2/out/liblink-cplusplus.a" "-nologo" "/workspaces/ars/build_windows_clang_x86_64_relnoopt/./cargo/build/x86_64-pc-windows-msvc/release/build/link-cplusplus-b04e59fc086748c2/out/0466faf07398e270-dummy.o"

which doesn't work, as llvm-ar takes in GNU-style ar flags.

i'm definitely open to a more robust way to get the archiver "Family" (maybe something similar to how we detect compiler family? idk) if that would be better

I also moved some APIs to to use Path as it avoided a string->path conversion. Let me know if that's not of interest.

With this and the other PR, I can now cross-compile to windows using clang from linux :)

EDIT: also fixes the path to the archiver not being set on when env_tool finds it

Copy link
Collaborator

@NobodyXu NobodyXu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm definitely open to a more robust way to get the archiver "Family" (maybe something similar to how we detect compiler family? idk) if that would be better

I don't know any better way than checking name, or its output of --version.

Perhaps we can try link something and check its output for signature of linker?

With this and the other PR, I can now cross-compile to windows using clang from window

Is it possible to add testing for this in CI?

src/lib.rs Outdated
@@ -2398,7 +2398,8 @@ impl Build {
}

let target = self.get_target()?;
if target.contains("msvc") {
let (mut ar, cmd, _any_flags) = self.get_ar()?;
if target.contains("msvc") && !cmd.to_str().unwrap().contains("llvm-") {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if target.contains("msvc") && !cmd.to_str().unwrap().contains("llvm-") {
if target.contains("msvc") && !cmd.to_str_lossy().contains("llvm-") {

Copy link
Contributor Author

@russelltg russelltg Mar 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied, except to_str_lossy of course doesn't exist as the lossy conversion requires a (conditional) allocation

src/lib.rs Outdated
if target.contains("msvc") {
let (mut cmd, program, any_flags) = self.get_ar()?;
let (mut cmd, program, any_flags) = self.get_ar()?;
if target.contains("msvc") && !program.to_str().unwrap().contains("llvm-") {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if target.contains("msvc") && !program.to_str().unwrap().contains("llvm-") {
if target.contains("msvc") && !program.to_str_lossy().contains("llvm-") {

this is somewhat a nasty hack here, but it does work. when (cross) compiling for msvc and you use llvm-ar as the archiver, then you need to use gnu-style flags.

currently it attemps to run llvm-ar like:

```
running: "/usr/bin/llvm-ar" "-out:/workspaces/ars/build_windows_clang_x86_64_relnoopt/./cargo/build/x86_64-pc-windows-msvc/release/build/link-cplusplus-b04e59fc086748c2/out/liblink-cplusplus.a" "-nologo" "/workspaces/ars/build_windows_clang_x86_64_relnoopt/./cargo/build/x86_64-pc-windows-msvc/release/build/link-cplusplus-b04e59fc086748c2/out/0466faf07398e270-dummy.o"
```

which doesn't work, as llvm-ar takes in GNU-style ar flags.

i'm definitely open to a more robust way to get the archiver "Family" (maybe something similar to how we detect compiler family? idk) if that would be better
.github/workflows/main.yml Outdated Show resolved Hide resolved
@russelltg
Copy link
Contributor Author

While working on that CI pass, I found that the clang-cl detection doesn't work at all....

Clang defines _MSC_VER when target is *msvc, and actually has no relation to the frontend variant. That combined with us not passing C[XX]FLAGS to the -E invocation just means that all it detects is if the host system is windows, lol....

@russelltg
Copy link
Contributor Author

While I'm working on clang cross compilation for linux->windows, I was going to add the CI pass to windows so I don't have to worry about getting windows SDK/msvc installed in Linux. But since the host is windows it ends up thinking clang is clang-cl!

@russelltg
Copy link
Contributor Author

I know you're waiting on this to release--I think it's still a good change of course, but that CI is not going to work yet. Want me to rip out CI and open a new PR with hopefully some way to fix clang-cl detection, that can be merged after the release?

@NobodyXu
Copy link
Collaborator

Want me to rip out CI and open a new PR with hopefully some way to fix clang-cl detection, that can be merged after the release?

I would prefer the clang-cl to be fixed as well before cutting a new release to avoid regression.

@NobodyXu
Copy link
Collaborator

BTW, can you please update the PR title and description?

Thanks!!

@russelltg russelltg changed the title fix llvm-ar as archiver for msvc targets fix llvm-ar as archiver for msvc targets; fix clang-cl detection; fix assembler output flag detection; add clang/clang-cl windows CI Mar 21, 2024
@russelltg
Copy link
Contributor Author

Okay, this seems to work now 😅

It ended up being more changes than I thought! Do you want me to split into mutiple PRs? Im also happy to rebase it into a cleaner incremental history for future bisecting

@russelltg
Copy link
Contributor Author

Hmm it's hard to be sure that the env vars are actually being set....

@russelltg
Copy link
Contributor Author

russelltg commented Mar 21, 2024

Ah, I don't think it's possible to emit multiple env vars from GITHUB_ENV? At least I can't figure it out.

which is kinda wild

@russelltg
Copy link
Contributor Author

Ok, not quite ready I guess. Will look tomorrow

@NobodyXu
Copy link
Collaborator

Ah, I don't think it's possible to emit multiple env vars from GITHUB_ENV? At least I can't figure it out.

The doc says just put them in multiple lines, i.e. echo -e "A=...\nB=..." >> "$GITHUB_ENV"

.github/workflows/main.yml Outdated Show resolved Hide resolved
Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
@NobodyXu
Copy link
Collaborator

Updated CI and code, still doesn't work

@russelltg
Copy link
Contributor Author

Ok, phew, there was some more cases to handle here, but it seems to be working.

@russelltg
Copy link
Contributor Author

I'm not sure if you want to keep the changes you made, notably the CI formatting changes. I'm happy to simplify that diff if you want.

@NobodyXu
Copy link
Collaborator

I'm not sure if you want to keep the changes you made, notably the CI formatting changes. I'm happy to simplify that diff if you want.

That'd be ok for me, thanks for yhe fix!

Copy link
Collaborator

@NobodyXu NobodyXu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, in LGTM, however since I'm not very familiar with cc test-suite, I'd like another approval from another maintainer @thomcc

@NobodyXu NobodyXu requested a review from thomcc March 31, 2024 23:40
@russelltg
Copy link
Contributor Author

Opened llvm/llvm-project#87209 to address clang-cl not taking /Fo: but let's definitely stick with /Fo for maximum compatibility.

Copy link
Member

@thomcc thomcc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, the changes look good. That said, it's a big change, and I don't think we have great test coverage here, so it does make me worry a little. We should land it anyway though.

That said, maybe we should squash-land this so that we can revert more easily if it causes problems. WDYT @NobodyXu?

# Some packages were removed, and this is causing the g++multilib
# install to fail. Similar issue:
# https://github.com/scikit-learn/scikit-learn/issues/13928.
sudo add-apt-repository --remove ppa:ubuntu-toolchain-r/test
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, if it works...

is_arm: bool,
) {
if msvc && !clang && !gnu && !cuda && !(is_asm && is_arm) {
pub(crate) struct CmdAddOutputFileArgs {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this.

if target.contains("msvc") {
let (mut cmd, program, any_flags) = self.get_ar()?;
let (mut cmd, program, any_flags) = self.get_ar()?;
if target.contains("msvc") && !program.to_string_lossy().contains("llvm-") {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will probably need adjusting but for now is fine.

@@ -3939,7 +3959,7 @@ fn which(tool: &Path, path_entries: Option<OsString>) -> Option<PathBuf> {
}

// search for |prog| on 'programs' path in '|cc| -print-search-dirs' output
fn search_programs(cc: &mut Command, prog: &str, cargo_output: &CargoOutput) -> Option<PathBuf> {
fn search_programs(cc: &mut Command, prog: &Path, cargo_output: &CargoOutput) -> Option<PathBuf> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally the change to use &Path would be in a different pr. But I'm not about to hold this up for that, since it is a good change.

// https://gitlab.kitware.com/cmake/cmake/-/blob/69a2eeb9dff5b60f2f1e5b425002a0fd45b7cadb/Modules/CMakeDetermineCompilerId.cmake#L267-271
let accepts_cl_style_flags =
run(Command::new(path).arg("-?").stdout(Stdio::null()), path, &{
// the errors are not errors!
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙃

@NobodyXu
Copy link
Collaborator

NobodyXu commented Apr 7, 2024

That said, maybe we should squash-land this so that we can revert more easily if it causes problems.

Yeah, cc-rs defaults to squash merge so it should be pretty easy to revert.

@NobodyXu NobodyXu merged commit fd912ec into rust-lang:main Apr 7, 2024
23 checks passed
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 this pull request may close these issues.

3 participants