PREREQ_PM specifies the runtime prerequisites, but how to specify which modules are required to run the test cases?
Should I use BUILD_REQUIRES for this?
As of ExtUtils::MakeMaker 6.64, there is a TEST_REQUIRES parameter.
use ExtUtils::MakeMaker 6.64;
WriteMakefile(
...,
TEST_REQUIRES => {
Test::More => 0.95,
},
...,
);
The CPAN::Meta::Spec defines how modules communicate their prerequisites to the toolchain. The version 2 spec revised the way prerequisites are listed. The test phase now has its own list of prerequisites.
But MakeMaker hasn't been updated for the v2 spec, and likely never will be. The only fully-compliant v2 distribution tool I know of is Dist::Zilla (and I recommend it for more reasons than that).
When CPAN::Meta::Converter converts from the v2 spec to v1.4, it merges the test requirements into build_requires.
So yes, if you stick with MakeMaker, any modules that are required to run the tests should be listed in BUILD_REQUIRES. PREREQ_PM should contain only modules that are still required after the module is installed.
If the tests fail without a module, then I list it in PREREQ_PM regardless of whether it's needed for testing or for running the module.
If I need modules for some tests, but they are not needed to run the module, I detect those when the tests are run, and I skip the tests (with a PASS) if I can't find them.
I don't think there is any field in ExtUtils::MakeMaker for what you want.
Related
New to Perl here, apologies for the maybe silly question. After running "carton install" I noticed in the cpanfile.snapshot that some dependencies still has "0" as version, so basically, no version was selected.
Is this the expected behaviour?
To be more precise, the dependency is declared in the cpanfile with "0" as version and does not appear in the snapshot file at all.
According to the documentation for ExtUtils::MakeMaker :
PREREQ_PM
A hash of modules that are needed to run your module. The
keys are the module names ie. Test::More, and the minimum version is
the value. If the required version number is 0 any version will do.
The versions given may be a Perl v-string (see version) or a range
(see CPAN::Meta::Requirements).
This will go into the requires field of your META.yml and the runtime
of the prereqs field of your META.json.
PREREQ_PM => {
# Require Test::More at least 0.47
"Test::More" => "0.47",
# Require any version of Acme::Buffy
"Acme::Buffy" => 0, }
So a zero version in the cpanfile.snapshot means that a dependent or required module specified a version number of zero, meaning that any version will do.
To be more precise, the dependency is declared in the cpanfile with "0" as version and does not appear in the snapshot file at all.
It depends if it is a core module or not, core modules are not included in the snapshot, but you can implicitly declare a version by specifying a minimum version for perl itself in the cpanfile:
requires 'perl', '5.022000';
See also Specifying dependencies for your CPAN distribution for more information.
I'm considering of using modules to group scripts. I often end up in the scenario that I have one or more scripts that uses a certain module.
Is it possible to pack the scripts together with the module?
Are there any specifics to how to achieve that?
Thanks for your input.
You can include scripts along with your module by including the EXE_FILES directive in a Makefile.PL file, and supplying the relative path to the scripts in an array reference. In the below example, the scripts live in a bin/ directory within the top level of your module's directory. You do not need to have your files in a distribution-like layout, but it helps (see below).
After setting up your directory structure and fiddling with the paths within the Makefile.PL, running make install will install your scripts along with your module.
use ExtUtils::MakeMaker;
WriteMakefile(
NAME => 'My::Module',
VERSION_FROM => 'lib/My/Module.pm',
($] >= 5.005 ?
(ABSTRACT_FROM => 'lib/My/Module.pm',
AUTHOR => 'My Name <email.addr>') : ()),
LIBS => [],
EXE_FILES => [qw(bin/script1 bin/script2)],
DEFINE => '',
INC => '-I.',
PREREQ_PM => {},
);
Personally, I'd recommend turning your module into a full-blown distribution. Here's an example. First, install Module::Starter, then:
module-starter --author="My Name" --email="my#email.com" --module=My::Module --eumm
Now you can copy your module's code to lib/My/Module.pm, create a bin/ directory, put your scripts in it, add the EXE_FILES directive to the Makefile.PL, and you can use the full suite of make commands to make, test and install your modules and the scripts, eg:
perl Makefile.PL
make
make test
make install
Here's a real-world example, one of my own distributions on the CPAN that includes a bundled pinmap Perl script along with the distribution's modules:
The File::ShareDir::Install module represents a practical way of carrying around auxiliary files with a Perl distribution/module. I feel however a bit puzzled on how to include it in the dependencies of my project.
I tried to install my package on a fresh machine (actually a docker container with base OS + Perl + CPAN) and I got the error:
Can't locate File/ShareDir/Install.pm in #INC ... at Makefile.PL line 7.
According to the documentation (perldoc File::ShareDir::Install), the pattern should be, in my Makefile.PL:
use ExtUtils::MakeMaker;
use File::ShareDir::Install;
install_share 'share';
install_share dist => 'dist-share';
install_share module => 'My::Module' => 'other-share';
WriteMakefile( ... ); # As you normaly would
package MY;
use File::ShareDir::Install qw(postamble);
However, by doing so I need File::ShareDir::Install to be pre-installed on my system as requirement to run the Makefile.PL script. Declaring it as dependency will not work, for obvious reasons!
Should I instruct my users to explicitly instasll File::ShareDir::Install before my module? Would it be possible to install it programmatically, within Makefile.PL, by directly calling the CPAN module?
This is what CONFIGURE_REQUIRES is for:
Available in version 6.52 and above.
A hash of modules that are required to run Makefile.PL itself, but not to run your distribution.
This will go into the configure_requires field of your META.yml and the configure of the prereqs field of your META.json.
Defaults to { "ExtUtils::MakeMaker" => 0 } if this attribute is not specified.
The format is the same as PREREQ_PM.
So you would add to your WriteMakefile parameters:
CONFIGURE_REQUIRES => {
"ExtUtils::MakeMaker" => '6.52',
"File::ShareDir::Install" => 0,
},
Then people using cpan or cpanm to install modules will get File::ShareDir::Install installed automatically.
To build the distribution
Make a File::ShareDir::Install a build-time dependency.
CONFIGURE_REQUIRES => {
'ExtUtils::MakeMaker' => '6.52',
'File::ShareDir::Install' => 0,
},
Install File::ShareDir::Install on the machine on which you will build the distribution.
Build the distribution.
This will create a META.yml that includes File::ShareDir::Install as a build-time dependency.
To install the distribution
Just use cpan or cpanm as normal. cpan and cpanm will extract build-time dependencies from META.yml and install them before running Makefile.PL.
I am familiar with using package.json with node.js, Gemfile for Ruby, Podfile for Objective-C, et al.
What is the equivalent file for Perl and what is the syntax used?
I've installed a couple packages using cpanm and would like to save the package names and version in a single file that can be executed by team members.
For simple use cases, writing a cpanfile is a good choice. A sample file might look like
requires 'Marpa::R2', '2.078';
requires 'String::Escape', '2010.002';
requires 'Moo', '1.003001';
requires 'Eval::Closure', '0.11';
on test => sub {
requires 'Test::More', '0.98';
};
That is, it's actually a Perl script, not a data format. The dependencies can then be installed like
$ cd /path/to/your/module
$ cpanm --installdeps .
This does not install your module! But it makes sure that all dependencies are satisfied, so we can do:
use lib '/path/to/your-module/lib'; # add the location as a module search root
use Your::Module; # works! yay
This is usually sufficient e.g. for a git repository which you want others to tinker with.
If you want to create a tarball that can be distributed and installed easily, I'd recommend Dist::Zilla (although it's geared towards CPAN releases). Instead of a cpanfile we use a dist.ini:
name = Your-Module
version = 1.2.3
author = Your Self <you#example.com>
license = GPL_3
copyright_holder = Your Self
[#Basic]
[Prereqs]
Marpa::R2 = 2.078
String::Escape = 2010.002
Moo = 1.003001
Eval::Closure = 0.11
[Prereqs / TestRequires]
Test::More = 0.98
Then:
$ dzil test # sanity checks, and runs your tests
$ dzil build # creates a tarball
Dist::Zilla takes care of creating a Makefile.PL and other infrastructure that is needed to install the module.
You can then distribute that tarball, and install it like cpanm Your-Module-1.2.3.tar.gz. Dependencies are resolved, your packages are copied to a permanent location, and you can now use Your::Module in any script without having to specify the location.
Note that you should adhere to the standard directory layout for Perl modules:
./
lib/
Your/
Module.pm # package Your::Module
Module/
Helper.pm # package Your::Module::Helper
t/ # tests to verify the module works on the target syste,
foo.t
bar.t
xt/ # optional: Author tests that are not run on installation
baz.t
bin/ # optional: scripts that will later end up in the target system's $PATH
command-line-tool
Makefile.PL usually (along with a few other files; Perl has had packages for longer then any of the other languages you mention and suffers from a bit of inelegance here).
Module Starter is a sensible way to start writing a package. It has a getting started guide.
I get a lot of errors on CpanTesters for my module EBook::MOBI::Image
(It is just some additional stuff for EBook::MOBI. Like this I keep graphics-dependencies from the main module away for those who don't need it anyways).
All tests, except those for GNU/Linux fail:
http://www.cpantesters.org/distro/E/EBook-MOBI-Image.html#EBook-MOBI-Image-0.11
Since I only have GNU/Linux and have some lack of experience in general, I ask for some help here.
The test results seem to indicate, that there is a problem with the dependency of Image::Imlib2
http://www.cpantesters.org/cpan/report/2306795e-99db-11e2-8c80-50d7c5c10595
There it says I should take care, that Image::Imlib2 is in the "Makefile.PL", but it is there as you can see:
https://metacpan.org/source/BORISD/EBook-MOBI-Image-0.11/Makefile.PL#L24
Image::Imlib2 itself does not have this issues. Tests pass all the systems:
http://www.cpantesters.org/distro/I/Image-Imlib2.html#Image-Imlib2-2.03
Can somebody give a hint here what is wrong?
The code is hosted here:
https://github.com/borisdaeppen/EBook-MOBI-Image
Thanks a lot.
When I try to install this module (on Cygwin) with the cpan command:
cpan recognizes that I need the Image::Imlib2 module (warning: prerequisite Image::Imlib2 0 not found)
cpan downloads and attempt to build Image::Imlib2
build of Image::Imlib2 fails (you must install the imlib2 library before you can install Image::Imlib2 ... Make has some problems, won't install)
cpan continues to build EBook::MOBI::Image (... Continuing, but chances to succeed are limited)
and of course, the tests for Ebook::MOBI::Image fail
The PREREQ_PM => ... directive in Makefile.PL tell cpan to make an effort to satisfy a prerequisite, but as you see, it will continue the build even if the prerequisite fails to install. The PREREQ_PM directive is good enough for most modules on CPAN, but not for modules that need an external library that cpan can't install on its own.
I think what you want in this case is for the cpan tester to bail out if you can't load the Image::Imlib2 module, and the place to do that is early in Makefile.PL.
if (!eval "require Image::Imlib2") {
print "This distribution requires Image::Imlib2!\n";
exit 0;
}
For systems that can't or won't install Image::Imlib2, bailing out of Makefile.PL will cause the tester to report a result of N/A instead of FAIL.