1{
2 pkgs,
3 system,
4 lib,
5 stdenv,
6
7 apple-sdk_15,
8 darwin,
9 darwinMinVersionHook,
10
11 cargo-about,
12 cargo-bundle,
13 crane,
14 rustPlatform,
15 rustToolchain,
16
17 copyDesktopItems,
18 envsubst,
19 fetchFromGitHub,
20 makeFontsConf,
21 makeWrapper,
22
23 alsa-lib,
24 cmake,
25 curl,
26 fontconfig,
27 freetype,
28 git,
29 glib,
30 libdrm,
31 libgbm,
32 libgit2,
33 libglvnd,
34 libva,
35 libxcomposite,
36 libxdamage,
37 libxext,
38 libxfixes,
39 libxkbcommon,
40 libxrandr,
41 libx11,
42 libxcb,
43 nodejs_22,
44 openssl,
45 perl,
46 pkg-config,
47 protobuf,
48 sqlite,
49 vulkan-loader,
50 wayland,
51 xorg,
52 zlib,
53 zstd,
54
55 withGLES ? false,
56 profile ? "release",
57 commitSha ? null,
58}:
59assert withGLES -> stdenv.hostPlatform.isLinux;
60let
61 mkIncludeFilter =
62 root': path: type:
63 let
64 # note: under lazy-trees this introduces an extra copy
65 root = toString root' + "/";
66 relPath = lib.removePrefix root path;
67 topLevelIncludes = [
68 "crates"
69 "assets"
70 "extensions"
71 "script"
72 "tooling"
73 "Cargo.toml"
74 ".config" # nextest?
75 ".cargo"
76 ];
77 firstComp = builtins.head (lib.path.subpath.components relPath);
78 in
79 builtins.elem firstComp topLevelIncludes;
80
81 craneLib = crane.overrideToolchain rustToolchain;
82 gpu-lib = if withGLES then libglvnd else vulkan-loader;
83 commonArgs =
84 let
85 zedCargoLock = builtins.fromTOML (builtins.readFile ../crates/zed/Cargo.toml);
86 stdenv' = stdenv;
87 in
88 rec {
89 pname = "zed-editor";
90 version =
91 zedCargoLock.package.version
92 + "-nightly"
93 + lib.optionalString (commitSha != null) "+${builtins.substring 0 7 commitSha}";
94 src = builtins.path {
95 path = ../.;
96 filter = mkIncludeFilter ../.;
97 name = "source";
98 };
99
100 cargoLock = ../Cargo.lock;
101
102 nativeBuildInputs = [
103 cmake
104 copyDesktopItems
105 curl
106 perl
107 pkg-config
108 protobuf
109 # Pin cargo-about to 0.8.2. Newer versions don't work with the current license identifiers
110 # See https://github.com/zed-industries/zed/pull/44012
111 (cargo-about.overrideAttrs (
112 new: old: rec {
113 version = "0.8.2";
114
115 src = fetchFromGitHub {
116 owner = "EmbarkStudios";
117 repo = "cargo-about";
118 tag = version;
119 sha256 = "sha256-cNKZpDlfqEXeOE5lmu79AcKOawkPpk4PQCsBzNtIEbs=";
120 };
121
122 cargoHash = "sha256-NnocSs6UkuF/mCM3lIdFk+r51Iz2bHuYzMT/gEbT/nk=";
123
124 # NOTE: can drop once upstream uses `finalAttrs` here:
125 # https://github.com/NixOS/nixpkgs/blob/10214747f5e6e7cb5b9bdf9e018a3c7b3032f5af/pkgs/build-support/rust/build-rust-package/default.nix#L104
126 #
127 # See (for context): https://github.com/NixOS/nixpkgs/pull/382550
128 cargoDeps = rustPlatform.fetchCargoVendor {
129 inherit (new) src;
130 hash = new.cargoHash;
131 patches = new.cargoPatches or [ ];
132 name = new.cargoDepsName or new.finalPackage.name;
133 };
134 }
135 ))
136 rustPlatform.bindgenHook
137 ]
138 ++ lib.optionals stdenv'.hostPlatform.isLinux [ makeWrapper ]
139 ++ lib.optionals stdenv'.hostPlatform.isDarwin [
140 (cargo-bundle.overrideAttrs (
141 new: old: {
142 version = "0.6.1-zed";
143 src = fetchFromGitHub {
144 owner = "zed-industries";
145 repo = "cargo-bundle";
146 rev = "2be2669972dff3ddd4daf89a2cb29d2d06cad7c7";
147 hash = "sha256-cSvW0ND148AGdIGWg/ku0yIacVgW+9f1Nsi+kAQxVrI=";
148 };
149 cargoHash = "sha256-urn+A3yuw2uAO4HGmvQnKvWtHqvG9KHxNCCWTiytE4k=";
150
151 # NOTE: can drop once upstream uses `finalAttrs` here:
152 # https://github.com/NixOS/nixpkgs/blob/10214747f5e6e7cb5b9bdf9e018a3c7b3032f5af/pkgs/build-support/rust/build-rust-package/default.nix#L104
153 #
154 # See (for context): https://github.com/NixOS/nixpkgs/pull/382550
155 cargoDeps = rustPlatform.fetchCargoVendor {
156 inherit (new) src;
157 hash = new.cargoHash;
158 patches = new.cargoPatches or [ ];
159 name = new.cargoDepsName or new.finalPackage.name;
160 };
161 }
162 ))
163 ];
164
165 buildInputs = [
166 curl
167 fontconfig
168 freetype
169 # TODO: need staticlib of this for linking the musl remote server.
170 # should make it a separate derivation/flake output
171 # see https://crane.dev/examples/cross-musl.html
172 libgit2
173 openssl
174 sqlite
175 zlib
176 zstd
177 ]
178 ++ lib.optionals stdenv'.hostPlatform.isLinux [
179 alsa-lib
180 glib
181 libva
182 libxkbcommon
183 wayland
184 gpu-lib
185 libglvnd
186 libx11
187 libxcb
188 libdrm
189 libgbm
190 libva
191 libxcomposite
192 libxdamage
193 libxext
194 libxfixes
195 libxrandr
196 ]
197 ++ lib.optionals stdenv'.hostPlatform.isDarwin [
198 apple-sdk_15
199 (darwinMinVersionHook "10.15")
200 ];
201
202 cargoExtraArgs = "-p zed -p cli --locked --features=gpui_platform/runtime_shaders";
203
204 stdenv =
205 pkgs:
206 let
207 base = pkgs.llvmPackages.stdenv;
208 addBinTools = old: {
209 cc = old.cc.override {
210 inherit (pkgs.llvmPackages) bintools;
211 };
212 };
213 custom = lib.pipe base [
214 (stdenv: stdenv.override addBinTools)
215 pkgs.stdenvAdapters.useMoldLinker
216 ];
217 in
218 if stdenv'.hostPlatform.isLinux then custom else base;
219
220 env = {
221 ZSTD_SYS_USE_PKG_CONFIG = true;
222 FONTCONFIG_FILE = makeFontsConf {
223 fontDirectories = [
224 ../assets/fonts/lilex
225 ../assets/fonts/ibm-plex-sans
226 ];
227 };
228 ZED_UPDATE_EXPLANATION = "Zed has been installed using Nix. Auto-updates have thus been disabled.";
229 RELEASE_VERSION = version;
230 ZED_COMMIT_SHA = lib.optionalString (commitSha != null) "${commitSha}";
231 LK_CUSTOM_WEBRTC = pkgs.callPackage ./livekit-libwebrtc/package.nix { };
232 PROTOC = "${protobuf}/bin/protoc";
233
234 CARGO_PROFILE = profile;
235 # need to handle some profiles specially https://github.com/rust-lang/cargo/issues/11053
236 TARGET_DIR = "target/" + (if profile == "dev" then "debug" else profile);
237
238 # for some reason these deps being in buildInputs isn't enough, the only thing
239 # about them that's special is that they're manually dlopened at runtime
240 NIX_LDFLAGS = lib.optionalString stdenv'.hostPlatform.isLinux "-rpath ${
241 lib.makeLibraryPath [
242 gpu-lib
243 wayland
244 libva
245 ]
246 }";
247
248 NIX_OUTPATH_USED_AS_RANDOM_SEED = "norebuilds";
249 };
250
251 # prevent nix from removing the "unused" wayland/gpu-lib rpaths
252 dontPatchELF = stdenv'.hostPlatform.isLinux;
253
254 # TODO: try craneLib.cargoNextest separate output
255 # for now we're not worried about running our test suite (or tests for deps) in the nix sandbox
256 doCheck = false;
257
258 cargoVendorDir = craneLib.vendorCargoDeps {
259 inherit src cargoLock;
260 overrideVendorGitCheckout =
261 let
262 hasWebRtcSys = builtins.any (crate: crate.name == "webrtc-sys");
263 # we can't set $RUSTFLAGS because that clobbers the cargo config
264 # see https://github.com/rust-lang/cargo/issues/5376#issuecomment-2163350032
265 glesConfig = builtins.toFile "config.toml" ''
266 [target.'cfg(all())']
267 rustflags = ["--cfg", "gles"]
268 '';
269
270 # `webrtc-sys` expects a staticlib; nixpkgs' `livekit-webrtc` has been patched to
271 # produce a `dylib`... patching `webrtc-sys`'s build script is the easier option
272 # TODO: send livekit sdk a PR to make this configurable
273 postPatch = ''
274 substituteInPlace webrtc-sys/build.rs --replace-fail \
275 "cargo:rustc-link-lib=static=webrtc" "cargo:rustc-link-lib=dylib=webrtc"
276
277 substituteInPlace webrtc-sys/build.rs --replace-fail \
278 'add_gio_headers(&mut builder);' \
279 'for lib_name in ["glib-2.0", "gio-2.0"] {
280 if let Ok(lib) = pkg_config::Config::new().cargo_metadata(false).probe(lib_name) {
281 for path in lib.include_paths {
282 builder.include(&path);
283 }
284 }
285 }'
286 ''
287 + lib.optionalString withGLES ''
288 cat ${glesConfig} >> .cargo/config/config.toml
289 '';
290 in
291 crates: drv:
292 if hasWebRtcSys crates then
293 drv.overrideAttrs (o: {
294 postPatch = (o.postPatch or "") + postPatch;
295 })
296 else
297 drv;
298 };
299 };
300 cargoArtifacts = craneLib.buildDepsOnly commonArgs;
301in
302craneLib.buildPackage (
303 lib.recursiveUpdate commonArgs {
304 inherit cargoArtifacts;
305
306 dontUseCmakeConfigure = true;
307
308 # without the env var generate-licenses fails due to crane's fetchCargoVendor, see:
309 # https://github.com/zed-industries/zed/issues/19971#issuecomment-2688455390
310 # TODO: put this in a separate derivation that depends on src to avoid running it on every build
311 preBuild = ''
312 ALLOW_MISSING_LICENSES=yes bash script/generate-licenses
313 echo nightly > crates/zed/RELEASE_CHANNEL
314 '';
315
316 installPhase =
317 if stdenv.hostPlatform.isDarwin then
318 ''
319 runHook preInstall
320
321 pushd crates/zed
322 sed -i "s/package.metadata.bundle-nightly/package.metadata.bundle/" Cargo.toml
323 export CARGO_BUNDLE_SKIP_BUILD=true
324 app_path="$(cargo bundle --profile $CARGO_PROFILE | xargs)"
325 popd
326
327 mkdir -p $out/Applications $out/bin
328 # Zed expects git next to its own binary
329 ln -s ${git}/bin/git "$app_path/Contents/MacOS/git"
330 mv $TARGET_DIR/cli "$app_path/Contents/MacOS/cli"
331 mv "$app_path" $out/Applications/
332
333 # Physical location of the CLI must be inside the app bundle as this is used
334 # to determine which app to start
335 ln -s "$out/Applications/Zed Nightly.app/Contents/MacOS/cli" $out/bin/zed
336
337 runHook postInstall
338 ''
339 else
340 ''
341 runHook preInstall
342
343 mkdir -p $out/bin $out/libexec
344 cp $TARGET_DIR/zed $out/libexec/zed-editor
345 cp $TARGET_DIR/cli $out/bin/zed
346 ln -s $out/bin/zed $out/bin/zeditor # home-manager expects the CLI binary to be here
347
348
349 install -D "crates/zed/resources/app-icon-nightly@2x.png" \
350 "$out/share/icons/hicolor/1024x1024@2x/apps/zed.png"
351 install -D crates/zed/resources/app-icon-nightly.png \
352 $out/share/icons/hicolor/512x512/apps/zed.png
353
354 # TODO: icons should probably be named "zed-nightly"
355 (
356 export DO_STARTUP_NOTIFY="true"
357 export APP_CLI="zed"
358 export APP_ICON="zed"
359 export APP_NAME="Zed Nightly"
360 export APP_ARGS="%U"
361 mkdir -p "$out/share/applications"
362 ${lib.getExe envsubst} < "crates/zed/resources/zed.desktop.in" > "$out/share/applications/dev.zed.Zed-Nightly.desktop"
363 chmod +x "$out/share/applications/dev.zed.Zed-Nightly.desktop"
364 )
365
366 runHook postInstall
367 '';
368
369 # TODO: why isn't this also done on macOS?
370 postFixup = lib.optionalString stdenv.hostPlatform.isLinux ''
371 wrapProgram $out/libexec/zed-editor --suffix PATH : ${lib.makeBinPath [ nodejs_22 ]}
372 '';
373
374 meta = {
375 description = "High-performance, multiplayer code editor from the creators of Atom and Tree-sitter";
376 homepage = "https://zed.dev";
377 changelog = "https://zed.dev/releases/preview";
378 license = lib.licenses.gpl3Only;
379 mainProgram = "zed";
380 platforms = lib.platforms.linux ++ lib.platforms.darwin;
381 };
382 }
383)