Skip to content

Commit

Permalink
Use apple_stub_binary for bundles with stub executables.
Browse files Browse the repository at this point in the history
RELNOTES: None.
PiperOrigin-RevId: 161534042
  • Loading branch information
allevato committed Jul 11, 2017
1 parent 3850dcb commit b5a3424
Show file tree
Hide file tree
Showing 6 changed files with 265 additions and 146 deletions.
150 changes: 120 additions & 30 deletions apple/bundling/binary_support.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,20 @@

"""Binary creation support functions."""

load("@build_bazel_rules_apple//apple/bundling:entitlements.bzl",
"entitlements",
"entitlements_support")
load("@build_bazel_rules_apple//apple/bundling:provider_support.bzl",
"provider_support")
load(
"@build_bazel_rules_apple//apple/bundling:entitlements.bzl",
"entitlements",
"entitlements_support",
)
load(
"@build_bazel_rules_apple//apple/bundling:product_support.bzl",
"apple_product_type",
"product_support",
)
load(
"@build_bazel_rules_apple//apple/bundling:provider_support.bzl",
"provider_support",
)


def _get_binary_provider(ctx, provider_key):
Expand All @@ -38,40 +47,79 @@ def _get_binary_provider(ctx, provider_key):
if len(ctx.attr.deps) != 1:
fail("Only one dependency (a binary target) should be specified " +
"as a bundling rule dependency")
providers = provider_support.matching_providers(ctx.attr.deps[0], provider_key)
providers = provider_support.matching_providers(
ctx.attr.deps[0], provider_key)
if providers:
if len(providers) > 1:
fail("Expected only one binary provider")
return providers[0]
return None


