using check_cxx_source_runs

Alexander Neundorf neundorf at kde.org
Sun Mar 15 21:35:43 CET 2009


On Thursday 12 March 2009, Leo Franchi wrote:
> On 12 Mar 2009, at 21:46, Alexander Neundorf wrote:
> > On Thursday 12 March 2009, Leo Franchi wrote:
> >> n 12 Mar 2009, at 20:12, Alexander Neundorf wrote:
> >>> On Thursday 12 March 2009, Leo Franchi wrote:
> >>>> On 12 Mar 2009, at 19:49, Alexander Neundorf wrote:
> >>>
> >>> ...
> >>>
> >>>>> Can you please post a minimal example ?
> >>>>> So I can just try and see what goes wrong ?
> >>>>
> >>>> and the cmake stuff is this:
> >>>>
> >>>> include(CheckCXXSourceRuns)
> >>>>
> >>>> file( READ "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/
> >>>> QtScriptBindingsTest.cpp" source )
> >>>> message(STATUS "Checking if the QtScript Qt Bindings are
> >>>> installed.")
> >>>>
> >>>> #set( BINDINGS_RUN_RESULT -10 )
> >>>> set(CMAKE_REQUIRED_DEFINTIONS ${QT_DEFINITIONS} $
> >>>> {KDE4_DEFINITIONS} )
> >>>> set(CMAKE_REQUIRED_INCLUDES ${QT_QTCORE_INCLUDE_DIR} $
> >>>> {QT_QTSCRIPT_INCLUDE_DIR} ${KDE4_INCLUDES})
> >>>> set(CMAKE_REQUIRED_LIBRARIES QtScript kdeui)
> >>>
> >>> I guess you tried ${QT_QTSCRIPT_LIBRARY} and ${KDE4_KDEUI_LIBS} ?
> >>
> >> First of all, apologies for the confusing emails. I've been hitting
> >> my
> >> head against this for a while, so what came out was probably pretty
> >> garbled and only made half sense.
> >
> > No, no, it made sense.
> >
> >> I didn't have a completely clean build dir (I guess on that test I
> >> had
> >> just removed CMakeCache.txt)
> >
> > Yes, this was part of the problem.
> >
> >> and also I couldn't figure out why $
> >> {KDE4_KDECORE_LIBS} didn't work. For some reason here the
> >> KDE4_KDE*_LIBS variables resolve to something like KDE4__kdeui
> >> instead
> >> of the actual path to the library.
> >
> > This is a new feature of cmake 2.6.
> > It is a so-called imported target. The nice thing about an imported
> > library
> > target (compared to a plain path) is that cmake can know more about
> > it. E.g.
> > it knows the "LINK_INTERFACE_LIBRARIES" of such imported library
> > targets. So
> > when you link against ${KDE4_KDEUI_LIBS}, which resolves to the
> > imported
> > target KDE4__kdeui, cmake checks the properties of this imported
> > target (set
> > in KDELibs4LibraryTargets.cmake, included by FindKDE4Internal.cmake
> > installed
> > with kdelibs, included by FindKDE4.cmake coming with cmake). It then
> > finds
> > the location of the file on disk (here: /opt/kdelibs/libkdeui.so.
> > 5.2.0), and
> > also its link interface libraries (here:
> > KDE4__kdecore;/usr/lib/qt4/lib/libQtSvg.so;/usr/lib/qt4/lib/
> > libQtGui.so )
> >
> > So now when you link a target against this imported library target,
> > you will
> > link against the library itself and the libraries from the link
> > interface
> > (which is a good thing).
> >
> > Now you use ${KDE4_KDEUI_LIBS} with check_cxx_source_runs(). The
> > problem here
> > now is that this creates a tiny cmake project itself, and then tries
> > to build
> > and run it. But here this tiny independent cmake project is told to
> > link
> > against KDE4__kdeui, but inside that project there are no imported
> > targets,
> > so it just takes that string and tries to link against it
> > using -lKDE4__kdeui, which of course fails.
> >
> > Please replace the CheckCXXSourceRuns.cmake which is installed by
> > the cmake on
> > your system with the one attached to this email. It adds some basic
> > handling
> > for using imported targets with check_cxx_source_runs().
> > It's not perfect yet, but it works here for me.
> > Please let me know if it works for you, then we can add it to
> > kdelibs/cmake/modules/.
> > A real fix for this should go into cmake itself.
>
> Yeah, this works great. Actually, since the whole link interface stuff
> makes it resolve the dependencies (qtcore is linked twice), can we

Can you please try the two attached files ?
They now do it (almost completely) properly, i.e. they resolve all imported 
targets to actual files on disk.
(the only thing they don't do yet is to deal with multiple configurations).

Please let me know if this works for you.
If it does, I'll commit it to kdelibs  and use it also in 
CheckCXXSourceCompiles. Well, actually it should be used in all modules which 
use CMAKE_REQUIRED_LIBRARIES...

Alex
-------------- next part --------------
# - Check if the C++ source code provided in the SOURCE argument compiles and runs.
# CHECK_CXX_SOURCE_RUNS(SOURCE VAR)
#
#  SOURCE - source code to try to compile
#  VAR    - variable to store the result, 1 for success, empty for failure
#
# The following variables may be set before calling this macro to
# modify the way the check is run:
#
#  CMAKE_REQUIRED_FLAGS = string of compile command line flags
#  CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
#  CMAKE_REQUIRED_INCLUDES = list of include directories
#  CMAKE_REQUIRED_LIBRARIES = list of libraries to link

GET_FILENAME_COMPONENT(_CHECK_CXX_SOURCE_RUNS_DIR ${CMAKE_CURRENT_LIST_FILE} PATH)
INCLUDE(${_CHECK_CXX_SOURCE_RUNS_DIR}/HandleImportedTargetsInCMakeRequiredLibraries.cmake)

MACRO(CHECK_CXX_SOURCE_RUNS SOURCE VAR)
  IF("${VAR}" MATCHES "^${VAR}$")
    SET(MACRO_CHECK_FUNCTION_DEFINITIONS 
      "-D${VAR} ${CMAKE_REQUIRED_FLAGS}")
    IF(CMAKE_REQUIRED_LIBRARIES)
      HANDLE_IMPORTED_TARGETS_IN_CMAKE_REQUIRED_LIBRARIES(_CHECK_CXX_SOURCE_RUNS_CMAKE_REQUIRED_LIBRARES)
      MESSAGE(STATUS "******* final req libs: ${_CHECK_CXX_SOURCE_RUNS_CMAKE_REQUIRED_LIBRARES}") 

      SET(CHECK_CXX_SOURCE_COMPILES_ADD_LIBRARIES
        "-DLINK_LIBRARIES:STRING=${_CHECK_CXX_SOURCE_RUNS_CMAKE_REQUIRED_LIBRARES}")
#        "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}")
    ELSE(CMAKE_REQUIRED_LIBRARIES)
      SET(CHECK_CXX_SOURCE_COMPILES_ADD_LIBRARIES)
    ENDIF(CMAKE_REQUIRED_LIBRARIES)
    IF(CMAKE_REQUIRED_INCLUDES)
      SET(CHECK_CXX_SOURCE_COMPILES_ADD_INCLUDES
        "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}")
    ELSE(CMAKE_REQUIRED_INCLUDES)
      SET(CHECK_CXX_SOURCE_COMPILES_ADD_INCLUDES)
    ENDIF(CMAKE_REQUIRED_INCLUDES)
    FILE(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.cxx"
      "${SOURCE}\n")

    MESSAGE(STATUS "Performing Test ${VAR}")
    TRY_RUN(${VAR}_EXITCODE ${VAR}_COMPILED
      ${CMAKE_BINARY_DIR}
      ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.cxx
      COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
      CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS}
      -DCMAKE_SKIP_RPATH:BOOL=${CMAKE_SKIP_RPATH}
      "${CHECK_CXX_SOURCE_COMPILES_ADD_LIBRARIES}"
      "${CHECK_CXX_SOURCE_COMPILES_ADD_INCLUDES}"
      COMPILE_OUTPUT_VARIABLE OUTPUT)

    # if it did not compile make the return value fail code of 1
    IF(NOT ${VAR}_COMPILED)
      SET(${VAR}_EXITCODE 1)
    ENDIF(NOT ${VAR}_COMPILED)
    # if the return value was 0 then it worked
    IF("${${VAR}_EXITCODE}" EQUAL 0)
      SET(${VAR} 1 CACHE INTERNAL "Test ${VAR}")
      MESSAGE(STATUS "Performing Test ${VAR} - Success")
      FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log 
        "Performing C++ SOURCE FILE Test ${VAR} succeded with the following output:\n"
        "${OUTPUT}\n" 
        "Return value: ${${VAR}}\n"
        "Source file was:\n${SOURCE}\n")
    ELSE("${${VAR}_EXITCODE}" EQUAL 0)
      IF(CMAKE_CROSSCOMPILING AND "${${VAR}_EXITCODE}" MATCHES  "FAILED_TO_RUN")
        SET(${VAR} "${${VAR}_EXITCODE}")
      ELSE(CMAKE_CROSSCOMPILING AND "${${VAR}_EXITCODE}" MATCHES  "FAILED_TO_RUN")
        SET(${VAR} "" CACHE INTERNAL "Test ${VAR}")
      ENDIF(CMAKE_CROSSCOMPILING AND "${${VAR}_EXITCODE}" MATCHES  "FAILED_TO_RUN")

      MESSAGE(STATUS "Performing Test ${VAR} - Failed")
      FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log 
        "Performing C++ SOURCE FILE Test ${VAR} failed with the following output:\n"
        "${OUTPUT}\n"  
        "Return value: ${${VAR}_EXITCODE}\n"
        "Source file was:\n${SOURCE}\n")
    ENDIF("${${VAR}_EXITCODE}" EQUAL 0)
  ENDIF("${VAR}" MATCHES "^${VAR}$")
