Skip to content

Commit

Permalink
Add feature to propagate the generated module map
Browse files Browse the repository at this point in the history
Allows `objc_library` to modularly import `swift_library` targets without having to generate a similar module map.
  • Loading branch information
brentleyjones committed Jun 14, 2024
1 parent ea2d4bd commit 5dba983
Show file tree
Hide file tree
Showing 9 changed files with 185 additions and 4 deletions.
40 changes: 40 additions & 0 deletions examples/apple/objc_interop_modulemap/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# This example tests that Swift code can be called from Objective-C code and
# vice versa when it is linked into the existing native linking rules for Apple
# platforms.

load(
"//swift:swift.bzl",
"swift_binary",
"swift_library",
)

licenses(["notice"])

objc_library(
name = "PrintStream",
srcs = ["OIPrintStream.m"],
hdrs = ["OIPrintStream.h"],
target_compatible_with = ["@platforms//os:macos"],
)

swift_library(
name = "Printer",
srcs = ["Printer.swift"],
# features = ["swift.propagate_generated_module_map"],
generated_header_name = "generated_header/Printer-Swift.h",
generates_header = True,
deps = [":PrintStream"],
)

objc_library(
name = "main",
srcs = ["main.m"],
enable_modules = True,
target_compatible_with = ["@platforms//os:macos"],
deps = [":Printer"],
)

swift_binary(
name = "objc_interop_modulemap",
deps = [":main"],
)
24 changes: 24 additions & 0 deletions examples/apple/objc_interop_modulemap/OIPrintStream.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// 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.

#import <Foundation/Foundation.h>

/** A very contrived interface for writing strings to a file handle. */
@interface OIPrintStream : NSObject

- (nonnull instancetype)initWithFileHandle:(nonnull NSFileHandle *)fileHandle;

- (void)printString:(nonnull NSString *)message;

@end
35 changes: 35 additions & 0 deletions examples/apple/objc_interop_modulemap/OIPrintStream.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// 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.

#import "examples/apple/objc_interop_modulemap/OIPrintStream.h"

@implementation OIPrintStream {
NSFileHandle *_fileHandle;
}

- (instancetype)initWithFileHandle:(nonnull NSFileHandle *)fileHandle {
if (self = [super init]) {
_fileHandle = fileHandle;
}
return self;
}

- (void)printString:(nonnull NSString *)message {
NSData *data = [message dataUsingEncoding:NSUTF8StringEncoding];
[_fileHandle writeData:data];
NSData *newline = [NSData dataWithBytes:"\n" length:1];
[_fileHandle writeData:newline];
}

@end
32 changes: 32 additions & 0 deletions examples/apple/objc_interop_modulemap/Printer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// 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.

import Foundation
import examples_apple_objc_interop_modulemap_PrintStream

@objc(OIPrinter)
public class Printer: NSObject {

private let stream: OIPrintStream
private let prefix: String

@objc public init(prefix: NSString) {
self.stream = OIPrintStream(fileHandle: .standardOutput)
self.prefix = prefix as String
}

@objc public func print(_ message: NSString) {
stream.print("\(prefix)\(message)")
}
}
23 changes: 23 additions & 0 deletions examples/apple/objc_interop_modulemap/main.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// 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.

@import examples_apple_objc_interop_modulemap_Printer;

int main(int argc, char **argv) {
@autoreleasepool {
OIPrinter *printer = [[OIPrinter alloc] initWithPrefix:@"*** "];
[printer print:@"Hello world"];
}
return 0;
}
19 changes: 18 additions & 1 deletion swift/internal/compiling.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ load(
"SWIFT_FEATURE_OPT",
"SWIFT_FEATURE_OPT_USES_OSIZE",
"SWIFT_FEATURE_OPT_USES_WMO",
"SWIFT_FEATURE_PROPAGATE_GENERATED_MODULE_MAP",
"SWIFT_FEATURE_REWRITE_GENERATED_HEADER",
"SWIFT_FEATURE_SPLIT_DERIVED_FILES_GENERATION",
"SWIFT_FEATURE_SUPPORTS_BARE_SLASH_REGEX",
Expand Down Expand Up @@ -2642,6 +2643,17 @@ to use swift_common.compile(include_dev_srch_paths = ...) instead.\
transitive_modules = transitive_modules,
)

