From 8ee21e2422dc1dc8150bf4c6c86808256b3080a7 Mon Sep 17 00:00:00 2001 From: Mathieu Olivari Date: Thu, 4 Sep 2025 21:37:51 -0700 Subject: [PATCH] feat(examples): make -cxx-interoperability-mode a feature -cxx-interoperability-mode currently needs to be passed as copts to targets who depend on C++ code, as seen in examples/xplatform/cxx_from_swift. This works in simple cases, but it currently fails if the `swift_symbol_graph_aspect` is applied on this target, as copts are not propagated to this action (rightfully, as not all copts will work). So in order to make it work, we're turning this flag into a feature, and we add corresponding action configs to both the compile action and to the symbol_graph_extract action. We're also enhancing the cxx_from_swift test by testing for this case. We're doing so by doing the following changes: * we're adding a swift_library() between the swift_binary() and the cc_library() targets * we're adding a new swift_extract_symbol_graph() target that depends on this new library This test will fail if -cxx-interoperability-mode=default is not passed to swift-symbolgraph-extract. --- examples/xplatform/cxx_from_swift/BUILD | 24 ++++++++++-- .../xplatform/cxx_from_swift/Counter.swift | 11 ++++++ examples/xplatform/cxx_from_swift/counter.h | 2 - examples/xplatform/cxx_from_swift/main.swift | 2 +- swift/internal/feature_names.bzl | 7 ++++ swift/toolchains/config/compile_config.bzl | 39 +++++++++++++++++++ .../toolchains/config/symbol_graph_config.bzl | 38 +++++++++++++++++- 7 files changed, 116 insertions(+), 7 deletions(-) create mode 100644 examples/xplatform/cxx_from_swift/Counter.swift diff --git a/examples/xplatform/cxx_from_swift/BUILD b/examples/xplatform/cxx_from_swift/BUILD index 7b4416de6..101b6cbe6 100644 --- a/examples/xplatform/cxx_from_swift/BUILD +++ b/examples/xplatform/cxx_from_swift/BUILD @@ -1,6 +1,8 @@ load("@rules_cc//cc:cc_library.bzl", "cc_library") load("//swift:swift_binary.bzl", "swift_binary") +load("//swift:swift_extract_symbol_graph.bzl", "swift_extract_symbol_graph") load("//swift:swift_interop_hint.bzl", "swift_interop_hint") +load("//swift:swift_library.bzl", "swift_library") licenses(["notice"]) @@ -21,7 +23,18 @@ swift_interop_hint( module_name = "CxxCounter", ) -# 2. The Swift binary then depends on the `cc_library`. This causes a +# 2. The Swift library then depends on the `cc_library`. This causes a +# Swift-compatible module map to be created for the `cc_library` so that the +# Swift code can import it. +swift_library( + name = "swift_counter", + srcs = ["Counter.swift"], + features = ["swift.enable_cpp20_interop"], + module_name = "Counter", + deps = [":counter"], +) + +# 3. The Swift binary then depends on the `cc_library`. This causes a # Swift-compatible module map to be created for the `cc_library` so that the # Swift code can import it. Be sure to enable C++ Interoperability in the Swift # compiler using the `-cxx-interoperability-mode` build flag. @@ -29,7 +42,12 @@ swift_interop_hint( swift_binary( name = "cxx_from_swift", srcs = ["main.swift"], - copts = ["-cxx-interoperability-mode=default"], + features = ["swift.enable_cpp20_interop"], module_name = "main", - deps = [":counter"], + deps = [":swift_counter"], +) + +swift_extract_symbol_graph( + name = "symbol_graph", + targets = [":swift_counter"], ) diff --git a/examples/xplatform/cxx_from_swift/Counter.swift b/examples/xplatform/cxx_from_swift/Counter.swift new file mode 100644 index 000000000..b2f163aba --- /dev/null +++ b/examples/xplatform/cxx_from_swift/Counter.swift @@ -0,0 +1,11 @@ +// Import the C++ interface. +@_exported import CxxCounter + +/// Wraps the C++ interface in a Swift interface. +extension swiftexample.Counter { + + mutating public func Decrement() { + count_ = count_ - 1 + } + +} diff --git a/examples/xplatform/cxx_from_swift/counter.h b/examples/xplatform/cxx_from_swift/counter.h index 8e533835e..a61f5a5a2 100644 --- a/examples/xplatform/cxx_from_swift/counter.h +++ b/examples/xplatform/cxx_from_swift/counter.h @@ -18,8 +18,6 @@ class Counter { public: int Get() const; void Increment(); - - private: int count_ = 0; }; diff --git a/examples/xplatform/cxx_from_swift/main.swift b/examples/xplatform/cxx_from_swift/main.swift index eca75e7a1..a13cf2121 100644 --- a/examples/xplatform/cxx_from_swift/main.swift +++ b/examples/xplatform/cxx_from_swift/main.swift @@ -13,7 +13,7 @@ // limitations under the License. // Import the C++ interface. -import CxxCounter +import Counter var counter = swiftexample.Counter() for _ in 1...10 { diff --git a/swift/internal/feature_names.bzl b/swift/internal/feature_names.bzl index 3242857a4..8bb080b21 100644 --- a/swift/internal/feature_names.bzl +++ b/swift/internal/feature_names.bzl @@ -399,3 +399,10 @@ SWIFT_FEATURE_THIN_LTO = "swift.thin_lto" # Enable full LTO and update output-file-map correctly SWIFT_FEATURE_FULL_LTO = "swift.full_lto" + +# Enables swift cpp interop. When enabled, this feature adds -cxx-interoperability-mode=default +# along with the corresponding -std=c++ options. Use this when swift needs to imports a module +# that has C++ headers. +SWIFT_FEATURE_ENABLE_CPP17_INTEROP = "swift.enable_cpp17_interop" +SWIFT_FEATURE_ENABLE_CPP20_INTEROP = "swift.enable_cpp20_interop" +SWIFT_FEATURE_ENABLE_CPP23_INTEROP = "swift.enable_cpp23_interop" diff --git a/swift/toolchains/config/compile_config.bzl b/swift/toolchains/config/compile_config.bzl index b8f6c5dc2..6539f0ffc 100644 --- a/swift/toolchains/config/compile_config.bzl +++ b/swift/toolchains/config/compile_config.bzl @@ -53,6 +53,9 @@ load( "SWIFT_FEATURE_EMIT_SWIFTINTERFACE", "SWIFT_FEATURE_ENABLE_BARE_SLASH_REGEX", "SWIFT_FEATURE_ENABLE_BATCH_MODE", + "SWIFT_FEATURE_ENABLE_CPP17_INTEROP", + "SWIFT_FEATURE_ENABLE_CPP20_INTEROP", + "SWIFT_FEATURE_ENABLE_CPP23_INTEROP", "SWIFT_FEATURE_ENABLE_LIBRARY_EVOLUTION", "SWIFT_FEATURE_ENABLE_SKIP_FUNCTION_BODIES", "SWIFT_FEATURE_ENABLE_TESTING", @@ -1241,6 +1244,42 @@ def compile_action_configs( SWIFT_FEATURE__SUPPORTS_V6, ], ), + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + ], + configurators = [ + add_arg("-cxx-interoperability-mode=default"), + add_arg("-Xcc", "-std=c++17"), + ], + features = [ + SWIFT_FEATURE_ENABLE_CPP17_INTEROP, + ], + ), + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + ], + configurators = [ + add_arg("-cxx-interoperability-mode=default"), + add_arg("-Xcc", "-std=c++20"), + ], + features = [ + SWIFT_FEATURE_ENABLE_CPP20_INTEROP, + ], + ), + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + ], + configurators = [ + add_arg("-cxx-interoperability-mode=default"), + add_arg("-Xcc", "-std=c++23"), + ], + features = [ + SWIFT_FEATURE_ENABLE_CPP23_INTEROP, + ], + ), ] # NOTE: The positions of these action configs in the list are important, diff --git a/swift/toolchains/config/symbol_graph_config.bzl b/swift/toolchains/config/symbol_graph_config.bzl index 3d09ceab3..fa3b05cad 100644 --- a/swift/toolchains/config/symbol_graph_config.bzl +++ b/swift/toolchains/config/symbol_graph_config.bzl @@ -18,7 +18,13 @@ load( "//swift/internal:action_names.bzl", "SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT", ) -load(":action_config.bzl", "ActionConfigInfo") +load( + "//swift/internal:feature_names.bzl", + "SWIFT_FEATURE_ENABLE_CPP17_INTEROP", + "SWIFT_FEATURE_ENABLE_CPP20_INTEROP", + "SWIFT_FEATURE_ENABLE_CPP23_INTEROP", +) +load(":action_config.bzl", "ActionConfigInfo", "add_arg") def symbol_graph_action_configs(): """Returns the list of action configs needed to extract symbol graphs. @@ -45,6 +51,36 @@ def symbol_graph_action_configs(): _symbol_graph_emit_extension_block_symbols_configurator, ], ), + ActionConfigInfo( + actions = [SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT], + configurators = [ + add_arg("-cxx-interoperability-mode=default"), + add_arg("-Xcc", "-std=c++17"), + ], + features = [ + SWIFT_FEATURE_ENABLE_CPP17_INTEROP, + ], + ), + ActionConfigInfo( + actions = [SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT], + configurators = [ + add_arg("-cxx-interoperability-mode=default"), + add_arg("-Xcc", "-std=c++20"), + ], + features = [ + SWIFT_FEATURE_ENABLE_CPP20_INTEROP, + ], + ), + ActionConfigInfo( + actions = [SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT], + configurators = [ + add_arg("-cxx-interoperability-mode=default"), + add_arg("-Xcc", "-std=c++23"), + ], + features = [ + SWIFT_FEATURE_ENABLE_CPP23_INTEROP, + ], + ), ] def _symbol_graph_minimum_access_level_configurator(prerequisites, args):