DownloadAndExtractFile.cmake 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. if(NOT DEFINED PREFIX)
  2. message(FATAL_ERROR "PREFIX must be defined.")
  3. endif()
  4. if(NOT DEFINED URL)
  5. message(FATAL_ERROR "URL must be defined.")
  6. endif()
  7. if(NOT DEFINED DOWNLOAD_DIR)
  8. message(FATAL_ERROR "DOWNLOAD_DIR must be defined.")
  9. endif()
  10. if(NOT DEFINED EXPECTED_SHA256)
  11. message(FATAL_ERROR "EXPECTED_SHA256 must be defined.")
  12. endif()
  13. if(NOT DEFINED TARGET)
  14. message(FATAL_ERROR "TARGET must be defined.")
  15. endif()
  16. if(NOT DEFINED SRC_DIR)
  17. set(SRC_DIR ${PREFIX}/src/${TARGET})
  18. endif()
  19. set(BINARY_DIR ${PREFIX}/src/${TARGET}-build)
  20. # Check whether the source has been downloaded. If true, skip it.
  21. # Useful for external downloads like homebrew.
  22. if(USE_EXISTING_SRC_DIR)
  23. if(EXISTS "${SRC_DIR}" AND IS_DIRECTORY "${SRC_DIR}")
  24. file(GLOB EXISTED_FILES "${SRC_DIR}/*")
  25. if(EXISTED_FILES)
  26. message(STATUS "${SRC_DIR} is found and not empty, skipping download and extraction. ")
  27. return()
  28. endif()
  29. endif()
  30. message(FATAL_ERROR "USE_EXISTING_SRC_DIR set to ON, but '${SRC_DIR}' does not exist or is empty.")
  31. endif()
  32. # Taken from ExternalProject_Add. Let's hope we can drop this one day when
  33. # ExternalProject_Add allows you to disable SHOW_PROGRESS on the file download.
  34. if(TIMEOUT)
  35. set(timeout_args TIMEOUT ${timeout})
  36. set(timeout_msg "${timeout} seconds")
  37. else()
  38. set(timeout_args "")
  39. set(timeout_msg "none")
  40. endif()
  41. string(REGEX MATCH "[^/\\?]*$" fname "${URL}")
  42. if(NOT "${fname}" MATCHES "(\\.|=)(bz2|tar|tgz|tar\\.gz|zip)$")
  43. string(REGEX MATCH "([^/\\?]+(\\.|=)(bz2|tar|tgz|tar\\.gz|zip))/.*$" match_result "${URL}")
  44. set(fname "${CMAKE_MATCH_1}")
  45. endif()
  46. if(NOT "${fname}" MATCHES "(\\.|=)(bz2|tar|tgz|tar\\.gz|zip)$")
  47. message(FATAL_ERROR "Could not extract tarball filename from url:\n ${url}")
  48. endif()
  49. string(REPLACE ";" "-" fname "${fname}")
  50. set(file ${DOWNLOAD_DIR}/${fname})
  51. message(STATUS "file: ${file}")
  52. set(EXISTING_SHA256 "")
  53. if(EXISTS ${file})
  54. file(SHA256 ${file} EXISTING_SHA256)
  55. endif()
  56. if(NOT EXISTING_SHA256 STREQUAL ${EXPECTED_SHA256})
  57. message(STATUS "downloading...
  58. src='${URL}'
  59. dst='${file}'
  60. timeout='${timeout_msg}'")
  61. file(DOWNLOAD ${URL} ${file}
  62. ${timeout_args}
  63. ${hash_args}
  64. STATUS status
  65. LOG log)
  66. list(GET status 0 status_code)
  67. list(GET status 1 status_string)
  68. if(NOT status_code EQUAL 0)
  69. # Retry on certain errors, e.g. CURLE_COULDNT_RESOLVE_HOST, which is often
  70. # seen with libtermkey (www.leonerd.org.uk).
  71. if((status_code EQUAL 6) # "Couldn't resolve host name"
  72. OR (status_code EQUAL 7)) # "Couldn't connect to server"
  73. message(STATUS "warning: retrying '${URL}' (${status_string}, status ${status_code})")
  74. execute_process(COMMAND ${CMAKE_COMMAND} -E sleep 10)
  75. file(DOWNLOAD ${URL} ${file}
  76. ${timeout_args}
  77. ${hash_args}
  78. STATUS status
  79. LOG log)
  80. list(GET status 0 status_code)
  81. list(GET status 1 status_string)
  82. endif()
  83. if(NOT status_code EQUAL 0)
  84. message(FATAL_ERROR "error: downloading '${URL}' failed
  85. status_code: ${status_code}
  86. status_string: ${status_string}
  87. log: ${log}
  88. ")
  89. endif()
  90. endif()
  91. endif()
  92. set(NULL_SHA256 "0000000000000000000000000000000000000000000000000000000000000000")
  93. # Allow users to use "SKIP" or "skip" as the sha256 to skip checking the hash.
  94. # You can still use the all zeros hash too.
  95. if((EXPECTED_SHA256 STREQUAL "SKIP") OR (EXPECTED_SHA256 STREQUAL "skip"))
  96. set(EXPECTED_SHA256 ${NULL_SHA256})
  97. endif()
  98. # We could avoid computing the SHA256 entirely if a NULL_SHA256 was given,
  99. # but we want to warn users of an empty file.
  100. file(SHA256 ${file} ACTUAL_SHA256)
  101. if(ACTUAL_SHA256 STREQUAL "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
  102. # File was empty. It's likely due to lack of SSL support.
  103. message(FATAL_ERROR
  104. "Failed to download ${URL}. The file is empty and likely means CMake "
  105. "was built without SSL support. Please use a version of CMake with "
  106. "proper SSL support. See "
  107. "https://github.com/neovim/neovim/wiki/Building-Neovim#build-prerequisites "
  108. "for more information.")
  109. elseif((NOT EXPECTED_SHA256 STREQUAL NULL_SHA256) AND
  110. (NOT EXPECTED_SHA256 STREQUAL ACTUAL_SHA256))
  111. # Wasn't a NULL SHA256 and we didn't match, so we fail.
  112. message(FATAL_ERROR
  113. "Failed to download ${URL}. Expected a SHA256 of "
  114. "${EXPECTED_SHA256} but got ${ACTUAL_SHA256} instead.")
  115. endif()
  116. message(STATUS "downloading... done")
  117. # Slurped from a generated extract-TARGET.cmake file.
  118. message(STATUS "extracting...
  119. src='${file}'
  120. dst='${SRC_DIR}'")
  121. if(NOT EXISTS "${file}")
  122. message(FATAL_ERROR "error: file to extract does not exist: '${file}'")
  123. endif()
  124. # Prepare a space for extracting:
  125. #
  126. set(i 1234)
  127. while(EXISTS "${SRC_DIR}/../ex-${TARGET}${i}")
  128. math(EXPR i "${i} + 1")
  129. endwhile()
  130. set(ut_dir "${SRC_DIR}/../ex-${TARGET}${i}")
  131. file(MAKE_DIRECTORY "${ut_dir}")
  132. # Extract it:
  133. #
  134. message(STATUS "extracting... [tar xfz]")
  135. execute_process(COMMAND ${CMAKE_COMMAND} -E tar xfz ${file}
  136. WORKING_DIRECTORY ${ut_dir}
  137. RESULT_VARIABLE rv)
  138. if(NOT rv EQUAL 0)
  139. message(STATUS "extracting... [error clean up]")
  140. file(REMOVE_RECURSE "${ut_dir}")
  141. message(FATAL_ERROR "error: extract of '${file}' failed")
  142. endif()
  143. # Analyze what came out of the tar file:
  144. #
  145. message(STATUS "extracting... [analysis]")
  146. file(GLOB contents "${ut_dir}/*")
  147. list(LENGTH contents n)
  148. if(NOT n EQUAL 1 OR NOT IS_DIRECTORY "${contents}")
  149. set(contents "${ut_dir}")
  150. endif()
  151. # Move "the one" directory to the final directory:
  152. #
  153. message(STATUS "extracting... [rename]")
  154. file(REMOVE_RECURSE ${SRC_DIR})
  155. get_filename_component(contents ${contents} ABSOLUTE)
  156. file(RENAME ${contents} ${SRC_DIR})
  157. # Remove any existing BINARY_DIR, to force a new build.
  158. # Without this a necessary output (e.g. libluv.a) might not be updated/installed.
  159. #
  160. message(STATUS "extracting... [clean binary dir]")
  161. file(REMOVE_RECURSE ${BINARY_DIR})
  162. file(MAKE_DIRECTORY ${BINARY_DIR})
  163. # Clean up:
  164. #
  165. message(STATUS "extracting... [clean up]")
  166. file(REMOVE_RECURSE "${ut_dir}")
  167. message(STATUS "extracting... done")