I'm trying to make a package that compiles LibreSSL, to be used in a later version or fork of openssl-sys, in place of openssl-src.
The LibreSSL build setup (unlike OpenSSL's bespoke system) uses the standard autotools ./configure; make install
. Everything works great for my package when the build/host and target systems coincide. I'm just doing this:
use autotools::Config;
let mut cfg = Config::new(&inner_dir);
cfg.disable_shared();
cfg.out_dir(&install_dir);
cfg.cflag("-v");
let dst = cfg.build();
However, things don't work right when I try to test for systems where host and target come apart. I'm using a ci infrastructure that uses github's Ubuntu machines and Docker instances to test on different architectures. For example, one of the non-working tests is for aarch64-unknown-linux-gnu
.
Here is the .github/workflows/main.yml file:
name: CI
on: [push, pull_request]
jobs:
test:
name: Test
runs-on: ${{ matrix.os }}
strategy:
matrix:
thing:
- stable
- beta
- nightly
- macos-x86_64
include:
- thing: stable
target: x86_64-unknown-linux-gnu
rust: stable
os: ubuntu-18.04
- thing: beta
target: x86_64-unknown-linux-gnu
rust: beta
os: ubuntu-18.04
- thing: nightly
target: x86_64-unknown-linux-gnu
rust: nightly
os: ubuntu-18.04
- thing: macos-x86_64
target: x86_64-apple-darwin
rust: stable
os: macos-10.15
- thing: aarch64-linux
target: aarch64-unknown-linux-gnu
rust: stable
os: ubuntu-18.04
steps:
- uses: actions/checkout@v1
with:
submodules: true
- name: Install Rust (rustup)
run: rustup update ${{ matrix.rust }} --no-self-update && rustup default ${{ matrix.rust }}
shell: bash
- run: rustup target add ${{ matrix.target }}
- name: Set crt-static
if: matrix.crt_static == 'yes'
run: echo ::set-env name=RUSTFLAGS::-Ctarget-feature=+crt-static
shell: bash
- run: |
set -e
cargo generate-lockfile
./ci/run-docker.sh ${{ matrix.target }}
if: "!startsWith(matrix.os, 'windows')"
name: Run tests (not Windows)
- run: |
cargo test --manifest-path testcrate/Cargo.toml --target ${{ matrix.target }}
cargo test --manifest-path testcrate/Cargo.toml --target ${{ matrix.target }} --release
cargo run --release --target ${{ matrix.target }} --manifest-path testcrate/Cargo.toml --features package
if: startsWith(matrix.os, 'windows')
name: Run tests (Windows)
shell: cmd
rustfmt:
name: Rustfmt
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v1
- name: Install Rust
run: rustup update stable && rustup default stable && rustup component add rustfmt
- run: cargo fmt -- --check
and here is ci/run-docker.sh:
#!/bin/sh
target=$1
if [ ! -d ci/docker/$1 ]; then
exec ci/run.sh $1
fi
set -ex
docker build \
--rm \
--tag libressl-src-ci \
ci/docker/$1
docker run \
--rm \
--volume `rustc --print sysroot`:/rust:ro \
--volume `pwd`:/usr/code:ro \
--volume `pwd`/target:/usr/code/target \
--volume $HOME/.cargo:/cargo \
--env CARGO_HOME=/cargo \
--workdir /usr/code \
libressl-src-ci \
bash -c "PATH=\$PATH:/rust/bin ci/run.sh $target"
and here ci/run.sh:
target=$1
set -ex
cargo test --manifest-path testcrate/Cargo.toml --target $1 -vv
cargo test --manifest-path testcrate/Cargo.toml --target $1 -vv --release
and here ci/docker/aarch64-unknown-linux-gnu/Dockerfile:
FROM ubuntu:18.04
RUN apt-get update -y && apt-get install -y --no-install-recommends \
ca-certificates \
make \
file \
gcc \
libc6-dev \
gcc-aarch64-linux-gnu \
libc6-dev-arm64-cross
ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER=echo \
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc
When running the job for that target, what happens is that my package invokes "/usr/code/target/aarch64-unknown-linux-gnu/debug/build/testcrate-185e7fb7707c88c7/out/libressl-build/build/src/configure" "--host=x86_64-unknown-lin ux-gnu" "--prefix=/usr/code/target/aarch64-unknown-linux-gnu/debug/build/testcrate-185e7fb7707c88c7/out/libressl-build" "--disable-shared" "--enable-static"
And then invokes make install
. But the libraries that get built don't seem to be the ones that the linker, aarch64-linux-gnu-gcc
, expects. I get errors like this:
= note: /usr/lib/gcc-cross/aarch64-linux-gnu/7/../../../../aarch64-linux-gnu/bin/ld: skipping incompatible /usr/code/target/aarch64-unknown-linux-gnu/debug/build/testcrate-185e7fb7707c88c7/out/libressl-build/lib/libtls.a when searching for -ltls
/usr/lib/gcc-cross/aarch64-linux-gnu/7/../../../../aarch64-linux-gnu/bin/ld: cannot find -ltls
Digging into this further, it seems that the ./configure; make install
process is never using an aarch64-targetting tool until it gets to the linker, as specified in the env var CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc
.
Why is that? At first I thought this may be related to #15, but when I made a fork of this repository that added that --target=$TARGET
to the invocation of ./configure
, it didn't resolve anything.
Looking into this repository's source code, it's hard to see what mechanism should be used to specify the compiler in a context like this. The pub fn build
begins with:
let mut c_cfg = cc::Build::new();
c_cfg.cargo_metadata(false)
.opt_level(0)
.debug(false)
.target(&target)
.warnings(false)
.host(&host);
let c_compiler = c_cfg.get_compiler();
And that cc::Tool
instance correctly selects my aarch64-targetting compiler, but then that information never gets passed to the invocation of ./configure
and/or make
.
How am I supposed to specify using this library that the make
should not be using the native compiler? Should I be passing env variables like CC to my autotools::Config
instance? Or should I be setting other CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_*
variables in the same way that the linker was specified?
(I borrowed the GitHub ci infrastructure from another library and am adapting it to my own needs; I guess these questions demonstrate that I don't understand it 100%.)