目录

针对linux 依赖问题的解决方案和个人对 linux distro 的看法

1 前言

对于经常使用计算机工作的人来将( 特别是程序员 ), 随着工作时间的推移和内容的延伸, 经常面临大量的文件需要管理的情况. 一个经常面临的问题是: 若果某个文件出现了异常, 如何快速方便地回退到之前的版本. 通常而言 office 和 git 等工具可以满足这些需求.

那么对于软件呢, 如果出现了 A 依赖 B , C 也依赖 B ,B 升级到新版 B1 ,假设 A 更新比较快也升级到 A1 ,但是 C 的开发比较慢,B1 下无法工作,这时怎么办?另一个更常见的问题是, A 依赖于B2, C 依赖于 B1, 彼此互不兼容, 虽然可以通过手动修改环境变量等方法可以绕开问题, 但比较混乱且治标不治本.

极端情况下,如果 B 是 linux 内核呢?

在此, 我想介绍linux 上能一劳永逸解决这些问题的方案: Guix 或者 Nix. 本文会讨论不同 linux distro 的特点及在这个问题上的解决. 最后给出为什么我认为Guix 的解决方案是 真正省心和有效 的.

2 Linux distribution

因个人倾向于实用性也就是快速解决实际问题, 所以在此不讨论UI 美观或者默认 package 等优化的问题, 仅讨论这些 dirstro 对于实际生产和生活的效率影响.

对大多数程序员来讲, 日常工作也就一个编辑器, 一个命令行,一个浏览器. 我个人也不喜欢在环境外观上花费太多时间, 仅在乎在生产和工作中的效率和实用性, 也就是 快速完成工作.

2.1 Ubuntu

大家最熟悉的可能是 Ubuntu, 这套 Debian 系的distro, 易于安装易于部署, 作为生产环境而言稳定可靠. 我至今也仍有使用Debian 系的生产环境, 特别是其在驱动方面的广泛适配非常省心.

但作为个人工作电脑而言, Ubuntu 有着一些缺点, 比如系统版本升级麻烦, 包管理不方便等. 而且 Ubuntu 对于上述问题, 只能选择一个版本装, 不然会引起互相冲突.

2.2 Arch

在多次遇到Ubuntu 著名的 “内部错误” 后, 我转向了 Archlinux, 一个滚动管理的 distro. 不得不说, archlinux 是一款从用户角度出发的系统, 极大地提升了工作和学习效率, 我使用了几年的 archlinux , 仍非常满意. 它有几个优点:

  • 完全的滚动升级, 其持续的更新体验会让你始终使用最新的系统和软件包.
  • 强大的社区基因. Arch wiki 可能是目前最强大 linux wiki 系统, 你遇到的绝大数linux 问题和知识都可以在这里获取, 不管你是否使用 arch, 这里都会大大帮助你的 linux 体验.
  • 近乎全能的包管理. Aur 上拥有着近乎所有工作中可能需要的 package, 数量远比其他 dirtro 多. 通常情况下一条 yay -S package 就可以一键式安装你需要的 package 及其依赖, 非成省心.

当然, arch 也有一些缺点:

  • 安装繁琐, arch 的安装不像 Ubuntu 等通过简单的图形化界面快速安装, 而是需要用户在命令行上输入大堆指令来推动系统的安装, 流程繁琐, 但保证了对系统的完全掌控.
  • 滚动升级带来的环境不稳定性, 如果遇到这种情况往往需要手动处理, 这对用户的水平有一些要求. 但长期使用并没有遇到滚挂的情况.

回到版本依赖的问题上, Arch一般在打包过程时把产物文件重命名一下, 避免相互冲突, 然后依赖这个软件包的包在这个改好的PKGBUILD的基础上重新打包. 但如果件依赖十分复杂, 得自己重新打一堆包, 就特别麻烦.

3 Guix 介绍

Guix/Nix的机制可以很好的解决依赖问题. 他们的软件实际在一个用sha256和文件名做区分的store里, 然后symlink出来一个软件包的集合(叫profile), 这样相同软件的不同版本可以很简单的互存. 那么他们的原理是什么呢?

3.1 GNU 项目与 linux

在介绍 Guix 之前, 我需要先介绍一些 Guix 的历史背景, 因为这些背景可以帮助我们理解 Guix 系统的特点和设计理念.

