From d59da9fc168abbf3208e6b2da3ccbdd0a36f3daf Mon Sep 17 00:00:00 2001 From: Samuel Giddins Date: Mon, 8 Jun 2020 18:54:27 -0700 Subject: [PATCH 1/6] Spike on framework transition # Conflicts: # rules/framework.bzl # rules/xcodeproj.bzl --- rules/framework.bzl | 56 ++++- rules/library.bzl | 25 +-- rules/precompiled_apple_resource_bundle.bzl | 207 ++++++++++++++++++ rules/transition_support.bzl | 124 +++++++++++ rules/xcodeproj.bzl | 22 +- tests/framework/platforms/BUILD.bazel | 33 +++ tests/framework/platforms/Resources/data.json | 1 + tests/framework/platforms/main.m | 3 + tests/framework/platforms/platform.m | 68 ++++++ tests/framework/platforms/versions.bzl | 90 ++++++++ .../unit-test/test-imports-app/BUILD.bazel | 3 + 11 files changed, 595 insertions(+), 37 deletions(-) create mode 100644 rules/precompiled_apple_resource_bundle.bzl create mode 100644 rules/transition_support.bzl create mode 100644 tests/framework/platforms/BUILD.bazel create mode 100644 tests/framework/platforms/Resources/data.json create mode 100644 tests/framework/platforms/main.m create mode 100644 tests/framework/platforms/platform.m create mode 100644 tests/framework/platforms/versions.bzl diff --git a/rules/framework.bzl b/rules/framework.bzl index 96997f21b..abb053d74 100644 --- a/rules/framework.bzl +++ b/rules/framework.bzl @@ -1,8 +1,18 @@ """Framework rules""" +load("@build_bazel_rules_apple//apple/internal:apple_product_type.bzl", "apple_product_type") +load("@build_bazel_rules_apple//apple:providers.bzl", "AppleBundleInfo") load("@bazel_skylib//lib:paths.bzl", "paths") load("@build_bazel_rules_swift//swift:swift.bzl", "SwiftInfo", "swift_common") load("//rules:library.bzl", "PrivateHeadersInfo", "apple_library") +load("//rules:transition_support.bzl", "transition_support") + +_APPLE_FRAMEWORK_PACKAGING_KWARGS = [ + "visibility", + "tags", + "bundle_id", + "skip_packaging", +] def apple_framework(name, apple_library = apple_library, **kwargs): """Builds and packages an Apple framework. @@ -12,15 +22,15 @@ def apple_framework(name, apple_library = apple_library, **kwargs): apple_library: The macro used to package sources into a library. **kwargs: Arguments passed to the apple_library and apple_framework_packaging rules as appropriate. """ - + framework_packaging_kwargs = {arg: kwargs.pop(arg) for arg in _APPLE_FRAMEWORK_PACKAGING_KWARGS if arg in kwargs} library = apple_library(name = name, **kwargs) apple_framework_packaging( name = name, framework_name = library.namespace, transitive_deps = library.transitive_deps, deps = library.lib_names, - visibility = kwargs.get("visibility", None), - tags = kwargs.get("tags", None), + platforms = library.platforms, + **framework_packaging_kwargs ) def _find_framework_dir(outputs): @@ -99,6 +109,11 @@ def _apple_framework_packaging_impl(ctx): swiftdoc_in = None swiftdoc_out = None + # AppleBundleInfo fields + bundle_id = ctx.attr.bundle_id + infoplist = None + current_apple_platform = transition_support.current_apple_platform(ctx.fragments.apple, ctx.attr._xcode_config) + # collect files for dep in ctx.attr.deps: files = dep.files.to_list() @@ -284,10 +299,25 @@ def _apple_framework_packaging_impl(ctx): cc_info_provider, swift_common.create_swift_info(**swift_info_fields), DefaultInfo(files = depset(framework_files)), + AppleBundleInfo( + archive = None, + archive_root = None, + binary = binary_out, + bundle_id = bundle_id, + bundle_name = framework_name, + bundle_extension = ctx.attr.bundle_extension, + entitlements = None, + infoplist = infoplist, + minimum_os_version = str(current_apple_platform.target_os_version), + platform_type = str(current_apple_platform.platform.platform_type), + product_type = ctx.attr._product_type, + uses_swift = swiftmodule_out != None, + ), ] apple_framework_packaging = rule( implementation = _apple_framework_packaging_impl, + cfg = transition_support.apple_rule_transition, fragments = ["apple"], output_to_genfiles = True, attrs = { @@ -337,6 +367,26 @@ Valid values are: "//rules/hmap:hmaptool", ), ), + "bundle_id": attr.string(mandatory = False), + "bundle_extension": attr.string(mandatory = False, default = "framework"), + "platforms": attr.string_dict( + mandatory = False, + default = {}, + ), + "_product_type": attr.string(default = apple_product_type.static_framework), + # TODO: allow customizing binary type between dynamic/static + # "binary_type": attr.string( + # default = "dylib", + # ), + "_xcode_config": attr.label( + default = configuration_field( + name = "xcode_config_label", + fragment = "apple", + ), + ), + "_whitelist_function_transition": attr.label( + default = "@build_bazel_rules_apple//tools/whitelists/function_transition_whitelist", + ), }, doc = "Packages compiled code into an Apple .framework package", ) diff --git a/rules/library.bzl b/rules/library.bzl index aeb2e9242..282214992 100644 --- a/rules/library.bzl +++ b/rules/library.bzl @@ -4,10 +4,9 @@ load("@rules_cc//cc:defs.bzl", "cc_library", "objc_import", "objc_library") load("@bazel_skylib//lib:paths.bzl", "paths") load("@bazel_skylib//lib:sets.bzl", "sets") load("@build_bazel_rules_apple//apple:apple.bzl", "apple_dynamic_framework_import", "apple_static_framework_import") -load("@build_bazel_rules_apple//apple:resources.bzl", "apple_resource_bundle") load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library") +load("//rules:precompiled_apple_resource_bundle.bzl", "precompiled_apple_resource_bundle") load("//rules:hmap.bzl", "headermap") -load("//rules:substitute_build_settings.bzl", "substitute_build_settings") load("//rules/library:resources.bzl", "wrap_resources_in_filegroup") load("//rules/library:xcconfig.bzl", "settings_from_xcconfig") @@ -157,26 +156,17 @@ FOUNDATION_EXPORT const unsigned char {module_name}VersionString[]; ) return destination -def _generate_resource_bundles(name, library_tools, module_name, resource_bundles, **kwargs): +def _generate_resource_bundles(name, library_tools, module_name, resource_bundles, platforms, **kwargs): bundle_target_names = [] for bundle_name in resource_bundles: target_name = "%s-%s" % (name, bundle_name) - substitute_build_settings( - name = name + ".info.plist", - source = "@build_bazel_rules_ios//rules/library:resource_bundle.plist", - variables = { - "PRODUCT_BUNDLE_IDENTIFIER": "com.cocoapods.%s" % bundle_name, - "PRODUCT_NAME": bundle_name, - }, - tags = _MANUAL, - ) - apple_resource_bundle( + precompiled_apple_resource_bundle( name = target_name, bundle_name = bundle_name, resources = [ library_tools["wrap_resources_in_filegroup"](name = target_name + "_resources", srcs = resource_bundles[bundle_name]), ], - infoplists = [name + ".info.plist"], + platforms = platforms, tags = _MANUAL, ) bundle_target_names.append(target_name) @@ -318,9 +308,12 @@ def apple_library(name, library_tools = {}, export_private_headers = True, names weak_sdk_frameworks = kwargs.pop("weak_sdk_frameworks", []) sdk_includes = kwargs.pop("sdk_includes", []) pch = kwargs.pop("pch", "@build_bazel_rules_ios//rules/library:common.pch") - deps = kwargs.pop("deps", []) + deps = [d for d in kwargs.pop("deps", [])] data = kwargs.pop("data", []) tags = kwargs.pop("tags", []) + platforms = kwargs.pop("platforms", { + "ios": "10.0", # TODO: remove default + }) tags_manual = tags if "manual" in tags else tags + _MANUAL internal_deps = [] lib_names = [] @@ -383,6 +376,7 @@ def apple_library(name, library_tools = {}, export_private_headers = True, names library_tools = library_tools, resource_bundles = kwargs.pop("resource_bundles", {}), module_name = module_name, + platforms = platforms, **kwargs ) deps += resource_bundles @@ -607,4 +601,5 @@ def apple_library(name, library_tools = {}, export_private_headers = True, names launch_screen_storyboard_name = launch_screen_storyboard_name, namespace = namespace, linkopts = linkopts, + platforms = platforms, ) diff --git a/rules/precompiled_apple_resource_bundle.bzl b/rules/precompiled_apple_resource_bundle.bzl new file mode 100644 index 000000000..5a68995e9 --- /dev/null +++ b/rules/precompiled_apple_resource_bundle.bzl @@ -0,0 +1,207 @@ +""" +This provides a resource bundle implementation that builds the resource bundle +only once +NOTE: This rule only exists because of this issue +https://github.com/bazelbuild/rules_apple/issues/319 +if this is ever fixed in bazel it should be removed +""" + +load("@bazel_skylib//lib:partial.bzl", "partial") +load("@bazel_skylib//lib:paths.bzl", "paths") +load("@build_bazel_rules_apple//apple/internal:apple_product_type.bzl", "apple_product_type") +load("@build_bazel_rules_apple//apple/internal:intermediates.bzl", "intermediates") +load("@build_bazel_rules_apple//apple/internal:partials.bzl", "partials") +load("@build_bazel_rules_apple//apple/internal:resource_actions.bzl", "resource_actions") +load("@build_bazel_rules_apple//apple/internal:rule_factory.bzl", "rule_factory") +load("//rules:transition_support.bzl", "transition_support") +load("@build_bazel_rules_apple//apple:providers.bzl", "AppleResourceBundleInfo", "AppleResourceInfo") + +_FAKE_BUNDLE_PRODUCT_TYPE_BY_PLATFORM_TYPE = { + "ios": apple_product_type.application, + "tvos": apple_product_type.application, + "watchos": apple_product_type.watch2_application, +} + +def _precompiled_apple_resource_bundle_impl(ctx): + bundle_name = ctx.attr.bundle_name or ctx.label.name + + attr_dict = {} + for k in dir(ctx.attr): + if k in ("to_json", "to_proto"): + continue + attr_dict[k] = getattr(ctx.attr, k) + + current_apple_platform = transition_support.current_apple_platform(apple_fragment = ctx.fragments.apple, xcode_config = ctx.attr._xcode_config) + attr_dict["platform_type"] = str(current_apple_platform.platform.platform_type) + attr_dict["minimum_os_version"] = str(current_apple_platform.target_os_version) + + # TODO: only do this dance if platform is not macos + attr_dict["_product_type"] = _FAKE_BUNDLE_PRODUCT_TYPE_BY_PLATFORM_TYPE.get(attr_dict["platform_type"], ctx.attr._product_type) + ios_app_ctx_dict = {} + for k in dir(ctx): + if k in ("aspect_ids", "build_setting_value", "rule", "to_json", "to_proto"): + continue + ios_app_ctx_dict[k] = getattr(ctx, k) + ios_app_ctx_dict["attr"] = struct(**attr_dict) + ios_app_ctx = struct(**ios_app_ctx_dict) + + partial_output = partial.call(partials.resources_partial( + top_level_attrs = ["resources"], + # plist_attrs = ["infoplist"] + ), ios_app_ctx) + + # Process the plist ourselves. This is required because + # include_executable_name defaults to True, which results in iTC rejecting + # our binary. + output_plist = ctx.actions.declare_file( + paths.join("%s-intermediates" % ctx.label.name, "Info.plist"), + ) + bundle_id = ctx.attr.bundle_id or "com.cocoapods." + bundle_name + resource_actions.merge_root_infoplists( + ios_app_ctx, + ctx.files.infoplists, + output_plist, + None, + bundle_id = bundle_id, + include_executable_name = False, + ) + + # This is a list of files to pass to bundletool using its format, this has + # a struct with a src and dest mapping that bundle tool uses to copy files + # https://github.com/bazelbuild/rules_apple/blob/d29df97b9652e0442ebf21f1bc0e04921b584f76/tools/bundletool/bundletool_experimental.py#L29-L35 + control_files = [] + input_files = [] + output_files = [] + output_bundle_dir = ctx.actions.declare_directory(paths.join(ctx.attr.name, bundle_name + ".bundle")) + + # Need getattr since the partial_ouput struct will be empty when there are no resources. + # Even so, we want to generate a resource bundle for compatibility. + # TODO: add an attr to allow skipping when there are no resources entirely + bundle_files = getattr(partial_output, "bundle_files", []) + + # `target_location` is a special identifier that tells you in a generic way + # where the resource should end up. This corresponds to: + # https://github.com/bazelbuild/rules_apple/blob/d29df97b9652e0442ebf21f1bc0e04921b584f76/apple/internal/processor.bzl#L107-L119 + # in this use case both "resource" and "content" correspond to the root + # directory of the final Foo.bundle/ + # + # `parent` is the directory the resource should be nested in + # (under `target_location`) for example Base.lproj would be the parent for + # a Localizable.strings file. If there is no `parent`, put it in the root + # + # `sources` is a depset of files or directories that we need to copy into + # the bundle. If it's a directory this likely means the compiler could + # output any number of files (like ibtool from a storyboard) and all the + # contents should be copied to the bundle (this is handled by bundletool) + for target_location, parent, sources in bundle_files: + sources_list = sources.to_list() + parent_output_directory = parent or "" + if target_location != "resource" and target_location != "content": + # For iOS resources these are the only ones we've hit, if we need + # to add more in the future we should be sure to double check where + # the need to end up + fail("Got unexpected target location '{}' for '{}'" + .format(target_location, sources_list)) + input_files.extend(sources_list) + for source in sources_list: + target_path = parent_output_directory + if not source.is_directory: + target_path = paths.join(target_path, source.basename) + output_files.append(target_path) + control_files.append(struct(src = source.path, dest = target_path)) + + # Create a file for bundletool to know what files to copy + # https://github.com/bazelbuild/rules_apple/blob/d29df97b9652e0442ebf21f1bc0e04921b584f76/tools/bundletool/bundletool_experimental.py#L29-L46 + bundletool_instructions = struct( + bundle_merge_files = control_files, + bundle_merge_zips = [], + output = output_bundle_dir.path, + code_signing_commands = "", + post_processor = "", + ) + bundletool_instructions_file = intermediates.file( + ctx.actions, + ctx.label.name, + "bundletool_actions.json", + ) + ctx.actions.write( + output = bundletool_instructions_file, + content = bundletool_instructions.to_json(), + ) + ctx.actions.run( + executable = ctx.executable._bundletool_experimental, + mnemonic = "BundleResources", + progress_message = "Bundling " + bundle_name, + inputs = input_files + [bundletool_instructions_file], + outputs = [output_bundle_dir], + arguments = [bundletool_instructions_file.path], + ) + return [ + AppleResourceInfo( + unowned_resources = depset(), + owners = depset([ + (output_bundle_dir.short_path, ctx.label), + (output_plist.short_path, ctx.label), + ]), + # This is a list of the resources to propagate without changing further + # In this case the tuple parameters are: + # 1. The final directory the resources should end up in, ex Foo.bundle + # would result in Bar.app/Foo.bundle + # 2. The Swift module associated with the resources, this isn't + # required for us since we don't use customModuleProvider in IB + # 3. The resources to propagate, in our case this is just the final + # Foo.bundle directory that contains our real resources + unprocessed = [ + (output_bundle_dir.basename, None, depset([output_bundle_dir, output_plist])), + ], + ), + AppleResourceBundleInfo(), + apple_common.new_objc_provider(), + ] + +precompiled_apple_resource_bundle = rule( + implementation = _precompiled_apple_resource_bundle_impl, + fragments = ["apple"], + cfg = transition_support.apple_rule_transition, + attrs = dict( + # This includes all the undocumented tool requirements for this rule + rule_factory.common_tool_attributes, + infoplists = attr.label_list( + allow_files = [".plist"], + default = [ + Label("@build_bazel_rules_ios//rules/library:resource_bundle.plist"), + ], + ), + bundle_name = attr.string(mandatory = False), + bundle_id = attr.string(mandatory = False), + resources = attr.label_list( + allow_empty = True, + allow_files = True, + ), + bundle_extension = attr.string(mandatory = False, default = "bundle"), + platforms = attr.string_dict( + mandatory = True, + ), + _product_type = attr.string(default = apple_product_type.bundle), + # This badly named property is required even though this isn't an ipa + ipa_post_processor = attr.label( + allow_files = True, + executable = True, + cfg = "exec", + ), + _environment_plist = attr.label( + allow_single_file = True, + # TODO: handle other platforms + default = Label("@build_bazel_rules_apple//apple/internal:environment_plist_ios"), + ), + _whitelist_function_transition = attr.label( + default = Label("@bazel_tools//tools/whitelists/function_transition_whitelist"), + ), + _xcode_config = attr.label( + default = configuration_field( + name = "xcode_config_label", + fragment = "apple", + ), + ), + ), +) diff --git a/rules/transition_support.bzl b/rules/transition_support.bzl new file mode 100644 index 000000000..1d7f847da --- /dev/null +++ b/rules/transition_support.bzl @@ -0,0 +1,124 @@ +"""Starlark transition support for Apple rules.""" + +def _current_apple_platform(apple_fragment, xcode_config): + """Returns a struct containing the platform and target os version""" + cpu = apple_fragment.single_arch_cpu + platform = apple_fragment.single_arch_platform + xcode_config = xcode_config[apple_common.XcodeVersionConfig] + target_os_version = xcode_config.minimum_os_for_platform_type( + platform.platform_type, + ) + return struct( + platform = platform, + target_os_version = target_os_version, + ) + +def _cpu_string(platform_type, settings): + """Generates a _ string for the current target based on the given parameters.""" + if platform_type == "ios": + ios_cpus = settings["//command_line_option:ios_multi_cpus"] + if ios_cpus: + return "ios_{}".format(ios_cpus[0]) + cpu_value = settings["//command_line_option:cpu"] + if cpu_value.startswith("ios_"): + return cpu_value + return "ios_x86_64" + if platform_type == "macos": + macos_cpus = settings["//command_line_option:macos_cpus"] + if macos_cpus: + return "darwin_{}".format(macos_cpus[0]) + return "darwin_x86_64" + if platform_type == "tvos": + tvos_cpus = settings["//command_line_option:tvos_cpus"] + if tvos_cpus: + return "tvos_{}".format(tvos_cpus[0]) + return "tvos_x86_64" + if platform_type == "watchos": + watchos_cpus = settings["//command_line_option:watchos_cpus"] + if watchos_cpus: + return "watchos_{}".format(watchos_cpus[0]) + return "watchos_i386" + + fail("ERROR: Unknown platform type: {}".format(platform_type)) + +def _min_os_version_or_none(attr, platform, attr_platform_type): + if attr_platform_type == platform: + if hasattr(attr, "platforms"): + platforms = attr.platforms + value = platforms.get(platform) + return value + elif hasattr(attr, "minimum_os_version"): + return attr.minimum_os_version + else: + fail("ERROR: must either specify a single platform/minimum_os_version, or specify a dict via platforms") + return None + +def _apple_rule_transition_impl(settings, attr): + """Rule transition for Apple rules.""" + platform_type = str(settings["//command_line_option:apple_platform_type"]) + attr_platform_type = getattr(attr, "platform_type", None) + attr_platforms = getattr(attr, "platforms", None) + fail_on_apple_rule_transition_platform_mismatches = getattr(attr, "fail_on_apple_rule_transition_platform_mismatches", False) + if attr_platform_type and attr_platform_type != platform_type: + if fail_on_apple_rule_transition_platform_mismatches: + fail("ERROR: {}: attribute platform_type set to {}, but inferred to be {}".format(attr.name, attr_platform_type, platform_type)) + platform_type = attr_platform_type + elif attr_platforms and platform_type not in attr_platforms: + if fail_on_apple_rule_transition_platform_mismatches: + print("ERROR: {}: attribute platforms set to {}, but platform inferred to be {}".format(attr.name, attr_platforms, platform_type)) + platform_type = attr_platforms.keys()[0] + ret = { + "//command_line_option:apple configuration distinguisher": "applebin_" + platform_type, + "//command_line_option:apple_platform_type": platform_type, + "//command_line_option:apple_split_cpu": "", + "//command_line_option:compiler": settings["//command_line_option:apple_compiler"], + "//command_line_option:cpu": _cpu_string(platform_type, settings), + "//command_line_option:crosstool_top": ( + settings["//command_line_option:apple_crosstool_top"] + ), + "//command_line_option:fission": [], + "//command_line_option:grte_top": settings["//command_line_option:apple_grte_top"], + "//command_line_option:ios_minimum_os": _min_os_version_or_none(attr, "ios", platform_type), + "//command_line_option:macos_minimum_os": _min_os_version_or_none(attr, "macos", platform_type), + "//command_line_option:tvos_minimum_os": _min_os_version_or_none(attr, "tvos", platform_type), + "//command_line_option:watchos_minimum_os": _min_os_version_or_none(attr, "watchos", platform_type), + } + return ret + +# These flags are a mix of options defined in native Bazel from the following fragments: +# - https://github.com/bazelbuild/bazel/blob/master/src/main/java/com/google/devtools/build/lib/analysis/config/CoreOptions.java +# - https://github.com/bazelbuild/bazel/blob/master/src/main/java/com/google/devtools/build/lib/rules/apple/AppleCommandLineOptions.java +# - https://github.com/bazelbuild/bazel/blob/master/src/main/java/com/google/devtools/build/lib/rules/cpp/CppOptions.java +_apple_rule_transition = transition( + implementation = _apple_rule_transition_impl, + inputs = [ + "//command_line_option:apple_compiler", + "//command_line_option:apple_crosstool_top", + "//command_line_option:apple_platform_type", + "//command_line_option:apple_grte_top", + "//command_line_option:cpu", + "//command_line_option:ios_multi_cpus", + "//command_line_option:macos_cpus", + "//command_line_option:tvos_cpus", + "//command_line_option:watchos_cpus", + ], + outputs = [ + "//command_line_option:apple configuration distinguisher", + "//command_line_option:apple_platform_type", + "//command_line_option:apple_split_cpu", + "//command_line_option:compiler", + "//command_line_option:cpu", + "//command_line_option:crosstool_top", + "//command_line_option:fission", + "//command_line_option:grte_top", + "//command_line_option:ios_minimum_os", + "//command_line_option:macos_minimum_os", + "//command_line_option:tvos_minimum_os", + "//command_line_option:watchos_minimum_os", + ], +) + +transition_support = struct( + apple_rule_transition = _apple_rule_transition, + current_apple_platform = _current_apple_platform, +) diff --git a/rules/xcodeproj.bzl b/rules/xcodeproj.bzl index 0c997a640..3bedab0ab 100644 --- a/rules/xcodeproj.bzl +++ b/rules/xcodeproj.bzl @@ -10,6 +10,7 @@ def _get_attr_values_for_name(deps, provider, field): _TargetInfo = provider() _SrcsInfo = provider() + _PLATFORM_MAPPING = { "ios": "iOS", "macos": "macOS", @@ -70,7 +71,7 @@ def _xcodeproj_aspect_impl(target, ctx): info = struct( name = bundle_info.bundle_name, - bundle_id = getattr(ctx.rule.attr, "bundle_id", None), + bundle_id = bundle_info.bundle_id, bundle_extension = bundle_info.bundle_extension, bazel_build_target_name = bazel_build_target_name, bazel_bin_subdir = bazel_bin_subdir, @@ -95,24 +96,7 @@ def _xcodeproj_aspect_impl(target, ctx): direct_targets = [info] if test_host_target: direct_targets.extend(test_host_target[_TargetInfo].direct_targets) - target_info = _TargetInfo(direct_targets = direct_targets, targets = depset([info] if info else [], transitive = _get_attr_values_for_name(deps, _TargetInfo, "targets"))) - providers.append(target_info) - elif ctx.rule.kind == "apple_framework_packaging": - info = struct( - name = target.label.name, - bundle_id = None, - bazel_build_target_name = bazel_build_target_name, - bazel_bin_subdir = bazel_bin_subdir, - srcs = depset([], transitive = _get_attr_values_for_name(deps, _SrcsInfo, "srcs")), - asset_srcs = depset([], transitive = _get_attr_values_for_name(deps, _SrcsInfo, "asset_srcs")), - build_files = depset([ctx.build_file_path], transitive = _get_attr_values_for_name(deps, _SrcsInfo, "build_files")), - product_type = "framework", - platform_type = "ios", - minimum_os_version = None, - test_env_vars = test_env_vars, - test_commandline_args = test_commandline_args, - ) - target_info = _TargetInfo(direct_targets = [info], targets = depset([info], transitive = _get_attr_values_for_name(deps, _TargetInfo, "targets"))) + target_info = _TargetInfo(direct_targets = direct_targets, targets = depset([info], transitive = _get_attr_values_for_name(deps, _TargetInfo, "targets"))) providers.append(target_info) else: srcs = [] diff --git a/tests/framework/platforms/BUILD.bazel b/tests/framework/platforms/BUILD.bazel new file mode 100644 index 000000000..0b413ea6d --- /dev/null +++ b/tests/framework/platforms/BUILD.bazel @@ -0,0 +1,33 @@ +load(":versions.bzl", "make_applications", "make_frameworks", "make_frameworks_with_dependencies") + +# [ +# apple_framework( +# name = "framework_{platform}_{version}".format(platform = platform, version = version), +# srcs = ["platform.m"], +# objc_copts = [ +# "-DTEST_PLATFORM={platform}".format(platform = platform), +# "-DTEST_PLATFORM_{platform}=1".format(platform = platform), +# "-DTEST_VERSION={version}".format(version = int(float(version) * ), +# "-DTEST_VERSION_{version}=1".format(version = version), +# ] +# ) +# for platform, versions in { +# "ios": ["10", "11", "12"], +# "macosx": ["10.11", "10.12"], +# }.items() +# for version in versions +# ] + +make_frameworks( + srcs = ["platform.m"], + resources_to_bundle = glob(["Resources/**/*"]), +) + +make_frameworks_with_dependencies( + srcs = ["platform.m"], + resources_to_bundle = glob(["Resources/**/*"]), +) + +make_applications( + srcs = ["main.m"], +) diff --git a/tests/framework/platforms/Resources/data.json b/tests/framework/platforms/Resources/data.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/tests/framework/platforms/Resources/data.json @@ -0,0 +1 @@ +{} diff --git a/tests/framework/platforms/main.m b/tests/framework/platforms/main.m new file mode 100644 index 000000000..c9eacc786 --- /dev/null +++ b/tests/framework/platforms/main.m @@ -0,0 +1,3 @@ +int main(__unused int argc, __unused char** argv) { + return 0; +} diff --git a/tests/framework/platforms/platform.m b/tests/framework/platforms/platform.m new file mode 100644 index 000000000..86c5d7a8c --- /dev/null +++ b/tests/framework/platforms/platform.m @@ -0,0 +1,68 @@ +#import "TargetConditionals.h" + +#define STR(X) #X +#define DEFER(M,...) M(__VA_ARGS__) +#define CONTENTS_OF(X) DEFER(STR,X) +#define CUSTOM_ERROR(X) _Pragma(STR(GCC error(__FILE__ ":" CONTENTS_OF(__LINE__) ": " CONTENTS_OF(BAZEL_TARGET_NAME) " " X))) +#define GLUE(X,Y) X ## Y + + +void DEFER(GLUE, printPlatform_, BAZEL_TARGET_NAME) (void) { + NSLog(@"PLATFORM %s VERSION %s", CONTENTS_OF(TEST_PLATFORM), CONTENTS_OF(TEST_VERSION)); +} + +#if TARGET_OS_OSX +# define REAL_TARGET_PLATFORM macos +# define REAL_TARGET_PLATFORM_macos 1 +#elif TARGET_OS_IOS +# define REAL_TARGET_PLATFORM ios +# define REAL_TARGET_PLATFORM_ios 1 +#elif TARGET_OS_TV +# define REAL_TARGET_PLATFORM tvos +# define REAL_TARGET_PLATFORM_tvos 1 +#elif TARGET_OS_WATCH +# define REAL_TARGET_PLATFORM watchos +# define REAL_TARGET_PLATFORM_watchos 1 +#endif + +#if REAL_TARGET_PLATFORM_macos == 1 +# if TEST_PLATFORM_macos != 1 +CUSTOM_ERROR("Unexpectedly compiling for macos, expected " CONTENTS_OF(TEST_PLATFORMS)) +# endif +# if __MAC_OS_X_VERSION_MIN_REQUIRED != TEST_VERSION_macos +CUSTOM_ERROR("Wrong version, given " CONTENTS_OF(__MAC_OS_X_VERSION_MIN_REQUIRED) " expected " CONTENTS_OF(TEST_VERSION)) +# endif +#elif TEST_PLATFORM_ios +# if TARGET_OS_IOS != 1 +CUSTOM_ERROR("Expected ios as platform, given " CONTENTS_OF(REAL_TARGET_PLATFORM)) +# endif +# if __IPHONE_OS_VERSION_MIN_REQUIRED != TEST_VERSION_ios +CUSTOM_ERROR("Wrong version, given " CONTENTS_OF(__IPHONE_OS_VERSION_MIN_REQUIRED) " expected " CONTENTS_OF(TEST_VERSION)) +# endif +#elif TEST_PLATFORM_watchos +# if TARGET_OS_WATCH != 1 +CUSTOM_ERROR("Expected watchos as platform, given " CONTENTS_OF(REAL_TARGET_PLATFORM)) +# endif +# if __WATCH_OS_VERSION_MIN_REQUIRED != TEST_VERSION_watchos +CUSTOM_ERROR("Wrong version, given " CONTENTS_OF(__WATCH_OS_VERSION_MIN_REQUIRED) " expected " CONTENTS_OF(TEST_VERSION)) +# endif +#elif TEST_PLATFORM_tvos +# if TARGET_OS_TV != 1 +CUSTOM_ERROR("Expected tvos as platform, given " CONTENTS_OF(REAL_TARGET_PLATFORM) " ") +# endif +# if __TV_OS_VERSION_MIN_REQUIRED != TEST_VERSION_tvos +CUSTOM_ERROR("Wrong version, given " CONTENTS_OF(__TV_OS_VERSION_MIN_REQUIRED) " expected " CONTENTS_OF(TEST_VERSION)) +# endif +#else +CUSTOM_ERROR("Unknown target platform " CONTENTS_OF(TEST_PLATFORM) " real platform " CONTENTS_OF(REAL_TARGET_PLATFORM)) +#endif + +#if REAL_TARGET_PLATFORM_ios +# import + +@interface DEFER(GLUE, FooView, BAZEL_TARGET_NAME) : UIView +@end +@implementation DEFER(GLUE, FooView, BAZEL_TARGET_NAME) +@end + +#endif diff --git a/tests/framework/platforms/versions.bzl b/tests/framework/platforms/versions.bzl new file mode 100644 index 000000000..6af1374c0 --- /dev/null +++ b/tests/framework/platforms/versions.bzl @@ -0,0 +1,90 @@ +load("//rules:framework.bzl", "apple_framework") +load("//rules:app.bzl", "ios_application") + +_VERSIONS = { + "macos": ["10.10", "10.11"], + "ios": ["10.0", "10.2", "12.0"], + "tvos": ["10.0", "10.2", "12.0"], + "watchos": ["3.2"], +} + +def _version_int(version): + parts = [int(x) for x in version.split(".")] + if len(parts) not in (2, 3): + fail("must have two/three parts") + + major = parts[0] + minor = parts[1] + patch = 0 if len(parts) == 2 else parts[2] + + return patch + minor * 100 + major * 10000 + +_MULTIPLATFORM = { + k: v[0] + for (k, v) in _VERSIONS.items() +} +_MULTIPLATFORM_SUFFIX = "".join(["_{}_{}".format(platform, _version_int(version)) for (platform, version) in _MULTIPLATFORM.items()]) + +def _make_framework(prefix, srcs, deps, platforms, resources_to_bundle): + name = prefix + defines = {} + for (platform, version) in platforms.items(): + version_int = _version_int(version) + defines["TEST_PLATFORM_%s" % platform] = "1" + defines["TEST_VERSION_%s" % platform] = "1" + defines["TEST_VERSION_%s" % platform] = version_int + defines["TEST_VERSION_%s_%s" % (platform, version_int)] = "1" + name += "_{}_{}".format(platform, version_int) + defines["BAZEL_TARGET_NAME"] = name + + apple_framework( + name = name, + srcs = srcs, + objc_copts = [ + "-D{}={}".format(k, v) + for (k, v) in defines.items() + ], + platforms = platforms, + deps = deps, + resource_bundles = {"{}_resources".format(name): resources_to_bundle}, + ) + +def make_frameworks(srcs, prefix = "framework", deps = [], resources_to_bundle = []): + for platform, versions in _VERSIONS.items(): + for version in versions: + _make_framework( + prefix = prefix, + srcs = srcs, + deps = deps, + resources_to_bundle = resources_to_bundle, + platforms = {platform: version}, + ) + + _make_framework( + prefix = prefix, + srcs = srcs, + deps = deps, + resources_to_bundle = resources_to_bundle, + platforms = _MULTIPLATFORM, + ) + +def make_frameworks_with_dependencies(srcs, resources_to_bundle): + make_frameworks(prefix = "framework_deps", srcs = srcs, resources_to_bundle = resources_to_bundle, deps = [":framework" + _MULTIPLATFORM_SUFFIX]) + +def make_applications(srcs): + existing_rules = native.existing_rules() + + for (platform, versions) in _VERSIONS.items(): + if platform != "ios": + continue + + for version in versions: + version_int = _version_int(version) + ios_application( + name = "ios_application_{}".format(version_int), + srcs = srcs, + minimum_os_version = version, + deps = [d for (d, t) in existing_rules.items() if "_ios_" in d and t["kind"] == "apple_framework_packaging"], + entitlements = None, + bundle_id = "com.example.iosapplication", + ) diff --git a/tests/ios/unit-test/test-imports-app/BUILD.bazel b/tests/ios/unit-test/test-imports-app/BUILD.bazel index a37771302..dc9802f07 100644 --- a/tests/ios/unit-test/test-imports-app/BUILD.bazel +++ b/tests/ios/unit-test/test-imports-app/BUILD.bazel @@ -30,6 +30,9 @@ ios_application( apple_framework_packaging( name = "TestImports-App_framework_unlinked", framework_name = "TestImports-App", + platforms = { + "ios": "12.0", + }, skip_packaging = ["binary"], transitive_deps = [], deps = [ From f6621f11f920f4617dd1c04f463da774a393a818 Mon Sep 17 00:00:00 2001 From: Samuel Giddins Date: Mon, 8 Jun 2020 19:22:46 -0700 Subject: [PATCH 2/6] Allow incremental regeneration of rcode projects --- .github/workflows/tests.yml | 8 ++--- rules/xcodeproj.bzl | 17 ++++++----- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ----- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ----- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ----- tools/xcodeproj_shims/xcodeproj-installer.sh | 30 ++++++++----------- 6 files changed, 24 insertions(+), 55 deletions(-) delete mode 100644 tests/macos/xcodeproj/Single-Application-Project-AllTargets.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 tests/macos/xcodeproj/Single-Application-Project-DirectTargetsOnly.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 tests/macos/xcodeproj/Test-Target-With-Test-Host-Project.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 148570caa..82bbbca9e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -44,12 +44,8 @@ jobs: - uses: actions/checkout@v1 - name: Select Xcode 11.2 run: sudo xcode-select -s /Applications/Xcode_11.2.app - - name: Generate Xcode projects that load all transitive targets and compare against existing record - run: bazelisk run tests/macos/xcodeproj:Single-Application-Project-AllTargets && git diff --exit-code tests/macos/xcodeproj - - name: Generate Xcode projects that load direct targets only and compare against existing record - run: bazelisk run tests/macos/xcodeproj:Single-Application-Project-DirectTargetsOnly && git diff --exit-code tests/macos/xcodeproj - - name: Generate Xcode projects that have a test target with a host app and compare against existing record - run: bazelisk run tests/macos/xcodeproj:Test-Target-With-Test-Host-Project && git diff --exit-code tests/macos/xcodeproj + - name: Generate Xcode projects and compare against existing record + run: (bazelisk query 'kind(xcodeproj, tests/macos/xcodeproj/...)' | xargs -n 1 bazelisk run) && git diff --exit-code tests/macos/xcodeproj - name: Run Xcode builds run: ./tests/macos/xcodeproj/build.sh - name: Run Unit tests diff --git a/rules/xcodeproj.bzl b/rules/xcodeproj.bzl index 3bedab0ab..e1560b2fd 100644 --- a/rules/xcodeproj.bzl +++ b/rules/xcodeproj.bzl @@ -85,14 +85,15 @@ def _xcodeproj_aspect_impl(target, ctx): test_commandline_args = test_commandline_args, test_host_appname = test_host_appname, ) - providers.append( - _SrcsInfo( - srcs = info.srcs, - asset_srcs = info.asset_srcs, - build_files = depset([ctx.build_file_path]), - direct_srcs = [], - ), - ) + if ctx.rule.kind != "apple_framework_packaging": + providers.append( + _SrcsInfo( + srcs = info.srcs, + asset_srcs = info.asset_srcs, + build_files = depset([ctx.build_file_path]), + direct_srcs = [], + ), + ) direct_targets = [info] if test_host_target: direct_targets.extend(test_host_target[_TargetInfo].direct_targets) diff --git a/tests/macos/xcodeproj/Single-Application-Project-AllTargets.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/tests/macos/xcodeproj/Single-Application-Project-AllTargets.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/tests/macos/xcodeproj/Single-Application-Project-AllTargets.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/tests/macos/xcodeproj/Single-Application-Project-DirectTargetsOnly.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/tests/macos/xcodeproj/Single-Application-Project-DirectTargetsOnly.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/tests/macos/xcodeproj/Single-Application-Project-DirectTargetsOnly.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/tests/macos/xcodeproj/Test-Target-With-Test-Host-Project.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/tests/macos/xcodeproj/Test-Target-With-Test-Host-Project.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/tests/macos/xcodeproj/Test-Target-With-Test-Host-Project.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/tools/xcodeproj_shims/xcodeproj-installer.sh b/tools/xcodeproj_shims/xcodeproj-installer.sh index ab2e1d267..60f2c97a3 100755 --- a/tools/xcodeproj_shims/xcodeproj-installer.sh +++ b/tools/xcodeproj_shims/xcodeproj-installer.sh @@ -6,10 +6,21 @@ readonly project_path="${PWD}/$(project_short_path)" readonly dest="${BUILD_WORKSPACE_DIRECTORY}/$(project_short_path)/" readonly tmp_dest=$(mktemp -d)/$(project_full_path)/ -readonly stubs_dir="${dest}/bazelstubs" +readonly installer="$(installer_short_path)" + +rm -fr "${tmp_dest}" +mkdir -p "$(dirname $tmp_dest)" +cp -r "${project_path}" "$tmp_dest" +chmod -R +w "${tmp_dest}" + +readonly stubs_dir="${tmp_dest}/bazelstubs" mkdir -p "${stubs_dir}" -readonly installer="$(installer_short_path)" +# The new build system leaves a subdirectory called XCBuildData in the DerivedData directory which causes incremental build and test attempts to fail at launch time. +# The error message says "Cannot attach to pid." This error seems to happen in the Xcode IDE, not when the project is tested from the xcodebuild command. +# Therefore, we force xcode to use the legacy build system by adding the contents of WorkspaceSettings.xcsettings to the generated project. +mkdir -p "$tmp_dest/project.xcworkspace/xcshareddata/" +cp "$(workspacesettings_xcsettings_short_path)" "$tmp_dest/project.xcworkspace/xcshareddata/" installer_dir=$(dirname "${stubs_dir}/${installer}") mkdir -p "${installer_dir}" @@ -22,24 +33,9 @@ cp "$(infoplist_stub)" "${stubs_dir}/Info-stub.plist" cp "$(build_wrapper_path)" "${stubs_dir}/build-wrapper" cp "$(output_processor_path)" "${stubs_dir}/output-processor.rb" -rm -fr "${tmp_dest}" -mkdir -p "$(dirname $tmp_dest)" -cp -r "${project_path}" "$tmp_dest" chmod -R +w "${tmp_dest}" # always trim three ../ from path, since that's "bazel-out/darwin-fastbuild/bin" sed -i.bak -E -e 's|([ "])../../../|\1|g' "${tmp_dest}/project.pbxproj" rm "${tmp_dest}/project.pbxproj.bak" rsync --recursive --quiet --copy-links "${tmp_dest}" "${dest}" - - -# The new build system leaves a subdirectory called XCBuildData in the DerivedData directory which causes incremental build and test attempts to fail at launch time. -# The error message says "Cannot attach to pid." This error seems to happen in the Xcode IDE, not when the project is tested from the xcodebuild command. -# Therefore, we force xcode to use the legacy build system by adding the contents of WorkspaceSettings.xcsettings to the generated project. -mkdir -p "$dest/project.xcworkspace/xcshareddata/" -cp "$(workspacesettings_xcsettings_short_path)" "$dest/project.xcworkspace/xcshareddata/" - - - -# - From cf87e73379cbbab4a860d76e43e84ffbaa0aa477 Mon Sep 17 00:00:00 2001 From: Samuel Giddins Date: Tue, 9 Jun 2020 12:55:38 -0700 Subject: [PATCH 3/6] Pass platforms through for apps/tests --- rules/app.bzl | 2 +- rules/library.bzl | 4 +--- rules/test.bzl | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/rules/app.bzl b/rules/app.bzl index 5b49d4d02..7da46f530 100644 --- a/rules/app.bzl +++ b/rules/app.bzl @@ -55,7 +55,7 @@ def ios_application(name, apple_library = apple_library, **kwargs): """ infoplists = write_info_plists_if_needed(name = name, plists = kwargs.pop("infoplists", [])) application_kwargs = {arg: kwargs.pop(arg) for arg in _IOS_APPLICATION_KWARGS if arg in kwargs} - library = apple_library(name = name, namespace_is_module_name = False, **kwargs) + library = apple_library(name = name, namespace_is_module_name = False, platforms = {"ios": application_kwargs.get('minimum_os_version')}, **kwargs) application_kwargs["launch_storyboard"] = application_kwargs.pop("launch_storyboard", library.launch_screen_storyboard_name) application_kwargs["families"] = application_kwargs.pop("families", ["iphone", "ipad"]) diff --git a/rules/library.bzl b/rules/library.bzl index 282214992..216c9c65a 100644 --- a/rules/library.bzl +++ b/rules/library.bzl @@ -311,10 +311,8 @@ def apple_library(name, library_tools = {}, export_private_headers = True, names deps = [d for d in kwargs.pop("deps", [])] data = kwargs.pop("data", []) tags = kwargs.pop("tags", []) - platforms = kwargs.pop("platforms", { - "ios": "10.0", # TODO: remove default - }) tags_manual = tags if "manual" in tags else tags + _MANUAL + platforms = kwargs.pop("platforms", None) internal_deps = [] lib_names = [] diff --git a/rules/test.bzl b/rules/test.bzl index 1bf9be4ec..9ffbc742e 100644 --- a/rules/test.bzl +++ b/rules/test.bzl @@ -41,7 +41,7 @@ def ios_unit_test(name, apple_library = apple_library, **kwargs): else: unit_test_kwargs["runner"] = runner - library = apple_library(name = name, namespace_is_module_name = False, **kwargs) + library = apple_library(name = name, namespace_is_module_name = False, platforms = {"ios": unit_test_kwargs.get('minimum_os_version')}, **kwargs) rule( name = name, From 8d8257011c31e28e40489f2e19665635e835ba83 Mon Sep 17 00:00:00 2001 From: Samuel Giddins Date: Tue, 9 Jun 2020 16:25:54 -0700 Subject: [PATCH 4/6] Add docs for new attrs --- rules/app.bzl | 2 +- rules/framework.bzl | 21 ++++-- rules/precompiled_apple_resource_bundle.bzl | 68 +++++++++++++------ rules/test.bzl | 2 +- tests/framework/platforms/BUILD.bazel | 18 ----- .../unit-test/test-imports-app/BUILD.bazel | 3 + 6 files changed, 70 insertions(+), 44 deletions(-) diff --git a/rules/app.bzl b/rules/app.bzl index 7da46f530..23fddfd2a 100644 --- a/rules/app.bzl +++ b/rules/app.bzl @@ -55,7 +55,7 @@ def ios_application(name, apple_library = apple_library, **kwargs): """ infoplists = write_info_plists_if_needed(name = name, plists = kwargs.pop("infoplists", [])) application_kwargs = {arg: kwargs.pop(arg) for arg in _IOS_APPLICATION_KWARGS if arg in kwargs} - library = apple_library(name = name, namespace_is_module_name = False, platforms = {"ios": application_kwargs.get('minimum_os_version')}, **kwargs) + library = apple_library(name = name, namespace_is_module_name = False, platforms = {"ios": application_kwargs.get("minimum_os_version")}, **kwargs) application_kwargs["launch_storyboard"] = application_kwargs.pop("launch_storyboard", library.launch_screen_storyboard_name) application_kwargs["families"] = application_kwargs.pop("families", ["iphone", "ipad"]) diff --git a/rules/framework.bzl b/rules/framework.bzl index abb053d74..03a34a99e 100644 --- a/rules/framework.bzl +++ b/rules/framework.bzl @@ -78,9 +78,10 @@ def _concat(*args): def _apple_framework_packaging_impl(ctx): framework_name = ctx.attr.framework_name + bundle_extension = ctx.attr.bundle_extension # declare framework directory - framework_dir = "%s/%s.framework" % (ctx.attr.name, framework_name) + framework_dir = "%s/%s.%s" % (ctx.attr.name, framework_name, bundle_extension) # binaries binary_in = [] @@ -305,7 +306,7 @@ def _apple_framework_packaging_impl(ctx): binary = binary_out, bundle_id = bundle_id, bundle_name = framework_name, - bundle_extension = ctx.attr.bundle_extension, + bundle_extension = bundle_extension, entitlements = None, infoplist = infoplist, minimum_os_version = str(current_apple_platform.target_os_version), @@ -367,11 +368,21 @@ Valid values are: "//rules/hmap:hmaptool", ), ), - "bundle_id": attr.string(mandatory = False), - "bundle_extension": attr.string(mandatory = False, default = "framework"), + "bundle_id": attr.string( + mandatory = False, + doc = "The bundle identifier of the framework. Currently unused.", + ), + "bundle_extension": attr.string( + mandatory = False, + default = "framework", + doc = "The extension of the bundle, defaults to \"framework\".", + ), "platforms": attr.string_dict( mandatory = False, default = {}, + doc = """A dictionary of platform names to minimum deployment targets. +If not given, the framework will be built for the platform it inherits from the target that uses +the framework as a dependency.""", ), "_product_type": attr.string(default = apple_product_type.static_framework), # TODO: allow customizing binary type between dynamic/static @@ -383,9 +394,11 @@ Valid values are: name = "xcode_config_label", fragment = "apple", ), + doc = "The xcode config that is used to determine the deployment target for the current platform.", ), "_whitelist_function_transition": attr.label( default = "@build_bazel_rules_apple//tools/whitelists/function_transition_whitelist", + doc = "Needed to allow this rule to have an incoming edge configuration transition.", ), }, doc = "Packages compiled code into an Apple .framework package", diff --git a/rules/precompiled_apple_resource_bundle.bzl b/rules/precompiled_apple_resource_bundle.bzl index 5a68995e9..8fc8ee682 100644 --- a/rules/precompiled_apple_resource_bundle.bzl +++ b/rules/precompiled_apple_resource_bundle.bzl @@ -34,21 +34,28 @@ def _precompiled_apple_resource_bundle_impl(ctx): current_apple_platform = transition_support.current_apple_platform(apple_fragment = ctx.fragments.apple, xcode_config = ctx.attr._xcode_config) attr_dict["platform_type"] = str(current_apple_platform.platform.platform_type) attr_dict["minimum_os_version"] = str(current_apple_platform.target_os_version) - - # TODO: only do this dance if platform is not macos attr_dict["_product_type"] = _FAKE_BUNDLE_PRODUCT_TYPE_BY_PLATFORM_TYPE.get(attr_dict["platform_type"], ctx.attr._product_type) - ios_app_ctx_dict = {} + + file_dict = {} + for k in dir(ctx.file): + if k in ("to_json", "to_proto"): + continue + file_dict[k] = getattr(ctx.file, k) + + file_dict["_environment_plist"] = [f for f in ctx.files._environment_plists if f.path.endswith("_{}.plist".format(attr_dict["platform_type"]))][0] + + fake_ctx_dict = {} for k in dir(ctx): if k in ("aspect_ids", "build_setting_value", "rule", "to_json", "to_proto"): continue - ios_app_ctx_dict[k] = getattr(ctx, k) - ios_app_ctx_dict["attr"] = struct(**attr_dict) - ios_app_ctx = struct(**ios_app_ctx_dict) + fake_ctx_dict[k] = getattr(ctx, k) + fake_ctx_dict["attr"] = struct(**attr_dict) + fake_ctx_dict["file"] = struct(**file_dict) + fake_ctx = struct(**fake_ctx_dict) partial_output = partial.call(partials.resources_partial( top_level_attrs = ["resources"], - # plist_attrs = ["infoplist"] - ), ios_app_ctx) + ), fake_ctx) # Process the plist ourselves. This is required because # include_executable_name defaults to True, which results in iTC rejecting @@ -58,7 +65,7 @@ def _precompiled_apple_resource_bundle_impl(ctx): ) bundle_id = ctx.attr.bundle_id or "com.cocoapods." + bundle_name resource_actions.merge_root_infoplists( - ios_app_ctx, + fake_ctx, ctx.files.infoplists, output_plist, None, @@ -172,15 +179,30 @@ precompiled_apple_resource_bundle = rule( Label("@build_bazel_rules_ios//rules/library:resource_bundle.plist"), ], ), - bundle_name = attr.string(mandatory = False), - bundle_id = attr.string(mandatory = False), + bundle_name = attr.string( + mandatory = False, + doc = "The name of the resource bundle. Defaults to the target name.", + ), + bundle_id = attr.string( + mandatory = False, + doc = "The bundle identifier of the resource bundle.", + ), resources = attr.label_list( allow_empty = True, allow_files = True, + doc = "The list of resources to be included in the resource bundle.", + ), + bundle_extension = attr.string( + mandatory = False, + default = "bundle", + doc = "The extension of the resource bundle.", ), - bundle_extension = attr.string(mandatory = False, default = "bundle"), platforms = attr.string_dict( - mandatory = True, + mandatory = False, + default = {}, + doc = """A dictionary of platform names to minimum deployment targets. +If not given, the resource bundle will be built for the platform it inherits from the target that uses +the bundle as a dependency.""", ), _product_type = attr.string(default = apple_product_type.bundle), # This badly named property is required even though this isn't an ipa @@ -189,19 +211,25 @@ precompiled_apple_resource_bundle = rule( executable = True, cfg = "exec", ), - _environment_plist = attr.label( - allow_single_file = True, - # TODO: handle other platforms - default = Label("@build_bazel_rules_apple//apple/internal:environment_plist_ios"), - ), - _whitelist_function_transition = attr.label( - default = Label("@bazel_tools//tools/whitelists/function_transition_whitelist"), + _environment_plists = attr.label_list( + allow_files = True, + default = [ + Label("@build_bazel_rules_apple//apple/internal:environment_plist_ios"), + Label("@build_bazel_rules_apple//apple/internal:environment_plist_macos"), + Label("@build_bazel_rules_apple//apple/internal:environment_plist_tvos"), + Label("@build_bazel_rules_apple//apple/internal:environment_plist_watchos"), + ], ), _xcode_config = attr.label( default = configuration_field( name = "xcode_config_label", fragment = "apple", ), + doc = "The xcode config that is used to determine the deployment target for the current platform.", + ), + _whitelist_function_transition = attr.label( + default = "@build_bazel_rules_apple//tools/whitelists/function_transition_whitelist", + doc = "Needed to allow this rule to have an incoming edge configuration transition.", ), ), ) diff --git a/rules/test.bzl b/rules/test.bzl index 9ffbc742e..a28f6b8be 100644 --- a/rules/test.bzl +++ b/rules/test.bzl @@ -41,7 +41,7 @@ def ios_unit_test(name, apple_library = apple_library, **kwargs): else: unit_test_kwargs["runner"] = runner - library = apple_library(name = name, namespace_is_module_name = False, platforms = {"ios": unit_test_kwargs.get('minimum_os_version')}, **kwargs) + library = apple_library(name = name, namespace_is_module_name = False, platforms = {"ios": unit_test_kwargs.get("minimum_os_version")}, **kwargs) rule( name = name, diff --git a/tests/framework/platforms/BUILD.bazel b/tests/framework/platforms/BUILD.bazel index 0b413ea6d..bcb9ac8ba 100644 --- a/tests/framework/platforms/BUILD.bazel +++ b/tests/framework/platforms/BUILD.bazel @@ -1,23 +1,5 @@ load(":versions.bzl", "make_applications", "make_frameworks", "make_frameworks_with_dependencies") -# [ -# apple_framework( -# name = "framework_{platform}_{version}".format(platform = platform, version = version), -# srcs = ["platform.m"], -# objc_copts = [ -# "-DTEST_PLATFORM={platform}".format(platform = platform), -# "-DTEST_PLATFORM_{platform}=1".format(platform = platform), -# "-DTEST_VERSION={version}".format(version = int(float(version) * ), -# "-DTEST_VERSION_{version}=1".format(version = version), -# ] -# ) -# for platform, versions in { -# "ios": ["10", "11", "12"], -# "macosx": ["10.11", "10.12"], -# }.items() -# for version in versions -# ] - make_frameworks( srcs = ["platform.m"], resources_to_bundle = glob(["Resources/**/*"]), diff --git a/tests/ios/unit-test/test-imports-app/BUILD.bazel b/tests/ios/unit-test/test-imports-app/BUILD.bazel index dc9802f07..67101f931 100644 --- a/tests/ios/unit-test/test-imports-app/BUILD.bazel +++ b/tests/ios/unit-test/test-imports-app/BUILD.bazel @@ -5,6 +5,9 @@ load("//rules:test.bzl", "ios_unit_test") apple_framework( name = "SomeFramework", srcs = glob(["SomeFramework/*.swift"]), + platforms = { + "ios": "12.0", + }, visibility = ["//visibility:public"], ) From 6964ecad81d19064ce3f1bc3028f0d4cd4104d81 Mon Sep 17 00:00:00 2001 From: Samuel Giddins Date: Tue, 9 Jun 2020 16:40:42 -0700 Subject: [PATCH 5/6] Generate docs for new bzl files --- docs/BUILD.bazel | 4 ++- docs/framework_doc.md | 6 +++- docs/precompiled_apple_resource_bundle_doc.md | 28 +++++++++++++++++++ docs/transition_support_doc.md | 21 ++++++++++++++ 4 files changed, 57 insertions(+), 2 deletions(-) create mode 100755 docs/precompiled_apple_resource_bundle_doc.md create mode 100755 docs/transition_support_doc.md diff --git a/docs/BUILD.bazel b/docs/BUILD.bazel index f0a0a2585..e54c4deed 100644 --- a/docs/BUILD.bazel +++ b/docs/BUILD.bazel @@ -5,12 +5,14 @@ package(default_visibility = ["//visibility:private"]) _RULES = [ "app", + "apple_patched", "framework", "hmap", "library", + "precompiled_apple_resource_bundle", "substitute_build_settings", "test", - "apple_patched", + "transition_support", ] _REPOSITORY_RULES = [ diff --git a/docs/framework_doc.md b/docs/framework_doc.md index 70ebd810a..e2745f28c 100755 --- a/docs/framework_doc.md +++ b/docs/framework_doc.md @@ -5,7 +5,8 @@ ## apple_framework_packaging
-apple_framework_packaging(name, deps, framework_name, skip_packaging, transitive_deps)
+apple_framework_packaging(name, bundle_extension, bundle_id, deps, framework_name, platforms,
+                          skip_packaging, transitive_deps)
 
