1# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2# file Copyright.txt or https://cmake.org/licensing for details.
3
4#[=======================================================================[.rst:
5FindThreads
6-----------
7
8This module determines the thread library of the system.
9
10Imported Targets
11^^^^^^^^^^^^^^^^
12
13.. versionadded:: 3.1
14
15This module defines the following :prop_tgt:`IMPORTED` target:
16
17``Threads::Threads``
18  The thread library, if found.
19
20Result Variables
21^^^^^^^^^^^^^^^^
22
23The following variables are set:
24
25``Threads_FOUND``
26  If a supported thread library was found.
27``CMAKE_THREAD_LIBS_INIT``
28  The thread library to use. This may be empty if the thread functions
29  are provided by the system libraries and no special flags are needed
30  to use them.
31``CMAKE_USE_WIN32_THREADS_INIT``
32  If the found thread library is the win32 one.
33``CMAKE_USE_PTHREADS_INIT``
34  If the found thread library is pthread compatible.
35``CMAKE_HP_PTHREADS_INIT``
36  If the found thread library is the HP thread library.
37
38Variables Affecting Behavior
39^^^^^^^^^^^^^^^^^^^^^^^^^^^^
40
41.. variable:: THREADS_PREFER_PTHREAD_FLAG
42
43  .. versionadded:: 3.1
44
45  If the use of the -pthread compiler and linker flag is preferred then
46  the caller can set this variable to TRUE. The compiler flag can only be
47  used with the imported target. Use of both the imported target as well
48  as this switch is highly recommended for new code.
49
50  This variable has no effect if the system libraries provide the
51  thread functions, i.e. when ``CMAKE_THREAD_LIBS_INIT`` will be empty.
52#]=======================================================================]
53
54include (CheckLibraryExists)
55set(Threads_FOUND FALSE)
56set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET})
57set(CMAKE_REQUIRED_QUIET ${Threads_FIND_QUIETLY})
58
59if(CMAKE_C_COMPILER_LOADED)
60  include (CheckIncludeFile)
61  include (CheckCSourceCompiles)
62elseif(CMAKE_CXX_COMPILER_LOADED)
63  include (CheckIncludeFileCXX)
64  include (CheckCXXSourceCompiles)
65else()
66  message(FATAL_ERROR "FindThreads only works if either C or CXX language is enabled")
67endif()
68
69# simple pthread test code
70set(PTHREAD_C_CXX_TEST_SOURCE [====[
71#include <pthread.h>
72
73static void* test_func(void* data)
74{
75  return data;
76}
77
78int main(void)
79{
80  pthread_t thread;
81  pthread_create(&thread, NULL, test_func, NULL);
82  pthread_detach(thread);
83  pthread_cancel(thread);
84  pthread_join(thread, NULL);
85  pthread_atfork(NULL, NULL, NULL);
86  pthread_exit(NULL);
87
88  return 0;
89}
90]====])
91
92# Internal helper macro.
93# Do NOT even think about using it outside of this file!
94macro(_check_threads_lib LIBNAME FUNCNAME VARNAME)
95  if(NOT Threads_FOUND)
96     CHECK_LIBRARY_EXISTS(${LIBNAME} ${FUNCNAME} "" ${VARNAME})
97     if(${VARNAME})
98       set(CMAKE_THREAD_LIBS_INIT "-l${LIBNAME}")
99       set(CMAKE_HAVE_THREADS_LIBRARY 1)
100       set(Threads_FOUND TRUE)
101     endif()
102  endif ()
103endmacro()
104
105# Internal helper macro.
106# Do NOT even think about using it outside of this file!
107macro(_check_pthreads_flag)
108  if(NOT Threads_FOUND)
109    # If we did not find -lpthreads, -lpthread, or -lthread, look for -pthread
110    if(NOT DEFINED THREADS_HAVE_PTHREAD_ARG)
111      message(CHECK_START "Check if compiler accepts -pthread")
112      if(CMAKE_C_COMPILER_LOADED)
113        set(_threads_src ${CMAKE_CURRENT_LIST_DIR}/CheckForPthreads.c)
114      elseif(CMAKE_CXX_COMPILER_LOADED)
115        set(_threads_src ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/FindThreads/CheckForPthreads.cxx)
116        configure_file(${CMAKE_CURRENT_LIST_DIR}/CheckForPthreads.c "${_threads_src}" COPYONLY)
117      endif()
118      try_compile(THREADS_HAVE_PTHREAD_ARG
119        ${CMAKE_BINARY_DIR}
120        ${_threads_src}
121        CMAKE_FLAGS -DLINK_LIBRARIES:STRING=-pthread
122        OUTPUT_VARIABLE _cmake_check_pthreads_output)
123
124      string(APPEND _cmake_find_threads_output "${_cmake_check_pthreads_output}")
125      unset(_cmake_check_pthreads_output)
126      unset(_threads_src)
127
128      if(THREADS_HAVE_PTHREAD_ARG)
129        set(Threads_FOUND TRUE)
130        message(CHECK_PASS "yes")
131      else()
132        message(CHECK_FAIL "no")
133      endif()
134
135    endif()
136
137    if(THREADS_HAVE_PTHREAD_ARG)
138      set(Threads_FOUND TRUE)
139      set(CMAKE_THREAD_LIBS_INIT "-pthread")
140    endif()
141  endif()
142endmacro()
143
144# Do we have pthreads?
145if(CMAKE_C_COMPILER_LOADED)
146  CHECK_INCLUDE_FILE("pthread.h" CMAKE_HAVE_PTHREAD_H)
147else()
148  CHECK_INCLUDE_FILE_CXX("pthread.h" CMAKE_HAVE_PTHREAD_H)
149endif()
150
151if(CMAKE_HAVE_PTHREAD_H)
152  #
153  # We have pthread.h
154  # Let's check for the library now.
155  #
156  set(CMAKE_HAVE_THREADS_LIBRARY)
157  if(NOT THREADS_HAVE_PTHREAD_ARG)
158    # Check if pthread functions are in normal C library.
159    # We list some pthread functions in PTHREAD_C_CXX_TEST_SOURCE test code.
160    # If the pthread functions already exist in C library, we could just use
161    # them instead of linking to the additional pthread library.
162    if(CMAKE_C_COMPILER_LOADED)
163      CHECK_C_SOURCE_COMPILES("${PTHREAD_C_CXX_TEST_SOURCE}" CMAKE_HAVE_LIBC_PTHREAD)
164    elseif(CMAKE_CXX_COMPILER_LOADED)
165      CHECK_CXX_SOURCE_COMPILES("${PTHREAD_C_CXX_TEST_SOURCE}" CMAKE_HAVE_LIBC_PTHREAD)
166    endif()
167    if(CMAKE_HAVE_LIBC_PTHREAD)
168      set(CMAKE_THREAD_LIBS_INIT "")
169      set(CMAKE_HAVE_THREADS_LIBRARY 1)
170      set(Threads_FOUND TRUE)
171    else()
172      # Check for -pthread first if enabled. This is the recommended
173      # way, but not backwards compatible as one must also pass -pthread
174      # as compiler flag then.
175      if (THREADS_PREFER_PTHREAD_FLAG)
176         _check_pthreads_flag()
177      endif ()
178
179      if(CMAKE_SYSTEM MATCHES "GHS-MULTI")
180        _check_threads_lib(posix pthread_create CMAKE_HAVE_PTHREADS_CREATE)
181      endif()
182      _check_threads_lib(pthreads pthread_create CMAKE_HAVE_PTHREADS_CREATE)
183      _check_threads_lib(pthread  pthread_create CMAKE_HAVE_PTHREAD_CREATE)
184      if(CMAKE_SYSTEM_NAME MATCHES "SunOS")
185          # On sun also check for -lthread
186          _check_threads_lib(thread thr_create CMAKE_HAVE_THR_CREATE)
187      endif()
188    endif()
189  endif()
190
191  _check_pthreads_flag()
192endif()
193
194if(CMAKE_THREAD_LIBS_INIT OR CMAKE_HAVE_LIBC_PTHREAD)
195  set(CMAKE_USE_PTHREADS_INIT 1)
196  set(Threads_FOUND TRUE)
197endif()
198
199if(CMAKE_SYSTEM_NAME MATCHES "Windows")
200  set(CMAKE_USE_WIN32_THREADS_INIT 1)
201  set(Threads_FOUND TRUE)
202endif()
203
204if(CMAKE_USE_PTHREADS_INIT)
205  if(CMAKE_SYSTEM_NAME MATCHES "HP-UX")
206    # Use libcma if it exists and can be used.  It provides more
207    # symbols than the plain pthread library.  CMA threads
208    # have actually been deprecated:
209    #   http://docs.hp.com/en/B3920-90091/ch12s03.html#d0e11395
210    #   http://docs.hp.com/en/947/d8.html
211    # but we need to maintain compatibility here.
212    # The CMAKE_HP_PTHREADS setting actually indicates whether CMA threads
213    # are available.
214    CHECK_LIBRARY_EXISTS(cma pthread_attr_create "" CMAKE_HAVE_HP_CMA)
215    if(CMAKE_HAVE_HP_CMA)
216      set(CMAKE_THREAD_LIBS_INIT "-lcma")
217      set(CMAKE_HP_PTHREADS_INIT 1)
218      set(Threads_FOUND TRUE)
219    endif()
220    set(CMAKE_USE_PTHREADS_INIT 1)
221  endif()
222
223  if(CMAKE_SYSTEM MATCHES "OSF1-V")
224    set(CMAKE_USE_PTHREADS_INIT 0)
225    set(CMAKE_THREAD_LIBS_INIT )
226  endif()
227
228  if(CMAKE_SYSTEM MATCHES "CYGWIN_NT" OR CMAKE_SYSTEM MATCHES "MSYS_NT")
229    set(CMAKE_USE_PTHREADS_INIT 1)
230    set(Threads_FOUND TRUE)
231    set(CMAKE_THREAD_LIBS_INIT )
232    set(CMAKE_USE_WIN32_THREADS_INIT 0)
233  endif()
234endif()
235
236set(CMAKE_REQUIRED_QUIET ${CMAKE_REQUIRED_QUIET_SAVE})
237include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
238FIND_PACKAGE_HANDLE_STANDARD_ARGS(Threads DEFAULT_MSG Threads_FOUND)
239
240if(THREADS_FOUND AND NOT TARGET Threads::Threads)
241  add_library(Threads::Threads INTERFACE IMPORTED)
242
243  if(THREADS_HAVE_PTHREAD_ARG)
244    set_property(TARGET Threads::Threads
245                 PROPERTY INTERFACE_COMPILE_OPTIONS "$<$<COMPILE_LANG_AND_ID:CUDA,NVIDIA>:SHELL:-Xcompiler -pthread>"
246                                                    "$<$<NOT:$<COMPILE_LANG_AND_ID:CUDA,NVIDIA>>:-pthread>")
247  endif()
248
249  if(CMAKE_THREAD_LIBS_INIT)
250    set_property(TARGET Threads::Threads PROPERTY INTERFACE_LINK_LIBRARIES "${CMAKE_THREAD_LIBS_INIT}")
251  endif()
252elseif(NOT THREADS_FOUND AND _cmake_find_threads_output)
253  file(APPEND
254    ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
255    "Determining if compiler accepts -pthread failed with the following output:\n${_cmake_find_threads_output}\n\n")
256endif()
257
258unset(_cmake_find_threads_output)
259