Richard Matthew Stallman(RMS)在1983年9月27日公开发起了GNU 计划,它的目标是创建一套完全自由的操作系统, 后来又创立了自由软件基金会(Free Software Foundation)来为GNU计划提供技术、法律以及财政支持.

RMS 为GNU 计划写的第一个产物便是著名的GCC 编译器. 接着又开发出了 emacs 和大部分 UNIX 系统的程序库, 并提出了 GPL 协议, 到1990 年, 唯一依然没有完成的重要组件, 就是操作系统的内核.

1991年, Linus编写出了与UNIX兼容的Linux操作系统内核并在GPL条款下发布. 1992年,Linux与其他GNU软件结合, 大家熟悉的"GNU/Linux" 或简称Linux 诞生了。

但 Linux 包含了许多非自由的成分( 比如驱动等 ), 因此GNU 项目一直在试图推出一个完整的自由系统. Guix 便是这种初衷下的产物, 这也意味着 Guix 是 百分之百自由 的.

3.2 函数与可复现

Guix/Nix 提供了一个函数式语言来描述软件包, 每一个软件包是一个表达式. 进一步地:

  1. 表达式可以求值, 那么求值结果可以看做一个软件包, 值不同则代表包不同.
  2. 如果更改包的版本, 依赖等, 则会改变表达式的值, 那么就得到了不同的包. 比如 libaaa1.2 和 libaaa1.3 虽然是同一个包的不同版本, 但通过表达式的方案, 会被看做两个不同的包.

有了这两点, 系统上可以派生出很多不同版本的 libaaa, 其他的包可以依赖不同的 libaaa, 因为这些 libaaa 在表达式的层面是不同的包, 因此可以共存.

这种方法还带来了一个优点, 就是干净, 比如一个 hello 的package

(use-modules (guix)
             (guix build-system gnu)
             (guix licenses))

(package
  (name "hello")
  (version "2.10")
  (source (origin
            (method url-fetch)
            (uri (string-append "mirror://gnu/hello/hello-" version
                                ".tar.gz"))
            (sha256
             (base32
              "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i"))))
  (build-system gnu-build-system)
  (synopsis "Hello, GNU world: An example GNU package")
  (description "Guess what GNU Hello prints!")
  (home-page "http://www.gnu.org/software/hello/")
  (license gpl3+))

描述了所需要的所有信息. 系统每次启动只会读取这些表达式, 因此不管你手动安装了多少包, 只要你没有修改 config 文件, 再进入系统都只有这些 config 里表达式的包.

3.3 Guix 优点

相比其他 linux distro, guix 有以下优点:

  • 函数式声明的方案从根本上彻底解决了依赖问题.
  • 整个系统就是一个声明式的系统, 只要备份好 configuration, 就可以随时拷贝配置文件在新设备上生成一个一样的系统, 因此强大的可复现性和统一性.
  • 原子级的系统回滚和控制. 如果更新遇到了任何问题, 总是可以执行原子级的快速回退, 这带来了强大的系统稳定新, 并节省大量时间
  • 完全可编程的系统. 对整个系统进行编程并处于版本控制之下, 这些都很容易做到.
  • 使用Scheme, 1975 年诞生于 MIT 的语言, 遵循极简主义哲学,以一个小型语言核心作为标准, 简洁强大, 也是我个人非常喜欢的语言.

3.4 Guix 缺点

  • 正如背景所述, Guix 是一个完全 GPL 协议的系统, 没有 non-free software. 用户在安装时往往需要 手动修改系统内核解决驱动 等问题, 对于新手使用者较为困难.
  • 占用空间较大.

4 结论

如果对linux 并不熟悉或者是用于部署工业生产环境, 我仍然建议使用 Debain 系或者直接使用 Ubuntu, 生产环境往往长期不变且更新需求小. 如果刚进阶或者希望能够快速进入工作, 我推荐使用 arch, 包罗万象的包管理和强大的wiki 是你最好的帮手.

如果能接受 Guix 的高门槛, 毫无疑问这是一个非常理想的个人操作系统, 完全可控, 稳定, 可复现, 兼容性好, 能够满足日常工作和生活的各种需求. 使用了 Guix 后, 可以把和版本管理相关的包( 比如, python 版本的 conda 或者 virenv 等, 甚至 gcc 的管理等) 都去除, 统一归到系统级别进行处理.