diff --git a/doc/api.md b/doc/api.md index 225982df0..0e5e9b127 100644 --- a/doc/api.md +++ b/doc/api.md @@ -4,6 +4,51 @@ The `swift_common` module provides API access to the behavior implemented by the Swift build rules, so that other custom rules can invoke Swift compilation and/or linking as part of their implementation. + + +## swift_common.create_swift_info + +
+swift_common.create_swift_info(direct_modules, transitive_modules) ++ +Contains information about the compiled artifacts of a Swift module. + +This provider has a custom initializer that will merge the transitive modules of +a list of `SwiftInfo` providers, rather than a separate "merge" function. The +correct signature when _creating_ a new `SwiftInfo` provider is the following: + +```build +SwiftInfo( + direct_swift_infos, + modules, + swift_infos, +) +``` + +where the arguments are: + +* `direct_swift_infos`: A list of `SwiftInfo` providers from dependencies + whose direct modules should be treated as direct modules in the resulting + provider, in addition to their transitive modules being merged. +* `modules`: A list of values (as returned by `create_swift_module_context`) + that represent Clang and/or Swift module artifacts that are direct outputs + of the target being built. +* `swift_infos`: A list of `SwiftInfo` providers from dependencies whose + transitive modules should be merged into the resulting provider. + +When reading an existing `SwiftInfo` provider, it has the two fields described +below. + +**FIELDS** + + +| Name | Description | +| :------------- | :------------- | +| direct_modules | `List` of values returned from `create_swift_module_context`. The modules (both Swift and C/Objective-C) emitted by the library that propagated this provider. | +| transitive_modules | `Depset` of values returned from `create_swift_module_context`. The transitive modules (both Swift and C/Objective-C) emitted by the library that propagated this provider and all of its dependencies. | + + ## swift_common.cc_feature_configuration @@ -127,7 +172,7 @@ Compiles a Swift module. A `struct` with the following fields: * `module_context`: A Swift module context (as returned by - `swift_common.create_module`) that contains the Swift (and + `create_swift_module_context`) that contains the Swift (and potentially C/Objective-C) compilation prerequisites of the compiled module. This should typically be propagated by a `SwiftInfo` provider of the calling rule, and the `CcCompilationContext` inside @@ -188,7 +233,7 @@ Compiles a Swift module interface. **RETURNS** -A Swift module context (as returned by `swift_common.create_module`) +A Swift module context (as returned by `create_swift_module_context`) that contains the Swift (and potentially C/Objective-C) compilation prerequisites of the compiled module. This should typically be propagated by a `SwiftInfo` provider of the calling rule, and the @@ -253,9 +298,7 @@ Creates a value representing a Clang module used as a Swift dependency. **RETURNS** -A `struct` containing the `compilation_context`, `module_map`, - `precompiled_module`, and `strict_includes` fields provided as - arguments. +A `struct` containing the values provided as arguments. @@ -275,7 +318,7 @@ Cretes a compilation context for a Swift target. | :------------- | :------------- | :------------- | | defines | A list of defines | none | | srcs | A list of Swift source files used to compile the target. | none | -| transitive_modules | A list of modules (as returned by `swift_common.create_module`) from the transitive dependencies of the target. | none | +| transitive_modules | A list of modules (as returned by `create_swift_module_context`) from the transitive dependencies of the target. | none | **RETURNS** @@ -374,51 +417,15 @@ the set of transitive module names that are propagated by dependencies | Name | Description | Default Value | | :------------- | :------------- | :------------- | | name | The name of the module. | none | -| clang | A value returned by `swift_common.create_clang_module` that contains artifacts related to Clang modules, such as a module map or precompiled module. This may be `None` if the module is a pure Swift module with no generated Objective-C interface. | `None` | +| clang | A value returned by `create_clang_module_inputs` that contains artifacts related to Clang modules, such as a module map or precompiled module. This may be `None` if the module is a pure Swift module with no generated Objective-C interface. | `None` | | const_gather_protocols | A list of protocol names from which constant values should be extracted from source code that takes this module as a *direct* dependency. | `[]` | | compilation_context | A value returned from `swift_common.create_compilation_context` that contains the context needed to compile the module being built. This may be `None` if the module wasn't compiled from sources. | `None` | | is_system | Indicates whether the module is a system module. The default value is `False`. System modules differ slightly from non-system modules in the way that they are passed to the compiler. For example, non-system modules have their Clang module maps passed to the compiler in both implicit and explicit module builds. System modules, on the other hand, do not have their module maps passed to the compiler in implicit module builds because there is currently no way to indicate that modules declared in a file passed via `-fmodule-map-file` should be treated as system modules even if they aren't declared with the `[system]` attribute, and some system modules may not build cleanly with respect to warnings otherwise. Therefore, it is assumed that any module with `is_system == True` must be able to be found using import search paths in order for implicit module builds to succeed. | `False` | -| swift | A value returned by `swift_common.create_swift_module` that contains artifacts related to Swift modules, such as the `.swiftmodule`, `.swiftdoc`, and/or `.swiftinterface` files emitted by the compiler. This may be `None` if the module is a pure C/Objective-C module. | `None` | - -**RETURNS** - -A `struct` containing the `name`, `clang`, `is_system`, and `swift` - fields provided as arguments. - - - - -## swift_common.create_swift_info - -
-swift_common.create_swift_info(direct_swift_infos, modules, swift_infos) -- -Creates a new `SwiftInfo` provider with the given values. - -This function is recommended instead of directly creating a `SwiftInfo` -provider because it encodes reasonable defaults for fields that some rules -may not be interested in and ensures that the direct and transitive fields -are set consistently. - -This function can also be used to do a simple merge of `SwiftInfo` -providers, by leaving the `modules` argument unspecified. In that case, the -returned provider will not represent a true Swift module; it is merely a -"collector" for other dependencies. - - -**PARAMETERS** - - -| Name | Description | Default Value | -| :------------- | :------------- | :------------- | -| direct_swift_infos | A list of `SwiftInfo` providers from dependencies whose direct modules should be treated as direct modules in the resulting provider, in addition to their transitive modules being merged. | `[]` | -| modules | A list of values (as returned by `swift_common.create_module`) that represent Clang and/or Swift module artifacts that are direct outputs of the target being built. | `[]` | -| swift_infos | A list of `SwiftInfo` providers from dependencies whose transitive modules should be merged into the resulting provider. | `[]` | +| swift | A value returned by `create_swift_module_inputs` that contains artifacts related to Swift modules, such as the `.swiftmodule`, `.swiftdoc`, and/or `.swiftinterface` files emitted by the compiler. This may be `None` if the module is a pure C/Objective-C module. | `None` | **RETURNS** -A new `SwiftInfo` provider with the given values. +A `struct` containing the given values provided as arguments. @@ -507,9 +514,7 @@ Creates a value representing a Swift module use as a Swift dependency. **RETURNS** -A `struct` containing the `ast_files`, `defines`, `indexstore, - `swiftdoc`, `swiftmodule`, and `swiftinterface` fields - provided as arguments. +A `struct` containing the values provided as arguments. diff --git a/doc/providers.md b/doc/providers.md index e27cd89fb..97134390d 100644 --- a/doc/providers.md +++ b/doc/providers.md @@ -22,18 +22,39 @@ SwiftInfo(direct_modules, direct_modules | `List` of values returned from `swift_common.create_module`. The modules (both Swift and C/Objective-C) emitted by the library that propagated this provider. | -| transitive_modules | `Depset` of values returned from `swift_common.create_module`. The transitive modules (both Swift and C/Objective-C) emitted by the library that propagated this provider and all of its dependencies. | +| direct_modules | `List` of values returned from `create_swift_module_context`. The modules (both Swift and C/Objective-C) emitted by the library that propagated this provider. | +| transitive_modules | `Depset` of values returned from `create_swift_module_context`. The transitive modules (both Swift and C/Objective-C) emitted by the library that propagated this provider and all of its dependencies. | diff --git a/mixed_language/internal/BUILD b/mixed_language/internal/BUILD index 26f370a66..9d4204110 100644 --- a/mixed_language/internal/BUILD +++ b/mixed_language/internal/BUILD @@ -10,10 +10,8 @@ bzl_library( "//swift:providers", "//swift:swift_clang_module_aspect", "//swift/internal:attrs", - "//swift/internal:compiling", "//swift/internal:feature_names", "//swift/internal:features", - "//swift/internal:providers", "//swift/internal:toolchain_utils", "//swift/internal:utils", "@bazel_skylib//lib:dicts", diff --git a/mixed_language/internal/library.bzl b/mixed_language/internal/library.bzl index f65958588..5ec82b2fe 100644 --- a/mixed_language/internal/library.bzl +++ b/mixed_language/internal/library.bzl @@ -16,7 +16,12 @@ load("@bazel_skylib//lib:dicts.bzl", "dicts") load("@bazel_skylib//lib:paths.bzl", "paths") -load("//swift:providers.bzl", "SwiftInfo") +load( + "//swift:providers.bzl", + "SwiftInfo", + "create_clang_module_inputs", + "create_swift_module_context", +) load("//swift:swift_clang_module_aspect.bzl", "swift_clang_module_aspect") # buildifier: disable=bzl-visibility @@ -35,14 +40,6 @@ load( "is_feature_enabled", ) -# buildifier: disable=bzl-visibility -load( - "//swift/internal:providers.bzl", - "create_clang_module", - "create_module", - "create_swift_info", -) - # buildifier: disable=bzl-visibility load( "//swift/internal:toolchain_utils.bzl", @@ -167,11 +164,11 @@ def _mixed_language_library_impl(ctx): ], cc_infos = [swift_target[CcInfo], clang_target[CcInfo]], ) - swift_info = create_swift_info( + swift_info = SwiftInfo( modules = [ - create_module( + create_swift_module_context( name = module_name, - clang = create_clang_module( + clang = create_clang_module_inputs( compilation_context = cc_info.compilation_context, module_map = extended_module_map, ), diff --git a/proto/swift_proto_utils.bzl b/proto/swift_proto_utils.bzl index a2bb0338e..d459bd85d 100644 --- a/proto/swift_proto_utils.bzl +++ b/proto/swift_proto_utils.bzl @@ -366,7 +366,7 @@ def compile_swift_protos_for_target( ) # Create the direct swift info provider: - direct_swift_info = swift_common.create_swift_info( + direct_swift_info = SwiftInfo( modules = [module_context], swift_infos = transitive_swift_infos, ) diff --git a/swift/BUILD b/swift/BUILD index b49ec37ed..38a906177 100644 --- a/swift/BUILD +++ b/swift/BUILD @@ -91,11 +91,11 @@ bzl_library( srcs = ["swift_common.bzl"], deps = [ ":module_name", + ":providers", "//swift/internal:attrs", "//swift/internal:compiling", "//swift/internal:features", "//swift/internal:linking", - "//swift/internal:providers", "//swift/internal:swift_interop_info", "//swift/internal:symbol_graph_extracting", "//swift/internal:toolchain_utils", @@ -187,7 +187,6 @@ bzl_library( ":providers", ":swift_clang_module_aspect", "//swift/internal:attrs", - "//swift/internal:providers", "//swift/internal:utils", ], ) diff --git a/swift/internal/BUILD b/swift/internal/BUILD index 0865ed419..354355332 100644 --- a/swift/internal/BUILD +++ b/swift/internal/BUILD @@ -85,10 +85,10 @@ bzl_library( ":feature_names", ":features", ":module_maps", - ":providers", ":utils", ":vfsoverlay", ":wmo", + "//swift:providers", "@bazel_skylib//lib:paths", "@bazel_skylib//lib:sets", ], @@ -203,12 +203,8 @@ bzl_library( name = "providers", srcs = ["providers.bzl"], visibility = [ - "//mixed_language:__subpackages__", "//swift:__subpackages__", ], - deps = [ - "//swift:providers.bzl", - ], ) bzl_library( @@ -249,8 +245,8 @@ bzl_library( deps = [ ":action_names", ":actions", - ":providers", ":utils", + "//swift:providers", ], ) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index 9f4f9e58e..400d70e73 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -16,6 +16,13 @@ load("@bazel_skylib//lib:paths.bzl", "paths") load("@bazel_skylib//lib:sets.bzl", "sets") +load( + "//swift:providers.bzl", + "SwiftInfo", + "create_clang_module_inputs", + "create_swift_module_context", + "create_swift_module_inputs", +) load( ":action_names.bzl", "SWIFT_ACTION_COMPILE", @@ -58,13 +65,6 @@ load( "is_feature_enabled", ) load(":module_maps.bzl", "write_module_map") -load( - ":providers.bzl", - "create_clang_module", - "create_module", - "create_swift_info", - "create_swift_module", -) load( ":utils.bzl", "compact", @@ -87,7 +87,7 @@ def create_compilation_context(defines, srcs, transitive_modules): defines: A list of defines srcs: A list of Swift source files used to compile the target. transitive_modules: A list of modules (as returned by - `swift_common.create_module`) from the transitive dependencies of + `create_swift_module_context`) from the transitive dependencies of the target. Returns: @@ -166,7 +166,7 @@ def compile_module_interface( outputs. Returns: - A Swift module context (as returned by `swift_common.create_module`) + A Swift module context (as returned by `create_swift_module_context`) that contains the Swift (and potentially C/Objective-C) compilation prerequisites of the compiled module. This should typically be propagated by a `SwiftInfo` provider of the calling rule, and the @@ -181,7 +181,7 @@ def compile_module_interface( for cc_info in swift_toolchain.implicit_deps_providers.cc_infos ], ) - merged_swift_info = create_swift_info( + merged_swift_info = SwiftInfo( swift_infos = ( swift_infos + swift_toolchain.implicit_deps_providers.swift_infos ), @@ -268,9 +268,9 @@ def compile_module_interface( swift_toolchain = swift_toolchain, ) - module_context = create_module( + module_context = create_swift_module_context( name = module_name, - clang = create_clang_module( + clang = create_clang_module_inputs( compilation_context = merged_compilation_context, module_map = None, ), @@ -278,7 +278,7 @@ def compile_module_interface( feature_configuration = feature_configuration, feature_name = SWIFT_FEATURE_SYSTEM_MODULE, ), - swift = create_swift_module( + swift = create_swift_module_inputs( swiftdoc = None, swiftinterface = swiftinterface_file, swiftmodule = swiftmodule_file, @@ -375,7 +375,7 @@ def compile( A `struct` with the following fields: * `module_context`: A Swift module context (as returned by - `swift_common.create_module`) that contains the Swift (and + `create_swift_module_context`) that contains the Swift (and potentially C/Objective-C) compilation prerequisites of the compiled module. This should typically be propagated by a `SwiftInfo` provider of the calling rule, and the `CcCompilationContext` inside @@ -511,7 +511,7 @@ def compile( providers = objc_infos + swift_toolchain.implicit_deps_providers.objc_infos, ) - merged_swift_info = create_swift_info( + merged_swift_info = SwiftInfo( swift_infos = ( swift_infos + private_swift_infos + @@ -737,9 +737,9 @@ to use swift_common.compile(include_dev_srch_paths = ...) instead.\ else: includes = [] - module_context = create_module( + module_context = create_swift_module_context( name = module_name, - clang = create_clang_module( + clang = create_clang_module_inputs( compilation_context = _create_cc_compilation_context( actions = actions, compilation_contexts = compilation_contexts, @@ -755,7 +755,7 @@ to use swift_common.compile(include_dev_srch_paths = ...) instead.\ ), compilation_context = compilation_context, is_system = False, - swift = create_swift_module( + swift = create_swift_module_inputs( ast_files = compile_outputs.ast_files, defines = defines, generated_header = compile_outputs.generated_header_file, @@ -927,7 +927,7 @@ def _precompile_clang_module( swift_infos.extend(implicit_swift_infos) if swift_infos: - merged_swift_info = create_swift_info(swift_infos = swift_infos) + merged_swift_info = SwiftInfo(swift_infos = swift_infos) transitive_modules = merged_swift_info.transitive_modules.to_list() else: transitive_modules = [] diff --git a/swift/internal/providers.bzl b/swift/internal/providers.bzl index 61f5c3482..f038c877a 100644 --- a/swift/internal/providers.bzl +++ b/swift/internal/providers.bzl @@ -12,13 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Internal providers and utility functions. -Note that some of these definitions are exported via the `swift_common` module. -*Public* providers should be defined in `swift:providers.bzl`, not in this file -(`swift/internal:providers.bzl`). -""" - -load("//swift:providers.bzl", "SwiftInfo") +"""Internal providers.""" SwiftModuleAliasesInfo = provider( doc = "Defines a remapping of Swift module names.", @@ -31,231 +25,3 @@ compiling it and/or any modules that depend on it. """, }, ) - -def create_module( - *, - name, - clang = None, - const_gather_protocols = [], - compilation_context = None, - is_system = False, - swift = None): - """Creates a value containing Clang/Swift module artifacts of a dependency. - - It is possible for both `clang` and `swift` to be present; this is the case - for Swift modules that generate an Objective-C header, where the Swift - module artifacts are propagated in the `swift` context and the generated - header and module map are propagated in the `clang` context. - - Though rare, it is also permitted for both the `clang` and `swift` arguments - to be `None`. One example of how this can be used is to model system - dependencies (like Apple SDK frameworks) that are implicitly available as - part of a non-hermetic SDK (Xcode) but do not propagate any artifacts of - their own. This would only apply in a build using implicit modules, however; - when using explicit modules, one would propagate the module artifacts - explicitly. But allowing for the empty case keeps the build graph consistent - if switching between the two modes is necessary, since it will not change - the set of transitive module names that are propagated by dependencies - (which other build rules may want to depend on for their own analysis). - - Args: - name: The name of the module. - clang: A value returned by `swift_common.create_clang_module` that - contains artifacts related to Clang modules, such as a module map or - precompiled module. This may be `None` if the module is a pure Swift - module with no generated Objective-C interface. - const_gather_protocols: A list of protocol names from which constant - values should be extracted from source code that takes this module - as a *direct* dependency. - compilation_context: A value returned from - `swift_common.create_compilation_context` that contains the - context needed to compile the module being built. This may be `None` - if the module wasn't compiled from sources. - is_system: Indicates whether the module is a system module. The default - value is `False`. System modules differ slightly from non-system - modules in the way that they are passed to the compiler. For - example, non-system modules have their Clang module maps passed to - the compiler in both implicit and explicit module builds. System - modules, on the other hand, do not have their module maps passed to - the compiler in implicit module builds because there is currently no - way to indicate that modules declared in a file passed via - `-fmodule-map-file` should be treated as system modules even if they - aren't declared with the `[system]` attribute, and some system - modules may not build cleanly with respect to warnings otherwise. - Therefore, it is assumed that any module with `is_system == True` - must be able to be found using import search paths in order for - implicit module builds to succeed. - swift: A value returned by `swift_common.create_swift_module` that - contains artifacts related to Swift modules, such as the - `.swiftmodule`, `.swiftdoc`, and/or `.swiftinterface` files emitted - by the compiler. This may be `None` if the module is a pure - C/Objective-C module. - - Returns: - A `struct` containing the `name`, `clang`, `is_system`, and `swift` - fields provided as arguments. - """ - return struct( - clang = clang, - const_gather_protocols = tuple(const_gather_protocols), - compilation_context = compilation_context, - is_system = is_system, - name = name, - swift = swift, - ) - -def create_clang_module( - *, - compilation_context, - module_map, - precompiled_module = None, - strict_includes = None): - """Creates a value representing a Clang module used as a Swift dependency. - - Args: - compilation_context: A `CcCompilationContext` that contains the header - files and other context (such as include paths, preprocessor - defines, and so forth) needed to compile this module as an explicit - module. - module_map: The text module map file that defines this module. This - argument may be specified as a `File` or as a `string`; in the - latter case, it is assumed to be the path to a file that cannot - be provided as an action input because it is outside the workspace - (for example, the module map for a module from an Xcode SDK). - precompiled_module: A `File` representing the precompiled module (`.pcm` - file) if one was emitted for the module. This may be `None` if no - explicit module was built for the module; in that case, targets that - depend on the module will fall back to the text module map and - headers. - strict_includes: A `depset` of strings representing additional Clang - include paths that should be passed to the compiler when this module - is a _direct_ dependency of the module being compiled. May be - `None`. **This field only exists to support a specific legacy use - case and should otherwise not be used, as it is fundamentally - incompatible with Swift's import model.** - - Returns: - A `struct` containing the `compilation_context`, `module_map`, - `precompiled_module`, and `strict_includes` fields provided as - arguments. - """ - return struct( - compilation_context = compilation_context, - module_map = module_map, - precompiled_module = precompiled_module, - strict_includes = strict_includes, - ) - -def create_swift_module( - *, - ast_files = [], - const_protocols_to_gather = [], - defines = [], - generated_header = None, - indexstore = None, - original_module_name = None, - plugins = [], - private_swiftinterface = None, - swiftdoc, - swiftinterface = None, - swiftmodule, - swiftsourceinfo = None): - """Creates a value representing a Swift module use as a Swift dependency. - - Args: - ast_files: A list of `File`s output from the `DUMP_AST` action. - const_protocols_to_gather: A list of protocol names from which constant - values should be extracted from source code that takes this module - as a *direct* dependency. - defines: A list of defines that will be provided as `copts` to targets - that depend on this module. If omitted, the empty list will be used. - generated_header: A `File` representing the Swift generated header. - indexstore: A `File` representing the directory that contains the index - store data generated by the compiler if the - `"swift.index_while_building"` feature is enabled, otherwise this - will be `None`. - original_module_name: The original name of the module if it was changed - by a module mapping; otherwise, `None`. - plugins: A list of `SwiftCompilerPluginInfo` providers representing - compiler plugins that are required by this module and should be - loaded by the compiler when this module is directly depended on. - private_swiftinterface: The `.private.swiftinterface` file emitted by - the compiler for this module. May be `None` if no private module - interface file was emitted. - swiftdoc: The `.swiftdoc` file emitted by the compiler for this module. - swiftinterface: The `.swiftinterface` file emitted by the compiler for - this module. May be `None` if no module interface file was emitted. - swiftmodule: The `.swiftmodule` file emitted by the compiler for this - module. - swiftsourceinfo: The `.swiftsourceinfo` file emitted by the compiler for - this module. May be `None` if no source info file was emitted. - - Returns: - A `struct` containing the `ast_files`, `defines`, `indexstore, - `swiftdoc`, `swiftmodule`, and `swiftinterface` fields - provided as arguments. - """ - return struct( - ast_files = tuple(ast_files), - const_protocols_to_gather = tuple(const_protocols_to_gather), - defines = tuple(defines), - generated_header = generated_header, - indexstore = indexstore, - plugins = plugins, - private_swiftinterface = private_swiftinterface, - original_module_name = original_module_name, - swiftdoc = swiftdoc, - swiftinterface = swiftinterface, - swiftmodule = swiftmodule, - swiftsourceinfo = swiftsourceinfo, - ) - -def create_swift_info( - *, - direct_swift_infos = [], - modules = [], - swift_infos = []): - """Creates a new `SwiftInfo` provider with the given values. - - This function is recommended instead of directly creating a `SwiftInfo` - provider because it encodes reasonable defaults for fields that some rules - may not be interested in and ensures that the direct and transitive fields - are set consistently. - - This function can also be used to do a simple merge of `SwiftInfo` - providers, by leaving the `modules` argument unspecified. In that case, the - returned provider will not represent a true Swift module; it is merely a - "collector" for other dependencies. - - Args: - direct_swift_infos: A list of `SwiftInfo` providers from dependencies - whose direct modules should be treated as direct modules in the - resulting provider, in addition to their transitive modules being - merged. - modules: A list of values (as returned by `swift_common.create_module`) - that represent Clang and/or Swift module artifacts that are direct - outputs of the target being built. - swift_infos: A list of `SwiftInfo` providers from dependencies whose - transitive modules should be merged into the resulting provider. - - Returns: - A new `SwiftInfo` provider with the given values. - """ - - direct_modules = modules + [ - module - for provider in direct_swift_infos - for module in provider.direct_modules - ] - transitive_modules = [ - provider.transitive_modules - for provider in direct_swift_infos + swift_infos - ] - - return SwiftInfo( - direct_modules = direct_modules, - transitive_modules = depset( - direct_modules, - transitive = transitive_modules, - ), - ) diff --git a/swift/internal/symbol_graph_extracting.bzl b/swift/internal/symbol_graph_extracting.bzl index 1caabe25b..07ae5d1ff 100644 --- a/swift/internal/symbol_graph_extracting.bzl +++ b/swift/internal/symbol_graph_extracting.bzl @@ -14,9 +14,9 @@ """Functions relating to symbol graph extraction.""" +load("//swift:providers.bzl", "SwiftInfo") load(":action_names.bzl", "SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT") load(":actions.bzl", "run_toolchain_action") -load(":providers.bzl", "create_swift_info") load(":utils.bzl", "merge_compilation_contexts") def extract_symbol_graph( @@ -69,7 +69,7 @@ def extract_symbol_graph( for cc_info in swift_toolchain.implicit_deps_providers.cc_infos ], ) - merged_swift_info = create_swift_info( + merged_swift_info = SwiftInfo( swift_infos = ( swift_infos + swift_toolchain.implicit_deps_providers.swift_infos ), diff --git a/swift/providers.bzl b/swift/providers.bzl index 91f48a82a..4445b3466 100644 --- a/swift/providers.bzl +++ b/swift/providers.bzl @@ -12,7 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Defines Starlark providers that propagated by the Swift BUILD rules.""" +"""Defines providers propagated by the Swift BUILD rules and related utilities. + +This file must be kept lightweight and not load any other `.bzl` files that may +update frequently (e.g., other files in rules_swift). This ensures that changes +to the rule implementations do not unnecessarily cause reanalysis impacting +users who just load these providers to inspect and/or repropagate them. +""" SwiftCompilerPluginInfo = provider( doc = "Information about compiler plugins, like macros.", @@ -62,26 +68,71 @@ the allowlist. }, ) -SwiftInfo = provider( +def _swift_info_init( + *, + direct_swift_infos = [], + modules = [], + swift_infos = []): + direct_modules = modules + [ + module + for provider in direct_swift_infos + for module in provider.direct_modules + ] + transitive_modules = [ + provider.transitive_modules + for provider in direct_swift_infos + swift_infos + ] + + return { + "direct_modules": direct_modules, + "transitive_modules": depset( + direct_modules, + transitive = transitive_modules, + ), + } + +SwiftInfo, _create_raw_swift_info = provider( doc = """\ Contains information about the compiled artifacts of a Swift module. -This provider contains a large number of fields and many custom rules may not -need to set all of them. Instead of constructing a `SwiftInfo` provider -directly, consider using the `swift_common.create_swift_info` function, which -has reasonable defaults for any fields not explicitly set. +This provider has a custom initializer that will merge the transitive modules of +a list of `SwiftInfo` providers, rather than a separate "merge" function. The +correct signature when _creating_ a new `SwiftInfo` provider is the following: + +```build +SwiftInfo( + direct_swift_infos, + modules, + swift_infos, +) +``` + +where the arguments are: + +* `direct_swift_infos`: A list of `SwiftInfo` providers from dependencies + whose direct modules should be treated as direct modules in the resulting + provider, in addition to their transitive modules being merged. +* `modules`: A list of values (as returned by `create_swift_module_context`) + that represent Clang and/or Swift module artifacts that are direct outputs + of the target being built. +* `swift_infos`: A list of `SwiftInfo` providers from dependencies whose + transitive modules should be merged into the resulting provider. + +When reading an existing `SwiftInfo` provider, it has the two fields described +below. """, fields = { "direct_modules": """\ -`List` of values returned from `swift_common.create_module`. The modules (both +`List` of values returned from `create_swift_module_context`. The modules (both Swift and C/Objective-C) emitted by the library that propagated this provider. """, "transitive_modules": """\ -`Depset` of values returned from `swift_common.create_module`. The transitive +`Depset` of values returned from `create_swift_module_context`. The transitive modules (both Swift and C/Objective-C) emitted by the library that propagated this provider and all of its dependencies. """, }, + init = _swift_info_init, ) SwiftPackageConfigurationInfo = provider( @@ -345,3 +396,176 @@ Swift build rules, and they are also passed to the C++ APIs used when linking """, }, ) + +def create_swift_module_context( + *, + name, + clang = None, + const_gather_protocols = [], + compilation_context = None, + is_system = False, + swift = None): + """Creates a value containing Clang/Swift module artifacts of a dependency. + + It is possible for both `clang` and `swift` to be present; this is the case + for Swift modules that generate an Objective-C header, where the Swift + module artifacts are propagated in the `swift` context and the generated + header and module map are propagated in the `clang` context. + + Though rare, it is also permitted for both the `clang` and `swift` arguments + to be `None`. One example of how this can be used is to model system + dependencies (like Apple SDK frameworks) that are implicitly available as + part of a non-hermetic SDK (Xcode) but do not propagate any artifacts of + their own. This would only apply in a build using implicit modules, however; + when using explicit modules, one would propagate the module artifacts + explicitly. But allowing for the empty case keeps the build graph consistent + if switching between the two modes is necessary, since it will not change + the set of transitive module names that are propagated by dependencies + (which other build rules may want to depend on for their own analysis). + + Args: + name: The name of the module. + clang: A value returned by `create_clang_module_inputs` that + contains artifacts related to Clang modules, such as a module map or + precompiled module. This may be `None` if the module is a pure Swift + module with no generated Objective-C interface. + const_gather_protocols: A list of protocol names from which constant + values should be extracted from source code that takes this module + as a *direct* dependency. + compilation_context: A value returned from + `swift_common.create_compilation_context` that contains the + context needed to compile the module being built. This may be `None` + if the module wasn't compiled from sources. + is_system: Indicates whether the module is a system module. The default + value is `False`. System modules differ slightly from non-system + modules in the way that they are passed to the compiler. For + example, non-system modules have their Clang module maps passed to + the compiler in both implicit and explicit module builds. System + modules, on the other hand, do not have their module maps passed to + the compiler in implicit module builds because there is currently no + way to indicate that modules declared in a file passed via + `-fmodule-map-file` should be treated as system modules even if they + aren't declared with the `[system]` attribute, and some system + modules may not build cleanly with respect to warnings otherwise. + Therefore, it is assumed that any module with `is_system == True` + must be able to be found using import search paths in order for + implicit module builds to succeed. + swift: A value returned by `create_swift_module_inputs` that + contains artifacts related to Swift modules, such as the + `.swiftmodule`, `.swiftdoc`, and/or `.swiftinterface` files emitted + by the compiler. This may be `None` if the module is a pure + C/Objective-C module. + + Returns: + A `struct` containing the given values provided as arguments. + """ + return struct( + clang = clang, + const_gather_protocols = tuple(const_gather_protocols), + compilation_context = compilation_context, + is_system = is_system, + name = name, + swift = swift, + ) + +def create_clang_module_inputs( + *, + compilation_context, + module_map, + precompiled_module = None, + strict_includes = None): + """Creates a value representing a Clang module used as a Swift dependency. + + Args: + compilation_context: A `CcCompilationContext` that contains the header + files and other context (such as include paths, preprocessor + defines, and so forth) needed to compile this module as an explicit + module. + module_map: The text module map file that defines this module. This + argument may be specified as a `File` or as a `string`; in the + latter case, it is assumed to be the path to a file that cannot + be provided as an action input because it is outside the workspace + (for example, the module map for a module from an Xcode SDK). + precompiled_module: A `File` representing the precompiled module (`.pcm` + file) if one was emitted for the module. This may be `None` if no + explicit module was built for the module; in that case, targets that + depend on the module will fall back to the text module map and + headers. + strict_includes: A `depset` of strings representing additional Clang + include paths that should be passed to the compiler when this module + is a _direct_ dependency of the module being compiled. May be + `None`. **This field only exists to support a specific legacy use + case and should otherwise not be used, as it is fundamentally + incompatible with Swift's import model.** + + Returns: + A `struct` containing the values provided as arguments. + """ + return struct( + compilation_context = compilation_context, + module_map = module_map, + precompiled_module = precompiled_module, + strict_includes = strict_includes, + ) + +def create_swift_module_inputs( + *, + ast_files = [], + const_protocols_to_gather = [], + defines = [], + generated_header = None, + indexstore = None, + original_module_name = None, + plugins = [], + private_swiftinterface = None, + swiftdoc, + swiftinterface = None, + swiftmodule, + swiftsourceinfo = None): + """Creates a value representing a Swift module use as a Swift dependency. + + Args: + ast_files: A list of `File`s output from the `DUMP_AST` action. + const_protocols_to_gather: A list of protocol names from which constant + values should be extracted from source code that takes this module + as a *direct* dependency. + defines: A list of defines that will be provided as `copts` to targets + that depend on this module. If omitted, the empty list will be used. + generated_header: A `File` representing the Swift generated header. + indexstore: A `File` representing the directory that contains the index + store data generated by the compiler if the + `"swift.index_while_building"` feature is enabled, otherwise this + will be `None`. + original_module_name: The original name of the module if it was changed + by a module mapping; otherwise, `None`. + plugins: A list of `SwiftCompilerPluginInfo` providers representing + compiler plugins that are required by this module and should be + loaded by the compiler when this module is directly depended on. + private_swiftinterface: The `.private.swiftinterface` file emitted by + the compiler for this module. May be `None` if no private module + interface file was emitted. + swiftdoc: The `.swiftdoc` file emitted by the compiler for this module. + swiftinterface: The `.swiftinterface` file emitted by the compiler for + this module. May be `None` if no module interface file was emitted. + swiftmodule: The `.swiftmodule` file emitted by the compiler for this + module. + swiftsourceinfo: The `.swiftsourceinfo` file emitted by the compiler for + this module. May be `None` if no source info file was emitted. + + Returns: + A `struct` containing the values provided as arguments. + """ + return struct( + ast_files = tuple(ast_files), + const_protocols_to_gather = tuple(const_protocols_to_gather), + defines = tuple(defines), + generated_header = generated_header, + indexstore = indexstore, + plugins = tuple(plugins), + private_swiftinterface = private_swiftinterface, + original_module_name = original_module_name, + swiftdoc = swiftdoc, + swiftinterface = swiftinterface, + swiftmodule = swiftmodule, + swiftsourceinfo = swiftsourceinfo, + ) diff --git a/swift/swift_binary.bzl b/swift/swift_binary.bzl index a6bd99d4b..70f831aee 100644 --- a/swift/swift_binary.bzl +++ b/swift/swift_binary.bzl @@ -38,7 +38,12 @@ load( "include_developer_search_paths", ) load(":module_name.bzl", "derive_swift_module_name") -load(":providers.bzl", "SwiftCompilerPluginInfo", "SwiftInfo") +load( + ":providers.bzl", + "SwiftCompilerPluginInfo", + "SwiftInfo", + "create_swift_module_context", +) load(":swift_common.bzl", "swift_common") def _maybe_parse_as_library_copts(srcs): @@ -171,9 +176,9 @@ def _swift_binary_impl(ctx): ), ), OutputGroupInfo(**output_groups), - swift_common.create_swift_info( + SwiftInfo( modules = [ - swift_common.create_module( + create_swift_module_context( name = module_context.name, compilation_context = module_context.compilation_context, # The rest of the fields are intentionally ommited, as we diff --git a/swift/swift_clang_module_aspect.bzl b/swift/swift_clang_module_aspect.bzl index 8b477d1a9..9a1e51d11 100644 --- a/swift/swift_clang_module_aspect.bzl +++ b/swift/swift_clang_module_aspect.bzl @@ -31,12 +31,6 @@ load( "is_feature_enabled", ) load("//swift/internal:module_maps.bzl", "write_module_map") -load( - "//swift/internal:providers.bzl", - "create_clang_module", - "create_module", - "create_swift_info", -) load( "//swift/internal:swift_interop_info.bzl", "SwiftInteropInfo", @@ -51,7 +45,12 @@ load( "compilation_context_for_explicit_module_compilation", ) load(":module_name.bzl", "derive_swift_module_name") -load(":providers.bzl", "SwiftInfo") +load( + ":providers.bzl", + "SwiftInfo", + "create_clang_module_inputs", + "create_swift_module_context", +) _MULTIPLE_TARGET_ASPECT_ATTRS = [ "deps", @@ -448,7 +447,7 @@ def _handle_module( if not module_map_file: if all_swift_infos: return [ - create_swift_info( + SwiftInfo( direct_swift_infos = direct_swift_infos, swift_infos = swift_infos, ), @@ -514,11 +513,11 @@ def _handle_module( indexstore_directory = getattr(pcm_outputs, "indexstore_directory", None) providers = [ - create_swift_info( + SwiftInfo( modules = [ - create_module( + create_swift_module_context( name = module_name, - clang = create_clang_module( + clang = create_clang_module_inputs( compilation_context = compilation_context, module_map = module_map_file, precompiled_module = precompiled_module, @@ -737,7 +736,7 @@ def _swift_clang_module_aspect_impl(target, aspect_ctx): # If it's any other rule, just merge the `SwiftInfo` providers from its # deps. if direct_swift_infos or swift_infos: - return [create_swift_info( + return [SwiftInfo( direct_swift_infos = direct_swift_infos, swift_infos = swift_infos, )] diff --git a/swift/swift_common.bzl b/swift/swift_common.bzl index f37d6d145..5d273c340 100644 --- a/swift/swift_common.bzl +++ b/swift/swift_common.bzl @@ -43,13 +43,6 @@ load( "//swift/internal:linking.bzl", "create_linking_context_from_compilation_outputs", ) -load( - "//swift/internal:providers.bzl", - "create_clang_module", - "create_module", - "create_swift_info", - "create_swift_module", -) load("//swift/internal:swift_interop_info.bzl", "create_swift_interop_info") load( "//swift/internal:symbol_graph_extracting.bzl", @@ -61,6 +54,13 @@ load( "use_swift_toolchain", ) load(":module_name.bzl", "derive_swift_module_name") +load( + ":providers.bzl", + "SwiftInfo", + "create_clang_module_inputs", + "create_swift_module_context", + "create_swift_module_inputs", +) # The exported `swift_common` module, which defines the public API for directly # invoking actions that compile Swift code from other rules. @@ -70,13 +70,21 @@ swift_common = struct( compile = compile, compile_module_interface = compile_module_interface, configure_features = configure_features, - create_clang_module = create_clang_module, + # TODO(b/261445197): Remove this after everyone is migrated to the free + # function. + create_clang_module = create_clang_module_inputs, create_compilation_context = create_compilation_context, create_linking_context_from_compilation_outputs = create_linking_context_from_compilation_outputs, - create_module = create_module, - create_swift_info = create_swift_info, + # TODO(b/261445197): Remove this after everyone is migrated to the free + # function. + create_module = create_swift_module_context, + # TODO(b/261445197): Remove this after everyone is migrated to the free + # function. + create_swift_info = SwiftInfo, create_swift_interop_info = create_swift_interop_info, - create_swift_module = create_swift_module, + # TODO(b/261445197): Remove this after everyone is migrated to the free + # function. + create_swift_module = create_swift_module_inputs, # TODO(b/261444771): Remove this after everyone is migrated to the free # function. derive_module_name = derive_swift_module_name, diff --git a/swift/swift_compiler_plugin.bzl b/swift/swift_compiler_plugin.bzl index 7997b8d9f..341119113 100644 --- a/swift/swift_compiler_plugin.bzl +++ b/swift/swift_compiler_plugin.bzl @@ -183,7 +183,7 @@ def _swift_compiler_plugin_impl(ctx): ), executable = binary_linking_outputs.executable, module_names = depset([module_name]), - swift_info = swift_common.create_swift_info( + swift_info = SwiftInfo( modules = [module_context], ), ), @@ -316,7 +316,7 @@ def _universal_swift_compiler_plugin_impl(ctx): cc_info = cc_common.merge_cc_infos(cc_infos = cc_infos), executable = output, module_names = depset([module_name]), - swift_info = swift_common.create_swift_info( + swift_info = SwiftInfo( modules = direct_swift_modules, swift_infos = swift_infos, ), diff --git a/swift/swift_import.bzl b/swift/swift_import.bzl index 028301b32..3b48ee904 100644 --- a/swift/swift_import.bzl +++ b/swift/swift_import.bzl @@ -28,7 +28,13 @@ load( "get_compilation_contexts", "get_providers", ) -load(":providers.bzl", "SwiftInfo") +load( + ":providers.bzl", + "SwiftInfo", + "create_clang_module_inputs", + "create_swift_module_context", + "create_swift_module_inputs", +) load(":swift_common.bzl", "swift_common") def _swift_import_impl(ctx): @@ -103,13 +109,13 @@ def _swift_import_impl(ctx): module_context.swift.swiftmodule, ] + compact([module_context.swift.swiftdoc]) else: - module_context = swift_common.create_module( + module_context = create_swift_module_context( name = ctx.attr.module_name, - clang = swift_common.create_clang_module( + clang = create_clang_module_inputs( compilation_context = cc_info.compilation_context, module_map = None, ), - swift = swift_common.create_swift_module( + swift = create_swift_module_inputs( swiftdoc = swiftdoc, swiftmodule = swiftmodule, ), @@ -140,7 +146,7 @@ def _swift_import_impl(ctx): module_context = module_context, swift_toolchain = swift_toolchain, ), - swift_common.create_swift_info( + SwiftInfo( modules = [module_context], swift_infos = swift_infos, ), diff --git a/swift/swift_library.bzl b/swift/swift_library.bzl index fc9e67dae..867807b3e 100644 --- a/swift/swift_library.bzl +++ b/swift/swift_library.bzl @@ -259,7 +259,7 @@ def _swift_library_impl(ctx): extensions = ["swift"], source_attributes = ["srcs"], ), - swift_common.create_swift_info( + SwiftInfo( modules = [module_context], # Note that private_deps are explicitly omitted here; they should # not propagate. diff --git a/swift/swift_library_group.bzl b/swift/swift_library_group.bzl index e99ddebd7..2d3d7b79f 100644 --- a/swift/swift_library_group.bzl +++ b/swift/swift_library_group.bzl @@ -15,7 +15,6 @@ """Implementation of the `swift_library_group` rule.""" load("//swift/internal:attrs.bzl", "swift_deps_attr") -load("//swift/internal:providers.bzl", "create_swift_info") load("//swift/internal:utils.bzl", "get_providers") load(":providers.bzl", "SwiftInfo") load(":swift_clang_module_aspect.bzl", "swift_clang_module_aspect") @@ -32,7 +31,7 @@ def _swift_library_group_impl(ctx): ctx, dependency_attributes = ["deps"], ), - create_swift_info( + SwiftInfo( swift_infos = get_providers(deps, SwiftInfo), ), # Propagate an `apple_common.Objc` provider with linking info about the diff --git a/swift/swift_module_alias.bzl b/swift/swift_module_alias.bzl index a83ec38a7..d48ba20b2 100644 --- a/swift/swift_module_alias.bzl +++ b/swift/swift_module_alias.bzl @@ -119,7 +119,7 @@ def _swift_module_alias_impl(ctx): compilation_context = module_context.clang.compilation_context, linking_context = linking_context, ), - swift_common.create_swift_info( + SwiftInfo( modules = [module_context], swift_infos = swift_infos, ), diff --git a/swift/swift_test.bzl b/swift/swift_test.bzl index b596cb552..c4fe1c34e 100644 --- a/swift/swift_test.bzl +++ b/swift/swift_test.bzl @@ -49,6 +49,7 @@ load( "SwiftCompilerPluginInfo", "SwiftInfo", "SwiftSymbolGraphInfo", + "create_swift_module_context", ) load(":swift_common.bzl", "swift_common") @@ -428,7 +429,7 @@ def _swift_test_impl(ctx): compilation_outputs = compile_result.compilation_outputs all_supplemental_outputs.append(compile_result.supplemental_outputs) - swift_infos_including_owner = [swift_common.create_swift_info( + swift_infos_including_owner = [SwiftInfo( modules = [compile_result.module_context], swift_infos = deps_swift_infos, )] @@ -590,9 +591,9 @@ def _swift_test_impl(ctx): extensions = ["swift"], source_attributes = ["srcs"], ), - swift_common.create_swift_info( + SwiftInfo( modules = [ - swift_common.create_module( + create_swift_module_context( name = module_context.name, compilation_context = module_context.compilation_context, # The rest of the fields are intentionally ommited, as we diff --git a/swift/toolchains/config/compile_config.bzl b/swift/toolchains/config/compile_config.bzl index 7bee390a7..7a7ccc2c4 100644 --- a/swift/toolchains/config/compile_config.bzl +++ b/swift/toolchains/config/compile_config.bzl @@ -1436,7 +1436,7 @@ def _collect_clang_module_inputs( explicit module compilation action. This parameter should be `None` if inputs are being collected for Swift compilation. modules: A list of module structures (as returned by - `swift_common.create_module`). The precompiled Clang modules or the + `create_swift_module_context`). The precompiled Clang modules or the textual module maps and headers of these modules (depending on the value of `prefer_precompiled_modules`) will be collected as inputs. prefer_precompiled_modules: If True, precompiled module artifacts should @@ -1511,7 +1511,7 @@ def _clang_modulemap_dependency_args(module, ignore_system = True): Args: module: A struct containing information about the module, as defined by - `swift_common.create_module`. + `create_swift_module_context`. ignore_system: If `True` and the module is a system module, no flag should be returned. Defaults to `True`. @@ -1542,7 +1542,7 @@ def _clang_module_dependency_args(module): Args: module: A struct containing information about the module, as defined by - `swift_common.create_module`. + `create_swift_module_context`. Returns: A list of arguments, possibly empty, to pass to `swiftc` (without the @@ -1714,7 +1714,7 @@ def _swift_module_search_path_map_fn(module): Args: module: The module structure (as returned by - `swift_common.create_module`) extracted from the transitive + `create_swift_module_context`) extracted from the transitive modules of a `SwiftInfo` provider. Returns: @@ -1755,7 +1755,7 @@ def _module_alias_map_fn(module): Args: module: The module structure (as returned by - `swift_common.create_module`) extracted from the transitive + `create_swift_module_context`) extracted from the transitive modules of a `SwiftInfo` provider. Returns: