Can't find application class in #INC when starting Mojolicious-generated app - perl

I generated a mojolicious app with the command mojo generate app first-app. It generated the app structure that should allow a running example when running the dev server with morbo ./script/first-app.
The file structure looks like this:
mojo app structure
My error when running morbo ./script/first-app in the root of the project directory is this error:
Can't load application from file "/home/djnorrisdev/Documents/mojo-practice/first-app/script/first-app":
Can't find application class "first-app" in #INC. (
/home/djnorrisdev/Documents/mojo-practice/first-app/lib
/home/djnorrisdev/perl5/perlbrew/perls/perl-5.30.0/lib/site_perl/5.30.0/x86_64-linux
/home/djnorrisdev/perl5/perlbrew/perls/perl-5.30.0/lib/site_perl/5.30.0
/home/djnorrisdev/perl5/perlbrew/perls/perl-5.30.0/lib/5.30.0/x86_64-linux
/home/djnorrisdev/perl5/perlbrew/perls/perl-5.30.0/lib/5.30.0)
Compilation failed in require at (eval 72) line 1
(Line breaks added for readability. An indented line is a continuation of the previous line.)
I tried using the full path for morbo (as mentioned in a 6 year old SO post), but that gives the same error as above. That command was this: /home/djnorrisdev/perl5/perlbrew/pls/perl-5.30.0/bin/morbo ./script/first-app
I'm guessing anyone familiar with a full mojolicious app would be familiar with the script file, but here's the contents of script/first-app :
#!/usr/bin/env perl
use strict;
use warnings;
use Mojo::File 'curfile';
use lib curfile->dirname->sibling('lib')->to_string;
use Mojolicious::Commands;
# Start command line interface for application
Mojolicious::Commands->start_app('first-app');
Considering this is a mojolicious-generated app, I would assume it should not get an #INC error and run with morbo without issue. Does anyone have insight into this?

For your setup to work, first-app.pm would have to contain package first-app;, but that's not legal code because of the dash. Håkon Hægland suggests that mojo generate app first-app should not have worked (presumably to avoid this very problem), so it's unclear how you came to have the setup you describe.
To fix the problem, you could rerun mojo generate app with a more suitable name (such as FirstApp) and start over.
Alternatively, you should theoretically be able to fix the problem with as little as three changes:
Rename lib/first-app.pm to a more conventional name such as lib/FirstApp.pm.
Change the argument passed to ->start_app to 'FirstApp'.
Change the package directive in now-named lib/FirstApp.pm to package FirstApp;.
A module's path, a module's package directive, and the use statement used to load the module —the value passed to ->start_app in this case— must all match. The three changes ensures this for the module in question.
[Note: I have no experience with Mojo.]

Related

Perl executable crashes even though file is not missing

I get the following error:
Can't load '...\AppData\Local\Temp\par-6e72616f\cache-20221205133501\5743946b.xs.dll' for module GD:
load_file:
The specified module could not be found at <embedded>/DynaLoader.pm line 193.
at <embedded>/PAR/Heavy.pm line 140.
(Line breaks added for readability.)
Here is the file t2.pl:
use GD;
Here is the command to convert it to an exe (I use a batch file that timestamps it):
pp -T 20221205133501 -o t2_20221205133501.exe t2.pl
On my laptop, the exe works, but on a barebones Citrix environment it fails.
My environment:
Strawberry Perl v5.32.1 built for MSWin32-x86-multi-thread-64int
GD v2.73
I know the file is simple, but that one line is enough to cause the crash.
The file it complains about exists and is located where it is looking.
I have looked and is looks like I need to add -m GD, or -l xxx to make it work. I tried adding all the dll files I could find for GD, but failed.
I have a corporate environment so I can't really use anything that depends on external programs not in Windows 10. pp_simple depends on wxpar which I do not have. I have used:
objdump -x C:\Strawberry\perl\vendor\lib\auto\GD\GD.xs.dll | find "DLL"
which got me a list of DLLs, and I did try using them with -l.
From Re: Par with strawberry-Perl
There are likely missing DLLs that need to be added to the pp call
using the --link option.
Finding these manually can be a pain, so have a look at pp_autolink or
pp_simple (the former is mine, but adapted from the latter).
https://github.com/shawnlaffan/perl-pp-autolink
https://www.perlmonks.org/?node_id=1148802

