Comandos Linux – Comando make

Comando make do Linux

comando de comando

Nos sistemas operacionais do tipo Unix, o make é um utilitário para criar e manter grupos de programas (e outros tipos de arquivos) a partir do código-fonte.

Este documento cobre a versão GNU / Linux do make .

Descrição

O objetivo do utilitário make é determinar automaticamente quais partes de um programa grande precisam ser recompiladas e emitir os comandos necessários para recompilá-las. Esta documentação descreve a implementação GNU do make , que foi escrita por Richard Stallman e Roland McGrath, e atualmente é mantida por Paul Smith. Muitos dos exemplos listados abaixo mostram programas C , pois são mais comuns, mas você pode usar o make com qualquer linguagem de programação cujo compilador possa ser executado com um comando shell . De fato, make não se limita a programas. Você pode usá-lo para descrever qualquer tarefa em que alguns arquivos devam ser atualizados automaticamente de outros sempre que outros forem alterados.

Para se preparar para usar o make , você deve escrever um arquivo chamado makefile que descreva os relacionamentos entre os arquivos no seu programa e os estados dos comandos para atualizar cada arquivo. Em um programa, normalmente o arquivo executável é atualizado a partir de arquivos de objetos , que são feitos por compilação de arquivos de origem .

Uma vez que existe um makefile adequado, toda vez que você altera alguns arquivos de origem, este comando simples do shell:

  faço

é suficiente para executar todas as recompilações necessárias. O programa make usa o banco de dados makefile e os horários da última modificação dos arquivos para decidir qual dos arquivos precisa ser atualizado. Para cada um desses arquivos, ele emite os comandos registrados no banco de dados.

O make executa comandos no makefile para atualizar um ou mais nomes de destino, onde o nome normalmente é um programa. Se nenhuma opção -f estiver presente, o make procurará os makefiles GNUmakefile , makefile e Makefile , nessa ordem.

Normalmente você deve chamar seu makefile como makefile ou Makefile . (O nome oficialmente recomendado é Makefile porque aparece em destaque próximo ao início de uma lista de diretórios , próximo a outros arquivos importantes, como o README .) O primeiro nome verificado, GNUmakefile , não é recomendado para a maioria dos makefiles . Você deve usar esse nome se tiver um makefile específico para o GNU make e não será entendido por outras versões do make . Se makefile for um traço (”  “), a entrada padrão será lida.

faça das atualizações um destino se depender dos arquivos de pré-requisito que foram modificados desde a última modificação do destino ou se o destino não existir.

Sintaxe

  make [-f makefile ] [ opções ] ... [ destinos ] ...

Opções

