aboutsummaryrefslogtreecommitdiff
path: root/cmake/ExtractPackages.cmake
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-13 11:04:35 +0000
committer_ov4 <ov4@ov4.org>2026-10-13 11:04:35 +0000
commit85bd5c6663dc8c663f86828d1b1a5273ee0a82fe (patch)
tree1618bd538c148f9164c95405898bba454e2836b3 /cmake/ExtractPackages.cmake
parent08fe39b4394b0fcd0272e08f17b7fed852bc2a47 (diff)
build: extract package dependencies and prefer local libraries
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat (limited to 'cmake/ExtractPackages.cmake')
-rw-r--r--cmake/ExtractPackages.cmake86
1 files changed, 86 insertions, 0 deletions
diff --git a/cmake/ExtractPackages.cmake b/cmake/ExtractPackages.cmake
new file mode 100644
index 0000000..7b525d7
--- /dev/null
+++ b/cmake/ExtractPackages.cmake
@@ -0,0 +1,86 @@
+# Use CMake's libarchive support, including on hosts without dpkg or pacman.
+function(cpsc_extract_archive archive destination)
+ file(MAKE_DIRECTORY "${destination}")
+ execute_process(
+ COMMAND "${CMAKE_COMMAND}" -E tar xf "${archive}"
+ WORKING_DIRECTORY "${destination}"
+ RESULT_VARIABLE result ERROR_VARIABLE error
+ )
+ if(NOT result EQUAL 0)
+ message(FATAL_ERROR "Cannot extract dependency package ${archive}: ${error}")
+ endif()
+endfunction()
+
+function(cpsc_extract_packages)
+ file(GLOB_RECURSE packages CONFIGURE_DEPENDS
+ "${CPSC_DEPS_DIR}/packages/*.deb"
+ "${CPSC_DEPS_DIR}/packages/*.pkg.tar.*"
+ "${CPSC_DEPS_DIR}/packages/*.bottle*.tar.gz"
+ )
+ list(FILTER packages EXCLUDE REGEX "\\.sig$")
+ # Homebrew exposes both a cache symlink and its downloads/ target.
+ set(archives)
+ foreach(package IN LISTS packages)
+ get_filename_component(package "${package}" REALPATH)
+ list(APPEND archives "${package}")
+ endforeach()
+ list(REMOVE_DUPLICATES archives)
+ list(SORT archives)
+
+ set(stamp "${CPSC_DEPS_DIR}/packages.sha256")
+ if(NOT archives)
+ if(EXISTS "${stamp}")
+ file(REMOVE_RECURSE "${CPSC_DEPS_ROOT}")
+ file(REMOVE "${stamp}")
+ endif()
+ return()
+ endif()
+
+ set(signature "${CPSC_DEPS_ROOT}\n")
+ foreach(archive IN LISTS archives)
+ file(SHA256 "${archive}" hash)
+ string(APPEND signature "${archive}:${hash}\n")
+ endforeach()
+ foreach(module ExtractPackages LinuxPackages WindowsPackages HomebrewPackages)
+ file(SHA256 "${CPSC_DEPS_MODULE_DIR}/${module}.cmake" hash)
+ string(APPEND signature "${module}:${hash}\n")
+ endforeach()
+ if(EXISTS "${stamp}" AND IS_DIRECTORY "${CPSC_DEPS_ROOT}")
+ file(READ "${stamp}" previous_signature)
+ if(signature STREQUAL previous_signature)
+ return()
+ endif()
+ endif()
+
+ # Rebuild the managed extraction directory when the package set changes.
+ file(REMOVE "${stamp}")
+ file(REMOVE_RECURSE "${CPSC_DEPS_ROOT}")
+ file(MAKE_DIRECTORY "${CPSC_DEPS_ROOT}")
+ foreach(archive IN LISTS archives)
+ message(STATUS "Extracting dependency package: ${archive}")
+ if(archive MATCHES "\\.deb$")
+ set(unpack "${CPSC_DEPS_DIR}/unpack")
+ file(REMOVE_RECURSE "${unpack}")
+ cpsc_extract_archive("${archive}" "${unpack}")
+ file(GLOB data "${unpack}/data.tar.*" "${unpack}/data.tar")
+ list(LENGTH data data_count)
+ if(NOT data_count EQUAL 1)
+ message(FATAL_ERROR "Dependency package ${archive} must contain one data.tar archive")
+ endif()
+ cpsc_extract_archive("${data}" "${CPSC_DEPS_ROOT}")
+ file(REMOVE_RECURSE "${unpack}")
+ elseif(archive MATCHES "\\.bottle[^/]*\\.tar\\.gz$")
+ cpsc_extract_archive("${archive}" "${CPSC_DEPS_ROOT}/Cellar")
+ else()
+ cpsc_extract_archive("${archive}" "${CPSC_DEPS_ROOT}")
+ endif()
+ endforeach()
+ if(CMAKE_HOST_APPLE)
+ cpsc_prepare_homebrew_packages()
+ elseif(CMAKE_HOST_WIN32)
+ cpsc_prepare_windows_packages()
+ else()
+ cpsc_prepare_linux_packages()
+ endif()
+ file(WRITE "${stamp}" "${signature}")
+endfunction()