Skip to content

Commit 8e0a527

Browse files
hvadehracopybara-github
authored andcommitted
Extract the Bazel cc_import rule from @_builtins to @rules_cc
PiperOrigin-RevId: 786644184 Change-Id: I83991e4d83c8700aade3cfee454ef94b8c6ea155
1 parent 2b15b96 commit 8e0a527

File tree

7 files changed

+893
-3
lines changed

7 files changed

+893
-3
lines changed

cc/common/cc_helper.bzl

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@
1515

1616
load("//cc:find_cc_toolchain.bzl", "CC_TOOLCHAIN_TYPE")
1717
load(":cc_common.bzl", "cc_common")
18+
load(
19+
":cc_helper_internal.bzl",
20+
"get_relative_path",
21+
"is_versioned_shared_library_extension_valid",
22+
"path_contains_up_level_references",
23+
_package_source_root = "package_source_root",
24+
_repository_exec_path = "repository_exec_path",
25+
)
26+
load(":cc_info.bzl", "CcInfo")
1827
load(":visibility.bzl", "INTERNAL_VISIBILITY")
1928

2029
visibility(INTERNAL_VISIBILITY)
@@ -27,6 +36,62 @@ linker_mode = struct(
2736
# LINT.ThenChange(https://github.com/bazelbuild/bazel/blob/master/src/main/starlark/builtins_bzl/common/cc/cc_helper.bzl:linker_mode)
2837

2938
# LINT.IfChange(forked_exports)
39+
40+
def _get_compilation_contexts_from_deps(deps):
41+
compilation_contexts = []
42+
for dep in deps:
43+
if CcInfo in dep:
44+
compilation_contexts.append(dep[CcInfo].compilation_context)
45+
return compilation_contexts
46+
47+
def _tool_path(cc_toolchain, tool):
48+
return cc_toolchain._tool_paths.get(tool, None)
49+
50+
def _get_toolchain_global_make_variables(cc_toolchain):
51+
result = {
52+
"CC": _tool_path(cc_toolchain, "gcc"),
53+
"AR": _tool_path(cc_toolchain, "ar"),
54+
"NM": _tool_path(cc_toolchain, "nm"),
55+
"LD": _tool_path(cc_toolchain, "ld"),
56+
"STRIP": _tool_path(cc_toolchain, "strip"),
57+
"C_COMPILER": cc_toolchain.compiler,
58+
} # buildifier: disable=unsorted-dict-items
59+
60+
obj_copy_tool = _tool_path(cc_toolchain, "objcopy")
61+
if obj_copy_tool != None:
62+
# objcopy is optional in Crostool.
63+
result["OBJCOPY"] = obj_copy_tool
64+
gcov_tool = _tool_path(cc_toolchain, "gcov-tool")
65+
if gcov_tool != None:
66+
# gcovtool is optional in Crostool.
67+
result["GCOVTOOL"] = gcov_tool
68+
69+
libc = cc_toolchain.libc
70+
if libc.startswith("glibc-"):
71+
# Strip "glibc-" prefix.
72+
result["GLIBC_VERSION"] = libc[6:]
73+
else:
74+
result["GLIBC_VERSION"] = libc
75+
76+
abi_glibc_version = cc_toolchain._abi_glibc_version
77+
if abi_glibc_version != None:
78+
result["ABI_GLIBC_VERSION"] = abi_glibc_version
79+
80+
abi = cc_toolchain._abi
81+
if abi != None:
82+
result["ABI"] = abi
83+
84+
result["CROSSTOOLTOP"] = cc_toolchain._crosstool_top_path
85+
return result
86+
87+
_SHARED_LIBRARY_EXTENSIONS = ["so", "dll", "dylib", "wasm"]
88+
89+
def _is_valid_shared_library_artifact(shared_library):
90+
if (shared_library.extension in _SHARED_LIBRARY_EXTENSIONS):
91+
return True
92+
93+
return is_versioned_shared_library_extension_valid(shared_library.basename)
94+
3095
def _get_static_mode_params_for_dynamic_library_libraries(libs):
3196
linker_inputs = []
3297
for lib in libs.to_list():
@@ -285,11 +350,79 @@ def _should_use_pic(ctx, cc_toolchain, feature_configuration):
285350
)
286351
)
287352