Perl IO::Socket::INET6::sockaddr_in6 redefined error

We have a custom perl install (5.10.1) in /usr/share, and I tried to do a 'cpan -i' install of GeoIP2 here
After doing this, it seemed to install a lot of dependencies I couldn't keep track of, and since I've been getting an error
Subroutine IO::Socket::INET6::sockaddr_in6 redefined at /usr/share/perl5/Exporter.pm line 67
On most scripts that we run that uses a 'use' command. I've been trying to nail down which module eventually calls that, but not succeeded as yet.
After some research, one suggestion was to comment out the following lines of
/usr/share/perl5/IO/Socket/INET6.pm # (version 2.56, think latest is 2.72)
###commented out the following
###use Socket6 (
### qw(AI_PASSIVE inet_ntop inet_pton getaddrinfo
### sockaddr_in6 unpack_sockaddr_in6_all pack_sockaddr_in6_all)
###);
This has stopped the errors from appearing on various scripts. Does anyone know if this is safe to do (ie will it cause further problems later), and is there a better way to go (ie is it possible to just update that module, I'm guessing that would cause problems and break other stuff?). What would be the best method of getting the module updated correctly ?
This was a bug in IO::Socket::INET6 which was fixed in version 2.69 according to this bug report:
Subroutine main::sockaddr_in6 redefined at /usr/share/perl/5.14/Exporter.pm line 67.
...
Should be fixed in 2.69.
You can update the module using cpan with the command cpan IO::Socket::INET6 from the shell as root.
Easiest is just to stop using IO::Socket::INET6 at all. That was created a very long time ago, but a far better solution has been created using the core Socket module, being IO::Socket::IP. Furthermore, this latter module is now core also since the newly-released 5.20. it would be better to use that IO::Socket::IP as that is the new core-recommended way to achieve IPv4/IPv6 transparency from now on.

Running Perl Script as CGI Script vs from cmd line

I am trying to run a Perl script as a CGI script. When I run the perl script from cmd line, it runs perfectly well, but it shows the following error when I run it from my browser.
Storable object version 1.012 does not match $Storable::VERSION 1.010 at
C:/Perl/lib/DynaLoader.pm line 225.
Compilation failed in require at C:/Perl/site/lib/AsiaXMLUtils.pm line 20.
BEGIN failed--compilation aborted at C:/Perl/site/lib/AsiaXMLUtils.pm line 20
The perl script concerned has basically been designed to queue some job to a remote software.
In case it rings a bell, Line 20 in the mentioned file is :
use Storable qw(&retrieve &store);
Here are the things I have done :
I have checked the following pages on how to troubleshoot your CGI
script but haven't got around the problem.
I have checked that the perl versions are the same for my PC as well
that used for the software I am sending the script too. I guess had
that been a problem, I wouldn't have been able to run the script
from the commnad line either.
I have run a simple Perl CGI (hello world) script using the same basic html code, so I guess that means I am not putting the cgi files (or accessing them) at the wrong places.
I am running a deadline for finishing this task, and thought should ask what approach I should take to solve such a problem. I am new to Perl. Any cues to what I should read to get around the problem will be greatly appreciated. I cannot share the code anyways, since much of it is proprietary.
Storable is an XS module, which means that it has both C code in Storable.dll (or Storable.so on Unix) and Perl code in Storable.pm. That error indicates that the version of Storable.dll ("Storable object version 1.012") does not match Storable.pm ("$Storable::VERSION 1.010"). If you can run the script from the command line, that means that your webserver is either using a different version of Perl, or #INC is different, or possibly you have an extra Storable.dll in your webserver's directory.
Try to use nstore instead of store. This way, your file will be crossplatform.
Also, try to reinstall the Store module.
Here is how I was able to solve the issue, which btw wouldn't have been possible without the valuable inputs of Miguel Prz and cjm.
Regarding the Storable Module : After reading both the answers, I noticed that my pc had two versions of
Perl. I removed one of them. This got me around the "Storable object
version 1.012 does not match $Storable::VERSION" error. Sounds pretty lame, I know. But I thought I should let you know anyways. But then
I ran into another set of problems. This :
Can't locate
AJE/Constants.pm in #INC (#INC contains: C:/Perl/lib
C:/Perl/site/lib .)
From comparing with the #INC of the perl environment from the
command line (for which I found this SO post very useful), I
noticed that the #INC that my web server was using (consisting of only 2 directories as shown above) did not include
many of the directories in the #INC of the command line perl environment. This is where cjm's words came back to me! I then used use lib to add those files in my
perl script and that solved the problem!
Thank you for all the help!

