[dfranke@pathfinder:~]$ nix-repl
Welcome to Nix version 1.9. Type :? for help.
nix-repl> #This behaves as expected
nix-repl> let f = { x ? "foo" }: x; g = y@{...}: f y; in g { x = "bar"; }
"bar"
nix-repl> :quit
[dfranke@pathfinder:~]$ cat test1.nix
let f = { x ? "foo", ... }: x; in y@{...}: f y
[dfranke@pathfinder:~]$ #This too should evaluate to "bar", not "foo"
[dfranke@pathfinder:~]$ nix-instantiate --eval --argstr x bar test1.nix
"foo"
[dfranke@pathfinder:~]$ #Now x is explicitly mentioned in the pattern
[dfranke@pathfinder:~]$ cat test2.nix
let f = { x ? "foo", ... }: x; in y@{x,...}: f y
[dfranke@pathfinder:~]$ #...and that's sufficient to produce a different result"
[dfranke@pathfinder:~]$ nix-instantiate --eval --argstr x bar test2.nix
"bar"
[dfranke@pathfinder:~]$ #Something's definitely wrong here!
I noticed this today too. I thought I could do nix-build -A opencv --arg enableBloat true (enables GUI + Python support), but that does not work; opencv has the same output path as before. However, nix-build -A opencv --arg system \"i686-linux\" clearly works (new output path). So apparently only top-level arguments can be overridden, not anything "deeper".
Noticed this too. I tried to refactor the rtags package using a parameter for its underlying llvmPackages dependencies. Since, we have 6 different llvmPackages, it would be important to have --arg/--argstrpropagated down to the package arguments. Otherwise any package maintainer has to bloat up the top-level/all-packages.nix by multiples of its package dependencies. e.g.:
nix-env -iA rtags --argstr withllvmVersion "3.9"
is a better solution than:
rtags = callPackage ../development/tools/rtags/default.nix {
inherit (darwin) apple_sdk;
llvmVersion = llvmPackages;
};
rtags_with_llvm_38 = callPackage ../development/tools/rtags/default.nix {
inherit (darwin) apple_sdk;
llvmVersion = llvmPackages_38;
};
rtags_with_llvm_39 = callPackage ../development/tools/rtags/default.nix {
inherit (darwin) apple_sdk;
llvmVersion = llvmPackages_39;
};
I've run into this issue as well. I've been trying to nix-env -iA nixos.pkgs.qbittorrent --arg guiSupport false (see https://github.com/NixOS/nixpkgs/blob/release-16.09/pkgs/applications/networking/p2p/qbittorrent/default.nix#L4). The problem exists since at least since 2013: http://lists.science.uu.nl/pipermail/nix-dev/2013-June/011312.html.
@edolstra @shlevy according to quick git-blame lookup you might be able to help here.
@peti A small test to reproduce this inconsistency:
test.nix
args @ { a ? "default", ... }:
builtins.trace args
(builtins.trace a
"abc")
nix-build says
$ nix-build --argstr a override test.nix
trace: { a = "override"; }
trace: override
error: expression does not evaluate to a derivation (or a set or list of those)
nix repl says
$ nix repl --argstr a override test.nix
Welcome to Nix version 2.1. Type :? for help.
Loading 'test.nix'...
trace: { }
trace: default
error: value is a string while a set was expected
The arguments seem to be never supplied to the call, if nix repl is used.
To fix this problem, go to https://github.com/NixOS/nix/blob/bba3f0a308cceb56bad4aa1efe13927360ae463f/src/nix/repl.cc#L449.
Replace this with Bindings * autoArgs = getAutoArgs(&state); and (perhaps) release it later.
This issue still occurs:
$ printf '%s\n' '{ foo ? null, ... } @ args: { inherit args; }' > a.nix
$ printf '%s\n' 'import ./a.nix' > b.nix
$ printf '%s\n' 'args: import ./a.nix args' > c.nix
$ printf '%s\n' '{ ... } @ args: import ./a.nix args' > d.nix
$ printf '%s\n' '{ foo ? false, bar ? false, ... } @ args: import ./a.nix args' > e.nix
$ printf '%s\n' '{ __functor = self: { ... } @ args: import ./a.nix args; __functionArgs = { foo = true; bar = true; }; }' > f.nix
$ nix --version
nix (Nix) 2.3.6
$ nix eval -f a.nix args
{ }
$ nix eval -f a.nix args --arg foo true
{ foo = true; }
$ nix eval -f a.nix args --arg bar true
{ }
$ nix eval -f b.nix args --arg foo true
{ foo = true; }
$ nix eval -f b.nix args --arg bar true
{ }
$ nix eval -f c.nix args
error: the expression selected by the selection path 'args' should be a set but is a function
$ nix eval -f c.nix args --arg foo true
error: the expression selected by the selection path 'args' should be a set but is a function
$ nix eval -f d.nix args --arg foo true
{ }
$ nix eval -f e.nix args
{ }
$ nix eval -f e.nix args --arg foo true
{ foo = true; }
$ nix eval -f e.nix args --arg bar true
{ bar = true; }
$ nix eval -f e.nix args --arg baz true
{ }
$ nix eval -f f.nix args
{ }
$ nix eval -f f.nix args --arg foo true
{ }
$ nix eval -f f.nix args --arg bar true
{ }
$ nix eval -f f.nix args --arg baz true
{ }
There's no way to pass through arguments without linearly returning a single function (or functor) with syntactic, non-setFunctionArgs arguments. This means you can't allow for selection from a range of functions, all recieving just the passed arguments, without duplicating every possible argument name into the wrapping function's argument set as optional arguments.
I just ran into this myself today, it was quite confusing until I found this issue. I think it should be reopened
FWIW @dingxiangfei2009's example gives a false positive of working for nix-build
test.nix
args @ { a ? "default", ... }: builtins.trace args (builtins.trace a "abc")nix-build says
$ nix-build --argstr a override test.nix trace: { a = "override"; } trace: override error: expression does not evaluate to a derivation (or a set or list of those)
to correctly reproduce the issue run the following instead:
$ nix-build --argstr a override --argstr b override test.nix
trace: { a = "override"; }
trace: override
error: expression does not evaluate to a derivation (or a set or list of those)
I would have expected
trace: { a = "override"; b = "override"; }
To get this result I need to add b to the args set in test.nix.
Unfortunately, my C isn't good enough to see where the fix should go, but this issue definitely should be reopened.
Most helpful comment
3965 fixes this for real