1{
2 aiohttp,
3 appdirs,
4 appnope,
5 black,
6 build,
7 clang-tools,
8 click,
9 colorama,
10 coloredlogs,
11 coverage,
12 cryptography,
13 diskcache,
14 fetchFromGitHub,
15 fetchpatch,
16 glib,
17 gn,
18 googleapis-common-protos,
19 google-cloud-storage,
20 ipython,
21 jinja2,
22 json5,
23 jsonschema,
24 lark,
25 lib,
26 libnl,
27 mobly,
28 mypy,
29 mypy-extensions,
30 mypy-protobuf,
31 ninja,
32 openssl,
33 packaging,
34 parameterized,
35 pip-tools,
36 pkg-config,
37 pkgconfig,
38 prompt-toolkit,
39 protobuf,
40 psutil,
41 ptpython,
42 pyelftools,
43 pygments,
44 pykwalify,
45 pylint,
46 pyperclip,
47 pyserial,
48 python,
49 python-daemon,
50 pythonOlder,
51 pyyaml,
52 requests,
53 setuptools,
54 six,
55 sphinx,
56 sphinx-argparse,
57 sphinx-design,
58 stdenv,
59 stringcase,
60 toml,
61 tornado,
62 types-protobuf,
63 types-pyyaml,
64 types-requests,
65 types-setuptools,
66 watchdog,
67 websockets,
68 wheel,
69 yapf,
70 zap-chip,
71}:
72
73stdenv.mkDerivation rec {
74 pname = "home-assistant-chip-wheels";
75 version = "2025.4.0";
76 src = fetchFromGitHub {
77 owner = "home-assistant-libs";
78 repo = "chip-wheels";
79 tag = version;
80 fetchSubmodules = false;
81 leaveDotGit = true;
82 hash = "sha256-20dqVXHPgSxBveTxlbHEjTtp9NI1oVCVpBTDbjDI2QA=";
83 postFetch = ''
84 cd $out
85 # Download connectedhomeip.
86 git fetch
87 git reset --hard HEAD
88 git submodule update --init --depth 1 connectedhomeip
89
90 # Initialize only necessary submodules.
91 cd connectedhomeip
92 ${python.interpreter} scripts/checkout_submodules.py --platform linux --shallow
93
94 # Keep the output deterministic.
95 cd $out
96 # in case python decided to leave a .pyc file, for example
97 git clean -fxd
98 rm -rf .git/
99 '';
100 };
101
102 strictDeps = true;
103
104 nativeBuildInputs = [
105 gn
106 pkg-config
107 ninja
108 clang-tools
109 zap-chip
110 # gdbus-codegen
111 glib
112 pkgconfig
113 python
114 # dependencies of build scripts
115 click
116 jinja2
117 lark
118 setuptools
119 stringcase
120 build
121 pip-tools
122 black
123 yapf
124 ];
125
126 propagatedBuildInputs = [
127 openssl
128 glib
129 libnl
130 ];
131
132 patches = [
133 (fetchpatch {
134 # Fix building with newer gn version
135 name = "pw_protobuf_compiler-Create-a-new-includes.txt-for-each-toolchain.patch";
136 # https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/300272
137 url = "https://pigweed.googlesource.com/pigweed/pigweed/+/b66729b90fcb9df2ee4818f6d4fff59385cdbc80^!?format=TEXT";
138 decode = "base64 -d";
139 stripLen = 1;
140 extraPrefix = "connectedhomeip/third_party/pigweed/repo/";
141 hash = "sha256-6ss3j8j69w7EMio9mFP/EL2oPqQ2sLh67eWsJjHdDa8=";
142 })
143 ];
144
145 postPatch = ''
146 cd connectedhomeip
147 export HOME=$(mktemp -d)
148
149 patchShebangs --build scripts
150
151 for patch in ../*.patch; do
152 patch -p1 < $patch
153 done
154
155 # unpin dependencies
156 # there are many files to modify, in different formats
157 sed -i 's/==.*$//' third_party/pigweed/repo/pw_env_setup/py/pw_env_setup/virtualenv_setup/python_base_requirements.txt
158 sed -i 's/==[^;]*//' scripts/setup/constraints.txt
159 sed -i 's/\(^ \+[a-zA-Z0-9-]*\)[=~><]=[^;]*/\1/' third_party/pigweed/repo/pw_protobuf_compiler/py/setup.cfg third_party/pigweed/repo/pw_protobuf/py/setup.cfg third_party/pigweed/repo/pw_protobuf_compiler/py/setup.cfg
160 # remove a few dependencies not packaged in nixpkgs and which are apparently
161 # not needed to build the python bindings of chip
162 sed -i -e '/sphinxcontrib-mermaid/d' -e '/types-six/d' -e '/types-pygment/d' -e '/types-pyserial/d' third_party/pigweed/repo/*/py/setup.cfg
163
164 # obtained by running a build in nix-shell with internet access
165 cp ${./pigweed_environment.gni} build_overrides/pigweed_environment.gni
166
167 # some code is generated by a templating tool (zap-cli)
168 scripts/codepregen.py ./zzz_pregenerated/
169 '';
170
171 # the python parts of the build system work as follows
172 # gn calls pigweed to read a dozen different files to generate
173 # a file looking like requirements.txt. It then calls pip
174 # to install this computed list of dependencies into a virtualenv.
175 # Of course, pip fails in the sandbox, because it cannot download
176 # the python packages.
177 # The documented way of doing offline builds is to create a folder
178 # with wheel files for all dependencies and point pip to it
179 # via its configuration file or environment variables.
180 # https://pigweed.dev/python_build.html#installing-offline
181 # The wheel of a python package foo is available as foo.dist.
182 # So that would be easy, but we also need wheels for transitive dependencies.
183 # the function saturateDependencies below computes this transitive closure.
184 #
185 # yes this list of dependencies contains both build tools and proper dependencies.
186 env.PIP_NO_INDEX = "1";
187 env.PIP_FIND_LINKS =
188 let
189 dependencies = [
190 aiohttp
191 appdirs
192 appnope
193 black
194 build
195 colorama
196 coloredlogs
197 coverage
198 click
199 cryptography
200 diskcache
201 googleapis-common-protos
202 google-cloud-storage
203 ipython
204 jinja2
205 json5
206 jsonschema
207 lark
208 mobly
209 mypy
210 mypy-extensions
211 mypy-protobuf
212 packaging
213 parameterized
214 pip-tools
215 pkgconfig
216 prompt-toolkit
217 protobuf
218 psutil
219 ptpython
220 pyelftools
221 pygments
222 pykwalify
223 (pylint.overridePythonAttrs { doCheck = pythonOlder "3.13"; })
224 pyperclip
225 pyserial
226 python-daemon
227 pyyaml
228 requests
229 setuptools
230 six
231 sphinx
232 sphinx-argparse
233 sphinx-design
234 stringcase
235 toml
236 tornado
237 types-protobuf
238 types-pyyaml
239 types-requests
240 types-setuptools
241 watchdog
242 websockets
243 wheel
244 yapf
245 ];
246 filterNull = list: lib.filter (dep: dep != null) list;
247 toItem = dep: {
248 inherit dep;
249 key = dep.name;
250 };
251 saturatedDependencies = lib.genericClosure {
252 startSet = map toItem (filterNull dependencies);
253 operator = item: map toItem (filterNull ((item.dep).propagatedBuildInputs or [ ]));
254 };
255 saturatedDependencyList = lib.filter (dep: dep ? dist && dep != null) (
256 map (item: item.dep) saturatedDependencies
257 );
258 in
259 lib.concatMapStringsSep " " (dep: "file://${dep.dist}") saturatedDependencyList;
260
261 gnFlags = [
262 ''chip_project_config_include_dirs=["//.."]''
263 ''chip_crypto="openssl"''
264 ''enable_rtti=true''
265 ''chip_config_memory_debug_checks=false''
266 ''chip_config_memory_debug_dmalloc=false''
267 ''chip_mdns="minimal"''
268 ''chip_minmdns_default_policy="libnl"''
269 ''chip_python_version="${lib.versions.majorMinor python.version}"''
270 ''chip_python_platform_tag="any"''
271 ''chip_python_package_prefix="home-assistant-chip"''
272 ''custom_toolchain="custom"''
273 ''target_cc="${stdenv.cc.targetPrefix}cc"''
274 ''target_cxx="${stdenv.cc.targetPrefix}c++"''
275 ''target_ar="${stdenv.cc.targetPrefix}ar"''
276 ];
277
278 preBuild = ''
279 export NIX_CFLAGS_COMPILE="$($PKG_CONFIG --cflags glib-2.0) -O2 -Wno-error"
280 export NIX_CFLAGS_LINK="$($PKG_CONFIG --libs gio-2.0) $($PKG_CONFIG --libs gobject-2.0) $($PKG_CONFIG --libs glib-2.0)"
281 '';
282
283 ninjaFlags = [ "chip-repl" ];
284
285 installPhase = ''
286 runHook preInstall
287
288 cp -r controller/python $out
289
290 runHook postInstall
291 '';
292
293 meta = {
294 description = "Python wheels for APIs and tools related to CHIP";
295 homepage = "https://github.com/home-assistant-libs/chip-wheels";
296 changelog = "https://github.com/home-assistant-libs/chip-wheels/releases/tag/${src.tag}";
297 license = lib.licenses.asl20;
298 teams = [ lib.teams.home-assistant ];
299 };
300
301}