perl C/C++ 扩展(五)
perl 的C++扩展,返回值为自定义类型。
在 perl C/C++扩展(三) 中,我已经介绍了,如何让perl 认识 c++的类,但是前面的介绍中,包括我参考的博客http://chunyemen.org/archives/493,都提到,返回值必须是基础类型。对于开发者而言,如果返回值只能是基础类型,那么对于扩展的开发热情就大大降低了。楼主排除万难,终于在《高级perl编程(第二版)》.((美)simon cozens)一书的第十八章与第二十章中得到些许启发。
下面我来介绍一下玩法。
首先创建一个新的工程,名为Cat
h2xs -A -n Cat
创建好工程后,进入Cat目录
cd Cat
创建一个mylib目录,并将c++代码拷贝到mylib目录下
mkdie mylib
Cat.h
#ifndef INCLUDE_CAT_H
#define INCLUDE_CAT_H 1
#include <iostream>
class Cat
{
public:
Cat(char *,int);
Cat(const Cat &);
void display();
char * getName();
int getAge();
~Cat();
private:
char * name;
int age;
};
#endif
Cat.cpp
#include "Cat.h" Cat::Cat(char * name, int age)
{
this->name = name;
this->age = age;
} Cat::Cat(const Cat & incat)
{
name = incat.name;
age = incat.age;
} void Cat::display()
{
std::cout<<"~~~~~~~~~~~~Cat.display()~~~~~~~~~~~~~~~~~~~~"<<std::endl; std::cout<<"name="<<name<<"\tage="<<age<<std::endl;
} char * Cat::getName()
{
return name;
} int Cat::getAge()
{
return age;
} Cat::~Cat(){}
Animal.h
#ifndef INCLUDE_ANIMAL_H
#define INCLUDE_ANIMAL_H 1
#include <iostream>
#include "Cat.h"
class Animal
{
public:
Animal(char *, int);
void display();
Cat * getAnimal();
Cat * setAnimal(Cat *);
bool haveAnimal();
~Animal();
private:
Cat * cat;
};
#endif
Animal.cpp
#include "Animal.h" Animal::Animal( char * name, int age):
cat( new Cat(name, age) )
{} void Animal::display()
{
std::cout<<"~~~~~~~~~~~Animal.display()~~~~~~~~~~~~~~~~~\n";
cat->display();
} Cat * Animal::getAnimal()
{
return cat;
} Cat * Animal::setAnimal(Cat * lcat)
{
//delete cat;
cat = new Cat(*lcat);
return cat;
} bool Animal::haveAnimal()
{
//return false;
return ;
//throw 1;
} Animal::~Animal()
{
//delete cat;
}
在mylib 目录下创建Makefile.PL 文件
mylib/Makefile.PL
use ExtUtils::MakeMaker;
$Verbose = ;
WriteMakefile(
NAME => 'Animal::mylib',
SKIP => [qw(all static static_lib dynamic dynamic_lib)],
clean => {'FILES' => 'libanimal.so'},
'CC' => 'g++',
); sub MY::top_targets {
'
all :: static
pure_all :: static
static :: libanimal.so
libanimal.so: $(C_FILES)
$(CC) -shared -fpic -g -Wall -o libanimal.so $(C_FILES)
$(RANLIB) libanimal.so
';
}
注意:mylib/Makefile.PL 的16 17 行前的不是空格键,而且table 键,因为这里是Makefile的代码,如果不按照Makefile格式编写,make 操作就会报错
退回Cat 目录
cd ../
创建一个typemap 文件,并写入如下内容。
typemap
TYPEMAP
Cat * ANIMAL_OBJECT OUTPUT
ANIMAL_OBJECT
sv_setref_pv($arg, CLASS, (void *) $var); INPUT
ANIMAL_OBJECT
$var = ($type) SvIV((SV*) SvRV($arg));
这个typemap 文件是让xs 识别新定义的类。在(三)那里是在Makefile.PL 文件中指定了一个perlobject。map的文件,其实内容和这个差不多,我们没有必要定义那么多的别名。
修改Ma ke f ile.PL
1 #use 5.018002;
use ExtUtils::MakeMaker;
# See lib/ExtUtils/MakeMaker.pm for details of how to influence
# the contents of the Makefile that is written.
5 $CC = 'g++';
WriteMakefile(
NAME => 'Cat',
VERSION_FROM => 'lib/Cat.pm', # finds $VERSION
PREREQ_PM => {}, # e.g., Module::Name => 1.1
($] >= 5.005 ? ## Add these new keywords supported since 5.005
(ABSTRACT_FROM => 'lib/Cat.pm', # retrieve abstract from module
AUTHOR => 'chen <chen@>') : ()),
13 LIBS => ['-Lmylib -lanimal'], # e.g., '-lm'
DEFINE => '', # e.g., '-DHAVE_SOMETHING'
15 INC => '-Imylib', # e.g., '-I. -I/usr/include/other'
# Un-comment this if you add C files to link with later:
# OBJECT => '$(O_FILES)', # link all the C files too
18 'XSOPT' => '-C++',
19 'CC' => $CC,
20 'LD' => '$(CC)',
); 23 sub MY::postamble {
24 '
25 mylib/libanimal.so: mylib/Makefile
26 cd mylib && $(MAKE) $(PASSTHRU)
27 ';
28 }
红色的代码为添加或修改代码。注意:26 行代码前是table 键,而不是普通空格
函数 MY::postmable 是往Makefile 文件插入的一段代码,作用是让编译Cat的扩展库之前,首先编译依赖的libanimal.so包。
其余添加的代码主要是定义编译使用g++。再一次提醒,需要注释第一行代码#use 5.018002;
修改Cat.xs 文件
Cat.xs
#ifdef __cplusplus
extern "C"{
#endif #define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#ifdef __cplusplus
}
#endif
#include "ppport.h"
#include "mylib/Cat.h" MODULE = Cat PACKAGE = Cat
Cat *
Cat::new(char * name, int age) void
Cat::display() char *
Cat::getName() int
Cat::getAge() void
Cat::DESTROY()
格式和之前的(三)一样,这里就不再展开讲了。
生成Makefile 文件,编译
perl Makefile.PL && make
割一下############################################################
第二部分,创建Animal的工程
h2xs -A -n Animal
将Cat工程的mylib 软链接过来
ln -sf /home/chen/learn/perl_c/Cat/mylib /home/chen/learn/perl_c/Animal/mylib
创建并编辑typemap
TYPEMAP
Animal * ANIMAL_OBJECT
Cat * CAT_OBJECT OUTPUT
ANIMAL_OBJECT
sv_setref_pv($arg, CLASS, (void *) $var);
CAT_OBJECT
sv_setref_pv($arg, "Cat", (void *) $var); INPUT
ANIMAL_OBJECT
$var = ($type) SvIV((SV*) SvRV($arg));
CAT_OBJECT
$var = ($type) SvIV((SV*) SvRV($arg));
实际上,这里就是本次博客的核心。
我们仔细观察Animal工程的 typemap 和Cat 工程的typemap 有什么不一样。Animal 工程的typemap 多了一个CAT_OBJECT 的定义,并且在 CAT_OBJECT 的 OUTPUT 中(第九行),是写明指向Cat的类。
如果我们仔细看一下前面的Cat 工程编译命令,有
g++ -c -Imylib -D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fstack-protector -fno-strict-aliasing -pipe -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS= -O2 -g -DVERSION=\"0.01\" -DXS_VERSION=\"0.01\" -fPIC "-I/usr/lib/perl/5.18/CORE" Cat.c
Cat.c这个文件是在make 命令执行时产生的文件,我们打开Cat.c 文件查看的话,会发现一些有趣的东西
XS_EUPXS(XS_Cat_new)
{
dVAR; dXSARGS;
if (items != )
croak_xs_usage(cv, "CLASS, name, age");
{
char * CLASS = (char *)SvPV_nolen(ST(0))
;
Cat * RETVAL;
char * name = (char *)SvPV_nolen(ST())
;
int age = (int)SvIV(ST())
; RETVAL = new Cat(name, age);
ST() = sv_newmortal();
sv_setref_pv(ST(0), CLASS, (void *) RETVAL);
}
XSRETURN();
}
上面的代码实际上就是Cat::new() 的真实代码。我们可以发现CLASS 的变量,其实就是一个字符串数组。我在实验过程中,将CLASS 字符串打印了一下,发现原来它记录的就是Cat的工程名“Cat"。
分析到这里,我们就不难反推,如果需要返回值是自定义的类,我们只需要将”CLASS“ 字段写成我们自己的工程名即可。
有兴趣的同学也可以深挖一下,为什么CLASS 会自动识别当前工程名,与(三)的perlobject.map文件中其他玩法。
后面的事情就很简单了,不过是修改Makefile.PL 与 Aniaml.xs 文件
Makefile.PL
1 #use 5.018002;
use ExtUtils::MakeMaker;
# See lib/ExtUtils/MakeMaker.pm for details of how to influence
# the contents of the Makefile that is written.
5 $CC = 'g++';
WriteMakefile(
NAME => 'Animal',
VERSION_FROM => 'lib/Animal.pm', # finds $VERSION
PREREQ_PM => {}, # e.g., Module::Name => 1.1
($] >= 5.005 ? ## Add these new keywords supported since 5.005
(ABSTRACT_FROM => 'lib/Animal.pm', # retrieve abstract from module
AUTHOR => 'chen <chen@>') : ()),
13 LIBS => ['-Lmylib -lanimal'], # e.g., '-lm'
DEFINE => '', # e.g., '-DHAVE_SOMETHING'
15 INC => '-Imylib', # e.g., '-I. -I/usr/include/other'
16 'CC' => $CC,
17 'LD' => '$(CC)',
# Un-comment this if you add C files to link with later:
# OBJECT => '$(O_FILES)', # link all the C files too
20 'XSOPT' => '-C++',
21 #'LDDLFLAGS' => '-r',
); 24 sub MY::postamble {
25 '
26 $(MYEXTLIB): mylib/Makefile
27 cd mylib && $(MAKE) $(PASSTHRU)
28 ';
29 }
红色部分为增改内容。
注意:27行代码前的为table 键,而不是普通空格
Animal.xs
1 #ifdef __cplusplus
2 extern "C"{
3 #endif #define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
9 #ifdef __cplusplus
10 }
11 #endif
#include "ppport.h"
13 #include "mylib/Cat.h"
14 #include "mylib/Animal.h" MODULE = Animal PACKAGE = Animal 18 Animal *
19 Animal::new(char * name, int age)
20
21 void
22 Animal::display()
23
24 Cat *
25 Animal::getAnimal()
26
27 Cat *
28 Animal::setAnimal(Cat * lcat)
29
30 bool
31 Animal::haveAnimal()
32
33 void
34 Animal::DESTROY()
生成Makefile并编译
perl Makefile.PL && make
编写测试代码,test.pl
#!/usr/bin/perl
use Animal;
use Cat;
$animal = new Animal("chen",);
$animal->display();
$cat = $animal->getAnimal();
$cat->display(); $name = $cat->getName(); print $name; $name = "sdjlfa";
$animal->display(); print "~~~~~~###############~~~~~~~~~~~~~~~\n"; $lcat = new Cat("ASKJKLF",);
$lcat->display();
print "~~~~~~###############~~~~~~~~~~~~~~~\n"; $tcat = $animal->setAnimal( $lcat );
$animal->display(); $test = $animal->haveAnimal();
print "@@@@@@@@@$test@@@@@@\n"; $animal2 = $animal; $animal2->display();
添加环境变量
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/home/chen/learn/perl_c/Animal/blib/arch/auto/Animal:/home/chen/learn/perl_c/Animal/mylib:/home/chen/learn/perl_c/Cat/blib/arch/auto/Cat export PERLLIB=${PERLLIB}:/home/chen/learn/perl_c/Animal/lib:/home/chen/learn/perl_c/Cat/lib
Animal 的扩展包动态库在Animal 工程的 blib/arch/auto/Animal 目录下,pm 文件则在 Animal 工程的 lib 目录下
同样,Cat 的扩展包动态库在Cat 工程的blib/arch/auto/Animal 目录下,pm 文件则在 Cat 工程的 lib 目录下
同时需要将libanimal.so 文件添加到LD_LIBRARY_PATH 环境变量中。
运行一下测试程序
perl test.pl
输出:
~~~~~~~~~~~Animal.display()~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~Cat.display()~~~~~~~~~~~~~~~~~~~~
name=chen age=
~~~~~~~~~~~~Cat.display()~~~~~~~~~~~~~~~~~~~~
name=chen age=
~~~~~~~~~~~Animal.display()~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~Cat.display()~~~~~~~~~~~~~~~~~~~~
name=chen age=
chen~~~~~~###############~~~~~~~~~~~~~~~
~~~~~~~~~~~~Cat.display()~~~~~~~~~~~~~~~~~~~~
name=ASKJKLF age=
~~~~~~###############~~~~~~~~~~~~~~~
~~~~~~~~~~~Animal.display()~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~Cat.display()~~~~~~~~~~~~~~~~~~~~
name=ASKJKLF age=
@@@@@@@@@@@@@@
~~~~~~~~~~~Animal.display()~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~Cat.display()~~~~~~~~~~~~~~~~~~~~
name=ASKJKLF age=
测试成功。
perl C/C++ 扩展(五)的更多相关文章
- perl C/C++ 扩展(四)
在前面三篇博客中,我们了解到如何使用c/c++ 扩展自己的perl 库,但是博主在学习过程中,对动态库或静态库的加载不是十分了解,后来自己又细挖一下.后来就有了这篇博文,再后来,没有再后来了,囧!! ...
- perl C/C++ 扩展(二)
第二讲perl 加载c/c++的库 先通过h2xs 创建一个新的工程 h2xs -A -n two_test 进入目录 cd two_test 创建一个mylib文件夹,存放静态库 mkdir myl ...
- perl C/C++ 扩展(三)
第三讲扩展库使用c++实现,在调用函数后,返回对象变量,perl 能正确使用所有对象成员 使用h2xs 命令生成初始文件 h2xs -A -n three_test 登录目录 cd three_tes ...
- Perl中的正则表达式(五)
正则表达式(Regular Expression),在Perl里边通常也叫做模式(Pattern),用来表示匹配(或不匹配)某个字符串的特征模板. 使用简单模式:若模式匹配的对象是$_的内容,只要把模 ...
- perl C/C++ 扩展(一)
通过h2xs 中间件,我们可以快速的使用c或则C++ 库来实现perl 扩展功能 第一讲:跑通hello world 程序******************************我们使用命令:h2 ...
- perl模块安装
转自: http://www.cnblogs.com/itech/archive/2009/08/10/1542832.html http://www.mike.org.cn/blog/index.p ...
- Windows下Memcache的安装及PHP扩展配置
一.下载 找到完整的memcache的Windows安装包,解压放在硬盘上,比如 F:\memcached.exe 二.安装 WIN7 64位双击打开这个exe可能只有一个空的窗口,不能输入任何命令, ...
- Perl中的正则表达式
转自:http://c20031776.blog.163.com/blog/static/684716252013624383887/ Perl 程序中,正则表达式有三种存在形式 分别是 (1 模式匹 ...
- (转载)CSV 文件处理 PERL
http://cn.perlmaven.com/how-to-read-a-csv-file-using-perl http://search.cpan.org/~hmbrand/Text-CSV_X ...
随机推荐
- spark 划分stage Wide vs Narrow Dependencies 窄依赖 宽依赖 解析 作业 job stage 阶段 RDD有向无环图拆分 任务 Task 网络传输和计算开销 任务集 taskset
每个job被划分为多个stage.划分stage的一个主要依据是当前计算因子的输入是否是确定的,如果是则将其分在同一个stage,从而避免多个stage之间的消息传递开销. http://spark. ...
- java之异常的捕获及处理
在java中程序的错误主要是语法错误和语义错误(也就是逻辑错误). java中异常处理语句的格式: try{ //有可能出现异常的语句 }catch(异常类 异常对象){ //编写异常的处理语句 }c ...
- 【智能无线小车系列九】在树莓派上使用USB摄像头
材料准备: 1.树莓派 2.AS 4WD小车 3.WebCam 4.小米移动电源 5.TP—LINK 高增益150MUSB无线网卡 操作流程: 1.将WebCam插上树莓派后,首先要确认树莓派是否支持 ...
- HTML5与php实现消息推送功能
1.html页面basic_sse.html <!DOCTYPE html> <html lang="en"> <head> <meta ...
- Python序列——Unicode
Unicode是什么 Python中的Unicode 编码与解码 在应用中使用Unicode的建议 1. Unicode是什么 Unicode是对字符进行编码的一种标准.而utf8或者utf-8是根据 ...
- [NOIP2011提高组day2]-1-计算系数
1.计算系数 (factor.cpp/c/pas) [问题描述] k n m给定一个多项式(ax+by)^k ,请求出多项式展开后(x^n)*(y^m)项的系数. [输入] 输入文件名为 factor ...
- /dev/sda2 is mounted; will not make a filesystem here!
一定要记住,不可以在分区挂载之后再进行格式化!!在错误提示当中可以看出你的分区已经挂载了.先将这个分区卸载了再重新格式化:umount /dev/sda2mkfs.ext2 /dev/sda2这样就没 ...
- ubuntu安装ros indigo
版本是14.04.1 一.先配置 1.点击新立得软件包管理器,输入密码exbot123, 2,点击最上面一栏的设置,选择软件源,前四个打勾,后一个不打,把sevice america改成mainsev ...
- UVa 11572 唯一的雪花(优化策略)
题目描述: 输入一个长度为n(n<=1000000)的序列A, 找到一个尽量长的连续子序列A(L)-->A(R),是的该序列中没有相同的元素. 输入: T:代表组数 n:代表有n个数 这一 ...
- poj3295 Tautology —— 构造法
题目链接:http://poj.org/problem?id=3295 题意: 输入由p.q.r.s.t.K.A.N.C.E共10个字母组成的逻辑表达式, 其中p.q.r.s.t的值为1(true)或 ...