@@ -30,6 +30,10 @@ macro(optionx variable type description)
3030 set (multiValueArgs)
3131 cmake_parse_arguments (${variable} "${options} " "${oneValueArgs} " "${multiValueArgs} " ${ARGN} )
3232
33+ if (DEFINED ${variable} )
34+ set (${variable} _VALUE ${${variable} })
35+ endif ()
36+
3337 if (NOT ${type} MATCHES "^(BOOL|STRING|FILEPATH|PATH|INTERNAL)$" )
3438 set (${variable} _REGEX ${type} )
3539 set (${variable} _TYPE STRING )
@@ -65,7 +69,9 @@ macro(optionx variable type description)
6569 message (FATAL_ERROR "Invalid ${${variable} _SOURCE}: ${${variable} _PREVIEW}=\" ${${variable} }\" , please use ${${variable} _PREVIEW}=<${${variable} _REGEX}>" )
6670 endif ()
6771
68- message (STATUS "Set ${variable} : ${${variable} }" )
72+ if (NOT ${variable} _VALUE STREQUAL ${variable} )
73+ message (STATUS "Set ${variable} : ${${variable} }" )
74+ endif ()
6975endmacro ()
7076
7177# unsupported()
@@ -194,102 +200,153 @@ function(setenv variable value)
194200 message (STATUS "Set ENV ${variable} : ${value} " )
195201endfunction ()
196202
197- # check_command ()
203+ # satisfies_range ()
198204# Description:
199- # Checks if a command is available, used by `find_command()` as a validator.
205+ # Check if a version satisfies a version range
200206# Arguments:
201- # FOUND bool - The variable to set to true if the version is found
202- # CMD string - The executable to check the version of
203- function (check_command FOUND CMD)
204- set (${FOUND} OFF PARENT_SCOPE)
205-
206- if (${CMD} MATCHES "zig" )
207- set (CHECK_COMMAND ${CMD} version )
208- else ()
209- set (CHECK_COMMAND ${CMD} --version )
207+ # version string - The version to check (e.g. "1.2.3")
208+ # range string - The range to check against (e.g. ">=1.2.3")
209+ # variable string - The variable to store the result in
210+ function (satisfies_range version range variable )
211+ if (range STREQUAL "ignore" )
212+ set (${variable} ON PARENT_SCOPE)
213+ return ()
210214 endif ()
211215
212- execute_process (
213- COMMAND ${CHECK_COMMAND}
214- RESULT_VARIABLE RESULT
215- OUTPUT_VARIABLE OUTPUT
216- OUTPUT_STRIP_TRAILING_WHITESPACE
217- )
216+ set (${variable} OFF PARENT_SCOPE)
218217
219- if ( NOT RESULT EQUAL 0 OR NOT OUTPUT )
220- message (DEBUG " ${CHECK_COMMAND} , exited with code ${RESULT} " )
218+ string ( REGEX MATCH "([0-9]+) \\ .([0-9]+) \\ .([0-9]+)" match " ${version} " )
219+ if ( NOT match )
221220 return ()
222221 endif ()
222+ set (version ${CMAKE_MATCH_1} .${CMAKE_MATCH_2} .${CMAKE_MATCH_3} )
223223
224- parse_semver(${OUTPUT} CMD)
225- parse_semver(${CHECK_COMMAND_VERSION} CHECK)
226-
227- if (CHECK_COMMAND_VERSION MATCHES ">=" )
228- if (NOT CMD_VERSION VERSION_GREATER_EQUAL ${CHECK_VERSION} )
229- message (DEBUG "${CHECK_COMMAND} , actual: ${CMD_VERSION} , expected: ${CHECK_COMMAND_VERSION} " )
230- return ()
231- endif ()
232- elseif (CHECK_COMMAND_VERSION MATCHES ">" )
233- if (NOT CMD_VERSION VERSION_GREATER ${CHECK_VERSION} )
234- message (DEBUG "${CHECK_COMMAND} , actual: ${CMD_VERSION} , expected: ${CHECK_COMMAND_VERSION} " )
235- return ()
236- endif ()
224+ string (REGEX MATCH "(>=|<=|>|<)?([0-9]+)\\ .([0-9]+)\\ .([0-9]+)" match "${range} " )
225+ if (NOT match)
226+ return ()
227+ endif ()
228+ set (comparator ${CMAKE_MATCH_1} )
229+ set (range ${CMAKE_MATCH_2} .${CMAKE_MATCH_3} .${CMAKE_MATCH_4} )
230+
231+ if (comparator STREQUAL ">=" )
232+ set (comparator VERSION_GREATER_EQUAL )
233+ elseif (comparator STREQUAL ">" )
234+ set (comparator VERSION_GREATER )
235+ elseif (comparator STREQUAL "<=" )
236+ set (comparator VERSION_LESS_EQUAL)
237+ elseif (comparator STREQUAL "<" )
238+ set (comparator VERSION_LESS )
237239 else ()
238- if (NOT CMD_VERSION VERSION_EQUAL ${CHECK_VERSION} )
239- message (DEBUG "${CHECK_COMMAND} , actual: ${CMD_VERSION} , expected: =${CHECK_COMMAND_VERSION} " )
240- return ()
241- endif ()
240+ set (comparator VERSION_EQUAL )
242241 endif ()
243242
244- set (${FOUND} TRUE PARENT_SCOPE)
243+ if (version ${comparator} ${range} )
244+ set (${variable} ON PARENT_SCOPE)
245+ endif ()
245246endfunction ()
246247
247248# find_command()
248249# Description:
249250# Finds a command, similar to `find_program()`, but allows for version checking.
250251# Arguments:
251- # VARIABLE string - The variable to set
252- # COMMAND string[] - The names of the command to find
253- # PATHS string[] - The paths to search for the command
254- # REQUIRED bool - If false, the command is optional
255- # VERSION string - The version of the command to find (e.g. "1.2.3" or ">1.2.3")
252+ # VARIABLE string - The variable to set
253+ # VERSION_VARIABLE string - The variable to check for the version
254+ # COMMAND string[] - The names of the command to find
255+ # PATHS string[] - The paths to search for the command
256+ # REQUIRED bool - If false, the command is optional
257+ # VERSION string - The version of the command to find (e.g. "1.2.3" or ">1.2.3")
256258function (find_command)
257- set (options )
258- set (args VARIABLE VERSION MIN_VERSION REQUIRED)
259+ set (args VARIABLE VERSION_VARIABLE REQUIRED VERSION )
259260 set (multiArgs COMMAND PATHS )
260- cmake_parse_arguments (CMD " ${options} " "${args} " "${multiArgs} " ${ARGN} )
261+ cmake_parse_arguments (FIND " " "${args} " "${multiArgs} " ${ARGN} )
261262
262- if (NOT CMD_VARIABLE )
263- message (FATAL_ERROR "find_command : VARIABLE is required" )
263+ if (NOT FIND_VARIABLE OR NOT FIND_COMMAND )
264+ message (FATAL_ERROR "${CMAKE_CURRENT_FUNCTION} : VARIABLE and COMMAND are required" )
264265 endif ()
265266
266- if (NOT CMD_COMMAND )
267- message (FATAL_ERROR "find_command: COMMAND is required" )
267+ if (NOT FIND_VERSION_VARIABLE )
268+ set (FIND_VERSION_VARIABLE ${FIND_VARIABLE} _VERSION )
268269 endif ()
269270
270- if (CMD_VERSION)
271- set (CHECK_COMMAND_VERSION ${CMD_VERSION} ) # special global variable
272- set (CMD_VALIDATOR VALIDATOR check_command)
271+ list (GET FIND_COMMAND 0 FIND_NAME)
272+ optionx(${FIND_VERSION_VARIABLE} STRING "The version of ${FIND_NAME} to find" DEFAULT "${FIND_VERSION} " )
273+
274+ if (${FIND_VERSION_VARIABLE} )
275+ function (find_command_version variable exe)
276+ set (${variable} OFF PARENT_SCOPE)
277+
278+ if (${exe} MATCHES "(go|zig)(\. exe)?$" )
279+ set (command ${exe} version )
280+ else ()
281+ set (command ${exe} --version )
282+ endif ()
283+
284+ execute_process (
285+ COMMAND ${command}
286+ RESULT_VARIABLE result
287+ OUTPUT_VARIABLE output
288+ OUTPUT_STRIP_TRAILING_WHITESPACE
289+ )
290+
291+ if (NOT result EQUAL 0)
292+ set (reason "exited with ${result} " )
293+ elseif (NOT output )
294+ set (reason "no output" )
295+ else ()
296+ string (REGEX MATCH "([0-9]+)\\ .([0-9]+)\\ .([0-9]+)" match "${output} " )
297+ if (match)
298+ set (version ${CMAKE_MATCH_1} .${CMAKE_MATCH_2} .${CMAKE_MATCH_3} )
299+ set (reason "\" ${version} \" " )
300+ else ()
301+ set (reason "no version" )
302+ endif ()
303+ endif ()
304+
305+ set_property (GLOBAL PROPERTY ${FIND_NAME} "${exe} : ${reason} " APPEND )
306+
307+ if (version )
308+ satisfies_range(${version} ${${FIND_VERSION_VARIABLE} } ${variable} )
309+ set (${variable} ${${variable} } PARENT_SCOPE)
310+ endif ()
311+ endfunction ()
312+
313+ set (FIND_VALIDATOR VALIDATOR find_command_version)
273314 endif ()
274315
275316 find_program (
276- ${CMD_VARIABLE }
277- NAMES ${CMD_COMMAND }
278- PATHS ${CMD_PATHS }
279- ${CMD_VALIDATOR }
317+ ${FIND_VARIABLE }
318+ NAMES ${FIND_COMMAND }
319+ PATHS ${FIND_PATHS }
320+ ${FIND_VALIDATOR }
280321 )
281322
282- if (NOT CMD_REQUIRED STREQUAL "OFF" AND ${CMD_VARIABLE} MATCHES "NOTFOUND" )
283- if (CMD_VERSION)
284- message (FATAL_ERROR "Command not found: \" ${CMD_COMMAND} \" that matches version \" ${CHECK_COMMAND_VERSION} \" " )
323+ if (NOT FIND_REQUIRED STREQUAL "OFF" AND ${FIND_VARIABLE} MATCHES "NOTFOUND" )
324+ set (error "Command not found: \" ${FIND_NAME} \" " )
325+
326+ if (FIND_VERSION)
327+ set (error "${error} that satisfies version \" ${${FIND_VERSION_VARIABLE} }\" " )
285328 endif ()
286- message (FATAL_ERROR "Command not found: \" ${CMD_COMMAND} \" " )
329+
330+ get_property (FIND_RESULTS GLOBAL PROPERTY ${FIND_NAME} )
331+ if (NOT FIND_RESULTS MATCHES "NOTFOUND" )
332+ set (error "${error} \n The following commands did not satisfy the requirement:" )
333+ foreach (result ${FIND_RESULTS} )
334+ set (error "${error} \n ${result} " )
335+ endforeach ()
336+ endif ()
337+
338+ set (error "${error} \n To fix this, either:
339+ 1. Install ${FIND_NAME} ${${FIND_VERSION_VARIABLE} }
340+ 2. Set -D${FIND_VERSION_VARIABLE} =<version> to require a different version
341+ 3. Set -D${FIND_VERSION_VARIABLE} =ignore to allow any version
342+ " )
343+ message (FATAL_ERROR ${error} )
287344 endif ()
288345
289- if (${CMD_VARIABLE } MATCHES "NOTFOUND" )
290- unset (${CMD_VARIABLE } PARENT_SCOPE)
346+ if (${FIND_VARIABLE } MATCHES "NOTFOUND" )
347+ unset (${FIND_VARIABLE } PARENT_SCOPE)
291348 else ()
292- setx(${CMD_VARIABLE } ${${CMD_VARIABLE } } PARENT_SCOPE)
349+ setx(${FIND_VARIABLE } ${${FIND_VARIABLE } } PARENT_SCOPE)
293350 endif ()
294351endfunction ()
295352
0 commit comments