bash completion of makefile target
Asked Answered
I

8

62

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.

Incendiarism answered 15/11, 2010 at 20:4 Comment(0)
K
14

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.

Karrah answered 15/11, 2010 at 20:4 Comment(4)
link is broken.Brainbrainard
@JonasStein thanks, I'm going to delete this one since I didn't find an alternative link for this projects. There's a lot of newer answers than mineKarrah
Oops I cannot delete because it's accepted. I'll leave a note.Karrah
try this. github.com/scop/bash-completionNightie
P
91

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:

  1. 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.

  2. 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.

Pretense answered 16/7, 2016 at 21:51 Comment(6)
I personally use: complete -W "`make -qp | sed -n -E 's/^([^.#\s][^:=]*)(:$|:\s+.*$)/\1/p' | sort -u'`" makeKyongkyoto
I think it would be good to handle the case of no Makefile in cwd: complete -W "`([[ -r Makefile ]] && grep -oE '^[a-zA-Z0-9_-]+:([^=]|$)' Makefile || cat /dev/null) | sed 's/[^a-zA-Z0-9_-]*$//'`" makeNeodymium
your solution is not detecting command that contain a point "."Cassiani
@ahmedbhs Updated to include recognition of "."Pretense
they should not consider .PHONY and .env etcc so this is my suggestion complete -W "`grep -oE '^[a-zA-Z0-9_-][a-zA-Z0-9_.-]+:([^=]|$)' Makefile | sed 's/[^a-zA-Z0-9_-]*$//'`" makeCassiani
I need to install bash-completion in order to run this on my centos sudo yum install bash-completionUncoil
H
15

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.)

Herzen answered 8/1, 2019 at 15:27 Comment(1)
for macOS - there is bash-completion@2 which directly conflicts with bash-completion. Encouraged to use @2 version if your bash >= 4.1. It doesnt seem to have Makefile completion included so adding custom rule in bashrc as raised in other answers might help.Neelyneeoma
K
14

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.

Karrah answered 15/11, 2010 at 20:4 Comment(4)
link is broken.Brainbrainard
@JonasStein thanks, I'm going to delete this one since I didn't find an alternative link for this projects. There's a lot of newer answers than mineKarrah
Oops I cannot delete because it's accepted. I'll leave a note.Karrah
try this. github.com/scop/bash-completionNightie
I
3

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
Impermeable answered 15/11, 2010 at 20:18 Comment(0)
L
3

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
Lesbianism answered 4/3, 2020 at 4:17 Comment(0)
H
2

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:

make using fzf

Hertford answered 22/4, 2022 at 9:38 Comment(0)
M
0

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
Mirk answered 23/2, 2023 at 13:41 Comment(0)
F
-3

In Ubuntu 10.04, source the following file:

. /etc/bash_completion

or uncomment it in

/etc/bash.bashrc
Fossorial answered 6/8, 2014 at 18:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.