blob: 9437bea7fd74504067f295b9ea9dc7ff8be6df46 [file] [log] [blame]
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +00001# Copyright 2016 The Bazel Authors. All rights reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14"""Rules for configuring the C++ toolchain (experimental)."""
15
16
17def _get_value(it):
18 """Convert `it` in serialized protobuf format."""
19 if type(it) == "int":
20 return str(it)
21 elif type(it) == "bool":
22 return "true" if it else "false"
23 else:
24 return "\"%s\"" % it
25
26
27def _build_crosstool(d, prefix=" "):
28 """Convert `d` to a string version of a CROSSTOOL file content."""
29 lines = []
30 for k in d:
31 if type(d[k]) == "list":
32 for it in d[k]:
33 lines.append("%s%s: %s" % (prefix, k, _get_value(it)))
34 else:
35 lines.append("%s%s: %s" % (prefix, k, _get_value(d[k])))
36 return "\n".join(lines)
37
38
39def _build_tool_path(d):
40 """Build the list of tool_path for the CROSSTOOL file."""
41 lines = []
42 for k in d:
43 lines.append(" tool_path {name: \"%s\" path: \"%s\" }" % (k, d[k]))
44 return "\n".join(lines)
45
Yun Peng001aade2016-07-18 11:25:45 +000046def auto_configure_fail(msg):
47 """Output failure message when auto configuration fails."""
48 red = "\033[0;31m"
49 no_color = "\033[0m"
50 fail("\n%sAuto-Configuration Error:%s %s\n" % (red, no_color, msg))
51
52
53def auto_configure_warning(msg):
54 """Output warning message during auto configuration."""
55 yellow = "\033[1;33m"
56 no_color = "\033[0m"
57 print("\n%sAuto-Configuration Warning:%s %s\n" % (yellow, no_color, msg))
58
59
60def _get_env_var(repository_ctx, name, default = None):
61 """Find an environment variable in system path."""
62 if name in repository_ctx.os.environ:
63 return repository_ctx.os.environ[name]
64 if default != None:
65 auto_configure_warning("'%s' environment variable is not set, using '%s' as default" % (name, default))
66 return default
67 auto_configure_fail("'%s' environment variable is not set" % name)
68
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +000069
Yun Penga79581e2016-11-22 14:59:01 +000070def _which(repository_ctx, cmd, default = None):
Damien Martin-Guillerezda258a02016-03-11 22:57:08 +000071 """A wrapper around repository_ctx.which() to provide a fallback value."""
72 result = repository_ctx.which(cmd)
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +000073 return default if result == None else str(result)
74
Yun Peng56b16e72016-07-12 10:55:57 +000075
Yun Peng001aade2016-07-18 11:25:45 +000076def _which_cmd(repository_ctx, cmd, default = None):
Yun Peng44fa4c72016-07-15 08:38:38 +000077 """Find cmd in PATH using repository_ctx.which() and fail if cannot find it."""
78 result = repository_ctx.which(cmd)
Yun Peng001aade2016-07-18 11:25:45 +000079 if result != None:
80 return str(result)
81 path = _get_env_var(repository_ctx, "PATH")
82 if default != None:
83 auto_configure_warning("Cannot find %s in PATH, using '%s' as default.\nPATH=%s" % (cmd, default, path))
84 return default
85 auto_configure_fail("Cannot find %s in PATH, please make sure %s is installed and add its directory in PATH.\nPATH=%s" % (cmd, cmd, path))
Yun Peng44fa4c72016-07-15 08:38:38 +000086 return str(result)
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +000087
Yun Penga4117462016-07-20 14:57:01 +000088
Yun Penge2084282016-11-24 13:54:01 +000089def _execute(repository_ctx, command, environment = None):
Yun Penga4117462016-07-20 14:57:01 +000090 """Execute a command, return stdout if succeed and throw an error if it fails."""
Yun Penge2084282016-11-24 13:54:01 +000091 if environment:
92 result = repository_ctx.execute(command, environment = environment)
93 else:
94 result = repository_ctx.execute(command)
Yun Penga4117462016-07-20 14:57:01 +000095 if result.stderr:
96 auto_configure_fail(result.stderr)
97 else:
98 return result.stdout.strip()
99
100
Damien Martin-Guillerezec2657f2016-05-09 14:30:20 +0000101def _get_tool_paths(repository_ctx, darwin, cc):
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000102 """Compute the path to the various tools."""
Damien Martin-Guillerezda258a02016-03-11 22:57:08 +0000103 return {k: _which(repository_ctx, k, "/usr/bin/" + k)
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000104 for k in [
105 "ld",
106 "cpp",
107 "dwp",
108 "gcov",
109 "nm",
110 "objcopy",
111 "objdump",
112 "strip",
113 ]} + {
Damien Martin-Guillerezec2657f2016-05-09 14:30:20 +0000114 "gcc": cc,
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000115 "ar": "/usr/bin/libtool"
Damien Martin-Guillerezda258a02016-03-11 22:57:08 +0000116 if darwin else _which(repository_ctx, "ar", "/usr/bin/ar")
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000117 }
118
119
Alpha Lamf9276e22016-04-01 09:38:55 +0000120def _cplus_include_paths(repository_ctx):
121 """Use ${CPLUS_INCLUDE_PATH} to compute the list of flags for cxxflag."""
122 if "CPLUS_INCLUDE_PATH" in repository_ctx.os.environ:
123 result = []
124 for p in repository_ctx.os.environ["CPLUS_INCLUDE_PATH"].split(":"):
125 p = str(repository_ctx.path(p)) # Normalize the path
126 result.append("-I" + p)
127 return result
128 else:
129 return []
130
131
Damien Martin-Guillerezda258a02016-03-11 22:57:08 +0000132def _get_cpu_value(repository_ctx):
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000133 """Compute the cpu_value based on the OS name."""
Damien Martin-Guillereza6d9ba72016-03-15 18:18:53 +0000134 os_name = repository_ctx.os.name.lower()
135 if os_name.startswith("mac os"):
136 return "darwin"
Damien Martin-Guillerez9116b3e2016-03-17 20:28:54 +0000137 if os_name.find("freebsd") != -1:
Damien Martin-Guillereza6d9ba72016-03-15 18:18:53 +0000138 return "freebsd"
Damien Martin-Guillerez9116b3e2016-03-17 20:28:54 +0000139 if os_name.find("windows") != -1:
Damien Martin-Guillereza6d9ba72016-03-15 18:18:53 +0000140 return "x64_windows"
Damien Martin-Guillerez0b26f442016-04-19 13:46:01 +0000141 # Use uname to figure out whether we are on x86_32 or x86_64
142 result = repository_ctx.execute(["uname", "-m"])
Nishidha Panpaliyaaaee64e2016-12-20 18:19:43 +0000143 if result.stdout.strip() in ["power", "ppc64le", "ppc"]:
144 return "ppc"
Marcel Hlopko5ab5cbd2017-01-24 12:26:24 +0000145 if result.stdout.strip() in ["arm", "armv7l", "aarch64"]:
146 return "arm"
Damien Martin-Guillerez4caa04f2016-05-11 09:50:38 +0000147 return "k8" if result.stdout.strip() in ["amd64", "x86_64", "x64"] else "piii"
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000148
149
Damien Martin-Guillerezc6da0342016-04-28 08:30:49 +0000150_INC_DIR_MARKER_BEGIN = "#include <...>"
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000151
Damien Martin-Guillerez97e5ab02016-04-19 09:55:21 +0000152# OSX add " (framework directory)" at the end of line, strip it.
153_OSX_FRAMEWORK_SUFFIX = " (framework directory)"
154_OSX_FRAMEWORK_SUFFIX_LEN = len(_OSX_FRAMEWORK_SUFFIX)
155def _cxx_inc_convert(path):
156 """Convert path returned by cc -E xc++ in a complete path."""
157 path = path.strip()
158 if path.endswith(_OSX_FRAMEWORK_SUFFIX):
159 path = path[:-_OSX_FRAMEWORK_SUFFIX_LEN].strip()
160 return path
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000161
Damien Martin-Guillerezda258a02016-03-11 22:57:08 +0000162def _get_cxx_inc_directories(repository_ctx, cc):
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000163 """Compute the list of default C++ include directories."""
Damien Martin-Guillerezda258a02016-03-11 22:57:08 +0000164 result = repository_ctx.execute([cc, "-E", "-xc++", "-", "-v"])
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000165 index1 = result.stderr.find(_INC_DIR_MARKER_BEGIN)
166 if index1 == -1:
167 return []
Damien Martin-Guillerezc6da0342016-04-28 08:30:49 +0000168 index1 = result.stderr.find("\n", index1)
169 if index1 == -1:
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000170 return []
Damien Martin-Guillerezc6da0342016-04-28 08:30:49 +0000171 index2 = result.stderr.rfind("\n ")
172 if index2 == -1 or index2 < index1:
173 return []
174 index2 = result.stderr.find("\n", index2 + 1)
175 if index2 == -1:
176 inc_dirs = result.stderr[index1 + 1:]
177 else:
178 inc_dirs = result.stderr[index1 + 1:index2].strip()
179
Damien Martin-Guillerez97e5ab02016-04-19 09:55:21 +0000180 return [repository_ctx.path(_cxx_inc_convert(p))
181 for p in inc_dirs.split("\n")]
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000182
Dmitry Lomov75855522016-11-21 19:28:33 +0000183def _add_option_if_supported(repository_ctx, cc, option):
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000184 """Checks that `option` is supported by the C compiler."""
Damien Martin-Guillerezda258a02016-03-11 22:57:08 +0000185 result = repository_ctx.execute([
186 cc,
187 option,
188 "-o",
189 "/dev/null",
190 "-c",
191 str(repository_ctx.path("tools/cpp/empty.cc"))
Damien Martin-Guillerez8a9e9ab2016-03-08 15:59:27 +0000192 ])
Dmitry Lomov75855522016-11-21 19:28:33 +0000193 return [option] if result.stderr.find(option) == -1 else []
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000194
Marcel Hlopkoc76c93e2017-01-02 12:32:19 +0000195def _is_gold_supported(repository_ctx, cc):
196 """Checks that `gold` is supported by the C compiler."""
197 result = repository_ctx.execute([
198 cc,
199 "-fuse-ld=gold",
200 "-o",
201 "/dev/null",
202 str(repository_ctx.path("tools/cpp/empty.cc"))
203 ])
204 return result.return_code == 0
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000205
Damien Martin-Guillerezda258a02016-03-11 22:57:08 +0000206def _crosstool_content(repository_ctx, cc, cpu_value, darwin):
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000207 """Return the content for the CROSSTOOL file, in a dictionary."""
Marcel Hlopkoc76c93e2017-01-02 12:32:19 +0000208 supports_gold_linker = _is_gold_supported(repository_ctx, cc)
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000209 return {
210 "abi_version": "local",
211 "abi_libc_version": "local",
212 "builtin_sysroot": "",
213 "compiler": "compiler",
214 "host_system_name": "local",
215 "needsPic": True,
Marcel Hlopkoc76c93e2017-01-02 12:32:19 +0000216 "supports_gold_linker": supports_gold_linker,
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000217 "supports_incremental_linker": False,
218 "supports_fission": False,
219 "supports_interface_shared_objects": False,
220 "supports_normalizing_ar": False,
Marcel Hlopkoc76c93e2017-01-02 12:32:19 +0000221 "supports_start_end_lib": supports_gold_linker,
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000222 "target_libc": "macosx" if darwin else "local",
223 "target_cpu": cpu_value,
224 "target_system_name": "local",
Alpha Lamf9276e22016-04-01 09:38:55 +0000225 "cxx_flag": [
226 "-std=c++0x",
227 ] + _cplus_include_paths(repository_ctx),
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000228 "linker_flag": [
229 "-lstdc++",
Damien Martin-Guillerezefebc4d2016-04-28 14:04:11 +0000230 "-lm", # Some systems expect -lm in addition to -lstdc++
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000231 # Anticipated future default.
Marcel Hlopkoc76c93e2017-01-02 12:32:19 +0000232 ] + (
233 ["-fuse-ld=gold"] if supports_gold_linker else []
234 ) + _add_option_if_supported(
Marcel Hlopko33d9e2a2016-12-07 09:56:07 +0000235 repository_ctx, cc, "-Wl,-no-as-needed"
236 ) + _add_option_if_supported(
237 repository_ctx, cc, "-Wl,-z,relro,-z,now"
238 ) + (
David Chenb86809e2016-05-17 08:29:50 +0000239 [
240 "-undefined",
241 "dynamic_lookup",
242 "-headerpad_max_install_names",
243 ] if darwin else [
Damien Martin-Guillerezda258a02016-03-11 22:57:08 +0000244 "-B" + str(repository_ctx.path(cc).dirname),
Damien Martin-Guillereza20352e2016-04-19 11:47:52 +0000245 # Always have -B/usr/bin, see https://github.com/bazelbuild/bazel/issues/760.
246 "-B/usr/bin",
Damien Martin-Guillerezda258a02016-03-11 22:57:08 +0000247 # Stamp the binary with a unique identifier.
248 "-Wl,--build-id=md5",
249 "-Wl,--hash-style=gnu"
250 # Gold linker only? Can we enable this by default?
251 # "-Wl,--warn-execstack",
252 # "-Wl,--detect-odr-violations"
Marcel Hlopkob5fb12f2016-12-23 08:34:16 +0000253 ] + _add_option_if_supported(
254 # Have gcc return the exit code from ld.
255 repository_ctx, cc, "-pass-exit-codes"
256 )
Marcel Hlopko33d9e2a2016-12-07 09:56:07 +0000257 ),
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000258 "ar_flag": ["-static", "-s", "-o"] if darwin else [],
Damien Martin-Guillerezda258a02016-03-11 22:57:08 +0000259 "cxx_builtin_include_directory": _get_cxx_inc_directories(repository_ctx, cc),
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000260 "objcopy_embed_flag": ["-I", "binary"],
Damien Martin-Guillerez8a9e9ab2016-03-08 15:59:27 +0000261 "unfiltered_cxx_flag":
Marcel Hlopko2354dc02016-12-15 20:09:15 +0000262 # If the compiler sometimes rewrites paths in the .d files without symlinks
263 # (ie when they're shorter), it confuses Bazel's logic for verifying all
264 # #included header files are listed as inputs to the action.
Damien Martin-Guillerezda258a02016-03-11 22:57:08 +0000265 _add_option_if_supported(repository_ctx, cc, "-fno-canonical-system-headers") + [
266 # Make C++ compilation deterministic. Use linkstamping instead of these
267 # compiler symbols.
268 "-Wno-builtin-macro-redefined",
269 "-D__DATE__=\\\"redacted\\\"",
270 "-D__TIMESTAMP__=\\\"redacted\\\"",
271 "-D__TIME__=\\\"redacted\\\""
272 ],
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000273 "compiler_flag": [
Marcel Hlopko5875be72016-12-16 07:15:33 +0000274 # Security hardening requires optimization.
275 # We need to undef it as some distributions now have it enabled by default.
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000276 "-U_FORTIFY_SOURCE",
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000277 "-fstack-protector",
278 # All warnings are enabled. Maybe enable -Werror as well?
279 "-Wall",
280 # Enable a few more warnings that aren't part of -Wall.
281 ] + (["-Wthread-safety", "-Wself-assign"] if darwin else [
Damien Martin-Guillerez810d60a2016-04-22 21:13:48 +0000282 "-B" + str(repository_ctx.path(cc).dirname),
283 # Always have -B/usr/bin, see https://github.com/bazelbuild/bazel/issues/760.
284 "-B/usr/bin",
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000285 ]) + (
Marcel Hlopko33d9e2a2016-12-07 09:56:07 +0000286 # Disable problematic warnings.
Alpha Lamf9276e22016-04-01 09:38:55 +0000287 _add_option_if_supported(repository_ctx, cc, "-Wunused-but-set-parameter") +
Damien Martin-Guillerez8a9e9ab2016-03-08 15:59:27 +0000288 # has false positives
Damien Martin-Guillerezda258a02016-03-11 22:57:08 +0000289 _add_option_if_supported(repository_ctx, cc, "-Wno-free-nonheap-object") +
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000290 # Enable coloring even if there's no attached terminal. Bazel removes the
291 # escape sequences if --nocolor is specified.
Marcel Hlopko2354dc02016-12-15 20:09:15 +0000292 _add_option_if_supported(repository_ctx, cc, "-fcolor-diagnostics")) + [
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000293 # Keep stack frames for debugging, even in opt mode.
294 "-fno-omit-frame-pointer",
295 ],
296 }
297
Yun Peng56b16e72016-07-12 10:55:57 +0000298# TODO(pcloudy): Remove this after MSVC CROSSTOOL becomes default on Windows
299def _get_windows_crosstool_content(repository_ctx):
300 """Return the content of msys crosstool which is still the default CROSSTOOL on Windows."""
Laszlo Csomor46d31b52017-02-01 12:31:01 +0000301 bazel_sh = _get_env_var(repository_ctx, "BAZEL_SH").replace("\\", "/").lower()
302 tokens = bazel_sh.rsplit("/", 1)
303 msys_root = None
304 # while-loops are not supported in order to avoid Turing-completeness.
305 # Use a for-loop, we know it'll halt in at most len(tokens[0]) steps.
306 for _ in range(len(tokens[0])):
307 if len(tokens) < 2:
308 break
309 if tokens[1].startswith("msys"):
310 msys_root = tokens[0] + "/" + tokens[1] + "/"
311 break
312 else:
313 tokens = tokens[0].rsplit("/", 1)
314 if not msys_root:
315 auto_configure_fail(
316 "Could not determine MSYS root from BAZEL_SH (%s)" % bazel_sh)
Yun Peng56b16e72016-07-12 10:55:57 +0000317 return (
318 ' abi_version: "local"\n' +
319 ' abi_libc_version: "local"\n' +
320 ' builtin_sysroot: ""\n' +
321 ' compiler: "windows_msys64"\n' +
322 ' host_system_name: "local"\n' +
323 " needsPic: false\n" +
324 ' target_libc: "local"\n' +
325 ' target_cpu: "x64_windows"\n' +
326 ' target_system_name: "local"\n' +
327 ' tool_path { name: "ar" path: "%susr/bin/ar" }\n' % msys_root +
328 ' tool_path { name: "compat-ld" path: "%susr/bin/ld" }\n' % msys_root +
329 ' tool_path { name: "cpp" path: "%susr/bin/cpp" }\n' % msys_root +
330 ' tool_path { name: "dwp" path: "%susr/bin/dwp" }\n' % msys_root +
331 ' tool_path { name: "gcc" path: "%susr/bin/gcc" }\n' % msys_root +
332 ' cxx_flag: "-std=gnu++0x"\n' +
333 ' linker_flag: "-lstdc++"\n' +
334 ' cxx_builtin_include_directory: "%s"\n' % msys_root +
335 ' cxx_builtin_include_directory: "/usr/"\n' +
336 ' tool_path { name: "gcov" path: "%susr/bin/gcov" }\n' % msys_root +
337 ' tool_path { name: "ld" path: "%susr/bin/ld" }\n' % msys_root +
338 ' tool_path { name: "nm" path: "%susr/bin/nm" }\n' % msys_root +
339 ' tool_path { name: "objcopy" path: "%susr/bin/objcopy" }\n' % msys_root +
340 ' objcopy_embed_flag: "-I"\n' +
341 ' objcopy_embed_flag: "binary"\n' +
342 ' tool_path { name: "objdump" path: "%susr/bin/objdump" }\n' % msys_root +
343 ' tool_path { name: "strip" path: "%susr/bin/strip" }'% msys_root )
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000344
345def _opt_content(darwin):
346 """Return the content of the opt specific section of the CROSSTOOL file."""
347 return {
348 "compiler_flag": [
349 # No debug symbols.
350 # Maybe we should enable https://gcc.gnu.org/wiki/DebugFission for opt or
351 # even generally? However, that can't happen here, as it requires special
352 # handling in Bazel.
353 "-g0",
354
355 # Conservative choice for -O
356 # -O3 can increase binary size and even slow down the resulting binaries.
357 # Profile first and / or use FDO if you need better performance than this.
358 "-O2",
359
Marcel Hlopko5875be72016-12-16 07:15:33 +0000360 # Security hardening on by default.
361 # Conservative choice; -D_FORTIFY_SOURCE=2 may be unsafe in some cases.
362 "-D_FORTIFY_SOURCE=1",
363
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000364 # Disable assertions
365 "-DNDEBUG",
366
367 # Removal of unused code and data at link time (can this increase binary size in some cases?).
368 "-ffunction-sections",
369 "-fdata-sections"
370 ],
371 "linker_flag": [] if darwin else ["-Wl,--gc-sections"]
372 }
373
374
375def _dbg_content():
376 """Return the content of the dbg specific section of the CROSSTOOL file."""
377 # Enable debug symbols
378 return {"compiler_flag": "-g"}
379
380
Yun Peng325b1552016-11-25 15:41:14 +0000381def _get_system_root(repository_ctx):
382 r"""Get System root path on Windows, default is C:\\Windows."""
383 if "SYSTEMROOT" in repository_ctx.os.environ:
384 return repository_ctx.os.environ["SYSTEMROOT"]
385 auto_configure_warning("SYSTEMROOT is not set, using default SYSTEMROOT=C:\\Windows")
386 return "C:\\Windows"
387
Damien Martin-Guillerezda258a02016-03-11 22:57:08 +0000388def _find_cc(repository_ctx):
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000389 """Find the C++ compiler."""
Damien Martin-Guillerez3e4e4162016-04-19 17:22:19 +0000390 cc_name = "gcc"
Damien Martin-Guillerezda258a02016-03-11 22:57:08 +0000391 if "CC" in repository_ctx.os.environ:
Damien Martin-Guillerez3bbfe162016-04-27 12:43:43 +0000392 cc_name = repository_ctx.os.environ["CC"].strip()
393 if not cc_name:
394 cc_name = "gcc"
Damien Martin-Guillerez810d60a2016-04-22 21:13:48 +0000395 if cc_name.startswith("/"):
396 # Absolute path, maybe we should make this suported by our which function.
397 return cc_name
Damien Martin-Guillerez3e4e4162016-04-19 17:22:19 +0000398 cc = repository_ctx.which(cc_name)
399 if cc == None:
400 fail(
401 "Cannot find gcc, either correct your path or set the CC" +
402 " environment variable")
403 return cc
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000404
405
Yun Penga79581e2016-11-22 14:59:01 +0000406def _find_cuda(repository_ctx):
407 """Find out if and where cuda is installed."""
408 if "CUDA_PATH" in repository_ctx.os.environ:
409 return repository_ctx.os.environ["CUDA_PATH"]
410 nvcc = _which(repository_ctx, "nvcc.exe")
411 if nvcc:
412 return nvcc[:-len("/bin/nvcc.exe")]
413 return None
414
Yun Peng001aade2016-07-18 11:25:45 +0000415def _find_python(repository_ctx):
416 """Find where is python on Windows."""
417 if "BAZEL_PYTHON" in repository_ctx.os.environ:
Yun Pengc30432c2016-09-28 20:36:26 +0000418 python_binary = repository_ctx.os.environ["BAZEL_PYTHON"]
419 if not python_binary.endswith(".exe"):
420 python_binary = python_binary + ".exe"
421 return python_binary
Yun Peng5d03c5c2016-09-15 16:30:52 +0000422 auto_configure_warning("'BAZEL_PYTHON' is not set, start looking for python in PATH.")
Yun Pengeb872082016-09-28 14:22:34 +0000423 python_binary = _which_cmd(repository_ctx, "python.exe")
424 auto_configure_warning("Python found at %s" % python_binary)
Yun Peng001aade2016-07-18 11:25:45 +0000425 return python_binary
426
Yun Peng7a95e422017-02-08 09:57:42 +0000427def _add_system_root(repository_ctx, env):
428 r"""Running VCVARSALL.BAT and VCVARSQUERYREGISTRY.BAT need %SYSTEMROOT%\\system32 in PATH."""
429 if "PATH" not in env:
430 env["PATH"] = ""
431 env["PATH"] = env["PATH"] + ";" + _get_system_root(repository_ctx) + "\\system32"
432 return env
Yun Peng001aade2016-07-18 11:25:45 +0000433
Yun Peng7a95e422017-02-08 09:57:42 +0000434def _find_vc_path(repository_ctx):
435 """Find Visual C++ build tools install path."""
436 # 1. Check if BAZEL_VC or BAZEL_VS is already set by user.
437 if "BAZEL_VC" in repository_ctx.os.environ:
438 return repository_ctx.os.environ["BAZEL_VC"]
439
Yun Pengeb872082016-09-28 14:22:34 +0000440 if "BAZEL_VS" in repository_ctx.os.environ:
Yun Peng7a95e422017-02-08 09:57:42 +0000441 return repository_ctx.os.environ["BAZEL_VS"] + "\\VC\\"
442 auto_configure_warning("'BAZEL_VC' is not set, " +
443 "start looking for the latest Visual C++ installed.")
Yun Peng325b1552016-11-25 15:41:14 +0000444
Yun Peng7a95e422017-02-08 09:57:42 +0000445 # 2. Check if VS%VS_VERSION%COMNTOOLS is set, if true then try to find and use
446 # vcvarsqueryregistry.bat to detect VC++.
447 auto_configure_warning("Looking for VS%VERSION%COMNTOOLS environment variables," +
448 "eg. VS140COMNTOOLS")
449 for vscommontools_env in ["VS140COMNTOOLS", "VS120COMNTOOLS",
450 "VS110COMNTOOLS", "VS100COMNTOOLS", "VS90COMNTOOLS"]:
451 if vscommontools_env not in repository_ctx.os.environ:
452 continue
453 vcvarsqueryregistry = repository_ctx.os.environ[vscommontools_env] + "\\vcvarsqueryregistry.bat"
454 if not repository_ctx.path(vcvarsqueryregistry).exists:
455 continue
456 repository_ctx.file("wrapper/get_vc_dir.bat",
457 "@echo off\n" +
458 "call \"" + vcvarsqueryregistry + "\"\n" +
459 "echo %VCINSTALLDIR%", True)
460 env = _add_system_root(repository_ctx, repository_ctx.os.environ)
461 vc_dir = _execute(repository_ctx, ["wrapper/get_vc_dir.bat"], environment=env)
462
463 auto_configure_warning("Visual C++ build tools found at %s" % vc_dir)
464 return vc_dir
465
466 # 3. User might clean up all environment variables, if so looking for Visual C++ through registry.
467 # This method only works if Visual Studio is installed, and for some reason, is flaky.
468 # https://github.com/bazelbuild/bazel/issues/2434
469 auto_configure_warning("Looking for Visual C++ through registry")
Yun Peng325b1552016-11-25 15:41:14 +0000470 # Query the installed visual stduios on the machine, should return something like:
471 # HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\14.0
472 # HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\8.0
473 # ...
474 reg_binary = _get_system_root(repository_ctx) + "\\system32\\reg.exe"
475 result = _execute(repository_ctx, [reg_binary, "query", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\VisualStudio"])
476 vs_versions = result.split("\n")
477
478 vs_dir = None
479 vs_version_number = -1
480 for entry in vs_versions:
481 entry = entry.strip()
482 # Query InstallDir to find out where a specific version of VS is installed.
483 # The output looks like if succeeded:
484 # HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\14.0
485 # InstallDir REG_SZ C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\
486 result = repository_ctx.execute([reg_binary, "query", entry, "-v", "InstallDir"])
487 if not result.stderr:
488 for line in result.stdout.split("\n"):
489 line = line.strip()
Yun Peng321aa542017-02-14 15:08:17 +0000490 if line.startswith("InstallDir") and line.find("REG_SZ") != -1:
491 install_dir = line[line.find("REG_SZ") + len("REG_SZ"):].strip()
492 path_segments = [ seg for seg in install_dir.split("\\") if seg ]
Yun Peng325b1552016-11-25 15:41:14 +0000493 # Extract version number X from "Microsoft Visual Studio X.0"
494 version_number = int(path_segments[-3].split(" ")[-1][:-len(".0")])
495 if version_number > vs_version_number:
496 vs_version_number = version_number
497 vs_dir = "\\".join(path_segments[:-2])
498
Yun Peng321aa542017-02-14 15:08:17 +0000499 # 4. Try to find Visual C++ build tools 2017
500 result = repository_ctx.execute([reg_binary, "query", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VS7", "/v", "15.0"])
501 if not result.stderr:
502 for line in result.stdout.split("\n"):
503 line = line.strip()
504 if line.startswith("15.0") and line.find("REG_SZ") != -1:
505 vs_dir = line[line.find("REG_SZ") + len("REG_SZ"):].strip()
506
Yun Peng325b1552016-11-25 15:41:14 +0000507 if not vs_dir:
Yun Peng7a95e422017-02-08 09:57:42 +0000508 auto_configure_fail("Visual C++ build tools not found on your machine.")
509 vc_dir = vs_dir + "\\VC\\"
510 auto_configure_warning("Visual C++ build tools found at %s" % vc_dir)
511 return vc_dir
Yun Peng56b16e72016-07-12 10:55:57 +0000512
Yun Peng321aa542017-02-14 15:08:17 +0000513def _is_vs_2017(vc_path):
514 """Check if the installed VS version is Visual Studio 2017."""
515 # In VS 2017, the location of VC is like:
516 # C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\
517 # In VS 2015 or older version, it is like:
518 # C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\
519 return vc_path.find("2017") != -1
520
521def _find_vcvarsall_bat_script(repository_ctx, vc_path):
522 """Find vcvarsall.bat script."""
523 if _is_vs_2017(vc_path):
524 vcvarsall = vc_path + "\\Auxiliary\\Build\\VCVARSALL.BAT"
525 else:
526 vcvarsall = vc_path + "\\VCVARSALL.BAT"
527
528 if not repository_ctx.path(vcvarsall).exists:
529 auto_configure_fail("vcvarsall.bat doesn't exists, please check your VC++ installation")
530 return vcvarsall
Yun Peng56b16e72016-07-12 10:55:57 +0000531
Yun Peng7a95e422017-02-08 09:57:42 +0000532def _find_env_vars(repository_ctx, vc_path):
Yun Peng56b16e72016-07-12 10:55:57 +0000533 """Get environment variables set by VCVARSALL.BAT."""
Yun Peng321aa542017-02-14 15:08:17 +0000534 vcvarsall = _find_vcvarsall_bat_script(repository_ctx, vc_path)
Yun Peng56b16e72016-07-12 10:55:57 +0000535 repository_ctx.file("wrapper/get_env.bat",
536 "@echo off\n" +
Yun Peng321aa542017-02-14 15:08:17 +0000537 "call \"" + vcvarsall + "\" amd64 > NUL \n" +
Yun Peng56b16e72016-07-12 10:55:57 +0000538 "echo PATH=%PATH%,INCLUDE=%INCLUDE%,LIB=%LIB% \n", True)
Yun Peng7a95e422017-02-08 09:57:42 +0000539 env = _add_system_root(repository_ctx, repository_ctx.os.environ)
Yun Penge2084282016-11-24 13:54:01 +0000540 envs = _execute(repository_ctx, ["wrapper/get_env.bat"], environment=env).split(",")
Yun Peng56b16e72016-07-12 10:55:57 +0000541 env_map = {}
542 for env in envs:
543 key, value = env.split("=")
544 env_map[key] = value.replace("\\", "\\\\")
545 return env_map
546
547
Yun Peng321aa542017-02-14 15:08:17 +0000548def _find_msvc_tool(repository_ctx, vc_path, tool):
549 """Find the exact path of a specific build tool in MSVC."""
550 tool_path = ""
551 if _is_vs_2017(vc_path):
552 # For VS 2017, the tools are under a directory like:
553 # C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Tools\MSVC\14.10.24930\bin\HostX64\x64
554 dirs = repository_ctx.path(vc_path + "\\Tools\\MSVC").readdir()
555 if len(dirs) < 1:
556 auto_configure_fail("VC++ build tools directory not found under " + vc_path + "\\Tools\\MSVC")
557 # Normally there should be only one child directory under %VC_PATH%\TOOLS\MSVC,
558 # but iterate every directory to be more robust.
559 for path in dirs:
560 tool_path = str(path) + "\\bin\\HostX64\\x64\\" + tool
561 if repository_ctx.path(tool_path).exists:
562 break
563 else:
564 # For VS 2015 and older version, the tools are under:
565 # C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64
566 tool_path = vc_path + "\\bin\\amd64\\" + tool
567
568 if not repository_ctx.path(tool_path).exists:
569 auto_configure_fail(tool_path + " not found, please check your VC++ installation.")
570 return tool_path
571
572def _is_support_whole_archive(repository_ctx, vc_path):
Yun Peng81aede12016-10-25 13:49:28 +0000573 """Run MSVC linker alone to see if it supports /WHOLEARCHIVE."""
Yun Penga79581e2016-11-22 14:59:01 +0000574 env = repository_ctx.os.environ
575 if "NO_WHOLE_ARCHIVE_OPTION" in env and env["NO_WHOLE_ARCHIVE_OPTION"] == "1":
576 return False
Yun Peng321aa542017-02-14 15:08:17 +0000577 linker = _find_msvc_tool(repository_ctx, vc_path, "link.exe")
578 result = _execute(repository_ctx, [linker])
Yun Peng81aede12016-10-25 13:49:28 +0000579 return result.find("/WHOLEARCHIVE") != -1
580
581
Yun Penga79581e2016-11-22 14:59:01 +0000582def _cuda_compute_capabilities(repository_ctx):
583 """Returns a list of strings representing cuda compute capabilities."""
584
585 if "CUDA_COMPUTE_CAPABILITIES" not in repository_ctx.os.environ:
586 return ["3.5", "5.2"]
587 capabilities_str = repository_ctx.os.environ["CUDA_COMPUTE_CAPABILITIES"]
588 capabilities = capabilities_str.split(",")
589 for capability in capabilities:
590 # Workaround for Skylark's lack of support for regex. This check should
591 # be equivalent to checking:
592 # if re.match("[0-9]+.[0-9]+", capability) == None:
593 parts = capability.split(".")
594 if len(parts) != 2 or not parts[0].isdigit() or not parts[1].isdigit():
595 auto_configure_fail("Invalid compute capability: %s" % capability)
596 return capabilities
597
598
Damien Martin-Guillerez6dab8152016-05-06 12:44:26 +0000599def _tpl(repository_ctx, tpl, substitutions={}, out=None):
600 if not out:
601 out = tpl
Damien Martin-Guillerezda258a02016-03-11 22:57:08 +0000602 repository_ctx.template(
Damien Martin-Guillerez6dab8152016-05-06 12:44:26 +0000603 out,
Damien Martin-Guillerezda258a02016-03-11 22:57:08 +0000604 Label("@bazel_tools//tools/cpp:%s.tpl" % tpl),
605 substitutions)
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000606
607
Damien Martin-Guillerez6dab8152016-05-06 12:44:26 +0000608def _get_env(repository_ctx):
Damien Martin-Guillerezec2657f2016-05-09 14:30:20 +0000609 """Convert the environment in a list of export if in Homebrew."""
Damien Martin-Guillerez6dab8152016-05-06 12:44:26 +0000610 env = repository_ctx.os.environ
Damien Martin-Guillerezec2657f2016-05-09 14:30:20 +0000611 if "HOMEBREW_RUBY_PATH" in env:
612 return "\n".join([
613 "export %s='%s'" % (k, env[k].replace("'", "'\\''"))
614 for k in env
615 if k != "_" and k.find(".") == -1
616 ])
617 else:
618 return ""
Damien Martin-Guillerez6dab8152016-05-06 12:44:26 +0000619
Marcel Hlopko71c72c12017-02-23 14:10:31 +0000620def _coverage_feature(darwin):
621 if darwin:
622 compile_flags = """flag_group {
623 flag: '-fprofile-instr-generate'
624 flag: '-fcoverage-mapping'
625 }"""
626 link_flags = """flag_group {
627 flag: '-fprofile-instr-generate'
628 }"""
629 else:
630 compile_flags = """flag_group {
631 flag: '-fprofile-arcs'
632 flag: '-ftest-coverage'
633 }"""
634 link_flags = """flag_group {
635 flag: '-lgcov'
636 }"""
637 return """
638 feature {
639 name: 'coverage'
640 provides: 'profile'
641 flag_set {
642 action: 'preprocess-assemble'
643 action: 'c-compile'
644 action: 'c++-compile'
645 action: 'c++-header-parsing'
646 action: 'c++-header-preprocessing'
647 action: 'c++-module-compile'
648 """ + compile_flags + """
649 }
650 flag_set {
651 action: 'c++-link-interface-dynamic-library'
652 action: 'c++-link-dynamic-library'
653 action: 'c++-link-executable'
654 """ + link_flags + """
655 }
656 }
657 """
658
Damien Martin-Guillerezda258a02016-03-11 22:57:08 +0000659def _impl(repository_ctx):
Marcel Hlopkoc76c93e2017-01-02 12:32:19 +0000660 repository_ctx.file("tools/cpp/empty.cc", "int main() {}")
Damien Martin-Guillerezda258a02016-03-11 22:57:08 +0000661 cpu_value = _get_cpu_value(repository_ctx)
Yun Peng56b16e72016-07-12 10:55:57 +0000662 if cpu_value == "freebsd":
Damien Martin-Guillereza6d9ba72016-03-15 18:18:53 +0000663 # This is defaulting to the static crosstool, we should eventually do those platform too.
664 # Theorically, FreeBSD should be straightforward to add but we cannot run it in a docker
665 # container so escaping until we have proper tests for FreeBSD.
Damien Martin-Guillerezbe1b1152016-03-31 13:41:48 +0000666 repository_ctx.symlink(Label("@bazel_tools//tools/cpp:CROSSTOOL"), "CROSSTOOL")
667 repository_ctx.symlink(Label("@bazel_tools//tools/cpp:BUILD.static"), "BUILD")
Yun Peng56b16e72016-07-12 10:55:57 +0000668 elif cpu_value == "x64_windows":
669 repository_ctx.symlink(Label("@bazel_tools//tools/cpp:BUILD.static"), "BUILD")
670
Yun Pengfdcb3b22016-04-19 20:03:10 +0000671 msvc_wrapper = repository_ctx.path(Label("@bazel_tools//tools/cpp:CROSSTOOL")).dirname.get_child("wrapper").get_child("bin")
Yun Peng56b16e72016-07-12 10:55:57 +0000672 for f in ["msvc_cl.bat", "msvc_link.bat", "msvc_nop.bat"]:
673 repository_ctx.symlink(msvc_wrapper.get_child(f), "wrapper/bin/" + f)
674 msvc_wrapper = msvc_wrapper.get_child("pydir")
675 for f in ["msvc_cl.py", "msvc_link.py"]:
676 repository_ctx.symlink(msvc_wrapper.get_child(f), "wrapper/bin/pydir/" + f)
677
Yun Peng001aade2016-07-18 11:25:45 +0000678 python_binary = _find_python(repository_ctx)
Yun Peng56b16e72016-07-12 10:55:57 +0000679 _tpl(repository_ctx, "wrapper/bin/call_python.bat", {"%{python_binary}": python_binary})
680
Yun Peng7a95e422017-02-08 09:57:42 +0000681 vc_path = _find_vc_path(repository_ctx)
682 env = _find_env_vars(repository_ctx, vc_path)
Yun Peng56b16e72016-07-12 10:55:57 +0000683 python_dir = python_binary[0:-10].replace("\\", "\\\\")
684 include_paths = env["INCLUDE"] + (python_dir + "include")
685 lib_paths = env["LIB"] + (python_dir + "libs")
Yun Peng321aa542017-02-14 15:08:17 +0000686 lib_tool = _find_msvc_tool(repository_ctx, vc_path, "lib.exe").replace("\\", "\\\\")
Yun Peng7a95e422017-02-08 09:57:42 +0000687 if _is_support_whole_archive(repository_ctx, vc_path):
Yun Peng81aede12016-10-25 13:49:28 +0000688 support_whole_archive = "True"
689 else:
690 support_whole_archive = "False"
Yun Penga79581e2016-11-22 14:59:01 +0000691 tmp_dir = _get_env_var(repository_ctx, "TMP", "C:\\Windows\\Temp").replace("\\", "\\\\")
692 # Make sure nvcc.exe is in PATH
693 paths = env["PATH"]
694 cuda_path = _find_cuda(repository_ctx)
695 if cuda_path:
696 paths = (cuda_path.replace("\\", "\\\\") + "/bin;") + paths
697 compute_capabilities = _cuda_compute_capabilities(repository_ctx)
Yun Peng56b16e72016-07-12 10:55:57 +0000698 _tpl(repository_ctx, "wrapper/bin/pydir/msvc_tools.py", {
Yun Penga79581e2016-11-22 14:59:01 +0000699 "%{tmp}": tmp_dir,
700 "%{path}": paths,
Yun Peng56b16e72016-07-12 10:55:57 +0000701 "%{include}": include_paths,
702 "%{lib}": lib_paths,
Yun Peng81aede12016-10-25 13:49:28 +0000703 "%{lib_tool}": lib_tool,
Yun Penga79581e2016-11-22 14:59:01 +0000704 "%{support_whole_archive}": support_whole_archive,
705 "%{cuda_compute_capabilities}": ", ".join(
706 ["\"%s\"" % c for c in compute_capabilities]),
Yun Peng56b16e72016-07-12 10:55:57 +0000707 })
708
Yun Penga79581e2016-11-22 14:59:01 +0000709 # nvcc will generate some source files under tmp_dir
710 cxx_include_directories = [ "cxx_builtin_include_directory: \"%s\"" % tmp_dir ]
Yun Peng56b16e72016-07-12 10:55:57 +0000711 for path in include_paths.split(";"):
712 if path:
713 cxx_include_directories.append(("cxx_builtin_include_directory: \"%s\"" % path))
714 _tpl(repository_ctx, "CROSSTOOL", {
715 "%{cpu}": cpu_value,
716 "%{content}": _get_windows_crosstool_content(repository_ctx),
717 "%{opt_content}": "",
718 "%{dbg_content}": "",
Yun Pengffdc05d2016-10-06 10:55:54 +0000719 "%{cxx_builtin_include_directory}": "\n".join(cxx_include_directories),
Marcel Hlopko5dbb23b2017-02-24 14:45:57 +0000720 "%{coverage}": "",
Yun Peng56b16e72016-07-12 10:55:57 +0000721 })
Damien Martin-Guillereza6d9ba72016-03-15 18:18:53 +0000722 else:
723 darwin = cpu_value == "darwin"
724 cc = _find_cc(repository_ctx)
Damien Martin-Guillerezec2657f2016-05-09 14:30:20 +0000725 tool_paths = _get_tool_paths(repository_ctx, darwin,
726 "cc_wrapper.sh" if darwin else str(cc))
Damien Martin-Guillereza6d9ba72016-03-15 18:18:53 +0000727 crosstool_content = _crosstool_content(repository_ctx, cc, cpu_value, darwin)
728 opt_content = _opt_content(darwin)
729 dbg_content = _dbg_content()
730 _tpl(repository_ctx, "BUILD", {
731 "%{name}": cpu_value,
Damien Martin-Guillerezec2657f2016-05-09 14:30:20 +0000732 "%{supports_param_files}": "0" if darwin else "1",
733 "%{cc_compiler_deps}": ":cc_wrapper" if darwin else ":empty",
Damien Martin-Guillereza6d9ba72016-03-15 18:18:53 +0000734 })
Damien Martin-Guillerez6dab8152016-05-06 12:44:26 +0000735 _tpl(repository_ctx,
736 "osx_cc_wrapper.sh" if darwin else "linux_cc_wrapper.sh",
737 {"%{cc}": str(cc), "%{env}": _get_env(repository_ctx)},
738 "cc_wrapper.sh")
Damien Martin-Guillereza6d9ba72016-03-15 18:18:53 +0000739 _tpl(repository_ctx, "CROSSTOOL", {
740 "%{cpu}": cpu_value,
741 "%{content}": _build_crosstool(crosstool_content) + "\n" +
742 _build_tool_path(tool_paths),
743 "%{opt_content}": _build_crosstool(opt_content, " "),
744 "%{dbg_content}": _build_crosstool(dbg_content, " "),
Yun Pengffdc05d2016-10-06 10:55:54 +0000745 "%{cxx_builtin_include_directory}": "",
Marcel Hlopko71c72c12017-02-23 14:10:31 +0000746 "%{coverage}": _coverage_feature(darwin),
Damien Martin-Guillereza6d9ba72016-03-15 18:18:53 +0000747 })
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000748
749
Damien Martin-Guillerezac29b782017-02-15 14:50:39 +0000750cc_autoconf = repository_rule(
751 implementation=_impl,
752 environ = [
753 "CC",
754 "BAZEL_VC",
755 "BAZEL_VS",
756 "BAZEL_SH",
757 "BAZEL_PYTHON",
758 "CPLUS_INCLUDE_PATH"])
Damien Martin-Guillerez8fa5ae62016-03-02 16:24:13 +0000759
760
761def cc_configure():
762 """A C++ configuration rules that generate the crosstool file."""
763 cc_autoconf(name="local_config_cc")
764 native.bind(name="cc_toolchain", actual="@local_config_cc//:toolchain")