The first step everyone takes when learning C++ is to write a “hello world” program. Since CMake is the most popular build system generator for C++, you must also learn how to create C++ programs with
In this post, we look at how to use
add_executable(...) to create a simple C++ program with CMake.
Contents of this post:
- Video demonstrating how to create executables with CMake.
- Explaining the simple version of
- Explaining advanced parameters and modes of
- Further reading.
Video – Creating Simple Programs With CMake
For probably 95% of the use cases, creating simple executables from a couple of different
cpp files is enough. For this reason, the video below demonstrates how you can use CMake to create a simple “hello world” program with
Moreover, if you’re interested in learning about the different modes and parameters for
add_executable(...), check out the following sections!
Simple Usage Of CMake
add_executable For Creating Programs
Ideally, your first program will look something like the example in the video above. For example, if you’re creating a “hello world” program, then your main
CMakeLists.txt will probably look something like the following.
cmake_minimum_required(VERSION 3.16) project(MyProgram LANGUAGES CXX) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) add_executable(MyProgram my_program.cpp)
In the snippet above, lines 1-6 are boilerplate CMake code. Interestingly, these lines just tell CMake what version it supports, what to look for in a compiler, and the C++ standard to use.
add_executable(MyProgram my_program.cpp) call at line 8 will create an executable called
MyProgram.exe on Windows).
In addition, the executable is created from compiling the files given after the name. For example, the
MyProgram above is created from the file
my_program.cpp, but you could also have
add_executable(MyComplexProgram my_source1.cpp my_source2.cpp), that creates
Generally, it’s not necessary to add the header files to the
add_executable(...) call. Due to C++ compilers copying and pasting the header file contents when you write
#include "...", you don’t need to specify which headers will be used in your executable! However, if you’re including other libraries into your executables with
target_link_libraries(...), you may want to see how to add include directories to you libraries in C++.
Advanced Modes And Options For CMake
If you’re planning to become an advance user, then you should probably learn all the modes and parameters you can pass to
add_executable(...). Specifically, the following block outlines most (if not all) useful options to
// Compile executable target mode add_executable(<name> [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL] [source1] [source2 ...]) // Importing an EXE mode add_executable(<name> IMPORTED [GLOBAL]) // Aliasing another target mode add_executable(<name> ALIAS <target>)
Luckily for you, the rest of this section provides explanations, tips and demos for each mode and parameter.
Extra Options To The Compiling Mode Of
As we’ve seen, the most common form of
add_executable(...) is the one used to create programs out of source files. Specifically, the parameters you can pass to line 2 above are summarised in the list below.
WIN32is used to create Windows applications. This means that your application will be created with the
WinMain()entry point, and it will be registered as a graphical application. Unsurprisingly, this option is ignored in non-Windows platforms, and you will need to make sure your application is compliant with the
msvccompiler (entry point matches the expected params, etc). I’ve been developing on Windows and this is rarely used, unless you want to create a Windows-specific app.
MACOSX_BUNDLEwill basically do something similar to
WIN32, but in iOS/OSX. I’m not very experienced with this option, but if you’re intending on developing apps for iOS/OSX, I’d recommend reading the documentation on MACOSX_BUNDLE.
EXCLUDE_FROM_ALLstops your program from building by default when calling
cmake --build ....
Interestingly, you will hardly ever use the options in the list above. Perhaps you may want to use
EXCLUDE_FROM_ALL on a few programs that you don’t want to build by default. As an example, I recently worked on a project that had a compression tool. Since this tool was more of a developer tool, we used
EXCLUDE_FROM_ALL so that it would only build when
cmake --target compression --build ... was called.
Importing Programs Built Outside With CMake
Although it’s kind of a rare situation, you may want to bring executables / programs built outside your project into the CMake project. Why would you want to do this? Well, by importing an executable into CMake, it will have a CMake target name, and you can simply refer to it in your build with this CMake name.
For example, say you want to check the formatting of your code as part of your build with
clang-format. Let’s also assume that you have this tool installed somewhere that is not in your
PATH, and you’re not using an IDE with
clang-format support (very unusual, I know). What you would need to do is something like the following block.
add_executable(ClangFormat IMPORTED) set_property(TARGET ClangFormat PROPERTY IMPORTED_LOCATION "/path/to/clang-format")
In addition, you can use the likes of
add_custom_command(...) to tell CMake to use the
ClangFormat target (executable) to inspect your files during your build. CMake would essentially replace the
ClangFormat target with the path declared in
set_property(... IMPORTED_LOCATION ...), hence you should always define that property, or CMake won’t know where your tool is!
I understand that there are much better ways to run
clang-format in your build, but this is just a simple example. Essentially,
IMPORTED executables are very useful when you need to use a tool in your CMake, such as generating files or inspecting them with third-party tools.
Lastly, you can add
GLOBAL to the
add_executable(... IMPORTED ...) if you want the imported program to be visible outside the current
CMakeLists.txt file (and its children). By default, this doesn’t happen, unlike executables you compile with
Aliasing Executable Targets With add_executable(… ALIAS …)
Perhaps the simplest form of
add_executable(...) is the alias one. Briefly speaking, it allows you to refer to different programs using different names. For example, the code block below shows how to refer to the
MyProgram target we created in the first section with a different name.
add_executable(MyAliasedProgram ALIAS MyProgram)
Unsurprisingly, whenever you then use
MyAliasedProgram, this will actually refer to
However, note that aliased programs / executables are read-only. This means that you cannot modify properties of the aliased (original) target.
I’ve found this to be quite useful for referring to a program that can have two different implementations. For example, for debugging a third-party tool, you may want to use the executable built with more information (verbose) if it’s provided to you. On the other hand, you may want to use the production build of your third-party tool if verbose information isn’t needed.
To be honest, I’ve only ever used the
ALIAS option for executables a couple of times, you will rarely need it. There are also many different rules as to how you can use aliases, so I’d recommend checking the documentation for
add_executable(... ALIAS ...).
Where Do I Go Next? What Other CMake Can I Learn?
Now that you at least know all the options for
add_executable(...), you should probably read more on creating libraries with CMake’s
add_library(...) command. Moreover, you can also improve your CMake arsenal by knowing how to expose headers with CMake’s