如何在C程序中嵌入Perl
如果你編譯本文檔中的腳本有困難。那么你不是一個人在戰(zhàn)斗。記住重要原則: 以編譯你的perl的方式,編譯你的程序(不好意思)
并且,每一個使用了Perl的C程序都必須連接 perl 庫. 你問,那是什么?Perl本身就是用C寫的。Perl庫是編譯過的用來創(chuàng)建Perl可執(zhí)行程序的C程序集合 (/usr/bin/perl或者類似的)。(結(jié)論:你不能在沒有編譯過或者正確安裝過Perl的系統(tǒng)中編譯嵌入了Perl的C程序。不正確安裝指,只是復(fù)制了Perl的二進制可執(zhí)行文件而沒有復(fù)制perl的庫目錄。)
當你在C中使用Perl時, 你的C程序?qū)⒁?-通常--需要創(chuàng)建、執(zhí)行,然后銷毀一個 Perl解釋器
如果你的Perl烤備足夠新到包含本文檔 (版本5.002或者更新), 則Perl庫 (以及你將需要的EXTERN.h 和 perl.h) 將會在類似這樣的目錄中:
/usr/local/lib/perl5/your_architecture_here/CORE
或者可能就直接是
/usr/local/lib/perl5/your_architecture_here/CORE
或者可能類似
/usr/opt/perl5/CORE
執(zhí)行這個表達式可以定位這個目錄:
perl -MConfig -e 'print $Config{archlib}'
這是如何編譯下節(jié)的示例代碼:往你的C程序中墻加一個Perl解釋器的語句,在我的linux機器上是這樣:
% gcc -O2 -Dbool=char -DHAS_BOOL -I/usr/local/include -I/usr/local/lib/perl5/i586-linux/5.003/CORE -I/usr/local/lib/perl5/i586-linux/5.003/CORE -o interp interp.c -lperl -lm
(那些是一行。) 在我跑著老版本perl 5.003_05的DEC Alpha機器上, 有一點點兒不一樣:
% cc -O2 -Olimit 2900 -DSTANDARD_C -I/usr/local/include -I/usr/local/lib/perl5/alpha-dec_osf/5.00305/CORE -L/usr/local/lib/perl5/alpha-dec_osf/5.00305/CORE -L/usr/local/lib -D__LANGUAGE_C__ -D_NO_PROTO -o interp interp.c -lperl -lm
你如何找出需要填加什么?如果你的Perl版本高于5.001, 執(zhí)行 perl -V 命令,注意一下它的有關(guān)``cc'' 和 ``ccflags''的信息。
你將不得不根據(jù)你的系統(tǒng)選擇適當?shù)木幾g器。 (cc,gcc,等等。) : perl -MConfig -e 'print $Config{cc}' 將告訴你用什么。
你還得根據(jù)你的系統(tǒng)選擇正確的Perl庫目錄 (/usr/local/lib/...) 如果你的編譯器抱怨有函數(shù)未定義,或者它不能定位 -lperl,則你需要用-L手動指定庫文件路徑。如果它抱怨找不到EXTERN.h 和 perl.h,你需要用-I手動指定頭文件路徑。
你可能還需要如法增加其它庫哪些?可能包括這行指令打印出的這些:
perl -MConfig -e 'print $Config{archlib}'
如果你的perl配置安裝無誤,則模塊ExtUtils::Embed將為你檢測出你需要的所有信息。
% cc -o interp interp.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
如果ExtUtils::Embed不包含在你的perl發(fā)行版中, 你可以從http://www.perl.com/perl/CPAN/modules/by-module/ExtUtils/.下載它 (如果本文檔來自你的perl發(fā)行版,則你已經(jīng)安裝了perl 5.004或者更高的版本,并且你肯定有這個模塊)
CPAN上的ExtUtils::Embed,包括了有關(guān)本文檔的所有的源碼、測試以及其它對你有用的示例程序。
--------------------------------------------------------------------------------
往你的C程序中增加一個Perl解釋器
通常, perl (C源程序) 是一個嵌入Perl(語言)的好例子,所以我將示范一個miniperlmain.c。當然,它不太標準,也不太精巧。
#include <EXTERN.h> /* from the Perl distribution */ #include <EXTERN.h> /* from the Perl distribution */
static PerlInterpreter *my_perl; /*** The Perl interpreter ***/
int main(int argc, char **argv, char **env) { my_perl = perl_alloc(); perl_construct(my_perl); perl_par(my_perl, NULL, argc, argv, (char **)NULL); perl_run(my_perl); perl_destruct(my_perl); perl_free(my_perl); }
注意我們沒有使用env指針。通常做為perl_par的最后一個選項, env參數(shù)為NULL,代表使用當前的環(huán)境變量。
現(xiàn)在編譯它 (我將叫它 interp.c)為可執(zhí)行文件:
% cc -o interp interp.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
經(jīng)過成功的編譯以后, 你將可以像使用perl一樣地使用interp。
% interp print "Pretty Good Perl \n"; print "10890 - 9801 is ", 10890 - 9801; <CTRL-D> Pretty Good Perl 10890 - 9801 is 1089
或者
% interp -e 'printf("%x", 3735928559)' deadbeef
你也可以通過在調(diào)用perl_fun以前替換argv[1],在C程序里從一個文件中讀取然后執(zhí)行Perl代碼。
--------------------------------------------------------------------------------
在你的C程序中調(diào)用一個Perl子程序
為了調(diào)用獨立的Perl子程序,你可以使用任何<al>perlcall手冊</al>中的perl_call_*類型的函數(shù)。在此例中,我們將使用perl_call_argv。
它們將在下面這個我叫做showtime.c的程序中中展現(xiàn)。
#include <EXTERN.h> #include <perl.h>
static PerlInterpreter *my_perl;
int main(int argc, char **argv, char **env) { char *args[] = { NULL }; my_perl = perl_alloc(); perl_construct(my_perl);
perl_par(my_perl, NULL, argc, argv, (char **)NULL);
/*** skipping perl_run() ***/
perl_call_argv("showtime", G_DISCARD | G_NOARGS, args);
perl_destruct(my_perl); perl_free(my_perl); }
showtime是一個Perl子程序,它沒有參數(shù)。 (它是 G_NOARGS) 并且我將忽略它的返回值 (它是G_DISCARD). 那些標記,以及其它一些標記,在perlcall手冊中。
我將在文件<el>showtime.pl</el>中定義showtime函數(shù):
print "I shan't be printed.";
sub showtime { print time; }
足夠簡單。現(xiàn)在編譯并運行:
% cc -o interp interp.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
% showtime showtime.pl 818284590
返回從1970年1月1日 (Unix epoch開始時間)到現(xiàn)在我正在執(zhí)行程序語句的時間。
在這一部分,我們不需要調(diào)用perl_run,但是通常好的編程習慣來保證正確的使用庫是好的,包括對所有的對象調(diào)用 DESTROY 方法以及塊的END {}。
如果你想傳遞參數(shù)給Perl函數(shù),你可以填加以NULL結(jié)尾的args表給perl_call_argv。為了其它數(shù)據(jù)類型或者測試返回值,你將需要操作Perl的棧。那將在本文檔最后的章節(jié)進行討論: 在你的C程序中操作Perl的棧。
--------------------------------------------------------------------------------
在你的C程序中執(zhí)行一個Perl表達式
Perl提供了兩個API函數(shù)來執(zhí)行Perl代碼片斷。它們是perl_eval_sv 和 perl_eval_pv。
經(jīng)常的情況是,你只需要在程序中執(zhí)行一塊的Perl代碼。它可以如你所愿的長:它可以包括 u、require和 do 用來包含其它的外部Perl文件。
perl_eval_pv 可以讓我執(zhí)行單獨的Perl語句,然后把執(zhí)行結(jié)果變量返回成C的形式。下面的程序 string.c,執(zhí)行三個Perl語句, 從第一個取得int,從第二個取回float, 從第三個取回char *。
#include <EXTERN.h> #include <perl.h> static PerlInterpreter *my_perl; int main(int argc, char **argv, char **env) { STRLEN n_a; char *embedding[] = { "", "-e", "0" }; my_perl = perl_alloc(); perl_construct(my_perl); perl_par(my_perl, NULL, 3, embedding, NULL); perl_run(my_perl); /** Treat $a as an integer **/ perl_eval_pv("$a = 3; $a **= 2", TRUE); printf("a = %d\n", SvIV(perl_get_sv("a", FALSE))); /** Treat $a as a float **/ perl_eval_pv("$a = 3; $a **= 2", TRUE); printf("a = %f\n", SvNV(perl_get_sv("a", FALSE))); /** Treat $a as a float **/ perl_eval_pv("$a = 'rekcaH lreP rehtonA tsuJ'; $a = rever($a);", TRUE); printf("a = %s\n", SvPV(perl_get_sv("a", FALSE), n_a)); perl_destruct(my_perl); perl_free(my_perl); }
所有這些名字中含有 sv 的這些怪函數(shù)都幫助把Perl的標量返回成C的類型。它們在 perlguts手冊里有描述。
如果你編譯并運行string.c,你將看到 SvIV()創(chuàng)建整數(shù),SvNV()創(chuàng)建浮點數(shù),以及SvPV()創(chuàng)建一個字符串:
a = 9 a = 9 a = Just Another Perl Hacker
在上例中,我們創(chuàng)建了一個全局的變量來保存我們表達式執(zhí)行的結(jié)果。在很多情形下,通過perl_eval_pv()的執(zhí)行結(jié)果來取回返回值,也不錯。如:
... STRLEN n_a; SV *val = perl_eval_pv("rever 'rekcaH lreP rehtonA tsuJ'", TRUE); printf("%s\n", SvPV(val,n_a)); ...
這種方法,我們通過不創(chuàng)建全局變量以及簡化我們的化碼,避免了名字空間污染。
如何在C程序中嵌入Perl
如果你編譯本文檔中的腳本有困難。那么你不是一個人在戰(zhàn)斗。記住重要原則: 以編譯你的perl的方式,編譯你的程序(不好意思)
并且,每一個使用了Perl的C程序都必須連接 perl 庫. 你問,那是什么?Perl本身就是用C寫的。Perl庫是編譯過的用來創(chuàng)建Perl可執(zhí)行程序的C程序集合 (/usr/bin/perl或者類似的)。(結(jié)論:你不能在沒有編譯過或者正確安裝過Perl的系統(tǒng)中編譯嵌入了Perl的C程序。不正確安裝指,只是復(fù)制了Perl的二進制可執(zhí)行文件而沒有復(fù)制perl的庫目錄。)
當你在C中使用Perl時, 你的C程序?qū)⒁?-通常--需要創(chuàng)建、執(zhí)行,然后銷毀一個 Perl解釋器
如果你的Perl烤備足夠新到包含本文檔 (版本5.002或者更新), 則Perl庫 (以及你將需要的EXTERN.h 和 perl.h) 將會在類似這樣的目錄中:
/usr/local/lib/perl5/your_architecture_here/CORE
或者可能就直接是
/usr/local/lib/perl5/your_architecture_here/CORE
或者可能類似
/usr/opt/perl5/CORE
執(zhí)行這個表達式可以定位這個目錄:
perl -MConfig -e 'print $Config{archlib}'
這是如何編譯下節(jié)的示例代碼:往你的C程序中墻加一個Perl解釋器的語句,在我的linux機器上是這樣:
% gcc -O2 -Dbool=char -DHAS_BOOL -I/usr/local/include -I/usr/local/lib/perl5/i586-linux/5.003/CORE -I/usr/local/lib/perl5/i586-linux/5.003/CORE -o interp interp.c -lperl -lm
(那些是一行。) 在我跑著老版本perl 5.003_05的DEC Alpha機器上, 有一點點兒不一樣:
% cc -O2 -Olimit 2900 -DSTANDARD_C -I/usr/local/include -I/usr/local/lib/perl5/alpha-dec_osf/5.00305/CORE -L/usr/local/lib/perl5/alpha-dec_osf/5.00305/CORE -L/usr/local/lib -D__LANGUAGE_C__ -D_NO_PROTO -o interp interp.c -lperl -lm
你如何找出需要填加什么?如果你的Perl版本高于5.001, 執(zhí)行 perl -V 命令,注意一下它的有關(guān)``cc'' 和 ``ccflags''的信息。
你將不得不根據(jù)你的系統(tǒng)選擇適當?shù)木幾g器。 (cc,gcc,等等。) : perl -MConfig -e 'print $Config{cc}' 將告訴你用什么。
你還得根據(jù)你的系統(tǒng)選擇正確的Perl庫目錄 (/usr/local/lib/...) 如果你的編譯器抱怨有函數(shù)未定義,或者它不能定位 -lperl,則你需要用-L手動指定庫文件路徑。如果它抱怨找不到EXTERN.h 和 perl.h,你需要用-I手動指定頭文件路徑。
你可能還需要如法增加其它庫哪些?可能包括這行指令打印出的這些:
perl -MConfig -e 'print $Config{archlib}'
如果你的perl配置安裝無誤,則模塊ExtUtils::Embed將為你檢測出你需要的所有信息。
% cc -o interp interp.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
如果ExtUtils::Embed不包含在你的perl發(fā)行版中, 你可以從http://www.perl.com/perl/CPAN/modules/by-module/ExtUtils/.下載它 (如果本文檔來自你的perl發(fā)行版,則你已經(jīng)安裝了perl 5.004或者更高的版本,并且你肯定有這個模塊)
CPAN上的ExtUtils::Embed,包括了有關(guān)本文檔的所有的源碼、測試以及其它對你有用的示例程序。
--------------------------------------------------------------------------------
往你的C程序中增加一個Perl解釋器
通常, perl (C源程序) 是一個嵌入Perl(語言)的好例子,所以我將示范一個miniperlmain.c。當然,它不太標準,也不太精巧。
#include <EXTERN.h> /* from the Perl distribution */ #include <EXTERN.h> /* from the Perl distribution */
static PerlInterpreter *my_perl; /*** The Perl interpreter ***/
int main(int argc, char **argv, char **env) { my_perl = perl_alloc(); perl_construct(my_perl); perl_par(my_perl, NULL, argc, argv, (char **)NULL); perl_run(my_perl); perl_destruct(my_perl); perl_free(my_perl); }
注意我們沒有使用env指針。通常做為perl_par的最后一個選項, env參數(shù)為NULL,代表使用當前的環(huán)境變量。
現(xiàn)在編譯它 (我將叫它 interp.c)為可執(zhí)行文件:
% cc -o interp interp.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
經(jīng)過成功的編譯以后, 你將可以像使用perl一樣地使用interp。
% interp print "Pretty Good Perl \n"; print "10890 - 9801 is ", 10890 - 9801; <CTRL-D> Pretty Good Perl 10890 - 9801 is 1089
或者
% interp -e 'printf("%x", 3735928559)' deadbeef
你也可以通過在調(diào)用perl_fun以前替換argv[1],在C程序里從一個文件中讀取然后執(zhí)行Perl代碼。
--------------------------------------------------------------------------------
在你的C程序中調(diào)用一個Perl子程序
為了調(diào)用獨立的Perl子程序,你可以使用任何<al>perlcall手冊</al>中的perl_call_*類型的函數(shù)。在此例中,我們將使用perl_call_argv。
它們將在下面這個我叫做showtime.c的程序中中展現(xiàn)。
#include <EXTERN.h> #include <perl.h>
static PerlInterpreter *my_perl;
int main(int argc, char **argv, char **env) { char *args[] = { NULL }; my_perl = perl_alloc(); perl_construct(my_perl);
perl_par(my_perl, NULL, argc, argv, (char **)NULL);
/*** skipping perl_run() ***/
perl_call_argv("showtime", G_DISCARD | G_NOARGS, args);
perl_destruct(my_perl); perl_free(my_perl); }
showtime是一個Perl子程序,它沒有參數(shù)。 (它是 G_NOARGS) 并且我將忽略它的返回值 (它是G_DISCARD). 那些標記,以及其它一些標記,在perlcall手冊中。
我將在文件<el>showtime.pl</el>中定義showtime函數(shù):
print "I shan't be printed.";
sub showtime { print time; }
足夠簡單。現(xiàn)在編譯并運行:
% cc -o interp interp.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
% showtime showtime.pl 818284590
返回從1970年1月1日 (Unix epoch開始時間)到現(xiàn)在我正在執(zhí)行程序語句的時間。
在這一部分,我們不需要調(diào)用perl_run,但是通常好的編程習慣來保證正確的使用庫是好的,包括對所有的對象調(diào)用 DESTROY 方法以及塊的END {}。
如果你想傳遞參數(shù)給Perl函數(shù),你可以填加以NULL結(jié)尾的args表給perl_call_argv。為了其它數(shù)據(jù)類型或者測試返回值,你將需要操作Perl的棧。那將在本文檔最后的章節(jié)進行討論: 在你的C程序中操作Perl的棧。
--------------------------------------------------------------------------------
在你的C程序中執(zhí)行一個Perl表達式
Perl提供了兩個API函數(shù)來執(zhí)行Perl代碼片斷。它們是perl_eval_sv 和 perl_eval_pv。
經(jīng)常的情況是,你只需要在程序中執(zhí)行一塊的Perl代碼。它可以如你所愿的長:它可以包括 u、require和 do 用來包含其它的外部Perl文件。
perl_eval_pv 可以讓我執(zhí)行單獨的Perl語句,然后把執(zhí)行結(jié)果變量返回成C的形式。下面的程序 string.c,執(zhí)行三個Perl語句, 從第一個取得int,從第二個取回float, 從第三個取回char *。
#include <EXTERN.h> #include <perl.h> static PerlInterpreter *my_perl; int main(int argc, char **argv, char **env) { STRLEN n_a; char *embedding[] = { "", "-e", "0" }; my_perl = perl_alloc(); perl_construct(my_perl); perl_par(my_perl, NULL, 3, embedding, NULL); perl_run(my_perl); /** Treat $a as an integer **/ perl_eval_pv("$a = 3; $a **= 2", TRUE); printf("a = %d\n", SvIV(perl_get_sv("a", FALSE))); /** Treat $a as a float **/ perl_eval_pv("$a = 3; $a **= 2", TRUE); printf("a = %f\n", SvNV(perl_get_sv("a", FALSE))); /** Treat $a as a float **/ perl_eval_pv("$a = 'rekcaH lreP rehtonA tsuJ'; $a = rever($a);", TRUE); printf("a = %s\n", SvPV(perl_get_sv("a", FALSE), n_a)); perl_destruct(my_perl); perl_free(my_perl); }
所有這些名字中含有 sv 的這些怪函數(shù)都幫助把Perl的標量返回成C的類型。它們在 perlguts手冊里有描述。
如果你編譯并運行string.c,你將看到 SvIV()創(chuàng)建整數(shù),SvNV()創(chuàng)建浮點數(shù),以及SvPV()創(chuàng)建一個字符串:
a = 9 a = 9 a = Just Another Perl Hacker
在上例中,我們創(chuàng)建了一個全局的變量來保存我們表達式執(zhí)行的結(jié)果。在很多情形下,通過perl_eval_pv()的執(zhí)行結(jié)果來取回返回值,也不錯。如:
... STRLEN n_a; SV *val = perl_eval_pv("rever 'rekcaH lreP rehtonA tsuJ'", TRUE); printf("%s\n", SvPV(val,n_a)); ...
這種方法,我們通過不創(chuàng)建全局變量以及簡化我們的化碼,避免了名字空間污染。
如何在C程序中嵌入Perl
如果你編譯本文檔中的腳本有困難。那么你不是一個人在戰(zhàn)斗。記住重要原則: 以編譯你的perl的方式,編譯你的程序(不好意思)
并且,每一個使用了Perl的C程序都必須連接 perl 庫. 你問,那是什么?Perl本身就是用C寫的。Perl庫是編譯過的用來創(chuàng)建Perl可執(zhí)行程序的C程序集合 (/usr/bin/perl或者類似的)。(結(jié)論:你不能在沒有編譯過或者正確安裝過Perl的系統(tǒng)中編譯嵌入了Perl的C程序。不正確安裝指,只是復(fù)制了Perl的二進制可執(zhí)行文件而沒有復(fù)制perl的庫目錄。)
當你在C中使用Perl時, 你的C程序?qū)⒁?-通常--需要創(chuàng)建、執(zhí)行,然后銷毀一個 Perl解釋器
如果你的Perl烤備足夠新到包含本文檔 (版本5.002或者更新), 則Perl庫 (以及你將需要的EXTERN.h 和 perl.h) 將會在類似這樣的目錄中:
/usr/local/lib/perl5/your_architecture_here/CORE
或者可能就直接是
/usr/local/lib/perl5/your_architecture_here/CORE
或者可能類似
/usr/opt/perl5/CORE
執(zhí)行這個表達式可以定位這個目錄:
perl -MConfig -e 'print $Config{archlib}'
這是如何編譯下節(jié)的示例代碼:往你的C程序中墻加一個Perl解釋器的語句,在我的linux機器上是這樣:
% gcc -O2 -Dbool=char -DHAS_BOOL -I/usr/local/include -I/usr/local/lib/perl5/i586-linux/5.003/CORE -I/usr/local/lib/perl5/i586-linux/5.003/CORE -o interp interp.c -lperl -lm
(那些是一行。) 在我跑著老版本perl 5.003_05的DEC Alpha機器上, 有一點點兒不一樣:
% cc -O2 -Olimit 2900 -DSTANDARD_C -I/usr/local/include -I/usr/local/lib/perl5/alpha-dec_osf/5.00305/CORE -L/usr/local/lib/perl5/alpha-dec_osf/5.00305/CORE -L/usr/local/lib -D__LANGUAGE_C__ -D_NO_PROTO -o interp interp.c -lperl -lm
你如何找出需要填加什么?如果你的Perl版本高于5.001, 執(zhí)行 perl -V 命令,注意一下它的有關(guān)``cc'' 和 ``ccflags''的信息。
你將不得不根據(jù)你的系統(tǒng)選擇適當?shù)木幾g器。 (cc,gcc,等等。) : perl -MConfig -e 'print $Config{cc}' 將告訴你用什么。
你還得根據(jù)你的系統(tǒng)選擇正確的Perl庫目錄 (/usr/local/lib/...) 如果你的編譯器抱怨有函數(shù)未定義,或者它不能定位 -lperl,則你需要用-L手動指定庫文件路徑。如果它抱怨找不到EXTERN.h 和 perl.h,你需要用-I手動指定頭文件路徑。
你可能還需要如法增加其它庫哪些?可能包括這行指令打印出的這些:
perl -MConfig -e 'print $Config{archlib}'
如果你的perl配置安裝無誤,則模塊ExtUtils::Embed將為你檢測出你需要的所有信息。
% cc -o interp interp.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
如果ExtUtils::Embed不包含在你的perl發(fā)行版中, 你可以從http://www.perl.com/perl/CPAN/modules/by-module/ExtUtils/.下載它 (如果本文檔來自你的perl發(fā)行版,則你已經(jīng)安裝了perl 5.004或者更高的版本,并且你肯定有這個模塊)
CPAN上的ExtUtils::Embed,包括了有關(guān)本文檔的所有的源碼、測試以及其它對你有用的示例程序。
--------------------------------------------------------------------------------
往你的C程序中增加一個Perl解釋器
通常, perl (C源程序) 是一個嵌入Perl(語言)的好例子,所以我將示范一個miniperlmain.c。當然,它不太標準,也不太精巧。
#include <EXTERN.h> /* from the Perl distribution */ #include <EXTERN.h> /* from the Perl distribution */
static PerlInterpreter *my_perl; /*** The Perl interpreter ***/
int main(int argc, char **argv, char **env) { my_perl = perl_alloc(); perl_construct(my_perl); perl_par(my_perl, NULL, argc, argv, (char **)NULL); perl_run(my_perl); perl_destruct(my_perl); perl_free(my_perl); }
注意我們沒有使用env指針。通常做為perl_par的最后一個選項, env參數(shù)為NULL,代表使用當前的環(huán)境變量。
現(xiàn)在編譯它 (我將叫它 interp.c)為可執(zhí)行文件:
% cc -o interp interp.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
經(jīng)過成功的編譯以后, 你將可以像使用perl一樣地使用interp。
% interp print "Pretty Good Perl \n"; print "10890 - 9801 is ", 10890 - 9801; <CTRL-D> Pretty Good Perl 10890 - 9801 is 1089
或者
% interp -e 'printf("%x", 3735928559)' deadbeef
你也可以通過在調(diào)用perl_fun以前替換argv[1],在C程序里從一個文件中讀取然后執(zhí)行Perl代碼。
--------------------------------------------------------------------------------
在你的C程序中調(diào)用一個Perl子程序
為了調(diào)用獨立的Perl子程序,你可以使用任何<al>perlcall手冊</al>中的perl_call_*類型的函數(shù)。在此例中,我們將使用perl_call_argv。
它們將在下面這個我叫做showtime.c的程序中中展現(xiàn)。
#include <EXTERN.h> #include <perl.h>
static PerlInterpreter *my_perl;
int main(int argc, char **argv, char **env) { char *args[] = { NULL }; my_perl = perl_alloc(); perl_construct(my_perl);
perl_par(my_perl, NULL, argc, argv, (char **)NULL);
/*** skipping perl_run() ***/
perl_call_argv("showtime", G_DISCARD | G_NOARGS, args);
perl_destruct(my_perl); perl_free(my_perl); }
showtime是一個Perl子程序,它沒有參數(shù)。 (它是 G_NOARGS) 并且我將忽略它的返回值 (它是G_DISCARD). 那些標記,以及其它一些標記,在perlcall手冊中。
我將在文件<el>showtime.pl</el>中定義showtime函數(shù):
print "I shan't be printed.";
sub showtime { print time; }
足夠簡單。現(xiàn)在編譯并運行:
% cc -o interp interp.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
% showtime showtime.pl 818284590
返回從1970年1月1日 (Unix epoch開始時間)到現(xiàn)在我正在執(zhí)行程序語句的時間。
在這一部分,我們不需要調(diào)用perl_run,但是通常好的編程習慣來保證正確的使用庫是好的,包括對所有的對象調(diào)用 DESTROY 方法以及塊的END {}。
如果你想傳遞參數(shù)給Perl函數(shù),你可以填加以NULL結(jié)尾的args表給perl_call_argv。為了其它數(shù)據(jù)類型或者測試返回值,你將需要操作Perl的棧。那將在本文檔最后的章節(jié)進行討論: 在你的C程序中操作Perl的棧。
--------------------------------------------------------------------------------
在你的C程序中執(zhí)行一個Perl表達式
Perl提供了兩個API函數(shù)來執(zhí)行Perl代碼片斷。它們是perl_eval_sv 和 perl_eval_pv。
經(jīng)常的情況是,你只需要在程序中執(zhí)行一塊的Perl代碼。它可以如你所愿的長:它可以包括 u、require和 do 用來包含其它的外部Perl文件。
perl_eval_pv 可以讓我執(zhí)行單獨的Perl語句,然后把執(zhí)行結(jié)果變量返回成C的形式。下面的程序 string.c,執(zhí)行三個Perl語句, 從第一個取得int,從第二個取回float, 從第三個取回char *。
#include <EXTERN.h> #include <perl.h> static PerlInterpreter *my_perl; int main(int argc, char **argv, char **env) { STRLEN n_a; char *embedding[] = { "", "-e", "0" }; my_perl = perl_alloc(); perl_construct(my_perl); perl_par(my_perl, NULL, 3, embedding, NULL); perl_run(my_perl); /** Treat $a as an integer **/ perl_eval_pv("$a = 3; $a **= 2", TRUE); printf("a = %d\n", SvIV(perl_get_sv("a", FALSE))); /** Treat $a as a float **/ perl_eval_pv("$a = 3; $a **= 2", TRUE); printf("a = %f\n", SvNV(perl_get_sv("a", FALSE))); /** Treat $a as a float **/ perl_eval_pv("$a = 'rekcaH lreP rehtonA tsuJ'; $a = rever($a);", TRUE); printf("a = %s\n", SvPV(perl_get_sv("a", FALSE), n_a)); perl_destruct(my_perl); perl_free(my_perl); }
所有這些名字中含有 sv 的這些怪函數(shù)都幫助把Perl的標量返回成C的類型。它們在 perlguts手冊里有描述。
如果你編譯并運行string.c,你將看到 SvIV()創(chuàng)建整數(shù),SvNV()創(chuàng)建浮點數(shù),以及SvPV()創(chuàng)建一個字符串:
a = 9 a = 9 a = Just Another Perl Hacker
在上例中,我們創(chuàng)建了一個全局的變量來保存我們表達式執(zhí)行的結(jié)果。在很多情形下,通過perl_eval_pv()的執(zhí)行結(jié)果來取回返回值,也不錯。如:
... STRLEN n_a; SV *val = perl_eval_pv("rever 'rekcaH lreP rehtonA tsuJ'", TRUE); printf("%s\n", SvPV(val,n_a)); ...
這種方法,我們通過不創(chuàng)建全局變量以及簡化我們的化碼,避免了名字空間污染。
如何在C程序中嵌入Perl
如果你編譯本文檔中的腳本有困難。那么你不是一個人在戰(zhàn)斗。記住重要原則: 以編譯你的perl的方式,編譯你的程序(不好意思)
并且,每一個使用了Perl的C程序都必須連接 perl 庫. 你問,那是什么?Perl本身就是用C寫的。Perl庫是編譯過的用來創(chuàng)建Perl可執(zhí)行程序的C程序集合 (/usr/bin/perl或者類似的)。(結(jié)論:你不能在沒有編譯過或者正確安裝過Perl的系統(tǒng)中編譯嵌入了Perl的C程序。不正確安裝指,只是復(fù)制了Perl的二進制可執(zhí)行文件而沒有復(fù)制perl的庫目錄。)
當你在C中使用Perl時, 你的C程序?qū)⒁?-通常--需要創(chuàng)建、執(zhí)行,然后銷毀一個 Perl解釋器
如果你的Perl烤備足夠新到包含本文檔 (版本5.002或者更新), 則Perl庫 (以及你將需要的EXTERN.h 和 perl.h) 將會在類似這樣的目錄中:
/usr/local/lib/perl5/your_architecture_here/CORE
或者可能就直接是
/usr/local/lib/perl5/your_architecture_here/CORE
或者可能類似
/usr/opt/perl5/CORE
執(zhí)行這個表達式可以定位這個目錄:
perl -MConfig -e 'print $Config{archlib}'
這是如何編譯下節(jié)的示例代碼:往你的C程序中墻加一個Perl解釋器的語句,在我的linux機器上是這樣:
% gcc -O2 -Dbool=char -DHAS_BOOL -I/usr/local/include -I/usr/local/lib/perl5/i586-linux/5.003/CORE -I/usr/local/lib/perl5/i586-linux/5.003/CORE -o interp interp.c -lperl -lm
(那些是一行。) 在我跑著老版本perl 5.003_05的DEC Alpha機器上, 有一點點兒不一樣:
% cc -O2 -Olimit 2900 -DSTANDARD_C -I/usr/local/include -I/usr/local/lib/perl5/alpha-dec_osf/5.00305/CORE -L/usr/local/lib/perl5/alpha-dec_osf/5.00305/CORE -L/usr/local/lib -D__LANGUAGE_C__ -D_NO_PROTO -o interp interp.c -lperl -lm
你如何找出需要填加什么?如果你的Perl版本高于5.001, 執(zhí)行 perl -V 命令,注意一下它的有關(guān)``cc'' 和 ``ccflags''的信息。
你將不得不根據(jù)你的系統(tǒng)選擇適當?shù)木幾g器。 (cc,gcc,等等。) : perl -MConfig -e 'print $Config{cc}' 將告訴你用什么。
你還得根據(jù)你的系統(tǒng)選擇正確的Perl庫目錄 (/usr/local/lib/...) 如果你的編譯器抱怨有函數(shù)未定義,或者它不能定位 -lperl,則你需要用-L手動指定庫文件路徑。如果它抱怨找不到EXTERN.h 和 perl.h,你需要用-I手動指定頭文件路徑。
你可能還需要如法增加其它庫哪些?可能包括這行指令打印出的這些:
perl -MConfig -e 'print $Config{archlib}'
如果你的perl配置安裝無誤,則模塊ExtUtils::Embed將為你檢測出你需要的所有信息。
% cc -o interp interp.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
如果ExtUtils::Embed不包含在你的perl發(fā)行版中, 你可以從http://www.perl.com/perl/CPAN/modules/by-module/ExtUtils/.下載它 (如果本文檔來自你的perl發(fā)行版,則你已經(jīng)安裝了perl 5.004或者更高的版本,并且你肯定有這個模塊)
CPAN上的ExtUtils::Embed,包括了有關(guān)本文檔的所有的源碼、測試以及其它對你有用的示例程序。
--------------------------------------------------------------------------------
往你的C程序中增加一個Perl解釋器
通常, perl (C源程序) 是一個嵌入Perl(語言)的好例子,所以我將示范一個miniperlmain.c。當然,它不太標準,也不太精巧。
#include <EXTERN.h> /* from the Perl distribution */ #include <EXTERN.h> /* from the Perl distribution */
static PerlInterpreter *my_perl; /*** The Perl interpreter ***/
int main(int argc, char **argv, char **env) { my_perl = perl_alloc(); perl_construct(my_perl); perl_par(my_perl, NULL, argc, argv, (char **)NULL); perl_run(my_perl); perl_destruct(my_perl); perl_free(my_perl); }
注意我們沒有使用env指針。通常做為perl_par的最后一個選項, env參數(shù)為NULL,代表使用當前的環(huán)境變量。
現(xiàn)在編譯它 (我將叫它 interp.c)為可執(zhí)行文件:
% cc -o interp interp.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
經(jīng)過成功的編譯以后, 你將可以像使用perl一樣地使用interp。
% interp print "Pretty Good Perl \n"; print "10890 - 9801 is ", 10890 - 9801; <CTRL-D> Pretty Good Perl 10890 - 9801 is 1089
或者
% interp -e 'printf("%x", 3735928559)' deadbeef
你也可以通過在調(diào)用perl_fun以前替換argv[1],在C程序里從一個文件中讀取然后執(zhí)行Perl代碼。
--------------------------------------------------------------------------------
在你的C程序中調(diào)用一個Perl子程序
為了調(diào)用獨立的Perl子程序,你可以使用任何<al>perlcall手冊</al>中的perl_call_*類型的函數(shù)。在此例中,我們將使用perl_call_argv。
它們將在下面這個我叫做showtime.c的程序中中展現(xiàn)。
#include <EXTERN.h> #include <perl.h>
static PerlInterpreter *my_perl;
int main(int argc, char **argv, char **env) { char *args[] = { NULL }; my_perl = perl_alloc(); perl_construct(my_perl);
perl_par(my_perl, NULL, argc, argv, (char **)NULL);
/*** skipping perl_run() ***/
perl_call_argv("showtime", G_DISCARD | G_NOARGS, args);
perl_destruct(my_perl); perl_free(my_perl); }
showtime是一個Perl子程序,它沒有參數(shù)。 (它是 G_NOARGS) 并且我將忽略它的返回值 (它是G_DISCARD). 那些標記,以及其它一些標記,在perlcall手冊中。
我將在文件<el>showtime.pl</el>中定義showtime函數(shù):
print "I shan't be printed.";
sub showtime { print time; }
足夠簡單。現(xiàn)在編譯并運行:
% cc -o interp interp.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
% showtime showtime.pl 818284590
返回從1970年1月1日 (Unix epoch開始時間)到現(xiàn)在我正在執(zhí)行程序語句的時間。
在這一部分,我們不需要調(diào)用perl_run,但是通常好的編程習慣來保證正確的使用庫是好的,包括對所有的對象調(diào)用 DESTROY 方法以及塊的END {}。
如果你想傳遞參數(shù)給Perl函數(shù),你可以填加以NULL結(jié)尾的args表給perl_call_argv。為了其它數(shù)據(jù)類型或者測試返回值,你將需要操作Perl的棧。那將在本文檔最后的章節(jié)進行討論: 在你的C程序中操作Perl的棧。
--------------------------------------------------------------------------------
在你的C程序中執(zhí)行一個Perl表達式
Perl提供了兩個API函數(shù)來執(zhí)行Perl代碼片斷。它們是perl_eval_sv 和 perl_eval_pv。
經(jīng)常的情況是,你只需要在程序中執(zhí)行一塊的Perl代碼。它可以如你所愿的長:它可以包括 u、require和 do 用來包含其它的外部Perl文件。
perl_eval_pv 可以讓我執(zhí)行單獨的Perl語句,然后把執(zhí)行結(jié)果變量返回成C的形式。下面的程序 string.c,執(zhí)行三個Perl語句, 從第一個取得int,從第二個取回float, 從第三個取回char *。
#include <EXTERN.h> #include <perl.h> static PerlInterpreter *my_perl; int main(int argc, char **argv, char **env) { STRLEN n_a; char *embedding[] = { "", "-e", "0" }; my_perl = perl_alloc(); perl_construct(my_perl); perl_par(my_perl, NULL, 3, embedding, NULL); perl_run(my_perl); /** Treat $a as an integer **/ perl_eval_pv("$a = 3; $a **= 2", TRUE); printf("a = %d\n", SvIV(perl_get_sv("a", FALSE))); /** Treat $a as a float **/ perl_eval_pv("$a = 3; $a **= 2", TRUE); printf("a = %f\n", SvNV(perl_get_sv("a", FALSE))); /** Treat $a as a float **/ perl_eval_pv("$a = 'rekcaH lreP rehtonA tsuJ'; $a = rever($a);", TRUE); printf("a = %s\n", SvPV(perl_get_sv("a", FALSE), n_a)); perl_destruct(my_perl); perl_free(my_perl); }
所有這些名字中含有 sv 的這些怪函數(shù)都幫助把Perl的標量返回成C的類型。它們在 perlguts手冊里有描述。
如果你編譯并運行string.c,你將看到 SvIV()創(chuàng)建整數(shù),SvNV()創(chuàng)建浮點數(shù),以及SvPV()創(chuàng)建一個字符串:
a = 9 a = 9 a = Just Another Perl Hacker
在上例中,我們創(chuàng)建了一個全局的變量來保存我們表達式執(zhí)行的結(jié)果。在很多情形下,通過perl_eval_pv()的執(zhí)行結(jié)果來取回返回值,也不錯。如:
... STRLEN n_a; SV *val = perl_eval_pv("rever 'rekcaH lreP rehtonA tsuJ'", TRUE); printf("%s\n", SvPV(val,n_a)); ...
這種方法,我們通過不創(chuàng)建全局變量以及簡化我們的化碼,避免了名字空間污染。
如何在C程序中嵌入Perl
如果你編譯本文檔中的腳本有困難。那么你不是一個人在戰(zhàn)斗。記住重要原則: 以編譯你的perl的方式,編譯你的程序(不好意思)
并且,每一個使用了Perl的C程序都必須連接 perl 庫. 你問,那是什么?Perl本身就是用C寫的。Perl庫是編譯過的用來創(chuàng)建Perl可執(zhí)行程序的C程序集合 (/usr/bin/perl或者類似的)。(結(jié)論:你不能在沒有編譯過或者正確安裝過Perl的系統(tǒng)中編譯嵌入了Perl的C程序。不正確安裝指,只是復(fù)制了Perl的二進制可執(zhí)行文件而沒有復(fù)制perl的庫目錄。)
當你在C中使用Perl時, 你的C程序?qū)⒁?-通常--需要創(chuàng)建、執(zhí)行,然后銷毀一個 Perl解釋器
如果你的Perl烤備足夠新到包含本文檔 (版本5.002或者更新), 則Perl庫 (以及你將需要的EXTERN.h 和 perl.h) 將會在類似這樣的目錄中:
/usr/local/lib/perl5/your_architecture_here/CORE
或者可能就直接是
/usr/local/lib/perl5/your_architecture_here/CORE
或者可能類似
/usr/opt/perl5/CORE
執(zhí)行這個表達式可以定位這個目錄:
perl -MConfig -e 'print $Config{archlib}'
這是如何編譯下節(jié)的示例代碼:往你的C程序中墻加一個Perl解釋器的語句,在我的linux機器上是這樣:
% gcc -O2 -Dbool=char -DHAS_BOOL -I/usr/local/include -I/usr/local/lib/perl5/i586-linux/5.003/CORE -I/usr/local/lib/perl5/i586-linux/5.003/CORE -o interp interp.c -lperl -lm
(那些是一行。) 在我跑著老版本perl 5.003_05的DEC Alpha機器上, 有一點點兒不一樣:
% cc -O2 -Olimit 2900 -DSTANDARD_C -I/usr/local/include -I/usr/local/lib/perl5/alpha-dec_osf/5.00305/CORE -L/usr/local/lib/perl5/alpha-dec_osf/5.00305/CORE -L/usr/local/lib -D__LANGUAGE_C__ -D_NO_PROTO -o interp interp.c -lperl -lm
你如何找出需要填加什么?如果你的Perl版本高于5.001, 執(zhí)行 perl -V 命令,注意一下它的有關(guān)``cc'' 和 ``ccflags''的信息。
你將不得不根據(jù)你的系統(tǒng)選擇適當?shù)木幾g器。 (cc,gcc,等等。) : perl -MConfig -e 'print $Config{cc}' 將告訴你用什么。
你還得根據(jù)你的系統(tǒng)選擇正確的Perl庫目錄 (/usr/local/lib/...) 如果你的編譯器抱怨有函數(shù)未定義,或者它不能定位 -lperl,則你需要用-L手動指定庫文件路徑。如果它抱怨找不到EXTERN.h 和 perl.h,你需要用-I手動指定頭文件路徑。
你可能還需要如法增加其它庫哪些?可能包括這行指令打印出的這些:
perl -MConfig -e 'print $Config{archlib}'
如果你的perl配置安裝無誤,則模塊ExtUtils::Embed將為你檢測出你需要的所有信息。
% cc -o interp interp.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
如果ExtUtils::Embed不包含在你的perl發(fā)行版中, 你可以從http://www.perl.com/perl/CPAN/modules/by-module/ExtUtils/.下載它 (如果本文檔來自你的perl發(fā)行版,則你已經(jīng)安裝了perl 5.004或者更高的版本,并且你肯定有這個模塊)
CPAN上的ExtUtils::Embed,包括了有關(guān)本文檔的所有的源碼、測試以及其它對你有用的示例程序。
--------------------------------------------------------------------------------
往你的C程序中增加一個Perl解釋器
通常, perl (C源程序) 是一個嵌入Perl(語言)的好例子,所以我將示范一個miniperlmain.c。當然,它不太標準,也不太精巧。
#include <EXTERN.h> /* from the Perl distribution */ #include <EXTERN.h> /* from the Perl distribution */
static PerlInterpreter *my_perl; /*** The Perl interpreter ***/
int main(int argc, char **argv, char **env) { my_perl = perl_alloc(); perl_construct(my_perl); perl_par(my_perl, NULL, argc, argv, (char **)NULL); perl_run(my_perl); perl_destruct(my_perl); perl_free(my_perl); }
注意我們沒有使用env指針。通常做為perl_par的最后一個選項, env參數(shù)為NULL,代表使用當前的環(huán)境變量。
現(xiàn)在編譯它 (我將叫它 interp.c)為可執(zhí)行文件:
% cc -o interp interp.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
經(jīng)過成功的編譯以后, 你將可以像使用perl一樣地使用interp。
% interp print "Pretty Good Perl \n"; print "10890 - 9801 is ", 10890 - 9801; <CTRL-D> Pretty Good Perl 10890 - 9801 is 1089
或者
% interp -e 'printf("%x", 3735928559)' deadbeef
你也可以通過在調(diào)用perl_fun以前替換argv[1],在C程序里從一個文件中讀取然后執(zhí)行Perl代碼。
--------------------------------------------------------------------------------
在你的C程序中調(diào)用一個Perl子程序
為了調(diào)用獨立的Perl子程序,你可以使用任何<al>perlcall手冊</al>中的perl_call_*類型的函數(shù)。在此例中,我們將使用perl_call_argv。
它們將在下面這個我叫做showtime.c的程序中中展現(xiàn)。
#include <EXTERN.h> #include <perl.h>
static PerlInterpreter *my_perl;
int main(int argc, char **argv, char **env) { char *args[] = { NULL }; my_perl = perl_alloc(); perl_construct(my_perl);
perl_par(my_perl, NULL, argc, argv, (char **)NULL);
/*** skipping perl_run() ***/
perl_call_argv("showtime", G_DISCARD | G_NOARGS, args);
perl_destruct(my_perl); perl_free(my_perl); }
showtime是一個Perl子程序,它沒有參數(shù)。 (它是 G_NOARGS) 并且我將忽略它的返回值 (它是G_DISCARD). 那些標記,以及其它一些標記,在perlcall手冊中。
我將在文件<el>showtime.pl</el>中定義showtime函數(shù):
print "I shan't be printed.";
sub showtime { print time; }
足夠簡單。現(xiàn)在編譯并運行:
% cc -o interp interp.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
% showtime showtime.pl 818284590
返回從1970年1月1日 (Unix epoch開始時間)到現(xiàn)在我正在執(zhí)行程序語句的時間。
在這一部分,我們不需要調(diào)用perl_run,但是通常好的編程習慣來保證正確的使用庫是好的,包括對所有的對象調(diào)用 DESTROY 方法以及塊的END {}。
如果你想傳遞參數(shù)給Perl函數(shù),你可以填加以NULL結(jié)尾的args表給perl_call_argv。為了其它數(shù)據(jù)類型或者測試返回值,你將需要操作Perl的棧。那將在本文檔最后的章節(jié)進行討論: 在你的C程序中操作Perl的棧。
--------------------------------------------------------------------------------
在你的C程序中執(zhí)行一個Perl表達式
Perl提供了兩個API函數(shù)來執(zhí)行Perl代碼片斷。它們是perl_eval_sv 和 perl_eval_pv。
經(jīng)常的情況是,你只需要在程序中執(zhí)行一塊的Perl代碼。它可以如你所愿的長:它可以包括 u、require和 do 用來包含其它的外部Perl文件。
perl_eval_pv 可以讓我執(zhí)行單獨的Perl語句,然后把執(zhí)行結(jié)果變量返回成C的形式。下面的程序 string.c,執(zhí)行三個Perl語句, 從第一個取得int,從第二個取回float, 從第三個取回char *。
#include <EXTERN.h> #include <perl.h> static PerlInterpreter *my_perl; int main(int argc, char **argv, char **env) { STRLEN n_a; char *embedding[] = { "", "-e", "0" }; my_perl = perl_alloc(); perl_construct(my_perl); perl_par(my_perl, NULL, 3, embedding, NULL); perl_run(my_perl); /** Treat $a as an integer **/ perl_eval_pv("$a = 3; $a **= 2", TRUE); printf("a = %d\n", SvIV(perl_get_sv("a", FALSE))); /** Treat $a as a float **/ perl_eval_pv("$a = 3; $a **= 2", TRUE); printf("a = %f\n", SvNV(perl_get_sv("a", FALSE))); /** Treat $a as a float **/ perl_eval_pv("$a = 'rekcaH lreP rehtonA tsuJ'; $a = rever($a);", TRUE); printf("a = %s\n", SvPV(perl_get_sv("a", FALSE), n_a)); perl_destruct(my_perl); perl_free(my_perl); }
所有這些名字中含有 sv 的這些怪函數(shù)都幫助把Perl的標量返回成C的類型。它們在 perlguts手冊里有描述。
如果你編譯并運行string.c,你將看到 SvIV()創(chuàng)建整數(shù),SvNV()創(chuàng)建浮點數(shù),以及SvPV()創(chuàng)建一個字符串:
a = 9 a = 9 a = Just Another Perl Hacker
在上例中,我們創(chuàng)建了一個全局的變量來保存我們表達式執(zhí)行的結(jié)果。在很多情形下,通過perl_eval_pv()的執(zhí)行結(jié)果來取回返回值,也不錯。如:
... STRLEN n_a; SV *val = perl_eval_pv("rever 'rekcaH lreP rehtonA tsuJ'", TRUE); printf("%s\n", SvPV(val,n_a)); ...
這種方法,我們通過不創(chuàng)建全局變量以及簡化我們的化碼,避免了名字空間污染。
如何在C程序中嵌入Perl
如果你編譯本文檔中的腳本有困難。那么你不是一個人在戰(zhàn)斗。記住重要原則: 以編譯你的perl的方式,編譯你的程序(不好意思)
并且,每一個使用了Perl的C程序都必須連接 perl 庫. 你問,那是什么?Perl本身就是用C寫的。Perl庫是編譯過的用來創(chuàng)建Perl可執(zhí)行程序的C程序集合 (/usr/bin/perl或者類似的)。(結(jié)論:你不能在沒有編譯過或者正確安裝過Perl的系統(tǒng)中編譯嵌入了Perl的C程序。不正確安裝指,只是復(fù)制了Perl的二進制可執(zhí)行文件而沒有復(fù)制perl的庫目錄。)
當你在C中使用Perl時, 你的C程序?qū)⒁?-通常--需要創(chuàng)建、執(zhí)行,然后銷毀一個 Perl解釋器
如果你的Perl烤備足夠新到包含本文檔 (版本5.002或者更新), 則Perl庫 (以及你將需要的EXTERN.h 和 perl.h) 將會在類似這樣的目錄中:
/usr/local/lib/perl5/your_architecture_here/CORE
或者可能就直接是
/usr/local/lib/perl5/your_architecture_here/CORE
或者可能類似
/usr/opt/perl5/CORE
執(zhí)行這個表達式可以定位這個目錄:
perl -MConfig -e 'print $Config{archlib}'
這是如何編譯下節(jié)的示例代碼:往你的C程序中墻加一個Perl解釋器的語句,在我的linux機器上是這樣:
% gcc -O2 -Dbool=char -DHAS_BOOL -I/usr/local/include -I/usr/local/lib/perl5/i586-linux/5.003/CORE -I/usr/local/lib/perl5/i586-linux/5.003/CORE -o interp interp.c -lperl -lm
(那些是一行。) 在我跑著老版本perl 5.003_05的DEC Alpha機器上, 有一點點兒不一樣:
% cc -O2 -Olimit 2900 -DSTANDARD_C -I/usr/local/include -I/usr/local/lib/perl5/alpha-dec_osf/5.00305/CORE -L/usr/local/lib/perl5/alpha-dec_osf/5.00305/CORE -L/usr/local/lib -D__LANGUAGE_C__ -D_NO_PROTO -o interp interp.c -lperl -lm
你如何找出需要填加什么?如果你的Perl版本高于5.001, 執(zhí)行 perl -V 命令,注意一下它的有關(guān)``cc'' 和 ``ccflags''的信息。
你將不得不根據(jù)你的系統(tǒng)選擇適當?shù)木幾g器。 (cc,gcc,等等。) : perl -MConfig -e 'print $Config{cc}' 將告訴你用什么。
你還得根據(jù)你的系統(tǒng)選擇正確的Perl庫目錄 (/usr/local/lib/...) 如果你的編譯器抱怨有函數(shù)未定義,或者它不能定位 -lperl,則你需要用-L手動指定庫文件路徑。如果它抱怨找不到EXTERN.h 和 perl.h,你需要用-I手動指定頭文件路徑。
你可能還需要如法增加其它庫哪些?可能包括這行指令打印出的這些:
perl -MConfig -e 'print $Config{archlib}'
如果你的perl配置安裝無誤,則模塊ExtUtils::Embed將為你檢測出你需要的所有信息。
% cc -o interp interp.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
如果ExtUtils::Embed不包含在你的perl發(fā)行版中, 你可以從http://www.perl.com/perl/CPAN/modules/by-module/ExtUtils/.下載它 (如果本文檔來自你的perl發(fā)行版,則你已經(jīng)安裝了perl 5.004或者更高的版本,并且你肯定有這個模塊)
CPAN上的ExtUtils::Embed,包括了有關(guān)本文檔的所有的源碼、測試以及其它對你有用的示例程序。
--------------------------------------------------------------------------------
往你的C程序中增加一個Perl解釋器
通常, perl (C源程序) 是一個嵌入Perl(語言)的好例子,所以我將示范一個miniperlmain.c。當然,它不太標準,也不太精巧。
#include <EXTERN.h> /* from the Perl distribution */ #include <EXTERN.h> /* from the Perl distribution */
static PerlInterpreter *my_perl; /*** The Perl interpreter ***/
int main(int argc, char **argv, char **env) { my_perl = perl_alloc(); perl_construct(my_perl); perl_par(my_perl, NULL, argc, argv, (char **)NULL); perl_run(my_perl); perl_destruct(my_perl); perl_free(my_perl); }
注意我們沒有使用env指針。通常做為perl_par的最后一個選項, env參數(shù)為NULL,代表使用當前的環(huán)境變量。
現(xiàn)在編譯它 (我將叫它 interp.c)為可執(zhí)行文件:
% cc -o interp interp.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
經(jīng)過成功的編譯以后, 你將可以像使用perl一樣地使用interp。
% interp print "Pretty Good Perl \n"; print "10890 - 9801 is ", 10890 - 9801; <CTRL-D> Pretty Good Perl 10890 - 9801 is 1089
或者
% interp -e 'printf("%x", 3735928559)' deadbeef
你也可以通過在調(diào)用perl_fun以前替換argv[1],在C程序里從一個文件中讀取然后執(zhí)行Perl代碼。
--------------------------------------------------------------------------------
在你的C程序中調(diào)用一個Perl子程序
為了調(diào)用獨立的Perl子程序,你可以使用任何<al>perlcall手冊</al>中的perl_call_*類型的函數(shù)。在此例中,我們將使用perl_call_argv。
它們將在下面這個我叫做showtime.c的程序中中展現(xiàn)。
#include <EXTERN.h> #include <perl.h>
static PerlInterpreter *my_perl;
int main(int argc, char **argv, char **env) { char *args[] = { NULL }; my_perl = perl_alloc(); perl_construct(my_perl);
perl_par(my_perl, NULL, argc, argv, (char **)NULL);
/*** skipping perl_run() ***/
perl_call_argv("showtime", G_DISCARD | G_NOARGS, args);
perl_destruct(my_perl); perl_free(my_perl); }
showtime是一個Perl子程序,它沒有參數(shù)。 (它是 G_NOARGS) 并且我將忽略它的返回值 (它是G_DISCARD). 那些標記,以及其它一些標記,在perlcall手冊中。
我將在文件<el>showtime.pl</el>中定義showtime函數(shù):
print "I shan't be printed.";
sub showtime { print time; }
足夠簡單。現(xiàn)在編譯并運行:
% cc -o interp interp.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
% showtime showtime.pl 818284590
返回從1970年1月1日 (Unix epoch開始時間)到現(xiàn)在我正在執(zhí)行程序語句的時間。
在這一部分,我們不需要調(diào)用perl_run,但是通常好的編程習慣來保證正確的使用庫是好的,包括對所有的對象調(diào)用 DESTROY 方法以及塊的END {}。
如果你想傳遞參數(shù)給Perl函數(shù),你可以填加以NULL結(jié)尾的args表給perl_call_argv。為了其它數(shù)據(jù)類型或者測試返回值,你將需要操作Perl的棧。那將在本文檔最后的章節(jié)進行討論: 在你的C程序中操作Perl的棧。
--------------------------------------------------------------------------------
在你的C程序中執(zhí)行一個Perl表達式
Perl提供了兩個API函數(shù)來執(zhí)行Perl代碼片斷。它們是perl_eval_sv 和 perl_eval_pv。
經(jīng)常的情況是,你只需要在程序中執(zhí)行一塊的Perl代碼。它可以如你所愿的長:它可以包括 u、require和 do 用來包含其它的外部Perl文件。
perl_eval_pv 可以讓我執(zhí)行單獨的Perl語句,然后把執(zhí)行結(jié)果變量返回成C的形式。下面的程序 string.c,執(zhí)行三個Perl語句, 從第一個取得int,從第二個取回float, 從第三個取回char *。
#include <EXTERN.h> #include <perl.h> static PerlInterpreter *my_perl; int main(int argc, char **argv, char **env) { STRLEN n_a; char *embedding[] = { "", "-e", "0" }; my_perl = perl_alloc(); perl_construct(my_perl); perl_par(my_perl, NULL, 3, embedding, NULL); perl_run(my_perl); /** Treat $a as an integer **/ perl_eval_pv("$a = 3; $a **= 2", TRUE); printf("a = %d\n", SvIV(perl_get_sv("a", FALSE))); /** Treat $a as a float **/ perl_eval_pv("$a = 3; $a **= 2", TRUE); printf("a = %f\n", SvNV(perl_get_sv("a", FALSE))); /** Treat $a as a float **/ perl_eval_pv("$a = 'rekcaH lreP rehtonA tsuJ'; $a = rever($a);", TRUE); printf("a = %s\n", SvPV(perl_get_sv("a", FALSE), n_a)); perl_destruct(my_perl); perl_free(my_perl); }
所有這些名字中含有 sv 的這些怪函數(shù)都幫助把Perl的標量返回成C的類型。它們在 perlguts手冊里有描述。
如果你編譯并運行string.c,你將看到 SvIV()創(chuàng)建整數(shù),SvNV()創(chuàng)建浮點數(shù),以及SvPV()創(chuàng)建一個字符串:
a = 9 a = 9 a = Just Another Perl Hacker
在上例中,我們創(chuàng)建了一個全局的變量來保存我們表達式執(zhí)行的結(jié)果。在很多情形下,通過perl_eval_pv()的執(zhí)行結(jié)果來取回返回值,也不錯。如:
... STRLEN n_a; SV *val = perl_eval_pv("rever 'rekcaH lreP rehtonA tsuJ'", TRUE); printf("%s\n", SvPV(val,n_a)); ...
這種方法,我們通過不創(chuàng)建全局變量以及簡化我們的化碼,避免了名字空間污染。