1# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2# file Copyright.txt or https://cmake.org/licensing for details.
3
4include_guard(GLOBAL)
5
6cmake_policy(PUSH)
7cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced
8cmake_policy(SET CMP0057 NEW) # if() supports IN_LIST
9
10function(CMAKE_CHECK_SOURCE_RUNS _lang _source _var)
11  if(NOT DEFINED "${_var}")
12
13    if(_lang STREQUAL "C")
14      set(_lang_textual "C")
15      set(_lang_ext "c")
16    elseif(_lang STREQUAL "CXX")
17      set(_lang_textual "C++")
18      set(_lang_ext "cxx")
19    elseif(_lang STREQUAL "CUDA")
20      set(_lang_textual "CUDA")
21      set(_lang_ext "cu")
22    elseif(_lang STREQUAL "Fortran")
23      set(_lang_textual "Fortran")
24      set(_lang_ext "F90")
25    elseif(_lang STREQUAL "HIP")
26      set(_lang_textual "HIP")
27      set(_lang_ext "hip")
28    elseif(_lang STREQUAL "OBJC")
29      set(_lang_textual "Objective-C")
30      set(_lang_ext "m")
31    elseif(_lang STREQUAL "OBJCXX")
32      set(_lang_textual "Objective-C++")
33      set(_lang_ext "mm")
34    else()
35      message (SEND_ERROR "check_source_runs: ${_lang}: unknown language.")
36      return()
37    endif()
38
39    get_property (_supported_languages GLOBAL PROPERTY ENABLED_LANGUAGES)
40    if (NOT _lang IN_LIST _supported_languages)
41      message (SEND_ERROR "check_source_runs: ${_lang}: needs to be enabled before use.")
42      return()
43    endif()
44
45    set(_FAIL_REGEX)
46    set(_SRC_EXT)
47    set(_key)
48    foreach(arg ${ARGN})
49      if("${arg}" MATCHES "^(FAIL_REGEX|SRC_EXT)$")
50        set(_key "${arg}")
51      elseif(_key STREQUAL "FAIL_REGEX")
52        list(APPEND _FAIL_REGEX "${arg}")
53      elseif(_key STREQUAL "SRC_EXT")
54        set(_SRC_EXT "${arg}")
55        set(_key "")
56      else()
57        set(message_type FATAL_ERROR)
58        if (_CheckSourceRuns_old_signature)
59          set(message_type AUTHOR_WARNING)
60        endif ()
61        message("${message_type}" "Unknown argument:\n  ${arg}\n")
62        unset(message_type)
63      endif()
64    endforeach()
65
66    if(NOT _SRC_EXT)
67      set(_SRC_EXT ${_lang_ext})
68    endif()
69
70    if(CMAKE_REQUIRED_LINK_OPTIONS)
71      set(CHECK_${_lang}_SOURCE_COMPILES_ADD_LINK_OPTIONS
72        LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS})
73    else()
74      set(CHECK_${_lang}_SOURCE_COMPILES_ADD_LINK_OPTIONS)
75    endif()
76    if(CMAKE_REQUIRED_LIBRARIES)
77      set(CHECK_${_lang}_SOURCE_COMPILES_ADD_LIBRARIES
78        LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES})
79    else()
80      set(CHECK_${_lang}_SOURCE_COMPILES_ADD_LIBRARIES)
81    endif()
82    if(CMAKE_REQUIRED_INCLUDES)
83      set(CHECK_${_lang}_SOURCE_COMPILES_ADD_INCLUDES
84        "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}")
85    else()
86      set(CHECK_${_lang}_SOURCE_COMPILES_ADD_INCLUDES)
87    endif()
88    file(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.${_SRC_EXT}"
89      "${_source}\n")
90
91    if(NOT CMAKE_REQUIRED_QUIET)
92      message(CHECK_START "Performing Test ${_var}")
93    endif()
94    try_run(${_var}_EXITCODE ${_var}_COMPILED
95      ${CMAKE_BINARY_DIR}
96      ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.${_SRC_EXT}
97      COMPILE_DEFINITIONS -D${_var} ${CMAKE_REQUIRED_DEFINITIONS}
98      ${CHECK_${_lang}_SOURCE_COMPILES_ADD_LINK_OPTIONS}
99      ${CHECK_${_lang}_SOURCE_COMPILES_ADD_LIBRARIES}
100      CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${CMAKE_REQUIRED_FLAGS}
101      -DCMAKE_SKIP_RPATH:BOOL=${CMAKE_SKIP_RPATH}
102      "${CHECK_${_lang}_SOURCE_COMPILES_ADD_INCLUDES}"
103      COMPILE_OUTPUT_VARIABLE OUTPUT
104      RUN_OUTPUT_VARIABLE RUN_OUTPUT)
105    # if it did not compile make the return value fail code of 1
106    if(NOT ${_var}_COMPILED)
107      set(${_var}_EXITCODE 1)
108      set(${_var}_EXITCODE 1 PARENT_SCOPE)
109    endif()
110    # if the return value was 0 then it worked
111    if("${${_var}_EXITCODE}" EQUAL 0)
112      set(${_var} 1 CACHE INTERNAL "Test ${_var}")
113      if(NOT CMAKE_REQUIRED_QUIET)
114        message(CHECK_PASS "Success")
115      endif()
116      file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
117        "Performing ${_lang_textual} SOURCE FILE Test ${_var} succeeded with the following compile output:\n"
118        "${OUTPUT}\n"
119        "...and run output:\n"
120        "${RUN_OUTPUT}\n"
121        "Return value: ${${_var}}\n"
122        "Source file was:\n${_source}\n")
123    else()
124      if(CMAKE_CROSSCOMPILING AND "${${_var}_EXITCODE}" MATCHES  "FAILED_TO_RUN")
125        set(${_var} "${${_var}_EXITCODE}" PARENT_SCOPE)
126      else()
127        set(${_var} "" CACHE INTERNAL "Test ${_var}")
128      endif()
129
130      if(NOT CMAKE_REQUIRED_QUIET)
131        message(CHECK_FAIL "Failed")
132      endif()
133      file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
134        "Performing ${_lang_textual} SOURCE FILE Test ${_var} failed with the following compile output:\n"
135        "${OUTPUT}\n"
136        "...and run output:\n"
137        "${RUN_OUTPUT}\n"
138        "Return value: ${${_var}_EXITCODE}\n"
139        "Source file was:\n${_source}\n")
140
141    endif()
142  endif()
143endfunction()
144
145cmake_policy(POP)
146