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 = "-p zed -p cli --locked --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 LK_CUSTOM_WEBRTC = livekit-libwebrtc;
150
151 CARGO_PROFILE = profile;
152 # need to handle some profiles specially https://github.com/rust-lang/cargo/issues/11053
153 TARGET_DIR = "target/" + (if profile == "dev" then "debug" else profile);
154
155 # for some reason these deps being in buildInputs isn't enough, the only thing
156 # about them that's special is that they're manually dlopened at runtime
157 NIX_LDFLAGS = lib.optionalString stdenv.hostPlatform.isLinux "-rpath ${
158 lib.makeLibraryPath [
159 gpu-lib
160 wayland
161 ]
162 }";
163 };
164
165 # prevent nix from removing the "unused" wayland/gpu-lib rpaths
166 dontPatchELF = stdenv.hostPlatform.isLinux;
167
168 # TODO: try craneLib.cargoNextest separate output
169 # for now we're not worried about running our test suite (or tests for deps) in the nix sandbox
170 doCheck = false;
171
172 cargoVendorDir = craneLib.vendorCargoDeps {
173 inherit src cargoLock;
174 overrideVendorGitCheckout =
175 let
176 hasWebRtcSys = builtins.any (crate: crate.name == "webrtc-sys");
177 # `webrtc-sys` expects a staticlib; nixpkgs' `livekit-webrtc` has been patched to
178 # produce a `dylib`... patching `webrtc-sys`'s build script is the easier option
179 # TODO: send livekit sdk a PR to make this configurable
180 postPatch = ''
181 substituteInPlace webrtc-sys/build.rs --replace-fail \
182 "cargo:rustc-link-lib=static=webrtc" "cargo:rustc-link-lib=dylib=webrtc"
183 '';
184 in
185 crates: drv:
186 if hasWebRtcSys crates then
187 drv.overrideAttrs (o: {
188 postPatch = (o.postPatch or "") + postPatch;
189 })
190 else
191 drv;
192 };
193 };
194 cargoArtifacts = craneLib.buildDepsOnly commonArgs;
195in
196craneLib.buildPackage (
197 lib.recursiveUpdate commonArgs {
198 inherit cargoArtifacts;
199
200 dontUseCmakeConfigure = true;
201
202 # without the env var generate-licenses fails due to crane's fetchCargoVendor, see:
203 # https://github.com/zed-industries/zed/issues/19971#issuecomment-2688455390
204 # TODO: put this in a separate derivation that depends on src to avoid running it on every build
205 preBuild = ''
206 ALLOW_MISSING_LICENSES=yes bash script/generate-licenses
207 echo nightly > crates/zed/RELEASE_CHANNEL
208 '';
209
210 installPhase =
211 if stdenv.hostPlatform.isDarwin then
212 ''
213 runHook preInstall
214
215 pushd crates/zed
216 sed -i "s/package.metadata.bundle-nightly/package.metadata.bundle/" Cargo.toml
217 export CARGO_BUNDLE_SKIP_BUILD=true
218 app_path="$(cargo bundle --profile $CARGO_PROFILE | xargs)"
219 popd
220
221 mkdir -p $out/Applications $out/bin
222 # Zed expects git next to its own binary
223 ln -s ${git}/bin/git "$app_path/Contents/MacOS/git"
224 mv $TARGET_DIR/cli "$app_path/Contents/MacOS/cli"
225 mv "$app_path" $out/Applications/
226
227 # Physical location of the CLI must be inside the app bundle as this is used
228 # to determine which app to start
229 ln -s "$out/Applications/Zed Nightly.app/Contents/MacOS/cli" $out/bin/zed
230
231 runHook postInstall
232 ''
233 else
234 ''
235 runHook preInstall
236
237 mkdir -p $out/bin $out/libexec
238 cp $TARGET_DIR/zed $out/libexec/zed-editor
239 cp $TARGET_DIR/cli $out/bin/zed
240
241 install -D "crates/zed/resources/app-icon-nightly@2x.png" \
242 "$out/share/icons/hicolor/1024x1024@2x/apps/zed.png"
243 install -D crates/zed/resources/app-icon-nightly.png \
244 $out/share/icons/hicolor/512x512/apps/zed.png
245
246 # TODO: icons should probably be named "zed-nightly"
247 (
248 export DO_STARTUP_NOTIFY="true"
249 export APP_CLI="zed"
250 export APP_ICON="zed"
251 export APP_NAME="Zed Nightly"
252 export APP_ARGS="%U"
253 mkdir -p "$out/share/applications"
254 ${lib.getExe envsubst} < "crates/zed/resources/zed.desktop.in" > "$out/share/applications/dev.zed.Zed-Nightly.desktop"
255 )
256
257 runHook postInstall
258 '';
259
260 # TODO: why isn't this also done on macOS?
261 postFixup = lib.optionalString stdenv.hostPlatform.isLinux ''
262 wrapProgram $out/libexec/zed-editor --suffix PATH : ${lib.makeBinPath [ nodejs_22 ]}
263 '';
264
265 meta = {
266 description = "High-performance, multiplayer code editor from the creators of Atom and Tree-sitter";
267 homepage = "https://zed.dev";
268 changelog = "https://zed.dev/releases/preview";
269 license = lib.licenses.gpl3Only;
270 mainProgram = "zed";
271 platforms = lib.platforms.linux ++ lib.platforms.darwin;
272 };
273 }
274)