Skip to content

Commit

Permalink
Move parse_xcframework_info_plist from feature to build setting (#2054)
Browse files Browse the repository at this point in the history
- Introduce build settings for rules_apple with
`parse_xcframework_info_plist`.
- Adds support for configurable build settings into
`apple_verification_test`.
- Updates XCFramework import rules and tests for XCFramework processor
tool.

(cherry picked from commit 5bdfb0a)
  • Loading branch information
keith authored Aug 14, 2023
1 parent 700f51a commit f1ac703
Show file tree
Hide file tree
Showing 10 changed files with 177 additions and 8 deletions.
1 change: 1 addition & 0 deletions apple/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ filegroup(
name = "for_bazel_tests",
testonly = 1,
srcs = glob(["**"]) + [
"//apple/build_settings:for_bazel_tests",
"//apple/internal:for_bazel_tests",
"//apple/testing:for_bazel_tests",
],
Expand Down
30 changes: 30 additions & 0 deletions apple/build_settings/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Build settings used throughout rules_apple build rules.

load("@bazel_skylib//rules:common_settings.bzl", "bool_flag")
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")

package(default_visibility = ["//visibility:public"])

licenses(["notice"])

# Configuration for enabling XCFramework import rules use the xcframework_processor_tool to
# parse the XCFramework bundle Info.plist file. See apple/internal/apple_xcframework_import.bzl
bool_flag(
name = "parse_xcframework_info_plist",
build_setting_default = False,
)

bzl_library(
name = "attrs",
srcs = ["attrs.bzl"],
)

# Consumed by bazel tests.
filegroup(
name = "for_bazel_tests",
testonly = 1,
srcs = glob(["**"]),
visibility = [
"//apple:__subpackages__",
],
)
64 changes: 64 additions & 0 deletions apple/build_settings/attrs.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Copyright 2022 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.

"""Apple build settings attributes to be added to rules that read configuration settings."""

# List of all registered build settings at `rules_apple/apple/build_settings/BUILD`.
_BUILD_SETTINGS = [
"parse_xcframework_info_plist",
]

# Build settings label template including label prefix.
_BUILD_SETTING_LABEL_TEMPLATE = "@build_bazel_rules_apple//apple/build_settings:{name}"

build_settings = struct(
# A list of labels is shared for apple_verification_test transition to allow
# tests set these custom build settings.
all_labels = [
_BUILD_SETTING_LABEL_TEMPLATE.format(
name = build_setting,
)
for build_setting in _BUILD_SETTINGS
],
# The following struct fields are dynamically generated using each build
# setting. Each build setting struct will have the following format:
#
# struct(
# build_setting_a = struct(
# label = "rules_apple/apple/build_settings:build_setting_a"
# attr = {
# "_build_setting_a": attr.label(
# default = "rules_apple/apple/build_settings:build_setting_a",
# )
# }
# )
# )
**{
build_setting: struct(
label = _BUILD_SETTING_LABEL_TEMPLATE.format(
name = build_setting,
),
attr = {
"_{build_setting_name}".format(
build_setting_name = build_setting,
): attr.label(
default = _BUILD_SETTING_LABEL_TEMPLATE.format(
name = build_setting,
),
),
},
)
for build_setting in _BUILD_SETTINGS
}
)
2 changes: 2 additions & 0 deletions apple/internal/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,11 @@ bzl_library(
":intermediates",
":rule_factory",
"//apple:providers",
"//apple/build_settings:attrs",
"//apple/internal/aspects:swift_usage_aspect",
"@bazel_skylib//lib:dicts",
"@bazel_skylib//lib:paths",
"@bazel_skylib//rules:common_settings",
"@bazel_tools//tools/cpp:toolchain_utils.bzl",
"@build_bazel_apple_support//lib:apple_support",
"@build_bazel_rules_swift//swift",
Expand Down
13 changes: 11 additions & 2 deletions apple/internal/apple_xcframework_import.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
"""Implementation of XCFramework import rules."""

load("@build_bazel_apple_support//lib:apple_support.bzl", "apple_support")
load(
"@build_bazel_rules_apple//apple/build_settings:attrs.bzl",
"build_settings",
)
load(
"@build_bazel_rules_apple//apple/internal:apple_toolchains.bzl",
"AppleMacToolsToolchainInfo",
Expand All @@ -41,6 +45,7 @@ load(
load("@build_bazel_rules_swift//swift:swift.bzl", "SwiftToolchainInfo", "swift_clang_module_aspect", "swift_common")
load("@bazel_skylib//lib:dicts.bzl", "dicts")
load("@bazel_skylib//lib:paths.bzl", "paths")
load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain", "use_cpp_toolchain")

# Currently, XCFramework bundles can contain Apple frameworks or libraries.
Expand Down Expand Up @@ -431,6 +436,7 @@ def _apple_dynamic_xcframework_import_impl(ctx):
features = ctx.features
grep_includes = ctx.file._grep_includes
label = ctx.label
parse_xcframework_info_plist = ctx.attr._parse_xcframework_info_plist[BuildSettingInfo].value
xcframework_imports = ctx.files.xcframework_imports
xcode_config = ctx.attr._xcode_config[apple_common.XcodeVersionConfig]

Expand All @@ -445,7 +451,7 @@ def _apple_dynamic_xcframework_import_impl(ctx):
apple_fragment = apple_fragment,
apple_mac_toolchain_info = apple_mac_toolchain_info,
label = label,
parse_xcframework_info_plist = "apple.parse_xcframework_info_plist" in features,
parse_xcframework_info_plist = parse_xcframework_info_plist,
target_triplet = target_triplet,
xcframework = xcframework,
xcode_config = xcode_config,
Expand Down Expand Up @@ -539,6 +545,7 @@ def _apple_static_xcframework_import_impl(ctx):
has_swift = ctx.attr.has_swift
label = ctx.label
linkopts = ctx.attr.linkopts
parse_xcframework_info_plist = ctx.attr._parse_xcframework_info_plist[BuildSettingInfo].value
xcframework_imports = ctx.files.xcframework_imports
xcode_config = ctx.attr._xcode_config[apple_common.XcodeVersionConfig]

Expand All @@ -550,7 +557,7 @@ def _apple_static_xcframework_import_impl(ctx):
apple_fragment = apple_fragment,
apple_mac_toolchain_info = apple_mac_toolchain_info,
label = label,
parse_xcframework_info_plist = "apple.parse_xcframework_info_plist" in features,
parse_xcframework_info_plist = parse_xcframework_info_plist,
target_triplet = target_triplet,
xcframework = xcframework,
xcode_config = xcode_config,
Expand Down Expand Up @@ -694,6 +701,7 @@ objc_library(
implementation = _apple_dynamic_xcframework_import_impl,
attrs = dicts.add(
rule_factory.common_tool_attributes,
build_settings.parse_xcframework_info_plist.attr,
swift_common.toolchain_attrs(),
{
"xcframework_imports": attr.label_list(
Expand Down Expand Up @@ -769,6 +777,7 @@ objc_library(
implementation = _apple_static_xcframework_import_impl,
attrs = dicts.add(
rule_factory.common_tool_attributes,
build_settings.parse_xcframework_info_plist.attr,
swift_common.toolchain_attrs(),
{
"alwayslink": attr.bool(
Expand Down
1 change: 1 addition & 0 deletions test/starlark_tests/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ bzl_library(
srcs = glob(["**/*.bzl"]),
deps = [
"//apple:providers",
"//apple/build_settings:attrs",
"//apple/internal:apple_product_type",
"@bazel_skylib//lib:dicts",
"@bazel_skylib//lib:new_sets",
Expand Down
20 changes: 18 additions & 2 deletions test/starlark_tests/apple_dynamic_xcframework_import_tests.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
"""apple_dynamic_xcframework_import Starlark tests."""

load(":rules/analysis_failure_message_test.bzl", "analysis_failure_message_test")
load(
":rules/analysis_target_actions_test.bzl",
"analysis_contains_xcframework_processor_action_test",
)
load(":rules/apple_verification_test.bzl", "apple_verification_test")
load(":rules/common_verification_tests.bzl", "archive_contents_test", "binary_contents_test")

Expand Down Expand Up @@ -165,6 +169,9 @@ def apple_dynamic_xcframework_import_test_suite(name):
archive_contents_test(
name = "{}_contains_imported_xcframework_framework_files_with_xcframework_import_tool".format(name),
build_type = "simulator",
build_settings = {
"//apple/build_settings:parse_xcframework_info_plist": "True",
},
target_under_test = "//test/starlark_tests/targets_under_test/ios:app_with_imported_xcframework",
contains = [
"$BUNDLE_ROOT/Frameworks/generated_dynamic_xcframework_with_headers.framework/Info.plist",
Expand All @@ -178,12 +185,14 @@ def apple_dynamic_xcframework_import_test_suite(name):
macho_load_commands_contain = [
"name @rpath/generated_dynamic_xcframework_with_headers.framework/generated_dynamic_xcframework_with_headers (offset 24)",
],
target_features = ["apple.parse_xcframework_info_plist"],
tags = [name],
)
archive_contents_test(
name = "{}_swift_contains_imported_swift_xcframework_framework_files_with_xcframework_import_tool".format(name),
build_type = "simulator",
build_settings = {
"//apple/build_settings:parse_xcframework_info_plist": "True",
},
target_under_test = "//test/starlark_tests/targets_under_test/ios:swift_app_with_imported_swift_xcframework",
contains = [
"$BUNDLE_ROOT/Frameworks/SwiftFmwkWithGenHeader.framework/Info.plist",
Expand All @@ -197,7 +206,14 @@ def apple_dynamic_xcframework_import_test_suite(name):
macho_load_commands_contain = [
"name @rpath/SwiftFmwkWithGenHeader.framework/SwiftFmwkWithGenHeader (offset 24)",
],
target_features = ["apple.parse_xcframework_info_plist"],
tags = [name],
)

# Verify XCFramework processor tool action is registered via build setting.
analysis_contains_xcframework_processor_action_test(
name = "{}_imported_xcframework_framework_files_registers_action_with_xcframework_import_tool".format(name),
target_under_test = "//test/starlark_tests/targets_under_test/apple:ios_imported_dynamic_xcframework",
target_mnemonic = "ProcessXCFrameworkFiles",
tags = [name],
)

Expand Down
20 changes: 18 additions & 2 deletions test/starlark_tests/apple_static_xcframework_import_tests.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@

"""apple_static_xcframework_import Starlark tests."""

load(
":rules/analysis_target_actions_test.bzl",
"analysis_contains_xcframework_processor_action_test",
)
load(":rules/common_verification_tests.bzl", "archive_contents_test")

def apple_static_xcframework_import_test_suite(name):
Expand Down Expand Up @@ -134,7 +138,9 @@ def apple_static_xcframework_import_test_suite(name):
"_OBJC_CLASS_$_SharedClass",
],
not_contains = ["$BUNDLE_ROOT/Frameworks/"],
target_features = ["apple.parse_xcframework_info_plist"],
build_settings = {
"//apple/build_settings:parse_xcframework_info_plist": "True",
},
tags = [name],
)
archive_contents_test(
Expand All @@ -147,7 +153,17 @@ def apple_static_xcframework_import_test_suite(name):
"_OBJC_CLASS_$__TtC34generated_swift_static_xcframework11SharedClass",
],
contains = ["$BUNDLE_ROOT/Frameworks/libswiftCore.dylib"],
target_features = ["apple.parse_xcframework_info_plist"],
build_settings = {
"//apple/build_settings:parse_xcframework_info_plist": "True",
},
tags = [name],
)

# Verify XCFramework processor tool action is registered via build setting.
analysis_contains_xcframework_processor_action_test(
name = "{}_ios_application_with_imported_static_xcframework_registers_action_with_xcframework_import_tool".format(name),
target_under_test = "//test/starlark_tests/targets_under_test/apple:ios_imported_static_xcframework",
target_mnemonic = "ProcessXCFrameworkFiles",
tags = [name],
)

Expand Down
8 changes: 8 additions & 0 deletions test/starlark_tests/rules/analysis_target_actions_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

"""Starlark analysis test inspecting target under test actions."""

load("@build_bazel_rules_apple//apple/build_settings:attrs.bzl", "build_settings")
load(
"@bazel_skylib//lib:unittest.bzl",
"analysistest",
Expand Down Expand Up @@ -167,3 +168,10 @@ List of action mnemonics not expected to be found on the target under test.""",

# Default analysis_target_actions_test without cfg.
analysis_target_actions_test = make_analysis_target_actions_test()

# The folowing test rules are used in more than one test suite and thus they are defined here.
analysis_contains_xcframework_processor_action_test = make_analysis_target_actions_test(
config_settings = {
build_settings.parse_xcframework_info_plist.label: True,
},
)
26 changes: 24 additions & 2 deletions test/starlark_tests/rules/apple_verification_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ This rule is meant to be used only for rules_apple tests and are considered impl
that may change at any time. Please do not depend on this rule.
"""

load("@build_bazel_rules_apple//apple/build_settings:attrs.bzl", "build_settings")
load(
"@build_bazel_rules_apple//apple/internal:apple_product_type.bzl", # buildifier: disable=bzl-visibility
"apple_product_type",
Expand Down Expand Up @@ -81,20 +82,37 @@ Internal Error: A verification test should only specify `apple_platforms` or `cp
command_line_option = "//command_line_option:%s" % cpu_option
output_dictionary.update({command_line_option: ",".join(cpus)})

# Features
existing_features = settings.get("//command_line_option:features") or []
if hasattr(attr, "target_features"):
existing_features.extend(attr.target_features)
if hasattr(attr, "sanitizer") and attr.sanitizer != "none":
existing_features.append(attr.sanitizer)
output_dictionary["//command_line_option:features"] = existing_features

# Build settings
for build_setting in build_settings.all_labels:
if build_setting in getattr(attr, "build_settings", []):
build_setting_value = attr.build_settings[build_setting]
build_setting_type = type(settings[build_setting])

# The `build_settings` rule attribute requires string values. However, build
# settings can have many types. In order to set the correct type, we inspect
# the default value from settings, and cast accordingly.
if build_setting_type == "bool":
build_setting_value = bool(build_setting_value)

output_dictionary[build_setting] = build_setting_value
else:
output_dictionary[build_setting] = settings[build_setting]

return output_dictionary

apple_verification_transition = transition(
implementation = _apple_verification_transition_impl,
inputs = [
"//command_line_option:features",
],
] + build_settings.all_labels,
outputs = [
"//command_line_option:apple_generate_dsym",
"//command_line_option:apple_platforms",
Expand All @@ -108,7 +126,7 @@ apple_verification_transition = transition(
"//command_line_option:objc_enable_binary_stripping",
"//command_line_option:tvos_cpus",
"//command_line_option:watchos_cpus",
],
] + build_settings.all_labels,
)

def _apple_verification_test_impl(ctx):
Expand Down Expand Up @@ -241,6 +259,10 @@ considered to be an error if this is set with `cpus` as both opt into different
resolution.
""",
),
"build_settings": attr.label_keyed_string_dict(
mandatory = False,
doc = "Build settings for target under test.",
),
"build_type": attr.string(
mandatory = True,
values = ["simulator", "device"],
Expand Down

0 comments on commit f1ac703

Please sign in to comment.