Autovervollständigung in Make basierend auf möglichen Zielen

Autovervollständigung in Make basierend auf möglichen Zielen

Das Makefileist:

%.pdf: %.tex
    rubber -d $<

doc.texWenn sich im Verzeichnis ein befindet , make doc.pdfwird erstellt doc.pdf. Das Problem ist, dass die Autovervollständigung nichts ausgibt, wenn ich eingebe make: Sie erlaubt nicht einmal die automatische Vervollständigung bis make doc.tex. Was kann man dagegen tun?

Antwort1

Das bash-completionPaket tut dies nicht, es führt einige akrobatische Tricks aus, um sowohl Befehlszeilenoptionen zu verarbeiten als auch eine Liste von MakefileZielen zu extrahieren, aber es versucht nicht, Übereinstimmungen durch die Anwendung von Platzhaltern oder die sonstige Verarbeitung vonMusterregeln.

Es ist jedoch möglich. Hier ist eine einfache Version mit einigen Einschränkungen.

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}

Es gibt zwei Teile: Eine Funktion _mkcacheextrahiert alle Regeln und Ziele aus einem Makefileund speichert diese im Cache. Sie führt auch einige Verarbeitungsvorgänge durch, sodass die Regeln target : pre-reqin diesem Cache zu einer einzigen " "-Form vereinfacht werden.

Anschließend nimmt eine Vervollständigungsfunktion _bc_makedas Token, für das Sie eine Vervollständigung versuchen, und versucht, es mit Zielen abzugleichen. Anschließend verwendet sie die Musterregeln, um einen Glob basierend auf den Voraussetzungen und dem Wort für die Vervollständigung zu erweitern. Wenn eine oder mehrere Übereinstimmungen gefunden werden, wird basierend auf den Musterregeln eine Liste mit Zielen erstellt.

GNU makewird vorausgesetzt. Es sollte korrekt handhaben:

  • Ziele und Musterregeln (allerdings nicht alle, siehe unten)
  • neue und alte Form .c.o%.o : %.c
  • Pfade in Voraussetzungen (zB RCS/)
  • mit oder ohne alle Standardregeln ( ggf. -rergänzen )make

Einschränkungen und nicht unterstützt:

  • Zwischen- oder Kettenabhängigkeiten, es ist nicht so intelligent wiemake
  • VPATHodervpath
  • .SUFFIXES
  • make -C dir
  • „archive(member)“-Ziele, explizit oder implizit
  • makeOptionenerweiterung
  • pathologischer Müll in der Umgebung, der Probleme bei der Makefile-Analyse verursachen kann ( TERMCAPzum Beispiel)
  • Makefiles mit anderen Namen alsMakefile

Einige der oben genannten Punkte können relativ einfach hinzugefügt werden, andere, wie beispielsweise die Archivverwaltung, sind nicht so einfach.

verwandte Informationen