是否可以安装和更新具有通用(x86_64、arm64)架构支持的 Perl(CPAN)模块?如果可以,那么如何操作?
背景
在基于 arm 的 macOS 计算机上,可以按照以下方式为一个指定架构安装 Perl CPAN 模块:
sudo cpan -i Encode
### equivalent since `-arm64` is the native processor in this situation:
sudo arch -arm64 cpan -i Encode
file /Library/Perl/5.30/darwin-thread-multi-2level/auto/Encode/Encode.bundle
# /Library/Perl/5.30/darwin-thread-multi-2level/auto/Encode/Encode.bundle:
# Mach-O 64-bit bundle arm64
sudo arch -x86_64 cpan -i Encode
file /Library/Perl/5.30/darwin-thread-multi-2level/auto/Encode/Encode.bundle
# /Library/Perl/5.30/darwin-thread-multi-2level/auto/Encode/Encode.bundle:
# Mach-O 64-bit bundle x86_64
不过,请注意,苹果公司的perl
本身就是一个“通用二进制文件”:
file /usr/bin/perl
# /usr/bin/perl: Mach-O universal binary with 2 architectures:
# [x86_64:Mach-O 64-bit executable x86_64]
# [arm64e:Mach-O 64-bit executable arm64e]
# /usr/bin/perl (for architecture x86_64):
# Mach-O 64-bit executable x86_64
# /usr/bin/perl (for architecture arm64e):
# Mach-O 64-bit executable arm64e
当本地和非本地应用程序共享相同的Perl依赖项时,任何一种架构的XOR都会产生冲突。例如,GnuCash Finance::Quote 不能在Arm上本地运行,而MacTeX LaTeX Live Update可以在Intel或Arm处理器上本地运行。这两个应用程序都使用Pearl Encode module。
如果找不到所需的架构版本,则应用程序日志错误消息将是以下之一:
'/Library/Perl/5.30/darwin-thread-multi-2level/auto/Encode/Encode.bundle'(mach-o文件,但是是不兼容的架构(有'arm64',需要'x86_64'))
'/Library/Perl/5.30/darwin-thread-multi-2level/auto/Encode/Encode.bundle'(mach-o文件,但是是不兼容的架构(有'x86_64',需要'arm64'))
注意:运行这些应用程序的一种解决方法是安装
x86_64
架构的常见 Perl 模块依赖项,然后在 Rosetta2(x86_64)模式下运行通用应用程序。
进一步的发现
cc选项'-bundle'
cc -bundle
在保存的安装日志中被发现。
rm -f blib/arch/auto/Encode/Encode.bundle
cc -bundle -undefined dynamic_lookup Encode.o def_t.o encengine.o -o blib/arch/auto/Encode/Encode.bundle
chmod 755 blib/arch/auto/Encode/Encode.bundle
…
Manifying 18 pod documents
Files found in blib/arch: installing files in blib/lib into architecture dependent library tree
Installing /Library/Perl/5.30/darwin-thread-multi-2level/auto/Encode/Encode.bundle
然而,man cc
和cc --help
没有提供有关cc clang LLVM编译器的-bundle
选项的任何开发人员信息。因此,不清楚-bundle
实际上是在做什么,或者Perl新手如何使用这个信息。
lipo
似乎“构建通用二进制文件的最安全方法是分别编译模块,然后使用lipo
合并生成的.bundle
文件。”参见:meta::cpan Config_u.pm
苹果文章"Building a Universal macOS Binary"提供了一个多步骤的示例:
以下示例显示了一个makefile,它将单个源文件编译两次-每个架构一次。然后,它使用
lipo
工具将生成的可执行文件合并为通用二进制文件。
x86_app: main.c
$(CC) main.c -o x86_app -target x86_64-apple-macos10.12
arm_app: main.c
$(CC) main.c -o arm_app -target arm64-apple-macos11
universal_app: x86_app arm_app
lipo -create -output universal_app x86_app arm_app
lipo
需要将各个架构文件作为输入来-create
通用文件。
文件Encode.bundle
搜索和查看所有Encode.bundle
文件,发现了混合的通用和非通用二进制文件。
find / -name "Encode.bundle"
file /Applications/FreeCAD_0.20.app/Contents/Resources/lib/perl5/5.32/core_perl/auto/Encode/Encode.bundle
file /Library/Perl/5.30/darwin-thread-multi-2level/auto/Encode/Encode.bundle
file /System/Library/Perl/5.30/darwin-thread-multi-2level/auto/Encode/Encode.bundle
file /System/Library/Perl/5.34/darwin-thread-multi-2level/auto/Encode/Encode.bundle
file /Users/USERNAME/.cpan/build/Encode-3.19-0/blib/arch/auto/Encode/Encode.bundle
# /Applications/FreeCAD_0.20.app/…/core_perl/auto/Encode/Encode.bundle:
# Mach-O 64-bit bundle x86_64
# /Library/Perl/5.30/darwin-thread-multi-2level/auto/Encode/Encode.bundle:
# Mach-O 64-bit bundle x86_64
# /System/Library/Perl/5.30/darwin-thread-multi-2level/auto/Encode/Encode.bundle:
# Mach-O universal binary with 2 architectures:
# [x86_64:Mach-O 64-bit bundle x86_64]
# [arm64e:Mach-O 64-bit bundle arm64e]
# /System/Library/Perl/5.34/darwin-thread-multi-2level/auto/Encode/Encode.bundle:
# Mach-O universal binary with 2 architectures:
# [x86_64:Mach-O 64-bit bundle x86_64]
# [arm64e:Mach-O 64-bit bundle arm64e]
# /Users/USERNAME/.cpan/build/Encode-3.19-0/blib/arch/auto/Encode/Encode.bundle:
# Mach-O 64-bit bundle x86_64
观察:
file /System/Library/Perl/…Encode.bundle
显示 Pearl 确实存在通用二进制使用。file /Library/Perl/…Encode.bundle
表明用户安装和/或更新可能会掩盖共享应用程序使用的通用/System/Library/Perl/…Encode.bundle
。
目标
理想情况下,一个总体解决方案应该:
- 足够普遍,不需要修改每个添加的模块。
- 适用于初始模块安装和任何后续更新。
- 不会在 Perl 安装中创建依赖冲突。
可能的方法
无论是隐式还是明确调用,似乎都需要使用 lipo
来创建通用二进制文件。
只是在思考一些方法方向:
修改Perl的make文件?(如何安全地进行此操作?这是一种实用的方法吗?)
创建Config_u的更新版本?
perl -MConfig_u Makefile.PL
有并行的
/Perl/arm64/…
和/Perl/x86_64/…
目录,然后通过脚本使用lipo
合并成一些/Perl/some_universal_version/…
。这是否可以像
sudo arch -x86_64 -arm64 -arm64e cpan -i Encode
这样简单?
Encode
bundle 的命令是cc -mmacosx-version-min=12.0 -bundle -undefined dynamic_lookup -fstack-protector-strong Encode.o def_t.o encengine.o -o blib/arch/auto/Encode/Encode.bundle
。如果可能创建通用的.bundle
文件(参见例如 https://ss64.com/osx/lipo.html),那么修改Makefile.PL
或者可能需要更改ExtUtils::MakeMaker
才能使其正常工作。 - Håkon Hægland-bundle
很有趣。然而,在系统本身上没有关于-bundle
选项的额外开发者信息。无论是隐式调用还是直接调用,lipo
都似乎是所需的工具。根据您提到的细节,我们在问题中添加了其他发现。 - l --marc lExtUtils::MakeMaker
以生成带有“通用二进制”(例如 arm64、x86_64)指令的 Makefile #445。 - l --marc l