Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
9e224bb
Add use_runfiles aspect_hint to include runfiles for specific cc_libr…
gkoreman Jun 26, 2024
df334c1
Change the resource aspect hint to be more general
gkoreman Jun 26, 2024
7c80246
Add missing load for AppleResourceHintInfo
gkoreman Jul 5, 2024
d835f0c
Add tests for runfiles and resources style data included from a cc_li…
gkoreman Jul 5, 2024
b8ea428
Add bzl_library for resource_aspect_hint
gkoreman Jul 5, 2024
3cd3c76
Add the bzl_library for resource_aspect_hint and run //doc:update
gkoreman Jul 5, 2024
efa38a5
Use correct paths for resources.
gkoreman Jul 5, 2024
6188803
Merge branch 'master' into use_runfiles
gkoreman Jul 5, 2024
acce355
Test suppress_resources and improve test naming
gkoreman Jul 5, 2024
db24d5e
Fix buildifier sorting
gkoreman Jul 5, 2024
4f186bb
Merge branch 'master' into use_runfiles
luispadron Jul 23, 2024
1b6db64
Remove unneeded @unsorted-dict-items
gkoreman Jul 25, 2024
eaf5275
Update error formatting
gkoreman Jul 25, 2024
5c7dd8a
Extract default_action check into variables
gkoreman Jul 25, 2024
2476de4
Add comment to explain why dylibs are excluded
gkoreman Jul 25, 2024
dc3e59a
Add comment to explain possible values for AppleResourceHintInfo acti…
gkoreman Jul 25, 2024
26c42c5
Fix buildifier warning
gkoreman Jul 25, 2024
d451086
Convert to use struct constants instead of strings.
gkoreman Jul 31, 2024
8662a61
Convert if check to positive assertion
gkoreman Jul 31, 2024
8e30c51
Alphabetize the struct definitions
gkoreman Aug 4, 2024
6713608
Add simple example of runfiles layout
gkoreman Aug 4, 2024
1905929
Merge branch 'master' into use_runfiles
gkoreman Aug 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions apple/BUILD
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
load("//apple/internal/aspects:resource_aspect_hint.bzl", "apple_resource_hint")
load(":cc_toolchain_forwarder.bzl", "cc_toolchain_forwarder")

package(default_visibility = ["//visibility:public"])
Expand Down Expand Up @@ -278,3 +279,20 @@ filegroup(
],
visibility = ["//:__pkg__"],
)

# An aspect hint that enables runfile inclusion as AppleResources
# for cc_libraries. Runfiles keep their folder structure.
apple_resource_hint(
name = "use_resources",
action = "RESOURCES",
)

apple_resource_hint(
name = "use_runfiles",
action = "RUNFILES",
)

