Вызов функции perl из другого скрипта perl с разными активными версиями perl
У нас есть две версии 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 с помощью системной команды, require или т. д.? Также как получить возвращаемое значение функции 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 script 5.6. Во время выполнения я не получил ожидаемого результата. Как получить значение «return $c» и значение «наш $OUTFILE» p5_24.pl в сценарии p5_6.pl?
Примечание . Вышеприведенный пример программы, основанный на этом, я изменю реальную программу, используя сериализованные данные.
Ответы
Поместите код функции, которой требуется версия 5.24, в скрипт-оболочку, написанный именно так, чтобы он запускал эту функцию (и выводил ее результат). На самом деле, я бы рекомендовал написать модуль с этой функцией, а затем загрузить этот модуль в скрипт-оболочку.
Затем запустите этот скрипт под нужным интерпретатором (5.24), вызвав его по полному пути. (Возможно, вам придется быть осторожным, чтобы убедиться, что все библиотеки и среда верны.) Сделайте это таким образом, чтобы вы могли получить его вывод. Это может быть что угодно, от обратных кавычек ( qx) до открытия канала или, что еще лучше, хороших модулей. Для этого существует ряд модулей, таких как Capture::Tiny, IPC::System::Simple, IPC::Run3или IPC::Run. Что использовать, будет зависеть от того, сколько вам нужно от этого звонка.
Вы не можете вызвать функцию в работающей программе, но каким-то образом запустить ее в другой программе.
Кроме того, переменные (такие как $OUTFILE), определенные в одной программе, не видны в другой. Вы можете распечатать их из программы версии 5.24 вместе с результатом этой функции, а затем проанализировать весь вывод в программе версии 5.6. Затем обеим программам потребуется небольшой «протокол» — чтобы либо подчиняться порядку, в котором что-то печатается, либо каким-то образом помечать отпечатки.
Гораздо лучше написать модуль с функциями и переменными, которые необходимо использовать совместно. Затем программа версии 5.24 может загрузить модуль, импортировать нужную функцию и запустить ее, в то время как программа версии 5.6 может загрузить тот же модуль, но только для того, чтобы подобрать эту переменную (а также запустить программу версии 5.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.plfor program_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в моем тесте.
Вы не можете напрямую вызвать функцию Perl, работающую с другой версией Perl. Вам нужно будет создать программу, которая явно вызывает функцию. Ввод и вывод должны быть явно сериализованы для переноса между этими двумя программами.
Сериализация может быть выполнена с помощью Data::Dumper, Storableили аналогичного. Если требуется более низкая производительность, вы можете вызвать программу, которая предоставляет функцию, systemи поделиться сериализованными данными с временными файлами или каналами. Или вы можете создать некоторую клиент-серверную архитектуру и поделиться сериализованными данными с сокетами. Последний быстрее, поскольку он пропускает повторный запуск и завершение другого процесса, а вместо этого поддерживает его работу.