是否可以安装和更新具有通用(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 编码模块.
如果找不到所需的体系结构版本,应用程序日志错误消息将是以下之一:
'/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
合并生成的 .bundle
文件。”参见:meta::cpan Config_u.pm
Apple文章“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
通用文件的输入。
文件编码.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
。目标
理想情况下,整体解决方案将:
可能的方法
无论是隐式调用还是显式调用,
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
一样简单吗?
是否可以安装和更新具有通用(x86_64、arm64)架构支持的 Perl(CPAN)模块?
我相信你可以通过为相关架构添加一个
.bundle
标志来更新-arch
文件到Makefile.PL
。我用 Encode
测试了这个,手动编译 Encode.bundle
而不是像这样使用 ExtUtils::MakeMaker
(macOS M1,ventura 13.1,自制 perl 版本 5.34):
#! /bin/bash
arch_opt="-arch x86_64 -arch arm64"
opt1="-I./Encode -fno-common -DPERL_DARWIN -fno-strict-aliasing"
opt2="-mmacosx-version-min=12.0 -fstack-protector-strong"
opt3="-pipe -DPERL_USE_SAFE_PUTENV -Wno-error=implicit-function-declaration -O3"
opt4=-DVERSION=\"3.19\"
opt5=-DXS_VERSION=\"3.19\"
opt6="-I/opt/homebrew/Cellar/perl/5.34.0/lib/perl5/5.34.0/darwin-thread-multi-2level/CORE"
ccopts="$arch_opt $opt1 $opt2 $opt3 $opt4 $opt5 $opt6"
ldopts="$arch_opt $opt2"
cc -c $ccopts Encode.c
cc -c $ccopts def_t.c
cc -c $ccopts encengine.c
cc -bundle -undefined dynamic_lookup $ldopts \
Encode.o def_t.o encengine.o -o blib/arch/auto/Encode/Encode.bundle
file blib/arch/auto/Encode/Encode.bundle
现在最后一个命令的输出是:
blib/arch/auto/Encode/Encode.bundle: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit bundle x86_64] [arm64:Mach-O 64-bit bundle arm64]
blib/arch/auto/Encode/Encode.bundle (for architecture x86_64): Mach-O 64-bit bundle x86_64
blib/arch/auto/Encode/Encode.bundle (for architecture arm64): Mach-O 64-bit bundle arm64
这表明
Encode.bundle
已更新为具有架构 x86_64
和 arm64
的通用二进制文件