第三讲
扩展库使用c++实现,在调用函数后,返回对象变量,perl 能正确使用所有对象成员

使用h2xs 命令生成初始文件

h2xs -A -n three_test

登录目录

cd three_test

c++ 头文件

#ifndef INCLUDED_DUCK_H
#define INCLUDED_DUCK_H 1
#include <string>
using std::string;
class Duck
{
public:
Duck(char*);
char* getName();
void swim();
~Duck(){}
private:
bool swimming;
string name;
};
#endif /* INCLUDED_DUCK_H */

c++程序代码

#include "Duck.h"
#include <cstdio> using namespace std; Duck::Duck(char* n) :
swimming(false), name(n)
{
}
const char* Duck::getName()
{
return name.c_str();
}
void Duck::swim()
{
if (!swimming)
{
printf("%s, ok .. go swimming\n", name.c_str());
swimming = true;
}
else
{
printf("%s is already swimming , stop\n", name.c_str());
swimming = false;
}
return;
}

使用g++编译成动态库

g++ -g -Wall -fpic -shared -o libduck.so Duck.cpp

将libduck.so 文件与Duck.h 文件拷贝到 three_test 目录下

cp libduck.so three_test;
cp Duck.h three_test;

XS是一种用于描述接口的文件格式,当我们希望把我们的C/C++库映射成Perl的package时,需要在一个.xs文件中描述接口的映射。另外,我们还需要进行数据类型的映射,下文会提到 perlobject.map文件的使用。

 perlobject.map 内容:(原文件地址:http://cpansearch.perl.org/src/ELEONORA/text_hunspell_1.3/perlobject.map)

# "perlobject.map"  Dean Roehrich, version
#
# TYPEMAPs
#
# HV * -> unblessed Perl HV object.
# AV * -> unblessed Perl AV object.
#
# INPUT/OUTPUT maps
#
# O_* -> opaque blessed objects
# T_* -> opaque blessed or unblessed objects
#
# O_OBJECT -> link an opaque C or C++ object to a blessed Perl object.
# T_OBJECT -> link an opaque C or C++ object to an unblessed Perl object.
# O_HvRV -> a blessed Perl HV object.
# T_HvRV -> an unblessed Perl HV object.
# O_AvRV -> a blessed Perl AV object.
# T_AvRV -> an unblessed Perl AV object. TYPEMAP HV * T_HvRV
AV * T_AvRV ######################################################################
OUTPUT # The Perl object is blessed into 'CLASS', which should be a
# char* having the name of the package for the blessing.
O_OBJECT
sv_setref_pv( $arg, CLASS, (void*)$var ); T_OBJECT
sv_setref_pv( $arg, Nullch, (void*)$var ); # Cannot use sv_setref_pv() because that will destroy
# the HV-ness of the object. Remember that newRV() will increment
# the refcount.
O_HvRV
# "perlobject.map" Dean Roehrich, version
#
# TYPEMAPs
#
# HV * -> unblessed Perl HV object.
# AV * -> unblessed Perl AV object.
#
# INPUT/OUTPUT maps
#
# O_* -> opaque blessed objects
# T_* -> opaque blessed or unblessed objects
#
# O_OBJECT -> link an opaque C or C++ object to a blessed Perl object.
# T_OBJECT -> link an opaque C or C++ object to an unblessed Perl object.
# O_HvRV -> a blessed Perl HV object.
# T_HvRV -> an unblessed Perl HV object.
# O_AvRV -> a blessed Perl AV object.
# T_AvRV -> an unblessed Perl AV object. TYPEMAP HV * T_HvRV
AV * T_AvRV ######################################################################
OUTPUT # The Perl object is blessed into 'CLASS', which should be a
# char* having the name of the package for the blessing.
O_OBJECT
sv_setref_pv( $arg, CLASS, (void*)$var ); T_OBJECT
sv_setref_pv( $arg, Nullch, (void*)$var ); # Cannot use sv_setref_pv() because that will destroy
# the HV-ness of the object. Remember that newRV() will increment
# the refcount.
O_HvRV
$arg = sv_bless( newRV((SV*)$var), gv_stashpv(CLASS,) ); T_HvRV
$arg = newRV((SV*)$var); # Cannot use sv_setref_pv() because that will destroy
# the AV-ness of the object. Remember that newRV() will increment
# the refcount.
O_AvRV
$arg = sv_bless( newRV((SV*)$var), gv_stashpv(CLASS,) ); T_AvRV
$arg = newRV((SV*)$var); ######################################################################
INPUT O_OBJECT
if( sv_isobject($arg) && (SvTYPE(SvRV($arg)) == SVt_PVMG) )
$var = ($type)SvIV((SV*)SvRV( $arg ));
else{
warn( \"${Package}::$func_name() -- $var is not a blessed SV reference\" );
XSRETURN_UNDEF;
} T_OBJECT
if( SvROK($arg) )
$var = ($type)SvIV((SV*)SvRV( $arg ));
else{
warn( \"${Package}::$func_name() -- $var is not an SV reference\" );
XSRETURN_UNDEF;
} O_HvRV
if( sv_isobject($arg) && (SvTYPE(SvRV($arg)) == SVt_PVHV) )
$var = (HV*)SvRV( $arg );
else {
warn( \"${Package}::$func_name() -- $var is not a blessed HV reference\" );
XSRETURN_UNDEF;
} T_HvRV
if( SvROK($arg) && (SvTYPE(SvRV($arg)) == SVt_PVHV) )
$var = (HV*)SvRV( $arg );
else {
warn( \"${Package}::$func_name() -- $var is not an HV reference\" );
XSRETURN_UNDEF;
} O_AvRV
if( sv_isobject($arg) && (SvTYPE(SvRV($arg)) == SVt_PVAV) )
$var = (AV*)SvRV( $arg );
else {
warn( \"${Package}::$func_name() -- $var is not a blessed AV reference\" );
XSRETURN_UNDEF;
} T_AvRV
if( SvROK($arg) && (SvTYPE(SvRV($arg)) == SVt_PVAV) )
$var = (AV*)SvRV( $arg );
else {
warn( \"${Package}::$func_name() -- $var is not an AV reference\" );
XSRETURN_UNDEF;
}

将文件perlobject.map 拷贝到 three_test 目录下

cp perlobject.map three_test

增加一个Duck类型,保存在文件typemap

touch three_test/typemap

typemap 文件内容

TYPEMAP
Duck* O_OBJECT

修改Makefile.PL 文件

#use 5.014002;
use ExtUtils::MakeMaker;
$CC = 'g++';
# See lib/ExtUtils/MakeMaker.pm for details of how to influence
# the contents of the Makefile that is written.
WriteMakefile(
NAME => 'three_test',
VERSION_FROM => 'lib/three_test.pm', # finds $VERSION
PREREQ_PM => {}, # e.g., Module::Name => 1.1
($] >= 5.005 ? ## Add these new keywords supported since 5.005
(ABSTRACT_FROM => 'lib/three_test.pm', # retrieve abstract from module
AUTHOR => 'root <root@>') : ()),
LIBS => ['-L./ -lduck'], # e.g., '-lm'
DEFINE => '', # e.g., '-DHAVE_SOMETHING'
'CC' => $CC,
'LD' => '$(CC)',
INC => '-I.', # 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 'XSOPT' => '-C++',
'TYPEMAPS' => ['perlobject.map']
);

注意,红色部分为增加会修改内容,特别需要指出的是,第一行use 5.014002; 一定需要注释,否则无法正确生成makefile

修改部分,主要是指定编译使用g++

修改three_test.xs 文件

#ifdef __cplusplus
extern "C"{
#endif
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#ifdef __cplusplus
}
#endif
#include "ppport.h"
#include "Duck.h"
using namespace std; MODULE = three_test PACKAGE = three_test Duck*
Duck::new(char * name) char*
Duck::getName() void
Duck::swim() void
Duck::DESTROY()

红色部分为增加内容

编译并安装

perl Makefile.PL
make
make install

编写一个perl 测试程序 test.pl

use three_test;

my $duck = new three_test("Dan");
my $name = $duck->getName();
$duck->swim();
$duck->swim();
print "$name\n";

执行

perl test.pl

输出:

Dan, ok .. go swimming
Dan is already swimming , stop
Dan

正确调用了C++的库

参考文章:

http://chunyemen.org/archives/493

http://www.johnkeiser.com/perl-xs-c++.html

官方文档:http://perldoc.perl.org/perlxs.html#NAME

perl C/C++ 扩展(三)的更多相关文章

  1. perl C/C++ 扩展(五)

    perl 的C++扩展,返回值为自定义类型. 在 perl C/C++扩展(三) 中,我已经介绍了,如何让perl 认识 c++的类,但是前面的介绍中,包括我参考的博客http://chunyemen ...

  2. perl C/C++ 扩展(四)

    在前面三篇博客中,我们了解到如何使用c/c++ 扩展自己的perl 库,但是博主在学习过程中,对动态库或静态库的加载不是十分了解,后来自己又细挖一下.后来就有了这篇博文,再后来,没有再后来了,囧!! ...

  3. 手把手教你开发Chrome扩展三:关于本地存储数据

    手把手教你开发chrome扩展一:开发Chrome Extenstion其实很简单 手把手教你开发Chrome扩展二:为html添加行为 手把手教你开发Chrome扩展三:关于本地存储数据 HTML5 ...

  4. perl C/C++ 扩展(二)

    第二讲perl 加载c/c++的库 先通过h2xs 创建一个新的工程 h2xs -A -n two_test 进入目录 cd two_test 创建一个mylib文件夹,存放静态库 mkdir myl ...

  5. puppet 横向扩展(三)

    Table of Contents 1. 概述 2. 实验环境 3. 实验步骤 3.1. 机器B 的配置 3.2. 机器A 的配置 3.3. 测试配置结果 概述 横向扩展实验之三 – 将CA 认证服务 ...

  6. perl C/C++ 扩展(一)

    通过h2xs 中间件,我们可以快速的使用c或则C++ 库来实现perl 扩展功能 第一讲:跑通hello world 程序******************************我们使用命令:h2 ...

  7. Perl中的正则表达式

    转自:http://c20031776.blog.163.com/blog/static/684716252013624383887/ Perl 程序中,正则表达式有三种存在形式 分别是 (1 模式匹 ...

  8. (转载)CSV 文件处理 PERL

    http://cn.perlmaven.com/how-to-read-a-csv-file-using-perl http://search.cpan.org/~hmbrand/Text-CSV_X ...

  9. Perl 语法 - 基础

    perl语言的核心是正则表达式,在文本处理上非常有优势,与python类似,但语法不同,perl的语法很灵活,用多了才会觉得好用. 常用知识点总结: perl语法类似于C语言(perl源于Unix), ...

随机推荐

  1. 原来浏览器原生支持JS Base64编码解码 outside of the Latin1 range

    原来浏览器原生支持JS Base64编码解码 « 张鑫旭-鑫空间-鑫生活 https://www.zhangxinxu.com/wordpress/2018/08/js-base64-atob-bto ...

  2. Java Virtual Machine (JVM) objects 虚拟机实例的产生 退出 两种线程

    Apache Spark is built around a distributed collection of immutable Java Virtual Machine (JVM) object ...

  3. Performance Tuning Using Linux Process Management Commands

    [root@bigdata-server-02 /]# ps --help all Usage: ps [options] Basic options: -A, -e all processes -a ...

  4. Memcached中的存取命令详解

    本文和大家分享的主要是Memcached中常用的一些存取命令相关用法,一起来看看吧,希望对大家学习Memcached有所帮互助. 存储命令 set:不管key存在与否,强制进行set操作: add:必 ...

  5. 服务化之Netty

    关于Netty的介绍可参考:https://www.zhihu.com/question/24322387 Netty官网为:http://netty.io/ Git:https://github.c ...

  6. 人生苦短之Python函数的健壮性

    如何评论一个开发代码写的好?清晰简洁明了?No,No,一个处女座就可以写出来了,整齐地代码,详细的注释不是代码好的标准,应该说不是最重要的标准.代码写的是否健壮才是检验的重要标准. 代码的健壮性: 当 ...

  7. node.js 开发博客系统

    1. 安装yoman :npm install -g yo 2. 安装 generator-express :npm install -g generator-express 3. 安装 bower ...

  8. linux下mysql开启二进制日志

    mysql的查询日志,慢查询日志,错误日志,网上的设置方法是正确的.但在二进制日志上设置有问题.正确的设置方法如下, 在/etc/my.cnf文件中[mysqld]下加上: server-id = 1 ...

  9. 检测SSL证书很好用的三个网站

    https://cryptoreport.websecurity.symantec.com/checker/views/certCheck.jsp https://cipherli.st/ https ...

  10. 让人头疼一晚上的 select 下拉框赋值问题

    一开始做这个功能 批量修改用户组 , 当勾选若干用户组后, 点击[批量修改用户组]->ajax提交后台查询->返回下拉菜单列表内容-> 弹出对话框并赋予下拉菜单select 动态数值 ...