blob: 04e64e3647dc46c326afe4282d0b0defa8a1302e [file] [log] [blame]
#!/usr/bin/env bash
# Shell script used to build the aten/*, caffe2/*, and third_party/*
# dependencies prior to linking libraries and passing headers to the Python
# extension compilation stage. This file is used from setup.py, but can also be
# called standalone to compile the libraries outside of the overall PyTorch
# build process.
#
# TODO: Replace this with the root-level CMakeLists.txt
set -ex
# Options for building only a subset of the libraries
WITH_CUDA=0
WITH_ROCM=0
WITH_NNPACK=0
WITH_MKLDNN=0
WITH_GLOO_IBVERBS=0
WITH_DISTRIBUTED_MW=0
FULL_CAFFE2=0
while [[ $# -gt 0 ]]; do
case "$1" in
--with-cuda)
WITH_CUDA=1
;;
--with-rocm)
WITH_ROCM=1
;;
--with-nnpack)
WITH_NNPACK=1
;;
--with-mkldnn)
WITH_MKLDNN=1
;;
--with-gloo-ibverbs)
WITH_GLOO_IBVERBS=1
;;
--with-distributed-mw)
WITH_DISTRIBUTED_MW=1
;;
--full-caffe2)
FULL_CAFFE2=1
;;
*)
break
;;
esac
shift
done
CMAKE_INSTALL=${CMAKE_INSTALL-make install}
# Save user specified env vars, we will manually propagate them
# to cmake. We copy distutils semantics, referring to
# cpython/Lib/distutils/sysconfig.py as the source of truth
USER_CFLAGS=""
USER_LDFLAGS=""
if [[ -n "$LDFLAGS" ]]; then
USER_LDFLAGS="$USER_LDFLAGS $LDFLAGS"
fi
if [[ -n "$CFLAGS" ]]; then
USER_CFLAGS="$USER_CFLAGS $CFLAGS"
USER_LDFLAGS="$USER_LDFLAGS $CFLAGS"
fi
if [[ -n "$CPPFLAGS" ]]; then
# Unlike distutils, NOT modifying CXX
USER_C_CFLAGS="$USER_CFLAGS $CPPFLAGS"
USER_LDFLAGS="$USER_LDFLAGS $CPPFLAGS"
fi
cd "$(dirname "$0")/.."
PWD=`printf "%q\n" "$(pwd)"`
BASE_DIR="$PWD"
TORCH_LIB_DIR="$BASE_DIR/torch/lib"
INSTALL_DIR="$TORCH_LIB_DIR/tmp_install"
THIRD_PARTY_DIR="$BASE_DIR/third_party"
CMAKE_VERSION=${CMAKE_VERSION:="cmake"}
C_FLAGS=" -DTH_INDEX_BASE=0 -I\"$INSTALL_DIR/include\" \
-I\"$INSTALL_DIR/include/TH\" -I\"$INSTALL_DIR/include/THC\" \
-I\"$INSTALL_DIR/include/THS\" -I\"$INSTALL_DIR/include/THCS\" \
-I\"$INSTALL_DIR/include/THNN\" -I\"$INSTALL_DIR/include/THCUNN\""
# Workaround OpenMPI build failure
# ImportError: /build/pytorch-0.2.0/.pybuild/pythonX.Y_3.6/build/torch/_C.cpython-36m-x86_64-linux-gnu.so: undefined symbol: _ZN3MPI8Datatype4FreeEv
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=686926
C_FLAGS="${C_FLAGS} -DOMPI_SKIP_MPICXX=1"
LDFLAGS="-L\"$INSTALL_DIR/lib\" "
LD_POSTFIX=".so"
if [[ $(uname) == 'Darwin' ]]; then
LDFLAGS="$LDFLAGS -Wl,-rpath,@loader_path"
LD_POSTFIX=".dylib"
else
LDFLAGS="$LDFLAGS -Wl,-rpath,\$ORIGIN"
fi
CPP_FLAGS=" -std=c++11 "
GLOO_FLAGS=""
THD_FLAGS=""
NCCL_ROOT_DIR=${NCCL_ROOT_DIR:-$INSTALL_DIR}
if [[ $WITH_CUDA -eq 1 ]]; then
GLOO_FLAGS="-DUSE_CUDA=1 -DNCCL_ROOT_DIR=$NCCL_ROOT_DIR"
fi
# Gloo infiniband support
if [[ $WITH_GLOO_IBVERBS -eq 1 ]]; then
GLOO_FLAGS+=" -DUSE_IBVERBS=1 -DBUILD_SHARED_LIBS=1"
THD_FLAGS="-DWITH_GLOO_IBVERBS=1"
fi
if [[ $WITH_DISTRIBUTED_MW -eq 1 ]]; then
THD_FLAGS+="-DWITH_DISTRIBUTED_MW=1"
fi
CWRAP_FILES="\
$BASE_DIR/torch/lib/ATen/Declarations.cwrap;\
$BASE_DIR/torch/lib/THNN/generic/THNN.h;\
$BASE_DIR/torch/lib/THCUNN/generic/THCUNN.h;\
$BASE_DIR/torch/lib/ATen/nn.yaml"
CUDA_NVCC_FLAGS=$C_FLAGS
if [[ -z "$CUDA_DEVICE_DEBUG" ]]; then
CUDA_DEVICE_DEBUG=0
fi
if [ -z "$NUM_JOBS" ]; then
NUM_JOBS="$(getconf _NPROCESSORS_ONLN)"
fi
BUILD_TYPE="Release"
if [[ -n "$DEBUG" && $DEBUG -ne 0 ]]; then
BUILD_TYPE="Debug"
elif [[ -n "$REL_WITH_DEB_INFO" && $REL_WITH_DEB_INFO -ne 0 ]]; then
BUILD_TYPE="RelWithDebInfo"
fi
echo "Building in $BUILD_TYPE mode"
# Used to build an individual library
function build() {
# We create a build directory for the library, which will
# contain the cmake output
mkdir -p build/$1
pushd build/$1
BUILD_C_FLAGS=''
case $1 in
THCS | THCUNN ) BUILD_C_FLAGS=$C_FLAGS;;
nanopb ) BUILD_C_FLAGS=$C_FLAGS" -fPIC -fexceptions";;
*) BUILD_C_FLAGS=$C_FLAGS" -fexceptions";;
esac
# TODO: The *_LIBRARIES cmake variables should eventually be
# deprecated because we are using .cmake files to handle finding
# installed libraries instead
${CMAKE_VERSION} ../../$1 -DCMAKE_MODULE_PATH="$BASE_DIR/cmake/FindCUDA" \
${CMAKE_GENERATOR} \
-DTorch_FOUND="1" \
-DCMAKE_INSTALL_PREFIX="$INSTALL_DIR" \
-DCMAKE_C_FLAGS="$BUILD_C_FLAGS $USER_CFLAGS" \
-DCMAKE_CXX_FLAGS="$BUILD_C_FLAGS $CPP_FLAGS $USER_CFLAGS" \
-DCMAKE_EXE_LINKER_FLAGS="$LDFLAGS $USER_LDFLAGS" \
-DCMAKE_SHARED_LINKER_FLAGS="$LDFLAGS $USER_LDFLAGS" \
-DCMAKE_INSTALL_LIBDIR="$INSTALL_DIR/lib" \
-DCUDA_NVCC_FLAGS="$CUDA_NVCC_FLAGS" \
-DCUDA_DEVICE_DEBUG=$CUDA_DEVICE_DEBUG \
-DCMAKE_PREFIX_PATH="$INSTALL_DIR" \
-Dcwrap_files="$CWRAP_FILES" \
-DTH_INCLUDE_PATH="$INSTALL_DIR/include" \
-DTH_LIB_PATH="$INSTALL_DIR/lib" \
-DTH_LIBRARIES="$INSTALL_DIR/lib/libTH$LD_POSTFIX" \
-DCAFFE2_LIBRARIES="$INSTALL_DIR/lib/libcaffe2$LD_POSTFIX" \
-DTHNN_LIBRARIES="$INSTALL_DIR/lib/libTHNN$LD_POSTFIX" \
-DTHCUNN_LIBRARIES="$INSTALL_DIR/lib/libTHCUNN$LD_POSTFIX" \
-DTHS_LIBRARIES="$INSTALL_DIR/lib/libTHS$LD_POSTFIX" \
-DTHC_LIBRARIES="$INSTALL_DIR/lib/libTHC$LD_POSTFIX" \
-DTHCS_LIBRARIES="$INSTALL_DIR/lib/libTHCS$LD_POSTFIX" \
-DTH_SO_VERSION=1 \
-DTHC_SO_VERSION=1 \
-DTHNN_SO_VERSION=1 \
-DTHCUNN_SO_VERSION=1 \
-DTHD_SO_VERSION=1 \
-DUSE_CUDA=$WITH_CUDA \
-DNO_NNPACK=$((1-$WITH_NNPACK)) \
-DNCCL_EXTERNAL=1 \
-Dnanopb_BUILD_GENERATOR=0 \
-DCMAKE_DEBUG_POSTFIX="" \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
${@:2} \
-DCMAKE_EXPORT_COMPILE_COMMANDS=1
${CMAKE_INSTALL} -j"$NUM_JOBS"
popd
local lib_prefix=$INSTALL_DIR/lib/lib$1
if [[ $(uname) == 'Darwin' ]]; then
pushd "$INSTALL_DIR/lib"
for lib in *.dylib; do
echo "Updating install_name for $lib"
install_name_tool -id @rpath/$lib $lib
done
popd
fi
}
function build_nccl() {
mkdir -p build/nccl
pushd build/nccl
${CMAKE_VERSION} ../../nccl -DCMAKE_MODULE_PATH="$BASE_DIR/cmake/FindCUDA" \
${CMAKE_GENERATOR} \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX="$INSTALL_DIR" \
-DCMAKE_C_FLAGS="$C_FLAGS $USER_CFLAGS" \
-DCMAKE_CXX_FLAGS="$C_FLAGS $CPP_FLAGS $USER_CFLAGS" \
-DCMAKE_SHARED_LINKER_FLAGS="$USER_LDFLAGS"
${CMAKE_INSTALL}
mkdir -p ${INSTALL_DIR}/lib
cp "lib/libnccl.so.1" "${INSTALL_DIR}/lib/libnccl.so.1"
if [ ! -f "${INSTALL_DIR}/lib/libnccl.so" ]; then
ln -s "${INSTALL_DIR}/lib/libnccl.so.1" "${INSTALL_DIR}/lib/libnccl.so"
fi
popd
}
# purposefully not using build() because we need Caffe2 to build the same
# regardless of whether it is inside PyTorch or not, so it
# cannot take any special flags
# special flags need to be part of the Caffe2 build itself
#
# However, we do explicitly pass library paths when setup.py has already
# detected them (to ensure that we have a consistent view between the
# PyTorch and Caffe2 builds.)
function build_caffe2() {
mkdir -p build
pushd build
${CMAKE_VERSION} .. \
${CMAKE_GENERATOR} \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DBUILD_CAFFE2=$FULL_CAFFE2 \
-DBUILD_ATEN=ON \
-DBUILD_PYTHON=$FULL_CAFFE2 \
-DBUILD_BINARY=OFF \
-DBUILD_SHARED_LIBS=ON \
-DONNX_NAMESPACE=$ONNX_NAMESPACE \
-DUSE_CUDA=$WITH_CUDA \
-DUSE_ROCM=$WITH_ROCM \
-DUSE_NNPACK=$WITH_NNPACK \
-DCUDNN_INCLUDE_DIR=$CUDNN_INCLUDE_DIR \
-DCUDNN_LIB_DIR=$CUDNN_LIB_DIR \
-DCUDNN_LIBRARY=$CUDNN_LIBRARY \
-DUSE_MKLDNN=$WITH_MKLDNN \
-DMKLDNN_INCLUDE_DIR=$MKLDNN_INCLUDE_DIR \
-DMKLDNN_LIB_DIR=$MKLDNN_LIB_DIR \
-DMKLDNN_LIBRARY=$MKLDNN_LIBRARY \
-DCMAKE_INSTALL_PREFIX="$INSTALL_DIR" \
-DCMAKE_EXPORT_COMPILE_COMMANDS=1 \
-DCMAKE_C_FLAGS="$USER_CFLAGS" \
-DCMAKE_CXX_FLAGS="$USER_CFLAGS" \
-DCMAKE_EXE_LINKER_FLAGS="$USER_LDFLAGS" \
-DCMAKE_SHARED_LINKER_FLAGS="$USER_LDFLAGS"
# STOP!!! Are you trying to add a C or CXX flag? Add it
# to CMakeLists.txt and aten/CMakeLists.txt, not here.
# We need the vanilla cmake build to work.
${CMAKE_INSTALL} -j"$NUM_JOBS"
# Install Python proto files
if [[ $FULL_CAFFE2 -ne 0 ]]; then
find . -name proto
for proto_file in ./caffe/proto/*.py; do
cp $proto_file "$BASE_DIR/caffe/proto/"
done
for proto_file in ./caffe2/proto/*.py; do
cp $proto_file "$BASE_DIR/caffe2/proto/"
done
fi
popd
}
# In the torch/lib directory, create an installation directory
mkdir -p torch/lib/tmp_install
# Build
for arg in "$@"; do
if [[ "$arg" == "nccl" ]]; then
pushd $THIRD_PARTY_DIR
build_nccl
popd
elif [[ "$arg" == "gloo" ]]; then
pushd "$THIRD_PARTY_DIR"
build gloo $GLOO_FLAGS
popd
elif [[ "$arg" == "caffe2" ]]; then
pushd $BASE_DIR
build_caffe2
popd
elif [[ "$arg" == "THD" ]]; then
pushd "$TORCH_LIB_DIR"
build THD $THD_FLAGS
popd
elif [[ "$arg" == "libshm" ]] || [[ "$arg" == "libshm_windows" ]]; then
pushd "$TORCH_LIB_DIR"
build $arg
popd
elif [[ "$arg" == "c10d" ]]; then
pushd "$TORCH_LIB_DIR"
build c10d
popd
else
pushd "$THIRD_PARTY_DIR"
build $arg
popd
fi
done
pushd torch/lib
# If all the builds succeed we copy the libraries, headers,
# binaries to torch/lib
rm -rf "$INSTALL_DIR/lib/cmake"
rm -rf "$INSTALL_DIR/lib/python"
cp -r "$INSTALL_DIR/lib"/* .
if [ -d "$INSTALL_DIR/lib64/" ]; then
cp -r "$INSTALL_DIR/lib64"/* .
fi
cp ../../aten/src/THNN/generic/THNN.h .
cp ../../aten/src/THCUNN/generic/THCUNN.h .
cp -r "$INSTALL_DIR/include" .
if [ -d "$INSTALL_DIR/bin/" ]; then
cp -r "$INSTALL_DIR/bin/"/* .
fi
popd