Setting Up Efficient Package Management in Emacs
Package management can be a significant challenge for Emacs users. We often face issues with dependencies, package builds, updates, and maintaining a clean configuration. Let’s explore how to set up a robust package management system.
Common Package Management Challenges in Emacs
1. multiple package sources
Emacs only includes the GNU ELPA repository by default. This limits access to many useful packages. Thus if we want to install the package we found (guaranteed to happen if we use Emacs), we need to:
- Add additional package repositories
- Manage potential conflicts between sources
- Handle different update cycles
2. Complex Package Dependencies
After starting using a great package, we need to maintain it by upgrading to apply bugfix or dependency management. But we MUST NOT do this by hand: manual package management can lead to:
- Missing dependencies
- Version conflicts
- Difficult troubleshooting
3. Package Build Occurs for Each Installation
Package installation involves compilation, which can cause:
- Confusing warning messages
- Failed installations due to compilation errors
- Interrupted installation process due to debugging prompts
Solution: Configure Package Management System in Modern-way
Now, let’s open ~/.emacs.d/init.el
and add the configurations to solve the problem described above.
First: Configure Package Sources
;; Configure package sources and directory
(eval-and-compile
(when (or load-file-name byte-compile-current-file)
(setq user-emacs-directory
(expand-file-name
(file-name-directory
(or load-file-name byte-compile-current-file)))))
;; Set up package archives
(customize-set-variable
'package-archives '(("org" . "https://orgmode.org/elpa/")
("melpa" . "https://melpa.org/packages/")
("gnu" . "https://elpa.gnu.org/packages/")))
(package-initialize)
This configuration:
- Sets up the user’s Emacs directory correctly during compilation
- Adds MELPA and Org repositories alongside GNU ELPA
- Initializes the package system
Seceond: Install and Configure leaf
We’ll use leaf
by conao3 as our primary package manager to use its modern features and declarative syntax:
;; Install leaf if not present
(unless (package-installed-p 'leaf)
(package-refresh-contents)
(package-install 'leaf))
(leaf leaf-keywords
:doc "Configure leaf and its extensions"
:url "https://github.com/conao3/leaf.el"
:ensure t
:init
(leaf el-get
:doc "Add el-get for additional package sources"
:ensure t
:custom ((el-get-notify-type . 'message)
(el-get-git-shallow-clone . t)))
(leaf hydra
:ensure t)
:config
(leaf-keywords-init))
This setup:
- Installs
leaf
automatically if it’s missing - Configures
el-get
for additional package sources - Sets up
hydra
for key binding management - Initializes leaf keywords for extended functionality
Third: Configure Build Process
Before setting up package management, let’s configure how Emacs handles package compilation:
(eval-and-compile
(leaf *byte-compile
:custom ((byte-compile-warnings . '(not free-vars docstrings lexical unresolved constants))
(warning-suppress-types . '(comp))
(debug-on-error . nil))))
This configuration enables the installation process smoother and cleaner by suppressesing non-critical compilation warnings during package installation.
Fourth: Add Package Management Utilities
(leaf package-utils
:doc "Interactive package manager"
:url "https://github.com/Silex/package-utils"
:ensure t)
This gives us commands for:
package-utils-upgrade-all
: Update all packagespackage-utils-remove-obsolete
: Clean up old packagespackage-utils-list-upgrades
: Check available updates
Benefits of This Setup
-
Extended Package Sources
- Access to MELPA’s extensive package collection
- Additional sources through el-get
-
Declarative Package Management
- Clear dependency specifications
- Easy to maintain and modify
- Self-documenting configuration
-
Streamlined Build Process
- Clean compilation output
- Fewer interruptions during installation
- Better error handling
-
Automated Maintenance
- Easy package updates
- Dependency resolution
- Cleanup obsolete packages
The final init.el
As a result, we’ve got our init.el
being configured as follows:
(eval-and-compile
(when (or load-file-name byte-compile-current-file)
(setq user-emacs-directory
(expand-file-name
(file-name-directory (or load-file-name byte-compile-current-file))))))
;; Initialize package manager for compile time
(eval-and-compile
(customize-set-variable
'package-archives '(("org" . "https://orgmode.org/elpa/")
("melpa" . "https://melpa.org/packages/")
("gnu" . "https://elpa.gnu.org/packages/")))
(package-initialize)
(unless (package-installed-p 'leaf)
(package-refresh-contents)
(package-install 'leaf))
;; Leaf keywords
(leaf leaf-keywords
:doc "Use leaf as a package manager"
:url "https://github.com/conao3/leaf.el"
:ensure t
:init
(leaf el-get
:ensure t
:custom
(el-get-notify-type . 'message)
(el-get-git-shallow-clone . t))
(leaf hydra :ensure t)
:config
(leaf-keywords-init)))
;; Compile
(eval-and-compile
(leaf *byte-compile
:custom
(byte-compile-warnings . '(not free-vars docstrings lexical unresolved constants))
(warning-suppress-types . '(comp))
(debug-on-error . nil)))
;; Package Manager
(leaf package-utils
:doc "Interactive package manager"
:url "https://github.com/Silex/package-utils"
:ensure t)
Next Steps
We should start version controlling because our Emacs setup will continue to grow. In the following article, we will install a package that will help us using Git command from Emacs.
comments powered by Disqus