Efficient Emacs Package Management
A huge pain point I see a lot of (especially, but not always, new) Emacs users having is how to go about installing and using packages from MELPA.
Emacs ships with the
package.el library which will underpin your package management
Essentially think of installing packages in 2 phases, Bootstrap, Install and Configure.
- Phase 1: Bootstrap - Configures
package.elto point to the MELPA, refresh the package index, and then checks for and installs
- Phase 2: Install and Configure - Evaluates your package manifest and installs and bootstraps the packages from MELPA.
First step is to have Emacs load and initialize
package.el on startup.
(require 'package) (setq package-enable-at-startup nil) ;; Prevent Emacs from executing package-initialize after reading init.el (package-initialize)
Now we need to tell
package.el where to look for packages. Most Emacs users have the Melpa and Melpa Stable repos
loaded into their config. To add a repo to
package.el's repo list use the
add-to-list command to target the
symbol like so.
;; ... Rest of file omitted (add-to-list 'package-archives '("melpa-stable" . "http://stable.melpa.org/packages/") t) (add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/") t)
At this point we have a fully functional package manager, accessible from within emacs. Using the
M-x package-install command
we can invoke the installation of any package we want. What we want to happen is for Emacs to load a list of packages and then
install them, upon startup. To do that we will have to write a little bit of wrapper code to first detect the installation status
of a given package and then install it if its not there. This is essentially the primary feature of
use-package itself. What
needs to happen is emacs needs to emulate
use-package in order to install it, then we can use it to do the same thing for
other packages we have.
The following block of code is a little lengthy but we will break it down.
;; ... Rest of file omitted (unless (package-installed-p 'use-package) (package-refresh-contents) (package-install 'use-package)) (require 'use-package) (setq use-package-always-ensure 't)
Lets break that down, line by line so we can understand what this is doing and why.
;; We first enter a conditional block and check the result ;; of package-installed-p (which takes a package name and returns ;; True or False) to determine if the use-package package is ;; installed. This unless block is evaluated on startup to ;; ensure our package manager is ready to go out of the box. (unless (package-installed-p 'use-package) ;; If use-package is not installed we will tell emacs ;; to execute a refresh of the package index ;; so everything is up to date. (package-refresh-contents) ;; We then invoke package-install to rectify the situation and ;; install use-package. (package-install use-package)) ;; We then load use-package using require (require 'use-package) ;; Finally we set the always-ensure option to true. This tells use-package ;; to automatically add the `:ensure t` tag to package declarations which ;; causes use-package to perform the `require` step on each package. (setq use-package-always-ensure 't)
We have a completed package management system baked right into our emacs
config. Now reload emacs to take advantage of our new machinery. At this
point we will start using the
use-package function to build a manifest
of packages to install. Normally to declare a package we write a
function call like this.
(use-package my-package :ensure t)
Because we set the
use-package-always-ensure to true, we don't need to
ensure tag. So to install a package all we need is the
When declaring a package you will usually have other steps to take.
things like setting options and activating major/minor modes. This
can all take place in the
use-package declaration. We simply create
:config tag. and write our configuration steps underneath.
(use-package my-package :config (my-package-mode 1))
There is also an
:init tag as well that defines lisp code that will evaulate
before the package is loaded. This is opposed to
will evaluate after the package has loaded.
To read more about use-package and how to use it
use-package docs (opens in a new tab).
© Josh Burns.RSS