-b , -m Essas opções são ignoradas, mas incluídas para compatibilidade com outras versões do make .
-B , – sempre faça Incondicionalmente faça todos os alvos.
-C dir , –directory = dir Mude para o diretório dir antes de ler os makefiles ou fazer qualquer outra coisa. Se várias opções -C forem especificadas, cada uma será interpretada em relação à anterior: -C / -C etc é equivalente a -C / etc. Isso é normalmente usado com invocações recursivas de make .
-d Imprima informações de depuração além do processamento normal. As informações de depuração indicam quais arquivos estão sendo considerados para refazer, quais horários estão sendo comparados e com quais resultados, quais arquivos realmente precisam ser refeitos, quais regras implícitas são consideradas e aplicadas; tudo interessante sobre como fazer decide o que fazer.
–debug [ = BANDEIRAS] Imprima informações de depuração além do processamento normal. Se os FLAGS forem omitidos, o comportamento será o mesmo que se -d fosse especificado. FLAGS pode ser a para todas as saídas de depuração (o mesmo que usar -d ), b para depuração básica, v para depuração básica mais detalhada, i para mostrar regras implícitas, j para detalhes sobre invocação de comandos e m para depuração enquanto refaz makefiles.
-e , – substituições de ambiente Dê variáveis ​​tiradas da precedência do ambiente sobre variáveis ​​de makefiles.
-f arquivo , –file = arquivo , –makefile = arquivo Use o arquivo como um makefile.
-i , –ignore-errors Ignore todos os erros nos comandos executados para refazer os arquivos.
-I dir , –include-dir = dir Especifica um diretório dir para procurar makefiles incluídos. Se várias opções -I forem usadas para especificar vários diretórios, os diretórios serão procurados na ordem especificada. Diferentemente dos argumentos para outros sinalizadores de make , os diretórios fornecidos com os sinalizadores -I podem vir diretamente após o sinalizador: -I dir é permitido, assim como -I dir . Essa sintaxe é permitida para compatibilidade com o sinalizador -I do pré-processador C.
-j [ trabalhos ], –jobs [ = trabalhos ] Especifica o número de tarefas (comandos) a serem executadas simultaneamente. Se houver mais de uma opção -j , a última será efetiva. Se a opção -j for fornecida sem argumento, o make não limitará o número de tarefas que podem ser executadas simultaneamente.
-k , – mantendo-se Continue o máximo possível após um erro. Embora o destino que falhou (e aqueles que dependem dele) não possam ser refeito, as outras dependências desses destinos podem ser processadas da mesma forma.
-l [ carga ], –load-média [ = carga ] Especifica que nenhum novo trabalho (comando) deve ser iniciado se houver outros trabalhos em execução e a média de carga for pelo menos carga (um número de ponto flutuante ). Sem argumento, remove um limite de carga anterior.
-L , –check-symlink-times Use o que for o último horário de modificação entre links simbólicos e destino.
-n , –just-print , –dry-run , –recon Imprima os comandos que seriam executados, mas não os execute.
-o arquivo , –old-arquivo = arquivo , – assume-antigo = arquivo Não refaça o arquivo do arquivo, mesmo que seja mais antigo que suas dependências, e não refaça nada por conta de alterações no arquivo. Essencialmente, o arquivo é tratado como muito antigo e suas regras são ignoradas.
-p , –print-base de dados Imprima o banco de dados (regras e valores variáveis) que resulta da leitura dos makefiles; depois execute como de costume ou conforme especificado. Isso também imprime as informações de versão fornecidas pela opção -v (veja abaixo). Para imprimir o banco de dados sem tentar refazer nenhum arquivo, use make -p -f / dev / null .
-q , –question “Modo de pergunta”. Não execute nenhum comando ou imprima nada; basta retornar um status de saída que seja zero se os destinos especificados já estiverem atualizados, diferente de zero.
-r , –no-builtin-rules Elimine o uso das regras implícitas internas. Além disso, limpe a lista padrão de sufixos para regras de sufixo.
-R , –no-builtin-variables Não defina nenhuma variável interna.
-s , –silent , –quiet Operação silenciosa; não imprima os comandos como eles são executados.
-S , – não continue , – pare Cancele o efeito da opção -k . Isso nunca é necessário, exceto em uma make recursiva em que -k pode ser herdado da make de nível superior via MAKEFLAGS ou se você definir -k em MAKEFLAGS em seu ambiente.
-t , –touch Toque nos arquivos (marque-os atualizados sem realmente alterá-los) em vez de executar seus comandos. Isso é usado para fingir que os comandos foram feitos, para enganar futuras invocações do make .
-v , –version Imprima a versão do make ; também um Copyright, uma lista de autores e um aviso de que não há garantia.
-w , –print-directory Imprima uma mensagem contendo o diretório de trabalho antes e depois de outro processamento. Isso pode ser útil para rastrear erros de ninhos complicados de comandos make recursivos.
–no-print-directory Desative -w , mesmo que tenha sido ativado implicitamente.
-W arquivo , –what-if = arquivo , –novo-arquivo = arquivo , –assume-novo = arquivo Finja que o arquivo de destino acabou de ser modificado. Quando usado com o sinalizador -n , isso mostra o que aconteceria se você modificasse esse arquivo. Sem -n , é quase o mesmo que executar um comando de toque no arquivo fornecido antes de executar o make , exceto que o tempo de modificação é alterado apenas internamente no make .
–warn-undefined-variable Avisar quando uma variável indefinida é referenciada.

Uso típico

