I am having an issue oxidizing a C++ project that needs an
ancient 32-bit GCC version to build. The build machine is an
AMD64 multilib setup, the target is i686. The Rust component
builds fine as 64 bits and also as 32 bit using a more recent GCC
8.3 for linking. But as soon as I switch to the system compiler
-- which is i686 only -- cargo fails to pass the correct linker
flags down to dependencies which causes linking to fail.
For an MNWE, adding a dependency on memchr
to a skeleton
project created using cargo init foo
is sufficient to
reproduce the issue. This is an excerpt of what happens:
# cargo build --target i686-unknown-linux-gnu
Compiling memchr v2.3.0
Running `rustc --crate-name build_script_build /datastore/dev/rust/cargo/registry/memchr-2.3.0/build.rs --error-format=json --json=diagnostic-rendered-ansi --crate-type bin --emit=dep-info,link -C debuginfo=2 --cfg 'feature="default"' --cfg 'feature="std"' -C metadata=44fb1dc86bc067ac -C extra-filename=-44fb1dc86bc067ac --out-dir /mnt/host-src/i2n/tmp/test-link/target/debug/build/memchr-44fb1dc86bc067ac -L dependency=/mnt/host-src/i2n/tmp/test-link/target/debug/deps --cap-lints allow`
error: linking with `cc` failed: exit code: 1
|
= note: "cc" "-Wl,--as-needed" "-Wl,-z,noexecstack" "-m64" "-L" "/datastore/dev/rust/lib/rustlib/x86_64-unknown-linux-gnu/lib" [[[ … snip till eol … ]]]
= note: /usr/bin/ld: i386:x86-64 architecture of input file `/mnt/host-src/i2n/tmp/test-link/target/debug/build/memchr-44fb1dc86bc067ac/build_script_build-44fb1dc86bc067ac.build_script_build.4gqz6kdo-cgu.0.rcgu.o' is incompatible with i386 output
[[[ … and many more of these lines … ]]]
/usr/bin/ld: /mnt/host-src/i2n/tmp/test-link/target/debug/build/memchr-44fb1dc86bc067ac/build_script_build-44fb1dc86bc067ac.build_script_build.4gqz6kdo-cgu.0.rcgu.o: file class ELFCLASS64 incompatible with ELFCLASS32
/usr/bin/ld: final link failed: file in wrong format
collect2: ld returned 1 exit status
error: aborting due to previous error
error: could not compile `memchr`.
Caused by:
process didn't exit successfully: `rustc --crate-name build_script_build /datastore/dev/rust/cargo/registry/memchr-2.3.0/build.rs --error-format=json --json=diagnostic-rendered-ansi --crate-type bin --emit=dep-info,link -C debuginfo=2 --cfg 'feature="default"' --cfg 'feature="std"' -C metadata=44fb1dc86bc067ac -C extra-filename=-44fb1dc86bc067ac --out-dir /mnt/host-src/i2n/tmp/test-link/target/debug/build/memchr-44fb1dc86bc067ac -L dependency=/mnt/host-src/i2n/tmp/test-link/target/debug/deps --cap-lints allow` (exit code: 1)
From the -m64
flag it seems that cargo attempts to compile
the dependencies for the wrong target which must fail since there
is no x86_64 compatible C toolchain in the path. The toolchain
path /datastore/dev/rust/lib/rustlib/x86_64-unknown-linux-gnu
is wrong too as everything 32 bit is located at
/datastore/dev/rust/lib/rustlib/i686-unknown-linux-gnu/
.
Where does cargo get those arguments from and how do I change
them?
Btw. even brute forcing the flags doesn’t help:
declare -x LD_RUN_PATH=/opt/rust/lib:/lib:/usr/lib
declare -x LIBRARY_PATH=/opt/rust/lib:/lib/:/usr/lib
declare -x CARGO_BUILD_TARGET=i686-unknown-linux-gnu
declare -x CFLAGS=-m32
declare -x CPPFLAGS=-m32
declare -x CXXFLAGS=-m32
declare -x LDFLAGS="-m32 -L/opt/rust/lib -L/usr/lib -L/lib"
declare -x CC=/usr/bin/i686-redhat-linux-gcc
#strace -f -o /tmp/$(date +%F)_cargo.strace \
cargo build \
--target i686-unknown-linux-gnu
-> same result. Forcing a target in .cargo/config
does not
appear to make a difference either.
- Rust 1.42.0 compiler:
/opt/rust/bin/rustc
. - Binutils (v2.32) can handle both i686 and x86_64.
- System compiler:
/usr/bin/i686-redhat-linux-gcc
(libs in
/usr/lib
,/lib
).