Building NumPy, SciPy & Matplotlib for Python 2.7 on Snow Leopard

A few days ago I wrote about how to build SciPy for Python 2.7 on Mac OS 10.6 Snow Leopard.

Usually you want to install NumPy, SciPy and Matplotlib. After reading Installing SciPy/Mac OS X, the Matplotlib installation instructions and the HJBlog you might come to the conclusion, that it’s not trivial to build them on your own and that you better use the 32bit binaries for Python 2.6 or get them via MacPorts.

But actually it’s really easy. The only dependencies that you need to install are Xcode (for gcc and X11) and gfortran.

To simplify the the installation, I wrote a small Makefile that downloads all packages (except for Xcode) and builds/installs them:

  1. Rename* the downloaded makefile to Makefile, open Terminal and cd to the diretory with the makefile.

  2. Download gfortran and start the graphical installer:

    $ make fortran
    
  3. Download and install NumPy, SciPy and Matplotlib:

    $ make
    
  4. Run NumPy’s and SciPy’s test suite and delete the temporary build diretory:

    $ make test clean
    

That’s how the makefile looks like:

# Download all packages to this directory.
TMP_DIR=./PYTMP

# Select Python version.
PYVERSION=2.7
PYTHON=python${PYVERSION}

# Package to download frm http://r.research.att.com/
FORTRANPACKAGE=gfortran-42-5664.pkg

# Select which versions of the packages you want to install.
NUMPYVERSION=1.5.0
SCIPYVERSION=0.8.0
MATPLOTLIBMAJORVERSION=1.0
MATPLOTLIBVERSION=${MATPLOTLIBMAJORVERSION}.0

# Normally, you shouldn’t need change this.
OSX_SDK_VER=10.6
ARCH_FLAGS=-arch i386 -arch x86_64

# Values for some environment variables. You shouldn’t need to change this.
MACOSX_DEPLOYMENT_TARGET=${OSX_SDK_VER}
CFLAGS="${ARCH_FLAGS} -I/usr/X11/include -I/usr/X11/include/freetype2 -isysroot /Developer/SDKs/MacOSX${OSX_SDK_VER}.sdk"
LDFLAGS="-Wall -undefined dynamic_lookup -bundle ${ARCH_FLAGS} -L/usr/X11/lib -syslibroot,/Developer/SDKs/MacOSX${OSX_SDK_VER}.sdk"
FFLAGS="${ARCH_FLAGS}"


default: all

# Create a temporary directory for the build process
_tmp_dir:
    mkdir -p ${TMP_DIR}

# Clean the the temporary build directory
clean:
    rm -rf ${TMP_DIR}

# Download gfortran and start the installer
fortran: _tmp_dir
    cd ${TMP_DIR} && \
    ${PYTHON} -c "import urllib; urllib.urlretrieve('http://r.research.att.com/${FORTRANPACKAGE}', '${FORTRANPACKAGE}')" && \
    open ${FORTRANPACKAGE}

# Download all required packages
fetch: _tmp_dir
    cd ${TMP_DIR} && \
    ${PYTHON} -c "import urllib; urllib.urlretrieve('http://sourceforge.net/projects/numpy/files/NumPy/${NUMPYVERSION}/numpy-${NUMPYVERSION}.tar.gz/download', 'numpy-${NUMPYVERSION}.tar.gz')" && \
    ${PYTHON} -c "import urllib; urllib.urlretrieve('http://sourceforge.net/projects/scipy/files/scipy/${SCIPYVERSION}/scipy-${SCIPYVERSION}.tar.gz/download', 'scipy-${SCIPYVERSION}.tar.gz')" && \
    ${PYTHON} -c "import urllib; urllib.urlretrieve('http://sourceforge.net/projects/matplotlib/files/matplotlib/matplotlib-${MATPLOTLIBMAJORVERSION}/matplotlib-${MATPLOTLIBVERSION}.tar.gz/download', 'matplotlib-${MATPLOTLIBVERSION}.tar.gz')"

# Extract, build and install NumPy
numpy:
    cd ${TMP_DIR} && \
    rm -rf numpy-${NUMPYVERSION} && \
    tar -xf numpy-${NUMPYVERSION}.tar.gz && \
    cd numpy-${NUMPYVERSION} && \
    export MACOSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET} && \
    export CFLAGS=${CFLAGS} && \
    export LDFLAGS=${LDFLAGS} && \
    export FFLAGS=${FFLAGS} && \
    ${PYTHON} setup.py build && \
    ${PYTHON} setup.py install && \
    cd .. && \
    ${PYTHON} -c "import numpy; print 'Installed NumPy', numpy.__version__"

# Extract, build and install SciPy
scipy:
    cd ${TMP_DIR} && \
    rm -rf scipy-${SCIPYVERSION} && \
    tar -xf scipy-${SCIPYVERSION}.tar.gz && \
    cd scipy-${SCIPYVERSION} && \
    export MACOSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET} && \
    export CFLAGS=${CFLAGS} && \
    export LDFLAGS=${LDFLAGS} && \
    export FFLAGS=${FFLAGS} && \
    ${PYTHON} setup.py build && \
    ${PYTHON} setup.py install && \
    cd .. && \
    ${PYTHON} -c "import scipy; print 'Installed SciPy', scipy.__version__"

# Extract, build and install Matplotlib
matplotlib:
    cd ${TMP_DIR} && \
    rm -rf matplotlib-${MATPLOTLIBVERSION} && \
    tar -xf matplotlib-${MATPLOTLIBVERSION}.tar.gz && \
    cd matplotlib-${MATPLOTLIBVERSION} && \
    export MACOSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET} && \
    export CFLAGS=${CFLAGS} && \
    export LDFLAGS=${LDFLAGS} && \
    ${PYTHON} setup.py build && \
    ${PYTHON} setup.py install && \
    cd .. && \
    ${PYTHON} -c "import matplotlib; print 'Installed Matplotlib', matplotlib.__version__"

# Fetch and build NumPy, SciPy and Matplotlib
all: fetch numpy scipy matplotlib
    echo "all done"

# Execute tests for NumPy and SciPy
test: _tmp_dir
    export MACOSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET} && \
    export CFLAGS=${CFLAGS} && \
    export LDFLAGS=${LDFLAGS} && \
    export FFLAGS=${FFLAGS} && \
    cd ${TMP_DIR} && \
    ${PYTHON} -c "import numpy; numpy.test('1', '10')" && \
    ${PYTHON} -c "import scipy; scipy.test('1', '10')"

I have only tested it on my local machine yet. Hope, it helps and you don’t run into any troubles.

* If you don’t rename the makefile, you must pass it’s name to make: make -f Makefile_nsm <target>.