rust-lang / cc-rs

Rust library for build scripts to compile C/C++ code into a Rust library
https://docs.rs/cc
Apache License 2.0
1.86k stars 448 forks source link

flag_if_supported("-lunwind") seems to always fail with ndk25 clang #731

Open plusls opened 2 years ago

plusls commented 2 years ago

Like #459

I compile A helloworld in windows with nightly-x86_64-pc-windows-msvc target aarch64-linux-android, with

cargo +nightly build -vv --release -Z build-std=std,panic_abort -Z build-std-features=panic_immediate_abort --target aarch64-linux-android

it tell me that

  = note: ld: error: unable to find library -lgcc
          clang: error: linker command failed with exit code 1 (use -v to see invocation)

But I found a fix in https://github.com/rust-lang/rust/pull/85806, it check if compiler support lunwind, it will use system-llvm-libunwind.

https://github.com/rust-lang/rust/blob/1536ab1b383f21b38f8d49230a2aecc51daffa3d/library/unwind/build.rs#L19

And I change it to

        let has_unwind = true;

It will compile and link success, so I think it's a bug that cause flag_if_supported("-lunwind") seems to always fail

And my cargo config:

[target.aarch64-linux-android]
linker = "C:\\Users\\plusls\\AppData\\Local\\Android\\Sdk\\ndk\\25.1.8937393\\toolchains\\llvm\\prebuilt\\windows-x86_64\\bin\\aarch64-linux-android33-clang.cmd"
ar = "C:\\Users\\plusls\\AppData\\Local\\Android\\Sdk\\ndk\\25.1.8937393\\toolchains\\llvm\\prebuilt\\windows-x86_64\\bin\\llvm-ar.exe"

[target.x86_64-unknown-linux-musl]
linker = "rust-lld"
dot-asm commented 2 years ago

It's not obvious that this is the right forum to discuss this problem. Because it appears to be a pure Rust problem. At least cc-rs is primarily about compiling C/C++ modules and no C/C++ modules are compiled here. However, cc-rs appears to be invoked exclusively to determine which library to link with to reach out for unwind interface.

[target.aarch64-linux-android]
linker = ...

In the context it's important to recognize that this linker line has no effect on cc-rs. At least not currently. The question is which command is executed when the referred test is performed, and the trouble is that it's not given that it's the one designated as linker. In case it's not specified, Rust should have its own algorithm to choose the linker, or at least attempt to. And it would have been better off using that to perform the test. As opposed to relying on cc-rs. If anything, it would be more appropriate to have cc-rs interrogate Rust when choosing the compiler, not vice versa, as discussed in #693.

dot-asm commented 2 years ago

Just in case, #728 is likely to be related. Maybe even making the current arrangement work?

dot-asm commented 2 years ago

If anything, it would be more appropriate to have cc-rs interrogate Rust when choosing the compiler, not vice versa, as discussed in #693.

Just in case, for completeness and ultimate clarity. cc-rs, or rather the build script, has access to the information about linker configured through .cargo/config.toml, but not one chosen by Rust automatically. "Interrogate" refers to the latter case.

plusls commented 2 years ago

I add some debug code, and I found that the command line is

./clang.exe --target=aarch64-linux-android33 -lunwind -O0 -DANDROID -ffunction-sections -fdata-sections -fPIC --t
arget=aarch64-linux-android -Wall -Wextra -lunwind a.c

clang output is:

ld: error: cannot open crtbegin_dynamic.o: No such file or directory
ld: error: cannot open crtend_android.o: No such file or directory
clang: error: linker command failed with exit code 1 (use -v to see invocation)

and the command in aarch64-linux-android33-clang.cmd is:

@echo off
setlocal
call :find_bin
if "%1" == "-cc1" goto :L

set "_BIN_DIR=" && "%_BIN_DIR%clang.exe" --target=aarch64-linux-android33 %*
if ERRORLEVEL 1 exit /b 1
goto :done

:L
rem Target is already an argument.
set "_BIN_DIR=" && "%_BIN_DIR%clang.exe" %*
if ERRORLEVEL 1 exit /b 1
goto :done

:find_bin
rem Accommodate a quoted arg0, e.g.: "clang"
rem https://github.com/android-ndk/ndk/issues/616
set _BIN_DIR=%~dp0
exit /b

:done

And I found that if I remove --t arget=aarch64-linux-android, it will compile success, I have no idea to configure it.

plusls commented 2 years ago

And I found that in cmake-rs, it set no_default_flags when use ndk

https://github.com/rust-lang/cmake-rs/blob/00e6b220342a8b0ec4548071928ade38fd5f691b/src/lib.rs#L464

So I think that unwind in rust also should add no_default_flags to fix it.

https://github.com/rust-lang/rust/blob/194140bef501ad3acb00d57c20fb80ee34aa1d3b/library/unwind/build.rs#L14

I know I shouldn't to talk this in here, but I found that although I set is_flag_supported, cc-rust will no respect it and create a new ctx.

https://github.com/rust-lang/cc-rs/blob/53fb72c87e5769a299f1886ead831901b9c775d6/src/lib.rs#L470

I think maybe it should add:

cfg.no_default_flags(self.no_default_flags);