Skip to content

Instantly share code, notes, and snippets.

@pete3n
Last active January 6, 2024 23:00
Show Gist options
  • Save pete3n/1ba68b490c2b58f08591dc640daab3a4 to your computer and use it in GitHub Desktop.
Save pete3n/1ba68b490c2b58f08591dc640daab3a4 to your computer and use it in GitHub Desktop.
Cross-compile source code with Nix Shells

Cross Compiling With Nix Shells

Nix shells offer an easy way to cross-compile source code without having to install a bunch of tool chains on your system. The shell will pull everything it needs to setup the build environment, and will keep it cached until you run garbage colleciotn.

A Simple Example With GCC

gcc_armv7-a.nix is a simple example configured to create a build environment for gcc with an ARMv7-a target. I can cross-compile my rev_shell.c code with:

nix-shell --run '$CC rev_shell.c -o rev_shell_armv7a'  gcc_armv7-a.nix

Checking the output binary with:

readelf -a rev_shell_armv7a

I see:

Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           ARM
  ...
  Tag_CPU_name: "7-A"
  Tag_CPU_arch: v7

Looks good. That was easy. What about something trickier. Let's grab a custom toolchain and build for MIPS and MIPSEL soft-float.

MIPS Soft Float

nix-shell --run '$CC rev_shell.c -o rev_shell_mips_muslsf'  musl-mips-sf.nix

Checking the output

  Class:                             ELF32
  Data:                              2's complement, big endian
  Machine:                           MIPS R3000
  ...
  File Attributes
  Tag_GNU_MIPS_ABI_FP: Soft float

Great, this is the exact same for mipsel, just replacing mips with mipsel.

with import <nixpkgs> {
crossSystem = {
config = "armv7a-unknown-linux-gnueabi";
bigEndian = false;
arch = "armv7-a";
libc = "glibc";
};
};
mkShell {
buildInputs = [ ]; # Add additional dependencies here
}
{ pkgs ? import <nixpkgs> {} }:
let
toolchainUrl = "https://musl.cc/mips-linux-muslsf-cross.tgz";
toolchain = pkgs.runCommand "mips-linux-muslsf-cross" {} ''
mkdir -p $out
cd $out
tar -xzf ${pkgs.fetchurl {
url = toolchainUrl;
sha256 = "sha256-VyR2xFhzD0HIbk24zNNB7R5mWFiXshTygvLwWkRfR9M=";
}}
'';
in pkgs.mkShell {
buildInputs = [ pkgs.stdenv ];
shellHook = ''
export PATH="${toolchain}/mips-linux-muslsf-cross/bin:$PATH"
export CC="${toolchain}/mips-linux-muslsf-cross/bin/mips-linux-muslsf-gcc"
export CXX="${toolchain}/mips-linux-muslsf-cross/bin/mips-linux-muslsf-g++"
export LD="${toolchain}/mips-linux-muslsf-cross/bin/mips-linux-muslfsf-ld"
'';
}
{ pkgs ? import <nixpkgs> {} }:
let
toolchainUrl = "https://musl.cc/mipsel-linux-muslsf-cross.tgz";
toolchain = pkgs.runCommand "mipsel-linux-muslsf-cross" {} ''
mkdir -p $out
cd $out
tar -xzf ${pkgs.fetchurl {
url = toolchainUrl;
sha256 = "sha256-phw7v5+7C+gP4qvbTqi29a/fZktbQQSjeEoyYnCQUhY=";
}}
'';
in pkgs.mkShell {
buildInputs = [ pkgs.stdenv ];
shellHook = ''
export PATH="${toolchain}/mipsel-linux-muslsf-cross/bin:$PATH"
export CC="${toolchain}/mipsel-linux-muslsf-cross/bin/mipsel-linux-muslsf-gcc"
export CXX="${toolchain}/mipsel-linux-muslsf-cross/bin/mipsel-linux-muslsf-g++"
export LD="${toolchain}/mipsel-linux-muslsf-cross/bin/mipsel-linux-muslfsf-ld"
'';
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment