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

[BUG] clang.cmd doesn't work well with -march=armv7-a #1856

Closed
Berrysoft opened this issue Mar 30, 2023 · 13 comments
Closed

[BUG] clang.cmd doesn't work well with -march=armv7-a #1856

Berrysoft opened this issue Mar 30, 2023 · 13 comments
Assignees
Labels

Comments

@Berrysoft
Copy link

Description

I've installed NDK 25.2.9519653 and want to work with rust. However, the content of *-*-*-clang.cmd causes issues. The content of such cmd script is:

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

set "_BIN_DIR=" && "%_BIN_DIR%clang.exe" --target=armv7a-linux-androideabi24 %*
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

The fourth line, if "%1" == "-cc1" goto :L, causes issues. Rust put a param "-march=armv7-a" with armv7a target, and cmd will throw error

=armv7-a"" was unexpected at this time.

That's because the line is interpreted as if ""-march=armv7-a"" == "-cc1" goto :L. When I comment out this line, it works well.

Affected versions

r25

Canary version

No response

Host OS

Windows

Host OS version

Windows 11

Affected ABIs

armeabi-v7a

Build system

ndk-build

Other build system

No response

minSdkVersion

24

Device API level

No response

@DanAlbert
Copy link
Member

@rprichard could you look at this for r26? I think you understand the cmd stuff better than the rest of us.

@rprichard
Copy link
Collaborator

Maybe EnableDelayedExpansion would help?

https://stackoverflow.com/a/26079381

@echo off
SetLocal EnableDelayedExpansion

:: Test empty string
set Lhs=
set Rhs=
echo Lhs: !Lhs! & echo Rhs: !Rhs!
if !Lhs! == !Rhs! (echo Equal) else (echo Not Equal)
echo.

:: Test symbols
set Lhs= \ / : * ? " ' < > | %% ^^ ` ~ @ # $ [ ] & ( ) + - _ =
set Rhs= \ / : * ? " ' < > | %% ^^ ` ~ @ # $ [ ] & ( ) + - _ =
echo Lhs: !Lhs! & echo Rhs: !Rhs!
if !Lhs! == !Rhs! (echo Equal) else (echo Not Equal)
echo.

I wonder if our wrappers can forward arguments containing special characters, like %, !, ^, "...

bbqsrc added a commit to bbqsrc/cargo-ndk that referenced this issue May 9, 2023
So there's a bug where NDK r25 doesn't handle command line args
properly to clang. Which is precisely what rustc calls, and breaks.

Highly paid teams at Google in their infinite wisdom implemented
argument handling with [reads notes] wizardry, wishful thinking,
and ... fucking batch scripts in 2023. `.cmd` files. For arg parsing! ON
WINDOWS! WHAT IN THE NAME OF ZOMBIE JESUS. Anyway.

So now cargo-ndk will use the actual Win32 function for parsing args
before handing them off to their cursed batch files. It took 2 hours to
workaround this issue. The bug in the NDK repo has been open for 3
months.

I should invoice Google at this point.

android/ndk#1856
bbqsrc added a commit to bbqsrc/cargo-ndk that referenced this issue May 9, 2023
So there's a bug where NDK r25 doesn't handle command line args
properly to clang. Which is precisely what rustc calls, and breaks.

Highly paid teams at Google in their infinite wisdom implemented
argument handling with [reads notes] wizardry, wishful thinking,
and ... fucking batch scripts in 2023. `.cmd` files. For arg parsing! ON
WINDOWS! WHAT IN THE NAME OF ZOMBIE JESUS. Anyway.

So now cargo-ndk will use the actual Win32 function for parsing args
before handing them off to their cursed batch files. It took 2 hours to
workaround this issue. The bug in the NDK repo has been open for 3
months.

I should invoice Google at this point.

android/ndk#1856
bbqsrc added a commit to bbqsrc/cargo-ndk that referenced this issue May 9, 2023
So there's a bug where NDK r25 doesn't handle command line args
properly to clang. Which is precisely what rustc calls, and breaks.

