I recently posted a question related to a problem I am having with running a bigger build system in nix-shell (link), but I think the question was too specific and not very approachable. So I built a small, very basic C++ build (two g++ invocations) that reproduces the problem.
Here it is, I would like to be able to run this script inside a nix-shell:
#!/usr/bin/env bash
set -u
set -o pipefail
cat > tmp.cpp << EOF
#include <iostream>
void test_tmp() {
std::cout << "test_tmp\n";
}
EOF
g++ -o shared.so -shared -fPIC -x c++ tmp.cpp - << EOF
#include <iostream>
void test() {
std::cout << "test\n";
}
EOF
if [ $? -eq 0 ]
then
echo "shared worked!"
else
echo "shared FAILED!"
fi
g++ -o static -static -x c++ - << EOF
#include <iostream>
int main() {
std::cout << "Hello World!\n";
}
EOF
if [ $? -eq 0 ]
then
echo "static worked!"
else
echo "static FAILED!"
fi
In summary, this script links two source files into a shared library shared.so
, and then compiles a simple “Hello World”-program into a static binary static
.
Sanity check, to make sure this issue is actually related to nix/nixos:
$ docker run --rm -ti -v "$(pwd)":/test ubuntu:20.04 bash -c "apt update && apt install g++ && cd /test && ./build.sh"
[...snipped apt output...]
shared worked!
static worked!
So this small script runs fine on a non-nix(os) linux.
Ok, now to the actual problem, and the different shell.nix
s I have tried to make it work.
Attempt #1, a basic shell.nix
:
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
nativeBuildInputs = with pkgs; [
gcc
];
}
With result:
$ nix-shell --pure
[nix-shell]$ ./build.sh
shared worked!
/nix/store/vfqlryhvm8063hs7ax9k2vb8wmch5v0v-binutils-2.31.1/bin/ld: cannot find -lm
/nix/store/vfqlryhvm8063hs7ax9k2vb8wmch5v0v-binutils-2.31.1/bin/ld: cannot find -lc
collect2: error: ld returned 1 exit status
static FAILED!
Ok, so no static libraries available by default, but there is glibc.static
, which provides them.
Attempt #2:
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
nativeBuildInputs = with pkgs; [
gcc
glibc.static
];
}
And output:
$ nix-shell --pure
[nix-shell]$ ./build.sh
/nix/store/vfqlryhvm8063hs7ax9k2vb8wmch5v0v-binutils-2.31.1/bin/ld: /nix/store/zxcqmz6sah8h9qqy4w7kknlbkd2m6d0p-glibc-2.31-74-static/lib/libc.a(dl-trampoline.o): relocation R_X86_64_PC32 against symbol `_dl_x86_cpu_features' can not be used when making a shared object; recompile with -fPIC
/nix/store/vfqlryhvm8063hs7ax9k2vb8wmch5v0v-binutils-2.31.1/bin/ld: final link failed: bad value
collect2: error: ld returned 1 exit status
shared FAILED!
static worked!
So with glibc.static
, the static build works, but the shared build fails.
Maybe glibc.static
overrides the shared glibc
, and this is not available anymore? If so, how about including both?
Attempt #3:
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
nativeBuildInputs = with pkgs; [
gcc
glibc.static
glibc
];
}
And output:
$ nix-shell --pure
[nix-shell]$ ./build.sh
In file included from /nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/include/c++/9.3.0/ext/string_conversions.h:41,
from /nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/include/c++/9.3.0/bits/basic_string.h:6493,
from /nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/include/c++/9.3.0/string:55,
from /nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/include/c++/9.3.0/bits/locale_classes.h:40,
from /nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/include/c++/9.3.0/bits/ios_base.h:41,
from /nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/include/c++/9.3.0/ios:42,
from /nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/include/c++/9.3.0/ostream:38,
from /nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/include/c++/9.3.0/iostream:39,
from tmp.cpp:1:
/nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/include/c++/9.3.0/cstdlib:75:15: fatal error: stdlib.h: No such file or directory
75 | #include_next <stdlib.h>
| ^~~~~~~~~~
compilation terminated.
In file included from /nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/include/c++/9.3.0/ext/string_conversions.h:41,
from /nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/include/c++/9.3.0/bits/basic_string.h:6493,
from /nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/include/c++/9.3.0/string:55,
from /nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/include/c++/9.3.0/bits/locale_classes.h:40,
from /nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/include/c++/9.3.0/bits/ios_base.h:41,
from /nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/include/c++/9.3.0/ios:42,
from /nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/include/c++/9.3.0/ostream:38,
from /nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/include/c++/9.3.0/iostream:39,
from <stdin>:1:
/nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/include/c++/9.3.0/cstdlib:75:15: fatal error: stdlib.h: No such file or directory
75 | #include_next <stdlib.h>
| ^~~~~~~~~~
compilation terminated.
shared FAILED!
In file included from /nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/include/c++/9.3.0/ext/string_conversions.h:41,
from /nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/include/c++/9.3.0/bits/basic_string.h:6493,
from /nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/include/c++/9.3.0/string:55,
from /nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/include/c++/9.3.0/bits/locale_classes.h:40,
from /nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/include/c++/9.3.0/bits/ios_base.h:41,
from /nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/include/c++/9.3.0/ios:42,
from /nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/include/c++/9.3.0/ostream:38,
from /nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/include/c++/9.3.0/iostream:39,
from <stdin>:1:
/nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/include/c++/9.3.0/cstdlib:75:15: fatal error: stdlib.h: No such file or directory
75 | #include_next <stdlib.h>
| ^~~~~~~~~~
compilation terminated.
static FAILED!
Boom. Now both fail, and with pretty evil errors. Googling them turns up this related issue: ardour: fix build with gcc6 by disassembler · Pull Request #28748 · NixOS/nixpkgs · GitHub
The fix for that issue was to remove glibc
from the buildInputs
. However, this means that I’m back to the stage where either only shared linking or only static linking works (Attempt #1 or #2, depending on whether glibc.static
is added to the buildInputs
).
At this point I’m rather lost, and don’t really know how to continue, and neither do I know much about nix’ internals and how, i.e., the gcc-wrapper works. What am I doing wrong/am I missing/could I try?