Question

I'm writing a Cross-compiling Toolchain file for VxWorks. Since it's an unknown system to cmake a also have write platform files (those in ../Modules/Platform).

Beside my toolchain file I have written these platform files so far:

  • VxWorks.cmake (VxWorks OS settings)
  • VxWorks-gcc.cmake (WindRiver (Gnu) compiler settings)
  • VxWorks-gcc-[CPU].cmake (CPU specific settings, is the processor as specified in the toolchain file)

Everything works fine with my files at the moment.

But some of the default platform files contain a include guard / include blocker like this one:

if(__WINDOWS_GNU)
  return()
endif()
set(__WINDOWS_GNU 1)

(from: Modules/Platform/Windows-GNU.cmake)

So i'm wondering: Do I have to insert such a guard too? And when it's a good idea to insert them?

Was it helpful?

Solution

CMake modules can include each other, so it can lead to diamond problem. If you are lucky, you've got double work for setting some variables, but if you will need some complex stuff, things may get worse.

Example:

FindB.cmake

find_package(A)

FindA.cmake

find_package(B)

CMakeLists.txt

cmake_minimum_required(VERSION 2.8)

list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR})

find_package(A) # include FindA.cmake, which include FindB.cmake
    # which include FindA.cmake ....

Now run cmake .

-- The C compiler identification is Clang 4.2.0
-- The CXX compiler identification is Clang 4.2.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
Segmentation fault: 11

Just use guards at beginning of the module (let variable describe path to prevent collision)

FindB.cmake

if(FIND_B_CMAKE)
  return()
endif()
set(FIND_B_CMAKE 1)

find_package(A)

OTHER TIPS

It is possible to use include guards but with some limitations as mentioned here:

Note that the type of the include guard variable should never be a CACHE variable, since this would cause the variable to persist across multiple CMake configure runs, thereby causing the bug of blocking any subsequent run from reading in the module file's content. A Non-CACHE variable is not fully appropriate either, however, since foreign scopes (which did not adopt that variable definition yet) will lead to (somewhat unnecessary and potentially problematic) re-reading of the file's content. Thus the best choice is implementing this check via a GLOBAL property setting, since such settings have all of the desired characteristics: they're both globally valid and single-session only.

Second, note that only module files that are supportive of such a construct (i.e., files declaring only functions or defining all their settings as CACHE variables) can make use of include guards without issues (Non-CACHE variables, while possibly being referenced within those functions, may suddenly end up being out of scope yet the function will remain reachable).

In my case I have IncludeGuard.cmake file with the following content:

# Include this file and invoke cmake_include_guard to prevent the CMake script
# parse invoker file multiple times.

macro(cmake_include_guard)
    get_property(INCLUDE_GUARD GLOBAL PROPERTY "INCLUDE_GUARD_${CMAKE_CURRENT_LIST_FILE}")
    if(INCLUDE_GUARD)
        return()
    endif()
    set_property(GLOBAL PROPERTY "INCLUDE_GUARD_${CMAKE_CURRENT_LIST_FILE}" TRUE)
endmacro()

In common cmake files I use the following snippet at the beggining:

include(IncludeGuard)
cmake_include_guard()

Macro cmake_include_guard use return() to stop further content processing.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top