TLDR
If you’re using a nix shell on macOS / darwin, and installing a Python package that has C++ extensions, then it may not compile because of missing shared standard / framework libraries. This is because Python confusingly uses clang
instead of clang++
to compile C++ extensions, and Nix doesn’t include C++ standard libraries in the clang
wrapper by default. To fix it, you can adjust your shell.nix
like this:
{ pkgs ? import <nixpkgs> {}}:
with pkgs; mkShell {
# Include C++ headers for regular clang calls:
NIX_CFLAGS_COMPILE = lib.optionals stdenv.isDarwin [
"-I${lib.getDev libcxx}/include/c++/v1"
];
nativeBuildInputs = [
...
] ++ lib.optionals stdenv.isDarwin [
# Add any Apple framework libraries your package needs, e.g.
darwin.apple_sdk.frameworks.IOKit
];
}
Longer story
I ran into an issue that chewed up a couple hours of my time yesterday, and figured I’d drop the solution here in case anyone else would find it useful. I use direnv with nix shells to create automatic virtual environments for my Python projects along with some other dependencies from nixpkgs. Yesterday, I went to upgrade a few packages and ran into a weird error with ddtrace==1.9.3
, which recently introduced a C++ extension:
clang -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -I/nix/store/4vfgllzm4wgpl5vf50zakd89l1gdx5jm-libxcrypt-4.4.33/include -I/usr/local/opt/openssl/include -I/Users/johnwhitman/projects/api.galileo.io/.direnv/python-3.10.10/include -I/nix/store/jx137r213yrklvvqd83dhhk01n671pas-python3-3.10.10/include/python3.10 -c ddtrace/appsec/iast/_taint_tracking/_taint_tracking.cpp -o /var/folders/3v/nn4ctvl12sl768gct5vt199h0000gn/T/tmp81l5u6lg.build-temp/ddtrace/appsec/iast/_taint_tracking/_taint_tracking.o -std=c++17
clang-11: warning: argument unused during compilation: '-fno-strict-overflow' [-Wunused-command-line-argument]
ddtrace/appsec/iast/_taint_tracking/_taint_tracking.cpp:2:10: fatal error: 'iostream' file not found
#include <iostream>
^~~~~~~~~~
1 error generated.
I noticed it was using clang
instead of clang++
to compile the source. That lead me to NixOS/nixpkgs#26531, which points out that Python confusingly uses cc
to compile C++ (ref unixcompiler.py). Another comment in that thread provides the following hint, which leads to the first fix for missing iostream
:
To hack around this problem you simply have to grep the pythonPackages for libcxx.
Sure enough, you can find a few examples of workarounds, like this one from kiwisolver
to override some compile flags:
NIX_CFLAGS_COMPILE = lib.optionals stdenv.isDarwin [
"-I${lib.getDev libcxx}/include/c++/v1"
];
Another attempt to install the package got further, but failed with an error about IOKit/IOKitLib.h
missing:
ddtrace/vendor/psutil/_psutil_osx.c:37:10: fatal error: 'IOKit/IOKitLib.h' file not found
#include <IOKit/IOKitLib.h>
^~~~~~~~~~~~~~~~~~
1 error generated.
This is apparently an Apple framework library that isn’t available in the shell’s sandbox by default, so you simply have to include that as an input in your shell (StackOverflow ref):
nativeBuildInputs = [
...
] ++ lib.optionals stdenv.isDarwin [
# Add any Apple framework libraries your package needs, e.g.
darwin.apple_sdk.frameworks.IOKit
];
Hope this saves somebody else some time in the future.