从另一个具有不同 Active perl 版本的 perl 脚本调用 perl 函数

Posted

技术标签:

【中文标题】从另一个具有不同 Active perl 版本的 perl 脚本调用 perl 函数【英文标题】:Call perl function from another perl script with different Active perl versions 【发布时间】:2020-07-18 02:16:49 【问题描述】:

我们有两个版本的 Active perl 5.6 和 5.24。我们有必须在 Active perl '5.24' 版本(采用 TLS 1.2 版本)上执行的 Web 服务,这需要从 Active perl '5.6' 版本调用。我们使用的是windows操作系统。

后续步骤: 在 5.6 版本中执行的调用者代码使用 system /require 命令调用 5.24 版本。

问题: 如何通过系统命令、require 等从 5.6 perl 脚本调用 5.24 perl 函数(例如:webservicecall(arg1)return "xyz")? 还有如何获取perl函数5.24的返回值?

注意: 拥有两个 perl 版本是一项临时工作,我们计划将其升级为更高版本。

这里 perl 5.6 版安装在“C:\Perl\bin\perl\”中,perl 5.24 版安装在“D:\Perl\bin\perl\”中。

"**p5_6.pl**"

print "Hello Perl5_6\n";
system('D:\Perl\bin\perl D:\sample_program\p5.24.pl');

print $OUTFILE;
$retval = Mul(25, 10);
print ("Return value is $retval\n" );

"**p5_24.pl**"

print "Hello Perl5_24\n";
our $OUTFILE  = "Hello test";
sub Mul($$)  

    my($a, $b ) = @_;  
    my $c = $a * $b;
    return($c);

我已经编写了示例程序以获取从 perl 脚本 5.6 版本调用 perl 5.24 版本的详细信息。在执行期间,我没有得到预期的输出。如何在 p5_6.pl 脚本中获取 p5_24.pl 的“return $c”值和“我们的 $OUTFILE”值?

注意:以上是基于此的示例程序,我将使用序列化数据修改实际程序。

【问题讨论】:

【参考方案1】:

将需要 v5.24 的函数的代码放在一个包装脚本中,编写它以便运行该函数(并打印其结果)。实际上,我建议使用该函数编写一个模块,然后将该模块加载到包装脚本中。

然后在想要的 (5.24) 解释器下运行该脚本,通过其完整路径调用它。 (您可能需要小心确保所有库和环境都是正确的。)这样做的方式可以让您获取其输出。这可以是任何东西,从反引号 (qx) 到管道打开,或者更好的是,到好的模块。为此有一系列模块,例如IPC::System::SimpleCapture::TinyIPC::Run3IPC::Run。使用哪个取决于您需要多少通话。

你不能在一个正在运行的程序中调用一个函数,而是让它在另一个程序下运行。

另外,在一个程序中定义的变量(如$OUTFILE)在另一个程序中是看不到的。您可以从 v5.24 程序中打印它们以及该函数结果,然后在 v5.6 程序中解析整个输出。然后这两个程序需要一些“协议”——要么遵守打印的顺序,要么以某种方式标记打印。

更好的是,编写一个包含需要共享的函数和变量的模块。然后 v5.24 程序可以加载模块并导入它需要的函数并运行它,而 v5.6 程序可以加载相同的模块,但只能获取该变量(并且还运行 v5.24 程序)。

这是所有这一切的草图。打包文件SharedBetweenPerls.pm

package SharedBetweenPerls;

use warnings; 
use strict;

use Exporter qw(import);
our @EXPORT_OK = qw(Mul export_vars);

my $OUTFILE = 'test_filename';

sub Mul  return $_[0] * $_[1] 

sub export_vars  return $OUTFILE 

1;

然后v5.24程序(下面用program_for_5.24.pl)就可以了

use warnings;
use strict;

# Require this to be run by at least v5.24.0
use v5.24;

# Add path to where the module is, relative to where this script is
# In our demo it's the script's directory ($RealBin)
use FindBin qw($RealBin);
use lib $RealBin;

use SharedBetweenPerls qw(Mul);
    
