Swift: Use per-config module file locations in multi-config generators

Place `.swiftmodule` files a subdirectory named after the configuration.

Fixes: #25864
Fixes: #25997

- Swift/RunCMakeTest.cmake:
  - CMP0157-OLD was enabled for Xcode, where it works.
  - A test was added that verifies .swiftmodule's are generated into
    separate directories with multi-config generators.

- Tests/SwiftOnly/CMakeLists.txt: tests were added that validate that
  cross-subdirectory module dependencies (via target_link_libraries)
  work.
This commit is contained in:
Dave Abrahams
2024-05-22 17:55:30 -07:00
parent b2e042d77a
commit 5bb7f8a4dd
12 changed files with 46 additions and 43 deletions

View File

@@ -544,6 +544,12 @@ public:
the given configuration. */ the given configuration. */
std::string GetSwiftModulePath(std::string const& config) const; std::string GetSwiftModulePath(std::string const& config) const;
/** Return the directory containing Swift module interface
descriptions for this target (including its `.swiftmodule`,
`.abi.json`, and `.swiftdoc`) in the given configuration. */
std::string GetSwiftModuleDirectory(std::string const& config) const;
private:
/** Return the given property of this target if it exists; otherwise /** Return the given property of this target if it exists; otherwise
return defaultValue. */ return defaultValue. */
std::string GetPropertyOrDefault(std::string const& property, std::string GetPropertyOrDefault(std::string const& property,
@@ -552,12 +558,6 @@ public:
/** Return the name of the `.swiftmodule` file for this target. */ /** Return the name of the `.swiftmodule` file for this target. */
std::string GetSwiftModuleFileName() const; std::string GetSwiftModuleFileName() const;
private:
/** Return the directory containing Swift module interface
descriptions for this target (including its `.swiftmodule`,
`.abi.json`, and `.swiftdoc`) in the given configuration. */
std::string GetSwiftModuleDirectory(std::string const& config) const;
using ConfigAndLanguage = std::pair<std::string, std::string>; using ConfigAndLanguage = std::pair<std::string, std::string>;
using ConfigAndLanguageToBTStrings = using ConfigAndLanguageToBTStrings =
std::map<ConfigAndLanguage, std::vector<BT<std::string>>>; std::map<ConfigAndLanguage, std::vector<BT<std::string>>>;

View File

@@ -114,7 +114,10 @@ void AddLangSpecificImplicitIncludeDirectories(
auto* lg = dependency->GetLocalGenerator(); auto* lg = dependency->GetLocalGenerator();
EvaluatedTargetPropertyEntry entry{ library, library.Backtrace }; EvaluatedTargetPropertyEntry entry{ library, library.Backtrace };
if (cmValue val = dependency->GetProperty(propertyName)) { if (lang == "Swift") {
entry.Values.emplace_back(
dependency->GetSwiftModuleDirectory(config));
} else if (cmValue val = dependency->GetProperty(propertyName)) {
entry.Values.emplace_back(*val); entry.Values.emplace_back(*val);
} else { } else {
if (mode == IncludeDirectoryFallBack::BINARY) { if (mode == IncludeDirectoryFallBack::BINARY) {

View File

@@ -1078,19 +1078,6 @@ void cmNinjaNormalTargetGenerator::WriteNvidiaDeviceLinkStatement(
this->WriteNvidiaDeviceLinkRule(usedResponseFile, config); this->WriteNvidiaDeviceLinkRule(usedResponseFile, config);
} }
/// Compute the swift module path for the target, sans any config-specific
/// subdirectory.
/// The returned path will need to be converted to the generator path
static std::string GetSwiftModulePathTree(cmGeneratorTarget const* target)
{
std::string moduleName = target->GetSwiftModuleName();
std::string moduleDirectory = target->GetPropertyOrDefault(
"Swift_MODULE_DIRECTORY",
target->LocalGenerator->GetCurrentBinaryDirectory());
std::string moduleFileName = target->GetSwiftModuleFileName();
return moduleDirectory + "/" + moduleFileName;
}
void cmNinjaNormalTargetGenerator::WriteLinkStatement( void cmNinjaNormalTargetGenerator::WriteLinkStatement(
const std::string& config, const std::string& fileConfig, const std::string& config, const std::string& fileConfig,
bool firstForConfig) bool firstForConfig)
@@ -1205,7 +1192,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
vars["SWIFT_MODULE_NAME"] = gt->GetSwiftModuleName(); vars["SWIFT_MODULE_NAME"] = gt->GetSwiftModuleName();
vars["SWIFT_MODULE"] = this->GetLocalGenerator()->ConvertToOutputFormat( vars["SWIFT_MODULE"] = this->GetLocalGenerator()->ConvertToOutputFormat(
this->ConvertToNinjaPath(GetSwiftModulePathTree(gt)), this->ConvertToNinjaPath(gt->GetSwiftModulePath(config)),
cmOutputConverter::SHELL); cmOutputConverter::SHELL);
vars["SWIFT_SOURCES"] = [this, config]() -> std::string { vars["SWIFT_SOURCES"] = [this, config]() -> std::string {
@@ -1538,7 +1525,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
if (dependency.Target && if (dependency.Target &&
dependency.Target->GetLinkerLanguage(config) == "Swift") { dependency.Target->GetLinkerLanguage(config) == "Swift") {
std::string swiftmodule = this->ConvertToNinjaPath( std::string swiftmodule = this->ConvertToNinjaPath(
GetSwiftModulePathTree(dependency.Target)); dependency.Target->GetSwiftModulePath(config));
linkBuild.ImplicitDeps.emplace_back(swiftmodule); linkBuild.ImplicitDeps.emplace_back(swiftmodule);
} }
} }

View File

@@ -1961,15 +1961,9 @@ void cmNinjaTargetGenerator::WriteSwiftObjectBuildStatement(
// changes to input files (e.g. addition of a comment). // changes to input files (e.g. addition of a comment).
vars.emplace("restat", "1"); vars.emplace("restat", "1");
std::string const moduleName = std::string const moduleName = target.GetSwiftModuleName();
target.GetPropertyOrDefault("Swift_MODULE_NAME", target.GetName());
std::string const moduleDirectory = target.GetPropertyOrDefault(
"Swift_MODULE_DIRECTORY",
target.LocalGenerator->GetCurrentBinaryDirectory());
std::string const moduleFilename = target.GetPropertyOrDefault(
"Swift_MODULE", cmStrCat(moduleName, ".swiftmodule"));
std::string const moduleFilepath = std::string const moduleFilepath =
this->ConvertToNinjaPath(cmStrCat(moduleDirectory, '/', moduleFilename)); this->ConvertToNinjaPath(target.GetSwiftModulePath(config));
vars.emplace("description", vars.emplace("description",
cmStrCat("Building Swift Module '", moduleName, "' with ", cmStrCat("Building Swift Module '", moduleName, "' with ",
@@ -2087,15 +2081,8 @@ void cmNinjaTargetGenerator::WriteSwiftObjectBuildStatement(
// If the dependency emits a swiftmodule, add a dependency edge on that // If the dependency emits a swiftmodule, add a dependency edge on that
// swiftmodule to the ninja build graph. // swiftmodule to the ninja build graph.
if (isImportableTarget(*dep)) { if (isImportableTarget(*dep)) {
std::string const depModuleName = std::string const depModuleFilepath =
dep->GetPropertyOrDefault("Swift_MODULE_NAME", dep->GetName()); this->ConvertToNinjaPath(dep->GetSwiftModulePath(config));
std::string const depModuleDir = dep->GetPropertyOrDefault(
"Swift_MODULE_DIRECTORY",
dep->LocalGenerator->GetCurrentBinaryDirectory());
std::string const depModuleFilename = dep->GetPropertyOrDefault(
"Swift_MODULE", cmStrCat(depModuleName, ".swiftmodule"));
std::string const depModuleFilepath = this->ConvertToNinjaPath(
cmStrCat(depModuleDir, '/', depModuleFilename));
objBuild.ImplicitDeps.push_back(depModuleFilepath); objBuild.ImplicitDeps.push_back(depModuleFilepath);
} }
} }

View File

@@ -19,9 +19,7 @@ block()
run_cmake(CMP0157-NEW) run_cmake(CMP0157-NEW)
run_cmake(CMP0157-WARN) run_cmake(CMP0157-WARN)
if(RunCMake_GENERATOR MATCHES "Ninja.*") set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CMP0157-OLD-build)
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CMP0157-OLD-build)
endif()
run_cmake(CMP0157-OLD) run_cmake(CMP0157-OLD)
@@ -32,9 +30,25 @@ block()
endif() endif()
endblock() endblock()
if(RunCMake_GENERATOR MATCHES "Ninja") block()
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/SwiftSimple-build)
run_cmake(SwiftSimple) run_cmake(SwiftSimple)
if(RunCMake_GENERATOR_IS_MULTI_CONFIG AND
# Older Xcode versions didn't support Swift static libraries.
NOT (RunCMake_GENERATOR STREQUAL "Xcode" AND XCODE_VERSION VERSION_LESS 9.0))
# Check that .swiftmodule files get their own directories
set(RunCMake_TEST_NO_CLEAN 1)
run_cmake_command(SwiftSimple-build-Debug ${CMAKE_COMMAND} --build . --config Debug)
run_cmake_command(SwiftSimple-build-Release ${CMAKE_COMMAND} --build . --config Release)
# Will fail if either path doesn't exist. Passing -r because Xcode
# generates .swiftmodule directories.
run_cmake_command(SwiftSimple-verify ${CMAKE_COMMAND} -E
rm -r Debug/L.swiftmodule Release/L.swiftmodule)
endif()
endblock()
if(RunCMake_GENERATOR MATCHES "Ninja")
block() block()
if (CMAKE_SYSTEM_NAME MATCHES "Windows") if (CMAKE_SYSTEM_NAME MATCHES "Windows")
run_cmake_with_options(Win32ExecutableDisallowed) run_cmake_with_options(Win32ExecutableDisallowed)

View File

@@ -28,6 +28,10 @@ endif()
add_subdirectory(SubA) add_subdirectory(SubA)
add_subdirectory(SubB) add_subdirectory(SubB)
add_subdirectory(SubC)
add_subdirectory(SubD)
add_subdirectory(SubE)
set(CMAKE_Swift_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/swift) set(CMAKE_Swift_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/swift)
add_executable(SwiftOnly main.swift) add_executable(SwiftOnly main.swift)

View File

@@ -0,0 +1,2 @@
add_library(SubC SubC.swift)
target_link_libraries(SubC PUBLIC SubD)

View File

@@ -0,0 +1 @@
import SubD

View File

@@ -0,0 +1 @@
add_library(SubD SubD.swift)

View File

@@ -0,0 +1 @@
public let x = 42

View File

@@ -0,0 +1,2 @@
add_executable(SubE main.swift)
target_link_libraries(SubE PUBLIC SubD)

View File

@@ -0,0 +1 @@
import SubD