2 minute read

Motivation

There are already some tutorials and examples of setting up a CMake project already but I work very much ny example and then deep dive later. It’s just how my brain works I guess. So let’s skim the waters.

Assumptions

This example uses the follow dev stack.

  • CMake (obviously)
  • C++ code.
  • Catch2 testing framework (GitHub).

The file layout has subdirectory for source code and tests, each with their own CMake file and one at the root level.

CMakeLists.txt
tests
├── CMakeLists.txt
└── mylib_test.cpp
src
├── CMakeLists.txt
├── mylib.h
└── mylib.h

Configuration

Here is the whole configuration in its respective files.

/CMakeLists.txt

cmake_minimum_required(VERSION 3.16.3)

include(GNUInstallDirs)     # Make CMAKE_INSTALL_*DIR variables available.
set(CMAKE_CXX_STANDARD 20)  # Use standard C++20 for compilation.

project(mylib VERSION 0.1 DESCRIPTION "My library is a library that you can use as a library.")

# Make the src directory available for include lookup.
include_directories(src)

# Tell CMake to include the /src/CMakeLists.txt file in the build.
add_subdirectory(src)

# Must live in the top level file or tests won't be found.
include(CTest)  # Automatically invokes enable_testing()
# Tell CMake to include the /tests/CMakeLists.txt file in the build.
add_subdirectory(tests)

/src/CMakeLists.txt

message(STATUS "Building and installing library.")

# Add library to build.
#
# STATIC rolls all code (including related includes) into a single compiled object.
# SHARED rolls only mylib code into a single compiled object.
#
# https://stackoverflow.com/questions/2649334/difference-between-static-and-shared-libraries
#
# If you are using a different type of library than STATIC, make sure to look into how the target properties and 
# install will be different. For example https://cmake.org/cmake/help/latest/command/install.html
#
add_library(mylib STATIC mylib.h mylib.cpp)

set_target_properties(mylib PROPERTIES
  VERSION ${PROJECT_VERSION}  # Already set in the parent CMakeLists.txt via 'project'.
  PUBLIC_HEADER mylib.h       # Pulic headers you intend other projects to include.
  CXX_STANDARD_REQUIRED 20)   # Enforce the C++20 standard to compile against.

install(TARGETS mylib
  # Used for STATIC library headers.
  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT lib
  # Rolled code lives here.
  PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/mylib COMPONENT dev)

/tests/CMakeLists.txt

include(FetchContent)

message(STATUS "Building tests.")

# Pull in the Catch2 framework.
FetchContent_Declare(
  Catch2
  GIT_REPOSITORY https://github.com/catchorg/Catch2.git
  GIT_TAG        v3.0.0-preview3)
FetchContent_MakeAvailable(Catch2)

# Most all test frameworks create a binary that then runs the tests.
# This is a simple expression of that and nothing special to tests themselves.
#
# In this framework, Catch2 provides a main function as executable entry point.
add_executable(query_tests mylib_test.cpp)

# Link the included libraries in for the tests.
target_link_libraries(my_tests PUBLIC Catch2 Catch2WithMain mylib)

add_test(NAME tests COMMAND query_tests)

More Resources

Here are some more examples to help you along.

Tags:

Updated:

Leave a comment