---
category: tool
tool: cmake
contributors:
    - ["Bruno Alano", "https://github.com/brunoalano"]
filename: CMake
---

CMake is a cross-platform, open-source build system. This tool allows you to test, 
compile, and create packages of your source code.

The problem that CMake tries to solve is the problem of Makefiles and 
Autoconfigure on cross-platforms (different make interpreters have different 
commands) and the ease-of-use on linking 3rd party libraries.

CMake is an extensible, open-source system that manages the build process in 
an operating system and compiler-agnostic manner. Unlike many 
cross-platform systems, CMake is designed to be used in conjunction with the 
native build environment. Simple configuration files placed in each source 
directory (called CMakeLists.txt files) are used to generate standard build 
files (e.g., makefiles on Unix and projects/workspaces in Windows MSVC) which 
are used in the usual way.

```cmake
# In CMake, this is a comment

# To run our code, please perform the following commands:
#  - mkdir build && cd build
#  - cmake ..
#  - make
# 
# With those steps, we will follow the best practice to compile into a subdir
# and the second line will request to CMake to generate a new OS-dependent
# Makefile. Finally, run the native Make command.

#------------------------------------------------------------------------------
# Basic
#------------------------------------------------------------------------------
#
# The CMake file MUST be named as "CMakeLists.txt".

# Setup the minimum version required of CMake to generate the Makefile
cmake_minimum_required (VERSION 2.8)

# Raises a FATAL_ERROR if version < 2.8
cmake_minimum_required (VERSION 2.8 FATAL_ERROR)

# We define the name of our project, and this changes some directories
# naming convention generated by CMake. We can send the LANG of code
# as the second param
project (learncmake C)

# Set the project source dir (just convention)
set( LEARN_CMAKE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} )
set( LEARN_CMAKE_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR} )

# It's useful to set up the current version of our code in the build system
# using a `semver` style
set (LEARN_CMAKE_VERSION_MAJOR 1)
set (LEARN_CMAKE_VERSION_MINOR 0)
set (LEARN_CMAKE_VERSION_PATCH 0)

# Send the variables (version number) to the source code header
configure_file (
  "${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"
  "${PROJECT_BINARY_DIR}/TutorialConfig.h"
)

# Include Directories
# In GCC, this will invoke the "-I" command
include_directories( include )

# Where are the additional libraries installed? Note: provide includes
# path here, subsequent checks will resolve everything else
set( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/CMake/modules/" )

# Conditions
if ( CONDITION )
  # Output!

  # Incidental information
  message(STATUS "My message")

  # CMake Warning, continue processing
  message(WARNING "My message")

  # CMake Warning (dev), continue processing
  message(AUTHOR_WARNING "My message")

  # CMake Error, continue processing, but skip generation
  message(SEND_ERROR "My message")

  # CMake Error, stop processing and generation
  message(FATAL_ERROR "My message")
endif()

if( CONDITION )

elseif( CONDITION )

else( CONDITION )

endif( CONDITION )

# Loops
foreach(loop_var arg1 arg2 ...)
  COMMAND1(ARGS ...)
  COMMAND2(ARGS ...)
  ...
endforeach(loop_var)

foreach(loop_var RANGE total)
foreach(loop_var RANGE start stop [step])

foreach(loop_var IN [LISTS [list1 [...]]]
                    [ITEMS [item1 [...]]])

while(condition)
  COMMAND1(ARGS ...)
  COMMAND2(ARGS ...)
  ...
endwhile(condition)


# Logic Operations
if(FALSE AND (FALSE OR TRUE))
  message("Don't display!")
endif()

# Set a regular, cache, or environment variable to a given value.
# If the PARENT_SCOPE option is given, the variable will be set in the scope
# above the current scope.
# `set(<variable> <value>... [PARENT_SCOPE])`

# How to reference variables inside quoted and unquoted arguments?
# A variable reference is replaced by either the variable value or by the 
# empty string if the variable is not set.
${variable_name}

# Lists
# Setup the list of source files
set( LEARN_CMAKE_SOURCES 
  src/main.c
  src/imagem.c
  src/pather.c
)

# Calls the compiler
#
# ${PROJECT_NAME} refers to Learn_CMake 
add_executable( ${PROJECT_NAME} ${LEARN_CMAKE_SOURCES} )

# Link the libraries
target_link_libraries( ${PROJECT_NAME} ${LIBS} m )

# Where are the additional libraries installed? Note: provide includes
# path here, subsequent checks will resolve everything else
set( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/CMake/modules/" )

# Compiler Condition (gcc ; g++)
if ( "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" )
  message( STATUS "Setting the flags for ${CMAKE_C_COMPILER_ID} compiler" )
  add_definitions( --std=c99 )
endif()

# Check for OS
if( UNIX )
    set( LEARN_CMAKE_DEFINITIONS
        "${LEARN_CMAKE_DEFINITIONS} -Wall -Wextra -Werror -Wno-deprecated-declarations -Wno-unused-parameter -Wno-comment" )
endif()
```

### More Resources

+ [CMake tutorial](https://cmake.org/cmake-tutorial/)
+ [CMake documentation](https://cmake.org/documentation/)
+ [Mastering CMake](http://amzn.com/1930934319/)
+ [An Introduction to Modern CMake](https://cliutils.gitlab.io/modern-cmake/)
