Today, I’ll address a topic I previously mentioned in ExternalProject Practices: how to download third-party dependencies.
Clarifying Requirements
Since everyone’s needs might differ, let’s discuss a common requirement: downloading a third-party dependency archive. Thus, we need to download the archive file locally, verify the file signature, and then extract it to a designated directory.
Commands Provided by CMake
We will mainly use the following commands:
1 2 3 4 5 6 7 8 9
- file - DOWNLOAD: Downloads a file - INSTALL: Installs files into a directory - READ: Reads the contents of a file - REMOVE: Deletes a file - REMOVE_RECURSE: Recursively deletes files - MAKE_DIRECTORY: Creates a directory - cmake_parse_arguments: Parses function arguments - execute_process: Executes external commands (note that external commands may run on different operating systems, so try to use commands provided by CMake to ensure compatibility across platforms.)
function(extract_file filename extract_dir) message(STATUS "Extracting to ${extract_dir} ...")
# Create a temporary directory for extraction; if it already exists, delete it # The following command uses CMake's internal extraction command, enabling cross-platform extraction: # cmake -E tar -xf filename.tgz set(temp_dir ${CMAKE_BINARY_DIR}/tmp_for_extract.dir) if(EXISTS${temp_dir}) file(REMOVE_RECURSE ${temp_dir}) endif() file(MAKE_DIRECTORY${temp_dir}) execute_process(COMMAND${CMAKE_COMMAND} -E tar -xf ${filename} WORKING_DIRECTORY ${temp_dir})
# This step is crucial as the temporary directory might contain a single folder with our desired content # or directly contain the files we need. Here, handle both cases uniformly by setting the source directory # to the subdirectory of the temporary directory if it contains a single folder file(GLOB contents "${temp_dir}/*") list(LENGTH contents n) if(NOT n EQUAL1ORNOTIS_DIRECTORY"${contents}") set(contents "${temp_dir}") endif()
get_filename_component(contents ${contents} ABSOLUTE) # Choose INSTALL over COPY to display file copying status file(INSTALL"${contents}/" DESTINATION ${extract_dir}) # Don't forget to delete the temporary directory file(REMOVE_RECURSE ${temp_dir}) endfunction()