Suporte a multiarquitetura

Flatpak tem suporte multiarch/multilib, mas não está habilitado por padrão e requer algumas etapas adicionais para habilitá-lo. Esta seção abrange a ativação de multiarch/multilib em seu pacote de aplicativos.

Executando programas de 32 bits

Para configurar o ambiente de runtime para executáveis de 32 bits, primeiro você precisa permitir isso em finish-args:

finish-args:
  - --allow=multiarch

Isso é suficiente para binários estáticos, mas a maioria dos programas GNU/Linux do mundo real são vinculados dinamicamente. Esses precisam de algumas bibliotecas compartilhadas para funcionar.

Os SDKs do Freedesktop.org e do GNOME fornecem uma extensão flatpak especial com um conjunto de bibliotecas para a arquitetura correspondente. Esta extensão pode ser anexada a um aplicativo de arquitetura diferente. Para habilitar a extensão para seu aplicativo, defina um ponto de extensão para ela no manifesto do aplicativo:

add-extensions:
  org.freedesktop.Platform.Compat.i386:
    directory: lib/i386-linux-gnu
    version: '23.08'

  # This is not strictly required, but needed for debugging 32-bit programs
  org.freedesktop.Platform.Compat.i386.Debug:
    directory: lib/debug/lib/i386-linux-gnu
    version: '23.08'
    no-autodownload: true

Para o tempo de execução do GNOME, use org.gnome.Platform.Compat.i386 em vez disso.

Note que esta extensão version deve corresponder à runtime-version do aplicativo.

Se os programas de 32 bits fizerem uso de aceleração de GPU ou tiverem alguma interface gráfica em geral, você também precisará de drivers GL de 32 bits. Adicione um ponto de extensão para ele:

add-extensions:
  org.freedesktop.Platform.GL32:
    directory: lib/i386-linux-gnu/GL
    version: '1.4'
    versions: 23.08;1.4
    subdirectories: true
    no-autodownload: true
    autodelete: false
    add-ld-path: lib
    merge-dirs: vulkan/icd.d;glvnd/egl_vendor.d;OpenCL/vendors;lib/dri;lib/d3d;vulkan/explicit_layer.d;vulkan/implicit_layer.d
    download-if: active-gl-driver
    enable-if: active-gl-driver

Observe que a propriedade versions aqui deve conter 1.4 e o mesmo valor que em runtime-version.

Certifique-se de criar diretórios onde as extensões serão montadas (os pontos de montagem são especificados nas propriedades do directory e são relativos ao ponto de montagem do pacote de aplicativos, ou seja, para /app/). Isso pode ser feito na fase de compilação.

Finalmente, você precisa fazer com que o carregador dinâmico de bibliotecas conheça os caminhos para bibliotecas de 32 bits. Para fazer isso, você pode instalar um arquivo /app/etc/ld.so.conf com conteúdo como este:

/app/lib32
/app/lib/i386-linux-gnu

Aqui /app/lib32 é o diretório onde você instala bibliotecas adicionais de 32 bits, se houver.

Você pode combinar as duas etapas acima em um módulo especial, por exemplo.

modules:
  - name: bundle-setup
    buildsystem: simple
    build-commands:
      - mkdir -p /app/lib/i386-linux-gnu
      - mkdir -p /app/lib/debug/lib/i386-linux-gnu
      - mkdir -p /app/lib/i386-linux-gnu/GL
      - install -Dm644 ld.so.conf /app/etc/ld.so.conf
    sources:
      - type: inline
        dest-filename: ld.so.conf
        contents: |
          /app/lib32
          /app/lib/i386-linux-gnu

Compilando módulos de 32 bits

A seção acima descreve como executar programas de 32 bits já compilados. Esta seção descreverá o processo de construção de componentes de 32 bits por conta própria para enviá-los com o aplicativo. Ele pressupõe que você já esteja familiarizado com a construção de flatpaks (arco único). Caso contrário, consulte primeiro o guia Flatpak Builder.

Em primeiro lugar, você precisará habilitar algumas extensões do SDK no momento da compilação:

sdk-extensions:
  - org.freedesktop.Sdk.Compat.i386
  - org.freedesktop.Sdk.Extension.toolchain-i386

A primeira é a parte de 32 bits do SDK, contendo bibliotecas de 32 bits e arquivos de desenvolvimento.

O segundo é um compilador cruzado. Normalmente gcc -m32 é usado para compilações multilib, mas o SDK flatpak vem com gcc sem suporte a multilib. Assim, você precisará de um compilador cruzado para compilar x86 em x86_64 assim como precisaria para qualquer arquitetura estrangeira como aarch64.

Para compilar um módulo de 32 bits, algumas opções globais de compilação precisam ser substituídas. Os exemplos aqui assumem que as bibliotecas de 32 bits estão instaladas no diretório /app/lib32:

modules:
  - name: some-lib-32bit
    build-options: &compat-i386-build-options
      # Make sure 32-bit dependencies are first on pkg-config search path
      prepend-pkg-config-path: /app/lib32/pkgconfig:/usr/lib/i386-linux-gnu/pkgconfig
      # Add /app/lib32 to linker search path for modules without pkg-config
      ldflags: -L/app/lib32
      # Add the cross-compiler to PATH
      prepend-path: /usr/lib/sdk/toolchain-i386/bin
      # Tell the build systems to use the cross-compiler for compilation
      env:
        CC: i686-unknown-linux-gnu-gcc
        CXX: i686-unknown-linux-gnu-g++
      # Tell the build systems to install libraries to /app/lib32
      libdir: /app/lib32

Essas build-options precisam ser definidas para cada módulo de 32 bits. Se o manifesto do seu aplicativo estiver no formato YAML, as âncoras YAML podem ser úteis e evitar que você copie e cole o mesmo trecho de código. Você pode definir o objeto build-options de 32 bits em algum lugar no manifesto, adicionar uma âncora a ele e então apontar cada build-options de cada módulo de 32 bits para essa âncora:

x-compat-i386-build-options: &compat-i386-build-options
  prepend-pkg-config-path: /app/lib32/pkgconfig:/usr/lib/i386-linux-gnu/pkgconfig
  ldflags: -L/app/lib32
  prepend-path: /usr/lib/sdk/toolchain-i386/bin
  env:
    CC: i686-unknown-linux-gnu-gcc
    CXX: i686-unknown-linux-gnu-g++
  libdir: /app/lib32

modules:
  - name: some-lib-32bit
    build-options: *compat-i386-build-options

  - name: some-other-lib-32bit
    build-options: *compat-i386-build-options

É claro que, para realmente usar os módulos de 32 bits que você construiu, você também precisará da mesma configuração da seção anterior.