pkg-config error during Rust cross-compilation - rust

I am getting this error when I try to cross-compile some Rust; does anyone know what I should be doing?
This happens when I run cargo build --target aarch64, I get:
Compiling glib-sys v0.10.1
error: failed to run custom build command for `glib-sys v0.10.1`
...
pkg-config has not been configured to support cross-compilation.
Install a sysroot for the target platform and configure it via
PKG_CONFIG_SYSROOT_DIR and PKG_CONFIG_PATH, or install a
cross-compiling wrapper for pkg-config and set it via
PKG_CONFIG environment variable.
I might have asked this before a year or so ago, but anyway I cannot find any answer. I have tried adding various lines to my Cargo.toml but nothing seems to help.
The relevant part of Cargo.toml has:
[target.'cfg(target_os = "android")'.dependencies]
cairo = "0.0.4"
freetype = "0.7.0"
glib = "0.14.2"
openssl = "0.10.36"
openssl-sys = {version = "0.9.66", features = ["vendored"]}
There is probably a one-line answer to this; can anyone help me please.

You could try adding feature vendored for the openssl crate.
openssl = { version = "0.10.35", features = ["vendored"] }
reference

I'm also new to rust so there may be some mistakes in my answer.
So the warning suggests that the pkg-config is not correctly set, which suggests that this is not a rust issue, it's a pkg-config issue.
If you check the doc of pkg-config, you might see there's an environment variable called PKG_CONFIG_SYSROOT_DIR which "is useful for cross compilation". What you'll need to do is to run cargo with this environment set, e.g. PKG_CONFIG_SYSROOT_DIR=/usr/x86_64-w64-mingw32/ cargo build, where /usr/x86_64-w64-mingw32 contains all the file necessary for cross build for windows (as you can see from the name).
I'm not sure how to cross compile for aarch64, and I'm not sure how to add environment variable for cargo build, but I hope my experience above can give you some hint.

Related

How to cross compile Rust code from Intel Mac to M1 Mac by Zig?

These days I'm curious about the cross-compile in Rust.As I know, it's very simple to do the same thing in Go or Zig.But in Rust, it's very difficult.I write Rust code in my Intel MacBook Pro, want to cross compile to get the executable file which could be run in M1 MacBook Pro. I take some tries and get some errors in linker.
Here is what I have tried.
I install Rust tool and Zig following the official instruction.
$ rustc --version
rustc 1.65.0 (897e37553 2022-11-02)
$
$ zig version
0.10.0-dev.4560+828735ac0
And my rust project structure is just like this:
hello-world -----
|--- .cargo--
|-- config.toml
|--- src-----
|-- main.rs
Cargo.toml
zig
And there are some files look like:
// main.rs
fn main() {
println!("hello world")
}
// config.toml
[target.aarch64-apple-darwin]
rustflags = ["-C", "linker-flavor=ld", "-C", "link-self-contained=no", "-C", "link-arg=-L/usr/local/opt/libiconv/lib"]
linker = "./zig"
// Cargo.toml
[package]
name = "hello-world"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
#[profile.release]
#lto=true
// zig
#!/usr/bin/env zsh
zig cc -target aarch64-macos-none $#
And I install libiconv by brew:
$ brew install libiconv
it puts libiconv in directory /usr/local/opt/libiconv/lib
$ ls /usr/local/opt/libiconv/lib
libcharset.1.dylib libcharset.a libcharset.dylib libiconv.2.dylib libiconv.a libiconv.dylib
I install target aarch64-apple-darwin by rustup and could see:
$ rustup show
Default host: x86_64-apple-darwin
rustup home: /Users/<my name>/.rustup
installed targets for active toolchain
--------------------------------------
aarch64-apple-darwin
x86_64-apple-darwin
x86_64-unknown-linux-gnu
x86_64-unknown-linux-musl
active toolchain
----------------
stable-x86_64-apple-darwin (default)
rustc 1.65.0 (897e37553 2022-11-02)
then I start to build in hello-world directory:
$ CC=./zig cargo build --target aarch64-apple-darwin
...
...
note: error(link): mismatched cpu architecture: expected aarch64, found x86_64
error: MismatchedCpuArchitecture
I find some solutions from stackoverflow, it said I can use macOS sdk to cross-compile.
But I think there are more than one method to finish cross-compile, and really want to know how to solve it using zig.
By the way,I just know the basic steps of assembly, not in details, I don't have experience in linking.
Could anyone give me some suggestions ?
Any answer will be appreciated.
This might not be enough to solve your problem fully, but you need at the very least to pass the cross-compilation flags to Zig, and you also need to use the cc subcommand.
Note also that Zig uses macos instead of darwin.
So you need to set CC="./zig cc -target aarch64-macos", that said, I'm not sure if Rust supports spaces in the CC command now (at least a while ago it did not). If it doesn't you will need to wrap everything in a bash script (zcc.sh):
#!/bin/sh
ZIG_LOCAL_CACHE_DIR="$HOME/tmp" zig cc -target aarch64-macos $#
And then CC=./zcc.sh
Note also that the same will need to be done for zig c++ if you also depend on C++ code. The env variable to set in that case is CXX.
Here you can find somebody doing this to build wasmtime:
https://actually.fyi/posts/zig-makes-rust-cross-compilation-just-work/
Finally, you can probably save yourself all this trouble simply by using cargo-zigbuild:
https://github.com/rust-cross/cargo-zigbuild

