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 1;//throw 1;
}Animal::~Animal()
{//delete cat;
}

在mylib 目录下创建Makefile.PL 文件

mylib/Makefile.PL

 1 use ExtUtils::MakeMaker;
 2  $Verbose = 1;
 3  WriteMakefile(
 4  NAME   => 'Animal::mylib',
 5  SKIP   => [qw(all static static_lib dynamic dynamic_lib)],
 6  clean  => {'FILES' => 'libanimal.so'},
 7  'CC'   => 'g++',
 8  );
 9
10 sub MY::top_targets {
11 '
12 all :: static
13 pure_all :: static
14 static ::  libanimal.so
15 libanimal.so: $(C_FILES)
16    $(CC) -shared -fpic -g -Wall -o libanimal.so $(C_FILES)
17    $(RANLIB) libanimal.so
18 ';
19 }

注意:mylib/Makefile.PL 的16 17 行前的不是空格键,而且table 键,因为这里是Makefile的代码,如果不按照Makefile格式编写,make 操作就会报错

退回Cat 目录

cd ../

创建一个typemap 文件,并写入如下内容。

typemap

TYPEMAP
Cat * ANIMAL_OBJECTOUTPUT
ANIMAL_OBJECTsv_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;
 2 use ExtUtils::MakeMaker;
 3 # See lib/ExtUtils/MakeMaker.pm for details of how to influence
 4 # the contents of the Makefile that is written.
 5 $CC = 'g++';
 6 WriteMakefile(
 7     NAME              => 'Cat',
 8     VERSION_FROM      => 'lib/Cat.pm', # finds $VERSION
 9     PREREQ_PM         => {}, # e.g., Module::Name => 1.1
10     ($] >= 5.005 ?     ## Add these new keywords supported since 5.005
11       (ABSTRACT_FROM  => 'lib/Cat.pm', # retrieve abstract from module
12        AUTHOR         => 'chen <chen@>') : ()),
13     LIBS              => ['-Lmylib -lanimal'], # e.g., '-lm'
14     DEFINE            => '', # e.g., '-DHAVE_SOMETHING'
15     INC               => '-Imylib', # e.g., '-I. -I/usr/include/other'
16    # Un-comment this if you add C files to link with later:
17     # OBJECT            => '$(O_FILES)', # link all the C files too
18     'XSOPT'           => '-C++',
19     'CC'              => $CC,
20     'LD'              => '$(CC)',
21 );
22
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

 1 TYPEMAP
 2 Animal * ANIMAL_OBJECT
 3 Cat * CAT_OBJECT
 4
 5 OUTPUT
 6 ANIMAL_OBJECT
 7    sv_setref_pv($arg, CLASS, (void *) $var);
 8 CAT_OBJECT
 9    sv_setref_pv($arg, "Cat", (void *) $var);
10
11 INPUT
12 ANIMAL_OBJECT
13    $var = ($type) SvIV((SV*) SvRV($arg));
14 CAT_OBJECT
15    $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=64 -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 != 3)croak_xs_usage(cv,  "CLASS, name, age");{char *   CLASS = (char *)SvPV_nolen(ST(0))
;Cat * RETVAL;char *   name = (char *)SvPV_nolen(ST(1))
;int   age = (int)SvIV(ST(2))
;RETVAL = new Cat(name, age);ST(0) = sv_newmortal();sv_setref_pv(ST(0), CLASS, (void *) RETVAL);}XSRETURN(1);
}

上面的代码实际上就是Cat::new() 的真实代码。我们可以发现CLASS 的变量,其实就是一个字符串数组。我在实验过程中,将CLASS 字符串打印了一下,发现原来它记录的就是Cat的工程名“Cat"。

分析到这里,我们就不难反推,如果需要返回值是自定义的类,我们只需要将”CLASS“ 字段写成我们自己的工程名即可。

有兴趣的同学也可以深挖一下,为什么CLASS 会自动识别当前工程名,与(三)的perlobject.map文件中其他玩法。

后面的事情就很简单了,不过是修改Makefile.PL 与 Aniaml.xs 文件

