OpenCVDownload.cmake 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. #
  2. # Download and optionally unpack a file
  3. #
  4. # ocv_download(FILENAME p HASH h URL u1 [u2 ...] DESTINATION_DIR d [ID id] [STATUS s] [UNPACK] [RELATIVE_URL])
  5. # FILENAME - filename
  6. # HASH - MD5 hash
  7. # URL - full download url (first nonempty value will be chosen)
  8. # DESTINATION_DIR - file will be copied to this directory
  9. # ID - identifier for project/group of downloaded files
  10. # STATUS - passed variable will be updated in parent scope,
  11. # function will not fail the build in case of download problem if this option is provided,
  12. # but will fail in case when other operations (copy, remove, etc.) failed
  13. # UNPACK - downloaded file will be unpacked to DESTINATION_DIR
  14. # RELATIVE_URL - if set, then URL is treated as a base, and FILENAME will be appended to it
  15. # Note: uses OPENCV_DOWNLOAD_PATH folder as cache, default is <opencv>/.cache
  16. set(HELP_OPENCV_DOWNLOAD_PATH "Cache directory for downloaded files")
  17. if(DEFINED ENV{OPENCV_DOWNLOAD_PATH})
  18. set(OPENCV_DOWNLOAD_PATH "$ENV{OPENCV_DOWNLOAD_PATH}" CACHE PATH "${HELP_OPENCV_DOWNLOAD_PATH}")
  19. endif()
  20. set(OPENCV_DOWNLOAD_PATH "${OpenCV_SOURCE_DIR}/.cache" CACHE PATH "${HELP_OPENCV_DOWNLOAD_PATH}")
  21. set(OPENCV_DOWNLOAD_LOG "${OpenCV_BINARY_DIR}/CMakeDownloadLog.txt")
  22. set(OPENCV_DOWNLOAD_WITH_CURL "${OpenCV_BINARY_DIR}/download_with_curl.sh")
  23. set(OPENCV_DOWNLOAD_WITH_WGET "${OpenCV_BINARY_DIR}/download_with_wget.sh")
  24. set(OPENCV_DOWNLOAD_TRIES_LIST 1 CACHE STRING "List of download tries") # a list
  25. set(OPENCV_DOWNLOAD_PARAMS INACTIVITY_TIMEOUT 60 TIMEOUT 600 CACHE STRING "Download parameters to be passed to file(DOWNLOAD ...)")
  26. mark_as_advanced(OPENCV_DOWNLOAD_TRIES_LIST OPENCV_DOWNLOAD_PARAMS)
  27. # Init download cache directory and log file and helper scripts
  28. if(NOT EXISTS "${OPENCV_DOWNLOAD_PATH}")
  29. file(MAKE_DIRECTORY ${OPENCV_DOWNLOAD_PATH})
  30. endif()
  31. if(NOT EXISTS "${OPENCV_DOWNLOAD_PATH}/.gitignore")
  32. file(WRITE "${OPENCV_DOWNLOAD_PATH}/.gitignore" "*\n")
  33. endif()
  34. file(WRITE "${OPENCV_DOWNLOAD_LOG}" "#use_cache \"${OPENCV_DOWNLOAD_PATH}\"\n")
  35. file(REMOVE "${OPENCV_DOWNLOAD_WITH_CURL}")
  36. file(REMOVE "${OPENCV_DOWNLOAD_WITH_WGET}")
  37. function(ocv_download)
  38. cmake_parse_arguments(DL "UNPACK;RELATIVE_URL" "FILENAME;HASH;DESTINATION_DIR;ID;STATUS" "URL" ${ARGN})
  39. function(ocv_download_log)
  40. file(APPEND "${OPENCV_DOWNLOAD_LOG}" "${ARGN}\n")
  41. endfunction()
  42. ocv_assert(DL_FILENAME)
  43. ocv_assert(DL_HASH)
  44. ocv_assert(DL_URL)
  45. ocv_assert(DL_DESTINATION_DIR)
  46. if((NOT " ${DL_UNPARSED_ARGUMENTS}" STREQUAL " ")
  47. OR DL_FILENAME STREQUAL ""
  48. OR DL_HASH STREQUAL ""
  49. OR DL_URL STREQUAL ""
  50. OR DL_DESTINATION_DIR STREQUAL ""
  51. )
  52. set(msg_level FATAL_ERROR)
  53. if(DEFINED DL_STATUS)
  54. set(${DL_STATUS} FALSE PARENT_SCOPE)
  55. set(msg_level WARNING)
  56. endif()
  57. message(${msg_level} "ERROR: ocv_download() unsupported arguments: ${ARGV}")
  58. return()
  59. endif()
  60. if(DEFINED DL_STATUS)
  61. set(${DL_STATUS} TRUE PARENT_SCOPE)
  62. endif()
  63. # Check CMake cache for already processed tasks
  64. string(FIND "${DL_DESTINATION_DIR}" "${CMAKE_BINARY_DIR}" DL_BINARY_PATH_POS)
  65. if(DL_BINARY_PATH_POS EQUAL 0)
  66. set(__file_id "${DL_DESTINATION_DIR}/${DL_FILENAME}")
  67. file(RELATIVE_PATH __file_id "${CMAKE_BINARY_DIR}" "${__file_id}")
  68. string(REGEX REPLACE "[^a-zA-Z0-9_]" "_" __file_id "${__file_id}")
  69. if(DL_ID)
  70. string(TOUPPER ${DL_ID} __id)
  71. string(REGEX REPLACE "[^a-zA-Z0-9_]" "_" __id "${__id}")
  72. set(OCV_DOWNLOAD_HASH_NAME "OCV_DOWNLOAD_${__id}_HASH_${__file_id}")
  73. else()
  74. set(OCV_DOWNLOAD_HASH_NAME "OCV_DOWNLOAD_HASH_${__file_id}")
  75. endif()
  76. if(" ${${OCV_DOWNLOAD_HASH_NAME}}" STREQUAL " ${DL_HASH}")
  77. ocv_download_log("#match_hash_in_cmake_cache \"${OCV_DOWNLOAD_HASH_NAME}\"")
  78. return()
  79. endif()
  80. unset("${OCV_DOWNLOAD_HASH_NAME}" CACHE)
  81. else()
  82. set(OCV_DOWNLOAD_HASH_NAME "")
  83. #message(WARNING "Download destination is not in CMAKE_BINARY_DIR=${CMAKE_BINARY_DIR}: ${DL_DESTINATION_DIR}")
  84. endif()
  85. # Select first non-empty url
  86. foreach(url ${DL_URL})
  87. if(url)
  88. set(DL_URL "${url}")
  89. break()
  90. endif()
  91. endforeach()
  92. # Append filename to url if needed
  93. if(DL_RELATIVE_URL)
  94. set(DL_URL "${DL_URL}${DL_FILENAME}")
  95. endif()
  96. set(mode "copy")
  97. if(DL_UNPACK)
  98. set(mode "unpack")
  99. endif()
  100. # Log all calls to file
  101. ocv_download_log("#do_${mode} \"${DL_FILENAME}\" \"${DL_HASH}\" \"${DL_URL}\" \"${DL_DESTINATION_DIR}\"")
  102. # ... and to console
  103. set(__msg_prefix "")
  104. if(DL_ID)
  105. set(__msg_prefix "${DL_ID}: ")
  106. endif()
  107. message(STATUS "${__msg_prefix}Download: ${DL_FILENAME}")
  108. # Copy mode: check if copy destination exists and is correct
  109. if(NOT DL_UNPACK)
  110. set(COPY_DESTINATION "${DL_DESTINATION_DIR}/${DL_FILENAME}")
  111. if(EXISTS "${COPY_DESTINATION}")
  112. ocv_download_log("#check_md5 \"${COPY_DESTINATION}\"")
  113. file(MD5 "${COPY_DESTINATION}" target_md5)
  114. if(target_md5 STREQUAL DL_HASH)
  115. ocv_download_log("#match_md5 \"${COPY_DESTINATION}\" \"${target_md5}\"")
  116. if(OCV_DOWNLOAD_HASH_NAME)
  117. set(${OCV_DOWNLOAD_HASH_NAME} "${DL_HASH}" CACHE INTERNAL "")
  118. endif()
  119. return()
  120. endif()
  121. ocv_download_log("#mismatch_md5 \"${COPY_DESTINATION}\" \"${target_md5}\"")
  122. else()
  123. ocv_download_log("#missing \"${COPY_DESTINATION}\"")
  124. endif()
  125. endif()
  126. # Check cache first
  127. if(DL_ID)
  128. string(TOLOWER "${DL_ID}" __id)
  129. string(REGEX REPLACE "[^a-zA-Z0-9_/ ]" "_" __id "${__id}")
  130. set(CACHE_CANDIDATE "${OPENCV_DOWNLOAD_PATH}/${__id}/${DL_HASH}-${DL_FILENAME}")
  131. else()
  132. set(CACHE_CANDIDATE "${OPENCV_DOWNLOAD_PATH}/${DL_HASH}-${DL_FILENAME}")
  133. endif()
  134. if(EXISTS "${CACHE_CANDIDATE}")
  135. ocv_download_log("#check_md5 \"${CACHE_CANDIDATE}\"")
  136. file(MD5 "${CACHE_CANDIDATE}" target_md5)
  137. if(NOT target_md5 STREQUAL DL_HASH)
  138. ocv_download_log("#mismatch_md5 \"${CACHE_CANDIDATE}\" \"${target_md5}\"")
  139. ocv_download_log("#delete \"${CACHE_CANDIDATE}\"")
  140. file(REMOVE ${CACHE_CANDIDATE})
  141. endif()
  142. endif()
  143. # Download
  144. if(NOT EXISTS "${CACHE_CANDIDATE}")
  145. ocv_download_log("#cmake_download \"${CACHE_CANDIDATE}\" \"${DL_URL}\"")
  146. foreach(try ${OPENCV_DOWNLOAD_TRIES_LIST})
  147. ocv_download_log("#try ${try}")
  148. file(DOWNLOAD "${DL_URL}" "${CACHE_CANDIDATE}"
  149. STATUS status
  150. LOG __log
  151. ${OPENCV_DOWNLOAD_PARAMS})
  152. if(status EQUAL 0)
  153. break()
  154. endif()
  155. message(STATUS "Try ${try} failed")
  156. endforeach()
  157. if(NOT OPENCV_SKIP_FILE_DOWNLOAD_DUMP) # workaround problem with old CMake versions: "Invalid escape sequence"
  158. string(LENGTH "${__log}" __log_length)
  159. if(__log_length LESS 65536)
  160. string(REPLACE "\n" "\n# " __log "${__log}")
  161. ocv_download_log("# ${__log}\n")
  162. endif()
  163. endif()
  164. if(NOT status EQUAL 0)
  165. set(msg_level FATAL_ERROR)
  166. if(DEFINED DL_STATUS)
  167. set(${DL_STATUS} FALSE PARENT_SCOPE)
  168. set(msg_level WARNING)
  169. endif()
  170. if(status MATCHES "Couldn't resolve host name")
  171. message(STATUS "
  172. =======================================================================
  173. Couldn't download files from the Internet.
  174. Please check the Internet access on this host.
  175. =======================================================================
  176. ")
  177. elseif(status MATCHES "Couldn't connect to server")
  178. message(STATUS "
  179. =======================================================================
  180. Couldn't connect to server from the Internet.
  181. Perhaps direct connections are not allowed in the current network.
  182. To use proxy please check/specify these environment variables:
  183. - http_proxy/https_proxy
  184. - and/or HTTP_PROXY/HTTPS_PROXY
  185. =======================================================================
  186. ")
  187. endif()
  188. message(${msg_level} "${__msg_prefix}Download failed: ${status}
  189. For details please refer to the download log file:
  190. ${OPENCV_DOWNLOAD_LOG}
  191. ")
  192. # write helper scripts for failed downloads
  193. file(APPEND "${OPENCV_DOWNLOAD_WITH_CURL}" "curl --create-dirs --output \"${CACHE_CANDIDATE}\" \"${DL_URL}\"\n")
  194. file(APPEND "${OPENCV_DOWNLOAD_WITH_WGET}" "mkdir -p $(dirname ${CACHE_CANDIDATE}) && wget -O \"${CACHE_CANDIDATE}\" \"${DL_URL}\"\n")
  195. return()
  196. endif()
  197. # Don't remove this code, because EXPECTED_MD5 parameter doesn't fail "file(DOWNLOAD)" step on wrong hash
  198. ocv_download_log("#check_md5 \"${CACHE_CANDIDATE}\"")
  199. file(MD5 "${CACHE_CANDIDATE}" target_md5)
  200. if(NOT target_md5 STREQUAL DL_HASH)
  201. ocv_download_log("#mismatch_md5 \"${CACHE_CANDIDATE}\" \"${target_md5}\"")
  202. set(msg_level FATAL_ERROR)
  203. if(DEFINED DL_STATUS)
  204. set(${DL_STATUS} FALSE PARENT_SCOPE)
  205. set(msg_level WARNING)
  206. endif()
  207. message(${msg_level} "${__msg_prefix}Hash mismatch: ${target_md5}")
  208. return()
  209. endif()
  210. endif()
  211. # Unpack or copy
  212. if(DL_UNPACK)
  213. if(EXISTS "${DL_DESTINATION_DIR}")
  214. ocv_download_log("#remove_unpack \"${DL_DESTINATION_DIR}\"")
  215. file(REMOVE_RECURSE "${DL_DESTINATION_DIR}")
  216. endif()
  217. ocv_download_log("#mkdir \"${DL_DESTINATION_DIR}\"")
  218. file(MAKE_DIRECTORY "${DL_DESTINATION_DIR}")
  219. ocv_download_log("#unpack \"${DL_DESTINATION_DIR}\" \"${CACHE_CANDIDATE}\"")
  220. execute_process(COMMAND "${CMAKE_COMMAND}" -E tar xzf "${CACHE_CANDIDATE}"
  221. WORKING_DIRECTORY "${DL_DESTINATION_DIR}"
  222. RESULT_VARIABLE res)
  223. if(NOT res EQUAL 0)
  224. message(FATAL_ERROR "${__msg_prefix}Unpack failed: ${res}")
  225. endif()
  226. else()
  227. ocv_download_log("#copy \"${COPY_DESTINATION}\" \"${CACHE_CANDIDATE}\"")
  228. execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CACHE_CANDIDATE}" "${COPY_DESTINATION}"
  229. RESULT_VARIABLE res)
  230. if(NOT res EQUAL 0)
  231. message(FATAL_ERROR "${__msg_prefix}Copy failed: ${res}")
  232. endif()
  233. endif()
  234. if(OCV_DOWNLOAD_HASH_NAME)
  235. set(${OCV_DOWNLOAD_HASH_NAME} "${DL_HASH}" CACHE INTERNAL "")
  236. endif()
  237. endfunction()