English 中文(简体)
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.

最佳回答

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.

问题回答

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.

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

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

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     $ 
  | 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

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

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




相关问题
makefile: how to show line numbers for debugging?

Is there a way to have make display the line number where it declares an error? The -d switch doesn t seem to cut it. Updated: Example output: Reaping winning child 0x08aa8648 PID 9381 /bin/sh: ...

What is the reasoning behind the Makefile whitespace syntax?

I m revisiting Python after Michael Sparks s excellent walk through of Peter Norvig s Python spell checker at the SO DevDay in London. One of the points he highlighted was how clean Python is to look ...

Debugging GNU make

Is there a command line way in make to find out which of the prerequisites of a target is not updated?

How to add an all rule to this Makefile?

I want to just type make all and have the following Makefile do everything it s supposed to do: LEX = lex YACC = yacc CC = gcc calcu: y.tab.o lex.yy.o $(CC) -o calcu y.tab.o lex.yy.o -ly -lfl ...

How to discover number of *logical* cores on Mac OS X?

How can you tell, from the command line, how many cores are on the machine when you re running Mac OS X? On Linux, I use: x=$(awk /^processor/ {++n} END {print n+1} /proc/cpuinfo) It s not ...

Using extern in C doesn t work as expected

I have created two files: tunables.h #ifndef TUNABLES_H #define TUNABLES_H void tunables_load_conservative(); void tunables_load_aggressive(); extern int timer_x; #endif /*TUNABLES_H */ and ...

热门标签