返回 DeepSeek-TUI-2026
preflight-glibc.js
根目录 / npm / deepseek-tui / scripts / preflight-glibc.js
1 const fs = require("fs");
2 const { execFileSync } = require("child_process");
3
4 const GLIBC_VERSION_RE = /GLIBC_(\d+)\.(\d+)(?:\.(\d+))?/g;
5
6 function isLinux() {
7 return process.platform === "linux";
8 }
9
10 function parseVersion(text) {
11 const match = String(text || "").match(/(\d+)\.(\d+)(?:\.(\d+))?/);
12 if (!match) return null;
13 return [Number(match[1]), Number(match[2]), Number(match[3] || 0)];
14 }
15
16 function compareVersion(a, b) {
17 for (let i = 0; i < 3; i += 1) {
18 if (a[i] !== b[i]) return a[i] - b[i];
19 }
20 return 0;
21 }
22
23 function formatVersion(version) {
24 return version[2] ? `${version[0]}.${version[1]}.${version[2]}` : `${version[0]}.${version[1]}`;
25 }
26
27 function detectHostGlibc() {
28 try {
29 const out = execFileSync("getconf", ["GNU_LIBC_VERSION"], {
30 encoding: "utf8",
31 stdio: ["ignore", "pipe", "ignore"],
32 });
33 const version = parseVersion(out);
34 if (version) return version;
35 } catch {
36 // fall through to ldd
37 }
38 try {
39 const out = execFileSync("ldd", ["--version"], {
40 encoding: "utf8",
41 stdio: ["ignore", "pipe", "ignore"],
42 });
43 const firstLine = out.split("\n", 1)[0];
44 const version = parseVersion(firstLine);
45 if (version) return version;
46 } catch {
47 // glibc not present (e.g. musl / Alpine)
48 }
49 return null;
50 }
51
52 function detectBinaryRequiredGlibc(filePath) {
53 const buf = fs.readFileSync(filePath);
54 const text = buf.toString("latin1");
55 let highest = null;
56 GLIBC_VERSION_RE.lastIndex = 0;
57 let match;
58 while ((match = GLIBC_VERSION_RE.exec(text)) !== null) {
59 const version = [Number(match[1]), Number(match[2]), Number(match[3] || 0)];
60 if (!highest || compareVersion(version, highest) > 0) {
61 highest = version;
62 }
63 }
64 return highest;
65 }
66
67 function buildFromSourceHint() {
68 return [
69 "You can still run DeepSeek TUI by building from source with Cargo:",
70 "",
71 " # Requires Rust 1.88+ (https://rustup.rs)",
72 " cargo install deepseek-tui-cli --locked # provides `deepseek`",
73 " cargo install deepseek-tui --locked # provides `deepseek-tui`",
74 "",
75 "Or build from a checkout:",
76 "",
77 " git clone https://github.com/Hmbown/DeepSeek-TUI.git",
78 " cd DeepSeek-TUI",
79 " cargo install --path crates/cli --locked",
80 " cargo install --path crates/tui --locked",
81 "",
82 "See https://github.com/Hmbown/DeepSeek-TUI/blob/main/docs/INSTALL.md",
83 ].join("\n");
84 }
85
86 function preflightGlibc(filePath) {
87 if (!isLinux()) return;
88 if (
89 process.env.DEEPSEEK_TUI_SKIP_GLIBC_CHECK === "1" ||
90 process.env.DEEPSEEK_SKIP_GLIBC_CHECK === "1"
91 ) {
92 return;
93 }
94
95 const required = detectBinaryRequiredGlibc(filePath);
96 if (!required) {
97 // Statically linked / musl binary, or no GLIBC_* version dependencies present.
98 return;
99 }
100
101 const host = detectHostGlibc();
102 if (!host) {
103 throw new Error(
104 [
105 `The prebuilt binary requires GLIBC_${formatVersion(required)}, but no GNU libc was detected on this host.`,
106 "This usually means you're on a musl-based distro such as Alpine.",
107 "",
108 buildFromSourceHint(),
109 "",
110 "Set DEEPSEEK_TUI_SKIP_GLIBC_CHECK=1 to bypass this check at your own risk.",
111 ].join("\n"),
112 );
113 }
114
115 if (compareVersion(host, required) < 0) {
116 throw new Error(
117 [
118 `Prebuilt DeepSeek TUI binary requires GLIBC_${formatVersion(required)} but this system has glibc ${formatVersion(host)}.`,
119 "Older distros (CentOS 7/8, RHEL 7/8, Debian 10, etc.) ship an older glibc that is not compatible with the prebuilt artifact.",
120 "",
121 buildFromSourceHint(),
122 "",
123 "Set DEEPSEEK_TUI_SKIP_GLIBC_CHECK=1 to bypass this check at your own risk.",
124 ].join("\n"),
125 );
126 }
127 }
128
129 module.exports = {
130 preflightGlibc,
131 detectHostGlibc,
132 detectBinaryRequiredGlibc,
133 // exported for tests
134 _internal: { parseVersion, compareVersion, formatVersion },
135 };
136
136 lines JAVASCRIPT