[CMake] TRY_COMPILE without linking...

Michael Hertling mhertling at online.de
Thu May 27 10:45:26 EDT 2010


On 05/26/2010 04:03 AM, Bill Hoffman wrote:
> On 5/25/2010 8:57 PM, Michael Hertling wrote:
>> On 05/25/2010 06:13 PM, Theodore Papadopoulo wrote:
>>> In porting a library (blitz) from autoconf to cmake, I have the
>>> sub-project of testing C++ compiler features.
>>> The autoconf way was to create some C++ files and test that they are
>>> compiling (and just compiling not linking).
>>>
>>> TRY_COMPILE (in the variant that creates automatically the CMake
>>> project) seems to oblige me to link the code.
>>> Many of the tests (taken from autoconf) do not include a main(), some
>>> the tests fail. Obviously, I can create a main,
>>> but I wondered if there was an easy way to avoid the linking phase
>>> (without having to create my own CMake project
>>> for all those files).
>>
>> Use the CMAKE_FLAGS of TRY_COMPILE() to pass in a no-op for the linker:
>>
>> TRY_COMPILE(...
>>      CMAKE_FLAGS "-DCMAKE_CXX_LINK_EXECUTABLE='echo not linking now...'"
>> ...)
> 
> 
> That will not work with Xcode and VS. [...]

:(

> [...] The best you can do with those 
> generators is to create a static library instead of a linked executable.

Thus, perhaps, the following approach will do a better job:

- Setting up a minimal CMakeLists.txt for a static library.
- Configure and generate using EXECUTE_PROCESS(cmake ...).
- Build using EXECUTE_PROCESS(cmake --build ...).

The function COMPILE() provides a - less elaborated - implementation:

CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)

PROJECT(COMPILE)

FUNCTION(COMPILE RESULT SOURCE)
    MESSAGE(STATUS "Compiling ${SOURCE}")
    # Ensure SOURCE is absolute:
    IF(NOT IS_ABSOLUTE ${SOURCE})
        SET(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE})
    ENDIF()
    # Set up CMakeLists.txt for static library:
    FILE(WRITE
        ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/compile/CMakeLists.txt
        "ADD_LIBRARY(compile STATIC ${SOURCE})"
    )
    # Configure:
    EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} . WORKING_DIRECTORY
        ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/compile
        OUTPUT_VARIABLE LOG1 ERROR_VARIABLE LOG1
    )
    # Build:
    EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} --build
        ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/compile
        RESULT_VARIABLE RESVAR OUTPUT_VARIABLE LOG2 ERROR_VARIABLE LOG2
    )
    # Clean up:
    FILE(REMOVE_RECURSE ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/compile)
    # Set up log:
    IF(ARGC GREATER 2)
        SET(${ARGV2} "${LOG1}${LOG2}" PARENT_SCOPE)
    ENDIF()
    # Set up result:
    IF(RESVAR EQUAL 0)
        SET(${RESULT} TRUE PARENT_SCOPE)
    ELSE()
        SET(${RESULT} FALSE PARENT_SCOPE)
    ENDIF()
ENDFUNCTION()

FILE(WRITE good.c "void f(void){}")
COMPILE(RESULT good.c LOG)
MESSAGE("RESULT: ${RESULT}\nLOG:\n${LOG}")

FILE(WRITE bad.c "void f(void){")
COMPILE(RESULT bad.c LOG)
MESSAGE("RESULT: ${RESULT}\nLOG:\n${LOG}")

FILE(WRITE main.c "int main(void){ return 0; }")
COMPILE(RESULT main.c LOG)
MESSAGE("RESULT: ${RESULT}\nLOG:\n${LOG}")

On *nix, this seems to work at first glance, but as I can't test with
VS or Xcode currently, I would be interested in learning whether it's
sustainable and sufficiently platform-independent.

Regards,

Michael


More information about the CMake mailing list