Creating a Makefile

Asked

Viewed 875 times

3

I’m needing to write a Makefile, I was able to configure something by searching, but I tried to improve more for what I need, and I’m not getting it. What I’m trying to do:

1 - Check all files . c or . cpp if they have their equivalents . o

2 - Not having the . o, then create from the file name . c or . cpp, before checking your headers . h or . hpp files

3 - I wanted to do this check not only in one directory, but in several, because my project is divided into folders, all the files in only one folder would be quite disorganized, ie, it do steps 1 and 2 in the current directory and in the subdirectories, in these subdirectories check for directory..., summarizing in the entire project directory and subdirectories.

What I got so far, however I’m getting this error when giving make:

"Makefile:22: *** Missing separator. Stop."(Up 2: Error due "$(COMPILER) -the $@$ " is blank instead of TAB, the Makefile file, recognizes only TAB)

#Compilador
COMPILADOR=g++
#Fontes .c
FONTES=$(wildcard *.c|*.cpp) 
#Headers .h
HEADERS=$(wildcard *.h|*.hpp)

.PHONY: all

all: compilar

#Verifica se os fontes .c possuem seus equivalentes arquivo-objetos .o
#Possuindo, compila e cria o arquivo executavel
compilar: $(FONTES:.c|.cpp=.o)
    $(COMPILADOR) -o $@ $^

#Verifica se os arquivos .c e .cpp, ainda não entendi muito bem aqui
%.o: %.c|%.cpp $(HEADERS)
    $(COMPILADOR) -c $< -o $@

Tutorial on which I based:

https://aulasdec.wordpress.com/2011/07/28/utilitarios-make-makefiles-e-sua-importancia/

Up 1:

I’m still trying; I managed to get the files in their folders, but I’m not able to check the object files of the OBJ folder, because even without file . some in the folder, is compiling and not going to the link code as it should ("Should," of course, if I had written the right code).

#Compilador
COMPILADOR=g++
#Diretorio dos arquivos de programa
PROGRAM=./program
#Diretorio dos arquivos binarios
BIN=./bin
#Diretorio dos arquivos .h e .hpp
INCLUDE=./include
#Diretorio dos arquivos-objetos
OBJ=./obj
#Diretorio dos arquivos .c e .cpp
SRC=./src
#Diretorio dos arquivos de bibliotecas
LIB=./lib

#Para otimizar e mostrar mais avisos
FLAGS= -O3 -Wall
#Para encontrar as bibliotecas utilizadas
LIBS= -lm -L $(LIB)


