Compilat onefile amb Nuitka (app.py + zstandard) i rutes en mode onefile
This commit is contained in:
@@ -64,10 +64,33 @@ Una entrada `[[game]]` por juego. Campos:
|
|||||||
| `info_url` | no | API Gitea del repo (def. derivada de `clone_url`) |
|
| `info_url` | no | API Gitea del repo (def. derivada de `clone_url`) |
|
||||||
| `icon_rel` | no | ruta del icono dentro del repo (def. `release/icons/icon.png`) |
|
| `icon_rel` | no | ruta del icono dentro del repo (def. `release/icons/icon.png`) |
|
||||||
|
|
||||||
## Compilar a binario (Nuitka)
|
## Compilar a binario (Nuitka, onefile)
|
||||||
|
|
||||||
|
`build.sh` lo hace todo: crea el `.venv`, instala dependencias (PySide6 + Nuitka +
|
||||||
|
zstandard) y compila un único ejecutable comprimido, empaquetándolo en
|
||||||
|
`dist/jlauncher-v<versión>-<os>-<arch>.tar.gz` junto a `games.toml`.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install nuitka PySide6
|
|
||||||
./build.sh
|
./build.sh
|
||||||
# binario en dist/jlauncher.dist/jlauncher
|
# binario: dist/jlauncher (+ dist/games.toml)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
El binario crea `jlauncher_data/` y `settings.json` **junto a sí mismo** (resuelto vía
|
||||||
|
`NUITKA_ONEFILE_DIRECTORY`). El punto de entrada para empaquetar es `app.py` (desde
|
||||||
|
fuente se ejecuta con `python -m jlauncher`).
|
||||||
|
|
||||||
|
### Prerequisitos del sistema (no los instala el script)
|
||||||
|
|
||||||
|
- **Python 3.11+** (usa `tomllib`).
|
||||||
|
- Un **compilador C**:
|
||||||
|
- Linux: `gcc` y `patchelf` (p. ej. `apt install build-essential patchelf python3-dev`).
|
||||||
|
- macOS: **Xcode Command Line Tools** (`xcode-select --install`); aquí *no* hace falta
|
||||||
|
patchelf (Nuitka usa `install_name_tool`).
|
||||||
|
- `git` en el PATH.
|
||||||
|
|
||||||
|
### macOS
|
||||||
|
|
||||||
|
Compila en el propio Mac (Nuitka no compila cruzado): `./build.sh` genera
|
||||||
|
`jlauncher-v…-darwin-arm64.tar.gz`. Como el binario no va firmado, la primera vez quizá
|
||||||
|
debas hacer `xattr -dr com.apple.quarantine jlauncher` o abrirlo con clic derecho → Abrir.
|
||||||
|
Lánzalo desde terminal (`./jlauncher`).
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
"""Punto de entrada para empaquetar con Nuitka.
|
||||||
|
|
||||||
|
Importa el paquete ``jlauncher`` con imports absolutos para que los imports relativos
|
||||||
|
internos (``from .config import …``) resuelvan correctamente al compilar. Para ejecutar
|
||||||
|
desde fuente sigue valiendo ``python -m jlauncher``.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from jlauncher.__main__ import main
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
@@ -1,19 +1,63 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Compila jlauncher a un binario nativo (C, vía Nuitka).
|
# Compila jlauncher a un binario standalone con Nuitka y empaqueta un tar.gz de release.
|
||||||
# Requiere: pip install nuitka PySide6
|
# Requisitos del sistema: python3-dev, gcc, patchelf (ver README).
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
cd "$(dirname "$0")"
|
HERE="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
cd "$HERE"
|
||||||
|
|
||||||
python -m nuitka \
|
VERSION="$(sed -n 's/^__version__[[:space:]]*=[[:space:]]*"\([^"]*\)".*/\1/p' jlauncher/__init__.py | head -n1)"
|
||||||
--standalone \
|
if [ -z "$VERSION" ]; then
|
||||||
--assume-yes-for-downloads \
|
echo "[build] no se pudo leer __version__ de jlauncher/__init__.py" >&2
|
||||||
--enable-plugin=pyside6 \
|
exit 1
|
||||||
--output-dir=dist \
|
fi
|
||||||
--output-filename=jlauncher \
|
ARCH="$(uname -m)"
|
||||||
--include-data-files=games.toml=games.toml \
|
OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
||||||
jlauncher
|
RELEASE_NAME="jlauncher-v${VERSION}-${OS}-${ARCH}"
|
||||||
|
|
||||||
echo
|
if [ ! -d .venv ]; then
|
||||||
echo "Listo. Binario en: dist/jlauncher.dist/jlauncher"
|
echo "[build] creando venv…"
|
||||||
echo "games.toml se incluye junto al binario; jlauncher_data/ se creará al lado al ejecutar."
|
python3 -m venv .venv
|
||||||
|
.venv/bin/pip install --quiet --upgrade pip
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[build] sincronizando dependencias…"
|
||||||
|
.venv/bin/pip install --quiet -r requirements.txt
|
||||||
|
|
||||||
|
if ! .venv/bin/python -c "import nuitka" 2>/dev/null; then
|
||||||
|
echo "[build] instalando nuitka en el venv…"
|
||||||
|
.venv/bin/pip install --quiet "nuitka[onefile]"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# zstandard habilita la compresión del onefile (binario mucho más pequeño).
|
||||||
|
if ! .venv/bin/python -c "import zstandard" 2>/dev/null; then
|
||||||
|
echo "[build] instalando zstandard (compresión onefile)…"
|
||||||
|
.venv/bin/pip install --quiet zstandard
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[build] versión: v${VERSION}"
|
||||||
|
echo "[build] limpiando artefactos previos…"
|
||||||
|
rm -rf dist build app.build app.dist app.onefile-build
|
||||||
|
|
||||||
|
echo "[build] compilando (PySide6 onefile; puede tardar varios minutos)…"
|
||||||
|
.venv/bin/python -m nuitka \
|
||||||
|
--onefile \
|
||||||
|
--assume-yes-for-downloads \
|
||||||
|
--enable-plugin=pyside6 \
|
||||||
|
--include-package=jlauncher \
|
||||||
|
--output-dir=dist \
|
||||||
|
--output-filename=jlauncher \
|
||||||
|
--remove-output \
|
||||||
|
--lto=yes \
|
||||||
|
app.py
|
||||||
|
|
||||||
|
echo "[build] copiando games.toml junto al binario…"
|
||||||
|
cp games.toml dist/games.toml
|
||||||
|
|
||||||
|
echo "[build] empaquetando release ${RELEASE_NAME}.tar.gz…"
|
||||||
|
tar -czf "dist/${RELEASE_NAME}.tar.gz" -C dist jlauncher games.toml
|
||||||
|
|
||||||
|
echo "[build] hecho:"
|
||||||
|
ls -lh "dist/jlauncher" "dist/games.toml" "dist/${RELEASE_NAME}.tar.gz"
|
||||||
|
echo "[build] el binario crea jlauncher_data/ y settings.json junto a sí mismo."
|
||||||
|
echo "[build] distribuir: descomprimir el tar.gz (jlauncher + games.toml juntos)."
|
||||||
|
|||||||
+11
-3
@@ -1,12 +1,14 @@
|
|||||||
"""Resolución de rutas: dónde está games.toml y dónde guardar los datos.
|
"""Resolución de rutas: dónde está games.toml y dónde guardar los datos.
|
||||||
|
|
||||||
Cuando se compila con Nuitka (``--standalone``) el atributo global ``__compiled__``
|
Compilado con Nuitka, ``__compiled__`` existe. En modo ``--onefile`` la carpeta del
|
||||||
existe, así que usamos la carpeta del ejecutable. Ejecutando desde fuente usamos la
|
binario real la expone ``NUITKA_ONEFILE_DIRECTORY`` (Nuitka 4.x); con versiones que usan
|
||||||
raíz del proyecto (la carpeta que contiene el paquete ``jlauncher``).
|
``NUITKA_ONEFILE_BINARY`` tomamos su carpeta; si no, ``sys.executable`` (standalone).
|
||||||
|
Ejecutando desde fuente usamos la raíz del proyecto (la carpeta que contiene ``jlauncher``).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
@@ -21,6 +23,12 @@ def is_compiled() -> bool:
|
|||||||
def base_dir() -> Path:
|
def base_dir() -> Path:
|
||||||
"""Carpeta base junto a la que viven games.toml y jlauncher_data."""
|
"""Carpeta base junto a la que viven games.toml y jlauncher_data."""
|
||||||
if is_compiled():
|
if is_compiled():
|
||||||
|
directory = os.environ.get("NUITKA_ONEFILE_DIRECTORY")
|
||||||
|
if directory:
|
||||||
|
return Path(directory).resolve()
|
||||||
|
binary = os.environ.get("NUITKA_ONEFILE_BINARY")
|
||||||
|
if binary:
|
||||||
|
return Path(binary).resolve().parent
|
||||||
return Path(sys.executable).resolve().parent
|
return Path(sys.executable).resolve().parent
|
||||||
# Desde fuente: raíz del proyecto = padre del paquete jlauncher/
|
# Desde fuente: raíz del proyecto = padre del paquete jlauncher/
|
||||||
return Path(__file__).resolve().parent.parent
|
return Path(__file__).resolve().parent.parent
|
||||||
|
|||||||
Reference in New Issue
Block a user