HunterGate.cmake 17 KB

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