Getting Started with CMake: From Basic C Code to Embedded Project Management

Hello everyone, welcome to <span>LiXin Embedded</span>.

Today we will talk about CMake, a powerful tool that makes cross-platform builds easy and helps you manage your projects efficiently.

Why Do We Need CMake?

If you are just starting to learn C++, you might be used to using an IDE like Visual Studio, VS Code, or CLion. These tools are indeed convenient; with a click of a run button, your code is compiled. But here comes the problem: if you move your code from Windows to Linux, the Visual Studio project file (.sln) is completely useless on Linux, which doesn’t recognize it at all! At this point, CMake acts like a universal <span>translator</span>, helping you abstract the build logic of your project so that it can compile smoothly on different platforms.

Getting Started with CMake: From Basic C Code to Embedded Project Management

For example, in an STM32 project, compiling with Keil on Windows is fine, but the client requests using an open-source toolchain (like GCC) on Linux. Without CMake, manually adjusting the Makefile would be a nightmare. However, with CMake, you only need one configuration file to adapt to different environments.

In simple terms, CMake is a build system generator that generates build scripts suitable for the current platform based on your project description. For instance, it generates Visual Studio solutions on Windows and Makefiles on Linux. With just a few commands, your project can be up and running.

What Can CMake Do?

The core function of CMake is cross-platform building, but its capabilities go far beyond that. Here are some key features:

  • Cross-platform support: The same CMake configuration file can generate build scripts on Windows, Linux, and even embedded platforms, saving you the hassle of repetitive configurations.
  • Flexible toolchain adaptation: Whether it’s GCC, Clang, or Keil’s ARMCC, CMake can seamlessly integrate with them.
  • Rich utility functions: For example, automatically finding system libraries, downloading third-party dependencies, copying files to specified directories, and even customizing build steps.
  • Modular management: Large embedded projects often contain multiple sub-modules, and CMake can clearly organize the code structure, facilitating team collaboration.
Getting Started with CMake: From Basic C Code to Embedded Project Management

For instance, in an IoT project, CMake can manage the dependencies of the MQTT library. CMake not only automatically pulls the latest version but also copies the compiled library files to the target directory, saving a lot of manual operations.

The Simplest C++ Program with CMake

To help you get started quickly, we will begin with the simplest C++ program:

int main() {
    return 0;
}

This code does nothing; it exits immediately after running, but it is sufficient for us to understand how to use CMake. Suppose we save this code in a main.cpp file, with the following directory structure:

simple_project/
├── main.cpp
├── CMakeLists.txt
Getting Started with CMake: From Basic C Code to Embedded Project Management

Next, we need to create a CMakeLists.txt file, which is the configuration file for CMake that defines the build rules for the project. Here is the simplest content for CMakeLists.txt:

cmake_minimum_required(VERSION 3.10)
project(SimpleProject)
add_executable(SimpleProject main.cpp)

Code Explanation

cmake_minimum_required(VERSION 3.1)

This line specifies the minimum required version of CMake. 3.10 is a relatively old version that most developers’ machines support, so it’s safe to include it. If your project uses new features, you can appropriately raise the version requirement.

 project(SimpleProject)

This defines the name of the project, which is called SimpleProject. This name is not only used to identify the project but can also be referenced in subsequent configurations, such as setting the version number or specifying the language (C++, C, etc.).

add_executable(SimpleProject main.cpp) 

This line tells CMake: I want to generate an executable file using the main.cpp file, named SimpleProject (on Windows, it will generate SimpleProject.exe). If there are multiple source files, you can continue to list them, such as <span>main.cpp utils.cpp</span>.

These three lines of code complete the simplest CMake configuration. Getting Started with CMake: From Basic C Code to Embedded Project Management

How to Compile a Project with CMake

Getting Started with CMake: From Basic C Code to Embedded Project Management

After configuring CMakeLists.txt, let’s see how to build the project. We will demonstrate three methods: command line, Visual Studio, and CLion.

Command Line

Whether on Windows or Linux, the steps for command line building are quite similar. Make sure you have CMake and a C++ compiler installed (like GCC on Linux or MSVC on Windows).

1. Check if CMake is Ready

Open the terminal and type <span>cmake --version</span>. If the version number is displayed, it means CMake is installed correctly. Linux users usually install it via <span>apt install cmake</span>; Windows users may need to manually download CMake and add the path of cmake.exe to the environment variables.

2. Create a Build Directory

Navigate to the project root directory (<span>simple_project</span>) and run:

mkdir build
cd build

This step creates a build directory specifically for storing compiled files, keeping the project root clean.

3. Generate Build Files

In the build directory, run:

cmake ..

This command tells CMake to generate platform-specific build scripts based on the CMakeLists.txt (Visual Studio project on Windows, Makefile on Linux).

4. Compile the Project

Continue running in the build directory:

cmake --build .

This compiles the entire project. After completion, you will find the executable file SimpleProject (on Windows, it is SimpleProject.exe) in the build directory (or its subdirectory).

In embedded projects, you usually specify the toolchain at this step, for example, using <span>cmake -DCMAKE_TOOLCHAIN_FILE=arm-gcc.cmake ..</span> to adapt for ARM chip cross-compilation.

Visual Studio 2019

Visual Studio has friendly support for CMake. Make sure you have installed the CMake Tools component, then:

  1. Open Visual Studio, select Open Local Folder, and load the simple_project directory.
  2. Select the target SimpleProject.exe from the top dropdown menu.
  3. Press Ctrl + Shift + B to compile, or click the green Run button to compile and run directly.

The whole process is as simple as playing a game; Visual Studio will automatically call CMake to generate the solution without manual operation.

CLion

CLion has a nearly perfect integration with CMake. The steps are as follows:

  1. Ensure you have a compiler installed, such as GCC on Linux (install with <span>sudo apt install build-essential</span>) or MinGW-w64 on Windows.
  2. Open CLion, select File -> Open, and load the simple_project directory.
  3. Select the target SimpleProject from the top.
  4. Press Ctrl + F9 to compile, or Shift + F10 to compile and run. You can also use the green hammer (compile) or green triangle (run) buttons on the interface.

CLion will automatically parse the CMakeLists.txt, and once configured, you can start working directly, which is very efficient. When debugging embedded projects, CLion is often used with GDB, providing a great experience.

Leave a Comment