Getting Perl, MySQL and Apache to all work together on Mac OS/X
So, I've been running this blog for a few years now; over time I've been adding bits and pieces
of dynamic functionality - not the least of which is a comment section. A little while ago, a reader pointed out
that the comment section doesn't allow for formatted source code, which is something I wanted to
fix. Before I did so, though, I wanted to set up a local test bed on my computer that I could
verify my fixes against. The comments section (and other dynamic functionality) of my miniature
content-management system is built on Perl and MySql,
so to create a local instance, all I ought to need is Apache, Perl & MySql.
As it turns out, Mac OS/X comes with Apache, MySql, and Perl all pre-installed... so it should be a simple matter
to create a "dev" environment copy of my blog and get them all working together, right? Well, as it turned out, not quite. It was easy enough
mysqldump to get a copy of my simple database schema and replicate that on
my local MySQL instance. I had Perl also, but didn't have DBI or the DBD::MySQL module that Perl
requires to access a MySQL database. Both were easy
enough to download, install and test; I was able to verify that I could run a Perl script
and retrieve and insert data into my local MySQL instance. My next step was to grab all of my
CGI scripts and copy them into
/Library/WebServer/CGI-Executabes. When I tried to
run it, though, I got a blank page and this error in
[Fri Jul 24 10:49:11.776642 2015] [cgi:error] [pid 1797] [client ::1:50793] AH01215: install_driver(mysql) failed: Can't locate DBD/mysql.pm in @INC
(you may need to install the DBD::mysql module)
(@INC contains: /Library/Perl/5.18/darwin-thread-multi-2level /Library/Perl/5.18 /Network/Library/Perl/5.18/darwin-thread-multi-2level /Network/Library/Perl/5.18
/Library/Perl/Updates/5.18.2 /System/Library/Perl/5.18/darwin-thread-multi-2level /System/Library/Perl/5.18 /System/Library/Perl/Extras/5.18/darwin-thread-multi-2level
/System/Library/Perl/Extras/5.18 .) at (eval 5) line 3.
[Fri Jul 24 10:49:11.776802 2015] [cgi:error] [pid 1797] [client ::1:50793] AH01215: Perhaps the DBD::mysql perl module hasn't been fully installed,
[Fri Jul 24 10:49:11.783131 2015] [cgi:error] [pid 1797] [client ::1:50793] AH01215: or perhaps the capitalisation of 'mysql' isn't right.
[Fri Jul 24 10:49:11.783192 2015] [cgi:error] [pid 1797] [client ::1:50793] AH01215: Available drivers: DBM, ExampleP, File, GetInfo, Gofer, Proxy, SQLite, Sponge.
[Fri Jul 24 10:49:11.783227 2015] [cgi:error] [pid 1797] [client ::1:50793] AH01215: at /Library/WebServer/CGI-Executables/showarticle.cgi line 76.
However, MySQL DBD was installed and worked just fine:
my $dbh = DBI->connect("DBI:mysql:blog", "user", "password");
my $sth = $dbh->prepare("SELECT count(*) FROM comment");
my $count = $sth->execute();
print $count . "\n";
Apparently, the Perl I use has a different search directory than the one that the web server uses:
$ perl -e 'print "@INC" . "\n"'
/opt/local/lib/perl5/5.16.3/darwin-thread-multi-2level /opt/local/lib/perl5/5.16.3 /opt/local/lib/perl5/site_perl /opt/local/lib/perl5/vendor_perl .
My first thought, because I'm lazy, is to just take my working
and force it into one of the directories listed in the
@INC path that Apache is
reporting. I can download and build the DBD::MySQL distribution (that's how I got it installed
in the first place); so you'd think I could just say, "Install it here, instead of there." You
would think... however, after an hour of examining the install script, I couldn't find a way to
force it to install itself into, say
Just so you know, the really brute force approach of copying the files themselves doesn't work (although you had probably already guessed that...)
So, I figure one of two things is happening — either my login is overwriting some default
Perl include search path, or, inexplicably, I have two Perl instances installed and my ordinary
login was loading one Perl instance and Apache was loading the other. So... how to figure out
where Apache was finding its Perl search path? For one thing, mod_perl isn't installed; I'm
running perl as scripts. I considered that a perfectly reasonable tradeoff since I'm just
testing. Given that, I should be able to assume the identity of the web server user and find his Perl
which perl. I can become root and verify that his Perl is the
same as mine.
httpd doesn't run as root, though, it runs as:
# ps -fe | grep http 0 77 1 0 8:42AM ?? 0:00.58 /usr/sbin/httpd -D FOREGROUND 70 315 77 0 8:42AM ?? 0:00.02 /usr/sbin/httpd -D FOREGROUND 70 3277 77 0 11:09AM ?? 0:00.00 /usr/sbin/httpd -D FOREGROUND 70 3278 77 0 11:10AM ?? 0:00.01 /usr/sbin/httpd -D FOREGROUND 70 3279 77 0 11:10AM ?? 0:00.00 /usr/sbin/httpd -D FOREGROUND 70 3280 77 0 11:10AM ?? 0:00.01 /usr/sbin/httpd -D FOREGROUND 70 3281 77 0 11:10AM ?? 0:00.01 /usr/sbin/httpd -D FOREGROUND 70 3282 77 0 11:10AM ?? 0:00.00 /usr/sbin/httpd -D FOREGROUND 70 3283 77 0 11:10AM ?? 0:00.00 /usr/sbin/httpd -D FOREGROUND # grep ":70:" /etc/passwd _www:*:70:70:World Wide Web Server:/Library/WebServer:/usr/bin/false
Who, of course, you can't log in as: shell is
/usr/bin/false. So what is his search path, and
how do I change it?
I can "cheat" by running this CGI script:
print "Content-type: text/html; charset=iso-8859-1\n\n";
This informs me that _www has the simplest path:
And, sure enough, there's another perl instance install under
/usr/bin that my
ordinary user never sees, because
/opt/local/bin is further up in his search path
At this point, I can do one of two things - I can reinstall DBI::Mysql under /usr/bin/perl (i.e. 5.18) or change
the default path to find /opt/local/bin/perl (5.16). Changing the default path is a little
disconcerting; I don't know what else might rely on this path configuration. However, by just
temporarily changing my current path to put
/usr/bin first and reinstalling DBI
$ export PATH=/usr/bin:$PATH $ perl Makefile.PL $ make $ sudo make install
I can get DBD::mysql to load... almost. Now it fails with:
[Wed Aug 19 13:01:02.582506 2015] [cgi:error] [pid 3281] [client ::1:52522] AH01215: install_driver(mysql) failed: Can't load '/Library/Perl/5.18/darwin-thread-multi-2level/auto/DBD/mysql/mysql.bundle' for module DBD::mysql: dlopen(/Library/Perl/5.18/darwin-thread-multi-2level/auto/DBD/mysql/mysql.bundle, 1): Library not loaded: libmysqlclient.18.dylib
Because the mysqlclient libraries are not in
The simplest fix for this is to create a symlink to it:
$ sudo ln -s /usr/local/mysql/lib/libmysqlclient.18.dylib /usr/lib/libmysqlclient.18.dylib
And voila! I have a working copy of my blog's CMS with which I can test out new functionality, like code-formatted comments — which, if you look below, you can now leave at the bottom of this post!
After doing a bit of research, I believe that the reason I have two Perl installations is because I used MacPorts to install some third-party software that itself was dependent of Perl. It appears that I'm not the only person to have been surprised by mismatched Perl installations.