ExtUtils::MakeMaker

简介

use ExtUtils::MakeMaker;

WriteMakefile(
    NAME            => 'Your::Module',
    VERSION_FROM    => 'lib/Your/Module.pm'
);

ExtUtils::MakeMaker 模块是用于创建Makefile文件的模块。

注:所有模块必须以项目的方式发布到CPAN。

语法

使用ExtUtils::MakeMaker模块来编写目标项目的Makefile.PL 文件(Makefile.PL文件的结构稍候介绍),使用如下代码段中的命令就可以完成目标项目的安装。

perl Makefile.PL
make
make test
make install

项目结构说明

目标项目(需要发布到CPAN的项目)的基本结构如下所示:

Makefile.PL
MANIFEST
lib/Your/Module.pm

以上基本结构是每个项目都必需的,除此之外还有其他一些可选的结构,如下面的代码段所示:

lib/Your/Other/Module.pm
t/some_test.t
t/some_other_test.t
Changes
README
INSTALL
MANIFEST.SKIP
bin/some_program

Makefile.PL

当你运行Makefile.PL时,它会生成一个Makefile。这就是ExtUtils::MakeMaker模块的全部内容。

akefile.PL是一个简单的程序,它加载ExtUtils :: MakeMaker并运行WriteMakefile()函数来生成一个Makefile。下面的代码段是一个简单的Makefile.PL文件的示例:

use ExtUtils::MakeMaker;

WriteMakefile(
    NAME            => 'Your::Module',
    VERSION_FROM    => 'lib/Your/Module.pm'
);

其中NAME是目标项目的顶级命名空间。VERSION_FROM是包含整个需要发布的项目的$VERSION变量的文件,通常它与您的顶级模块相同。

MANIFEST

这个文件中列出了项目发布时包含的所有文件。下面是一个MANIFEST文件内容的示例:

Makefile.PL
MANIFEST
lib/Your/Module.pm

MANIFEST文件中的内容,对于文件路径的分隔符必须是Unix约定的/,即使不在Unix系统中也是一样。这个文件你可以自己编写也可以使用make manifest命令生成。

lib/

在这个目录下存放目标项目的所有.pm和.pod文件,它们根据命名空间不同而分布在不同的文件夹中。

t/

在这个目录中存放的是所有对你的模块进行测试的代码,每个测试文件都以.t结尾。make test命令将会运行这里的所有测试。参赛情况下所有测试文件都位于t/ 目录下。但你也可以构建子目录,把不同的测试文件分别放到不同的目录下方便在测试文件较多时进行有效的管理。

t/foo/subdir_test.t

为了能够在执行make test命令时能够运行目标项目t/ 目录下的所有测试代码,你需要在Makefile.PL文件WriteMakeFile方法调用的函数中加入如下内容:

test => {TESTS => 't/*.t t/*/*.t'}

上面的代码会使得t/目录下的所有.t文件以及t/目录的子目录下的所有.t文件得以在执行make test命令时运行。当然如果在你的t/目录下存放的测试文件有更深层级的嵌套,你还需要对test参数选项指定更多的内容。

t/foo/bar/subdir_test.t

test => {TESTS => 't/*.t t/*/*/*.t'}

从中应该觉察到规则,也就是说*是通配符,但其不能匹配/

注:测试运行时的当前目录为项目的顶级目标。

Changes

这个文件中记录了目标项目的修改记录。文件的格式比较自由,下面是一个可供参考的例子。

1.01 Fri Apr 11 00:21:25 PDT 2003
    - thing() does some stuff now
    - fixed the wiggy bug in withit()

1.00 Mon Apr  7 00:57:15 PDT 2003
    - "Rain of Frogs" now supported

README

对目标项目的简短说明,它的作用是向用户介绍在什么情况下可以使用你的项目,以及使用这个项目的一些限制。CPAN将自动把这个文件中的内容展示给CPAN用户,这是他们最先看到到的有关你项目的内容,并根据这些内容来判断这个项目是否适合于他们使用。

INSTALL

有关如何安装模块和所有依赖关系的说明,建议包含以下信息:

  1. 使用这个项目必须安装的依赖模块
  2. 这个项目可运行在的Perl的最小版本
  3. 这个项目对操作系统的依赖

