zhangwenwen
11/1/2017 - 1:11 PM

This is a script to compile caffe without root permission. It hasn't been extensively tested, but it will hopefully still make things easier

This is a script to compile caffe without root permission. It hasn't been extensively tested, but it will hopefully still make things easier than going about it on your own. Please let me know if there are any bugs!

# This script installs (or at least, attempts to install) Caffe in CPU mode
# with Python bindings without root permission. In doing so, it installs the
# following dependencies:
#
# * protobuf
# * cmake
# * gflags
# * glog
# * opencv
# * hdf5
# * python2
# * pip
# * libpng (recent version required for freetype)
# * automake (recent version required for freetype)
# * freetype (required for scikit-image)
# * various python modules
#     - numpy
#     - scipy
#     - scikit-image
#     - protobuf
#     - yaml
# * boost
# * lmdb
# * libtool
# * snappy
# * leveldb
# * openblas

LOCAL_INSTALL_DIR="${HOME}/local"
SCRATCH_DIR="${HOME}/scratch_for_setup"
CAFFE_INSTALL_DIR="${HOME}/caffe"

# Note that changing these versions may not work - it's a little fragile and
# depends on the URLs for these utilities to have the same template across
# versions (e.g. http://example.com/tool/tool_v${version_number}). The URLs
# work with the versions listed as of the last committed version, but should
# be tested before updating and committing.
PROTOBUF_VERSION="2.6.1"
GFLAGS_VERSION="2.1.2"
GLOG_VERSION="0.3.4"
OPENCV_VERSION="2.4.11"
LMDB_VERSION="0.87"
PYTHON_VERSION="2.7.10" # Must be python2.*
LIBPNG_VERSION="1.6.18"
FREETYPE_VERSION="2.6.1"
LIBTOOL_VERSION="2.4.6"
AUTOMAKE_VERSION="1.15"
LEVELDB_VERSION="1.18"
OPENBLAS_VERSION="0.2.14"

# Hardcoded versions - these cannot be changed here.
# TODO: Allow changing the below values.
# BOOST_VERSION="1.59.0"
# HDF5_VERSION="1.8.15-patch1"
# CMAKE_VERSION="3.2.3"

# E.g. 2.7.10 -> python2.7
PYTHON_SHORT_VERSION="$(echo $PYTHON_VERSION | sed -e 's/\([0-9]*\.[0-9]*\)\(\..*\)\?/\1/g')"
PYTHON_BINARY="python${PYTHON_SHORT_VERSION}"

# Exit on error.
set -e

# Taken from
# https://github.com/achalddave/dotfiles/blob/master/misc/sudo-less-servers/install_utilities.sh
# Usage: untar_to_dir <tar_file> <output_directory>
# Untars to a specified directory, instead of using the "root" directory
# specified in the tar file. Useful for cd'ing.
untar_to_dir() {
    if [[ "$#" -ne 2 ]] ; then
        echo "Improper number of arguments to untar_to_dir"
        exit
    fi

    TAR_FILE="${1}"
    OUTPUT="${2}"
    mkdir -p "${OUTPUT}"

    tar xzvf "${TAR_FILE}" -C "${OUTPUT}" --strip-components=1
}

# Usage: scratch_init <utility_name>
scratch_init() {
    if [[ "$#" -ne 1 ]] ; then
        echo "Improper number of arguments to scratch_init"
        exit
    fi

    cd "${SCRATCH_DIR}"
    mkdir -p "$1"
    cd "$1"
}

install_protobufs() {
    scratch_init protobuf

    wget "https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protobuf-${PROTOBUF_VERSION}.tar.gz"
    untar_to_dir "protobuf-${PROTOBUF_VERSION}.tar.gz" protobuf-${PROTOBUF_VERSION}
    cd protobuf-${PROTOBUF_VERSION}

    ./configure --prefix="${LOCAL_INSTALL_DIR}/protobuf-${PROTOBUF_VERSION}"
    make -j4
    make install
}

install_cmake() {
    scratch_init cmake

    # Cmake has pre-built binaries ready, so we will just untar it in
    # ${LOCAL_INSTALL_DIR}.
    wget "https://cmake.org/files/v3.2/cmake-3.2.3-Linux-x86_64.tar.gz"
    cd ${LOCAL_INSTALL_DIR}
    untar_to_dir "${SCRATCH_DIR}/cmake-3.2.3-Linux-x86_64.tar.gz" .

    echo "You will need to add the following line to your .zshrc/.bashrc:"
    echo 'export CMAKE_ROOT="'${LOCAL_INSTALL_DIR}'/share/cmake-3.2"'
}

