diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index 96cec8aef..fcc6d695b 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -213,6 +213,37 @@ def create_compilation_context(defines, srcs, transitive_modules): swiftmodules = tuple(swiftmodules), ) +def _clang_module_map_info(swift_infos): + """Returns Clang module maps and include dirs from Swift deps.""" + + module_maps = [] + include_dirs = [] + seen_module_maps = {} + for swift_info in swift_infos: + for module in swift_info.direct_modules: + clang_module = module.clang + if not clang_module: + continue + + module_map = clang_module.module_map + if type(module_map) != "File": + continue + + if module_map.path in seen_module_maps: + continue + + seen_module_maps[module_map.path] = None + module_maps.append(module_map) + include_dirs.append(module_map.dirname) + + if not module_maps: + return None + + return struct( + include_dirs = include_dirs, + module_maps = module_maps, + ) + def compile_module_interface( *, actions, @@ -698,6 +729,13 @@ def compile( cc_info.compilation_context for cc_info in cc_infos ] + + generated_header_module_map_info = None + if generated_header_name: + generated_header_module_map_info = _clang_module_map_info( + generated_module_deps_swift_infos, + ) + merged_cc_info = cc_common.merge_cc_infos( cc_infos = cc_infos + private_cc_infos + implicit_cc_infos, @@ -913,6 +951,10 @@ to use swift_common.compile(include_dev_srch_paths = ...) instead.\ else: includes = [] + if generated_header_module_map_info: + public_hdrs.extend(generated_header_module_map_info.module_maps) + includes.extend(generated_header_module_map_info.include_dirs) + module_context = create_swift_module_context( name = module_name, clang = create_clang_module_inputs( diff --git a/test/fixtures/generated_header/BUILD b/test/fixtures/generated_header/BUILD index b87b2f80e..2ac414187 100644 --- a/test/fixtures/generated_header/BUILD +++ b/test/fixtures/generated_header/BUILD @@ -1,3 +1,8 @@ +load("@rules_cc//cc:objc_library.bzl", "objc_library") +load( + "//swift:swift_interop_hint.bzl", + "swift_interop_hint", +) load( "//swift:swift_library.bzl", "swift_library", @@ -55,3 +60,37 @@ swift_library( generates_header = False, tags = FIXTURE_TAGS, ) + +objc_library( + name = "c_dependency", + srcs = ["CDependency.m"], + hdrs = ["CDependency.h"], + aspect_hints = [":c_dependency_hint"], + tags = FIXTURE_TAGS, + target_compatible_with = ["@platforms//os:macos"], + deps = ["@system_sdk//:Foundation"], +) + +swift_interop_hint( + name = "c_dependency_hint", + module_name = "GeneratedHeaderCDependency", + tags = FIXTURE_TAGS, +) + +swift_library( + name = "generated_header_with_c_dep", + srcs = ["UsesCDependency.swift"], + generates_header = True, + tags = FIXTURE_TAGS, + target_compatible_with = ["@platforms//os:macos"], + deps = [":c_dependency"], +) + +objc_library( + name = "objc_consumer_of_generated_header", + srcs = ["ObjcConsumer.m"], + enable_modules = True, + tags = FIXTURE_TAGS, + target_compatible_with = ["@platforms//os:macos"], + deps = [":generated_header_with_c_dep"], +) diff --git a/test/fixtures/generated_header/CDependency.h b/test/fixtures/generated_header/CDependency.h new file mode 100644 index 000000000..ebb16d8d1 --- /dev/null +++ b/test/fixtures/generated_header/CDependency.h @@ -0,0 +1,18 @@ +// Copyright 2026 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 + +@interface GHCBox : NSObject +@end diff --git a/test/fixtures/generated_header/CDependency.m b/test/fixtures/generated_header/CDependency.m new file mode 100644 index 000000000..df6e422d5 --- /dev/null +++ b/test/fixtures/generated_header/CDependency.m @@ -0,0 +1,18 @@ +// Copyright 2026 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 "test/fixtures/generated_header/CDependency.h" + +@implementation GHCBox +@end diff --git a/test/fixtures/generated_header/ObjcConsumer.m b/test/fixtures/generated_header/ObjcConsumer.m new file mode 100644 index 000000000..48e96fc96 --- /dev/null +++ b/test/fixtures/generated_header/ObjcConsumer.m @@ -0,0 +1,19 @@ +// Copyright 2026 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 "test/fixtures/generated_header/generated_header_with_c_dep-Swift.h" + +void useGeneratedHeader(GHUsesCDependency *object, NSObject *value) { + (void)[object box:value]; +} diff --git a/test/fixtures/generated_header/UsesCDependency.swift b/test/fixtures/generated_header/UsesCDependency.swift new file mode 100644 index 000000000..804156e71 --- /dev/null +++ b/test/fixtures/generated_header/UsesCDependency.swift @@ -0,0 +1,23 @@ +// Copyright 2026 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 +import GeneratedHeaderCDependency + +@objc(GHUsesCDependency) +public class UsesCDependency: NSObject { + @objc public func box(_ value: NSObject) -> GHCBox { + fatalError("not implemented") + } +} diff --git a/test/generated_header_tests.bzl b/test/generated_header_tests.bzl index d09650da3..022597bd0 100644 --- a/test/generated_header_tests.bzl +++ b/test/generated_header_tests.bzl @@ -14,6 +14,7 @@ """Tests for `swift_library.generated_header`.""" +load("@bazel_skylib//rules:build_test.bzl", "build_test") load( "//test/rules:action_command_line_test.bzl", "make_action_command_line_test_rule", @@ -108,6 +109,15 @@ def generated_header_test_suite(name, tags = []): target_compatible_with = ["@platforms//os:macos"], ) + build_test( + name = "{}_objc_consumer_finds_generated_header_imports".format(name), + targets = [ + "//test/fixtures/generated_header:objc_consumer_of_generated_header", + ], + tags = all_tags, + target_compatible_with = ["@platforms//os:macos"], + ) + # Verify that no generated header is created if the target doesn't request # it. provider_test(