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