install_gflags() {
    scratch_init gflags

    wget "https://github.com/gflags/gflags/archive/v${GFLAGS_VERSION}.tar.gz"
    untar_to_dir "v${GFLAGS_VERSION}.tar.gz" "v${GFLAGS_VERSION}"
    cd "v${GFLAGS_VERSION}"

    mkdir build
    cd build

    cmake -D CMAKE_INSTALL_PREFIX="${LOCAL_INSTALL_DIR}" -D CMAKE_POSITION_INDEPENDENT_CODE=ON ..
    make
    make install
}

install_glog() {
    scratch_init glog

    wget "https://github.com/google/glog/archive/v${GLOG_VERSION}.tar.gz"
    untar_to_dir "v${GLOG_VERSION}.tar.gz" "v${GLOG_VERSION}"
    cd "v${GLOG_VERSION}"

    ./configure --prefix="${LOCAL_INSTALL_DIR}/glog-${GLOG_VERSION}"
    make
    make install
}

install_opencv() {
    scratch_init opencv

    wget "https://github.com/Itseez/opencv/archive/${OPENCV_VERSION}.tar.gz" -O "opencv-${OPENCV_VERSION}.tar.gz"
    untar_to_dir "opencv-${OPENCV_VERSION}.tar.gz" "opencv-${OPENCV_VERSION}"
    cd "opencv-${OPENCV_VERSION}"

    mkdir release
    cd release
    cmake -D BUILD_ZLIB=ON -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX="${LOCAL_INSTALL_DIR}" -D BUILD_PYTHON_SUPPORT=ON -D WITH_GTK=OFF ..

    # Update ${SCRATCH_DIR}/opencv-2.4.11/release/modules/features2d/CMakeFiles/opencv_features2d.dir/build.make
    # cd ${SCRATCH_DIR}/opencv/opencv-2.4.11/release/modules/features2d && /usr/bin/c++   $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_features2d.dir/src/freak.cpp.o -c ${SCRATCH_DIR}/opencv/opencv-2.4.11/modules/features2d/src/freak.cpp
    # to
    # cd ${SCRATCH_DIR}/opencv/opencv-2.4.11/release/modules/features2d && /usr/bin/c++   $(CXX_DEFINES) $(CXX_FLAGS) -O0 -o CMakeFiles/opencv_features2d.dir/src/freak.cpp.o -c ${SCRATCH_DIR}/opencv/opencv-2.4.11/modules/features2d/src/freak.cpp
    # (Add -O0 after CXX_FLAGS)
    # This is necessary due to http://stackoverflow.com/a/14619427/1291812
    sed -i'' -e \
        's:'${SCRATCH_DIR}'/opencv/opencv-2.4.11/release/modules/features2d && /usr/bin/c++   $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/opencv_features2d.dir/src/freak.cpp.o -c '${SCRATCH_DIR}'/opencv/opencv-2.4.11/modules/features2d/src/freak.cpp:'${SCRATCH_DIR}'/opencv/opencv-2.4.11/release/modules/features2d && /usr/bin/c++   $(CXX_DEFINES) $(CXX_FLAGS) -O0 -o CMakeFiles/opencv_features2d.dir/src/freak.cpp.o -c '${SCRATCH_DIR}'/opencv/opencv-2.4.11/modules/features2d/src/freak.cpp:' \
        "${SCRATCH_DIR}/opencv/opencv-2.4.11/release/modules/features2d/CMakeFiles/opencv_features2d.dir/build.make"

    make -j16
    make install
}

install_hdf5() {
    scratch_init hdf5

    wget "http://www.hdfgroup.org/ftp/HDF5/current/src/hdf5-1.8.15-patch1.tar.gz"
    untar_to_dir "hdf5-1.8.15-patch1.tar.gz" "hdf5-1.8.15"
    cd hdf5-1.8.15

    ./configure --prefix="${LOCAL_INSTALL_DIR}/hdf5-1.8.15"
    make -j4
    make install
}

install_libpng() {
    scratch_init libpng

    wget "http://downloads.sourceforge.net/libpng/libpng-${LIBPNG_VERSION}.tar.gz"
    untar_to_dir "libpng-${LIBPNG_VERSION}.tar.gz" "libpng-${LIBPNG_VERSION}"
    cd "libpng-${LIBPNG_VERSION}"

    LDFLAGS="-L ${LOCAL_INSTALL_DIR}/lib" ./configure --prefix="${LOCAL_INSTALL_DIR}/libpng-${LIBPNG_VERSION}"
    make -j4
    make install
}

install_automake() {
    scratch_init automake

    wget "http://ftp.gnu.org/gnu/automake/automake-${AUTOMAKE_VERSION}.tar.gz"
    untar_to_dir "automake-${AUTOMAKE_VERSION}.tar.gz" "automake-${AUTOMAKE_VERSION}"
    cd "automake-${AUTOMAKE_VERSION}"

    ./configure --prefix="${LOCAL_INSTALL_DIR}/automake-${AUTOMAKE_VERSION}"
    make -j4
    make install
}

