Codectionary / Developer documentation / C++

Learn what CMakeLists.txt describes, configure a C++17 project, build it with a selected generator and locate its executable.

CMake describes a build; a compiler produces the program

CMake is a build-system generator and a project-configuration tool. A CMakeLists.txt file describes targets, source files and build requirements. During configuration, CMake finds a compiler and generates files for a native build tool such as Ninja, Make or a Visual Studio solution. The native build tool then invokes the compiler and linker. CMake is not itself a C++ compiler, and an IDE such as CLion is another separate tool.

For a single main.cpp, a direct g++ or clang++ command is simpler and remains a good way to learn. CMake becomes useful when projects have several source files, libraries or platforms, because the build description records relationships that you would otherwise repeat in shell commands. This guide is an optional next step after your first program.

Choose the tools before configuring

Install a current supported CMake release from Kitware or your trusted platform package source and check cmake --version. You also need a working C++ compiler and a compatible native build tool or IDE generator. On Windows, Visual Studio with the Desktop development with C++ workload is one complete path; in its Developer Command Prompt the MSVC environment is available. On macOS use Apple Command Line Tools; on Linux use your distribution’s G++ or Clang packages.

If you use CLion, it bundles CMake for its own project workflow, so you may not need another copy solely for the IDE. A separate terminal command still needs cmake to be available there. Check the compiler reported by CMake at configure time, because a successful cmake --version check alone does not establish that a toolchain is installed.

Check the CMake command available in this terminal

cmake --version

Create the source and CMakeLists.txt

Create a folder named hello-cmake containing main.cpp and CMakeLists.txt side by side. Save the complete greeting program below in main.cpp. Save the second block exactly as CMakeLists.txt, including its capital letters. Do not put these source files in build/: that directory is for generated output.

cmake_minimum_required(VERSION 3.16) states the oldest CMake version this small description is written for. project(HelloCpp LANGUAGES CXX) names the project and enables C++. add_executable(hello main.cpp) creates an executable target from main.cpp. target_compile_features(hello PRIVATE cxx_std_17) requires a compiler capable of at least C++17 for that target; CMake adds a standard flag when needed. It does not promise to force an exact C++17 mode if a compiler already defaults to a newer one.

main.cpp

#include <iostream>

int main() {
  std::cout << "Hello, Codectionary!\n";
  return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.16)
project(HelloCpp LANGUAGES CXX)

add_executable(hello main.cpp)
target_compile_features(hello PRIVATE cxx_std_17)

Configure a separate build directory

From hello-cmake/, run cmake -S . -B build. -S . points to the current source directory; -B build names a separate output directory. CMake reads CMakeLists.txt, checks the toolchain and generates the build system in build/. Read the configuration output to see which compiler and generator it selected. Configuration creates build instructions; it does not yet mean your C++ source has been compiled into the final program.

CMake chooses a default generator suited to the environment. A generator determines the native build files: for example, Ninja, Unix Makefiles or a Visual Studio solution. You can list locally available generators with cmake --help and select one using -G during a new configuration. An existing build directory remembers its generator and compiler; use a fresh build directory when changing either instead of mixing incompatible cached settings.

From the hello-cmake project folder

cmake -S . -B build

Optional: inspect generators available on this machine

cmake --help

Build and find the executable

Run cmake --build build. CMake delegates to the generated native build tool, which compiles and links the hello target. On Linux and macOS with a typical single-configuration Make or Ninja generator, run ./build/hello. With a single-configuration Ninja generator on Windows PowerShell, the file is commonly .\build\hello.exe. A multi-configuration generator such as Visual Studio usually puts a Debug build under build\Debug\hello.exe; use cmake --build build --config Debug and run that file. Check the build output or build directory rather than assuming every generator uses the same path.

The terminal should print Hello, Codectionary!. Edit the message, save and run cmake --build build again before rerunning the executable. If a source file is missing from add_executable, CMake will not build it simply because it exists in the folder. CMake does not decide whether your program behaves correctly; verify the output yourself.

Build with the configured generator

cmake --build build

Linux or macOS with a single-configuration generator

./build/hello

Windows PowerShell with a single-configuration generator

.\build\hello.exe

Windows PowerShell with a Visual Studio Debug generator

cmake --build build --config Debug
.\build\Debug\hello.exe

Add files when the project grows

The optional CMakeLists.txt below builds the two-source-file greeting project from the project-structure guide. add_executable lists both .cpp definitions. target_include_directories gives this target the include/ header location; PRIVATE means that this path is needed while building hello and is not passed to other targets. The compiler still needs both sources, and a header alone cannot repair a missing definition. CMake can also describe a reusable library target and link it to an executable as a later step.

Keep build/ outside the editable source tree in your version-control ignore rules where appropriate. If CMake reports a missing compiler, fix the selected toolchain. If it reports that a source file does not exist, check its spelling and path in CMakeLists.txt. If the compiler reports a C++ error, correct the source. Each error belongs to a different stage.

Optional CMakeLists.txt for the project-structure guide

cmake_minimum_required(VERSION 3.16)
project(HelloProject LANGUAGES CXX)

add_executable(hello src/main.cpp src/greeting.cpp)
target_include_directories(hello PRIVATE include)
target_compile_features(hello PRIVATE cxx_std_17)

Syntax

cmake_minimum_required(VERSION 3.16)
project(HelloCpp LANGUAGES CXX)

add_executable(hello main.cpp)
target_compile_features(hello PRIVATE cxx_std_17)

Examples

A small C++17 executable target

Save beside main.cpp, then configure with cmake -S . -B build and compile with cmake --build build.

cmake_minimum_required(VERSION 3.16)
project(HelloCpp LANGUAGES CXX)

add_executable(hello main.cpp)
target_compile_features(hello PRIVATE cxx_std_17)
  1. The goal is to describe one executable called hello without writing a platform-specific compiler command into the project.
  2. The first two commands set a supported CMake baseline and establish a C++ project. add_executable names the output target and its source file.
  3. target_compile_features asks the selected compiler for C++17 support for hello. CMake generates native build files; it does not execute C++ source itself.
  4. The matching main.cpp prints the greeting. Configure first, build second, then run the executable from the location used by your generator.

Best practices

  • Learn a direct single-file compiler command before introducing a build system.
  • Keep source and generated build directories separate.
  • Inspect the selected compiler and generator, especially when switching tools or operating systems.

Runtime & versions

Compiled native applications. Feature availability depends on the language and runtime version used by your project; consult the official reference below.

ISO C++ resources

Specifications & further reading