#Fontes .c
FONTES=$(wildcard $(SRC)/*.cpp) $(wildcard $(SRC)/*\*.c)
#Headers .h
HEADERS=$(wildcard $(INCLUDE)/*.hpp) $(wildcard $(INCLUDE)/*.h)


.PHONY: all

all: linkar
#Verifica se os fontes .c possuem seus equivalentes arquivo-objetos .o
#Possuindo, compila e cria o arquivo executavel
#Porém não está verificando, acredito que meu erro é aqui: 
#"%.%=$(OBJ)/.o"
#Mas não consigo imaginar outra forma de fazer isso
linkar: $(FONTES:%.%=$(OBJ)/.o)
    OBJETOS=$(wildcard $(OBJ)/*.o)
    $(COMPILADOR) $(FLAGS) $(PROGRAM)/programPrincipal.cpp $(OBJETOS) -I $(INCLUDE) -o $(BIN)/arquivoExecutavel

#Aqui compila e gera os .o
%.o: $(SRC)/%.c $(HEADERS) 
    $(COMPILADOR) $(FLAGS) -c $< -I $(INCLUDE) -o $(OBJ)/$@

And a doubt(Up 2: Solved):

1 - You need to put "-I $(INCLUDE)" when compiling and linking, or only when compiling the object-files?

Answer = It is only needed in pre-processing, where the #include is replaced by the code of the file to which it refers. So it’s necessary when I say "Compile" using "g++ -c", it’s actually already preprocessing and compiling each file individually, so it’s necessary, as well as in the linkage, because I’m calling the file. cpp with the "int main" function and if it has organized into separate files, it will have its file . hpp, i.e., it is necessary to "-I $(INCLUDE)" in the two situations where I use g++.

Up 2:

I managed to solve, just change "%. %=$(OBJ)/. o", and further down in the code where you enter again in this question you need the "or":

$(subst .c,.o,$(subst .cpp,.o,$(FONTES)))

However, do not do this, it is not recommended to compile code. c in c++ compilers, errors can occur, of course if the code is very simple, it compiles quietly, but it is better to avoid. If you really need to compile in both languages, create a target for each in the Makefile with its proper compiler. What I decided to do was to compile in the Makefile only c++, as for the codes in c, I preferred to create libraries and refer them in the link.

Link to answer my question about the "or" in the Makefile that helped me: https://stackoverflow.com/questions/44743704/how-to-write-or-inside-dependencies-in-makefile/

Series of videos about Makefile file that also helped me:

https://www.youtube.com/watch?v=0UX9XDkR01E

I’ll leave the code here for if someone has any questions about creating the Makefile:(Up 3: Not functional code below, I just left it here to learn about the error that occurred. The working code is just below Up 3)

########################################
###Script by PerguGames
###GitHub:https://github.com/PerduGames
########################################
#Arquivo Makefile 
#Arquivo para compilar executavel em c++, 
#buscando as dependencias em suas respectivas pastas
#O que acontece quando digito "make"?
#Busca dentro do diretorio atribuido na variavel "SRC" todos os arquivos .cpp
#Muda o sufixo e prefixo de todos os arquivos: "src/*.cpp" para "obj/*.o"
#Compila os arquivos .cpp e cria os arquivos .o no diretorio atribuido na variavel "OBJ"
#Linka e cria o executavel com o nome que você colocou em "coloqueAquiOnomeDoSeuExecutavel",
#buscando primeiro o arquivo principal .cpp no diretorio atribuido na variavel "PROGRAM"
#e buscando as devidas dependecias, bibliotecas e arquivos-objetos que foram criados
#O que acontece quando digito "make run"?
#Executa o programa "coloqueAquiOnomeDoSeuExecutavel",
#O que acontece quando digito "make cleanObjetos"?
#Exclui todos os arquivos .o no diretorio atribuido na variavel "OBJ"
#O que acontece quando digito "make clean"?
#Exclui todos os arquivos no diretorio atribuido na variavel "BIN" que seria seu
#executavel que deu o nome em "coloqueAquiOnomeDoSeuExecutavel"
#O que acontece quando digito "make tar"?
#Empacota todo o diretorio atual onde esta o arquivo makefile com o
#nome que voce substituir em "nomeDeSeuProjeto"
#Notas:
#Lembrem-se ao nomear o executavel em "coloqueAquiOnomeDoSeuExecutavel",
#precisa existir um arquivo .cpp com o mesmo nome no diretorio atribuido 
#na variavel "PROGRAM", para sastisfazer a dependencia do alvo,
#esse arquivo, seria seu arquivo com a funcao "int main()". 

#Compilador
COMPILADOR=g++
#Diretorio dos arquivos de programa
PROGRAM=./program
#Diretorio dos arquivos binarios
BIN=./bin
#Diretorio dos arquivos .h e .hpp
INCLUDE=./include
#Diretorio dos arquivos-objetos
OBJ=./obj
#Diretorio dos arquivos .c e .cpp
SRC=./src
#Diretorio dos arquivos de bibliotecas
LIB=./lib

#Para otimizar e mostrar mais avisos
FLAGS= -O3 -Wall
#Para encontrar as bibliotecas utilizadas(em "-lm", apenas um exemplo, caso seu compilador nao faca isso por voce)
LIBS= -lm -L $(LIB)

#Pega todos arquivos .cpp e muda os nomes para .o
#Fontes .cpp
FONTES=$(wildcard $(SRC)/*.cpp)
#Retirar prefixo e sufixo
OBJLIMPAR=$(notdir $(basename $(FONTES)))
#Adicionar novo prefixo e sufixo
OBJETOS=$(addprefix $(OBJ)/, $(addsuffix .o, $(OBJLIMPAR)))

.PHONY: all cleanObjetos clean tar

all: compilar executaveis

#Arquivos .o do projeto
compilar: $(OBJETOS)

#Executaveis do projeto
executaveis: $(BIN)/coloqueAquiOnomeDoSeuExecutavel
    echo $(OBJETOS)

#Compilar e criar os arquivos-objetos
$(OBJ)/%.o: $(SRC)/%.cpp $(INCLUDE)/%.hpp
    $(COMPILADOR) $(FLAGS) -c $< -I $(INCLUDE) -o $@

#Linkar e criar o executavel
$(BIN)/%: $(PROGRAM)/%.cpp
    $(COMPILADOR) $(FLAGS) $< $(OBJETOS) -I $(INCLUDE) $(LIBS) -o $@

#Executar programa
run:
    $(BIN)/coloqueAquiOnomeDoSeuExecutavel

#Limpar arquivos .o
cleanObjetos:
    rm -f $(OBJ)/*.o

#Limpar executaveis
clean:
    rm -f $(BIN)/%

#Empacotar projeto
tar:
    tar cvjf nomeDeSeuProjeto.tar.bz2 pwd

I have only two questions left:

1 - The code was commented after "/(asterisk)" in the code posted, I could not escape it with " ", there is some way to do this?

2 - It’s right to do this: "g++ archivePrincipal.cpp archive1.o -I include/ -o archiveExecutable", I can compile my main file where the "int main() function is located and at the same time link the object files?

Answer = It is not certain, you will receive an error for not having compiled the.cpp file, maybe not if your files are without content (as happened with me in my test directory), the right is to compile separately before the file. cpp, and then link all the object-files and libraries, to create the executable. Remember that doing so no longer requires "-I $(INCLUDE)" in the linkage part, as all files have already been pre-processed and compiled. Follow the code working in Up 3 below.

Up 3:

Resolved issue, working code answered below.

  • 2-the ideal would be to leave the compilation of object files individually. This makes it easy to maintain the Makefile itself.

  • 1

    But that way it works, right? because I don’t get any errors, and it seems to be all going correctly. But I will create another target then for the compilation of the contents of the folder "PROGRAM" and only Linko on the next target.

  • That is why I spoke ideal; I did not enter into the merit of right or wrong. In fact, the right thing in Makefile is to have targets and commands that transform dependencies into targets. How this is done may be easier to maintain or not, but you’ll be right

  • I thank you for the answer, I will fix here, also I believe that it is more organized to compile before everything, so also dispenses the "-I $(INCLUDE)", since all the files have been pre-processed and compiled.

  • @Jeffersonquesado It would not be ideal, it would be right to compile everything before even, because otherwise he accuses that there is no archivalPrincipal. o, why didn’t you compile the.cpp file.

  • didn’t understand your update. Did you find the answer? If yes, you’d better put it as an answer, because then someone else might ask if you have the same problem

  • 1

    I found, the Up 3 is working perfectly, my last edition was to add a reference link where I had studied on Makefile to get the resolution of the issue, I had forgotten it.

  • great, so this whole up3 part I think should become an answer.

  • I think it would be strange to put it as an answer, the right thing would be to put the question as wiki, it follows learning steps, but I don’t see the option for this.

  • https://stackoverflow.blog/2011/07/01/its-ok-to-ask-and-answer-your-own-questions/

  • I’m even thinking about doing this on mime type on Android :-)

  • There, I put it in response.

Show 7 more comments

1 answer

1


Code link on Github:

https://github.com/PerduGames/Makefile

########################################
###Script by PerguGames
###GitHub:https://github.com/PerduGames
########################################
#Arquivo Makefile 
#Arquivo para compilar executavel em c++, 
#buscando as dependencias em suas respectivas pastas
#O que acontece quando digito "make"?
#Busca dentro do diretorio atribuido na variavel "SRC" todos os arquivos .cpp
#Muda o sufixo e prefixo de todos os arquivos: "src/*.cpp" para "obj/*.o"
#Compila os arquivos .cpp e cria os arquivos .o no diretorio atribuido na variavel "OBJ"
#Linka e cria o executavel com o nome que você colocou na variavel "NOME_EXECUTAVEL",
#buscando as bibliotecas e os arquivos-objetos que foram criados
#O que acontece quando digito "make run"?
#Executa o programa "NOME_EXECUTAVEL",
#O que acontece quando digito "make cleanObjetos"?
#Exclui todos os arquivos .o no diretorio atribuido na variavel "OBJ"
#O que acontece quando digito "make clean"?
#Exclui todos os arquivos no diretorio atribuido na variavel "BIN" que seria seu
#executavel que deu o nome em "NOME_EXECUTAVEL"
#O que acontece quando digito "make tar"?
#Empacota todo o diretorio atual onde esta o arquivo makefile com o
#nome que voce colocou na variavel "NOME_EXECUTAVEL"

#Compilador
COMPILADOR=g++
#Nome do seu executavel
NOME_EXECUTAVEL=nomeDoSeuExecutavel
#Diretorio dos arquivos binarios
BIN=./bin
#Diretorio dos arquivos .h e .hpp
INCLUDE=./include
#Diretorio dos arquivos-objetos
OBJ=./obj
#Diretorio dos arquivos .c e .cpp
SRC=./src
#Diretorio dos arquivos de bibliotecas
LIB=./lib

#Para otimizar e mostrar mais avisos
FLAGS= -O3 -Wall
#Para encontrar as bibliotecas utilizadas(em "-lm", apenas um exemplo, caso seu compilador nao faca isso por voce)
LIBS= -lm -L $(LIB)

#Pega todos arquivos .cpp e muda os nomes para .o
#Fontes .cpp
FONTES=$(wildcard $(SRC)/*.cpp)
#Retirar prefixo e sufixo
OBJLIMPAR=$(notdir $(basename $(FONTES)))
#Adicionar novo prefixo e sufixo
OBJETOS=$(addprefix $(OBJ)/, $(addsuffix .o, $(OBJLIMPAR)))

.PHONY: all cleanObjetos clean tar

all: compilar $(NOME_EXECUTAVEL)

#Arquivos .o do projeto
compilar: $(OBJETOS)

#Compilar e criar os arquivos-objetos
$(OBJ)/%.o: $(SRC)/%.cpp $(INCLUDE)/%.hpp
    $(COMPILADOR) $(FLAGS) -c $< -I $(INCLUDE) -o $@

#Linkar e criar o executavel
$(NOME_EXECUTAVEL): $(OBJETOS)
    $(COMPILADOR) $(FLAGS) $(OBJETOS) $(LIBS) -o $(BIN)/$@

#Executar programa
run:
    $(BIN)/$(NOME_EXECUTAVEL)

#Limpar arquivos .o
cleanObjetos:
    rm -f $(OBJ)/*.o

#Limpar executavel
clean:
    rm -f $(BIN)/$(NOME_EXECUTAVEL)

#Empacotar projeto
tar:
    tar cvjf $(NOME_EXECUTAVEL).tar.bz2 pwd

Browser other questions tagged

You are not signed in. Login or sign up in order to post.