Skip to content
This repository was archived by the owner on Aug 23, 2025. It is now read-only.

Commit 69c4cdd

Browse files
committed
Add support for byte-compiling dot-emacs for package.el users
This was always supported, what this commit adds is that once the new use-package-with-elpa macro is used, the byte-compiled init file has no call to package-initialize or other parts of package.el. This means that the resulting byte-compiled init file loads very quickly, while the user keeps the option to use package.el again at a later time to install more packages.
1 parent 7b05549 commit 69c4cdd

File tree

2 files changed

+99
-0
lines changed

2 files changed

+99
-0
lines changed

README.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,69 @@ such cases, use the `:no-require` keyword, which implies `:defer`:
320320
(message "This is evaluated when `foo' is loaded"))
321321
```
322322

323+
### Byte-compiling with `package.el`
324+
325+
For general discussion on `package.el`, please first read the "For
326+
package.el users" section.
327+
328+
If you would like to byte-compile your init file, and in the
329+
byte-compiled version would like to avoid the `package-initialize`
330+
call (which is quite expensive), then you can use the
331+
`use-package-with-elpa` helper function.
332+
333+
A fully working `.emacs` example:
334+
```elisp
335+
(setq package-user-dir "~/my-new-elpa-dir"
336+
package-archives '(("melpa" . "http://melpa.milkbox.net/packages/")
337+
("gnu" . "http://elpa.gnu.org/packages/")))
338+
339+
;; Install use-package if not yet installed.
340+
(eval-when-compile
341+
(package-initialize)
342+
(unless (package-installed-p 'use-package)
343+
(package-refresh-contents)
344+
(package-install 'use-package)))
345+
346+
(use-package-with-elpa)
347+
348+
(use-package bind-key)
349+
(use-package diminish)
350+
351+
(use-package magit
352+
:bind ("C-c s" . magit-status))
353+
354+
(use-package yaml-mode
355+
:mode ("\\.yaml\\'"))
356+
```
357+
358+
The `use-package-with-elpa` call provides the following functionality
359+
in case of an interpreted init file:
360+
361+
- `use-package-always-ensure` is set to `t`,
362+
- `use-package-verbose` logging is enabled.
363+
364+
These settings together with the `eval-when-compile` initialization
365+
block mean that you can just start Emacs with the init file above.
366+
Even if your elpa directory is completely empty, everything will be
367+
installed automatically with dependencies.
368+
369+
Byte compilation of your init file can be done with a command like this:
370+
```
371+
rm -f ~/.emacs.elc; emacs -Q --batch -l ~/.emacs -f batch-byte-compile ~/.emacs
372+
```
373+
374+
Once your init file is byte-compiled, this configuration provides the
375+
following functionality:
376+
377+
- `package.el` initialization is completely disabled,
378+
- the `load-path` variable is set the same way as it was in the
379+
interpreted init file,
380+
- `use-package-verbose` is set to nil.
381+
382+
Using `use-package` this way together with `package.el` provides very
383+
quick startup times even with a lot of packages, once your init file
384+
is byte-compiled.
385+
323386
## Extending the load-path
324387

325388
If your package needs a directory added to the `load-path` in order to load,

use-package.el

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,42 @@ This is in contrast to merely setting it to 0."
478478

479479
(font-lock-add-keywords 'emacs-lisp-mode use-package-font-lock-keywords)
480480

481+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
482+
;;
483+
;;; Little bit opinionated helper function for package.el users
484+
;;
485+
486+
;;;###autoload
487+
(defmacro use-package-with-elpa ()
488+
"Set up use-package to optimal usage with package.el.
489+
490+
For full documentation on the meaning and usage fo this, please
491+
consult the README file that came with this file at the section
492+
called `Byte-compiling with Package.el'."
493+
'(progn
494+
;; Disable package initialize after us. We either initialize it
495+
;; anyway in case of interpreted .emacs, or we don't want slow
496+
;; initizlization in case of byte-compiled .emacs.elc.
497+
(setq package-enable-at-startup nil)
498+
;; Set use-package-verbose to t for interpreted .emacs,
499+
;; and to nil for byte-compiled .emacs.elc.
500+
(eval-and-compile
501+
(setq use-package-verbose (not (bound-and-true-p byte-compile-current-file))))
502+
;; Add the macro generated list of package.el loadpaths to load-path.
503+
(mapc (lambda (add) (add-to-list 'load-path add))
504+
(eval-when-compile
505+
(setq use-package-always-ensure t)
506+
(let ((package-user-dir-real (file-truename package-user-dir)))
507+
;; The reverse is necessary, because outside we mapc
508+
;; add-to-list element-by-element, which reverses.
509+
(nreverse (apply #'nconc
510+
;; Only keep package.el provided loadpaths.
511+
(mapcar #'(lambda (path)
512+
(if (string-prefix-p package-user-dir-real path)
513+
(list path)
514+
nil))
515+
load-path))))))))
516+
481517
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
482518
;;
483519
;;; Keyword processing

0 commit comments

Comments
 (0)