Creando winepak para evoland

2018/09/04

Objetivo

Luego de enterarme de la existencia de winepak, pensé en empaquetar una aplicación de windows para probar como funciona.

Para dar un contexto, winepak es un runtime para flatpak que como su nombre lo indica incluye a wine y puede utilizarse para ejecutar aplicaciones windows, instalandolas mediante flatpak.

PlayOnLinux

Una alternativa a crear un flatpak podría ser utilizar playonlinux.

La ventaja de flatpak es que se puede tener instalado a nivel de sistema los runtime con las diferentes versiones de wine, mientras que en playonlinux estas instalaciones se deben hacer por usuario.

Por otro lado, la ventaja de playonlinux es que tiene muchas más versiones de wine disponibles.

Evoland

Como ejemplo de aplicación a probar utilizaré el juego evoland, comprado en gog y que según la base de datos de aplicaciones de wine tiene un rating de platino para la versión de gog.com, lo que permite suponer que funcionará sin problemas emulandose mediante wine.

Vale la pena mencionar que la ventaja de haber realizado la compra en gog es que el juego está libre de DRM, lo que debería hacer la tarea de empaquetación de la aplicación más fácil.

Instalación de dependencias

flatpak

A continuación las dependencias necesarias para comenzar a trabajar:

  1. flatpak-builder: necesario para realizar el empaquetado y que no tiene por que estar necesariamente instalado ya que usualmente se utiliza el paquete flatpak para ejecutar las aplicaciones. En debian basta con hacer:

    $ sudo apt-get install -V flatpak-builder
    

    Si se está utilizando debian stretch (estable), con backports habilitados conviene instalarlo haciendo

    $ sudo apt-get install -V -t stretch-backports flatpak-builder
    

    para obtener la última versión disponible.

  2. runtime winepak: según consta en la documentación de desarrollo de winepak, hay que instalar el runtime y el sdk de winepak, junto con sus dependencias:

    Primero se agrega el sdk y runtime de freedesktop del cual depende winepak:

    $ flatpak remote-add --user --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo
    $ flatpak install --user flathub org.freedesktop.Sdk
    $ flatpak install --user flathub org.freedesktop.Platform
    

    Luego se agrega el sdk y el runtime de winepak:

    $ flatpak remote-add --user --if-not-exists winepak https://dl.winepak.org/repo/winepak.flatpakrepo
    $ flatpak install --user winepak org.winepak.Sdk/x86_64/3.0
    $ flatpak install --user winepak org.winepak.Platform/x86_64/3.0
    $ flatpak install --user winepak org.winepak.Platform.Compat32/x86_64/3.0
    

    Nota: solo se instala la última version estable de wine (no las staging) de 64bits. Se agrega Compat32 para poder utilizar versiones de aplicaciones de 32bits con wine. Para determinar la última versión estable se utiliza:

    $ flatpak remote-ls --show-details winepak | grep -i sdk
    runtime/org.winepak.Sdk/x86_64/3.0      9ffce8874289    2.5 GB  994.2 MB
    
  3. evoland: el programa evoland, que se descargará del sitio de gog como se indicó más arriba. A continuacion el sha256 del archivo descargado:

    a478ca738c312a6b8a2f289f309efa7c893efe3b06ff1753a6bea88864b62ce7  setup_evoland_1.1.2490_(20677).exe
    

    Se comprueba que es una aplicación windows de 32bits utilizando el comando file:

    $ file "setup_evoland_1.1.2490_(20677).exe"
    /home/jmpc/Downloads/setup_evoland_1.1.2490_(20677).exe: PE32 executable (GUI) Intel 80386, for MS Windows
    

    por lo que va a tener sentido utilizar la extensión Compat32 de winepak

Creación de paquete genérico para pruebas de instalación

Ya que se está explorando el uso de winepak, no se pretenderá crear el flatpak final, sinó que se creara un paquete genérico que nos permita realizar pruebas como se detalla en la sección Debugging de la documentación de flatpak.

De Building your first Flatpak se obtiene la descripción de como construir un flatpak Hello world.

