Open vlisivka opened 5 years ago
Ah indeed, the current build.rs script compiles and execute a small program, which makes it hard to cross-compile it.
The absurd solution would be to install something like qemu-static
with binfmt
support - it lets the system run foreign binaries like here transparently. But as we'll soon see, it's not really what you want either.
The real solution is a bit trickier. Ncurses is a dynamically-linked library, but not all versions are ABI compatible. There is a bunch of options that can be enabled when building ncurses for the system, and as a result, when building a binary that links to ncurses, it's not guaranteed that it'll run seamlessly when linking the ncurses lib from another system.
For example, on 64-bits architectures, there are 2 possible sizes for the chtype
type defined in ncurses.h
. If the binary is compiled with a different size than the ncurses lib, then bad things happen.
Another possible difference is the version of the mouse API; different OS may ship ncurses libs with different version of the mouse API, even when the version of ncurses itself is the same. This is here again done with macro definitions in ncurses.h
, and must match the version of the library being linked.
The first point doesn't apply on armv7 (it's 32-bits anyway), but the second point is still valid. It means that running a binary on a different system than the one it was built on is not safe in general. So when cross-compiling, we have no idea what options will be used on the target system.
The result is that we can't safely predict what will be compatible with the target system, but we could let the user override it - in which case we wouldn't need to try to guess it. This means when cross-compiling, you will need to somehow transmit some information about the target system: what is the size of a chtype
, and what is the version of the mouse API (the only 2 options currently auto-detected). A chtype
will probably be 32-bits on armv7, but the mouse API will depend on the OS installed (Ubuntu and Archlinux, for example, will ship ncurses libs with different options).
How to transmit this information? There are a few ways: we could use env variables, or rustc/cargo features... not sure which option is easiest to integrate in a larger build (when ncurses
is used as a dependency of a dependency...).
To detect type size at compile time this trick can be used:
int main()
{
int dummy;
int a_type;
switch (dummy) {
case 4:
case sizeof(a_type):
break;
}
return 0;
}
Program will not compile if int size is 4 bytes.
Same approach can be used to detect mouse API version: some programs will compile, some not. Just generate a sample program and then test is it compilable, like autoconf does.
But the problem remains: it only tests the host ncurses config, not the target.
If you will compile sample program using target compiler, then it will be tested with target ncurses config.
TARGET_CC = Some("/opt/scel/17.2/sysroots/x86_64-scelsdk-linux/usr/bin/arm-scel-linux-gnueabi/arm-scel-linux-gnueabi-gcc")
TARGET_CFLAGS = Some("--sysroot=/opt/scel/17.2/sysroots/armv7ahf-neon-scel-linux-gnueabi -mcpu=cortex-a9 -mfpu=neon -mfloat-abi=hard -marm")
I commented out check_chtype_size(&ncurses_lib);
and examples compiled fine and works fine on armv7 linux (Yocto), except for unicode, but Cursive examples are unable to display pseudo-graphics characters, maybe because ncurses thinks that unicode is not supported.
I'm having a similar problem when trying to create a package with TARGET x86_64-unknown-linux-musl on travis-ci:
error: failed to run custom build command for `ncurses v5.99.0`
Caused by:
process didn't exit successfully: `/home/travis/build/jansc/ncgopher/target/release/build/ncurses-91d5844f60f28ff9/build-script-build` (exit code: 101)
--- stdout
cargo:rerun-if-env-changed=PKG_CONFIG_PATH
cargo:rustc-link-lib=ncursesw
OPT_LEVEL = Some("3")
TARGET = Some("x86_64-unknown-linux-musl")
HOST = Some("x86_64-unknown-linux-gnu")
CC_x86_64-unknown-linux-musl = None
CC_x86_64_unknown_linux_musl = None
TARGET_CC = None
CC = None
CROSS_COMPILE = None
CFLAGS_x86_64-unknown-linux-musl = None
CFLAGS_x86_64_unknown_linux_musl = None
TARGET_CFLAGS = None
CFLAGS = None
CRATE_CC_NO_DEFAULTS = None
DEBUG = Some("false")
CARGO_CFG_TARGET_FEATURE = Some("crt-static,fxsr,sse,sse2")
--- stderr
/home/travis/build/jansc/ncgopher/target/x86_64-unknown-linux-musl/release/build/ncurses-b21f308415d32a8b/out/chtype_size.c:6:21: fatal error: ncurses.h: No such file or directory
compilation terminated.
thread 'main' panicked at 'assertion failed: command.status().expect("compilation failed").success()', /home/travis/.cargo/registry/src/github.com-1ecc6299db9ec823/ncurses-5.99.0/build.rs:105:5```
Any updates on this?
I have the same exact problem with --target=aarch64-unknown-linux-gnu
TARGET = Some("aarch64-unknown-linux-gnu")
HOST = Some("x86_64-unknown-linux-musl")
cargo:rerun-if-env-changed=CC_aarch64-unknown-linux-gnu
CC_aarch64-unknown-linux-gnu = None
cargo:rerun-if-env-changed=CC_aarch64_unknown_linux_gnu
CC_aarch64_unknown_linux_gnu = None
cargo:rerun-if-env-changed=TARGET_CC
TARGET_CC = Some("aarch64-oe-linux-gcc -mcpu=cortex-a53 -march=armv8-a+crc+crypto --sysroot=/opt/oecore-x86_64-kirkstone/sysroots/cortexa53-crypto-oe-linux")
cargo:rerun-if-env-changed=CFLAGS_aarch64-unknown-linux-gnu
CFLAGS_aarch64-unknown-linux-gnu = None
cargo:rerun-if-env-changed=CFLAGS_aarch64_unknown_linux_gnu
CFLAGS_aarch64_unknown_linux_gnu = None
cargo:rerun-if-env-changed=TARGET_CFLAGS
TARGET_CFLAGS = Some(" -O2 -pipe -g -feliminate-unused-debug-types ")
cargo:rerun-if-env-changed=CRATE_CC_NO_DEFAULTS
CRATE_CC_NO_DEFAULTS = None
DEBUG = Some("false")
CARGO_CFG_TARGET_FEATURE = Some("aes,crc,llvm14-builtins-abi,neon,pmuv3,sha2")
--- stderr
thread 'main' panicked at '/(....)/target/aarch64-unknown-linux-gnu/release/build/ncurses-e40bbafe95398f15/out/chtype_size failed: Os { code: 8, kind: Uncategorized, message: "Exec format error" }', /src/.cargo/registry/src/github.com-1ecc6299db9ec823/ncurses-5.101.0/build.rs:107:10
Cannot crosscompile ncurses-rs, because it compiles test program for armv7 and tries to execute it on x86_64. How to disable that?