t4mer@notebook

// learning · #07 · cmake · c++ · 12 august 2026 · 3 min

CMakeLists.txt is a map of targets, not Composer

A Web Developer Learns C++ · #07

A Web Developer Learns C++

I opened CMakeLists.txt looking for the PHP equivalent of composer.json. A list of packages. A version constraint. Something I could run and then forget.

That is the wrong file.

CMake does not install my application. It does not even compile it. It describes targets - executables, libraries, the source files that belong to them - and then generates a build that some other tool actually runs. Ninja, Visual Studio, Make. I wrote a short TIL when that sentence first landed. This note is what I do with the file now that I know what it is for.

The mental model that finally stuck

In a Laravel app I know where to stand:

  • composer.json - what gets installed
  • artisan - what I run
  • public/index.php - where a request starts

In a CMake C++ project:

  • CMakeLists.txt - what exists as a target, and which files belong to it
  • the generator + compiler - what actually builds
  • main.cpp - where the process starts, when that file is even the right place to look (main.cpp is not index.php)

cmake . is not composer install. Configure can succeed and the build can still fail. That confused me longer than it should have.

What I look for first

I do not read the file top to bottom like a tutorial. I grep for the parts that answer web-developer questions:

  • project( - the name. Not important until it is.
  • add_executable( / add_library( - the actual products. This is the “what are we building?”
  • target_sources( - which .cpp / .qml files are in the target. This is where I finally found the UI that Qt Designer would not open.
  • find_package( - Qt, or whatever the project needs. This is closer to Composer than anything else in the file, and still not the same.
  • target_link_libraries( - what gets linked. Dynamic vs static is a later problem.

If those five exist, I can usually find main or the QML entry without scrolling through a generated wall of include().

A shape, not my project file

I am not pasting a real application CMakeLists.txt here. Generated Qt files are noisy, and I am not going to republish a blob I do not want to maintain. The shape I keep in my head looks like this:

cmake_minimum_required(VERSION 3.16)
project(example LANGUAGES CXX)
 
find_package(Qt6 REQUIRED COMPONENTS Quick)
 
qt_add_executable(example
    main.cpp
)
 
qt_add_qml_module(example
    URI Example
    QML_FILES
        Main.qml
)
 
target_link_libraries(example PRIVATE Qt6::Quick)

That is a sketch. Real files have more version pins, more Qt components, and more comments generated by a wizard. The sketch is enough to see: this is a map of targets, not a package lockfile.

What still feels strange

Coming from PHP:

  • There is no request. The program lives until you quit it.
  • Headers and .cpp files are a split I am still getting used to. CMake is the thing that has to know about both.
  • A missing file in CMakeLists.txt does not 404. It fails at configure or at compile, with an error that assumes I already speak this dialect.

I still cannot write a non-trivial CMake module from memory. I need to read the file well enough to answer: what is the target, which sources does it include, and which main did I fail to find?

Next time the UI is QML and Designer looks empty, I will open CMakeLists.txt before I open another settings panel.