# How to do both efficient and correct System Inspection?

**URL:** https://discourse.cmake.org/t/how-to-do-both-efficient-and-correct-system-inspection/5380
**Category:** Code
**Created:** [April 5, 2022, 6:28pm UTC](https://discourse.cmake.org/t/how-to-do-both-efficient-and-correct-system-inspection/5380 "2022-04-05T18:28:42Z")
**Posts on this page:** 2
**Page:** 1

<div class="post-metadata">

### Author: ![frankj](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/f/df705f/32.png) [@frankj](https://discourse.cmake.org/u/frankj)
#### Post date: [April 5, 2022, 6:28pm UTC](https://discourse.cmake.org/t/how-to-do-both-efficient-and-correct-system-inspection/5380/1 "2022-04-05T18:28:43Z")

</div>

I’m trying to use CMake to do System Inspection as described in “Mastering CMake” ([https://cmake.org/cmake/help/book/mastering-cmake/chapter/System%20Inspection.html](https://cmake.org/cmake/help/book/mastering-cmake/chapter/System%20Inspection.html)), and I can’t figure out how to get it to happen _if and only if_ it needs to.

My project is fairly straightforward, and mostly consists of a top-level CMakeLists.txt and main.cpp, plus two libraries:

```auto
project(Demo C CXX)
include(detect/CMakeLists.txt) # I talk about this below
add_subdirectory(lib1)
add_subdirectory(lib2)
add_executable(Demo main.cpp)
target_link_libraries(Demo Demolib1 Demolib2)
target_include_directories(Demo PUBLIC include)

```

The detect/ directory contains a CMakeLists.txt that probes which of 30+ features are available, and does a bunch of CMake configuration based on what it finds. This configuration applies to both libraries as well as main.cpp. The probing _absolutely must_ happen via try\_compile(); I promise there is no more reliable way for me to detect these features. A representative sample looks like:

```auto
set(DETECTSRCDIR ${CMAKE_SOURCE_DIR}/detect)

try_compile(RESULT_VAR ${CMAKE_BINARY_DIR} ${DETECTSRCDIR}/feature1.cpp)
if(RESULT_VAR)
  add_definitions(-DHAVE_FEATURE1)
  message(STATUS "feature1 available")
endif()

try_compile(RESULT_VAR ${CMAKE_BINARY_DIR} ${DETECTSRCDIR}/feature2.cpp)
if(RESULT_VAR)
  add_definitions(-DHAVE_FEATURE2)
  set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
  message(STATUS "feature2 available")

  try_compile(RESULT_VAR ${CMAKE_BINARY_DIR} ${DETECTSRCDIR}/feature3.cpp)
  if(RESULT_VAR)
    add_definitions(-DHAVE_FEATURE3)
    set(CMAKE_CXX_EXTENSIONS ON)
    message(STATUS "feature3 available")
  endif()
else()
  try_compile(RESULT_VAR ${CMAKE_BINARY_DIR} ${DETECTSRCDIR}/feature4.cpp)
  if(RESULT_VAR)
    add_definitions(-DHAVE_FEATURE4)
    message(STATUS "feature4 available")
  endif()
endif()

#....

set_property(
  DIRECTORY
  APPEND
  PROPERTY CMAKE_CONFIGURE_DEPENDS
  ${DETECTSRCDIR}/feature1.cpp
  ${DETECTSRCDIR}/feature2.cpp
  ${DETECTSRCDIR}/feature3.cpp
  ${DETECTSRCDIR}/feature4.cpp
  #....
)

```

All of these feature detections are independent of the other code and CMakeLists.txt. That is, I promise that no CMake setting they make will ever affect how these detections take place. They are only affected by things like compiler, build type, etc.; inputs to the build environment. So a solution that somehow isolates that detection into some kind of sub-project or independent CMake configuration is at least plausible.

And this basically works correctly, but it is terribly inefficient. It is quite common to add a file to lib1 or lib2 during development, which means adding that file to that library’s CMakeLists.txt, which means the entire CMake configuration process happens, which means the entire detection process happens again! This can take **quite** a long time, since there are so many try\_compile() calls needed. This is very frustrating to developers! So I would like to be efficient about this as well.

**How can I make this detection happen _only if_ it needs to; meaning, only if the reconfiguration happens because of something in detect/ changing or some compiler/buildtype setting?**

I could maybe cache variables for all the features and guard the try\_compile() calls, but then I would need to invalidate those cache entries if any of the feature\*.cpp files change, and I can’t find a way to do that. Changing the include() to add\_subdirectory() doesn’t change anything. I think if I made it an ExternalProject then I couldn’t do all the CMake configuration that it does. I could make it generate a file with a bunch of “set()” commands recording the detection results, and then include() _that_ in my main CMakeLists.txt and duplicate all the configuration there, but that separates detection from configuration _and_ makes maintenance and understanding more difficult _and_ seems more like working around CMake rather than working with it. I also dumped all the CMake variables when a reconfigure happens because of a detect .cpp file changing versus a library’s CMakeLists.txt changing, and there were 0 differences, so I don’t know how to even detect that. So I am out of ideas.

To make things more complicated, I need a solution that _ideally_ works with CMake 3.2, and _needs_ to work with CMake 3.5, but if there is an easy solution that only exists in later versions, I would at least like to know about it. This is also a very cross-platform project, being built with gcc, clang, icc, MSVC, and mingw at the least, so I can’t count on any non-CMake scripting language being available for use (no bash/python/batch files can be used). And it also supports cross-compiling, so I cannot count on being able to execute anything that gets compiled.

If you have any ideas, I would love some help. Thank you for reading.

---

<div class="post-metadata">

### Author: ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)
#### Post date: [April 9, 2022, 12:40pm UTC](https://discourse.cmake.org/t/how-to-do-both-efficient-and-correct-system-inspection/5380/2 "2022-04-09T12:40:39Z")

</div>

> [@frankj](#):
>
> How can I make this detection happen _only if_ it needs to; meaning, only if the reconfiguration happens because of something in detect/ changing or some compiler/buildtype setting?

The issue is that you’re reusing the `RESULT_VAR` for each run. I would recommend using a separate variable name for each detection so that the cache actually remembers each `try_compile` individually. Alas, there’s probably no easy way to detect “needs to rerun” other than doing something like a hash of what matters and, if that changes, clearing all of the result variables used from the cache (and therefore letting `try_compile` have another go).