ENDMACRO(CHECK_CXX_SOURCE_RUNS)

-------------- next part --------------
# - Check if the C++ source code provided in the SOURCE argument compiles and runs.
# CHECK_CXX_SOURCE_RUNS(SOURCE VAR)
#
#  SOURCE - source code to try to compile
#  VAR    - variable to store the result, 1 for success, empty for failure
#
# The following variables may be set before calling this macro to
# modify the way the check is run:
#
#  CMAKE_REQUIRED_FLAGS = string of compile command line flags
#  CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
#  CMAKE_REQUIRED_INCLUDES = list of include directories
#  CMAKE_REQUIRED_LIBRARIES = list of libraries to link


FUNCTION(HANDLE_IMPORTED_TARGETS_IN_CMAKE_REQUIRED_LIBRARIES _RESULT)
# handle imported library targets
   SET(_CCSR_IMP_TARGETS_MAP)
   SET(_CCSR_REQ_LIBS ${CMAKE_REQUIRED_LIBRARIES})
   SET(_CHECK_FOR_IMPORTED_TARGETS TRUE)
   SET(_CCSR_LOOP_COUNTER 0)
   WHILE(_CHECK_FOR_IMPORTED_TARGETS)
      MATH(EXPR _CCSR_LOOP_COUNTER "${_CCSR_LOOP_COUNTER} + 1 ")
      SET(_CCSR_NEW_REQ_LIBS )
      SET(_CHECK_FOR_IMPORTED_TARGETS FALSE)
      FOREACH(_CURRENT_LIB ${_CCSR_REQ_LIBS})
         GET_TARGET_PROPERTY(_importedConfigs ${_CURRENT_LIB} IMPORTED_CONFIGURATIONS)
         IF (_importedConfigs)
            # Ok, so this is an imported target.
            # First we get the imported configurations.
            # Then we get the location of the actual library on disk of the first configuration.
            # then we'll get its link interface libraries property,
            # iterate through it and replace all imported targets we find there
            # with there actual location.

            # guard against infinite loop: abort after 100 iterations ( 100 is arbitrary chosen)
            IF ("${_CCSR_LOOP_COUNTER}" LESS 100)
               SET(_CHECK_FOR_IMPORTED_TARGETS TRUE)
