Skip to content

Tutorial: Build your SFML project with CMake

Trifonov Dmitriy edited this page Jul 29, 2023 · 17 revisions

CMake allows your project to be built in various environments, including most popular Makefiles and IDE's. It is available from SFML 2.0.

In this tutorial we'll write a simple CMake configuration file with centralized version numbering, and see how to integrate SFML in it. This example is not for compiling SFML using CMake but for creating an example project that utilizes an existing build of SFML.

The source files

First, create a cmake_modules directory and copy FindSFML.cmake in it. FindXXXX is automatically searched by CMake's find_package command.

Then create a main.cpp, for instance:

#include "config.h"
#include <iostream>
#include <SFML/Graphics.hpp>
using namespace std;

int main(int argc, char* argv[]) {

  // Code adapted from the SFML 2 "Window" example.

  cout << "Version " << myproject_VERSION_MAJOR << "." << myproject_VERSION_MINOR << endl;

  sf::Window App(sf::VideoMode(800, 600), "myproject");

  while (App.isOpen()) {
    sf::Event Event;
    while (App.pollEvent(Event)) {
      if (Event.type == sf::Event::Closed)
	App.close();
    }
    App.display();
  }
}

We use a config.h file that is built by CMake, let's also create a config.h.in file:

#define myproject_VERSION_MAJOR @myproject_VERSION_MAJOR@
#define myproject_VERSION_MINOR @myproject_VERSION_MINOR@

And place your project license (such as the zlib license) in a file named COPYING.

CMake configuration

SFML version >= 2.5

Let's describe our project configuration in the CMakeLists.txt file:

# SFML version >= 2.5
cmake_minimum_required(VERSION 3.1)


# Enable debug symbols by default
# must be done before project() statement
if(NOT CMAKE_BUILD_TYPE)
  set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build (Debug or Release)" FORCE)
endif()
# (you can also set it on the command line: -D CMAKE_BUILD_TYPE=Release)

project(myproject)

# Set version information in a config.h file
set(myproject_VERSION_MAJOR 1)
set(myproject_VERSION_MINOR 0)
configure_file(
  "${PROJECT_SOURCE_DIR}/config.h.in"
  "${PROJECT_BINARY_DIR}/config.h"
  )
include_directories("${PROJECT_BINARY_DIR}")

# Define sources and executable
set(EXECUTABLE_NAME "myproject")
add_executable(${EXECUTABLE_NAME} main.cpp)


# Detect and add SFML

# SFML version >= 2.5
# set(SFML_DIR "<sfml root prefix>/lib/cmake/SFML")
# ex) If you are using debian10, 11, ubuntu20.24, 22.04 and installed with apt package manager, set the values below.
# set(SFML_DIR "/usr/local/vcpkg/ports/sfml/SFML")
# ex) If you are using Windows, manually set the location where you installed SFML.
# set(SFML_DIR "C:/Users/yourname/library/frameworks/SFML-2.5.1/lib/cmake/SFML")
# ex) If you are using MacOS and installed with homebrew, set the values as shown below.
# set(SFML_DIR "/usr/local/Cellar/sfml/2.5.1_1/lib/cmake/SFML")

find_package(SFML 2.5 COMPONENTS network audio graphics window system REQUIRED)
if(SFML_FOUND)
  include_directories(${SFML_INCLUDE_DIR})
  # SFML version >= 2.5
  #In SFML Version 2.5 or later, ${SFML_LIBRARIES}, ${SFML_DEPENDENCIES}, ${SFML_INCLUDE_DIR} no longer exist. Specify libraries individually.
  target_link_libraries(${PROJECT_NAME} sfml-network sfml-audio sfml-graphics sfml-window sfml-system)
endif()


# Install target
install(TARGETS ${EXECUTABLE_NAME} DESTINATION bin)


# CPack packaging
include(InstallRequiredSystemLibraries)
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/COPYING")
set(CPACK_PACKAGE_VERSION_MAJOR "${myproject_VERSION_MAJOR}")
set(CPACK_PACKAGE_VERSION_MINOR "${myproject_VERSION_MINOR}")
include(CPack)

The interesting part is:

# Detect and add SFML
set(SFML_DIR "<sfml root prefix>/lib/cmake/SFML")
find_package(SFML 2.5 COMPONENTS network audio graphics window system REQUIRED)
target_link_libraries(${PROJECT_NAME} sfml-network sfml-audio sfml-graphics sfml-window sfml-system)
  • First set SFML_DIR to the SMFL of the location you want to use.
  • Then we request CMake to look for it in the system, and search for the specified modules (here I specified them all).
  • In SFML Version 2.5 or later, ${SFML_LIBRARIES}, ${SFML_DEPENDENCIES}, ${SFML_INCLUDE_DIR} no longer exist. For more information, visit this forum post. Specify libraries individually.

SFML version < 2.5

Let's describe our project configuration in the CMakeLists.txt file:

#Change this if you need to target a specific CMake version
# SFML version < 2.5
cmake_minimum_required(VERSION 2.6)


# Enable debug symbols by default
# must be done before project() statement
if(NOT CMAKE_BUILD_TYPE)
  set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build (Debug or Release)" FORCE)
