1#
2# SRT - Secure, Reliable, Transport Copyright (c) 2021 Haivision Systems Inc.
3#
4# This Source Code Form is subject to the terms of the Mozilla Public License,
5# v. 2.0. If a copy of the MPL was not distributed with this file, You can
6# obtain one at http://mozilla.org/MPL/2.0/.
7#
8
9# Check for GCC Atomic Intrinsics and whether libatomic is required.
10#
11# Sets:
12#	HAVE_LIBATOMIC
13#	HAVE_LIBATOMIC_COMPILES
14#	HAVE_LIBATOMIC_COMPILES_STATIC
15#	HAVE_GCCATOMIC_INTRINSICS
16#	HAVE_GCCATOMIC_INTRINSICS_REQUIRES_LIBATOMIC
17#
18# See
19#	https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html
20#	https://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync
21
22include(CheckCSourceCompiles)
23include(CheckLibraryExists)
24
25function(CheckGCCAtomicIntrinsics)
26
27	unset(HAVE_LIBATOMIC CACHE)
28	unset(HAVE_LIBATOMIC_COMPILES CACHE)
29	unset(HAVE_LIBATOMIC_COMPILES_STATIC CACHE)
30	unset(HAVE_GCCATOMIC_INTRINSICS CACHE)
31	unset(HAVE_GCCATOMIC_INTRINSICS_REQUIRES_LIBATOMIC CACHE)
32
33	set(CMAKE_TRY_COMPILE_TARGET_TYPE EXECUTABLE) # CMake 3.6
34
35	unset(CMAKE_REQUIRED_FLAGS)
36	unset(CMAKE_REQUIRED_LIBRARIES)
37	unset(CMAKE_REQUIRED_LINK_OPTIONS)
38
39	# Check for existance of libatomic and whether this symbol is present.
40	check_library_exists(atomic __atomic_fetch_add_8 "" HAVE_LIBATOMIC)
41
42	set(CheckLibAtomicCompiles_CODE
43		"
44		int main(void)
45		{
46			const int result = 0;
47			return result;
48		}
49	")
50
51	set(CMAKE_REQUIRED_LIBRARIES "atomic")
52
53	# Check that the compiler can build a simple application and link with
54	# libatomic.
55	check_c_source_compiles("${CheckLibAtomicCompiles_CODE}"
56							HAVE_LIBATOMIC_COMPILES)
57	if(NOT HAVE_LIBATOMIC_COMPILES)
58		set(HAVE_LIBATOMIC
59			0
60			CACHE INTERNAL "" FORCE)
61	endif()
62	if(HAVE_LIBATOMIC AND HAVE_LIBATOMIC_COMPILES)
63		# CMAKE_REQUIRED_LINK_OPTIONS was introduced in CMake 3.14.
64		if(CMAKE_VERSION VERSION_LESS "3.14")
65			set(CMAKE_REQUIRED_LINK_OPTIONS "-static")
66		else()
67			set(CMAKE_REQUIRED_FLAGS "-static")
68	endif()
69	# Check that the compiler can build a simple application and statically link
70	# with libatomic.
71	check_c_source_compiles("${CheckLibAtomicCompiles_CODE}"
72							HAVE_LIBATOMIC_COMPILES_STATIC)
73	else()
74		set(HAVE_LIBATOMIC_COMPILES_STATIC
75			0
76			CACHE INTERNAL "" FORCE)
77	endif()
78
79	unset(CMAKE_REQUIRED_FLAGS)
80	unset(CMAKE_REQUIRED_LIBRARIES)
81	unset(CMAKE_REQUIRED_LINK_OPTIONS)
82
83	set(CheckGCCAtomicIntrinsics_CODE
84		"
85		#include<stddef.h>
86		#include<stdint.h>
87		int main(void)
88		{
89			ptrdiff_t x = 0;
90			intmax_t y = 0;
91			__atomic_add_fetch(&x, 1, __ATOMIC_SEQ_CST);
92			__atomic_add_fetch(&y, 1, __ATOMIC_SEQ_CST);
93			return __atomic_sub_fetch(&x, 1, __ATOMIC_SEQ_CST)
94				+ __atomic_sub_fetch(&y, 1, __ATOMIC_SEQ_CST);
95		}
96	")
97
98	set(CMAKE_TRY_COMPILE_TARGET_TYPE EXECUTABLE) # CMake 3.6
99	check_c_source_compiles("${CheckGCCAtomicIntrinsics_CODE}"
100							HAVE_GCCATOMIC_INTRINSICS)
101
102	if(NOT HAVE_GCCATOMIC_INTRINSICS AND HAVE_LIBATOMIC)
103		set(CMAKE_REQUIRED_LIBRARIES "atomic")
104		check_c_source_compiles("${CheckGCCAtomicIntrinsics_CODE}"
105							HAVE_GCCATOMIC_INTRINSICS_REQUIRES_LIBATOMIC)
106		if(HAVE_GCCATOMIC_INTRINSICS_REQUIRES_LIBATOMIC)
107			set(HAVE_GCCATOMIC_INTRINSICS
108				1
109				CACHE INTERNAL "" FORCE)
110		endif()
111	endif()
112
113endfunction(CheckGCCAtomicIntrinsics)
114