-
-
Notifications
You must be signed in to change notification settings - Fork 194
Expand file tree
/
Copy pathflake.nix
More file actions
377 lines (356 loc) · 14.3 KB
/
Copy pathflake.nix
File metadata and controls
377 lines (356 loc) · 14.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
{
description = "RootFS";
nixConfig = {
# 国内镜像优先,保留官方缓存作为回退
extra-substituters = [
"https://mirrors.tuna.tsinghua.edu.cn/nix-channels/store"
"https://mirrors.ustc.edu.cn/nix-channels/store"
];
extra-trusted-public-keys = [
"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
];
};
inputs = {
fenix = {
url = "github:nix-community/fenix";
inputs.nixpkgs.follows = "nixpkgs";
};
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11";
flake-parts.url = "github:hercules-ci/flake-parts";
treefmt-nix = {
url = "github:numtide/treefmt-nix";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs =
inputs@{
self,
nixpkgs,
fenix,
flake-parts,
treefmt-nix,
}:
flake-parts.lib.mkFlake { inherit inputs; } {
imports = [
inputs.treefmt-nix.flakeModule
];
systems = [
"x86_64-linux"
];
perSystem =
{
self',
inputs',
system,
...
}:
let
nixpkgs = inputs.nixpkgs;
fenix = inputs.fenix;
pkgs = nixpkgs.legacyPackages.${system};
lib = pkgs.lib;
rootfsType = "ext4";
buildDir = "./bin"; # Specifying temp file location
rust-toolchain-toml = builtins.fromTOML (builtins.readFile ./kernel/rust-toolchain.toml);
rust-channel-raw = rust-toolchain-toml.toolchain.channel;
rust-channel-match = builtins.match "^(stable|beta|nightly)(-([0-9]{4}-[0-9]{2}-[0-9]{2}))?$" rust-channel-raw;
rust-channel =
if rust-channel-match == null then rust-channel-raw else builtins.elemAt rust-channel-match 0;
rust-date =
if rust-channel-match == null || builtins.elemAt rust-channel-match 2 == null then
null
else
builtins.elemAt rust-channel-match 2;
rust-components-from-toml = rust-toolchain-toml.toolchain.components or [ ];
rust-required-components = [
"cargo"
"rustc"
"rust-std"
];
rust-missing-required = builtins.filter (
component: !(builtins.elem component rust-components-from-toml)
) rust-required-components;
rust-components-effective = lib.unique (rust-components-from-toml ++ rust-required-components);
rust-components-selected =
if rust-missing-required == [ ] then
rust-components-effective
else
builtins.trace "Warning: kernel/rust-toolchain.toml is missing required Rust components: ${lib.concatStringsSep ", " rust-missing-required}. DragonOS Nix build will auto-add them. Recommended: add them to kernel/rust-toolchain.toml to keep one explicit source of truth." rust-components-effective;
rust-dist-root = "https://rsproxy.cn/dist";
rust-toolchain-base = fenix.packages.${system}.toolchainOf {
root = rust-dist-root;
channel = rust-channel;
date = rust-date;
# Fixed-output hash for Rust channel metadata.
# Update this when rust-toolchain channel/date changes:
# 1) run nix develop / nix run
# 2) copy the "got: sha256-..." from mismatch error to this field
# 3) re-run nix develop and verify rustc/cargo come from rust-toolchain-wrapped/bin
sha256 = "sha256-ggvRZZFjlAlrZVjqul/f/UpU5CEhDbdKZU0OCR8Uzbc=";
};
rust-toolchain-raw = rust-toolchain-base.withComponents rust-components-selected;
rust-toolchain = pkgs.symlinkJoin {
name = "rust-toolchain-wrapped";
paths = [ rust-toolchain-raw ];
nativeBuildInputs = [ pkgs.makeWrapper ];
postBuild = ''
for bin in "$out/bin/"*; do
if [ -x "$bin" ]; then
wrapProgram "$bin" --prefix LD_LIBRARY_PATH : ${pkgs.zlib}/lib
fi
done
'';
};
testOpt = {
# 自动测试项目,指定内核启动环境变量参数 AUTO_TEST
autotest = "none"; # syscall / dunit
syscall = {
enable = true;
testDir = "/opt/gvisor";
version = "20251218";
};
dunitest = {
enable = true;
testDir = "/opt/tests/dunitest";
};
};
mkOutputs =
target:
let
diskPath = "${buildDir}/disk-image-${target}.img";
# vsock 固定配置(nix run .#start-* / .#yolo-* 生效):
# - guestCid 不能为 2(host CID)
vsockConfig = {
enable = true;
guestCid = 3;
deviceModel = "vhost-vsock-pci-non-transitional";
};
qemuScripts = import ./tools/qemu/default.nix {
inherit
lib
pkgs
testOpt
diskPath
;
# QEMU 相关参数:
# 内核位置
kernel = "${buildDir}/kernel/kernel.elf"; # TODO: make it a drv 用nix构建内核,避免指定相对目录
# 不开 GDB stub,普通启动
debug = false;
enableVsock = vsockConfig.enable;
vsockGuestCid = vsockConfig.guestCid;
vsockDeviceModel = vsockConfig.deviceModel;
# 启用 VM 状态管理,与 make qemu 行为保持一致
vmstateDir = "${buildDir}/vmstate";
};
qemuScriptsSystem = import ./tools/qemu/default.nix {
inherit
lib
pkgs
testOpt
diskPath
;
# QEMU 相关参数:
# 内核位置
kernel = "${buildDir}/kernel/kernel.elf"; # TODO: make it a drv 用nix构建内核,避免指定相对目录
# -s -S
debug = false;
enableVsock = vsockConfig.enable;
vsockGuestCid = vsockConfig.guestCid;
vsockDeviceModel = vsockConfig.deviceModel;
# 启用 VM 状态管理,与 make qemu 行为保持一致
vmstateDir = "${buildDir}/vmstate";
# 优先使用系统 QEMU,避免 Nix 下载 QEMU 依赖
preferSystemQemu = true;
};
qemuScriptsDebug = import ./tools/qemu/default.nix {
inherit
lib
pkgs
testOpt
diskPath
;
# QEMU 相关参数:
# 内核位置
kernel = "${buildDir}/kernel/kernel.elf";
# 开启 GDB stub,用于调试
debug = true;
enableVsock = vsockConfig.enable;
vsockGuestCid = vsockConfig.guestCid;
vsockDeviceModel = vsockConfig.deviceModel;
# 启用 VM 状态管理,与 make qemu 行为保持一致
vmstateDir = "${buildDir}/vmstate";
};
startPkg = qemuScripts.${target};
startSystemPkg = qemuScriptsSystem.${target};
startDebugPkg = qemuScriptsDebug.${target};
rootfsPkg = pkgs.callPackage ./user/default.nix {
inherit
lib
pkgs
nixpkgs
fenix
system
target
testOpt
rootfsType
buildDir
diskPath
;
};
gdbBin = if target == "x86_64" then "rust-gdb" else "gdb-multiarch";
gdbScript = pkgs.writeScriptBin "dragonos-gdb" ''
#!${pkgs.runtimeShell}
GDB_PORT_FILE="${buildDir}/vmstate/gdb"
if [ ! -f "$GDB_PORT_FILE" ]; then
echo "Error: VM not running or GDB port not allocated"
echo "Start VM first: nix run .#start-debug-''${target}"
exit 1
fi
GDB_PORT=$(cat "$GDB_PORT_FILE")
GDB_INIT_TMP=$(mktemp)
trap "rm -f $GDB_INIT_TMP" EXIT
sed "s/{{GDB_PORT}}/$GDB_PORT/" ${./tools/.gdbinit} > "$GDB_INIT_TMP"
echo "Connecting to GDB port: $GDB_PORT"
exec ${gdbBin} -n -x "$GDB_INIT_TMP"
'';
# 一键化构建启动脚本 (yolo: You Only Live Once - 一条命令跑通全部)
runApp = pkgs.writeScriptBin "dragonos-yolo" ''
#!${pkgs.runtimeShell}
set -e
export USING_DRAGONOS_NIX_ENV=1
export PATH=${rust-toolchain}/bin:$PATH
echo "==> Step 1: Building kernel with make kernel..."
${pkgs.gnumake}/bin/make kernel
echo "==> Step 2: Building rootfs (re-evaluating userland packages)..."
${pkgs.nix}/bin/nix run .#rootfs-${target}
echo "==> Step 3: Starting DragonOS..."
exec ${pkgs.nix}/bin/nix run .#start-${target} -- "$@"
'';
in
{
apps = {
# yolo-${target}: 一键化构建启动命令 (make kernel + rootfs + start)
"yolo-${target}" = {
type = "app";
program = "${runApp}/bin/dragonos-yolo";
meta.description = "一键化构建并启动DragonOS (${target})";
};
# start-${target} 的产物只是一个shell脚本,因此启动相关的参数,直接在上面修改即可,
# 脚本不占什么空间所以重复eval也没关系,并且最终产出的脚本可读性更好.
"start-${target}" = {
type = "app";
program = "${startPkg}/bin/dragonos-run";
meta.description = "以 ${target} 启动DragonOS";
};
"start-system-${target}" = {
type = "app";
program = "${startSystemPkg}/bin/dragonos-run";
meta.description = "以系统 QEMU 启动DragonOS (${target})";
};
"start-debug-${target}" = {
type = "app";
program = "${startDebugPkg}/bin/dragonos-run";
meta.description = "以调试模式启动DragonOS (开启GDB stub, ${target})";
};
# rootfs 中涉及到基于docker镜像的rootfs构建,修改了 user/ 下软件包相关内容后,
# rootfs 的docker镜像会重复构建,并且由于nix特性,副本会全部保留
# 因此可能会占很多空间,如果要清理空间请执行 nix store gc
"rootfs-${target}" = {
type = "app";
program = "${rootfsPkg}/bin/dragonos-rootfs";
meta.description = "构建 ${target} rootfs 镜像";
};
"gdb-${target}" = {
type = "app";
program = "${gdbScript}/bin/dragonos-gdb";
meta.description = "Connect GDB to running DragonOS (${target})";
};
};
packages = {
"yolo-${target}" = runApp;
"start-${target}" = startPkg;
"start-system-${target}" = startSystemPkg;
"start-debug-${target}" = startDebugPkg;
"rootfs-${target}" = rootfsPkg;
"gdb-${target}" = gdbScript;
};
};
allOutputs = map mkOutputs [
"x86_64"
"riscv64"
];
merged =
lib.foldl'
(acc: elem: {
apps = acc.apps // elem.apps;
packages = acc.packages // elem.packages;
})
{
apps = { };
packages = { };
}
allOutputs;
in
{
inherit (merged) apps packages;
# treefmt formatter配置 (使用nixfmt)
treefmt = {
projectRootFile = "flake.nix";
programs = {
nixfmt = {
enable = true;
package = pkgs.nixfmt-rfc-style;
};
};
settings.formatter.nixfmt.excludes = [ ".direnv/**" ];
};
devShells.default = pkgs.mkShell {
# 基础工具链
buildInputs = with pkgs; [
git
llvm
libclang
gcc
rust-toolchain
zlib
gnumake
qemu_kvm
meson
ninja
];
env = {
LIBCLANG_PATH = "${pkgs.libclang.lib}/lib";
USING_DRAGONOS_NIX_ENV = 1;
};
# Shell启动脚本
shellHook = ''
export PATH=${rust-toolchain}/bin:$PATH
# 自动创建 GC root,避免 nix store gc 清理开发环境
if [ -z "''${DRAGONOS_NIX_GC_ROOT:-}" ]; then
if [ ! -e ".nix-gc-root" ]; then
echo "创建 Nix GC root: .nix-gc-root"
${pkgs.nix}/bin/nix build .#devShells.${system}.default -o ./.nix-gc-root >/dev/null 2>&1 || true
fi
fi
echo "欢迎进入 DragonOS Nix 开发环境!"
echo ""
echo " Rust toolchain:"
echo " rustc: $(rustc -V)"
echo " cargo: $(cargo -V)"
echo " path : ${rust-toolchain}/bin (prepended)"
echo ""
echo "要运行 DragonOS,请构建内核、rootfs,再QEMU运行"
echo ""
echo " 以下命令都会沿用当前 shell 的 Rust/Cargo 工具链:"
echo " 一键运行: nix run .#yolo-x86_64"
echo " 构建内核: make kernel"
echo " 构建 rootfs: nix run .#rootfs-x86_64"
echo " QEMU 运行: nix run .#start-x86_64"
echo ""
echo " 文档: https://docs.dragonos.org.cn/"
'';
};
};
};
}