Compreendendo a sintaxe do Makefile: problemas e soluções comuns (incluindo ‘operador ausente’ e ‘ponto de entrada não encontrado’)

Compreendendo A Sintaxe Do Makefile Problemas E Solucoes Comuns Incluindo Operador Ausente E Ponto De Entrada Nao Encontrado



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.

#include
show 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.