가능한 대상을 기반으로 자동 완성

가능한 대상을 기반으로 자동 완성

이다 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}

두 부분으로 구성됩니다. 함수는 _mkcachea에서 모든 규칙과 대상을 추출하고 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예:)
  • 이외의 이름으로 지정된 MakefileMakefile

위의 일부 기능은 상대적으로 간단하게 추가할 수 있지만 아카이브 처리와 같은 다른 기능은 그렇게 간단하지 않습니다.

관련 정보