my ($v1, $v2) = @ARGV;

print Mul($v1, $v2);

而v5.6程序可以做到

use warnings;
use strict;
use feature 'say';

use FindBin qw($RealBin);
use lib $RealBin;

use SharedBetweenPerls qw(export_vars);

my $outfile = export_vars();  #--> 'test_filename'

# Replace "path-to-perl..."  with an actual path to a perl
my $from_5.24 = qx(path-to-perl-5.24 program_for_5.24.pl 25 10);  #--> 250

say "Got variable: $outfile, and return from function: $from_5.24";

其中$outfile 具有字符串test_filename$from_5.24 变量是250

如果两个程序和模块都在同一个目录中,并且名称与本示例中的名称相同,则测试它可以正常工作。 (并将path-to-perl-5.24 替换为您的v5.24 可执行文件的实际路径。)如果它们位于不同的位置,您需要调整路径,可能是包名称和use lib 行。见lib pragma。

请注意,有更好的方法来运行外部程序 --- 请参阅上面推荐的模块。所有这些都是粗略的演示,因为许多细节取决于你具体做什么。

最后,程序还可以通过套接字连接并交换所需的一切,但这有点复杂,可能不需要。


问题已被编辑,我们现在有D:\Perl\bin\perl 对应path-to-perl-5.24D:\sample_program\p5.24.pl 对应program_for_5.24

请注意,使用p5.24.pl 程序的这样一个位置,您必须为模块提供一个合适的位置,然后它的名称需要在其中包含(一部分)该路径并被加载有这样的名字。参见例如this post。


没有模块的粗略演示(最初发布)

作为一个非常粗略的草图,在你的 v5.6 下运行的程序中你可以这样做

my $from_5.24 = qx(path-to-perl-5.24 program_for_5.24.pl 25 10);

program_for_5.24.pl 可能类似于

use warnings;
use strict;

sub Mul  return $_[0] * $_[1] 

my ($v1, $v2) = @ARGV;

print Mul($v1, $v2);

变量$from_5.24 在我的测试中最终成为250

【讨论】:

我已经详细分享了我的查询 @Grace 您的示例 p5.24.pl 程序需要运行它定义的函数 (Mul),并打印它想要发送给调用它的任何人的内容。所以你需要print Mul(25,10);。然后调用 p5.24.pl 程序(来自 v5.6 程序),以便您可以获得它的输出(system 不做的事情),例如 my $ret = qx(path-to-perl-5.24 D:\sample_program\p.5.24.pl) 。 (并从p5.24.pl 程序中删除Hello 的打印:)。或者,让p5.24.pl 在调用p5.24.pl 之后将其结果打印到其他程序可以读取的文件。 @Grace 我在答案末尾添加了一个基本示例 @Grace 已编辑并添加到答案中 @Grace 添加了一行代码来帮助加载模块(到两个程序),以防你不知道该怎么做【参考方案2】:

您不能直接调用使用另一个 Perl 版本运行的 Perl 函数。您需要创建一个显式调用该函数的程序。输入和输出需要显式序列化才能在这两个程序之间传输。

序列化可以使用Data::DumperStorable 或类似方法完成。如果需要较低的性能,您可以调用提供system 功能的程序,并与临时文件或管道共享序列化数据。或者您可以创建一些客户端-服务器架构并与套接字共享序列化数据。后者更快,因为它跳过了另一个进程的重复启动和拆卸,而是保持它运行。

【讨论】:

我已经详细分享了我的查询

以上是关于从另一个具有不同 Active perl 版本的 perl 脚本调用 perl 函数的主要内容,如果未能解决你的问题,请参考以下文章

可以将 perl 脚本的执行权限限制为从另一个 perl 脚本调用吗?

从另一个 Perl 脚本内部调用 Perl 搜索和替换命令时不起作用

从另一个环境调用 Perl 在后台

Perl ipc 使用管道从另一个进程启动一个进程的执行

Excel VBA从另一个具有多个输入,不同大小的输出的子调用子

如何从另一个按钮激活一个按钮