Difference between revisions of "Complete roguelike tutorial using C++ and libtcod - extra 4: makefiles"

From RogueBasin
Jump to navigation Jump to search
(pasted →‎top: , cat and sidebar)
 
Line 10: Line 10:


Note that with the current size of the project, you won't see much difference in compilation times, but the gain will get bigger and bigger as your project grows.
Note that with the current size of the project, you won't see much difference in compilation times, but the gain will get bigger and bigger as your project grows.
==A 11 lines makefile==
So we will create a "makefile" file in our project root directory. We start by determining the list of sources files for the project :
SOURCES=$(wildcard src/*.cpp)
SOURCES will contain a space separated list of filenames : src/Actor.cpp src/Ai.cpp ...
From this variable, we deduce the list of .o files by replacing .cpp with .o :
OBJS=$(SOURCES:.cpp=.o)
Now we're going to tell make how to generate the tuto file. The problem is that the flags for the linker depend on the operating system. So we're using the uname -s shell command to detect if we're on Linux or Windows :
ifeq ($(shell sh -c 'uname -s'),Linux)
  LIBFLAGS=-L. -ltcod_debug -ltcodxx_debug -Wl,-rpath=.
else
  LIBFLAGS=-Llib -ltcod-mingw-debug -static-libgcc -static-libstdc++
endif
Now we can write our first compilation rule :
tuto : $(OBJS)
    g++ $(OBJS) -o tuto -Wall $(LIBFLAGS) -g
It's important to use your final .exe as the first rule in the makefile because it's what make will build when you run it without parameter.
We're telling make that the target named 'tuto' depends on all .o files. Or rather : if a .o file is modified, we need to execute the commands associated with the tuto target. This command is the linking phase of the compilation, using g++ to link all .o files together.
'''It's important for make to work that the command line starts with a tabulation.'''
Ok now make knows how to generate tuto (or tuto.exe on Windows), but not how to get the .o files. Let's tell him.
src/%.o : src/%.cpp
    g++ $< -c -o $@ -Iinclude -Wall -g
This is a generic rule, telling that any src/xxx.o file is depending on src/xxx.cpp. When src/xxx.cpp is modified, we call the command below :
g++ $< -c -o $@ -Iinclude -Wall -g
We're using two make automatic variables here :
$@ represent the current target (src/xxx.o)
$< represent the current target's dependencies (src/xxx.cpp)
So the executed command will be :
g++ src/xxx.cpp -c -o src/xxx.o -Iinclude -Wall -g
The -c flag tells g++ to generate the object file, but not try to link it into an executable.
That's it. This is a tiny makefile but it does the job, compiling the project on both Windows/Mingw and Linux :
SOURCES=$(wildcard src/*.cpp)
OBJS=$(SOURCES:.cpp=.o)
ifeq ($(shell sh -c 'uname -s'),Linux)
  LIBFLAGS=-L. -ltcod_debug -ltcodxx_debug -Wl,-rpath=.
else
  LIBFLAGS=-Llib -ltcod-mingw-debug -static-libgcc -static-libstdc++ -mwindows
endif
tuto : $(OBJS)
    g++ $(OBJS) -o tuto -Wall $(LIBFLAGS) -g
src/%.o : src/%.cpp
    g++ $< -c -o $@ -Iinclude -Wall -g
Now type 'make' in your terminal and check that it actually builds the game. Now open one of the cpp files and save it, then run make again. Only this cpp file is compiled. Even better, delete all src/*.o files and type
make -j4
to compile the project using 4 threads.




[[Category:Developing]]
[[Category:Developing]]

Revision as of 13:09, 23 October 2015

Complete roguelike tutorial using C++ and libtcod
-originally written by Jice
Text in this tutorial was released under the Creative Commons Attribution-ShareAlike 3.0 Unported and the GNU Free Documentation License (unversioned, with no invariant sections, front-cover texts, or back-cover texts) on 2015-09-21.


This article will show you how to use a makefile to speed up compilation. If you're using an IDE, you probably don't need this, except if you want to port your application to an OS where your IDE is not available. As with gdb, even if there are better alternatives, it's always useful to know how to quickly setup a makefile for your project.

There are several ways a makefile will speed up compilation compared to recompiling everything every time with a single g++ command line :

  • we will generate an intermediate .o file for each .cpp source file, then link all .o files together to get the executable. When a single cpp file is modified, we only need to recompile its .o and link the new executable.
  • using the same idea, we can generate an intermediate file for a header. This is called a precompiled header and uses the .gch extension. As long as you don't modify a header, the compiler will be able to use this precompiled header instead of re-parsing them.
  • finally, make can use multi-threading to compile several .cpp files at the same time.

Note that with the current size of the project, you won't see much difference in compilation times, but the gain will get bigger and bigger as your project grows.

A 11 lines makefile

So we will create a "makefile" file in our project root directory. We start by determining the list of sources files for the project :

SOURCES=$(wildcard src/*.cpp)

SOURCES will contain a space separated list of filenames : src/Actor.cpp src/Ai.cpp ... From this variable, we deduce the list of .o files by replacing .cpp with .o :

OBJS=$(SOURCES:.cpp=.o)

Now we're going to tell make how to generate the tuto file. The problem is that the flags for the linker depend on the operating system. So we're using the uname -s shell command to detect if we're on Linux or Windows :

ifeq ($(shell sh -c 'uname -s'),Linux)
  LIBFLAGS=-L. -ltcod_debug -ltcodxx_debug -Wl,-rpath=.
else
  LIBFLAGS=-Llib -ltcod-mingw-debug -static-libgcc -static-libstdc++
endif

Now we can write our first compilation rule :

tuto : $(OBJS)
   g++ $(OBJS) -o tuto -Wall $(LIBFLAGS) -g

It's important to use your final .exe as the first rule in the makefile because it's what make will build when you run it without parameter. We're telling make that the target named 'tuto' depends on all .o files. Or rather : if a .o file is modified, we need to execute the commands associated with the tuto target. This command is the linking phase of the compilation, using g++ to link all .o files together. It's important for make to work that the command line starts with a tabulation.

Ok now make knows how to generate tuto (or tuto.exe on Windows), but not how to get the .o files. Let's tell him.

src/%.o : src/%.cpp
   g++ $< -c -o $@ -Iinclude -Wall -g

This is a generic rule, telling that any src/xxx.o file is depending on src/xxx.cpp. When src/xxx.cpp is modified, we call the command below :

g++ $< -c -o $@ -Iinclude -Wall -g

We're using two make automatic variables here :

$@ represent the current target (src/xxx.o)

$< represent the current target's dependencies (src/xxx.cpp)

So the executed command will be :

g++ src/xxx.cpp -c -o src/xxx.o -Iinclude -Wall -g

The -c flag tells g++ to generate the object file, but not try to link it into an executable.

That's it. This is a tiny makefile but it does the job, compiling the project on both Windows/Mingw and Linux :

SOURCES=$(wildcard src/*.cpp)
OBJS=$(SOURCES:.cpp=.o)
ifeq ($(shell sh -c 'uname -s'),Linux)
  LIBFLAGS=-L. -ltcod_debug -ltcodxx_debug -Wl,-rpath=.
else
  LIBFLAGS=-Llib -ltcod-mingw-debug -static-libgcc -static-libstdc++ -mwindows
endif
tuto : $(OBJS)
   g++ $(OBJS) -o tuto -Wall $(LIBFLAGS) -g
src/%.o : src/%.cpp
   g++ $< -c -o $@ -Iinclude -Wall -g

Now type 'make' in your terminal and check that it actually builds the game. Now open one of the cpp files and save it, then run make again. Only this cpp file is compiled. Even better, delete all src/*.o files and type

make -j4

to compile the project using 4 threads.