El Makefile
es:
%.pdf: %.tex
rubber -d $<
Si hay un doc.tex
en el directorio, entonces make doc.pdf
compila doc.pdf
. El problema es que cuando escribo make
, el autocompletado no da nada: ni siquiera permite autocompletar hasta make doc.tex
. ¿Qué se puede hacer al respecto?
Respuesta1
El bash-completion
paquete no hace esto, hace algunas acrobacias para manejar ambas opciones de línea de comando y extraer una lista de Makefile
objetivos, pero no intenta generar coincidencias aplicando comodines ni manejando ningún otroreglas de patrón.
Se puede hacer, sin embargo, aquí hay una versión simple con algunas advertencias.
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}
Hay dos partes, una función _mkcache
extrae todas las reglas y objetivos de a Makefile
y los almacena en caché. También realiza un poco de procesamiento para que las reglas se simplifiquen a un único target : pre-req
formulario " " en ese caché.
Luego, una función de finalización _bc_make
toma el token en el que intenta completarlo e intenta compararlo con los objetivos, y utiliza las reglas del patrón para expandir un globo en función de los requisitos previos y la palabra para completar. Si se encuentran una o más coincidencias, crea una lista de objetivos basada en las reglas del patrón.
make
Se supone GNU . Debe manejar correctamente:
- objetivos y reglas de patrones (aunque no todos, ver más abajo)
- forma nueva y vieja
.c.o
→%.o : %.c
- rutas en requisitos previos (por ejemplo
RCS/
) - con o sin todas las reglas predeterminadas (agregue
-r
simake
lo prefiere)
Advertencias y no admitidos:
- dependencias intermedias o encadenadas, no es tan inteligente como
make
VPATH
ovpath
.SUFFIXES
make -C dir
- Objetivos "archivo (miembro)", explícitos o implícitos
make
expansión de opciones- basura patológica en el entorno que puede causar problemas de análisis de Makefile (
TERMCAP
por ejemplo) - Makefiles con nombres distintos a
Makefile
Algunos de los anteriores se pueden agregar de manera relativamente simple, otros, como el manejo de archivos, no son tan simples.