在Alpine Linux ARMHF上为Python3使用nuitka编译器(musl)。

激励

医师 是用Python写的(因为没有简单的方法让Crystal在ARMHF / musl上工作)。

这意味着对Python的依赖性--这增加了开销。

我怀疑这种开销是pidoctor不能在256 MB的Raspberry Pi上运行的原因--因为RAM被所有需要的软件包耗尽了。

此外,我们希望发行版的下载量越小越好。这意味着Python必须以某种方式从方程中移除,软件包应该产生一个二进制文件(就像Crystal的方式一样)。

幸运的是,有nuitka。

而且--你很幸运--我已经解决了在Alpine Linux、ARMHF上使用nuitka的一些问题(也许它也能用于x86)。

Nuitka

nuitka 是一个神奇的软件,它可以将Python脚本编译为可执行文件,从而大大加快了速度。

nuitka完成了所有繁重的工作,你甚至不需要在你的源代码中调整任何东西(我想)。你可以像这样运行它。

python3 -m nuitka -follow-imports -standalone pidoctor.py

注意-standalone标志,它将把必要的共享库编译到你的.dist文件夹中--因此安装将能够在没有 任何依赖性 关于Python!

请注意:不幸的是,WordPress把双破折号弄成了单破折号。-m是单破折号,-follow-imports和-standalone是双破折号。

在Alpine Linux上安装Nuitka(特别是arhmf,可能在其他目标上工作)。

apk添加python3-dev

apk添加chrpath

pip3安装 -U nuitka

选项,如果你在无盘模式下运行(将nuitka添加到应该被持久化的文件中)。

lbu add /usr/bin/nuitka3-run

lbu add /usr/bin/nuitka3

lbu add /usr/lib/python3.6/Site-packages/nuitka

lbu commit -d

注意:nuitka的源代码是Python语言。

检查nuitka是否运行。

python3 -m nuitka

应执行 没有 显示任何语法错误。

修复nuitka以使其在Alpine Linux armhf下运行

重要提示:不幸的是,WordPress严重误导了语法。 请参考我打开的GitHUB问题,在那里我还附上了补丁文件供参考。

nuitka在你的系统上调用几个支持的二进制工具,并期望它们以某种方式返回结果。这就是,nuitka最初的绊脚石。

第一个错误

pidoctor:/opt/pidoctor# python3 -m nuitka -follow-imports -standalone pidoctor.py

回溯(最近的一次调用)。

文件 "/usr/lib/python3.6/Site-packages/nuitka/__main__.py",第188行,在 中

main()

文件 "/usr/lib/python3.6/Site-packages/nuitka/__main__.py", 第182行, in main

MainControl.main()

文件 "/usr/lib/python3.6/Site-packages/nuitka/MainControl.py", 第846行, in main

Plugins.considerExtraDlls(dist_dir, module)

文件 "/usr/lib/python3.6/Site-packages/nuitka/plugins/Plugins.py", 第102行, in considerExtraDlls

for extra_dll in plugin.considerExtraDlls(dist_dir, module):

文件 "/usr/lib/python3.6/Site-packages/nuitka/plugins/standard/ImplicitImports.py", 第372行, in considerExtraDlls

uuid_dll_path = locateDLL("uuid")

文件 "/usr/lib/python3.6/Site-packages/nuitka/utils/SharedLibraries.py", 第71行, in locateDLL

返回dll_map[dll_name]。

KeyError: 'libuuid.so.1.3.0'

错误背后的原因:nuitka调用ldconfig -p,希望它能列出一个缓存共享库的列表,格式如下。

libICE.so.6 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libICE.so.6

在Alpine Linux上,ldconfig -p失败了--因为没有这样的选项。Alpine Linux上的ldconfig没有能力产生Nuitka想要的形式的列表。

修复。

in /usr/lib/python3.6/Site-packages/nuitka/utils/SharedLibraries.py