make é normalmente usado para criar programas executáveis e bibliotecas a partir do código-fonte. De um modo geral, make é aplicável a qualquer processo que envolva a execução de comandos arbitrários para transformar um arquivo de origem em um resultado de destino. Por exemplo, make pode ser usado para detectar uma alteração feita em um arquivo de imagem (a origem) e as ações de transformação podem ser converter o arquivo em algum formato específico, copiar o resultado em um sistema de gerenciamento de conteúdo e enviar um email a um conjunto predefinido de usuários que as ações acima foram executadas.

make é chamado com uma lista de nomes de arquivos de destino para construir como argumentos da linha de comandos :

  faça [ TARGET ...]

Sem argumentos, make cria o primeiro destino que aparece em seu makefile, que tradicionalmente é um destino chamado all .

make decide se um destino precisa ser regenerado comparando os tempos de modificação do arquivo. Isso resolve o problema de evitar a criação de arquivos que já estão atualizados, mas falha quando um arquivo é alterado, mas seu tempo de modificação permanece no passado. Essas alterações podem ser causadas pela restauração de uma versão mais antiga de um arquivo de origem ou quando um sistema de arquivos da rede é uma fonte de arquivos e seu relógio ou fuso horário não é sincronizado com a máquina que está executando o make . O usuário deve lidar com essa situação forçando uma compilação completa. Por outro lado, se o tempo de modificação de um arquivo de origem estiver no futuro, isso poderá desencadear uma reconstrução desnecessária.

Makefiles

make pesquisa o diretório atual para o makefile usar. O GNU faz pesquisas nos arquivos em busca de um arquivo chamado GNUmakefile , makefile e, em seguida, Makefile , e executa o (s) destino (s) especificado (s) nesse arquivo.

A linguagem makefile é semelhante à programação declarativa, na qual as condições finais necessárias são descritas, mas a ordem na qual as ações devem ser executadas não é importante. Isso pode ser confuso para programadores acostumados à programação imperativa, que descreve explicitamente como o resultado final será alcançado.

Um problema na automação de construção é a adaptação de um processo de construção a uma determinada plataforma . Por exemplo, o compilador usado em uma plataforma pode não aceitar as mesmas opções que o usado em outra. Isso não é bem tratado pela marca por si só. Esse problema geralmente é tratado pela geração de instruções de construção específicas da plataforma, que por sua vez podem ser processadas por make . As ferramentas comuns para esse processo são autoconf e cmake .

Regras

Um makefile consiste essencialmente em regras . Cada regra começa com uma linha de dependência que define um destino seguido por dois pontos (” : “) e, opcionalmente, uma enumeração de componentes (arquivos ou outros destinos) dos quais o destino depende. A linha de dependência é organizada de modo que o alvo (mão esquerda do cólon) dependa dos componentes (mão direita do cólon). É comum se referir aos componentes como pré-requisitos do destino.

  target [ target ...]: [ component ...] [ <TAB> comando 1 ].  .  . 
        [ <TAB> comando n ]

Aqui, <TAB> é o caractere de tabulação. Normalmente, cada regra tem um único destino único, em vez de vários destinos.

Por exemplo, um arquivo de objeto C .o é criado a partir de arquivos .c , portanto, os arquivos .c são os primeiros (ou seja, o destino específico do arquivo de objeto depende de um arquivo de origem C e de arquivos de cabeçalho). Como o próprio make não entende, reconhece ou distingue diferentes tipos de arquivos, isso abre a possibilidade de erro humano. Uma dependência esquecida ou extra pode não ser imediatamente óbvia e resultar em erros sutis no software gerado. É possível escrever arquivos de make que geram essas dependências chamando ferramentas de terceiros, e alguns geradores de makefiles, como o conjunto de ferramentas GNU automake , podem fazê-lo automaticamente.

Após cada linha de dependência, uma série de linhas de comando pode seguir, definindo como transformar os componentes (geralmente arquivos de origem) no destino (geralmente a “saída”). Se algum dos componentes tiver sido modificado, as linhas de comando serão executadas.

Com o GNU make , o primeiro comando pode aparecer na mesma linha após os pré-requisitos, separados por ponto e vírgula:

  metas : pré - requisitos ;  comando

por exemplo:

  Olá: ;  @echo "hello"

