在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/lddpidoctor:~# 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页面。