nix-shell介绍 @
今天又学了一点新东西,nix-shell 是 Nix 包管理器提供的一个强大的开发环境工具,它可以让你在不影响系统环境的情况下,使用特定版本的工具和依赖。
最开始我以为nix-shell是类似沙箱一样的东西,结果并不是,它只是创建一个新的shell,然后将你需要的软件及依赖注入到shell中,但实际上并没有将其真正安装到你的系统上。用完退出此shell,并不会影响你现有的操作环境,对于系统洁癖症患者真的太好了!
先简单介绍下基础用法
# 使用旧的语法 (nix 2.3 之前)
nix-shell -p python3
# 使用新的语法 (nix 2.4+ 推荐)
nix shell nixpkgs#python3
# 进入一个包含多个包的环境
nix shell nixpkgs#python3 nixpkgs#go nixpkgs#nodejs
# 指定特定的 Nixpkgs 频道
nix shell github:NixOS/nixpkgs#python310
# 在 shell 中执行命令
nix shell nixpkgs#python3 -c python --version
举个简单的例子,我作为golang后端开发者,以前在公司编译老项目,需要使用go1.18去编译,但我自己系统的go版本早就升级到了1.26,最早我是使用go install来管理多个go版本,意味着在我的系统中同时存在多个go版本的二进制,且都会被添加到系统path。
# 安装某个版本的go
go install -v golang.org/dl/go1.20.7@latest
go1.20.7 download # Go放在~/sdk/go1.20.7目录下
# download完成后, 会在go/bin下多一个带版本的go二进制,可以这样使用
go1.20.7 build main.go
可以看出上述用法其实也是很麻烦,而现在使用nixos系统,就简单多了,我可以很方便的使用nix shell来创建一个对应版本的go环境。
# 指定github:NixOS/nixpkgs/nixos-22.11的作用是只有nixos-22.11版本的源才存在go1.18
nix shell github:NixOS/nixpkgs/nixos-22.11#go_1_18
进入环境后,可以直接使用go1.18来编译项目,完成后exit不会对现有系统环境产生任何影响。
flake配置优化 @
此前的flake目录文件太混乱,没有任何目录结构,因此最近优化了下。
├── flake.nix # Flake 入口
├── flake.lock # 依赖锁定文件
├── hosts/
│ └── default/
│ ├── default.nix # 系统配置
│ └── hardware.nix # 硬件配置
└── home/
├── default.nix # 用户配置入口(packages + imports)
├── git.nix # git 配置
├── zsh.nix # zsh + p10k 配置
├── nvchad.nix # nvchad 配置
└── p10k.zsh # p10k 主题文件
具体则是将之前的git、zsh、nvchad相关配置拆分为多个文件来维护,然后再default.nix中import。然后在flake.nix中引用default.nix即可,后续会介绍import。
nix相关语法的粗浅理解 @
Nix 是一个纯函数式的包管理器,理解它的核心概念对使用 NixOS 至关重要。目前我还没有专门看过nix语法相关的东西,但也学习到一些概念。
下面介绍下flake.nix入口文件的核心概念,input和output。
input
简单来说,inputs主要包含你要从外面下载、依赖的东西,例如nixpkgs、home-manager、github等等,而outputs则是指你用这些依赖构建出来的结果,例如系统、home 配置、软件包等等
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
claude-code.url = "github:sadjow/claude-code-nix";
home-manager = {
url = "github:nix-community/home-manager";
inputs.nixpkgs.follows = "nixpkgs";
};
nix4nvchad = {
url = "github:nix-community/nix4nvchad";
inputs.nixpkgs.follows = "nixpkgs";
};
};
例如上例的input配置,说明我需要依赖从github下载的nixpkgs、claude-code、home-manager、nix4nvchad模块。运行时,Nix 会把它们全部下载到 /nix/store,并生成 flake.lock 锁定版本。
output
output的基础格式可以用一个很简单的语法来描述。
outputs = { 我要用哪些inputs }: {
我要输出什么东西
};
一般来说,在input中出现的模块,都是需要在outputs中引用的,否则下载下来干嘛呢。。而输出的内容基本就是你的用户环境,比如你的用户配置、软件包等等
下面介绍一份output的配置内容
outputs = { self, nixpkgs, home-manager, nix4nvchad, claude-code, ... }@inputs:
let
system = "x86_64-linux";
pkgs = import nixpkgs {
inherit system;
config = {
allowUnfree = true;
};
overlays = [
claude-code.overlays.default
];
};
in
{
nixosConfigurations.nixos = nixpkgs.lib.nixosSystem {
inherit system;
inherit pkgs;
modules = [
./hosts/default/hardware.nix
./hosts/default/default.nix
home-manager.nixosModules.home-manager {
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.sharedModules = [
inputs.nix4nvchad.homeManagerModules.default
];
home-manager.users.lznauy = import ./home/default.nix;
}
];
specialArgs = { inherit inputs; };
};
};
第一行的output就是一个函数定义,而{ self, nixpkgs, ... }@inputs 则是函数对应的参数,@inputs 表示把所有依赖打包成一个集合,叫inputs。
第二行的let ... in 是 Nix 中用于定义局部变量的语法,这里定义了 system、pkgs 等局部变量。
下面的{ ... } 是函数的主体,这里定义了 nixosConfigurations.nixos 这个输出,作用是输出一个叫 “nixos” 的 NixOS 系统配置。
inherit system; inherit pkgs; 的意思则是把外面定义的 system、pkgs 变量,传给 nixosSystem 当参数,所以下面的modules和specialArgs也是参数。你可能会疑惑,你怎么知道这几个是参数呢?由于目前没有对应的文档,只能从nixpkgs的flake.nix
源码中获得下列信息。
Create a NixOS system configuration.
Example:
lib.nixosSystem {
modules = [ ./configuration.nix ];
}
Inputs:
- `modules` (list of paths or inline modules): The NixOS modules to include in the system configuration.
- `specialArgs` (attribute set): Extra arguments to pass to all modules, that are available in `imports` but can not be extended or overridden by the `modules`.
- `modulesLocation` (path): A default location for modules that aren't passed by path, used for error messages.
Legacy inputs:
- `system`: Legacy alias for `nixpkgs.hostPlatform`, but this is already set in the generated `hardware-configuration.nix`, included by `configuration.nix`.
- `pkgs`: Legacy alias for `nixpkgs.pkgs`; use `nixpkgs.pkgs` and `nixosModules.readOnlyPkgs` instead.
这段源码注释告诉我们,它的参数有modules、specialArgs、modulesLocation, 而system和pkgs是被废弃的字段, 未来可能彻底移除,所以更现代的方式是如下写法,而pkgs和system则不需要传递了。
outputs = { self, nixpkgs, home-manager, nix4nvchad, claude-code, ... }@inputs:
{
nixosConfigurations.nixos = nixpkgs.lib.nixosSystem {
modules = [
# 匿名函数 { ... }: { } 的意思是 参数 { ... },返回 { }
({ ... }: {
nixpkgs.hostPlatform = "x86_64-linux";
nixpkgs.config.allowUnfree = true;
nixpkgs.overlays = [
claude-code.overlays.default
];
})
# 路径
./hosts/default/hardware.nix
./hosts/default/default.nix
# 函数调用,形式为func {...},其中{...}是传递给函数的参数
home-manager.nixosModules.home-manager {
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.sharedModules = [
inputs.nix4nvchad.homeManagerModules.default
];
home-manager.users.lznauy = import ./home/default.nix;
}
];
specialArgs = { inherit inputs; };
};
};
import 语句 @
import 用于引入外部 Nix 文件,借助import,我们可以将之前的git、zsh、nvchad相关配置拆分为多个文件来维护,然后再default.nix中import。
# default.nix
imports = [
./git.nix
./zsh.nix
./nvchad.nix
];
mcp-nixos介绍 @
mcp-nixos 是专门为 NixOS 提供的 MCP 服务,由于nixos相关文档很少,很多东西需要看源码,之前也尝试问过AI,但它经常给我瞎编一些内容,压根就是nix不存在的语法或者配置,因此使用该mcp能让AI更加聪明点。
安装只需要在home.packages中添加mcp-nixos即可 (如果你使用home-manager的话)
home.packages = with pkgs; [
mcp-nixos
];
然后就是配置你的mcp,例如我的opencode,只需要在当前项目目录添加opencode.json,然后填写下述信息即可使用该mcp。
{
"$schema": "https://opencode.ai/config.schema.json",
"mcp": {
"nixos": {
"type": "local",
"command": ["mcp-nixos"],
"enabled": true
}
}
}
内容总结 @
主要了解下nix shell的使用,还有flake.nix的概念,以及一些简单的语法,并且介绍了下mcp-nixos使用,同时优化下之前的配置结构。