Como você obtém a lista de destinos em um makefile?


202

Eu usei o rake um pouco (um programa Ruby make) e tem uma opção para obter uma lista de todos os destinos disponíveis, por exemplo

> rake --tasks
rake db:charset      # retrieve the charset for your data...
rake db:collation    # retrieve the collation for your da...
rake db:create       # Creates the databases defined in y...
rake db:drop         # Drops the database for your curren...
...

mas parece não haver opção para fazer isso no GNU make.

Aparentemente, o código está quase lá para ele em 2007 - http://www.mail-archive.com/help-make@gnu.org/msg06434.html .

Enfim, fiz pouco hack para extrair os alvos de um makefile, que você pode incluir em um makefile.

list:
    @grep '^[^#[:space:]].*:' Makefile

Ele fornecerá uma lista dos destinos definidos. É apenas um começo - não filtra as dependências, por exemplo.

> make list
list:
copy:
run:
plot:
turnin:

2
Leio rapidamente as respostas, que são interessantes, mas até agora prefiro mantê-lo claro, simples e portátil usando um alias (no meu .bashrc): alias makefile-targets='grep "^[^#[:space:]].*:" Makefile' Na maioria das vezes, só preciso examinar o makefile atual e a conclusão do bash se expande meu apelido.
rocky road


4
É muito trivial apenas grep : Makefile:?
cibercitizen1

Respostas:


130

Esta é uma tentativa de melhorar a excelente abordagem do @ nobar da seguinte maneira:

  • usa um comando mais robusto para extrair os nomes de destino, o que, esperançosamente, evita quaisquer falsos positivos (e também elimina o desnecessário sh -c)
  • invariavelmente não tem como alvo o makefile no diretório atual ; respeita makefiles explicitamente especificados com-f <file>
  • exclui alvos ocultos - por convenção, são alvos cujo nome não começa com uma letra nem um dígito
  • se contentar com um único alvo falso
  • prefixa o comando com @para impedir que ele seja ecoado antes da execução

Curiosamente, o GNU makenão tem nenhum recurso para listar apenas os nomes dos destinos definidos em um makefile. A -popção produz resultados que incluem todos os destinos, mas os enterram em muitas outras informações.

Coloque a seguinte regra em um makefile para o GNU makeimplementar um destino nomeado listque simplesmente lista todos os nomes de destinos em ordem alfabética - ie: invoke asmake list :

.PHONY: list
list:
    @$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | egrep -v -e '^[^[:alnum:]]' -e '^$@$$'

Importante : Ao colar isso, verifique se a última linha é recuada com exatamente 1 caractere de tabulação real. (espaços não funcionam) .

Observe que a classificação da lista de destinos resultante é a melhor opção, pois a não classificação não produz uma ordem útil, pois a ordem na qual os destinos aparecem no makefile não é preservada.
Além disso, os subalvos de uma regra que compreende vários destinos são sempre emitidos separadamente e, portanto, devido à classificação, geralmente não são aparecem próximos um do outro; por exemplo, uma regra que começa com a z:o não têm metas ae zlistados ao lado do outro na saída, se houver alvos adicionais.