Por otro lado de las aplicaciones en el repositorio de winepak se toma como ejemplo la forma de agregar winepak como dependencia y ejemplos de como crear el entorno de wine e instalar la aplicación si esta no está instalada.

Se comenzará creando el directorio de trabajo:

$ mkdir -p ~/workspace/my-winepak-apps/evoland
$ cd ~/workspace/my-winepak-apps/evoland

y en este se agregarán los siguientes archivos que se mencionan a continuación.

entrypoint.sh

Script de ejemplo que luego será sustituido por un script que realiza el setup y ejecución de la aplicación en wine (tomando como ejemplo las aplicaciones de winepak). Muestra el mensaje de Hello world estandar y por conveniencia las variables de entorno:

#!/bin/sh
echo "Hello world, from a sandbox"
printenv | LC_ALL=C sort

org.winepak.Generic.yaml

Manifiesto de la aplicación genérica de pruebas. Aquí se definirá el uso de winepak.

Como se puede ver el manifiesto utiliza yaml en lugar de json ya que lo considero más comodo para escribir y lo más importante, se pueden utilizar comentarios.

A continuación algunas explicaciones:

  1. app-id: org.winepak.Generic
    

    Identificador único de la aplicación.

  2. runtime: org.winepak.Platform
    runtime-version: 3.0
    sdk: org.winepak.Sdk
    
    add-extensions:
      org.winepak.Platform.Compat32:
        directory: lib/32bit
        version: 3.0
        add-ld-path: lib
        no-autodownload: false
    

    Definición de las versiones del runtime y del sdk utilizados, así como las extensiones (apartado [Extension NAME]) necesarias.

    Notar que a diferencia de las aplicaciones en el repositorio de winepak que utilizan una versión staging de wine, aquí se utilizará la versión estable como se sugiere en la documentación de winepak.

  3. command: entrypoint.sh
    
    finish-args:
      - --socket=x11
      - --share=ipc
      - --socket=pulseaudio
      - --device=dri
      - --allow=multiarch
      - --filesystem=xdg-download:ro
      - --env=WINEDEBUG=-all
    

    Se agrega, obviamente, el script entrypoint.sh como comando a ejecutar cuando se desea ejecutar el flatpak.

    Por otro lado, con finish-args se dan los permisos para:

    1. Conectarse al X server para ver salida gráfica del programa (--socket=x11 y --share=ipc) y utilizar aceleración gráfica (--device=dri).
    2. Utilizar pulseaudio para escuchar el audio del programa (--socket=pulseaudio).
    3. Poder ejecutar programas compilados para un ABI distinto al soportado nativamente (--allow=multiarch, buscar el texto multiarch en la documentación ya que puede llegar a utilizarse la versión de wine de 32bits mediante la extensión Compat32.
    4. Tener acceso de solo lectura a los archivos de la carpeta de descargas del usuario (--filesystem=xdg-download:ro). Este acceso es necesario ya que no se puede distribuir el instalador de Evoland junto al flatpak y no se desea que en la etapa de setup se descargue el archivo, sinó que se buscará por este en el directorio de descargas mostrando un diálogo de error en caso de que no se encuentre. Se limita el acceso a solo lectura para dar el menor acceso posible.
    5. Evitar los mensajes de wine en la consola; para ello se utilizan variables de entorno (--env=WINEDEBUG=-all).
  4.   - name: setup-compat32
        buildsystem: simple
        build-commands:
          - mkdir -p /app/lib/32bit
          - ln -s /app/lib/32bit/lib/ld-linux.so.2 /app/lib/ld-linux.so.2
    

    Copiado de las aplicaciones de winepak. De la página del manual de ld-linux el archivo ld-linux.so es el dynamic linker, y lo que se está haciendo aquí es utilizar un linker de 32bits.

  5.   - name: generic
        buildsystem: simple
        no-make-install: true
        build-commands:
          - install -d /app/bin
          - install -m555 entrypoint.sh /app/bin/entrypoint.sh
        sources:
          - type: file
            path: entrypoint.sh
    

    Por último, se copia el script a utilizar como entrypoint y se dan permisos de ejecución.

Archivos faltantes

Ya que se va a realizar una aplicación para realizar pruebas que se ejecutará directamente desde consola y no tendrá integración con el sistema, se omiten los siguientes archivos esperados por flatpak si se desean seguir las convenciones de escritorio de linux:

Construcción y ejecución del flatpak genérico de pruebas

Según la documentación de flatpak, hay que utilizar el comando flatpak-builder para la construcción del flatpak.

Particularmente, ya que se están realizando pruebas se instalará directamente la aplicación al repositorio de usuario:

$ flatpak-builder --user --install --force-clean build org.winepak.Generic.yaml

Para ejecutar el flatpak y ver que fué instalado sin problemas:

$ flatpak run org.winepak.Generic

Pruebas con el flatpak genérico

Para realizar pruebas con el flatpak se seguirán las indicaciones de debug encontradas en la documentación de flatpak:

$ flatpak run --command=bash org.winepak.Generic

Notar que no se utilizó la opción --devel ya que según se vió en el repositorio de aplicaciones de winepak las aplicaciones deben instalarse en el prefijo de wine que se crea al ejecutar por primera vez la aplicación. El prefijo de wine queda almacenado localmente, en el caso de la aplicación genérica en $HOME/.var/app/org.winepak.Generic.

Nos interesarán las siguientes pruebas:

  1. Verificar el acceso al directorio de descargas del usuario y comprobar que puede leerse el instalador:

    bash-4.3$ XDG_DOWNLOAD_DIR="$(xdg-user-dir DOWNLOAD)"
    bash-4.3$ sha256sum "$XDG_DOWNLOAD_DIR/setup_evoland_1.1.2490_(20677).exe"
    a478ca738c312a6b8a2f289f309efa7c893efe3b06ff1753a6bea88864b62ce7  /home/jmpc/Downloads/setup_evoland_1.1.2490_(20677).exe
    

    Primero se obtiene la ruta del directorio de Downloads. Para ello se utiliza el ejecutable xdg-user-dir del programa xdg-user-dirs.

    Luego se realiza el checksum del archivo, comprobando que se tiene acceso de lectura al archivo y que el contenido de este es el esperado.

  2. Creación del prefijo wine, instalación y ejecución de Evoland:

    Para poder utilizar wine es necesario que se cree un prefijo. Se puede hacer manualmente utilizando el comando wineboot o automáticamente: al ejecutar un programa de wine, si no existe el prefijo este se crea.

    Se dejará que la creación del wineprefix se realize de forma automática en el directorio $WINEPREFIX (o si dicha variable no esta definida en $HOME/.wine), al instalar Evoland:

    bash-4.3$ wine64 "$XDG_DOWNLOAD_DIR/setup_evoland_1.1.2490_(20677).exe"
    

    Luego se siguen los pasos de instalación, obteniendo los siguiente errores:

    Error en instalador

    Error en instalador

    Error en instalador

    Por último, se sale del instalador sin lanzar la aplicación. Para ejecutar la aplicación se utiliza:

    bash-4.3$ wine64 "$WINEPREFIX/drive_c/GOG Games/Evoland/Evoland.exe"
    

    obteniendose el siguiente error:

    Error en programa

Segunda versión del flatpak genérico

En este punto se busca nuevamente en internet por el problema, encontrandose en el bug 35345 de wine (referenciado en la versión de evoland para gog.com en appdb) la descripción del problema ocurrido. Allí se hace referencia a que el problema estaría corregido en la versión de staging 3.15.

Utilizando el comando wine64 --version se obtiene que la versión de wine utilizada es la wine-3.0.1, por lo que se buscará instalar una versión de wine staging.

Para ver las versiones disponibles en el repositorio se utiliza flatpack remote-ls:

$ flatpak remote-ls --user --show-details winepak | grep staging
runtime/org.winepak.Platform.Wine.Compat32/x86_64/3.10-staging        cd29ac1fe713        406.9 MB        133.7 MB
runtime/org.winepak.Platform.Wine.Compat32/x86_64/3.8-staging        d8c5b995813b        405.4 MB        133.2 MB
runtime/org.winepak.Platform.Wine.Compat32/x86_64/3.9-staging        2fe64ef3a987        406.1 MB        133.5 MB
runtime/org.winepak.Platform.Wine/x86_64/3.10-staging        4413574e3d51        509.7 MB        142.9 MB
runtime/org.winepak.Platform.Wine/x86_64/3.8-staging        ace7dd340813        507.4 MB        142.4 MB
runtime/org.winepak.Platform.Wine/x86_64/3.9-staging        823a7359fa8c        508.8 MB        142.7 MB

De lo anterior, se modificará el archivo org.winepak.Generic.yaml para instalar la versión de wine 3.10-staging como una extensión.

Se utilizará como ejemplo de uso de una versión de staging en winepak los archivos [com.blizzard.StarCraft2.yml][winepack-apps-starcraftmanifest] y com.blizzard.BattleNet.BaseApp.yml del repositorio de aplicaciones de winepak.

El archivo org.winepak.Generic.yaml queda ahora de la siguiente forma:

app-id: org.winepak.Generic

runtime: org.winepak.Platform
runtime-version: 3.0
sdk: org.winepak.Sdk

add-extensions:
  org.winepak.Platform.Compat32:
    directory: lib/32bit
    version: 3.0
    add-ld-path: lib
    no-autodownload: false

  org.winepak.Platform.Wine:
    directory: lib/wine
    version: 3.10-staging
    add-ld-path: lib
    no-autodownload: false

  org.winepak.Platform.Wine.Compat32:
    directory: lib/wine-32bit
    version: 3.10-staging
    add-ld-path: lib
    no-autodownload: false

tags:
  - generic app

command: entrypoint.sh

finish-args:
  - --socket=x11
  - --share=ipc
  - --socket=pulseaudio
  - --device=dri
  - --allow=multiarch
  - --filesystem=xdg-download:ro
  - --env=WINEDEBUG=-all

modules:
  - name: setup-compat32
    buildsystem: simple
    build-commands:
      - mkdir -p /app/lib/32bit
      - ln -s /app/lib/32bit/lib/ld-linux.so.2 /app/lib/ld-linux.so.2

  - name: setup-wine
    buildsystem: simple
    build-commands:
      - mkdir -p /app/lib/wine

  - name: setup-wine-compat32
    buildsystem: simple
    build-commands:
      - mkdir -p /app/lib/wine-32bit

  - name: generic
    buildsystem: simple
    no-make-install: true
    build-commands:
      - install -d /app/bin
      - install -m555 entrypoint.sh /app/bin
    sources:
      - type: file
        path: entrypoint.sh

Aquí se agregó la versión 3.10-staging como está indicado en https://github.com/winepak/winepak-sdk-images#structure. Luego, se agregaron los módulos setup-wine y setup-wine-compat32 para que se creen los directorios en los que se montarán las extensiones.

Ya modificado el archivo:

  1. Se instala la extensión 3.10-staging del repositorio winepak como se indica en https://github.com/winepak/winepak-sdk-images#install-the-runtime:

    $ flatpak install --user winepak org.winepak.Platform.Wine/x86_64/3.10-staging
    $ flatpak install --user winepak org.winepak.Platform.Wine.Compat32/x86_64/3.10-staging
    
  2. Se vuelven a construir e instalar el flatpak:

    $ flatpak-builder --user --install --force-clean build org.winepak.Generic.yaml
    
  3. Se instala nuevamente Evoland, asegurandonos de borrar el wineprefix que quedó de pruebas anteriores.

    Se ingresa al entorno del flatpak:

    $ flatpak run --command=bash org.winepak.Generic
    

    Se comprueban las versiones de wine en el sistema (la de 32 y 64 bits):

    bash-4.3$ which wine64
    /app/lib/wine/bin/wine64
    bash-4.3$ wine64 --version
    wine-3.10 (Staging)
    bash-4.3$ which wine
    /app/lib/wine-32bit/bin/wine
    bash-4.3$ wine --version
    wine-3.10 (Staging)
    

    Se borra el wineprefix anterior:

    bash-4.3$ rm -fr $WINEPREFIX
    

    Se realiza nuevamente la instalación:

    bash-4.3$ XDG_DOWNLOAD_DIR="$(xdg-user-dir DOWNLOAD)"
    bash-4.3$ wine64 "$XDG_DOWNLOAD_DIR/setup_evoland_1.1.2490_(20677).exe"
    

    (siguen apareciendo los mensajes de error al finalizar la instalación).

    Se ejecuta Evoland:

    bash-4.3$ wine64 "$WINEPREFIX/drive_c/GOG Games/Evoland/Evoland.exe"
    

    ¡Y esta vez se logra que funcione!

Creación de aplicación flatpak com.gog.Evoland

Hasta ahora se consiguió:

Ahora se pasará a crear el flatpak específico para Evoland:

  1. Se copiarán los archivos utilizados renombrando org.winepack.Generic.yaml a com.gog.Evoland.yaml.

    Se modificará el archivo com.gog.Evoland.yaml:

    1. Se cambia el valor de app-id a com.gog.Evoland
    2. Se reemplazan los tags por gog y evoland.
    3. En modules, se renombra en name generic por evoland.
  2. Se modificará el script entrypoint.sh para ejecutar Evoland si se encuentra y en caso contrario instalarlo. Si al momento de instalar no existe el instalador se mostrará un mensaje de error acorde utilizando zenity.

    A continuación el código del archivo entrypoint.sh:

    #!/bin/sh
    set -e
    
    # Variables
    PROGRAM_NAME="Evoland"
    PROGRAM_URL="https://www.gog.com/game/evoland"
    PROGRAM_PATH="GOG Games/Evoland/Evoland.exe"
    INSTALLER_FILE="setup_evoland_1.1.2490_(20677).exe"
    INSTALLER_CHECKSUM=a478ca738c312a6b8a2f289f309efa7c893efe3b06ff1753a6bea88864b62ce7
    DIALOG_WIDTH=400
    
    if [ ! -f "$WINEPREFIX/drive_c/$PROGRAM_PATH" ]; then
        # install
        XDG_DOWNLOAD_DIR="$(xdg-user-dir DOWNLOAD)"
    
        if [ ! -f "$XDG_DOWNLOAD_DIR/$INSTALLER_FILE" ]; then
            zenity --error --no-markup --width=$DIALOG_WIDTH --text="$(cat <<END
    Can't found the file \`${INSTALLER_FILE}\`
    in the *Downloads* directory.
    
    Please, download it from <${PROGRAM_URL}>
    and run again.
    END
                )"
            exit 1
        fi
    
        if ! echo "$INSTALLER_CHECKSUM  $XDG_DOWNLOAD_DIR/$INSTALLER_FILE" | sha256sum -c --quiet; then
            zenity --error --no-markup --width=$DIALOG_WIDTH --text="$(cat <<END
    The file \`${INSTALLER_FILE}\` in *Downloads* directory
    has an unexpected sha256 sum.
    
    Please, download it again from <${PROGRAM_URL}>
    and check that the sha256sum of the file is
    \`${INSTALLER_CHECKSUM}\` and run again.
    END
                )"
            exit 1
        fi
    
        zenity --info --no-markup --width=$DIALOG_WIDTH --text="$(cat <<END
    Running ${PROGRAM_NAME} installer.
    
    * Only accept the EULA (don't change installation directory)
    * Ignore error messages at the end of installation
    * Exit the installer - Don't press Launch button!
    END
            )"
        wine64 "$XDG_DOWNLOAD_DIR/$INSTALLER_FILE" '/LANG=English'
    fi
    
    # run program
    wine64 "$WINEPREFIX/drive_c/$PROGRAM_PATH"
    

    Comentarios:

    • Se utilizan variables para la ruta del programa y el archivo del instalador ya que puede darse el caso de crear otro flatpak en que el script de instalación sea similar.
    • Se utiliza la opción --width= ya que sin esta la ventana de dialogo queda muy angosta y resulta ilegible.
    • Si bien se pudo determinar que el instalador fué creado con inno setup (comentado en el foro de gog) no se encontraron opciones de linea de comando para evitar tener que aceptar el EULA.
  3. Quedan agregar, según las convenciones de escritorio de linux:

    1. Archivo com.gog.Evoland.desktop:

      [Desktop Entry]
      Name=Evoland
      Comment=Evoland is a journey through the history of action/adventure gaming.
      Exec=/app/bin/entrypoint.sh
      Type=Application
      Icon=com.gog.Evoland
      Categories=Game;ArcadeGame;
      MimeType=application/x-ms-dos-executable;application/x-msi;application/x-ms-shortcut;
      StartupNotify=true
      Terminal=false
      

      Dicho archivo puede encontrarse aquí.

      Para que sea agregado se debe modificar el manifiesto com.gog.Evoland.yaml agregando en modules para evoland:

        - name: evoland
          ...
          build-commands:
            ...
            - install -Dm644 com.gog.Evoland.desktop /app/share/applications/com.gog.Evoland.desktop
          sources:
            ...
            - type: file
              path: com.gog.Evoland.desktop
      
    2. Íconos de la aplicación. Estos se pueden obtener de la instalación de Evoland en el flatpak genérico.

      Primero se copian al directorio de trabajo:

      $ grep Icon $(find ~/.var/app/org.winepak.Generic/ -name Evoland.desktop)
      Icon=D357_goggame-1207659200.0
      $ find ~/.var/app/org.winepak.Generic/ -name 'D357_goggame-1207659200.0*'
      /home/jmpc/.var/app/org.winepak.Generic/data/icons/hicolor/256x256/apps/D357_goggame-1207659200.0.png
      /home/jmpc/.var/app/org.winepak.Generic/data/icons/hicolor/48x48/apps/D357_goggame-1207659200.0.png
      /home/jmpc/.var/app/org.winepak.Generic/data/icons/hicolor/32x32/apps/D357_goggame-1207659200.0.png
      /home/jmpc/.var/app/org.winepak.Generic/data/icons/hicolor/16x16/apps/D357_goggame-1207659200.0.png
      $ cd ~/workspace/my-winepak-apps/evoland
      $ ICONPREFIX=/home/jmpc/.var/app/org.winepak.Generic/data/icons/hicolor
      $ ICONSUFFIX=apps/D357_goggame-1207659200.0.png
      $ for size in 16x16 32x32 48x48 256x256; do
          cp $ICONPREFIX/$size/$ICONSUFFIX com.gog.Evoland-$size.png
      done
      

      Luego se vuelve a modificar el manifiesto para realizar la instalación:

        - name: evoland
          ...
          build-commands:
            ...
            - install -Dm664 com.gog.Evoland-16x16.png /app/share/icons/hicolor/16x16/apps/com.gog.Evoland.png
            - install -Dm664 com.gog.Evoland-32x32.png /app/share/icons/hicolor/32x32/apps/com.gog.Evoland.png
            - install -Dm664 com.gog.Evoland-48x48.png /app/share/icons/hicolor/48x48/apps/com.gog.Evoland.png
            - install -Dm664 com.gog.Evoland-256x256.png /app/share/icons/hicolor/256x256/apps/com.gog.Evoland.png
          sources:
            ...
            - type: file
              path: com.gog.Evoland-16x16.png
            - type: file
              path: com.gog.Evoland-32x32.png
            - type: file
              path: com.gog.Evoland-48x48.png
            - type: file
              path: com.gog.Evoland-256x256.png
      
    3. Queda por crear el archivo com.gog.Evoland.appdata.xml. La documentación de como crear el archivo puede encontrarse en la documentación de appstream.

      En este caso no se creará el archivo, ya que no es necesario y no aporta.

La versión final del manifiesto se encuentra aquí.

Paso seguido se crea el flatpak y se instala a nivel de usuario:

$ flatpak-builder --user --install --force-clean build com.gog.Evoland.yaml

Se ejecuta el flatpak (recordar que el instalador ya fué descargado en el directoro de descargas):

$ flatpak run com.gog.Evoland

Y ahora si quedó funcionando.

Funcionando

Todos los archivos para construir el flatpak se pueden descargar de aquí.

Conclusiones

Pendientes

Referencias