diff --git a/CMakeLists.txt b/CMakeLists.txt index ff669fbfb89..333dc8c62f9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,10 +8,25 @@ cmake_minimum_required(VERSION 3.19.6) +if(POLICY CMP0157) + cmake_policy(SET CMP0157 NEW) +endif() + list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) project(SwiftSyntax LANGUAGES C Swift) +if(CMAKE_Swift_COMPILATION_MODE_DEFAULT) + # Modern way of doing split builds with CMake 3.29+. This allows us to get proper module + # dependencies and avoid the workaround in AddSwiftHostLibrary.cmake. + set(SWIFT_SYNTAX_USE_SPLIT_BUILD TRUE) +else() + # Legacy way of doing split builds, which is to build the module in a separate target and then + # link to it. This is necessary for CMake versions before 3.29, which don't have proper support + # for Swift module dependencies. + set(SWIFT_SYNTAX_USE_SPLIT_BUILD FALSE) +endif() + set(SWIFT_VERSION 5) set(CMAKE_Swift_LANGUAGE_VERSION ${SWIFT_VERSION}) @@ -37,9 +52,11 @@ endif() set(CMAKE_MACOSX_RPATH YES) -option(SWIFT_SYNTAX_ENABLE_WMO_PRE_3_26 - "Enable Whole Module Optimization (WMO) - requires swift-driver" - $>,$>,YES,NO>) +if(NOT SWIFT_SYNTAX_USE_SPLIT_BUILD) + option(SWIFT_SYNTAX_ENABLE_WMO_PRE_3_26 + "Enable Whole Module Optimization (WMO) - requires swift-driver" + $>,$>,YES,NO>) +endif() include(AddSwiftHostLibrary) include(SwiftCompilerCapability) diff --git a/cmake/modules/AddSwiftHostLibrary.cmake b/cmake/modules/AddSwiftHostLibrary.cmake index 4c4b6e0b977..b6a0e46b3e5 100644 --- a/cmake/modules/AddSwiftHostLibrary.cmake +++ b/cmake/modules/AddSwiftHostLibrary.cmake @@ -26,26 +26,28 @@ function(target_link_swift_syntax_libraries TARGET) target_link_libraries(${TARGET} ${link_type} ${dependencies}) - # cmake generation for Swift adds an order only dependency, which matches how C-family languages - # works. In that case, however, ninja (and presumably other generators) will rebuild on header - # changes. That's not the case for Swift, and thus if A -> B, A is not being rebuilt when the - # ABI/API of B changes. - # - # For now workaround this by touching a file whenever B is rebuilt and then compiling that file as - # part of A. Ideally this file would be generated by each of the targets, but that dependency didn't - # seem to be being tracked. - # - # Remove once rdar://102202478 is fixed. - foreach(DEPENDENCY ${dependencies}) - string(REGEX REPLACE [<>:\"/\\|?*] _ sanitized ${DEPENDENCY}) - add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/forced-${sanitized}-dep.swift - COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/forced-${sanitized}-dep.swift - DEPENDS ${DEPENDENCY} - ) - target_sources(${TARGET} PRIVATE - ${CMAKE_CURRENT_BINARY_DIR}/forced-${sanitized}-dep.swift - ) - endforeach() + if(NOT SWIFT_SYNTAX_USE_SPLIT_BUILD) + # cmake generation for Swift adds an order only dependency, which matches how C-family languages + # work. In that case, however, ninja (and presumably other generators) will rebuild on header + # changes. That's not the case for Swift, and thus if A -> B, A is not being rebuilt when the + # ABI/API of B changes. + # + # For now workaround this by touching a file whenever B is rebuilt and then compiling that file as + # part of A. Ideally this file would be generated by each of the targets, but that dependency didn't + # seem to be being tracked. + # + # Remove once rdar://102202478 is fixed. + foreach(DEPENDENCY ${dependencies}) + string(REGEX REPLACE [=[[<>:"/\|?*]]=] _ sanitized ${DEPENDENCY}) + add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/forced-${sanitized}-dep.swift + COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/forced-${sanitized}-dep.swift + DEPENDS ${DEPENDENCY} + ) + target_sources(${TARGET} PRIVATE + ${CMAKE_CURRENT_BINARY_DIR}/forced-${sanitized}-dep.swift + ) + endforeach() + endif() endfunction() # Add a new host library with the given name. @@ -67,14 +69,6 @@ function(add_swift_syntax_library name) set(module_file "${module_base}/${SWIFT_HOST_MODULE_TRIPLE}.swiftmodule") set(module_interface_file "${module_base}/${SWIFT_HOST_MODULE_TRIPLE}.swiftinterface") set(module_private_interface_file "${module_base}/${SWIFT_HOST_MODULE_TRIPLE}.private.swiftinterface") - set(module_sourceinfo_file "${module_base}/${SWIFT_HOST_MODULE_TRIPLE}.swiftsourceinfo") - - # Add a custom target to create the module directory. - add_custom_command( - TARGET ${target} - PRE_BUILD - COMMAND "${CMAKE_COMMAND}" -E make_directory ${module_base} - COMMENT "Generating module directory for ${target}") # Configure the emission of the Swift module files. target_compile_options("${target}" PRIVATE @@ -82,7 +76,6 @@ function(add_swift_syntax_library name) -DRESILIENT_LIBRARIES; -enable-library-evolution; -emit-module-path;${module_file}; - -emit-module-source-info-path;${module_sourceinfo_file}; -emit-module-interface-path;${module_interface_file}; -emit-private-module-interface-path;${module_private_interface_file} >) @@ -106,43 +99,64 @@ function(add_swift_syntax_library name) else() set(module_dir ${CMAKE_CURRENT_BINARY_DIR}) set(module_base "${module_dir}/${name}.swiftmodule") - set(module_file "${module_file}") endif() - # Touch the library and objects to workaround their mtime not being updated - # when there are no real changes (eg. a file was updated with a comment). - # Ideally this should be done in the driver, which could only update the - # files that have changed. - add_custom_command( - TARGET ${target} - POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E touch_nocreate $ "${module_base}" - COMMAND_EXPAND_LISTS - COMMENT "Update mtime of library outputs workaround") - add_custom_command( - TARGET ${target} - POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E touch_nocreate $ - COMMAND_EXPAND_LISTS - COMMENT "Update mtime of objcect files workaround") - set_target_properties(${target} PROPERTIES Swift_MODULE_NAME ${name} Swift_MODULE_DIRECTORY ${module_dir} INTERFACE_INCLUDE_DIRECTORIES ${module_dir} ) - # Configure the emission of the Swift module files. target_compile_options("${target}" PRIVATE $<$: - "SHELL:-module-name ${name}" "SHELL:-Xfrontend -module-abi-name -Xfrontend ${SWIFT_MODULE_ABI_NAME_PREFIX}${name}" - "-no-emit-module-separately-wmo" + >) + + if(NOT SWIFT_SYNTAX_USE_SPLIT_BUILD) + # Legacy build configuration. + if(SWIFTSYNTAX_EMIT_MODULE) + set(module_sourceinfo_file "${module_base}/${SWIFT_HOST_MODULE_TRIPLE}.swiftsourceinfo") + + # Add a custom target to create the module directory. + add_custom_command( + TARGET ${target} + PRE_BUILD + COMMAND "${CMAKE_COMMAND}" -E make_directory ${module_base} + COMMENT "Generating module directory for ${target}") + + # Configure the emission of the Swift module files. + target_compile_options("${target}" PRIVATE + $<$: + -emit-module-source-info-path;${module_sourceinfo_file}; + >) + endif() + + # Touch the library and objects to workaround their mtime not being updated + # when there are no real changes (eg. a file was updated with a comment). + add_custom_command( + TARGET ${target} + POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E touch_nocreate $ "${module_base}" + COMMAND_EXPAND_LISTS + COMMENT "Update mtime of library outputs workaround") + add_custom_command( + TARGET ${target} + POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E touch_nocreate $ + COMMAND_EXPAND_LISTS + COMMENT "Update mtime of object files workaround") + + # Configure the emission of the Swift module files. + target_compile_options("${target}" PRIVATE + $<$: + "SHELL:-module-name ${name}" + "-no-emit-module-separately-wmo" >) - if(CMAKE_VERSION VERSION_LESS 3.26.0 AND SWIFT_SYNTAX_ENABLE_WMO_PRE_3_26) - target_compile_options(${target} PRIVATE - $<$:-wmo>) + if(CMAKE_VERSION VERSION_LESS 3.26.0 AND SWIFT_SYNTAX_ENABLE_WMO_PRE_3_26) + target_compile_options(${target} PRIVATE + $<$:-wmo>) + endif() endif() target_compile_options(${target} PRIVATE @@ -155,11 +169,6 @@ function(add_swift_syntax_library name) ) endif() - # NOTE: workaround for CMake not setting up include flags yet - set_target_properties(${target} PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES ${module_dir} - ) - set_target_properties(${target} PROPERTIES BUILD_WITH_INSTALL_RPATH YES )