DownloadAndExtractFile.cmake 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  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. message(STATUS "downloading...
  53. src='${URL}'
  54. dst='${file}'
  55. timeout='${timeout_msg}'")
  56. file(DOWNLOAD ${URL} ${file}
  57. ${timeout_args}
  58. ${hash_args}
  59. STATUS status
  60. LOG log)
  61. list(GET status 0 status_code)
  62. list(GET status 1 status_string)
  63. if(NOT status_code EQUAL 0)
  64. # Retry on certain errors, e.g. CURLE_COULDNT_RESOLVE_HOST, which is often
  65. # seen with libtermkey (www.leonerd.org.uk).
  66. if(status_code EQUAL 6) # "Couldn't resolve host name"
  67. message(STATUS "warning: retrying '${URL}' (${status_string}, status ${status_code})")
  68. execute_process(COMMAND ${CMAKE_COMMAND} -E sleep 10)
  69. file(DOWNLOAD ${URL} ${file}
  70. ${timeout_args}
  71. ${hash_args}
  72. STATUS status
  73. LOG log)
  74. list(GET status 0 status_code)
  75. list(GET status 1 status_string)
  76. endif()
  77. if(NOT status_code EQUAL 0)
  78. message(FATAL_ERROR "error: downloading '${URL}' failed
  79. status_code: ${status_code}
  80. status_string: ${status_string}
  81. log: ${log}
  82. ")
  83. endif()
  84. endif()
  85. set(NULL_SHA256 "0000000000000000000000000000000000000000000000000000000000000000")
  86. # Allow users to use "SKIP" or "skip" as the sha256 to skip checking the hash.
  87. # You can still use the all zeros hash too.
  88. if((EXPECTED_SHA256 STREQUAL "SKIP") OR (EXPECTED_SHA256 STREQUAL "skip"))
  89. set(EXPECTED_SHA256 ${NULL_SHA256})
  90. endif()
  91. # We could avoid computing the SHA256 entirely if a NULL_SHA256 was given,
  92. # but we want to warn users of an empty file.
  93. file(SHA256 ${file} ACTUAL_SHA256)
  94. if(ACTUAL_SHA256 STREQUAL "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
  95. # File was empty. It's likely due to lack of SSL support.
  96. message(FATAL_ERROR
  97. "Failed to download ${URL}. The file is empty and likely means CMake "
  98. "was built without SSL support. Please use a version of CMake with "
  99. "proper SSL support. See "
  100. "https://github.com/neovim/neovim/wiki/Building-Neovim#build-prerequisites "
  101. "for more information.")
  102. elseif((NOT EXPECTED_SHA256 STREQUAL NULL_SHA256) AND
  103. (NOT EXPECTED_SHA256 STREQUAL ACTUAL_SHA256))
  104. # Wasn't a NULL SHA256 and we didn't match, so we fail.
  105. message(FATAL_ERROR
  106. "Failed to download ${URL}. Expected a SHA256 of "
  107. "${EXPECTED_SHA256} but got ${ACTUAL_SHA256} instead.")
  108. endif()
  109. message(STATUS "downloading... done")
  110. # Slurped from a generated extract-TARGET.cmake file.
  111. message(STATUS "extracting...
  112. src='${file}'
  113. dst='${SRC_DIR}'")
  114. if(NOT EXISTS "${file}")
  115. message(FATAL_ERROR "error: file to extract does not exist: '${file}'")
  116. endif()
  117. # Prepare a space for extracting:
  118. #
  119. set(i 1234)
  120. while(EXISTS "${SRC_DIR}/../ex-${TARGET}${i}")
  121. math(EXPR i "${i} + 1")
  122. endwhile()
  123. set(ut_dir "${SRC_DIR}/../ex-${TARGET}${i}")
  124. file(MAKE_DIRECTORY "${ut_dir}")
  125. # Extract it:
  126. #
  127. message(STATUS "extracting... [tar xfz]")
  128. execute_process(COMMAND ${CMAKE_COMMAND} -E tar xfz ${file}
  129. WORKING_DIRECTORY ${ut_dir}
  130. RESULT_VARIABLE rv)
  131. if(NOT rv EQUAL 0)
  132. message(STATUS "extracting... [error clean up]")
  133. file(REMOVE_RECURSE "${ut_dir}")
  134. message(FATAL_ERROR "error: extract of '${file}' failed")
  135. endif()
  136. # Analyze what came out of the tar file:
  137. #
  138. message(STATUS "extracting... [analysis]")
  139. file(GLOB contents "${ut_dir}/*")
  140. list(LENGTH contents n)
  141. if(NOT n EQUAL 1 OR NOT IS_DIRECTORY "${contents}")
  142. set(contents "${ut_dir}")
  143. endif()
  144. # Move "the one" directory to the final directory:
  145. #
  146. message(STATUS "extracting... [rename]")
  147. file(REMOVE_RECURSE ${SRC_DIR})
  148. get_filename_component(contents ${contents} ABSOLUTE)
  149. file(RENAME ${contents} ${SRC_DIR})
  150. # Remove any existing BINARY_DIR, to force a new build.
  151. # Without this a necessary output (e.g. libluv.a) might not be updated/installed.
  152. #
  153. message(STATUS "extracting... [clean binary dir]")
  154. file(REMOVE_RECURSE ${BINARY_DIR})
  155. file(MAKE_DIRECTORY ${BINARY_DIR})
  156. # Clean up:
  157. #
  158. message(STATUS "extracting... [clean up]")
  159. file(REMOVE_RECURSE "${ut_dir}")
  160. message(STATUS "extracting... done")