CheckStructHasMember: Add support for C++

Previously if headers required to check if a struct has a member can be
compiled with C++ compiler only, the check would fail because the C
compiler fails.  As a consequence, the result variable would be set to
false, even if the struct has that particular member.

Teach CHECK_STRUCT_HAS_MEMBER to accept a new optional argument LANGUAGE
that allows one to explicitly set the compiler to use.  The new
signature is therefore:

  CHECK_STRUCT_HAS_MEMBER (<struct> <member> <header> <variable>
                           [LANGUAGE <language>])
This commit is contained in:
Daniele E. Domenichelli 2013-09-20 15:10:40 +02:00 committed by Brad King
parent 951a158c8a
commit 73d28d2177
24 changed files with 219 additions and 9 deletions

View File

@ -1,10 +1,12 @@
# - Check if the given struct or class has the specified member variable
# CHECK_STRUCT_HAS_MEMBER (STRUCT MEMBER HEADER VARIABLE)
# CHECK_STRUCT_HAS_MEMBER (<struct> <member> <header> <variable>
# [LANGUAGE <language>])
#
# STRUCT - the name of the struct or class you are interested in
# MEMBER - the member which existence you want to check
# HEADER - the header(s) where the prototype should be declared
# VARIABLE - variable to store the result
# <struct> - the name of the struct or class you are interested in
# <member> - the member which existence you want to check
# <header> - the header(s) where the prototype should be declared
# <variable> - variable to store the result
# <language> - the compiler to use (C or CXX)
#
# The following variables may be set before calling this macro to
# modify the way the check is run:
@ -12,8 +14,9 @@
# 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
#
# Example: CHECK_STRUCT_HAS_MEMBER("struct timeval" tv_sec sys/select.h HAVE_TIMEVAL_TV_SEC)
# Example: CHECK_STRUCT_HAS_MEMBER("struct timeval" tv_sec sys/select.h HAVE_TIMEVAL_TV_SEC LANGUAGE C)
#=============================================================================
# Copyright 2007-2009 Kitware, Inc.
@ -29,6 +32,7 @@
# License text for the above reference.)
include(CheckCSourceCompiles)
include(CheckCXXSourceCompiles)
macro (CHECK_STRUCT_HAS_MEMBER _STRUCT _MEMBER _HEADER _RESULT)
set(_INCLUDE_FILES)
@ -36,16 +40,29 @@ macro (CHECK_STRUCT_HAS_MEMBER _STRUCT _MEMBER _HEADER _RESULT)
set(_INCLUDE_FILES "${_INCLUDE_FILES}#include <${it}>\n")
endforeach ()
if("x${ARGN}" STREQUAL "x")
set(_lang C)
elseif("x${ARGN}" MATCHES "^xLANGUAGE;([a-zA-Z]+)$")
set(_lang "${CMAKE_MATCH_1}")
else()
message(FATAL_ERROR "Unknown arguments:\n ${ARGN}\n")
endif()
set(_CHECK_STRUCT_MEMBER_SOURCE_CODE "
${_INCLUDE_FILES}
int main()
{
${_STRUCT}* tmp;
tmp->${_MEMBER};
return 0;
return 0;
}
")
CHECK_C_SOURCE_COMPILES("${_CHECK_STRUCT_MEMBER_SOURCE_CODE}" ${_RESULT})
if("${_lang}" STREQUAL "C")
CHECK_C_SOURCE_COMPILES("${_CHECK_STRUCT_MEMBER_SOURCE_CODE}" ${_RESULT})
elseif("${_lang}" STREQUAL "CXX")
CHECK_CXX_SOURCE_COMPILES("${_CHECK_STRUCT_MEMBER_SOURCE_CODE}" ${_RESULT})
else()
message(FATAL_ERROR "Unknown language:\n ${_lang}\nSupported languages: C, CXX.\n")
endif()
endmacro ()

View File

@ -19,6 +19,8 @@ add_CMakeOnly_test(CheckCXXCompilerFlag)
add_CMakeOnly_test(CheckLanguage)
add_CMakeOnly_test(CheckStructHasMember)
add_CMakeOnly_test(CompilerIdC)
add_CMakeOnly_test(CompilerIdCXX)
if(CMAKE_Fortran_COMPILER)

View File

@ -0,0 +1,93 @@
cmake_minimum_required(VERSION 2.8)
project(CheckStructHasMember)
set(CMAKE_REQUIRED_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}")
include(CheckStructHasMember)
foreach(_config_type Release RelWithDebInfo MinSizeRel Debug)
set(CMAKE_TRY_COMPILE_CONFIGURATION ${_config_type})
unset(CSHM_RESULT_S1_${_config_type} CACHE)
unset(CSHM_RESULT_S2_${_config_type} CACHE)
unset(CSHM_RESULT_S3_${_config_type} CACHE)
message(STATUS "Testing configuration ${_config_type}")
check_struct_has_member("struct non_existent_struct" "foo" "cm_cshm.h" CSHM_RESULT_S1_${_config_type})
check_struct_has_member("struct struct_with_member" "non_existent_member" "cm_cshm.h" CSHM_RESULT_S2_${_config_type})
check_struct_has_member("struct struct_with_member" "member" "cm_cshm.h" CSHM_RESULT_S3_${_config_type})
if(CSHM_RESULT_S1_${_config_type} OR CSHM_RESULT_S2_${_config_type})
message(SEND_ERROR "CheckStructHasMember reported a nonexistent member as existing in configuration ${_config_type}")
endif()
if(NOT CSHM_RESULT_S3_${_config_type})
message(SEND_ERROR "CheckStructHasMember did not report an existent member as existing in configuration ${_config_type}")
endif()
endforeach()
foreach(_config_type Release RelWithDebInfo MinSizeRel Debug)
set(CMAKE_TRY_COMPILE_CONFIGURATION ${_config_type})
unset(CSHM_RESULT_S1_${_config_type}_C CACHE)
unset(CSHM_RESULT_S2_${_config_type}_C CACHE)
unset(CSHM_RESULT_S3_${_config_type}_C CACHE)
message(STATUS "Testing configuration ${_config_type}")
check_struct_has_member("struct non_existent_struct" "foo" "cm_cshm.h" CSHM_RESULT_S1_${_config_type}_C LANGUAGE C)
check_struct_has_member("struct struct_with_member" "non_existent_member" "cm_cshm.h" CSHM_RESULT_S2_${_config_type}_C LANGUAGE C)
check_struct_has_member("struct struct_with_member" "member" "cm_cshm.h" CSHM_RESULT_S3_${_config_type}_C LANGUAGE C)
if(CSHM_RESULT_S1_${_config_type}_C OR CSHM_RESULT_S2_${_config_type}_C)
message(SEND_ERROR "CheckStructHasMember reported a nonexistent member as existing in configuration ${_config_type}")
endif()
if(NOT CSHM_RESULT_S3_${_config_type}_C)
message(SEND_ERROR "CheckStructHasMember did not report an existent member as existing in configuration ${_config_type}")
endif()
endforeach()
foreach(_config_type Release RelWithDebInfo MinSizeRel Debug)
set(CMAKE_TRY_COMPILE_CONFIGURATION ${_config_type})
unset(CSHM_RESULT_S1_${_config_type}_CXX CACHE)
unset(CSHM_RESULT_S2_${_config_type}_CXX CACHE)
unset(CSHM_RESULT_S3_${_config_type}_CXX CACHE)
unset(CSHM_RESULT_C1_${_config_type}_CXX CACHE)
unset(CSHM_RESULT_C2_${_config_type}_CXX CACHE)
unset(CSHM_RESULT_C3_${_config_type}_CXX CACHE)
message(STATUS "Testing configuration ${_config_type}")
check_struct_has_member("non_existent_struct" "foo" "cm_cshm.h" CSHM_RESULT_S1_${_config_type}_CXX LANGUAGE CXX)
check_struct_has_member("struct_with_non_existent_members" "non_existent_member" "cm_cshm.h" CSHM_RESULT_S2_${_config_type}_CXX LANGUAGE CXX)
check_struct_has_member("struct struct_with_member" "member" "cm_cshm.h" CSHM_RESULT_S3_${_config_type}_CXX LANGUAGE CXX)
check_struct_has_member("ns::non_existent_class" "foo" "cm_cshm.hxx" CSHM_RESULT_C1_${_config_type}_CXX LANGUAGE CXX)
check_struct_has_member("ns::class_with_non_existent_members" "foo" "cm_cshm.hxx" CSHM_RESULT_C2_${_config_type}_CXX LANGUAGE CXX)
check_struct_has_member("ns::class_with_member" "foo" "cm_cshm.hxx" CSHM_RESULT_C3_${_config_type}_CXX LANGUAGE CXX)
if(CSHM_RESULT_S1_${_config_type}_CXX OR CSHM_RESULT_S2_${_config_type}_CXX OR CSHM_RESULT_C1_${_config_type}_CXX OR CSHM_RESULT_C2_${_config_type}_CXX)
message(SEND_ERROR "CheckStructHasMember reported a nonexistent member as existing in configuration ${_config_type}")
endif()
if(NOT CSHM_RESULT_S3_${_config_type}_CXX OR NOT CSHM_RESULT_C3_${_config_type}_CXX)
message(SEND_ERROR "CheckStructHasMember did not report an existent member as existing in configuration ${_config_type}")
endif()
endforeach()
set(CMAKE_TRY_COMPILE_CONFIGURATION ${CMAKE_BUILD_TYPE})
if (CMAKE_COMPILER_IS_GNUCC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3")
unset(CSHM_RESULT_O3 CACHE)
unset(CSHM_RESULT_O3_C CACHE)
unset(CSHM_RESULT_O3_CXX CACHE)
message(STATUS "Testing with optimization -O3")
check_struct_has_member("class_with_non_existent_members" foo "cm_cshm.h" CSHM_RESULT_O3)
check_struct_has_member("class_with_non_existent_members" foo "cm_cshm.h" CSHM_RESULT_O3_C LANGUAGE C)
check_struct_has_member("class_with_non_existent_members" foo "cm_cshm.h" CSHM_RESULT_O3_CXX LANGUAGE CXX)
if (CSE_RESULT_O3 OR CSHM_RESULT_O3_C OR CSHM_RESULT_O3_CXX)
message(SEND_ERROR "CheckSymbolExists reported a nonexistent symbol as existing with optimization -O3")
endif ()
endif ()

View File

@ -0,0 +1,9 @@
#ifndef _CSHM_DUMMY_H
#define _CSHM_DUMMY_H
struct non_existent_struct;
struct struct_with_member{
int member;
};
#endif

View File

@ -0,0 +1,16 @@
#ifndef _CSHM_DUMMY_HXX
#define _CSHM_DUMMY_HXX
namespace ns {
class non_existent_class;
class class_with_non_existent_members {
};
class class_with_member {
public:
int foo;
};
}
#endif

View File

@ -119,3 +119,4 @@ endif()
add_RunCMake_test(File_Generate)
add_RunCMake_test(ExportWithoutLanguage)
add_RunCMake_test(target_link_libraries)
add_RunCMake_test(CheckModules)

View File

@ -0,0 +1,3 @@
cmake_minimum_required(VERSION 2.8.11)
project(${RunCMake_TEST})
include(${RunCMake_TEST}.cmake)

View File

@ -0,0 +1,8 @@
CMake Error at .*/Modules/CheckStructHasMember.cmake:[0-9]+. \(message\):
Unknown arguments:
C
Call Stack \(most recent call first\):
CheckStructHasMemberMissingKey.cmake:[0-9]+ \(check_struct_has_member\)
CMakeLists.txt:[0-9]+ \(include\)

View File

@ -0,0 +1,2 @@
include(CheckStructHasMember)
check_struct_has_member("struct timeval" tv_sec sys/select.h HAVE_TIMEVAL_TV_SEC_K C)

View File

@ -0,0 +1,8 @@
CMake Error at .*/Modules/CheckStructHasMember.cmake:[0-9]+. \(message\):
Unknown arguments:
LANGUAGE
Call Stack \(most recent call first\):
CheckStructHasMemberMissingLanguage.cmake:[0-9]+ \(check_struct_has_member\)
CMakeLists.txt:[0-9]+ \(include\)

View File

@ -0,0 +1,2 @@
include(CheckStructHasMember)
check_struct_has_member("struct timeval" tv_sec sys/select.h HAVE_TIMEVAL_TV_SEC_K LANGUAGE)

View File

@ -0,0 +1,4 @@
include(CheckStructHasMember)
check_struct_has_member("struct timeval" tv_sec sys/select.h HAVE_TIMEVAL_TV_SEC)
check_struct_has_member("struct timeval" tv_sec sys/select.h HAVE_TIMEVAL_TV_SEC_C LANGUAGE C)
check_struct_has_member("struct timeval" tv_sec sys/select.h HAVE_TIMEVAL_TV_SEC_CXX LANGUAGE CXX)

View File

@ -0,0 +1,8 @@
CMake Error at .*/Modules/CheckStructHasMember.cmake:[0-9]+. \(message\):
Unknown arguments:
LANGUAGE;C;CXX
Call Stack \(most recent call first\):
CheckStructHasMemberTooManyArguments.cmake:[0-9]+ \(check_struct_has_member\)
CMakeLists.txt:[0-9]+ \(include\)

View File

@ -0,0 +1,2 @@
include(CheckStructHasMember)
check_struct_has_member("struct timeval" tv_sec sys/select.h HAVE_TIMEVAL_TV_SEC_K LANGUAGE C CXX)

View File

@ -0,0 +1,10 @@
CMake Error at .*/Modules/CheckStructHasMember.cmake:[0-9]+. \(message\):
Unknown language:
FORTRAN
Supported languages: C, CXX.
Call Stack \(most recent call first\):
CheckStructHasMemberUnknownLanguage.cmake:[0-9]+ \(check_struct_has_member\)
CMakeLists.txt:[0-9]+ \(include\)

View File

@ -0,0 +1,2 @@
include(CheckStructHasMember)
check_struct_has_member("struct timeval" tv_sec sys/select.h HAVE_TIMEVAL_TV_SEC_K LANGUAGE FORTRAN)

View File

@ -0,0 +1,8 @@
CMake Error at .*/Modules/CheckStructHasMember.cmake:[0-9]+. \(message\):
Unknown arguments:
LANGUAG;C
Call Stack \(most recent call first\):
CheckStructHasMemberWrongKey.cmake:[0-9]+ \(check_struct_has_member\)
CMakeLists.txt:[0-9]+ \(include\)

View File

@ -0,0 +1,2 @@
include(CheckStructHasMember)
check_struct_has_member("struct timeval" tv_sec sys/select.h HAVE_TIMEVAL_TV_SEC_K LANGUAG C)

View File

@ -0,0 +1,8 @@
include(RunCMake)
run_cmake(CheckStructHasMemberOk)
run_cmake(CheckStructHasMemberUnknownLanguage)
run_cmake(CheckStructHasMemberMissingLanguage)
run_cmake(CheckStructHasMemberMissingKey)
run_cmake(CheckStructHasMemberTooManyArguments)
run_cmake(CheckStructHasMemberWrongKey)