Using CMAKE_CROSSCOMPILING evaluates to FALSE after -DCMAKE_CROSSCOMPILING=ON

Hi, I am scratching my head trying to find out why checks with if(CMAKE_CROSSCOMPILING) return false (running cmake version 3.18.2).

I am trying to cross compile pieces of the llvm-project with the following command-line in clean build folders:

cmake -GNinja \
  "-H$LLVM_SRC_DIR/llvm" \
  "-B$build_dir$suffix" \
  -DCMAKE_INSTALL_PREFIX=$install_dir$suffix  \
  -DMLIR_TABLEGEN=$mlir_tablegen \
  -DLLVM_INSTALL_UTILS=OFF  \
  -DLLVM_ENABLE_LLD=OFF   \
  -DLLVM_ENABLE_PROJECTS="mlir" \
  -DCMAKE_C_COMPILER=arm-linux-gnueabihf-gcc-7 \
  -DCMAKE_CXX_COMPILER=arm-linux-gnueabihf-g++-7 \
  -DCMAKE_CXX_FLAGS='-fcompare-debug-second' \
  -DCMAKE_CROSSCOMPILING:BOOL=ON \
  -DLLVM_DEFAULT_TARGET_TRIPLE=arm-linux-gnueabihf \
  -DLLVM_TARGET_ARCH=ARM \
  -DLLVM_TARGETS_TO_BUILD=ARM  \
  -DLLVM_BUILD_TOOLS=OFF   \
  -DLLVM_INCLUDE_TESTS=OFF   \
  -DMLIR_INCLUDE_TESTS=OFF   \
  -DCMAKE_BUILD_TYPE=RelWithDebInfo \
  -DLLVM_ENABLE_ASSERTIONS=ON \
  -DLLVM_BUILD_EXAMPLES=OFF

cmake --build "$build_dir$suffix" --target mlir_c_runner_utils mlir_runner_utils

Note the -DCMAKE_CROSSCOMPILING:BOOL=ON option. This is correctly shown in CMakeCache.txt:

$ cat CMakeCache.txt | grep CROSS
CMAKE_CROSSCOMPILING:BOOL=ON

But when I try to message or test the variable, it evaluates to FALSE

message (STATUS "!!! CMAKE_CROSSCOMPILING flag value: ${CMAKE_CROSSCOMPILING}")

if(CMAKE_CROSSCOMPILING)
  message (STATUS "!!! Crosscompiling, SystemC api libraries are disabed")
else()
  message (STATUS "!!! Not Crosscompiling, SystemC api libraries are enabled")
  endif()
endif()
[0/1] Re-running CMake...
...
-- Targeting ARM
-- !!! CMAKE_CROSSCOMPILING flag value: FALSE
-- !!! Not Crosscompiling, SystemC api libraries are enabled
...

Should I be using a different approach to set and check CMAKE_CROSSCOMPILING?
It appears that some internal logic is overriding my variable.

I appreciate any help.


ps.: I was redirected here from this issue https://gitlab.kitware.com/cmake/cmake/-/issues/21744
ps.: Others have pointed similar problems (cmake - How do I detect that I am cross-compiling in CMakeLists.txt? - Stack Overflow). Their solution was to change it in CMakeLists.txt file, but I was trying to avoid this approach, favoring the usage of the -DCMAKE_CROSSCOMPILING option.

The reason is, that CMake internally always sets CMAKE_CROSSCOMPILING as a normal variable to either TRUE or FALSE. You set it only as a cache variable but not as a normal one. As per cmake-language(7):

When evaluating Variable References, CMake first searches the function call stack, if any, for a binding and then falls back to the binding in the current directory scope, if any. If a “set” binding is found, its value is used. If an “unset” binding is found, or no binding is found, CMake then searches for a cache entry. If a cache entry is found, its value is used. Otherwise, the variable reference evaluates to an empty string. The $CACHE{VAR} syntax can be used to do direct cache entry lookups.

This means that the normal variable set internally by CMake will shadow your cache variable. You can check, that ${CMAKE_CROSSCOMPILING} and $CACHE{CMAKE_CROSSCOMPILING} should have contradicting values.

The documentation states, that the value of CMAKE_CROSSCOMPILING depends on whether CMAKE_SYSTEM_NAME was explicitly set or not. This is rather unintuitive, but until this behavior gets changed with a new policy as discussed in the issue you linked, the best approach is to simply set -DCMAKE_SYSTEM_NAME=... or set it in a toolchain file.

If your target system is not supported by CMake (I had this issue e.g. with VxWorks), you can either set it to Generic if appropriate (e.g. embedded devices without any OS) or provide a custom platform description file, which must be located at <CMAKE_MODULE_PATH>/Platform/<CMAKE_SYSTEM_NAME>.cmake. You can take a look at the ones provided by CMake here.

1 Like

Thank you for the explanation and links. The toolchain file approach addressed my problem.