From ceb3e226542aaffc51c2e3b890462774990641a7 Mon Sep 17 00:00:00 2001 From: Cody Vandermyn Date: Mon, 3 Nov 2025 08:30:04 -0800 Subject: [PATCH 1/7] Add support for aws-crt-swift and complex C dependencies - Add umbrella directory modulemap generation to match SPM behavior - Add framework detection: scan C source files for framework imports and auto-link - Add default include/ path handling when publicHeadersPath is not specified - Add header collection from excluded directories (SPM excludes only affect compilation) - Add aws_crt_example demonstrating aws-crt-swift building successfully Fixes enable building Swift packages with complex C dependencies that have: - Inline implementation files (.inl) that should be conditionally included - Default public header paths (include/) - Excluded directories containing needed headers - System framework dependencies not declared in Package.swift The umbrella directory approach prevents atomics redefinition errors by only processing headers when explicitly included, rather than importing all headers upfront when listed individually in the modulemap. --- examples/aws_crt_example/.bazelrc | 4 + examples/aws_crt_example/BUILD.bazel | 9 +++ examples/aws_crt_example/MODULE.bazel | 36 +++++++++ examples/aws_crt_example/Package.resolved | 23 ++++++ examples/aws_crt_example/Package.swift | 10 +++ examples/aws_crt_example/README.md | 3 + .../Tests/AwsCrtTests/AwsCrtTests.swift | 10 +++ examples/aws_crt_example/WORKSPACE | 1 + examples/aws_crt_example/WORKSPACE.bzlmod | 1 + examples/aws_crt_example/do_test | 5 ++ swiftpkg/internal/generate_modulemap.bzl | 22 +++++- swiftpkg/internal/module_maps.bzl | 7 ++ swiftpkg/internal/pkginfos.bzl | 74 ++++++++++++++++++- swiftpkg/internal/swiftpkg_build_files.bzl | 13 ++++ 14 files changed, 216 insertions(+), 2 deletions(-) create mode 100644 examples/aws_crt_example/.bazelrc create mode 100644 examples/aws_crt_example/BUILD.bazel create mode 100644 examples/aws_crt_example/MODULE.bazel create mode 100644 examples/aws_crt_example/Package.resolved create mode 100644 examples/aws_crt_example/Package.swift create mode 100644 examples/aws_crt_example/README.md create mode 100644 examples/aws_crt_example/Tests/AwsCrtTests/AwsCrtTests.swift create mode 100644 examples/aws_crt_example/WORKSPACE create mode 100644 examples/aws_crt_example/WORKSPACE.bzlmod create mode 100755 examples/aws_crt_example/do_test diff --git a/examples/aws_crt_example/.bazelrc b/examples/aws_crt_example/.bazelrc new file mode 100644 index 000000000..0820c757d --- /dev/null +++ b/examples/aws_crt_example/.bazelrc @@ -0,0 +1,4 @@ +build --enable_bzlmod +build --lockfile_mode=update +build --macos_minimum_os=15.0 +build --host_macos_minimum_os=15.0 diff --git a/examples/aws_crt_example/BUILD.bazel b/examples/aws_crt_example/BUILD.bazel new file mode 100644 index 000000000..cced3a540 --- /dev/null +++ b/examples/aws_crt_example/BUILD.bazel @@ -0,0 +1,9 @@ +load("@build_bazel_rules_swift//swift:swift_test.bzl", "swift_test") + +swift_test( + name = "AwsCrtTests", + srcs = ["Tests/AwsCrtTests/AwsCrtTests.swift"], + deps = [ + "@swiftpkg_aws_crt_swift//:AwsCommonRuntimeKit", + ], +) diff --git a/examples/aws_crt_example/MODULE.bazel b/examples/aws_crt_example/MODULE.bazel new file mode 100644 index 000000000..66bed05ab --- /dev/null +++ b/examples/aws_crt_example/MODULE.bazel @@ -0,0 +1,36 @@ +module(name = "aws_crt_example") + +bazel_dep(name = "rules_swift_package_manager", version = "") +local_path_override( + module_name = "rules_swift_package_manager", + path = "../..", +) + +bazel_dep(name = "apple_support", version = "1.24.2") +bazel_dep(name = "rules_swift", version = "3.1.2", repo_name = "build_bazel_rules_swift") +bazel_dep(name = "rules_apple", version = "4.2.0", repo_name = "build_bazel_rules_apple") + +apple_cc_configure = use_extension( + "@apple_support//crosstool:setup.bzl", + "apple_cc_configure_extension", +) +use_repo(apple_cc_configure, "local_config_apple_cc") + +swift_deps = use_extension( + "@rules_swift_package_manager//:extensions.bzl", + "swift_deps", +) +swift_deps.from_package( + resolved = "//:Package.resolved", + swift = "//:Package.swift", +) +swift_deps.configure_package( + name = "aws-crt-swift", + init_submodules = True, + recursive_init_submodules = True, +) +use_repo( + swift_deps, + "swift_package", + "swiftpkg_aws_crt_swift", +) diff --git a/examples/aws_crt_example/Package.resolved b/examples/aws_crt_example/Package.resolved new file mode 100644 index 000000000..feeb37908 --- /dev/null +++ b/examples/aws_crt_example/Package.resolved @@ -0,0 +1,23 @@ +{ + "pins" : [ + { + "identity" : "aws-crt-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/awslabs/aws-crt-swift.git", + "state" : { + "revision" : "2f4f02595a25a43f9ca9acdc9f4d4a8ff6e5d3ac", + "version" : "0.54.0" + } + }, + { + "identity" : "swift-argument-parser", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-argument-parser.git", + "state" : { + "revision" : "cdd0ef3755280949551dc26dee5de9ddeda89f54", + "version" : "1.6.2" + } + } + ], + "version" : 2 +} diff --git a/examples/aws_crt_example/Package.swift b/examples/aws_crt_example/Package.swift new file mode 100644 index 000000000..2c9d24407 --- /dev/null +++ b/examples/aws_crt_example/Package.swift @@ -0,0 +1,10 @@ +// swift-tools-version: 5.9 + +import PackageDescription + +let package = Package( + name: "AwsCrtExample", + dependencies: [ + .package(url: "https://github.com/awslabs/aws-crt-swift.git", from: "0.54.0"), + ] +) diff --git a/examples/aws_crt_example/README.md b/examples/aws_crt_example/README.md new file mode 100644 index 000000000..455e5ffa2 --- /dev/null +++ b/examples/aws_crt_example/README.md @@ -0,0 +1,3 @@ +# AWS CRT Swift Example + +This example demonstrates using [aws-crt-swift](https://github.com/awslabs/aws-crt-swift) with Bazel. diff --git a/examples/aws_crt_example/Tests/AwsCrtTests/AwsCrtTests.swift b/examples/aws_crt_example/Tests/AwsCrtTests/AwsCrtTests.swift new file mode 100644 index 000000000..2128ffd57 --- /dev/null +++ b/examples/aws_crt_example/Tests/AwsCrtTests/AwsCrtTests.swift @@ -0,0 +1,10 @@ +import XCTest +import AwsCommonRuntimeKit + +final class AwsCrtTests: XCTestCase { + func testCrtTypes() throws { + // Test that we can use types from AwsCommonRuntimeKit + let logLevel = LogLevel.info + XCTAssertEqual(logLevel, LogLevel.info) + } +} diff --git a/examples/aws_crt_example/WORKSPACE b/examples/aws_crt_example/WORKSPACE new file mode 100644 index 000000000..6f47a752b --- /dev/null +++ b/examples/aws_crt_example/WORKSPACE @@ -0,0 +1 @@ +# Intentionally blank. Using bzlmod. diff --git a/examples/aws_crt_example/WORKSPACE.bzlmod b/examples/aws_crt_example/WORKSPACE.bzlmod new file mode 100644 index 000000000..4b83dbf2b --- /dev/null +++ b/examples/aws_crt_example/WORKSPACE.bzlmod @@ -0,0 +1 @@ +# Intentionally blank. The content for this workspace is generated by bzlmod. diff --git a/examples/aws_crt_example/do_test b/examples/aws_crt_example/do_test new file mode 100755 index 000000000..c6883a53c --- /dev/null +++ b/examples/aws_crt_example/do_test @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -euo pipefail + +bazel test //... diff --git a/swiftpkg/internal/generate_modulemap.bzl b/swiftpkg/internal/generate_modulemap.bzl index b9669e836..6dac16e36 100644 --- a/swiftpkg/internal/generate_modulemap.bzl +++ b/swiftpkg/internal/generate_modulemap.bzl @@ -38,12 +38,32 @@ def _generate_modulemap_impl(ctx): if len(hdrs) == 0: fail("No header files were provided.") + # Use umbrella directory if all headers share a common root + umbrella_dir = None + if len(hdrs) > 0: + # Find the longest common directory prefix + dirs = [h.dirname for h in hdrs] + if len(dirs) > 0: + common_parts = dirs[0].split("/") + for d in dirs[1:]: + d_parts = d.split("/") + new_common = [] + for i in range(min(len(common_parts), len(d_parts))): + if common_parts[i] == d_parts[i]: + new_common.append(common_parts[i]) + else: + break + common_parts = new_common + if len(common_parts) > 0: + umbrella_dir = "/".join(common_parts) + write_module_map( actions = ctx.actions, module_map_file = modulemap_file, module_name = module_name, dependent_module_names = uses, - public_headers = hdrs, + umbrella_directory = umbrella_dir, + public_headers = hdrs if not umbrella_dir else [], ) provider_hdr = [modulemap_file] diff --git a/swiftpkg/internal/module_maps.bzl b/swiftpkg/internal/module_maps.bzl index fe7088fca..04b4b2c41 100644 --- a/swiftpkg/internal/module_maps.bzl +++ b/swiftpkg/internal/module_maps.bzl @@ -32,6 +32,7 @@ def write_module_map( private_headers = [], private_textual_headers = [], umbrella_header = None, + umbrella_directory = None, workspace_relative = False): """Writes the content of the module map to a file. @@ -60,6 +61,8 @@ def write_module_map( umbrella_header: A `File` representing an umbrella header that, if present, will be written into the module map instead of the list of headers in the compilation context. + umbrella_directory: A path string representing an umbrella directory that, if + present, will be written into the module map instead of individual headers. workspace_relative: A Boolean value indicating whether the header paths written in the module map file should be relative to the workspace or relative to the module map file. @@ -105,6 +108,10 @@ def write_module_map( if umbrella_header: _add_headers(headers = [umbrella_header], kind = "umbrella header") + elif umbrella_directory: + # Umbrella directory must be absolute path + abs_umbrella = back_to_root_path + umbrella_directory if back_to_root_path else umbrella_directory + content.add(abs_umbrella, format = ' umbrella "%s"') else: _add_headers(headers = public_headers, kind = "header") _add_headers(headers = private_headers, kind = "private header") diff --git a/swiftpkg/internal/pkginfos.bzl b/swiftpkg/internal/pkginfos.bzl index 3ea8b3e12..fe7571721 100644 --- a/swiftpkg/internal/pkginfos.bzl +++ b/swiftpkg/internal/pkginfos.bzl @@ -11,6 +11,7 @@ load( "//config_settings/spm/platform:platforms.bzl", spm_platforms = "platforms", ) +load(":apple_builtin.bzl", "apple_builtin") load(":clang_files.bzl", "clang_files") load(":objc_files.bzl", "objc_files") load(":pkginfo_dependencies.bzl", "pkginfo_dependencies") @@ -1173,6 +1174,38 @@ def _new_swift_src_info( # MARK: - Clang Source Info +def _detect_frameworks_from_sources(repository_ctx, srcs): + """Detect Apple frameworks from #include patterns in C source files.""" + frameworks_set = sets.make() + + for src in srcs: + # Only scan C/C++/ObjC source and header files + if not (src.endswith(".c") or src.endswith(".cc") or src.endswith(".cpp") or + src.endswith(".m") or src.endswith(".mm") or src.endswith(".h") or + src.endswith(".hpp")): + continue + + # Read the file and look for framework includes + content = repository_ctx.read(src) + lines = content.split("\n") + for line in lines: + line = line.strip() + # Look for #include or #import + if line.startswith("#include") or line.startswith("#import"): + # Extract the include path + if "<" in line and ">" in line: + start = line.index("<") + 1 + end = line.index(">") + include_path = line[start:end] + # Check if it's a framework include (has a slash) + if "/" in include_path: + framework = include_path.split("/")[0] + # Check if it's a known Apple framework + if sets.contains(apple_builtin.frameworks.all, framework): + sets.insert(frameworks_set, framework) + + return sorted(sets.to_list(frameworks_set)) + def _new_clang_src_info_from_sources( repository_ctx, pkg_path, @@ -1188,6 +1221,20 @@ def _new_clang_src_info_from_sources( paths.join(pkg_path, target_path), ) + # If no explicit public headers path is specified, default to "include" + # if it exists. This matches Swift Package Manager's behavior for C targets. + # Also remove any exclude patterns that would exclude the include directory, + # since SPM doesn't exclude public headers even if they're in the exclude list. + if public_hdrs_path == None: + default_include_path = paths.normalize(paths.join(abs_target_path, "include")) + if repository_files.is_directory(repository_ctx, default_include_path): + public_hdrs_path = "include" + # Remove any exclude paths that start with "include/" + exclude_paths = [ + ep for ep in exclude_paths + if not ep.startswith("include/") and ep != "include" + ] + public_includes = [] if public_hdrs_path != None: public_includes.append( @@ -1234,6 +1281,25 @@ def _new_clang_src_info_from_sources( exclude_paths = abs_exclude_paths, )) + # SPM's exclude list only excludes files from being compiled as sources, + # but headers in excluded directories are still available for inclusion. + # We need to find all header files in excluded directories and add them + # to all_srcs so they can be discovered and added to the BUILD file. + for ep in exclude_paths: + abs_exclude_path = paths.normalize(paths.join(abs_target_path, ep)) + if repository_files.is_directory(repository_ctx, abs_exclude_path): + # Get all files in the excluded directory + excluded_files = repository_files.list_files_under( + repository_ctx, + abs_exclude_path, + exclude_paths = [], + ) + # Filter to only header files + for f in excluded_files: + _, ext = paths.split_extension(f) + if ext in [".h", ".hpp", ".hh", ".hxx", ".inc", ".inl", ".modulemap"]: + all_srcs.append(f) + # Organize the source files # Be sure that the all_srcs and the public_includes that are passed to # `collect_files` are all absolute paths. The relative_to option will @@ -1304,6 +1370,9 @@ def _new_clang_src_info_from_sources( # GH1290: Can I remove explicit_srcs? I believe that it is obsolete. + # Detect Apple frameworks used by C source files + frameworks = _detect_frameworks_from_sources(repository_ctx, all_srcs) + return _new_clang_src_info( srcs = srcs, explicit_srcs = explicit_srcs, @@ -1312,6 +1381,7 @@ def _new_clang_src_info_from_sources( public_includes = public_includes, private_includes = private_includes, modulemap_path = organized_files.modulemap, + frameworks = frameworks, ) def _new_clang_src_info( @@ -1321,7 +1391,8 @@ def _new_clang_src_info( textual_hdrs = [], public_includes = [], private_includes = [], - modulemap_path = None): + modulemap_path = None, + frameworks = []): return struct( organized_srcs = clang_files.organize_srcs(srcs), explicit_srcs = explicit_srcs, @@ -1330,6 +1401,7 @@ def _new_clang_src_info( public_includes = public_includes, private_includes = private_includes, modulemap_path = modulemap_path, + frameworks = frameworks, ) # MARK: - Objc Source Info diff --git a/swiftpkg/internal/swiftpkg_build_files.bzl b/swiftpkg/internal/swiftpkg_build_files.bzl index 735ec2e91..2a2b5b567 100644 --- a/swiftpkg/internal/swiftpkg_build_files.bzl +++ b/swiftpkg/internal/swiftpkg_build_files.bzl @@ -395,6 +395,19 @@ def _clang_target_build_file(repository_ctx, pkg_ctx, target): for bs in target.linker_settings.linked_frameworks ])) + # Add frameworks detected from source files as linkopts + # cc_library doesn't support sdk_frameworks, so we use -framework flags + if clang_src_info.frameworks: + for framework in clang_src_info.frameworks: + platform_conditions = bazel_apple_platforms.for_framework(framework) + for pc in platform_conditions: + linkopts.append( + bzl_selects.new( + value = "-framework {}".format(framework), + condition = pc, + ), + ) + # Assemble attributes attrs = { From 63f0fa60682042799733773646043ba19f6b3563 Mon Sep 17 00:00:00 2001 From: Cody Vandermyn Date: Mon, 3 Nov 2025 11:27:38 -0800 Subject: [PATCH 2/7] Add aws_sdk_example demonstrating full AWS SDK Swift support This example builds and runs successfully, demonstrating that all the fixes for complex C dependencies work with aws-sdk-swift, which transitively depends on aws-crt-swift and its complex C library dependencies. --- examples/aws_sdk_example/.bazelrc | 4 + examples/aws_sdk_example/BUILD.bazel | 9 + examples/aws_sdk_example/MODULE.bazel | 22 ++ examples/aws_sdk_example/Package.resolved | 257 ++++++++++++++++++ examples/aws_sdk_example/Package.swift | 10 + examples/aws_sdk_example/README.md | 29 ++ .../Sources/AwsSdkExample/main.swift | 11 + examples/aws_sdk_example/WORKSPACE | 0 examples/aws_sdk_example/WORKSPACE.bzlmod | 0 9 files changed, 342 insertions(+) create mode 100644 examples/aws_sdk_example/.bazelrc create mode 100644 examples/aws_sdk_example/BUILD.bazel create mode 100644 examples/aws_sdk_example/MODULE.bazel create mode 100644 examples/aws_sdk_example/Package.resolved create mode 100644 examples/aws_sdk_example/Package.swift create mode 100644 examples/aws_sdk_example/README.md create mode 100644 examples/aws_sdk_example/Sources/AwsSdkExample/main.swift create mode 100644 examples/aws_sdk_example/WORKSPACE create mode 100644 examples/aws_sdk_example/WORKSPACE.bzlmod diff --git a/examples/aws_sdk_example/.bazelrc b/examples/aws_sdk_example/.bazelrc new file mode 100644 index 000000000..0820c757d --- /dev/null +++ b/examples/aws_sdk_example/.bazelrc @@ -0,0 +1,4 @@ +build --enable_bzlmod +build --lockfile_mode=update +build --macos_minimum_os=15.0 +build --host_macos_minimum_os=15.0 diff --git a/examples/aws_sdk_example/BUILD.bazel b/examples/aws_sdk_example/BUILD.bazel new file mode 100644 index 000000000..44fc218e8 --- /dev/null +++ b/examples/aws_sdk_example/BUILD.bazel @@ -0,0 +1,9 @@ +load("@rules_swift//swift:swift_binary.bzl", "swift_binary") + +swift_binary( + name = "AwsSdkExample", + srcs = ["Sources/AwsSdkExample/main.swift"], + deps = [ + "@swiftpkg_aws_sdk_swift//:AWSS3", + ], +) diff --git a/examples/aws_sdk_example/MODULE.bazel b/examples/aws_sdk_example/MODULE.bazel new file mode 100644 index 000000000..cf7ba9800 --- /dev/null +++ b/examples/aws_sdk_example/MODULE.bazel @@ -0,0 +1,22 @@ +module(name = "aws_sdk_example") + +bazel_dep(name = "rules_swift_package_manager", version = "1.10.0") +local_path_override( + module_name = "rules_swift_package_manager", + path = "../..", +) + +bazel_dep(name = "rules_swift", version = "2.3.0") + +swift_deps = use_extension( + "@rules_swift_package_manager//:extensions.bzl", + "swift_deps", +) +swift_deps.from_package( + resolved = "//:Package.resolved", + swift = "//:Package.swift", +) +use_repo( + swift_deps, + "swiftpkg_aws_sdk_swift", +) diff --git a/examples/aws_sdk_example/Package.resolved b/examples/aws_sdk_example/Package.resolved new file mode 100644 index 000000000..a5c4c11f9 --- /dev/null +++ b/examples/aws_sdk_example/Package.resolved @@ -0,0 +1,257 @@ +{ + "pins" : [ + { + "identity" : "aws-crt-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/awslabs/aws-crt-swift", + "state" : { + "revision" : "2f4f02595a25a43f9ca9acdc9f4d4a8ff6e5d3ac", + "version" : "0.54.0" + } + }, + { + "identity" : "aws-sdk-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/awslabs/aws-sdk-swift", + "state" : { + "revision" : "c1eef6225b0ee29a1c0494e1b5691bd51e0ca571", + "version" : "1.5.75" + } + }, + { + "identity" : "grpc-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/grpc/grpc-swift.git", + "state" : { + "revision" : "a56a157218877ef3e9625f7e1f7b2cb7e46ead1b", + "version" : "1.26.1" + } + }, + { + "identity" : "opentelemetry-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/open-telemetry/opentelemetry-swift", + "state" : { + "revision" : "ef63c346d05f4fa7c9ca883f92631fd139eb2cfe", + "version" : "1.17.1" + } + }, + { + "identity" : "opentracing-objc", + "kind" : "remoteSourceControl", + "location" : "https://github.com/undefinedlabs/opentracing-objc", + "state" : { + "revision" : "18c1a35ca966236cee0c5a714a51a73ff33384c1", + "version" : "0.5.2" + } + }, + { + "identity" : "smithy-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/smithy-lang/smithy-swift", + "state" : { + "revision" : "825beae9be4a2518f457a4930d8969dc598d8c0c", + "version" : "0.168.0" + } + }, + { + "identity" : "swift-algorithms", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-algorithms.git", + "state" : { + "revision" : "87e50f483c54e6efd60e885f7f5aa946cee68023", + "version" : "1.2.1" + } + }, + { + "identity" : "swift-argument-parser", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-argument-parser.git", + "state" : { + "revision" : "cdd0ef3755280949551dc26dee5de9ddeda89f54", + "version" : "1.6.2" + } + }, + { + "identity" : "swift-asn1", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-asn1.git", + "state" : { + "revision" : "40d25bbb2fc5b557a9aa8512210bded327c0f60d", + "version" : "1.5.0" + } + }, + { + "identity" : "swift-async-algorithms", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-async-algorithms.git", + "state" : { + "revision" : "042e1c4d9d19748c9c228f8d4ebc97bb1e339b0b", + "version" : "1.0.4" + } + }, + { + "identity" : "swift-atomics", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-atomics.git", + "state" : { + "revision" : "b601256eab081c0f92f059e12818ac1d4f178ff7", + "version" : "1.3.0" + } + }, + { + "identity" : "swift-certificates", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-certificates.git", + "state" : { + "revision" : "c399f90e7bbe8874f6cbfda1d5f9023d1f5ce122", + "version" : "1.15.1" + } + }, + { + "identity" : "swift-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-collections.git", + "state" : { + "revision" : "7b847a3b7008b2dc2f47ca3110d8c782fb2e5c7e", + "version" : "1.3.0" + } + }, + { + "identity" : "swift-crypto", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-crypto.git", + "state" : { + "revision" : "e8ed8867ec23bccf5f3bb9342148fa8deaff9b49", + "version" : "4.1.0" + } + }, + { + "identity" : "swift-http-structured-headers", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-http-structured-headers.git", + "state" : { + "revision" : "a9f3c352f4d46afd155e00b3c6e85decae6bcbeb", + "version" : "1.5.0" + } + }, + { + "identity" : "swift-http-types", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-http-types.git", + "state" : { + "revision" : "45eb0224913ea070ec4fba17291b9e7ecf4749ca", + "version" : "1.5.1" + } + }, + { + "identity" : "swift-log", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-log.git", + "state" : { + "revision" : "ce592ae52f982c847a4efc0dd881cc9eb32d29f2", + "version" : "1.6.4" + } + }, + { + "identity" : "swift-metrics", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-metrics.git", + "state" : { + "revision" : "0743a9364382629da3bf5677b46a2c4b1ce5d2a6", + "version" : "2.7.1" + } + }, + { + "identity" : "swift-nio", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio.git", + "state" : { + "revision" : "a24771a4c228ff116df343c85fcf3dcfae31a06c", + "version" : "2.88.0" + } + }, + { + "identity" : "swift-nio-extras", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio-extras.git", + "state" : { + "revision" : "b87fdbf492c8fd5ac860e642c714d2d24156990a", + "version" : "1.30.0" + } + }, + { + "identity" : "swift-nio-http2", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio-http2.git", + "state" : { + "revision" : "5e9e99ec96c53bc2c18ddd10c1e25a3cd97c55e5", + "version" : "1.38.0" + } + }, + { + "identity" : "swift-nio-ssl", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio-ssl.git", + "state" : { + "revision" : "173cc69a058623525a58ae6710e2f5727c663793", + "version" : "2.36.0" + } + }, + { + "identity" : "swift-nio-transport-services", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio-transport-services.git", + "state" : { + "revision" : "df6c28355051c72c884574a6c858bc54f7311ff9", + "version" : "1.25.2" + } + }, + { + "identity" : "swift-numerics", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-numerics.git", + "state" : { + "revision" : "0c0290ff6b24942dadb83a929ffaaa1481df04a2", + "version" : "1.1.1" + } + }, + { + "identity" : "swift-protobuf", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-protobuf.git", + "state" : { + "revision" : "c169a5744230951031770e27e475ff6eefe51f9d", + "version" : "1.33.3" + } + }, + { + "identity" : "swift-service-lifecycle", + "kind" : "remoteSourceControl", + "location" : "https://github.com/swift-server/swift-service-lifecycle.git", + "state" : { + "revision" : "0fcc4c9c2d58dd98504c06f7308c86de775396ff", + "version" : "2.9.0" + } + }, + { + "identity" : "swift-system", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-system.git", + "state" : { + "revision" : "395a77f0aa927f0ff73941d7ac35f2b46d47c9db", + "version" : "1.6.3" + } + }, + { + "identity" : "thrift-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/undefinedlabs/Thrift-Swift", + "state" : { + "revision" : "18ff09e6b30e589ed38f90a1af23e193b8ecef8e", + "version" : "1.1.2" + } + } + ], + "version" : 2 +} diff --git a/examples/aws_sdk_example/Package.swift b/examples/aws_sdk_example/Package.swift new file mode 100644 index 000000000..ec8c2865d --- /dev/null +++ b/examples/aws_sdk_example/Package.swift @@ -0,0 +1,10 @@ +// swift-tools-version: 5.9 + +import PackageDescription + +let package = Package( + name: "AwsSdkExample", + dependencies: [ + .package(url: "https://github.com/awslabs/aws-sdk-swift", from: "1.0.0"), + ] +) diff --git a/examples/aws_sdk_example/README.md b/examples/aws_sdk_example/README.md new file mode 100644 index 000000000..0147772ed --- /dev/null +++ b/examples/aws_sdk_example/README.md @@ -0,0 +1,29 @@ +# AWS SDK Swift Example + +This example demonstrates building a Swift application that uses the AWS SDK for Swift. + +## Building + +```bash +bazel build //:AwsSdkExample +``` + +## Running + +```bash +bazel run //:AwsSdkExample +``` + +Expected output: +``` +AWS SDK Swift S3 client created successfully +``` + +## What This Tests + +This example verifies that rules_swift_package_manager can successfully build aws-sdk-swift, which depends on: +- aws-crt-swift (complex C dependencies with inline headers, excluded directories, and system frameworks) +- Multiple Swift packages with various dependency patterns +- Transitive C library dependencies with framework auto-detection + +The successful build demonstrates that all the fixes for complex C dependencies work correctly with a real-world, complex Swift package. diff --git a/examples/aws_sdk_example/Sources/AwsSdkExample/main.swift b/examples/aws_sdk_example/Sources/AwsSdkExample/main.swift new file mode 100644 index 000000000..03cae5c99 --- /dev/null +++ b/examples/aws_sdk_example/Sources/AwsSdkExample/main.swift @@ -0,0 +1,11 @@ +import AWSS3 + +struct AwsSdkExample { + static func main() async throws { + // Simple example that creates an S3 client + _ = try await S3Client() + print("AWS SDK Swift S3 client created successfully") + } +} + +try await AwsSdkExample.main() diff --git a/examples/aws_sdk_example/WORKSPACE b/examples/aws_sdk_example/WORKSPACE new file mode 100644 index 000000000..e69de29bb diff --git a/examples/aws_sdk_example/WORKSPACE.bzlmod b/examples/aws_sdk_example/WORKSPACE.bzlmod new file mode 100644 index 000000000..e69de29bb From f0fc80911fd3ddeaa7b5014512344b200a89075d Mon Sep 17 00:00:00 2001 From: Cody Vandermyn Date: Tue, 4 Nov 2025 15:08:52 -0800 Subject: [PATCH 3/7] Update example_infos and run tidy to generate CI workflow - Added aws_crt_example and aws_sdk_example to example_infos.bzl - Ran bazel run //:tidy to update CI workflow and deleted_packages - CI will now test both new examples on macOS --- .bazelrc | 4 ++-- .github/workflows/ci.yml | 4 ++++ examples/example_infos.bzl | 2 ++ swiftpkg/internal/pkginfos.bzl | 18 ++++++++++++------ 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/.bazelrc b/.bazelrc index 680734883..c5aa2d368 100644 --- a/.bazelrc +++ b/.bazelrc @@ -1,7 +1,7 @@ # To update these lines, execute # `bazel run @rules_bazel_integration_test//tools:update_deleted_packages` -build --deleted_packages=bzlmod/workspace,bzlmod/workspace/Sources/MyExecutable,bzlmod/workspace/Sources/MyLibrary,bzlmod/workspace/Tests/MyLibraryTests,examples/firebase_example,examples/firebase_example/abtesting,examples/firebase_example/abtesting/SharedApp,examples/firebase_example/analytics/AnalyticsExample,examples/firebase_example/appdistribution,examples/firebase_example/appdistribution/AppDistributionExample,examples/firebase_example/appdistribution/AppDistributionTests,examples/firebase_example/crashlytics,examples/google_maps_example,examples/google_maps_example/GoogleMapsExample,examples/google_maps_example/third-party/google-maps-ios-sdk,examples/grpc_example,examples/grpc_example/compilers,examples/grpc_example/protos/echo_service,examples/grpc_example/protos/echo_service/requests,examples/grpc_example/protos/echo_service/responses,examples/grpc_example/sources/client,examples/grpc_example/sources/server,examples/injectionnext_example,examples/injectionnext_example/Tests,examples/interesting_deps,examples/interesting_deps/ios,examples/ios_sim,examples/ios_sim/Sources/Foo,examples/ios_sim/Tests/FooTests,examples/kscrash_example,examples/kscrash_example/Sources/MyApp,examples/kscrash_example/Tests/MyAppUITests,examples/kscrash_example/swift,examples/language_modes_example,examples/lottie_ios_example,examples/lottie_ios_example/LottieExample,examples/lottie_ios_example/LottieExampleUITest,examples/messagekit_example,examples/messagekit_example/Sources/Models,examples/messagekit_example/Tests/ModelTests,examples/nimble_example,examples/nimble_example/Sources/NimbleExample,examples/objc_code,examples/objc_code/Tests/TrustKitTests,examples/phone_number_kit,examples/phone_number_kit/Tests/PhoneNumberKitTests,examples/pkg_manifest_minimal,examples/pkg_manifest_minimal/Sources/MyExecutable,examples/pkg_manifest_minimal/Sources/MyLibrary,examples/pkg_manifest_minimal/Tests/MyLibraryTests,examples/pkg_manifest_minimal/third_party,examples/resources_example,examples/resources_example/Sources/MyApp,examples/resources_example/Tests/MyAppTests,examples/resources_example/Tests/MyAppUITests,examples/resources_example/swift,examples/resources_example/third_party,examples/shake_ios_example,examples/shake_ios_example/ShakeIOSExample,examples/shake_ios_example/ShakeIOSExampleUITests,examples/skip_local_transitive_dependencies_example,examples/snapkit_example,examples/soto_example,examples/soto_example/Tests/SotoTests,examples/sqlite_data_example,examples/stripe_example,examples/stripe_example/PaymentSheet/PaymentSheetExample,examples/stripe_example/PaymentSheet/PaymentSheetUITest,examples/swift_package_registry_example,examples/symlink_example,examples/symlink_example/Sources/ImportFramework,examples/symlink_example/Tests/ImportFrameworkTests,examples/tca_example,examples/tca_example/Sources,examples/tca_example/Tests,examples/vapor_example,examples/vapor_example/Sources/App,examples/vapor_example/Sources/Run,examples/vapor_example/Tests/AppTests,examples/vapor_example/swift,examples/xcmetrics_example -query --deleted_packages=bzlmod/workspace,bzlmod/workspace/Sources/MyExecutable,bzlmod/workspace/Sources/MyLibrary,bzlmod/workspace/Tests/MyLibraryTests,examples/firebase_example,examples/firebase_example/abtesting,examples/firebase_example/abtesting/SharedApp,examples/firebase_example/analytics/AnalyticsExample,examples/firebase_example/appdistribution,examples/firebase_example/appdistribution/AppDistributionExample,examples/firebase_example/appdistribution/AppDistributionTests,examples/firebase_example/crashlytics,examples/google_maps_example,examples/google_maps_example/GoogleMapsExample,examples/google_maps_example/third-party/google-maps-ios-sdk,examples/grpc_example,examples/grpc_example/compilers,examples/grpc_example/protos/echo_service,examples/grpc_example/protos/echo_service/requests,examples/grpc_example/protos/echo_service/responses,examples/grpc_example/sources/client,examples/grpc_example/sources/server,examples/injectionnext_example,examples/injectionnext_example/Tests,examples/interesting_deps,examples/interesting_deps/ios,examples/ios_sim,examples/ios_sim/Sources/Foo,examples/ios_sim/Tests/FooTests,examples/kscrash_example,examples/kscrash_example/Sources/MyApp,examples/kscrash_example/Tests/MyAppUITests,examples/kscrash_example/swift,examples/language_modes_example,examples/lottie_ios_example,examples/lottie_ios_example/LottieExample,examples/lottie_ios_example/LottieExampleUITest,examples/messagekit_example,examples/messagekit_example/Sources/Models,examples/messagekit_example/Tests/ModelTests,examples/nimble_example,examples/nimble_example/Sources/NimbleExample,examples/objc_code,examples/objc_code/Tests/TrustKitTests,examples/phone_number_kit,examples/phone_number_kit/Tests/PhoneNumberKitTests,examples/pkg_manifest_minimal,examples/pkg_manifest_minimal/Sources/MyExecutable,examples/pkg_manifest_minimal/Sources/MyLibrary,examples/pkg_manifest_minimal/Tests/MyLibraryTests,examples/pkg_manifest_minimal/third_party,examples/resources_example,examples/resources_example/Sources/MyApp,examples/resources_example/Tests/MyAppTests,examples/resources_example/Tests/MyAppUITests,examples/resources_example/swift,examples/resources_example/third_party,examples/shake_ios_example,examples/shake_ios_example/ShakeIOSExample,examples/shake_ios_example/ShakeIOSExampleUITests,examples/skip_local_transitive_dependencies_example,examples/snapkit_example,examples/soto_example,examples/soto_example/Tests/SotoTests,examples/sqlite_data_example,examples/stripe_example,examples/stripe_example/PaymentSheet/PaymentSheetExample,examples/stripe_example/PaymentSheet/PaymentSheetUITest,examples/swift_package_registry_example,examples/symlink_example,examples/symlink_example/Sources/ImportFramework,examples/symlink_example/Tests/ImportFrameworkTests,examples/tca_example,examples/tca_example/Sources,examples/tca_example/Tests,examples/vapor_example,examples/vapor_example/Sources/App,examples/vapor_example/Sources/Run,examples/vapor_example/Tests/AppTests,examples/vapor_example/swift,examples/xcmetrics_example +build --deleted_packages=bzlmod/workspace,bzlmod/workspace/Sources/MyExecutable,bzlmod/workspace/Sources/MyLibrary,bzlmod/workspace/Tests/MyLibraryTests,examples/aws_crt_example,examples/aws_sdk_example,examples/firebase_example,examples/firebase_example/abtesting,examples/firebase_example/abtesting/SharedApp,examples/firebase_example/analytics/AnalyticsExample,examples/firebase_example/appdistribution,examples/firebase_example/appdistribution/AppDistributionExample,examples/firebase_example/appdistribution/AppDistributionTests,examples/firebase_example/crashlytics,examples/google_maps_example,examples/google_maps_example/GoogleMapsExample,examples/google_maps_example/third-party/google-maps-ios-sdk,examples/grpc_example,examples/grpc_example/compilers,examples/grpc_example/protos/echo_service,examples/grpc_example/protos/echo_service/requests,examples/grpc_example/protos/echo_service/responses,examples/grpc_example/sources/client,examples/grpc_example/sources/server,examples/injectionnext_example,examples/injectionnext_example/Tests,examples/interesting_deps,examples/interesting_deps/ios,examples/ios_sim,examples/ios_sim/Sources/Foo,examples/ios_sim/Tests/FooTests,examples/kscrash_example,examples/kscrash_example/Sources/MyApp,examples/kscrash_example/Tests/MyAppUITests,examples/kscrash_example/swift,examples/language_modes_example,examples/lottie_ios_example,examples/lottie_ios_example/LottieExample,examples/lottie_ios_example/LottieExampleUITest,examples/messagekit_example,examples/messagekit_example/Sources/Models,examples/messagekit_example/Tests/ModelTests,examples/nimble_example,examples/nimble_example/Sources/NimbleExample,examples/objc_code,examples/objc_code/Tests/TrustKitTests,examples/phone_number_kit,examples/phone_number_kit/Tests/PhoneNumberKitTests,examples/pkg_manifest_minimal,examples/pkg_manifest_minimal/Sources/MyExecutable,examples/pkg_manifest_minimal/Sources/MyLibrary,examples/pkg_manifest_minimal/Tests/MyLibraryTests,examples/pkg_manifest_minimal/third_party,examples/resources_example,examples/resources_example/Sources/MyApp,examples/resources_example/Tests/MyAppTests,examples/resources_example/Tests/MyAppUITests,examples/resources_example/swift,examples/resources_example/third_party,examples/shake_ios_example,examples/shake_ios_example/ShakeIOSExample,examples/shake_ios_example/ShakeIOSExampleUITests,examples/skip_local_transitive_dependencies_example,examples/snapkit_example,examples/soto_example,examples/soto_example/Tests/SotoTests,examples/sqlite_data_example,examples/stripe_example,examples/stripe_example/PaymentSheet/PaymentSheetExample,examples/stripe_example/PaymentSheet/PaymentSheetUITest,examples/swift_package_registry_example,examples/symlink_example,examples/symlink_example/Sources/ImportFramework,examples/symlink_example/Tests/ImportFrameworkTests,examples/tca_example,examples/tca_example/Sources,examples/tca_example/Tests,examples/vapor_example,examples/vapor_example/Sources/App,examples/vapor_example/Sources/Run,examples/vapor_example/Tests/AppTests,examples/vapor_example/swift,examples/xcmetrics_example +query --deleted_packages=bzlmod/workspace,bzlmod/workspace/Sources/MyExecutable,bzlmod/workspace/Sources/MyLibrary,bzlmod/workspace/Tests/MyLibraryTests,examples/aws_crt_example,examples/aws_sdk_example,examples/firebase_example,examples/firebase_example/abtesting,examples/firebase_example/abtesting/SharedApp,examples/firebase_example/analytics/AnalyticsExample,examples/firebase_example/appdistribution,examples/firebase_example/appdistribution/AppDistributionExample,examples/firebase_example/appdistribution/AppDistributionTests,examples/firebase_example/crashlytics,examples/google_maps_example,examples/google_maps_example/GoogleMapsExample,examples/google_maps_example/third-party/google-maps-ios-sdk,examples/grpc_example,examples/grpc_example/compilers,examples/grpc_example/protos/echo_service,examples/grpc_example/protos/echo_service/requests,examples/grpc_example/protos/echo_service/responses,examples/grpc_example/sources/client,examples/grpc_example/sources/server,examples/injectionnext_example,examples/injectionnext_example/Tests,examples/interesting_deps,examples/interesting_deps/ios,examples/ios_sim,examples/ios_sim/Sources/Foo,examples/ios_sim/Tests/FooTests,examples/kscrash_example,examples/kscrash_example/Sources/MyApp,examples/kscrash_example/Tests/MyAppUITests,examples/kscrash_example/swift,examples/language_modes_example,examples/lottie_ios_example,examples/lottie_ios_example/LottieExample,examples/lottie_ios_example/LottieExampleUITest,examples/messagekit_example,examples/messagekit_example/Sources/Models,examples/messagekit_example/Tests/ModelTests,examples/nimble_example,examples/nimble_example/Sources/NimbleExample,examples/objc_code,examples/objc_code/Tests/TrustKitTests,examples/phone_number_kit,examples/phone_number_kit/Tests/PhoneNumberKitTests,examples/pkg_manifest_minimal,examples/pkg_manifest_minimal/Sources/MyExecutable,examples/pkg_manifest_minimal/Sources/MyLibrary,examples/pkg_manifest_minimal/Tests/MyLibraryTests,examples/pkg_manifest_minimal/third_party,examples/resources_example,examples/resources_example/Sources/MyApp,examples/resources_example/Tests/MyAppTests,examples/resources_example/Tests/MyAppUITests,examples/resources_example/swift,examples/resources_example/third_party,examples/shake_ios_example,examples/shake_ios_example/ShakeIOSExample,examples/shake_ios_example/ShakeIOSExampleUITests,examples/skip_local_transitive_dependencies_example,examples/snapkit_example,examples/soto_example,examples/soto_example/Tests/SotoTests,examples/sqlite_data_example,examples/stripe_example,examples/stripe_example/PaymentSheet/PaymentSheetExample,examples/stripe_example/PaymentSheet/PaymentSheetUITest,examples/swift_package_registry_example,examples/symlink_example,examples/symlink_example/Sources/ImportFramework,examples/symlink_example/Tests/ImportFrameworkTests,examples/tca_example,examples/tca_example/Sources,examples/tca_example/Tests,examples/vapor_example,examples/vapor_example/Sources/App,examples/vapor_example/Sources/Run,examples/vapor_example/Tests/AppTests,examples/vapor_example/swift,examples/xcmetrics_example # Import Shared settings import %workspace%/shared.bazelrc diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3198fef30..226686fc1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,6 +35,10 @@ jobs: runner: ubuntu-22.04 - test: '@@//bzlmod:e2e_test' runner: macos-15 + - test: '@@//examples:aws_crt_example_test_bazel_.bazelversion' + runner: macos-15 + - test: '@@//examples:aws_sdk_example_test_bazel_.bazelversion' + runner: macos-15 - test: '@@//examples:firebase_example_test_bazel_.bazelversion' runner: macos-15 - test: '@@//examples:google_maps_example_test_bazel_.bazelversion' diff --git a/examples/example_infos.bzl b/examples/example_infos.bzl index e24fede67..e311d8b37 100644 --- a/examples/example_infos.bzl +++ b/examples/example_infos.bzl @@ -132,6 +132,8 @@ _all_os_single_bazel_version_test_examples = [ ] _macos_single_bazel_version_test_examples = [ + "aws_crt_example", + "aws_sdk_example", "firebase_example", "google_maps_example", "interesting_deps", diff --git a/swiftpkg/internal/pkginfos.bzl b/swiftpkg/internal/pkginfos.bzl index fe7571721..6cda1df9c 100644 --- a/swiftpkg/internal/pkginfos.bzl +++ b/swiftpkg/internal/pkginfos.bzl @@ -1177,19 +1177,20 @@ def _new_swift_src_info( def _detect_frameworks_from_sources(repository_ctx, srcs): """Detect Apple frameworks from #include patterns in C source files.""" frameworks_set = sets.make() - + for src in srcs: # Only scan C/C++/ObjC source and header files - if not (src.endswith(".c") or src.endswith(".cc") or src.endswith(".cpp") or - src.endswith(".m") or src.endswith(".mm") or src.endswith(".h") or + if not (src.endswith(".c") or src.endswith(".cc") or src.endswith(".cpp") or + src.endswith(".m") or src.endswith(".mm") or src.endswith(".h") or src.endswith(".hpp")): continue - + # Read the file and look for framework includes content = repository_ctx.read(src) lines = content.split("\n") for line in lines: line = line.strip() + # Look for #include or #import if line.startswith("#include") or line.startswith("#import"): # Extract the include path @@ -1197,13 +1198,15 @@ def _detect_frameworks_from_sources(repository_ctx, srcs): start = line.index("<") + 1 end = line.index(">") include_path = line[start:end] + # Check if it's a framework include (has a slash) if "/" in include_path: framework = include_path.split("/")[0] + # Check if it's a known Apple framework if sets.contains(apple_builtin.frameworks.all, framework): sets.insert(frameworks_set, framework) - + return sorted(sets.to_list(frameworks_set)) def _new_clang_src_info_from_sources( @@ -1229,9 +1232,11 @@ def _new_clang_src_info_from_sources( default_include_path = paths.normalize(paths.join(abs_target_path, "include")) if repository_files.is_directory(repository_ctx, default_include_path): public_hdrs_path = "include" + # Remove any exclude paths that start with "include/" exclude_paths = [ - ep for ep in exclude_paths + ep + for ep in exclude_paths if not ep.startswith("include/") and ep != "include" ] @@ -1294,6 +1299,7 @@ def _new_clang_src_info_from_sources( abs_exclude_path, exclude_paths = [], ) + # Filter to only header files for f in excluded_files: _, ext = paths.split_extension(f) From fe597017be1e5a9e00e41f190d6f1bdc76593644 Mon Sep 17 00:00:00 2001 From: Cody Vandermyn Date: Wed, 5 Nov 2025 07:30:33 -0800 Subject: [PATCH 4/7] Address code review feedback: formatting and style improvements - Update .bazelrc files to use shared config imports - Update do_test script to use BIT_BAZEL_BINARY - Wrap long lines in MODULE.bazel to stay under 80 chars - Refactor framework detection with helper function and constants - Move header extensions to constants - Improve line wrapping and formatting throughout --- examples/aws_crt_example/.bazelrc | 12 ++++--- examples/aws_crt_example/MODULE.bazel | 12 +++++-- examples/aws_crt_example/do_test | 7 +++- examples/aws_sdk_example/.bazelrc | 12 ++++--- swiftpkg/internal/module_maps.bzl | 6 +++- swiftpkg/internal/pkginfos.bzl | 50 +++++++++++++++++---------- 6 files changed, 68 insertions(+), 31 deletions(-) diff --git a/examples/aws_crt_example/.bazelrc b/examples/aws_crt_example/.bazelrc index 0820c757d..e9769fc7b 100644 --- a/examples/aws_crt_example/.bazelrc +++ b/examples/aws_crt_example/.bazelrc @@ -1,4 +1,8 @@ -build --enable_bzlmod -build --lockfile_mode=update -build --macos_minimum_os=15.0 -build --host_macos_minimum_os=15.0 +# Import Shared settings +import %workspace%/../../shared.bazelrc + +# Import CI settings. +import %workspace%/../../ci.bazelrc + +# Try to import a local.rc file; typically, written by CI +try-import %workspace%/../../local.bazelrc diff --git a/examples/aws_crt_example/MODULE.bazel b/examples/aws_crt_example/MODULE.bazel index 66bed05ab..eafccf4e3 100644 --- a/examples/aws_crt_example/MODULE.bazel +++ b/examples/aws_crt_example/MODULE.bazel @@ -7,8 +7,16 @@ local_path_override( ) bazel_dep(name = "apple_support", version = "1.24.2") -bazel_dep(name = "rules_swift", version = "3.1.2", repo_name = "build_bazel_rules_swift") -bazel_dep(name = "rules_apple", version = "4.2.0", repo_name = "build_bazel_rules_apple") +bazel_dep( + name = "rules_swift", + version = "3.1.2", + repo_name = "build_bazel_rules_swift", +) +bazel_dep( + name = "rules_apple", + version = "4.2.0", + repo_name = "build_bazel_rules_apple", +) apple_cc_configure = use_extension( "@apple_support//crosstool:setup.bzl", diff --git a/examples/aws_crt_example/do_test b/examples/aws_crt_example/do_test index c6883a53c..6e66fa478 100755 --- a/examples/aws_crt_example/do_test +++ b/examples/aws_crt_example/do_test @@ -2,4 +2,9 @@ set -euo pipefail -bazel test //... +# Use the Bazel binary specified by the integration test. Otherise, fall back +# to bazel. +bazel="${BIT_BAZEL_BINARY:-bazel}" + +# Ensure that it builds and tests pass +"${bazel}" test //... diff --git a/examples/aws_sdk_example/.bazelrc b/examples/aws_sdk_example/.bazelrc index 0820c757d..e9769fc7b 100644 --- a/examples/aws_sdk_example/.bazelrc +++ b/examples/aws_sdk_example/.bazelrc @@ -1,4 +1,8 @@ -build --enable_bzlmod -build --lockfile_mode=update -build --macos_minimum_os=15.0 -build --host_macos_minimum_os=15.0 +# Import Shared settings +import %workspace%/../../shared.bazelrc + +# Import CI settings. +import %workspace%/../../ci.bazelrc + +# Try to import a local.rc file; typically, written by CI +try-import %workspace%/../../local.bazelrc diff --git a/swiftpkg/internal/module_maps.bzl b/swiftpkg/internal/module_maps.bzl index 04b4b2c41..6943297c7 100644 --- a/swiftpkg/internal/module_maps.bzl +++ b/swiftpkg/internal/module_maps.bzl @@ -110,7 +110,11 @@ def write_module_map( _add_headers(headers = [umbrella_header], kind = "umbrella header") elif umbrella_directory: # Umbrella directory must be absolute path - abs_umbrella = back_to_root_path + umbrella_directory if back_to_root_path else umbrella_directory + abs_umbrella = ( + back_to_root_path + umbrella_directory + if back_to_root_path + else umbrella_directory + ) content.add(abs_umbrella, format = ' umbrella "%s"') else: _add_headers(headers = public_headers, kind = "header") diff --git a/swiftpkg/internal/pkginfos.bzl b/swiftpkg/internal/pkginfos.bzl index 6cda1df9c..03da79209 100644 --- a/swiftpkg/internal/pkginfos.bzl +++ b/swiftpkg/internal/pkginfos.bzl @@ -1174,15 +1174,21 @@ def _new_swift_src_info( # MARK: - Clang Source Info +_FRAMEWORK_SRC_EXTS = [".c", ".cc", ".cpp", ".m", ".mm", ".h", ".hpp"] +_HEADER_EXTS = [".h", ".hpp", ".hh", ".hxx", ".inc", ".inl", ".modulemap"] + +def _is_framework_src(path): + _root, ext = paths.split_extension(path) + return lists.contains(_FRAMEWORK_SRC_EXTS, ext) + def _detect_frameworks_from_sources(repository_ctx, srcs): - """Detect Apple frameworks from #include patterns in C source files.""" + """Detect Apple frameworks from #include patterns in \ + C source files.""" frameworks_set = sets.make() for src in srcs: # Only scan C/C++/ObjC source and header files - if not (src.endswith(".c") or src.endswith(".cc") or src.endswith(".cpp") or - src.endswith(".m") or src.endswith(".mm") or src.endswith(".h") or - src.endswith(".hpp")): + if not _is_framework_src(src): continue # Read the file and look for framework includes @@ -1191,21 +1197,25 @@ def _detect_frameworks_from_sources(repository_ctx, srcs): for line in lines: line = line.strip() - # Look for #include or #import - if line.startswith("#include") or line.startswith("#import"): - # Extract the include path - if "<" in line and ">" in line: - start = line.index("<") + 1 - end = line.index(">") - include_path = line[start:end] + # Look for #include or + # #import + if not line.startswith("#include") and \ + not line.startswith("#import"): + continue - # Check if it's a framework include (has a slash) - if "/" in include_path: - framework = include_path.split("/")[0] + # Extract the include path + if "<" in line and ">" in line: + start = line.index("<") + 1 + end = line.index(">") + include_path = line[start:end] - # Check if it's a known Apple framework - if sets.contains(apple_builtin.frameworks.all, framework): - sets.insert(frameworks_set, framework) + # Check if it's a framework include (has a slash) + if "/" in include_path: + framework = include_path.split("/")[0] + + # Check if it's a known Apple framework + if sets.contains(apple_builtin.frameworks.all, framework): + sets.insert(frameworks_set, framework) return sorted(sets.to_list(frameworks_set)) @@ -1229,7 +1239,9 @@ def _new_clang_src_info_from_sources( # Also remove any exclude patterns that would exclude the include directory, # since SPM doesn't exclude public headers even if they're in the exclude list. if public_hdrs_path == None: - default_include_path = paths.normalize(paths.join(abs_target_path, "include")) + default_include_path = paths.normalize( + paths.join(abs_target_path, "include"), + ) if repository_files.is_directory(repository_ctx, default_include_path): public_hdrs_path = "include" @@ -1303,7 +1315,7 @@ def _new_clang_src_info_from_sources( # Filter to only header files for f in excluded_files: _, ext = paths.split_extension(f) - if ext in [".h", ".hpp", ".hh", ".hxx", ".inc", ".inl", ".modulemap"]: + if ext in _HEADER_EXTS: all_srcs.append(f) # Organize the source files From b9582f3441ed9440441c7c66d1fbeb202e939c19 Mon Sep 17 00:00:00 2001 From: Cody Vandermyn Date: Wed, 5 Nov 2025 07:46:39 -0800 Subject: [PATCH 5/7] Add cgrindel_bazel_starlib dependency for shared.bazelrc compatibility Both examples now include cgrindel_bazel_starlib dependency which is required by the shared.bazelrc configuration. --- examples/aws_crt_example/MODULE.bazel | 1 + examples/aws_sdk_example/MODULE.bazel | 1 + 2 files changed, 2 insertions(+) diff --git a/examples/aws_crt_example/MODULE.bazel b/examples/aws_crt_example/MODULE.bazel index eafccf4e3..9af7e012b 100644 --- a/examples/aws_crt_example/MODULE.bazel +++ b/examples/aws_crt_example/MODULE.bazel @@ -1,5 +1,6 @@ module(name = "aws_crt_example") +bazel_dep(name = "cgrindel_bazel_starlib", version = "0.27.0") bazel_dep(name = "rules_swift_package_manager", version = "") local_path_override( module_name = "rules_swift_package_manager", diff --git a/examples/aws_sdk_example/MODULE.bazel b/examples/aws_sdk_example/MODULE.bazel index cf7ba9800..8346f76df 100644 --- a/examples/aws_sdk_example/MODULE.bazel +++ b/examples/aws_sdk_example/MODULE.bazel @@ -1,5 +1,6 @@ module(name = "aws_sdk_example") +bazel_dep(name = "cgrindel_bazel_starlib", version = "0.27.0") bazel_dep(name = "rules_swift_package_manager", version = "1.10.0") local_path_override( module_name = "rules_swift_package_manager", From f2568efd66aba590c674ecdc98349d94842adcb9 Mon Sep 17 00:00:00 2001 From: Cody Vandermyn Date: Mon, 10 Nov 2025 08:08:16 -0800 Subject: [PATCH 6/7] Add Gazelle integration and CI support to AWS examples - Add .bazelignore files to exclude .build directories from Bazel - Add Gazelle targets for automated BUILD file generation - Add tidy targets to run Gazelle updates - Add swift_package_tool targets for package updates - Update MODULE.bazel files with Gazelle dependencies and swift_deps_info - Add do_test script for aws_sdk_example - Update do_test script for aws_crt_example to run tidy - Exclude Tests directory from Gazelle in aws_crt_example - Fix repository name references to use build_bazel_rules_swift - Standardize bash options and formatting in do_test scripts --- examples/aws_crt_example/.bazelignore | 1 + examples/aws_crt_example/BUILD.bazel | 43 +++++++++++++++++++++++++ examples/aws_crt_example/MODULE.bazel | 34 +++++++++++++++----- examples/aws_crt_example/do_test | 5 ++- examples/aws_sdk_example/.bazelignore | 1 + examples/aws_sdk_example/BUILD.bazel | 45 +++++++++++++++++++++++++- examples/aws_sdk_example/MODULE.bazel | 46 +++++++++++++++++++++++++-- examples/aws_sdk_example/do_test | 15 +++++++++ 8 files changed, 177 insertions(+), 13 deletions(-) create mode 100644 examples/aws_crt_example/.bazelignore create mode 100644 examples/aws_sdk_example/.bazelignore create mode 100755 examples/aws_sdk_example/do_test diff --git a/examples/aws_crt_example/.bazelignore b/examples/aws_crt_example/.bazelignore new file mode 100644 index 000000000..24e5b0a1a --- /dev/null +++ b/examples/aws_crt_example/.bazelignore @@ -0,0 +1 @@ +.build diff --git a/examples/aws_crt_example/BUILD.bazel b/examples/aws_crt_example/BUILD.bazel index cced3a540..5321ab438 100644 --- a/examples/aws_crt_example/BUILD.bazel +++ b/examples/aws_crt_example/BUILD.bazel @@ -1,4 +1,7 @@ +load("@bazel_gazelle//:def.bzl", "gazelle", "gazelle_binary") load("@build_bazel_rules_swift//swift:swift_test.bzl", "swift_test") +load("@cgrindel_bazel_starlib//bzltidy:defs.bzl", "tidy") +load("@rules_swift_package_manager//swiftpkg:defs.bzl", "swift_package_tool") swift_test( name = "AwsCrtTests", @@ -7,3 +10,43 @@ swift_test( "@swiftpkg_aws_crt_swift//:AwsCommonRuntimeKit", ], ) + +tidy( + name = "tidy", + targets = [ + ":update_build_files", + ], +) + +# Purposefully am not adding this to tidy. It is expensive to run and only +# needs to be run when the Package.swift has been updated. +swift_package_tool( + name = "update_swift_packages", + cmd = "update", + package = "Package.swift", +) + +# MARK: - Gazelle + +# Ignore the Swift build folder +# gazelle:exclude .build +# gazelle:exclude Tests + +gazelle_binary( + name = "gazelle_bin", + languages = [ + "@bazel_skylib_gazelle_plugin//bzl", + "@swift_gazelle_plugin//gazelle", + ], +) + +gazelle( + name = "update_build_files", + data = [ + "@swift_deps_info//:swift_deps_index", + ], + extra_args = [ + "-swift_dependency_index=$(location @swift_deps_info//:swift_deps_index)", + ], + gazelle = ":gazelle_bin", +) diff --git a/examples/aws_crt_example/MODULE.bazel b/examples/aws_crt_example/MODULE.bazel index 9af7e012b..6e6fde806 100644 --- a/examples/aws_crt_example/MODULE.bazel +++ b/examples/aws_crt_example/MODULE.bazel @@ -1,13 +1,17 @@ module(name = "aws_crt_example") -bazel_dep(name = "cgrindel_bazel_starlib", version = "0.27.0") -bazel_dep(name = "rules_swift_package_manager", version = "") +bazel_dep( + name = "rules_swift_package_manager", + version = "0.0.0", +) local_path_override( module_name = "rules_swift_package_manager", path = "../..", ) -bazel_dep(name = "apple_support", version = "1.24.2") +bazel_dep(name = "cgrindel_bazel_starlib", version = "0.27.0") +bazel_dep(name = "bazel_skylib", version = "1.8.2") +bazel_dep(name = "apple_support", version = "1.24.3") bazel_dep( name = "rules_swift", version = "3.1.2", @@ -19,6 +23,23 @@ bazel_dep( repo_name = "build_bazel_rules_apple", ) +bazel_dep( + name = "bazel_skylib_gazelle_plugin", + version = "1.8.2", + dev_dependency = True, +) +bazel_dep( + name = "gazelle", + version = "0.46.0", + dev_dependency = True, + repo_name = "bazel_gazelle", +) +bazel_dep( + name = "swift_gazelle_plugin", + version = "0.2.1", + dev_dependency = True, +) + apple_cc_configure = use_extension( "@apple_support//crosstool:setup.bzl", "apple_cc_configure_extension", @@ -30,16 +51,13 @@ swift_deps = use_extension( "swift_deps", ) swift_deps.from_package( + declare_swift_deps_info = True, resolved = "//:Package.resolved", swift = "//:Package.swift", ) -swift_deps.configure_package( - name = "aws-crt-swift", - init_submodules = True, - recursive_init_submodules = True, -) use_repo( swift_deps, + "swift_deps_info", "swift_package", "swiftpkg_aws_crt_swift", ) diff --git a/examples/aws_crt_example/do_test b/examples/aws_crt_example/do_test index 6e66fa478..a4eb535e9 100755 --- a/examples/aws_crt_example/do_test +++ b/examples/aws_crt_example/do_test @@ -1,10 +1,13 @@ #!/usr/bin/env bash -set -euo pipefail +set -o errexit -o nounset -o pipefail # Use the Bazel binary specified by the integration test. Otherise, fall back # to bazel. bazel="${BIT_BAZEL_BINARY:-bazel}" +# Generate Swift external deps and update build files +"${bazel}" run //:tidy + # Ensure that it builds and tests pass "${bazel}" test //... diff --git a/examples/aws_sdk_example/.bazelignore b/examples/aws_sdk_example/.bazelignore new file mode 100644 index 000000000..24e5b0a1a --- /dev/null +++ b/examples/aws_sdk_example/.bazelignore @@ -0,0 +1 @@ +.build diff --git a/examples/aws_sdk_example/BUILD.bazel b/examples/aws_sdk_example/BUILD.bazel index 44fc218e8..aa2706627 100644 --- a/examples/aws_sdk_example/BUILD.bazel +++ b/examples/aws_sdk_example/BUILD.bazel @@ -1,4 +1,7 @@ -load("@rules_swift//swift:swift_binary.bzl", "swift_binary") +load("@bazel_gazelle//:def.bzl", "gazelle", "gazelle_binary") +load("@build_bazel_rules_swift//swift:swift_binary.bzl", "swift_binary") +load("@cgrindel_bazel_starlib//bzltidy:defs.bzl", "tidy") +load("@rules_swift_package_manager//swiftpkg:defs.bzl", "swift_package_tool") swift_binary( name = "AwsSdkExample", @@ -7,3 +10,43 @@ swift_binary( "@swiftpkg_aws_sdk_swift//:AWSS3", ], ) + +tidy( + name = "tidy", + targets = [ + ":update_build_files", + ], +) + +# Puprosefully am not adding this to tidy. It is expensive to run and only +# needs to be run when the Package.swift has been updated. +swift_package_tool( + name = "update_swift_packages", + cmd = "update", + package = "Package.swift", +) + +# MARK: - Gazelle + +# Ignore the Swift build folder +# gazelle:exclude .build +# gazelle:exclude Sources + +gazelle_binary( + name = "gazelle_bin", + languages = [ + "@bazel_skylib_gazelle_plugin//bzl", + "@swift_gazelle_plugin//gazelle", + ], +) + +gazelle( + name = "update_build_files", + data = [ + "@swift_deps_info//:swift_deps_index", + ], + extra_args = [ + "-swift_dependency_index=$(location @swift_deps_info//:swift_deps_index)", + ], + gazelle = ":gazelle_bin", +) diff --git a/examples/aws_sdk_example/MODULE.bazel b/examples/aws_sdk_example/MODULE.bazel index 8346f76df..c3a525fbf 100644 --- a/examples/aws_sdk_example/MODULE.bazel +++ b/examples/aws_sdk_example/MODULE.bazel @@ -1,23 +1,63 @@ module(name = "aws_sdk_example") -bazel_dep(name = "cgrindel_bazel_starlib", version = "0.27.0") -bazel_dep(name = "rules_swift_package_manager", version = "1.10.0") +bazel_dep( + name = "rules_swift_package_manager", + version = "0.0.0", +) local_path_override( module_name = "rules_swift_package_manager", path = "../..", ) -bazel_dep(name = "rules_swift", version = "2.3.0") +bazel_dep(name = "cgrindel_bazel_starlib", version = "0.27.0") +bazel_dep(name = "bazel_skylib", version = "1.8.2") +bazel_dep(name = "apple_support", version = "1.24.3") +bazel_dep( + name = "rules_swift", + version = "3.1.2", + repo_name = "build_bazel_rules_swift", +) +bazel_dep( + name = "rules_apple", + version = "4.2.0", + repo_name = "build_bazel_rules_apple", +) + +bazel_dep( + name = "bazel_skylib_gazelle_plugin", + version = "1.8.2", + dev_dependency = True, +) +bazel_dep( + name = "gazelle", + version = "0.46.0", + dev_dependency = True, + repo_name = "bazel_gazelle", +) +bazel_dep( + name = "swift_gazelle_plugin", + version = "0.2.1", + dev_dependency = True, +) + +apple_cc_configure = use_extension( + "@apple_support//crosstool:setup.bzl", + "apple_cc_configure_extension", +) +use_repo(apple_cc_configure, "local_config_apple_cc") swift_deps = use_extension( "@rules_swift_package_manager//:extensions.bzl", "swift_deps", ) swift_deps.from_package( + declare_swift_deps_info = True, resolved = "//:Package.resolved", swift = "//:Package.swift", ) use_repo( swift_deps, + "swift_deps_info", + "swift_package", "swiftpkg_aws_sdk_swift", ) diff --git a/examples/aws_sdk_example/do_test b/examples/aws_sdk_example/do_test new file mode 100755 index 000000000..f99357224 --- /dev/null +++ b/examples/aws_sdk_example/do_test @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +set -o errexit -o nounset -o pipefail + +# Use the Bazel binary specified by the integration test. Otherise, fall back +# to bazel. +bazel="${BIT_BAZEL_BINARY:-bazel}" + +# Generate Swift external deps and update build files +"${bazel}" run //:tidy + +# Ensure that it builds and runs +"${bazel}" run //:AwsSdkExample + + From 5c5105cc74448f070be16d5394e414bcb2e10168 Mon Sep 17 00:00:00 2001 From: Cody Vandermyn Date: Mon, 17 Nov 2025 07:32:40 -0800 Subject: [PATCH 7/7] fix: format ternary expression to single line in module_maps.bzl --- swiftpkg/internal/module_maps.bzl | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/swiftpkg/internal/module_maps.bzl b/swiftpkg/internal/module_maps.bzl index 6943297c7..5aaf3c29d 100644 --- a/swiftpkg/internal/module_maps.bzl +++ b/swiftpkg/internal/module_maps.bzl @@ -111,9 +111,7 @@ def write_module_map( elif umbrella_directory: # Umbrella directory must be absolute path abs_umbrella = ( - back_to_root_path + umbrella_directory - if back_to_root_path - else umbrella_directory + back_to_root_path + umbrella_directory if back_to_root_path else umbrella_directory ) content.add(abs_umbrella, format = ' umbrella "%s"') else: