Reputation: 8064
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.
Upvotes: 62
Views: 38108
Reputation: 550
To improve on this answer by Kjell Ericson, this function follows includes but now also does it recursively (in case the makefile you include in turn also includes other files), and it supports expanding environment variables in the paths.
function recurseMakefile() {
# First, look for any targets here - then look for includes and recurse
grep -oE '^[a-zA-Z0-9_.-]+:([^=]|$)' $1 | sed 's/[^a-zA-Z0-9_.-]*$//' | grep -v '.phony'
for x in $(grep -E '^include' $1 | sed -e 's/include //' -e 's/(/{/' -e 's/)/}/')
do
# Use envsubst to force variable name expansion
recurseMakefile "$(echo "$x" | envsubst)"
done
}
complete -W "\$(recurseMakefile ?akefile)" make
EDIT: added filtering to ignore the .phony
target, in case it exists
Upvotes: 0
Reputation: 39
I added so I follow "include" directives in Makefile. So my .bashrc looks like this:
function followMakefile() {
grep -oE '^[a-zA-Z0-9_.-]+:([^=]|$)' ?akefile | sed 's/[^a-zA-Z0-9_.-]*$//'
for x in `grep -E '^include' ?akefile | sed 's/include //'`
do
grep -oE '^[a-zA-Z0-9_.-]+:([^=]|$)' $x | sed 's/[^a-zA-Z0-9_.-]*$//'
done
}
complete -W "\`followMakefile\`" make
Upvotes: 0
Reputation: 72279
This answer from 2010 is outdated - the project mentioned here seems to have been discontinued.
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.
Upvotes: 14
Reputation: 21
I had 2 problems with the normal completions:
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.
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
You can use Homebrew (on macOS or Linux) to install fzf.
brew install fzf
$(brew --prefix)/opt/fzf/install
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 |
:
compatible auto-complete commandPut 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!
Then you can use as following:
Upvotes: 2
Reputation: 510
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
Upvotes: 3
Reputation: 1273
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.
Upvotes: 92
Reputation: 1704
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
.)
Upvotes: 17
Reputation: 21
In Ubuntu 10.04, source the following file:
. /etc/bash_completion
or uncomment it in
/etc/bash.bashrc
Upvotes: -2
Reputation: 47104
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
Upvotes: 3