anvil-editor: init at 0.4
[NixPkgs.git] / pkgs / applications / editors / emacs / make-emacs.nix
blob7bae78f35e70ef1f60923f10eb8df909b4b4732b
1 { pname
2 , version
3 , variant
4 , src
5 , patches ? _: [ ]
6 , meta
7 }:
9 { lib
10 , stdenv
11 , Xaw3d
12 , acl
13 , alsa-lib
14 , autoreconfHook
15 , cairo
16 , dbus
17 , emacsPackagesFor
18 , fetchpatch
19 , gettext
20 , giflib
21 , glib-networking
22 , gnutls
23 , gpm
24 , gsettings-desktop-schemas
25 , gtk3
26 , gtk3-x11
27 , harfbuzz
28 , imagemagick
29 , jansson
30 , libXaw
31 , libXcursor
32 , libXi
33 , libXpm
34 , libgccjit
35 , libjpeg
36 , libotf
37 , libpng
38 , librsvg
39 , libselinux
40 , libtiff
41 , libwebp
42 , libxml2
43 , llvmPackages_14
44 , m17n_lib
45 , mailutils
46 , makeWrapper
47 , motif
48 , ncurses
49 , nixosTests
50 , pkg-config
51 , recurseIntoAttrs
52 , sigtool
53 , sqlite
54 , substituteAll
55 , systemd
56 , tree-sitter
57 , texinfo
58 , webkitgtk_4_0
59 , wrapGAppsHook3
60 , zlib
62 # Boolean flags
63 , withNativeCompilation ? stdenv.buildPlatform.canExecute stdenv.hostPlatform
64 , noGui ? false
65 , srcRepo ? true
66 , withAcl ? false
67 , withAlsaLib ? false
68 , withAthena ? false
69 , withCsrc ? true
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
78 , withMotif ? false
79 , withNS ? stdenv.hostPlatform.isDarwin && !(variant == "macport" || noGui)
80 , withPgtk ? false
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
93 # Options
94 , siteStart ? ./site-start.el
95 , toolkit ? (
96   if withGTK3 then "gtk3"
97   else if withMotif then "motif"
98   else if withAthena then "athena"
99   else "lucid")
101 # macOS dependencies for NS and macPort
102 , Accelerate
103 , AppKit
104 , Carbon
105 , Cocoa
106 , GSS
107 , IOKit
108 , ImageCaptureCore
109 , ImageIO
110 , OSAKit
111 , Quartz
112 , QuartzCore
113 , UniformTypeIdentifiers
114 , WebKit
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"
133   ];
135   inherit (if variant == "macport"
136            then llvmPackages_14.stdenv
137            else stdenv) mkDerivation;
139 mkDerivation (finalAttrs: {
140   pname = pname
141           + (if noGui then "-nox"
142              else if variant == "macport" then "-macport"
143              else if withPgtk then "-pgtk"
144              else if withGTK3 then "-gtk3"
145              else "");
146   inherit version;
148   inherit src;
150   patches = patches fetchpatch ++ lib.optionals withNativeCompilation [
151     (substituteAll {
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"
166         ])));
167     })
168   ];
170   postPatch = lib.concatStringsSep "\n" [
171     (lib.optionalString srcRepo ''
172       rm -fr .git
173     '')
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
180     '') [
181       "tramp-compat-process-running-p"
182       "tramp-process-running-p"
183     ]))
185     # Reduce closure size by cleaning the environment of the emacs dumper
186     ''
187       substituteInPlace src/Makefile.in \
188         --replace 'RUN_TEMACS = ./temacs' 'RUN_TEMACS = env -i ./temacs'
189     ''
191     ''
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
197       done
198     ''
200     ""
201   ];
203   nativeBuildInputs = [
204     makeWrapper
205     pkg-config
206   ] ++ lib.optionals (variant == "macport") [
207     texinfo
208   ] ++ lib.optionals srcRepo [
209     autoreconfHook
210     texinfo
211   ] ++ lib.optionals (withPgtk || withX && (withGTK3 || withXwidgets)) [ wrapGAppsHook3 ];
213   buildInputs = [
214     gettext
215     gnutls
216     (lib.getDev harfbuzz)
217   ] ++ lib.optionals withJansson [
218     jansson
219   ] ++ [
220     libxml2
221     ncurses
222   ] ++ lib.optionals withAcl [
223     acl
224   ] ++ lib.optionals withAlsaLib [
225     alsa-lib
226   ] ++ lib.optionals withGpm [
227     gpm
228   ] ++ lib.optionals withDbus [
229     dbus
230   ] ++ lib.optionals withSelinux [
231     libselinux
232   ] ++ lib.optionals (!stdenv.hostPlatform.isDarwin && withGTK3) [
233     gsettings-desktop-schemas
234   ] ++ lib.optionals (stdenv.hostPlatform.isLinux && withX) [
235     libotf
236     m17n_lib
237   ] ++ lib.optionals (withX && withGTK3) [
238     gtk3-x11
239   ] ++ lib.optionals (withX && withMotif) [
240     motif
241   ] ++ lib.optionals withGlibNetworking [
242     glib-networking
243   ] ++ lib.optionals withNativeCompilation [
244     libgccjit
245     zlib
246   ] ++ lib.optionals withImageMagick [
247     imagemagick
248   ] ++ lib.optionals withPgtk [
249     giflib
250     gtk3
251     libXpm
252     libjpeg
253     libpng
254     librsvg
255     libtiff
256   ] ++ lib.optionals withSQLite3 [
257     sqlite
258   ] ++ lib.optionals withSystemd [
259     systemd
260   ] ++ lib.optionals withTreeSitter [
261     tree-sitter
262   ] ++ lib.optionals withWebP [
263     libwebp
264   ] ++ lib.optionals withX [
265     Xaw3d
266     cairo
267     giflib
268     libXaw
269     libXpm
270     libjpeg
271     libpng
272     librsvg
273     libtiff
274   ] ++ lib.optionals withXinput2 [
275     libXi
276   ] ++ lib.optionals withXwidgets [
277     webkitgtk_4_0
278   ] ++ lib.optionals stdenv.hostPlatform.isDarwin [
279     sigtool
280   ] ++ lib.optionals withNS [
281     librsvg
282     AppKit
283     GSS
284     ImageIO
285   ] ++ lib.optionals (variant == "macport") [
286     Accelerate
287     AppKit
288     Carbon
289     Cocoa
290     IOKit
291     OSAKit
292     Quartz
293     QuartzCore
294     WebKit
295     # TODO are these optional?
296     GSS
297     ImageCaptureCore
298     ImageIO
299   ] ++ lib.optionals (variant == "macport" && stdenv.hostPlatform.isAarch64) [
300     UniformTypeIdentifiers
301   ];
303   # Emacs needs to find movemail at run time, see info (emacs) Movemail
304   propagatedUserEnvPkgs = lib.optionals withMailutils [
305     mailutils
306   ];
308   hardeningDisable = [ "format" ];
310   configureFlags = [
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")
321   ] else [
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")
328   ])
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")
334   ]
335   ++ lib.optionals stdenv.hostPlatform.isDarwin [
336     (lib.withFeature withNS "ns")
337   ]
338   ++ [
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")
350   ];
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}";
359   };
361   enableParallelBuilding = true;
363   installTargets = [ "tags" "install" ];
365   postInstall = ''
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
377       mkdir -p $dstdir
378       find $srcdir -name "*.[chm]" -exec cp {} $dstdir \;
379       cp $srcdir/TAGS $dstdir
380       echo '((nil . ((tags-file-name . "TAGS"))))' > $dstdir/.dir-locals.el
381     done
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
400   '';
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"
405   '';
407   passthru = {
408     inherit withNativeCompilation;
409     inherit withTreeSitter;
410     inherit withXwidgets;
411     pkgs = recurseIntoAttrs (emacsPackagesFor finalAttrs.finalPackage);
412     tests = { inherit (nixosTests) emacs-daemon; };
413   };
415   meta = meta // {
416     broken = withNativeCompilation && !(stdenv.buildPlatform.canExecute stdenv.hostPlatform);
417   };