#!/bin/bash # build_linux_nvidia.sh # Date: 08-03-2022, 24-04-2022 # # Run this script to build MMDeploy SDK and install necessary prerequisites. # This script will also setup python venv and generate prebuild binaries if requested. # ##### # Build vars BUILD_TYPE="Release" ARCH=$(uname -i) PROC_NUM=$(nproc) # Default GCC GCC_COMPILER="g++" ##### # Directories # WORKING_DIR must correspond to MMDeploy root dir WORKING_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/../.." && pwd )" PPLCV_DIR=${WORKING_DIR}/ppl.cv MMDEPLOY_DIR=${WORKING_DIR} ##### # Versions PPLCV_VER="0.7.0" CMAKE_VER="3.23.0" ##### # Flags # WITH_PYTHON: Install misc. dependencies in the active venv WITH_PYTHON=1 # WITH_CLEAN: Remove build output dirs WITH_CLEAN=1 # WITH_PREBUILD: Generate prebuild archives WITH_PREBUILD=0 # WITH_UNATTENDED: Unattended install, skip/use default options WITH_UNATTENDED=0 ##### # Prefix: Set install prefix for ppl.cv, mmdeploy SDK depending on arch if [[ "$ARCH" == aarch64 ]]; then INSTALL_PREFIX="/usr/local/aarch64-linux-gnu" else INSTALL_PREFIX="/usr/local" fi PYTHON_VENV_DIR=${WORKING_DIR}/venv-mmdeploy appargument1=$1 appargument2=$2 ##### # helper functions echo_green() { if [ -n "$1" ]; then echo "$(tput setaf 10)$1$(tput sgr 0)" fi } echo_red() { if [ -n "$1" ]; then echo "$(tput setaf 1)$1$(tput sgr 0)" fi } echo_blue() { if [ -n "$1" ]; then echo "$(tput setaf 4)$1$(tput sgr 0)" fi } contains_element () { local e match="$1" shift for e; do [[ "$e" == "$match" ]] && return 0; done return 1 } function version { echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }'; } prompt_yesno() { if [ -n "$1" ]; then echo_blue "$1" fi if [[ $WITH_UNATTENDED -eq 1 ]] then echo_green "Unattended install, selecting default option" return 2 else echo_blue "(y/n/q) or press [ENTER] to select default option" read -p "?" -n 1 -r echo if [[ $REPLY =~ ^[Yy]$ ]] then return 1 elif [[ $REPLY =~ ^[Nn]$ ]] then return 0 elif [[ $REPLY = "" ]] then echo "Selecting default option..." return 2 elif [[ $REPLY =~ ^[Qq]$ ]] then echo_green "Quitting!" exit else echo_red "Invalid argument. Try again" prompt_yesno fi fi } prereqs() { echo_green "Installing prerequisites..." # cmake check & install echo_green "Checking your cmake version..." CMAKE_DETECT_VER=$(cmake --version | grep -oP '(?<=version).*') if [ $(version $CMAKE_DETECT_VER) -ge $(version "3.14.0") ]; then echo "Cmake version $CMAKE_DETECT_VER is up to date" else echo "CMake too old, purging existing cmake and installing ${CMAKE_VER}..." # purge existing sudo apt-get purge cmake sudo snap remove cmake # install prebuild wget https://github.com/Kitware/CMake/releases/download/v${CMAKE_VER}/cmake-${CMAKE_VER}-linux-${ARCH}.sh chmod +x cmake-${CMAKE_VER}-linux-${ARCH}.sh sudo ./cmake-${CMAKE_VER}-linux-${ARCH}.sh --prefix=/usr --skip-license fi # gcc-7 check echo_green "Checking your gcc version..." GCC_DETECT_VER=$(gcc --version | grep -oP '(?<=\)).*' -m1) if [ $(version $GCC_DETECT_VER) -ge $(version "7.0.0") ]; then echo "GCC version $GCC_DETECT_VER is up to date" else echo "gcc version too old, installing ${CMAKE_VER}..." echo "Purge existing cmake and install ${GCC_DETECT_VER}..." # Add repository if ubuntu < 18.04 sudo add-apt-repository ppa:ubuntu-toolchain-r/test sudo apt-get update sudo apt-get install gcc-7 sudo apt-get install g++-7 GCC_COMPILER="g++-7" fi # spdlog echo_green "Checking spdlog version..." prompt_yesno "Install latest spdlog from source? (Default:no)" local res=$? if [[ $res -eq 1 ]] # || [ $res -eq 2 ] then echo_green "Building and installing latest spdlog from source" # remove libspdlog, as it might be an old version sudo apt-get remove libspdlog-dev -y git clone https://github.com/gabime/spdlog.git spdlog cd spdlog git pull git checkout tags/v1.8.1 mkdir build -p && cd build # we must build spdlog with -fPIC enabled cmake .. -DCMAKE_POSITION_INDEPENDENT_CODE=ON && make -j${PROC_NUM} sudo make install sudo ldconfig fi # tensorrt check echo_green "Check your TensorRT version:" ## Check if ${TENSORRT_DIR} env variable has been set if [ -d "${TENSORRT_DIR}" ]; then echo "TENSORRT_DIR env. variable has been set ${TENSORRT_DIR}" else echo_red "TENSORRT_DIR env. variable has NOT been set." if [[ "$ARCH" == aarch64 ]]; then echo "Added TENSORRT_DIR, CUDNN_DIR to env." echo 'export TENSORRT_DIR="/usr/include/'${ARCH}'-linux-gnu/"' >> ${HOME}/.bashrc echo 'export CUDNN_DIR="/usr/include/'${ARCH}'-linux-gnu/"' >> ${HOME}/.bashrc echo 'export LD_LIBRARY_PATH="/usr/lib/'${ARCH}'-linux-gnu/:$LD_LIBRARY_PATH"' >> ${HOME}/.bashrc #source ${HOME}/.bashrc # sourcing in bash script won't set the env. variables so we will set them temporarily export TENSORRT_DIR="/usr/include/'${ARCH}'-linux-gnu/" export CUDNN_DIR="/usr/include/'${ARCH}'-linux-gnu/" export LD_LIBRARY_PATH="/usr/lib/'${ARCH}'-linux-gnu/:$LD_LIBRARY_PATH" else echo_red "Please Install TensorRT, CUDNN and add TENSORRT_DIR, CUDNN_DIR to environment variables before running this script!" exit fi fi # Determine TensorRT version and set paths accordingly echo "Checking TensorRT version...Please verify the detected versions below:" if [[ "$ARCH" == aarch64 ]]; then cat /usr/include/${ARCH}-linux-gnu/NvInferVersion.h | grep NV_TENSORRT else cat ${TENSORRT_DIR}/include/NvInferVersion.h | grep NV_TENSORRT fi prompt_yesno "Is TensorRT >=8.0.1.6 installed? (Always installed on Jetson) (Default:yes)" local res=$? if [[ $res -eq 1 ]] || [ $res -eq 2 ] then echo "TensorRT appears to be installed..." else echo_red "Error: You must install TensorRT before installing MMDeploy!" exit fi prompt_yesno "Install OpenCV? (Always installed on Jetson) (Default:no)" local res=$? if [[ $res -eq 1 ]] # || [ $res -eq 2 ] then echo "Installing libopencv-dev..." # opencv sudo apt-get install libopencv-dev fi } py_venv() { ## python venv echo_green "Installing python venv..." #check for python installed version pyv="$(python3 -V 2>&1)" pyv_old="Python 3.6" if echo "$pyv" | grep -q "$pyv_old"; then # use python 3.6 curl https://bootstrap.pypa.io/pip/3.6/get-pip.py -o get-pip.py else # use python >=3.7 curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py fi # dependencies sudo apt-get install protobuf-compiler libprotoc-dev libssl-dev curl ninja-build -y sudo apt-get install libopenblas-dev python3-venv python3-dev python3-setuptools -y sudo python3 get-pip.py pip3 install testresources pip3 install --upgrade setuptools wheel if [ -d "${PYTHON_VENV_DIR}" ]; then prompt_yesno "Reinstall existing Python venv ${PYTHON_VENV_DIR}? (Default:no)" local res=$? if [[ $res -eq 1 ]] then rm -r ${PYTHON_VENV_DIR} python3 -m venv ${PYTHON_VENV_DIR} --system-site-packages #system site packages to keep trt from system installation fi else python3 -m venv ${PYTHON_VENV_DIR} --system-site-packages #system site packages to keep trt from system installation fi source ${PYTHON_VENV_DIR}/bin/activate python3 get-pip.py pip3 install testresources pip3 install --upgrade setuptools wheel # Latest PIL is not compatible with mmcv=1.4.1 pip3 install Pillow==7.0.0 if [[ "$ARCH" == aarch64 ]] then # protofbuf on jetson is quite old - must be upgraded pip3 install --upgrade protobuf # Install numpy >1.19.4 might give "Illegal instruction (core dumped)" on Jetson/aarch64 # To solve it, we should set OPENBLAS_CORETYPE echo 'export OPENBLAS_CORETYPE=ARMV8' >> ~/.bashrc #source ${HOME}/.bashrc # sourcing in bash script won't set the env. variables so we will set them temporarily export OPENBLAS_CORETYPE=ARMV8 fi pip3 install numpy pip3 install opencv-python pip3 install matplotlib prompt_yesno "Install PyTorch, Torchvision, mmcv in the active venv? (Default:no)" local res=$? if [[ $res -eq 1 ]] then # pytorch, torchvision, torchaudio if [[ "$ARCH" == aarch64 ]] then # pytorch wget https://nvidia.box.com/shared/static/fjtbno0vpo676a25cgvuqc1wty0fkkg6.whl -O torch-1.10.0-cp36-cp36m-linux_aarch64.whl pip3 install torch-1.10.0-cp36-cp36m-linux_aarch64.whl # torchvision sudo apt-get install libjpeg-dev zlib1g-dev libpython3-dev libavcodec-dev libavformat-dev libswscale-dev -y sudo rm -r torchvision git clone --branch v0.11.1 https://github.com/pytorch/vision torchvision cd torchvision export BUILD_VERSION=0.11.1 # where 0.x.0 is the torchvision version python3 setup.py install cd ../ # torchaudio #sudo apt-get install -y sox libsox-dev libsox-fmt-all #sudo rm -r torchaudio #git clone -b v0.10.0 https://github.com/pytorch/audio torchaudio #cd torchaudio #git submodule update --init --recursive #python3 setup.py install #cd ../ # mmcv pip3 uninstall mmcv-full pip3 install mmcv-full==1.4.1 -f https://download.openmmlab.com/mmcv/dist/cu102/torch1.10.0/index.html else pip3 install torch==1.10.0+cu113 torchvision==0.11.1+cu113 torchaudio==0.10.0+cu113 -f https://download.pytorch.org/whl/cu113/torch_stable.html # mmcv pip3 uninstall mmcv-full pip3 install mmcv-full==1.4.1 -f https://download.openmmlab.com/mmcv/dist/cu113/torch1.10.0/index.html fi fi # cleanup rm get-pip.py } pplcv() { ## ppl.cv echo_green "Building and installing ppl.cv..." cd ${WORKING_DIR} echo_blue "checking out '${PPLCV_DIR}' pkg..." if [ -d "${PPLCV_DIR}" ]; then echo "Already exists! Checking out the requested version..." else git clone https://github.com/openppl-public/ppl.cv.git ${PPLCV_DIR} fi cd ${PPLCV_DIR} git pull git checkout tags/v${PPLCV_VER} # remove all build files if [[ $WITH_CLEAN -eq 1 ]] then sudo rm -r ${PPLCV_DIR}/build fi # build mkdir build -p && cd build cmake -DPPLCV_USE_CUDA=ON -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} .. && make -j${processor_num} && sudo make install sudo ldconfig # generate prebuild and pack into .tar.gz if [[ $WITH_PREBUILD -eq 1 ]] then sudo make DESTDIR=./prebuild install tar -zcvf ${WORKING_DIR}/pplcv_${PPLCV_VER}_cuda-${ARCH}-build.tar.gz -C ./prebuild/ . fi } mmdeploy(){ ## mmdeploy SDK echo_green "Building and installing mmdeploysdk..." cd ${MMDEPLOY_DIR} MMDEPLOY_DETECT_VER=$(cat mmdeploy/version.py | grep -Eo '[0-9]\.[0-9].[0-9]+') # reinit submodules git submodule update --init --recursive # python dependencies if [[ $WITH_PYTHON -eq 1 ]] then source ${PYTHON_VENV_DIR}/bin/activate ## h5py (Required by mmdeploy) ## h5py not directly supported by jetson and must be built/installed manually sudo apt-get install pkg-config libhdf5-10* libhdf5-dev -y sudo pip3 install Cython sudo env H5PY_SETUP_REQUIRES=0 pip3 install -U h5py==2.9.0 pip install -e . fi # remove all build files if [[ $WITH_CLEAN -eq 1 ]] then sudo rm -r ${MMDEPLOY_DIR}/build fi # build mkdir build -p && cd build cmake .. \ -DMMDEPLOY_BUILD_SDK=ON \ -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} \ -DCMAKE_CXX_COMPILER=${GCC_COMPILER} \ -Dpplcv_DIR=${INSTALL_PREFIX}/lib/cmake/ppl \ -DMMDEPLOY_TARGET_DEVICES="cuda;cpu" \ -DMMDEPLOY_TARGET_BACKENDS=trt \ -DMMDEPLOY_CODEBASES=all \ -DMMDEPLOY_BUILD_SDK_PYTHON_API=ON \ -DTENSORRT_DIR=${TENSORRT_DIR} \ -DCUDNN_DIR=${CUDNN_DIR} cmake --build . -- -j${PROC_NUM} && sudo make install sudo ldconfig # generate prebuild and pack into .tar.gz if [[ $WITH_PREBUILD -eq 1 ]] then sudo make DESTDIR=./prebuild install tar -zcvf ${WORKING_DIR}/mmdeploysdk_${MMDEPLOY_VER}_${ARCH}-build.tar.gz -C ./prebuild/ . fi ## build mmdeploy examples cp -r ${MMDEPLOY_DIR}/demo/csrc ${MMDEPLOY_DIR}/build/example cd ${MMDEPLOY_DIR}/build/example rm -r build mkdir build -p && cd build cmake -DMMDeploy_DIR=${INSTALL_PREFIX} .. make all } all() { # build all prereqs py_venv pplcv mmdeploy } ##### # supported package package_list=( "all" "prereqs" "py_venv" "pplcv" "mmdeploy" ) ##### # check input argument if contains_element "$appargument1" "${package_list[@]}"; then echo_green "Build and install '$appargument1'..." else echo_red "Unsupported argument '$appargument1'. Use one of the following:" for i in ${package_list[@]} do echo $i done exit fi ##### # Unattended/auto install if [[ $appargument2 == "auto" ]] then WITH_UNATTENDED=1 fi ##### # Install dependencies in venv? prompt_yesno "Install misc. dependencies in the active venv? (Default:${WITH_PYTHON})" res=$? if [[ $res -eq 1 ]] then WITH_PYTHON=1 elif [[ $res -eq 0 ]] then WITH_PYTHON=0 fi ##### # Clean previous build dirs? prompt_yesno "Clean previous build dirs? (Default:${WITH_CLEAN})" res=$? if [[ $res -eq 1 ]] then WITH_CLEAN=1 elif [[ $res -eq 0 ]] then WITH_CLEAN=0 fi ##### # Generate prebuild dirs? prompt_yesno "Generate prebuild dirs? (Default:${WITH_PREBUILD})" res=$? if [[ $res -eq 1 ]] then WITH_PREBUILD=1 elif [[ $res -eq 0 ]] then WITH_PREBUILD=0 fi $appargument1 cd ${WORKING_DIR} # update env. variables exec bash