Introduction to the Basics · Modern CMake (2024)

Minimum Version

Here's the first line of every CMakeLists.txt, which is the required name ofthe file CMake looks for:

cmake_minimum_required(VERSION 3.1)

Let's mention a bit of CMake syntax. The command namecmake_minimum_required is case insensitive, so the common practiceis to use lower case. 1 The VERSION is a special keyword for thisfunction. And the value of the version follows the keyword. Like everywhere inthis book, just click on the command name to see the official documentation,and use the dropdown to switch documentation between CMake versions.

This line is special! 2 The version of CMake will also dictate the policies,which define behavior changes. So, if you set minimum_required to VERSION 2.8, you'll get the wrong linking behavior on macOS, for example, even in thenewest CMake versions. If you set it to 3.3 or less, you'll get the wronghidden symbols behaviour, etc. A list of policies and versions is available atpolicies.

Starting in CMake 3.12, this supports a range, such as VERSION 3.1...3.15;this means you support as low as 3.1 but have also tested it with the newpolicy settings up to 3.15. This is much nicer on users that need the bettersettings, and due to a trick in the syntax, it's backward compatible with olderversions of CMake (though actually running CMake 3.1-3.11 will only set the 3.1version of the policies in this example, since those versions didn't treat thisspecially). New versions of policies tend to be most important for macOS andWindows users, who also usually have a very recent version of CMake.

This is what new projects should do:

cmake_minimum_required(VERSION 3.7...3.29)if(${CMAKE_VERSION} VERSION_LESS 3.12) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})endif()

If CMake version is less than 3.12, the if block will be true, and the policywill be set to the current CMake version. If CMake is 3.12 or higher, the ifblock will be false, but the new syntax in cmake_minimum_required will berespected and this will continue to work properly!

WARNING: MSVC's CMake server mode originally had abug in reading this format, so ifyou need to support non-command line Windows builds for older MSVC versions,you will want to do this instead:

cmake_minimum_required(VERSION 3.7)if(${CMAKE_VERSION} VERSION_LESS 3.29) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})else() cmake_policy(VERSION 3.29)endif()

If you really need to set to a low value here, you can usecmake_policy to conditionally increase the policy level or set aspecific policy. Please at least do this for your macOS users!

Setting a project

Now, every top-level CMake file will have the next line:

project(MyProject VERSION 1.0 DESCRIPTION "Very nice project" LANGUAGES CXX)

Now we see even more syntax. Strings are quoted, whitespace doesn't matter, andthe name of the project is the first argument (positional). All the keywordarguments here are optional. The version sets a bunch of variables, likeMyProject_VERSION and PROJECT_VERSION. The languages are C, CXX,Fortran, ASM, CUDA (CMake 3.8+), CSharp (3.8+), and SWIFT (CMake3.15+ experimental). C CXX is the default. In CMake 3.9, DESCRIPTION wasadded to set a project description, as well. The documentation forproject may be helpful.

You can addcommentswith the # character. CMake does have an inline syntax for comments too, butit's rarely used.

There's really nothing special about the project name. No targets are added at this point.

Making an executable

Although libraries are much more interesting, and we'll spend most of our timewith them, let's start with a simple executable.

add_executable(one two.cpp three.h)