MANIFEST.SKIP

这个文件中记录的是用于make manifest 命令使用的正则表达式,所有与这些正则表达式匹配的文件都不会被包含在make manifest命令生成的MANIFEST文件中。这些正则表达式将针对项目中找的每个文件路径进行检查,只要有一个正则不匹配某个文件,这个文件就会被排除在MANIFEST文件之外。

WriteMakefile 方法

WriteMakefile方法是这个模块中对外导出的唯一方法,在这个方法中实现了ExtUtils::MakeMaker模块的所有功能。所有的功能都是通过WriteMakefile方法的参数来控制的。

首先WriteMakefile支持的所有参数选项:

ABSTRACT  摘要,对项目的一句话(一行)说明,上传到CPAN后会被加入到PPD文件中。
ABSTRACT_FROM 指定从一个文件的POD中提取摘要
AUTHOR  作者信息
BINARY_LOCATION 
BUILD_REQUIRES 模块构建时所依赖的包
C
CCFLAGS
CONFIG
CONFIGURE
CONFIGURE_REQUIRES 运行Makefile.PL所依赖的包
DEFINE
DESTDIR 安装代码的根目录
DIR
DISTNAME 项目包的文件名
DISTVNAME 包含版本号的项目包的文件名
DLEXT
DL_FUNCS
DL_VARS
EXCLUDE_EXT
EXE_FILES
FIRST_MAKEFILE
FULLPERL
FULLPERLRUN
FULLPERLRUNINST
FUNCLIST
H
IMPORTS
INC
INCLUDE_EXT
INSTALLARCHLIB
INSTALLBIN
INSTALLDIRS
INSTALLMAN1DIR
INSTALLMAN3DIR
INSTALLPRIVLIB
INSTALLSCRIPT
INSTALLSITEARCH
INSTALLSITEBIN
INSTALLSITELIB
INSTALLSITEMAN1DIR
INSTALLSITEMAN3DIR
INSTALLSITESCRIPT
INSTALLVENDORARCH
INSTALLVENDORBIN
INSTALLVENDORLIB
INSTALLVENDORMAN1DIR
INSTALLVENDORMAN3DIR
INSTALLVENDORSCRIPT
INST_ARCHLIB
INST_BIN
INST_LIB
INST_MAN1DIR
INST_MAN3DIR
INST_SCRIPT
LD
LDDLFLAGS
LDFROM
LIB
LIBPERL_A
LIBS
LICENSE
LINKTYPE
MAGICXS
MAKE
MAKEAPERL
MAKEFILE_OLD
MAN1PODS
MAN3PODS
MAP_TARGET
META_ADD  要添加到CPAN元数据中的项目信息
META_MERGE 要添加到CPAN元数据中的项目信息
MIN_PERL_VERSION  支持的最小的Perl版本
MYEXTLIB
NAME
NEEDS_LINKING
NOECHO
NORECURS
NO_META
NO_MYMETA
NO_PACKLIST
NO_PERLLOCAL
NO_VC
OBJECT
OPTIMIZE
PERL
PERL_CORE
PERLMAINCC
PERL_ARCHLIB
PERL_LIB
PERL_MALLOC_OK
PERLPREFIX
PERLRUN
PERLRUNINST
PERL_SRC
PERM_DIR
PERM_RW
PERM_RWX
PL_FILES  指定MakeMaker在构建时运行的perl程序
PM
PMLIBDIRS
PM_FILTER
POLLUTE
PPM_INSTALL_EXEC
PPM_INSTALL_SCRIPT
PPM_UNINSTALL_EXEC
PPM_UNINSTALL_SCRIPT
PREFIX
PREREQ_FATAL 指定当不满足项目运行时依赖时是否禁安装,布尔值。
PREREQ_PM  项目运行时依赖的模块
PREREQ_PRINT
PRINT_PREREQ
SITEPREFIX
SIGN
SKIP
TEST_REQUIRES
TYPEMAPS
VENDORPREFIX
VERBINST
VERSION
VERSION_FROM
VERSION_SYM
XS
XSBUILD
XSMULTI
XSOPT
XSPROTOARG
XS_VERSION
clean
depend
dist
dynamic_lib
linkext
macro
postamble
realclean
test
tool_autosplit

