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). 不过我没跑过, 有兴趣可以试试.