Makefile.PL

 1 #use 5.018002;
 2 use ExtUtils::MakeMaker;
 3 # See lib/ExtUtils/MakeMaker.pm for details of how to influence
 4 # the contents of the Makefile that is written.
 5 $CC = 'g++';
 6 WriteMakefile(
 7     NAME              => 'Animal',
 8     VERSION_FROM      => 'lib/Animal.pm', # finds $VERSION
 9     PREREQ_PM         => {}, # e.g., Module::Name => 1.1
10     ($] >= 5.005 ?     ## Add these new keywords supported since 5.005
11       (ABSTRACT_FROM  => 'lib/Animal.pm', # retrieve abstract from module
12        AUTHOR         => 'chen <chen@>') : ()),
13     LIBS              => ['-Lmylib -lanimal'], # e.g., '-lm'
14     DEFINE            => '', # e.g., '-DHAVE_SOMETHING'
15     INC               => '-Imylib', # e.g., '-I. -I/usr/include/other'
16     'CC'              => $CC,
17     'LD'              => '$(CC)',
18    # Un-comment this if you add C files to link with later:
19     # OBJECT            => '$(O_FILES)', # link all the C files too
20     'XSOPT'           => '-C++',
21     #'LDDLFLAGS'       => '-r',
22 );
23
24 sub MY::postamble {
25 '
26 $(MYEXTLIB): mylib/Makefile
27    cd mylib && $(MAKE) $(PASSTHRU)
28 ';
29 }

红色部分为增改内容。

注意:27行代码前的为table 键,而不是普通空格

Animal.xs

 1 #ifdef __cplusplus2 extern "C"{3 #endif
 4
 5 #define PERL_NO_GET_CONTEXT
 6 #include "EXTERN.h"
 7 #include "perl.h"
 8 #include "XSUB.h"
 9 #ifdef __cplusplus
10 }
11 #endif
12 #include "ppport.h"
13 #include "mylib/Cat.h"
14 #include "mylib/Animal.h"
15
16 MODULE = Animal      PACKAGE = Animal
17
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

 1 #!/usr/bin/perl
 2 use Animal;
 3 use Cat;
 4 $animal = new Animal("chen",123);
 5 $animal->display();
 6 $cat = $animal->getAnimal();
 7 $cat->display();
 8
 9 $name = $cat->getName();
10
11 print $name;
12
13 $name = "sdjlfa";
14 $animal->display();
15
16 print "~~~~~~###############~~~~~~~~~~~~~~~\n";
17
18 $lcat = new Cat("ASKJKLF",889);
19 $lcat->display();
20 print "~~~~~~###############~~~~~~~~~~~~~~~\n";
21
22 $tcat = $animal->setAnimal( $lcat );
23 $animal->display();
24
25 $test = $animal->haveAnimal();
26 print "@@@@@@@@@$test@@@@@@\n";
27
28
29 $animal2 = $animal;
30
31 $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/Catexport 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=123
~~~~~~~~~~~~Cat.display()~~~~~~~~~~~~~~~~~~~~
name=chen    age=123
~~~~~~~~~~~Animal.display()~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~Cat.display()~~~~~~~~~~~~~~~~~~~~
name=chen    age=123
chen~~~~~~###############~~~~~~~~~~~~~~~
~~~~~~~~~~~~Cat.display()~~~~~~~~~~~~~~~~~~~~
name=ASKJKLF    age=889
~~~~~~###############~~~~~~~~~~~~~~~
~~~~~~~~~~~Animal.display()~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~Cat.display()~~~~~~~~~~~~~~~~~~~~
name=ASKJKLF    age=889
@@@@@@@@@@@@@@
~~~~~~~~~~~Animal.display()~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~Cat.display()~~~~~~~~~~~~~~~~~~~~
name=ASKJKLF    age=889

测试成功。

转载于:https://www.cnblogs.com/chenfool/p/3910452.html

