Can I insert break point into source perl program? - perl

I want the perl program launch debugger when some condition hit. Some other language has debug() statement supported by library, is there any similar statement in perl?

If I understand you correctly, you need to use a specific debugger variable in your code - $DB::single. Setting this to a true value in your code will cause the debugger to stop on that line.
$x = 1234;
$DB::single = 1;
enter_problematic_sub_now();
Your code will then stop at the line with $DB::single set to 1.
Of course, if you can't actually ensure that your code is running in the debugger then you have another problem entirely. You will need to run your code via perl -d as well.

Have you tried adding the -d switch to the shebang line at the top of your script? Something like
#!/usr/bin/perl -d
use strict;
use warnings;
$|=1;$\="\n";
print "Test";
It really depends exactly how it gets launched, but at least in simple cases this should start the debugger.
Edit:
You can then set a breakpoint on a specific line with a certain condition using
> b [line] [condition]
and hit
> c
to continue with running the script - the debugger will stop at the specified line when the condition is met

Well, there is something which will enable you to do something like breakpoints, but the functionality is wider: Perl Debugger.

Essentially the -d switch allows you to communicate with the perl executable, and allows the perl executable to communicate with you.
More

Related

Run perl binary with autoflush enabled

My program runs perl as a process in potentially many places with different scripts which I have inherited and would prefer not to modify needlessly if I can avoid it.
The root problem I'm facing is that my program cannot consume standard output as the perl script is executing unless autoflush is enabled (otherwise it will just get every log message instantly after the perl script has finished).
Therefore, what I'd like to do is to run perl with autoflush enabled by command line argument if possible. Something like this would be ideal:
perl -e "$| = 1" -e "foo.pl"
But obviously that doesn't work.
There is a CPAN module called Devel::Autoflush that does exactly this. You would invoke it from the command line:
perl -MDevel::Autoflush your-script-name-here.pl
...and it sets autoflush mode. Looking at the source code it's pretty easy to see how it works. You could just implement it yourself if you live in a world where CPAN modules are not permitted. Just create a module as follows:
package AutoFlush;
my $orig_fh = select STDOUT;
$| = 1;
select STDERR;
$| = 1;
select $orig_fh;
1;
And then from the command line invoke it just as I described above:
perl -MAutoFlush your-script-name-here.pl
This little example module is almost identical to how Devel::Autoflush does it.
Update: And as TLP correctly points out, the following would be even simpler syntax:
package AutoFlush
STDOUT->autoflush(1);
STDERR->autoflush(1);
1;
This may pull in more code, since the syntax relies on the implicit on-demand upgrading of the STDOUT and STDERR filehandles to IO::Handle objects, but when coding for clarity and programmer efficiency first, this is an obvious improvement.

Whitespace with perl Switch module

The following trivially short perl program works fine (and does nothing, as expected):
use Switch;
switch (1) {}
However if I put the program on one line, as follows,
use Switch; switch (1) {}
I get an error
richard#affric:~$ perl foo.pl
syntax error at foo.pl line 1, near ") {"
Execution of foo.pl aborted due to compilation errors.
Can anyone explain this to me?
(Edit: Yes, I know Switch.pm is deprecated, and, yes, I know that the code is more readable with the line break.)
The Switch module is written as a Perl filter, which essentially means that the Switch module gets to see and make changes to the source code before the perl parser gets it.
I believe what you're seeing here is just a bug in the filter. If you use the backend B::Deparse module then you get a chance to see what nasty things Switch has done to your program. For instance, for your initial version
perl -MO=Deparse myswitch.pl
produces
use Switch;
S_W_I_T_C_H: while (1) {
local $_S_W_I_T_C_H;
&Switch::switch(1);
}
continue {
(last);
}
so you can see that there is plenty of scope for error.
If I had to guess I would say that Switch is simply expecting all of the line starting use Switch to contain module options and nothing else. If you use the -M switch to include the module, like this
perl -MO=Deparse -MSwitch -E'switch (1) { }'
then the result is this
use Switch;
S_W_I_T_C_H: while (1) {
local $_S_W_I_T_C_H;
&Switch::switch(1);
}
continue {
last;
}
-e syntax OK
which is different in that neither a compile time nor a run time error is raised.
Update
The problem seems to be an issue with the Filter::Util::Call module, on which Switch is based. The problem is that the text that this module passes to source filters begins only on the line following the use Switch statement. Anything after it on the same line is processed directly by the perl parser as normal.
That means that, in your second case, perl is seeing the (unmodified) program switch (1) {} while Switch has nothing to do as there is no code at all after this line to be filtered.
I think this is highly likely to be an inherent part of perl, and there is no way to intercept the source stream in the mid-line. But it's a non-critical bug and, now that you know the cause, you should be able to work around it easily.

How to debug a perl script used inside another perlscript?