How do I cross-compile openssL libraries on Mac OS by rust?

When I was compiling a Linux binary on MacOS, I encountered this problem:
It looks like the rust library "openssl-sys v0.9.61" is bound to the C library of MacOS. can't link to linux.
cargo build --release --target=x86_64-unknown-linux-musl
Compiling openssl-sys v0.9.61
error: failed to run custom build command for `openssl-sys v0.9.61`
Caused by:
process didn't exit successfully: `~/test/../bin/release/build/openssl-sys-96148dcd52905249/build-script-main` (exit status: 101)
--- stdout
cargo:rustc-cfg=const_fn
cargo:rerun-if-env-changed=X86_64_UNKNOWN_LINUX_MUSL_OPENSSL_LIB_DIR
X86_64_UNKNOWN_LINUX_MUSL_OPENSSL_LIB_DIR unset
cargo:rerun-if-env-changed=OPENSSL_LIB_DIR
OPENSSL_LIB_DIR unset
cargo:rerun-if-env-changed=X86_64_UNKNOWN_LINUX_MUSL_OPENSSL_INCLUDE_DIR
X86_64_UNKNOWN_LINUX_MUSL_OPENSSL_INCLUDE_DIR unset
cargo:rerun-if-env-changed=OPENSSL_INCLUDE_DIR
OPENSSL_INCLUDE_DIR unset
cargo:rerun-if-env-changed=X86_64_UNKNOWN_LINUX_MUSL_OPENSSL_DIR
X86_64_UNKNOWN_LINUX_MUSL_OPENSSL_DIR unset
cargo:rerun-if-env-changed=OPENSSL_DIR
OPENSSL_DIR unset
cargo:rerun-if-env-changed=OPENSSL_NO_PKG_CONFIG
cargo:rerun-if-env-changed=PKG_CONFIG_ALLOW_CROSS_x86_64-unknown-linux-musl
cargo:rerun-if-env-changed=PKG_CONFIG_ALLOW_CROSS_x86_64_unknown_linux_musl
cargo:rerun-if-env-changed=TARGET_PKG_CONFIG_ALLOW_CROSS
cargo:rerun-if-env-changed=PKG_CONFIG_ALLOW_CROSS
cargo:rerun-if-env-changed=PKG_CONFIG_x86_64-unknown-linux-musl
cargo:rerun-if-env-changed=PKG_CONFIG_x86_64_unknown_linux_musl
cargo:rerun-if-env-changed=TARGET_PKG_CONFIG
cargo:rerun-if-env-changed=PKG_CONFIG
cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR_x86_64-unknown-linux-musl
cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR_x86_64_unknown_linux_musl
cargo:rerun-if-env-changed=TARGET_PKG_CONFIG_SYSROOT_DIR
cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR
run pkg_config fail: "pkg-config has not been configured to support cross-compilation.\n\n Install a sysroot for the target platform and configure it via\n PKG_CONFIG_SYSROOT_DIR and PKG_CONFIG_PATH, or install a\n cross-compiling wrapper for pkg-config and set it via\n PKG_CONFIG environment variable."
--- 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.
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-apple-darwin
$TARGET = x86_64-unknown-linux-musl
openssl-sys = 0.9.61
', ~/.cargo/registry/src/openssl-sys-0.9.61/build/find_normal.rs:174:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
I found that some people also encountered this problem:
https://www.andrew-thorburn.com/cross-compiling-a-simple-rust-web-app/
It's true that you need to determine which rust dependencies use openssl during the cross compile link phase. In my project, reqwest and mysql dependencies apparently use them when cross-compiling. I had a similar issue when cross-compiling from my mac to x86_64 or aarch64 (arm) linux targets on my mac m1. The linker was failing when linking to openssl.. The trick is to add openssl crate to your project. There is good information here: https://docs.rs/openssl/latest/openssl/
here are the steps with other helpful links also:
1.rustup add target (this is AMD64 linux)
rustup target add x86_64-unknown-linux-musl
for (arm7 linux)
rustup target add aarch64-unknown-linux-musl
1(a) add the xplatform linker
brew install FiloSottile/musl-cross/musl-cross
for x86 and arm7 support:
brew install FiloSottile/musl-cross/musl-cross --with-aarch64 --with-x86_64
1(b) add openssl crate
https://docs.rs/openssl/latest/openssl/
may need to install openssl (see directions)
brew install openssl#1.1
[dependencies]
openssl = { version = "0.10", features = ["vendored"] }
2. modify ~/.cargo/config.toml
add link targets
[target.x86_64-unknown-linux-musl]
linker = "x86_64-linux-musl-gcc"
[target.aarch64-unknown-linux-musl]
linker = "aarch64-linux-musl-gcc"
[target.x86_64-unknown-linux-gnu] - notneeded
linker = "x86_64-unknown-linux-gnu-gcc"
3. export TARGET_CC
x86_64:
export TARGET_CC=x86_64-linux-musl-gcc
for arm7:
export TARGET_CC=aarch64-linux-musl-gcc
4. compiling openssl
include the openssl crate:
openssl = { version = "0.10", features = ["vendored"] }
5. build for target
cargo build --target x86_64-unknown-linux-musl
cargo build --target aarch64-unknown-linux-musl
The first step is to determine which dependency is using openssl, which you can do with crate tree:
crate tree --target=x86_64-unknown-linux-musl -i openssl-sys
In my case this identified the rusoto_core crate as the one depending on it. Some crates can be compiled with feature flags to use alternate TLS libraries, making them easier to use than OpenSSL.
For example, Rusoto enables rustls like this in the Cargo.toml:
rusoto_core = {version = "0.42.0", default_features = false, features=["rustls"]}
rusoto_s3 = {version = "0.42.0", default_features = false, features=["rustls"]}
rusoto_sqs = {version = "0.42.0", default_features = false, features=["rustls"]}
In the Rusoto case, there is documentation for cross-compiling for use with AWS Lambda: https://rusoto.org/lambdas.html
Alternately, you may be able to provide cross-compiled OpenSSL to the compiler, but from what I understand this is more difficult and poorly documented at this time.

