Issue
I'm using CMake in my project, as does one of my project's third-party library (included with add_subdirectory()
for convenience). I have been having strange build issues, and I think I've tracked them down to the following line in the third-party library's top-level CMakeLists.txt
:
set(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "")
This sets CMAKE_DEBUG_POSTFIX
for my entire project (except for any subtrees where it's explicitly set), which breaks my build. Worse, the build behavior is order- and time-dependent, with the value being changed in the middle of my build after a clean build, and not after a rebuild. (Lots of fun to track down.)
The library sets lots of cache variables whose name begins with "XXXX_", where "XXXX" is the name of the library. That's fine by me, as it's unlikely these variables will be used by others' code. But, it seems antisocial to set commonly-used variables globally when your code is meant to be a component of someone else's project. It also is fragile; if I use set(XXXX <aValue>)
in my top-level CMakeLists.txt
then the library's set(XXXX CACHE...)
statements will be ignored.
Instead, the library should just use set(CMAKE_DEBUG_POSTFIX "d")
, which sets the variable for all of the library's code tree, and nobody else's.
Is this a bug in the library's build code? Should libraries that aim to be good CMake citizens avoid CACHE variables except for their clearly-named private variables?
Solution
For libraries that intend to be usable as a subproject (via add_subdirectory
or FetchContent
), I would say it is a bug to set such cache variables without a check that the project is top-level. On the other hand, a project that does not intend to be usable this way should explicitly check and issue a fatal error (or maybe an author warning) in this case. So either way, I would argue there's a bug and you should notify the maintainers.
In CMake 3.21+ the variable PROJECT_IS_TOP_LEVEL
works. In earlier versions, you can write:
string(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}" PROJECT_IS_TOP_LEVEL)
to get the same variable. Then check:
if (PROJECT_IS_TOP_LEVEL)
# Either this: (AUTHOR_WARNING acceptable, too)
message(FATAL_ERROR "Subproject inclusion not supported")
# or:
set(CMAKE_* ... CACHE ...)
endif ()
Answered By - Alex Reinking Answer Checked By - Robin (WPSolving Admin)