diff --git a/docs/bazel.md b/docs/bazel.md index 7c62a1bcb..ee5ae0873 100755 --- a/docs/bazel.md +++ b/docs/bazel.md @@ -933,8 +933,9 @@ rules, then you will use these providers to communicate between them. XcodeProjAutomaticTargetProcessingInfo(alternate_icons, app_icons, args, bundle_id, codesign_inputs, codesignopts, collect_uncategorized_files, deps, entitlements, env, exported_symbols_lists, extra_files, hdrs, - implementation_deps, infoplists, is_supported, is_top_level, - label, launchdplists, link_mnemonics, non_arc_srcs, pch, + implementation_deps, infoplists, is_header_only_library, + is_mixed_language, is_supported, is_top_level, label, + launchdplists, link_mnemonics, non_arc_srcs, pch, provisioning_profile, should_generate, srcs, target_type, xcode_targets) @@ -970,6 +971,8 @@ return an `XcodeProjInfo` provider instance instead. | hdrs | A sequence of attribute names to collect `File`s from for `hdrs`-like attributes.

This is only used when `xcodeproj.generation_mode = "legacy"` is set. | | implementation_deps | A sequence of attribute names to collect `Target`s from for `implementation_deps`-like attributes. | | infoplists | A sequence of attribute names to collect `File`s from for the `infoplists`-like attributes.

This is only used when `xcodeproj.generation_mode = "legacy"` is set. | +| is_header_only_library | Whether this target doesn't contain src files.

This is only used when `xcodeproj.generation_mode = "incremental"` is set. | +| is_mixed_language | Whether this target is a mixed-language target.

This is only used when `xcodeproj.generation_mode = "incremental"` is set. | | is_supported | Whether an Xcode target can be generated for this target. Even if this value is `False`, setting values for the other attributes can cause inputs to be collected and shown in the Xcode project. | | is_top_level | Whether this target is a "top-level" (e.g. bundled or executable) target. | | label | The effective `Label` to use for the target. This should generally be `target.label`, but in the case of skipped wrapper rules (e.g. `*_unit_test` targets), you might want to rename the target to the skipped target's label.

This is only used when `xcodeproj.generation_mode = "incremental"` is set. | @@ -1020,7 +1023,7 @@ Provides information needed to generate an Xcode project. | framework_product_mappings | A `depset` of `(linker_path, product_path)` `tuple`s. `linker_path` is the `.framework/Executable` path used when linking to a framework. `product_path` is the path to a built `.framework` product. In particular, `product_path` can have a fully fleshed out framework, including resources, while `linker_path` will most likely only have a symlink to a `.dylib` in it.

This is only set and used when `xcodeproj.generation_mode = "incremental"` is set. | | hosted_targets | A `depset` of `struct`s with `host` and `hosted` fields. The `host` field is the target ID (see `xcode_target.id`) of the hosting target. The `hosted` field is the target ID of the hosted target. | | inputs | A value from `input_files.collect`/`inputs_files.merge`, that contains information related to all of the input `File`s for the project collected so far. It also includes information related to "extra files" that should be added to the Xcode project, but are not associated with any targets. | -| label | The `Label` of the target.

This is only set and used when `xcodeproj.generation_mode = "legacy"` is set. | +| label | The `Label` of the target. | | labels | A `depset` of `Labels` for the target and its transitive dependencies.

This is only set and used when `xcodeproj.generation_mode = "legacy"` is set. | | lldb_context | A value from `lldb_context.collect`. | | mergable_xcode_library_targets | A `depset` of target IDs (see `xcode_target.id`). Each represents a target that can potentially merge into a top-level target (to be decided by the top-level target).