includes = []
public_hdrs = []
if compile_outputs.generated_header_file:
public_hdrs = [compile_outputs.generated_header_file]
if compile_outputs.generated_module_map_file and is_feature_enabled(
feature_configuration = feature_configuration,
feature_name = SWIFT_FEATURE_PROPAGATE_GENERATED_MODULE_MAP,
):
public_hdrs.append(compile_outputs.generated_module_map_file)
includes = [compile_outputs.generated_module_map_file.dirname]

module_context = create_module(
name = module_name,
clang = create_clang_module(
Expand All @@ -2650,7 +2662,8 @@ to use swift_common.compile(include_dev_srch_paths = ...) instead.\
defines = defines,
deps = deps,
feature_configuration = feature_configuration,
public_hdrs = compact([compile_outputs.generated_header_file]),
includes = includes,
public_hdrs = public_hdrs,
swift_toolchain = swift_toolchain,
target_name = target_name,
),
Expand Down Expand Up @@ -2859,6 +2872,7 @@ def _create_cc_compilation_context(
defines,
deps,
feature_configuration,
includes,
public_hdrs,
swift_toolchain,
target_name):
Expand All @@ -2878,6 +2892,8 @@ def _create_cc_compilation_context(
`SwiftInfo`, or `apple_common.Objc`.
feature_configuration: A feature configuration obtained from
`swift_common.configure_features`.
includes: Include paths that should be propagated by the new compilation
context.
public_hdrs: Public headers that should be propagated by the new
compilation context (for example, the module's generated header).
swift_toolchain: The `SwiftToolchainInfo` provider of the toolchain.
Expand Down Expand Up @@ -2912,6 +2928,7 @@ def _create_cc_compilation_context(
feature_configuration = feature_configuration,
),
name = target_name,
includes = includes,
public_hdrs = public_hdrs,
)
return compilation_context
Expand Down
7 changes: 6 additions & 1 deletion swift/internal/derived_files.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,12 @@ def _module_map(actions, target_name):
Returns:
The declared `File`.
"""
return actions.declare_file("{}.swift.modulemap".format(target_name))

# Path is two directories deep to avoid automatic discovery by
# `-fimplicit-module-maps` and with non-related include paths
return actions.declare_file(
"{}_modulemap/_/module.modulemap".format(target_name),
)

def _modulewrap_object(actions, target_name):
"""Declares the object file used to wrap Swift modules for ELF binaries.
Expand Down
5 changes: 5 additions & 0 deletions swift/internal/feature_names.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,11 @@ SWIFT_FEATURE_NO_ASAN_VERSION_CHECK = "swift.no_asan_version_check"
# the target is not generating a header.
SWIFT_FEATURE_NO_GENERATED_MODULE_MAP = "swift.no_generated_module_map"

# If enabled, the generates module map is named `module.modulemap` and
# the parent directory is added as to `CcInfo.compliation_context.includes`.
# This allows `objc_library` to import the Swift module.
SWIFT_FEATURE_PROPAGATE_GENERATED_MODULE_MAP = "swift.propagate_generated_module_map"

# If enabled, builds using the "opt" compilation mode will invoke `swiftc` with
# the `-whole-module-optimization` flag (in addition to `-O`).
SWIFT_FEATURE_OPT_USES_WMO = "swift.opt_uses_wmo"
Expand Down
4 changes: 2 additions & 2 deletions test/private_deps_tests.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ def private_deps_test_suite(name):
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_modulemap/_/module.modulemap",
"-/test/fixtures/private_deps/private_cc_modulemap_/module.modulemap",
],
field = "transitive_modules.clang!.module_map!",
provider = "SwiftInfo",
Expand Down

0 comments on commit 5dba983

Please sign in to comment.