下面分别对WriteMakefile方法中的常用参数选项进行介绍。

ABSTRACT

指定项目的摘要,对项目的一句话(单行)说明,上传到CPAN后会被加入到PPD文档中。

ABSTRACT_FROM

指定从某个模块文件的POD中提取摘要。MakeMaker会在指定模块文件的POD中进行正则/^($package\s-\s)(.*)/的匹配。把匹配得到的$2作为摘要。这通常是“= head1 NAME”小节的第一行。

AUTHOR

包含作者的名称(和电子邮件地址)的字符串数组。用于PPM(Perl Package Manager)的CPAN Meta文件(META.yml或META.json)和PPD(Perl Package Description)文件。

BUILD_REQUIRES

模块构建时所依赖的包,在运行时并不依赖这些包。该参数值的类型为hashref,在这个hashref中key为依赖的包名,value为依赖包的版本号。

CONFIGURE_REQUIRES

运行Makefile.PL文件时所依赖的包,在项目构建和运行时并不依赖这些包。该参数值的类型为hashref,在这个hashref中key为依赖的包名,value为依赖包的版本号。

META_ADD

META_MERGE

把项目的信息添加到CPAN的元数据中,如果他们具有与默认元数据相同的关键字META_ADD与META_MERGE的行为将有所不同。META_ADD将用会覆盖默认值,而META_MERGE将会把这里的值与默认值合并。

除非你确定要覆盖默认值,否则请优先使用META_MERGE。

注:这些数据仅用于生成META.yml和META.json,而不会直接被META.yml和META.json使用。

这儿默认使用的是CPAN Meta 规范 1.4 版本。如果要使用2.0版本,在需要指定 meta-spec 键。如下所示:

META_MERGE        => {
  "meta-spec" => { version => 2 },
  resources => {
    repository => {
        type => 'git',
        url => 'git://github.com/Perl-Toolchain-Gang/ExtUtils-MakeMaker.git',
        web => 'https://github.com/Perl-Toolchain-Gang/ExtUtils-MakeMaker',
    },
  },
},

PREREQ_FATAL

此选项被指定一个布尔值,用于说明当不满足项目运行时依赖时是否禁安装。如果值为真,则当PREREQ_PM 中指定的模块不被满足时将发生致命错误而退出安装。

不建议设置此参数为真。你可以编写一个测试(t/00compile.t)来检查你的代码运行时所依赖的包是否满足,如果不满足则可以在运行测试时就给出详细的提醒,并且模块安装工具会根据你在测试过程中给出的信息自动解决依赖关系。

PL_FILES

MakeMaker在构建时会运行你用此参数选项指定的perl文件。默认情况下顶级目录中名为*.PL(Makefile.PL和Build.PL除外)的任何文件都将被假定为一个Perl程序,在构建过程中MakeMaker会运行这些程序,并将其自己的basename作为参数。如下面的代码段所示:

perl foo.PL foo

你可以通过PL_FILES参数选项指定自己的一组文件来覆盖此默认行为。PL_FILES接受一个hashref,键名是要运行的文件,键值是运行文件时传入的第一个参数。

PL_FILES => {'bin/foobar.PL' => 'bin/foobar'}

PL_FILES => {'foo.PL' => 'foo.c'}

如上配置会像下面这样运行bin/foobar.PL

perl bin/foobar.PL bin/foobar

如果需要使用不同参数多次运行同一文件,则可以使用数据引用作为键值:

PL_FILES => {'bin/foobar.PL' => [qw(bin/foobar1 bin/foobar2)]}

这种情况下,程序将对每个目标文件执行一次:

perl bin/foobar.PL bin/foobar1
perl bin/foobar.PL bin/foobar2

PREREQ_PM

项目运行时所依赖的包。该参数值的类型为hashref,在这个hashref中key为依赖的包名,value为依赖包的版本号。如果所指定的版本号为0,则说明是所有版本都可以。下面是一个例子:

PREREQ_PM => {
    # Require Test::More at least 0.47
    "Test::More" => "0.47",

    # Require any version of Acme::Buffy
    "Acme::Buffy" => 0,
}

结束

暂时先写这么多,对于我自己来说够用了,后续在实际使用过程中慢慢被全。

a

推荐阅读更多精彩内容