Building a Game Engine from Scratch with C++ and Native Platform Languages (Part Two)
Let’s get cracking! This series is going to be making use of the terminal, so you will want to brush up on using the command line for your operating system. I will explain what’s going on but it will be up to you to figure it out for your operating system.
So go ahead and open up our project in your favourite code editor. Also, pop open a terminal and cd (change directory) into the root of the project. Let’s write our first line the CMakeLists.txt file we created.
The very first line needs to be the minimum version of CMake we intend this file to work with. This will signal to CMake to only attempt to build our project if a new enough version of CMake is installed.
In the terminal, enter the command…
cmake --version
The output will tell you the version of CMake that you have installed. Mine says “cmake version 3.16.1”. Copy this number and lets add this line to the top of our file.
cmake_minimum_required(VERSION 3.16.1 FATAL_ERROR)
Great! Our engine has officially started! Nice job. The next step is to name our project. Add these line to the file.
project(engine)set(CMAKE_CXX_STANDARD 11)
Now we have told CMake the name of our project, and which version of C++ we are going to be using. For us, C++11 is all that we will need.
Next up, we are going to add a static library target, which will be our engine, and an executable target, which will just be for testing. Later on we will create native platform projects for running our games. But for now, we just want a quick way to test the code we write.
Firstly, lets define our source code files. We haven’t created any C++ files yet, but we will do that next.
Add these lines to the bottom of the CMakeLists.txt
set(ENGINE_SOURCE ${CMAKE_CURRENT_LIST_DIR}/src/engine.h ${CMAKE_CURRENT_LIST_DIR}/src/engine.cpp)add_library(engine STATIC ${ENGINE_SOURCE})
set(TESTING_SOURCE ${CMAKE_CURRENT_LIST_DIR}/src/testing.cpp)
add_executable(program ${TESTING_SOURCE})
target_link_libraries(program engine)
So we have defined a static library target as well as an executable, and we have assigned some source code files to each. Hopefully this is all self explanatory. CMAKE_CURRENT_LIST_DIR is simply a variable that stores the absolute path on disk to the CMake file.
Let’s go ahead and add those source files and stuff some code into them!
Let’s create ./src/engine.h first. We will keep it very simple for now.
#pragma oncevoid Initialise();
… and ./src/engine.cpp can implement this function.
#include "engine.h"#include <iostream>void Initialise(){ std::cout << "ENGINE INITIALISED!" << std::endl;}
Very good, a powerful game engine indeed!
Now lets create that file that our temporary testing executable will use. That’s ./src/testing.cpp
#include "engine.h"int main(){ Initialise(); return 0;
}
This may all seem very basic and simple, but this is the foundations of our entire project!
The time has come, the first build of our almighty game engine…. I hope we didn’t add too many features!
Let’s jump into the terminal, make sure we have set the directory to the root of our project and create a new folder called bin. On Mac and Linux the command to create a folder called bin is ‘mkdir bin’.
It’s a common convention to call this folder bin as it’s where the compiled binaries will go. Let’s cd into that folder and run our cmake command.
cmake --help
This will spit out a bunch of information, but what we are interested in, is the list of generators near the bottom.
* Unix Makefiles = Generates standard UNIX makefiles.
Ninja = Generates build.ninja files.
Xcode = Generate Xcode project files.
CodeBlocks - Ninja = Generates CodeBlocks project files.
CodeBlocks - Unix Makefiles = Generates CodeBlocks project files.
CodeLite - Ninja = Generates CodeLite project files.
CodeLite - Unix Makefiles = Generates CodeLite project files.
These are the possible build systems that my CMake can generate. Your’s may look different. I have a star next to ‘Unix Makefiles’ which tells me this is my default. Which is perfect as that’s what I want to use. If you are on Mac or Linux then this is what you want too, however if you are on Windows then you will need to use the Visual Studio generator. Go ahead and copy the Visual Studio generator name the the list.
Let’s run CMake!
If you are on Mac or Linux…
cmake ..
… and for Windows, just be sure to replace the command with the exact string of text you copied from the list.
cmake .. -G"Visual Studio 16 2019"
This command tells cmake to run, but to look in the directory below for a CMakeLists.txt file, that’s what the .. means. That .. could have been a full absolute path to somewhere on disk and as long as there is a CMakeLists.txt file there, then it will work.
If all went well, then we will now have a generated project in the bin directory ready to build! On Windows go ahead and open up the Visual Studio project that was created and hit build and run.
On Mac and Linux, make sure you are cd’d into the bin directory (or wherever you ran cmake from) and simple enter…
make
This will run the Makefile that CMake created, and build our library target and our executable.
If there were any syntax errors in the code, then…… fix them…… and try again.
Once the build has succeeded, go ahead and run the testing executable by either double clicking on it or running it in the terminal.
./program
We should see the output “ENGINE INITIALISED!”
We are in business! A powerful game engine packed with features!
I hope you are excited about this, it doesn’t have fancy 3D graphics…. or any graphics at all…. however, we now have a well organised project that we can build upon. Go ahead and completely delete the bin folder. WHAT?! Delete the bin folder?! You must be mad!
I am NOT mad! The bin folders contents were generated for us by CMake, which means we don’t have to worry about it, and certainly shouldn’t check it in to version control. So go ahead and delete the bin folder, recreate it, cd into it in your terminal and try generating the project again.
We won’t need to regenerate every time we make a change though, CMake is very powerful and knows when you change something, either in your source code or in the CMakeLists.txt file itself. It will detect changes and update itself for you. So our development process will look like this:
- Create or edit source code file
- Add any new files to the CMakeLists.txt
- Run ‘make’ or build in your IDE.
- Repeat until the game engine is complete.
I hope you can appreciate the power of CMake over maintaining your own Makefile / XCode project / Visual Studio Solution etc. Not only is CMake cross platform, but if we mess around with the generated project, and break something, we can just regenerate!
That’s all for now. Next episode, we will add some real code to our engine.