Highly paid teams at Google in their infinite wisdom implemented
argument handling with [reads notes] wizardry, wishful thinking,
and ... fucking batch scripts in 2023. `.cmd` files. For arg parsing! ON
WINDOWS! WHAT IN THE NAME OF ZOMBIE JESUS. Anyway.

So now cargo-ndk will use the actual Win32 function for parsing args
before handing them off to their cursed batch files. It took 2 hours to
workaround this issue. The bug in the NDK repo has been open for 3
months.

I should invoice Google at this point.

android/ndk#1856
bbqsrc added a commit to bbqsrc/cargo-ndk that referenced this issue May 9, 2023
So there's a bug where NDK r25 doesn't handle command line args
properly to clang. Which is precisely what rustc calls, and breaks.

Highly paid teams at Google in their infinite wisdom implemented
argument handling with [reads notes] wizardry, wishful thinking,
and ... fucking batch scripts in 2023. `.cmd` files. For arg parsing! ON
WINDOWS! WHAT IN THE NAME OF ZOMBIE JESUS. Anyway.

So now cargo-ndk will use the actual Win32 function for parsing args
before handing them off to their cursed batch files. It took 2 hours to
workaround this issue. The bug in the NDK repo has been open for 3
months.

I should invoice Google at this point.

android/ndk#1856
bbqsrc added a commit to bbqsrc/cargo-ndk that referenced this issue May 9, 2023
So there's a bug where NDK r25 doesn't handle command line args
properly to clang. Which is precisely what rustc calls, and breaks.

Highly paid teams at Google in their infinite wisdom implemented
argument handling with [reads notes] wizardry, wishful thinking,
and ... fucking batch scripts in 2023. `.cmd` files. For arg parsing! ON
WINDOWS! WHAT IN THE NAME OF ZOMBIE JESUS. Anyway.

So now cargo-ndk will use the actual Win32 function for parsing args
before handing them off to their cursed batch files. It took 2 hours to
workaround this issue. The bug in the NDK repo has been open for 3
months.

I should invoice Google at this point.

android/ndk#1856
@vbieleny
Copy link

I also encountered this problem. I've found that if %1 contains multiple " it can cause problems on this line if "%1" == "-cc1" goto :L.

What helped me was to replace this line

if "%1" == "-cc1" goto :L

with

if "%~1" == "-cc1" goto :L

The %~1 will remove the surrounding " from the argument and then it can be safely parsed. Although I am not sure about other special characters.

@rib
Copy link

rib commented May 16, 2023

I also just arrived at the same workaround as @vbieleny

@MarijnS95
Copy link

Isn't the idea to ditch the .cmd scripts and invoke clang directly, as per https://android-review.googlesource.com/c/platform/ndk/+/2134712?

@rib
Copy link

rib commented May 17, 2023

Isn't the idea to ditch the .cmd scripts and invoke clang directly, as per https://android-review.googlesource.com/c/platform/ndk/+/2134712?

At least for my current use case i'm using the toolchain via cargo/rustc and I'm not sure if there's any practical way yet to specify the target api level via cargo afaik? (adding the api level suffix wouldn't be a valid target name for rust) so at least for now it's still useful to have these wrappers.

@MarijnS95
Copy link

In ndk-build we provide that via C(XX)FLAGS and RUSTFLAGS. cargo-apk selects the API level via the manifest (and some other sources such as latest installed SDK?), cargo-ndk seems to pull it from cmdline.

@DanAlbert
Copy link
Member

Isn't the idea to ditch the .cmd scripts and invoke clang directly, as per https://android-review.googlesource.com/c/platform/ndk/+/2134712?

At least for my current use case i'm using the toolchain via cargo/rustc and I'm not sure if there's any practical way yet to specify the target api level via cargo afaik? (adding the api level suffix wouldn't be a valid target name for rust) so at least for now it's still useful to have these wrappers.

CC="clang -target aarch64-linux-android24". You only need the wrappers in the rare cases where you're using a system that's going to fumble when escaping that. They're rare but I've seen it happen in not-actually-autoconf-but-almost projects.

@MarijnS95
Copy link

