📄 ch27.htm
字号:
<HTML>
<HEAD>
<TITLE>Chapter 27 -- Writing Extensions in C</TITLE>
<META NAME="GENERATOR" CONTENT="Mozilla/3.0b5aGold (WinNT; I) [Netscape]">
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#0000EE" VLINK="#551A8B" ALINK="#CE2910">
<H1><FONT COLOR=#FF0000>Chapter 27</FONT></H1>
<H1><B><FONT SIZE=5 COLOR=#FF0000>Writing Extensions in C</FONT></B>
</H1>
<P>
<HR WIDTH="100%"></P>
<P>
<H3 ALIGN=CENTER><FONT COLOR="#000000"><FONT SIZE=+2>CONTENTS<A NAME="CONTENTS"></A>
</FONT></FONT></H3>
<UL>
<LI><A HREF="#IntroductiontoXS" >Introduction to XS</A>
<LI><A HREF="#StepsforCreatinganExtension" >Steps for Creating an Extension</A>
<UL>
<LI><A HREF="#Step1ChangetothePerlDirectory" >Step 1: Change to the Perl Directory</A>
<LI><A HREF="#Step2Runh2sx" >Step 2: Run h2sx</A>
<LI><A HREF="#Step3CreateaMakefile" >Step 3: Create a Makefile</A>
<LI><A HREF="#Step4AddSomeCode" >Step 4: Add Some Code</A>
<LI><A HREF="#Step5TestYourExtensionModule" >Step 5: Test Your Extension Module</A>
<LI><A HREF="#FinalConsiderations" >Final Considerations</A>
</UL>
<LI><A HREF="#ThexsubppCompiler" >The xsubpp Compiler</A>
<LI><A HREF="#InputandOutputParameterstoFunctions" >Input and Output Parameters to Functions</A>
<UL>
<LI><A HREF="#ThetypemapFile" >The typemap File</A>
</UL>
<LI><A HREF="#ThebootstrapFunction" >The bootstrap Function</A>
<LI><A HREF="#PassingArguments" >Passing Arguments</A>
<LI><A HREF="#TheRETVALVariableandtheOUTPUTSecti" >The RETVAL Variable and the OUTPUT Section</A>
<LI><A HREF="#Keywords" >Keywords</A>
<UL>
<LI><A HREF="#TheMODULEKeyword" >The MODULE Keyword</A>
<LI><A HREF="#ThePACKAGEKeyword" >The PACKAGE Keyword</A>
<LI><A HREF="#TheCODEKeyword" >The CODE: Keyword</A>
<LI><A HREF="#TheOUTPUTKeyword" >The OUTPUT: Keyword</A>
<LI><A HREF="#PpcODEforReturningMoreThanOneValu" >PpcODE: for Returning More Than One Value</A>
<LI><A HREF="#ReturningUndefandEmptyLists" >Returning Undef and Empty Lists</A>
<LI><A HREF="#TheBOOTKeyword" >The BOOT: Keyword</A>
</UL>
<LI><A HREF="#TheListingsofModules" >The Listings of Modules</A>
<LI><A HREF="#Summary" >Summary</A>
</UL>
<HR>
<P>
In this chapter you'll work with the Perl XS<FONT FACE="AGaramond Bold">
</FONT>language, which is used to create an interface between
Perl and a C library. Such interfaces are called <I>extensions</I>
to Perl because they enable your code to look and feel just like
it is a part of Perl. Extensions are useful in appending extra
functionality to Perl. This chapter covers the basics of writing
extensions. The examples are simple enough to build on in order
to create your own extensions library.
<H2><A NAME="IntroductiontoXS"><B><FONT SIZE=5 COLOR=#FF0000>Introduction
to XS</FONT></B></A></H2>
<P>
In Perl, XS refers to a programming language interface used to
create an interface between C code and Perl scripts. Using the
XS API, you can create a library that can be loaded dynamically
into Perl.
<P>
The XS interface defines language components that wrap around
Perl constructs. To use the XS language, you need the <TT><FONT FACE="Courier">xsubpp</FONT></TT>
compiler to embed the constructs for you. The base construct in
the XS language is the <TT><FONT FACE="Courier">XSUB</FONT></TT>
function. The <TT><FONT FACE="Courier">XSUB</FONT></TT> function
is called when calls are made to pass data and control between
Perl and C code. Basically, Perl scripts call the <TT><FONT FACE="Courier">XSUB</FONT></TT>
routines to get to the C code in the libraries encapsulated by
the <TT><FONT FACE="Courier">XSUB</FONT></TT> functions.
<P>
To ensure that correct data types are mapped between C and Perl
scripts, the XS compiler does a mapping of one C type of variable
to a type in Perl. The mapping is maintained in a file called
<TT><FONT FACE="Courier">typemap</FONT></TT>. When you're looking
for extension files, it's often instructive to see how files are
mapped by using the <TT><FONT FACE="Courier">typemap</FONT></TT>
file in the same directory as the source file. <TT><FONT FACE="Courier">typemap</FONT></TT>
files are covered later in this chapter.
<P>
You may be asking yourself why someone would want to write an
extension in C when Perl is a perfectly good working language.
For one thing, Perl is slow compared to C. Your C compiler can
generate really tight code. All that power does have drawbacks.
Another reason is that you might already have source code written
and working in C, and porting this existing code to Perl would
not make much sense. Also, it's possible to write code that can
be accessed with Perl and C if you write the interfaces to your
core functions correctly.
<H2><A NAME="StepsforCreatinganExtension"><B><FONT SIZE=5 COLOR=#FF0000>Steps
for Creating an Extension</FONT></B></A></H2>
<P>
The best way to show the creation of an extension is by example.
This section steps you through the creation of the <TT><FONT FACE="Courier">futureValue</FONT></TT>
world function for Perl.
<H3><A NAME="Step1ChangetothePerlDirectory"><B>Step 1: Change
to the Perl Directory</B></A></H3>
<P>
Go to the directory where you installed the Perl distribution.
This is important. Do not try this in any other directory or you'll
get errors.
<H3><A NAME="Step2Runh2sx"><B>Step 2: Run </B><TT><B><FONT SIZE=4 FACE="Courier">h2sx</FONT></B></TT></A>
</H3>
<P>
For Step 2, you have to run the header to extension program <TT><FONT FACE="Courier">h2xs</FONT></TT>.
To obtain a list of the options for this program, use the <TT><FONT FACE="Courier">-h</FONT></TT>
option, as shown here:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">$ <B>h2xs -h<BR>
<BR>
</B>h2xs [-Acfh] [-n module_name] [headerfile [extra_libraries]]
<BR>
-f Force creation of
the extension even if the C header does not exist.<BR>
-n Specify a name to
use for the extension (recommended).<BR>
-c Omit the constant()
function and specialised AUTOLOAD from the XS file.<BR>
-A Omit all autoloading
facilities (implies -c).<BR>
-h Display this help
message<BR>
extra_libraries<BR>
are any
libraries that might be needed for loading the<BR>
extension,
e.g. -lm would try to link in the math library.</FONT></TT>
</BLOCKQUOTE>
<P>
Run <TT><FONT FACE="Courier">h2XS -n Finance</FONT></TT>. This
creates a directory named <TT><FONT FACE="Courier">Finance</FONT></TT>,
possibly under the subdirectory <TT><FONT FACE="Courier">ext/</FONT></TT>
if it exists in the current working directory. Four files are
created in the <TT><FONT FACE="Courier">Finance</FONT></TT> directory:
<TT><FONT FACE="Courier">MANIFEST</FONT></TT>, <TT><FONT FACE="Courier">Makefile.PL</FONT></TT>,
<TT><FONT FACE="Courier">Finance.pm</FONT></TT>, and <TT><FONT FACE="Courier">Finance.xs</FONT></TT>.
Here's what the output on your terminal will look like:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">$ <B>h2xs -n Finance<BR>
</B>Writing ext/Finance/Finance.pm<BR>
Writing ext/Finance/Finance.xs<BR>
Writing ext/Finance/Makefile.PL</FONT></TT>
</BLOCKQUOTE>
<P>
The <TT><FONT FACE="Courier">MANIFEST</FONT></TT> file in the
<TT><FONT FACE="Courier">ext/Finance</FONT></TT> directory contains
the names of the four files created. You have to change directories
to <TT><FONT FACE="Courier">./ext/Finance</FONT></TT> to be able
to work with these four files. Also, depending on who installed
your Perl distribution, you might have to run as <TT><FONT FACE="Courier">root</FONT></TT>.
<P>
The contents of file <TT><FONT FACE="Courier">Makefile.PL</FONT></TT>
are shown in Listing 27.1.
<HR>
<BLOCKQUOTE>
<B>Listing 27.1. The contents of </B><TT><B><FONT FACE="Courier">Makefile.PL</FONT></B></TT><B>.
<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<TT><FONT FACE="Courier"> 1 use ExtUtils::MakeMaker;<BR>
2 # See lib/ExtUtils/MakeMaker.pm for details of how to
influence<BR>
3 # the contents of the Makefile that is written.<BR>
4 WriteMakefile(<BR>
5 'NAME' =>
'Finance',<BR>
6 'VERSION' =>
'0.1',<BR>
7 'LIBS' =>
['-lm'], # e.g., '-lm'<BR>
8 'DEFINE' =>
'', # e.g., '-DHAVE_SOMETHING'<BR>
9 'Inc' =>
'', # e.g., '-I/usr/include/other'
<BR>
10 );</FONT></TT>
</BLOCKQUOTE>
<HR>
<P>
The <TT><FONT FACE="Courier">h2xs</FONT></TT> script also creates
a <TT><FONT FACE="Courier">.pm</FONT></TT> file. The contents
of file <TT><FONT FACE="Courier">Finance.pm</FONT></TT> are shown
in Listing 27.2. The <TT><FONT FACE="Courier">Finance.pm</FONT></TT>
file is where you add your exports and any Perl code.
<HR>
<BLOCKQUOTE>
<B>Listing 27.2. The module file: </B><TT><B><FONT FACE="Courier">Finance.pm</FONT></B></TT><B>.
<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<TT><FONT FACE="Courier"> 1 package Finance;<BR>
2<BR>
3 require Exporter;<BR>
4 require DynaLoader;<BR>
5 require AutoLoader;<BR>
6<BR>
7 @ISA = qw(Exporter DynaLoader);<BR>
8 # Items to export into callers namespace by default. Note:
do not export<BR>
9 # names by default without a very good reason. Use EXPORT_OK
instead.<BR>
10 # Do not simply export all your public functions/methods/constants.
<BR>
11 @EXPORT = qw(<BR>
12<BR>
13 );<BR>
14 sub AUTOLOAD {<BR>
15 # This AUTOLOAD is used to 'autoload'
constants from the constant()<BR>
16 # XS function. If a
constant is not found then control is passed<BR>
17 # to the AUTOLOAD in AutoLoader.
<BR>
18<BR>
19 local($constname);<BR>
20 ($constname = $AUTOLOAD) =~ s/.*:://;
<BR>
21 $val = constant($constname, @_
? $_[0] : 0);<BR>
22 if ($! != 0) {<BR>
23 if ($! =~ /Invalid/) {<BR>
24 $AutoLoader::AUTOLOAD
= $AUTOLOAD;<BR>
25 goto
&AutoLoader::AUTOLOAD;<BR>
26 }<BR>
27 else {<BR>
28 ($pack,$file,$line)
= caller;<BR>
29 die
"Your vendor has not defined Finance macro<BR>
$constname, used at $file line $line.<BR>
30 ";<BR>
31 }<BR>
32 }<BR>
33 eval "sub $AUTOLOAD { $val
}";<BR>
34 goto &$AUTOLOAD;<BR>
35 }<BR>
36<BR>
37 bootstrap Finance;<BR>
38<BR>
39 # Preloaded methods go here.<BR>
40<BR>
41 # Autoload methods go after _ _END_ _, and are processed
by the autosplit program.<BR>
42<BR>
43 1;<BR>
44 _ _END_ _</FONT></TT>
</BLOCKQUOTE>
<HR>
<P>
All scripts which use <TT><FONT FACE="Courier">Finance.pm</FONT></TT>
will now have to tell Perl to use functions in the <TT><FONT FACE="Courier">Finance.pm</FONT></TT>
extension with the following command:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">use Finance;</FONT></TT>
</BLOCKQUOTE>
<P>
When Perl sees this <TT><FONT FACE="Courier">use</FONT></TT> command,
it searches for a <TT><FONT FACE="Courier">Finance.pm</FONT></TT>
file of the same name in the various directories listed in the
<TT><FONT FACE="Courier">@Inc</FONT></TT> array. If it cannot
find the file, Perl stops with an error message.
<P>
The <TT><FONT FACE="Courier">.pm</FONT></TT> file extension generally
requests that the Exporter and Dynamic Loader extensions also
be loaded. You need them for exporting functions and dynamic loading.
Perl uses the <TT><FONT FACE="Courier">@ISA</FONT></TT> array
to get any methods that are not found in the current package.
After this set, the library is loaded as an extension into Perl.
<P>
There are two files to look at in the <TT><FONT FACE="Courier">Finance</FONT></TT>
example we just created. The <TT><FONT FACE="Courier">Finance.xs</FONT></TT>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -