mirror of
https://gitlab.kitware.com/cmake/cmake.git
synced 2026-09-25 04:09:36 +03:00
Swift/Ninja: Fix emit-module-path clobbering on separate emit-module edge
Since commit b6367f723b (Swift/Ninja: Emit modules separately from
compilation, 2026-04-10) the compile edge still appends
-emit-module -emit-module-path when emitModuleSeparately is active,
duplicating the emit-module edge. For targets with directory-style
module paths (CMP0195=NEW), this causes a file/directory conflict
that fails the build.
Guard -emit-module -emit-module-path on both the compile and
emit-module edges so they are not appended when the flags already
contain -emit-module-path (e.g. from the target's compile options).
Discovered building swift-syntax on Windows where the directory-style
path was overwritten by the flat path from the compile edge.
Issue: #27748
This commit is contained in:
@@ -2200,8 +2200,8 @@ void cmNinjaTargetGenerator::WriteSwiftObjectBuildStatement(
|
||||
objBuild.RspFile = cmStrCat(targetObjectFilename, ".swift.rsp");
|
||||
|
||||
// Importable targets keep -emit-module on compile so swiftc still emits
|
||||
// .swiftdoc. When splitting module emission, only the .swiftmodule output
|
||||
// moves to the separate emit-module edge.
|
||||
// .swiftdoc. When splitting module emission, both the .swiftmodule output
|
||||
// and -emit-module flags move entirely to the separate emit-module edge.
|
||||
if (targetIsImportable && !emitModuleSeparately) {
|
||||
objBuild.Outputs.push_back(moduleFilepath);
|
||||
}
|
||||
@@ -2240,7 +2240,8 @@ void cmNinjaTargetGenerator::WriteSwiftObjectBuildStatement(
|
||||
std::string const moduleOutputPath =
|
||||
this->LocalGenerator->ConvertToOutputFormat(moduleFilepath,
|
||||
cmOutputConverter::SHELL);
|
||||
if (targetIsImportable) {
|
||||
if (targetIsImportable && !emitModuleSeparately &&
|
||||
commonFlags.find("-emit-module-path") == std::string::npos) {
|
||||
std::string const emitModuleFlag = "-emit-module";
|
||||
std::string const modulePathFlag = "-emit-module-path";
|
||||
this->LocalGenerator->AppendFlags(
|
||||
@@ -2291,10 +2292,14 @@ void cmNinjaTargetGenerator::WriteSwiftObjectBuildStatement(
|
||||
// Start from common flags (shared with compile edge) and add
|
||||
// emit-module-specific flags. The emit-module rule template already
|
||||
// contains -emit-module, so we only need -emit-module-path here.
|
||||
// Skip if the flags already contain one (e.g. a directory-style path
|
||||
// set by the target's compile options).
|
||||
modBuild.Variables["FLAGS"] = commonFlags;
|
||||
this->LocalGenerator->AppendFlags(
|
||||
modBuild.Variables["FLAGS"],
|
||||
cmStrCat("-emit-module-path ", moduleOutputPath));
|
||||
if (commonFlags.find("-emit-module-path") == std::string::npos) {
|
||||
this->LocalGenerator->AppendFlags(
|
||||
modBuild.Variables["FLAGS"],
|
||||
cmStrCat("-emit-module-path ", moduleOutputPath));
|
||||
}
|
||||
|
||||
modBuild.RspFile = cmStrCat(moduleFilepath, ".rsp");
|
||||
|
||||
|
||||
@@ -2,8 +2,17 @@ string(
|
||||
REGEX MATCHALL
|
||||
"swiftc(\\.exe)?\"? [^\n]* -emit-module-path [^\n]*L\\.swiftmodule"
|
||||
swift_module_commands "${actual_stdout}")
|
||||
list(LENGTH swift_module_commands swift_module_command_count)
|
||||
if(swift_module_command_count LESS 2)
|
||||
|
||||
set(emit_module_commands "${swift_module_commands}")
|
||||
list(FILTER emit_module_commands EXCLUDE REGEX " -c ")
|
||||
if(NOT emit_module_commands)
|
||||
string(APPEND RunCMake_TEST_FAILED
|
||||
"Expected separate compile and emit-module commands for L, found ${swift_module_command_count} command(s) with '-emit-module-path ... L.swiftmodule'.\n")
|
||||
"Expected an emit-module command with '-emit-module-path ... L.swiftmodule'.\n")
|
||||
endif()
|
||||
|
||||
set(compile_commands "${swift_module_commands}")
|
||||
list(FILTER compile_commands INCLUDE REGEX " -c ")
|
||||
if(compile_commands)
|
||||
string(APPEND RunCMake_TEST_FAILED
|
||||
"Compile command (-c) should not contain '-emit-module-path' when emitting module separately.\n")
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
string(
|
||||
REGEX MATCHALL
|
||||
"swiftc(\\.exe)?\"? [^\n]* -emit-module-path [^\n]*L\\.swiftmodule[^ \n]*"
|
||||
swift_module_commands "${actual_stdout}")
|
||||
|
||||
set(emit_module_commands "${swift_module_commands}")
|
||||
list(FILTER emit_module_commands EXCLUDE REGEX " -c ")
|
||||
if(NOT emit_module_commands)
|
||||
string(APPEND RunCMake_TEST_FAILED
|
||||
"Expected an emit-module command with '-emit-module-path ... L.swiftmodule'.\n")
|
||||
endif()
|
||||
|
||||
set(compile_commands "${swift_module_commands}")
|
||||
list(FILTER compile_commands INCLUDE REGEX " -c ")
|
||||
if(compile_commands)
|
||||
string(APPEND RunCMake_TEST_FAILED
|
||||
"Compile command (-c) should not contain '-emit-module-path' when emitting module separately.\n")
|
||||
endif()
|
||||
|
||||
# CMP0195=NEW: the emit-module path should be directory-style
|
||||
# (L.swiftmodule/<triple>.swiftmodule), not flat.
|
||||
list(FILTER emit_module_commands INCLUDE REGEX "L\\.swiftmodule(/|\\\\)[-_a-zA-Z0-9]+\\.swiftmodule")
|
||||
if(NOT emit_module_commands)
|
||||
string(APPEND RunCMake_TEST_FAILED
|
||||
"Expected directory-style -emit-module-path (L.swiftmodule/<triple>.swiftmodule) from CMP0195=NEW.\n")
|
||||
endif()
|
||||
@@ -0,0 +1,15 @@
|
||||
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)
|
||||
@@ -0,0 +1,11 @@
|
||||
# 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()
|
||||
@@ -0,0 +1,22 @@
|
||||
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)
|
||||
@@ -162,6 +162,22 @@ if(RunCMake_GENERATOR MATCHES "Ninja")
|
||||
run_cmake_command(EmitModuleSeparatelyResponseFile-build ${CMAKE_COMMAND} --build . -- -vn)
|
||||
endblock()
|
||||
|
||||
block()
|
||||
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/EmitModuleSeparatelyDirectoryStyle-build)
|
||||
run_cmake(EmitModuleSeparatelyDirectoryStyle)
|
||||
set(RunCMake_TEST_NO_CLEAN 1)
|
||||
# -v: verbose to capture executed commands -n: dry-run to avoid actually compiling
|
||||
run_cmake_command(EmitModuleSeparatelyDirectoryStyle-build ${CMAKE_COMMAND} --build . -- -vn)
|
||||
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)
|
||||
endblock()
|
||||
|
||||
block()
|
||||
if(CMAKE_SYSTEM_NAME MATCHES Windows)
|
||||
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/ImportLibraryFlags-build)
|
||||
|
||||
Reference in New Issue
Block a user