install_freetype() {
    scratch_init freetype

    wget "http://download.savannah.gnu.org/releases/freetype/freetype-${FREETYPE_VERSION}.tar.gz"
    untar_to_dir "freetype-${FREETYPE_VERSION}.tar.gz" "freetype-${FREETYPE_VERSION}"
    cd "freetype-${FREETYPE_VERSION}"

    ./autogen.sh
    ./configure --prefix="${LOCAL_INSTALL_DIR}/freetype-${FREETYPE_VERSION}"
    make
    make install
}

# Taken from
# https://github.com/achalddave/dotfiles/blob/master/misc/sudo-less-servers/install_utilities.sh
install_python2() {
    scratch_init python2

    wget https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tgz
    untar_to_dir "Python-${PYTHON_VERSION}.tgz" "python-${PYTHON_VERSION}"

    cd "python-${PYTHON_VERSION}"
    ./configure --prefix="${LOCAL_INSTALL_DIR}/python-${PYTHON_VERSION}" --enable-shared
    make -j4
    make altinstall
}

# Taken from
# https://github.com/achalddave/dotfiles/blob/master/misc/sudo-less-servers/install_utilities.sh
install_pip() {
    scratch_init pip2

    wget https://raw.github.com/pypa/pip/master/contrib/get-pip.py
    ${PYTHON_BINARY} get-pip.py
}

install_python_modules() {
    ${PYTHON_BINARY} -m pip install numpy
    ${PYTHON_BINARY} -m pip install scipy
    ${PYTHON_BINARY} -m pip install scikit-image
    ${PYTHON_BINARY} -m pip install protobuf
    ${PYTHON_BINARY} -m pip install pyyaml
}

# TODO: This does not install the python bindings, it seems... That is,
# import boost
# does not work in python.
install_boost() {
    scratch_init boost

    wget "http://sourceforge.net/projects/boost/files/boost/1.59.0/boost_1_59_0.tar.gz/download" -O "boost_1_59_0.tar.gz"
    untar_to_dir "boost_1_59_0.tar.gz" "boost_1_59_0"

    cd boost_1_59_0
    ./bootstrap.sh --prefix="${LOCAL_INSTALL_DIR}/boost-1.59.0" --with-python="${LOCAL_INSTALL_DIR}/python-${PYTHON_VERSION}/bin/python${PYTHON_SHORT_VERSION}"
    ./b2 install
}

install_lmdb() {
    scratch_init lmdb

    wget "https://github.com/dw/py-lmdb/archive/py-lmdb_${LMDB_VERSION}.tar.gz"
    untar_to_dir "py-lmdb_${LMDB_VERSION}.tar.gz" "py-lmdb_${LMDB_VERSION}"
    cd "py-lmdb_${LMDB_VERSION}"
    ${PYTHON_BINARY} setup.py install

    # Contains the actual LMDB sources?
    scratch_init openldap
    wget "ftp://ftp.openldap.org/pub/OpenLDAP/openldap-release/openldap-2.4.42.tgz"
    untar_to_dir "openldap-2.4.42.tgz" openldap-2.4.42
    cd openldap-2.4.42/libraries/lmdb
    make -j4
    sed -i'' -e 's:\(prefix.*=\).*:\1'${LOCAL_INSTALL_DIR}':g' Makefile
    make install
}

install_libtool() {
    scratch_init libtool

    wget "http://ftpmirror.gnu.org/libtool/libtool-${LIBTOOL_VERSION}.tar.gz"
    untar_to_dir "libtool-${LIBTOOL_VERSION}.tar.gz" "libtool-${LIBTOOL_VERSION}"
    cd libtool-${LIBTOOL_VERSION}

    ./configure --prefix="${LOCAL_INSTALL_DIR}/libtool-${LIBTOOL_VERSION}"
    make -j4
    make install
}

install_snappy() {
    scratch_init snappy

    wget "https://github.com/google/snappy/tarball/master" -O snappy.tar.gz
    untar_to_dir "snappy.tar.gz" "libsnappy"
    cd "libsnappy"

    ./autogen.sh
    echo "AC_PROG_LIBTOOL" >>config.ac
    ./configure --prefix="${LOCAL_INSTALL_DIR}/snappy"
    make
    make install
    # The default autogen.sh does not handle compatibility well... This one,
    # from the following PR: https://github.com/google/snappy/pull/4 is
    # preferable.
    #wget https://raw.githubusercontent.com/juanmaneo/snappy/49262984cddf3985fba7d1ceca6b14986f6dbef0/autogen.sh -O autogen.sh
}