How can I run a test perl script designed for prove form inside TextMate?

I'm using TextMate 1.5.10 (Mac OSX 10.7.2) to write a perl modulino application. To verify the functionality, I'm using test scripts designed to be run with the prove command line tool.
An example of the directory structure I'm using looks like this:
text_mate_test/MyModule.pm
text_mate_test/t/001_load_test.t
The 001_load_test.t file looks like this:
#!/usr/bin/perl
use Modern::Perl;
use Test::More;
use MyModule;
my $testObj = new_ok("MyModule", undef, "Initial load test.");
done_testing();
When I run prove or prove -v in the "text_mate_test" directory, everything passes as expected.
I'd like to be able to setup a hotkey in TextMate that allows me to run the test file without having to jump over to the terminal. Currently, if I run "001_load_test.t" directly from inside TextMate with Cmd+R, it chokes saying "Can't locate MyModule.pm in #INC". That's expected since the test script isn't designed to run directly. (I'm still pretty new to writing test files, but I believe that's the proper way to set them up.)
Running off the assumption that I don't want to change the test file itself, is there a way to setup a hotkey so I can run the file accurately from inside TextMate?
I've figured out an even better way to do this.
In the TextMate Bundle Editor (Menubar -> Bundles -> Bundle Editor -> Show Bundle Editor), I've updated the default "Perl -> Run Script" bundle to this:
#!/usr/bin/env ruby
require "#{ENV["TM_SUPPORT_PATH"]}/lib/tm/executor"
require "#{ENV["TM_SUPPORT_PATH"]}/lib/tm/save_current_document"
TextMate.save_current_document
TextMate::Executor.make_project_master_current_document
### If it's a ".t" test script in a "t" directory, run prove
if ( ENV["TM_FILEPATH"] =~ /^.*\/(t\/[^\/]+)$/ )
### Grab the relative file path for more legible output
relative_file_path = $1
### Jump up one directory so prove will work
Dir.chdir("../");
### Call prove with args to run only the file you are working on.
TextMate::Executor.run("prove", :script_args => ["-v", relative_file_path]);
### Otherwise, run with perl
else
TextMate::Executor.run(ENV["TM_PERL"] || "perl", "-I#{ENV["TM_BUNDLE_SUPPORT"]}",
"-Mexception_handler", ENV["TM_FILEPATH"],
:version_args => ["-e", 'printf "Perl v%vd", $^V;'])
end
Here's a screenshot of how it looks in the Bundle Editor.
The benefit of this is that you can use the same hot key (Cmd+r by default) to run your normal scripts with perl and your test scripts with prove.
This is what I was looking for.
UPDATED: When I first developed this, I only had one test script in the "t" directory. I didn't notice until I added other test scripts that the code in the original version of this answer would run prove across all the scripts. Not just the one being worked on. To get back to the expected behavior, I've update the bundle code so that prove will only run on the active script.
I've come up with a solution. Create a new Perl bundle called "Run Script with prove" and associate it with Shift-Cmd-R. The code for the bundle is:
#!/usr/bin/env ruby
require "#{ENV["TM_SUPPORT_PATH"]}/lib/tm/executor"
require "#{ENV["TM_SUPPORT_PATH"]}/lib/tm/save_current_document"
TextMate.save_current_document
TextMate::Executor.make_project_master_current_document
### If it's a ".t" test script in a "t" directory, run prove
if ( ENV["TM_FILEPATH"] =~ /^.*\/(t\/[^\/]+)$/ )
### Use the relative file path for more legible output
relative_file_path = $1
### Jump up one directory so prove will work
Dir.chdir("../");
### Call prove with args to run only the file you are working on.
TextMate::Executor.run("prove", :script_args => ["-v", relative_file_path]);
else
error_string = "This script's filepath doesn't end with /t/.*\.t\n"
error_string += "That is required for the 'Perl -> Run Script with prove' bundle to work.\n"
TextMate::Executor.run("echo", :script_args => [error_string]);
end
Note: This is the results of a bunch of trial and error hacking. I don't know if it's the "right" to do it, but this works for me. Everything but the last two lines is a copy from the original "Run Script" bundle that comes with TextMate. Based on that, it seems like this should be pretty safe.
UPDATE: When I first built this I only had one test file in the "t" directory. When I added more, I discovered that the original version of the bundle was running all the test files. This code represents an update to the expected behavior of only running the test script you working on. Because of the way I ended up doing that, it also became necessary to add in a fallback. If you try to run a script that doesn't match the standard test file path format, it gives an error message.
It will enable the program to find your module if you add
use lib '..';
to the top of your code (before the use MyModule). This will add the text_mate_test directory to #INC and enable Perl to find the module, though you may come across other problems with running the program directly.

