总结一下怎么在windows xp下,完成perl扩展的过程

总结一下如何在windows xp下,完成perl扩展的过程

最近,需要完成一个功能,需要在PERL中调用C++动态库。

这一个星期就为了完成这项工作,还是付出不少努力。

 

首先,找到一篇文章:

《Perl 对 C  的扩展接口》

http://www.ibm.com/developerworks/cn/aix/library/0908_tangming_perltoc/index.html

 

写得很详细。

看完后,开工。

清单 17 . 头文件 test.h
 #define TESTVAL        3
 extern double   add(int, long);
 extern int    max(int, int);

清单 18 . 源文件 test1.c
 #include "./test.h"
 double add(int a, long b)
 {
 return (a + b + TESTVAL);
 }

清单 19 . 源文件 test2.c
 #include "./test.h"
 int max(int a, int b)
 {
 return ((a>b)? a:b);
 }

 

这些照着做,


 2. 在 Mytest/mylib 目录下创建 Makefile.PL 文件,以保证在 Mytest 目录运行 ”make” 时会自动调用该 Makefile.PL 并生成相应的 Makefile。

这步手工用VC6做一个静态库,当然动态库也成

 

 3. 在 Mytest 的上级目录中执行命令 “h2xs -A -O -n Mytest ./Mytest/mylib/test.h” 以生成扩展接口系列文件。
注意:Perl 会提示覆盖 Mytest 目录,并在 Mytest 中生成上节介绍的系列文件,这也是要将源文件放在 /Mytest/mylib/ 下的原因,以免被自动生成的文件覆盖。

照做

 4. Perl 在 Mytest 下自动生成的 Makefile.PL 并不知道子目录 mylib 的存在,因此需要修改该 Makefile.PL。
清单 21 . 修改 Mytest 目录下的 Makefile.PL
 WriteMakefile(
         'NAME'         => 'Mytest',
         'VERSION_FROM' => 'Mytest.pm', # finds $VERSION
         'LIBS'         => [''],   # e.g., '-lm'
         'DEFINE'       => '',     # e.g., '-DHAVE_SOMETHING'
         'INC'          => '',     # e.g., '-I/usr/include/other'
         'MYEXTLIB'     => 'mylib/libmylib$(LIB_EXT)',
 );

指定了 MYEXTLIB 为 mylib 子目录下的 libmylib.a。
清单 22 . 在 Makefile.PL 文件的最后添加 MY::postamble  函数
 sub MY::postamble {
'
 $(MYEXTLIB): mylib/Makefile
 cd mylib && $(MAKE) $(PASSTHRU)
';
 }

在 MY::postamble 中进入 mylib 子目录并运行其下的 Makefile 进行编译,以生成静态库 libmylib.a。
注意: ‘ cd ’ 前面应该是 ‘ Tab ’ 而不是空格,否则 Make 会报 “missing separator” 错误并终止编译。

 5. 修改 MANIFEST 文件使其能够正确包含该扩展接口的所有内容。清单 23 . 修改 MANIFEST  文件
 mylib/Makefile.PL
 mylib/test1.c
 mylib/test2.c
 mylib/test.h


 6. 修改 Mytest.xs 文件并添加函数定义。
清单 24 . 修改 #include test.h
 #include "mylib/test.h"

修改路径为 mylib/test.h 并将尖括号 <> 改为双引号””,以使编译程序能正确找到 mylib 子目录下面的 test.h 头文件。
清单 25 . 添加 add() 和 max () 函数定义
 double
 add(a,b)
 int  a
 long b

 int
 max(a,b)
   int a
   int b

提供 Perl 与 C 之间的接口函数,使得 Perl 代码通过 Mytest.xs 中的接口函数可以直接调用相应的 C 函数 add(a,b) 和 max(a,b) 函数。

 7. 在 Mytest 目录下运行 ”perl Makefile.PL” 生成 Makefile。清单 26 . 运行 perl Makefile.PL
 % perl Makefile.PL
 Checking if your kit is complete...
 Looks good
 Writing Makefile for Mytest::mylib
 Writing Makefile for Mytest
 %

 

这里会出错,不要理它,原因是IBM这篇文章是对linux而言的,所以第2步就已经不对了,cr 指令不支持。

编译器根据 Makefile.PL 自动生成相应的 Makefile 和 mylib 子目录下的 Makefile。

 8. 运行 ”make” 生成需要的库文件。
清单 27 . 运行 make
 % make
 gcc  -c <compile_flag>   test1.c
 gcc  -c   <compile_flag> test2.c
 ar cr libmylib.a test1.o test2.o
 : libmylib.a
 perl xsubpp -typemap typemap  Mytest.xs > Mytest.xsc && mv Mytest.xsc Mytest.c
 Please specify prototyping behavior for Mytest.xs (see perlxs manual)
 gcc  -c  <compile_flag>   Mytest.c
 rm -f blib/arch/auto/Mytest/Mytest.so
 gcc <compile_flag> Mytest.o -o blib/arch/auto/Mytest/Mytest.so mylib/libmylib.a

 chmod 755 blib/arch/auto/Mytest/Mytest.so
 cp Mytest.bs blib/arch/auto/Mytest/Mytest.bs
 chmod 644 blib/arch/auto/Mytest/Mytest.bs
 Manifying blib/man3/Mytest.3pm
 %

 

