#!/bin/bash # # Copyright (c) Microsoft. All rights reserved. # # Licensed under the MIT license. See LICENSE.md file in the project root # for full license information. # ============================================================================== # # TODO --math-library support on Windows # Setting some default values BUILD=1 RUN=1 CLEAN_AFTER=0 CLEAN_BEFORE=0 RANDOM_OUTPUT=0 CODE_COVERAGE=no FLAVORS="debug:release" TARGETS="cpu:gpu" MATH_LIBRARY="mkl" TESTTARGETS="cpu:gpu" EXTRA_CONFIGURE_OPTIONS= # parsing command line arguments: while [[ $# > 0 ]] do key="$1" case $key in -h|--help) echo "Usage: build-and-test [options]" echo "Options:" echo " -q|--quiet-build - redirect build output to file" echo " -r|--run-only - elides build step, runs the binaries that have already been built" echo " -b|--build-only - just build, do not run" echo " -f|--flavors - which flavor to build (by default $FLAVORS)" echo " -t|--targets - which target to build (by default $TARGETS)" echo " -m|--math-library - which math library to build with (by default $MATH_LIBRARY)" echo " -tt|--test-targets - which target to test (by default $TESTTARGETS)" echo " -cc|--code-coverage - build with support for code coverage (gcov)" echo " -cb|--clean-build - clean up the enlistment binaries before build" echo " -cba|--clean-build-after - clean up the enlistment binaries after build" echo " -rnd|--random-output-suffix - add random suffix to output directory" echo " -o|--output-directory - specify output directory to use (by default those will be in .run-)" echo " -x|--extra-configure-options - extra options to pass to configure" echo "The root directory used to build and run CNTK is hosts the Scripts directory that contains this script" exit 1 ;; -q|--quiet) QUIET_BUILD=1 ;; -r|--run-only) BUILD=0 RUN=1 ;; -rnd|--random-output-suffix) RANDOM_OUTPUT=1 ;; -b|--build-only) BUILD=1 RUN=0 ;; -cb|--clean-build) CLEAN_BEFORE=1 BUILD=1 ;; -cba|--clean-build-after) CLEAN_AFTER=1 BUILD=1 ;; -f|--flavors) FLAVORS="${2,,}" shift # past argument ;; -t|--targets) TARGETS="${2,,}" shift # past argument ;; -m|--math-library) case ${2,,} in mkl) MATH_LIBRARY_OPTION="--with-mkl=$MKL_PATH" ;; mkl-sequential) MATH_LIBRARY_OPTION="--with-mkl-sequential=$MKL_PATH" ;; *) echo Unknown math library $MATH_LIBRARY exit 1 ;; esac shift # past argument ;; -tt|--test-targets) TESTTARGETS="${2,,}" shift # past argument ;; -cc|--code-coverage) CODE_COVERAGE=yes ;; -x|--extra-configure-options) EXTRA_CONFIGURE_OPTIONS="$2" shift # past argument ;; -o|--output-directory) OUTPUT_DIR="$2" shift # past argument ;; *) echo Unknown option $key exit 1 ;; esac shift # past argument or value done # Step 0 -- Validate all necessary prerequisites and check for incompatible options # It is possible to use this script on Windows to build CNTK # from Cygwin window with Visual C++ environment loaded. # In that case OS environment variable will be set and we # can use it to differentiate from Linux. if [[ $CLEAN_BEFORE == 1 && $RUN == 1 && $BUILD == 0 ]]; then echo "============ ERROR: Incompatible options RUN and CLEAN_BEFORE set without BUILD ============" exit 1 fi if [[ $OS == "Windows_NT" && $OSTYPE == "cygwin" ]]; then DEBUG_DIR=Debug RELEASE_DIR=Release PREFIX_DIR=x64 BIN_NAME=CNTK.exe BUILD_OS="windows" if [[ $VS120COMNTOOLS == "" ]]; then echo "============ Visual Studio 12.0 environment not properly setup or VS not installed ============" echo "============ Please find and run the appropriate vcvarsall.bat script ============" exit 1 fi if [[ "${TARGETS,,}" =~ "1bitsgd" && "${TARGETS,,}" =~ "gpu" ]]; then echo "============ Cannot specify both GPU and 1bit-SGD as targets, please choose one ============" exit 1 fi elif [[ $OSTYPE == "linux-gnu" ]]; then DEBUG_DIR=build/$TARGET/debug RELEASE_DIR=build/$TARGET/release PREFIX_DIR= # Make sure no dependencies on current directory BIN_NAME=bin/cntk MAKEFILE=Makefile BUILD_OS="linux" else echo "============ ERROR: Unsupported OS ============" echo "============ Script supports only building from Linux and Windows through Cygwin ============" exit 1 fi # Step 1 -- Prepare temporary folders and files, tweak settings if necessary # Get to the root path from which we know how to build and run SCRIPT=`readlink -f $0` SCRIPT_DIR=`dirname $SCRIPT` CNTK_ROOT=`dirname $SCRIPT_DIR` # Setup the output directory if [[ $OUTPUT_DIR == "" ]]; then OUTPUT_DIR="$CNTK_ROOT/.run-$BUILD_OS" fi # Add random number at the end of the output directory to prevent overwriting previous results if [[ $RANDOM_OUTPUT == 1 ]]; then OUTPUT_DIR="$OUTPUT_DIR-$RANDOM" fi echo "============ Creating CNTK temp directory in $OUTPUT_DIR ============" mkdir -p $OUTPUT_DIR || exit $? CONF_FILE="$OUTPUT_DIR/OneHidden.cntk" BUILD_FILE="$OUTPUT_DIR/Build" RUN_FILE="$OUTPUT_DIR/Result" if ! [[ -d "$CNTK_ROOT/Source" ]]; then echo "============ ERROR: Build script located in the wrong directory ($SCRIPT_DIR) ============" exit 1 fi cd $CNTK_ROOT if ! [[ -f $CONF_FILE ]]; then cp Tests/EndToEndTests/Simple2d/OneHidden.cntk $CONF_FILE || exit $? # This chmod is necessary due to restrictive Cygwin interpretation of Windows permissions. # Cygwin interprets Windows permissions as ----rwx---, which lacks read permissions for user. chmod a+r $CONF_FILE || exit $? fi if [[ $QUIET_BUILD == 1 ]]; then echo "============ WARNING: You have selected quiet build. All build output will be placed in ($OUTPUT_DIR) ============" fi # Initialize lists of flavors and targets flavorArray=(${FLAVORS//:/ }) targetArray=(${TARGETS//:/ }) testTargetArray=(${TESTTARGETS//:/ }) # Step 2 -- Build the project for all requested flavors and targets if [[ $BUILD == 1 ]]; then for FLAVOR in "${flavorArray[@]}" do for TARGET in "${targetArray[@]}" do echo "============ Building CNTK $TARGET/$FLAVOR (clean=$CLEAN_BEFORE) ============" # Our make is too noisy right now and it is difficult to spot # issues from stdout and stderr. In the quiet mode these are # redirected to a file where they could be examined after the fact if [[ $QUIET_BUILD == 1 ]]; then exec 6>$BUILD_FILE.$FLAVOR.out || exit $? exec 7>$BUILD_FILE.$FLAVOR.err || exit $? else exec 6>&1 || exit $? exec 7>&2 || exit $? fi if [[ $OS == "Windows_NT" ]]; then OneBitSGDOPT=/property:CNTK_ENABLE_1BitSGD= if [[ $TARGET == "cpu" ]]; then CONFIGURATION=${FLAVOR}_CpuOnly else CONFIGURATION=${FLAVOR} if [[ $TARGET == "1bitsgd" ]]; then OneBitSGDOPT=/property:CNTK_ENABLE_1BitSGD=true fi fi if [[ $CLEAN_BEFORE == 1 ]]; then msbuild.exe /nologo /verbosity:m /property:Configuration=$CONFIGURATION /t:Clean 1>&6 2>&7 || exit $? fi msbuild.exe /nologo /verbosity:m /m /property:Configuration=$CONFIGURATION $OneBitSGDOPT 1>&6 2>&7 || exit $? else OneBitSGDOPT=no BUILD_DIR=build/$TARGET/$FLAVOR if [[ $TARGET == "cpu" ]]; then CUDAOPT=no else CUDAOPT=yes if [[ $TARGET == "1bitsgd" ]]; then OneBitSGDOPT=yes fi fi ./configure --with-build-top=$BUILD_DIR ${MATH_LIBRARY_OPTION} --with-buildtype=$FLAVOR --cuda=$CUDAOPT --with-code-coverage=$CODE_COVERAGE --1bitsgd=$OneBitSGDOPT $EXTRA_CONFIGURE_OPTIONS if [[ $CLEAN_BEFORE == 1 ]]; then make -C $BUILD_DIR -f $MAKEFILE clean 1>&6 2>&7 || exit $? fi make -C $BUILD_DIR -j `nproc` -f $MAKEFILE 1>&6 2>&7 || exit $? fi if [[ $QUIET_BUILD == 1 ]]; then chmod a+r $BUILD_FILE.* fi done done fi # Step 3 -- Run the project tests, both debug and release, if requested if [[ $RUN == 1 ]]; then cd $PREFIX_DIR echo "============ cp Tests/EndToEndTests/Simple2d/OneHidden.cntk $CONF_FILE ============" echo "============ cd $CNTK_ROOT/Tests/EndToEndTests/Simple2d/Data ============" for FLAVOR in "${flavorArray[@]}" do for TARGET in "${targetArray[@]}" do for TESTTARGET in "${testTargetArray[@]}" do # Determine how to set the deviceId parameter in the configuration. # 0 will pick the first GPU (or fail. -1 will pick the CPU. if [[ $TESTTARGET == gpu ]]; then DEVICE_ID=0 else DEVICE_ID=-1 fi if [[ $TESTTARGET == gpu && $TARGET == cpu ]]; then # CPU-only builds cannot run GPU test targets continue; fi if [[ $OSTYPE == "linux-gnu" ]]; then FLAVOR_DIR=build/$TARGET/$FLAVOR else if [[ $FLAVOR == "debug" ]]; then FLAVOR_DIR="$DEBUG_DIR" else FLAVOR_DIR="$RELEASE_DIR" fi if [[ $TARGET == cpu ]]; then FLAVOR_DIR="${FLAVOR}_CpuOnly" fi fi OUT_FILE="$RUN_FILE.$FLAVOR.$TARGET.$TESTTARGET.out" BIN_PATH=$CNTK_ROOT/$PREFIX_DIR/$FLAVOR_DIR/$BIN_NAME if ! [[ -f $BIN_PATH ]]; then echo "============ ERROR: CNTK did not build properly for $TARGET/$FLAVOR ============" echo "Missing file: $BIN_PATH" exit 1 fi if [[ $OS == "Windows_NT" ]]; then echo "============ Running $BIN_PATH configFile=`cygpath -w $CONF_FILE` for $TARGET/$FLAVOR (on $TESTTARGET) ============" else echo "============ Running $BIN_PATH configFile=$CONF_FILE for $TARGET/$FLAVOR (on $TESTTARGET) ============" fi echo "============ output in ($OUT_FILE) ============" cd $CNTK_ROOT/Tests/EndToEndTests/Simple2d/Data rm -rf "$OUTPUT_DIR/Models" if [[ $OS == "Windows_NT" ]]; then # We have to use cygpath on Windows to modify the file paths into the format readable by cntk. time $BIN_PATH configFile="`cygpath -w $CONF_FILE`" deviceId=$DEVICE_ID OutputDir="`cygpath -w $OUTPUT_DIR`" &>$OUT_FILE || exit $? else time $BIN_PATH configFile=$CONF_FILE deviceId=$DEVICE_ID OutputDir="$OUTPUT_DIR" &>$OUT_FILE || exit $? fi chmod a+r $RUN_FILE.* # Check if execution was successful grep -q "Using ${TESTTARGET^^}" "$OUT_FILE" || { echo "============ ERROR: Run output (in $OUT_FILE) did not contain information about target device ($TESTTARGET) ============" exit 1 } grep -q "EXCEPTION" "$OUT_FILE" && { echo "============ ERROR: Run output in ($OUT_FILE) contains exceptions ============" grep "EXCEPTION" "$OUT_FILE" exit 1 } done done done fi # Step 5 -- Optionally clean after builds and tests if [[ $CLEAN_AFTER == 1 ]]; then cd $CNTK_ROOT for FLAVOR in "${flavorArray[@]}" do for TARGET in "${targetArray[@]}" do echo "============ Cleaning up CNTK $TARGET/$FLAVOR ============" if [[ $OS == "Windows_NT" ]]; then if [[ $TARGET == "cpu" ]]; then CONFIGURATION=${FLAVOR}_CpuOnly else CONFIGURATION=${FLAVOR} fi msbuild.exe /nologo /verbosity:m /property:Configuration=$CONFIGURATION /t:clean 1>&6 2>&7 || exit $? else make -C build/$TARGET/$FLAVOR -f $MAKEFILE clean 1>&6 2>&7 || exit $? fi done done rm -rf "$OUTPUT_DIR" fi echo "============ Build and test of CNTK was successful! ============"