PerlApp generate perl script to executable. I get a problem using the PerlApp
Here are the steps:
Generate a perl script (e.pl) with the following 2 lines
require Date::Manip;
require Date::Manip::DM6;
perlapp e.pl --add Date::Manip --add Date::Manip::DM6
e.exe generate the following errors:
c:_test>e.exe
ERROR LOADING MODULE: Date::Manip::DM6 at /Date/Manip.pm line 35.
You need to add more than just Date::Manip::DM6:
perlapp --add Date::Manip::** e.pl
The wildcards indicate that all submodules in the Date::Manip namespace should be added, including some that are more than 1 level down. The error is because DM6 depends on these other submodules, some of which seem to be implicit.
Also you don't need to require Date::Manip::DM6 as that is not how you're meant to use the module. Version 6 is used automatically depending on your version of perl, which gets included in your compiled exe.
Just in case you're suffering from an XY Problem:
Considering using pp instead of PerlApp. The following works just fine:
use strict;
use warnings;
use Date::Manip;
print "Hello World\n";
And then packaging:
pp hello_date.pl
Related
I have made my own perl modules(pm files),named test.pm
package test;
use Exporter;
use strict;
use File::Basename qw(basename dirname);
use Cwd qw(abs_path);
use File::Path qw(make_path);
use FindBin qw($Bin $Script);
BEGIN {
our #ISA = qw(Exporter);
our #EXPORT = qw(mkdirOrDie);
our $VERSION = 1.0;
}
sub mkdirOrDie
{
my ($dir) = #_ ;
if(!-d $dir){
make_path($dir);
$dir=abs_path($dir);
# timeLog("Directory Created: $dir");
}
}
and I tried to install this module as follows,
h2xs -AX -n test
perl Makefile.PL
make
make install
there is no error,and I copy the test.pm to /usr/lib64/perl5/5.10.0/,but when i call sub function using test, an error has occurred,
Undefined subroutine &main::mkdirOrDie called at /to/my/path/main.pl line 92
is there something i ignored?
It's unclear at which point things started to go wrong for you.
Firstly, test.pm is a bad name for a Perl module. Perl modules should have names that begin with upper case letters (and Test.pm is already taken).
You should run h2xs before writing your code - as it generates a module skeleton for you fill in. I hope it hasn't overwritten your code with an almost empty file! It's also worth noting that most people stopped using h2xs many years ago. These days we have tools like Module::Starter.
Then, running, make install (which you need to do with root permissions - so usually with sudo) is what installs your module into the system libraries. There should be no need to run that cp command afterwards.
As for why your code doesn't find the module, there are many possible reasons. Are you using Perl 5.10 or do you have other Perl versions installed? What does the code look like that you are trying to use? Does test.pm still include the code you think it does?
Need more information to be much help here.
I'm using the PAR::Packer module to create a Windows executable of a Perl script that uses the Unicode::GCString module.
A stripped down version of the script is as follows:
mwe.pl
#!/usr/bin/env perl
use strict;
use warnings;
use Unicode::GCString;
my $gcs = Unicode::GCString->new("hello world");
print $gcs->columns();
exit(0);
When I run
perl mwe.pl
the output gives the 'width' of the string:
11
which is as expected.
I create mwe.exe using the command
pp -o mwe.exe mwe.pl
and when I run
mwe.exe
I receive the error
Can't locate object method "new" via package "Unicode::GCString" at
script/mwe.pl line 6
Having reviewed AppData\Local\Temp\par-xxxxxx\cache-xxxxx\inc\lib, I believe that Unicode::GCString is present, as is Unicode::LineBreak.
Does anyone have any ideas on how to fix this?
A solution can be to use this version of "pp" I call it "ppp.pl"
$ENV{PAR_VERBATIM}=1;
system 'pp', #ARGV;
Details at https://metacpan.org/pod/distribution/PAR/lib/PAR/Environment.pod#PAR_VERBATIM
The cause is related to this bug Bug #38271 for PAR-Packer: PodStrip does not strip "=encoding utf8" which cause the executable generated by pp failed to exec
Also the boilerplate inside Unicode::GCString
Is there any way to report the missing modules used in the Perl file beforehand instead of getting as an error.
I have something like use Digest::MD5, use File::DosGlob modules in my Perl program. Whenever the users run the script they are getting an error if there is no specific module installed in their system. They could not understand the default error message given by #INC. So I would like to clearly tell them that these modules need to be installed to run the script.
You could build your own verification by using a BEGIN block. Those are run at compile time, just like use is. Keep in mind that use Foo is essentially nothing else as this:
BEGIN {
require Foo;
Foo->import;
}
The following code will replace all use statements with a single BEGIN and place them inside an eval. That's essentially like a try/catch mechanism.
We need the string eval (which is considered evil around here) because require only converts from package names with colons :: to paths if the argument is a bareword. But because we have the name in $module, it's a string, so we need to place it into an eval according to require's docs.
If that string eval fails, we die. That's caught by the outer eval block and $# is set. We can then check if it contains our module name, in which case we naively assume the failure was because that module is not installed. This check could be a bit more elaborate.
We keep track of any failures in $fails, and if there were any, we stop.
#!/usr/bin/perl
use strict;
use warnings;
# all our use statements go here
BEGIN {
my $fails;
foreach my $module ( qw/Digest::MD5 File::DosGlob ASDF/ ) {
eval {
eval "require $module" or die; # because $module is not a bareword
$module->import;
};
if ($# && $# =~ /$module/) {
warn "You need to install the $module module";
$fails++;
}
}
exit if $fails;
}
# ...
Above I included ASDF, which I don't have, so when run it will say
You need to install the ASDF module at /home/code/scratch.pl line 1335.
You might want to make that message a bit more verbose. If your users are not able to understand the default error message that Perl gives when it cannot find a module, it might be wise to include a guide on how to install stuff right there.
Note that both modules you listed have been included with Perl for a while (read: since March 2002). So why would you want to do this for those modules?
$ corelist Digest::MD5
Data for 2014-09-14
Digest::MD5 was first released with perl v5.7.3
$ corelist File::DosGlob
Data for 2014-09-14
File::DosGlob was first released with perl 5.00405
A better way would be ship your program as a distribution that can be installed, and include a Makefile or a cpanfile or something similar that lists dependencies. There is a guide in perlnewmod on how to start a new module. You'd not want to upload to CPAN obviously, but the basics are the same.
With this, your users would get all dependencies installed automatically.
You could use Devel::Modlist, it will list all the required module for your program.
perl -d:Modlist test.pl
There's another module Module::ScanDeps which comes with a utility scandeps.pl which you can use on your script as:
scandeps.pl test.pl
Note that sanity checking your Perl code using perl -c is dangerous, so use it carefully.
Your question isn't really clear about what "beforehand" means. To check if a Perl program's syntax is correct and directly included modules are resolvable, use
perl -c <perl-program.pl>
This checks the syntax of your file and ensures that any modules used by your code exist. However, it does not transitively check the entire dependency tree, only those mentioned in perl-program.pl.
I created a perl script that includes the Switch module.
hello_world.pl
use strict;
use warnings;
use Switch;
use Data::Dumper;
my $var = "Hello World\n";
print Dumper($var);
if I launch perl hello_world.pl everything works fine. But if I pack my script with pp hello_world.pl and than launch ./a.out it gives me back this error:
Can't locate Switch.pm in #INC (you may need to install the Switch module) (#INC contains: CODE(0x7fb2631e6a88) /var/folders/rb/2b5sbs355n57svwzjjh7cb9c0000gn/T/par-6967676c6f62616c33/cache-710e967842eb844ab8d6fe5f46968c1b6f49e019/inc/lib /var/folders/rb/2b5sbs355n57svwzjjh7cb9c0000gn/T/par-6967676c6f62616c33/cache-710e967842eb844ab8d6fe5f46968c1b6f49e019/inc CODE(0x7fb262988de0) CODE(0x7fb262989930)) at script/hello_world.pl line 3.
BEGIN failed--compilation aborted at script/hello_world.pl line 3
$ corelist Switch
Data for 2016-05-09
Switch was first released with perl v5.7.3, deprecated (will be CPAN-only) in v5.11.0 and removed from v5.13.1
Switch was never a good idea. It's a source filter which means it's a clever party trick but shouldn't be used in production code. For that reason it has removed from Perl several versions ago.
I suspect that you are running your packaged program on a more recent version of Perl than the unpackaged version - one that no longer includes Switch.
You can install Switch on your target system or you can work out how to get pp to include the module in the package. But the best solution is to rewrite the code to stop using Switch.
You can try to force the modules to be included, with -M option:
pp -M Switch -M YAML ...
I have a perl script written for version 5.6.1 and which has dependencies on Oracle packages, DBI packages and more stuff. Everything is correctly installed and works.
Recently perl version 5.8.4 got installed and because those dependencies are not correctly set so the script fails.
'perl' command points to /program/perl_v5.8.4/bin/perl -- latest version
So, when I have to run my perl script I have to manually specify in command prompt
/program/perl_v5.6.1/bin/perl scriptName.pl
I tried adding following lines in script:
/program/perl_v5.6.1/bin/perl
use v5.6.1;
But, this means script has to take Perl version > 5.6.1
I found couple of related question which suggested:
To export path. But, I want the script for all the users without have to export path
Specify version greater than. But, I want to use just one specific version for this script.
use/require commands. Same issue as above.
My question: How to specify in the script to only use a specific version of perl?
The problem is that the interpreter specified in the shebang line (#!/some/path/to/perl) is not used if perl script is called like this:
perl some_script.pl
... as the 'default' (to simplify) perl is chosen then. One should use the raw power of shebang instead, by executing the file itself:
./some_script.pl
Of course, that means this file should be made executable (with chmod a+x, for example).
I have in my code:
our $LEVEL = '5.10.1';
our $BRACKETLEVEL = sprintf "%d.%03d%03d", split/\./, $LEVEL;
if ($] != $currentperl::BRACKETLEVEL)
{
die sprintf "Must use perl %s, this is %vd!\n", $LEVEL, $^V;
}
These are actually two different modules, but that's the basic idea. I simply "use correctlevel" at the top of my script instead of use 5.10.1; and I get this die if a developer tries using the wrong level of perl for that product. It does not, however, do anything else that use 5.10.1; would do (enable strict, enable features like say, switch, etc.).