how to list emacs package dependencies

For now there is no command or function that recursively list all dependencies of a Emacs package or several of them, but one can write up such a function.

1. how to see one-level dependencies of a package

Just see the value of package-alist.

2. how to programmatically collect the names of all the required packages for a given set of packages

I searched for “dependen” in package.el in the hope that I’d find some hints for how to do that. The code of the function package-activate contained enough hints:

  • package-alist is an alist listing all activated packages and their dependencies and other information.
  • Dependencies are accessed by calling the function package-desc-reqs
  • Defining a recursive function is good for navigating the dependency tree and this is why package-activate is recursive.
  • package-activated-list is all activated packages.

Here is how to extract just the dependency information from package-alist:

(cl-loop for pkg in package-activated-list
         for pkg-vec = (cdr (assq pkg package-alist))
         when pkg-vec
         collect (cons pkg
                       (cl-loop for req in (package-desc-reqs pkg-vec)
                                for req-name = (car req)
                                when (memq req-name package-activated-list)
                                collect req-name)))

Evaluating the above expression gives the following result in my case:

((anything) (anything-config) …. (elnode web dash noflet s creole fakir db kv) (db kv) (creole noflet kv) ….)

So for example, we see that

  • elnode depends on web, dash, noflet, s, creole, fakir, db, kv
  • and db depends on kv.

Here is a function that grows a list by including all dependencies recursively:

(defun my-grow-list-by-dependency (original-list dependency-alist)
  "Return a new list (of symbols) including all items in ORIGINAL-LIST and
also recursively including all dependency as specified in DEPENDENCY-ALIST."
  (cl-labels ((adjoin-with-dependency (item list)
                                      (setq list (cl-adjoin item list))
                                      (dolist (dep (cdr (assq item dependency-alist)))
                                        (setq list (adjoin-with-dependency dep list)))
                                      list))
    (let ((ret nil))
      (dolist (item original-list ret)
        (setq ret (adjoin-with-dependency item ret))))))

And here are some tests for that function:

(sort (my-grow-list-by-dependency (list 'a 'x)
                                  '((a b) (b c)))
      'string<)
;; ⇒ (a b c x)

(sort (my-grow-list-by-dependency (list 'b 'd)
                                  '((b a c) (d c e)))
      'string<)
;; ⇒ (a b c d e)

Test results are fine but you might have noticed that the input lists are given as non-literal data. I did that because writing

(sort (my-grow-list-by-dependency '(b d)
                                  '((b a c) (d c e)))
      'string<)

would violate the rule “don’t modify literal data” and the reason it violates the rule is because sort is a destructive function.

Now that we have all the tools, we can programmatically answer the questions like:

  • what is the full dependency list of elnode?
  • what is the full dependency list for org2blog and elnode together?

You can get the answers by loading Emacs with the following alternate init file:

(require 'cl-lib)

(package-initialize)
(setq package-enable-at-startup nil)


(defvar my-dependency-alist
  (cl-loop for pkg in package-activated-list
           for pkg-vec = (cdr (assq pkg package-alist))
           when pkg-vec
           collect (cons pkg
                         (cl-loop for req in (package-desc-reqs pkg-vec)
                                  for req-name = (car req)
                                  when (memq req-name package-activated-list)
                                  collect req-name))))


(defun my-grow-list-by-dependency (original-list dependency-alist)
  "Return a new list (of symbols) including all items in ORIGINAL-LIST and
also recursively including all dependency as specified in DEPENDENCY-ALIST."
  (cl-labels ((adjoin-with-dependency (item list)
                                      (setq list (cl-adjoin item list))
                                      (dolist (dep (cdr (assq item dependency-alist)))
                                        (setq list (adjoin-with-dependency dep list)))
                                      list))
    (let ((ret nil))
      (dolist (item original-list ret)
        (setq ret (adjoin-with-dependency item ret))))))

(message "elnode full dependency: %S"
         (sort (my-grow-list-by-dependency (list 'elnode)
                                           my-dependency-alist)
               'string<))


(message "full dependency for elnode and org2blog together: %S"
         (sort (my-grow-list-by-dependency (list 'elnode
                                                 'org2blog)
                                           my-dependency-alist)
               'string<))

(view-echo-area-messages)
This entry was posted in Emacs, Lisp and tagged , . Bookmark the permalink.

3 Responses to how to list emacs package dependencies

  1. I triied and this does not seem to work on Emacs 24.5. Is there a fix ?

  2. Mike says:

    Hi Jisang, I was playing around with my emacs config and trying to find out which package(s) were pulling in some unwanted packages, and your post has been the most helpful in understanding dependencies in package.el

    There is one small typo in the first snippet in your post. The second line should read:

    for pkg-vec = (cadr (assq pkg package-alist))

    When I change the cdr to a cadr, it correctly dumps out a list of packages with their dependencies. Hope this helps you @pedro!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s