mirror of
https://gitlab.kitware.com/cmake/cmake.git
synced 2026-09-25 04:09:36 +03:00
Swift/Ninja: Add link edge dependency on emit-module output
Since commit b6367f723b (Swift/Ninja: Emit modules separately from
compilation, 2026-04-10) the .swiftmodule output moved from the
compile edge to a separate emit-module edge. The link edge does not
depend on the emit-module output, so ninja never runs the emit-module
edge when no other target in the build imports the module (e.g.
install-only targets).
Store the declared .swiftmodule output path during Swift object
statement generation and add it as an implicit dependency of the link
edge.
Issue: #27748
This commit is contained in:
@@ -1652,6 +1652,14 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
|
||||
}
|
||||
}
|
||||
|
||||
// For split Swift builds, ensure the link edge depends on the target's own
|
||||
// .swiftmodule so the emit-module edge runs even when no other target in
|
||||
// the build depends on it (e.g. install-only targets).
|
||||
std::string swiftModuleOutput = this->GetSwiftModuleOutput(config);
|
||||
if (!swiftModuleOutput.empty()) {
|
||||
linkBuild.ImplicitDeps.emplace_back(std::move(swiftModuleOutput));
|
||||
}
|
||||
|
||||
// Ninja should restat after linking if and only if there are byproducts.
|
||||
vars["RESTAT"] = byproducts.ExplicitOuts.empty() ? "" : "1";
|
||||
|
||||
|
||||
@@ -2202,6 +2202,9 @@ void cmNinjaTargetGenerator::WriteSwiftObjectBuildStatement(
|
||||
// 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;
|
||||
}
|
||||
if (targetIsImportable && !emitModuleSeparately) {
|
||||
objBuild.Outputs.push_back(moduleFilepath);
|
||||
}
|
||||
@@ -2673,6 +2676,16 @@ cmNinjaDeps cmNinjaTargetGenerator::GetObjects(std::string const& config) const
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string cmNinjaTargetGenerator::GetSwiftModuleOutput(
|
||||
std::string const& config) const
|
||||
{
|
||||
auto const it = this->Configs.find(config);
|
||||
if (it != this->Configs.end()) {
|
||||
return it->second.SwiftModuleOutput;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void cmNinjaTargetGenerator::EnsureDirectoryExists(
|
||||
std::string const& path) const
|
||||
{
|
||||
|
||||
@@ -216,6 +216,7 @@ protected:
|
||||
void AdditionalCleanFiles(std::string const& config);
|
||||
|
||||
cmNinjaDeps GetObjects(std::string const& config) const;
|
||||
std::string GetSwiftModuleOutput(std::string const& config) const;
|
||||
|
||||
void EnsureDirectoryExists(std::string const& dir) const;
|
||||
void EnsureParentDirectoryExists(std::string const& path) const;
|
||||
@@ -278,6 +279,8 @@ private:
|
||||
Json::Value SwiftOutputMap;
|
||||
cmNinjaDeps ExtraFiles;
|
||||
std::unique_ptr<MacOSXContentGeneratorType> MacOSXContentGenerator;
|
||||
// Path declared as the .swiftmodule output (compile or emit-module edge).
|
||||
std::string SwiftModuleOutput;
|
||||
};
|
||||
|
||||
std::map<std::string, ByConfig> Configs;
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# The link edge for a Swift library must implicitly depend on the
|
||||
# .swiftmodule so the emit-module edge runs even when no other target
|
||||
# in the build depends on it.
|
||||
if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
|
||||
set(path "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/impl-Debug.ninja")
|
||||
else()
|
||||
set(path "${RunCMake_TEST_BINARY_DIR}/build.ninja")
|
||||
endif()
|
||||
file(READ "${path}" build_ninja)
|
||||
|
||||
if(NOT build_ninja MATCHES "build [^\n]*(libL\\.a|L\\.lib)[^\n]*:.*\\|[^\n]*L\\.swiftmodule")
|
||||
string(APPEND RunCMake_TEST_FAILED
|
||||
"Link edge for L does not depend on L.swiftmodule.\n")
|
||||
endif()
|
||||
@@ -0,0 +1,12 @@
|
||||
cmake_policy(SET CMP0157 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)
|
||||
|
||||
# A standalone library with no dependent Swift targets. The link edge
|
||||
# must still depend on the .swiftmodule so the emit-module edge runs.
|
||||
add_library(L STATIC L.swift)
|
||||
@@ -0,0 +1,14 @@
|
||||
# Same as EmitModuleSeparatelyLinkDep but with a custom module directory.
|
||||
# The link edge must depend on the actual emit-module output path, not a
|
||||
# default that doesn't match the target's configuration.
|
||||
if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
|
||||
set(path "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/impl-Debug.ninja")
|
||||
else()
|
||||
set(path "${RunCMake_TEST_BINARY_DIR}/build.ninja")
|
||||
endif()
|
||||
file(READ "${path}" build_ninja)
|
||||
|
||||
if(NOT build_ninja MATCHES "build [^\n]*(libL\\.a|L\\.lib)[^\n]*:.*\\|[^\n]*custom(/|\\\\)[^\n]*L\\.swiftmodule")
|
||||
string(APPEND RunCMake_TEST_FAILED
|
||||
"Link edge for L does not depend on custom/.../L.swiftmodule.\n")
|
||||
endif()
|
||||
@@ -0,0 +1,15 @@
|
||||
cmake_policy(SET CMP0157 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)
|
||||
|
||||
# A standalone library with a custom module output path (like swiftCore
|
||||
# in the Swift stdlib). The link edge must depend on the actual
|
||||
# emit-module output, not GetSwiftModulePath().
|
||||
add_library(L STATIC L.swift)
|
||||
set_target_properties(L PROPERTIES
|
||||
Swift_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/custom)
|
||||
@@ -170,6 +170,14 @@ if(RunCMake_GENERATOR MATCHES "Ninja")
|
||||
run_cmake_command(EmitModuleSeparatelyDirectoryStyle-build ${CMAKE_COMMAND} --build . -- -vn)
|
||||
endblock()
|
||||
|
||||
block()
|
||||
run_cmake(EmitModuleSeparatelyLinkDep)
|
||||
endblock()
|
||||
|
||||
block()
|
||||
run_cmake(EmitModuleSeparatelyLinkDepCustomPath)
|
||||
endblock()
|
||||
|
||||
block()
|
||||
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/EmitModuleSeparatelyExistingModulePath-build)
|
||||
run_cmake(EmitModuleSeparatelyExistingModulePath)
|
||||
|
||||
Reference in New Issue
Block a user