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

Generate bindings in build.rs to fix cross-compilation #15

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

ivan-aksamentov
Copy link

@ivan-aksamentov ivan-aksamentov commented Nov 11, 2024

Related to: rust-ndarray/ndarray-linalg#384

The pre-generated bindings are not working on the platforms that is not the same platform these bindings are generated at: /src/lapack.rs

error[E0308]: mismatched types
     --> /home/user/.cargo/registry/src/index.crates.io-6f17d22bba15001f/lax-0.16.0/src/cholesky.rs:30:26
      |
30    |                     $trf(uplo.as_ptr(), &n, AsPtr::as_mut_ptr(a), &n, &mut info);
      |                     ---- ^^^^^^^^^^^^^ expected `*const u8`, found `*const i8`
      |                     |
      |                     arguments to this function are incorrect
...
41    | impl_cholesky_!(c64, lapack_sys::zpotrf_);
      | ----------------------------------------- in this macro invocation
      |
      = note: expected raw pointer `*const u8`
                 found raw pointer `*const i8`

In particular, this is failing during pretty much any attempt at cross-compilation. And might cause problems during native compilation on different platforms as well. For example, when cross-compiling to aarch64-unknown-linux-gnu, the defaut C integer types are different from what's on x86_64: build.log.txt

The preferred approach nowadays is to generate bindings at build-time and then programmatically paste them into lib.rs. This way they come out with all the specifics required for the target platform.

Here I:

  • add build.rs script which uses bindgen library to generate $OUTPUT_DIR/bindings.rs (in the target/ directory)

  • add the functions starting with underscore to the allowlist (.allowlist_function("^.*_$"))

  • include!() the $OUTPUT_DIR/bindings.rsinto lib.rs

  • remove the generate.sh script (the build.rs is now doing it's job)

  • remove pre-generated bindings

The pre-generated bindings are not working on the platforms that is not the same platform these bindings are generated at:
[/src/lapack.rs](https://github.com/numrs/lapack-sys/blob/6f42e18ff245e0b53527a24211af1f640b4b637d/src/lapack.rs)

In particular, this is failing during pretty much any attempt at cross-compilation. And might cause problems diring native compilation on different platform as well. For example, when cross-compiling to aarch64-unknown-linux-gnu, the defaut C integer types are different from what's on x86_64:
[build.log.txt](https://github.com/user-attachments/files/17705378/build.log.txt)

The [preferred approach[(https://rust-lang.github.io/rust-bindgen/library-usage.html) nowadays is to generate bindings at build-time and then programmatically paste them into lib.rs. This way they come out with all the specifics required for the target platform.

Here I:
- add `build.rs` script which uses bindgen library to generate `$OUTPUT_DIR/bindings.rs` (in the `target/` directory)
- add the functions starting with underscore to the allowlist (`.allowlist_function("^.*_$")`)
-`include!()` the `$OUTPUT_DIR/bindings.rs`into `lib.rs`
- remove the `generate.sh` script (the `build.rs` is now doing it's job)
- remove pre-generated bindings
ivan-aksamentov added a commit to numrs/ndarray-linalg that referenced this pull request Nov 11, 2024
Depends on blas-lapack-rs/lapack-sys#15

This replaces hardcoded platform-specific `char*` types with the opaque types from [`core::ffi`](https://doc.rust-lang.org/stable/core/ffi/type.c_char.html). This is necessary when cross-compiling.

I believe when interacting with C and Fortran, both `lax` and `lapack-sys` should not assume integer and pointer types. Current setup is biased towards x86_64 platform and it could cause broken builds and undefined behavior on other platforms.

For example, cross compilation build could fail with:

error[E0308]: mismatched types
     --> /home/user/.cargo/registry/src/index.crates.io-6f17d22bba15001f/lax-0.16.0/src/cholesky.rs:30:26
      |
30    |                     $trf(uplo.as_ptr(), &n, AsPtr::as_mut_ptr(a), &n, &mut info);
      |                     ---- ^^^^^^^^^^^^^ expected `*const u8`, found `*const i8`
      |                     |
      |                     arguments to this function are incorrect
...
41    | impl_cholesky_!(c64, lapack_sys::zpotrf_);
      | ----------------------------------------- in this macro invocation
      |
      = note: expected raw pointer `*const u8`
                 found raw pointer `*const i8`
note: function defined here
     --> /workdir/.build/docker-aarch64-unknown-linux-gnu/aarch64-unknown-linux-gnu/release/build/lapack-sys-5fad11066d38a1a6/out/bindings.rs:12886:12

Full build log for aarch64-unknown-linux-gnu:
[build.log.txt](https://github.com/user-attachments/files/17706011/build.log.txt)

In this PR I change `i8` to `core::ffi::c_char` - this, for example, resolves to `i8` on x86  and to `u8` on ARM, but is also universal for any platform rust supports, removing bias towards x86.
@chadmed
Copy link

chadmed commented Dec 26, 2024

This does not just fail with cross compilation, it fails when compiling natively on non-x86 hosts too. I have had to postpone indefinitely a Rust signal processing project intended to be run on aarch64 because of this issue.

@IvanUkhov
Copy link
Member

Hello! Sorry for being slow. Now trying to catch up with what has happened. According to the discussion in the linked PR, it has been resolved. At least, as far as ndarray-linalg is concerned. @ivan-aksamentov, is this the case?

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

Successfully merging this pull request may close these issues.

3 participants