技术栈:nix-shell + uv + direnv
主要问题:Python 编译问题;matplotlib 作图问题。
shell.nix 配置示例#
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell{
buildInputs = with pkgs; [
(python312.withPackages (ps: with ps; [
matplotlib
pyqt5 # Qt5Agg 所需 Python binding
]))
qt5.qtwayland
qt5.qtbase
uv
];
shellHook = ''
export LD_LIBRARY_PATH=${pkgs.lib.makeLibraryPath [
pkgs.stdenv.cc.cc.lib
pkgs.zlib
pkgs.libGL
pkgs.qt5.qtbase
pkgs.glib
]}
export MPLBACKEND=Qt5Agg
export QT_PLUGIN_PATH=${pkgs.qt5.qtbase}/${pkgs.qt5.qtbase.qtPluginPrefix}
export QT_QPA_PLATFORM_PLUGIN_PATH=${pkgs.qt5.qtbase}/${pkgs.qt5.qtbase.qtPluginPrefix}/platforms
'';
}如需在代码中覆盖后端,应在导入 pyplot 之前指定;已设置 MPLBACKEND 时不必重复:
import matplotlib
matplotlib.use("Qt5Agg")
import matplotlib.pyplot as plt查找缺失依赖的方法#
1. nix-locate(按 .so 文件名反查包名)
nix-locate --whole-name libgthread-2.0.so.0需要先装 nix-index 并建立索引:nix-index(第一次运行要几分钟)。
2. nixpkgs 网站搜索
包搜索主要检索软件包元数据,不是完整文件索引;知道候选包名后在这里确认属性:search.nixos.org
3. ldd 诊断 PyPI 包依赖
仅对可信二进制使用 ldd;对不可信文件先用 readelf -d 或 objdump -p 静态查看依赖。路径随 Python 和 PyQt 版本变化。
ldd .venv/lib/python3.12/site-packages/PyQt5/QtWidgets.so | grep "not found"一次性列出所有缺失的 .so,再用 nix-locate 批量查。
推荐流程:ldd 找全缺失库 → nix-locate 查包名 → 一次性加进 shell.nix
阶段性总结(2026-04-08)#
此记录中的核心问题是 PyPI wheel、Qt 插件和 Nix 提供的系统库混合后,搜索路径与 ABI 不一致;这不是 uv 与 Nix 必然冲突。
- uv 的设计哲学:通常把 Python 依赖解析并安装到
.venv;带原生扩展的 wheel 仍可能依赖环境提供的系统库。 - nix 的设计哲学:所有依赖在 nix store(
/nix/store/…),不在标准系统路径。
在纯 Python 包上没有冲突,但 matplotlib+Qt 链需要系统库:
matplotlib (PyPI)
└── PyQt5
└── libQt5XcbQpa.so (Qt 运行时)
└── libqxcb.so (platform plugin)
└── libxcb, libX11, libxkbcommon…(全在 nix store)踩到的坑:
- PyPI 的 PyQt5 自带 platform plugin,但缺几乎所有 X11 库
- 加进
LD_LIBRARY_PATH后版本不匹配,出现undefined symbol - 把 PyQt5 移入 nix 管理,但 uv 的
.venv覆盖了 PATH - 用
--python $(which python3)指定 nix 的 python,但 matplotlib 还在 venv 里
这份排错记录采用的收敛方案:把 matplotlib、PyQt 和 Qt5 系统库交给同一 Nixpkgs 管理,降低 ABI 混用。uv 也能用于含原生依赖的项目,但需要正确的动态库环境、wheel 兼容性与 Python 路径策略;不能仅靠全局叠加 LD_LIBRARY_PATH。
版本与两套依赖路径#
本篇保留 2026-04-08 记录里的 Python 3.12 / Qt5 示例;后端、插件路径和包属性以所用版本为准。纯 withPackages 路线直接使用该 Python;若另建 uv 虚拟环境,要明确哪些包来自 PyPI、哪些系统库来自 Nix,必要时设计 --system-site-packages,而不是让两套 Qt/PyQt 混在搜索路径里。nix-locate 查询前要建立或取得适配系统的文件索引。
参考与延伸
根据技术笔记重新整理,示例使用通用名称。