2

I have packaged my app as a Perl module, which fails to install using the cpan or cpanm commands. The problem is that these commands - when not run as root - install the prerequisite modules into the ~/perl5 directory. However, my ~/perl5 directory is not included in the @INC

This leads to the following confusing output from cpanm:

$ cpanm --installdeps .
--> Working on .
Configuring my-module-0.001 ... OK
==> Found dependencies: Image::Size
--> Working on Image::Size
Fetching http://www.cpan.org/authors/id/R/RJ/RJRAY/Image-Size-3.232.tar.gz ... OK
Configuring Image-Size-3.232 ... OK
Building and testing Image-Size-3.232 ... OK
Successfully installed Image-Size-3.232
! Installing the dependencies failed: Module 'Image::Size' is not installed
! Bailing out the installation for my-module-0.001.
1 distribution installed

As you can see, it successfully downloads, tests and installs the Image::Size module, but then tries to use it and fails.

I know I can fix this problem by setting the environment variable $PERL5LIB to "~/perl5/lib/perl5" and adding "~/perl5/bin" to my $PATH, but I'd really like to know how this situation arose in the first place. I would like to keep the installation instructions for my app's users as simple as possible, and manually modifying environment variables is not something I plan to instruct them.

Jaap Joris Vens
  • 3,382
  • 2
  • 26
  • 42
  • If you don't have root privileges, you can't install into the system directories. End of story. Tell them to use `su`, or just don't tell them anything at all; since this is normal behaviour, they will not be expecting anything different. – CodeClown42 Jul 13 '14 at 12:26
  • @goldilocks Isn't it unexpected that cpan and cpanm install to ~/perl5, from where the modules cannot automatically be used? – Jaap Joris Vens Jul 13 '14 at 14:23
  • Not if you are non-root. System directories are read-only for normal users and everyone knows that. They will not expect to magically be able to add their own modules to `/usr/lib/perl5` because the only magic that could accomplish that would be to set the directory world writable, which is obviously an incredibly bad idea. When I'm working on a system where I do not have root privileges and I need to install my own modules, I know I have to use my home directory. That's totally normal. – CodeClown42 Jul 13 '14 at 14:34
  • You're right, it makes total sense that a non-root user cannot write to /usr/lib/. However, it is very weird that once the modules are installed to ~/perl5, they cannot be used! – Jaap Joris Vens Jul 13 '14 at 15:02
  • I don't know why `@INC` doesn't include that directory by default -- perhaps because then there's the issue of whether it should pre-empt (listed first) or be pre-empted (listed last) and it's a bit easier to add to `@INC` than to remove from it. It's also the norm, though, with e.g. `$PATH`, `$LIBRARY_PATH`, etc., so this convention perhaps follows that one. – CodeClown42 Jul 13 '14 at 15:10

2 Answers2

0

Here is my own solution to the problem. I switched to Dist::Zilla and came up with the following installation instructions for my users:

Installation instructions
=========================

To install this program you need Dist::Zilla, which can be installed
by running the following command as root:

    cpan Dist::Zilla

After that, make sure you're in directory where this INSTALL file is,
and run the following command as root:

    dzil install
Jaap Joris Vens
  • 3,382
  • 2
  • 26
  • 42
  • 1
    I would not recommend this solution. Dist::Zilla is a distribution building tool with a huge dependency chain and is not meant to be used as an installer. If you want your users to be able to install locally, I would recommend `cpanm` with `local::lib` (`cpanm -L ~perl5`) or `perlbrew` – friedo Jul 13 '14 at 23:05
  • @friedo I tried, but couldn't make concise installation instructions using cpanm or perlbrew. Experienced users will know what to do, and beginners will just have to type these two commands to make it work. I'd still love to learn of even simpler installation instructions. – Jaap Joris Vens Jul 14 '14 at 06:29
  • If I see these instructions, I _will_ know what to do, but I'm not sure I'll want to do it, especially if this is a module I want to use in production. – oalders Jul 14 '14 at 19:02
0

If you're using bash, you could install local::lib add something like this to your .bashrc file

# adds $HOME/perl5/bin to PATH
[ $SHLVL -eq 1 ] && eval "$(perl -I$HOME/perl5/lib/perl5 -Mlocal::lib)"

That should solve your problem. The issue is the way your local system is configured, so tweak that rather than bringing Dist::Zilla into the mix where it's not required.

oalders
  • 5,239
  • 2
  • 23
  • 34
  • Thanks for answering. My original question was mostly a rant that this doesn't get appended by default. I like Dist::Zilla though, keeps me focused on other things than packaging my module ;-) – Jaap Joris Vens Jul 15 '14 at 22:12
  • I hear what you're saying, but I think if it were appended by default, that might surprise a lot of people. :) I also like Dist::Zilla and use it for most of my CPAN modules. I just wouldn't want to deploy it with production code. – oalders Jul 16 '14 at 14:13
  • If it's a CPAN module, I use Dist::Zilla and "dzil release", so that the end user never needs to know what was used to create the distribution. The end user (ie not the developer) shouldn't ever need Dist::Zilla just to install the finished product. It pulls in a lot of other dependencies. If you use Dist::Zilla plugins it can get even worse. :) They're amazing tools for development, but they're not required for installation. – oalders Jul 17 '14 at 14:56
  • And if it's not a CPAN module? I.e., it's a non-library end-user application? – Jaap Joris Vens Jul 18 '14 at 17:24
  • For my own work (not $work) I usually deploy the master branch of a git repo. If I need to pull in other work that's not appropriate for CPAN I use git submodules and then add the path to those modules to INC. For CPAN modules I use https://metacpan.org/pod/Carton to install my modules locally. So, I'll run my scripts via a wrapper that does a "carton exec" and also adds any submodules I've included to INC. – oalders Jul 18 '14 at 18:52
  • 1
    Another option is to package and ship your code to a private repository using something like [Pinto](https://metacpan.org/pod/Pinto) or [Stratopan](http://stratopan.com). Then end-users can deploy your proprietary code in exactly the same manner that public CPAN modules are deployed. Disclaimer: I an responsible for both Pinto and Stratopan. – Jeffrey Ryan Thalhammer Dec 09 '14 at 05:01