Hello world
main.c
// You can compile and run this program directly without CMake using a C
// compiler manually. Here's how you might do so with GCC:
//
// gcc -o hello-world main.c
// ./hello-world
//
// ...but that can quickly become unweildly when you add more .c files,
// dependencies, include directories, etc. That's where CMake really shines.
#include <stdio.h>
int main() {
puts("Hello, World!");
return 0;
}
CMakeLists.txt
# First we require a minimum version of CMake. It's a good idea to choose
# something recent. You can find the latest version on the CMake website
# https://cmake.org/download/. This function is HIGHLY RECOMMENDED. It should be
# before even the project() function.
cmake_minimum_required(VERSION 3.30)
# Next we define a project. Think of a project as similar to a Python package, a
# JavaScript package, a Rust package, etc. This project() function call will
# define all subsequent targets (executables, libraries, etc.) in the scope of
# this project. You may specify more than just a project name:
#
# project(<PROJECT-NAME>
# [VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
# [DESCRIPTION <project-description-string>]
# [HOMEPAGE_URL <url-string>]
# [LANGUAGES <language-name>...])
project(hello-world)
# Finally, we add an executable target. This will create an executable named
# hello-world from the source file main.c. You are able to specify more than one
# source file if you wish:
#
# add_executable(<name> <options>... <sources>...)
#
# For example: add_executable(hello-world main.c other.c). For now we only need
# one main.c file.
add_executable(hello-world main.c)
# CMake isn't actually a build system itself. It's a meta build system. CMake
# takes your imperative build instructions from the CMakeLists.txt script and
# generates the complicated structure that each platform-specific build tool
# requires. For example, GNU Makefiles on Linux, Xcode projects on macOS, and
# Visual Studio solutions on Windows. This is called "configuring" or
# "generation". You can perform the configure step by running `cmake`. **But**
# by default that creates a lot of files in the current working directory. That
# gets messy with complicated `.gitignore` patterns and such. It's much easier
# to perform an *out of source build* where we tell CMake to put those files in
# another folder like `./build/` instead of `./`. That's where the `-B build`
# flag comes in.
cmake -B ./build/
-- The C compiler identification is GNU 13.3.0
-- The CXX compiler identification is GNU 13.3.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done (0.4s)
-- Generating done (0.0s)
-- Build files have been written to: /home/runner/work/cmakebyexample.jcbhmr.com/cmakebyexample.jcbhmr.com/src/hello-world/build
# Now that we've generated the platform-specific build system files in
# `./build/`, we can tell CMake to invoke `make`, `msbuild`, `ninja`, or another
# build command in that directory to finally build our project. This stage is
# aptly called "building". You can perform the build step by running `cmake
# --build <configure_output_folder>` where `<configure_output_folder>` is the
# folder you specified with the `-B` flag. In our case, that's `./build/`.
cmake --build ./build/
[ 50%] Building C object CMakeFiles/hello-world.dir/main.c.o
[100%] Linking C executable hello-world
[100%] Built target hello-world
# And finally we can run the executable that was built in `./build/`. The
# executable is named `hello-world` because that's the target name we specified
# in the `add_executable()` function in `CMakeLists.txt`. (You _can_ override
# this with the `OUTPUT_NAME` target property.)
./build/hello-world
Hello, World!