353+
SYSROOT_FLAG = "--sysroot="
354+
355+
def _contains_sysroot(original_cc_flags, feature_config_cc_flags):
356+
if SYSROOT_FLAG in original_cc_flags:
357+
return True
358+
for flag in feature_config_cc_flags:
359+
if SYSROOT_FLAG in flag:
360+
return True
361+
362+
return False
363+
364+
def _get_cc_flags_make_variable(_ctx, feature_configuration, cc_toolchain):
365+
original_cc_flags = cc_toolchain._legacy_cc_flags_make_variable
366+
sysroot_cc_flag = ""
367+
if cc_toolchain.sysroot != None:
368+
sysroot_cc_flag = SYSROOT_FLAG + cc_toolchain.sysroot
369+
370+
build_vars = cc_toolchain._build_variables
371+
feature_config_cc_flags = cc_common.get_memory_inefficient_command_line(
372+
feature_configuration = feature_configuration,
373+
action_name = "cc-flags-make-variable",
374+
variables = build_vars,
375+
)
376+
cc_flags = [original_cc_flags]
377+
378+
# Only add sysroots flag if nothing else adds sysroot, BUT it must appear
379+
# before the feature config flags.
380+
if not _contains_sysroot(original_cc_flags, feature_config_cc_flags):
381+
cc_flags.append(sysroot_cc_flag)
382+
cc_flags.extend(feature_config_cc_flags)
383+
return {"CC_FLAGS": " ".join(cc_flags)}
384+
385+
def _package_exec_path(ctx, package, sibling_repository_layout):
386+
return get_relative_path(_repository_exec_path(ctx.label.workspace_name, sibling_repository_layout), package)
387+
388+
def _system_include_dirs(ctx, additional_make_variable_substitutions):
389+
result = []
390+
sibling_repository_layout = ctx.configuration.is_sibling_repository_layout()
391+
package = ctx.label.package
392+
package_exec_path = _package_exec_path(ctx, package, sibling_repository_layout)
393+
package_source_root = _package_source_root(ctx.label.workspace_name, package, sibling_repository_layout)
394+
for include in ctx.attr.includes:
395+
includes_attr = _expand(ctx, include, additional_make_variable_substitutions)
396+
if includes_attr.startswith("/"):
397+
continue
398+
includes_path = get_relative_path(package_exec_path, includes_attr)
399+
if not sibling_repository_layout and path_contains_up_level_references(includes_path):
400+
fail("Path references a path above the execution root.", attr = "includes")
401+
402+
if includes_path == ".":
403+
fail("'" + includes_attr + "' resolves to the workspace root, which would allow this rule and all of its " +
404+
"transitive dependents to include any file in your workspace. Please include only" +
405+
" what you need", attr = "includes")
406+
result.append(includes_path)
407+
408+
# We don't need to perform the above checks against out_includes_path again since any errors
409+
# must have manifested in includesPath already.
410+
out_includes_path = get_relative_path(package_source_root, includes_attr)
411+
if (ctx.configuration.has_separate_genfiles_directory()):
412+
result.append(get_relative_path(ctx.genfiles_dir.path, out_includes_path))
413+
result.append(get_relative_path(ctx.bin_dir.path, out_includes_path))
414+
return result
415+
288416
cc_helper = struct(
289417
create_strip_action = _create_strip_action,
290418
get_expanded_env = _get_expanded_env,
291419
get_static_mode_params_for_dynamic_library_libraries = _get_static_mode_params_for_dynamic_library_libraries,
292420
should_use_pic = _should_use_pic,
293421
tokenize = _tokenize,
422+
is_valid_shared_library_artifact = _is_valid_shared_library_artifact,
423+
get_toolchain_global_make_variables = _get_toolchain_global_make_variables,
424+
get_cc_flags_make_variable = _get_cc_flags_make_variable,
425+
get_compilation_contexts_from_deps = _get_compilation_contexts_from_deps,
426+
system_include_dirs = _system_include_dirs,
294427
)
295428
# LINT.ThenChange(https://github.com/bazelbuild/bazel/blob/master/src/main/starlark/builtins_bzl/common/cc/cc_helper.bzl:forked_exports)

cc/common/cc_helper_internal.bzl

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# Copyright 2024 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+
15+
"""
16+
Utility functions for C++ rules that don't depend on cc_common.
17+
18+
Only use those within C++ implementation. The others need to go through cc_common.
19+
"""
20+
21+
load("@bazel_skylib//lib:paths.bzl", "paths")
22+
23+
# LINT.IfChange(forked_exports)
24+
25+
def is_versioned_shared_library_extension_valid(shared_library_name):
26+
"""Validates the name against the regex "^.+\\.((so)|(dylib))(\\.\\d\\w*)+$",
27+
28+
Args:
29+
shared_library_name: (str) the name to validate
30+
31+
Returns:
32+
(bool)
33+
"""
34+
35+
# must match VERSIONED_SHARED_LIBRARY.
36+
for ext in (".so.", ".dylib."):
37+
name, _, version = shared_library_name.rpartition(ext)
38+
if name and version:
39+
version_parts = version.split(".")
40+
for part in version_parts:
41+
if not part[0].isdigit():
42+
return False
43+
for c in part[1:].elems():
44+
if not (c.isalnum() or c == "_"):
45+
return False
46+
return True
47+
return False
48+
49+
def _is_repository_main(repository):
50+
return repository == ""
51+
52+
def package_source_root(repository, package, sibling_repository_layout):
53+
"""
54+
Determines the source root for a given repository and package.
55+
56+
Args:
57+
repository: The repository to get the source root for.
58+
package: The package to get the source root for.
59+
sibling_repository_layout: Whether the repository layout is a sibling repository layout.
60+
61+
Returns:
62+
The source root for the given repository and package.
63+
"""
64+
if _is_repository_main(repository) or sibling_repository_layout:
65+
return package
66+
if repository.startswith("@"):
67+
repository = repository[1:]
68+
return paths.get_relative(paths.get_relative("external", repository), package)
69+
70+
def repository_exec_path(repository, sibling_repository_layout):
71+
"""
72+
Determines the exec path for a given repository.
73+
74+
Args:
75+
repository: The repository to get the exec path for.
76+
sibling_repository_layout: Whether the repository layout is a sibling repository layout.
77+
78+
Returns:
79+
The exec path for the given repository.
80+
"""
81+
if _is_repository_main(repository):
82+
return ""
83+
prefix = "external"
84+
if sibling_repository_layout:
85+
prefix = ".."
86+
if repository.startswith("@"):
87+
repository = repository[1:]
88+
return paths.get_relative(prefix, repository)
89+
90+
# LINT.ThenChange(https://github.com/bazelbuild/bazel/blob/master/src/main/starlark/builtins_bzl/common/cc/cc_helper_internal.bzl:forked_exports)
91+
92+
def get_relative_path(path_a, path_b):
93+
if paths.is_absolute(path_b):
94+
return path_b
95+
return paths.normalize(paths.join(path_a, path_b))
96+
97+
def path_contains_up_level_references(path):
98+
return path.startswith("..") and (len(path) == 2 or path[2] == "/")

0 commit comments

Comments
 (0)