I am currently encountering “Argument list too long” when attempting to use a dev shell that uses clang with nix-ros-overlay when I have a bunch of transitive dependencies:
$ nix build -L .#devShells.x86_64-linux.default
argument-list-too-long> Running phase: buildPhase
argument-list-too-long> /nix/store/93nj5v35ldxpmjsl6rhl9i394kaf54ni-stdenv-linux/setup: line 1752: /nix/store/8ksax0a2mxglr5hlkj2dzl556jx7xqn5-coreutils-9.7/bin/date: Argument list too long
error: Cannot build '/nix/store/m217xc3z50h50c6hbr9v4sf051dv8vv1-argument-list-too-long.drv'.
Reason: builder failed with exit code 126.
Output paths:
/nix/store/7pcjypww7a37z6pbpjhmsk3722b7mvfw-argument-list-too-long
Last 2 log lines:
> Running phase: buildPhase
> /nix/store/93nj5v35ldxpmjsl6rhl9i394kaf54ni-stdenv-linux/setup: line 1752: /nix/store/8ksax0a2mxglr5hlkj2dzl556jx7xqn5-coreutils-9.7/bin/date: Argument list too long
For full logs, run:
nix-store -l /nix/store/m217xc3z50h50c6hbr9v4sf051dv8vv1-argument-list-too-long.drv
See:
opened 09:24PM - 03 Mar 26 UTC
Possibly related: #285
If I attempt to build `nav2-bringup` using clang, then i… t fails with the message `Argument list too long`
here is the full error:
```
$ nix build -L .#devShells.x86_64-linux.default --show-trace
ros-jazzy-nav2-bringup> Running phase: qtPreHook
ros-jazzy-nav2-bringup> /nix/store/3037naxrk7h2qiadv1s2ah8jvdllxv8p-stdenv-linux/setup: line 1752: /nix/store/8ksax0a2mxglr5hlkj2dzl556jx7xqn5-coreutils-9.7/bin/date: Argument list too long
error: build of '/nix/store/lbhqs2fh32k79wv9s374r6q53pviwsgw-ros-jazzy-nav2-bringup-1.3.11-r1.drv' on 'ssh-ng://remotebuild@inx.moe' failed: builder for '/nix/store/lbhqs2fh32k79wv9s374r6q53pviwsgw-ros-jazzy-nav2-bringup-1.3.11-r1.drv' failed with exit code 126;
last 2 log lines:
> Running phase: qtPreHook
> /nix/store/3037naxrk7h2qiadv1s2ah8jvdllxv8p-stdenv-linux/setup: line 1752: /nix/store/8ksax0a2mxglr5hlkj2dzl556jx7xqn5-coreutils-9.7/bin/date: Argument list too long
For full logs, run:
nix log /nix/store/lbhqs2fh32k79wv9s374r6q53pviwsgw-ros-jazzy-nav2-bringup-1.3.11-r1.drv
error: Cannot build '/nix/store/lbhqs2fh32k79wv9s374r6q53pviwsgw-ros-jazzy-nav2-bringup-1.3.11-r1.drv'.
Reason: builder failed with exit code 1.
Output paths:
/nix/store/2syxr2qby4h68nv61xdhk6snx5bny9rw-ros-jazzy-nav2-bringup-1.3.11-r1-debug
/nix/store/qqk4gdvp936hib9pdd17a3hfma1splnc-ros-jazzy-nav2-bringup-1.3.11-r1
error: Cannot build '/nix/store/9vcm146fvyd7zlf7kcii5hw1qg5g8kba-ros-env.drv'.
Reason: 1 dependency failed.
Output paths:
/nix/store/jbdni5pxpp5g6bqybj8h7camnkjfspy7-ros-env
error: Build failed due to failed dependency
error: Cannot build '/nix/store/7kv0vhay3264bmfnf1qg5m9xh195y8cv-argument-list-too-long.drv'.
Reason: 1 dependency failed.
Output paths:
/nix/store/cfjd5il4ypndymc134z3fbsd0xr091ks-argument-list-too-long
error: Build failed due to failed dependency
```
and here's the full log:
```
Running phase: qtPreHook
@nix {"action":"setPhase","phase":"qtPreHook"}
/nix/store/3037naxrk7h2qiadv1s2ah8jvdllxv8p-stdenv-linux/setup: line 1752: /nix/store/8ksax0a2mxglr5hlkj2dzl556jx7xqn5-coreutils-9.7/bin/date: Argument list too long
```
line `1752` of that `setup` script is:
```bash
startTime=$(date +"%s")
```
so I assume that somewhere under the hood here there's an `execve` happening.
and here's a minimal reproduction case:
```nix
{
inputs = {
nix-ros-overlay.url = "github:lopsided98/nix-ros-overlay/master";
nixpkgs.follows = "nix-ros-overlay/nixpkgs"; # IMPORTANT!!!
};
outputs = { self, nix-ros-overlay, nixpkgs }:
nix-ros-overlay.inputs.flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs {
inherit system;
overlays = [ nix-ros-overlay.overlays.default ];
};
llvm = pkgs.llvmPackages_latest;
clangStdenv = llvm.stdenv;
jazzy = pkgs.rosPackages.jazzy.overrideScope (rosSelf: rosSuper:
let
buildRosPackageClang = rosSelf.buildRosPackage.override {
stdenv = clangStdenv;
};
in pkgs.lib.mapAttrs (_: package: (package.override {
buildRosPackage = buildRosPackageClang;
}).overrideAttrs ({
propagatedBuildInputs ? [],
...
} : {
propagatedBuildInputs = propagatedBuildInputs ++ [ llvm.openmp ];
})) {
inherit (rosSuper)
nav2-bringup
;
});
in {
devShells.default = pkgs.mkShell.override {
stdenv = clangStdenv;
} {
name = "argument-list-too-long";
packages = with pkgs; [
(with jazzy; buildEnv {
paths = [
nav2-bringup
];
})
];
};
});
nixConfig = {
extra-substituters = [
"https://cache.nixos.org"
"https://ros.cachix.org"
];
extra-trusted-public-keys = [
"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
"ros.cachix.org-1:dSyZxI8geDCJrwgvCOHDoAfOm5sV1wCPjBkKL+38Rvo="
];
};
}
```
here's also the `flake.lock` in case this is sometime after and the repo has since been updated:
<details>
<summary><code>flake.lock</code></summary>
```json
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nix-ros-overlay": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
},
"locked": {
"lastModified": 1771881010,
"narHash": "sha256-vYTYv1PoGG/Q6afrKnj7fdT+h2f4b1auOdXmQZTaldU=",
"owner": "lopsided98",
"repo": "nix-ros-overlay",
"rev": "2d52dc94f1eeb1465195d1f909b5a10006c8fafd",
"type": "github"
},
"original": {
"owner": "lopsided98",
"ref": "master",
"repo": "nix-ros-overlay",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1759381078,
"narHash": "sha256-gTrEEp5gEspIcCOx9PD8kMaF1iEmfBcTbO0Jag2QhQs=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "7df7ff7d8e00218376575f0acdcc5d66741351ee",
"type": "github"
},
"original": {
"owner": "lopsided98",
"ref": "nix-ros",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nix-ros-overlay": "nix-ros-overlay",
"nixpkgs": [
"nix-ros-overlay",
"nixpkgs"
]
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}
```
</details>
this error is new and only started happening once I updated to the latest version of the `master` branch, which I assume was merged with `develop` around 2-ish weeks ago.
if I don't use clang for `nav2-bringup`, the same issue also occurs with the devshell itself.
interestingly, this same error does *not* happen with some of the other nav2 packages. I have no clue why.
My understanding is that this is a long-standing issue in nix:
opened 10:06PM - 31 May 18 UTC
2.status: stale
### Quick summary
* nix blows up number of `-L` flags passed to GCC
* GCC pa… sses all `-L` flags to its subprogram `cc1` via an environment variable
* If that's longer than 128 KB, then everything crashes with `E2BIG`
### Details
So once again, I'm building some Haskell with lots of library dependencies.
Trying to upgrade this build to 18.03, the `nix-build` of the Haskell package newly fails with
```
Setup: Missing dependencies on foreign libraries:
* Missing C libraries: glog
```
This error message is wrong (cabal doesn't correctly propagate the `argument list too long` error shown below; I filed a bug about it being misleading at https://github.com/haskell/cabal/issues/5355); the dependency exists.
The problem is that because in some eventual `gcc` invocation the amount of arguments passed to GCC turns out to be very long.
`strace` confirms:
```
strace -fye execve -s 100000000 -v runhaskell Setup.hs build 2>&1 | grep E2BIG
```
```
execve("cc1", [arguments here], [env vars here, "COLLECT_GCC_OPTIONS='-fno-stack-protector -L... 150KB of -L flags here'"] = -1 E2BIG (Argument list too long)
```
`E2BIG (Argument list too long)`, in this case because `COLLECT_GCC_OPTIONS` is longer than 128 KB (32 * 4 KB pages, see [here](https://unix.stackexchange.com/a/120842/100270), and a [repro script I made here](https://github.com/NixOS/nixpkgs/issues/41340#issuecomment-469026735)).
What is the `COLLECT_GCC_OPTIONS` environment variable? [It is](https://gcc.gnu.org/ml/gcc-help/2013-05/msg00093.html) an environment variable set by `gcc` before calling out to `cc1`, over which it communicates flags to `cc1`. Most (if not all?) flags given to gcc will make it into this variable. So it can grow very big (easily larger than the 128 KB limit, especially on nix).
Note that even flags given in a "response file" via `gcc @myresponsefile.rsp` (which was designed to pass GCC flags via a file instead of command line args to circumvent command line arg limits) will be put into `COLLECT_GCC_OPTIONS` by `gcc` itself to communicate them to `cc1` (I have just confirmed that with a small example on my Ubuntu 16.04). So using `@myresponsefile.rsp` is _not_ a workaround. (Yes, this seems to defeat the purpose of response files, but I suspect those were originally made to circumvent a much smaller limit of command line argument on Windows, where the limit is well below the 128 KB limit for environment variable lengths on Linux).
---
Aside: nix inflates the number of `-L` flags by the fact that each `-L` option to gcc is present multiple times, but those duplicates make only for factor 4x or so; even if they were deduplicated, I'd already be at half of [`MAX_ARG_STRLEN`](https://unix.stackexchange.com/questions/120642/what-defines-the-maximum-size-for-a-command-single-argument/120842#120842) with my medium-size Haskell project; so if I added a couple more dependencies to my Haskell project (all _recursive_ nix Haskell dependencies make it as `-L` options into the gcc command line), I'd quickly exceed that limit again even without duplication.
---
### Problems to fix
1. Deduplicating the `-L` flags passed to GCC will help the issue by a small constant factor and make a couple more projects compile, but won't help with projects with many dependencies.
2. The fundamental issue seems to be a GCC problem (its way of passing arbitrarily sized information via environment variables to a direct child program doesn't work), so technically it's not nix's department. But we need to do something about it, because otherwise we can't build large Haskell projects (on nix or otherwise).
### Steps to reproduce
* Build a Haskell project with lots of dependencies on nixpkgs 18.03.
* **update:** and lots of native C dependencies, and lots of `executable` sections in the cabal file, see [comment](https://github.com/NixOS/nixpkgs/issues/41340#issuecomment-393887066) below
## Environment
* on top of nixpkgs commit a0b977bdb461a756047adb1dcbb70d7c106507da; tested on both NixOS and Ubuntu 16.04
Here is a flake to reproduce the issue:
{
inputs = {
nix-ros-overlay.url = "github:lopsided98/nix-ros-overlay/master";
nixpkgs.follows = "nix-ros-overlay/nixpkgs"; # IMPORTANT!!!
};
outputs = { self, nix-ros-overlay, nixpkgs }:
nix-ros-overlay.inputs.flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs {
inherit system;
overlays = [ nix-ros-overlay.overlays.default ];
};
llvm = pkgs.llvmPackages_latest;
clangStdenv = llvm.stdenv;
jazzy = pkgs.rosPackages.jazzy.overrideScope (rosSelf: rosSuper:
let
buildRosPackageClang = rosSelf.buildRosPackage.override {
stdenv = clangStdenv;
};
in pkgs.lib.mapAttrs (_: package: (package.override {
buildRosPackage = buildRosPackageClang;
}).overrideAttrs ({
propagatedBuildInputs ? [],
...
} : {
propagatedBuildInputs = propagatedBuildInputs ++ [ llvm.openmp ];
})) {
inherit (rosSuper)
nav2-bringup
;
});
in {
devShells.default = pkgs.mkShell.override {
stdenv = clangStdenv;
} {
name = "argument-list-too-long";
packages = with pkgs; [
(with jazzy; buildEnv {
paths = [
nav2-bringup
];
})
];
};
});
nixConfig = {
extra-substituters = [
"https://cache.nixos.org"
"https://ros.cachix.org"
];
extra-trusted-public-keys = [
"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
"ros.cachix.org-1:dSyZxI8geDCJrwgvCOHDoAfOm5sV1wCPjBkKL+38Rvo="
];
};
}
note that the issue does not happen if stdenv = clangStdenv is not included.
This is because of the following:
This causes -fmacro-prefix-map= to be spammed a ton, massively inflating the size of the NIX_CFLAGS_COMPILE environment variable. In my case, I’m seeing a NIX_CFLAGS_COMPILE that is 182667 characters long, which is ABSURDLY huge.
This is in addition to the fact that every added include directory is duplicated 4 times. (NixOS/nixpkgs#364984 , lopsided98/nix-ros-overlay#544 )
Another environment variable significantly contributing to this is NIX_LDFLAGS. For me, that environment variable is 74514 characters log, with everything duplicated 6x.
For the NIX_CFLAGS_COMPILE environment variable, from what I can tell, the issue essentially boils down to the ccWrapper_addCVars hook being called 4 times, twice for envHostHostHook and twice for envHostTargetHook.
And for NIX_LDFLAGS, it gets called 6 times, three times for envHostHostHook and three times for envHostTargetHook.
Not sure why they’re being called multiple times however. I’d guess it has something to do with in _addToEnv:
# Set the relevant environment variables to point to the build inputs
# found above.
#
# These `depOffset`s, beyond indexing the arrays, also tell the env
# hook what sort of dependency (ignoring propagatedness) is being
# passed to the env hook. In a real language, we'd append a closure
# with this information to the relevant env hook array, but bash
# doesn't have closures, so it's easier to just pass this in.
_addToEnv() {
local depHostOffset depTargetOffset
local pkg
for depHostOffset in "${allPlatOffsets[@]}"; do
local hookVar="${pkgHookVarVars[depHostOffset + 1]}"
local pkgsVar="${pkgAccumVarVars[depHostOffset + 1]}"
for depTargetOffset in "${allPlatOffsets[@]}"; do
(( depHostOffset <= depTargetOffset )) || continue
local hookRef="${hookVar}[$depTargetOffset - $depHostOffset]"
if [[ -z "${strictDeps-}" ]]; then
This file has been truncated. show original
Is my understanding of the issue here correct, or is there something I’m missing? I’m not too familiar with nix, so I could very well be wrong about what it’s doing.
And if this is the cause, I could PR a ‘hack’ to fix this by just scanning the existing env variable for any copies of it and if they exist. would such a PR be accepted?
however, IMO, the real fix for this would be to
store NIX_CFLAGS_COMPILE and NIX_LDFLAGS in a file rather than an environment variable, and then read from this file in the cc/ld wrappers. (though, to a degree this is also just kinda pushing it down the road for GCC a bit)
figure out why the hooks are getting called multiple times, and have them not do that.