Cada linha de comando deve começar com um caractere de tabulação para ser reconhecido como um comando. A guia é um caractere de espaço em branco , mas o caractere de espaço não tem o mesmo significado especial. Isso é problemático, pois pode não haver diferença visual entre uma guia e uma série de caracteres de espaço. Esse aspecto da sintaxe dos makefiles geralmente está sujeito a críticas e é importante anotar.

No entanto, o GNU make (desde a versão 3.82) permite ao usuário escolher qualquer símbolo (um caractere) como prefixo da receita usando a variável especial .RECIPEPREFIX , por exemplo:

  .RECIPEPREFIX: =: all:: @echo "o símbolo do prefixo da receita está definido como '$ (. RECIPEPREFIX)'"

Cada comando é executado por uma instância separada do shell ou do interpretador de linha de comando. Como os sistemas operacionais usam diferentes intérpretes de linha de comando, isso pode levar a makefiles não portáveis. Por exemplo, o GNU make, por padrão, executa comandos com / bin / sh , que é o shell em que comandos do Unix, como o cp, são normalmente usados.

Uma regra pode não ter linhas de comando definidas. A linha de dependência pode consistir apenas em componentes que se referem a destinos, por exemplo:

  realclean: limpo e limpo

As linhas de comando de uma regra geralmente são organizadas para gerar o destino. Um exemplo: se ” file.html ” for mais recente, ele será convertido em texto. O conteúdo do makefile:

  file.txt: file.html lynx -dump file.html> file.txt

A regra acima seria acionada ao fazer as atualizações ” file.txt “.

Na chamada a seguir, o make normalmente usaria essa regra para atualizar o destino ” file.txt ” se ” file.html ” fosse mais recente:

  make file.txt

As linhas de comando podem ter um ou mais dos três prefixos a seguir:

  • um hífen-menos (  ), especificando que os erros são ignorados
  • um sinal de arroba ( @ ), especificando que o comando não é impresso na saída padrão antes de ser executado
  • um sinal de adição ( + ), o comando é executado mesmo que make seja chamado no modo “não executar”

Ignorando erros e silenciando toda a saída de eco também pode ser obtida através dos destinos especiais ” .IGNORE ” e ” .SILENT “, respectivamente.

Macros

Um makefile pode conter definições de macros . As macros geralmente são chamadas de variáveis ​​quando contêm definições simples de cadeia, como ” CC = clang “, que especificaria clang como o compilador C. Macros em makefiles podem ser substituídas nos argumentos da linha de comando passados ​​para o utilitário make . variáveis ​​de ambiente também estão disponíveis como macros.

As macros permitem que os usuários especifiquem os programas invocados e outro comportamento personalizado durante o processo de criação. Por exemplo, como mostrado abaixo, a macro ” CC ” é freqüentemente usada em makefiles para se referir à localização de um compilador C.

Novas macros são tradicionalmente definidas usando letras maiúsculas:

  MACRO = definição

Uma macro é usada expandindo-a. Tradicionalmente, isso é feito colocando seu nome dentro de $ () . Uma forma equivalente usa chaves entre parênteses, ou seja, $ {} , que é o estilo usado nos sistemas operacionais BSD .

  NEW_MACRO = $ ( MACRO ) - $ ( MACRO2 )

