1{
2 lib,
3 crane,
4 rustToolchain,
5 rustPlatform,
6 cmake,
7 copyDesktopItems,
8 fetchFromGitHub,
9 curl,
10 clang,
11 perl,
12 pkg-config,
13 protobuf,
14 fontconfig,
15 freetype,
16 libgit2,
17 openssl,
18 sqlite,
19 zlib,
20 zstd,
21 alsa-lib,
22 libxkbcommon,
23 wayland,
24 libglvnd,
25 xorg,
26 stdenv,
27 makeFontsConf,
28 vulkan-loader,
29 envsubst,
30 cargo-about,
31 cargo-bundle,
32 git,
33 livekit-libwebrtc,
34 apple-sdk_15,
35 darwin,
36 darwinMinVersionHook,
37 makeWrapper,
38 nodejs_22,
39
40 withGLES ? false,
41 profile ? "release",
42}:
43
44assert withGLES -> stdenv.hostPlatform.isLinux;
45
46let
47 mkIncludeFilter =
48 root': path: type:
49 let
50 # note: under lazy-trees this introduces an extra copy
51 root = toString root' + "/";
52 relPath = lib.removePrefix root path;
53 topLevelIncludes = [
54 "crates"
55 "assets"
56 "extensions"
57 "script"
58 "tooling"
59 "Cargo.toml"
60 ".config" # nextest?
61 ];
62 firstComp = builtins.head (lib.path.subpath.components relPath);
63 in
64 builtins.elem firstComp topLevelIncludes;
65
66 craneLib = crane.overrideToolchain rustToolchain;
67 gpu-lib = if withGLES then libglvnd else vulkan-loader;
68 commonArgs =
69 let
70 zedCargoLock = builtins.fromTOML (builtins.readFile ../crates/zed/Cargo.toml);
71 in
72 rec {
73 pname = "zed-editor";
74 version = zedCargoLock.package.version + "-nightly";
75 src = builtins.path {
76 path = ../.;
77 filter = mkIncludeFilter ../.;
78 name = "source";
79 };
80
81 cargoLock = ../Cargo.lock;
82
83 nativeBuildInputs =
84 [
85 clang # TODO: use pkgs.clangStdenv or ignore cargo config?
86 cmake
87 copyDesktopItems
88 curl
89 perl
90 pkg-config
91 protobuf
92 cargo-about
93 rustPlatform.bindgenHook
94 ]
95 ++ lib.optionals stdenv.hostPlatform.isLinux [ makeWrapper ]
96 ++ lib.optionals stdenv.hostPlatform.isDarwin [
97 # TODO: move to overlay so it's usable in the shell
98 (cargo-bundle.overrideAttrs (
99 new: old: {
100 version = "0.6.1-zed";
101 src = fetchFromGitHub {
102 owner = "zed-industries";
103 repo = "cargo-bundle";
104 rev = "2be2669972dff3ddd4daf89a2cb29d2d06cad7c7";
105 hash = "sha256-cSvW0ND148AGdIGWg/ku0yIacVgW+9f1Nsi+kAQxVrI=";
106 };
107 # https://nixos.asia/en/buildRustPackage
108 cargoDeps = old.cargoDeps.overrideAttrs ({
109 inherit src;
110 name = "${new.pname}-${new.version}-vendor.tar.gz";
111 outputHash = "sha256-Q49FnXNHWhvbH1LtMUpXFcvGKu9VHwqOXXd+MjswO64=";
112 });
113 }
114 ))
115 ];
116
117 buildInputs =
118 [
119 curl
120 fontconfig
121 freetype
122 # TODO: need staticlib of this for linking the musl remote server.
123 # should make it a separate derivation/flake output
124 # see https://crane.dev/examples/cross-musl.html
125 libgit2
126 openssl
127 sqlite
128 zlib
129 zstd
130 ]
131 ++ lib.optionals stdenv.hostPlatform.isLinux [
132 alsa-lib
133 libxkbcommon
134 wayland
135 gpu-lib
136 xorg.libxcb
137 ]
138 ++ lib.optionals stdenv.hostPlatform.isDarwin [
139 apple-sdk_15
140 darwin.apple_sdk.frameworks.System
141 (darwinMinVersionHook "10.15")
142 ];
143
144 cargoExtraArgs = "-p zed -p cli --locked --features=gpui/runtime_shaders";
145
146 env = {
147 ZSTD_SYS_USE_PKG_CONFIG = true;
148 FONTCONFIG_FILE = makeFontsConf {
149 fontDirectories = [
150 ../assets/fonts/plex-mono
151 ../assets/fonts/plex-sans
152 ];
153 };
154 ZED_UPDATE_EXPLANATION = "Zed has been installed using Nix. Auto-updates have thus been disabled.";
155 RELEASE_VERSION = version;
156 RUSTFLAGS = if withGLES then "--cfg gles" else "";
157 LK_CUSTOM_WEBRTC = livekit-libwebrtc;
158
159 CARGO_PROFILE = profile;
160 # need to handle some profiles specially https://github.com/rust-lang/cargo/issues/11053
161 TARGET_DIR = "target/" + (if profile == "dev" then "debug" else profile);
162
163 # for some reason these deps being in buildInputs isn't enough, the only thing
164 # about them that's special is that they're manually dlopened at runtime
165 NIX_LDFLAGS = lib.optionalString stdenv.hostPlatform.isLinux "-rpath ${
166 lib.makeLibraryPath [
167 gpu-lib
168 wayland
169 ]
170 }";
171 };
172
173 # prevent nix from removing the "unused" wayland/gpu-lib rpaths
174 dontPatchELF = stdenv.hostPlatform.isLinux;
175
176 # TODO: try craneLib.cargoNextest separate output
177 # for now we're not worried about running our test suite (or tests for deps) in the nix sandbox
178 doCheck = false;
179
180 cargoVendorDir = craneLib.vendorCargoDeps {
181 inherit src cargoLock;
182 overrideVendorGitCheckout =
183 let
184 hasWebRtcSys = builtins.any (crate: crate.name == "webrtc-sys");
185 # `webrtc-sys` expects a staticlib; nixpkgs' `livekit-webrtc` has been patched to
186 # produce a `dylib`... patching `webrtc-sys`'s build script is the easier option
187 # TODO: send livekit sdk a PR to make this configurable
188 postPatch = ''
189 substituteInPlace webrtc-sys/build.rs --replace-fail \
190 "cargo:rustc-link-lib=static=webrtc" "cargo:rustc-link-lib=dylib=webrtc"
191 '';
192 in
193 crates: drv:
194 if hasWebRtcSys crates then
195 drv.overrideAttrs (o: {
196 postPatch = (o.postPatch or "") + postPatch;
197 })
198 else
199 drv;
200 };
201 };
202 cargoArtifacts = craneLib.buildDepsOnly commonArgs;
203in
204craneLib.buildPackage (
205 lib.recursiveUpdate commonArgs {
206 inherit cargoArtifacts;
207
208 dontUseCmakeConfigure = true;
209
210 # without the env var generate-licenses fails due to crane's fetchCargoVendor, see:
211 # https://github.com/zed-industries/zed/issues/19971#issuecomment-2688455390
212 # TODO: put this in a separate derivation that depends on src to avoid running it on every build
213 preBuild = ''
214 ALLOW_MISSING_LICENSES=yes bash script/generate-licenses
215 echo nightly > crates/zed/RELEASE_CHANNEL
216 '';
217
218 installPhase =
219 if stdenv.hostPlatform.isDarwin then
220 ''
221 runHook preInstall
222
223 pushd crates/zed
224 sed -i "s/package.metadata.bundle-nightly/package.metadata.bundle/" Cargo.toml
225 export CARGO_BUNDLE_SKIP_BUILD=true
226 app_path="$(cargo bundle --profile $CARGO_PROFILE | xargs)"
227 popd
228
229 mkdir -p $out/Applications $out/bin
230 # Zed expects git next to its own binary
231 ln -s ${git}/bin/git "$app_path/Contents/MacOS/git"
232 mv $TARGET_DIR/cli "$app_path/Contents/MacOS/cli"
233 mv "$app_path" $out/Applications/
234
235 # Physical location of the CLI must be inside the app bundle as this is used
236 # to determine which app to start
237 ln -s "$out/Applications/Zed Nightly.app/Contents/MacOS/cli" $out/bin/zed
238
239 runHook postInstall
240 ''
241 else
242 ''
243 runHook preInstall
244
245 mkdir -p $out/bin $out/libexec
246 cp $TARGET_DIR/zed $out/libexec/zed-editor
247 cp $TARGET_DIR/cli $out/bin/zed
248
249 install -D "crates/zed/resources/app-icon-nightly@2x.png" \
250 "$out/share/icons/hicolor/1024x1024@2x/apps/zed.png"
251 install -D crates/zed/resources/app-icon-nightly.png \
252 $out/share/icons/hicolor/512x512/apps/zed.png
253
254 # TODO: icons should probably be named "zed-nightly"
255 (
256 export DO_STARTUP_NOTIFY="true"
257 export APP_CLI="zed"
258 export APP_ICON="zed"
259 export APP_NAME="Zed Nightly"
260 export APP_ARGS="%U"
261 mkdir -p "$out/share/applications"
262 ${lib.getExe envsubst} < "crates/zed/resources/zed.desktop.in" > "$out/share/applications/dev.zed.Zed-Nightly.desktop"
263 )
264
265 runHook postInstall
266 '';
267
268 # TODO: why isn't this also done on macOS?
269 postFixup = lib.optionalString stdenv.hostPlatform.isLinux ''
270 wrapProgram $out/libexec/zed-editor --suffix PATH : ${lib.makeBinPath [ nodejs_22 ]}
271 '';
272
273 meta = {
274 description = "High-performance, multiplayer code editor from the creators of Atom and Tree-sitter";
275 homepage = "https://zed.dev";
276 changelog = "https://zed.dev/releases/preview";
277 license = lib.licenses.gpl3Only;
278 mainProgram = "zed";
279 platforms = lib.platforms.linux ++ lib.platforms.darwin;
280 };
281 }
282)