Packages compiled code into an Apple .framework package @@ -16,8 +17,11 @@ Packages compiled code into an Apple .framework package | Name | Description | Type | Mandatory | Default | | :-------------: | :-------------: | :-------------: | :-------------: | :-------------: | | name | A unique name for this target. | Name | required | | +| bundle_extension | The extension of the bundle, defaults to "framework". | String | optional | "framework" | +| bundle_id | The bundle identifier of the framework. Currently unused. | String | optional | "" | | deps | Objc or Swift rules to be packed by the framework rule | List of labels | required | | | framework_name | Name of the framework, usually the same as the module name | String | required | | +| platforms | A dictionary of platform names to minimum deployment targets. If not given, the framework will be built for the platform it inherits from the target that uses the framework as a dependency. | Dictionary: String -> String | optional | {} | | skip_packaging | Parts of the framework packaging process to be skipped. Valid values are: - "binary" - "modulemap" - "header" - "private_header" - "swiftmodule" - "swiftdoc" | List of strings | optional | [] | | transitive_deps | Deps of the deps | List of labels | required | | diff --git a/docs/precompiled_apple_resource_bundle_doc.md b/docs/precompiled_apple_resource_bundle_doc.md new file mode 100755 index 000000000..1c0b0fc7e --- /dev/null +++ b/docs/precompiled_apple_resource_bundle_doc.md @@ -0,0 +1,28 @@ + + + + +## precompiled_apple_resource_bundle + +
+precompiled_apple_resource_bundle(name, bundle_extension, bundle_id, bundle_name, infoplists,
+                                  ipa_post_processor, platforms, resources)
+
+ + + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :-------------: | :-------------: | :-------------: | :-------------: | :-------------: | +| name | A unique name for this target. | Name | required | | +| bundle_extension | The extension of the resource bundle. | String | optional | "bundle" | +| bundle_id | The bundle identifier of the resource bundle. | String | optional | "" | +| bundle_name | The name of the resource bundle. Defaults to the target name. | String | optional | "" | +| infoplists | - | List of labels | optional | [Label("@build_bazel_rules_ios//rules/library:resource_bundle.plist")] | +| ipa_post_processor | - | Label | optional | None | +| platforms | A dictionary of platform names to minimum deployment targets. If not given, the resource bundle will be built for the platform it inherits from the target that uses the bundle as a dependency. | Dictionary: String -> String | optional | {} | +| resources | The list of resources to be included in the resource bundle. | List of labels | optional | [] | + + diff --git a/docs/transition_support_doc.md b/docs/transition_support_doc.md new file mode 100755 index 000000000..2680eacc1 --- /dev/null +++ b/docs/transition_support_doc.md @@ -0,0 +1,21 @@ + + + + +## transition_support.current_apple_platform + +
+transition_support.current_apple_platform(apple_fragment, xcode_config)
+
+ +Returns a struct containing the platform and target os version + +**PARAMETERS** + + +| Name | Description | Default Value | +| :-------------: | :-------------: | :-------------: | +| apple_fragment |

