1#
2# SRT - Secure, Reliable, Transport
3# Copyright (c) 2018 Haivision Systems Inc.
4#
5# This Source Code Form is subject to the terms of the Mozilla Public
6# License, v. 2.0. If a copy of the MPL was not distributed with this
7# file, You can obtain one at http://mozilla.org/MPL/2.0/.
8#
9
10include(CheckCXXSourceCompiles)
11
12# Useful for combinging paths
13
14function(adddirname prefix lst out_lst)
15	set(output)
16	foreach(item ${lst})
17		list(APPEND output "${prefix}/${item}")
18	endforeach()
19	set(${out_lst} ${${out_lst}} ${output} PARENT_SCOPE)
20endfunction()
21
22# Splits a version formed as "major.minor.patch" recorded in variable 'prefix'
23# and writes it into variables started with 'prefix' and ended with _MAJOR, _MINOR and _PATCH.
24MACRO(set_version_variables prefix value)
25	string(REPLACE "." ";" VERSION_LIST ${value})
26	list(GET VERSION_LIST 0 ${prefix}_MAJOR)
27	list(GET VERSION_LIST 1 ${prefix}_MINOR)
28	list(GET VERSION_LIST 2 ${prefix}_PATCH)
29	set(${prefix}_DEFINESTR "")
30ENDMACRO(set_version_variables)
31
32# Sets given variable to 1, if the condition that follows it is satisfied.
33# Otherwise set it to 0.
34MACRO(set_if varname)
35	IF(${ARGN})
36		SET(${varname} 1)
37	ELSE(${ARGN})
38		SET(${varname} 0)
39	ENDIF(${ARGN})
40ENDMACRO(set_if)
41
42FUNCTION(join_arguments outvar)
43	set (output)
44
45	foreach (i ${ARGN})
46		set(output "${output} ${i}")
47	endforeach()
48
49	set (${outvar} ${output} PARENT_SCOPE)
50ENDFUNCTION()
51
52# The directory specifies the location of maffile and
53# all files specified in the list.
54MACRO(MafReadDir directory maffile)
55	# ARGN contains the extra "section-variable" pairs
56	# If empty, return nothing
57	set (MAFREAD_TAGS
58		SOURCES            # source files
59		PUBLIC_HEADERS     # installable headers for include
60		PROTECTED_HEADERS  # installable headers used by other headers
61		PRIVATE_HEADERS    # non-installable headers
62		SOURCES_WIN32_SHARED	# windows specific SOURCES
63		PRIVATE_HEADERS_WIN32_SHARED	# windows specific PRIVATE_HEADERS
64		OPTIONS
65	)
66	cmake_parse_arguments(MAFREAD_VAR "" "${MAFREAD_TAGS}" "" ${ARGN})
67	# Arguments for these tags are variables to be filled
68	# with the contents of particular section.
69	# While reading the file, extract the section.
70	# Section is recognized by either first uppercase character or space.
71
72	# @c http://cmake.org/pipermail/cmake/2007-May/014222.html
73	FILE(READ ${directory}/${maffile} MAFREAD_CONTENTS)
74	STRING(REGEX REPLACE ";" "\\\\;" MAFREAD_CONTENTS "${MAFREAD_CONTENTS}")
75	STRING(REGEX REPLACE "\n" ";" MAFREAD_CONTENTS "${MAFREAD_CONTENTS}")
76
77	# Once correctly read, declare this file as dependency of the build file.
78	# Normally you should use cmake_configure_depends(), but this is
79	# available only since 3.0 version.
80	configure_file(${directory}/${maffile} dummy_${maffile}.cmake.out)
81	file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/dummy_${maffile}.cmake.out)
82
83	#message("DEBUG: MAF FILE CONTENTS: ${MAFREAD_CONTENTS}")
84	#message("DEBUG: PASSED VARIABLES:")
85	#foreach(DEBUG_VAR ${MAFREAD_TAGS})
86	#	message("DEBUG: ${DEBUG_VAR}=${MAFREAD_VAR_${DEBUG_VAR}}")
87	#endforeach()
88
89	# The unnamed section becomes SOURCES
90	set (MAFREAD_VARIABLE ${MAFREAD_VAR_SOURCES})
91	set (MAFREAD_UNASSIGNED "")
92
93	# Default section type. Another is 'flags'.
94	set (MAFREAD_SECTION_TYPE file)
95
96	FOREACH(MAFREAD_LINE ${MAFREAD_CONTENTS})
97		# Test what this line is
98		string(STRIP ${MAFREAD_LINE} MAFREAD_OLINE)
99		string(SUBSTRING ${MAFREAD_OLINE} 0 1 MAFREAD_FIRST)
100		#message("DEBUG: LINE='${MAFREAD_LINE}' FIRST='${MAFREAD_FIRST}'")
101
102		# The 'continue' command is cmake 3.2 - very late discovery
103		if (MAFREAD_FIRST STREQUAL "")
104			#message("DEBUG: ... skipped: empty")
105		elseif (MAFREAD_FIRST STREQUAL "#")
106			#message("DEBUG: ... skipped: comment")
107		else()
108			# Will be skipped if the line was a comment/empty
109			string(REGEX MATCH "[ A-Z-]" MAFREAD_SECMARK ${MAFREAD_FIRST})
110			if (MAFREAD_SECMARK STREQUAL "")
111				# This isn't a section, it's a list element.
112				#message("DEBUG: ITEM: ${MAFREAD_OLINE} --> ${MAFREAD_VARIABLE}")
113				if (${MAFREAD_SECTION_TYPE} STREQUAL file)
114					get_filename_component(MAFREAD_OLINE ${directory}/${MAFREAD_OLINE} ABSOLUTE)
115				endif()
116
117				set (MAFREAD_CONDITION_OK 1)
118				if (DEFINED MAFREAD_CONDITION_LIST)
119					FOREACH(MFITEM IN ITEMS ${MAFREAD_CONDITION_LIST})
120						separate_arguments(MFITEM)
121						FOREACH(MFVAR IN ITEMS ${MFITEM})
122							STRING(SUBSTRING ${MFVAR} 0 1 MFPREFIX)
123							if (MFPREFIX STREQUAL "!")
124								STRING(SUBSTRING ${MFVAR} 1 -1 MFVAR)
125								if (${MFVAR})
126									set (MFCONDITION_RESULT 0)
127								else()
128									set (MFCONDITION_RESULT 1)
129								endif()
130							else()
131								if (${MFVAR})
132									set (MFCONDITION_RESULT 1)
133								else()
134									set (MFCONDITION_RESULT 0)
135								endif()
136							endif()
137							#message("CONDITION: ${MFPREFIX} ${MFVAR} -> ${MFCONDITION_RESULT}")
138
139							MATH(EXPR MAFREAD_CONDITION_OK "${MAFREAD_CONDITION_OK} & (${MFCONDITION_RESULT})")
140						ENDFOREACH()
141					ENDFOREACH()
142				endif()
143
144				if (MAFREAD_CONDITION_OK)
145					LIST(APPEND ${MAFREAD_VARIABLE} ${MAFREAD_OLINE})
146				else()
147					#message("... NOT ADDED ITEM: ${MAFREAD_OLINE}")
148				endif()
149			else()
150				# It's a section
151				# Check for conditionals (clear current conditions first)
152				unset(MAFREAD_CONDITION_LIST)
153
154				STRING(FIND ${MAFREAD_OLINE} " -" MAFREAD_HAVE_CONDITION)
155				if (NOT MAFREAD_HAVE_CONDITION EQUAL -1)
156					# Cut off conditional specification, and
157					# grab the section name and condition list
158					STRING(REPLACE " -" ";" MAFREAD_CONDITION_LIST ${MAFREAD_OLINE})
159
160					#message("CONDITION READ: ${MAFREAD_CONDITION_LIST}")
161
162					LIST(GET MAFREAD_CONDITION_LIST 0 MAFREAD_OLINE)
163					LIST(REMOVE_AT MAFREAD_CONDITION_LIST 0)
164					#message("EXTRACTING SECTION=${MAFREAD_OLINE} CONDITIONS=${MAFREAD_CONDITION_LIST}")
165				endif()
166				# change the running variable
167				# Make it section name
168				STRING(REPLACE  " " "_" MAFREAD_SECNAME ${MAFREAD_OLINE})
169				#message("MAF SECTION: ${MAFREAD_SECNAME}")
170
171				# The cmake's version of 'if (MAFREAD_SECNAME[0] == '-')' - sigh...
172				string(SUBSTRING ${MAFREAD_SECNAME} 0 1 MAFREAD_SECNAME0)
173				if (${MAFREAD_SECNAME0} STREQUAL "-")
174					set (MAFREAD_SECTION_TYPE option)
175					string(SUBSTRING ${MAFREAD_SECNAME} 1 -1 MAFREAD_SECNAME)
176				else()
177					set (MAFREAD_SECTION_TYPE file)
178				endif()
179				set(MAFREAD_VARIABLE ${MAFREAD_VAR_${MAFREAD_SECNAME}})
180				if (MAFREAD_VARIABLE STREQUAL "")
181					set(MAFREAD_VARIABLE MAFREAD_UNASSIGNED)
182				endif()
183				#message("DEBUG: NEW SECTION: '${MAFREAD_SECNAME}' --> VARIABLE: '${MAFREAD_VARIABLE}'")
184			endif()
185		endif()
186	ENDFOREACH()
187
188	# Final debug report
189	#set (ALL_VARS "")
190	#message("DEBUG: extracted variables:")
191	#foreach(DEBUG_VAR ${MAFREAD_TAGS})
192	#	list(APPEND ALL_VARS ${MAFREAD_VAR_${DEBUG_VAR}})
193	#endforeach()
194	#list(REMOVE_DUPLICATES ALL_VARS)
195	#foreach(DEBUG_VAR ${ALL_VARS})
196	#	message("DEBUG: --> ${DEBUG_VAR} = ${${DEBUG_VAR}}")
197	#endforeach()
198ENDMACRO(MafReadDir)
199
200# NOTE: This is historical only. Not in use.
201# It should be a similar interface to mafread.tcl like
202# the above MafRead macro.
203MACRO(GetMafHeaders directory outvar)
204	EXECUTE_PROCESS(
205		COMMAND ${CMAKE_MODULE_PATH}/mafread.tcl
206			${CMAKE_SOURCE_DIR}/${directory}/HEADERS.maf
207			"PUBLIC HEADERS"
208			"PROTECTED HEADERS"
209		OUTPUT_STRIP_TRAILING_WHITESPACE
210		OUTPUT_VARIABLE ${outvar}
211	)
212	SEPARATE_ARGUMENTS(${outvar})
213	adddirname(${CMAKE_SOURCE_DIR}/${directory} "${${outvar}}" ${outvar})
214ENDMACRO(GetMafHeaders)
215
216function (getVarsWith _prefix _varResult)
217	get_cmake_property(_vars VARIABLES)
218	string (REGEX MATCHALL "(^|;)${_prefix}[A-Za-z0-9_]*" _matchedVars "${_vars}")
219	set (${_varResult} ${_matchedVars} PARENT_SCOPE)
220endfunction()
221
222function (check_testcode_compiles testcode libraries _successful)
223	set (save_required_libraries ${CMAKE_REQUIRED_LIBRARIES})
224	set (CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES} ${libraries}")
225
226	check_cxx_source_compiles("${testcode}" ${_successful})
227	set (${_successful} ${${_successful}} PARENT_SCOPE)
228	set (CMAKE_REQUIRED_LIBRARIES ${save_required_libraries})
229endfunction()
230
231function (test_requires_clock_gettime _enable _linklib)
232	# This function tests if clock_gettime can be used
233	# - at all
234	# - with or without librt
235
236	# Result will be:
237	# - CLOCK_MONOTONIC is available, link with librt:
238	#   _enable = ON; _linklib = "-lrt".
239	# - CLOCK_MONOTONIC is available, link without librt:
240	#   _enable = ON; _linklib = "".
241	# - CLOCK_MONOTONIC is not available:
242	#   _enable = OFF; _linklib = "-".
243
244	set (code "
245		#include <time.h>
246		int main() {
247		  timespec res\;
248		  int result = clock_gettime(CLOCK_MONOTONIC, &res)\;
249		  return result == 0\;
250		}
251	")
252
253	check_testcode_compiles(${code} "" HAVE_CLOCK_GETTIME_IN)
254	if (HAVE_CLOCK_GETTIME_IN)
255		message(STATUS "CLOCK_MONOTONIC: available, no extra libs needed")
256		set (${_enable}  ON PARENT_SCOPE)
257		set (${_linklib} "" PARENT_SCOPE)
258		return()
259	endif()
260
261	check_testcode_compiles(${code} "rt" HAVE_CLOCK_GETTIME_LIBRT)
262	if (HAVE_CLOCK_GETTIME_LIBRT)
263		message(STATUS "CLOCK_MONOTONIC: available, requires -lrt")
264		set (${_enable}  ON PARENT_SCOPE)
265		set (${_linklib} "-lrt" PARENT_SCOPE)
266		return()
267	endif()
268
269	set (${_enable}  OFF PARENT_SCOPE)
270	set (${_linklib} "-" PARENT_SCOPE)
271	message(STATUS "CLOCK_MONOTONIC: not available on this system")
272endfunction()
273
274function (parse_compiler_type wct _type _suffix)
275	if (wct STREQUAL "")
276		set(${_type} "" PARENT_SCOPE)
277		set(${_suffix} "" PARENT_SCOPE)
278	else()
279		string(REPLACE "-" ";" OUTLIST ${wct})
280		list(LENGTH OUTLIST OUTLEN)
281		list(GET OUTLIST 0 ITEM)
282		set(${_type} ${ITEM} PARENT_SCOPE)
283		if (OUTLEN LESS 2)
284			set(_suffix "" PARENT_SCOPE)
285		else()
286			list(GET OUTLIST 1 ITEM)
287			set(${_suffix} "-${ITEM}" PARENT_SCOPE)
288		endif()
289	endif()
290endfunction()
291