xsubpp -typemap typemap  Mytest.xs > Mytest.xsc && mv Mytest.xsc Mytest.c

这个是关键,我们要得到Mytest.c,注意前面不要写perl,否则无法执行。

然后,建一个DLL,引入这个mytest.c,然后写个def文件:见我写的前一篇文章。

LIBRARY "Mytest"
EXPORTS
  boot_Mytest
  _boot_Mytest = boot_Mytest

 

XSUB.h 改成:

#undef XS
#undef XS_EXTERNAL
#undef XS_INTERNAL
#if defined(__CYGWIN__) && defined(USE_DYNAMIC_LOADING)
#  define XS_EXTERNAL(name) __declspec(dllexport) XSPROTO(name)
#  define XS_INTERNAL(name) STATIC XSPROTO(name)
#endif
#if defined(__SYMBIAN32__)
#  define XS_EXTERNAL(name) EXPORT_C XSPROTO(name)
#  define XS_INTERNAL(name) EXPORT_C STATIC XSPROTO(name)
#endif
#ifndef XS_EXTERNAL
#  if defined(HASATTRIBUTE_UNUSED) && !defined(__cplusplus)
#    define XS_EXTERNAL(name) void name(pTHX_ CV* cv __attribute__unused__)
#    define XS_INTERNAL(name) STATIC void name(pTHX_ CV* cv __attribute__unused__)
#  else
#    ifdef __cplusplus //haoyujie modify 2014-03-13
#      define XS_EXTERNAL(name) extern "C" __declspec(dllexport) XSPROTO(name)
#      define XS_INTERNAL(name) static XSPROTO(name)
#    else
#      define XS_EXTERNAL(name) __declspec(dllexport) XSPROTO(name)
#      define XS_INTERNAL(name) STATIC XSPROTO(name)
#    endif
#  endif
#endif

 总结一下怎么在windows xp下,完成perl扩展的过程

 


 9. 修改 Mytest.t 文件,添加测试代码
清单 28 . 修改 Mytest.t
 is( &Mytest::add(1, 2), 6 );
 is( &Mytest::add(3, 1), 7 );
 is( &Mytest::max(1, 2), 2 );
 is( &Mytest::max(3, 1), 3 );

 

下面的都不需要看了,因为编译不过。

测试代码以不同的参数调用 Mytest::add() 和 Mytest::max() 并同预期结果比较,以确认相应的 C 函数 add() 和 max() 被正确调用。

 10. 运行命令 ”make test”,确保所有测试结果正确。清单 29 . 运行 make test
 % make test
 PERL_DL_NONLAZY=1 /usr/bin/perl "-MExtUtils::Command::MM" "-e" "test_harness
 (0, 'blib/lib', 'blib/arch')" *.t
 Mytest....ok                                                              
 All tests successful.
 Files=1, Tests=4,  0 wallclock secs ( 0.03 cusr +  0.01 csys =  0.04 CPU)
 %

从结果可以看到测试全部通过,说明相应 C 函数被调用并计算得到了正确的结果。

  1. 运行命令 ”make install”,将生成的库文件安装到系统目录中。
  2. 至此,我们就能在自己的 Perl 代码中直接调用 test1.c 和 test2.c 里面定义的函数 add() 和 max() 了。
清单 30 .Perl  代码调用
 use Mytest;
 my $sum = &Mytest::add(1, 2);
 my $max = &Mytest::max(2, 3);
 print “Sum of 1 add 2 is: $sum\n”;
 print “Max of 2 and 3 is: $max\n”;

 

============================
用VC6编译过之后,我们要手工进行安装,以使perl能加载。

编译结果拷到这里:

C:\perl\site\lib\auto\Mytest

 

建一个文本文件.packlist,最好从你装好的别的目录找一个:

内容如下,

C:\Perl\html\site\lib\Mytest.html
C:\Perl\site\lib\Mytest.pm
C:\Perl\site\lib\auto\Mytest\Mytest.bs
C:\Perl\site\lib\auto\Mytest\Mytest.dll
C:\Perl\site\lib\auto\Mytest\Mytest.exp
C:\Perl\site\lib\auto\Mytest\Mytest.lib
C:\Perl\site\lib\auto\Mytest\Mytest.pdb

OK。

 

用eclipse打开上面写好的测试文件,调试一下吧:

 

总结一下怎么在windows xp下,完成perl扩展的过程


 OYeah.

 

总结:

IBM的文章把原理讲得很清晰,所以一定要打印出来,反反复复地看。

主方向:

.h ===> .XS === >mytest.c==========>dll==========>手工安装

      h2xs         xsubpp         用VC编译&link      制作.packlist文件。

 

其它:作mytest.dll不要忘了,把那两个C文件所在的静态库libmylib.lib,和 perl516.lib,引入。

 

总结一下怎么在windows xp下,完成perl扩展的过程
1楼haoyujie昨天 17:34
本文需要混一下鼠标再看,图有点小。