-

| none | +| xcode_config |

-

| none | + + From e0255759ee5939796ed3dfc6cda4ea120cc95951 Mon Sep 17 00:00:00 2001 From: Oscar Bonilla <6f6231@gmail.com> Date: Thu, 11 Jun 2020 14:21:55 -0700 Subject: [PATCH 6/6] Fix a coupld of CI failures --- rules/hmap.bzl | 2 +- rules/repositories.bzl | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/rules/hmap.bzl b/rules/hmap.bzl index b997f0c87..be5e2ba91 100644 --- a/rules/hmap.bzl +++ b/rules/hmap.bzl @@ -45,7 +45,7 @@ def _make_headermap_impl(ctx): tool included here to create the actual .hmap file. :param ctx: context for this rule. See - https://docs.bazel.build/versions/master/skylark/lib/ctx.html + https://docs.bazel.build/versions/master/starlark/lib/ctx.html :return: provider with the info for this rule """ diff --git a/rules/repositories.bzl b/rules/repositories.bzl index fa6d072c9..42b68f84d 100644 --- a/rules/repositories.bzl +++ b/rules/repositories.bzl @@ -29,7 +29,8 @@ def rules_ios_dependencies(): git_repository, name = "build_bazel_rules_apple", commit = "74eca5857a136b9f1e2020886be76b791eb08231", - shallow_since = "1590530217 -0700", + # TODO: Investigate why enabling this causes an analysis failure + # shallow_since = "1590530217 -0700", remote = "https://github.com/bazelbuild/rules_apple.git", )