During the last two community of practice meetups of the Munich NixOS group, @lo1tuma, me & @globin analyzed the state of the union of cross-compilation for x86_64-linux
binaries on a darwin host machine. The main driver behind the analysis is to use cross-compilation with dockerTools.buildImage
.
Management summary:
x86_64-linux
on a x86_64-darwin
host platform.Libsystem
headers and dylibs modulo rpath-modifications with any nix-store dependencies.darwin.xcode
as codified in nixpkgs. Currently not possible due to nix issue #619.darwin.usr-include
is missing dylibs.stdenv.darwin
into an additional package darwin.libsystem-inpure
. Results in a mass rebuild if we add this to the buildInputs of cc-wrapper
. More testing needs to finalize this approach.Solution proposals in order of favor:
Libsystem
from stdenv.darwin
as an additional package for gccCrossStageStatic
.Further improvements for cross-compilation:
isXXXX
-fields in the crossSystem attribute set.crossSystem
for your nix-build's default.nix
:let
targetSystem = rec {
config = "x86_64-linux-gnu";
arch = "x86_64";
withTLS = true;
libc = "libSystem"; # This is the libc of your hostsystem
platform = (with buildPkgs.lib.systems.platforms; pc64 // { kernelMajor = "2.6"; });
openssl.system = "linux-generic64";
isDarwin = false;
isWindows = false;
isCygwin = false;
isLinux = true;
};
buildPkgs = import ../nixpkgs {};
targetPkgs = import ../nixpkgs {
crossSystem = targetSystem;
};
in
targetPkgs.hello
stdenv.cross
:[BuildPackages] [TargetPackages]
stdenv.cross ----> gccCrossStageFinal ---> hello
|
|
|
---> libcCross ---> gccCrossStageStatic --> crossSystem.libc e.g. Libsystem
{stdenv
, localSystem
, bootstrapFiles ? let
fetch = { file, sha256, executable ? true }: import <nix/fetchurl.nix> {
url = "http://tarballs.nixos.org/stdenv-darwin/x86_64/c4effbe806be9a0a3727fdbbc9a5e28149347532/${file}";
inherit (localSystem) system;
inherit sha256 executable;
}; in {
sh = fetch { file = "sh"; sha256 = "1b9r3dksj907bpxp589yhc4217cas73vni8sng4r57f04ydjcinr"; };
bzip2 = fetch { file = "bzip2"; sha256 = "1wm28jgap4cbr8hf4ambg6h9flr2b4mcbh7fw20i0l51v6n8igky"; };
mkdir = fetch { file = "mkdir"; sha256 = "0jc32mzx2whhx2xh70grvvgz4jj26118p9yxmhjqcysagc0k7y66"; };
cpio = fetch { file = "cpio"; sha256 = "0x5dcczkzn0g8yb4pah449jmgy3nmpzrqy4s480grcx05b6v6hkp"; };
tarball = fetch { file = "bootstrap-tools.cpio.bz2"; sha256 = "0ifdc8bwxdhmpbhx2vd3lwjg71gqm6pi5mfm0fkcsbqavl8hd8hz"; executable = false; };
}
}:
let
inherit (localSystem) system;
libSystemProfile = ''
(import "${../../../stdenv/darwin/standard-sandbox.sb}")
'';
binShClosure = ''
(allow file-read* (literal "/usr/lib/libncurses.5.4.dylib"))
'';
bootstrapTools = derivation rec {
inherit system;
name = "bootstrap-tools";
builder = bootstrapFiles.sh; # Not a filename! Attribute 'sh' on bootstrapFiles
args = [ ../../../stdenv/darwin/unpack-bootstrap-tools.sh ];
inherit (bootstrapFiles) mkdir bzip2 cpio tarball;
__sandboxProfile = binShClosure + libSystemProfile;
};
in stdenv.mkDerivation {
name = "libsystem-impure";
buildCommand = ''
mkdir -p $out
ln -s ${bootstrapTools}/lib $out/lib
ln -s ${bootstrapTools}/include-Libsystem $out/include
'';
}
and use in all-packages.nix
:
libsystem-impure = callPackage ../os-specific/darwin/libsystem-impure {
localSystem = buildPlatform;
} ;
replace all darwin.xcode
occurrences with darwin.libsystem-impure
in all-packages.nix
.
macOS 10.12.6
nix-env (Nix) 1.11.13
17.09pre-git
cc @Ericson2314 & @fpletz
I think the attributes are correct just being used incorrectly. This should be much easier to fix. On commute + phone now, but can discuss soon.
I think the key component here is _running_ Linux binaries on a Darwin machine, right? @puffnfresh is doing some work on transparent VMs for that, but cross-compilation doesn't seem like the core issue here to me.
I also don't understand the darwin.xcode
stuff, which isn't really used very much at all.
Yes, I am trying to solve the dockerTools
problem for my team. So far I have got HyperKit working within Nix and have a script to configure it as a remote builder. You can find my work here:
https://github.com/puffnfresh/nixpkgs/tree/feature/hyperkit-builder
I would like to try a few different things:
Then I'd like to think about turning the remote builder into a:
runInLinuxVM
I'm confident that HyperKit is the appropriate tool for producing x86_64-linux on x86_64-darwin.
This is about cross-compiling linux binaries on darwin, not about running them.
@copumpkin
darwin.xcode
is afaik a bridge to provide a libsystem
for packages like gccCrossStageStatic
, which are built by apple. I suppose because nobody except apple can built the libsystem from source.
@puffnfresh
Thx for the link to your HyperKit
work. I'll take a look on it. However, can you elaborate why cross-building linux binaries on darwin with the nixpkgs.stdenv.cross
means is (not) enough for producing linux binaries for docker images?
@periklis dockerTools
has stuff around building root layers, which use runInLinuxVM
. It should hopefully be possible if you don't use the root layer building.
@puffnfresh i had a look on your hyperkit branches and it is indeed a very interesting approach to run a vm as nix-builder machine through xhyve. This approach makes cross-compilation totally obsolete, but constrains the handling of total resources to build, doesn't it?
Did you collect any cross-compilation experience in the first place and then switched to the hyper-kit approach? ooo(i saw a stale cross-compilation on your repo)
@globin but my point is that if you're building Docker images with the current codebase for doing that, you're also _running_ Linux binaries to produce the images. And once you're running Linux binaries, you can build Linux binaries more easily
@copumpkin That is only the case when you build an image with using runAsRoot
or am I missing something?
Oh, you might be right. I haven't looked at the docker builder in a long time. I'd love it if we could build those images with no VM involvement!
The following example builds successfully on macOS:
{ pkgs ? import <nixpkgs> {} }:
let
inherit (pkgs) dockerTools;
in
dockerTools.buildImage {
name = "hello";
tag = "latest";
config = {
Cmd = [ "${pkgs.hello}/bin/hello" ];
};
}
I can even load the image via docker load < ./result
, but I can’t run it because the hello
binary in the image is a macOS binary.
@lo1tuma oh, I see. So in that case just doing the following:
{ pkgs ? import <nixpkgs> {} }:
let
inherit (pkgs) dockerTools;
linuxPkgs = import <nixpkgs> { system = "x86_64-linux"; };
in
dockerTools.buildImage {
name = "hello";
tag = "latest";
config = {
Cmd = [ "${linuxPkgs.hello}/bin/hello" ];
};
}
Should be fine if binaries are available in the cache. And with @puffnfresh's builder, it should build them seamlessly in the background Linux VM similarly to how Docker for Mac works. Cross compilation would also be nice but feels like a much gnarlier problem.
Unfortunately, the above snippet does not work on my Nix on macOS because it claims that Docker is unsupported on Darwin. Did you do something special to make our docker
package work on macOS there?
The dockerTools don't depend on docker AFAIK
@LnL7 I just tried evaluating the snippet in my post above and it complained that docker was unsupported. Not sure what depends on it:
error: Package ‘docker-17.06.0-ce’ in /nix/store/zdzvl6fk60cw4izxfakhxiz17aipxfd1-nixpkgs-17.09pre111456.d4ef5ac0e9/nixpkgs/pkgs/applications/virtualization/docker/default.nix:165 is not supported on ‘x86_64-darwin’, refusing to evaluate.
a) For `nixos-rebuild` you can set
{ nixpkgs.config.allowBroken = true; }
in configuration.nix to override this.
b) For `nix-env`, `nix-build`, `nix-shell` or any other Nix command you can add
{ allowBroken = true; }
to ~/.config/nixpkgs/config.nix.
(use ‘--show-trace’ to show detailed location information)
Must have changed recently then.
dockerTools
switched to using Docker to pull images recently. There were problems around image URLs.
Alternative approach by @puffnfresh: #29628
@LnL7 and I started working on linux->Darwin cross compilation.
You mean building Darwin on Linux or building Linux on Darwin?
@Ericson2314 Great news! My intention was only to cross-reference to @puffnfresh approach.
@Ericson2314 do you have a jobset for the linux->darwin cc to watch?
Oh sorry meant Darwin->Linux. No jobset just yet, but https://github.com/Ericson2314/nixpkgs/tree/darwin-to-linux is a branch
@Ericson2314 Your WIP starts with https://github.com/Ericson2314/nixpkgs/commit/d8243d3befbe5b33749b39eb48442dfa227242a2 on top of #29396 and #26805 right?
Indeed! All those branches will end up being rebased, but that's the order.
And yes with a special substituter, the @puffnfresh approach and mine could dovetail nicely
@Ericson2314 Is the "special" substituter inevitable for macOS cross? I'd like to be able to do "true" cross compile stuff on macOS but everything seems to lead to @puffnfresh's Linux VM route. That can probably work but seems a little bit like cheating. Ideally macOS cross compiling should work just like Linux cross compiling does.
@matthewbauer The special substituter stuff is only necessary to use a native cache for cross builds.
@Ericson2314 Actually there was an experimental branch of yours obsidiansystems/darwin-to-linux
from last Nixcon, which was fruitful thought on the missing parts for darwin-to-linux cross-compilation, but i can't find it anymore.
@periklis These are my changes based on John's branch darwin-to-linux. I got stuck with the kernel build because of case sensitivity issues, etc.
Most helpful comment
@periklis These are my changes based on John's branch darwin-to-linux. I got stuck with the kernel build because of case sensitivity issues, etc.