Finally, we can actually build the environment. This just uses Nixpkgs buildEnv to generate Nix paths for the different packages. Some need special handling.

First, we build the info pages. This takes all of the packages listed in userPackages and runs install-info on them. Info pages are usually found in the $out/share/info directory, but in Emacs packages can be found anywhere in $out/share/emacs .

infopages = buildEnv { name = "info-pages" ; buildInputs = [ pkgs.texinfoInteractive ]; paths = userPackages ++ [customEmacsPackages.emacs] ++ lib.optional hostPlatform.isLinux pkgs.glibcInfo; extraOutputsToInstall = [ "info" "doc" "devdoc" ]; pathsToLink = [ "/share/info" ]; postBuild = '' shopt -s nullglob find -L ${ myEmacsPackages } /share/emacs/ -name '*.info*' -exec ln -s {} $out/share/info \; for i in $out/share/info/*.info*; do install-info $i $out/share/info/dir done '' ; };

Next, we build the man pages. Again, these come from userPackages and are in the /share/man directory. In addition, some extra man pages are added like the POSIX man pages, and the C++ stdlib man pages. Other OS-specific ones are also included where appropriate Linux man pages ( man-pages ), and the ones from the Apple SDK.

manpages = buildEnv { name = "man-pages" ; ignoreCollisions = (!(config.bauer.small or false )); paths = userPackages ++ [pkgs.posix_man_pages pkgs.stdman ] ++ lib.optional (hostPlatform.isDarwin && big && allowUnfree) " ${ apple_sdk } /usr" ++ lib.optional hostPlatform.isLinux pkgs.man-pages; extraOutputsToInstall = [ "man" "doc" "devdoc" "devman" ]; pathsToLink = [ "/share/man" ]; };

Next, build the XDG / FreeDesktop directory paths. These come from userPackages and include relevnt information for Desktop files, MIME info, menus, and icons. This updates the caches where appropriate as well. The location of these directories is defined in the FreeDesktop specification.

xdg-data = buildEnv { name = "xdg-data-dirs" ; buildInputs = [ pkgs.desktop-file-utils pkgs.shared-mime-info ]; paths = userPackages ++ [ customEmacsPackages.emacs pkgs.zsh ]; pathsToLink = [ "/share/applications" "/share/mime" "/share/menus" "/share/icons" ]; postBuild = '' export XDG_DATA_DIRS=$out/share if [ -w $out/share/applications ]; then update-desktop-database $out/share/applications fi if [ -w $out/share/mime ] \ && [ -w $out/share/mime/packages ]; then update-mime-database -V $out/share/mime fi '' ; };

Next, ZSH completions are built. These all reside in the $out/share/zsh/site-functions directory.

zsh-completions = buildEnv { name = "zsh-completions" ; paths = [ pkgs.zsh-completions pkgs.nix-zsh-completions ] ++ userPackages; pathsToLink = [ "/share/zsh" ]; };

Next, setup the binary directory. This will be put in the user’s PATH . We also remove binaries starting with . , as they are used in Nixpkgs for the “wrapped” version of executables.

bins = buildEnv { name = "bins" ; paths = userPackages; extraOutputsToInstall = [ "bin" ]; pathsToLink = [ "/bin" ]; postBuild = '' find $out/bin -maxdepth 1 -name ".*" -type l -delete '' ; };

Setup the system headers path. This is delibirately light to avoid huge closures. Right now, only libc and libcxx are included by default.

sysheaders = buildEnv { name = "headers" ; pathsToLink = [ "/include" ]; extraOutputsToInstall = [ "dev" ]; paths = [ stdenv.cc.libc ] ++ lib.optional hostPlatform.isDarwin pkgs.libcxx ++ lib.optional (hostPlatform.isDarwin && big && allowUnfree) " ${ apple_sdk } /usr" ; };

Also setup the Apple framework paths. These are a mix between lib directory and include directory. This is oinly useful on macOS/Darwin machines.

apple_sdk = " ${ pkgs.darwin.xcode } /Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk" ; sysframeworks = buildEnv { name = "frameworks" ; paths = lib.optionals (hostPlatform.isDarwin && big && allowUnfree) [ " ${ apple_sdk } /System/Library/Frameworks" " ${ apple_sdk } /System/Library/PrivateFrameworks" ]; };

Setup XML schema needed for editing some docbooks in Emacs. Not entirely sure why this is necessary, but nXML complains otherwise.

schemas = writeText "schemas.xml" '' <locatingRules xmlns="http://thaiopensource.com/ns/locating-rules/1.0" > <documentElement localName="section" typeId="DocBook"/> <documentElement localName="chapter" typeId="DocBook"/> <documentElement localName="article" typeId="DocBook"/> <documentElement localName="book" typeId="DocBook"/> <typeId id="DocBook" uri=" ${ pkgs.docbook5 } /xml/rng/docbook/docbookxi.rnc" /> </locatingRules> '' ;

Full listing of packages that will be made available.

userPackages = ( with pkgs; [ coreutils findutils diffutils gnused gnugrep gawk gnutar gzip bzip2 gnumake bashInteractive patch xz curl zsh cacert file lsof pstree which rsync unzip man openssh less calc ag ripgrep tree gnutls ] ++ lib.optionals big ([ isync notmuch graphviz indent graphviz imagemagick bazaar mercurial myTex rEnv perl python lua coq ocaml openjdk nodejs gcc gdb travis v8 ] ++ ( with netbsd; [ getent getconf ]) ++ ( with nodePackages; [ tern heroku node2nix ]) ++ ( with gitAndTools; [ hub ]) ++ ( with haskellPackages; [ ghc jq nix-diff cabal2nix cabal-install ]) ++ ( with unixtools; [ utillinux nettools procps ]) ));

Setup global environment variables & directories. Most of the global directories will not exist, but the way search paths work, means that is okay. We aim to support all directories in a common system, prioritizing ones that the user has the most direct access to. Global directories should only contain system paths.

global-dirs = [ "/nix/var/nix/profiles/default" "/run/wrappers" "/run/current-system/sw" "/usr/local" "/usr" "" ]; PATH = lib.concatStringsSep ":" [ (lib.makeBinPath ([ bins customEmacsPackages.emacs pkgs.zsh ] ++ global-dirs)) (lib.makeSearchPath "sbin" [ "/usr" "" ]) ]; MANPATH = ":" + lib.makeSearchPathOutput "man" "share/man" ([ manpages customEmacsPackages.emacs pkgs.zsh ] ++ global-dirs); INFOPATH = " ${ infopages } /share/info" ; XDG_DATA_DIRS = lib.makeSearchPathOutput "xdg" "share" ([ xdg-data ] ++ global-dirs); TERMINFO_DIRS = lib.makeSearchPathOutput "terminfo" "share/terminfo" ([ pkgs.ncurses ]); INPUTRC = builtins.toFile "inputrc" '' $include /etc/inputrc "\C-p":history-search-backward "\C-n":history-search-forward set colored-stats on set completion-ignore-case on set completion-prefix-display-length 3 set mark-symlinked-directories on set show-all-if-ambiguous on set show-all-if-unmodified on set visible-stats on set editing-mode emacs Space:magic-space '' ;

Finally, build the final environment. This only contains Emacs and ZSH, which have been configured to use the paths above.