apple_resource_hint(
name = "suppress_resources",
action = "SUPPRESS",
)
8 changes: 8 additions & 0 deletions apple/internal/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ bzl_library(
"//apple:providers",
"//apple/internal/aspects:framework_provider_aspect",
"//apple/internal/aspects:resource_aspect",
"//apple/internal/aspects:resource_aspect_hint",
"//apple/internal/utils:clang_rt_dylibs",
"//apple/internal/utils:main_thread_checker_dylibs",
"@bazel_skylib//lib:collections",
Expand Down Expand Up @@ -394,6 +395,7 @@ bzl_library(
"//apple:providers",
"//apple/internal/aspects:framework_provider_aspect",
"//apple/internal/aspects:resource_aspect",
"//apple/internal/aspects:resource_aspect_hint",
"//apple/internal/utils:clang_rt_dylibs",
"//apple/internal/utils:main_thread_checker_dylibs",
],
Expand Down Expand Up @@ -533,6 +535,7 @@ bzl_library(
"//apple/internal/aspects:app_intents_aspect",
"//apple/internal/aspects:framework_provider_aspect",
"//apple/internal/aspects:resource_aspect",
"//apple/internal/aspects:resource_aspect_hint",
"//apple/internal/aspects:swift_usage_aspect",
"//apple/internal/testing:apple_test_bundle_support",
"@bazel_skylib//lib:dicts",
Expand All @@ -556,6 +559,7 @@ bzl_library(
"//apple:providers",
"//apple/internal/aspects:framework_provider_aspect",
"//apple/internal/aspects:resource_aspect",
"//apple/internal/aspects:resource_aspect_hint",
"//apple/internal/aspects:swift_dynamic_framework_aspect",
"//apple/internal/aspects:swift_usage_aspect",
"//apple/internal/testing:apple_test_bundle_support",
Expand Down Expand Up @@ -667,6 +671,7 @@ bzl_library(
"//apple:providers",
"//apple/internal/aspects:framework_provider_aspect",
"//apple/internal/aspects:resource_aspect",
"//apple/internal/aspects:resource_aspect_hint",
"//apple/internal/utils:clang_rt_dylibs",
"//apple/internal/utils:main_thread_checker_dylibs",
"@bazel_tools//tools/cpp:toolchain_utils.bzl",
Expand Down Expand Up @@ -703,6 +708,7 @@ bzl_library(
"//apple:providers",
"//apple/internal/aspects:framework_provider_aspect",
"//apple/internal/aspects:resource_aspect",
"//apple/internal/aspects:resource_aspect_hint",
"//apple/internal/utils:clang_rt_dylibs",
"//apple/internal/utils:main_thread_checker_dylibs",
"@bazel_skylib//lib:sets",
Expand Down Expand Up @@ -738,6 +744,7 @@ bzl_library(
"//apple:providers",
"//apple/internal/aspects:framework_provider_aspect",
"//apple/internal/aspects:resource_aspect",
"//apple/internal/aspects:resource_aspect_hint",
"//apple/internal/utils:clang_rt_dylibs",
"//apple/internal/utils:main_thread_checker_dylibs",
"@bazel_skylib//lib:sets",
Expand Down Expand Up @@ -771,6 +778,7 @@ bzl_library(
":transition_support",
"//apple:providers",
"//apple/internal/aspects:resource_aspect",
"//apple/internal/aspects:resource_aspect_hint",
"//apple/internal/aspects:swift_usage_aspect",
"//apple/internal/utils:files",
"@bazel_skylib//lib:partial",
Expand Down
12 changes: 12 additions & 0 deletions apple/internal/aspects/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,18 @@ bzl_library(
],
)

bzl_library(
name = "resource_aspect_hint",
srcs = ["resource_aspect_hint.bzl"],
visibility = [
"//apple/internal:__pkg__",
"//apple/internal/testing:__pkg__",
],
deps = [
"@build_bazel_rules_swift//swift",
],
)

bzl_library(
name = "swift_dynamic_framework_aspect",
srcs = ["swift_dynamic_framework_aspect.bzl"],
Expand Down
57 changes: 53 additions & 4 deletions apple/internal/aspects/resource_aspect.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ load(
"@build_bazel_rules_apple//apple/internal/providers:apple_debug_info.bzl",
"AppleDebugInfo",
)
load(
"@build_bazel_rules_apple//apple/internal/aspects:resource_aspect_hint.bzl",
"AppleResourceHintInfo",
)
load(
"@build_bazel_rules_apple//apple/internal/providers:framework_import_bundle_info.bzl",
"AppleFrameworkImportBundleInfo",
Expand Down Expand Up @@ -125,48 +129,82 @@ def _apple_resource_aspect_impl(target, ctx):
collect_structured_args = {}
collect_framework_import_bundle_files = None

hint_action = None
default_action = None

# TODO: remove usage of `getattr` and use `aspect_ctx.rule.attr.aspect_hints` directly when we drop Bazel 6.
aspect_hint = None
for hint in getattr(ctx.rule.attr, "aspect_hints", []):
if AppleResourceHintInfo in hint:
if aspect_hint:
fail(("Conflicting AppleResourceHintInfo from aspect hints " +
"'{hint1}' and '{hint2}'. Only one is " +
"allowed.").format(
hint1 = str(aspect_hint.label),
hint2 = str(hint.label),
))
aspect_hint = hint
hint_action = hint[AppleResourceHintInfo].action

# Owner to attach to the resources as they're being bucketed.
owner = None

# The name of the bundle directory to place resources within, if required.
bundle_name = None

if ctx.rule.kind == "objc_library":
default_action = "RESOURCES"
collect_args["res_attrs"] = ["data"]

# Only set objc_library targets as owners if they have srcs, non_arc_srcs or deps. This
# treats objc_library targets without sources as resource aggregators.
if ctx.rule.attr.srcs or ctx.rule.attr.non_arc_srcs or ctx.rule.attr.deps:
owner = str(ctx.label)

elif ctx.rule.kind == "cc_library":
default_action = "RUNFILES"
collect_args["res_attrs"] = ["data"]

elif ctx.rule.kind == "objc_import":
default_action = "RESOURCES"
collect_args["res_attrs"] = ["data"]

elif ctx.rule.kind == "cc_import":
default_action = "RUNFILES"
collect_args["res_attrs"] = ["data"]

elif ctx.rule.kind == "swift_library":
default_action = "RESOURCES"
module_names = [x.name for x in target[SwiftInfo].direct_modules if x.swift]
bucketize_args["swift_module"] = module_names[0] if module_names else None
collect_args["res_attrs"] = ["data"]
owner = str(ctx.label)

elif ctx.rule.kind in ["apple_static_framework_import", "apple_static_xcframework_import"]:
default_action = "RESOURCES"
if AppleFrameworkImportBundleInfo in target:
collect_framework_import_bundle_files = target[AppleFrameworkImportBundleInfo].bundle_files
collect_args["res_attrs"] = ["data"]
owner = str(ctx.label)

elif ctx.rule.kind == "apple_resource_group":
default_action = "RESOURCES"
collect_args["res_attrs"] = ["resources"]
collect_structured_args["res_attrs"] = ["structured_resources"]

elif ctx.rule.kind == "apple_resource_bundle":
default_action = "RESOURCES"
collect_infoplists_args["res_attrs"] = ["infoplists"]
collect_args["res_attrs"] = ["resources"]
collect_structured_args["res_attrs"] = ["structured_resources"]
process_args["bundle_id"] = ctx.rule.attr.bundle_id or None
bundle_name = "{}.bundle".format(ctx.rule.attr.bundle_name or ctx.label.name)

if hint_action != None:
default_action = hint_action

# Collect all resource files related to this target.
if collect_infoplists_args:
if collect_infoplists_args and default_action == "RESOURCES":
infoplists = resources.collect(
attr = ctx.rule.attr,
**collect_infoplists_args
Expand All @@ -190,7 +228,7 @@ def _apple_resource_aspect_impl(target, ctx):
),
)

if collect_args:
if collect_args and default_action == "RESOURCES":
resource_files = resources.collect(
attr = ctx.rule.attr,
**collect_args
Expand All @@ -213,7 +251,7 @@ def _apple_resource_aspect_impl(target, ctx):
),
)

if collect_structured_args:
if collect_structured_args and default_action == "RESOURCES":
# `structured_resources` requires an explicit parent directory, requiring them to be
# processed differently from `resources` and resources inherited from other fields.
#
Expand Down Expand Up @@ -264,7 +302,7 @@ def _apple_resource_aspect_impl(target, ctx):
)

# Collect .bundle/ files from framework_import rules
if collect_framework_import_bundle_files:
if collect_framework_import_bundle_files and default_action == "RESOURCES":
parent_dir_param = partial.make(
resources.bundle_relative_parent_dir,
extension = "bundle",
Expand All @@ -278,6 +316,17 @@ def _apple_resource_aspect_impl(target, ctx):
),
)

if default_action == "RUNFILES":
# Gather the runfiles and mark them as pre-processed/unprocessed
apple_resource_infos.append(
resources.bucketize_typed(
[x for x in target[DefaultInfo].default_runfiles.files.to_list() if x.extension != "dylib"],
owner = None,
bucket_type = "unprocessed",
parent_dir_param = partial.make(resources.runfiles_resources_parent_dir),
),
)

# Get the providers from dependencies, referenced by deps and locations for resources.
apple_debug_infos = []
apple_dsym_bundle_infos = []
Expand Down
114 changes: 114 additions & 0 deletions apple/internal/aspects/resource_aspect_hint.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# Copyright 2024 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Implementation of the `apple_resource_hint` rule."""

_resource_actions = ["RESOURCES", "RUNFILES", "SUPPRESS"]

AppleResourceHintInfo = provider(
doc = """Provider that propagates desire to automatically bundle runfiles, resources, or suppress both.""",
# @unsorted-dict-items
fields = {
"action": "Which resource action to run.",
},
)

def _apple_resource_hint_impl(ctx):
if ctx.attr.action not in _resource_actions:
fail(str(ctx.label) + " apple resource hint allowed to take values {" +
", ".join(_resource_actions) + "} but was set to unallowed value " +
ctx.attr.action)
return AppleResourceHintInfo(
action = ctx.attr.action,
)

apple_resource_hint = rule(
attrs = {
"action": attr.string(
mandatory = True,
doc = """
Hints the resource collector to take a specific action.
Available actions are
`RESOURCES` collect all labels referenced in the data attribute, process them based on
file extension, flatten the folder heirarchy and include them in Contents/Resources
`RUNFILES` collect all runfiles without processing and include them in Contents/Resources.
`SUPPRESS` stop any collection of resources on this target. Transitive runfiles may still be
collected based on ancestor resource rules.
""",
),
},
doc = """\
Defines an aspect hint that generates an appropriate AppleResourceHintInfo based on the
runfiles for this target.

> [!NOTE]
> Bazel 6 users must set the `--experimental_enable_aspect_hints` flag to utilize
> this rule. In addition, downstream consumers of rules that utilize this rule
> must also set the flag. The flag is enabled by default in Bazel 7.

Some rules like `cc_library` may have data associated with them in the data attribute
that is needed at runtime. If the library was linked in a `cc_binary` then those data
files would be made available to the application as `runfiles`. To control this
functionality with a `macos_application` you may use this aspect hint.


#### Collect resources of a cc_library

By default a cc_library will add its runfiles to the Contents/Resources folder of a
`macos_application`. To alter this behavior and have it collect resources instead
you can add this pre-built aspect hint. This will cause resources to be collected
and processed like objc_library.

```build
# //my/project/BUILD
cc_library(
name = "somelib",
data = ["mydata.txt"],
aspect_hints = ["@build_bazel_rules_apple//apple:use_resources"],
)
```

#### Collect runfiles of a objc_library

Similar to above, you can modify the default resource collection behavior of
an objc_library by adding an aspect hint to `use_runfiles` instead of resources.

```build
# //my/project/BUILD
objc_library(
name = "somelib",
data = ["mydata.txt"],
aspect_hints = ["@build_bazel_rules_apple//apple:use_runfiles"],
)
```

#### Suppress resource collection

In some situations you may wish to suppress resource or runfile collection of
a target. You can add the `suppress_resources` aspect hint to accomplish this.
Note that runfile collection is transitive, so if an ancestor of this target
collects runfiles then this targets runfiles will be included regardless of
any aspect hint applied.

```build
# //my/project/BUILD
objc_library(
name = "somelib",
data = ["mydata.txt"],
aspect_hints = ["@build_bazel_rules_apple//apple:suppress_resources"],
)
```
""",
implementation = _apple_resource_hint_impl,
)
14 changes: 13 additions & 1 deletion apple/internal/resources.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ def _bucketize_typed_data(*, bucket_type, owner = None, parent_dir_param = None,
if types.is_string(parent_dir_param) or parent_dir_param == None:
parent = parent_dir_param
else:
parent = partial.call(parent_dir_param, resource)
parent = partial.call(partial = parent_dir_param, resource = resource)

if ".lproj/" in resource_short_path and (not parent or ".lproj" not in parent):
lproj_path = bundle_paths.farthest_parent(resource_short_path, "lproj")
Expand Down Expand Up @@ -786,6 +786,17 @@ def _structured_resources_parent_dir(*, parent_dir = None, resource):
path = paths.dirname(package_relative).rstrip("/")
return paths.join(parent_dir or "", path or "") or None

def _runfiles_resources_parent_dir(*, resource):
"""Returns the parent directory of the file.

Args:
resource: The resource for which to calculate the package relative path.

Returns:
The package relative path to the parent directory of the resource.
"""
return paths.dirname(resource.path)

def _expand_owners(*, owners):
"""Converts a depset of (path, owner) to a dict of paths to dict of owners.

Expand Down Expand Up @@ -975,4 +986,5 @@ resources = struct(
populated_resource_fields = _populated_resource_fields,
process_bucketized_data = _process_bucketized_data,
structured_resources_parent_dir = _structured_resources_parent_dir,
runfiles_resources_parent_dir = _runfiles_resources_parent_dir,
)
Loading