⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch26.htm

📁 《Perl 5 Unreleased》
💻 HTM
📖 第 1 页 / 共 5 页
字号:
<HTML>



<HEAD>

   <TITLE>Chapter 26 -- Writing C Extensions in Perl</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 26</FONT></H1>

<H1><B><FONT SIZE=5 COLOR=#FF0000>Writing C Extensions in Perl</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="#Introduction" >Introduction</A>

<LI><A HREF="#CompilingaCProgramThatCallsPerl" >Compiling a C Program That Calls Perl</A>

<UL>

<LI><A HREF="#WhatIsExtUtilsembed" >What Is ExtUtils::embed?</A>

<LI><A HREF="#UsingtheembedpmPackage" >Using the embed.pm Package</A>

</UL>

<LI><A HREF="#AddingaPerlInterpreter" >Adding a Perl Interpreter to Your C Program</A>

<LI><A HREF="#CallingPerlSubroutinesfromWithin" >Calling Perl Subroutines from Within a C Program</A>

<LI><A HREF="#WorkingwiththePerlStack" >Working with the Perl Stack</A>

<UL>

<LI><A HREF="#Theperl_call_svFunction" >The perl_call_sv Function</A>

<LI><A HREF="#Theperl_call_pvFunction" >The perl_call_pv Function</A>

<LI><A HREF="#Theperl_call_methodFunction" >The perl_call_method Function</A>

<LI><A HREF="#Theperl_call_argvFunction" >The perl_call_argv Function</A>

</UL>

<LI><A HREF="#TheFlagstoUse" >The Flags to Use</A>

<UL>

<LI><A HREF="#TheG_DISCARDFlag" >The G_DISCARD Flag</A>

<LI><A HREF="#TheG_NOARGSFlag" >The G_NOARGS Flag</A>

<LI><A HREF="#TheG_SCALARFlag" >The G_SCALAR Flag</A>

<LI><A HREF="#TheG_ARRAYFlag" >The G_ARRAY Flag</A>

<LI><A HREF="#TheG_EVALFlag" >The G_EVAL Flag</A>

</UL>

<LI><A HREF="#UsingSCALARContext" >Using SCALAR Context</A>

<LI><A HREF="#ReturningListsfromSubroutines" >Returning Lists from Subroutines</A>

<LI><A HREF="#UsingG_EVAL" >Using G_EVAL</A>

<LI><A HREF="#GettingSpecialVariableValues" >Getting Special Variable Values</A>

<LI><A HREF="#UsingtheSTMacros" >Using the ST Macros</A>

<LI><A HREF="#EvaluatingPerlExpressions" >Evaluating Perl Expressions</A>

<LI><A HREF="#PatternMatchesandSubstitutions" >Pattern Matches and Substitutions from Your C Program</A>

<LI><A HREF="#Summary" >Summary</A>

</UL>

<HR>

<P>

This chapter introduces a way to embed the Perl interpreter into

a C program. After reading this chapter, you should be able to

integrate the Perl interpreter or its library code with a C application.

The information in this chapter relies heavily on the discussion

of Perl's internal data types from <A HREF="ch25.htm" tppabs="http://www.mcp.com/815097600/0-672/0-672-30891-6/ch25.htm" >Chapter 25</A>,

&quot;Perl Internal Files and Structures.&quot;

<H2><A NAME="Introduction"><B><FONT SIZE=5 COLOR=#FF0000>Introduction</FONT></B></A>

</H2>

<P>

The Perl interpreter is written in C and can therefore be linked

with C code. The combination process is relatively straightforward.

However, there are some caveats that you should be aware of. I

discuss these caveats in this chapter. Also, even though you can

combine C and Perl code, you might want to rethink the way you

want to use each language. Both C and Perl have their strong points.

C code can be optimized to a greater degree than can Perl code.

Perl is great for processing text files and strings, whereas manipulation

strings in C is a bit clumsy at times. 

<P>

Several alternatives exist for combining C and Perl code. You

can use extensions, call complete programs, run a background process,

and so on. For example, if you want to create a library of mathematical

functions to use in your Perl programs, you can write an extension

and use it from within your Perl code. If the functionality you

need from a C program can be encapsulated into an executable program,

you can call this program from within a system call. The system

call will force your Perl program to wait until the called program

terminates. You can start the executable program as a background

process from the command line or from within a Perl program using

a <TT><FONT FACE="Courier">fork</FONT></TT> system call. 

<P>

If one of these methods will solve your problem, you may not have

to take the more complicated route of embedding Perl in C code.

Think through your design thoroughly before deciding which solution

is best. If you feel that your design requires you to write a

C program and also use the functionality of Perl from within your

program, you are left with no alternative except to follow the

more complicated route.

<P>

The first question to answer is Whether the solution you are deriving

