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

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

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을 확장하여 대상과 일치시키려고 합니다. 하나 이상의 일치 항목이 발견되면 패턴 규칙을 기반으로 대상 목록을 작성합니다.

makeGNU로 가정했습니다. 다음을 올바르게 처리해야 합니다.

  • 목표 및 패턴 규칙(모두는 아니지만 아래 참조)
  • 이전 양식과 새 양식 .c.o%.o : %.c
  • 필수 구성 요소의 경로(예 RCS/: )
  • 모든 기본 규칙이 있거나 없음(원하는 경우 추가할 수 있음 -r)make

경고, 지원되지 않음:

  • 중간 또는 체인 종속성은 다음만큼 좋지 않습니다.make
  • VPATH또는vpath
  • .SUFFIXES
  • make -C dir
  • "archive(member)" 대상, 명시적 또는 암시적
  • make옵션 확장
  • 환경의 병리학적 쓰레기로 인해 Makefile 구문 분석 문제가 발생할 수 있습니다( TERMCAP예:)
  • 다음을 제외하고 이름이 지정된 MakefileMakefile

위의 일부 기능은 비교적 쉽게 추가할 수 있는 반면 다른 것(예: 아카이브 처리)은 그렇게 간단하지 않습니다.

관련 정보