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