emacs all in one

TOC TOC

Introduction

It's a note on how to compile and use spacemacs/doom and custom emacs profile on one computer in the same time.

And the offline emcs package is used in PortableLinuxTools. For providing a portable toolset for some adhoc linux development and maintainance.

build emacs

building emacs should be in fact very easy. Here is some shell history on resovling dependencies on ubuntu:

sudo apt install \
     libxpm-dev \
     libgif-dev \
     libjpeg-dev \
     libpng-dev \
     libtiff-dev \
     libx11-dev \
     libncurses5-dev \
     automake \
     autoconf \
     texinfo \
     libgtk2.0-dev
sudo add-apt-repository ppa:ubuntu-toolchain-r/ppa
sudo apt install gcc-10 \
     g++-10 \
     libgccjit0 \
     libgccjit-10-dev \
     libjansson4 \
     libjansson-dev
# this for gcc-9, ubuntu 1604 has no prebuilt gcc-10
#  sudo apt install gcc-9 \
    #       g++-9 \
    #       libgccjit0 \
    #       libgccjit-9-dev \
    #       libjansson4 \
    #       libjansson-dev
sudo apt install libgnutls-dev

then clone the code from gnu.org. It's ok to clone from other mirrors too:

git clone git://git.sv.gnu.org/emacs.git
# or clone from github mirror
# https://github.com/emacs-mirror/emacs
# git@github.com:emacs-mirror/emacs.git

