เรียกใช้ฟังก์ชัน Perl จากสคริปต์ Perl อื่นที่มีเวอร์ชัน Active Perl ต่างกัน

Apr 06 2020

เรามี Active perl 5.6 และ 5.24 สองเวอร์ชัน เรามีบริการเว็บที่ต้องดำเนินการในเวอร์ชัน Active perl '5.24' (เพื่อใช้เวอร์ชัน TLS 1.2) และสิ่งนี้จำเป็นต้องเรียกใช้จากเวอร์ชัน Active perl '5.6' เรากำลังใช้ระบบปฏิบัติการ windows

ตามขั้นตอน:รหัสผู้โทรซึ่งดำเนินการในเวอร์ชัน 5.6 เรียกใช้เวอร์ชัน 5.24 โดยใช้คำสั่ง system /require

ปัญหา:วิธีเรียกใช้ฟังก์ชัน perl 5.24 (ตัวอย่าง: webservicecall(arg1){return "xyz") จากสคริปต์ perl 5.6 ผ่านคำสั่งระบบ ต้องการ หรืออื่นๆ .. จะรับค่าส่งคืนของฟังก์ชัน 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.24 จากเวอร์ชันสคริปต์ perl 5.6 ในระหว่างการดำเนินการ ฉันไม่ได้รับผลลัพธ์ตามที่คาดไว้ วิธีรับค่า "return $c" & ค่า "$OUTFILE ของเรา" ของ p5_24.pl ในสคริปต์ p5_6.pl

หมายเหตุ:ข้างต้นคือโปรแกรมตัวอย่างตามนี้ ฉันจะแก้ไขโปรแกรมจริงโดยใช้ข้อมูลซีเรียลไลซ์

คำตอบ

4 zdim Apr 06 2020 at 13:16

วางโค้ดสำหรับฟังก์ชันที่ต้องการ v5.24 ในสคริปต์ตัวตัดคำ ซึ่งเขียนขึ้นเพื่อให้เรียกใช้ฟังก์ชันนั้น (และพิมพ์ผลลัพธ์ออกมา) อันที่จริง ฉันขอแนะนำให้เขียนโมดูลด้วยฟังก์ชันนั้น แล้วโหลดโมดูลนั้นในสคริปต์ตัวตัดคำ

จากนั้นเรียกใช้สคริปต์นั้นภายใต้ล่ามที่ต้องการ (5.24) โดยเรียกใช้ผ่านเส้นทางแบบเต็ม (คุณอาจต้องระมัดระวังเพื่อให้แน่ใจว่าไลบรารีและสภาพแวดล้อมทั้งหมดถูกต้อง) ทำเช่นนี้ในลักษณะที่ช่วยให้คุณสามารถรับเอาต์พุตได้ ซึ่งสามารถเป็นอะไรก็ได้ตั้งแต่ backticks ( qx) ไปจนถึงท่อเปิดหรือดีกว่านั้นไปจนถึงโมดูลที่ดี มีโมดูลมากมายสำหรับสิ่งนี้ เช่นCapture::Tiny, IPC::System::Simple, , IPC::Run3หรือ IPC::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 ปรากมา

โปรดทราบว่ามีวิธีที่ดีกว่าในการรันโปรแกรมภายนอก --- ดูโมดูลที่แนะนำด้านบน ฉันขอย้ำว่านี่เป็นการสาธิตคร่าวๆเนื่องจากรายละเอียดหลายอย่างขึ้นอยู่กับสิ่งที่คุณทำ

สุดท้าย โปรแกรมยังสามารถเชื่อมต่อผ่านซ็อกเก็ตและแลกเปลี่ยนทุกอย่างที่ต้องการได้ แต่นั่นซับซ้อนกว่าเล็กน้อยและอาจไม่จำเป็น


คำถามได้รับการแก้ไขแล้ว และตอนนี้เรามีD:\Perl\bin\perlfor path-to-perl-5.24และD:\sample_program\p5.24.plforprogram_for_5.24

โปรดทราบว่าด้วยตำแหน่งดังกล่าวของp5.24.plโปรแกรม คุณต้องหาตำแหน่งที่เหมาะสมสำหรับโมดูล จากนั้นชื่อของมันจะต้องมี (ส่วนหนึ่งของ) เส้นทางนั้นอยู่ในนั้นและต้องโหลดด้วยชื่อดังกล่าว ดูตัวอย่างกระทู้นี้


การสาธิตคร่าวๆ ที่ไม่มีโมดูล (โพสต์ต้นฉบับ)

ในโปรแกรมของคุณที่ทำงานภายใต้ 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ในการทดสอบของฉัน

1 SteffenUllrich Apr 06 2020 at 13:15

คุณไม่สามารถเรียกฟังก์ชัน Perl ที่ทำงานด้วย Perl เวอร์ชันอื่นได้โดยตรง คุณจะต้องสร้างโปรแกรมที่เรียกใช้ฟังก์ชันอย่างชัดเจน อินพุตและเอาต์พุตจำเป็นต้องทำให้เป็นซีเรียลไลซ์อย่างชัดเจนเพื่อขนส่งระหว่างสองโปรแกรมนี้

การทำให้เป็นอันดับสามารถทำได้ด้วย หรือ Data::Dumperที่Storableคล้ายกัน หากต้องการประสิทธิภาพที่ต่ำกว่า คุณสามารถเรียกใช้โปรแกรมที่มีฟังก์ชันsystemและแบ่งปันข้อมูลซีเรียลไลซ์กับไฟล์ชั่วคราวหรือไพพ์ หรือคุณสามารถสร้างสถาปัตยกรรมไคลเอนต์เซิร์ฟเวอร์และแบ่งปันข้อมูลซีเรียลไลซ์กับซ็อกเก็ต วิธีหลังเร็วกว่าเนื่องจากข้ามการเริ่มต้นซ้ำๆ และการแยกย่อยของกระบวนการอื่น แต่ให้ทำงานแทน