在顶部的导入语句之后立即添加以下代码。

def find_alpine(name,paths):
     for paths in paths:
         for root, dirs, files in os.walk(path):
             如果名字在文件中。
                 返回 os.path.join(root,name)

并在locateDLL中,在导入子进程之前,添加以下代码。

如果os.path.isfile('/etc/alpine-release')。
     return find_alpine(dll_name,["/lib","/usr/lib","/usr/local/lib").
否则。
     输入subprocess

    (...)

上面的(...)表示 locateDLL 的其余代码应该缩进到 else 下面。

这段代码的作用是:如果文件/etc/alpine-release存在--表明我们在Alpine Linux上运行,我们在三个预定义的目录中搜索共享库。

  • /lib
  • /usr/lib
  • /usr/local/lib

并返回第一个匹配的文件。 注意,我们不处理找不到文件的情况--在这种情况下不返回任何东西。.

第二个错误

回溯(最近的一次调用)。
   文件 "/usr/lib/python3.6/Site-packages/nuitka/__main__.py",第188行,在 中
     main()
   文件 "/usr/lib/python3.6/Site-packages/nuitka/__main__.py", 第182行, in main
     MainControl.main()
   文件 "/usr/lib/python3.6/Site-packages/nuitka/MainControl.py", 第859行, in main
     独立的入口点 = Standalone_entry_points
   文件 "/usr/lib/python3.6/Site-packages/nuitka/freezer/Standalone.py", 第1169行, in copyUsedDLLs
     used_dlls = detectUsedDLLs(source_dir, standalone_entry_points)
   文件 "/usr/lib/python3.6/Site-packages/nuitka/freezer/Standalone.py", 第1062行, in detectUsedDLLs
     assert os.path.isabs(dll_filename), dll_filename
断言错误: ldd

错误背后的原因:nuitka用每个共享库("dll_filename")来调用ldd,将其添加到你的.dist文件夹中。这样做的目的是为了找到这些共享库本身的依赖关系。(如果你愿意的话,这是一个递归搜索)。

比如说。

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)

如你所见,libexpat.so.1有两个依赖项。

  • libgcc_s.so.1 -- 在/usr/lib/libgcc_s.so.1找到。
  • libc.musl-armhf.so.1 -- -- 可在以下位置找到 ǞǞǞ

而这正是nuitka的问题所在。它想复制一个有绝对路径的文件,但却得到了 "ldd "的名字。这也是Alpine Linux特有的东西。

因此,断言失败,nuitka没有继续。

下面是如何找出它实际引用的文件。

pidoctor:~# which ldd
/usr/bin/ldd

pidoctor:~# ls -alh /usr/bin/ldd
lrwxrwxrwx 1 root 28 Jan 1 1970 /usr/bin/ldd -> ..././lib/ld-musl-armhf.so.1

注意 .../.../lib/ld-musl-armhf.so.1 是一个相对路径,它实际上指的是 /lib/ld-musl-armhf.so.1 在我的系统上。在你的系统上,可能也是如此。

修复。

寻找 libutil.so。 在文件/usr/lib/python3.6/Site-packages/nuitka/freezer/Standalone.py中。

下面有一行是 result.add(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' 为 Alpine 修复

第三个错误

错误,在你的系统中需要'chrpath',由于在使用的共享中的'RPATH'设置,导致了错误。

修复。

你是否按照上述建议安装了chrpath?

apk添加chrpath

就是这样--现在nuitka应该可以毫无障碍地发挥它的魔力了。我会把补丁和这篇博客文章发给nuitka的作者,也许他能把它们加入nuitka。

工厂版

2019年2月2日更新:Nuitka的作者添加了我的补丁(以略微修改的形式)。在当前的 "工厂 "版本中,-独立编译对我来说是有效的。详情请参考这个github页面。

https://github.com/Nuitka/Nuitka/issues/237

http://nuitka.net/doc/factory.html