From 616439c80e5006466020cd7d02041b08c477dbee Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Mon, 10 Aug 2020 18:26:30 -0700 Subject: [PATCH 001/152] Add .clang-format (#467) Fixes https://github.com/bazelbuild/rules_swift/issues/305 --- .clang-format | 1 + 1 file changed, 1 insertion(+) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..f6cb8ad93 --- /dev/null +++ b/.clang-format @@ -0,0 +1 @@ +BasedOnStyle: Google From b255732244abc7e264e0b484271c10bd8999acab Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Mon, 10 Aug 2020 18:31:23 -0700 Subject: [PATCH 002/152] Add error for no Linux swiftc path (#466) Fixes https://github.com/bazelbuild/rules_swift/issues/16 --- swift/internal/swift_autoconfiguration.bzl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/swift/internal/swift_autoconfiguration.bzl b/swift/internal/swift_autoconfiguration.bzl index 7ba611926..cc585ca46 100644 --- a/swift/internal/swift_autoconfiguration.bzl +++ b/swift/internal/swift_autoconfiguration.bzl @@ -203,6 +203,9 @@ def _create_linux_toolchain(repository_ctx): "in your environment before invoking Bazel.") path_to_swiftc = repository_ctx.which("swiftc") + if not path_to_swiftc: + fail("No 'swiftc' executable found in $PATH") + root = path_to_swiftc.dirname.dirname feature_values = _compute_feature_values(repository_ctx, path_to_swiftc) version_file = _write_swift_version(repository_ctx, path_to_swiftc) From d93238edd63e94d4cff169659142398fcf2551aa Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Tue, 11 Aug 2020 10:39:20 -0700 Subject: [PATCH 003/152] Update dump_toolchains to support home dir (#471) Before: ``` swift-DEVELOPMENT-SNAPSHOT-2020-01-29-a.xctoolchain -> org.swift.50202001291a swift-TEST-SNAPSHOT-2020-01-23-a.xctoolchain -> org.swift.50202001231a swift-latest.xctoolchain -> org.swift.50202001291a ``` After: ``` /Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2020-01-29-a.xctoolchain -> org.swift.50202001291a /Library/Developer/Toolchains/swift-TEST-SNAPSHOT-2020-01-23-a.xctoolchain -> org.swift.50202001231a /Library/Developer/Toolchains/swift-latest.xctoolchain -> org.swift.50202001291a /Users/ksmiley/Library/Developer/Toolchains/swift-5.2-DEVELOPMENT-SNAPSHOT-2020-04-28-a.xctoolchain -> org.swift.52202004281a /Users/ksmiley/Library/Developer/Toolchains/swift-latest.xctoolchain -> org.swift.52202004281a ``` --- tools/dump_toolchains/dump_toolchains.sh | 29 ++++++++++++------------ 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/tools/dump_toolchains/dump_toolchains.sh b/tools/dump_toolchains/dump_toolchains.sh index 18f008211..9a97fc793 100755 --- a/tools/dump_toolchains/dump_toolchains.sh +++ b/tools/dump_toolchains/dump_toolchains.sh @@ -21,22 +21,23 @@ if [[ "$(uname)" != Darwin ]]; then exit 1 fi -toolchain_directory=/Library/Developer/Toolchains -if [[ ! -d "$toolchain_directory" ]]; then - echo "error: '$toolchain_directory' doesn't exist" - exit 1 -fi +readonly toolchain_directories=( + /Library/Developer/Toolchains + ~/Library/Developer/Toolchains +) -for toolchain in "$toolchain_directory"/*.xctoolchain +for toolchain_directory in "${toolchain_directories[@]}" do - plist_path="$toolchain/Info.plist" + for toolchain in "$toolchain_directory"/*.xctoolchain + do + plist_path="$toolchain/Info.plist" - if [[ ! -f "$plist_path" ]]; then - echo "error: '$toolchain' is missing Info.plist" - exit 1 - fi + if [[ ! -f "$plist_path" ]]; then + echo "error: '$toolchain' is missing Info.plist" + exit 1 + fi - bundle_id=$(/usr/libexec/PlistBuddy -c "print :CFBundleIdentifier" "$plist_path") - toolchain_name=$(basename "$toolchain") - echo "$toolchain_name -> $bundle_id" + bundle_id=$(/usr/libexec/PlistBuddy -c "print :CFBundleIdentifier" "$plist_path") + echo "$toolchain -> $bundle_id" + done done From e87aace2ccacbefc274248d072724b7cec3f3713 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Tue, 11 Aug 2020 10:39:26 -0700 Subject: [PATCH 004/152] Run clang-format on everything (#470) --- examples/apple/objc_interop/OIPrintStream.h | 2 +- examples/xplatform/c_from_swift/c_counter.cc | 1 + tools/common/temp_file.h | 4 ++-- tools/worker/compile_with_worker.cc | 4 ++-- tools/worker/output_file_map.cc | 2 +- tools/worker/output_file_map.h | 3 +-- tools/worker/work_processor.cc | 4 ++-- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/apple/objc_interop/OIPrintStream.h b/examples/apple/objc_interop/OIPrintStream.h index ff79a7280..2873ba84f 100644 --- a/examples/apple/objc_interop/OIPrintStream.h +++ b/examples/apple/objc_interop/OIPrintStream.h @@ -15,7 +15,7 @@ #import /** A very contrived interface for writing strings to a file handle. */ -@interface OIPrintStream: NSObject +@interface OIPrintStream : NSObject - (nonnull instancetype)initWithFileHandle:(nonnull NSFileHandle *)fileHandle; diff --git a/examples/xplatform/c_from_swift/c_counter.cc b/examples/xplatform/c_from_swift/c_counter.cc index c8cb23819..e95a0b155 100644 --- a/examples/xplatform/c_from_swift/c_counter.cc +++ b/examples/xplatform/c_from_swift/c_counter.cc @@ -13,6 +13,7 @@ // limitations under the License. #include "examples/xplatform/c_from_swift/c_counter.h" + #include "examples/xplatform/c_from_swift/counter.h" using ::swiftexample::Counter; diff --git a/tools/common/temp_file.h b/tools/common/temp_file.h index 04d9f7029..1429a9de9 100644 --- a/tools/common/temp_file.h +++ b/tools/common/temp_file.h @@ -41,8 +41,8 @@ class TempFile { snprintf(path.get(), size, "%s/%s", tmpDir, path_template.c_str()); if (mkstemp(path.get()) == -1) { - std::cerr << "Failed to create temporary file '" << path.get() << "': " - << strerror(errno) << "\n"; + std::cerr << "Failed to create temporary file '" << path.get() + << "': " << strerror(errno) << "\n"; return nullptr; } return std::unique_ptr(new TempFile(path.get())); diff --git a/tools/worker/compile_with_worker.cc b/tools/worker/compile_with_worker.cc index e17288846..36f873787 100644 --- a/tools/worker/compile_with_worker.cc +++ b/tools/worker/compile_with_worker.cc @@ -14,12 +14,12 @@ #include "tools/worker/compile_with_worker.h" +#include +#include #include #include -#include -#include #include "third_party/bazel_protos/worker_protocol.pb.h" #include "tools/worker/work_processor.h" diff --git a/tools/worker/output_file_map.cc b/tools/worker/output_file_map.cc index a8649099d..57bb94807 100644 --- a/tools/worker/output_file_map.cc +++ b/tools/worker/output_file_map.cc @@ -17,10 +17,10 @@ #include #include #include +#include #include #include "tools/common/path_utils.h" -#include namespace { diff --git a/tools/worker/output_file_map.h b/tools/worker/output_file_map.h index a81907112..b52e7f601 100644 --- a/tools/worker/output_file_map.h +++ b/tools/worker/output_file_map.h @@ -16,9 +16,8 @@ #define BUILD_BAZEL_RULES_SWIFT_TOOLS_WORKER_OUTPUT_FILE_MAP_H #include -#include - #include +#include // Supports loading and rewriting a `swiftc` output file map to support // incremental compilation. diff --git a/tools/worker/work_processor.cc b/tools/worker/work_processor.cc index 2a91764b6..07857d352 100644 --- a/tools/worker/work_processor.cc +++ b/tools/worker/work_processor.cc @@ -14,21 +14,21 @@ #include "tools/worker/work_processor.h" +#include #include #include #include +#include #include #include -#include #include "tools/common/file_system.h" #include "tools/common/path_utils.h" #include "tools/common/string_utils.h" #include "tools/common/temp_file.h" #include "tools/worker/output_file_map.h" #include "tools/worker/swift_runner.h" -#include namespace { From fe0a8811e179e6721109577bc1ceb928f3454da8 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Tue, 11 Aug 2020 16:27:46 -0700 Subject: [PATCH 005/152] Update README instructions (#472) --- README.md | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index a98b0fcb2..9fce91f3a 100644 --- a/README.md +++ b/README.md @@ -47,23 +47,12 @@ replacing the `urls` and `sha256` attributes with the values from the release you wish to depend on: ```python -load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") -# rules_swift and apple_support no longer support releases. If you'd like to pin -# down these dependencies to a specific commit, please add the following to the -# top of your WORKSPACE, using the commit you'd like to pin for each of the -# repositories. -git_repository( +http_archive( name = "build_bazel_rules_swift", - remote = "https://github.com/bazelbuild/rules_swift.git", - commit = "[SOME_HASH_VALUE]", -) - -git_repository( - name = "build_bazel_apple_support", - remote = "https://github.com/bazelbuild/apple_support.git", - commit = "[SOME_HASH_VALUE]", + sha256 = "cea22c0616d797e494d7844a9b604520c87f53c81de49613a7e679ec5b821620", + url = "https://github.com/bazelbuild/rules_swift/releases/download/0.14.0/rules_swift.0.14.0.tar.gz", ) load( From 49de7e52e3ea6c01d903d6bb4395b9cef59dfa3b Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Thu, 6 Aug 2020 14:05:29 -0700 Subject: [PATCH 006/152] Ensure that `swift_module_alias` propagates instrumented file info from its dependencies, otherwise coverage data might get dropped. PiperOrigin-RevId: 325306099 --- swift/internal/swift_module_alias.bzl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/swift/internal/swift_module_alias.bzl b/swift/internal/swift_module_alias.bzl index 28eea793c..55a57bf7c 100644 --- a/swift/internal/swift_module_alias.bzl +++ b/swift/internal/swift_module_alias.bzl @@ -97,6 +97,10 @@ def _swift_module_alias_impl(ctx): OutputGroupInfo(**output_groups_from_compilation_outputs( compilation_outputs = compilation_outputs, )), + coverage_common.instrumented_files_info( + ctx, + dependency_attributes = ["deps"], + ), create_cc_info( cc_infos = get_providers(deps, CcInfo), compilation_outputs = compilation_outputs, From fc74b43fe1d2c93c79c0a277d3c2e56498a14e9f Mon Sep 17 00:00:00 2001 From: Michael Eisel Date: Thu, 13 Aug 2020 13:00:03 -0400 Subject: [PATCH 007/152] Allow generated headers with path separators (#439) Co-authored-by: Michael Eisel Co-authored-by: Keith Smiley --- swift/internal/compiling.bzl | 9 +-------- test/fixtures/generated_header/BUILD | 4 ++-- test/generated_header_tests.bzl | 15 ++++++++++----- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index 74d8307d6..023031c44 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -1588,8 +1588,7 @@ def _declare_multiple_outputs_and_write_output_file_map( def _declare_validated_generated_header(actions, generated_header_name): """Validates and declares the explicitly named generated header. - If the file does not have a `.h` extension or conatins path separators, the - build will fail. + If the file does not have a `.h` extension, the build will fail. Args: actions: The context's `actions` object. @@ -1598,12 +1597,6 @@ def _declare_validated_generated_header(actions, generated_header_name): Returns: A `File` that should be used as the output for the generated header. """ - if "/" in generated_header_name: - fail( - "The generated header for a Swift module may not contain " + - "directory components (got '{}').".format(generated_header_name), - ) - extension = paths.split_extension(generated_header_name)[1] if extension != ".h": fail( diff --git a/test/fixtures/generated_header/BUILD b/test/fixtures/generated_header/BUILD index 1263edd94..9e8fdc1b3 100644 --- a/test/fixtures/generated_header/BUILD +++ b/test/fixtures/generated_header/BUILD @@ -28,8 +28,8 @@ swift_library( ) swift_library( - name = "invalid_path_separator", + name = "valid_path_separator", srcs = ["Empty.swift"], - generated_header_name = "Invalid/Separator.h", + generated_header_name = "Valid/Separator.h", tags = FIXTURE_TAGS, ) diff --git a/test/generated_header_tests.bzl b/test/generated_header_tests.bzl index bd7ec4c4a..47bf7f8f5 100644 --- a/test/generated_header_tests.bzl +++ b/test/generated_header_tests.bzl @@ -121,12 +121,17 @@ def generated_header_test_suite(name = "generated_header"): target_under_test = "@build_bazel_rules_swift//test/fixtures/generated_header:invalid_extension", ) - # Verify that the build fails to analyze if a path separator is used. - generate_header_and_module_map_failure_test( - name = "{}_invalid_path_separator".format(name), - expected_message = "The generated header for a Swift module may not contain directory components", + # Verify that the build analyzes if a path separator is used. + generate_header_and_module_map_provider_test( + name = "{}_valid_path_separator".format(name), + expected_files = [ + "test/fixtures/generated_header/Valid/Separator.h", + "*", + ], + field = "files", + provider = "DefaultInfo", tags = [name], - target_under_test = "@build_bazel_rules_swift//test/fixtures/generated_header:invalid_path_separator", + target_under_test = "@build_bazel_rules_swift//test/fixtures/generated_header:valid_path_separator", ) # Verify that the header is not generated if the feature From 4bc7405f3b8b8163b83c49f358ce425fb54cedfc Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Thu, 13 Aug 2020 11:35:10 -0700 Subject: [PATCH 008/152] Delete CONTRIBUTORS (#475) This is outdated, best to look at the github insights tab --- CONTRIBUTORS | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 CONTRIBUTORS diff --git a/CONTRIBUTORS b/CONTRIBUTORS deleted file mode 100644 index a8d530dca..000000000 --- a/CONTRIBUTORS +++ /dev/null @@ -1,12 +0,0 @@ -# People who have agreed to one of the CLAs and can contribute patches. -# The AUTHORS file lists the copyright holders; this file -# lists people. For example, Google employees are listed here -# but not in AUTHORS, because Google holds the copyright. -# -# https://developers.google.com/open-source/cla/individual -# https://developers.google.com/open-source/cla/corporate -# -# Names should be added to this file as: -# Name - -Tony Allevato From 44e8c29afe3baa7f5fc434f4a7e83f7ac786644e Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Fri, 21 Aug 2020 17:41:48 -0700 Subject: [PATCH 009/152] Various changes related to explicit module compilation: (#477) * Add a feature to support compiling system modules with reduced diagnostic output. * Support system modules passed as path names (strings) instead of `File` artifacts. * Add the necessary tool config to support compiling explicit modules with Xcode 12 and higher (when the features are also enabled). * When compiling explicit modules, generate module maps for `objc_library` targets in the Swift rules instead of using the one propagated by `ObjcProvider` to ensure that `use` declarations for dependencies unknown to the native Bazel module map generation code are present. PiperOrigin-RevId: 327813526 Co-authored-by: Tony Allevato --- swift/internal/compiling.bzl | 89 ++++++++++++- swift/internal/feature_names.bzl | 8 ++ swift/internal/providers.bzl | 29 +++- swift/internal/swift_clang_module_aspect.bzl | 131 ++++++++++++++----- swift/internal/xcode_swift_toolchain.bzl | 55 +++++++- 5 files changed, 267 insertions(+), 45 deletions(-) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index 023031c44..13fb43cb3 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -51,7 +51,9 @@ load( "SWIFT_FEATURE_OPT", "SWIFT_FEATURE_OPT_USES_OSIZE", "SWIFT_FEATURE_OPT_USES_WMO", + "SWIFT_FEATURE_STRICT_MODULES", "SWIFT_FEATURE_SUPPORTS_LIBRARY_EVOLUTION", + "SWIFT_FEATURE_SYSTEM_MODULE", "SWIFT_FEATURE_USE_C_MODULES", "SWIFT_FEATURE_USE_GLOBAL_MODULE_CACHE", "SWIFT_FEATURE_VFSOVERLAY", @@ -362,6 +364,72 @@ def compile_action_configs(): features = [SWIFT_FEATURE_IMPLICIT_MODULES], not_features = [SWIFT_FEATURE_USE_GLOBAL_MODULE_CACHE], ), + swift_toolchain_config.action_config( + actions = [ + swift_action_names.COMPILE, + swift_action_names.PRECOMPILE_C_MODULE, + ], + configurators = [ + # If we're consuming explicit modules of C dependencies, disable + # all implicit module usage (both searching for module maps and + # implicit compilation) to ensure that all modules must be + # explicitly provided. + swift_toolchain_config.add_arg( + "-Xcc", + "-fno-implicit-modules", + ), + swift_toolchain_config.add_arg( + "-Xcc", + "-fno-implicit-module-maps", + ), + ], + features = [SWIFT_FEATURE_USE_C_MODULES], + ), + swift_toolchain_config.action_config( + actions = [swift_action_names.PRECOMPILE_C_MODULE], + configurators = [ + # Enforce `use` declarations for user modules since we generate + # those, but not for system modules since they typically do not + # have the proper `use` decls. + swift_toolchain_config.add_arg( + "-Xcc", + "-fmodules-decluse", + ), + ], + not_features = [ + [SWIFT_FEATURE_STRICT_MODULES], + [SWIFT_FEATURE_SYSTEM_MODULE], + ], + ), + swift_toolchain_config.action_config( + actions = [swift_action_names.PRECOMPILE_C_MODULE], + configurators = [ + swift_toolchain_config.add_arg( + "-Xcc", + "-fmodules-strict-decluse", + ), + ], + features = [SWIFT_FEATURE_STRICT_MODULES], + not_features = [SWIFT_FEATURE_SYSTEM_MODULE], + ), + swift_toolchain_config.action_config( + actions = [swift_action_names.PRECOMPILE_C_MODULE], + configurators = [ + # TODO(b/165649949): ClangImporter doesn't currently handle the + # IsSystem bit correctly for the input file, which causes the + # module map to be treated as a user input. To work around this + # for now, we disable all diagnostics when compiling the + # explicit module for system modules, since they're not useful + # anyway; this is "close enough" to compiling it as a system + # module for the purposes of avoiding noise in the build logs. + swift_toolchain_config.add_arg("-Xcc", "-w"), + swift_toolchain_config.add_arg( + "-Xcc", + "-Wno-nullability-declspec", + ), + ], + features = [SWIFT_FEATURE_SYSTEM_MODULE], + ), ] #### Search paths for Swift module dependencies @@ -709,7 +777,8 @@ def _collect_clang_module_inputs( # Add the module map, which we use for both implicit and explicit module # builds. For implicit module builds, we don't worry about the headers # above because we collect the full transitive header set below. - module_inputs.append(module_map) + if not types.is_string(module_map): + module_inputs.append(module_map) # If we prefer textual module maps and headers for the build, fall back to # using the full set of transitive headers. @@ -732,9 +801,15 @@ def _clang_modulemap_dependency_args(module): Returns: A list of arguments to pass to `swiftc`. """ + module_map = module.clang.module_map + if types.is_string(module_map): + module_map_path = module_map + else: + module_map_path = module_map.path + return [ "-Xcc", - "-fmodule-map-file={}".format(module.clang.module_map.path), + "-fmodule-map-file={}".format(module_map_path), ] def _clang_module_dependency_args(module): @@ -867,8 +942,16 @@ def _stats_output_dir_configurator(prerequisites, args): def _source_files_configurator(prerequisites, args): """Adds source files to the command line and required inputs.""" args.add_all(prerequisites.source_files) + + # Only add source files to the input file set if they are not strings (for + # example, the module map of a system framework will be passed in as a file + # path relative to the SDK root, not as a `File` object). return swift_toolchain_config.config_result( - inputs = prerequisites.source_files, + inputs = [ + source_file + for source_file in prerequisites.source_files + if not types.is_string(source_file) + ], ) def _user_compile_flags_configurator(prerequisites, args): diff --git a/swift/internal/feature_names.bzl b/swift/internal/feature_names.bzl index ee01a3e77..0885a19ee 100644 --- a/swift/internal/feature_names.bzl +++ b/swift/internal/feature_names.bzl @@ -67,6 +67,14 @@ SWIFT_FEATURE_DEBUG_PREFIX_MAP = "swift.debug_prefix_map" # graph. SWIFT_FEATURE_EMIT_C_MODULE = "swift.emit_c_module" +# If enabled, when compiling an explicit C or Objectve-C module, every header +# included by the module being compiled must belong to one of the modules listed +# in its dependencies. This is ignored for system modules. +SWIFT_FEATURE_STRICT_MODULES = "swift.strict_modules" + +# If enabled, the C or Objective-C target should be compiled as a system module. +SWIFT_FEATURE_SYSTEM_MODULE = "swift.system_module" + # If enabled, Swift compilation actions will use batch mode by passing # `-enable-batch-mode` to `swiftc`. This is a new compilation mode as of # Swift 4.2 that is intended to speed up non-incremental non-WMO builds by diff --git a/swift/internal/providers.bzl b/swift/internal/providers.bzl index fcfcaac7a..29bef0bc3 100644 --- a/swift/internal/providers.bzl +++ b/swift/internal/providers.bzl @@ -15,6 +15,7 @@ """Defines Starlark providers that propagated by the Swift BUILD rules.""" load("@bazel_skylib//lib:sets.bzl", "sets") +load("@bazel_skylib//lib:types.bzl", "types") SwiftInfo = provider( doc = """\ @@ -37,10 +38,14 @@ Swift and C/Objective-C) emitted by the library that propagated this provider. "direct_swiftdocs": """\ `List` of `File`s. The Swift documentation (`.swiftdoc`) files for the library that directly propagated this provider. + +This field is deprecated; use `direct_modules` instead. """, "direct_swiftmodules": """\ `List` of `File`s. The Swift modules (`.swiftmodule`) for the library that directly propagated this provider. + +This field is deprecated; use `direct_modules` instead. """, "module_name": """\ `String`. The name of the Swift module represented by the target that directly @@ -48,11 +53,16 @@ propagated this provider. This field will be equal to the explicitly assigned module name (if present); otherwise, it will be equal to the autogenerated module name. + +This field is deprecated; use `direct_modules` instead. """, "swift_version": """\ `String`. The version of the Swift language that was used when compiling the propagating target; that is, the value passed via the `-swift-version` compiler flag. This will be `None` if the flag was not set. + +This field is deprecated; the Swift version should be obtained by inspecting the +arguments passed to specific compilation actions. """, "transitive_defines": """\ `Depset` of `string`s. The transitive `defines` specified for the library that @@ -77,15 +87,21 @@ this provider and all of its dependencies. `Depset` of `File`s. The transitive Swift documentation (`.swiftdoc`) files emitted by the library that propagated this provider and all of its dependencies. + +This field is deprecated; use `transitive_modules` instead. """, "transitive_swiftinterfaces": """\ `Depset` of `File`s. The transitive Swift interface (`.swiftinterface`) files emitted by the library that propagated this provider and all of its dependencies. + +This field is deprecated; use `transitive_modules` instead. """, "transitive_swiftmodules": """\ `Depset` of `File`s. The transitive Swift modules (`.swiftmodule`) emitted by the library that propagated this provider and all of its dependencies. + +This field is deprecated; use `transitive_modules` instead. """, }, ) @@ -270,8 +286,11 @@ def create_clang_module( files, include paths, and other context necessary to compile targets that depend on this module (if using the text module map instead of the precompiled module). - module_map: A `File` representing the text module map file that defines - this 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 @@ -427,7 +446,11 @@ def create_swift_info( transitive = transitive_generated_headers, ), transitive_modulemaps = depset( - [m.clang.module_map for m in modules if m.clang], + [ + m.clang.module_map + for m in modules + if m.clang and not types.is_string(m.clang.module_map) + ], transitive = transitive_modulemaps, ), transitive_modules = depset(modules, transitive = transitive_modules), diff --git a/swift/internal/swift_clang_module_aspect.bzl b/swift/internal/swift_clang_module_aspect.bzl index 8ae9db53c..00dec750f 100644 --- a/swift/internal/swift_clang_module_aspect.bzl +++ b/swift/internal/swift_clang_module_aspect.bzl @@ -19,6 +19,7 @@ load(":compiling.bzl", "derive_module_name", "precompile_clang_module") load(":derived_files.bzl", "derived_files") load( ":feature_names.bzl", + "SWIFT_FEATURE_EMIT_C_MODULE", "SWIFT_FEATURE_MODULE_MAP_HOME_IS_CWD", "SWIFT_FEATURE_MODULE_MAP_NO_PRIVATE_HEADERS", ) @@ -139,6 +140,94 @@ def _generate_module_map( ) return module_map_file +def _module_info_for_target( + target, + aspect_ctx, + compilation_context, + dependent_module_names, + feature_configuration): + """Returns the module name and module map for the target. + + Args: + aspect_ctx: The aspect context. + target: The target for which the module map is being generated. + compilation_context: The C++ compilation context that provides the + headers for the module. + dependent_module_names: A `list` of names of Clang modules that are + direct dependencies of the target whose module map is being written. + feature_configuration: A Swift feature configuration. + + Returns: + A tuple containing the module name (a string) and module map file (a + `File`) for the target. One or both of these values may be `None`. + """ + attr = aspect_ctx.rule.attr + + if apple_common.Objc in target: + # TODO(b/142867898): For `objc_library`, stop using the module map from + # the Objc provider and generate our own. (For imported frameworks, + # continue using the module map included with it.) + objc = target[apple_common.Objc] + module_maps = objc.direct_module_maps + if not module_maps: + return None, None + + # If the target isn't an `objc_library`, return its module map (so we + # can propagate it) but don't return a module name; this will be used + # later as an indicator that we shouldn't try to compile an explicit + # module. + if not aspect_ctx.rule.kind == "objc_library": + return None, module_maps[0] + + module_name = getattr(attr, "module_name", None) + if not module_name: + module_name = derive_module_name(target.label) + + # For an `objc_library`, if we're emitting an explicit module, generate + # our own module map instead of using the one generated by the native + # Bazel `objc_library` implementation. This is necessary to get the + # correct `use` decls for dependencies to include everything in + # `SwiftInfo.direct_modules[].clang`, which will reference targets that + # `ObjcProvider` doesn't know about, like SDK modules. + # TODO(b/142867905): Once explicit modules are enabled by default, make + # this the only code path (i.e., this aspect should generate all module + # maps for `objc_library` targets). + emit_c_module = is_feature_enabled( + feature_configuration = feature_configuration, + feature_name = SWIFT_FEATURE_EMIT_C_MODULE, + ) + if not emit_c_module: + return module_name, module_maps[0] + + module_map_file = _generate_module_map( + actions = aspect_ctx.actions, + compilation_context = compilation_context, + dependent_module_names = dependent_module_names, + feature_configuration = feature_configuration, + module_name = module_name, + target = target, + ) + return module_name, module_map_file + + # For all other targets, there is no mechanism to provide a custom + # module map, and we only generate one if the target is tagged. + module_name = _tagged_target_module_name( + label = target.label, + tags = attr.tags, + ) + if not module_name: + return None, None + + module_map_file = _generate_module_map( + actions = aspect_ctx.actions, + compilation_context = compilation_context, + dependent_module_names = dependent_module_names, + feature_configuration = feature_configuration, + module_name = module_name, + target = target, + ) + return module_name, module_map_file + def _handle_cc_target( aspect_ctx, feature_configuration, @@ -173,9 +262,6 @@ def _handle_cc_target( else: merged_swift_info = None - module_map_file = None - module_name = None - # Collect the names of Clang modules that the module being built directly # depends on. dependent_module_names = [] @@ -184,34 +270,13 @@ def _handle_cc_target( if module.clang: dependent_module_names.append(module.name) - if apple_common.Objc in target: - # TODO(b/142867898): For `objc_library`, stop using the module map from - # the Objc provider and generate our own. (For imported frameworks, - # continue using the module map included with it.) - objc = target[apple_common.Objc] - module_maps = objc.direct_module_maps - if module_maps: - if aspect_ctx.rule.kind == "objc_library": - module_name = getattr(attr, "module_name", None) - if not module_name: - module_name = derive_module_name(target.label) - module_map_file = module_maps[0] - else: - # For all other targets, there is no mechanism to provide a custom - # module map, and we only generate one if the target is tagged. - module_name = _tagged_target_module_name( - label = target.label, - tags = attr.tags, - ) - if module_name: - module_map_file = _generate_module_map( - actions = aspect_ctx.actions, - compilation_context = compilation_context, - dependent_module_names = dependent_module_names, - feature_configuration = feature_configuration, - module_name = module_name, - target = target, - ) + module_name, module_map_file = _module_info_for_target( + target = target, + aspect_ctx = aspect_ctx, + compilation_context = compilation_context, + dependent_module_names = dependent_module_names, + feature_configuration = feature_configuration, + ) if not module_map_file: if merged_swift_info: @@ -235,7 +300,9 @@ def _handle_cc_target( for dep in getattr(attr, "deps", []): if CcInfo in dep: target_and_deps_cc_infos.append( - CcInfo(compilation_context = dep[CcInfo].compilation_context), + CcInfo( + compilation_context = dep[CcInfo].compilation_context, + ), ) compilation_context_to_compile = cc_common.merge_cc_infos( diff --git a/swift/internal/xcode_swift_toolchain.bzl b/swift/internal/xcode_swift_toolchain.bzl index 81c8f24a6..c06df3686 100644 --- a/swift/internal/xcode_swift_toolchain.bzl +++ b/swift/internal/xcode_swift_toolchain.bzl @@ -285,7 +285,10 @@ def _all_action_configs( action_configs = [ # Basic compilation flags (target triple and toolchain search paths). swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.PRECOMPILE_C_MODULE, + ], configurators = [ swift_toolchain_config.add_arg("-target", target_triple), swift_toolchain_config.add_arg("-sdk", sdk_dir), @@ -299,15 +302,31 @@ def _all_action_configs( ), ], ), + swift_toolchain_config.action_config( + actions = [swift_action_names.PRECOMPILE_C_MODULE], + configurators = [ + swift_toolchain_config.add_arg( + "-Xcc", + platform_framework_dir, + format = "-F%s", + ), + ], + ), # Bitcode-related flags. swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.PRECOMPILE_C_MODULE, + ], configurators = [swift_toolchain_config.add_arg("-embed-bitcode")], features = [SWIFT_FEATURE_BITCODE_EMBEDDED], ), swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.PRECOMPILE_C_MODULE, + ], configurators = [ swift_toolchain_config.add_arg("-embed-bitcode-marker"), ], @@ -321,7 +340,10 @@ def _all_action_configs( # directory so that modules are found correctly. action_configs.append( swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.PRECOMPILE_C_MODULE, + ], configurators = [ partial.make( _resource_directory_configurator, @@ -340,7 +362,8 @@ def _all_tool_configs( execution_requirements, swift_executable, toolchain_root, - use_param_file): + use_param_file, + xcode_config): """Returns the tool configurations for the Swift toolchain. Args: @@ -353,6 +376,7 @@ def _all_tool_configs( toolchain_root: The root directory of the toolchain, if provided. use_param_file: If True, actions should have their arguments written to param files. + xcode_config: The `apple_common.XcodeVersionConfig` provider. Returns: A dictionary mapping action name to tool configuration. @@ -365,7 +389,7 @@ def _all_tool_configs( env = dict(env) env["TOOLCHAINS"] = custom_toolchain - return { + tool_configs = { swift_action_names.COMPILE: swift_toolchain_config.driver_tool_config( driver_mode = "swiftc", env = env, @@ -377,6 +401,22 @@ def _all_tool_configs( ), } + # Xcode 12.0 implies Swift 5.3. + if _is_xcode_at_least_version(xcode_config, "12.0"): + tool_configs[swift_action_names.PRECOMPILE_C_MODULE] = ( + swift_toolchain_config.driver_tool_config( + driver_mode = "swiftc", + env = env, + execution_requirements = execution_requirements, + swift_executable = swift_executable, + toolchain_root = toolchain_root, + use_param_file = use_param_file, + worker_mode = "wrap", + ) + ) + + return tool_configs + def _is_macos(platform): """Returns `True` if the given platform is macOS. @@ -393,7 +433,7 @@ def _is_xcode_at_least_version(xcode_config, desired_version): """Returns True if we are building with at least the given Xcode version. Args: - xcode_config: the `apple_common.XcodeVersionConfig` provider. + xcode_config: The `apple_common.XcodeVersionConfig` provider. desired_version: The minimum desired Xcode version, as a dotted version string. @@ -571,6 +611,7 @@ def _xcode_swift_toolchain_impl(ctx): swift_executable = swift_executable, toolchain_root = toolchain_root, use_param_file = use_param_file, + xcode_config = xcode_config, ) all_action_configs = _all_action_configs( apple_fragment = apple_fragment, From d5eb04fe075761426ac835416d311454bfb605b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thi=20Do=C3=A3n?= Date: Mon, 24 Aug 2020 10:01:06 +0900 Subject: [PATCH 010/152] Use a parameter file when linking Swift libraries when the host machine is macOS (#473) This is to prevent the linking failures if a `swift_library` target has too many files that can cause its linking args to become longer than the system's command length limits. This does not change the behavior when building on Linux yet, since `ar` does not support passing arguments using a parameter file. --- swift/internal/linking.bzl | 12 ++++++++++-- swift/internal/providers.bzl | 4 ++++ swift/internal/swift_toolchain.bzl | 7 +++++++ swift/internal/xcode_swift_toolchain.bzl | 1 + 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/swift/internal/linking.bzl b/swift/internal/linking.bzl index 6d4336478..613c77ff2 100644 --- a/swift/internal/linking.bzl +++ b/swift/internal/linking.bzl @@ -58,7 +58,15 @@ def _register_static_library_link_action( ) args = actions.args() args.add_all(command_line) - args.add_all(objects) + + filelist_args = actions.args() + if swift_toolchain.linker_supports_filelist: + args.add("-filelist") + filelist_args.set_param_file_format("multiline") + filelist_args.use_param_file("%s", use_always = True) + filelist_args.add_all(objects) + else: + args.add_all(objects) env = cc_common.get_environment_variables( action_name = CPP_LINK_STATIC_LIBRARY_ACTION_NAME, @@ -73,7 +81,7 @@ def _register_static_library_link_action( execution_requirements = {req: "1" for req in execution_requirements_list} actions.run( - arguments = [args], + arguments = [args, filelist_args], env = env, executable = archiver_path, execution_requirements = execution_requirements, diff --git a/swift/internal/providers.bzl b/swift/internal/providers.bzl index 29bef0bc3..fac8549de 100644 --- a/swift/internal/providers.bzl +++ b/swift/internal/providers.bzl @@ -161,6 +161,10 @@ The partial should be called with two arguments: or dynamic runtime libraries. * `is_test`: A `Boolean` value indicating whether the target being linked is a test target. +""", + "linker_supports_filelist": """\ +`Boolean`. Indicates whether or not the toolchain's linker supports the input +files passed to it via a file list. """, "object_format": """\ `String`. The object file format of the platform that the toolchain is diff --git a/swift/internal/swift_toolchain.bzl b/swift/internal/swift_toolchain.bzl index d52efab7b..86a8ed013 100644 --- a/swift/internal/swift_toolchain.bzl +++ b/swift/internal/swift_toolchain.bzl @@ -168,6 +168,12 @@ def _swift_toolchain_impl(ctx): toolchain_root, ) + # The static archiver on Linux doesn't currently support the `-filelist` + # flag. This should be handled by the C++ toolchain once we migrate away + # from invoking the linker directly for static linking. + # See https://github.com/bazelbuild/rules_swift/pull/349#issuecomment-550353580. + linker_supports_filelist = True if ctx.attr.os == "darwin" else False + # Combine build mode features, autoconfigured features, and required # features. requested_features = features_for_build_modes(ctx) @@ -204,6 +210,7 @@ def _swift_toolchain_impl(ctx): command_line_copts = ctx.fragments.swift.copts(), cpu = ctx.attr.arch, linker_opts_producer = linker_opts_producer, + linker_supports_filelist = linker_supports_filelist, object_format = "elf", optional_implicit_deps = [], requested_features = requested_features, diff --git a/swift/internal/xcode_swift_toolchain.bzl b/swift/internal/xcode_swift_toolchain.bzl index c06df3686..0c60d2b91 100644 --- a/swift/internal/xcode_swift_toolchain.bzl +++ b/swift/internal/xcode_swift_toolchain.bzl @@ -635,6 +635,7 @@ def _xcode_swift_toolchain_impl(ctx): command_line_copts = command_line_copts, cpu = cpu, linker_opts_producer = linker_opts_producer, + linker_supports_filelist = True, object_format = "macho", optional_implicit_deps = [], requested_features = requested_features, From a59b8d1b9a67f7787bb220076331085f93fa9def Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Mon, 31 Aug 2020 10:21:39 -0700 Subject: [PATCH 011/152] Read the `custom_malloc` configuration field in `swift_{binary,test}` to use an allocator provided by the `--custom_malloc` flag, if any. (#478) PiperOrigin-RevId: 329317960 Co-authored-by: Tony Allevato --- swift/internal/swift_binary_test.bzl | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/swift/internal/swift_binary_test.bzl b/swift/internal/swift_binary_test.bzl index fa0a56b4e..6d0d544d3 100644 --- a/swift/internal/swift_binary_test.bzl +++ b/swift/internal/swift_binary_test.bzl @@ -78,6 +78,15 @@ into the binary. Possible values are: "_cc_toolchain": attr.label( default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"), ), + # A late-bound attribute denoting the value of the `--custom_malloc` + # command line flag (or None if the flag is not provided). + "_custom_malloc": attr.label( + default = configuration_field( + fragment = "cpp", + name = "custom_malloc", + ), + providers = [[CcInfo]], + ), # TODO(b/119082664): Used internally only. "_grep_includes": attr.label( allow_single_file = True, @@ -215,10 +224,8 @@ def _swift_linking_rule_impl( # If a custom malloc implementation has been provided, pass that to the # linker as well. - if ctx.attr.malloc: - additional_linking_contexts.append( - ctx.attr.malloc[CcInfo].linking_context, - ) + malloc = ctx.attr._custom_malloc or ctx.attr.malloc + additional_linking_contexts.append(malloc[CcInfo].linking_context) # Finally, consider linker flags in the `linkopts` attribute and the # `--linkopt` command line flag last, so they get highest priority. From 28365f0eb1ded30566fc480e13891510986c5a5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thi=20Do=C3=A3n?= Date: Tue, 1 Sep 2020 07:37:16 +0900 Subject: [PATCH 012/152] No need to check if we're on macOS for non-Darwin Swift toolchain (#479) --- swift/internal/swift_toolchain.bzl | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/swift/internal/swift_toolchain.bzl b/swift/internal/swift_toolchain.bzl index 86a8ed013..d752e9107 100644 --- a/swift/internal/swift_toolchain.bzl +++ b/swift/internal/swift_toolchain.bzl @@ -168,12 +168,6 @@ def _swift_toolchain_impl(ctx): toolchain_root, ) - # The static archiver on Linux doesn't currently support the `-filelist` - # flag. This should be handled by the C++ toolchain once we migrate away - # from invoking the linker directly for static linking. - # See https://github.com/bazelbuild/rules_swift/pull/349#issuecomment-550353580. - linker_supports_filelist = True if ctx.attr.os == "darwin" else False - # Combine build mode features, autoconfigured features, and required # features. requested_features = features_for_build_modes(ctx) @@ -210,7 +204,7 @@ def _swift_toolchain_impl(ctx): command_line_copts = ctx.fragments.swift.copts(), cpu = ctx.attr.arch, linker_opts_producer = linker_opts_producer, - linker_supports_filelist = linker_supports_filelist, + linker_supports_filelist = False, object_format = "elf", optional_implicit_deps = [], requested_features = requested_features, From 8015d0ec6657846d917dad581ac75fa96dc5050d Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Tue, 1 Sep 2020 15:51:04 -0700 Subject: [PATCH 013/152] Update protobuf deps (#480) --- swift/repositories.bzl | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/swift/repositories.bzl b/swift/repositories.bzl index b7e1ae40b..32ae0c473 100644 --- a/swift/repositories.bzl +++ b/swift/repositories.bzl @@ -68,9 +68,9 @@ def swift_rules_dependencies(): _maybe( http_archive, name = "com_github_apple_swift_protobuf", - urls = ["https://github.com/apple/swift-protobuf/archive/1.7.0.zip"], - sha256 = "a4546ee8e95e7f7d4cf46b5b667e824b58f3943a71c352bf1e0b91660afdf3c3", - strip_prefix = "swift-protobuf-1.7.0/", + urls = ["https://github.com/apple/swift-protobuf/archive/1.12.0.zip"], + sha256 = "a9c1c14d81df690ed4c15bfb3c0aab0cb7a3f198ee95620561b89b1da7b76a9f", + strip_prefix = "swift-protobuf-1.12.0/", type = "zip", build_file = "@build_bazel_rules_swift//third_party:com_github_apple_swift_protobuf/BUILD.overlay", ) @@ -99,12 +99,12 @@ def swift_rules_dependencies(): _maybe( http_archive, name = "com_google_protobuf", - # v3.11.2, latest as of 2019-12-19 + # latest as of 2020-09-01 urls = [ - "https://github.com/protocolbuffers/protobuf/archive/v3.11.2.zip", + "https://github.com/protocolbuffers/protobuf/archive/v3.13.0.zip", ], - sha256 = "e4f8bedb19a93d0dccc359a126f51158282e0b24d92e0cad9c76a9699698268d", - strip_prefix = "protobuf-3.11.2", + sha256 = "1c744a6a1f2c901e68c5521bc275e22bdc66256eeb605c2781923365b7087e5f", + strip_prefix = "protobuf-3.13.0", type = "zip", ) From 911072783b662292bf568b48e4c833575d50aa4f Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Wed, 2 Sep 2020 14:11:39 -0700 Subject: [PATCH 014/152] Run //test/... on Linux CI (#463) --- .bazelci/presubmit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index 1659c84f7..7140dd33b 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -26,7 +26,7 @@ x_defaults: test_targets: - "--" - "//examples/..." - # - "//test/..." TODO: Enable once https://github.com/bazelbuild/continuous-integration/pull/1015 is deployed + - "//test/..." - "-//examples/apple/..." tasks: From 57058aadc2be9839f6950b97f43467045876b2fc Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Wed, 2 Sep 2020 15:21:45 -0700 Subject: [PATCH 015/152] Ensure that intermediate outputs created for Swift source files (such as object files) do not have spaces in their names. This was already handled for basenames, but not for directory names between the target's package and the file; for example, if one had `swift_library(name = "ArgumentParser", ...)` in a `BUILD` file that also contained `Sources/ArgumentParser/Parsable Types/ParsableCommand.swift`. PiperOrigin-RevId: 329799243 --- swift/internal/derived_files.bzl | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/swift/internal/derived_files.bzl b/swift/internal/derived_files.bzl index ee57fce17..4bbe6ba8a 100644 --- a/swift/internal/derived_files.bzl +++ b/swift/internal/derived_files.bzl @@ -80,11 +80,10 @@ def _intermediate_frontend_file_path(target_name, src): target and source file should be stored. """ objs_dir = "{}_objs".format(target_name) - owner_rel_path = owner_relative_path(src) - # TODO(b/131185317): Remove this once ar_wrapper handles filenames with - # spaces correctly. - safe_name = src.basename.replace(" ", "__SPACE__") + owner_rel_path = owner_relative_path(src).replace(" ", "__SPACE__") + safe_name = paths.basename(owner_rel_path) + return paths.join(objs_dir, paths.dirname(owner_rel_path)), safe_name def _intermediate_object_file(actions, target_name, src): From beb3a30faf3982b870924cfcedf01dc596400599 Mon Sep 17 00:00:00 2001 From: Samuel Giddins Date: Thu, 3 Sep 2020 22:24:27 -0700 Subject: [PATCH 016/152] Update bzl_library targets (#482) * Pin rules_proto to a rev that contains bzl_library definitions * Update bzl_library targets Mostly so depending on them from a stardoc rule works now we load rules_proto Mostly autogenerated & then tweaked based on the gazelle in https://github.com/bazelbuild/bazel-skylib/pull/271 * Revert removal of for_bazel_tests filegroup target * Update internal bzl_libraries to only be visible to //swift:__subpackages__ * Also limit visibility of //test/fixtures:common --- swift/BUILD | 28 +-- swift/internal/BUILD | 384 +++++++++++++++++++++++++++++++++++------ swift/repositories.bzl | 12 ++ test/fixtures/BUILD | 6 + 4 files changed, 362 insertions(+), 68 deletions(-) diff --git a/swift/BUILD b/swift/BUILD index ad1437b20..cf6045612 100644 --- a/swift/BUILD +++ b/swift/BUILD @@ -6,28 +6,34 @@ package(default_visibility = ["//visibility:public"]) licenses(["notice"]) bzl_library( - name = "swift", - srcs = ["swift.bzl"], + name = "repositories", + srcs = ["repositories.bzl"], deps = [ - "//swift/internal:build_defs", - "//swift/internal:rules", - "//swift/internal:swift_common", + "//swift/internal:swift_autoconfiguration", + "@bazel_tools//tools/build_defs/repo:http.bzl", ], ) bzl_library( name = "stats", srcs = ["stats.bzl"], - deps = [ - "//swift/internal:build_defs", - ], + deps = ["//swift/internal:utils"], ) bzl_library( - name = "repositories", - srcs = ["repositories.bzl"], + name = "swift", + srcs = ["swift.bzl"], deps = [ - "//swift/internal:toolchain_support", + "//swift/internal:providers", + "//swift/internal:swift_binary_test", + "//swift/internal:swift_c_module", + "//swift/internal:swift_common", + "//swift/internal:swift_grpc_library", + "//swift/internal:swift_import", + "//swift/internal:swift_library", + "//swift/internal:swift_module_alias", + "//swift/internal:swift_proto_library", + "//swift/internal:swift_usage_aspect", ], ) diff --git a/swift/internal/BUILD b/swift/internal/BUILD index 7d5295eef..944ff4844 100644 --- a/swift/internal/BUILD +++ b/swift/internal/BUILD @@ -3,96 +3,366 @@ load("@bazel_skylib//:bzl_library.bzl", "bzl_library") licenses(["notice"]) bzl_library( - name = "rules", - srcs = [ - "swift_binary_test.bzl", - "swift_c_module.bzl", - "swift_grpc_library.bzl", - "swift_import.bzl", - "swift_library.bzl", - "swift_module_alias.bzl", - "swift_proto_library.bzl", - "swift_protoc_gen_aspect.bzl", - ], - visibility = [ - "//swift:__pkg__", + name = "actions", + srcs = ["actions.bzl"], + visibility = ["//swift:__subpackages__"], + deps = [ + ":features", + ":toolchain_config", + "@bazel_skylib//lib:partial", + "@bazel_skylib//lib:types", ], +) + +bzl_library( + name = "attrs", + srcs = ["attrs.bzl"], + visibility = ["//swift:__subpackages__"], deps = [ - ":build_defs", - ":swift_common", + ":providers", "@bazel_skylib//lib:dicts", - "@bazel_skylib//lib:new_sets", + ], +) + +bzl_library( + name = "autolinking", + srcs = ["autolinking.bzl"], + visibility = ["//swift:__subpackages__"], + deps = [ + ":actions", + ":toolchain_config", + ], +) + +bzl_library( + name = "compiling", + srcs = ["compiling.bzl"], + visibility = ["//swift:__subpackages__"], + deps = [ + ":actions", + ":autolinking", + ":debugging", + ":derived_files", + ":feature_names", + ":features", + ":providers", + ":toolchain_config", + ":utils", + ":vfsoverlay", + "@bazel_skylib//lib:collections", "@bazel_skylib//lib:partial", "@bazel_skylib//lib:paths", - "@bazel_skylib//rules:common_settings", + "@bazel_skylib//lib:types", ], ) bzl_library( - name = "swift_common", - srcs = ["swift_common.bzl"], - visibility = [ - "//swift:__pkg__", - ], - deps = [":build_defs"], -) - -bzl_library( - name = "build_defs", - srcs = [ - "actions.bzl", - "attrs.bzl", - "autolinking.bzl", - "compiling.bzl", - "debugging.bzl", - "derived_files.bzl", - "feature_names.bzl", - "features.bzl", - "linking.bzl", - "module_maps.bzl", - "proto_gen_utils.bzl", - "providers.bzl", - "swift_clang_module_aspect.bzl", - "swift_usage_aspect.bzl", - "toolchain_config.bzl", - "utils.bzl", - "vfsoverlay.bzl", + name = "debugging", + srcs = ["debugging.bzl"], + visibility = ["//swift:__subpackages__"], + deps = [ + ":actions", + ":derived_files", + ":toolchain_config", ], - visibility = [ - "//swift:__pkg__", +) + +bzl_library( + name = "derived_files", + srcs = ["derived_files.bzl"], + visibility = ["//swift:__subpackages__"], + deps = [ + ":utils", + "@bazel_skylib//lib:paths", ], +) + +bzl_library( + name = "features", + srcs = ["features.bzl"], + visibility = ["//swift:__subpackages__"], deps = [ + ":feature_names", "@bazel_skylib//lib:collections", - "@bazel_skylib//lib:dicts", "@bazel_skylib//lib:new_sets", + ], +) + +bzl_library( + name = "linking", + srcs = ["linking.bzl"], + visibility = ["//swift:__subpackages__"], + deps = [ + ":derived_files", + "@bazel_skylib//lib:collections", "@bazel_skylib//lib:partial", + "@bazel_tools//tools/build_defs/cc:action_names.bzl", + ], +) + +bzl_library( + name = "module_maps", + srcs = ["module_maps.bzl"], + visibility = ["//swift:__subpackages__"], + deps = ["@bazel_skylib//lib:paths"], +) + +bzl_library( + name = "proto_gen_utils", + srcs = ["proto_gen_utils.bzl"], + visibility = ["//swift:__subpackages__"], + deps = [ + ":utils", "@bazel_skylib//lib:paths", + ], +) + +bzl_library( + name = "providers", + srcs = ["providers.bzl"], + visibility = ["//swift:__subpackages__"], + deps = [ "@bazel_skylib//lib:sets", "@bazel_skylib//lib:types", + ], +) + +bzl_library( + name = "swift_autoconfiguration", + srcs = ["swift_autoconfiguration.bzl"], + visibility = ["//swift:__subpackages__"], + deps = ["@build_bazel_rules_swift//swift/internal:feature_names"], +) + +bzl_library( + name = "swift_c_module", + srcs = ["swift_c_module.bzl"], + visibility = ["//swift:__subpackages__"], + deps = [ + ":swift_common", + ":utils", + ], +) + +bzl_library( + name = "swift_binary_test", + visibility = ["//swift:__subpackages__"], + deps = [ + ":compiling", + ":derived_files", + ":feature_names", + ":linking", + ":providers", + ":swift_common", + ":utils", + "@bazel_skylib//lib:dicts", + "@bazel_skylib//lib:partial", + ], +) + +bzl_library( + name = "swift_clang_module_aspect", + srcs = ["swift_clang_module_aspect.bzl"], + visibility = ["//swift:__subpackages__"], + deps = [ + ":attrs", + ":compiling", + ":derived_files", + ":feature_names", + ":features", + ":module_maps", + ":providers", + ":utils", + ], +) + +bzl_library( + name = "swift_common", + srcs = ["swift_common.bzl"], + visibility = ["//swift:__subpackages__"], + deps = [ + ":attrs", + ":compiling", + ":features", + ":linking", + ":providers", + ":swift_clang_module_aspect", + ], +) + +bzl_library( + name = "swift_grpc_library", + srcs = ["swift_grpc_library.bzl"], + visibility = ["//swift:__subpackages__"], + deps = [ + ":compiling", + ":feature_names", + ":linking", + ":proto_gen_utils", + ":providers", + ":swift_common", + ":utils", + "@bazel_skylib//lib:dicts", + "@rules_proto//proto:defs", + ], +) + +bzl_library( + name = "swift_import", + srcs = ["swift_import.bzl"], + visibility = ["//swift:__subpackages__"], + deps = [ + ":attrs", + ":compiling", + ":providers", + ":swift_common", + ":utils", + "@bazel_skylib//lib:dicts", + ], +) + +bzl_library( + name = "swift_library", + srcs = ["swift_library.bzl"], + visibility = ["//swift:__subpackages__"], + deps = [ + ":attrs", + ":compiling", + ":feature_names", + ":linking", + ":providers", + ":swift_common", + ":utils", + "@bazel_skylib//lib:dicts", + "@bazel_skylib//lib:sets", "@bazel_skylib//rules:common_settings", - "@bazel_tools//tools/build_defs/cc:action_names.bzl", ], ) bzl_library( - name = "toolchain_support", - srcs = [ - "swift_autoconfiguration.bzl", - "swift_toolchain.bzl", - "xcode_swift_toolchain.bzl", + name = "swift_module_alias", + srcs = ["swift_module_alias.bzl"], + visibility = ["//swift:__subpackages__"], + deps = [ + ":compiling", + ":derived_files", + ":linking", + ":providers", + ":swift_common", + ":utils", + "@bazel_skylib//lib:dicts", ], - visibility = [ - "//swift:__pkg__", +) + +bzl_library( + name = "swift_proto_library", + srcs = ["swift_proto_library.bzl"], + visibility = ["//swift:__subpackages__"], + deps = [ + ":providers", + ":swift_protoc_gen_aspect", + "@rules_proto//proto:defs", ], +) + +bzl_library( + name = "swift_protoc_gen_aspect", + srcs = ["swift_protoc_gen_aspect.bzl"], + visibility = ["//swift:__subpackages__"], + deps = [ + ":attrs", + ":compiling", + ":feature_names", + ":linking", + ":proto_gen_utils", + ":providers", + ":swift_common", + ":utils", + "@bazel_skylib//lib:dicts", + "@bazel_skylib//rules:common_settings", + "@rules_proto//proto:defs", + ], +) + +bzl_library( + name = "swift_toolchain", + srcs = ["swift_toolchain.bzl"], + visibility = ["//swift:__subpackages__"], + deps = [ + ":actions", + ":attrs", + ":autolinking", + ":compiling", + ":debugging", + ":feature_names", + ":features", + ":providers", + ":toolchain_config", + ":utils", + "@bazel_skylib//lib:dicts", + "@bazel_skylib//lib:partial", + "@bazel_tools//tools/cpp:toolchain_utils.bzl", + ], +) + +bzl_library( + name = "swift_usage_aspect", + srcs = ["swift_usage_aspect.bzl"], + visibility = ["//swift:__subpackages__"], + deps = [":providers"], +) + +bzl_library( + name = "toolchain_config", + srcs = ["toolchain_config.bzl"], + visibility = ["//swift:__subpackages__"], + deps = [ + "@bazel_skylib//lib:partial", + "@bazel_skylib//lib:paths", + "@bazel_skylib//lib:types", + ], +) + +bzl_library( + name = "utils", + srcs = ["utils.bzl"], + visibility = ["//swift:__subpackages__"], + deps = ["@bazel_skylib//lib:paths"], +) + +bzl_library( + name = "xcode_swift_toolchain", + srcs = ["xcode_swift_toolchain.bzl"], + visibility = ["//swift:__subpackages__"], deps = [ - ":build_defs", + ":actions", + ":attrs", + ":compiling", + ":feature_names", + ":features", + ":providers", + ":toolchain_config", + ":utils", "@bazel_skylib//lib:collections", "@bazel_skylib//lib:dicts", "@bazel_skylib//lib:partial", "@bazel_skylib//lib:paths", + "@bazel_tools//tools/cpp:toolchain_utils.bzl", ], ) +bzl_library( + name = "feature_names", + srcs = ["feature_names.bzl"], + visibility = ["//swift:__subpackages__"], +) + +bzl_library( + name = "vfsoverlay", + srcs = ["vfsoverlay.bzl"], + visibility = ["//swift:__subpackages__"], +) + # Consumed by Bazel integration tests. filegroup( name = "for_bazel_tests", diff --git a/swift/repositories.bzl b/swift/repositories.bzl index 32ae0c473..73e930295 100644 --- a/swift/repositories.bzl +++ b/swift/repositories.bzl @@ -96,6 +96,18 @@ def swift_rules_dependencies(): build_file = "@build_bazel_rules_swift//third_party:com_github_nlohmann_json/BUILD.overlay", ) + _maybe( + http_archive, + name = "rules_proto", + # latest as of 2020-09-01 + urls = [ + "https://github.com/bazelbuild/rules_proto/archive/40298556293ae502c66579620a7ce867d5f57311.zip", + ], + sha256 = "37d32b789be90fead9ab108dbe4fe4df463d26c122dc896dc1bf134252d3c49a", + strip_prefix = "rules_proto-40298556293ae502c66579620a7ce867d5f57311", + type = "zip", + ) + _maybe( http_archive, name = "com_google_protobuf", diff --git a/test/fixtures/BUILD b/test/fixtures/BUILD index ec39f3b2b..fee23b0b3 100644 --- a/test/fixtures/BUILD +++ b/test/fixtures/BUILD @@ -7,3 +7,9 @@ bzl_library( "//test:__pkg__", ], ) + +bzl_library( + name = "common", + srcs = ["common.bzl"], + visibility = ["//test:__pkg__"], +) From 48f1b5765471a12445135a9e910a482355cca1ed Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Tue, 8 Sep 2020 10:33:17 -0700 Subject: [PATCH 017/152] Add a feature flag to enable generation from raw proto sources. The DescriptorSets ProtoInfo exposes don't have source info, so the generated source don't have the comment. https://github.com/bazelbuild/bazel/issues/9337 is open to attempt to get that, but this provides a way to opt into forcing it. This does come with a minor risk for cross repository and/or generated proto files where the protoc command line might not be crafted correctly, so it remains opt in. RELNOTES: None PiperOrigin-RevId: 330538313 --- swift/internal/feature_names.bzl | 14 ++++ swift/internal/proto_gen_utils.bzl | 28 ++++++- swift/internal/swift_grpc_library.bzl | 2 +- swift/internal/swift_protoc_gen_aspect.bzl | 85 ++++++++++++++++------ swift/internal/utils.bzl | 33 --------- 5 files changed, 104 insertions(+), 58 deletions(-) diff --git a/swift/internal/feature_names.bzl b/swift/internal/feature_names.bzl index 0885a19ee..da282aeef 100644 --- a/swift/internal/feature_names.bzl +++ b/swift/internal/feature_names.bzl @@ -208,3 +208,17 @@ SWIFT_FEATURE_SUPPORTS_PRIVATE_DEPS = "swift.supports_private_deps" # numbers of `-Wl,-add_ast_path,` flags to the linker do not overrun the # system command line limit. SWIFT_FEATURE_NO_EMBED_DEBUG_MODULE = "swift.no_embed_debug_module" + +# If enabled, the toolchain will directly generate from the raw proto files +# and not from the DescriptorSets. +# +# The DescriptorSets ProtoInfo exposes don't have source info, so comments in +# the .proto files don't get carried over to the generated Swift sources as +# documentation comments. https://github.com/bazelbuild/bazel/issues/9337 +# is open to attempt to get that, but this provides a way to opt into forcing +# it. +# +# This does come with a minor risk for cross repository and/or generated proto +# files where the protoc command line might not be crafted correctly, so it +# remains opt in. +SWIFT_FEATURE_GENERATE_FROM_RAW_PROTO_FILES = "swift.generate_from_raw_proto_files" diff --git a/swift/internal/proto_gen_utils.bzl b/swift/internal/proto_gen_utils.bzl index 6f51560e1..017397b33 100644 --- a/swift/internal/proto_gen_utils.bzl +++ b/swift/internal/proto_gen_utils.bzl @@ -15,7 +15,6 @@ """Utilities for rules/aspects that generate sources from .proto files.""" load("@bazel_skylib//lib:paths.bzl", "paths") -load(":utils.bzl", "proto_import_path") def declare_generated_files( name, @@ -113,6 +112,33 @@ def register_module_mapping_write_action(name, actions, module_mappings): return mapping_file +def proto_import_path(f, proto_source_root): + """ Returns the import path of a `.proto` file given its path. + + Args: + f: The `File` object representing the `.proto` file. + proto_source_root: The source root for the `.proto` file. + + Returns: + The path the `.proto` file should be imported at. + """ + + if proto_source_root: + # Don't want to accidentally match "foo" to "foobar", so add the slash. + if not proto_source_root.endswith("/"): + proto_source_root += "/" + if f.path.startswith(proto_source_root): + return f.path[len(proto_source_root):] + + # Cross-repository proto file references is sorta a grey area. If that is + # needed, please see the comments in ProtoCompileActionBuilder.java's + # guessProtoPathUnderRoot() for some guidance of what would be needed, but + # the current (Q3/2020) reading says that seems to not maintain the + # references, so the proto file namespace is likely flat across + # repositories. + workspace_path = paths.join(f.root.path, f.owner.workspace_root) + return paths.relativize(f.path, workspace_path) + def _generated_file_path( name, extension_fragment, diff --git a/swift/internal/swift_grpc_library.bzl b/swift/internal/swift_grpc_library.bzl index dc7c69a1a..2e44a6c64 100644 --- a/swift/internal/swift_grpc_library.bzl +++ b/swift/internal/swift_grpc_library.bzl @@ -31,6 +31,7 @@ load( ":proto_gen_utils.bzl", "declare_generated_files", "extract_generated_dir_path", + "proto_import_path", "register_module_mapping_write_action", ) load(":providers.bzl", "SwiftInfo", "SwiftProtoInfo", "SwiftToolchainInfo") @@ -40,7 +41,6 @@ load( "compact", "create_cc_info", "get_providers", - "proto_import_path", ) def _register_grpcswift_generate_action( diff --git a/swift/internal/swift_protoc_gen_aspect.bzl b/swift/internal/swift_protoc_gen_aspect.bzl index 83dcdad90..091013a9e 100644 --- a/swift/internal/swift_protoc_gen_aspect.bzl +++ b/swift/internal/swift_protoc_gen_aspect.bzl @@ -24,6 +24,7 @@ load( "SWIFT_FEATURE_EMIT_SWIFTINTERFACE", "SWIFT_FEATURE_ENABLE_LIBRARY_EVOLUTION", "SWIFT_FEATURE_ENABLE_TESTING", + "SWIFT_FEATURE_GENERATE_FROM_RAW_PROTO_FILES", "SWIFT_FEATURE_NO_GENERATED_HEADER", ) load(":linking.bzl", "register_libraries_to_link") @@ -31,6 +32,7 @@ load( ":proto_gen_utils.bzl", "declare_generated_files", "extract_generated_dir_path", + "proto_import_path", "register_module_mapping_write_action", ) load(":providers.bzl", "SwiftInfo", "SwiftProtoInfo", "SwiftToolchainInfo") @@ -40,7 +42,6 @@ load( "compact", "create_cc_info", "get_providers", - "proto_import_path", ) # The paths of proto files bundled with the runtime. This is mainly the well @@ -109,6 +110,7 @@ def _register_pbswift_generate_action( proto_source_root, transitive_descriptor_sets, module_mapping_file, + generate_from_proto_sources, mkdir_and_run, protoc_executable, protoc_plugin_executable): @@ -127,6 +129,10 @@ def _register_pbswift_generate_action( target being analyzed. May be `None`, in which case no module mapping will be passed (the case for leaf nodes in the dependency graph). + generate_from_proto_sources: True/False for is generation should happen + from proto source file vs just via the DescriptorSets. The Sets + don't have source info, so the generated sources won't have + comments (https://github.com/bazelbuild/bazel/issues/9337). mkdir_and_run: The `File` representing the `mkdir_and_run` executable. protoc_executable: The `File` representing the `protoc` executable. protoc_plugin_executable: The `File` representing the `protoc` plugin @@ -175,13 +181,32 @@ def _register_pbswift_generate_action( module_mapping_file, format = "--swift_opt=ProtoPathModuleMappings=%s", ) - protoc_args.add("--descriptor_set_in") - protoc_args.add_joined(transitive_descriptor_sets, join_with = ":") + protoc_args.add_joined( + transitive_descriptor_sets, + join_with = ":", + format_joined = "--descriptor_set_in=%s", + omit_if_empty = True, + ) + + if generate_from_proto_sources: + # ProtoCompileActionBuilder.java's XPAND_TRANSITIVE_PROTO_PATH_FLAGS + # leaves this off also. + if proto_source_root != ".": + protoc_args.add(proto_source_root, format = "--proto_path=%s") + + # Follow ProtoCompileActionBuilder.java's + # ExpandImportArgsFn::expandToCommandLine() logic and provide a mapping + # for each file to the proto path. + for f in direct_srcs: + protoc_args.add("-I%s=%s" % (proto_import_path(f, proto_source_root), f.path)) + protoc_args.add_all( [proto_import_path(f, proto_source_root) for f in direct_srcs], ) additional_command_inputs = [] + if generate_from_proto_sources: + additional_command_inputs.extend(direct_srcs) if module_mapping_file: additional_command_inputs.append(module_mapping_file) @@ -298,13 +323,6 @@ def _swift_protoc_gen_aspect_impl(target, aspect_ctx): target[ProtoInfo].proto_source_root, ) - # Direct sources are passed as arguments to protoc to generate *only* the - # files in this target, but we need to pass the transitive sources as inputs - # to the generating action so that all the dependent files are available for - # protoc to parse. - # Instead of providing all those files and opening/reading them, we use - # protoc's support for reading descriptor sets to resolve things. - transitive_descriptor_sets = target[ProtoInfo].transitive_descriptor_sets proto_deps = [ dep for dep in aspect_ctx.rule.attr.deps @@ -334,19 +352,6 @@ def _swift_protoc_gen_aspect_impl(target, aspect_ctx): support_deps = aspect_ctx.attr._proto_support if direct_srcs: - # Generate the Swift sources from the .proto files. - pbswift_files = _register_pbswift_generate_action( - target.label, - aspect_ctx.actions, - direct_srcs, - target[ProtoInfo].proto_source_root, - transitive_descriptor_sets, - transitive_module_mapping_file, - aspect_ctx.executable._mkdir_and_run, - aspect_ctx.executable._protoc, - aspect_ctx.executable._protoc_gen_swift, - ) - extra_features = [] # This feature is not fully supported because the SwiftProtobuf library @@ -374,6 +379,40 @@ def _swift_protoc_gen_aspect_impl(target, aspect_ctx): ], ) + generate_from_proto_sources = swift_common.is_enabled( + feature_configuration = feature_configuration, + feature_name = SWIFT_FEATURE_GENERATE_FROM_RAW_PROTO_FILES, + ) + + # Only the files for direct sources should be generated, but the + # transitive descriptor sets are still need to be able to parse/load + # those descriptors. + if generate_from_proto_sources: + # Take the transitive descriptor sets from the proto_library deps, + # so the direct sources won't be in any descriptor sets to reduce + # the input to the action (and what protoc has to parse). + transitive_descriptor_sets = depset(transitive = [ + dep[ProtoInfo].transitive_descriptor_sets + for dep in aspect_ctx.rule.attr.deps + if ProtoInfo in dep + ]) + else: + transitive_descriptor_sets = target[ProtoInfo].transitive_descriptor_sets + + # Generate the Swift sources from the .proto files. + pbswift_files = _register_pbswift_generate_action( + target.label, + aspect_ctx.actions, + direct_srcs, + target[ProtoInfo].proto_source_root, + transitive_descriptor_sets, + transitive_module_mapping_file, + generate_from_proto_sources, + aspect_ctx.executable._mkdir_and_run, + aspect_ctx.executable._protoc, + aspect_ctx.executable._protoc_gen_swift, + ) + module_name = swift_common.derive_module_name(target.label) compilation_outputs = swift_common.compile( diff --git a/swift/internal/utils.bzl b/swift/internal/utils.bzl index 13b4caa89..b4e41d85f 100644 --- a/swift/internal/utils.bzl +++ b/swift/internal/utils.bzl @@ -330,36 +330,3 @@ def struct_fields(s): # TODO(b/36412967): Remove the `to_json` and `to_proto` checks. if field not in ("to_json", "to_proto") } - -def _workspace_relative_path(file): - """Returns the path of a file relative to its workspace. - - Args: - file: The `File` object. - - Returns: - The path of the file relative to its workspace. - """ - workspace_path = paths.join(file.root.path, file.owner.workspace_root) - return paths.relativize(file.path, workspace_path) - -def proto_import_path(f, proto_source_root): - """ Returns the import path of a `.proto` file given its path. - - Args: - f: The `File` object representing the `.proto` file. - proto_source_root: The source root for the `.proto` file. - - Returns: - The path the `.proto` file should be imported at. - """ - - # The simple repo case seems to say this branch is never happening as the - # proto_source_root seems to always be ".". So the general logic here likely - # needs a revisit. - if f.path.startswith(proto_source_root): - return f.path[len(proto_source_root) + 1:] - else: - # Happens before Bazel 1.0, where proto_source_root was not - # guaranteed to be a parent of the .proto file - return _workspace_relative_path(f) From 9eef33fd77ce0dbc6f9359a3eba46e2d54a01ec1 Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Wed, 9 Sep 2020 08:44:42 -0700 Subject: [PATCH 018/152] Honor the feature flag to enable generation from raw proto sources. The DescriptorSets ProtoInfo exposes don't have source info, so the generated source don't have the comment. https://github.com/bazelbuild/bazel/issues/9337 is open to attempt to get that, but this provides a way to opt into forcing it. This does come with a minor risk for cross repository and/or generated proto files where the protoc command line might not be crafted correctly, so it remains opt in. This is followup to the previous change that did this for swift_proto_library. NOTE: The current version of swift grpc depended on doesn't include comments, but the NIO version appears to support it for methods, so landing the work in advance of things updating to that version. RELNOTES: None PiperOrigin-RevId: 330729710 --- swift/internal/swift_grpc_library.bzl | 87 ++++++++++++++++++++------- 1 file changed, 64 insertions(+), 23 deletions(-) diff --git a/swift/internal/swift_grpc_library.bzl b/swift/internal/swift_grpc_library.bzl index 2e44a6c64..5688ac18c 100644 --- a/swift/internal/swift_grpc_library.bzl +++ b/swift/internal/swift_grpc_library.bzl @@ -24,6 +24,7 @@ load( load( ":feature_names.bzl", "SWIFT_FEATURE_ENABLE_TESTING", + "SWIFT_FEATURE_GENERATE_FROM_RAW_PROTO_FILES", "SWIFT_FEATURE_NO_GENERATED_HEADER", ) load(":linking.bzl", "register_libraries_to_link") @@ -50,6 +51,7 @@ def _register_grpcswift_generate_action( proto_source_root, transitive_descriptor_sets, module_mapping_file, + generate_from_proto_sources, mkdir_and_run, protoc_executable, protoc_plugin_executable, @@ -70,6 +72,10 @@ def _register_grpcswift_generate_action( target being analyzed. May be `None`, in which case no module mapping will be passed (the case for leaf nodes in the dependency graph). + generate_from_proto_sources: True/False for is generation should happen + from proto source file vs just via the DescriptorSets. The Sets + don't have source info, so the generated sources won't have + comments (https://github.com/bazelbuild/bazel/issues/9337). mkdir_and_run: The `File` representing the `mkdir_and_run` executable. protoc_executable: The `File` representing the `protoc` executable. protoc_plugin_executable: The `File` representing the `protoc` plugin @@ -136,14 +142,34 @@ def _register_grpcswift_generate_action( module_mapping_file, format = "--swiftgrpc_opt=ProtoPathModuleMappings=%s", ) - protoc_args.add("--descriptor_set_in") - protoc_args.add_joined(transitive_descriptor_sets, join_with = ":") + + protoc_args.add_joined( + transitive_descriptor_sets, + join_with = ":", + format_joined = "--descriptor_set_in=%s", + omit_if_empty = True, + ) + + if generate_from_proto_sources: + # ProtoCompileActionBuilder.java's XPAND_TRANSITIVE_PROTO_PATH_FLAGS + # leaves this off also. + if proto_source_root != ".": + protoc_args.add(proto_source_root, format = "--proto_path=%s") + + # Follow ProtoCompileActionBuilder.java's + # ExpandImportArgsFn::expandToCommandLine() logic and provide a mapping + # for each file to the proto path. + for f in direct_srcs: + protoc_args.add("-I%s=%s" % (proto_import_path(f, proto_source_root), f.path)) + protoc_args.add_all([ proto_import_path(f, proto_source_root) for f in direct_srcs ]) additional_command_inputs = [] + if generate_from_proto_sources: + additional_command_inputs.extend(direct_srcs) if module_mapping_file: additional_command_inputs.append(module_mapping_file) @@ -182,16 +208,41 @@ def _swift_grpc_library_impl(ctx): swift_toolchain = ctx.attr._toolchain[SwiftToolchainInfo] - # Direct sources are passed as arguments to protoc to generate *only* the - # files in this target, but we need to pass the transitive sources as inputs - # to the generating action so that all the dependent files are available for - # protoc to parse. - # Instead of providing all those files and opening/reading them, we use - # protoc's support for reading descriptor sets to resolve things. - direct_srcs = ctx.attr.srcs[0][ProtoInfo].direct_sources - transitive_descriptor_sets = ( - ctx.attr.srcs[0][ProtoInfo].transitive_descriptor_sets + unsupported_features = ctx.disabled_features + if ctx.attr.flavor != "client_stubs": + unsupported_features.append(SWIFT_FEATURE_ENABLE_TESTING) + + feature_configuration = swift_common.configure_features( + ctx = ctx, + requested_features = ctx.features + [SWIFT_FEATURE_NO_GENERATED_HEADER], + swift_toolchain = swift_toolchain, + unsupported_features = unsupported_features, + ) + + generate_from_proto_sources = swift_common.is_enabled( + feature_configuration = feature_configuration, + feature_name = SWIFT_FEATURE_GENERATE_FROM_RAW_PROTO_FILES, ) + + srcs_proto_info = ctx.attr.srcs[0][ProtoInfo] + + # Only the files for direct sources should be generated, but the + # transitive descriptor sets are still need to be able to parse/load + # those descriptors. + direct_srcs = srcs_proto_info.direct_sources + if generate_from_proto_sources: + # Take the transitive descriptor sets from the proto_library deps, + # so the direct sources won't be in any descriptor sets to reduce + # the input to the action (and what protoc has to parse). + direct_descriptor_set = srcs_proto_info.direct_descriptor_set + transitive_descriptor_sets = depset(direct = [ + x + for x in srcs_proto_info.transitive_descriptor_sets.to_list() + if x != direct_descriptor_set + ]) + else: + transitive_descriptor_sets = srcs_proto_info.transitive_descriptor_sets + deps = ctx.attr.deps minimal_module_mappings = deps[0][SwiftProtoInfo].module_mappings @@ -210,9 +261,10 @@ def _swift_grpc_library_impl(ctx): ctx.label, ctx.actions, direct_srcs, - ctx.attr.srcs[0][ProtoInfo].proto_source_root, + srcs_proto_info.proto_source_root, transitive_descriptor_sets, transitive_module_mapping_file, + generate_from_proto_sources, ctx.executable._mkdir_and_run, ctx.executable._protoc, ctx.executable._protoc_gen_swiftgrpc, @@ -226,17 +278,6 @@ def _swift_grpc_library_impl(ctx): # action. compile_deps = deps + ctx.attr._proto_support - unsupported_features = ctx.disabled_features - if ctx.attr.flavor != "client_stubs": - unsupported_features.append(SWIFT_FEATURE_ENABLE_TESTING) - - feature_configuration = swift_common.configure_features( - ctx = ctx, - requested_features = ctx.features + [SWIFT_FEATURE_NO_GENERATED_HEADER], - swift_toolchain = swift_toolchain, - unsupported_features = unsupported_features, - ) - module_name = swift_common.derive_module_name(ctx.label) compilation_outputs = swift_common.compile( From 6ae82f57ebefa13df5ce1daf7a2fd3080e41df55 Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Wed, 9 Sep 2020 14:44:24 -0700 Subject: [PATCH 019/152] Remove unused value. RELNOTES: None PiperOrigin-RevId: 330801521 --- swift/internal/swift_autoconfiguration.bzl | 2 -- 1 file changed, 2 deletions(-) diff --git a/swift/internal/swift_autoconfiguration.bzl b/swift/internal/swift_autoconfiguration.bzl index cc585ca46..48b772acf 100644 --- a/swift/internal/swift_autoconfiguration.bzl +++ b/swift/internal/swift_autoconfiguration.bzl @@ -255,8 +255,6 @@ def _create_xcode_toolchain(repository_ctx): Args: repository_ctx: The repository rule context. """ - path_to_swiftc = repository_ctx.which("swiftc") - feature_values = [ # TODO: This is being enabled here, rather than in the toolchain rule # implementations, so that we can provide a way to optionally turn it From 4f4b7f012e714eaecc7f16534690e1183aa1b9ca Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Thu, 17 Sep 2020 09:07:43 -0700 Subject: [PATCH 020/152] Don't propagate an empty module map for `{cc,objc}_library` targets that don't have any headers (and that don't specify an explicit module map using the `module_map` attribute). This is typically the case for libraries that group other libraries via their `deps`. Users mistakenly import these thinking they're required to use the underlying declarations, but they do nothing (except make more work for the compiler). PiperOrigin-RevId: 332246632 (cherry picked from commit 639ecfa9a164fc94ed205c25e6e43353ca0699c1) --- swift/internal/swift_clang_module_aspect.bzl | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/swift/internal/swift_clang_module_aspect.bzl b/swift/internal/swift_clang_module_aspect.bzl index 00dec750f..2b871c685 100644 --- a/swift/internal/swift_clang_module_aspect.bzl +++ b/swift/internal/swift_clang_module_aspect.bzl @@ -179,6 +179,16 @@ def _module_info_for_target( if not aspect_ctx.rule.kind == "objc_library": return None, module_maps[0] + # If an `objc_library` doesn't have any headers (and doesn't specify an + # explicit module map), then don't generate or propagate a module map + # for it. Such modules define nothing and only waste space on the + # compilation command line and add more work for the compiler. + if not getattr(attr, "module_map", None) and not ( + compilation_context.direct_headers or + compilation_context.direct_textual_headers + ): + return None, None + module_name = getattr(attr, "module_name", None) if not module_name: module_name = derive_module_name(target.label) From d2efe38e58a060b619aa7f2db19ed66408bfc833 Mon Sep 17 00:00:00 2001 From: Andre Brisco Date: Sun, 13 Sep 2020 13:59:16 -0700 Subject: [PATCH 021/152] Added helper macro for declaring transitive dependencies --- README.md | 41 +++++++++++++++++------------------------ swift/extras.bzl | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 24 deletions(-) create mode 100644 swift/extras.bzl diff --git a/README.md b/README.md index 9fce91f3a..cee0d0ce3 100644 --- a/README.md +++ b/README.md @@ -63,18 +63,11 @@ load( swift_rules_dependencies() load( - "@build_bazel_apple_support//lib:repositories.bzl", - "apple_support_dependencies", + "@build_bazel_rules_swift//swift:extras.bzl", + "swift_rules_extra_dependencies", ) -apple_support_dependencies() - -load( - "@com_google_protobuf//:protobuf_deps.bzl", - "protobuf_deps", -) - -protobuf_deps() +swift_rules_extra_dependencies() ``` The `swift_rules_dependencies` macro creates a toolchain appropriate for your @@ -98,7 +91,7 @@ uses `clang`. `/Library/Developer/Toolchains` instead of Xcode's default. To do so, pass the following flag to Bazel: -``` +```lang-none --define=SWIFT_CUSTOM_TOOLCHAIN=toolchain.id ``` @@ -107,7 +100,7 @@ toolchain's Info.plist file. To list the available toolchains and their bundle identifiers, you can run: -``` +```command bazel run @build_bazel_rules_swift//tools/dump_toolchains ``` @@ -116,13 +109,13 @@ encountered first on your `PATH`. ## Future Work -* Support for building and linking to shared libraries (`.dylib`/`.so`) written +- Support for building and linking to shared libraries (`.dylib`/`.so`) written in Swift. -* Interoperability with Swift Package Manager. -* Migration to the Bazel platforms/toolchains APIs. -* Support for multiple toolchains, and support for non-Xcode toolchains on +- Interoperability with Swift Package Manager. +- Migration to the Bazel platforms/toolchains APIs. +- Support for multiple toolchains, and support for non-Xcode toolchains on macOS. -* Automatically download a Linux toolchain from [swift.org](https://swift.org) +- Automatically download a Linux toolchain from [swift.org](https://swift.org) if one is not already installed. ## Acknowledgments @@ -130,10 +123,10 @@ encountered first on your `PATH`. We gratefully acknowledge the following external packages that rules_swift depends on: -* [Apple Support for Bazel](https://github.com/bazelbuild/apple_support) (Google) -* [Bazel Skylib](https://github.com/bazelbuild/bazel-skylib) (Google) -* [JSON for Modern C++](https://github.com/nlohmann/json) (Niels Lohmann) -* [Protocol Buffers](https://github.com/protocolbuffers/protobuf) (Google) -* [Swift gRPC](https://github.com/grpc/grpc-swift) (Google) -* [Swift Protobuf](https://github.com/apple/swift-protobuf) (Apple) -* [zlib](https://www.zlib.net) (Jean-loup Gailly and Mark Adler) +- [Apple Support for Bazel](https://github.com/bazelbuild/apple_support) (Google) +- [Bazel Skylib](https://github.com/bazelbuild/bazel-skylib) (Google) +- [JSON for Modern C++](https://github.com/nlohmann/json) (Niels Lohmann) +- [Protocol Buffers](https://github.com/protocolbuffers/protobuf) (Google) +- [Swift gRPC](https://github.com/grpc/grpc-swift) (Google) +- [Swift Protobuf](https://github.com/apple/swift-protobuf) (Apple) +- [zlib](https://www.zlib.net) (Jean-loup Gailly and Mark Adler) diff --git a/swift/extras.bzl b/swift/extras.bzl new file mode 100644 index 000000000..a8003b0f3 --- /dev/null +++ b/swift/extras.bzl @@ -0,0 +1,33 @@ +# Copyright 2018 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Definitions for handling Bazel transitive repositories used by the +dependencies of the Swift rules. +""" + +load("@build_bazel_apple_support//lib:repositories.bzl", "apple_support_dependencies") +load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps") + +def swift_rules_extra_dependencies(): + """Fetches transitive repositories of the dependencies of `rules_swift`. + + Users should call this macro in their `WORKSPACE` following the use of + `swift_rules_dependencies` to ensure that all of the dependencies of + the Swift rules are downloaded and that they are isolated from changes + to those dependencies. + """ + + apple_support_dependencies() + + protobuf_deps() From b7a269355fc9852a885c5becbdeb1497cf787164 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Mon, 21 Sep 2020 14:33:46 -0700 Subject: [PATCH 022/152] Update README shas --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cee0d0ce3..c8090067f 100644 --- a/README.md +++ b/README.md @@ -51,8 +51,8 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "build_bazel_rules_swift", - sha256 = "cea22c0616d797e494d7844a9b604520c87f53c81de49613a7e679ec5b821620", - url = "https://github.com/bazelbuild/rules_swift/releases/download/0.14.0/rules_swift.0.14.0.tar.gz", + sha256 = "d2f38c33dc82cf3160c59342203d31a030e53ebe8f4c7365add7a549223f9c62", + url = "https://github.com/bazelbuild/rules_swift/releases/download/0.15.0/rules_swift.0.15.0.tar.gz", ) load( From 9d472c1a0124a2f06ee234ce64fa174cba0637c9 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Thu, 8 Oct 2020 13:17:37 -0700 Subject: [PATCH 023/152] Fix buildifier warning --- test/rules/provider_test.bzl | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/test/rules/provider_test.bzl b/test/rules/provider_test.bzl index eba66af58..42799fa79 100644 --- a/test/rules/provider_test.bzl +++ b/test/rules/provider_test.bzl @@ -23,15 +23,19 @@ load( "unittest", ) -# A sentinel value returned by `_evaluate_field` when a `None` value is -# encountered during the evaluation of a dotted path on any component other than -# the last component. This allows the caller to distinguish between a legitimate -# `None` value being returned by the entire path vs. an unexpected `None` in an -# earlier component. -# -# A `provider` is used here because it is a simple way of getting a known unique -# object from Bazel that cannot be equal to any other object. -_EVALUATE_FIELD_FAILED = provider() +_EVALUATE_FIELD_FAILED = provider( + doc = """ +A sentinel value returned by `_evaluate_field` when a `None` value is +encountered during the evaluation of a dotted path on any component other than +the last component. This allows the caller to distinguish between a legitimate +`None` value being returned by the entire path vs. an unexpected `None` in an +earlier component. + +A `provider` is used here because it is a simple way of getting a known unique +object from Bazel that cannot be equal to any other object. +""", + fields = [], +) def _evaluate_field(env, source, field): """Evaluates a field or field path on an object and returns its value. From abc377ef237b203aa87fc2b4d5b9a12c382c8859 Mon Sep 17 00:00:00 2001 From: Googler Date: Wed, 30 Sep 2020 09:03:05 -0700 Subject: [PATCH 024/152] Update rules_swift to use the toolchain transition. This is phase 2 of of the switch to toolchain transitions. See https://github.com/bazelbuild/bazel/issues/11584 for details. This shouldn't be merged into rules_swift's master branch until https://cs.opensource.google/bazel/bazel/+/58fdf63d81cc71f0315918b111fc56f4c039f1a5 is in a Bazel release (which should be 3.7, https://github.com/bazelbuild/bazel/issues/12188). PiperOrigin-RevId: 334610489 --- swift/internal/swift_toolchain.bzl | 1 + swift/internal/xcode_swift_toolchain.bzl | 1 + 2 files changed, 2 insertions(+) diff --git a/swift/internal/swift_toolchain.bzl b/swift/internal/swift_toolchain.bzl index d752e9107..40e0ee879 100644 --- a/swift/internal/swift_toolchain.bzl +++ b/swift/internal/swift_toolchain.bzl @@ -275,5 +275,6 @@ for incremental compilation using a persistent mode. doc = "Represents a Swift compiler toolchain.", fragments = ["swift"], toolchains = ["@bazel_tools//tools/cpp:toolchain_type"], + incompatible_use_toolchain_transition = True, implementation = _swift_toolchain_impl, ) diff --git a/swift/internal/xcode_swift_toolchain.bzl b/swift/internal/xcode_swift_toolchain.bzl index 0c60d2b91..4e0209835 100644 --- a/swift/internal/xcode_swift_toolchain.bzl +++ b/swift/internal/xcode_swift_toolchain.bzl @@ -692,5 +692,6 @@ for incremental compilation using a persistent mode. "swift", ], toolchains = ["@bazel_tools//tools/cpp:toolchain_type"], + incompatible_use_toolchain_transition = True, implementation = _xcode_swift_toolchain_impl, ) From 8e3715a25ba9352e8fe153be2ed7b549e376dc45 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Thu, 8 Oct 2020 13:07:05 -0700 Subject: [PATCH 025/152] Update apple_support --- swift/repositories.bzl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/swift/repositories.bzl b/swift/repositories.bzl index 73e930295..783a49039 100644 --- a/swift/repositories.bzl +++ b/swift/repositories.bzl @@ -51,9 +51,9 @@ def swift_rules_dependencies(): http_archive, name = "build_bazel_apple_support", urls = [ - "https://github.com/bazelbuild/apple_support/releases/download/0.7.2/apple_support.0.7.2.tar.gz", + "https://github.com/bazelbuild/apple_support/releases/download/0.9.0/apple_support.0.9.0.tar.gz", ], - sha256 = "9114c452eee622598cf9cdc90ecb12b06af7f914f33440b26deba9a9704d450c", + sha256 = "36d60bce680446ab534b141c47f2aef6b9c598267ef3450b7d74b9d81e1fd6bd", ) _maybe( From 3ad9d41be80c08192c7f48d528b0469b1aec5955 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Tue, 13 Oct 2020 08:44:52 -0700 Subject: [PATCH 026/152] Implement -coverage-prefix-map feature (#489) --- swift/internal/compiling.bzl | 14 +++++++++ swift/internal/feature_names.bzl | 5 +++ test/BUILD | 3 ++ test/coverage_settings_tests.bzl | 53 ++++++++++++++++++++++++++++++++ tools/worker/swift_runner.cc | 6 ++++ 5 files changed, 81 insertions(+) create mode 100644 test/coverage_settings_tests.bzl diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index 13fb43cb3..a752d4147 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -32,6 +32,7 @@ load( "SWIFT_FEATURE_CACHEABLE_SWIFTMODULES", "SWIFT_FEATURE_COMPILE_STATS", "SWIFT_FEATURE_COVERAGE", + "SWIFT_FEATURE_COVERAGE_PREFIX_MAP", "SWIFT_FEATURE_DBG", "SWIFT_FEATURE_DEBUG_PREFIX_MAP", "SWIFT_FEATURE_EMIT_C_MODULE", @@ -293,6 +294,19 @@ def compile_action_configs(): [SWIFT_FEATURE_DEBUG_PREFIX_MAP, SWIFT_FEATURE_FULL_DEBUG_INFO], ], ), + + # Make paths written into coverage info workspace-relative. + swift_toolchain_config.action_config( + actions = [swift_action_names.COMPILE], + configurators = [ + swift_toolchain_config.add_arg( + "-Xwrapped-swift=-coverage-prefix-pwd-is-dot", + ), + ], + features = [ + [SWIFT_FEATURE_COVERAGE_PREFIX_MAP, SWIFT_FEATURE_COVERAGE], + ], + ), ] #### Coverage and sanitizer instrumentation flags diff --git a/swift/internal/feature_names.bzl b/swift/internal/feature_names.bzl index da282aeef..ad3ed8969 100644 --- a/swift/internal/feature_names.bzl +++ b/swift/internal/feature_names.bzl @@ -61,6 +61,11 @@ SWIFT_FEATURE_COMPILE_STATS = "swift.compile_stats" # builds. SWIFT_FEATURE_DEBUG_PREFIX_MAP = "swift.debug_prefix_map" +# If enabled, coverage builds will use the `-coverage-prefix-map` feature to +# remap the current working directory to `.`, which increases reproducibility +# of remote builds. +SWIFT_FEATURE_COVERAGE_PREFIX_MAP = "swift.coverage_prefix_map" + # If enabled, C and Objective-C libraries that are direct or transitive # dependencies of a Swift library will emit explicit precompiled modules that # are compatible with Swift's ClangImporter and propagate them up the build diff --git a/test/BUILD b/test/BUILD index 38d7e1de4..ea685d048 100644 --- a/test/BUILD +++ b/test/BUILD @@ -1,5 +1,6 @@ load("@bazel_skylib//:bzl_library.bzl", "bzl_library") load(":debug_settings_tests.bzl", "debug_settings_test_suite") +load(":coverage_settings_tests.bzl", "coverage_settings_test_suite") load(":generated_header_tests.bzl", "generated_header_test_suite") load(":private_deps_tests.bzl", "private_deps_test_suite") load(":swift_through_non_swift_tests.bzl", "swift_through_non_swift_test_suite") @@ -8,6 +9,8 @@ licenses(["notice"]) debug_settings_test_suite() +coverage_settings_test_suite() + generated_header_test_suite() private_deps_test_suite() diff --git a/test/coverage_settings_tests.bzl b/test/coverage_settings_tests.bzl new file mode 100644 index 000000000..e16d7da10 --- /dev/null +++ b/test/coverage_settings_tests.bzl @@ -0,0 +1,53 @@ +"""Tests for coverage-related command line flags under various configs.""" + +load( + "@build_bazel_rules_swift//test/rules:action_command_line_test.bzl", + "make_action_command_line_test_rule", +) + +default_coverage_test = make_action_command_line_test_rule( + config_settings = { + "//command_line_option:collect_code_coverage": "true", + }, +) + +coverage_prefix_map_test = make_action_command_line_test_rule( + config_settings = { + "//command_line_option:collect_code_coverage": "true", + "//command_line_option:features": [ + "swift.coverage_prefix_map", + ], + }, +) + +def coverage_settings_test_suite(name = "coverage_settings"): + """Test suite for coverage options. + + Args: + name: The name prefix for all the nested tests + """ + default_coverage_test( + name = "{}_default_coverage".format(name), + tags = [name], + expected_argv = [ + "-profile-generate", + "-profile-coverage-mapping", + ], + not_expected_argv = [ + "-Xwrapped-swift=-coverage-prefix-pwd-is-dot", + ], + mnemonic = "SwiftCompile", + target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", + ) + + coverage_prefix_map_test( + name = "{}_prefix_map".format(name), + tags = [name], + expected_argv = [ + "-profile-generate", + "-profile-coverage-mapping", + "-Xwrapped-swift=-coverage-prefix-pwd-is-dot", + ], + mnemonic = "SwiftCompile", + target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", + ) diff --git a/tools/worker/swift_runner.cc b/tools/worker/swift_runner.cc index eca0f2993..c1a387f66 100644 --- a/tools/worker/swift_runner.cc +++ b/tools/worker/swift_runner.cc @@ -187,6 +187,12 @@ bool SwiftRunner::ProcessArgument( consumer("-debug-prefix-map"); consumer(GetCurrentDirectory() + "=."); changed = true; + } else if (arg == "-Xwrapped-swift=-coverage-prefix-pwd-is-dot") { + // Get the actual current working directory (the workspace root), which we + // didn't know at analysis time. + consumer("-coverage-prefix-map"); + consumer(GetCurrentDirectory() + "=."); + changed = true; } else if (arg == "-Xwrapped-swift=-ephemeral-module-cache") { // Create a temporary directory to hold the module cache, which will be // deleted after compilation is finished. From cfd9e36f870b8305c1fd1e53c85b2f6d1afdb808 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Wed, 14 Oct 2020 09:21:14 -0700 Subject: [PATCH 027/152] Update worker docstring with example (#505) This comment made it sound like this shouldn't ever happen, but if you pass `-rpath @loader_path/something` you will always hit this case. --- tools/worker/swift_runner.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/worker/swift_runner.cc b/tools/worker/swift_runner.cc index c1a387f66..cca929f63 100644 --- a/tools/worker/swift_runner.cc +++ b/tools/worker/swift_runner.cc @@ -130,7 +130,7 @@ bool SwiftRunner::ProcessPossibleResponseFile( auto path = arg.substr(1); std::ifstream original_file(path); // If we couldn't open it, maybe it's not a file; maybe it's just some other - // argument that starts with "@". (Unlikely, but it's safer to check.) + // argument that starts with "@" such as "@loader_path/..." if (!original_file.good()) { consumer(arg); return false; From dcc52352949d5ccf184f5d202aa5084957b0e103 Mon Sep 17 00:00:00 2001 From: Kanglei Fang Date: Tue, 20 Oct 2020 14:13:39 -0700 Subject: [PATCH 028/152] Introduce feature to register a separate action to generate swift derived files (#504) Co-authored-by: Keith Smiley --- swift/internal/actions.bzl | 4 + swift/internal/compiling.bzl | 284 +++++++++++++++++---- swift/internal/feature_names.bzl | 9 + swift/internal/swift_autoconfiguration.bzl | 11 + swift/internal/swift_toolchain.bzl | 19 +- swift/internal/xcode_swift_toolchain.bzl | 30 ++- test/BUILD | 3 + test/split_derived_files_tests.bzl | 226 ++++++++++++++++ 8 files changed, 519 insertions(+), 67 deletions(-) create mode 100644 test/split_derived_files_tests.bzl diff --git a/swift/internal/actions.bzl b/swift/internal/actions.bzl index 931d22f51..fd7773877 100644 --- a/swift/internal/actions.bzl +++ b/swift/internal/actions.bzl @@ -37,6 +37,10 @@ swift_action_names = struct( # Precompiles an explicit module for a C/Objective-C module map and its # headers, emitting a `.pcm` file. PRECOMPILE_C_MODULE = "SwiftPrecompileCModule", + + # Produces files that are usually fallout of the compilation such as + # .swiftmodule, -Swift.h and more. + DERIVE_FILES = "SwiftDeriveFiles", ) def _apply_configurator(configurator, prerequisites, args): diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index a752d4147..778a6ae04 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -39,6 +39,7 @@ load( "SWIFT_FEATURE_EMIT_SWIFTINTERFACE", "SWIFT_FEATURE_ENABLE_BATCH_MODE", "SWIFT_FEATURE_ENABLE_LIBRARY_EVOLUTION", + "SWIFT_FEATURE_ENABLE_SKIP_FUNCTION_BODIES", "SWIFT_FEATURE_ENABLE_TESTING", "SWIFT_FEATURE_FASTBUILD", "SWIFT_FEATURE_FULL_DEBUG_INFO", @@ -52,6 +53,7 @@ load( "SWIFT_FEATURE_OPT", "SWIFT_FEATURE_OPT_USES_OSIZE", "SWIFT_FEATURE_OPT_USES_WMO", + "SWIFT_FEATURE_SPLIT_DERIVED_FILES_GENERATION", "SWIFT_FEATURE_STRICT_MODULES", "SWIFT_FEATURE_SUPPORTS_LIBRARY_EVOLUTION", "SWIFT_FEATURE_SYSTEM_MODULE", @@ -106,6 +108,10 @@ def compile_action_configs(): actions = [swift_action_names.COMPILE], configurators = [_output_object_or_file_map_configurator], ), + swift_toolchain_config.action_config( + actions = [swift_action_names.DERIVE_FILES], + configurators = [_output_swiftmodule_or_file_map_configurator], + ), # Emit precompiled Clang modules, and embed all files that were read # during compilation into the PCM. @@ -131,11 +137,19 @@ def compile_action_configs(): swift_toolchain_config.action_config( actions = [swift_action_names.COMPILE], configurators = [_emit_module_path_configurator], + not_features = [SWIFT_FEATURE_SPLIT_DERIVED_FILES_GENERATION], + ), + swift_toolchain_config.action_config( + actions = [swift_action_names.DERIVE_FILES], + configurators = [_emit_module_path_configurator], ), # Configure library evolution and the path to the .swiftinterface file. swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], configurators = [ swift_toolchain_config.add_arg("-enable-library-evolution"), ], @@ -145,23 +159,39 @@ def compile_action_configs(): ], ), swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], configurators = [_emit_module_interface_path_configurator], features = [ SWIFT_FEATURE_SUPPORTS_LIBRARY_EVOLUTION, SWIFT_FEATURE_EMIT_SWIFTINTERFACE, ], ), + + # Configure the path to the emitted *-Swift.h file. swift_toolchain_config.action_config( actions = [swift_action_names.COMPILE], configurators = [_emit_objc_header_path_configurator], + not_features = [ + [SWIFT_FEATURE_NO_GENERATED_HEADER], + [SWIFT_FEATURE_SPLIT_DERIVED_FILES_GENERATION], + ], + ), + swift_toolchain_config.action_config( + actions = [swift_action_names.DERIVE_FILES], + configurators = [_emit_objc_header_path_configurator], not_features = [SWIFT_FEATURE_NO_GENERATED_HEADER], ), # Configure the location where compiler performance statistics are # dumped. swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], configurators = [_stats_output_dir_configurator], features = [SWIFT_FEATURE_COMPILE_STATS], ), @@ -177,14 +207,20 @@ def compile_action_configs(): # Define appropriate conditional compilation symbols depending on the # build mode. swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], configurators = [ swift_toolchain_config.add_arg("-DDEBUG"), ], features = [[SWIFT_FEATURE_DBG], [SWIFT_FEATURE_FASTBUILD]], ), swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], configurators = [ swift_toolchain_config.add_arg("-DNDEBUG"), ], @@ -195,14 +231,20 @@ def compile_action_configs(): # `-O` unless the `swift.opt_uses_osize` feature is enabled, then use # `-Osize`. swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], configurators = [ swift_toolchain_config.add_arg("-Onone"), ], features = [[SWIFT_FEATURE_DBG], [SWIFT_FEATURE_FASTBUILD]], ), swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], configurators = [ swift_toolchain_config.add_arg("-O"), ], @@ -210,7 +252,10 @@ def compile_action_configs(): not_features = [SWIFT_FEATURE_OPT_USES_OSIZE], ), swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], configurators = [ swift_toolchain_config.add_arg("-Osize"), ], @@ -220,7 +265,10 @@ def compile_action_configs(): # If the `swift.opt_uses_wmo` feature is enabled, opt builds should also # automatically imply whole-module optimization. swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], configurators = [ swift_toolchain_config.add_arg("-whole-module-optimization"), ], @@ -230,7 +278,10 @@ def compile_action_configs(): # Enable or disable serialization of debugging options into # swiftmodules. swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], configurators = [ swift_toolchain_config.add_arg( "-Xfrontend", @@ -240,7 +291,10 @@ def compile_action_configs(): features = [SWIFT_FEATURE_CACHEABLE_SWIFTMODULES], ), swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], configurators = [ swift_toolchain_config.add_arg( "-Xfrontend", @@ -255,7 +309,10 @@ def compile_action_configs(): # Enable testability if requested. swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], configurators = [ swift_toolchain_config.add_arg("-enable-testing"), ], @@ -267,12 +324,18 @@ def compile_action_configs(): # `dsymutil` produces spurious warnings about symbols in the debug map # when run on DI emitted by `-gline-tables-only`. swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], configurators = [swift_toolchain_config.add_arg("-g")], features = [[SWIFT_FEATURE_DBG], [SWIFT_FEATURE_FULL_DEBUG_INFO]], ), swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], configurators = [ swift_toolchain_config.add_arg("-gline-tables-only"), ], @@ -282,7 +345,10 @@ def compile_action_configs(): # Make paths written into debug info workspace-relative. swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], configurators = [ swift_toolchain_config.add_arg( "-Xwrapped-swift=-debug-prefix-pwd-is-dot", @@ -297,7 +363,10 @@ def compile_action_configs(): # Make paths written into coverage info workspace-relative. swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], configurators = [ swift_toolchain_config.add_arg( "-Xwrapped-swift=-coverage-prefix-pwd-is-dot", @@ -316,7 +385,10 @@ def compile_action_configs(): # supporting them either. action_configs += [ swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], configurators = [ swift_toolchain_config.add_arg("-profile-generate"), swift_toolchain_config.add_arg("-profile-coverage-mapping"), @@ -324,14 +396,20 @@ def compile_action_configs(): features = [SWIFT_FEATURE_COVERAGE], ), swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], configurators = [ swift_toolchain_config.add_arg("-sanitize=address"), ], features = ["asan"], ), swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], configurators = [ swift_toolchain_config.add_arg("-sanitize=thread"), ], @@ -346,6 +424,7 @@ def compile_action_configs(): swift_toolchain_config.action_config( actions = [ swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, swift_action_names.PRECOMPILE_C_MODULE, ], configurators = [ @@ -361,7 +440,10 @@ def compile_action_configs(): # Configure how implicit modules are handled--either using the module # cache, or disabled completely when using explicit modules. swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], configurators = [_global_module_cache_configurator], features = [ SWIFT_FEATURE_IMPLICIT_MODULES, @@ -369,7 +451,10 @@ def compile_action_configs(): ], ), swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], configurators = [ swift_toolchain_config.add_arg( "-Xwrapped-swift=-ephemeral-module-cache", @@ -381,6 +466,7 @@ def compile_action_configs(): swift_toolchain_config.action_config( actions = [ swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, swift_action_names.PRECOMPILE_C_MODULE, ], configurators = [ @@ -449,12 +535,18 @@ def compile_action_configs(): #### Search paths for Swift module dependencies action_configs.extend([ swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], configurators = [_dependencies_swiftmodules_configurator], not_features = [SWIFT_FEATURE_VFSOVERLAY], ), swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], configurators = [ _dependencies_swiftmodules_vfsoverlay_configurator, ], @@ -467,6 +559,7 @@ def compile_action_configs(): swift_toolchain_config.action_config( actions = [ swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, swift_action_names.PRECOMPILE_C_MODULE, ], configurators = [_framework_search_paths_configurator], @@ -479,6 +572,7 @@ def compile_action_configs(): swift_toolchain_config.action_config( actions = [ swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, swift_action_names.PRECOMPILE_C_MODULE, ], configurators = [ @@ -492,6 +586,7 @@ def compile_action_configs(): swift_toolchain_config.action_config( actions = [ swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, swift_action_names.PRECOMPILE_C_MODULE, ], configurators = [_dependencies_clang_modules_configurator], @@ -500,6 +595,7 @@ def compile_action_configs(): swift_toolchain_config.action_config( actions = [ swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, swift_action_names.PRECOMPILE_C_MODULE, ], configurators = [_dependencies_clang_modulemaps_configurator], @@ -514,6 +610,7 @@ def compile_action_configs(): swift_toolchain_config.action_config( actions = [ swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, swift_action_names.PRECOMPILE_C_MODULE, ], configurators = [ @@ -532,7 +629,10 @@ def compile_action_configs(): # flags themselves, since some Swift users enable it there as a build # performance hack. swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], configurators = [_batch_mode_configurator], features = [SWIFT_FEATURE_ENABLE_BATCH_MODE], not_features = [SWIFT_FEATURE_OPT, SWIFT_FEATURE_OPT_USES_WMO], @@ -540,7 +640,10 @@ def compile_action_configs(): # Set the number of threads to use for WMO. swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], configurators = [ partial.make( _wmo_thread_count_configurator, @@ -552,7 +655,10 @@ def compile_action_configs(): features = [SWIFT_FEATURE_OPT, SWIFT_FEATURE_OPT_USES_WMO], ), swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], configurators = [ partial.make( _wmo_thread_count_configurator, @@ -568,14 +674,29 @@ def compile_action_configs(): swift_toolchain_config.action_config( actions = [ swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, swift_action_names.PRECOMPILE_C_MODULE, ], configurators = [_module_name_configurator], ), + # Pass extra flags for swiftmodule only compilations + swift_toolchain_config.action_config( + actions = [swift_action_names.DERIVE_FILES], + configurators = [ + swift_toolchain_config.add_arg( + "-experimental-skip-non-inlinable-function-bodies", + ), + ], + features = [SWIFT_FEATURE_ENABLE_SKIP_FUNCTION_BODIES], + ), + # Configure index-while-building. swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], configurators = [_index_while_building_configurator], features = [SWIFT_FEATURE_INDEX_WHILE_BUILDING], ), @@ -583,13 +704,19 @@ def compile_action_configs(): # User-defined conditional compilation flags (defined for Swift; those # passed directly to ClangImporter are handled above). swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], configurators = [_conditional_compilation_flag_configurator], ), # Disable auto-linking for prebuilt static frameworks. swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], configurators = [_static_frameworks_disable_autolink_configurator], ), ] @@ -600,7 +727,10 @@ def compile_action_configs(): # the rule implementations as a last resort. action_configs.append( swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], configurators = [_user_compile_flags_configurator], ), ) @@ -609,6 +739,7 @@ def compile_action_configs(): swift_toolchain_config.action_config( actions = [ swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, swift_action_names.PRECOMPILE_C_MODULE, ], configurators = [_source_files_configurator], @@ -618,33 +749,50 @@ def compile_action_configs(): # Add additional input files to the sandbox (does not modify flags). action_configs.append( swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], configurators = [_additional_inputs_configurator], ), ) return action_configs -def _output_object_or_file_map_configurator(prerequisites, args): - """Adds the output file map or single object file to the command line.""" - output_file_map = prerequisites.output_file_map +def _output_or_file_map(output_file_map, outputs, args): + """Adds the output file map or single file to the command line.""" if output_file_map: args.add("-output-file-map", output_file_map) return swift_toolchain_config.config_result( inputs = [output_file_map], ) - object_files = prerequisites.object_files - if len(object_files) != 1: + if len(outputs) != 1: fail( "Internal error: If not using an output file map, there should " + "only be a single object file expected as the output, but we " + - "found: {}".format(object_files), + "found: {}".format(outputs), ) - args.add("-o", object_files[0]) + args.add("-o", outputs[0]) return None +def _output_object_or_file_map_configurator(prerequisites, args): + """Adds the output file map or single object file to the command line.""" + return _output_or_file_map( + output_file_map = prerequisites.output_file_map, + outputs = prerequisites.object_files, + args = args, + ) + +def _output_swiftmodule_or_file_map_configurator(prerequisites, args): + """Adds the output file map or single object file to the command line.""" + return _output_or_file_map( + output_file_map = prerequisites.output_file_map, + outputs = [prerequisites.swiftmodule_file], + args = args, + ) + def _output_pcm_file_configurator(prerequisites, args): """Adds the `.pcm` output path to the command line.""" args.add("-o", prerequisites.pcm_file) @@ -1175,18 +1323,41 @@ def compile( target_name = target_name, user_compile_flags = copts + swift_toolchain.command_line_copts, ) - all_compile_outputs = compact([ - # The `.swiftmodule` file is explicitly listed as the first output - # because it will always exist and because Bazel uses it as a key for - # various things (such as the filename prefix for param files generated - # for that action). This guarantees some predictability. - compile_outputs.swiftmodule_file, - compile_outputs.swiftdoc_file, - compile_outputs.swiftinterface_file, - compile_outputs.generated_header_file, - compile_outputs.indexstore_directory, - compile_outputs.stats_directory, - ]) + compile_outputs.object_files + other_outputs + + split_derived_file_generation = is_feature_enabled( + feature_configuration = feature_configuration, + feature_name = SWIFT_FEATURE_SPLIT_DERIVED_FILES_GENERATION, + ) + + if split_derived_file_generation: + all_compile_outputs = compact([ + compile_outputs.swiftinterface_file, + compile_outputs.indexstore_directory, + compile_outputs.stats_directory, + ]) + compile_outputs.object_files + all_derived_outputs = compact([ + # The `.swiftmodule` file is explicitly listed as the first output + # because it will always exist and because Bazel uses it as a key for + # various things (such as the filename prefix for param files generated + # for that action). This guarantees some predictability. + compile_outputs.swiftmodule_file, + compile_outputs.swiftdoc_file, + compile_outputs.generated_header_file, + ]) + other_outputs + else: + all_compile_outputs = compact([ + # The `.swiftmodule` file is explicitly listed as the first output + # because it will always exist and because Bazel uses it as a key for + # various things (such as the filename prefix for param files generated + # for that action). This guarantees some predictability. + compile_outputs.swiftmodule_file, + compile_outputs.swiftdoc_file, + compile_outputs.swiftinterface_file, + compile_outputs.generated_header_file, + compile_outputs.indexstore_directory, + compile_outputs.stats_directory, + ]) + compile_outputs.object_files + other_outputs + all_derived_outputs = [] # Merge the providers from our dependencies so that we have one each for # `SwiftInfo`, `CcInfo`, and `apple_common.Objc`. Then we can pass these @@ -1260,6 +1431,19 @@ def compile( **struct_fields(compile_outputs) ) + if split_derived_file_generation: + run_toolchain_action( + actions = actions, + action_name = swift_action_names.DERIVE_FILES, + feature_configuration = feature_configuration, + outputs = all_derived_outputs, + prerequisites = prerequisites, + progress_message = ( + "Generating derived files for Swift module {}".format(module_name) + ), + swift_toolchain = swift_toolchain, + ) + run_toolchain_action( actions = actions, action_name = swift_action_names.COMPILE, diff --git a/swift/internal/feature_names.bzl b/swift/internal/feature_names.bzl index ad3ed8969..21257554a 100644 --- a/swift/internal/feature_names.bzl +++ b/swift/internal/feature_names.bzl @@ -227,3 +227,12 @@ SWIFT_FEATURE_NO_EMBED_DEBUG_MODULE = "swift.no_embed_debug_module" # files where the protoc command line might not be crafted correctly, so it # remains opt in. SWIFT_FEATURE_GENERATE_FROM_RAW_PROTO_FILES = "swift.generate_from_raw_proto_files" + +# If enabled and whole module optimisation is being used, the `*.swiftdoc`, +# `*.swiftmodule` and `*-Swift.h` are generated with a separate action +# rather than as part of the compilation. +SWIFT_FEATURE_SPLIT_DERIVED_FILES_GENERATION = "swift.split_derived_files_generation" + +# If enabled the skip function bodies frontend flag is passed when using derived +# files generation. This requires Swift 5.2 +SWIFT_FEATURE_ENABLE_SKIP_FUNCTION_BODIES = "swift.skip_function_bodies_for_derived_files" diff --git a/swift/internal/swift_autoconfiguration.bzl b/swift/internal/swift_autoconfiguration.bzl index 48b772acf..dbcf1af9b 100644 --- a/swift/internal/swift_autoconfiguration.bzl +++ b/swift/internal/swift_autoconfiguration.bzl @@ -28,6 +28,7 @@ load( "@build_bazel_rules_swift//swift/internal:feature_names.bzl", "SWIFT_FEATURE_DEBUG_PREFIX_MAP", "SWIFT_FEATURE_ENABLE_BATCH_MODE", + "SWIFT_FEATURE_ENABLE_SKIP_FUNCTION_BODIES", "SWIFT_FEATURE_IMPLICIT_MODULES", "SWIFT_FEATURE_MODULE_MAP_NO_PRIVATE_HEADERS", "SWIFT_FEATURE_SUPPORTS_PRIVATE_DEPS", @@ -75,6 +76,15 @@ def _check_enable_batch_mode(repository_ctx, swiftc_path, temp_dir): "-enable-batch-mode", ) +def _check_skip_function_bodies(repository_ctx, swiftc_path, temp_dir): + """Returns True if `swiftc` supports skip function bodies.""" + return _swift_succeeds( + repository_ctx, + swiftc_path, + "-version", + "-experimental-skip-non-inlinable-function-bodies", + ) + def _check_debug_prefix_map(repository_ctx, swiftc_path, temp_dir): """Returns True if `swiftc` supports debug prefix mapping.""" return _swift_succeeds( @@ -187,6 +197,7 @@ def _compute_feature_values(repository_ctx, swiftc_path): _FEATURE_CHECKS = { SWIFT_FEATURE_DEBUG_PREFIX_MAP: _check_debug_prefix_map, SWIFT_FEATURE_ENABLE_BATCH_MODE: _check_enable_batch_mode, + SWIFT_FEATURE_ENABLE_SKIP_FUNCTION_BODIES: _check_skip_function_bodies, SWIFT_FEATURE_SUPPORTS_PRIVATE_DEPS: _check_supports_private_deps, SWIFT_FEATURE_USE_RESPONSE_FILES: _check_use_response_files, } diff --git a/swift/internal/swift_toolchain.bzl b/swift/internal/swift_toolchain.bzl index 40e0ee879..c975787bc 100644 --- a/swift/internal/swift_toolchain.bzl +++ b/swift/internal/swift_toolchain.bzl @@ -59,6 +59,15 @@ def _all_tool_configs( """ _swift_driver_tool_config = swift_toolchain_config.driver_tool_config + compile_tool_config = _swift_driver_tool_config( + driver_mode = "swiftc", + swift_executable = swift_executable, + toolchain_root = toolchain_root, + use_param_file = use_param_file, + worker_mode = "persistent", + additional_tools = additional_tools, + ) + return { swift_action_names.AUTOLINK_EXTRACT: _swift_driver_tool_config( driver_mode = "swift-autolink-extract", @@ -67,14 +76,8 @@ def _all_tool_configs( worker_mode = "wrap", additional_tools = additional_tools, ), - swift_action_names.COMPILE: _swift_driver_tool_config( - driver_mode = "swiftc", - swift_executable = swift_executable, - toolchain_root = toolchain_root, - use_param_file = use_param_file, - worker_mode = "persistent", - additional_tools = additional_tools, - ), + swift_action_names.COMPILE: compile_tool_config, + swift_action_names.DERIVE_FILES: compile_tool_config, swift_action_names.MODULEWRAP: _swift_driver_tool_config( # This must come first after the driver name. args = ["-modulewrap"], diff --git a/swift/internal/xcode_swift_toolchain.bzl b/swift/internal/xcode_swift_toolchain.bzl index 4e0209835..5a0d2a6cf 100644 --- a/swift/internal/xcode_swift_toolchain.bzl +++ b/swift/internal/xcode_swift_toolchain.bzl @@ -34,6 +34,7 @@ load( "SWIFT_FEATURE_BUNDLED_XCTESTS", "SWIFT_FEATURE_DEBUG_PREFIX_MAP", "SWIFT_FEATURE_ENABLE_BATCH_MODE", + "SWIFT_FEATURE_ENABLE_SKIP_FUNCTION_BODIES", "SWIFT_FEATURE_MODULE_MAP_HOME_IS_CWD", "SWIFT_FEATURE_MODULE_MAP_NO_PRIVATE_HEADERS", "SWIFT_FEATURE_SUPPORTS_LIBRARY_EVOLUTION", @@ -287,6 +288,7 @@ def _all_action_configs( swift_toolchain_config.action_config( actions = [ swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, swift_action_names.PRECOMPILE_C_MODULE, ], configurators = [ @@ -317,6 +319,7 @@ def _all_action_configs( swift_toolchain_config.action_config( actions = [ swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, swift_action_names.PRECOMPILE_C_MODULE, ], configurators = [swift_toolchain_config.add_arg("-embed-bitcode")], @@ -325,6 +328,7 @@ def _all_action_configs( swift_toolchain_config.action_config( actions = [ swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, swift_action_names.PRECOMPILE_C_MODULE, ], configurators = [ @@ -342,6 +346,7 @@ def _all_action_configs( swift_toolchain_config.action_config( actions = [ swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, swift_action_names.PRECOMPILE_C_MODULE, ], configurators = [ @@ -389,16 +394,19 @@ def _all_tool_configs( env = dict(env) env["TOOLCHAINS"] = custom_toolchain + tool_config = swift_toolchain_config.driver_tool_config( + driver_mode = "swiftc", + env = env, + execution_requirements = execution_requirements, + swift_executable = swift_executable, + toolchain_root = toolchain_root, + use_param_file = use_param_file, + worker_mode = "persistent", + ) + tool_configs = { - swift_action_names.COMPILE: swift_toolchain_config.driver_tool_config( - driver_mode = "swiftc", - env = env, - execution_requirements = execution_requirements, - swift_executable = swift_executable, - toolchain_root = toolchain_root, - use_param_file = use_param_file, - worker_mode = "persistent", - ), + swift_action_names.COMPILE: tool_config, + swift_action_names.DERIVE_FILES: tool_config, } # Xcode 12.0 implies Swift 5.3. @@ -594,6 +602,10 @@ def _xcode_swift_toolchain_impl(ctx): requested_features.append(SWIFT_FEATURE_SUPPORTS_LIBRARY_EVOLUTION) requested_features.append(SWIFT_FEATURE_SUPPORTS_PRIVATE_DEPS) + # Xcode 11.4 implies Swift 5.2. + if _is_xcode_at_least_version(xcode_config, "11.4"): + requested_features.append(SWIFT_FEATURE_ENABLE_SKIP_FUNCTION_BODIES) + command_line_copts = _command_line_objc_copts( ctx.var["COMPILATION_MODE"], ctx.fragments.objc, diff --git a/test/BUILD b/test/BUILD index ea685d048..70dcb37e7 100644 --- a/test/BUILD +++ b/test/BUILD @@ -4,6 +4,7 @@ load(":coverage_settings_tests.bzl", "coverage_settings_test_suite") load(":generated_header_tests.bzl", "generated_header_test_suite") load(":private_deps_tests.bzl", "private_deps_test_suite") load(":swift_through_non_swift_tests.bzl", "swift_through_non_swift_test_suite") +load(":split_derived_files_tests.bzl", "split_derived_files_test_suite") licenses(["notice"]) @@ -17,6 +18,8 @@ private_deps_test_suite() swift_through_non_swift_test_suite() +split_derived_files_test_suite() + test_suite( name = "all_tests", ) diff --git a/test/split_derived_files_tests.bzl b/test/split_derived_files_tests.bzl new file mode 100644 index 000000000..89baa9b47 --- /dev/null +++ b/test/split_derived_files_tests.bzl @@ -0,0 +1,226 @@ +"""Tests for derived files related command line flags under various configs.""" + +load( + "@build_bazel_rules_swift//test/rules:action_command_line_test.bzl", + "make_action_command_line_test_rule", +) +load( + "@build_bazel_rules_swift//test/rules:provider_test.bzl", + "make_provider_test_rule", +) + +default_no_split_test = make_action_command_line_test_rule() +default_no_split_provider_test = make_provider_test_rule() +split_swiftmodule_test = make_action_command_line_test_rule( + config_settings = { + "//command_line_option:features": [ + "swift.split_derived_files_generation", + ], + }, +) +split_swiftmodule_provider_test = make_provider_test_rule( + config_settings = { + "//command_line_option:features": [ + "swift.split_derived_files_generation", + ], + }, +) +split_swiftmodule_wmo_test = make_action_command_line_test_rule( + config_settings = { + "//command_line_option:swiftcopt": [ + "-whole-module-optimization", + ], + "//command_line_option:features": [ + "swift.split_derived_files_generation", + ], + }, +) +split_swiftmodule_wmo_provider_test = make_provider_test_rule( + config_settings = { + "//command_line_option:swiftcopt": [ + "-whole-module-optimization", + ], + "//command_line_option:features": [ + "swift.split_derived_files_generation", + ], + }, +) +split_swiftmodule_skip_function_bodies_test = make_action_command_line_test_rule( + config_settings = { + "//command_line_option:swiftcopt": [ + "-whole-module-optimization", + ], + "//command_line_option:features": [ + "swift.split_derived_files_generation", + "swift.enable_skip_function_bodies", + ], + }, +) + +def split_derived_files_test_suite(name = "split_derived_files"): + """Test suite for split derived files options. + + Args: + name: The name prefix for all the nested tests + """ + default_no_split_test( + name = "{}_default_no_split_args".format(name), + expected_argv = [ + "-emit-module-path", + "-emit-object", + ], + mnemonic = "SwiftCompile", + tags = [name], + target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", + ) + + default_no_split_provider_test( + name = "{}_default_no_split_provider".format(name), + expected_files = [ + "test_fixtures_debug_settings_simple.swiftmodule", + ], + field = "direct_modules.swift.swiftmodule", + provider = "SwiftInfo", + tags = [name], + target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", + ) + + default_no_split_provider_test( + name = "{}_default_no_split_provider_ccinfo".format(name), + expected_files = [ + "libsimple.a", + ], + field = "linking_context.libraries_to_link.pic_static_library!", + provider = "CcInfo", + tags = [name], + target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", + ) + + split_swiftmodule_test( + name = "{}_object_only".format(name), + expected_argv = [ + "-emit-object", + ], + mnemonic = "SwiftCompile", + not_expected_argv = [ + "-emit-module-path", + ], + tags = [name], + target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", + ) + + split_swiftmodule_test( + name = "{}_swiftmodule_only".format(name), + expected_argv = [ + "-emit-module-path", + ], + mnemonic = "SwiftDeriveFiles", + not_expected_argv = [ + "-emit-object", + ], + tags = [name], + target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", + ) + + split_swiftmodule_provider_test( + name = "{}_split_provider".format(name), + expected_files = [ + "test_fixtures_debug_settings_simple.swiftmodule", + ], + field = "direct_modules.swift.swiftmodule", + provider = "SwiftInfo", + tags = [name], + target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", + ) + + split_swiftmodule_provider_test( + name = "{}_split_provider_ccinfo".format(name), + expected_files = [ + "libsimple.a", + ], + field = "linking_context.libraries_to_link.pic_static_library!", + provider = "CcInfo", + tags = [name], + target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", + ) + + split_swiftmodule_wmo_test( + name = "{}_object_only_wmo".format(name), + expected_argv = [ + "-emit-object", + "-whole-module-optimization", + ], + mnemonic = "SwiftCompile", + not_expected_argv = [ + "-emit-module-path", + ], + tags = [name], + target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", + ) + + split_swiftmodule_wmo_test( + name = "{}_swiftmodule_only_wmo".format(name), + expected_argv = [ + "-emit-module-path", + "-whole-module-optimization", + ], + mnemonic = "SwiftDeriveFiles", + not_expected_argv = [ + "-emit-object", + ], + tags = [name], + target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", + ) + + split_swiftmodule_wmo_provider_test( + name = "{}_split_wmo_provider".format(name), + expected_files = [ + "test_fixtures_debug_settings_simple.swiftmodule", + ], + field = "direct_modules.swift.swiftmodule", + provider = "SwiftInfo", + tags = [name], + target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", + ) + + split_swiftmodule_wmo_provider_test( + name = "{}_split_wmo_provider_ccinfo".format(name), + expected_files = [ + "libsimple.a", + ], + field = "linking_context.libraries_to_link.pic_static_library!", + provider = "CcInfo", + tags = [name], + target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", + ) + + split_swiftmodule_skip_function_bodies_test( + name = "{}_no_skip_function_bodies".format(name), + expected_argv = [ + "-emit-object", + ], + mnemonic = "SwiftCompile", + not_expected_argv = [ + "-experimental-skip-non-inlinable-function-bodies", + ], + tags = [name], + target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", + ) + + split_swiftmodule_skip_function_bodies_test( + name = "{}_skip_function_bodies".format(name), + expected_argv = [ + "-experimental-skip-non-inlinable-function-bodies", + ], + mnemonic = "SwiftDeriveFiles", + not_expected_argv = [ + "-emit-object", + ], + tags = [name], + target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", + ) + + native.test_suite( + name = name, + tags = [name], + ) From 3dcf6f197d2578ea4dcb3bba2381f9ef55200543 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Tue, 20 Oct 2020 15:55:49 -0700 Subject: [PATCH 029/152] Fix index while building with derived files (#506) The swiftmodule generation should not attempt to perform indexing. --- swift/internal/compiling.bzl | 5 +---- test/split_derived_files_tests.bzl | 36 ++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index 778a6ae04..f16fdd656 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -693,10 +693,7 @@ def compile_action_configs(): # Configure index-while-building. swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - ], + actions = [swift_action_names.COMPILE], configurators = [_index_while_building_configurator], features = [SWIFT_FEATURE_INDEX_WHILE_BUILDING], ), diff --git a/test/split_derived_files_tests.bzl b/test/split_derived_files_tests.bzl index 89baa9b47..baba76f70 100644 --- a/test/split_derived_files_tests.bzl +++ b/test/split_derived_files_tests.bzl @@ -56,6 +56,14 @@ split_swiftmodule_skip_function_bodies_test = make_action_command_line_test_rule ], }, ) +split_swiftmodule_indexing_test = make_action_command_line_test_rule( + config_settings = { + "//command_line_option:features": [ + "swift.index_while_building", + "swift.split_derived_files_generation", + ], + }, +) def split_derived_files_test_suite(name = "split_derived_files"): """Test suite for split derived files options. @@ -220,6 +228,34 @@ def split_derived_files_test_suite(name = "split_derived_files"): target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", ) + split_swiftmodule_indexing_test( + name = "{}_object_only_indexing".format(name), + expected_argv = [ + "-emit-object", + "-index-store-path", + ], + mnemonic = "SwiftCompile", + not_expected_argv = [ + "-emit-module-path", + ], + tags = [name], + target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", + ) + + split_swiftmodule_indexing_test( + name = "{}_swiftmodule_only_indexing".format(name), + expected_argv = [ + "-emit-module-path", + ], + mnemonic = "SwiftDeriveFiles", + not_expected_argv = [ + "-emit-object", + "-index-store-path", + ], + tags = [name], + target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", + ) + native.test_suite( name = name, tags = [name], From f1e125c72f5f03843a6df3d909bcb5d72861c388 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Wed, 21 Oct 2020 08:45:45 -0700 Subject: [PATCH 030/152] Fix derive files with bitcode (#509) --- swift/internal/xcode_swift_toolchain.bzl | 2 - test/BUILD | 8 +++ test/split_derived_files_tests.bzl | 62 ++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 2 deletions(-) diff --git a/swift/internal/xcode_swift_toolchain.bzl b/swift/internal/xcode_swift_toolchain.bzl index 5a0d2a6cf..cc10af3c1 100644 --- a/swift/internal/xcode_swift_toolchain.bzl +++ b/swift/internal/xcode_swift_toolchain.bzl @@ -319,7 +319,6 @@ def _all_action_configs( swift_toolchain_config.action_config( actions = [ swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, swift_action_names.PRECOMPILE_C_MODULE, ], configurators = [swift_toolchain_config.add_arg("-embed-bitcode")], @@ -328,7 +327,6 @@ def _all_action_configs( swift_toolchain_config.action_config( actions = [ swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, swift_action_names.PRECOMPILE_C_MODULE, ], configurators = [ diff --git a/test/BUILD b/test/BUILD index 70dcb37e7..fb4afe0d7 100644 --- a/test/BUILD +++ b/test/BUILD @@ -32,3 +32,11 @@ bzl_library( "//test/rules:starlark_tests_bzls", ], ) + +# TODO: Remove once https://github.com/bazelbuild/bazel/pull/10945 lands +config_setting( + name = "linux", + constraint_values = [ + "@bazel_tools//platforms:linux", + ], +) diff --git a/test/split_derived_files_tests.bzl b/test/split_derived_files_tests.bzl index baba76f70..2eeb17664 100644 --- a/test/split_derived_files_tests.bzl +++ b/test/split_derived_files_tests.bzl @@ -64,6 +64,22 @@ split_swiftmodule_indexing_test = make_action_command_line_test_rule( ], }, ) +split_swiftmodule_bitcode_test = make_action_command_line_test_rule( + config_settings = { + "//command_line_option:apple_bitcode": "embedded", + "//command_line_option:features": [ + "swift.split_derived_files_generation", + ], + }, +) +split_swiftmodule_bitcode_markers_test = make_action_command_line_test_rule( + config_settings = { + "//command_line_option:apple_bitcode": "embedded_markers", + "//command_line_option:features": [ + "swift.split_derived_files_generation", + ], + }, +) def split_derived_files_test_suite(name = "split_derived_files"): """Test suite for split derived files options. @@ -256,6 +272,52 @@ def split_derived_files_test_suite(name = "split_derived_files"): target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", ) + split_swiftmodule_bitcode_test( + name = "{}_bitcode_compile".format(name), + expected_argv = select({ + "//test:linux": [], + "//conditions:default": [ + "-embed-bitcode", + ], + }), + mnemonic = "SwiftCompile", + tags = [name], + target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", + ) + + split_swiftmodule_bitcode_test( + name = "{}_bitcode_derive_files".format(name), + not_expected_argv = [ + "-embed-bitcode", + ], + mnemonic = "SwiftDeriveFiles", + tags = [name], + target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", + ) + + split_swiftmodule_bitcode_markers_test( + name = "{}_bitcode_markers_compile".format(name), + expected_argv = select({ + "//test:linux": [], + "//conditions:default": [ + "-embed-bitcode-marker", + ], + }), + mnemonic = "SwiftCompile", + tags = [name], + target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", + ) + + split_swiftmodule_bitcode_markers_test( + name = "{}_bitcode_markers_derive_files".format(name), + not_expected_argv = [ + "-embed-bitcode-marker", + ], + mnemonic = "SwiftDeriveFiles", + tags = [name], + target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", + ) + native.test_suite( name = name, tags = [name], From cd66dc7c0aa6010f56676dbb89091f882d4ec9c5 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Wed, 21 Oct 2020 08:45:51 -0700 Subject: [PATCH 031/152] Output command lines of failed action command line tests (#508) This is helpful when debugging what does or doesn't exist --- test/rules/action_command_line_test.bzl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/rules/action_command_line_test.bzl b/test/rules/action_command_line_test.bzl index 8701901c8..539957dc4 100644 --- a/test/rules/action_command_line_test.bzl +++ b/test/rules/action_command_line_test.bzl @@ -69,18 +69,20 @@ def _action_command_line_test_impl(ctx): if expected + " " not in concatenated_args: unittest.fail( env, - "{}expected argv to contain '{}', but it did not".format( + "{}expected argv to contain '{}', but it did not: {}".format( message_prefix, expected, + concatenated_args, ), ) for not_expected in ctx.attr.not_expected_argv: if not_expected + " " in concatenated_args: unittest.fail( env, - "{}expected argv to not contain '{}', but it did".format( + "{}expected argv to not contain '{}', but it did: {}".format( message_prefix, not_expected, + concatenated_args, ), ) From 320d0a336f39a9ef15ee60ef46cbf1401a3e7610 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Thu, 22 Oct 2020 10:47:58 -0700 Subject: [PATCH 032/152] Add swift.remap_xcode_path feature (#511) --- swift/internal/feature_names.bzl | 4 +++ swift/internal/xcode_swift_toolchain.bzl | 39 ++++++++++++++++++++++++ test/coverage_settings_tests.bzl | 24 +++++++++++++++ test/debug_settings_tests.bzl | 24 +++++++++++++++ 4 files changed, 91 insertions(+) diff --git a/swift/internal/feature_names.bzl b/swift/internal/feature_names.bzl index 21257554a..50447909e 100644 --- a/swift/internal/feature_names.bzl +++ b/swift/internal/feature_names.bzl @@ -236,3 +236,7 @@ SWIFT_FEATURE_SPLIT_DERIVED_FILES_GENERATION = "swift.split_derived_files_genera # If enabled the skip function bodies frontend flag is passed when using derived # files generation. This requires Swift 5.2 SWIFT_FEATURE_ENABLE_SKIP_FUNCTION_BODIES = "swift.skip_function_bodies_for_derived_files" + +# If enabled remap the absolute path to Xcode in debug info. When used with +# swift.coverage_prefix_map also remap the path in coverage data. +SWIFT_FEATURE_REMAP_XCODE_PATH = "swift.remap_xcode_path" diff --git a/swift/internal/xcode_swift_toolchain.bzl b/swift/internal/xcode_swift_toolchain.bzl index cc10af3c1..8cd32ab1c 100644 --- a/swift/internal/xcode_swift_toolchain.bzl +++ b/swift/internal/xcode_swift_toolchain.bzl @@ -32,11 +32,14 @@ load( "SWIFT_FEATURE_BITCODE_EMBEDDED", "SWIFT_FEATURE_BITCODE_EMBEDDED_MARKERS", "SWIFT_FEATURE_BUNDLED_XCTESTS", + "SWIFT_FEATURE_COVERAGE", + "SWIFT_FEATURE_COVERAGE_PREFIX_MAP", "SWIFT_FEATURE_DEBUG_PREFIX_MAP", "SWIFT_FEATURE_ENABLE_BATCH_MODE", "SWIFT_FEATURE_ENABLE_SKIP_FUNCTION_BODIES", "SWIFT_FEATURE_MODULE_MAP_HOME_IS_CWD", "SWIFT_FEATURE_MODULE_MAP_NO_PRIVATE_HEADERS", + "SWIFT_FEATURE_REMAP_XCODE_PATH", "SWIFT_FEATURE_SUPPORTS_LIBRARY_EVOLUTION", "SWIFT_FEATURE_SUPPORTS_PRIVATE_DEPS", "SWIFT_FEATURE_USE_RESPONSE_FILES", @@ -334,6 +337,42 @@ def _all_action_configs( ], features = [SWIFT_FEATURE_BITCODE_EMBEDDED_MARKERS], ), + + # Xcode path remapping + swift_toolchain_config.action_config( + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], + configurators = [ + swift_toolchain_config.add_arg( + "-debug-prefix-map", + "__BAZEL_XCODE_DEVELOPER_DIR__=DEVELOPER_DIR", + ), + ], + features = [ + [SWIFT_FEATURE_REMAP_XCODE_PATH, SWIFT_FEATURE_DEBUG_PREFIX_MAP], + ], + ), + swift_toolchain_config.action_config( + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], + configurators = [ + swift_toolchain_config.add_arg( + "-coverage-prefix-map", + "__BAZEL_XCODE_DEVELOPER_DIR__=DEVELOPER_DIR", + ), + ], + features = [ + [ + SWIFT_FEATURE_REMAP_XCODE_PATH, + SWIFT_FEATURE_COVERAGE_PREFIX_MAP, + SWIFT_FEATURE_COVERAGE, + ], + ], + ), ] if needs_resource_directory: diff --git a/test/coverage_settings_tests.bzl b/test/coverage_settings_tests.bzl index e16d7da10..397b8ffb9 100644 --- a/test/coverage_settings_tests.bzl +++ b/test/coverage_settings_tests.bzl @@ -20,6 +20,16 @@ coverage_prefix_map_test = make_action_command_line_test_rule( }, ) +coverage_xcode_prefix_map_test = make_action_command_line_test_rule( + config_settings = { + "//command_line_option:collect_code_coverage": "true", + "//command_line_option:features": [ + "swift.coverage_prefix_map", + "swift.remap_xcode_path", + ], + }, +) + def coverage_settings_test_suite(name = "coverage_settings"): """Test suite for coverage options. @@ -51,3 +61,17 @@ def coverage_settings_test_suite(name = "coverage_settings"): mnemonic = "SwiftCompile", target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", ) + + coverage_xcode_prefix_map_test( + name = "{}_xcode_prefix_map".format(name), + tags = [name], + expected_argv = select({ + "//test:linux": [], + "//conditions:default": [ + "-coverage-prefix-map", + "__BAZEL_XCODE_DEVELOPER_DIR__=DEVELOPER_DIR", + ], + }), + mnemonic = "SwiftCompile", + target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", + ) diff --git a/test/debug_settings_tests.bzl b/test/debug_settings_tests.bzl index 40530be67..380572583 100644 --- a/test/debug_settings_tests.bzl +++ b/test/debug_settings_tests.bzl @@ -90,6 +90,16 @@ cacheable_opt_action_command_line_test = make_action_command_line_test_rule( config_settings = CACHEABLE_OPT_CONFIG_SETTINGS, ) +xcode_remap_command_line_test = make_action_command_line_test_rule( + config_settings = { + "//command_line_option:compilation_mode": "dbg", + "//command_line_option:features": [ + "swift.debug_prefix_map", + "swift.remap_xcode_path", + ], + }, +) + def debug_settings_test_suite(name = "debug_settings"): """Test suite for serializing debugging options. @@ -213,6 +223,20 @@ def debug_settings_test_suite(name = "debug_settings"): target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", ) + xcode_remap_command_line_test( + name = "{}_remap_xcode_path".format(name), + expected_argv = select({ + "//test:linux": [], + "//conditions:default": [ + "-debug-prefix-map", + "__BAZEL_XCODE_DEVELOPER_DIR__=DEVELOPER_DIR", + ], + }), + mnemonic = "SwiftCompile", + tags = [name], + target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", + ) + native.test_suite( name = name, tags = [name], From 410d8ed546e3e43dd06f01cb3916ede6632a6d71 Mon Sep 17 00:00:00 2001 From: Brentley Jones Date: Tue, 21 Apr 2020 07:55:05 -0500 Subject: [PATCH 033/152] Only read output_file_map if it's going to be written The output_file_map is only written to disk in a transformed state if an incremental build is happening. This change causes the output_file_map to only be read and processed in that case as well, leading to less work in the WMO case. --- tools/worker/work_processor.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/worker/work_processor.cc b/tools/worker/work_processor.cc index 07857d352..a738041c1 100644 --- a/tools/worker/work_processor.cc +++ b/tools/worker/work_processor.cc @@ -72,7 +72,6 @@ void WorkProcessor::ProcessWorkRequest( arg.clear(); } else if (prev_arg == "-output-file-map") { output_file_map_path = arg; - output_file_map.ReadFromPath(output_file_map_path); arg.clear(); } else if (ArgumentEnablesWMO(arg)) { is_wmo = true; @@ -87,6 +86,8 @@ void WorkProcessor::ProcessWorkRequest( if (!output_file_map_path.empty()) { if (!is_wmo) { + output_file_map.ReadFromPath(output_file_map_path); + // Rewrite the output file map to use the incremental storage area and // pass the compiler the path to the rewritten file. auto new_path = From ed81c15f9b577880c13b987101100cbac03f45c2 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Thu, 29 Oct 2020 18:06:17 -0700 Subject: [PATCH 034/152] Create a build setting to allow forcing a Swift target to Apple with bazel transitions. (#515) PiperOrigin-RevId: 339779917 (cherry picked from commit e4ad1cc258a33946d506f1ed8805b2bdbcaeff17) Co-authored-by: Googler --- swift/BUILD | 8 ++++++++ swift/internal/BUILD | 1 + swift/internal/attrs.bzl | 4 ++-- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/swift/BUILD b/swift/BUILD index cf6045612..dd79c6127 100644 --- a/swift/BUILD +++ b/swift/BUILD @@ -55,6 +55,14 @@ bool_setting( build_setting_default = False, ) +# Configuration setting for forcing generation of Apple targets. +# NOTE: this is only intended for use with transitions that want to force +# building of an Apple target when building for Linux. +bool_setting( + name = "force_apple_target", + build_setting_default = False, +) + # Allows a user to override the default Swift driver during a build, if the # toolchain is using the default. label_flag( diff --git a/swift/internal/BUILD b/swift/internal/BUILD index 944ff4844..57c345add 100644 --- a/swift/internal/BUILD +++ b/swift/internal/BUILD @@ -347,6 +347,7 @@ bzl_library( "@bazel_skylib//lib:dicts", "@bazel_skylib//lib:partial", "@bazel_skylib//lib:paths", + "@bazel_skylib//rules:common_settings", "@bazel_tools//tools/cpp:toolchain_utils.bzl", ], ) diff --git a/swift/internal/attrs.bzl b/swift/internal/attrs.bzl index 52f76f510..ffac373e3 100644 --- a/swift/internal/attrs.bzl +++ b/swift/internal/attrs.bzl @@ -325,7 +325,7 @@ def swift_toolchain_driver_attrs(): return { "swift_executable": attr.label( allow_single_file = True, - cfg = "host", + cfg = "exec", doc = """\ A replacement Swift driver executable. @@ -337,7 +337,7 @@ that it is invoked in the correct mode (i.e., `swift`, `swiftc`, ), "_default_swift_executable": attr.label( allow_files = True, - cfg = "host", + cfg = "exec", default = Label( "@build_bazel_rules_swift//swift:default_swift_executable", ), From 17126a9d4f049937a0ca03af0ebe61a0bf9c0492 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Wed, 4 Nov 2020 12:45:21 -0800 Subject: [PATCH 035/152] Update apple_support (#517) --- swift/repositories.bzl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/swift/repositories.bzl b/swift/repositories.bzl index 783a49039..af1a45b43 100644 --- a/swift/repositories.bzl +++ b/swift/repositories.bzl @@ -51,9 +51,9 @@ def swift_rules_dependencies(): http_archive, name = "build_bazel_apple_support", urls = [ - "https://github.com/bazelbuild/apple_support/releases/download/0.9.0/apple_support.0.9.0.tar.gz", + "https://github.com/bazelbuild/apple_support/releases/download/0.9.1/apple_support.0.9.1.tar.gz", ], - sha256 = "36d60bce680446ab534b141c47f2aef6b9c598267ef3450b7d74b9d81e1fd6bd", + sha256 = "02ac04ff0a0de1e891a1fa8839cc6a5957e3c4a80856545aa35a786d15aad108", ) _maybe( From 22793036d280719fa3ed2e0f6beddfafa23fddfd Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Wed, 4 Nov 2020 14:48:22 -0800 Subject: [PATCH 036/152] Update README with new URLs (#518) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c8090067f..7345b3b18 100644 --- a/README.md +++ b/README.md @@ -51,8 +51,8 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "build_bazel_rules_swift", - sha256 = "d2f38c33dc82cf3160c59342203d31a030e53ebe8f4c7365add7a549223f9c62", - url = "https://github.com/bazelbuild/rules_swift/releases/download/0.15.0/rules_swift.0.15.0.tar.gz", + sha256 = "bfbd03624a1e2addecc1078227ea421e5321a30f9f3a5e8b53ac85efb3107f92", + url = "https://github.com/bazelbuild/rules_swift/releases/download/0.16.0/rules_swift.0.16.0.tar.gz", ) load( From aff1754b064898fde731a64622840535f8dd7165 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Fri, 6 Nov 2020 16:56:35 -0600 Subject: [PATCH 037/152] Migrate to the modern Starlark linker input API. (#512) See https://github.com/bazelbuild/bazel/issues/10860. --- swift/internal/linking.bzl | 40 +++++++++++++----- swift/internal/swift_binary_test.bzl | 1 + swift/internal/swift_grpc_library.bzl | 11 +++-- swift/internal/swift_import.bzl | 22 ++++++---- swift/internal/swift_library.bzl | 13 +++--- swift/internal/swift_module_alias.bzl | 12 +++--- swift/internal/swift_protoc_gen_aspect.bzl | 11 +++-- swift/internal/utils.bzl | 49 +++++++--------------- test/private_deps_tests.bzl | 2 +- test/rules/provider_test.bzl | 9 +++- test/split_derived_files_tests.bzl | 6 +-- 11 files changed, 100 insertions(+), 76 deletions(-) diff --git a/swift/internal/linking.bzl b/swift/internal/linking.bzl index 613c77ff2..ac8a87c27 100644 --- a/swift/internal/linking.bzl +++ b/swift/internal/linking.bzl @@ -95,6 +95,7 @@ def _register_static_library_link_action( ) def register_libraries_to_link( + owning_label, actions, alwayslink, cc_feature_configuration, @@ -102,10 +103,13 @@ def register_libraries_to_link( is_static, library_name, objects, - swift_toolchain): + swift_toolchain, + user_link_flags, + additional_inputs): """Declares the requested libraries and registers actions to link them. Args: + owning_label: Label executing rule (i.e., ctx.label). actions: The object used to register actions. alwayslink: If True, create a static library that should be always-linked (having a `.lo` extension instead of `.a`). This @@ -120,9 +124,11 @@ def register_libraries_to_link( linked. swift_toolchain: The Swift toolchain provider to use when constructing the action. + user_link_flags: Extra link flags to be passed with the library. + additional_inputs: Extra inputs for a link action involving the library. Returns: - A `LibraryToLink` object containing the libraries that were created. + A `LinkerInput` object containing the libraries that were created. """ dynamic_library = None if is_dynamic: @@ -145,16 +151,24 @@ def register_libraries_to_link( else: static_library = None - return cc_common.create_library_to_link( - actions = actions, - alwayslink = alwayslink, - cc_toolchain = swift_toolchain.cc_toolchain_info, - feature_configuration = cc_feature_configuration, - pic_static_library = static_library, - dynamic_library = dynamic_library, + return cc_common.create_linker_input( + owner = owning_label, + libraries = depset(direct = [ + cc_common.create_library_to_link( + actions = actions, + alwayslink = alwayslink, + cc_toolchain = swift_toolchain.cc_toolchain_info, + feature_configuration = cc_feature_configuration, + pic_static_library = static_library, + dynamic_library = dynamic_library, + ), + ]), + additional_inputs = depset(direct = additional_inputs), + user_link_flags = depset(direct = user_link_flags), ) def register_link_binary_action( + owning_label, actions, additional_inputs, additional_linking_contexts, @@ -170,6 +184,7 @@ def register_link_binary_action( """Registers an action that invokes the linker to produce a binary. Args: + owning_label: Label of the rule creating the link action. actions: The object used to register actions. additional_inputs: A list of additional inputs to the link action, such as those used in `$(location ...)` substitution, linker @@ -231,7 +246,12 @@ def register_link_binary_action( linking_contexts.append( cc_common.create_linking_context( - user_link_flags = dep_link_flags, + linker_inputs = depset(direct = [ + cc_common.create_linker_input( + owner = owning_label, + user_link_flags = depset(direct = dep_link_flags), + ), + ]) ), ) diff --git a/swift/internal/swift_binary_test.bzl b/swift/internal/swift_binary_test.bzl index 6d0d544d3..bfbc80d93 100644 --- a/swift/internal/swift_binary_test.bzl +++ b/swift/internal/swift_binary_test.bzl @@ -237,6 +237,7 @@ def _swift_linking_rule_impl( user_link_flags.extend(ctx.fragments.cpp.linkopts) linking_outputs = register_link_binary_action( + owning_label = ctx.label, actions = ctx.actions, additional_inputs = additional_inputs_to_linker, additional_linking_contexts = additional_linking_contexts, diff --git a/swift/internal/swift_grpc_library.bzl b/swift/internal/swift_grpc_library.bzl index 5688ac18c..29ffa6f46 100644 --- a/swift/internal/swift_grpc_library.bzl +++ b/swift/internal/swift_grpc_library.bzl @@ -293,7 +293,8 @@ def _swift_grpc_library_impl(ctx): target_name = ctx.label.name, ) - library_to_link = register_libraries_to_link( + linker_input = register_libraries_to_link( + owning_label = ctx.label, actions = ctx.actions, alwayslink = False, cc_feature_configuration = swift_common.cc_feature_configuration( @@ -304,6 +305,8 @@ def _swift_grpc_library_impl(ctx): library_name = ctx.label.name, objects = compilation_outputs.object_files, swift_toolchain = swift_toolchain, + additional_inputs = compilation_outputs.linker_inputs, + user_link_flags = compilation_outputs.linker_flags, ) providers = [ @@ -311,7 +314,7 @@ def _swift_grpc_library_impl(ctx): files = depset(direct = generated_files + compact([ compilation_outputs.swiftdoc, compilation_outputs.swiftmodule, - library_to_link.pic_static_library, + linker_input.libraries[0].pic_static_library, ])), ), OutputGroupInfo(**output_groups_from_compilation_outputs( @@ -320,7 +323,7 @@ def _swift_grpc_library_impl(ctx): create_cc_info( cc_infos = get_providers(compile_deps, CcInfo), compilation_outputs = compilation_outputs, - libraries_to_link = [library_to_link], + linker_inputs = [linker_input], ), deps[0][SwiftProtoInfo], swift_common.create_swift_info( @@ -346,7 +349,7 @@ def _swift_grpc_library_impl(ctx): link_inputs = compilation_outputs.linker_inputs, linkopts = compilation_outputs.linker_flags, module_map = compilation_outputs.generated_module_map, - static_archives = compact([library_to_link.pic_static_library]), + static_archives = compact([linker_input.libraries[0].pic_static_library]), swiftmodules = [compilation_outputs.swiftmodule], objc_header = compilation_outputs.generated_header, )) diff --git a/swift/internal/swift_import.bzl b/swift/internal/swift_import.bzl index 7fdfd3f31..10fc0c7ec 100644 --- a/swift/internal/swift_import.bzl +++ b/swift/internal/swift_import.bzl @@ -38,14 +38,18 @@ def _swift_import_impl(ctx): unsupported_features = ctx.disabled_features, ) - libraries_to_link = [ - cc_common.create_library_to_link( - actions = ctx.actions, - cc_toolchain = cc_toolchain, - feature_configuration = cc_feature_configuration, - static_library = archive, - ) - for archive in archives + linker_inputs = [ + cc_common.create_linker_input( + libraries = depset(direct = [ + cc_common.create_library_to_link( + actions = ctx.actions, + cc_toolchain = cc_toolchain, + feature_configuration = cc_feature_configuration, + static_library = archive, + ) + for archive in archives + ]), + ), ] providers = [ @@ -59,7 +63,7 @@ def _swift_import_impl(ctx): ), create_cc_info( cc_infos = get_providers(deps, CcInfo), - libraries_to_link = libraries_to_link, + linker_inputs = linker_inputs, ), # Propagate an `Objc` provider so that Apple-specific rules like # apple_binary` will link the imported library properly. Typically we'd diff --git a/swift/internal/swift_library.bzl b/swift/internal/swift_library.bzl index 374b5184e..706eb6a1b 100644 --- a/swift/internal/swift_library.bzl +++ b/swift/internal/swift_library.bzl @@ -179,7 +179,8 @@ def _swift_library_impl(ctx): else: clang_module = None - library_to_link = register_libraries_to_link( + linker_input = register_libraries_to_link( + owning_label = ctx.label, actions = ctx.actions, alwayslink = ctx.attr.alwayslink, cc_feature_configuration = swift_common.cc_feature_configuration( @@ -190,6 +191,8 @@ def _swift_library_impl(ctx): library_name = ctx.label.name, objects = compilation_outputs.object_files, swift_toolchain = swift_toolchain, + user_link_flags = linkopts, + additional_inputs = compilation_outputs.linker_inputs, ) direct_output_files = compact([ @@ -197,7 +200,7 @@ def _swift_library_impl(ctx): compilation_outputs.swiftdoc, compilation_outputs.swiftinterface, compilation_outputs.swiftmodule, - library_to_link.pic_static_library, + linker_input.libraries[0].pic_static_library, ]) providers = [ @@ -213,14 +216,12 @@ def _swift_library_impl(ctx): compilation_outputs = compilation_outputs, )), create_cc_info( - additional_inputs = additional_inputs, cc_infos = get_providers(deps, CcInfo), compilation_outputs = compilation_outputs, defines = ctx.attr.defines, includes = [ctx.bin_dir.path], - libraries_to_link = [library_to_link], + linker_inputs = [linker_input], private_cc_infos = get_providers(private_deps, CcInfo), - user_link_flags = linkopts, ), coverage_common.instrumented_files_info( ctx, @@ -261,7 +262,7 @@ def _swift_library_impl(ctx): link_inputs = compilation_outputs.linker_inputs + additional_inputs, linkopts = compilation_outputs.linker_flags + linkopts, module_map = compilation_outputs.generated_module_map, - static_archives = compact([library_to_link.pic_static_library]), + static_archives = compact([linker_input.libraries[0].pic_static_library]), swiftmodules = [compilation_outputs.swiftmodule], objc_header = compilation_outputs.generated_header, )) diff --git a/swift/internal/swift_module_alias.bzl b/swift/internal/swift_module_alias.bzl index 55a57bf7c..217b7798c 100644 --- a/swift/internal/swift_module_alias.bzl +++ b/swift/internal/swift_module_alias.bzl @@ -72,7 +72,8 @@ def _swift_module_alias_impl(ctx): target_name = ctx.label.name, ) - library_to_link = register_libraries_to_link( + linker_input = register_libraries_to_link( + owning_label = ctx.label, actions = ctx.actions, alwayslink = False, cc_feature_configuration = swift_common.cc_feature_configuration( @@ -83,6 +84,7 @@ def _swift_module_alias_impl(ctx): library_name = ctx.label.name, objects = compilation_outputs.object_files, swift_toolchain = swift_toolchain, + additional_inputs = compilation_outputs.linker_inputs, ) providers = [ @@ -90,8 +92,8 @@ def _swift_module_alias_impl(ctx): files = depset(compact([ compilation_outputs.swiftdoc, compilation_outputs.swiftmodule, - library_to_link.dynamic_library, - library_to_link.pic_static_library, + linker_input.libraries[0].dynamic_library, + linker_input.libraries[0].pic_static_library, ])), ), OutputGroupInfo(**output_groups_from_compilation_outputs( @@ -105,7 +107,7 @@ def _swift_module_alias_impl(ctx): cc_infos = get_providers(deps, CcInfo), compilation_outputs = compilation_outputs, includes = [ctx.bin_dir.path], - libraries_to_link = [library_to_link], + linker_inputs = [linker_input], ), swift_common.create_swift_info( modules = [ @@ -130,7 +132,7 @@ def _swift_module_alias_impl(ctx): link_inputs = compilation_outputs.linker_inputs, linkopts = compilation_outputs.linker_flags, module_map = compilation_outputs.generated_module_map, - static_archives = compact([library_to_link.pic_static_library]), + static_archives = compact([linker_input.libraries[0].pic_static_library]), swiftmodules = [compilation_outputs.swiftmodule], objc_header = compilation_outputs.generated_header, )) diff --git a/swift/internal/swift_protoc_gen_aspect.bzl b/swift/internal/swift_protoc_gen_aspect.bzl index 091013a9e..45f78837a 100644 --- a/swift/internal/swift_protoc_gen_aspect.bzl +++ b/swift/internal/swift_protoc_gen_aspect.bzl @@ -428,7 +428,8 @@ def _swift_protoc_gen_aspect_impl(target, aspect_ctx): target_name = target.label.name, ) - library_to_link = register_libraries_to_link( + linker_input = register_libraries_to_link( + owning_label = aspect_ctx.label, actions = aspect_ctx.actions, alwayslink = False, cc_feature_configuration = swift_common.cc_feature_configuration( @@ -442,6 +443,8 @@ def _swift_protoc_gen_aspect_impl(target, aspect_ctx): library_name = "{}.swift".format(target.label.name), objects = compilation_outputs.object_files, swift_toolchain = swift_toolchain, + additional_inputs = compilation_outputs.linker_inputs, + user_link_flags = compilation_outputs.linker_flags, ) # It's bad practice to attach providers you don't own to other targets, @@ -477,9 +480,9 @@ def _swift_protoc_gen_aspect_impl(target, aspect_ctx): objc_info_args["header"] = depset([ compilation_outputs.generated_header, ]) - if library_to_link.pic_static_library: + if linker_input.libraries[0].pic_static_library: objc_info_args["library"] = depset( - [library_to_link.pic_static_library], + [linker_input.libraries[0].pic_static_library], order = "topological", ) if compilation_outputs.linker_flags: @@ -516,7 +519,7 @@ def _swift_protoc_gen_aspect_impl(target, aspect_ctx): cc_infos = cc_infos, compilation_outputs = compilation_outputs, includes = includes, - libraries_to_link = [library_to_link], + linker_inputs = [linker_input], ), objc_info = objc_info, ), diff --git a/swift/internal/utils.bzl b/swift/internal/utils.bzl index b4e41d85f..fcda609af 100644 --- a/swift/internal/utils.bzl +++ b/swift/internal/utils.bzl @@ -41,25 +41,20 @@ def collect_cc_libraries( """ libraries = [] - # TODO(https://github.com/bazelbuild/bazel/issues/8118): Remove once flag is - # flipped. - libraries_to_link = cc_info.linking_context.libraries_to_link - if hasattr(libraries_to_link, "to_list"): - libraries_to_link = libraries_to_link.to_list() - - for library in libraries_to_link: - if include_pic_static: - if library.pic_static_library: - libraries.append(library.pic_static_library) - elif library.static_library: + for li in cc_info.linking_context.linker_inputs.to_list(): + for library in li.libraries: + if include_pic_static: + if library.pic_static_library: + libraries.append(library.pic_static_library) + elif library.static_library: + libraries.append(library.static_library) + elif include_static and library.static_library: libraries.append(library.static_library) - elif include_static and library.static_library: - libraries.append(library.static_library) - if include_dynamic and library.dynamic_library: - libraries.append(library.dynamic_library) - if include_interface and library.interface_library: - libraries.append(library.interface_library) + if include_dynamic and library.dynamic_library: + libraries.append(library.dynamic_library) + if include_interface and library.interface_library: + libraries.append(library.interface_library) return libraries @@ -74,19 +69,15 @@ def compact(sequence): return [item for item in sequence if item != None] def create_cc_info( - additional_inputs = [], cc_infos = [], compilation_outputs = None, defines = [], includes = [], - libraries_to_link = [], - private_cc_infos = [], - user_link_flags = []): + linker_inputs = [], + private_cc_infos = []): """Creates a `CcInfo` provider from Swift compilation info and deps. Args: - additional_inputs: A list of additional files that should be passed as - inputs to the final link action. cc_infos: A list of `CcInfo` providers from public dependencies, whose compilation and linking contexts should both be merged into the new provider. @@ -96,32 +87,24 @@ def create_cc_info( context. includes: The list of include paths to insert into the compilation context. - libraries_to_link: A list of `LibraryToLink` objects that represent the + linker_inputs: A list of `LinkerInput` objects that represent the libraries that should be linked into the final binary. private_cc_infos: A list of `CcInfo` providers from private (implementation-only) dependencies, whose linking contexts should be merged into the new provider but whose compilation contexts should be excluded. - user_link_flags: A list of flags that should be passed to the final link - action. Returns: A new `CcInfo`. """ - all_additional_inputs = list(additional_inputs) - all_user_link_flags = list(user_link_flags) all_headers = [] if compilation_outputs: - all_additional_inputs.extend(compilation_outputs.linker_inputs) - all_user_link_flags.extend(compilation_outputs.linker_flags) all_headers = compact([compilation_outputs.generated_header]) local_cc_infos = [ CcInfo( linking_context = cc_common.create_linking_context( - additional_inputs = all_additional_inputs, - libraries_to_link = libraries_to_link, - user_link_flags = all_user_link_flags, + linker_inputs = depset(direct = linker_inputs), ), compilation_context = cc_common.create_compilation_context( defines = depset(defines), diff --git a/test/private_deps_tests.bzl b/test/private_deps_tests.bzl index 1afd6b10e..148777462 100644 --- a/test/private_deps_tests.bzl +++ b/test/private_deps_tests.bzl @@ -115,7 +115,7 @@ def private_deps_test_suite(name = "private_deps"): # dependencies, which we need to ignore. "*", ], - field = "linking_context.libraries_to_link.static_library!", + field = "linking_context.linker_inputs.libraries.static_library!", provider = "CcInfo", tags = [name], target_under_test = "@build_bazel_rules_swift//test/fixtures/private_deps:client_cc_deps", diff --git a/test/rules/provider_test.bzl b/test/rules/provider_test.bzl index 42799fa79..b9cf0b762 100644 --- a/test/rules/provider_test.bzl +++ b/test/rules/provider_test.bzl @@ -85,7 +85,14 @@ def _evaluate_field(env, source, field): ) return _EVALUATE_FIELD_FAILED - source = [getattr(item, component, None) for item in source] + expanded = [] + for item in source: + item = _normalize_collection(item) + if types.is_list(item): + expanded.extend(item) + else: + expanded.append(item) + source = [getattr(item, component, None) for item in expanded] if filter_nones: source = [item for item in source if item != None] else: diff --git a/test/split_derived_files_tests.bzl b/test/split_derived_files_tests.bzl index 2eeb17664..34839ebae 100644 --- a/test/split_derived_files_tests.bzl +++ b/test/split_derived_files_tests.bzl @@ -114,7 +114,7 @@ def split_derived_files_test_suite(name = "split_derived_files"): expected_files = [ "libsimple.a", ], - field = "linking_context.libraries_to_link.pic_static_library!", + field = "linking_context.linker_inputs.libraries.pic_static_library!", provider = "CcInfo", tags = [name], target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", @@ -162,7 +162,7 @@ def split_derived_files_test_suite(name = "split_derived_files"): expected_files = [ "libsimple.a", ], - field = "linking_context.libraries_to_link.pic_static_library!", + field = "linking_context.linker_inputs.libraries.pic_static_library!", provider = "CcInfo", tags = [name], target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", @@ -212,7 +212,7 @@ def split_derived_files_test_suite(name = "split_derived_files"): expected_files = [ "libsimple.a", ], - field = "linking_context.libraries_to_link.pic_static_library!", + field = "linking_context.linker_inputs.libraries.pic_static_library!", provider = "CcInfo", tags = [name], target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", From 8141f747a1fc6bb4856d2671e8399ef5c7f5463f Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Mon, 9 Nov 2020 17:00:01 -0800 Subject: [PATCH 038/152] Update README with new URLs (#520) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7345b3b18..2f9a759a2 100644 --- a/README.md +++ b/README.md @@ -51,8 +51,8 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "build_bazel_rules_swift", - sha256 = "bfbd03624a1e2addecc1078227ea421e5321a30f9f3a5e8b53ac85efb3107f92", - url = "https://github.com/bazelbuild/rules_swift/releases/download/0.16.0/rules_swift.0.16.0.tar.gz", + sha256 = "a228a8e41fdc165a2c55924b728c466e0086f3e638a05d6da98aa6222cbb19c1", + url = "https://github.com/bazelbuild/rules_swift/releases/download/0.16.1/rules_swift.0.16.1.tar.gz", ) load( From 77afbc22d87c3398bfcf1fb8ce322b1ed183f350 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Fri, 13 Nov 2020 16:32:56 -0800 Subject: [PATCH 039/152] Update protobuf (#524) --- swift/repositories.bzl | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/swift/repositories.bzl b/swift/repositories.bzl index af1a45b43..7dbafe7dd 100644 --- a/swift/repositories.bzl +++ b/swift/repositories.bzl @@ -111,12 +111,11 @@ def swift_rules_dependencies(): _maybe( http_archive, name = "com_google_protobuf", - # latest as of 2020-09-01 urls = [ - "https://github.com/protocolbuffers/protobuf/archive/v3.13.0.zip", + "https://github.com/protocolbuffers/protobuf/archive/v3.14.0.zip", ], - sha256 = "1c744a6a1f2c901e68c5521bc275e22bdc66256eeb605c2781923365b7087e5f", - strip_prefix = "protobuf-3.13.0", + sha256 = "bf0e5070b4b99240183b29df78155eee335885e53a8af8683964579c214ad301", + strip_prefix = "protobuf-3.14.0", type = "zip", ) From 64c7b95db075316277b4623f9d0f78751bb3f169 Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Wed, 25 Nov 2020 08:54:11 -0800 Subject: [PATCH 040/152] Clean up some old TODOs. - Remove some deprecated fields. - Assert that atleast one module is provided. RELNOTES: None PiperOrigin-RevId: 344261262 (cherry picked from commit eefede5ccb761fcea4862826c812355b0d0ce806) --- swift/internal/providers.bzl | 91 +------------------------- test/private_deps_tests.bzl | 8 +-- test/swift_through_non_swift_tests.bzl | 2 +- 3 files changed, 8 insertions(+), 93 deletions(-) diff --git a/swift/internal/providers.bzl b/swift/internal/providers.bzl index fac8549de..d640a41ce 100644 --- a/swift/internal/providers.bzl +++ b/swift/internal/providers.bzl @@ -15,7 +15,6 @@ """Defines Starlark providers that propagated by the Swift BUILD rules.""" load("@bazel_skylib//lib:sets.bzl", "sets") -load("@bazel_skylib//lib:types.bzl", "types") SwiftInfo = provider( doc = """\ @@ -34,18 +33,6 @@ library that directly propagated this provider. "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. -""", - "direct_swiftdocs": """\ -`List` of `File`s. The Swift documentation (`.swiftdoc`) files for the library -that directly propagated this provider. - -This field is deprecated; use `direct_modules` instead. -""", - "direct_swiftmodules": """\ -`List` of `File`s. The Swift modules (`.swiftmodule`) for the library that -directly propagated this provider. - -This field is deprecated; use `direct_modules` instead. """, "module_name": """\ `String`. The name of the Swift module represented by the target that directly @@ -71,37 +58,11 @@ propagated this provider and all of its dependencies. "transitive_generated_headers": """\ `Depset` of `File`s. The transitive generated header files that can be used by Objective-C sources to interop with the transitive Swift libraries. -""", - "transitive_modulemaps": """\ -`Depset` of `File`s. The transitive module map files that will be passed to -Clang using the `-fmodule-map-file` option. - -This field is deprecated; use `transitive_modules` instead. """, "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. -""", - "transitive_swiftdocs": """\ -`Depset` of `File`s. The transitive Swift documentation (`.swiftdoc`) files -emitted by the library that propagated this provider and all of its -dependencies. - -This field is deprecated; use `transitive_modules` instead. -""", - "transitive_swiftinterfaces": """\ -`Depset` of `File`s. The transitive Swift interface (`.swiftinterface`) files -emitted by the library that propagated this provider and all of its -dependencies. - -This field is deprecated; use `transitive_modules` instead. -""", - "transitive_swiftmodules": """\ -`Depset` of `File`s. The transitive Swift modules (`.swiftmodule`) emitted by -the library that propagated this provider and all of its dependencies. - -This field is deprecated; use `transitive_modules` instead. """, }, ) @@ -269,9 +230,8 @@ def create_module(name, *, clang = None, swift = None): A `struct` containing the `name`, `clang`, and `swift` fields provided as arguments. """ - - # TODO(b/149999519): Once Swift module artifacts have migrated to this API, - # fail if both `clang` and `swift` are `None`. + if clang == None and swift == None: + fail("Must provide atleast a clang or swift module.") return struct( clang = clang, name = name, @@ -374,13 +334,8 @@ def create_swift_info( A new `SwiftInfo` provider with the given values. """ - # TODO(b/149999519): Remove the legacy direct/transitive fields and this - # transitional code. defines_set = sets.make() generated_headers = [] - swiftdocs = [] - swiftinterfaces = [] - swiftmodules = [] for module in modules: swift_module = module.swift if not swift_module: @@ -391,12 +346,6 @@ def create_swift_info( defines_set, sets.make(swift_module.defines), ) - if swift_module.swiftdoc: - swiftdocs.append(swift_module.swiftdoc) - if swift_module.swiftinterface: - swiftinterfaces.append(swift_module.swiftinterface) - if swift_module.swiftmodule: - swiftmodules.append(swift_module.swiftmodule) # If this is both a Swift and a Clang module, then the header in its # compilation context is its Swift generated header. @@ -408,8 +357,7 @@ def create_swift_info( defines = sets.to_list(defines_set) - # TODO(b/149999519): Remove the legacy `module_name` field and this - # transitional code. + # TODO(b/149999519): Remove the legacy `module_name`. if not module_name and len(modules) == 1: # Populate the module name based on the single module provided, if there # was one, and if the legacy `module_name` parameter wasn't already @@ -418,30 +366,17 @@ def create_swift_info( transitive_defines = [] transitive_generated_headers = [] - transitive_modulemaps = [] transitive_modules = [] - transitive_swiftdocs = [] - transitive_swiftinterfaces = [] - transitive_swiftmodules = [] for swift_info in swift_infos: transitive_defines.append(swift_info.transitive_defines) transitive_generated_headers.append( swift_info.transitive_generated_headers, ) - transitive_modulemaps.append(swift_info.transitive_modulemaps) transitive_modules.append(swift_info.transitive_modules) - transitive_swiftdocs.append(swift_info.transitive_swiftdocs) - transitive_swiftinterfaces.append(swift_info.transitive_swiftinterfaces) - transitive_swiftmodules.append(swift_info.transitive_swiftmodules) - # TODO(b/149999519): Remove `transitive_modulemaps`, - # `(direct|transitive)_swift*` fields, `module_name`, and `swift_version` - # after Tulsi is migrated. return SwiftInfo( direct_defines = defines, direct_modules = modules, - direct_swiftdocs = swiftdocs, - direct_swiftmodules = swiftmodules, module_name = module_name, swift_version = swift_version, transitive_defines = depset(defines, transitive = transitive_defines), @@ -449,25 +384,5 @@ def create_swift_info( generated_headers, transitive = transitive_generated_headers, ), - transitive_modulemaps = depset( - [ - m.clang.module_map - for m in modules - if m.clang and not types.is_string(m.clang.module_map) - ], - transitive = transitive_modulemaps, - ), transitive_modules = depset(modules, transitive = transitive_modules), - transitive_swiftdocs = depset( - swiftdocs, - transitive = transitive_swiftdocs, - ), - transitive_swiftinterfaces = depset( - swiftinterfaces, - transitive = transitive_swiftinterfaces, - ), - transitive_swiftmodules = depset( - swiftmodules, - transitive = transitive_swiftmodules, - ), ) diff --git a/test/private_deps_tests.bzl b/test/private_deps_tests.bzl index 148777462..d08c98b0c 100644 --- a/test/private_deps_tests.bzl +++ b/test/private_deps_tests.bzl @@ -40,7 +40,7 @@ def private_deps_test_suite(name = "private_deps"): expected_files = [ "test_fixtures_private_deps_private_swift.swiftmodule", ], - field = "transitive_swiftmodules", + field = "transitive_modules.swift!.swiftmodule", provider = "SwiftInfo", tags = [name], target_under_test = "@build_bazel_rules_swift//test/fixtures/private_deps:private_swift", @@ -51,7 +51,7 @@ def private_deps_test_suite(name = "private_deps"): expected_files = [ "test_fixtures_private_deps_public_swift.swiftmodule", ], - field = "transitive_swiftmodules", + field = "transitive_modules.swift!.swiftmodule", provider = "SwiftInfo", tags = [name], target_under_test = "@build_bazel_rules_swift//test/fixtures/private_deps:public_swift", @@ -66,7 +66,7 @@ def private_deps_test_suite(name = "private_deps"): "test_fixtures_private_deps_public_swift.swiftmodule", "-test_fixtures_private_deps_private_swift.swiftmodule", ], - field = "transitive_swiftmodules", + field = "transitive_modules.swift!.swiftmodule", provider = "SwiftInfo", tags = [name], target_under_test = "@build_bazel_rules_swift//test/fixtures/private_deps:client_swift_deps", @@ -97,7 +97,7 @@ def private_deps_test_suite(name = "private_deps"): "/test/fixtures/private_deps/public_cc.modulemaps/module.modulemap", "-/test/fixtures/private_deps/private_cc.modulemaps/module.modulemap", ], - field = "transitive_modulemaps", + field = "transitive_modules.clang!.module_map", provider = "SwiftInfo", tags = [name], target_under_test = "@build_bazel_rules_swift//test/fixtures/private_deps:client_cc_deps", diff --git a/test/swift_through_non_swift_tests.bzl b/test/swift_through_non_swift_tests.bzl index c0906260e..92b31fb8e 100644 --- a/test/swift_through_non_swift_tests.bzl +++ b/test/swift_through_non_swift_tests.bzl @@ -34,7 +34,7 @@ def swift_through_non_swift_test_suite(name = "swift_through_non_swift"): "test_fixtures_swift_through_non_swift_lower.swiftmodule", "test_fixtures_swift_through_non_swift_upper.swiftmodule", ], - field = "transitive_swiftmodules", + field = "transitive_modules.swift!.swiftmodule", provider = "SwiftInfo", tags = [name], target_under_test = "@build_bazel_rules_swift//test/fixtures/swift_through_non_swift:upper", From fe9d08e97029cfadd6a9a79320e6c55c3901af8b Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Mon, 30 Nov 2020 20:35:12 -0800 Subject: [PATCH 041/152] Remove the `swift.implicit_modules` feature. This feature permitted an odd three-state situation around the way the implicit module cache is handled: 1. The so-called "global module cache", which is placed in `bazel-out` 2. The ephemeral module cache, which is created and destroyed around each compile action 3. A state where no flags related to the implicit module cache are passed to the compiler, meaning "do whatever the compiler does by default". This third state is the one we want to get rid of, since the default is to place the module cache in a temp location outside the sandbox. PiperOrigin-RevId: 344942165 (cherry picked from commit 575b819f0bc7d06e1844c0721b8470707a7b4239) --- swift/internal/compiling.bzl | 13 ++++++------- swift/internal/feature_names.bzl | 6 ------ swift/internal/swift_autoconfiguration.bzl | 13 ------------- 3 files changed, 6 insertions(+), 26 deletions(-) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index f16fdd656..d1bfce6a4 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -43,7 +43,6 @@ load( "SWIFT_FEATURE_ENABLE_TESTING", "SWIFT_FEATURE_FASTBUILD", "SWIFT_FEATURE_FULL_DEBUG_INFO", - "SWIFT_FEATURE_IMPLICIT_MODULES", "SWIFT_FEATURE_INDEX_WHILE_BUILDING", "SWIFT_FEATURE_MINIMAL_DEPS", "SWIFT_FEATURE_MODULE_MAP_HOME_IS_CWD", @@ -445,10 +444,8 @@ def compile_action_configs(): swift_action_names.DERIVE_FILES, ], configurators = [_global_module_cache_configurator], - features = [ - SWIFT_FEATURE_IMPLICIT_MODULES, - SWIFT_FEATURE_USE_GLOBAL_MODULE_CACHE, - ], + features = [SWIFT_FEATURE_USE_GLOBAL_MODULE_CACHE], + not_features = [SWIFT_FEATURE_USE_C_MODULES], ), swift_toolchain_config.action_config( actions = [ @@ -460,8 +457,10 @@ def compile_action_configs(): "-Xwrapped-swift=-ephemeral-module-cache", ), ], - features = [SWIFT_FEATURE_IMPLICIT_MODULES], - not_features = [SWIFT_FEATURE_USE_GLOBAL_MODULE_CACHE], + not_features = [ + [SWIFT_FEATURE_USE_C_MODULES], + [SWIFT_FEATURE_USE_GLOBAL_MODULE_CACHE], + ], ), swift_toolchain_config.action_config( actions = [ diff --git a/swift/internal/feature_names.bzl b/swift/internal/feature_names.bzl index 50447909e..f3412f61b 100644 --- a/swift/internal/feature_names.bzl +++ b/swift/internal/feature_names.bzl @@ -99,12 +99,6 @@ SWIFT_FEATURE_ENABLE_TESTING = "swift.enable_testing" # warnings otherwise. SWIFT_FEATURE_FULL_DEBUG_INFO = "swift.full_debug_info" -# If enabled, ClangImporter will perform implicit search for module maps and -# compile modules in the implicit module cache for any that were not provided -# explicitly on the command line. Otherwise, all modules must be provided -# explicitly. -SWIFT_FEATURE_IMPLICIT_MODULES = "swift.implicit_modules" - # If enabled, the compilation action for a target will produce an index store. SWIFT_FEATURE_INDEX_WHILE_BUILDING = "swift.index_while_building" diff --git a/swift/internal/swift_autoconfiguration.bzl b/swift/internal/swift_autoconfiguration.bzl index dbcf1af9b..d386773a4 100644 --- a/swift/internal/swift_autoconfiguration.bzl +++ b/swift/internal/swift_autoconfiguration.bzl @@ -29,7 +29,6 @@ load( "SWIFT_FEATURE_DEBUG_PREFIX_MAP", "SWIFT_FEATURE_ENABLE_BATCH_MODE", "SWIFT_FEATURE_ENABLE_SKIP_FUNCTION_BODIES", - "SWIFT_FEATURE_IMPLICIT_MODULES", "SWIFT_FEATURE_MODULE_MAP_NO_PRIVATE_HEADERS", "SWIFT_FEATURE_SUPPORTS_PRIVATE_DEPS", "SWIFT_FEATURE_USE_RESPONSE_FILES", @@ -221,12 +220,6 @@ def _create_linux_toolchain(repository_ctx): feature_values = _compute_feature_values(repository_ctx, path_to_swiftc) version_file = _write_swift_version(repository_ctx, path_to_swiftc) - # TODO: This is being enabled here, rather than in the toolchain rule - # implementations, so that we can provide a way to optionally turn it off - # later when we have a way to model modules from outside Bazel workspaces - # (i.e., from the Swift toolchain) as explicit modules. - feature_values.append(SWIFT_FEATURE_IMPLICIT_MODULES) - # TODO: This should be removed so that private headers can be used with # explicit modules, but the build targets for CgRPC need to be cleaned up # first because they contain C++ code. @@ -267,12 +260,6 @@ def _create_xcode_toolchain(repository_ctx): repository_ctx: The repository rule context. """ feature_values = [ - # TODO: This is being enabled here, rather than in the toolchain rule - # implementations, so that we can provide a way to optionally turn it - # off later when we have a way to model modules from outside Bazel - # workspaces (i.e., from the Swift toolchain and Xcode SDKs) as explicit - # modules. - SWIFT_FEATURE_IMPLICIT_MODULES, # TODO: This should be removed so that private headers can be used with # explicit modules, but the build targets for CgRPC need to be cleaned # up first because they contain C++ code. From 420cc7a68c24cc96f980dee1189c072d96a21f79 Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Mon, 30 Nov 2020 11:51:00 -0800 Subject: [PATCH 042/152] Stop computing transitive_generated_headers. RELNOTES: None PiperOrigin-RevId: 344857866 (cherry picked from commit 5167ae9ddde9c663e193da0bb1bb4b83073dded7) --- swift/internal/providers.bzl | 21 --------------------- test/generated_header_tests.bzl | 12 ------------ 2 files changed, 33 deletions(-) diff --git a/swift/internal/providers.bzl b/swift/internal/providers.bzl index d640a41ce..e85dc13ad 100644 --- a/swift/internal/providers.bzl +++ b/swift/internal/providers.bzl @@ -54,10 +54,6 @@ arguments passed to specific compilation actions. "transitive_defines": """\ `Depset` of `string`s. The transitive `defines` specified for the library that propagated this provider and all of its dependencies. -""", - "transitive_generated_headers": """\ -`Depset` of `File`s. The transitive generated header files that can be used by -Objective-C sources to interop with the transitive Swift libraries. """, "transitive_modules": """\ `Depset` of values returned from `swift_common.create_module`. The transitive @@ -335,7 +331,6 @@ def create_swift_info( """ defines_set = sets.make() - generated_headers = [] for module in modules: swift_module = module.swift if not swift_module: @@ -347,14 +342,6 @@ def create_swift_info( sets.make(swift_module.defines), ) - # If this is both a Swift and a Clang module, then the header in its - # compilation context is its Swift generated header. - clang_module = module.clang - if clang_module: - generated_headers.extend( - clang_module.compilation_context.headers.to_list(), - ) - defines = sets.to_list(defines_set) # TODO(b/149999519): Remove the legacy `module_name`. @@ -365,13 +352,9 @@ def create_swift_info( module_name = modules[0].name transitive_defines = [] - transitive_generated_headers = [] transitive_modules = [] for swift_info in swift_infos: transitive_defines.append(swift_info.transitive_defines) - transitive_generated_headers.append( - swift_info.transitive_generated_headers, - ) transitive_modules.append(swift_info.transitive_modules) return SwiftInfo( @@ -380,9 +363,5 @@ def create_swift_info( module_name = module_name, swift_version = swift_version, transitive_defines = depset(defines, transitive = transitive_defines), - transitive_generated_headers = depset( - generated_headers, - transitive = transitive_generated_headers, - ), transitive_modules = depset(modules, transitive = transitive_modules), ) diff --git a/test/generated_header_tests.bzl b/test/generated_header_tests.bzl index 47bf7f8f5..cf216d900 100644 --- a/test/generated_header_tests.bzl +++ b/test/generated_header_tests.bzl @@ -73,18 +73,6 @@ def generated_header_test_suite(name = "generated_header"): target_under_test = "@build_bazel_rules_swift//test/fixtures/generated_header:auto_header", ) - # Verify that the generated header is propagated in `SwiftInfo`. - generate_header_and_module_map_provider_test( - name = "{}_automatically_named_header_is_propagated".format(name), - expected_files = [ - "test/fixtures/generated_header/auto_header-Swift.h", - ], - field = "transitive_generated_headers", - provider = "SwiftInfo", - tags = [name], - target_under_test = "@build_bazel_rules_swift//test/fixtures/generated_header:auto_header", - ) - # Verify that the generated module map is propagated in `apple_common.Objc`. # TODO(b/148604334): Enable this when it analyzes correctly on all platforms. # generate_header_and_module_map_provider_test( From a277fe4ede0170b501f6c727dfa38a928809a253 Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Tue, 1 Dec 2020 08:20:00 -0800 Subject: [PATCH 043/152] Standardize on FIXTURE_TAGS, ensure all targets tagged. RELNOTES: None PiperOrigin-RevId: 345024048 (cherry picked from commit d5fa2f5d711b81c5c0b7aecf97ce07ac2dd98b58) --- test/fixtures/BUILD | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/fixtures/BUILD b/test/fixtures/BUILD index fee23b0b3..2fa1a0273 100644 --- a/test/fixtures/BUILD +++ b/test/fixtures/BUILD @@ -3,9 +3,7 @@ load("@bazel_skylib//:bzl_library.bzl", "bzl_library") bzl_library( name = "starlark_tests_bzls", srcs = glob(["*.bzl"]), - visibility = [ - "//test:__pkg__", - ], + visibility = ["//test:__pkg__"], ) bzl_library( From efc75e0cb80186f5c774cb4fc87f2aeba9addad8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thi=20Do=C3=A3n?= Date: Fri, 9 Oct 2020 11:18:49 +0900 Subject: [PATCH 044/152] Deduplicate module map flags in Swift compilation Module map files being propagated through different providers seem to ended up being treated like different modules, even though they point to the same .modulemap files. Swift compilation in targets with a lot of objc_library dependencies were getting a lot of duplicate flags. This fixes that by deduplicate the module map list before passing them to the compiler. --- swift/internal/compiling.bzl | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index d1bfce6a4..2b938c8dd 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -17,6 +17,7 @@ load("@bazel_skylib//lib:collections.bzl", "collections") load("@bazel_skylib//lib:partial.bzl", "partial") load("@bazel_skylib//lib:paths.bzl", "paths") +load("@bazel_skylib//lib:sets.bzl", "sets") load("@bazel_skylib//lib:types.bzl", "types") load( ":actions.bzl", @@ -959,11 +960,14 @@ def _clang_modulemap_dependency_args(module): Returns: A list of arguments to pass to `swiftc`. """ - module_map = module.clang.module_map - if types.is_string(module_map): - module_map_path = module_map + if types.is_string(module): + module_map_path = module else: - module_map_path = module_map.path + module_map = module.clang.module_map + if types.is_string(module_map): + module_map_path = module_map + else: + module_map_path = module_map.path return [ "-Xcc", @@ -1003,8 +1007,11 @@ def _dependencies_clang_modulemaps_configurator(prerequisites, args): for module in prerequisites.transitive_modules if module.clang ] - - args.add_all(modules, map_each = _clang_modulemap_dependency_args) + module_map_paths = sets.to_list(sets.make([ + module.clang.module_map.path + for module in modules + ])) + args.add_all(module_map_paths, map_each = _clang_modulemap_dependency_args) return _collect_clang_module_inputs( cc_info = prerequisites.cc_info, From cd67daebbfc6e8e4a6f9fd98f11dbd1a0b5d5730 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Wed, 11 Nov 2020 08:21:22 -0800 Subject: [PATCH 045/152] Revert "Migrate to the modern Starlark linker input API. (#512)" This reverts commit aff1754b064898fde731a64622840535f8dd7165. --- swift/internal/linking.bzl | 40 +++++------------- swift/internal/swift_binary_test.bzl | 1 - swift/internal/swift_grpc_library.bzl | 11 ++--- swift/internal/swift_import.bzl | 22 ++++------ swift/internal/swift_library.bzl | 13 +++--- swift/internal/swift_module_alias.bzl | 12 +++--- swift/internal/swift_protoc_gen_aspect.bzl | 11 ++--- swift/internal/utils.bzl | 49 +++++++++++++++------- test/private_deps_tests.bzl | 2 +- test/rules/provider_test.bzl | 9 +--- test/split_derived_files_tests.bzl | 6 +-- 11 files changed, 76 insertions(+), 100 deletions(-) diff --git a/swift/internal/linking.bzl b/swift/internal/linking.bzl index ac8a87c27..613c77ff2 100644 --- a/swift/internal/linking.bzl +++ b/swift/internal/linking.bzl @@ -95,7 +95,6 @@ def _register_static_library_link_action( ) def register_libraries_to_link( - owning_label, actions, alwayslink, cc_feature_configuration, @@ -103,13 +102,10 @@ def register_libraries_to_link( is_static, library_name, objects, - swift_toolchain, - user_link_flags, - additional_inputs): + swift_toolchain): """Declares the requested libraries and registers actions to link them. Args: - owning_label: Label executing rule (i.e., ctx.label). actions: The object used to register actions. alwayslink: If True, create a static library that should be always-linked (having a `.lo` extension instead of `.a`). This @@ -124,11 +120,9 @@ def register_libraries_to_link( linked. swift_toolchain: The Swift toolchain provider to use when constructing the action. - user_link_flags: Extra link flags to be passed with the library. - additional_inputs: Extra inputs for a link action involving the library. Returns: - A `LinkerInput` object containing the libraries that were created. + A `LibraryToLink` object containing the libraries that were created. """ dynamic_library = None if is_dynamic: @@ -151,24 +145,16 @@ def register_libraries_to_link( else: static_library = None - return cc_common.create_linker_input( - owner = owning_label, - libraries = depset(direct = [ - cc_common.create_library_to_link( - actions = actions, - alwayslink = alwayslink, - cc_toolchain = swift_toolchain.cc_toolchain_info, - feature_configuration = cc_feature_configuration, - pic_static_library = static_library, - dynamic_library = dynamic_library, - ), - ]), - additional_inputs = depset(direct = additional_inputs), - user_link_flags = depset(direct = user_link_flags), + return cc_common.create_library_to_link( + actions = actions, + alwayslink = alwayslink, + cc_toolchain = swift_toolchain.cc_toolchain_info, + feature_configuration = cc_feature_configuration, + pic_static_library = static_library, + dynamic_library = dynamic_library, ) def register_link_binary_action( - owning_label, actions, additional_inputs, additional_linking_contexts, @@ -184,7 +170,6 @@ def register_link_binary_action( """Registers an action that invokes the linker to produce a binary. Args: - owning_label: Label of the rule creating the link action. actions: The object used to register actions. additional_inputs: A list of additional inputs to the link action, such as those used in `$(location ...)` substitution, linker @@ -246,12 +231,7 @@ def register_link_binary_action( linking_contexts.append( cc_common.create_linking_context( - linker_inputs = depset(direct = [ - cc_common.create_linker_input( - owner = owning_label, - user_link_flags = depset(direct = dep_link_flags), - ), - ]) + user_link_flags = dep_link_flags, ), ) diff --git a/swift/internal/swift_binary_test.bzl b/swift/internal/swift_binary_test.bzl index bfbc80d93..6d0d544d3 100644 --- a/swift/internal/swift_binary_test.bzl +++ b/swift/internal/swift_binary_test.bzl @@ -237,7 +237,6 @@ def _swift_linking_rule_impl( user_link_flags.extend(ctx.fragments.cpp.linkopts) linking_outputs = register_link_binary_action( - owning_label = ctx.label, actions = ctx.actions, additional_inputs = additional_inputs_to_linker, additional_linking_contexts = additional_linking_contexts, diff --git a/swift/internal/swift_grpc_library.bzl b/swift/internal/swift_grpc_library.bzl index 29ffa6f46..5688ac18c 100644 --- a/swift/internal/swift_grpc_library.bzl +++ b/swift/internal/swift_grpc_library.bzl @@ -293,8 +293,7 @@ def _swift_grpc_library_impl(ctx): target_name = ctx.label.name, ) - linker_input = register_libraries_to_link( - owning_label = ctx.label, + library_to_link = register_libraries_to_link( actions = ctx.actions, alwayslink = False, cc_feature_configuration = swift_common.cc_feature_configuration( @@ -305,8 +304,6 @@ def _swift_grpc_library_impl(ctx): library_name = ctx.label.name, objects = compilation_outputs.object_files, swift_toolchain = swift_toolchain, - additional_inputs = compilation_outputs.linker_inputs, - user_link_flags = compilation_outputs.linker_flags, ) providers = [ @@ -314,7 +311,7 @@ def _swift_grpc_library_impl(ctx): files = depset(direct = generated_files + compact([ compilation_outputs.swiftdoc, compilation_outputs.swiftmodule, - linker_input.libraries[0].pic_static_library, + library_to_link.pic_static_library, ])), ), OutputGroupInfo(**output_groups_from_compilation_outputs( @@ -323,7 +320,7 @@ def _swift_grpc_library_impl(ctx): create_cc_info( cc_infos = get_providers(compile_deps, CcInfo), compilation_outputs = compilation_outputs, - linker_inputs = [linker_input], + libraries_to_link = [library_to_link], ), deps[0][SwiftProtoInfo], swift_common.create_swift_info( @@ -349,7 +346,7 @@ def _swift_grpc_library_impl(ctx): link_inputs = compilation_outputs.linker_inputs, linkopts = compilation_outputs.linker_flags, module_map = compilation_outputs.generated_module_map, - static_archives = compact([linker_input.libraries[0].pic_static_library]), + static_archives = compact([library_to_link.pic_static_library]), swiftmodules = [compilation_outputs.swiftmodule], objc_header = compilation_outputs.generated_header, )) diff --git a/swift/internal/swift_import.bzl b/swift/internal/swift_import.bzl index 10fc0c7ec..7fdfd3f31 100644 --- a/swift/internal/swift_import.bzl +++ b/swift/internal/swift_import.bzl @@ -38,18 +38,14 @@ def _swift_import_impl(ctx): unsupported_features = ctx.disabled_features, ) - linker_inputs = [ - cc_common.create_linker_input( - libraries = depset(direct = [ - cc_common.create_library_to_link( - actions = ctx.actions, - cc_toolchain = cc_toolchain, - feature_configuration = cc_feature_configuration, - static_library = archive, - ) - for archive in archives - ]), - ), + libraries_to_link = [ + cc_common.create_library_to_link( + actions = ctx.actions, + cc_toolchain = cc_toolchain, + feature_configuration = cc_feature_configuration, + static_library = archive, + ) + for archive in archives ] providers = [ @@ -63,7 +59,7 @@ def _swift_import_impl(ctx): ), create_cc_info( cc_infos = get_providers(deps, CcInfo), - linker_inputs = linker_inputs, + libraries_to_link = libraries_to_link, ), # Propagate an `Objc` provider so that Apple-specific rules like # apple_binary` will link the imported library properly. Typically we'd diff --git a/swift/internal/swift_library.bzl b/swift/internal/swift_library.bzl index 706eb6a1b..374b5184e 100644 --- a/swift/internal/swift_library.bzl +++ b/swift/internal/swift_library.bzl @@ -179,8 +179,7 @@ def _swift_library_impl(ctx): else: clang_module = None - linker_input = register_libraries_to_link( - owning_label = ctx.label, + library_to_link = register_libraries_to_link( actions = ctx.actions, alwayslink = ctx.attr.alwayslink, cc_feature_configuration = swift_common.cc_feature_configuration( @@ -191,8 +190,6 @@ def _swift_library_impl(ctx): library_name = ctx.label.name, objects = compilation_outputs.object_files, swift_toolchain = swift_toolchain, - user_link_flags = linkopts, - additional_inputs = compilation_outputs.linker_inputs, ) direct_output_files = compact([ @@ -200,7 +197,7 @@ def _swift_library_impl(ctx): compilation_outputs.swiftdoc, compilation_outputs.swiftinterface, compilation_outputs.swiftmodule, - linker_input.libraries[0].pic_static_library, + library_to_link.pic_static_library, ]) providers = [ @@ -216,12 +213,14 @@ def _swift_library_impl(ctx): compilation_outputs = compilation_outputs, )), create_cc_info( + additional_inputs = additional_inputs, cc_infos = get_providers(deps, CcInfo), compilation_outputs = compilation_outputs, defines = ctx.attr.defines, includes = [ctx.bin_dir.path], - linker_inputs = [linker_input], + libraries_to_link = [library_to_link], private_cc_infos = get_providers(private_deps, CcInfo), + user_link_flags = linkopts, ), coverage_common.instrumented_files_info( ctx, @@ -262,7 +261,7 @@ def _swift_library_impl(ctx): link_inputs = compilation_outputs.linker_inputs + additional_inputs, linkopts = compilation_outputs.linker_flags + linkopts, module_map = compilation_outputs.generated_module_map, - static_archives = compact([linker_input.libraries[0].pic_static_library]), + static_archives = compact([library_to_link.pic_static_library]), swiftmodules = [compilation_outputs.swiftmodule], objc_header = compilation_outputs.generated_header, )) diff --git a/swift/internal/swift_module_alias.bzl b/swift/internal/swift_module_alias.bzl index 217b7798c..55a57bf7c 100644 --- a/swift/internal/swift_module_alias.bzl +++ b/swift/internal/swift_module_alias.bzl @@ -72,8 +72,7 @@ def _swift_module_alias_impl(ctx): target_name = ctx.label.name, ) - linker_input = register_libraries_to_link( - owning_label = ctx.label, + library_to_link = register_libraries_to_link( actions = ctx.actions, alwayslink = False, cc_feature_configuration = swift_common.cc_feature_configuration( @@ -84,7 +83,6 @@ def _swift_module_alias_impl(ctx): library_name = ctx.label.name, objects = compilation_outputs.object_files, swift_toolchain = swift_toolchain, - additional_inputs = compilation_outputs.linker_inputs, ) providers = [ @@ -92,8 +90,8 @@ def _swift_module_alias_impl(ctx): files = depset(compact([ compilation_outputs.swiftdoc, compilation_outputs.swiftmodule, - linker_input.libraries[0].dynamic_library, - linker_input.libraries[0].pic_static_library, + library_to_link.dynamic_library, + library_to_link.pic_static_library, ])), ), OutputGroupInfo(**output_groups_from_compilation_outputs( @@ -107,7 +105,7 @@ def _swift_module_alias_impl(ctx): cc_infos = get_providers(deps, CcInfo), compilation_outputs = compilation_outputs, includes = [ctx.bin_dir.path], - linker_inputs = [linker_input], + libraries_to_link = [library_to_link], ), swift_common.create_swift_info( modules = [ @@ -132,7 +130,7 @@ def _swift_module_alias_impl(ctx): link_inputs = compilation_outputs.linker_inputs, linkopts = compilation_outputs.linker_flags, module_map = compilation_outputs.generated_module_map, - static_archives = compact([linker_input.libraries[0].pic_static_library]), + static_archives = compact([library_to_link.pic_static_library]), swiftmodules = [compilation_outputs.swiftmodule], objc_header = compilation_outputs.generated_header, )) diff --git a/swift/internal/swift_protoc_gen_aspect.bzl b/swift/internal/swift_protoc_gen_aspect.bzl index 45f78837a..091013a9e 100644 --- a/swift/internal/swift_protoc_gen_aspect.bzl +++ b/swift/internal/swift_protoc_gen_aspect.bzl @@ -428,8 +428,7 @@ def _swift_protoc_gen_aspect_impl(target, aspect_ctx): target_name = target.label.name, ) - linker_input = register_libraries_to_link( - owning_label = aspect_ctx.label, + library_to_link = register_libraries_to_link( actions = aspect_ctx.actions, alwayslink = False, cc_feature_configuration = swift_common.cc_feature_configuration( @@ -443,8 +442,6 @@ def _swift_protoc_gen_aspect_impl(target, aspect_ctx): library_name = "{}.swift".format(target.label.name), objects = compilation_outputs.object_files, swift_toolchain = swift_toolchain, - additional_inputs = compilation_outputs.linker_inputs, - user_link_flags = compilation_outputs.linker_flags, ) # It's bad practice to attach providers you don't own to other targets, @@ -480,9 +477,9 @@ def _swift_protoc_gen_aspect_impl(target, aspect_ctx): objc_info_args["header"] = depset([ compilation_outputs.generated_header, ]) - if linker_input.libraries[0].pic_static_library: + if library_to_link.pic_static_library: objc_info_args["library"] = depset( - [linker_input.libraries[0].pic_static_library], + [library_to_link.pic_static_library], order = "topological", ) if compilation_outputs.linker_flags: @@ -519,7 +516,7 @@ def _swift_protoc_gen_aspect_impl(target, aspect_ctx): cc_infos = cc_infos, compilation_outputs = compilation_outputs, includes = includes, - linker_inputs = [linker_input], + libraries_to_link = [library_to_link], ), objc_info = objc_info, ), diff --git a/swift/internal/utils.bzl b/swift/internal/utils.bzl index fcda609af..b4e41d85f 100644 --- a/swift/internal/utils.bzl +++ b/swift/internal/utils.bzl @@ -41,20 +41,25 @@ def collect_cc_libraries( """ libraries = [] - for li in cc_info.linking_context.linker_inputs.to_list(): - for library in li.libraries: - if include_pic_static: - if library.pic_static_library: - libraries.append(library.pic_static_library) - elif library.static_library: - libraries.append(library.static_library) - elif include_static and library.static_library: + # TODO(https://github.com/bazelbuild/bazel/issues/8118): Remove once flag is + # flipped. + libraries_to_link = cc_info.linking_context.libraries_to_link + if hasattr(libraries_to_link, "to_list"): + libraries_to_link = libraries_to_link.to_list() + + for library in libraries_to_link: + if include_pic_static: + if library.pic_static_library: + libraries.append(library.pic_static_library) + elif library.static_library: libraries.append(library.static_library) + elif include_static and library.static_library: + libraries.append(library.static_library) - if include_dynamic and library.dynamic_library: - libraries.append(library.dynamic_library) - if include_interface and library.interface_library: - libraries.append(library.interface_library) + if include_dynamic and library.dynamic_library: + libraries.append(library.dynamic_library) + if include_interface and library.interface_library: + libraries.append(library.interface_library) return libraries @@ -69,15 +74,19 @@ def compact(sequence): return [item for item in sequence if item != None] def create_cc_info( + additional_inputs = [], cc_infos = [], compilation_outputs = None, defines = [], includes = [], - linker_inputs = [], - private_cc_infos = []): + libraries_to_link = [], + private_cc_infos = [], + user_link_flags = []): """Creates a `CcInfo` provider from Swift compilation info and deps. Args: + additional_inputs: A list of additional files that should be passed as + inputs to the final link action. cc_infos: A list of `CcInfo` providers from public dependencies, whose compilation and linking contexts should both be merged into the new provider. @@ -87,24 +96,32 @@ def create_cc_info( context. includes: The list of include paths to insert into the compilation context. - linker_inputs: A list of `LinkerInput` objects that represent the + libraries_to_link: A list of `LibraryToLink` objects that represent the libraries that should be linked into the final binary. private_cc_infos: A list of `CcInfo` providers from private (implementation-only) dependencies, whose linking contexts should be merged into the new provider but whose compilation contexts should be excluded. + user_link_flags: A list of flags that should be passed to the final link + action. Returns: A new `CcInfo`. """ + all_additional_inputs = list(additional_inputs) + all_user_link_flags = list(user_link_flags) all_headers = [] if compilation_outputs: + all_additional_inputs.extend(compilation_outputs.linker_inputs) + all_user_link_flags.extend(compilation_outputs.linker_flags) all_headers = compact([compilation_outputs.generated_header]) local_cc_infos = [ CcInfo( linking_context = cc_common.create_linking_context( - linker_inputs = depset(direct = linker_inputs), + additional_inputs = all_additional_inputs, + libraries_to_link = libraries_to_link, + user_link_flags = all_user_link_flags, ), compilation_context = cc_common.create_compilation_context( defines = depset(defines), diff --git a/test/private_deps_tests.bzl b/test/private_deps_tests.bzl index d08c98b0c..10d3eddb3 100644 --- a/test/private_deps_tests.bzl +++ b/test/private_deps_tests.bzl @@ -115,7 +115,7 @@ def private_deps_test_suite(name = "private_deps"): # dependencies, which we need to ignore. "*", ], - field = "linking_context.linker_inputs.libraries.static_library!", + field = "linking_context.libraries_to_link.static_library!", provider = "CcInfo", tags = [name], target_under_test = "@build_bazel_rules_swift//test/fixtures/private_deps:client_cc_deps", diff --git a/test/rules/provider_test.bzl b/test/rules/provider_test.bzl index b9cf0b762..42799fa79 100644 --- a/test/rules/provider_test.bzl +++ b/test/rules/provider_test.bzl @@ -85,14 +85,7 @@ def _evaluate_field(env, source, field): ) return _EVALUATE_FIELD_FAILED - expanded = [] - for item in source: - item = _normalize_collection(item) - if types.is_list(item): - expanded.extend(item) - else: - expanded.append(item) - source = [getattr(item, component, None) for item in expanded] + source = [getattr(item, component, None) for item in source] if filter_nones: source = [item for item in source if item != None] else: diff --git a/test/split_derived_files_tests.bzl b/test/split_derived_files_tests.bzl index 34839ebae..2eeb17664 100644 --- a/test/split_derived_files_tests.bzl +++ b/test/split_derived_files_tests.bzl @@ -114,7 +114,7 @@ def split_derived_files_test_suite(name = "split_derived_files"): expected_files = [ "libsimple.a", ], - field = "linking_context.linker_inputs.libraries.pic_static_library!", + field = "linking_context.libraries_to_link.pic_static_library!", provider = "CcInfo", tags = [name], target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", @@ -162,7 +162,7 @@ def split_derived_files_test_suite(name = "split_derived_files"): expected_files = [ "libsimple.a", ], - field = "linking_context.linker_inputs.libraries.pic_static_library!", + field = "linking_context.libraries_to_link.pic_static_library!", provider = "CcInfo", tags = [name], target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", @@ -212,7 +212,7 @@ def split_derived_files_test_suite(name = "split_derived_files"): expected_files = [ "libsimple.a", ], - field = "linking_context.linker_inputs.libraries.pic_static_library!", + field = "linking_context.libraries_to_link.pic_static_library!", provider = "CcInfo", tags = [name], target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", From 2e1d299c3589930396ed4a9f51a36740b27017ec Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Wed, 11 Nov 2020 08:02:29 -0800 Subject: [PATCH 046/152] Migrate Swift build rules to the new C++ `LinkerInput` APIs. Based partially on https://github.com/bazelbuild/rules_swift/pull/512 by @benjaminp. PiperOrigin-RevId: 341831304 (cherry picked from commit bf9560d39502f33bfdf478199c9a7ef95ad3dc2b) --- swift/internal/linking.bzl | 45 +++++++++++++++--- swift/internal/swift_binary_test.bzl | 1 + swift/internal/swift_grpc_library.bzl | 8 ++-- swift/internal/swift_import.bzl | 23 ++++++---- swift/internal/swift_library.bzl | 12 +++-- swift/internal/swift_module_alias.bzl | 8 ++-- swift/internal/swift_protoc_gen_aspect.bzl | 8 ++-- swift/internal/utils.bzl | 53 ++++++++-------------- test/private_deps_tests.bzl | 2 +- test/rules/provider_test.bzl | 11 ++++- 10 files changed, 105 insertions(+), 66 deletions(-) diff --git a/swift/internal/linking.bzl b/swift/internal/linking.bzl index 613c77ff2..7520bfcca 100644 --- a/swift/internal/linking.bzl +++ b/swift/internal/linking.bzl @@ -94,16 +94,21 @@ def _register_static_library_link_action( progress_message = "Linking {}".format(output.short_path), ) -def register_libraries_to_link( +def create_linker_input( + *, actions, alwayslink, cc_feature_configuration, + compilation_outputs, is_dynamic, is_static, library_name, objects, - swift_toolchain): - """Declares the requested libraries and registers actions to link them. + owner, + swift_toolchain, + additional_inputs = [], + user_link_flags = []): + """Creates a linker input for a library to link and additional inputs/flags. Args: actions: The object used to register actions. @@ -112,17 +117,26 @@ def register_libraries_to_link( argument is ignored if `is_static` is False. cc_feature_configuration: The C++ feature configuration to use when constructing the action. + compilation_outputs: The compilation outputs from a Swift compile + action, as returned by `swift_common.compile`, or None. is_dynamic: If True, declare and link a dynamic library. is_static: If True, declare and link a static library. library_name: The basename (without extension) of the libraries to declare. objects: A list of `File`s denoting object (`.o`) files that will be linked. + owner: The `Label` of the target that owns this linker input. swift_toolchain: The Swift toolchain provider to use when constructing the action. + additional_inputs: A list of extra `File` inputs passed to the linking + action. + user_link_flags: A list of extra flags to pass to the linking command. Returns: - A `LibraryToLink` object containing the libraries that were created. + A tuple containing two elements: + + 1. A `LinkerInput` object containing the library that was created. + 2. The single `LibraryToLink` object that is inside the linker input. """ dynamic_library = None if is_dynamic: @@ -145,7 +159,7 @@ def register_libraries_to_link( else: static_library = None - return cc_common.create_library_to_link( + library_to_link = cc_common.create_library_to_link( actions = actions, alwayslink = alwayslink, cc_toolchain = swift_toolchain.cc_toolchain_info, @@ -153,6 +167,18 @@ def register_libraries_to_link( pic_static_library = static_library, dynamic_library = dynamic_library, ) + linker_input = cc_common.create_linker_input( + owner = owner, + libraries = depset([library_to_link]), + additional_inputs = depset( + compilation_outputs.linker_inputs + additional_inputs, + ), + user_link_flags = depset( + compilation_outputs.linker_flags + user_link_flags, + ), + ) + + return linker_input, library_to_link def register_link_binary_action( actions, @@ -164,6 +190,7 @@ def register_link_binary_action( name, objects, output_type, + owner, stamp, swift_toolchain, user_link_flags): @@ -186,6 +213,7 @@ def register_link_binary_action( objects: A list of object (.o) files that will be passed to the linker. output_type: A string indicating the output type; "executable" or "dynamic_library". + owner: The `Label` of the target that owns this linker input. stamp: A tri-state value (-1, 0, or 1) that specifies whether link stamping is enabled. See `cc_common.link` for details about the behavior of this argument. @@ -231,7 +259,12 @@ def register_link_binary_action( linking_contexts.append( cc_common.create_linking_context( - user_link_flags = dep_link_flags, + linker_inputs = depset([ + cc_common.create_linker_input( + owner = owner, + user_link_flags = depset(dep_link_flags), + ), + ]), ), ) diff --git a/swift/internal/swift_binary_test.bzl b/swift/internal/swift_binary_test.bzl index 6d0d544d3..cb394f563 100644 --- a/swift/internal/swift_binary_test.bzl +++ b/swift/internal/swift_binary_test.bzl @@ -246,6 +246,7 @@ def _swift_linking_rule_impl( name = ctx.label.name, objects = objects_to_link, output_type = "executable", + owner = ctx.label, stamp = ctx.attr.stamp, swift_toolchain = swift_toolchain, user_link_flags = user_link_flags, diff --git a/swift/internal/swift_grpc_library.bzl b/swift/internal/swift_grpc_library.bzl index 5688ac18c..8ca93dcc4 100644 --- a/swift/internal/swift_grpc_library.bzl +++ b/swift/internal/swift_grpc_library.bzl @@ -27,7 +27,7 @@ load( "SWIFT_FEATURE_GENERATE_FROM_RAW_PROTO_FILES", "SWIFT_FEATURE_NO_GENERATED_HEADER", ) -load(":linking.bzl", "register_libraries_to_link") +load(":linking.bzl", "create_linker_input") load( ":proto_gen_utils.bzl", "declare_generated_files", @@ -293,16 +293,18 @@ def _swift_grpc_library_impl(ctx): target_name = ctx.label.name, ) - library_to_link = register_libraries_to_link( + linker_input, library_to_link = create_linker_input( actions = ctx.actions, alwayslink = False, cc_feature_configuration = swift_common.cc_feature_configuration( feature_configuration = feature_configuration, ), + compilation_outputs = compilation_outputs, is_dynamic = False, is_static = True, library_name = ctx.label.name, objects = compilation_outputs.object_files, + owner = ctx.label, swift_toolchain = swift_toolchain, ) @@ -320,7 +322,7 @@ def _swift_grpc_library_impl(ctx): create_cc_info( cc_infos = get_providers(compile_deps, CcInfo), compilation_outputs = compilation_outputs, - libraries_to_link = [library_to_link], + linker_inputs = [linker_input], ), deps[0][SwiftProtoInfo], swift_common.create_swift_info( diff --git a/swift/internal/swift_import.bzl b/swift/internal/swift_import.bzl index 7fdfd3f31..079feeb3a 100644 --- a/swift/internal/swift_import.bzl +++ b/swift/internal/swift_import.bzl @@ -38,15 +38,18 @@ def _swift_import_impl(ctx): unsupported_features = ctx.disabled_features, ) - libraries_to_link = [ - cc_common.create_library_to_link( - actions = ctx.actions, - cc_toolchain = cc_toolchain, - feature_configuration = cc_feature_configuration, - static_library = archive, - ) - for archive in archives - ] + linker_input = cc_common.create_linker_input( + owner = ctx.label, + libraries = depset([ + cc_common.create_library_to_link( + actions = ctx.actions, + cc_toolchain = cc_toolchain, + feature_configuration = cc_feature_configuration, + static_library = archive, + ) + for archive in archives + ]), + ) providers = [ DefaultInfo( @@ -59,7 +62,7 @@ def _swift_import_impl(ctx): ), create_cc_info( cc_infos = get_providers(deps, CcInfo), - libraries_to_link = libraries_to_link, + linker_inputs = [linker_input], ), # Propagate an `Objc` provider so that Apple-specific rules like # apple_binary` will link the imported library properly. Typically we'd diff --git a/swift/internal/swift_library.bzl b/swift/internal/swift_library.bzl index 374b5184e..bf7d49644 100644 --- a/swift/internal/swift_library.bzl +++ b/swift/internal/swift_library.bzl @@ -28,7 +28,7 @@ load( "SWIFT_FEATURE_ENABLE_LIBRARY_EVOLUTION", "SWIFT_FEATURE_SUPPORTS_PRIVATE_DEPS", ) -load(":linking.bzl", "register_libraries_to_link") +load(":linking.bzl", "create_linker_input") load(":providers.bzl", "SwiftInfo", "SwiftToolchainInfo") load(":swift_common.bzl", "swift_common") load( @@ -179,17 +179,21 @@ def _swift_library_impl(ctx): else: clang_module = None - library_to_link = register_libraries_to_link( + linker_input, library_to_link = create_linker_input( actions = ctx.actions, + additional_inputs = additional_inputs, alwayslink = ctx.attr.alwayslink, cc_feature_configuration = swift_common.cc_feature_configuration( feature_configuration = feature_configuration, ), + compilation_outputs = compilation_outputs, is_dynamic = False, is_static = True, library_name = ctx.label.name, objects = compilation_outputs.object_files, + owner = ctx.label, swift_toolchain = swift_toolchain, + user_link_flags = linkopts, ) direct_output_files = compact([ @@ -213,14 +217,12 @@ def _swift_library_impl(ctx): compilation_outputs = compilation_outputs, )), create_cc_info( - additional_inputs = additional_inputs, cc_infos = get_providers(deps, CcInfo), compilation_outputs = compilation_outputs, defines = ctx.attr.defines, includes = [ctx.bin_dir.path], - libraries_to_link = [library_to_link], + linker_inputs = [linker_input], private_cc_infos = get_providers(private_deps, CcInfo), - user_link_flags = linkopts, ), coverage_common.instrumented_files_info( ctx, diff --git a/swift/internal/swift_module_alias.bzl b/swift/internal/swift_module_alias.bzl index 55a57bf7c..cff5a9abd 100644 --- a/swift/internal/swift_module_alias.bzl +++ b/swift/internal/swift_module_alias.bzl @@ -21,7 +21,7 @@ load( "output_groups_from_compilation_outputs", ) load(":derived_files.bzl", "derived_files") -load(":linking.bzl", "register_libraries_to_link") +load(":linking.bzl", "create_linker_input") load(":providers.bzl", "SwiftInfo", "SwiftToolchainInfo") load(":swift_common.bzl", "swift_common") load(":utils.bzl", "compact", "create_cc_info", "get_providers") @@ -72,16 +72,18 @@ def _swift_module_alias_impl(ctx): target_name = ctx.label.name, ) - library_to_link = register_libraries_to_link( + linker_input, library_to_link = create_linker_input( actions = ctx.actions, alwayslink = False, cc_feature_configuration = swift_common.cc_feature_configuration( feature_configuration = feature_configuration, ), + compilation_outputs = compilation_outputs, is_dynamic = False, is_static = True, library_name = ctx.label.name, objects = compilation_outputs.object_files, + owner = ctx.label, swift_toolchain = swift_toolchain, ) @@ -105,7 +107,7 @@ def _swift_module_alias_impl(ctx): cc_infos = get_providers(deps, CcInfo), compilation_outputs = compilation_outputs, includes = [ctx.bin_dir.path], - libraries_to_link = [library_to_link], + linker_inputs = [linker_input], ), swift_common.create_swift_info( modules = [ diff --git a/swift/internal/swift_protoc_gen_aspect.bzl b/swift/internal/swift_protoc_gen_aspect.bzl index 091013a9e..3f7536e42 100644 --- a/swift/internal/swift_protoc_gen_aspect.bzl +++ b/swift/internal/swift_protoc_gen_aspect.bzl @@ -27,7 +27,7 @@ load( "SWIFT_FEATURE_GENERATE_FROM_RAW_PROTO_FILES", "SWIFT_FEATURE_NO_GENERATED_HEADER", ) -load(":linking.bzl", "register_libraries_to_link") +load(":linking.bzl", "create_linker_input") load( ":proto_gen_utils.bzl", "declare_generated_files", @@ -428,12 +428,13 @@ def _swift_protoc_gen_aspect_impl(target, aspect_ctx): target_name = target.label.name, ) - library_to_link = register_libraries_to_link( + linker_input, library_to_link = create_linker_input( actions = aspect_ctx.actions, alwayslink = False, cc_feature_configuration = swift_common.cc_feature_configuration( feature_configuration = feature_configuration, ), + compilation_outputs = compilation_outputs, is_dynamic = False, is_static = True, # Prevent conflicts with C++ protos in the same output directory, @@ -441,6 +442,7 @@ def _swift_protoc_gen_aspect_impl(target, aspect_ctx): # `lib{name}.swift.a` instead. library_name = "{}.swift".format(target.label.name), objects = compilation_outputs.object_files, + owner = target.label, swift_toolchain = swift_toolchain, ) @@ -516,7 +518,7 @@ def _swift_protoc_gen_aspect_impl(target, aspect_ctx): cc_infos = cc_infos, compilation_outputs = compilation_outputs, includes = includes, - libraries_to_link = [library_to_link], + linker_inputs = [linker_input], ), objc_info = objc_info, ), diff --git a/swift/internal/utils.bzl b/swift/internal/utils.bzl index b4e41d85f..4c248ab85 100644 --- a/swift/internal/utils.bzl +++ b/swift/internal/utils.bzl @@ -41,25 +41,20 @@ def collect_cc_libraries( """ libraries = [] - # TODO(https://github.com/bazelbuild/bazel/issues/8118): Remove once flag is - # flipped. - libraries_to_link = cc_info.linking_context.libraries_to_link - if hasattr(libraries_to_link, "to_list"): - libraries_to_link = libraries_to_link.to_list() - - for library in libraries_to_link: - if include_pic_static: - if library.pic_static_library: - libraries.append(library.pic_static_library) - elif library.static_library: + for linker_input in cc_info.linking_context.linker_inputs.to_list(): + for library in linker_input.libraries: + if include_pic_static: + if library.pic_static_library: + libraries.append(library.pic_static_library) + elif library.static_library: + libraries.append(library.static_library) + elif include_static and library.static_library: libraries.append(library.static_library) - elif include_static and library.static_library: - libraries.append(library.static_library) - if include_dynamic and library.dynamic_library: - libraries.append(library.dynamic_library) - if include_interface and library.interface_library: - libraries.append(library.interface_library) + if include_dynamic and library.dynamic_library: + libraries.append(library.dynamic_library) + if include_interface and library.interface_library: + libraries.append(library.interface_library) return libraries @@ -74,19 +69,16 @@ def compact(sequence): return [item for item in sequence if item != None] def create_cc_info( - additional_inputs = [], + *, cc_infos = [], compilation_outputs = None, defines = [], includes = [], - libraries_to_link = [], - private_cc_infos = [], - user_link_flags = []): + linker_inputs = [], + private_cc_infos = []): """Creates a `CcInfo` provider from Swift compilation info and deps. Args: - additional_inputs: A list of additional files that should be passed as - inputs to the final link action. cc_infos: A list of `CcInfo` providers from public dependencies, whose compilation and linking contexts should both be merged into the new provider. @@ -96,32 +88,25 @@ def create_cc_info( context. includes: The list of include paths to insert into the compilation context. - libraries_to_link: A list of `LibraryToLink` objects that represent the - libraries that should be linked into the final binary. + linker_inputs: A list of `LinkerInput` objects that represent the + libraries that should be linked into the final binary as well as any + additional inputs and flags that should be passed to the linker. private_cc_infos: A list of `CcInfo` providers from private (implementation-only) dependencies, whose linking contexts should be merged into the new provider but whose compilation contexts should be excluded. - user_link_flags: A list of flags that should be passed to the final link - action. Returns: A new `CcInfo`. """ - all_additional_inputs = list(additional_inputs) - all_user_link_flags = list(user_link_flags) all_headers = [] if compilation_outputs: - all_additional_inputs.extend(compilation_outputs.linker_inputs) - all_user_link_flags.extend(compilation_outputs.linker_flags) all_headers = compact([compilation_outputs.generated_header]) local_cc_infos = [ CcInfo( linking_context = cc_common.create_linking_context( - additional_inputs = all_additional_inputs, - libraries_to_link = libraries_to_link, - user_link_flags = all_user_link_flags, + linker_inputs = depset(linker_inputs), ), compilation_context = cc_common.create_compilation_context( defines = depset(defines), diff --git a/test/private_deps_tests.bzl b/test/private_deps_tests.bzl index 10d3eddb3..d08c98b0c 100644 --- a/test/private_deps_tests.bzl +++ b/test/private_deps_tests.bzl @@ -115,7 +115,7 @@ def private_deps_test_suite(name = "private_deps"): # dependencies, which we need to ignore. "*", ], - field = "linking_context.libraries_to_link.static_library!", + field = "linking_context.linker_inputs.libraries.static_library!", provider = "CcInfo", tags = [name], target_under_test = "@build_bazel_rules_swift//test/fixtures/private_deps:client_cc_deps", diff --git a/test/rules/provider_test.bzl b/test/rules/provider_test.bzl index 42799fa79..f9744e98d 100644 --- a/test/rules/provider_test.bzl +++ b/test/rules/provider_test.bzl @@ -85,7 +85,16 @@ def _evaluate_field(env, source, field): ) return _EVALUATE_FIELD_FAILED - source = [getattr(item, component, None) for item in source] + # If the elements are lists or depsets, flatten the whole thing into + # a single list. + flattened = [] + for item in source: + item = _normalize_collection(item) + if types.is_list(item): + flattened.extend(item) + else: + flattened.append(item) + source = [getattr(item, component, None) for item in flattened] if filter_nones: source = [item for item in source if item != None] else: From 989430f3a06218ac3c0c6d4b9af330f275f3888b Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Tue, 1 Dec 2020 14:48:41 -0800 Subject: [PATCH 047/152] Fix tests --- test/split_derived_files_tests.bzl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/split_derived_files_tests.bzl b/test/split_derived_files_tests.bzl index 2eeb17664..34839ebae 100644 --- a/test/split_derived_files_tests.bzl +++ b/test/split_derived_files_tests.bzl @@ -114,7 +114,7 @@ def split_derived_files_test_suite(name = "split_derived_files"): expected_files = [ "libsimple.a", ], - field = "linking_context.libraries_to_link.pic_static_library!", + field = "linking_context.linker_inputs.libraries.pic_static_library!", provider = "CcInfo", tags = [name], target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", @@ -162,7 +162,7 @@ def split_derived_files_test_suite(name = "split_derived_files"): expected_files = [ "libsimple.a", ], - field = "linking_context.libraries_to_link.pic_static_library!", + field = "linking_context.linker_inputs.libraries.pic_static_library!", provider = "CcInfo", tags = [name], target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", @@ -212,7 +212,7 @@ def split_derived_files_test_suite(name = "split_derived_files"): expected_files = [ "libsimple.a", ], - field = "linking_context.libraries_to_link.pic_static_library!", + field = "linking_context.linker_inputs.libraries.pic_static_library!", provider = "CcInfo", tags = [name], target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", From 7fdbb717372911b87537b83fff86927217c6557b Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Tue, 1 Dec 2020 16:09:15 -0800 Subject: [PATCH 048/152] Make the `srcs` attribute of `swift_library` mandatory and non-empty. PiperOrigin-RevId: 345120894 (cherry picked from commit c21080442fe664cfa3f4a35fc654e10af8791b37) --- swift/internal/attrs.bzl | 17 ++++++++++++++--- swift/internal/swift_binary_test.bzl | 1 + 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/swift/internal/attrs.bzl b/swift/internal/attrs.bzl index ffac373e3..9954f89d0 100644 --- a/swift/internal/attrs.bzl +++ b/swift/internal/attrs.bzl @@ -43,7 +43,9 @@ indirect (transitive) dependents. ), } -def swift_compilation_attrs(additional_deps_aspects = []): +def swift_compilation_attrs( + additional_deps_aspects = [], + requires_srcs = True): """Returns an attribute dictionary for rules that compile Swift code. The returned dictionary contains the subset of attributes that are shared by @@ -76,6 +78,8 @@ def swift_compilation_attrs(additional_deps_aspects = []): 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`. Returns: A new attribute dictionary that can be added to the attributes of a @@ -89,11 +93,13 @@ def swift_compilation_attrs(additional_deps_aspects = []): swift_toolchain_attrs(), { "srcs": attr.label_list( - flags = ["DIRECT_COMPILE_TIME_INPUT"], + allow_empty = not requires_srcs, allow_files = ["swift"], doc = """\ A list of `.swift` source files that will be compiled into the library. """, + flags = ["DIRECT_COMPILE_TIME_INPUT"], + mandatory = requires_srcs, ), "copts": attr.string_list( doc = """\ @@ -186,7 +192,9 @@ Linux), those dependencies will be **ignored.** **kwargs ) -def swift_library_rule_attrs(additional_deps_aspects = []): +def swift_library_rule_attrs( + additional_deps_aspects = [], + requires_srcs = True): """Returns an attribute dictionary for `swift_library`-like rules. The returned dictionary contains the same attributes that are defined by the @@ -221,6 +229,8 @@ def swift_library_rule_attrs(additional_deps_aspects = []): 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`. Returns: A new attribute dictionary that can be added to the attributes of a @@ -229,6 +239,7 @@ def swift_library_rule_attrs(additional_deps_aspects = []): return dicts.add( swift_compilation_attrs( additional_deps_aspects = additional_deps_aspects, + requires_srcs = requires_srcs, ), swift_config_attrs(), { diff --git a/swift/internal/swift_binary_test.bzl b/swift/internal/swift_binary_test.bzl index cb394f563..d5eec6dab 100644 --- a/swift/internal/swift_binary_test.bzl +++ b/swift/internal/swift_binary_test.bzl @@ -36,6 +36,7 @@ def _binary_rule_attrs(stamp_default): return dicts.add( swift_common.compilation_attrs( additional_deps_aspects = [swift_common.swift_clang_module_aspect], + requires_srcs = False, ), { "linkopts": attr.string_list( From 0f773324d3778e21a6a3c57ef8d3cdd8e4e5a645 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Tue, 1 Dec 2020 17:05:23 -0800 Subject: [PATCH 049/152] Update README with new URLs --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2f9a759a2..654c74ed6 100644 --- a/README.md +++ b/README.md @@ -51,8 +51,8 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "build_bazel_rules_swift", - sha256 = "a228a8e41fdc165a2c55924b728c466e0086f3e638a05d6da98aa6222cbb19c1", - url = "https://github.com/bazelbuild/rules_swift/releases/download/0.16.1/rules_swift.0.16.1.tar.gz", + sha256 = "c07abf4d94fef598c45e539e9adc0ed25795260c618e167b714cc285b20525e2", + url = "https://github.com/bazelbuild/rules_swift/releases/download/0.17.0/rules_swift.0.17.0.tar.gz", ) load( From eca50db5a95a50b2be8367d644aebf4d1d880c52 Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Wed, 2 Dec 2020 08:26:26 -0800 Subject: [PATCH 050/152] Migration off SwiftInfo.module_name. - Make module alias use the direct modules instead with legacy fall back for the existing support. - Validate during creation of SwiftInfo that any provided module_name matches the first module (if any modules are provided). RELNOTES: None PiperOrigin-RevId: 345237478 (cherry picked from commit 46613b2f6056cfd9b0c491f72f1faa57c938e3db) --- swift/internal/providers.bzl | 2 ++ swift/internal/swift_module_alias.bzl | 11 +++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/swift/internal/providers.bzl b/swift/internal/providers.bzl index e85dc13ad..d0fb34a08 100644 --- a/swift/internal/providers.bzl +++ b/swift/internal/providers.bzl @@ -350,6 +350,8 @@ def create_swift_info( # was one, and if the legacy `module_name` parameter wasn't already # given. module_name = modules[0].name + elif module_name and modules and module_name != modules[0].name: + fail("Explicit module name should be the first provided module.") transitive_defines = [] transitive_modules = [] diff --git a/swift/internal/swift_module_alias.bzl b/swift/internal/swift_module_alias.bzl index cff5a9abd..927daab86 100644 --- a/swift/internal/swift_module_alias.bzl +++ b/swift/internal/swift_module_alias.bzl @@ -29,11 +29,18 @@ load(":utils.bzl", "compact", "create_cc_info", "get_providers") def _swift_module_alias_impl(ctx): deps = ctx.attr.deps module_mapping = { - dep[SwiftInfo].module_name: dep.label + module.name: dep.label for dep in deps - if dep[SwiftInfo].module_name + for module in dep[SwiftInfo].direct_modules } + # TODO(b/149999519): remove the support for SwiftInfo.module_name that + # didn't have any direct_modules. + for dep in deps: + swift_info = dep[SwiftInfo] + if not swift_info.direct_modules and swift_info.module_name: + module_mapping[swift_info.module_name] = dep.label + module_name = ctx.attr.module_name if not module_name: module_name = swift_common.derive_module_name(ctx.label) From 768bfe3fe885f92fbaea75488268e2612ab9ef9c Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Thu, 10 Dec 2020 07:58:06 -0800 Subject: [PATCH 051/152] Add the SDK's `Developer/Library/Frameworks` directory to the compiler and linker search paths on platforms that have it. Added in Xcode 12, `StoreKitTest.framework` is in a new Developer directory hierarchy under the SDK root (not to be confused with the one under the `.platform` root), except on macOS where it *does* live in the `.platform`'s Developer directory. A small cleanup here means we also no longer pass a non-existent developer frameworks path when targeting watchOS. PiperOrigin-RevId: 346784495 (cherry picked from commit 0ec7a5783be1e5daf02f1d1748cf03c07e0fcc0e) --- swift/internal/xcode_swift_toolchain.bzl | 156 ++++++++++++++++++----- 1 file changed, 122 insertions(+), 34 deletions(-) diff --git a/swift/internal/xcode_swift_toolchain.bzl b/swift/internal/xcode_swift_toolchain.bzl index 8cd32ab1c..21ac36dfd 100644 --- a/swift/internal/xcode_swift_toolchain.bzl +++ b/swift/internal/xcode_swift_toolchain.bzl @@ -47,7 +47,7 @@ load( load(":features.bzl", "features_for_build_modes") load(":toolchain_config.bzl", "swift_toolchain_config") load(":providers.bzl", "SwiftToolchainInfo") -load(":utils.bzl", "get_swift_executable_for_toolchain") +load(":utils.bzl", "compact", "get_swift_executable_for_toolchain") def _swift_developer_lib_dir(platform_framework_dir): """Returns the directory containing extra Swift developer libraries. @@ -115,6 +115,47 @@ def _command_line_objc_copts(compilation_mode, objc_fragment): [copt for copt in clang_copts if copt != "-g"], ) +def _platform_developer_framework_dir(apple_toolchain, apple_fragment): + """Returns the Developer framework directory for the platform. + + Args: + apple_fragment: The `apple` configuration fragment. + apple_toolchain: The `apple_common.apple_toolchain()` object. + + Returns: + The path to the Developer framework directory for the platform if one + exists, otherwise `None`. + """ + platform_type = apple_fragment.single_arch_platform.platform_type + if platform_type == apple_common.platform_type.watchos: + return None + + # All platforms except watchOS have a `Developer/Library/Frameworks` + # directory in their platform root. + return apple_toolchain.platform_developer_framework_dir(apple_fragment) + +def _sdk_developer_framework_dir(apple_toolchain, apple_fragment): + """Returns the Developer framework directory for the SDK. + + Args: + apple_fragment: The `apple` configuration fragment. + apple_toolchain: The `apple_common.apple_toolchain()` object. + + Returns: + The path to the Developer framework directory for the SDK if one + exists, otherwise `None`. + """ + platform_type = apple_fragment.single_arch_platform.platform_type + if platform_type in ( + apple_common.platform_type.macos, + apple_common.platform_type.watchos, + ): + return None + + # All platforms except macOS and watchOS have a + # `Developer/Library/Frameworks` directory in their SDK root. + return paths.join(apple_toolchain.sdk_dir(), "Developer/Library/Frameworks") + def _default_linker_opts( apple_fragment, apple_toolchain, @@ -143,7 +184,12 @@ def _default_linker_opts( The command line options to pass to `clang` to link against the desired variant of the Swift runtime libraries. """ - platform_framework_dir = apple_toolchain.platform_developer_framework_dir( + platform_developer_framework_dir = _platform_developer_framework_dir( + apple_toolchain, + apple_fragment, + ) + sdk_developer_framework_dir = _sdk_developer_framework_dir( + apple_toolchain, apple_fragment, ) linkopts = [] @@ -189,28 +235,41 @@ def _default_linker_opts( if uses_runtime_in_os and platform == apple_common.platform.macos: linkopts.append("-Wl,-rpath,{}".format(swift_lib_dir)) - linkopts.extend([ - "-F{}".format(platform_framework_dir), - "-L{}".format(swift_lib_dir), - # TODO(b/112000244): These should get added by the C++ Starlark API, but - # we're using the "c++-link-executable" action right now instead of - # "objc-executable" because the latter requires additional variables not - # provided by cc_common. Figure out how to handle this correctly. - "-ObjC", - "-Wl,-objc_abi_version,2", - ]) + linkopts.extend( + [ + "-F{}".format(path) + for path in compact([ + platform_developer_framework_dir, + sdk_developer_framework_dir, + ]) + ] + [ + "-L{}".format(swift_lib_dir), + # TODO(b/112000244): These should get added by the C++ Starlark API, + # but we're using the "c++-link-executable" action right now instead + # of "objc-executable" because the latter requires additional + # variables not provided by cc_common. Figure out how to handle this + # correctly. + "-ObjC", + "-Wl,-objc_abi_version,2", + ], + ) use_system_swift_libs = _is_xcode_at_least_version(xcode_config, "11.0") if use_system_swift_libs: linkopts.append("-L/usr/lib/swift") - # XCTest.framework only lives in the Xcode bundle (its platform framework - # directory), so test binaries need to have that directory explicitly added - # to their rpaths. - if is_test: + # Frameworks in the platform's developer frameworks directory (like XCTest, + # but also StoreKitTest on macOS) contain the actual binary for that + # framework, not a .tbd file that says where to find it on simulator/device. + # So, we need to explicitly add that to test binaries' rpaths. We also need + # to add the linker path to the directory containing the dylib with Swift + # extensions for the XCTest module. + if is_test and platform_developer_framework_dir: linkopts.extend([ - "-Wl,-rpath,{}".format(platform_framework_dir), - "-L{}".format(_swift_developer_lib_dir(platform_framework_dir)), + "-Wl,-rpath,{}".format(platform_developer_framework_dir), + "-L{}".format( + _swift_developer_lib_dir(platform_developer_framework_dir), + ), ]) return linkopts @@ -280,14 +339,21 @@ def _all_action_configs( Returns: The action configurations for the Swift toolchain. """ - developer_dir = apple_toolchain.developer_dir() - platform_framework_dir = ( - apple_toolchain.platform_developer_framework_dir(apple_fragment) + platform_developer_framework_dir = _platform_developer_framework_dir( + apple_toolchain, + apple_fragment, ) - sdk_dir = apple_toolchain.sdk_dir() + sdk_developer_framework_dir = _sdk_developer_framework_dir( + apple_toolchain, + apple_fragment, + ) + developer_framework_dirs = compact([ + platform_developer_framework_dir, + sdk_developer_framework_dir, + ]) + # Basic compilation flags (target triple and toolchain search paths). action_configs = [ - # Basic compilation flags (target triple and toolchain search paths). swift_toolchain_config.action_config( actions = [ swift_action_names.COMPILE, @@ -296,15 +362,13 @@ def _all_action_configs( ], configurators = [ swift_toolchain_config.add_arg("-target", target_triple), - swift_toolchain_config.add_arg("-sdk", sdk_dir), swift_toolchain_config.add_arg( - platform_framework_dir, - format = "-F%s", - ), - swift_toolchain_config.add_arg( - _swift_developer_lib_dir(platform_framework_dir), - format = "-I%s", + "-sdk", + apple_toolchain.sdk_dir(), ), + ] + [ + swift_toolchain_config.add_arg(framework_dir, format = "-F%s") + for framework_dir in developer_framework_dirs ], ), swift_toolchain_config.action_config( @@ -312,12 +376,36 @@ def _all_action_configs( configurators = [ swift_toolchain_config.add_arg( "-Xcc", - platform_framework_dir, + framework_dir, format = "-F%s", - ), + ) + for framework_dir in developer_framework_dirs ], ), + ] + # The platform developer framework directory contains XCTest.swiftmodule + # with Swift extensions to XCTest, so it needs to be added to the search + # path on platforms where it exists. + if platform_developer_framework_dir: + action_configs.append( + swift_toolchain_config.action_config( + actions = [ + swift_action_names.COMPILE, + swift_action_names.PRECOMPILE_C_MODULE, + ], + configurators = [ + swift_toolchain_config.add_arg( + _swift_developer_lib_dir( + platform_developer_framework_dir, + ), + format = "-I%s", + ), + ], + ), + ) + + action_configs.extend([ # Bitcode-related flags. swift_toolchain_config.action_config( actions = [ @@ -373,7 +461,7 @@ def _all_action_configs( ], ], ), - ] + ]) if needs_resource_directory: # If the user is using a custom driver but not a complete custom @@ -389,7 +477,7 @@ def _all_action_configs( configurators = [ partial.make( _resource_directory_configurator, - developer_dir, + apple_toolchain.developer_dir(), ), ], ), From 92ce7022504c44fb2862f6feb0fe7dcdab87b543 Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Fri, 11 Dec 2020 10:59:27 -0800 Subject: [PATCH 052/152] Require `name` to be a named argument. RELNOTES: None PiperOrigin-RevId: 347033042 (cherry picked from commit 3355e61c8cddd33e2e3158d61a3ddefd06368b38) --- swift/internal/providers.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swift/internal/providers.bzl b/swift/internal/providers.bzl index d0fb34a08..dcb8124aa 100644 --- a/swift/internal/providers.bzl +++ b/swift/internal/providers.bzl @@ -202,7 +202,7 @@ provider. }, ) -def create_module(name, *, clang = None, swift = None): +def create_module(*, name, clang = None, swift = None): """Creates a value containing Clang/Swift module artifacts of a dependency. At least one of the `clang` and `swift` arguments must not be `None`. It is From bdb2a7b10a0bd8680d08b87390d2e045d00a8df0 Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Fri, 11 Dec 2020 11:08:35 -0800 Subject: [PATCH 053/152] Retire `module_name` from create_swift_info. RELNOTES: None PiperOrigin-RevId: 347035229 (cherry picked from commit 6e4e3ca24f5d927828cc2b115fc64b75b8b0ab52) --- swift/internal/providers.bzl | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/swift/internal/providers.bzl b/swift/internal/providers.bzl index dcb8124aa..38abb7aae 100644 --- a/swift/internal/providers.bzl +++ b/swift/internal/providers.bzl @@ -297,7 +297,6 @@ def create_swift_module( def create_swift_info( *, - module_name = None, modules = [], swift_infos = [], swift_version = None): @@ -314,8 +313,6 @@ def create_swift_info( true Swift module; it is merely a "collector" for other dependencies. Args: - module_name: This argument is deprecated. The module name(s) should be - specified in the values passed to the `modules` argument. 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. @@ -344,15 +341,6 @@ def create_swift_info( defines = sets.to_list(defines_set) - # TODO(b/149999519): Remove the legacy `module_name`. - if not module_name and len(modules) == 1: - # Populate the module name based on the single module provided, if there - # was one, and if the legacy `module_name` parameter wasn't already - # given. - module_name = modules[0].name - elif module_name and modules and module_name != modules[0].name: - fail("Explicit module name should be the first provided module.") - transitive_defines = [] transitive_modules = [] for swift_info in swift_infos: @@ -362,7 +350,8 @@ def create_swift_info( return SwiftInfo( direct_defines = defines, direct_modules = modules, - module_name = module_name, + # TODO(b/149999519): Remove the legacy `module_name`. + module_name = modules[0].name if len(modules) == 1 else None, swift_version = swift_version, transitive_defines = depset(defines, transitive = transitive_defines), transitive_modules = depset(modules, transitive = transitive_modules), From 134370dffaa970bcd963a2d5611966f25260d331 Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Wed, 16 Dec 2020 09:53:53 -0800 Subject: [PATCH 054/152] Allow `optional_implicit_deps` and `required_implicit_deps` to be set on an `xcode_swift_toolchain` target. PiperOrigin-RevId: 347841955 (cherry picked from commit 875de9fc0b08bedb30e7de2e3f992cd9f818e40d) --- swift/internal/xcode_swift_toolchain.bzl | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/swift/internal/xcode_swift_toolchain.bzl b/swift/internal/xcode_swift_toolchain.bzl index 21ac36dfd..09af2dd72 100644 --- a/swift/internal/xcode_swift_toolchain.bzl +++ b/swift/internal/xcode_swift_toolchain.bzl @@ -46,7 +46,7 @@ load( ) load(":features.bzl", "features_for_build_modes") load(":toolchain_config.bzl", "swift_toolchain_config") -load(":providers.bzl", "SwiftToolchainInfo") +load(":providers.bzl", "SwiftInfo", "SwiftToolchainInfo") load(":utils.bzl", "compact", "get_swift_executable_for_toolchain") def _swift_developer_lib_dir(platform_framework_dir): @@ -774,9 +774,9 @@ def _xcode_swift_toolchain_impl(ctx): linker_opts_producer = linker_opts_producer, linker_supports_filelist = True, object_format = "macho", - optional_implicit_deps = [], + optional_implicit_deps = ctx.attr.optional_implicit_deps, requested_features = requested_features, - required_implicit_deps = [], + required_implicit_deps = ctx.attr.required_implicit_deps, supports_objc_interop = True, swift_worker = ctx.executable._worker, system_name = "darwin", @@ -795,6 +795,23 @@ xcode_swift_toolchain = rule( attrs = dicts.add( swift_toolchain_driver_attrs(), { + "optional_implicit_deps": attr.label_list( + allow_files = True, + doc = """\ +A list of labels to library targets that should be added as implicit +dependencies of any Swift compilation or linking target that does not have the +`swift.minimal_deps` feature applied. +""", + providers = [[CcInfo], [SwiftInfo]], + ), + "required_implicit_deps": attr.label_list( + allow_files = True, + doc = """\ +A list of labels to library targets that should be unconditionally added as +implicit dependencies of any Swift compilation or linking target. +""", + providers = [[CcInfo], [SwiftInfo]], + ), "_cc_toolchain": attr.label( default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"), doc = """\ From e46ae724aecb2e5b60f032b132c9d97eea740d27 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Wed, 16 Dec 2020 18:05:39 -0800 Subject: [PATCH 055/152] Fix XCTest -I for derived files In 768bfe3fe885f92fbaea75488268e2612ab9ef9c this was moved and this wasn't added (since it isn't used inside Google) --- swift/internal/xcode_swift_toolchain.bzl | 1 + 1 file changed, 1 insertion(+) diff --git a/swift/internal/xcode_swift_toolchain.bzl b/swift/internal/xcode_swift_toolchain.bzl index 09af2dd72..24ee7215f 100644 --- a/swift/internal/xcode_swift_toolchain.bzl +++ b/swift/internal/xcode_swift_toolchain.bzl @@ -392,6 +392,7 @@ def _all_action_configs( swift_toolchain_config.action_config( actions = [ swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, swift_action_names.PRECOMPILE_C_MODULE, ], configurators = [ From c512f8e59b4c9084cede72276bbf30f6df4342f7 Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Thu, 17 Dec 2020 08:40:25 -0800 Subject: [PATCH 056/152] Remove SwiftInfo.module_name, it was deprecated a while ago. RELNOTES: None PiperOrigin-RevId: 348027802 (cherry picked from commit 789b20b0a3c0bc6c8d1ffd3eb8ae49259cdccfa8) --- swift/internal/providers.bzl | 11 ----------- swift/internal/swift_module_alias.bzl | 7 ------- 2 files changed, 18 deletions(-) diff --git a/swift/internal/providers.bzl b/swift/internal/providers.bzl index 38abb7aae..675d3c8c6 100644 --- a/swift/internal/providers.bzl +++ b/swift/internal/providers.bzl @@ -33,15 +33,6 @@ library that directly propagated this provider. "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. -""", - "module_name": """\ -`String`. The name of the Swift module represented by the target that directly -propagated this provider. - -This field will be equal to the explicitly assigned module name (if present); -otherwise, it will be equal to the autogenerated module name. - -This field is deprecated; use `direct_modules` instead. """, "swift_version": """\ `String`. The version of the Swift language that was used when compiling the @@ -350,8 +341,6 @@ def create_swift_info( return SwiftInfo( direct_defines = defines, direct_modules = modules, - # TODO(b/149999519): Remove the legacy `module_name`. - module_name = modules[0].name if len(modules) == 1 else None, swift_version = swift_version, transitive_defines = depset(defines, transitive = transitive_defines), transitive_modules = depset(modules, transitive = transitive_modules), diff --git a/swift/internal/swift_module_alias.bzl b/swift/internal/swift_module_alias.bzl index 927daab86..05eb449ca 100644 --- a/swift/internal/swift_module_alias.bzl +++ b/swift/internal/swift_module_alias.bzl @@ -34,13 +34,6 @@ def _swift_module_alias_impl(ctx): for module in dep[SwiftInfo].direct_modules } - # TODO(b/149999519): remove the support for SwiftInfo.module_name that - # didn't have any direct_modules. - for dep in deps: - swift_info = dep[SwiftInfo] - if not swift_info.direct_modules and swift_info.module_name: - module_mapping[swift_info.module_name] = dep.label - module_name = ctx.attr.module_name if not module_name: module_name = swift_common.derive_module_name(ctx.label) From c517a72b64dcdf9c5a78fcb8dbe43a6b213a32e7 Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Thu, 17 Dec 2020 11:08:30 -0800 Subject: [PATCH 057/152] Ignore a feature when a `SwiftToolchainInfo` says it does not support it instead of making it a build failure. This is closer to the C++ crosstool behavior. This change also cleans up the internal representation of the feature configuration, by no longer tracking unsupported features (which were never used elsewhere) and by preceding the `struct` fields with underscores to indicate that they should not be read by clients (the value should only be queried by passing it to other `swift_common` functions). PiperOrigin-RevId: 348055621 (cherry picked from commit 3c85e63d7961e45df2c37a750992b01247b9856a) --- swift/internal/features.bzl | 52 ++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/swift/internal/features.bzl b/swift/internal/features.bzl index cf6b264b3..6e19d7d0e 100644 --- a/swift/internal/features.bzl +++ b/swift/internal/features.bzl @@ -14,7 +14,6 @@ """Helper functions for working with Bazel features.""" -load("@bazel_skylib//lib:collections.bzl", "collections") load("@bazel_skylib//lib:new_sets.bzl", "sets") load( ":feature_names.bzl", @@ -60,9 +59,10 @@ def configure_features( Args: ctx: The rule context. swift_toolchain: The `SwiftToolchainInfo` provider of the toolchain - being used to build. The C++ toolchain associated with the Swift - toolchain is used to create the underlying C++ feature - configuration. + being used to build. This is used to determine features that are + enabled by default or unsupported by the toolchain, and the C++ + toolchain associated with the Swift toolchain is used to create the + underlying C++ feature configuration. requested_features: The list of features to be enabled. This is typically obtained using the `ctx.features` field in a rule implementation function. @@ -72,45 +72,37 @@ def configure_features( Returns: An opaque value representing the feature configuration that can be - passed to other `swift_common` functions. + passed to other `swift_common` functions. Note that the structure of + this value should otherwise not be relied on or inspected directly. """ # The features to enable for a particular rule/target are the ones requested # by the toolchain, plus the ones requested by the target itself, *minus* - # any that are explicitly disabled on the target itself. - requested_features_set = sets.make(swift_toolchain.requested_features) - requested_features_set = sets.union( - requested_features_set, + # any that are explicitly disabled on the target or the toolchain. + requestable_features_set = sets.make(swift_toolchain.requested_features) + requestable_features_set = sets.union( + requestable_features_set, sets.make(requested_features), ) - requested_features_set = sets.difference( - requested_features_set, + requestable_features_set = sets.difference( + requestable_features_set, sets.make(unsupported_features), ) - all_requested_features = sets.to_list(requested_features_set) - - all_unsupported_features = collections.uniq( - swift_toolchain.unsupported_features + unsupported_features, + requestable_features_set = sets.difference( + requestable_features_set, + sets.make(swift_toolchain.unsupported_features), ) - - # Verify the consistency of Swift features requested vs. those that are not - # supported by the toolchain. We don't need to do this for C++ features - # because `cc_common.configure_features` handles verifying those. - for feature in requested_features: - if feature.startswith("swift.") and feature in all_unsupported_features: - fail("Feature '{}' was requested, ".format(feature) + - "but it is not supported by the current toolchain or rule.") + requestable_features = sets.to_list(requestable_features_set) cc_feature_configuration = cc_common.configure_features( ctx = ctx, cc_toolchain = swift_toolchain.cc_toolchain_info, - requested_features = all_requested_features, - unsupported_features = all_unsupported_features, + requested_features = requestable_features, + unsupported_features = unsupported_features, ) return struct( - cc_feature_configuration = cc_feature_configuration, - requested_features = all_requested_features, - unsupported_features = all_unsupported_features, + _cc_feature_configuration = cc_feature_configuration, + _enabled_features = requestable_features, ) def features_for_build_modes(ctx, objc_fragment = None): @@ -150,7 +142,7 @@ def get_cc_feature_configuration(feature_configuration): [`cc_common.configure_features`](https://docs.bazel.build/versions/master/skylark/lib/cc_common.html#configure_features) for more information). """ - return feature_configuration.cc_feature_configuration + return feature_configuration._cc_feature_configuration def is_feature_enabled(feature_configuration, feature_name): """Returns `True` if the feature is enabled in the feature configuration. @@ -168,7 +160,7 @@ def is_feature_enabled(feature_configuration, feature_name): `True` if the given feature is enabled in the feature configuration. """ if feature_name.startswith("swift."): - return feature_name in feature_configuration.requested_features + return feature_name in feature_configuration._enabled_features else: return cc_common.is_enabled( feature_configuration = get_cc_feature_configuration( From d916037ac3a918ce7231c355945246d265cb78a3 Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Thu, 17 Dec 2020 20:17:38 -0800 Subject: [PATCH 058/152] Uniquify `-fmodule-map-file=` flags passed to `swiftc`. In some cases (e.g., if a module map defines multiple modules and both or more were present in the dependency graph), the `depset` won't deduplicate the module structures because their values are distinct (they contain different module names). That's the behavior we want, but it also resulted in the `-fmodule-map-file=` for that module map appearing multiple times on the command line. PiperOrigin-RevId: 348139990 (cherry picked from commit df1198b3826b7d10ab91b04250f672d812acfb0f) --- swift/internal/compiling.bzl | 51 ++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index 2b938c8dd..333cee1f2 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -17,7 +17,6 @@ load("@bazel_skylib//lib:collections.bzl", "collections") load("@bazel_skylib//lib:partial.bzl", "partial") load("@bazel_skylib//lib:paths.bzl", "paths") -load("@bazel_skylib//lib:sets.bzl", "sets") load("@bazel_skylib//lib:types.bzl", "types") load( ":actions.bzl", @@ -951,14 +950,14 @@ def _collect_clang_module_inputs( ) def _clang_modulemap_dependency_args(module): - """Returns `swiftc` arguments for the module map of a Clang module. + """Returns a `swiftc` argument for the module map of a Clang module. Args: module: A struct containing information about the module, as defined by `swift_common.create_module`. Returns: - A list of arguments to pass to `swiftc`. + The argument to pass to `swiftc` (without the `-Xcc` prefix). """ if types.is_string(module): module_map_path = module @@ -969,35 +968,34 @@ def _clang_modulemap_dependency_args(module): else: module_map_path = module_map.path - return [ - "-Xcc", - "-fmodule-map-file={}".format(module_map_path), - ] + return "-fmodule-map-file={}".format(module_map_path) def _clang_module_dependency_args(module): """Returns `swiftc` arguments for a precompiled Clang module, if possible. - If no precompiled module was emitted for this module, then this function - falls back to the textual module map. + If a precompiled module is present for this module, then flags for both it + and the module map are returned (the latter is required in order to map + headers to mdules in some scenarios, since the precompiled modules are + passed by name). If no precompiled module is present for this module, then + this function falls back to the textual module map alone. Args: module: A struct containing information about the module, as defined by `swift_common.create_module`. Returns: - A list of arguments to pass to `swiftc`. + A list of arguments to pass to `swiftc` (without the `-Xcc` prefix). """ args = [] if module.clang.precompiled_module: - args.extend([ - "-Xcc", + args.append( "-fmodule-file={}={}".format( module.name, module.clang.precompiled_module.path, ), - ]) + ) if module.clang.module_map: - args.extend(_clang_modulemap_dependency_args(module)) + args.append(_clang_modulemap_dependency_args(module)) return args def _dependencies_clang_modulemaps_configurator(prerequisites, args): @@ -1007,11 +1005,16 @@ def _dependencies_clang_modulemaps_configurator(prerequisites, args): for module in prerequisites.transitive_modules if module.clang ] - module_map_paths = sets.to_list(sets.make([ - module.clang.module_map.path - for module in modules - ])) - args.add_all(module_map_paths, map_each = _clang_modulemap_dependency_args) + + # Uniquify the arguments because different modules might be defined in the + # same module map file, so it only needs to be present once on the command + # line. + args.add_all( + modules, + before_each = "-Xcc", + map_each = _clang_modulemap_dependency_args, + uniquify = True, + ) return _collect_clang_module_inputs( cc_info = prerequisites.cc_info, @@ -1029,7 +1032,15 @@ def _dependencies_clang_modules_configurator(prerequisites, args): if module.clang ] - args.add_all(modules, map_each = _clang_module_dependency_args) + # Uniquify the arguments because different modules might be defined in the + # same module map file, so it only needs to be present once on the command + # line. + args.add_all( + modules, + before_each = "-Xcc", + map_each = _clang_module_dependency_args, + uniquify = True, + ) return _collect_clang_module_inputs( cc_info = prerequisites.cc_info, From ca8fe5b39c273d1368723ec7e88470365c173687 Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Tue, 22 Dec 2020 13:13:26 -0800 Subject: [PATCH 059/152] Work around https://github.com/bazelbuild/stardoc/issues/78. Markdown bullet lists work fine in the general descriptions block of macros/rules/providers, but for rule attributes and provider fields the the markdown is a table, and `*` has no means (and stardoc transforms the content to remove newlines). The above issue is to support catch these and marking html bullet lists out of them, but until that is done, adding a blank line between each bullet gets slightly more readable generated/render documents. PiperOrigin-RevId: 348682502 (cherry picked from commit 5383052ecc5e008dd9e4a42edf2570c60bd6dc5c) --- swift/internal/attrs.bzl | 1 + swift/internal/providers.bzl | 2 ++ swift/internal/swift_binary_test.bzl | 2 ++ swift/internal/swift_grpc_library.bzl | 2 ++ 4 files changed, 7 insertions(+) diff --git a/swift/internal/attrs.bzl b/swift/internal/attrs.bzl index 9954f89d0..e4a72886b 100644 --- a/swift/internal/attrs.bzl +++ b/swift/internal/attrs.bzl @@ -177,6 +177,7 @@ Allowed kinds of dependencies are: * `swift_c_module`, `swift_import` and `swift_library` (or anything propagating `SwiftInfo`) + * `cc_library` (or anything propagating `CcInfo`) Additionally, on platforms that support Objective-C interop, `objc_library` diff --git a/swift/internal/providers.bzl b/swift/internal/providers.bzl index 675d3c8c6..d80cf6366 100644 --- a/swift/internal/providers.bzl +++ b/swift/internal/providers.bzl @@ -107,6 +107,7 @@ The partial should be called with two arguments: * `is_static`: A `Boolean` value indicating whether to link against the static or dynamic runtime libraries. + * `is_test`: A `Boolean` value indicating whether the target being linked is a test target. """, @@ -157,6 +158,7 @@ compiles). * `env`: A `dict` of environment variables to be set when running tests that were built with this toolchain. + * `execution_requirements`: A `dict` of execution requirements for tests that were built with this toolchain. diff --git a/swift/internal/swift_binary_test.bzl b/swift/internal/swift_binary_test.bzl index d5eec6dab..d0ab1e884 100644 --- a/swift/internal/swift_binary_test.bzl +++ b/swift/internal/swift_binary_test.bzl @@ -67,8 +67,10 @@ into the binary. Possible values are: * `stamp = 1`: Stamp the build information into the binary. Stamped binaries are only rebuilt when their dependencies change. Use this if there are tests that depend on the build information. + * `stamp = 0`: Always replace build information by constant values. This gives good build result caching. + * `stamp = -1`: Embedding of build information is controlled by the `--[no]stamp` flag. """, diff --git a/swift/internal/swift_grpc_library.bzl b/swift/internal/swift_grpc_library.bzl index 8ca93dcc4..a42f87f60 100644 --- a/swift/internal/swift_grpc_library.bzl +++ b/swift/internal/swift_grpc_library.bzl @@ -384,7 +384,9 @@ on the `swift_grpc_library` implementing the service. The kind of definitions that should be generated: * `"client"` to generate client definitions. + * `"client_stubs"` to generate client test stubs. + * `"server"` to generate server definitions. """, ), From 329a810ed8390ac888c4ca7d49ae119099805d11 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Wed, 6 Jan 2021 16:34:59 -0800 Subject: [PATCH 060/152] Update README with new URLs --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 654c74ed6..4baf51954 100644 --- a/README.md +++ b/README.md @@ -51,8 +51,8 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "build_bazel_rules_swift", - sha256 = "c07abf4d94fef598c45e539e9adc0ed25795260c618e167b714cc285b20525e2", - url = "https://github.com/bazelbuild/rules_swift/releases/download/0.17.0/rules_swift.0.17.0.tar.gz", + sha256 = "d0e5f888b2ccce42c92e6d4686b5507b4230462627f965f9d39862e11ae9fb35", + url = "https://github.com/bazelbuild/rules_swift/releases/download/0.18.0/rules_swift.0.18.0.tar.gz", ) load( From d70190015019bc5ba7ddb7bd79f3f9b2b8339e16 Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Thu, 14 Jan 2021 16:03:22 -0800 Subject: [PATCH 061/152] Allow modules propagated by `SwiftInfo` to indicate whether they are system modules. System modules differ from non-system modules in that we don't pass the module map to the compiler via `-fmodule-map-file` for system modules in implicit module builds, only in explicit module builds. This is because module maps passed via `-fmodule-map-file` are always treated as non-system modules, which affects how diagnostics are emitted when their headers are parsed, and some Swift modules like `SwiftOverlayShims` don't declare themselves as `[system]` in their module map file but contain small nullability issues. Such headers *must* be found through a standard header search via a system path like `-isystem` so that they don't cause builds to fail if they treat warnings more severely. PiperOrigin-RevId: 351896080 (cherry picked from commit 214061922f68fbf4f0f7fcf4df9d54af5b279cf5) --- swift/internal/compiling.bzl | 44 ++++++++++++++++++++---------------- swift/internal/providers.bzl | 23 +++++++++++++++---- 2 files changed, 44 insertions(+), 23 deletions(-) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index 333cee1f2..9bc214aba 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -935,7 +935,7 @@ def _collect_clang_module_inputs( # Add the module map, which we use for both implicit and explicit module # builds. For implicit module builds, we don't worry about the headers # above because we collect the full transitive header set below. - if not types.is_string(module_map): + if not module.is_system and not types.is_string(module_map): module_inputs.append(module_map) # If we prefer textual module maps and headers for the build, fall back to @@ -949,33 +949,36 @@ def _collect_clang_module_inputs( transitive_inputs = header_depsets, ) -def _clang_modulemap_dependency_args(module): +def _clang_modulemap_dependency_args(module, ignore_system = True): """Returns a `swiftc` argument for the module map of a Clang module. Args: module: A struct containing information about the module, as defined by `swift_common.create_module`. + ignore_system: If `True` and the module is a system module, no flag + should be returned. Defaults to `True`. Returns: - The argument to pass to `swiftc` (without the `-Xcc` prefix). + A list of arguments, possibly empty, to pass to `swiftc` (without the + `-Xcc` prefix). """ - if types.is_string(module): - module_map_path = module + if module.is_system and ignore_system: + return [] + + module_map = module.clang.module_map + if types.is_string(module_map): + module_map_path = module_map else: - module_map = module.clang.module_map - if types.is_string(module_map): - module_map_path = module_map - else: - module_map_path = module_map.path + module_map_path = module_map.path - return "-fmodule-map-file={}".format(module_map_path) + return ["-fmodule-map-file={}".format(module_map_path)] def _clang_module_dependency_args(module): """Returns `swiftc` arguments for a precompiled Clang module, if possible. If a precompiled module is present for this module, then flags for both it and the module map are returned (the latter is required in order to map - headers to mdules in some scenarios, since the precompiled modules are + headers to modules in some scenarios, since the precompiled modules are passed by name). If no precompiled module is present for this module, then this function falls back to the textual module map alone. @@ -984,19 +987,22 @@ def _clang_module_dependency_args(module): `swift_common.create_module`. Returns: - A list of arguments to pass to `swiftc` (without the `-Xcc` prefix). + A list of arguments, possibly empty, to pass to `swiftc` (without the + `-Xcc` prefix). """ - args = [] if module.clang.precompiled_module: - args.append( + # If we're consuming an explicit module, we must also provide the + # textual module map, whether or not it's a system module. + return [ "-fmodule-file={}={}".format( module.name, module.clang.precompiled_module.path, ), - ) - if module.clang.module_map: - args.append(_clang_modulemap_dependency_args(module)) - return args + ] + _clang_modulemap_dependency_args(module, ignore_system = False) + else: + # If we have no explicit module, then only include module maps for + # non-system modules. + return _clang_modulemap_dependency_args(module) def _dependencies_clang_modulemaps_configurator(prerequisites, args): """Configures Clang module maps from dependencies.""" diff --git a/swift/internal/providers.bzl b/swift/internal/providers.bzl index d80cf6366..00dfc4053 100644 --- a/swift/internal/providers.bzl +++ b/swift/internal/providers.bzl @@ -195,7 +195,7 @@ provider. }, ) -def create_module(*, name, clang = None, swift = None): +def create_module(*, name, clang = None, is_system = False, swift = None): """Creates a value containing Clang/Swift module artifacts of a dependency. At least one of the `clang` and `swift` arguments must not be `None`. It is @@ -209,6 +209,20 @@ def create_module(*, name, clang = None, swift = None): 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. + 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 @@ -216,13 +230,14 @@ def create_module(*, name, clang = None, swift = None): C/Objective-C module. Returns: - A `struct` containing the `name`, `clang`, and `swift` fields provided - as arguments. + A `struct` containing the `name`, `clang`, `is_system`, and `swift` + fields provided as arguments. """ if clang == None and swift == None: - fail("Must provide atleast a clang or swift module.") + fail("Must provide at least a clang or swift module.") return struct( clang = clang, + is_system = is_system, name = name, swift = swift, ) From 5a4f76d4075d2131038c038f8b7d1b2703449259 Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Wed, 13 Jan 2021 08:09:15 -0800 Subject: [PATCH 062/152] Stop computing/tracking defines. They are already exposed in the modules, so use them directly from there instead. This also means they union doesn't have to keep being computed going up the build graph, which will save some cycles. RELNOTES: None PiperOrigin-RevId: 351588940 (cherry picked from commit 52b9ffae47f39df35826448ecfabc04c4cccb8c1) --- swift/internal/compiling.bzl | 24 +++++++++++++++--------- swift/internal/providers.bzl | 32 +------------------------------- 2 files changed, 16 insertions(+), 40 deletions(-) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index 9bc214aba..bebbe85ca 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -17,6 +17,7 @@ load("@bazel_skylib//lib:collections.bzl", "collections") load("@bazel_skylib//lib:partial.bzl", "partial") load("@bazel_skylib//lib:paths.bzl", "paths") +load("@bazel_skylib//lib:sets.bzl", "sets") load("@bazel_skylib//lib:types.bzl", "types") load( ":actions.bzl", @@ -1183,7 +1184,6 @@ def _conditional_compilation_flag_configurator(prerequisites, args): all_defines = depset( prerequisites.defines, transitive = [ - prerequisites.transitive_defines, # Take any Swift-compatible defines from Objective-C dependencies # and define them for Swift. prerequisites.cc_info.compilation_context.defines, @@ -1402,15 +1402,22 @@ def compile( merged_providers.swift_info.transitive_modules.to_list() ) + transitive_swiftmodules = [] + defines_set = sets.make(defines) + for module in transitive_modules: + swift_module = module.swift + if not swift_module: + continue + transitive_swiftmodules.append(swift_module.swiftmodule) + if swift_module.defines: + defines_set = sets.union( + defines_set, + sets.make(swift_module.defines), + ) + # We need this when generating the VFS overlay file and also when # configuring inputs for the compile action, so it's best to precompute it # here. - transitive_swiftmodules = [ - module.swift.swiftmodule - for module in transitive_modules - if module.swift - ] - if is_feature_enabled( feature_configuration = feature_configuration, feature_name = SWIFT_FEATURE_VFSOVERLAY, @@ -1432,7 +1439,7 @@ def compile( additional_inputs = additional_inputs, bin_dir = bin_dir, cc_info = merged_providers.cc_info, - defines = defines, + defines = sets.to_list(defines_set), genfiles_dir = genfiles_dir, is_swift = True, module_name = module_name, @@ -1441,7 +1448,6 @@ def compile( ), objc_info = merged_providers.objc_info, source_files = srcs, - transitive_defines = merged_providers.swift_info.transitive_defines, transitive_modules = transitive_modules, transitive_swiftmodules = transitive_swiftmodules, user_compile_flags = copts + swift_toolchain.command_line_copts, diff --git a/swift/internal/providers.bzl b/swift/internal/providers.bzl index 00dfc4053..9736b0c27 100644 --- a/swift/internal/providers.bzl +++ b/swift/internal/providers.bzl @@ -14,8 +14,6 @@ """Defines Starlark providers that propagated by the Swift BUILD rules.""" -load("@bazel_skylib//lib:sets.bzl", "sets") - SwiftInfo = provider( doc = """\ Contains information about the compiled artifacts of a Swift module. @@ -26,10 +24,6 @@ directly, consider using the `swift_common.create_swift_info` function, which has reasonable defaults for any fields not explicitly set. """, fields = { - "direct_defines": """\ -`List` of `string`s. The values specified by the `defines` attribute of the -library that directly propagated this provider. -""", "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. @@ -41,10 +35,6 @@ flag. This will be `None` if the flag was not set. This field is deprecated; the Swift version should be obtained by inspecting the arguments passed to specific compilation actions. -""", - "transitive_defines": """\ -`Depset` of `string`s. The transitive `defines` specified for the library that -propagated this provider and all of its dependencies. """, "transitive_modules": """\ `Depset` of values returned from `swift_common.create_module`. The transitive @@ -335,30 +325,10 @@ def create_swift_info( A new `SwiftInfo` provider with the given values. """ - defines_set = sets.make() - for module in modules: - swift_module = module.swift - if not swift_module: - continue - - if swift_module.defines: - defines_set = sets.union( - defines_set, - sets.make(swift_module.defines), - ) - - defines = sets.to_list(defines_set) - - transitive_defines = [] - transitive_modules = [] - for swift_info in swift_infos: - transitive_defines.append(swift_info.transitive_defines) - transitive_modules.append(swift_info.transitive_modules) + transitive_modules = [x.transitive_modules for x in swift_infos] return SwiftInfo( - direct_defines = defines, direct_modules = modules, swift_version = swift_version, - transitive_defines = depset(defines, transitive = transitive_defines), transitive_modules = depset(modules, transitive = transitive_modules), ) From 3d1f6a3c57ab8f08326164e07cdbdc60181dafbd Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Wed, 13 Jan 2021 08:52:27 -0800 Subject: [PATCH 063/152] Remove swift_version. It was deprecated a while ago, and it avoids the collection in swift_library now. RELNOTES: None PiperOrigin-RevId: 351595739 (cherry picked from commit 5b1aabd92e93e38d0e98dcaa6ce062f9476d9d86) --- swift/internal/compiling.bzl | 22 ---------------------- swift/internal/providers.bzl | 15 +-------------- swift/internal/swift_library.bzl | 2 -- 3 files changed, 1 insertion(+), 38 deletions(-) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index bebbe85ca..cc3d4cfd1 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -2056,28 +2056,6 @@ def _register_post_compile_actions( linker_inputs = linker_inputs, ) -def find_swift_version_copt_value(copts): - """Returns the value of the `-swift-version` argument, if found. - - Args: - copts: The list of copts to be scanned. - - Returns: - The value of the `-swift-version` argument, or None if it was not found - in the copt list. - """ - - # Note that the argument can occur multiple times, and the last one wins. - last_swift_version = None - - count = len(copts) - for i in range(count): - copt = copts[i] - if copt == "-swift-version" and i + 1 < count: - last_swift_version = copts[i + 1] - - return last_swift_version - def new_objc_provider( deps, link_inputs, diff --git a/swift/internal/providers.bzl b/swift/internal/providers.bzl index 9736b0c27..247f7d212 100644 --- a/swift/internal/providers.bzl +++ b/swift/internal/providers.bzl @@ -27,14 +27,6 @@ has reasonable defaults for any fields not explicitly set. "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. -""", - "swift_version": """\ -`String`. The version of the Swift language that was used when compiling the -propagating target; that is, the value passed via the `-swift-version` compiler -flag. This will be `None` if the flag was not set. - -This field is deprecated; the Swift version should be obtained by inspecting the -arguments passed to specific compilation actions. """, "transitive_modules": """\ `Depset` of values returned from `swift_common.create_module`. The transitive @@ -296,8 +288,7 @@ def create_swift_module( def create_swift_info( *, modules = [], - swift_infos = [], - swift_version = None): + swift_infos = []): """Creates a new `SwiftInfo` provider with the given values. This function is recommended instead of directly creating a `SwiftInfo` @@ -317,9 +308,6 @@ def create_swift_info( swift_infos: A list of `SwiftInfo` providers from dependencies, whose transitive fields should be merged into the new one. If omitted, no transitive data is collected. - swift_version: A string containing the value of the `-swift-version` - flag used when compiling this target, or `None` (the default) if it - was not set or is not relevant. Returns: A new `SwiftInfo` provider with the given values. @@ -329,6 +317,5 @@ def create_swift_info( return SwiftInfo( direct_modules = modules, - swift_version = swift_version, transitive_modules = depset(modules, transitive = transitive_modules), ) diff --git a/swift/internal/swift_library.bzl b/swift/internal/swift_library.bzl index bf7d49644..050c8baa9 100644 --- a/swift/internal/swift_library.bzl +++ b/swift/internal/swift_library.bzl @@ -17,7 +17,6 @@ load(":attrs.bzl", "swift_deps_attr") load( ":compiling.bzl", - "find_swift_version_copt_value", "new_objc_provider", "output_groups_from_compilation_outputs", "swift_library_output_map", @@ -246,7 +245,6 @@ def _swift_library_impl(ctx): # Note that private_deps are explicitly omitted here; they should # not propagate. swift_infos = get_providers(deps, SwiftInfo), - swift_version = find_swift_version_copt_value(copts), ), ] From 08e3036c6511dd5a0f0fe6b52e9a95a13e1a471c Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Thu, 21 Jan 2021 14:27:09 -0800 Subject: [PATCH 064/152] Add a `swift_explicit_module` output group to the `swift_clang_module_aspect` to provide a way to invoke the aspect from the command line and retrieve the `.pcm` file. This provides an easier way to manually verify that a `{cc,objc}_library` builds correctly as an explicit module. PiperOrigin-RevId: 353103538 (cherry picked from commit 1b63232f01d665aab1157a4d66a4ee2c91c2e9a6) --- swift/internal/swift_clang_module_aspect.bzl | 33 +++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/swift/internal/swift_clang_module_aspect.bzl b/swift/internal/swift_clang_module_aspect.bzl index 2b871c685..7fea0317e 100644 --- a/swift/internal/swift_clang_module_aspect.bzl +++ b/swift/internal/swift_clang_module_aspect.bzl @@ -338,19 +338,30 @@ def _handle_cc_target( module_name = derive_module_name(target.label) precompiled_module = None - return [create_swift_info( - modules = [ - create_module( - name = module_name, - clang = create_clang_module( - compilation_context = compilation_context, - module_map = module_map_file, - precompiled_module = precompiled_module, + providers = [ + create_swift_info( + modules = [ + create_module( + name = module_name, + clang = create_clang_module( + compilation_context = compilation_context, + module_map = module_map_file, + precompiled_module = precompiled_module, + ), ), + ], + swift_infos = swift_infos, + ), + ] + + if precompiled_module: + providers.append( + OutputGroupInfo( + swift_explicit_module = depset([precompiled_module]), ), - ], - swift_infos = swift_infos, - )] + ) + + return providers def _swift_clang_module_aspect_impl(target, aspect_ctx): # Do nothing if the target already propagates `SwiftInfo`. From d0b6a7e437ce587f241f1cead7c6c26501aeb30d Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Mon, 25 Jan 2021 09:42:18 -0800 Subject: [PATCH 065/152] Lessen restrictions on when implicit modules can be used: - Allow Swift compiles to use implicit modules even if `swift.use_c_modules` is enabled (a necessary fallback if some dependencies don't emit explicit modules). - Continue to disallow usage of implicit modules when compiling explicit C/Objective-C modules because those implicit module paths would become embedded in the `.pcm` files, making them immovable. PiperOrigin-RevId: 353665654 (cherry picked from commit 2711a2b930108e48c1b22541efb5408989d2eac0) --- swift/internal/compiling.bzl | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index cc3d4cfd1..0e9eca9ae 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -463,6 +463,9 @@ def compile_action_configs(): [SWIFT_FEATURE_USE_GLOBAL_MODULE_CACHE], ], ), + # When using C modules, disable the implicit search for module map files + # because all of them, including system dependencies, will be provided + # explicitly. swift_toolchain_config.action_config( actions = [ swift_action_names.COMPILE, @@ -470,17 +473,33 @@ def compile_action_configs(): swift_action_names.PRECOMPILE_C_MODULE, ], configurators = [ - # If we're consuming explicit modules of C dependencies, disable - # all implicit module usage (both searching for module maps and - # implicit compilation) to ensure that all modules must be - # explicitly provided. swift_toolchain_config.add_arg( "-Xcc", - "-fno-implicit-modules", + "-fno-implicit-module-maps", ), + ], + features = [SWIFT_FEATURE_USE_C_MODULES], + ), + # Do not allow implicit modules to be used at all when emitting an + # explicit C/Objective-C module. Consider the case of two modules A and + # B, where A depends on B. If B does not emit an explicit module, then + # when A is compiled it would contain a hardcoded reference to B via its + # path in the implicit module cache. Thus, A would not be movable; some + # library importing A would try to resolve B at that path, which may no + # longer exist when the upstream library is built. + # + # This implies that for a C/Objective-C library to build as an explicit + # module, all of its dependencies must as well. On the other hand, a + # Swift library can be compiled with some of its Objective-C + # dependencies still using implicit modules, as long as no Objective-C + # library wants to import that Swift library's generated header and + # build itself as an explicit module. + swift_toolchain_config.action_config( + actions = [swift_action_names.PRECOMPILE_C_MODULE], + configurators = [ swift_toolchain_config.add_arg( "-Xcc", - "-fno-implicit-module-maps", + "-fno-implicit-modules", ), ], features = [SWIFT_FEATURE_USE_C_MODULES], From 4de93c132cf1f61fa99d65ccb841af980e5eaa22 Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Wed, 27 Jan 2021 12:10:47 -0800 Subject: [PATCH 066/152] Fix header selection when falling back to implicit modules. If we're compiling a `swift_library` with explicit modules enabled but some dependency subtree doesn't propagate explicit modules, we weren't collecting the right headers; we need the full transitive set for that subtree, not just the direct headers. Also cleaned up the comments and control flow in this function, which had gotten out-of-date and confusing, which no doubt contributed to the problem. PiperOrigin-RevId: 354142943 (cherry picked from commit 0ad70ff0a551675508d4e83c5abca7ff27506435) --- swift/internal/compiling.bzl | 81 ++++++++++++++++++++++-------------- 1 file changed, 50 insertions(+), 31 deletions(-) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index 0e9eca9ae..04a33710d 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -925,48 +925,67 @@ def _collect_clang_module_inputs( `swift_toolchain_config.config_result`) that contains the input artifacts for the action. """ - module_inputs = [] - header_depsets = [] - - # Swift compiles (not Clang module compiles) that prefer precompiled modules - # do not need the full set of transitive headers. - if cc_info and not (is_swift and prefer_precompiled_modules): - header_depsets.append(cc_info.compilation_context.headers) + direct_inputs = [] + transitive_inputs = [] + + if cc_info: + # The headers stored in the `cc_info` argument's compilation context + # differ depending on the kind of action we're invoking: + if (is_swift and not prefer_precompiled_modules) or not is_swift: + # If this is a `SwiftCompile` with explicit modules disabled, the + # `headers` field is an already-computed set of the transitive + # headers of all the deps. (For an explicit module build, we skip it + # and will more selectively pick subsets for any individual modules + # that need to fallback to implicit modules in the loop below). + # + # If this is a `SwiftPrecompileCModule`, then by definition we're + # only here in a build with explicit modules enabled. We should only + # need the direct headers of the module being compiled and its + # direct dependencies (the latter because Clang needs them present + # on the file system to map them to the module that contains them.) + # However, we may also need some of the transitive headers, if the + # module has dependencies that aren't recognized as modules (e.g., + # `cc_library` targets without the `swift_module` tag) and the + # module's headers include those. This will likely over-estimate the + # needed inputs, but we can't do better without include scanning in + # Starlark. + transitive_inputs.append(cc_info.compilation_context.headers) + + # Some rules still use the `umbrella_header` field to propagate a header + # that they don't also include in `CcInfo.compilation_context.headers`, so + # we also need to pull this in for the time being. + if not prefer_precompiled_modules and objc_info: + transitive_inputs.append(objc_info.umbrella_header) for module in modules: clang_module = module.clang + + # Add the module map, which we use for both implicit and explicit module + # builds. module_map = clang_module.module_map + if not module.is_system and not types.is_string(module_map): + direct_inputs.append(module_map) + if prefer_precompiled_modules: - # If the build prefers precompiled modules, use the .pcm if it - # exists; otherwise, use the textual module map and the headers for - # that module (because we only want to propagate the headers that - # are required, not the full transitive set). precompiled_module = clang_module.precompiled_module if precompiled_module: - module_inputs.append(precompiled_module) + # For builds preferring explicit modules, use it if we have it + # and don't include any headers as inputs. + direct_inputs.append(precompiled_module) else: - module_inputs.extend( - clang_module.compilation_context.direct_headers, + # If we don't have an explicit module, we need the transitive + # headers from the compilation context associated with the + # module. This will likely overestimate the headers that will + # actually be used in the action, but until we can use include + # scanning from Starlark, we can't compute a more precise input + # set. + transitive_inputs.append( + clang_module.compilation_context.headers, ) - module_inputs.extend( - clang_module.compilation_context.direct_textual_headers, - ) - - # Add the module map, which we use for both implicit and explicit module - # builds. For implicit module builds, we don't worry about the headers - # above because we collect the full transitive header set below. - if not module.is_system and not types.is_string(module_map): - module_inputs.append(module_map) - - # If we prefer textual module maps and headers for the build, fall back to - # using the full set of transitive headers. - if not prefer_precompiled_modules: - if objc_info: - header_depsets.append(objc_info.umbrella_header) return swift_toolchain_config.config_result( - inputs = module_inputs, - transitive_inputs = header_depsets, + inputs = direct_inputs, + transitive_inputs = transitive_inputs, ) def _clang_modulemap_dependency_args(module, ignore_system = True): From c2eb110c77eaefea4564665e46ae4342dd6af4fa Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Wed, 27 Jan 2021 12:49:14 -0800 Subject: [PATCH 067/152] Simplify the paths to module maps generated by the Swift build rules. Since we pass these module maps directly to the compiler with `-fmodule-map-file`, we don't need them to be named exactly `module.modulemap`, so the extra subdirectory is also unnecessary. PiperOrigin-RevId: 354151400 (cherry picked from commit 71998c865b827828c17dbd24bf48bb856523d4f5) --- swift/internal/derived_files.bzl | 10 ++++++---- test/private_deps_tests.bzl | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/swift/internal/derived_files.bzl b/swift/internal/derived_files.bzl index 4bbe6ba8a..c86e89251 100644 --- a/swift/internal/derived_files.bzl +++ b/swift/internal/derived_files.bzl @@ -108,7 +108,11 @@ def _intermediate_object_file(actions, target_name, src): ) def _module_map(actions, target_name): - """Declares the module map for the generated header of a target. + """Declares the module map for a target. + + These module maps are used when generating a Swift-compatible module map for + a C/Objective-C target, and also when generating the module map for the + generated header of a Swift target. Args: actions: The context's actions object. @@ -117,9 +121,7 @@ def _module_map(actions, target_name): Returns: The declared `File`. """ - return actions.declare_file( - "{}.modulemaps/module.modulemap".format(target_name), - ) + return actions.declare_file("{}.swift.modulemap".format(target_name)) def _modulewrap_object(actions, target_name): """Declares the object file used to wrap Swift modules for ELF binaries. diff --git a/test/private_deps_tests.bzl b/test/private_deps_tests.bzl index d08c98b0c..e594cb852 100644 --- a/test/private_deps_tests.bzl +++ b/test/private_deps_tests.bzl @@ -94,8 +94,8 @@ def private_deps_test_suite(name = "private_deps"): private_deps_provider_test( name = "{}_client_cc_deps_modulemaps".format(name), expected_files = [ - "/test/fixtures/private_deps/public_cc.modulemaps/module.modulemap", - "-/test/fixtures/private_deps/private_cc.modulemaps/module.modulemap", + "/test/fixtures/private_deps/public_cc.swift.modulemap", + "-/test/fixtures/private_deps/private_cc.swift.modulemap", ], field = "transitive_modules.clang!.module_map", provider = "SwiftInfo", From fb60b5493e2108c182ce339fc144f569fd852294 Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Wed, 27 Jan 2021 14:26:19 -0800 Subject: [PATCH 068/152] Automated rollback of commit 71998c865b827828c17dbd24bf48bb856523d4f5. PiperOrigin-RevId: 354172938 (cherry picked from commit 6dc76fe2400aac4aa4ddf1ba22866693ff181c63) --- swift/internal/derived_files.bzl | 10 ++++------ test/private_deps_tests.bzl | 4 ++-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/swift/internal/derived_files.bzl b/swift/internal/derived_files.bzl index c86e89251..4bbe6ba8a 100644 --- a/swift/internal/derived_files.bzl +++ b/swift/internal/derived_files.bzl @@ -108,11 +108,7 @@ def _intermediate_object_file(actions, target_name, src): ) def _module_map(actions, target_name): - """Declares the module map for a target. - - These module maps are used when generating a Swift-compatible module map for - a C/Objective-C target, and also when generating the module map for the - generated header of a Swift target. + """Declares the module map for the generated header of a target. Args: actions: The context's actions object. @@ -121,7 +117,9 @@ def _module_map(actions, target_name): Returns: The declared `File`. """ - return actions.declare_file("{}.swift.modulemap".format(target_name)) + return actions.declare_file( + "{}.modulemaps/module.modulemap".format(target_name), + ) def _modulewrap_object(actions, target_name): """Declares the object file used to wrap Swift modules for ELF binaries. diff --git a/test/private_deps_tests.bzl b/test/private_deps_tests.bzl index e594cb852..d08c98b0c 100644 --- a/test/private_deps_tests.bzl +++ b/test/private_deps_tests.bzl @@ -94,8 +94,8 @@ def private_deps_test_suite(name = "private_deps"): private_deps_provider_test( name = "{}_client_cc_deps_modulemaps".format(name), expected_files = [ - "/test/fixtures/private_deps/public_cc.swift.modulemap", - "-/test/fixtures/private_deps/private_cc.swift.modulemap", + "/test/fixtures/private_deps/public_cc.modulemaps/module.modulemap", + "-/test/fixtures/private_deps/private_cc.modulemaps/module.modulemap", ], field = "transitive_modules.clang!.module_map", provider = "SwiftInfo", From aa542252a2ea9c11a77b45de314350838d554747 Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Thu, 28 Jan 2021 09:08:01 -0800 Subject: [PATCH 069/152] Simplify the paths to module maps generated by the Swift build rules. Since we pass these module maps directly to the compiler with `-fmodule-map-file`, we don't need them to be named exactly `module.modulemap`, so the extra subdirectory is also unnecessary. This change also migrates generation of the modulemap file content for the generated header's module to the same code (`module_maps.bzl`) already used by `swift_clang_module_aspect`, instead of having its own separate code path. PiperOrigin-RevId: 354324121 (cherry picked from commit 5f51ca9c5149122f41cada6122c61788d880fee9) --- swift/internal/compiling.bzl | 30 ++++-------------------------- swift/internal/derived_files.bzl | 10 ++++++---- swift/internal/module_maps.bzl | 7 +++++++ test/private_deps_tests.bzl | 4 ++-- 4 files changed, 19 insertions(+), 32 deletions(-) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index 04a33710d..3247a9cf7 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -62,6 +62,7 @@ load( "SWIFT_FEATURE_VFSOVERLAY", ) load(":features.bzl", "are_all_features_enabled", "is_feature_enabled") +load(":module_maps.bzl", "write_module_map") load(":providers.bzl", "SwiftInfo", "create_swift_info") load(":toolchain_config.bzl", "swift_toolchain_config") load( @@ -1774,11 +1775,11 @@ def _declare_compile_outputs( actions = actions, target_name = target_name, ) - _write_objc_header_module_map( + write_module_map( actions = actions, + module_map_file = generated_module_map, module_name = module_name, - objc_header = generated_header, - output = generated_module_map, + public_headers = [generated_header], ) else: generated_module_map = None @@ -2243,29 +2244,6 @@ def swift_library_output_map(name, alwayslink): "archive": "lib{}.{}".format(name, extension), } -def _write_objc_header_module_map( - actions, - module_name, - objc_header, - output): - """Writes a module map for a generated Swift header to a file. - - Args: - actions: The context's actions object. - module_name: The name of the Swift module. - objc_header: The `File` representing the generated header. - output: The `File` to which the module map should be written. - """ - actions.write( - content = ('module "{module_name}" {{\n' + - ' header "../{header_name}"\n' + - "}}\n").format( - header_name = objc_header.basename, - module_name = module_name, - ), - output = output, - ) - def _index_store_path_overridden(copts): """Checks if index_while_building must be disabled. diff --git a/swift/internal/derived_files.bzl b/swift/internal/derived_files.bzl index 4bbe6ba8a..c86e89251 100644 --- a/swift/internal/derived_files.bzl +++ b/swift/internal/derived_files.bzl @@ -108,7 +108,11 @@ def _intermediate_object_file(actions, target_name, src): ) def _module_map(actions, target_name): - """Declares the module map for the generated header of a target. + """Declares the module map for a target. + + These module maps are used when generating a Swift-compatible module map for + a C/Objective-C target, and also when generating the module map for the + generated header of a Swift target. Args: actions: The context's actions object. @@ -117,9 +121,7 @@ def _module_map(actions, target_name): Returns: The declared `File`. """ - return actions.declare_file( - "{}.modulemaps/module.modulemap".format(target_name), - ) + return actions.declare_file("{}.swift.modulemap".format(target_name)) def _modulewrap_object(actions, target_name): """Declares the object file used to wrap Swift modules for ELF binaries. diff --git a/swift/internal/module_maps.bzl b/swift/internal/module_maps.bzl index 1fb4f6eee..67951916c 100644 --- a/swift/internal/module_maps.bzl +++ b/swift/internal/module_maps.bzl @@ -115,6 +115,13 @@ def _header_path(header_file, module_map_file, workspace_relative): if workspace_relative: return header_file.path + # Minor optimization for the generated Objective-C header of a Swift module, + # which will be in the same directory as the module map file -- we can just + # use the header's basename instead of the elaborate relative path + # computation below. + if header_file.dirname == module_map_file.dirname: + return header_file.basename + # Otherwise, since the module map is generated, we need to get the full path # to it rather than just its short path (that is, the path starting with # bazel-out/). Then, we can simply walk up the same number of parent diff --git a/test/private_deps_tests.bzl b/test/private_deps_tests.bzl index d08c98b0c..e594cb852 100644 --- a/test/private_deps_tests.bzl +++ b/test/private_deps_tests.bzl @@ -94,8 +94,8 @@ def private_deps_test_suite(name = "private_deps"): private_deps_provider_test( name = "{}_client_cc_deps_modulemaps".format(name), expected_files = [ - "/test/fixtures/private_deps/public_cc.modulemaps/module.modulemap", - "-/test/fixtures/private_deps/private_cc.modulemaps/module.modulemap", + "/test/fixtures/private_deps/public_cc.swift.modulemap", + "-/test/fixtures/private_deps/private_cc.swift.modulemap", ], field = "transitive_modules.clang!.module_map", provider = "SwiftInfo", From 1ef4601bacd625d77915758c553dd8b62b09c64c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thi=20Do=C3=A3n?= Date: Mon, 1 Feb 2021 15:52:20 +0900 Subject: [PATCH 070/152] Use released protoc binaries where possible (#555) This updates `rules_proto`, which has been configured to use released protoc binaries where it can. This can be a breaking change if users have a call to `protobuf_deps()` _before_ `swift_rules_extra_dependencies()` in their WORKSPACE. To fix, remove `load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps")` and `protobuf_deps()` from the WORKSPACE file, and use the following instead: ``` load( "@build_bazel_rules_swift//swift:extras.bzl", "swift_rules_extra_dependencies", ) swift_rules_extra_dependencies() ``` --- WORKSPACE | 13 +++---------- swift/extras.bzl | 14 ++++++++++---- swift/repositories.bzl | 19 ++++--------------- 3 files changed, 17 insertions(+), 29 deletions(-) diff --git a/WORKSPACE b/WORKSPACE index d3760f2ed..cff5498cd 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -8,18 +8,11 @@ load( swift_rules_dependencies() load( - "@build_bazel_apple_support//lib:repositories.bzl", - "apple_support_dependencies", + "@build_bazel_rules_swift//swift:extras.bzl", + "swift_rules_extra_dependencies", ) -apple_support_dependencies() - -load( - "@com_google_protobuf//:protobuf_deps.bzl", - "protobuf_deps", -) - -protobuf_deps() +swift_rules_extra_dependencies() load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace") diff --git a/swift/extras.bzl b/swift/extras.bzl index a8003b0f3..7ab8af518 100644 --- a/swift/extras.bzl +++ b/swift/extras.bzl @@ -17,17 +17,23 @@ dependencies of the Swift rules. """ load("@build_bazel_apple_support//lib:repositories.bzl", "apple_support_dependencies") -load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps") +load( + "@rules_proto//proto:repositories.bzl", + "rules_proto_dependencies", + "rules_proto_toolchains", +) def swift_rules_extra_dependencies(): """Fetches transitive repositories of the dependencies of `rules_swift`. Users should call this macro in their `WORKSPACE` following the use of - `swift_rules_dependencies` to ensure that all of the dependencies of - the Swift rules are downloaded and that they are isolated from changes + `swift_rules_dependencies` to ensure that all of the dependencies of + the Swift rules are downloaded and that they are isolated from changes to those dependencies. """ apple_support_dependencies() - protobuf_deps() + rules_proto_dependencies() + + rules_proto_toolchains() diff --git a/swift/repositories.bzl b/swift/repositories.bzl index 7dbafe7dd..4bef54bae 100644 --- a/swift/repositories.bzl +++ b/swift/repositories.bzl @@ -99,23 +99,12 @@ def swift_rules_dependencies(): _maybe( http_archive, name = "rules_proto", - # latest as of 2020-09-01 + # latest as of 2021-01-27 urls = [ - "https://github.com/bazelbuild/rules_proto/archive/40298556293ae502c66579620a7ce867d5f57311.zip", + "https://github.com/bazelbuild/rules_proto/archive/a0761ed101b939e19d83b2da5f59034bffc19c12.zip", ], - sha256 = "37d32b789be90fead9ab108dbe4fe4df463d26c122dc896dc1bf134252d3c49a", - strip_prefix = "rules_proto-40298556293ae502c66579620a7ce867d5f57311", - type = "zip", - ) - - _maybe( - http_archive, - name = "com_google_protobuf", - urls = [ - "https://github.com/protocolbuffers/protobuf/archive/v3.14.0.zip", - ], - sha256 = "bf0e5070b4b99240183b29df78155eee335885e53a8af8683964579c214ad301", - strip_prefix = "protobuf-3.14.0", + sha256 = "32c9deb114c9e2d6ea3afd48a4d203d775b60a01876186d1ad52d752a8be439f", + strip_prefix = "rules_proto-a0761ed101b939e19d83b2da5f59034bffc19c12", type = "zip", ) From 18b48c2f586a948c191987c9e9190bd94f45b591 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Mon, 8 Feb 2021 11:41:18 -0800 Subject: [PATCH 071/152] Add disable system index feature (#563) --- swift/internal/compiling.bzl | 13 +++++++++++++ swift/internal/feature_names.bzl | 3 +++ 2 files changed, 16 insertions(+) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index 3247a9cf7..332a7ded3 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -36,6 +36,7 @@ load( "SWIFT_FEATURE_COVERAGE_PREFIX_MAP", "SWIFT_FEATURE_DBG", "SWIFT_FEATURE_DEBUG_PREFIX_MAP", + "SWIFT_FEATURE_DISABLE_SYSTEM_INDEX", "SWIFT_FEATURE_EMIT_C_MODULE", "SWIFT_FEATURE_EMIT_SWIFTINTERFACE", "SWIFT_FEATURE_ENABLE_BATCH_MODE", @@ -717,6 +718,18 @@ def compile_action_configs(): configurators = [_index_while_building_configurator], features = [SWIFT_FEATURE_INDEX_WHILE_BUILDING], ), + swift_toolchain_config.action_config( + actions = [swift_action_names.COMPILE], + configurators = [ + swift_toolchain_config.add_arg( + "-index-ignore-system-modules", + ), + ], + features = [ + SWIFT_FEATURE_INDEX_WHILE_BUILDING, + SWIFT_FEATURE_DISABLE_SYSTEM_INDEX, + ], + ), # User-defined conditional compilation flags (defined for Swift; those # passed directly to ClangImporter are handled above). diff --git a/swift/internal/feature_names.bzl b/swift/internal/feature_names.bzl index f3412f61b..583e33178 100644 --- a/swift/internal/feature_names.bzl +++ b/swift/internal/feature_names.bzl @@ -102,6 +102,9 @@ SWIFT_FEATURE_FULL_DEBUG_INFO = "swift.full_debug_info" # If enabled, the compilation action for a target will produce an index store. SWIFT_FEATURE_INDEX_WHILE_BUILDING = "swift.index_while_building" +# If enabled the compilation action will not produce indexes for system modules. +SWIFT_FEATURE_DISABLE_SYSTEM_INDEX = "swift.disable_system_index" + # If enabled, Swift libraries, binaries, and tests will only have automatic # dependencies on the targets provided by the toolchain's # `required_implicit_deps` field but not those in the `optional_implicit_deps` From dadd12190182530cf6f91ca7f9e70391644ce502 Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Mon, 8 Feb 2021 13:24:10 -0800 Subject: [PATCH 072/152] Don't re-export the modules imported by a Swift generated header. This was an unintentional change in behavior from https://github.com/bazelbuild/rules_swift/commit/5f51ca9c5149122f41cada6122c61788d880fee9; this puts us back to the original behavior, but leaves an API in place for finer-grained control over re-exporting modules in the future. (But the BUILD rules today don't really have the flexibility to support it yet.) PiperOrigin-RevId: 356338982 (cherry picked from commit f45eea8c02a87c3077e5209f471fe4a193b5b0ba) --- swift/internal/module_maps.bzl | 16 +++++++++++++++- swift/internal/swift_clang_module_aspect.bzl | 1 + 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/swift/internal/module_maps.bzl b/swift/internal/module_maps.bzl index 67951916c..fbd21cb15 100644 --- a/swift/internal/module_maps.bzl +++ b/swift/internal/module_maps.bzl @@ -21,6 +21,7 @@ def write_module_map( module_map_file, module_name, dependent_module_names = [], + exported_module_ids = [], public_headers = [], public_textual_headers = [], private_headers = [], @@ -34,6 +35,14 @@ def write_module_map( module_name: The name of the module being generated. dependent_module_names: A `list` of names of Clang modules that are direct dependencies of the target whose module map is being written. + exported_module_ids: A `list` of Clang wildcard module identifiers that + will be re-exported as part of the API of the module being written. + The values in this list should match `wildcard-module-id` as + described by + https://clang.llvm.org/docs/Modules.html#export-declaration. Common + values include the empty list to re-export nothing (except the + module's own API), or `["*"]` to re-export all modules that were + imported by the header files in the module. public_headers: The `list` of `File`s representing the public modular headers of the target whose module map is being written. public_textual_headers: The `list` of `File`s representing the public @@ -47,7 +56,12 @@ def write_module_map( or relative to the module map file. """ content = 'module "{}" {{\n'.format(module_name) - content += " export *\n\n" + if exported_module_ids: + content += "".join([ + " export {}\n".format(module_id) + for module_id in exported_module_ids + ]) + content += "\n" content += "".join([ ' header "{}"\n'.format(_header_path( diff --git a/swift/internal/swift_clang_module_aspect.bzl b/swift/internal/swift_clang_module_aspect.bzl index 7fea0317e..9131e6f70 100644 --- a/swift/internal/swift_clang_module_aspect.bzl +++ b/swift/internal/swift_clang_module_aspect.bzl @@ -131,6 +131,7 @@ def _generate_module_map( write_module_map( actions = actions, dependent_module_names = dependent_module_names, + exported_module_ids = ["*"], module_map_file = module_map_file, module_name = module_name, private_headers = private_headers, From 9e743aa01635348a99b469995f41264c92877534 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thi=20Do=C3=A3n?= Date: Wed, 17 Feb 2021 09:28:14 +0900 Subject: [PATCH 073/152] Explicitly set --macos_minimum_os=10.15 to make `swift_{binary,test}` runnable on macOS Catalina (which is the macOS version used by Bazel CI) when building with Xcode 12 or above (#566) Since there's no way to set the deployment version for `*_{binary,test}`, this makes rules_swift on CI green again without having to go back to using Xcode 11.7. --- .bazelrc | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .bazelrc diff --git a/.bazelrc b/.bazelrc new file mode 100644 index 000000000..1f52e460b --- /dev/null +++ b/.bazelrc @@ -0,0 +1,4 @@ +# Since there's no way to set the deployment version for swift_{binary,test}, +# this forces all targets' minimum macOS to Catalina until Bazel CI has +# upgraded their Mac machines to Big Sur. +build --macos_minimum_os=10.15 From 3d59e85ff45d37b4f098def4758d008f6b6a6a46 Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Wed, 3 Feb 2021 12:07:35 -0800 Subject: [PATCH 074/152] Move toolchain- and command-line-provided compiler flags into action configurators. This change removes of the `SwiftToolchainInfo.command_line_copts` field, no longer treating those command line flags as an odd special case. It also ensures that flags from the toolchain are passed in a unified manner regardless of which rule registers the action. For example, Bazel-legacy Objective-C flags determined by compilation mode, like `-fstack-protector`, affect the compatibility of Clang modules and need to be passed both when compiling an explicit module and when compiling the Swift code that consumes those modules. This required a bit more shuffling around of the way we need to handle differing outptus for WMO, since the `--swiftcopt` flags would no longer be able to be scanned directly after the toolchain configuration. PiperOrigin-RevId: 355451642 (cherry picked from commit 1bea35e22e18c56818f1c485ab04d2272736ea45) --- swift/internal/actions.bzl | 12 +- swift/internal/compiling.bzl | 218 ++++++++++++++++++----- swift/internal/feature_names.bzl | 10 ++ swift/internal/providers.bzl | 7 - swift/internal/swift_toolchain.bzl | 22 ++- swift/internal/xcode_swift_toolchain.bzl | 29 +-- 6 files changed, 227 insertions(+), 71 deletions(-) diff --git a/swift/internal/actions.bzl b/swift/internal/actions.bzl index fd7773877..9066cd758 100644 --- a/swift/internal/actions.bzl +++ b/swift/internal/actions.bzl @@ -135,7 +135,17 @@ def _apply_action_configs( prerequisites, args, ) - if action_inputs: + + # If we create an action configurator from a lambda that calls + # `Args.add*`, the result will be the `Args` objects (rather + # than `None`) because those methods return the same `Args` + # object for chaining. We can guard against this (and possibly + # other errors) by checking that the value is a struct. If it + # is, then it's not `None` and it probably came from the + # provider used by `swift_toolchain_config.config_result`. If + # it's some other kind of struct, then we'll error out trying to + # access the fields. + if type(action_inputs) == "struct": inputs.extend(action_inputs.inputs) transitive_inputs.extend(action_inputs.transitive_inputs) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index 332a7ded3..f7018394d 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -61,6 +61,8 @@ load( "SWIFT_FEATURE_USE_C_MODULES", "SWIFT_FEATURE_USE_GLOBAL_MODULE_CACHE", "SWIFT_FEATURE_VFSOVERLAY", + "SWIFT_FEATURE__NUM_THREADS_1_IN_SWIFTCOPTS", + "SWIFT_FEATURE__WMO_IN_SWIFTCOPTS", ) load(":features.bzl", "are_all_features_enabled", "is_feature_enabled") load(":module_maps.bzl", "write_module_map") @@ -85,12 +87,32 @@ _SWIFTMODULES_VFS_ROOT = "/__build_bazel_rules_swift/swiftmodules" # when an API to obtain this is available. _DEFAULT_WMO_THREAD_COUNT = 12 -def compile_action_configs(): +# Swift command line flags that enable whole module optimization. (This +# dictionary is used as a set for quick lookup; the values are irrelevant.) +_WMO_FLAGS = { + "-wmo": True, + "-whole-module-optimization": True, + "-force-single-frontend-invocation": True, +} + +def compile_action_configs( + *, + additional_objc_copts = [], + additional_swiftc_copts = []): """Returns the list of action configs needed to perform Swift compilation. Toolchains must add these to their own list of action configs so that compilation actions will be correctly configured. + Args: + additional_objc_copts: An optional list of additional Objective-C + compiler flags that should be passed (preceded by `-Xcc`) to Swift + compile actions *and* Swift explicit module precompile actions after + any other toolchain- or user-provided flags. + additional_swiftc_copts: An optional list of additional Swift compiler + flags that should be passed to Swift compile actions only after any + other toolchain- or user-provided flags. + Returns: The list of action configs needed to perform compilation. """ @@ -274,7 +296,10 @@ def compile_action_configs(): configurators = [ swift_toolchain_config.add_arg("-whole-module-optimization"), ], - features = [SWIFT_FEATURE_OPT, SWIFT_FEATURE_OPT_USES_WMO], + features = [ + [SWIFT_FEATURE_OPT, SWIFT_FEATURE_OPT_USES_WMO], + [SWIFT_FEATURE__WMO_IN_SWIFTCOPTS], + ], ), # Enable or disable serialization of debugging options into @@ -656,10 +681,14 @@ def compile_action_configs(): ], configurators = [_batch_mode_configurator], features = [SWIFT_FEATURE_ENABLE_BATCH_MODE], - not_features = [SWIFT_FEATURE_OPT, SWIFT_FEATURE_OPT_USES_WMO], + not_features = [ + [SWIFT_FEATURE_OPT, SWIFT_FEATURE_OPT_USES_WMO], + [SWIFT_FEATURE__WMO_IN_SWIFTCOPTS], + ], ), - # Set the number of threads to use for WMO. + # Set the number of threads to use for WMO. (We can skip this if we know + # we'll already be applying `-num-threads` via `--swiftcopt` flags.) swift_toolchain_config.action_config( actions = [ swift_action_names.COMPILE, @@ -673,7 +702,11 @@ def compile_action_configs(): False, ), ], - features = [SWIFT_FEATURE_OPT, SWIFT_FEATURE_OPT_USES_WMO], + features = [ + [SWIFT_FEATURE_OPT, SWIFT_FEATURE_OPT_USES_WMO], + [SWIFT_FEATURE__WMO_IN_SWIFTCOPTS], + ], + not_features = [SWIFT_FEATURE__NUM_THREADS_1_IN_SWIFTCOPTS], ), swift_toolchain_config.action_config( actions = [ @@ -688,7 +721,10 @@ def compile_action_configs(): True, ), ], - not_features = [SWIFT_FEATURE_OPT, SWIFT_FEATURE_OPT_USES_WMO], + not_features = [ + [SWIFT_FEATURE_OPT, SWIFT_FEATURE_OPT_USES_WMO], + [SWIFT_FEATURE__NUM_THREADS_1_IN_SWIFTCOPTS], + ], ), # Set the module name. @@ -751,10 +787,12 @@ def compile_action_configs(): ), ] - # NOTE: The position of this action config in the list is important, because - # it places user compile flags after flags added by the rules, allowing - # `copts` attributes and `--swiftcopt` flag values to override flags set by - # the rule implementations as a last resort. + # NOTE: The positions of these action configs in the list are important, + # because it places the `copts` attribute ("user compile flags") after flags + # added by the rules, and then the "additional objc" and "additional swift" + # flags follow those, which are `--objccopt` and `--swiftcopt` flags from + # the command line that should override even the flags specified in the + # `copts` attribute. action_configs.append( swift_toolchain_config.action_config( actions = [ @@ -764,6 +802,40 @@ def compile_action_configs(): configurators = [_user_compile_flags_configurator], ), ) + if additional_objc_copts: + action_configs.append( + swift_toolchain_config.action_config( + actions = [ + swift_action_names.COMPILE, + swift_action_names.PRECOMPILE_C_MODULE, + ], + configurators = [ + # TODO(#568): Switch to using lambda when the minimum + # supported Bazel version by rules_swift supports it. + partial.make( + _additional_objc_copts_configurator, + additional_objc_copts, + ), + ], + ), + ) + if additional_swiftc_copts: + action_configs.append( + swift_toolchain_config.action_config( + # TODO(allevato): Determine if there are any uses of + # `-Xcc`-prefixed flags that need to be added to explicit module + # actions, or if we should advise against/forbid that. + actions = [swift_action_names.COMPILE], + configurators = [ + # TODO(#568): Switch to using lambda when the minimum + # supported Bazel version by rules_swift supports it. + partial.make( + _additional_swift_copts_configurator, + additional_swiftc_copts, + ), + ], + ), + ) action_configs.append( swift_toolchain_config.action_config( @@ -1222,9 +1294,34 @@ def _is_wmo_manually_requested(user_compile_flags): Returns: True if WMO is enabled in the given list of flags. """ - return ("-wmo" in user_compile_flags or - "-whole-module-optimization" in user_compile_flags or - "-force-single-frontend-invocation" in user_compile_flags) + for copt in user_compile_flags: + if copt in _WMO_FLAGS: + return True + return False + +def features_from_swiftcopts(swiftcopts): + """Returns a list of features to enable based on `--swiftcopt` flags. + + Since `--swiftcopt` flags are hooked into the action configuration when the + toolchain is configured, it's not possible for individual actions to query + them easily if those flags may determine the nature of outputs (for example, + single- vs. multi-threaded WMO). The toolchain can call this function to map + those flags to private features that can be queried instead. + + Args: + swiftcopts: The list of command line flags that were passed using + `--swiftcopt`. + + Returns: + A list (possibly empty) of strings denoting feature names that should be + enabled on the toolchain. + """ + features = [] + if _is_wmo_manually_requested(user_compile_flags = swiftcopts): + features.append(SWIFT_FEATURE__WMO_IN_SWIFTCOPTS) + if _find_num_threads_flag_value(user_compile_flags = swiftcopts) == 1: + features.append(SWIFT_FEATURE__NUM_THREADS_1_IN_SWIFTCOPTS) + return features def _index_while_building_configurator(prerequisites, args): """Adds flags for index-store generation to the command line.""" @@ -1259,6 +1356,19 @@ def _additional_inputs_configurator(prerequisites, args): inputs = prerequisites.additional_inputs, ) +def _additional_objc_copts_configurator(additional_objc_copts, prerequisites, args): + """Adds additional Objective-C compiler flags to the command line.""" + _unused = [prerequisites] + args.add_all( + additional_objc_copts, + before_each = "-Xcc", + ) + +def _additional_swift_copts_configurator(additional_swiftc_copts, prerequisites, args): + """Adds additional Swift compiler flags to the command line.""" + _unused = [prerequisites] + args.add_all(additional_swiftc_copts) + def derive_module_name(*args): """Returns a derived module name from the given build label. @@ -1393,7 +1503,7 @@ def compile( module_name = module_name, srcs = srcs, target_name = target_name, - user_compile_flags = copts + swift_toolchain.command_line_copts, + user_compile_flags = copts, ) split_derived_file_generation = is_feature_enabled( @@ -1502,7 +1612,7 @@ def compile( source_files = srcs, transitive_modules = transitive_modules, transitive_swiftmodules = transitive_swiftmodules, - user_compile_flags = copts + swift_toolchain.command_line_copts, + user_compile_flags = copts, vfsoverlay_file = vfsoverlay_file, vfsoverlay_search_path = _SWIFTMODULES_VFS_ROOT, # Merge the compile outputs into the prerequisites. @@ -1799,12 +1909,8 @@ def _declare_compile_outputs( # Now, declare outputs like object files for which there may be one or many, # depending on the compilation mode. - is_wmo_implied_by_features = are_all_features_enabled( - feature_configuration = feature_configuration, - feature_names = [SWIFT_FEATURE_OPT, SWIFT_FEATURE_OPT_USES_WMO], - ) output_nature = _emitted_output_nature( - is_wmo_implied_by_features = is_wmo_implied_by_features, + feature_configuration = feature_configuration, user_compile_flags = user_compile_flags, ) @@ -2315,7 +2421,32 @@ def _disable_autolink_framework_copts(framework_name): ], ) -def _emitted_output_nature(is_wmo_implied_by_features, user_compile_flags): +def _find_num_threads_flag_value(user_compile_flags): + """Finds the value of the `-num-threads` flag. + + This function looks for both forms of the flag (`-num-threads X` and + `-num-threads=X`) and returns the corresponding value if found. If the flag + is present multiple times, the last value is the one returned. + + Args: + user_compile_flags: The options passed into the compile action. + + Returns: + The numeric value of the `-num-threads` flag if found, otherwise `None`. + """ + num_threads = None + saw_space_separated_num_threads = False + for copt in user_compile_flags: + if saw_space_separated_num_threads: + saw_space_separated_num_threads = False + num_threads = _safe_int(copt) + elif copt == "-num-threads": + saw_space_separated_num_threads = True + elif copt.startswith("-num-threads="): + num_threads = _safe_int(copt.split("=")[1]) + return num_threads + +def _emitted_output_nature(feature_configuration, user_compile_flags): """Returns information about the nature of emitted compilation outputs. The compiler emits a single object if it is invoked with whole-module @@ -2325,8 +2456,8 @@ def _emitted_output_nature(is_wmo_implied_by_features, user_compile_flags): thread count,_ so we have to treat that case separately. Args: - is_wmo_implied_by_features: Whether WMO is implied by features set in - the feature configuration. + feature_configuration: The feature configuration for the current + compilation. user_compile_flags: The options passed into the compile action. Returns: @@ -2340,35 +2471,28 @@ def _emitted_output_nature(is_wmo_implied_by_features, user_compile_flags): compilation action with the given flags. """ is_wmo = ( - is_wmo_implied_by_features or + is_feature_enabled( + feature_configuration = feature_configuration, + feature_name = SWIFT_FEATURE__WMO_IN_SWIFTCOPTS, + ) or + are_all_features_enabled( + feature_configuration = feature_configuration, + feature_names = [SWIFT_FEATURE_OPT, SWIFT_FEATURE_OPT_USES_WMO], + ) or _is_wmo_manually_requested(user_compile_flags) ) - saw_space_separated_num_threads = False - - # If WMO is enabled, the action config will automatically add - # `-num-threads 12` to the command line. We need to stage that as our - # initial default here to ensure that we return the right value if the user - # compile flags don't otherwise override it. - # - # 0 is the only option that makes swift emit a single object file, anything - # greater and it uses that number of threads to emit multiple objects - num_threads = _DEFAULT_WMO_THREAD_COUNT if is_wmo else 0 - - for copt in user_compile_flags: - if saw_space_separated_num_threads: - saw_space_separated_num_threads = False - num_threads = _safe_int(copt) - elif copt == "-num-threads": - saw_space_separated_num_threads = True - elif copt.startswith("-num-threads="): - num_threads = _safe_int(copt.split("=")[1]) - - if num_threads == None or num_threads < 0: - fail("The value of '-num-threads' must be a positive integer.") + # We check the feature first because that implies that `-num-threads 1` was + # present in `--swiftcopt`, which overrides all other flags (like the user + # compile flags, which come from the target's `copts`). Only fallback to + # checking the flags if the feature is disabled. + is_single_threaded = is_feature_enabled( + feature_configuration = feature_configuration, + feature_name = SWIFT_FEATURE__NUM_THREADS_1_IN_SWIFTCOPTS, + ) or _find_num_threads_flag_value(user_compile_flags) == 1 return struct( - emits_multiple_objects = not (is_wmo and num_threads == 0), + emits_multiple_objects = not (is_wmo and is_single_threaded), emits_partial_modules = not is_wmo, ) diff --git a/swift/internal/feature_names.bzl b/swift/internal/feature_names.bzl index 583e33178..b656905bf 100644 --- a/swift/internal/feature_names.bzl +++ b/swift/internal/feature_names.bzl @@ -237,3 +237,13 @@ SWIFT_FEATURE_ENABLE_SKIP_FUNCTION_BODIES = "swift.skip_function_bodies_for_deri # If enabled remap the absolute path to Xcode in debug info. When used with # swift.coverage_prefix_map also remap the path in coverage data. SWIFT_FEATURE_REMAP_XCODE_PATH = "swift.remap_xcode_path" + +# A private feature that is set by the toolchain if a flag enabling WMO was +# passed on the command line using `--swiftcopt`. Users should never manually +# enable, disable, or query this feature. +SWIFT_FEATURE__WMO_IN_SWIFTCOPTS = "swift._wmo_in_swiftcopts" + +# A private feature that is set by the toolchain if the flags `-num-threads 1` +# were passed on the command line using `--swiftcopt`. Users should never +# manually enable, disable, or query this feature. +SWIFT_FEATURE__NUM_THREADS_1_IN_SWIFTCOPTS = "swift._num_threads_1_in_swiftcopts" diff --git a/swift/internal/providers.bzl b/swift/internal/providers.bzl index 247f7d212..bf3e14586 100644 --- a/swift/internal/providers.bzl +++ b/swift/internal/providers.bzl @@ -69,13 +69,6 @@ using this toolchain. "cc_toolchain_info": """\ The `cc_common.CcToolchainInfo` provider from the Bazel C++ toolchain that this Swift toolchain depends on. -""", - "command_line_copts": """\ -`List` of `strings`. Flags that were passed to Bazel using the `--swiftcopt` -command line flag. These flags have the highest precedence; they are added to -compilation command lines after the toolchain default flags -(`SwiftToolchainInfo.swiftc_copts`) and after flags specified in the `copts` -attributes of Swift targets. """, "cpu": """\ `String`. The CPU architecture that the toolchain is targeting. diff --git a/swift/internal/swift_toolchain.bzl b/swift/internal/swift_toolchain.bzl index c975787bc..9cd75fff0 100644 --- a/swift/internal/swift_toolchain.bzl +++ b/swift/internal/swift_toolchain.bzl @@ -25,7 +25,7 @@ load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain") load(":actions.bzl", "swift_action_names") load(":attrs.bzl", "swift_toolchain_driver_attrs") load(":autolinking.bzl", "autolink_extract_action_configs") -load(":compiling.bzl", "compile_action_configs") +load(":compiling.bzl", "compile_action_configs", "features_from_swiftcopts") load(":debugging.bzl", "modulewrap_action_configs") load( ":feature_names.bzl", @@ -89,14 +89,20 @@ def _all_tool_configs( ), } -def _all_action_configs(): +def _all_action_configs(additional_swiftc_copts): """Returns the action configurations for the Swift toolchain. + Args: + additional_swiftc_copts: Additional Swift compiler flags obtained from + the `swift` configuration fragment. + Returns: A list of action configurations for the toolchain. """ return ( - compile_action_configs() + + compile_action_configs( + additional_swift_copts = additional_swiftc_copts, + ) + modulewrap_action_configs() + autolink_extract_action_configs() ) @@ -173,7 +179,10 @@ def _swift_toolchain_impl(ctx): # Combine build mode features, autoconfigured features, and required # features. - requested_features = features_for_build_modes(ctx) + requested_features = ( + features_for_build_modes(ctx) + + features_from_swiftcopts(swiftcopts = ctx.fragments.swift.copts()) + ) requested_features.extend([ SWIFT_FEATURE_NO_GENERATED_HEADER, SWIFT_FEATURE_NO_GENERATED_MODULE_MAP, @@ -194,7 +203,9 @@ def _swift_toolchain_impl(ctx): use_param_file = SWIFT_FEATURE_USE_RESPONSE_FILES in ctx.features, additional_tools = [ctx.file.version_file], ) - all_action_configs = _all_action_configs() + all_action_configs = _all_action_configs( + additional_swiftc_copts = ctx.fragments.swift.copts(), + ) # TODO(allevato): Move some of the remaining hardcoded values, like object # format and Obj-C interop support, to attributes so that we can remove the @@ -204,7 +215,6 @@ def _swift_toolchain_impl(ctx): action_configs = all_action_configs, all_files = depset(all_files), cc_toolchain_info = cc_toolchain, - command_line_copts = ctx.fragments.swift.copts(), cpu = ctx.attr.arch, linker_opts_producer = linker_opts_producer, linker_supports_filelist = False, diff --git a/swift/internal/xcode_swift_toolchain.bzl b/swift/internal/xcode_swift_toolchain.bzl index 24ee7215f..8be6f4685 100644 --- a/swift/internal/xcode_swift_toolchain.bzl +++ b/swift/internal/xcode_swift_toolchain.bzl @@ -19,14 +19,13 @@ toolchain package. If you are looking for rules to build Swift code using this toolchain, see `swift.bzl`. """ -load("@bazel_skylib//lib:collections.bzl", "collections") load("@bazel_skylib//lib:dicts.bzl", "dicts") load("@bazel_skylib//lib:partial.bzl", "partial") load("@bazel_skylib//lib:paths.bzl", "paths") load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain") load(":actions.bzl", "swift_action_names") load(":attrs.bzl", "swift_toolchain_driver_attrs") -load(":compiling.bzl", "compile_action_configs") +load(":compiling.bzl", "compile_action_configs", "features_from_swiftcopts") load( ":feature_names.bzl", "SWIFT_FEATURE_BITCODE_EMBEDDED", @@ -109,11 +108,7 @@ def _command_line_objc_copts(compilation_mode, objc_fragment): ] clang_copts = objc_fragment.copts + legacy_copts - - return collections.before_each( - "-Xcc", - [copt for copt in clang_copts if copt != "-g"], - ) + return [copt for copt in clang_copts if copt != "-g"] def _platform_developer_framework_dir(apple_toolchain, apple_fragment): """Returns the Developer framework directory for the platform. @@ -323,6 +318,8 @@ def _resource_directory_configurator(developer_dir, prerequisites, args): ) def _all_action_configs( + additional_objc_copts, + additional_swiftc_copts, apple_fragment, apple_toolchain, needs_resource_directory, @@ -330,6 +327,11 @@ def _all_action_configs( """Returns the action configurations for the Swift toolchain. Args: + additional_objc_copts: Additional Objective-C compiler flags obtained + from the `objc` configuration fragment (and legacy flags that were + previously passed directly by Bazel). + additional_swiftc_copts: Additional Swift compiler flags obtained from + the `swift` configuration fragment. apple_fragment: The `apple` configuration fragment. apple_toolchain: The `apple_common.apple_toolchain()` object. needs_resource_directory: If True, the toolchain needs the resource @@ -484,7 +486,10 @@ def _all_action_configs( ), ) - action_configs.extend(compile_action_configs()) + action_configs.extend(compile_action_configs( + additional_objc_copts = additional_objc_copts, + additional_swiftc_copts = additional_swiftc_copts, + )) return action_configs def _all_tool_configs( @@ -700,7 +705,7 @@ def _xcode_swift_toolchain_impl(ctx): requested_features = features_for_build_modes( ctx, objc_fragment = ctx.fragments.objc, - ) + ) + features_from_swiftcopts(swiftcopts = ctx.fragments.swift.copts()) requested_features.extend(ctx.features) requested_features.append(SWIFT_FEATURE_BUNDLED_XCTESTS) requested_features.extend( @@ -752,6 +757,11 @@ def _xcode_swift_toolchain_impl(ctx): xcode_config = xcode_config, ) all_action_configs = _all_action_configs( + additional_objc_copts = _command_line_objc_copts( + ctx.var["COMPILATION_MODE"], + ctx.fragments.objc, + ), + additional_swiftc_copts = ctx.fragments.swift.copts(), apple_fragment = apple_fragment, apple_toolchain = apple_toolchain, needs_resource_directory = swift_executable or toolchain_root, @@ -770,7 +780,6 @@ def _xcode_swift_toolchain_impl(ctx): action_configs = all_action_configs, all_files = depset(all_files), cc_toolchain_info = cc_toolchain, - command_line_copts = command_line_copts, cpu = cpu, linker_opts_producer = linker_opts_producer, linker_supports_filelist = True, From 3c7ed7171b9546771f34d2fad043e75633280a8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thi=20Do=C3=A3n?= Date: Mon, 22 Feb 2021 15:46:10 +0900 Subject: [PATCH 075/152] Fix incorrect param name --- swift/internal/compiling.bzl | 4 ++-- swift/internal/swift_toolchain.bzl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index f7018394d..cf8680f8a 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -830,7 +830,7 @@ def compile_action_configs( # TODO(#568): Switch to using lambda when the minimum # supported Bazel version by rules_swift supports it. partial.make( - _additional_swift_copts_configurator, + _additional_swiftc_copts_configurator, additional_swiftc_copts, ), ], @@ -1364,7 +1364,7 @@ def _additional_objc_copts_configurator(additional_objc_copts, prerequisites, ar before_each = "-Xcc", ) -def _additional_swift_copts_configurator(additional_swiftc_copts, prerequisites, args): +def _additional_swiftc_copts_configurator(additional_swiftc_copts, prerequisites, args): """Adds additional Swift compiler flags to the command line.""" _unused = [prerequisites] args.add_all(additional_swiftc_copts) diff --git a/swift/internal/swift_toolchain.bzl b/swift/internal/swift_toolchain.bzl index 9cd75fff0..a7749312b 100644 --- a/swift/internal/swift_toolchain.bzl +++ b/swift/internal/swift_toolchain.bzl @@ -101,7 +101,7 @@ def _all_action_configs(additional_swiftc_copts): """ return ( compile_action_configs( - additional_swift_copts = additional_swiftc_copts, + additional_swiftc_copts = additional_swiftc_copts, ) + modulewrap_action_configs() + autolink_extract_action_configs() From daf7baaa501d96c7fb249f2c3d395fc64b27a3cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thi=20Do=C3=A3n?= Date: Tue, 23 Feb 2021 09:01:04 +0900 Subject: [PATCH 076/152] Fix non-threaded mode WMO The non-threaded mode WMO, which produces a single object file for the entire compilation unit (.o), is determined by the non-presence of the `-num-threads` flag, or `-num-threads 0` flags are passed. --- swift/internal/compiling.bzl | 16 ++++++++-------- swift/internal/feature_names.bzl | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index cf8680f8a..26128bd48 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -61,7 +61,7 @@ load( "SWIFT_FEATURE_USE_C_MODULES", "SWIFT_FEATURE_USE_GLOBAL_MODULE_CACHE", "SWIFT_FEATURE_VFSOVERLAY", - "SWIFT_FEATURE__NUM_THREADS_1_IN_SWIFTCOPTS", + "SWIFT_FEATURE__NUM_THREADS_0_IN_SWIFTCOPTS", "SWIFT_FEATURE__WMO_IN_SWIFTCOPTS", ) load(":features.bzl", "are_all_features_enabled", "is_feature_enabled") @@ -706,7 +706,7 @@ def compile_action_configs( [SWIFT_FEATURE_OPT, SWIFT_FEATURE_OPT_USES_WMO], [SWIFT_FEATURE__WMO_IN_SWIFTCOPTS], ], - not_features = [SWIFT_FEATURE__NUM_THREADS_1_IN_SWIFTCOPTS], + not_features = [SWIFT_FEATURE__NUM_THREADS_0_IN_SWIFTCOPTS], ), swift_toolchain_config.action_config( actions = [ @@ -723,7 +723,7 @@ def compile_action_configs( ], not_features = [ [SWIFT_FEATURE_OPT, SWIFT_FEATURE_OPT_USES_WMO], - [SWIFT_FEATURE__NUM_THREADS_1_IN_SWIFTCOPTS], + [SWIFT_FEATURE__NUM_THREADS_0_IN_SWIFTCOPTS], ], ), @@ -1319,8 +1319,8 @@ def features_from_swiftcopts(swiftcopts): features = [] if _is_wmo_manually_requested(user_compile_flags = swiftcopts): features.append(SWIFT_FEATURE__WMO_IN_SWIFTCOPTS) - if _find_num_threads_flag_value(user_compile_flags = swiftcopts) == 1: - features.append(SWIFT_FEATURE__NUM_THREADS_1_IN_SWIFTCOPTS) + if _find_num_threads_flag_value(user_compile_flags = swiftcopts) == 0: + features.append(SWIFT_FEATURE__NUM_THREADS_0_IN_SWIFTCOPTS) return features def _index_while_building_configurator(prerequisites, args): @@ -2482,14 +2482,14 @@ def _emitted_output_nature(feature_configuration, user_compile_flags): _is_wmo_manually_requested(user_compile_flags) ) - # We check the feature first because that implies that `-num-threads 1` was + # We check the feature first because that implies that `-num-threads 0` was # present in `--swiftcopt`, which overrides all other flags (like the user # compile flags, which come from the target's `copts`). Only fallback to # checking the flags if the feature is disabled. is_single_threaded = is_feature_enabled( feature_configuration = feature_configuration, - feature_name = SWIFT_FEATURE__NUM_THREADS_1_IN_SWIFTCOPTS, - ) or _find_num_threads_flag_value(user_compile_flags) == 1 + feature_name = SWIFT_FEATURE__NUM_THREADS_0_IN_SWIFTCOPTS, + ) or _find_num_threads_flag_value(user_compile_flags) == 0 return struct( emits_multiple_objects = not (is_wmo and is_single_threaded), diff --git a/swift/internal/feature_names.bzl b/swift/internal/feature_names.bzl index b656905bf..7ca468c92 100644 --- a/swift/internal/feature_names.bzl +++ b/swift/internal/feature_names.bzl @@ -243,7 +243,7 @@ SWIFT_FEATURE_REMAP_XCODE_PATH = "swift.remap_xcode_path" # enable, disable, or query this feature. SWIFT_FEATURE__WMO_IN_SWIFTCOPTS = "swift._wmo_in_swiftcopts" -# A private feature that is set by the toolchain if the flags `-num-threads 1` +# A private feature that is set by the toolchain if the flags `-num-threads 0` # were passed on the command line using `--swiftcopt`. Users should never # manually enable, disable, or query this feature. -SWIFT_FEATURE__NUM_THREADS_1_IN_SWIFTCOPTS = "swift._num_threads_1_in_swiftcopts" +SWIFT_FEATURE__NUM_THREADS_0_IN_SWIFTCOPTS = "swift._num_threads_0_in_swiftcopts" From a84b2c6c0af48f6972c0be718847a7da5bd8cb36 Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Thu, 4 Feb 2021 09:47:09 -0800 Subject: [PATCH 077/152] No longer scan for `-num-threads=X` (specifically the form with the equal sign). We've always supported this, but `swiftc` today doesn't accept the version with the equal sign and briefly looking through the history of Options.td I can't find any evidence that it ever did. We continue to support space-separated `-num-threads X`. PiperOrigin-RevId: 355647561 (cherry picked from commit d26868fee498495a5ac66a54a540b4c50014380b) --- swift/internal/compiling.bzl | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index 26128bd48..6e2f619b4 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -2424,9 +2424,9 @@ def _disable_autolink_framework_copts(framework_name): def _find_num_threads_flag_value(user_compile_flags): """Finds the value of the `-num-threads` flag. - This function looks for both forms of the flag (`-num-threads X` and - `-num-threads=X`) and returns the corresponding value if found. If the flag - is present multiple times, the last value is the one returned. + This function looks for the `-num-threads` flag and returns the + corresponding value if found. If the flag is present multiple times, the + last value is the one returned. Args: user_compile_flags: The options passed into the compile action. @@ -2435,15 +2435,13 @@ def _find_num_threads_flag_value(user_compile_flags): The numeric value of the `-num-threads` flag if found, otherwise `None`. """ num_threads = None - saw_space_separated_num_threads = False + saw_num_threads = False for copt in user_compile_flags: - if saw_space_separated_num_threads: - saw_space_separated_num_threads = False + if saw_num_threads: + saw_num_threads = False num_threads = _safe_int(copt) elif copt == "-num-threads": - saw_space_separated_num_threads = True - elif copt.startswith("-num-threads="): - num_threads = _safe_int(copt.split("=")[1]) + saw_num_threads = True return num_threads def _emitted_output_nature(feature_configuration, user_compile_flags): From 87b4d412629424b9a3c38db324597b2dbc7b3374 Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Thu, 4 Feb 2021 11:09:19 -0800 Subject: [PATCH 078/152] Unconditionally add `ObjcProvider.umbrella_header` files to compiler inputs, even when preferring explicit modules. A small number of rules use `umbrella_header` to propagate an umbrella header for their module map that they don't propagate in any other header field. Since there is no `direct_*` version of this field, `swift_clang_module_aspect` can't easily extract the one umbrella header from the `depset` in the provider that may also include transitive umbrella headers. PiperOrigin-RevId: 355667496 (cherry picked from commit bd8c7d45f3616c83fc54645a069f5aa76e6f3612) --- swift/internal/compiling.bzl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index 6e2f619b4..698b14fe0 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -1039,8 +1039,10 @@ def _collect_clang_module_inputs( # Some rules still use the `umbrella_header` field to propagate a header # that they don't also include in `CcInfo.compilation_context.headers`, so - # we also need to pull this in for the time being. - if not prefer_precompiled_modules and objc_info: + # we also need to pull these in for the time being. + # TODO(b/142867898): This can be removed once the Swift rules start + # generating its own module map for these targets. + if objc_info: transitive_inputs.append(objc_info.umbrella_header) for module in modules: From ad39543f85b5ce955d40e4bd63608ee0b19bdc2e Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Fri, 19 Feb 2021 08:01:50 -0800 Subject: [PATCH 079/152] Compile an explicit module for the generated header of a `swift_library`. The notion of "implicit compile-time dependencies for generated header modules only" has been added to the toolchain because generated Obj-C headers always import Foundation and Darwin, but we don't necessarily want to force those as dependencies of every Swift compilation. Likewise, the private (implementation-only) dependencies of a module shouldn't be included when generating the module map `use` decls for the Obj-C header module, because by definition, they can't be exported. PiperOrigin-RevId: 358406043 (cherry picked from commit ab1c5cd0038c76a88738d8aff7397e728ccad3cf) --- swift/internal/compiling.bzl | 93 ++++++++++++++++++++---- swift/internal/providers.bzl | 7 ++ swift/internal/swift_library.bzl | 12 +-- swift/internal/swift_toolchain.bzl | 1 + swift/internal/xcode_swift_toolchain.bzl | 11 +++ 5 files changed, 102 insertions(+), 22 deletions(-) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index 698b14fe0..b95dba870 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -1424,7 +1424,8 @@ def compile( defines = [], deps = [], generated_header_name = None, - genfiles_dir = None): + genfiles_dir = None, + private_deps = []): """Compiles a Swift module. Args: @@ -1453,9 +1454,11 @@ def compile( determine whether whole module optimization is being requested, which affects the nature of the output files. defines: Symbols that should be defined by passing `-D` to the compiler. - deps: Dependencies of the target being compiled. These targets must - propagate one of the following providers: `CcInfo`, `SwiftInfo`, or - `apple_common.Objc`. + deps: Non-private dependencies of the target being compiled. These + targets are used as dependencies of both the Swift module being + compiled and the Clang module for the generated header. These + targets must propagate one of the following providers: `CcInfo`, + `SwiftInfo`, or `apple_common.Objc`. generated_header_name: The name of the Objective-C generated header that should be generated for this module. If omitted, the name `${target_name}-Swift.h` will be used. @@ -1463,6 +1466,11 @@ def compile( path is added to ClangImporter's header search paths for compatibility with Bazel's C++ and Objective-C rules which support inclusions of generated headers from that location. + private_deps: Private (implementation-only) dependencies of the target + being compiled. These are only used as dependencies of the Swift + module, not of the Clang module for the generated header. These + targets must propagate one of the following providers: `CcInfo`, + `SwiftInfo`, or `apple_common.Objc`. Returns: A `struct` containing the following fields: @@ -1487,6 +1495,9 @@ def compile( never None. * `object_files`: A list of `.o` files that were produced by the compiler. + * `precompiled_module`: A `File` representing the explicit module + (`.pcm`) of the Clang module for the generated header, or `None` if + no explicit module was generated. * `stats_directory`: A `File` representing the directory that contains the timing statistics emitted by the compiler. If no stats were requested, this field will be None. @@ -1498,10 +1509,14 @@ def compile( * `swiftmodule`: The `.swiftmodule` file that was produced by the compiler. """ + generated_module_deps = ( + deps + swift_toolchain.generated_header_module_implicit_deps + ) compile_outputs, other_outputs = _declare_compile_outputs( actions = actions, - generated_header_name = generated_header_name, feature_configuration = feature_configuration, + generated_header_name = generated_header_name, + generated_module_deps = generated_module_deps, module_name = module_name, srcs = srcs, target_name = target_name, @@ -1547,13 +1562,12 @@ def compile( # `SwiftInfo`, `CcInfo`, and `apple_common.Objc`. Then we can pass these # into the action prerequisites so that configurators have easy access to # the full set of values and inputs through a single accessor. - all_deps = deps + get_implicit_deps( - feature_configuration = feature_configuration, - swift_toolchain = swift_toolchain, - ) merged_providers = _merge_targets_providers( supports_objc_interop = swift_toolchain.supports_objc_interop, - targets = all_deps, + targets = deps + private_deps + get_implicit_deps( + feature_configuration = feature_configuration, + swift_toolchain = swift_toolchain, + ), ) # Flattening this `depset` is necessary because we need to extract the @@ -1640,12 +1654,42 @@ def compile( feature_configuration = feature_configuration, outputs = all_compile_outputs, prerequisites = prerequisites, - progress_message = ( - "Compiling Swift module {}".format(module_name) - ), + progress_message = "Compiling Swift module {}".format(module_name), swift_toolchain = swift_toolchain, ) + # If a header and module map were generated for this Swift module, attempt + # to precompile the explicit module for that header as well. + if not is_feature_enabled( + feature_configuration = feature_configuration, + feature_name = SWIFT_FEATURE_NO_GENERATED_HEADER, + ) and not is_feature_enabled( + feature_configuration = feature_configuration, + feature_name = SWIFT_FEATURE_NO_GENERATED_MODULE_MAP, + ): + precompiled_module = precompile_clang_module( + actions = actions, + bin_dir = bin_dir, + cc_compilation_context = cc_common.create_compilation_context( + headers = depset([compile_outputs.generated_header_file]), + ), + feature_configuration = feature_configuration, + genfiles_dir = genfiles_dir, + module_map_file = compile_outputs.generated_module_map_file, + module_name = module_name, + swift_info = create_swift_info( + swift_infos = [ + dep[SwiftInfo] + for dep in generated_module_deps + if SwiftInfo in dep + ], + ), + swift_toolchain = swift_toolchain, + target_name = target_name, + ) + else: + precompiled_module = None + # As part of the full compilation flow, register additional post-compile # actions that toolchains may conditionally support for their target # platform, like module-wrap or autolink-extract. @@ -1668,6 +1712,7 @@ def compile( compile_outputs.object_files + post_compile_results.additional_object_files ), + precompiled_module = precompiled_module, stats_directory = compile_outputs.stats_directory, swiftdoc = compile_outputs.swiftdoc_file, swiftinterface = compile_outputs.swiftinterface_file, @@ -1796,9 +1841,11 @@ def get_implicit_deps(feature_configuration, swift_toolchain): return deps def _declare_compile_outputs( + *, actions, - generated_header_name, feature_configuration, + generated_header_name, + generated_module_deps, module_name, srcs, target_name, @@ -1807,10 +1854,12 @@ def _declare_compile_outputs( Args: actions: The object used to register actions. - generated_header_name: The desired name of the generated header for this - module, or `None` to use `${target_name}-Swift.h`. feature_configuration: A feature configuration obtained from `swift_common.configure_features`. + generated_header_name: The desired name of the generated header for this + module, or `None` to use `${target_name}-Swift.h`. + generated_module_deps: Dependencies of the module for the generated + header of the target being compiled. module_name: The name of the Swift module being compiled. srcs: The list of source files that will be compiled. target_name: The name (excluding package path) of the target being @@ -1896,12 +1945,24 @@ def _declare_compile_outputs( feature_configuration = feature_configuration, feature_name = SWIFT_FEATURE_NO_GENERATED_MODULE_MAP, ): + # Collect the names of Clang modules that the module being built + # directly depends on. + dependent_module_names = sets.make() + for dep in generated_module_deps: + if SwiftInfo in dep: + for module in dep[SwiftInfo].direct_modules: + if module.clang: + sets.insert(dependent_module_names, module.name) + generated_module_map = derived_files.module_map( actions = actions, target_name = target_name, ) write_module_map( actions = actions, + dependent_module_names = sorted( + sets.to_list(dependent_module_names), + ), module_map_file = generated_module_map, module_name = module_name, public_headers = [generated_header], diff --git a/swift/internal/providers.bzl b/swift/internal/providers.bzl index bf3e14586..b6405013b 100644 --- a/swift/internal/providers.bzl +++ b/swift/internal/providers.bzl @@ -72,6 +72,13 @@ Swift toolchain depends on. """, "cpu": """\ `String`. The CPU architecture that the toolchain is targeting. +""", + "generated_header_module_implicit_deps": """\ +`List` of `Target`s. Targets whose `SwiftInfo` providers should be treated as +compile-time inputs to actions that precompile the explicit module for the +generated Objective-C header of a Swift module. This is used to provide modular +dependencies for the fixed inclusions (Darwin, Foundation) that are +unconditionally emitted in those files. """, "linker_opts_producer": """\ Skylib `partial`. A partial function that returns the flags that should be diff --git a/swift/internal/swift_library.bzl b/swift/internal/swift_library.bzl index 050c8baa9..ee8feaea8 100644 --- a/swift/internal/swift_library.bzl +++ b/swift/internal/swift_library.bzl @@ -153,27 +153,26 @@ def _swift_library_impl(ctx): bin_dir = ctx.bin_dir, copts = _maybe_parse_as_library_copts(srcs) + copts, defines = ctx.attr.defines, - deps = deps + private_deps, + deps = deps, feature_configuration = feature_configuration, generated_header_name = ctx.attr.generated_header_name, genfiles_dir = ctx.genfiles_dir, module_name = module_name, + private_deps = private_deps, srcs = srcs, swift_toolchain = swift_toolchain, target_name = ctx.label.name, ) - # If a module map was created for the generated header, propagate it as a - # Clang module so that it is passed as a module input to upstream - # compilation actions. + # If a module was created for the generated header, propagate it as well so + # that it is passed as a module input to upstream compilation actions. if compilation_outputs.generated_module_map: clang_module = swift_common.create_clang_module( compilation_context = cc_common.create_compilation_context( headers = depset([compilation_outputs.generated_header]), ), module_map = compilation_outputs.generated_module_map, - # TODO(b/142867898): Precompile the module and place it here. - precompiled_module = None, + precompiled_module = compilation_outputs.precompiled_module, ) else: clang_module = None @@ -197,6 +196,7 @@ def _swift_library_impl(ctx): direct_output_files = compact([ compilation_outputs.generated_header, + compilation_outputs.precompiled_module, compilation_outputs.swiftdoc, compilation_outputs.swiftinterface, compilation_outputs.swiftmodule, diff --git a/swift/internal/swift_toolchain.bzl b/swift/internal/swift_toolchain.bzl index a7749312b..581b46824 100644 --- a/swift/internal/swift_toolchain.bzl +++ b/swift/internal/swift_toolchain.bzl @@ -216,6 +216,7 @@ def _swift_toolchain_impl(ctx): all_files = depset(all_files), cc_toolchain_info = cc_toolchain, cpu = ctx.attr.arch, + generated_header_module_implicit_deps = [], linker_opts_producer = linker_opts_producer, linker_supports_filelist = False, object_format = "elf", diff --git a/swift/internal/xcode_swift_toolchain.bzl b/swift/internal/xcode_swift_toolchain.bzl index 8be6f4685..8f644b760 100644 --- a/swift/internal/xcode_swift_toolchain.bzl +++ b/swift/internal/xcode_swift_toolchain.bzl @@ -781,6 +781,9 @@ def _xcode_swift_toolchain_impl(ctx): all_files = depset(all_files), cc_toolchain_info = cc_toolchain, cpu = cpu, + generated_header_module_implicit_deps = ( + ctx.attr.generated_header_module_implicit_deps + ), linker_opts_producer = linker_opts_producer, linker_supports_filelist = True, object_format = "macho", @@ -805,6 +808,14 @@ xcode_swift_toolchain = rule( attrs = dicts.add( swift_toolchain_driver_attrs(), { + "generated_header_module_implicit_deps": attr.label_list( + doc = """\ +Targets whose `SwiftInfo` providers should be treated as compile-time inputs to +actions that precompile the explicit module for the generated Objective-C header +of a Swift module. +""", + providers = [[SwiftInfo]], + ), "optional_implicit_deps": attr.label_list( allow_files = True, doc = """\ From ff330612baa088ef93ddf3b40b20a084149578c4 Mon Sep 17 00:00:00 2001 From: Brentley Jones Date: Thu, 25 Feb 2021 07:30:24 -0600 Subject: [PATCH 080/152] Pass framework search paths directly to clang for pcms This is needed since swiftc doesn't pass the framework search paths to clang, causing issues with framework style imports in headers. --- swift/internal/compiling.bzl | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index b95dba870..30882a335 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -611,6 +611,14 @@ def compile_action_configs( configurators = [_framework_search_paths_configurator], ), ) + action_configs.append( + swift_toolchain_config.action_config( + actions = [ + swift_action_names.PRECOMPILE_C_MODULE, + ], + configurators = [_pcm_additional_framework_search_paths_configurator], + ), + ) #### Other ClangImporter flags action_configs.extend([ @@ -1190,6 +1198,18 @@ def _framework_search_paths_configurator(prerequisites, args): format_each = "-F%s", ) +def _pcm_additional_framework_search_paths_configurator(prerequisites, args): + """Add search paths for prebuilt frameworks to the command line for pcms. + + This is needed since swiftc doesn't pass the framework search paths to + clang, causing issues with framework style imports in headers. + """ + args.add_all( + prerequisites.cc_info.compilation_context.framework_includes, + before_each = "-Xcc", + format_each = "-F%s", + ) + def _static_frameworks_disable_autolink_configurator(prerequisites, args): """Add flags to disable auto-linking for static prebuilt frameworks. From 22a2472c0272a5f57e895ffcdec0617317253d64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thi=20Do=C3=A3n?= Date: Fri, 26 Feb 2021 10:32:07 +0900 Subject: [PATCH 081/152] Pass `-no-clang-module-breadcrumbs` to frontend jobs (#574) By default, absolute paths to the dependent pcm files are embedded into the debug info, which was used as a fallback path for LLDB to reconstruct Clang types from DWARF, when it wasn't able to import a dependent Clang module from source. Since those paths aren't shareable across machines, disabling this behavior makes the compilation outputs more reproducible. --- swift/internal/compiling.bzl | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index 30882a335..c00318742 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -151,6 +151,17 @@ def compile_action_configs( ], ), + # Don't embed Clang module breadcrumbs in debug info. + swift_toolchain_config.action_config( + actions = [swift_action_names.COMPILE], + configurators = [ + swift_toolchain_config.add_arg( + "-Xfrontend", + "-no-clang-module-breadcrumbs", + ), + ], + ), + # Add the output precompiled module file path to the command line. swift_toolchain_config.action_config( actions = [swift_action_names.PRECOMPILE_C_MODULE], From 5fc096ea28d7ca36705c47d6391f0bf125422628 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Fri, 12 Mar 2021 09:39:48 -0800 Subject: [PATCH 082/152] Add remotely debuggable Swift document (#576) --- README.md | 5 ++ doc/debuggable_remote_swift.md | 112 +++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 doc/debuggable_remote_swift.md diff --git a/README.md b/README.md index 4baf51954..c697a7e23 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,11 @@ bazel run @build_bazel_rules_swift//tools/dump_toolchains **Linux hosts:** At this time, Bazel uses whichever `swift` executable is encountered first on your `PATH`. +## Supporting remote builds + +To make remote builds work correctly with debugging and general +reproducibility see [this doc](doc/debuggable_remote_swift.md) + ## Future Work - Support for building and linking to shared libraries (`.dylib`/`.so`) written diff --git a/doc/debuggable_remote_swift.md b/doc/debuggable_remote_swift.md new file mode 100644 index 000000000..24e6d4ccb --- /dev/null +++ b/doc/debuggable_remote_swift.md @@ -0,0 +1,112 @@ +# Debuggable Remotely Built Swift + +This is a guide to using remotely built Swift modules in local debug builds. + +At the time of writing, `lldb` depends on debugging options embedded in `.swiftmodule` files. These options include paths that are only valid on the build host. For local builds, this all just works, but for remote builds, it doesn't. + +The solution is two parts: + +1. Use `-no-serialize-debugging-options` globally, to prevent embedded paths +2. Use `-serialize-debugging-options` locally in one empty module + +Globally disabling debugging options makes those `.swiftmodule`s usable on any machine. Locally enabling debugging options for one module provides lldb with enough info to make debugging work. + +An lldb bug has been filed here: https://bugs.swift.org/browse/SR-11485 + +### Disable Debugging Options Globally + +To globally disable debugging options, use the `swift.cacheable_swiftmodules` feature in rules_swift. For example, your `.bazelrc` could look like this: + +``` +build --features=swift.cacheable_swiftmodules +``` + +What this does is ensure all modules are built explicitly with `-no-serialize-debugging-options`. It has to be explicit because `swiftc` enables `-serialize-debugging-options` in some cases. + +### Add Debug Build Config + +In a `BUILD` file - in this example, the root `BUILD` file, define the following [`config_setting`](https://docs.bazel.build/versions/master/be/general.html#config_setting). This will allow targets to conditionally depend on the locally built debugging module. + +```python +config_setting( + name = "debug", + values = { + "compilation_mode": "dbg", + }, +) +``` + +### Define Local Debug Target + +In the `BUILD` file of your choice, define a `swift_library` with: + +* A single empty source file +* Enables `-serialize-debugging-options` +* Built locally, not remote - using the `no-remote` tag + +Here is one way to define the `BUILD` file, using a [`genrule`](https://docs.bazel.build/versions/master/be/general.html#genrule) to create the empty swift file. + +```python +genrule( + name = "empty", + outs = ["empty.swift"], + cmd = "touch $(OUTS)", +) + +swift_library( + name = "_LocalDebugOptions", + srcs = [":empty"], + copts = [ + "-Xfrontend", + "-serialize-debugging-options", + ], + module_name = "_LocalDebugOptions", + tags = ["no-remote"], + visibility = ["//visibility:public"], +) +``` + +### Update Top Level Test Targets + +Finally, for each top-level test target (`ios_unit_test`, `ios_ui_test`*, etc), conditionally add the local debugging module to the deps. This is done via the [debug config](#add-debug-build-config). In the past this also had to be done for `ios_application` targets but that has since been fixed in lldb. + +```python +debug_deps = select({ + "//:debug": ["//some/path:_LocalDebugOptions"], + "//conditions:default": [], +}) + +ios_unit_test( + name = "...", + deps = debug_deps + [ + # ... + ], + # ... +) +``` + +##### Note about `ios_unit_test` + +When using a test host, the debugging module must be added to the test host target only, not the unit test target. _However_, for tests without a test host, the debugging module must be added to the unit test target. + +### LLDB Settings + +Additional settings may be required, depending on your build setup. For example, an Xcode Run Script may look like: + +``` +echo "settings set target.sdk-path $SDKROOT" +echo "settings set target.swift-framework-search-paths $FRAMEWORK_SEARCH_PATHS" +``` + +Other settings you can try customizing are: + +* `target.clang-module-search-paths` +* `target.debug-file-search-paths` +* `target.sdk-path` +* `target.swift-extra-clang-flags` +* `target.swift-framework-search-paths` +* `target.swift-module-search-paths` +* `target.use-all-compiler-flags` +* `symbols.clang-modules-cache-path` + +These settings would be written to some project specific lldbinit file which you can include directly in Xcode's scheme. From 6ebb0f0f8849775d2164e7e9e821975fc46428b2 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Fri, 12 Mar 2021 10:11:38 -0800 Subject: [PATCH 083/152] Update apple_support (#577) --- swift/repositories.bzl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/swift/repositories.bzl b/swift/repositories.bzl index 4bef54bae..3bb3250a9 100644 --- a/swift/repositories.bzl +++ b/swift/repositories.bzl @@ -51,9 +51,9 @@ def swift_rules_dependencies(): http_archive, name = "build_bazel_apple_support", urls = [ - "https://github.com/bazelbuild/apple_support/releases/download/0.9.1/apple_support.0.9.1.tar.gz", + "https://github.com/bazelbuild/apple_support/releases/download/0.9.2/apple_support.0.9.2.tar.gz", ], - sha256 = "02ac04ff0a0de1e891a1fa8839cc6a5957e3c4a80856545aa35a786d15aad108", + sha256 = "a1926bbc5bbb86d596ee1e9c307e22c9a0305053e46057cf186d015b09b3c5f2", ) _maybe( From 0e84c1e2b78779d541e2af169cbfe78e8c720e38 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Fri, 12 Mar 2021 13:33:26 -0800 Subject: [PATCH 084/152] Update README for new URL (#578) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c697a7e23..154d27c88 100644 --- a/README.md +++ b/README.md @@ -51,8 +51,8 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "build_bazel_rules_swift", - sha256 = "d0e5f888b2ccce42c92e6d4686b5507b4230462627f965f9d39862e11ae9fb35", - url = "https://github.com/bazelbuild/rules_swift/releases/download/0.18.0/rules_swift.0.18.0.tar.gz", + sha256 = "be80375680b2553a8b318ffd02ce916a7e1d9060ccad3e7c50f543caafb86fed", + url = "https://github.com/bazelbuild/rules_swift/releases/download/0.19.0/rules_swift.0.19.0.tar.gz", ) load( From 2a20daa7ce087195b3fe0dbde78f7c5209526946 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Omar=20Z=C3=BA=C3=B1iga?= Date: Mon, 15 Mar 2021 19:16:45 -0600 Subject: [PATCH 085/152] Support "Make" variable expansion in `copts` and `linkopts` Resolves https://github.com/bazelbuild/rules_swift/issues/314. --- doc/rules.md | 45 ++++++++++++++++---------------- swift/internal/attrs.bzl | 4 +-- swift/internal/swift_library.bzl | 3 +++ swift/internal/utils.bzl | 17 ++++++++++++ 4 files changed, 45 insertions(+), 24 deletions(-) diff --git a/doc/rules.md b/doc/rules.md index 4ad65f182..91a374d24 100644 --- a/doc/rules.md +++ b/doc/rules.md @@ -63,7 +63,7 @@ please use one of the platform-specific application rules in deps -

List of labels; optional

A list of targets that are dependencies of the target being built, which will be +

List of labels; optional

A list of targets that are dependencies of the target being built, which will be linked into that target.

If the Swift toolchain supports implementation-only imports (private_deps on swift_library), then targets in deps are treated as regular @@ -83,12 +83,12 @@ Linux), those dependencies will be ignored.

srcs -

List of labels; optional

A list of .swift source files that will be compiled into the library.

+

List of labels; optional

A list of .swift source files that will be compiled into the library.

data -

List of labels; optional

The list of files needed by this target at runtime.

+

List of labels; optional

The list of files needed by this target at runtime.

Files and targets named in the data attribute will appear in the *.runfiles area of this target, if it has one. This may include data files needed by a binary or library, or other programs needed by it.

@@ -152,7 +152,7 @@ good build result caching. swiftc_inputs -

List of labels; optional

Additional files that are referenced using $(location ...) in attributes that +

List of labels; optional

Additional files that are referenced using $(location ...) in attributes that support location expansion.

@@ -214,7 +214,7 @@ any C++ declarations. deps -

List of labels; required

A list of C targets (or anything propagating CcInfo) that are dependencies of +

List of labels; required

A list of C targets (or anything propagating CcInfo) that are dependencies of this target and whose headers may be referenced by the module map.

@@ -330,14 +330,14 @@ swift_grpc_library( deps -

List of labels; optional

Exactly one swift_proto_library or swift_grpc_library target that contains +

List of labels; optional

Exactly one swift_proto_library or swift_grpc_library target that contains the Swift protos used by the services being generated. Test stubs should depend on the swift_grpc_library implementing the service.

srcs -

List of labels; optional

Exactly one proto_library target that defines the services being generated.

+

List of labels; optional

Exactly one proto_library target that defines the services being generated.

flavor @@ -381,7 +381,7 @@ Allows for the use of precompiled Swift modules as dependencies in other deps -

List of labels; optional

A list of targets that are dependencies of the target being built, which will be +

List of labels; optional

A list of targets that are dependencies of the target being built, which will be linked into that target.

If the Swift toolchain supports implementation-only imports (private_deps on swift_library), then targets in deps are treated as regular @@ -401,7 +401,7 @@ Linux), those dependencies will be ignored.

data -

List of labels; optional

The list of files needed by this target at runtime.

+

List of labels; optional

The list of files needed by this target at runtime.

Files and targets named in the data attribute will appear in the *.runfiles area of this target, if it has one. This may include data files needed by a binary or library, or other programs needed by it.

@@ -409,7 +409,7 @@ binary or library, or other programs needed by it.

archives -

List of labels; required

The list of .a files provided to Swift targets that depend on this target.

+

List of labels; required

The list of .a files provided to Swift targets that depend on this target.

module_name @@ -458,7 +458,7 @@ Compiles and links Swift code into a static library and Swift module. deps -

List of labels; optional

A list of targets that are dependencies of the target being built, which will be +

List of labels; optional

A list of targets that are dependencies of the target being built, which will be linked into that target.

If the Swift toolchain supports implementation-only imports (private_deps on swift_library), then targets in deps are treated as regular @@ -478,12 +478,12 @@ Linux), those dependencies will be ignored.

srcs -

List of labels; optional

A list of .swift source files that will be compiled into the library.

+

List of labels; optional

A list of .swift source files that will be compiled into the library.

data -

List of labels; optional

The list of files needed by this target at runtime.

+

List of labels; optional

The list of files needed by this target at runtime.

Files and targets named in the data attribute will appear in the *.runfiles area of this target, if it has one. This may include data files needed by a binary or library, or other programs needed by it.

@@ -503,7 +503,7 @@ conformance.

copts

List of strings; optional

Additional compiler options that should be passed to swiftc. These strings are -subject to $(location ...) expansion.

+subject to $(location ...) and "Make" variable expansion.

defines @@ -533,6 +533,7 @@ or if the target has the swift.no_generated_header feature enabled.

List of strings; optional

Additional linker options that should be passed to the linker for the binary that depends on this target. These strings are subject to $(location ...) +and "Make" variable expansion.

expansion.

@@ -546,7 +547,7 @@ non-identifier characters with underscores.

private_deps -

List of labels; optional

A list of targets that are implementation-only dependencies of the target being +

List of labels; optional

A list of targets that are implementation-only dependencies of the target being built. Libraries/linker flags from these dependencies will be propagated to dependent for linking, but artifacts/flags required for compilation (such as .swiftmodule files, C headers, and search paths) will not be propagated.

@@ -564,7 +565,7 @@ Linux), those dependencies will be ignored.

swiftc_inputs -

List of labels; optional

Additional files that are referenced using $(location ...) in attributes that +

List of labels; optional

Additional files that are referenced using $(location ...) in attributes that support location expansion.

@@ -614,7 +615,7 @@ symbol is defined; it is not repeated by the alias module.) deps -

List of labels; optional

A list of targets that are dependencies of the target being built, which will be +

List of labels; optional

A list of targets that are dependencies of the target being built, which will be linked into that target. Allowed kinds are swift_import and swift_library (or anything else propagating SwiftInfo).

@@ -730,7 +731,7 @@ prevents unused modules from being loaded by `swiftc`. deps -

List of labels; optional

Exactly one proto_library target (or any target that propagates a proto +

List of labels; optional

Exactly one proto_library target (or any target that propagates a proto provider) from which the Swift library should be generated.

@@ -795,7 +796,7 @@ to your BUILD file's `package()` declaration instead of the individual targets. deps -

List of labels; optional

A list of targets that are dependencies of the target being built, which will be +

List of labels; optional

A list of targets that are dependencies of the target being built, which will be linked into that target.

If the Swift toolchain supports implementation-only imports (private_deps on swift_library), then targets in deps are treated as regular @@ -815,12 +816,12 @@ Linux), those dependencies will be ignored.

srcs -

List of labels; optional

A list of .swift source files that will be compiled into the library.

+

List of labels; optional

A list of .swift source files that will be compiled into the library.

data -

List of labels; optional

The list of files needed by this target at runtime.

+

List of labels; optional

The list of files needed by this target at runtime.

Files and targets named in the data attribute will appear in the *.runfiles area of this target, if it has one. This may include data files needed by a binary or library, or other programs needed by it.

@@ -884,7 +885,7 @@ good build result caching. swiftc_inputs -

List of labels; optional

Additional files that are referenced using $(location ...) in attributes that +

List of labels; optional

Additional files that are referenced using $(location ...) in attributes that support location expansion.

diff --git a/swift/internal/attrs.bzl b/swift/internal/attrs.bzl index e4a72886b..f9f91b307 100644 --- a/swift/internal/attrs.bzl +++ b/swift/internal/attrs.bzl @@ -104,7 +104,7 @@ A list of `.swift` source files that will be compiled into the library. "copts": attr.string_list( doc = """\ Additional compiler options that should be passed to `swiftc`. These strings are -subject to `$(location ...)` expansion. +subject to `$(location ...)` and "Make" variable expansion. """, ), "defines": attr.string_list( @@ -248,7 +248,7 @@ def swift_library_rule_attrs( doc = """\ Additional linker options that should be passed to the linker for the binary that depends on this target. These strings are subject to `$(location ...)` -expansion. +and "Make" variable expansion. """, ), "alwayslink": attr.bool( diff --git a/swift/internal/swift_library.bzl b/swift/internal/swift_library.bzl index ee8feaea8..1f1af4f98 100644 --- a/swift/internal/swift_library.bzl +++ b/swift/internal/swift_library.bzl @@ -35,6 +35,7 @@ load( "compact", "create_cc_info", "expand_locations", + "expand_make_variables", "get_providers", ) load("@bazel_skylib//lib:dicts.bzl", "dicts") @@ -100,7 +101,9 @@ def _swift_library_impl(ctx): # These can't use additional_inputs since expand_locations needs targets, # not files. copts = expand_locations(ctx, ctx.attr.copts, ctx.attr.swiftc_inputs) + copts = expand_make_variables(ctx, copts, "copts") linkopts = expand_locations(ctx, ctx.attr.linkopts, ctx.attr.swiftc_inputs) + linkopts = expand_make_variables(ctx, linkopts, "linkopts") srcs = ctx.files.srcs extra_features = [] diff --git a/swift/internal/utils.bzl b/swift/internal/utils.bzl index 4c248ab85..5da237b2f 100644 --- a/swift/internal/utils.bzl +++ b/swift/internal/utils.bzl @@ -142,6 +142,23 @@ def expand_locations(ctx, values, targets = []): """ return [ctx.expand_location(value, targets) for value in values] +def expand_make_variables(ctx, values, attribute_name): + """Expands all references to Make variables in each of the given values. + + Args: + ctx: The rule context. + values: A list of strings, which may contain Make variable placeholders. + attribute_name: The attribute name string that will be presented in + console when an error occurs. + + Returns: + A list of strings with Make variables placeholders filled in. + """ + return [ + ctx.expand_make_variables(attribute_name, value, {}) + for value in values + ] + def get_swift_executable_for_toolchain(ctx): """Returns the Swift driver executable that the toolchain should use. From d8d688c719c7cda1cb1e24cb825762bea67cda3c Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Fri, 12 Mar 2021 11:23:55 -0800 Subject: [PATCH 086/152] Add a `generates_header` attribute to `swift_library` to control Objective-C header generation. Today, `swift_library` unconditionally generates a header and module map for all targets (unless rarely-used features are applied), even if the library has no APIs exported to Objective-C. This creates a small amount of unnecessary work, but that work grows significantly when explicit modules are used in the build, because we also need to compile the explicit modules for those generated headers _just in case_ some `objc_library` further up in the build graph needs to import the header. This is the first of a few changes that will eventually require the `generates_header` attribute to be set on targets to have the generated header emitted and propagated. This change also removes the `swift.no_generated_header` feature, since the attribute's behavior supplants it. PiperOrigin-RevId: 362562962 (cherry picked from commit e621e5e644c7f62f44241da253fb40ea14672451) --- swift/internal/attrs.bzl | 23 ++++- swift/internal/compiling.bzl | 40 +++------ swift/internal/derived_files.bzl | 13 --- swift/internal/feature_names.bzl | 9 +- swift/internal/swift_grpc_library.bzl | 3 +- swift/internal/swift_library.bzl | 16 +++- swift/internal/swift_protoc_gen_aspect.bzl | 5 +- swift/internal/swift_toolchain.bzl | 6 +- test/fixtures/generated_header/BUILD | 19 ++++ test/fixtures/private_deps/BUILD | 15 ++-- test/generated_header_tests.bzl | 100 ++++++--------------- 11 files changed, 107 insertions(+), 142 deletions(-) diff --git a/swift/internal/attrs.bzl b/swift/internal/attrs.bzl index f9f91b307..bcc6099b0 100644 --- a/swift/internal/attrs.bzl +++ b/swift/internal/attrs.bzl @@ -271,8 +271,27 @@ a `.h` extension and cannot contain any path separators. If this attribute is not specified, then the default behavior is to name the header `${target_name}-Swift.h`. -This attribute is ignored if the toolchain does not support generating headers -or if the target has the `swift.no_generated_header` feature enabled. +It is an error to specify a value for this attribute when `generates_header` is +False. +""", + mandatory = False, + ), + "generates_header": attr.bool( + # TODO(b/182493307): Make the default False after migrating all + # targets to explicitly specify it when needed. + default = True, + doc = """\ +If True, an Objective-C header will be generated for this target, in the same +build package where the target is defined. By default, the name of the header is +`${target_name}-Swift.h`; this can be changed using the `generated_header_name` +attribute. + +Targets should only set this attribute to True if they export Objective-C APIs. +A header generated for a target that does not export Objective-C APIs will be +effectively empty (except for a large amount of prologue and epilogue code) and +this is generally wasteful because the extra file needs to be propagated in the +build graph and, when explicit modules are enabled, extra actions must be +executed to compile the Objective-C module for the generated header. """, mandatory = False, ), diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index c00318742..53c450cb8 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -49,7 +49,6 @@ load( "SWIFT_FEATURE_MINIMAL_DEPS", "SWIFT_FEATURE_MODULE_MAP_HOME_IS_CWD", "SWIFT_FEATURE_NO_EMBED_DEBUG_MODULE", - "SWIFT_FEATURE_NO_GENERATED_HEADER", "SWIFT_FEATURE_NO_GENERATED_MODULE_MAP", "SWIFT_FEATURE_OPT", "SWIFT_FEATURE_OPT_USES_OSIZE", @@ -210,14 +209,12 @@ def compile_action_configs( actions = [swift_action_names.COMPILE], configurators = [_emit_objc_header_path_configurator], not_features = [ - [SWIFT_FEATURE_NO_GENERATED_HEADER], - [SWIFT_FEATURE_SPLIT_DERIVED_FILES_GENERATION], + SWIFT_FEATURE_SPLIT_DERIVED_FILES_GENERATION, ], ), swift_toolchain_config.action_config( actions = [swift_action_names.DERIVE_FILES], configurators = [_emit_objc_header_path_configurator], - not_features = [SWIFT_FEATURE_NO_GENERATED_HEADER], ), # Configure the location where compiler performance statistics are @@ -928,7 +925,8 @@ def _emit_module_interface_path_configurator(prerequisites, args): def _emit_objc_header_path_configurator(prerequisites, args): """Adds the generated header output path to the command line.""" - args.add("-emit-objc-header-path", prerequisites.generated_header_file) + if prerequisites.generated_header_file: + args.add("-emit-objc-header-path", prerequisites.generated_header_file) def _global_module_cache_configurator(prerequisites, args): """Adds flags to enable the global module cache.""" @@ -1491,8 +1489,8 @@ def compile( targets must propagate one of the following providers: `CcInfo`, `SwiftInfo`, or `apple_common.Objc`. generated_header_name: The name of the Objective-C generated header that - should be generated for this module. If omitted, the name - `${target_name}-Swift.h` will be used. + should be generated for this module. If omitted, no header will be + generated. genfiles_dir: The Bazel `*-genfiles` directory root. If provided, its path is added to ClangImporter's header search paths for compatibility with Bazel's C++ and Objective-C rules which support @@ -1691,10 +1689,7 @@ def compile( # If a header and module map were generated for this Swift module, attempt # to precompile the explicit module for that header as well. - if not is_feature_enabled( - feature_configuration = feature_configuration, - feature_name = SWIFT_FEATURE_NO_GENERATED_HEADER, - ) and not is_feature_enabled( + if generated_header_name and not is_feature_enabled( feature_configuration = feature_configuration, feature_name = SWIFT_FEATURE_NO_GENERATED_MODULE_MAP, ): @@ -1888,7 +1883,7 @@ def _declare_compile_outputs( feature_configuration: A feature configuration obtained from `swift_common.configure_features`. generated_header_name: The desired name of the generated header for this - module, or `None` to use `${target_name}-Swift.h`. + module, or `None` if no header should be generated. generated_module_deps: Dependencies of the module for the generated header of the target being compiled. module_name: The name of the Swift module being compiled. @@ -1945,22 +1940,13 @@ def _declare_compile_outputs( else: stats_directory = None - # If supported, generate the Swift header for this library so that it can be + # If requested, generate the Swift header for this library so that it can be # included by Objective-C code that depends on it. - if not is_feature_enabled( - feature_configuration = feature_configuration, - feature_name = SWIFT_FEATURE_NO_GENERATED_HEADER, - ): - if generated_header_name: - generated_header = _declare_validated_generated_header( - actions = actions, - generated_header_name = generated_header_name, - ) - else: - generated_header = derived_files.default_generated_header( - actions = actions, - target_name = target_name, - ) + if generated_header_name: + generated_header = _declare_validated_generated_header( + actions = actions, + generated_header_name = generated_header_name, + ) else: generated_header = None diff --git a/swift/internal/derived_files.bzl b/swift/internal/derived_files.bzl index c86e89251..c979fafce 100644 --- a/swift/internal/derived_files.bzl +++ b/swift/internal/derived_files.bzl @@ -29,18 +29,6 @@ def _autolink_flags(actions, target_name): """ return actions.declare_file("{}.autolink".format(target_name)) -def _default_generated_header(actions, target_name): - """Declares the automatically-named generated header for a Swift target. - - Args: - actions: The context's actions object. - target_name: The name of the target being built. - - Returns: - The declared `File`. - """ - return actions.declare_file("{}-Swift.h".format(target_name)) - def _executable(actions, target_name): """Declares a file for the executable created by a binary or test rule. @@ -320,7 +308,6 @@ def _xctest_runner_script(actions, target_name): derived_files = struct( autolink_flags = _autolink_flags, - default_generated_header = _default_generated_header, executable = _executable, indexstore_directory = _indexstore_directory, intermediate_object_file = _intermediate_object_file, diff --git a/swift/internal/feature_names.bzl b/swift/internal/feature_names.bzl index 7ca468c92..550e1281c 100644 --- a/swift/internal/feature_names.bzl +++ b/swift/internal/feature_names.bzl @@ -126,14 +126,9 @@ SWIFT_FEATURE_MODULE_MAP_NO_PRIVATE_HEADERS = ( "swift.module_map_no_private_headers" ) -# If enabled, the compilation action for a library target will not generate an -# Objective-C header for the module. This feature also implies -# `swift.no_generated_module_map`. -SWIFT_FEATURE_NO_GENERATED_HEADER = "swift.no_generated_header" - # If enabled, the compilation action for a library target will not generate a -# module map for the Objective-C generated header. Note that this feature -# is ignored if `swift.no_generated_header` is present. +# module map for the Objective-C generated header. This feature is ignored if +# the target is not generating a header. SWIFT_FEATURE_NO_GENERATED_MODULE_MAP = "swift.no_generated_module_map" # If enabled, builds using the "opt" compilation mode will invoke `swiftc` with diff --git a/swift/internal/swift_grpc_library.bzl b/swift/internal/swift_grpc_library.bzl index a42f87f60..781600600 100644 --- a/swift/internal/swift_grpc_library.bzl +++ b/swift/internal/swift_grpc_library.bzl @@ -25,7 +25,6 @@ load( ":feature_names.bzl", "SWIFT_FEATURE_ENABLE_TESTING", "SWIFT_FEATURE_GENERATE_FROM_RAW_PROTO_FILES", - "SWIFT_FEATURE_NO_GENERATED_HEADER", ) load(":linking.bzl", "create_linker_input") load( @@ -214,7 +213,7 @@ def _swift_grpc_library_impl(ctx): feature_configuration = swift_common.configure_features( ctx = ctx, - requested_features = ctx.features + [SWIFT_FEATURE_NO_GENERATED_HEADER], + requested_features = ctx.features, swift_toolchain = swift_toolchain, unsupported_features = unsupported_features, ) diff --git a/swift/internal/swift_library.bzl b/swift/internal/swift_library.bzl index 1f1af4f98..d6f463710 100644 --- a/swift/internal/swift_library.bzl +++ b/swift/internal/swift_library.bzl @@ -150,6 +150,20 @@ def _swift_library_impl(ctx): deps = ctx.attr.deps private_deps = [] + if ctx.attr.generates_header: + generated_header_name = ( + ctx.attr.generated_header_name or + "{}-Swift.h".format(ctx.label.name) + ) + elif not ctx.attr.generated_header_name: + generated_header_name = None + else: + fail( + "'generated_header_name' may only be provided when " + + "'generates_header' is True.", + attr = "generated_header_name", + ) + compilation_outputs = swift_common.compile( actions = ctx.actions, additional_inputs = additional_inputs, @@ -158,7 +172,7 @@ def _swift_library_impl(ctx): defines = ctx.attr.defines, deps = deps, feature_configuration = feature_configuration, - generated_header_name = ctx.attr.generated_header_name, + generated_header_name = generated_header_name, genfiles_dir = ctx.genfiles_dir, module_name = module_name, private_deps = private_deps, diff --git a/swift/internal/swift_protoc_gen_aspect.bzl b/swift/internal/swift_protoc_gen_aspect.bzl index 3f7536e42..fd161fb47 100644 --- a/swift/internal/swift_protoc_gen_aspect.bzl +++ b/swift/internal/swift_protoc_gen_aspect.bzl @@ -25,7 +25,6 @@ load( "SWIFT_FEATURE_ENABLE_LIBRARY_EVOLUTION", "SWIFT_FEATURE_ENABLE_TESTING", "SWIFT_FEATURE_GENERATE_FROM_RAW_PROTO_FILES", - "SWIFT_FEATURE_NO_GENERATED_HEADER", ) load(":linking.bzl", "create_linker_input") load( @@ -370,9 +369,7 @@ def _swift_protoc_gen_aspect_impl(target, aspect_ctx): # compile action. feature_configuration = swift_common.configure_features( ctx = aspect_ctx, - requested_features = aspect_ctx.features + extra_features + [ - SWIFT_FEATURE_NO_GENERATED_HEADER, - ], + requested_features = aspect_ctx.features + extra_features, swift_toolchain = swift_toolchain, unsupported_features = aspect_ctx.disabled_features + [ SWIFT_FEATURE_ENABLE_TESTING, diff --git a/swift/internal/swift_toolchain.bzl b/swift/internal/swift_toolchain.bzl index 581b46824..124630c01 100644 --- a/swift/internal/swift_toolchain.bzl +++ b/swift/internal/swift_toolchain.bzl @@ -30,7 +30,6 @@ load(":debugging.bzl", "modulewrap_action_configs") load( ":feature_names.bzl", "SWIFT_FEATURE_MODULE_MAP_HOME_IS_CWD", - "SWIFT_FEATURE_NO_GENERATED_HEADER", "SWIFT_FEATURE_NO_GENERATED_MODULE_MAP", "SWIFT_FEATURE_USE_RESPONSE_FILES", ) @@ -183,10 +182,7 @@ def _swift_toolchain_impl(ctx): features_for_build_modes(ctx) + features_from_swiftcopts(swiftcopts = ctx.fragments.swift.copts()) ) - requested_features.extend([ - SWIFT_FEATURE_NO_GENERATED_HEADER, - SWIFT_FEATURE_NO_GENERATED_MODULE_MAP, - ]) + requested_features.append(SWIFT_FEATURE_NO_GENERATED_MODULE_MAP) requested_features.extend(ctx.features) # Swift.org toolchains assume everything is just available on the PATH so we diff --git a/test/fixtures/generated_header/BUILD b/test/fixtures/generated_header/BUILD index 9e8fdc1b3..a87575213 100644 --- a/test/fixtures/generated_header/BUILD +++ b/test/fixtures/generated_header/BUILD @@ -7,9 +7,17 @@ package( licenses(["notice"]) +swift_library( + name = "no_header", + srcs = ["Empty.swift"], + generates_header = False, + tags = FIXTURE_TAGS, +) + swift_library( name = "auto_header", srcs = ["Empty.swift"], + generates_header = True, tags = FIXTURE_TAGS, ) @@ -17,6 +25,7 @@ swift_library( name = "explicit_header", srcs = ["Empty.swift"], generated_header_name = "SomeOtherName.h", + generates_header = True, tags = FIXTURE_TAGS, ) @@ -24,6 +33,7 @@ swift_library( name = "invalid_extension", srcs = ["Empty.swift"], generated_header_name = "Invalid.extension", + generates_header = True, tags = FIXTURE_TAGS, ) @@ -31,5 +41,14 @@ swift_library( name = "valid_path_separator", srcs = ["Empty.swift"], generated_header_name = "Valid/Separator.h", + generates_header = True, + tags = FIXTURE_TAGS, +) + +swift_library( + name = "invalid_attribute_combination", + srcs = ["Empty.swift"], + generated_header_name = "SomeOtherName.h", + generates_header = False, tags = FIXTURE_TAGS, ) diff --git a/test/fixtures/private_deps/BUILD b/test/fixtures/private_deps/BUILD index b616d30ea..16c4bfb96 100644 --- a/test/fixtures/private_deps/BUILD +++ b/test/fixtures/private_deps/BUILD @@ -14,18 +14,21 @@ licenses(["notice"]) swift_library( name = "private_swift", srcs = ["Empty.swift"], + generates_header = True, tags = FIXTURE_TAGS, ) swift_library( name = "public_swift", srcs = ["Empty.swift"], + generates_header = True, tags = FIXTURE_TAGS, ) swift_library( name = "client_swift_deps", srcs = ["Empty.swift"], + generates_header = True, private_deps = [ ":private_swift", ], @@ -68,13 +71,11 @@ cc_library( swift_library( name = "client_cc_deps", srcs = ["Empty.swift"], - features = [ - # Suppress the generated header/module map on platforms that support - # Objective-C interop so that we don't have to worry about - # conditionally checking for it in the transitive modules on just those - # platforms. - "swift.no_generated_header", - ], + # Suppress the generated header/module map on platforms that support + # Objective-C interop so that we don't have to worry about + # conditionally checking for it in the transitive modules on just those + # platforms. + generates_header = False, private_deps = [ ":private_cc", ], diff --git a/test/generated_header_tests.bzl b/test/generated_header_tests.bzl index cf216d900..8a9903e92 100644 --- a/test/generated_header_tests.bzl +++ b/test/generated_header_tests.bzl @@ -16,44 +16,15 @@ load( "@build_bazel_rules_swift//test/rules:analysis_failure_test.bzl", - "make_analysis_failure_test_rule", + "analysis_failure_test", ) load( "@build_bazel_rules_swift//test/rules:provider_test.bzl", - "make_provider_test_rule", -) - -# A configuration that forces header and module map generation, regardless of -# the toolchain's default feature set. -GENERATE_HEADER_AND_MODULE_MAP_CONFIG_SETTINGS = { - "//command_line_option:features": [ - "-swift.no_generated_header", - "-swift.no_generated_module_map", - ], -} - -# A configuration that disables header (and therefore module map) generation, -# regardless of the toolchain's default feature set. -NO_GENERATE_HEADER_CONFIG_SETTINGS = { - "//command_line_option:features": [ - "swift.no_generated_header", - ], -} - -generate_header_and_module_map_provider_test = make_provider_test_rule( - config_settings = GENERATE_HEADER_AND_MODULE_MAP_CONFIG_SETTINGS, -) - -generate_header_and_module_map_failure_test = make_analysis_failure_test_rule( - config_settings = GENERATE_HEADER_AND_MODULE_MAP_CONFIG_SETTINGS, -) - -no_generate_header_provider_test = make_provider_test_rule( - config_settings = NO_GENERATE_HEADER_CONFIG_SETTINGS, + "provider_test", ) def generated_header_test_suite(name = "generated_header"): - """Test suite for `swift_library.generated_header`. + """Test suite for `swift_library` generated headers. Args: name: The name prefix for all the nested tests @@ -61,7 +32,7 @@ def generated_header_test_suite(name = "generated_header"): # Verify that the generated header by default gets an automatically # generated name and is an output of the rule. - generate_header_and_module_map_provider_test( + provider_test( name = "{}_automatically_named_header_is_rule_output".format(name), expected_files = [ "test/fixtures/generated_header/auto_header-Swift.h", @@ -73,22 +44,23 @@ def generated_header_test_suite(name = "generated_header"): target_under_test = "@build_bazel_rules_swift//test/fixtures/generated_header:auto_header", ) - # Verify that the generated module map is propagated in `apple_common.Objc`. - # TODO(b/148604334): Enable this when it analyzes correctly on all platforms. - # generate_header_and_module_map_provider_test( - # name = "{}_automatically_named_header_modulemap_is_propagated".format(name), - # expected_files = [ - # "test/fixtures/generated_header/auto_header.modulemaps/module.modulemap", - # ], - # field = "direct_module_maps", - # provider = "apple_common.Objc", - # tags = [name], - # target_under_test = "@build_bazel_rules_swift//test/fixtures/generated_header:auto_header", - # ) + # Verify that no generated header is created if the target doesn't request + # it. + provider_test( + name = "{}_no_header".format(name), + expected_files = [ + "-test/fixtures/generated_header/no_header-Swift.h", + "*", + ], + field = "files", + provider = "DefaultInfo", + tags = [name], + target_under_test = "@build_bazel_rules_swift//test/fixtures/generated_header:no_header", + ) # Verify that the explicit generated header is an output of the rule and # that the automatically named one is *not*. - generate_header_and_module_map_provider_test( + provider_test( name = "{}_explicit_header".format(name), expected_files = [ "test/fixtures/generated_header/SomeOtherName.h", @@ -102,7 +74,7 @@ def generated_header_test_suite(name = "generated_header"): ) # Verify that the build fails to analyze if an invalid extension is used. - generate_header_and_module_map_failure_test( + analysis_failure_test( name = "{}_invalid_extension".format(name), expected_message = "The generated header for a Swift module must have a '.h' extension", tags = [name], @@ -110,7 +82,7 @@ def generated_header_test_suite(name = "generated_header"): ) # Verify that the build analyzes if a path separator is used. - generate_header_and_module_map_provider_test( + provider_test( name = "{}_valid_path_separator".format(name), expected_files = [ "test/fixtures/generated_header/Valid/Separator.h", @@ -122,33 +94,13 @@ def generated_header_test_suite(name = "generated_header"): target_under_test = "@build_bazel_rules_swift//test/fixtures/generated_header:valid_path_separator", ) - # Verify that the header is not generated if the feature - # `swift.no_generated_header` set, when using an automatically named header. - no_generate_header_provider_test( - name = "{}_no_header".format(name), - expected_files = [ - "-test/fixtures/generated_header/auto_header-Swift.h", - "*", - ], - field = "files", - provider = "DefaultInfo", - tags = [name], - target_under_test = "@build_bazel_rules_swift//test/fixtures/generated_header:auto_header", - ) - - # Verify that the header is not generated if the feature - # `swift.no_generated_header` set, even when specifying an explicit header - # name. - no_generate_header_provider_test( - name = "{}_no_explicit_header".format(name), - expected_files = [ - "-test/fixtures/generated_header/SomeOtherName.h", - "*", - ], - field = "files", - provider = "DefaultInfo", + # Verify that the build fails if `generated_header_name` is set when + # `generates_header` is False. + analysis_failure_test( + name = "{}_fails_when_name_provided_but_generates_header_is_false".format(name), + expected_message = "'generated_header_name' may only be provided when 'generates_header' is True", tags = [name], - target_under_test = "@build_bazel_rules_swift//test/fixtures/generated_header:explicit_header", + target_under_test = "@build_bazel_rules_swift//test/fixtures/generated_header:invalid_attribute_combination", ) native.test_suite( From f1c30a2e79faf1cf5c7543a882097015a41cec05 Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Fri, 2 Apr 2021 12:47:29 -0700 Subject: [PATCH 087/152] Internal change. PiperOrigin-RevId: 366495458 (cherry picked from commit d27e5a6cd4e1ce6cb0e698a51095be536de7e809) --- tools/common/BUILD | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tools/common/BUILD b/tools/common/BUILD index a627524a9..b5da106c2 100644 --- a/tools/common/BUILD +++ b/tools/common/BUILD @@ -1,9 +1,7 @@ load("@rules_cc//cc:defs.bzl", "cc_library") package( - default_visibility = [ - "//tools/worker:__pkg__", - ], + default_visibility = ["//tools/worker:__pkg__"], ) licenses(["notice"]) From 9cba5ecfef79ed4fe9a5ec512bc17bd0389aec28 Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Wed, 24 Mar 2021 07:29:50 -0700 Subject: [PATCH 088/152] Switch to XcodeVersionConfig.execution_info(). RELNOTES: None PiperOrigin-RevId: 364797902 (cherry picked from commit aeb56dc0b633b0175b2f04a0c4a476eb647302a4) --- swift/internal/xcode_swift_toolchain.bzl | 29 +----------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/swift/internal/xcode_swift_toolchain.bzl b/swift/internal/xcode_swift_toolchain.bzl index 8f644b760..61c37d4f5 100644 --- a/swift/internal/xcode_swift_toolchain.bzl +++ b/swift/internal/xcode_swift_toolchain.bzl @@ -633,31 +633,6 @@ def _xcode_env(xcode_config, platform): apple_common.target_apple_env(xcode_config, platform), ) -def _xcode_execution_requirements(xcode_config): - """Returns execution requirements for actions involving Xcode. - - Args: - xcode_config: The Xcode configuration object. - - Returns: - A dictionary of execution requirements to be passed when registering - actions. - """ - - # All Swift actions should be executed on Darwin, even if Bazel is running - # on a non-Darwin host. - # TODO(steinman): Replace this with xcode_config.execution_info once it is - # available. - execution_requirements = {"requires-darwin": ""} - if xcode_config: - if xcode_config.availability() == "remote": - execution_requirements["no-local"] = "1" - elif xcode_config.availability() == "local": - execution_requirements["no-remote"] = "1" - execution_requirements["supports-xcode-requirements-set"] = "1" - - return execution_requirements - def _xcode_swift_toolchain_impl(ctx): apple_fragment = ctx.fragments.apple apple_toolchain = apple_common.apple_toolchain() @@ -743,9 +718,7 @@ def _xcode_swift_toolchain_impl(ctx): ) + ctx.fragments.swift.copts() env = _xcode_env(platform = platform, xcode_config = xcode_config) - execution_requirements = _xcode_execution_requirements( - xcode_config = xcode_config, - ) + execution_requirements = xcode_config.execution_info() all_tool_configs = _all_tool_configs( custom_toolchain = custom_toolchain, From e7ec73552127d0a8b6efb2eda1e618dc3c902bd0 Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Wed, 17 Mar 2021 07:50:39 -0700 Subject: [PATCH 089/152] Distinguish between direct and transitive information when creating the `CcInfo` for a `swift_library`. This ensures that, for a `swift_library` target `t`, reading from either the direct fields of `t[CcInfo].compilation_context` or `t[SwiftInfo].direct_modules[...].clang.compilation_context` produces consistent results. PiperOrigin-RevId: 363418185 (cherry picked from commit 027e1801cace2034b75fd9732e6fa8670ea252ea) --- swift/internal/utils.bzl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/swift/internal/utils.bzl b/swift/internal/utils.bzl index 5da237b2f..f7d545892 100644 --- a/swift/internal/utils.bzl +++ b/swift/internal/utils.bzl @@ -126,7 +126,10 @@ def create_cc_info( linking_context = full_private_cc_info.linking_context, )) - return cc_common.merge_cc_infos(cc_infos = local_cc_infos + cc_infos) + return cc_common.merge_cc_infos( + cc_infos = cc_infos, + direct_cc_infos = local_cc_infos, + ) def expand_locations(ctx, values, targets = []): """Expands the `$(location)` placeholders in each of the given values. From 03dd9abecb3ef7456a1dc670e233ffa72920eae1 Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Fri, 19 Mar 2021 07:34:37 -0700 Subject: [PATCH 090/152] Delete support for compiler performance stats collection. This wasn't used frequently enough to rationalize being so deeply woven into the build rules. A better approach might be to use an aspect that runs the same actions in parallel but with the necessary stats flags and collects the data files; while this would double the actions executed, it's better code-health wise. But I don't have any plans to do that in the near-term. PiperOrigin-RevId: 363887607 (cherry picked from commit 4234e38ce3b4efc0fb0319c96f9052f07bed6775) --- swift/BUILD | 6 - swift/internal/compiling.bzl | 39 ----- swift/internal/derived_files.bzl | 13 -- swift/internal/feature_names.bzl | 9 -- swift/stats.bzl | 61 -------- tools/compile_stats/BUILD | 6 - tools/compile_stats/README.md | 18 --- tools/compile_stats/build.sh | 62 -------- tools/compile_stats/main.swift | 242 ------------------------------- 9 files changed, 456 deletions(-) delete mode 100644 swift/stats.bzl delete mode 100644 tools/compile_stats/BUILD delete mode 100644 tools/compile_stats/README.md delete mode 100755 tools/compile_stats/build.sh delete mode 100644 tools/compile_stats/main.swift diff --git a/swift/BUILD b/swift/BUILD index dd79c6127..9ac4eaa93 100644 --- a/swift/BUILD +++ b/swift/BUILD @@ -14,12 +14,6 @@ bzl_library( ], ) -bzl_library( - name = "stats", - srcs = ["stats.bzl"], - deps = ["//swift/internal:utils"], -) - bzl_library( name = "swift", srcs = ["swift.bzl"], diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index 53c450cb8..5b521cc49 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -31,7 +31,6 @@ load(":derived_files.bzl", "derived_files") load( ":feature_names.bzl", "SWIFT_FEATURE_CACHEABLE_SWIFTMODULES", - "SWIFT_FEATURE_COMPILE_STATS", "SWIFT_FEATURE_COVERAGE", "SWIFT_FEATURE_COVERAGE_PREFIX_MAP", "SWIFT_FEATURE_DBG", @@ -216,17 +215,6 @@ def compile_action_configs( actions = [swift_action_names.DERIVE_FILES], configurators = [_emit_objc_header_path_configurator], ), - - # Configure the location where compiler performance statistics are - # dumped. - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - ], - configurators = [_stats_output_dir_configurator], - features = [SWIFT_FEATURE_COMPILE_STATS], - ), ] #### Compilation-mode-related flags @@ -1273,10 +1261,6 @@ def _module_name_configurator(prerequisites, args): """Adds the module name flag to the command line.""" args.add("-module-name", prerequisites.module_name) -def _stats_output_dir_configurator(prerequisites, args): - """Adds the compile stats output directory path to the command line.""" - args.add("-stats-output-dir", prerequisites.stats_directory.path) - def _source_files_configurator(prerequisites, args): """Adds source files to the command line and required inputs.""" args.add_all(prerequisites.source_files) @@ -1527,9 +1511,6 @@ def compile( * `precompiled_module`: A `File` representing the explicit module (`.pcm`) of the Clang module for the generated header, or `None` if no explicit module was generated. - * `stats_directory`: A `File` representing the directory that contains - the timing statistics emitted by the compiler. If no stats were - requested, this field will be None. * `swiftdoc`: The `.swiftdoc` file that was produced by the compiler. * `swiftinterface`: The `.swiftinterface` file that was produced by the compiler. If no interface file was produced (because the @@ -1561,7 +1542,6 @@ def compile( all_compile_outputs = compact([ compile_outputs.swiftinterface_file, compile_outputs.indexstore_directory, - compile_outputs.stats_directory, ]) + compile_outputs.object_files all_derived_outputs = compact([ # The `.swiftmodule` file is explicitly listed as the first output @@ -1583,7 +1563,6 @@ def compile( compile_outputs.swiftinterface_file, compile_outputs.generated_header_file, compile_outputs.indexstore_directory, - compile_outputs.stats_directory, ]) + compile_outputs.object_files + other_outputs all_derived_outputs = [] @@ -1739,7 +1718,6 @@ def compile( post_compile_results.additional_object_files ), precompiled_module = precompiled_module, - stats_directory = compile_outputs.stats_directory, swiftdoc = compile_outputs.swiftdoc_file, swiftinterface = compile_outputs.swiftinterface_file, swiftmodule = compile_outputs.swiftmodule_file, @@ -1929,17 +1907,6 @@ def _declare_compile_outputs( else: swiftinterface_file = None - if is_feature_enabled( - feature_configuration = feature_configuration, - feature_name = SWIFT_FEATURE_COMPILE_STATS, - ): - stats_directory = derived_files.stats_directory( - actions = actions, - target_name = target_name, - ) - else: - stats_directory = None - # If requested, generate the Swift header for this library so that it can be # included by Objective-C code that depends on it. if generated_header_name: @@ -2041,7 +2008,6 @@ def _declare_compile_outputs( indexstore_directory = indexstore_directory, object_files = object_files, output_file_map = output_file_map, - stats_directory = stats_directory, swiftdoc_file = swiftdoc_file, swiftinterface_file = swiftinterface_file, swiftmodule_file = swiftmodule_file, @@ -2400,11 +2366,6 @@ def output_groups_from_compilation_outputs(compilation_outputs): compilation_outputs.indexstore, ]) - if compilation_outputs.stats_directory: - output_groups["swift_compile_stats_direct"] = depset([ - compilation_outputs.stats_directory, - ]) - if compilation_outputs.swiftdoc: output_groups["swiftdoc"] = depset([ compilation_outputs.swiftdoc, diff --git a/swift/internal/derived_files.bzl b/swift/internal/derived_files.bzl index c979fafce..fa9ab4f88 100644 --- a/swift/internal/derived_files.bzl +++ b/swift/internal/derived_files.bzl @@ -186,18 +186,6 @@ def _static_archive(actions, alwayslink, link_name): extension = "lo" if alwayslink else "a" return actions.declare_file("lib{}.{}".format(link_name, extension)) -def _stats_directory(actions, target_name): - """Declares a directory that will contain timing statistics for a compile. - - Args: - actions: The context's actions object. - target_name: The name of the target being built. - - Returns: - The declared `File`. - """ - return actions.declare_directory("{}.compile-stats".format(target_name)) - def _swiftc_output_file_map(actions, target_name): """Declares a file for the output file map for a compilation action. @@ -317,7 +305,6 @@ derived_files = struct( precompiled_module = _precompiled_module, reexport_modules_src = _reexport_modules_src, static_archive = _static_archive, - stats_directory = _stats_directory, swiftc_output_file_map = _swiftc_output_file_map, swiftdoc = _swiftdoc, swiftinterface = _swiftinterface, diff --git a/swift/internal/feature_names.bzl b/swift/internal/feature_names.bzl index 550e1281c..20133fe4a 100644 --- a/swift/internal/feature_names.bzl +++ b/swift/internal/feature_names.bzl @@ -47,15 +47,6 @@ SWIFT_FEATURE_COVERAGE = "swift.coverage" # `swift_test` output just a binary. SWIFT_FEATURE_BUNDLED_XCTESTS = "swift.bundled_xctests" -# If enabled, the Swift compiler will emit a directory containing JSON files -# with timing information about the driver/frontend's actions. This directory -# will be emitted as a default output when a Swift target is built directly, and -# it will also be propagated in an output group named -# `swift_compile_stats_direct`. Typically this output group will not be accessed -# directly, but used by the `collect_swift_compile_stats` aspect to gather the -# transitive stats for the entire build. -SWIFT_FEATURE_COMPILE_STATS = "swift.compile_stats" - # If enabled, debug builds will use the `-debug-prefix-map` feature to remap the # current working directory to `.`, which permits debugging remote or sandboxed # builds. diff --git a/swift/stats.bzl b/swift/stats.bzl deleted file mode 100644 index 293b4b9d4..000000000 --- a/swift/stats.bzl +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright 2019 The Bazel Authors. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""An aspect that collects compilation timing statistics.""" - -load( - "@build_bazel_rules_swift//swift/internal:utils.bzl", - "get_output_groups", -) - -def _collect_swift_compile_stats_impl(target, aspect_ctx): - output_groups = target[OutputGroupInfo] - - deps = getattr(aspect_ctx.rule.attr, "deps", []) - merged_stats = get_output_groups(deps, "swift_compile_stats") - direct_stats = getattr(output_groups, "swift_compile_stats_direct", None) - if direct_stats: - merged_stats.append(direct_stats) - - return [OutputGroupInfo( - swift_compile_stats = depset(transitive = merged_stats), - )] - -collect_swift_compile_stats = aspect( - attr_aspects = ["deps"], - doc = """ -Collects compilation statistics reports from the entire build graph. - -This aspect is intended to be used from the command line to profile the Swift -compiler during a build. It needs to be combined with the `swift.compile_stats` -feature that asks the compiler to write out the statistics and a request for the -`swift_compile_stats` output group so that the files are available at the end of -the build: - -``` -bazel build //your/swift:target \ - --features=swift.compile_stats \ - --output_groups=swift_compile_stats \ - --aspects=@build_bazel_rules_swift//swift:stats.bzl%collect_swift_compile_stats -``` - -Since this command is a bit of a mouthful, we've provided a helper script in the -tools directory that wraps this up: - -``` -.../tools/compile_stats/build.sh -``` -""", - implementation = _collect_swift_compile_stats_impl, -) diff --git a/tools/compile_stats/BUILD b/tools/compile_stats/BUILD deleted file mode 100644 index fea2dd826..000000000 --- a/tools/compile_stats/BUILD +++ /dev/null @@ -1,6 +0,0 @@ -load("//swift:swift.bzl", "swift_binary") - -swift_binary( - name = "stats_processor", - srcs = ["main.swift"], -) diff --git a/tools/compile_stats/README.md b/tools/compile_stats/README.md deleted file mode 100644 index 8e771dad4..000000000 --- a/tools/compile_stats/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# compile_stats/build.sh helper - -This script conveniently wraps up the various Bazel arguments needed to collect -timing statistics from the Swift compiler. - -## Usage - -``` -build.sh [arguments] -``` - -where `[arguments]` is a list of arguments that should be passed directly to -Bazel (such as targets to build, or additional flags). - -The output of this script will be a Markdown-formatted consolidated report that -shows the driver and frontend timings for the jobs that were invoked across -_every_ Swift target in the build, with the slowest driver invocations at the -top (and the slowest frontend invocations at the top within those groups). diff --git a/tools/compile_stats/build.sh b/tools/compile_stats/build.sh deleted file mode 100755 index 9c0669e65..000000000 --- a/tools/compile_stats/build.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/bash -# -# Copyright 2019 The Bazel Authors. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -euo pipefail - -manifest="$(mktemp "${TMPDIR:-/tmp}/compile_stats_manifest.XXXXXX")" -trap "rm -f $manifest" EXIT - -collect_stats_flags=( - --features=swift.compile_stats - --output_groups=swift_compile_stats - --aspects=@build_bazel_rules_swift//swift:stats.bzl%collect_swift_compile_stats -) - -# Build the desired targets, with stderr being output as normal. -bazel build "${collect_stats_flags[@]}" "$@" - -# Build the targets *again*, this time with `--experimental_show_artifacts`. -# This should be a null build since we just built everything above. The reason -# we split this is because the artifact output also goes to stderr, so we'd have -# to either capture the whole thing or redirect it to `tee` with color/curses -# support disabled, which would be difficult for the user to read. -# -# A human-readable explanation of the code below: -# -# 1. Build the requested targets while collecting the stats outputs. Use the -# `--experimental_show_artifacts` flag to get a scrapeable dump of the output -# files at the end. -# 2. Pipe stderr into a `sed` command that ignores all lines before the line -# "Build artifacts:", which signifies the beginning of the listing. -# 3. Pipe that into a `sed` command that ignores any lines that don't start with -# ">>>" and strips that prefix off the ones that do. This is the list of -# stats directories that were created for each built target. -# 4. Pass those directories into `find` to print just the filenames of the -# contents of those directories. - -bazel build --experimental_show_artifacts "${collect_stats_flags[@]}" "$@" \ - 2>&1 > /dev/null \ - | sed -e '/Build artifacts:/,$!d' \ - | sed -e 's/^>>>//' -e 't' -e 'd' \ - | while read statsdir ; do - find "$statsdir" -type f - done > "$manifest" - -# Run the report generating tool. -bazel run \ - --apple_platform_type=macos \ - @build_bazel_rules_swift//tools/compile_stats:stats_processor -- \ - "$manifest" diff --git a/tools/compile_stats/main.swift b/tools/compile_stats/main.swift deleted file mode 100644 index 8a5df0fd1..000000000 --- a/tools/compile_stats/main.swift +++ /dev/null @@ -1,242 +0,0 @@ -// Copyright 2019 The Bazel Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import Foundation - -/// Encapsulates the wall, user, and sys clock times of a process's execution. -struct Timing: Comparable { - /// Total wall clock time. - var wall: TimeInterval - - /// Amount of time spent in user-mode code. - var user: TimeInterval - - /// Amount of time spent in kernel code. - var sys: TimeInterval - - static func < (lhs: Timing, rhs: Timing) -> Bool { - return lhs.wall < rhs.wall - } - - /// Creates a new timing with the given values. - init(wall: TimeInterval = 0, user: TimeInterval = 0, sys: TimeInterval = 0) { - self.wall = wall - self.user = user - self.sys = sys - } - - /// Gets or sets one of the clock values in this timing. - /// - /// - Parameter key: The timing to update. Must be `"wall"`, `"user"`, or `"sys"`. - subscript(key: String) -> Double { - get { return self[keyPath: keyPath(for: key)] } - set { - let keyPath = self.keyPath(for: key) - self[keyPath: keyPath] = newValue - } - } - - /// Gets a keypath that can be used to get or set the given timing. - /// - /// - Precondition: `name` must be `"wall"`, `"user"`, or `"sys"`. - private func keyPath(for name: String) -> WritableKeyPath { - switch name { - case "wall": return \.wall - case "user": return \.user - case "sys": return \.sys - default: fatalError("Unknown timing '\(name)'") - } - } -} - -/// Statistics about an invocation of the Swift frontend. -struct FrontendStats { - /// The name of the Swift module being compiled. - let moduleName: String - - /// The source file being compiled, or `"all"` if the invocation involved multiple files. - let sourceFile: String - - /// The start time of frontend invocation. - let startTime: Date - - /// The timings of various tasks (such as type checking, code generation, etc.) that occurred - /// during compilation. - private(set) var taskTimings = [String: Timing]() - - /// The total timing of the frontend invocation. - private(set) var frontendTiming = Timing() - - /// The timings of various tasks sorted such that the slowest ones are first. - func sortedTaskTimings(interestingOnly: Bool) -> [(String, Timing)] { - var allTimings = Array(taskTimings) - - if interestingOnly { - allTimings = allTimings.filter { - switch $0.0 { - case "AST verification", - "Name binding", - "LLVM pipeline", - "Parsing", - "Serialization, swiftdoc", - "Serialization, swiftmodule", - "SILGen", - "SIL optimization", - "SIL verification, post-optimization", - "SIL verification, pre-optimization", - "Type checking and Semantic analysis": - return true - default: return false - } - } - } - - allTimings.sort { $0.1.wall > $1.1.wall } - return allTimings - } - - /// Creates a new `FrontendStats` with information from the given JSON report. - /// - /// - Parameter url: A URL to the frontend report JSON file. - /// - Throws: If there was an error reading or decoding the report. - init(contentsOf url: URL) throws { - let reportData = try Data(contentsOf: url) - let jsonDictionary = try JSONSerialization.jsonObject(with: reportData) as! [String: Any] - - let pathParts = url.lastPathComponent.split(separator: "-") - self.moduleName = String(pathParts[4]) - self.sourceFile = String(pathParts[5]) - self.startTime = Date(timeIntervalSince1970: TimeInterval(pathParts[1])! / 10e9) - - for (key, value) in jsonDictionary { - let keyParts = key.split(separator: ".") - - if key.hasPrefix("time.swift.") { - let category = String(keyParts[2]) - let timingName = String(keyParts[3]) - self.taskTimings[category, default: Timing()][timingName] = value as! Double - } else if key.hasPrefix("time.swift-frontend.") { - // The filename and target triple embedded in this string might contain dots, which screws - // up our string splitting. Instead, we can just get the last component. - let timingName = String(keyParts.last!) - self.frontendTiming[timingName] = value as! Double - } - } - } -} - -/// Statistics about an invocation of the Swift compiler driver. -struct DriverStats { - /// The name of the Swift module being compiled. - let moduleName: String - - /// The start time of the driver invocation. - let startTime: Date - - /// The total timing of the driver invocation. - private(set) var driverTiming = Timing() - - /// Creates a new `DriverStats` with information from the given JSON report. - /// - /// - Parameter url: A URL to the driver report JSON file. - /// - Throws: If there was an error reading or decoding the report. - init(contentsOf url: URL) throws { - let reportData = try Data(contentsOf: url) - let jsonDictionary = try JSONSerialization.jsonObject(with: reportData) as! [String: Any] - - let pathParts = url.lastPathComponent.split(separator: "-") - self.moduleName = String(pathParts[4]) - self.startTime = Date(timeIntervalSince1970: TimeInterval(pathParts[1])! / 10e9) - - for (key, value) in jsonDictionary { - let keyParts = key.split(separator: ".") - - if key.hasPrefix("time.swift-driver.") { - // The filename and target triple embedded in this string might contain dots, which screws - // up our string splitting. Instead, we can just get the last component. - let timingName = String(keyParts.last!) - self.driverTiming[timingName] = value as! Double - } - } - } -} - -/// Returns a formatted string for the given time interval, appropriate for tabular output. -func formattedSeconds(_ value: TimeInterval) -> String { - return String(format: "%8.3fs", value) -} - -/// Processes the reports described in the manifest file and outputs formatted tables to standard -/// output. -func processReports(fromManifest url: URL) throws { - let manifestContents = try String(contentsOf: url).trimmingCharacters(in: .whitespacesAndNewlines) - let reportPaths = manifestContents.split(separator: "\n") - - var allDriverStats = [DriverStats]() - var allFrontendStats = [String: [FrontendStats]]() - - for reportPath in reportPaths.lazy.map(String.init) { - let reportURL = URL(fileURLWithPath: reportPath) - if reportPath.contains("swift-driver") { - let stats = try DriverStats(contentsOf: reportURL) - allDriverStats.append(stats) - } else if reportPath.contains("swift-frontend") { - let stats = try FrontendStats(contentsOf: reportURL) - allFrontendStats[stats.moduleName, default: []].append(stats) - } - } - - // Sort the driver stats so that the slowest compiles come first. - allDriverStats.sort { $0.driverTiming.wall > $1.driverTiming.wall } - - for driverStats in allDriverStats { - let totalDriverTime = String(format: "%0.3fs", driverStats.driverTiming.wall) - print("# Driver invocation for module \(driverStats.moduleName) (\(totalDriverTime))") - print() - - guard var frontendStatsForModule = allFrontendStats[driverStats.moduleName] else { continue } - frontendStatsForModule.sort { $0.frontendTiming.wall > $1.frontendTiming.wall } - - for frontendStats in frontendStatsForModule { - let totalFrontendTime = String(format: "%0.3fs", frontendStats.frontendTiming.wall) - print( - """ - ## Frontend invocation for \ - \(frontendStats.moduleName)/\(frontendStats.sourceFile) \ - (\(totalFrontendTime)) - """) - print() - print("| Task | Wall | User | Sys |") - print("| ----------------------------------- | --------- | --------- | --------- |") - - for (category, taskTiming) in frontendStats.sortedTaskTimings(interestingOnly: true) { - let formattedCategory = category.padding(toLength: 35, withPad: " ", startingAt: 0) - let formattedWall = formattedSeconds(taskTiming.wall) - let formattedUser = formattedSeconds(taskTiming.user) - let formattedSys = formattedSeconds(taskTiming.sys) - print("| \(formattedCategory) | \(formattedWall) | \(formattedUser) | \(formattedSys) |") - } - - print() - } - } -} - -guard CommandLine.arguments.count == 2 else { - print("USAGE: stats_processor ") - exit(1) -} - -let manifestURL = URL(fileURLWithPath: CommandLine.arguments[1]) -try processReports(fromManifest: manifestURL) From 97221ad1b9f9f7370e3c75688ab3e4df07ab57d2 Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Tue, 6 Apr 2021 11:11:55 -0700 Subject: [PATCH 091/152] Simplify and cleanup how implicit toolchain dependencies are managed. - When propagating implicit deps in the toolchain, merge and propagate the providers instead of the `Target` object itself. The `Target` object is fairly heavyweight and not intended to be propagated around the build graph. - Remove the `swift.minimal_deps` feature and the distinction between "required" and "optional" implicit deps. PiperOrigin-RevId: 367044294 (cherry picked from commit 665ea7576e0794dc2d72cc7302714056ba143211) --- swift/internal/compiling.bzl | 91 +++++++++++------------- swift/internal/feature_names.bzl | 7 -- swift/internal/providers.bzl | 80 ++++++++++++++------- swift/internal/swift_binary_test.bzl | 13 ++-- swift/internal/swift_common.bzl | 2 - swift/internal/swift_library.bzl | 15 ++-- swift/internal/swift_toolchain.bzl | 15 ++-- swift/internal/utils.bzl | 37 ++++++++++ swift/internal/xcode_swift_toolchain.bzl | 34 ++++----- 9 files changed, 175 insertions(+), 119 deletions(-) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index 5b521cc49..172fd1b91 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -45,7 +45,6 @@ load( "SWIFT_FEATURE_FASTBUILD", "SWIFT_FEATURE_FULL_DEBUG_INFO", "SWIFT_FEATURE_INDEX_WHILE_BUILDING", - "SWIFT_FEATURE_MINIMAL_DEPS", "SWIFT_FEATURE_MODULE_MAP_HOME_IS_CWD", "SWIFT_FEATURE_NO_EMBED_DEBUG_MODULE", "SWIFT_FEATURE_NO_GENERATED_MODULE_MAP", @@ -1519,16 +1518,26 @@ def compile( * `swiftmodule`: The `.swiftmodule` file that was produced by the compiler. """ - generated_module_deps = ( - deps + swift_toolchain.generated_header_module_implicit_deps + + # Collect the `SwiftInfo` providers that represent the dependencies of the + # Objective-C generated header module -- this includes the dependencies of + # the Swift module, plus any additional dependencies that the toolchain says + # are required for all generated header modules. These are used immediately + # below to write the module map for the header's module (to provide the + # `use` declarations), and later in this function when precompiling the + # module. + generated_module_deps_swift_infos = ( + get_providers(deps, SwiftInfo) + + swift_toolchain.generated_header_module_implicit_deps_providers.swift_infos ) + compile_outputs, other_outputs = _declare_compile_outputs( + srcs = srcs, actions = actions, feature_configuration = feature_configuration, generated_header_name = generated_header_name, - generated_module_deps = generated_module_deps, + generated_module_deps_swift_infos = generated_module_deps_swift_infos, module_name = module_name, - srcs = srcs, target_name = target_name, user_compile_flags = copts, ) @@ -1571,11 +1580,9 @@ def compile( # into the action prerequisites so that configurators have easy access to # the full set of values and inputs through a single accessor. merged_providers = _merge_targets_providers( + implicit_deps_providers = swift_toolchain.implicit_deps_providers, supports_objc_interop = swift_toolchain.supports_objc_interop, - targets = deps + private_deps + get_implicit_deps( - feature_configuration = feature_configuration, - swift_toolchain = swift_toolchain, - ), + targets = deps + private_deps, ) # Flattening this `depset` is necessary because we need to extract the @@ -1683,11 +1690,7 @@ def compile( module_map_file = compile_outputs.generated_module_map_file, module_name = module_name, swift_info = create_swift_info( - swift_infos = [ - dep[SwiftInfo] - for dep in generated_module_deps - if SwiftInfo in dep - ], + swift_infos = generated_module_deps_swift_infos, ), swift_toolchain = swift_toolchain, target_name = target_name, @@ -1824,32 +1827,12 @@ def precompile_clang_module( return precompiled_module -def get_implicit_deps(feature_configuration, swift_toolchain): - """Gets the list of implicit dependencies from the toolchain. - - Args: - feature_configuration: The feature configuration, which determines - whether optional implicit dependencies are included. - swift_toolchain: The Swift toolchain. - - Returns: - A list of targets that should be treated as implicit dependencies of - the toolchain under the given feature configuration. - """ - deps = list(swift_toolchain.required_implicit_deps) - if not is_feature_enabled( - feature_configuration = feature_configuration, - feature_name = SWIFT_FEATURE_MINIMAL_DEPS, - ): - deps.extend(swift_toolchain.optional_implicit_deps) - return deps - def _declare_compile_outputs( *, actions, feature_configuration, generated_header_name, - generated_module_deps, + generated_module_deps_swift_infos, module_name, srcs, target_name, @@ -1862,8 +1845,9 @@ def _declare_compile_outputs( `swift_common.configure_features`. generated_header_name: The desired name of the generated header for this module, or `None` if no header should be generated. - generated_module_deps: Dependencies of the module for the generated - header of the target being compiled. + generated_module_deps_swift_infos: `SwiftInfo` providers from + dependencies of the module for the generated header of the target + being compiled. module_name: The name of the Swift module being compiled. srcs: The list of source files that will be compiled. target_name: The name (excluding package path) of the target being @@ -1932,11 +1916,10 @@ def _declare_compile_outputs( # Collect the names of Clang modules that the module being built # directly depends on. dependent_module_names = sets.make() - for dep in generated_module_deps: - if SwiftInfo in dep: - for module in dep[SwiftInfo].direct_modules: - if module.clang: - sets.insert(dependent_module_names, module.name) + for swift_info in generated_module_deps_swift_infos: + for module in swift_info.direct_modules: + if module.clang: + sets.insert(dependent_module_names, module.name) generated_module_map = derived_files.module_map( actions = actions, @@ -2117,7 +2100,10 @@ def _declare_validated_generated_header(actions, generated_header_name): return actions.declare_file(generated_header_name) -def _merge_targets_providers(supports_objc_interop, targets): +def _merge_targets_providers( + implicit_deps_providers, + supports_objc_interop, + targets): """Merges the compilation-related providers for the given targets. This function merges the `CcInfo`, `SwiftInfo`, and `apple_common.Objc` @@ -2127,6 +2113,8 @@ def _merge_targets_providers(supports_objc_interop, targets): their data. Args: + implicit_deps_providers: The implicit deps providers `struct` from the + Swift toolchain. supports_objc_interop: `True` if the current toolchain supports Objective-C interop and the `apple_common.Objc` providers should also be used to determine compilation flags and inputs. If `False`, @@ -2144,9 +2132,9 @@ def _merge_targets_providers(supports_objc_interop, targets): * `objc_info`: The merged `apple_common.Objc` provider of the targets. * `swift_info`: The merged `SwiftInfo` provider of the targets. """ - cc_infos = [] - objc_infos = [] - swift_infos = [] + cc_infos = list(implicit_deps_providers.cc_infos) + objc_infos = list(implicit_deps_providers.objc_infos) + swift_infos = list(implicit_deps_providers.swift_infos) # TODO(b/146575101): This is only being used to preserve the current # behavior of strict Objective-C include paths being propagated one more @@ -2267,7 +2255,8 @@ def new_objc_provider( module_map, static_archives, swiftmodules, - objc_header = None): + objc_header = None, + objc_providers = []): """Creates an `apple_common.Objc` provider for a Swift target. Args: @@ -2287,15 +2276,17 @@ def new_objc_provider( `None`, no headers will be propagated. This header is only needed for Swift code that defines classes that should be exposed to Objective-C. + objc_providers: Additional `apple_common.Objc` providers from transitive + dependencies not provided by the `deps` argument. Returns: An `apple_common.Objc` provider that should be returned by the calling rule. """ - objc_providers = get_providers(deps, apple_common.Objc) + all_objc_providers = get_providers(deps, apple_common.Objc) + objc_providers objc_provider_args = { "link_inputs": depset(direct = swiftmodules + link_inputs), - "providers": objc_providers, + "providers": all_objc_providers, "uses_swift": True, } @@ -2335,7 +2326,7 @@ def new_objc_provider( # direct deps' Objective-C module maps to dependents, because those Swift # modules still need to see them. We need to construct a new transitive objc # provider to get the correct strict propagation behavior. - transitive_objc_provider_args = {"providers": objc_providers} + transitive_objc_provider_args = {"providers": all_objc_providers} if module_map: transitive_objc_provider_args["module_map"] = depset( direct = [module_map], diff --git a/swift/internal/feature_names.bzl b/swift/internal/feature_names.bzl index 20133fe4a..7694d69c7 100644 --- a/swift/internal/feature_names.bzl +++ b/swift/internal/feature_names.bzl @@ -96,13 +96,6 @@ SWIFT_FEATURE_INDEX_WHILE_BUILDING = "swift.index_while_building" # If enabled the compilation action will not produce indexes for system modules. SWIFT_FEATURE_DISABLE_SYSTEM_INDEX = "swift.disable_system_index" -# If enabled, Swift libraries, binaries, and tests will only have automatic -# dependencies on the targets provided by the toolchain's -# `required_implicit_deps` field but not those in the `optional_implicit_deps` -# field. Users may still explicitly list the latter in the `deps` of their -# targets if they are needed. -SWIFT_FEATURE_MINIMAL_DEPS = "swift.minimal_deps" - # If enabled, compilation actions and module map generation will assume that the # header paths in module maps are relative to the current working directory # (i.e., the workspace root); if disabled, header paths in module maps are diff --git a/swift/internal/providers.bzl b/swift/internal/providers.bzl index b6405013b..5af061c1a 100644 --- a/swift/internal/providers.bzl +++ b/swift/internal/providers.bzl @@ -73,12 +73,38 @@ Swift toolchain depends on. "cpu": """\ `String`. The CPU architecture that the toolchain is targeting. """, - "generated_header_module_implicit_deps": """\ -`List` of `Target`s. Targets whose `SwiftInfo` providers should be treated as -compile-time inputs to actions that precompile the explicit module for the -generated Objective-C header of a Swift module. This is used to provide modular -dependencies for the fixed inclusions (Darwin, Foundation) that are -unconditionally emitted in those files. + "generated_header_module_implicit_deps_providers": """\ +A `struct` with the following fields, which are providers from targets that +should be treated as compile-time inputs to actions that precompile the explicit +module for the generated Objective-C header of a Swift module: + +* `cc_infos`: A list of `CcInfo` providers from targets specified as the + toolchain's implicit dependencies. +* `objc_infos`: A list of `apple_common.Objc` providers from targets specified + as the toolchain's implicit dependencies. +* `swift_infos`: A list of `SwiftInfo` providers from targets specified as the + toolchain's implicit dependencies. + +This is used to provide modular dependencies for the fixed inclusions (Darwin, +Foundation) that are unconditionally emitted in those files. + +For ease of use, this field is never `None`; it will always be a valid `struct` +containing the fields described above, even if those lists are empty. +""", + "implicit_deps_providers": """\ +A `struct` with the following fields, which represent providers from targets +that should be added as implicit dependencies of any Swift compilation or +linking target (but not to precompiled explicit C/Objective-C modules): + +* `cc_infos`: A list of `CcInfo` providers from targets specified as the + toolchain's implicit dependencies. +* `objc_infos`: A list of `apple_common.Objc` providers from targets specified + as the toolchain's implicit dependencies. +* `swift_infos`: A list of `SwiftInfo` providers from targets specified as the + toolchain's implicit dependencies. + +For ease of use, this field is never `None`; it will always be a valid `struct` +containing the fields described above, even if those lists are empty. """, "linker_opts_producer": """\ Skylib `partial`. A partial function that returns the flags that should be @@ -100,11 +126,6 @@ files passed to it via a file list. "object_format": """\ `String`. The object file format of the platform that the toolchain is targeting. The currently supported values are `"elf"` and `"macho"`. -""", - "optional_implicit_deps": """\ -`List` of `Target`s. Library targets that should be added as implicit -dependencies of any `swift_library`, `swift_binary`, or `swift_test` target that -does not have the feature `swift.minimal_deps` applied. """, "requested_features": """\ `List` of `string`s. Features that should be implicitly enabled by default for @@ -115,11 +136,6 @@ their negation in the `features` attribute of a target/package or in the These features determine various compilation and debugging behaviors of the Swift build rules, and they are also passed to the C++ APIs used when linking (so features defined in CROSSTOOL may be used here). -""", - "required_implicit_deps": """\ -`List` of `Target`s. Library targets that should be unconditionally added as -implicit dependencies of any `swift_library`, `swift_binary`, or `swift_test` -target. """, "root_dir": """\ `String`. The workspace-relative root directory of the toolchain. @@ -287,6 +303,7 @@ def create_swift_module( def create_swift_info( *, + direct_swift_infos = [], modules = [], swift_infos = []): """Creates a new `SwiftInfo` provider with the given values. @@ -297,25 +314,38 @@ def create_swift_info( are set consistently. This function can also be used to do a simple merge of `SwiftInfo` - providers, by leaving all of the arguments except for `swift_infos` as their - empty defaults. In that case, the returned provider will not represent a - true Swift module; it is merely a "collector" for other dependencies. + 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 fields should be merged into the new one. If omitted, no - transitive data is collected. + 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. """ - transitive_modules = [x.transitive_modules for x in swift_infos] + direct_modules = modules + [ + provider.modules + for provider in direct_swift_infos + ] + transitive_modules = [ + provider.transitive_modules + for provider in direct_swift_infos + swift_infos + ] return SwiftInfo( - direct_modules = modules, - transitive_modules = depset(modules, transitive = transitive_modules), + direct_modules = direct_modules, + transitive_modules = depset( + direct_modules, + transitive = transitive_modules, + ), ) diff --git a/swift/internal/swift_binary_test.bzl b/swift/internal/swift_binary_test.bzl index d0ab1e884..598454080 100644 --- a/swift/internal/swift_binary_test.bzl +++ b/swift/internal/swift_binary_test.bzl @@ -217,13 +217,10 @@ def _swift_linking_rule_impl( ) user_link_flags.extend(toolchain_linker_flags) - # Collect the dependencies of the target being linked as well as the - # toolchain's implicit dependencies (depending on the current feature - # configuration). - deps_to_link = ctx.attr.deps + swift_common.get_implicit_deps( - feature_configuration = feature_configuration, - swift_toolchain = swift_toolchain, - ) + # Collect linking contexts from any of the toolchain's implicit + # dependencies. + for cc_info in swift_toolchain.implicit_deps_providers.cc_infos: + additional_linking_contexts.append(cc_info.linking_context) # If a custom malloc implementation has been provided, pass that to the # linker as well. @@ -244,7 +241,7 @@ def _swift_linking_rule_impl( additional_inputs = additional_inputs_to_linker, additional_linking_contexts = additional_linking_contexts, cc_feature_configuration = cc_feature_configuration, - deps = deps_to_link, + deps = ctx.attr.deps, grep_includes = ctx.file._grep_includes, name = ctx.label.name, objects = objects_to_link, diff --git a/swift/internal/swift_common.bzl b/swift/internal/swift_common.bzl index 09dffc4d5..98ebd736c 100644 --- a/swift/internal/swift_common.bzl +++ b/swift/internal/swift_common.bzl @@ -33,7 +33,6 @@ load( ":compiling.bzl", "compile", "derive_module_name", - "get_implicit_deps", "precompile_clang_module", ) load( @@ -64,7 +63,6 @@ swift_common = struct( create_swift_info = create_swift_info, create_swift_module = create_swift_module, derive_module_name = derive_module_name, - get_implicit_deps = get_implicit_deps, is_enabled = is_feature_enabled, library_rule_attrs = swift_library_rule_attrs, precompile_clang_module = precompile_clang_module, diff --git a/swift/internal/swift_library.bzl b/swift/internal/swift_library.bzl index d6f463710..c290f37b1 100644 --- a/swift/internal/swift_library.bzl +++ b/swift/internal/swift_library.bzl @@ -123,10 +123,6 @@ def _swift_library_impl(ctx): unsupported_features = ctx.disabled_features, ) - implicit_deps = swift_common.get_implicit_deps( - feature_configuration = feature_configuration, - swift_toolchain = swift_toolchain, - ) if swift_common.is_enabled( feature_configuration = feature_configuration, feature_name = SWIFT_FEATURE_SUPPORTS_PRIVATE_DEPS, @@ -137,8 +133,8 @@ def _swift_library_impl(ctx): # deps in "deps", either, so we need to make sure not to pass them in to # `_check_deps_are_disjoint`. deps = ctx.attr.deps - private_deps = ctx.attr.private_deps + implicit_deps - _check_deps_are_disjoint(ctx.label, deps, ctx.attr.private_deps) + private_deps = ctx.attr.private_deps + _check_deps_are_disjoint(ctx.label, deps, private_deps) elif ctx.attr.private_deps: fail( ("In target '{}', 'private_deps' cannot be used because this " + @@ -220,6 +216,7 @@ def _swift_library_impl(ctx): library_to_link.pic_static_library, ]) + implicit_deps_providers = swift_toolchain.implicit_deps_providers providers = [ DefaultInfo( files = depset(direct_output_files), @@ -238,7 +235,10 @@ def _swift_library_impl(ctx): defines = ctx.attr.defines, includes = [ctx.bin_dir.path], linker_inputs = [linker_input], - private_cc_infos = get_providers(private_deps, CcInfo), + private_cc_infos = ( + get_providers(private_deps, CcInfo) + + implicit_deps_providers.cc_infos + ), ), coverage_common.instrumented_files_info( ctx, @@ -281,6 +281,7 @@ def _swift_library_impl(ctx): static_archives = compact([library_to_link.pic_static_library]), swiftmodules = [compilation_outputs.swiftmodule], objc_header = compilation_outputs.generated_header, + objc_providers = implicit_deps_providers.objc_infos, )) return providers diff --git a/swift/internal/swift_toolchain.bzl b/swift/internal/swift_toolchain.bzl index 124630c01..29b68e2a1 100644 --- a/swift/internal/swift_toolchain.bzl +++ b/swift/internal/swift_toolchain.bzl @@ -36,7 +36,11 @@ load( load(":features.bzl", "features_for_build_modes") load(":providers.bzl", "SwiftToolchainInfo") load(":toolchain_config.bzl", "swift_toolchain_config") -load(":utils.bzl", "get_swift_executable_for_toolchain") +load( + ":utils.bzl", + "collect_implicit_deps_providers", + "get_swift_executable_for_toolchain", +) def _all_tool_configs( swift_executable, @@ -212,13 +216,16 @@ def _swift_toolchain_impl(ctx): all_files = depset(all_files), cc_toolchain_info = cc_toolchain, cpu = ctx.attr.arch, - generated_header_module_implicit_deps = [], + generated_header_module_implicit_deps_providers = ( + collect_implicit_deps_providers([]) + ), + implicit_deps_providers = ( + collect_implicit_deps_providers([]) + ), linker_opts_producer = linker_opts_producer, linker_supports_filelist = False, object_format = "elf", - optional_implicit_deps = [], requested_features = requested_features, - required_implicit_deps = [], root_dir = toolchain_root, supports_objc_interop = False, swift_worker = ctx.executable._worker, diff --git a/swift/internal/utils.bzl b/swift/internal/utils.bzl index f7d545892..d87c80cdd 100644 --- a/swift/internal/utils.bzl +++ b/swift/internal/utils.bzl @@ -14,6 +14,7 @@ """Common utility definitions used by various BUILD rules.""" +load(":providers.bzl", "SwiftInfo") load("@bazel_skylib//lib:paths.bzl", "paths") def collect_cc_libraries( @@ -58,6 +59,42 @@ def collect_cc_libraries( return libraries +def collect_implicit_deps_providers(targets): + """Returns a struct with important providers from a list of implicit deps. + + Note that the relationship between each provider in the list and the target + it originated from is no longer retained. + + Args: + targets: A list (possibly empty) of `Target`s. + + Returns: + A `struct` containing three fields: + + * `cc_infos`: The merged `CcInfo` provider from the given targets. + * `objc_infos`: The merged `apple_common.Objc` provider from the given + targets. + * `swift_infos`: The merged `SwiftInfo` provider from the given + targets. + """ + cc_infos = [] + objc_infos = [] + swift_infos = [] + + for target in targets: + if CcInfo in target: + cc_infos.append(target[CcInfo]) + if apple_common.Objc in target: + objc_infos.append(target[apple_common.Objc]) + if SwiftInfo in target: + swift_infos.append(target[SwiftInfo]) + + return struct( + cc_infos = cc_infos, + objc_infos = objc_infos, + swift_infos = swift_infos, + ) + def compact(sequence): """Returns a copy of the sequence with any `None` items removed. diff --git a/swift/internal/xcode_swift_toolchain.bzl b/swift/internal/xcode_swift_toolchain.bzl index 61c37d4f5..5237b4687 100644 --- a/swift/internal/xcode_swift_toolchain.bzl +++ b/swift/internal/xcode_swift_toolchain.bzl @@ -46,7 +46,12 @@ load( load(":features.bzl", "features_for_build_modes") load(":toolchain_config.bzl", "swift_toolchain_config") load(":providers.bzl", "SwiftInfo", "SwiftToolchainInfo") -load(":utils.bzl", "compact", "get_swift_executable_for_toolchain") +load( + ":utils.bzl", + "collect_implicit_deps_providers", + "compact", + "get_swift_executable_for_toolchain", +) def _swift_developer_lib_dir(platform_framework_dir): """Returns the directory containing extra Swift developer libraries. @@ -754,15 +759,18 @@ def _xcode_swift_toolchain_impl(ctx): all_files = depset(all_files), cc_toolchain_info = cc_toolchain, cpu = cpu, - generated_header_module_implicit_deps = ( - ctx.attr.generated_header_module_implicit_deps + generated_header_module_implicit_deps_providers = ( + collect_implicit_deps_providers( + ctx.attr.generated_header_module_implicit_deps, + ) + ), + implicit_deps_providers = collect_implicit_deps_providers( + ctx.attr.implicit_deps, ), linker_opts_producer = linker_opts_producer, linker_supports_filelist = True, object_format = "macho", - optional_implicit_deps = ctx.attr.optional_implicit_deps, requested_features = requested_features, - required_implicit_deps = ctx.attr.required_implicit_deps, supports_objc_interop = True, swift_worker = ctx.executable._worker, system_name = "darwin", @@ -789,22 +797,16 @@ of a Swift module. """, providers = [[SwiftInfo]], ), - "optional_implicit_deps": attr.label_list( - allow_files = True, - doc = """\ -A list of labels to library targets that should be added as implicit -dependencies of any Swift compilation or linking target that does not have the -`swift.minimal_deps` feature applied. -""", - providers = [[CcInfo], [SwiftInfo]], - ), - "required_implicit_deps": attr.label_list( + "implicit_deps": attr.label_list( allow_files = True, doc = """\ A list of labels to library targets that should be unconditionally added as implicit dependencies of any Swift compilation or linking target. """, - providers = [[CcInfo], [SwiftInfo]], + providers = [ + [CcInfo], + [SwiftInfo], + ], ), "_cc_toolchain": attr.label( default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"), From 430311c8d24f2cb9a63441e852d7eafa88169fea Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Mon, 15 Mar 2021 07:08:19 -0700 Subject: [PATCH 092/152] Update examples/tests with `generates_header = True` where necessary before flipping the attribute. PiperOrigin-RevId: 362932692 (cherry picked from commit 1bcdd5756d044a4caa264dab4cac6aa321776478) --- examples/apple/objc_interop/BUILD | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/apple/objc_interop/BUILD b/examples/apple/objc_interop/BUILD index 8cd5252d9..bb2d2fa71 100644 --- a/examples/apple/objc_interop/BUILD +++ b/examples/apple/objc_interop/BUILD @@ -20,6 +20,7 @@ objc_library( swift_library( name = "Printer", srcs = ["Printer.swift"], + generates_header = True, deps = [":PrintStream"], ) From f81fa6f15220716ae9bf613d45969b05abbaa8e9 Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Tue, 6 Apr 2021 08:40:21 -0700 Subject: [PATCH 093/152] Make `swift_library` not generate an Objective-C header by default. To generate a header, `generates_header` must be set to `True` on the target. PiperOrigin-RevId: 367012879 (cherry picked from commit 413cc02802fff11916e5bf4738767f99cb1cf1e3) --- swift/internal/attrs.bzl | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/swift/internal/attrs.bzl b/swift/internal/attrs.bzl index bcc6099b0..d27aa525f 100644 --- a/swift/internal/attrs.bzl +++ b/swift/internal/attrs.bzl @@ -277,9 +277,7 @@ False. mandatory = False, ), "generates_header": attr.bool( - # TODO(b/182493307): Make the default False after migrating all - # targets to explicitly specify it when needed. - default = True, + default = False, doc = """\ If True, an Objective-C header will be generated for this target, in the same build package where the target is defined. By default, the name of the header is From 006a981e5ca2d520c58e2d82624616e74ae4c3a3 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Tue, 6 Apr 2021 17:09:23 -0700 Subject: [PATCH 094/152] Update apple_support to new release --- swift/repositories.bzl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/swift/repositories.bzl b/swift/repositories.bzl index 3bb3250a9..36b5f5a3e 100644 --- a/swift/repositories.bzl +++ b/swift/repositories.bzl @@ -51,9 +51,9 @@ def swift_rules_dependencies(): http_archive, name = "build_bazel_apple_support", urls = [ - "https://github.com/bazelbuild/apple_support/releases/download/0.9.2/apple_support.0.9.2.tar.gz", + "https://github.com/bazelbuild/apple_support/releases/download/0.10.0/apple_support.0.10.0.tar.gz", ], - sha256 = "a1926bbc5bbb86d596ee1e9c307e22c9a0305053e46057cf186d015b09b3c5f2", + sha256 = "741366f79d900c11e11d8efd6cc6c66a31bfb2451178b58e0b5edc6f1db17b35", ) _maybe( From 9c8d8f7af3210922936e42f1936d1180aef8d467 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Tue, 6 Apr 2021 17:29:53 -0700 Subject: [PATCH 095/152] Update README with new URLs --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 154d27c88..bf26fe20e 100644 --- a/README.md +++ b/README.md @@ -51,8 +51,8 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "build_bazel_rules_swift", - sha256 = "be80375680b2553a8b318ffd02ce916a7e1d9060ccad3e7c50f543caafb86fed", - url = "https://github.com/bazelbuild/rules_swift/releases/download/0.19.0/rules_swift.0.19.0.tar.gz", + sha256 = "a525d254b0323380b7abe7cbbe03534167f0fcb45f44f7d16cdd4d7d057b8f8d", + url = "https://github.com/bazelbuild/rules_swift/releases/download/0.20.0/rules_swift.0.20.0.tar.gz", ) load( From a62e084c78ff0b52382c70c5eb2e019fd4b75005 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Tue, 6 Apr 2021 17:35:23 -0700 Subject: [PATCH 096/152] Add -Werror for C++ --- .bazelrc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.bazelrc b/.bazelrc index 1f52e460b..2ae30cf59 100644 --- a/.bazelrc +++ b/.bazelrc @@ -2,3 +2,7 @@ # this forces all targets' minimum macOS to Catalina until Bazel CI has # upgraded their Mac machines to Big Sur. build --macos_minimum_os=10.15 + +# Make sure no warnings slip into the C++ tools we vendor +build --copt=-Werror +build --host_copt=-Werror From 5bf6ef7fe48eba463881db4deb8134aadfd75b3b Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Mon, 19 Apr 2021 10:18:05 -0700 Subject: [PATCH 097/152] Fix skylib branch name Fixes https://github.com/bazelbuild/rules_apple/issues/1130 --- .bazelci/update_workspace_to_deps_heads.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.bazelci/update_workspace_to_deps_heads.sh b/.bazelci/update_workspace_to_deps_heads.sh index 4b82dc75c..45681551b 100755 --- a/.bazelci/update_workspace_to_deps_heads.sh +++ b/.bazelci/update_workspace_to_deps_heads.sh @@ -33,7 +33,7 @@ load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")\ git_repository(\ \ name = "bazel_skylib",\ \ remote = "https://github.com/bazelbuild/bazel-skylib.git",\ -\ branch = "master",\ +\ branch = "main",\ )\ \ git_repository(\ From 21b1541f6e43ea660ca67916787b6aef57bdfd90 Mon Sep 17 00:00:00 2001 From: Alex Eagle Date: Fri, 30 Apr 2021 13:20:12 -0700 Subject: [PATCH 098/152] Add first stardoc API docgen target (#598) --- WORKSPACE | 15 + doc/BUILD.bazel | 45 +++ doc/rules.md | 757 ++++++++------------------------------- swift/internal/attrs.bzl | 7 +- swift/swift.bzl | 9 + 5 files changed, 230 insertions(+), 603 deletions(-) create mode 100644 doc/BUILD.bazel diff --git a/WORKSPACE b/WORKSPACE index cff5498cd..dc6ef478a 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -17,3 +17,18 @@ swift_rules_extra_dependencies() load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace") bazel_skylib_workspace() + +# For API doc generation +# This is a dev dependency, users should not need to install it +# so we declare it in the WORKSPACE +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +http_archive( + name = "io_bazel_stardoc", + patches = [], + sha256 = "f89bda7b6b696c777b5cf0ba66c80d5aa97a6701977d43789a9aee319eef71e8", + strip_prefix = "stardoc-d93ee5347e2d9c225ad315094507e018364d5a67", + urls = [ + "https://github.com/bazelbuild/stardoc/archive/d93ee5347e2d9c225ad315094507e018364d5a67.tar.gz", + ], +) diff --git a/doc/BUILD.bazel b/doc/BUILD.bazel new file mode 100644 index 000000000..3a7d71565 --- /dev/null +++ b/doc/BUILD.bazel @@ -0,0 +1,45 @@ +load("@bazel_skylib//rules:write_file.bzl", "write_file") +load("@bazel_skylib//rules:diff_test.bzl", "diff_test") +load("@io_bazel_stardoc//stardoc:stardoc.bzl", "stardoc") + +_RULES_SYMBOLS = [ + "swift_binary", + "swift_c_module", + "swift_grpc_library", + "swift_import", + "swift_library", + "swift_module_alias", + "swift_proto_library", + "swift_test", +] + +write_file( + name = "gen_header", + out = "header.vm", + content = [ + "", + "", + "${moduleDocstring}", + "On this page:", + "", + ] + [" * [{0}](#{0})".format(r) for r in _RULES_SYMBOLS] + [ + "", + ], +) + +stardoc( + name = "doc", + out = "swift.md", + header_template = ":header.vm", + input = "//swift:swift.bzl", + symbol_names = _RULES_SYMBOLS, + deps = ["//swift"], +) + +# To make this test pass, run +# bazel build doc:all && cp bazel-bin/doc/swift.md doc/rules.md +diff_test( + name = "test", + file1 = "swift.md", + file2 = "rules.md", +) diff --git a/doc/rules.md b/doc/rules.md index 91a374d24..f8cd92984 100644 --- a/doc/rules.md +++ b/doc/rules.md @@ -1,8 +1,9 @@ -# BUILD Rule Reference - - + +BUILD rules to define Swift libraries and executable binaries. +This file is the public interface that users should import to use the Swift +rules. Do not import definitions from the `internal` subdirectory directly. To use the Swift build rules in your BUILD files, load them from `@build_bazel_rules_swift//swift:swift.bzl`. @@ -23,13 +24,14 @@ On this page: * [swift_module_alias](#swift_module_alias) * [swift_proto_library](#swift_proto_library) * [swift_test](#swift_test) - + + + ## swift_binary -
-swift_binary(name, deps, srcs, data, compatible_with, copts, defines, deprecation, distribs,
-features, licenses, linkopts, malloc, module_name, restricted_to, stamp, swiftc_inputs, tags,
-testonly, visibility)
+
+swift_binary(name, copts, data, defines, deps, linkopts, malloc, module_name, srcs, stamp,
+             swiftc_inputs)
 
Compiles and links Swift code into an executable binary. @@ -46,125 +48,31 @@ please use one of the platform-specific application rules in [rules_apple](https://github.com/bazelbuild/rules_apple) instead of `swift_binary`. - -### Attributes - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
name -

Name; required

A unique name for this target.

deps -

List of labels; optional

A list of targets that are dependencies of the target being built, which will be -linked into that target.

-

If the Swift toolchain supports implementation-only imports (private_deps on -swift_library), then targets in deps are treated as regular -(non-implementation-only) imports that are propagated both to their direct and -indirect (transitive) dependents.

-

Allowed kinds of dependencies are:

-
    -
  • swift_c_module, swift_import and swift_library (or anything -propagating SwiftInfo)
  • -
  • cc_library (or anything propagating CcInfo)
  • -
-

Additionally, on platforms that support Objective-C interop, objc_library -targets (or anything propagating the apple_common.Objc provider) are allowed -as dependencies. On platforms that do not support Objective-C interop (such as -Linux), those dependencies will be ignored.

srcs -

List of labels; optional

A list of .swift source files that will be compiled into the library.

data -

List of labels; optional

The list of files needed by this target at runtime.

-

Files and targets named in the data attribute will appear in the *.runfiles -area of this target, if it has one. This may include data files needed by a -binary or library, or other programs needed by it.

copts -

List of strings; optional

Additional compiler options that should be passed to swiftc. These strings are -subject to $(location ...) expansion.

defines -

List of strings; optional

A list of defines to add to the compilation command line.

-

Note that unlike C-family languages, Swift defines do not have values; they are -simply identifiers that are either defined or undefined. So strings in this list -should be simple identifiers, not name=value pairs.

-

Each string is prepended with -D and added to the command line. Unlike -copts, these flags are added for the target and every target that depends on -it, so use this attribute with caution. It is preferred that you add defines -directly to copts, only using this feature in the rare case that a library -needs to propagate a symbol up to those that depend on it.

linkopts -

List of strings; optional

Additional linker options that should be passed to clang. These strings are -subject to $(location ...) expansion.

malloc -

Label; optional; default is @bazel_tools//tools/cpp:malloc

Override the default dependency on malloc.

-

By default, Swift binaries are linked against @bazel_tools//tools/cpp:malloc", -which is an empty library and the resulting binary will use libc's malloc. -This label must refer to a cc_library rule.

module_name -

String; optional

The name of the Swift module being built.

-

If left unspecified, the module name will be computed based on the target's -build label, by stripping the leading // and replacing /, :, and other -non-identifier characters with underscores.

stamp -

Integer; optional; default is -1

Enable or disable link stamping; that is, whether to encode build information -into the binary. Possible values are:

-
    -
  • stamp = 1: Stamp the build information into the binary. Stamped binaries are -only rebuilt when their dependencies change. Use this if there are tests that -depend on the build information.
  • -
  • stamp = 0: Always replace build information by constant values. This gives -good build result caching.
  • -
  • stamp = -1: Embedding of build information is controlled by the ---[no]stamp flag.
  • -
swiftc_inputs -

List of labels; optional

Additional files that are referenced using $(location ...) in attributes that -support location expansion.

- - - + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | +| copts | Additional compiler options that should be passed to swiftc. These strings are subject to $(location ...) and ["Make" variable](https://docs.bazel.build/versions/master/be/make-variables.html) expansion. | List of strings | optional | [] | +| data | The list of files needed by this target at runtime.

Files and targets named in the data attribute will appear in the *.runfiles area of this target, if it has one. This may include data files needed by a binary or library, or other programs needed by it. | List of labels | optional | [] | +| defines | A list of defines to add to the compilation command line.

Note that unlike C-family languages, Swift defines do not have values; they are simply identifiers that are either defined or undefined. So strings in this list should be simple identifiers, **not** name=value pairs.

Each string is prepended with -D and added to the command line. Unlike copts, these flags are added for the target and every target that depends on it, so use this attribute with caution. It is preferred that you add defines directly to copts, only using this feature in the rare case that a library needs to propagate a symbol up to those that depend on it. | List of strings | optional | [] | +| deps | A list of targets that are dependencies of the target being built, which will be linked into that target.

If the Swift toolchain supports implementation-only imports (private_deps on swift_library), then targets in deps are treated as regular (non-implementation-only) imports that are propagated both to their direct and indirect (transitive) dependents.

Allowed kinds of dependencies are:

* swift_c_module, swift_import and swift_library (or anything propagating SwiftInfo)

* cc_library (or anything propagating CcInfo)

Additionally, on platforms that support Objective-C interop, objc_library targets (or anything propagating the apple_common.Objc provider) are allowed as dependencies. On platforms that do not support Objective-C interop (such as Linux), those dependencies will be **ignored.** | List of labels | optional | [] | +| linkopts | Additional linker options that should be passed to clang. These strings are subject to $(location ...) expansion. | List of strings | optional | [] | +| malloc | Override the default dependency on malloc.

By default, Swift binaries are linked against @bazel_tools//tools/cpp:malloc", which is an empty library and the resulting binary will use libc's malloc. This label must refer to a cc_library rule. | Label | optional | @bazel_tools//tools/cpp:malloc | +| module_name | The name of the Swift module being built.

If left unspecified, the module name will be computed based on the target's build label, by stripping the leading // and replacing /, :, and other non-identifier characters with underscores. | String | optional | "" | +| srcs | A list of .swift source files that will be compiled into the library. | List of labels | optional | [] | +| stamp | Enable or disable link stamping; that is, whether to encode build information into the binary. Possible values are:

* stamp = 1: Stamp the build information into the binary. Stamped binaries are only rebuilt when their dependencies change. Use this if there are tests that depend on the build information.

* stamp = 0: Always replace build information by constant values. This gives good build result caching.

* stamp = -1: Embedding of build information is controlled by the --[no]stamp flag. | Integer | optional | -1 | +| swiftc_inputs | Additional files that are referenced using $(location ...) in attributes that support location expansion. | List of labels | optional | [] | + + + + ## swift_c_module -
-swift_c_module(name, deps, compatible_with, deprecation, distribs, features, licenses, module_map,
-module_name, restricted_to, tags, testonly, visibility)
+
+swift_c_module(name, deps, module_map, module_name)
 
Wraps one or more C targets in a new module map that allows it to be imported @@ -197,55 +105,24 @@ referenced by a module map that is imported into Swift must have only C features visible, often by using preprocessor conditions like `#if __cplusplus` to hide any C++ declarations. - -### Attributes - - - - - - - - - - - - - - - - - - - - - - - - -
name -

Name; required

A unique name for this target.

deps -

List of labels; required

A list of C targets (or anything propagating CcInfo) that are dependencies of -this target and whose headers may be referenced by the module map.

module_map -

Label; required

The module map file that should be loaded to import the C library dependency -into Swift.

module_name -

String; required

The name of the top-level module in the module map that this target represents.

-

A single module.modulemap file can define multiple top-level modules. When -building with implicit modules, the presence of that module map allows any of -the modules defined in it to be imported. When building explicit modules, -however, there is a one-to-one correspondence between top-level modules and -BUILD targets and the module name must be known without reading the module map -file, so it must be provided directly. Therefore, one may have multiple -swift_c_module targets that reference the same module.modulemap file but -with different module names and headers.

- - - + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | +| deps | A list of C targets (or anything propagating CcInfo) that are dependencies of this target and whose headers may be referenced by the module map. | List of labels | required | | +| module_map | The module map file that should be loaded to import the C library dependency into Swift. | Label | required | | +| module_name | The name of the top-level module in the module map that this target represents.

A single module.modulemap file can define multiple top-level modules. When building with implicit modules, the presence of that module map allows any of the modules defined in it to be imported. When building explicit modules, however, there is a one-to-one correspondence between top-level modules and BUILD targets and the module name must be known without reading the module map file, so it must be provided directly. Therefore, one may have multiple swift_c_module targets that reference the same module.modulemap file but with different module names and headers. | String | required | | + + + + ## swift_grpc_library -
-swift_grpc_library(name, deps, srcs, compatible_with, deprecation, distribs, features, flavor,
-licenses, restricted_to, tags, testonly, visibility)
+
+swift_grpc_library(name, deps, flavor, srcs)
 
Generates a Swift library from gRPC services defined in protocol buffer sources. @@ -313,271 +190,82 @@ swift_grpc_library( ) ``` - -### Attributes - - - - - - - - - - - - - - - - - - - - - - - - -
name -

Name; required

A unique name for this target.

deps -

List of labels; optional

Exactly one swift_proto_library or swift_grpc_library target that contains -the Swift protos used by the services being generated. Test stubs should depend -on the swift_grpc_library implementing the service.

srcs -

List of labels; optional

Exactly one proto_library target that defines the services being generated.

flavor -

String; required; valid values are ['client', 'client_stubs', 'server']

The kind of definitions that should be generated:

-
    -
  • "client" to generate client definitions.
  • -
  • "client_stubs" to generate client test stubs.
  • -
  • "server" to generate server definitions.
  • -
- - - + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | +| deps | Exactly one swift_proto_library or swift_grpc_library target that contains the Swift protos used by the services being generated. Test stubs should depend on the swift_grpc_library implementing the service. | List of labels | optional | [] | +| flavor | The kind of definitions that should be generated:

* "client" to generate client definitions.

* "client_stubs" to generate client test stubs.

* "server" to generate server definitions. | String | required | | +| srcs | Exactly one proto_library target that defines the services being generated. | List of labels | optional | [] | + + + + ## swift_import -
-swift_import(name, deps, data, archives, compatible_with, deprecation, distribs, features, licenses,
-module_name, restricted_to, swiftdoc, swiftmodule, tags, testonly, visibility)
+
+swift_import(name, archives, data, deps, module_name, swiftdoc, swiftmodule)
 
Allows for the use of precompiled Swift modules as dependencies in other `swift_library` and `swift_binary` targets. - -### Attributes - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
name -

Name; required

A unique name for this target.

deps -

List of labels; optional

A list of targets that are dependencies of the target being built, which will be -linked into that target.

-

If the Swift toolchain supports implementation-only imports (private_deps on -swift_library), then targets in deps are treated as regular -(non-implementation-only) imports that are propagated both to their direct and -indirect (transitive) dependents.

-

Allowed kinds of dependencies are:

-
    -
  • swift_c_module, swift_import and swift_library (or anything -propagating SwiftInfo)
  • -
  • cc_library (or anything propagating CcInfo)
  • -
-

Additionally, on platforms that support Objective-C interop, objc_library -targets (or anything propagating the apple_common.Objc provider) are allowed -as dependencies. On platforms that do not support Objective-C interop (such as -Linux), those dependencies will be ignored.

data -

List of labels; optional

The list of files needed by this target at runtime.

-

Files and targets named in the data attribute will appear in the *.runfiles -area of this target, if it has one. This may include data files needed by a -binary or library, or other programs needed by it.

archives -

List of labels; required

The list of .a files provided to Swift targets that depend on this target.

module_name -

String; required

The name of the module represented by this target.

swiftdoc -

Label; optional

The .swiftdoc file provided to Swift targets that depend on this target.

swiftmodule -

Label; required

The .swiftmodule file provided to Swift targets that depend on this target.

- - - + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | +| archives | The list of .a files provided to Swift targets that depend on this target. | List of labels | required | | +| data | The list of files needed by this target at runtime.

Files and targets named in the data attribute will appear in the *.runfiles area of this target, if it has one. This may include data files needed by a binary or library, or other programs needed by it. | List of labels | optional | [] | +| deps | A list of targets that are dependencies of the target being built, which will be linked into that target.

If the Swift toolchain supports implementation-only imports (private_deps on swift_library), then targets in deps are treated as regular (non-implementation-only) imports that are propagated both to their direct and indirect (transitive) dependents.

Allowed kinds of dependencies are:

* swift_c_module, swift_import and swift_library (or anything propagating SwiftInfo)

* cc_library (or anything propagating CcInfo)

Additionally, on platforms that support Objective-C interop, objc_library targets (or anything propagating the apple_common.Objc provider) are allowed as dependencies. On platforms that do not support Objective-C interop (such as Linux), those dependencies will be **ignored.** | List of labels | optional | [] | +| module_name | The name of the module represented by this target. | String | required | | +| swiftdoc | The .swiftdoc file provided to Swift targets that depend on this target. | Label | optional | None | +| swiftmodule | The .swiftmodule file provided to Swift targets that depend on this target. | Label | required | | + + + + ## swift_library -
-swift_library(name, deps, srcs, data, alwayslink, compatible_with, copts, defines, deprecation,
-distribs, features, generated_header_name, licenses, linkopts, module_name, private_deps,
-restricted_to, swiftc_inputs, tags, testonly, visibility)
+
+swift_library(name, alwayslink, copts, data, defines, deps, generated_header_name, generates_header,
+              linkopts, module_name, private_deps, srcs, swiftc_inputs)
 
Compiles and links Swift code into a static library and Swift module. - -### Attributes - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -expansion.

- - - - - - - - - - - - - - -
name -

Name; required

A unique name for this target.

deps -

List of labels; optional

A list of targets that are dependencies of the target being built, which will be -linked into that target.

-

If the Swift toolchain supports implementation-only imports (private_deps on -swift_library), then targets in deps are treated as regular -(non-implementation-only) imports that are propagated both to their direct and -indirect (transitive) dependents.

-

Allowed kinds of dependencies are:

-
    -
  • swift_c_module, swift_import and swift_library (or anything -propagating SwiftInfo)
  • -
  • cc_library (or anything propagating CcInfo)
  • -
-

Additionally, on platforms that support Objective-C interop, objc_library -targets (or anything propagating the apple_common.Objc provider) are allowed -as dependencies. On platforms that do not support Objective-C interop (such as -Linux), those dependencies will be ignored.

srcs -

List of labels; optional

A list of .swift source files that will be compiled into the library.

data -

List of labels; optional

The list of files needed by this target at runtime.

-

Files and targets named in the data attribute will appear in the *.runfiles -area of this target, if it has one. This may include data files needed by a -binary or library, or other programs needed by it.

copts -

List of strings; optional

Additional compiler options that should be passed to swiftc. These strings are -subject to $(location ...) and "Make" variable expansion.

defines -

List of strings; optional

A list of defines to add to the compilation command line.

-

Note that unlike C-family languages, Swift defines do not have values; they are -simply identifiers that are either defined or undefined. So strings in this list -should be simple identifiers, not name=value pairs.

-

Each string is prepended with -D and added to the command line. Unlike -copts, these flags are added for the target and every target that depends on -it, so use this attribute with caution. It is preferred that you add defines -directly to copts, only using this feature in the rare case that a library -needs to propagate a symbol up to those that depend on it.

generated_header_name -

String; optional

The name of the generated Objective-C interface header. This name must end with -a .h extension and cannot contain any path separators.

-

If this attribute is not specified, then the default behavior is to name the -header ${target_name}-Swift.h.

-

This attribute is ignored if the toolchain does not support generating headers -or if the target has the swift.no_generated_header feature enabled.

linkopts -

List of strings; optional

Additional linker options that should be passed to the linker for the binary -that depends on this target. These strings are subject to $(location ...) -and "Make" variable expansion.

module_name -

String; optional

The name of the Swift module being built.

-

If left unspecified, the module name will be computed based on the target's -build label, by stripping the leading // and replacing /, :, and other -non-identifier characters with underscores.

private_deps -

List of labels; optional

A list of targets that are implementation-only dependencies of the target being -built. Libraries/linker flags from these dependencies will be propagated to -dependent for linking, but artifacts/flags required for compilation (such as -.swiftmodule files, C headers, and search paths) will not be propagated.

-

Allowed kinds of dependencies are:

-
    -
  • swift_c_module, swift_import and swift_library (or anything -propagating SwiftInfo)
  • -
  • cc_library (or anything propagating CcInfo)
  • -
-

Additionally, on platforms that support Objective-C interop, objc_library -targets (or anything propagating the apple_common.Objc provider) are allowed -as dependencies. On platforms that do not support Objective-C interop (such as -Linux), those dependencies will be ignored.

swiftc_inputs -

List of labels; optional

Additional files that are referenced using $(location ...) in attributes that -support location expansion.

- - - + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | +| alwayslink | If true, any binary that depends (directly or indirectly) on this Swift module will link in all the object files for the files listed in srcs, even if some contain no symbols referenced by the binary. This is useful if your code isn't explicitly called by code in the binary; for example, if you rely on runtime checks for protocol conformances added in extensions in the library but do not directly reference any other symbols in the object file that adds that conformance. | Boolean | optional | False | +| copts | Additional compiler options that should be passed to swiftc. These strings are subject to $(location ...) and ["Make" variable](https://docs.bazel.build/versions/master/be/make-variables.html) expansion. | List of strings | optional | [] | +| data | The list of files needed by this target at runtime.

Files and targets named in the data attribute will appear in the *.runfiles area of this target, if it has one. This may include data files needed by a binary or library, or other programs needed by it. | List of labels | optional | [] | +| defines | A list of defines to add to the compilation command line.

Note that unlike C-family languages, Swift defines do not have values; they are simply identifiers that are either defined or undefined. So strings in this list should be simple identifiers, **not** name=value pairs.

Each string is prepended with -D and added to the command line. Unlike copts, these flags are added for the target and every target that depends on it, so use this attribute with caution. It is preferred that you add defines directly to copts, only using this feature in the rare case that a library needs to propagate a symbol up to those that depend on it. | List of strings | optional | [] | +| deps | A list of targets that are dependencies of the target being built, which will be linked into that target.

If the Swift toolchain supports implementation-only imports (private_deps on swift_library), then targets in deps are treated as regular (non-implementation-only) imports that are propagated both to their direct and indirect (transitive) dependents.

Allowed kinds of dependencies are:

* swift_c_module, swift_import and swift_library (or anything propagating SwiftInfo)

* cc_library (or anything propagating CcInfo)

Additionally, on platforms that support Objective-C interop, objc_library targets (or anything propagating the apple_common.Objc provider) are allowed as dependencies. On platforms that do not support Objective-C interop (such as Linux), those dependencies will be **ignored.** | List of labels | optional | [] | +| generated_header_name | The name of the generated Objective-C interface header. This name must end with a .h extension and cannot contain any path separators.

If this attribute is not specified, then the default behavior is to name the header ${target_name}-Swift.h.

This attribute is ignored if the toolchain does not support generating headers or if the target has the swift.no_generated_header feature enabled. | String | optional | "" | +| generates_header | If True, an Objective-C header will be generated for this target, in the same build package where the target is defined. By default, the name of the header is ${target_name}-Swift.h; this can be changed using the generated_header_name attribute.

Targets should only set this attribute to True if they export Objective-C APIs. A header generated for a target that does not export Objective-C APIs will be effectively empty (except for a large amount of prologue and epilogue code) and this is generally wasteful because the extra file needs to be propagated in the build graph and, when explicit modules are enabled, extra actions must be executed to compile the Objective-C module for the generated header. | Boolean | optional | False | +| linkopts | Additional linker options that should be passed to the linker for the binary that depends on this target. These strings are subject to $(location ...) and ["Make" variable](https://docs.bazel.build/versions/master/be/make-variables.html) expansion. | List of strings | optional | [] | +| module_name | The name of the Swift module being built.

If left unspecified, the module name will be computed based on the target's build label, by stripping the leading // and replacing /, :, and other non-identifier characters with underscores. | String | optional | "" | +| private_deps | A list of targets that are implementation-only dependencies of the target being built. Libraries/linker flags from these dependencies will be propagated to dependent for linking, but artifacts/flags required for compilation (such as .swiftmodule files, C headers, and search paths) will not be propagated.

Allowed kinds of dependencies are:

* swift_c_module, swift_import and swift_library (or anything propagating SwiftInfo)

* cc_library (or anything propagating CcInfo)

Additionally, on platforms that support Objective-C interop, objc_library targets (or anything propagating the apple_common.Objc provider) are allowed as dependencies. On platforms that do not support Objective-C interop (such as Linux), those dependencies will be **ignored.** | List of labels | optional | [] | +| srcs | A list of .swift source files that will be compiled into the library. | List of labels | required | | +| swiftc_inputs | Additional files that are referenced using $(location ...) in attributes that support location expansion. | List of labels | optional | [] | + + + + ## swift_module_alias -
-swift_module_alias(name, deps, compatible_with, deprecation, distribs, features, licenses,
-module_name, restricted_to, tags, testonly, visibility)
+
+swift_module_alias(name, deps, module_name)
 
Creates a Swift module that re-exports other modules. @@ -598,45 +286,23 @@ symbol is defined; it is not repeated by the alias module.) > `deps` in the new module. You depend on undocumented features at your own > risk, as they may change in a future version of Swift. - -### Attributes - - - - - - - - - - - - - - - - - - - - -
name -

Name; required

A unique name for this target.

deps -

List of labels; optional

A list of targets that are dependencies of the target being built, which will be -linked into that target. Allowed kinds are swift_import and swift_library -(or anything else propagating SwiftInfo).

module_name -

String; optional

The name of the Swift module being built.

-

If left unspecified, the module name will be computed based on the target's -build label, by stripping the leading // and replacing /, :, and other -non-identifier characters with underscores.

- - - + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | +| deps | A list of targets that are dependencies of the target being built, which will be linked into that target. Allowed kinds are swift_import and swift_library (or anything else propagating SwiftInfo). | List of labels | optional | [] | +| module_name | The name of the Swift module being built.

If left unspecified, the module name will be computed based on the target's build label, by stripping the leading // and replacing /, :, and other non-identifier characters with underscores. | String | optional | "" | + + + + ## swift_proto_library -
-swift_proto_library(name, deps, compatible_with, deprecation, distribs, features, licenses,
-restricted_to, tags, testonly, visibility)
+
+swift_proto_library(name, deps)
 
Generates a Swift library from protocol buffer sources. @@ -714,37 +380,23 @@ has `deps` that aren't needed. Removing those along with the `import` statement(s) will speed up downstream Swift compilation actions, because it prevents unused modules from being loaded by `swiftc`. - -### Attributes - - - - - - - - - - - - - - - - -
name -

Name; required

A unique name for this target.

deps -

List of labels; optional

Exactly one proto_library target (or any target that propagates a proto -provider) from which the Swift library should be generated.

- - - + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | +| deps | Exactly one proto_library target (or any target that propagates a proto provider) from which the Swift library should be generated. | List of labels | optional | [] | + + + + ## swift_test -
-swift_test(name, deps, srcs, data, args, compatible_with, copts, defines, deprecation, distribs,
-features, flaky, licenses, linkopts, local, malloc, module_name, restricted_to, shardcount, size,
-stamp, swiftc_inputs, tags, testonly, timeout, visibility)
+
+swift_test(name, copts, data, defines, deps, linkopts, malloc, module_name, srcs, stamp,
+           swiftc_inputs)
 
Compiles and links Swift code into an executable test target. @@ -779,115 +431,22 @@ swift_test( You can also disable this feature for all the tests in a package by applying it to your BUILD file's `package()` declaration instead of the individual targets. - -### Attributes - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
name -

Name; required

A unique name for this target.

deps -

List of labels; optional

A list of targets that are dependencies of the target being built, which will be -linked into that target.

-

If the Swift toolchain supports implementation-only imports (private_deps on -swift_library), then targets in deps are treated as regular -(non-implementation-only) imports that are propagated both to their direct and -indirect (transitive) dependents.

-

Allowed kinds of dependencies are:

-
    -
  • swift_c_module, swift_import and swift_library (or anything -propagating SwiftInfo)
  • -
  • cc_library (or anything propagating CcInfo)
  • -
-

Additionally, on platforms that support Objective-C interop, objc_library -targets (or anything propagating the apple_common.Objc provider) are allowed -as dependencies. On platforms that do not support Objective-C interop (such as -Linux), those dependencies will be ignored.

srcs -

List of labels; optional

A list of .swift source files that will be compiled into the library.

data -

List of labels; optional

The list of files needed by this target at runtime.

-

Files and targets named in the data attribute will appear in the *.runfiles -area of this target, if it has one. This may include data files needed by a -binary or library, or other programs needed by it.

copts -

List of strings; optional

Additional compiler options that should be passed to swiftc. These strings are -subject to $(location ...) expansion.

defines -

List of strings; optional

A list of defines to add to the compilation command line.

-

Note that unlike C-family languages, Swift defines do not have values; they are -simply identifiers that are either defined or undefined. So strings in this list -should be simple identifiers, not name=value pairs.

-

Each string is prepended with -D and added to the command line. Unlike -copts, these flags are added for the target and every target that depends on -it, so use this attribute with caution. It is preferred that you add defines -directly to copts, only using this feature in the rare case that a library -needs to propagate a symbol up to those that depend on it.

linkopts -

List of strings; optional

Additional linker options that should be passed to clang. These strings are -subject to $(location ...) expansion.

malloc -

Label; optional; default is @bazel_tools//tools/cpp:malloc

Override the default dependency on malloc.

-

By default, Swift binaries are linked against @bazel_tools//tools/cpp:malloc", -which is an empty library and the resulting binary will use libc's malloc. -This label must refer to a cc_library rule.

module_name -

String; optional

The name of the Swift module being built.

-

If left unspecified, the module name will be computed based on the target's -build label, by stripping the leading // and replacing /, :, and other -non-identifier characters with underscores.

stamp -

Integer; optional; default is 0

Enable or disable link stamping; that is, whether to encode build information -into the binary. Possible values are:

-
    -
  • stamp = 1: Stamp the build information into the binary. Stamped binaries are -only rebuilt when their dependencies change. Use this if there are tests that -depend on the build information.
  • -
  • stamp = 0: Always replace build information by constant values. This gives -good build result caching.
  • -
  • stamp = -1: Embedding of build information is controlled by the ---[no]stamp flag.
  • -
swiftc_inputs -

List of labels; optional

Additional files that are referenced using $(location ...) in attributes that -support location expansion.

+ +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | +| copts | Additional compiler options that should be passed to swiftc. These strings are subject to $(location ...) and ["Make" variable](https://docs.bazel.build/versions/master/be/make-variables.html) expansion. | List of strings | optional | [] | +| data | The list of files needed by this target at runtime.

Files and targets named in the data attribute will appear in the *.runfiles area of this target, if it has one. This may include data files needed by a binary or library, or other programs needed by it. | List of labels | optional | [] | +| defines | A list of defines to add to the compilation command line.

Note that unlike C-family languages, Swift defines do not have values; they are simply identifiers that are either defined or undefined. So strings in this list should be simple identifiers, **not** name=value pairs.

Each string is prepended with -D and added to the command line. Unlike copts, these flags are added for the target and every target that depends on it, so use this attribute with caution. It is preferred that you add defines directly to copts, only using this feature in the rare case that a library needs to propagate a symbol up to those that depend on it. | List of strings | optional | [] | +| deps | A list of targets that are dependencies of the target being built, which will be linked into that target.

If the Swift toolchain supports implementation-only imports (private_deps on swift_library), then targets in deps are treated as regular (non-implementation-only) imports that are propagated both to their direct and indirect (transitive) dependents.

Allowed kinds of dependencies are:

* swift_c_module, swift_import and swift_library (or anything propagating SwiftInfo)

* cc_library (or anything propagating CcInfo)

Additionally, on platforms that support Objective-C interop, objc_library targets (or anything propagating the apple_common.Objc provider) are allowed as dependencies. On platforms that do not support Objective-C interop (such as Linux), those dependencies will be **ignored.** | List of labels | optional | [] | +| linkopts | Additional linker options that should be passed to clang. These strings are subject to $(location ...) expansion. | List of strings | optional | [] | +| malloc | Override the default dependency on malloc.

By default, Swift binaries are linked against @bazel_tools//tools/cpp:malloc", which is an empty library and the resulting binary will use libc's malloc. This label must refer to a cc_library rule. | Label | optional | @bazel_tools//tools/cpp:malloc | +| module_name | The name of the Swift module being built.

If left unspecified, the module name will be computed based on the target's build label, by stripping the leading // and replacing /, :, and other non-identifier characters with underscores. | String | optional | "" | +| srcs | A list of .swift source files that will be compiled into the library. | List of labels | optional | [] | +| stamp | Enable or disable link stamping; that is, whether to encode build information into the binary. Possible values are:

* stamp = 1: Stamp the build information into the binary. Stamped binaries are only rebuilt when their dependencies change. Use this if there are tests that depend on the build information.

* stamp = 0: Always replace build information by constant values. This gives good build result caching.

* stamp = -1: Embedding of build information is controlled by the --[no]stamp flag. | Integer | optional | 0 | +| swiftc_inputs | Additional files that are referenced using $(location ...) in attributes that support location expansion. | List of labels | optional | [] | + diff --git a/swift/internal/attrs.bzl b/swift/internal/attrs.bzl index d27aa525f..2be478884 100644 --- a/swift/internal/attrs.bzl +++ b/swift/internal/attrs.bzl @@ -104,7 +104,7 @@ A list of `.swift` source files that will be compiled into the library. "copts": attr.string_list( doc = """\ Additional compiler options that should be passed to `swiftc`. These strings are -subject to `$(location ...)` and "Make" variable expansion. +subject to `$(location ...)` and ["Make" variable](https://docs.bazel.build/versions/master/be/make-variables.html) expansion. """, ), "defines": attr.string_list( @@ -248,7 +248,7 @@ def swift_library_rule_attrs( doc = """\ Additional linker options that should be passed to the linker for the binary that depends on this target. These strings are subject to `$(location ...)` -and "Make" variable expansion. +and ["Make" variable](https://docs.bazel.build/versions/master/be/make-variables.html) expansion. """, ), "alwayslink": attr.bool( @@ -271,8 +271,7 @@ a `.h` extension and cannot contain any path separators. If this attribute is not specified, then the default behavior is to name the header `${target_name}-Swift.h`. -It is an error to specify a value for this attribute when `generates_header` is -False. +This attribute is ignored if the toolchain does not support generating headers. """, mandatory = False, ), diff --git a/swift/swift.bzl b/swift/swift.bzl index 7832afb25..6bcb31045 100644 --- a/swift/swift.bzl +++ b/swift/swift.bzl @@ -16,6 +16,15 @@ This file is the public interface that users should import to use the Swift rules. Do not import definitions from the `internal` subdirectory directly. + +To use the Swift build rules in your BUILD files, load them from +`@build_bazel_rules_swift//swift:swift.bzl`. + +For example: + +```build +load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library") +``` """ load( From 4ee4be0f8a6fbe1e8c3ba487a182f244da19ea4f Mon Sep 17 00:00:00 2001 From: Alex Eagle Date: Fri, 30 Apr 2021 16:46:12 -0700 Subject: [PATCH 099/152] Generate providers.md from sources (#599) --- doc/BUILD.bazel | 58 ++++++-- doc/providers.md | 335 ++++++++++++----------------------------------- doc/rules.md | 2 +- 3 files changed, 136 insertions(+), 259 deletions(-) diff --git a/doc/BUILD.bazel b/doc/BUILD.bazel index 3a7d71565..4e3f25efe 100644 --- a/doc/BUILD.bazel +++ b/doc/BUILD.bazel @@ -13,9 +13,16 @@ _RULES_SYMBOLS = [ "swift_test", ] +_PROVIDERS_SYMBOLS = [ + "SwiftInfo", + "SwiftToolchainInfo", + "SwiftProtoInfo", + "SwiftUsageInfo", +] + write_file( - name = "gen_header", - out = "header.vm", + name = "rules_header", + out = "rules_header.vm", content = [ "", "", @@ -27,19 +34,54 @@ write_file( ], ) +write_file( + name = "providers_header", + out = "providers_header.vm", + content = [ + "", + "", + "The providers described below are propagated and required by various Swift", + "build rules. Clients interested in writing custom rules that interface", + "with the rules in this package should use these providers to communicate", + "with the Swift build rules as needed.", + "", + "On this page:", + "", + ] + [" * [{0}](#{0})".format(r) for r in _PROVIDERS_SYMBOLS] + [ + "", + ], +) + stardoc( - name = "doc", - out = "swift.md", - header_template = ":header.vm", + name = "rules_doc", + out = "rules.md_", + header_template = ":rules_header.vm", input = "//swift:swift.bzl", symbol_names = _RULES_SYMBOLS, deps = ["//swift"], ) +stardoc( + name = "providers_doc", + out = "providers.md_", + header_template = ":providers_header.vm", + input = "//swift:swift.bzl", + symbol_names = _PROVIDERS_SYMBOLS, + deps = ["//swift"], +) + # To make this test pass, run -# bazel build doc:all && cp bazel-bin/doc/swift.md doc/rules.md +# bazel build doc:all && cp bazel-bin/doc/rules.md_ doc/rules.md diff_test( - name = "test", - file1 = "swift.md", + name = "test_rules", + file1 = "rules.md_", file2 = "rules.md", ) + +# To make this test pass, run +# bazel build doc:all && cp bazel-bin/doc/providers.md_ doc/providers.md +diff_test( + name = "test_providers", + file1 = "providers.md_", + file2 = "providers.md", +) diff --git a/doc/providers.md b/doc/providers.md index 6e68f71ab..8965560ac 100644 --- a/doc/providers.md +++ b/doc/providers.md @@ -1,8 +1,4 @@ -# Providers - - - - + The providers described below are propagated and required by various Swift build rules. Clients interested in writing custom rules that interface @@ -15,9 +11,15 @@ On this page: * [SwiftToolchainInfo](#SwiftToolchainInfo) * [SwiftProtoInfo](#SwiftProtoInfo) * [SwiftUsageInfo](#SwiftUsageInfo) - + + + ## SwiftInfo +
+SwiftInfo(direct_modules, transitive_modules)
+
+ Contains information about the compiled artifacts of a Swift module. This provider contains a large number of fields and many custom rules may not @@ -25,260 +27,93 @@ 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. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
direct_defines

List of strings. The values specified by the defines attribute of the -library that directly propagated this provider.

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.

direct_swiftdocs

List of Files. The Swift documentation (.swiftdoc) files for the library -that directly propagated this provider.

direct_swiftmodules

List of Files. The Swift modules (.swiftmodule) for the library that -directly propagated this provider.

module_name

String. The name of the Swift module represented by the target that directly -propagated this provider.

-

This field will be equal to the explicitly assigned module name (if present); -otherwise, it will be equal to the autogenerated module name.

swift_version

String. The version of the Swift language that was used when compiling the -propagating target; that is, the value passed via the -swift-version compiler -flag. This will be None if the flag was not set.

transitive_defines

Depset of strings. The transitive defines specified for the library that -propagated this provider and all of its dependencies.

transitive_generated_headers

Depset of Files. The transitive generated header files that can be used by -Objective-C sources to interop with the transitive Swift libraries.

transitive_modulemaps

Depset of Files. The transitive module map files that will be passed to -Clang using the -fmodule-map-file option.

-

This field is deprecated; use transitive_modules instead.

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.

transitive_swiftdocs

Depset of Files. The transitive Swift documentation (.swiftdoc) files -emitted by the library that propagated this provider and all of its -dependencies.

transitive_swiftinterfaces

Depset of Files. The transitive Swift interface (.swiftinterface) files -emitted by the library that propagated this provider and all of its -dependencies.

transitive_swiftmodules

Depset of Files. The transitive Swift modules (.swiftmodule) emitted by -the library that propagated this provider and all of its dependencies.

- - - + +**FIELDS** + + +| Name | Description | +| :------------- | :------------- | +| 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. | + + + + +## SwiftProtoInfo + +
+SwiftProtoInfo(module_mappings, pbswift_files)
+
+ +Propagates Swift-specific information about a `proto_library`. + +**FIELDS** + + +| Name | Description | +| :------------- | :------------- | +| module_mappings | Sequence of structs. Each struct contains module_name and proto_file_paths fields that denote the transitive mappings from .proto files to Swift modules. This allows messages that reference messages in other libraries to import those modules in generated code. | +| pbswift_files | Depset of Files. The transitive Swift source files (.pb.swift) generated from the .proto files. | + + + + ## SwiftToolchainInfo +
+SwiftToolchainInfo(action_configs, all_files, cc_toolchain_info, cpu,
+                   generated_header_module_implicit_deps_providers, implicit_deps_providers,
+                   linker_opts_producer, linker_supports_filelist, object_format, requested_features,
+                   root_dir, supports_objc_interop, swift_worker, system_name, test_configuration,
+                   tool_configs, unsupported_features)
+
+ + Propagates information about a Swift toolchain to compilation and linking rules that use the toolchain. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
action_configs

This field is an internal implementation detail of the build rules.

all_files

A depset of Files containing all the Swift toolchain files (tools, -libraries, and other resource files) so they can be passed as tools to actions -using this toolchain.

cc_toolchain_info

The cc_common.CcToolchainInfo provider from the Bazel C++ toolchain that this -Swift toolchain depends on.

command_line_copts

List of strings. Flags that were passed to Bazel using the --swiftcopt -command line flag. These flags have the highest precedence; they are added to -compilation command lines after the toolchain default flags -(SwiftToolchainInfo.swiftc_copts) and after flags specified in the copts -attributes of Swift targets.

cpu

String. The CPU architecture that the toolchain is targeting.

linker_opts_producer

Skylib partial. A partial function that returns the flags that should be -passed to Clang to link a binary or test target with the Swift runtime -libraries.

-

The partial should be called with two arguments:

-
    -
  • is_static: A Boolean value indicating whether to link against the static -or dynamic runtime libraries.
  • -
  • is_test: A Boolean value indicating whether the target being linked is a -test target.
  • -
object_format

String. The object file format of the platform that the toolchain is -targeting. The currently supported values are "elf" and "macho".

optional_implicit_deps

List of Targets. Library targets that should be added as implicit -dependencies of any swift_library, swift_binary, or swift_test target that -does not have the feature swift.minimal_deps applied.

requested_features

List of strings. Features that should be implicitly enabled by default for -targets built using this toolchain, unless overridden by the user by listing -their negation in the features attribute of a target/package or in the ---features command line flag.

-

These features determine various compilation and debugging behaviors of the -Swift build rules, and they are also passed to the C++ APIs used when linking -(so features defined in CROSSTOOL may be used here).

required_implicit_deps

List of Targets. Library targets that should be unconditionally added as -implicit dependencies of any swift_library, swift_binary, or swift_test -target.

root_dir

String. The workspace-relative root directory of the toolchain.

supports_objc_interop

Boolean. Indicates whether or not the toolchain supports Objective-C interop.

swift_worker

File. The executable representing the worker executable used to invoke the -compiler and other Swift tools (for both incremental and non-incremental -compiles).

system_name

String. The name of the operating system that the toolchain is targeting.

test_configuration

Struct containing two fields:

-
    -
  • env: A dict of environment variables to be set when running tests -that were built with this toolchain.
  • -
  • execution_requirements: A dict of execution requirements for tests -that were built with this toolchain.
  • -
-

This is used, for example, with Xcode-based toolchains to ensure that the -xctest helper and coverage tools are found in the correct developer -directory when running tests.

tool_configs

This field is an internal implementation detail of the build rules.

unsupported_features

List of strings. Features that should be implicitly disabled by default for -targets built using this toolchain, unless overridden by the user by listing -them in the features attribute of a target/package or in the --features -command line flag.

-

These features determine various compilation and debugging behaviors of the -Swift build rules, and they are also passed to the C++ APIs used when linking -(so features defined in CROSSTOOL may be used here).

- - - -## SwiftProtoInfo -Propagates Swift-specific information about a `proto_library`. +**FIELDS** + + +| Name | Description | +| :------------- | :------------- | +| action_configs | This field is an internal implementation detail of the build rules. | +| all_files | A depset of Files containing all the Swift toolchain files (tools, libraries, and other resource files) so they can be passed as tools to actions using this toolchain. | +| cc_toolchain_info | The cc_common.CcToolchainInfo provider from the Bazel C++ toolchain that this Swift toolchain depends on. | +| cpu | String. The CPU architecture that the toolchain is targeting. | +| generated_header_module_implicit_deps_providers | A struct with the following fields, which are providers from targets that should be treated as compile-time inputs to actions that precompile the explicit module for the generated Objective-C header of a Swift module:

* cc_infos: A list of CcInfo providers from targets specified as the toolchain's implicit dependencies. * objc_infos: A list of apple_common.Objc providers from targets specified as the toolchain's implicit dependencies. * swift_infos: A list of SwiftInfo providers from targets specified as the toolchain's implicit dependencies.

This is used to provide modular dependencies for the fixed inclusions (Darwin, Foundation) that are unconditionally emitted in those files.

For ease of use, this field is never None; it will always be a valid struct containing the fields described above, even if those lists are empty. | +| implicit_deps_providers | A struct with the following fields, which represent providers from targets that should be added as implicit dependencies of any Swift compilation or linking target (but not to precompiled explicit C/Objective-C modules):

* cc_infos: A list of CcInfo providers from targets specified as the toolchain's implicit dependencies. * objc_infos: A list of apple_common.Objc providers from targets specified as the toolchain's implicit dependencies. * swift_infos: A list of SwiftInfo providers from targets specified as the toolchain's implicit dependencies.

For ease of use, this field is never None; it will always be a valid struct containing the fields described above, even if those lists are empty. | +| linker_opts_producer | Skylib partial. A partial function that returns the flags that should be passed to Clang to link a binary or test target with the Swift runtime libraries.

The partial should be called with two arguments:

* is_static: A Boolean value indicating whether to link against the static or dynamic runtime libraries.

* is_test: A Boolean value indicating whether the target being linked is a test target. | +| linker_supports_filelist | Boolean. Indicates whether or not the toolchain's linker supports the input files passed to it via a file list. | +| object_format | String. The object file format of the platform that the toolchain is targeting. The currently supported values are "elf" and "macho". | +| requested_features | List of strings. Features that should be implicitly enabled by default for targets built using this toolchain, unless overridden by the user by listing their negation in the features attribute of a target/package or in the --features command line flag.

These features determine various compilation and debugging behaviors of the Swift build rules, and they are also passed to the C++ APIs used when linking (so features defined in CROSSTOOL may be used here). | +| root_dir | String. The workspace-relative root directory of the toolchain. | +| supports_objc_interop | Boolean. Indicates whether or not the toolchain supports Objective-C interop. | +| swift_worker | File. The executable representing the worker executable used to invoke the compiler and other Swift tools (for both incremental and non-incremental compiles). | +| system_name | String. The name of the operating system that the toolchain is targeting. | +| test_configuration | Struct containing two fields:

* env: A dict of environment variables to be set when running tests that were built with this toolchain.

* execution_requirements: A dict of execution requirements for tests that were built with this toolchain.

This is used, for example, with Xcode-based toolchains to ensure that the xctest helper and coverage tools are found in the correct developer directory when running tests. | +| tool_configs | This field is an internal implementation detail of the build rules. | +| unsupported_features | List of strings. Features that should be implicitly disabled by default for targets built using this toolchain, unless overridden by the user by listing them in the features attribute of a target/package or in the --features command line flag.

These features determine various compilation and debugging behaviors of the Swift build rules, and they are also passed to the C++ APIs used when linking (so features defined in CROSSTOOL may be used here). | + + + - - - - - - - - - - - - - - - -
module_mappings

Sequence of structs. Each struct contains module_name and -proto_file_paths fields that denote the transitive mappings from .proto -files to Swift modules. This allows messages that reference messages in other -libraries to import those modules in generated code.

pbswift_files

Depset of Files. The transitive Swift source files (.pb.swift) generated -from the .proto files.

- - - ## SwiftUsageInfo +
+SwiftUsageInfo(toolchain)
+
+ A provider that indicates that Swift was used by a target or any target that it depends on, and specifically which toolchain was used. - - - - - - - - - - - -
toolchain

The Swift toolchain that was used to build the targets propagating this -provider.

+ +**FIELDS** + + +| Name | Description | +| :------------- | :------------- | +| toolchain | The Swift toolchain that was used to build the targets propagating this provider. | + diff --git a/doc/rules.md b/doc/rules.md index f8cd92984..cfdd59204 100644 --- a/doc/rules.md +++ b/doc/rules.md @@ -251,7 +251,7 @@ Compiles and links Swift code into a static library and Swift module. | data | The list of files needed by this target at runtime.

Files and targets named in the data attribute will appear in the *.runfiles area of this target, if it has one. This may include data files needed by a binary or library, or other programs needed by it. | List of labels | optional | [] | | defines | A list of defines to add to the compilation command line.

Note that unlike C-family languages, Swift defines do not have values; they are simply identifiers that are either defined or undefined. So strings in this list should be simple identifiers, **not** name=value pairs.

Each string is prepended with -D and added to the command line. Unlike copts, these flags are added for the target and every target that depends on it, so use this attribute with caution. It is preferred that you add defines directly to copts, only using this feature in the rare case that a library needs to propagate a symbol up to those that depend on it. | List of strings | optional | [] | | deps | A list of targets that are dependencies of the target being built, which will be linked into that target.

If the Swift toolchain supports implementation-only imports (private_deps on swift_library), then targets in deps are treated as regular (non-implementation-only) imports that are propagated both to their direct and indirect (transitive) dependents.

Allowed kinds of dependencies are:

* swift_c_module, swift_import and swift_library (or anything propagating SwiftInfo)

* cc_library (or anything propagating CcInfo)

Additionally, on platforms that support Objective-C interop, objc_library targets (or anything propagating the apple_common.Objc provider) are allowed as dependencies. On platforms that do not support Objective-C interop (such as Linux), those dependencies will be **ignored.** | List of labels | optional | [] | -| generated_header_name | The name of the generated Objective-C interface header. This name must end with a .h extension and cannot contain any path separators.

If this attribute is not specified, then the default behavior is to name the header ${target_name}-Swift.h.

This attribute is ignored if the toolchain does not support generating headers or if the target has the swift.no_generated_header feature enabled. | String | optional | "" | +| generated_header_name | The name of the generated Objective-C interface header. This name must end with a .h extension and cannot contain any path separators.

If this attribute is not specified, then the default behavior is to name the header ${target_name}-Swift.h.

This attribute is ignored if the toolchain does not support generating headers. | String | optional | "" | | generates_header | If True, an Objective-C header will be generated for this target, in the same build package where the target is defined. By default, the name of the header is ${target_name}-Swift.h; this can be changed using the generated_header_name attribute.

Targets should only set this attribute to True if they export Objective-C APIs. A header generated for a target that does not export Objective-C APIs will be effectively empty (except for a large amount of prologue and epilogue code) and this is generally wasteful because the extra file needs to be propagated in the build graph and, when explicit modules are enabled, extra actions must be executed to compile the Objective-C module for the generated header. | Boolean | optional | False | | linkopts | Additional linker options that should be passed to the linker for the binary that depends on this target. These strings are subject to $(location ...) and ["Make" variable](https://docs.bazel.build/versions/master/be/make-variables.html) expansion. | List of strings | optional | [] | | module_name | The name of the Swift module being built.

If left unspecified, the module name will be computed based on the target's build label, by stripping the leading // and replacing /, :, and other non-identifier characters with underscores. | String | optional | "" | From ec1c3ff846d7684f8807e9378859527ada8bcc61 Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Wed, 7 Apr 2021 10:49:13 -0700 Subject: [PATCH 100/152] Add `swift_common.create_swift_interop_info`. This API allows custom rules to opt-in to "lightweight Swift interop". If they are already propagating a `CcInfo` with a compilation context, then `swift_clang_module_aspect` will detect this provider and generate a module name/module map (if necessary), and also compile the explicit module (if enabled). This frees the custom rule from having to understand details of the Swift compilation APIs, or even having to have a dependency on the Swift toolchain at all. PiperOrigin-RevId: 367251939 (cherry picked from commit 9be992e3d6c696978ea62a5b2def7d7e977b8df1) --- swift/internal/swift_clang_module_aspect.bzl | 184 +++++++++++++++---- swift/internal/swift_common.bzl | 7 +- 2 files changed, 159 insertions(+), 32 deletions(-) diff --git a/swift/internal/swift_clang_module_aspect.bzl b/swift/internal/swift_clang_module_aspect.bzl index 9131e6f70..8009c82f7 100644 --- a/swift/internal/swift_clang_module_aspect.bzl +++ b/swift/internal/swift_clang_module_aspect.bzl @@ -47,6 +47,86 @@ _SINGLE_TARGET_ASPECT_ATTRS = [ "_jre_lib", ] +_SwiftInteropInfo = provider( + doc = """\ +Contains minimal information required for the `swift_clang_module_aspect` to +generate a module map and/or precompiled module for a target so that it can +expose C/Objective-C APIs to Swift. +""", + fields = { + "additional_swift_infos": """\ +A list of additional `SwiftInfo` providers from dependencies that aren't +reachable via the `deps` attribute of the rule propagating this provider, but +which should be treated as dependencies of the C/Objective-C module. +""", + "module_map": """\ +A `File` representing an existing module map that should be used to represent +the module, or `None` if the module map should be generated based on the headers +in the target's compilation context. +""", + "module_name": """\ +A string denoting the name of the module, or `None` if the name should be +derived automatically from the target label. +""", + }, +) + +def create_swift_interop_info( + *, + additional_swift_infos = [], + module_map = None, + module_name = None): + """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 the custom rule to simply return + `swift_common.create_swift_interop_info()` without any arguments; this + tells `swift_clang_module_aspect` to derive the module name from the target + label and create a module map using the headers from the compilation + context. + + 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. + + The `swift_clang_module_aspect` automatically traverses the `deps` attribute + of even custom rules, so those rules don't need to do anything extra to + collect those dependencies. However, if a custom rule has dependencies in + other attributes (such as a runtime library specified as the default value + of a private attribute), it should pass the `SwiftInfo` provider from that + target into this function via the `additional_swift_infos` argument. + + Args: + additional_swift_infos: A list of additional `SwiftInfo` providers from + dependencies that aren't reachable via the `deps` attribute of the + rule propagating this provider, but which should be treated as + dependencies of the C/Objective-C module. + module_map: A `File` representing an existing module map that should be + used to represent the module, or `None` 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. + module_name: A string denoting the name of the module, or `None` if the + name should be derived automatically from the target label. + + Returns: + A provider whose type/layout is an implementation detail and should not + be relied upon. + """ + if module_map and not module_name: + fail("'module_name' must be specified when 'module_map' is specified.") + + return _SwiftInteropInfo( + additional_swift_infos = additional_swift_infos, + module_map = module_map, + module_name = module_name, + ) + def _tagged_target_module_name(label, tags): """Returns the module name of a `swift_module`-tagged target. @@ -146,17 +226,21 @@ def _module_info_for_target( aspect_ctx, compilation_context, dependent_module_names, - feature_configuration): + feature_configuration, + module_name): """Returns the module name and module map for the target. Args: - aspect_ctx: The aspect context. target: The target for which the module map is being generated. + aspect_ctx: The aspect context. compilation_context: The C++ compilation context that provides the headers for the module. dependent_module_names: A `list` of names of Clang modules that are direct dependencies of the target whose module map is being written. feature_configuration: A Swift feature configuration. + module_name: The module name to prefer (if we're generating a module map + from `_SwiftInteropInfo`), or None to derive it from other + properties of the target. Returns: A tuple containing the module name (a string) and module map file (a @@ -164,7 +248,7 @@ def _module_info_for_target( """ attr = aspect_ctx.rule.attr - if apple_common.Objc in target: + if not module_name and apple_common.Objc in target: # TODO(b/142867898): For `objc_library`, stop using the module map from # the Objc provider and generate our own. (For imported frameworks, # continue using the module map included with it.) @@ -220,15 +304,26 @@ def _module_info_for_target( ) return module_name, module_map_file - # For all other targets, there is no mechanism to provide a custom - # module map, and we only generate one if the target is tagged. - module_name = _tagged_target_module_name( - label = target.label, - tags = attr.tags, - ) - if not module_name: + # If a target doesn't have any headers (and if we're on this code path, it + # didn't provide an explicit module map), then don't generate a module map + # for it. Such modules define nothing and only waste space on the + # compilation command line and add more work for the compiler. + if not ( + compilation_context.direct_headers or + compilation_context.direct_textual_headers + ): return None, None + if not module_name: + # For all other targets, there is no mechanism to provide a custom + # module map, and we only generate one if the target is tagged. + module_name = _tagged_target_module_name( + label = target.label, + tags = attr.tags, + ) + if not module_name: + return None, None + module_map_file = _generate_module_map( actions = aspect_ctx.actions, compilation_context = compilation_context, @@ -239,20 +334,30 @@ def _module_info_for_target( ) return module_name, module_map_file -def _handle_cc_target( +def _handle_module( aspect_ctx, + compilation_context, feature_configuration, + module_map_file, + module_name, swift_infos, swift_toolchain, target): - """Processes a C++ target that is a dependency of a Swift target. + """Processes a C/Objective-C target that is a dependency of a Swift target. Args: aspect_ctx: The aspect's context. + compilation_context: The `CcCompilationContext` containing the target's + headers. feature_configuration: The current feature configuration. + module_map_file: The `.modulemap` file that defines the module, or None + if it should be inferred from other properties of the target (for + legacy support). + module_name: The name of the module, or None if it should be inferred + from other properties of the target (for legacy support). swift_infos: The `SwiftInfo` providers of the current target's dependencies, which should be merged into the `SwiftInfo` provider - created and returned for this C++ target. + created and returned for this target. swift_toolchain: The Swift toolchain being used to build this target. target: The C++ target to which the aspect is currently being applied. @@ -261,13 +366,6 @@ def _handle_cc_target( """ attr = aspect_ctx.rule.attr - # TODO(b/142867898): Only check `CcInfo` once all rules correctly propagate - # it. - if CcInfo in target: - compilation_context = target[CcInfo].compilation_context - else: - compilation_context = None - if swift_infos: merged_swift_info = create_swift_info(swift_infos = swift_infos) else: @@ -281,13 +379,18 @@ def _handle_cc_target( if module.clang: dependent_module_names.append(module.name) - module_name, module_map_file = _module_info_for_target( - target = target, - aspect_ctx = aspect_ctx, - compilation_context = compilation_context, - dependent_module_names = dependent_module_names, - feature_configuration = feature_configuration, - ) + # If we weren't passed a module map (i.e., from a `_SwiftInteropInfo` + # provider), infer it and the module name based on properties of the rule to + # support legacy rules. + if not module_map_file: + module_name, module_map_file = _module_info_for_target( + target = target, + aspect_ctx = aspect_ctx, + compilation_context = compilation_context, + dependent_module_names = dependent_module_names, + feature_configuration = feature_configuration, + module_name = module_name, + ) if not module_map_file: if merged_swift_info: @@ -389,12 +492,31 @@ def _swift_clang_module_aspect_impl(target, aspect_ctx): unsupported_features = aspect_ctx.disabled_features, ) - # TODO(b/142867898): Only check `CcInfo` once all native rules correctly - # propagate both. - if apple_common.Objc in target or CcInfo in target: - return _handle_cc_target( + if CcInfo in target: + compilation_context = target[CcInfo].compilation_context + else: + compilation_context = None + + if _SwiftInteropInfo in target: + interop_info = target[_SwiftInteropInfo] + swift_infos.extend(interop_info.additional_swift_infos) + module_map_file = interop_info.module_map + module_name = interop_info.module_name + else: + module_map_file = None + module_name = None + + if ( + _SwiftInteropInfo in target or + apple_common.Objc in target or + CcInfo in target + ): + return _handle_module( aspect_ctx = aspect_ctx, + compilation_context = compilation_context, feature_configuration = feature_configuration, + module_map_file = module_map_file, + module_name = module_name, swift_infos = swift_infos, swift_toolchain = swift_toolchain, target = target, diff --git a/swift/internal/swift_common.bzl b/swift/internal/swift_common.bzl index 98ebd736c..ab8192f74 100644 --- a/swift/internal/swift_common.bzl +++ b/swift/internal/swift_common.bzl @@ -49,7 +49,11 @@ load( "create_swift_info", "create_swift_module", ) -load(":swift_clang_module_aspect.bzl", "swift_clang_module_aspect") +load( + ":swift_clang_module_aspect.bzl", + "create_swift_interop_info", + "swift_clang_module_aspect", +) # The exported `swift_common` module, which defines the public API for directly # invoking actions that compile Swift code from other rules. @@ -61,6 +65,7 @@ swift_common = struct( create_clang_module = create_clang_module, create_module = create_module, create_swift_info = create_swift_info, + create_swift_interop_info = create_swift_interop_info, create_swift_module = create_swift_module, derive_module_name = derive_module_name, is_enabled = is_feature_enabled, From 3009fc21292a4e4382e39e29a63265b8751bb46c Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Fri, 9 Apr 2021 11:43:59 -0700 Subject: [PATCH 101/152] Move swift_clang_module_aspect out of swift_common and directly expose it. RELNOTES: swift_clang_module_aspect is directly exported instead of being in swift_common. PiperOrigin-RevId: 367673524 (cherry picked from commit bf8243d1732b7cc48e99c045ebd03387014e620e) --- swift/internal/swift_binary_test.bzl | 3 ++- swift/internal/swift_clang_module_aspect.bzl | 8 ++++---- swift/internal/swift_common.bzl | 7 +------ swift/internal/swift_library.bzl | 5 +++-- swift/swift.bzl | 5 +++++ 5 files changed, 15 insertions(+), 13 deletions(-) diff --git a/swift/internal/swift_binary_test.bzl b/swift/internal/swift_binary_test.bzl index 598454080..2a4490882 100644 --- a/swift/internal/swift_binary_test.bzl +++ b/swift/internal/swift_binary_test.bzl @@ -21,6 +21,7 @@ load(":derived_files.bzl", "derived_files") load(":feature_names.bzl", "SWIFT_FEATURE_BUNDLED_XCTESTS") load(":linking.bzl", "register_link_binary_action") load(":providers.bzl", "SwiftToolchainInfo") +load(":swift_clang_module_aspect.bzl", "swift_clang_module_aspect") load(":swift_common.bzl", "swift_common") load(":utils.bzl", "expand_locations") @@ -35,7 +36,7 @@ def _binary_rule_attrs(stamp_default): """ return dicts.add( swift_common.compilation_attrs( - additional_deps_aspects = [swift_common.swift_clang_module_aspect], + additional_deps_aspects = [swift_clang_module_aspect], requires_srcs = False, ), { diff --git a/swift/internal/swift_clang_module_aspect.bzl b/swift/internal/swift_clang_module_aspect.bzl index 8009c82f7..872532934 100644 --- a/swift/internal/swift_clang_module_aspect.bzl +++ b/swift/internal/swift_clang_module_aspect.bzl @@ -547,10 +547,10 @@ depends on an `objc_library` that depends on a `swift_library`). It also manages module map generation for `cc_library` targets that have the `swift_module` tag. This tag may take one of two forms: - * `swift_module`: By itself, this indicates that the target is compatible - with Swift and should be given a module name that is derived from its - target label. - * `swift_module=name`: The module should be given the name `name`. +* `swift_module`: By itself, this indicates that the target is compatible + with Swift and should be given a module name that is derived from its + target label. +* `swift_module=name`: The module should be given the name `name`. Note that the public headers of such `cc_library` targets must be parsable as C, since Swift does not support C++ interop at this time. diff --git a/swift/internal/swift_common.bzl b/swift/internal/swift_common.bzl index ab8192f74..6c32f89ae 100644 --- a/swift/internal/swift_common.bzl +++ b/swift/internal/swift_common.bzl @@ -49,11 +49,7 @@ load( "create_swift_info", "create_swift_module", ) -load( - ":swift_clang_module_aspect.bzl", - "create_swift_interop_info", - "swift_clang_module_aspect", -) +load(":swift_clang_module_aspect.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. @@ -71,7 +67,6 @@ swift_common = struct( is_enabled = is_feature_enabled, library_rule_attrs = swift_library_rule_attrs, precompile_clang_module = precompile_clang_module, - swift_clang_module_aspect = swift_clang_module_aspect, swift_runtime_linkopts = swift_runtime_linkopts, toolchain_attrs = swift_toolchain_attrs, ) diff --git a/swift/internal/swift_library.bzl b/swift/internal/swift_library.bzl index c290f37b1..e8a961fc7 100644 --- a/swift/internal/swift_library.bzl +++ b/swift/internal/swift_library.bzl @@ -29,6 +29,7 @@ load( ) load(":linking.bzl", "create_linker_input") load(":providers.bzl", "SwiftInfo", "SwiftToolchainInfo") +load(":swift_clang_module_aspect.bzl", "swift_clang_module_aspect") load(":swift_common.bzl", "swift_common") load( ":utils.bzl", @@ -289,11 +290,11 @@ def _swift_library_impl(ctx): swift_library = rule( attrs = dicts.add( swift_common.library_rule_attrs(additional_deps_aspects = [ - swift_common.swift_clang_module_aspect, + swift_clang_module_aspect, ]), { "private_deps": swift_deps_attr( - aspects = [swift_common.swift_clang_module_aspect], + aspects = [swift_clang_module_aspect], doc = """\ A list of targets that are implementation-only dependencies of the target being built. Libraries/linker flags from these dependencies will be propagated to diff --git a/swift/swift.bzl b/swift/swift.bzl index 6bcb31045..835051d92 100644 --- a/swift/swift.bzl +++ b/swift/swift.bzl @@ -43,6 +43,10 @@ load( "@build_bazel_rules_swift//swift/internal:swift_c_module.bzl", _swift_c_module = "swift_c_module", ) +load( + "@build_bazel_rules_swift//swift/internal:swift_clang_module_aspect.bzl", + _swift_clang_module_aspect = "swift_clang_module_aspect", +) load( "@build_bazel_rules_swift//swift/internal:swift_common.bzl", _swift_common = "swift_common", @@ -92,4 +96,5 @@ swift_module_alias = _swift_module_alias swift_proto_library = _swift_proto_library # Re-export public aspects. +swift_clang_module_aspect = _swift_clang_module_aspect swift_usage_aspect = _swift_usage_aspect From 29f26cd4634a21a32f68cafbbf88d15c9300859c Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Mon, 12 Apr 2021 08:10:05 -0700 Subject: [PATCH 102/152] Update the module name derivation algorithm to handle any sequence of non-identifier characters safely. PiperOrigin-RevId: 368004995 (cherry picked from commit ec941966bd596ff55f5c957d5993abeb0fbf5210) --- swift/internal/compiling.bzl | 49 ++++++++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index 172fd1b91..ab471e8d6 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -1383,14 +1383,44 @@ def _additional_swiftc_copts_configurator(additional_swiftc_copts, prerequisites _unused = [prerequisites] args.add_all(additional_swiftc_copts) +def _module_name_safe(string): + """Returns a transformation of `string` that is safe for module names.""" + result = "" + saw_non_identifier_char = False + for ch in string.elems(): + if ch.isalnum() or ch == "_": + # If we're seeing an identifier character after a sequence of + # non-identifier characters, append an underscore and reset our + # tracking state before appending the identifier character. + if saw_non_identifier_char: + result += "_" + saw_non_identifier_char = False + result += ch + elif result: + # Only track this if `result` has content; this ensures that we + # (intentionally) drop leading non-identifier characters instead of + # adding a leading underscore. + saw_non_identifier_char = True + + return result + def 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 by creating an underscore-delimited string from the components - of the label, replacing any non-identifier characters also with underscores. + 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 not intended to be reversible. + This mapping is intended to be fairly predictable, but not reversible. Args: *args: Either a single argument of type `Label`, or two arguments of @@ -1415,12 +1445,15 @@ def derive_module_name(*args): fail("derive_module_name may only be called with a single argument " + "of type 'Label' or two arguments of type 'str'.") - package_part = (package.lstrip("//").replace("/", "_").replace("-", "_") - .replace(".", "_")) - name_part = name.replace("-", "_") + package_part = _module_name_safe(package.lstrip("//")) + name_part = _module_name_safe(name) if package_part: - return package_part + "_" + name_part - return name_part + module_name = package_part + "_" + name_part + else: + module_name = name_part + if module_name[0].isdigit(): + module_name = "_" + module_name + return module_name def compile( *, From dea7e7248885b4b9c48831c53db89d5e5b970fc8 Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Thu, 15 Apr 2021 09:18:17 -0700 Subject: [PATCH 103/152] API changes to `create_swift_interop_info`. - Require all dependencies' `SwiftInfo`s to be passed instead of implicitly (and unconditionally) traversing `deps`. - Add `requested_features` and `unsupported_features` parameters so rule implementations can provide these values (to be automatically added to the values on the target) as if they were supplying the feature configuration themselves. - Correctly derive a module name if it is not provided. PiperOrigin-RevId: 368653094 (cherry picked from commit 24a044900b655dc6b14354cd2d924b9688e6b213) --- swift/internal/swift_clang_module_aspect.bzl | 155 ++++++++++++------- 1 file changed, 101 insertions(+), 54 deletions(-) diff --git a/swift/internal/swift_clang_module_aspect.bzl b/swift/internal/swift_clang_module_aspect.bzl index 872532934..ccf5cd976 100644 --- a/swift/internal/swift_clang_module_aspect.bzl +++ b/swift/internal/swift_clang_module_aspect.bzl @@ -49,16 +49,10 @@ _SINGLE_TARGET_ASPECT_ATTRS = [ _SwiftInteropInfo = provider( doc = """\ -Contains minimal information required for the `swift_clang_module_aspect` to -generate a module map and/or precompiled module for a target so that it can -expose C/Objective-C APIs to Swift. +Contains minimal information required to allow `swift_clang_module_aspect` to +manage the creation of a `SwiftInfo` provider for a C/Objective-C target. """, fields = { - "additional_swift_infos": """\ -A list of additional `SwiftInfo` providers from dependencies that aren't -reachable via the `deps` attribute of the rule propagating this provider, but -which should be treated as dependencies of the C/Objective-C module. -""", "module_map": """\ A `File` representing an existing module map that should be used to represent the module, or `None` if the module map should be generated based on the headers @@ -67,15 +61,39 @@ in the target's compilation context. "module_name": """\ A string denoting the name of the module, or `None` if the name should be derived automatically from the target label. +""", + "requested_features": """\ +A list of features that should be enabled for the target, in addition to those +supplied in the `features` attribute, unless the feature is otherwise marked as +unsupported (either on the target or by the toolchain). This allows the rule +implementation to supply an additional set of fixed features that should always +be enabled when the aspect processes that target; 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. +""", + "swift_infos": """\ +A list of `SwiftInfo` providers from dependencies of the target, which will be +merged with the new `SwiftInfo` created by the aspect. +""", + "unsupported_features": """\ +A list of features that should be disabled for the target, in addition to those +supplied as negations in the `features` attribute. This allows the rule +implementation to supply an additional set of fixed features that should always +be disabled when the aspect processes that target; 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. """, }, ) def create_swift_interop_info( *, - additional_swift_infos = [], module_map = None, - module_name = None): + module_name = None, + requested_features = [], + 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 @@ -85,34 +103,54 @@ def create_swift_interop_info( make into a module, and then also propagate the provider returned from this function. - The simplest usage is for the custom rule to simply return - `swift_common.create_swift_interop_info()` without any arguments; this - tells `swift_clang_module_aspect` to derive the module name from the target - label and create a module map using the headers from the compilation - context. + The simplest usage is for a custom rule to call + `swift_common.create_swift_interop_info` passing it only the list of + `SwiftInfo` providers from its dependencies; this tells + `swift_clang_module_aspect` to derive the module name from the target label + and create a module map using the headers from the compilation context. 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. - The `swift_clang_module_aspect` automatically traverses the `deps` attribute - of even custom rules, so those rules don't need to do anything extra to - collect those dependencies. However, if a custom rule has dependencies in - other attributes (such as a runtime library specified as the default value - of a private attribute), it should pass the `SwiftInfo` provider from that - target into this function via the `additional_swift_infos` argument. + 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 do so automatically. This allows the rule to not only add extra + dependencies (such as support libraries from implicit attributes) but also + exclude dependencies if necessary. Args: - additional_swift_infos: A list of additional `SwiftInfo` providers from - dependencies that aren't reachable via the `deps` attribute of the - rule propagating this provider, but which should be treated as - dependencies of the C/Objective-C module. module_map: A `File` representing an existing module map that should be - used to represent the module, or `None` 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. - module_name: A string denoting the name of the module, or `None` if the - name should be derived automatically from the target label. + 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. + 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. + 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. + 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 @@ -122,9 +160,11 @@ def create_swift_interop_info( fail("'module_name' must be specified when 'module_map' is specified.") return _SwiftInteropInfo( - additional_swift_infos = additional_swift_infos, module_map = module_map, module_name = module_name, + requested_features = requested_features, + swift_infos = swift_infos, + unsupported_features = unsupported_features, ) def _tagged_target_module_name(label, tags): @@ -472,40 +512,47 @@ def _swift_clang_module_aspect_impl(target, aspect_ctx): if SwiftInfo in target: return [] - # Collect `SwiftInfo` providers from dependencies, based on the attributes - # that this aspect traverses. - attr = aspect_ctx.rule.attr - deps = [] - for attr_name in _MULTIPLE_TARGET_ASPECT_ATTRS: - deps.extend(getattr(attr, attr_name, [])) - for attr_name in _SINGLE_TARGET_ASPECT_ATTRS: - dep = getattr(attr, attr_name, None) - if dep: - deps.append(dep) - swift_infos = get_providers(deps, SwiftInfo) - - swift_toolchain = aspect_ctx.attr._toolchain_for_aspect[SwiftToolchainInfo] - feature_configuration = configure_features( - ctx = aspect_ctx, - requested_features = aspect_ctx.features, - swift_toolchain = swift_toolchain, - unsupported_features = aspect_ctx.disabled_features, - ) - if CcInfo in target: compilation_context = target[CcInfo].compilation_context else: compilation_context = None + requested_features = aspect_ctx.features + unsupported_features = aspect_ctx.disabled_features + if _SwiftInteropInfo in target: interop_info = target[_SwiftInteropInfo] - swift_infos.extend(interop_info.additional_swift_infos) module_map_file = interop_info.module_map - module_name = interop_info.module_name + module_name = ( + interop_info.module_name or derive_module_name(target.label) + ) + swift_infos = interop_info.swift_infos + requested_features.extend(interop_info.requested_features) + unsupported_features.extend(interop_info.unsupported_features) else: module_map_file = None module_name = None + # Collect `SwiftInfo` providers from dependencies, based on the + # attributes that this aspect traverses. + deps = [] + attr = aspect_ctx.rule.attr + for attr_name in _MULTIPLE_TARGET_ASPECT_ATTRS: + deps.extend(getattr(attr, attr_name, [])) + for attr_name in _SINGLE_TARGET_ASPECT_ATTRS: + dep = getattr(attr, attr_name, None) + if dep: + deps.append(dep) + swift_infos = get_providers(deps, SwiftInfo) + + swift_toolchain = aspect_ctx.attr._toolchain_for_aspect[SwiftToolchainInfo] + feature_configuration = configure_features( + ctx = aspect_ctx, + requested_features = requested_features, + swift_toolchain = swift_toolchain, + unsupported_features = unsupported_features, + ) + if ( _SwiftInteropInfo in target or apple_common.Objc in target or From 5f6154d23aa74d2516fcc930572302be127570ae Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Fri, 2 Apr 2021 09:48:06 -0700 Subject: [PATCH 104/152] Factor out Bazel placeholder substitution functionality into a separate reusable class. PiperOrigin-RevId: 366461152 (cherry picked from commit 89c6ab26a2d5a597fe00fda1fe5c56c58cb9f180) --- tools/common/BUILD | 12 ++-- tools/common/bazel_substitutions.cc | 90 ++++++++++++++++++++++++++++ tools/common/bazel_substitutions.h | 93 +++++++++++++++++++++++++++++ tools/common/string_utils.cc | 42 ------------- tools/common/string_utils.h | 25 -------- tools/worker/BUILD | 3 +- tools/worker/swift_runner.cc | 30 +--------- tools/worker/swift_runner.h | 4 +- tools/worker/work_processor.cc | 1 - 9 files changed, 195 insertions(+), 105 deletions(-) create mode 100644 tools/common/bazel_substitutions.cc create mode 100644 tools/common/bazel_substitutions.h delete mode 100644 tools/common/string_utils.cc delete mode 100644 tools/common/string_utils.h diff --git a/tools/common/BUILD b/tools/common/BUILD index b5da106c2..83eff15a9 100644 --- a/tools/common/BUILD +++ b/tools/common/BUILD @@ -6,6 +6,12 @@ package( licenses(["notice"]) +cc_library( + name = "bazel_substitutions", + srcs = ["bazel_substitutions.cc"], + hdrs = ["bazel_substitutions.h"], +) + cc_library( name = "file_system", srcs = ["file_system.cc"], @@ -30,12 +36,6 @@ cc_library( ], ) -cc_library( - name = "string_utils", - srcs = ["string_utils.cc"], - hdrs = ["string_utils.h"], -) - cc_library( name = "temp_file", hdrs = ["temp_file.h"], diff --git a/tools/common/bazel_substitutions.cc b/tools/common/bazel_substitutions.cc new file mode 100644 index 000000000..3cabf8c01 --- /dev/null +++ b/tools/common/bazel_substitutions.cc @@ -0,0 +1,90 @@ +// Copyright 2021 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "tools/common/bazel_substitutions.h" + +#include +#include +#include +#include + +namespace bazel_rules_swift { +namespace { + +// Returns the value of the given environment variable, or the empty string if +// it wasn't set. +std::string GetEnvironmentVariable(const char *name) { + char *env_value = getenv(name); + if (env_value == nullptr) { + return ""; + } + return env_value; +} + +} // namespace + +BazelPlaceholderSubstitutions::BazelPlaceholderSubstitutions() { + // When targeting Apple platforms, replace the magic Bazel placeholders with + // the path in the corresponding environment variable. These should be set by + // the build rules; only attempt to retrieve them if they're actually seen in + // the argument list. + placeholder_resolvers_ = { + {kBazelXcodeDeveloperDir, PlaceholderResolver([]() { + return GetEnvironmentVariable("DEVELOPER_DIR"); + })}, + {kBazelXcodeSdkRoot, + PlaceholderResolver([]() { return GetEnvironmentVariable("SDKROOT"); })}, + }; +} + +BazelPlaceholderSubstitutions::BazelPlaceholderSubstitutions( + const std::string &developer_dir, const std::string &sdk_root) { + placeholder_resolvers_ = { + {kBazelXcodeDeveloperDir, + PlaceholderResolver([=]() { return developer_dir; })}, + {kBazelXcodeSdkRoot, + PlaceholderResolver([=]() { return sdk_root; })}, + }; +} + +bool BazelPlaceholderSubstitutions::Apply(std::string &arg) { + bool changed = false; + + // Replace placeholders in the string with their actual values. + for (auto &[placeholder, env_var] : placeholder_resolvers_) { + changed |= FindAndReplace(placeholder, env_var, arg); + } + + return changed; +} + +bool BazelPlaceholderSubstitutions::FindAndReplace( + const std::string &placeholder, + BazelPlaceholderSubstitutions::PlaceholderResolver &resolver, + std::string &str) { + int start = 0; + bool changed = false; + while ((start = str.find(placeholder, start)) != std::string::npos) { + std::string resolved_value = resolver.get(); + if (resolved_value.empty()) { + return false; + } + changed = true; + str.replace(start, placeholder.length(), resolved_value); + start += resolved_value.length(); + } + return changed; +} + +} // namespace bazel_rules_swift diff --git a/tools/common/bazel_substitutions.h b/tools/common/bazel_substitutions.h new file mode 100644 index 000000000..2660faf3b --- /dev/null +++ b/tools/common/bazel_substitutions.h @@ -0,0 +1,93 @@ +// Copyright 2021 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef BUILD_BAZEL_RULES_SWIFT_TOOLS_COMMON_BAZEL_SUBSTITUTIONS_H_ +#define BUILD_BAZEL_RULES_SWIFT_TOOLS_COMMON_BAZEL_SUBSTITUTIONS_H_ + +#include +#include + +namespace bazel_rules_swift { + +// Manages the substitution of special Bazel placeholder strings in command line +// arguments that are used to defer the determination of Apple developer and SDK +// paths until execution time. +class BazelPlaceholderSubstitutions { + public: + // Initializes the substitutions by looking them up in the process's + // environment when they are first requested. + BazelPlaceholderSubstitutions(); + + // Initializes the substitutions with the given fixed strings. Intended to be + // used for testing. + BazelPlaceholderSubstitutions(const std::string &developer_dir, + const std::string &sdk_root); + + // Applies any necessary substitutions to `arg` and returns true if this + // caused the string to change. + bool Apply(std::string &arg); + + // The placeholder string used by Bazel that should be replaced by + // `DEVELOPER_DIR` at runtime. + static constexpr const char kBazelXcodeDeveloperDir[] = + "__BAZEL_XCODE_DEVELOPER_DIR__"; + + // The placeholder string used by Bazel that should be replaced by `SDKROOT` + // at runtime. + static constexpr const char kBazelXcodeSdkRoot[] = "__BAZEL_XCODE_SDKROOT__"; + + private: + // A resolver for a Bazel placeholder string that retrieves and caches the + // value the first time it is requested. + class PlaceholderResolver { + public: + explicit PlaceholderResolver(std::function fn) + : function_(fn), initialized_(false) {} + + // Returns the requested placeholder value, caching it for future + // retrievals. + std::string get() { + if (!initialized_) { + value_ = function_(); + initialized_ = true; + } + return value_; + } + + private: + // The function that returns the value of the placeholder, or the empty + // string if the placeholder should not be replaced. + std::function function_; + + // Indicates whether the value of the placeholder has been requested yet and + // and is therefore initialized. + bool initialized_; + + // The cached value of the placeholder if `initialized_` is true. + std::string value_; + }; + + // Finds and replaces all instances of `placeholder` with the value provided + // by `resolver`, in-place on `str`. Returns true if the string was changed. + bool FindAndReplace(const std::string &placeholder, + PlaceholderResolver &resolver, std::string &str); + + // A mapping from Bazel placeholder strings to resolvers that provide their + // values. + std::map placeholder_resolvers_; +}; + +} // namespace bazel_rules_swift + +#endif // BUILD_BAZEL_RULES_SWIFT_TOOLS_COMMON_BAZEL_SUBSTITUTIONS_H_ diff --git a/tools/common/string_utils.cc b/tools/common/string_utils.cc deleted file mode 100644 index 07c137faa..000000000 --- a/tools/common/string_utils.cc +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2019 The Bazel Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include - -// Finds and replaces all instances of oldsub with newsub, in-place on str. -// Returns true if the string was changed. -static bool FindAndReplace(const std::string &oldsub, const std::string &newsub, - std::string *str) { - int start = 0; - bool changed = false; - while ((start = str->find(oldsub, start)) != std::string::npos) { - changed = true; - str->replace(start, oldsub.length(), newsub); - start += newsub.length(); - } - return changed; -} - -bool MakeSubstitutions(std::string *arg, - const std::map &mappings) { - bool changed = false; - - // Replace placeholders in the string with their actual values. - for (const std::pair &mapping : mappings) { - changed |= FindAndReplace(mapping.first, mapping.second, arg); - } - - return changed; -} diff --git a/tools/common/string_utils.h b/tools/common/string_utils.h deleted file mode 100644 index 46715e511..000000000 --- a/tools/common/string_utils.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2019 The Bazel Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef BUILD_BAZEL_RULES_SWIFT_TOOLS_COMMON_STRING_UTILS_H_ -#define BUILD_BAZEL_RULES_SWIFT_TOOLS_COMMON_STRING_UTILS_H_ - -#include -#include - -// Rewrites the given argument by replacing any Bazel path placeholders. -bool MakeSubstitutions(std::string *arg, - const std::map &mappings); - -#endif // BUILD_BAZEL_RULES_SWIFT_TOOLS_COMMON_STRING_UTILS_H_ diff --git a/tools/worker/BUILD b/tools/worker/BUILD index 23bb274ae..6bda082c8 100644 --- a/tools/worker/BUILD +++ b/tools/worker/BUILD @@ -33,7 +33,6 @@ cc_library( "//third_party/bazel_protos:worker_protocol_cc_proto", "//tools/common:file_system", "//tools/common:path_utils", - "//tools/common:string_utils", "//tools/common:temp_file", "@com_github_nlohmann_json//:json", "@com_google_protobuf//:protobuf", @@ -54,9 +53,9 @@ cc_library( srcs = ["swift_runner.cc"], hdrs = ["swift_runner.h"], deps = [ + "//tools/common:bazel_substitutions", "//tools/common:file_system", "//tools/common:process", - "//tools/common:string_utils", "//tools/common:temp_file", ], ) diff --git a/tools/worker/swift_runner.cc b/tools/worker/swift_runner.cc index cca929f63..aed6c76fc 100644 --- a/tools/worker/swift_runner.cc +++ b/tools/worker/swift_runner.cc @@ -16,26 +16,13 @@ #include +#include "tools/common/bazel_substitutions.h" #include "tools/common/file_system.h" #include "tools/common/process.h" -#include "tools/common/string_utils.h" #include "tools/common/temp_file.h" namespace { -#if __APPLE__ -// Returns the requested environment variable in the current process's -// environment. Aborts if this variable is unset. -static std::string GetMandatoryEnvVar(const std::string &var_name) { - char *env_value = getenv(var_name.c_str()); - if (env_value == nullptr) { - std::cerr << "Error: " << var_name << " not set.\n"; - abort(); - } - return env_value; -} -#endif - // Creates a temporary file and writes the given arguments to it, one per line. static std::unique_ptr WriteResponseFile( const std::vector &args) { @@ -104,19 +91,6 @@ static std::string Unescape(const std::string &arg) { SwiftRunner::SwiftRunner(const std::vector &args, bool force_response_file) : force_response_file_(force_response_file) { -#if __APPLE__ - // On Apple platforms, replace the magic Bazel placeholders with the path - // in the corresponding environment variable. - std::string developer_dir = GetMandatoryEnvVar("DEVELOPER_DIR"); - std::string sdk_root = GetMandatoryEnvVar("SDKROOT"); - - bazel_placeholder_substitutions_ = { - {"__BAZEL_XCODE_DEVELOPER_DIR__", developer_dir}, - {"__BAZEL_XCODE_SDKROOT__", sdk_root}, - }; -#else - // We don't have these placeholder strings on non-Apple platforms. -#endif args_ = ProcessArguments(args); } @@ -212,7 +186,7 @@ bool SwiftRunner::ProcessArgument( // Bazel doesn't quote arguments in multi-line params files, so we need to // ensure that our defensive quoting kicks in if an argument contains a // space, even if no other changes would have been made. - changed = MakeSubstitutions(&new_arg, bazel_placeholder_substitutions_) || + changed = bazel_placeholder_substitutions_.Apply(new_arg) || new_arg.find_first_of(' ') != std::string::npos; consumer(new_arg); } diff --git a/tools/worker/swift_runner.h b/tools/worker/swift_runner.h index 55a4ba31b..d2cfe67d5 100644 --- a/tools/worker/swift_runner.h +++ b/tools/worker/swift_runner.h @@ -22,6 +22,7 @@ #include #include +#include "tools/common/bazel_substitutions.h" #include "tools/common/temp_file.h" // Handles spawning the Swift compiler driver, making any required substitutions @@ -106,7 +107,8 @@ class SwiftRunner { // A mapping of Bazel placeholder strings to the actual paths that should be // substituted for them. Supports Xcode resolution on Apple OSes. - std::map bazel_placeholder_substitutions_; + bazel_rules_swift::BazelPlaceholderSubstitutions + bazel_placeholder_substitutions_; // The arguments, post-substitution, passed to the spawner. std::vector args_; diff --git a/tools/worker/work_processor.cc b/tools/worker/work_processor.cc index a738041c1..1e48bebc5 100644 --- a/tools/worker/work_processor.cc +++ b/tools/worker/work_processor.cc @@ -25,7 +25,6 @@ #include "tools/common/file_system.h" #include "tools/common/path_utils.h" -#include "tools/common/string_utils.h" #include "tools/common/temp_file.h" #include "tools/worker/output_file_map.h" #include "tools/worker/swift_runner.h" From 65af06233f90a02e041d612f0cc75fb79a194bc3 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Tue, 6 Apr 2021 16:16:10 -0700 Subject: [PATCH 105/152] Support older C++ versions Google's internal C++ version is higher than bazel's default. Theoretically we could mess with the `-std` flag that's passed, and I tried that a bit, but the public crosstool differs between macOS and Linux so it makes it a bit of a pain. For this case this is easy enough. --- tools/common/bazel_substitutions.cc | 13 +++++++++++-- tools/common/bazel_substitutions.h | 10 +--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/tools/common/bazel_substitutions.cc b/tools/common/bazel_substitutions.cc index 3cabf8c01..25f3c1b6a 100644 --- a/tools/common/bazel_substitutions.cc +++ b/tools/common/bazel_substitutions.cc @@ -22,6 +22,15 @@ namespace bazel_rules_swift { namespace { +// The placeholder string used by Bazel that should be replaced by +// `DEVELOPER_DIR` at runtime. +static const char kBazelXcodeDeveloperDir[] = + "__BAZEL_XCODE_DEVELOPER_DIR__"; + +// The placeholder string used by Bazel that should be replaced by `SDKROOT` +// at runtime. +static const char kBazelXcodeSdkRoot[] = "__BAZEL_XCODE_SDKROOT__"; + // Returns the value of the given environment variable, or the empty string if // it wasn't set. std::string GetEnvironmentVariable(const char *name) { @@ -62,8 +71,8 @@ bool BazelPlaceholderSubstitutions::Apply(std::string &arg) { bool changed = false; // Replace placeholders in the string with their actual values. - for (auto &[placeholder, env_var] : placeholder_resolvers_) { - changed |= FindAndReplace(placeholder, env_var, arg); + for (auto& pair : placeholder_resolvers_) { + changed |= FindAndReplace(pair.first, pair.second, arg); } return changed; diff --git a/tools/common/bazel_substitutions.h b/tools/common/bazel_substitutions.h index 2660faf3b..8ba54586b 100644 --- a/tools/common/bazel_substitutions.h +++ b/tools/common/bazel_substitutions.h @@ -15,6 +15,7 @@ #ifndef BUILD_BAZEL_RULES_SWIFT_TOOLS_COMMON_BAZEL_SUBSTITUTIONS_H_ #define BUILD_BAZEL_RULES_SWIFT_TOOLS_COMMON_BAZEL_SUBSTITUTIONS_H_ +#include #include #include @@ -38,15 +39,6 @@ class BazelPlaceholderSubstitutions { // caused the string to change. bool Apply(std::string &arg); - // The placeholder string used by Bazel that should be replaced by - // `DEVELOPER_DIR` at runtime. - static constexpr const char kBazelXcodeDeveloperDir[] = - "__BAZEL_XCODE_DEVELOPER_DIR__"; - - // The placeholder string used by Bazel that should be replaced by `SDKROOT` - // at runtime. - static constexpr const char kBazelXcodeSdkRoot[] = "__BAZEL_XCODE_SDKROOT__"; - private: // A resolver for a Bazel placeholder string that retrieves and caches the // value the first time it is requested. From 26f81cac555e3d0b22d01fc11ad0b0362538a12e Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Wed, 7 Apr 2021 08:07:10 -0700 Subject: [PATCH 106/152] Sort headers in the module maps generated by `swift_clang_module_aspect`, and rewrite generation to use a multi-line `Args` object as a file writer instead of building up an analysis time string. With this approach, each "arg" (or each entry in a list/depset of args) is treated as its own line in the output file; we use the `format_each` and `map_each` parameters to provide any additional text that should surround that value on the line. More importantly, this adds support for expanding tree artifacts (directories) if one is provided in a compilation context. PiperOrigin-RevId: 367221120 (cherry picked from commit 5f7af6972ca83d703fa1858a6bb568d2e300ed33) --- swift/internal/module_maps.bzl | 145 +++++++++++-------- swift/internal/swift_clang_module_aspect.bzl | 21 ++- 2 files changed, 101 insertions(+), 65 deletions(-) diff --git a/swift/internal/module_maps.bzl b/swift/internal/module_maps.bzl index fbd21cb15..b920af6e8 100644 --- a/swift/internal/module_maps.bzl +++ b/swift/internal/module_maps.bzl @@ -14,8 +14,6 @@ """Logic for generating Clang module map files.""" -load("@bazel_skylib//lib:paths.bzl", "paths") - def write_module_map( actions, module_map_file, @@ -55,69 +53,93 @@ def write_module_map( written in the module map file should be relative to the workspace or relative to the module map file. """ - content = 'module "{}" {{\n'.format(module_name) - if exported_module_ids: - content += "".join([ - " export {}\n".format(module_id) - for module_id in exported_module_ids - ]) - content += "\n" - - content += "".join([ - ' header "{}"\n'.format(_header_path( - header_file = header_file, - module_map_file = module_map_file, - workspace_relative = workspace_relative, - )) - for header_file in public_headers - ]) - content += "".join([ - ' private header "{}"\n'.format(_header_path( - header_file = header_file, - module_map_file = module_map_file, - workspace_relative = workspace_relative, - )) - for header_file in private_headers - ]) - content += "".join([ - ' textual header "{}"\n'.format(_header_path( - header_file = header_file, - module_map_file = module_map_file, - workspace_relative = workspace_relative, - )) - for header_file in public_textual_headers - ]) - content += "".join([ - ' private textual header "{}"\n'.format(_header_path( - header_file = header_file, - module_map_file = module_map_file, - workspace_relative = workspace_relative, - )) - for header_file in private_textual_headers - ]) - - content += "".join([ - ' use "{}"\n'.format(name) - for name in dependent_module_names - ]) - - content += "}\n" + + # In the non-workspace-relative case, precompute the relative-to-dir and the + # repeated `../` string used to go back up to the workspace root instead of + # recomputing it every time a header path is written. + if workspace_relative: + relative_to_dir = None + back_to_root_path = None + else: + relative_to_dir = module_map_file.dirname + back_to_root_path = "../" * len(relative_to_dir.split("/")) + + content = actions.args() + content.set_param_file_format("multiline") + + content.add(module_name, format = 'module "%s" {') + + # Write an `export` declaration for each of the module identifiers that + # should be re-exported by this module. + content.add_all(exported_module_ids, format_each = " export %s") + content.add("") + + def _add_headers(*, headers, kind): + # Each header is added to the `Args` object as a tuple along with + # `relative_to_dir` and `back_to_root_path`. This gives the mapping + # function the information it needs to relativize the header paths even + # when they're expanded from a tree artifact (and thus not known at + # analysis time). + content.add_all( + [(file, relative_to_dir, back_to_root_path) for file in headers], + format_each = ' {} "%s"'.format(kind), + map_each = _header_info_mapper, + ) + + _add_headers(headers = public_headers, kind = "header") + _add_headers(headers = private_headers, kind = "private header") + _add_headers(headers = public_textual_headers, kind = "textual header") + _add_headers( + headers = private_textual_headers, + kind = "private textual header", + ) + content.add("") + + # Write a `use` declaration for each of the module's dependencies. + content.add_all(dependent_module_names, format_each = ' use "%s"') + content.add("}") actions.write( content = content, output = module_map_file, ) -def _header_path(header_file, module_map_file, workspace_relative): +def _header_info_mapper(header_info, directory_expander): + """Maps header info passed to the `Args` object to a list of header paths. + + Args: + header_info: A tuple containing three elements: a `File` representing a + header (or a directory containing headers), the path to the + directory that should be used to relativize the header paths, and + the path string consisting of repeated `../` segments that should be + used to return from the module map's directory to the workspace + root. The latter two elements will be `None` if the headers should + be written workspace-relative). + directory_expander: The object used to expand tree artifacts into the + list of files in that directory. + + Returns: + A list of file paths as they should be written into the module map file. + """ + return [ + _header_path(file, header_info[1], header_info[2]) + for file in directory_expander.expand(header_info[0]) + ] + +def _header_path(header_file, relative_to_dir, back_to_root_path): """Returns the path to a header file to be written in the module map. Args: header_file: A `File` representing the header whose path should be returned. - module_map_file: A `File` representing the module map being written, - which is used during path relativization if necessary. - workspace_relative: A Boolean value indicating whether the path should - be workspace-relative or module-map-relative. + relative_to_dir: A `File` representing the module map being + written, which is used during path relativization if necessary. If + this is `None`, then no relativization is performed of the header + path and the workspace-relative path is used instead. + back_to_root_path: A path string consisting of repeated `../` segments + that should be used to return from the module map's directory to the + workspace root. This should be `None` if `relative_to_dir` is + `None`. Returns: The path to the header file, relative to either the workspace or the @@ -126,20 +148,21 @@ def _header_path(header_file, module_map_file, workspace_relative): # If the module map is workspace-relative, then the file's path is what we # want. - if workspace_relative: + if not relative_to_dir: return header_file.path # Minor optimization for the generated Objective-C header of a Swift module, # which will be in the same directory as the module map file -- we can just - # use the header's basename instead of the elaborate relative path - # computation below. - if header_file.dirname == module_map_file.dirname: + # use the header's basename instead of the elaborate relative path string + # below. + if header_file.dirname == relative_to_dir: return header_file.basename # Otherwise, since the module map is generated, we need to get the full path # to it rather than just its short path (that is, the path starting with # bazel-out/). Then, we can simply walk up the same number of parent # directories as there are path segments, and append the header file's path - # to that. - num_segments = len(paths.dirname(module_map_file.path).split("/")) - return ("../" * num_segments) + header_file.path + # to that. The `back_to_root_path` string is guaranteed to end in a slash, + # so we use simple concatenation instead of Skylib's `paths.join` to avoid + # extra work. + return back_to_root_path + header_file.path diff --git a/swift/internal/swift_clang_module_aspect.bzl b/swift/internal/swift_clang_module_aspect.bzl index ccf5cd976..f4f72f11c 100644 --- a/swift/internal/swift_clang_module_aspect.bzl +++ b/swift/internal/swift_clang_module_aspect.bzl @@ -248,15 +248,28 @@ def _generate_module_map( actions = actions, target_name = target.label.name, ) + + # Sort dependent module names and the headers to ensure a deterministic + # order in the output file, in the event the compilation context would ever + # change this on us. For files, use the execution path as the sorting key. + def _path_sorting_key(file): + return file.path + write_module_map( actions = actions, - dependent_module_names = dependent_module_names, + dependent_module_names = sorted(dependent_module_names), exported_module_ids = ["*"], module_map_file = module_map_file, module_name = module_name, - private_headers = private_headers, - public_headers = compilation_context.direct_public_headers, - public_textual_headers = compilation_context.direct_textual_headers, + private_headers = sorted(private_headers, key = _path_sorting_key), + public_headers = sorted( + compilation_context.direct_public_headers, + key = _path_sorting_key, + ), + public_textual_headers = sorted( + compilation_context.direct_textual_headers, + key = _path_sorting_key, + ), workspace_relative = workspace_relative, ) return module_map_file From b1cc2123c44d9763e5e7fb902181cff0dfa87fc8 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Mon, 3 May 2021 18:02:35 -0700 Subject: [PATCH 107/152] Remove top level functions for now --- swift/internal/module_maps.bzl | 34 +++++++++++--------- swift/internal/swift_clang_module_aspect.bzl | 13 ++++---- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/swift/internal/module_maps.bzl b/swift/internal/module_maps.bzl index b920af6e8..67b77b1c5 100644 --- a/swift/internal/module_maps.bzl +++ b/swift/internal/module_maps.bzl @@ -14,6 +14,19 @@ """Logic for generating Clang module map files.""" +# TODO: Once bazel supports nested functions unify it with upstream +def _add_headers(*, headers, kind, content, relative_to_dir, back_to_root_path): + # Each header is added to the `Args` object as a tuple along with + # `relative_to_dir` and `back_to_root_path`. This gives the mapping + # function the information it needs to relativize the header paths even + # when they're expanded from a tree artifact (and thus not known at + # analysis time). + content.add_all( + [(file, relative_to_dir, back_to_root_path) for file in headers], + format_each = ' {} "%s"'.format(kind), + map_each = _header_info_mapper, + ) + def write_module_map( actions, module_map_file, @@ -74,24 +87,15 @@ def write_module_map( content.add_all(exported_module_ids, format_each = " export %s") content.add("") - def _add_headers(*, headers, kind): - # Each header is added to the `Args` object as a tuple along with - # `relative_to_dir` and `back_to_root_path`. This gives the mapping - # function the information it needs to relativize the header paths even - # when they're expanded from a tree artifact (and thus not known at - # analysis time). - content.add_all( - [(file, relative_to_dir, back_to_root_path) for file in headers], - format_each = ' {} "%s"'.format(kind), - map_each = _header_info_mapper, - ) - - _add_headers(headers = public_headers, kind = "header") - _add_headers(headers = private_headers, kind = "private header") - _add_headers(headers = public_textual_headers, kind = "textual header") + _add_headers(headers = public_headers, kind = "header", content = content, relative_to_dir = relative_to_dir, back_to_root_path = back_to_root_path) + _add_headers(headers = private_headers, kind = "private header", content = content, relative_to_dir = relative_to_dir, back_to_root_path = back_to_root_path) + _add_headers(headers = public_textual_headers, kind = "textual header", content = content, relative_to_dir = relative_to_dir, back_to_root_path = back_to_root_path) _add_headers( headers = private_textual_headers, kind = "private textual header", + content = content, + relative_to_dir = relative_to_dir, + back_to_root_path = back_to_root_path, ) content.add("") diff --git a/swift/internal/swift_clang_module_aspect.bzl b/swift/internal/swift_clang_module_aspect.bzl index f4f72f11c..d7839b0f0 100644 --- a/swift/internal/swift_clang_module_aspect.bzl +++ b/swift/internal/swift_clang_module_aspect.bzl @@ -205,6 +205,13 @@ def _tagged_target_module_name(label, tags): _, _, module_name = tag.partition("=") return module_name +# TODO: Once bazel supports nested functions unify this with upstream +# Sort dependent module names and the headers to ensure a deterministic +# order in the output file, in the event the compilation context would ever +# change this on us. For files, use the execution path as the sorting key. +def _path_sorting_key(file): + return file.path + def _generate_module_map( actions, compilation_context, @@ -249,12 +256,6 @@ def _generate_module_map( target_name = target.label.name, ) - # Sort dependent module names and the headers to ensure a deterministic - # order in the output file, in the event the compilation context would ever - # change this on us. For files, use the execution path as the sorting key. - def _path_sorting_key(file): - return file.path - write_module_map( actions = actions, dependent_module_names = sorted(dependent_module_names), From e77df5b27fe9e1cabc6d5d6c17c0633cd7ccb46d Mon Sep 17 00:00:00 2001 From: Walter Lee Date: Wed, 28 Apr 2021 07:35:10 -0700 Subject: [PATCH 108/152] Use cpp fragment, instead of objc fragment, to determine whether to generate dsym The information is identical, and we would like to migrate all uses to cpp fragment so that we can delete the info in objc fragment. PiperOrigin-RevId: 370899517 (cherry picked from commit 3e53aa28a558b7cb690cae10afd63ca98b221a35) --- swift/internal/features.bzl | 6 +++--- swift/internal/xcode_swift_toolchain.bzl | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/swift/internal/features.bzl b/swift/internal/features.bzl index 6e19d7d0e..3a3f57cb9 100644 --- a/swift/internal/features.bzl +++ b/swift/internal/features.bzl @@ -105,7 +105,7 @@ def configure_features( _enabled_features = requestable_features, ) -def features_for_build_modes(ctx, objc_fragment = None): +def features_for_build_modes(ctx, cpp_fragment = None): """Returns a list of Swift toolchain features for current build modes. This function explicitly breaks the "don't pass `ctx` as an argument" @@ -114,7 +114,7 @@ def features_for_build_modes(ctx, objc_fragment = None): Args: ctx: The current rule context. - objc_fragment: The Objective-C configuration fragment, if available. + cpp_fragment: The Cpp configuration fragment, if available. Returns: A list of Swift toolchain features to enable. @@ -126,7 +126,7 @@ def features_for_build_modes(ctx, objc_fragment = None): features.append(SWIFT_FEATURE_COVERAGE) if compilation_mode in ("dbg", "fastbuild"): features.append(SWIFT_FEATURE_ENABLE_TESTING) - if objc_fragment and objc_fragment.generate_dsym: + if cpp_fragment and cpp_fragment.apple_generate_dsym: features.append(SWIFT_FEATURE_FULL_DEBUG_INFO) return features diff --git a/swift/internal/xcode_swift_toolchain.bzl b/swift/internal/xcode_swift_toolchain.bzl index 5237b4687..3ce52348e 100644 --- a/swift/internal/xcode_swift_toolchain.bzl +++ b/swift/internal/xcode_swift_toolchain.bzl @@ -684,7 +684,7 @@ def _xcode_swift_toolchain_impl(ctx): # version. requested_features = features_for_build_modes( ctx, - objc_fragment = ctx.fragments.objc, + cpp_fragment = ctx.fragments.cpp, ) + features_from_swiftcopts(swiftcopts = ctx.fragments.swift.copts()) requested_features.extend(ctx.features) requested_features.append(SWIFT_FEATURE_BUNDLED_XCTESTS) @@ -838,6 +838,7 @@ for incremental compilation using a persistent mode. doc = "Represents a Swift compiler toolchain provided by Xcode.", fragments = [ "apple", + "cpp", "objc", "swift", ], From 1b4e4c06ad71e4fc6383d72d64d517ff6674995b Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Mon, 3 May 2021 18:15:41 -0700 Subject: [PATCH 109/152] Add support for older bazel versions for now --- swift/internal/features.bzl | 11 +++++++++-- swift/internal/xcode_swift_toolchain.bzl | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/swift/internal/features.bzl b/swift/internal/features.bzl index 3a3f57cb9..51b20c287 100644 --- a/swift/internal/features.bzl +++ b/swift/internal/features.bzl @@ -105,7 +105,7 @@ def configure_features( _enabled_features = requestable_features, ) -def features_for_build_modes(ctx, cpp_fragment = None): +def features_for_build_modes(ctx, objc_fragment = None, cpp_fragment = None): """Returns a list of Swift toolchain features for current build modes. This function explicitly breaks the "don't pass `ctx` as an argument" @@ -114,6 +114,7 @@ def features_for_build_modes(ctx, cpp_fragment = None): Args: ctx: The current rule context. + objc_fragment: The Objective-C configuration fragment, if available. cpp_fragment: The Cpp configuration fragment, if available. Returns: @@ -126,7 +127,13 @@ def features_for_build_modes(ctx, cpp_fragment = None): features.append(SWIFT_FEATURE_COVERAGE) if compilation_mode in ("dbg", "fastbuild"): features.append(SWIFT_FEATURE_ENABLE_TESTING) - if cpp_fragment and cpp_fragment.apple_generate_dsym: + + # TODO: Remove getattr once bazel is released with this change + if cpp_fragment and getattr(cpp_fragment, "apple_generate_dsym", False): + features.append(SWIFT_FEATURE_FULL_DEBUG_INFO) + + # TODO: Remove the objc_fragment usage once bazel is released with the C++ change + if objc_fragment and getattr(objc_fragment, "generate_dsym", False): features.append(SWIFT_FEATURE_FULL_DEBUG_INFO) return features diff --git a/swift/internal/xcode_swift_toolchain.bzl b/swift/internal/xcode_swift_toolchain.bzl index 3ce52348e..e276f53c4 100644 --- a/swift/internal/xcode_swift_toolchain.bzl +++ b/swift/internal/xcode_swift_toolchain.bzl @@ -684,6 +684,7 @@ def _xcode_swift_toolchain_impl(ctx): # version. requested_features = features_for_build_modes( ctx, + objc_fragment = ctx.fragments.objc, cpp_fragment = ctx.fragments.cpp, ) + features_from_swiftcopts(swiftcopts = ctx.fragments.swift.copts()) requested_features.extend(ctx.features) From 728528dba9cbbec5c671197dbdc2c9a4c061180a Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Mon, 19 Apr 2021 16:07:21 -0700 Subject: [PATCH 110/152] Add Xcode toolchain support for an optional binary that can rewrite the generated header of a Swift module after compilation. PiperOrigin-RevId: 369323385 (cherry picked from commit e4912a311f32f7c5ae2c5a61f549f03a4b0aab16) --- swift/internal/compiling.bzl | 26 +++++- swift/internal/feature_names.bzl | 5 ++ swift/internal/xcode_swift_toolchain.bzl | 31 +++++++ tools/worker/swift_runner.cc | 108 ++++++++++++++++------- tools/worker/swift_runner.h | 4 + 5 files changed, 140 insertions(+), 34 deletions(-) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index ab471e8d6..ca279f342 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -51,6 +51,7 @@ load( "SWIFT_FEATURE_OPT", "SWIFT_FEATURE_OPT_USES_OSIZE", "SWIFT_FEATURE_OPT_USES_WMO", + "SWIFT_FEATURE_REWRITE_GENERATED_HEADER", "SWIFT_FEATURE_SPLIT_DERIVED_FILES_GENERATION", "SWIFT_FEATURE_STRICT_MODULES", "SWIFT_FEATURE_SUPPORTS_LIBRARY_EVOLUTION", @@ -95,7 +96,8 @@ _WMO_FLAGS = { def compile_action_configs( *, additional_objc_copts = [], - additional_swiftc_copts = []): + additional_swiftc_copts = [], + generated_header_rewriter = None): """Returns the list of action configs needed to perform Swift compilation. Toolchains must add these to their own list of action configs so that @@ -109,6 +111,9 @@ def compile_action_configs( additional_swiftc_copts: An optional list of additional Swift compiler flags that should be passed to Swift compile actions only after any other toolchain- or user-provided flags. + generated_header_rewriter: An executable that will be invoked after + compilation to rewrite the generated header, or None if this is not + desired. Returns: The list of action configs needed to perform compilation. @@ -216,6 +221,25 @@ def compile_action_configs( ), ] + if generated_header_rewriter: + # Only add the generated header rewriter to the command line only if the + # toolchain provides one, the relevant feature is requested, and the + # particular compilation action is generating a header. + def generated_header_rewriter_configurator(prerequisites, args): + if prerequisites.generated_header_file: + args.add( + generated_header_rewriter, + format = "-Xwrapped-swift=-generated-header-rewriter=%s", + ) + + action_configs.append( + swift_toolchain_config.action_config( + actions = [swift_action_names.COMPILE], + configurators = [generated_header_rewriter_configurator], + features = [SWIFT_FEATURE_REWRITE_GENERATED_HEADER], + ), + ) + #### Compilation-mode-related flags # # These configs set flags based on the current compilation mode. They mirror diff --git a/swift/internal/feature_names.bzl b/swift/internal/feature_names.bzl index 7694d69c7..fafaae457 100644 --- a/swift/internal/feature_names.bzl +++ b/swift/internal/feature_names.bzl @@ -123,6 +123,11 @@ SWIFT_FEATURE_OPT_USES_WMO = "swift.opt_uses_wmo" # the `-Osize` flag instead of `-O`. SWIFT_FEATURE_OPT_USES_OSIZE = "swift.opt_uses_osize" +# If enabled, and if the toolchain specifies a generated header rewriting tool, +# that tool will be invoked after compilation to rewrite the generated header in +# place. +SWIFT_FEATURE_REWRITE_GENERATED_HEADER = "swift.rewrite_generated_header" + # If enabled, Swift compiler invocations will use precompiled modules from # dependencies instead of module maps and headers, if those dependencies provide # them. diff --git a/swift/internal/xcode_swift_toolchain.bzl b/swift/internal/xcode_swift_toolchain.bzl index e276f53c4..a2872efb4 100644 --- a/swift/internal/xcode_swift_toolchain.bzl +++ b/swift/internal/xcode_swift_toolchain.bzl @@ -327,6 +327,7 @@ def _all_action_configs( additional_swiftc_copts, apple_fragment, apple_toolchain, + generated_header_rewriter, needs_resource_directory, target_triple): """Returns the action configurations for the Swift toolchain. @@ -339,6 +340,9 @@ def _all_action_configs( the `swift` configuration fragment. apple_fragment: The `apple` configuration fragment. apple_toolchain: The `apple_common.apple_toolchain()` object. + generated_header_rewriter: An executable that will be invoked after + compilation to rewrite the generated header, or None if this is not + desired. needs_resource_directory: If True, the toolchain needs the resource directory passed explicitly to the compiler. target_triple: The target triple. @@ -494,6 +498,7 @@ def _all_action_configs( action_configs.extend(compile_action_configs( additional_objc_copts = additional_objc_copts, additional_swiftc_copts = additional_swiftc_copts, + generated_header_rewriter = generated_header_rewriter, )) return action_configs @@ -501,6 +506,7 @@ def _all_tool_configs( custom_toolchain, env, execution_requirements, + generated_header_rewriter, swift_executable, toolchain_root, use_param_file, @@ -512,6 +518,9 @@ def _all_tool_configs( one was requested. env: The environment variables to set when launching tools. execution_requirements: The execution requirements for tools. + generated_header_rewriter: An executable that will be invoked after + compilation to rewrite the generated header, or None if this is not + desired. swift_executable: A custom Swift driver executable to be used during the build, if provided. toolchain_root: The root directory of the toolchain, if provided. @@ -530,7 +539,12 @@ def _all_tool_configs( env = dict(env) env["TOOLCHAINS"] = custom_toolchain + additional_compile_tools = [] + if generated_header_rewriter: + additional_compile_tools.append(generated_header_rewriter) + tool_config = swift_toolchain_config.driver_tool_config( + additional_tools = additional_compile_tools, driver_mode = "swiftc", env = env, execution_requirements = execution_requirements, @@ -725,11 +739,13 @@ def _xcode_swift_toolchain_impl(ctx): env = _xcode_env(platform = platform, xcode_config = xcode_config) execution_requirements = xcode_config.execution_info() + generated_header_rewriter = ctx.executable.generated_header_rewriter all_tool_configs = _all_tool_configs( custom_toolchain = custom_toolchain, env = env, execution_requirements = execution_requirements, + generated_header_rewriter = generated_header_rewriter, swift_executable = swift_executable, toolchain_root = toolchain_root, use_param_file = use_param_file, @@ -743,6 +759,7 @@ def _xcode_swift_toolchain_impl(ctx): additional_swiftc_copts = ctx.fragments.swift.copts(), apple_fragment = apple_fragment, apple_toolchain = apple_toolchain, + generated_header_rewriter = generated_header_rewriter, needs_resource_directory = swift_executable or toolchain_root, target_triple = target, ) @@ -798,6 +815,20 @@ of a Swift module. """, providers = [[SwiftInfo]], ), + "generated_header_rewriter": attr.label( + allow_files = True, + cfg = "host", + doc = """\ +If present, an executable that will be invoked after compilation to rewrite the +generated header. + +This tool is expected to have a command line interface such that the Swift +compiler invocation is passed to it following a `"--"` argument, and any +arguments preceding the `"--"` can be defined by the tool itself (however, at +this time the worker does not support passing additional flags to the tool). +""", + executable = True, + ), "implicit_deps": attr.label_list( allow_files = True, doc = """\ diff --git a/tools/worker/swift_runner.cc b/tools/worker/swift_runner.cc index aed6c76fc..0abf53f03 100644 --- a/tools/worker/swift_runner.cc +++ b/tools/worker/swift_runner.cc @@ -86,6 +86,17 @@ static std::string Unescape(const std::string &arg) { return result; } +// If `str` starts with `prefix`, `str` is mutated to remove `prefix` and the +// function returns true. Otherwise, `str` is left unmodified and the function +// returns `false`. +static bool StripPrefix(const std::string &prefix, std::string &str) { + if (str.find(prefix) != 0) { + return false; + } + str.erase(0, prefix.size()); + return true; +} + } // namespace SwiftRunner::SwiftRunner(const std::vector &args, @@ -96,6 +107,28 @@ SwiftRunner::SwiftRunner(const std::vector &args, int SwiftRunner::Run(std::ostream *stderr_stream, bool stdout_to_stderr) { int exit_code = RunSubProcess(args_, stderr_stream, stdout_to_stderr); + if (exit_code != 0) { + return exit_code; + } + + if (!generated_header_rewriter_path_.empty()) { +#if __APPLE__ + // Skip the `xcrun` argument that's added when running on Apple platforms. + int initial_args_to_skip = 1; +#else + int initial_args_to_skip = 0; +#endif + + std::vector rewriter_args; + rewriter_args.reserve(args_.size() + 2 - initial_args_to_skip); + rewriter_args.push_back(generated_header_rewriter_path_); + rewriter_args.push_back("--"); + rewriter_args.insert(rewriter_args.end(), + args_.begin() + initial_args_to_skip, args_.end()); + + exit_code = RunSubProcess(rewriter_args, stderr_stream, stdout_to_stderr); + } + return exit_code; } @@ -155,40 +188,49 @@ bool SwiftRunner::ProcessArgument( if (arg[0] == '@') { changed = ProcessPossibleResponseFile(arg, consumer); - } else if (arg == "-Xwrapped-swift=-debug-prefix-pwd-is-dot") { - // Get the actual current working directory (the workspace root), which we - // didn't know at analysis time. - consumer("-debug-prefix-map"); - consumer(GetCurrentDirectory() + "=."); - changed = true; - } else if (arg == "-Xwrapped-swift=-coverage-prefix-pwd-is-dot") { - // Get the actual current working directory (the workspace root), which we - // didn't know at analysis time. - consumer("-coverage-prefix-map"); - consumer(GetCurrentDirectory() + "=."); - changed = true; - } else if (arg == "-Xwrapped-swift=-ephemeral-module-cache") { - // Create a temporary directory to hold the module cache, which will be - // deleted after compilation is finished. - auto module_cache_dir = TempDirectory::Create("swift_module_cache.XXXXXX"); - consumer("-module-cache-path"); - consumer(module_cache_dir->GetPath()); - temp_directories_.push_back(std::move(module_cache_dir)); - changed = true; - } else if (arg.find("-Xwrapped-swift=") == 0) { - // TODO(allevato): Report that an unknown wrapper arg was found and give the - // caller a way to exit gracefully. - changed = true; } else { - // Apply any other text substitutions needed in the argument (i.e., for - // Apple toolchains). - auto new_arg = arg; - // Bazel doesn't quote arguments in multi-line params files, so we need to - // ensure that our defensive quoting kicks in if an argument contains a - // space, even if no other changes would have been made. - changed = bazel_placeholder_substitutions_.Apply(new_arg) || - new_arg.find_first_of(' ') != std::string::npos; - consumer(new_arg); + std::string new_arg = arg; + if (StripPrefix("-Xwrapped-swift=", new_arg)) { + if (new_arg == "-debug-prefix-pwd-is-dot") { + // Get the actual current working directory (the workspace root), which + // we didn't know at analysis time. + consumer("-debug-prefix-map"); + consumer(GetCurrentDirectory() + "=."); + changed = true; + } else if (new_arg == "-coverage-prefix-pwd-is-dot") { + // Get the actual current working directory (the workspace root), which we + // didn't know at analysis time. + consumer("-coverage-prefix-map"); + consumer(GetCurrentDirectory() + "=."); + changed = true; + } else if (new_arg == "-ephemeral-module-cache") { + // Create a temporary directory to hold the module cache, which will be + // deleted after compilation is finished. + auto module_cache_dir = + TempDirectory::Create("swift_module_cache.XXXXXX"); + consumer("-module-cache-path"); + consumer(module_cache_dir->GetPath()); + temp_directories_.push_back(std::move(module_cache_dir)); + changed = true; + } else if (StripPrefix("-generated-header-rewriter=", new_arg)) { + generated_header_rewriter_path_ = new_arg; + changed = true; + } else { + // TODO(allevato): Report that an unknown wrapper arg was found and give + // the caller a way to exit gracefully. + changed = true; + } + } else { + // Apply any other text substitutions needed in the argument (i.e., for + // Apple toolchains). + // + // Bazel doesn't quote arguments in multi-line params files, so we need to + // ensure that our defensive quoting kicks in if an argument contains a + // space, even if no other changes would have been made. + changed = bazel_placeholder_substitutions_.Apply(new_arg) || + new_arg.find_first_of(' ') != std::string::npos; + consumer(new_arg); + } } return changed; diff --git a/tools/worker/swift_runner.h b/tools/worker/swift_runner.h index d2cfe67d5..e662b614c 100644 --- a/tools/worker/swift_runner.h +++ b/tools/worker/swift_runner.h @@ -124,6 +124,10 @@ class SwiftRunner { // Arguments will be unconditionally written into a response file and passed // to the tool that way. bool force_response_file_; + + // The path to the generated header rewriter tool, if one is being used for + // this compilation. + std::string generated_header_rewriter_path_; }; #endif // BUILD_BAZEL_RULES_SWIFT_TOOLS_WORKER_SWIFT_RUNNER_H_ From bb2efe2ca973ab087bf6c323f247ead9cc021c58 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Mon, 3 May 2021 18:16:30 -0700 Subject: [PATCH 111/152] Disable generated_header_rewriter for now This doesn't work without nested functions. I think this use case is pretty rare but if someone wants to enable this before bazel supports nested functions that's fine. --- swift/internal/compiling.bzl | 38 ++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index ca279f342..35255c3c7 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -51,7 +51,6 @@ load( "SWIFT_FEATURE_OPT", "SWIFT_FEATURE_OPT_USES_OSIZE", "SWIFT_FEATURE_OPT_USES_WMO", - "SWIFT_FEATURE_REWRITE_GENERATED_HEADER", "SWIFT_FEATURE_SPLIT_DERIVED_FILES_GENERATION", "SWIFT_FEATURE_STRICT_MODULES", "SWIFT_FEATURE_SUPPORTS_LIBRARY_EVOLUTION", @@ -221,24 +220,25 @@ def compile_action_configs( ), ] - if generated_header_rewriter: - # Only add the generated header rewriter to the command line only if the - # toolchain provides one, the relevant feature is requested, and the - # particular compilation action is generating a header. - def generated_header_rewriter_configurator(prerequisites, args): - if prerequisites.generated_header_file: - args.add( - generated_header_rewriter, - format = "-Xwrapped-swift=-generated-header-rewriter=%s", - ) - - action_configs.append( - swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], - configurators = [generated_header_rewriter_configurator], - features = [SWIFT_FEATURE_REWRITE_GENERATED_HEADER], - ), - ) + # TODO: Enable once bazel supports nested functions + # if generated_header_rewriter: + # # Only add the generated header rewriter to the command line only if the + # # toolchain provides one, the relevant feature is requested, and the + # # particular compilation action is generating a header. + # def generated_header_rewriter_configurator(prerequisites, args): + # if prerequisites.generated_header_file: + # args.add( + # generated_header_rewriter, + # format = "-Xwrapped-swift=-generated-header-rewriter=%s", + # ) + + # action_configs.append( + # swift_toolchain_config.action_config( + # actions = [swift_action_names.COMPILE], + # configurators = [generated_header_rewriter_configurator], + # features = [SWIFT_FEATURE_REWRITE_GENERATED_HEADER], + # ), + # ) #### Compilation-mode-related flags # From b44baa3a9322958a6d7c3e5cb83dc4487741fddc Mon Sep 17 00:00:00 2001 From: Googler Date: Wed, 28 Apr 2021 14:52:50 -0700 Subject: [PATCH 112/152] Make the strict include paths from `objc_proto_library` targets available so headers can be found when `swift_clang_module_aspect` compiles a module. `swift_clang_module_aspect` assumes that CcInfo contains all of the necessary compiler flags to be able to find the headers that are used when compiling an explicit module. This is true for all flags except the header search path in the Objc provider's `strict_include` field. This means that the `strict_include` field needs to be explicitly translated to an equivalent CcInfo when compiling the module. PiperOrigin-RevId: 370991285 (cherry picked from commit 1aca023d007646d44da3512bac05ebbad64e8135) --- swift/internal/swift_clang_module_aspect.bzl | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/swift/internal/swift_clang_module_aspect.bzl b/swift/internal/swift_clang_module_aspect.bzl index d7839b0f0..7a934e6a6 100644 --- a/swift/internal/swift_clang_module_aspect.bzl +++ b/swift/internal/swift_clang_module_aspect.bzl @@ -472,6 +472,14 @@ def _handle_module( compilation_context = dep[CcInfo].compilation_context, ), ) + if apple_common.Objc in dep: + target_and_deps_cc_infos.append( + CcInfo( + compilation_context = cc_common.create_compilation_context( + includes = dep[apple_common.Objc].strict_include, + ), + ), + ) compilation_context_to_compile = cc_common.merge_cc_infos( direct_cc_infos = target_and_deps_cc_infos, From 000401112b4584f887de4696da78e201d8c6b2ec Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Mon, 3 May 2021 07:35:31 -0700 Subject: [PATCH 113/152] Rename `swift.strict_modules` to `swift.layering_check` to match the C++ feature name. PiperOrigin-RevId: 371693623 (cherry picked from commit 06322f12a2dcbcafb33e598416486c25bef621c8) --- swift/internal/compiling.bzl | 6 +++--- swift/internal/feature_names.bzl | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index 35255c3c7..a923991cc 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -45,6 +45,7 @@ load( "SWIFT_FEATURE_FASTBUILD", "SWIFT_FEATURE_FULL_DEBUG_INFO", "SWIFT_FEATURE_INDEX_WHILE_BUILDING", + "SWIFT_FEATURE_LAYERING_CHECK", "SWIFT_FEATURE_MODULE_MAP_HOME_IS_CWD", "SWIFT_FEATURE_NO_EMBED_DEBUG_MODULE", "SWIFT_FEATURE_NO_GENERATED_MODULE_MAP", @@ -52,7 +53,6 @@ load( "SWIFT_FEATURE_OPT_USES_OSIZE", "SWIFT_FEATURE_OPT_USES_WMO", "SWIFT_FEATURE_SPLIT_DERIVED_FILES_GENERATION", - "SWIFT_FEATURE_STRICT_MODULES", "SWIFT_FEATURE_SUPPORTS_LIBRARY_EVOLUTION", "SWIFT_FEATURE_SYSTEM_MODULE", "SWIFT_FEATURE_USE_C_MODULES", @@ -562,7 +562,7 @@ def compile_action_configs( ), ], not_features = [ - [SWIFT_FEATURE_STRICT_MODULES], + [SWIFT_FEATURE_LAYERING_CHECK], [SWIFT_FEATURE_SYSTEM_MODULE], ], ), @@ -574,7 +574,7 @@ def compile_action_configs( "-fmodules-strict-decluse", ), ], - features = [SWIFT_FEATURE_STRICT_MODULES], + features = [SWIFT_FEATURE_LAYERING_CHECK], not_features = [SWIFT_FEATURE_SYSTEM_MODULE], ), swift_toolchain_config.action_config( diff --git a/swift/internal/feature_names.bzl b/swift/internal/feature_names.bzl index fafaae457..9623b6b54 100644 --- a/swift/internal/feature_names.bzl +++ b/swift/internal/feature_names.bzl @@ -66,7 +66,7 @@ SWIFT_FEATURE_EMIT_C_MODULE = "swift.emit_c_module" # If enabled, when compiling an explicit C or Objectve-C module, every header # included by the module being compiled must belong to one of the modules listed # in its dependencies. This is ignored for system modules. -SWIFT_FEATURE_STRICT_MODULES = "swift.strict_modules" +SWIFT_FEATURE_LAYERING_CHECK = "swift.layering_check" # If enabled, the C or Objective-C target should be compiled as a system module. SWIFT_FEATURE_SYSTEM_MODULE = "swift.system_module" From ee7e6e303df776fd611a3645f6272b9e4d784350 Mon Sep 17 00:00:00 2001 From: Googler Date: Mon, 3 May 2021 10:40:41 -0700 Subject: [PATCH 114/152] Add a user settable build setting to specify additional swiftcopts for a swift_libray target. The flag accepts a comma separated list of "target=copts" pairs, where "target" is a fully qualified target label and "copts" is a colon separated list of Swift copts. PiperOrigin-RevId: 371728552 (cherry picked from commit de9c4e1a00f779af382b2a9b96a2685b54a3f93a) --- swift/BUILD | 11 ++++ swift/internal/BUILD | 5 ++ swift/internal/attrs.bzl | 3 ++ swift/internal/build_settings.bzl | 85 +++++++++++++++++++++++++++++++ swift/internal/swift_library.bzl | 11 ++++ 5 files changed, 115 insertions(+) create mode 100644 swift/internal/build_settings.bzl diff --git a/swift/BUILD b/swift/BUILD index 9ac4eaa93..af2101f9a 100644 --- a/swift/BUILD +++ b/swift/BUILD @@ -1,5 +1,9 @@ load("@bazel_skylib//:bzl_library.bzl", "bzl_library") load("@bazel_skylib//rules:common_settings.bzl", "bool_setting") +load( + "//swift/internal:build_settings.bzl", + "per_module_swiftcopt_flag", +) package(default_visibility = ["//visibility:public"]) @@ -43,6 +47,13 @@ filegroup( ], ) +# User settable flag that specifies additional Swift copts on a per-swiftmodule basis. +per_module_swiftcopt_flag( + name = "per_module_swiftcopt", + build_setting_default = "", + visibility = ["//visibility:public"], +) + # Configuration setting for enabling the generation of swiftinterface files. bool_setting( name = "emit_swiftinterface", diff --git a/swift/internal/BUILD b/swift/internal/BUILD index 57c345add..6f5e35702 100644 --- a/swift/internal/BUILD +++ b/swift/internal/BUILD @@ -364,6 +364,11 @@ bzl_library( visibility = ["//swift:__subpackages__"], ) +bzl_library( + name = "build_settings", + srcs = ["build_settings.bzl"], +) + # Consumed by Bazel integration tests. filegroup( name = "for_bazel_tests", diff --git a/swift/internal/attrs.bzl b/swift/internal/attrs.bzl index 2be478884..bf1785110 100644 --- a/swift/internal/attrs.bzl +++ b/swift/internal/attrs.bzl @@ -152,6 +152,9 @@ def swift_config_attrs(): "_config_emit_swiftinterface": attr.label( default = "@build_bazel_rules_swift//swift:emit_swiftinterface", ), + "_per_module_swiftcopt": attr.label( + default = "@build_bazel_rules_swift//swift:per_module_swiftcopt", + ), } def swift_deps_attr(doc, **kwargs): diff --git a/swift/internal/build_settings.bzl b/swift/internal/build_settings.bzl new file mode 100644 index 000000000..447118bb8 --- /dev/null +++ b/swift/internal/build_settings.bzl @@ -0,0 +1,85 @@ +# Copyright 2021 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Custom build settings rules for Swift rules.""" + +PerModuleSwiftCoptSettingInfo = provider( + doc = "A provider for the parsed per-swiftmodule swift copts.", + fields = { + "value": "A map of target labels to lists of additional Swift copts to apply to" + + "the target.", + }, +) + +def additional_per_module_swiftcopts(label, provider): + """Returns additional swiftcopts to apply to a target named `label`. + + Args: + label: The label of the target. + provider: The `PerModuleSwiftCoptsSettingInfo` provider from the calling + context. + Returns: + A list of additional swiftcopts to use when builing the target. + """ + per_module_copts = provider.value + if per_module_copts: + target_label = str(label) + return per_module_copts.get(target_label, []) + return [] + +def _per_module_swiftcopt_flag_impl(ctx): + # Each item in this list should of the form + # "=". + module_and_copts_list = ctx.build_setting_value + value = dict() + for item in module_and_copts_list: + if not item: + continue + contents = item.split("=", 1) + if len(contents) != 2: + fail("""\ +--per_module_swiftcopt must be written as a target label, an equal sign \ +("="), and a comma-delimited list of compiler flags. For example, \ +"//package:target=-copt,-copt,...".""") + + # Canonicalize the label using the `Label` constructor. + label = str(Label(contents[0])) + raw_copts = contents[1] + + # TODO(b/186875113): This breaks if any of the copts actually use + # commas. Switch to a more selective approach to splitting, + # respecting an escape sequence for commas inside of copts. + copts = raw_copts.split(",") + if len(copts) > 0: + existing_copts = value.get(label) + if existing_copts: + existing_copts.extend(copts) + else: + value[label] = copts + return PerModuleSwiftCoptSettingInfo(value = value) + +per_module_swiftcopt_flag = rule( + build_setting = config.string( + flag = True, + allow_multiple = True, + ), + # TODO(b/186869451): Support adding swiftcopts by module name in addition + # to the target label. + doc = """\ +A string list build setting that can be set on the command line. Each item in +the list is expected to be of the form: = where +copts is a colon separated list of Swift copts. +""", + implementation = _per_module_swiftcopt_flag_impl, +) diff --git a/swift/internal/swift_library.bzl b/swift/internal/swift_library.bzl index e8a961fc7..931318d42 100644 --- a/swift/internal/swift_library.bzl +++ b/swift/internal/swift_library.bzl @@ -15,6 +15,11 @@ """Implementation of the `swift_library` rule.""" load(":attrs.bzl", "swift_deps_attr") +load( + ":build_settings.bzl", + "PerModuleSwiftCoptSettingInfo", + "additional_per_module_swiftcopts", +) load( ":compiling.bzl", "new_objc_provider", @@ -107,6 +112,12 @@ def _swift_library_impl(ctx): linkopts = expand_make_variables(ctx, linkopts, "linkopts") srcs = ctx.files.srcs + module_copts = additional_per_module_swiftcopts( + ctx.label, + ctx.attr._per_module_swiftcopt[PerModuleSwiftCoptSettingInfo], + ) + copts.extend(module_copts) + extra_features = [] if ctx.attr._config_emit_swiftinterface[BuildSettingInfo].value: extra_features.append(SWIFT_FEATURE_ENABLE_LIBRARY_EVOLUTION) From 51a8f827d8aa6f2de2a1897aff4a1906d8b2f7c3 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Mon, 3 May 2021 18:25:44 -0700 Subject: [PATCH 115/152] Disable allow_multiple for per_module_swiftcopt_flag Bazel doesn't support this yet --- swift/internal/build_settings.bzl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/swift/internal/build_settings.bzl b/swift/internal/build_settings.bzl index 447118bb8..858496fdf 100644 --- a/swift/internal/build_settings.bzl +++ b/swift/internal/build_settings.bzl @@ -41,7 +41,8 @@ def additional_per_module_swiftcopts(label, provider): def _per_module_swiftcopt_flag_impl(ctx): # Each item in this list should of the form # "=". - module_and_copts_list = ctx.build_setting_value + # TODO: Remove extra list once allow_multiple is enabled + module_and_copts_list = [ctx.build_setting_value] value = dict() for item in module_and_copts_list: if not item: @@ -72,7 +73,7 @@ def _per_module_swiftcopt_flag_impl(ctx): per_module_swiftcopt_flag = rule( build_setting = config.string( flag = True, - allow_multiple = True, + # allow_multiple = True, # TODO: Enable once bazel supports it ), # TODO(b/186869451): Support adding swiftcopts by module name in addition # to the target label. From 52827d975cddc1f7ce8b242ff375eef7b6bc45a2 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Mon, 3 May 2021 19:06:08 -0700 Subject: [PATCH 116/152] Update README with new URLs --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bf26fe20e..cc5d82cfd 100644 --- a/README.md +++ b/README.md @@ -51,8 +51,8 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "build_bazel_rules_swift", - sha256 = "a525d254b0323380b7abe7cbbe03534167f0fcb45f44f7d16cdd4d7d057b8f8d", - url = "https://github.com/bazelbuild/rules_swift/releases/download/0.20.0/rules_swift.0.20.0.tar.gz", + sha256 = "8407fa0fd04a7ce1d6bb95e90b216404466f809eda459c23cb57b5fa1ef9d639", + url = "https://github.com/bazelbuild/rules_swift/releases/download/0.21.0/rules_swift.0.21.0.tar.gz", ) load( From aab5e21516bf971faba6053a414dac26224e588e Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Tue, 4 May 2021 06:39:27 -0700 Subject: [PATCH 117/152] Use target_compatible_with for macOS only tests (#514) --- test/BUILD | 8 -------- test/coverage_settings_tests.bzl | 12 +++++------- test/debug_settings_tests.bzl | 12 +++++------- test/split_derived_files_tests.bzl | 16 ++++------------ 4 files changed, 14 insertions(+), 34 deletions(-) diff --git a/test/BUILD b/test/BUILD index fb4afe0d7..70dcb37e7 100644 --- a/test/BUILD +++ b/test/BUILD @@ -32,11 +32,3 @@ bzl_library( "//test/rules:starlark_tests_bzls", ], ) - -# TODO: Remove once https://github.com/bazelbuild/bazel/pull/10945 lands -config_setting( - name = "linux", - constraint_values = [ - "@bazel_tools//platforms:linux", - ], -) diff --git a/test/coverage_settings_tests.bzl b/test/coverage_settings_tests.bzl index 397b8ffb9..b14e58234 100644 --- a/test/coverage_settings_tests.bzl +++ b/test/coverage_settings_tests.bzl @@ -65,13 +65,11 @@ def coverage_settings_test_suite(name = "coverage_settings"): coverage_xcode_prefix_map_test( name = "{}_xcode_prefix_map".format(name), tags = [name], - expected_argv = select({ - "//test:linux": [], - "//conditions:default": [ - "-coverage-prefix-map", - "__BAZEL_XCODE_DEVELOPER_DIR__=DEVELOPER_DIR", - ], - }), + expected_argv = [ + "-coverage-prefix-map", + "__BAZEL_XCODE_DEVELOPER_DIR__=DEVELOPER_DIR", + ], + target_compatible_with = ["@platforms//os:macos"], mnemonic = "SwiftCompile", target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", ) diff --git a/test/debug_settings_tests.bzl b/test/debug_settings_tests.bzl index 380572583..49d5a61d6 100644 --- a/test/debug_settings_tests.bzl +++ b/test/debug_settings_tests.bzl @@ -225,13 +225,11 @@ def debug_settings_test_suite(name = "debug_settings"): xcode_remap_command_line_test( name = "{}_remap_xcode_path".format(name), - expected_argv = select({ - "//test:linux": [], - "//conditions:default": [ - "-debug-prefix-map", - "__BAZEL_XCODE_DEVELOPER_DIR__=DEVELOPER_DIR", - ], - }), + expected_argv = [ + "-debug-prefix-map", + "__BAZEL_XCODE_DEVELOPER_DIR__=DEVELOPER_DIR", + ], + target_compatible_with = ["@platforms//os:macos"], mnemonic = "SwiftCompile", tags = [name], target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", diff --git a/test/split_derived_files_tests.bzl b/test/split_derived_files_tests.bzl index 34839ebae..5aa8243a5 100644 --- a/test/split_derived_files_tests.bzl +++ b/test/split_derived_files_tests.bzl @@ -274,12 +274,8 @@ def split_derived_files_test_suite(name = "split_derived_files"): split_swiftmodule_bitcode_test( name = "{}_bitcode_compile".format(name), - expected_argv = select({ - "//test:linux": [], - "//conditions:default": [ - "-embed-bitcode", - ], - }), + expected_argv = ["-embed-bitcode"], + target_compatible_with = ["@platforms//os:macos"], mnemonic = "SwiftCompile", tags = [name], target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", @@ -297,12 +293,8 @@ def split_derived_files_test_suite(name = "split_derived_files"): split_swiftmodule_bitcode_markers_test( name = "{}_bitcode_markers_compile".format(name), - expected_argv = select({ - "//test:linux": [], - "//conditions:default": [ - "-embed-bitcode-marker", - ], - }), + expected_argv = ["-embed-bitcode-marker"], + target_compatible_with = ["@platforms//os:macos"], mnemonic = "SwiftCompile", tags = [name], target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", From 83d2fb709b5453df747f3445420a9f63bde0b8cf Mon Sep 17 00:00:00 2001 From: Brentley Jones Date: Wed, 12 May 2021 22:28:05 -0500 Subject: [PATCH 118/152] Add `swift.global_module_cache_uses_tmpdir` feature (#581) * Add `swift.global_module_cache_uses_tmpdir` feature This adds a new feature, that can be enabled by passing `--features=swift.use_global_module_cache` and `--features=swift.global_module_cache_uses_tmpdir` to the build command. This feature, when enabled, will makes the Swift compilation actions use the shared Clang module cache path written to `/tmp/__build_bazel_rules_swift/swift_module_cache/REPOSITORY_NAME`. This makes the embedded Clang module breadcrumbs deterministic between Bazel instances, because they are always embedded as absolute paths. Note that the use of this cache is non-hermetic--the cached modules are not wiped between builds, and won't be cleaned when invoking bazel clean; the user is responsible for manually cleaning them. Additionally, this can be used as a workaround for a bug in the Swift compiler that causes the module breadcrumbs to be embedded even though the `-no-clang-module-breadcrumbs` flag is passed (https://bugs.swift.org/browse/SR-13275). Since the source path of modulemaps might be different for the same module, (i.e. multiple checkouts of the same repository, or remote execution), multiple modules with different hashes can end up in the cache. This can result in build failures. Don't use this feature with sandboxing (or probably remote execution as well). --- swift/internal/compiling.bzl | 33 +++++++ swift/internal/feature_names.bzl | 23 +++++ swift/internal/swift_binary_test.bzl | 1 + swift/internal/swift_grpc_library.bzl | 1 + swift/internal/swift_library.bzl | 1 + swift/internal/swift_module_alias.bzl | 1 + swift/internal/swift_protoc_gen_aspect.bzl | 1 + test/BUILD | 3 + test/module_cache_settings_tests.bzl | 103 +++++++++++++++++++++ 9 files changed, 167 insertions(+) create mode 100644 test/module_cache_settings_tests.bzl diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index a923991cc..5facd35f8 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -44,6 +44,7 @@ load( "SWIFT_FEATURE_ENABLE_TESTING", "SWIFT_FEATURE_FASTBUILD", "SWIFT_FEATURE_FULL_DEBUG_INFO", + "SWIFT_FEATURE_GLOBAL_MODULE_CACHE_USES_TMPDIR", "SWIFT_FEATURE_INDEX_WHILE_BUILDING", "SWIFT_FEATURE_LAYERING_CHECK", "SWIFT_FEATURE_MODULE_MAP_HOME_IS_CWD", @@ -492,6 +493,21 @@ def compile_action_configs( ], configurators = [_global_module_cache_configurator], features = [SWIFT_FEATURE_USE_GLOBAL_MODULE_CACHE], + not_features = [ + [SWIFT_FEATURE_USE_C_MODULES], + [SWIFT_FEATURE_GLOBAL_MODULE_CACHE_USES_TMPDIR], + ], + ), + swift_toolchain_config.action_config( + actions = [ + swift_action_names.COMPILE, + swift_action_names.DERIVE_FILES, + ], + configurators = [_tmpdir_module_cache_configurator], + features = [ + SWIFT_FEATURE_USE_GLOBAL_MODULE_CACHE, + SWIFT_FEATURE_GLOBAL_MODULE_CACHE_USES_TMPDIR, + ], not_features = [SWIFT_FEATURE_USE_C_MODULES], ), swift_toolchain_config.action_config( @@ -951,6 +967,18 @@ def _global_module_cache_configurator(prerequisites, args): paths.join(prerequisites.bin_dir.path, "_swift_module_cache"), ) +def _tmpdir_module_cache_configurator(prerequisites, args): + """Adds flags to enable a stable tmp directory module cache.""" + + args.add( + "-module-cache-path", + paths.join( + "/tmp/__build_bazel_rules_swift", + "swift_module_cache", + prerequisites.workspace_name, + ), + ) + def _batch_mode_configurator(prerequisites, args): """Adds flags to enable batch compilation mode.""" if not _is_wmo_manually_requested(prerequisites.user_compile_flags): @@ -1487,6 +1515,7 @@ def compile( srcs, swift_toolchain, target_name, + workspace_name, additional_inputs = [], bin_dir = None, copts = [], @@ -1509,6 +1538,9 @@ def compile( target_name: The name of the target for which the code is being compiled, which is used to determine unique file paths for the outputs. + workspace_name: The name of the workspace for which the code is being + compiled, which is used to determine unique file paths for some + outputs. additional_inputs: A list of `File`s representing additional input files that need to be passed to the Swift compile action because they are referenced by compiler flags. @@ -1703,6 +1735,7 @@ def compile( user_compile_flags = copts, vfsoverlay_file = vfsoverlay_file, vfsoverlay_search_path = _SWIFTMODULES_VFS_ROOT, + workspace_name = workspace_name, # Merge the compile outputs into the prerequisites. **struct_fields(compile_outputs) ) diff --git a/swift/internal/feature_names.bzl b/swift/internal/feature_names.bzl index 9623b6b54..589bd724e 100644 --- a/swift/internal/feature_names.bzl +++ b/swift/internal/feature_names.bzl @@ -142,6 +142,29 @@ SWIFT_FEATURE_USE_C_MODULES = "swift.use_c_modules" # crashes. SWIFT_FEATURE_USE_GLOBAL_MODULE_CACHE = "swift.use_global_module_cache" +# If enabled, and Swift compilation actions will use the shared Clang module +# cache path written to +# `/private/tmp/__build_bazel_rules_swift/swift_module_cache/REPOSITORY_NAME`. +# This makes the embedded Clang module breadcrumbs deterministic between Bazel +# instances, because they are always embedded as absolute paths. Note that the +# use of this cache is non-hermetic--the cached modules are not wiped between +# builds, and won't be cleaned when invoking `bazel clean`; the user is +# responsible for manually cleaning them. +# +# Additionally, this can be used as a workaround for a bug in the Swift +# compiler that causes the module breadcrumbs to be embedded even though the +# `-no-clang-module-breadcrumbs` flag is passed +# (https://bugs.swift.org/browse/SR-13275). +# +# Since the source path of modulemaps might be different for the same module, +# (i.e. multiple checkouts of the same repository, or remote execution), +# multiple modules with different hashes can end up in the cache. This can +# result in build failures. Don't use this feature with sandboxing (or +# probably remote execution as well). +# +# This feature requires `swift.use_global_module_cache` to be enabled. +SWIFT_FEATURE_GLOBAL_MODULE_CACHE_USES_TMPDIR = "swift.global_module_cache_uses_tmpdir" + # If enabled, actions invoking the Swift driver or frontend may write argument # lists into response files (i.e., "@args.txt") to avoid passing command lines # that exceed the system limit. Toolchains typically set this automatically if diff --git a/swift/internal/swift_binary_test.bzl b/swift/internal/swift_binary_test.bzl index 2a4490882..0444b7a21 100644 --- a/swift/internal/swift_binary_test.bzl +++ b/swift/internal/swift_binary_test.bzl @@ -199,6 +199,7 @@ def _swift_linking_rule_impl( srcs = srcs, swift_toolchain = swift_toolchain, target_name = ctx.label.name, + workspace_name = ctx.workspace_name, ) user_link_flags.extend(compilation_outputs.linker_flags) objects_to_link.extend(compilation_outputs.object_files) diff --git a/swift/internal/swift_grpc_library.bzl b/swift/internal/swift_grpc_library.bzl index 781600600..91babff32 100644 --- a/swift/internal/swift_grpc_library.bzl +++ b/swift/internal/swift_grpc_library.bzl @@ -290,6 +290,7 @@ def _swift_grpc_library_impl(ctx): srcs = generated_files, swift_toolchain = swift_toolchain, target_name = ctx.label.name, + workspace_name = ctx.workspace_name, ) linker_input, library_to_link = create_linker_input( diff --git a/swift/internal/swift_library.bzl b/swift/internal/swift_library.bzl index 931318d42..de5bc9d09 100644 --- a/swift/internal/swift_library.bzl +++ b/swift/internal/swift_library.bzl @@ -187,6 +187,7 @@ def _swift_library_impl(ctx): srcs = srcs, swift_toolchain = swift_toolchain, target_name = ctx.label.name, + workspace_name = ctx.workspace_name, ) # If a module was created for the generated header, propagate it as well so diff --git a/swift/internal/swift_module_alias.bzl b/swift/internal/swift_module_alias.bzl index 05eb449ca..66942b40c 100644 --- a/swift/internal/swift_module_alias.bzl +++ b/swift/internal/swift_module_alias.bzl @@ -70,6 +70,7 @@ def _swift_module_alias_impl(ctx): srcs = [reexport_src], swift_toolchain = swift_toolchain, target_name = ctx.label.name, + workspace_name = ctx.workspace_name, ) linker_input, library_to_link = create_linker_input( diff --git a/swift/internal/swift_protoc_gen_aspect.bzl b/swift/internal/swift_protoc_gen_aspect.bzl index fd161fb47..31ef772d5 100644 --- a/swift/internal/swift_protoc_gen_aspect.bzl +++ b/swift/internal/swift_protoc_gen_aspect.bzl @@ -423,6 +423,7 @@ def _swift_protoc_gen_aspect_impl(target, aspect_ctx): srcs = pbswift_files, swift_toolchain = swift_toolchain, target_name = target.label.name, + workspace_name = aspect_ctx.workspace_name, ) linker_input, library_to_link = create_linker_input( diff --git a/test/BUILD b/test/BUILD index 70dcb37e7..9d0783f77 100644 --- a/test/BUILD +++ b/test/BUILD @@ -2,6 +2,7 @@ load("@bazel_skylib//:bzl_library.bzl", "bzl_library") load(":debug_settings_tests.bzl", "debug_settings_test_suite") load(":coverage_settings_tests.bzl", "coverage_settings_test_suite") load(":generated_header_tests.bzl", "generated_header_test_suite") +load(":module_cache_settings_tests.bzl", "module_cache_settings_test_suite") load(":private_deps_tests.bzl", "private_deps_test_suite") load(":swift_through_non_swift_tests.bzl", "swift_through_non_swift_test_suite") load(":split_derived_files_tests.bzl", "split_derived_files_test_suite") @@ -14,6 +15,8 @@ coverage_settings_test_suite() generated_header_test_suite() +module_cache_settings_test_suite() + private_deps_test_suite() swift_through_non_swift_test_suite() diff --git a/test/module_cache_settings_tests.bzl b/test/module_cache_settings_tests.bzl new file mode 100644 index 000000000..da5cde047 --- /dev/null +++ b/test/module_cache_settings_tests.bzl @@ -0,0 +1,103 @@ +# Copyright 2021 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Tests for module cache related command line flags under various configs.""" + +load( + "@build_bazel_rules_swift//test/rules:action_command_line_test.bzl", + "make_action_command_line_test_rule", +) + +use_global_module_cache_action_command_line_test = make_action_command_line_test_rule( + config_settings = { + "//command_line_option:features": [ + "swift.use_global_module_cache", + ], + }, +) + +global_module_cache_uses_tmpdir_action_command_line_test = make_action_command_line_test_rule( + config_settings = { + "//command_line_option:features": [ + "swift.global_module_cache_uses_tmpdir", + "swift.use_global_module_cache", + ], + }, +) + +incorrect_global_module_cache_uses_tmpdir_action_command_line_test = make_action_command_line_test_rule( + config_settings = { + "//command_line_option:features": [ + "swift.global_module_cache_uses_tmpdir", + ], + }, +) + +def module_cache_settings_test_suite(name = "module_cache_settings"): + """Test suite for module cache options. + + Args: + name: The name prefix for all the nested tests + """ + + # Verify that a global module cache path is passed to swiftc. + use_global_module_cache_action_command_line_test( + name = "{}_global_module_cache_build".format(name), + expected_argv = [ + "-module-cache-path", + # Starlark doesn't have support for regular expression yet, so we + # can't verify the whole argument here. + "/bin/_swift_module_cache", + ], + not_expected_argv = [ + "-Xwrapped-swift=-ephemeral-module-cache", + "/tmp/__build_bazel_rules_swift/swift_module_cache/build_bazel_rules_swift", + ], + mnemonic = "SwiftCompile", + tags = [name], + target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", + ) + + # Verify that a pre-defined shared module cache path in `/tmp` is + # passed to swiftc. + global_module_cache_uses_tmpdir_action_command_line_test( + name = "{}_tmpdir_module_cache_build".format(name), + expected_argv = [ + "-module-cache-path", + "/tmp/__build_bazel_rules_swift/swift_module_cache/build_bazel_rules_swift", + ], + not_expected_argv = [ + "-Xwrapped-swift=-ephemeral-module-cache", + ], + mnemonic = "SwiftCompile", + tags = [name], + target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", + ) + + # Verify that no module cache path is used when only + # `swift.global_module_cache_uses_tmpdir` is passed. + incorrect_global_module_cache_uses_tmpdir_action_command_line_test( + name = "{}_incorrect_tmpdir_module_cache_build".format(name), + not_expected_argv = [ + "/tmp/__build_bazel_rules_swift/swift_module_cache/build_bazel_rules_swift", + ], + mnemonic = "SwiftCompile", + tags = [name], + target_under_test = "@build_bazel_rules_swift//test/fixtures/debug_settings:simple", + ) + + native.test_suite( + name = name, + tags = [name], + ) From e64d472785ab47671375f8571dd2cafdfae89e66 Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Fri, 14 May 2021 12:41:35 -0700 Subject: [PATCH 119/152] Stop passing `uses_swift` to `new_objc_provider`. This flag hasn't been used by Bazel for a very very very very very long time. PiperOrigin-RevId: 373845026 (cherry picked from commit 05f18b8b495a6b3385b708d2d906b224a8913be6) --- swift/internal/compiling.bzl | 1 - swift/internal/swift_protoc_gen_aspect.bzl | 1 - 2 files changed, 2 deletions(-) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index 5facd35f8..4c9f38d49 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -2377,7 +2377,6 @@ def new_objc_provider( objc_provider_args = { "link_inputs": depset(direct = swiftmodules + link_inputs), "providers": all_objc_providers, - "uses_swift": True, } # The link action registered by `apple_binary` only looks at `Objc` diff --git a/swift/internal/swift_protoc_gen_aspect.bzl b/swift/internal/swift_protoc_gen_aspect.bzl index 31ef772d5..9103266a5 100644 --- a/swift/internal/swift_protoc_gen_aspect.bzl +++ b/swift/internal/swift_protoc_gen_aspect.bzl @@ -500,7 +500,6 @@ def _swift_protoc_gen_aspect_impl(target, aspect_ctx): includes = [aspect_ctx.bin_dir.path] objc_info = apple_common.new_objc_provider( providers = objc_infos, - uses_swift = True, **objc_info_args ) else: From c674b9de71876c65153c2345c482e84c6a887058 Mon Sep 17 00:00:00 2001 From: Alex Eagle Date: Tue, 18 May 2021 12:54:47 -0700 Subject: [PATCH 120/152] Enable CI testing for docgen (#617) --- .bazelci/presubmit.yml | 1 + doc/BUILD.bazel | 126 ++++++++++++++++++++++++++--------------- doc/aspects.md | 29 +++++++--- swift/internal/BUILD | 2 + 4 files changed, 105 insertions(+), 53 deletions(-) diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index 7140dd33b..f658181a9 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -25,6 +25,7 @@ x_defaults: test_flags: *linux_flags test_targets: - "--" + - "//doc/..." - "//examples/..." - "//test/..." - "-//examples/apple/..." diff --git a/doc/BUILD.bazel b/doc/BUILD.bazel index 4e3f25efe..245aa23fc 100644 --- a/doc/BUILD.bazel +++ b/doc/BUILD.bazel @@ -2,23 +2,45 @@ load("@bazel_skylib//rules:write_file.bzl", "write_file") load("@bazel_skylib//rules:diff_test.bzl", "diff_test") load("@io_bazel_stardoc//stardoc:stardoc.bzl", "stardoc") -_RULES_SYMBOLS = [ - "swift_binary", - "swift_c_module", - "swift_grpc_library", - "swift_import", - "swift_library", - "swift_module_alias", - "swift_proto_library", - "swift_test", -] +_DOC_SRCS = { + "aspects": [ + "swift_usage_aspect", + ], + "providers": [ + "SwiftInfo", + "SwiftToolchainInfo", + "SwiftProtoInfo", + "SwiftUsageInfo", + ], + "rules": [ + "swift_binary", + "swift_c_module", + "swift_grpc_library", + "swift_import", + "swift_library", + "swift_module_alias", + "swift_proto_library", + "swift_test", + ], +} -_PROVIDERS_SYMBOLS = [ - "SwiftInfo", - "SwiftToolchainInfo", - "SwiftProtoInfo", - "SwiftUsageInfo", -] +write_file( + name = "aspects_header", + out = "aspects_header.vm", + content = [ + "", + "# Aspects", + "", + "The aspects described below are used within the build rule implementations.", + "Clients interested in writing custom rules that interface with the rules/provides", + "in this package might needs them to provide some of the same information.", + "", + "On this page:", + "", + ] + [" * [{0}](#{0})".format(r) for r in _DOC_SRCS["aspects"]] + [ + "", + ], +) write_file( name = "rules_header", @@ -29,7 +51,7 @@ write_file( "${moduleDocstring}", "On this page:", "", - ] + [" * [{0}](#{0})".format(r) for r in _RULES_SYMBOLS] + [ + ] + [" * [{0}](#{0})".format(r) for r in _DOC_SRCS["rules"]] + [ "", ], ) @@ -47,41 +69,53 @@ write_file( "", "On this page:", "", - ] + [" * [{0}](#{0})".format(r) for r in _PROVIDERS_SYMBOLS] + [ + ] + [" * [{0}](#{0})".format(r) for r in _DOC_SRCS["providers"]] + [ "", ], ) -stardoc( - name = "rules_doc", - out = "rules.md_", - header_template = ":rules_header.vm", - input = "//swift:swift.bzl", - symbol_names = _RULES_SYMBOLS, - deps = ["//swift"], -) +[ + stardoc( + name = file + "_doc", + out = file + ".md_", + header_template = file + "_header.vm", + input = "//swift:swift.bzl", + symbol_names = symbols, + deps = ["//swift"], + ) + for [ + file, + symbols, + ] in _DOC_SRCS.items() +] -stardoc( - name = "providers_doc", - out = "providers.md_", - header_template = ":providers_header.vm", - input = "//swift:swift.bzl", - symbol_names = _PROVIDERS_SYMBOLS, - deps = ["//swift"], -) +# To make these tests pass, run +# bazel run //doc:update +[ + diff_test( + name = "test_" + file, + file1 = file + ".md_", + file2 = file + ".md", + ) + for file in _DOC_SRCS.keys() +] -# To make this test pass, run -# bazel build doc:all && cp bazel-bin/doc/rules.md_ doc/rules.md -diff_test( - name = "test_rules", - file1 = "rules.md_", - file2 = "rules.md", +write_file( + name = "gen_update", + out = "update.sh", + content = [ + "#!/usr/bin/env bash", + "cd $BUILD_WORKSPACE_DIRECTORY", + ] + [ + "cp -fv bazel-bin/doc/{0}.md_ doc/{0}.md".format( + file, + ) + for file in _DOC_SRCS.keys() + ], ) -# To make this test pass, run -# bazel build doc:all && cp bazel-bin/doc/providers.md_ doc/providers.md -diff_test( - name = "test_providers", - file1 = "providers.md_", - file2 = "providers.md", +sh_binary( + name = "update", + srcs = ["update.sh"], + data = [file + ".md_" for file in _DOC_SRCS.keys()], ) diff --git a/doc/aspects.md b/doc/aspects.md index c6031c107..d28f385e2 100644 --- a/doc/aspects.md +++ b/doc/aspects.md @@ -1,9 +1,6 @@ + # Aspects - - - - The aspects described below are used within the build rule implementations. Clients interested in writing custom rules that interface with the rules/provides in this package might needs them to provide some of the same information. @@ -12,11 +9,12 @@ On this page: * [swift_usage_aspect](#swift_usage_aspect) - + + ## swift_usage_aspect -
-swift_usage_aspect()
+
+swift_usage_aspect(name)
 
Collects information about how Swift is used in a dependency tree. @@ -40,3 +38,20 @@ providers returned by `swift_library`) because the information is needed if Swift is used _anywhere_ in a dependency graph, even as dependencies of other language rules that wouldn't know how to propagate the Swift-specific providers. + +**ASPECT ATTRIBUTES** + + +| Name | Type | +| :------------- | :------------- | +| deps| String | + + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | + + diff --git a/swift/internal/BUILD b/swift/internal/BUILD index 6f5e35702..5a83d02a1 100644 --- a/swift/internal/BUILD +++ b/swift/internal/BUILD @@ -146,6 +146,7 @@ bzl_library( bzl_library( name = "swift_binary_test", + srcs = ["swift_binary_test.bzl"], visibility = ["//swift:__subpackages__"], deps = [ ":compiling", @@ -227,6 +228,7 @@ bzl_library( visibility = ["//swift:__subpackages__"], deps = [ ":attrs", + ":build_settings", ":compiling", ":feature_names", ":linking", From ae0c5bdf40068c447d1ac0c62e1ea71ec6d9b201 Mon Sep 17 00:00:00 2001 From: Alex Eagle Date: Tue, 18 May 2021 16:39:14 -0700 Subject: [PATCH 121/152] Generate api.md from sources (#618) --- WORKSPACE | 2 +- doc/BUILD.bazel | 16 + doc/api.md | 1056 +++++++++++++-------------------------- doc/stardoc.pr103.patch | 12 + 4 files changed, 377 insertions(+), 709 deletions(-) create mode 100644 doc/stardoc.pr103.patch diff --git a/WORKSPACE b/WORKSPACE index dc6ef478a..c48f7685a 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -25,7 +25,7 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "io_bazel_stardoc", - patches = [], + patches = ["//doc:stardoc.pr103.patch"], sha256 = "f89bda7b6b696c777b5cf0ba66c80d5aa97a6701977d43789a9aee319eef71e8", strip_prefix = "stardoc-d93ee5347e2d9c225ad315094507e018364d5a67", urls = [ diff --git a/doc/BUILD.bazel b/doc/BUILD.bazel index 245aa23fc..dd4f80111 100644 --- a/doc/BUILD.bazel +++ b/doc/BUILD.bazel @@ -3,6 +3,9 @@ load("@bazel_skylib//rules:diff_test.bzl", "diff_test") load("@io_bazel_stardoc//stardoc:stardoc.bzl", "stardoc") _DOC_SRCS = { + "api": [ + "swift_common", + ], "aspects": [ "swift_usage_aspect", ], @@ -24,6 +27,19 @@ _DOC_SRCS = { ], } +write_file( + name = "api_header", + out = "api_header.vm", + content = [ + "", + "# Build API", + "", + "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.", + ], +) + write_file( name = "aspects_header", out = "aspects_header.vm", diff --git a/doc/api.md b/doc/api.md index 656c2e6e3..472e1d935 100644 --- a/doc/api.md +++ b/doc/api.md @@ -1,70 +1,39 @@ + # Build API - - - - 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. + -On this page: - - * [swift_common.cc_feature_configuration](#swift_common.cc_feature_configuration) - * [swift_common.compilation_attrs](#swift_common.compilation_attrs) - * [swift_common.compile](#swift_common.compile) - * [swift_common.configure_features](#swift_common.configure_features) - * [swift_common.create_clang_module](#swift_common.create_clang_module) - * [swift_common.create_module](#swift_common.create_module) - * [swift_common.create_swift_info](#swift_common.create_swift_info) - * [swift_common.create_swift_module](#swift_common.create_swift_module) - * [swift_common.derive_module_name](#swift_common.derive_module_name) - * [swift_common.get_implicit_deps](#swift_common.get_implicit_deps) - * [swift_common.is_enabled](#swift_common.is_enabled) - * [swift_common.library_rule_attrs](#swift_common.library_rule_attrs) - * [swift_common.precompile_clang_module](#swift_common.precompile_clang_module) - * [swift_common.swift_clang_module_aspect](#swift_common.swift_clang_module_aspect) - * [swift_common.swift_runtime_linkopts](#swift_common.swift_runtime_linkopts) - * [swift_common.toolchain_attrs](#swift_common.toolchain_attrs) - - ## swift_common.cc_feature_configuration -
-swift_common.cc_feature_configuration(feature_configuration)
+
+swift_common.cc_feature_configuration(feature_configuration)
 
Returns the C++ feature configuration in a Swift feature configuration. - -### Arguments - - - - - - - - - - - - -
feature_configuration

Required

The Swift feature configuration, as returned from -swift_common.configure_features.

- - -### Returns +**PARAMETERS** + + +| Name | Description | Default Value | +| :------------- | :------------- | :------------- | +| feature_configuration | The Swift feature configuration, as returned from swift_common.configure_features. | none | + +**RETURNS** A C++ `FeatureConfiguration` value (see -[`cc_common.configure_features`](https://docs.bazel.build/versions/master/skylark/lib/cc_common.html#configure_features) -for more information). + [`cc_common.configure_features`](https://docs.bazel.build/versions/master/skylark/lib/cc_common.html#configure_features) + for more information). + + + - ## swift_common.compilation_attrs -
-swift_common.compilation_attrs(additional_deps_aspects=[])
+
+swift_common.compilation_attrs(additional_deps_aspects, requires_srcs)
 
Returns an attribute dictionary for rules that compile Swift code. @@ -93,172 +62,97 @@ API: Each of the attribute functions in the list above also contains the attributes from the earlier items in the list. - -### Arguments - - - - - - - - - - - - -
additional_deps_aspects

Optional; default is []

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.

- - -### Returns + +**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 a similar interface to `swift_binary`, -`swift_library`, and `swift_test`. + custom build rule to provide a similar interface to `swift_binary`, + `swift_library`, and `swift_test`. + + + - ## swift_common.compile -
-swift_common.compile(*, actions, feature_configuration, module_name, srcs, swift_toolchain,
-target_name, additional_inputs=[], bin_dir=None, copts=[], defines=[], deps=[],
-generated_header_name=None, genfiles_dir=None)
+
+swift_common.compile(actions, feature_configuration, module_name, srcs, swift_toolchain,
+                     target_name, workspace_name, additional_inputs, bin_dir, copts, defines, deps,
+                     generated_header_name, genfiles_dir, private_deps)
 
Compiles a Swift module. - -### Arguments - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
actions

Required

The context's actions object.

feature_configuration

Required

A feature configuration obtained from -swift_common.configure_features.

module_name

Required

The name of the Swift module being compiled. This must be -present and valid; use swift_common.derive_module_name to generate -a default from the target's label if needed.

srcs

Required

The Swift source files to compile.

swift_toolchain

Required

The SwiftToolchainInfo provider of the toolchain.

target_name

Required

The name of the target for which the code is being -compiled, which is used to determine unique file paths for the -outputs.

additional_inputs

Optional; default is []

A list of Files representing additional input files -that need to be passed to the Swift compile action because they are -referenced by compiler flags.

bin_dir

Optional; default is None

The Bazel *-bin directory root. If provided, its path is used -to store the cache for modules precompiled by Swift's ClangImporter, -and it is added to ClangImporter's header search paths for -compatibility with Bazel's C++ and Objective-C rules which support -includes of generated headers from that location.

copts

Optional; default is []

A list of compiler flags that apply to the target being built. -These flags, along with those from Bazel's Swift configuration -fragment (i.e., --swiftcopt command line flags) are scanned to -determine whether whole module optimization is being requested, -which affects the nature of the output files.

defines

Optional; default is []

Symbols that should be defined by passing -D to the compiler.

deps

Optional; default is []

Dependencies of the target being compiled. These targets must -propagate one of the following providers: CcInfo, SwiftInfo, or -apple_common.Objc.

generated_header_name

Optional; default is None

The name of the Objective-C generated header that -should be generated for this module. If omitted, the name -${target_name}-Swift.h will be used.

genfiles_dir

Optional; default is None

The Bazel *-genfiles directory root. If provided, its -path is added to ClangImporter's header search paths for -compatibility with Bazel's C++ and Objective-C rules which support -inclusions of generated headers from that location.

- - -### Returns +**PARAMETERS** + + +| Name | Description | Default Value | +| :------------- | :------------- | :------------- | +| actions | The context's actions object. | none | +| feature_configuration | A feature configuration obtained from swift_common.configure_features. | none | +| module_name | The name of the Swift module being compiled. This must be present and valid; use swift_common.derive_module_name to generate a default from the target's label if needed. | none | +| srcs | The Swift source files to compile. | none | +| swift_toolchain | The SwiftToolchainInfo provider of the toolchain. | none | +| target_name | The name of the target for which the code is being compiled, which is used to determine unique file paths for the outputs. | none | +| workspace_name | The name of the workspace for which the code is being compiled, which is used to determine unique file paths for some outputs. | none | +| additional_inputs | A list of Files representing additional input files that need to be passed to the Swift compile action because they are referenced by compiler flags. | [] | +| bin_dir | The Bazel *-bin directory root. If provided, its path is used to store the cache for modules precompiled by Swift's ClangImporter, and it is added to ClangImporter's header search paths for compatibility with Bazel's C++ and Objective-C rules which support includes of generated headers from that location. | None | +| copts | A list of compiler flags that apply to the target being built. These flags, along with those from Bazel's Swift configuration fragment (i.e., --swiftcopt command line flags) are scanned to determine whether whole module optimization is being requested, which affects the nature of the output files. | [] | +| defines | Symbols that should be defined by passing -D to the compiler. | [] | +| deps | Non-private dependencies of the target being compiled. These targets are used as dependencies of both the Swift module being compiled and the Clang module for the generated header. These targets must propagate one of the following providers: CcInfo, SwiftInfo, or apple_common.Objc. | [] | +| generated_header_name | The name of the Objective-C generated header that should be generated for this module. If omitted, no header will be generated. | None | +| genfiles_dir | The Bazel *-genfiles directory root. If provided, its path is added to ClangImporter's header search paths for compatibility with Bazel's C++ and Objective-C rules which support inclusions of generated headers from that location. | None | +| private_deps | Private (implementation-only) dependencies of the target being compiled. These are only used as dependencies of the Swift module, not of the Clang module for the generated header. These targets must propagate one of the following providers: CcInfo, SwiftInfo, or apple_common.Objc. | [] | + +**RETURNS** A `struct` containing the following fields: -* `generated_header`: A `File` representing the Objective-C header - that was generated for the compiled module. If no header was - generated, this field will be None. -* `generated_header_module_map`: A `File` representing the module map - that was generated to correspond to the generated Objective-C - header. If no module map was generated, this field will be None. -* `indexstore`: A `File` representing the directory that contains the - index store data generated by the compiler if index-while-building - is enabled. May be None if no indexing was requested. -* `linker_flags`: A list of strings representing additional flags that - should be passed to the linker when linking these objects into a - binary. If there are none, this field will always be an empty list, - never None. -* `linker_inputs`: A list of `File`s representing additional input - files (such as those referenced in `linker_flags`) that need to be - available to the link action when linking these objects into a - binary. If there are none, this field will always be an empty list, - never None. -* `object_files`: A list of `.o` files that were produced by the - compiler. -* `stats_directory`: A `File` representing the directory that contains - the timing statistics emitted by the compiler. If no stats were - requested, this field will be None. -* `swiftdoc`: The `.swiftdoc` file that was produced by the compiler. -* `swiftinterface`: The `.swiftinterface` file that was produced by - the compiler. If no interface file was produced (because the - toolchain does not support them or it was not requested), this field - will be None. -* `swiftmodule`: The `.swiftmodule` file that was produced by the - compiler. - - + * `generated_header`: A `File` representing the Objective-C header + that was generated for the compiled module. If no header was + generated, this field will be None. + * `generated_header_module_map`: A `File` representing the module map + that was generated to correspond to the generated Objective-C + header. If no module map was generated, this field will be None. + * `indexstore`: A `File` representing the directory that contains the + index store data generated by the compiler if index-while-building + is enabled. May be None if no indexing was requested. + * `linker_flags`: A list of strings representing additional flags that + should be passed to the linker when linking these objects into a + binary. If there are none, this field will always be an empty list, + never None. + * `linker_inputs`: A list of `File`s representing additional input + files (such as those referenced in `linker_flags`) that need to be + available to the link action when linking these objects into a + binary. If there are none, this field will always be an empty list, + never None. + * `object_files`: A list of `.o` files that were produced by the + compiler. + * `precompiled_module`: A `File` representing the explicit module + (`.pcm`) of the Clang module for the generated header, or `None` if + no explicit module was generated. + * `swiftdoc`: The `.swiftdoc` file that was produced by the compiler. + * `swiftinterface`: The `.swiftinterface` file that was produced by + the compiler. If no interface file was produced (because the + toolchain does not support them or it was not requested), this field + will be None. + * `swiftmodule`: The `.swiftmodule` file that was produced by the + compiler. + + + + ## swift_common.configure_features -
-swift_common.configure_features(ctx, swift_toolchain, *, requested_features=[],
-unsupported_features=[])
+
+swift_common.configure_features(ctx, swift_toolchain, requested_features, unsupported_features)
 
Creates a feature configuration to be passed to Swift build APIs. @@ -269,99 +163,55 @@ inside the Swift one. Users who need to call C++ APIs that require a feature configuration can extract it by calling `swift_common.cc_feature_configuration(feature_configuration)`. - -### Arguments - - - - - - - - - - - - - - - - - - - - - - - - -
ctx

Required

The rule context.

swift_toolchain

Required

The SwiftToolchainInfo provider of the toolchain -being used to build. The C++ toolchain associated with the Swift -toolchain is used to create the underlying C++ feature -configuration.

requested_features

Optional; default is []

The list of features to be enabled. This is -typically obtained using the ctx.features field in a rule -implementation function.

unsupported_features

Optional; default is []

The list of features that are unsupported by the -current rule. This is typically obtained using the -ctx.disabled_features field in a rule implementation function.

- - -### Returns + +**PARAMETERS** + + +| Name | Description | Default Value | +| :------------- | :------------- | :------------- | +| ctx | The rule context. | none | +| swift_toolchain | The SwiftToolchainInfo provider of the toolchain being used to build. This is used to determine features that are enabled by default or unsupported by the toolchain, and the C++ toolchain associated with the Swift toolchain is used to create the underlying C++ feature configuration. | none | +| requested_features | The list of features to be enabled. This is typically obtained using the ctx.features field in a rule implementation function. | [] | +| unsupported_features | The list of features that are unsupported by the current rule. This is typically obtained using the ctx.disabled_features field in a rule implementation function. | [] | + +**RETURNS** An opaque value representing the feature configuration that can be -passed to other `swift_common` functions. + passed to other `swift_common` functions. Note that the structure of + 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=None)
+
+swift_common.create_clang_module(compilation_context, module_map, precompiled_module)
 
Creates a value representing a Clang module used as a Swift dependency. - -### Arguments - - - - - - - - - - - - - - - - - - - - -
compilation_context

Required

A CcCompilationContext that contains the header -files, include paths, and other context necessary to compile targets -that depend on this module (if using the text module map instead of -the precompiled module).

module_map

Required

A File representing the text module map file that defines -this module.

precompiled_module

Optional; default is None

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.

- - -### Returns +**PARAMETERS** + + +| Name | Description | Default Value | +| :------------- | :------------- | :------------- | +| compilation_context | A CcCompilationContext that contains the header files, include paths, and other context necessary to compile targets that depend on this module (if using the text module map instead of the precompiled 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 | + +**RETURNS** A `struct` containing the `compilation_context`, `module_map`, and -`precompiled_module` fields provided as arguments. + `precompiled_module` fields provided as arguments. + + + - ## swift_common.create_module -
-swift_common.create_module(name, *, clang=None, swift=None)
+
+swift_common.create_module(name, clang, is_system, swift)
 
Creates a value containing Clang/Swift module artifacts of a dependency. @@ -371,48 +221,29 @@ valid for both to be present; this is the case for most Swift modules, which provide both Swift module artifacts as well as a generated header/module map for Objective-C targets to depend on. - -### Arguments - - - - - - - - - - - - - - - - - - - - -
name

Required

The name of the module.

clang

Optional; default is None

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.

swift

Optional; default is None

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`, and `swift` fields provided -as arguments. - - + +**PARAMETERS** + + +| 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 | +| 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(*, module_name=None, modules=[], swift_infos=[], swift_version=None)
+
+swift_common.create_swift_info(direct_swift_infos, modules, swift_infos)
 
Creates a new `SwiftInfo` provider with the given values. @@ -423,175 +254,147 @@ 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 all of the arguments except for `swift_infos` as their -empty defaults. In that case, the returned provider will not represent a -true Swift module; it is merely a "collector" for other dependencies. - - -### Arguments - - - - - - - - - - - - - - - - - - - - - - - - -
module_name

Optional; default is None

This argument is deprecated. The module name(s) should be -specified in the values passed to the modules argument.

modules

Optional; default is []

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

Optional; default is []

A list of SwiftInfo providers from dependencies, whose -transitive fields should be merged into the new one. If omitted, no -transitive data is collected.

swift_version

Optional; default is None

A string containing the value of the -swift-version -flag used when compiling this target, or None (the default) if it -was not set or is not relevant.

- - -### Returns +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. | [] | + +**RETURNS** A new `SwiftInfo` provider with the given values. - + + + +## swift_common.create_swift_interop_info + +
+swift_common.create_swift_interop_info(module_map, module_name, requested_features, 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 call +`swift_common.create_swift_interop_info` passing it only the list of +`SwiftInfo` providers from its dependencies; this tells +`swift_clang_module_aspect` to derive the module name from the target label +and create a module map using the headers from the compilation context. + +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 do so automatically. This allows the rule to not only add extra +dependencies (such as support libraries from implicit attributes) but also +exclude dependencies if necessary. + + +**PARAMETERS** + + +| Name | Description | Default Value | +| :------------- | :------------- | :------------- | +| 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. | [] | +| 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(*, swiftdoc, swiftmodule, defines=[], swiftinterface=None)
+
+swift_common.create_swift_module(swiftdoc, swiftmodule, defines, swiftinterface)
 
Creates a value representing a Swift module use as a Swift dependency. - -### Arguments - - - - - - - - - - - - - - - - - - - - - - - - -
swiftdoc

Required

The .swiftdoc file emitted by the compiler for this module.

swiftmodule

Required

The .swiftmodule file emitted by the compiler for this -module.

defines

Optional; default is []

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.

swiftinterface

Optional; default is None

The .swiftinterface file emitted by the compiler for -this module. May be None if no module interface file was emitted.

- - -### Returns +**PARAMETERS** + + +| Name | Description | Default Value | +| :------------- | :------------- | :------------- | +| swiftdoc | The .swiftdoc file emitted by the compiler for this module. | none | +| swiftmodule | The .swiftmodule file emitted by the compiler for this module. | none | +| 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. | [] | +| swiftinterface | The .swiftinterface file emitted by the compiler for this module. May be None if no module interface file was emitted. | None | + +**RETURNS** A `struct` containing the `defines`, `swiftdoc`, `swiftmodule`, and -`swiftinterface` fields provided as arguments. + `swiftinterface` fields provided as arguments. + + + - ## swift_common.derive_module_name -
-swift_common.derive_module_name(*args)
+
+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 by creating an underscore-delimited string from the components -of the label, replacing any non-identifier characters also with underscores. - -This mapping is not intended to be reversible. - - -### Arguments - - - - - - - - - - - - -
*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.

- - -### Returns +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.get_implicit_deps -
-swift_common.get_implicit_deps(feature_configuration, swift_toolchain)
-
+ -Gets the list of implicit dependencies from the toolchain. - - -### Arguments - - - - - - - - - - - - - - - - -
feature_configuration

Required

The feature configuration, which determines -whether optional implicit dependencies are included.

swift_toolchain

Required

The Swift toolchain.

- - -### Returns - -A list of targets that should be treated as implicit dependencies of -the toolchain under the given feature configuration. - - ## swift_common.is_enabled -
-swift_common.is_enabled(feature_configuration, feature_name)
+
+swift_common.is_enabled(feature_configuration, feature_name)
 
Returns `True` if the feature is enabled in the feature configuration. @@ -600,37 +403,26 @@ This function handles both Swift-specific features and C++ features so that users do not have to manually extract the C++ configuration in order to check it. - -### Arguments - - - - - - - - - - - - - - - - -
feature_configuration

Required

The Swift feature configuration, as returned by -swift_common.configure_features.

feature_name

Required

The name of the feature to check.

- - -### Returns + +**PARAMETERS** + + +| Name | Description | Default Value | +| :------------- | :------------- | :------------- | +| feature_configuration | The Swift feature configuration, as returned by swift_common.configure_features. | none | +| feature_name | The name of the feature to check. | none | + +**RETURNS** `True` if the given feature is enabled in the feature configuration. - + + + ## swift_common.library_rule_attrs -
-swift_common.library_rule_attrs(additional_deps_aspects=[])
+
+swift_common.library_rule_attrs(additional_deps_aspects, requires_srcs)
 
Returns an attribute dictionary for `swift_library`-like rules. @@ -661,183 +453,61 @@ API: Each of the attribute functions in the list above also contains the attributes from the earlier items in the list. - -### Arguments - - - - - - - - - - - - -
additional_deps_aspects

Optional; default is []

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.

- - -### Returns + +**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`. + custom build rule to provide the same interface as `swift_library`. + + + - ## swift_common.precompile_clang_module -
-swift_common.precompile_clang_module(*, actions, cc_compilation_context, feature_configuration,
-module_map_file, module_name, swift_toolchain, target_name, bin_dir=None, genfiles_dir=None,
-swift_info=None)
+
+swift_common.precompile_clang_module(actions, cc_compilation_context, feature_configuration,
+                                     module_map_file, module_name, swift_toolchain, target_name,
+                                     bin_dir, genfiles_dir, swift_info)
 
Precompiles an explicit Clang module that is compatible with Swift. - -### Arguments - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
actions

Required

The context's actions object.

cc_compilation_context

Required

A CcCompilationContext that contains headers -and other information needed to compile this module. This -compilation context should contain all headers required to compile -the module, which includes the headers for the module itself and -any others that must be present on the file system/in the sandbox -for compilation to succeed. The latter typically refers to the set -of headers of the direct dependencies of the module being compiled, -which Clang needs to be physically present before it detects that -they belong to one of the precompiled module dependencies.

feature_configuration

Required

A feature configuration obtained from -swift_common.configure_features.

module_map_file

Required

A textual module map file that defines the Clang module -to be compiled.

module_name

Required

The name of the top-level module in the module map that -will be compiled.

swift_toolchain

Required

The SwiftToolchainInfo provider of the toolchain.

target_name

Required

The name of the target for which the code is being -compiled, which is used to determine unique file paths for the -outputs.

bin_dir

Optional; default is None

The Bazel *-bin directory root. If provided, its path is used -to store the cache for modules precompiled by Swift's ClangImporter, -and it is added to ClangImporter's header search paths for -compatibility with Bazel's C++ and Objective-C rules which support -includes of generated headers from that location.

genfiles_dir

Optional; default is None

The Bazel *-genfiles directory root. If provided, its -path is added to ClangImporter's header search paths for -compatibility with Bazel's C++ and Objective-C rules which support -inclusions of generated headers from that location.

swift_info

Optional; default is None

A SwiftInfo provider that contains dependencies required -to compile this module.

- - -### Returns +**PARAMETERS** -A `File` representing the precompiled module (`.pcm`) file, or `None` if -the toolchain or target does not support precompiled modules. +| Name | Description | Default Value | +| :------------- | :------------- | :------------- | +| actions | The context's actions object. | none | +| cc_compilation_context | A CcCompilationContext that contains headers and other information needed to compile this module. This compilation context should contain all headers required to compile the module, which includes the headers for the module itself *and* any others that must be present on the file system/in the sandbox for compilation to succeed. The latter typically refers to the set of headers of the direct dependencies of the module being compiled, which Clang needs to be physically present before it detects that they belong to one of the precompiled module dependencies. | none | +| feature_configuration | A feature configuration obtained from swift_common.configure_features. | none | +| module_map_file | A textual module map file that defines the Clang module to be compiled. | none | +| module_name | The name of the top-level module in the module map that will be compiled. | none | +| swift_toolchain | The SwiftToolchainInfo provider of the toolchain. | none | +| target_name | The name of the target for which the code is being compiled, which is used to determine unique file paths for the outputs. | none | +| bin_dir | The Bazel *-bin directory root. If provided, its path is used to store the cache for modules precompiled by Swift's ClangImporter, and it is added to ClangImporter's header search paths for compatibility with Bazel's C++ and Objective-C rules which support includes of generated headers from that location. | None | +| genfiles_dir | The Bazel *-genfiles directory root. If provided, its path is added to ClangImporter's header search paths for compatibility with Bazel's C++ and Objective-C rules which support inclusions of generated headers from that location. | None | +| swift_info | A SwiftInfo provider that contains dependencies required to compile this module. | None | - -## swift_common.swift_clang_module_aspect +**RETURNS** -
-swift_common.swift_clang_module_aspect(name)
-
+A `File` representing the precompiled module (`.pcm`) file, or `None` if + the toolchain or target does not support precompiled modules. + + + -Propagates unified `SwiftInfo` providers for targets that represent -C/Objective-C modules. - -This aspect unifies the propagation of Clang module artifacts so that Swift -targets that depend on C/Objective-C targets can find the necessary module -artifacts, and so that Swift module artifacts are not lost when passing through -a non-Swift target in the build graph (for example, a `swift_library` that -depends on an `objc_library` that depends on a `swift_library`). - -It also manages module map generation for `cc_library` targets that have the -`swift_module` tag. This tag may take one of two forms: - - * `swift_module`: By itself, this indicates that the target is compatible - with Swift and should be given a module name that is derived from its - target label. - * `swift_module=name`: The module should be given the name `name`. - -Note that the public headers of such `cc_library` targets must be parsable as C, -since Swift does not support C++ interop at this time. - -Most users will not need to interact directly with this aspect, since it is -automatically applied to the `deps` attribute of all `swift_binary`, -`swift_library`, and `swift_test` targets. However, some rules may need to -provide custom propagation logic of C/Objective-C module dependencies; for -example, a rule that has a support library as a private attribute would need to -ensure that `SwiftInfo` providers for that library and its dependencies are -propagated to any targets that depend on it, since they would not be propagated -via `deps`. In this case, the custom rule can attach this aspect to that support -library's attribute and then merge its `SwiftInfo` provider with any others that -it propagates for its targets. - - -### Attributes - - - - - - - - - - - - -
name -

Name; required

A unique name for this target.

- - ## swift_common.swift_runtime_linkopts -
-swift_common.swift_runtime_linkopts(is_static, toolchain, is_test=False)
+
+swift_common.swift_runtime_linkopts(is_static, toolchain, is_test)
 
Returns the flags that should be passed when linking a Swift binary. @@ -846,45 +516,28 @@ This function provides the appropriate linker arguments to callers who need to link a binary using something other than `swift_binary` (for example, an application bundle containing a universal `apple_binary`). - -### Arguments - - - - - - - - - - - - - - - - - - - - -
is_static

Required

A Boolean value indicating whether the binary should be -linked against the static (rather than the dynamic) Swift runtime -libraries.

toolchain

Required

The SwiftToolchainInfo provider of the toolchain whose -linker options are desired.

is_test

Optional; default is False

A Boolean value indicating whether the target being linked is -a test target.

- - -### Returns + +**PARAMETERS** + + +| Name | Description | Default Value | +| :------------- | :------------- | :------------- | +| is_static | A Boolean value indicating whether the binary should be linked against the static (rather than the dynamic) Swift runtime libraries. | none | +| toolchain | The SwiftToolchainInfo provider of the toolchain whose linker options are desired. | none | +| is_test | A Boolean value indicating whether the target being linked is a test target. | False | + +**RETURNS** A `list` of command line flags that should be passed when linking a -binary against the Swift runtime libraries. + binary against the Swift runtime libraries. + + + - ## swift_common.toolchain_attrs -
-swift_common.toolchain_attrs(toolchain_attr_name='_toolchain')
+
+swift_common.toolchain_attrs(toolchain_attr_name)
 
Returns an attribute dictionary for toolchain users. @@ -911,30 +564,17 @@ API: Each of the attribute functions in the list above also contains the attributes from the earlier items in the list. - -### Arguments - - - - - - - - - - - - -
toolchain_attr_name

Optional; default is '_toolchain'

The name of the attribute that should be created -that points to the toolchain. This defaults to _toolchain, which -is sufficient for most rules; it is customizable for certain aspects -where having an attribute with the same name but different values -applied to a particular target causes a build crash.

- - -### Returns + +**PARAMETERS** + + +| Name | Description | Default Value | +| :------------- | :------------- | :------------- | +| toolchain_attr_name | The name of the attribute that should be created that points to the toolchain. This defaults to _toolchain, which is sufficient for most rules; it is customizable for certain aspects where having an attribute with the same name but different values applied to a particular target causes a build crash. | "_toolchain" | + +**RETURNS** A new attribute dictionary that can be added to the attributes of a -custom build rule to provide access to the Swift toolchain. + custom build rule to provide access to the Swift toolchain. diff --git a/doc/stardoc.pr103.patch b/doc/stardoc.pr103.patch new file mode 100644 index 000000000..f078cd72e --- /dev/null +++ b/doc/stardoc.pr103.patch @@ -0,0 +1,12 @@ +diff stardoc/templates/markdown_tables/func.vm stardoc/templates/markdown_tables/func.vm +index e53e639..1b7bd7a 100644 +--- stardoc/templates/markdown_tables/func.vm ++++ stardoc/templates/markdown_tables/func.vm +@@ -18,3 +18,7 @@ ${funcInfo.docString} + | $param.name | #if(!$param.docString.isEmpty()) ${util.markdownCellFormat($param.docString)} #else

-

#end | #if(!$param.getDefaultValue().isEmpty()) $param.getDefaultValue() #else none #end| + #end + #end ++ ++**RETURNS** ++ ++${funcInfo.return.docString} \ No newline at end of file From 9f42d7514b7f2d5afe522bc941daef0e545969e5 Mon Sep 17 00:00:00 2001 From: Alex Eagle Date: Tue, 18 May 2021 19:47:58 -0700 Subject: [PATCH 122/152] Generate setup.md from sources (#619) This is the last doc that should be generated from sources, but wasn't, from what I can tell. --- doc/BUILD.bazel | 21 +++++++++++++++++++-- doc/setup.md | 15 +++++++++------ doc/stardoc.pr103.patch | 6 ++++-- swift/BUILD | 7 ++++++- 4 files changed, 38 insertions(+), 11 deletions(-) diff --git a/doc/BUILD.bazel b/doc/BUILD.bazel index dd4f80111..edbad25a0 100644 --- a/doc/BUILD.bazel +++ b/doc/BUILD.bazel @@ -90,6 +90,15 @@ write_file( ], ) +write_file( + name = "setup_header", + out = "setup_header.vm", + content = [ + "", + "# Workspace Setup", + ], +) + [ stardoc( name = file + "_doc", @@ -105,6 +114,14 @@ write_file( ] in _DOC_SRCS.items() ] +stardoc( + name = "setup_doc", + out = "setup.md_", + header_template = "setup_header.vm", + input = "//swift:repositories.bzl", + deps = ["//swift:repositories"], +) + # To make these tests pass, run # bazel run //doc:update [ @@ -113,7 +130,7 @@ write_file( file1 = file + ".md_", file2 = file + ".md", ) - for file in _DOC_SRCS.keys() + for file in _DOC_SRCS.keys() + ["setup"] ] write_file( @@ -126,7 +143,7 @@ write_file( "cp -fv bazel-bin/doc/{0}.md_ doc/{0}.md".format( file, ) - for file in _DOC_SRCS.keys() + for file in _DOC_SRCS.keys() + ["setup"] ], ) diff --git a/doc/setup.md b/doc/setup.md index 249170d21..4df2072d4 100644 --- a/doc/setup.md +++ b/doc/setup.md @@ -1,16 +1,19 @@ + # Workspace Setup + - - ## swift_rules_dependencies -
+
 swift_rules_dependencies()
 
-Fetches repositories that are dependencies of the `rules_swift` workspace. +Fetches repositories that are dependencies of `rules_swift`. Users should call this macro in their `WORKSPACE` to ensure that all of the -dependencies of the Swift rules are downloaded and that they are isolated from -changes to those dependencies. +dependencies of the Swift rules are downloaded and that they are isolated +from changes to those dependencies. + + + diff --git a/doc/stardoc.pr103.patch b/doc/stardoc.pr103.patch index f078cd72e..2de970b47 100644 --- a/doc/stardoc.pr103.patch +++ b/doc/stardoc.pr103.patch @@ -2,11 +2,13 @@ diff stardoc/templates/markdown_tables/func.vm stardoc/templates/markdown_tables index e53e639..1b7bd7a 100644 --- stardoc/templates/markdown_tables/func.vm +++ stardoc/templates/markdown_tables/func.vm -@@ -18,3 +18,7 @@ ${funcInfo.docString} +@@ -18,3 +18,9 @@ ${funcInfo.docString} | $param.name | #if(!$param.docString.isEmpty()) ${util.markdownCellFormat($param.docString)} #else

-

#end | #if(!$param.getDefaultValue().isEmpty()) $param.getDefaultValue() #else none #end| #end #end + ++#if (!$funcInfo.return.docString.isEmpty()) +**RETURNS** + -+${funcInfo.return.docString} \ No newline at end of file ++${funcInfo.return.docString} ++#end \ No newline at end of file diff --git a/swift/BUILD b/swift/BUILD index af2101f9a..d48b57c47 100644 --- a/swift/BUILD +++ b/swift/BUILD @@ -9,12 +9,17 @@ package(default_visibility = ["//visibility:public"]) licenses(["notice"]) +bzl_library( + name = "bazel_tools_bzl", + srcs = ["@bazel_tools//tools:bzl_srcs"], +) + bzl_library( name = "repositories", srcs = ["repositories.bzl"], deps = [ + ":bazel_tools_bzl", "//swift/internal:swift_autoconfiguration", - "@bazel_tools//tools/build_defs/repo:http.bzl", ], ) From ce673975d0da4e480a7a45fbb9bb0651e938f48c Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Thu, 27 May 2021 14:51:16 -0700 Subject: [PATCH 123/152] Update README with new URLs (#621) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cc5d82cfd..4e9c7c4a5 100644 --- a/README.md +++ b/README.md @@ -51,8 +51,8 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "build_bazel_rules_swift", - sha256 = "8407fa0fd04a7ce1d6bb95e90b216404466f809eda459c23cb57b5fa1ef9d639", - url = "https://github.com/bazelbuild/rules_swift/releases/download/0.21.0/rules_swift.0.21.0.tar.gz", + sha256 = "653e8756001616500b110fd156694de7899278bb7480aba22b2f156438a1d810", + url = "https://github.com/bazelbuild/rules_swift/releases/download/0.22.0/rules_swift.0.22.0.tar.gz", ) load( From bdf5288e170720571f9692f5fd558a4873d07dcb Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Thu, 27 May 2021 14:51:56 -0700 Subject: [PATCH 124/152] Update bazel_skylib (#620) --- swift/repositories.bzl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/swift/repositories.bzl b/swift/repositories.bzl index 36b5f5a3e..0f59e87c2 100644 --- a/swift/repositories.bzl +++ b/swift/repositories.bzl @@ -42,9 +42,9 @@ def swift_rules_dependencies(): http_archive, name = "bazel_skylib", urls = [ - "https://github.com/bazelbuild/bazel-skylib/releases/download/1.0.2/bazel-skylib-1.0.2.tar.gz", + "https://github.com/bazelbuild/bazel-skylib/releases/download/1.0.3/bazel-skylib-1.0.3.tar.gz", ], - sha256 = "97e70364e9249702246c0e9444bccdc4b847bed1eb03c5a3ece4f83dfe6abc44", + sha256 = "1c531376ac7e5a180e0237938a2536de0c54d93f5c278634818e0efc952dd56c", ) _maybe( From a757f59f00b2681c7e981bab1f593d1d35717ce9 Mon Sep 17 00:00:00 2001 From: Samuel Giddins Date: Thu, 27 May 2021 16:28:20 -0700 Subject: [PATCH 125/152] Update the worker protocol proto (#622) --- third_party/bazel_protos/README.md | 5 +-- .../bazel_protos/worker_protocol.proto | 33 +++++++++++++++++-- tools/worker/work_processor.cc | 1 + 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/third_party/bazel_protos/README.md b/third_party/bazel_protos/README.md index 442e981f4..8eaca51dd 100644 --- a/third_party/bazel_protos/README.md +++ b/third_party/bazel_protos/README.md @@ -1,3 +1,4 @@ -This directory contains protocol buffers vendored from the main Bazel -repository, so that rules_swift does not need to depend on the entire +This directory contains protocol buffers vendored from the +[main Bazel repository](https://raw.githubusercontent.com/bazelbuild/bazel/master/src/main/protobuf/worker_protocol.proto), +so that rules_swift does not need to depend on the entire `@io_bazel` workspace, which is approximately 100MB. diff --git a/third_party/bazel_protos/worker_protocol.proto b/third_party/bazel_protos/worker_protocol.proto index 0a777a96b..2381df106 100644 --- a/third_party/bazel_protos/worker_protocol.proto +++ b/third_party/bazel_protos/worker_protocol.proto @@ -31,16 +31,31 @@ message Input { bytes digest = 2; } -// This represents a single work unit that Bazel sends to the worker. +// This represents a single work unit that Blaze sends to the worker. message WorkRequest { repeated string arguments = 1; // The inputs that the worker is allowed to read during execution of this // request. repeated Input inputs = 2; + + // Each WorkRequest must have either a unique + // request_id or request_id = 0. If request_id is 0, this WorkRequest must be + // processed alone (singleplex), otherwise the worker may process multiple + // WorkRequests in parallel (multiplexing). As an exception to the above, if + // the cancel field is true, the request_id must be the same as a previously + // sent WorkRequest. The request_id must be attached unchanged to the + // corresponding WorkResponse. Only one singleplex request may be sent to a + // worker at a time. + int32 request_id = 3; + + // EXPERIMENTAL: When true, this is a cancel request, indicating that a + // previously sent WorkRequest with the same request_id should be cancelled. + // The arguments and inputs fields must be empty and should be ignored. + bool cancel = 4; } -// The worker sends this message to Bazel when it finished its work on the +// The worker sends this message to Blaze when it finished its work on the // WorkRequest message. message WorkResponse { int32 exit_code = 1; @@ -49,4 +64,18 @@ message WorkResponse { // supposed to contain compiler warnings / errors etc. - thus we'll use a // string type here, which gives us UTF-8 encoding. string output = 2; + + // This field must be set to the same request_id as the WorkRequest it is a + // response to. Since worker processes which support multiplex worker will + // handle multiple WorkRequests in parallel, this ID will be used to + // determined which WorkerProxy does this WorkResponse belong to. + int32 request_id = 3; + + // EXPERIMENTAL When true, indicates that this response was sent due to + // receiving a cancel request. The exit_code and output fields should be empty + // and will be ignored. Exactly one WorkResponse must be sent for each + // non-cancelling WorkRequest received by the worker, but if the worker + // received a cancel request, it doesn't matter if it replies with a regular + // WorkResponse or with one where was_cancelled = true. + bool was_cancelled = 4; } diff --git a/tools/worker/work_processor.cc b/tools/worker/work_processor.cc index 1e48bebc5..8e824ade0 100644 --- a/tools/worker/work_processor.cc +++ b/tools/worker/work_processor.cc @@ -145,4 +145,5 @@ void WorkProcessor::ProcessWorkRequest( response->set_exit_code(exit_code); response->set_output(stderr_stream.str()); + response->set_request_id(request.request_id()); } From d8244633d0877245e0034484ccf937ef56dcaaa3 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Fri, 28 May 2021 11:15:32 -0700 Subject: [PATCH 126/152] Add ubsan support (#544) --- swift/internal/compiling.bzl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index 4c9f38d49..14eb84b4e 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -462,6 +462,13 @@ def compile_action_configs( ], features = ["tsan"], ), + swift_toolchain_config.action_config( + actions = [swift_action_names.COMPILE], + configurators = [ + swift_toolchain_config.add_arg("-sanitize=undefined"), + ], + features = ["ubsan"], + ), ] #### Flags controlling how Swift/Clang modular inputs are processed From 7197d5a97043246c020101a3ec460796345b3100 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Fri, 28 May 2021 11:20:03 -0700 Subject: [PATCH 127/152] Remove unused command_line_copts (#625) --- swift/internal/xcode_swift_toolchain.bzl | 5 ----- 1 file changed, 5 deletions(-) diff --git a/swift/internal/xcode_swift_toolchain.bzl b/swift/internal/xcode_swift_toolchain.bzl index a2872efb4..a2cb1e8a0 100644 --- a/swift/internal/xcode_swift_toolchain.bzl +++ b/swift/internal/xcode_swift_toolchain.bzl @@ -732,11 +732,6 @@ def _xcode_swift_toolchain_impl(ctx): if _is_xcode_at_least_version(xcode_config, "11.4"): requested_features.append(SWIFT_FEATURE_ENABLE_SKIP_FUNCTION_BODIES) - command_line_copts = _command_line_objc_copts( - ctx.var["COMPILATION_MODE"], - ctx.fragments.objc, - ) + ctx.fragments.swift.copts() - env = _xcode_env(platform = platform, xcode_config = xcode_config) execution_requirements = xcode_config.execution_info() generated_header_rewriter = ctx.executable.generated_header_rewriter From 4979602b37f8417bd5121565f52ab733c3231e4d Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Wed, 5 May 2021 17:23:16 -0700 Subject: [PATCH 128/152] Include the headers from direct dependencies of a Swift target when compiling the explicit module for its generated header. PiperOrigin-RevId: 372240650 (cherry picked from commit cc15b6eb5fb7bcd129eaa4960ff60e5c44d9a7eb) --- swift/internal/compiling.bzl | 13 ++++-- swift/internal/swift_clang_module_aspect.bzl | 40 +++++------------ swift/internal/utils.bzl | 45 ++++++++++++++++++++ 3 files changed, 66 insertions(+), 32 deletions(-) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index 14eb84b4e..6fcadbc33 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -70,6 +70,7 @@ load( ":utils.bzl", "collect_cc_libraries", "compact", + "compilation_context_for_explicit_module_compilation", "get_providers", "struct_fields", ) @@ -1776,12 +1777,18 @@ def compile( feature_configuration = feature_configuration, feature_name = SWIFT_FEATURE_NO_GENERATED_MODULE_MAP, ): + compilation_context_to_compile = ( + compilation_context_for_explicit_module_compilation( + compilation_contexts = [cc_common.create_compilation_context( + headers = depset([compile_outputs.generated_header_file]), + )], + deps = deps, + ) + ) precompiled_module = precompile_clang_module( actions = actions, bin_dir = bin_dir, - cc_compilation_context = cc_common.create_compilation_context( - headers = depset([compile_outputs.generated_header_file]), - ), + cc_compilation_context = compilation_context_to_compile, feature_configuration = feature_configuration, genfiles_dir = genfiles_dir, module_map_file = compile_outputs.generated_module_map_file, diff --git a/swift/internal/swift_clang_module_aspect.bzl b/swift/internal/swift_clang_module_aspect.bzl index 7a934e6a6..e42a4f09e 100644 --- a/swift/internal/swift_clang_module_aspect.bzl +++ b/swift/internal/swift_clang_module_aspect.bzl @@ -33,7 +33,11 @@ load( "create_module", "create_swift_info", ) -load(":utils.bzl", "get_providers") +load( + ":utils.bzl", + "compilation_context_for_explicit_module_compilation", + "get_providers", +) _MULTIPLE_TARGET_ASPECT_ATTRS = [ "deps", @@ -457,34 +461,12 @@ def _handle_module( # a framework import rule. For now, we won't support compiling those as # explicit modules; fix this. if module_name: - # We only need to propagate the information from the compilation - # contexts, but we can't merge those directly; we can only merge - # `CcInfo` objects. So we "unwrap" the compilation context from each - # provider and then "rewrap" it in a new provider that lacks the linking - # context so that our merge operation does less work. - target_and_deps_cc_infos = [ - CcInfo(compilation_context = compilation_context), - ] - for dep in getattr(attr, "deps", []): - if CcInfo in dep: - target_and_deps_cc_infos.append( - CcInfo( - compilation_context = dep[CcInfo].compilation_context, - ), - ) - if apple_common.Objc in dep: - target_and_deps_cc_infos.append( - CcInfo( - compilation_context = cc_common.create_compilation_context( - includes = dep[apple_common.Objc].strict_include, - ), - ), - ) - - compilation_context_to_compile = cc_common.merge_cc_infos( - direct_cc_infos = target_and_deps_cc_infos, - ).compilation_context - + compilation_context_to_compile = ( + compilation_context_for_explicit_module_compilation( + compilation_contexts = [compilation_context], + deps = getattr(attr, "deps", []), + ) + ) precompiled_module = precompile_clang_module( actions = aspect_ctx.actions, bin_dir = aspect_ctx.bin_dir, diff --git a/swift/internal/utils.bzl b/swift/internal/utils.bzl index d87c80cdd..5ff45a774 100644 --- a/swift/internal/utils.bzl +++ b/swift/internal/utils.bzl @@ -168,6 +168,51 @@ def create_cc_info( direct_cc_infos = local_cc_infos, ) +def compilation_context_for_explicit_module_compilation( + compilation_contexts, + deps): + """Returns a compilation context suitable for compiling an explicit module. + + Args: + compilation_contexts: `CcCompilationContext`s that provide information + about headers and include paths for the target being compiled. + deps: Direct dependencies of the target being compiled. + + Returns: + A `CcCompilationContext` containing information needed when compiling an + explicit module, such as the headers and search paths of direct + dependencies (since Clang needs to find those on the file system in + order to map them to a module). + """ + cc_infos = [ + CcInfo(compilation_context = compilation_context) + for compilation_context in compilation_contexts + ] + + for dep in deps: + if CcInfo in dep: + # TODO(b/179692096): We only need to propagate the information from + # the compilation contexts, but we can't merge those directly; we + # can only merge `CcInfo` objects. So we "unwrap" the compilation + # context from each provider and then "rewrap" it in a new provider + # that lacks the linking context so that our merge operation does + # less work. + cc_infos.append( + CcInfo(compilation_context = dep[CcInfo].compilation_context), + ) + if apple_common.Objc in dep: + cc_infos.append( + CcInfo( + compilation_context = cc_common.create_compilation_context( + includes = dep[apple_common.Objc].strict_include, + ), + ), + ) + + return cc_common.merge_cc_infos( + direct_cc_infos = cc_infos, + ).compilation_context + def expand_locations(ctx, values, targets = []): """Expands the `$(location)` placeholders in each of the given values. From 8e63bada29baf0fb743c27b0bbd2553a53c8ddc1 Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Mon, 10 May 2021 17:22:33 -0700 Subject: [PATCH 129/152] Use `-fsystem-module` if the compiler is new enough to support it (Xcode 12.5/Swift 5.4 or higher). PiperOrigin-RevId: 373046121 (cherry picked from commit 4cd9b2c01e5e71ba20e78b61e28e396d83de5840) --- swift/internal/compiling.bzl | 28 ++++++++++++++++++------ swift/internal/feature_names.bzl | 8 +++++++ swift/internal/xcode_swift_toolchain.bzl | 5 +++++ 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index 6fcadbc33..0482f5a68 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -55,6 +55,7 @@ load( "SWIFT_FEATURE_OPT_USES_WMO", "SWIFT_FEATURE_SPLIT_DERIVED_FILES_GENERATION", "SWIFT_FEATURE_SUPPORTS_LIBRARY_EVOLUTION", + "SWIFT_FEATURE_SUPPORTS_SYSTEM_MODULE_FLAG", "SWIFT_FEATURE_SYSTEM_MODULE", "SWIFT_FEATURE_USE_C_MODULES", "SWIFT_FEATURE_USE_GLOBAL_MODULE_CACHE", @@ -604,13 +605,14 @@ def compile_action_configs( swift_toolchain_config.action_config( actions = [swift_action_names.PRECOMPILE_C_MODULE], configurators = [ - # TODO(b/165649949): ClangImporter doesn't currently handle the - # IsSystem bit correctly for the input file, which causes the - # module map to be treated as a user input. To work around this - # for now, we disable all diagnostics when compiling the - # explicit module for system modules, since they're not useful - # anyway; this is "close enough" to compiling it as a system - # module for the purposes of avoiding noise in the build logs. + # Before Swift 5.4, ClangImporter doesn't currently handle the + # IsSystem bit correctly for the input file and ignores the + # `-fsystem-module` flag, which causes the module map to be + # treated as a user input. We can work around this by disabling + # diagnostics for system modules. However, this also disables + # behavior in ClangImporter that causes system APIs that use + # `UInt` to be imported to use `Int` instead. The only solution + # here is to use Xcode 12.5 or higher. swift_toolchain_config.add_arg("-Xcc", "-w"), swift_toolchain_config.add_arg( "-Xcc", @@ -618,6 +620,18 @@ def compile_action_configs( ), ], features = [SWIFT_FEATURE_SYSTEM_MODULE], + not_features = [SWIFT_FEATURE_SUPPORTS_SYSTEM_MODULE_FLAG], + ), + swift_toolchain_config.action_config( + actions = [swift_action_names.PRECOMPILE_C_MODULE], + configurators = [ + swift_toolchain_config.add_arg("-Xcc", "-Xclang"), + swift_toolchain_config.add_arg("-Xcc", "-fsystem-module"), + ], + features = [ + SWIFT_FEATURE_SUPPORTS_SYSTEM_MODULE_FLAG, + SWIFT_FEATURE_SYSTEM_MODULE, + ], ), ] diff --git a/swift/internal/feature_names.bzl b/swift/internal/feature_names.bzl index 589bd724e..639b516eb 100644 --- a/swift/internal/feature_names.bzl +++ b/swift/internal/feature_names.bzl @@ -71,6 +71,14 @@ SWIFT_FEATURE_LAYERING_CHECK = "swift.layering_check" # If enabled, the C or Objective-C target should be compiled as a system module. SWIFT_FEATURE_SYSTEM_MODULE = "swift.system_module" +# If enabled, the `-Xcc -fsystem-module` flag will be passed when compiling a +# system C/Objective-C module (with feature `swift.system_module`) because the +# compiler is new enough to honor it correctly. If disabled, we attempt to mimic +# this by disabling certain warnings; however, this unfortunately causes `UInt` +# APIs to be imported by ClangImporter as `UInt` instead of `Int` because +# ClangImporter doesn't recognize them as true system modules. +SWIFT_FEATURE_SUPPORTS_SYSTEM_MODULE_FLAG = "swift.supports_system_module_flag" + # If enabled, Swift compilation actions will use batch mode by passing # `-enable-batch-mode` to `swiftc`. This is a new compilation mode as of # Swift 4.2 that is intended to speed up non-incremental non-WMO builds by diff --git a/swift/internal/xcode_swift_toolchain.bzl b/swift/internal/xcode_swift_toolchain.bzl index a2cb1e8a0..e84945998 100644 --- a/swift/internal/xcode_swift_toolchain.bzl +++ b/swift/internal/xcode_swift_toolchain.bzl @@ -41,6 +41,7 @@ load( "SWIFT_FEATURE_REMAP_XCODE_PATH", "SWIFT_FEATURE_SUPPORTS_LIBRARY_EVOLUTION", "SWIFT_FEATURE_SUPPORTS_PRIVATE_DEPS", + "SWIFT_FEATURE_SUPPORTS_SYSTEM_MODULE_FLAG", "SWIFT_FEATURE_USE_RESPONSE_FILES", ) load(":features.bzl", "features_for_build_modes") @@ -732,6 +733,10 @@ def _xcode_swift_toolchain_impl(ctx): if _is_xcode_at_least_version(xcode_config, "11.4"): requested_features.append(SWIFT_FEATURE_ENABLE_SKIP_FUNCTION_BODIES) + # Xcode 12.5 implies Swift 5.4. + if _is_xcode_at_least_version(xcode_config, "12.5"): + requested_features.append(SWIFT_FEATURE_SUPPORTS_SYSTEM_MODULE_FLAG) + env = _xcode_env(platform = platform, xcode_config = xcode_config) execution_requirements = xcode_config.execution_info() generated_header_rewriter = ctx.executable.generated_header_rewriter From a0fcdebc43f721cacdfb9a1ed47248b0486d57d5 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Fri, 28 May 2021 11:47:39 -0700 Subject: [PATCH 130/152] Add the `swift_feature_allowlist` rule that lets toolchains control which packages are allowed to enable/disable specific features. (#627) Co-authored-by: Tony Allevato --- doc/BUILD.bazel | 1 + doc/providers.md | 3 +- doc/rules.md | 32 ++++++ swift/BUILD | 1 + swift/internal/BUILD | 9 ++ swift/internal/features.bzl | 102 +++++++++++++++++++ swift/internal/providers.bzl | 45 +++++++++ swift/internal/swift_feature_allowlist.bzl | 109 +++++++++++++++++++++ swift/internal/swift_toolchain.bzl | 13 ++- swift/internal/xcode_swift_toolchain.bzl | 18 +++- swift/swift.bzl | 7 +- 11 files changed, 336 insertions(+), 4 deletions(-) create mode 100644 swift/internal/swift_feature_allowlist.bzl diff --git a/doc/BUILD.bazel b/doc/BUILD.bazel index edbad25a0..72eaced5e 100644 --- a/doc/BUILD.bazel +++ b/doc/BUILD.bazel @@ -18,6 +18,7 @@ _DOC_SRCS = { "rules": [ "swift_binary", "swift_c_module", + "swift_feature_allowlist", "swift_grpc_library", "swift_import", "swift_library", diff --git a/doc/providers.md b/doc/providers.md index 8965560ac..fa06673b6 100644 --- a/doc/providers.md +++ b/doc/providers.md @@ -61,7 +61,7 @@ Propagates Swift-specific information about a `proto_library`. ## SwiftToolchainInfo
-SwiftToolchainInfo(action_configs, all_files, cc_toolchain_info, cpu,
+SwiftToolchainInfo(action_configs, all_files, cc_toolchain_info, cpu, feature_allowlists,
                    generated_header_module_implicit_deps_providers, implicit_deps_providers,
                    linker_opts_producer, linker_supports_filelist, object_format, requested_features,
                    root_dir, supports_objc_interop, swift_worker, system_name, test_configuration,
@@ -82,6 +82,7 @@ that use the toolchain.
 | all_files |  A depset of Files containing all the Swift toolchain files (tools, libraries, and other resource files) so they can be passed as tools to actions using this toolchain.    |
 | cc_toolchain_info |  The cc_common.CcToolchainInfo provider from the Bazel C++ toolchain that this Swift toolchain depends on.    |
 | cpu |  String. The CPU architecture that the toolchain is targeting.    |
+| feature_allowlists |  A list of SwiftFeatureAllowlistInfo providers that allow or prohibit packages from requesting or disabling features.    |
 | generated_header_module_implicit_deps_providers |  A struct with the following fields, which are providers from targets that should be treated as compile-time inputs to actions that precompile the explicit module for the generated Objective-C header of a Swift module:

* cc_infos: A list of CcInfo providers from targets specified as the toolchain's implicit dependencies. * objc_infos: A list of apple_common.Objc providers from targets specified as the toolchain's implicit dependencies. * swift_infos: A list of SwiftInfo providers from targets specified as the toolchain's implicit dependencies.

This is used to provide modular dependencies for the fixed inclusions (Darwin, Foundation) that are unconditionally emitted in those files.

For ease of use, this field is never None; it will always be a valid struct containing the fields described above, even if those lists are empty. | | implicit_deps_providers | A struct with the following fields, which represent providers from targets that should be added as implicit dependencies of any Swift compilation or linking target (but not to precompiled explicit C/Objective-C modules):

* cc_infos: A list of CcInfo providers from targets specified as the toolchain's implicit dependencies. * objc_infos: A list of apple_common.Objc providers from targets specified as the toolchain's implicit dependencies. * swift_infos: A list of SwiftInfo providers from targets specified as the toolchain's implicit dependencies.

For ease of use, this field is never None; it will always be a valid struct containing the fields described above, even if those lists are empty. | | linker_opts_producer | Skylib partial. A partial function that returns the flags that should be passed to Clang to link a binary or test target with the Swift runtime libraries.

The partial should be called with two arguments:

* is_static: A Boolean value indicating whether to link against the static or dynamic runtime libraries.

* is_test: A Boolean value indicating whether the target being linked is a test target. | diff --git a/doc/rules.md b/doc/rules.md index cfdd59204..7117649fa 100644 --- a/doc/rules.md +++ b/doc/rules.md @@ -18,6 +18,7 @@ On this page: * [swift_binary](#swift_binary) * [swift_c_module](#swift_c_module) + * [swift_feature_allowlist](#swift_feature_allowlist) * [swift_grpc_library](#swift_grpc_library) * [swift_import](#swift_import) * [swift_library](#swift_library) @@ -117,6 +118,37 @@ any C++ declarations. | module_name | The name of the top-level module in the module map that this target represents.

A single module.modulemap file can define multiple top-level modules. When building with implicit modules, the presence of that module map allows any of the modules defined in it to be imported. When building explicit modules, however, there is a one-to-one correspondence between top-level modules and BUILD targets and the module name must be known without reading the module map file, so it must be provided directly. Therefore, one may have multiple swift_c_module targets that reference the same module.modulemap file but with different module names and headers. | String | required | | + + +## swift_feature_allowlist + +
+swift_feature_allowlist(name, managed_features, packages)
+
+ +Limits the ability to request or disable certain features to a set of packages +(and possibly subpackages) in the workspace. + +A Swift toolchain target can reference any number (zero or more) of +`swift_feature_allowlist` targets. The features managed by these allowlists may +overlap. For some package _P_, a feature is allowed to be used by targets in +that package if _P_ matches the `packages` patterns in *all* of the allowlists +that manage that feature. + +A feature that is not managed by any allowlist is allowed to be used by any +package. + + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | +| managed_features | A list of feature strings that are permitted to be specified by the targets in the packages matched by the packages attribute. This list may include both feature names and/or negations (a name with a leading -); a regular feature name means that the targets in the matching packages may explicitly request that the feature be enabled, and a negated feature means that the target may explicitly request that the feature be disabled.

For example, managed_features = ["foo", "-bar"] means that targets in the allowlist's packages may request that feature "foo" be enabled and that feature "bar" be disabled. | List of strings | optional | [] | +| packages | A list of strings representing packages (possibly recursive) whose targets are allowed to enable/disable the features in managed_features. Each package pattern is written in the syntax used by the package_group function:

* //foo/bar: Targets in the package //foo/bar but not in subpackages. * //foo/bar/...: Targets in the package //foo/bar and any of its subpackages. * A leading - excludes packages that would otherwise have been included by the patterns in the list.

Exclusions always take priority over inclusions; order in the list is irrelevant. | List of strings | required | | + + ## swift_grpc_library diff --git a/swift/BUILD b/swift/BUILD index d48b57c47..03429e5fe 100644 --- a/swift/BUILD +++ b/swift/BUILD @@ -31,6 +31,7 @@ bzl_library( "//swift/internal:swift_binary_test", "//swift/internal:swift_c_module", "//swift/internal:swift_common", + "//swift/internal:swift_feature_allowlist", "//swift/internal:swift_grpc_library", "//swift/internal:swift_import", "//swift/internal:swift_library", diff --git a/swift/internal/BUILD b/swift/internal/BUILD index 5a83d02a1..f63b536e6 100644 --- a/swift/internal/BUILD +++ b/swift/internal/BUILD @@ -144,6 +144,15 @@ bzl_library( ], ) +bzl_library( + name = "swift_feature_allowlist", + srcs = ["swift_feature_allowlist.bzl"], + visibility = ["//swift:__subpackages__"], + deps = [ + ":providers", + ], +) + bzl_library( name = "swift_binary_test", srcs = ["swift_binary_test.bzl"], diff --git a/swift/internal/features.bzl b/swift/internal/features.bzl index 51b20c287..2cd6cfc4b 100644 --- a/swift/internal/features.bzl +++ b/swift/internal/features.bzl @@ -75,6 +75,13 @@ def configure_features( passed to other `swift_common` functions. Note that the structure of this value should otherwise not be relied on or inspected directly. """ + if swift_toolchain.feature_allowlists: + _check_allowlists( + allowlists = swift_toolchain.feature_allowlists, + label = ctx.label, + requested_features = requested_features, + unsupported_features = unsupported_features, + ) # The features to enable for a particular rule/target are the ones requested # by the toolchain, plus the ones requested by the target itself, *minus* @@ -175,3 +182,98 @@ def is_feature_enabled(feature_configuration, feature_name): ), feature_name = feature_name, ) + +def _check_allowlists( + *, + allowlists, + label, + requested_features, + unsupported_features): + """Checks the toolchain's allowlists to verify the requested features. + + If any of the features requested to be enabled or disabled is not allowed in + the target's package by one of the allowlists, the build will fail with an + error message indicating the feature and the allowlist that denied it. + + Args: + allowlists: A list of `SwiftFeatureAllowlistInfo` providers that will be + checked. + label: The label of the target being checked against the allowlist. + requested_features: The list of features to be enabled. This is + typically obtained using the `ctx.features` field in a rule + implementation function. + unsupported_features: The list of features that are unsupported by the + current rule. This is typically obtained using the + `ctx.disabled_features` field in a rule implementation function. + """ + features_to_check = list(requested_features) + features_to_check.extend( + ["-{}".format(feature) for feature in unsupported_features], + ) + + for allowlist in allowlists: + for feature_string in features_to_check: + if not _is_feature_allowed_in_package( + allowlist = allowlist, + feature = feature_string, + package = label.package, + workspace_name = label.workspace_name, + ): + fail(( + "Feature '{feature}' is not allowed to be set by the " + + "target '{target}'; see the allowlist at '{allowlist}' " + + "for more information." + ).format( + allowlist = allowlist.allowlist_label, + feature = feature_string, + target = str(label), + )) + +def _is_feature_allowed_in_package( + allowlist, + feature, + package, + workspace_name = None): + """Returns a value indicating whether a feature is allowed in a package. + + Args: + allowlist: The `SwiftFeatureAllowlistInfo` provider that contains the + allowlist. + feature: The name of the feature (or its negation) being checked. + package: The package part of the label being checked for access (e.g., + the value of `ctx.label.package`). + workspace_name: The workspace name part of the label being checked for + access (e.g., the value of `ctx.label.workspace_name`). + + Returns: + True if the feature is allowed to be used in the package, or False if it + is not. + """ + + # Any feature not managed by the allowlist is allowed by default. + if feature not in allowlist.managed_features: + return True + + if workspace_name: + package_spec = "@{}//{}".format(workspace_name, package) + else: + package_spec = "//{}".format(package) + + is_allowed = False + for package_info in allowlist.packages: + if package_info.match_subpackages: + is_match = ( + package_spec == package_info.package or + package_spec.startswith(package_info.package + "/") + ) + else: + is_match = package_spec == package_info.package + + # Package exclusions always take precedence over package inclusions, so + # if we have an exclusion match, return false immediately. + if package_info.excluded and is_match: + return False + else: + is_allowed = True + + return is_allowed diff --git a/swift/internal/providers.bzl b/swift/internal/providers.bzl index 5af061c1a..5131b102e 100644 --- a/swift/internal/providers.bzl +++ b/swift/internal/providers.bzl @@ -14,6 +14,47 @@ """Defines Starlark providers that propagated by the Swift BUILD rules.""" +SwiftAllowlistPackageInfo = provider( + doc = "Describes a package match in an allowlist.", + fields = { + "excluded": """\ +A Boolean value indicating whether the packages described by this value are +exclusions rather than inclusions. +""", + "match_subpackages": """\ +A Boolean value indicating whether subpackages of `package` should also be +matched. +""", + "package": """\ +A string indicating the name of the package to match, in the form +`//path/to/package`, or `@repository//path/to/package` if an explicit repository +name was given. +""", + }, +) + +SwiftFeatureAllowlistInfo = provider( + doc = """\ +Describes a set of features and the packages that are allowed to request or +disable them. +""", + fields = { + "allowlist_label": """\ +A string containing the label of the `swift_feature_allowlist` target that +created this provider. +""", + "managed_features": """\ +A list of strings representing feature names or their negations that packages in +the `packages` list are allowed to explicitly request or disable. +""", + "packages": """\ +A list of `SwiftAllowlistPackageInfo` values describing packages (possibly +recursive) whose targets are allowed to request or disable a feature managed by +this allowlist. +""", + }, +) + SwiftInfo = provider( doc = """\ Contains information about the compiled artifacts of a Swift module. @@ -72,6 +113,10 @@ Swift toolchain depends on. """, "cpu": """\ `String`. The CPU architecture that the toolchain is targeting. +""", + "feature_allowlists": """\ +A list of `SwiftFeatureAllowlistInfo` providers that allow or prohibit packages +from requesting or disabling features. """, "generated_header_module_implicit_deps_providers": """\ A `struct` with the following fields, which are providers from targets that diff --git a/swift/internal/swift_feature_allowlist.bzl b/swift/internal/swift_feature_allowlist.bzl new file mode 100644 index 000000000..fc31a778f --- /dev/null +++ b/swift/internal/swift_feature_allowlist.bzl @@ -0,0 +1,109 @@ +# Copyright 2021 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Support for restricting access to features based on an allowlist.""" + +load(":providers.bzl", "SwiftAllowlistPackageInfo", "SwiftFeatureAllowlistInfo") + +def _parse_allowlist_package(package_spec): + """Parses an allowlist package specification from a string. + + Args: + package_spec: A string that represents a possibly recursive package + specification, with an optional exclusion marker in front. + + Returns: + An instance of `SwiftAllowlistPackageInfo` containing the parsed + information from the package specification. + """ + if package_spec.startswith("-"): + excluded = True + package_spec = package_spec[1:] + else: + excluded = False + + if package_spec.endswith("/..."): + match_subpackages = True + package_spec = package_spec[:-4] + else: + match_subpackages = False + + return SwiftAllowlistPackageInfo( + excluded = excluded, + match_subpackages = match_subpackages, + package = package_spec, + ) + +def _swift_feature_allowlist_impl(ctx): + return [SwiftFeatureAllowlistInfo( + allowlist_label = str(ctx.label), + managed_features = ctx.attr.managed_features, + packages = [ + _parse_allowlist_package(package_spec) + for package_spec in ctx.attr.packages + ], + )] + +swift_feature_allowlist = rule( + attrs = { + "managed_features": attr.string_list( + allow_empty = True, + doc = """\ +A list of feature strings that are permitted to be specified by the targets in +the packages matched by the `packages` attribute. This list may include both +feature names and/or negations (a name with a leading `-`); a regular feature +name means that the targets in the matching packages may explicitly request that +the feature be enabled, and a negated feature means that the target may +explicitly request that the feature be disabled. + +For example, `managed_features = ["foo", "-bar"]` means that targets in the +allowlist's packages may request that feature `"foo"` be enabled and that +feature `"bar"` be disabled. +""", + mandatory = False, + ), + "packages": attr.string_list( + allow_empty = True, + doc = """\ +A list of strings representing packages (possibly recursive) whose targets are +allowed to enable/disable the features in `managed_features`. Each package +pattern is written in the syntax used by the `package_group` function: + +* `//foo/bar`: Targets in the package `//foo/bar` but not in subpackages. +* `//foo/bar/...`: Targets in the package `//foo/bar` and any of its + subpackages. +* A leading `-` excludes packages that would otherwise have been included by + the patterns in the list. + +Exclusions always take priority over inclusions; order in the list is +irrelevant. +""", + mandatory = True, + ), + }, + doc = """\ +Limits the ability to request or disable certain features to a set of packages +(and possibly subpackages) in the workspace. + +A Swift toolchain target can reference any number (zero or more) of +`swift_feature_allowlist` targets. The features managed by these allowlists may +overlap. For some package _P_, a feature is allowed to be used by targets in +that package if _P_ matches the `packages` patterns in *all* of the allowlists +that manage that feature. + +A feature that is not managed by any allowlist is allowed to be used by any +package. +""", + implementation = _swift_feature_allowlist_impl, +) diff --git a/swift/internal/swift_toolchain.bzl b/swift/internal/swift_toolchain.bzl index 29b68e2a1..05ec28e24 100644 --- a/swift/internal/swift_toolchain.bzl +++ b/swift/internal/swift_toolchain.bzl @@ -34,7 +34,7 @@ load( "SWIFT_FEATURE_USE_RESPONSE_FILES", ) load(":features.bzl", "features_for_build_modes") -load(":providers.bzl", "SwiftToolchainInfo") +load(":providers.bzl", "SwiftFeatureAllowlistInfo", "SwiftToolchainInfo") load(":toolchain_config.bzl", "swift_toolchain_config") load( ":utils.bzl", @@ -216,6 +216,10 @@ def _swift_toolchain_impl(ctx): all_files = depset(all_files), cc_toolchain_info = cc_toolchain, cpu = ctx.attr.arch, + feature_allowlists = [ + target[SwiftFeatureAllowlistInfo] + for target in ctx.attr.feature_allowlists + ], generated_header_module_implicit_deps_providers = ( collect_implicit_deps_providers([]) ), @@ -254,6 +258,13 @@ architecture-specific content, such as "x86_64" in "lib/swift/linux/x86_64". """, mandatory = True, ), + "feature_allowlists": attr.label_list( + doc = """\ +A list of `swift_feature_allowlist` targets that allow or prohibit packages from +requesting or disabling features. +""", + providers = [[SwiftFeatureAllowlistInfo]], + ), "os": attr.string( doc = """\ The name of the operating system that this toolchain targets. diff --git a/swift/internal/xcode_swift_toolchain.bzl b/swift/internal/xcode_swift_toolchain.bzl index e84945998..0d9b52781 100644 --- a/swift/internal/xcode_swift_toolchain.bzl +++ b/swift/internal/xcode_swift_toolchain.bzl @@ -46,7 +46,12 @@ load( ) load(":features.bzl", "features_for_build_modes") load(":toolchain_config.bzl", "swift_toolchain_config") -load(":providers.bzl", "SwiftInfo", "SwiftToolchainInfo") +load( + ":providers.bzl", + "SwiftFeatureAllowlistInfo", + "SwiftInfo", + "SwiftToolchainInfo", +) load( ":utils.bzl", "collect_implicit_deps_providers", @@ -777,6 +782,10 @@ def _xcode_swift_toolchain_impl(ctx): all_files = depset(all_files), cc_toolchain_info = cc_toolchain, cpu = cpu, + feature_allowlists = [ + target[SwiftFeatureAllowlistInfo] + for target in ctx.attr.feature_allowlists + ], generated_header_module_implicit_deps_providers = ( collect_implicit_deps_providers( ctx.attr.generated_header_module_implicit_deps, @@ -807,6 +816,13 @@ xcode_swift_toolchain = rule( attrs = dicts.add( swift_toolchain_driver_attrs(), { + "feature_allowlists": attr.label_list( + doc = """\ +A list of `swift_feature_allowlist` targets that allow or prohibit packages from +requesting or disabling features. +""", + providers = [[SwiftFeatureAllowlistInfo]], + ), "generated_header_module_implicit_deps": attr.label_list( doc = """\ Targets whose `SwiftInfo` providers should be treated as compile-time inputs to diff --git a/swift/swift.bzl b/swift/swift.bzl index 835051d92..e8e2e4397 100644 --- a/swift/swift.bzl +++ b/swift/swift.bzl @@ -51,6 +51,10 @@ load( "@build_bazel_rules_swift//swift/internal:swift_common.bzl", _swift_common = "swift_common", ) +load( + "@build_bazel_rules_swift//swift/internal:swift_feature_allowlist.bzl", + _swift_feature_allowlist = "swift_feature_allowlist", +) load( "@build_bazel_rules_swift//swift/internal:swift_grpc_library.bzl", _swift_grpc_library = "swift_grpc_library", @@ -88,12 +92,13 @@ swift_common = _swift_common # Re-export rules. swift_binary = _swift_binary swift_c_module = _swift_c_module +swift_feature_allowlist = _swift_feature_allowlist swift_grpc_library = _swift_grpc_library swift_import = _swift_import swift_library = _swift_library -swift_test = _swift_test swift_module_alias = _swift_module_alias swift_proto_library = _swift_proto_library +swift_test = _swift_test # Re-export public aspects. swift_clang_module_aspect = _swift_clang_module_aspect From 046ab589de39a20386e4008128a72640679d72a7 Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Tue, 4 May 2021 08:30:28 -0700 Subject: [PATCH 131/152] Disable layering checks when compiling the explicit module for a Swift generated header. The Swift compiler determines which module to import a symbol from based on the module that defines that symbol. Due to modular re-exports (which are particularly common among system frameworks), this may not be the same framework that the user imported from Swift and added to their dependencies. (For example, most users will import and depend on `Foundation` to use `NSObject`, but Swift will import it from the module it is actually defined in, `ObjectiveC`.) PiperOrigin-RevId: 371919747 (cherry picked from commit d8a381c0174d3a445389c3decc3727d41b80b255) --- swift/internal/compiling.bzl | 104 +++++++++++++++++++++++++++++++---- 1 file changed, 94 insertions(+), 10 deletions(-) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index 0482f5a68..0148c5a28 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -474,6 +474,21 @@ def compile_action_configs( ] #### Flags controlling how Swift/Clang modular inputs are processed + + def c_layering_check_configurator(prerequisites, args, *, strict): + # We do not enforce layering checks for the Objective-C header generated + # by Swift, because we don't have predictable control over the imports + # that it generates. Due to modular re-exports (which are especially + # common among system frameworks), it may generate an import declaration + # for a particular symbol from a different module than the Swift code + # imported it from. + if not prerequisites.is_swift_generated_header: + args.add( + "-Xcc", + "-fmodules-strict-decluse" if strict else "-fmodules-decluse", + ) + return None + action_configs += [ # Treat paths in .modulemap files as workspace-relative, not modulemap- # relative. @@ -578,12 +593,10 @@ def compile_action_configs( swift_toolchain_config.action_config( actions = [swift_action_names.PRECOMPILE_C_MODULE], configurators = [ - # Enforce `use` declarations for user modules since we generate - # those, but not for system modules since they typically do not - # have the proper `use` decls. - swift_toolchain_config.add_arg( - "-Xcc", - "-fmodules-decluse", + lambda prerequisites, args: c_layering_check_configurator( + prerequisites, + args, + strict = False, ), ], not_features = [ @@ -594,9 +607,10 @@ def compile_action_configs( swift_toolchain_config.action_config( actions = [swift_action_names.PRECOMPILE_C_MODULE], configurators = [ - swift_toolchain_config.add_arg( - "-Xcc", - "-fmodules-strict-decluse", + lambda prerequisites, args: c_layering_check_configurator( + prerequisites, + args, + strict = True, ), ], features = [SWIFT_FEATURE_LAYERING_CHECK], @@ -1799,12 +1813,13 @@ def compile( deps = deps, ) ) - precompiled_module = precompile_clang_module( + precompiled_module = _precompile_clang_module( actions = actions, bin_dir = bin_dir, cc_compilation_context = compilation_context_to_compile, feature_configuration = feature_configuration, genfiles_dir = genfiles_dir, + is_swift_generated_header = True, module_map_file = compile_outputs.generated_module_map_file, module_name = module_name, swift_info = create_swift_info( @@ -1891,6 +1906,74 @@ def precompile_clang_module( swift_info: A `SwiftInfo` provider that contains dependencies required to compile this module. + Returns: + A `File` representing the precompiled module (`.pcm`) file, or `None` if + the toolchain or target does not support precompiled modules. + """ + return _precompile_clang_module( + actions = actions, + bin_dir = bin_dir, + cc_compilation_context = cc_compilation_context, + feature_configuration = feature_configuration, + genfiles_dir = genfiles_dir, + is_swift_generated_header = False, + module_map_file = module_map_file, + module_name = module_name, + swift_info = swift_info, + swift_toolchain = swift_toolchain, + target_name = target_name, + ) + +def _precompile_clang_module( + *, + actions, + cc_compilation_context, + feature_configuration, + is_swift_generated_header, + module_map_file, + module_name, + swift_toolchain, + target_name, + bin_dir = None, + genfiles_dir = None, + swift_info = None): + """Precompiles an explicit Clang module that is compatible with Swift. + + Args: + actions: The context's `actions` object. + cc_compilation_context: A `CcCompilationContext` that contains headers + and other information needed to compile this module. This + compilation context should contain all headers required to compile + the module, which includes the headers for the module itself *and* + any others that must be present on the file system/in the sandbox + for compilation to succeed. The latter typically refers to the set + of headers of the direct dependencies of the module being compiled, + which Clang needs to be physically present before it detects that + they belong to one of the precompiled module dependencies. + feature_configuration: A feature configuration obtained from + `swift_common.configure_features`. + is_swift_generated_header: If True, the action is compiling the + Objective-C header generated by the Swift compiler for a module. + module_map_file: A textual module map file that defines the Clang module + to be compiled. + module_name: The name of the top-level module in the module map that + will be compiled. + swift_toolchain: The `SwiftToolchainInfo` provider of the toolchain. + target_name: The name of the target for which the code is being + compiled, which is used to determine unique file paths for the + outputs. + bin_dir: The Bazel `*-bin` directory root. If provided, its path is used + to store the cache for modules precompiled by Swift's ClangImporter, + and it is added to ClangImporter's header search paths for + compatibility with Bazel's C++ and Objective-C rules which support + includes of generated headers from that location. + genfiles_dir: The Bazel `*-genfiles` directory root. If provided, its + path is added to ClangImporter's header search paths for + compatibility with Bazel's C++ and Objective-C rules which support + inclusions of generated headers from that location. + swift_info: A `SwiftInfo` provider that contains dependencies required + to compile this module. + Returns: A `File` representing the precompiled module (`.pcm`) file, or `None` if the toolchain or target does not support precompiled modules. @@ -1925,6 +2008,7 @@ def precompile_clang_module( cc_info = CcInfo(compilation_context = cc_compilation_context), genfiles_dir = genfiles_dir, is_swift = False, + is_swift_generated_header = is_swift_generated_header, module_name = module_name, objc_include_paths_workaround = depset(), objc_info = apple_common.new_objc_provider(), From 021c11b1d578ffba547140eb24854cdfe74c794f Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Fri, 28 May 2021 15:13:22 -0700 Subject: [PATCH 132/152] Disable layering checks for now This depends on lambda support which bazel 4.1 does not have --- swift/internal/compiling.bzl | 49 +++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index 0148c5a28..f55e8060f 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -475,19 +475,20 @@ def compile_action_configs( #### Flags controlling how Swift/Clang modular inputs are processed - def c_layering_check_configurator(prerequisites, args, *, strict): - # We do not enforce layering checks for the Objective-C header generated - # by Swift, because we don't have predictable control over the imports - # that it generates. Due to modular re-exports (which are especially - # common among system frameworks), it may generate an import declaration - # for a particular symbol from a different module than the Swift code - # imported it from. - if not prerequisites.is_swift_generated_header: - args.add( - "-Xcc", - "-fmodules-strict-decluse" if strict else "-fmodules-decluse", - ) - return None + # TODO: Enable once bazel supports lambdas + # def c_layering_check_configurator(prerequisites, args, *, strict): + # # We do not enforce layering checks for the Objective-C header generated + # # by Swift, because we don't have predictable control over the imports + # # that it generates. Due to modular re-exports (which are especially + # # common among system frameworks), it may generate an import declaration + # # for a particular symbol from a different module than the Swift code + # # imported it from. + # if not prerequisites.is_swift_generated_header: + # args.add( + # "-Xcc", + # "-fmodules-strict-decluse" if strict else "-fmodules-decluse", + # ) + # return None action_configs += [ # Treat paths in .modulemap files as workspace-relative, not modulemap- @@ -593,11 +594,12 @@ def compile_action_configs( swift_toolchain_config.action_config( actions = [swift_action_names.PRECOMPILE_C_MODULE], configurators = [ - lambda prerequisites, args: c_layering_check_configurator( - prerequisites, - args, - strict = False, - ), + # TODO: Enable once bazel supports lambdas + # lambda prerequisites, args: c_layering_check_configurator( + # prerequisites, + # args, + # strict = False, + # ), ], not_features = [ [SWIFT_FEATURE_LAYERING_CHECK], @@ -607,11 +609,12 @@ def compile_action_configs( swift_toolchain_config.action_config( actions = [swift_action_names.PRECOMPILE_C_MODULE], configurators = [ - lambda prerequisites, args: c_layering_check_configurator( - prerequisites, - args, - strict = True, - ), + # TODO: Enable once bazel supports lambdas + # lambda prerequisites, args: c_layering_check_configurator( + # prerequisites, + # args, + # strict = True, + # ), ], features = [SWIFT_FEATURE_LAYERING_CHECK], not_features = [SWIFT_FEATURE_SYSTEM_MODULE], From 0414e01e7bc7233e0fc55abd8f8f27671912e4fe Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Fri, 28 May 2021 15:19:06 -0700 Subject: [PATCH 133/152] Revert "Disable layering checks for now" This reverts commit 021c11b1d578ffba547140eb24854cdfe74c794f. --- swift/internal/compiling.bzl | 49 +++++++++++++++++------------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index f55e8060f..0148c5a28 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -475,20 +475,19 @@ def compile_action_configs( #### Flags controlling how Swift/Clang modular inputs are processed - # TODO: Enable once bazel supports lambdas - # def c_layering_check_configurator(prerequisites, args, *, strict): - # # We do not enforce layering checks for the Objective-C header generated - # # by Swift, because we don't have predictable control over the imports - # # that it generates. Due to modular re-exports (which are especially - # # common among system frameworks), it may generate an import declaration - # # for a particular symbol from a different module than the Swift code - # # imported it from. - # if not prerequisites.is_swift_generated_header: - # args.add( - # "-Xcc", - # "-fmodules-strict-decluse" if strict else "-fmodules-decluse", - # ) - # return None + def c_layering_check_configurator(prerequisites, args, *, strict): + # We do not enforce layering checks for the Objective-C header generated + # by Swift, because we don't have predictable control over the imports + # that it generates. Due to modular re-exports (which are especially + # common among system frameworks), it may generate an import declaration + # for a particular symbol from a different module than the Swift code + # imported it from. + if not prerequisites.is_swift_generated_header: + args.add( + "-Xcc", + "-fmodules-strict-decluse" if strict else "-fmodules-decluse", + ) + return None action_configs += [ # Treat paths in .modulemap files as workspace-relative, not modulemap- @@ -594,12 +593,11 @@ def compile_action_configs( swift_toolchain_config.action_config( actions = [swift_action_names.PRECOMPILE_C_MODULE], configurators = [ - # TODO: Enable once bazel supports lambdas - # lambda prerequisites, args: c_layering_check_configurator( - # prerequisites, - # args, - # strict = False, - # ), + lambda prerequisites, args: c_layering_check_configurator( + prerequisites, + args, + strict = False, + ), ], not_features = [ [SWIFT_FEATURE_LAYERING_CHECK], @@ -609,12 +607,11 @@ def compile_action_configs( swift_toolchain_config.action_config( actions = [swift_action_names.PRECOMPILE_C_MODULE], configurators = [ - # TODO: Enable once bazel supports lambdas - # lambda prerequisites, args: c_layering_check_configurator( - # prerequisites, - # args, - # strict = True, - # ), + lambda prerequisites, args: c_layering_check_configurator( + prerequisites, + args, + strict = True, + ), ], features = [SWIFT_FEATURE_LAYERING_CHECK], not_features = [SWIFT_FEATURE_SYSTEM_MODULE], From 7688933952ea0ce17acec05361c79925a6b66000 Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Tue, 25 May 2021 16:54:34 -0700 Subject: [PATCH 134/152] Get rid of the non-strict use of `-fmodules-decluse`. For layering checks with explicit modules, we only want `-fmodules-strict-decluse`; it's not useful to let headers without a known module map sneak through. PiperOrigin-RevId: 375825780 (cherry picked from commit 214f725069a19529b53d3d084e1fab1f6502b03b) --- swift/internal/compiling.bzl | 46 +++++++++--------------------------- 1 file changed, 11 insertions(+), 35 deletions(-) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index 0148c5a28..6927c79df 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -475,20 +475,6 @@ def compile_action_configs( #### Flags controlling how Swift/Clang modular inputs are processed - def c_layering_check_configurator(prerequisites, args, *, strict): - # We do not enforce layering checks for the Objective-C header generated - # by Swift, because we don't have predictable control over the imports - # that it generates. Due to modular re-exports (which are especially - # common among system frameworks), it may generate an import declaration - # for a particular symbol from a different module than the Swift code - # imported it from. - if not prerequisites.is_swift_generated_header: - args.add( - "-Xcc", - "-fmodules-strict-decluse" if strict else "-fmodules-decluse", - ) - return None - action_configs += [ # Treat paths in .modulemap files as workspace-relative, not modulemap- # relative. @@ -592,27 +578,7 @@ def compile_action_configs( ), swift_toolchain_config.action_config( actions = [swift_action_names.PRECOMPILE_C_MODULE], - configurators = [ - lambda prerequisites, args: c_layering_check_configurator( - prerequisites, - args, - strict = False, - ), - ], - not_features = [ - [SWIFT_FEATURE_LAYERING_CHECK], - [SWIFT_FEATURE_SYSTEM_MODULE], - ], - ), - swift_toolchain_config.action_config( - actions = [swift_action_names.PRECOMPILE_C_MODULE], - configurators = [ - lambda prerequisites, args: c_layering_check_configurator( - prerequisites, - args, - strict = True, - ), - ], + configurators = [_c_layering_check_configurator], features = [SWIFT_FEATURE_LAYERING_CHECK], not_features = [SWIFT_FEATURE_SYSTEM_MODULE], ), @@ -1020,6 +986,16 @@ def _batch_mode_configurator(prerequisites, args): if not _is_wmo_manually_requested(prerequisites.user_compile_flags): args.add("-enable-batch-mode") +def _c_layering_check_configurator(prerequisites, args): + # We do not enforce layering checks for the Objective-C header generated by + # Swift, because we don't have predictable control over the imports that it + # generates. Due to modular re-exports (which are especially common among + # system frameworks), it may generate an import declaration for a particular + # symbol from a different module than the Swift code imported it from. + if not prerequisites.is_swift_generated_header: + args.add("-Xcc", "-fmodules-strict-decluse") + return None + def _clang_search_paths_configurator(prerequisites, args): """Adds Clang search paths to the command line.""" args.add_all( From 0487a75d9a8c70edd03068af28d67236b20bc4a9 Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Tue, 25 May 2021 16:05:19 -0700 Subject: [PATCH 135/152] Support implicit C/Objective-C dependencies that are passed when compiling any explicit Clang module. The toolchain's `clang_implicit_deps` are not passed to Swift compilations; only to actions that compile an explicit C/Objective-C module using `swift_common.precompile_clang_module`. PiperOrigin-RevId: 375816204 (cherry picked from commit 9afbc30ed16ba1fe82e33241051e62d788cdda5b) --- swift/internal/compiling.bzl | 34 +++++++++++++------- swift/internal/providers.bzl | 15 +++++++++ swift/internal/swift_clang_module_aspect.bzl | 15 ++++----- swift/internal/swift_toolchain.bzl | 3 ++ swift/internal/xcode_swift_toolchain.bzl | 19 +++++++++++ 5 files changed, 66 insertions(+), 20 deletions(-) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index 6927c79df..6482d5f52 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -1798,9 +1798,7 @@ def compile( is_swift_generated_header = True, module_map_file = compile_outputs.generated_module_map_file, module_name = module_name, - swift_info = create_swift_info( - swift_infos = generated_module_deps_swift_infos, - ), + swift_infos = generated_module_deps_swift_infos, swift_toolchain = swift_toolchain, target_name = target_name, ) @@ -1846,7 +1844,7 @@ def precompile_clang_module( target_name, bin_dir = None, genfiles_dir = None, - swift_info = None): + swift_infos = []): """Precompiles an explicit Clang module that is compatible with Swift. Args: @@ -1879,8 +1877,8 @@ def precompile_clang_module( path is added to ClangImporter's header search paths for compatibility with Bazel's C++ and Objective-C rules which support inclusions of generated headers from that location. - swift_info: A `SwiftInfo` provider that contains dependencies required - to compile this module. + swift_infos: A list of `SwiftInfo` providers representing dependencies + required to compile this module. Returns: A `File` representing the precompiled module (`.pcm`) file, or `None` if @@ -1895,7 +1893,7 @@ def precompile_clang_module( is_swift_generated_header = False, module_map_file = module_map_file, module_name = module_name, - swift_info = swift_info, + swift_infos = swift_infos, swift_toolchain = swift_toolchain, target_name = target_name, ) @@ -1912,7 +1910,7 @@ def _precompile_clang_module( target_name, bin_dir = None, genfiles_dir = None, - swift_info = None): + swift_infos = []): """Precompiles an explicit Clang module that is compatible with Swift. Args: @@ -1947,8 +1945,8 @@ def _precompile_clang_module( path is added to ClangImporter's header search paths for compatibility with Bazel's C++ and Objective-C rules which support inclusions of generated headers from that location. - swift_info: A `SwiftInfo` provider that contains dependencies required - to compile this module. + swift_infos: A list of `SwiftInfo` providers representing dependencies + required to compile this module. Returns: A `File` representing the precompiled module (`.pcm`) file, or `None` if @@ -1974,8 +1972,20 @@ def _precompile_clang_module( target_name = target_name, ) - if swift_info: - transitive_modules = swift_info.transitive_modules.to_list() + if not is_swift_generated_header: + implicit_swift_infos = ( + swift_toolchain.clang_implicit_deps_providers.swift_infos + ) + else: + implicit_swift_infos = [] + + if not is_swift_generated_header and implicit_swift_infos: + swift_infos = list(swift_infos) + swift_infos.extend(implicit_swift_infos) + + if swift_infos: + merged_swift_info = create_swift_info(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 5131b102e..990715686 100644 --- a/swift/internal/providers.bzl +++ b/swift/internal/providers.bzl @@ -110,6 +110,21 @@ using this toolchain. "cc_toolchain_info": """\ The `cc_common.CcToolchainInfo` provider from the Bazel C++ toolchain that this Swift toolchain depends on. +""", + "clang_implicit_deps_providers": """\ +A `struct` with the following fields, which represent providers from targets +that should be added as implicit dependencies of any precompiled explicit +C/Objective-C modules: + +* `cc_infos`: A list of `CcInfo` providers from targets specified as the + toolchain's implicit dependencies. +* `objc_infos`: A list of `apple_common.Objc` providers from targets specified + as the toolchain's implicit dependencies. +* `swift_infos`: A list of `SwiftInfo` providers from targets specified as the + toolchain's implicit dependencies. + +For ease of use, this field is never `None`; it will always be a valid `struct` +containing the fields described above, even if those lists are empty. """, "cpu": """\ `String`. The CPU architecture that the toolchain is targeting. diff --git a/swift/internal/swift_clang_module_aspect.bzl b/swift/internal/swift_clang_module_aspect.bzl index e42a4f09e..e2e0efa06 100644 --- a/swift/internal/swift_clang_module_aspect.bzl +++ b/swift/internal/swift_clang_module_aspect.bzl @@ -424,15 +424,14 @@ def _handle_module( """ attr = aspect_ctx.rule.attr - if swift_infos: - merged_swift_info = create_swift_info(swift_infos = swift_infos) - else: - merged_swift_info = None + all_swift_infos = ( + swift_infos + swift_toolchain.clang_implicit_deps_providers.swift_infos + ) # Collect the names of Clang modules that the module being built directly # depends on. dependent_module_names = [] - for swift_info in swift_infos: + for swift_info in all_swift_infos: for module in swift_info.direct_modules: if module.clang: dependent_module_names.append(module.name) @@ -451,8 +450,8 @@ def _handle_module( ) if not module_map_file: - if merged_swift_info: - return [merged_swift_info] + if all_swift_infos: + return [create_swift_info(swift_infos = swift_infos)] else: return [] @@ -475,7 +474,7 @@ def _handle_module( genfiles_dir = aspect_ctx.genfiles_dir, module_map_file = module_map_file, module_name = module_name, - swift_info = merged_swift_info, + swift_infos = swift_infos, swift_toolchain = swift_toolchain, target_name = target.label.name, ) diff --git a/swift/internal/swift_toolchain.bzl b/swift/internal/swift_toolchain.bzl index 05ec28e24..3c4a5c29f 100644 --- a/swift/internal/swift_toolchain.bzl +++ b/swift/internal/swift_toolchain.bzl @@ -215,6 +215,9 @@ def _swift_toolchain_impl(ctx): action_configs = all_action_configs, all_files = depset(all_files), cc_toolchain_info = cc_toolchain, + clang_implicit_deps_providers = ( + collect_implicit_deps_providers([]) + ), cpu = ctx.attr.arch, feature_allowlists = [ target[SwiftFeatureAllowlistInfo] diff --git a/swift/internal/xcode_swift_toolchain.bzl b/swift/internal/xcode_swift_toolchain.bzl index 0d9b52781..44fc95dd9 100644 --- a/swift/internal/xcode_swift_toolchain.bzl +++ b/swift/internal/xcode_swift_toolchain.bzl @@ -781,6 +781,9 @@ def _xcode_swift_toolchain_impl(ctx): action_configs = all_action_configs, all_files = depset(all_files), cc_toolchain_info = cc_toolchain, + clang_implicit_deps_providers = collect_implicit_deps_providers( + ctx.attr.clang_implicit_deps, + ), cpu = cpu, feature_allowlists = [ target[SwiftFeatureAllowlistInfo] @@ -816,6 +819,22 @@ xcode_swift_toolchain = rule( attrs = dicts.add( swift_toolchain_driver_attrs(), { + "clang_implicit_deps": attr.label_list( + doc = """\ +A list of labels to library targets that should be unconditionally added as +implicit dependencies of any explicit C/Objective-C module compiled by the Swift +toolchain. + +Despite being C/Objective-C modules, the targets specified by this attribute +must propagate the `SwiftInfo` provider because the Swift build rules use that +provider to look up Clang module requirements. In particular, the targets must +propagate the provider in their rule implementation themselves and not rely on +the implicit traversal performed by `swift_clang_module_aspect`; the latter is +not possible as it would create a dependency cycle between the toolchain and the +implicit dependencies. +""", + providers = [[SwiftInfo]], + ), "feature_allowlists": attr.label_list( doc = """\ A list of `swift_feature_allowlist` targets that allow or prohibit packages from From bc0bd43c254288e02938a3866d781a586189d80f Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Fri, 28 May 2021 15:21:47 -0700 Subject: [PATCH 136/152] Update docs --- doc/api.md | 4 ++-- doc/providers.md | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/doc/api.md b/doc/api.md index 472e1d935..9922e501a 100644 --- a/doc/api.md +++ b/doc/api.md @@ -475,7 +475,7 @@ A new attribute dictionary that can be added to the attributes of a
 swift_common.precompile_clang_module(actions, cc_compilation_context, feature_configuration,
                                      module_map_file, module_name, swift_toolchain, target_name,
-                                     bin_dir, genfiles_dir, swift_info)
+                                     bin_dir, genfiles_dir, swift_infos)
 
Precompiles an explicit Clang module that is compatible with Swift. @@ -494,7 +494,7 @@ Precompiles an explicit Clang module that is compatible with Swift. | target_name | The name of the target for which the code is being compiled, which is used to determine unique file paths for the outputs. | none | | bin_dir | The Bazel *-bin directory root. If provided, its path is used to store the cache for modules precompiled by Swift's ClangImporter, and it is added to ClangImporter's header search paths for compatibility with Bazel's C++ and Objective-C rules which support includes of generated headers from that location. | None | | genfiles_dir | The Bazel *-genfiles directory root. If provided, its path is added to ClangImporter's header search paths for compatibility with Bazel's C++ and Objective-C rules which support inclusions of generated headers from that location. | None | -| swift_info | A SwiftInfo provider that contains dependencies required to compile this module. | None | +| swift_infos | A list of SwiftInfo providers representing dependencies required to compile this module. | [] | **RETURNS** diff --git a/doc/providers.md b/doc/providers.md index fa06673b6..32470a279 100644 --- a/doc/providers.md +++ b/doc/providers.md @@ -61,11 +61,11 @@ Propagates Swift-specific information about a `proto_library`. ## SwiftToolchainInfo
-SwiftToolchainInfo(action_configs, all_files, cc_toolchain_info, cpu, feature_allowlists,
-                   generated_header_module_implicit_deps_providers, implicit_deps_providers,
-                   linker_opts_producer, linker_supports_filelist, object_format, requested_features,
-                   root_dir, supports_objc_interop, swift_worker, system_name, test_configuration,
-                   tool_configs, unsupported_features)
+SwiftToolchainInfo(action_configs, all_files, cc_toolchain_info, clang_implicit_deps_providers, cpu,
+                   feature_allowlists, generated_header_module_implicit_deps_providers,
+                   implicit_deps_providers, linker_opts_producer, linker_supports_filelist,
+                   object_format, requested_features, root_dir, supports_objc_interop, swift_worker,
+                   system_name, test_configuration, tool_configs, unsupported_features)
 
@@ -81,6 +81,7 @@ that use the toolchain. | action_configs | This field is an internal implementation detail of the build rules. | | all_files | A depset of Files containing all the Swift toolchain files (tools, libraries, and other resource files) so they can be passed as tools to actions using this toolchain. | | cc_toolchain_info | The cc_common.CcToolchainInfo provider from the Bazel C++ toolchain that this Swift toolchain depends on. | +| clang_implicit_deps_providers | A struct with the following fields, which represent providers from targets that should be added as implicit dependencies of any precompiled explicit C/Objective-C modules:

* cc_infos: A list of CcInfo providers from targets specified as the toolchain's implicit dependencies. * objc_infos: A list of apple_common.Objc providers from targets specified as the toolchain's implicit dependencies. * swift_infos: A list of SwiftInfo providers from targets specified as the toolchain's implicit dependencies.

For ease of use, this field is never None; it will always be a valid struct containing the fields described above, even if those lists are empty. | | cpu | String. The CPU architecture that the toolchain is targeting. | | feature_allowlists | A list of SwiftFeatureAllowlistInfo providers that allow or prohibit packages from requesting or disabling features. | | generated_header_module_implicit_deps_providers | A struct with the following fields, which are providers from targets that should be treated as compile-time inputs to actions that precompile the explicit module for the generated Objective-C header of a Swift module:

* cc_infos: A list of CcInfo providers from targets specified as the toolchain's implicit dependencies. * objc_infos: A list of apple_common.Objc providers from targets specified as the toolchain's implicit dependencies. * swift_infos: A list of SwiftInfo providers from targets specified as the toolchain's implicit dependencies.

This is used to provide modular dependencies for the fixed inclusions (Darwin, Foundation) that are unconditionally emitted in those files.

For ease of use, this field is never None; it will always be a valid struct containing the fields described above, even if those lists are empty. | From cde21126dd8d6f3987590876fd4394903abc3c90 Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Wed, 26 May 2021 07:53:04 -0700 Subject: [PATCH 137/152] Get rid of spurious diagnostics when compiling system modules with Xcode 12.5: ``` :0: error: invalid argument '-fsystem-module' only allowed with '-emit-module' ``` This happens because ClangImporter changes the invocation's action to `GenerateModule` *after* the invocation is created by parsing the `-Xcc` flags from the Swift command line, and Clang's argument parser emits a diagnostic if `-fsystem-module` is used with any other action. PiperOrigin-RevId: 375942286 (cherry picked from commit c497e6ed8ca6ea1cf006f950e577e433065f2d6b) --- swift/internal/compiling.bzl | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index 6482d5f52..8cea13102 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -605,6 +605,19 @@ def compile_action_configs( swift_toolchain_config.action_config( actions = [swift_action_names.PRECOMPILE_C_MODULE], configurators = [ + # `-Xclang -emit-module` ought to be unnecessary if `-emit-pcm` + # is present because ClangImporter configures the invocation to + # use the `GenerateModule` action. However, it does so *after* + # creating the invocation by parsing the command line via a + # helper shared by `-emit-pcm` and other operations, so the + # changing of the action to `GenerateModule` occurs too late; + # the argument parser doesn't know that this will be the + # intended action and it emits a spurious diagnostic: + # "'-fsystem-module' only allowed with '-emit-module'". So, for + # system modules we'll pass `-emit-module` as well; it gets rid + # of the diagnostic and doesn't appear to cause other issues. + swift_toolchain_config.add_arg("-Xcc", "-Xclang"), + swift_toolchain_config.add_arg("-Xcc", "-emit-module"), swift_toolchain_config.add_arg("-Xcc", "-Xclang"), swift_toolchain_config.add_arg("-Xcc", "-fsystem-module"), ], From 3d6141f46f6a592d0fb768d29d429b9f6c607724 Mon Sep 17 00:00:00 2001 From: Alex Eagle Date: Thu, 3 Jun 2021 13:14:41 -0700 Subject: [PATCH 138/152] Add buildifier pre-commit hook (#632) Matches the one just landed in rules_apple: bazelbuild/rules_apple@61bc7c0 --- .pre-commit-config.yaml | 9 +++++++++ CONTRIBUTING.md | 13 +++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000..fa3c57b57 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,9 @@ +# See CONTRIBUTING.md for instructions. +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +repos: + - repo: https://github.com/keith/pre-commit-buildifier + rev: 4.0.1.1 + hooks: + - id: buildifier + - id: buildifier-lint diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4ae040462..4d47688c2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,6 +3,19 @@ We'd love to accept your patches and contributions to this project. There are just a few small guidelines you need to follow. +## Formatting + +Starlark files should be formatted by buildifier. +We suggest using a pre-commit hook to automate this. +First [install pre-commit](https://pre-commit.com/#installation), +then run + +```shell +pre-commit install +``` + +Otherwise the Buildkite CI will yell at you about formatting/linting violations. + ## File or claim an issue Please let us know what you're working on if you want to change or add to the From 84286ada38264db60fdfc907bb72863471de6fd7 Mon Sep 17 00:00:00 2001 From: Brentley Jones Date: Fri, 4 Jun 2021 17:32:35 -0500 Subject: [PATCH 139/152] Reuse swiftmodule for incremental builds (#633) --- tools/common/file_system.cc | 15 +++++++ tools/common/file_system.h | 6 +++ tools/worker/output_file_map.cc | 10 +++++ tools/worker/output_file_map.h | 9 +++++ tools/worker/work_processor.cc | 71 +++++++++++++++++++++++++++------ 5 files changed, 98 insertions(+), 13 deletions(-) diff --git a/tools/common/file_system.cc b/tools/common/file_system.cc index f04f55dab..15b2c274f 100644 --- a/tools/common/file_system.cc +++ b/tools/common/file_system.cc @@ -22,6 +22,7 @@ #ifdef __APPLE__ #include +#include #else #include #include @@ -37,6 +38,20 @@ std::string GetCurrentDirectory() { return cwd; } +bool FileExists(const std::string &path) { + return access(path.c_str(), 0) == 0; +} + +bool RemoveFile(const std::string &path) { +#ifdef __APPLE__ + return removefile(path.c_str(), nullptr, 0); +#elif __unix__ + return remove(path.c_str()); +#else +#error Only macOS and Unix are supported at this time. +#endif +} + bool CopyFile(const std::string &src, const std::string &dest) { #ifdef __APPLE__ // The `copyfile` function with `COPYFILE_ALL` mode preserves permissions and diff --git a/tools/common/file_system.h b/tools/common/file_system.h index 2d233809a..644917de3 100644 --- a/tools/common/file_system.h +++ b/tools/common/file_system.h @@ -20,6 +20,12 @@ // Gets the path to the current working directory. std::string GetCurrentDirectory(); +// Returns true if something exists at path. +bool FileExists(const std::string &path); + +// Removes the file at path. Returns true if successful. +bool RemoveFile(const std::string &path); + // Copies the file at src to dest. Returns true if successful. bool CopyFile(const std::string &src, const std::string &dest); diff --git a/tools/worker/output_file_map.cc b/tools/worker/output_file_map.cc index 57bb94807..126d366d2 100644 --- a/tools/worker/output_file_map.cc +++ b/tools/worker/output_file_map.cc @@ -57,6 +57,7 @@ void OutputFileMap::WriteToPath(const std::string &path) { void OutputFileMap::UpdateForIncremental(const std::string &path) { nlohmann::json new_output_file_map; std::map incremental_outputs; + std::map incremental_inputs; // The empty string key is used to represent outputs that are for the whole // module, rather than for a particular source file. @@ -111,6 +112,15 @@ void OutputFileMap::UpdateForIncremental(const std::string &path) { new_output_file_map[src] = src_map; } + auto swiftmodule_path = ReplaceExtension(path, ".swiftmodule", /*all_extensions=*/true); + auto copied_swiftmodule_path = MakeIncrementalOutputPath(swiftmodule_path); + incremental_inputs[swiftmodule_path] = copied_swiftmodule_path; + + auto swiftdoc_path = ReplaceExtension(path, ".swiftdoc", /*all_extensions=*/true); + auto copied_swiftdoc_path = MakeIncrementalOutputPath(swiftdoc_path); + incremental_inputs[swiftdoc_path] = copied_swiftdoc_path; + json_ = new_output_file_map; incremental_outputs_ = incremental_outputs; + incremental_inputs_ = incremental_inputs; } diff --git a/tools/worker/output_file_map.h b/tools/worker/output_file_map.h index b52e7f601..4e17f16fe 100644 --- a/tools/worker/output_file_map.h +++ b/tools/worker/output_file_map.h @@ -39,6 +39,14 @@ class OutputFileMap { return incremental_outputs_; } + // A map containing expected output files that will be generated in the + // non-incremental storage area, but need to be copied back at the start of + // the next compile. The key is the original object path; the corresponding + // value is its location in the incremental storage area. + const std::map incremental_inputs() const { + return incremental_inputs_; + } + // Reads the output file map from the JSON file at the given path, and updates // it to support incremental builds. void ReadFromPath(const std::string &path); @@ -53,6 +61,7 @@ class OutputFileMap { nlohmann::json json_; std::map incremental_outputs_; + std::map incremental_inputs_; }; #endif // BUILD_BAZEL_RULES_SWIFT_TOOLS_WORKER_OUTPUT_FILE_MAP_H_ diff --git a/tools/worker/work_processor.cc b/tools/worker/work_processor.cc index 8e824ade0..ba0ca7a0a 100644 --- a/tools/worker/work_processor.cc +++ b/tools/worker/work_processor.cc @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "tools/worker/work_processor.h" - #include #include @@ -28,6 +26,7 @@ #include "tools/common/temp_file.h" #include "tools/worker/output_file_map.h" #include "tools/worker/swift_runner.h" +#include "tools/worker/work_processor.h" namespace { @@ -38,6 +37,15 @@ static bool ArgumentEnablesWMO(const std::string &arg) { arg == "-force-single-frontend-invocation"; } +static void FinalizeWorkRequest(const blaze::worker::WorkRequest &request, + blaze::worker::WorkResponse *response, + int exit_code, + const std::ostringstream &output) { + response->set_exit_code(exit_code); + response->set_output(output.str()); + response->set_request_id(request.request_id()); +} + }; // end namespace WorkProcessor::WorkProcessor(const std::vector &args) { @@ -111,6 +119,8 @@ void WorkProcessor::ProcessWorkRequest( processed_args.push_back("@" + params_file->GetPath()); params_file_stream.close(); + std::ostringstream stderr_stream; + if (!is_wmo) { for (const auto &expected_object_pair : output_file_map.incremental_outputs()) { @@ -119,15 +129,30 @@ void WorkProcessor::ProcessWorkRequest( // incremental storage area. auto dir_path = Dirname(expected_object_pair.second); if (!MakeDirs(dir_path, S_IRWXU)) { - std::cerr << "Could not create directory " << dir_path << " (errno " - << errno << ")\n"; + stderr_stream << "swift_worker: Could not create directory " << dir_path + << " (errno " << errno << ")\n"; + FinalizeWorkRequest(request, response, EXIT_FAILURE, stderr_stream); + } + } + + // Copy some input files from the incremental storage area to the locations + // where Bazel will generate them. + for (const auto &expected_object_pair : + output_file_map.incremental_inputs()) { + if (FileExists(expected_object_pair.second)) { + if (!CopyFile(expected_object_pair.second, + expected_object_pair.first)) { + stderr_stream << "swift_worker: Could not copy " + << expected_object_pair.second << " to " + << expected_object_pair.first << " (errno " << errno + << ")\n"; + FinalizeWorkRequest(request, response, EXIT_FAILURE, stderr_stream); + } } } } - std::ostringstream stderr_stream; SwiftRunner swift_runner(processed_args, /*force_response_file=*/true); - int exit_code = swift_runner.Run(&stderr_stream, /*stdout_to_stderr=*/true); if (!is_wmo) { @@ -136,14 +161,34 @@ void WorkProcessor::ProcessWorkRequest( for (const auto &expected_object_pair : output_file_map.incremental_outputs()) { if (!CopyFile(expected_object_pair.second, expected_object_pair.first)) { - std::cerr << "Could not copy " << expected_object_pair.second << " to " - << expected_object_pair.first << " (errno " << errno << ")\n"; - exit_code = EXIT_FAILURE; + stderr_stream << "swift_worker: Could not copy " + << expected_object_pair.second << " to " + << expected_object_pair.first << " (errno " << errno + << ")\n"; + FinalizeWorkRequest(request, response, EXIT_FAILURE, stderr_stream); } } - } - response->set_exit_code(exit_code); - response->set_output(stderr_stream.str()); - response->set_request_id(request.request_id()); + // Copy the replaced input files back to the incremental storage for the + // next run. + for (const auto &expected_object_pair : + output_file_map.incremental_inputs()) { + if (FileExists(expected_object_pair.first)) { + if (FileExists(expected_object_pair.second)) { + // CopyFile fails if the file already exists + RemoveFile(expected_object_pair.second); + } + if (!CopyFile(expected_object_pair.first, + expected_object_pair.second)) { + stderr_stream << "swift_worker: Could not copy " + << expected_object_pair.first << " to " + << expected_object_pair.second << " (errno " << errno + << ")\n"; + FinalizeWorkRequest(request, response, EXIT_FAILURE, stderr_stream); + } + } + } + + FinalizeWorkRequest(request, response, exit_code, stderr_stream); + } } From 254e3fa25b282ebe6924566d12cc77d36f7e3b04 Mon Sep 17 00:00:00 2001 From: Brentley Jones Date: Mon, 7 Jun 2021 08:32:52 -0500 Subject: [PATCH 140/152] Add returns (#634) Missed with 84286ada38264db60fdfc907bb72863471de6fd7. Also reverts the hard error on not creating directories. It could try to create the same directory multiple times, and the previous behavior silently errored on those. This can get fixed up in a later change to only try to create each directory once, and to only error if the directory doesn't already exist. --- tools/worker/work_processor.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tools/worker/work_processor.cc b/tools/worker/work_processor.cc index ba0ca7a0a..2cfb40fbb 100644 --- a/tools/worker/work_processor.cc +++ b/tools/worker/work_processor.cc @@ -129,9 +129,8 @@ void WorkProcessor::ProcessWorkRequest( // incremental storage area. auto dir_path = Dirname(expected_object_pair.second); if (!MakeDirs(dir_path, S_IRWXU)) { - stderr_stream << "swift_worker: Could not create directory " << dir_path - << " (errno " << errno << ")\n"; - FinalizeWorkRequest(request, response, EXIT_FAILURE, stderr_stream); + std::cerr << "Could not create directory " << dir_path << " (errno " + << errno << ")\n"; } } @@ -147,6 +146,7 @@ void WorkProcessor::ProcessWorkRequest( << expected_object_pair.first << " (errno " << errno << ")\n"; FinalizeWorkRequest(request, response, EXIT_FAILURE, stderr_stream); + return; } } } @@ -166,6 +166,7 @@ void WorkProcessor::ProcessWorkRequest( << expected_object_pair.first << " (errno " << errno << ")\n"; FinalizeWorkRequest(request, response, EXIT_FAILURE, stderr_stream); + return; } } @@ -185,6 +186,7 @@ void WorkProcessor::ProcessWorkRequest( << expected_object_pair.second << " (errno " << errno << ")\n"; FinalizeWorkRequest(request, response, EXIT_FAILURE, stderr_stream); + return; } } } From 914eff948be54cbcde847ae800a2e373e61a5c56 Mon Sep 17 00:00:00 2001 From: Jerry Marino Date: Wed, 9 Jun 2021 10:10:35 -0700 Subject: [PATCH 141/152] Implement global index store cache (#567) swift and clang write index data based on the status of what resides in `index-store-path`. When using a transient per-swift-library index, it writes O( M imports * N libs) indexer data and slows down compilation significantly: to the tune of 6GB+ index data in my testing. Bazel likes to use per `swift_library` data in order to remote cache them, which needs extra consideration to work with the design of swift and clang and preserve the performance This PR does 2 things to make index while building use the original model of the index-store so we don't have to patch clang and swift for this yet. When the feature, `swift.use_global_index_store`, is set: 1. it writes to a global index cache, `bazel-out/global_index_store` 2. it copies indexstore data (records and units) to where Bazel expected them for caching: e.g. the original location with `swift.index_while_building` I added a detailed description of this feature in the RFC to add it there https://github.com/lyft/index-import/pull/53. In practice, transitive imports will be indexed by deps and if they aren't cached then the fallback is Xcode wil index transitive files if we set those as deps on the unit files --- swift/internal/compiling.bzl | 15 +++ swift/internal/feature_names.bzl | 4 + swift/repositories.bzl | 21 ++++ tools/worker/BUILD | 30 +++++- tools/worker/swift_runner.cc | 168 +++++++++++++++++++++++++++---- tools/worker/swift_runner.h | 20 +++- 6 files changed, 235 insertions(+), 23 deletions(-) diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index 8cea13102..fba2971d4 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -58,6 +58,7 @@ load( "SWIFT_FEATURE_SUPPORTS_SYSTEM_MODULE_FLAG", "SWIFT_FEATURE_SYSTEM_MODULE", "SWIFT_FEATURE_USE_C_MODULES", + "SWIFT_FEATURE_USE_GLOBAL_INDEX_STORE", "SWIFT_FEATURE_USE_GLOBAL_MODULE_CACHE", "SWIFT_FEATURE_VFSOVERLAY", "SWIFT_FEATURE__NUM_THREADS_0_IN_SWIFTCOPTS", @@ -805,6 +806,14 @@ def compile_action_configs( ], features = [SWIFT_FEATURE_ENABLE_SKIP_FUNCTION_BODIES], ), + swift_toolchain_config.action_config( + actions = [swift_action_names.COMPILE], + configurators = [_global_index_store_configurator], + features = [ + SWIFT_FEATURE_INDEX_WHILE_BUILDING, + SWIFT_FEATURE_USE_GLOBAL_INDEX_STORE, + ], + ), # Configure index-while-building. swift_toolchain_config.action_config( @@ -1419,6 +1428,12 @@ def _index_while_building_configurator(prerequisites, args): if not _index_store_path_overridden(prerequisites.user_compile_flags): args.add("-index-store-path", prerequisites.indexstore_directory.path) +def _global_index_store_configurator(prerequisites, args): + """Adds flags for index-store generation to the command line.""" + out_dir = prerequisites.indexstore_directory.dirname.split("/")[0] + path = out_dir + "/_global_index_store" + args.add("-Xwrapped-swift=-global-index-store-import-path=" + path) + def _conditional_compilation_flag_configurator(prerequisites, args): """Adds (non-Clang) conditional compilation flags to the command line.""" all_defines = depset( diff --git a/swift/internal/feature_names.bzl b/swift/internal/feature_names.bzl index 639b516eb..318235d0c 100644 --- a/swift/internal/feature_names.bzl +++ b/swift/internal/feature_names.bzl @@ -99,11 +99,15 @@ SWIFT_FEATURE_ENABLE_TESTING = "swift.enable_testing" SWIFT_FEATURE_FULL_DEBUG_INFO = "swift.full_debug_info" # If enabled, the compilation action for a target will produce an index store. +# https://docs.google.com/document/d/1cH2sTpgSnJZCkZtJl1aY-rzy4uGPcrI-6RrUpdATO2Q/ SWIFT_FEATURE_INDEX_WHILE_BUILDING = "swift.index_while_building" # If enabled the compilation action will not produce indexes for system modules. SWIFT_FEATURE_DISABLE_SYSTEM_INDEX = "swift.disable_system_index" +# Index while building - using a global index store cache +SWIFT_FEATURE_USE_GLOBAL_INDEX_STORE = "swift.use_global_index_store" + # If enabled, compilation actions and module map generation will assume that the # header paths in module maps are relative to the current working directory # (i.e., the workspace root); if disabled, header paths in module maps are diff --git a/swift/repositories.bzl b/swift/repositories.bzl index 0f59e87c2..c27e0c466 100644 --- a/swift/repositories.bzl +++ b/swift/repositories.bzl @@ -108,6 +108,27 @@ def swift_rules_dependencies(): type = "zip", ) + # It relies on `index-import` to import indexes into Bazel's remote + # cache and allow using a global index internally in workers. + # Note: this is only loaded if swift.index_while_building_v2 is enabled + _maybe( + http_archive, + name = "build_bazel_rules_swift_index_import", + build_file_content = """\ +load("@bazel_skylib//rules:native_binary.bzl", "native_binary") + +native_binary( + name = "index_import", + src = "index-import", + out = "index-import", + visibility = ["//visibility:public"], +) +""", + canonical_id = "index-import-5.3.2.6", + urls = ["https://github.com/MobileNativeFoundation/index-import/releases/download/5.3.2.6/index-import.zip"], + sha256 = "61a58363f56c5fd84d4ebebe0d9b5dd90c74ae170405a7b9018e8cf698e679de", + ) + _maybe( swift_autoconfiguration, name = "build_bazel_rules_swift_local_config", diff --git a/tools/worker/BUILD b/tools/worker/BUILD index 6bda082c8..3cd73c71c 100644 --- a/tools/worker/BUILD +++ b/tools/worker/BUILD @@ -18,12 +18,18 @@ config_setting( }, ) +# Internal hinge for index while building V2 feature +config_setting( + name = "use_global_index_store", + values = { + "features": "swift.use_global_index_store", + }, +) + cc_library( name = "compile_with_worker", srcs = [ "compile_with_worker.cc", - "output_file_map.cc", - "output_file_map.h", "work_processor.cc", "work_processor.h", ], @@ -34,7 +40,6 @@ cc_library( "//tools/common:file_system", "//tools/common:path_utils", "//tools/common:temp_file", - "@com_github_nlohmann_json//:json", "@com_google_protobuf//:protobuf", ], ) @@ -50,13 +55,30 @@ cc_library( cc_library( name = "swift_runner", - srcs = ["swift_runner.cc"], + srcs = [ + "output_file_map.cc", + "output_file_map.h", + "swift_runner.cc", + ], hdrs = ["swift_runner.h"], + copts = select({ + ":use_global_index_store": [ + "-DINDEX_IMPORT_PATH=\\\"$(rootpath @build_bazel_rules_swift_index_import//:index_import)\\\"", + ], + "//conditions:default": [], + }), + data = select({ + ":use_global_index_store": [ + "@build_bazel_rules_swift_index_import//:index_import", + ], + "//conditions:default": [], + }), deps = [ "//tools/common:bazel_substitutions", "//tools/common:file_system", "//tools/common:process", "//tools/common:temp_file", + "@com_github_nlohmann_json//:json", ], ) diff --git a/tools/worker/swift_runner.cc b/tools/worker/swift_runner.cc index 0abf53f03..41068581c 100644 --- a/tools/worker/swift_runner.cc +++ b/tools/worker/swift_runner.cc @@ -20,6 +20,7 @@ #include "tools/common/file_system.h" #include "tools/common/process.h" #include "tools/common/temp_file.h" +#include "tools/worker/output_file_map.h" namespace { @@ -129,13 +130,87 @@ int SwiftRunner::Run(std::ostream *stderr_stream, bool stdout_to_stderr) { exit_code = RunSubProcess(rewriter_args, stderr_stream, stdout_to_stderr); } + auto enable_global_index_store = global_index_store_import_path_ != ""; + if (enable_global_index_store) { + OutputFileMap output_file_map; + output_file_map.ReadFromPath(output_file_map_path_); + + auto outputs = output_file_map.incremental_outputs(); + std::map::iterator it; + + std::vector ii_args; +// The index-import runfile path is passed as a define +#if defined(INDEX_IMPORT_PATH) + ii_args.push_back(INDEX_IMPORT_PATH); +#else + // Logical error + std::cerr << "Incorrectly compiled work_processor.cc"; + exit_code = EXIT_FAILURE; + return exit_code; +#endif + + for (it = outputs.begin(); it != outputs.end(); it++) { + // Need the actual output paths of the compiler - not bazel + auto output_path = it->first; + auto file_type = output_path.substr(output_path.find_last_of(".") + 1); + if (file_type == "o") { + ii_args.push_back("-import-output-file"); + ii_args.push_back(output_path); + } + } + + auto exec_root = GetCurrentDirectory(); + // Copy back from the global index store to bazel's index store + ii_args.push_back(exec_root + "/" + global_index_store_import_path_); + ii_args.push_back(exec_root + "/" + index_store_path_); + exit_code = + RunSubProcess(ii_args, stderr_stream, /*stdout_to_stderr=*/true); + } return exit_code; } +// Marker for end of iteration +class StreamIteratorEnd {}; + +// Basic iterator over an ifstream +class StreamIterator { + public: + StreamIterator(std::ifstream &file) : file_{file} { next(); } + + const std::string &operator*() const { return str_; } + + StreamIterator &operator++() { + next(); + return *this; + } + + bool operator!=(StreamIteratorEnd) const { return !!file_; } + + private: + void next() { std::getline(file_, str_); } + + std::ifstream &file_; + std::string str_; +}; + +class ArgsFile { + public: + ArgsFile(std::ifstream &file) : file_(file) {} + + StreamIterator begin() { return StreamIterator{file_}; } + + StreamIteratorEnd end() { return StreamIteratorEnd{}; } + + private: + std::ifstream &file_; +}; + bool SwiftRunner::ProcessPossibleResponseFile( const std::string &arg, std::function consumer) { auto path = arg.substr(1); std::ifstream original_file(path); + ArgsFile args_file(original_file); + // If we couldn't open it, maybe it's not a file; maybe it's just some other // argument that starts with "@" such as "@loader_path/..." if (!original_file.good()) { @@ -143,15 +218,17 @@ bool SwiftRunner::ProcessPossibleResponseFile( return false; } + // Read the file to a vector to prevent double I/O + auto args = ParseArguments(args_file); + // If we're forcing response files, process and send the arguments from this // file directly to the consumer; they'll all get written to the same response // file at the end of processing all the arguments. if (force_response_file_) { - std::string arg_from_file; - while (std::getline(original_file, arg_from_file)) { + for (auto it = args.begin(); it != args.end(); ++it) { // Arguments in response files might be quoted/escaped, so we need to // unescape them ourselves. - ProcessArgument(Unescape(arg_from_file), consumer); + ProcessArgument(it, Unescape(*it), consumer); } return true; } @@ -161,12 +238,10 @@ bool SwiftRunner::ProcessPossibleResponseFile( bool changed = false; std::string arg_from_file; std::vector new_args; - - while (std::getline(original_file, arg_from_file)) { - changed |= - ProcessArgument(arg_from_file, [&](const std::string &processed_arg) { - new_args.push_back(processed_arg); - }); + for (auto it = args.begin(); it != args.end(); ++it) { + changed |= ProcessArgument(it, *it, [&](const std::string &processed_arg) { + new_args.push_back(processed_arg); + }); } if (changed) { @@ -182,10 +257,11 @@ bool SwiftRunner::ProcessPossibleResponseFile( return changed; } +template bool SwiftRunner::ProcessArgument( - const std::string &arg, std::function consumer) { + Iterator &itr, const std::string &arg, + std::function consumer) { bool changed = false; - if (arg[0] == '@') { changed = ProcessPossibleResponseFile(arg, consumer); } else { @@ -198,8 +274,8 @@ bool SwiftRunner::ProcessArgument( consumer(GetCurrentDirectory() + "=."); changed = true; } else if (new_arg == "-coverage-prefix-pwd-is-dot") { - // Get the actual current working directory (the workspace root), which we - // didn't know at analysis time. + // Get the actual current working directory (the workspace root), which + // we didn't know at analysis time. consumer("-coverage-prefix-map"); consumer(GetCurrentDirectory() + "=."); changed = true; @@ -213,7 +289,8 @@ bool SwiftRunner::ProcessArgument( temp_directories_.push_back(std::move(module_cache_dir)); changed = true; } else if (StripPrefix("-generated-header-rewriter=", new_arg)) { - generated_header_rewriter_path_ = new_arg; + changed = true; + } else if (StripPrefix("-global-index-store-import-path=", new_arg)) { changed = true; } else { // TODO(allevato): Report that an unknown wrapper arg was found and give @@ -221,6 +298,28 @@ bool SwiftRunner::ProcessArgument( changed = true; } } else { + // Process default arguments + if (arg == "-index-store-path") { + consumer("-index-store-path"); + ++itr; + + // If there was a global index store set, pass that to swiftc. + // Otherwise, pass the users. We later copy index data onto the users. + if (global_index_store_import_path_ != "") { + new_arg = global_index_store_import_path_; + } else { + new_arg = index_store_path_; + } + changed = true; + } else if (arg == "-output-file-map") { + // Save the output file map to the value proceeding + // `-output-file-map` + consumer("-output-file-map"); + ++itr; + new_arg = output_file_map_path_; + changed = true; + } + // Apply any other text substitutions needed in the argument (i.e., for // Apple toolchains). // @@ -236,6 +335,36 @@ bool SwiftRunner::ProcessArgument( return changed; } +template +std::vector SwiftRunner::ParseArguments(Iterator itr) { + std::vector out_args; + for (auto it = itr.begin(); it != itr.end(); ++it) { + auto arg = *it; + out_args.push_back(arg); + + if (StripPrefix("-Xwrapped-swift=", arg)) { + if (StripPrefix("-global-index-store-import-path=", arg)) { + global_index_store_import_path_ = arg; + } else if (StripPrefix("-generated-header-rewriter=", arg)) { + generated_header_rewriter_path_ = arg; + } + } else { + if (arg == "-output-file-map") { + ++it; + arg = *it; + output_file_map_path_ = arg; + out_args.push_back(arg); + } else if (arg == "-index-store-path") { + ++it; + arg = *it; + index_store_path_ = arg; + out_args.push_back(arg); + } + } + } + return out_args; +} + std::vector SwiftRunner::ProcessArguments( const std::vector &args) { std::vector new_args; @@ -248,16 +377,19 @@ std::vector SwiftRunner::ProcessArguments( #endif // The tool is assumed to be the first argument. Push it directly. - auto it = args.begin(); + auto parsed_args = ParseArguments(args); + + auto it = parsed_args.begin(); new_args.push_back(*it++); // If we're forcing response files, push the remaining processed args onto a // different vector that we write out below. If not, push them directly onto // the vector being returned. auto &args_destination = force_response_file_ ? response_file_args : new_args; - while (it != args.end()) { - ProcessArgument( - *it, [&](const std::string &arg) { args_destination.push_back(arg); }); + while (it != parsed_args.end()) { + ProcessArgument(it, *it, [&](const std::string &arg) { + args_destination.push_back(arg); + }); ++it; } diff --git a/tools/worker/swift_runner.h b/tools/worker/swift_runner.h index e662b614c..ad5389576 100644 --- a/tools/worker/swift_runner.h +++ b/tools/worker/swift_runner.h @@ -97,9 +97,15 @@ class SwiftRunner { // // This method has file system side effects, creating temporary files and // directories as needed for a particular substitution. - bool ProcessArgument(const std::string &arg, + template + bool ProcessArgument(Iterator &itr, const std::string &arg, std::function consumer); + // Parses arguments to ivars and returns a vector of strings from the iterator. + // This method doesn't actually mutate any of the arguments. + template + std::vector ParseArguments(Iterator itr); + // Applies substitutions to the given command line arguments, returning the // results in a new vector. std::vector ProcessArguments( @@ -128,6 +134,18 @@ class SwiftRunner { // The path to the generated header rewriter tool, if one is being used for // this compilation. std::string generated_header_rewriter_path_; + + // The path of the output map file + std::string output_file_map_path_; + + // The index store path argument passed to the runner + std::string index_store_path_; + + // The path of the global index store when using + // swift.use_global_index_store. When set, this is passed to `swiftc` as the + // `-index-store-path`. After running `swiftc` `index-import` copies relevant + // index outputs into the `index_store_path` to integrate outputs with Bazel. + std::string global_index_store_import_path_; }; #endif // BUILD_BAZEL_RULES_SWIFT_TOOLS_WORKER_SWIFT_RUNNER_H_ From 325b91f79cd208b78aa4dbfaeab2a17e1bf98d46 Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Mon, 7 Jun 2021 08:20:15 -0700 Subject: [PATCH 142/152] Modernize `xcode_swift_toolchain` features and linkopts. This change adds the search path for StoreKitTest/XCTest now available on watchOS in Xcode 12.5, and retires a number of workarounds and/or conditional code paths that are for older versions of Xcode that we don't care about anymore. For example, statically linking the Swift runtime is no longer supported on Darwin with modern versions of Xcode. PiperOrigin-RevId: 377920556 (cherry picked from commit bf5fccc55f83e0583c193c97cbbc7913ac005715) --- swift/internal/xcode_swift_toolchain.bzl | 176 +++++++++-------------- 1 file changed, 67 insertions(+), 109 deletions(-) diff --git a/swift/internal/xcode_swift_toolchain.bzl b/swift/internal/xcode_swift_toolchain.bzl index 44fc95dd9..5b2c97e69 100644 --- a/swift/internal/xcode_swift_toolchain.bzl +++ b/swift/internal/xcode_swift_toolchain.bzl @@ -121,45 +121,59 @@ def _command_line_objc_copts(compilation_mode, objc_fragment): clang_copts = objc_fragment.copts + legacy_copts return [copt for copt in clang_copts if copt != "-g"] -def _platform_developer_framework_dir(apple_toolchain, apple_fragment): +def _platform_developer_framework_dir( + apple_toolchain, + apple_fragment, + xcode_config): """Returns the Developer framework directory for the platform. Args: apple_fragment: The `apple` configuration fragment. apple_toolchain: The `apple_common.apple_toolchain()` object. + xcode_config: The Xcode configuration. Returns: The path to the Developer framework directory for the platform if one exists, otherwise `None`. """ + + # All platforms have a `Developer/Library/Frameworks` directory in their + # platform root, except for watchOS prior to Xcode 12.5. platform_type = apple_fragment.single_arch_platform.platform_type - if platform_type == apple_common.platform_type.watchos: + if ( + platform_type == apple_common.platform_type.watchos and + not _is_xcode_at_least_version(xcode_config, "12.5") + ): return None - # All platforms except watchOS have a `Developer/Library/Frameworks` - # directory in their platform root. return apple_toolchain.platform_developer_framework_dir(apple_fragment) -def _sdk_developer_framework_dir(apple_toolchain, apple_fragment): +def _sdk_developer_framework_dir(apple_toolchain, apple_fragment, xcode_config): """Returns the Developer framework directory for the SDK. Args: apple_fragment: The `apple` configuration fragment. apple_toolchain: The `apple_common.apple_toolchain()` object. + xcode_config: The Xcode configuration. Returns: The path to the Developer framework directory for the SDK if one exists, otherwise `None`. """ + + # All platforms have a `Developer/Library/Frameworks` directory in their SDK + # root except for macOS (all versions of Xcode so far), and watchOS (prior + # to Xcode 12.5). platform_type = apple_fragment.single_arch_platform.platform_type - if platform_type in ( - apple_common.platform_type.macos, - apple_common.platform_type.watchos, + if ( + platform_type == apple_common.platform_type.macos or + ( + platform_type == apple_common.platform_type.watchos and + not _is_xcode_at_least_version(xcode_config, "12.5") + ) ): return None - # All platforms except macOS and watchOS have a - # `Developer/Library/Frameworks` directory in their SDK root. return paths.join(apple_toolchain.sdk_dir(), "Developer/Library/Frameworks") def _default_linker_opts( @@ -193,76 +207,37 @@ def _default_linker_opts( platform_developer_framework_dir = _platform_developer_framework_dir( apple_toolchain, apple_fragment, + xcode_config, ) sdk_developer_framework_dir = _sdk_developer_framework_dir( apple_toolchain, apple_fragment, + xcode_config, ) - linkopts = [] - - uses_runtime_in_os = _is_xcode_at_least_version(xcode_config, "10.2") - if uses_runtime_in_os: - # Starting with Xcode 10.2, Apple forbids statically linking to the - # Swift runtime. The libraries are distributed with the OS and located - # in /usr/lib/swift. - swift_subdir = "swift" - linkopts.append("-Wl,-rpath,/usr/lib/swift") - elif is_static: - # This branch and the branch below now only support Xcode 10.1 and - # below. Eventually, once we drop support for those versions, they can - # be deleted. - swift_subdir = "swift_static" - linkopts.extend([ - "-Wl,-force_load_swift_libs", - "-framework", - "Foundation", - "-lstdc++", - ]) - else: - swift_subdir = "swift" - - swift_lib_dir = ( - "{developer_dir}/Toolchains/{toolchain}.xctoolchain/" + - "usr/lib/{swift_subdir}/{platform}" - ).format( - developer_dir = apple_toolchain.developer_dir(), - platform = platform.name_in_plist.lower(), - swift_subdir = swift_subdir, - toolchain = "XcodeDefault", - ) - - # TODO(b/128303533): It's possible to run Xcode 10.2 on a version of macOS - # 10.14.x that does not yet include `/usr/lib/swift`. Later Xcode 10.2 betas - # have deleted the `swift_static` directory, so we must manually add the - # dylibs to the binary's rpath or those binaries won't be able to run at - # all. This is added after `/usr/lib/swift` above so the system versions - # will always be preferred if they are present. This workaround can be - # removed once Xcode 10.2 and macOS 10.14.4 are out of beta. - if uses_runtime_in_os and platform == apple_common.platform.macos: - linkopts.append("-Wl,-rpath,{}".format(swift_lib_dir)) - - linkopts.extend( - [ - "-F{}".format(path) - for path in compact([ - platform_developer_framework_dir, - sdk_developer_framework_dir, - ]) - ] + [ - "-L{}".format(swift_lib_dir), - # TODO(b/112000244): These should get added by the C++ Starlark API, - # but we're using the "c++-link-executable" action right now instead - # of "objc-executable" because the latter requires additional - # variables not provided by cc_common. Figure out how to handle this - # correctly. - "-ObjC", - "-Wl,-objc_abi_version,2", - ], + swift_lib_dir = paths.join( + apple_toolchain.developer_dir(), + "Toolchains/XcodeDefault.xctoolchain/usr/lib/swift", + platform.name_in_plist.lower(), ) - use_system_swift_libs = _is_xcode_at_least_version(xcode_config, "11.0") - if use_system_swift_libs: - linkopts.append("-L/usr/lib/swift") + linkopts = [ + "-F{}".format(path) + for path in compact([ + platform_developer_framework_dir, + sdk_developer_framework_dir, + ]) + ] + [ + "-Wl,-rpath,/usr/lib/swift", + "-L{}".format(swift_lib_dir), + "-L/usr/lib/swift", + # TODO(b/112000244): These should get added by the C++ Starlark API, + # but we're using the "c++-link-executable" action right now instead + # of "objc-executable" because the latter requires additional + # variables not provided by cc_common. Figure out how to handle this + # correctly. + "-ObjC", + "-Wl,-objc_abi_version,2", + ] # Frameworks in the platform's developer frameworks directory (like XCTest, # but also StoreKitTest on macOS) contain the actual binary for that @@ -335,7 +310,8 @@ def _all_action_configs( apple_toolchain, generated_header_rewriter, needs_resource_directory, - target_triple): + target_triple, + xcode_config): """Returns the action configurations for the Swift toolchain. Args: @@ -352,6 +328,7 @@ def _all_action_configs( needs_resource_directory: If True, the toolchain needs the resource directory passed explicitly to the compiler. target_triple: The target triple. + xcode_config: The Xcode configuration. Returns: The action configurations for the Swift toolchain. @@ -359,10 +336,12 @@ def _all_action_configs( platform_developer_framework_dir = _platform_developer_framework_dir( apple_toolchain, apple_fragment, + xcode_config, ) sdk_developer_framework_dir = _sdk_developer_framework_dir( apple_toolchain, apple_fragment, + xcode_config, ) developer_framework_dirs = compact([ platform_developer_framework_dir, @@ -515,7 +494,6 @@ def _all_tool_configs( generated_header_rewriter, swift_executable, toolchain_root, - use_param_file, xcode_config): """Returns the tool configurations for the Swift toolchain. @@ -530,8 +508,6 @@ def _all_tool_configs( swift_executable: A custom Swift driver executable to be used during the build, if provided. toolchain_root: The root directory of the toolchain, if provided. - use_param_file: If True, actions should have their arguments written to - param files. xcode_config: The `apple_common.XcodeVersionConfig` provider. Returns: @@ -556,7 +532,7 @@ def _all_tool_configs( execution_requirements = execution_requirements, swift_executable = swift_executable, toolchain_root = toolchain_root, - use_param_file = use_param_file, + use_param_file = True, worker_mode = "persistent", ) @@ -574,25 +550,13 @@ def _all_tool_configs( execution_requirements = execution_requirements, swift_executable = swift_executable, toolchain_root = toolchain_root, - use_param_file = use_param_file, + use_param_file = True, worker_mode = "wrap", ) ) return tool_configs -def _is_macos(platform): - """Returns `True` if the given platform is macOS. - - Args: - platform: An `apple_platform` value describing the platform for which a - target is being built. - - Returns: - `True` if the given platform is macOS. - """ - return platform.platform_type == apple_common.platform_type.macos - def _is_xcode_at_least_version(xcode_config, desired_version): """Returns True if we are building with at least the given Xcode version. @@ -708,26 +672,20 @@ def _xcode_swift_toolchain_impl(ctx): cpp_fragment = ctx.fragments.cpp, ) + features_from_swiftcopts(swiftcopts = ctx.fragments.swift.copts()) requested_features.extend(ctx.features) - requested_features.append(SWIFT_FEATURE_BUNDLED_XCTESTS) requested_features.extend( _features_for_bitcode_mode(apple_fragment.bitcode_mode), ) - - # TODO(b/142867898): Added to match existing Bazel Objective-C module map - # behavior; remove it when possible. - requested_features.append(SWIFT_FEATURE_MODULE_MAP_NO_PRIVATE_HEADERS) - - # Xcode 10.0 implies Swift 4.2. - if _is_xcode_at_least_version(xcode_config, "10.0"): - use_param_file = True - requested_features.append(SWIFT_FEATURE_ENABLE_BATCH_MODE) - requested_features.append(SWIFT_FEATURE_USE_RESPONSE_FILES) - else: - use_param_file = False - - # Xcode 10.2 implies Swift 5.0. - if _is_xcode_at_least_version(xcode_config, "10.2"): - requested_features.append(SWIFT_FEATURE_DEBUG_PREFIX_MAP) + requested_features.extend([ + SWIFT_FEATURE_BUNDLED_XCTESTS, + SWIFT_FEATURE_ENABLE_BATCH_MODE, + SWIFT_FEATURE_USE_RESPONSE_FILES, + SWIFT_FEATURE_DEBUG_PREFIX_MAP, + SWIFT_FEATURE_SUPPORTS_LIBRARY_EVOLUTION, + SWIFT_FEATURE_SUPPORTS_PRIVATE_DEPS, + # TODO(b/142867898): Added to match existing Bazel Objective-C module + # map behavior; remove it when possible. + SWIFT_FEATURE_MODULE_MAP_NO_PRIVATE_HEADERS, + ]) # Xcode 11.0 implies Swift 5.1. if _is_xcode_at_least_version(xcode_config, "11.0"): @@ -753,7 +711,6 @@ def _xcode_swift_toolchain_impl(ctx): generated_header_rewriter = generated_header_rewriter, swift_executable = swift_executable, toolchain_root = toolchain_root, - use_param_file = use_param_file, xcode_config = xcode_config, ) all_action_configs = _all_action_configs( @@ -767,6 +724,7 @@ def _xcode_swift_toolchain_impl(ctx): generated_header_rewriter = generated_header_rewriter, needs_resource_directory = swift_executable or toolchain_root, target_triple = target, + xcode_config = xcode_config, ) # Xcode toolchains don't pass any files explicitly here because they're From 1b6b854a280796a3aaba39f7f7c68c0bb4d0bda1 Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Wed, 9 Jun 2021 07:29:51 -0700 Subject: [PATCH 143/152] Remove the `-rpath` for the Xcode's developer frameworks directory from the Swift toolchain. It may have been needed in the past with older versions of Swift, but it doesn't appear to be anymore (and it causes problems if the version targeted during the build is mismatched with the simulator/OS version under which the test is running). PiperOrigin-RevId: 378400910 (cherry picked from commit 92b727ede6af6a09ec4977c4ea5257c3357a5986) --- swift/internal/xcode_swift_toolchain.bzl | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/swift/internal/xcode_swift_toolchain.bzl b/swift/internal/xcode_swift_toolchain.bzl index 5b2c97e69..a6ae7931d 100644 --- a/swift/internal/xcode_swift_toolchain.bzl +++ b/swift/internal/xcode_swift_toolchain.bzl @@ -239,15 +239,10 @@ def _default_linker_opts( "-Wl,-objc_abi_version,2", ] - # Frameworks in the platform's developer frameworks directory (like XCTest, - # but also StoreKitTest on macOS) contain the actual binary for that - # framework, not a .tbd file that says where to find it on simulator/device. - # So, we need to explicitly add that to test binaries' rpaths. We also need - # to add the linker path to the directory containing the dylib with Swift + # Add the linker path to the directory containing the dylib with Swift # extensions for the XCTest module. if is_test and platform_developer_framework_dir: linkopts.extend([ - "-Wl,-rpath,{}".format(platform_developer_framework_dir), "-L{}".format( _swift_developer_lib_dir(platform_developer_framework_dir), ), From 446d8f4a1531357e089795ef597af88d87e9ba9d Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Mon, 7 Jun 2021 15:51:31 -0700 Subject: [PATCH 144/152] Propagate Swift-specific linker flags as an implicit dependency of the toolchain. Apple binaries/bundles will automatically get these linker flags if they have any Swift target in their dependencies; this eliminates the need to pass them separately at the top level. PiperOrigin-RevId: 378024438 (cherry picked from commit 96f0a67223abcff67a41f9d095d4053bdfea5a91) # Conflicts: # swift/internal/providers.bzl # swift/internal/swift_toolchain.bzl # swift/internal/xcode_swift_toolchain.bzl --- doc/providers.md | 7 ++-- swift/internal/providers.bzl | 13 ------ swift/internal/swift_binary_test.bzl | 11 ----- swift/internal/swift_toolchain.bzl | 52 ++++++++++++------------ swift/internal/utils.bzl | 13 ++++-- swift/internal/xcode_swift_toolchain.bzl | 51 +++++++++++++++-------- 6 files changed, 73 insertions(+), 74 deletions(-) diff --git a/doc/providers.md b/doc/providers.md index 32470a279..a3c6ad7cc 100644 --- a/doc/providers.md +++ b/doc/providers.md @@ -63,9 +63,9 @@ Propagates Swift-specific information about a `proto_library`.
 SwiftToolchainInfo(action_configs, all_files, cc_toolchain_info, clang_implicit_deps_providers, cpu,
                    feature_allowlists, generated_header_module_implicit_deps_providers,
-                   implicit_deps_providers, linker_opts_producer, linker_supports_filelist,
-                   object_format, requested_features, root_dir, supports_objc_interop, swift_worker,
-                   system_name, test_configuration, tool_configs, unsupported_features)
+                   implicit_deps_providers, linker_supports_filelist, object_format,
+                   requested_features, root_dir, supports_objc_interop, swift_worker, system_name,
+                   test_configuration, tool_configs, unsupported_features)
 
@@ -86,7 +86,6 @@ that use the toolchain. | feature_allowlists | A list of SwiftFeatureAllowlistInfo providers that allow or prohibit packages from requesting or disabling features. | | generated_header_module_implicit_deps_providers | A struct with the following fields, which are providers from targets that should be treated as compile-time inputs to actions that precompile the explicit module for the generated Objective-C header of a Swift module:

* cc_infos: A list of CcInfo providers from targets specified as the toolchain's implicit dependencies. * objc_infos: A list of apple_common.Objc providers from targets specified as the toolchain's implicit dependencies. * swift_infos: A list of SwiftInfo providers from targets specified as the toolchain's implicit dependencies.

This is used to provide modular dependencies for the fixed inclusions (Darwin, Foundation) that are unconditionally emitted in those files.

For ease of use, this field is never None; it will always be a valid struct containing the fields described above, even if those lists are empty. | | implicit_deps_providers | A struct with the following fields, which represent providers from targets that should be added as implicit dependencies of any Swift compilation or linking target (but not to precompiled explicit C/Objective-C modules):

* cc_infos: A list of CcInfo providers from targets specified as the toolchain's implicit dependencies. * objc_infos: A list of apple_common.Objc providers from targets specified as the toolchain's implicit dependencies. * swift_infos: A list of SwiftInfo providers from targets specified as the toolchain's implicit dependencies.

For ease of use, this field is never None; it will always be a valid struct containing the fields described above, even if those lists are empty. | -| linker_opts_producer | Skylib partial. A partial function that returns the flags that should be passed to Clang to link a binary or test target with the Swift runtime libraries.

The partial should be called with two arguments:

* is_static: A Boolean value indicating whether to link against the static or dynamic runtime libraries.

* is_test: A Boolean value indicating whether the target being linked is a test target. | | linker_supports_filelist | Boolean. Indicates whether or not the toolchain's linker supports the input files passed to it via a file list. | | object_format | String. The object file format of the platform that the toolchain is targeting. The currently supported values are "elf" and "macho". | | requested_features | List of strings. Features that should be implicitly enabled by default for targets built using this toolchain, unless overridden by the user by listing their negation in the features attribute of a target/package or in the --features command line flag.

These features determine various compilation and debugging behaviors of the Swift build rules, and they are also passed to the C++ APIs used when linking (so features defined in CROSSTOOL may be used here). | diff --git a/swift/internal/providers.bzl b/swift/internal/providers.bzl index 990715686..c2a576e8c 100644 --- a/swift/internal/providers.bzl +++ b/swift/internal/providers.bzl @@ -165,19 +165,6 @@ linking target (but not to precompiled explicit C/Objective-C modules): For ease of use, this field is never `None`; it will always be a valid `struct` containing the fields described above, even if those lists are empty. -""", - "linker_opts_producer": """\ -Skylib `partial`. A partial function that returns the flags that should be -passed to Clang to link a binary or test target with the Swift runtime -libraries. - -The partial should be called with two arguments: - -* `is_static`: A `Boolean` value indicating whether to link against the static - or dynamic runtime libraries. - -* `is_test`: A `Boolean` value indicating whether the target being linked is a - test target. """, "linker_supports_filelist": """\ `Boolean`. Indicates whether or not the toolchain's linker supports the input diff --git a/swift/internal/swift_binary_test.bzl b/swift/internal/swift_binary_test.bzl index 0444b7a21..868f9ccad 100644 --- a/swift/internal/swift_binary_test.bzl +++ b/swift/internal/swift_binary_test.bzl @@ -15,7 +15,6 @@ """Implementation of the `swift_binary` and `swift_test` rules.""" load("@bazel_skylib//lib:dicts.bzl", "dicts") -load("@bazel_skylib//lib:partial.bzl", "partial") load(":compiling.bzl", "output_groups_from_compilation_outputs") load(":derived_files.bzl", "derived_files") load(":feature_names.bzl", "SWIFT_FEATURE_BUNDLED_XCTESTS") @@ -209,16 +208,6 @@ def _swift_linking_rule_impl( compilation_outputs = compilation_outputs, ) - # Retrieve any additional linker flags required by the Swift toolchain. - # TODO(b/70228246): Also support mostly-static and fully-dynamic modes, - # here and for the C++ toolchain args below. - toolchain_linker_flags = partial.call( - swift_toolchain.linker_opts_producer, - is_static = True, - is_test = is_test, - ) - user_link_flags.extend(toolchain_linker_flags) - # Collect linking contexts from any of the toolchain's implicit # dependencies. for cc_info in swift_toolchain.implicit_deps_providers.cc_infos: diff --git a/swift/internal/swift_toolchain.bzl b/swift/internal/swift_toolchain.bzl index 3c4a5c29f..67672ca31 100644 --- a/swift/internal/swift_toolchain.bzl +++ b/swift/internal/swift_toolchain.bzl @@ -20,7 +20,6 @@ toolchain, see `swift.bzl`. """ load("@bazel_skylib//lib:dicts.bzl", "dicts") -load("@bazel_skylib//lib:partial.bzl", "partial") load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain") load(":actions.bzl", "swift_action_names") load(":attrs.bzl", "swift_toolchain_driver_attrs") @@ -110,18 +109,17 @@ def _all_action_configs(additional_swiftc_copts): autolink_extract_action_configs() ) -def _default_linker_opts( +def _swift_linkopts_cc_info( cc_toolchain, cpu, os, - toolchain_root, - is_static, - is_test): - """Returns options that should be passed by default to `clang` when linking. + toolchain_label, + toolchain_root): + """Returns a `CcInfo` containing flags that should be passed to the linker. - This function is wrapped in a `partial` that will be propagated as part of - the toolchain provider. The first three arguments are pre-bound; the - `is_static` and `is_test` arguments are expected to be passed by the caller. + The provider returned by this function will be used as an implicit + dependency of the toolchain to ensure that any binary containing Swift code + will link to the standard libraries correctly. Args: cc_toolchain: The cpp toolchain from which the `ld` executable is @@ -129,18 +127,15 @@ def _default_linker_opts( cpu: The CPU architecture, which is used as part of the library path. os: The operating system name, which is used as part of the library path. + toolchain_label: The label of the Swift toolchain that will act as the + owner of the linker input propagating the flags. toolchain_root: The toolchain's root directory. - is_static: `True` to link against the static version of the Swift - runtime, or `False` to link against dynamic/shared libraries. - is_test: `True` if the target being linked is a test target. Returns: - The command line options to pass to `clang` to link against the desired - variant of the Swift runtime libraries. + A `CcInfo` provider that will provide linker flags to binaries that + depend on Swift targets. """ - _ignore = is_test - # TODO(#8): Support statically linking the Swift runtime. platform_lib_dir = "{toolchain_root}/lib/swift/{os}".format( os = os, @@ -161,22 +156,29 @@ def _default_linker_opts( "-lrt", "-ldl", runtime_object_path, + "-static-libgcc", ] - if is_static: - linkopts.append("-static-libgcc") - - return linkopts + return CcInfo( + linking_context = cc_common.create_linking_context( + linker_inputs = depset([ + cc_common.create_linker_input( + owner = toolchain_label, + user_link_flags = depset(linkopts), + ), + ]), + ), + ) def _swift_toolchain_impl(ctx): toolchain_root = ctx.attr.root cc_toolchain = find_cpp_toolchain(ctx) - linker_opts_producer = partial.make( - _default_linker_opts, + swift_linkopts_cc_info = _swift_linkopts_cc_info( cc_toolchain, ctx.attr.arch, ctx.attr.os, + ctx.label, toolchain_root, ) @@ -226,10 +228,10 @@ def _swift_toolchain_impl(ctx): generated_header_module_implicit_deps_providers = ( collect_implicit_deps_providers([]) ), - implicit_deps_providers = ( - collect_implicit_deps_providers([]) + implicit_deps_providers = collect_implicit_deps_providers( + [], + additional_cc_infos = [swift_linkopts_cc_info], ), - linker_opts_producer = linker_opts_producer, linker_supports_filelist = False, object_format = "elf", requested_features = requested_features, diff --git a/swift/internal/utils.bzl b/swift/internal/utils.bzl index 5ff45a774..da5c0c758 100644 --- a/swift/internal/utils.bzl +++ b/swift/internal/utils.bzl @@ -59,7 +59,10 @@ def collect_cc_libraries( return libraries -def collect_implicit_deps_providers(targets): +def collect_implicit_deps_providers( + targets, + additional_cc_infos = [], + additional_objc_infos = []): """Returns a struct with important providers from a list of implicit deps. Note that the relationship between each provider in the list and the target @@ -67,6 +70,10 @@ def collect_implicit_deps_providers(targets): Args: targets: A list (possibly empty) of `Target`s. + additional_cc_infos: A `list` of additional `CcInfo` providers that + should be included in the returned value. + additional_objc_infos: A `list` of additional `apple_common.Objc` + providers that should be included in the returned value. Returns: A `struct` containing three fields: @@ -90,8 +97,8 @@ def collect_implicit_deps_providers(targets): swift_infos.append(target[SwiftInfo]) return struct( - cc_infos = cc_infos, - objc_infos = objc_infos, + cc_infos = cc_infos + additional_cc_infos, + objc_infos = objc_infos + additional_objc_infos, swift_infos = swift_infos, ) diff --git a/swift/internal/xcode_swift_toolchain.bzl b/swift/internal/xcode_swift_toolchain.bzl index a6ae7931d..7573e0334 100644 --- a/swift/internal/xcode_swift_toolchain.bzl +++ b/swift/internal/xcode_swift_toolchain.bzl @@ -176,33 +176,35 @@ def _sdk_developer_framework_dir(apple_toolchain, apple_fragment, xcode_config): return paths.join(apple_toolchain.sdk_dir(), "Developer/Library/Frameworks") -def _default_linker_opts( +def _swift_linkopts_providers( apple_fragment, apple_toolchain, platform, target, - xcode_config, - is_static, - is_test): - """Returns options that should be passed by default to `clang` when linking. + toolchain_label, + xcode_config): + """Returns providers containing flags that should be passed to the linker. - This function is wrapped in a `partial` that will be propagated as part of - the toolchain provider. The first five arguments are pre-bound; the - `is_static` and `is_test` arguments are expected to be passed by the caller. + The providers returned by this function will be used as implicit + dependencies of the toolchain to ensure that any binary containing Swift code + will link to the standard libraries correctly. Args: apple_fragment: The `apple` configuration fragment. apple_toolchain: The `apple_common.apple_toolchain()` object. platform: The `apple_platform` value describing the target platform. target: The target triple. + toolchain_label: The label of the Swift toolchain that will act as the + owner of the linker input propagating the flags. xcode_config: The Xcode configuration. - is_static: `True` to link against the static version of the Swift - runtime, or `False` to link against dynamic/shared libraries. - is_test: `True` if the target being linked is a test target. Returns: - The command line options to pass to `clang` to link against the desired - variant of the Swift runtime libraries. + A `struct` containing the following fields: + + * `cc_info`: A `CcInfo` provider that will provide linker flags to + binaries that depend on Swift targets. + * `objc_info`: An `apple_common.Objc` provider that will provide + linker flags to binaries that depend on Swift targets. """ platform_developer_framework_dir = _platform_developer_framework_dir( apple_toolchain, @@ -241,14 +243,26 @@ def _default_linker_opts( # Add the linker path to the directory containing the dylib with Swift # extensions for the XCTest module. - if is_test and platform_developer_framework_dir: + if platform_developer_framework_dir: linkopts.extend([ "-L{}".format( _swift_developer_lib_dir(platform_developer_framework_dir), ), ]) - return linkopts + return struct( + cc_info = CcInfo( + linking_context = cc_common.create_linking_context( + linker_inputs = depset([ + cc_common.create_linker_input( + owner = toolchain_label, + user_link_flags = depset(linkopts), + ), + ]), + ), + ), + objc_info = apple_common.new_objc_provider(linkopt = depset(linkopts)), + ) def _features_for_bitcode_mode(bitcode_mode): """Gets the list of features to enable for the selected Bitcode mode. @@ -631,12 +645,12 @@ def _xcode_swift_toolchain_impl(ctx): ) target = _swift_apple_target_triple(cpu, platform, target_os_version) - linker_opts_producer = partial.make( - _default_linker_opts, + swift_linkopts_providers = _swift_linkopts_providers( apple_fragment, apple_toolchain, platform, target, + ctx.label, xcode_config, ) @@ -749,8 +763,9 @@ def _xcode_swift_toolchain_impl(ctx): ), implicit_deps_providers = collect_implicit_deps_providers( ctx.attr.implicit_deps, + additional_cc_infos = [swift_linkopts_providers.cc_info], + additional_objc_infos = [swift_linkopts_providers.objc_info], ), - linker_opts_producer = linker_opts_producer, linker_supports_filelist = True, object_format = "macho", requested_features = requested_features, From 13865924b2ff6cca040d464082fdad5df751238c Mon Sep 17 00:00:00 2001 From: Brentley Jones Date: Thu, 10 Jun 2021 09:03:57 -0500 Subject: [PATCH 145/152] Fix worker based error reporting for WMO (#642) --- tools/worker/work_processor.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/worker/work_processor.cc b/tools/worker/work_processor.cc index 2cfb40fbb..32dc74d77 100644 --- a/tools/worker/work_processor.cc +++ b/tools/worker/work_processor.cc @@ -190,7 +190,7 @@ void WorkProcessor::ProcessWorkRequest( } } } - - FinalizeWorkRequest(request, response, exit_code, stderr_stream); } + + FinalizeWorkRequest(request, response, exit_code, stderr_stream); } From ebd617515ec0a994caf3225021a61c35cf624abe Mon Sep 17 00:00:00 2001 From: Jerry Marino Date: Thu, 10 Jun 2021 11:31:24 -0700 Subject: [PATCH 146/152] Fix race condition in MakeDirs (#644) If there are 2 concurrent processes creating the same directories, then it will fail I noticed this on the CI errors of #567, and a co-worker was hitting it today. I suspect invalidating the worker or other updates triggered big rebuilds. I don't know of a perfect repro but, at a 10% rate: invoking Bazel to build 2 swift libraries in the same BUILD file. --- tools/common/file_system.cc | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/tools/common/file_system.cc b/tools/common/file_system.cc index 15b2c274f..081c82750 100644 --- a/tools/common/file_system.cc +++ b/tools/common/file_system.cc @@ -18,7 +18,9 @@ #include #include +#include #include +#include #ifdef __APPLE__ #include @@ -99,7 +101,13 @@ bool MakeDirs(const std::string &path, int mode) { struct stat dir_stats; if (stat(path.c_str(), &dir_stats) == 0) { // Return true if the directory already exists. - return S_ISDIR(dir_stats.st_mode); + if (!S_ISDIR(dir_stats.st_mode)) { + std::cerr << "error: path exists and isn't a directory " + << strerror(errno) << " (" << path.c_str() << ") \n"; + return false; + } else { + return true; + } } // Recurse to create the parent directory. @@ -108,5 +116,29 @@ bool MakeDirs(const std::string &path, int mode) { } // Create the directory that was requested. - return mkdir(path.c_str(), mode) == 0; + int mkdir_ret = mkdir(path.c_str(), mode); + if (mkdir_ret == 0) { + return true; + } + + // Save the mkdir errno for better reporting. + int mkdir_errno = errno; + + // Deal with a race condition when 2 `MakeDirs` are running at the same time: + // one `mkdir` invocation will fail in each recursive call at different + // points. Don't recurse here to avoid an infinite loop in failure cases. + if (errno == EEXIST && stat(path.c_str(), &dir_stats) == 0) { + if (!S_ISDIR(dir_stats.st_mode)) { + std::cerr << "error: path exists and isn't a directory " + << strerror(errno) << " (" << path.c_str() << ") \n"; + return false; + } else { + // Return true if the directory already exists. + return true; + } + } + + std::cerr << "error:" << strerror(mkdir_errno) << " (" << path.c_str() + << ") \n"; + return false; } From 0d0f9132b1a92de91de1031fe9c9f4776e562a3d Mon Sep 17 00:00:00 2001 From: Brentley Jones Date: Thu, 10 Jun 2021 13:48:23 -0500 Subject: [PATCH 147/152] Error out on failed `MakeDir` (#645) Now that we only report failures from `MakeDir` if there is actually an error, we can error out earlier for a better error message. --- tools/worker/work_processor.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/worker/work_processor.cc b/tools/worker/work_processor.cc index 32dc74d77..6e4c8fdb1 100644 --- a/tools/worker/work_processor.cc +++ b/tools/worker/work_processor.cc @@ -129,8 +129,10 @@ void WorkProcessor::ProcessWorkRequest( // incremental storage area. auto dir_path = Dirname(expected_object_pair.second); if (!MakeDirs(dir_path, S_IRWXU)) { - std::cerr << "Could not create directory " << dir_path << " (errno " - << errno << ")\n"; + stderr_stream << "swift_worker: Could not create directory " << dir_path + << " (errno " << errno << ")\n"; + FinalizeWorkRequest(request, response, EXIT_FAILURE, stderr_stream); + return; } } From 7e284a9b8d622ada3a747f5e4f607b6f4a9d1402 Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Thu, 10 Jun 2021 09:57:16 -0700 Subject: [PATCH 148/152] Delete the `swift_common.swift_runtime_linkopts` function. This should have been deleted in the previous change that refactored the linker flags. It no longer works because it tries to access a provide field that no longer exists, but nothing broke because nothing calls it anymore. Yay weak typing. PiperOrigin-RevId: 378673728 (cherry picked from commit 503c9cc8c116599c217ba0c6743998fbfa865f4b) --- doc/api.md | 30 ------------------------------ swift/internal/linking.bzl | 27 --------------------------- swift/internal/swift_common.bzl | 2 -- 3 files changed, 59 deletions(-) diff --git a/doc/api.md b/doc/api.md index 9922e501a..7cfdff859 100644 --- a/doc/api.md +++ b/doc/api.md @@ -502,36 +502,6 @@ A `File` representing the precompiled module (`.pcm`) file, or `None` if the toolchain or target does not support precompiled modules. - - -## swift_common.swift_runtime_linkopts - -
-swift_common.swift_runtime_linkopts(is_static, toolchain, is_test)
-
- -Returns the flags that should be passed when linking a Swift binary. - -This function provides the appropriate linker arguments to callers who need -to link a binary using something other than `swift_binary` (for example, an -application bundle containing a universal `apple_binary`). - - -**PARAMETERS** - - -| Name | Description | Default Value | -| :------------- | :------------- | :------------- | -| is_static | A Boolean value indicating whether the binary should be linked against the static (rather than the dynamic) Swift runtime libraries. | none | -| toolchain | The SwiftToolchainInfo provider of the toolchain whose linker options are desired. | none | -| is_test | A Boolean value indicating whether the target being linked is a test target. | False | - -**RETURNS** - -A `list` of command line flags that should be passed when linking a - binary against the Swift runtime libraries. - - ## swift_common.toolchain_attrs diff --git a/swift/internal/linking.bzl b/swift/internal/linking.bzl index 7520bfcca..08699878a 100644 --- a/swift/internal/linking.bzl +++ b/swift/internal/linking.bzl @@ -15,7 +15,6 @@ """Implementation of linking logic for Swift.""" load("@bazel_skylib//lib:collections.bzl", "collections") -load("@bazel_skylib//lib:partial.bzl", "partial") load( "@bazel_tools//tools/build_defs/cc:action_names.bzl", "CPP_LINK_STATIC_LIBRARY_ACTION_NAME", @@ -287,29 +286,3 @@ def register_link_binary_action( output_type = output_type, stamp = stamp, ) - -def swift_runtime_linkopts(is_static, toolchain, is_test = False): - """Returns the flags that should be passed when linking a Swift binary. - - This function provides the appropriate linker arguments to callers who need - to link a binary using something other than `swift_binary` (for example, an - application bundle containing a universal `apple_binary`). - - Args: - is_static: A `Boolean` value indicating whether the binary should be - linked against the static (rather than the dynamic) Swift runtime - libraries. - toolchain: The `SwiftToolchainInfo` provider of the toolchain whose - linker options are desired. - is_test: A `Boolean` value indicating whether the target being linked is - a test target. - - Returns: - A `list` of command line flags that should be passed when linking a - binary against the Swift runtime libraries. - """ - return partial.call( - toolchain.linker_opts_producer, - is_static = is_static, - is_test = is_test, - ) diff --git a/swift/internal/swift_common.bzl b/swift/internal/swift_common.bzl index 6c32f89ae..985103abc 100644 --- a/swift/internal/swift_common.bzl +++ b/swift/internal/swift_common.bzl @@ -41,7 +41,6 @@ load( "get_cc_feature_configuration", "is_feature_enabled", ) -load(":linking.bzl", "swift_runtime_linkopts") load( ":providers.bzl", "create_clang_module", @@ -67,6 +66,5 @@ swift_common = struct( is_enabled = is_feature_enabled, library_rule_attrs = swift_library_rule_attrs, precompile_clang_module = precompile_clang_module, - swift_runtime_linkopts = swift_runtime_linkopts, toolchain_attrs = swift_toolchain_attrs, ) From 1946db6cd8a99a4774fefcbf02a6f1e873faadc9 Mon Sep 17 00:00:00 2001 From: Samuel Giddins Date: Thu, 10 Jun 2021 16:35:30 -0700 Subject: [PATCH 149/152] Refer to build_bazel_rules_swift_index_import via a file rather than inline string (#647) For consistency with other repos that do not define their own build files --- swift/repositories.bzl | 11 +---------- .../BUILD.overlay | 9 +++++++++ 2 files changed, 10 insertions(+), 10 deletions(-) create mode 100644 third_party/build_bazel_rules_swift_index_import/BUILD.overlay diff --git a/swift/repositories.bzl b/swift/repositories.bzl index c27e0c466..14c7634b9 100644 --- a/swift/repositories.bzl +++ b/swift/repositories.bzl @@ -114,16 +114,7 @@ def swift_rules_dependencies(): _maybe( http_archive, name = "build_bazel_rules_swift_index_import", - build_file_content = """\ -load("@bazel_skylib//rules:native_binary.bzl", "native_binary") - -native_binary( - name = "index_import", - src = "index-import", - out = "index-import", - visibility = ["//visibility:public"], -) -""", + build_file = "@build_bazel_rules_swift//third_party/build_bazel_rules_swift_index_import/BUILD.overlay", canonical_id = "index-import-5.3.2.6", urls = ["https://github.com/MobileNativeFoundation/index-import/releases/download/5.3.2.6/index-import.zip"], sha256 = "61a58363f56c5fd84d4ebebe0d9b5dd90c74ae170405a7b9018e8cf698e679de", diff --git a/third_party/build_bazel_rules_swift_index_import/BUILD.overlay b/third_party/build_bazel_rules_swift_index_import/BUILD.overlay new file mode 100644 index 000000000..13d2855a7 --- /dev/null +++ b/third_party/build_bazel_rules_swift_index_import/BUILD.overlay @@ -0,0 +1,9 @@ +load("@bazel_skylib//rules:native_binary.bzl", "native_binary") + +package(default_visibility = ["//visibility:public"]) + +native_binary( + name = "index_import", + src = "index-import", + out = "index-import", +) From b630afe36fa1930ba78e1001c4cb7c2b99cf1a33 Mon Sep 17 00:00:00 2001 From: Samuel Giddins Date: Fri, 11 Jun 2021 10:34:49 -0700 Subject: [PATCH 150/152] Add files in third_party to :for_bazel_tests (#648) So they are copied over in integration tests in rules_apple --- BUILD | 1 + third_party/BUILD | 11 +++++++++++ third_party/bazel_protos/BUILD | 10 ++++++++++ 3 files changed, 22 insertions(+) diff --git a/BUILD b/BUILD index 1f684e0fc..fa55c907f 100644 --- a/BUILD +++ b/BUILD @@ -11,6 +11,7 @@ filegroup( srcs = [ "WORKSPACE", "//swift:for_bazel_tests", + "//third_party:for_bazel_tests", "//tools:for_bazel_tests", ], ) diff --git a/third_party/BUILD b/third_party/BUILD index e69de29bb..cd09ba89b 100644 --- a/third_party/BUILD +++ b/third_party/BUILD @@ -0,0 +1,11 @@ +# Consumed by Bazel integration tests. +filegroup( + name = "for_bazel_tests", + testonly = 1, + srcs = glob(["**"]) + [ + "//third_party/bazel_protos:for_bazel_tests", + ], + visibility = [ + "//:__pkg__", + ], +) diff --git a/third_party/bazel_protos/BUILD b/third_party/bazel_protos/BUILD index 3fb0a2c80..553d41bc6 100644 --- a/third_party/bazel_protos/BUILD +++ b/third_party/bazel_protos/BUILD @@ -13,3 +13,13 @@ cc_proto_library( visibility = ["//tools/worker:__pkg__"], deps = [":worker_protocol_proto"], ) + +# Consumed by Bazel integration tests. +filegroup( + name = "for_bazel_tests", + testonly = 1, + srcs = glob(["**"]), + visibility = [ + "//third_party:__pkg__", + ], +) From 334b6fdcd78c3911fe4227c3bc024f1bc1d261ee Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Fri, 11 Jun 2021 11:35:12 -0700 Subject: [PATCH 151/152] Fix index_import label Not sure why this works sometimes and not others but we need to terminate this where the BUILD file lives --- swift/repositories.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swift/repositories.bzl b/swift/repositories.bzl index 14c7634b9..562e79eb2 100644 --- a/swift/repositories.bzl +++ b/swift/repositories.bzl @@ -114,7 +114,7 @@ def swift_rules_dependencies(): _maybe( http_archive, name = "build_bazel_rules_swift_index_import", - build_file = "@build_bazel_rules_swift//third_party/build_bazel_rules_swift_index_import/BUILD.overlay", + build_file = "@build_bazel_rules_swift//third_party:build_bazel_rules_swift_index_import/BUILD.overlay", canonical_id = "index-import-5.3.2.6", urls = ["https://github.com/MobileNativeFoundation/index-import/releases/download/5.3.2.6/index-import.zip"], sha256 = "61a58363f56c5fd84d4ebebe0d9b5dd90c74ae170405a7b9018e8cf698e679de", From 8dd2c9408d133f0d69f91c357e8f135f04a00043 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Fri, 11 Jun 2021 11:50:42 -0700 Subject: [PATCH 152/152] Update apple_support to 0.11.0 --- swift/repositories.bzl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/swift/repositories.bzl b/swift/repositories.bzl index 562e79eb2..bbc01d868 100644 --- a/swift/repositories.bzl +++ b/swift/repositories.bzl @@ -51,9 +51,9 @@ def swift_rules_dependencies(): http_archive, name = "build_bazel_apple_support", urls = [ - "https://github.com/bazelbuild/apple_support/releases/download/0.10.0/apple_support.0.10.0.tar.gz", + "https://github.com/bazelbuild/apple_support/releases/download/0.11.0/apple_support.0.11.0.tar.gz", ], - sha256 = "741366f79d900c11e11d8efd6cc6c66a31bfb2451178b58e0b5edc6f1db17b35", + sha256 = "76df040ade90836ff5543888d64616e7ba6c3a7b33b916aa3a4b68f342d1b447", ) _maybe(