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
configuration.
Essentially think of installing packages in 2 phases, Bootstrap, Install and Configure.
- Phase 1: Bootstrap - Configures
package.el
to point to the MELPA, refresh the package index, and then checks for and installsuse-package
. - Phase 2: Install and Configure - Evaluates your package manifest and installs and bootstraps the packages from MELPA.
Bootstrap package.el
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 package-archives
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)
Install and Configure Packages
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
specify the ensure
tag. So to install a package all we need is the
following code.
(use-package my-package)
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
a :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 :config
which
will evaluate after the package has loaded.
To read more about use-package and how to use it
visit the use-package
docs (opens in a new tab).
fin