Search code examples
cmakeconfigureccldflagscflags

Get C/CXX FLAGS set by commands add_definitions() and add_compile_options()


In my CMakeLists.txt, global C and CXX flags are set using commands add_definitions() and add_compile_options.

Many attempts to retrieve the C/CXX flags:

  1. ${CMAKE_C_FLAGS} and ${CMAKE_CXX_FLAGS} are empty
  2. ${CMAKE_C_FLAGS_${CMAKE_BUILD_TYPE}} is the original default CMake value
    (e.g. -g for CMAKE_C_FLAGS_DEBUG)
  3. ${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}} same as above
  4. get_cmake_property(def COMPILE_DEFINITIONS) is NOTFOUND
  5. get_cmake_property(opt COMPILE_OPTIONS) is also NOTFOUND

I want to pass my custom C/CXX flags to an external project based on ./configure:

ExternalProject_Add( my_external_lib
  DEPENDS            Threads::Threads
  SOURCE_DIR         ${CMAKE_CURRENT_LIST_DIR}
  BUILD_IN_SOURCE    1
  UPDATE_COMMAND     echo "Full clean" && make distclean
  CONFIGURE_COMMAND  ${CMAKE_CURRENT_LIST_DIR}/configure
       --prefix=${CMAKE_BINARY_DIR}
       --cc=${CMAKE_C_COMPILER}
       --cxx=${CMAKE_CXX_COMPILER}
       --CFLAGS=${CMAKE_C_FLAGS_${CMAKE_BUILD_TYPE}}
       --CXXFLAGS=${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}}
       --LDFLAGS=${CMAKE_STATIC_LINKER_FLAGS_${CMAKE_BUILD_TYPE}}
       --ARFLAGS=${CMAKE_STATIC_LINKER_FLAGS_${CMAKE_BUILD_TYPE}}
       --enable-static
)

(1) How to get compilation flags set by add_definitions() and add_compile_options?

Note: I use CMake version 3.3.2


While writing the question, I realize I am wondering another question:

I use ccache but the ./configure script does not see my environment variables CC and CXX when I set them like that:

get_cmake_property(launcher   RULE_LAUNCH_COMPILE)
set(ENV{CC}  ${launcher} ${CMAKE_C_COMPILER})
set(ENV{CXX} ${launcher} ${CMAKE_CXX_COMPILER})

(2) Are these above CMake statements correct?


Oops I have again another question:

I retrieve the LDFLAGS and ARFLAGS from the same variable ${CMAKE_STATIC_LINKER_FLAGS}.
(3) Is there another CMake variable to set ARFLAGS?


Solution

  • Several questions in one post, but all of them are simple:

    1. Documentation link for add_definitions() explicitely refers to directory and target COMPILE_DEFINITION properties. The first of them is extracted by using get_directory_property(), the second by using get_target_property(). Any of them can also be extracted by using get_property(). get_cmake_property you tried to use is inapplicable here (it is used for other type of properties).

    2. You set environment variables CC and CXX at configuration step, but all commands for ExternalProject_Add are executed at build step.

    Currently ExternalProject_Add doesn't support simple setting environment variables. As adviced in this bugreport, for set variable's value without spaces you may prepend command with "VAR=VAL" clauses. But for your case this wouldn't work because of escaping problems.

    See also CMake FAQ: How can I get or set environment variables?

    [...]
    environment variables SET in the CMakeLists.txt only take effect for cmake itself (configure-time), so you cannot use this method to set an environment variable that a custom command might need (build-time). Barring environment variable support by various CMake commands (e.g. add_custom_command(), currently not supported yet), an acceptable workaround may be to invoke shell scripts instead which wrap the commands to be executed.

    Simple wrapper script to set environment variables and run actual command:

    wrapper.sh.in:

    export "CC=ccache @CMAKE_C_COMPILER@"
    export "CXX=ccache @CMAKE_XX_COMPILER@"
    eval "$*"
    

    CMakeLists.txt:

    configure_file(wrapper.sh.in wrapper.sh @ONLY)
    ExternalProject_Add(my_external_lib
        ...
        CONFIGURE_COMMAND /bin/sh ${CMAKE_CURRENT_BINARY_DIR}/wrapper.sh
            ${CMAKE_CURRENT_LIST_DIR}/configure ...
        BUILD_COMMAND /bin/sh ${CMAKE_CURRENT_BINARY_DIR}/wrapper.sh make
    )
    

    Note, that you should use wrapper for every command which requires this variables. In you case, these are CONFIGURE_COMMAND and BUILD_COMMAND.

    1. Documentation for CMAKE_STATIC_LINKER_FLAGS says that these flags are used for linker, so you may probably use them as LDFLAGS. As for ARFLAGS, they are hardcoded directrly to CMAKE_C_ARCHIVE_CREATE variable, contained full command line for ar. By default this command simply uses linker flags, so your approach seems to be correct too.