2019-08-21 14:29:46 +00:00
# pylint: disable=g-bad-file-header
# Copyright 2016 The Bazel 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
#
# 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.
""" Configuring the C++ toolchain on Windows. """
load (
2019-10-24 14:01:01 +00:00
" :lib_cc_configure.bzl " ,
2019-08-21 14:29:46 +00:00
" auto_configure_fail " ,
" auto_configure_warning " ,
" auto_configure_warning_maybe " ,
" escape_string " ,
" execute " ,
" resolve_labels " ,
2019-09-03 09:30:13 +00:00
" write_builtin_include_directory_paths " ,
2019-08-21 14:29:46 +00:00
)
def _get_path_env_var ( repository_ctx , name ) :
""" Returns a path from an environment variable.
Removes quotes , replaces ' / ' with ' \' , and strips trailing ' \' s. " " "
if name in repository_ctx . os . environ :
value = repository_ctx . os . environ [ name ]
if value [ 0 ] == " \" " :
if len ( value ) == 1 or value [ - 1 ] != " \" " :
auto_configure_fail ( " ' %s ' environment variable has no trailing quote " % name )
value = value [ 1 : - 1 ]
if " / " in value :
value = value . replace ( " / " , " \\ " )
if value [ - 1 ] == " \\ " :
value = value . rstrip ( " \\ " )
return value
else :
return None
def _get_temp_env ( repository_ctx ) :
""" Returns the value of TMP, or TEMP, or if both undefined then C: \\ Windows. """
tmp = _get_path_env_var ( repository_ctx , " TMP " )
if not tmp :
tmp = _get_path_env_var ( repository_ctx , " TEMP " )
if not tmp :
tmp = " C: \\ Windows \\ Temp "
auto_configure_warning (
" neither ' TMP ' nor ' TEMP ' environment variables are set, using ' %s ' as default " % tmp ,
)
return tmp
def _get_escaped_windows_msys_starlark_content ( repository_ctx , use_mingw = False ) :
""" Return the content of msys cc toolchain rule. """
msys_root = " "
bazel_sh = _get_path_env_var ( repository_ctx , " BAZEL_SH " )
if bazel_sh :
bazel_sh = bazel_sh . replace ( " \\ " , " / " ) . lower ( )
tokens = bazel_sh . rsplit ( " / " , 1 )
if tokens [ 0 ] . endswith ( " /usr/bin " ) :
msys_root = tokens [ 0 ] [ : len ( tokens [ 0 ] ) - len ( " usr/bin " ) ]
elif tokens [ 0 ] . endswith ( " /bin " ) :
msys_root = tokens [ 0 ] [ : len ( tokens [ 0 ] ) - len ( " bin " ) ]
prefix = " mingw64 " if use_mingw else " usr "
tool_path_prefix = escape_string ( msys_root ) + prefix
tool_bin_path = tool_path_prefix + " /bin "
tool_path = { }
for tool in [ " ar " , " compat-ld " , " cpp " , " dwp " , " gcc " , " gcov " , " ld " , " nm " , " objcopy " , " objdump " , " strip " ] :
if msys_root :
tool_path [ tool ] = tool_bin_path + " / " + tool
else :
tool_path [ tool ] = " msys_gcc_installation_error.bat "
tool_paths = " , \n " . join ( [ ' " %s " : " %s " ' % ( k , v ) for k , v in tool_path . items ( ) ] )
include_directories = ( ' " %s / " , \n ' % tool_path_prefix ) if msys_root else " "
return tool_paths , tool_bin_path , include_directories
def _get_system_root ( repository_ctx ) :
""" Get System root path on Windows, default is C: \\ Windows. Doesn ' t %-e scape the result. """
systemroot = _get_path_env_var ( repository_ctx , " SYSTEMROOT " )
if not systemroot :
systemroot = " C: \\ Windows "
auto_configure_warning_maybe (
repository_ctx ,
" SYSTEMROOT is not set, using default SYSTEMROOT=C: \\ Windows " ,
)
return escape_string ( systemroot )
def _add_system_root ( repository_ctx , env ) :
""" Running VCVARSALL.BAT and VCVARSQUERYREGISTRY.BAT need % SYSTEMROOT % \\ \\ system32 in PATH. """
if " PATH " not in env :
env [ " PATH " ] = " "
env [ " PATH " ] = env [ " PATH " ] + " ; " + _get_system_root ( repository_ctx ) + " \\ system32 "
return env
2019-10-24 14:01:01 +00:00
def _find_vc_path ( repository_ctx ) :
2019-08-21 14:29:46 +00:00
""" Find Visual C++ build tools install path. Doesn ' t %-e scape the result. """
# 1. Check if BAZEL_VC or BAZEL_VS is already set by user.
bazel_vc = _get_path_env_var ( repository_ctx , " BAZEL_VC " )
if bazel_vc :
if repository_ctx . path ( bazel_vc ) . exists :
return bazel_vc
else :
auto_configure_warning_maybe (
repository_ctx ,
" % BAZEL_VC % i s set to non-existent path, ignoring. " ,
)
bazel_vs = _get_path_env_var ( repository_ctx , " BAZEL_VS " )
if bazel_vs :
if repository_ctx . path ( bazel_vs ) . exists :
bazel_vc = bazel_vs + " \\ VC "
if repository_ctx . path ( bazel_vc ) . exists :
return bazel_vc
else :
auto_configure_warning_maybe (
repository_ctx ,
" No ' VC ' directory found under % BAZEL_VS % , ignoring. " ,
)
else :
auto_configure_warning_maybe (
repository_ctx ,
" % BAZEL_VS % i s set to non-existent path, ignoring. " ,
)
auto_configure_warning_maybe (
repository_ctx ,
" Neither % BAZEL_VC % nor % BAZEL_VS % a re set, start looking for the latest Visual C++ " +
" installed. " ,
)
# 2. Check if VS%VS_VERSION%COMNTOOLS is set, if true then try to find and use
# vcvarsqueryregistry.bat / VsDevCmd.bat to detect VC++.
auto_configure_warning_maybe ( repository_ctx , " Looking for VS % VERSION % COMNTOOLS environment variables, " +
" eg. VS140COMNTOOLS " )
for vscommontools_env , script in [
( " VS160COMNTOOLS " , " VsDevCmd.bat " ) ,
( " VS150COMNTOOLS " , " VsDevCmd.bat " ) ,
( " VS140COMNTOOLS " , " vcvarsqueryregistry.bat " ) ,
( " VS120COMNTOOLS " , " vcvarsqueryregistry.bat " ) ,
( " VS110COMNTOOLS " , " vcvarsqueryregistry.bat " ) ,
( " VS100COMNTOOLS " , " vcvarsqueryregistry.bat " ) ,
( " VS90COMNTOOLS " , " vcvarsqueryregistry.bat " ) ,
] :
if vscommontools_env not in repository_ctx . os . environ :
continue
script = _get_path_env_var ( repository_ctx , vscommontools_env ) + " \\ " + script
if not repository_ctx . path ( script ) . exists :
continue
repository_ctx . file (
" get_vc_dir.bat " ,
" @echo off \n " +
" call \" " + script + " \" \n " +
" echo % VCINSTALLDIR % " ,
True ,
)
env = _add_system_root ( repository_ctx , repository_ctx . os . environ )
vc_dir = execute ( repository_ctx , [ " ./get_vc_dir.bat " ] , environment = env )
auto_configure_warning_maybe ( repository_ctx , " Visual C++ build tools found at %s " % vc_dir )
return vc_dir
# 3. User might have purged all environment variables. If so, look for Visual C++ in registry.
# Works for Visual Studio 2017 and older. (Does not work for Visual Studio 2019 Preview.)
# TODO(laszlocsomor): check if "16.0" also has this registry key, after VS 2019 is released.
auto_configure_warning_maybe ( repository_ctx , " Looking for Visual C++ through registry " )
reg_binary = _get_system_root ( repository_ctx ) + " \\ system32 \\ reg.exe "
vc_dir = None
for key , suffix in ( ( " VC7 " , " " ) , ( " VS7 " , " \\ VC " ) ) :
for version in [ " 15.0 " , " 14.0 " , " 12.0 " , " 11.0 " , " 10.0 " , " 9.0 " , " 8.0 " ] :
if vc_dir :
break
result = repository_ctx . execute ( [ reg_binary , " query " , " HKEY_LOCAL_MACHINE \\ SOFTWARE \\ Wow6432Node \\ Microsoft \\ VisualStudio \\ SxS \\ " + key , " /v " , version ] )
auto_configure_warning_maybe ( repository_ctx , " registry query result for VC %s : \n \n STDOUT(start) \n %s \n STDOUT(end) \n STDERR(start): \n %s \n STDERR(end) \n " %
( version , result . stdout , result . stderr ) )
if not result . stderr :
for line in result . stdout . split ( " \n " ) :
line = line . strip ( )
if line . startswith ( version ) and line . find ( " REG_SZ " ) != - 1 :
vc_dir = line [ line . find ( " REG_SZ " ) + len ( " REG_SZ " ) : ] . strip ( ) + suffix
if vc_dir :
auto_configure_warning_maybe ( repository_ctx , " Visual C++ build tools found at %s " % vc_dir )
return vc_dir
# 4. Check default directories for VC installation
auto_configure_warning_maybe ( repository_ctx , " Looking for default Visual C++ installation directory " )
program_files_dir = _get_path_env_var ( repository_ctx , " PROGRAMFILES(X86) " )
if not program_files_dir :
program_files_dir = " C: \\ Program Files (x86) "
auto_configure_warning_maybe (
repository_ctx ,
" ' PROGRAMFILES(X86) ' environment variable is not set, using ' %s ' as default " % program_files_dir ,
)
for path in [
" Microsoft Visual Studio \\ 2019 \\ Preview \\ VC " ,
" Microsoft Visual Studio \\ 2019 \\ BuildTools \\ VC " ,
" Microsoft Visual Studio \\ 2019 \\ Community \\ VC " ,
" Microsoft Visual Studio \\ 2019 \\ Professional \\ VC " ,
" Microsoft Visual Studio \\ 2019 \\ Enterprise \\ VC " ,
" Microsoft Visual Studio \\ 2017 \\ BuildTools \\ VC " ,
" Microsoft Visual Studio \\ 2017 \\ Community \\ VC " ,
" Microsoft Visual Studio \\ 2017 \\ Professional \\ VC " ,
" Microsoft Visual Studio \\ 2017 \\ Enterprise \\ VC " ,
" Microsoft Visual Studio 14.0 \\ VC " ,
] :
path = program_files_dir + " \\ " + path
if repository_ctx . path ( path ) . exists :
vc_dir = path
break
if not vc_dir :
auto_configure_warning_maybe ( repository_ctx , " Visual C++ build tools not found. " )
return None
auto_configure_warning_maybe ( repository_ctx , " Visual C++ build tools found at %s " % vc_dir )
return vc_dir
def _is_vs_2017_or_2019 ( vc_path ) :
""" Check if the installed VS version is Visual Studio 2017. """
# In VS 2017 and 2019, the location of VC is like:
# C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\
# In VS 2015 or older version, it is like:
# C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\
return vc_path . find ( " 2017 " ) != - 1 or vc_path . find ( " 2019 " ) != - 1
def _find_vcvars_bat_script ( repository_ctx , vc_path ) :
""" Find batch script to set up environment variables for VC. Doesn ' t %-e scape the result. """
if _is_vs_2017_or_2019 ( vc_path ) :
vcvars_script = vc_path + " \\ Auxiliary \\ Build \\ VCVARSALL.BAT "
else :
vcvars_script = vc_path + " \\ VCVARSALL.BAT "
if not repository_ctx . path ( vcvars_script ) . exists :
return None
return vcvars_script
def _is_support_vcvars_ver ( vc_full_version ) :
""" -vcvars_ver option is supported from version 14.11.25503 (VS 2017 version 15.3). """
version = [ int ( i ) for i in vc_full_version . split ( " . " ) ]
min_version = [ 14 , 11 , 25503 ]
return version > = min_version
def _is_support_winsdk_selection ( repository_ctx , vc_path ) :
""" Windows SDK selection is supported with VC 2017 / 2019 or with full VS 2015 installation. """
if _is_vs_2017_or_2019 ( vc_path ) :
return True
# By checking the source code of VCVARSALL.BAT in VC 2015, we know that
# when devenv.exe or wdexpress.exe exists, VCVARSALL.BAT supports Windows SDK selection.
vc_common_ide = repository_ctx . path ( vc_path ) . dirname . get_child ( " Common7 " ) . get_child ( " IDE " )
for tool in [ " devenv.exe " , " wdexpress.exe " ] :
if vc_common_ide . get_child ( tool ) . exists :
return True
return False
def setup_vc_env_vars ( repository_ctx , vc_path , envvars = [ ] , allow_empty = False , escape = True ) :
""" Get environment variables set by VCVARSALL.BAT script. Doesn ' t %-e scape the result!
Args :
repository_ctx : the repository_ctx object
vc_path : Visual C + + root directory
envvars : list of envvars to retrieve ; default is [ " PATH " , " INCLUDE " , " LIB " , " WINDOWSSDKDIR " ]
allow_empty : allow unset envvars ; if False then report errors for those
escape : if True , escape " \" as " \\" and " % " as " % % " in the envvar values
Returns :
dictionary of the envvars
"""
if not envvars :
envvars = [ " PATH " , " INCLUDE " , " LIB " , " WINDOWSSDKDIR " ]
vcvars_script = _find_vcvars_bat_script ( repository_ctx , vc_path )
if not vcvars_script :
auto_configure_fail ( " Cannot find VCVARSALL.BAT script under %s " % vc_path )
# Getting Windows SDK version set by user.
# Only supports VC 2017 & 2019 and VC 2015 with full VS installation.
winsdk_version = _get_winsdk_full_version ( repository_ctx )
if winsdk_version and not _is_support_winsdk_selection ( repository_ctx , vc_path ) :
auto_configure_warning ( ( " BAZEL_WINSDK_FULL_VERSION= %s is ignored, " +
" because standalone Visual C++ Build Tools 2015 doesn ' t support specifying Windows " +
" SDK version, please install the full VS 2015 or use VC 2017/2019. " ) % winsdk_version )
winsdk_version = " "
# Get VC version set by user. Only supports VC 2017 & 2019.
vcvars_ver = " "
if _is_vs_2017_or_2019 ( vc_path ) :
full_version = _get_vc_full_version ( repository_ctx , vc_path )
# Because VCVARSALL.BAT is from the latest VC installed, so we check if the latest
# version supports -vcvars_ver or not.
if _is_support_vcvars_ver ( _get_latest_subversion ( repository_ctx , vc_path ) ) :
vcvars_ver = " -vcvars_ver= " + full_version
cmd = " \" %s \" amd64 %s %s " % ( vcvars_script , winsdk_version , vcvars_ver )
print_envvars = " , " . join ( [ " {k} = % {k} % " . format ( k = k ) for k in envvars ] )
repository_ctx . file (
" get_env.bat " ,
" @echo off \n " +
( " call %s > NUL \n " % cmd ) + ( " echo %s \n " % print_envvars ) ,
True ,
)
env = _add_system_root ( repository_ctx , { k : " " for k in envvars } )
envs = execute ( repository_ctx , [ " ./get_env.bat " ] , environment = env ) . split ( " , " )
env_map = { }
for env in envs :
key , value = env . split ( " = " , 1 )
env_map [ key ] = escape_string ( value . replace ( " \\ " , " \\ \\ " ) ) if escape else value
if not allow_empty :
_check_env_vars ( env_map , cmd , expected = envvars )
return env_map
def _check_env_vars ( env_map , cmd , expected ) :
for env in expected :
if not env_map . get ( env ) :
auto_configure_fail (
" Setting up VC environment variables failed, %s is not set by the following command: \n %s " % ( env , cmd ) ,
)
def _get_latest_subversion ( repository_ctx , vc_path ) :
""" Get the latest subversion of a VS 2017/2019 installation.
For VS 2017 & 2019 , there could be multiple versions of VC build tools .
The directories are like :
< vc_path > \\Tools \\MSVC \\14.10 .24930 \\bin \\HostX64 \\x64
< vc_path > \\Tools \\MSVC \\14.16 .27023 \\bin \\HostX64 \\x64
This function should return 14.16 .27023 in this case . """
versions = [ path . basename for path in repository_ctx . path ( vc_path + " \\ Tools \\ MSVC " ) . readdir ( ) ]
if len ( versions ) < 1 :
auto_configure_warning_maybe ( repository_ctx , " Cannot find any VC installation under BAZEL_VC( %s ) " % vc_path )
return None
# Parse the version string into integers, then sort the integers to prevent textual sorting.
version_list = [ ]
for version in versions :
parts = [ int ( i ) for i in version . split ( " . " ) ]
version_list . append ( ( parts , version ) )
version_list = sorted ( version_list )
latest_version = version_list [ - 1 ] [ 1 ]
auto_configure_warning_maybe ( repository_ctx , " Found the following VC verisons: \n %s \n \n Choosing the latest version = %s " % ( " \n " . join ( versions ) , latest_version ) )
return latest_version
def _get_vc_full_version ( repository_ctx , vc_path ) :
""" Return the value of BAZEL_VC_FULL_VERSION if defined, otherwise the latest version. """
if " BAZEL_VC_FULL_VERSION " in repository_ctx . os . environ :
return repository_ctx . os . environ [ " BAZEL_VC_FULL_VERSION " ]
return _get_latest_subversion ( repository_ctx , vc_path )
def _get_winsdk_full_version ( repository_ctx ) :
""" Return the value of BAZEL_WINSDK_FULL_VERSION if defined, otherwise an empty string. """
return repository_ctx . os . environ . get ( " BAZEL_WINSDK_FULL_VERSION " , default = " " )
2019-10-24 14:01:01 +00:00
def _find_msvc_tool ( repository_ctx , vc_path , tool ) :
2019-08-21 14:29:46 +00:00
""" Find the exact path of a specific build tool in MSVC. Doesn ' t %-e scape the result. """
tool_path = None
if _is_vs_2017_or_2019 ( vc_path ) :
full_version = _get_vc_full_version ( repository_ctx , vc_path )
if full_version :
tool_path = " %s \\ Tools \\ MSVC \\ %s \\ bin \\ HostX64 \\ x64 \\ %s " % ( vc_path , full_version , tool )
else :
# For VS 2015 and older version, the tools are under:
# C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64
tool_path = vc_path + " \\ bin \\ amd64 \\ " + tool
if not tool_path or not repository_ctx . path ( tool_path ) . exists :
return None
return tool_path . replace ( " \\ " , " / " )
def _find_missing_vc_tools ( repository_ctx , vc_path ) :
""" Check if any required tool is missing under given VC path. """
missing_tools = [ ]
if not _find_vcvars_bat_script ( repository_ctx , vc_path ) :
missing_tools . append ( " VCVARSALL.BAT " )
for tool in [ " cl.exe " , " link.exe " , " lib.exe " , " ml64.exe " ] :
2019-10-24 14:01:01 +00:00
if not _find_msvc_tool ( repository_ctx , vc_path , tool ) :
2019-08-21 14:29:46 +00:00
missing_tools . append ( tool )
return missing_tools
def _is_support_debug_fastlink ( repository_ctx , linker ) :
""" Run linker alone to see if it supports /DEBUG:FASTLINK. """
if _use_clang_cl ( repository_ctx ) :
# LLVM's lld-link.exe doesn't support /DEBUG:FASTLINK.
return False
result = execute ( repository_ctx , [ linker ] , expect_failure = True )
return result . find ( " /DEBUG[: { FASTLINK|FULL|NONE}] " ) != - 1
2019-10-24 14:01:01 +00:00
def _find_llvm_path ( repository_ctx ) :
2019-08-21 14:29:46 +00:00
""" Find LLVM install path. """
# 1. Check if BAZEL_LLVM is already set by user.
bazel_llvm = _get_path_env_var ( repository_ctx , " BAZEL_LLVM " )
if bazel_llvm :
return bazel_llvm
auto_configure_warning_maybe ( repository_ctx , " ' BAZEL_LLVM ' is not set, " +
" start looking for LLVM installation on machine. " )
# 2. Look for LLVM installation through registry.
auto_configure_warning_maybe ( repository_ctx , " Looking for LLVM installation through registry " )
reg_binary = _get_system_root ( repository_ctx ) + " \\ system32 \\ reg.exe "
llvm_dir = None
result = repository_ctx . execute ( [ reg_binary , " query " , " HKEY_LOCAL_MACHINE \\ SOFTWARE \\ WOW6432Node \\ LLVM \\ LLVM " ] )
auto_configure_warning_maybe ( repository_ctx , " registry query result for LLVM: \n \n STDOUT(start) \n %s \n STDOUT(end) \n STDERR(start): \n %s \n STDERR(end) \n " %
( result . stdout , result . stderr ) )
if not result . stderr :
for line in result . stdout . split ( " \n " ) :
line = line . strip ( )
if line . startswith ( " (Default) " ) and line . find ( " REG_SZ " ) != - 1 :
llvm_dir = line [ line . find ( " REG_SZ " ) + len ( " REG_SZ " ) : ] . strip ( )
if llvm_dir :
auto_configure_warning_maybe ( repository_ctx , " LLVM installation found at %s " % llvm_dir )
return llvm_dir
# 3. Check default directories for LLVM installation
auto_configure_warning_maybe ( repository_ctx , " Looking for default LLVM installation directory " )
program_files_dir = _get_path_env_var ( repository_ctx , " PROGRAMFILES " )
if not program_files_dir :
program_files_dir = " C: \\ Program Files "
auto_configure_warning_maybe (
repository_ctx ,
" ' PROGRAMFILES ' environment variable is not set, using ' %s ' as default " % program_files_dir ,
)
path = program_files_dir + " \\ LLVM "
if repository_ctx . path ( path ) . exists :
llvm_dir = path
if not llvm_dir :
auto_configure_warning_maybe ( repository_ctx , " LLVM installation not found. " )
return None
auto_configure_warning_maybe ( repository_ctx , " LLVM installation found at %s " % llvm_dir )
return llvm_dir
2019-10-24 14:01:01 +00:00
def _find_llvm_tool ( repository_ctx , llvm_path , tool ) :
2019-08-21 14:29:46 +00:00
""" Find the exact path of a specific build tool in LLVM. Doesn ' t %-e scape the result. """
tool_path = llvm_path + " \\ bin \\ " + tool
if not repository_ctx . path ( tool_path ) . exists :
return None
return tool_path . replace ( " \\ " , " / " )
def _use_clang_cl ( repository_ctx ) :
""" Returns True if USE_CLANG_CL is set to 1. """
return repository_ctx . os . environ . get ( " USE_CLANG_CL " , default = " 0 " ) == " 1 "
def _find_missing_llvm_tools ( repository_ctx , llvm_path ) :
""" Check if any required tool is missing under given LLVM path. """
missing_tools = [ ]
for tool in [ " clang-cl.exe " , " lld-link.exe " , " llvm-lib.exe " ] :
2019-10-24 14:01:01 +00:00
if not _find_llvm_tool ( repository_ctx , llvm_path , tool ) :
2019-08-21 14:29:46 +00:00
missing_tools . append ( tool )
return missing_tools
def _get_clang_version ( repository_ctx , clang_cl ) :
result = repository_ctx . execute ( [ clang_cl , " -v " ] )
if result . return_code != 0 :
auto_configure_fail ( " Failed to get clang version by running \" %s -v \" " % clang_cl )
# Stderr should look like "clang version X.X.X ..."
2020-11-03 21:24:08 +00:00
return result . stderr . splitlines ( ) [ 0 ] . split ( " " ) [ 2 ]
2019-08-21 14:29:46 +00:00
def _get_msys_mingw_vars ( repository_ctx ) :
""" Get the variables we need to populate the msys/mingw toolchains. """
tool_paths , tool_bin_path , inc_dir_msys = _get_escaped_windows_msys_starlark_content ( repository_ctx )
tool_paths_mingw , tool_bin_path_mingw , inc_dir_mingw = _get_escaped_windows_msys_starlark_content ( repository_ctx , use_mingw = True )
2019-09-03 09:30:13 +00:00
write_builtin_include_directory_paths ( repository_ctx , " mingw " , [ inc_dir_mingw ] , file_suffix = " _mingw " )
2019-08-21 14:29:46 +00:00
msys_mingw_vars = {
" % {cxx_builtin_include_directories} " : inc_dir_msys ,
" % {mingw_cxx_builtin_include_directories} " : inc_dir_mingw ,
2019-10-24 14:01:01 +00:00
" % {mingw_tool_bin_path} " : tool_bin_path_mingw ,
2019-08-21 14:29:46 +00:00
" % {mingw_tool_paths} " : tool_paths_mingw ,
" % {tool_bin_path} " : tool_bin_path ,
2019-10-24 14:01:01 +00:00
" % {tool_paths} " : tool_paths ,
2019-08-21 14:29:46 +00:00
}
return msys_mingw_vars
def _get_msvc_vars ( repository_ctx , paths ) :
""" Get the variables we need to populate the MSVC toolchains. """
msvc_vars = dict ( )
2019-10-24 14:01:01 +00:00
vc_path = _find_vc_path ( repository_ctx )
2019-08-21 14:29:46 +00:00
missing_tools = None
if not vc_path :
repository_ctx . template (
" vc_installation_error.bat " ,
paths [ " @rules_cc//cc/private/toolchain:vc_installation_error.bat.tpl " ] ,
{ " % {vc_error_message} " : " " } ,
)
else :
missing_tools = _find_missing_vc_tools ( repository_ctx , vc_path )
if missing_tools :
message = " \r \n " . join ( [
" echo. 1>&2 " ,
" echo Visual C++ build tools seems to be installed at %s 1>&2 " % vc_path ,
" echo But Bazel can ' t find the following tools: 1>&2 " ,
" echo %s 1>&2 " % " , " . join ( missing_tools ) ,
" echo. 1>&2 " ,
] )
repository_ctx . template (
" vc_installation_error.bat " ,
paths [ " @rules_cc//cc/private/toolchain:vc_installation_error.bat.tpl " ] ,
{ " % {vc_error_message} " : message } ,
)
if not vc_path or missing_tools :
2019-09-03 09:30:13 +00:00
write_builtin_include_directory_paths ( repository_ctx , " msvc " , [ ] , file_suffix = " _msvc " )
2019-08-21 14:29:46 +00:00
msvc_vars = {
" % {dbg_mode_debug_flag} " : " /DEBUG " ,
" % {fastbuild_mode_debug_flag} " : " /DEBUG " ,
2019-10-24 14:01:01 +00:00
" % {msvc_cl_path} " : " vc_installation_error.bat " ,
2019-08-21 14:29:46 +00:00
" % {msvc_cxx_builtin_include_directories} " : " " ,
2019-10-24 14:01:01 +00:00
" % {msvc_env_include} " : " msvc_not_found " ,
" % {msvc_env_lib} " : " msvc_not_found " ,
" % {msvc_env_path} " : " msvc_not_found " ,
" % {msvc_env_tmp} " : " msvc_not_found " ,
" % {msvc_lib_path} " : " vc_installation_error.bat " ,
" % {msvc_link_path} " : " vc_installation_error.bat " ,
" % {msvc_ml_path} " : " vc_installation_error.bat " ,
2019-08-21 14:29:46 +00:00
}
return msvc_vars
env = setup_vc_env_vars ( repository_ctx , vc_path )
escaped_paths = escape_string ( env [ " PATH " ] )
escaped_include_paths = escape_string ( env [ " INCLUDE " ] )
escaped_lib_paths = escape_string ( env [ " LIB " ] )
escaped_tmp_dir = escape_string ( _get_temp_env ( repository_ctx ) . replace ( " \\ " , " \\ \\ " ) )
llvm_path = " "
if _use_clang_cl ( repository_ctx ) :
2019-10-24 14:01:01 +00:00
llvm_path = _find_llvm_path ( repository_ctx )
2019-08-21 14:29:46 +00:00
if not llvm_path :
auto_configure_fail ( " \n USE_CLANG_CL is set to 1, but Bazel cannot find Clang installation on your system. \n " +
" Please install Clang via http://releases.llvm.org/download.html \n " )
2019-10-24 14:01:01 +00:00
cl_path = _find_llvm_tool ( repository_ctx , llvm_path , " clang-cl.exe " )
link_path = _find_llvm_tool ( repository_ctx , llvm_path , " lld-link.exe " )
2019-08-21 14:29:46 +00:00
if not link_path :
2019-10-24 14:01:01 +00:00
link_path = _find_msvc_tool ( repository_ctx , vc_path , " link.exe " )
lib_path = _find_llvm_tool ( repository_ctx , llvm_path , " llvm-lib.exe " )
2019-08-21 14:29:46 +00:00
if not lib_path :
2019-10-24 14:01:01 +00:00
lib_path = _find_msvc_tool ( repository_ctx , vc_path , " lib.exe " )
2019-08-21 14:29:46 +00:00
else :
2019-10-24 14:01:01 +00:00
cl_path = _find_msvc_tool ( repository_ctx , vc_path , " cl.exe " )
link_path = _find_msvc_tool ( repository_ctx , vc_path , " link.exe " )
lib_path = _find_msvc_tool ( repository_ctx , vc_path , " lib.exe " )
2019-08-21 14:29:46 +00:00
2019-10-24 14:01:01 +00:00
msvc_ml_path = _find_msvc_tool ( repository_ctx , vc_path , " ml64.exe " )
2019-08-21 14:29:46 +00:00
escaped_cxx_include_directories = [ ]
for path in escaped_include_paths . split ( " ; " ) :
if path :
escaped_cxx_include_directories . append ( " \" %s \" " % path )
if llvm_path :
clang_version = _get_clang_version ( repository_ctx , cl_path )
clang_dir = llvm_path + " \\ lib \\ clang \\ " + clang_version
clang_include_path = ( clang_dir + " \\ include " ) . replace ( " \\ " , " \\ \\ " )
escaped_cxx_include_directories . append ( " \" %s \" " % clang_include_path )
clang_lib_path = ( clang_dir + " \\ lib \\ windows " ) . replace ( " \\ " , " \\ \\ " )
escaped_lib_paths = escaped_lib_paths + " ; " + clang_lib_path
support_debug_fastlink = _is_support_debug_fastlink ( repository_ctx , link_path )
2019-09-03 09:30:13 +00:00
write_builtin_include_directory_paths ( repository_ctx , " msvc " , escaped_cxx_include_directories , file_suffix = " _msvc " )
2019-08-21 14:29:46 +00:00
msvc_vars = {
" % {dbg_mode_debug_flag} " : " /DEBUG:FULL " if support_debug_fastlink else " /DEBUG " ,
" % {fastbuild_mode_debug_flag} " : " /DEBUG:FASTLINK " if support_debug_fastlink else " /DEBUG " ,
2019-10-24 14:01:01 +00:00
" % {msvc_cl_path} " : cl_path ,
2019-08-21 14:29:46 +00:00
" % {msvc_cxx_builtin_include_directories} " : " " + " , \n " . join ( escaped_cxx_include_directories ) ,
2019-10-24 14:01:01 +00:00
" % {msvc_env_include} " : escaped_include_paths ,
" % {msvc_env_lib} " : escaped_lib_paths ,
" % {msvc_env_path} " : escaped_paths ,
" % {msvc_env_tmp} " : escaped_tmp_dir ,
" % {msvc_lib_path} " : lib_path ,
" % {msvc_link_path} " : link_path ,
" % {msvc_ml_path} " : msvc_ml_path ,
2019-08-21 14:29:46 +00:00
}
return msvc_vars
def _get_clang_cl_vars ( repository_ctx , paths , msvc_vars ) :
""" Get the variables we need to populate the clang-cl toolchains. """
2019-10-24 14:01:01 +00:00
llvm_path = _find_llvm_path ( repository_ctx )
2019-08-21 14:29:46 +00:00
error_script = None
if msvc_vars [ " % {msvc_cl_path} " ] == " vc_installation_error.bat " :
error_script = " vc_installation_error.bat "
elif not llvm_path :
repository_ctx . template (
" clang_installation_error.bat " ,
paths [ " @rules_cc//cc/private/toolchain:clang_installation_error.bat.tpl " ] ,
{ " % {clang_error_message} " : " " } ,
)
error_script = " clang_installation_error.bat "
else :
missing_tools = _find_missing_llvm_tools ( repository_ctx , llvm_path )
if missing_tools :
message = " \r \n " . join ( [
" echo. 1>&2 " ,
" echo LLVM/Clang seems to be installed at %s 1>&2 " % llvm_path ,
" echo But Bazel can ' t find the following tools: 1>&2 " ,
" echo %s 1>&2 " % " , " . join ( missing_tools ) ,
" echo. 1>&2 " ,
] )
repository_ctx . template (
" clang_installation_error.bat " ,
2019-09-03 09:51:10 +00:00
paths [ " @rules_cc//cc/private/toolchain:clang_installation_error.bat.tpl " ] ,
2019-08-21 14:29:46 +00:00
{ " % {clang_error_message} " : message } ,
)
error_script = " clang_installation_error.bat "
if error_script :
2019-09-03 09:30:13 +00:00
write_builtin_include_directory_paths ( repository_ctx , " clang-cl " , [ ] , file_suffix = " _clangcl " )
2019-08-21 14:29:46 +00:00
clang_cl_vars = {
2019-10-24 14:01:01 +00:00
" % {clang_cl_cl_path} " : error_script ,
" % {clang_cl_cxx_builtin_include_directories} " : " " ,
" % {clang_cl_dbg_mode_debug_flag} " : " /DEBUG " ,
2019-08-21 14:29:46 +00:00
" % {clang_cl_env_include} " : " clang_cl_not_found " ,
" % {clang_cl_env_lib} " : " clang_cl_not_found " ,
2019-10-24 14:01:01 +00:00
" % {clang_cl_env_path} " : " clang_cl_not_found " ,
" % {clang_cl_env_tmp} " : " clang_cl_not_found " ,
" % {clang_cl_fastbuild_mode_debug_flag} " : " /DEBUG " ,
2019-08-21 14:29:46 +00:00
" % {clang_cl_lib_path} " : error_script ,
2019-10-24 14:01:01 +00:00
" % {clang_cl_link_path} " : error_script ,
2019-08-21 14:29:46 +00:00
" % {clang_cl_ml_path} " : error_script ,
}
return clang_cl_vars
2019-10-24 14:01:01 +00:00
clang_cl_path = _find_llvm_tool ( repository_ctx , llvm_path , " clang-cl.exe " )
lld_link_path = _find_llvm_tool ( repository_ctx , llvm_path , " lld-link.exe " )
llvm_lib_path = _find_llvm_tool ( repository_ctx , llvm_path , " llvm-lib.exe " )
2019-08-21 14:29:46 +00:00
clang_version = _get_clang_version ( repository_ctx , clang_cl_path )
clang_dir = llvm_path + " \\ lib \\ clang \\ " + clang_version
clang_include_path = ( clang_dir + " \\ include " ) . replace ( " \\ " , " \\ \\ " )
clang_lib_path = ( clang_dir + " \\ lib \\ windows " ) . replace ( " \\ " , " \\ \\ " )
2019-09-03 09:30:13 +00:00
clang_cl_include_directories = msvc_vars [ " % {msvc_cxx_builtin_include_directories} " ] + ( " , \n \" %s \" " % clang_include_path )
write_builtin_include_directory_paths ( repository_ctx , " clang-cl " , [ clang_cl_include_directories ] , file_suffix = " _clangcl " )
2019-08-21 14:29:46 +00:00
clang_cl_vars = {
" % {clang_cl_cl_path} " : clang_cl_path ,
2019-10-24 14:01:01 +00:00
" % {clang_cl_cxx_builtin_include_directories} " : clang_cl_include_directories ,
2019-08-21 14:29:46 +00:00
# LLVM's lld-link.exe doesn't support /DEBUG:FASTLINK.
" % {clang_cl_dbg_mode_debug_flag} " : " /DEBUG " ,
2019-10-24 14:01:01 +00:00
" % {clang_cl_env_include} " : msvc_vars [ " % {msvc_env_include} " ] + " ; " + clang_include_path ,
" % {clang_cl_env_lib} " : msvc_vars [ " % {msvc_env_lib} " ] + " ; " + clang_lib_path ,
" % {clang_cl_env_path} " : msvc_vars [ " % {msvc_env_path} " ] ,
" % {clang_cl_env_tmp} " : msvc_vars [ " % {msvc_env_tmp} " ] ,
2019-08-21 14:29:46 +00:00
" % {clang_cl_fastbuild_mode_debug_flag} " : " /DEBUG " ,
2019-10-24 14:01:01 +00:00
" % {clang_cl_lib_path} " : llvm_lib_path ,
" % {clang_cl_link_path} " : lld_link_path ,
" % {clang_cl_ml_path} " : msvc_vars [ " % {msvc_ml_path} " ] ,
2019-08-21 14:29:46 +00:00
}
return clang_cl_vars
def configure_windows_toolchain ( repository_ctx ) :
2019-10-24 14:01:01 +00:00
""" Configure C++ toolchain on Windows.
Args :
repository_ctx : The repository context .
"""
2019-08-21 14:29:46 +00:00
paths = resolve_labels ( repository_ctx , [
" @rules_cc//cc/private/toolchain:BUILD.windows.tpl " ,
" @rules_cc//cc/private/toolchain:windows_cc_toolchain_config.bzl " ,
" @rules_cc//cc/private/toolchain:armeabi_cc_toolchain_config.bzl " ,
" @rules_cc//cc/private/toolchain:vc_installation_error.bat.tpl " ,
" @rules_cc//cc/private/toolchain:msys_gcc_installation_error.bat " ,
" @rules_cc//cc/private/toolchain:clang_installation_error.bat.tpl " ,
] )
repository_ctx . symlink (
paths [ " @rules_cc//cc/private/toolchain:windows_cc_toolchain_config.bzl " ] ,
" windows_cc_toolchain_config.bzl " ,
)
repository_ctx . symlink (
paths [ " @rules_cc//cc/private/toolchain:armeabi_cc_toolchain_config.bzl " ] ,
" armeabi_cc_toolchain_config.bzl " ,
)
repository_ctx . symlink (
paths [ " @rules_cc//cc/private/toolchain:msys_gcc_installation_error.bat " ] ,
" msys_gcc_installation_error.bat " ,
)
template_vars = dict ( )
msvc_vars = _get_msvc_vars ( repository_ctx , paths )
template_vars . update ( msvc_vars )
template_vars . update ( _get_clang_cl_vars ( repository_ctx , paths , msvc_vars ) )
template_vars . update ( _get_msys_mingw_vars ( repository_ctx ) )
repository_ctx . template (
" BUILD " ,
paths [ " @rules_cc//cc/private/toolchain:BUILD.windows.tpl " ] ,
template_vars ,
)