Skip to Content
Course content

77: Introduction to CMake for C Projects

Click on the "Edit" button in the top corner of the screen to edit your slide content.

You've likely spent the last few lessons running a command like gcc main.c -o program. That works great when your project is a single file. But the moment you start splitting your code into modules—which you should be doing—the command line becomes a nightmare. I remember a project early in my career where I spent an hour debugging a "missing function" only to realize I'd just forgotten to add one .c file to my manual build string.

The "Undefined Reference" Headache

Imagine you've built a simple string utility library to help with your project. You have main.c, string_utils.c, and string_utils.h. You try to compile it like this:

gcc main.c -o my_app

The compiler doesn't complain about the header (because it's included), but the linker throws a fit:

/usr/bin/ld: /tmp/ccXyZ.o: in function 'main':
main.c:(.text+0x15): undefined reference to 'string_reverse'
collect2: error: ld returned 1 exit status

The problem is that gcc compiled main.c, but it has no idea that the actual machine code for string_reverse lives inside string_utils.c. To fix this manually, you'd have to run gcc main.c string_utils.c -o my_app. Now, imagine you have 20 files. Do you really want to type them all out every time, or maintain a fragile shell script that breaks the moment you add a new file?

Offloading the Heavy Lifting to CMake

This is where CMake comes in. It isn't a compiler; it's a build system generator. You describe your project in a file called CMakeLists.txt, and CMake generates the actual build instructions (like a Makefile) for whatever system you're on. It's the industry standard for C and C++ because it handles the dependencies and linking for you.

Here is how we'd solve the "undefined reference" problem by creating a CMakeLists.txt file in your project root:

cmake_minimum_required(VERSION 3.10)
project(StringApp)

# We tell CMake to create an executable called 'my_app' 
# and list every source file that needs to be compiled and linked.
add_executable(my_app main.c string_utils.c)

Now, instead of fighting with gcc flags, you use a standard workflow. I always recommend "out-of-source" builds. This keeps your source directory clean of temporary build artifacts.

mkdir build
cd build
cmake ..
make

By running cmake .., CMake looks at the parent directory, finds your CMakeLists.txt, and figures out exactly how to invoke the compiler on your specific OS. When you run make, it executes those instructions.

Handling Include Directories

As your project grows, you'll probably start putting headers in a /include folder and source files in a /src folder. If you do that, the compiler will complain that it can't find your .h files.

You could add -I./include to every gcc call, but in CMake, you just add one line to your configuration:

target_include_directories(my_app PUBLIC include)

I love this approach because it explicitly ties the include directory to the my_app target. If you later add a second executable or a library to the same project, you can give it its own set of include paths without them leaking into each other.




📋 Practical Task

Building a Multi-File Geometry Calculator

Your task is to move away from manual compilation and set up a CMake build for a geometry project. You are provided with three files:

  • main.c: Calls functions to calculate the area of a circle and a rectangle.
  • geom.c: Contains the logic for calc_circle_area() and calc_rect_area().
  • geom.h: The function prototypes.

Requirements:

  1. Create a CMakeLists.txt file that sets the minimum version to 3.10 and names the project "GeoCalc".
  2. Configure the build so that the resulting executable is named geometry_tool.
  3. Ensure that both main.c and geom.c are included in the build process so that no "undefined reference" errors occur.
  4. Demonstrate the build process by listing the commands you would run in the terminal to create a build directory and compile the project.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.