Build fails with Error: Pear requires a 'dev' or 'nightly' version of rustc even after a successful rustup override set nightly

Windows 10
rustup 1.23.1 (3df2264a9 2020-11-30)
default rustc 1.50.0 (cb75ad5db 2021-02-10)
project rustc 1.52.0-nightly (4a8b6f708 2021-03-11)
rocket = "0.4.4"
I'm trying to build a rust project with rocket but I always get this error when compiling, even after successfully overwriting the project's toolchain:
D:\GitHub\Learning-Rust\poke_api> rustup override set nightly
info: using existing install for 'nightly-x86_64-pc-windows-msvc'
info: override toolchain for 'D:\GitHub\Learning-Rust\poke_api' set to 'nightly-x86_64-pc-windows-msvc'
nightly-x86_64-pc-windows-msvc unchanged - rustc 1.52.0-nightly (4a8b6f708 2021-03-11)
PS D:\GitHub\Learning-Rust\poke_api> cargo build
Compiling winapi v0.3.9
Compiling serde_derive v1.0.124
Compiling rocket v0.4.7
Compiling pear_codegen v0.1.4
Compiling rocket_codegen v0.4.7
Compiling proc-macro2 v1.0.24
Compiling pq-sys v0.4.6
Compiling aho-corasick v0.6.10
Compiling serde_json v1.0.64
error: failed to run custom build command for `pear_codegen v0.1.4`
Caused by:
process didn't exit successfully: `D:\GitHub\Learning-Rust\poke_api\target\debug\build\pear_codegen-e182711746033ac9\build-script-build` (exit code: 101)
--- stderr
Error: Pear requires a 'dev' or 'nightly' version of rustc.
Installed version: 1.48.0 (2020-11-16)
Minimum required: 1.31.0-nightly (2018-10-05)
thread 'main' panicked at 'Aborting compilation due to incompatible compiler.', C:\Users\gabre\.cargo\registry\src\github.com-1ecc6299db9ec823\pear_codegen-0.1.4\build.rs:24:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
warning: build failed, waiting for other jobs to finish...
error: build failed
I had a similar issue while using rocket. Same error message too, Error: Pear requires a 'dev' or 'nightly' version of rustc.
If you get to the get-started page on rocket framework website. It says, "Rocket makes abundant use of Rust's syntax extensions and other advanced, unstable features. Because of this, we'll need to use a nightly version of Rust."
My issue was I was not using a nightly version of rust. Running this on my terminal in my project directory did it for me.
rustup override set nightly
If you check the cargo version for that directory after,
cargo version
you will confirm it has switched to nightly version
Failed compilation even with nightly
It looks like you have some outdated dependencies (pear-codegen probably being the one that causes trouble), updating these may resolve the compilation issues.
General notes on how to override the toolchain
Using rustups override works fine, but it is bound to your local rustup configuration and not specified inside the project.
In order to achieve this, thereby making the project more portable and allowing others to always use the correct toolchain, I would recommend the toolchain file. It can look something like this (example taken from linked page) and will accurately specify the required toolchain only for the containing project.
# rust-toolchain.toml
[toolchain]
channel = "nightly-2020-07-10"
components = [ "rustfmt", "rustc-dev" ]
targets = [ "wasm32-unknown-unknown", "thumbv2-none-eabi" ]
profile = "minimal"
For your purposes a simple configuration like this will most likely be all you need, although adding the components you want to use would be beneficial.
[toolchain]
channel = "nightly"
My issue was with rust-analyser that wouldn't start because multiple rocket dependencies needed nightly or dev version of rustc.
These steps fixed my issue:
Switch to nightly for my rocket project by running rustup override set nightly inside the app folder.
Remove all target folders in my project. (I also had one in root)
Manually remove the faulty cached packages from cargo cache. cd ~/.cargo/registry/cache/github.com-xxxxxxxxxxxx && rm -r pear_codegen-0.1.5/

