diff --git a/doc/api.md b/doc/api.md index 756be148a..0054bfc2c 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 @@ -28,6 +73,59 @@ A C++ `FeatureConfiguration` value (see for more information). + + +## swift_common.compilation_attrs + +
+swift_common.compilation_attrs(additional_deps_aspects, additional_deps_providers,
+                               include_dev_srch_paths_attrib, requires_srcs)
+
+ +Returns an attribute dictionary for rules that compile Swift code. + +The returned dictionary contains the subset of attributes that are shared by +the `swift_binary`, `swift_library`, and `swift_test` rules that deal with +inputs and options for compilation. Users who are authoring custom rules +that compile Swift code but not as a library can add this dictionary to +their own rule's attributes to give it a familiar API. + +Do note, however, that it is the responsibility of the rule implementation +to retrieve the values of those attributes and pass them correctly to the +other `swift_common` APIs. + +There is a hierarchy to the attribute sets offered by the `swift_common` +API: + +1. If you only need access to the toolchain for its tools and libraries but + are not doing any compilation, use `toolchain_attrs`. +2. If you need to invoke compilation actions but are not making the + resulting object files into a static or shared library, use + `compilation_attrs`. +3. If you want to provide a rule interface that is suitable as a drop-in + replacement for `swift_library`, use `library_rule_attrs`. + +Each of the attribute functions in the list above also contains the +attributes from the earlier items in the list. + + +**PARAMETERS** + + +| Name | Description | Default Value | +| :------------- | :------------- | :------------- | +| additional_deps_aspects | A list of additional aspects that should be applied to `deps`. Defaults to the empty list. These must be passed by the individual rules to avoid potential circular dependencies between the API and the aspects; the API loaded the aspects directly, then those aspects would not be able to load the API. | `[]` | +| additional_deps_providers | A list of lists representing additional providers that should be allowed by the `deps` attribute of the rule. | `[]` | +| include_dev_srch_paths_attrib | A `bool` that indicates whether to include the `always_include_developer_search_paths` attribute. | `False` | +| requires_srcs | Indicates whether the `srcs` attribute should be marked as mandatory and non-empty. Defaults to `True`. | `True` | + +**RETURNS** + +A new attribute dictionary that can be added to the attributes of a + custom build rule to provide a similar interface to `swift_binary`, + `swift_library`, and `swift_test`. + + ## swift_common.compile @@ -187,6 +285,32 @@ An opaque value representing the feature configuration that can be this value should otherwise not be relied on or inspected directly. + + +## swift_common.create_clang_module + +
+swift_common.create_clang_module(compilation_context, module_map, precompiled_module,
+                                 strict_includes)
+
+ +Creates a value representing a Clang module used as a Swift dependency. + +**PARAMETERS** + + +| Name | Description | Default Value | +| :------------- | :------------- | :------------- | +| 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. | none | +| 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). | none | +| 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. | `None` | +| 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.** | `None` | + +**RETURNS** + +A `struct` containing the values provided as arguments. + + ## swift_common.create_compilation_context @@ -269,6 +393,186 @@ A tuple of `(CcLinkingContext, CcLinkingOutputs)` containing the linking artifact representing the library that was linked, respectively. + + +## swift_common.create_module + +
+swift_common.create_module(name, clang, const_gather_protocols, compilation_context, is_framework,
+                           is_system, swift)
+
+ +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). + + +**PARAMETERS** + + +| Name | Description | Default Value | +| :------------- | :------------- | :------------- | +| name | The name of the module. | 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_framework | Indictates whether the module is a framework module. The default value is `False`. | `False` | +| 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 `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 `struct` containing the given values provided as arguments. + + + + +## swift_common.create_swift_interop_info + +
+swift_common.create_swift_interop_info(exclude_headers, module_map, module_name, requested_features,
+                                       suppressed, swift_infos, unsupported_features)
+
+ +Returns a provider that lets a target expose C/Objective-C APIs to Swift. + +The provider returned by this function allows custom build rules written in +Starlark to be uninvolved with much of the low-level machinery involved in +making a Swift-compatible module. Such a target should propagate a `CcInfo` +provider whose compilation context contains the headers that it wants to +make into a module, and then also propagate the provider returned from this +function. + +The simplest usage is for a custom rule to do the following: + +* Add `swift_clang_module_aspect` to any attribute that provides + dependencies of the code that needs to interop with Swift (typically + `deps`, but could be other attributes as well, such as attributes + providing additional support libraries). +* Have the rule implementation call `create_swift_interop_info`, passing + it only the list of `SwiftInfo` providers from its dependencies. This + tells `swift_clang_module_aspect` when it runs on *this* rule's target + to derive the module name from the target label and create a module map + using the headers from the compilation context of the `CcInfo` you + propagate. + +If the custom rule has reason to provide its own module name or module map, +then it can do so using the `module_name` and `module_map` arguments. + +When a rule returns this provider, it must provide the full set of +`SwiftInfo` providers from dependencies that will be merged with the one +that `swift_clang_module_aspect` creates for the target itself. The aspect +will **not** collect dependency providers automatically. This allows the +rule to not only add extra dependencies (such as support libraries from +implicit attributes) but also to exclude dependencies if necessary. + + +**PARAMETERS** + + +| Name | Description | Default Value | +| :------------- | :------------- | :------------- | +| exclude_headers | A `list` of `File`s representing headers that should be excluded from the module if the module map is generated. | `[]` | +| module_map | A `File` representing an existing module map that should be used to represent the module, or `None` (the default) if the module map should be generated based on the headers in the target's compilation context. If this argument is provided, then `module_name` must also be provided. | `None` | +| module_name | A string denoting the name of the module, or `None` (the default) if the name should be derived automatically from the target label. | `None` | +| requested_features | A list of features (empty by default) that should be requested for the target, which are added to those supplied in the `features` attribute of the target. These features will be enabled unless they are otherwise marked as unsupported (either on the target or by the toolchain). This allows the rule implementation to have additional control over features that should be supported by default for all instances of that rule as if it were creating the feature configuration itself; for example, a rule can request that `swift.emit_c_module` always be enabled for its targets even if it is not explicitly enabled in the toolchain or on the target directly. | `[]` | +| suppressed | A `bool` indicating whether the module that the aspect would create for the target should instead be suppressed. | `False` | +| swift_infos | A list of `SwiftInfo` providers from dependencies, which will be merged with the new `SwiftInfo` created by the aspect. | `[]` | +| unsupported_features | A list of features (empty by default) that should be considered unsupported for the target, which are added to those supplied as negations in the `features` attribute. This allows the rule implementation to have additional control over features that should be disabled by default for all instances of that rule as if it were creating the feature configuration itself; for example, a rule that processes frameworks with headers that do not follow strict layering can request that `swift.strict_module` always be disabled for its targets even if it is enabled by default in the toolchain. | `[]` | + +**RETURNS** + +A provider whose type/layout is an implementation detail and should not + be relied upon. + + + + +## swift_common.create_swift_module + +
+swift_common.create_swift_module(ast_files, const_protocols_to_gather, defines, generated_header,
+                                 indexstore, original_module_name, plugins, private_swiftinterface,
+                                 swiftdoc, swiftinterface, swiftmodule, swiftsourceinfo)
+
+ +Creates a value representing a Swift module use as a Swift dependency. + +**PARAMETERS** + + +| Name | Description | Default Value | +| :------------- | :------------- | :------------- | +| 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. | `None` | +| 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`. | `None` | +| original_module_name | The original name of the module if it was changed by a module mapping; otherwise, `None`. | `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. | `None` | +| swiftdoc | The `.swiftdoc` file emitted by the compiler for this module. | none | +| swiftinterface | The `.swiftinterface` file emitted by the compiler for this module. May be `None` if no module interface file was emitted. | `None` | +| swiftmodule | The `.swiftmodule` file emitted by the compiler for this module. | none | +| swiftsourceinfo | The `.swiftsourceinfo` file emitted by the compiler for this module. May be `None` if no source info file was emitted. | `None` | + +**RETURNS** + +A `struct` containing the values provided as arguments. + + + + +## swift_common.derive_module_name + +
+swift_common.derive_module_name(args)
+
+ +Returns a derived module name from the given build label. + +For targets whose module name is not explicitly specified, the module name +is computed using the following algorithm: + +* The package and name components of the label are considered separately. + All _interior_ sequences of non-identifier characters (anything other + than `a-z`, `A-Z`, `0-9`, and `_`) are replaced by a single underscore + (`_`). Any leading or trailing non-identifier characters are dropped. +* If the package component is non-empty after the above transformation, + it is joined with the transformed name component using an underscore. + Otherwise, the transformed name is used by itself. +* If this would result in a string that begins with a digit (`0-9`), an + underscore is prepended to make it identifier-safe. + +This mapping is intended to be fairly predictable, but not reversible. + + +**PARAMETERS** + + +| Name | Description | Default Value | +| :------------- | :------------- | :------------- | +| args | Either a single argument of type `Label`, or two arguments of type `str` where the first argument is the package name and the second argument is the target name. | none | + +**RETURNS** + +The module name derived from the label. + + ## swift_common.extract_symbol_graph @@ -352,6 +656,57 @@ check it. `True` if the given feature is enabled in the feature configuration. + + +## swift_common.library_rule_attrs + +
+swift_common.library_rule_attrs(additional_deps_aspects, requires_srcs)
+
+ +Returns an attribute dictionary for `swift_library`-like rules. + +The returned dictionary contains the same attributes that are defined by the +`swift_library` rule (including the private `_toolchain` attribute that +specifies the toolchain dependency). Users who are authoring custom rules +can use this dictionary verbatim or add other custom attributes to it in +order to make their rule a drop-in replacement for `swift_library` (for +example, if writing a custom rule that does some preprocessing or generation +of sources and then compiles them). + +Do note, however, that it is the responsibility of the rule implementation +to retrieve the values of those attributes and pass them correctly to the +other `swift_common` APIs. + +There is a hierarchy to the attribute sets offered by the `swift_common` +API: + +1. If you only need access to the toolchain for its tools and libraries but + are not doing any compilation, use `toolchain_attrs`. +2. If you need to invoke compilation actions but are not making the + resulting object files into a static or shared library, use + `compilation_attrs`. +3. If you want to provide a rule interface that is suitable as a drop-in + replacement for `swift_library`, use `library_rule_attrs`. + +Each of the attribute functions in the list above also contains the +attributes from the earlier items in the list. + + +**PARAMETERS** + + +| Name | Description | Default Value | +| :------------- | :------------- | :------------- | +| additional_deps_aspects | A list of additional aspects that should be applied to `deps`. Defaults to the empty list. These must be passed by the individual rules to avoid potential circular dependencies between the API and the aspects; the API loaded the aspects directly, then those aspects would not be able to load the API. | `[]` | +| requires_srcs | Indicates whether the `srcs` attribute should be marked as mandatory and non-empty. Defaults to `True`. | `True` | + +**RETURNS** + +A new attribute dictionary that can be added to the attributes of a + custom build rule to provide the same interface as `swift_library`. + + ## swift_common.precompile_clang_module diff --git a/proto/BUILD b/proto/BUILD index 17555d5dc..9576bf187 100644 --- a/proto/BUILD +++ b/proto/BUILD @@ -35,6 +35,7 @@ bzl_library( ":swift_proto_utils", "//swift:module_name", "//swift:swift_clang_module_aspect", + "//swift:swift_common", "//swift/internal:attrs", "//swift/internal:toolchain_utils", "//swift/internal:utils", diff --git a/proto/swift_proto_library.bzl b/proto/swift_proto_library.bzl index c8bc6e047..f90fd600a 100644 --- a/proto/swift_proto_library.bzl +++ b/proto/swift_proto_library.bzl @@ -27,13 +27,10 @@ load( load("//swift:module_name.bzl", "derive_swift_module_name") load("//swift:providers.bzl", "SwiftProtoCompilerInfo") load("//swift:swift_clang_module_aspect.bzl", "swift_clang_module_aspect") +load("//swift:swift_common.bzl", "swift_common") # buildifier: disable=bzl-visibility -load( - "//swift/internal:attrs.bzl", - "swift_deps_attr", - "swift_library_rule_attrs", -) +load("//swift/internal:attrs.bzl", "swift_deps_attr") # buildifier: disable=bzl-visibility load("//swift/internal:toolchain_utils.bzl", "use_swift_toolchain") @@ -109,7 +106,7 @@ def _swift_proto_library_impl(ctx): swift_proto_library = rule( attrs = dicts.add( - swift_library_rule_attrs( + swift_common.library_rule_attrs( additional_deps_aspects = [ swift_clang_module_aspect, ], diff --git a/swift/BUILD b/swift/BUILD index 0239353f5..8925c515b 100644 --- a/swift/BUILD +++ b/swift/BUILD @@ -91,10 +91,14 @@ bzl_library( name = "swift_common", srcs = ["swift_common.bzl"], deps = [ + ":module_name", + ":providers", + ":swift_interop_info", "//swift/internal:attrs", "//swift/internal:compiling", "//swift/internal:features", "//swift/internal:linking", + "//swift/internal:swift_interop_info", "//swift/internal:symbol_graph_extracting", "//swift/internal:toolchain_utils", ], diff --git a/swift/swift_common.bzl b/swift/swift_common.bzl index aec38dd6b..8d95a3b96 100644 --- a/swift/swift_common.bzl +++ b/swift/swift_common.bzl @@ -20,7 +20,12 @@ example, `swift_proto_library` generates Swift source code from `.proto` files and then needs to compile them. This module provides that lower-level interface. """ -load("//swift/internal:attrs.bzl", "swift_toolchain_attrs") +load( + "//swift/internal:attrs.bzl", + "swift_compilation_attrs", + "swift_library_rule_attrs", + "swift_toolchain_attrs", +) load( "//swift/internal:compiling.bzl", "compile", @@ -47,19 +52,48 @@ load( "get_swift_toolchain", "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", +) +load(":swift_interop_info.bzl", "create_swift_interop_info") # The exported `swift_common` module, which defines the public API for directly # invoking actions that compile Swift code from other rules. swift_common = struct( cc_feature_configuration = get_cc_feature_configuration, + compilation_attrs = swift_compilation_attrs, compile = compile, compile_module_interface = compile_module_interface, configure_features = configure_features, + # 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, + # 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, + # TODO(b/261445197): Remove this after everyone is migrated to the free + # function. + create_swift_interop_info = create_swift_interop_info, + # 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, extract_symbol_graph = extract_symbol_graph, get_toolchain = get_swift_toolchain, is_enabled = is_feature_enabled, + library_rule_attrs = swift_library_rule_attrs, precompile_clang_module = precompile_clang_module, toolchain_attrs = swift_toolchain_attrs, use_toolchain = use_swift_toolchain,