安装和更新 Perl 模块为 “universal”(x86_64、arm64)?

huangapple go评论67阅读模式
英文:

Install & update a Perl module as "universal" (x86_64, arm64)?

问题

可以在具有通用(x86_64、arm64)架构支持的情况下安装和更新Perl(CPAN)模块吗?如果可以,如何进行操作?

背景:

在基于arm的macOS计算机上,可以通过以下方式为Perl CPAN模块安装特定架构:

sudo cpan -i Encode
### 等效,因为在这种情况下`-arm64`是本机处理器:
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

然而,请注意,Apple的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出现在保存的安装日志中,但man cccc --help没有提供有关-bundle选项的开发人员信息,因此不清楚-bundle实际上是在做什么,或者Perl新手如何使用这些信息。

  • 似乎最安全的构建通用二进制的方法是单独编译模块,然后使用lipo工具合并生成的.bundle文件。苹果的文章“构建通用macOS二进制”提供了一个多步骤示例。

  • file Encode.bundle显示了Encode.bundle文件的混合通用和非通用二进制。

  • 理想情况下,整体解决方案应该足够通用,不需要修改每个单独添加的模块,适用于初始模块安装和后续更新,不会创建Perl安装中的依赖冲突。

  • 可能的方法之一是使用lipo来创建通用二进制。

请告诉我您需要什么进一步的信息或帮助。

英文:

Is is possible to install and update Perl (CPAN) modules with universal (x86_64, arm64) architecture support? If yes, then how?

background

On an arm-based macOS computer, a Perl CPAN module can be installed for exactly one designated architecture as follows:

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

Notice, however, Apple's perl itself is a "universal binary":

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

The XOR of either one architecture or the other presents a conflict when native and non-native applications share the same Perl dependency. For example, GnuCash Finance::Quote does not run on natively on Arm while MacTeX LaTeX Live Update can run natively on either Intel or Arm processors. Both applications use the Pearl Encode module.

The application log error message will be one of the following if the required architecture version is not found:

> '/Library/Perl/5.30/darwin-thread-multi-2level/auto/Encode/Encode.bundle' (mach-o file, but is an incompatible architecture (have 'arm64', need 'x86_64'))

> '/Library/Perl/5.30/darwin-thread-multi-2level/auto/Encode/Encode.bundle' (mach-o file, but is an incompatible architecture (have 'x86_64', need 'arm64'))


Note: A workaround for running the applications is to install the common Perl module dependancy for the x86_64 architecture, and then run the universal capable application in Rosetta2 (x86_64) mode.


Additional Findings

cc option '-bundle'

cc -bundle was found in the saved install log.

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

However, man cc and cc --help do not provide any developer information about a -bundle option for the cc clang LLVM compiler. So, it's not clear what -bundle is actually doing, or how a Perl novice might use this piece of information.

lipo

It would appear that the "safest way to build Universal binaries is to compile the modules separately and then use lipo to merge the resulting .bundle files." See: meta::cpan Config_u.pm

The Apple article "Building a Universal macOS Binary" provides a such multi-step example:

> The following example shows a makefile that compiles a single-source file twice—once for each architecture. It then creates a universal binary by merging the resulting executable files together with the lipo tool.

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 requires the individual architecture files as inputs to -create the universal file.

file Encode.bundle

A search and review for all Encode.bundle files found a mixture of universal and non-universal binaries.

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

observations:

  1. file /System/Library/Perl/…Encode.bundle shows that universal binary use does indeed exist for Pearl.
  2. file /Library/Perl/…Encode.bundle indicate that a user install and/or update may be masking the universal /System/Library/Perl/…Encode.bundle from shared application use.

objectives

Ideally, an overall solution would:

  1. be generally enough to not require modification of each individual module which gets added.
  2. work for both an initial module installation and any subsequent updates.
  3. does not create dependency conflicts with in the Perl installation.

possible approaches

Whether implicitly or expressly invoked, lipo appear to be needed to create the univeral binary.

Just thinking out-loud about some approach directions:

  • modify the Perl make file? (how would one safely do this? is this a practical approach?)

  • create an updated version of Config_u?

