Assim como um arquivo de código contém uma ou mais linhas de código como conteúdo para valer a pena, o makefile básico é construído usando variáveis, regras e alvos. Fora isso, existem outros fatores que são necessários para fazer um makefile completo sem problemas. Neste guia, discutiremos a sintaxe básica do makefile e os problemas comuns ao escrever um makefile e forneceremos soluções para resolver esses problemas.
Compreendendo a sintaxe básica do Makefile
Para começar a criar um makefile, explicamos as propriedades básicas de um makefile por meio do exemplo de código makefile. É necessário incluir as seguintes propriedades de sintaxe no conteúdo do makefile para obter um arquivo executável:
Variável s: Dados básicos que armazenam objetos que são necessários para serem usados no makefile. Essas variáveis são utilizadas para especificar um compilador, sinalizadores, arquivos de origem, arquivos de objeto e arquivos de destino. Dentro do makefile de exemplo a seguir, há um total de cinco variáveis que são CXX (para definir um compilador C++), CXXFLAGSc (sinalizadores do compilador), TARGET (para definir um nome de arquivo executável de destino), SRCS (para definir um arquivo de código-fonte) , OBJS (para conter os arquivos objeto que são gerados por meio do arquivo de código-fonte).
Alvos: Uma saída esperada para construir a partir da fonte. Pode ser um arquivo alvo ou qualquer nome simbólico: “all” é o alvo padrão que deve ser construído através da variável “TARGET”, “$TARGET” depende das variáveis “OBJS”, e o alvo “limpo” remove o alvo e arquivos de objeto do diretório de trabalho.
Regras e comandos de construção: Conjunto de instruções básicas a serem executadas para criar um destino a partir do arquivo de origem ou dependências. Por exemplo, a regra “%.o: %.cpp” mostra que o arquivo com extensão “cpp” é usado para criar um arquivo objeto com extensão “o” enquanto ambos os arquivos contêm o mesmo nome. Por outro lado, o comando build $(CXX) $(CXXFLAGS) -o $(TARGET) $(OBJS) é utilizado para vincular um arquivo objeto e um novo arquivo de destino. Da mesma forma, o comando build $(CXX) $(CXXFLAGS) -c $< -o $@ compila o arquivo de origem em um arquivo objeto.
Dependências: As dependências estão sempre presentes quando você deseja criar um makefile. Por exemplo, o alvo “todos” depende da variável “TARGET” enquanto o “TARGET” depende da variável “OBJS”. Ao mesmo tempo, a variável “OBJS” depende do arquivo fonte através da variável “SRCS”.
Comentários: Instruções compreensíveis geralmente são usadas para explicar a finalidade da linha de código caso você esteja usando um arquivo após um longo período de tempo. No makefile a seguir, utilizamos os comentários começando com o sinal “#” para explicar cada linha.
CXX = g++
CXXBANDEIRAS = -std =c++ onze -Parede
ALVO = Novo
SRCS = principal.cpp
OBJS = $ ( SRCS:.cpp=.o )
tudo: $ ( ALVO )
$ ( ALVO ) : $ ( OBJS )
$ ( CXX ) $ ( CXXFLAGS ) -o $ ( ALVO ) $ ( OBJS )
% .o: % .cpp
$ ( CXX ) $ ( CXXFLAGS ) -c $ < -o $ @
limpar:
rm -f $ ( ALVO ) $ ( OBJS )
Problemas e soluções comuns
Ao escrever qualquer makefile, é necessário considerar cada pequeno detalhe para obter a saída desejada no final. Alguns problemas comuns são frequentemente encontrados pelos usuários ao criar um makefile. Nesta seção, discutiremos essas questões e sugeriremos as possíveis soluções da seguinte forma:
1: Não usando variáveis
Usar as variáveis em um makefile é obrigatório, pois é necessário para definir os compiladores, destino, arquivos de origem, etc. O problema mais comum que pode ser encontrado é não usar nenhuma variável em um makefile. Portanto, certifique-se de utilizar as variáveis essenciais como CXX, CXXFLAGSc (sinalizadores do compilador), TARGET, SRCS e OBJS no makefile de amostra anterior.
2: Problema de separador ausente
Ao escrever um makefile, é necessário considerar as regras de indentação com muito cuidado, pois usar espaços em vez de tabulações levará você a um problema de “separador ausente” durante a execução da instrução “make”. Por exemplo, adicionamos o espaço no início de uma regra na linha 13 e removemos a tabulação.
$ ( ALVO ) :$ ( OBJS )$ ( CXX ) $ ( CXXFLAGS ) -o $ ( ALVO ) $ ( OBJS )
Após a execução da consulta “make”, obtemos um erro de “separador ausente” na linha 13 e a execução do arquivo para. Para evitar esse problema, certifique-se de usar “tab” em vez de espaços.
fazer
Para evitar esse problema, certifique-se de usar “tab” em vez de espaços, conforme mostrado na imagem a seguir:
$ ( ALVO ) :$ ( OBJS )$ ( CXX ) $ ( CXXFLAGS ) -o $ ( ALVO ) $ ( OBJS )
3: Problema de “ponto de entrada não encontrado”
Este erro ocorre principalmente devido ao arquivo fonte e não por causa do makefile, como quando você perde o uso da função “main()” no arquivo de código fonte. Por exemplo, substituímos a definição da função main() por uma simples declaração de função definida pelo usuário.
#includeshow interno ( ) {
caractere v;
std::cout << 'Insira um valor:' ;
std::cin >> em;
std::cout << em << std::endl;
retornar 0 ;
}
Ao executar a instrução “make” no prompt de comando do Windows, encontramos a “referência indefinida para ‘WinMain’”. Isso ocorre porque o compilador não encontra nenhum ponto de entrada para iniciar a execução do arquivo C++. Para resolver isso, substitua “show” por “main”.
4: Uso de extensões incorretas
Às vezes, um usuário pode usar involuntariamente extensões erradas para um arquivo de origem a ser usado no makefile. Usar a extensão errada levará a erros de tempo de execução, ou seja, nenhuma regra para definir um alvo. Criamos um makefile para construir o arquivo executável e objeto para o arquivo C++. Na sétima linha, fornecemos o arquivo fonte com extensão “c”.
CXX := g++CXXFLAGS := -std =c++ onze -Parede
ALVO = novo
SRCS = principal.c
OBJS = $ ( SRCS:.cpp=.o )
Todos: $ ( ALVO )
$ ( ALVO ) : $ ( OBJS )
A execução da instrução “make” nos leva ao erro “Nenhuma regra para criar o alvo ‘main.c’”. Para evitar esse problema, certifique-se de usar a extensão de arquivo de origem correta.
fazer
5: Dependências ausentes
Ao escrever um makefile, você deve incluir todas as dependências de um arquivo de origem para obter a saída desejada. Por exemplo, nosso arquivo de código C++ usa o arquivo “myheader.h” como dependência. Portanto, mencionamos isso no arquivo de código C++ da seguinte forma:
#include#include “meuheader.h”
show interno ( ) {
caractere v;
std::cout << 'Insira um valor:' ;
std::cin >> em;
std::cout << em << std::endl;
retornar 0 ;
}
Dentro do makefile, ignoramos intencionalmente o uso do arquivo “myheader.h” dentro da regra de construção escrita na linha 9.
% .o: % .cpp$ ( CXX ) $ ( CXXFLAGS ) -c $ < -o $ @
Agora, ao usar a instrução “make”, encontramos o erro “Nada a ser feito para ‘todos’”.
fazer% .o: % .cpp meucabeçalho.h
$ ( CXX ) $ ( CXXFLAGS ) -c $ < -o $ @
Para evitar esse problema e executar o código-fonte com sucesso, mencione o nome do arquivo “myheader.h” na nona linha do makefile, conforme descrito a seguir:
Conclusão
Neste guia, explicamos detalhadamente a sintaxe do makefile usando seus conteúdos necessários, como variáveis, comandos de construção, regras, etc. No final, discutimos alguns problemas regulares e suas soluções que um usuário pode encontrar ao criar um makefile.