native library `glib` is being linked to by more than one package, and can only be linked to by one package [duplicate]

I'm facing this problem when I try to cargo build:
error: native library openssl is being linked to by more than one version of the same package, but it can only be linked once; try updating or pinning your dependencies to ensure that this package only shows up once
openssl-sys v0.6.7
openssl-sys v0.7.13
Cargo and Rust versions:
$ cargo --version
cargo 0.11.0-nightly (3ff108a 2016-05-24)
$ rustc --version
rustc 1.11.0-nightly (7746a334d 2016-05-28)
Files:
Cargo.toml
Cargo.lock
can't get why this doesn't compile and how to solve this problem.
Thank you!
The way that linking works, you can only have a single version of a native library linked, otherwise you end up with duplicate symbols. Cargo's links manifest key helps prevent you from accidentally linking to the same set of symbols twice.
To solve it, you need to read through your Cargo.lock (it's not a difficult file format to understand). Find the crates that have the offending library as a dependency and note which ones have conflicting versions.
Then you have to manually resolve your dependencies so that their dependencies use the same version of the native library.
In this case, the important aspects of the dependency chain are:
server (0.0.1) => cookie (0.2.4) => openssl (0.7.13)
=> hyper (0.6.16) => cookie (0.1.21) => openssl (0.6.7)
To fix it, modify your Cargo.toml to use the same version of cookie as hyper. Then you will implicitly get the same version of openssl.
To be honest, this is one of the roughest parts of Rust at the moment. At least this version of the "multiple different versions of the same crate" strangeness provides a straight-forward Cargo error.

How to build an executable that depends on curl for x86_64-unknown-linux-musl

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.

Resources