Swift: Propagate Swift_MODULE_DIRECTORY as include directory

Teach include directory computation for Swift to implicitly propagate
the `Swift_MODULE_DIRECTORY` of all linked targets as include
directories.  This is required to ensure that the swiftmodule of a
linked target is accessible to the compiler of the current target.

Fixes: #19272
This commit is contained in:
Saleem Abdulrasool 2020-02-03 21:32:51 -08:00 committed by Brad King
parent cb8227ecbf
commit 2026915f8f
5 changed files with 113 additions and 0 deletions

View File

@ -1282,6 +1282,86 @@ std::string cmGeneratorTarget::EvaluateInterfaceProperty(
}
namespace {
std::string AddSwiftInterfaceIncludeDirectories(
const cmGeneratorTarget* root, const cmGeneratorTarget* target,
const std::string& config, cmGeneratorExpressionDAGChecker* context)
{
cmGeneratorExpressionDAGChecker dag{ target->GetBacktrace(), target,
"Swift_MODULE_DIRECTORY", nullptr,
context };
switch (dag.Check()) {
case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
dag.ReportError(nullptr,
"$<TARGET_PROPERTY:" + target->GetName() +
",Swift_MODULE_DIRECTORY>");
return "";
case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
// No error. We just skip cyclic references.
return "";
case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
// No error. We have already seen this transitive property.
return "";
case cmGeneratorExpressionDAGChecker::DAG:
break;
}
std::string directories;
if (const auto* interface =
target->GetLinkInterfaceLibraries(config, root, true)) {
for (const cmLinkItem& library : interface->Libraries) {
if (const cmGeneratorTarget* dependency = library.Target) {
if (cmContains(dependency->GetAllConfigCompileLanguages(), "Swift")) {
std::string value =
dependency->GetSafeProperty("Swift_MODULE_DIRECTORY");
if (value.empty()) {
value =
dependency->GetLocalGenerator()->GetCurrentBinaryDirectory();
}
if (!directories.empty()) {
directories += ";";
}
directories += value;
}
}
}
}
return directories;
}
void AddSwiftImplicitIncludeDirectories(
const cmGeneratorTarget* target, const std::string& config,
std::vector<EvaluatedTargetPropertyEntry>& entries)
{
if (const auto* libraries = target->GetLinkImplementationLibraries(config)) {
cmGeneratorExpressionDAGChecker dag{ target->GetBacktrace(), target,
"Swift_MODULE_DIRECTORY", nullptr,
nullptr };
for (const cmLinkImplItem& library : libraries->Libraries) {
if (const cmGeneratorTarget* dependency = library.Target) {
if (cmContains(dependency->GetAllConfigCompileLanguages(), "Swift")) {
EvaluatedTargetPropertyEntry entry{ library, library.Backtrace };
if (const char* val =
dependency->GetProperty("Swift_MODULE_DIRECTORY")) {
entry.Values.emplace_back(val);
} else {
entry.Values.emplace_back(
dependency->GetLocalGenerator()->GetCurrentBinaryDirectory());
}
cmExpandList(AddSwiftInterfaceIncludeDirectories(target, dependency,
config, &dag),
entry.Values);
entries.emplace_back(std::move(entry));
}
}
}
}
}
void AddInterfaceEntries(cmGeneratorTarget const* headTarget,
std::string const& config, std::string const& prop,
std::string const& lang,
@ -3177,6 +3257,10 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories(
EvaluateTargetPropertyEntries(this, config, lang, &dagChecker,
this->IncludeDirectoriesEntries);
if (lang == "Swift") {
AddSwiftImplicitIncludeDirectories(this, config, entries);
}
AddInterfaceEntries(this, config, "INTERFACE_INCLUDE_DIRECTORIES", lang,
&dagChecker, entries);

View File

@ -1,4 +1,16 @@
cmake_minimum_required(VERSION 3.3)
# NOTE: Force the Release mode configuration as there are some issues with the
# debug information handling on macOS on certain Xcode builds.
if(NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build" FORCE)
endif()
# NOTE: enable shared libraries by default. Older Xcode releases do not play
# well with static libraries, and Windows does not currently support static
# libraries in Swift.
set(BUILD_SHARED_LIBS YES)
project(SwiftOnly Swift)
if(NOT XCODE_VERSION VERSION_LESS 10.2)
@ -7,7 +19,19 @@ elseif(NOT XCODE_VERSION VERSION_LESS 8.0)
set(CMAKE_Swift_LANGUAGE_VERSION 3.0)
endif()
set(CMAKE_Swift_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/swift)
add_executable(SwiftOnly main.swift)
add_library(L L.swift)
add_library(M M.swift)
target_link_libraries(M PUBLIC
L)
add_library(N N.swift)
target_link_libraries(N PUBLIC
M)
# Dummy to make sure generation works with such targets.
add_library(SwiftIface INTERFACE)

1
Tests/SwiftOnly/L.swift Normal file
View File

@ -0,0 +1 @@
public let ThirtyTwo: Int = 32

2
Tests/SwiftOnly/M.swift Normal file
View File

@ -0,0 +1,2 @@
import L
public let SixtyFour: Int = ThirtyTwo * 2

2
Tests/SwiftOnly/N.swift Normal file
View File

@ -0,0 +1,2 @@
import M
public let OneTwentyEight = SixtyFour * 2