CMake cross-compiling: C flags from toolchain file ignored
Asked Answered
C

2

27

I use cmake for cross compiling. In my toolchain file there is a line

SET(CMAKE_C_FLAGS "-std=gnu99")

This variable is not set in CMakeLists.txt again.

When I run cmake -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake .. this flag is ignored.

To be more detailed: The line of flags.cmake shows an empty C_FLAGS = line. But in CMakeOutput.log I can find a line Build flags: -std=gnu99.

I found out that a second run of cmake .. (same with or without toolchain file specified) fixes this problem.

But why is it not set the first time i run cmake ??

EDIT: Added MNWE

CMakeLists.txt:

cmake_minimum_required(VERSION 2.6)
project(myproject)

SET(files src/main.c)

add_executable(myexec ${files})

avr.cmake:

SET(CMAKE_SYSTEM_NAME Generic)

SET(CMAKE_C_COMPILER avr-gcc)

SET(CMAKE_C_FLAGS "-std=gnu99")
Chidester answered 10/7, 2012 at 23:7 Comment(1)
Thank you! I had this exact issue.Presentationism
C
27

I've found a temporary solution by replacing the line

SET(CMAKE_C_FLAGS "-std=gnu99")

by

SET(CMAKE_C_FLAGS "-std=gnu99" CACHE STRING "" FORCE)
Chidester answered 18/7, 2012 at 7:49 Comment(2)
It works, thank you (I added the line just after the "project" instruction)Quad
This saved my evening.Suspensory
T
18

I just wanted to add some background information (discussed e.g. here how to setup cmake_c/xx_flags per toolchain?).

In short, the CMAKE_<LANG>_FLAGS variables are cached by design in the CMake<Lang>Information.cmake scripts (meaning you could change them in CMake's GUI application after the configure step).

So you have to - if setting them in the Toolchain file - put them in the cache first. CMake's own script (executed after the Toolchain file) does not come with a FORCE, so it won't overwrite it again.

Take a look into CMakeCInformation.cmake (from share\cmake-2.8\Modules):

set(CMAKE_C_FLAGS_INIT "$ENV{CFLAGS} ${CMAKE_C_FLAGS_INIT}")
# avoid just having a space as the initial value for the cache
if(CMAKE_C_FLAGS_INIT STREQUAL " ")
  set(CMAKE_C_FLAGS_INIT)
endif()
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS_INIT}" CACHE STRING
     "Flags used by the compiler during all build types.")

As you can see, the official way to do it would be using CMAKE_C_FLAGS_INIT to inject additional flags. The problem there is, that later changes in the Toolchain file would not be recognized (the cache won't be overwritten, see above).

Taken all this into account, your temporary solution is the right choice. To be really sure - because the Toolchain file is parsed twice during the Configuration/Generation process - you could even add an UNSET call before setting CMAKE_C_FLAGS in your toolchain file:

UNSET(CMAKE_C_FLAGS CACHE)
SET(CMAKE_C_FLAGS "-std=gnu99" CACHE STRING "" FORCE)

Another often found solution is to use something like:

add_definitions(" -std=gnu99")

to inject compile flags (but this is not build configuration aware, as the variable definitions are). See also CMake clang and c++0x

With CMake 2.8.12 there were new commands introduced, so you could do (not tested, just to show the possibilities):

add_compile_options("$<$<CONFIG:RELASE>:-std=gnu99>")
add_compile_options("$<$<CONFIG:DEBUG>:-std=gnu99 -g3>")

See What is the modern method for setting general compile flags in CMake? and CMake generator expression, differentiate C / C++ code for more on this.

Transpolar answered 13/5, 2015 at 13:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.