I’m going to be writing my engine in my favourite language, C. This seems to be a natural choice for a chess engine as it lends itself to performance analysis and optimisation and can easily live alongside assembly language for those performance critical routines.
For a build system I’m going to be using CMake. This will provide cross-platform build capability as well as providing support for a number of toolchains and IDEs including Visual Studio and Eclipse.
So let’s start with some placeholder C files, starting with main.c the entry point for Ircos.
|
#include "board.h" int main(int argc, char** argv[]) { reset_board(); return 0; } |
As you can see this file currently just calls “reset_board” which will ultimately set the initial configuration of the chess board.
Let’s follow that up with the header and implementation files for our chess board.
|
#pragma once void reset_board(); |
|
#include "board.h" void reset_board() { } |
As you can see, these are just empty but compilable files at present so we can get the build environment working.
For CMake we need to provide a CMakeLists.txt that configures the build.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
|
# # CMake file for ircos chess engine # cmake_minimum_required (VERSION 2.6) project (ircos) find_package(CxxTest) include_directories( src ) # Compile the engine source into a library so we can link it into the # main application and the unit tests add_library(ircos_l STATIC src/board.c ) # Create the main ircos application add_executable( ircos src/main.c ) add_dependencies( ircos ircos_l ) target_link_libraries( ircos ircos_l ) |
This maybe needs a short explanation.
Line #9 – defines the include directories for the project. The CMakeLists.txt lives in the root folder and the .c and .h files live in a subdirectory named “src”.
Line #15 – we build the engine source files into a static library. This allows us two link it into two modules; the main Ircos engine executable and a unit test executable (more on this later).
Line #20 – the main.c module is compiled and linked with the static library to generate the engine executable.
You’ll also notice that I’m looking for a package named “CxxTest”. This is a unit test framework that I’ll be using to test various parts of the engine. In order to achieve this we need to add a few more lines to CMakeLists.txt.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
# If the test library is available then build and run the unit tests if(CXXTEST_FOUND) enable_testing() # Board tests cxxtest_add_test(test_ircos test_board.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/test_board.h) target_link_libraries( test_ircos ircos_l ) add_dependencies( test_ircos ircos_l ) # Make the unit tests run as part of the build add_custom_command( TARGET test_ircos COMMENT "Run tests" POST_BUILD COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test_ircos ) endif(CXXTEST_FOUND) |
I’ve made the unit testing optional based on whether the CxxTest framework was found or not. This allows the engine to still be built on platforms that do not support CxxTest.
Line #4 – The CxxTest framework is found so we enable testing.
Line #7 – We will add a single test module at present. The tests are defined in “test_board.h”. CxxTest will auto-generate a source file from this named “test_board.cpp” (we do not need to provide this file) and the test module will be added to the target “test_ircos”
Line #9 – We can see now why I built the engine source into a static library. It can be added as a dependency of the unit test application “test_ircos” rather than having to rebuild the source files all over again.
Line #20 – Finally, we make the unit tests run as part of the build process after the build is complete.
The final piece of the puzzle is the unit test module, “test_board.h”. Again I provide a placeholder to be filled-in later.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
#include <cxxtest/TestSuite.h> extern "C" { #include "board.h" } class BoardTestSuite : public CxxTest::TestSuite { public: BoardTestSuite() { } void test_reset_board() { reset_board(); TS_ASSERT(true); } }; |
In here we provide a single example test on line #12 that calls the (empty) reset_board() function before asserting ‘true’ (which will obviously never fail).
All that is left to do now is to build the engine and see if works! I’ll do this in the next post.