forked from google-ml-infra/rules_ml_toolchain
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcompiler_common_tools.bzl
More file actions
180 lines (157 loc) · 6.42 KB
/
Copy pathcompiler_common_tools.bzl
File metadata and controls
180 lines (157 loc) · 6.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
"""Common compiler functions. """
load(
"//common:common.bzl",
"err_out",
"raw_exec",
"realpath",
)
def to_list_of_strings(elements):
"""Convert the list of ["a", "b", "c"] into '"a", "b", "c"'.
This is to be used to put a list of strings into the bzl file templates
so it gets interpreted as list of strings in Starlark.
Args:
elements: list of string elements
Returns:
single string of elements wrapped in quotes separated by a comma."""
quoted_strings = ["\"" + element + "\"" for element in elements]
return ", ".join(quoted_strings)
_INC_DIR_MARKER_BEGIN = "#include <...>"
# OSX add " (framework directory)" at the end of line, strip it.
_OSX_FRAMEWORK_SUFFIX = " (framework directory)"
_OSX_FRAMEWORK_SUFFIX_LEN = len(_OSX_FRAMEWORK_SUFFIX)
# TODO(dzc): Once these functions have been factored out of Bazel's
# cc_configure.bzl, load them from @bazel_tools instead.
def _cxx_inc_convert(path):
"""Convert path returned by cc -E xc++ in a complete path."""
path = path.strip()
if path.endswith(_OSX_FRAMEWORK_SUFFIX):
path = path[:-_OSX_FRAMEWORK_SUFFIX_LEN].strip()
return path
def _normalize_include_path(repository_ctx, path):
"""Normalizes include paths before writing them to the crosstool.
If path points inside the 'crosstool' folder of the repository, a relative
path is returned.
If path points outside the 'crosstool' folder, an absolute path is returned.
"""
path = str(repository_ctx.path(path))
crosstool_folder = str(repository_ctx.path(".").get_child("crosstool"))
if path.startswith(crosstool_folder):
# We drop the path to "$REPO/crosstool" and a trailing path separator.
return path[len(crosstool_folder) + 1:]
return path
def _is_compiler_option_supported(repository_ctx, cc, option):
"""Checks that `option` is supported by the C compiler. Doesn't %-escape the option."""
result = repository_ctx.execute([
cc,
option,
"-o",
"/dev/null",
"-c",
str(repository_ctx.path("tools/cpp/empty.cc")),
])
return result.stderr.find(option) == -1
def _get_cxx_inc_directories_impl(repository_ctx, cc, lang_is_cpp, tf_sys_root):
"""Compute the list of default C or C++ include directories."""
if lang_is_cpp:
lang = "c++"
else:
lang = "c"
sysroot = []
if tf_sys_root:
sysroot += ["--sysroot", tf_sys_root]
no_canonical_prefixes_supported = _is_compiler_option_supported(
repository_ctx,
cc,
"-no-canonical-prefixes",
)
no_canonical_prefixes = (["-no-canonical-prefixes"] if no_canonical_prefixes_supported else [])
result = raw_exec(repository_ctx, [cc, "-E", "-x" + lang, "-", "-v"] +
sysroot + no_canonical_prefixes)
stderr = err_out(result)
index1 = stderr.find(_INC_DIR_MARKER_BEGIN)
if index1 == -1:
return []
index1 = stderr.find("\n", index1)
if index1 == -1:
return []
index2 = stderr.rfind("\n ")
if index2 == -1 or index2 < index1:
return []
index2 = stderr.find("\n", index2 + 1)
if index2 == -1:
inc_dirs = stderr[index1 + 1:]
else:
inc_dirs = stderr[index1 + 1:index2].strip()
print_resource_dir_supported = _is_compiler_option_supported(
repository_ctx,
cc,
"-print-resource-dir",
)
if print_resource_dir_supported:
resource_dir = repository_ctx.execute(
[cc, "-print-resource-dir"],
).stdout.strip() + "/share"
inc_dirs += "\n" + resource_dir
compiler_includes = [
_normalize_include_path(repository_ctx, _cxx_inc_convert(p))
for p in inc_dirs.split("\n")
]
# The compiler might be on a symlink, e.g. /symlink -> /opt/gcc
# The above keeps only the resolved paths to the default includes (e.g. /opt/gcc/include/c++/11)
# but Bazel might encounter either (usually reported by the compiler)
# especially when a compiler wrapper (e.g. ccache) is used.
# So we need to also include paths where symlinks are not resolved.
# Try to find real path to CC installation to "see through" compiler wrappers
# GCC has the path to g++
index1 = result.stderr.find("COLLECT_GCC=")
if index1 != -1:
index1 = result.stderr.find("=", index1)
index2 = result.stderr.find("\n", index1)
cc_topdir = repository_ctx.path(result.stderr[index1 + 1:index2]).dirname.dirname
else:
# Clang has the directory
index1 = result.stderr.find("InstalledDir: ")
if index1 != -1:
index1 = result.stderr.find(" ", index1)
index2 = result.stderr.find("\n", index1)
cc_topdir = repository_ctx.path(result.stderr[index1 + 1:index2]).dirname
else:
# Fallback to the CC path
cc_topdir = repository_ctx.path(cc).dirname.dirname
# We now have the compiler installation prefix, e.g. /symlink/gcc
# And the resolved installation prefix, e.g. /opt/gcc
cc_topdir_resolved = str(realpath(repository_ctx, cc_topdir)).strip()
cc_topdir = str(cc_topdir).strip()
# If there is (any!) symlink involved we add paths where the unresolved installation prefix is kept.
# e.g. [/opt/gcc/include/c++/11, /opt/gcc/lib/gcc/x86_64-linux-gnu/11/include, /other/path]
# adds [/symlink/include/c++/11, /symlink/lib/gcc/x86_64-linux-gnu/11/include]
if cc_topdir_resolved != cc_topdir:
unresolved_compiler_includes = [
cc_topdir + inc[len(cc_topdir_resolved):]
for inc in compiler_includes
if inc.startswith(cc_topdir_resolved)
]
compiler_includes = compiler_includes + unresolved_compiler_includes
return compiler_includes
def get_cxx_inc_directories(repository_ctx, cc, tf_sys_root):
"""Compute the list of default C and C++ include directories."""
# For some reason `clang -xc` sometimes returns include paths that are
# different from the ones from `clang -xc++`. (Symlink and a dir)
# So we run the compiler with both `-xc` and `-xc++` and merge resulting lists
includes_cpp = _get_cxx_inc_directories_impl(
repository_ctx,
cc,
True,
tf_sys_root,
)
includes_c = _get_cxx_inc_directories_impl(
repository_ctx,
cc,
False,
tf_sys_root,
)
return includes_cpp + [
inc
for inc in includes_c
if inc not in includes_cpp
]