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
|
{
stdenv,
lib,
fetchFromGitHub,
python3,
python3Packages,
extraPythonPackages ? ps: [ ],
unstableGitUpdater,
makeWrapper,
writeShellScript,
}:
let
isCross = (stdenv.hostPlatform != stdenv.buildPlatform);
in
stdenv.mkDerivation rec {
pname = "klipper";
version = "0.13.0-unstable-2026-08-18";
src = fetchFromGitHub {
owner = "Klipper3d";
repo = "klipper";
rev = "60fc7aa67a8da9abb43a2bad825d4992294ebf3f";
sha256 = "sha256-qs60qBwlD7A0xneNzeNcKfWc8II5rG2oj+tvuhn/aWw=";
};
sourceRoot = "${src.name}/klippy";
# NB: This is needed for the postBuild step
nativeBuildInputs = [
python3Packages.cffi
makeWrapper
];
buildInputs = [
(python3.withPackages (
p:
with p;
[
python-can
cffi
pyserial
greenlet
jinja2
markupsafe
numpy
]
++ extraPythonPackages p
))
];
# we need to run this to prebuild the chelper .so. However when cross
# compiling, a patch is temporarily required during the build process to
# prevent the build process from using dlopen() on this .so which has been
# built for a foreign architecture. We then place the unpatched __init__.py
# back, as this dlopen() call is required at runtime
postBuild =
if isCross then
''
python ./chelper/__init__.py
mv ./chelper/__init__unpatched.py ./chelper/__init__.py
''
else
''
python ./chelper/__init__.py
'';
prePatch = lib.optionalString isCross ''
cp ./chelper/__init__.py ./chelper/__init__unpatched.py
'';
patches = lib.optionals isCross [
# https://github.com/Klipper3d/klipper/pull/7254
./cross-ffi.patch
];
# Python 3 is already supported but shebangs aren't updated yet
postPatch = ''
for file in klippy.py console.py parsedump.py; do
substituteInPlace $file \
--replace-warn '/usr/bin/env python2' '/usr/bin/env python'
done
# needed for cross compilation
substituteInPlace ./chelper/__init__*.py \
--replace-warn 'GCC_CMD = "gcc"' 'GCC_CMD = "${stdenv.cc.targetPrefix}cc"'
'';
pythonInterpreter =
(python3.withPackages (
p: with p; [
numpy
matplotlib
python-can
]
)).interpreter;
pythonScriptWrapper = writeShellScript pname ''
${pythonInterpreter} "@out@/lib/scripts/@script@" "$@"
'';
# NB: We don't move the main entry point into `/bin`, or even symlink it,
# because it uses relative paths to find necessary modules. We could wrap but
# this is used 99% of the time as a service, so it's not worth the effort.
installPhase = ''
runHook preInstall
mkdir -p $out/lib/klipper
cp -r ./* $out/lib/klipper
# Moonraker expects `config_examples` and `docs` to be available
# under `klipper_path`
cp -r $src/docs $out/lib/docs
cp -r $src/config $out/lib/config
cp -r $src/klippy $out/lib/klippy
mkdir -p $out/lib/scripts
cp -r $src/scripts/* $out/lib/scripts
cp $src/lib/katapult/flashtool.py $out/lib/scripts/flash_can.py
# Add version information. For the normal procedure see https://www.klipper3d.org/Packaging.html#versioning
# This is done like this because scripts/make_version.py is not available when sourceRoot is set to "${src.name}/klippy"
echo "${version}-NixOS" > $out/lib/klipper/.version
mkdir -p $out/bin
chmod 755 $out/lib/klipper/klippy.py
makeWrapper $out/lib/klipper/klippy.py $out/bin/klippy --chdir $out/lib/klipper
substitute "$pythonScriptWrapper" "$out/bin/klipper-calibrate-shaper" \
--subst-var "out" \
--subst-var-by "script" "calibrate_shaper.py"
chmod 755 "$out/bin/klipper-calibrate-shaper"
substitute "$pythonScriptWrapper" "$out/bin/klipper-canbus-query" \
--subst-var "out" \
--subst-var-by "script" "canbus_query.py"
chmod 755 "$out/bin/klipper-canbus-query"
runHook postInstall
'';
passthru.updateScript = unstableGitUpdater {
url = meta.homepage;
tagPrefix = "v";
};
meta = {
description = "Klipper 3D printer firmware";
mainProgram = "klippy";
homepage = "https://github.com/Klipper3d/klipper";
maintainers = with lib.maintainers; [
lovesegfault
zhaofengli
cab404
];
platforms = lib.platforms.linux;
license = lib.licenses.gpl3Only;
};
}
|