HydroOJ 从入门到入土(10) 配置 nix 支配下的 Python 环境
官网已经更新了在线生成数据的功能, 方便不少, 如果能用我习惯用的 cyaron 数据生成器就好了. 但 nix 作为 Hydro 的安全沙箱, 隔离性做的太好, 以至于跟 Python 这种喜爱全局安装包的编译器天生八字不合, 用 nix 安装 Python 包, 大坑套小坑, 这里记录一下解决的几种方法.
1. 基本方法
参考官网faq: 15. 在沙箱中引入 Python 包, 基本思想是先用 nix-env 安装一个包, 如果不行的话, 就尝试找出这个包的所在位置, 然后手动添加到运行环境中. 可以用, 但是比较麻烦.
而且, 我在尝试安装cyaron的时候, 发现无法通过 nix-shell -p xxx 的方法加载 cyaron, 试了好多都出错, 不知道中间该填什么.
最后还是用 ls -alh /nix/store/ | grep cyaron 手动筛出了cyaron的真实地址.
2. 不需要处理 PATH 的方法
以下以 Python3.11 为例.
根据第一种方法, 会发现有的包, 比如numpy, 装完就可以直接用, 但是有的就不行, 比如pandas.
经过进一步探究, 发现使用nix-env -iA nixpkgs.python311Packages.xxxxx这种方式安装的包, 是直接将包装到/nix/store/里, 然后再把包中的xxx/lib/python3.11/site-packages里边所有的库写一个软链接到 ~/.nix-profile/lib/python3.11/site-packages 这个位置, 所以 numpy 和 pandas 其实装完都在这个环境里.
但用nix-env -iA安装的时候, 自动安装的那些依赖项却并不会被加进 nix 的安装列表(nix-env q查不到), 所以当然也不会被加进这个路径!
这也直接导致了 pandas 或 cyaron安装完无法使用, 只有像numpy这种单一个包的才能直接用.
明确了这个思路之后, 我就看一下某个包的依赖多不多, 如果不多的话, 就手动按顺序安装所有依赖项, 避免之后处理 path.
经过一番尝试, 幸好依赖都不多, 我成功安装了 3 个库, 并确定安装顺序如下:
2.1 numpy
一个包, 没啥依赖项, 直接装了, 重启沙箱就能用:
nix-env -iA nixpkgs.python311Packages.numpy
2.2 pandas
依赖有 5 个, 其中一个是numpy, 所以需要要在 pandas 之前安装numpy.
nix-env -iA nixpkgs.python311Packages.six
nix-env -iA nixpkgs.python311Packages.tzdata
nix-env -iA nixpkgs.python311Packages.pytz
nix-env -iA nixpkgs.python311Packages.dateutil
nix-env -iA nixpkgs.python311Packages.numpy
nix-env -iA nixpkgs.python311Packages.pandas
2.3 cyaron
这个搞了很久, 因为安装 cyaron 依赖 xeger, 但是这个包 nix 官方没找到. 这俩可能都不是 nix 官方 channel, 最后想起来 Hydro 的repo 里好像有个 nix 什么的, 果然在这里.
找到就好办了, 顺序如下:
nix-env -iA hydro.xeger
nix-env -iA hydro.cyaron
按照以上顺序安装, 可以不需要设置 path. 重启沙箱即可使用.
另外,如果 nix 提示 error: attribute 'xeger' in selection path 'hydro.xeger' not found,可以先更新一下 channel,方法在下边。
2.4 装完记得重启沙箱
pm2 restart hydro-sandbox
2.5 其他库
包很多, 想装什么, 可以在 pypi 上查好依赖, 然后手动安装. 如果装错顺序导致导入时报依赖错误, 就删掉, 换个顺序重装.
注意, 在nix-env -iA xxx的时候, 最上边会显示几行要装的东西, 含有python3.11这种的基本就是依赖项, 可以记下来.
2.6 requests
nix-env -iA nixpkgs.python311Packages.certifi
nix-env -iA nixpkgs.python311Packages.charset-normalizer
nix-env -iA nixpkgs.python311Packages.idna
nix-env -iA nixpkgs.python311Packages.pycparser
nix-env -iA nixpkgs.python311Packages.urllib3
nix-env -iA nixpkgs.python311Packages.cffi
nix-env -iA nixpkgs.python311Packages.brotlicffi
nix-env -iA nixpkgs.python311Packages.requests
3. 其他操作
更新 channel
nix-channel --update
清除不用的软件包(垃圾回收)
注意, nix-env -e 只会删除指定包, 但是仍有可能会留下一些 old generation, 所以过段时间会变得巨大, 需要使用垃圾回收清理.
nix-collect-garbage
查看<直接>安装的包的位置(绝对路径)
使用这个命令, 可以较为方便的查询出某个 Python 包的位置, 并按需加入 path. 这样就不需要使用 nix-shell -p xxx 去找了.
需要注意, 用nix-env -iA 安装的时候, 依赖不会进入nix-env -q的列表.
nix-env -q --out-path
查找 nix store 中安装的包<直接+间接>
nix 安装的所有的包都在这里. 比如要找xeger
ls -alh /nix/store/ | grep xeger
常用 nix-env 命令
| 说明 | 命令 |
|---|---|
| Searching for packages | nix search nixpkgs packagename |
| Installing a package | nix-env -iA packagename |
| List installed packages | nix-env -q |
| Uninstall packages | nix-env -e packagename |
| Upgrade packages | nix-env -u |
在 oj 外的 Linux 系统也加入Python 环境变量
oj 里边是有 PATH 变量设置的, 但是 Linux 不一定有. 如果oj 能用 numpy 但是 linux 里用不了的话, 可以手动添加一下环境变量.
vi ~/.bashrc
export PYTHONPATH=$PYTHONPATH:~/.nix-profile/lib/python3.11/site-packages
前边已经把所有的包都集中到这里来了, 所以就不用再加很多乱七八糟的 PATH 了.
其他要安装的包可以参考Hydro 主站的构建脚本
地址: https://github.com/hydro-dev/nix-channel/blob/master/judge.nix
直接跑的话, 除了吃不少磁盘空间, 其他不会有啥问题. 好像一套装齐在10G多点.(by udf). 不过我没跑过, 有兴趣可以试试.

浙公网安备 33010602011771号