From 1ab0dca539ff29927939f2a5b1b167ff5585eeb7 Mon Sep 17 00:00:00 2001 From: storypku Date: Sun, 13 Sep 2020 19:25:16 +0800 Subject: [PATCH] Bazel: apollo.sh config interactive mode simplified and improved --- docker/build/installers/installer_base.sh | 4 +- scripts/apollo_config.sh | 24 +- tools/apollo.bazelrc.sample | 19 +- tools/bootstrap.py | 749 +++++++--------------- 4 files changed, 259 insertions(+), 537 deletions(-) mode change 100644 => 100755 tools/bootstrap.py diff --git a/docker/build/installers/installer_base.sh b/docker/build/installers/installer_base.sh index d5cd376a56c..659aab3c3db 100755 --- a/docker/build/installers/installer_base.sh +++ b/docker/build/installers/installer_base.sh @@ -34,8 +34,8 @@ export APOLLO_LD_FILE="/etc/ld.so.conf.d/apollo.conf" export DOWNLOAD_LOG="/opt/apollo/build.log" export LOCAL_HTTP_ADDR="http://172.17.0.1:8388" -# export SUPPORTED_NVIDIA_SMS="5.0 5.2 6.0 6.1 7.0 7.2 7.5" -export SUPPORTED_NVIDIA_SMS="5.0 6.0 6.1 7.0 7.2 7.5" +# export SUPPORTED_NVIDIA_SMS="3.7 5.0 5.2 6.0 6.1 7.0 7.2 7.5" +export SUPPORTED_NVIDIA_SMS="3.7 5.2 6.0 6.1 7.0 7.2 7.5" function py3_version() { local version diff --git a/scripts/apollo_config.sh b/scripts/apollo_config.sh index 0b87354bfa2..735c349e573 100755 --- a/scripts/apollo_config.sh +++ b/scripts/apollo_config.sh @@ -18,13 +18,6 @@ TOP_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)" source "${TOP_DIR}/cyber/setup.bash" -# STAGE="${STAGE:-dev}" -: ${STAGE:=dev} - -IFS='' read -r -d '' STARTUP_TXT << EOF -startup --output_user_root="${APOLLO_CACHE_DIR}/bazel" -common --distdir="${APOLLO_BAZEL_DISTDIR}" -EOF set -e @@ -33,23 +26,24 @@ BAZEL_CONF="${TOP_DIR}/.apollo.bazelrc" ARCH="$(uname -m)" function config_noninteractive() { - echo "${STARTUP_TXT}" > "${BAZEL_CONF}" + local output_dir="${APOLLO_CACHE_DIR}/bazel" + + > "${BAZEL_CONF}" + echo "startup --output_user_root=\"${output_dir}\"" >> "${BAZEL_CONF}" + echo "common --distdir=\"${APOLLO_BAZEL_DISTDIR}\"" >> "${BAZEL_CONF}" + echo >> "${BAZEL_CONF}" + echo -e "build --action_env GCC_HOST_COMPILER_PATH=\"/usr/bin/${ARCH}-linux-gnu-gcc-7\"" >> "${BAZEL_CONF}" cat "${TOP_DIR}/tools/apollo.bazelrc.sample" >> "${BAZEL_CONF}" } function config_interactive() { - if [ -z "$PYTHON_BIN_PATH" ]; then - PYTHON_BIN_PATH=$(which python3 || true) - fi - + py3_bin="$(which python3 || true)" # Set all env variables - "$PYTHON_BIN_PATH" "${TOP_DIR}/tools/bootstrap.py" "$@" - echo "${STARTUP_TXT}" >> "${BAZEL_CONF}" + "${py3_bin}" "${TOP_DIR}/tools/bootstrap.py" "$@" } function config() { - local stage="${STAGE}" if [ $# -eq 0 ]; then config_noninteractive else diff --git a/tools/apollo.bazelrc.sample b/tools/apollo.bazelrc.sample index 4d4d69ef09d..291cdc46ab1 100644 --- a/tools/apollo.bazelrc.sample +++ b/tools/apollo.bazelrc.sample @@ -1,6 +1,3 @@ -build --action_env CUDA_TOOLKIT_PATH="/usr/local/cuda-10.2" -build --action_env TF_CUDA_COMPUTE_CAPABILITIES="5.2,6.0,6.1,7.0,7.2,7.5" - build --action_env PYTHON_BIN_PATH="/usr/bin/python3" build --action_env PYTHON_LIB_PATH="/usr/lib/python3/dist-packages" build --python_path="/usr/bin/python3" @@ -8,25 +5,17 @@ build --python_path="/usr/bin/python3" build:gpu --config=cuda build:gpu --config=tensorrt -## The following was adapted from tensorflow/.bazelrc +build --action_env CUDA_TOOLKIT_PATH="/usr/local/cuda-10.2" +build --action_env TF_CUDA_COMPUTE_CAPABILITIES="3.7,5.2,6.0,6.1,7.0,7.2,7.5" -# This config refers to building with CUDA available. It does not necessarily -# mean that we build CUDA op kernels. +# This config refers to building with CUDA available. build:using_cuda --define=using_cuda=true build:using_cuda --action_env TF_NEED_CUDA=1 build:using_cuda --crosstool_top=@local_config_cuda//crosstool:toolchain -# This config refers to building CUDA op kernels with nvcc. +# This config refers to building CUDA with nvcc. build:cuda --config=using_cuda build:cuda --define=using_cuda_nvcc=true -# This config refers to building CUDA op kernels with clang. -build:cuda_clang --config=using_cuda -build:cuda_clang --define=using_cuda_clang=true -build:cuda_clang --define=using_clang=true -build:cuda_clang --action_env TF_CUDA_CLANG=1 - build:tensorrt --action_env TF_NEED_TENSORRT=1 -build:nonccl --define=no_nccl_support=true - build:teleop --define=WITH_TELEOP=true diff --git a/tools/bootstrap.py b/tools/bootstrap.py old mode 100644 new mode 100755 index 6848d5b2f7c..c7059e4254c --- a/tools/bootstrap.py +++ b/tools/bootstrap.py @@ -1,27 +1,37 @@ #! /usr/bin/env python3 -# Adapted from tensorflow.git/configure.py -# Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +# **************************************************************************** +# Copyright 2020 The Apollo Authors. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +# +# Copyright 2017 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# # ============================================================================== -"""configure script to get build parameters from user.""" + +# -*- coding: utf-8 -*- +"""Script to get build parameters interactively from user. +Adapted significantly from tensorflow.git/configure.py . +""" from __future__ import absolute_import from __future__ import division from __future__ import print_function import argparse -import errno import os import platform import re @@ -38,15 +48,16 @@ _DEFAULT_CUDA_VERSION = '10' _DEFAULT_CUDNN_VERSION = '7' _DEFAULT_TENSORRT_VERSION = '7' -_DEFAULT_CUDA_COMPUTE_CAPABILITIES = '6.0,6.1,7.0,7.2,7.5' +_DEFAULT_CUDA_COMPUTE_CAPABILITIES = '3.7,5.2,6.0,6.1,7.0,7.2,7.5' -_DEFAULT_PROMPT_ASK_ATTEMPTS = 10 +_DEFAULT_PROMPT_ASK_ATTEMPTS = 3 _APOLLO_ROOT_DIR = '' -_APOLLO_BAZELRC = '' +_APOLLO_BAZELRC = '.apollo.bazelrc' + _APOLLO_CURRENT_BAZEL_VERSION = None _APOLLO_MIN_BAZEL_VERSION = '2.0.0' -_APOLLO_MAX_BAZEL_VERSION = '3.99.0' +_APOLLO_INSIDE_DOCKER = True class UserInputError(Exception): @@ -57,6 +68,17 @@ def is_linux(): return platform.system() == 'Linux' +def inside_docker(): + return os.path.isfile('/.dockerenv') + + +def default_root_dir(): + current_dir = os.path.dirname(__file__) + if len(current_dir) == 0: + current_dir = '.' + return os.path.abspath(os.path.join(current_dir, '..')) + + def get_input(question): try: try: @@ -68,38 +90,6 @@ def get_input(question): return answer -def symlink_force(target, link_name): - """Force symlink, equivalent of 'ln -sf'. - - Args: - target: items to link to. - link_name: name of the link. - """ - try: - os.symlink(target, link_name) - except OSError as e: - if e.errno == errno.EEXIST: - os.remove(link_name) - os.symlink(target, link_name) - else: - raise e - - -def sed_in_place(filename, old, new): - """Replace old string with new string in file. - - Args: - filename: string for filename. - old: string to replace. - new: new string to replace to. - """ - with open(filename, 'r') as f: - filedata = f.read() - newdata = filedata.replace(old, new) - with open(filename, 'w') as f: - f.write(newdata) - - def write_to_bazelrc(line): with open(_APOLLO_BAZELRC, 'a') as f: f.write(line + '\n') @@ -109,6 +99,13 @@ def write_action_env_to_bazelrc(var_name, var): write_to_bazelrc('build --action_env {}="{}"'.format(var_name, str(var))) +def write_build_var_to_bazelrc(bazel_config_name, option_name): + # TODO(build): Migrate all users of configure.py to use --config Bazel + # options and not to set build configs through environment variables. + write_to_bazelrc('build:%s --define %s=true' % (bazel_config_name, + option_name)) + + def run_shell(cmd, allow_non_zero=False, stderr=None): if stderr is None: stderr = sys.stdout @@ -119,7 +116,7 @@ def run_shell(cmd, allow_non_zero=False, stderr=None): output = e.output else: output = subprocess.check_output(cmd, stderr=stderr) - return output.decode('UTF-8').strip() + return output.decode("UTF-8").strip() def get_python_path(environ_cp, python_bin_path): @@ -148,7 +145,8 @@ def get_python_path(environ_cp, python_bin_path): paths = [] for path in all_paths: - if os.path.isdir(path): + if os.path.isdir(path) and not path.startswith( + os.path.join(_APOLLO_ROOT_DIR, "bazel-bin")): paths.append(path) return paths @@ -159,6 +157,24 @@ def get_python_major_version(python_bin_path): [python_bin_path, '-c', 'import sys; print(sys.version[0])']) +def setup_common_dirs(environ_cp): + """Setup --distdir and --output_user_root directories""" + default_cache_dir = os.path.join(_APOLLO_ROOT_DIR, '.cache') + default_dist_dir = os.path.join(_APOLLO_ROOT_DIR, '.cache/distdir') + cache_dir = environ_cp.get('APOLLO_CACHE_DIR') + dist_dir = environ_cp.get('APOLLO_BAZEL_DISTDIR') + + # if cyber/setup.bash not sourced + if len(cache_dir) == 0: + cache_dir = default_cache_dir + if len(dist_dir) == 0: + dist_dir = default_dist_dir + + write_to_bazelrc('startup --output_user_root="{}/bazel"'.format(cache_dir)) + write_to_bazelrc('common --distdir="{}"'.format(dist_dir)) + write_to_bazelrc('') + + def setup_python(environ_cp): """Setup python related env variables.""" # Get PYTHON_BIN_PATH, default is the current running python. @@ -186,28 +202,25 @@ def setup_python(environ_cp): python_lib_path = environ_cp.get('PYTHON_LIB_PATH') if not python_lib_path: python_lib_paths = get_python_path(environ_cp, python_bin_path) - if environ_cp.get('USE_DEFAULT_PYTHON_LIB_PATH') == '1': - python_lib_path = python_lib_paths[0] - else: - print('Found possible Python library paths:\n %s' % - '\n '.join(python_lib_paths)) - default_python_lib_path = python_lib_paths[0] - python_lib_path = get_input( - 'Please input the desired Python library path to use. ' - 'Default is [{}]\n'.format(python_lib_paths[0])) - if not python_lib_path: - python_lib_path = default_python_lib_path + print('Found possible Python library paths:\n %s' % + '\n '.join(python_lib_paths)) + default_python_lib_path = python_lib_paths[0] + python_lib_path = get_input( + 'Please input the desired Python library path to use. ' + 'Default is [{}]\n'.format(python_lib_paths[0])) + if not python_lib_path: + python_lib_path = default_python_lib_path environ_cp['PYTHON_LIB_PATH'] = python_lib_path python_major_version = get_python_major_version(python_bin_path) if python_major_version != '3': - print('Python 2 was RETIRED on April 2020. Use Python 3 instead.') + print('Python 2 was Retired on April 2020. Use Python 3 instead.') sys.exit(1) # Set-up env variables used by python_configure.bzl write_action_env_to_bazelrc('PYTHON_BIN_PATH', python_bin_path) write_action_env_to_bazelrc('PYTHON_LIB_PATH', python_lib_path) - write_to_bazelrc('build --python_path=\"{}"'.format(python_bin_path)) + write_to_bazelrc('build --python_path=\"{}\"'.format(python_bin_path)) environ_cp['PYTHON_BIN_PATH'] = python_bin_path # If choosen python_lib_path is from a path specified in the PYTHONPATH @@ -218,7 +231,8 @@ def setup_python(environ_cp): write_action_env_to_bazelrc('PYTHONPATH', environ_cp.get('PYTHONPATH')) -def reset_tf_configure_bazelrc(): + +def reset_apollo_bazelrc(): """Reset file that contains customized config settings.""" open(_APOLLO_BAZELRC, 'w').close() @@ -232,28 +246,28 @@ def get_var(environ_cp, no_reply=None): """Get boolean input from user. - If var_name is not set in env, ask user to enable query_item or not. If the - response is empty, use the default. - - Args: - environ_cp: copy of the os.environ. - var_name: string for name of environment variable, e.g. "TF_NEED_CUDA". - query_item: string for feature related to the variable, e.g. "CUDA for - Nvidia GPUs". - enabled_by_default: boolean for default behavior. - question: optional string for how to ask for user input. - yes_reply: optional string for reply when feature is enabled. - no_reply: optional string for reply when feature is disabled. - - Returns: - boolean value of the variable. - - Raises: - UserInputError: if an environment variable is set, but it cannot be - interpreted as a boolean indicator, assume that the user has made a - scripting error, and will continue to provide invalid input. - Raise the error to avoid infinitely looping. - """ + If var_name is not set in env, ask user to enable query_item or not. If the + response is empty, use the default. + + Args: + environ_cp: copy of the os.environ. + var_name: string for name of environment variable, e.g. "TF_NEED_CUDA". + query_item: string for feature related to the variable, e.g. "CUDA for + Nvidia GPUs". + enabled_by_default: boolean for default behavior. + question: optional string for how to ask for user input. + yes_reply: optional string for reply when feature is enabled. + no_reply: optional string for reply when feature is disabled. + + Returns: + boolean value of the variable. + + Raises: + UserInputError: if an environment variable is set, but it cannot be + interpreted as a boolean indicator, assume that the user has made a + scripting error, and will continue to provide invalid input. + Raise the error to avoid infinitely looping. + """ if not question: question = 'Do you wish to build your project with {} support?'.format( query_item) @@ -309,88 +323,18 @@ def get_var(environ_cp, return var -def set_build_var(environ_cp, - var_name, - query_item, - option_name, - enabled_by_default, - bazel_config_name=None): - """Set if query_item will be enabled for the build. - - Ask user if query_item will be enabled. Default is used if no input is given. - Set subprocess environment variable and write to .bazelrc if enabled. - - Args: - environ_cp: copy of the os.environ. - var_name: string for name of environment variable, e.g. "TF_NEED_CUDA". - query_item: string for feature related to the variable, e.g. "CUDA for - Nvidia GPUs". - option_name: string for option to define in .bazelrc. - enabled_by_default: boolean for default behavior. - bazel_config_name: Name for Bazel --config argument to enable build feature. - """ - - var = str( - int(get_var(environ_cp, var_name, query_item, enabled_by_default))) - environ_cp[var_name] = var - if var == '1': - write_to_bazelrc('build:%s --define %s=true' % (bazel_config_name, - option_name)) - write_to_bazelrc('build --config=%s' % bazel_config_name) - elif bazel_config_name is not None: - # TODO(mikecase): Migrate all users of configure.py to use --config Bazel - # options and not to set build configs through environment variables. - write_to_bazelrc('build:%s --define %s=true' % (bazel_config_name, - option_name)) - - -def set_action_env_var(environ_cp, - var_name, - query_item, - enabled_by_default, - question=None, - yes_reply=None, - no_reply=None, - bazel_config_name=None): - """Set boolean action_env variable. - - Ask user if query_item will be enabled. Default is used if no input is given. - Set environment variable and write to .bazelrc. - - Args: - environ_cp: copy of the os.environ. - var_name: string for name of environment variable, e.g. "TF_NEED_CUDA". - query_item: string for feature related to the variable, e.g. "CUDA for - Nvidia GPUs". - enabled_by_default: boolean for default behavior. - question: optional string for how to ask for user input. - yes_reply: optional string for reply when feature is enabled. - no_reply: optional string for reply when feature is disabled. - bazel_config_name: adding config to .bazelrc instead of action_env. - """ - var = int( - get_var(environ_cp, var_name, query_item, enabled_by_default, question, - yes_reply, no_reply)) - - if not bazel_config_name: - write_action_env_to_bazelrc(var_name, var) - elif var: - write_to_bazelrc('build --config=%s' % bazel_config_name) - environ_cp[var_name] = str(var) - - def convert_version_to_int(version): """Convert a version number to a integer that can be used to compare. - Version strings of the form X.YZ and X.Y.Z-xxxxx are supported. The - 'xxxxx' part, for instance 'homebrew' on OS/X, is ignored. + Version strings of the form X.YZ and X.Y.Z-xxxxx are supported. The + 'xxxxx' part, for instance 'homebrew' on OS/X, is ignored. - Args: - version: a version to be converted + Args: + version: a version to be converted - Returns: - An integer if converted successfully, otherwise return None. - """ + Returns: + An integer if converted successfully, otherwise return None. + """ version = version.split('-')[0] version_segments = version.split('.') # Treat "0.24" as "0.24.0" @@ -404,18 +348,17 @@ def convert_version_to_int(version): return int(version_str) -def check_bazel_version(min_version, max_version): - """Check installed bazel version is between min_version and max_version. +def check_bazel_version(min_version): + """Check installed bazel version. Args: min_version: string for minimum bazel version (must exist!). - max_version: string for maximum bazel version (must exist!). Returns: The bazel version detected. """ if which('bazel') is None: - print('Cannot find bazel. Please install bazel.') + print('Cannot find bazel. Please install bazel first.') sys.exit(0) stderr = open(os.devnull, 'wb') @@ -426,7 +369,6 @@ def check_bazel_version(min_version, max_version): min_version_int = convert_version_to_int(min_version) curr_version_int = convert_version_to_int(curr_version) - max_version_int = convert_version_to_int(max_version) # Check if current bazel version can be detected properly. if not curr_version_int: @@ -440,75 +382,25 @@ def check_bazel_version(min_version, max_version): print( 'Please upgrade your bazel installation to version %s or higher' % min_version) sys.exit(1) - if (curr_version_int > max_version_int - and 'TF_IGNORE_MAX_BAZEL_VERSION' not in os.environ): - print( - 'Please downgrade your bazel installation to version %s or lower' - '! To downgrade: download the installer for the old version (from' - 'https://github.com/bazelbuild/bazel/releases) then run the ' - 'installer.' % max_version) - sys.exit(1) return curr_version -def set_cc_opt_flags(environ_cp): - """Set up architecture-dependent optimization flags. - - Also append CC optimization flags to bazel.rc.. - - Args: - environ_cp: copy of the os.environ. - """ - default_cc_opt_flags = '-march=native' - question = ( - 'Please specify optimization flags to use during compilation when' - ' bazel option "--config=opt" is specified [Default is %s]: ' - ) % default_cc_opt_flags - cc_opt_flags = get_from_env_or_user_or_default( - environ_cp, 'CC_OPT_FLAGS', question, default_cc_opt_flags) - for opt in cc_opt_flags.split(): - write_to_bazelrc('build:opt --copt=%s' % opt) - # It should be safe on the same build host. - write_to_bazelrc('build:opt --host_copt=-march=native') - write_to_bazelrc('build:opt --define with_default_optimizations=true') - - -def set_tf_cuda_clang(environ_cp): - """set TF_CUDA_CLANG action_env. - - Args: - environ_cp: copy of the os.environ. - """ - question = 'Do you want to use clang as CUDA compiler?' - yes_reply = 'Clang will be used as CUDA compiler.' - no_reply = 'nvcc will be used as CUDA compiler.' - set_action_env_var( - environ_cp, - 'TF_CUDA_CLANG', - None, - False, - question=question, - yes_reply=yes_reply, - no_reply=no_reply, - bazel_config_name='cuda_clang') - - def get_from_env_or_user_or_default(environ_cp, var_name, ask_for_var, var_default): """Get var_name either from env, or user or default. - If var_name has been set as environment variable, use the preset value, else - ask for user input. If no input is provided, the default is used. + If var_name has been set as environment variable, use the preset value, else + ask for user input. If no input is provided, the default is used. - Args: - environ_cp: copy of the os.environ. - var_name: string for name of environment variable, e.g. "TF_NEED_CUDA". - ask_for_var: string for how to ask for user input. - var_default: default value string. + Args: + environ_cp: copy of the os.environ. + var_name: string for name of environment variable, e.g. "TF_NEED_CUDA". + ask_for_var: string for how to ask for user input. + var_default: default value string. - Returns: - string value for var_name - """ + Returns: + string value for var_name + """ var = environ_cp.get(var_name) if not var: var = get_input(ask_for_var) @@ -518,31 +410,6 @@ def get_from_env_or_user_or_default(environ_cp, var_name, ask_for_var, return var -def set_clang_cuda_compiler_path(environ_cp): - """Set CLANG_CUDA_COMPILER_PATH.""" - default_clang_path = which('clang') or '' - ask_clang_path = ( - 'Please specify which clang should be used as device and ' - 'host compiler. [Default is %s]: ') % default_clang_path - - while True: - clang_cuda_compiler_path = get_from_env_or_user_or_default( - environ_cp, 'CLANG_CUDA_COMPILER_PATH', ask_clang_path, - default_clang_path) - if os.path.exists(clang_cuda_compiler_path): - break - - # Reset and retry - print('Invalid clang path: %s cannot be found.' % - clang_cuda_compiler_path) - environ_cp['CLANG_CUDA_COMPILER_PATH'] = '' - - # Set CLANG_CUDA_COMPILER_PATH - environ_cp['CLANG_CUDA_COMPILER_PATH'] = clang_cuda_compiler_path - write_action_env_to_bazelrc('CLANG_CUDA_COMPILER_PATH', - clang_cuda_compiler_path) - - def prompt_loop_or_load_from_env(environ_cp, var_name, var_default, @@ -554,36 +421,36 @@ def prompt_loop_or_load_from_env(environ_cp, n_ask_attempts=_DEFAULT_PROMPT_ASK_ATTEMPTS): """Loop over user prompts for an ENV param until receiving a valid response. - For the env param var_name, read from the environment or verify user input - until receiving valid input. When done, set var_name in the environ_cp to its - new value. - - Args: - environ_cp: (Dict) copy of the os.environ. - var_name: (String) string for name of environment variable, e.g. "TF_MYVAR". - var_default: (String) default value string. - ask_for_var: (String) string for how to ask for user input. - check_success: (Function) function that takes one argument and returns a - boolean. Should return True if the value provided is considered valid. May - contain a complex error message if error_msg does not provide enough - information. In that case, set suppress_default_error to True. - error_msg: (String) String with one and only one '%s'. Formatted with each - invalid response upon check_success(input) failure. - suppress_default_error: (Bool) Suppress the above error message in favor of - one from the check_success function. - resolve_symlinks: (Bool) Translate symbolic links into the real filepath. - n_ask_attempts: (Integer) Number of times to query for valid input before - raising an error and quitting. - - Returns: - [String] The value of var_name after querying for input. - - Raises: - UserInputError: if a query has been attempted n_ask_attempts times without - success, assume that the user has made a scripting error, and will - continue to provide invalid input. Raise the error to avoid infinitely - looping. - """ + For the env param var_name, read from the environment or verify user input + until receiving valid input. When done, set var_name in the environ_cp to its + new value. + + Args: + environ_cp: (Dict) copy of the os.environ. + var_name: (String) string for name of environment variable, e.g. "TF_MYVAR". + var_default: (String) default value string. + ask_for_var: (String) string for how to ask for user input. + check_success: (Function) function that takes one argument and returns a + boolean. Should return True if the value provided is considered valid. May + contain a complex error message if error_msg does not provide enough + information. In that case, set suppress_default_error to True. + error_msg: (String) String with one and only one '%s'. Formatted with each + invalid response upon check_success(input) failure. + suppress_default_error: (Bool) Suppress the above error message in favor of + one from the check_success function. + resolve_symlinks: (Bool) Translate symbolic links into the real filepath. + n_ask_attempts: (Integer) Number of times to query for valid input before + raising an error and quitting. + + Returns: + [String] The value of var_name after querying for input. + + Raises: + UserInputError: if a query has been attempted n_ask_attempts times without + success, assume that the user has made a scripting error, and will + continue to provide invalid input. Raise the error to avoid infinitely + looping. + """ default = environ_cp.get(var_name) or var_default full_query = '%s [Default is %s]: ' % ( ask_for_var, @@ -635,19 +502,19 @@ def set_gcc_host_compiler_path(environ_cp): def reformat_version_sequence(version_str, sequence_count): """Reformat the version string to have the given number of sequences. - For example: - Given (7, 2) -> 7.0 - (7.0.1, 2) -> 7.0 - (5, 1) -> 5 - (5.0.3.2, 1) -> 5 + For example: + Given (7, 2) -> 7.0 + (7.0.1, 2) -> 7.0 + (5, 1) -> 5 + (5.0.3.2, 1) -> 5 - Args: - version_str: String, the version string. - sequence_count: int, an integer. + Args: + version_str: String, the version string. + sequence_count: int, an integer. - Returns: - string, reformatted version string. - """ + Returns: + string, reformatted version string. + """ v = version_str.split('.') if len(v) < sequence_count: v = v + (['0'] * (sequence_count - len(v))) @@ -655,7 +522,7 @@ def reformat_version_sequence(version_str, sequence_count): return '.'.join(v[:sequence_count]) -def set_tf_cuda_paths(environ_cp): +def set_cuda_paths(environ_cp): """Set TF_CUDA_PATHS.""" ask_cuda_paths = ( 'Please specify the comma-separated list of base paths to look for CUDA ' @@ -666,7 +533,7 @@ def set_tf_cuda_paths(environ_cp): environ_cp['TF_CUDA_PATHS'] = tf_cuda_paths -def set_tf_cuda_version(environ_cp): +def set_cuda_version(environ_cp): """Set TF_CUDA_VERSION.""" ask_cuda_version = ( 'Please specify the CUDA SDK version you want to use. ' @@ -676,7 +543,7 @@ def set_tf_cuda_version(environ_cp): environ_cp['TF_CUDA_VERSION'] = tf_cuda_version -def set_tf_cudnn_version(environ_cp): +def set_cudnn_version(environ_cp): """Set TF_CUDNN_VERSION.""" ask_cudnn_version = ( 'Please specify the cuDNN version you want to use. ' @@ -716,7 +583,7 @@ def is_cuda_compatible(lib, cuda_ver, cudnn_ver): return cudnn_ok and cuda_ok -def set_tf_tensorrt_version(environ_cp): +def set_tensorrt_version(environ_cp): """Set TF_TENSORRT_VERSION.""" if not int(environ_cp.get('TF_NEED_TENSORRT', False)): return @@ -731,14 +598,14 @@ def set_tf_tensorrt_version(environ_cp): environ_cp['TF_TENSORRT_VERSION'] = tf_tensorrt_version -def set_tf_nccl_version(environ_cp): +def set_nccl_version(environ_cp): """Set TF_NCCL_VERSION.""" if 'TF_NCCL_VERSION' in environ_cp: return ask_nccl_version = ( 'Please specify the locally installed NCCL version you want to use. ' - '[Leave empty to use http://github.com/nvidia/nccl]: ') + ) tf_nccl_version = get_from_env_or_user_or_default( environ_cp, 'TF_NCCL_VERSION', ask_nccl_version, '') environ_cp['TF_NCCL_VERSION'] = tf_nccl_version @@ -747,12 +614,12 @@ def set_tf_nccl_version(environ_cp): def get_native_cuda_compute_capabilities(environ_cp): """Get native cuda compute capabilities. - Args: - environ_cp: copy of the os.environ. + Args: + environ_cp: copy of the os.environ. - Returns: - string of native cuda compute capabilities, separated by comma. - """ + Returns: + string of native cuda compute capabilities, separated by comma. + """ device_query_bin = os.path.join( environ_cp.get('CUDA_TOOLKIT_PATH'), 'extras/demo_suite/deviceQuery') if os.path.isfile(device_query_bin) and os.access(device_query_bin, @@ -769,7 +636,7 @@ def get_native_cuda_compute_capabilities(environ_cp): return output -def set_tf_cuda_compute_capabilities(environ_cp): +def set_cuda_compute_capabilities(environ_cp): """Set TF_CUDA_COMPUTE_CAPABILITIES.""" while True: native_cuda_compute_capabilities = get_native_cuda_compute_capabilities( @@ -807,17 +674,12 @@ def set_tf_cuda_compute_capabilities(environ_cp): all_valid = False else: ver = float(m.group(0)) - if ver < 5.0: + if ver < 3.5: print( - 'ERROR: We only supports CUDA compute capabilities 5.0 ' + 'ERROR: We only supports CUDA compute capabilities 3.7 ' 'and higher. Please re-specify the list of compute ' 'capabilities excluding version %s.' % ver) all_valid = False - if ver < 3.5: - print( - 'WARNING: XLA does not support CUDA compute capabilities ' - 'lower than 3.5. Disable XLA when running on older GPUs.' - ) if all_valid: break @@ -834,81 +696,8 @@ def set_tf_cuda_compute_capabilities(environ_cp): def set_other_cuda_vars(environ_cp): """Set other CUDA related variables.""" # If CUDA is enabled, always use GPU during build and test. - if environ_cp.get('TF_CUDA_CLANG') == '1': - write_to_bazelrc('build --config=cuda_clang') - else: - write_to_bazelrc('build --config=cuda') - - -def set_host_cxx_compiler(environ_cp): - """Set HOST_CXX_COMPILER.""" - default_cxx_host_compiler = which('g++') or '' - - host_cxx_compiler = prompt_loop_or_load_from_env( - environ_cp, - var_name='HOST_CXX_COMPILER', - var_default=default_cxx_host_compiler, - ask_for_var=('Please specify which C++ compiler should be used as the ' - 'host C++ compiler.'), - check_success=os.path.exists, - error_msg='Invalid C++ compiler path. %s cannot be found.', - ) - - write_action_env_to_bazelrc('HOST_CXX_COMPILER', host_cxx_compiler) - - -def set_host_c_compiler(environ_cp): - """Set HOST_C_COMPILER.""" - default_c_host_compiler = which('gcc') or '' - - host_c_compiler = prompt_loop_or_load_from_env( - environ_cp, - var_name='HOST_C_COMPILER', - var_default=default_c_host_compiler, - ask_for_var=( - 'Please specify which C compiler should be used as the host ' - 'C compiler.'), - check_success=os.path.exists, - error_msg='Invalid C compiler path. %s cannot be found.', - ) - - write_action_env_to_bazelrc('HOST_C_COMPILER', host_c_compiler) - - -def system_specific_test_config(environ_cp): - """Add default build and test flags required for TF tests to bazelrc.""" - write_to_bazelrc('test --flaky_test_attempts=3') - write_to_bazelrc('test --test_size_filters=small,medium') - - # Each instance of --test_tag_filters or --build_tag_filters overrides all - # previous instances, so we need to build up a complete list and write a - # single list of filters for the .bazelrc file. - - if environ_cp.get('TF_NEED_CUDA', None) == '1': - write_to_bazelrc('test --test_env=LD_LIBRARY_PATH') - - -def set_system_libs_flag(environ_cp): - syslibs = environ_cp.get('TF_SYSTEM_LIBS', '') - if syslibs: - if ',' in syslibs: - syslibs = ','.join(sorted(syslibs.split(','))) - else: - syslibs = ','.join(sorted(syslibs.split())) - write_action_env_to_bazelrc('TF_SYSTEM_LIBS', syslibs) - - if 'PREFIX' in environ_cp: - write_to_bazelrc('build --define=PREFIX=%s' % environ_cp['PREFIX']) - if 'LIBDIR' in environ_cp: - write_to_bazelrc('build --define=LIBDIR=%s' % environ_cp['LIBDIR']) - if 'INCLUDEDIR' in environ_cp: - write_to_bazelrc( - 'build --define=INCLUDEDIR=%s' % environ_cp['INCLUDEDIR']) - - -def config_info_line(name, help_text): - """Helper function to print formatted help text for Bazel config options.""" - print('\t--config=%-12s\t# %s' % (name, help_text)) + # write_to_bazelrc('build --config=cuda') + pass def validate_cuda_config(environ_cp): @@ -922,8 +711,8 @@ def validate_cuda_config(environ_cp): # FIXME(all): abs path for find_cuda_config.py proc = subprocess.Popen( - [environ_cp['PYTHON_BIN_PATH'], 'third_party/gpus/find_cuda_config.py'] + - cuda_libraries, + [environ_cp['PYTHON_BIN_PATH'], 'third_party/gpus/find_cuda_config.py'] + + cuda_libraries, stdout=subprocess.PIPE, env=environ_cp) @@ -960,173 +749,123 @@ def validate_cuda_config(environ_cp): return True -def set_overall_build_config(): - overall_text = """ -## The following was adapted from tensorflow/.bazelrc - -# This config refers to building with CUDA available. It does not necessarily -# mean that we build CUDA op kernels. +def set_other_build_config(): + build_text = """ +# This config refers to building with CUDA available. build:using_cuda --define=using_cuda=true build:using_cuda --action_env TF_NEED_CUDA=1 build:using_cuda --crosstool_top=@local_config_cuda//crosstool:toolchain -# This config refers to building CUDA op kernels with nvcc. +# This config refers to building CUDA with nvcc. build:cuda --config=using_cuda build:cuda --define=using_cuda_nvcc=true -# This config refers to building CUDA op kernels with clang. -build:cuda_clang --config=using_cuda -build:cuda_clang --define=using_cuda_clang=true -build:cuda_clang --define=using_clang=true -build:cuda_clang --action_env TF_CUDA_CLANG=1 - build:tensorrt --action_env TF_NEED_TENSORRT=1 -build:nonccl --define=no_nccl_support=true """ with open(_APOLLO_BAZELRC, 'a') as f: - f.write(overall_text) - + f.write(build_text) -def default_workspace_directory(): - current_dir = os.path.dirname(__file__) - if len(current_dir) == 0: - current_dir = "." - return os.path.abspath(current_dir + "/..") + write_build_var_to_bazelrc('teleop', 'WITH_TELEOP') def main(): if not is_linux(): - raise ValueError("Currently ONLY Linux platform is supported.") + raise ValueError('Currently, only Linux is support.') global _APOLLO_ROOT_DIR global _APOLLO_BAZELRC global _APOLLO_CURRENT_BAZEL_VERSION + global _APOLLO_INSIDE_DOCKER parser = argparse.ArgumentParser() - parser.add_argument( - '--workspace', - type=str, - default=default_workspace_directory(), - help='The absolute path to your active Bazel workspace.') parser.add_argument( '--output_file', type=str, default='.apollo.bazelrc', - help='Path of the bazelrc file to write to (relative to workspace directory)') + help='Path of the bazelrc file to write to (relative to APOLLO_ROOT_DIR)') args = parser.parse_args() - _APOLLO_ROOT_DIR = args.workspace + _APOLLO_ROOT_DIR = default_root_dir() _APOLLO_BAZELRC = os.path.join(_APOLLO_ROOT_DIR, args.output_file) + _APOLLO_INSIDE_DOCKER = inside_docker() # Make a copy of os.environ to be clear when functions and getting and setting # environment variables. environ_cp = dict(os.environ) try: - current_bazel_version = check_bazel_version(_APOLLO_MIN_BAZEL_VERSION, - _APOLLO_MAX_BAZEL_VERSION) + current_bazel_version = check_bazel_version(_APOLLO_MIN_BAZEL_VERSION) except subprocess.CalledProcessError as e: - print("Error checking bazel version: ", + print('Error checking bazel version: ', e.output.decode('UTF-8').strip()) raise e _APOLLO_CURRENT_BAZEL_VERSION = convert_version_to_int( current_bazel_version) - reset_tf_configure_bazelrc() + reset_apollo_bazelrc() + setup_common_dirs(environ_cp) setup_python(environ_cp) - environ_cp['TF_NEED_CUDA'] = str( - int(get_var(environ_cp, 'TF_NEED_CUDA', 'CUDA', False))) - if environ_cp.get('TF_NEED_CUDA') == '1': - set_action_env_var( - environ_cp, - 'TF_NEED_TENSORRT', - 'TensorRT', - False, - bazel_config_name='tensorrt') - - environ_save = dict(environ_cp) - for _ in range(_DEFAULT_PROMPT_ASK_ATTEMPTS): - - if validate_cuda_config(environ_cp): - cuda_env_names = [ - 'TF_CUDA_VERSION', - 'TF_CUBLAS_VERSION', - 'TF_CUDNN_VERSION', - 'TF_TENSORRT_VERSION', - 'TF_NCCL_VERSION', - 'TF_CUDA_PATHS', - # Items below are for backwards compatibility when not using - # TF_CUDA_PATHS. - 'CUDA_TOOLKIT_PATH', - 'CUDNN_INSTALL_PATH', - 'NCCL_INSTALL_PATH', - 'NCCL_HDR_PATH', - 'TENSORRT_INSTALL_PATH' - ] - # Note: set_action_env_var above already writes to bazelrc. - for name in cuda_env_names: - if name in environ_cp: - write_action_env_to_bazelrc(name, environ_cp[name]) - break - - # Restore settings changed below if CUDA config could not be validated. - environ_cp = dict(environ_save) - - set_tf_cuda_version(environ_cp) - set_tf_cudnn_version(environ_cp) - set_tf_tensorrt_version(environ_cp) - set_tf_nccl_version(environ_cp) - - set_tf_cuda_paths(environ_cp) + environ_cp['TF_NEED_CUDA'] = '1' + environ_cp['TF_NEED_TENSORRT'] = '1' + + # build:gpu --config=using_cuda + write_to_bazelrc('build:gpu --config=cuda') + write_to_bazelrc('build:gpu --config=tensorrt') + write_to_bazelrc('') + + environ_save = dict(environ_cp) + for _ in range(_DEFAULT_PROMPT_ASK_ATTEMPTS): + + if validate_cuda_config(environ_cp): + cuda_env_names = [ + 'TF_CUDA_VERSION', + 'TF_CUBLAS_VERSION', + 'TF_CUDNN_VERSION', + 'TF_TENSORRT_VERSION', + 'TF_NCCL_VERSION', + 'TF_CUDA_PATHS', + # Items below are for backwards compatibility + 'CUDA_TOOLKIT_PATH', + 'CUDNN_INSTALL_PATH', + 'NCCL_INSTALL_PATH', + 'NCCL_HDR_PATH', + 'TENSORRT_INSTALL_PATH' + ] + # Note: set_action_env_var above already writes to bazelrc. + for name in cuda_env_names: + if name in environ_cp: + write_action_env_to_bazelrc(name, environ_cp[name]) + break + + # Restore settings changed below if CUDA config could not be + # validated. + environ_cp = dict(environ_save) + + set_cuda_version(environ_cp) + set_cudnn_version(environ_cp) + set_tensorrt_version(environ_cp) + set_nccl_version(environ_cp) + + set_cuda_paths(environ_cp) - else: - raise UserInputError( - 'Invalid CUDA setting were provided %d ' - 'times in a row. Assuming to be a scripting mistake.' % - _DEFAULT_PROMPT_ASK_ATTEMPTS) - - set_tf_cuda_compute_capabilities(environ_cp) - if 'LD_LIBRARY_PATH' in environ_cp and environ_cp.get( - 'LD_LIBRARY_PATH') != '1': - write_action_env_to_bazelrc('LD_LIBRARY_PATH', - environ_cp.get('LD_LIBRARY_PATH')) - - set_tf_cuda_clang(environ_cp) - if environ_cp.get('TF_CUDA_CLANG') == '1': - # Set up which clang we should use as the cuda / host compiler. - set_clang_cuda_compiler_path(environ_cp) - else: - # Set up which gcc nvcc should use as the host compiler - set_gcc_host_compiler_path(environ_cp) - set_other_cuda_vars(environ_cp) else: - # CUDA not required. Ask whether we should download the clang toolchain and - # use it for the CPU build. - pass - # set_tf_download_clang(environ_cp) - -# set_system_libs_flag(environ_cp) -# set_cc_opt_flags(environ_cp) -# system_specific_test_config(environ_cp) - set_overall_build_config() - -# print('Preconfigured Bazel build configs. You can use any of the below by ' -# 'adding "--config=<>" to your build command. See .bazelrc for more ' -# 'details.') -# config_info_line('mkl', 'Build with MKL support.') -# config_info_line('ngraph', 'Build with Intel nGraph support.') -# config_info_line('numa', 'Build with NUMA support.') -# config_info_line( -# 'dynamic_kernels', -# '(Experimental) Build kernels into separate shared objects.') - print('Preconfigured Bazel build configs to DISABLE default on features:') - config_info_line('nonccl', 'Disable NVIDIA NCCL support.') -# config_info_line('noaws', 'Disable AWS S3 filesystem support.') -# config_info_line('nogcp', 'Disable GCP support.') -# config_info_line('nohdfs', 'Disable HDFS support.') + raise UserInputError( + 'Invalid CUDA setting were provided %d ' + 'times in a row. Assuming to be a scripting mistake.' % + _DEFAULT_PROMPT_ASK_ATTEMPTS) + + set_cuda_compute_capabilities(environ_cp) + if not _APOLLO_INSIDE_DOCKER and 'LD_LIBRARY_PATH' in environ_cp: + write_action_env_to_bazelrc('LD_LIBRARY_PATH', + environ_cp.get('LD_LIBRARY_PATH')) + + # Set up which gcc nvcc should use as the host compiler + set_gcc_host_compiler_path(environ_cp) + set_other_cuda_vars(environ_cp) + set_other_build_config() if __name__ == '__main__':