Sample C++ project with CMake and GTest

  1. Introduction:
    Recently I needed to come up as quickly as possible with a “hello world” C++ project that is also uses the GTest framework and is maintained using the CMake tool. In this post I describe what is the very minimum that needs to be done in order to bring this “sample project” up and running
    . My assumptions:
    – I’m using C++14
    – The project platform is Linux based (Ubuntu 16.04)
    – CMake version: 3.5.2

    2. Installing CMake:
    In order to install the CMake utility on your Linux machine you can do the following:
sudo apt install cmake

3. Installing GTest on your Linux machine
GTest is a C++ open source project for unit testing of C++ code developed by Google. See the following link on how to download (clone) it and install (build) it for your Linux machine (yes – GTest ALSO uses CMake to build and maintain itself):https://www.eriksmistad.no/getting-started-with-google-test-on-ubuntu/

4. Project folder structure:
The project will have the following folders structure:

sampleCppCmakeGtestProject/
|-- build/
|-- CMakeLists.txt
|-- src/
|   |-- CMakeLists.txt
|   |-- main.cpp
|-- sampleObj1Lib/
|   |-- CMakeLists.txt
|   |-- sampleObj1.cpp
|   |-- sampleObj1.h
|-- test/
    |-- CMakeLists.txt
    |-- SampleObj1-test.h
    |-- main.cpp

Note that the following folder:
src: This is where the source code of the project reside. It might be further sub-divided into more sub folders. For now, I kept it simple. The main.cpp file here is the main of the actual final executable (application). The SampleObj1.h and SampleObj1.cpp are the source files for some sample object – just for testing and for some minimal code in the application.
sampleObj1Lib: This is one library
build: This is the “artifactory” folder for this project – where all the temporary .o and .a and executable will be built into. Usually, these files are NOT tracked as part of the project’s repository.
test: This is where all the tests for this project reside. The main.cpp file here is the main of the GTest relevant tests (will be discussed further).
source folder: Note that the top-level folder, i.e. – sampleCppCmakeGtestProject ALSO has a CMakeLists.txt file. This is the “main” CMake file for this entire project.

5. CMakeLists files
This sample project has several CMakeLists.txt files – which are the main “building blocks” of the CMake utility.

#This is the project's main CMakeLists.txt
#======================================== 
cmake_minimum_required(VERSION 3.5)
project(sampleProject)
message(STATUS "main CMakeLists.txt of ${CMAKE_PROJECT_NAME}")

set(CMAKE_CXX_STANDARD 14)
set (CMAKE_CXX_FLAGS "-m32")
set (CMAKE_C_FLAGS "-m32")

include_directories(src)
add_subdirectory(src)
add_subdirectory(sampleObj1Lib)
add_subdirectory(test)

5.1 Main CMakeLists.txt file:
It is located in the root folder of the project.
This is the “first” CMake file that is to be processed.
The three set commands are used to state what is the C++ version I use (14), and to indicate that for compiling C and C++ code I will use the 32 bit version in the compiler (this is ONLY because I pre-built the GTest library for 32 bit machines, and not for any other reason).
The include_directories is used to indicate to the compiler command is used to indicate include directories to the compiler.
The three add_subdirectory simply indicates to the CMake “compiler” to carry on what it is doing and search for additional CMakeLists.txt files in the sub directors provided as arguments.

5.2 CMakeLists.txt file for the main application (executable):
This is the CMake file that will build the application (executable) of the project:

# CMakeLists.txt file for the main application (executable)
# =========================================================
set(exeName "mainApplication")
message(STATUS "CMakeLists.txt of ${exeName} executable")
# add the executable
add_executable(${exeName} main.cpp)

target_link_libraries(${exeName} PUBLIC sampleObj1Lib)

# add the binary tree to the search path for include files
# so that we will find sampleObj1.h
target_include_directories(${exeName} PUBLIC
                          "${PROJECT_BINARY_DIR}"
                          "${PROJECT_SOURCE_DIR}/sampleObj1Lib"
                          )

– The add_executable command creates the final executable.
– The target_link_libraries command links it with a library (that “later on” will be built).
– The target_include_directories command indicates which folders are in the include directories list of the target (library/executable).
5.3 CMakeLists.txt file for the sampleObj1 library:

# CMakeLists.txt file for the sampleObj1 library
# ==============================================
set(libName "sampleObj1Lib")
message(STATUS "CMakeLists.txt of ${libName} library")
add_library(${libName} sampleObj1.cpp)

– The add_library command simple creates the library and names it, in this case, sampleObj1Lib

5.4 CMakeLists.txt file for the GTest unit tests executable:
The GTest unit test, will eventually will be “compiled” into an executable.

# CMakeLists.txt for the unit tests:
# =================================
message(STATUS "unit tests CMakeLists.txt of ${CMAKE_PROJECT_NAME}")
 
# Locate GTest
find_package(GTest REQUIRED)
include_directories(${GTEST_INCLUDE_DIRS})
 
# Link runTests with what we want to test and the GTest and pthread library
find_library(GTEST_LIBRARY gtest HINTS /usr/lib)
message(STATUS "GTEST_INCLUDE_DIRS is: ${GTEST_INCLUDE_DIRS}")
message(STATUS "GTEST_LIBRARY is: ${GTEST_LIBRARY}")
message(STATUS "GTEST_LIBRARIES is: ${GTEST_LIBRARIES}")

add_executable(unitTestsExe main.cpp)
target_link_libraries(unitTestsExe ${GTEST_LIBRARY} pthread)

– The find_package and find_library commands are used to locate the GTest library that I (chose to) built ahead (and indeed are located under /usr/lib/gtest folder)
– The add_executable simply creates the executable that will trigger (run) all the GTest unit tests that will be implemented.
– The target_link_libraries command simply links the executable with the GTest library and the pthread (known pre-condition to run the GTest framework).

6. Source files for this project:
The source files for this project are fairly straight forward so I will not introduce them here, YET they can be found in the following git repository:
https://github.com/guyavrah1986/sampleCppCmakeGtestProject

7. Conclusions:
In this post, a very minimal and simple C++ (14) project that is maintained and built using the CMake utility and that is leveraging the GTest testing framework for unit testing of the code. There is, off course, lots more to add to CMake and GTest, but here I kept it simple.

Resources:
https://raymii.org/s/tutorials/Cpp_project_setup_with_cmake_and_unit_tests.html
https://www.eriksmistad.no/getting-started-with-google-test-on-ubuntu/
https://stackoverflow.com/questions/5805874/the-proper-way-of-forcing-a-32-bit-compile-using-cmake

The picture: The small carter, near the city of Dimona, Israel.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: