A collection of as simple as possible, modern CMake projects

Overview

Modern CMake Examples Mentioned in Awesome CMake

Overview

This repository is a collection of as simple as possible CMake projects (with a focus on installing). The idea is to try and help understand exactly what each part of a CMakeLists.txt file does and why it is needed.

This is basically intended as a series of reminders to help me remember how to use CMake 🤦

Please see the Core Example README for steps on using the example libraries and the Installing README for an overview of installing CMake libraries. The More Example section contains slightly more complex examples and will continue to grow.

Disclaimer

I am NOT a CMake expert - these examples may contain gaffs, faux pas, mistakes etc etc.. Please take everything with a pinch of salt and if you recognize a blatant error or mistake please feel free to create an issue or PR.

Background

For the longest time I just didn't grok installing in CMake1.

I didn't understand why you'd ever want to do it, or what it was useful for. When I started looking into how to do it I could not make head nor tail of all the various install commands. While trying to figure all this stuff out I was immersing myself in trying to learn Modern CMake (targets, targets targets...) and how these two things are related.

The examples in this repo are the culmination of many months of sporadic research to try and understand CMake more fully and write better CMake scripts.

I'm sharing my journey so far to hopefully help some other poor soul who is in the same boat I'm in. With any luck there will be something someone finds useful here.

For an explanation2 of what (in the context of CMake) installing is, please see the installing section and take a look at the various example projects for context.

  1. I recently discovered a kindred spirit on reddit
  2. My interpretation?

Miscellaneous

While using CMake over the last several months I've stumbled across a few useful little bits and bobs that I feel are worth recording/sharing.

Less cd-ing

To run CMake from your source directory (instead of having to mkdir build && cd build) you can pass -S and the path to your source folder (most likely just . for where you currently are) and -B to specify the build folder.

cd <project/root>
cmake -S . -B build/

You then just need to remember to call

cmake --build build/

to actually build your project.

Note: The -S option was added to CMake in version 3.13. Before then you could use the undocumented -H option. I'd recommend sticking with -S now if you can 🙂 .

compile_commands.json

You should absolutely use -DCMAKE_EXPORT_COMPILE_COMMANDS=ON when generating your project to have CMake create a compile_commands.json file for you. This is useful for all sorts of tools (clang-tidy, cppcheck, oclint, include-what-you-use etc. etc...).

# when configuring from the root CMakeLists.txt of your project
cmake -S . -B build/ -DCMAKE_EXPORT_COMPILE_COMMANDS=ON

Note: CMAKE_EXPORT_COMPILE_COMMANDS is only supported for Make and Ninja generators. The good news is it's pretty simple to use Ninja on Windows in place of Visual Studio/MSBuild - for instructions please see this repo.

TLDR: Add -G Ninja to the above command to use Ninja.

Defines

Sometimes it's really useful to be able to set defines at the command line when running the CMake generator. An easy way to do this is to add a simple generator expression to your CMakeLists.txt file in target_compile_definitions.

target_compile_definitions(
    ${PROJECT_NAME} PRIVATE
    $<$<BOOL:${YOUR_DEFINE}>:YOUR_DEFINE>)

In your code you can then use this define for some sort of conditional compilation.

#ifdef YOUR_DEFINE
// something useful
#endif // YOUR_DEFINE

And when invoking cmake you can pass a CMake variable like so if you want that macro to be defined.

# from the src/ (root) folder
cmake -S . -B build/ -DYOUR_DEFINE

If you don't pass the variable then the generator expression will evaluate to false and no define will be added.

Extra Output

Sometimes when building with CMake to diagnose an issue you might want more info about exactly what's being compiled. You can see everything that's passed to the compiler when building with the --verbose (-v) flag.

# from the src/ (root) folder
cmake --build build/ -v

This works for an array of generators (Make, Visual Studio, Ninja etc.).

CONFIG

You'll notice all of the find_package commands include the CONFIG keyword after the package name (and REQUIRED). This is to let CMake know we're explicitly using a CMake <package>-config.cmake file and not a FindModule command (all these examples use the more modern config approach so including CONFIG in the find_package command should be preferred).

