首页 > 解决方案 > 嵌入仅 Perl 的模块和嵌入的 Perl 解释器

问题描述

我关注了https://perldoc.perl.org/perlembed并成功构建了一个interp二进制文件。当我使用static_ext时,输出目录将*.pm文件安装到前缀目录中。

如何添加自定义的简单*.pm模块,例如TLUtils.pm,而无需将模块文件解压到临时目录中?基本上,作为一个例子,我想嵌入https://github.com/TeX-Live/texlive-source/blob/trunk/texk/texlive/linked_scripts/texlive/fmtutil.plhttps://github.com /TeX-Live/texlive-source/blob/trunk/texk/texlive/linked_scripts/texlive/updmap.pl依赖于 TLUtils。一个更复杂的目标可能是在不使用 PAR 的情况下打包biber 。

我可以以某种方式将此模块导入给定*.pm源代码的解释器吗?

在虚拟文件系统方面,是否有人有滚动原始只读虚拟文件系统(例如通过覆盖lstat, open, read)以从内存导入包的示例?

我意识到 PAR 解决了这个问题,但我想知道是否有简单的拐杖可以在不依赖 PAR 的情况下使用。

谢谢!

升级版:

mkdir -p source build/native/perl
wget -nc https://www.cpan.org/src/5.0/perl-5.30.0.tar.gz -P source
tar -xf source/*.tar.gz --strip-components=1 --directory=build/native/perl
cd build/native/perl
bash ./Configure -sde -Dprefix=$PWD/../prefix -Aldflags=-lm -Accflags=-lm -Dstatic_ext="IO Fcntl"
make miniperl generate_uudmap
make perl
make install

../prefix/bin/perl5.30.0 -e 'print 123; use Fcntl; print 456;'
# prints 123456

../prefix/bin/perl5.30.0 -MExtUtils::Embed -e ccopts -e ldopts
# -Wl,-E  -lm -fstack-protector-strong -L/usr/local/lib /home/runner/work/buildbiber/buildbiber/build/native/perl/../prefix/lib/5.30.0/x86_64-linux/auto/Fcntl/Fcntl.a /home/runner/work/buildbiber/buildbiber/build/native/perl/../prefix/lib/5.30.0/x86_64-linux/auto/IO/IO.a -L/home/runner/work/buildbiber/buildbiber/build/native/perl/../prefix/lib/5.30.0/x86_64-linux/CORE -lperl -lpthread -lnsl -ldl -lm -lcrypt -lutil -lc           -lm -fwrapv -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64  -I/home/runner/work/buildbiber/buildbiber/build/native/perl/../prefix/lib/5.30.0/x86_64-linux/CORE

cc -o emperl ../../../emperl.c `../prefix/bin/perl5.30.0 -MExtUtils::Embed -e ccopts -e ldopts`
./emperl -e 'print 123; use Fcntl; print 456;'
# prints Can't load module Fcntl, dynamic loading not available in this perl.
#  (You may need to build a new perl executable which either supports
#  dynamic loading or has the Fcntl module statically linked into it.)
# at -e line 1.
# Compilation failed in require at -e line 1.

# This is an extremely strange error because Fcntl is indeed built and linked statically as evidenced by the linking flags above

echo '{' > fmtutil_.pl
curl https://raw.githubusercontent.com/TeX-Live/installer/master/tlpkg/TeXLive/TLUtils.pm >> fmtutil_.pl
echo '}' >> fmtutil_.pl
curl https://raw.githubusercontent.com/TeX-Live/texlive-source/trunk/texk/texlive/linked_scripts/texlive/fmtutil.pl >> fmtutil_.pl

./emperl fmtutil_.pl --help
# also fails with Fcntl problem

标签: perlmoduleembed

解决方案


第一个问题:

无法加载模块 Fcntl,此 perl 中不提供动态加载。

根据perlembed,您需要在嵌入式解释器中插入一些 XS 胶水代码emperl.c

#include <EXTERN.h>               /* from the Perl distribution     */
#include <perl.h>                 /* from the Perl distribution     */
static PerlInterpreter *my_perl;  /***    The Perl interpreter    ***/
EXTERN_C void xs_init (pTHX);

int main(int argc, char **argv, char **env)
{
       PERL_SYS_INIT3(&argc,&argv,&env);
       my_perl = perl_alloc();
       perl_construct(my_perl);
       PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
       perl_parse(my_perl, xs_init, argc, argv, (char **)NULL);
       perl_run(my_perl);
       perl_destruct(my_perl);
       perl_free(my_perl);
       PERL_SYS_TERM();
       exit(EXIT_SUCCESS);
}

请注意,perl_parse()现在以指向xs_init子例程的指针作为第二个参数运行。xs_init()可以emperl使用以下命令生成该函数并将其编译为二进制文件:

PERL=build/native/prefix/bin/perl5.34.0
$PERL -MExtUtils::Embed -e xsinit -- -o perlxsi.c
cc -c perlxsi.c `$PERL -MExtUtils::Embed -e ccopts`
cc -c emperl.c `$PERL -MExtUtils::Embed -e ccopts`
cc -o emperl perlxsi.o emperl.o `$PERL -MExtUtils::Embed -e ldopts`

如果我现在像您一样测试嵌入式二进制文件,它似乎工作正常:

$ ./emperl -e 'print 123; use Fcntl; print 456;'
123456

第二个问题:

如何添加自定义简单*.pm模块,例如TLUtils.pm无需将模块文件解压缩到临时目录中?

根据安装文件:

如果您ext/在运行之前解压缩目录中的任何其他扩展Configure,那么Configure也将提供构建这些额外的扩展。

我用这样一个简单的 XS 模块尝试了Sort::Key这个(这里我使用Configure选项-Uusedl强制perl完全静态编译):

mkdir -p source build/native/perl
wget -nc https://www.cpan.org/src/5.0/perl-5.34.0.tar.gz -P source
tar -xf source/*.tar.gz --strip-components=1 --directory=build/native/perl
cd build/native/perl
cd ext
wget https://cpan.metacpan.org/authors/id/S/SA/SALVA/Sort-Key-1.33.tar.gz
mkdir -p Sort-Key
tar -xf Sort-Key-1.33.tar.gz --strip-components=1 --directory=Sort-Key
cd ..
sh ./Configure -sde -Dman1dir=none -Dman3dir=none -Dprefix=$PWD/../prefix -Uusedl
make
make install

perl然后像以前一样使用emperl.c代码嵌入它:

PERL=build/native/prefix/bin/perl5.34.0
$PERL -MExtUtils::Embed -e xsinit -- -o perlxsi.c
# Note: for some reason you need to comment out the two lines with 
#   Devel::PPPort from perlxsi.c in order to compile it..
perl -i -ne 'print if !/PPPort/' perlxsi.c
cc -c perlxsi.c `$PERL -MExtUtils::Embed -e ccopts`
cc -c emperl.c `$PERL -MExtUtils::Embed -e ccopts`
cc -o emperl perlxsi.o emperl.o `$PERL -MExtUtils::Embed -e ldopts`

然后用模块测试嵌入式解释Sort::Key器:

$ ./emperl -e 'print 123; use Sort::Key; print 456'
123456

推荐阅读