Explicação da regra :

  • .PHONY: list
    • declara a lista de alvos um alvo falso, ou seja, aquele que não se refere a um arquivo , que deve, portanto, ter sua receita invocada incondicionalmente
  • $(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null

    • Invoca makenovamente para imprimir e analisar o banco de dados derivado do makefile:
      • -p imprime o banco de dados
      • -Rr suprime a inclusão de regras e variáveis ​​internas
      • -qapenas testa o status atualizado de um destino (sem refazer nada), mas isso por si só não impede a execução de comandos de receita em todos os casos; conseqüentemente:
      • -f $(lastword $(MAKEFILE_LIST))garante que o mesmo makefile seja direcionado como na invocação original, independentemente de ter sido direcionado implícita ou explicitamente -f ....
        Advertência : Isso será interrompido se o seu makefile contiver includediretivas; Para resolver isso, defina a variável THIS_FILE := $(lastword $(MAKEFILE_LIST)) antes de qualquer includediretiva e use -f $(THIS_FILE).
      • :é um destino deliberadamente inválido que visa garantir que nenhum comando seja executado ; 2>/dev/nullsuprime a mensagem de erro resultante. Nota: Isso depende da -pimpressão do banco de dados, no entanto, como é o caso do GNU make 3.82. Infelizmente, o GNU make não oferece opção direta para apenas imprimir o banco de dados, sem também executar a tarefa padrão (ou fornecida); se você não precisar segmentar um Makefile específico, poderá usá-lo make -p -f/dev/null, conforme recomendado na manpágina.
  • -v RS=

    • Este é um idioma awk que divide a entrada em blocos de linhas não vazias contíguas.
  • /^# File/,/^# Finished Make data base/
    • Corresponde ao intervalo de linhas na saída que contém todos os destinos (verdadeiro no GNU make 3.82) - limitando a análise a esse intervalo, não há necessidade de lidar com falsos positivos de outras seções de saída.
  • if ($$1 !~ "^[#.]")
    • Ignora seletivamente os blocos:
      • # ... ignora não-alvos, cujos blocos começam com # Not a target:
      • . ... ignora alvos especiais
    • Todos os outros blocos devem começar com uma linha contendo apenas o nome de um destino definido explicitamente seguido por :
  • egrep -v -e '^[^[:alnum:]]' -e '^$@$$' remove destinos indesejados da saída:
    • '^[^[:alnum:]]' ... exclui oculto alvos , que - por convenção - são alvos que não começam com uma letra nem um dígito.
    • '^$@$$' ... exclui o list próprio alvo

A corrida make listentão imprime todos os destinos, cada um em sua própria linha; você pode canalizar para xargscriar uma lista separada por espaço.


Essa é uma ótima resposta, no entanto, como obteria a descrição para cada tarefa? Atualmente, estou armazenando-o como um comentário acima da definição da tarefa. Não tem certeza se é possível incluí-lo na lista de maneira semelhante ao rake --tasksque é?
Piotr Kuczynski

1
@PiotrKuczynski: Pergunta interessante, mas sugiro que você a publique como uma nova pergunta (apontando para esta como referência).
mklement0

"Infelizmente, o GNU make não oferece opção direta apenas para imprimir o banco de dados." Existe uma -nopção.
Bulletmagnet

@ Bulletmagnet: O objetivo da -nopção é "Imprimir os comandos que seriam executados ..." - em outras palavras: um recurso de execução a seco. Também não é que sua citação esteja faltando o itálico da palavra apenas : make -ppor si imprime o banco de dados, mas invariavelmente também executa a tarefa padrão ; o manual recomenda o desajeitado make -p -f/dev/nullpara evitar isso.
Mklement0

1
Também irá listar todos os alvos .PHONY, para se certificar que você não tem.PHONY: *
tekumara

189

Em Bash (pelo menos), isso pode ser feito automaticamente com a conclusão da guia:

make spacetabtab


1
Testado: bash --version = 4.2.45 (1) -release. make --version = 3,81.
No2

53
+1, mas observe que esse não é um recurso do bash , mas depende da sua plataforma . As plataformas se enquadram em três categorias: aquelas em que esta conclusão é instalada por padrão (por exemplo, Debian 7, Fedora 20), aquelas em que você pode instalá-lo opcionalmente (por exemplo, Ubuntu 14, com . /etc/bash_completion) e aquelas que não são compatíveis com ela. (por exemplo, OSX 10.9)
mklement0

8
Ele funciona no OS X 10.10 (não com o bash, mas com o zsh).
Florian Oswald

4
Ótima dica, mas também precisa de bash-completionpacote. Encontrado no Fedora, RHEL, Gentoo, ect.
precisa saber é o seguinte

4
Isso não funciona com os destinos de criação criados programaticamente, como AFAICT, por exemplo$(RUN_TARGETS): run-%: ...
Matthias

32

Obviamente, isso não funcionará em muitos casos, mas se o seu Makefilefoi criado pelo CMake, você poderá executá-lo make help.

$ make help
The following are some of the valid targets for this Makefile:
... all (the default if no target is provided)
... clean
... depend
... install
etc

Você tem alguma opção para ativar seu CMakeList para obter isso? Eu tenho um makefile gerado pelo CMake e eu não tenho o alvo pseudo ajuda disponível
Xavier T.

Não. No OSX, pelo menos com um CMake recente (na verdade, estou usando todas as noites, mas acredito que quando escrevi isso estava usando o 3.3), basta executar touch CMakeLists.txt && cmake . && make helpe deve funcionar. Só posso supor que você está usando um cmake antigo ou não está usando o gerador Unf Makefiles?
Timmmm

Estou usando o CMake 3.6.2 com gerador unix no Windows. Vou procurar uma explicação, porque parece útil.
Xavier T.

26

Combinei essas duas respostas: https://stackoverflow.com/a/9524878/86967 e https://stackoverflow.com/a/7390874/86967 e escapei para que isso pudesse ser usado dentro de um makefile.

.PHONY: no_targets__ list
no_targets__:
list:
    sh -c "$(MAKE) -p no_targets__ | awk -F':' '/^[a-zA-Z0-9][^\$$#\/\\t=]*:([^=]|$$)/ {split(\$$1,A,/ /);for(i in A)print A[i]}' | grep -v '__\$$' | sort"

.

$ make -s list
build
clean
default
distclean
doc
fresh
install
list
makefile ## this is kind of extraneous, but whatever...
run

10
Também descobri (recentemente) que o preenchimento de guias no Bash listará os destinos disponíveis.
Nobar

1
+1 para uma ótima abordagem, mas algumas melhorias poderiam ser feitas: (a) especificar explicitamente sh -c "…"é desnecessário, porque é o que, makepor padrão, usa para chamar comandos de receita; (b) o comando que você usa é muito simplista, resultando em falsos positivos (como você observa); (c) se você prefixar o comando @, ele não será ecoado para stdout antes da execução, evitando a necessidade de usar -sna invocação.
mklement0

1
há um alvo de criação muito mais simples que você pode adicionar: list: cat Makefile | grep "^ [Az]" | awk '{print $$ 1}' | sed "s /: // g | sort"
thamster 16/10

2
A abordagem cat / sed falha em vários níveis. Ele não expande variáveis ​​e também falha na lista de destinos resultantes da inclusão de outros arquivos.
Troy Daniels

1
@ mklement0: Prefiro usar make -s(por meio de um alias do Bash) em vez de prefixar comandos no makefile @. Existem alguns casos em que @podem ser úteis, principalmente como prefixo de echocomandos (onde a exibição do comando seria redundante), mas em geral eu não gosto de usá-lo. Dessa forma, posso ver as "receitas" quando preciso ( não usando -s), mas não normalmente. Aqui está a documentação relacionada: GNU Make Manual, 5.2 Eco de receita .
Nobar

14

Se você tiver a conclusão do bash makeinstalada, o script de conclusão definirá uma função _make_target_extract_script. Esta função visa criar um sedscript que pode ser usado para obter os destinos como uma lista.

Use-o assim:

# Make sure bash completion is enabled
source /etc/bash_completion 

# List targets from Makefile
sed -nrf <(_make_target_extract_script --) Makefile

3
Útil, mas observe que nem todas as plataformas possuem script /etc/bash_completione / ou função _make_target_extract_script- você parece estar no Ubuntu> 12. Se você mirar em /usr/share/bash-completion/completions/makevez disso, sua abordagem funcionará em plataformas adicionais, como o Fedora 20. Existem plataformas (mais antigas) que possuem este arquivo, mas não a função (por exemplo, Debian 7 e Ubuntu 12); outras plataformas, como OSX, não vêm com o preenchimento de guias make. Talvez postar a definição real da função seja útil.
mklement0

1
Obrigado por seu comentário. Isso é muito apreciado. Sim, eu testei isso no Ubuntu 14.04
hek2mgl 13/10

11

Como mklement0 aponta , um recurso para listar todos os destinos Makefile está faltando no GNU-make, e sua resposta e outras fornecem maneiras de fazer isso.

No entanto, a postagem original também menciona rake , cujas tarefas mudam algo ligeiramente diferente do que apenas listar todas as tarefas no arquivo rake. O Rake fornecerá apenas uma lista de tarefas que têm descrições associadas. Tarefas sem descrições não serão listadas . Isso permite ao autor fornecer descrições personalizadas da ajuda e também omitir a ajuda para determinados destinos.

Se você deseja imitar o comportamento do rake, onde fornece descrições para cada destino , existe uma técnica simples para fazer isso: incorpore descrições nos comentários para cada destino que você deseja listar.

Você pode colocar a descrição ao lado do destino ou, como costumo fazer, ao lado de uma especificação PHONY acima do destino, assim:

.PHONY: target1 # Target 1 help text
target1: deps
    [... target 1 build commands]

.PHONY: target2 # Target 2 help text
target2:
    [... target 2 build commands]

...                                                                                                         

.PHONY: help # Generate list of targets with descriptions                                                                
help:                                                                                                                    
    @grep '^.PHONY: .* #' Makefile | sed 's/\.PHONY: \(.*\) # \(.*\)/\1 \2/' | expand -t20

Qual trará

$ make help
target1             Target 1 help text
target2             Target 2 help text

...
help                Generate list of targets with descriptions

Você também pode encontrar um exemplo de código curto nesta lista e aqui também.

Novamente, isso não resolve o problema de listar todos os destinos em um Makefile. Por exemplo, se você tem um grande Makefile que talvez tenha sido gerado ou que alguém escreveu, e você deseja uma maneira rápida de listar seus destinos sem procurar, isso não ajudará.

No entanto, se você estiver escrevendo um Makefile e desejar gerar uma forma de texto de ajuda de maneira consistente e auto-documentável, essa técnica poderá ser útil.


Essa é uma ótima técnica - agradável e simples, mas também fornece descrições!
Brian Burns

Ótima técnica. Modifiquei isso um pouco para usar o echocomando como descrição do comando ( stackoverflow.com/a/52059487/814145 ).
Penghe Geng

@PengheGeng Obrigado pelo post. Quero deixar claro que @echo "Target 1"é apenas um espaço reservado e não um "comando de eco de descrição". O texto de ajuda gerado não é proveniente do @echo. Em um Makefile real, eles echoseriam substituídos por um comando de construção ou algo parecido. Vou editar a postagem para deixar isso mais claro.
JSP

5

Minha resposta favorita foi postada por Chris Down no Unix e Linux Stack Exchange. Vou citar.

É assim que o módulo de conclusão do bash makeobtém sua lista:

make -qp | awk -F':' '/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split($1,A,/ /);for(i in A)print A[i]}'

Ele imprime uma lista de destinos delimitados por nova linha, sem paginação.

O usuário Brainstone sugere canalizar sort -upara remover entradas duplicadas:

make -qp | awk -F':' '/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split($1,A,/ /);for(i in A)print A[i]}' | sort -u

Fonte: Como listar todos os destinos no make? (Unix e Linux SE)


4

A resposta do @ nobar mostra útil como usar o preenchimento de guias para listar os destinos de um makefile .

  • Isso funciona muito bem para plataformas que fornecem essa funcionalidade por padrão (por exemplo, Debian, Fedora ).

  • Em outras plataformas (por exemplo, Ubuntu ), você deve carregar explicitamente essa funcionalidade, como está implícito na resposta de @ hek2mgl :

    • . /etc/bash_completion instala várias funções de preenchimento de guias, incluindo a make
    • Como alternativa, instale apenas o preenchimento de guias para make:
      • . /usr/share/bash-completion/completions/make
  • Para plataformas que não oferecem essa funcionalidade , como o OSX , você pode originar os seguintes comandos (adaptados daqui ) para implementá-la:
_complete_make() { COMPREPLY=($(compgen -W "$(make -pRrq : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($1 !~ "^[#.]") {print $1}}' | egrep -v '^[^[:alnum:]]' | sort | xargs)" -- "${COMP_WORDS[$COMP_CWORD]}")); }
complete -F _complete_make make
  • Nota: Isso não é tão sofisticado quanto a funcionalidade de preenchimento de guias que vem com as distribuições Linux: mais notavelmente, ele invariavelmente direciona o makefile no diretório atual , mesmo que a linha de comando direcione um makefile diferente -f <file>.

4

Focando uma sintaxe fácil para descrever um destino de criação e ter uma saída limpa, escolhi esta abordagem:

help:
    @grep -B1 -E "^[a-zA-Z0-9_-]+\:([^\=]|$$)" Makefile \
     | grep -v -- -- \
     | sed 'N;s/\n/###/' \
     | sed -n 's/^#: \(.*\)###\(.*\):.*/\2###\1/p' \
     | column -t  -s '###'


#: Starts the container stack
up: a b
  command

#: Pulls in new container images
pull: c d 
    another command

make-target-not-shown:

# this does not count as a description, so leaving
# your implementation comments alone, e.g TODOs
also-not-shown:

Portanto, tratar o acima como um Makefile e executá-lo fornece algo como

> make help
up          Starts the container stack
pull        Pulls in new container images

Explicação para a cadeia de comandos:


Solução muito boa. Eu tenho usado isso há alguns anos agora: awk -F ':|##' '/^[^\t].+:.*##/ { printf "\033[36mmake %-28s\033[0m -%s\n", $$1, $$NF }' $(MAKEFILE_LIST) | sort com ##o comentário anterior na mesma linha do alvo. Mas acho que sua solução permite antes a legibilidade.
thoroc 9/03

Um makefile composto pelos dois primeiros relatórios de linhas grep: parentheses not balancedna minha máquina OSX 10.15.
Malcolm Crum

@ Crummy desculpe, meu erro. Obrigado por apontar isso. Corrigido. make exige escapar de cifrões que não devem iniciar nomes de variáveis.
Richard Kiefer

Cuidado, o StackOverflow converte guias em espaços ao exibir as seções de código acima, mas os Makefiles exigem guias. Você pode editar a postagem e copiar as seções, para manter as guias.
Richard Kiefer

2

Muitas soluções viáveis ​​aqui, mas como eu gosto de dizer, "se vale a pena fazer uma vez, vale a pena fazer novamente". Votei na sugestão de usar (guia) (guia), mas, como alguns observaram, talvez você não tenha suporte para a conclusão ou, se houver muitos arquivos incluídos, convém uma maneira mais fácil de saber onde um destino está definido.

Eu não testei o abaixo com sub-marcas ... Eu acho que não iria funcionar. Como sabemos, as recursivas são consideradas prejudiciais.

.PHONY: list ls
ls list :
    @# search all include files for targets.
    @# ... excluding special targets, and output dynamic rule definitions unresolved.
    @for inc in $(MAKEFILE_LIST); do \
    echo ' =' $$inc '= '; \
    grep -Eo '^[^\.#[:blank:]]+.*:.*' $$inc | grep -v ':=' | \
    cut -f 1 | sort | sed 's/.*/  &/' | sed -n 's/:.*$$//p' | \
    tr $$ \\\ | tr $(open_paren) % | tr $(close_paren) % \
; done

# to get around escaping limitations:
open_paren := \(
close_paren := \)

Que eu gosto porque:

  • aliste destinos por arquivo de inclusão.
  • definições de destino dinâmico bruto de saída (substitui delimitadores de variáveis ​​por módulo)
  • gerar cada destino em uma nova linha
  • parece mais claro (opinião subjetiva)

Explicação:

  • foreach arquivo no MAKEFILE_LIST
  • produz o nome do arquivo
  • linhas grep contendo dois pontos, que não são recuados, não comentam e não começam com um ponto
  • excluir expressões de atribuição imediata (: =)
  • cortar, classificar, recuar e cortar dependências de regras (após dois pontos)
  • delimitadores variáveis ​​do munge para impedir a expansão

Saída de amostra:

 = Makefile = 
  includes
  ls list
 = util/kiss/snapshots.mk = 
  rotate-db-snapshots
  rotate-file-snapshots
  snap-db
  snap-files
  snapshot
 = util/kiss/main.mk = 
  dirs
  install
   %MK_DIR_PREFIX%env-config.php
   %MK_DIR_PREFIX%../srdb

1

Este foi útil para mim, porque eu queria ver os alvos de compilação necessários (e suas dependências) pelo make make. Eu sei que criar alvos não pode começar com um "." personagem. Não sei quais idiomas são suportados, então fui com as expressões entre colchetes do egrep.

cat Makefile | egrep "^[[:alnum:][:punct:]]{0,}:[[:space:]]{0,}[[:alnum:][:punct:][:space:]]{0,}$"

1

Isso está longe de ser limpo, mas fez o trabalho para mim.

make -p 2&>/dev/null | grep -A 100000 "# Files" | grep -v "^$" | grep -v "^\(\s\|#\|\.\)" | grep -v "Makefile:" | cut -d ":" -f 1

Eu uso make -pque despeja o banco de dados interno, ditch stderr, use um rápido e sujo grep -A 100000para manter a parte inferior da saída. Depois, limpo a saída com algumas grep -ve finalmente uso cutpara obter o que está antes dos dois pontos, a saber, os alvos.

Isso é suficiente para meus scripts auxiliares na maioria dos meus Makefiles.

EDIT: adicionado grep -v Makefileque é uma regra interna


1

Esta é uma modificação da resposta muito útil do jsp ( https://stackoverflow.com/a/45843594/814145 ). Gosto da ideia de obter não apenas uma lista de alvos, mas também suas descrições. O Makefile do jsp coloca a descrição como o comentário, que eu achei muitas vezes repetido no comando echo da descrição do alvo. Então, em vez disso, extraio a descrição do comando echo para cada destino.

Makefile de exemplo:

.PHONY: all
all: build
        : "same as 'make build'"

.PHONY: build
build:
        @echo "Build the project"

.PHONY: clean
clean:
        @echo "Clean the project"

.PHONY: help
help:
        @echo -n "Common make targets"
        @echo ":"
        @cat Makefile | sed -n '/^\.PHONY: / h; /\(^\t@*echo\|^\t:\)/ {H; x; /PHONY/ s/.PHONY: \(.*\)\n.*"\(.*\)"/    make \1\t\2/p; d; x}'| sort -k2,2 |expand -t 20

Saída de make help:

$ make help
Common make targets:
    make all        same as 'make build'
    make build      Build the project
    make clean      Clean the project
    make help       Common make targets

Notas:

  • Igual à resposta do jsp , apenas alvos PHONY podem ser listados, o que pode ou não funcionar para o seu caso
  • Além disso, lista apenas os destinos PHONY que possuem um comando echoou :como o primeiro comando da receita. :significa "não fazer nada". Eu o uso aqui para os alvos em que nenhum eco é necessário, comoall destino acima.
  • Há um truque adicional para o helpdestino adicionar o ":" na make helpsaída.

0

Mais uma resposta adicional acima.

testado no MacOSX usando apenas cat e awk no terminal

cat Makefile | awk '!/SHELL/ && /^[A-z]/ {print $1}' | awk '{print substr($0, 1, length($0)-1)}'

irá produzir o arquivo make como abaixo:

target1

target2

target3

no Makefile, deve ser a mesma instrução, assegure-se de que você escape das variáveis ​​usando $$ variable em vez de $ variable.

Explicação

gato - cospe o conteúdo

| - pipe analisa a saída para o próximo awk

awk - executa regex excluindo "shell" e aceitando apenas linhas "Az" e depois imprime a primeira coluna $ 1

awk - mais uma vez remove o último caractere ":" da lista

esse é um resultado difícil e você pode fazer coisas mais descoladas com apenas AWK. Tente evitar o sed, pois não é tão consistente nas variantes do BSDs, ou seja, alguns funcionam no * nix, mas falham nos BSDs como o MacOSX.

Mais

Você deve poder adicionar isso (com modificações) a um arquivo para make , na pasta padrão de conclusão do bash /usr/local/etc/bash-completion.d/, o que significa quando você "cria a guia tab ". destinos com base no script de um liner.


você também pode usar make -qp em vez de cat. então ele se tornará make -qp | awk '/: / &&! /: = / && / ^ [Az] / &&! / PATH / &&! / DISPLAY / &&! / TERM_SESSION / &&! / USER_TEXT_ENCODING / &&! / Makefile / {print substr ($ 0, 1 , comprimento ($ 0) -1) | "sort -u"} '
Jimmy MG Lim

0

Eu costumo fazer:

grep install_targets Makefile

Voltaria com algo como:

install_targets = install-xxx1 install-xxx2 ... etc

Eu espero que isso ajude


0

Para um script Bash

Aqui está uma maneira muito simples de fazer isso bash- com base no comentário de @ cibercitizen1 acima :

grep : Makefile | awk -F: '/^[^.]/ {print $1;}'

Veja também a resposta mais autorizada de @ Marc.2377, que diz como faz o módulo de conclusão do Bash make.


-4

Não sei por que a resposta anterior foi tão complicada:

list:
    cat Makefile | grep "^[A-z]" | awk '{print $$1}' | sed "s/://g" 

8
A resposta anterior é tão complicada, porque abrange todos os cenários que sua resposta NÃO abrange: (a) inclusão de metas definidas por meio de variáveis (por exemplo, $(SHELLS): ...), (b) inclusão de metas que começam com um dígito, (c) não inclusão de definições de variáveis ; (d) visando o makefile adequado, se makeespecificado com um caminho explícito do makefile. (a) é a falha crucial: mesmo que você tenha como alvo confiável o makefile correto , a análise do arquivo bruto não funcionará no caso geral, devido à falta de expansão variável.
mklement0

6
Como um aparte, re complicado: o seu comando pode ser simplificada para a seguinte -, mas o ponto principal é que não é o suficiente robusta : awk -F: '/^[A-z]/ {print $$1}' Makefile. Finalmente, um ponto amplamente acadêmico: usar, em [A-z]vez de, [:alpha:]significa que você perderá alvos que começam com um personagem estrangeiro como á.
mklement0

@ mklement0 Seu primeiro comando do awk funciona bem, e é o mais simples até agora, embora usar [: alpha:] pareça quebrá-lo por algum motivo - ele perde alguns alvos em um arquivo de teste.
Brian Burns

@ bburns.km: Meu ruim: eu deveria ter dito [[:alpha:]], em vez de [:alpha:]( [:alpha:]representa o conjunto locale-aware de letras dentro de uma classe de caracteres ( [...]), daí a necessidade efetiva de duplo [[ / ]].
mklement0

4
Por que essa resposta é tão complicada? Você consegue coletar vários pecados inúteis neste pequeno trecho. awk -F: '/^[A-Za-z]/ { print $$1 }' Makefileusa um único processo e, esperançosamente, uma expressão regular mais correta (embora você possa, obviamente, ter alvos com sublinhados, números etc. também, como observado nos comentários anteriores).
tripleee
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.