I am trying to cross compile Rust project using Cross
I am getting an error and I want to trace into the process by setting the environment variable RUST_BACKTRACE=1
But I don't know how to do so while using Cross.
Edit
I am using the command cross build --target aarch64-unknown-linux-gnu
and this my 'cross.toml' contents
[target.aarch64-unknown-linux-gnu]
openssl-sys = "0.9.76"
[build.env]
passthrough = [
"RUST_BACKTRACE",
"RUST_LOG",
"TRAVIS",
]
[target.aarch64-unknown-linux-gnu.env]
passthrough = [
"RUST_DEBUG",
]
I get the following error while trying to compile
thread 'main' panicked at '
Could not find directory of OpenSSL installation, and this `-sys` crate cannot
proceed without this knowledge. If OpenSSL is installed and this crate had
trouble finding it, you can set the `OPENSSL_DIR` environment variable for the
compilation process.
Make sure you also have the development packages of openssl installed.
For example, `libssl-dev` on Ubuntu or `openssl-devel` on Fedora.
If you're in a situation where you think the directory *should* be found
automatically, please open a bug at https://github.com/sfackler/rust-openssl
and include information about your system as well as this message.
$HOST = x86_64-unknown-linux-gnu
$TARGET = aarch64-unknown-linux-gnu
openssl-sys = 0.9.76
', /cargo/registry/src/github.com-1ecc6299db9ec823/openssl-sys-0.9.76/build/find_normal.rs:191:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Using passthrough in Cross.toml is just passing your local environment variables. So in your case, it is working as expected but the reason it is not working as you want it to, is because the RUST_BACKTRACE variable is not set.
In Linux/Unix (mac) you can check the value of a environment vairable by for example writing echo $RUST_BACKTRACE and to set it temporarily by writing RUST_BACKTRACE=1.
So in order to set the variable in cross, you can for example set RUST_BACKTRACE when running the command like this:
RUST_BACKTRACE=1 cross build --target aarch64-unknown-linux-gnu
Or you can set the value directly in your Cross.toml config like this:
[target.aarch64-unknown-linux-gnu]
openssl-sys = "0.9.76"
[build.env]
passthrough = [
"RUST_BACKTRACE=1",
"RUST_LOG",
"TRAVIS",
]
[target.aarch64-unknown-linux-gnu.env]
passthrough = [
"RUST_DEBUG",
]
Related
rust-gpu says:
Copy the rust-toolchain file to your project. (You must use the same version of Rust as rust-gpu.)
So I copied that file into my root getting rust-toolchain with contents:
# If you see this, run `rustup self update` to get rustup 1.23 or newer.
# NOTE: above comment is for older `rustup` (before TOML support was added),
# which will treat the first line as the toolchain name, and therefore show it
# to the user in the error, instead of "error: invalid channel name '[toolchain]'".
[toolchain]
channel = "nightly-2022-10-29"
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
# commit_hash = 9565dfeb4e6225177bbe78f18cd48a7982f34401
# Whenever changing the nightly channel, update the commit hash above, and make
# sure to change REQUIRED_TOOLCHAIN in crates/rustc_codegen_spirv/src/build.rs also.
Then I tried building by doing cargo-run, getting:
error: failed to run custom build command for `rustc_codegen_spirv v0.4.0-alpha.17 (https://github.com/EmbarkStudios/rust-gpu#fabcbd9c)`
Caused by:
process didn't exit successfully: `/home/makogan/rust_never_engine/target/debug/build/rustc_codegen_spirv-b4185236522e0515/build-script-build` (exit status: 1)
--- stdout
cargo:rerun-if-env-changed=RUSTGPU_SKIP_TOOLCHAIN_CHECK
--- stderr
error: wrong toolchain detected (found commit hash `e631891f7ad40eac3ef58ec3c2b57ecd81e40615`, expected `9565dfeb4e6225177bbe78f18cd48a7982f34401`).
Make sure your `rust_toolchain` file contains the following:
-------------
[toolchain]
channel = "nightly-2022-10-29"
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
I am confused, the toolchain file says the same thing as the error message, what did I do wrong?
You're running a different version of nightly than the crate requires.
To check the version of cargo try to run cargo --version from within the project directory. If it shows anything else than the version you specified in the rust-toolchain file then you can try and check out the list below for possible fixes.
Make sure that:
The cargo you're using is managed by rustup if it is cargo +stable --version should show a version number and not an error.
The rust-toolchain is in the same directory as Cargo.toml if it's not copy or move it there.
There is no override on the crates directory. You can list them with rustup override list if the crate where the error appears is listed you can unset it with rustup override unset from within the crate root.
In this specific case 3. was the culprit.
I'm specifying the -Cpanic=abort and -Zbuild-std=panic_abort when compiling. Why does the linker still say it needs libunwind to compile a program?
I'm experimenting with various ways to cross-compile Rust programs as small as possible (using the min-sized-rust repo as a reference). Right now I'm trying to compile the powerpc64-unknown-linux-musl target and I'm stuck on trying to remove a dependency on libunwind.
Here's my setup:
# 1. Install the Rust std source code
rustup component add rust-src --toolchain nightly
# 2. Setup a simple rust repo
cargo init testing
cd testing
# 3. Download a musl toolchain
wget https://musl.cc/powerpc64-linux-musl-cross.tgz
tar xzf powerpc64-linux-musl-cross.tgz
# 4. Try to compile the project (options on the command line instead of in files for
# maximum obviousness).
# RUSTFLAGS:
# -Cpanic=abort - abort immediately on panic
# -Clink-self-contained=no - don't use rustc's builtin libraries and objects (this
# is needed because powerpc64-unknown-linux-musl is a tier 3 target)
# -Clink-arg=--sysroot and -Clink-arg=/path/to/sysroot - pass the option to the linker
# to specify the sysroot of cross-compilation toolchain
# Cargo options:
# --config target.<triple>.linker - specify the linker to use
# -Zbuild-std=std,panic_abort - build the standard library from source. Specify
# panic_abort to make the abort on panic work
RUSTFLAGS="-Cpanic=abort -Clink-self-contained=no -Clink-arg=--sysroot -Clink-arg=powerpc64-linux-musl-cross/powerpc64-linux-musl/" \
cargo +nightly build \
--config "target.powerpc64-unknown-linux-musl.linker=\"powerpc64-linux-musl-cross/bin/powerpc64-linux-musl-gcc\"" \
--target powerpc64-unknown-linux-musl -Zbuild-std=panic_abort,std --release
This fails with the following error:
error: linking with `/home/user/Projects/testing/powerpc64-linux-musl-cross/bin/powerpc64-linux-musl-gcc` failed: exit status: 1
<output snipped>
= note: /home/user/Projects/testing/powerpc64-linux-musl-cross/bin/../lib/gcc/powerpc64-linux-musl/11.2.1/../../../../powerpc64-linux-musl/bin/ld: cannot find -lunwind
From min-size-rust repository:
"Even if panic = "abort" is specified in Cargo.toml, rustc will still include panic strings and formatting code in final binary by default. An unstable panic_immediate_abort feature has been merged into the nightly rustc compiler to address this.
To use this, repeat the instructions above to use build-std, but also pass the following -Z build-std-features=panic_immediate_abort option."
Still, you will get "cannot find -lunwind", because the linker still uses libunwind, even though it's truly unneeded,why! I do not know, maybe it's a bug.(Maybe someone with fair knowledge about linkers can easily solve that.I tried a naive solution which is "cargo .... --verbose", copy , remove "libunwind" then relinking which failed)
I verified that is indeed the missing piece by build from source(--target=x86_64-unknown-linux-musl) AND using an old simple trick which is "touch libunwind.a" in the "self-contained" directory inside a target lib folder.(because the linker would still use it even though it's now truly unneeded, then I gave him a dummy libunwind.a)
In your case, I really tried to build it to your target until I got a headache, but couldn't and stopped, but here is possible solutions:
Giving that you're using "-Z build-std-features=panic_immediate_abort"
-If you can custom the linking process, then solve it (until what seems to be a bug is solved)
-Create a dummy(empty) libunwind.a where it should be in your toolchain
I want to set rustc-env=VAR=VALUE so that I could access it using env::var("VAR") in my code. However, I'm not clear on where to specify it. Can I set the environment variable VAR in the Makefile?
TL;DR
build.rs
fn main() {
println!("cargo:rustc-env=VAR=VALUE");
}
src/main.rs
fn main() {
let var = env!("VAR");
}
The documentation that you linked is for a Cargo build script:
The Rust file designated by the build command (relative to the package root) will be compiled and invoked before anything else is compiled in the package, allowing your Rust code to depend on the built or generated artifacts. By default Cargo looks up for "build.rs" file in a package root (even if you do not specify a value for build). Use build = "custom_build_name.rs" to specify a custom build name or build = false to disable automatic detection of the build script.
On the same page, there's a section that describes outputs of build.rs
All the lines printed to stdout by a build script are written to a file [...] Any line that starts with cargo: is interpreted directly by Cargo. This line must be of the form cargo:key=value, like the examples below:
cargo:rustc-env=FOO=bar
It then details rustc-env:
rustc-env=VAR=VALUE indicates that the specified environment variable will be added to the environment which the compiler is run within. The value can be then retrieved by the env! macro in the compiled crate. This is useful for embedding additional metadata in crate's code, such as the hash of Git HEAD or the unique identifier of a continuous integration server.
env! is a macro.
access it using env::var("VAR")
No. env::var is for reading environment variables set when the program runs, not when the program is compiled.
See also:
Is it possible to initialize a variable from an environment variable at compilation time when using no_std?
I am on an amd64 Debian machine, and am trying to build a x86_64-unknown-linux-musl executable. I have this in my Cargo.toml:
[dependencies]
curl = "0.4"
When I run cargo build --target=x86_64-unknown-linux-musl I get
this:
error: failed to run custom build command for `libz-sys v1.0.10`
process didn't exit successfully: `/tmp/foo/target/debug/build/libz-sys-c20da5f29c41e515/build-script-build` (exit code: 101)
--- stdout
OPT_LEVEL = Some("0")
PROFILE = Some("debug")
TARGET = Some("x86_64-unknown-linux-musl")
debug=true opt-level=0
HOST = Some("x86_64-unknown-linux-gnu")
TARGET = Some("x86_64-unknown-linux-musl")
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
HOST = Some("x86_64-unknown-linux-gnu")
CROSS_COMPILE = None
TARGET = Some("x86_64-unknown-linux-musl")
HOST = Some("x86_64-unknown-linux-gnu")
CFLAGS_x86_64-unknown-linux-musl = None
CFLAGS_x86_64_unknown_linux_musl = None
TARGET_CFLAGS = None
CFLAGS = None
running: "./configure" "--prefix=/tmp/foo/target/x86_64-unknown-linux-musl/debug/build/libz-sys-e109627694e9981e/out"
Compiler error reporting is too harsh for ./configure (perhaps remove -Werror).
** ./configure aborting.
--- stderr
thread 'main' panicked at 'failed to run successfully: exit code: 1', /home/tshepang/.cargo/registry/src/github.com-1ecc6299db9ec823/libz-sys-1.0.10/build.rs:189
When I re-run it:
error: failed to run custom build command for `openssl-sys v0.9.6`
process didn't exit successfully: `/tmp/foo/target/debug/build/openssl-sys-ac9c042b062dad1d/build-script-build` (exit code: 101)
--- stderr
thread 'main' panicked at '
Could not find directory of OpenSSL installation, and this `-sys` crate cannot
proceed without this knowledge. If OpenSSL is installed and this crate had
trouble finding it, you can set the `OPENSSL_DIR` environment variable for the
compilation process.
If you're in a situation where you think the directory *should* be found
automatically, please open a bug at https://github.com/sfackler/rust-openssl
and include information about your system as well as this message.
$HOST = x86_64-unknown-linux-gnu
$TARGET = x86_64-unknown-linux-musl
openssl-sys = 0.9.6
All works well when I build natively, i.e. cargo build --target=x86_64-unknown-linux-gnu.
Searching around, I learned about an environment variable, PKG_CONFIG_ALLOW_CROSS:
PKG_CONFIG_ALLOW_CROSS=true cargo build --target=x86_64-unknown-linux-musl
In doing that, I also found that I was missing the Debian package
named libcurl4-openssl-dev.
Running ldd target/target/x86_64-unknown-linux-musl/debug/foo
indicated the executable is dynamically linked, then searching
further, I learned about another environment variable,
PKG_CONFIG_ALL_STATIC:
PKG_CONFIG_ALL_STATIC=true PKG_CONFIG_ALLOW_CROSS=true cargo build --target=x86_64-unknown-linux-musl
That revealed a whole bunch of missing deps, all of which (luckily)
had Debian dependencies. But installing all of them did not help, as,
in the end, I was still sitting with an executable that wasn't
statically linked .
I gave in and ended up using cross:
cargo install cross
cross build --target=x86_64-unknown-linux-musl
This was just too easy, and you will find the executable in target/x86_64-unknown-linux-musl/debug.
The curl crate depends (directly or indirectly) on the two crates libz-sys and openssl-sys.
A crate whose name ends in "-sys" is generally a set of FFI (foreign function interface) bindings to a native C library.
Building such a "-sys" crate requires linking to the native library. If your target is x86_64-unknown-linux-musl, then you must link to a native library built against musl, not glic. However, most of the packages you will find in the repositories of your distribution provide libraries built against glibc.
The solution is to build yourself the libraries you need, linking to musl instead of glibc.
I don't have access to a Debian installation, but on Ubuntu 16.04 this looks like this for OpenSSL:
# this package provides the "musl-gcc" wrapper
apt-get install musl-tools
# you will also need these, if they are not installed yet
apt-get install pkg-config xutils-dev build-essential
# Download and build OpenSSL against musl
VERS=1.0.2j
export CC=musl-gcc
export MUSL_PREFIX=/usr/local/musl
export C_INCLUDE_PATH="$MUSL_PREFIX/include/"
curl -O https://www.openssl.org/source/openssl-$VERS.tar.gz
tar xvzf openssl-$VERS.tar.gz
cd openssl-$VERS
./config --prefix "$MUSL_PREFIX"
make depend
make
sudo make install
export OPENSSL_DIR=/usr/local/musl/
export OPENSSL_STATIC=1
Once you have one the same for libz (I haven't tried to built it), you should then be able to build your crate:
cargo build --target=x86_64-unknown-linux-musl
and the resulting binary will be in target/x86_64-unknown-linux-musl/debug/<binary_name>
The cross tool does basically this, but inside a Docker container as to keep your host machine clean.
The binary produced by this build should be statically linked, and not depend even on glibc. This also means that it will be bigger* and that you will need to take care yourself of upgrading any dependency (especially OpenSSL) if a security issue is found in one of them.
*You may want to use strip on the released binary.
With Cargo, I can set a project's development settings to use parallel code generation:
[profile.dev]
codegen-units = 8
According to the documentation, it should be possible to put this into ~/.cargo/config to apply this setting to all projects. This doesn't work for me: it seems that the .cargo/config file isn't used at all. Is there any way to apply such configuration to every project I compile?
You can set rustflags for all builds or per target in your .cargo/config file.
[build] # or [target.$triple]
rustflags = ["-Ccodegen-units=4"]
To be clear, this will set the codegen-units for all your projects (covered by this .cargo/config) regardless of profile.
To make sure it's actually set, you can also set verbose output in the same file. This will show each rustc command with flags that cargo invokes.
[term]
verbose = true
A workaround is to create a script to be called instead of cargo
#!/bin/bash
if [[ $* != *--release* ]]; then
# dev build
export RUSTFLAGS="-C codegen-units=8"
fi
cargo "$#"
If you use the full path to cargo on the script, you can create a alias
alias cargo=/path/to/script
and just call cargo.