diff --git a/Help/policy/CMP0215.rst b/Help/policy/CMP0215.rst index 7573597e31..acee88c468 100644 --- a/Help/policy/CMP0215.rst +++ b/Help/policy/CMP0215.rst @@ -24,13 +24,15 @@ The :prop_tgt:`Swift_SEPARATE_MODULE_EMISSION` target property and corresponding :variable:`CMAKE_Swift_SEPARATE_MODULE_EMISSION` variable may be set to enable or disable the behavior on a per-target basis. -.. note:: - - Separate module emission takes effect only when policy :policy:`CMP0157` - is set to ``NEW`` prior to the first :command:`project` or - :command:`enable_language` command that enables the Swift language. - The dedicated ``.swiftmodule`` edge is available only in the split - Swift build model. +The ``NEW`` behavior requires that policies :policy:`CMP0157` and +:policy:`CMP0195` are also set to ``NEW``. :policy:`CMP0157` selects the +split Swift build model that provides the dedicated ``.swiftmodule`` edge, +and must be set prior to the first :command:`project` or +:command:`enable_language` command that enables the Swift language. +:policy:`CMP0195` places the module in the Swift module directory structure +that the dedicated edge writes. If either policy is not ``NEW`` while +``CMP0215`` is ``NEW``, CMake issues a fatal error when the Swift language +is enabled. .. |INTRODUCED_IN_CMAKE_VERSION| replace:: 4.4 .. |WARNS_OR_DOES_NOT_WARN| replace:: does *not* warn diff --git a/Help/release/4.4.rst b/Help/release/4.4.rst index 47b200a583..9bee567403 100644 --- a/Help/release/4.4.rst +++ b/Help/release/4.4.rst @@ -322,7 +322,9 @@ Swift :prop_tgt:`Swift_SEPARATE_MODULE_EMISSION` target property, initialized by the :variable:`CMAKE_Swift_SEPARATE_MODULE_EMISSION` variable, to control whether importable Swift targets emit ``.swiftmodule`` from a dedicated - build edge. Policy :policy:`CMP0215` enables this by default. + build edge. Policy :policy:`CMP0215` enables this by default. The + behavior requires policies :policy:`CMP0157` and :policy:`CMP0195` to be + set to ``NEW``. * The default :prop_tgt:`Swift_MODULE_NAME` now replaces hyphens with underscores, since hyphens are not valid in Swift module identifiers. @@ -450,3 +452,9 @@ Changes made since CMake 4.4.0 include the following. * This version made no changes to documented features or interfaces. Some implementation updates were made to support ecosystem changes and/or fix regressions. + +.. 4.4.3 + + * Swift policy :poilcy:`CMP0215`'s ``NEW`` behavior has been updated + to require policies :policy:`CMP0157` and :policy:`CMP0195` to also + be set to ``NEW``. diff --git a/Modules/CMakeSwiftInformation.cmake b/Modules/CMakeSwiftInformation.cmake index 0cd8b77041..a7b053cc09 100644 --- a/Modules/CMakeSwiftInformation.cmake +++ b/Modules/CMakeSwiftInformation.cmake @@ -109,6 +109,47 @@ else() endif() unset(__SWIFT_COMP_MODE_CMP0157) +# Separate Swift module emission (see policy CMP0215) is available only in the +# split build model selected by policy CMP0157, and it writes the module into +# the Swift module directory structure selected by policy CMP0195. When +# CMP0215 is NEW, require both to also be NEW. This is a Ninja-only feature, +# so only enforce the requirement for Ninja generators. +if(CMAKE_GENERATOR MATCHES "Ninja") + cmake_policy(GET CMP0215 __SWIFT_SEPARATE_MODULE_CMP0215) + if(__SWIFT_SEPARATE_MODULE_CMP0215 STREQUAL "NEW") + set(__SWIFT_SEPARATE_MODULE_UNMET "") + cmake_policy(GET CMP0157 __SWIFT_SEPARATE_MODULE_CMP0157) + if(NOT __SWIFT_SEPARATE_MODULE_CMP0157 STREQUAL "NEW") + list(APPEND __SWIFT_SEPARATE_MODULE_UNMET CMP0157) + endif() + cmake_policy(GET CMP0195 __SWIFT_SEPARATE_MODULE_CMP0195) + if(NOT __SWIFT_SEPARATE_MODULE_CMP0195 STREQUAL "NEW") + list(APPEND __SWIFT_SEPARATE_MODULE_UNMET CMP0195) + endif() + if(__SWIFT_SEPARATE_MODULE_UNMET) + list(LENGTH __SWIFT_SEPARATE_MODULE_UNMET __SWIFT_SEPARATE_MODULE_UNMET_COUNT) + list(JOIN __SWIFT_SEPARATE_MODULE_UNMET " and " __SWIFT_SEPARATE_MODULE_UNMET_STR) + if(__SWIFT_SEPARATE_MODULE_UNMET_COUNT GREATER 1) + set(__SWIFT_SEPARATE_MODULE_VERB "are") + else() + set(__SWIFT_SEPARATE_MODULE_VERB "is") + endif() + message(FATAL_ERROR + "Policy CMP0215 is set to 'NEW', which requires policies CMP0157 and " + "CMP0195 to be set to 'NEW', but ${__SWIFT_SEPARATE_MODULE_UNMET_STR} " + "${__SWIFT_SEPARATE_MODULE_VERB} not. Note that CMP0157 must be set " + "before the Swift language is enabled.") + endif() + unset(__SWIFT_SEPARATE_MODULE_CMP0157) + unset(__SWIFT_SEPARATE_MODULE_CMP0195) + unset(__SWIFT_SEPARATE_MODULE_UNMET) + unset(__SWIFT_SEPARATE_MODULE_UNMET_COUNT) + unset(__SWIFT_SEPARATE_MODULE_UNMET_STR) + unset(__SWIFT_SEPARATE_MODULE_VERB) + endif() + unset(__SWIFT_SEPARATE_MODULE_CMP0215) +endif() + cmake_initialize_per_config_variable(CMAKE_Swift_FLAGS "Swift Compiler Flags") if(NOT CMAKE_Swift_NUM_THREADS MATCHES "^[0-9]+$") diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 5d02ef4e73..26ae9775ff 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -1291,7 +1291,6 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements( this->GeneratorTarget->GetObjectSources(objectSources, config); std::vector swiftSources; - for (cmSourceFile const* sf : objectSources) { if (this->GetLocalGenerator()->IsSplitSwiftBuild() && sf->GetLanguage() == "Swift") { @@ -1301,6 +1300,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements( firstForConfig); } } + WriteSwiftObjectBuildStatement(swiftSources, config, fileConfig, firstForConfig); } @@ -2223,9 +2223,6 @@ void cmNinjaTargetGenerator::WriteSwiftObjectBuildStatement( this->GetGlobalGenerator()->GetLanguageOutputExtension(language))); objBuild.RspFile = cmStrCat(targetObjectFilename, ".swift.rsp"); - // Importable targets keep -emit-module on compile so swiftc still emits - // .swiftdoc. When splitting module emission, both the .swiftmodule output - // and -emit-module flags move entirely to the separate emit-module edge. if (targetIsImportable) { this->Configs[config].SwiftModuleOutput = moduleFilepath; } @@ -2267,8 +2264,8 @@ void cmNinjaTargetGenerator::WriteSwiftObjectBuildStatement( std::string const moduleOutputPath = this->LocalGenerator->ConvertToOutputFormat(moduleFilepath, cmOutputConverter::SHELL); - if (targetIsImportable && !emitModuleSeparately && - commonFlags.find("-emit-module-path") == std::string::npos) { + + if (targetIsImportable && !emitModuleSeparately) { std::string const emitModuleFlag = "-emit-module"; std::string const modulePathFlag = "-emit-module-path"; this->LocalGenerator->AppendFlags( @@ -2317,11 +2314,9 @@ void cmNinjaTargetGenerator::WriteSwiftObjectBuildStatement( // Skip if the flags already contain one (e.g. a directory-style path // set by the target's compile options). modBuild.Variables["FLAGS"] = commonFlags; - if (commonFlags.find("-emit-module-path") == std::string::npos) { - this->LocalGenerator->AppendFlags( - modBuild.Variables["FLAGS"], - cmStrCat("-emit-module-path ", moduleOutputPath)); - } + this->LocalGenerator->AppendFlags( + modBuild.Variables["FLAGS"], + cmStrCat("-emit-module-path ", moduleOutputPath)); modBuild.RspFile = cmStrCat(moduleFilepath, ".rsp"); diff --git a/Tests/RunCMake/Swift/EmitModuleSeparately.cmake b/Tests/RunCMake/Swift/EmitModuleSeparately.cmake index d5ac09c2de..31955ba7af 100644 --- a/Tests/RunCMake/Swift/EmitModuleSeparately.cmake +++ b/Tests/RunCMake/Swift/EmitModuleSeparately.cmake @@ -1,4 +1,5 @@ cmake_policy(SET CMP0157 NEW) +cmake_policy(SET CMP0195 NEW) cmake_policy(SET CMP0215 NEW) if(NOT CMAKE_GENERATOR MATCHES "Ninja") diff --git a/Tests/RunCMake/Swift/EmitModuleSeparatelyExistingModulePath-build-check.cmake b/Tests/RunCMake/Swift/EmitModuleSeparatelyExistingModulePath-build-check.cmake deleted file mode 100644 index 1a0c488e62..0000000000 --- a/Tests/RunCMake/Swift/EmitModuleSeparatelyExistingModulePath-build-check.cmake +++ /dev/null @@ -1,11 +0,0 @@ -# When the target's flags already contain -emit-module-path, the emit-module -# edge should not append a second one that clobbers it. -# Match command lines that have two -emit-module-path flags on the same line. -string( - REGEX MATCHALL - "-emit-module-path [^\n]*-emit-module-path" - duplicate_flags "${actual_stdout}") -if(duplicate_flags) - string(APPEND RunCMake_TEST_FAILED - "Found command with duplicate -emit-module-path flags.\n") -endif() diff --git a/Tests/RunCMake/Swift/EmitModuleSeparatelyExistingModulePath.cmake b/Tests/RunCMake/Swift/EmitModuleSeparatelyExistingModulePath.cmake deleted file mode 100644 index 1decca43f8..0000000000 --- a/Tests/RunCMake/Swift/EmitModuleSeparatelyExistingModulePath.cmake +++ /dev/null @@ -1,22 +0,0 @@ -cmake_minimum_required(VERSION 4.0) - -cmake_policy(SET CMP0157 NEW) -cmake_policy(SET CMP0195 NEW) -cmake_policy(SET CMP0215 NEW) - -if(NOT CMAKE_GENERATOR MATCHES "Ninja") - message(SEND_ERROR "this test must use a Ninja generator, found ${CMAKE_GENERATOR}") -endif() - -enable_language(Swift) - -add_library(L STATIC L.swift) -add_library(LClient STATIC LClient.swift) -target_link_libraries(LClient PRIVATE L) - -# Simulate a target whose flags already contain -emit-module-path with a -# directory-style path (as seen with swift-syntax's CMake config). Use the -# real module triple so the path matches GetSwiftModulePath() and the build -# would succeed outside of dry-run. -target_compile_options(L PRIVATE - -emit-module-path ${CMAKE_CURRENT_BINARY_DIR}/L.swiftmodule/${CMAKE_Swift_MODULE_TRIPLE}.swiftmodule) diff --git a/Tests/RunCMake/Swift/EmitModuleSeparatelyLinkDep.cmake b/Tests/RunCMake/Swift/EmitModuleSeparatelyLinkDep.cmake index 7ef69cfcc9..6eec25ca42 100644 --- a/Tests/RunCMake/Swift/EmitModuleSeparatelyLinkDep.cmake +++ b/Tests/RunCMake/Swift/EmitModuleSeparatelyLinkDep.cmake @@ -1,4 +1,5 @@ cmake_policy(SET CMP0157 NEW) +cmake_policy(SET CMP0195 NEW) cmake_policy(SET CMP0215 NEW) if(NOT CMAKE_GENERATOR MATCHES "Ninja") diff --git a/Tests/RunCMake/Swift/EmitModuleSeparatelyLinkDepCustomPath.cmake b/Tests/RunCMake/Swift/EmitModuleSeparatelyLinkDepCustomPath.cmake index fbb3ac86f2..5dc0533a20 100644 --- a/Tests/RunCMake/Swift/EmitModuleSeparatelyLinkDepCustomPath.cmake +++ b/Tests/RunCMake/Swift/EmitModuleSeparatelyLinkDepCustomPath.cmake @@ -1,4 +1,5 @@ cmake_policy(SET CMP0157 NEW) +cmake_policy(SET CMP0195 NEW) cmake_policy(SET CMP0215 NEW) if(NOT CMAKE_GENERATOR MATCHES "Ninja") diff --git a/Tests/RunCMake/Swift/EmitModuleSeparatelyOrdering.cmake b/Tests/RunCMake/Swift/EmitModuleSeparatelyOrdering.cmake index 62644539e0..2c643e0db3 100644 --- a/Tests/RunCMake/Swift/EmitModuleSeparatelyOrdering.cmake +++ b/Tests/RunCMake/Swift/EmitModuleSeparatelyOrdering.cmake @@ -1,4 +1,5 @@ cmake_policy(SET CMP0157 NEW) +cmake_policy(SET CMP0195 NEW) cmake_policy(SET CMP0215 NEW) if(NOT CMAKE_GENERATOR MATCHES "Ninja") diff --git a/Tests/RunCMake/Swift/EmitModuleSeparatelyRequiresPolicies-result.txt b/Tests/RunCMake/Swift/EmitModuleSeparatelyRequiresPolicies-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/Swift/EmitModuleSeparatelyRequiresPolicies-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/Swift/EmitModuleSeparatelyRequiresPolicies-stderr.txt b/Tests/RunCMake/Swift/EmitModuleSeparatelyRequiresPolicies-stderr.txt new file mode 100644 index 0000000000..4619f1b8f4 --- /dev/null +++ b/Tests/RunCMake/Swift/EmitModuleSeparatelyRequiresPolicies-stderr.txt @@ -0,0 +1,4 @@ +CMake Error at [^ +]*CMakeSwiftInformation\.cmake:[0-9]+ \(message\): + Policy CMP0215 is set to 'NEW', which requires policies CMP0157 and CMP0195 + to be set to 'NEW', but CMP0157 and CMP0195 are not\. diff --git a/Tests/RunCMake/Swift/EmitModuleSeparatelyRequiresPolicies.cmake b/Tests/RunCMake/Swift/EmitModuleSeparatelyRequiresPolicies.cmake new file mode 100644 index 0000000000..416efd5b16 --- /dev/null +++ b/Tests/RunCMake/Swift/EmitModuleSeparatelyRequiresPolicies.cmake @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 4.0) + +# CMP0157 must be set before the Swift language is enabled. +cmake_policy(SET CMP0157 OLD) +cmake_policy(SET CMP0195 OLD) +cmake_policy(SET CMP0215 NEW) + +if(NOT CMAKE_GENERATOR MATCHES "Ninja") + message(SEND_ERROR "this test must use a Ninja generator, found ${CMAKE_GENERATOR}") +endif() + +# CMP0215=NEW requires both CMP0157=NEW and CMP0195=NEW; neither is set here, +# so enabling the Swift language must fail and name both policies. +enable_language(Swift) diff --git a/Tests/RunCMake/Swift/EmitModuleSeparatelyResponseFile-build-check.cmake b/Tests/RunCMake/Swift/EmitModuleSeparatelyResponseFile-build-check.cmake index c9d58ee957..2bf01963c7 100644 --- a/Tests/RunCMake/Swift/EmitModuleSeparatelyResponseFile-build-check.cmake +++ b/Tests/RunCMake/Swift/EmitModuleSeparatelyResponseFile-build-check.cmake @@ -5,7 +5,7 @@ if(NOT actual_stdout MATCHES endif() if(NOT actual_stdout MATCHES - "swiftc(\\.exe)?\"? [^\n]* -emit-module @.*L\\.swiftmodule\\.rsp") + "swiftc(\\.exe)?\"? [^\n]* -emit-module @.*L\\.swiftmodule(/|\\\\)[-_a-zA-Z0-9]+\\.swiftmodule\\.rsp") string(APPEND RunCMake_TEST_FAILED "No Swift emit-module response-file command found for target L.\n") endif() diff --git a/Tests/RunCMake/Swift/EmitModuleSeparatelyResponseFile.cmake b/Tests/RunCMake/Swift/EmitModuleSeparatelyResponseFile.cmake index fa405d4546..772405b0c8 100644 --- a/Tests/RunCMake/Swift/EmitModuleSeparatelyResponseFile.cmake +++ b/Tests/RunCMake/Swift/EmitModuleSeparatelyResponseFile.cmake @@ -1,4 +1,5 @@ cmake_policy(SET CMP0157 NEW) +cmake_policy(SET CMP0195 NEW) cmake_policy(SET CMP0215 NEW) if(NOT CMAKE_GENERATOR MATCHES "Ninja") diff --git a/Tests/RunCMake/Swift/RunCMakeTest.cmake b/Tests/RunCMake/Swift/RunCMakeTest.cmake index f927e77ae8..55e059496d 100644 --- a/Tests/RunCMake/Swift/RunCMakeTest.cmake +++ b/Tests/RunCMake/Swift/RunCMakeTest.cmake @@ -184,15 +184,11 @@ if(RunCMake_GENERATOR MATCHES "Ninja") endblock() block() - set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/EmitModuleSeparatelyExistingModulePath-build) - run_cmake(EmitModuleSeparatelyExistingModulePath) - set(RunCMake_TEST_NO_CLEAN 1) - # -v: verbose to capture executed commands -n: dry-run to avoid actually compiling - run_cmake_command(EmitModuleSeparatelyExistingModulePath-build ${CMAKE_COMMAND} --build . -- -vn) + run_cmake(EmitModuleSeparatelyOrdering) endblock() block() - run_cmake(EmitModuleSeparatelyOrdering) + run_cmake(EmitModuleSeparatelyRequiresPolicies) endblock() block()