0

I have a small CMake project that encapsulate a small C++ library. For this library, I want to enable almost all available warnings by default while developing it. However, if someone wants to make use of my library and therefore uses add_subdirectory to include my project, I would like to disable warnings for my library.

I know how to disable warnings, but I would like to know how one would go about detecting whether the CMake project is currently processed stand-alone or embedded in another CMake project.

Raven
  • 2,951
  • 2
  • 26
  • 42

1 Answers1

0

CMake >= v3.21

There's a boolean flag PROJECT_IS_TOP_LEVEL, which seems to indicate exactly this.

For more general querying (not only the current project), there's also <PROJECT-NAME>_IS_TOP_LEVEL.


CMake pre < v3.21

Disclaimer: This answer assumes that project calls always happen in the first processed CMakeLists.txt file that is processed for every project.


The best way to check for this (to my knowledge) would be to test whether the variables CMAKE_SOURCE_DIR and PROJECT_SOURCE_DIR (note: no CMAKE_ prefix) refer to the same path.

From the docs 1, 2: CMAKE_SOURCE_DIR

The path to the top level of the source tree.

This is the full path to the top level of the current CMake source tree.

PROJECT_SOURCE_DIR

This is the source directory of the last call to the project() command made in the current directory scope or one of its parents. Note, it is not affected by calls to project() made within a child directory scope (i.e. from within a call to add_subdirectory() from the current scope).

So the gist of it is that if the project is built stand-alone, top-level source directory, is the one that contains your own CMakeLists.txt file, which (as is normally the case) contains the project call of your own project. Assuming you don't have multiple project calls in your project (again: as is usually the case), that means that the directory in which the last project call happened (and which does not lie in a sun directory of your current directory, which according to the docs don't count) is the same as the top-level source directory. Therefore, the mentioned variables will refer to the same path.

If, however, your project is embedded in someone else's CMake project, their CMakeLists.txt location will define the top-level source directory. At some point, they will include your project, which starts by its own project call, updating PROJECT_SOURCE_DIR to the path to the directory in which your CMakeLists.txt file lies. Therefore, CMAKE_SOURCE_DIR != PROJECT_SOURCE_DIR.


TL;DR: This is the necessary check

if (CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
    message(STATUS "Your project is standalone")
else()
    message(STATUS "Your project is embedded")
endif()
Raven
  • 2,951
  • 2
  • 26
  • 42
  • I don't think this is correct. Did you mean CMAKE_CURRENT_SOURCE_DIR instead? – maciek gajewski Apr 03 '23 at 09:16
  • @maciekgajewski no. Then the check would always fail for subdirectories. The code should be correct as it is. – Raven Apr 03 '23 at 09:24
  • It's not correct if there is `project()` in the same file, before the check, as this will set PROJECT_SOURCE_DIR to CMAKE_CURRENT_SOURCE_DIR – maciek gajewski Apr 05 '23 at 13:04
  • @maciekgajewski your argument is precisely why this solution yields the correct result. Because `PROJECT_SOURCE_DIR` is then no longer equal to `CMAKE_SOURCE_DIR`, the test will correctly tell you that the project you are currently in is not the top-level project. That is all under the assumptions given in my answer. – Raven Apr 05 '23 at 13:24