is based for the UNIX platform? Most of the tested situations

to date for combining C code with Perl are those on the UNIX platform.

Such a combination is therefore not viable for non-UNIX platforms.

If you intend to port the combined code to an NT system, it simply

won't compile, let alone work. Therefore, if you've concluded

that you must embed the Perl interpreter in your C code, keep

in mind that you're also limiting your solution to UNIX platforms.

Embedding Perl in C code on Windows will not work at the moment,

so you might want to rethink your design to see whether you can

obtain comparable functionality using extension libraries.

<P>

The second question to answer is What exactly is the solution

you are trying to achieve by combining Perl with C? Again, if

all you want do is use C code from within Perl, you might want

to consider writing the C code as a Perl extension. In such an

event, you should rethink your design to see how to use only portions

of the C code as parts of an extension library for a Perl program.

The methods to do just this are covered in <A HREF="ch27.htm" tppabs="http://www.mcp.com/815097600/0-672/0-672-30891-6/ch27.htm" >Chapter 27</A>,

&quot;Writing Extensions in C.&quot;

<P>

Normally you want to write extensions in C because the compiled

code is faster. For example, complex mathematical calculations

are probably best written in C rather than in Perl. The compiled

C code runs much faster than interpreted code in Perl for specific

tasks. Also, with the use of extensions, it's possible to send

in pointers to variables, existing with the Perl program, into

the extension code. By receiving pointers to the Perl variables,

code within extensions can modify the contents of variables directly.

<P>

Of course, if you are attempting to run another complete C program

from Perl, consider using the <TT><FONT FACE="Courier">system()</FONT></TT>,

<TT><FONT FACE="Courier">backtick</FONT></TT>, or <TT><FONT FACE="Courier">exec()</FONT></TT>

calls. They are convenient ways of calling complete programs.

With the <TT><FONT FACE="Courier">open()</FONT></TT> call using

pipes, it's easy to collect the standard output from the executed

application. However, you are constrained to reading only the

output from the child process you started. The child process cannot

manipulate any Perl variables directly. The Perl code and the

called code run as completely different applications in their

own address spaces. This is in contrast to working with Perl's

extensions that run C as part of the calling process. (Of course,

you can take explicit measures to create a bi-directional pipe

through which to communicate.)

<P>

The flexibility in the two methods outlined up to now in this

section solves a majority of the problems solved using C and Perl.

In both methods, though, the calling program is a Perl application.

What if you want to call Perl code from within a C application?

You can write the Perl code as an executable script and then make

a <TT><FONT FACE="Courier">system()</FONT></TT> call from within

the C code. However, you'll be constrained by the same things

as you were using the <TT><FONT FACE="Courier">system()</FONT></TT>

call from within Perl. There is no direct connection between the

child process started with <TT><FONT FACE="Courier">system()</FONT></TT>

and the calling application, unless you take explicit measures

to create a communication channel like a socket or pipe.

<P>

Sometimes you just have to call Perl code from within a C program.

For example, the C language is not designed to process regular

expressions. The functionality of parsing tokens from a string

using the <TT><FONT FACE="Courier">strtok()</FONT></TT> function

may not be sufficient for your problem. There are ways to port

some regular expression parsers like <TT><FONT FACE="Courier">grep</FONT></TT>

into C. (A good example is Allen Holub's port of <TT><FONT FACE="Courier">grep</FONT></TT>

in an article in <I>Dr. Dobbs</I>, October, 1984, and in <I>The

Dr. Dobbs Toolbox of C</I>, Brady Books, 1986.) Perhaps all you

need is simple regular expression parsing, in which case using

a port of <TT><FONT FACE="Courier">grep</FONT></TT> makes sense.

The <TT><FONT FACE="Courier">grep</FONT></TT> code you link will

not have the overhead of the entire Perl preprocessor.

<P>

However, if all else fails and you do want the Perl interpreter

in your C program, or at the very least want to call a Perl subroutine

from within your C program, this chapter might provide the information

you need. Here are the topics I will cover:

<UL>

<LI><FONT COLOR=#000000>How to add a Perl interpreter to a C program</FONT>

<LI><FONT COLOR=#000000>How to call a Perl subroutine from within

a C program</FONT>

<LI><FONT COLOR=#000000>How to use Perl pattern matches and string

substitutions</FONT>

</UL>

<H2><A NAME="CompilingaCProgramThatCallsPerl"><B><FONT SIZE=5 COLOR=#FF0000>Compiling

a C Program That Calls Perl</FONT></B></A></H2>

<P>

First of all, make sure you have read access to the Perl 5 distribution

including Perl header files and linking Perl libraries. Make sure

that your Perl 5.002 source code distribution is complete and

installed correctly. Copying the Perl executable program from

another machine won't work because you need the whole source tree

to work with your C program.

