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