Can a Perl module distribution include a script - perl

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:

Related

ExtUtils::MakeMaker doesn't generate make target to install dependencies for development

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.

Perl: Makefile.PL, File::ShareDir::Install, chicken and eggs

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.

Is it possible to setup the cross module version in VERSION_FROM option (of Makefile.PL)?

I want to setup the same version for few projects in one place.
I've tried:
use ExtUtils::MakeMaker;
WriteMakefile(
VERSION_FROM => 'lib/project/version.pm',
...
In 'lib/project/version.pm':
package project::version;
use AnotherProject;
our $VERSION = AnotherProject->VERSION();
1;
Note: AnotherProject is located in separate directory, but could be loaded by 'use AnotherProject'. And contain 'our $VERSION="1.00"'.
$ perl Makefile.PL
WARNING: Setting VERSION via file 'lib/project/version.pm' failed
at /usr/lib64/perl5/5.18.2/ExtUtils/MakeMaker.pm line 599.
Can't parse version 'undef'
Is it possible to pass (get) the version string from another module?
Maybe there is another way to do it, please support me.
When you use VERSION_FROM, ExtUtils::MakeMaker doesn't run the file you point at, it parses it itself and tries to find a version number that way. In this case, that won't work. Using VERSION instead of VERSION_FROM in Makefile.PL and calling the other module from there should work.

Can I build Perl modules with ExtUtils::MakeMaker-based build system "out of tree"?

Instead of adding or modifying files in the directory where the sources of a Perl module are unpacked, I would like to build everything in a separate directory. Is this easily achievable with a fairly standard Makefile.PL that uses ExtUtils::MakeMaker? (By easy, I mean something like one or a few command line parameters.) If no, does any of the other build systems support this?
Update / Reason: The Perl module is a binding to a library whose build system is autoconf/automake/libtool-based. The Perl module is shipped together with this library and calling make in the top directory eventually also builds the Perl library. I am interested in building the entire project in a separate build tree. At the moment I do something similar to what runrig suggested, only using symlinks. (cp -sru $(srcdir)/. $(builddir)/.). This has worked so far, but if there is a more elegant solution, I'd like to read about it.
MakeMaker already copies the sources and builds them in a separate directory (that's what blib/ is). You can control the build location with the INST_* set of arguments to WriteMakefile(). This example changes the location from blib/ to foo/.
INST_ARCHLIB => "foo/arch",
INST_LIB => "foo/lib",
INST_BIN => "foo/bin",
INST_SCRIPT => "foo/script",
INST_MAN1DIR => 'foo/man1',
INST_MAN3DIR => 'foo/man3',
In addition you have to tell MakeMaker to cleanup the new build directory.
clean => {
FILES => 'foo'
},
See "Determination of Perl Library and Installation Locations" in the ExtUtils::MakeMaker docs for more info.
cp -R Module-Directory-0.01 Module-Directory-0.01.copy
cd Module-Directory-0.01.copy
perl Makefile.PL
make
make test
...etc.
I ended up using symlinks:
The library to which the Perl module provides bindings uses an
autoconf/automake/libtool-based build system. Makefile.PL is
generated from Makefile.PL.in by configure. Makefile.PL
generates Makefile-pl (Makefile has already been taken by
autoconf/automake).
This is the relevant part of Makefile.am:
all: Makefile-pl src_deps
$(MAKE) -f Makefile-pl
Makefile-pl: Makefile.PL
perl Makefile.PL INSTALLDIRS=$(INSTALLDIRS) PREFIX=$(prefix)
I changed the second target to:
Makefile-pl: Makefile.PL
-[ $(srcdir) != $(builddir) ] && cp -rsu $(abs_srcdir)/. $(builddir)/.
perl Makefile.PL INSTALLDIRS=$(INSTALLDIRS) PREFIX=$(prefix)
This should work as long as building or installing the Perl module
does not result in any files being modified in-place.

How can I tell Module::Build not to add the lib/perl5 subdirectories to the installation path?

I am trying to setup a directory that contains Perl modules that should be set aside to not interfere with a production system.
This works OK, with modules that use Module::Install. I just specify a "lib" option and all is well. Now I tried and tried and I simply cannot make this happen with Module::Build. For instance, this command:
./Build install --lib /foo
Will install the module in "/foo/share/perl/5.10.0".
How can I get rid off the "share/perl/5.10.0" part?
PS: Yes, I have taken a long look at the documentation and found some promising sections, but I simply must admit that I seem to be too stupid to grok them.
See install_path. It looks like (I haven't tried) you can either put in .modulebuildrc or specify on the command line all of the path options:
./Build install --install_base $CUSTOMPERLSTUFF \
--install_path lib=$CUSTOMPERLSTUFF/lib \
--install_path arch=$CUSTOMPERLSTUFF/lib
I think your best chance is with install_base. From the doc:
install_base
You can also set the whole bunch of installation paths by supplying the install_base parameter to point to a directory on your system. For instance, if you set install_base to "/home/ken" on a Linux system, you'll install as follows:
lib => /home/ken/lib/perl5
arch => /home/ken/lib/perl5/i386-linux
script => /home/ken/bin
bin => /home/ken/bin
bindoc => /home/ken/man/man1
libdoc => /home/ken/man/man3
binhtml => /home/ken/html
libhtml => /home/ken/html