Writing programs using SDL with linux and Makefiles
Author |
Message |
md
|
Posted: Sat Nov 26, 2005 8:32 pm Post subject: Writing programs using SDL with linux and Makefiles |
|
|
Since a quick google will provide lots of help for linux users of SDL I'm not going to cover that at all. Linux on the other hand is a completely different story; it's not extremely difficult to figure it out on your own but it can be a pain in the ass.
Disclaimer: There are many different linux distributions and many different ways of getting the job done. I use gentoo and gnome, so that's what will be used in this tutorial; however there shouldn't be any major differences if you use something else.
Installing SDL
Installing SDL is actually pretty strait forward, the easiest way is to download the tarball and extract it to a folder you find convienent.
Getting SDL wrote:
mkdir -p ~SDL//libsdl
cd ~/SDL/libsdl
wget http://www.libsdl.org/release/SDL-1.2.9.tar.gz
tar -xvjpf SDL-1.2.9.tar.gz
** note you can get the file though Firefox or any other web browser and extract it however you wish. wget and tar are just quick and easy
Now that we've got the source code it's just a simple ./configure, make, make install away! However therin lies the first challenge. In order to run make install you must have root privileges; the simplest way to do that would be using su or sudo, since I don't have sudo I use su. Since we don't need to be root to compile anything it's safer to wait until we need to run make install to become root, and we'll go back to being a normal user once we're done.
Installing wrote:
./configure
make
su
make install
exit
There! Done just like that! The problem is that this gets you only the very basic libraries. To make things a lot more useful we'll also get the SDL_image library too
Get and install SDL_image wrote:
mkdir ~/SDL/SDL_image
cd ~/SDL/SDL_image
wget http://www.libsdl.org/projects/SDL_image/release/SDL_image-1.2.4.tar.gz
tar -xvjpf SDL_image-1.2.4.tar.gz
./configure
make
su
make install
exit
Setting up a Project
When I say project I mean a project as an idea; not in some IDE or anything. I find that if I create a simple directory-tree to keep my source and object files organized it helps me keep track of things much easier. For this tutorial we're going to name our project "SDL_Test", and we're going to store all it's files in ~/SDL_Test.
Creating the 'Project' wrote:
mkdir ~/SDL_Test
cd ~/SDL_Test
mkdir Build
mkdir Source
It's fairly simple; source code goes in Source, the compiled code will go in Build. If your project requires lots of other resourses (sounds, graphics) create another directory to store them in. That way you can keep things seperated and easy to find. Since we only have one image it's easiest just to store it in the base directory
A directory structure is nice and all, but it isn't much of a program. So what we now need to do is write some code. We're going to have two files: main.cpp which will contain our main function, and global.h which will contain any includes we want to be assessible in any additional files we might want to add later. Both get saved in Source
Source/main.cpp
c++: |
#include "global.h"
int main (int argc, char **argv)
{
// initialize SDL
SDL_Init(SDL_INIT_VIDEO);
// set the title bar
SDL_WM_SetCaption("SDL Test", "SDL Test");
// create window
SDL_Surface* screen = SDL_SetVideoMode(640, 480, 0, 0);
/* load bitmap to temp surface */
SDL_Surface* temp = IMG_Load("hello.png");
/* convert bitmap to display format */
SDL_Surface* bg = SDL_DisplayFormat(temp);
/* free the temp surface */
SDL_FreeSurface(temp);
SDL_Event event;
int gameover = 0;
/* message pump */
while (!gameover)
{
/* look for an event */
if (SDL_PollEvent(&event))
{
/* an event was found */
switch (event.type)
{
/* close button clicked */
case SDL_QUIT:
gameover = 1;
break;
/* handle the keyboard */
case SDL_KEYDOWN:
switch (event.key.keysym.sym)
{
case SDLK_ESCAPE:
case SDLK_q:
gameover = 1;
break;
}
break;
}
}
/* draw the background */
SDL_BlitSurface(bg, NULL, screen, NULL);
/* update the screen */
SDL_UpdateRect(screen, 0, 0, 0, 0);
}
/* free the background surface */
SDL_FreeSurface(bg);
// cleanup SDL
SDL_Quit();
return 0;
}
|
Source/global.h
c++: |
#include <iostream>
// SDL
#include <SDL.h>
#include <SDL_image.h>
|
Makefiles
We've got source code; we've got libraries. Surely we can just call the compiler directly and not worry about these makefile things right? Of course we can, but then what happens if you add another file? Or two? Or 20? It quickly becomes a nightmare to remember all those filenames and type them all just to compile a small change. Makefiles to the rescue!
A makefile allows you to say what files depend on what and how t obuild them, and then when you want to recompile after a small change only the things that need to be will be recompiled. So now when you change one file out of your 20 it'll only take a second or two to compile instead of the minute or more that all 20 might take.
There are lots of guides on writing makefiles on the web, and makefiles are WAY beyond my ability to write a thorough tutorial on, but for my projects I've written one makefile which is easy to extend and very straitforward
Makefile
code: |
#
# Default make file
#
########
# Directories
S_DIR=Source
B_DIR=Build
########
# Output
EXEC=$(B_DIR)/SDL_test.exec
# default build settings
## debug setup
CC_OPTS=-c -pipe -Wall -Wno-switch -ggdb -g3
LN_OPTS=
CC=g++
## release setup
#C_OPTS=-c -pipe
#LN_OPTS=
#CC=g++
########
# SDL options
CC_SDL=-I/usr/local/include/SDL -D_REENTRANT
LN_SDL=-L/usr/local/lib -Wl,-rpath,/usr/local/lib -lSDL -lSDL_image -lpthread
########
# This is the default action
all:Build
########
# Object list
#
OBJ = $(B_DIR)/main.o
########
# Objects
$(B_DIR)/main.o : $(S_DIR)/main.cpp $(S_DIR)/global.h
$(CC) $(CC_OPTS) -o $(B_DIR)/main.o $(S_DIR)/main.cpp $(CC_SDL)
########
# Main build rule
Build : $(OBJ) Makefile
$(CC) $(LN_OPTS) -o $(EXEC) $(OBJ) $(LN_SDL)
clean:
rm -f $(B_DIR)/*
|
Now... it looks really complex and to be fair it kinda is; but a little bit of info makes it useful.
First we have our source and build directories. We set S_DIR and B_DIR because you could technically name your directories whatever you wanted, and S_DIR and B_DIR are nice and short.
Next up is the name of finished compiled program, though you can call it whatever I usually add .exec so I know that it's easy to tell it's an executable.
Then there are three important variables that are best left alone. CC_OPTS are compile options, LN_OPTS are link options, and CC is the compiler/linker. CC_OPTS and LN_OPTS are just standard options for whatever you choose as your compiler (here we're using g++, the GNU C++ compiler).
The SDL Options are taken from the ouput of sdl-config --cflags --libs. The output should look something like code: | john@sax ~/SDL_Test $ sdl-config --cflags --libs
-I/usr/local/include/SDL -D_REENTRANT
-L/usr/local/lib -Wl,-rpath,/usr/local/lib -lSDL -lpthread
| The first line is where we get our SDL_CC line from, the second SDL_LN; they are the SDL include directory and SDL libraries and library directories respectively. We add -lSDL_image to the linker because the SDL_image library is also used.
The rest of the file is instructions on what to build. The important parts are OBJ= which is a space seperated list of all the object files you have rules for, and the section listed as Objects. The OBJ list is quite simple, basically there should be a *.o for every source file you have. Object files (*.o) will be saved to the build directory so we need to put $(B_DIR) (the build directory shortcut) in from of each object file name.
In the Objects grouping things are a little more complex. Each f=source file has two lines, one which specifies what it depends on, and one to say how to build it.
code: |
$(B_DIR)/main.o : $(S_DIR)/main.cpp $(S_DIR)/global.h | Says that the object file main.o relies on main.cpp and global.h. If either main.cpp or global.h have changed since the last time we compiled recompile main.o.
code: | $(CC) $(CC_OPTS) -o $(B_DIR)/main.o $(S_DIR)/main.cpp $(CC_SDL) | Says how to compile.
To add aditional files all you need to do is add the file to the OBJ list and copy/modify the lines for main.o; main.o becomes <filename.o>, main.cpp becomes <filename>.cpp, and any other required files go on the end of the first line just like $(S_DIR)/global.h
After that all that's left is the step for building the executable, it doesn't require any changes, and the command to clean all the intermediate files. The makefile given will work for out SDL_Test project without any modifications.
Compiling and testing
At this point it's actually pretty trivial; to compile we just need to type "make" in the base directory, and then to run the executable we just type "Build/SDL_Test.exec". We also need to copy a png file (any png file!) to the base directory or the program won't run right. Here's the commands:
Compiling nad Running wrote:
make
Build/SDL_Test
And the output:
Conclusions
Setting up SDL really isn't that difficult once you figure it out, and once you get a working makefile it's really easy to keep things working. Hopefully this will inspire some more people to check out SDL and/or linux
resources
http://www.libsdl.org SDL site |
|
|
|
|
|
Sponsor Sponsor
|
|
|
|
|