DEBUG_POSTFIX

It is possible to set a property called DEBUG_POSTFIX on a given target to have a string appended to the name of the debug version of the library (usually d or -debug, but as far as I know it can be anything).

set_target_properties(
    ${PROJECT_NAME} PROPERTIES DEBUG_POSTFIX "d")

This is incredibly useful when installing libraries as it means if you build and install the Debug configuration and then build and install the Release configuration, the Debug version of the library won't be overridden (you'll just have your-libraryd.lib and your-library.lib) in the lib/ folder. This works for single and multi-config generators.

FetchContent

Check out the fetch-content example for a simple demonstration using the commands and see the links below by Sascha Offe, Kuba Sejdak and Michael Hirsch for more information.

ExternalProject_Add

Check out the external-project-add example for an (opinionated) introduction on how to take advantage of the command.

cmake-helpers

I've put together some little wrappers to reduce the amount of boilerplate needed when installing libraries. These can be pulled in using FetchContent. Please see cmake-helpers for more details.

Project Structure

When creating a library that is going to be used via installing (find_package) and/or add_subdirectory/FetchContent, it is wise to ensure the include paths for files are the same for both. For this reason it's (in my humble opinion) best to format your directory structure like so:

|-- <library-name>/
    |-- include/
        |-- <library-name>/
            |-- file1.h
            |-- file2.h
            |-- etc...
    |-- src/
        |-- file1.cpp
        |-- file2.cpp
        |-- etc...
    |-- CMakeLists.txt

When you specify target_include_directories (see below), have it point to the include/ folder so all includes wind up looking like #include "library-name/file1.h" as opposed to just #include "file1.h". This helps to compartmentalize the library files (similar to a namespace).

target_include_directories(
    ${PROJECT_NAME}
    INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
              $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)

The install command for the interface (.h) files then looks like this:

install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/include/${PROJECT_NAME}
        DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME})

Now the include paths for the library will always be consistent whether using find_package or FetchContent.

Aside: For more information on approaches to project structure checkout out Pitchfork by vector-of-bool.

CMake Resources

I've been attempting to learn CMake for a while and have built up quite a list of articles/blogs/documentation that have helped inform my understanding up to this point. Please see them listed below (mainly for my benefit so I have them all in one place).

Articles

Documentation

Stack Overflow

YouTube

Books

Other

  • Cpplang Slack #cmake channel
    • There's some super helpful people on there, the search functionality is great too (someone likely will have had your problem before 😉 ).
  • vector-of-bool
    • Was incredibly kind in answering some of my dumb CMake questions - thank you!
