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.nixs 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?