checkout the target branch (here it's the native-comp branch), and read the instruction in repos and do build it:

git checkout feature/native-comp
# export CC=/usr/bin/gcc-10 CXX=/usr/bin/gcc-10
export CC=/usr/bin/gcc-9 CXX=/usr/bin/gcc-9
./autogen.sh 
./configure \
    --prefix=$(realpath ../emacs-native-comp-build) \
    --with-nativecomp \
    --with-json CFLAGS="-O3 -mtune=native -march=native -fomit-frame-pointer"
make -j4 NATIVE_FULL_AOT=1
make install

or build a version of emacs 27.1 and remove some features not needed in terminal mode:

git checkout emacs-27.1
./autogen.sh
# here we remove all elc files and do make clean
# for sometimes we switching branch to make different target
./configure --prefix=$(realpath ../emacs-build-27.1) \
            --with-json CFLAGS="-O3 -mtune=native -march=native -fomit-frame-pointer" \
            --with-x-toolkit=no --with-xpm=no --with-jpeg=no \
            --with-png=no --with-gif=no --with-tiff=no 
make -j 4
make install

we remove most gui related features for avoiding dependencies on many unnecessary lib**.so libraries. BUt still we do not do --with-x=no

check emacsnativecomp too, there are some commands about building in it

run emacs

this part mostly is copied from

copy dependencies

we copy all necessary to relative path ~/emacs-build-27.1/lib:

for i in $(ldd ../bin/emacs-27.1|rg '=> /' | awk '{print $3}')
do
    cp $i .
done

and according to the file excludelist in project

# wget https://raw.githubusercontent.com/AppImage/pkg2appimage/master/excludelist
for i in $(grep -P ^lib.+so excludelist|awk '{print $1}')
do
    rm -rf $i
done

but still we lack some so files, we add it back again:

libxcb.so.1
libX11.so.6
libfontconfig.so.1
libfreetype.so.6
libharfbuzz.so.0

all files we copied are:

libgraphite2.so.3
libjansson.so.4
libtasn1.so.6
libXdmcp.so.6
libXrandr.so.2
libffi.so.6
libharfbuzz.so.0
liblzma.so.5
libtinfo.so.5
libXext.so.6
libXrender.so.1
libfontconfig.so.1
libhogweed.so.4
libnettle.so.6
libX11.so.6
libXfixes.so.3
libfreetype.so.6
libicudata.so.55
libpcre.so.3
libX11-xcb.so.1
libXft.so.2
libgmodule-2.0.so.0
libicuuc.so.55
libpng12.so.0
libXau.so.6
libXinerama.so.1
libgnutls.so.30
libidn.so.11
libselinux.so.1
libxcb.so.1
libxml2.so.2

run built emacs

just setup all the related enviroment:

EMACS_PREFIX=$(realpath ~/emacs-build-27.1) \
            LD_LIBRARY_PATH=$EMACS_PREFIX/lib/:$LD_LIBRARY_PATH \
            PATH=$EMACS_PREFIX/bin:$PATH \
            EMACSPATH=$EMACS_PREFIX/share/emacs/27.1 \
            EMACSDATA=$EMACSPATH/etc \
            EMACSDOC=$EMACSPATH/etc \
            EMACSLOADPATH=$EMACSPATH/site-lisp:$EMACSPATH/lisp:$EMACSPATH/lisp/emacs-lisp \
            emacs 

The EMACS_PREFIX is for our convinients to define other enviroments. LD_LIBRARY_PATH is used to specified so for the target executable. For more detail plz ref to rpath.

EMACSPATH EMACSDATA EMACSLOADPATH EMACSDOC are all enviroment variables related to emacs. TODO currently we still not well understand and document this part.

chemacs, spacemacs and doom

This part is mostly about how to setup multiple version of emacs profile and using it in an offline enviroment. We use chemacs2 to switch different emacs profile (originally we use chemacs). Most part about chemacs2 is just following the tutorial.

the profile (file .emacs-profiles.el) setup is:

(
 ("spacemacs" . ((user-emacs-directory . "~/csh_spacemacs_install")
                 (env . (("SPACEMACSDIR" . "~/.spacemacs.d")))))
 ("spacemacs-old" . ((user-emacs-directory . "~/spacemacs_old/.emacs.d")
                     (env . (("SPACEMACSDIR" . "~/spacemacs_old/.spacemacs.d")))))
 ;;
 ;; ("new-config" . ((user-emacs-directory . "~/spacemacs/develop")
 ;;                  (env . (("SPACEMACSDIR" . "~/my-spacemacs-config")))))
 ("default" . ((user-emacs-directory . "~/.emacs.d")))
 ("doom" . ((user-emacs-directory . "~/doom-emacs-27")
            (env . (("DOOMDIR" . "~/.doom.d")))))
 ("myp1". ((user-emacs-directory . "~/.myp1")))
 ("enc". ((user-emacs-directory . "~/.enc.d")))
 )

For emacs build files and .emacs.d .spacemacs.d and other files just tar them into a tar.gz file from an ubuntu enviroment (an enviroment that we installed chemacs2 and spacemacs and doom normally). Beware that we need to tar all directories removing its soft links and owner/group. Aka the package should use tar with a dereference option -h , like: tar -zcvh -f targetfile.tar.gz blablabla if got an error like: https://superuser.com/questions/169195/tar-exiting-with-failure-status-due-to-previous-errors try remove -v to get a concrete reason or package without .git:

tar -zcvh -f emacs-all-in-one.tar.gz --exclude .git  .emacs.d  csh_spacemacs_install  .spacemacs.d  doom-emacs-27  .doom.d  .enc.d  emacs-build-27.1  .emacs-profiles.el spacemacs_old

and for removing user/group, we use --owner=0 --group=0

for detail:

--exclude .git --owner=0 --group=0 

package without git got an error in doom:

Loading /home/powerop/doom-emacs-27/.local/cache/recentf...done
Doom loaded 152 packages across 28 modules in 1.362s
Loading loadup.el (source)...done
Cannot determine Magit’s version (error "/home/powerop/doom-emacs-27/.local/straight/repos/magit/lisp/magit.el" repo static elpa dirname hash)
Reading /home/powerop/doom-emacs-27/.local/etc/scratch/__default.el
evil-motion-range: Beginning of buffer

but seems does not matter

and finaly, we just package the tar.gz file to the PortableLinuxTools, a tool set for adhoc linux enviroment.

fix doom installation for offline usage

tldr, we need do doom build and doom sync again. And beware that do remove soft links in tar.gz file. It contains lots of soft links.

and another problem is that we failed at some point like:

Debugger entered--Lisp error: (wrong-type-argument stringp (require . china-util))
   string-match("\\(\\`\\|/\\)imenu\\(\\.elc\\|\\.el\\|\\.so\\)?\\(\\.gz\\)?\\'" (require . china-util))
   load-history-filename-element("\\(\\`\\|/\\)imenu\\(\\.elc\\|\\.el\\|\\.so\\)?\\(\\.gz\\)?\\'")
   eval-after-load("imenu" #f(compiled-function () #<bytecode 0x156f3dd>))
   require(org-compat)
   byte-code("\302\303!\210\302\304!\210\302\305!\210\302\306!\210\10\307=\204:\0\3101)\0\311\312\11!\313P\314\315\211\211%0\2029\0\210\316\317!\210\320\321!\210..." [this-command load-fi$
   #<subr autoload-do-load>((autoload "org" "Outline-based notes management and organizer, alia..." t nil) org-mode nil)
   apply(#<subr autoload-do-load> ((autoload "org" "Outline-based notes management and organizer, alia..." t nil) org-mode))
   autoload-do-load((autoload "org" "Outline-based notes management and organizer, alia..." t nil) org-mode)
   command-execute(org-mode record)
   counsel-M-x-action("org-mode")
   ivy-call()
   ivy-read("M-x " ("toggle-debug-on-error" "org-mode" "cd" "5x5" "amx" "arp" "dbx" "dig" "erc" "ert" "eww" "ftp" "gdb" "irc" "jdb" "man" "mpc" "pdb" "pwd" "rsh" "sdb" "xdb" "calc" "diff"$
   counsel-M-x()
   funcall-interactively(counsel-M-x)
   call-interactively(counsel-M-x nil nil)
   command-execute(counsel-M-x)

we did https://www.reddit.com/r/emacs/comments/bezim2/issue_with_withevalafterload_and_emacs_27/ and https://www.google.com/search?q=load-history-filename-element+emacs but it doesnt help.

but we did it with method mentioned in at https://emacs.stackexchange.com/q/5552/

put the code:

(defun load-history-filename-element (file-regexp)
  "Get the first elt of `load-history' whose car matches FILE-REGEXP.
        Return nil if there isn't one."
  (let* ((loads load-history)
         (load-elt (and loads (car loads))))
    (save-match-data
      (while (and loads
                  (or (null (car load-elt))
                      (not (and (stringp (car load-elt)) ; new condition
                                (string-match file-regexp (car load-elt))))))
        (setq loads (cdr loads)
              load-elt (and loads (car loads)))))
    load-elt))

put in a very early point, it's working now. It should be something related to load-history. But we haven't figure it too much now.