Introduction to CMake

Article Info
Last Updated
(24b0f86)
Tags
Guide

CMake is driven by a file called CMakeLists.txt which contains:

  • Rules for how the software should be compiled

  • Rules for which libraries and executables are built by this project (called targets)

  • Rules for which libraries are needed, and how to find them

You can include other CMakeLists.txt files, and other .CMake files directly to make your build scripts tidier, but you don’t need to do this.

An example CMakeLists

This is what a CMake file with dependencies should look like:

CMakeLists.txt
cmake_minimum_required(VERSION 3.22)

# if VCPKG exsits, inject its build chain
if(DEFINED ENV{VCPKG_ROOT} AND NOT DEFINED CMAKE_TOOLCHAIN_FILE)
    set(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
        CACHE STRING "")
endif()

# create a project called Comp270
project(comp270)

# This is how we should handle dependencies in CMake
find_package(glfw REQUIRED CONFIG)

// create an executable called worksheet 1
add_executable(ws1)

// link the dependencies for worksheet 1
target_link_libraries( ws1 PRIVATE SDL2::SDL2 SDL2::SDL2main )

// this is where our include files will live
target_include_directories( ws1 PUBLIC include )

// now we list our C++ sources
target_sources( ws1
    PRIVATE
        src/main.cpp
)

// Extra command to manage resources when a build is triggered for ws1
add_custom_command(TARGET ws1 PRE_BUILD
                   COMMAND ${CMAKE_COMMAND} -E copy_directory
			${CMAKE_SOURCE_DIR}/assets/ $<TARGET_FILE_DIR:ws1>)
Tip
3rd party code you rely on should really be vendored into it’s own directory. It’s best not to mix your own code and 3rd party code.

You can see an example of how you might vendor a header-only library in FGGL.

Using included files

Your header files should be structured as standard header files should be:

include/main.h
#ifndef PROJECT_HEADER_H
#define PROJECT_HEADER_H

#include <glad/glad.h>
#include <GLFW/glfw.h>

namespace project {

}

#endif // PROJECT_HEADER_H

CPP file contents

src/main.cpp
#include "main.h"
#include <iostream>

void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void process_input(GLFWwindow* window);
void glfw_error(int code, const char* description);

int main(int argc, char* argv[]) {
	auto status = glfwInit();
	if ( status == GLFW_FALSE ) {
		std::cerr << "Could not init GLFW" << std::endl;
		return 1;
	}

	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

	GLFWwindow* window = glfwCreateWindow("Demo Application", 800, 600);
	if ( !window ){
		std::cerr << "could not create GLFW window" << std::endl;
		glfwTerminate();
		return 1;
	}
	glfwMakeContextCurrent( window );

	// GLAD dynamically loads OpenGL
	if ( !gladLoadGLLoader( (GLADloadproc)glfwGetProcAddress) ) {
		std::cerr << "" << std::endl;
		glfwTerminate();
		return 1;
	}

	// Cleanup GLFW
	glfwTerminate();
	return 0;
}
Graduation Cap Book Open book GitHub Info chevron-right Sticky Note chevron-left Puzzle Piece Lightbulb Video Exclamation Triangle Globe