<P>

Essentially, the files you need are the <TT><FONT FACE="Courier">EXTERN.h</FONT></TT>

and <TT><FONT FACE="Courier">perl.h</FONT></TT> header files.

The Perl libraries should exist in a directory using the following

format:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">/usr/local/lib/perl5/your_architecture_here/CORE</FONT></TT>

</BLOCKQUOTE>

<P>

Execute this statement for a hint about where to find <TT><FONT FACE="Courier">CORE</FONT></TT>:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">perl -e 'use Config; print $Config{archlib}\n'</FONT></TT>

</BLOCKQUOTE>

<P>

On my Linux system, this program returned the following pathname

(the path might be completely different for your machine):

<BLOCKQUOTE>

<TT><FONT FACE="Courier">/usr/lib/perl5/i486-linux/5.002</FONT></TT>

</BLOCKQUOTE>

<P>

The command line to use for compiling and running a program is

<BLOCKQUOTE>

<TT><FONT FACE="Courier">gcc -o filename filename.c -L($LIBS)

-I($IncS)</FONT></TT>

</BLOCKQUOTE>

<P>

The <TT><FONT FACE="Courier">-L</FONT></TT> and <TT><FONT FACE="Courier">-I</FONT></TT>

flags define the locations of the library and header files. The

libraries that you are linking with are

<BLOCKQUOTE>

<TT><FONT FACE="Courier">perl -e 'use Config; print $Config{libs}

, &quot;\n&quot;;'</FONT></TT>

</BLOCKQUOTE>

<P>

An easier way to find out which libraries you are using is to

use the <TT><FONT FACE="Courier">ExtUtils::embed</FONT></TT> module

extensions. This library is available from any CPAN site and is

in the public domain.

<H3><A NAME="WhatIsExtUtilsembed"><B>What Is </B><TT><B><FONT SIZE=4 FACE="Courier">ExtUtils::embed</FONT></B></TT><B><FONT SIZE=4>?</FONT></B></A>

</H3>

<P>

<TT><FONT FACE="Courier">ExtUtils::embed</FONT></TT> is a set

of utility functions used when embedding a Perl interpreter and

extensions in your C/C++ applications. You do not have to use

this library, but it does a lot of the basic grunt work (such

as finding the correct libraries, include files, and definitions)

for you. The author of the <TT><FONT FACE="Courier">ExtUtils::embed</FONT></TT>

package is Doug MacEachern (<TT><FONT FACE="Courier">dougm@osf.org</FONT></TT>).

You can address problems and comments to him directly.

<P>

Installing the package is easy. Simply un<TT><FONT FACE="Courier">tar</FONT></TT>

the archive, which will create a directory called <TT><FONT FACE="Courier">ExtUtils-embed-version_number</FONT></TT>.

Change directory into this new directory and run these commands:

<BLOCKQUOTE>

<TT><B><FONT FACE="Courier">perl Makefile.PL<BR>

make<BR>

make test<BR>

make install</FONT></B></TT>

</BLOCKQUOTE>

<H3><A NAME="UsingtheembedpmPackage"><B>Using the </B><TT><B><FONT SIZE=4 FACE="Courier">embed.pm</FONT></B></TT><B><FONT SIZE=4>

Package</FONT></B></A></H3>

<P>

Usually, you'll place a call to the <TT><FONT FACE="Courier">embed.pm</FONT></TT>

function in a makefile. The instructions on how to do this are

in the <TT><FONT FACE="Courier">embed.pm</FONT></TT> package itself.

In practice, however, I just took the values returned from a few

calls to the <TT><FONT FACE="Courier">embed.pm</FONT></TT> functions

and placed them directly in a makefile. This way there was a written

record in the makefile for the explicit pathnames used to build

the programs I happen to be using. The risk was that if the location

of the Perl library changed in the future, my makefile would break.

This change is too unlikely to happen on my machine because I

administer it. Your case might be different if you are on a multiuser

system or are writing this makefile for the benefit of a group.

<P>

The one-line command to compile and link the <TT><FONT FACE="Courier">ex1.c</FONT></TT>

file in a makefile is

<BLOCKQUOTE>

<TT><FONT FACE="Courier">$gcc -o ex1 ex1.c 'perl -MExtUtils::embed

-e ccopts -e ldopts'</FONT></TT>

</BLOCKQUOTE>

<P>

In fact, this line can be placed in a shell script like this:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">$gcc -o $1 $1.c 'perl -MExtUtils::embed

-e ccopts -e ldopts'</FONT></TT>

</BLOCKQUOTE>

<P>

Each execution of the makefile will cause the Perl script to recreate

the include and link paths. This might slow down each execution

of <TT><FONT FACE="Courier">make</FONT></TT>. A <TT><FONT FACE="Courier">make</FONT></TT>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -