예 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을 확장하여 대상과 일치시키려고 합니다. 하나 이상의 일치 항목이 발견되면 패턴 규칙을 기반으로 대상 목록을 작성합니다.
make
GNU로 가정했습니다. 다음을 올바르게 처리해야 합니다.
- 목표 및 패턴 규칙(모두는 아니지만 아래 참조)
- 이전 양식과 새 양식
.c.o
→%.o : %.c
- 필수 구성 요소의 경로(예
RCS/
: ) - 모든 기본 규칙이 있거나 없음(원하는 경우 추가할 수 있음
-r
)make
경고, 지원되지 않음:
- 중간 또는 체인 종속성은 다음만큼 좋지 않습니다.
make
VPATH
또는vpath
.SUFFIXES
make -C dir
- "archive(member)" 대상, 명시적 또는 암시적
make
옵션 확장- 환경의 병리학적 쓰레기로 인해 Makefile 구문 분석 문제가 발생할 수 있습니다(
TERMCAP
예:) - 다음을 제외하고 이름이 지정된 Makefile
Makefile
위의 일부 기능은 비교적 쉽게 추가할 수 있는 반면 다른 것(예: 아카이브 처리)은 그렇게 간단하지 않습니다.