def _create_binary(
def _create_stub_binary_target(
name,
platform_type,
product_type_info,
**kwargs):
"""Creates a binary target for a bundle by copying a stub from the SDK.
Some Apple bundles may not need a binary target depending on their product
type; for example, watchOS applications and iMessage sticker packs contain
stub binaries copied from the platform SDK, rather than binaries with user
code. This function creates an `apple_stub_binary` target (instead of
`apple_binary`) that ensures that the platform transition is correct (for
platform selection in downstream dependencies) but that does not cause any
user code to be linked.
Args:
name: The name of the bundle target, from which the binary target's name
will be derived.
platform_type: The platform type for which the binary should be copied.
product_type_info: The information about the product type's stub executable.
**kwargs: The arguments that were passed into the top-level macro.
Returns:
A modified copy of `**kwargs` that should be passed to the bundling rule.
"""
bundling_args = dict(kwargs)

apple_binary_name = "%s.apple_binary" % name
minimum_os_version = kwargs.get("minimum_os_version")

# Remove the deps so that we only pass them to the binary, not to the
# bundling rule.
deps = bundling_args.pop("deps", [])

native.apple_stub_binary(
name = apple_binary_name,
minimum_os_version = minimum_os_version,
platform_type = platform_type,
xcenv_based_path = product_type_info.stub_path,
deps = deps,
tags = ["manual"] + kwargs.get("tags", []),
testonly = kwargs.get("testonly"),
visibility = kwargs.get("visibility"),
)

bundling_args["binary"] = apple_binary_name
bundling_args["deps"] = [apple_binary_name]

return bundling_args


def _create_linked_binary_target(
name,
platform_type,
linkopts,
sdk_frameworks=[],
extension_safe=False,
**kwargs):
"""Creates a binary target for a bundle.
"""Creates a binary target for a bundle by linking user code.
This function also wraps the entitlements handling logic. It returns a
modified copy of the given keyword arguments that has `binary` and
`entitlements` attributes added if necessary and removes other
binary-specific options (such as `linkopts`).
Some Apple bundles may not need a binary target depending on their product
type; for example, watchOS applications and iMessage sticker packs contain
stub binaries copied from the platform SDK, rather than binaries with user
code. This function creates the target anyway (because `apple_binary` is where
the platform transition occurs, which allows dependencies to select on it
properly), but the bundler will not use the binary artifact if it is not
needed; in these cases, even though the target will be created in the graph,
it will not actually be linked.
This function must be called from one of the top-level application or
extension macros, because it invokes a rule to create a target. As such, it
cannot be called within rule implementation functions.
Args:
name: The name of the bundle target, from which the binary target's name
will be derived.
Expand All @@ -87,15 +135,7 @@ def _create_binary(
"""
bundling_args = dict(kwargs)

# If a user provides a "binary" attribute of their own, it is ignored and
# silently overwritten below. Instead of allowing this, we should fail fast
# to prevent confusion.
if "binary" in bundling_args:
fail("Do not provide your own binary; one will be linked from your deps.",
attr="binary")

entitlements_value = bundling_args.pop("entitlements", None)
linkopts = bundling_args.pop("linkopts", [])
minimum_os_version = kwargs.get("minimum_os_version")
provisioning_profile = kwargs.get("provisioning_profile")

Expand Down Expand Up @@ -131,7 +171,7 @@ def _create_binary(
name = apple_binary_name,
srcs = entitlements_srcs,
dylibs = kwargs.get("frameworks"),
extension_safe = kwargs.get("extension_safe"),
extension_safe = extension_safe,
features = kwargs.get("features"),
linkopts = linkopts,
minimum_os_version = minimum_os_version,
Expand All @@ -148,6 +188,56 @@ def _create_binary(
return bundling_args


def _create_binary(name, platform_type, **kwargs):
"""Creates a binary target for a bundle.
This function checks the desired product type of the bundle and creates either
an `apple_binary` or `apple_stub_binary` depending on what the product type
needs. It must be called from one of the top-level application or extension
macros, because it invokes a rule to create a target. As such, it cannot be
called within rule implementation functions.
Args:
name: The name of the bundle target, from which the binary target's name
will be derived.
platform_type: The platform type for which the binary should be built.
**kwargs: The arguments that were passed into the top-level macro.
Returns:
A modified copy of `**kwargs` that should be passed to the bundling rule.
"""
args_copy = dict(kwargs)

linkopts = args_copy.pop("linkopts", [])
sdk_frameworks = args_copy.pop("sdk_frameworks", [])
extension_safe = args_copy.pop("extension_safe", False)

# If a user provides a "binary" attribute of their own, it is ignored and
# silently overwritten below. Instead of allowing this, we should fail fast
# to prevent confusion.
if "binary" in args_copy:
fail("Do not provide your own binary; one will be linked from your deps.",
attr="binary")

# Note the pop/get difference here. If the attribute is present as "private",
# we want to pop it off so that it does not get passed down to the underlying
# bundling rule (this is the macro's way of giving us default information in
# the rule that we don't have access to yet). If the argument is present
# without the underscore, then we leave it in so that the bundling rule can
# access the value the user provided in their build target (if any).
product_type = args_copy.pop("_product_type", None)
if not product_type:
product_type = args_copy.get("product_type")

product_type_info = product_support.product_type_info(product_type)
if product_type_info and product_type_info.stub_path:
return _create_stub_binary_target(
name, platform_type, product_type_info, **args_copy)
else:
return _create_linked_binary_target(
name, platform_type, linkopts, sdk_frameworks, extension_safe,
**args_copy)


# Define the loadable module that lists the exported symbols in this file.
binary_support = struct(
create_binary=_create_binary,
Expand Down
136 changes: 89 additions & 47 deletions apple/bundling/bundler.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -18,49 +18,92 @@ This file is only meant to be imported by the platform-specific top-level rules
(ios.bzl, tvos.bzl, and so forth).
"""

load("@build_bazel_rules_apple//apple:providers.bzl",
"AppleBundleInfo",
"AppleResourceInfo",
"AppleResourceSet",
"apple_resource_set_utils",
)
load("@build_bazel_rules_apple//apple:utils.bzl",
"basename",
"bash_array_string",
"bash_quote",
"dirname",
"group_files_by_directory",
"optionally_prefixed_path",
"relativize_path",
"remove_extension",
)
load("@build_bazel_rules_apple//apple/bundling:binary_support.bzl",
"binary_support")
load("@build_bazel_rules_apple//apple/bundling:bitcode_actions.bzl", "bitcode_actions")
load("@build_bazel_rules_apple//apple/bundling:bundling_support.bzl",
"bundling_support")
load("@build_bazel_rules_apple//apple/bundling:clang_support.bzl",
"clang_support")
load("@build_bazel_rules_apple//apple/bundling:codesigning_support.bzl",
"codesigning_support")
load("@build_bazel_rules_apple//apple/bundling:debug_symbol_actions.bzl", "debug_symbol_actions")
load("@build_bazel_rules_apple//apple/bundling:file_actions.bzl", "file_actions")
load("@build_bazel_rules_apple//apple/bundling:file_support.bzl", "file_support")
load("@build_bazel_rules_apple//apple/bundling:platform_support.bzl",
"platform_support")
load("@build_bazel_rules_apple//apple/bundling:plist_actions.bzl", "plist_actions")
load("@build_bazel_rules_apple//apple/bundling:product_actions.bzl",
"product_actions")
load("@build_bazel_rules_apple//apple/bundling:product_support.bzl",
"product_support")
load("@build_bazel_rules_apple//apple/bundling:provider_support.bzl",
"provider_support")
load("@build_bazel_rules_apple//apple/bundling:resource_actions.bzl",
"resource_actions")
load("@build_bazel_rules_apple//apple/bundling:resource_support.bzl",
"resource_support")
load("@build_bazel_rules_apple//apple/bundling:swift_actions.bzl", "swift_actions")
load("@build_bazel_rules_apple//apple/bundling:swift_support.bzl", "swift_support")
load(
"@build_bazel_rules_apple//apple:providers.bzl",
"AppleBundleInfo",
"AppleResourceInfo",
"AppleResourceSet",
"apple_resource_set_utils",
)
load(
"@build_bazel_rules_apple//apple:utils.bzl",
"basename",
"bash_array_string",
"bash_quote",
"dirname",
"group_files_by_directory",
"optionally_prefixed_path",
"relativize_path",
"remove_extension",
)
load(
"@build_bazel_rules_apple//apple/bundling:binary_support.bzl",
"binary_support",
)
load(
"@build_bazel_rules_apple//apple/bundling:bitcode_actions.bzl",
"bitcode_actions",
)
load(
"@build_bazel_rules_apple//apple/bundling:bundling_support.bzl",
"bundling_support",
)
load(
"@build_bazel_rules_apple//apple/bundling:clang_support.bzl",
"clang_support",
)
load(
"@build_bazel_rules_apple//apple/bundling:codesigning_support.bzl",
"codesigning_support",
)
load(
"@build_bazel_rules_apple//apple/bundling:debug_symbol_actions.bzl",
"debug_symbol_actions",
)
load(
"@build_bazel_rules_apple//apple/bundling:file_actions.bzl",
"file_actions",
)
load(
"@build_bazel_rules_apple//apple/bundling:file_support.bzl",
"file_support",
)
load(
"@build_bazel_rules_apple//apple/bundling:platform_support.bzl",
"platform_support",
)
load(
"@build_bazel_rules_apple//apple/bundling:plist_actions.bzl",
"plist_actions",
)
load(
"@build_bazel_rules_apple//apple/bundling:product_actions.bzl",
"product_actions",
)
load(
"@build_bazel_rules_apple//apple/bundling:product_support.bzl",
"product_support",
)
load(
"@build_bazel_rules_apple//apple/bundling:provider_support.bzl",
"provider_support",
)
load(
"@build_bazel_rules_apple//apple/bundling:resource_actions.bzl",
"resource_actions",
)
load(
"@build_bazel_rules_apple//apple/bundling:resource_support.bzl",
"resource_support",
)
load(
"@build_bazel_rules_apple//apple/bundling:swift_actions.bzl",
"swift_actions",
)
load(
"@build_bazel_rules_apple//apple/bundling:swift_support.bzl",
"swift_support",
)


# Directories inside .frameworks that should not be included in final
Expand Down Expand Up @@ -753,19 +796,18 @@ def _run(
product_info = product_support.product_type_info_for_target(ctx)
if product_info:
has_built_binary = False
stub_binary = product_actions.copy_stub_for_bundle(ctx, product_info)
bundle_merge_files.append(bundling_support.binary_file(
ctx, stub_binary, bundle_name, executable=True))
ctx, ctx.file.binary, bundle_name, executable=True))
if product_info.bundle_path:
# TODO(b/34684393): Figure out if macOS ever uses stub binaries for any
# product types, and if so, is this the right place for them?
bundle_merge_files.append(bundling_support.contents_file(
ctx, stub_binary, product_info.bundle_path, executable=True))
ctx, ctx.file.binary, product_info.bundle_path, executable=True))
# TODO(b/34047985): This should be conditioned on a flag, not just
# compilation mode.
if ctx.var["COMPILATION_MODE"] == "opt":
support_zip = product_actions.create_stub_zip_for_archive_merging(
ctx, product_info)
ctx, ctx.file.binary, product_info)
root_merge_zips.append(bundling_support.bundlable_file(support_zip, "."))
elif hasattr(ctx.attr, "deps"):
if not ctx.attr.deps:
Expand Down
Loading

0 comments on commit b5a3424

Please sign in to comment.