2
0

HunterGate.cmake 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. # Copyright (c) 2013-2018, Ruslan Baratov
  2. # All rights reserved.
  3. #
  4. # Redistribution and use in source and binary forms, with or without
  5. # modification, are permitted provided that the following conditions are met:
  6. #
  7. # * Redistributions of source code must retain the above copyright notice, this
  8. # list of conditions and the following disclaimer.
  9. #
  10. # * Redistributions in binary form must reproduce the above copyright notice,
  11. # this list of conditions and the following disclaimer in the documentation
  12. # and/or other materials provided with the distribution.
  13. #
  14. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  15. # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  17. # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  18. # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  19. # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  20. # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  21. # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  22. # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  23. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. # This is a gate file to Hunter package manager.
  25. # Include this file using `include` command and add package you need, example:
  26. #
  27. # cmake_minimum_required(VERSION 3.2)
  28. #
  29. # include("cmake/HunterGate.cmake")
  30. # HunterGate(
  31. # URL "https://github.com/path/to/hunter/archive.tar.gz"
  32. # SHA1 "798501e983f14b28b10cda16afa4de69eee1da1d"
  33. # )
  34. #
  35. # project(MyProject)
  36. #
  37. # hunter_add_package(Foo)
  38. # hunter_add_package(Boo COMPONENTS Bar Baz)
  39. #
  40. # Projects:
  41. # * https://github.com/hunter-packages/gate/
  42. # * https://github.com/ruslo/hunter
  43. option(HUNTER_ENABLED "Enable Hunter package manager support" ON)
  44. if(HUNTER_ENABLED)
  45. if(CMAKE_VERSION VERSION_LESS "3.2")
  46. message(
  47. FATAL_ERROR
  48. "At least CMake version 3.2 required for Hunter dependency management."
  49. " Update CMake or set HUNTER_ENABLED to OFF."
  50. )
  51. endif()
  52. endif()
  53. include(CMakeParseArguments) # cmake_parse_arguments
  54. option(HUNTER_STATUS_PRINT "Print working status" ON)
  55. option(HUNTER_STATUS_DEBUG "Print a lot info" OFF)
  56. option(HUNTER_TLS_VERIFY "Enable/disable TLS certificate checking on downloads" ON)
  57. set(HUNTER_WIKI "https://github.com/ruslo/hunter/wiki")
  58. function(hunter_gate_status_print)
  59. if(HUNTER_STATUS_PRINT OR HUNTER_STATUS_DEBUG)
  60. foreach(print_message ${ARGV})
  61. message(STATUS "[hunter] ${print_message}")
  62. endforeach()
  63. endif()
  64. endfunction()
  65. function(hunter_gate_status_debug)
  66. if(HUNTER_STATUS_DEBUG)
  67. foreach(print_message ${ARGV})
  68. string(TIMESTAMP timestamp)
  69. message(STATUS "[hunter *** DEBUG *** ${timestamp}] ${print_message}")
  70. endforeach()
  71. endif()
  72. endfunction()
  73. function(hunter_gate_wiki wiki_page)
  74. message("------------------------------ WIKI -------------------------------")
  75. message(" ${HUNTER_WIKI}/${wiki_page}")
  76. message("-------------------------------------------------------------------")
  77. message("")
  78. message(FATAL_ERROR "")
  79. endfunction()
  80. function(hunter_gate_internal_error)
  81. message("")
  82. foreach(print_message ${ARGV})
  83. message("[hunter ** INTERNAL **] ${print_message}")
  84. endforeach()
  85. message("[hunter ** INTERNAL **] [Directory:${CMAKE_CURRENT_LIST_DIR}]")
  86. message("")
  87. hunter_gate_wiki("error.internal")
  88. endfunction()
  89. function(hunter_gate_fatal_error)
  90. cmake_parse_arguments(hunter "" "WIKI" "" "${ARGV}")
  91. string(COMPARE EQUAL "${hunter_WIKI}" "" have_no_wiki)
  92. if(have_no_wiki)
  93. hunter_gate_internal_error("Expected wiki")
  94. endif()
  95. message("")
  96. foreach(x ${hunter_UNPARSED_ARGUMENTS})
  97. message("[hunter ** FATAL ERROR **] ${x}")
  98. endforeach()
  99. message("[hunter ** FATAL ERROR **] [Directory:${CMAKE_CURRENT_LIST_DIR}]")
  100. message("")
  101. hunter_gate_wiki("${hunter_WIKI}")
  102. endfunction()
  103. function(hunter_gate_user_error)
  104. hunter_gate_fatal_error(${ARGV} WIKI "error.incorrect.input.data")
  105. endfunction()
  106. function(hunter_gate_self root version sha1 result)
  107. string(COMPARE EQUAL "${root}" "" is_bad)
  108. if(is_bad)
  109. hunter_gate_internal_error("root is empty")
  110. endif()
  111. string(COMPARE EQUAL "${version}" "" is_bad)
  112. if(is_bad)
  113. hunter_gate_internal_error("version is empty")
  114. endif()
  115. string(COMPARE EQUAL "${sha1}" "" is_bad)
  116. if(is_bad)
  117. hunter_gate_internal_error("sha1 is empty")
  118. endif()
  119. string(SUBSTRING "${sha1}" 0 7 archive_id)
  120. if(EXISTS "${root}/cmake/Hunter")
  121. set(hunter_self "${root}")
  122. else()
  123. set(
  124. hunter_self
  125. "${root}/_Base/Download/Hunter/${version}/${archive_id}/Unpacked"
  126. )
  127. endif()
  128. set("${result}" "${hunter_self}" PARENT_SCOPE)
  129. endfunction()
  130. # Set HUNTER_GATE_ROOT cmake variable to suitable value.
  131. function(hunter_gate_detect_root)
  132. # Check CMake variable
  133. string(COMPARE NOTEQUAL "${HUNTER_ROOT}" "" not_empty)
  134. if(not_empty)
  135. set(HUNTER_GATE_ROOT "${HUNTER_ROOT}" PARENT_SCOPE)
  136. hunter_gate_status_debug("HUNTER_ROOT detected by cmake variable")
  137. return()
  138. endif()
  139. # Check environment variable
  140. string(COMPARE NOTEQUAL "$ENV{HUNTER_ROOT}" "" not_empty)
  141. if(not_empty)
  142. set(HUNTER_GATE_ROOT "$ENV{HUNTER_ROOT}" PARENT_SCOPE)
  143. hunter_gate_status_debug("HUNTER_ROOT detected by environment variable")
  144. return()
  145. endif()
  146. # Check HOME environment variable
  147. string(COMPARE NOTEQUAL "$ENV{HOME}" "" result)
  148. if(result)
  149. set(HUNTER_GATE_ROOT "$ENV{HOME}/.hunter" PARENT_SCOPE)
  150. hunter_gate_status_debug("HUNTER_ROOT set using HOME environment variable")
  151. return()
  152. endif()
  153. # Check SYSTEMDRIVE and USERPROFILE environment variable (windows only)
  154. if(WIN32)
  155. string(COMPARE NOTEQUAL "$ENV{SYSTEMDRIVE}" "" result)
  156. if(result)
  157. set(HUNTER_GATE_ROOT "$ENV{SYSTEMDRIVE}/.hunter" PARENT_SCOPE)
  158. hunter_gate_status_debug(
  159. "HUNTER_ROOT set using SYSTEMDRIVE environment variable"
  160. )
  161. return()
  162. endif()
  163. string(COMPARE NOTEQUAL "$ENV{USERPROFILE}" "" result)
  164. if(result)
  165. set(HUNTER_GATE_ROOT "$ENV{USERPROFILE}/.hunter" PARENT_SCOPE)
  166. hunter_gate_status_debug(
  167. "HUNTER_ROOT set using USERPROFILE environment variable"
  168. )
  169. return()
  170. endif()
  171. endif()
  172. hunter_gate_fatal_error(
  173. "Can't detect HUNTER_ROOT"
  174. WIKI "error.detect.hunter.root"
  175. )
  176. endfunction()
  177. function(hunter_gate_download dir)
  178. string(
  179. COMPARE
  180. NOTEQUAL
  181. "$ENV{HUNTER_DISABLE_AUTOINSTALL}"
  182. ""
  183. disable_autoinstall
  184. )
  185. if(disable_autoinstall AND NOT HUNTER_RUN_INSTALL)
  186. hunter_gate_fatal_error(
  187. "Hunter not found in '${dir}'"
  188. "Set HUNTER_RUN_INSTALL=ON to auto-install it from '${HUNTER_GATE_URL}'"
  189. "Settings:"
  190. " HUNTER_ROOT: ${HUNTER_GATE_ROOT}"
  191. " HUNTER_SHA1: ${HUNTER_GATE_SHA1}"
  192. WIKI "error.run.install"
  193. )
  194. endif()
  195. string(COMPARE EQUAL "${dir}" "" is_bad)
  196. if(is_bad)
  197. hunter_gate_internal_error("Empty 'dir' argument")
  198. endif()
  199. string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" is_bad)
  200. if(is_bad)
  201. hunter_gate_internal_error("HUNTER_GATE_SHA1 empty")
  202. endif()
  203. string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" is_bad)
  204. if(is_bad)
  205. hunter_gate_internal_error("HUNTER_GATE_URL empty")
  206. endif()
  207. set(done_location "${dir}/DONE")
  208. set(sha1_location "${dir}/SHA1")
  209. set(build_dir "${dir}/Build")
  210. set(cmakelists "${dir}/CMakeLists.txt")
  211. hunter_gate_status_debug("Locking directory: ${dir}")
  212. file(LOCK "${dir}" DIRECTORY GUARD FUNCTION)
  213. hunter_gate_status_debug("Lock done")
  214. if(EXISTS "${done_location}")
  215. # while waiting for lock other instance can do all the job
  216. hunter_gate_status_debug("File '${done_location}' found, skip install")
  217. return()
  218. endif()
  219. file(REMOVE_RECURSE "${build_dir}")
  220. file(REMOVE_RECURSE "${cmakelists}")
  221. file(MAKE_DIRECTORY "${build_dir}") # check directory permissions
  222. # Disabling languages speeds up a little bit, reduces noise in the output
  223. # and avoids path too long windows error
  224. file(
  225. WRITE
  226. "${cmakelists}"
  227. "cmake_minimum_required(VERSION 3.2)\n"
  228. "project(HunterDownload LANGUAGES NONE)\n"
  229. "include(ExternalProject)\n"
  230. "ExternalProject_Add(\n"
  231. " Hunter\n"
  232. " URL\n"
  233. " \"${HUNTER_GATE_URL}\"\n"
  234. " URL_HASH\n"
  235. " SHA1=${HUNTER_GATE_SHA1}\n"
  236. " DOWNLOAD_DIR\n"
  237. " \"${dir}\"\n"
  238. " TLS_VERIFY\n"
  239. " ${HUNTER_TLS_VERIFY}\n"
  240. " SOURCE_DIR\n"
  241. " \"${dir}/Unpacked\"\n"
  242. " CONFIGURE_COMMAND\n"
  243. " \"\"\n"
  244. " BUILD_COMMAND\n"
  245. " \"\"\n"
  246. " INSTALL_COMMAND\n"
  247. " \"\"\n"
  248. ")\n"
  249. )
  250. if(HUNTER_STATUS_DEBUG)
  251. set(logging_params "")
  252. else()
  253. set(logging_params OUTPUT_QUIET)
  254. endif()
  255. hunter_gate_status_debug("Run generate")
  256. # Need to add toolchain file too.
  257. # Otherwise on Visual Studio + MDD this will fail with error:
  258. # "Could not find an appropriate version of the Windows 10 SDK installed on this machine"
  259. if(EXISTS "${CMAKE_TOOLCHAIN_FILE}")
  260. get_filename_component(absolute_CMAKE_TOOLCHAIN_FILE "${CMAKE_TOOLCHAIN_FILE}" ABSOLUTE)
  261. set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=${absolute_CMAKE_TOOLCHAIN_FILE}")
  262. else()
  263. # 'toolchain_arg' can't be empty
  264. set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=")
  265. endif()
  266. string(COMPARE EQUAL "${CMAKE_MAKE_PROGRAM}" "" no_make)
  267. if(no_make)
  268. set(make_arg "")
  269. else()
  270. # Test case: remove Ninja from PATH but set it via CMAKE_MAKE_PROGRAM
  271. set(make_arg "-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}")
  272. endif()
  273. execute_process(
  274. COMMAND
  275. "${CMAKE_COMMAND}"
  276. "-H${dir}"
  277. "-B${build_dir}"
  278. "-G${CMAKE_GENERATOR}"
  279. "${toolchain_arg}"
  280. ${make_arg}
  281. WORKING_DIRECTORY "${dir}"
  282. RESULT_VARIABLE download_result
  283. ${logging_params}
  284. )
  285. if(NOT download_result EQUAL 0)
  286. hunter_gate_internal_error(
  287. "Configure project failed."
  288. "To reproduce the error run: ${CMAKE_COMMAND} -H${dir} -B${build_dir} -G${CMAKE_GENERATOR} ${toolchain_arg} ${make_arg}"
  289. "In directory ${dir}"
  290. )
  291. endif()
  292. hunter_gate_status_print(
  293. "Initializing Hunter workspace (${HUNTER_GATE_SHA1})"
  294. " ${HUNTER_GATE_URL}"
  295. " -> ${dir}"
  296. )
  297. execute_process(
  298. COMMAND "${CMAKE_COMMAND}" --build "${build_dir}"
  299. WORKING_DIRECTORY "${dir}"
  300. RESULT_VARIABLE download_result
  301. ${logging_params}
  302. )
  303. if(NOT download_result EQUAL 0)
  304. hunter_gate_internal_error("Build project failed")
  305. endif()
  306. file(REMOVE_RECURSE "${build_dir}")
  307. file(REMOVE_RECURSE "${cmakelists}")
  308. file(WRITE "${sha1_location}" "${HUNTER_GATE_SHA1}")
  309. file(WRITE "${done_location}" "DONE")
  310. hunter_gate_status_debug("Finished")
  311. endfunction()
  312. # Must be a macro so master file 'cmake/Hunter' can
  313. # apply all variables easily just by 'include' command
  314. # (otherwise PARENT_SCOPE magic needed)
  315. macro(HunterGate)
  316. if(HUNTER_GATE_DONE)
  317. # variable HUNTER_GATE_DONE set explicitly for external project
  318. # (see `hunter_download`)
  319. set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES)
  320. endif()
  321. # First HunterGate command will init Hunter, others will be ignored
  322. get_property(_hunter_gate_done GLOBAL PROPERTY HUNTER_GATE_DONE SET)
  323. if(NOT HUNTER_ENABLED)
  324. # Empty function to avoid error "unknown function"
  325. function(hunter_add_package)
  326. endfunction()
  327. set(
  328. _hunter_gate_disabled_mode_dir
  329. "${CMAKE_CURRENT_LIST_DIR}/cmake/Hunter/disabled-mode"
  330. )
  331. if(EXISTS "${_hunter_gate_disabled_mode_dir}")
  332. hunter_gate_status_debug(
  333. "Adding \"disabled-mode\" modules: ${_hunter_gate_disabled_mode_dir}"
  334. )
  335. list(APPEND CMAKE_PREFIX_PATH "${_hunter_gate_disabled_mode_dir}")
  336. endif()
  337. elseif(_hunter_gate_done)
  338. hunter_gate_status_debug("Secondary HunterGate (use old settings)")
  339. hunter_gate_self(
  340. "${HUNTER_CACHED_ROOT}"
  341. "${HUNTER_VERSION}"
  342. "${HUNTER_SHA1}"
  343. _hunter_self
  344. )
  345. include("${_hunter_self}/cmake/Hunter")
  346. else()
  347. set(HUNTER_GATE_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}")
  348. string(COMPARE NOTEQUAL "${PROJECT_NAME}" "" _have_project_name)
  349. if(_have_project_name)
  350. hunter_gate_fatal_error(
  351. "Please set HunterGate *before* 'project' command. "
  352. "Detected project: ${PROJECT_NAME}"
  353. WIKI "error.huntergate.before.project"
  354. )
  355. endif()
  356. cmake_parse_arguments(
  357. HUNTER_GATE "LOCAL" "URL;SHA1;GLOBAL;FILEPATH" "" ${ARGV}
  358. )
  359. string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" _empty_sha1)
  360. string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" _empty_url)
  361. string(
  362. COMPARE
  363. NOTEQUAL
  364. "${HUNTER_GATE_UNPARSED_ARGUMENTS}"
  365. ""
  366. _have_unparsed
  367. )
  368. string(COMPARE NOTEQUAL "${HUNTER_GATE_GLOBAL}" "" _have_global)
  369. string(COMPARE NOTEQUAL "${HUNTER_GATE_FILEPATH}" "" _have_filepath)
  370. if(_have_unparsed)
  371. hunter_gate_user_error(
  372. "HunterGate unparsed arguments: ${HUNTER_GATE_UNPARSED_ARGUMENTS}"
  373. )
  374. endif()
  375. if(_empty_sha1)
  376. hunter_gate_user_error("SHA1 suboption of HunterGate is mandatory")
  377. endif()
  378. if(_empty_url)
  379. hunter_gate_user_error("URL suboption of HunterGate is mandatory")
  380. endif()
  381. if(_have_global)
  382. if(HUNTER_GATE_LOCAL)
  383. hunter_gate_user_error("Unexpected LOCAL (already has GLOBAL)")
  384. endif()
  385. if(_have_filepath)
  386. hunter_gate_user_error("Unexpected FILEPATH (already has GLOBAL)")
  387. endif()
  388. endif()
  389. if(HUNTER_GATE_LOCAL)
  390. if(_have_global)
  391. hunter_gate_user_error("Unexpected GLOBAL (already has LOCAL)")
  392. endif()
  393. if(_have_filepath)
  394. hunter_gate_user_error("Unexpected FILEPATH (already has LOCAL)")
  395. endif()
  396. endif()
  397. if(_have_filepath)
  398. if(_have_global)
  399. hunter_gate_user_error("Unexpected GLOBAL (already has FILEPATH)")
  400. endif()
  401. if(HUNTER_GATE_LOCAL)
  402. hunter_gate_user_error("Unexpected LOCAL (already has FILEPATH)")
  403. endif()
  404. endif()
  405. hunter_gate_detect_root() # set HUNTER_GATE_ROOT
  406. # Beautify path, fix probable problems with windows path slashes
  407. get_filename_component(
  408. HUNTER_GATE_ROOT "${HUNTER_GATE_ROOT}" ABSOLUTE
  409. )
  410. hunter_gate_status_debug("HUNTER_ROOT: ${HUNTER_GATE_ROOT}")
  411. if(NOT HUNTER_ALLOW_SPACES_IN_PATH)
  412. string(FIND "${HUNTER_GATE_ROOT}" " " _contain_spaces)
  413. if(NOT _contain_spaces EQUAL -1)
  414. hunter_gate_fatal_error(
  415. "HUNTER_ROOT (${HUNTER_GATE_ROOT}) contains spaces."
  416. "Set HUNTER_ALLOW_SPACES_IN_PATH=ON to skip this error"
  417. "(Use at your own risk!)"
  418. WIKI "error.spaces.in.hunter.root"
  419. )
  420. endif()
  421. endif()
  422. string(
  423. REGEX
  424. MATCH
  425. "[0-9]+\\.[0-9]+\\.[0-9]+[-_a-z0-9]*"
  426. HUNTER_GATE_VERSION
  427. "${HUNTER_GATE_URL}"
  428. )
  429. string(COMPARE EQUAL "${HUNTER_GATE_VERSION}" "" _is_empty)
  430. if(_is_empty)
  431. set(HUNTER_GATE_VERSION "unknown")
  432. endif()
  433. hunter_gate_self(
  434. "${HUNTER_GATE_ROOT}"
  435. "${HUNTER_GATE_VERSION}"
  436. "${HUNTER_GATE_SHA1}"
  437. _hunter_self
  438. )
  439. set(_master_location "${_hunter_self}/cmake/Hunter")
  440. if(EXISTS "${HUNTER_GATE_ROOT}/cmake/Hunter")
  441. # Hunter downloaded manually (e.g. by 'git clone')
  442. set(_unused "xxxxxxxxxx")
  443. set(HUNTER_GATE_SHA1 "${_unused}")
  444. set(HUNTER_GATE_VERSION "${_unused}")
  445. else()
  446. get_filename_component(_archive_id_location "${_hunter_self}/.." ABSOLUTE)
  447. set(_done_location "${_archive_id_location}/DONE")
  448. set(_sha1_location "${_archive_id_location}/SHA1")
  449. # Check Hunter already downloaded by HunterGate
  450. if(NOT EXISTS "${_done_location}")
  451. hunter_gate_download("${_archive_id_location}")
  452. endif()
  453. if(NOT EXISTS "${_done_location}")
  454. hunter_gate_internal_error("hunter_gate_download failed")
  455. endif()
  456. if(NOT EXISTS "${_sha1_location}")
  457. hunter_gate_internal_error("${_sha1_location} not found")
  458. endif()
  459. file(READ "${_sha1_location}" _sha1_value)
  460. string(COMPARE EQUAL "${_sha1_value}" "${HUNTER_GATE_SHA1}" _is_equal)
  461. if(NOT _is_equal)
  462. hunter_gate_internal_error(
  463. "Short SHA1 collision:"
  464. " ${_sha1_value} (from ${_sha1_location})"
  465. " ${HUNTER_GATE_SHA1} (HunterGate)"
  466. )
  467. endif()
  468. if(NOT EXISTS "${_master_location}")
  469. hunter_gate_user_error(
  470. "Master file not found:"
  471. " ${_master_location}"
  472. "try to update Hunter/HunterGate"
  473. )
  474. endif()
  475. endif()
  476. include("${_master_location}")
  477. set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES)
  478. endif()
  479. endmacro()