Das Makefile
ist:
%.pdf: %.tex
rubber -d $<
doc.tex
Wenn sich im Verzeichnis ein befindet , make doc.pdf
wird erstellt doc.pdf
. Das Problem ist, dass die Autovervollständigung nichts ausgibt, wenn ich eingebe make
: Sie erlaubt nicht einmal die automatische Vervollständigung bis make doc.tex
. Was kann man dagegen tun?
Antwort1
Das bash-completion
Paket tut dies nicht, es führt einige akrobatische Tricks aus, um sowohl Befehlszeilenoptionen zu verarbeiten als auch eine Liste von Makefile
Zielen zu extrahieren, aber es versucht nicht, Übereinstimmungen durch die Anwendung von Platzhaltern oder die sonstige Verarbeitung vonMusterregeln.
Es ist jedoch möglich. Hier ist eine einfache Version mit einigen Einschränkungen.
function _mkcache() {
local _file="$1"
# add "-r" to omit defaults (60+ rules)
${MAKE:-make} ${_file:+-f "$_file"} -qp 2>/dev/null |
gawk '/^# *Make data base/,/^# *Finished Make data base/{
if (/^# Not a target/) { getline; next }
## handle "target: ..."
if (match($0,/^([^.#% ][^:%=]+) *:($|[^=])(.*)/,bits)) {
#if (bits[3]=="") next # OPT: skip phony
printf("%s\n",bits[1])
}
## handle "%.x [...]: %.y [| x]", split into distinct targets/prereqs
else if (match($0,/^([^:]*%[^:]*) *(::?) *(.*%.*) *(\| *(.*))?/,bits)) {
#if (bits[3]=="%") next # OPT: skip wildcard ones
nb1=split(bits[1],bb1)
nb3=split(bits[3],bb3)
for (nn=1; nn<=nb1; nn++)
for (mm=1; mm<=nb3; mm++)
printf("%s : %s\n",bb1[nn],bb3[mm])
}
## handle fixed (no %) deps
else if (match($0,/^([^:]*%[^:]*) *(::?) *([^%]*)$/,bits)) {
if (bits[3]=="") next # phony
printf("%s : %s\n",bits[1],bits[3])
}
## handle old form ".c.o:" rewrite to new form "%.o: %.c"
else if (match($0,/^\.([^.]+)\.([^.]+): *(.*)/,bits)) {
printf("%%.%s : %%.%s\n", bits[2],bits[1])
}
}' > ".${_file:-Makefile}.targets"
}
function _bc_make() {
local ctok=${COMP_WORDS[COMP_CWORD]} # curr token
local ptok=${COMP_WORDS[COMP_CWORD-1]} # prev token
local -a mkrule maybe
local try rr lhs rhs rdir pat makefile=Makefile
## check we're not doing any make options
[[ ${ctok:0:1} != "-" && ! $ptok =~ ^-[fCIjloW] ]] && {
COMPREPLY=()
[[ "$makefile" -nt .${makefile}.targets ]] &&
_mkcache "$makefile"
mapfile -t mkrule < ".${makefile}.targets"
# mkrule+=( "%.o : %.c" ) # stuff in extra rules
for rr in "${mkrule[@]}"; do
IFS=": " read lhs rhs <<< $rr
## special "archive(member):"
[[ "$lhs" =~ ^(.*)?\((.+)\) ]] && {
continue # not handled
}
## handle simple targets
[[ "$rhs" == "" ]] && {
COMPREPLY+=( $(compgen -W "$lhs" -- "$ctok" ) )
continue
}
## rules with a path, like "% : RCS/%,v"
rdir=""
[[ "$rhs" == */* ]] && rdir="${rhs/%\/*/}/"
rhs=${rhs/#*\//}
## expand (glob) that matches RHS
## if current token already ends in a "." strip it
## match by replacing "%" stem with "*"
[[ $ctok == *. ]] && try="${rdir}${rhs/\%./$ctok*}" \
|| try="${rdir}${rhs/\%/$ctok*}"
maybe=( $(compgen -G "$try") ) # try must be quoted
## maybe[] is an array of filenames from expanded prereq globs
(( ${#maybe[*]} )) && {
[[ "$rhs" =~ % ]] && {
## promote rhs glob to a regex: % -> (.*)
rhs="${rhs/./\\.}"
pat="${rdir}${rhs/\%/(.*)}"
## use regex to extract stem from RHS, sub "%" on LHS
for nn in "${maybe[@]}"; do
[[ $nn =~ $pat ]] && {
COMPREPLY+=( "${lhs/\%/${BASH_REMATCH[1]}}" )
}
done
} || {
# fixed prereqs (no % on RHS)
COMPREPLY+=( "${lhs/\%/$ctok}" )
}
}
done
return
}
COMPREPLY=() #default
}
complete -F _bc_make ${MAKE:-make}
Es gibt zwei Teile: Eine Funktion _mkcache
extrahiert alle Regeln und Ziele aus einem Makefile
und speichert diese im Cache. Sie führt auch einige Verarbeitungsvorgänge durch, sodass die Regeln target : pre-req
in diesem Cache zu einer einzigen " "-Form vereinfacht werden.
Anschließend nimmt eine Vervollständigungsfunktion _bc_make
das Token, für das Sie eine Vervollständigung versuchen, und versucht, es mit Zielen abzugleichen. Anschließend verwendet sie die Musterregeln, um einen Glob basierend auf den Voraussetzungen und dem Wort für die Vervollständigung zu erweitern. Wenn eine oder mehrere Übereinstimmungen gefunden werden, wird basierend auf den Musterregeln eine Liste mit Zielen erstellt.
GNU make
wird vorausgesetzt. Es sollte korrekt handhaben:
- Ziele und Musterregeln (allerdings nicht alle, siehe unten)
- neue und alte Form
.c.o
→%.o : %.c
- Pfade in Voraussetzungen (zB
RCS/
) - mit oder ohne alle Standardregeln ( ggf.
-r
ergänzen )make
Einschränkungen und nicht unterstützt:
- Zwischen- oder Kettenabhängigkeiten, es ist nicht so intelligent wie
make
VPATH
odervpath
.SUFFIXES
make -C dir
- „archive(member)“-Ziele, explizit oder implizit
make
Optionenerweiterung- pathologischer Müll in der Umgebung, der Probleme bei der Makefile-Analyse verursachen kann (
TERMCAP
zum Beispiel) - Makefiles mit anderen Namen als
Makefile
Einige der oben genannten Punkte können relativ einfach hinzugefügt werden, andere, wie beispielsweise die Archivverwaltung, sind nicht so einfach.