이다 Makefile
:
%.pdf: %.tex
rubber -d $<
doc.tex
디렉토리에 이 있으면 make doc.pdf
빌드합니다 doc.pdf
. 문제는 를 입력할 때 make
자동 완성이 아무것도 제공하지 않는다는 것입니다. 를 자동 완성하는 것도 허용하지 않습니다 make doc.tex
. 그것에 대해 무엇을 할 수 있습니까?
답변1
패키지 bash-completion
는 이 작업을 수행하지 않고 명령줄 옵션을 모두 처리하고 대상 목록을 추출하기 위해 몇 가지 곡예를 수행 Makefile
하지만 와일드카드를 적용하거나 다른 방식으로 처리하여 일치 항목을 생성하려고 시도하지 않습니다.패턴 규칙.
그러나 수행할 수는 있지만 몇 가지 주의 사항이 있는 간단한 버전이 있습니다.
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}
두 부분으로 구성됩니다. 함수는 _mkcache
a에서 모든 규칙과 대상을 추출하고 Makefile
이를 캐시합니다. 또한 약간의 처리를 수행하므로 규칙이 target : pre-req
해당 캐시의 단일 " " 형식으로 단순화됩니다.
그런 다음 완료 함수는 _bc_make
완료를 시도하는 토큰을 가져와 대상과 일치시키려고 시도하며 패턴 규칙을 사용하여 전제 조건과 완료 단어를 기반으로 glob을 확장합니다. 하나 이상의 일치 항목이 발견되면 패턴 규칙을 기반으로 대상 목록을 작성합니다.
GNU make
가 가정됩니다. 다음을 올바르게 처리해야 합니다.
- 대상 및 패턴 규칙(모두는 아니지만 아래 참조)
- 새로운 형태와 기존 형태
.c.o
→%.o : %.c
- 전제조건의 경로(예
RCS/
: ) - 모든 기본 규칙이 있거나 없음( 원하는 경우
-r
추가 )make
주의 사항 및 지원되지 않음:
- 중간 또는 연결된 종속성은 그다지 똑똑하지 않습니다.
make
VPATH
또는vpath
.SUFFIXES
make -C dir
- "archive(member)" 대상, 명시적 또는 암시적
make
옵션 확장- Makefile 구문 분석 문제를 일으킬 수 있는 환경의 병리적 정크(
TERMCAP
예:) - 이외의 이름으로 지정된 Makefile
Makefile
위의 일부 기능은 상대적으로 간단하게 추가할 수 있지만 아카이브 처리와 같은 다른 기능은 그렇게 간단하지 않습니다.