Skip to content

Commit

Permalink
bazel_to_cmake: improve make variable substitution, debugging.
Browse files Browse the repository at this point in the history
Allow make variables to contain nested ().

PiperOrigin-RevId: 586910026
Change-Id: I70d4654e5d0cf89c33d510beda786deec960211b
  • Loading branch information
laramiel authored and copybara-github committed Dec 1, 2023
1 parent 048ec71 commit 94870d8
Show file tree
Hide file tree
Showing 8 changed files with 199 additions and 94 deletions.
52 changes: 32 additions & 20 deletions tools/cmake/bazel_to_cmake/evaluation.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@


class RuleInfo(NamedTuple):
mnemonic: Optional[str] # Only used for debugging currently.
mnemonic: str # Only used for debugging currently.
callers: List[str]
outs: List[TargetId]
impl: RuleImpl

Expand All @@ -129,18 +130,6 @@ class Phase(enum.Enum):
ANALYZE = 3


def _get_mnemonic(currentframe) -> Optional[str]:
"""Returns a mnemonic from currentframe."""
if not currentframe:
return None
# pytype: disable=attribute-error
kind = currentframe.f_back.f_back.f_code.co_name
# pytype: enable=attribute-error
if kind.startswith("bazel_"):
kind = kind[len("bazel_") :]
return kind


class EvaluationState:
"""State used while evaluating Starlark code."""

Expand Down Expand Up @@ -220,6 +209,8 @@ def analyze(self, targets: List[TargetId]):

