I’m right now experiencing the joys of setting up a Perl development environment on Mac OS X 10.11 (El Capitan). I’ve already talked about the weird linker warnings that appear when building Perl, and I’ve just come across another fun roadblock: A lack of OpenSSL header files. This is not unintentional, and there is a solution.
One of the modules I need for my work is LWP::Protocol::https, and that relies on additional modules to implement the underlying transport, and if you go far-enough down the chain, you eventually come to a dependency on OpenSSL.
The problem is, on El Capitan there is an OpenSSL shared library installed (version 0.9.8zg, plus whatever patches Apple has put in), but there are no header files available, which means I can’t build anything against this shared library.
After some searching, I came to understand that this is an intentional omission by Apple. Quoting from Apple’s Cryptographic Services Guide:
… a number of open source tools use OpenSSL for secure networking. If you use OpenSSL in your publicly shipping apps, you must provide your own copy of the OpenSSL libraries, preferably as part of your app bundle; the OpenSSL libraries that OS X provides are deprecated.
Apple has also confirmed that the removal of OpenSSL headers is intentional, as Apple tries to get developers to either switch to Secure Transport. Problem is, I’m not trying to develop software to give to others. Well, actually I am, but I’m not using OpenSSL directly, I’m just trying to use modules that do rely on OpenSSL.
So, what to do about this? Well, the Perl modules I want to use require OpenSSL, so I guess I’ll just install my own OpenSSL. That being said, there’s no way I’m going to build OpenSSL manually, nor do I want to install OpenSSL into the normal file system hierarchy. The reasons are simple:
- OpenSSL is a complex beast, with lots of configuration options. I don’t want to have to choose what to enable, and then keep a record of my build settings for the inevitable time when I have to go back and build a new version of OpenSSL.
- Apple is still providing an OpenSSL shared library, which is identifying itself as being part of the 0.9.8 series. I’m building a much-newer version of OpenSSL, so there could be compatibility issues in general if I try to instal into the local file system hierarchy.
- Apple’s tools assume that, if you are installing stuff, you are going to install stuff into proper, Apple-approved locations, and that you are not going to put things anywhere else.
The solution to my problem is MacPorts. Once you download and run their installer package, you get access to the `port` command in Terminal. Then all you have to do is run `sudo port install openssl` to get the latest stable OpenSSL distribution (which, according to `port info openssl`, is version 1.0.2e).
MacPorts installs everything into /opt/local on your system, so everything you install using the `ports` command is kept separate from the files installed and maintained by Mac OS X itself. MacPorts also drops a shell snippet into your ~/.bash_profile, adding /opt/local/bin and /opt/local/sbin to your path. Once the MacPorts build of OpenSSL (and its dependencies) is installed, you can go ahead and install all the Perl modules you need!
Before I end this blog entry, I want to answer one question: “If you’re going to all the trouble of installing MacPorts, and then installing OpenSSL through MacPorts, why don’t you just install Perl through MacPorts too?” The answer is simple: If I am going to use a distribution’s Perl, then I’ll want to exclusively use that distribution’s packaged modules.
It doesn’t matter if I’m using MacPorts Perl, or Debian Perl, some other distro’s Perl; whatever the distribution is, I do not want to mix packaged modules with locally-built modules. It just gets difficult to keep track of which modules are packaged (and so are updated using the package manager), and which modules are locally-built (and so are updated by me). There is an additional wrinkle: When I build a module, I have to catch any missing dependencies, and then check each dependency to see if it is already provided by a package, and then install that. That dance can get really complicated when those dependencies have their own dependencies, and there will always be times when the distribution’s package is too old for what I’m trying to build, so then I have to build the module myself, but the distribution won’t recognize that I’ve done that, and it might try to install its module’s package some time in the future, and now I’m really annoyed.
That is why I am just using MacPorts to provide the shared libraries that my locally-built modules (contained in my perlbrew environment) will be using. Of course, what if I come across a Perl module that needs a shared library which MacPorts does not provide? In that case, I’ll probably find an alternative module, because I don’t want to make things even more complicated by hand-building a library.
Of course, because I’m installing my own packages, I do occasionally have to go through and make sure that I’ve got the latest MacPorts packages installed, and the latest modules installed: Since I’m installing this extra software, it’s now my responsibility to make sure it is kept up-to-date. For critical software like OpenSSL, this is extremely important. Yes it’s not a system-level library, but this is a matter of proper discipline: If I can’t keep my own laptop up-to-date, how can I be trusted to keep critical work systems updated?
That’s it! When I ran into this OpenSSL issue last night, it seemed like a difficult problem. Luckily, this problem has been seen, and dealt with, by others. All the software we build sits on the shoulders of libraries like OpenSSL, and I am thankful for everyone involved in the MacPorts project, who are building (and updating) critical libraries like OpenSSL in such a way that I can install and use them easily.
<> Happy coding!