I’ve just migrated a somewhat large project from Visual Studio solutions to CMake and I’ve noticed a weird behavior. I have something like the following structure:
project/CMakeLists.txt
project/code/CMakeLists.txt
project/code/library-1/CMakeLists.txt
project/code/library-1/*.hpp
project/code/library-1/*.cpp
project/code/library-2/CMakeLists.txt
project/code/library-2/*.hpp
project/code/library-2/*.cpp
...
project/code/library-n/CMakeLists.txt
project/code/library-n/*.hpp
project/code/library-n/*.cpp
project/demo/CMakeLists.txt
project/demo/demo-1/CMakeLists.txt
project/demo/demo-1/*.hpp
project/demo/demo-1/*.cpp
project/demo/demo-2/CMakeLists.txt
project/demo/demo-2/*.hpp
project/demo/demo-2/*.cpp
...
project/demo/demo-n/CMakeLists.txt
project/demo/demo-n/*.hpp
project/demo/demo-n/*.cpp
- The root
CMakeLists.txtfile configures the compilation flags, macro definitions, etc. and uses CMake’sadd_subdirectory()to include targets defined by the libraries and demo projects. - The
codesub-folder contains a flat list of sub-folders with each containing source code for a static library (as well as its target defined in aCMakeLists.txtfile). - The
demosub-folder contains a flat list of sub-folders. Each contains source code for an executable and associatedCMakeLists.txtfile. - Each library is a standalone component and builds independently from all other libraries and demo projects.
- Each demo program depends on one or more of the different libraries in the
codesub-folder.
This setup is really nice. If I want to change build options, I only need to modify the root CMakeLists.txt and everything re-compiles with the new settings. If I modify any source code anywhere in the tree, the appropriate libraries, if any, are recompiled and all dependent demo programs are also re-built.
However, if I modify any CMakeLists.txt file anywhere in the tree, the entire tree of libraries and programs is re-compiled without respect of dependencies. To give an idea of what I mean, here a few parts of the CMake build scripts.
project/demo/CMakeLists.txt
# Resolve libraries built in `code` sub-folder.
link_directories(${LIBRARY_OUTPUT_PATH})
set(demo-projects
demo-1
demo-2
...
demo-n
)
foreach(demo-project ${demo-projects})
add_subdirectory(${demo-project})
endforeach()
project/demo/demo-n/CMakeLists.txt
# Find all source code in the same folder.
file(GLOB ${demo-project}_headers
${CMAKE_CURRENT_SOURCE_DIR}/*.hpp
)
file(GLOB ${demo-project}_sources
${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
)
# Select libraries to link with.
set(${demo-project}_libraries
library-1
library-2
library-5
)
# Build the demo program.
add_executable(${demo-project}
${${demo-project}_headers}
${${demo-project}_sources}
)
if(${demo-project}_libraries)
target_link_libraries(${demo-project} ${${demo-project}_libraries})
endif()
# Manually register some dependencies on other targets.
if(${demo-project}_dependencies)
add_dependencies(${demo-project} ${${demo-project}_dependencies})
endif()
If I happen to modify project/demo/demo-n/CMakeLists.txt to add an extra library, like this:
set(${demo-project}_libraries
library-1
library-2
library-5
library-6
)
Then the entire source code for all libraries and demo programs in the project is re-compiled. Why is this so? Is there a better way to structure my scripts in order to avoid this?
It happens that my problem was cause by a totally unrelated issue. I applied Bill Hoffman’s suggestion and the modifying any “CMakeLists.txt” file in the project ended up modifying the
CXX_FLAGS(C++ compiler flags) variable in all generated Makefiles.I traced that back to my root “CMakeLists.txt” file, which had something like the following:
I changed it to the following.
CMake no longer repeats the
/WX /wd4355flags when updating the build scripts and my project no longer re-compiles from scratch at each modification!