endif()
# (you can also set it on the command line: -D CMAKE_BUILD_TYPE=Release)

project(myproject)

# Set version information in a config.h file
set(myproject_VERSION_MAJOR 1)
set(myproject_VERSION_MINOR 0)
configure_file(
  "${PROJECT_SOURCE_DIR}/config.h.in"
  "${PROJECT_BINARY_DIR}/config.h"
  )
include_directories("${PROJECT_BINARY_DIR}")

# Define sources and executable
set(EXECUTABLE_NAME "myproject")
add_executable(${EXECUTABLE_NAME} main.cpp)


# Detect and add SFML
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake_modules" ${CMAKE_MODULE_PATH})
#See the FindSFML.cmake file for additional details and instructions

# SFML version < 2.5
find_package(SFML 2.4 REQUIRED network audio graphics window system)
if(SFML_FOUND)
  include_directories(${SFML_INCLUDE_DIR})
  # SFML version < 2.5
  target_link_libraries(${EXECUTABLE_NAME} ${SFML_LIBRARIES} ${SFML_DEPENDENCIES})
endif()


# Install target
install(TARGETS ${EXECUTABLE_NAME} DESTINATION bin)


# CPack packaging
include(InstallRequiredSystemLibraries)
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/COPYING")
set(CPACK_PACKAGE_VERSION_MAJOR "${myproject_VERSION_MAJOR}")
set(CPACK_PACKAGE_VERSION_MINOR "${myproject_VERSION_MINOR}")
include(CPack)

The interesting part is:

# Detect and add SFML
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake_modules" ${CMAKE_MODULE_PATH})
find_package(SFML 2.4 REQUIRED COMPONENTS network audio graphics window system)
target_link_libraries(${EXECUTABLE_NAME} ${SFML_LIBRARIES} ${SFML_DEPENDENCIES})
  • First we specify where we stored the FindSFML.cmake module.
  • Then we request CMake to look for it in the system, and search for the specified modules (here I specified them all).
  • Last, we tell CMake to link our executable with the SFML libraries that it just found.

Additional libraries

Here are a few example of commonly used C/C++ libraries:

# OpenGL
find_package(OpenGL REQUIRED)
include_directories(${OPENGL_INCLUDE_DIR})
if (OPENGL_FOUND)
  target_link_libraries(${EXECUTABLE_NAME} ${OPENGL_LIBRARIES})
  # or: target_link_libraries(${EXECUTABLE_NAME} ${OPENGL_gl_LIBRARY})
  target_link_libraries(${EXECUTABLE_NAME} m)  # if you use maths.h
endif()
# boost::filesystem
#set(Boost_ADDITIONAL_VERSIONS "1.78" "1.78.0" "1.79" "1.79.0")
find_package(Boost 1.34.0 REQUIRED system filesystem)
if(Boost_FOUND)
  include_directories(${Boost_INCLUDE_DIRS})
  target_link_libraries(${EXECUTABLE_NAME} ${Boost_LIBRARIES})
endif()
# pkg-config-based library
include(FindPkgConfig)
pkg_check_modules(yaml-cpp REQUIRED yaml-cpp>=0.2.5)
if(yaml-cpp_FOUND)
  include_directories(${yaml-cpp_INCLUDE_DIRS})
  link_directories(${yaml-cpp_LIBRARY_DIRS})
endif()
add_executable(${EXECUTABLE_NAME} ${SOURCES})
target_link_libraries(${EXECUTABLE_NAME} ${yaml-cpp_LIBRARIES})
...

Note: because link_directories needs to be called before a target is created, if you use the pkg-config snippet, you need to move your add_executable and target_link_libraries calls after the call to link_directories.

Configuration

To configure a CMake project, execute cmake .. (where .. is the relative path to your CMakeLists.txt created above).

At this point you may also specify a specific Generator by adding the -G flag to the cmake command, e.g. cmake .. -G"Xcode". For a full list of generators run cmake --help

At this point your project may complain that SFML is not found. If you have installed SFML to a non-standard place, then you will need to set the SFML_ROOT variable so it can be found, e.g. cmake .. -G"Xcode" -DSFML_ROOT=/path/to/sfml

Compilation

At this point you should have generated project files in the folder you executed cmake from. You can use these directly as you normally would, or you can use cmake's build command: cmake --build .

Installation

To install your project, build the install target. If you're using the cmake build command, you can add --target install

You can also define CMAKE_INSTALL_PREFIX when invoking cmake to change the default install path (/usr/local under Unix).

cmake -D CMAKE_INSTALL_PREFIX=/usr ..

If you want to check a variable's value, open CMakeCache.txt, they are all there!

Packaging

To package your project into an archive/installer, just build the package target

cmake --build . --target package

By default this usually just creates a compressed archive with your installed files, but it is highly configurable. See CMake/CPack documentation for more info

Further information

  • CMake has built-in help, for instance:
$ cmake --help-variable CMAKE_SOURCE_DIR
cmake version 2.8.5
  CMAKE_SOURCE_DIR
       The path to the top level of the source tree.

       This is the full path to the top level of the current CMake source
       tree.  For an in-source build, this would be the same as
       CMAKE_BINARY_DIR.

-- Beuc & the other members of the SFML community

Clone this wiki locally