24 , gsettings-desktop-schemas
63 , withNativeCompilation ? stdenv.buildPlatform.canExecute stdenv.hostPlatform
70 , withDbus ? stdenv.hostPlatform.isLinux
71 , withGTK3 ? withPgtk && !noGui
72 , withGlibNetworking ? withPgtk || withGTK3 || (withX && withXwidgets)
73 , withGpm ? stdenv.hostPlatform.isLinux
74 , withImageMagick ? lib.versionOlder version "27" && (withX || withNS)
75 # Emacs 30+ has native JSON support
76 , withJansson ? lib.versionOlder version "30"
77 , withMailutils ? true
79 , withNS ? stdenv.hostPlatform.isDarwin && !(variant == "macport" || noGui)
81 , withSelinux ? stdenv.hostPlatform.isLinux
82 , withSQLite3 ? lib.versionAtLeast version "29"
83 , withSystemd ? lib.meta.availableOn stdenv.hostPlatform systemd
84 , withToolkitScrollBars ? true
85 , withTreeSitter ? lib.versionAtLeast version "29"
86 , withWebP ? lib.versionAtLeast version "29"
87 , withX ? !(stdenv.hostPlatform.isDarwin || noGui || withPgtk)
88 , withXinput2 ? withX && lib.versionAtLeast version "29"
89 , withXwidgets ? !stdenv.hostPlatform.isDarwin && !noGui && (withGTK3 || withPgtk) && (lib.versionOlder version "30") # XXX: upstream bug 66068 precludes newer versions of webkit2gtk (https://lists.gnu.org/archive/html/bug-gnu-emacs/2024-09/msg00695.html)
90 , withSmallJaDic ? false
91 , withCompressInstall ? true
94 , siteStart ? ./site-start.el
96 if withGTK3 then "gtk3"
97 else if withMotif then "motif"
98 else if withAthena then "athena"
101 # macOS dependencies for NS and macPort
113 , UniformTypeIdentifiers
117 assert (withGTK3 && !withNS && variant != "macport") -> withX || withPgtk;
119 assert noGui -> !(withX || withGTK3 || withNS || variant == "macport");
120 assert withAcl -> stdenv.hostPlatform.isLinux;
121 assert withAlsaLib -> stdenv.hostPlatform.isLinux;
122 assert withGpm -> stdenv.hostPlatform.isLinux;
123 assert withNS -> stdenv.hostPlatform.isDarwin && !(withX || variant == "macport");
124 assert withPgtk -> withGTK3 && !withX;
125 assert withXwidgets -> !noGui && (withGTK3 || withPgtk);
128 libGccJitLibraryPaths = [
129 "${lib.getLib libgccjit}/lib/gcc"
130 "${lib.getLib stdenv.cc.libc}/lib"
131 ] ++ lib.optionals (stdenv.cc?cc.lib.libgcc) [
132 "${lib.getLib stdenv.cc.cc.lib.libgcc}/lib"
135 inherit (if variant == "macport"
136 then llvmPackages_14.stdenv
137 else stdenv) mkDerivation;
139 mkDerivation (finalAttrs: {
141 + (if noGui then "-nox"
142 else if variant == "macport" then "-macport"
143 else if withPgtk then "-pgtk"
144 else if withGTK3 then "-gtk3"
150 patches = patches fetchpatch ++ lib.optionals withNativeCompilation [
152 src = if lib.versionOlder finalAttrs.version "29"
153 then ./native-comp-driver-options-28.patch
154 else if lib.versionOlder finalAttrs.version "30"
155 then ./native-comp-driver-options.patch
156 else ./native-comp-driver-options-30.patch;
157 backendPath = (lib.concatStringsSep " "
158 (builtins.map (x: ''"-B${x}"'') ([
159 # Paths necessary so the JIT compiler finds its libraries:
160 "${lib.getLib libgccjit}/lib"
161 ] ++ libGccJitLibraryPaths ++ [
162 # Executable paths necessary for compilation (ld, as):
163 "${lib.getBin stdenv.cc.cc}/bin"
164 "${lib.getBin stdenv.cc.bintools}/bin"
165 "${lib.getBin stdenv.cc.bintools.bintools}/bin"
170 postPatch = lib.concatStringsSep "\n" [
171 (lib.optionalString srcRepo ''
175 # Add the name of the wrapped gvfsd
176 # This used to be carried as a patch but it often got out of sync with
177 # upstream and was hard to maintain for emacs-overlay.
178 (lib.concatStrings (map (fn: ''
179 sed -i 's#(${fn} "gvfs-fuse-daemon")#(${fn} "gvfs-fuse-daemon") (${fn} ".gvfsd-fuse-wrapped")#' lisp/net/tramp-gvfs.el
181 "tramp-compat-process-running-p"
182 "tramp-process-running-p"
185 # Reduce closure size by cleaning the environment of the emacs dumper
187 substituteInPlace src/Makefile.in \
188 --replace 'RUN_TEMACS = ./temacs' 'RUN_TEMACS = env -i ./temacs'
192 substituteInPlace lisp/international/mule-cmds.el \
193 --replace /usr/share/locale ${gettext}/share/locale
195 for makefile_in in $(find . -name Makefile.in -print); do
196 substituteInPlace $makefile_in --replace /bin/pwd pwd
203 nativeBuildInputs = [
206 ] ++ lib.optionals (variant == "macport") [
208 ] ++ lib.optionals srcRepo [
211 ] ++ lib.optionals (withPgtk || withX && (withGTK3 || withXwidgets)) [ wrapGAppsHook3 ];
216 (lib.getDev harfbuzz)
217 ] ++ lib.optionals withJansson [
222 ] ++ lib.optionals withAcl [
224 ] ++ lib.optionals withAlsaLib [
226 ] ++ lib.optionals withGpm [
228 ] ++ lib.optionals withDbus [
230 ] ++ lib.optionals withSelinux [
232 ] ++ lib.optionals (!stdenv.hostPlatform.isDarwin && withGTK3) [
233 gsettings-desktop-schemas
234 ] ++ lib.optionals (stdenv.hostPlatform.isLinux && withX) [
237 ] ++ lib.optionals (withX && withGTK3) [
239 ] ++ lib.optionals (withX && withMotif) [
241 ] ++ lib.optionals withGlibNetworking [
243 ] ++ lib.optionals withNativeCompilation [
246 ] ++ lib.optionals withImageMagick [
248 ] ++ lib.optionals withPgtk [
256 ] ++ lib.optionals withSQLite3 [
258 ] ++ lib.optionals withSystemd [
260 ] ++ lib.optionals withTreeSitter [
262 ] ++ lib.optionals withWebP [
264 ] ++ lib.optionals withX [
274 ] ++ lib.optionals withXinput2 [
276 ] ++ lib.optionals withXwidgets [
278 ] ++ lib.optionals stdenv.hostPlatform.isDarwin [
280 ] ++ lib.optionals withNS [
285 ] ++ lib.optionals (variant == "macport") [
295 # TODO are these optional?
299 ] ++ lib.optionals (variant == "macport" && stdenv.hostPlatform.isAarch64) [
300 UniformTypeIdentifiers
303 # Emacs needs to find movemail at run time, see info (emacs) Movemail
304 propagatedUserEnvPkgs = lib.optionals withMailutils [
308 hardeningDisable = [ "format" ];
311 (lib.enableFeature false "build-details") # for a (more) reproducible build
312 (lib.withFeature true "modules")
313 ] ++ (if withNS then [
314 (lib.enableFeature false "ns-self-contained")
315 ] else if withX then [
316 (lib.withFeatureAs true "x-toolkit" toolkit)
317 (lib.withFeature true "cairo")
318 (lib.withFeature true "xft")
319 ] else if withPgtk then [
320 (lib.withFeature true "pgtk")
322 (lib.withFeature false "gif")
323 (lib.withFeature false "jpeg")
324 (lib.withFeature false "png")
325 (lib.withFeature false "tiff")
326 (lib.withFeature false "x")
327 (lib.withFeature false "xpm")
329 ++ lib.optionals (variant == "macport") [
330 (lib.enableFeatureAs true "mac-app" "$$out/Applications")
331 (lib.withFeature true "gnutls")
332 (lib.withFeature true "mac")
333 (lib.withFeature true "xml2")
335 ++ lib.optionals stdenv.hostPlatform.isDarwin [
336 (lib.withFeature withNS "ns")
339 (lib.withFeature withCompressInstall "compress-install")
340 (lib.withFeature withToolkitScrollBars "toolkit-scroll-bars")
341 (lib.withFeature withNativeCompilation "native-compilation")
342 (lib.withFeature withImageMagick "imagemagick")
343 (lib.withFeature withMailutils "mailutils")
344 (lib.withFeature withSmallJaDic "small-ja-dic")
345 (lib.withFeature withTreeSitter "tree-sitter")
346 (lib.withFeature withXinput2 "xinput2")
347 (lib.withFeature withXwidgets "xwidgets")
348 (lib.withFeature withDbus "dbus")
349 (lib.withFeature withSelinux "selinux")
352 env = lib.optionalAttrs withNativeCompilation {
353 NATIVE_FULL_AOT = "1";
354 LIBRARY_PATH = lib.concatStringsSep ":" libGccJitLibraryPaths;
355 } // lib.optionalAttrs (variant == "macport") {
356 # Fixes intermittent segfaults when compiled with LLVM >= 7.0.
357 # See https://github.com/NixOS/nixpkgs/issues/127902
358 NIX_CFLAGS_COMPILE = "-include ${./macport_noescape_noop.h}";
361 enableParallelBuilding = true;
363 installTargets = [ "tags" "install" ];
366 mkdir -p $out/share/emacs/site-lisp
367 cp ${siteStart} $out/share/emacs/site-lisp/site-start.el
369 $out/bin/emacs --batch -f batch-byte-compile $out/share/emacs/site-lisp/site-start.el
371 siteVersionDir=`ls $out/share/emacs | grep -v site-lisp | head -n 1`
373 rm -r $out/share/emacs/$siteVersionDir/site-lisp
374 '' + lib.optionalString withCsrc ''
375 for srcdir in src lisp lwlib ; do
376 dstdir=$out/share/emacs/$siteVersionDir/$srcdir
378 find $srcdir -name "*.[chm]" -exec cp {} $dstdir \;
379 cp $srcdir/TAGS $dstdir
380 echo '((nil . ((tags-file-name . "TAGS"))))' > $dstdir/.dir-locals.el
382 '' + lib.optionalString withNS ''
383 mkdir -p $out/Applications
384 mv nextstep/Emacs.app $out/Applications
385 '' + lib.optionalString (withNativeCompilation && (withNS || variant == "macport")) ''
386 ln -snf $out/lib/emacs/*/native-lisp $out/Applications/Emacs.app/Contents/native-lisp
387 '' + lib.optionalString withNativeCompilation ''
388 echo "Generating native-compiled trampolines..."
389 # precompile trampolines in parallel, but avoid spawning one process per trampoline.
390 # 1000 is a rough lower bound on the number of trampolines compiled.
391 $out/bin/emacs --batch --eval "(mapatoms (lambda (s) \
392 (when (subr-primitive-p (symbol-function s)) (print s))))" \
393 | xargs -n $((1000/NIX_BUILD_CORES + 1)) -P $NIX_BUILD_CORES \
394 $out/bin/emacs --batch -l comp --eval "(while argv \
395 (comp-trampoline-compile (intern (pop argv))))"
396 mkdir -p $out/share/emacs/native-lisp
397 $out/bin/emacs --batch \
398 --eval "(add-to-list 'native-comp-eln-load-path \"$out/share/emacs/native-lisp\")" \
399 -f batch-native-compile $out/share/emacs/site-lisp/site-start.el
402 postFixup = lib.optionalString (stdenv.hostPlatform.isLinux && withX && toolkit == "lucid") ''
403 patchelf --add-rpath ${lib.makeLibraryPath [ libXcursor ]} $out/bin/emacs
404 patchelf --add-needed "libXcursor.so.1" "$out/bin/emacs"
408 inherit withNativeCompilation;
409 inherit withTreeSitter;
410 inherit withXwidgets;
411 pkgs = recurseIntoAttrs (emacsPackagesFor finalAttrs.finalPackage);
412 tests = { inherit (nixosTests) emacs-daemon; };
416 broken = withNativeCompilation && !(stdenv.buildPlatform.canExecute stdenv.hostPlatform);