#                ELSE ("${_CCSR_LOOP_COUNTER}" LESS 1)
#                   MESSAGE(STATUS "********* aborting loop, counter : ${_CCSR_LOOP_COUNTER}")
            ENDIF ("${_CCSR_LOOP_COUNTER}" LESS 100)

            LIST(GET _importedConfigs 0 _firstImportedConfig)
            GET_TARGET_PROPERTY(_firstImportedLocation ${_CURRENT_LIB} LOCATION_${_firstImportedConfig})
            GET_TARGET_PROPERTY(_linkInterfaceLibs ${_CURRENT_LIB} IMPORTED_LINK_INTERFACE_LIBRARIES_${_firstImportedConfig} )

            LIST(APPEND _CCSR_NEW_REQ_LIBS  ${_firstImportedLocation})
#                MESSAGE(STATUS "Appending lib ${_CURRENT_LIB} as ${_firstImportedLocation}")
            FOREACH(_currentLinkInterfaceLib ${_linkInterfaceLibs})
#                   MESSAGE(STATUS "Appending link interface lib ${_currentLinkInterfaceLib}")
               LIST(APPEND _CCSR_NEW_REQ_LIBS ${_currentLinkInterfaceLib} )
            ENDFOREACH(_currentLinkInterfaceLib ${_linkInterfaceLibs})
         ELSE(_importedConfigs)
            # "Normal" libraries are just used as they are.
            LIST(APPEND _CCSR_NEW_REQ_LIBS ${_CURRENT_LIB} )
