shared_internal_commands.cmake 58 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979
  1. cmake_policy(VERSION 3.25)
  2. # Determine the remote URL of the project containing the working_directory.
  3. # This will leave output_variable unset if the URL can't be determined.
  4. function(_ep_get_git_remote_url output_variable working_directory)
  5. set("${output_variable}" "" PARENT_SCOPE)
  6. find_package(Git QUIET REQUIRED)
  7. execute_process(
  8. COMMAND ${GIT_EXECUTABLE} symbolic-ref --short HEAD
  9. WORKING_DIRECTORY "${working_directory}"
  10. OUTPUT_VARIABLE git_symbolic_ref
  11. OUTPUT_STRIP_TRAILING_WHITESPACE
  12. ERROR_QUIET
  13. )
  14. if(NOT git_symbolic_ref STREQUAL "")
  15. # We are potentially on a branch. See if that branch is associated with
  16. # an upstream remote (might be just a local one or not a branch at all).
  17. execute_process(
  18. COMMAND ${GIT_EXECUTABLE} config branch.${git_symbolic_ref}.remote
  19. WORKING_DIRECTORY "${working_directory}"
  20. OUTPUT_VARIABLE git_remote_name
  21. OUTPUT_STRIP_TRAILING_WHITESPACE
  22. ERROR_QUIET
  23. )
  24. endif()
  25. if(NOT git_remote_name)
  26. # Can't select a remote based on a branch. If there's only one remote,
  27. # or we have multiple remotes but one is called "origin", choose that.
  28. execute_process(
  29. COMMAND ${GIT_EXECUTABLE} remote
  30. WORKING_DIRECTORY "${working_directory}"
  31. OUTPUT_VARIABLE git_remote_list
  32. OUTPUT_STRIP_TRAILING_WHITESPACE
  33. ERROR_QUIET
  34. )
  35. string(REPLACE "\n" ";" git_remote_list "${git_remote_list}")
  36. list(LENGTH git_remote_list git_remote_list_length)
  37. if(git_remote_list_length EQUAL 0)
  38. message(FATAL_ERROR "Git remote not found in parent project.")
  39. elseif(git_remote_list_length EQUAL 1)
  40. list(GET git_remote_list 0 git_remote_name)
  41. else()
  42. set(base_warning_msg "Multiple git remotes found for parent project")
  43. if("origin" IN_LIST git_remote_list)
  44. message(WARNING "${base_warning_msg}, defaulting to origin.")
  45. set(git_remote_name "origin")
  46. else()
  47. message(FATAL_ERROR "${base_warning_msg}, none of which are origin.")
  48. endif()
  49. endif()
  50. endif()
  51. if(GIT_VERSION VERSION_LESS 1.7.5)
  52. set(_git_remote_url_cmd_args config remote.${git_remote_name}.url)
  53. elseif(GIT_VERSION VERSION_LESS 2.7)
  54. set(_git_remote_url_cmd_args ls-remote --get-url ${git_remote_name})
  55. else()
  56. set(_git_remote_url_cmd_args remote get-url ${git_remote_name})
  57. endif()
  58. execute_process(
  59. COMMAND ${GIT_EXECUTABLE} ${_git_remote_url_cmd_args}
  60. WORKING_DIRECTORY "${working_directory}"
  61. OUTPUT_VARIABLE git_remote_url
  62. OUTPUT_STRIP_TRAILING_WHITESPACE
  63. COMMAND_ERROR_IS_FATAL LAST
  64. ENCODING UTF-8 # Needed to handle non-ascii characters in local paths
  65. )
  66. set("${output_variable}" "${git_remote_url}" PARENT_SCOPE)
  67. endfunction()
  68. function(_ep_is_relative_git_remote output_variable remote_url)
  69. if(remote_url MATCHES "^\\.\\./")
  70. set("${output_variable}" TRUE PARENT_SCOPE)
  71. else()
  72. set("${output_variable}" FALSE PARENT_SCOPE)
  73. endif()
  74. endfunction()
  75. # Return an absolute remote URL given an existing remote URL and relative path.
  76. # The output_variable will be set to an empty string if an absolute URL
  77. # could not be computed (no error message is output).
  78. function(_ep_resolve_relative_git_remote
  79. output_variable
  80. parent_remote_url
  81. relative_remote_url
  82. )
  83. set("${output_variable}" "" PARENT_SCOPE)
  84. if(parent_remote_url STREQUAL "")
  85. return()
  86. endif()
  87. string(REGEX MATCH
  88. "^(([A-Za-z0-9][A-Za-z0-9+.-]*)://)?(([^/@]+)@)?(\\[[A-Za-z0-9:]+\\]|[^/:]+)?([/:]/?)(.+(\\.git)?/?)$"
  89. git_remote_url_components
  90. "${parent_remote_url}"
  91. )
  92. set(protocol "${CMAKE_MATCH_1}")
  93. set(auth "${CMAKE_MATCH_3}")
  94. set(host "${CMAKE_MATCH_5}")
  95. set(separator "${CMAKE_MATCH_6}")
  96. set(path "${CMAKE_MATCH_7}")
  97. string(REPLACE "/" ";" remote_path_components "${path}")
  98. string(REPLACE "/" ";" relative_path_components "${relative_remote_url}")
  99. foreach(relative_path_component IN LISTS relative_path_components)
  100. if(NOT relative_path_component STREQUAL "..")
  101. break()
  102. endif()
  103. list(LENGTH remote_path_components remote_path_component_count)
  104. if(remote_path_component_count LESS 1)
  105. return()
  106. endif()
  107. list(POP_BACK remote_path_components)
  108. list(POP_FRONT relative_path_components)
  109. endforeach()
  110. list(APPEND final_path_components ${remote_path_components} ${relative_path_components})
  111. list(JOIN final_path_components "/" path)
  112. set("${output_variable}" "${protocol}${auth}${host}${separator}${path}" PARENT_SCOPE)
  113. endfunction()
  114. # The output_variable will be set to the original git_repository if it
  115. # could not be resolved (no error message is output). The original value is
  116. # also returned if it doesn't need to be resolved.
  117. function(_ep_resolve_git_remote
  118. output_variable
  119. git_repository
  120. cmp0150
  121. cmp0150_old_base_dir
  122. )
  123. if(git_repository STREQUAL "")
  124. set("${output_variable}" "" PARENT_SCOPE)
  125. return()
  126. endif()
  127. _ep_is_relative_git_remote(_git_repository_is_relative "${git_repository}")
  128. if(NOT _git_repository_is_relative)
  129. set("${output_variable}" "${git_repository}" PARENT_SCOPE)
  130. return()
  131. endif()
  132. if(cmp0150 STREQUAL "NEW")
  133. _ep_get_git_remote_url(_parent_git_remote_url "${CMAKE_CURRENT_SOURCE_DIR}")
  134. _ep_resolve_relative_git_remote(_resolved_git_remote_url "${_parent_git_remote_url}" "${git_repository}")
  135. if(_resolved_git_remote_url STREQUAL "")
  136. message(FATAL_ERROR
  137. "Failed to resolve relative git remote URL:\n"
  138. " Relative URL: ${git_repository}\n"
  139. " Parent URL: ${_parent_git_remote_url}"
  140. )
  141. endif()
  142. set("${output_variable}" "${_resolved_git_remote_url}" PARENT_SCOPE)
  143. return()
  144. elseif(cmp0150 STREQUAL "")
  145. cmake_policy(GET_WARNING CMP0150 _cmp0150_warning)
  146. message(AUTHOR_WARNING
  147. "${_cmp0150_warning}\n"
  148. "A relative GIT_REPOSITORY path was detected. "
  149. "This will be interpreted as a local path to where the project is being cloned. "
  150. "Set GIT_REPOSITORY to an absolute path or set policy CMP0150 to NEW to avoid "
  151. "this warning."
  152. )
  153. endif()
  154. set("${output_variable}" "${cmp0150_old_base_dir}/${git_repository}" PARENT_SCOPE)
  155. endfunction()
  156. macro(_ep_get_hash_algos out_var)
  157. set(${out_var}
  158. MD5
  159. SHA1
  160. SHA224
  161. SHA256
  162. SHA384
  163. SHA512
  164. SHA3_224
  165. SHA3_256
  166. SHA3_384
  167. SHA3_512
  168. )
  169. endmacro()
  170. macro(_ep_get_hash_regex out_var)
  171. _ep_get_hash_algos(${out_var})
  172. list(JOIN ${out_var} "|" ${out_var})
  173. set(${out_var} "^(${${out_var}})=([0-9A-Fa-f]+)$")
  174. endmacro()
  175. function(_ep_parse_arguments_to_vars
  176. f
  177. keywords
  178. name
  179. ns
  180. args
  181. )
  182. # Transfer the arguments into variables in the calling scope.
  183. # Because some keywords can be repeated, we can't use cmake_parse_arguments().
  184. # Instead, we loop through the args and consider the namespace starting with
  185. # an upper-case letter followed by at least two more upper-case letters,
  186. # numbers or underscores to be keywords.
  187. foreach(key IN LISTS keywords)
  188. unset(${ns}${key})
  189. endforeach()
  190. set(key)
  191. foreach(arg IN LISTS args)
  192. set(is_value 1)
  193. if(arg MATCHES "^[A-Z][A-Z0-9_][A-Z0-9_]+$" AND
  194. NOT (("x${arg}x" STREQUAL "x${key}x") AND
  195. ("x${key}x" STREQUAL "xCOMMANDx")) AND
  196. NOT arg MATCHES "^(TRUE|FALSE|YES)$")
  197. if(arg IN_LIST keywords)
  198. set(is_value 0)
  199. endif()
  200. endif()
  201. if(is_value)
  202. if(key)
  203. # Value
  204. list(APPEND ${ns}${key} "${arg}")
  205. else()
  206. # Missing Keyword
  207. message(AUTHOR_WARNING
  208. "value '${arg}' with no previous keyword in ${f}"
  209. )
  210. endif()
  211. else()
  212. set(key "${arg}")
  213. endif()
  214. endforeach()
  215. foreach(key IN LISTS keywords)
  216. if(DEFINED ${ns}${key})
  217. set(${ns}${key} "${${ns}${key}}" PARENT_SCOPE)
  218. else()
  219. unset(${ns}${key} PARENT_SCOPE)
  220. endif()
  221. endforeach()
  222. endfunction()
  223. # NOTE: This cannot be a macro because that will evaluate anything that looks
  224. # like a CMake variable in any of the args.
  225. function(_ep_parse_arguments
  226. f
  227. keywords
  228. name
  229. ns
  230. args
  231. )
  232. _ep_parse_arguments_to_vars(
  233. "${f}"
  234. "${keywords}"
  235. ${name}
  236. ${ns}
  237. "${args}"
  238. )
  239. foreach(key IN LISTS keywords)
  240. if(DEFINED ${ns}${key})
  241. set(${ns}${key} "${${ns}${key}}" PARENT_SCOPE)
  242. else()
  243. unset(${ns}${key} PARENT_SCOPE)
  244. endif()
  245. endforeach()
  246. # Transfer the arguments to the target as target properties. These are
  247. # read by the various steps, potentially from different scopes.
  248. foreach(key IN LISTS keywords)
  249. if(DEFINED ${ns}${key})
  250. set_property(TARGET ${name} PROPERTY ${ns}${key} "${${ns}${key}}")
  251. endif()
  252. endforeach()
  253. endfunction()
  254. function(_ep_get_tls_version name tls_version_var)
  255. # Note that the arguments are assumed to have already been parsed and have
  256. # been translated into variables with the prefix _EP_... by a call to
  257. # ep_parse_arguments() or ep_parse_arguments_to_vars().
  258. set(tls_version_regex "^1\\.[0-3]$")
  259. set(tls_version "${_EP_TLS_VERSION}")
  260. if(NOT "x${tls_version}" STREQUAL "x")
  261. if(NOT tls_version MATCHES "${tls_version_regex}")
  262. message(FATAL_ERROR "TLS_VERSION '${tls_version}' not known")
  263. endif()
  264. elseif(NOT "x${CMAKE_TLS_VERSION}" STREQUAL "x")
  265. set(tls_version "${CMAKE_TLS_VERSION}")
  266. if(NOT tls_version MATCHES "${tls_version_regex}")
  267. message(FATAL_ERROR "CMAKE_TLS_VERSION '${tls_version}' not known")
  268. endif()
  269. elseif(NOT "x$ENV{CMAKE_TLS_VERSION}" STREQUAL "x")
  270. set(tls_version "$ENV{CMAKE_TLS_VERSION}")
  271. if(NOT tls_version MATCHES "${tls_version_regex}")
  272. message(FATAL_ERROR "ENV{CMAKE_TLS_VERSION} '${tls_version}' not known")
  273. endif()
  274. endif()
  275. set("${tls_version_var}" "${tls_version}" PARENT_SCOPE)
  276. endfunction()
  277. function(_ep_get_tls_verify name tls_verify_var)
  278. # Note that the arguments are assumed to have already been parsed and have
  279. # been translated into variables with the prefix _EP_... by a call to
  280. # ep_parse_arguments() or ep_parse_arguments_to_vars().
  281. set(tls_verify "${_EP_TLS_VERIFY}")
  282. if("x${tls_verify}" STREQUAL "x")
  283. if(NOT "x${CMAKE_TLS_VERIFY}" STREQUAL "x")
  284. set(tls_verify "${CMAKE_TLS_VERIFY}")
  285. elseif(NOT "x$ENV{CMAKE_TLS_VERIFY}" STREQUAL "x")
  286. set(tls_verify "$ENV{CMAKE_TLS_VERIFY}")
  287. endif()
  288. endif()
  289. set("${tls_verify_var}" "${tls_verify}" PARENT_SCOPE)
  290. endfunction()
  291. function(_ep_get_tls_cainfo name tls_cainfo_var)
  292. # Note that the arguments are assumed to have already been parsed and have
  293. # been translated into variables with the prefix _EP_... by a call to
  294. # ep_parse_arguments() or ep_parse_arguments_to_vars().
  295. set(tls_cainfo "${_EP_TLS_CAINFO}")
  296. if("x${tls_cainfo}" STREQUAL "x" AND DEFINED CMAKE_TLS_CAINFO)
  297. set(tls_cainfo "${CMAKE_TLS_CAINFO}")
  298. endif()
  299. set("${tls_cainfo_var}" "${tls_cainfo}" PARENT_SCOPE)
  300. endfunction()
  301. function(_ep_get_netrc name netrc_var)
  302. # Note that the arguments are assumed to have already been parsed and have
  303. # been translated into variables with the prefix _EP_... by a call to
  304. # ep_parse_arguments() or ep_parse_arguments_to_vars().
  305. set(netrc "${_EP_NETRC}")
  306. if("x${netrc}" STREQUAL "x" AND DEFINED CMAKE_NETRC)
  307. set(netrc "${CMAKE_NETRC}")
  308. endif()
  309. set("${netrc_var}" "${netrc}" PARENT_SCOPE)
  310. endfunction()
  311. function(_ep_get_netrc_file name netrc_file_var)
  312. # Note that the arguments are assumed to have already been parsed and have
  313. # been translated into variables with the prefix _EP_... by a call to
  314. # ep_parse_arguments() or ep_parse_arguments_to_vars().
  315. set(netrc_file "${_EP_NETRC_FILE}")
  316. if("x${netrc_file}" STREQUAL "x" AND DEFINED CMAKE_NETRC_FILE)
  317. set(netrc_file "${CMAKE_NETRC_FILE}")
  318. endif()
  319. set("${netrc_file_var}" "${netrc_file}" PARENT_SCOPE)
  320. endfunction()
  321. function(_ep_write_gitclone_script
  322. script_filename
  323. source_dir
  324. git_EXECUTABLE
  325. git_repository
  326. git_tag
  327. git_remote_name
  328. init_submodules
  329. git_submodules_recurse
  330. git_submodules
  331. git_shallow
  332. git_progress
  333. git_config
  334. src_name
  335. work_dir
  336. gitclone_infofile
  337. gitclone_stampfile
  338. tls_version
  339. tls_verify
  340. )
  341. if(NOT GIT_VERSION_STRING VERSION_LESS 1.8.5)
  342. # Use `git checkout <tree-ish> --` to avoid ambiguity with a local path.
  343. set(git_checkout_explicit-- "--")
  344. else()
  345. # Use `git checkout <branch>` even though this risks ambiguity with a
  346. # local path. Unfortunately we cannot use `git checkout <tree-ish> --`
  347. # because that will not search for remote branch names, a common use case.
  348. set(git_checkout_explicit-- "")
  349. endif()
  350. if("${git_tag}" STREQUAL "")
  351. message(FATAL_ERROR "Tag for git checkout should not be empty.")
  352. endif()
  353. if(GIT_VERSION_STRING VERSION_LESS 2.20 OR
  354. 2.21 VERSION_LESS_EQUAL GIT_VERSION_STRING)
  355. set(git_clone_options "--no-checkout")
  356. else()
  357. set(git_clone_options)
  358. endif()
  359. if(git_shallow)
  360. if(NOT GIT_VERSION_STRING VERSION_LESS 1.7.10)
  361. list(APPEND git_clone_options "--depth 1 --no-single-branch")
  362. else()
  363. list(APPEND git_clone_options "--depth 1")
  364. endif()
  365. endif()
  366. if(git_progress)
  367. list(APPEND git_clone_options --progress)
  368. endif()
  369. foreach(config IN LISTS git_config)
  370. list(APPEND git_clone_options --config \"${config}\")
  371. endforeach()
  372. if(NOT ${git_remote_name} STREQUAL "origin")
  373. list(APPEND git_clone_options --origin \"${git_remote_name}\")
  374. endif()
  375. # The clone config option is sticky, it will apply to all subsequent git
  376. # update operations. The submodules config option is not sticky, because
  377. # git doesn't provide any way to do that. Thus, we will have to pass the
  378. # same config option in the update step too for submodules, but not for
  379. # the main git repo.
  380. set(git_submodules_config_options "")
  381. if(NOT "x${tls_version}" STREQUAL "x")
  382. list(APPEND git_clone_options -c http.sslVersion=tlsv${tls_version})
  383. list(APPEND git_submodules_config_options -c http.sslVersion=tlsv${tls_version})
  384. endif()
  385. if(NOT "x${tls_verify}" STREQUAL "x")
  386. if(tls_verify)
  387. # Default git behavior is "true", but the user might have changed the
  388. # global default to "false". Since TLS_VERIFY was given, ensure we honor
  389. # the specified setting regardless of what the global default might be.
  390. list(APPEND git_clone_options -c http.sslVerify=true)
  391. list(APPEND git_submodules_config_options -c http.sslVerify=true)
  392. else()
  393. list(APPEND git_clone_options -c http.sslVerify=false)
  394. list(APPEND git_submodules_config_options -c http.sslVerify=false)
  395. endif()
  396. endif()
  397. string (REPLACE ";" " " git_clone_options "${git_clone_options}")
  398. configure_file(
  399. ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/gitclone.cmake.in
  400. ${script_filename}
  401. @ONLY
  402. )
  403. endfunction()
  404. function(_ep_write_hgclone_script
  405. script_filename
  406. source_dir
  407. hg_EXECUTABLE
  408. hg_repository
  409. hg_tag
  410. src_name
  411. work_dir
  412. hgclone_infofile
  413. hgclone_stampfile
  414. )
  415. if("${hg_tag}" STREQUAL "")
  416. message(FATAL_ERROR "Tag for hg checkout should not be empty.")
  417. endif()
  418. configure_file(
  419. ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/hgclone.cmake.in
  420. ${script_filename}
  421. @ONLY
  422. )
  423. endfunction()
  424. function(_ep_write_gitupdate_script
  425. script_filename
  426. git_EXECUTABLE
  427. git_tag
  428. git_remote_name
  429. init_submodules
  430. git_submodules_recurse
  431. git_submodules
  432. git_repository
  433. work_dir
  434. git_update_strategy
  435. tls_version
  436. tls_verify
  437. )
  438. if("${git_tag}" STREQUAL "")
  439. message(FATAL_ERROR "Tag for git checkout should not be empty.")
  440. endif()
  441. set(git_stash_save_options --quiet)
  442. if(GIT_VERSION_STRING VERSION_GREATER_EQUAL 1.7.7)
  443. # This avoids stashing files covered by .gitignore
  444. list(APPEND git_stash_save_options --include-untracked)
  445. elseif(GIT_VERSION_STRING VERSION_GREATER_EQUAL 1.7.6)
  446. # Untracked files, but also ignored files, so potentially slower
  447. list(APPEND git_stash_save_options --all)
  448. endif()
  449. # The submodules config option is not sticky, git doesn't provide any way
  450. # to do that. We have to pass this config option for the update step too.
  451. # We don't need to set it for the non-submodule update because it gets
  452. # recorded as part of the clone operation in a sticky manner.
  453. set(git_submodules_config_options "")
  454. if(NOT "x${tls_version}" STREQUAL "x")
  455. list(APPEND git_submodules_config_options -c http.sslVersion=tlsv${tls_version})
  456. endif()
  457. if(NOT "x${tls_verify}" STREQUAL "x")
  458. if(tls_verify)
  459. # Default git behavior is "true", but the user might have changed the
  460. # global default to "false". Since TLS_VERIFY was given, ensure we honor
  461. # the specified setting regardless of what the global default might be.
  462. list(APPEND git_submodules_config_options -c http.sslVerify=true)
  463. else()
  464. list(APPEND git_submodules_config_options -c http.sslVerify=false)
  465. endif()
  466. endif()
  467. configure_file(
  468. "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/gitupdate.cmake.in"
  469. "${script_filename}"
  470. @ONLY
  471. )
  472. endfunction()
  473. function(_ep_write_downloadfile_script
  474. script_filename
  475. REMOTE
  476. LOCAL
  477. timeout
  478. inactivity_timeout
  479. no_progress
  480. hash
  481. tls_version
  482. tls_verify
  483. tls_cainfo
  484. userpwd
  485. http_headers
  486. netrc
  487. netrc_file
  488. )
  489. if("x${REMOTE}" STREQUAL "x")
  490. message(FATAL_ERROR "REMOTE can't be empty")
  491. endif()
  492. if("x${LOCAL}" STREQUAL "x")
  493. message(FATAL_ERROR "LOCAL can't be empty")
  494. endif()
  495. # REMOTE could contain special characters that parse as separate arguments.
  496. # Things like parentheses are legitimate characters in a URL, but would be
  497. # seen as the start of a new unquoted argument by the cmake language parser.
  498. # Avoid those special cases by preparing quoted strings for direct inclusion
  499. # in the foreach() call that iterates over the set of URLs in REMOTE.
  500. set(REMOTE "[====[${REMOTE}]====]")
  501. string(REPLACE ";" "]====] [====[" REMOTE "${REMOTE}")
  502. if(timeout)
  503. set(TIMEOUT_ARGS TIMEOUT ${timeout})
  504. set(TIMEOUT_MSG "${timeout} seconds")
  505. else()
  506. set(TIMEOUT_ARGS "# no TIMEOUT")
  507. set(TIMEOUT_MSG "none")
  508. endif()
  509. if(inactivity_timeout)
  510. set(INACTIVITY_TIMEOUT_ARGS INACTIVITY_TIMEOUT ${inactivity_timeout})
  511. set(INACTIVITY_TIMEOUT_MSG "${inactivity_timeout} seconds")
  512. else()
  513. set(INACTIVITY_TIMEOUT_ARGS "# no INACTIVITY_TIMEOUT")
  514. set(INACTIVITY_TIMEOUT_MSG "none")
  515. endif()
  516. if(no_progress)
  517. set(SHOW_PROGRESS "")
  518. else()
  519. set(SHOW_PROGRESS "SHOW_PROGRESS")
  520. endif()
  521. _ep_get_hash_regex(_ep_hash_regex)
  522. if("${hash}" MATCHES "${_ep_hash_regex}")
  523. set(ALGO "${CMAKE_MATCH_1}")
  524. string(TOLOWER "${CMAKE_MATCH_2}" EXPECT_VALUE)
  525. else()
  526. set(ALGO "")
  527. set(EXPECT_VALUE "")
  528. endif()
  529. set(TLS_VERSION_CODE "")
  530. if(NOT "x${tls_version}" STREQUAL "x")
  531. set(TLS_VERSION_CODE "set(CMAKE_TLS_VERSION \"${tls_version}\")")
  532. endif()
  533. set(TLS_VERIFY_CODE "")
  534. if(NOT "x${tls_verify}" STREQUAL "x")
  535. set(TLS_VERIFY_CODE "set(CMAKE_TLS_VERIFY \"${tls_verify}\")")
  536. endif()
  537. set(TLS_CAINFO_CODE "")
  538. if(NOT "x${tls_cainfo}" STREQUAL "x")
  539. set(TLS_CAINFO_CODE "set(CMAKE_TLS_CAINFO \"${tls_cainfo}\")")
  540. endif()
  541. set(NETRC_CODE "")
  542. if(NOT "x${netrc}" STREQUAL "x")
  543. set(NETRC_CODE "set(CMAKE_NETRC \"${netrc}\")")
  544. endif()
  545. set(NETRC_FILE_CODE "")
  546. if(NOT "x${netrc_file}" STREQUAL "x")
  547. set(NETRC_FILE_CODE "set(CMAKE_NETRC_FILE \"${netrc_file}\")")
  548. endif()
  549. if(userpwd STREQUAL ":")
  550. set(USERPWD_ARGS)
  551. else()
  552. set(USERPWD_ARGS USERPWD "${userpwd}")
  553. endif()
  554. set(HTTP_HEADERS_ARGS "")
  555. if(NOT http_headers STREQUAL "")
  556. foreach(header IN LISTS http_headers)
  557. string(PREPEND HTTP_HEADERS_ARGS
  558. "HTTPHEADER \"${header}\"\n "
  559. )
  560. endforeach()
  561. endif()
  562. # Used variables:
  563. # * TLS_VERSION_CODE
  564. # * TLS_VERIFY_CODE
  565. # * TLS_CAINFO_CODE
  566. # * ALGO
  567. # * EXPECT_VALUE
  568. # * REMOTE
  569. # * LOCAL
  570. # * SHOW_PROGRESS
  571. # * TIMEOUT_ARGS
  572. # * TIMEOUT_MSG
  573. # * USERPWD_ARGS
  574. # * HTTP_HEADERS_ARGS
  575. configure_file(
  576. "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/download.cmake.in"
  577. "${script_filename}"
  578. @ONLY
  579. )
  580. endfunction()
  581. function(_ep_write_verifyfile_script
  582. script_filename
  583. LOCAL
  584. hash
  585. )
  586. _ep_get_hash_regex(_ep_hash_regex)
  587. if("${hash}" MATCHES "${_ep_hash_regex}")
  588. set(ALGO "${CMAKE_MATCH_1}")
  589. string(TOLOWER "${CMAKE_MATCH_2}" EXPECT_VALUE)
  590. else()
  591. set(ALGO "")
  592. set(EXPECT_VALUE "")
  593. endif()
  594. # Used variables:
  595. # * ALGO
  596. # * EXPECT_VALUE
  597. # * LOCAL
  598. configure_file(
  599. "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/verify.cmake.in"
  600. "${script_filename}"
  601. @ONLY
  602. )
  603. endfunction()
  604. function(_ep_write_extractfile_script
  605. script_filename
  606. name
  607. filename
  608. directory
  609. options
  610. )
  611. set(args "")
  612. if(filename MATCHES
  613. "(\\.|=)(7z|tar\\.bz2|tar\\.gz|tar\\.xz|tbz2|tgz|txz|zip)$")
  614. set(args xfz)
  615. endif()
  616. if(filename MATCHES "(\\.|=)tar$")
  617. set(args xf)
  618. endif()
  619. if(args STREQUAL "")
  620. message(FATAL_ERROR
  621. "Do not know how to extract '${filename}' -- known types are: "
  622. ".7z, .tar, .tar.bz2, .tar.gz, .tar.xz, .tbz2, .tgz, .txz and .zip"
  623. )
  624. endif()
  625. configure_file(
  626. "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/extractfile.cmake.in"
  627. "${script_filename}"
  628. @ONLY
  629. )
  630. endfunction()
  631. function(_ep_is_dir_empty dir empty_var)
  632. file(GLOB gr "${dir}/*")
  633. if("${gr}" STREQUAL "")
  634. set(${empty_var} 1 PARENT_SCOPE)
  635. else()
  636. set(${empty_var} 0 PARENT_SCOPE)
  637. endif()
  638. endfunction()
  639. function(_ep_get_git_submodules_recurse git_submodules_recurse)
  640. # Checks for GIT_SUBMODULES_RECURSE argument. Default is ON, which sets
  641. # git_submodules_recurse output variable to "--recursive". Otherwise, the
  642. # output variable is set to an empty value "".
  643. # Note that the arguments are assumed to have already been parsed and have
  644. # been translated into variables with the prefix _EP_... by a call to
  645. # ep_parse_arguments() or ep_parse_arguments_to_vars().
  646. if(NOT DEFINED _EP_GIT_SUBMODULES_RECURSE)
  647. set(recurseFlag "--recursive")
  648. else()
  649. if(_EP_GIT_SUBMODULES_RECURSE)
  650. set(recurseFlag "--recursive")
  651. else()
  652. set(recurseFlag "")
  653. endif()
  654. endif()
  655. set(${git_submodules_recurse} "${recurseFlag}" PARENT_SCOPE)
  656. # The git submodule update '--recursive' flag requires git >= v1.6.5
  657. if(recurseFlag AND GIT_VERSION_STRING VERSION_LESS 1.6.5)
  658. message(FATAL_ERROR
  659. "git version 1.6.5 or later required for --recursive flag with "
  660. "'git submodule ...': GIT_VERSION_STRING='${GIT_VERSION_STRING}'"
  661. )
  662. endif()
  663. endfunction()
  664. function(_ep_add_script_commands script_var work_dir cmd)
  665. # We only support a subset of what ep_replace_location_tags() handles
  666. set(location_tags
  667. SOURCE_DIR
  668. SOURCE_SUBDIR
  669. BINARY_DIR
  670. TMP_DIR
  671. DOWNLOAD_DIR
  672. DOWNLOADED_FILE
  673. )
  674. # There can be multiple COMMANDs, but we have to split those up to
  675. # one command per call to execute_process()
  676. string(CONCAT execute_process_cmd
  677. "execute_process(\n"
  678. " WORKING_DIRECTORY \"${work_dir}\"\n"
  679. " COMMAND_ERROR_IS_FATAL LAST\n"
  680. )
  681. cmake_language(GET_MESSAGE_LOG_LEVEL active_log_level)
  682. if(active_log_level MATCHES "VERBOSE|DEBUG|TRACE")
  683. string(APPEND execute_process_cmd " COMMAND_ECHO STDOUT\n")
  684. endif()
  685. string(APPEND execute_process_cmd " COMMAND ")
  686. string(APPEND ${script_var} "${execute_process_cmd}")
  687. foreach(cmd_arg IN LISTS cmd)
  688. if(cmd_arg STREQUAL "COMMAND")
  689. string(APPEND ${script_var} "\n)\n${execute_process_cmd}")
  690. else()
  691. if(_EP_LIST_SEPARATOR)
  692. string(REPLACE "${_EP_LIST_SEPARATOR}" "\\;" cmd_arg "${cmd_arg}")
  693. endif()
  694. foreach(dir IN LISTS location_tags)
  695. string(REPLACE "<${dir}>" "${_EP_${dir}}" cmd_arg "${cmd_arg}")
  696. endforeach()
  697. string(APPEND ${script_var} " [====[${cmd_arg}]====]")
  698. endif()
  699. endforeach()
  700. string(APPEND ${script_var} "\n)")
  701. set(${script_var} "${${script_var}}" PARENT_SCOPE)
  702. endfunction()
  703. function(_ep_add_download_command name)
  704. set(noValueOptions )
  705. set(singleValueOptions
  706. SCRIPT_FILE # These should only be used by FetchContent
  707. DEPENDS_VARIABLE #
  708. )
  709. set(multiValueOptions )
  710. cmake_parse_arguments(PARSE_ARGV 1 arg
  711. "${noValueOptions}" "${singleValueOptions}" "${multiValueOptions}"
  712. )
  713. # The various _EP_... variables mentioned here and throughout this function
  714. # are expected to already have been set by the caller via a call to
  715. # _ep_parse_arguments() or ep_parse_arguments_to_vars(). Other variables
  716. # with different names are assigned to for historical reasons only to keep
  717. # the code more readable and minimize change.
  718. set(source_dir "${_EP_SOURCE_DIR}")
  719. set(stamp_dir "${_EP_STAMP_DIR}")
  720. set(download_dir "${_EP_DOWNLOAD_DIR}")
  721. set(tmp_dir "${_EP_TMP_DIR}")
  722. set(cmd "${_EP_DOWNLOAD_COMMAND}")
  723. set(cvs_repository "${_EP_CVS_REPOSITORY}")
  724. set(svn_repository "${_EP_SVN_REPOSITORY}")
  725. set(git_repository "${_EP_GIT_REPOSITORY}")
  726. set(hg_repository "${_EP_HG_REPOSITORY}")
  727. set(url "${_EP_URL}")
  728. set(fname "${_EP_DOWNLOAD_NAME}")
  729. # TODO: Perhaps file:// should be copied to download dir before extraction.
  730. string(REGEX REPLACE "file://" "" url "${url}")
  731. set(step_script_contents)
  732. set(depends)
  733. set(comment)
  734. set(work_dir)
  735. set(extra_repo_info)
  736. if(DEFINED _EP_DOWNLOAD_COMMAND)
  737. set(work_dir ${download_dir})
  738. set(method custom)
  739. if(NOT "x${cmd}" STREQUAL "x" AND arg_SCRIPT_FILE)
  740. _ep_add_script_commands(
  741. step_script_contents
  742. "${work_dir}"
  743. "${cmd}" # Must be a single quoted argument
  744. )
  745. endif()
  746. elseif(cvs_repository)
  747. set(method cvs)
  748. find_package(CVS QUIET)
  749. if(NOT CVS_EXECUTABLE)
  750. message(FATAL_ERROR "error: could not find cvs for checkout of ${name}")
  751. endif()
  752. set(cvs_module "${_EP_CVS_MODULE}")
  753. if(NOT cvs_module)
  754. message(FATAL_ERROR "error: no CVS_MODULE")
  755. endif()
  756. set(cvs_tag "${_EP_CVS_TAG}")
  757. get_filename_component(src_name "${source_dir}" NAME)
  758. get_filename_component(work_dir "${source_dir}" PATH)
  759. set(comment "Performing download step (CVS checkout) for '${name}'")
  760. set(cmd
  761. ${CVS_EXECUTABLE}
  762. -d ${cvs_repository}
  763. -q
  764. co ${cvs_tag}
  765. -d ${src_name}
  766. ${cvs_module}
  767. )
  768. if(arg_SCRIPT_FILE)
  769. _ep_add_script_commands(
  770. step_script_contents
  771. "${work_dir}"
  772. "${cmd}" # Must be a single quoted argument
  773. )
  774. endif()
  775. elseif(svn_repository)
  776. set(method svn)
  777. find_package(Subversion QUIET)
  778. if(NOT Subversion_SVN_EXECUTABLE)
  779. message(FATAL_ERROR "error: could not find svn for checkout of ${name}")
  780. endif()
  781. set(svn_trust_cert "${_EP_SVN_TRUST_CERT}")
  782. set(uses_terminal "${_EP_USES_TERMINAL_DOWNLOAD}")
  783. get_filename_component(src_name "${source_dir}" NAME)
  784. get_filename_component(work_dir "${source_dir}" PATH)
  785. set(comment "Performing download step (SVN checkout) for '${name}'")
  786. set(cmd
  787. ${Subversion_SVN_EXECUTABLE}
  788. co
  789. ${svn_repository}
  790. ${_EP_SVN_REVISION}
  791. )
  792. # The --trust-server-cert option requires --non-interactive
  793. if(svn_trust_cert OR NOT uses_terminal)
  794. list(APPEND cmd "--non-interactive")
  795. endif()
  796. if(svn_trust_cert)
  797. list(APPEND cmd "--trust-server-cert")
  798. endif()
  799. if(DEFINED _EP_SVN_USERNAME)
  800. list(APPEND cmd "--username=${_EP_SVN_USERNAME}")
  801. endif()
  802. if(DEFINED _EP_SVN_PASSWORD)
  803. list(APPEND cmd "--password=${_EP_SVN_PASSWORD}")
  804. endif()
  805. list(APPEND cmd ${src_name})
  806. if(arg_SCRIPT_FILE)
  807. _ep_add_script_commands(
  808. step_script_contents
  809. "${work_dir}"
  810. "${cmd}" # Must be a single quoted argument
  811. )
  812. endif()
  813. elseif(git_repository)
  814. set(method git)
  815. # FetchContent gives us these directly, so don't try to recompute them
  816. if(NOT GIT_EXECUTABLE OR NOT GIT_VERSION_STRING)
  817. unset(CMAKE_MODULE_PATH) # Use CMake builtin find module
  818. find_package(Git QUIET)
  819. if(NOT GIT_EXECUTABLE)
  820. message(FATAL_ERROR "error: could not find git for clone of ${name}")
  821. endif()
  822. endif()
  823. _ep_get_git_submodules_recurse(git_submodules_recurse)
  824. set(git_tag "${_EP_GIT_TAG}")
  825. if(NOT git_tag)
  826. set(git_tag "master")
  827. endif()
  828. set(git_init_submodules TRUE)
  829. if(DEFINED _EP_GIT_SUBMODULES)
  830. set(git_submodules "${_EP_GIT_SUBMODULES}")
  831. if(git_submodules STREQUAL "" AND _EP_CMP0097 STREQUAL "NEW")
  832. set(git_init_submodules FALSE)
  833. endif()
  834. endif()
  835. set(git_remote_name "${_EP_GIT_REMOTE_NAME}")
  836. if(NOT git_remote_name)
  837. set(git_remote_name "origin")
  838. endif()
  839. _ep_get_tls_version(${name} tls_version)
  840. _ep_get_tls_verify(${name} tls_verify)
  841. set(git_shallow "${_EP_GIT_SHALLOW}")
  842. set(git_progress "${_EP_GIT_PROGRESS}")
  843. set(git_config "${_EP_GIT_CONFIG}")
  844. # If git supports it, make checkouts quiet when checking out a git hash.
  845. # This avoids the very noisy detached head message.
  846. if(GIT_VERSION_STRING VERSION_GREATER_EQUAL 1.7.7)
  847. list(PREPEND git_config advice.detachedHead=false)
  848. endif()
  849. # The command doesn't expose any details, so we need to record additional
  850. # information in the RepositoryInfo.txt file. For the download step, only
  851. # the things specifically affecting the clone operation should be recorded.
  852. # If the repo changes, the clone script should be run again.
  853. # But if only the tag changes, avoid running the clone script again.
  854. # Let the 'always' running update step checkout the new tag.
  855. #
  856. set(extra_repo_info
  857. "repository=${git_repository}
  858. remote=${git_remote_name}
  859. init_submodules=${git_init_submodules}
  860. recurse_submodules=${git_submodules_recurse}
  861. submodules=${git_submodules}
  862. CMP0097=${_EP_CMP0097}
  863. ")
  864. get_filename_component(src_name "${source_dir}" NAME)
  865. get_filename_component(work_dir "${source_dir}" PATH)
  866. # Since git clone doesn't succeed if the non-empty source_dir exists,
  867. # create a cmake script to invoke as download command.
  868. # The script will delete the source directory and then call git clone.
  869. #
  870. set(clone_script ${tmp_dir}/${name}-gitclone.cmake)
  871. _ep_write_gitclone_script(
  872. ${clone_script}
  873. ${source_dir}
  874. ${GIT_EXECUTABLE}
  875. ${git_repository}
  876. ${git_tag}
  877. ${git_remote_name}
  878. ${git_init_submodules}
  879. "${git_submodules_recurse}"
  880. "${git_submodules}"
  881. "${git_shallow}"
  882. "${git_progress}"
  883. "${git_config}"
  884. ${src_name}
  885. ${work_dir}
  886. ${stamp_dir}/${name}-gitinfo.txt
  887. ${stamp_dir}/${name}-gitclone-lastrun.txt
  888. "${tls_version}"
  889. "${tls_verify}"
  890. )
  891. set(comment "Performing download step (git clone) for '${name}'")
  892. set(cmd ${CMAKE_COMMAND}
  893. -DCMAKE_MESSAGE_LOG_LEVEL=VERBOSE
  894. -P ${clone_script}
  895. )
  896. if(arg_SCRIPT_FILE)
  897. set(step_script_contents "include(\"${clone_script}\")")
  898. list(APPEND depends ${clone_script})
  899. endif()
  900. elseif(hg_repository)
  901. set(method hg)
  902. find_package(Hg QUIET)
  903. if(NOT HG_EXECUTABLE)
  904. message(FATAL_ERROR "error: could not find hg for clone of ${name}")
  905. endif()
  906. set(hg_tag "${_EP_HG_TAG}")
  907. if(NOT hg_tag)
  908. set(hg_tag "tip")
  909. endif()
  910. # The command doesn't expose any details, so we need to record additional
  911. # information in the RepositoryInfo.txt file. For the download step, only
  912. # the things specifically affecting the clone operation should be recorded.
  913. # If the repo changes, the clone script should be run again.
  914. # But if only the tag changes, avoid running the clone script again.
  915. # Let the 'always' running update step checkout the new tag.
  916. #
  917. set(extra_repo_info "repository=${hg_repository}")
  918. get_filename_component(src_name "${source_dir}" NAME)
  919. get_filename_component(work_dir "${source_dir}" PATH)
  920. # Since hg clone doesn't succeed if the non-empty source_dir exists,
  921. # create a cmake script to invoke as download command.
  922. # The script will delete the source directory and then call hg clone.
  923. #
  924. set(clone_script ${tmp_dir}/${name}-hgclone.cmake)
  925. _ep_write_hgclone_script(
  926. ${clone_script}
  927. ${source_dir}
  928. ${HG_EXECUTABLE}
  929. ${hg_repository}
  930. ${hg_tag}
  931. ${src_name}
  932. ${work_dir}
  933. ${stamp_dir}/${name}-hginfo.txt
  934. ${stamp_dir}/${name}-hgclone-lastrun.txt
  935. )
  936. set(comment "Performing download step (hg clone) for '${name}'")
  937. set(cmd ${CMAKE_COMMAND}
  938. -DCMAKE_MESSAGE_LOG_LEVEL=VERBOSE
  939. -P ${clone_script}
  940. )
  941. if(arg_SCRIPT_FILE)
  942. set(step_script_contents "include(\"${clone_script}\")")
  943. list(APPEND depends ${clone_script})
  944. endif()
  945. elseif(url)
  946. set(method url)
  947. get_filename_component(work_dir "${source_dir}" PATH)
  948. set(hash "${_EP_URL_HASH}")
  949. _ep_get_hash_regex(_ep_hash_regex)
  950. if(hash AND NOT "${hash}" MATCHES "${_ep_hash_regex}")
  951. _ep_get_hash_algos(_ep_hash_algos)
  952. list(JOIN _ep_hash_algos "|" _ep_hash_algos)
  953. message(FATAL_ERROR
  954. "URL_HASH is set to\n"
  955. " ${hash}\n"
  956. "but must be ALGO=value where ALGO is\n"
  957. " ${_ep_hash_algos}\n"
  958. "and value is a hex string."
  959. )
  960. endif()
  961. set(md5 "${_EP_URL_MD5}")
  962. if(md5 AND NOT "MD5=${md5}" MATCHES "${_ep_hash_regex}")
  963. message(FATAL_ERROR
  964. "URL_MD5 is set to\n"
  965. " ${md5}\n"
  966. "but must be a hex string."
  967. )
  968. endif()
  969. if(md5 AND NOT hash)
  970. set(hash "MD5=${md5}")
  971. endif()
  972. set(extra_repo_info
  973. "url(s)=${url}
  974. hash=${hash}
  975. ")
  976. list(LENGTH url url_list_length)
  977. if(NOT "${url_list_length}" STREQUAL "1")
  978. foreach(entry IN LISTS url)
  979. if(NOT "${entry}" MATCHES "^[a-z]+://")
  980. message(FATAL_ERROR
  981. "At least one entry of URL is a path (invalid in a list)"
  982. )
  983. endif()
  984. endforeach()
  985. if("x${fname}" STREQUAL "x")
  986. list(GET url 0 fname)
  987. endif()
  988. endif()
  989. if(IS_DIRECTORY "${url}")
  990. get_filename_component(abs_dir "${url}" ABSOLUTE)
  991. set(comment "Performing download step (DIR copy) for '${name}'")
  992. set(cmd
  993. ${CMAKE_COMMAND} -E rm -rf ${source_dir}
  994. COMMAND ${CMAKE_COMMAND} -E copy_directory ${abs_dir} ${source_dir}
  995. )
  996. if(arg_SCRIPT_FILE)
  997. # While it may be tempting to implement the two operations directly
  998. # with file(), the behavior is different. file(COPY) preserves input
  999. # file timestamps, which we don't want. Therefore, still use the same
  1000. # external commands so that we get the same behavior.
  1001. _ep_add_script_commands(
  1002. step_script_contents
  1003. "${work_dir}"
  1004. "${cmd}" # Must be a single quoted argument
  1005. )
  1006. endif()
  1007. else()
  1008. set(no_extract "${_EP_DOWNLOAD_NO_EXTRACT}")
  1009. string(APPEND extra_repo_info "no_extract=${no_extract}\n")
  1010. set(verify_script "${stamp_dir}/verify-${name}.cmake")
  1011. if("${url}" MATCHES "^[a-z]+://")
  1012. # TODO: Should download and extraction be different steps?
  1013. if("x${fname}" STREQUAL "x")
  1014. set(fname "${url}")
  1015. endif()
  1016. set(ext_regex [[7z|tar|tar\.bz2|tar\.gz|tar\.xz|tbz2|tgz|txz|zip]])
  1017. if("${fname}" MATCHES "([^/\\?#]+(\\.|=)(${ext_regex}))([/?#].*)?$")
  1018. set(fname "${CMAKE_MATCH_1}")
  1019. elseif(no_extract)
  1020. get_filename_component(fname "${fname}" NAME)
  1021. else()
  1022. # Fall back to a default file name. The actual file name does not
  1023. # matter because it is used only internally and our extraction tool
  1024. # inspects the file content directly. If it turns out the wrong URL
  1025. # was given that will be revealed during the build which is an easier
  1026. # place for users to diagnose than an error here anyway.
  1027. set(fname "archive.tar")
  1028. endif()
  1029. string(REPLACE ";" "-" fname "${fname}")
  1030. set(file ${download_dir}/${fname})
  1031. set(timeout "${_EP_TIMEOUT}")
  1032. set(inactivity_timeout "${_EP_INACTIVITY_TIMEOUT}")
  1033. set(no_progress "${_EP_DOWNLOAD_NO_PROGRESS}")
  1034. _ep_get_tls_version(${name} tls_version)
  1035. _ep_get_tls_verify(${name} tls_verify)
  1036. _ep_get_tls_cainfo(${name} tls_cainfo)
  1037. _ep_get_netrc(${name} netrc)
  1038. _ep_get_netrc_file(${name} netrc_file)
  1039. set(http_username "${_EP_HTTP_USERNAME}")
  1040. set(http_password "${_EP_HTTP_PASSWORD}")
  1041. set(http_headers "${_EP_HTTP_HEADER}")
  1042. set(download_script "${stamp_dir}/download-${name}.cmake")
  1043. _ep_write_downloadfile_script(
  1044. "${download_script}"
  1045. "${url}"
  1046. "${file}"
  1047. "${timeout}"
  1048. "${inactivity_timeout}"
  1049. "${no_progress}"
  1050. "${hash}"
  1051. "${tls_version}"
  1052. "${tls_verify}"
  1053. "${tls_cainfo}"
  1054. "${http_username}:${http_password}"
  1055. "${http_headers}"
  1056. "${netrc}"
  1057. "${netrc_file}"
  1058. )
  1059. set(cmd
  1060. ${CMAKE_COMMAND}
  1061. -DCMAKE_MESSAGE_LOG_LEVEL=VERBOSE
  1062. -P "${download_script}"
  1063. COMMAND
  1064. )
  1065. if(arg_SCRIPT_FILE)
  1066. set(step_script_contents "include(\"${download_script}\")\n")
  1067. endif()
  1068. if (no_extract)
  1069. set(steps "download and verify")
  1070. else ()
  1071. set(steps "download, verify and extract")
  1072. endif ()
  1073. set(comment "Performing download step (${steps}) for '${name}'")
  1074. # already verified by 'download_script'
  1075. file(WRITE "${verify_script}" "")
  1076. # Rather than adding everything to the RepositoryInfo.txt file, it is
  1077. # more robust to just depend on the download script. That way, we will
  1078. # re-download if any aspect of the download changes.
  1079. list(APPEND depends "${download_script}")
  1080. else()
  1081. set(file "${url}")
  1082. if (no_extract)
  1083. set(steps "verify")
  1084. else ()
  1085. set(steps "verify and extract")
  1086. endif ()
  1087. set(comment "Performing download step (${steps}) for '${name}'")
  1088. _ep_write_verifyfile_script(
  1089. "${verify_script}"
  1090. "${file}"
  1091. "${hash}"
  1092. )
  1093. endif()
  1094. list(APPEND cmd ${CMAKE_COMMAND}
  1095. -DCMAKE_MESSAGE_LOG_LEVEL=VERBOSE
  1096. -P ${verify_script}
  1097. )
  1098. if(arg_SCRIPT_FILE)
  1099. string(APPEND step_script_contents "include(\"${verify_script}\")\n")
  1100. list(APPEND depends ${verify_script})
  1101. endif()
  1102. set(extract_timestamp "${_EP_DOWNLOAD_EXTRACT_TIMESTAMP}")
  1103. if(no_extract)
  1104. if(DEFINED _EP_DOWNLOAD_EXTRACT_TIMESTAMP)
  1105. message(FATAL_ERROR
  1106. "Cannot specify DOWNLOAD_EXTRACT_TIMESTAMP when using "
  1107. "DOWNLOAD_NO_EXTRACT TRUE"
  1108. )
  1109. endif()
  1110. if(arg_SCRIPT_FILE)
  1111. # There's no target to record the location of the downloaded file.
  1112. # Instead, we copy it to the source directory within the script,
  1113. # which is what FetchContent always does in this situation.
  1114. cmake_path(SET safe_file NORMALIZE "${file}")
  1115. cmake_path(GET safe_file FILENAME filename)
  1116. string(APPEND step_script_contents
  1117. "file(COPY_FILE\n"
  1118. " \"${file}\"\n"
  1119. " \"${source_dir}/${filename}\"\n"
  1120. " ONLY_IF_DIFFERENT\n"
  1121. " INPUT_MAY_BE_RECENT\n"
  1122. ")"
  1123. )
  1124. list(APPEND depends ${source_dir}/${filename})
  1125. else()
  1126. set_property(TARGET ${name} PROPERTY _EP_DOWNLOADED_FILE ${file})
  1127. endif()
  1128. else()
  1129. if(NOT DEFINED _EP_DOWNLOAD_EXTRACT_TIMESTAMP)
  1130. # Default depends on policy CMP0135
  1131. if(_EP_CMP0135 STREQUAL "")
  1132. message(AUTHOR_WARNING
  1133. "The DOWNLOAD_EXTRACT_TIMESTAMP option was not given and policy "
  1134. "CMP0135 is not set. The policy's OLD behavior will be used. "
  1135. "When using a URL download, the timestamps of extracted files "
  1136. "should preferably be that of the time of extraction, otherwise "
  1137. "code that depends on the extracted contents might not be "
  1138. "rebuilt if the URL changes. The OLD behavior preserves the "
  1139. "timestamps from the archive instead, but this is usually not "
  1140. "what you want. Update your project to the NEW behavior or "
  1141. "specify the DOWNLOAD_EXTRACT_TIMESTAMP option with a value of "
  1142. "true to avoid this robustness issue."
  1143. )
  1144. set(extract_timestamp TRUE)
  1145. elseif(_EP_CMP0135 STREQUAL "NEW")
  1146. set(extract_timestamp FALSE)
  1147. else()
  1148. set(extract_timestamp TRUE)
  1149. endif()
  1150. endif()
  1151. if(extract_timestamp)
  1152. set(options "")
  1153. else()
  1154. set(options "--touch")
  1155. endif()
  1156. set(extract_script "${stamp_dir}/extract-${name}.cmake")
  1157. _ep_write_extractfile_script(
  1158. "${extract_script}"
  1159. "${name}"
  1160. "${file}"
  1161. "${source_dir}"
  1162. "${options}"
  1163. )
  1164. list(APPEND cmd
  1165. COMMAND ${CMAKE_COMMAND}
  1166. -DCMAKE_MESSAGE_LOG_LEVEL=VERBOSE
  1167. -P ${extract_script}
  1168. )
  1169. if(arg_SCRIPT_FILE)
  1170. string(APPEND step_script_contents "include(\"${extract_script}\")\n")
  1171. list(APPEND depends ${extract_script})
  1172. endif()
  1173. endif ()
  1174. endif()
  1175. else()
  1176. set(method source_dir)
  1177. _ep_is_dir_empty("${source_dir}" empty)
  1178. if(${empty})
  1179. message(FATAL_ERROR
  1180. "No download info given for '${name}' and its source directory:\n"
  1181. " ${source_dir}\n"
  1182. "is not an existing non-empty directory. Please specify one of:\n"
  1183. " * SOURCE_DIR with an existing non-empty directory\n"
  1184. " * DOWNLOAD_COMMAND\n"
  1185. " * URL\n"
  1186. " * GIT_REPOSITORY\n"
  1187. " * SVN_REPOSITORY\n"
  1188. " * HG_REPOSITORY\n"
  1189. " * CVS_REPOSITORY and CVS_MODULE"
  1190. )
  1191. endif()
  1192. if(arg_SCRIPT_FILE)
  1193. set(step_script_contents "message(VERBOSE [[Using SOURCE_DIR as is]])")
  1194. endif()
  1195. endif()
  1196. # We use configure_file() to write the repo_info_file so that the file's
  1197. # timestamp is not updated if we don't change the contents
  1198. set(repo_info_file ${stamp_dir}/${name}-${method}info.txt)
  1199. list(APPEND depends ${repo_info_file})
  1200. configure_file(
  1201. "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/RepositoryInfo.txt.in"
  1202. "${repo_info_file}"
  1203. @ONLY
  1204. )
  1205. if(arg_SCRIPT_FILE)
  1206. set(step_name download)
  1207. configure_file(
  1208. "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/stepscript.cmake.in"
  1209. "${arg_SCRIPT_FILE}"
  1210. @ONLY
  1211. )
  1212. set(${arg_DEPENDS_VARIABLE} "${depends}" PARENT_SCOPE)
  1213. return()
  1214. endif()
  1215. # Nothing below this point is applicable when we've been asked to put the
  1216. # download step in a script file (which is the FetchContent case).
  1217. if(_EP_LOG_DOWNLOAD)
  1218. set(log LOG 1)
  1219. else()
  1220. set(log "")
  1221. endif()
  1222. if(_EP_USES_TERMINAL_DOWNLOAD)
  1223. set(uses_terminal USES_TERMINAL 1)
  1224. else()
  1225. set(uses_terminal "")
  1226. endif()
  1227. set(__cmdQuoted)
  1228. foreach(__item IN LISTS cmd)
  1229. string(APPEND __cmdQuoted " [==[${__item}]==]")
  1230. endforeach()
  1231. cmake_language(EVAL CODE "
  1232. ExternalProject_Add_Step(\${name} download
  1233. INDEPENDENT TRUE
  1234. COMMENT \${comment}
  1235. COMMAND ${__cmdQuoted}
  1236. WORKING_DIRECTORY \${work_dir}
  1237. DEPENDS \${depends}
  1238. DEPENDEES mkdir
  1239. ${log}
  1240. ${uses_terminal}
  1241. )"
  1242. )
  1243. endfunction()
  1244. function(_ep_get_update_disconnected var name)
  1245. # Note that the arguments are assumed to have already been parsed and have
  1246. # been translated into variables with the prefix _EP_... by a call to
  1247. # ep_parse_arguments() or ep_parse_arguments_to_vars().
  1248. if(DEFINED _EP_UPDATE_DISCONNECTED)
  1249. set(update_disconnected "${_EP_UPDATE_DISCONNECTED}")
  1250. else()
  1251. get_property(update_disconnected
  1252. DIRECTORY
  1253. PROPERTY EP_UPDATE_DISCONNECTED
  1254. )
  1255. endif()
  1256. set(${var} "${update_disconnected}" PARENT_SCOPE)
  1257. endfunction()
  1258. function(_ep_add_update_command name)
  1259. set(noValueOptions )
  1260. set(singleValueOptions
  1261. SCRIPT_FILE # These should only be used by FetchContent
  1262. DEPEND_VARIABLE #
  1263. )
  1264. set(multiValueOptions )
  1265. cmake_parse_arguments(PARSE_ARGV 1 arg
  1266. "${noValueOptions}" "${singleValueOptions}" "${multiValueOptions}"
  1267. )
  1268. # The various _EP_... variables mentioned here and throughout this function
  1269. # are expected to already have been set by the caller via a call to
  1270. # _ep_parse_arguments() or ep_parse_arguments_to_vars(). Other variables
  1271. # with different names are assigned to for historical reasons only to keep
  1272. # the code more readable and minimize change.
  1273. set(source_dir "${_EP_SOURCE_DIR}")
  1274. set(stamp_dir "${_EP_STAMP_DIR}")
  1275. set(tmp_dir "${_EP_TMP_DIR}")
  1276. set(cmd "${_EP_UPDATE_COMMAND}")
  1277. set(cvs_repository "${_EP_CVS_REPOSITORY}")
  1278. set(svn_repository "${_EP_SVN_REPOSITORY}")
  1279. set(git_repository "${_EP_GIT_REPOSITORY}")
  1280. set(hg_repository "${_EP_HG_REPOSITORY}")
  1281. _ep_get_update_disconnected(update_disconnected ${name})
  1282. set(work_dir)
  1283. set(cmd_disconnected)
  1284. set(comment)
  1285. set(comment_disconnected)
  1286. set(always)
  1287. set(file_deps)
  1288. if(DEFINED _EP_UPDATE_COMMAND)
  1289. set(work_dir ${source_dir})
  1290. if(NOT "x${cmd}" STREQUAL "x")
  1291. set(always 1)
  1292. _ep_add_script_commands(
  1293. step_script_contents
  1294. "${work_dir}"
  1295. "${cmd}" # Must be a single quoted argument
  1296. )
  1297. endif()
  1298. elseif(cvs_repository)
  1299. if(NOT CVS_EXECUTABLE)
  1300. message(FATAL_ERROR "error: could not find cvs for update of ${name}")
  1301. endif()
  1302. set(work_dir ${source_dir})
  1303. set(comment "Performing update step (CVS update) for '${name}'")
  1304. set(cvs_tag "${_EP_CVS_TAG}")
  1305. set(cmd ${CVS_EXECUTABLE} -d ${cvs_repository} -q up -dP ${cvs_tag})
  1306. set(always 1)
  1307. if(arg_SCRIPT_FILE)
  1308. _ep_add_script_commands(
  1309. step_script_contents
  1310. "${work_dir}"
  1311. "${cmd}" # Must be a single quoted argument
  1312. )
  1313. endif()
  1314. elseif(svn_repository)
  1315. if(NOT Subversion_SVN_EXECUTABLE)
  1316. message(FATAL_ERROR "error: could not find svn for update of ${name}")
  1317. endif()
  1318. set(work_dir ${source_dir})
  1319. set(comment "Performing update step (SVN update) for '${name}'")
  1320. set(svn_trust_cert "${_EP_SVN_TRUST_CERT}")
  1321. set(uses_terminal "${_EP_USES_TERMINAL_UPDATE}")
  1322. set(cmd
  1323. ${Subversion_SVN_EXECUTABLE}
  1324. up
  1325. ${_EP_SVN_REVISION}
  1326. )
  1327. # The --trust-server-cert option requires --non-interactive
  1328. if(svn_trust_cert OR NOT uses_terminal)
  1329. list(APPEND cmd "--non-interactive")
  1330. endif()
  1331. if(svn_trust_cert)
  1332. list(APPEND cmd --trust-server-cert)
  1333. endif()
  1334. if(DEFINED _EP_SVN_USERNAME)
  1335. list(APPEND cmd "--username=${_EP_SVN_USERNAME}")
  1336. endif()
  1337. if(DEFINED _EP_SVN_PASSWORD)
  1338. list(APPEND cmd "--password=${_EP_SVN_PASSWORD}")
  1339. endif()
  1340. set(always 1)
  1341. if(arg_SCRIPT_FILE)
  1342. _ep_add_script_commands(
  1343. step_script_contents
  1344. "${work_dir}"
  1345. "${cmd}" # Must be a single quoted argument
  1346. )
  1347. endif()
  1348. elseif(git_repository)
  1349. # FetchContent gives us these directly, so don't try to recompute them
  1350. if(NOT GIT_EXECUTABLE OR NOT GIT_VERSION_STRING)
  1351. unset(CMAKE_MODULE_PATH) # Use CMake builtin find module
  1352. find_package(Git QUIET)
  1353. if(NOT GIT_EXECUTABLE)
  1354. message(FATAL_ERROR "error: could not find git for fetch of ${name}")
  1355. endif()
  1356. endif()
  1357. set(work_dir ${source_dir})
  1358. set(comment "Performing update step for '${name}'")
  1359. set(comment_disconnected "Performing disconnected update step for '${name}'")
  1360. set(git_tag "${_EP_GIT_TAG}")
  1361. if(NOT git_tag)
  1362. set(git_tag "master")
  1363. endif()
  1364. set(git_remote_name "${_EP_GIT_REMOTE_NAME}")
  1365. if(NOT git_remote_name)
  1366. set(git_remote_name "origin")
  1367. endif()
  1368. set(git_init_submodules TRUE)
  1369. if(DEFINED _EP_GIT_SUBMODULES)
  1370. set(git_submodules "${_EP_GIT_SUBMODULES}")
  1371. if(git_submodules STREQUAL "" AND _EP_CMP0097 STREQUAL "NEW")
  1372. set(git_init_submodules FALSE)
  1373. endif()
  1374. endif()
  1375. set(git_update_strategy "${_EP_GIT_REMOTE_UPDATE_STRATEGY}")
  1376. if(NOT git_update_strategy)
  1377. set(git_update_strategy "${CMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY}")
  1378. endif()
  1379. if(NOT git_update_strategy)
  1380. set(git_update_strategy REBASE)
  1381. endif()
  1382. set(strategies CHECKOUT REBASE REBASE_CHECKOUT)
  1383. if(NOT git_update_strategy IN_LIST strategies)
  1384. message(FATAL_ERROR
  1385. "'${git_update_strategy}' is not one of the supported strategies: "
  1386. "${strategies}"
  1387. )
  1388. endif()
  1389. _ep_get_git_submodules_recurse(git_submodules_recurse)
  1390. _ep_get_tls_version(${name} tls_version)
  1391. _ep_get_tls_verify(${name} tls_verify)
  1392. set(update_script "${tmp_dir}/${name}-gitupdate.cmake")
  1393. list(APPEND file_deps ${update_script})
  1394. _ep_write_gitupdate_script(
  1395. "${update_script}"
  1396. "${GIT_EXECUTABLE}"
  1397. "${git_tag}"
  1398. "${git_remote_name}"
  1399. "${git_init_submodules}"
  1400. "${git_submodules_recurse}"
  1401. "${git_submodules}"
  1402. "${git_repository}"
  1403. "${work_dir}"
  1404. "${git_update_strategy}"
  1405. "${tls_version}"
  1406. "${tls_verify}"
  1407. )
  1408. set(cmd ${CMAKE_COMMAND}
  1409. -Dcan_fetch=YES
  1410. -DCMAKE_MESSAGE_LOG_LEVEL=VERBOSE
  1411. -P ${update_script}
  1412. )
  1413. set(cmd_disconnected ${CMAKE_COMMAND}
  1414. -Dcan_fetch=NO
  1415. -DCMAKE_MESSAGE_LOG_LEVEL=VERBOSE
  1416. -P ${update_script}
  1417. )
  1418. set(always 1)
  1419. if(arg_SCRIPT_FILE)
  1420. if(update_disconnected)
  1421. set(can_fetch_default NO)
  1422. else()
  1423. set(can_fetch_default YES)
  1424. endif()
  1425. set(step_script_contents "include(\"${update_script}\")")
  1426. endif()
  1427. elseif(hg_repository)
  1428. if(NOT HG_EXECUTABLE)
  1429. message(FATAL_ERROR "error: could not find hg for pull of ${name}")
  1430. endif()
  1431. set(work_dir ${source_dir})
  1432. set(comment "Performing update step (hg pull) for '${name}'")
  1433. set(comment_disconnected "Performing disconnected update step for '${name}'")
  1434. set(hg_tag "${_EP_HG_TAG}")
  1435. if(NOT hg_tag)
  1436. set(hg_tag "tip")
  1437. endif()
  1438. if("${HG_VERSION_STRING}" STREQUAL "2.1")
  1439. set(notesAnchor
  1440. "#A2.1.1:_revert_pull_return_code_change.2C_compile_issue_on_OS_X"
  1441. )
  1442. message(WARNING
  1443. "Mercurial 2.1 does not distinguish an empty pull from a failed pull:
  1444. http://mercurial.selenic.com/wiki/UpgradeNotes${notesAnchor}
  1445. http://thread.gmane.org/gmane.comp.version-control.mercurial.devel/47656
  1446. Update to Mercurial >= 2.1.1.
  1447. ")
  1448. endif()
  1449. set(cmd
  1450. ${HG_EXECUTABLE} pull
  1451. COMMAND ${HG_EXECUTABLE} update ${hg_tag}
  1452. )
  1453. set(cmd_disconnected ${HG_EXECUTABLE} update ${hg_tag})
  1454. set(always 1)
  1455. if(arg_SCRIPT_FILE)
  1456. # These commands are simple, and we know whether updates need to be
  1457. # disconnected or not for this case, so write them directly instead of
  1458. # forming them from "cmd" and "cmd_disconnected".
  1459. if(NOT update_disconnected)
  1460. string(APPEND step_script_contents
  1461. "execute_process(\n"
  1462. " WORKING_DIRECTORY \"${work_dir}\"\n"
  1463. " COMMAND_ERROR_IS_FATAL LAST\n"
  1464. " COMMAND \"${HG_EXECUTABLE}\" pull\n"
  1465. ")"
  1466. )
  1467. endif()
  1468. string(APPEND step_script_contents
  1469. "execute_process(\n"
  1470. " WORKING_DIRECTORY \"${work_dir}\"\n"
  1471. " COMMAND_ERROR_IS_FATAL LAST\n"
  1472. " COMMAND \"${HG_EXECUTABLE}\" update \"${hg_tag}\"\n"
  1473. ")"
  1474. )
  1475. endif()
  1476. endif()
  1477. # We use configure_file() to write the update_info_file so that the file's
  1478. # timestamp is not updated if we don't change the contents
  1479. if(NOT DEFINED cmd_disconnected)
  1480. set(cmd_disconnected "${cmd}")
  1481. endif()
  1482. set(update_info_file ${stamp_dir}/${name}-update-info.txt)
  1483. list(APPEND file_deps ${update_info_file})
  1484. configure_file(
  1485. "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/UpdateInfo.txt.in"
  1486. "${update_info_file}"
  1487. @ONLY
  1488. )
  1489. if(arg_SCRIPT_FILE)
  1490. set(step_name update)
  1491. configure_file(
  1492. "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/stepscript.cmake.in"
  1493. "${arg_SCRIPT_FILE}"
  1494. @ONLY
  1495. )
  1496. set(${arg_DEPENDS_VARIABLE} "${file_deps}" PARENT_SCOPE)
  1497. return()
  1498. endif()
  1499. # Nothing below this point is applicable when we've been asked to put the
  1500. # update step in a script file (which is the FetchContent case).
  1501. if(_EP_LOG_UPDATE)
  1502. set(log LOG 1)
  1503. else()
  1504. set(log "")
  1505. endif()
  1506. if(_EP_USES_TERMINAL_UPDATE)
  1507. set(uses_terminal USES_TERMINAL 1)
  1508. else()
  1509. set(uses_terminal "")
  1510. endif()
  1511. set(__cmdQuoted)
  1512. foreach(__item IN LISTS cmd)
  1513. string(APPEND __cmdQuoted " [==[${__item}]==]")
  1514. endforeach()
  1515. cmake_language(EVAL CODE "
  1516. ExternalProject_Add_Step(${name} update
  1517. INDEPENDENT TRUE
  1518. COMMENT \${comment}
  1519. COMMAND ${__cmdQuoted}
  1520. ALWAYS \${always}
  1521. EXCLUDE_FROM_MAIN \${update_disconnected}
  1522. WORKING_DIRECTORY \${work_dir}
  1523. DEPENDEES download
  1524. DEPENDS \${file_deps}
  1525. ${log}
  1526. ${uses_terminal}
  1527. )"
  1528. )
  1529. if(update_disconnected)
  1530. if(NOT DEFINED comment_disconnected)
  1531. set(comment_disconnected "${comment}")
  1532. endif()
  1533. set(__cmdQuoted)
  1534. foreach(__item IN LISTS cmd_disconnected)
  1535. string(APPEND __cmdQuoted " [==[${__item}]==]")
  1536. endforeach()
  1537. cmake_language(EVAL CODE "
  1538. ExternalProject_Add_Step(${name} update_disconnected
  1539. INDEPENDENT TRUE
  1540. COMMENT \${comment_disconnected}
  1541. COMMAND ${__cmdQuoted}
  1542. WORKING_DIRECTORY \${work_dir}
  1543. DEPENDEES download
  1544. DEPENDS \${file_deps}
  1545. ${log}
  1546. ${uses_terminal}
  1547. )"
  1548. )
  1549. endif()
  1550. endfunction()
  1551. function(_ep_add_patch_command name)
  1552. set(noValueOptions )
  1553. set(singleValueOptions
  1554. SCRIPT_FILE # These should only be used by FetchContent
  1555. )
  1556. set(multiValueOptions )
  1557. cmake_parse_arguments(PARSE_ARGV 1 arg
  1558. "${noValueOptions}" "${singleValueOptions}" "${multiValueOptions}"
  1559. )
  1560. # The various _EP_... variables mentioned here and throughout this function
  1561. # are expected to already have been set by the caller via a call to
  1562. # _ep_parse_arguments() or ep_parse_arguments_to_vars(). Other variables
  1563. # with different names are assigned to for historical reasons only to keep
  1564. # the code more readable and minimize change.
  1565. set(source_dir "${_EP_SOURCE_DIR}")
  1566. set(stamp_dir "${_EP_STAMP_DIR}")
  1567. set(cmd "${_EP_PATCH_COMMAND}")
  1568. set(step_script_contents "")
  1569. set(work_dir)
  1570. if(DEFINED _EP_PATCH_COMMAND)
  1571. set(work_dir ${source_dir})
  1572. if(arg_SCRIPT_FILE)
  1573. _ep_add_script_commands(
  1574. step_script_contents
  1575. "${work_dir}"
  1576. "${cmd}" # Must be a single quoted argument
  1577. )
  1578. endif()
  1579. endif()
  1580. # We use configure_file() to write the patch_info_file so that the file's
  1581. # timestamp is not updated if we don't change the contents
  1582. set(patch_info_file ${stamp_dir}/${name}-patch-info.txt)
  1583. configure_file(
  1584. "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/PatchInfo.txt.in"
  1585. "${patch_info_file}"
  1586. @ONLY
  1587. )
  1588. if(arg_SCRIPT_FILE)
  1589. set(step_name patch)
  1590. configure_file(
  1591. "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/stepscript.cmake.in"
  1592. "${arg_SCRIPT_FILE}"
  1593. @ONLY
  1594. )
  1595. return()
  1596. endif()
  1597. # Nothing below this point is applicable when we've been asked to put the
  1598. # patch step in a script file (which is the FetchContent case).
  1599. if(_EP_LOG_PATCH)
  1600. set(log LOG 1)
  1601. else()
  1602. set(log "")
  1603. endif()
  1604. if(_EP_USES_TERMINAL_PATCH)
  1605. set(uses_terminal USES_TERMINAL 1)
  1606. else()
  1607. set(uses_terminal "")
  1608. endif()
  1609. _ep_get_update_disconnected(update_disconnected ${name})
  1610. set(__cmdQuoted)
  1611. foreach(__item IN LISTS cmd)
  1612. string(APPEND __cmdQuoted " [==[${__item}]==]")
  1613. endforeach()
  1614. cmake_language(EVAL CODE "
  1615. ExternalProject_Add_Step(${name} patch
  1616. INDEPENDENT TRUE
  1617. COMMAND ${__cmdQuoted}
  1618. WORKING_DIRECTORY \${work_dir}
  1619. EXCLUDE_FROM_MAIN \${update_disconnected}
  1620. DEPENDEES update
  1621. DEPENDS \${patch_info_file}
  1622. ${log}
  1623. ${uses_terminal}
  1624. )"
  1625. )
  1626. if(update_disconnected)
  1627. cmake_language(EVAL CODE "
  1628. ExternalProject_Add_Step(${name} patch_disconnected
  1629. INDEPENDENT TRUE
  1630. COMMAND ${__cmdQuoted}
  1631. WORKING_DIRECTORY \${work_dir}
  1632. DEPENDEES update_disconnected
  1633. DEPENDS \${patch_info_file}
  1634. ${log}
  1635. ${uses_terminal}
  1636. )"
  1637. )
  1638. endif()
  1639. endfunction()
  1640. macro(_ep_get_add_keywords out_var)
  1641. set(${out_var}
  1642. #
  1643. # Directory options
  1644. #
  1645. PREFIX
  1646. TMP_DIR
  1647. STAMP_DIR
  1648. LOG_DIR
  1649. DOWNLOAD_DIR
  1650. SOURCE_DIR
  1651. BINARY_DIR
  1652. INSTALL_DIR
  1653. #
  1654. # Download step options
  1655. #
  1656. DOWNLOAD_COMMAND
  1657. #
  1658. URL
  1659. URL_HASH
  1660. URL_MD5
  1661. DOWNLOAD_NAME
  1662. DOWNLOAD_EXTRACT_TIMESTAMP
  1663. DOWNLOAD_NO_EXTRACT
  1664. DOWNLOAD_NO_PROGRESS
  1665. TIMEOUT
  1666. INACTIVITY_TIMEOUT
  1667. HTTP_USERNAME
  1668. HTTP_PASSWORD
  1669. HTTP_HEADER
  1670. TLS_VERSION # Also used for git clone operations
  1671. TLS_VERIFY # Also used for git clone operations
  1672. TLS_CAINFO
  1673. NETRC
  1674. NETRC_FILE
  1675. #
  1676. GIT_REPOSITORY
  1677. GIT_TAG
  1678. GIT_REMOTE_NAME
  1679. GIT_SUBMODULES
  1680. GIT_SUBMODULES_RECURSE
  1681. GIT_SHALLOW
  1682. GIT_PROGRESS
  1683. GIT_CONFIG
  1684. GIT_REMOTE_UPDATE_STRATEGY
  1685. #
  1686. SVN_REPOSITORY
  1687. SVN_REVISION
  1688. SVN_USERNAME
  1689. SVN_PASSWORD
  1690. SVN_TRUST_CERT
  1691. #
  1692. HG_REPOSITORY
  1693. HG_TAG
  1694. #
  1695. CVS_REPOSITORY
  1696. CVS_MODULE
  1697. CVS_TAG
  1698. #
  1699. # Update step options
  1700. #
  1701. UPDATE_COMMAND
  1702. UPDATE_DISCONNECTED
  1703. #
  1704. # Patch step options
  1705. #
  1706. PATCH_COMMAND
  1707. #
  1708. # Configure step options
  1709. #
  1710. CONFIGURE_COMMAND
  1711. CMAKE_COMMAND
  1712. CMAKE_GENERATOR
  1713. CMAKE_GENERATOR_PLATFORM
  1714. CMAKE_GENERATOR_TOOLSET
  1715. CMAKE_GENERATOR_INSTANCE
  1716. CMAKE_ARGS
  1717. CMAKE_CACHE_ARGS
  1718. CMAKE_CACHE_DEFAULT_ARGS
  1719. SOURCE_SUBDIR
  1720. CONFIGURE_HANDLED_BY_BUILD
  1721. #
  1722. # Build step options
  1723. #
  1724. BUILD_COMMAND
  1725. BUILD_IN_SOURCE
  1726. BUILD_ALWAYS
  1727. BUILD_BYPRODUCTS
  1728. BUILD_JOB_SERVER_AWARE
  1729. #
  1730. # Install step options
  1731. #
  1732. INSTALL_COMMAND
  1733. INSTALL_BYPRODUCTS
  1734. #
  1735. # Test step options
  1736. #
  1737. TEST_COMMAND
  1738. TEST_BEFORE_INSTALL
  1739. TEST_AFTER_INSTALL
  1740. TEST_EXCLUDE_FROM_MAIN
  1741. #
  1742. # Logging options
  1743. #
  1744. LOG_DOWNLOAD
  1745. LOG_UPDATE
  1746. LOG_PATCH
  1747. LOG_CONFIGURE
  1748. LOG_BUILD
  1749. LOG_INSTALL
  1750. LOG_TEST
  1751. LOG_MERGED_STDOUTERR
  1752. LOG_OUTPUT_ON_FAILURE
  1753. #
  1754. # Terminal access options
  1755. #
  1756. USES_TERMINAL_DOWNLOAD
  1757. USES_TERMINAL_UPDATE
  1758. USES_TERMINAL_PATCH
  1759. USES_TERMINAL_CONFIGURE
  1760. USES_TERMINAL_BUILD
  1761. USES_TERMINAL_INSTALL
  1762. USES_TERMINAL_TEST
  1763. #
  1764. # Target options
  1765. #
  1766. DEPENDS
  1767. EXCLUDE_FROM_ALL
  1768. STEP_TARGETS
  1769. INDEPENDENT_STEP_TARGETS
  1770. #
  1771. # Miscellaneous options
  1772. #
  1773. LIST_SEPARATOR
  1774. #
  1775. # Internal options (undocumented)
  1776. #
  1777. EXTERNALPROJECT_INTERNAL_ARGUMENT_SEPARATOR
  1778. )
  1779. endmacro()