How to create and link to libraries with CMake

So I thought it would be a good idea to add some more information about CMake. Since the basics of project structure were discussed in the previous post, we can continue talking about creating a library as target and how to ling to a created or external library.

The same structure as the previous post will be used, so to refresh the memory, the structure looked as following:


├── build dir
├── CMakeLists.txt
├── src
|	├── CMakeLists.txt
|	├── main.cpp
|	├── example.h
|	├── example.cpp
|	├── example2.h
|	└── example2.cpp
├── test
|	├── CMakeLists.txt
|	├── exampleTest.cpp
|	└── example2Test.cpp
├── ui
|	├── CMakeLists.txt
|	├── exampleView.h
|	└── exampleView.cpp
└── lib/thirdparty
	├── CMakeLists.txt
	├── UI dir
	|	├── exampleUi.h
	|	└── exampleUi.cpp
	└── Test dir
		├── exampleTest.h
		└── exampleTest.cpp

In this example, the specifics of creating your own library target and linking to a test framework will be discussed. The test framework that will be used is Gtest from Google, which is a library that can be used for unit testing of c++ code. (This means that the structure that was shown above will be a little bit different. The lib/Test dir will be replaced with lib/googletest.)

Gtest is a widely popular and used unit testing framework, because it is open source and there is constant support from the development team! Also it can be used on Multi platforms! But enough about googletest I am not a salesman that wants to sell it to you.

So to start off, the CMakeLists.txt file in src is going to be a little bit different than the previous one we constructed. In order to create a test application that can be used to run the unit tests, the test application will need to be linked to the object files of the files in the src directory and needs access to the include files, so the code knows the function prototypes and does not give an undefined reference error.

The configuration of the src directory will look as followed:


cmake_minimum_required(VERSION 3.10.0 FATAL_ERROR)

set(CMAKE_BUILD_TYPE Debug)
set(CMAKE_CXX_FLAGS -std=c++11 -Wall)

set(HEADERFILES
      example.h
      example2.h)

# The main.cpp is no longer a part of the 
# SRCFILES variable. 
set(SRCFILES
      example.cpp
      example2.cpp)

# Adding the files to a library target.
add_library(SrcFiles STATIC ${SRCFILES})

# Adding the files to the application executable
# should look familiar.
add_executable(${PROJECT_NAME} 
               ${HEADERFILES} 
	       main.cpp
)

target_link_libraries(${PROJECT_NAME} SrcFiles)

So there have been some slight changes made to the configuration file. The main.cpp was taken out of the SRCFILES variable.  This is done because you only want to add the files that contain functionality to a library target. I don’t know for certain if it causes any problems if you leave the main.cpp in the variable, but just to be sure you leave it out.

For the creation of a library target the add_library() command is used. The library is given a name, in this case SrcFiles, the type of library is set, and by de-referencing the SRCFILES variable certain files are added to the library.

In order to keep the scripting of the configuration file clean. The target_link_libraries() command specifies specific targets (libraries) to link to the executable.

The created static library target can now also be used for the unit tests as this can be added to the CMakeLists.txt file in the test dir. The test directory will look as followed:


cmake_minimum_required(VERSION 3.10.0 FATAL_ERROR)
project(example)

# Include the directories so there is access 
# to the header files.
include_directories(${gtest_dir} ${gtest_dir}/include)
include_directories(${PROJECT_DIR})

set(TEST_FILES
		exampleTest.cpp
		exampleTest2.cpp
	)

add_executable(Unit_tests ${TEST_FILES})
target_link_libraries(Unit_tests 
		      gtest_main 
		      gtest 
	              SrcFiles)  

As can be seen in the test configuration file, the target_link_libraries and the include_directories commands are being used in order to build the test application.

First of all, the include_directories() command adds the given directories so the compiler is able to use them while searching for include (header) files. This is needed for both, the own created target and a external target, like googletest.

Secondly, just like the target_link_libraries command in the src CMakeLists.txt file, the command specifies to what targets the executable needs to link.

Small side note about googletest, it has it’s own main which is pretty neat. This way it runs just like a normal application that has a main function as its starting point. From this function all the testcase functions, if the functions are according the specfications of googletest, are called.

For more information about googletest go check out the following link:

https://github.com/google/googletest

Or clone the repository and start messing around with CMake and googletest. The best way to learn is to just do it! I hope this small guide can help you out with your first steps. Happy Coding!

 

 

Leave a Reply

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