def add_rule(
self,
_mnemonic: str,
_callers: List[str],
rule_id: TargetId,
impl: RuleImpl,
outs: Optional[List[TargetId]] = None,
Expand All @@ -239,11 +230,8 @@ def add_rule(
raise ValueError(f"Duplicate rule: {rule_id.as_label()}")
if outs is None:
outs = []

# kind is assigned from caller function name
currentframe = inspect.currentframe()
r = RuleInfo(mnemonic=_get_mnemonic(currentframe), outs=outs, impl=impl)
del currentframe
r = RuleInfo(_mnemonic, _callers, outs=outs, impl=impl)
self._all_rules[rule_id] = r
self._unanalyzed_rules.add(rule_id)
self._unanalyzed_targets[rule_id] = rule_id
Expand Down Expand Up @@ -475,7 +463,7 @@ def get_dep(
for package in info[CMakePackageDepsProvider].packages:
self.add_required_dep_package(package)
if info.get(CMakeDepsProvider):
return info[CMakeDepsProvider].targets
return info[CMakeDepsProvider].targets.copy()

# If this package is already a required dependency, return that.
cmake_target = self._required_dep_targets.get(target_id)
Expand Down Expand Up @@ -708,7 +696,12 @@ def wrapper(*args, **kwargs):
class EvaluationContext(InvocationContext):
"""Implements InvocationContext interface for EvaluationState."""

__slots__ = ("_state", "_caller_package_id", "_caller_package")
__slots__ = (
"_state",
"_caller_package_id",
"_caller_package",
"_rule_location",
)

def __init__(
self,
Expand All @@ -720,6 +713,7 @@ def __init__(
self._state = state
self._caller_package_id = package_id
self._caller_package = package
self._rule_location = ("<unknown>", list())
assert self._caller_package_id

def __repr__(self):
Expand All @@ -732,6 +726,16 @@ def __repr__(self):
"}\n"
)

def record_rule_location(self, mnemonic):
# Record the path of non-python callers.
s = inspect.stack()
callers = []
for i in range(2, min(6, len(s))):
c = inspect.getframeinfo(s[i][0])
if not c.filename.endswith(".py"):
callers.append(f"{c.filename}:{c.lineno}")
self._rule_location = (mnemonic, callers)

def update_current_package(
self,
package: Optional[Package] = None,
Expand Down Expand Up @@ -829,7 +833,15 @@ def add_rule(
kwargs["analyze_by_default"] = Visibility(
self._caller_package
).analyze_by_default(self.resolve_target_or_label_list(visibility))
self._state.add_rule(rule_id, impl, outs, **kwargs)

self._state.add_rule(
self._rule_location[0],
self._rule_location[1],
rule_id,
impl,
outs,
**kwargs,
)

@trace_exception
def add_analyzed_target(self, target_id: TargetId, info: TargetInfo) -> None:
Expand Down
61 changes: 32 additions & 29 deletions tools/cmake/bazel_to_cmake/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,35 +87,7 @@ def get_bindings_from_args(
return bindings


def main():
ap = argparse.ArgumentParser()
# Used for top-level project and dependencies.
ap.add_argument("--bazel-repo-name", required=True)
ap.add_argument("--cmake-project-name", required=True)
ap.add_argument("--build-rules-output")
ap.add_argument("--cmake-binary-dir")
ap.add_argument("--include-package", action="append", default=[])
ap.add_argument("--exclude-package", action="append", default=[])
ap.add_argument("--repo-mapping", nargs=2, action="append", default=[])
ap.add_argument("--extra-build", action="append", default=[])
ap.add_argument("--exclude-target", action="append", default=[])
ap.add_argument("--bind", action="append", default=[])

# Used for sub-projects only.
ap.add_argument("--load-workspace")
ap.add_argument("--target", action="append", default=[])

# Used for the top-level project only.
ap.add_argument("--save-workspace")
ap.add_argument("--define", action="append", default=[])
ap.add_argument("--ignore-library", action="append", default=[])
ap.add_argument("--cmake-vars")
ap.add_argument("--bazelrc", action="append", default=[])
ap.add_argument("--module", action="append", default=[])
ap.add_argument("--verbose", type=int, default=0)

args = ap.parse_args()

def run_main(args: argparse.Namespace):
assert args.bazel_repo_name
repository_id: RepositoryId = RepositoryId(args.bazel_repo_name)
current_repository: CMakeRepository = CMakeRepository(
Expand Down Expand Up @@ -327,3 +299,34 @@ def _persist_cmakepairs(target: TargetId, cmake_pair: CMakeTargetPair):
pickle.dump(workspace, f)

return 0


def main():
ap = argparse.ArgumentParser()
# Used for top-level project and dependencies.
ap.add_argument("--bazel-repo-name", required=True)
ap.add_argument("--cmake-project-name", required=True)
ap.add_argument("--build-rules-output")
ap.add_argument("--cmake-binary-dir")
ap.add_argument("--include-package", action="append", default=[])
ap.add_argument("--exclude-package", action="append", default=[])
ap.add_argument("--repo-mapping", nargs=2, action="append", default=[])
ap.add_argument("--extra-build", action="append", default=[])
ap.add_argument("--exclude-target", action="append", default=[])
ap.add_argument("--bind", action="append", default=[])

# Used for sub-projects only.
ap.add_argument("--load-workspace")
ap.add_argument("--target", action="append", default=[])

# Used for the top-level project only.
ap.add_argument("--save-workspace")
ap.add_argument("--define", action="append", default=[])
ap.add_argument("--ignore-library", action="append", default=[])
ap.add_argument("--cmake-vars")
ap.add_argument("--bazelrc", action="append", default=[])
ap.add_argument("--module", action="append", default=[])
ap.add_argument("--verbose", type=int, default=0)

args = ap.parse_args()
return run_main(args)
13 changes: 7 additions & 6 deletions tools/cmake/bazel_to_cmake/starlark/bazel_globals.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
from .select import Select
from .struct import Struct


T = TypeVar("T")


Expand Down Expand Up @@ -158,12 +159,10 @@ def bazel_native(self):
return BazelNativeBuildRules(self._context)

def bazel_select(self, conditions: Dict[RelativeLabel, T]) -> Select[T]:
return Select(
{
self._context.resolve_target_or_label(condition): value
for condition, value in conditions.items()
}
)
return Select({
self._context.resolve_target_or_label(condition): value
for condition, value in conditions.items()
})

bazel_provider = staticmethod(provider)

Expand Down Expand Up @@ -208,6 +207,7 @@ def register_native_build_rule(impl):
name = impl.__name__

def wrapper(self, *args, **kwargs):
self._context.record_rule_location(name) # pylint: disable=protected-access
return impl(self._context, *args, **kwargs) # pylint: disable=protected-access

setattr(BazelNativeBuildRules, name, wrapper)
Expand All @@ -219,6 +219,7 @@ def register_native_workspace_rule(impl):
name = impl.__name__

def wrapper(self, *args, **kwargs):
self._context.record_rule_location(name) # pylint: disable=protected-access
return impl(self._context, *args, **kwargs) # pylint: disable=protected-access

setattr(BazelNativeWorkspaceRules, name, wrapper)
Expand Down
4 changes: 4 additions & 0 deletions tools/cmake/bazel_to_cmake/starlark/invocation_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ def caller_repository_name(self) -> str:
def caller_package_id(self) -> PackageId:
raise NotImplementedError("caller_package_id")

def record_rule_location(self, mnemonic):
# Adds debugging information to registered rules.
pass

def workspace_root_for_label(self, repository_id: RepositoryId) -> str:
# This should return something like the Package.source_directory
return self.resolve_source_root(repository_id).as_posix()
Expand Down
41 changes: 41 additions & 0 deletions tools/cmake/bazel_to_cmake/starlark/rule.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,47 @@ def impl(ctx: RuleCtx):

return Attr(handle)

@staticmethod
def string_list(
mandatory: bool = False,
allow_empty: bool = True,
*,
default: Optional[List[str]] = None,
doc: str = "",
):
"""https://bazel.build/rules/lib/attr#string_list"""
del doc

if default is None:
default = []

def handle(
context: InvocationContext,
name: str,
value: Optional[List[str]],
outs: List[TargetId],
):
if mandatory and value is None:
raise ValueError(f"Attribute {name} not specified")
if value is None:
value = default
if not value and not allow_empty:
raise ValueError(f"Attribute {name} is empty")

del outs
del context

def impl(ctx: RuleCtx):
setattr(
ctx.attr,
name,
ctx._context.evaluate_configurable_list(value),
)

return impl

return Attr(handle)

@staticmethod
def label(
default: Optional[Configurable[RelativeLabel]] = None,
Expand Down
1 change: 1 addition & 0 deletions tools/cmake/bazel_to_cmake/starlark/rule_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ def _empty_rule_impl(ctx):
implementation = _empty_rule_impl,
attrs = {
"a_string": attr.string(default = "b"),
"a_stringlist": attr.string_list(),
"a_label": attr.label(allow_files = [".header"]),
"a_labellist": attr.label_list(),
"a_bool": attr.bool(default = False),
Expand Down
Loading

0 comments on commit 94870d8

Please sign in to comment.