Comments
  • Feature/external project add

    Feature/external project add

    Created an example with ExternalProject_Add

    Builds a very simple project which requires 3 external libraries: restbed, rapidjson and catch2. All 3 libraries are got with ExternalProject_Add using their respective .cmake file inside cmake directory.

    Although catch2 and rapidjson worked just fine with FetchContent, restbed did not and I wanted to have a consistent way of adding the libraries to the project.

    From what I've researched the adding part is more or less standard:

    • each library gets its own .cmake file (because different settings)
    • call ExternalProject_Add with each library's particular options
    • create the directories needed beforehand so I could set INTERFACE_INCLUDE_DIRECTORIES which does not work if the directory does not exist
    • create an IMPORTED target
    • set_target_properties
    • call add_dependency()

    Use the newly created target in the main CMakeLists.txt file

    Tested on Windows with Visual Studio 2019 and on CentOS 7 with GCC 9.3

    opened by smeualex 23
  • Installing is bad

    Installing is bad

    Generally, installing means you've made the local system and specific compiler for a project some sort of default.

    This is bad. Modern developers need to compile for multiple targets using multiple compilers and multiple versions of dependencies. For example, what does it mean to "install" something like openssl when you want to use it for multiple versions of Android, iOS, your local machine, a Windows 7 desktop app, and some embedded system? Even if you think you're just running on your local machine, you probably have several different versions of compilers you use - clang, gcc, some Microsoft thing, some other version of some Microsoft thing, etc.

    Installing isn't a useful concept in 2019. Build dependencies, always and everywhere.

    opened by banshee 10
  • Fixes/cmake fetch content

    Fixes/cmake fetch content

    2 minor fixes to the fetch-content example to make the build ok

    a typo (case error) in main.cpp CMake FetchContent_Declare defaults to origin/master [ bit-field-enum-class is on origin/main]

    opened by smeualex 8
  • shared library example met build error

    shared library example met build error

    I try a few times to build core/shared/application. The following error occurs. The detailed log as follows

    [email protected]:~/cmake-examples/examples/core/shared/application$ cmake --build build
    Checking file [/home/user/cmake-examples/examples/core/shared/library/install/lib/cmake/calculator-shared/calculator-sharedConfig.cmake]
    Checking file [/home/user/cmake-examples/examples/core/shared/library/install/lib/cmake/calculator-shared/calculator-shared-config.cmake]
    -- Configuring done
    -- Generating done
    -- Build files have been written to: /home/user/cmake-examples/examples/core/shared/application/build
    Scanning dependencies of target calculator-app
    [ 50%] Building CXX object CMakeFiles/calculator-app.dir/main.cpp.o
    [100%] Linking CXX executable calculator-app
    /usr/bin/ld: CMakeFiles/calculator-app.dir/main.cpp.o: in function `main':
    main.cpp:(.text+0x1e): undefined reference to `calc_pow'
    /usr/bin/ld: calculator-app: hidden symbol `calc_pow' isn't defined
    /usr/bin/ld: final link failed: bad value
    collect2: error: ld returned 1 exit status
    make[2]: *** [CMakeFiles/calculator-app.dir/build.make:85: calculator-app] Error 1
    make[1]: *** [CMakeFiles/Makefile2:76: CMakeFiles/calculator-app.dir/all] Error 2
    make: *** [Makefile:84: all] Error 2
    
    
    opened by HomeLH 2
  • Update CMakeLists.txt files to use target_sources

    Update CMakeLists.txt files to use target_sources

    After watching a new CMake video (https://youtu.be/y9kSr5enrSk) the speaker made mention of the new(ish) command target_sources which is now preferable to listing source files in the add_library/add_executable commands (it's possible to get more fine grained control of visibility with PRIVATE/INTERFACE/PUBLIC too). Should really update the examples to use this! (Soon...)

    Also should add the new video to the README!

    opened by pr0g 0
Owner
Tom Hulton-Harrop
Tom Hulton-Harrop
The code implemented in ROS projects a point cloud obtained by a Velodyne VLP16 3D-Lidar sensor on an image from an RGB camera.

PointCloud on Image The code implemented in ROS projects a point cloud obtained by a Velodyne VLP16 3D-Lidar sensor on an image from an RGB camera. Th

Edison Velasco Sánchez 5 Aug 12, 2022
Eclipse Deeplearning4J (DL4J) ecosystem is a set of projects intended to support all the needs of a JVM based deep learning application

Suite of tools for deploying and training deep learning models using the JVM. Highlights include model import for keras, tensorflow, and onnx/pytorch, a modular and tiny c++ library for running math code and a java based math library on top of the core c++ library. Also includes samediff: a pytorch/tensorflow like library for running deep learning using automatic differentiation.

Eclipse Foundation 12.6k Sep 22, 2022
Repository for course content (homeworks, projects, recitation exercises) of CSCI 1300 in Spring 2022.

CSCI1300 Spring 2022 Repository for course content (e.g. homework assignments, project write-ups, recitation exercises) of CSCI 1300 in Spring 2022. C

null 12 Apr 6, 2022
Collection of Fluid Structure Interaction codes, used for one of my PhD courses

Continuum mechanics and fluid-structure interaction problems mathematical modeling and numerical approximation Fluid-structure interaction (FSI) refer

Luca Heltai 3 Aug 12, 2022
A collection of useful features to customize and improve existing OpenXR applications.

OpenXR Toolkit This software provides a collection of useful features to customize and improve existing OpenXR applications, including render upscalin

Matthieu Bucchianeri 119 Sep 20, 2022
C-based/Cached/Core Computer Vision Library, A Modern Computer Vision Library

Build Status Travis CI VM: Linux x64: Raspberry Pi 3: Jetson TX2: Backstory I set to build ccv with a minimalism inspiration. That was back in 2010, o

Liu Liu 6.9k Sep 21, 2022
📚 Modern C++ Tutorial: C++11/14/17/20 On the Fly

The book claims to be "On the Fly". Its intent is to provide a comprehensive introduction to the relevant features regarding modern C++ (before 2020s). Readers can choose interesting content according to the following table of content to learn and quickly familiarize the new features you would like to learn. Readers should be aware that not all of these features are required. Instead, it should be learned when you really need it.

Changkun Ou 18.7k Sep 16, 2022
A modern object detector inside fragment shaders

YOLOv4 Tiny in UnityCG/HLSL Video Demo: https://twitter.com/SCRNinVR/status/1380238589238206465?s=20 Overview YOLOv4 Tiny is one of the fastest object

null 46 Sep 15, 2022
A Modern C++ Data Sciences Toolkit

MeTA: ModErn Text Analysis Please visit our web page for information and tutorials about MeTA! Build Status (by branch) master: develop: Outline Intro

null 647 Sep 19, 2022
A fast and modern voxel based raytracing engine

CubiCAD A fast and modern voxel based raytracing engine Currently in heavy development and unusable at its current state. This reposity will hold the

RedNicStone 14 Sep 6, 2022
Modern(-ish) password hashing for your software and your servers

bcrypt Good password hashing for your software and your servers Installation To install bcrypt, simply: $ pip install bcrypt Note that bcrypt should b

Python Cryptographic Authority 909 Sep 16, 2022
simple neural network library in ANSI C

Genann Genann is a minimal, well-tested library for training and using feedforward artificial neural networks (ANN) in C. Its primary focus is on bein

Lewis Van Winkle 1.3k Sep 15, 2022
Simple samples for TensorRT programming

Introduction This is a collection of simplified TensorRT samples to get you started with TensorRT programming. Most of the samples are written in C++,

NVIDIA Corporation 547 Sep 20, 2022
A simple demonstration of how PyTorch autograd works

简单地演示了 PyTorch 中自动求导机制的原理。 官方博客:https://pytorch.org/blog/overview-of-pytorch-autograd-engine/ 编译运行 使用 Bazel bazel run autograd_test 包含了一个使用 MSE 损失函数的一

Howard Lau 14 Feb 24, 2022
A simple facial recognition script using OpenCV's FaceRecognizer module implemented in C++

Local Binary Patterns Histogram Recognizer A proyect that implements the LBPHRecognizer class of the OpenCV library to determine if a detected face co

Pablo Agustín Ortega-Kral 0 Jan 18, 2022
A simple ros wrapper for apriltag-cpp

Ros wrapper for apriltags-cpp Ros wrapper of the APRIL tags library, using OpenCV (and optionally, CGAL). Requirements Currently, apriltags-cpp requir

Robot Perception & Navigation Group (RPNG) 6 Dec 30, 2021
It is a simple AI model running at Art-Pi.

Garbage Classification Device at Embedded AI Summer School 2021 of Nanjing IC Training Base Based on garbage datasets online, apply TensorFlow to get

MJ.XU 7 Aug 29, 2022
AGE is a simple 2D console game engine runs in UNIX using third library Ncurses.

AGE-Game-Engine AGE is a simple 2D console game engine runs in UNIX using third library Ncurses. How-To-Run You need to install ncurses using the foll

SIHAN LI 1 Dec 16, 2021
EdgeKiller is a simple application that fully replaces Microsoft Edge with the Browser of choice.

EdgeKiller EdgeKiller is a simple application that fully replaces Microsoft Edge with the Browser of choice, while also intercepting all the microsoft

Jan Ochwat 2 Nov 30, 2021