There are several things to unpack here. one is both the name of the executable file generated, and the name of the CMake target created (you'll hear a lot more about targets soon, I promise). The source file list comes next, and you can list as many as you'd like. CMake is smart, and will only compile source file extensions. The headers will be, for most intents and purposes, ignored; the only reason to list them is to get them to show up in IDEs. Targets show up as folders in many IDEs. More about the general build system and targets is available at buildsystem.

Making a library

Making a library is done with add_library, and is just about as simple:

add_library(one STATIC two.cpp three.h)

You get to pick a type of library, STATIC, SHARED, or MODULE. If you leave this choice off, the value of BUILD_SHARED_LIBS will be used to pick between STATIC and SHARED.

As you'll see in the following sections, often you'll need to make a fictional target, that is, one where nothing needs to be compiled, for example, for a header-only library. That is called an INTERFACE library, and is another choice; the only difference is it cannot be followed by filenames.

You can also make an ALIAS library with an existing library, which simply gives you a new name for a target. The one benefit to this is that you can make libraries with :: in the name (which you'll see later). 3

Targets are your friend

Now we've specified a target, how do we add information about it? For example, maybe it needs an include directory:

target_include_directories(one PUBLIC include)

target_include_directories adds an include directory to a target. PUBLICdoesn't mean much for an executable; for a library it lets CMake know that any targets that link to this target must also need that include directory. Other options arePRIVATE(only affect the current target, not dependencies), andINTERFACE (only needed for dependencies).

We can then chain targets:

add_library(another STATIC another.cpp another.h)target_link_libraries(another PUBLIC one)

target_link_libraries is probably the most useful and confusing command in CMake. It takes a target (another) and adds a dependency if a target is given. If no target of that name (one) exists, then it adds a link to a library called one on your path (hence the name of the command). Or you can give it a full path to a library. Or a linker flag. Just to add a final bit of confusion, classic CMake allowed you to skip the keyword selection of PUBLIC, etc. If this was done on a target, you'll get an error if you try to mix styles further down the chain.

Focus on using targets everywhere, and keywords everywhere, and you'll be fine.

Targets can have include directories, linked libraries (or linked targets), compile options, compile definitions, compile features (see the C++11 chapter), and more. As you'll see in the two including projects chapters, you can often get targets (and always make targets) to represent all the libraries you use. Even things that are not true libraries, like OpenMP, can be represented with targets. This is why Modern CMake is great!

Dive in

See if you can follow the following file. It makes a simple C++11 library and a program using it. No dependencies. I'll discuss more C++ standard options later, using the CMake 3.8 system for now.

cmake_minimum_required(VERSION 3.8)project(Calculator LANGUAGES CXX)add_library(calclib STATIC src/calclib.cpp include/calc/lib.hpp)target_include_directories(calclib PUBLIC include)target_compile_features(calclib PUBLIC cxx_std_11)add_executable(calc apps/calc.cpp)target_link_libraries(calc PUBLIC calclib)
1. In this book, I'll mostly avoid showing you the wrong way to do things; you can find plenty of examples of that online. I'll mention alternatives occasionally, but these are not recommended unless they are absolutely necessary; often they are just there to help you read older CMake code.
2. You will sometimes see FATAL_ERROR here, that was needed to support nice failures when running this in CMake <2.6, which should not be a problem anymore.
3. The :: syntax was originally intended for INTERFACE IMPORTED libraries, which were explicitly supposed to be libraries defined outside the current project. But, because of this, most of the target_* commands don't work on IMPORTED libraries, making them hard to set up yourself. So don't use the IMPORTED keyword for now, and use an ALIAS target instead; it will be fine until you start exporting targets. This limitation was fixed in CMake 3.11.
Introduction to the Basics · Modern CMake (2024)

FAQs

Is CMake still relevant? ›

Since the initial CMake implementation , CMake has grown in popularity as a build tool. Both the developer and user communities continue to grow.

What is CMake for beginners? ›

CMake stands for cross-platform make. It is a tool designed to manage the build process of software using compiler-independent methods. It was created to support complex directory hierarchies and applications that depend on several libraries. Unlike traditional build systems, CMake does not build the software directly.

What is CMake and why it is used? ›

CMake is not a build system itself; it generates another system's build files. It supports directory hierarchies and applications that depend on multiple libraries. It can invoke native build environments such as Make, Qt Creator, Ninja, Android Studio, Apple's Xcode, and Microsoft Visual Studio.

What is the best version of CMake? ›

CMake ≥ 3.21 is strongly recommended for general users for more robust and easy syntax. For project developers, we recommend CMake ≥ 3.28 for C++20 modules and IDE integration.

Why is CMake such a mess? ›

Biggest issue is CMake as scripting language which is string typed, messy and hard to debug. Also, people do not read documentation and love to copy paste outdated examples to their projects.

Why use CMake instead of Visual Studio? ›

CMake is a better build system than Visual Studio projects and solutions. It is compact and much more easier to maintain even for Windows only projects. See CMake for Visual Studio Developers for some reasons.

What is the alternative to CMake? ›

The best overall CMake alternative is GNU Make. Other similar apps like CMake are SCons, GNU Automake, Leiningen, and FinalBuilder. CMake alternatives can be found in Other Continuous Delivery Software.

Does CMake need a compiler? ›

To build CMake, you will need a modern C++ compiler and the source distribution from the CMake Download page or Kitware's GitLab instance. To build CMake, follow the instructions in README. rst at the top of the source tree.

Is CMake only for C++? ›

It supports the C language, and can also be used with Java, Rust, and other languages. While it's possible to use CMake with other programming languages, you're much more likely to see it used with C++.

Is CMake free to use? ›

License Information

CMake is an open source license and comes with few restrictions typically seen at the university. All use cases (e.g., commercial research) and roles (e.g., alumni) are allowed to use the software. The software is free and can be redistributed and/or modified.

What is the difference between CMake and CMake? ›

CMake and Make work on different principles. With CMake you specify build targets, and assign source files and various parameters. With Make, you create a set of build rules. Each rule has a target file, a set of dependencies (to the right of the colon), and the commands needed to perform the rule's build task.

Why are we using CMake? ›

CMake is an open source build system and configuration tool used to manage the build process of software projects. It allows developers to define the build process in a platform-independent and efficient way by creating a set of configuration files (CMakeLists. txt) that describe how the project should be built.

Do we really need CMake? ›

CMake is better for large projects, and helps you generate a Makefile (or Ninja, or other build system) to build the project. CMake helps with building for multiple operating systems and such like. Make is much simpler for those projects that have few files to build, and no real need to build in different environments.

Is CMake server 7 deprecated? ›

how i can repair this? CMake server mode is an old way of communicating between CMake and your IDE. It has been deprecated in favor of the file API. You're receiving this message because your IDE is still using server mode and hasn't been updated for file API.

Is CMake better than Autotools? ›

If you use CMake, you never have to worry about shell incompatibilities. CMake works on every major platform, including Windows. Thirdly, as we discussed earlier, autotools often exposes details of the underlying platform. It's a real challenge to use autotools without introducing Linux dependencies in your code.

References

Top Articles
Latest Posts
Article information

Author: Dan Stracke

Last Updated:

Views: 5311

Rating: 4.2 / 5 (43 voted)

Reviews: 90% of readers found this page helpful

Author information

Name: Dan Stracke

Birthday: 1992-08-25

Address: 2253 Brown Springs, East Alla, OH 38634-0309

Phone: +398735162064

Job: Investor Government Associate

Hobby: Shopping, LARPing, Scrapbooking, Surfing, Slacklining, Dance, Glassblowing

Introduction: My name is Dan Stracke, I am a homely, gleaming, glamorous, inquisitive, homely, gorgeous, light person who loves writing and wants to share my knowledge and understanding with you.