diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst index b9cf81ac13..c960828aca 100644 --- a/Help/manual/cmake-policies.7.rst +++ b/Help/manual/cmake-policies.7.rst @@ -98,6 +98,7 @@ Policies Introduced by CMake 4.1 .. toctree:: :maxdepth: 1 + CMP0195: Swift modules in build trees use the Swift module directory structure. CMP0194: MSVC is not an assembler for language ASM. CMP0193: GNUInstallDirs caches CMAKE_INSTALL_* with leading 'usr/' for install prefix '/'. CMP0192: GNUInstallDirs uses absolute SYSCONFDIR, LOCALSTATEDIR, and RUNSTATEDIR in special prefixes. diff --git a/Help/policy/CMP0195.rst b/Help/policy/CMP0195.rst new file mode 100644 index 0000000000..09f81aaa61 --- /dev/null +++ b/Help/policy/CMP0195.rst @@ -0,0 +1,27 @@ +CMP0195 +------- + +.. versionadded:: 4.1 + +Swift modules in build trees use the Swift module directory structure. + +The Swift compiler emits several supplementary files that make up the +interface to a Swift library. It accepts finding these files separately +or in a single swiftmodule directory. The single file keeps things better +organized and makes it easier to install the resulting products. + +CMake versions 4.1 and above prefer to generate the modules in the +directory structure when working with a new enough Swift compiler. +This policy provides compatibility for projects that have not been +updated to expect the new behavior. + +The ``OLD`` behavior for this policy is to emit the interface files directly +into the current binary directory. +The ``NEW`` behavior for this policy is to gather the binary swiftmodule and +other supplemental compiler outputs in a single Swift module directory. + +.. |INTRODUCED_IN_CMAKE_VERSION| replace:: 4.1 +.. |WARNS_OR_DOES_NOT_WARN| replace:: does *not* warn +.. include:: include/STANDARD_ADVICE.rst + +.. include:: include/DEPRECATED.rst diff --git a/Modules/CMakeDetermineSwiftCompiler.cmake b/Modules/CMakeDetermineSwiftCompiler.cmake index a7dc1500e4..6d46e78f07 100644 --- a/Modules/CMakeDetermineSwiftCompiler.cmake +++ b/Modules/CMakeDetermineSwiftCompiler.cmake @@ -126,6 +126,19 @@ elseif(NOT DEFINED CMAKE_Swift_COMPILER_USE_OLD_DRIVER) unset(_CMAKE_Swift_COMPILER_CHECK_OUTPUT) endif() +if(CMAKE_Swift_COMPILER_VERSION VERSION_GREATER_EQUAL 5.2) + set(target_info_command "${CMAKE_Swift_COMPILER}" -print-target-info) + if(CMAKE_Swift_COMPILER_TARGET) + list(APPEND target_info_command -target ${CMAKE_Swift_COMPILER_TARGET}) + endif() + execute_process( + COMMAND ${target_info_command} + OUTPUT_VARIABLE swift_target_info) + message(CONFIGURE_LOG "Swift target info:\n" "${swift_target_info}") + string(JSON module_triple GET "${swift_target_info}" "target" "moduleTriple") + set(CMAKE_Swift_MODULE_TRIPLE ${module_triple}) +endif() + if (NOT _CMAKE_TOOLCHAIN_LOCATION) get_filename_component(_CMAKE_TOOLCHAIN_LOCATION "${CMAKE_Swift_COMPILER}" PATH) endif () diff --git a/Modules/CMakeSwiftCompiler.cmake.in b/Modules/CMakeSwiftCompiler.cmake.in index 92108804db..5e2483a02d 100644 --- a/Modules/CMakeSwiftCompiler.cmake.in +++ b/Modules/CMakeSwiftCompiler.cmake.in @@ -16,3 +16,5 @@ set(CMAKE_Swift_SOURCE_FILE_EXTENSIONS swift) set(CMAKE_Swift_COMPILER_USE_OLD_DRIVER "@CMAKE_Swift_COMPILER_USE_OLD_DRIVER@") set(CMAKE_Swift_IMPLICIT_INCLUDE_DIRECTORIES "@CMAKE_Swift_IMPLICIT_INCLUDE_DIRECTORIES@") + +set(CMAKE_Swift_MODULE_TRIPLE "@CMAKE_Swift_MODULE_TRIPLE@") diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 0f9ee97cb3..54f2fdccca 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -6002,8 +6002,15 @@ std::string cmGeneratorTarget::GetSwiftModuleName() const std::string cmGeneratorTarget::GetSwiftModuleFileName() const { - return this->GetPropertyOrDefault( + std::string moduleFilename = this->GetPropertyOrDefault( "Swift_MODULE", this->GetSwiftModuleName() + ".swiftmodule"); + if (this->GetPolicyStatusCMP0195() == cmPolicies::NEW) { + if (cmValue moduleTriple = + this->Makefile->GetDefinition("CMAKE_Swift_MODULE_TRIPLE")) { + moduleFilename += "/" + *moduleTriple + ".swiftmodule"; + } + } + return moduleFilename; } std::string cmGeneratorTarget::GetSwiftModuleDirectory( diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index 9b17f42416..c987e6fadd 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -580,7 +580,11 @@ class cmMakefile; "install prefix '/'.", \ 4, 1, 0, WARN) \ SELECT(POLICY, CMP194, "MSVC is not an assembler for language ASM.", 4, 1, \ - 0, WARN) + 0, WARN) \ + SELECT( \ + POLICY, CMP0195, \ + "Swift modules in build trees use the Swift module directory structure.", \ + 4, 1, 0, WARN) #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1) #define CM_FOR_EACH_POLICY_ID(POLICY) \ @@ -627,7 +631,8 @@ class cmMakefile; F(CMP0162) \ F(CMP0179) \ F(CMP0181) \ - F(CMP0182) + F(CMP0182) \ + F(CMP0195) #define CM_FOR_EACH_CUSTOM_COMMAND_POLICY(F) \ F(CMP0116) \ diff --git a/Tests/RunCMake/Swift/CMP0195-NEW-build-stdout.txt b/Tests/RunCMake/Swift/CMP0195-NEW-build-stdout.txt new file mode 100644 index 0000000000..94839b9056 --- /dev/null +++ b/Tests/RunCMake/Swift/CMP0195-NEW-build-stdout.txt @@ -0,0 +1 @@ +swiftc(.exe)? .* -emit-module -emit-module-path El(/|\\)((Debug|Release)(/|\\))?El\.swiftmodule(/|\\)[-_a-z0-9]+\.swiftmodule -module-name El diff --git a/Tests/RunCMake/Swift/CMP0195-NEW.cmake b/Tests/RunCMake/Swift/CMP0195-NEW.cmake new file mode 100644 index 0000000000..cf4ba38704 --- /dev/null +++ b/Tests/RunCMake/Swift/CMP0195-NEW.cmake @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 4.0) + +cmake_policy(SET CMP0195 NEW) +include(CMP0195-common.cmake) diff --git a/Tests/RunCMake/Swift/CMP0195-OLD-build-stdout.txt b/Tests/RunCMake/Swift/CMP0195-OLD-build-stdout.txt new file mode 100644 index 0000000000..1c0df06dd2 --- /dev/null +++ b/Tests/RunCMake/Swift/CMP0195-OLD-build-stdout.txt @@ -0,0 +1 @@ +swiftc(.exe)? .* -emit-module -emit-module-path El(/|\\)((Debug|Release)(/|\\))?El.swiftmodule -module-name El diff --git a/Tests/RunCMake/Swift/CMP0195-OLD.cmake b/Tests/RunCMake/Swift/CMP0195-OLD.cmake new file mode 100644 index 0000000000..b877c2fa8c --- /dev/null +++ b/Tests/RunCMake/Swift/CMP0195-OLD.cmake @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 4.0) + +cmake_policy(SET CMP0195 OLD) +include(CMP0195-common.cmake) diff --git a/Tests/RunCMake/Swift/CMP0195-common.cmake b/Tests/RunCMake/Swift/CMP0195-common.cmake new file mode 100644 index 0000000000..074e78c510 --- /dev/null +++ b/Tests/RunCMake/Swift/CMP0195-common.cmake @@ -0,0 +1,6 @@ +enable_language(Swift) + +add_library(L OBJECT L.swift) +set_target_properties(L PROPERTIES + Swift_MODULE_NAME El + Swift_MODULE_DIRECTORY El) diff --git a/Tests/RunCMake/Swift/CompileCommands-check.cmake b/Tests/RunCMake/Swift/CompileCommands-check.cmake index 0ce347a15f..5ab3b4b165 100644 --- a/Tests/RunCMake/Swift/CompileCommands-check.cmake +++ b/Tests/RunCMake/Swift/CompileCommands-check.cmake @@ -3,31 +3,32 @@ if(NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/compile_commands.json") return() endif() +set(ESCAPED_BINARY_DIR [==[[^ +]*/Tests/RunCMake/Swift/CompileCommands-build]==]) +set(E_SOURCE_PATH [==[(\\")?[^ +]*(/Tests/RunCMake/Swift/E.swift|\\\\Tests\\\\RunCMake\\\\Swift\\\\E.swift)(\\")?]==]) +set(L_SOURCE_PATH [==[(\\")?[^ +]*(/Tests/RunCMake/Swift/L.swift|\\\\Tests\\\\RunCMake\\\\Swift\\\\L.swift)(\\")?]==]) + # The compile command for both files should contain all Swift source files in # the module set(expected_compile_commands [==[^\[ { - "directory": "[^ -]*/Tests/RunCMake/Swift/CompileCommands-build", + "directory": "${BINARY_DIR}", "command": "[^ ]*swiftc[^ -]* (\\")?[^ -]*(/Tests/RunCMake/Swift/E.swift|\\\\Tests\\\\RunCMake\\\\Swift\\\\E.swift)(\\")? (\\")?[^ -]*(/Tests/RunCMake/Swift/L.swift|\\\\Tests\\\\RunCMake\\\\Swift\\\\L.swift)(\\")?", +]* ${E_SOURCE_PATH} ${L_SOURCE_PATH}", "file": "[^ ]*/Tests/RunCMake/Swift/E.swift", "output": "[^ ]*/CMakeFiles/CompileCommandLib.dir/(Debug/)?E.swift.(o|obj)" }, { - "directory": "[^ -]*/Tests/RunCMake/Swift/CompileCommands-build", + "directory": "${BINARY_DIR}", "command": "[^ ]*swiftc[^ -]* (\\")?[^ -]*(/Tests/RunCMake/Swift/E.swift|\\\\Tests\\\\RunCMake\\\\Swift\\\\E.swift)(\\")? (\\")?[^ -]*(/Tests/RunCMake/Swift/L.swift|\\\\Tests\\\\RunCMake\\\\Swift\\\\L.swift)(\\")?", +]* ${E_SOURCE_PATH} ${L_SOURCE_PATH}", "file": "[^ ]*/Tests/RunCMake/Swift/L.swift", "output": "[^ @@ -35,6 +36,10 @@ set(expected_compile_commands }]==] ) +string(REPLACE [=[${BINARY_DIR}]=] "${ESCAPED_BINARY_DIR}" expected_compile_commands "${expected_compile_commands}") +string(REPLACE [=[${E_SOURCE_PATH}]=] "${E_SOURCE_PATH}" expected_compile_commands "${expected_compile_commands}") +string(REPLACE [=[${L_SOURCE_PATH}]=] "${L_SOURCE_PATH}" expected_compile_commands "${expected_compile_commands}") + file(READ "${RunCMake_TEST_BINARY_DIR}/compile_commands.json" compile_commands) if(NOT compile_commands MATCHES "${expected_compile_commands}") string(REPLACE "\n" "\n " expected_compile_commands_formatted "${expected_compile_commands}") diff --git a/Tests/RunCMake/Swift/CompileCommands.cmake b/Tests/RunCMake/Swift/CompileCommands.cmake index f859693e17..f0a88dad2b 100644 --- a/Tests/RunCMake/Swift/CompileCommands.cmake +++ b/Tests/RunCMake/Swift/CompileCommands.cmake @@ -1,6 +1,10 @@ if(POLICY CMP0157) cmake_policy(SET CMP0157 NEW) endif() +if(POLICY CMP0195) + cmake_policy(SET CMP0195 NEW) +endif() + set(CMAKE_Swift_COMPILATION_MODE "singlefile") enable_language(Swift) diff --git a/Tests/RunCMake/Swift/NoWorkToDo.cmake b/Tests/RunCMake/Swift/NoWorkToDo.cmake index b58f8ffba8..750a40aece 100644 --- a/Tests/RunCMake/Swift/NoWorkToDo.cmake +++ b/Tests/RunCMake/Swift/NoWorkToDo.cmake @@ -1,4 +1,7 @@ cmake_policy(SET CMP0157 NEW) +if(POLICY CMP0195) + cmake_policy(SET CMP0195 NEW) +endif() enable_language(Swift) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/hello.swift "") diff --git a/Tests/RunCMake/Swift/RunCMakeTest.cmake b/Tests/RunCMake/Swift/RunCMakeTest.cmake index 716075e99f..63ad2323b7 100644 --- a/Tests/RunCMake/Swift/RunCMakeTest.cmake +++ b/Tests/RunCMake/Swift/RunCMakeTest.cmake @@ -30,6 +30,21 @@ block() endif() endblock() +if(RunCMake_GENERATOR MATCHES "Ninja.*") + block() + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CMP0195-NEW-build) + run_cmake(CMP0195-NEW) + set(RunCMake_TEST_NO_CLEAN 1) + run_cmake_command(CMP0195-NEW-build ${CMAKE_COMMAND} --build . -- -n -v) + endblock() + block() + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CMP0195-OLD-build) + run_cmake(CMP0195-OLD) + set(RunCMake_TEST_NO_CLEAN 1) + run_cmake_command(CMP0195-OLD-build ${CMAKE_COMMAND} --build . -- -n -v) + endblock() +endif() + block() set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/SwiftSimple-build) run_cmake(SwiftSimple) diff --git a/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt b/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt index 0e57ffd8cd..80f0047e4a 100644 --- a/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt +++ b/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt @@ -46,6 +46,7 @@ \* CMP0179 \* CMP0181 \* CMP0182 + \* CMP0195 Call Stack \(most recent call first\): CMakeLists.txt:3 \(include\) diff --git a/Tests/SwiftOnly/CMakeLists.txt b/Tests/SwiftOnly/CMakeLists.txt index 494a9bf51f..01243848dd 100644 --- a/Tests/SwiftOnly/CMakeLists.txt +++ b/Tests/SwiftOnly/CMakeLists.txt @@ -5,6 +5,10 @@ endif() if(POLICY CMP0157) cmake_policy(SET CMP0157 NEW) endif() +if(POLICY CMP0195) + cmake_policy(SET CMP0195 NEW) + set(Swift_NESTED_MODULE TRUE) +endif() # NOTE: Force the Release mode configuration as there are some issues with the # debug information handling on macOS on certain Xcode builds. @@ -52,11 +56,18 @@ target_link_libraries(N PUBLIC # FIXME(#25989): The Xcode generator doesn't respect CMAKE_Swift_MODULE_DIRECTORY. if(NOT CMAKE_GENERATOR STREQUAL "Xcode") + if(Swift_NESTED_MODULE) + # Swift module is a directory, grab the binary swiftmodule file + set(ModulePath "${CMAKE_Swift_MODULE_DIRECTORY}/M.swiftmodule/${CMAKE_Swift_MODULE_TRIPLE}.swiftmodule") + else() + # Swift modules are files + set(ModulePath "${CMAKE_Swift_MODULE_DIRECTORY}/M.swiftmodule") + endif() add_custom_command(TARGET M POST_BUILD COMMAND "${CMAKE_COMMAND}" -E compare_files - "${CMAKE_Swift_MODULE_DIRECTORY}/M.swiftmodule" - "${CMAKE_Swift_MODULE_DIRECTORY}/M.swiftmodule" + "${ModulePath}" + "${ModulePath}" COMMENT "check that .swiftmodule files are generated in CMAKE_Swift_MODULE_DIRECTORY" VERBATIM) endif()