From 357e2ef429b5245de4f2f5fc7ba7b8089d90bb1c Mon Sep 17 00:00:00 2001 From: Robert Maynard Date: Mon, 14 Sep 2020 13:26:43 -0400 Subject: CheckSoureRuns: Add a unified way to check if a source runs --- Help/manual/cmake-modules.7.rst | 1 + Help/module/CheckSourceRuns.rst | 1 + Help/release/dev/check-source-modules.rst | 4 + Modules/CheckCSourceRuns.cmake | 77 +------- Modules/CheckCXXSourceRuns.cmake | 77 +------- Modules/CheckFortranSourceRuns.cmake | 89 +-------- Modules/CheckOBJCSourceRuns.cmake | 77 +------- Modules/CheckOBJCXXSourceRuns.cmake | 77 +------- Modules/CheckSourceRuns.cmake | 202 +++++++++++++++++++++ Tests/RunCMake/CMakeLists.txt | 1 + Tests/RunCMake/CheckSourceRuns/CMakeLists.txt | 5 + .../CheckSourceRuns/CheckCSourceRuns.cmake | 13 ++ .../CheckSourceRuns/CheckCXXSourceRuns.cmake | 20 ++ .../CheckSourceRuns/CheckFortranSourceRuns.cmake | 14 ++ .../CheckSourceRuns/CheckOBJCSourceRuns.cmake | 14 ++ .../CheckSourceRuns/CheckOBJCXXSourceRuns.cmake | 17 ++ .../CheckSourceRuns/NonExistentLanguage-result.txt | 1 + .../CheckSourceRuns/NonExistentLanguage-stderr.txt | 2 + .../CheckSourceRuns/NonExistentLanguage.cmake | 3 + .../CheckSourceRuns/NotEnabledLanguage-result.txt | 1 + .../CheckSourceRuns/NotEnabledLanguage-stderr.txt | 2 + .../CheckSourceRuns/NotEnabledLanguage.cmake | 3 + Tests/RunCMake/CheckSourceRuns/RunCMakeTest.cmake | 16 ++ 23 files changed, 330 insertions(+), 387 deletions(-) create mode 100644 Help/module/CheckSourceRuns.rst create mode 100644 Modules/CheckSourceRuns.cmake create mode 100644 Tests/RunCMake/CheckSourceRuns/CMakeLists.txt create mode 100644 Tests/RunCMake/CheckSourceRuns/CheckCSourceRuns.cmake create mode 100644 Tests/RunCMake/CheckSourceRuns/CheckCXXSourceRuns.cmake create mode 100644 Tests/RunCMake/CheckSourceRuns/CheckFortranSourceRuns.cmake create mode 100644 Tests/RunCMake/CheckSourceRuns/CheckOBJCSourceRuns.cmake create mode 100644 Tests/RunCMake/CheckSourceRuns/CheckOBJCXXSourceRuns.cmake create mode 100644 Tests/RunCMake/CheckSourceRuns/NonExistentLanguage-result.txt create mode 100644 Tests/RunCMake/CheckSourceRuns/NonExistentLanguage-stderr.txt create mode 100644 Tests/RunCMake/CheckSourceRuns/NonExistentLanguage.cmake create mode 100644 Tests/RunCMake/CheckSourceRuns/NotEnabledLanguage-result.txt create mode 100644 Tests/RunCMake/CheckSourceRuns/NotEnabledLanguage-stderr.txt create mode 100644 Tests/RunCMake/CheckSourceRuns/NotEnabledLanguage.cmake create mode 100644 Tests/RunCMake/CheckSourceRuns/RunCMakeTest.cmake diff --git a/Help/manual/cmake-modules.7.rst b/Help/manual/cmake-modules.7.rst index d206193..d364198 100644 --- a/Help/manual/cmake-modules.7.rst +++ b/Help/manual/cmake-modules.7.rst @@ -46,6 +46,7 @@ These modules are loaded using the :command:`include` command. /module/CheckPIESupported /module/CheckPrototypeDefinition /module/CheckSourceCompiles + /module/CheckSourceRuns /module/CheckStructHasMember /module/CheckSymbolExists /module/CheckTypeSize diff --git a/Help/module/CheckSourceRuns.rst b/Help/module/CheckSourceRuns.rst new file mode 100644 index 0000000..d469244 --- /dev/null +++ b/Help/module/CheckSourceRuns.rst @@ -0,0 +1 @@ +.. cmake-module:: ../../Modules/CheckSourceRuns.cmake diff --git a/Help/release/dev/check-source-modules.rst b/Help/release/dev/check-source-modules.rst index a98ed03..9a7785a 100644 --- a/Help/release/dev/check-source-modules.rst +++ b/Help/release/dev/check-source-modules.rst @@ -4,3 +4,7 @@ check-source-modules * The :module:`CheckSourceCompiles` module has been added to generalize :module:`CheckCSourceCompiles` and :module:`CheckCXXSourceCompiles` to more languages. + +* The :module:`CheckSourceRuns` module has been added to + generalize :module:`CheckCSourceRuns` and + :module:`CheckCXXSourceRuns` to more languages. diff --git a/Modules/CheckCSourceRuns.cmake b/Modules/CheckCSourceRuns.cmake index 7d116db..86ad248 100644 --- a/Modules/CheckCSourceRuns.cmake +++ b/Modules/CheckCSourceRuns.cmake @@ -65,81 +65,8 @@ subsequently be run. #]=======================================================================] include_guard(GLOBAL) +include(CheckSourceRuns) macro(CHECK_C_SOURCE_RUNS SOURCE VAR) - if(NOT DEFINED "${VAR}") - set(MACRO_CHECK_FUNCTION_DEFINITIONS - "-D${VAR} ${CMAKE_REQUIRED_FLAGS}") - if(CMAKE_REQUIRED_LINK_OPTIONS) - set(CHECK_C_SOURCE_COMPILES_ADD_LINK_OPTIONS - LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS}) - else() - set(CHECK_C_SOURCE_COMPILES_ADD_LINK_OPTIONS) - endif() - if(CMAKE_REQUIRED_LIBRARIES) - set(CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES - LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) - else() - set(CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES) - endif() - if(CMAKE_REQUIRED_INCLUDES) - set(CHECK_C_SOURCE_COMPILES_ADD_INCLUDES - "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}") - else() - set(CHECK_C_SOURCE_COMPILES_ADD_INCLUDES) - endif() - file(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c" - "${SOURCE}\n") - - if(NOT CMAKE_REQUIRED_QUIET) - message(CHECK_START "Performing Test ${VAR}") - endif() - try_run(${VAR}_EXITCODE ${VAR}_COMPILED - ${CMAKE_BINARY_DIR} - ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c - COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} - ${CHECK_C_SOURCE_COMPILES_ADD_LINK_OPTIONS} - ${CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES} - CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS} - -DCMAKE_SKIP_RPATH:BOOL=${CMAKE_SKIP_RPATH} - "${CHECK_C_SOURCE_COMPILES_ADD_INCLUDES}" - COMPILE_OUTPUT_VARIABLE OUTPUT - RUN_OUTPUT_VARIABLE RUN_OUTPUT) - # if it did not compile make the return value fail code of 1 - if(NOT ${VAR}_COMPILED) - set(${VAR}_EXITCODE 1) - endif() - # if the return value was 0 then it worked - if("${${VAR}_EXITCODE}" EQUAL 0) - set(${VAR} 1 CACHE INTERNAL "Test ${VAR}") - if(NOT CMAKE_REQUIRED_QUIET) - message(CHECK_PASS "Success") - endif() - file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log - "Performing C SOURCE FILE Test ${VAR} succeeded with the following compile output:\n" - "${OUTPUT}\n" - "...and run output:\n" - "${RUN_OUTPUT}\n" - "Return value: ${${VAR}}\n" - "Source file was:\n${SOURCE}\n") - else() - if(CMAKE_CROSSCOMPILING AND "${${VAR}_EXITCODE}" MATCHES "FAILED_TO_RUN") - set(${VAR} "${${VAR}_EXITCODE}") - else() - set(${VAR} "" CACHE INTERNAL "Test ${VAR}") - endif() - - if(NOT CMAKE_REQUIRED_QUIET) - message(CHECK_FAIL "Failed") - endif() - file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log - "Performing C SOURCE FILE Test ${VAR} failed with the following compile output:\n" - "${OUTPUT}\n" - "...and run output:\n" - "${RUN_OUTPUT}\n" - "Return value: ${${VAR}_EXITCODE}\n" - "Source file was:\n${SOURCE}\n") - - endif() - endif() + check_source_runs(C "${SOURCE}" ${VAR} ${ARGN}) endmacro() diff --git a/Modules/CheckCXXSourceRuns.cmake b/Modules/CheckCXXSourceRuns.cmake index 408e183..70511ee 100644 --- a/Modules/CheckCXXSourceRuns.cmake +++ b/Modules/CheckCXXSourceRuns.cmake @@ -65,81 +65,8 @@ subsequently be run. #]=======================================================================] include_guard(GLOBAL) +include(CheckSourceRuns) macro(CHECK_CXX_SOURCE_RUNS SOURCE VAR) - if(NOT DEFINED "${VAR}") - set(MACRO_CHECK_FUNCTION_DEFINITIONS - "-D${VAR} ${CMAKE_REQUIRED_FLAGS}") - if(CMAKE_REQUIRED_LINK_OPTIONS) - set(CHECK_CXX_SOURCE_COMPILES_ADD_LINK_OPTIONS - LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS}) - else() - set(CHECK_CXX_SOURCE_COMPILES_ADD_LINK_OPTIONS) - endif() - if(CMAKE_REQUIRED_LIBRARIES) - set(CHECK_CXX_SOURCE_COMPILES_ADD_LIBRARIES - LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) - else() - set(CHECK_CXX_SOURCE_COMPILES_ADD_LIBRARIES) - endif() - if(CMAKE_REQUIRED_INCLUDES) - set(CHECK_CXX_SOURCE_COMPILES_ADD_INCLUDES - "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}") - else() - set(CHECK_CXX_SOURCE_COMPILES_ADD_INCLUDES) - endif() - file(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.cxx" - "${SOURCE}\n") - - if(NOT CMAKE_REQUIRED_QUIET) - message(CHECK_START "Performing Test ${VAR}") - endif() - try_run(${VAR}_EXITCODE ${VAR}_COMPILED - ${CMAKE_BINARY_DIR} - ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.cxx - COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} - ${CHECK_CXX_SOURCE_COMPILES_ADD_LINK_OPTIONS} - ${CHECK_CXX_SOURCE_COMPILES_ADD_LIBRARIES} - CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS} - -DCMAKE_SKIP_RPATH:BOOL=${CMAKE_SKIP_RPATH} - "${CHECK_CXX_SOURCE_COMPILES_ADD_INCLUDES}" - COMPILE_OUTPUT_VARIABLE OUTPUT - RUN_OUTPUT_VARIABLE RUN_OUTPUT) - - # if it did not compile make the return value fail code of 1 - if(NOT ${VAR}_COMPILED) - set(${VAR}_EXITCODE 1) - endif() - # if the return value was 0 then it worked - if("${${VAR}_EXITCODE}" EQUAL 0) - set(${VAR} 1 CACHE INTERNAL "Test ${VAR}") - if(NOT CMAKE_REQUIRED_QUIET) - message(CHECK_PASS "Success") - endif() - file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log - "Performing C++ SOURCE FILE Test ${VAR} succeeded with the following output:\n" - "${OUTPUT}\n" - "...and run output:\n" - "${RUN_OUTPUT}\n" - "Return value: ${${VAR}}\n" - "Source file was:\n${SOURCE}\n") - else() - if(CMAKE_CROSSCOMPILING AND "${${VAR}_EXITCODE}" MATCHES "FAILED_TO_RUN") - set(${VAR} "${${VAR}_EXITCODE}") - else() - set(${VAR} "" CACHE INTERNAL "Test ${VAR}") - endif() - - if(NOT CMAKE_REQUIRED_QUIET) - message(CHECK_FAIL "Failed") - endif() - file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log - "Performing C++ SOURCE FILE Test ${VAR} failed with the following output:\n" - "${OUTPUT}\n" - "...and run output:\n" - "${RUN_OUTPUT}\n" - "Return value: ${${VAR}_EXITCODE}\n" - "Source file was:\n${SOURCE}\n") - endif() - endif() + check_source_runs(CXX "${SOURCE}" ${VAR} ${ARGN}) endmacro() diff --git a/Modules/CheckFortranSourceRuns.cmake b/Modules/CheckFortranSourceRuns.cmake index a710352..29f4a98 100644 --- a/Modules/CheckFortranSourceRuns.cmake +++ b/Modules/CheckFortranSourceRuns.cmake @@ -83,93 +83,8 @@ subsequently be run. #]=======================================================================] include_guard(GLOBAL) +include(CheckSourceRuns) macro(CHECK_Fortran_SOURCE_RUNS SOURCE VAR) - if(NOT DEFINED "${VAR}") - set(_SRC_EXT) - set(_key) - foreach(arg ${ARGN}) - if("${arg}" MATCHES "^(SRC_EXT)$") - set(_key "${arg}") - elseif(_key) - list(APPEND _${_key} "${arg}") - else() - message(FATAL_ERROR "Unknown argument:\n ${arg}\n") - endif() - endforeach() - if(NOT _SRC_EXT) - set(_SRC_EXT F90) - endif() - if(CMAKE_REQUIRED_LINK_OPTIONS) - set(CHECK_Fortran_SOURCE_COMPILES_ADD_LINK_OPTIONS - LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS}) - else() - set(CHECK_Fortran_SOURCE_COMPILES_ADD_LINK_OPTIONS) - endif() - if(CMAKE_REQUIRED_LIBRARIES) - set(CHECK_Fortran_SOURCE_COMPILES_ADD_LIBRARIES - LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) - else() - set(CHECK_Fortran_SOURCE_COMPILES_ADD_LIBRARIES) - endif() - if(CMAKE_REQUIRED_INCLUDES) - set(CHECK_Fortran_SOURCE_COMPILES_ADD_INCLUDES - "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}") - else() - set(CHECK_Fortran_SOURCE_COMPILES_ADD_INCLUDES) - endif() - file(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.${_SRC_EXT}" - "${SOURCE}\n") - - if(NOT CMAKE_REQUIRED_QUIET) - message(CHECK_START "Performing Test ${VAR}") - endif() - try_run(${VAR}_EXITCODE ${VAR}_COMPILED - ${CMAKE_BINARY_DIR} - ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.${_SRC_EXT} - COMPILE_DEFINITIONS -D${VAR} ${CMAKE_REQUIRED_DEFINITIONS} - ${CHECK_Fortran_SOURCE_COMPILES_ADD_LINK_OPTIONS} - ${CHECK_Fortran_SOURCE_COMPILES_ADD_LIBRARIES} - CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${CMAKE_REQUIRED_FLAGS} - -DCMAKE_SKIP_RPATH:BOOL=${CMAKE_SKIP_RPATH} - "${CHECK_Fortran_SOURCE_COMPILES_ADD_INCLUDES}" - COMPILE_OUTPUT_VARIABLE OUTPUT - RUN_OUTPUT_VARIABLE RUN_OUTPUT) - - # if it did not compile make the return value fail code of 1 - if(NOT ${VAR}_COMPILED) - set(${VAR}_EXITCODE 1) - endif() - # if the return value was 0 then it worked - if("${${VAR}_EXITCODE}" EQUAL 0) - set(${VAR} 1 CACHE INTERNAL "Test ${VAR}") - if(NOT CMAKE_REQUIRED_QUIET) - message(CHECK_PASS "Success") - endif() - file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log - "Performing Fortran SOURCE FILE Test ${VAR} succeeded with the following output:\n" - "${OUTPUT}\n" - "...and run output:\n" - "${RUN_OUTPUT}\n" - "Return value: ${${VAR}}\n" - "Source file was:\n${SOURCE}\n") - else() - if(CMAKE_CROSSCOMPILING AND "${${VAR}_EXITCODE}" MATCHES "FAILED_TO_RUN") - set(${VAR} "${${VAR}_EXITCODE}") - else() - set(${VAR} "" CACHE INTERNAL "Test ${VAR}") - endif() - - if(NOT CMAKE_REQUIRED_QUIET) - message(CHECK_FAIL "Failed") - endif() - file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log - "Performing Fortran SOURCE FILE Test ${VAR} failed with the following output:\n" - "${OUTPUT}\n" - "...and run output:\n" - "${RUN_OUTPUT}\n" - "Return value: ${${VAR}_EXITCODE}\n" - "Source file was:\n${SOURCE}\n") - endif() - endif() + check_source_runs(Fortran "${SOURCE}" ${VAR} ${ARGN}) endmacro() diff --git a/Modules/CheckOBJCSourceRuns.cmake b/Modules/CheckOBJCSourceRuns.cmake index 9d4fb1b..dadab21 100644 --- a/Modules/CheckOBJCSourceRuns.cmake +++ b/Modules/CheckOBJCSourceRuns.cmake @@ -67,81 +67,8 @@ subsequently be run. #]=======================================================================] include_guard(GLOBAL) +include(CheckSourceRuns) macro(CHECK_OBJC_SOURCE_RUNS SOURCE VAR) - if(NOT DEFINED "${VAR}") - set(MACRO_CHECK_FUNCTION_DEFINITIONS - "-D${VAR} ${CMAKE_REQUIRED_FLAGS}") - if(CMAKE_REQUIRED_LINK_OPTIONS) - set(CHECK_OBJC_SOURCE_COMPILES_ADD_LINK_OPTIONS - LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS}) - else() - set(CHECK_OBJC_SOURCE_COMPILES_ADD_LINK_OPTIONS) - endif() - if(CMAKE_REQUIRED_LIBRARIES) - set(CHECK_OBJC_SOURCE_COMPILES_ADD_LIBRARIES - LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) - else() - set(CHECK_OBJC_SOURCE_COMPILES_ADD_LIBRARIES) - endif() - if(CMAKE_REQUIRED_INCLUDES) - set(CHECK_OBJC_SOURCE_COMPILES_ADD_INCLUDES - "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}") - else() - set(CHECK_OBJC_SOURCE_COMPILES_ADD_INCLUDES) - endif() - file(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.m" - "${SOURCE}\n") - - if(NOT CMAKE_REQUIRED_QUIET) - message(CHECK_START "Performing Test ${VAR}") - endif() - try_run(${VAR}_EXITCODE ${VAR}_COMPILED - ${CMAKE_BINARY_DIR} - ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.m - COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} - ${CHECK_OBJC_SOURCE_COMPILES_ADD_LINK_OPTIONS} - ${CHECK_OBJC_SOURCE_COMPILES_ADD_LIBRARIES} - CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS} - -DCMAKE_SKIP_RPATH:BOOL=${CMAKE_SKIP_RPATH} - "${CHECK_OBJC_SOURCE_COMPILES_ADD_INCLUDES}" - COMPILE_OUTPUT_VARIABLE OUTPUT - RUN_OUTPUT_VARIABLE RUN_OUTPUT) - # if it did not compile make the return value fail code of 1 - if(NOT ${VAR}_COMPILED) - set(${VAR}_EXITCODE 1) - endif() - # if the return value was 0 then it worked - if("${${VAR}_EXITCODE}" EQUAL 0) - set(${VAR} 1 CACHE INTERNAL "Test ${VAR}") - if(NOT CMAKE_REQUIRED_QUIET) - message(CHECK_PASS "Success") - endif() - file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log - "Performing Objective-C SOURCE FILE Test ${VAR} succeeded with the following compile output:\n" - "${OUTPUT}\n" - "...and run output:\n" - "${RUN_OUTPUT}\n" - "Return value: ${${VAR}}\n" - "Source file was:\n${SOURCE}\n") - else() - if(CMAKE_CROSSCOMPILING AND "${${VAR}_EXITCODE}" MATCHES "FAILED_TO_RUN") - set(${VAR} "${${VAR}_EXITCODE}") - else() - set(${VAR} "" CACHE INTERNAL "Test ${VAR}") - endif() - - if(NOT CMAKE_REQUIRED_QUIET) - message(CHECK_FAIL "Failed") - endif() - file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log - "Performing Objective-C SOURCE FILE Test ${VAR} failed with the following compile output:\n" - "${OUTPUT}\n" - "...and run output:\n" - "${RUN_OUTPUT}\n" - "Return value: ${${VAR}_EXITCODE}\n" - "Source file was:\n${SOURCE}\n") - - endif() - endif() + check_source_runs(OBJC "${SOURCE}" ${VAR} ${ARGN}) endmacro() diff --git a/Modules/CheckOBJCXXSourceRuns.cmake b/Modules/CheckOBJCXXSourceRuns.cmake index c327598..200e799 100644 --- a/Modules/CheckOBJCXXSourceRuns.cmake +++ b/Modules/CheckOBJCXXSourceRuns.cmake @@ -67,81 +67,8 @@ subsequently be run. #]=======================================================================] include_guard(GLOBAL) +include(CheckSourceRuns) macro(CHECK_OBJCXX_SOURCE_RUNS SOURCE VAR) - if(NOT DEFINED "${VAR}") - set(MACRO_CHECK_FUNCTION_DEFINITIONS - "-D${VAR} ${CMAKE_REQUIRED_FLAGS}") - if(CMAKE_REQUIRED_LINK_OPTIONS) - set(CHECK_OBJCXX_SOURCE_COMPILES_ADD_LINK_OPTIONS - LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS}) - else() - set(CHECK_OBJCXX_SOURCE_COMPILES_ADD_LINK_OPTIONS) - endif() - if(CMAKE_REQUIRED_LIBRARIES) - set(CHECK_OBJCXX_SOURCE_COMPILES_ADD_LIBRARIES - LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) - else() - set(CHECK_OBJCXX_SOURCE_COMPILES_ADD_LIBRARIES) - endif() - if(CMAKE_REQUIRED_INCLUDES) - set(CHECK_OBJCXX_SOURCE_COMPILES_ADD_INCLUDES - "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}") - else() - set(CHECK_OBJCXX_SOURCE_COMPILES_ADD_INCLUDES) - endif() - file(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.mm" - "${SOURCE}\n") - - if(NOT CMAKE_REQUIRED_QUIET) - message(CHECK_START "Performing Test ${VAR}") - endif() - try_run(${VAR}_EXITCODE ${VAR}_COMPILED - ${CMAKE_BINARY_DIR} - ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.mm - COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} - ${CHECK_OBJCXX_SOURCE_COMPILES_ADD_LINK_OPTIONS} - ${CHECK_OBJCXX_SOURCE_COMPILES_ADD_LIBRARIES} - CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS} - -DCMAKE_SKIP_RPATH:BOOL=${CMAKE_SKIP_RPATH} - "${CHECK_OBJCXX_SOURCE_COMPILES_ADD_INCLUDES}" - COMPILE_OUTPUT_VARIABLE OUTPUT - RUN_OUTPUT_VARIABLE RUN_OUTPUT) - - # if it did not compile make the return value fail code of 1 - if(NOT ${VAR}_COMPILED) - set(${VAR}_EXITCODE 1) - endif() - # if the return value was 0 then it worked - if("${${VAR}_EXITCODE}" EQUAL 0) - set(${VAR} 1 CACHE INTERNAL "Test ${VAR}") - if(NOT CMAKE_REQUIRED_QUIET) - message(CHECK_PASS "Success") - endif() - file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log - "Performing Objective-C++ SOURCE FILE Test ${VAR} succeeded with the following output:\n" - "${OUTPUT}\n" - "...and run output:\n" - "${RUN_OUTPUT}\n" - "Return value: ${${VAR}}\n" - "Source file was:\n${SOURCE}\n") - else() - if(CMAKE_CROSSCOMPILING AND "${${VAR}_EXITCODE}" MATCHES "FAILED_TO_RUN") - set(${VAR} "${${VAR}_EXITCODE}") - else() - set(${VAR} "" CACHE INTERNAL "Test ${VAR}") - endif() - - if(NOT CMAKE_REQUIRED_QUIET) - message(CHECK_FAIL "Failed") - endif() - file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log - "Performing Objective-C++ SOURCE FILE Test ${VAR} failed with the following output:\n" - "${OUTPUT}\n" - "...and run output:\n" - "${RUN_OUTPUT}\n" - "Return value: ${${VAR}_EXITCODE}\n" - "Source file was:\n${SOURCE}\n") - endif() - endif() + check_source_runs(OBJCXX "${SOURCE}" ${VAR} ${ARGN}) endmacro() diff --git a/Modules/CheckSourceRuns.cmake b/Modules/CheckSourceRuns.cmake new file mode 100644 index 0000000..6165123 --- /dev/null +++ b/Modules/CheckSourceRuns.cmake @@ -0,0 +1,202 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + + +#[=======================================================================[.rst: +CheckSourceRuns +------------------- + +.. versionadded:: 3.19 + +Check if given source compiles and links into an executable and can +subsequently be run. + +.. command:: check_source_runs + + .. code-block:: cmake + + check_source_runs( + [SRC_EXT ]) + + Check that the source supplied in ```` can be compiled as a source + file for the requested language, linked as an executable and then run. + The ```` must contain at least a ``main()`` function. If the ```` + could be built and run successfully, the internal cache variable specified by + ```` will be set to 1, otherwise it will be set to an value that + evaluates to boolean false (e.g. an empty string or an error message). + + By default, the test source file will be given a file extension that matches + the requested language. The ``SRC_EXT`` option can be used to override this + with ``.`` instead. + + The underlying check is performed by the :command:`try_run` command. The + compile and link commands can be influenced by setting any of the following + variables prior to calling ``check_objc_source_runs()``: + + ``CMAKE_REQUIRED_FLAGS`` + Additional flags to pass to the compiler. Note that the contents of + :variable:`CMAKE_OBJC_FLAGS _FLAGS>` and its associated + configuration-specific variable are automatically added to the compiler + command before the contents of ``CMAKE_REQUIRED_FLAGS``. + + ``CMAKE_REQUIRED_DEFINITIONS`` + A :ref:`;-list ` of compiler definitions of the form + ``-DFOO`` or ``-DFOO=bar``. A definition for the name specified by + ```` will also be added automatically. + + ``CMAKE_REQUIRED_INCLUDES`` + A :ref:`;-list ` of header search paths to pass to + the compiler. These will be the only header search paths used by + ``try_run()``, i.e. the contents of the :prop_dir:`INCLUDE_DIRECTORIES` + directory property will be ignored. + + ``CMAKE_REQUIRED_LINK_OPTIONS`` + A :ref:`;-list ` of options to add to the link + command (see :command:`try_run` for further details). + + ``CMAKE_REQUIRED_LIBRARIES`` + A :ref:`;-list ` of libraries to add to the link + command. These can be the name of system libraries or they can be + :ref:`Imported Targets ` (see :command:`try_run` for + further details). + + ``CMAKE_REQUIRED_QUIET`` + If this variable evaluates to a boolean true value, all status messages + associated with the check will be suppressed. + + The check is only performed once, with the result cached in the variable + named by ````. Every subsequent CMake run will re-use this cached + value rather than performing the check again, even if the ```` changes. + In order to force the check to be re-evaluated, the variable named by + ```` must be manually removed from the cache. + +#]=======================================================================] + +include_guard(GLOBAL) + +cmake_policy(PUSH) +cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced +cmake_policy(SET CMP0057 NEW) # if() supports IN_LIST + +function(CHECK_SOURCE_RUNS _lang _source _var) + if(NOT DEFINED "${_var}") + + if(_lang STREQUAL C) + set(_lang_textual "C") + set(_lang_ext "c") + elseif(_lang STREQUAL CXX) + set(_lang_textual "C++") + set(_lang_ext "cxx") + elseif(_lang STREQUAL Fortran) + set(_lang_textual "Fortran") + set(_lang_ext "F") + elseif(_lang STREQUAL OBJC) + set(_lang_textual "Objective-C") + set(_lang_ext "m") + elseif(_lang STREQUAL OBJCXX) + set(_lang_textual "Objective-C++") + set(_lang_ext "mm") + else() + message (SEND_ERROR "check_source_runs: ${_lang}: unknown language.") + return() + endif() + + get_property (_supported_languages GLOBAL PROPERTY ENABLED_LANGUAGES) + if (NOT _lang IN_LIST _supported_languages) + message (SEND_ERROR "check_source_runs: ${_lang}: needs to be enabled before use.") + return() + endif() + + set(_FAIL_REGEX) + set(_SRC_EXT) + set(_key) + foreach(arg ${ARGN}) + if("${arg}" MATCHES "^(SRC_EXT)$") + set(_key "${arg}") + elseif(_key) + list(APPEND _${_key} "${arg}") + else() + message(FATAL_ERROR "Unknown argument:\n ${arg}\n") + endif() + endforeach() + + if(NOT _SRC_EXT) + set(_SRC_EXT ${_lang_ext}) + endif() + + if(CMAKE_REQUIRED_LINK_OPTIONS) + set(CHECK_${_lang}_SOURCE_COMPILES_ADD_LINK_OPTIONS + LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS}) + else() + set(CHECK_${_lang}_SOURCE_COMPILES_ADD_LINK_OPTIONS) + endif() + if(CMAKE_REQUIRED_LIBRARIES) + set(CHECK_${_lang}_SOURCE_COMPILES_ADD_LIBRARIES + LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) + else() + set(CHECK_${_lang}_SOURCE_COMPILES_ADD_LIBRARIES) + endif() + if(CMAKE_REQUIRED_INCLUDES) + set(CHECK_${_lang}_SOURCE_COMPILES_ADD_INCLUDES + "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}") + else() + set(CHECK_${_lang}_SOURCE_COMPILES_ADD_INCLUDES) + endif() + file(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.${_SRC_EXT}" + "${_source}\n") + + if(NOT CMAKE_REQUIRED_QUIET) + message(CHECK_START "Performing Test ${_var}") + endif() + try_run(${_var}_EXITCODE ${_var}_COMPILED + ${CMAKE_BINARY_DIR} + ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.${_SRC_EXT} + COMPILE_DEFINITIONS -D${_var} ${CMAKE_REQUIRED_DEFINITIONS} + ${CHECK_${_lang}_SOURCE_COMPILES_ADD_LINK_OPTIONS} + ${CHECK_${_lang}_SOURCE_COMPILES_ADD_LIBRARIES} + CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${CMAKE_REQUIRED_FLAGS} + -DCMAKE_SKIP_RPATH:BOOL=${CMAKE_SKIP_RPATH} + "${CHECK_${_lang}_SOURCE_COMPILES_ADD_INCLUDES}" + COMPILE_OUTPUT_VARIABLE OUTPUT + RUN_OUTPUT_VARIABLE RUN_OUTPUT) + # if it did not compile make the return value fail code of 1 + if(NOT ${_var}_COMPILED) + set(${_var}_EXITCODE 1) + set(${_var}_EXITCODE 1 PARENT_SCOPE) + endif() + # if the return value was 0 then it worked + if("${${_var}_EXITCODE}" EQUAL 0) + set(${_var} 1 CACHE INTERNAL "Test ${_var}") + if(NOT CMAKE_REQUIRED_QUIET) + message(CHECK_PASS "Success") + endif() + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "Performing ${_lang_textual} SOURCE FILE Test ${_var} succeeded with the following compile output:\n" + "${OUTPUT}\n" + "...and run output:\n" + "${RUN_OUTPUT}\n" + "Return value: ${${_var}}\n" + "Source file was:\n${_source}\n") + else() + if(CMAKE_CROSSCOMPILING AND "${${_var}_EXITCODE}" MATCHES "FAILED_TO_RUN") + set(${_var} "${${_var}_EXITCODE}" PARENT_SCOPE) + else() + set(${_var} "" CACHE INTERNAL "Test ${_var}") + endif() + + if(NOT CMAKE_REQUIRED_QUIET) + message(CHECK_FAIL "Failed") + endif() + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "Performing ${_lang_textual} SOURCE FILE Test ${_var} failed with the following compile output:\n" + "${OUTPUT}\n" + "...and run output:\n" + "${RUN_OUTPUT}\n" + "Return value: ${${_var}_EXITCODE}\n" + "Source file was:\n${_source}\n") + + endif() + endif() +endfunction() + +cmake_policy(POP) diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index a8b76b4..c97a959 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -535,6 +535,7 @@ add_RunCMake_test(target_compile_options -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILE add_RunCMake_test(target_include_directories) add_RunCMake_test(target_sources) add_RunCMake_test(CheckSourceCompiles) +add_RunCMake_test(CheckSourceRuns) add_RunCMake_test(CheckModules) add_RunCMake_test(CheckIPOSupported) if (CMAKE_SYSTEM_NAME MATCHES "(Linux|Darwin)" diff --git a/Tests/RunCMake/CheckSourceRuns/CMakeLists.txt b/Tests/RunCMake/CheckSourceRuns/CMakeLists.txt new file mode 100644 index 0000000..0421e28 --- /dev/null +++ b/Tests/RunCMake/CheckSourceRuns/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.13) + +project(${RunCMake_TEST} LANGUAGES NONE) + +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/CheckSourceRuns/CheckCSourceRuns.cmake b/Tests/RunCMake/CheckSourceRuns/CheckCSourceRuns.cmake new file mode 100644 index 0000000..3029ac2 --- /dev/null +++ b/Tests/RunCMake/CheckSourceRuns/CheckCSourceRuns.cmake @@ -0,0 +1,13 @@ + +enable_language (C) +include(CheckSourceRuns) + +check_source_runs(C "int main() {return 2;}" SHOULD_FAIL) +if(SHOULD_FAIL) + message(SEND_ERROR "C check_source_runs succeeded, but should have failed.") +endif() + +check_source_runs(C "int main() {return 0;}" SHOULD_RUN) +if(NOT SHOULD_RUN) + message(SEND_ERROR "C check_source_runs failed for valid C executable.") +endif() diff --git a/Tests/RunCMake/CheckSourceRuns/CheckCXXSourceRuns.cmake b/Tests/RunCMake/CheckSourceRuns/CheckCXXSourceRuns.cmake new file mode 100644 index 0000000..d47ddda --- /dev/null +++ b/Tests/RunCMake/CheckSourceRuns/CheckCXXSourceRuns.cmake @@ -0,0 +1,20 @@ + +enable_language (CXX) +include(CheckSourceRuns) + +check_source_runs(CXX "int main() {return 2;}" SHOULD_FAIL) +if(SHOULD_FAIL) + message(SEND_ERROR "CXX check_source_runs succeeded, but should have failed.") +endif() + +check_source_runs(CXX +[=[ + #include + int main() { + return 0; + } +]=] + SHOULD_RUN) +if(NOT SHOULD_RUN) + message(SEND_ERROR "CXX check_source_runs failed for valid C executable.") +endif() diff --git a/Tests/RunCMake/CheckSourceRuns/CheckFortranSourceRuns.cmake b/Tests/RunCMake/CheckSourceRuns/CheckFortranSourceRuns.cmake new file mode 100644 index 0000000..2a1fdfe --- /dev/null +++ b/Tests/RunCMake/CheckSourceRuns/CheckFortranSourceRuns.cmake @@ -0,0 +1,14 @@ + + +enable_language (Fortran) +include(CheckSourceRuns) + +check_source_runs(Fortran [=[ + PROGRAM TEST_HAVE_PRINT + PRINT *, 'Hello' + END +]=] SHOULD_BUILD) + +if(NOT SHOULD_BUILD) + message(SEND_ERROR "Test fail for valid Fortran source.") +endif() diff --git a/Tests/RunCMake/CheckSourceRuns/CheckOBJCSourceRuns.cmake b/Tests/RunCMake/CheckSourceRuns/CheckOBJCSourceRuns.cmake new file mode 100644 index 0000000..55f28f3 --- /dev/null +++ b/Tests/RunCMake/CheckSourceRuns/CheckOBJCSourceRuns.cmake @@ -0,0 +1,14 @@ +enable_language (OBJC) +include(CheckSourceRuns) + +check_source_runs(OBJC [[ + #import + int main() { + NSObject *foo; + return 0; + } +]] SHOULD_BUILD) + +if(NOT SHOULD_BUILD) + message(SEND_ERROR "Test fail for valid OBJC source.") +endif() diff --git a/Tests/RunCMake/CheckSourceRuns/CheckOBJCXXSourceRuns.cmake b/Tests/RunCMake/CheckSourceRuns/CheckOBJCXXSourceRuns.cmake new file mode 100644 index 0000000..a218acd --- /dev/null +++ b/Tests/RunCMake/CheckSourceRuns/CheckOBJCXXSourceRuns.cmake @@ -0,0 +1,17 @@ +enable_language (OBJCXX) +include(CheckSourceRuns) + +check_source_runs(OBJCXX [[ + #include + #import + int main() { + std::vector v; + NSObject *foo; + return 0; + } +]] SHOULD_BUILD) + + +if(NOT SHOULD_BUILD) + message(SEND_ERROR "Test fail for OBJCXX source.") +endif() diff --git a/Tests/RunCMake/CheckSourceRuns/NonExistentLanguage-result.txt b/Tests/RunCMake/CheckSourceRuns/NonExistentLanguage-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CheckSourceRuns/NonExistentLanguage-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CheckSourceRuns/NonExistentLanguage-stderr.txt b/Tests/RunCMake/CheckSourceRuns/NonExistentLanguage-stderr.txt new file mode 100644 index 0000000..08ffc2d --- /dev/null +++ b/Tests/RunCMake/CheckSourceRuns/NonExistentLanguage-stderr.txt @@ -0,0 +1,2 @@ +CMake Error at .*CheckSourceRuns\.cmake:[0-9]+ \(message\): + check_source_runs: FAKE_LANG: unknown language. diff --git a/Tests/RunCMake/CheckSourceRuns/NonExistentLanguage.cmake b/Tests/RunCMake/CheckSourceRuns/NonExistentLanguage.cmake new file mode 100644 index 0000000..8300740 --- /dev/null +++ b/Tests/RunCMake/CheckSourceRuns/NonExistentLanguage.cmake @@ -0,0 +1,3 @@ + +include(CheckSourceRuns) +check_source_runs(FAKE_LANG "int main() {return 0;}" SHOULD_BUILD) diff --git a/Tests/RunCMake/CheckSourceRuns/NotEnabledLanguage-result.txt b/Tests/RunCMake/CheckSourceRuns/NotEnabledLanguage-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CheckSourceRuns/NotEnabledLanguage-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CheckSourceRuns/NotEnabledLanguage-stderr.txt b/Tests/RunCMake/CheckSourceRuns/NotEnabledLanguage-stderr.txt new file mode 100644 index 0000000..b590763 --- /dev/null +++ b/Tests/RunCMake/CheckSourceRuns/NotEnabledLanguage-stderr.txt @@ -0,0 +1,2 @@ +CMake Error at .*CheckSourceRuns\.cmake:[0-9]+ \(message\): + check_source_runs: C: needs to be enabled before use. diff --git a/Tests/RunCMake/CheckSourceRuns/NotEnabledLanguage.cmake b/Tests/RunCMake/CheckSourceRuns/NotEnabledLanguage.cmake new file mode 100644 index 0000000..e16cec2 --- /dev/null +++ b/Tests/RunCMake/CheckSourceRuns/NotEnabledLanguage.cmake @@ -0,0 +1,3 @@ + +include(CheckSourceRuns) +check_source_runs(C "int main() {return 0;}" SHOULD_BUILD) diff --git a/Tests/RunCMake/CheckSourceRuns/RunCMakeTest.cmake b/Tests/RunCMake/CheckSourceRuns/RunCMakeTest.cmake new file mode 100644 index 0000000..8bcde6a --- /dev/null +++ b/Tests/RunCMake/CheckSourceRuns/RunCMakeTest.cmake @@ -0,0 +1,16 @@ +include(RunCMake) + +run_cmake(NotEnabledLanguage) +run_cmake(NonExistentLanguage) + +run_cmake(CheckCSourceRuns) +run_cmake(CheckCXXSourceRuns) + +if (APPLE) + run_cmake(CheckOBJCSourceRuns) + run_cmake(CheckOBJCXXSourceRuns) +endif() + +if (CMAKE_Fortran_COMPILER_ID) + run_cmake(CheckFortranSourceRuns) +endif() -- cgit v0.12