Rust unfortunately seems to be rare in how we can provide the linker... by needing a different nontrivial environment var (RUSTFLAGS with all kinds of mutual exclusivity with user-settable config files) to add this extra arg (https://github.com/rust-mobile/ndk/pull/306/files#diff-33520aaf2e3ca2264c50b4159237131b9804b93d42e50b2276a281da69567b8bR41-R42).

I wonder if we could have added it to the LINKER env var directly and do away with all this hassle, like you suggest for CC.

@rib
Copy link

rib commented May 18, 2023

I wonder if we could have added it to the LINKER env var directly and do away with all this hassle, like you suggest for CC.

Just for reference, I gave this a try and cargo expects to be able to resolve the _LINKER to an absolute path and so it didn't work to try and add the target argument to the _LINKER environment variable. Also just conceptually; without something similar to CARGO_ENCODED_RUSTFLAGS it would be awkward to deal with paths that have spaces, in conjunction with arguments.

Unfortunately right now it looks like it's very difficult to pass --target to Clang when cross compiling Rust crates with Cargo without risking trampling the user's own rustflags.

As discussed here bbqsrc/cargo-ndk#104 (comment); tools such as cargo ndk, cargo apk and xbuild have no real hope of being able to determine the rustflags that have been configured by the user and so they can't add the required -Clink-arg= to add the --target to the rustflags without potentially trampling the user's own configuration of rustflags.

Unfortunately that means that the solution mentioned above for ndk-build isn't compatible with Rust projects that configure rustflags via Cargo. The current project I'm working with, for example, configures rustflags via .cargo/config.toml

The best solution for Rust projects would probably be to look at adding cargo ndk functionality to cargo itself, considering that cargo is the only thing that can really extend rustflags reliably.

Alternatively I think Cargo and the cc crate would need to offer some alternative ways of specifying a linker, with flags that can be used by tools like cargo ndk / ndk-build that won't trample the user's configured rustflags. E.g. Cargo could potentially support a CARGO_ENCODED_<target>_LINKER that could accept arguments for the linker too.

Without something like that then I think we need to continue using these .cmd wrappers with Rust and we also need to patch them to fix this bug because rustc seems to be passing arguments to the linker with quotes (E.g. we see this with -Wl,--version-scripts created by rustc)

One other approach I may investigate is to treat cargo-ndk as a RUSTC_WRAPPER on Windows so we can handle adding the -Clink-arg= at a point where all the rustflags should have been resolved by Cargo. This will likely make builds noticeably slower on Windows if it works since it will add a redundant CreateProcess for every rustc invocation.

@leleliu008
Copy link

leleliu008 commented May 18, 2023

to package manager developers and build system developers, maybe write your own wrapper in C API is a better choice.

here is a example I'm using https://github.com/leleliu008/ndk-pkg/blob/master/ndk-pkg-wrapper-cc.c

write your own wrapper, you can do many things. let's show you some examples:

  1. fix bugs. for exmaple, checking if --Wl,--soname,libxx.so is passed, if not, adding it. as discussed in [BUG]My compiled .so file depends on other shared object files, but has path prefixes included. #1865
  2. implement verbose mode, likes make V=1
  3. generate compile_commands.json
  4. do whatever you want

rib added a commit to rib/cargo-ndk that referenced this issue May 18, 2023
This is an alternative workaround for bbqsrc#92 that's similar to the solution
used in ndk-build except that the `-Clink-arg rustflag` is injected via
a RUSTC_WRAPPER instead of trying to modify CARGO_ENCODED_RUSTFLAGS.

It turned out to be practically impossible to be able to reliably
set CARGO_ENCODED_RUSTFLAGS without risking trampling over rustflags
that might be configured via Cargo (for example `target.<cfg>.rustflags`
are especially difficult to read outside of cargo itself)

This approach avoids hitting the command line length limitations of the
current workaround and avoids needing temporary hard links or copying
the cargo-ndk binary to the target/ directory.

Even though we've only seen quoting issues with the Windows `.cmd`
wrappers this change to avoid using the wrapper scripts is being
applied consistently for all platforms. E.g. considering the upstream
recommendation to avoid the wrapper scripts if possible:

https://android-review.googlesource.com/c/platform/ndk/+/2134712

Fixes: bbqsrc#92
Fixes: bbqsrc#104
Addresses: android/ndk#1856
rib added a commit to rib/cargo-ndk that referenced this issue May 18, 2023
This is an alternative workaround for bbqsrc#92 that's similar to the solution
used in ndk-build except that the `-Clink-arg rustflag` is injected via
a RUSTC_WRAPPER instead of trying to modify CARGO_ENCODED_RUSTFLAGS.

It turned out to be practically impossible to be able to reliably
set CARGO_ENCODED_RUSTFLAGS without risking trampling over rustflags
that might be configured via Cargo (for example `target.<cfg>.rustflags`
are especially difficult to read outside of cargo itself)

This approach avoids hitting the command line length limitations of the
current workaround and avoids needing temporary hard links or copying
the cargo-ndk binary to the target/ directory.

Even though we've only seen quoting issues with the Windows `.cmd`
wrappers this change to avoid using the wrapper scripts is being
applied consistently for all platforms. E.g. considering the upstream
recommendation to avoid the wrapper scripts if possible:

https://android-review.googlesource.com/c/platform/ndk/+/2134712

Fixes: bbqsrc#92
Fixes: bbqsrc#104
Addresses: android/ndk#1856
rib added a commit to rib/cargo-ndk that referenced this issue May 18, 2023
This is an alternative workaround for bbqsrc#92 that's similar to the solution
used in ndk-build except that the `--target=<triple><api-level>` argument
for Clang is injected by using cargo-ndk as a linker wrapper instead of
trying to modify CARGO_ENCODED_RUSTFLAGS.

It turned out to be practically impossible to be able to reliably
set CARGO_ENCODED_RUSTFLAGS without risking trampling over rustflags
that might be configured via Cargo (for example `target.<cfg>.rustflags`
are especially difficult to read outside of cargo itself)

This approach avoids hitting the command line length limitations of the
current workaround and avoids needing temporary hard links or copying
the cargo-ndk binary to the target/ directory.

Even though we've only seen quoting issues with the Windows `.cmd`
wrappers this change to avoid using the wrapper scripts is being
applied consistently for all platforms. E.g. considering the upstream
recommendation to avoid the wrapper scripts if possible:

https://android-review.googlesource.com/c/platform/ndk/+/2134712

Fixes: bbqsrc#92
Fixes: bbqsrc#104
Addresses: android/ndk#1856
bbqsrc pushed a commit to bbqsrc/cargo-ndk that referenced this issue May 22, 2023
This is an alternative workaround for #92 that's similar to the solution
used in ndk-build except that the `--target=<triple><api-level>` argument
for Clang is injected by using cargo-ndk as a linker wrapper instead of
trying to modify CARGO_ENCODED_RUSTFLAGS.

It turned out to be practically impossible to be able to reliably
set CARGO_ENCODED_RUSTFLAGS without risking trampling over rustflags
that might be configured via Cargo (for example `target.<cfg>.rustflags`
are especially difficult to read outside of cargo itself)

This approach avoids hitting the command line length limitations of the
current workaround and avoids needing temporary hard links or copying
the cargo-ndk binary to the target/ directory.

Even though we've only seen quoting issues with the Windows `.cmd`
wrappers this change to avoid using the wrapper scripts is being
applied consistently for all platforms. E.g. considering the upstream
recommendation to avoid the wrapper scripts if possible:

https://android-review.googlesource.com/c/platform/ndk/+/2134712

Fixes: #92
Fixes: #104
Addresses: android/ndk#1856
@DanAlbert
Copy link
Member

https://android-review.googlesource.com/c/platform/ndk/+/2925163 incorporates @vbieleny's suggested fix. Thanks! I need to wait for presubmit to finish with it before I can verify it, but I should be able to do that later today.

@DanAlbert
Copy link
Member

Confirmed, fix merged.

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

No branches or pull requests

7 participants