Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add cross-compilation support #153

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

szlend
Copy link

@szlend szlend commented Oct 27, 2024

Fixes #138

This PR attempts to add cross-compilation support to nix2container. It's the same approach as taken in #139, but without moving derivations into separate files, so it should be much easier to review.

What was done:

  • Add and pass --arch argument to nix2container image command
  • Wrap each derivation in callPackage
  • Move derivation references to builtInputs/nativeBuildInputs (avoid ${foo}/bin/foo)
  • Explicitly pick the correct derivation variant (e.g. pkgsBuildHost.<name>) when builtInputs/nativeBuildInputs is not available
  • Expose derivations through makeScopeWithSplicing'

These changes as a whole make nix2container cross-compilation-aware when overlayed with a cross-compiling pkgs instance.

Todo:

  • Some sort of basic cross-compilation test coverage. Ideally with a cross stdenv that's guaranteed to be cached in nixpkgs.

Other thoughts:

  • I would still recommend moving all calPackage-based derivations into their own separate files in a followup MR. I think it will be easier to maintain as it won't be possible to accidentally reference derivations outside of callPackage scope.

@szlend
Copy link
Author

szlend commented Oct 27, 2024

Right now you can test this by adding examplesCross to flake.nix:

pkgsCross = if pkgs.stdenv.isAarch64 then pkgs.pkgsCross.gnu64 else pkgs.pkgsCross.aarch64-multiplatform;
nix2containerCross = import ./. {
    pkgs = pkgsCross;
    inherit system;
};
examplesCross = import ./examples {
    pkgs = pkgsCross;
    inherit (nix2containerCross) nix2container;
};

Example run from x86_64-linux (targeting aarch64-linux):

$ nix build .#examplesCross.hello -L

image-hello.json> INFO[0000] Getting image configuration from /nix/store/h79jhrvld9srwavwygcdsn9ax0rsj326-config.json
image-hello.json> INFO[0000] Adding 1 layers from /nix/store/n1mwd8a4clf2d1lq9wvlrxl70skmx9sd-layers.json/layers.json
image-hello.json> INFO[0000] Adding 1 layers from /nix/store/8biixrls4j1j71q817v41969djxhcw95-layers.json/layers.json
image-hello.json> INFO[0000] Image has been written to /nix/store/y74almkax67q7xw6yp0j059cyklh3wja-image-hello.json
{
  "version": 1,
  "image-config": {
    "Entrypoint": [
      "/nix/store/zaff90jlqbg1z7jjsp0z9im1hkpmbaxk-bash-aarch64-unknown-linux-gnu-5.2p26/bin/bash",
      "/nix/store/wf6kk5r79gsimj2kpbxrj6l8wpn5yqf8-conversation"
    ]
  },
  "layers": [
    {
      "digest": "sha256:15a9646981e88ef04dc77bd490816d9d4836d27ae1184ddb9d36eb6026e85e29",
      "size": 46515712,
      "diff_ids": "sha256:15a9646981e88ef04dc77bd490816d9d4836d27ae1184ddb9d36eb6026e85e29",
      "paths": [
        {
          "path": "/nix/store/vafhdaaycr12b08a7aad25qkwcn53kcw-libgcc-aarch64-unknown-linux-gnu-13.2.0"
        },
        {
          "path": "/nix/store/9jhzhfgwv9c26azvmv3a4vk4ih1cqpqh-glibc-aarch64-unknown-linux-gnu-2.39-5"
        },
        {
          "path": "/nix/store/zaff90jlqbg1z7jjsp0z9im1hkpmbaxk-bash-aarch64-unknown-linux-gnu-5.2p26"
        },
        {
          "path": "/nix/store/hz6dk22fsdqg593v83kyvqwnsdnz6izh-hello-aarch64-unknown-linux-gnu-2.12.1"
        }
      ],
      "mediatype": "application/vnd.oci.image.layer.v1.tar"
    },
    {
      "digest": "sha256:c1418b4793e8cda79e71d01d7096c051d8968af9801239971173659f80783ccd",
      "size": 3584,
      "diff_ids": "sha256:c1418b4793e8cda79e71d01d7096c051d8968af9801239971173659f80783ccd",
      "paths": [
        {
          "path": "/nix/store/wf6kk5r79gsimj2kpbxrj6l8wpn5yqf8-conversation"
        }
      ],
      "mediatype": "application/vnd.oci.image.layer.v1.tar"
    }
  ],
  "arch": "arm64",
  "created": "0001-01-01T00:00:00Z"
}

@szlend
Copy link
Author

szlend commented Oct 27, 2024

I'm not sure yet how to tackle cross-compilation tests. Should we run the same example tests against a cross nixpkgs instance?

Some ideas (from simplest to hardest):
a) Skip all runtime checks (e.g. podman run) and just check the output image json has the correct architecture set
b) Scan layers (nix store references) for any foreign binaries
c) Run the same runtime checks but use qemu foreign architecture emulation to execute containers

@szlend
Copy link
Author

szlend commented Oct 27, 2024

Something like this works for method B:

crossTestScript = { image, hostPlatform }: pkgs.writeScriptBin "test-script" ''
  export PATH="${pkgs.lib.makeBinPath [pkgs.nix pkgs.findutils pkgs.gnugrep pkgs.file pkgs.coreutils]}"

  binaries=$(nix-store --query --requisites ${image} | xargs find | xargs file | grep ELF)
  native_binaries=$(echo "$binaries" | grep ${hostPlatform.qemuArch})

  if [ "$binaries" == "$native_binaries" ]; then
    echo "No foreign binaries detected (expected ${hostPlatform.qemuArch})"
  else
    echo "Error: Foreign binaries detected (expected ${hostPlatform.qemuArch}):"
    echo "$binaries" | grep -v ${hostPlatform.qemuArch}
    exit 1
  fi
'';

@szlend
Copy link
Author

szlend commented Nov 9, 2024

@nlewo Could I get your thoughts on this? Happy to answer any questions or do any other work necessary to get cross-compilation support in.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Cannot cross-build images for a foreign architecture
1 participant