Organizing A C++ Project Using Cmake And Gtest

Simple and effective project structure using cmake for the build system and gtest for testing

The goal of this post is to show a simple, but effective project structure for C++ projects, using cmake and gtest. If you want to skip the details and just download the project as a starting point feel free to grab it from github:

git clone https://github.com/curiousinspiration/cpp_base_project.git

If you grabbed the repo from github, feel free to stop right here and modify the files as need be! If not, let's get into the nitty gritty of how and why we made this project structure.

When getting started with a C++ project, I always like to get a few basic things out of the way first: a build system, a library, tools and tests. This example should be a good starting point for unix type systems ie. OSX and Ubuntu. Note this post also assumes a basic working knowledge of C++. At the end of the project, the repo will look like this:

For this example we are going to build a simple program that takes input from the command line and calculates the volume of a sphere. We are going to organize the files into a calculator library for doing the calculations, tests for testing our library, and a tool that you can use on the command line.

A README for general project info, build instructions, etc:
touch README.md

A .gitignore file to tell git what we do not want checked into the repo:
touch .gitignore

Then all the directories we will want:
mkdir -p include/calculator
mkdir -p src
mkdir -p tests
mkdir -p tools/sphere_calculator

A good place to start is defining a test, that our library will have to pass. Let's create the files we will need to make this happen.
touch tests/main.cpp
touch tests/calculator_test.cpp
touch include/calculator/calculator.h
touch src/calculator.cpp

For our tests we are going to use the google testing framework gtest. Edit tests/main.cpp to define our main function for the testing framework.

I like to write tests first to make sure I like the interface for the class. We are only going to have one simple test for our class, because all it does is calculate the volume of a sphere given the radius.

Now let's write the definition/implementation for our simple calculator class.

Edit include/calculator/calculator.h to define our calculator class, and the one method we want to test.

Now for the simple implementation that calculates the volume given the equation below:

In order to try out our new class, and make sure it passes our test, we will need to add our CMakeLists.txt file.
touch CMakeLists.txt


# CMakeLists.txt
cmake_minimum_required(VERSION 3.1)
project(calculator)
set(CMAKE_BUILD_TYPE Release)

set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
set(CMAKE_CXX_FLAGS "-Wall -std=c++0x -O0 -g3")

# Project Headers
include_directories(include)

# Project Sources
file(GLOB_RECURSE SOURCES "src/*.cpp")
add_library(calculator STATIC ${SOURCES})

# Third Party
include_directories(${GTEST_INCLUDE_DIR})

link_directories(${GTEST_LIB_DIR})

set(LIBS
    ${LIBS}
    gtest
    calculator
)

link_directories(build)

# tests
file(GLOB_RECURSE TEST_SOURCES "tests/*.cpp")
add_executable(tests ${TEST_SOURCES})
target_link_libraries(tests ${LIBS})

Now to build the project:
mkdir build
cd build

Give cmake the path to your gtest build directories:
cmake -D GTEST_INCLUDE_DIR=~/Code/3rdParty/googletest-release-1.8.0/install/include/ \ -D GTEST_LIB_DIR=~/Code/3rdParty/googletest-release-1.8.0/install/lib/ ..

Now you should have an executable called ./tests, which after running should give you the following output:

Woohoo! We have a library, class, and test case that passes! This is a great start. Let's finish it off by creating a tool that the user can interact with on the command line.

Create a directory and the main file for your tool.
mkdir ../tools/sphere_calculator/
touch ../tools/sphere_calculator/main.cpp

Now time to implement our tool that uses our library. We will make a REPL that takes in a radius as input, then takes in user input, and prints out the volume.

We could do more fancy checking that user input is valid, but that is not the main focus of this post :)
Now let's add our tool to bottom of CMakeLists.txt



# tools
add_executable(sphere_calculator tools/sphere_calculator/main.cpp)
target_link_libraries(sphere_calculator ${LIBS})

Build the new tool and test it out!
cmake ..
make
./sphere_calculator

You should see the following output:

Congrats! You successfully setup a project with cmake and gtest! You can use this as a good starting point for future C++ projects.

Comments


No comments yet.

Add your feedback below


Login to comment