This is only set and used when `xcodeproj.generation_mode = "legacy"` is set. | diff --git a/test/internal/pbxproj_partials/write_target_build_settings_tests.bzl b/test/internal/pbxproj_partials/write_target_build_settings_tests.bzl index d9a55c105..304ac361e 100644 --- a/test/internal/pbxproj_partials/write_target_build_settings_tests.bzl +++ b/test/internal/pbxproj_partials/write_target_build_settings_tests.bzl @@ -82,11 +82,11 @@ def _write_target_build_settings_test_impl(ctx): entitlements = ctx.attr.entitlements, extension_safe = ctx.attr.extension_safe, generate_build_settings = ctx.attr.generate_build_settings, + generate_swift_debug_settings = ctx.attr.generate_swift_debug_settings, include_self_swift_debug_settings = ( ctx.attr.include_self_swift_debug_settings ), infoplist = ctx.attr.infoplist, - is_top_level_target = ctx.attr.is_top_level_target, name = "a_target_name", previews_dynamic_frameworks = [ (mock_actions.mock_file(f), True) @@ -176,9 +176,9 @@ write_target_build_settings_test = unittest.make( "entitlements": attr.string(), "extension_safe": attr.bool(mandatory = True), "generate_build_settings": attr.bool(mandatory = True), + "generate_swift_debug_settings": attr.bool(mandatory = True), "include_self_swift_debug_settings": attr.bool(mandatory = True), "infoplist": attr.string(), - "is_top_level_target": attr.bool(mandatory = True), "previews_dynamic_frameworks": attr.string_list(mandatory = True), "previews_include_path": attr.string(mandatory = True), "provisioning_profile_is_xcode_managed": attr.bool(mandatory = True), @@ -219,9 +219,9 @@ def write_target_build_settings_test_suite(name): entitlements = None, extension_safe = False, generate_build_settings, + generate_swift_debug_settings, include_self_swift_debug_settings = True, infoplist = None, - is_top_level_target = False, previews_dynamic_frameworks = [], previews_include_path = "", provisioning_profile_is_xcode_managed = False, @@ -250,9 +250,9 @@ def write_target_build_settings_test_suite(name): entitlements = entitlements, extension_safe = extension_safe, generate_build_settings = generate_build_settings, + generate_swift_debug_settings = generate_swift_debug_settings, include_self_swift_debug_settings = include_self_swift_debug_settings, infoplist = infoplist, - is_top_level_target = is_top_level_target, previews_dynamic_frameworks = previews_dynamic_frameworks, previews_include_path = previews_include_path, provisioning_profile_is_xcode_managed = provisioning_profile_is_xcode_managed, @@ -278,6 +278,7 @@ def write_target_build_settings_test_suite(name): conly_args = [], cxx_args = [], generate_build_settings = False, + generate_swift_debug_settings = False, swift_args = [], # Expected @@ -297,6 +298,7 @@ def write_target_build_settings_test_suite(name): conly_args = [], cxx_args = [], generate_build_settings = True, + generate_swift_debug_settings = False, swift_args = [], # Expected @@ -344,6 +346,7 @@ def write_target_build_settings_test_suite(name): conly_args = ["a", "c", "b"], cxx_args = [], generate_build_settings = True, + generate_swift_debug_settings = False, swift_args = [], # Expected @@ -389,6 +392,7 @@ def write_target_build_settings_test_suite(name): conly_args = [], cxx_args = ["a", "c", "b"], generate_build_settings = True, + generate_swift_debug_settings = False, swift_args = [], # Expected @@ -434,6 +438,7 @@ def write_target_build_settings_test_suite(name): conly_args = ["a1", "c2", "b1"], cxx_args = ["a2", "c1", "b2"], generate_build_settings = True, + generate_swift_debug_settings = False, swift_args = [], # Expected @@ -481,6 +486,7 @@ def write_target_build_settings_test_suite(name): conly_args = ["a1", "c2", "b1"], cxx_args = ["a2", "c1", "b2"], generate_build_settings = True, + generate_swift_debug_settings = True, include_self_swift_debug_settings = False, swift_args = ["a", "c", "b"], @@ -535,6 +541,7 @@ def write_target_build_settings_test_suite(name): certificate_name = "best certificate", entitlements = "some/app.entitlements", generate_build_settings = True, + generate_swift_debug_settings = False, provisioning_profile_is_xcode_managed = True, provisioning_profile_name = "a profile", swift_args = [], @@ -585,6 +592,7 @@ def write_target_build_settings_test_suite(name): conly_args = [], cxx_args = [], generate_build_settings = True, + generate_swift_debug_settings = True, swift_args = ["-v", "a"], # Expected @@ -634,6 +642,7 @@ def write_target_build_settings_test_suite(name): conly_args = [], cxx_args = [], generate_build_settings = True, + generate_swift_debug_settings = True, swift_args = ["-v", "a"], swift_debug_settings_to_merge = [ "transitive_debug_settings/2", @@ -693,9 +702,9 @@ def write_target_build_settings_test_suite(name): device_family = "1,2", extension_safe = True, generate_build_settings = False, + generate_swift_debug_settings = True, include_self_swift_debug_settings = False, infoplist = "some/Info.plist", - is_top_level_target = True, previews_dynamic_frameworks = [ "bazel-out/generated.framework", "/absolute/f.framework", diff --git a/xcodeproj/internal/automatic_target_info.bzl b/xcodeproj/internal/automatic_target_info.bzl index 97b9c885f..2a461cbf4 100644 --- a/xcodeproj/internal/automatic_target_info.bzl +++ b/xcodeproj/internal/automatic_target_info.bzl @@ -144,6 +144,16 @@ A sequence of attribute names to collect `File`s from for the `infoplists`-like attributes. This is only used when `xcodeproj.generation_mode = "legacy"` is set. +""", + "is_header_only_library": """\ +Whether this target doesn't contain src files. + +This is only used when `xcodeproj.generation_mode = "incremental"` is set. +""", + "is_mixed_language": """\ +Whether this target is a mixed-language target. + +This is only used when `xcodeproj.generation_mode = "incremental"` is set. """, "is_supported": """\ Whether an Xcode target can be generated for this target. Even if this value is @@ -313,10 +323,6 @@ _BUNDLE_XCODE_TARGETS = { "private_deps": _XCODE_TARGET_TYPES_COMPILE, "transitive_deps": _XCODE_TARGET_TYPES_COMPILE, } -_MIXED_LANGUAGE_XCODE_TARGETS = { - "clang_target": _XCODE_TARGET_TYPES_COMPILE, - "swift_target": _XCODE_TARGET_TYPES_COMPILE, -} _OBJC_LIBRARY_XCODE_TARGETS = { "deps": _XCODE_TARGET_TYPES_COMPILE_AND_NONE, # Issues like https://github.com/bazelbuild/bazel/issues/17646 made some Bazel users @@ -393,6 +399,8 @@ def calculate_automatic_target_info( hdrs = EMPTY_LIST implementation_deps = EMPTY_LIST infoplists = EMPTY_LIST + is_header_only_library = False + is_mixed_language = False is_supported = True is_top_level = False label = target.label @@ -411,6 +419,7 @@ def calculate_automatic_target_info( bool(target.files) and _has_values_in(_SRCS_ATTRS, attr = rule_attr) ) + is_header_only_library = not is_supported elif rule_kind == "cc_import": extra_files = _CC_IMPORT_EXTRA_FILES_ATTRS is_supported = False @@ -428,6 +437,7 @@ def calculate_automatic_target_info( _has_values_in(_NON_ARC_SRCS_ATTRS, attr = rule_attr) ) ) + is_header_only_library = not is_supported elif rule_kind == "objc_import": extra_files = _OBJC_IMPORT_EXTRA_FILES_ATTRS is_supported = False @@ -441,8 +451,8 @@ def calculate_automatic_target_info( elif rule_kind == "swift_proto_library": xcode_targets = _DEPS_XCODE_TARGETS elif rule_kind == "mixed_language_library": - is_supported = False - xcode_targets = _MIXED_LANGUAGE_XCODE_TARGETS + is_mixed_language = True + xcode_targets = _DEPS_XCODE_TARGETS elif (AppleResourceBundleInfo in target and rule_kind != "apple_bundle_import"): is_supported = False @@ -564,6 +574,8 @@ def calculate_automatic_target_info( exported_symbols_lists = exported_symbols_lists, hdrs = hdrs, infoplists = infoplists, + is_header_only_library = is_header_only_library, + is_mixed_language = is_mixed_language, is_supported = is_supported, is_top_level = is_top_level, implementation_deps = implementation_deps, diff --git a/xcodeproj/internal/files/incremental_input_files.bzl b/xcodeproj/internal/files/incremental_input_files.bzl index e98777905..1c14e866f 100644 --- a/xcodeproj/internal/files/incremental_input_files.bzl +++ b/xcodeproj/internal/files/incremental_input_files.bzl @@ -606,6 +606,101 @@ def _collect_incremental_input_files( ), ) +def _collect_mixed_language_input_files( + *, + mergeable_info, + mixed_target_infos): + """Collects all of the inputs of a target. + + Args: + mergeable_info: A value from `mergeable_infos.calculate_mixed_language`. + mixed_target_infos: A `list` of `XcodeProjInfo`s for the underlying + Clang and Swift targets. + + Returns: + A `tuple` with two elements: + + * A `struct`, which will be passed to `xcode_targets.make`, with the + following fields: + + * `extra_file_paths`: A `depset` of file path strings that aren't + covered under the other attributes, but should be included in + the project navigator. + * `extra_files`: A `depset` of `File` that aren't covered under + the other attributes, but should be included in the project + navigator. + * `extra_folders`: A `depset` of folder path strings that aren't + covered under the other attributes, but should be included in + the project navigator. + * `non_arc_srcs`: A `list` of `File`s that are inputs to + `target`'s `non_arc_srcs`-like attributes. + * `srcs`: A `list` of `File`s that are inputs to `target`'s + `srcs`-like attributes. + + * A `struct`, which will end up in `XcodeProjInfo.inputs`, with the + following fields: + + * `important_generated`: A `depset` of important generated `File`s + that are inputs to `target` or its transitive dependencies. + These differ from `generated` in that they will be generated as + part of project generation, to ensure they are created before + Xcode is opened. Entitlements are an example of this, as Xcode + won't even start a build if they are missing. + * `resource_bundles`: A `depset` of values from + `resources.collect().bundles`. + * `unsupported_extra_files`: A `depset` of `File`s that are inputs + of unsupported targets. These should be included in the project + navigator. + * `xccurrentversions`: A `depset` of `.xccurrentversion` `File`s + that are in `resources`. + """ + return ( + struct( + extra_file_paths = mergeable_info.extra_file_paths, + extra_files = mergeable_info.extra_files, + extra_folders = EMPTY_DEPSET, + extra_generated_folders = EMPTY_DEPSET, + infoplist = None, + non_arc_srcs = mergeable_info.non_arc_srcs, + srcs = mergeable_info.srcs, + ), + struct( + # Framework files only come from top-level targets, so no need to + # collect them from `mixed_target_infos` + _product_framework_files = EMPTY_DEPSET, + # Resources only come from top-level targets, so no need to collect + # them from `mixed_target_infos` + _resource_bundle_labels = EMPTY_DEPSET, + _resource_bundle_uncategorized_files = EMPTY_DEPSET, + _resource_bundle_uncategorized_folders = EMPTY_DEPSET, + _resource_bundle_uncategorized_generated_folders = EMPTY_DEPSET, + _uncategorized = memory_efficient_depset( + transitive = [ + _collect_transitive_uncategorized(info) + for info in mixed_target_infos + ], + ), + resource_bundles = EMPTY_DEPSET, + # Only entitlements are currently considered important, but to + # prevent bugs if we add more files in the future, we will still + # merge here + important_generated = memory_efficient_depset( + transitive = [ + info.inputs.important_generated + for info in mixed_target_infos + ], + ), + unsupported_extra_files = memory_efficient_depset( + transitive = [ + info.inputs.unsupported_extra_files + for info in mixed_target_infos + ], + ), + # Same as resource collection, so no need to merge + xccurrentversions = EMPTY_DEPSET, + ), + ) + def _collect_unsupported_input_files( *, ctx, @@ -879,6 +974,7 @@ def _merge_top_level_input_files( incremental_input_files = struct( collect = _collect_incremental_input_files, + collect_mixed_language = _collect_mixed_language_input_files, collect_unsupported = _collect_unsupported_input_files, merge = _merge_input_files, merge_top_level = _merge_top_level_input_files, diff --git a/xcodeproj/internal/files/incremental_output_files.bzl b/xcodeproj/internal/files/incremental_output_files.bzl index 126e261a1..19f816999 100644 --- a/xcodeproj/internal/files/incremental_output_files.bzl +++ b/xcodeproj/internal/files/incremental_output_files.bzl @@ -289,6 +289,107 @@ def _collect_incremental_output_files( ), ) +def _collect_mixed_language_output_files( + *, + actions, + compile_params_files, + id, + indexstore_overrides, + mixed_target_infos, + name): + """Collects the outputs of a target. + + Args: + actions: `ctx.actions`. + compile_params_files: A `list` of compiler params `File`s that should be + generated for Index Build and Xcode Previews. + id: A unique identifier for the target. + indexstore_overrides: A `list` of `(indexstore, target_name)` `tuple`s + that override the indexstore for the target. This is used for merged + targets. + mixed_target_infos: A `list` of `XcodeProjInfo`s for the underlying + Clang and Swift targets. + name: Name (potentially replaced) of the target. + + Returns: + An opaque `struct` that should be used with `output_files.to_dto` or + `output_files.to_output_groups_fields`. + """ + transitive_indexstore_overrides = memory_efficient_depset( + indexstore_overrides, + transitive = [ + info.outputs._transitive_indexstore_overrides + for info in mixed_target_infos + ], + ) + transitive_indexstores = memory_efficient_depset( + transitive = [ + info.outputs._transitive_indexstores + for info in mixed_target_infos + ], + ) + + transitive_compile_params = memory_efficient_depset( + compile_params_files, + transitive = [ + info.outputs._transitive_compile_params + for info in mixed_target_infos + ], + ) + + # Only top-level targets will have `Info.plist` files + transitive_infoplists = EMPTY_DEPSET + + # Only top-level targets will have link params + transitive_link_params = EMPTY_DEPSET + + products_output_group_name = "bp {}".format(id) + + indexstores_filelist = indexstore_filelists.write( + actions = actions, + indexstore_and_target_overrides = transitive_indexstore_overrides, + indexstores = transitive_indexstores, + name = "bi", + rule_name = name, + ) + + products_depset = memory_efficient_depset( + ( + # We don't want to declare indexstore files as outputs, because they + # expand to individual files and blow up the BEP. Instead they are + # declared as inputs to `indexstores_filelist`, ensuring they are + # downloaded as needed. + [indexstores_filelist] + ), + ) + + direct_group_list = [ + ("bc {}".format(id), transitive_compile_params), + ("bl {}".format(id), transitive_link_params), + (products_output_group_name, products_depset), + ] + + return ( + struct( + direct_outputs = None, + products_output_group_name = products_output_group_name, + transitive_infoplists = transitive_infoplists, + ), + struct( + _is_framework = False, + _transitive_compile_params = transitive_compile_params, + _transitive_indexstore_overrides = transitive_indexstore_overrides, + _transitive_indexstores = transitive_indexstores, + _transitive_infoplists = transitive_infoplists, + _transitive_link_params = transitive_link_params, + # Only top-level targets will have products or dSYM files + _transitive_products = EMPTY_DEPSET, + ), + struct( + _direct_group_list = direct_group_list, + ), + ) + def _merge_output_files(*, transitive_infos): """Creates merged outputs. @@ -422,6 +523,7 @@ def parse_swift_info_module(module): incremental_output_files = struct( collect = _collect_incremental_output_files, + collect_mixed_language = _collect_mixed_language_output_files, merge = _merge_output_files, ) diff --git a/xcodeproj/internal/incremental_xcodeprojinfos.bzl b/xcodeproj/internal/incremental_xcodeprojinfos.bzl index 81dd961f2..14149350b 100644 --- a/xcodeproj/internal/incremental_xcodeprojinfos.bzl +++ b/xcodeproj/internal/incremental_xcodeprojinfos.bzl @@ -27,6 +27,10 @@ load( "//xcodeproj/internal/processed_targets:incremental_unsupported_targets.bzl", unsupported_targets = "incremental_unsupported_targets", ) +load( + "//xcodeproj/internal/processed_targets:mixed_language_library_targets.bzl", + "mixed_language_library_targets", +) load(":automatic_target_info.bzl", "calculate_automatic_target_info") load(":compilation_providers.bzl", "compilation_providers") load(":dependencies.bzl", "dependencies") @@ -565,6 +569,43 @@ def _make_non_skipped_target_xcodeprojinfo( transitive_infos = valid_transitive_infos, ) focused_library_deps = EMPTY_DEPSET + elif automatic_target_info.is_mixed_language: + ( + processed_target, + swift_label, + clang_label, + ) = mixed_language_library_targets.process( + ctx = ctx, + automatic_target_info = automatic_target_info, + generate_target = ( + automatic_target_info.should_generate and is_focused + ), + target = target, + transitive_infos = valid_transitive_infos, + rule_attr = rule_attr, + ) + focused_library_deps = memory_efficient_depset( + [ + struct( + id = processed_target.xcode_target.id, + label = str(swift_label), + ), + struct( + id = processed_target.xcode_target.id, + label = str(clang_label), + ), + struct( + id = processed_target.xcode_target.id, + label = label_str, + ), + ] if processed_target.xcode_target else None, + # We want the last one specified to be the one used + order = "postorder", + transitive = [ + info.focused_library_deps + for info in valid_transitive_infos + ], + ) else: processed_target = library_targets.process( ctx = ctx, @@ -775,6 +816,7 @@ def _make_xcodeprojinfo( ) return XcodeProjInfo( + label = target.label, **info_fields ) diff --git a/xcodeproj/internal/pbxproj_partials.bzl b/xcodeproj/internal/pbxproj_partials.bzl index 7360d7457..34f3b4639 100644 --- a/xcodeproj/internal/pbxproj_partials.bzl +++ b/xcodeproj/internal/pbxproj_partials.bzl @@ -4,6 +4,7 @@ load("//xcodeproj/internal/files:files.bzl", "join_paths_ignoring_empty") load(":collections.bzl", "uniq") load( ":memory_efficiency.bzl", + "EMPTY_DEPSET", "EMPTY_LIST", "EMPTY_STRING", "FALSE_ARG", @@ -1120,16 +1121,16 @@ def _write_target_build_settings( entitlements = None, extension_safe = False, generate_build_settings, + generate_swift_debug_settings, include_self_swift_debug_settings = True, infoplist = None, - is_top_level_target = False, name, previews_dynamic_frameworks = EMPTY_LIST, previews_include_path = EMPTY_STRING, provisioning_profile_is_xcode_managed = False, provisioning_profile_name = None, swift_args, - swift_debug_settings_to_merge, + swift_debug_settings_to_merge = EMPTY_DEPSET, team_id = None, tool): """Creates the `OTHER_SWIFT_FLAGS` build setting string file for a target. @@ -1146,13 +1147,13 @@ def _write_target_build_settings( extension_safe: If `True`, `APPLICATION_EXTENSION_API_ONLY` will be set. generate_build_settings: A `bool` indicating whether to generate build settings. This is mostly tied to if the target is focused or not. + generate_swift_debug_settings: A `bool` indicating whether to generate + Swift debug settings. include_self_swift_debug_settings: A `bool` indicating whether to include the target's own Swift debug settings. Should be false for merged top-level targets. infoplist: An optional `File` containing the `Info.plist` for the target. - is_top_level_target: A `bool` indicating whether this is a top level - target. name: The name of the target. previews_dynamic_frameworks: A `list` of `(File, bool)` `tuple`s. If the `bool` is `True`, the file points to a dynamic framework. If @@ -1180,8 +1181,6 @@ def _write_target_build_settings( has them available for the `Create Compile Dependencies` build phase. """ - generate_swift_debug_settings = swift_args or is_top_level_target - if not (generate_build_settings or generate_swift_debug_settings): return None, None, EMPTY_LIST diff --git a/xcodeproj/internal/processed_targets/incremental_library_targets.bzl b/xcodeproj/internal/processed_targets/incremental_library_targets.bzl index c9aa14074..4b6915c87 100644 --- a/xcodeproj/internal/processed_targets/incremental_library_targets.bzl +++ b/xcodeproj/internal/processed_targets/incremental_library_targets.bzl @@ -13,7 +13,6 @@ load( ) load( "//xcodeproj/internal:memory_efficiency.bzl", - "EMPTY_DEPSET", "EMPTY_TUPLE", ) load("//xcodeproj/internal:pbxproj_partials.bzl", "pbxproj_partials") @@ -55,8 +54,8 @@ def _process_incremental_library_target( generate_target: Whether an Xcode target should be generated for this target. rule_attr: `ctx.rule.attr`. - transitive_infos: A `list` of `depset`s of `XcodeProjInfo`s from the - transitive dependencies of `target`. + transitive_infos: A `list` of `XcodeProjInfo`s from the transitive + dependencies of `target`. Returns: A value from `processed_target`. @@ -135,15 +134,15 @@ def _process_incremental_library_target( swift_debug_settings_file, params_files, ) = pbxproj_partials.write_target_build_settings( - actions = ctx.actions, + actions = actions, apple_generate_dsym = ctx.fragments.cpp.apple_generate_dsym, colorize = ctx.attr._colorize[BuildSettingInfo].value, conly_args = args.conly, cxx_args = args.cxx, generate_build_settings = generate_target, + generate_swift_debug_settings = bool(args.swift), name = label.name, swift_args = args.swift, - swift_debug_settings_to_merge = EMPTY_DEPSET, tool = ctx.executable._target_build_settings_generator, ) @@ -156,6 +155,11 @@ def _process_incremental_library_target( order = "topological", ) + if apple_common.AppleDebugOutputs in target: + debug_outputs = target[apple_common.AppleDebugOutputs] + else: + debug_outputs = None + ( target_outputs, provider_outputs, @@ -163,9 +167,7 @@ def _process_incremental_library_target( ) = output_files.collect( actions = actions, compile_params_files = params_files, - debug_outputs = ( - target[apple_common.AppleDebugOutputs] if apple_common.AppleDebugOutputs in target else None - ), + debug_outputs = debug_outputs, id = id, name = label.name, output_group_info = ( @@ -192,6 +194,7 @@ def _process_incremental_library_target( indexstores = (swift_outputs.indexstore,) else: indexstores = EMPTY_TUPLE + mergeable_infos = depset( [ struct( @@ -201,6 +204,7 @@ def _process_incremental_library_target( inputs = target_inputs.xcode_inputs, module_name = module_name, package_bin_dir = package_bin_dir, + premerged_info = None, product_file = product.file, swift_debug_settings = swift_debug_settings, swiftmodule = ( @@ -236,6 +240,7 @@ def _process_incremental_library_target( # in `top_level_targets.bzl`. struct( id = None, + premerged_info = None, swiftmodule = bool(swift_outputs), ), ], diff --git a/xcodeproj/internal/processed_targets/incremental_processed_targets.bzl b/xcodeproj/internal/processed_targets/incremental_processed_targets.bzl index c4e2b66f2..2d8bdd2ce 100644 --- a/xcodeproj/internal/processed_targets/incremental_processed_targets.bzl +++ b/xcodeproj/internal/processed_targets/incremental_processed_targets.bzl @@ -11,7 +11,7 @@ def _make_incremental_processed_target( hosted_targets = None, inputs, is_top_level = False, - mergeable_infos = None, + mergeable_infos, merged_target_ids = None, outputs, platform = None, diff --git a/xcodeproj/internal/processed_targets/incremental_top_level_targets.bzl b/xcodeproj/internal/processed_targets/incremental_top_level_targets.bzl index a7b9b596b..c62b2bc31 100644 --- a/xcodeproj/internal/processed_targets/incremental_top_level_targets.bzl +++ b/xcodeproj/internal/processed_targets/incremental_top_level_targets.bzl @@ -452,9 +452,9 @@ def _process_focused_top_level_target( entitlements = target_inputs.entitlements, extension_safe = props.extension_safe, generate_build_settings = True, + generate_swift_debug_settings = True, include_self_swift_debug_settings = not mergeable_info, infoplist = infoplist, - is_top_level_target = True, name = label.name, previews_dynamic_frameworks = previews_dynamic_frameworks, previews_include_path = ( @@ -855,8 +855,8 @@ def _process_incremental_top_level_target( generate_target: Whether an Xcode target should be generated for this target. rule_attr: `ctx.rule.attr`. - transitive_infos: A `list` of `depset`s of `XcodeProjInfo`s from the - transitive dependencies of `target`. + transitive_infos: A `list` of `XcodeProjInfo`s from the transitive + dependencies of `target`. Returns: A value from `processed_target`. diff --git a/xcodeproj/internal/processed_targets/incremental_unsupported_targets.bzl b/xcodeproj/internal/processed_targets/incremental_unsupported_targets.bzl index fb4382163..ac03a2477 100644 --- a/xcodeproj/internal/processed_targets/incremental_unsupported_targets.bzl +++ b/xcodeproj/internal/processed_targets/incremental_unsupported_targets.bzl @@ -86,6 +86,27 @@ def _process_incremental_unsupported_target( objc = target[apple_common.Objc] if apple_common.Objc in target else None, ) + if automatic_target_info.is_header_only_library: + mergeable_infos = depset( + [ + # We still set a value to prevent unfocused targets from + # changing which targets _could_ merge. This is filtered out + # in `top_level_targets.bzl`. + struct( + id = None, + premerged_info = None, + swiftmodule = False, + ), + ], + ) + else: + mergeable_infos = memory_efficient_depset( + transitive = [ + info.mergeable_infos + for info in transitive_infos + ], + ) + return processed_targets.make( compilation_providers = provider_compilation_providers, direct_dependencies = direct_dependencies, @@ -99,12 +120,7 @@ def _process_incremental_unsupported_target( rule_attr = rule_attr, transitive_infos = transitive_infos, ), - mergeable_infos = memory_efficient_depset( - transitive = [ - info.mergeable_infos - for info in transitive_infos - ], - ), + mergeable_infos = mergeable_infos, outputs = output_files.merge(transitive_infos = transitive_infos), resource_bundle_ids = resource_bundle_ids, swift_debug_settings = memory_efficient_depset( diff --git a/xcodeproj/internal/processed_targets/mergeable_infos.bzl b/xcodeproj/internal/processed_targets/mergeable_infos.bzl index d3fe141f1..0ec6c7113 100644 --- a/xcodeproj/internal/processed_targets/mergeable_infos.bzl +++ b/xcodeproj/internal/processed_targets/mergeable_infos.bzl @@ -24,27 +24,6 @@ _PREVIEWS_ENABLED_PRODUCT_TYPES = { "w": None, # com.apple.product-type.application.watchapp2 } -def _cc_mergeable_info(*, id, mergeable_info): - return struct( - compile_target_ids = mergeable_info.id, - compile_target_ids_list = [mergeable_info.id], - conly_args = mergeable_info.args.conly, - cxx_args = mergeable_info.args.cxx, - extra_file_paths = mergeable_info.inputs.extra_file_paths, - extra_files = mergeable_info.inputs.extra_files, - indexstores = mergeable_info.indexstores, - ids = [(id, (mergeable_info.id,))], - module_name = mergeable_info.module_name, - non_arc_srcs = mergeable_info.inputs.non_arc_srcs, - package_bin_dir = mergeable_info.package_bin_dir, - previews_dynamic_frameworks = EMPTY_LIST, - previews_include_path = EMPTY_STRING, - product_files = (mergeable_info.product_file,), - srcs = mergeable_info.inputs.srcs, - swift_args = EMPTY_LIST, - swift_debug_settings_to_merge = mergeable_info.swift_debug_settings, - ) - def _calculate_mergeable_info( *, avoid_deps, @@ -87,6 +66,12 @@ def _calculate_mergeable_info( # `None` for `id` means the library target was explicitly unfocused return None + premerged_info = mergeable_info.premerged_info + if premerged_info: + # Mixed-language targets already ran through this process, so + # return that value + return premerged_info + if mergeable_info.swiftmodule: return _swift_mergeable_info( dynamic_frameworks = dynamic_frameworks, @@ -105,6 +90,11 @@ def _calculate_mergeable_info( mergeable_info1 = mergeable_infos[0] mergeable_info2 = mergeable_infos[1] + if (mergeable_info1.premerged_info or + mergeable_info2.premerged_info): + # Mixed-language targets can't merge with other library targets + return None + if not mergeable_info1.id and not mergeable_info2.id: # `None` for `id` means the library target was explicitly unfocused return None @@ -120,72 +110,81 @@ def _calculate_mergeable_info( cc = mergeable_info1 if mergeable_info2_is_swift else mergeable_info2 swift = mergeable_info1 if mergeable_info1_is_swift else mergeable_info2 - if not cc.id: - return _swift_mergeable_info( - dynamic_frameworks = dynamic_frameworks, - id = id, - mergeable_info = swift, - product_type = product_type, - ) - if not swift.id: - return _cc_mergeable_info( - id = id, - mergeable_info = cc, - ) - - previews_info = _previews_info( - swift, + return _handle_mixed_language_mergeable_infos( + cc = cc, dynamic_frameworks = dynamic_frameworks, + id = id, product_type = product_type, - ) - - return struct( - compile_target_ids = swift.id + " " + cc.id, - compile_target_ids_list = [swift.id, cc.id], - conly_args = cc.args.conly, - cxx_args = cc.args.cxx, - extra_file_paths = memory_efficient_depset( - transitive = [ - swift.inputs.extra_file_paths, - cc.inputs.extra_file_paths, - ], - ), - extra_files = memory_efficient_depset( - transitive = [ - swift.inputs.extra_files, - cc.inputs.extra_files, - ], - ), - indexstores = list(swift.indexstores) + list(cc.indexstores), - ids = [(id, (swift.id, cc.id))], - module_name = swift.module_name, - non_arc_srcs = cc.inputs.non_arc_srcs, - package_bin_dir = swift.package_bin_dir, - previews_dynamic_frameworks = previews_info.frameworks, - previews_include_path = previews_info.include_path, - product_files = ( - swift.product_file, - cc.product_file, - ), - srcs = memory_efficient_depset( - transitive = [ - swift.inputs.srcs, - cc.inputs.srcs, - ], - ), - swift_args = swift.args.swift, - swift_debug_settings_to_merge = memory_efficient_depset( - transitive = [ - mergeable_infos[0].swift_debug_settings, - mergeable_infos[1].swift_debug_settings, - ], - order = "topological", - ), + swift = swift, ) # Unmergeable source target count return None +def _calculate_mixed_language_mergeable_info( + *, + clang_target_info, + id, + product_type, + swift_target_info): + return _handle_mixed_language_mergeable_infos( + cc = clang_target_info.mergeable_infos.to_list()[0], + dynamic_frameworks = EMPTY_LIST, + id = id, + product_type = product_type, + swift = swift_target_info.mergeable_infos.to_list()[0], + ) + +def _cc_mergeable_info(*, id, mergeable_info): + return struct( + compile_target_ids = mergeable_info.id, + compile_target_ids_list = (mergeable_info.id,), + conly_args = mergeable_info.args.conly, + cxx_args = mergeable_info.args.cxx, + extra_file_paths = mergeable_info.inputs.extra_file_paths, + extra_files = mergeable_info.inputs.extra_files, + indexstores = mergeable_info.indexstores, + ids = ((id, (mergeable_info.id,)),), + is_mixed_langauge = False, + module_name = mergeable_info.module_name, + non_arc_srcs = mergeable_info.inputs.non_arc_srcs, + package_bin_dir = mergeable_info.package_bin_dir, + previews_dynamic_frameworks = EMPTY_LIST, + previews_include_path = EMPTY_STRING, + product_files = (mergeable_info.product_file,), + srcs = mergeable_info.inputs.srcs, + swift_args = EMPTY_LIST, + swift_debug_settings_to_merge = mergeable_info.swift_debug_settings, + ) + +def _handle_mixed_language_mergeable_infos( + *, + cc, + dynamic_frameworks, + id, + product_type, + swift): + if not cc.id: + return _swift_mergeable_info( + dynamic_frameworks = dynamic_frameworks, + id = id, + mergeable_info = swift, + product_type = product_type, + ) + if not swift.id: + return _cc_mergeable_info( + id = id, + mergeable_info = cc, + ) + + return _mixed_language_mergeable_info( + cc = cc, + dynamic_frameworks = dynamic_frameworks, + id = id, + product_type = product_type, + swift = swift, + ) + def _previews_info( mergeable_info, *, @@ -210,6 +209,63 @@ def _previews_info( include_path = include_path, ) +def _mixed_language_mergeable_info( + *, + cc, + dynamic_frameworks, + id, + product_type, + swift): + previews_info = _previews_info( + swift, + dynamic_frameworks = dynamic_frameworks, + product_type = product_type, + ) + + return struct( + compile_target_ids = swift.id + " " + cc.id, + compile_target_ids_list = (swift.id, cc.id), + conly_args = cc.args.conly, + cxx_args = cc.args.cxx, + extra_file_paths = memory_efficient_depset( + transitive = [ + swift.inputs.extra_file_paths, + cc.inputs.extra_file_paths, + ], + ), + extra_files = memory_efficient_depset( + transitive = [ + swift.inputs.extra_files, + cc.inputs.extra_files, + ], + ), + indexstores = tuple(list(swift.indexstores) + list(cc.indexstores)), + ids = ((id, (swift.id, cc.id)),), + module_name = swift.module_name, + non_arc_srcs = cc.inputs.non_arc_srcs, + package_bin_dir = swift.package_bin_dir, + previews_dynamic_frameworks = previews_info.frameworks, + previews_include_path = previews_info.include_path, + product_files = ( + swift.product_file, + cc.product_file, + ), + srcs = memory_efficient_depset( + transitive = [ + swift.inputs.srcs, + cc.inputs.srcs, + ], + ), + swift_args = swift.args.swift, + swift_debug_settings_to_merge = memory_efficient_depset( + transitive = [ + swift.swift_debug_settings, + cc.swift_debug_settings, + ], + order = "topological", + ), + ) + def _swift_mergeable_info( *, dynamic_frameworks, @@ -224,13 +280,14 @@ def _swift_mergeable_info( return struct( compile_target_ids = mergeable_info.id, - compile_target_ids_list = [mergeable_info.id], + compile_target_ids_list = (mergeable_info.id,), conly_args = EMPTY_LIST, cxx_args = EMPTY_LIST, extra_file_paths = mergeable_info.inputs.extra_file_paths, extra_files = mergeable_info.inputs.extra_files, indexstores = mergeable_info.indexstores, - ids = [(id, (mergeable_info.id,))], + ids = ((id, (mergeable_info.id,)),), + is_mixed_langauge = False, module_name = mergeable_info.module_name, non_arc_srcs = EMPTY_DEPSET, package_bin_dir = mergeable_info.package_bin_dir, @@ -244,4 +301,5 @@ def _swift_mergeable_info( mergeable_infos = struct( calculate = _calculate_mergeable_info, + calculate_mixed_language = _calculate_mixed_language_mergeable_info, ) diff --git a/xcodeproj/internal/processed_targets/mixed_language_library_targets.bzl b/xcodeproj/internal/processed_targets/mixed_language_library_targets.bzl new file mode 100644 index 000000000..aafd0e8c8 --- /dev/null +++ b/xcodeproj/internal/processed_targets/mixed_language_library_targets.bzl @@ -0,0 +1,241 @@ +"""Functions for processing mixed-language library targets.""" + +load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") +load("//xcodeproj/internal:build_settings.bzl", "get_product_module_name") +load("//xcodeproj/internal:compilation_providers.bzl", "compilation_providers") +load("//xcodeproj/internal:configuration.bzl", "calculate_configuration") +load("//xcodeproj/internal:dependencies.bzl", "dependencies") +load( + "//xcodeproj/internal:incremental_xcode_targets.bzl", + xcode_targets = "incremental_xcode_targets", +) +load("//xcodeproj/internal:pbxproj_partials.bzl", "pbxproj_partials") +load("//xcodeproj/internal:platforms.bzl", "platforms") +load("//xcodeproj/internal:products.bzl", "products") +load("//xcodeproj/internal:target_id.bzl", "get_id") +load("//xcodeproj/internal:xcodeprojinfo.bzl", "XcodeProjInfo") +load( + "//xcodeproj/internal/files:incremental_input_files.bzl", + input_files = "incremental_input_files", +) +load( + "//xcodeproj/internal/files:incremental_output_files.bzl", + "output_groups", + output_files = "incremental_output_files", +) +load("//xcodeproj/internal/files:linker_input_files.bzl", "linker_input_files") +load( + ":incremental_processed_targets.bzl", + processed_targets = "incremental_processed_targets", +) +load(":mergeable_infos.bzl", mergeable_infos_module = "mergeable_infos") + +def _process_mixed_language_library_target( + *, + ctx, + target, + automatic_target_info, + generate_target, + rule_attr, + transitive_infos): + """Gathers information about a library target. + + Args: + ctx: The aspect context. + target: The `Target` to process. + automatic_target_info: The `XcodeProjAutomaticTargetProcessingInfo` for + `target`. + generate_target: Whether an Xcode target should be generated for this + target. + rule_attr: `ctx.rule.attr`. + transitive_infos: A `list` of `XcodeProjInfo`s from the transitive + dependencies of `target`. + + Returns: + A `tuple` of three values: + + * A value from `processed_target`. + * The `Label` of the Swift target. + * The `Label` of the Clang target. + """ + bin_dir_path = ctx.bin_dir.path + configuration = calculate_configuration(bin_dir_path = bin_dir_path) + label = automatic_target_info.label + id = get_id(label = label, configuration = configuration) + + clang_target_info = rule_attr.clang_target[XcodeProjInfo] + swift_target_info = rule_attr.swift_target[XcodeProjInfo] + mixed_target_infos = [swift_target_info, clang_target_info] + + product_name = rule_attr.name + + direct_dependencies, transitive_dependencies = dependencies.collect( + transitive_infos = transitive_infos, + ) + + objc = target[apple_common.Objc] if apple_common.Objc in target else None + ( + target_compilation_providers, + provider_compilation_providers, + ) = compilation_providers.collect( + cc_info = target[CcInfo], + objc = objc, + ) + linker_inputs = linker_input_files.collect( + automatic_target_info = automatic_target_info, + compilation_providers = target_compilation_providers, + target = target, + ) + + platform = platforms.collect(ctx = ctx) + + actions = ctx.actions + + # Value taken from `PRODUCT_TYPE_ENCODED` in `product.bzl`, for + # `com.apple.product-type.library.static` + product_type = "L" + + product = products.collect( + actions = actions, + linker_inputs = linker_inputs, + product_name = product_name, + product_type = product_type, + target = target, + ) + + mergeable_info = mergeable_infos_module.calculate_mixed_language( + clang_target_info = clang_target_info, + id = id, + product_type = product_type, + swift_target_info = swift_target_info, + ) + + (xcode_inputs, provider_inputs) = input_files.collect_mixed_language( + mergeable_info = mergeable_info, + mixed_target_infos = mixed_target_infos, + ) + + actual_package_bin_dir = products.calculate_packge_bin_dir( + bin_dir_path = bin_dir_path, + label = label, + ) + + package_bin_dir = mergeable_info.package_bin_dir + args = struct( + cxx = mergeable_info.cxx_args, + swift = mergeable_info.swift_args, + ) + + ( + target_build_settings, + _, + params_files, + ) = pbxproj_partials.write_target_build_settings( + actions = actions, + apple_generate_dsym = ctx.fragments.cpp.apple_generate_dsym, + colorize = ctx.attr._colorize[BuildSettingInfo].value, + conly_args = mergeable_info.conly_args, + cxx_args = mergeable_info.cxx_args, + generate_build_settings = generate_target, + generate_swift_debug_settings = False, + include_self_swift_debug_settings = False, + name = label.name, + swift_args = args.swift, + tool = ctx.executable._target_build_settings_generator, + ) + + indexstore_override_path = actual_package_bin_dir + "/" + label.name + indexstore_overrides = [ + (indexstore, indexstore_override_path) + for indexstore in mergeable_info.indexstores + ] + + ( + target_outputs, + provider_outputs, + target_output_groups_metadata, + ) = output_files.collect_mixed_language( + actions = actions, + compile_params_files = params_files, + id = id, + indexstore_overrides = indexstore_overrides, + name = label.name, + mixed_target_infos = mixed_target_infos, + ) + target_output_groups = output_groups.collect( + metadata = target_output_groups_metadata, + transitive_infos = mixed_target_infos, + ) + + if generate_target: + module_name_attribute, module_name = get_product_module_name( + rule_attr = rule_attr, + target = target, + ) + + mergeable_infos = depset( + [ + struct( + id = id, + premerged_info = mergeable_info, + ), + ], + ) + + xcode_target = xcode_targets.make( + build_settings_file = target_build_settings, + configuration = configuration, + direct_dependencies = direct_dependencies, + has_c_params = bool(mergeable_info.conly_args), + has_cxx_params = bool(mergeable_info.cxx_args), + id = id, + inputs = xcode_inputs, + is_top_level = False, + label = label, + module_name = module_name, + module_name_attribute = module_name_attribute, + outputs = target_outputs, + package_bin_dir = package_bin_dir, + platform = platform, + product = product.xcode_product, + transitive_dependencies = transitive_dependencies, + ) + else: + mergeable_infos = depset( + [ + # We still set a value to prevent unfocused targets from + # changing which targets _could_ merge. This is filtered out + # in `top_level_targets.bzl`. + struct( + id = None, + # `premerged_info` is only checked for truthiness if + # `id == None`. No other values are checked in this case. + premerged_info = True, + ), + ], + ) + xcode_target = None + + processed_target = processed_targets.make( + compilation_providers = provider_compilation_providers, + direct_dependencies = direct_dependencies, + inputs = provider_inputs, + mergeable_infos = mergeable_infos, + merged_target_ids = mergeable_info.ids, + outputs = provider_outputs, + platform = platform.apple_platform, + swift_debug_settings = swift_target_info.swift_debug_settings, + target_output_groups = target_output_groups, + transitive_dependencies = transitive_dependencies, + xcode_target = xcode_target, + ) + + return ( + processed_target, + swift_target_info.label, + clang_target_info.label, + ) + +mixed_language_library_targets = struct( + process = _process_mixed_language_library_target, +) diff --git a/xcodeproj/internal/xcodeprojinfo.bzl b/xcodeproj/internal/xcodeprojinfo.bzl index 02789c48c..1098198e0 100644 --- a/xcodeproj/internal/xcodeprojinfo.bzl +++ b/xcodeproj/internal/xcodeprojinfo.bzl @@ -79,8 +79,6 @@ to the Xcode project, but are not associated with any targets. """, "label": """\ The `Label` of the target. - -This is only set and used when `xcodeproj.generation_mode = "legacy"` is set. """, "labels": """\ A `depset` of `Labels` for the target and its transitive dependencies.