7

I have a cmake cross compiler toolchain file, abridged as:

set(CMAKE_SYSTEM_NAME Linux)
if( DEFINED TC_PATH )
    message( STATUS " TC_PATH IS defined. ${TC_PATH}" )
else()
    message( FATAL_ERROR " TC_PATH not defined." )
endif()

set(CMAKE_C_COMPILER ${TC_PATH}/usr/bin/i586-linux/i586-linux-gcc )
set(CMAKE_CXX_COMPILER ${TC_PATH}/usr/bin/i586-linux/i586-linux-g++ )
set(CMAKE_LINKER ${TC_PATH}/usr/bin/i586-linux/i586-linux-ld )

I call cmake, setting the TC_PATH as well as the toolchain file:

~/CMakeTest/output $ cmake -DTC_PATH:PATH=/opt/toolchain -DCMAKE_TOOLCHAIN_FILE=../toolchain.cmake ../

It appears cmake is invoking the toolchain file multiple times. On the first two time, the TC_PATH check succeeds, but later, after identifying the compilers, it throws an error:

--  TC_PATH IS defined. /opt/toolchain
--  TC_PATH IS defined. /opt/toolchain
-- The C compiler identification is GNU 4.9.1
-- The CXX compiler identification is GNU 4.9.1
-- Check for working C compiler: /opt/toolchain/usr/bin/i586-linux/i586-linux-gcc
CMake Error at /home/gnac/CMakeTest/toolchain.cmake:4 (message):
   TC_PATH not defined.
Call Stack (most recent call first):
  /home/gnac/CMakeTest/output/CMakeFiles/3.0.2/CMakeSystem.cmake:6 (include)
  CMakeLists.txt:2 (project)

So, outside of setting a permanent environment variable in the shell, how I can set the TC_PATH variable via the command line so that it will be remain in context while executing the cmake generate command?

gnac
  • 1,573
  • 15
  • 17

3 Answers3

2

When compiling a test project, CMake does not pass variables to it by default.

There is CMAKE_TRY_COMPILE_PLATFORM_VARIABLES option for passing variables into the test project. In order to fix your issue, this line should be put into the toolchain file:

set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES TC_PATH)
1

Your toolchain needs to be self-sufficient. The step that fails is a try_compile() which is not getting your cached variables.

Your toolchain file does not look like you're cross-compiling (it does not have a CMAKE_SYSTEM_NAME) so you can do one of the following (besides setting the CC and CXX environment variables as you have mentioned):

  1. It's sufficient to give the full path to your C and/or CXX compiler (depending on which languages you enabled), CMake will detect the rest of your GNU toolchain automatically

    cmake -DCMAKE_C_COMPILER:PATH=/opt/toolchain/usr/bin/i586-linux/i586-linux-gcc 
          -DCMAKE_CXX_COMPILER:PATH=/opt/toolchain/usr/bin/i586-linux/i586-linux-g++ ...
    
  2. Add the following to your toolchain to skip the compiler tests (because not all options may be passed to it or because your compiler/linker of choice will not produce a valid executable)

    set(CMAKE_C_COMPILER_WORKS 1 CACHE INTERNAL "")
    set(CMAKE_CXX_COMPILER_WORKS 1 CACHE INTERNAL "")
    

    Or just use the CMakeForceCompiler macros, but the use is "Discouraged. Avoid using this module if possible."

  3. Use configure_file() to put the path into your toolchain file (just make sure to do it before the project() call)

  4. Prefer find_program() if the possible paths of your toolchain are known over setting it from the outside (see e.g. here)

References

Community
  • 1
  • 1
Florian
  • 39,996
  • 9
  • 133
  • 149
  • Florian, my toolchain file does in fact have set CMAKE_SYSTEM_NAME. I left it out of the "abridged" version to keep the question more concise. I've added it in now to provide a more complete/correct question. Thanks. – gnac Jun 08 '16 at 18:55
  • This is a bit old, but just curious on a strategy for dealing with this. I want to build for iOS and there are available iOS toolchain files. One issues is setting something called the minimum deployment version. This can vary for people so ideally would be passed in as an argument. A couple options I could see would be using an environment variable to pass this through, creating a temp cmake file, or having different versions of the toolchain per deployment version. All have their issues. – Mobile Ben Jun 04 '18 at 04:00
1

I am sorry that I have to revive this but I'm still wondering why I need to resort to hacks like this to propagate variables to the toolchain configuration file:

...
elseif(${OS_FSFW} STREQUAL linux AND TGT_BSP)
    if(NOT SOME_VARIABLE_USED_BY_TOOLCHAINFILE)
        set(ENV{SOME_VARIABLE_USED_BY_TOOLCHAINFILE} "$ENV{HOME}/raspberrypi/rootfs")
    else()
        set(ENV{SOME_VARIABLE_USED_BY_TOOLCHAINFILE} "${SOME_VARIABLE_USED_BY_TOOLCHAINFILE}")
    endif()
    set(CMAKE_TOOLCHAIN_FILE 
        ${CMAKE_CURRENT_SOURCE_DIR}/buildsystem/cmake/CrossCompileConfig.cmake
    )
endif()

I mean, it works, but why is the toolchain file unable to handle variables set by the upper CMakeList properly? CMake is even able to print out variables set that way, but doing things like checking their existence does not appear to work unless they are environmental variables.

Spacefish
  • 305
  • 4
  • 11