perl -MConfig_u Makefile.PL
  • have parallel /Perl/arm64/… and /Perl/x86_64/… trees which are then lipo merged into some /Perl/some_universal_version/… via a script.

  • Could this be a easy as sudo arch -x86_64 -arm64 -arm64e cpan -i Encode?

答案1

得分: 4

Here are the translated parts of the code and text you provided:

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

Observation: I've had runtime issues if only one of arm64 or arm64e was installed. So far, including both arm64 and arm64e with x86_64 has been successful.

Check:

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]

Approach was found in the historic man perlmacosx page:

> Related to this support is the new environment variable ARCHFLAGS, which provides a way to build extensions for different machine and 32/64-bit architectures. The default architecture to build extensions before 10.5 was the (single) architecture of the building machine. In 10.6 and beyond, the default architectures were changed to building 32-bit for both PowerPC and Intel, and 64-bit only for Intel. With ARCHFLAGS, this can be changed to whatever architectures the user wants to build. For example:

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

>

> will build only 2-way universal.


The env ARCHFLAGS='…' variable also works with cpan. However, to replace a single-architecture binary with a universal binary of the same version number, then the -f force option is needed. The cpan version comparison is not universal binary aware.

# 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

Caveat: The -f force option does not provide potential useful test result information.


Approach: App::cpanminus

Example for a clean install GnuCash Finance::Quote using cpanm:

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

Caveat: This works for a clean install. An existing install will likely need an uninstall-reinstall or forced-install process to replace the non-universal binary.

Use find and file commands to determine which Perl *.bundle modules need to be fixed by uninstall-reinstall or forced-install approaches.

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

Related

英文:
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

Observation: I've had runtime issues if only one of arm64 or arm64e was installed. So far, including both arm64 and arm64e with x86_64 has been successful.

Check:

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]

Approach was found in the historic man perlmacosx page:

> Related to this support is the new environment variable ARCHFLAGS, which provides a way to build extensions for different machine and 32/64-bit architectures. The default architecture to build extensions before 10.5 was the (single) architecture of the building machine. In 10.6 and beyond, the default architectures were changed to building 32-bit for both PowerPC and Intel, and 64-bit only for Intel. With ARCHFLAGS, this can be changed to whatever architectures the user wants to build. For example:
>
> lang-sh
> % env ARCHFLAGS='-arch i386 -arch x86_64' perl Makefile.PL
> % make
> % make install
>

>
> will build only 2-way universal.


The env ARCHFLAGS='…' variable also works with cpan. However, to replace a single-architecture binary with a universal binary of the same version number, then the -f force option is needed. The cpan version comparison is not univeral binary aware.

# 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

Caveat: The -f force option does not provide potential useful test result information.


Approach: App::cpanminus

Example for a clean install GnuCash Finance::Quote using cpanm:

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

Caveat: This works for a clean install. An existing install will likely need an uninstall-reinstall or forced-install process to replace the non-universal binary.

Use find and file commands to determine which Perl *.bundle modules need to be fixed by uninstall-reinstall or forced-install approaches.

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

Related

答案2

得分: 1

以下是已翻译的内容:

> Is is possible to install and update Perl (CPAN) modules with universal (x86_64, arm64) architecture support?

我相信您可以通过为Makefile.PL添加与相关架构对应的-arch标志来更新.bundle文件。我用Encode进行了测试,手动编译Encode.bundle而不是使用ExtUtils::MakeMaker,如下所示(macOS M1,ventura 13.1,homebrew 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的通用二进制文件。

英文:

> Is is possible to install and update Perl (CPAN) modules with universal (x86_64, arm64) architecture support?

I believe you can update the .bundle file by adding a -arch flag for the relevant architectures to the Makefile.PL. I tested this with Encode compiling the Encode.bundle by hand instead of using ExtUtils::MakeMaker like this (macOS M1, ventura 13.1, homebrew perl version 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

The output of the last command is now:

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

which shows that the Encode.bundle has been updated to a universal binary with architectures x86_64 and arm64

huangapple
  • 本文由 发表于 2023年4月11日 14:59:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/75983186.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定