By Jon Saints - 12 May 2014
Often on Heroku your app might depend on a system package that is not installed in the base Heroku system. Including an external binary dependency in your Heroku app is easy. These binaries are called vendored binaries.
Here is a quick summary of how to do this:
heroku run /bin/bash
.heroku/vendor
On your next push to heroku, the system path will recognize the binary dependencies in your path LD_LIBRARY_PATH.
Recently I needed to install the python Shapely library on a Heroku app. Shapely has a dependency on the C Library GEOS which is not part of the base Heroku system.
Here is how I complied and vendored the GEOS binary for Heroku. You could use the same process to vendor a different binary.
I assume you have read and followed the appropriate Heroku Getting Started Guide for your language. I used Getting Started with Python on Heroku
With your application configured, run bash on a Heroku process
heroku run /bin/bash
From the Heroku bash command prompt, download and extract the source code for the binary package you need to run on Heroku. In my case it was:
curl -O http://download.osgeo.org/geos/geos-3.4.2.tar.bz2
tar -xjvf geos-3.4.2.tar.bz2
Open the README or the INSTALL doc for your source code and follow the compile instructions with one change. Change the prefix
for the install to be something easy to find in your /app folder.
cd geos-3.4.2
./configure --prefix=/app/.heroku/vendor
make
make install
When the compiling is finished you will have a working binary in the /app/scratch-space folder. In my case geos made three folders in the scratch-space folder: bin
, lib
, and include
.
Create an zip archive of the binaries.
tar -czvf /app/geos-3.4.2-heroku.tar.gz .heroku/vendor
Next copy the geos-3.4.2-heroku.tar.gz to your local machine. I did this in two steps. You might have a better method. I used scp
to copy the file to another server and then scp
again copy the geos-3.4.2-heroku.tar.gz to my local machine.
With the geos-3.4.2-heroku.tar.gz on your local machine extract it into a folder .heroku/vendor in the root of your app. Heroku will automatically add the .heroku/vendor folder to your LD_LIBRARY_PATH.
# from my app root folder
mkdir .heroku
mkdir .heroku/vendor
tar -xzvf ~/Downloads/geos-3.4.2-heroku.tar.gz
Make sure you have the same folder structure as scratch-space in .heroku/vendor. In my case I have three folders: bin
, lib
, and include
.
ls .heroku/vendor
bin include lib
Add the binaries to your git repo and deploy to Heroku. The binaries will be available to your app.
git add .
git commit -m "vendored binary for lib geos"
git push heroku master
Instead of Step #3 you can also use the Multi Buildpack and the Vendored Libraries Buildpack build if you prefer not to have vendored binaries in your git repo.
You will want to modify your tar.gz file from Step #2 so that it extracts its contents to .heroku/vendor/BINARY_FILES_HERE.
Then copy your binary from Step #2 to amazon s3. Make the URL public.
Install Multi build pack support. See https://github.com/ddollar/heroku-buildpack-multi
Install Vendored Binary buildpack support and create a .vendor_urls file and add your S3 url to the tar.gz to it.
Use this command to find where php .so extentions are installed:
php-config --extension-dir
look for geos.so
in the folder listed and include this in your zip file
tar -czvf /app/geos-3.4.2-heroku.tar.gz .heroku/vendor/ `php-config --extension-dir`/geos.so
Then add .heroku/php/etc/php/conf.d/geos.ini
with
; GEOS extension
extension=geos.so
Commit all of this to your local source and push to heroku. NOTE: Everytime PHP is upgraded on heroku you will need to recompile the geos extension. The php-config --extension-dir
will change with each upgrade as well.