blob: dcdf3d6f843ee846d824cd82e64635f04fa60d2a [file] [log] [blame]
Yun Peng65cda4f2017-06-22 11:06:11 +02001# pylint: disable=g-bad-file-header
2# Copyright 2016 The Bazel Authors. All rights reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15"""Configuring the C++ toolchain on Windows."""
16
17load(
18 "@bazel_tools//tools/cpp:lib_cc_configure.bzl",
Yun Peng65cda4f2017-06-22 11:06:11 +020019 "auto_configure_fail",
20 "auto_configure_warning",
Marcel Hlopkoff6fa782019-06-04 05:52:05 -070021 "auto_configure_warning_maybe",
vladmos20a042f2018-06-01 04:51:21 -070022 "escape_string",
Yun Peng65cda4f2017-06-22 11:06:11 +020023 "execute",
jmmv5b025592018-05-29 12:03:21 -070024 "resolve_labels",
Yun Peng65cda4f2017-06-22 11:06:11 +020025)
26
Laszlo Csomor63d4f112019-05-14 06:40:26 -070027def _get_path_env_var(repository_ctx, name):
28 """Returns a path from an environment variable.
29
30 Removes quotes, replaces '/' with '\', and strips trailing '\'s."""
31 if name in repository_ctx.os.environ:
32 value = repository_ctx.os.environ[name]
33 if value[0] == "\"":
34 if len(value) == 1 or value[-1] != "\"":
35 auto_configure_fail("'%s' environment variable has no trailing quote" % name)
36 value = value[1:-1]
37 if "/" in value:
38 value = value.replace("/", "\\")
39 if value[-1] == "\\":
40 value = value.rstrip("\\")
41 return value
42 else:
43 return None
44
45def _get_temp_env(repository_ctx):
Marwan Tammam20c84132019-06-04 07:27:31 -070046 """Returns the value of TMP, or TEMP, or if both undefined then C:\\Windows."""
Laszlo Csomor63d4f112019-05-14 06:40:26 -070047 tmp = _get_path_env_var(repository_ctx, "TMP")
48 if not tmp:
49 tmp = _get_path_env_var(repository_ctx, "TEMP")
50 if not tmp:
51 tmp = "C:\\Windows\\Temp"
52 auto_configure_warning(
53 "neither 'TMP' nor 'TEMP' environment variables are set, using '%s' as default" % tmp,
54 )
55 return tmp
56
rosica71bc38f2019-02-04 02:39:30 -080057def _get_escaped_windows_msys_starlark_content(repository_ctx, use_mingw = False):
58 """Return the content of msys cc toolchain rule."""
Yun Pengf66086d2018-10-24 08:33:09 -070059 msys_root = ""
Laszlo Csomor63d4f112019-05-14 06:40:26 -070060 bazel_sh = _get_path_env_var(repository_ctx, "BAZEL_SH")
61 if bazel_sh:
62 bazel_sh = bazel_sh.replace("\\", "/").lower()
63 tokens = bazel_sh.rsplit("/", 1)
64 if tokens[0].endswith("/usr/bin"):
65 msys_root = tokens[0][:len(tokens[0]) - len("usr/bin")]
66 elif tokens[0].endswith("/bin"):
67 msys_root = tokens[0][:len(tokens[0]) - len("bin")]
68
Yun Pengf66086d2018-10-24 08:33:09 -070069 prefix = "mingw64" if use_mingw else "usr"
70 tool_path_prefix = escape_string(msys_root) + prefix
pcloudy511fe9b2018-11-19 03:27:09 -080071 tool_bin_path = tool_path_prefix + "/bin"
Yun Pengf66086d2018-10-24 08:33:09 -070072 tool_path = {}
73
74 for tool in ["ar", "compat-ld", "cpp", "dwp", "gcc", "gcov", "ld", "nm", "objcopy", "objdump", "strip"]:
75 if msys_root:
pcloudy511fe9b2018-11-19 03:27:09 -080076 tool_path[tool] = tool_bin_path + "/" + tool
Yun Pengf66086d2018-10-24 08:33:09 -070077 else:
78 tool_path[tool] = "msys_gcc_installation_error.bat"
rosicabeaba922019-05-20 02:36:26 -070079 tool_paths = ",\n ".join(['"%s": "%s"' % (k, v) for k, v in tool_path.items()])
rosica71bc38f2019-02-04 02:39:30 -080080 include_directories = (' "%s/",\n ' % tool_path_prefix) if msys_root else ""
rosicabeaba922019-05-20 02:36:26 -070081 return tool_paths, tool_bin_path, include_directories
Yun Peng65cda4f2017-06-22 11:06:11 +020082
Yun Peng65cda4f2017-06-22 11:06:11 +020083def _get_system_root(repository_ctx):
Marwan Tammam20c84132019-06-04 07:27:31 -070084 """Get System root path on Windows, default is C:\\Windows. Doesn't %-escape the result."""
Laszlo Csomor63d4f112019-05-14 06:40:26 -070085 systemroot = _get_path_env_var(repository_ctx, "SYSTEMROOT")
86 if not systemroot:
87 systemroot = "C:\\Windows"
Marcel Hlopkoff6fa782019-06-04 05:52:05 -070088 auto_configure_warning_maybe(
Laszlo Csomor63d4f112019-05-14 06:40:26 -070089 repository_ctx,
90 "SYSTEMROOT is not set, using default SYSTEMROOT=C:\\Windows",
91 )
92 return escape_string(systemroot)
Yun Peng65cda4f2017-06-22 11:06:11 +020093
Yun Peng65cda4f2017-06-22 11:06:11 +020094def _add_system_root(repository_ctx, env):
vladmos20a042f2018-06-01 04:51:21 -070095 """Running VCVARSALL.BAT and VCVARSQUERYREGISTRY.BAT need %SYSTEMROOT%\\\\system32 in PATH."""
96 if "PATH" not in env:
97 env["PATH"] = ""
98 env["PATH"] = env["PATH"] + ";" + _get_system_root(repository_ctx) + "\\system32"
99 return env
Yun Peng65cda4f2017-06-22 11:06:11 +0200100
Yun Pengff12a222017-12-01 07:27:24 -0800101def find_vc_path(repository_ctx):
vladmos20a042f2018-06-01 04:51:21 -0700102 """Find Visual C++ build tools install path. Doesn't %-escape the result."""
Yun Peng65cda4f2017-06-22 11:06:11 +0200103
vladmos20a042f2018-06-01 04:51:21 -0700104 # 1. Check if BAZEL_VC or BAZEL_VS is already set by user.
Laszlo Csomor63d4f112019-05-14 06:40:26 -0700105 bazel_vc = _get_path_env_var(repository_ctx, "BAZEL_VC")
106 if bazel_vc:
107 if repository_ctx.path(bazel_vc).exists:
108 return bazel_vc
109 else:
Marcel Hlopkoff6fa782019-06-04 05:52:05 -0700110 auto_configure_warning_maybe(
Laszlo Csomor63d4f112019-05-14 06:40:26 -0700111 repository_ctx,
112 "%BAZEL_VC% is set to non-existent path, ignoring.",
113 )
Yun Peng65cda4f2017-06-22 11:06:11 +0200114
Laszlo Csomor63d4f112019-05-14 06:40:26 -0700115 bazel_vs = _get_path_env_var(repository_ctx, "BAZEL_VS")
116 if bazel_vs:
117 if repository_ctx.path(bazel_vs).exists:
118 bazel_vc = bazel_vs + "\\VC"
119 if repository_ctx.path(bazel_vc).exists:
120 return bazel_vc
121 else:
Marcel Hlopkoff6fa782019-06-04 05:52:05 -0700122 auto_configure_warning_maybe(
Laszlo Csomor63d4f112019-05-14 06:40:26 -0700123 repository_ctx,
124 "No 'VC' directory found under %BAZEL_VS%, ignoring.",
125 )
126 else:
Marcel Hlopkoff6fa782019-06-04 05:52:05 -0700127 auto_configure_warning_maybe(
Laszlo Csomor63d4f112019-05-14 06:40:26 -0700128 repository_ctx,
129 "%BAZEL_VS% is set to non-existent path, ignoring.",
130 )
131
Marcel Hlopkoff6fa782019-06-04 05:52:05 -0700132 auto_configure_warning_maybe(
Laszlo Csomor63d4f112019-05-14 06:40:26 -0700133 repository_ctx,
134 "Neither %BAZEL_VC% nor %BAZEL_VS% are set, start looking for the latest Visual C++" +
135 " installed.",
136 )
Yun Peng65cda4f2017-06-22 11:06:11 +0200137
vladmos20a042f2018-06-01 04:51:21 -0700138 # 2. Check if VS%VS_VERSION%COMNTOOLS is set, if true then try to find and use
Laszlo Csomor18d70242019-04-03 00:38:02 -0700139 # vcvarsqueryregistry.bat / VsDevCmd.bat to detect VC++.
Marcel Hlopkoff6fa782019-06-04 05:52:05 -0700140 auto_configure_warning_maybe(repository_ctx, "Looking for VS%VERSION%COMNTOOLS environment variables, " +
141 "eg. VS140COMNTOOLS")
Laszlo Csomor18d70242019-04-03 00:38:02 -0700142 for vscommontools_env, script in [
143 ("VS160COMNTOOLS", "VsDevCmd.bat"),
144 ("VS150COMNTOOLS", "VsDevCmd.bat"),
145 ("VS140COMNTOOLS", "vcvarsqueryregistry.bat"),
146 ("VS120COMNTOOLS", "vcvarsqueryregistry.bat"),
147 ("VS110COMNTOOLS", "vcvarsqueryregistry.bat"),
148 ("VS100COMNTOOLS", "vcvarsqueryregistry.bat"),
149 ("VS90COMNTOOLS", "vcvarsqueryregistry.bat"),
vladmos20a042f2018-06-01 04:51:21 -0700150 ]:
151 if vscommontools_env not in repository_ctx.os.environ:
152 continue
Laszlo Csomor63d4f112019-05-14 06:40:26 -0700153 script = _get_path_env_var(repository_ctx, vscommontools_env) + "\\" + script
Laszlo Csomor18d70242019-04-03 00:38:02 -0700154 if not repository_ctx.path(script).exists:
vladmos20a042f2018-06-01 04:51:21 -0700155 continue
156 repository_ctx.file(
157 "get_vc_dir.bat",
158 "@echo off\n" +
Laszlo Csomor18d70242019-04-03 00:38:02 -0700159 "call \"" + script + "\"\n" +
vladmos20a042f2018-06-01 04:51:21 -0700160 "echo %VCINSTALLDIR%",
161 True,
162 )
163 env = _add_system_root(repository_ctx, repository_ctx.os.environ)
164 vc_dir = execute(repository_ctx, ["./get_vc_dir.bat"], environment = env)
165
Marcel Hlopkoff6fa782019-06-04 05:52:05 -0700166 auto_configure_warning_maybe(repository_ctx, "Visual C++ build tools found at %s" % vc_dir)
vladmos20a042f2018-06-01 04:51:21 -0700167 return vc_dir
168
Laszlo Csomor18d70242019-04-03 00:38:02 -0700169 # 3. User might have purged all environment variables. If so, look for Visual C++ in registry.
170 # Works for Visual Studio 2017 and older. (Does not work for Visual Studio 2019 Preview.)
171 # TODO(laszlocsomor): check if "16.0" also has this registry key, after VS 2019 is released.
Marcel Hlopkoff6fa782019-06-04 05:52:05 -0700172 auto_configure_warning_maybe(repository_ctx, "Looking for Visual C++ through registry")
vladmos20a042f2018-06-01 04:51:21 -0700173 reg_binary = _get_system_root(repository_ctx) + "\\system32\\reg.exe"
174 vc_dir = None
175 for key, suffix in (("VC7", ""), ("VS7", "\\VC")):
176 for version in ["15.0", "14.0", "12.0", "11.0", "10.0", "9.0", "8.0"]:
177 if vc_dir:
178 break
179 result = repository_ctx.execute([reg_binary, "query", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\" + key, "/v", version])
Marcel Hlopkoff6fa782019-06-04 05:52:05 -0700180 auto_configure_warning_maybe(repository_ctx, "registry query result for VC %s:\n\nSTDOUT(start)\n%s\nSTDOUT(end)\nSTDERR(start):\n%s\nSTDERR(end)\n" %
181 (version, result.stdout, result.stderr))
vladmos20a042f2018-06-01 04:51:21 -0700182 if not result.stderr:
183 for line in result.stdout.split("\n"):
184 line = line.strip()
185 if line.startswith(version) and line.find("REG_SZ") != -1:
186 vc_dir = line[line.find("REG_SZ") + len("REG_SZ"):].strip() + suffix
Yun Pengf445af52018-11-02 07:55:01 -0700187 if vc_dir:
Marcel Hlopkoff6fa782019-06-04 05:52:05 -0700188 auto_configure_warning_maybe(repository_ctx, "Visual C++ build tools found at %s" % vc_dir)
Yun Pengf445af52018-11-02 07:55:01 -0700189 return vc_dir
vladmos20a042f2018-06-01 04:51:21 -0700190
pcloudydf427892018-07-04 06:32:33 -0700191 # 4. Check default directories for VC installation
Marcel Hlopkoff6fa782019-06-04 05:52:05 -0700192 auto_configure_warning_maybe(repository_ctx, "Looking for default Visual C++ installation directory")
Laszlo Csomor63d4f112019-05-14 06:40:26 -0700193 program_files_dir = _get_path_env_var(repository_ctx, "PROGRAMFILES(X86)")
194 if not program_files_dir:
195 program_files_dir = "C:\\Program Files (x86)"
Marcel Hlopkoff6fa782019-06-04 05:52:05 -0700196 auto_configure_warning_maybe(
Laszlo Csomor63d4f112019-05-14 06:40:26 -0700197 repository_ctx,
198 "'PROGRAMFILES(X86)' environment variable is not set, using '%s' as default" % program_files_dir,
199 )
pcloudydf427892018-07-04 06:32:33 -0700200 for path in [
Laszlo Csomor18d70242019-04-03 00:38:02 -0700201 "Microsoft Visual Studio\\2019\\Preview\\VC",
202 "Microsoft Visual Studio\\2019\\BuildTools\\VC",
203 "Microsoft Visual Studio\\2019\\Community\\VC",
204 "Microsoft Visual Studio\\2019\\Professional\\VC",
205 "Microsoft Visual Studio\\2019\\Enterprise\\VC",
pcloudydf427892018-07-04 06:32:33 -0700206 "Microsoft Visual Studio\\2017\\BuildTools\\VC",
207 "Microsoft Visual Studio\\2017\\Community\\VC",
Gregor Jasny7f9de5d2018-08-20 09:00:36 -0700208 "Microsoft Visual Studio\\2017\\Professional\\VC",
pcloudydf427892018-07-04 06:32:33 -0700209 "Microsoft Visual Studio\\2017\\Enterprise\\VC",
210 "Microsoft Visual Studio 14.0\\VC",
211 ]:
212 path = program_files_dir + "\\" + path
213 if repository_ctx.path(path).exists:
214 vc_dir = path
215 break
216
vladmos20a042f2018-06-01 04:51:21 -0700217 if not vc_dir:
Marcel Hlopkoff6fa782019-06-04 05:52:05 -0700218 auto_configure_warning_maybe(repository_ctx, "Visual C++ build tools not found.")
vladmos20a042f2018-06-01 04:51:21 -0700219 return None
Marcel Hlopkoff6fa782019-06-04 05:52:05 -0700220 auto_configure_warning_maybe(repository_ctx, "Visual C++ build tools found at %s" % vc_dir)
Yun Peng65cda4f2017-06-22 11:06:11 +0200221 return vc_dir
222
Laszlo Csomor18d70242019-04-03 00:38:02 -0700223def _is_vs_2017_or_2019(vc_path):
vladmos20a042f2018-06-01 04:51:21 -0700224 """Check if the installed VS version is Visual Studio 2017."""
225
Laszlo Csomor18d70242019-04-03 00:38:02 -0700226 # In VS 2017 and 2019, the location of VC is like:
vladmos20a042f2018-06-01 04:51:21 -0700227 # C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\
228 # In VS 2015 or older version, it is like:
229 # C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\
Laszlo Csomor18d70242019-04-03 00:38:02 -0700230 return vc_path.find("2017") != -1 or vc_path.find("2019") != -1
Yun Peng65cda4f2017-06-22 11:06:11 +0200231
Yun Peng65cda4f2017-06-22 11:06:11 +0200232def _find_vcvarsall_bat_script(repository_ctx, vc_path):
vladmos20a042f2018-06-01 04:51:21 -0700233 """Find vcvarsall.bat script. Doesn't %-escape the result."""
Laszlo Csomor18d70242019-04-03 00:38:02 -0700234 if _is_vs_2017_or_2019(vc_path):
vladmos20a042f2018-06-01 04:51:21 -0700235 vcvarsall = vc_path + "\\Auxiliary\\Build\\VCVARSALL.BAT"
236 else:
237 vcvarsall = vc_path + "\\VCVARSALL.BAT"
Yun Peng65cda4f2017-06-22 11:06:11 +0200238
vladmos20a042f2018-06-01 04:51:21 -0700239 if not repository_ctx.path(vcvarsall).exists:
240 return None
Yun Peng7284d6e2018-03-14 04:13:54 -0700241
vladmos20a042f2018-06-01 04:51:21 -0700242 return vcvarsall
Yun Peng65cda4f2017-06-22 11:06:11 +0200243
Yun Penga3dd7772018-03-22 03:09:32 -0700244def setup_vc_env_vars(repository_ctx, vc_path):
vladmos20a042f2018-06-01 04:51:21 -0700245 """Get environment variables set by VCVARSALL.BAT. Doesn't %-escape the result!"""
246 vcvarsall = _find_vcvarsall_bat_script(repository_ctx, vc_path)
247 if not vcvarsall:
248 return None
Yun Penge5b7bd62019-05-21 01:26:45 -0700249 vcvars_ver = ""
250 if _is_vs_2017_or_2019(vc_path):
251 full_version = _get_vc_full_version(repository_ctx, vc_path)
252 if full_version:
253 vcvars_ver = "-vcvars_ver=" + full_version
vladmos20a042f2018-06-01 04:51:21 -0700254 repository_ctx.file(
255 "get_env.bat",
256 "@echo off\n" +
Yun Penge5b7bd62019-05-21 01:26:45 -0700257 ("call \"%s\" amd64 %s > NUL \n" % (vcvarsall, vcvars_ver)) +
vladmos20a042f2018-06-01 04:51:21 -0700258 "echo PATH=%PATH%,INCLUDE=%INCLUDE%,LIB=%LIB%,WINDOWSSDKDIR=%WINDOWSSDKDIR% \n",
259 True,
260 )
261 env = _add_system_root(
262 repository_ctx,
263 {"PATH": "", "INCLUDE": "", "LIB": "", "WINDOWSSDKDIR": ""},
264 )
265 envs = execute(repository_ctx, ["./get_env.bat"], environment = env).split(",")
266 env_map = {}
267 for env in envs:
268 key, value = env.split("=", 1)
269 env_map[key] = escape_string(value.replace("\\", "\\\\"))
270 return env_map
Yun Peng65cda4f2017-06-22 11:06:11 +0200271
Yun Penge5b7bd62019-05-21 01:26:45 -0700272def _get_latest_subversion(repository_ctx, vc_path):
273 """Get the latest subversion of a VS 2017/2019 installation.
274
275 For VS 2017 & 2019, there could be multiple versions of VC build tools.
276 The directories are like:
277 <vc_path>\\Tools\\MSVC\\14.10.24930\\bin\\HostX64\\x64
278 <vc_path>\\Tools\\MSVC\\14.16.27023\\bin\\HostX64\\x64
279 This function should return 14.16.27023 in this case."""
280 versions = [path.basename for path in repository_ctx.path(vc_path + "\\Tools\\MSVC").readdir()]
281 if len(versions) < 1:
Marcel Hlopkoff6fa782019-06-04 05:52:05 -0700282 auto_configure_warning_maybe(repository_ctx, "Cannot find any VC installation under BAZEL_VC(%s)" % vc_path)
Yun Penge5b7bd62019-05-21 01:26:45 -0700283 return None
284
285 # Parse the version string into integers, then sort the integers to prevent textual sorting.
286 version_list = []
287 for version in versions:
288 parts = [int(i) for i in version.split(".")]
289 version_list.append((parts, version))
290
291 version_list = sorted(version_list)
292 latest_version = version_list[-1][1]
293
Marcel Hlopkoff6fa782019-06-04 05:52:05 -0700294 auto_configure_warning_maybe(repository_ctx, "Found the following VC verisons:\n%s\n\nChoosing the latest version = %s" % ("\n".join(versions), latest_version))
Yun Penge5b7bd62019-05-21 01:26:45 -0700295 return latest_version
296
297def _get_vc_full_version(repository_ctx, vc_path):
298 """Return the value of BAZEL_VC_FULL_VERSION if defined, otherwise the latest version."""
299 if "BAZEL_VC_FULL_VERSION" in repository_ctx.os.environ:
300 return repository_ctx.os.environ["BAZEL_VC_FULL_VERSION"]
301 return _get_latest_subversion(repository_ctx, vc_path)
302
Yun Pengff12a222017-12-01 07:27:24 -0800303def find_msvc_tool(repository_ctx, vc_path, tool):
vladmos20a042f2018-06-01 04:51:21 -0700304 """Find the exact path of a specific build tool in MSVC. Doesn't %-escape the result."""
Yun Penge5b7bd62019-05-21 01:26:45 -0700305 tool_path = None
Laszlo Csomor18d70242019-04-03 00:38:02 -0700306 if _is_vs_2017_or_2019(vc_path):
Yun Penge5b7bd62019-05-21 01:26:45 -0700307 full_version = _get_vc_full_version(repository_ctx, vc_path)
308 if full_version:
309 tool_path = "%s\\Tools\\MSVC\\%s\\bin\\HostX64\\x64\\%s" % (vc_path, full_version, tool)
vladmos20a042f2018-06-01 04:51:21 -0700310 else:
311 # For VS 2015 and older version, the tools are under:
312 # C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64
313 tool_path = vc_path + "\\bin\\amd64\\" + tool
Yun Peng7284d6e2018-03-14 04:13:54 -0700314
Yun Penge5b7bd62019-05-21 01:26:45 -0700315 if not tool_path or not repository_ctx.path(tool_path).exists:
vladmos20a042f2018-06-01 04:51:21 -0700316 return None
317
Yun Pengf445af52018-11-02 07:55:01 -0700318 return tool_path.replace("\\", "/")
Yun Peng65cda4f2017-06-22 11:06:11 +0200319
Yun Peng7284d6e2018-03-14 04:13:54 -0700320def _find_missing_vc_tools(repository_ctx, vc_path):
vladmos20a042f2018-06-01 04:51:21 -0700321 """Check if any required tool is missing under given VC path."""
322 missing_tools = []
323 if not _find_vcvarsall_bat_script(repository_ctx, vc_path):
324 missing_tools.append("VCVARSALL.BAT")
Yun Peng7284d6e2018-03-14 04:13:54 -0700325
vladmos20a042f2018-06-01 04:51:21 -0700326 for tool in ["cl.exe", "link.exe", "lib.exe", "ml64.exe"]:
327 if not find_msvc_tool(repository_ctx, vc_path, tool):
328 missing_tools.append(tool)
Yun Peng7284d6e2018-03-14 04:13:54 -0700329
vladmos20a042f2018-06-01 04:51:21 -0700330 return missing_tools
Yun Peng7284d6e2018-03-14 04:13:54 -0700331
Yun Pengf445af52018-11-02 07:55:01 -0700332def _is_support_debug_fastlink(repository_ctx, linker):
333 """Run linker alone to see if it supports /DEBUG:FASTLINK."""
334 if _use_clang_cl(repository_ctx):
335 # LLVM's lld-link.exe doesn't support /DEBUG:FASTLINK.
336 return False
vladmos20a042f2018-06-01 04:51:21 -0700337 result = execute(repository_ctx, [linker], expect_failure = True)
338 return result.find("/DEBUG[:{FASTLINK|FULL|NONE}]") != -1
Yun Peng09a6a9f2017-12-11 07:24:45 -0800339
Yun Pengf445af52018-11-02 07:55:01 -0700340def find_llvm_path(repository_ctx):
341 """Find LLVM install path."""
342
343 # 1. Check if BAZEL_LLVM is already set by user.
Laszlo Csomor63d4f112019-05-14 06:40:26 -0700344 bazel_llvm = _get_path_env_var(repository_ctx, "BAZEL_LLVM")
345 if bazel_llvm:
346 return bazel_llvm
Yun Pengf445af52018-11-02 07:55:01 -0700347
Marcel Hlopkoff6fa782019-06-04 05:52:05 -0700348 auto_configure_warning_maybe(repository_ctx, "'BAZEL_LLVM' is not set, " +
349 "start looking for LLVM installation on machine.")
Yun Pengf445af52018-11-02 07:55:01 -0700350
351 # 2. Look for LLVM installation through registry.
Marcel Hlopkoff6fa782019-06-04 05:52:05 -0700352 auto_configure_warning_maybe(repository_ctx, "Looking for LLVM installation through registry")
Yun Pengf445af52018-11-02 07:55:01 -0700353 reg_binary = _get_system_root(repository_ctx) + "\\system32\\reg.exe"
354 llvm_dir = None
355 result = repository_ctx.execute([reg_binary, "query", "HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\LLVM\\LLVM"])
Marcel Hlopkoff6fa782019-06-04 05:52:05 -0700356 auto_configure_warning_maybe(repository_ctx, "registry query result for LLVM:\n\nSTDOUT(start)\n%s\nSTDOUT(end)\nSTDERR(start):\n%s\nSTDERR(end)\n" %
357 (result.stdout, result.stderr))
Yun Pengf445af52018-11-02 07:55:01 -0700358 if not result.stderr:
359 for line in result.stdout.split("\n"):
360 line = line.strip()
361 if line.startswith("(Default)") and line.find("REG_SZ") != -1:
362 llvm_dir = line[line.find("REG_SZ") + len("REG_SZ"):].strip()
363 if llvm_dir:
Marcel Hlopkoff6fa782019-06-04 05:52:05 -0700364 auto_configure_warning_maybe(repository_ctx, "LLVM installation found at %s" % llvm_dir)
Yun Pengf445af52018-11-02 07:55:01 -0700365 return llvm_dir
366
367 # 3. Check default directories for LLVM installation
Marcel Hlopkoff6fa782019-06-04 05:52:05 -0700368 auto_configure_warning_maybe(repository_ctx, "Looking for default LLVM installation directory")
Laszlo Csomor63d4f112019-05-14 06:40:26 -0700369 program_files_dir = _get_path_env_var(repository_ctx, "PROGRAMFILES")
370 if not program_files_dir:
371 program_files_dir = "C:\\Program Files"
Marcel Hlopkoff6fa782019-06-04 05:52:05 -0700372 auto_configure_warning_maybe(
Laszlo Csomor63d4f112019-05-14 06:40:26 -0700373 repository_ctx,
374 "'PROGRAMFILES' environment variable is not set, using '%s' as default" % program_files_dir,
375 )
Yun Pengf445af52018-11-02 07:55:01 -0700376 path = program_files_dir + "\\LLVM"
377 if repository_ctx.path(path).exists:
378 llvm_dir = path
379
380 if not llvm_dir:
Marcel Hlopkoff6fa782019-06-04 05:52:05 -0700381 auto_configure_warning_maybe(repository_ctx, "LLVM installation not found.")
Yun Pengf445af52018-11-02 07:55:01 -0700382 return None
Marcel Hlopkoff6fa782019-06-04 05:52:05 -0700383 auto_configure_warning_maybe(repository_ctx, "LLVM installation found at %s" % llvm_dir)
Yun Pengf445af52018-11-02 07:55:01 -0700384 return llvm_dir
385
386def find_llvm_tool(repository_ctx, llvm_path, tool):
387 """Find the exact path of a specific build tool in LLVM. Doesn't %-escape the result."""
388 tool_path = llvm_path + "\\bin\\" + tool
389
390 if not repository_ctx.path(tool_path).exists:
391 return None
392
393 return tool_path.replace("\\", "/")
394
395def _use_clang_cl(repository_ctx):
396 """Returns True if USE_CLANG_CL is set to 1."""
397 return repository_ctx.os.environ.get("USE_CLANG_CL", default = "0") == "1"
398
Yun Peng009e6c02018-12-03 05:31:26 -0800399def _get_clang_version(repository_ctx, clang_cl):
400 result = repository_ctx.execute([clang_cl, "-v"])
401 if result.return_code != 0:
402 auto_configure_fail("Failed to get clang version by running \"%s -v\"" % clang_cl)
403
404 # Stderr should look like "clang version X.X.X ..."
405 return result.stderr.strip().split(" ")[2]
406
Yun Peng65cda4f2017-06-22 11:06:11 +0200407def configure_windows_toolchain(repository_ctx):
vladmos20a042f2018-06-01 04:51:21 -0700408 """Configure C++ toolchain on Windows."""
409 paths = resolve_labels(repository_ctx, [
rosicabeaba922019-05-20 02:36:26 -0700410 "@bazel_tools//tools/cpp:BUILD.windows.tpl",
411 "@bazel_tools//tools/cpp:windows_cc_toolchain_config.bzl",
412 "@bazel_tools//tools/cpp:armeabi_cc_toolchain_config.bzl",
vladmos20a042f2018-06-01 04:51:21 -0700413 "@bazel_tools//tools/cpp:vc_installation_error.bat.tpl",
Yun Pengf66086d2018-10-24 08:33:09 -0700414 "@bazel_tools//tools/cpp:msys_gcc_installation_error.bat",
vladmos20a042f2018-06-01 04:51:21 -0700415 ])
jmmv5b025592018-05-29 12:03:21 -0700416
rosicabeaba922019-05-20 02:36:26 -0700417 repository_ctx.symlink(
418 paths["@bazel_tools//tools/cpp:windows_cc_toolchain_config.bzl"],
419 "windows_cc_toolchain_config.bzl",
420 )
421 repository_ctx.symlink(
422 paths["@bazel_tools//tools/cpp:armeabi_cc_toolchain_config.bzl"],
423 "armeabi_cc_toolchain_config.bzl",
424 )
Yun Pengf66086d2018-10-24 08:33:09 -0700425 repository_ctx.symlink(
426 paths["@bazel_tools//tools/cpp:msys_gcc_installation_error.bat"],
427 "msys_gcc_installation_error.bat",
428 )
Yun Peng65cda4f2017-06-22 11:06:11 +0200429
vladmos20a042f2018-06-01 04:51:21 -0700430 vc_path = find_vc_path(repository_ctx)
431 missing_tools = None
432 if not vc_path:
433 repository_ctx.template(
434 "vc_installation_error.bat",
435 paths["@bazel_tools//tools/cpp:vc_installation_error.bat.tpl"],
436 {"%{vc_error_message}": ""},
437 )
438 else:
439 missing_tools = _find_missing_vc_tools(repository_ctx, vc_path)
440 if missing_tools:
441 message = "\r\n".join([
442 "echo. 1>&2",
443 "echo Visual C++ build tools seems to be installed at %s 1>&2" % vc_path,
444 "echo But Bazel can't find the following tools: 1>&2",
445 "echo %s 1>&2" % ", ".join(missing_tools),
446 "echo. 1>&2",
447 ])
448 repository_ctx.template(
449 "vc_installation_error.bat",
450 paths["@bazel_tools//tools/cpp:vc_installation_error.bat.tpl"],
451 {"%{vc_error_message}": message},
452 )
Yun Peng7284d6e2018-03-14 04:13:54 -0700453
rosicabeaba922019-05-20 02:36:26 -0700454 tool_paths_mingw, tool_bin_path_mingw, inc_dir_mingw = _get_escaped_windows_msys_starlark_content(repository_ctx, use_mingw = True)
455 tool_paths, tool_bin_path, inc_dir_msys = _get_escaped_windows_msys_starlark_content(repository_ctx)
vladmos20a042f2018-06-01 04:51:21 -0700456 if not vc_path or missing_tools:
457 repository_ctx.template(
rosicabeaba922019-05-20 02:36:26 -0700458 "BUILD",
459 paths["@bazel_tools//tools/cpp:BUILD.windows.tpl"],
vladmos20a042f2018-06-01 04:51:21 -0700460 {
pcloudy56366ee2019-03-07 07:48:17 -0800461 "%{msvc_env_tmp}": "msvc_not_found",
462 "%{msvc_env_path}": "msvc_not_found",
463 "%{msvc_env_include}": "msvc_not_found",
464 "%{msvc_env_lib}": "msvc_not_found",
vladmos20a042f2018-06-01 04:51:21 -0700465 "%{msvc_cl_path}": "vc_installation_error.bat",
466 "%{msvc_ml_path}": "vc_installation_error.bat",
467 "%{msvc_link_path}": "vc_installation_error.bat",
468 "%{msvc_lib_path}": "vc_installation_error.bat",
rosicabeaba922019-05-20 02:36:26 -0700469 "%{dbg_mode_debug_flag}": "/DEBUG",
470 "%{fastbuild_mode_debug_flag}": "/DEBUG",
pcloudyb1370712019-04-05 03:05:53 -0700471 "%{cxx_builtin_include_directories}": inc_dir_msys,
rosica71bc38f2019-02-04 02:39:30 -0800472 "%{mingw_cxx_builtin_include_directories}": inc_dir_mingw,
rosicabeaba922019-05-20 02:36:26 -0700473 "%{msvc_cxx_builtin_include_directories}": "",
rosica71bc38f2019-02-04 02:39:30 -0800474 "%{tool_paths}": tool_paths,
475 "%{mingw_tool_paths}": tool_paths_mingw,
rosica71bc38f2019-02-04 02:39:30 -0800476 "%{tool_bin_path}": tool_bin_path,
477 "%{mingw_tool_bin_path}": tool_bin_path_mingw,
vladmos20a042f2018-06-01 04:51:21 -0700478 },
479 )
480 return
481
482 env = setup_vc_env_vars(repository_ctx, vc_path)
483 escaped_paths = escape_string(env["PATH"])
484 escaped_include_paths = escape_string(env["INCLUDE"])
485 escaped_lib_paths = escape_string(env["LIB"])
Laszlo Csomor63d4f112019-05-14 06:40:26 -0700486 escaped_tmp_dir = escape_string(_get_temp_env(repository_ctx).replace("\\", "\\\\"))
Yun Pengf445af52018-11-02 07:55:01 -0700487
488 llvm_path = ""
489 if _use_clang_cl(repository_ctx):
490 llvm_path = find_llvm_path(repository_ctx)
491 if not llvm_path:
492 auto_configure_fail("\nUSE_CLANG_CL is set to 1, but Bazel cannot find Clang installation on your system.\n" +
493 "Please install Clang via http://releases.llvm.org/download.html\n")
494 cl_path = find_llvm_tool(repository_ctx, llvm_path, "clang-cl.exe")
495 link_path = find_llvm_tool(repository_ctx, llvm_path, "lld-link.exe")
Yun Peng009e6c02018-12-03 05:31:26 -0800496 if not link_path:
497 link_path = find_msvc_tool(repository_ctx, vc_path, "link.exe")
Yun Pengf445af52018-11-02 07:55:01 -0700498 lib_path = find_llvm_tool(repository_ctx, llvm_path, "llvm-lib.exe")
Yun Peng009e6c02018-12-03 05:31:26 -0800499 if not lib_path:
500 lib_path = find_msvc_tool(repository_ctx, vc_path, "lib.exe")
Yun Pengf445af52018-11-02 07:55:01 -0700501 else:
502 cl_path = find_msvc_tool(repository_ctx, vc_path, "cl.exe")
503 link_path = find_msvc_tool(repository_ctx, vc_path, "link.exe")
504 lib_path = find_msvc_tool(repository_ctx, vc_path, "lib.exe")
505
506 msvc_ml_path = find_msvc_tool(repository_ctx, vc_path, "ml64.exe")
vladmos20a042f2018-06-01 04:51:21 -0700507 escaped_cxx_include_directories = []
vladmos20a042f2018-06-01 04:51:21 -0700508
509 for path in escaped_include_paths.split(";"):
510 if path:
rosica71bc38f2019-02-04 02:39:30 -0800511 escaped_cxx_include_directories.append("\"%s\"" % path)
Yun Pengf445af52018-11-02 07:55:01 -0700512 if llvm_path:
Yun Peng009e6c02018-12-03 05:31:26 -0800513 clang_version = _get_clang_version(repository_ctx, cl_path)
514 clang_dir = llvm_path + "\\lib\\clang\\" + clang_version
515 clang_include_path = (clang_dir + "\\include").replace("\\", "\\\\")
rosica71bc38f2019-02-04 02:39:30 -0800516 escaped_cxx_include_directories.append("\"%s\"" % clang_include_path)
Yun Peng009e6c02018-12-03 05:31:26 -0800517 clang_lib_path = (clang_dir + "\\lib\\windows").replace("\\", "\\\\")
518 escaped_lib_paths = escaped_lib_paths + ";" + clang_lib_path
vladmos20a042f2018-06-01 04:51:21 -0700519
Yun Pengf445af52018-11-02 07:55:01 -0700520 support_debug_fastlink = _is_support_debug_fastlink(repository_ctx, link_path)
vladmos20a042f2018-06-01 04:51:21 -0700521
jmmv5b025592018-05-29 12:03:21 -0700522 repository_ctx.template(
rosicabeaba922019-05-20 02:36:26 -0700523 "BUILD",
524 paths["@bazel_tools//tools/cpp:BUILD.windows.tpl"],
jmmv5b025592018-05-29 12:03:21 -0700525 {
vladmos20a042f2018-06-01 04:51:21 -0700526 "%{msvc_env_tmp}": escaped_tmp_dir,
527 "%{msvc_env_path}": escaped_paths,
528 "%{msvc_env_include}": escaped_include_paths,
529 "%{msvc_env_lib}": escaped_lib_paths,
Yun Pengf445af52018-11-02 07:55:01 -0700530 "%{msvc_cl_path}": cl_path,
vladmos20a042f2018-06-01 04:51:21 -0700531 "%{msvc_ml_path}": msvc_ml_path,
Yun Pengf445af52018-11-02 07:55:01 -0700532 "%{msvc_link_path}": link_path,
533 "%{msvc_lib_path}": lib_path,
rosicabeaba922019-05-20 02:36:26 -0700534 "%{dbg_mode_debug_flag}": "/DEBUG:FULL" if support_debug_fastlink else "/DEBUG",
535 "%{fastbuild_mode_debug_flag}": "/DEBUG:FASTLINK" if support_debug_fastlink else "/DEBUG",
pcloudyb1370712019-04-05 03:05:53 -0700536 "%{cxx_builtin_include_directories}": inc_dir_msys + ",\n ".join(escaped_cxx_include_directories),
537 "%{msvc_cxx_builtin_include_directories}": " " + ",\n ".join(escaped_cxx_include_directories),
rosica71bc38f2019-02-04 02:39:30 -0800538 "%{mingw_cxx_builtin_include_directories}": inc_dir_mingw + ",\n ".join(escaped_cxx_include_directories),
rosica71bc38f2019-02-04 02:39:30 -0800539 "%{tool_paths}": tool_paths,
540 "%{mingw_tool_paths}": tool_paths_mingw,
rosica71bc38f2019-02-04 02:39:30 -0800541 "%{tool_bin_path}": tool_bin_path,
542 "%{mingw_tool_bin_path}": tool_bin_path_mingw,
vladmos20a042f2018-06-01 04:51:21 -0700543 },
544 )