Learning CMake 2: working with targets
Tags: cmake, cpp, buildsystems, crossplatform
Published: 2019-10-14 19:50:56

---
title: Learning CMake 2: working with targets
published: true
description: A different approach to learn CMake.
tags: cmake, cpp, buildsystems, crossplatform
cover_image: https://cdn.dribbble.com/users/2939235/screenshots/6575723/how-to-build-effective-web-pages.jpg
series: "Learning CMake"
---

In the previous post, we learnt how to build a really basic application. For that, we created a CMake target using the `add_executable` CMake macro. During this post, I will explain some extra things can we do with targets.

# Compiler definitions

Sometimes you will need to build software that is using definitions. Example:

```c
#include <stdio.h>
int main()
{
   #ifdef AWESOME
      char *message = "YOU ARE AWESOME!\n";
   #else
      char *message = "Sorry, you are not awesome\n";
   #endif
   printf("%s", message);

   return 0;
}
```

This code is using the `AWESOME` definition. If we provide to the compiler the definition `AWESOME` the final application will print "`YOU ARE AWESOME!`". Otherwise, it will print "`Sorry, you are not awesome`". How can we handle this situation from CMake?

```cmake
cmake_minimum_required(VERSION 3.5)
project(example)

add_executable(my_app
    "${CMAKE_CURRENT_SOURCE_DIR}/myapp.c"
)

target_compile_definitions(my_app
    PRIVATE
        AWESOME
)
```

As before, we created one target (that will build an executable) using the source files. Then, we provide the definitions needed by that target using the `target_compile_definitions`.

There are other methods to the compiler calls like `add_definitions` but they are discouraged. Why? Using `target_compile_definitions` we will apply the definitions just to the desired targets and `add_definitions` will ad them to all the targets.

The `PRIVATE`keyword references to the visibility of the definition. There are 3 visibility modes:
* PRIVATE: used when the definitions will be applied just for the current target.
* INTERFACE: used when the definitions need to be applied to targets that link against the given target.
* PUBLIC: it is the union between the `INTERFACE` and `PRIVATE` vibilities. It will use the given definitions to build the current target and also targets that link against the current target.

`INTERFACE` and `PUBLIC` visibility modes are useful for libraries.

# Include directories
Now, let's imagine we need to build a software where the folder structure is this one:

```sh
.
├── include
│   └── awesome.h
└── src
    └── myapp.c
```

The file `src/myapp.c` contains:

```c
#include "awesome.h"

int main()
{
   print_awesome();
   return 0;
}
```

And `include/awesome.h`:

```c
#ifndef _awesome_h
#define _awesome_h

#include <stdio.h>

void print_awesome() {
    printf("AWESOME MESSAGE\n");
}

#endif
```

We need to add the `include` directory as part of the build of the application. How can this be done? It is really similar to how we add a compiler definition:

```cmake
cmake_minimum_required(VERSION 3.5)
project(example)

add_executable(my_app
    "${CMAKE_CURRENT_SOURCE_DIR}/src/myapp.c"
)

target_include_directories(my_app
    PRIVATE
        "${CMAKE_CURRENT_SOURCE_DIR}/include"
)
```

The visibility parameters has the same meaning than in the case of `target_compile_definitions`.

# Target properties
The macros shown during the previous sections will modify the target properties. You can access these properties using the [get_target_property](https://cmake.org/cmake/help/latest/command/get_target_property.html) CMake macro. Also, you can set some of these properties with the [set_target_properties](https://cmake.org/cmake/help/latest/command/set_target_properties.html) CMake macro.

You will find [the complete list of properties in this link](https://cmake.org/cmake/help/latest/manual/cmake-properties.7.html). Some of then can be modified and others only will apply depending on different situations like the operating system or the generator used to create the build system.

Pay special attention to these properties where the token `<CONFIG>` is present: these variables will be used in multiconfiguration generators: depending on the configuration used to build or generate the build system. For instance, the property `OUTPUT_NAME_<CONFIG>` is used to the base name for output files created for an executable or library target. It can exists as `OUTPUT_NAME_RELEASE` and `OUTPUT_NAME_DEBUG`

# Recap
What did we learn?
* How to work with targets
* The use of `target_compile_definitions` and `target_include_directories`
    * How the visibility works for these CMake macros
* How to get and modify the target properties values