From 5eaea6cee01e9172ae65ccb6356861786a0f85cc Mon Sep 17 00:00:00 2001 From: John Ericson Date: Mon, 26 Dec 2016 14:32:14 -0800 Subject: cross stdenv: let build package's build deps resolve to native packages This fixes the "sliding window" principle: 0. Run packages: build = native; host = foreign; target = foreign; 1. Build packages: build = native; host = native; target = foreign; 2. Vanilla packages: build = native; host = native; target = native; 3. Vanilla packages: build = native; host = native; target = native; n+3. ... Each stage's build dependencies are resolved against the previous stage, and the "foreigns" are shifted accordingly. Vanilla packages alone are built against themsevles, since there are no more "foreign"s to shift away. Before, build packages' build dependencies were resolved against themselves: 0. Run packages: build = native; host = foreign; target = foreign; 1. Build packages: build = native; host = native; target = foreign; 2. Build packages: build = native; host = native; target = foreign; n+2. ... This is wrong because that principle is violated by the target platform staying foreign. This will change the hashes of many build packages and run packages, but that is OK. This is an unavoidable cost of fixing cross compiling. The cross compilation docs have been updated to reflect this fix. --- doc/cross-compilation.xml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'doc') diff --git a/doc/cross-compilation.xml b/doc/cross-compilation.xml index e93d1a98f7fd..32cf198449bb 100644 --- a/doc/cross-compilation.xml +++ b/doc/cross-compilation.xml @@ -105,14 +105,15 @@ This is the most important guiding principle behind cross-compilation with Nixpkgs, and will be called the sliding window principle. In this manner, given the 3 platforms for one package, we can determine the three platforms for all its transitive dependencies. + + Some examples will probably make this clearer. + If a package is being built with a (build, host, target) platform triple of (foo, bar, bar), then its build-time dependencies would have a triple of (foo, foo, bar), and those packages' build-time dependencies would have triple of (foo, foo, foo). + In other words, it should take two "rounds" of following build-time dependency edges before one reaches a fixed point where, by the sliding window principle, the platform triple no longer changes. + Indeed, this happens with cross compilation, where only rounds of native dependencies starting with the second necessarily coincide with native packages. + The depending package's target platform is unconstrained by the sliding window principle, which makes sense in that one can in principle build cross compilers targeting arbitrary platforms. - - From the above, one would surmise that if a package is being built with a (build, host, target) platform triple of (foo, bar, bar), then its build-time dependencies would have a triple of (foo, foo, bar), and those packages' build-time dependencies would have triple of (foo, foo, foo). - In other words, it should take two "rounds" of following build-time dependency edges before one reaches a fixed point where, by the sliding window principle, the platform triple no longer changes. - Unfortunately, at the moment, we do not implement this correctly, and after only one round of following build-time dependencies is the fixed point reached, with target incorrectly kept different than the others. - How does this work in practice? Nixpkgs is now structured so that build-time dependencies are taken from from buildPackages, whereas run-time dependencies are taken from the top level attribute set. For example, buildPackages.gcc should be used at build time, while gcc should be used at run time. -- cgit 1.4.1 From 8cd4c31d6b8c6432986edf0ec5d00d2fe1c12854 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Wed, 8 Feb 2017 16:43:52 -0500 Subject: top-level: Allow nixpkgs to take localSystem directly This is instead of both system and platform, which is kind of ugly. --- doc/cross-compilation.xml | 20 +++++++++++++++--- pkgs/top-level/all-packages.nix | 6 ++++-- pkgs/top-level/default.nix | 47 +++++++++++++++-------------------------- pkgs/top-level/impure.nix | 19 +++++++++++++---- 4 files changed, 53 insertions(+), 39 deletions(-) (limited to 'doc') diff --git a/doc/cross-compilation.xml b/doc/cross-compilation.xml index 32cf198449bb..8e981a4318e1 100644 --- a/doc/cross-compilation.xml +++ b/doc/cross-compilation.xml @@ -25,7 +25,7 @@
- Packing in a cross-friendly manner + Packaging in a cross-friendly manner
Platform parameters @@ -132,9 +132,23 @@
Cross-building packages + + More information needs to moved from the old wiki, especially , for this section. + + + Many sources (manual, wiki, etc) probably mention passing system, platform, and, optionally, crossSystem to nixpkgs: + import <nixpkgs> { system = ..; platform = ..; crossSystem = ..; }. + system and platform together determine the system on which packages are built, and crossSystem specifies the platform on which packages are ultimately intended to run, if it is different. + This still works, but with more recent changes, one can alternatively pass localSystem, containing system and platform, for symmetry. + - To be written. - This is basically unchanged so see the old wiki for now. + One would think that localSystem and crossSystem overlap horribly with the three *Platforms (buildPlatform, hostPlatform, and targetPlatform; see stage.nix or the manual). + Actually, those identifiers are purposefully not used here to draw a subtle but important distinction: + While the granularity of having 3 platforms is necessary to properly *build* packages, it is overkill for specifying the user's *intent* when making a build plan or package set. + A simple "build vs deploy" dichotomy is adequate: the sliding window principle described in the previous section shows how to interpolate between the these two "end points" to get the 3 platform triple for each bootstrapping stage. + That means for any package a given package set, even those not bound on the top level but only reachable via dependencies or buildPackages, the three platforms will be defined as one of localSystem or crossSystem, with the former replacing the latter as one traverses build-time dependencies. + A last simple difference then is crossSystem should be null when one doesn't want to cross-compile, while the *Platforms are always non-null. + localSystem is always non-null.
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index e066d1ababd9..fc6b1e41d534 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -18,8 +18,10 @@ with pkgs; # Override system. This is useful to build i686 packages on x86_64-linux. forceSystem = system: kernel: nixpkgsFun { - inherit system; - platform = platform // { kernelArch = kernel; }; + localSystem = { + inherit system; + platform = platform // { kernelArch = kernel; }; + }; }; # Used by wine, firefox with debugging version of Flash, ... diff --git a/pkgs/top-level/default.nix b/pkgs/top-level/default.nix index 3c67d316f7c8..3e3ecdeea6cb 100644 --- a/pkgs/top-level/default.nix +++ b/pkgs/top-level/default.nix @@ -17,8 +17,14 @@ evaluation is taking place, and the configuration from environment variables or dot-files. */ -{ # The system (e.g., `i686-linux') for which to build the packages. - system +{ # The system packages will be built on. See the manual for the + # subtle division of labor between these two `*System`s and the three + # `*Platform`s. + localSystem + + # The system packages will ultimately be run on. Null if the two should be the + # same. +, crossSystem ? null , # Allow a configuration attribute set to be passed in as an argument. config ? {} @@ -27,12 +33,9 @@ overlays ? [] , # A function booting the final package set for a specific standard - # environment. See below for the arguments given to that function, - # the type of list it returns. + # environment. See below for the arguments given to that function, the type of + # list it returns. stdenvStages ? import ../stdenv - -, crossSystem ? null -, platform ? assert false; null } @ args: let # Rename the function arguments @@ -51,10 +54,10 @@ in let # Allow setting the platform in the config file. Otherwise, let's use a # reasonable default. - platform = - args.platform - or ( config.platform - or ((import ./platforms.nix).selectPlatformBySystem system) ); + localSystem = + { platform = (import ./platforms.nix).selectPlatformBySystem args.localSystem.system; } + // builtins.intersectAttrs { platform = null; } config + // args.localSystem; # A few packages make a new package set to draw their dependencies from. # (Currently to get a cross tool chain, or forced-i686 package.) Rather than @@ -71,7 +74,8 @@ in let # To put this in concrete terms, this function is basically just used today to # use package for a different platform for the current platform (namely cross # compiling toolchains and 32-bit packages on x86_64). In both those cases we - # want the provided non-native `system` argument to affect the stdenv chosen. + # want the provided non-native `localSystem` argument to affect the stdenv + # chosen. nixpkgsFun = newArgs: import ./. (args // newArgs); # Partially apply some arguments for building bootstraping stage pkgs @@ -83,24 +87,7 @@ in let boot = import ../stdenv/booter.nix { inherit lib allPackages; }; stages = stdenvStages { - # One would think that `localSystem` and `crossSystem` overlap horribly with - # the three `*Platforms` (`buildPlatform`, `hostPlatform,` and - # `targetPlatform`; see `stage.nix` or the manual). Actually, those - # identifiers I, @Ericson2314, purposefully not used here to draw a subtle - # but important distinction: - # - # While the granularity of having 3 platforms is necessary to properly - # *build* packages, it is overkill for specifying the user's *intent* when - # making a build plan or package set. A simple "build vs deploy" dichotomy - # is adequate: the "sliding window" principle described in the manual shows - # how to interpolate between the these two "end points" to get the 3 - # platform triple for each bootstrapping stage. - # - # Also, less philosophically but quite practically, `crossSystem` should be - # null when one doesn't want to cross-compile, while the `*Platform`s are - # always non-null. `localSystem` is always non-null. - localSystem = { inherit system platform; }; - inherit lib crossSystem config overlays; + inherit lib localSystem crossSystem config overlays; }; pkgs = boot stages; diff --git a/pkgs/top-level/impure.nix b/pkgs/top-level/impure.nix index 6999b7428ba7..98094e931600 100644 --- a/pkgs/top-level/impure.nix +++ b/pkgs/top-level/impure.nix @@ -12,9 +12,11 @@ let in -{ # Fallback: Assume we are building packages for the current (host, in GNU - # Autotools parlance) system. - system ? builtins.currentSystem +{ # We combine legacy `system` and `platform` into `localSystem`, if + # `localSystem` was not passed. Strictly speaking, this is pure desugar, but + # it is most convient to do so before the impure `localSystem.system` default, + # so we do it now. + localSystem ? builtins.intersectAttrs { system = null; platform = null; } args , # Fallback: The contents of the configuration file found at $NIXPKGS_CONFIG or # $HOME/.config/nixpkgs/config.nix. @@ -49,4 +51,13 @@ in , ... } @ args: -import ./. (args // { inherit system config overlays; }) +# If `localSystem` was explicitly passed, legacy `system` and `platform` should +# not be passed. +assert args ? localSystem -> !(args ? system || args ? platform); + +import ./. (builtins.removeAttrs args [ "system" "platform" ] // { + inherit config overlays; + # Fallback: Assume we are building packages on the current (build, in GNU + # Autotools parlance) system. + localSystem = { system = builtins.currentSystem; } // localSystem; +}) -- cgit 1.4.1