#                MESSAGE(STATUS "Appending lib directly: ${_CURRENT_LIB}")
         ENDIF(_importedConfigs)
      ENDFOREACH(_CURRENT_LIB ${_CCSR_REQ_LIBS})

      SET(_CCSR_REQ_LIBS ${_CCSR_NEW_REQ_LIBS} )
   ENDWHILE(_CHECK_FOR_IMPORTED_TARGETS)

   # Finally we iterate once more over all libraries. This loop only removes
   # all remaining imported target names (there shouldn't be any left anyway).
   SET(_CCSR_NEW_REQ_LIBS )
   FOREACH(_CURRENT_LIB ${_CCSR_REQ_LIBS})
      GET_TARGET_PROPERTY(_importedConfigs ${_CURRENT_LIB} IMPORTED_CONFIGURATIONS)
      IF (NOT _importedConfigs)
         LIST(APPEND _CCSR_NEW_REQ_LIBS ${_CURRENT_LIB} )
#             MESSAGE(STATUS "final: appending ${_CURRENT_LIB}")
      ELSE (NOT _importedConfigs)
#             MESSAGE(STATUS "final: skipping ${_CURRENT_LIB}")
      ENDIF (NOT _importedConfigs)
   ENDFOREACH(_CURRENT_LIB ${_CCSR_REQ_LIBS})
   SET(${_RESULT} ${_CCSR_NEW_REQ_LIBS} PARENT_SCOPE)

ENDFUNCTION(HANDLE_IMPORTED_TARGETS_IN_CMAKE_REQUIRED_LIBRARIES _CCSR_REQ_LIBS)



More information about the Kde-buildsystem mailing list