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.
Related
I'm building a Perl module. Makefile.PL has
WriteMakefile(
PREREQ_PM => {
'DBI' => '>= 1.641, < 2',
# etc, ...
},
TEST_REQUIRES => {
'Test::More' => 0,
},
# more stuff ...
);
Recently, my ~/perl5 tree got corrupted (PERL5LIB=~/perl5) so I decided to rebuild it, so I blew it away. Doesn't WriteMakefile() generate some make target that will do this for me with all the modules/packages in PREREQ_PM and TEST_REQUIRES. Instead, it just prints warnings:
Warning: prerequisite DBI >= 1.641, < 2 not found.
So I have to start re-installing all these by hand in order to run tests. For my small project, this isn't such a problem, but what if the project had many dependencies? Isn't there a way to automate this?
There is no Makefile target that will do what you want, but the cpan tool will use the information in the META file created by Makefile.PL to fetch and install dependencies.
If you to use cpan offline, consider cloning CPAN using CPAN::Mini.
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:
I plan on uploading a module to CPAN, shortly. This is the first module I've contributed. I've got the module to what I'd consider a "beta" stage. I'm using ExtUtils::MakeMaker to generate a Makefile through Makefile.PL (I've pasted the contents of it below). The Makefile.PL script has all the prereq modules listed. I'm wondering at which point in the installation process, the prereq modules are installed if they're not present? I'm wondering because I ran Makefile.PL followed by make then make install in a separate environment that's missing some of the prereq modules. However, they were not installed? I was under the impression they would be but maybe im missing something? I'm looking for someone to provide some clarity. Thanks in advance~
Makefile.PL
#!/usr/bin/env perl
use strict;
use warnings;
use ExtUtils::MakeMaker;
WriteMakefile(
NAME => 'Imgur',
VERSION => '0.01',
PREREQ_PM => {
'JSON' => 2.90,
'LWP::UserAgent' => 6.05,
'HTTP::Request::Common' => 6.04,
'Data::Dumper' => 2.154,
'DateTime::Format::ISO8601' => 0.08,
'Config::IniFiles' => 2.86,
'Scalar::Util' => 1.42,
'Class::Std::Utils' => 0.0.3,
'MIME::Base64' => 3.15,
'File::Slurp' => 9999.19
}
);
The Makefile.PL doesn't install prerequisites; it just complains if they're not installed. It's the CPAN client's job to install prerequisites.
Note: Module::Install has an auto_install feature that does this, but the general consensus seems to be that using it is a bad idea.
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.
If I have a distribution with X and X::Y also in it, how do I make Module::Build install both the modules? I have put X.pm in lib, written a file Build.PL with the line
my $build = Module::Build->new
(
module_name => "X",
);
This installs X OK, but how do I tell Module::Build to also include X::Y in the distribution?
Module::Build should automatically find and install both modules, though you should indicate to it (in Build.PL) which one the distribution name/version is taken from.
Try creating your distribution with module-starter and let it worry about the details?
module-starter -mb --module=X --module=X::Y --author=Me --email=me#example.com