2018-11-20 00:48:22 +00:00
#!/usr/bin/env python3
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
import argparse
import fileinput
import getpass
import glob
import logging
import multiprocessing
import os
import platform
import re
import shutil
import subprocess
import sys
2018-12-11 03:15:03 +00:00
import hashlib
from os . path import expanduser
2018-11-20 00:48:22 +00:00
logging . basicConfig ( format = " %(asctime)s %(name)s [ %(levelname)s ] - %(message)s " , level = logging . DEBUG )
log = logging . getLogger ( " Build " )
2019-01-10 06:33:14 +00:00
class BaseError ( Exception ) :
""" Base class for errors originating from build.py. """
pass
2018-12-13 22:46:59 +00:00
2019-01-10 06:33:14 +00:00
class BuildError ( BaseError ) :
2018-12-18 21:23:32 +00:00
""" Error from running build steps. """
def __init__ ( self , * messages ) :
super ( ) . __init__ ( " \n " . join ( messages ) )
2019-01-10 06:33:14 +00:00
class UsageError ( BaseError ) :
""" Usage related error. """
def __init__ ( self , message ) :
super ( ) . __init__ ( message )
2018-11-20 00:48:22 +00:00
def parse_arguments ( ) :
parser = argparse . ArgumentParser ( description = " ONNXRuntime CI build driver. " ,
usage = '''
2019-03-09 01:42:20 +00:00
Default behavior is - - update - - build - - test for native architecture builds .
Default behavior is - - update - - build for cross - compiled builds .
2018-11-20 00:48:22 +00:00
The Update phase will update git submodules , and run cmake to generate makefiles .
The Build phase will build all projects .
The Test phase will run all unit tests , and optionally the ONNX tests .
Use the individual flags to only run the specified stages .
''' )
# Main arguments
parser . add_argument ( " --build_dir " , required = True , help = " Path to the build directory. " )
parser . add_argument ( " --config " , nargs = " + " , default = [ " Debug " ] ,
choices = [ " Debug " , " MinSizeRel " , " Release " , " RelWithDebInfo " ] ,
help = " Configuration(s) to build. " )
parser . add_argument ( " --update " , action = ' store_true ' , help = " Update makefiles. " )
parser . add_argument ( " --build " , action = ' store_true ' , help = " Build. " )
parser . add_argument ( " --clean " , action = ' store_true ' , help = " Run ' cmake --build --target clean ' for the selected config/s. " )
parser . add_argument ( " --parallel " , action = ' store_true ' , help = ''' Use parallel build.
The build setup doesn ' t get all dependencies right, so --parallel only works if you ' re just rebuilding ONNXRuntime code .
If you ' ve done an update that fetched external dependencies you have to build without --parallel the first time.
Once that ' s done, run with " --build --parallel --test " to just build in parallel and run tests. ' ' ' )
parser . add_argument ( " --test " , action = ' store_true ' , help = " Run unit tests. " )
2019-11-27 21:03:23 +00:00
parser . add_argument ( " --skip_tests " , action = ' store_true ' , help = " Skip all tests. " )
2018-11-20 00:48:22 +00:00
# enable ONNX tests
parser . add_argument ( " --enable_onnx_tests " , action = ' store_true ' ,
help = ''' When running the Test phase, run onnx_test_running against available test data directories. ''' )
2019-03-23 00:41:21 +00:00
parser . add_argument ( " --path_to_protoc_exe " , help = " Path to protoc exe. " )
2019-01-10 06:33:14 +00:00
parser . add_argument ( " --test_data_url " , help = " Test data URL. " )
parser . add_argument ( " --test_data_checksum " , help = " Test data checksum (MD5 digest). " )
2019-03-27 04:58:01 +00:00
# generate documentaiton
parser . add_argument ( " --gen_doc " , action = ' store_true ' , help = " Generate documentation on contrib ops " )
2018-11-20 00:48:22 +00:00
# CUDA related
parser . add_argument ( " --use_cuda " , action = ' store_true ' , help = " Enable CUDA. " )
2019-01-23 02:06:14 +00:00
parser . add_argument ( " --cuda_version " , help = " The version of CUDA toolkit to use. Auto-detect if not specified. e.g. 9.0 " )
2018-11-20 00:48:22 +00:00
parser . add_argument ( " --cuda_home " , help = " Path to CUDA home. "
" Read from CUDA_HOME environment variable if --use_cuda is true and --cuda_home is not specified. " )
parser . add_argument ( " --cudnn_home " , help = " Path to CUDNN home. "
" Read from CUDNN_HOME environment variable if --use_cuda is true and --cudnn_home is not specified. " )
# Python bindings
parser . add_argument ( " --enable_pybind " , action = ' store_true ' , help = " Enable Python Bindings. " )
parser . add_argument ( " --build_wheel " , action = ' store_true ' , help = " Build Python Wheel. " )
2019-05-15 16:38:18 +00:00
parser . add_argument ( " --numpy_version " , help = " Installs a specific version of numpy "
2019-03-13 09:55:56 +00:00
" before building the python binding. " )
parser . add_argument ( " --skip-keras-test " , action = ' store_true ' , help = " Skip tests with Keras if keras is installed " )
2018-11-20 00:48:22 +00:00
# C-Sharp bindings
parser . add_argument ( " --build_csharp " , action = ' store_true ' , help = " Build C#.Net DLL and NuGet package " )
# Build a shared lib
parser . add_argument ( " --build_shared_lib " , action = ' store_true ' , help = " Build a shared library for the ONNXRuntime. " )
2019-05-01 01:21:23 +00:00
# Build ONNX Runtime server
parser . add_argument ( " --build_server " , action = ' store_true ' , help = " Build server application for the ONNXRuntime. " )
parser . add_argument ( " --enable_server_tests " , action = ' store_true ' , help = " Run server application tests. " )
2019-05-14 06:08:51 +00:00
parser . add_argument ( " --enable_server_model_tests " , action = ' store_true ' , help = " Run server model tests. " )
2019-05-01 01:21:23 +00:00
2018-11-20 00:48:22 +00:00
# Build options
parser . add_argument ( " --cmake_extra_defines " , nargs = " + " ,
help = " Extra definitions to pass to CMake during build system generation. " +
" These are just CMake -D options without the leading -D. " )
parser . add_argument ( " --x86 " , action = ' store_true ' ,
help = " Create x86 makefiles. Requires --update and no existing cache CMake setup. Delete CMakeCache.txt if needed " )
2019-03-09 01:42:20 +00:00
parser . add_argument ( " --arm " , action = ' store_true ' ,
help = " Create ARM makefiles. Requires --update and no existing cache CMake setup. Delete CMakeCache.txt if needed " )
parser . add_argument ( " --arm64 " , action = ' store_true ' ,
help = " Create ARM64 makefiles. Requires --update and no existing cache CMake setup. Delete CMakeCache.txt if needed " )
2018-11-29 00:37:21 +00:00
parser . add_argument ( " --msvc_toolset " , help = " MSVC toolset to use. e.g. 14.11 " )
2019-07-24 20:20:05 +00:00
parser . add_argument ( " --android " , action = ' store_true ' , help = ' Build for Android ' )
parser . add_argument ( " --android_abi " , type = str , default = ' arm64-v8a ' ,
help = ' ' )
parser . add_argument ( " --android_api " , type = int , default = 27 ,
help = ' Android API Level, e.g. 21 ' )
parser . add_argument ( " --android_ndk_path " , default = " " , help = " Path to the Android NDK " )
2018-11-20 00:48:22 +00:00
# Arguments needed by CI
parser . add_argument ( " --cmake_path " , default = " cmake " , help = " Path to the CMake program. " )
parser . add_argument ( " --ctest_path " , default = " ctest " , help = " Path to the CTest program. " )
parser . add_argument ( " --skip_submodule_sync " , action = ' store_true ' , help = " Don ' t do a ' git submodule update ' . Makes the Update phase faster. " )
2018-12-18 21:23:32 +00:00
parser . add_argument ( " --use_jemalloc " , action = ' store_true ' , help = " Use jemalloc. " )
2019-09-14 00:12:48 +00:00
parser . add_argument ( " --use_mimalloc " , action = ' store_true ' , help = " Use mimalloc. " )
2018-11-20 00:48:22 +00:00
parser . add_argument ( " --use_openblas " , action = ' store_true ' , help = " Build with OpenBLAS. " )
2019-12-03 15:34:23 +00:00
parser . add_argument ( " --use_dnnl " , action = ' store_true ' , help = " Build with DNNL. " )
2018-11-20 00:48:22 +00:00
parser . add_argument ( " --use_mklml " , action = ' store_true ' , help = " Build with MKLML. " )
2019-08-27 01:13:22 +00:00
parser . add_argument ( " --use_gemmlowp " , action = ' store_true ' , help = " Build with gemmlowp for quantized gemm. " )
2019-08-15 20:59:59 +00:00
parser . add_argument ( " --use_automl " , action = ' store_true ' , help = " Build with AutoML support. " )
2019-04-21 00:02:35 +00:00
parser . add_argument ( " --use_ngraph " , action = ' store_true ' , help = " Build with nGraph. " )
2019-06-18 15:58:53 +00:00
parser . add_argument ( " --use_openvino " , nargs = " ? " , const = " CPU_FP32 " ,
2019-09-27 01:32:16 +00:00
choices = [ " CPU_FP32 " , " GPU_FP32 " , " GPU_FP16 " , " VAD-M_FP16 " , " MYRIAD_FP16 " , " VAD-F_FP32 " ] , help = " Build with OpenVINO for specific hardware. " )
2019-07-24 20:20:05 +00:00
parser . add_argument ( " --use_dnnlibrary " , action = ' store_true ' , help = " Build with DNNLibrary. " )
2019-01-18 20:28:13 +00:00
parser . add_argument ( " --use_nsync " , action = ' store_true ' , help = " Build with NSYNC. " )
2018-11-20 00:48:22 +00:00
parser . add_argument ( " --use_preinstalled_eigen " , action = ' store_true ' , help = " Use pre-installed eigen. " )
parser . add_argument ( " --eigen_path " , help = " Path to pre-installed eigen. " )
parser . add_argument ( " --use_tvm " , action = " store_true " , help = " Build with tvm " )
2019-06-01 01:48:14 +00:00
parser . add_argument ( " --use_openmp " , action = ' store_true ' , help = " Build with OpenMP. " )
2018-11-20 00:48:22 +00:00
parser . add_argument ( " --use_llvm " , action = " store_true " , help = " Build tvm with llvm " )
2019-01-15 23:19:30 +00:00
parser . add_argument ( " --use_eigenthreadpool " , action = " store_true " , help = " Build with eigenthreadpool " )
2018-11-20 00:48:22 +00:00
parser . add_argument ( " --enable_msinternal " , action = " store_true " , help = " Enable for Microsoft internal builds only. " )
parser . add_argument ( " --llvm_path " , help = " Path to llvm dir " )
parser . add_argument ( " --use_brainslice " , action = " store_true " , help = " Build with brain slice " )
2018-12-18 21:23:32 +00:00
parser . add_argument ( " --brain_slice_package_path " , help = " Path to brain slice packages " )
parser . add_argument ( " --brain_slice_package_name " , help = " Name of brain slice packages " )
2018-11-20 00:48:22 +00:00
parser . add_argument ( " --brain_slice_client_package_name " , help = " Name of brainslice client package " )
parser . add_argument ( " --use_nuphar " , action = ' store_true ' , help = " Build with nuphar " )
2019-03-14 19:00:39 +00:00
parser . add_argument ( " --use_tensorrt " , action = ' store_true ' , help = " Build with TensorRT " )
parser . add_argument ( " --tensorrt_home " , help = " Path to TensorRT installation dir " )
2019-03-21 21:06:38 +00:00
parser . add_argument ( " --use_full_protobuf " , action = ' store_true ' , help = " Use the full protobuf library " )
2019-03-26 19:31:36 +00:00
parser . add_argument ( " --disable_contrib_ops " , action = ' store_true ' , help = " Disable contrib ops (reduces binary size) " )
2019-11-27 21:03:23 +00:00
parser . add_argument ( " --skip_onnx_tests " , action = ' store_true ' , help = " Explicitly disable all onnx related tests. Note: Use --skip_tests to skip all tests. " )
2019-11-22 00:55:32 +00:00
parser . add_argument ( " --skip_winml_tests " , action = ' store_true ' , help = " Explicitly disable all WinML related tests " )
2019-04-16 05:37:47 +00:00
parser . add_argument ( " --enable_msvc_static_runtime " , action = ' store_true ' , help = " Enable static linking of MSVC runtimes. " )
2019-06-07 18:50:23 +00:00
parser . add_argument ( " --enable_language_interop_ops " , action = ' store_true ' , help = " Enable operator implemented in language other than cpp " )
2019-09-27 01:32:16 +00:00
parser . add_argument ( " --cmake_generator " , choices = [ ' Visual Studio 15 2017 ' , ' Visual Studio 16 2019 ' ] ,
2019-07-18 18:43:11 +00:00
default = ' Visual Studio 15 2017 ' , help = " Specify the generator that CMake invokes. This is only supported on Windows " )
2019-10-14 18:16:34 +00:00
parser . add_argument ( " --enable_multi_device_test " , action = ' store_true ' , help = " Test with multi-device. Mostly used for multi-device GPU " )
2019-10-15 13:13:07 +00:00
parser . add_argument ( " --use_dml " , action = ' store_true ' , help = " Build with DirectML. " )
2019-08-15 22:27:05 +00:00
parser . add_argument ( " --use_winml " , action = ' store_true ' , help = " Build with WinML. " )
2019-11-16 01:43:44 +00:00
parser . add_argument ( " --use_telemetry " , action = ' store_true ' , help = " Only official builds can set this flag to enable telemetry. " )
2018-11-20 00:48:22 +00:00
return parser . parse_args ( )
2018-12-18 21:23:32 +00:00
def resolve_executable_path ( command_or_path ) :
""" Returns the absolute path of an executable. """
executable_path = shutil . which ( command_or_path )
if executable_path is None :
raise BuildError ( " Failed to resolve executable path for ' {} ' . " . format ( command_or_path ) )
return os . path . realpath ( executable_path )
2018-11-20 00:48:22 +00:00
def is_windows ( ) :
return sys . platform . startswith ( " win " )
def is_ubuntu_1604 ( ) :
return platform . linux_distribution ( ) [ 0 ] == ' Ubuntu ' and platform . linux_distribution ( ) [ 1 ] == ' 16.04 '
def get_config_build_dir ( build_dir , config ) :
# build directory per configuration
return os . path . join ( build_dir , config )
2019-09-02 06:01:47 +00:00
def run_subprocess ( args , cwd = None , capture = False , dll_path = None , shell = False , env = { } ) :
2018-11-20 00:48:22 +00:00
log . debug ( " Running subprocess in ' {0} ' \n {1} " . format ( cwd or os . getcwd ( ) , args ) )
my_env = os . environ . copy ( )
if dll_path :
if is_windows ( ) :
2019-01-08 03:37:06 +00:00
my_env [ " PATH " ] = dll_path + os . pathsep + my_env [ " PATH " ]
2018-11-20 00:48:22 +00:00
else :
if " LD_LIBRARY_PATH " in my_env :
my_env [ " LD_LIBRARY_PATH " ] + = os . pathsep + dll_path
else :
my_env [ " LD_LIBRARY_PATH " ] = dll_path
2019-01-10 06:33:14 +00:00
stdout , stderr = ( subprocess . PIPE , subprocess . STDOUT ) if capture else ( None , None )
2019-09-02 06:01:47 +00:00
my_env . update ( env )
2019-11-27 21:03:23 +00:00
completed_process = subprocess . run ( args , cwd = cwd , check = True , stdout = stdout , stderr = stderr , env = my_env , shell = shell )
log . debug ( " Subprocess completed. Return code= " + str ( completed_process . returncode ) )
return completed_process
2018-11-20 00:48:22 +00:00
def update_submodules ( source_dir ) :
2019-07-10 20:11:59 +00:00
run_subprocess ( [ " git " , " submodule " , " sync " , " --recursive " ] , cwd = source_dir )
2018-11-20 00:48:22 +00:00
run_subprocess ( [ " git " , " submodule " , " update " , " --init " , " --recursive " ] , cwd = source_dir )
def is_docker ( ) :
path = ' /proc/self/cgroup '
return (
os . path . exists ( ' /.dockerenv ' ) or
os . path . isfile ( path ) and any ( ' docker ' in line for line in open ( path ) )
)
def is_sudo ( ) :
return ' SUDO_UID ' in os . environ . keys ( )
def install_apt_package ( package ) :
have = package in str ( run_subprocess ( [ " apt " , " list " , " --installed " , package ] , capture = True ) . stdout )
if not have :
if is_sudo ( ) :
run_subprocess ( [ ' apt-get ' , ' install ' , ' -y ' , package ] )
else :
2018-12-18 21:23:32 +00:00
raise BuildError ( package + " APT package missing. Please re-run this script using sudo to install. " )
2018-11-20 00:48:22 +00:00
def install_ubuntu_deps ( args ) :
2018-12-18 21:23:32 +00:00
' Check if the necessary Ubuntu dependencies are installed. Not required on docker. Provide help output if missing. '
2018-11-20 00:48:22 +00:00
# check we need the packages first
if not ( args . enable_pybind or args . use_openblas ) :
return
# not needed on docker as packages are pre-installed
if not is_docker ( ) :
try :
if args . enable_pybind :
install_apt_package ( " python3 " )
if args . use_openblas :
install_apt_package ( " libopenblas-dev " )
except Exception as e :
2018-12-18 21:23:32 +00:00
raise BuildError ( " Error setting up required APT packages. {} " . format ( str ( e ) ) )
2018-11-20 00:48:22 +00:00
2019-03-13 09:55:56 +00:00
def install_python_deps ( numpy_version = " " ) :
2019-09-02 06:01:47 +00:00
dep_packages = [ ' setuptools ' , ' wheel ' , ' pytest ' ]
2019-05-15 16:38:18 +00:00
dep_packages . append ( ' numpy== {} ' . format ( numpy_version ) if numpy_version else ' numpy>=1.15.0 ' )
2019-09-02 06:01:47 +00:00
dep_packages . append ( ' sympy>=1.1 ' )
dep_packages . append ( ' packaging ' )
2018-11-20 00:48:22 +00:00
run_subprocess ( [ sys . executable , ' -m ' , ' pip ' , ' install ' , ' --trusted-host ' , ' files.pythonhosted.org ' ] + dep_packages )
2018-12-11 03:15:03 +00:00
def check_md5 ( filename , expected_md5 ) :
if not os . path . exists ( filename ) :
return False
hash_md5 = hashlib . md5 ( )
BLOCKSIZE = 1024 * 64
with open ( filename , " rb " ) as f :
buf = f . read ( BLOCKSIZE )
while len ( buf ) > 0 :
hash_md5 . update ( buf )
buf = f . read ( BLOCKSIZE )
hex = hash_md5 . hexdigest ( )
if hex != expected_md5 :
log . info ( ' md5 mismatch, expect %s , got %s ' % ( expected_md5 , hex ) )
os . remove ( filename )
return False
return True
2019-01-10 06:33:14 +00:00
2019-11-22 20:14:03 +00:00
def setup_test_data ( build_dir , configs ) :
2019-01-10 06:33:14 +00:00
# create a shortcut for test models if there is a 'models' folder in build_dir
if is_windows ( ) :
2018-12-13 22:46:59 +00:00
src_model_dir = os . path . join ( build_dir , ' models ' )
for config in configs :
config_build_dir = get_config_build_dir ( build_dir , config )
os . makedirs ( config_build_dir , exist_ok = True )
dest_model_dir = os . path . join ( config_build_dir , ' models ' )
if os . path . exists ( src_model_dir ) and not os . path . exists ( dest_model_dir ) :
log . debug ( " creating shortcut %s -> %s " % ( src_model_dir , dest_model_dir ) )
2019-01-10 06:33:14 +00:00
run_subprocess ( [ ' mklink ' , ' /D ' , ' /J ' , dest_model_dir , src_model_dir ] , shell = True )
2019-03-23 00:41:21 +00:00
def generate_build_tree ( cmake_path , source_dir , build_dir , cuda_home , cudnn_home , tensorrt_home , path_to_protoc_exe , configs , cmake_extra_defines , args , cmake_extra_args ) :
2018-11-20 00:48:22 +00:00
log . info ( " Generating CMake build tree " )
cmake_dir = os . path . join ( source_dir , " cmake " )
# TODO: fix jemalloc build so it does not conflict with onnxruntime shared lib builds. (e.g. onnxuntime_pybind)
# for now, disable jemalloc if pybind is also enabled.
cmake_args = [ cmake_path , cmake_dir ,
2019-01-10 06:33:14 +00:00
" -Donnxruntime_RUN_ONNX_TESTS= " + ( " ON " if args . enable_onnx_tests else " OFF " ) ,
2019-11-22 00:55:32 +00:00
" -Donnxruntime_BUILD_WINML_TESTS= " + ( " OFF " if args . skip_winml_tests else " ON " ) ,
2018-11-20 00:48:22 +00:00
" -Donnxruntime_GENERATE_TEST_REPORTS=ON " ,
2019-12-03 17:57:56 +00:00
" -Donnxruntime_DEV_MODE= " + ( " OFF " if args . android else " ON " ) ,
2018-11-20 00:48:22 +00:00
" -DPYTHON_EXECUTABLE= " + sys . executable ,
" -Donnxruntime_USE_CUDA= " + ( " ON " if args . use_cuda else " OFF " ) ,
2019-01-18 20:28:13 +00:00
" -Donnxruntime_USE_NSYNC= " + ( " OFF " if is_windows ( ) or not args . use_nsync else " ON " ) ,
2018-11-20 00:48:22 +00:00
" -Donnxruntime_CUDNN_HOME= " + ( cudnn_home if args . use_cuda else " " ) ,
2019-09-27 01:32:16 +00:00
" -Donnxruntime_USE_AUTOML= " + ( " ON " if args . use_automl else " OFF " ) ,
2019-03-14 19:00:39 +00:00
" -Donnxruntime_CUDA_HOME= " + ( cuda_home if args . use_cuda else " " ) ,
2018-11-20 00:48:22 +00:00
" -Donnxruntime_USE_JEMALLOC= " + ( " ON " if args . use_jemalloc else " OFF " ) ,
2019-09-14 00:12:48 +00:00
" -Donnxruntime_USE_MIMALLOC= " + ( " ON " if args . use_mimalloc else " OFF " ) ,
2018-11-20 00:48:22 +00:00
" -Donnxruntime_ENABLE_PYTHON= " + ( " ON " if args . enable_pybind else " OFF " ) ,
" -Donnxruntime_BUILD_CSHARP= " + ( " ON " if args . build_csharp else " OFF " ) ,
2019-07-04 08:08:14 +00:00
" -Donnxruntime_BUILD_SHARED_LIB= " + ( " ON " if args . build_shared_lib or args . build_server else " OFF " ) ,
2018-11-20 00:48:22 +00:00
" -Donnxruntime_USE_EIGEN_FOR_BLAS= " + ( " OFF " if args . use_openblas else " ON " ) ,
" -Donnxruntime_USE_OPENBLAS= " + ( " ON " if args . use_openblas else " OFF " ) ,
2019-12-03 15:34:23 +00:00
" -Donnxruntime_USE_DNNL= " + ( " ON " if args . use_dnnl else " OFF " ) ,
2018-11-20 00:48:22 +00:00
" -Donnxruntime_USE_MKLML= " + ( " ON " if args . use_mklml else " OFF " ) ,
2019-08-27 01:13:22 +00:00
" -Donnxruntime_USE_GEMMLOWP= " + ( " ON " if args . use_gemmlowp else " OFF " ) ,
2019-04-21 00:02:35 +00:00
" -Donnxruntime_USE_NGRAPH= " + ( " ON " if args . use_ngraph else " OFF " ) ,
2019-06-18 15:58:53 +00:00
" -Donnxruntime_USE_OPENVINO= " + ( " ON " if args . use_openvino else " OFF " ) ,
" -Donnxruntime_USE_OPENVINO_MYRIAD= " + ( " ON " if args . use_openvino == " MYRIAD_FP16 " else " OFF " ) ,
" -Donnxruntime_USE_OPENVINO_GPU_FP32= " + ( " ON " if args . use_openvino == " GPU_FP32 " else " OFF " ) ,
" -Donnxruntime_USE_OPENVINO_GPU_FP16= " + ( " ON " if args . use_openvino == " GPU_FP16 " else " OFF " ) ,
" -Donnxruntime_USE_OPENVINO_CPU_FP32= " + ( " ON " if args . use_openvino == " CPU_FP32 " else " OFF " ) ,
2019-08-05 22:28:46 +00:00
" -Donnxruntime_USE_OPENVINO_VAD_M= " + ( " ON " if args . use_openvino == " VAD-M_FP16 " else " OFF " ) ,
2019-09-27 01:32:16 +00:00
" -Donnxruntime_USE_OPENVINO_VAD_F= " + ( " ON " if args . use_openvino == " VAD-F_FP32 " else " OFF " ) ,
2019-07-24 20:20:05 +00:00
" -Donnxruntime_USE_NNAPI= " + ( " ON " if args . use_dnnlibrary else " OFF " ) ,
2019-08-02 05:25:56 +00:00
" -Donnxruntime_USE_OPENMP= " + ( " ON " if args . use_openmp and not args . use_dnnlibrary and not args . use_mklml and not args . use_ngraph else " OFF " ) ,
2018-11-20 00:48:22 +00:00
" -Donnxruntime_USE_TVM= " + ( " ON " if args . use_tvm else " OFF " ) ,
" -Donnxruntime_USE_LLVM= " + ( " ON " if args . use_llvm else " OFF " ) ,
" -Donnxruntime_ENABLE_MICROSOFT_INTERNAL= " + ( " ON " if args . enable_msinternal else " OFF " ) ,
" -Donnxruntime_USE_BRAINSLICE= " + ( " ON " if args . use_brainslice else " OFF " ) ,
" -Donnxruntime_USE_NUPHAR= " + ( " ON " if args . use_nuphar else " OFF " ) ,
2019-03-21 21:06:38 +00:00
" -Donnxruntime_USE_EIGEN_THREADPOOL= " + ( " ON " if args . use_eigenthreadpool else " OFF " ) ,
2019-03-14 19:00:39 +00:00
" -Donnxruntime_USE_TENSORRT= " + ( " ON " if args . use_tensorrt else " OFF " ) ,
" -Donnxruntime_TENSORRT_HOME= " + ( tensorrt_home if args . use_tensorrt else " " ) ,
2019-03-09 01:42:20 +00:00
# By default - we currently support only cross compiling for ARM/ARM64 (no native compilation supported through this script)
" -Donnxruntime_CROSS_COMPILING= " + ( " ON " if args . arm64 or args . arm else " OFF " ) ,
2019-05-01 01:21:23 +00:00
" -Donnxruntime_BUILD_SERVER= " + ( " ON " if args . build_server else " OFF " ) ,
2019-03-12 16:47:45 +00:00
" -Donnxruntime_BUILD_x86= " + ( " ON " if args . x86 else " OFF " ) ,
2019-04-21 00:02:35 +00:00
# nGraph and TensorRT providers currently only supports full_protobuf option.
2019-05-01 21:58:21 +00:00
" -Donnxruntime_USE_FULL_PROTOBUF= " + ( " ON " if args . use_full_protobuf or args . use_ngraph or args . use_tensorrt or args . build_server or args . gen_doc else " OFF " ) ,
2019-03-26 19:31:36 +00:00
" -Donnxruntime_DISABLE_CONTRIB_OPS= " + ( " ON " if args . disable_contrib_ops else " OFF " ) ,
2019-04-16 05:37:47 +00:00
" -Donnxruntime_MSVC_STATIC_RUNTIME= " + ( " ON " if args . enable_msvc_static_runtime else " OFF " ) ,
2019-10-08 19:02:45 +00:00
# enable pyop if it is nightly build
" -Donnxruntime_ENABLE_LANGUAGE_INTEROP_OPS= " + ( " ON " if args . enable_language_interop_ops or ( args . config != ' Debug ' and bool ( os . getenv ( ' NIGHTLY_BUILD ' ) == ' 1 ' ) ) else " OFF " ) ,
2019-10-15 13:13:07 +00:00
" -Donnxruntime_USE_DML= " + ( " ON " if args . use_dml else " OFF " ) ,
2019-11-23 00:13:28 +00:00
" -Donnxruntime_USE_WINML= " + ( " ON " if args . use_winml else " OFF " ) ,
2019-11-16 01:43:44 +00:00
" -Donnxruntime_USE_TELEMETRY= " + ( " ON " if args . use_telemetry else " OFF " ) ,
2018-11-20 00:48:22 +00:00
]
if args . use_brainslice :
2018-12-05 21:48:51 +00:00
bs_pkg_name = args . brain_slice_package_name . split ( ' . ' , 1 )
bs_shared_lib_name = ' . ' . join ( ( bs_pkg_name [ 0 ] , ' redist ' , bs_pkg_name [ 1 ] ) )
cmake_args + = [
" -Donnxruntime_BRAINSLICE_LIB_PATH= %s / %s " % ( args . brain_slice_package_path , args . brain_slice_package_name ) ,
" -Donnxruntime_BS_CLIENT_PACKAGE= %s / %s " % ( args . brain_slice_package_path , args . brain_slice_client_package_name ) ,
" -Donnxruntime_BRAINSLICE_dynamic_lib_PATH= %s / %s " % ( args . brain_slice_package_path , bs_shared_lib_name ) ]
2018-11-20 00:48:22 +00:00
if args . use_llvm :
cmake_args + = [ " -DLLVM_DIR= %s " % args . llvm_path ]
if args . use_cuda and not is_windows ( ) :
nvml_stub_path = cuda_home + " /lib64/stubs "
cmake_args + = [ " -DCUDA_CUDA_LIBRARY= " + nvml_stub_path ]
if args . use_preinstalled_eigen :
cmake_args + = [ " -Donnxruntime_USE_PREINSTALLED_EIGEN=ON " ,
" -Deigen_SOURCE_PATH= " + args . eigen_path ]
2019-07-24 20:20:05 +00:00
if args . android :
cmake_args + = [ " -DCMAKE_TOOLCHAIN_FILE= " + args . android_ndk_path + " /build/cmake/android.toolchain.cmake " ,
" -DANDROID_PLATFORM=android- " + str ( args . android_api ) ,
" -DANDROID_ABI= " + str ( args . android_abi ) ]
2019-03-23 00:41:21 +00:00
if path_to_protoc_exe :
2019-03-09 01:42:20 +00:00
cmake_args + = [ " -DONNX_CUSTOM_PROTOC_EXECUTABLE= %s " % path_to_protoc_exe ]
2019-03-27 04:58:01 +00:00
if args . gen_doc :
cmake_args + = [ " -Donnxruntime_PYBIND_EXPORT_OPSCHEMA=ON " ]
2019-07-19 18:25:03 +00:00
else :
cmake_args + = [ " -Donnxruntime_PYBIND_EXPORT_OPSCHEMA=OFF " ]
2019-03-27 04:58:01 +00:00
2018-11-20 00:48:22 +00:00
cmake_args + = [ " -D {} " . format ( define ) for define in cmake_extra_defines ]
if is_windows ( ) :
cmake_args + = cmake_extra_args
for config in configs :
config_build_dir = get_config_build_dir ( build_dir , config )
os . makedirs ( config_build_dir , exist_ok = True )
if args . use_tvm :
2019-01-08 03:37:06 +00:00
os . environ [ " PATH " ] = os . path . join ( config_build_dir , " external " , " tvm " , config ) + os . pathsep + os . environ [ " PATH " ]
2018-11-20 00:48:22 +00:00
run_subprocess ( cmake_args + [ " -DCMAKE_BUILD_TYPE= {} " . format ( config ) ] , cwd = config_build_dir )
def clean_targets ( cmake_path , build_dir , configs ) :
for config in configs :
log . info ( " Cleaning targets for %s configuration " , config )
build_dir2 = get_config_build_dir ( build_dir , config )
cmd_args = [ cmake_path ,
" --build " , build_dir2 ,
" --config " , config ,
" --target " , " clean " ]
run_subprocess ( cmd_args )
def build_targets ( cmake_path , build_dir , configs , parallel ) :
for config in configs :
log . info ( " Building targets for %s configuration " , config )
build_dir2 = get_config_build_dir ( build_dir , config )
cmd_args = [ cmake_path ,
" --build " , build_dir2 ,
" --config " , config ]
build_tool_args = [ ]
if parallel :
num_cores = str ( multiprocessing . cpu_count ( ) )
if is_windows ( ) :
build_tool_args + = [ " /maxcpucount: " + num_cores ]
else :
build_tool_args + = [ " -j " + num_cores ]
if ( build_tool_args ) :
cmd_args + = [ " -- " ]
cmd_args + = build_tool_args
run_subprocess ( cmd_args )
def add_dir_if_exists ( dir , dir_list ) :
if ( os . path . isdir ( dir ) ) :
dir_list . append ( dir )
def setup_cuda_vars ( args ) :
cuda_home = " "
cudnn_home = " "
if ( args . use_cuda ) :
cuda_home = args . cuda_home if args . cuda_home else os . getenv ( " CUDA_HOME " )
cudnn_home = args . cudnn_home if args . cudnn_home else os . getenv ( " CUDNN_HOME " )
cuda_home_valid = ( cuda_home != None and os . path . exists ( cuda_home ) )
cudnn_home_valid = ( cudnn_home != None and os . path . exists ( cudnn_home ) )
if ( not cuda_home_valid or not cudnn_home_valid ) :
2018-12-18 21:23:32 +00:00
raise BuildError ( " cuda_home and cudnn_home paths must be specified and valid. " ,
" cuda_home= ' {} ' valid= {} . cudnn_home= ' {} ' valid= {} "
. format ( cuda_home , cuda_home_valid , cudnn_home , cudnn_home_valid ) )
2018-11-20 00:48:22 +00:00
if ( is_windows ( ) ) :
2018-11-29 02:25:41 +00:00
# Validate that the cudnn_home is pointing at the right level
if ( not os . path . exists ( os . path . join ( cudnn_home , " bin " ) ) ) :
2018-12-18 21:23:32 +00:00
raise BuildError ( " cudnn_home path should include the ' cuda ' folder, and must contain the CUDNN ' bin ' directory. " ,
" cudnn_home= ' {} ' " . format ( cudnn_home ) )
2018-11-29 02:25:41 +00:00
2018-11-20 00:48:22 +00:00
os . environ [ " CUDA_PATH " ] = cuda_home
os . environ [ " CUDA_TOOLKIT_ROOT_DIR " ] = cuda_home
cuda_bin_path = os . path . join ( cuda_home , ' bin ' )
os . environ [ " CUDA_BIN_PATH " ] = cuda_bin_path
2019-01-15 18:29:00 +00:00
os . environ [ " PATH " ] + = os . pathsep + cuda_bin_path + os . pathsep + os . path . join ( cudnn_home , ' bin ' )
2018-11-20 00:48:22 +00:00
# Add version specific CUDA_PATH_Vx_y value as the Visual Studio build files require that
version_file = os . path . join ( cuda_home , ' version.txt ' )
if not os . path . exists ( version_file ) :
2018-12-18 21:23:32 +00:00
raise BuildError ( " No version file found in CUDA install directory. Looked for " + version_file )
2018-11-20 00:48:22 +00:00
2018-11-29 00:37:21 +00:00
cuda_major_version = " unknown "
2018-11-20 00:48:22 +00:00
with open ( version_file ) as f :
# First line of version file should have something like 'CUDA Version 9.2.148'
first_line = f . readline ( )
m = re . match ( " CUDA Version ( \ d+).( \ d+) " , first_line )
if not m :
2018-12-18 21:23:32 +00:00
raise BuildError ( " Couldn ' t read version from first line of " + version_file )
2018-11-20 00:48:22 +00:00
2018-11-29 00:37:21 +00:00
cuda_major_version = m . group ( 1 )
2018-11-20 00:48:22 +00:00
minor = m . group ( 2 )
2018-11-29 00:37:21 +00:00
os . environ [ " CUDA_PATH_V {} _ {} " . format ( cuda_major_version , minor ) ] = cuda_home
2018-11-20 00:48:22 +00:00
vc_ver_str = os . getenv ( " VCToolsVersion " ) or " "
vc_ver = vc_ver_str . split ( " . " )
if len ( vc_ver ) != 3 :
log . warning ( " Unable to automatically verify VS 2017 toolset is compatible with CUDA. Will attempt to use. " )
log . warning ( " Failed to get valid Visual C++ Tools version from VCToolsVersion environment variable value of ' " + vc_ver_str + " ' " )
log . warning ( " VCToolsVersion is set in a VS 2017 Developer Command shell, or by running \" % VS2017INSTALLDIR % \\ VC \\ Auxiliary \\ Build \\ vcvars64.bat \" " )
2018-11-29 00:37:21 +00:00
log . warning ( " See build.md in the root ONNXRuntime directory for instructions on installing the Visual C++ 2017 14.11 toolset if needed. " )
2018-11-20 00:48:22 +00:00
2018-11-29 00:37:21 +00:00
elif cuda_major_version == " 9 " and vc_ver [ 0 ] == " 14 " and int ( vc_ver [ 1 ] ) > 11 :
2018-12-18 21:23:32 +00:00
raise BuildError ( " Visual C++ Tools version not supported by CUDA v9. You must setup the environment to use the 14.11 toolset. " ,
" Current version is {} . CUDA 9.2 requires version 14.11.* " . format ( vc_ver_str ) ,
" If necessary manually install the 14.11 toolset using the Visual Studio 2017 updater. " ,
" See ' Windows CUDA Build ' in build.md in the root directory of this repository. " )
2019-09-27 01:32:16 +00:00
2019-07-18 18:43:11 +00:00
# TODO: check if cuda_version >=10.1, when cuda is enabled and VS version >=2019
2018-11-20 00:48:22 +00:00
return cuda_home , cudnn_home
2019-03-14 19:00:39 +00:00
def setup_tensorrt_vars ( args ) :
tensorrt_home = " "
if ( args . use_tensorrt ) :
tensorrt_home = args . tensorrt_home if args . tensorrt_home else os . getenv ( " TENSORRT_HOME " )
tensorrt_home_valid = ( tensorrt_home != None and os . path . exists ( tensorrt_home ) )
if ( not tensorrt_home_valid ) :
raise BuildError ( " tensorrt_home paths must be specified and valid. " ,
" tensorrt_home= ' {} ' valid= {} . "
. format ( tensorrt_home , tensorrt_home_valid ) )
2019-06-18 15:58:53 +00:00
# Set maximum batch size for TensorRT. The number needs to be no less than maximum batch size in all unit tests
2019-04-18 20:20:37 +00:00
os . environ [ " ORT_TENSORRT_MAX_BATCH_SIZE " ] = " 13 "
2019-06-18 15:58:53 +00:00
# Set maximum workspace size in byte for TensorRT (1GB = 1073741824 bytes)
os . environ [ " ORT_TENSORRT_MAX_WORKSPACE_SIZE " ] = " 1073741824 "
2019-05-24 17:12:55 +00:00
# Set maximum number of iterations to detect unsupported nodes and partition the models for TensorRT
os . environ [ " ORT_TENSORRT_MAX_PARSER_ITERATIONS " ] = " 6 "
2019-06-18 15:58:53 +00:00
2019-03-14 19:00:39 +00:00
return tensorrt_home
2019-10-15 13:13:07 +00:00
def setup_dml_build ( args , cmake_path , build_dir , configs ) :
if ( args . use_dml ) :
for config in configs :
# Run the RESTORE_PACKAGES target to perform the initial NuGet setup
cmd_args = [ cmake_path ,
" --build " , get_config_build_dir ( build_dir , config ) ,
" --config " , config ,
" --target " , " RESTORE_PACKAGES " ]
run_subprocess ( cmd_args )
2019-07-24 20:20:05 +00:00
def adb_push ( source_dir , src , dest , * * kwargs ) :
return run_subprocess ( [ os . path . join ( source_dir , ' tools ' , ' ci_build ' , ' github ' , ' android ' , ' adb-push.sh ' ) , src , dest ] , * * kwargs )
def adb_shell ( * args , * * kwargs ) :
return run_subprocess ( [ ' adb ' , ' shell ' , * args ] , * * kwargs )
2019-10-05 00:39:51 +00:00
def run_onnxruntime_tests ( args , source_dir , ctest_path , build_dir , configs , enable_python_tests , enable_tvm = False , enable_tensorrt = False , enable_ngraph = False , enable_nnapi = False ) :
2018-11-20 00:48:22 +00:00
for config in configs :
log . info ( " Running tests for %s configuration " , config )
cwd = get_config_build_dir ( build_dir , config )
2019-07-24 20:20:05 +00:00
android_x86_64 = args . android_abi == ' x86_64 '
if android_x86_64 :
run_subprocess ( os . path . join ( source_dir , ' tools ' , ' ci_build ' , ' github ' , ' android ' , ' start_android_emulator.sh ' ) )
adb_push ( source_dir , ' testdata ' , ' /data/local/tmp/ ' , cwd = cwd )
adb_push ( source_dir , os . path . join ( source_dir , ' cmake ' , ' external ' , ' onnx ' , ' onnx ' , ' backend ' , ' test ' ) , ' /data/local/tmp/ ' , cwd = cwd )
adb_push ( source_dir , ' onnxruntime_test_all ' , ' /data/local/tmp/ ' , cwd = cwd )
adb_push ( source_dir , ' onnx_test_runner ' , ' /data/local/tmp/ ' , cwd = cwd )
adb_shell ( ' cd /data/local/tmp && /data/local/tmp/onnxruntime_test_all ' )
if args . use_dnnlibrary :
adb_shell ( ' cd /data/local/tmp && /data/local/tmp/onnx_test_runner -e nnapi /data/local/tmp/test ' )
else :
adb_shell ( ' cd /data/local/tmp && /data/local/tmp/onnx_test_runner /data/local/tmp/test ' )
continue
2019-04-08 20:18:36 +00:00
if enable_tvm :
dll_path = os . path . join ( build_dir , config , " external " , " tvm " , config )
elif enable_tensorrt :
dll_path = os . path . join ( args . tensorrt_home , ' lib ' )
else :
dll_path = None
2018-11-20 00:48:22 +00:00
run_subprocess ( [ ctest_path , " --build-config " , config , " --verbose " ] ,
cwd = cwd , dll_path = dll_path )
if enable_python_tests :
2019-03-15 05:25:16 +00:00
# Disable python tests for TensorRT because many tests are not supported yet
2019-04-24 17:35:26 +00:00
if enable_tensorrt :
2019-03-15 05:25:16 +00:00
return
2018-11-20 00:48:22 +00:00
if is_windows ( ) :
cwd = os . path . join ( cwd , config )
2019-11-27 21:03:23 +00:00
2018-11-20 00:48:22 +00:00
run_subprocess ( [ sys . executable , ' onnxruntime_test_python.py ' ] , cwd = cwd , dll_path = dll_path )
2019-11-27 21:03:23 +00:00
2018-11-20 00:48:22 +00:00
try :
import onnx
2019-11-27 21:03:23 +00:00
import scipy # gen_test_models.py used by onnx_test has a dependency on scipy
2018-11-20 00:48:22 +00:00
onnx_test = True
2019-11-27 21:03:23 +00:00
except ImportError as error :
log . exception ( error )
log . warning ( " onnx or scipy is not installed. The ONNX tests will be skipped. " )
2018-11-20 00:48:22 +00:00
onnx_test = False
2019-11-27 21:03:23 +00:00
2018-11-20 00:48:22 +00:00
if onnx_test :
run_subprocess ( [ sys . executable , ' onnxruntime_test_python_backend.py ' ] , cwd = cwd , dll_path = dll_path )
2019-11-27 21:03:23 +00:00
run_subprocess ( [ sys . executable , os . path . join ( source_dir , ' onnxruntime ' , ' test ' , ' onnx ' , ' gen_test_models.py ' ) ,
' --output_dir ' , ' test_models ' ] , cwd = cwd )
2018-11-20 00:48:22 +00:00
run_subprocess ( [ os . path . join ( cwd , ' onnx_test_runner ' ) , ' test_models ' ] , cwd = cwd )
2018-12-13 00:25:16 +00:00
if config != ' Debug ' :
run_subprocess ( [ sys . executable , ' onnx_backend_test_series.py ' ] , cwd = cwd , dll_path = dll_path )
2019-11-27 21:03:23 +00:00
2019-03-13 09:55:56 +00:00
if not args . skip_keras_test :
try :
import onnxmltools
import keras
onnxml_test = True
except ImportError :
2019-11-27 21:03:23 +00:00
log . warning ( " onnxmltools and keras are not installed. The keras tests will be skipped. " )
2019-03-13 09:55:56 +00:00
onnxml_test = False
if onnxml_test :
run_subprocess ( [ sys . executable , ' onnxruntime_test_python_keras.py ' ] , cwd = cwd , dll_path = dll_path )
2018-11-20 00:48:22 +00:00
2019-11-22 20:14:03 +00:00
def run_onnx_tests ( build_dir , configs , onnx_test_data_dir , provider , enable_multi_device_test , enable_parallel_executor_test , num_parallel_models , num_parallel_tests = 0 ) :
2018-11-20 00:48:22 +00:00
for config in configs :
cwd = get_config_build_dir ( build_dir , config )
if is_windows ( ) :
exe = os . path . join ( cwd , config , ' onnx_test_runner ' )
model_dir = os . path . join ( cwd , " models " )
else :
exe = os . path . join ( cwd , ' onnx_test_runner ' )
model_dir = os . path . join ( build_dir , " models " )
2018-12-12 23:52:36 +00:00
cmd = [ ]
2018-11-20 00:48:22 +00:00
if provider :
cmd + = [ " -e " , provider ]
2019-11-22 20:14:03 +00:00
if num_parallel_tests != 0 :
cmd + = [ ' -c ' , str ( num_parallel_tests ) ]
2019-03-06 02:12:02 +00:00
if num_parallel_models > 0 :
cmd + = [ " -j " , str ( num_parallel_models ) ]
2019-10-14 18:16:34 +00:00
if enable_multi_device_test :
cmd + = [ ' -d ' , ' 1 ' ]
2018-11-20 00:48:22 +00:00
if config != ' Debug ' and os . path . exists ( model_dir ) :
2019-10-06 17:40:53 +00:00
# some models in opset9 and above are not supported by TensorRT yet
2019-03-14 19:00:39 +00:00
if provider == ' tensorrt ' :
model_dir = os . path . join ( model_dir , " opset8 " )
2018-11-20 00:48:22 +00:00
cmd . append ( model_dir )
if os . path . exists ( onnx_test_data_dir ) :
cmd . append ( onnx_test_data_dir )
2019-03-21 21:06:38 +00:00
2019-09-02 06:01:47 +00:00
if config == ' Debug ' and provider == ' nuphar ' :
return
2019-04-23 20:24:24 +00:00
run_subprocess ( [ exe ] + cmd , cwd = cwd )
2018-12-12 23:52:36 +00:00
if enable_parallel_executor_test :
2019-04-23 20:24:24 +00:00
run_subprocess ( [ exe , ' -x ' ] + cmd , cwd = cwd )
2018-11-20 00:48:22 +00:00
2019-12-03 15:34:23 +00:00
# dnnl temporary function for running onnx tests and model tests separately.
def dnnl_run_onnx_tests ( build_dir , configs , onnx_test_data_dir ) :
2019-06-11 03:18:56 +00:00
for config in configs :
cwd = get_config_build_dir ( build_dir , config )
if is_windows ( ) :
exe = os . path . join ( cwd , config , ' onnx_test_runner ' )
model_dir = os . path . join ( cwd , " models " )
else :
exe = os . path . join ( cwd , ' onnx_test_runner ' )
model_dir = os . path . join ( build_dir , " models " )
2019-12-03 15:34:23 +00:00
cmd_base = [ ' -e ' , ' dnnl ' , ' -c ' , ' 1 ' , ' -j ' , ' 1 ' ]
2019-06-11 03:18:56 +00:00
if os . path . exists ( onnx_test_data_dir ) :
onnxdata_cmd = cmd_base + [ onnx_test_data_dir ]
# /data/onnx
run_subprocess ( [ exe ] + onnxdata_cmd , cwd = cwd )
run_subprocess ( [ exe , ' -x ' ] + onnxdata_cmd , cwd = cwd )
2019-11-22 20:14:03 +00:00
2019-06-11 03:18:56 +00:00
if config != ' Debug ' and os . path . exists ( model_dir ) :
opset7_model_dir = os . path . join ( model_dir , ' opset7 ' )
opset7_cmd = cmd_base + [ opset7_model_dir ]
opset8_model_dir = os . path . join ( model_dir , ' opset8 ' )
opset8_cmd = cmd_base + [ opset8_model_dir ]
opset9_model_dir = os . path . join ( model_dir , ' opset9 ' )
opset9_cmd = cmd_base + [ opset9_model_dir ]
2019-11-22 20:14:03 +00:00
opset10_model_dir = os . path . join ( model_dir , ' opset10 ' )
opset10_cmd = cmd_base + [ opset10_model_dir ]
2019-06-11 03:18:56 +00:00
run_subprocess ( [ exe ] + opset7_cmd , cwd = cwd )
run_subprocess ( [ exe , ' -x ' ] + opset7_cmd , cwd = cwd )
run_subprocess ( [ exe ] + opset8_cmd , cwd = cwd )
run_subprocess ( [ exe , ' -x ' ] + opset8_cmd , cwd = cwd )
run_subprocess ( [ exe ] + opset9_cmd , cwd = cwd )
run_subprocess ( [ exe , ' -x ' ] + opset9_cmd , cwd = cwd )
2019-11-22 20:14:03 +00:00
run_subprocess ( [ exe ] + opset10_cmd , cwd = cwd )
run_subprocess ( [ exe , ' -x ' ] + opset10_cmd , cwd = cwd )
2019-06-11 03:18:56 +00:00
2019-09-02 06:01:47 +00:00
# nuphar temporary function for running python tests separately as it requires ONNX 1.5.0
2019-11-22 20:14:03 +00:00
def nuphar_run_python_tests ( build_dir , configs ) :
2019-09-02 06:01:47 +00:00
for config in configs :
if config == ' Debug ' :
continue
cwd = get_config_build_dir ( build_dir , config )
if is_windows ( ) :
cwd = os . path . join ( cwd , config )
dll_path = os . path . join ( build_dir , config , " external " , " tvm " , config )
# install onnx for shape inference in testing Nuphar scripts
# this needs to happen after onnx_test_data preparation which uses onnx 1.3.0
run_subprocess ( [ sys . executable , ' -m ' , ' pip ' , ' install ' , ' --user ' , ' onnx==1.5.0 ' ] )
run_subprocess ( [ sys . executable , ' onnxruntime_test_python_nuphar.py ' ] , cwd = cwd , dll_path = dll_path )
2019-05-30 00:46:07 +00:00
def split_server_binary_and_symbol ( build_dir , configs ) :
if is_windows ( ) :
# TODO: Windows support
pass
else :
for config in configs :
if config == ' RelWithDebInfo ' :
config_build_dir = get_config_build_dir ( build_dir , config )
run_subprocess ( [ ' objcopy ' , ' --only-keep-debug ' , ' onnxruntime_server ' , ' onnxruntime_server.symbol ' ] , cwd = config_build_dir )
run_subprocess ( [ ' strip ' , ' --strip-debug ' , ' --strip-unneeded ' , ' onnxruntime_server ' ] , cwd = config_build_dir )
run_subprocess ( [ ' objcopy ' , ' --add-gnu-debuglink=onnxruntime_server.symbol ' , ' onnxruntime_server ' ] , cwd = config_build_dir )
2019-07-04 08:08:14 +00:00
libonnx = glob . glob ( os . path . join ( config_build_dir , " libonnxruntime.so.* " ) )
if len ( libonnx ) != 1 :
raise ValueError ( " Too many libonxruntime.so.* " )
libonnx = libonnx [ 0 ]
run_subprocess ( [ ' objcopy ' , ' --only-keep-debug ' , libonnx , libonnx + ' .symbol ' ] , cwd = config_build_dir )
run_subprocess ( [ ' strip ' , ' --strip-debug ' , libonnx ] , cwd = config_build_dir )
run_subprocess ( [ ' objcopy ' , ' --add-gnu-debuglink= {} .symbol ' . format ( libonnx ) , libonnx ] , cwd = config_build_dir )
2019-06-18 15:58:53 +00:00
2019-05-30 00:46:07 +00:00
2019-05-01 01:21:23 +00:00
def run_server_tests ( build_dir , configs ) :
2019-05-08 18:37:39 +00:00
pip_freeze_result = run_subprocess ( [ sys . executable , ' -m ' , ' pip ' , ' freeze ' ] , capture = True ) . stdout
installed_packages = [ r . decode ( ) . split ( ' == ' ) [ 0 ] for r in pip_freeze_result . split ( ) ]
2019-07-18 18:10:38 +00:00
if not ( ( ' requests ' in installed_packages ) and ( ' protobuf ' in installed_packages ) and ( ' numpy ' in installed_packages ) and ( ' grpcio ' in installed_packages ) ) :
2019-05-08 18:37:39 +00:00
if hasattr ( sys , ' real_prefix ' ) :
# In virtualenv
2019-07-18 18:10:38 +00:00
run_subprocess ( [ sys . executable , ' -m ' , ' pip ' , ' install ' , ' --trusted-host ' , ' files.pythonhosted.org ' , ' requests ' , ' protobuf ' , ' numpy ' , ' grpcio ' ] )
2019-05-08 18:37:39 +00:00
else :
# Outside virtualenv
2019-07-18 18:10:38 +00:00
run_subprocess ( [ sys . executable , ' -m ' , ' pip ' , ' install ' , ' --user ' , ' --trusted-host ' , ' files.pythonhosted.org ' , ' requests ' , ' protobuf ' , ' numpy ' , ' grpcio ' ] )
2019-05-01 01:21:23 +00:00
for config in configs :
config_build_dir = get_config_build_dir ( build_dir , config )
if is_windows ( ) :
server_app_path = os . path . join ( config_build_dir , config , ' onnxruntime_server.exe ' )
2019-05-21 01:40:52 +00:00
python_package_path = os . path . join ( config_build_dir , config )
2019-05-01 01:21:23 +00:00
else :
server_app_path = os . path . join ( config_build_dir , ' onnxruntime_server ' )
2019-05-21 01:40:52 +00:00
python_package_path = config_build_dir
2019-05-01 01:21:23 +00:00
server_test_folder = os . path . join ( config_build_dir , ' server_test ' )
2019-10-23 20:48:20 +00:00
server_test_model_folder = os . path . join ( build_dir , ' models ' , ' opset8 ' , ' test_mnist ' )
server_test_data_folder = os . path . join ( config_build_dir , ' testdata ' , ' server ' )
run_subprocess ( [ sys . executable , ' test_main.py ' , server_app_path , server_test_model_folder , server_test_data_folder , python_package_path , server_test_folder ] , cwd = server_test_folder , dll_path = None )
2019-05-01 01:21:23 +00:00
2019-05-14 06:08:51 +00:00
def run_server_model_tests ( build_dir , configs ) :
for config in configs :
config_build_dir = get_config_build_dir ( build_dir , config )
2019-05-21 01:40:52 +00:00
server_test_folder = os . path . join ( config_build_dir , ' server_test ' )
server_test_data_folder = os . path . join ( config_build_dir , ' server_test_data ' )
2019-06-18 15:58:53 +00:00
2019-05-14 06:08:51 +00:00
if is_windows ( ) :
server_app_path = os . path . join ( config_build_dir , config , ' onnxruntime_server.exe ' )
test_raw_data_folder = os . path . join ( config_build_dir , ' models ' )
2019-05-21 01:40:52 +00:00
python_package_path = os . path . join ( config_build_dir , config )
2019-05-14 06:08:51 +00:00
else :
server_app_path = os . path . join ( config_build_dir , ' onnxruntime_server ' )
test_raw_data_folder = os . path . join ( build_dir , ' models ' )
2019-05-21 01:40:52 +00:00
python_package_path = config_build_dir
2019-06-18 15:58:53 +00:00
2019-05-21 01:40:52 +00:00
run_subprocess ( [ sys . executable , ' model_zoo_data_prep.py ' , test_raw_data_folder , server_test_data_folder , python_package_path , server_test_folder ] , cwd = server_test_folder , dll_path = None )
run_subprocess ( [ sys . executable , ' model_zoo_tests.py ' , server_app_path , test_raw_data_folder , server_test_data_folder , python_package_path , server_test_folder ] , cwd = server_test_folder , dll_path = None )
2019-05-14 06:08:51 +00:00
2019-09-05 15:50:48 +00:00
def build_python_wheel ( source_dir , build_dir , configs , use_cuda , use_ngraph , use_tensorrt , use_openvino , use_nuphar , nightly_build = False ) :
2018-11-20 00:48:22 +00:00
for config in configs :
cwd = get_config_build_dir ( build_dir , config )
if is_windows ( ) :
cwd = os . path . join ( cwd , config )
2019-06-27 22:45:06 +00:00
args = [ sys . executable , os . path . join ( source_dir , ' setup.py ' ) , ' bdist_wheel ' ]
2019-04-12 05:06:18 +00:00
if nightly_build :
2019-06-27 22:45:06 +00:00
args . append ( ' --nightly_build ' )
if use_tensorrt :
args . append ( ' --use_tensorrt ' )
elif use_cuda :
args . append ( ' --use_cuda ' )
elif use_ngraph :
args . append ( ' --use_ngraph ' )
elif use_openvino :
args . append ( ' --use_openvino ' )
2019-09-05 15:50:48 +00:00
elif use_nuphar :
args . append ( ' --use_nuphar ' )
2019-06-27 22:45:06 +00:00
run_subprocess ( args , cwd = cwd )
2018-11-20 00:48:22 +00:00
2019-07-24 20:20:05 +00:00
def build_protoc_for_host ( cmake_path , source_dir , build_dir , args ) :
if ( args . arm or args . arm64 ) and not is_windows ( ) :
2019-03-09 01:42:20 +00:00
raise BuildError ( ' Currently only support building protoc for Windows host while cross-compiling for ARM/ARM64 arch ' )
log . info ( " Building protoc for host to be used in cross-compiled build process " )
2019-07-24 20:20:05 +00:00
protoc_build_dir = os . path . join ( os . getcwd ( ) , build_dir , ' host_protoc ' )
2019-03-09 01:42:20 +00:00
os . makedirs ( protoc_build_dir , exist_ok = True )
# Generate step
cmd_args = [ cmake_path ,
2019-07-24 20:20:05 +00:00
os . path . join ( source_dir , ' cmake ' , ' external ' , ' protobuf ' , ' cmake ' ) ,
2019-03-09 01:42:20 +00:00
' -Dprotobuf_BUILD_TESTS=OFF ' ,
' -Dprotobuf_WITH_ZLIB_DEFAULT=OFF ' ,
' -Dprotobuf_BUILD_SHARED_LIBS=OFF ' ]
2019-07-24 20:20:05 +00:00
if is_windows ( ) :
cmd_args + = [ ' -T ' ,
' host=x64 ' ,
' -G ' ,
args . cmake_generator ]
2019-03-09 01:42:20 +00:00
run_subprocess ( cmd_args , cwd = protoc_build_dir )
# Build step
cmd_args = [ cmake_path ,
" --build " , protoc_build_dir ,
" --config " , " Release " ,
" --target " , " protoc " ]
run_subprocess ( cmd_args )
2019-07-24 20:20:05 +00:00
# Absolute protoc path is needed for cmake
expected_protoc_path = os . path . join ( protoc_build_dir , ' Release ' , ' protoc.exe ' ) if is_windows ( ) else os . path . join ( protoc_build_dir , ' protoc ' )
if not os . path . exists ( expected_protoc_path ) :
raise BuildError ( " Couldn ' t build protoc for host. Failing build. " )
return expected_protoc_path
2019-03-09 01:42:20 +00:00
2019-03-27 04:58:01 +00:00
def generate_documentation ( source_dir , build_dir , configs ) :
operator_doc_path = os . path . join ( source_dir , ' docs ' , ' ContribOperators.md ' )
2019-08-15 01:12:24 +00:00
opkernel_doc_path = os . path . join ( source_dir , ' docs ' , ' OperatorKernels.md ' )
2019-03-27 04:58:01 +00:00
for config in configs :
#copy the gen_doc.py
2019-05-01 21:58:21 +00:00
shutil . copy ( os . path . join ( source_dir , ' tools ' , ' python ' , ' gen_doc.py ' ) ,
2019-03-27 04:58:01 +00:00
os . path . join ( build_dir , config , config ) )
2019-08-15 01:12:24 +00:00
shutil . copy ( os . path . join ( source_dir , ' tools ' , ' python ' , ' gen_opkernel_doc.py ' ) ,
os . path . join ( build_dir , config , config ) )
2019-03-27 04:58:01 +00:00
run_subprocess ( [
sys . executable ,
' gen_doc.py ' ,
' --output_path ' , operator_doc_path
2019-06-18 15:58:53 +00:00
] ,
2019-03-27 04:58:01 +00:00
cwd = os . path . join ( build_dir , config , config ) )
2019-08-15 01:12:24 +00:00
run_subprocess ( [
sys . executable ,
' gen_opkernel_doc.py ' ,
' --output_path ' , opkernel_doc_path
] ,
cwd = os . path . join ( build_dir , config , config ) )
2019-05-01 21:58:21 +00:00
docdiff = ' '
2019-06-18 15:58:53 +00:00
try :
2019-08-15 01:12:24 +00:00
docdiff = subprocess . check_output ( [ ' git ' , ' diff ' , opkernel_doc_path ] )
2019-05-01 21:58:21 +00:00
except subprocess . CalledProcessError :
print ( ' git diff returned non-zero error code ' )
2019-08-15 01:12:24 +00:00
if len ( docdiff ) > 0 :
2019-09-27 01:32:16 +00:00
# Show warning instead of throwing exception, because it is dependent on build configuration for including execution propviders
2019-12-03 15:34:23 +00:00
log . warning ( ' The updated opkernel document file ' + str ( opkernel_doc_path ) + ' is different from the checked in version. Consider regenrating the file with CPU, DNNL and CUDA providers enabled. ' )
2019-08-15 01:12:24 +00:00
log . debug ( ' diff: \n ' + str ( docdiff ) )
2019-06-18 15:58:53 +00:00
2019-08-15 01:12:24 +00:00
docdiff = ' '
try :
docdiff = subprocess . check_output ( [ ' git ' , ' diff ' , operator_doc_path ] )
except subprocess . CalledProcessError :
print ( ' git diff returned non-zero error code ' )
2019-03-27 04:58:01 +00:00
if len ( docdiff ) > 0 :
2019-05-03 02:21:41 +00:00
raise BuildError ( ' The updated operator document file ' + str ( operator_doc_path ) + ' must be checked in. \n diff: \n ' + str ( docdiff ) )
2019-05-01 21:58:21 +00:00
2019-03-27 04:58:01 +00:00
2018-11-20 00:48:22 +00:00
def main ( ) :
args = parse_arguments ( )
cmake_extra_defines = args . cmake_extra_defines if args . cmake_extra_defines else [ ]
2019-07-24 20:20:05 +00:00
cross_compiling = args . arm or args . arm64 or args . android
2019-03-09 01:42:20 +00:00
# if there was no explicit argument saying what to do, default to update, build and test (for native builds).
2018-11-20 00:48:22 +00:00
if ( args . update == False and args . clean == False and args . build == False and args . test == False ) :
2019-03-09 01:42:20 +00:00
log . debug ( " Defaulting to running update, build [and test for native builds]. " )
2018-11-20 00:48:22 +00:00
args . update = True
args . build = True
2019-07-24 20:20:05 +00:00
if cross_compiling :
args . test = args . android_abi == ' x86_64 '
2019-03-09 01:42:20 +00:00
else :
args . test = True
2018-11-20 00:48:22 +00:00
2019-11-27 21:03:23 +00:00
if args . skip_tests :
args . test = False
2019-03-14 19:00:39 +00:00
if args . use_tensorrt :
args . use_cuda = True
2019-05-21 01:40:52 +00:00
if args . build_wheel or args . enable_server_model_tests :
2018-11-20 00:48:22 +00:00
args . enable_pybind = True
2019-03-21 21:06:38 +00:00
2019-01-10 01:06:56 +00:00
if args . build_csharp :
args . build_shared_lib = True
2018-11-20 00:48:22 +00:00
2019-09-27 01:32:16 +00:00
# Disabling unit tests for VAD-F as FPGA only supports models with NCHW layout
if args . use_openvino == " VAD-F_FP32 " :
args . test = False
2018-11-20 00:48:22 +00:00
configs = set ( args . config )
# setup paths and directories
2018-12-18 21:23:32 +00:00
cmake_path = resolve_executable_path ( args . cmake_path )
ctest_path = resolve_executable_path ( args . ctest_path )
2018-11-20 00:48:22 +00:00
build_dir = args . build_dir
script_dir = os . path . realpath ( os . path . dirname ( __file__ ) )
source_dir = os . path . normpath ( os . path . join ( script_dir , " .. " , " .. " ) )
# if using cuda, setup cuda paths and env vars
cuda_home , cudnn_home = setup_cuda_vars ( args )
2019-03-14 19:00:39 +00:00
# if using tensorrt, setup tensorrt paths
tensorrt_home = setup_tensorrt_vars ( args )
2018-11-20 00:48:22 +00:00
os . makedirs ( build_dir , exist_ok = True )
log . info ( " Build started " )
if ( args . update ) :
2019-01-15 18:29:00 +00:00
cmake_extra_args = [ ]
2019-07-24 20:20:05 +00:00
path_to_protoc_exe = None
2019-01-15 18:29:00 +00:00
if ( is_windows ( ) ) :
if ( args . x86 ) :
2019-07-18 18:43:11 +00:00
cmake_extra_args = [ ' -A ' , ' Win32 ' , ' -T ' , ' host=x64 ' , ' -G ' , args . cmake_generator ]
2019-03-09 01:42:20 +00:00
elif ( args . arm or args . arm64 ) :
# Cross-compiling for ARM(64) architecture
# First build protoc for host to use during cross-compilation
2019-07-24 20:20:05 +00:00
path_to_protoc_exe = build_protoc_for_host ( cmake_path , source_dir , build_dir , args )
2019-03-09 01:42:20 +00:00
if args . arm :
cmake_extra_args = [ ' -A ' , ' ARM ' ]
else :
cmake_extra_args = [ ' -A ' , ' ARM64 ' ]
2019-07-18 18:43:11 +00:00
cmake_extra_args + = [ ' -G ' , args . cmake_generator ]
2019-03-09 01:42:20 +00:00
# Cannot test on host build machine for cross-compiled builds (Override any user-defined behaviour for test if any)
if args . test :
log . info ( " Cannot test on host build machine for cross-compiled ARM(64) builds. Will skip test running after build. " )
args . test = False
2019-01-15 18:29:00 +00:00
else :
toolset = ' host=x64 '
if ( args . msvc_toolset ) :
toolset + = ' ,version= ' + args . msvc_toolset
2019-01-23 02:06:14 +00:00
if ( args . cuda_version ) :
toolset + = ' ,cuda= ' + args . cuda_version
2019-01-15 18:29:00 +00:00
2019-07-18 18:43:11 +00:00
cmake_extra_args = [ ' -A ' , ' x64 ' , ' -T ' , toolset , ' -G ' , args . cmake_generator ]
2019-07-24 20:20:05 +00:00
if args . android :
# Cross-compiling for Android
path_to_protoc_exe = build_protoc_for_host ( cmake_path , source_dir , build_dir , args )
2018-11-20 00:48:22 +00:00
if is_ubuntu_1604 ( ) :
2019-03-09 01:42:20 +00:00
if ( args . arm or args . arm64 ) :
raise BuildError ( " Only Windows ARM(64) cross-compiled builds supported currently through this script " )
2018-11-20 00:48:22 +00:00
install_ubuntu_deps ( args )
2019-02-12 05:29:36 +00:00
if not is_docker ( ) :
install_python_deps ( )
2018-11-20 00:48:22 +00:00
if ( args . enable_pybind and is_windows ( ) ) :
2019-03-13 09:55:56 +00:00
install_python_deps ( args . numpy_version )
2018-11-20 00:48:22 +00:00
if ( not args . skip_submodule_sync ) :
update_submodules ( source_dir )
2019-11-22 20:14:03 +00:00
if args . enable_onnx_tests :
setup_test_data ( build_dir , configs )
2019-01-10 06:33:14 +00:00
2019-03-09 01:42:20 +00:00
if args . path_to_protoc_exe :
path_to_protoc_exe = args . path_to_protoc_exe
2019-03-23 00:41:21 +00:00
generate_build_tree ( cmake_path , source_dir , build_dir , cuda_home , cudnn_home , tensorrt_home , path_to_protoc_exe , configs , cmake_extra_defines ,
2018-11-20 00:48:22 +00:00
args , cmake_extra_args )
if ( args . clean ) :
clean_targets ( cmake_path , build_dir , configs )
2019-10-15 13:13:07 +00:00
# if using DML, perform initial nuget package restore
setup_dml_build ( args , cmake_path , build_dir , configs )
2018-11-20 00:48:22 +00:00
if ( args . build ) :
build_targets ( cmake_path , build_dir , configs , args . parallel )
2019-04-12 05:06:18 +00:00
if args . test :
run_onnxruntime_tests ( args , source_dir , ctest_path , build_dir , configs ,
2019-05-16 01:30:18 +00:00
args . enable_pybind and not args . skip_onnx_tests ,
2019-10-05 00:39:51 +00:00
args . use_tvm , args . use_tensorrt , args . use_ngraph ,
args . use_dnnlibrary )
2019-01-15 18:29:00 +00:00
# run the onnx model tests if requested explicitly.
2019-04-12 05:06:18 +00:00
if args . enable_onnx_tests and not args . skip_onnx_tests :
2019-01-15 18:29:00 +00:00
# directory from ONNX submodule with ONNX test data
onnx_test_data_dir = ' /data/onnx '
if is_windows ( ) or not os . path . exists ( onnx_test_data_dir ) :
onnx_test_data_dir = os . path . join ( source_dir , " cmake " , " external " , " onnx " , " onnx " , " backend " , " test " , " data " )
2019-06-18 15:58:53 +00:00
2019-03-14 19:00:39 +00:00
if args . use_tensorrt :
2019-10-06 17:40:53 +00:00
# Disable some onnx unit tests that TensorRT doesn't supported yet
if not is_windows ( ) :
onnx_test_data_dir = os . path . join ( source_dir , " cmake " , " external " , " onnx " , " onnx " , " backend " , " test " , " data " , " simple " )
2019-10-14 18:16:34 +00:00
run_onnx_tests ( build_dir , configs , onnx_test_data_dir , ' tensorrt ' , args . enable_multi_device_test , False , 1 )
2019-11-22 20:14:03 +00:00
if args . use_cuda :
run_onnx_tests ( build_dir , configs , onnx_test_data_dir , ' cuda ' , args . enable_multi_device_test , False , 2 )
if args . use_ngraph :
2019-10-14 18:16:34 +00:00
run_onnx_tests ( build_dir , configs , onnx_test_data_dir , ' ngraph ' , args . enable_multi_device_test , True , 1 )
2019-11-22 20:14:03 +00:00
if args . use_openvino :
run_onnx_tests ( build_dir , configs , onnx_test_data_dir , ' openvino ' , args . enable_multi_device_test , False , 1 , 1 )
2019-03-06 22:56:53 +00:00
# TODO: parallel executor test fails on MacOS
2019-11-22 20:14:03 +00:00
if args . use_nuphar :
run_onnx_tests ( build_dir , configs , onnx_test_data_dir , ' nuphar ' , args . enable_multi_device_test , False , 1 , 1 )
2019-03-06 02:12:02 +00:00
2019-10-15 13:13:07 +00:00
if args . use_dml :
2019-11-22 20:14:03 +00:00
run_onnx_tests ( build_dir , configs , onnx_test_data_dir , ' dml ' , args . enable_multi_device_test , False , 1 )
2019-12-03 15:34:23 +00:00
# Run some models are disabled to keep memory utilization under control
if args . use_dnnl :
dnnl_run_onnx_tests ( build_dir , configs , onnx_test_data_dir )
2019-10-15 13:13:07 +00:00
2019-11-22 20:14:03 +00:00
run_onnx_tests ( build_dir , configs , onnx_test_data_dir , None , args . enable_multi_device_test , False ,
1 if args . x86 or platform . system ( ) == ' Darwin ' else 0 ,
1 if args . x86 or platform . system ( ) == ' Darwin ' else 0 )
2018-11-20 00:48:22 +00:00
2019-09-02 06:01:47 +00:00
# run nuphar python tests last, as it installs ONNX 1.5.0
2019-09-05 15:50:48 +00:00
if args . enable_pybind and not args . skip_onnx_tests and args . use_nuphar :
2019-11-22 20:14:03 +00:00
nuphar_run_python_tests ( build_dir , configs )
2019-09-02 06:01:47 +00:00
2019-05-30 00:46:07 +00:00
if args . build_server :
split_server_binary_and_symbol ( build_dir , configs )
if args . enable_server_tests :
run_server_tests ( build_dir , configs )
if args . enable_server_model_tests :
run_server_model_tests ( build_dir , configs )
2019-05-14 06:08:51 +00:00
2019-01-15 18:29:00 +00:00
if args . build :
if args . build_wheel :
2019-04-12 05:06:18 +00:00
nightly_build = bool ( os . getenv ( ' NIGHTLY_BUILD ' ) == ' 1 ' )
2019-09-05 15:50:48 +00:00
build_python_wheel ( source_dir , build_dir , configs , args . use_cuda , args . use_ngraph , args . use_tensorrt , args . use_openvino , args . use_nuphar , nightly_build )
2019-04-21 00:02:35 +00:00
2019-05-01 21:58:21 +00:00
if args . gen_doc and ( args . build or args . test ) :
2019-03-27 04:58:01 +00:00
generate_documentation ( source_dir , build_dir , configs )
2018-11-20 00:48:22 +00:00
log . info ( " Build complete " )
if __name__ == " __main__ " :
2018-12-18 21:23:32 +00:00
try :
sys . exit ( main ( ) )
2019-01-10 06:33:14 +00:00
except BaseError as e :
2018-12-18 21:23:32 +00:00
log . error ( str ( e ) )
sys . exit ( 1 )