安装和更新Perl模块作为"universal"(x86_64,arm64)?



是否可以安装和更新支持通用(x86_64,arm64)体系结构的Perl(CPAN)模块?如果是,那么怎么做?

背景

在基于arm的macOS计算机上,可以为以下一个指定的体系结构安装PerlCPAN模块:

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模块。

如果找不到所需的体系结构版本,则应用程序日志错误消息将是以下消息之一:

'/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

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 cccc --help没有为cc-crang LLVM编译器提供任何关于-bundle选项的开发人员信息。因此,目前还不清楚-bundle实际在做什么,也不清楚Perl新手如何使用这条信息。

看来;构建通用二进制文件最安全的方法是分别编译模块,然后使用lipo合并生成的.bundle文件"请参阅:meta::cpan Config_u.pm

苹果的文章";构建通用macOS二进制";提供了这样一个多步骤示例:

下面的示例显示了一个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文件的搜索和审查发现了通用和非通用二进制文件的混合。

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

观察结果:

  1. file /System/Library/Perl/…Encode.bundle表明,珀尔确实存在普遍的二进制使用
  2. CCD_ 15指示用户安装和/或更新可能屏蔽通用CCD_

目标

理想情况下,整体解决方案是:

  1. 通常足以不需要修改添加的每个单独模块
  2. 用于初始模块安装和任何后续更新
  3. 在Perl安装中不会创建与的依赖关系冲突

可能的方法

无论是隐式调用还是显式调用,似乎都需要lipo来创建univeral二进制文件。

只是大声思考一些进近方向:

  • 是否修改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一样简单吗?

env ARCHFLAGS='-arch arm64 -arch arm64e -arch x86_64' perl Makefile.PL
make
arch -x86_64 make test
arch -arm64  make test
arch -arm64e make test
(sudo) make install

观察:如果只安装了arm64arm64e中的一个,我会遇到运行时问题。到目前为止,将arm64arm64e都包含在x86_64中是成功的

检查:

file Encode.bundle
# Encode.bundle: Mach-O universal binary with 3 architectures: 
#     [x86_64:Mach-O 64-bit bundle x86_64] 
#     [arm64e:Mach-O 64-bit bundle arm64]
#     [arm64e:Mach-O 64-bit bundle arm64e]

方法在历史man perlmacosx页面中找到:

与此支持相关的是新的环境变量ARCHFLAGS,它提供了一种为不同的机器和32/64位体系结构构建扩展的方法。10.5之前构建扩展的默认体系结构是构建机器的(单一)体系结构。在10.6及更高版本中,PowerPC和Intel的默认体系结构都更改为构建32位,而Intel仅构建64位使用ARCHFLAGS,可以将其更改为用户想要构建的任何体系结构例如:

% env ARCHFLAGS='-arch i386 -arch x86_64' perl Makefile.PL
% make
% make install

将只建立双向通用。


env ARCHFLAGS='…'变量也适用于cpan。但是,要用相同版本号的通用二进制文件替换单个体系结构二进制文件,则需要-fforce选项。cpan版本比较不是唯一的二进制识别。

# ok for initial install or version update
(sudo) env ARCHFLAGS='-arch arm64 -arch arm64e -arch x86_64' cpan -i Encode
# -f force is needed to "reinstall|replace" an existing version
(sudo) env ARCHFLAGS='-arch arm64 -arch arm64e -arch x86_64' cpan -f -i Encode

注意事项:-fforce选项不提供潜在有用的测试结果信息


方法:App::cpanminus

使用cpanm:的干净安装GnuCash Finance::Quote的示例

sudo env ARCHFLAGS='-arch arm64 -arch arm64e -arch x86_64' cpan App::cpanminus
sudo env ARCHFLAGS='-arch arm64 -arch arm64e -arch x86_64' cpanm Test2
sudo env ARCHFLAGS='-arch arm64 -arch arm64e -arch x86_64' cpanm Finance::Quote
sudo env ARCHFLAGS='-arch arm64 -arch arm64e -arch x86_64' cpanm JSON::Parse

注意事项:这适用于干净的安装。现有安装可能需要卸载-重新安装或强制安装过程来替换非通用二进制文件

使用findfile命令来确定哪些Perl*.bundle模块需要通过卸载-重新安装或强制安装方法进行修复。

find /Library/Perl -name "*.bundle" | xargs file
# /Library/Perl/5.30/…/Readonly/XS/XS.bundle:
#     Mach-O universal binary with 3 architectures: 
#         [x86_64:Mach-O 64-bit bundle x86_64] 
#         [arm64:Mach-O 64-bit bundle arm64] 
#         [arm64e:Mach-O 64-bit bundle arm64e]
# /Library/Perl/5.30/…/Test/LeakTrace/LeakTrace.bundle: 
#     Mach-O universal binary with 3 architectures: 
# …
#
# /Library/Perl/5.30/…/Date/Simple/Simple.bundle: 
#     Mach-O 64-bit bundle x86_64
# /Library/Perl/5.30/…/Sereal/Encoder/Encoder.bundle:
#     Mach-O 64-bit bundle x86_64

相关

  • GitHub/Perl/perl5:[doc]README.macosx-如何使用多个mach-O ISA切片安装/更新Perl模块#21140

是否可以安装和更新支持通用(x86_64,arm64)体系结构的Perl(CPAN)模块?

我相信您可以通过在Makefile.PL中添加相关体系结构的-arch标志来更新.bundle文件。我用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_64arm64的通用二进制

最新更新