CMake - Integrating C++ Libraries
In modern C++ development, CMake is an indispensable tool for managing project dependencies. This comprehensive guide empowers you to effortlessly integrate widely used C++ libraries into your projects using the versatile CMake build system.
We’ll delve into strategies for incorporating Google Test, Google Benchmark, OpenCV, PkgFinder, GStreamer, Catch2, and Qt, providing clear instructions and code examples tailored to both Windows and Ubuntu environments.
1. Streamlining Library Integration with CMake
CMake offers a robust mechanism for managing external libraries, simplifying the process of adding them to your C++ projects. Here are the fundamental approaches:
-
FetchContent
Module: This convenient module assists in downloading and integrating libraries directly from source repositories. It’s ideal for libraries under active development or those not readily available through package managers. -
find_package
Command: For libraries distributed with package managers (e.g., PkgConfig, Conan, vcpkg, etc.), CMake’sfind_package
command simplifies the discovery and linking process. -
Manual Configuration: In some cases, you might need to set environment variables or manually specify library and include directories. This approach is usually employed for libraries not managed by package managers.
Exploring Popular C++ Libraries:
Now, let’s embark on a journey through integrating some of the most popular C++ libraries.
2. Google Test
Purpose: Google Test is a robust testing framework designed for writing unit tests in C++.
2.1. Integration Google Test using FetchContent
Windows and Ubuntu Instructions: The procedure for both systems is identical using CMake’s FetchContent
.
include(FetchContent) # to use FetchContent_Declare
# -- START: GOOGLE_TEST_INCLUDE --
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG main
OVERRIDE_FIND_PACKAGE
)
FetchContent_MakeAvailable(googletest)
include(GoogleTest) # to use gtest_discover_tests
target_link_libraries(simple_test GTest::gtest_main)
# -- END: GOOGLE_TEST_INCLUDE --
# test files
add_executable(simple_test "simple_test.cpp")
gtest_discover_tests(simple_test)
Simple Test Code: simple_test.cpp
# include <gtest/gtest.h>
TEST(HelloTest, BasicAssertions) {
// Expect two strings not to be equal.
EXPECT_STRNE("hello", "world");
// Expect equality.
EXPECT_EQ(7 * 6, 42);
}
2.2. Installing Google Test on Ubuntu
For Ubuntu, you can alternatively install Google Test using apt
:
sudo apt-get install libgtest-dev
Then manually compile the library and link it to your project.
3. Google Benchmark
Purpose: Google Benchmark simplifies the process of benchmarking C++ code for performance testing.
3.1. Integration Google Benchmark using FetchContent
include(FetchContent) # to use FetchContent_Declare
# -- START: GOOGLE_BENCHMARK_INCLUDE --
FetchContent_Declare(
googlebenchmark
GIT_REPOSITORY https://github.com/google/benchmark.git
GIT_TAG main
OVERRIDE_FIND_PACKAGE
)
FetchContent_MakeAvailable(googlebenchmark)
target_link_libraries(${EXE_NAME} benchmark::benchmark)
# -- END: GOOGLE_BENCHMARK_INCLUDE --
# test files
add_executable(simple_benchmark "simple_benchmark.cpp")
gtest_discover_tests(simple_benchmark)
Example Benchmark Code: simple_benchmark.cpp
#include <benchmark/benchmark.h>
static void BM_StringCreation(benchmark::State& state) {
for (auto _ : state)
std::string empty_string;
}
// Register the function as a benchmark
BENCHMARK(BM_StringCreation);
static void BM_StringCopy(benchmark::State& state) {
std::string x = "hello";
for (auto _ : state)
std::string copy(x);
}
BENCHMARK(BM_StringCopy);
3.2. Installing Google Benchmark on Ubuntu
sudo apt-get install libbenchmark-dev
Update your CMake file:
find_package(benchmark REQUIRED)
target_link_libraries(MyBenchmarkTarget benchmark::benchmark)
4. OpenCV
Purpose: OpenCV is a powerful library for real-time computer vision and image processing.
4.1. Integration of OpenCV on Windows
- Download the pre-built OpenCV binaries for MinGW from the OpenCV-MinGW-Build.
- Ensure you add the OpenCV binaries to your
PATH
variable.
CMakeLists.txt:
# Add this
set(OpenCV_DIR "C:\\OpenCV-MinGW-Build-OpenCV-4.5.5-x64")
# Find and link OpenCV
find_package(OpenCV REQUIRED)
target_include_directories(MyApp PRIVATE ${OpenCV_INCLUDE_DIRS})
target_link_libraries(MyApp PRIVATE ${OpenCV_LIBS} )
To avoid hard coded paths in CMake, you could consider adding OpenCV_DIR
to your system’s PATH
variable.
4.2. Integration of OpenCV on Ubuntu
To install OpenCV on Ubuntu:
sudo apt-get install libopencv-dev
Then update your CMakeLists.txt
:
find_package(OpenCV REQUIRED)
target_link_libraries(MyApp PRIVATE ${OpenCV_LIBS})
Sample OpenCV Code: main.cpp
#include <opencv2/opencv.hpp>
int main(int argc, char *argv[]) {
// Create a window using OpenCV
cv::namedWindow("MyWindow", cv::WINDOW_AUTOSIZE);
// Wait for a keystroke in the window
cv::waitKey(0);
return 0;
}
5. PkgFinder Package Manager
- Purpose: A platform-independent package manager for C libraries.
5.1. Integration of PkgFinder on Windows
-
Download and install the required binaries from the pkg-config website. Specifically, you’ll need to install the required binaries. Copy the following files into your MinGW64 bin directory:
-
bin/pkg-config.exe from pkg-config_0.26-1_win32.zip
-
bin/intl.dll from gettext-runtime_0.18.1.1-2_win32.zip
-
bin/libglib-2.0-0.dll from glib_2.28.8-1_win32.zip
-
-
Note that this is not necessary for CLion’s bundled CMake or for MSVC.
5.2. Installing on Ubuntu
sudo apt-get install pkg-config
Example usage in CMakeLists.txt
find_package(PkgConfig REQUIRED)
pkg_check_modules(LIBNAME REQUIRED libname)
target_include_directories(MyApp PRIVATE ${LIBNAME_INCLUDE_DIRS})
target_link_libraries(MyApp PRIVATE ${LIBNAME_LIBRARIES})
6. GStreamer
- Purpose: GStreamer is a powerful multimedia framework for streaming and video processing.
6.1. Integration of GStreamer on Windows
Gstream requires PkgFinder packe for CMake
To use GStreamer in your C++ projects, ensure the following:
-
Make sure that Microsoft Visual C++ Redistributable is installed (or install it from the official website vc_redist.x86.exe)
-
Install the GStreamer runtime and SDK (MSVC-64 version) from GStreamer’s website.
-
Add the GStreamer’s binary folder to the system
PATH
variable. -
Set the
PKG_CONFIG_PATH
environment variable to the GStreamer package config path:
PKG_CONFIG_PATH = path/to/gstreamer/1.0/msvc_x86_64/lib/pkgconfig
`
Update your CMakeLists.txt
:
find_package(PkgConfig REQUIRED)
pkg_check_modules(GST REQUIRED gstreamer-1.0)
pkg_search_module(GSTREAMER REQUIRED IMPORTED_TARGET gstreamer-1.0>=1.4)
target_include_directories(MyApp PRIVATE ${GST_INCLUDE_DIRS})
target_link_libraries(MyApp PRIVATE PkgConfig::GSTREAMER)
6.2. Integration of GStreamer on Ubuntu
To install GStreamer:
sudo apt-get install gstreamer1.0-dev
7. Catch2
7.1. Downloading and Installing Catch2
Catch2 is another popular testing framework. To add Catch2 to your project, clone the repository and build it:
git clone https://github.com/catchorg/Catch2.git
cd Catch2
# if you want a specific version
git checkout v2.13.9
Build and install the library:
mkdir build && cd build
cmake .. -G "MinGW Makefiles" # or "Visual Studio 17 2022"
cmake --build . --config Release # or Debug
cmake --install . --prefix /path # Path to installation
By following these instructions, you should be able to seamlessly integrate these libraries into your C++ projects using CMake.
8. Qt6
Purpose: Qt6 is a modern, cross-platform GUI framework for building high-performance, visually rich applications. Qt6 also includes non-GUI components, making it a comprehensive tool for application development.
8.1. Integration of Qt6 on Windows
- Firstly, install Qt from Qt’s official website
- Integrating Qt6 in a self-sufficient manner with CMake involves properly setting up the environment and linking the necessary components.
8.2. Setting Up CMake
-
At the project level, define the
CMAKE_PREFIX_PATH
to locate the Qt libraries:# Paths to depedencies set(CMAKE_PREFIX_PATH "${DEPENDENCY_FOLDER}/some_library/" "path/to/Qt/6.5.3/mingw_64/lib/cmake/Qt6" )
-
At the executable/library level, include the following configurations:
find_package(Qt6 REQUIRED COMPONENTS Core Gui) # Enable Qt's meta-object compiler (moc), resource compiler (rcc), and UI compiler (uic) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_AUTOUIC ON) # Define Qt version macros add_definitions(-DQT_VERSION_MAJOR=${Qt6_VERSION_MAJOR}) add_definitions(-DQT_VERSION_MINOR=${Qt6_VERSION_MINOR}) add_definitions(-DQT_VERSION_PATCH=${Qt6_VERSION_PATCH})
-
Next, add all what is dependent on MOC, RCC, UIC. and so on
add_executable(MyApp) # Declare it as a GUI application (disable console) set_target_properties(MyApp PROPERTIES WIN32_EXECUTABLE TRUE MACOSX_BUNDLE TRUE ) # Link against Qt6 Components target_link_libraries(MyApp PRIVATE Qt6::Core Qt6::Gui)
-
Only then, set up the executable:
# Add sources and headers target_sources(experiment_01 PRIVATE source/main.cpp include/MyApp.h # Also headers with QObject ) # Specify include directories target_include_directories(experiment_01 PRIVATE include)
8.3. Linking Libraries
- For platform-specific libraries, copy the necessary plugins (e.g.,
qwindows.dll
) to theplatform
directory in your binary.
path/to/Qt/6.5.3/mingw_64/plugins/platforms
If you are on Windows, Copy qwindows.dll
- Core Qt components such as
Qt6Core.dll
,Qt6Widgets.dll
, andQt6Gui.dll
can be found in:
path/to/Qt/6.5.3/mingw_64/bin
8.4. Integration of Qt6 on Ubuntu
To integrate Qt6 on Ubuntu, follow these steps:
-
Install Qt6: On Ubuntu, you can use the system’s package manager to install the necessary development packages for Qt6.
sudo apt-get install qt6-base-dev qt6-tools-dev-tools qt6-tools-dev qt6-base-dev-tools
This will install the Qt6 Core, Gui, and other essential components.
-
Set Up CMake for Qt6: Once Qt6 is installed, configure your
CMakeLists.txt
to find and link the necessary Qt6 components.
8.5. Deploying Qt6 Applications on Ubuntu
To ensure your Qt6 application runs smoothly on Ubuntu, you might need to ensure that the correct Qt6 libraries and plugins are packaged with your application. For development purposes, the necessary libraries will usually be located automatically through CMake, but for deployment, you may need to package or point to the correct Qt paths manually.
For Qt6 deployment, use the qt6-deploy
tool, available as part of the Qt6 installation, to gather all the necessary components and bundle them with your application.
qt6-deploy MyApp
9. Conclusion
In this guide, we have covered the essential steps to seamlessly integrate some of the most widely-used C++ libraries into your projects using CMake. From Google Test for unit testing, Google Benchmark for performance measurement, OpenCV for computer vision, to GStreamer for multimedia handling, and Qt6 for building cross-platform graphical applications, this guide provides a structured approach to handling dependencies.