Sample SFML statically linked Windows C++ application built with MinGW and SCons

Before we get started, let’s state some assumptions and also cover WHY I wanted to do this for myself:

First, assumptions:

  • You already have SCons installed and working on Windows and know the basics of using it. I’m excluding the details in this post because I’m sure SCons own site will do a better job of getting you started with that: http://www.scons.org/
  • You don’t have MinGW installed yet (you can, but you’ll need the specific version linked in this tutorial).
  • You don’t have SFML installed yet (see above parenthesis).

Now, why bother doing this:
The main reason is that I LOVE USING SCONS. I have no quantifiable reason other than I’ve used it, and I love it. So instead of using Visual Studio or Code::Blocks, I’ve based my programming environment around using SCons. I like to program in a unix environment much more than a Windows environment. However, I want to program Windows games because for all the Microsoft hate you want to spew, Gaming on Windows > Gaming on Mac. At least it is for the type of gamer I am. Windows gamers are just ‘my kind of people’ and I want to make games that they might enjoy.

After attempting some fairly elaborate setups with VirtualBox running Windows on OSX and using the OSX terminal I found there were just too many gotcha’s when it came to diving into bare bolts OpenGL and that while VirtualBox is pretty amazing, the full end-user experience for testing your game just isn’t there. Instead, I decided to try developing on Window’s native and do my best to make programming in Windows as ‘unix-like’ as possible. Of course there are about a million more gotcha’s in trying to do this than running a game in a virtual machine but the most important thing to me is having the most accurate depiction of what my end-users will see when they play my game. I deal with the gotcha’s so they (who don’t actually exist yet) won’t have to. So there you have it, there’s my lame justification for doing things this way, if this doesn’t make any sense to you, don’t bother reading any further!

So what’s the first step? Download MinGW, but not any old MinGW, SFML provides one in their setup with Code::Blocks tutorial located here under the ‘Install SFML’ header. Extract it to C:\MinGW so that it ends up looking like this:

Now add C:\MinGW\bin to your PATH environment variable. For those of you who don’t know what that means (you should if you have already gotten SCons working) here are some incredibly detailed images on how to do so:

First, go to Start -> Computer.

Click System Properties near the top.

Click on Advanced System settings at the bottom of the menu on the left.

Click on the Advanced tab and go to Environment Variables.

In the System Variables box, scroll down until you find Path, select it and click Edit…

Click inside the Variable Value textbox and go all the way to the end and type in ‘C:\MinGW\bin’ and make sure you separate it from the previous last entry with a semi colon ‘;’

This will ensure SCons can find it later. You’ll then want to download the MinGW (Code::Blocks) version of SFML. The only difference between their tutorial for Code::Blocks and this one is that I’m replacing Code::Blocks with SCons. Save your SFML files to C:\SFML\SFML-1.6. For those that seem to always have problems unzipping files into just the right place, make sure it ends up looking like this:

We’ll be able to point SCons to these directories directly so there is no need to add any more paths to your path environment variable. The trick here is that this version of SFML comes already compiled to be compatible with the version of MinGW we also downloaded from them, so everything is going to work out great.

Once you have all that setup you can start your project. If you haven’t worked with SCons before, the basics work like this: You make a file named ‘SConstruct’ in a directory, you fill it with instructions of what you want to do, like which files to compile and which libraries to link, etc. Then, using a command prompt, you type ‘scons’ in the directory where you made the SConstruct file, it will read it, do what you told it to do and exit. The example here will be very basic but SCons is a highly flexible tool that makes it easy to manage different builds on different platforms, even wrangling all the 32bit/64bit flavors of things, etc. All powered by Python which you also have at your disposal any time you want. I won’t be going into depth on that here, though. Here’s our SConstruct file for this sample. I’ve purposely sprinkled explanations in between the code in order to encourage people to type it out rather than just copy/paste and see if it works. It may seem unnecessary but I believe there’s value in typing things out yourself when working with a new tool.

import SCons

All we’re doing here is telling Python that were going to be using SCons.

env = Environment()

Now we create an environment object that we’re going to configure to build our application for us. This is where SCons becomes very flexible, allowing you to create multiple environments for different configurations.

Tool('mingw')(env)

By default on a Windows platform, SCons assumes you’re working with the Visual Studio compiler. This line will tell SCons we want to use the MinGW compiler instead. This part relies on the MinGW compiler being in your PATH environment variable, so don’t forget that step! If you have multiple instances of MinGW in your PATH, I’m not sure what will happen. More than likely one will just take priority and if it’s the wrong one, you’re gonna have a bad time until you fix it.

env.Replace(CCFLAGS=[])

Here, were getting rid of another assumption SCons made. On Windows, it will assume you want to pass /nologo to the Windows compiler. However, MinGW will think thats a file name, so here we’re replacing the CCFLAGS environment variable with nothing.

env.Append(CPPPATH=['C:\SFML\SFML-1.6\include'])
env.Append(LIBPATH=['C:\SFML\SFML-1.6\lib'])

