HunterGate.cmake 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  1. # Copyright (c) 2013-2019, 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_ROOT "" CACHE FILEPATH "Override the HUNTER_ROOT.")
  58. set(HUNTER_ERROR_PAGE "https://hunter.readthedocs.io/en/latest/reference/errors")
  59. function(hunter_gate_status_print)
  60. if(HUNTER_STATUS_PRINT OR HUNTER_STATUS_DEBUG)
  61. foreach(print_message ${ARGV})
  62. message(STATUS "[hunter] ${print_message}")
  63. endforeach()
  64. endif()
  65. endfunction()
  66. function(hunter_gate_status_debug)
  67. if(HUNTER_STATUS_DEBUG)
  68. foreach(print_message ${ARGV})
  69. string(TIMESTAMP timestamp)
  70. message(STATUS "[hunter *** DEBUG *** ${timestamp}] ${print_message}")
  71. endforeach()
  72. endif()
  73. endfunction()
  74. function(hunter_gate_error_page error_page)
  75. message("------------------------------ ERROR ------------------------------")
  76. message(" ${HUNTER_ERROR_PAGE}/${error_page}.html")
  77. message("-------------------------------------------------------------------")
  78. message("")
  79. message(FATAL_ERROR "")
  80. endfunction()
  81. function(hunter_gate_internal_error)
  82. message("")
  83. foreach(print_message ${ARGV})
  84. message("[hunter ** INTERNAL **] ${print_message}")
  85. endforeach()
  86. message("[hunter ** INTERNAL **] [Directory:${CMAKE_CURRENT_LIST_DIR}]")
  87. message("")
  88. hunter_gate_error_page("error.internal")
  89. endfunction()
  90. function(hunter_gate_fatal_error)
  91. cmake_parse_arguments(hunter "" "ERROR_PAGE" "" "${ARGV}")
  92. if("${hunter_ERROR_PAGE}" STREQUAL "")
  93. hunter_gate_internal_error("Expected ERROR_PAGE")
  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_error_page("${hunter_ERROR_PAGE}")
  102. endfunction()
  103. function(hunter_gate_user_error)
  104. hunter_gate_fatal_error(${ARGV} ERROR_PAGE "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. if(HUNTER_ROOT)
  134. set(HUNTER_GATE_ROOT "${HUNTER_ROOT}" PARENT_SCOPE)
  135. hunter_gate_status_debug("HUNTER_ROOT detected by cmake variable")
  136. return()
  137. endif()
  138. # Check environment variable
  139. if(DEFINED ENV{HUNTER_ROOT})
  140. set(HUNTER_GATE_ROOT "$ENV{HUNTER_ROOT}" PARENT_SCOPE)
  141. hunter_gate_status_debug("HUNTER_ROOT detected by environment variable")
  142. return()
  143. endif()
  144. # Check HOME environment variable
  145. if(DEFINED ENV{HOME})
  146. set(HUNTER_GATE_ROOT "$ENV{HOME}/.hunter" PARENT_SCOPE)
  147. hunter_gate_status_debug("HUNTER_ROOT set using HOME environment variable")
  148. return()
  149. endif()
  150. # Check SYSTEMDRIVE and USERPROFILE environment variable (windows only)
  151. if(WIN32)
  152. if(DEFINED ENV{SYSTEMDRIVE})
  153. set(HUNTER_GATE_ROOT "$ENV{SYSTEMDRIVE}/.hunter" PARENT_SCOPE)
  154. hunter_gate_status_debug(
  155. "HUNTER_ROOT set using SYSTEMDRIVE environment variable"
  156. )
  157. return()
  158. endif()
  159. if(DEFINED ENV{USERPROFILE})
  160. set(HUNTER_GATE_ROOT "$ENV{USERPROFILE}/.hunter" PARENT_SCOPE)
  161. hunter_gate_status_debug(
  162. "HUNTER_ROOT set using USERPROFILE environment variable"
  163. )
  164. return()
  165. endif()
  166. endif()
  167. hunter_gate_fatal_error(
  168. "Can't detect HUNTER_ROOT"
  169. ERROR_PAGE "error.detect.hunter.root"
  170. )
  171. endfunction()
  172. function(hunter_gate_download dir)
  173. string(
  174. COMPARE
  175. NOTEQUAL
  176. "$ENV{HUNTER_DISABLE_AUTOINSTALL}"
  177. ""
  178. disable_autoinstall
  179. )
  180. if(disable_autoinstall AND NOT HUNTER_RUN_INSTALL)
  181. hunter_gate_fatal_error(
  182. "Hunter not found in '${dir}'"
  183. "Set HUNTER_RUN_INSTALL=ON to auto-install it from '${HUNTER_GATE_URL}'"
  184. "Settings:"
  185. " HUNTER_ROOT: ${HUNTER_GATE_ROOT}"
  186. " HUNTER_SHA1: ${HUNTER_GATE_SHA1}"
  187. ERROR_PAGE "error.run.install"
  188. )
  189. endif()
  190. string(COMPARE EQUAL "${dir}" "" is_bad)
  191. if(is_bad)
  192. hunter_gate_internal_error("Empty 'dir' argument")
  193. endif()
  194. string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" is_bad)
  195. if(is_bad)
  196. hunter_gate_internal_error("HUNTER_GATE_SHA1 empty")
  197. endif()
  198. string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" is_bad)
  199. if(is_bad)
  200. hunter_gate_internal_error("HUNTER_GATE_URL empty")
  201. endif()
  202. set(done_location "${dir}/DONE")
  203. set(sha1_location "${dir}/SHA1")
  204. set(build_dir "${dir}/Build")
  205. set(cmakelists "${dir}/CMakeLists.txt")
  206. hunter_gate_status_debug("Locking directory: ${dir}")
  207. file(LOCK "${dir}" DIRECTORY GUARD FUNCTION)
  208. hunter_gate_status_debug("Lock done")
  209. if(EXISTS "${done_location}")
  210. # while waiting for lock other instance can do all the job
  211. hunter_gate_status_debug("File '${done_location}' found, skip install")
  212. return()
  213. endif()
  214. file(REMOVE_RECURSE "${build_dir}")
  215. file(REMOVE_RECURSE "${cmakelists}")
  216. file(MAKE_DIRECTORY "${build_dir}") # check directory permissions
  217. # Disabling languages speeds up a little bit, reduces noise in the output
  218. # and avoids path too long windows error
  219. file(
  220. WRITE
  221. "${cmakelists}"
  222. "cmake_minimum_required(VERSION 3.2)\n"
  223. "project(HunterDownload LANGUAGES NONE)\n"
  224. "include(ExternalProject)\n"
  225. "ExternalProject_Add(\n"
  226. " Hunter\n"
  227. " URL\n"
  228. " \"${HUNTER_GATE_URL}\"\n"
  229. " URL_HASH\n"
  230. " SHA1=${HUNTER_GATE_SHA1}\n"
  231. " DOWNLOAD_DIR\n"
  232. " \"${dir}\"\n"
  233. " TLS_VERIFY\n"
  234. " ${HUNTER_TLS_VERIFY}\n"
  235. " SOURCE_DIR\n"
  236. " \"${dir}/Unpacked\"\n"
  237. " CONFIGURE_COMMAND\n"
  238. " \"\"\n"
  239. " BUILD_COMMAND\n"
  240. " \"\"\n"
  241. " INSTALL_COMMAND\n"
  242. " \"\"\n"
  243. ")\n"
  244. )
  245. if(HUNTER_STATUS_DEBUG)
  246. set(logging_params "")
  247. else()
  248. set(logging_params OUTPUT_QUIET)
  249. endif()
  250. hunter_gate_status_debug("Run generate")
  251. # Need to add toolchain file too.
  252. # Otherwise on Visual Studio + MDD this will fail with error:
  253. # "Could not find an appropriate version of the Windows 10 SDK installed on this machine"
  254. if(EXISTS "${CMAKE_TOOLCHAIN_FILE}")
  255. get_filename_component(absolute_CMAKE_TOOLCHAIN_FILE "${CMAKE_TOOLCHAIN_FILE}" ABSOLUTE)
  256. set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=${absolute_CMAKE_TOOLCHAIN_FILE}")
  257. else()
  258. # 'toolchain_arg' can't be empty
  259. set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=")
  260. endif()
  261. string(COMPARE EQUAL "${CMAKE_MAKE_PROGRAM}" "" no_make)
  262. if(no_make)
  263. set(make_arg "")
  264. else()
  265. # Test case: remove Ninja from PATH but set it via CMAKE_MAKE_PROGRAM
  266. set(make_arg "-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}")
  267. endif()
  268. execute_process(
  269. COMMAND
  270. "${CMAKE_COMMAND}"
  271. "-H${dir}"
  272. "-B${build_dir}"
  273. "-G${CMAKE_GENERATOR}"
  274. "${toolchain_arg}"
  275. ${make_arg}
  276. WORKING_DIRECTORY "${dir}"
  277. RESULT_VARIABLE download_result
  278. ${logging_params}
  279. )
  280. if(NOT download_result EQUAL 0)
  281. hunter_gate_internal_error(
  282. "Configure project failed."
  283. "To reproduce the error run: ${CMAKE_COMMAND} -H${dir} -B${build_dir} -G${CMAKE_GENERATOR} ${toolchain_arg} ${make_arg}"
  284. "In directory ${dir}"
  285. )
  286. endif()
  287. hunter_gate_status_print(
  288. "Initializing Hunter workspace (${HUNTER_GATE_SHA1})"
  289. " ${HUNTER_GATE_URL}"
  290. " -> ${dir}"
  291. )
  292. execute_process(
  293. COMMAND "${CMAKE_COMMAND}" --build "${build_dir}"
  294. WORKING_DIRECTORY "${dir}"
  295. RESULT_VARIABLE download_result
  296. ${logging_params}
  297. )
  298. if(NOT download_result EQUAL 0)
  299. hunter_gate_internal_error("Build project failed")
  300. endif()
  301. file(REMOVE_RECURSE "${build_dir}")
  302. file(REMOVE_RECURSE "${cmakelists}")
  303. file(WRITE "${sha1_location}" "${HUNTER_GATE_SHA1}")
  304. file(WRITE "${done_location}" "DONE")
  305. hunter_gate_status_debug("Finished")
  306. endfunction()
  307. # Must be a macro so master file 'cmake/Hunter' can
  308. # apply all variables easily just by 'include' command
  309. # (otherwise PARENT_SCOPE magic needed)
  310. macro(HunterGate)
  311. if(HUNTER_GATE_DONE)
  312. # variable HUNTER_GATE_DONE set explicitly for external project
  313. # (see `hunter_download`)
  314. set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES)
  315. endif()
  316. # First HunterGate command will init Hunter, others will be ignored
  317. get_property(_hunter_gate_done GLOBAL PROPERTY HUNTER_GATE_DONE SET)
  318. if(NOT HUNTER_ENABLED)
  319. # Empty function to avoid error "unknown function"
  320. function(hunter_add_package)
  321. endfunction()
  322. set(
  323. _hunter_gate_disabled_mode_dir
  324. "${CMAKE_CURRENT_LIST_DIR}/cmake/Hunter/disabled-mode"
  325. )
  326. if(EXISTS "${_hunter_gate_disabled_mode_dir}")
  327. hunter_gate_status_debug(
  328. "Adding \"disabled-mode\" modules: ${_hunter_gate_disabled_mode_dir}"
  329. )
  330. list(APPEND CMAKE_PREFIX_PATH "${_hunter_gate_disabled_mode_dir}")
  331. endif()
  332. elseif(_hunter_gate_done)
  333. hunter_gate_status_debug("Secondary HunterGate (use old settings)")
  334. hunter_gate_self(
  335. "${HUNTER_CACHED_ROOT}"
  336. "${HUNTER_VERSION}"
  337. "${HUNTER_SHA1}"
  338. _hunter_self
  339. )
  340. include("${_hunter_self}/cmake/Hunter")
  341. else()
  342. set(HUNTER_GATE_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}")
  343. string(COMPARE NOTEQUAL "${PROJECT_NAME}" "" _have_project_name)
  344. if(_have_project_name)
  345. hunter_gate_fatal_error(
  346. "Please set HunterGate *before* 'project' command. "
  347. "Detected project: ${PROJECT_NAME}"
  348. ERROR_PAGE "error.huntergate.before.project"
  349. )
  350. endif()
  351. cmake_parse_arguments(
  352. HUNTER_GATE "LOCAL" "URL;SHA1;GLOBAL;FILEPATH" "" ${ARGV}
  353. )
  354. string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" _empty_sha1)
  355. string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" _empty_url)
  356. string(
  357. COMPARE
  358. NOTEQUAL
  359. "${HUNTER_GATE_UNPARSED_ARGUMENTS}"
  360. ""
  361. _have_unparsed
  362. )
  363. string(COMPARE NOTEQUAL "${HUNTER_GATE_GLOBAL}" "" _have_global)
  364. string(COMPARE NOTEQUAL "${HUNTER_GATE_FILEPATH}" "" _have_filepath)
  365. if(_have_unparsed)
  366. hunter_gate_user_error(
  367. "HunterGate unparsed arguments: ${HUNTER_GATE_UNPARSED_ARGUMENTS}"
  368. )
  369. endif()
  370. if(_empty_sha1)
  371. hunter_gate_user_error("SHA1 suboption of HunterGate is mandatory")
  372. endif()
  373. if(_empty_url)
  374. hunter_gate_user_error("URL suboption of HunterGate is mandatory")
  375. endif()
  376. if(_have_global)
  377. if(HUNTER_GATE_LOCAL)
  378. hunter_gate_user_error("Unexpected LOCAL (already has GLOBAL)")
  379. endif()
  380. if(_have_filepath)
  381. hunter_gate_user_error("Unexpected FILEPATH (already has GLOBAL)")
  382. endif()
  383. endif()
  384. if(HUNTER_GATE_LOCAL)
  385. if(_have_global)
  386. hunter_gate_user_error("Unexpected GLOBAL (already has LOCAL)")
  387. endif()
  388. if(_have_filepath)
  389. hunter_gate_user_error("Unexpected FILEPATH (already has LOCAL)")
  390. endif()
  391. endif()
  392. if(_have_filepath)
  393. if(_have_global)
  394. hunter_gate_user_error("Unexpected GLOBAL (already has FILEPATH)")
  395. endif()
  396. if(HUNTER_GATE_LOCAL)
  397. hunter_gate_user_error("Unexpected LOCAL (already has FILEPATH)")
  398. endif()
  399. endif()
  400. hunter_gate_detect_root() # set HUNTER_GATE_ROOT
  401. # Beautify path, fix probable problems with windows path slashes
  402. get_filename_component(
  403. HUNTER_GATE_ROOT "${HUNTER_GATE_ROOT}" ABSOLUTE
  404. )
  405. hunter_gate_status_debug("HUNTER_ROOT: ${HUNTER_GATE_ROOT}")
  406. if(NOT HUNTER_ALLOW_SPACES_IN_PATH)
  407. string(FIND "${HUNTER_GATE_ROOT}" " " _contain_spaces)
  408. if(NOT _contain_spaces EQUAL -1)
  409. hunter_gate_fatal_error(
  410. "HUNTER_ROOT (${HUNTER_GATE_ROOT}) contains spaces."
  411. "Set HUNTER_ALLOW_SPACES_IN_PATH=ON to skip this error"
  412. "(Use at your own risk!)"
  413. ERROR_PAGE "error.spaces.in.hunter.root"
  414. )
  415. endif()
  416. endif()
  417. string(
  418. REGEX
  419. MATCH
  420. "[0-9]+\\.[0-9]+\\.[0-9]+[-_a-z0-9]*"
  421. HUNTER_GATE_VERSION
  422. "${HUNTER_GATE_URL}"
  423. )
  424. string(COMPARE EQUAL "${HUNTER_GATE_VERSION}" "" _is_empty)
  425. if(_is_empty)
  426. set(HUNTER_GATE_VERSION "unknown")
  427. endif()
  428. hunter_gate_self(
  429. "${HUNTER_GATE_ROOT}"
  430. "${HUNTER_GATE_VERSION}"
  431. "${HUNTER_GATE_SHA1}"
  432. _hunter_self
  433. )
  434. set(_master_location "${_hunter_self}/cmake/Hunter")
  435. if(EXISTS "${HUNTER_GATE_ROOT}/cmake/Hunter")
  436. # Hunter downloaded manually (e.g. by 'git clone')
  437. set(_unused "xxxxxxxxxx")
  438. set(HUNTER_GATE_SHA1 "${_unused}")
  439. set(HUNTER_GATE_VERSION "${_unused}")
  440. else()
  441. get_filename_component(_archive_id_location "${_hunter_self}/.." ABSOLUTE)
  442. set(_done_location "${_archive_id_location}/DONE")
  443. set(_sha1_location "${_archive_id_location}/SHA1")
  444. # Check Hunter already downloaded by HunterGate
  445. if(NOT EXISTS "${_done_location}")
  446. hunter_gate_download("${_archive_id_location}")
  447. endif()
  448. if(NOT EXISTS "${_done_location}")
  449. hunter_gate_internal_error("hunter_gate_download failed")
  450. endif()
  451. if(NOT EXISTS "${_sha1_location}")
  452. hunter_gate_internal_error("${_sha1_location} not found")
  453. endif()
  454. file(READ "${_sha1_location}" _sha1_value)
  455. string(TOLOWER "${_sha1_value}" _sha1_value_lower)
  456. string(TOLOWER "${HUNTER_GATE_SHA1}" _HUNTER_GATE_SHA1_lower)
  457. string(COMPARE EQUAL "${_sha1_value_lower}" "${_HUNTER_GATE_SHA1_lower}" _is_equal)
  458. if(NOT _is_equal)
  459. hunter_gate_internal_error(
  460. "Short SHA1 collision:"
  461. " ${_sha1_value} (from ${_sha1_location})"
  462. " ${HUNTER_GATE_SHA1} (HunterGate)"
  463. )
  464. endif()
  465. if(NOT EXISTS "${_master_location}")
  466. hunter_gate_user_error(
  467. "Master file not found:"
  468. " ${_master_location}"
  469. "try to update Hunter/HunterGate"
  470. )
  471. endif()
  472. endif()
  473. include("${_master_location}")
  474. set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES)
  475. endif()
  476. endmacro()