📄 perlxstut.1
字号:
However, for readability purposes, it is suggested that you indent \s-1CODE:\s0one level and the lines following one more level..PPNow we'll run "\f(CW\*(C`perl Makefile.PL\*(C'\fR". This will create a real Makefile,which make needs. Its output looks something like:.PP.Vb 5\& % perl Makefile.PL\& Checking if your kit is complete...\& Looks good\& Writing Makefile for Mytest\& %.Ve.PPNow, running make will produce output that looks something like this (somelong lines have been shortened for clarity and some extraneous lines havebeen deleted):.PP.Vb 10\& % make\& cp lib/Mytest.pm blib/lib/Mytest.pm\& perl xsubpp \-typemap typemap Mytest.xs > Mytest.xsc && mv Mytest.xsc Mytest.c\& Please specify prototyping behavior for Mytest.xs (see perlxs manual)\& cc \-c Mytest.c\& Running Mkbootstrap for 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 \e\& \e\&\& 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\& Manifying blib/man3/Mytest.3pm\& %.Ve.PPYou can safely ignore the line about \*(L"prototyping behavior\*(R" \- it isexplained in the section \*(L"The \s-1PROTOTYPES:\s0 Keyword\*(R" in perlxs..PPIf you are on a Win32 system, and the build process fails with linkererrors for functions in the C library, check if your Perl is configuredto use PerlCRT (running \fBperl \-V:libc\fR should show you if this is thecase). If Perl is configured to use PerlCRT, you have to make surePerlCRT.lib is copied to the same location that msvcrt.lib lives in,so that the compiler can find it on its own. msvcrt.lib is usuallyfound in the Visual C compiler's lib directory (e.g. C:/DevStudio/VC/lib)..PPPerl has its own special way of easily writing test scripts, but for thisexample only, we'll create our own test script. Create a file called hellothat looks like this:.PP.Vb 1\& #! /opt/perl5/bin/perl\&\& use ExtUtils::testlib;\&\& use Mytest;\&\& Mytest::hello();.Ve.PPNow we make the script executable (\f(CW\*(C`chmod +x hello\*(C'\fR), run the scriptand we should see the following output:.PP.Vb 3\& % ./hello\& Hello, world!\& %.Ve.Sh "\s-1EXAMPLE\s0 2".IX Subsection "EXAMPLE 2"Now let's add to our extension a subroutine that will take a single numericargument as input and return 0 if the number is even or 1 if the numberis odd..PPAdd the following to the end of Mytest.xs:.PP.Vb 7\& int\& is_even(input)\& int input\& CODE:\& RETVAL = (input % 2 == 0);\& OUTPUT:\& RETVAL.Ve.PPThere does not need to be whitespace at the start of the "\f(CW\*(C`int input\*(C'\fR\*(L"line, but it is useful for improving readability. Placing a semi-colon atthe end of that line is also optional. Any amount and kind of whitespacemay be placed between the \*(R"\f(CW\*(C`int\*(C'\fR\*(L" and \*(R"\f(CW\*(C`input\*(C'\fR"..PPNow re-run make to rebuild our new shared library..PPNow perform the same steps as before, generating a Makefile from theMakefile.PL file, and running make..PPIn order to test that our extension works, we now need to look at thefile Mytest.t. This file is set up to imitate the same kind of testingstructure that Perl itself has. Within the test script, you perform anumber of tests to confirm the behavior of the extension, printing \*(L"ok\*(R"when the test is correct, \*(L"not ok\*(R" when it is not..PP.Vb 2\& use Test::More tests => 4;\& BEGIN { use_ok(\*(AqMytest\*(Aq) };\&\& #########################\&\& # Insert your test code below, the Test::More module is use()ed here so read\& # its man page ( perldoc Test::More ) for help writing this test script.\&\& is(&Mytest::is_even(0), 1);\& is(&Mytest::is_even(1), 0);\& is(&Mytest::is_even(2), 1);.Ve.PPWe will be calling the test script through the command "\f(CW\*(C`make test\*(C'\fR". Youshould see output that looks something like this:.PP.Vb 6\& %make test\& PERL_DL_NONLAZY=1 /usr/bin/perl "\-MExtUtils::Command::MM" "\-e" "test_harness(0, \*(Aqblib/lib\*(Aq, \*(Aqblib/arch\*(Aq)" t/*.t\& t/Mytest....ok\& All tests successful.\& Files=1, Tests=4, 0 wallclock secs ( 0.03 cusr + 0.00 csys = 0.03 CPU)\& %.Ve.Sh "What has gone on?".IX Subsection "What has gone on?"The program h2xs is the starting point for creating extensions. In laterexamples we'll see how we can use h2xs to read header files and generatetemplates to connect to C routines..PPh2xs creates a number of files in the extension directory. The fileMakefile.PL is a perl script which will generate a true Makefile to buildthe extension. We'll take a closer look at it later..PPThe .pm and .xs files contain the meat of the extension. The .xs file holdsthe C routines that make up the extension. The .pm file contains routinesthat tell Perl how to load your extension..PPGenerating the Makefile and running \f(CW\*(C`make\*(C'\fR created a directory called blib(which stands for \*(L"build library\*(R") in the current working directory. Thisdirectory will contain the shared library that we will build. Once we havetested it, we can install it into its final location..PPInvoking the test script via "\f(CW\*(C`make test\*(C'\fR" did something very important.It invoked perl with all those \f(CW\*(C`\-I\*(C'\fR arguments so that it could find thevarious files that are part of the extension. It is \fIvery\fR important thatwhile you are still testing extensions that you use "\f(CW\*(C`make test\*(C'\fR\*(L". If youtry to run the test script all by itself, you will get a fatal error.Another reason it is important to use \*(R"\f(CW\*(C`make test\*(C'\fR\*(L" to run your testscript is that if you are testing an upgrade to an already-existing version,using \*(R"\f(CW\*(C`make test\*(C'\fR" ensures that you will test your new extension, not thealready-existing version..PPWhen Perl sees a \f(CW\*(C`use extension;\*(C'\fR, it searches for a file with the same nameas the \f(CW\*(C`use\*(C'\fR'd extension that has a .pm suffix. If that file cannot be found,Perl dies with a fatal error. The default search path is contained in the\&\f(CW@INC\fR array..PPIn our case, Mytest.pm tells perl that it will need the Exporter and DynamicLoader extensions. It then sets the \f(CW@ISA\fR and \f(CW@EXPORT\fR arrays and the\&\f(CW$VERSION\fR scalar; finally it tells perl to bootstrap the module. Perlwill call its dynamic loader routine (if there is one) and load the sharedlibrary..PPThe two arrays \f(CW@ISA\fR and \f(CW@EXPORT\fR are very important. The \f(CW@ISA\fRarray contains a list of other packages in which to search for methods (orsubroutines) that do not exist in the current package. This is usuallyonly important for object-oriented extensions (which we will talk aboutmuch later), and so usually doesn't need to be modified..PPThe \f(CW@EXPORT\fR array tells Perl which of the extension's variables andsubroutines should be placed into the calling package's namespace. Becauseyou don't know if the user has already used your variable and subroutinenames, it's vitally important to carefully select what to export. Do \fInot\fRexport method or variable names \fIby default\fR without a good reason..PPAs a general rule, if the module is trying to be object-oriented then don'texport anything. If it's just a collection of functions and variables, thenyou can export them via another array, called \f(CW@EXPORT_OK\fR. This arraydoes not automatically place its subroutine and variable names into thenamespace unless the user specifically requests that this be done..PPSee perlmod for more information..PPThe \f(CW$VERSION\fR variable is used to ensure that the .pm file and the sharedlibrary are \*(L"in sync\*(R" with each other. Any time you make changes tothe .pm or .xs files, you should increment the value of this variable..Sh "Writing good test scripts".IX Subsection "Writing good test scripts"The importance of writing good test scripts cannot be over-emphasized. Youshould closely follow the \*(L"ok/not ok\*(R" style that Perl itself uses, so thatit is very easy and unambiguous to determine the outcome of each test case.When you find and fix a bug, make sure you add a test case for it..PPBy running "\f(CW\*(C`make test\*(C'\fR\*(L", you ensure that your Mytest.t script runs and usesthe correct version of your extension. If you have many test cases,save your test files in the \*(R"t\*(L" directory and use the suffix \*(R".t\*(L".When you run \*(R"\f(CW\*(C`make test\*(C'\fR", all of these test files will be executed..Sh "\s-1EXAMPLE\s0 3".IX Subsection "EXAMPLE 3"Our third extension will take one argument as its input, round off thatvalue, and set the \fIargument\fR to the rounded value..PPAdd the following to the end of Mytest.xs:.PP.Vb 10\& void\& round(arg)\& double arg\& CODE:\& if (arg > 0.0) {\& arg = floor(arg + 0.5);\& } else if (arg < 0.0) {\& arg = ceil(arg \- 0.5);\& } else {\& arg = 0.0;\& }\& OUTPUT:\& arg.Ve.PPEdit the Makefile.PL file so that the corresponding line looks like this:.PP.Vb 1\& \*(AqLIBS\*(Aq => [\*(Aq\-lm\*(Aq], # e.g., \*(Aq\-lm\*(Aq.Ve.PPGenerate the Makefile and run make. Change the test number in Mytest.t to\&\*(L"9\*(R" and add the following tests:.PP.Vb 5\& $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 );.Ve.PPRunning "\f(CW\*(C`make test\*(C'\fR" should now print out that all nine tests are okay..PPNotice that in these new test cases, the argument passed to round was ascalar variable. You might be wondering if you can round a constant orliteral. To see what happens, temporarily add the following line to Mytest.t:.PP.Vb 1\& &Mytest::round(3);.Ve.PPRun "\f(CW\*(C`make test\*(C'\fR" and notice that Perl dies with a fatal error. Perl won'tlet you change the value of constants!.Sh "What's new here?".IX Subsection "What's new here?".IP "\(bu" 4We've made some changes to Makefile.PL. In this case, we've specified anextra library to be linked into the extension's shared library, the mathlibrary libm in this case. We'll talk later about how to write XSUBs thatcan call every routine in a library..IP "\(bu" 4The value of the function is not being passed back as the function's returnvalue, but by changing the value of the variable that was passed into thefunction. You might have guessed that when you saw that the return valueof round is of type \*(L"void\*(R"..Sh "Input and Output Parameters".IX Subsection "Input and Output Parameters"You specify the parameters that will be passed into the \s-1XSUB\s0 on the line(s)after you declare the function's return value and name. Each input parameterline starts with optional whitespace, and may have an optional terminatingsemicolon..PPThe list of output parameters occurs at the very end of the function, justbefore after the \s-1OUTPUT:\s0 directive. The use of \s-1RETVAL\s0 tells Perl that youwish to send this value back as the return value of the \s-1XSUB\s0 function. InExample 3, we wanted the \*(L"return value\*(R" placed in the original variablewhich we passed in, so we listed it (and not \s-1RETVAL\s0) in the \s-1OUTPUT:\s0 section..Sh "The \s-1XSUBPP\s0 Program".IX Subsection "The XSUBPP Program"The \fBxsubpp\fR program takes the \s-1XS\s0 code in the .xs file and translates it intoC code, placing it in a file whose suffix is .c. The C code created makesheavy use of the C functions within Perl..Sh "The \s-1TYPEMAP\s0 file".IX Subsection "The TYPEMAP file"The \fBxsubpp\fR program uses rules to convert from Perl's data types (scalar,array, etc.) to C's data types (int, char, etc.). These rules are storedin the typemap file ($PERLLIB/ExtUtils/typemap). This file is split intothree parts..PPThe first section maps various C data types to a name, which correspondssomewhat with the various Perl types. The second section contains C codewhich \fBxsubpp\fR uses to handle input parameters. The third section containsC code which \fBxsubpp\fR uses to handle output parameters..PPLet's take a look at a portion of the .c file created for our extension.The file name is Mytest.c:.PP.Vb 10\& XS(XS_Mytest_round)\& {\& dXSARGS;\& if (items != 1)\& Perl_croak(aTHX_ "Usage: Mytest::round(arg)");\& PERL_UNUSED_VAR(cv); /* \-W */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -