[Nix-dev] The nixpkgs.config vs overrides (was: Documenting nixpkgs.config options)
Jan Malakhovski
oxij at oxij.org
Thu May 28 14:30:47 CEST 2015
Hi.
The problem is that people will say than "config is deprecated, use
overrides". I had a pull-request with a set of patches that allows one
to write
nixpkgs.config = {
allowUnfree = unfree;
common.x11Support = graphical; # note this
pulseaudio = false; # should be renamed to common.pulseAudioSupport
# but I didn't get around to rename it yet
conky = {
wirelessSupport = true;
luaSupport = true;
};
mplayer = {
xineramaSupport = graphical;
xvSupport = graphical;
screenSaverSupport = graphical;
useUnfreeCodecs = enslaved;
};
sylpheed.gpgSupport = true;
}
in their configuration.nix (with that `common` thing setting
`x11Support` to all the packages that have that option), but it was cut
down with "do not add new config options, they are deprecated, we have
overrides already".
Personally I have some problems with current practices:
* I don't like the idea of using `null`s in package arguments of a
package expression as a way to specify features. I think this is ugly
and error prone.
* Currently obsessive use of overrides generates more versions of
packages than needed. Do
egrep -A 3 -B 6 ' .*override' all-packages.nix
every override of a package in an argument set for another package
will likely to ask nix to compile another version. This is crazy. And
I see that craziness in action every time I rebuild my configuration,
'cause I use a shitton of packages in `environment.systemPackages` on
my desktop machines. I haven't measured the CPU time and disk space
losses to this craziness, but I don't like the fact that these losses
exist at all.
I think packages should assert that some options are set in their
dependencies (e.g. the original xbmc[1] expression that used external
ffmpeg checked that ffmpeg it was supplied was compiled with the
required options using `passthru`; current `kodi` just builds another
ffmpeg; it might have other valid reasons to do that, but still). And
only then add another version of the package with those packages
forcefully made to comply to those assertions. I.e. instead of the
currently popular
dependency = callPackage ({..., whateverSupport, }: ...) ...;
somepackage = callPackage ({..., thisWhateverSupport ? true, dependency, ...}:
assert thisWhateverSupport -> dependency.whateverSupport;
mkDerivation { ... })
{
dependency = dependency.override { whateverSupport = true; };
};
that generates another version of dependency one would write
dependency = callPackage ... {};
somepackage = callPackage ({..., dependency, ...}:
assert thisWhateverSupport -> dependency.whateverSupport;
mkDerivation { ... }) {};
somepackage_forced = somepackage.override {
dependency = if config.somepackage.thisWhateverSupport
then dependency.override { whateverSupport = true; }
else dependency;
};
which doesn't. When one simply does
nixpkgs.config.dependency.whateverSupport = true;
or maybe even
nixpkgs.config.common.whateverSupport = true;
* Overrides are not fixed points and this is a serious problem for some.
See https://github.com/NixOS/nixpkgs/pull/7102.
* For some strange reason it seems that overrides sometimes evaluate
stuff too early. I haven't been able debug this, but overriding all
the X11, GTK and QT packages (exactly those packages, not the packages
that use those packages) to `null`s in nixpkgs and then specifically
overriding some of the packages that use them shows that some of the
latter packages will try to evaluate X11, GTK or QT even when
explicitly overridden not to so. I guess that's because something in
the derivation get's stuck on the previous version of the argument,
but, as I said, I haven't been able to debug this yet.
And so now I maintain my own set of patches I rebase on top of master
once and then, that goes against the grain and simplifies all that
`nixpkgs.config`-style configuration stuff fairly significantly by
adding another version of callConfPackages (also removing a ton of
copy-paste from `all-packages.nix` as a side effect)
https://github.com/NixOS/nixpkgs/compare/master...oxij:call-conf-package
and weep every time someone rewrites and expression for a package
dropping the support for `<feature>Support` options (e.g. most recently
`qemu` =/).
Said that, I agree that there are problems with this:
* All that `somepackage_forced` is somewhat ugly. I would prefer to have
a way to describe and introspect assertions in the packages and
generate those *_forced thingies automatically. Or maybe even write
something like
environment.systemPackages = [ somepackage.force_dependencies ];
* Package options need documentation (which the original message by
Herwig Hochleitner is about). This is totally doable even now with
reusing NixOS modules in nixpkgs:
{ dependency1, dependency2, ... }:
{ config, ...} :
{ options = { supportWhatever = mkOption ...; };
assertions = [ ... ];
config = mkDerivation { ... };
};
and then fixing `callPackage` to grab only the `config` and move the
`options` to `meta`. And then collecting the latter by grabbing all
the stuff from the packages `nix-env -q` uses (one could even show the
options in nix-env this way).
But I agree that this is somewhat ugly. Especially because usually
all `supportWhatever` does is adds a flag to `configureFlags` and
another dependency to `buildInputs`.
The proper solution is to implement a dual of `bulitins.functionArgs`
that _generates_ a function with arguments and their defaults set from
an attrset. And then implement a dual of `callPackageWith` (which I
call `generatePackageWith` below) that generates package expressions
with all the options, flags and requirements from expressions like:
generatePackageWith (args: {
x11 = { addToArgs = [ "libX11" ];
configureFlags = [ "--with-x11" ];
buildInputs = [ args.libX11; ];
};
}) { mkDerivation, other stuff, ...}:
mkDerivation { ... };
(with `generatePackageWith` simply overriding `mkDerivation` inside.)
The type of a configuration stub shown above could then be generalized
to something like
cfbiFlag = name: f: { addToArgs = [ name ];
configureFlags = [ "--with-${f}" ];
buildInputs = [ args.${name} ];
};
and put into lib.
All in all, all of this (and even more, but this message is long enough
already) is totally doable, but the generic lack of free time and a
continuous explicit and implicit discouraging of this by "we have
overrides, nixpkgs.config is deprecated, do not add new options there"
and the perverse use of those overrides
(that, by the way, makes me either revert my changes a bit by bit or
rewrite the whole expressions (which I actually did a couple of times
for `samba` because I (and, I suppose, other sane people) DO NOT WANT
`ceph` by default on the desktop!, but after another rewrite of that
expression in upstream I dropped my changes altogether, simply
overrode the stub in all-packages.nix and walked away)
holds most of those ideas at the "only the idea" stage of development.
If there is interest in all this, then maybe. Currently I have that set
of patches from above and another set which simply overrides another ton
of expressions directly in `all-packages.nix` so that this craziness is
limited to stuff I don't want to touch anymore. I'm not happy about
this, but I'm okay.
Cheers,
Jan
[1] https://github.com/NixOS/nixpkgs/compare/master...oxij:xbmc-11
this was merged into master awhile ago.
Herwig Hochleitner <hhochleitner at gmail.com> writes:
> Contrary to nixos *module* options, which are self-documenting at
> http://nixos.org/nixos/options.html, there is no equivalent documentation
> for options available in nixpkgs.config. ...
More information about the nix-dev
mailing list