install_leveldb() {
    scratch_init leveldb

    wget "https://github.com/google/leveldb/archive/v${LEVELDB_VERSION}.tar.gz"
    untar_to_dir "v${LEVELDB_VERSION}.tar.gz" "leveldb-${LEVELDB_VERSION}"
    cd "leveldb-${LEVELDB_VERSION}"

    LD_FLAGS="-L${LOCAL_INSTALL_DIR}/lib" make -j4

    # leveldb doesn't have a make install target...
    # Instructions below taken from
    # http://techoverflow.net/blog/2012/12/14/compiling-installing-leveldb-on-linux/
    cp --preserve=links libleveldb.* ${LOCAL_INSTALL_DIR}/lib
    cp -r include/leveldb ${LOCAL_INSTALL_DIR}/include/
}

install_openblas() {
    scratch_init openblas

    wget "https://github.com/xianyi/OpenBLAS/archive/v${OPENBLAS_VERSION}.tar.gz" -O "openblas_${OPENBLAS_VERSION}.tar.gz"
    untar_to_dir openblas_${OPENBLAS_VERSION}.tar.gz openblas_${OPENBLAS_VERSION}
    cd openblas_${OPENBLAS_VERSION}

    make -j4
    make PREFIX="${LOCAL_INSTALL_DIR}" install

    # OpenBLAS only installs libopenblas.a, but it provides the symbols for
    # libcblas.a and libatlas.a (I think). Symlinking libatlas and libcblas
    # allows Caffe to build.
    ln -s "${LOCAL_INSTALL_DIR}/lib/libopenblas.a" "${LOCAL_INSTALL_DIR}/lib/libcblas.a"
    ln -s "${LOCAL_INSTALL_DIR}/lib/libopenblas.a" "${LOCAL_INSTALL_DIR}/lib/libatlas.a"
}

install_caffe() {
    mkdir -p "${CAFFE_INSTALL_DIR}"
    cd "${CAFFE_INSTALL_DIR}"

    wget https://github.com/BVLC/caffe/archive/rc2.tar.gz
    untar_to_dir rc2.tar.gz .

    cp Makefile.config.example Makefile.config
    echo "=== Compiling caffe ==="
    CPU_ONLY=1 \
        LDFLAGS="-L${LOCAL_INSTALL_DIR}/lib" \
        make -j4

    echo "=== Compiling caffe python bindings ==="
    python_include_dir="${LOCAL_INSTALL_DIR}/include/python${PYTHON_SHORT_VERSION}"
    numpy_include_dir="${LOCAL_INSTALL_DIR}/lib/python${PYTHON_SHORT_VERSION}/site-packages/numpy/core/include"

    CPU_ONLY=1 \
        CPLUS_INCLUDE_PATH="${CPLUS_INCLUDE_PATH}:${python_include_dir}:${numpy_include_dir}" \
        LDFLAGS="-L${LOCAL_INSTALL_DIR}/lib" \
        make pycaffe

    echo "=== If that worked, congrats! One last note: ==="
    echo "You'll need to update your PYTHONPATH in .bashrc/.zshrc as follows:"
    echo 'export PYTHONPATH="'${CAFFE_INSTALL_DIR}'/python:$PYTHONPATH"'
}

echo "=== Installing Protobufs ==="
install_protobuf
echo "=== Installing cmake ==="
install_cmake
echo "=== Installing gflags ==="
install_gflags
echo "=== Installing glog ==="
install_glog
echo "=== Installing opencv ==="
install_opencv
echo "=== Installing hdf5 ==="
install_hdf5
echo "=== Installing python2 ==="
install_python2
echo "=== Installing pip ==="
install_pip
echo "=== Installing libpng ==="
install_libpng
echo "=== Installing automake ==="
install_automake
echo "=== Installing freetype ==="
install_freetype
echo "=== Installing python modules ==="
install_python_modules
echo "=== Installing boost ==="
install_boost
echo "=== Installing lmdb ==="
install_lmdb
echo "=== Installing libtool ==="
install_libtool
echo "=== Installing snappy ==="
install_snappy
echo "=== Installing leveldb ==="
install_leveldb
echo "=== Installing openblas ==="
install_openblas

echo "=== The dependencies are installed! ==="
echo "You likely want to add the following lines to your .bashrc/.zshrc"
echo 'export LD_LIBRARY_PATH="'${LOCAL_INSTALL_DIR}'/lib64:'${LOCAL_INSTALL_DIR}'/lib:$LD_LIBRARY_PATH"'
echo 'export C_INCLUDE_PATH="'${LOCAL_INSTALL_DIR}'/include:$C_INCLUDE_PATH"'
echo 'export CPLUS_INCLUDE_PATH="'${LOCAL_INSTALL_DIR}'/include:$CPLUS_INCLUDE_PATH"'

echo "=== Once you've done that, you can run install_caffe by uncommenting below. ==="
# install_caffe