pokche
pokche

Reputation: 1149

Single CMakeLists.txt enough for my project?

I am trying to port my old CMake to modern CMake (CMake 3.0.2 or above). In the old design I had multiple CMakelists.txt, each directory contained a CMakeLists.txt file.

My current project's directory structure looks like :

.
├── VizSim.cpp
├── algo
├── contacts
│   ├── BoundingVolumeHierarchies
│   │   └── AABBTree.h
│   └── SpatialPartitoning
├── geom
│   └── Geometry.h
├── math
│   ├── Tolerance.h
│   ├── Vector3.cpp
│   └── Vector3.h
├── mesh
│   ├── Edge.h
│   ├── Face.h
│   ├── Mesh.cpp
│   ├── Mesh.h
│   └── Node.h
├── util
|   |__ Defines.h
|   |__ Math.h
|
└── viz
    └── Renderer.h

What I was planning to do was just use a single CMakelists.txt and place all the cpp files in SOURCE and all the headers in HEADER and use add_executable.

set (SOURCE
    ${SOURCE}
    ${CMAKE_CURRENT_SOURCE_DIR}/src/mesh/Mesh.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/src/math/Vector3.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/src/VizSim.cpp
    ....
)

set (HEADER
    ${HEADER}
    ${CMAKE_CURRENT_SOURCE_DIR}/src/mesh/Mesh.h
    ${CMAKE_CURRENT_SOURCE_DIR}/src/math/Vector3.h
    .... 
)

add_library(${PROJECT_NAME} SHARED ${SOURCE})

Doing this I am worried if using a single CMakeLists.txt is good practice. So does single CMakeLists.txt suffice or do I need a CMakeLists.txt for each folder?

I can only think of one good reason to have multiple CMakeLists.txt in my project and that is modularity.

Considering my project will grow eventually.

Upvotes: 8

Views: 3262

Answers (2)

Scheff's Cat
Scheff's Cat

Reputation: 20141

This is a bit long for a comment – so I make it an answer:

In one of my projects (a library), I have that many sources that I started to move some of them in a sub-directory util.

For this, I made separate variables:

file(GLOB headers *.h)
file(GLOB sources *.cc)
file(GLOB utilHeaders
  RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
  ${CMAKE_CURRENT_SOURCE_DIR}/util/*.h)
file(GLOB utilSources
  RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
  ${CMAKE_CURRENT_SOURCE_DIR}/util/*.cc)

To make it nice looking / more convenient in VisualStudio, I inserted source_groups which generates appropriate sub-folders in the VS project. I believe they are called "Filters".

source_group("Header Files\\Utilities" FILES ${utilHeaders})
source_group("Source Files\\Utilities" FILES ${utilSources})

Of course, I have to consider the variables utilHeaders and utilSources as well where the sources have to be provided:

add_library(libName
  ${sources} ${headers}
  ${utilSources} ${utilHeaders})

That's it.


Fred reminded in his comment that I shouldn't forget to mention that file(GLOB has a certain weakness (although I find it very valuable in our daily work). This is even mentioned in the CMake doc.:

Note: We do not recommend using GLOB to collect a list of source files from your source tree. If no CMakeLists.txt file changes when a source is added or removed then the generated build system cannot know when to ask CMake to regenerate. The CONFIGURE_DEPENDS flag may not work reliably on all generators, or if a new generator is added in the future that cannot support it, projects using it will be stuck. Even if CONFIGURE_DEPENDS works reliably, there is still a cost to perform the check on every rebuild.

So, using file(GLOB, you shouldn't never forget to re-run CMake once files have been added, moved, or removed. An alternative could be as well, to add, move, remove the files directly in the generated built-scripts (e.g. VS project files) and rely on the fact that the next re-run of CMake will those files cover as well. Last but not least, a git pull is something else that it's worth to consider a re-run of CMake.

Upvotes: 2

usr1234567
usr1234567

Reputation: 23394

I would always recommend a CMakeList.txt file per directory. My reasons:

  • locality: keep everything in the same folder that belongs together. This includes the relevant parts of the build system. I would hate it to navigate to the root folder to see how a library or target was invoked.
  • separation of build artifacts and related build code: Tests belong below test, libraries below lib, binaries below bin, documentation below doc, and utilities below utils. This may vary from project to project. When I have to make a change to the documentation, why should I wade through dozens of unrelated CMake code? Just have a look into the right CMakeLists.txt.
  • avoid handling of paths: In most cases relative or absolute paths including stuff like ${CMAKE_CURRENT_SOURCE_DIR} can be avoided. That leads to maintainable build code and reduces errors from wrong paths. Especially with out-of-source build, which should be used anyway.
  • localization of errors: If a CMake error occurs it is easier to locate the problem. Often a sub-directory can be excluded as a first workaround.

Upvotes: 3

Related Questions