Lesson 30 · Reference
What not to use
Every bad habit from old CMake tutorials, explained. What it is, why it hurts, what to use instead, and what CMake 4.x actually deprecated.
This is the “skip the old tutorials” lesson. Every item here appears in old blog posts, and every one has a replacement with a concrete reason. Some items are officially deprecated. Others are officially discouraged. We mark the difference.
1. Global commands, discouraged
| Old, global | Per-target | Reason |
|---|---|---|
include_directories(dir) | target_include_directories(t PRIVATE/PUBLIC dir) | Leaks into every target, including third-party |
add_definitions(-DFOO) | target_compile_definitions(t ...) | Same leak |
add_compile_options(...) | target_compile_options(t ...) | Same leak |
link_libraries(lib) | target_link_libraries(t ...) | Same leak, plus no transitivity control |
Why. Lesson 7’s whole point. Global settings apply to targets you do not own, and cannot express “who needs what”.
2. file(GLOB) for sources, discouraged
file(GLOB SRCS src/*.cpp) # do not
add_executable(app ${SRCS})
The official docs warn against it. Adding a file does not trigger regeneration, and the result is silently missing files. CONFIGURE_DEPENDS is unreliable on some generators and costs a scan every rebuild.
Use instead. Explicit lists (lesson 19).
3. Global CMAKE_CXX_STANDARD, discouraged
set(CMAKE_CXX_STANDARD 20) # global. Hides incompatibilities.
The official tutorial “cautions against globally setting CMAKE_<LANG>_STANDARD”.
Use instead. target_compile_features(t PUBLIC cxx_std_20) (lesson 12).
4. cmake_minimum_required below 3.5, an error on CMake 4.x
cmake_minimum_required(VERSION 3.4) # error on CMake 4.x
Since CMake 4.0, a policy version below 3.5 is an error. The OLD behaviors of the oldest policies were removed.
Use instead. VERSION 4.4, or 3.28...4.4 (lesson 6).
5. Policies set to OLD, deprecated by definition
cmake_policy(SET CMP0079 OLD) # silences warnings by choosing removed behavior
The docs. “The OLD behavior of a policy is deprecated by definition” and may be removed in a future version. OLD behaviors get removed on a schedule.
Use instead. NEW behavior and updated code (lesson 6).
6. Deprecated in CMake 4.4, the current release
From the 4.4 release notes:
| Deprecated in 4.4 | Replacement |
|---|---|
CMAKE_WARN_DEPRECATED / CMAKE_ERROR_DEPRECATED variables | cmake_diagnostic() |
write_basic_package_version_file(... COMPATIBILITY ExactVersion) | AnyNewerVersion / SameMajorVersion / SameMinorVersion |
-Wdev / --warn-uninitialized / --no-warn-unused-cli flags | -Wauthor / -Wuninitialized / -Wno-unused-cli |
| MACROS directory property (removed, policy CMP0217) | none |
7. Deprecated in other 4.x releases
- 4.3.
CMAKE_ENABLE_EXPORTS, replaced byCMAKE_EXECUTABLE_ENABLE_EXPORTSandCMAKE_SHARED_LIBRARY_ENABLE_EXPORTS. Alsoexport(EXPORT)without arguments. - 4.2. The Visual Studio 14 2015 generator, “will be removed in a future version”. Also uppercased
<Package>_FOUNDvariables. - 4.1.
FindGTestresult variables,GTEST_INCLUDE_DIRSand so on. UseGTest::gtest. AlsoFindProtobuf’sprotobuf_generate_cpp()andprotobuf_generate_python(). - 4.0. The undocumented declarative form of
ctest -Sscripting was removed, the one triggered by a script that calls no CTest commands. Normalctest -Sdashboard scripts still work. AlsoFindGDALwas deprecated.
8. Style traps that cost you
if(MSVC)versusif(CMAKE_CXX_COMPILER_FRONTEND_VARIANT MATCHES "MSVC"). The second catches clang-cl. Use it (lesson 11).- No
.gitignoreforbuild/. Commit build dirs, lose your mind (lesson 4). - Branch-pinned
FetchContent.GIT_TAG mainbreaks reproducibility. Hash-pin (lesson 18). install()with absolute destinations. CPack silently ignores them (lesson 24).
Tip
The rule behind every entry. The tool gives you a way to say what and who. Use it. Global settings, GLOB and OLD policies exist because they were the only tools once. CMake grew better tools. The old ones stayed for compatibility, not because they are good.
Read the docs