Selective Intellect

View Original

How to use CMake to add Third Party Libraries to your Project

CMake is an excellent cross-platform build tool for automatically generating Unix Makefiles, Windows NMake Makefiles, Microsoft Visual Studio® Solution projects or Apple Xcode® projects for MacOS. It has its own domain specific language and various modules for most commonly used libraries and software frameworks. The most common use of CMake is to build projects that are written in C, C++ or both. As a longtime user of CMake we have written build systems for large and complex projects in it that also build Java and C# wrappers, or use it for auto-generating cross-platform C/C++ code using Perl.

In this blog post we demonstrate how to use CMake to build a large toolkit like Intel® Threading Building Blocks (TBB).

Although TBB might be available in your Linux operating system's package manager, sometimes you may want to compile the latest version from source using a different compiler like Intel's C Compiler (icc) instead of GNU C Compiler (gcc), or you're building software that runs on both Linux and Windows, and you don't want to use a pre-built version of TBB from Intel.

CMake has a module called ExternalProject that can do this for you. Below we demonstrate how to download the latest source from the TBB website, and how to use features present in CMake to make sure that the project gets compiled and ready to use in your project. TBB is a C++ library, hence our example will be with C++ source.

Sample Setup

Let's say your source code directory structure looks like below. For brevity we are not displaying too many C++ files. We will use this example to show how to use TBB as an external dependency.

See this content in the original post

Here the myproject.h, myproject.cpp are the source code for your application that will use TBB and loadtbb.cpp is a unit test to check that you have loaded TBB correctly. The CMakeLists.txt files in each directory are for CMake to know how to handle the files in each directory. Sample files are given at the end of this post.

The myproject/CMakeLists.txt file

Note that the below file tbb.cmake doesn't exist yet and we will be creating it in the following section.

See this content in the original post

Sample test/loadtbb.cpp file

See this content in the original post

Sample test/CMakeLists.txt file

See this content in the original post

Creating the tbb.cmake file

Create an empty file using your favorite text editor called tbb.cmake in the thirdparty directory. Your directory structure should look like this:

See this content in the original post

The tbb.cmake file can be downloaded here.

Downloading the TBB Source Code

There are two ways to download the source: manually and using CMake. We explain the manual method first, as the CMake method follows from that.

Using curl or wget or any browser download the source from the TBB website.

For example, the latest source code version at the time of writing of this blog post is 4.4. Place this downloaded file in the thirdparty directory of your project, which in our case is the myproject directory. Our tree structure now looks like this.

See this content in the original post

Let's add the following lines to the tbb.cmake file now.

See this content in the original post

If you want to use the direct URL from the TBB website, the TBB_URL variable line will look like below. Be aware that this causes TBB source to be downloaded each time you build the project which may not be what you want. Hence, we recommend the manual download method above.

See this content in the original post

The rest of the tbb.cmake file will be described assuming the manual download method since that is expedient.

Building the TBB Source

To build the TBB source, we have to use the CMake functions provided by the ExternalProject module, viz., ExternalProject_Add, ExternalProject_Get_Property and ExternalProject_Add_Step. The details of each of these functions can be viewed in the CMake manual or using the command man cmake on your terminal.

NOTE: To build TBB on Windows requires GNU Make or gmake installed and in the PATH or set it in the TBB_MAKE variable.

The best way to verify this works is to first test it on Linux or MacOS.

We add the TBB project using the ExternalProject_Add command to the
tbb.cmake file like below. We also add the sub-projects in TBB that are required in the file using ExternalProject_Step.

The ExternalProject_Add will uncompress the TBB source file we downloaded earlier and compile it using as many CPU cores as available in your system. The number of CPUs can be modified by editing the NCPU variable in the file.

It will then compile the source and all its dependencies that are specified. Any following targets that need to be built usign ExternalProject_Step are also built.

NOTE: Building the examples is optional. It can take very long and isn't recommended for regular use. It is only useful if you want to see how stuff works.

We then use CMake's module CheckIncludeFileCXX to have CMake test whether it can include the tbb/tbb.h header file in code and compile it. If it can, then we have succeeded in adding TBB as a dependency in our project.

The complete tbb.cmake file is below:

See this content in the original post

As you see above this file looks complex but in reality, that's how CMake build files look. You have to instruct CMake in detail to avoid it making mistakes, especially in such cases. However, once you have a template like the above, it is easy to make it work for other libraries too.

The commands to build the project are as follows:

See this content in the original post

This has worked well for us on Linux and MacOS. We have not had a need to test on Windows, but if you find any problems let us know.

NOTE: If you have errors in your run of cmake for any reason and they don't go away, remember to delete the CMakeCache.txt file and then retry.

The complete source code for the sample project can be downloaded here.