How to Add Cross-Compile Target for Offline System without Rustup

Hello all!

I hope all is well with everyone. I have been struggling with attempting the following and would appreciate insight (please consider that I am rather new to Rust so patience is appreciated):

I have an offline system that I would like to cross-compile Rust code on. Whilst I could plop files to/from the offline system, the system must be offline.

Rust does offer an offline installer for such an offline system, but there is a catch: there is no rustup as part of that offline installer as Rustup is heavily reliant on internet access. This is proving to be an issue with cross-compilation as Rustup is typically used to acquire a desired target.

Moreover, this is what I would like insight on: how can I add a target for cross-compiling on an offline system that does not have Rustup, if it is even possible? If it is a matter of having rustup on a seperate online system, getting the target and then moving files to the offline system then I would appreciate guidance on what files to grab and how to point to them in the offline system?

Thanks in advance!

Can you install everything to an online system then transfer the .cargo folder to the offline system?

1 Like

Probably also the .rustup folder, since I think that's where the toolchains are installed

2 Likes

If you read the stable manifest, then you can find the url for pkg.rust.target.* for your host toolchain, and pkg.rust-std.target.* for the standard library for your cross-compilation targets. Extract those and run their install script into a common --prefix, and you'll have a sysroot just like what rustup installs.

3 Likes

(post deleted by author)

  1. Do the architecture matter for the online system (as an example, if the offline system is X86 Linux then would the online system also need to be X86 Linux)?

  2. Where could I expect the .cargo and .rustup folders to be for Linux?

  3. If there is a need or option to point to .cargo or .rustup at a different location, what would that process entail?

Thanks!

Excellent! I apologize, could you explain what you mean by "into a common --prefix"? I could give it a try once I get clarification on the --prefix aspect. Thanks!

The --prefix argument specifies the base directory things should be installed in. For example, if I set --prefix /tmp, then rustc would be installed to /tmp/bin/rustc and so on.

You can use $CARGO_HOME and $RUSTUP_HOME to override the home directories for cargo and rustup, but on Linux they're $HOME/.cargo/ and $HOME/.rustup/ by default.

You might also want to have a skim through the Rustup books' Installation chapter because that explains everything in more detail.

2 Likes

Apologies for the late reply, finally got time to get back around to this. For reference, the offline server is x86 and I would like to cross-compile to arm.

So I downloaded the desired targets from the stable manifest and ran their install scripts. It appears to uninstall whatever cargo I currently have and then installs the cargo I am installing.

Howbeit, when I attempt any commands with cargo I will now get "cannot execute binary file: Exec format error" message. I assume it is because the cargo I downloaded and installed is of another architecture and running it install scripts replaces the proper cargo.

Should I be choosing a different path for cargo when I run the install script and if so then what additonal steps am I missing? Apologies in advance if this has already been covered, I am new to cross-compiling so I am learning and getting confused as I go haha

You should only use pkg.rust (the entire toolchain) for your host x86, and pkg.rust-std (just the standard library) for arm.

Ah ok, that explains it, thanks!

I was able to install the std (armv7-unknown-linux-gnueabihf in this case) but when I attempt the following line:

cargo build --target=armv7-unknown-linux-gnueabihf

I get the following error:

error: linking with `cc` failed: exit status: 1

  |
= note: /usr/bin/ld: [path/to/example/project]/target/armv7-unknown-linux-gnueabihf/debug/deps/Hello_World-2317478ee666daf4.1cjpn3jrpstei8dn.rcgu.o: relocations in generic ELF (EM: 40)

          /usr/bin/ld: [path/to/example/project]/target/armv7-unknown-linux-gnueabihf/debug/deps/Hello_World-2317478ee666daf4.1cjpn3jrpstei8dn.rcgu.o: relocations in generic ELF (EM: 40)

          /usr/bin/ld: [path/to/example/project]/target/armv7-unknown-linux-gnueabihf/debug/deps/Hello_World-2317478ee666daf4.1cjpn3jrpstei8dn.rcgu.o: relocations in generic ELF (EM: 40)

          /usr/bin/ld: [path/to/example/project]/target/armv7-unknown-linux-gnueabihf/debug/deps/Hello_World-2317478ee666daf4.1cjpn3jrpstei8dn.rcgu.o: relocations in generic ELF (EM: 40)

          /usr/bin/ld: [path/to/example/project]/target/armv7-unknown-linux-gnueabihf/debug/deps/Hello_World-2317478ee666daf4.1cjpn3jrpstei8dn.rcgu.o: relocations in generic ELF (EM: 40)

          /usr/bin/ld: [path/to/example/project]/target/armv7-unknown-linux-gnueabihf/debug/deps/Hello_World-2317478ee666daf4.1cjpn3jrpstei8dn.rcgu.o: relocations in generic ELF (EM: 40)

          /usr/bin/ld: [path/to/example/project]/target/armv7-unknown-linux-gnueabihf/debug/deps/Hello_World-2317478ee666daf4.1cjpn3jrpstei8dn.rcgu.o: relocations in generic ELF (EM: 40)

          /usr/bin/ld: [path/to/example/project]/target/armv7-unknown-linux-gnueabihf/debug/deps/Hello_World-2317478ee666daf4.1cjpn3jrpstei8dn.rcgu.o: relocations in generic ELF (EM: 40)

          /usr/bin/ld: [path/to/example/project]/target/armv7-unknown-linux-gnueabihf/debug/deps/Hello_World-2317478ee666daf4.1cjpn3jrpstei8dn.rcgu.o: relocations in generic ELF (EM: 40)

          /usr/bin/ld: [path/to/example/project]/target/armv7-unknown-linux-gnueabihf/debug/deps/Hello_World-2317478ee666daf4.1cjpn3jrpstei8dn.rcgu.o: relocations in generic ELF (EM: 40)

          /usr/bin/ld: [path/to/example/project]/target/armv7-unknown-linux-gnueabihf/debug/deps/Hello_World-2317478ee666daf4.1cjpn3jrpstei8dn.rcgu.o: error adding symbols: file in wrong format

          collect2: error: ld returned 1 exit status

I attempted to troubleshoot this by creating a .cargo folder and in that creating a config.toml that has the following:

[target.armv7-unknown-linux-gnueabihf]
linker = "rust-lld"

but when I attempt the cargo build command from above then I get this new error message:

error: linking with `rust-lld` failed: exit status: 1

  |
= note: rust-lld: error: unable to find library -lgcc_s

          rust-lld: error: unable to find library -lutil

          rust-lld: error: unable to find library -lrt

          rust-lld: error: unable to find library -lpthread

          rust-lld: error: unable to find library -lm

          rust-lld: error: unable to find library -ldl

          rust-lld: error: unable to find library -lc

so I am currently stumped on what to try next. I suspect it has something to do with the target being arm as opposed to X86. Any further insight would be appreciated, thanks!

I FIGURED IT OUT!

So it appears that with the "relocations in generic ELF" errors, those were because the linker is x86 and I have to use arm, so I proceeded to add gcc-arm-linux-gnueabihf except for some silly reason, it has to be called "arm-linux-gnueabihf-gcc" in config.toml. Regardless, I can now build successfully!

Thanks everyone! I will mark the original answer from @cuviper as the solution as that was what started to lead me on the right path. I appreciate the help and I hope everyone has an awesome day!

3 Likes