Mac OS X Server
Mac OS X Server
Compiling Perl modules with x86_64 support for use with mod_perl
Friday, 21 August 2009
Last night I was playing around with a mod_perl page on my Mac OS X Server and wanted to use DBI. Okay nothing too fancy there I thought. It’s been a couple of years since I was playing with this code as I’ve been busy doing other thing... Problem was that when I tried restart Apache I got server errors. What could be going on I though... I have come across that before. So I checked my test script which did the same thing without all the request handler goodness. All works as expected! Hmmm... Lets take another look at the logs...
[Thu Aug 20 23:53:29 2009] [error] Can't load '/Library/Perl/5.8.8/darwin-thread-multi-2level/auto/DBI/DBI.bundle' for module DBI: dlopen(/Library/Perl/5.8.8/darwin-thread-multi-2level/auto/DBI/DBI.bundle, 1): no suitable image found. Did find:\n\t/Library/Perl/5.8.8/darwin-thread-multi-2level/auto/DBI/DBI.bundle: no matching architecture in universal wrapper at /System/Library/Perl/5.8.8/darwin-thread-multi-2level/DynaLoader.pm line 230.\n at /Library/Perl/5.8.8/darwin-thread-multi-2level/DBI.pm line 263\nBEGIN failed--compilation aborted at /Library/Perl/5.8.8/darwin-thread-multi-2level/DBI.pm line 263.\nCompilation failed in require at /Users/Share/Library/Perl/Test.pm line 12.\nBEGIN failed--compilation aborted at /Users/Shared/Library/Perl/Test.pm line 12.\nCompilation failed in require at /Users/Shared/Library/Perl/startup.pl line 14.\nBEGIN failed--compilation aborted at /Users/Shared/Library/Perl/startup.pl line 14.\nCompilation failed in require at (eval 2) line 1.\n
A quick search on my favorite search engine returned a few interesting threads... It looked like my module wasn’t compiled to support the required architectures... i.e. the module bundle didn’t have an object for x86_64.
A quick check with the file command shows the problem.
file /usr/bin/perl
/usr/bin/perl: Mach-O universal binary with 2 architectures
/usr/bin/perl (for architecture ppc7400):Mach-O executable ppc
/usr/bin/perl (for architecture i386):Mach-O executable i386
file /usr/libexec/apache2/mod_perl.so
/usr/libexec/apache2/mod_perl.so: Mach-O universal binary with 4 architectures
/usr/libexec/apache2/mod_perl.so (for architecture ppc7400):Mach-O bundle ppc
/usr/libexec/apache2/mod_perl.so (for architecture ppc64):Mach-O 64-bit bundle ppc64
/usr/libexec/apache2/mod_perl.so (for architecture i386):Mach-O bundle i386
/usr/libexec/apache2/mod_perl.so (for architecture x86_64):Mach-O 64-bit bundle x86_64
file /Library/Perl/5.8.8/darwin-thread-multi-2level/auto/DBI/DBI.bundle
/Library/Perl/5.8.8/darwin-thread-multi-2level/auto/DBI/DBI.bundle: Mach-O universal binary with 2 architectures
/Library/Perl/5.8.8/darwin-thread-multi-2level/auto/DBI/DBI.bundle (for architecture ppc7400):Mach-O bundle ppc
/Library/Perl/5.8.8/darwin-thread-multi-2level/auto/DBI/DBI.bundle (for architecture i386):Mach-O bundle i386
So how can this be? I installed via the usual way
sudo perl -MCPAN -e shell
install DBI
So what did I do wrong?
Well nothing actually... You see Apple have compiled Apache and mod_perl with 64 bit support. This is for both Power PC and Intel CPUs. But the Perl has only been compiled with 32 bit support.
With a little more fishing around on the web I found that I need to add “-arch x86_64” to the compile flags for module when building them.
So here’s the slightly tricky bit that has absolutely no warranty. If you follow these instructions you do so at your own risk... But hey if you’re reading this then chances are you’re a techie and are willing to take the risk.
The compile flags used to compile all Perl stuff are set in the module Config which is created when Perl was originally compiled. But I don’t way to rebuild Perl. That’s Apples job to maintain. That’s why I have Mac OS X Server and not the Linux or Solaris boxes any more.
If you modify the Config module settings then any new modules you install will use these configuration options.
So what are we looking for? Well it was easy enough to see that Perl had been built with i386 support so lets look for that and see what comes up.
Where to look next... Well this is where the find and grep commands come in... Oh and perl of course...
perl -V
Tells you where all the default Perl module search paths are, so that narrows down the search a little. But I took a stab in the dark and thought that /System/Library/Perl sounded like a nice place to start.
cd /System/Library/Perl
find . -type f -exec grep -li "arch i386" {} \;
./5.8.8/darwin-thread-multi-2level/Config_heavy.pl
./Extras/5.8.8/darwin-thread-multi-2level/Apache2/BuildConfig.pm
Of these two modules Config_heavy.pl is what we are after. Apache2/BuildConfig.pm is part of the Apache mod_perl install and is completely the wrong thing.
So the edit...
sudo vi ./5.8.8/darwin-thread-multi-2level/Config_heavy.pl
Now we want to find where the architectures used to build are set.
With a quick search (/-arch i386) you’ll find yourself on line 1197 which will have the magic compiler options that we want to add to.
$archflags = exists($ENV{ARCHFLAGS}) ? $ENV{ARCHFLAGS} : '-arch ppc -arch i386';
You need to add to this line so that it looks like this
$archflags = exists($ENV{ARCHFLAGS}) ? $ENV{ARCHFLAGS} : '-arch ppc -arch i386 -arch x86_64';
Save the file and you’re done.
Now go back to the DBI build path in ~/.cpan/build and try to build it again manually.
cd
sudo -s
cd .cpan/build/DBI-1.609/
make distclean
perl Makefile.PL
make
make test
Now we want to check that what we have build has the required architectures.
file blib/arch/auto/DBI/DBI.bundle
blib/arch/auto/DBI/DBI.bundle: Mach-O universal binary with 3 architectures
blib/arch/auto/DBI/DBI.bundle (for architecture ppc7400):Mach-O bundle ppc
blib/arch/auto/DBI/DBI.bundle (for architecture i386):Mach-O bundle i386
blib/arch/auto/DBI/DBI.bundle (for architecture x86_64):Mach-O 64-bit bundle x86_64
As you can see you now have a bundle that supports x86_64.
A quick make install will overwrite the DBI that was previously built.
Now for the easy bit, testing...
Since the error was reported in the Apache error log starting the server and tailing the logs will show you if all is to plan.
tail -f /var/log/apache2/error_log
[Thu Aug 20 23:56:00 2009] [error] Can't load '/Library/Perl/5.8.8/darwin-thread-multi-2level/auto/DBI/DBI.bundle' for module DBI: dlopen(/Library/Perl/5.8.8/darwin-thread-multi-2level/auto/DBI/DBI.bundle, 1): no suitable image found. Did find:\n\t/Library/Perl/5.8.8/darwin-thread-multi-2level/auto/DBI/DBI.bundle: no matching architecture in universal wrapper at /System/Library/Perl/5.8.8/darwin-thread-multi-2level/DynaLoader.pm line 230.\n at /Library/Perl/5.8.8/darwin-thread-multi-2level/DBI.pm line 263\nBEGIN failed--compilation aborted at /Library/Perl/5.8.8/darwin-thread-multi-2level/DBI.pm line 263.\nCompilation failed in require at /Users/Shared/Library/Perl/Test.pm line 12.\nBEGIN failed--compilation aborted at /Users/Shared/Library/Perl/Test.pm line 12.\nCompilation failed in require at /Users/Shared/Library/Perl/startup.pl line 14.\nBEGIN failed--compilation aborted at /Users/Shared/Library/Perl/startup.pl line 14.\nCompilation failed in require at (eval 2) line 1.\n
[Thu Aug 20 23:56:11 2009] [notice] Apache/2.2.11 (Unix) mod_ssl/2.2.11 OpenSSL/0.9.7l PHP/5.2.8 mod_perl/2.0.2 Perl/v5.8.8 configured -- resuming normal operations
[Fri Aug 21 00:44:36 2009] [notice] caught SIGTERM, shutting down
[Fri Aug 21 00:44:46 2009] [notice] Apache/2.2.11 (Unix) mod_ssl/2.2.11 OpenSSL/0.9.7l PHP/5.2.8 mod_perl/2.0.2 Perl/v5.8.8 configured -- resuming normal operations
Yep thats what we want to see.
But remember that this is only a workaround and not a fix. Any patches to Perl will possibly overwrite the change and so it will need to be made again. (unless Apple apply this change to their distribution)
So when you are building / installing modules pay closer attention to the compiling of any C files and make sure it contains all the architectures that you need.
Related posts: