#!/usr/bin/env bash set -euo pipefail SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd) ROOT_DIR=$(cd -- "${SCRIPT_DIR}/.." && pwd) CONFIG_FILE="${ROOT_DIR}/config/mesa-opt.conf" if [[ ! -f "${CONFIG_FILE}" ]]; then echo "missing config: ${CONFIG_FILE}" >&2 exit 1 fi # shellcheck disable=SC1090 source "${CONFIG_FILE}" require_cmd() { local cmd for cmd in "$@"; do command -v "${cmd}" >/dev/null 2>&1 || { echo "missing command: ${cmd}" >&2 exit 1 } done } require_cmd dpkg-deb git ldd meson ninja pkg-config python3 readlink WORK_DIR="${ROOT_DIR}/work" LIBDRM_SRC_DIR="${WORK_DIR}/libdrm" LIBDRM_BUILD_DIR="${WORK_DIR}/build-libdrm" SRC_DIR="${WORK_DIR}/mesa" BUILD_DIR="${WORK_DIR}/build" PKG_DIR="${WORK_DIR}/pkg" PREREQ_DIR="${WORK_DIR}/prereq" DIST_DIR="${ROOT_DIR}/dist" mkdir -p "${WORK_DIR}" "${DIST_DIR}" rm -rf "${LIBDRM_SRC_DIR}" "${LIBDRM_BUILD_DIR}" "${SRC_DIR}" "${BUILD_DIR}" "${PKG_DIR}" "${PREREQ_DIR}" mkdir -p "${PKG_DIR}" UPSTREAM_REF="${MESA_UPSTREAM_REF:-${UPSTREAM_GIT_REF}}" LIBDRM_REF="${LIBDRM_UPSTREAM_REF:-${LIBDRM_GIT_REF}}" git clone --depth 1 --single-branch --branch "${LIBDRM_REF}" "${LIBDRM_GIT_URL}" "${LIBDRM_SRC_DIR}" meson setup "${LIBDRM_BUILD_DIR}" "${LIBDRM_SRC_DIR}" \ --buildtype="${BUILD_TYPE}" \ --prefix="${INSTALL_PREFIX}" ninja -C "${LIBDRM_BUILD_DIR}" DESTDIR="${PREREQ_DIR}" ninja -C "${LIBDRM_BUILD_DIR}" install # Debian's xf86drm.h includes , while newer libdrm installs it below # include/libdrm/. Mirror the headers into the prefix root so Mesa finds them. if [[ -d "${PREREQ_DIR}${INSTALL_PREFIX}/include/libdrm" ]]; then ln -sf libdrm/drm.h "${PREREQ_DIR}${INSTALL_PREFIX}/include/drm.h" ln -sf libdrm/drm_mode.h "${PREREQ_DIR}${INSTALL_PREFIX}/include/drm_mode.h" ln -sf libdrm/libsync.h "${PREREQ_DIR}${INSTALL_PREFIX}/include/libsync.h" fi # libdrm's pkg-config metadata points to the real prefix path. Mirror the staged # files there during the Mesa build so compiler and linker can resolve them. mkdir -p "${INSTALL_PREFIX}" cp -a "${PREREQ_DIR}${INSTALL_PREFIX}/." "${INSTALL_PREFIX}/" export PKG_CONFIG_PATH="${PREREQ_DIR}${INSTALL_PREFIX}/lib/x86_64-linux-gnu/pkgconfig:${PREREQ_DIR}${INSTALL_PREFIX}/lib/pkgconfig:${PKG_CONFIG_PATH:-}" export LD_LIBRARY_PATH="${PREREQ_DIR}${INSTALL_PREFIX}/lib/x86_64-linux-gnu:${PREREQ_DIR}${INSTALL_PREFIX}/lib:${LD_LIBRARY_PATH:-}" # The apt version and release notes rely on the upstream commit count being # monotonic across builds. Clone the full branch history instead of repairing a # shallow clone afterwards, which is more fragile in CI and local container runs. git clone --single-branch --branch "${UPSTREAM_REF}" "${UPSTREAM_GIT_URL}" "${SRC_DIR}" detect_upstream_version() { local source_dir="${1}" if [[ -f "${source_dir}/VERSION" ]]; then sed -n '1p' "${source_dir}/VERSION" return fi awk -F"'" '/project\(/ { for (i = 1; i <= NF; ++i) if ($i ~ /^[0-9][0-9A-Za-z.+~:-]*$/) { print $i; exit } }' \ "${source_dir}/meson.build" } configure_llvm_toolchain() { local spirv_version local spirv_major if [[ -n "${LLVM_CONFIG:-}" ]]; then return fi if ! pkg-config --exists LLVMSPIRVLib; then return fi spirv_version="$(pkg-config --modversion LLVMSPIRVLib)" spirv_major="${spirv_version%%.*}" if command -v "llvm-config-${spirv_major}" >/dev/null 2>&1; then export LLVM_CONFIG="llvm-config-${spirv_major}" fi } should_bundle_runtime_lib() { local base_name="${1}" case "${base_name}" in libLLVM.so.*|libdisplay-info.so.*|libwayland-client.so.*|libwayland-cursor.so.*|libwayland-egl.so.*|libwayland-server.so.*|libxcb-keysyms.so.*) return 0 ;; *) return 1 ;; esac } bundle_runtime_libraries() { local package_lib_dir="${PKG_DIR}${INSTALL_PREFIX}/lib/x86_64-linux-gnu" local source_path local resolved_path local base_name local bundled_any=1 mkdir -p "${package_lib_dir}" while (( bundled_any != 0 )); do bundled_any=0 while IFS= read -r source_path; do [[ -n "${source_path}" ]] || continue base_name="$(basename "${source_path}")" if ! should_bundle_runtime_lib "${base_name}"; then continue fi resolved_path="$(readlink -f "${source_path}")" if [[ -f "${package_lib_dir}/$(basename "${resolved_path}")" ]]; then continue fi install -m 0644 "${resolved_path}" "${package_lib_dir}/$(basename "${resolved_path}")" if [[ "${base_name}" != "$(basename "${resolved_path}")" ]]; then ln -sf "$(basename "${resolved_path}")" "${package_lib_dir}/${base_name}" fi bundled_any=1 done < <( find "${PKG_DIR}${INSTALL_PREFIX}" -type f \( -name '*.so' -o -name '*.so.*' \) -print0 \ | xargs -0 -r ldd 2>/dev/null \ | awk '/=> \// { print $3 }' \ | sort -u ) done } GIT_SHA=$(git -C "${SRC_DIR}" rev-parse --short=12 HEAD) GIT_SHA_FULL=$(git -C "${SRC_DIR}" rev-parse HEAD) UPSTREAM_COMMIT_COUNT=$(git -C "${SRC_DIR}" rev-list --count HEAD) UPSTREAM_VERSION="${PACKAGE_VERSION_PREFIX:-$(detect_upstream_version "${SRC_DIR}")}" PACKAGE_VERSION="${UPSTREAM_VERSION}+r${UPSTREAM_COMMIT_COUNT}.${GIT_SHA}-${PACKAGE_RELEASE}" OUTPUT_DEB="${DIST_DIR}/${PACKAGE_NAME}_${PACKAGE_VERSION}_${PACKAGE_ARCH}.deb" configure_llvm_toolchain meson setup "${BUILD_DIR}" "${SRC_DIR}" \ --buildtype="${BUILD_TYPE}" \ --prefix="${INSTALL_PREFIX}" \ -Dplatforms="${PLATFORMS}" \ -Dgallium-drivers="${GALLIUM_DRIVERS}" \ -Dvulkan-drivers="${VULKAN_DRIVERS}" \ -Dvulkan-layers="${VULKAN_LAYERS}" \ -Dglx=dri \ -Dllvm=enabled \ -Dshared-glapi=enabled ninja -C "${BUILD_DIR}" cp -a "${PREREQ_DIR}/." "${PKG_DIR}/" DESTDIR="${PKG_DIR}" ninja -C "${BUILD_DIR}" install bundle_runtime_libraries mkdir -p \ "${PKG_DIR}/DEBIAN" \ "${PKG_DIR}/usr/share/doc/${PACKAGE_NAME}" \ "${PKG_DIR}/usr/bin" cat > "${PKG_DIR}/DEBIAN/control" < Depends: libc6, libexpat1, libgcc-s1, libgl1, libstdc++6, libvulkan1, libwayland-client0, libx11-6, zlib1g Description: Mesa snapshot build installed below ${INSTALL_PREFIX} Built from ${UPSTREAM_GIT_URL} (${UPSTREAM_REF}) with bundled libdrm from ${LIBDRM_GIT_URL} (${LIBDRM_REF}) and installed into ${INSTALL_PREFIX}. EOF cat > "${PKG_DIR}/usr/share/doc/${PACKAGE_NAME}/README.Debian" < "${PKG_DIR}/usr/bin/${PACKAGE_NAME}-env" </dev/null; then icd_files=(${INSTALL_PREFIX}/share/vulkan/icd.d/*.json) icd_joined=\$(printf '%s:' "\${icd_files[@]}") export VK_ICD_FILENAMES="\${icd_joined%:}" export VK_DRIVER_FILES="\${VK_ICD_FILENAMES}" fi exec "\$@" EOF chmod 0755 "${PKG_DIR}/usr/bin/${PACKAGE_NAME}-env" find "${PKG_DIR}" -type d -exec chmod 0755 {} + find "${PKG_DIR}" -path "${PKG_DIR}/DEBIAN" -prune -o -type f -exec chmod 0644 {} + chmod 0755 "${PKG_DIR}/usr/bin/${PACKAGE_NAME}-env" dpkg-deb --build "${PKG_DIR}" "${OUTPUT_DEB}" cat > "${DIST_DIR}/package-info.env" <