How can I install CPAN modules locally without root access (DynaLoader.pm line 229 error)?

Doesn't work with other modules, but to give an example. I installed Text::CSV_XS with a CPAN setting:
'makepl_arg' => q[PREFIX=~/lib],
When I try running a test.pl script:
$ perl test.pl
#!/usr/bin/perl
use lib "/homes/foobar/lib/lib64/perl5/site_perl/5.8.8/x86_64-linux-thread-multi";
use Text::CSV_XS;
print "test";
I get
Can't load '/homes/foobar/lib/lib64/perl5/site_perl/5.8.8/x86_64-linux-thread-multi/auto/Text/CSV_XS/CSV_XS.so' for module Text::CSV_XS: /homes/foobar/lib/lib64/perl5/site_perl/5.8.8/x86_64-linux-thread-multi/auto/Text/CSV_XS/CSV_XS.so: cannot open shared object file: No such file or directory at /www/common/perl/lib/5.8.2/i686-linux/DynaLoader.pm line 229.
at test.pl line 6
Compilation failed in require at test.pl line 6.
BEGIN failed--compilation aborted at test.pl line 6.
I traced the error back to DynaLoader.pm it happens at this line:
# Many dynamic extension loading problems will appear to come from
# this section of code: XYZ failed at line 123 of DynaLoader.pm.
# Often these errors are actually occurring in the initialisation
# C code of the extension XS file. Perl reports the error as being
# in this perl code simply because this was the last perl code
# it executed.
my $libref = dl_load_file($file, $module->dl_load_flags) or
croak("Can't load '$file' for module $module: ".dl_error());
CSV_XS.so exists in the above directory
When you installed the module, did you watch the output? Where did it say it installed the module? Look in lib. Do you see the next directory you expect?
Look in ~/lib to see where eveything ended up to verify that you have the right directory name in your use lib statement:
% find ~/lib -name CSV_XS.so
Once you see where it is installed, use that directory name in your use lib (or PERL5LIB or whatever).
I expect you have a lib/lib in there somehow. The PREFIX is just the, well, prefix, and the installer appends other directory portions to that base path. That includes lib, man, bin, etc.
Personally I would suggest to use local::lib. :)
Try this instead:
'makepl_arg' => q[PREFIX=~/]
PREFIX sets the base for all the directories you will be installing into (bin, lib, and so forth.)
You may also be running into shell expansion problems with your '~'. You can try to expand it yourself:
'makepl_arg' => q[PREFIX=/home/users/foobar]
It would also be helpful if you included the commands you used to get the error you are asking about.
It looks from the error message ("at /www/common ...") that your script is a CGI or mod_perl script. The web server is probably not running as the user 'foo', under whose home directory you've installed the module - that could result in the web server being unable to read that directory.
It may also be running in a "chroot jail", which would mean that the directory in which you've installed the module may not be visible to the script.
In other words, just because you can see the module, does not mean that the web server, and therefore your script, can do so. You should check the relevant file permissions, and if the server is chrooted, whether your module directory is mounted within the virtual file system.
Does the file in question (CSV_XS.so) exist?
Does it exist at the listed location?
If you do:
set |grep PERL
What is the output?
Have you successfully installed other local perl modules?
I strongly suggest installing your own perl in your own home directory, if you have space. Then you can keep everything under your control and keep your own module set, as well as escaping if the admins are keeping you on an older version of perl. (Not to mention preserving yourself if they upgrade some day and leave out all the modules you are relying on.)