این دستور perlxstut است که می تواند در ارائه دهنده هاست رایگان OnWorks با استفاده از یکی از چندین ایستگاه کاری آنلاین رایگان ما مانند Ubuntu Online، Fedora Online، شبیه ساز آنلاین ویندوز یا شبیه ساز آنلاین MAC OS اجرا شود.
برنامه:
نام
perlxstut - آموزش نوشتن XSUB
شرح
این آموزش به خواننده در مورد مراحل ایجاد یک افزونه Perl آموزش می دهد.
فرض بر این است که خواننده به perlguts، perlapi و perlxs دسترسی دارد.
این آموزش با مثال های بسیار ساده شروع می شود و با هر بار جدید پیچیده تر می شود
به عنوان مثال اضافه کردن ویژگی های جدید برخی مفاهیم ممکن است تا بعداً به طور کامل توضیح داده نشوند
در این آموزش به منظور آسان کردن خواننده در ساخت برنامه های افزودنی.
این آموزش از دیدگاه یونیکس نوشته شده است. جایی که من می دانم آنها در غیر این صورت هستند
برای پلتفرم های دیگر (مانند Win32) متفاوت است، من آنها را لیست می کنم. اگر چیزی پیدا کردید که
از دست رفته بود لطفا به من اطلاع دهید
ویژه NOTES
ساخت
این آموزش فرض می کند که برنامه make که Perl برای استفاده از آن پیکربندی شده است فراخوانی می شود
"ساختن". به جای اجرای "make" در مثال های زیر، ممکن است مجبور شوید جایگزین کنید
هر برنامه make Perl برای استفاده پیکربندی شده است. در حال دویدن پرل -V:ساخت باید بگوید
تو چی هستی
نسخه هشدار
هنگام نوشتن پسوند Perl برای مصرف عمومی، باید انتظار داشت که
برنامه افزودنی با نسخه های Perl متفاوت از نسخه موجود در شما استفاده می شود
دستگاه. از آنجایی که شما در حال خواندن این سند هستید، نسخه Perl در دستگاه شما موجود است
احتمالاً 5.005 یا بالاتر، اما کاربران برنامه افزودنی شما ممکن است نسخه های قدیمی تری داشته باشند.
برای درک اینکه چه نوع ناسازگاری هایی را می توان انتظار داشت، و در موارد نادر آن
نسخه Perl در دستگاه شما قدیمی تر از این سند است، به بخش مربوطه مراجعه کنید
برای اطلاعات بیشتر "عیب یابی این نمونه ها".
اگر برنامه افزودنی شما از برخی ویژگیهای Perl استفاده میکند که در نسخههای قدیمیتر موجود نیستند
پرل، کاربران شما از یک هشدار زودهنگام قدردانی خواهند کرد. احتمالا قرار می دهید
این اطلاعات به README فایل، اما امروزه نصب پسوندها ممکن است
به طور خودکار انجام می شود، با هدایت CPAN.pm ماژول یا ابزارهای دیگر
در نصب های مبتنی بر MakeMaker، Makefile.PL اولین فرصت را برای اجرا فراهم می کند
بررسی نسخه می توان چنین چیزی را در آن قرار داد Makefile.PL به این منظور:
ارزش {نیازمند 5.007}
یا بمیرید <
############
### این ماژول از چارچوب frobnication استفاده می کند که در دسترس نیست
### قبل از نسخه 5.007 پرل. قبلا پرل خود را ارتقا دهید
### نصب Kara::Mba.
############
سپس
پویا بار در مقابل ایستا بار
معمولاً تصور می شود که اگر یک سیستم قابلیت بارگذاری دینامیکی a را نداشته باشد
کتابخانه، شما نمی توانید XSUB بسازید. این نادرست است. شما می توان آنها را بسازید، اما باید
زیر روال های XSUBs را با بقیه Perl پیوند دهید و یک فایل اجرایی جدید ایجاد کنید. این
وضعیت مشابه پرل 4 است.
این آموزش همچنان در چنین سیستمی قابل استفاده است. مکانیزم ساخت XSUB این را بررسی می کند
سیستم و در صورت امکان یک کتابخانه با قابلیت بارگذاری پویا بسازید یا یک کتابخانه استاتیک و
سپس، به صورت اختیاری، یک فایل اجرایی جدید با پیوند ایستا با آن کتابخانه ایستا مرتبط است.
اگر بخواهید یک فایل اجرایی با پیوند استاتیک روی سیستمی بسازید که بتواند به صورت پویا باشد
در تمام مثالهای زیر میتوانید کتابخانهها را بارگیری کنید، جایی که دستور "make" با شماره وجود دارد
آرگومان ها اجرا می شود، به جای آن دستور "make perl" را اجرا کنید.
اگر چنین فایل اجرایی با پیوند ایستا را با انتخاب ایجاد کرده اید، به جای آن
با گفتن "make test"، باید بگویید "make test_static"". در سیستم هایی که نمی توانند بسازند
اصلاً کتابخانههای با قابلیت بارگذاری پویا، فقط گفتن «مستت کردن» کافی است.
موضوع و PERL_NO_GET_CONTEXT
برای ساختهای رشتهای، پرل به نشانگر زمینه برای رشته فعلی نیاز دارد، بدون آن
"PERL_NO_GET_CONTEXT"، perl تابعی را برای بازیابی متن فراخوانی می کند.
برای بهبود عملکرد، شامل:
#define PERL_NO_GET_CONTEXT
همانطور که در زیر نشان داده شده است.
برای جزئیات بیشتر، به perlguts مراجعه کنید.
آموزش
حالا بیایید به نمایش ادامه دهیم!
مثال 1
اولین افزونه ما بسیار ساده خواهد بود. وقتی روال را در پسوند فراخوانی می کنیم، آن را
یک پیام شناخته شده را چاپ می کند و باز می گردد.
"h2xs -A -n Mytest" را اجرا کنید. این یک دایرکتوری به نام Mytest، احتمالاً در زیر ext/if ایجاد می کند
آن دایرکتوری در دایرکتوری کاری فعلی وجود دارد. چندین فایل ایجاد خواهد شد
تحت راهنمای Mytest، از جمله MANIFEST، Makefile.PL، lib/Mytest.pm، Mytest.xs،
t/Mytest.t و Changes.
فایل MANIFEST حاوی نام تمام فایل هایی است که در Mytest ایجاد شده اند
دایرکتوری.
فایل Makefile.PL باید چیزی شبیه به این باشد:
از ExtUtils::MakeMaker استفاده کنید.
# برای جزئیات نحوه تأثیرگذاری به lib/ExtUtils/MakeMaker.pm مراجعه کنید
# محتویات Makefile که نوشته شده است.
WriteMakefile(
NAME => 'Mytest',
VERSION_FROM => 'Mytest.pm'، # $VERSION را پیدا می کند
LIBS => ['']، # به عنوان مثال، '-lm'
DEFINE => ''، # برای مثال، "-DHAVE_SOMETHING"
INC => ''، # به عنوان مثال، '-I/usr/include/other'
);
فایل Mytest.pm باید با چیزی شبیه به این شروع شود:
بسته Mytest;
استفاده از 5.008008;
سخت استفاده کنید
استفاده از هشدارها؛
نیاز به صادرکننده
ما @ISA = qw (صادر کننده)؛
%EXPORT_TAGS ما = ( 'همه' => [ qw(
) ] )
@EXPORT_OK ما = ( @{ $EXPORT_TAGS{'all'} } );
صادرات @ ما = qw(
);
$VERSION ما = '0.01';
نیاز به XSLoader.
XSLoader::load('Mytest', $VERSION);
# روش های از پیش بارگذاری شده به اینجا بروید.
1;
__پایان__
# در زیر مقاله خرد مربوط به ماژول شما آمده است. تو بهتری
# ویرایشش کن
بقیه فایل .pm شامل کد نمونه برای ارائه مستندات برای
افزونه.
در نهایت، فایل Mytest.xs باید چیزی شبیه به این باشد:
#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#شامل "perl.h"
#include "XSUB.h"
#include "ppport.h"
MODULE = Mytest PACKAGE = Mytest
بیایید فایل .xs را با اضافه کردن این به انتهای فایل ویرایش کنیم:
از درجه اعتبار ساقط
سلام()
کد:
printf("سلام، دنیا!\n");
اشکالی ندارد که خطوطی که از خط "CODE:" شروع می شوند تورفتگی نداشته باشند. با این حال، برای
به منظور خوانایی، پیشنهاد می شود CODE: یک سطح و خطوط را تورفتگی کنید
دنبال کردن یک سطح دیگر
اکنون ""perl Makefile.PL" را اجرا می کنیم. این یک Makefile واقعی ایجاد می کند که نیازها را ایجاد می کند.
خروجی آن چیزی شبیه به این است:
% perl Makefile.PL
بررسی کامل بودن کیت شما...
به نظر خوب میاد
نوشتن Makefile برای Mytest
%
اکنون، اجرای make خروجی ای شبیه به این تولید می کند (برخی از خطوط طولانی دارند
برای وضوح کوتاه شده و برخی از خطوط اضافی حذف شده اند):
% می سازند
cp lib/Mytest.pm blib/lib/Mytest.pm
perl xsubpp -typemap typemap Mytest.xs > Mytest.xsc && \
mv Mytest.xsc Mytest.c
لطفاً رفتار نمونه سازی را برای Mytest.xs مشخص کنید (به کتابچه راهنمای perlxs مراجعه کنید)
cc -c Mytest.c
اجرای Mkbootstrap برای Mytest ()
chmod 644 Mytest.bs
rm -f blib/arch/auto/Mytest/Mytest.so
cc -shared -L/usr/local/lib Mytest.o -o blib/arch/auto/Mytest/Mytest.so
chmod 755 blib/arch/auto/Mytest/Mytest.so
cp Mytest.bs blib/arch/auto/Mytest/Mytest.bs
chmod 644 blib/arch/auto/Mytest/Mytest.bs
نمایش blib/man3/Mytest.3 بعد از ظهر
%
شما می توانید با خیال راحت خط مربوط به "رفتار نمونه سازی" را نادیده بگیرید - که در "The
نمونه های اولیه: کلمه کلیدی" در perlxs.
پرل روش خاص خود را برای نوشتن آسان اسکریپت های آزمایشی دارد، اما فقط برای این مثال،
ما اسکریپت آزمایشی خود را ایجاد خواهیم کرد. فایلی به نام hello بسازید که به شکل زیر باشد:
#! /opt/perl5/bin/perl
استفاده از ExtUtils::testlib;
از Mytest استفاده کنید.
Mytest::hello();
اکنون اسکریپت را قابل اجرا می کنیم ("chmod +x hello")، اسکریپت را اجرا می کنیم و باید
خروجی زیر:
٪ ./سلام
سلام دنیا!
%
مثال 2
حالا بیایید یک زیربرنامه را به پسوند خود اضافه کنیم که یک آرگومان عددی منفرد را به عنوان یک آرگومان در نظر می گیرد
وارد کرده و در صورت زوج بودن عدد 1 یا اگر عدد فرد است 0 برگردانید.
موارد زیر را به انتهای Mytest.xs اضافه کنید:
INT
is_even (ورودی)
ورودی int
کد:
RETVAL = (ورودی % 2 == 0)؛
خروجی:
RETVAL
در ابتدای خط "int input" نیازی نیست که فضای خالی وجود داشته باشد، اما اینطور است
برای بهبود خوانایی مفید است. قرار دادن نیم دونقطه در انتهای آن خط نیز می باشد
اختیاری. هر مقدار و نوع فضای خالی ممکن است بین ""int" و قرار گیرد
""ورودی"".
اکنون make را مجددا اجرا کنید تا کتابخانه مشترک جدید خود را بازسازی کنید.
حالا همان مراحل قبلی را انجام دهید و یک Makefile از فایل Makefile.PL ایجاد کنید و
در حال اجرا ساختن.
برای آزمایش اینکه پسوند ما کار می کند، اکنون باید به فایل Mytest.t نگاه کنیم. این
فایل برای تقلید از همان نوع ساختار آزمایشی تنظیم شده است که خود پرل دارد. در داخل
در اسکریپت تست، تعدادی آزمایش برای تایید رفتار برنامه افزودنی انجام می دهید،
چاپ "ok" زمانی که تست درست است، "not ok" زمانی که درست نیست.
استفاده از تست::تست های بیشتر => 4;
BEGIN { use_ok('Mytest') };
########################
# کد تست خود را در زیر وارد کنید، ماژول Test::More در اینجا استفاده می شود
# پس برای کمک به نوشتن این صفحه، صفحه مرد آن ( perldoc Test::More ) را بخوانید
# اسکریپت تست.
is(&Mytest::است_حتی(0)، 1);
is(&Mytest::است_حتی(1)، 0);
is(&Mytest::است_حتی(2)، 1);
ما اسکریپت تست را از طریق دستور "make test" فراخوانی خواهیم کرد. باید ببینی
خروجی که چیزی شبیه به این است:
% ساختن تست
PERL_DL_NONLAZY=1 /usr/bin/perl "-MExtUtils::Command::MM" "-e"
"test_harness(0، 'blib/lib'، 'blib/arch')" t/*.t
t/Mytest .... باشه
تمام تست ها با موفقیت
فایلها=1، تستها=4، 0 ثانیه ساعت دیواری (0.03 cusr + 0.00 csys = 0.03 CPU)
%
چی است رفته بر؟
برنامه h2xs نقطه شروع ایجاد برنامه های افزودنی است. در مثال های بعدی خواهیم گفت
ببینید چگونه میتوانیم از h2xs برای خواندن فایلهای هدر و تولید الگوهایی برای اتصال به C استفاده کنیم
کارهای روزمره.
h2xs تعدادی فایل را در فهرست برنامه افزودنی ایجاد می کند. فایل Makefile.PL یک پرل است
اسکریپتی که یک Makefile واقعی برای ساخت پسوند ایجاد می کند. نزدیک تر می کنیم
بعدا نگاهش کن
فایلهای pm. و xs. حاوی محتوای پسوند هستند. فایل xs C را نگه می دارد
روال هایی که پسوند را تشکیل می دهند. فایل .pm شامل روال هایی است که به پرل می گویند چگونه این کار را انجام دهد
برنامه افزودنی خود را بارگیری کنید.
با تولید Makefile و اجرای "make" دایرکتوری به نام blib (که ایستاده است
برای "build library") در فهرست کاری فعلی. این دایرکتوری حاوی
کتابخانه مشترکی که ما خواهیم ساخت. وقتی آن را آزمایش کردیم، می توانیم آن را در آن نصب کنیم
مکان نهایی
فراخوانی اسکریپت تست از طریق ""ساخت تست"" کار بسیار مهمی انجام داد. پرل را فراخوانی کرد
با تمام آن آرگومان های "-I" تا بتواند فایل های مختلفی را که بخشی از آن هستند پیدا کند
افزونه. این است بسیار مهم است که در حالی که هنوز در حال آزمایش افزونه هایی هستید که استفاده می کنید
""آزمون درست کن"". اگر سعی کنید اسکریپت تست را به تنهایی اجرا کنید، یک نتیجه مرگبار دریافت خواهید کرد
خطا یکی دیگر از دلایل مهم استفاده از "make test" برای اجرای اسکریپت تست است
که اگر در حال آزمایش ارتقاء به یک نسخه از قبل موجود هستید، از ""make test" استفاده کنید.
تضمین می کند که افزونه جدید خود را آزمایش خواهید کرد، نه نسخه موجود.
وقتی Perl یک "use extension;" را میبیند، فایلی را با همان نام جستجو میکند
پسوند pm "استفاده کنید". اگر آن فایل پیدا نشد، پرل با a می میرد
خطای مرگبار مسیر جستجوی پیش فرض در آرایه @INC موجود است.
در مورد ما، Mytest.pm به perl میگوید که به صادرکننده و Dynamic Loader نیاز دارد
پسوندها سپس آرایه های @ISA و @EXPORT و اسکالر $VERSION را تنظیم می کند. در نهایت آن را
به پرل می گوید که ماژول را بوت استرپ کند. پرل روتین لودر پویا خود را فراخوانی می کند (اگر وجود داشته باشد
یک است) و کتابخانه مشترک را بارگیری کنید.
دو آرایه @ISA و @EXPORT بسیار مهم هستند. آرایه @ISA حاوی لیستی از
بستههای دیگری که در آنها میتوان روشها (یا زیرروالهایی) را جستجو کرد که در آن وجود ندارند
بسته فعلی. این معمولاً فقط برای پسوندهای شی گرا مهم است (که ما
بعداً در مورد آن صحبت خواهد شد)، و بنابراین معمولاً نیازی به اصلاح نیست.
آرایه @EXPORT به پرل می گوید که کدام یک از متغیرها و زیرروال های برنامه افزودنی باید باشد
در فضای نام بسته تماس قرار می گیرد. زیرا نمی دانید که کاربر دارد یا خیر
قبلاً از نام متغیرها و زیربرنامه های خود استفاده کرده اید، بسیار مهم است که دقت کنید
انتخاب کنید چه چیزی صادر شود. انجام دادن نه روش صادرات یا نام متغیرها by به طور پیش فرض بدون خوب
دلیل.
به عنوان یک قاعده کلی، اگر ماژول سعی می کند شی گرا باشد، صادرات نکنید
هر چیزی. اگر فقط مجموعه ای از توابع و متغیرها باشد، می توانید آنها را صادر کنید
از طریق آرایه دیگری به نام @EXPORT_OK. این آرایه به طور خودکار خود را قرار نمی دهد
نام های زیر روال و متغیرها در فضای نام، مگر اینکه کاربر به طور خاص درخواست کند
که این کار انجام شود
برای اطلاعات بیشتر به perlmod مراجعه کنید.
متغیر $VERSION برای اطمینان از اینکه فایل .pm و کتابخانه مشترک "in" هستند استفاده می شود
با یکدیگر همگام سازی کنید. هر زمان که در فایل های pm. یا .xs تغییراتی ایجاد می کنید، باید
مقدار این متغیر را افزایش دهید.
نوشته خوب آزمون اسکریپت
اهمیت نوشتن اسکریپت های تست خوب را نمی توان بیش از حد مورد تاکید قرار داد. شما باید از نزدیک
از سبک "ok/not ok" که خود پرل استفاده می کند پیروی کنید تا خیلی راحت و آسان باشد
بدون ابهام برای تعیین نتیجه هر مورد آزمایشی. وقتی باگ را پیدا کردید و آن را برطرف کردید، درست کنید
حتماً یک مورد آزمایشی برای آن اضافه کنید.
با اجرای ""make test"، مطمئن می شوید که اسکریپت Mytest.t شما اجرا می شود و از درستی استفاده می کند
نسخه افزونه شما اگر موارد تست زیادی دارید، فایل های آزمایشی خود را در "t" ذخیره کنید.
دایرکتوری و از پسوند ".t" استفاده کنید. وقتی ""make test" را اجرا می کنید، همه این فایل های آزمایشی را اجرا می کنید
اعدام خواهد شد
مثال 3
پسوند سوم ما یک آرگومان را به عنوان ورودی می گیرد، آن مقدار را گرد کرده و مقدار را تنظیم می کند
استدلال به مقدار گرد شده
موارد زیر را به انتهای Mytest.xs اضافه کنید:
از درجه اعتبار ساقط
گرد (ارگ)
دو آرگ
کد:
if (arg > 0.0) {
arg = طبقه (arg + 0.5)؛
} else if (arg < 0.0) {
arg = سقف (arg - 0.5)؛
} دیگری {
arg = 0.0;
}
خروجی:
ارگ
فایل Makefile.PL را به گونه ای ویرایش کنید که خط مربوطه به شکل زیر باشد:
'LIBS' => ['-lm']، # به عنوان مثال، '-lm'
Makefile را تولید کرده و make را اجرا کنید. شماره تست را در Mytest.t به "9" تغییر دهید و آن را اضافه کنید
تست های زیر:
$i = -1.5; &Mytest::round($i); is( $i, -2.0 );
$i = -1.1; &Mytest::round($i); is( $i, -1.0 );
$i = 0.0; &Mytest::round($i); is($i، 0.0)؛
$i = 0.5; &Mytest::round($i); is($i، 1.0)؛
$i = 1.2; &Mytest::round($i); is($i، 1.0)؛
در حال اجرا ""ساخت تست"" اکنون باید چاپ شود که هر XNUMX تست اوکی هستند.
توجه داشته باشید که در این موارد آزمایشی جدید، آرگومان منتقل شده به دور یک متغیر اسکالر بود.
ممکن است از خود بپرسید که آیا می توانید یک ثابت یا تحت اللفظی را گرد کنید. تا ببینیم چه می شود،
خط زیر را به طور موقت به Mytest.t اضافه کنید:
&Mytest::دور(3)؛
""make test"" را اجرا کنید و متوجه شوید که پرل با یک خطای مهلک می میرد. پرل به شما اجازه تغییر نمی دهد
مقدار ثابت ها!
چه خبر جدید اینجا؟
· ما تغییراتی در Makefile.PL ایجاد کرده ایم. در این مورد، ما یک مورد اضافی را مشخص کرده ایم
کتابخانه به کتابخانه مشترک برنامه افزودنی پیوند داده شود، کتابخانه ریاضی libm in
این مورد. بعداً در مورد نحوه نوشتن XSUB هایی که می توانند هر روتین را در یک فراخوانی کنند صحبت خواهیم کرد
کتابخانه
· مقدار تابع به عنوان مقدار بازگشتی تابع پس داده نمی شود، اما
با تغییر مقدار متغیری که به تابع داده شده است. شما ممکن است
حدس زدید که وقتی دیدید که مقدار برگشتی round از نوع "void" است.
ورودی و تولید پارامترهای
شما پارامترهایی را مشخص می کنید که در خط(های) بعد از شما به XSUB ارسال می شود
مقدار و نام بازگشتی تابع را اعلام کنید. هر خط پارامتر ورودی با شروع می شود
فضای سفید اختیاری، و ممکن است یک نقطه ویرگول پایانی اختیاری داشته باشد.
لیست پارامترهای خروجی در انتهای تابع، درست بعد از آن رخ می دهد
OUTPUT: دستورالعمل. استفاده از RETVAL به پرل می گوید که می خواهید این مقدار را به عنوان بازگردانید
مقدار بازگشتی تابع XSUB. در مثال 3، ما می خواستیم "مقدار بازگشتی" قرار داده شود
در متغیر اصلی که در آن پاس دادیم، بنابراین آن را (و نه RETVAL) را در فهرست قرار دادیم
OUTPUT: بخش.
La XSUBPP برنامه
La xsubpp برنامه کد XS را در فایل xs می گیرد و آن را به کد C ترجمه می کند.
قرار دادن آن در فایلی که پسوند آن .c است. کد C ایجاد شده به شدت از C استفاده می کند
توابع در پرل.
La TYPEMAP پرونده
La xsubpp این برنامه از قوانینی برای تبدیل انواع داده های پرل (اسکالر، آرایه و غیره) به آن استفاده می کند
انواع داده های C (int، char، و غیره). این قوانین در فایل typemap ذخیره می شوند
($PERLLIB/ExtUtils/typemap). یک بحث مختصر در زیر وجود دارد، اما همه چیز ناخوشایند
جزئیات را می توان در perlxstypemap یافت. اگر نسخه جدید به اندازه کافی پرل دارید (5.16 و
بالا) یا یک کامپایلر XS ارتقا یافته ("ExtUtils::ParseXS" 3.13_01 یا بهتر)، سپس می توانید
به جای نوشتن فایل های جداگانه، تایپ های درون خطی را در XS خود تهیه کنید. در هر صورت، این نوع نقشه
چیز به سه قسمت تقسیم می شود:
بخش اول انواع مختلف داده های C را به یک نام ترسیم می کند که تا حدودی با آن مطابقت دارد
انواع پرل بخش دوم شامل کد C است که xsubpp برای مدیریت ورودی استفاده می کند
مولفه های. بخش سوم شامل کد C است که xsubpp برای رسیدگی به خروجی استفاده می کند
پارامترها.
بیایید نگاهی به بخشی از فایل c. ایجاد شده برای پسوند ما بیاندازیم. نام فایل است
Mytest.c:
XS (XS_Mytest_round)
{
dXSARGS;
اگر (موارد != 1)
Perl_croak(aTHX_ "استفاده: Mytest::round(arg)");
PERL_UNUSED_VAR(cv)؛ /* -W */
{
آرگ دو برابر = (دو برابر)SvNV(ST(0))؛ /* XXXX */
if (arg > 0.0) {
arg = طبقه (arg + 0.5)؛
} else if (arg < 0.0) {
arg = سقف (arg - 0.5)؛
} دیگری {
arg = 0.0;
}
sv_setnv(ST(0)، (دو) ارگ)؛ /* XXXX */
SvSETMAGIC(ST(0))؛
}
XSRETURN_EMPTY؛
}
به دو خط کامنت شده با "XXXX" توجه کنید. اگر قسمت اول تایپ مپ را بررسی کنید
فایل (یا بخش)، خواهید دید که دوبل ها از نوع T_DOUBLE هستند. در بخش INPUT از
typemap، یک آرگومان که T_DOUBLE است با فراخوانی به متغیر arg اختصاص داده می شود.
SvNV را روی چیزی معمول کنید، سپس آن را دو برابر کنید، سپس به متغیر arg اختصاص دهید.
به طور مشابه، در بخش OUTPUT، هنگامی که arg مقدار نهایی خود را بدست آورد، به قسمت ارسال می شود
تابع sv_setnv به زیر روال فراخوانی بازگردانده می شود. این دو تابع هستند
توضیح داده شده در perlguts; ما بعداً در مورد آن صحبت خواهیم کرد"ST(0)" به معنی در بخش است
در پشته آرگومان
هشدار در باره تولید استدلال
به طور کلی، نوشتن پسوندهایی که پارامترهای ورودی خود را تغییر می دهند، ایده خوبی نیست.
مانند مثال 3. در عوض، احتمالاً باید چندین مقدار را در یک آرایه برگردانید و اجازه دهید
تماس گیرنده آنها را مدیریت می کند (این کار را در مثال بعدی انجام خواهیم داد). با این حال، به منظور بهتر
فراخوانی روتین های C از قبل موجود را که اغلب پارامترهای ورودی خود را تغییر می دهند، تطبیق می دهند.
این رفتار قابل تحمل است
مثال 4
در این مثال، ما اکنون شروع به نوشتن XSUB هایی می کنیم که با C از پیش تعریف شده تعامل دارند
کتابخانه ها برای شروع، ما یک کتابخانه کوچک برای خودمان می سازیم، سپس اجازه می دهیم h2xs بنویسد
فایل های pm. و xs ما برای ما.
یک دایرکتوری جدید به نام Mytest2 در همان سطح دایرکتوری Mytest ایجاد کنید. در
دایرکتوری Mytest2، دایرکتوری دیگری به نام mylib ایجاد کنید و در آن دایرکتوری cd کنید.
در اینجا ما چند فایل ایجاد می کنیم که یک کتابخانه آزمایشی ایجاد می کند. این شامل یک C خواهد بود
فایل منبع و فایل هدر. ما همچنین یک Makefile.PL را در این فهرست ایجاد خواهیم کرد. سپس
ما مطمئن خواهیم شد که اجرای make در سطح Mytest2 به طور خودکار این را اجرا می کند
فایل Makefile.PL و Makefile حاصل.
در پوشه mylib، یک فایل mylib.h به شکل زیر ایجاد کنید:
#تعریف TESTVAL 4
extern double foo (int, long, const char*);
همچنین یک فایل mylib.c به شکل زیر ایجاد کنید:
#عبارتند از
#include "./mylib.h"
دو برابر
foo(int a، long b، const char *c)
{
بازگشت (a + b + atof(c) + TESTVAL)؛
}
و در نهایت یک فایل Makefile.PL ایجاد کنید که به شکل زیر است:
از ExtUtils::MakeMaker استفاده کنید.
$Verbose = 1;
WriteMakefile(
NAME => 'Mytest2::mylib'،
SKIP => [qw (همه static_lib dynamic_lib پویا)]،
پاک => {'FILES' => 'libmylib$(LIB_EXT)'}،
);
زیر من::top_targets {
'
همه :: استاتیک
pure_all :: استاتیک
ثابت :: libmylib$(LIB_EXT)
libmylib$(LIB_EXT): $(O_FILES)
$(AR) cr libmylib$(LIB_EXT) $(O_FILES)
$(RANLIB) libmylib$(LIB_EXT)
';
}
اطمینان حاصل کنید که از یک برگه استفاده می کنید نه از فاصله در خطوطی که با "$(AR)" و شروع می شوند
"$(RANLIB)". در صورت استفاده از فاصله، Make به درستی کار نخواهد کرد. نیز بوده است
گزارش داد که آرگومان "cr" به $(AR) در سیستم های Win32 غیر ضروری است.
اکنون فایلهای سطح بالای Mytest2 را ایجاد میکنیم. به دایرکتوری بالا تغییر دهید
Mytest2 و دستور زیر را اجرا کنید:
% h2xs -O -n Mytest2 ./Mytest2/mylib/mylib.h
این یک اخطار در مورد بازنویسی Mytest2 چاپ می کند، اما اشکالی ندارد. فایل های ما هستند
در Mytest2/mylib ذخیره شده و دست نخورده خواهد بود.
Makefile.PL معمولی که h2xs تولید می کند، از دایرکتوری mylib اطلاعی ندارد. ما
باید به آن بگوییم که یک زیر شاخه وجود دارد و ما یک کتابخانه در آن ایجاد خواهیم کرد
آی تی. بیایید آرگومان MYEXTLIB را به فراخوانی WriteMakefile اضافه کنیم تا شبیه به این شود:
WriteMakefile(
'NAME' => 'Mytest2'،
'VERSION_FROM' => 'Mytest2.pm'، # $VERSION را پیدا می کند
'LIBS' => [']، # به عنوان مثال، '-lm'
'DEFINE' => ''، # برای مثال، '-DHAVE_SOMETHING'
'INC' => ''، # به عنوان مثال، '-I/usr/include/other'
'MYEXTLIB' => 'mylib/libmylib$(LIB_EXT)'،
);
و سپس در پایان یک زیربرنامه اضافه کنید (که زیربرنامه از قبل موجود را لغو می کند).
به یاد داشته باشید که از یک کاراکتر تب برای تورفتگی خطی که با "cd" شروع می شود استفاده کنید!
زیر من::postamble {
'
$(MYEXTLIB): mylib/Makefile
سی دی mylib && $(MAKE) $(PASSTHRU)
';
}
بیایید فایل MANIFEST را نیز تصحیح کنیم تا محتویات ما را دقیقاً منعکس کند
افزونه. تنها خطی که می گوید "mylib" باید با سه مورد زیر جایگزین شود
خطوط:
mylib/Makefile.PL
mylib/mylib.c
mylib/mylib.h
برای اینکه فضای نام ما زیبا و بدون آلودگی باشد، فایل pm. را ویرایش کرده و متغیر را تغییر دهید
@EXPORT به @EXPORT_OK. در نهایت، در فایل xs، خط #include را برای خواندن ویرایش کنید:
#include "mylib/mylib.h"
و همچنین تعریف تابع زیر را به انتهای فایل xs اضافه کنید:
دو برابر
foo(a,b,c)
int a
طولانی ب
const char * c
خروجی:
RETVAL
اکنون ما همچنین باید یک تایپ مپ ایجاد کنیم زیرا Perl پیش فرض در حال حاضر پشتیبانی نمی کند
نوع "const char *". قبل از موارد فوق، بخش TYPEMAP جدیدی را در کد XS خود وارد کنید
عملکرد:
TYPEMAP: <
const char * T_PV
END
اکنون perl را در Makefile.PL سطح بالا اجرا کنید. توجه داشته باشید که یک Makefile نیز در آن ایجاد کرد
دایرکتوری mylib. make را اجرا کنید و ببینید که cd را در پوشه mylib وارد کرده و make را اجرا کنید
در آنجا نیز
اکنون اسکریپت Mytest2.t را ویرایش کنید و تعداد تست ها را به "4" تغییر دهید و موارد زیر را اضافه کنید
خطوط تا انتهای فیلمنامه:
is( &Mytest2::foo(1, 2, "سلام، دنیا!"), 7 );
is( &Mytest2::foo(1, 2, "0.0"), 7 );
ok( abs(&Mytest2::foo(0, 0, "-3.4") - 0.6) <= 0.01 );
(هنگامی که با مقایسه های ممیز شناور سر و کار دارید، بهتر است برابری را بررسی نکنید، اما
بلکه تفاوت بین نتیجه مورد انتظار و واقعی کمتر از حد معین باشد
مقدار (به نام اپسیلون) که در این مورد 0.01 است)
""make test"" را اجرا کنید و همه چیز خوب باشد. برخی از هشدارها در مورد آزمایشات از دست رفته برای این وجود دارد
پسوند Mytest2::mylib، اما می توانید آنها را نادیده بگیرید.
چی است اتفاق افتاده است اینجا؟
برخلاف نمونههای قبلی، ما اکنون h2xs را روی یک فایل شامل واقعی اجرا کردهایم. این باعث برخی شده است
چیزهای اضافی برای نمایش در هر دو فایل pm و xs.
· در فایل xs، یک دستور #include با مسیر مطلق به وجود دارد
فایل هدر mylib.h. ما این را به یک مسیر نسبی تغییر دادیم تا بتوانیم آن را جابجا کنیم
دایرکتوری افزونه اگر می خواستیم.
· اکنون تعدادی کد C جدید وجود دارد که به فایل xs. اضافه شده است. هدف از
روال "constant" ایجاد مقادیری است که در فایل هدر #define'd هستند
قابل دسترسی با اسکریپت Perl (با فراخوانی "TESTVAL" یا &Mytest2::TESTVAL).
همچنین مقداری کد XS وجود دارد که امکان تماسها را به روال "مستمر" میدهد.
· فایل pm. در ابتدا نام "TESTVAL" را در آرایه EXPORT @ صادر کرد. این می تواند
منجر به درگیری نام یک قانون سرانگشتی خوب این است که اگر #define قرار است باشد
استفاده شده توسط خود روتین C، و نه توسط کاربر، باید از آنها حذف شود
آرایه @EXPORT. متناوبا، اگر برایتان مهم نیست که از «نام کاملاً واجد شرایط» استفاده کنید
یک متغیر، میتوانید اکثر یا همه موارد را از آرایه @EXPORT به داخل آن منتقل کنید
آرایه @EXPORT_OK.
· اگر فایل شامل ما حاوی دستورات #include بود، اینها نبودند
پردازش شده توسط h2xs. در حال حاضر راه حل خوبی برای این موضوع وجود ندارد.
ما همچنین در مورد کتابخانه ای که در زیر شاخه mylib ساخته ایم به پرل گفته ایم. که
فقط نیاز به افزودن متغیر "MYEXTLIB" به فراخوانی WriteMakefile و
جایگزینی زیربرنامه postamble به cd در زیر شاخه و اجرای make.
Makefile.PL برای کتابخانه کمی پیچیده تر است، اما نه بیش از حد.
دوباره زیر روال postamble را جایگزین کردیم تا کد خود را وارد کنیم. این کد به سادگی
مشخص کرد که کتابخانه ای که در اینجا ایجاد می شود یک کتابخانه بایگانی ثابت است (برعکس
به یک کتابخانه قابل بارگذاری پویا) و دستورات ساخت آن را ارائه کرد.
تشریح of xs پرونده
فایل .xs "EXAMPLE 4" حاوی عناصر جدیدی بود. برای درک معنای
این عناصر، به خطی که خوانده می شود توجه کنید
MODULE = Mytest2 PACKAGE = Mytest2
هر چیزی قبل از این خط یک کد C ساده است که توضیح می دهد کدام سرصفحه ها را شامل شود و
برخی از توابع راحتی را تعریف می کند. به غیر از این قسمت هیچ ترجمه ای انجام نمی شود
از رد شدن اسناد POD جاسازی شده (به perlpod مراجعه کنید) به داخل می رود
فایل خروجی C را همانطور که هست ایجاد کرد.
هر چیزی بعد از این خط شرح عملکردهای XSUB است. این توصیفات هستند
ترجمه شده توسط xsubpp به کد C که این توابع را با استفاده از فراخوانی Perl پیاده سازی می کند
قراردادها، و باعث می شود که این توابع از مفسر پرل قابل مشاهده باشند.
به تابع "ثابت" توجه ویژه ای داشته باشید. این نام دو بار در
فایل xs تولید شده: یک بار در قسمت اول، به عنوان تابع C استاتیک، سپس بار دیگر در
قسمت دوم، زمانی که یک رابط XSUB برای این تابع C ثابت تعریف می شود.
این برای فایلهای xs کاملاً معمول است: معمولاً فایل xs یک رابط را برای یک فراهم میکند
تابع C موجود سپس این تابع C در جایی تعریف می شود (یا در یک خارجی
کتابخانه، یا در قسمت اول فایل xs.، و یک رابط Perl برای این تابع (یعنی
"چسب پرل") در قسمت دوم فایل xs توضیح داده شده است. وضعیت در "مثال 1"،
"مثال 2" و "مثال 3"، زمانی که تمام کارها در داخل "چسب پرل" انجام شود،
تا حدودی یک استثنا به جای قاعده.
گرفتن la چربی خارج of XSUB ها
در "مثال 4" قسمت دوم فایل .xs حاوی توضیحات زیر از یک XSUB است:
دو برابر
foo(a,b,c)
int a
طولانی ب
const char * c
خروجی:
RETVAL
توجه داشته باشید که برخلاف "EXAMPLE 1"، "EXAMPLE 2" و "EXAMPLE 3"، این توضیحات
شامل واقعی نیست رمز برای کاری که در حین فراخوانی تابع Perl انجام می شود فو (). به
درک کنید که اینجا چه خبر است، می توانید یک بخش CODE را به این XSUB اضافه کنید:
دو برابر
foo(a,b,c)
int a
طولانی ب
const char * c
کد:
RETVAL = foo(a,b,c);
خروجی:
RETVAL
با این حال، این دو XSUB کد C تولید شده تقریباً یکسان را ارائه می دهند: xsubpp کامپایلر است
به اندازه کافی هوشمند است که بخش "CODE:" را از دو خط اول توضیحات مشخص کند
از XSUB. در مورد بخش "OUTPUT:" چطور؟ در واقع، این کاملاً یکسان است! در
بخش "OUTPUT:" را نیز می توان حذف کرد، as بسیار as "کد:" بخش or "PPCODE:" بخش
مشخص نشده است: xsubpp می تواند ببیند که باید یک بخش فراخوانی تابع تولید کند و
بخش OUTPUT را نیز به طور خودکار تولید می کند. بنابراین میتوان XSUB را به صورت میانبر:
دو برابر
foo(a,b,c)
int a
طولانی ب
const char * c
آیا می توانیم همین کار را با XSUB انجام دهیم؟
INT
is_even (ورودی)
ورودی int
کد:
RETVAL = (ورودی % 2 == 0)؛
خروجی:
RETVAL
از "مثال 2"؟ برای انجام این کار، باید تابع C "int is_even(int input)" را تعریف کنیم.
همانطور که در "آناتومی فایل .xs" دیدیم، جای مناسب برای این تعریف در اول است
بخشی از فایل xs. در واقع یک تابع C
INT
is_even (int arg)
{
بازگشت (arg % 2 == 0);
}
احتمالاً برای این امر بیش از حد است. چیزی به سادگی "#define" نیز انجام خواهد شد:
#define is_even(arg) ((arg) % 2 == 0)
بعد از قرار دادن این قسمت در قسمت اول فایل xs، قسمت "Perl glue" به همین سادگی می شود.
INT
is_even (ورودی)
ورودی int
این تکنیک جداسازی قسمت چسب از قسمت اسب کار بدیهی است
معاوضه ها: اگر می خواهید رابط پرل را تغییر دهید، باید دو مکان را در خود تغییر دهید
کد با این حال، بسیاری از درهم و برهمی ها را از بین می برد و باعث می شود که قطعه کار از آن مستقل شود
ویژگی های خاص قرارداد فراخوانی پرل. (در واقع، هیچ چیز خاص پرل در آن وجود ندارد
توضیحات بالا، نسخه متفاوتی از xsubpp ممکن است این را به TCL ترجمه کرده باشد
چسب یا چسب پایتون نیز.)
بیشتر در باره XSUB استدلال
با تکمیل مثال 4، اکنون یک راه آسان برای شبیه سازی برخی از زندگی واقعی داریم
کتابخانههایی که رابطهایشان ممکن است تمیزترین در جهان نباشد. اکنون ادامه خواهیم داد
با بحث در مورد استدلال های ارائه شده به xsubpp گردآورنده
وقتی آرگومان هایی را برای روتین ها در فایل .xs مشخص می کنید، در واقع سه را پاس می کنید
اطلاعات برای هر آرگومان فهرست شده اولین قطعه ترتیب آن است
استدلال نسبت به دیگران (اول، دوم، و غیره). دوم نوع استدلال است،
و از نوع اعلان آرگومان (مانند int، char* و غیره) تشکیل شده است. سومین
piece قرارداد فراخوانی آرگومان در فراخوانی تابع کتابخانه است.
در حالی که پرل آرگومان ها را با مرجع به توابع ارسال می کند، C آرگومان ها را با مقدار ارسال می کند. به
یک تابع C را پیاده سازی کنید که داده های یکی از آرگومان ها، آرگومان واقعی را تغییر می دهد
این تابع C یک اشاره گر به داده خواهد بود. بنابراین دو تابع C با اعلان
int string_length(char *s);
int upper_case_char(char *cp);
ممکن است معنای کاملاً متفاوتی داشته باشد: اولین مورد ممکن است آرایه ای از کاراکترها را بررسی کند
با s نشان داده می شود، و دومی ممکن است بلافاصله "cp" را حذف کند و فقط *cp را دستکاری کند
(مثلاً با استفاده از مقدار بازگشتی به عنوان یک شاخص موفقیت). از پرل یکی از اینها استفاده می کند
به شیوه ای کاملا متفاوت عمل می کند.
یکی این اطلاعات را به xsubpp با جایگزین کردن "*" قبل از آرگومان با "&". "&" به معنای
که آرگومان باید با آدرس آن به یک تابع کتابخانه منتقل شود. دو مورد بالا
عملکرد ممکن است به عنوان XSUB ساخته شود
INT
طول(های) رشته
char * s
INT
upper_case_char (cp)
char & cp
برای مثال در نظر بگیرید:
INT
فو (الف، ب)
کاراکتر و الف
کاراکتر * ب
اولین آرگومان Perl برای این تابع به عنوان یک کاراکتر در نظر گرفته می شود و به آن اختصاص داده می شود
متغیر a، و آدرس آن به تابع foo منتقل می شود. پرل دوم
آرگومان به عنوان یک اشاره گر رشته ای در نظر گرفته می شود و به متغیر b اختصاص می یابد. در ارزش of
b به تابع foo منتقل می شود. تماس واقعی به تابع foo که xsubpp
تولیدات به شکل زیر خواهد بود:
foo(&a, b);
xsubpp لیست های آرگومان تابع زیر را به طور یکسان تجزیه می کند:
کاراکتر و الف
char&a
char & a
با این حال، برای کمک به درک آسان، پیشنهاد می شود که یک "&" را در کنار آن قرار دهید
نام متغیر و دور از نوع متغیر)، و یک "*" را در نزدیکی نوع متغیر قرار دهید،
اما دور از نام متغیر (مانند فراخوانی به foo در بالا). با انجام این کار، آسان است
دقیقاً درک کنید که چه چیزی به تابع C منتقل می شود. هر آنچه در آن باشد خواهد بود
"ستون آخر".
شما باید زحمت زیادی بکشید و سعی کنید تابع را به نوع متغیری که می خواهد منتقل کنید.
در صورت امکان در دراز مدت شما را از مشکلات زیادی نجات می دهد.
La استدلال پشته
اگر به هر یک از کدهای C تولید شده توسط هر یک از مثال ها به جز مثال 1 نگاه کنیم، شما
تعدادی از ارجاعات به ST(n) را مشاهده خواهد کرد، جایی که n معمولاً 0 است. "ST" در واقع a است
ماکرو که به آرگومان n در پشته آرگومان اشاره می کند. ST(0) بنابراین اولین است
آرگومان روی پشته و بنابراین اولین آرگومان به XSUB ارسال شد، ST(1) است
استدلال دوم و غیره.
وقتی آرگومان های XSUB را در فایل xs. فهرست می کنید، این نشان می دهد xsubpp کدام استدلال
مربوط به کدام یک از پشته آرگومان است (یعنی اولین مورد لیست شده اولین است
استدلال و غیره). اگر آنها را به همان ترتیب فهرست نکنید، فاجعه را دعوت می کنید
تابع از آنها انتظار دارد.
مقادیر واقعی روی پشته آرگومان نشانگر مقادیر ارسال شده در آن هستند
آرگومان به عنوان یک مقدار OUTPUT، مقدار متناظر آن در پشته (به عنوان مثال،
ST(0) اگر آرگومان اول بود) تغییر می کند. شما می توانید این را با نگاه کردن به C تأیید کنید
کد تولید شده برای مثال 3. کد برای گرد() روال XSUB شامل خطوطی است که
مانند این نگاه کنید:
آرگ دو برابر = (دو برابر)SvNV(ST(0))؛
/* محتویات متغیر arg را گرد کنید */
sv_setnv(ST(0)، (دو) ارگ)؛
متغیر arg در ابتدا با گرفتن مقدار از تنظیم می شود ST(0)، سپس دوباره در ذخیره می شود
ST(0) در پایان روال.
XSUB ها همچنین مجاز به بازگشت لیست هستند، نه فقط اسکالرها. این باید توسط
دستکاری مقادیر پشته ST(0) ST(1) و غیره، به روشی کاملاً متفاوت. perlxs را ببینید
جزئیات.
XSUB ها همچنین مجاز به جلوگیری از تبدیل خودکار آرگومان های تابع Perl به C هستند
آرگومان های تابع برای جزئیات بیشتر به perlxs مراجعه کنید. برخی افراد تبدیل دستی را ترجیح می دهند
بازرسی ST(i) حتی در مواردی که تبدیل خودکار انجام می شود، با این استدلال که این
منطق تماس XSUB را واضح تر می کند. برای مقایسه با "برداشتن چربی از XSUB".
یک مبادله مشابه از جداسازی کامل قطعات "چسب پرل" و "اسب کار" یک
XSUB.
در حالی که متخصصان ممکن است در مورد این اصطلاحات بحث کنند، یک مبتدی به پرل guts ممکن است راهی را ترجیح دهد
تا حد ممکن مختص Perl-guts است، به معنی تبدیل خودکار و خودکار
تولید تماس، مانند «دریافت چربی از XSUB». این رویکرد دارای ویژگی های اضافی است
مزایای محافظت از نویسنده XSUB در برابر تغییرات آینده در Perl API.
در حال گسترش خود را توسعه
گاهی اوقات ممکن است بخواهید چند روش اضافی یا برنامه های فرعی برای کمک به ساخت ارائه دهید
رابط بین Perl و برنامه افزودنی شما ساده تر یا قابل درک است. اینها
روال ها باید در فایل .pm زندگی کنند. این که آیا آنها به طور خودکار بارگذاری می شوند زمانی که
خود پسوند بارگیری می شود یا فقط زمانی که فراخوانی می شود بارگیری می شود بستگی به این دارد که در کجای فایل .pm قرار دارد
تعریف زیر روال قرار داده شده است. همچنین میتوانید با AutoLoader برای روشی جایگزین مشورت کنید
زیربرنامه های اضافی خود را ذخیره و بارگذاری کنید.
مستند سازی خود را توسعه
مطلقاً هیچ بهانه ای برای مستند نکردن پسوند شما وجود ندارد. اسناد متعلق است
در فایل pm. این فایل به pod2man ارسال می شود و مستندات جاسازی شده نیز خواهد بود
به فرمت manpage تبدیل می شود، سپس در فهرست blib قرار می گیرد. در آن کپی می شود
دایرکتوری manpage Perl هنگام نصب برنامه افزودنی.
شما می توانید اسناد و کد پرل را در فایل pm. پر کنید. در واقع اگر بخواهید
برای استفاده از روش بارگذاری خودکار، باید این کار را انجام دهید، همانطور که در کامنت داخل فایل pm توضیح داده شده است.
برای اطلاعات بیشتر در مورد قالب پاد به perlpod مراجعه کنید.
نصب و راه اندازی خود را توسعه
هنگامی که برنامه افزودنی شما کامل شد و تمام آزمایشات خود را پشت سر گذاشت، نصب آن بسیار ساده است:
شما به سادگی "make install" را اجرا کنید. شما یا باید مجوز نوشتن را داشته باشید
دایرکتوری هایی که Perl در آن نصب شده است، یا از مدیر سیستم خود بخواهید که make for را اجرا کند
شما خواهد شد.
متناوباً، میتوانید فهرست دقیقی را برای قرار دادن فایلهای پسوند با قرار دادن مشخص کنید
یک "PREFIX=/destination/directory" پس از نصب make (یا بین ساخت و
اگر نسخه مرگ مغزی از make دارید نصب کنید). اگر هستید این می تواند بسیار مفید باشد
ساخت یک افزونه که در نهایت به چندین سیستم توزیع می شود. تو می توانی
سپس فقط فایل ها را در دایرکتوری مقصد بایگانی کنید و آنها را در سایت خود توزیع کنید
سیستم های مقصد
مثال 5
در این مثال، ما کارهای بیشتری را با پشته آرگومان انجام خواهیم داد. نمونه های قبلی
همه فقط یک مقدار را برگردانده اند. اکنون یک پسوند ایجاد می کنیم که an را برمی گرداند
آرایه.
این پسوند بسیار یونیکس گرا است (struct statfs و statfs system call). اگر شما
در سیستم یونیکس اجرا نمی شوند، می توانید هر تابع دیگری را جایگزین statfs کنید
چندین مقدار را برمی گرداند، می توانید مقادیر سخت کدی را برای تماس گیرنده بازگردانید (اگرچه
آزمایش مورد خطا کمی سخت تر خواهد بود)، یا به سادگی نمی توانید این مثال را انجام دهید.
اگر XSUB را عوض می کنید، حتماً موارد تست را مطابق با تغییرات تعمیر کنید.
به دایرکتوری Mytest برگردید و کد زیر را به انتهای Mytest.xs اضافه کنید:
از درجه اعتبار ساقط
statfs (مسیر)
char * مسیر
INIT:
بین من
struct statfs buf;
PPCODE:
i = statfs(مسیر، &buf);
اگر (i == 0) {
XPUSHs(sv_2mortal(newSVnv(buf.f_bavail)));
XPUSHs(sv_2mortal(newSVnv(buf.f_bfree)));
XPUSHs(sv_2mortal(newSVnv(buf.f_blocks)));
XPUSHs(sv_2mortal(newSVnv(buf.f_bsize)));
XPUSHs(sv_2mortal(newSVnv(buf.f_free)));
XPUSHs(sv_2mortal(newSVnv(buf.f_files)));
XPUSHs(sv_2mortal(newSVnv(buf.f_type)));
} دیگری {
XPUSHs(sv_2mortal(newSVnv(errno)));
}
همچنین باید کد زیر را به بالای فایل xs. درست بعد از آن اضافه کنید
شامل "XSUB.h" است:
#عبارتند از
همچنین بخش کد زیر را به Mytest.t اضافه کنید و تست های "9" را به "11" افزایش دهید:
@a = &Mytest::statfs("/blech");
ok( scalar(@a) == 1 && $a[0] == 2 );
@a = &Mytest::statfs("/");
is( scalar(@a), 7 );
جدید اشیاء in این مثال
این مثال چند مفهوم جدید را اضافه کرد. ما آنها را یکی یکی می بریم.
· دستورالعمل INIT: حاوی کدی است که بلافاصله بعد از آرگومان قرار می گیرد
پشته رمزگشایی می شود. C به اعلان متغیرها در مکان های دلخواه اجازه نمی دهد
در داخل یک تابع، بنابراین این معمولا بهترین راه برای اعلام متغیرهای محلی مورد نیاز است
توسط XSUB (به طور متناوب، می توان کل بخش "PPCODE:" را در بریس ها قرار داد،
و این اعلامیه ها را در بالا قرار دهید.)
· این روال همچنین تعداد متفاوتی از آرگومان ها را بسته به موفقیت یا برمی گرداند
شکست تماس با statfs اگر خطایی وجود داشته باشد، شماره خطا به عنوان برگردانده می شود
یک آرایه تک عنصری اگر تماس با موفقیت انجام شود، یک آرایه 7 عنصری است
بازگشت. از آنجایی که تنها یک آرگومان به این تابع داده می شود، ما به اتاقی در آن نیاز داریم
پشته برای نگه داشتن 7 مقداری که ممکن است برگردانده شوند.
ما این کار را با استفاده از دستورالعمل PPCODE: به جای دستورالعمل CODE: انجام می دهیم. این
می گوید xsubpp که ما مقادیر بازگشتی را که بر روی قرار داده می شود مدیریت خواهیم کرد
پشته استدلال توسط خودمان.
· وقتی می خواهیم مقادیری را در پشته قرار دهیم تا به تماس گیرنده برگردانده شوند، از عبارت استفاده می کنیم
مجموعه ای از ماکروهایی که با "XPUSH" شروع می شوند. پنج نسخه مختلف وجود دارد، برای
قرار دادن اعداد صحیح، اعداد صحیح بدون علامت، دوبل ها، رشته ها و اسکالرهای پرل در پشته.
در مثال ما، یک اسکالر پرل را روی پشته قرار دادیم. (در واقع این تنها است
ماکرو که می تواند برای برگرداندن چندین مقدار استفاده شود.)
ماکروهای XPUSH* به طور خودکار پشته بازگشتی را گسترش می دهند تا از وجود آن جلوگیری کنند
بیش از حد. شما مقادیر را به ترتیبی که میخواهید توسط آنها دیده شود به پشته فشار میدهید
برنامه تماس
· مقادیر فشار داده شده بر روی پشته برگشتی XSUB در واقع مقادیر SV فانی هستند. آنها
فانی ساخته می شوند به طوری که وقتی مقادیر توسط برنامه فراخوان کپی می شوند، SV ها
که مقادیر برگردانده شده را نگه می دارد، می توان آن را توزیع کرد. اگر آنها فانی نبودند، پس آنها بودند
پس از بازگشت روتین XSUB همچنان وجود خواهد داشت، اما قابل دسترسی نخواهد بود.
این یک نشت حافظه است.
· اگر به عملکرد علاقه مند بودیم، نه به فشردگی کد، در شاخه موفقیت
ما از ماکروهای "XPUSH" استفاده نمی کنیم، بلکه از ماکروهای "PUSH" استفاده می کنیم و پشته را از قبل گسترش می دهیم.
قبل از فشار دادن مقادیر بازگشتی:
EXTEND(SP, 7);
مبادله این است که فرد باید تعداد مقادیر بازگشتی را از قبل محاسبه کند
(اگرچه گسترش بیش از حد پشته معمولاً به چیزی جز حافظه آسیب نمی رساند
مصرف).
به طور مشابه، در شاخه شکست می توانیم از "PUSHs" استفاده کنیم. بدون گسترش پشته: the
مرجع تابع Perl به یک XSUB در پشته می آید، بنابراین پشته است همیشه بزرگ
برای گرفتن یک مقدار بازگشتی کافی است.
مثال 6
در این مثال، ارجاع به یک آرایه را به عنوان پارامتر ورودی می پذیریم و برمی گردانیم
ارجاع به آرایه ای از هش ها. این دستکاری پرل پیچیده را نشان می دهد
انواع داده از یک XSUB
این پسوند تا حدودی ساختگی است. این بر اساس کد در مثال قبلی است.
تابع statfs را چندین بار فراخوانی می کند و ارجاع به آرایه ای را می پذیرد
نام فایل ها به عنوان ورودی، و بازگرداندن یک مرجع به آرایه ای از هش های حاوی داده ها
برای هر یک از سیستم های فایل
به دایرکتوری Mytest برگردید و کد زیر را به انتهای Mytest.xs اضافه کنید:
SV *
multi_statfs (مسیرها)
مسیرهای SV *
INIT:
نتایج AV *
SSize_t numpaths = 0, n;
بین من
struct statfs buf;
SvGETMAGIC (مسیرها)؛
اگر ((!SvROK(مسیرها))
|| (SvTYPE(SvRV(مسیرها)) != SVt_PVAV)
|| ((numpaths = av_top_index((AV *)SvRV(مسیرها))) < 0))
{
XSRETURN_UNDEF؛
}
نتایج = (AV *)sv_2mortal((SV *)newAV());
کد:
برای (n = 0; n <= numpaths; n++) {
HV * rh;
STRLEN l;
char * fn = SvPV(*av_fetch((AV *)SvRV(مسیرها)، n، 0)، l);
i = statfs(fn، &buf);
اگر (i != 0) {
av_push(نتایج، newSVnv(errno));
ادامه هید؛
}
rh = (HV *)sv_2mortal((SV *)newHV());
hv_store(rh، "f_bavail"، 8، newSVnv(buf.f_bavail)، 0);
hv_store(rh، "f_bfree"، 7، newSVnv(buf.f_bfree)، 0);
hv_store(rh، "f_blocks"، 8، newSVnv(buf.f_blocks)، 0);
hv_store(rh، "f_bsize"، 7، newSVnv(buf.f_bsize)، 0);
hv_store(rh، "f_ffree"، 7، newSVnv(buf.f_ffree)، 0);
hv_store(rh، "f_files"، 7، newSVnv(buf.f_files)، 0);
hv_store(rh، "f_type"، 6، newSVnv(buf.f_type)، 0);
av_push(نتایج، newRV((SV *)rh));
}
RETVAL = newRV((SV *)نتایج);
خروجی:
RETVAL
و کد زیر را به Mytest.t اضافه کنید، در حالی که تست های "11" را به "13" افزایش دهید:
$results = Mytest::multi_statfs([ '/', '/blech' ]);
ok( ref $results->[0] );
ok(! ref $results->[1]);
جدید اشیاء in این مثال
تعدادی از مفاهیم جدید در اینجا معرفی شده است که در زیر توضیح داده شده است:
· این تابع از نقشه نوع استفاده نمی کند. در عوض، آن را به عنوان پذیرش یک SV* اعلام می کنیم
پارامتر (اسکالر)، و یک مقدار SV* را برمی گرداند، و ما از پر کردن آنها مراقبت می کنیم
اسکالرهای درون کد از آنجایی که ما فقط یک مقدار را برمی گردانیم، نیازی به a نداریم
دستورالعمل "PPCODE:" - به جای آن، از دستورالعمل های "CODE:" و "OUTPUT:" استفاده می کنیم.
· هنگام برخورد با مراجع، مهم است که با احتیاط با آنها برخورد کنید. در
بلوک "INIT:" ابتدا SvGETMAGIC(مسیرها) را فرا می خواند، در صورتی که مسیرها یک متغیر گره خورده باشند. سپس
بررسی می کند که "SvROK" true را برمی گرداند، که نشان می دهد مسیرها یک مرجع معتبر است.
(به سادگی علامت زدن "SvROK" FETCH را روی یک متغیر گره خورده فعال نمی کند.) سپس تأیید می کند.
اینکه شی مورد اشاره توسط مسیرها یک آرایه است که از "SvRV" برای ارجاع دادن به مسیرها استفاده می کند.
و "SvTYPE" را برای کشف نوع آن. به عنوان یک آزمایش اضافه، آن آرایه را بررسی می کند
با استفاده از تابع "av_top_index" (که -1 را برمی گرداند، غیر خالی است.
اگر آرایه خالی باشد). ماکرو XSRETURN_UNDEF برای لغو XSUB و بازگشت استفاده می شود
مقدار نامشخص زمانی که هر سه این شرایط برآورده نشدند.
ما چندین آرایه را در این XSUB دستکاری می کنیم. توجه داشته باشید که یک آرایه نشان داده شده است
داخلی توسط یک اشاره گر AV*. توابع و ماکروها برای دستکاری آرایه ها هستند
مشابه توابع پرل: "av_top_index" بالاترین شاخص را در AV* برمی گرداند،
بسیار شبیه $#array; "av_fetch" با توجه به آرایه، یک مقدار اسکالر واحد را واکشی می کند
فهرست مطالب؛ "av_push" یک مقدار اسکالر را به طور خودکار به انتهای آرایه فشار می دهد
گسترش آرایه در صورت لزوم
به طور خاص، نام مسیرها را یکی یکی از آرایه ورودی می خوانیم و آن را ذخیره می کنیم
منجر به یک آرایه خروجی (نتایج) به همان ترتیب می شود. اگر statfs با شکست مواجه شد، عنصر
در آرایه بازگشتی، مقدار errno پس از شکست است. اگر statfs
موفق می شود، هرچند، مقداری که روی آرایه بازگشتی فشار داده می شود، ارجاع به هش است
حاوی برخی از اطلاعات در ساختار statfs.
مانند پشته بازگشتی، ممکن است (و یک برد عملکرد کوچک) قبل از
آرایه بازگشتی را قبل از فشار دادن داده به آن گسترش دهید، زیرا می دانیم چند عنصر
ما بر میگردیم:
av_extend(نتایج، numpaths)؛
· ما فقط یک عملیات هش را در این تابع انجام می دهیم که ذخیره سازی جدید است
اسکالر زیر یک کلید با استفاده از "hv_store". یک هش با یک نشانگر HV* نشان داده می شود. پسندیدن
آرایه ها، توابع برای دستکاری هش از یک XSUB عملکرد را منعکس می کند
موجود از پرل. برای جزئیات بیشتر به perlguts و perlapi مراجعه کنید.
· برای ایجاد یک مرجع، از تابع "newRV" استفاده می کنیم. توجه داشته باشید که می توانید AV* یا
یک HV* برای تایپ SV* در این مورد (و بسیاری موارد دیگر). این به شما امکان میدهد تا ارجاع دهید
به آرایه ها، هش ها و اسکالرها با عملکرد یکسان. برعکس، تابع "SvRV".
همیشه یک SV* را برمیگرداند که در صورت وجود، ممکن است نیاز باشد به نوع مناسب ارسال شود
چیزی غیر از اسکالر (با "SvTYPE" بررسی کنید).
· در این مرحله، xsubpp کار بسیار کمی انجام می دهد - تفاوت بین Mytest.xs
و Mytest.c حداقل هستند.
مثال 7 (آینده به زودی)
XPUSH args و RETVAL را تنظیم کنید و مقدار بازگشتی را به آرایه اختصاص دهید
مثال 8 (آینده به زودی)
تنظیم $!
مثال 9 عبور باز کن فایل ها به XSes
شما فکر می کنید که ارسال فایل ها به XS دشوار است، با تمام تایپ گلوب ها و چیزهای دیگر.
خوب، اینطور نیست.
فرض کنید به دلایلی عجیب به یک بسته بندی در اطراف کتابخانه استاندارد C نیاز داریم
تابع "fputs()". این تمام چیزی است که ما نیاز داریم:
#define PERLIO_NOT_STDIO 0
#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#شامل "perl.h"
#include "XSUB.h"
#عبارتند از
INT
fputs (ها، جریان)
char * s
FILE * جریان
کار واقعی در تایپ مپ استاندارد انجام می شود.
اما شما تمام کارهای خوب انجام شده توسط لایه های perlio را از دست می دهید. این تابع stdio را فراخوانی می کند
"fputs()" که چیزی در مورد آنها نمی داند.
نوع استاندارد سه نوع PerlIO * را ارائه می دهد: "InputStream" (T_IN)،
"InOutStream" (T_INOUT) و "OutputStream" (T_OUT). یک "PerlIO *" خالی در نظر گرفته می شود
T_INOUT. اگر در کد شما مهم است (برای اینکه چرا ممکن است به زیر مراجعه کنید) یک #define یا تایپ کنید
نام های خاص را انتخاب کنید و از آن به عنوان آرگومان یا نتیجه در فایل XS خود استفاده کنید.
تایپ مپ استاندارد شامل PerlIO * قبل از perl 5.7 نیست، اما این سه مورد را دارد
انواع جریان استفاده از PerlIO * به طور مستقیم سازگار با عقب نیست مگر اینکه شما ارائه دهید
تایپ مپ خودت
برای جریان های در حال آمدن از جانب perl تفاوت اصلی این است که "OutputStream" دریافت خواهد کرد
خروجی PerlIO * - که ممکن است در یک سوکت تفاوت ایجاد کند. مانند مثال ما ...
برای جریان های در حال تحویل به perl یک دسته فایل جدید ایجاد می شود (یعنی ارجاع به فایل جدید
glob) و مرتبط با PerlIO * ارائه شده است. اگر حالت خواندن/نوشتن PerlIO *
درست نیست، پس ممکن است از زمانی که از دسته فایل استفاده می شود، خطاها یا هشدارهایی دریافت کنید. بنابراین
اگر PerlIO * را به صورت "w" باز کردید، اگر به صورت "r" باز شود، واقعاً باید یک "OutputStream" باشد.
باید یک "InputStream" باشد.
حال فرض کنید می خواهید از لایه های perlio در XS خود استفاده کنید. ما از پرلیو استفاده خواهیم کرد
عملکرد "PerlIO_puts()" به عنوان مثال.
در قسمت C از فایل XS (بالای خط اول MODULE) شما دارید
#define OutputStream PerlIO *
or
typedef PerlIO * OutputStream;
و این هم کد XS:
INT
پرلیوپوت (ها، جریان)
char * s
جریان خروجی
کد:
RETVAL = PerlIO_puts(stream, s);
خروجی:
RETVAL
ما باید از بخش "CODE" استفاده کنیم زیرا "PerlIO_puts()" آرگومان ها را معکوس کرده است.
در مقایسه با "fputs()"، و ما می خواهیم آرگومان ها را ثابت نگه داریم.
برای بررسی کامل این موضوع، میخواهیم از stdio "fputs()" در PerlIO * استفاده کنیم. این
یعنی باید از سیستم perlio یک stdio "FILE *" بخواهیم:
INT
perliofputs (ها، جریان)
char * s
جریان خروجی
PREINIT:
FILE *fp = PerlIO_findFILE(stream);
کد:
if (fp != (FILE*) 0) {
RETVAL = fputs (s, fp)؛
} دیگری {
RETVAL = -1;
}
خروجی:
RETVAL
توجه: "PerlIO_findFILE()" لایه ها را برای یک لایه stdio جستجو می کند. اگر نتواند یکی را پیدا کند،
"PerlIO_exportFILE()" را برای ایجاد یک stdio جدید "FILE" فراخوانی می کند. لطفا فقط تماس بگیرید
"PerlIO_exportFILE()" اگر می خواهید یک جدید "فایل". این یک در هر تماس و فشار ایجاد می کند
یک لایه stdio جدید بنابراین آن را به طور مکرر در یک فایل صدا نکنید. "PerlIO_findFILE()" خواهد شد
لایه stdio را زمانی که توسط "PerlIO_exportFILE() تولید شد، بازیابی کنید.
این فقط برای سیستم پرلیو صدق می کند. برای نسخه های قبل از 5.7، "PerlIO_exportFILE()" است
معادل "PerlIO_findFILE()".
عیب یابی اینها مثال ها
همانطور که در بالای این سند ذکر شد، اگر با این مثال مشکل دارید
برنامه های افزودنی، ممکن است ببینید آیا هر یک از این موارد به شما کمک می کند یا خیر.
· در نسخه های 5.002 قبل از نسخه گاما، اسکریپت آزمایشی در مثال 1 نخواهد بود.
به درستی عمل کند برای خواندن باید خط "use lib" را تغییر دهید:
استفاده از lib './blib';
· در نسخه های 5.002 قبل از نسخه 5.002b1h، فایل test.pl به طور خودکار نبود.
ایجاد شده توسط h2xs. این بدان معناست که برای اجرای اسکریپت تست نمی توانید بگویید "make test".
قبل از عبارت use extension باید خط زیر را اضافه کنید:
استفاده از lib './blib';
· در نسخه های 5.000 و 5.001، به جای استفاده از خط بالا، باید از
خط زیر:
BEGIN { unshift(@INC، "./blib") }
· این سند فرض می کند که فایل اجرایی با نام "perl" نسخه 5 پرل است
ممکن است سیستم ها نسخه 5 پرل را به عنوان "perl5" نصب کرده باشند.
دیدن همچنین
برای اطلاعات بیشتر با perlguts، perlapi، perlxs، perlmod و perlpod مشورت کنید.
نویسنده
جف اوکاموتو[ایمیل محافظت شده]>
بازبینی و دستیار دین روریچ، ایلیا زاخارویچ، آندریاس کونیگ و تیم بانس.
مطالب PerlIO توسط لوپ کریستوف، با توضیحاتی توسط نیک اینگ ارائه شده است.
سیمونز
تغییرات برای h2xs از Perl 5.8.x توسط Renee Baecker
نام تغییر کرد
2012-01-20
از perlxstut آنلاین با استفاده از خدمات onworks.net استفاده کنید