'bash completion of makefile target
Suppose I have a simple makefile like:
hello:
echo "hello world"
bye:
echo "bye bye"
Then in bash I want something like:
make h < tab >
so it can complete to
make hello
I found a simple way like creating empty files hello
and bye
but I'm looking for something more sophisticated.
Solution 1:[1]
Could this be what you're looking for?
http://freshmeat.net/projects/bashcompletion/
make [Tab] would complete on all targets in Makefile. This project was conceived to produce programmable completion routines for the most common Linux/UNIX commands, reducing the amount of typing sysadmins and programmers need to do on a daily basis.
Solution 2:[2]
Add this in your ~/.bash_profile file or ~/.bashrc file
complete -W "\`grep -oE '^[a-zA-Z0-9_.-]+:([^=]|$)' ?akefile | sed 's/[^a-zA-Z0-9_.-]*$//'\`" make
This searches for a target in your Makefile titled 'Makefile' or 'makefile' (note the capital ?
wildcard in ?akefile
) using grep, and pipes it over to the complete
command in bash which is used to specify how arguments are autocompleted. The -W
flag denotes that the input to the complete
command will be a wordlist which is accomplished by passing the results of grep through sed
which arranges it into the desirable wordlist format.
Caveats and gotchas:
Your make file is named 'GNUMakefile' or anything else other than 'Makefile' or 'makefile'. If you frequently encounter such titles consider changing the regular expression
?akefile
accordingly.Forgetting to source your ~/.bash_profile or ~/.bashrc file after making the changes. I add this seemingly trivial detail since, to the uninitiated it is unfamiliar. For any change to your bash files to take effect, source them using the command
source ~/.bashrc
or
source ~/.bash_profile
PS. You also now have the added ability to display the possible make targets by pressing [Tab] twice just like in bash completion. Just make sure you add a space after the command make before typing [Tab] twice.
Solution 3:[3]
There's a useful package called bash-completion available for most every OS. It includes Makefile completion.
(If you're using macOS and Homebrew, you can get this via brew install bash-completion
.)
Solution 4:[4]
This seems to be default in at least Debian Lenny:
$ grep Makefile /etc/bash_completion
# make reads `GNUmakefile', then `makefile', then `Makefile'
elif [ -f ${makef_dir}/Makefile ]; then
makef=${makef_dir}/Makefile
# before we scan for targets, see if a Makefile name was
# deal with included Makefiles
The header of this file states:
# The latest version of this software can be obtained here:
#
# http://bash-completion.alioth.debian.org/
#
# RELEASE: 20080617.5
Solution 5:[5]
Here is a completion script that looks at the .PHONY: declaration.
_make_phony_words() {
local opt_revert
if [ -n "${BASH_VERSION:-}" ]; then
shopt -q nullglob || {
opt_revert=1 ; shopt -s nullglob ;
}
elif [ -n "${ZSH_VERSION:-}" ]; then
[[ -o nullglob ]] || {
opt_revert=1 ; setopt nullglob
}
fi
for f in ./?akefile ./*.make ; do
sed -nEe '/^.PHONY/ { s/^.PHONY:[ ]?// ; p ; } ' "$f" | tr ' ' $'\n' | sort -u
done
if [ -n "$opt_revert" ]; then
[ -n "${ZSH_VERSION:-}" ] && unsetopt nullglob
[ -n "${BASH_VERSION:-}" ] && shopt -u nullglob
fi
unset opt_revert
}
_make_phony_complete() {
local cur="${COMP_WORDS[COMP_CWORD]}"
COMPREPLY+=( $(compgen -W "$( _make_phony_words )" -- ${cur}) )
}
complete -F _make_phony_complete make
Solution 6:[6]
Makefile completion on steroids!
I had 2 problems with the normal completions:
Problem #1
Sometimes you have targets you want to call like make greet:hi
and make greet:hola
sort of like namespacing Makefile
target names. So your Makefile
ends up looking like:
greet\:hola:
echo "hola world"
# OR a .PHONY target
.PHONY: greet\:hi
greet\:hi:
echo "hi world"
In this case the auto-completions after :
don't show up as it uses \:
in the Makefile as shown above.
Problem #2
There wasn't a way to navigate through the list of all Makefile
targets that match my input using arrow keys (or CTRL-p
/ CTRL-n
) in my bash
shell.
Basically, I wanted to use fuzzy search like approach on the targets (i.e. fzf
).
FZF Repo: https://github.com/junegunn/fzf
Solution
Install FZF Dependency
Using Homebrew
You can use Homebrew (on macOS or Linux) to install fzf.
brew install fzf
$(brew --prefix)/opt/fzf/install
Using Linux package managers
Package Manager | Linux Distribution | Command |
---|---|---|
APK | Alpine Linux | sudo apk add fzf |
APT | Debian 9+/Ubuntu 19.10+ | sudo apt-get install fzf |
Conda | conda install -c conda-forge fzf |
|
DNF | Fedora | sudo dnf install fzf |
Nix | NixOS, etc. | nix-env -iA nixpkgs.fzf |
Pacman | Arch Linux | sudo pacman -S fzf |
pkg | FreeBSD | pkg install fzf |
pkgin | NetBSD | pkgin install fzf |
pkg_add | OpenBSD | pkg_add fzf |
XBPS | Void Linux | sudo xbps-install -S fzf |
Zypper | openSUSE | sudo zypper install fzf |
FZF and :
compatible auto-complete command
Put this in your .bashrc
complete -W "\`grep -oE '^[a-zA-Z0-9_.-]+[\\:]*[a-zA-Z0-9_.-]+:([^=]|$)' ?akefile | sort | uniq | sed 's/[^a-zA-Z0-9_.-]*$//' | sed 's/[\]//g' | fzf\`" make
Now just typing make
and then hitting the key will work!
DEMO: in action!
Then you can use as following:
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Kos |
Solution 2 | |
Solution 3 | Paul Bissex |
Solution 4 | mvds |
Solution 5 | Alissa H |
Solution 6 | Shahzad Lone |