dmenu Source Build^
The Dynamic Menu, or dmenu, simplifies the menu selection process. It is especially useful operating on large user-defined lists and as an alternative to bloated application menus.
Unlike most Linux tools but like most everything that Suckless.org ships, the preferred installation path does not involve a call to your distribution’s package manager: instead, they prefer you build from source.
The procedure below is slightly more complex than necessary. It includes in the use of a personal repository, which is helpful but not a strict requirement. It also includes some additional verification steps for cases where you need to confirm that the process was successful.
Configure the Repository^
Suckless.org uses Git to handle its version control, which is convenient since we also use Git to version control our work.
In order to build dmenu from source, you need a local repository with the dmenu code. But, since you may want to save and share any changes you make to this code, it is good to also set up a personal remote repository to keep your code in sync with the upstream dmenu code.
This guide organizes the following remote repositories:
|
Your personal remote repository, hosted on GitHub, GitLab, or your own remote infrastructure from a bare Git repository. |
|
The dmenu repository hosted by Suckless.org. |
Clone the Origin Repository^
Start with the origin remote repository. This can be created
on GitHub or GitLab as managed solution, or if you need to
self-manage everything, you can set up a server in the cloud or
on your network to host a bare Git repository.
Once you have the repository ready, clone it onto your local system:
$ git clone git@gitlab.com:kennethpjdyer/dyer-dmenu ~/.local/opt/dmenu/main
This command clones the remote Git repository (in this case, my
private repository for hosting my fork of dmenu) from the host to
the ~/.local/opt/dmenu/main directory.
Note
The flat ~/.local/opt/dmenu directory will be a more
familiar path to most users. The reason why I have mine down
to dmenu/main is that I use Git worktrees to separate the
branch of live code from feature branches I have in the
works.
Configure the Upstream Repository^
The repository is currently empty. In order to pull down the code from Suckless.org, you need to configure a separate remote to tell Git where to look for the upstream code.
First, add the upstream remote:
$ cd ~/.local/opt/dmenu/main
$ git remote add upstream https://git.suckless.org/dmenu
To test that you have the correct URL, use the fetch command
to connect to the remote repository and pull down the
commit and branch information you need to use the upstream:
$ git fetch upstream
If the fetch pulls down data from upstream, it indicates that the remote repository was correctly configured.
Merge the Upstream Release^
In order to bring the remote code down from Suckless.org to your local repository, you need to pull a specific branch.
The remote dmenu repository uses the master branch to track
on-going work on the tool. If you plan to run dmenu as a bleeding
edge build, this is the branch to pull down.
However, it is generally advisable that you track a specific release. Suckless.org tags release commits and pushes them to specific branches on the upstream repository.
To list the available tags, use the tag command:
$ git tags
...
4.9
5.0
5.1
5.2
5.3
This shows the available tags. It’s generally advisable to pull down the latest release, but you can work from any that you feel comfortable using.
To pull down a specific release, use the pull command:
$ git pull --no-rebase upstream 5.3
The --no-rebase option ensures that Git merges the changes
from the upstream branch rather than rebases.
Note
As of the writing, I don’t have a strong opinion on whether it’s better to merge or rebase. I expect at some point in this process I’ll do a write up on both so watch for the KB articles on the Git page for more information.
Push the Changes to Origin^
Once you have the base code from the upstream remote merged into your local repository, you should also push the changes up to your personal remote repository.
$ git push origin HEAD
The HEAD branch is a special designation to push your
current branch to a remote branch of the same name.
As best practice, you should make a habit of always pushing
your commits up to the origin HEAD branch. This ensures that
whatever you are doing exists in at least two places, which is
much more secure than trusting your hard drive with all your
important work to last forever.
Note
When pushing a rebase up to a remote repository, you
sometimes need to use the --force-with-lease option.
Build and Install^
Now that you have the source code, you need to build dmenu in your
local repository. This can be done using GNU Make, which reads
the provided Makefile to perform a series of operations in
order to compile the C code to native binaries.
Build Binaries^
Dmenu is written to the C99 standard of the C programming language.
Make calls the cc command, which on my system invokes GCC.
$ make
cc -c -std=c99 -pedantic -Wall -Os -I/usr/X11R6/include
-I/usr/include/freetype2 -D_DEFAULT_SOURCE -D_BSD_SOURCE
-D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"5.3\"
-DXINERAMA dmenu.c
cc -c -std=c99 -pedantic -Wall -Os -I/usr/X11R6/include
-I/usr/include/freetype2 -D_DEFAULT_SOURCE -D_BSD_SOURCE
-D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"5.3\"
-DXINERAMA drw.c
cc -c -std=c99 -pedantic -Wall -Os -I/usr/X11R6/include
-I/usr/include/freetype2 -D_DEFAULT_SOURCE -D_BSD_SOURCE
-D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"5.3\"
-DXINERAMA util.c
cc -o dmenu dmenu.o drw.o util.o -L/usr/X11R6/lib -lX11 -lXinerama
-lfontconfig -lXft
cc -c -std=c99 -pedantic -Wall -Os -I/usr/X11R6/include
-I/usr/include/freetype2 -D_DEFAULT_SOURCE -D_BSD_SOURCE
-D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"5.3\"
-DXINERAMA stest.c
cc -o stest stest.o -L/usr/X11R6/lib -lX11 -lXinerama -lfontconfig
-lXft
As you can see, it runs the compiler several times to build out
the dmenu binaries that runs the terminal emulator.
A benefit of Suckless.org’s focus on simplicity is that their software tends to compile very fast. So fast that it’s pretty trivial to make a quick change to the C code and then recompile and run the updated binary—which is something you’ll likely be doing a lot as you hack on the code to get it to do what you need.
Note
Most errors you encounter at this stage relate either to a build error you introduced or a missing dependency. In the future I’ll test building dmenu on a fresh installation to work out distro specific requirements for Arch Linux and Gentoo.
Install Binaries^
With the binary successfully built, it’s time to install them on your system.
Installation on Linux requires elevated privileges to copy the
binary to /usr/local/bin. You can modify the prefix to
install the binary somewhere in your user’s /home directory
path, such as ~/.local/bin—but, you shouldn’t. It’s best
practice to move executable binaries some place where users
or rogue processes would have difficulty in making changes. So,
use sudo to run the install process.
$ sudo make install
[sudo] password for kbapheus:
mkdir -p /usr/local/bin
cp -f dmenu dmenu_path dmenu_run stest /usr/local/bin
chmod 755 /usr/local/bin/dmenu
chmod 755 /usr/local/bin/dmenu_path
chmod 755 /usr/local/bin/dmenu_run
chmod 755 /usr/local/bin/stest
mkdir -p /usr/local/share/man/man1
sed "s/VERSION/5.3/g" < dmenu.1 > /usr/local/share/man/man1/dmenu.1
sed "s/VERSION/5.3/g" < stest.1 > /usr/local/share/man/man1/stest.1
chmod 644 /usr/local/share/man/man1/dmenu.1
chmod 644 /usr/local/share/man/man1/stest.1
This command install dmenu, dmenu_path, and dmenu_run
in the /usr/local/bin directory with the appropriate
permissions. It also installs the dmenu documentation, which you
can access through the man command.
Clean Repository^
The next step after installing dmenu is to clean the repository.
This can also be done with Make using the clean target to
run the appropriate rm operations.
$ make clean
rm -f dmenu stest drw.o dmenu.o stest.o util.o dmenu-5.3.tar.gz
Verify Install^
Verification of an installation is not a step you need to
undertake every time you rebuild dmenu. You can usually just call
dmenu_run to ensure that it’s available to you.
But, it’s good to know how to verify an install in the event that you encounter errors or similarly unexpected behaviors.
Check Location^
This simplest check is to see if the dmenu binaries are
available in your PATH. This can be done with the
whereis command:
$ whereis dmenu dmenu_run dmenu_path
dmenu: /usr/local/bin/dmenu
dmenu_run: /usr/local/bin/dmenu_run
dmenu_path: /usr/local/bin/dmenu_path
Check Version^
An even simpler check to verify the installation of dmenu is to
check its version. Many Linux applications are configured with a
version sub-command or a --version option to retrieve
this information. Dmenu uses the simpler -v option.
$ dmenu -v
dmenu-5.3
Installation should overwrite any existing binaries installed on
your system. If the version number shown here does not match the
one for the tag you compiled, something went wrong with the
install and you should double-check whereis and other areas
to investigate the reason.