Skip to content

Commit

Permalink
CXX-Interop: Fix missing header deps edge
Browse files Browse the repository at this point in the history
The custom target dependency was an order-only dependency edge. As a
result, changing the swift file wouldn't result in the header getting
regenerated at the right time because nothing actually depended on it
being up-to-date. This patch should fix that and ties it into the
`fibonacci` target a little more cleanly. The generated header is marked
as being one of the target sources, so the target itself depends on the
header getting built. This ensures that the C++ file gets rebuilt if the
header changes. The header still depends on the Swift sources in the
target. We're now extracting that list directly from the target itself
instead of needing to pass it in explicitly. The module is also
extracted from the target itself. We're also automatically adding the
location of the header include directory so that dependees can find it
as part of the target interface.

Fixes #8
  • Loading branch information
etcwilde committed Apr 20, 2024
1 parent 7a86d39 commit 25f01fe
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 55 deletions.
68 changes: 44 additions & 24 deletions 3_bidirectional_cxx_interop/cmake/modules/AddSwift.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,28 @@
#
# See https://swift.org/LICENSE.txt for license information

include(CheckCompilerFlag)

# Generate bridging header from Swift to C++
# NOTE: This logic will eventually be upstreamed into CMake
function(_swift_generate_cxx_header_target target module header)
cmake_parse_arguments(ARG "" "" "SOURCES;SEARCH_PATHS;DEPENDS" ${ARGN})
if(NOT ARG_SOURCES)
message(FATAL_ERROR "No sources provided to 'swift_generate_cxx_header_target'")

# Generate the bridging header from Swift to C++
#
# target: the name of the target to generate headers for.
# This target must build swift source files.
# header: the name of the header file to generate.
#
# NOTE: This logic will eventually be unstreamed into CMake.
function(_swift_generate_cxx_header target header)
if(NOT TARGET ${target})
message(FATAL_ERROR "Target ${target} not defined.")
endif()

if(NOT DEFINED CMAKE_Swift_COMPILER)
message(WARNING "Swift not enabled in project. Cannot generate headers for Swift files.")
return()
endif()

cmake_parse_arguments(ARG "" "" "SEARCH_PATHS;MODULE_NAME" ${ARGN})

if(NOT ARG_MODULE_NAME)
set(ARG_MODULE_NAME $<TARGET_PROPERTY:${target},Swift_MODULE_NAME>)
endif()

if(ARG_SEARCH_PATHS)
Expand All @@ -23,27 +37,33 @@ function(_swift_generate_cxx_header_target target module header)
set(SDK_FLAGS "-sdk" "${CMAKE_OSX_SYSROOT}")
elseif(WIN32)
set(SDK_FLAGS "-sdk" "$ENV{SDKROOT}")
elseif(DEFINED ${CMAKE_SYSROOT})
set(SDK_FLAGS "-sdk" "${CMAKE_SYSROOT}")
endif()

add_custom_command(
OUTPUT
"${header}"
cmake_path(APPEND CMAKE_CURRENT_BINARY_DIR include
OUTPUT_VARIABLE base_path)

cmake_path(APPEND base_path ${header}
OUTPUT_VARIABLE header_path)

set(_AllSources $<TARGET_PROPERTY:${target},SOURCES>)
set(_SwiftSources $<FILTER:${_AllSources},INCLUDE,\\.swift$> )
add_custom_command(OUTPUT ${header_path}
DEPENDS ${_SwiftSources}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND
${CMAKE_Swift_COMPILER} -frontend -typecheck
${ARG_SEARCH_PATHS}
${ARG_SOURCES}
${_SwiftSources}
${SDK_FLAGS}
-module-name "${module}"
-module-name "${ARG_MODULE_NAME}"
-cxx-interoperability-mode=default
-emit-clang-header-path "${header}"
DEPENDS
${ARG_DEPENDS}
COMMENT
"Generating '${header}'"
)

add_custom_target("${target}"
DEPENDS
"${header}"
)
-emit-clang-header-path ${header_path})

# Added to public interface for dependees to find.
target_include_directories(${target} PUBLIC ${base_path})
# Added to the target to ensure target rebuilds if header changes and is used
# by sources in the target.
target_sources(${target} PRIVATE ${header_path})
endfunction()
40 changes: 9 additions & 31 deletions 3_bidirectional_cxx_interop/lib/fibonacci/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,16 @@
#
# See https://swift.org/LICENSE.txt for license information


# Generate a C++ header from Swift sources
#
# This function is implemented in cmake/modules/AddSwift.cmake.
#
# _swift_generate_cxx_header_target(target-name,
# SwiftModule/C++ namespace,
# generated header path)
_swift_generate_cxx_header_target(
fibonacci_swift_h
SwiftFibonacci
"${CMAKE_CURRENT_BINARY_DIR}/include/fibonacci/fibonacci-swift.h"
SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/fibonacci.swift"
SEARCH_PATHS "${PINGPONG_INCLUDE_DIR}")

# 1. Create a library from the Swift and C++ sources.
# 2. The library requires the Swift header in order to compile, so we create a
# dependency between the library and the header target created above.
# 3. This libraries, and users of this library, will need to find the
# generated header, so we direct CMake to emit `PUBLIC` a public header
# search path, ensuring that dependees of this library also pick up this
# search path.
# 4. Manually override the Swift module name to "SwiftFibonacci" to match the
# name in the generated header header above.
# 5. Enable C++ interoperability mode on all Swift compilations. Again, this is
# required for users of this library, so we make it 'PUBLIC' to ensure the
# flag is propagated to users of the library. Emitting the flag is gated by
# the COMPILE_LANGUAGE cmake generator expression to ensure that the flag is
# only passed to the Swift compiler and not the C++ compiler.
add_library(fibonacci STATIC fibonacci.swift fibonacci.cpp)
add_dependencies(fibonacci fibonacci_swift_h)
target_include_directories(fibonacci PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/include")
set_target_properties(fibonacci PROPERTIES Swift_MODULE_NAME "SwiftFibonacci")
target_compile_options(fibonacci PUBLIC
"$<$<COMPILE_LANGUAGE:Swift>:-cxx-interoperability-mode=default>")

# Generate a C++ header from Swift sources. This is automatically added to the
# fibonacci target. The target will regenerate the header file when any of the
# Swift sources change. Clang detects that the C++ file depends on the header,
# and tells Ninja about this dependency in the depfile.
# This function is implemented in cmake/modules/AddSwift.cmake.
_swift_generate_cxx_header(fibonacci
fibonacci/fibonacci-swift.h
SEARCH_PATHS "${PINGPONG_INCLUDE_DIR}")

0 comments on commit 25f01fe

Please sign in to comment.