157 lines
6.3 KiB
Bash
Executable File
157 lines
6.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Descarga y EMBEBE (build-time) todo lo que el binario Linux necesita en runtime:
|
|
# - 7zz (7-Zip para Linux)
|
|
# - Driver MS ODBC 18 + unixODBC
|
|
# - Libs de sistema de Qt (cluster xcb/X11 + EGL) y del stack ODBC
|
|
# (libltdl, Kerberos/GSSAPI, OpenSSL) que PySide6/pyodbc cargan por dlopen
|
|
# y que NO vienen dentro del wheel.
|
|
# Objetivo: que el onefile corra en un servidor Linux "pelado" sin instalar nada.
|
|
set -euo pipefail
|
|
|
|
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
VERSIONS="$ROOT/packaging/bundled-versions.json"
|
|
BUNDLED="$ROOT/packaging/bundled/linux"
|
|
SEVEN="$BUNDLED/7zip"
|
|
ODBC="$BUNDLED/odbc/lib"
|
|
QTLIB="$BUNDLED/qt/lib" # libs de sistema extra a embeder en la raíz de _MEIPASS
|
|
|
|
mkdir -p "$SEVEN" "$ODBC" "$QTLIB"
|
|
|
|
read_url() {
|
|
python3 -c "import json; print(json.load(open('$VERSIONS'))['$1'])"
|
|
}
|
|
|
|
# Descarga uno o más paquetes .deb (y NO sus dependencias), extrae sus .so y los
|
|
# copia al directorio destino con el NOMBRE DE SONAME (lo que busca el loader:
|
|
# libfoo.so.N), dereferenciando symlinks para no dejar enlaces colgantes.
|
|
# Requiere apt-get/dpkg-deb.
|
|
fetch_pkg_libs() {
|
|
local destdir="$1"; shift
|
|
if ! command -v apt-get >/dev/null 2>&1; then
|
|
echo " (apt-get no disponible; se omite descarga de $* — el entorno de build debe proveerlas)"
|
|
return 0
|
|
fi
|
|
local tmp; tmp=$(mktemp -d)
|
|
(
|
|
cd "$tmp"
|
|
apt-get download "$@" >/dev/null 2>&1 || {
|
|
# Reintento tras refrescar índices (build env con red).
|
|
apt-get update -qq >/dev/null 2>&1 || true
|
|
apt-get download "$@" >/dev/null 2>&1 || true
|
|
}
|
|
for deb in *.deb; do
|
|
[[ -f "$deb" ]] || continue
|
|
dpkg-deb -x "$deb" x
|
|
done
|
|
[[ -d x ]] || exit 0
|
|
# 1) Symlinks SONAME del propio paquete (libfoo.so.N -> libfoo.so.N.M.P):
|
|
# copiar el contenido REAL bajo el nombre del symlink (= SONAME exacto).
|
|
while IFS= read -r link; do
|
|
cp -Lf "$link" "$destdir/$(basename "$link")" 2>/dev/null || true
|
|
done < <(find x -type l -name '*.so.*')
|
|
# 2) Archivos reales sin symlink: derivar SONAME por truncación de versión
|
|
# (libfoo.so.N.M.P -> libfoo.so.N) para no dejarlos con nombre versionado.
|
|
while IFS= read -r f; do
|
|
local soname
|
|
soname=$(basename "$f" | sed -E 's/(\.so\.[0-9]+)\..*/\1/')
|
|
[[ -e "$destdir/$soname" ]] || cp -Lf "$f" "$destdir/$soname" 2>/dev/null || true
|
|
done < <(find x -type f -name '*.so.*')
|
|
)
|
|
rm -rf "$tmp"
|
|
}
|
|
|
|
echo "==> 7-Zip Linux (7zz)"
|
|
LINUX_7Z_URL="$(read_url seven_zip_linux_x64)"
|
|
if [[ ! -f "$SEVEN/7zz" ]]; then
|
|
TMP=$(mktemp -d)
|
|
curl -fsSL -o "$TMP/7z.tar.xz" "$LINUX_7Z_URL"
|
|
tar -xJf "$TMP/7z.tar.xz" -C "$TMP"
|
|
cp "$TMP/7zz" "$SEVEN/7zz"
|
|
chmod +x "$SEVEN/7zz"
|
|
rm -rf "$TMP"
|
|
echo " 7zz instalado"
|
|
else
|
|
echo " 7zz ya existe"
|
|
fi
|
|
|
|
echo "==> ODBC Driver 18 + unixODBC"
|
|
MSODBC_DEB="$(read_url msodbcsql18_deb)"
|
|
if [[ -z "$(ls -A "$ODBC" 2>/dev/null || true)" ]]; then
|
|
TMP=$(mktemp -d)
|
|
cd "$TMP"
|
|
curl -fsSL -o msodbcsql18.deb "$MSODBC_DEB"
|
|
|
|
if command -v apt-get >/dev/null 2>&1; then
|
|
export DEBIAN_FRONTEND=noninteractive
|
|
apt-get update -qq || true
|
|
apt-get install -y -qq unixodbc dpkg-dev > /dev/null 2>&1 || true
|
|
if dpkg -l unixodbc 2>/dev/null | grep -q ^ii; then
|
|
# -L: dereferencia symlinks para no dejar enlaces colgantes en el destino.
|
|
find /usr/lib -name 'libodbc*.so*' -exec cp -Lf {} "$ODBC/" \; 2>/dev/null || true
|
|
find /usr/lib -name 'libodbcinst*.so*' -exec cp -Lf {} "$ODBC/" \; 2>/dev/null || true
|
|
fi
|
|
fi
|
|
|
|
dpkg-deb -x msodbcsql18.deb msodbcsql
|
|
# Copiar SOLO el archivo real versionado del driver (evita el symlink -> /opt).
|
|
find msodbcsql -type f -name 'libmsodbcsql-18*.so*' -exec cp -Lf {} "$ODBC/" \;
|
|
cd "$ROOT"
|
|
rm -rf "$TMP"
|
|
|
|
# Stack de dependencias del driver MS ODBC 18, JUNTO al driver, para que un
|
|
# servidor pelado (sin unixODBC/krb5/openssl) pueda cargarlo. El driver se
|
|
# patchelf-ea a RPATH=$ORIGIN (más abajo) para resolverlas en su propio dir.
|
|
ODBC_DEP_PKGS=(
|
|
libltdl7 libkrb5-3 libgssapi-krb5-2 libk5crypto3 libkrb5support0
|
|
libcom-err2 libkeyutils1 libssl3 libodbc2 libodbcinst2
|
|
)
|
|
fetch_pkg_libs "$ODBC" "${ODBC_DEP_PKGS[@]}" || true
|
|
fetch_pkg_libs "$ODBC" unixodbc || true
|
|
echo " Bibliotecas ODBC + deps en $ODBC"
|
|
else
|
|
echo " ODBC ya existe"
|
|
fi
|
|
|
|
# RPATH=$ORIGIN en TODAS las .so del cluster ODBC: así el driver y sus deps
|
|
# (libkrb5 -> libk5crypto/libkrb5support/libkeyutils, libgssapi, libltdl,
|
|
# libodbcinst, openssl) se resuelven entre sí en su propio directorio una vez
|
|
# copiados a config/odbc/lib, sin depender de LD_LIBRARY_PATH.
|
|
if command -v patchelf >/dev/null 2>&1; then
|
|
for so in "$ODBC"/*.so*; do
|
|
[[ -f "$so" && ! -L "$so" ]] || continue
|
|
patchelf --set-rpath '$ORIGIN' "$so" 2>/dev/null || true
|
|
done
|
|
echo " RPATH=\$ORIGIN aplicado a todo el cluster ODBC"
|
|
else
|
|
echo " ADVERTENCIA: patchelf no disponible; el driver ODBC podría no resolver" >&2
|
|
echo " sus deps en un servidor sin unixODBC/krb5. Instálalo en el entorno de build." >&2
|
|
fi
|
|
|
|
echo "==> Libs de sistema Qt (cluster xcb/X11 + EGL) para la GUI con display"
|
|
if [[ -z "$(ls -A "$QTLIB" 2>/dev/null || true)" ]]; then
|
|
# Plataforma Qt xcb + su cierre X11/xcb + EGL. Van junto a las libs Qt en el
|
|
# onefile (PySide6/Qt/lib) para que libQt6XcbQpa las encuentre por $ORIGIN.
|
|
QT_XCB_PKGS=(
|
|
libxcb-cursor0 libxcb-icccm4 libxcb-util1 libxcb-image0 libxcb-keysyms1
|
|
libxcb-render-util0 libxcb-render0 libxcb-shape0 libxcb-xkb1
|
|
libxkbcommon-x11-0 libxkbcommon0 libxtst6 libxcomposite1 libxdamage1
|
|
libxrandr2 libxkbfile1 libxcb1 libx11-6 libx11-xcb1 libxext6 libxrender1
|
|
libxi6 libxfixes3 libxcb-glx0 libxcb-randr0 libxcb-shm0 libxcb-sync1
|
|
libxcb-present0 libxcb-dri2-0 libxcb-dri3-0 libxcb-xfixes0 libxau6
|
|
libxdmcp6 libbsd0 libsm6 libice6
|
|
)
|
|
QT_GL_PKGS=(libglvnd0 libegl1 libgl1 libopengl0 libglx0 libgles2)
|
|
fetch_pkg_libs "$QTLIB" "${QT_XCB_PKGS[@]}"
|
|
fetch_pkg_libs "$QTLIB" "${QT_GL_PKGS[@]}"
|
|
COUNT=$(find "$QTLIB" -type f -name '*.so*' 2>/dev/null | wc -l)
|
|
echo " $COUNT libs Qt embebidas en $QTLIB"
|
|
if [[ "$COUNT" -eq 0 ]]; then
|
|
echo " ADVERTENCIA: no se embebió ninguna lib Qt. El entorno de build" >&2
|
|
echo " (docker-build-linux.sh) debe traerlas para que PyInstaller las incluya." >&2
|
|
fi
|
|
else
|
|
echo " Libs Qt ya existen ($(find "$QTLIB" -type f -name '*.so*' | wc -l) archivos)"
|
|
fi
|
|
|
|
echo "Listo: $BUNDLED"
|