Compilation Amnesia
May 15, 2000
The curious reader will wonder, besides why people are madly buying
cars that are too large to fit into parking spaces, why we wrapped
the outer code of name_lib.pl inside a seemingly unnecessary
init() subroutine, and then called this subroutine from
name.cgi? After all, wasn't the require() enough
to pull all the code together?
In fact, it is true that if you did not wrap the code of
name_lib.pl inside of a subroutine, it would simply have
been executed in sequence when name.cgi was called. It seems
we didn't really need &name_main::init(); after all.
But wait! If you've tried to test this, now hit reload in the browser
and execute the script a second time. Something new:
"Document returned no data". Try again -- same message.
Now what's going on?
When you have "naked" code at the start of your pulled-in
package, also known as a BEGIN block, mod_perl generally only
executes this code once per compilation. That usually translates
into once per child process -- on first invocation. The solution,
as we've already seen, is not to code this way, but to enclose your
control code inside a subroutine within its package, and call
this subroutine from the mod_perl script, exactly as we did in
name.cgi.
Stubborn, Too
Not only will mod_perl conveniently "forget" about BEGIN
blocks pulled in via require, it will also tend to ignore changes
you make to your library packages or modules. Return to the script
we've created, name.cgi with the library name_lib.pl
pulled in via a require(). Suppose the script doesn't work,
or the script does work but we want to make changes to its output.
So, we fire up the trusty editor and hack away at name_lib.pl.
Heading back to the browser, hit reload with great anticipation,
and what happens?
What happens is whatever happened the previous time you ran the
script, because mod_perl doesn't see any of the changes you've
slaved over! The stubborn little thing does not check to see if
name_lib.pl has changed, and so when name.cgi is
invoked again it simply pulls in the compiled name_lib.pl
that it's been using all along.
One way to shock mod_perl into its senses is the drastic method,
akin to cold-water-in-the-face: kill or restart the Apache server.
For instance (modify to match your installation):
/usr/local/apache/bin/apachectl restart
That will force it to re-load any requested files from the disk.
This method works fine in testing, but assuming you make many small
changes to your script during development, you'll quickly find
restarting the server everytime you want to test a change rather
tedious. No, not coal mining tedious, or transcontinental railroad
spike pounding tedious, but tedious nonetheless. Sometimes it's the
little things.
Our hero is named StatINC, which is an Apache Perl module
that will effectively check the files you pull in via a
require() to see if they've been updated, every time your
mod_perl script is invoked. To enable StatINC, you'll need
to modify the Apache server configuration file, httpd.conf,
found in /path/to/apache/conf/ (modify to match your
installation).
Find the portion of your httpd.conf file where mod_perl is
configured; using last month's example, that section might look like:
Alias /cgi-perl/ "/usr/local/apache/cgi-perl/"
<Location /cgi-perl>
SetHandler perl-script
PerlHandler Apache::Registry
Options ExecCGI
PerlSendHeader On
</Location>
Now, we need to add three lines to the above (or whatever
configuration is similar to the above in your httpd.conf),
marked below in bold and red.
PerlModule Apache::StatINC
Alias /cgi-perl/ "/usr/local/apache/cgi-perl/"
<Location /cgi-perl>
SetHandler perl-script
PerlHandler Apache::Registry
Options ExecCGI
PerlSendHeader On
PerlInitHandler Apache::StatINC
PerlSetVar StatINCDebug On
</Location>
With StatINC enabled with debugging on, as seen above, the
Apache errorlog will now contain messages when a change to one of
your require'd script files is detected:
Apache::StatINC: process 15420
reloading /home/username/cgi-bin/test_lib.pl
Repackage Your Way to Success
The Perl You Need to Know
Conclusion
|