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. */
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 defaultValue. */
std::string GetPropertyOrDefault(std::string const& property,
@ -552,12 +558,6 @@ public:
/** Return the name of the `.swiftmodule` file for this target. */
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 ConfigAndLanguageToBTStrings =
std::map<ConfigAndLanguage, std::vector<BT<std::string>>>;

View File

@ -114,7 +114,10 @@ void AddLangSpecificImplicitIncludeDirectories(
auto* lg = dependency->GetLocalGenerator();
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);
} else {
if (mode == IncludeDirectoryFallBack::BINARY) {

View File

@ -1078,19 +1078,6 @@ void cmNinjaNormalTargetGenerator::WriteNvidiaDeviceLinkStatement(
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(
const std::string& config, const std::string& fileConfig,
bool firstForConfig)
@ -1205,7 +1192,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
vars["SWIFT_MODULE_NAME"] = gt->GetSwiftModuleName();
vars["SWIFT_MODULE"] = this->GetLocalGenerator()->ConvertToOutputFormat(
this->ConvertToNinjaPath(GetSwiftModulePathTree(gt)),
this->ConvertToNinjaPath(gt->GetSwiftModulePath(config)),
cmOutputConverter::SHELL);
vars["SWIFT_SOURCES"] = [this, config]() -> std::string {
@ -1538,7 +1525,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
if (dependency.Target &&
dependency.Target->GetLinkerLanguage(config) == "Swift") {
std::string swiftmodule = this->ConvertToNinjaPath(
GetSwiftModulePathTree(dependency.Target));
dependency.Target->GetSwiftModulePath(config));
linkBuild.ImplicitDeps.emplace_back(swiftmodule);
}
}

View File

@ -1961,15 +1961,9 @@ void cmNinjaTargetGenerator::WriteSwiftObjectBuildStatement(
// changes to input files (e.g. addition of a comment).
vars.emplace("restat", "1");
std::string const moduleName =
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 moduleName = target.GetSwiftModuleName();
std::string const moduleFilepath =
this->ConvertToNinjaPath(cmStrCat(moduleDirectory, '/', moduleFilename));
this->ConvertToNinjaPath(target.GetSwiftModulePath(config));
vars.emplace("description",
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
// swiftmodule to the ninja build graph.
if (isImportableTarget(*dep)) {
std::string const depModuleName =
dep->GetPropertyOrDefault("Swift_MODULE_NAME", dep->GetName());
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));
std::string const depModuleFilepath =
this->ConvertToNinjaPath(dep->GetSwiftModulePath(config));
objBuild.ImplicitDeps.push_back(depModuleFilepath);
}
}

View File

@ -19,9 +19,7 @@ block()
run_cmake(CMP0157-NEW)
run_cmake(CMP0157-WARN)
if(RunCMake_GENERATOR MATCHES "Ninja.*")
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CMP0157-OLD-build)
endif()
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CMP0157-OLD-build)
run_cmake(CMP0157-OLD)
@ -32,9 +30,25 @@ block()
endif()
endblock()
if(RunCMake_GENERATOR MATCHES "Ninja")
block()
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/SwiftSimple-build)
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()
if (CMAKE_SYSTEM_NAME MATCHES "Windows")
run_cmake_with_options(Win32ExecutableDisallowed)

View File

@ -28,6 +28,10 @@ endif()
add_subdirectory(SubA)
add_subdirectory(SubB)
add_subdirectory(SubC)
add_subdirectory(SubD)
add_subdirectory(SubE)
set(CMAKE_Swift_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/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