As macros podem ser compostas de comandos do shell usando o operador de substituição de comando, indicado por backticks (” ` ` “).

  AAAAMMDD = ` data '

O conteúdo da definição é armazenado “como está”. A avaliação preguiçosa é usada, o que significa que as macros normalmente são expandidas somente quando suas expansões são realmente necessárias, como quando usadas nas linhas de comando de uma regra. Por exemplo:

  PACOTE = pacote
 VERSION = `data +"% Y.% m% d "`
 ARQUIVO = $ (PACOTE) - $ (VERSÃO)
 
 dist:
      # Observe que somente agora as macros são expandidas para o shell interpretar:
      # tar -cf pacote-`data +"% Y% m% d "` .tar
 
 tar -zcf $ (ARQUIVO) .tar.

A sintaxe genérica para substituir macros na linha de comando é:

  make MACRO = " value " [ MACRO = " value " ...] ALVO [ ALVO ...]

Os makefiles podem acessar várias macros internas predefinidas, sendo ” ? ” E ” @ ” as mais comuns.

  target: component1 component2
      eco $?  contém os componentes que precisam de atenção 
              (ou seja, são mais jovens que o TARGET atual).
      echo $@ avalia o nome atual do TARGET dentre os que restam dos dois pontos.

Regras de sufixo

As regras de sufixo têm “destinos” com nomes no formato .FROM.TO e são usadas para iniciar ações com base na extensão do arquivo . Nas linhas de comando das regras de sufixo, o POSIX especifica que a macro interna ” $ < ” se refere ao primeiro pré-requisito e ” $@ ” se refere ao destino. Neste exemplo, que converte qualquer arquivo HTML em texto, o token de redirecionamento de shell ” > ” faz parte da linha de comando, enquanto ” $ < ” é uma macro referente ao arquivo HTML:

  .SUFFIXES: .txt .html
 # De .html a .txt
 .html.txt:
         lynx -dump $ <> $@

Quando chamado a partir da linha de comando, o exemplo acima expande o comando:

  make -n file.txt

para dentro:

  lynx -dump file.html> file.txt

Outros elementos

  • Comentários de linha única são iniciados com o símbolo de hash (” # “).
  • Algumas diretivas em makefiles podem incluir outros makefiles.
  • A continuação da linha é indicada com um caractere de barra invertida (” \ “) no final de uma linha, como no seguinte:
  target: component \
               componente
       Comando <TAB>;  \
       Comando <TAB> |  \
       <TAB> comando canalizado

Status de saída

O GNU faz saídas com o status de:

  • 0 se todos os makefiles foram analisados ​​com sucesso e nenhum destino que foi construído falhou;
  • 1 se o sinalizador -q foi usado e make determina que um destino precisa ser reconstruído; e
  • 2 se algum erro foi encontrado.

Exemplos

Os makefiles são tradicionalmente usados ​​para compilar código ( * .c , * .cc , * .C , etc.), mas também podem ser usados ​​para fornecer comandos para automatizar tarefas comuns.

Aqui está um exemplo de três maneiras de executar make dado um determinado makefile. Os comandos make são listados primeiro e depois o makefile:

  faço

Sem nenhum argumento, o make executará o primeiro alvo;

  fazer ajuda

Quando recebe o argumento de ajuda , o make mostra os alvos disponíveis;

  fazer dist

Quando recebe o argumento dist , o make cria um arquivo de liberação a partir do diretório atual.

Aqui está o makefile para os comandos make acima:

  PACOTE = pacote
 VERSION = `data" +% Y.% m% d% "`
 RELEASE_DIR = ..
 RELEASE_FILE = $ (PACOTE) - $ (VERSÃO)
 # Observe que a variável LOGNAME vem do ambiente em
 # Conchas POSIX.
 #
 # target: all - destino padrão.  Faz nada.
 tudo:
         eco "Olá $ (LOGNAME), nada a fazer por padrão"
         # às vezes: echo "Olá $ {LOGNAME}, nada a fazer por padrão"
         eco "Tente 'fazer ajuda'"
 # target: help - Exibir destinos que podem ser chamados.
 Socorro:
         egrep "^ # target:" [Mm] akefile
 # target: list - lista arquivos de origem
 Lista:
         # Não vai funcionar.  Cada comando está em shell separado
         cd src
         ls
         # Correto, continuação do mesmo shell
         cd src;  \
         ls
 # target: dist - Faça um lançamento.
 dist:
         tar -cf $ (RELEASE_DIR) / $ (RELEASE_FILE) && \
         gzip -9 $ (RELEASE_DIR) / $ (RELEASE_FILE) .tar

A seguir, aqui está um makefile muito simples que, por padrão (a regra ” todos “, que é listada primeiro) compila um arquivo de origem chamado ” helloworld.c ” usando o compilador C do sistema e também fornece um destino ” limpo ” para remover o arquivos gerados se o usuário quiser recomeçar. $@ e $ < são duas macros internas (também conhecidas como variáveis ​​automáticas) que representam o nome do destino e a origem implícita, respectivamente. No exemplo abaixo, $ ^ se expande para uma lista delimitada por espaço dos pré-requisitos.

Aqui está o makefile:

  CFLAGS? = -G
 tudo: helloworld
 helloworld: helloworld.o
         # Comandos começam com TAB, não espaços
         $ (CC) $ (LDFLAGS) -o $@ $ ^
 helloworld.o: helloworld.c
         $ (CC) $ (CFLAGS) -c -o $@ $ <
 limpo: FRC
         rm -f helloworld helloworld.o
 # Este pseudo alvo causa todos os alvos que dependem do FRC
 # a ser refeito, mesmo que exista um arquivo com o nome do destino.
 # Isso funciona com qualquer implementação make sob a suposição de que
 # não há arquivo FRC no diretório atual.
 FRC:

Muitos sistemas vêm com regras e macros predefinidas para especificar tarefas comuns, como compilação com base no sufixo do arquivo. Isso permite que o usuário omita as instruções reais (geralmente não portáveis) de como gerar o destino a partir da (s) fonte (s). Nesse sistema, o makefile acima pode ser modificado da seguinte maneira:

  tudo: helloworld
 helloworld: helloworld.o
     $ (CC) $ (CFLAGS) $ (LDFLAGS) -o $@ $ ^
 limpo: FRC
     rm -f helloworld helloworld.o
 # Esta é uma regra de sufixo explícita.  Pode ser omitido em sistemas
 # que lida com regras simples como essa automaticamente.
 .co:
     $ (CC) $ (CFLAGS) -c $ <
 FRC:
 .SUFIXOS: .c

Usando esse makefile, o fato de ” helloworld.o ” depender de ” helloworld.c ” agora é automaticamente manipulado pelo make . Neste exemplo simples, isso pouco importa, mas o poder real das regras de sufixo se torna evidente quando o número de arquivos de origem em um projeto de software começa a crescer. Só é necessário escrever uma regra para a etapa de vinculação e declarar os arquivos do objeto como pré-requisitos. O make determinará implicitamente como criar todos os arquivos de objeto e buscará alterações em todos os arquivos de origem.

Regras simples de sufixo funcionam bem desde que os arquivos de origem não dependam um do outro e de outros arquivos, como arquivos de cabeçalho. Outra rota para simplificar o processo de construção é usar regras de correspondência de padrões que podem ser combinadas com a geração de dependência assistida por compilador.

O próximo exemplo requer o compilador gcc . É um makefile genérico que compila todos os arquivos C em uma pasta para os arquivos de objeto correspondentes e os vincula ao executável final. Antes da compilação, as dependências são reunidas no formato compatível com makefile em um arquivo oculto ” .depend ” que é incluído no makefile.

  # GNUMakefile genérico
 # Apenas um trecho para parar de executar sob outros comandos make (1)
 # que não entenderá essas linhas
 ifneq (,)
 Este makefile requer o GNU Make.
 fim se
 PROGRAMA = foo
 C_FILES: = $ (curinga * .c)
 OBJS: = $ (patsubst% .c,% .o, $ (C_FILES))
 CC = cc
 CFLAGS = -pedrado na parede
 LDFLAGS =
 tudo: $ (PROGRAM)
 $ (PROGRAMA): .depend $ (OBJS)
     $ (CC) $ (CFLAGS) $ (OBJS) $ (LDFLAGS) -o $ (PROGRAMA)
 depend: .depend
 .depend: cmd = gcc -MM -MF depende de $ (var);  gato depende >> .depend;
 .depender:
     @echo "Gerando dependências ..."
     @ $ (foreach var, $ (C_FILES), $ (cmd))
     @rm -f depend
 -include .depend
 # Estas são as regras de correspondência de padrões.  Além do automático
 # variáveis ​​usadas aqui, a variável $ * que corresponde a qualquer% que significa
 # pode ser útil em casos especiais.
 % .o:% .c
     $ (CC) $ (CFLAGS) -c $ <-o $@
 %:% .c
     $ (CC) $ (CFLAGS) -o $@ $ <
 limpar \ limpo:
     rm -f .depend * .o
 .PHONY: limpo depende

cd – Altere o diretório de trabalho.
sh – O interpretador de comandos do Bourne shell.

Categorias
Compartilhe esse post

Posts populares

Linux Force Security Cursos de linux e segurança da informação

Seu futuro na tecnologia começa agora! Não deixe essa chance escapar.