How to debug a perl script used inside another perlscript. We can debug both separately. Is it possible to debug in one step?
Ex:
!/user/bin/perl
my $param= 8;
my #res=\`perl extract.pl $config`;
print "The results is .... #res\n";
Similarly, can we debug the perl scripts used inside shell script?
Thanks.
You can add -d switch to the shebang line of the script you are invoking:
#!/usr/bin/perl -d
A dynamic solution:
my $dswitch = $INC{"perl5db.pl"} ? "-d" : "";
my #res=`perl $dswitch extract.pl $config`;
$INC{"perl5db.pl"} is true when you are using the debugger, and false when you are not.
The "correct" thing to do would be to change your design so you are not calling the other script through a system command. Then you would have a single debugging environment.
The best design would be to make extract.pl into a module.
You could also use the do command to import the code from the other file: do 'extract.pl'. Then the only change needed would probably be the way you pass $config in.
Either of these approaches would be quite simple to implement and would have other benefits for continued development. Maybe you have a good reason not to do it this way, but I would consider this first if you haven't already.
Just debug extract.pl passing in the value in $config. If you don't know what it is, the age-old printf will do that for you.
say "\$config='$config'";
And then do:
perl -d extract.pl 'Stuff that printed in config'.
As the two are isolated processes, the only communication is what is passed on the command line and what is printed by the called script. So the called script should be capable of being tested without the calling script. (Unless you've set up some sort of IPC or shared memory or something tricky like that.)

.pm file that's loaded on every invocation of the perl interpreter?

I thought I remember reading somewhere about where perl can be configured to automatically load a certain .pm file on start up.
I know about PERL5OPT, but to my recollection, this was a specific file that would be loaded if it exists.
Is it a compile option that can be set (i.e. via Configure)?
Reading through perldoc perlrun it looks like you are looking for what is talked about in the -f option:
-f
Disable executing $Config{sitelib}/sitecustomize.pl at startup.
Perl can be built so that it by default will try to execute
$Config{sitelib}/sitecustomize.pl at startup (in a BEGIN block). This
is a hook that allows the sysadmin to customize how Perl behaves. It
can for instance be used to add entries to the #INC array to make Perl
find modules in non-standard locations.
Perl actually inserts the following code:
BEGIN {
do { local $!; -f "$Config{sitelib}/sitecustomize.pl"; }
&& do "$Config{sitelib}/sitecustomize.pl";
}
Since it is an actual do (not a require), sitecustomize.pl doesn't
need to return a true value. The code is run in package main , in its
own lexical scope. However, if the script dies, $# will not be set.
The value of $Config{sitelib} is also determined in C code and not
read from Config.pm , which is not loaded.
The code is executed very early. For example, any changes made to #INC
will show up in the output of perl -V. Of course, END blocks will be
likewise executed very late.
To determine at runtime if this capability has been compiled in your
perl, you can check the value of $Config{usesitecustomize} .
I've never done this, but it looks like if you put what you want in $Config{sitelib}/sitecustomize.pl you'll get what you are looking for.
See:
http://perldoc.perl.org/perlrun.html
http://www.nntp.perl.org/group/perl.perl5.porters/2007/10/msg129926.html
I'm confused by what you mean by "on start up". If you mean when a script / CGI / whatever is "started", then just use the module in the script:
use Data::Dumper;
Or do you mean something else?

Why doesn't "use lib" take effect in this way?

In my app, I put all the modules in one directory , let's just call it libx.
Since it's up to the user to choose where to deploy the app, I don't want to hardcode the lib path.
So at the beginning of myapp.pl, I wrote the following lines of code.
#! /usr/bin/perl -w
use strict;
my $curr_dir = $0;
my $curr_lib = $curr_dir;
$curr_lib =~ s/myapp\.pl/libx/;
use $curr_lib ;
Instead of getting what I'm expecting, I got compiling errors!
So what's wrong with my code? I don't want to hardcode the lib path when using use lib, how should I do this?
Sorry I forgot to mention that when the app is deployed, myapp.pl and libx are in the same directory.
use happens at compile-time, not run-time, so your variable hasn't been set yet.
You can do:
my $curr_lib;
BEGIN {
$curr_lib = $0;
$curr_lib =~ s/myapp\.pl/libx/;
}
use lib $curr_lib;
or you could:
use FindBin;
use lib "$FindBin::Bin/libx";
I had trouble with this before too. What's happening is that Perl makes two passes over your code: once to compile it, and the second time to run it. In you example, lines 4,5, and 6 don't execute until run time, but use takes effect during compile time.
One possibility is to put it all inside a BEGIN{} block, which will make the code execute at compile time. I've done this, but it's messy/ugly. (BTW, instead of $0, you need to use $ARGV[0] in Perl).
The best way to tell Perl where to pick up libraries is to use the -I flag. You can put it on the #! line, or if you are starting the script from another script, you can start it as
perl -I/your/directory/libx your_script.pl
You can use relative paths, so maybe
perl -I./libx script.pl
would work for you.
use xxx is a compile-time directive, not a run-time instruction. You cannot set it programmatically within the script you are running.
You may need to try require rather than use
If you need use, you need to set your $PERL5LIB environment variable to ensure your modules are correctly located and used, or change your shebang line to read #! /usr/local/perl -w -I/path/to/libx. There are other methods (local::lib etc.), but from your question it seems your control over installation is a bit limited for that sort of approach.