[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