Here we tell SCons where to find the SFML headers for the compiler, as well as where to find the libraries we’ll be specifying to the linker.

end.Append(LINKFLAGS=['-static-libgcc'])

EDIT: This will remove dependencies on some stdlib stuff MinGW uses, so you won’t have to require your users to have MinGW or redistribute MinGW’s dll’s. (Not pictured in the screenshot of the final output as I added this step after publishing this post, but see if you can guess where it will show up!)

env.Append(LIBS=['glu32', 'sfml-graphics-s', 'sfml-window-s', 'sfml-system-s'])

Now we’re telling SCons about the libraries we want to use. My dirty secret here is I don’t remember where I got ‘glu32′ but it’s needed for the sample C++ code I’m about to get into. I’ll need to update this in the future. You’ll notice I’ve specified the ‘-s’ flavors of SFML, which is the statically linked versions. If you want dynamic, you’ll also need to add ‘-DSFML_DYNAMIC’ in the step above where we replaced CCFLAGS with nothing. But then of course, you’re program will either need those .dll’s adjacent to the executable, or somewhere on your PATH variable.

env.Program('SFMLSample', ['main.cc'])

Last line of the SConstruct file here, this tells SCons to make a program named ‘SFMLSample’ and hands it a list of source files, which in this case is only main.cc. This is another place SCons can be useful since it has a Glob function that can be used to create a list of all *.cc files in a directory so when you add a new file to your project, it will automatically be picked up by SCons without any additional effort on your part.

Next, we need our actual C++ code, if you’ll notice the last line in the SConstruct file, you’ll see were going to be putting this into main.cc which needs to be adjacent to the SConstruct file. This is an example pieced together from SFML’s tutorials located here. It’s just an OpenGL window that spins a white cube around. The details of the code are better explained on SFML’s website. You can basically put in any of the SFML’s samples that you want, so I’m not going to bother splicing in explanations here.

#include
#include
#include

void openGLInit() {
    // Set color and depth clear value
    glClearDepth(1.f);
    glClearColor(0.f, 0.f, 0.f, 0.f);

    // Enable Z-buffer read and write
    glEnable(GL_DEPTH_TEST);
    glDepthMask(GL_TRUE);

    // Setup a perspective projection
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(90.f, 1.f, 1.f, 500.f);
}

void render(float delta) {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef(0.f, 0.f, -200.f);
    glRotatef(delta * 50, 1.f, 0.f, 0.f);
    glRotatef(delta * 30, 0.f, 1.f, 0.f);
    glRotatef(delta * 90, 0.f, 0.f, 1.f);

    glBegin(GL_QUADS);

        glVertex3f(-50.f, -50.f, -50.f);
        glVertex3f(-50.f,  50.f, -50.f);
        glVertex3f( 50.f,  50.f, -50.f);
        glVertex3f( 50.f, -50.f, -50.f);

        glVertex3f(-50.f, -50.f, 50.f);
        glVertex3f(-50.f,  50.f, 50.f);
        glVertex3f( 50.f,  50.f, 50.f);
        glVertex3f( 50.f, -50.f, 50.f);

        glVertex3f(-50.f, -50.f, -50.f);
        glVertex3f(-50.f,  50.f, -50.f);
        glVertex3f(-50.f,  50.f,  50.f);
        glVertex3f(-50.f, -50.f,  50.f);

        glVertex3f(50.f, -50.f, -50.f);
        glVertex3f(50.f,  50.f, -50.f);
        glVertex3f(50.f,  50.f,  50.f);
        glVertex3f(50.f, -50.f,  50.f);

        glVertex3f(-50.f, -50.f,  50.f);
        glVertex3f(-50.f, -50.f, -50.f);
        glVertex3f( 50.f, -50.f, -50.f);

        glVertex3f( 50.f, -50.f,  50.f);

        glVertex3f(-50.f, 50.f,  50.f);
        glVertex3f(-50.f, 50.f, -50.f);
        glVertex3f( 50.f, 50.f, -50.f);
        glVertex3f( 50.f, 50.f,  50.f);

    glEnd();
}

int main() {

    sf::Clock clock;

    sf::RenderWindow app(sf::VideoMode(800, 600, 32), "SFML Window");

    openGLInit();

    app.SetFramerateLimit(60);

    const sf::Input& input = app.GetInput();

    while (app.IsOpened()) {

        float framerate = 1.f / app.GetFrameTime();
        sf::Event event;

        while (app.GetEvent(event)) {

            if (event.Type == sf::Event::Closed) {
                app.Close();
            }

            if (event.Type == sf::Event::Resized) {
                glViewport(0, 0, event.Size.Width, event.Size.Height);
            }

            app.SetActive();

        }

        render(clock.GetElapsedTime());

        app.Display();

    }

    return EXIT_SUCCESS;

}

Now if you just open a command prompt, cd into your project’s directory and type ‘scons’ you should have a working SFML application for Windows, statically linked and built with SCons! You can also run the program by typing SFMLSample.exe. If you’ve done everything right you should be looking at something like this

This entry was posted in C++, Programming, SCons. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>