perl C/C++ 扩展(五)相关推荐

  1. python程序的扩展名是perl程序的扩展名是_Python 程序扩展名(py, pyc, pyw, pyo, pyd)及发布程序时的选择...

    扩展名 在写Python程序时我们常见的扩展名是py, pyc,其实还有其他几种扩展名.下面是几种扩展名的用法. py py就是最基本的源码扩展名.windows下直接双击运行会调用python.ex ...

  2. Bootstrap栅格系统扩展 五格

    Bootstrap栅格系统布局的魅力是毋容置疑的,但是再好的东西也会有不完美的地方,比如当布局上需要水平排列5列平分宽度时,bootstrap就显得比较尴尬了,这时候就需要老司机按照它的命名风格自定义 ...

  3. Unity Editor 编辑器扩展 五 EditorGUI

    目录 创建一个窗口添加简单控件 制作一个可以渐入渐出的窗口控件 最后做一个比较炫酷的窗口 创建一个窗口,添加简单控件 在Editor创建脚本GUIWindow1如下,添加一些简单的控件,体验一下他们的 ...

  4. Perl/CGI脚本语言编程学习资料及开发工具下载大全

    Practical Extraction and Report Language Perl 最初的设计者为拉里·沃尔(Larry Wall),它于1987年12月18日发表.Perl借取了C.sed. ...

  5. 各种平台下Perl模块的安装方法

    各种平台下Perl模块的安装方法 来源:http://www.linuxforum.net David lee (2001-04-21 18:11:53) Perl到了第五版增加了模块的概念,用来提供 ...

  6. perl中unicode属性

    http://shouce.jb51.net/perl/PatternMatching.html 第五章 模式匹配 第五章 模式匹配 5.1 正则表达式箴言 5.2 模式匹配操作符 5.2.1 模式修 ...

  7. 安装perl package

    安装perl package[@more@] Perl模块多平台安装方法 出 处:中国Perl协会 FPC(Foundation of Perlchina) 作 者:dlee linuxforum.n ...

  8. Python3 如何优雅地使用正则表达式(详解五)

    非捕获组命名组 精心设计的正则表达式可能会划分很多组,这些组不仅可以匹配相关的子串,还能够对正则表达式本身进行分组和结构化.在复杂的正则表达式中,由于有太多的组,因此通过组的序号来跟踪和使用会变得困难 ...

  9. Windows下Memcache的安装及PHP扩展配置方法

    这篇文章主要介绍了Windows下Memcache的安装及PHP扩展配置方法,需要的朋友可以参考下 一.下载 找到完整的memcache的Windows安装包,解压放在硬盘上,比如 F:\memcac ...

最新文章

  1. VirtualBox虚拟机开机后台自启动
  2. 轻松搞定Retrofit不同网络请求方式的请求参数配置,及常用注解使用
  3. winform 基础
  4. Js的Url中传递中文参数乱码的解决
  5. MFC VS2005 添加Override 和 Message
  6. 概率论-3.2 边际分布与随机变量的独立性
  7. 2015蓝桥杯省赛---java---B---8(饮料换购)
  8. LeetCode 312. 戳气球(DP,难)
  9. android 尺寸变化动画,Android ScaleAnimation类:尺寸变化动画类
  10. 如何套用模板绘制生产管理流程图
  11. git的基本使用和多人协作合并管理
  12. android 更新apk 应用为安装,应用未安装!从Android Studio构建安装APK时出错 - java
  13. TP5.0 Redis(单例模式)(原)
  14. 月球 dem_通过“月球灾害”应对错误信息的流行
  15. 第二十三期 基于hg255d的OpenWrt固件编译《路由器就是开发板》
  16. wps 字体对系统无效_wps 字体不显示怎么办 - 卡饭网
  17. 第九届蓝桥杯C/C++ 大学B组省赛编程题题目及答案解析
  18. Paypal无限转圈
  19. CRM系统更换服务器,CRM系统三种常见安装实施解决方式
  20. U盘加密软件测试自学,TrueCrypt加密软件的相关技巧与问题

热门文章

  1. 毕业设计-基于机器视觉的甘蔗茎秆识别方法-OpenCV
  2. Java字符串相似度匹配
  3. 医疗ChatGPT、金融GPT都来啦!“潘多拉的魔盒”已经打开?
  4. 使用微信小程序拨打电话
  5. 微信统一支付详解,坑太多,不得不写
  6. Sci-Fi 科幻迷们,爱死机第二季来啦 | Mixlab 科幻实验
  7. 如何用java判断手机号运营商?
  8. jetty服务器与tomcat9服务器重定向到当前应用不一致报错
  9. Linux下装无线网卡(Ubuntu)
  10. 当代年轻人的社恐(二)