Usando o compilador nuitka para python3 no Alpine Linux ARMHF (musl)
Motivação
pidoctor é escrito em Python (pois não havia uma maneira fácil de fazer o Crystal funcionar em ARMHF / musl).
Isto significa uma dependência do Python - que acrescenta despesas gerais.
Eu suspeito que esta sobrecarga é a razão pela qual o pidoctor não irá funcionar com 256 MB de Raspberry Pi's - porque a RAM está esgotada por todos os pacotes que são necessários.
Além disso, é desejável que a distribuição seja o menor download possível! Isto significa que Python tem que ser removido da equação de alguma forma, o pacote deve produzir um binário (como seria o caso do Crystal).
Felizmente, há nuitka.
E - felizmente você - eu tenho trabalhado algumas dicas para usar nuitka no Alpine Linux, ARMHF (talvez funcione para x86 também).
Nuitka
nuitka é um software fantástico, que vai pegar um script Python e compilá-lo para um executável, acelerando-o assim dramaticamente.
nuitka faz todo o trabalho pesado, você nem precisa ajustar nada no seu código fonte (methinks). Você pode executá-lo assim:
python3 -m nuitka -follow-imports -standalone pidoctor.py
Note a bandeira -standalone, que compilará as bibliotecas compartilhadas necessárias em sua pasta .dist - assim a instalação será capaz de rodar sem qualquer dependência em Python!
Por favor note: o WordPress infelizmente fode os traços duplos e transforma-os em traços simples. o -m tem um único traço, o -seguinte-importações e o -standalone tem traços duplos.
Instalação de Nuitka no Alpine Linux (especificamente arhmf, pode funcionar em outros alvos)
apk adicionar python3-dev
apk add chrpath
pip3 instalar -U nuitka
opcionalmente, se você estiver rodando no modo diskless (para adicionar nuitka aos arquivos que devem ser persistidos):
lbu add /usr/bin/nuitka3-run
lbu add /usr/bin/nuitka3
lbu add /usr/lib/python3.6/site-packages/nuitka
lbu commit -d
Nota: a fonte de nuitka está em Python.
Verifica se a nuitka corre:
python3 -m nuitka
deve executar sem mostrando quaisquer erros de sintaxe.
Consertando nuitka para rodar com o armhf Linux Alpino
Importante: Infelizmente, o WordPress altera mal a sintaxe. Por favor, consulte a edição do GitHUB que abrionde também anexei os arquivos de patch para uma referência.
nuitka chama vários utilitários binários de suporte em seu sistema, e espera que eles retornem os resultados de uma certa forma. Isto é, onde a nuitka inicialmente tropeça.
Primeiro erro
pidoctor:/opt/pidoctor# python3 -m nuitka -follow-imports -standalone pidoctor.py
Traceback (última chamada):
Arquivo "/usr/lib/python3.6/site-packages/nuitka/__main__.py", linha 188, em
principal()
Arquivo "/usr/lib/python3.6/site-packages/nuitka/__main__.py", linha 182, em principal
MainControl.main()
Arquivo "/usr/lib/python3.6/site-packages/nuitka/MainControl.py", linha 846, na principal
Plugins.considerExtraDlls(dist_dir, módulo)
Arquivo "/usr/lib/python3.6/site-packages/nuitka/plugins/Plugins.py", linha 102, in considerExtraDlls
para extra_dll in plugin.considerExtraDlls(dist_dir, módulo):
Arquivo "/usr/lib/python3.6/site-packages/nuitka/plugins/standard/ImplicitImports.py", linha 372, in considerExtraDlls
uuid_dll_path = locateDLL("uuid")
Arquivo "/usr/lib/python3.6/site-packages/nuitka/utils/SharedLibraries.py", linha 71, in locateDLL
retornar dll_map[dll_name]
KeyError: 'libuuid.so.1.3.0'.
Motivo do erro: nuitka chama ldconfig -p e espera que ela liste uma lista de bibliotecas compartilhadas em cache, em um formato como este:
libICE.so.6 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libICE.so.6
no Alpine Linux, o ldconfig -p falha - pois não existe tal opção. O ldconfig no Alpine Linux é incapaz de produzir uma lista da forma que o Nuitka quer.
Consertar:
in /usr/lib/python3.6/site-packages/nuitka/utils/SharedLibraries.py
adicione o seguinte código imediatamente após as declarações de importação na parte superior:
def find_alpine(nome,caminhos):
para o caminho nos caminhos:
para root, dirs, arquivos em os.walk(path):
se nome em arquivos:
return os.path.join(root,name)
e em locateDLL, antes do subprocesso de importação, adicione o seguinte código:
if os.path.isfile('/etc/alpine-release'):
retornar find_alpine(dll_name,["/lib","/usr/lib","/usr/local/lib"])
senão..:
subprocesso de importação(…)
O (...) acima indica que o restante do código de localização daDLL deve ser recuado sob o outro.
O que este código faz: se o arquivo /etc/alpine-release existe - indicando que estamos rodando no Alpine Linux, procuramos pela biblioteca compartilhada em três diretórios pré-definidos:
- /lib
- /usr/lib
- /usr/local/lib
e devolver o primeiro ficheiro correspondente. Nota, não tratamos da situação caso o ficheiro não seja encontrado - neste caso nada é devolvido..
Segundo erro
Traceback (última chamada):
Arquivo "/usr/lib/python3.6/site-packages/nuitka/__main__.py", linha 188, em
principal()
Arquivo "/usr/lib/python3.6/site-packages/nuitka/__main__.py", linha 182, em principal
MainControl.main()
Arquivo "/usr/lib/python3.6/site-packages/nuitka/MainControl.py", linha 859, na principal
pontos_de_entrada_automática = pontos_de_entrada_automática
Arquivo "/usr/lib/python3.6/site-packages/nuitka/freezer/Standalone.py", linha 1169, em copyUsedDLLs
used_dlls = detectUsedDLLs(source_dir, standalone_entry_points)
Arquivo "/usr/lib/python3.6/site-packages/nuitka/freezer/Standalone.py", linha 1062, em detectUsedDLLs
assert os.path.isabs(dll_filename), dll_filename
AssertionError: ldd
Motivo do erro: nuitka chama ldd com cada biblioteca compartilhada ("dll_filename") para ser adicionado à sua pasta .dist. O propósito disto é encontrar as dependências destas bibliotecas compartilhadas. (Uma pesquisa recursiva se você quiser).
Por exemplo:
pidoctor:/opt/pidoctor# ldd /usr/lib/libexpat.so.1
ldd (0x76f43000)
libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x76efd000)
libc.musl-armhf.so.1 => ldd (0x76f43000)
Como você vê, libexpat.so.1 tem duas dependências:
- libgcc_s.so.1 -> para ser encontrado em /usr/lib/libgcc_s.so.1
- libc.musl-armhf.so.1 -> para ser encontrado em ldd
e é precisamente aqui que a nuitka tem problemas. Ela quer copiar um arquivo com um caminho absoluto, e recebe o nome "ldd" em seu lugar. Mais uma vez, algo que é específico do Alpine Linux.
Portanto, a afirmação falha, e nuitka não continua.
Aqui está como descobrir qual arquivo ele realmente se refere:
pidoctor:~# que ldd
/usr/bin/lddpidoctor:~# ls -alh /usr/bin/ldd
lrwxrwxrwx 1 root root 28 Jan 1 1970 /usr/bin/ldd -> ../.../lib/ld-musl-armhf.so.1
Note que ../.../lib/ld-musl-armhf.so.1 é um caminho relativo, que na verdade se refere a /lib/ld-musl-armhf.so.1 no meu sistema. E no teu, provavelmente, também.
Consertar:
procurar libutil.so. no arquivo /usr/lib/python3.6/site-packages/nuitka/freezer/Standalone.py
Há uma linha com result.add(filename) abaixo dela. Apenas acima esta linha, insira:
if filename == 'ldd':
filename = os.path.join(os.path.dirname('/usr/bin/ldd'),os.readlink('/usr/bin/ldd')) #e.g. '/lib/ld-musl-armhf.so.1' correcção para Alpine
Terceiro erro
Erro, precisa de 'chrpath' no seu sistema, devido a configurações de 'RPATH' em uso compartilhado
Consertar:
Você instalou o Christpath como aconselhado acima?
apk add chrpath
É isso - agora nuitka deve fazer magia sem soluços. Vou enviar ao autor de nuitka os adesivos e este artigo no blog, talvez ele possa incluí-los em nuitka.
Versão de fábrica
Atualização 2.2.2019: O autor de Nuitka adicionou meus patches (em uma forma ligeiramente modificada). Na atual versão "de fábrica", a compilação - independente funciona para mim. Por favor, consulte esta página do github para mais detalhes: