I'm working on a Perl module called Mite. It is a "compiler", of sorts. You write Perl classes using a Moose-like declarative OO syntax. Rather than doing all the work to put the class together every time it's executed, Mite does that work at build time. It generates an extra file containing the Perl code for your accessors and inheritance and whatnot.
This extra file is put into lib with the rest of your code and released with your project. As a result, the installing user does not need to install Mite and the code loads faster.
During development, the mite compiler is run when make or Build is run. So things like make test and ./Build test just work. This is accomplished by using special shims for MakeMaker or Module::Build.
This works fine for Module::Build, but ExtUtils::MakeMaker does not see the mite files. MakeMaker hard codes a list of what is in lib when Makefile.PL is run. The pm_to_lib step then fails to copy the generated files into blib where make test will see them.
How can I best work around this problem? I wish the process to remain transparent to the developer (once they've loaded the appropriate shim), and require no special dependencies for the installing user.
UPDATE: Here is a clearer example. Let's say you have a project like this.
Makefile.PL
lib/
Foo.pm
Bar.pm
Foo/
Thing.pm
t/
foo.t
bar.t
You run perl Makefile.PL and then make. The make step has been modified to generate an extra .mite.pm file for each .pm file. After the make step, what I want is this.
Makefile.PL
Makefile
lib/
Foo.pm
Foo.pm.mite.pm
Bar.pm
Bar.pm.mite.pm
Foo/
Thing.pm
Thing.pm.mite.pm
blib/
lib/
Foo.pm
Foo.pm.mite.pm
Bar.pm
Bar.pm.mite.pm
Foo/
Thing.pm
Thing.pm.mite.pm
t/
foo.t
bar.t
All the new files introduced into lib have been copied into blib/lib where they can be seen as part of make test. What I get instead is this.
Makefile.PL
Makefile
lib/
Foo.pm
Foo.pm.mite.pm
Bar.pm
Bar.pm.mite.pm
Foo/
Thing.pm
Thing.pm.mite.pm
blib/
lib/
Foo.pm
Bar.pm
Foo/
Thing.pm
t/
foo.t
bar.t
That is because the Makefile is generated by Makefile.PL with a hard coded list of what is in lib.
(This is particularly silly, I maintained MakeMaker for 10 years and failed to fix this.)
I wound up adding a new target and having pm_to_blib depend on it. The new target just moves all .pm files from lib/ to blib/lib/. The redundancy shouldn't matter.
I'm not happy with this solution, but it appears to work.
https://github.com/evalEmpire/Mite/commit/feff24e4d68e062a06a721591ff0d785c5dad80b
Related
I have a bunch of unit tests for my module, and I find that I copy the same mock and setup code from one to the other. How can I DRY that up and reuse the mock code?
I've placed this simple mock object next to my tests:
package MockObject;
1;
If I just say use MockObject; in the test case, make test cannot find MockObject. Makes sense; after all, it's not installed system wide and it's not next to the module under test.
I can run my tests with prove -I lib -I t t/*.t but I'd like to keep make test, if only for the laziness of typing a few characters less.
Since the mock object isn't a full module and shouldn't be officially installed anyway, I cannot and don't want to set TEST_REQUIRES in Makefile.PL.
Adding test => { FILES => 't/*.t', INC => 't/' } to Makefile.PL didn't help.
How can I (simply) reuse Perl mock code with the MakeMaker generated Makefile?
Setup PERL5LIB or add use lib in your script. I found FindBin package useful for setting up the lib path for tests.
use FindBin qw($Bin);
use lib "$Bin/../lib";
Where:
$Bin - path to bin directory from where script was invoked
I have created a perl modul with 3 submodules. I want to create a makefile with MakeMaker and have a problem.
My structure of my module is
/module.pm and /module/sub.pm.
If i create the makefile only the module.pm file will be included. Which parameter i need to write in the makemaker so the submodules are included too?
Thank you very much.
Don't put your module in the root directory of your distribution. Instead, create a lib subdirectory and put all the modules under it:
Makefile.PL
lib/module.pm
lib/module/sub.pm
The Makefile.PL should automatically notice all modules under lib. You shouldn't have to change anything except any paths pointing to modules (e.g. VERSION_FROM).
If your module has a prefix, include that under the lib directory. If your module is named Some::Other::Module, you'd have:
Makefile.PL
lib/Some/Other/Module.pm
lib/Some/Other/Module/Sub.pm
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.
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.
My OS-Distribution provides the rpm-package "perl-obexftp", which installs the Modul "OBEXFTP".
These are the files:
/usr/lib/perl5/vendor_perl/5.10.0/x86_64-linux-thread-multi/OBEXFTP.pm
/usr/lib/perl5/vendor_perl/5.10.0/x86_64-linux-thread-multi/auto/OBEXFTP
/usr/lib/perl5/vendor_perl/5.10.0/x86_64-linux-thread-multi/auto/OBEXFTP/.packlist
/usr/lib/perl5/vendor_perl/5.10.0/x86_64-linux-thread-multi/auto/OBEXFTP/OBEXFTP.bs
/usr/lib/perl5/vendor_perl/5.10.0/x86_64-linux-thread-multi/auto/OBEXFTP/OBEXFTP.so
/var/adm/perl-modules/obexftp
I am using now a Perl which I have build from the source.
Is there a simple way to make this OBEXFTP-module accesseble to my Perlinstallation?
Choose one of
Add the following pragma to your code:
use lib '/usr/lib/perl5/vendor_perl/5.10.0';
Add that path to the PERL5LIB environment variable
Invoke your code with perl -I/usr/lib/perl5/vendor_perl/5.10.0 program
Rebuild perl so that path is in its baked-in #INC
Build the module yourself using your custom-built perl
For details, see perlrun.