diff options
-rw-r--r-- | Modules/CMakeSwiftInformation.cmake | 72 | ||||
-rw-r--r-- | Source/cmLocalGenerator.cxx | 8 | ||||
-rw-r--r-- | Source/cmLocalGenerator.h | 4 | ||||
-rw-r--r-- | Source/cmNinjaNormalTargetGenerator.cxx | 15 | ||||
-rw-r--r-- | Source/cmNinjaTargetGenerator.cxx | 238 | ||||
-rw-r--r-- | Source/cmNinjaTargetGenerator.h | 3 | ||||
-rw-r--r-- | Tests/RunCMake/Swift/IncrementalSwift-second-stdout.txt | 6 | ||||
-rw-r--r-- | Tests/SwiftOnly/CMakeLists.txt | 24 | ||||
-rw-r--r-- | Tests/SwiftOnly/O.swift | 0 |
9 files changed, 323 insertions, 47 deletions
diff --git a/Modules/CMakeSwiftInformation.cmake b/Modules/CMakeSwiftInformation.cmake index 9f4ed34..04d500e 100644 --- a/Modules/CMakeSwiftInformation.cmake +++ b/Modules/CMakeSwiftInformation.cmake @@ -116,36 +116,66 @@ endif() cmake_initialize_per_config_variable(CMAKE_Swift_FLAGS "Swift Compiler Flags") -# NOTE(compnerd) we do not have an object compile rule since we build the objects as part of the link step -if(NOT CMAKE_Swift_COMPILE_OBJECT) - set(CMAKE_Swift_COMPILE_OBJECT ":") -endif() - if(NOT CMAKE_Swift_NUM_THREADS MATCHES "^[0-9]+$") cmake_host_system_information(RESULT CMAKE_Swift_NUM_THREADS QUERY NUMBER_OF_LOGICAL_CORES) endif() -if(NOT CMAKE_Swift_CREATE_SHARED_LIBRARY) - set(CMAKE_Swift_CREATE_SHARED_LIBRARY "<CMAKE_Swift_COMPILER> -j ${CMAKE_Swift_NUM_THREADS} -num-threads ${CMAKE_Swift_NUM_THREADS} -emit-library -o <TARGET> -module-name <SWIFT_MODULE_NAME> -module-link-name <SWIFT_LIBRARY_NAME> -emit-module -emit-module-path <SWIFT_MODULE> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> <SONAME_FLAG> <TARGET_INSTALLNAME_DIR><TARGET_SONAME> ${CMAKE_Swift_IMPLIB_LINKER_FLAGS} <LINK_LIBRARIES>") -endif() +# Swift split-compilation requires CMP0157 NEW policy +if(CMAKE_Swift_COMPILATION_MODE_DEFAULT) + set(CMAKE_Swift_PARALLEL_FLAGS "-j ${CMAKE_Swift_NUM_THREADS} -num-threads ${CMAKE_Swift_NUM_THREADS}") + if(NOT CMAKE_Swift_COMPILE_OBJECT) + # Omit the object output. The output is controlled by the output-file-map + # for normal builds. For wholemodule builds, CMake appends the appropriate + # flags. + set(CMAKE_Swift_COMPILE_OBJECT "<CMAKE_Swift_COMPILER> ${CMAKE_Swift_PARALLEL_FLAGS} -c <DEFINES> <FLAGS> <INCLUDES> <SOURCE>") + endif() -if(NOT CMAKE_Swift_CREATE_SHARED_MODULE) - set(CMAKE_Swift_CREATE_SHARED_MODULE ${CMAKE_Swift_CREATE_SHARED_LIBRARY}) -endif() + if(NOT CMAKE_Swift_CREATE_SHARED_LIBRARY) + set(CMAKE_Swift_CREATE_SHARED_LIBRARY "<CMAKE_Swift_COMPILER> ${CMAKE_Swift_PARALLEL_FLAGS} -emit-library <CMAKE_SHARED_LIBRARY_Swift_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <SONAME_FLAG> <TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>") + endif() -if(NOT CMAKE_Swift_LINK_EXECUTABLE) - set(CMAKE_Swift_LINK_EXECUTABLE "<CMAKE_Swift_COMPILER> -j ${CMAKE_Swift_NUM_THREADS} -num-threads ${CMAKE_Swift_NUM_THREADS} -emit-executable -o <TARGET> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> <LINK_LIBRARIES>") -endif() + if(NOT CMAKE_Swift_CREATE_SHARED_MODULE) + set(CMAKE_Swift_CREATE_SHARED_MODULE ${CMAKE_Swift_CREATE_SHARED_LIBRARY}) + endif() -if(NOT CMAKE_Swift_LINK_EXECUTABLE_WITH_EXPORTS) - set(CMAKE_Swift_LINK_EXECUTABLE_WITH_EXPORTS "${CMAKE_Swift_LINK_EXECUTABLE} -emit-module -emit-module-path <SWIFT_MODULE> ${CMAKE_Swift_IMPLIB_LINKER_FLAGS}") -endif() + if(NOT CMAKE_Swift_LINK_EXECUTABLE) + set(CMAKE_Swift_LINK_EXECUTABLE "<CMAKE_Swift_COMPILER> ${CMAKE_Swift_PARALLEL_FLAGS} -emit-executable -o <TARGET> <FLAGS> <OBJECTS> <LINK_FLAGS> <LINK_LIBRARIES>") + endif() -if(NOT CMAKE_Swift_CREATE_STATIC_LIBRARY) - set(CMAKE_Swift_CREATE_STATIC_LIBRARY "<CMAKE_Swift_COMPILER> -j ${CMAKE_Swift_NUM_THREADS} -num-threads ${CMAKE_Swift_NUM_THREADS} -emit-library -static -o <TARGET> -module-name <SWIFT_MODULE_NAME> -module-link-name <SWIFT_LIBRARY_NAME> -emit-module -emit-module-path <SWIFT_MODULE> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> <LINK_LIBRARIES>") + if(NOT CMAKE_Swift_CREATE_STATIC_LIBRARY) + set(CMAKE_Swift_CREATE_STATIC_LIBRARY "<CMAKE_Swift_COMPILER> -emit-library -static -o <TARGET> <OBJECTS> <LINK_FLAGS>") + set(CMAKE_Swift_ARCHIVE_CREATE "<CMAKE_AR> crs <TARGET> <OBJECTS>") + set(CMAKE_Swift_ARCHIVE_FINISH "") + endif() + unset(CMAKE_Swift_PARALLEL_FLAGS) +else() + # NOTE(compnerd) we do not have an object compile rule since we build the objects as part of the link step + if(NOT CMAKE_Swift_COMPILE_OBJECT) + set(CMAKE_Swift_COMPILE_OBJECT ":") + endif() + + if(NOT CMAKE_Swift_CREATE_SHARED_LIBRARY) + set(CMAKE_Swift_CREATE_SHARED_LIBRARY "<CMAKE_Swift_COMPILER> -j ${CMAKE_Swift_NUM_THREADS} -num-threads ${CMAKE_Swift_NUM_THREADS} -emit-library -o <TARGET> -module-name <SWIFT_MODULE_NAME> -module-link-name <SWIFT_LIBRARY_NAME> -emit-module -emit-module-path <SWIFT_MODULE> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> <SONAME_FLAG> <TARGET_INSTALLNAME_DIR><TARGET_SONAME> ${CMAKE_Swift_IMPLIB_LINKER_FLAGS} <LINK_LIBRARIES>") + endif() - set(CMAKE_Swift_ARCHIVE_CREATE "<CMAKE_AR> crs <TARGET> <OBJECTS>") - set(CMAKE_Swift_ARCHIVE_FINISH "") + if(NOT CMAKE_Swift_CREATE_SHARED_MODULE) + set(CMAKE_Swift_CREATE_SHARED_MODULE ${CMAKE_Swift_CREATE_SHARED_LIBRARY}) + endif() + + if(NOT CMAKE_Swift_LINK_EXECUTABLE) + set(CMAKE_Swift_LINK_EXECUTABLE "<CMAKE_Swift_COMPILER> -j ${CMAKE_Swift_NUM_THREADS} -num-threads ${CMAKE_Swift_NUM_THREADS} -emit-executable -o <TARGET> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> <LINK_LIBRARIES>") + endif() + + if(NOT CMAKE_Swift_LINK_EXECUTABLE_WITH_EXPORTS) + set(CMAKE_Swift_LINK_EXECUTABLE_WITH_EXPORTS "${CMAKE_Swift_LINK_EXECUTABLE} -emit-module -emit-module-path <SWIFT_MODULE> ${CMAKE_Swift_IMPLIB_LINKER_FLAGS}") + endif() + + if(NOT CMAKE_Swift_CREATE_STATIC_LIBRARY) + set(CMAKE_Swift_CREATE_STATIC_LIBRARY "<CMAKE_Swift_COMPILER> -j ${CMAKE_Swift_NUM_THREADS} -num-threads ${CMAKE_Swift_NUM_THREADS} -emit-library -static -o <TARGET> -module-name <SWIFT_MODULE_NAME> -module-link-name <SWIFT_LIBRARY_NAME> -emit-module -emit-module-path <SWIFT_MODULE> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> <LINK_LIBRARIES>") + + set(CMAKE_Swift_ARCHIVE_CREATE "<CMAKE_AR> crs <TARGET> <OBJECTS>") + set(CMAKE_Swift_ARCHIVE_FINISH "") + endif() endif() set(CMAKE_Swift_INFORMATION_LOADED 1) diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index eaf38d4..e479931 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -1366,7 +1366,7 @@ std::vector<BT<std::string>> cmLocalGenerator::GetStaticLibraryFlags( { const std::string configUpper = cmSystemTools::UpperCase(config); std::vector<BT<std::string>> flags; - if (linkLanguage != "Swift") { + if (linkLanguage != "Swift" && !this->IsSplitSwiftBuild()) { std::string staticLibFlags; this->AppendFlags( staticLibFlags, @@ -3016,6 +3016,12 @@ cm::optional<cmSwiftCompileMode> cmLocalGenerator::GetSwiftCompileMode( return cmSwiftCompileMode::Unknown; } +bool cmLocalGenerator::IsSplitSwiftBuild() const +{ + return cmNonempty(this->GetMakefile()->GetDefinition( + "CMAKE_Swift_COMPILATION_MODE_DEFAULT")); +} + namespace { inline void RegisterUnitySources(cmGeneratorTarget* target, cmSourceFile* sf, diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index af5b35e..3ec349b 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -562,6 +562,10 @@ public: cm::optional<cmSwiftCompileMode> GetSwiftCompileMode( cmGeneratorTarget const* target, std::string const& config); + // Can we build Swift with a separate object build and link step + // (If CMP0157 is NEW, we can do a split build) + bool IsSplitSwiftBuild() const; + protected: // The default implementation converts to a Windows shortpath to // help older toolchains handle spaces and such. A generator may diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index 5e7bb6e..99ea009 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -1209,7 +1209,10 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement( globalGen->GetByproductsForCleanTarget(config).push_back(targetOutputReal); } - if (this->TargetLinkLanguage(config) == "Swift") { + // If we can't split the Swift build model (CMP0157 is OLD or unset), fall + // back on the old one-step "build/link" logic. + if (!this->GetLocalGenerator()->IsSplitSwiftBuild() && + this->TargetLinkLanguage(config) == "Swift") { vars["SWIFT_LIBRARY_NAME"] = [this, config]() -> std::string { cmGeneratorTarget::Names targetNames = this->GetGeneratorTarget()->GetLibraryNames(config); @@ -1222,12 +1225,12 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement( cmOutputConverter::SHELL); vars["SWIFT_SOURCES"] = [this, config]() -> std::string { - std::vector<cmSourceFile const*> sources; + std::vector<cmSourceFile const*> sourceFiles; std::stringstream oss; - this->GetGeneratorTarget()->GetObjectSources(sources, config); + this->GetGeneratorTarget()->GetObjectSources(sourceFiles, config); cmLocalGenerator const* LocalGen = this->GetLocalGenerator(); - for (const auto& source : sources) { + for (const auto& source : sourceFiles) { const std::string sourcePath = source->GetLanguage() == "Swift" ? this->GetCompiledSourceNinjaPath(source) : this->GetObjectFilePath(source, config); @@ -1245,10 +1248,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement( vars["FLAGS"] = this->GetFlags("Swift", config); vars["INCLUDES"] = this->GetIncludes("Swift", config); this->GenerateSwiftOutputFileMap(config, vars["FLAGS"]); - } - // Compute specific libraries to link with. - if (this->TargetLinkLanguage(config) == "Swift") { + // Compute specific libraries to link with. std::vector<cmSourceFile const*> sources; gt->GetObjectSources(sources, config); for (const auto& source : sources) { diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 666d7b6..6367075 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -14,6 +14,7 @@ #include <utility> #include <cm/memory> +#include <cm/optional> #include <cm/string_view> #include <cmext/algorithm> #include <cmext/string_view> @@ -31,6 +32,7 @@ #include "cmGlobalCommonGenerator.h" #include "cmGlobalNinjaGenerator.h" #include "cmList.h" +#include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmLocalNinjaGenerator.h" #include "cmMakefile.h" @@ -47,6 +49,7 @@ #include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmTarget.h" +#include "cmTargetDepend.h" #include "cmValue.h" #include "cmake.h" @@ -145,7 +148,7 @@ std::string cmNinjaTargetGenerator::LanguageScanRule( bool cmNinjaTargetGenerator::NeedExplicitPreprocessing( std::string const& lang) const { - return lang == "Fortran"; + return lang == "Fortran" || lang == "Swift"; } bool cmNinjaTargetGenerator::CompileWithDefines(std::string const& lang) const @@ -1136,9 +1139,18 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements( std::vector<cmSourceFile const*> objectSources; this->GeneratorTarget->GetObjectSources(objectSources, config); + std::vector<cmSourceFile const*> swiftSources; + for (cmSourceFile const* sf : objectSources) { - this->WriteObjectBuildStatement(sf, config, fileConfig, firstForConfig); + if (sf->GetLanguage() == "Swift") { + swiftSources.push_back(sf); + } else { + this->WriteObjectBuildStatement(sf, config, fileConfig, + firstForConfig); + } } + WriteSwiftObjectBuildStatement(swiftSources, config, fileConfig, + firstForConfig); } { @@ -1234,9 +1246,11 @@ void cmNinjaTargetGenerator::GenerateSwiftOutputFileMap( if (cmValue name = target->GetProperty("Swift_DEPENDENCIES_FILE")) { return *name; } - return this->ConvertToNinjaPath(cmStrCat(target->GetSupportDirectory(), - '/', config, '/', - target->GetName(), ".swiftdeps")); + return this->GetLocalGenerator()->ConvertToOutputFormat( + this->ConvertToNinjaPath(cmStrCat(target->GetSupportDirectory(), '/', + config, '/', target->GetName(), + ".swiftdeps")), + cmOutputConverter::SHELL); }(); std::string mapFilePath = @@ -1254,8 +1268,10 @@ void cmNinjaTargetGenerator::GenerateSwiftOutputFileMap( // Add flag this->LocalGenerator->AppendFlags(flags, "-output-file-map"); - this->LocalGenerator->AppendFlagEscape(flags, - ConvertToNinjaPath(mapFilePath)); + this->LocalGenerator->AppendFlagEscape( + flags, + this->GetLocalGenerator()->ConvertToOutputFormat( + ConvertToNinjaPath(mapFilePath), cmOutputConverter::SHELL)); } namespace { @@ -1862,6 +1878,214 @@ void cmNinjaTargetGenerator::WriteCxxModuleBmiBuildStatement( bmiBuild, commandLineLengthLimit); } +void cmNinjaTargetGenerator::WriteSwiftObjectBuildStatement( + std::vector<cmSourceFile const*> const& sources, std::string const& config, + std::string const& fileConfig, bool firstForConfig) +{ + // Swift sources are compiled as a module, not individually like with C/C++. + // Flags, header search paths, and definitions are passed to the entire + // module build, but we still need to emit compile-commands for each source + // file in order to support CMAKE_EXPORT_COMPILE_COMMANDS. + // In whole-module mode, with a single thread, the Swift compiler will + // only emit a single object file, but if more than one thread is specified, + // or building in other modes, the compiler will emit multiple object files. + // When building a single-output, we do not provide an output-file-map (OFM), + // and instead pass `-o` to tell the compiler where to write the object. + // When building multiple outputs, we provide an OFM to tell the compiler + // where to put each object. + // + // + // Per-Target (module): + // - Flags + // - Definitions + // - Include paths + // - (single-output) output object filename + // - Swiftmodule + // + // Per-File: + // - compile-command + // - (multi-output) OFM data + // - (multi-output) output object filename + // + // Note: Due to the differences in the build models, we are only able to + // build the object build-graph if we know what mode the target is built in. + // For that, we need the "NEW" behavior for CMP0157. Otherwise, we have to + // fall back on the old "linker" build. Otherwise, this should be + // indistinguishable from the old behavior. + // + // FIXME(#25490): Add response file support to Swift object build step + // FIXME(#25491): Include all files in module in compile_commands.json + + if (sources.empty()) { + return; + } + + cmSwiftCompileMode compileMode; + if (cm::optional<cmSwiftCompileMode> optionalCompileMode = + this->LocalGenerator->GetSwiftCompileMode(this->GeneratorTarget, + config)) { + compileMode = *optionalCompileMode; + } else { + // CMP0157 is not NEW, bailing early! + return; + } + + auto getTargetPropertyOrDefault = + [](cmGeneratorTarget const& target, std::string const& property, + std::string defaultValue) -> std::string { + if (cmValue value = target.GetProperty(property)) { + return *value; + } + return defaultValue; + }; + + std::string const language = "Swift"; + std::string const objectDir = this->ConvertToNinjaPath( + cmStrCat(this->GeneratorTarget->GetSupportDirectory(), + this->GetGlobalGenerator()->ConfigDirectory(config))); + + cmGeneratorTarget const& target = *this->GeneratorTarget; + cmNinjaBuild objBuild( + this->LanguageCompilerRule(language, config, WithScanning::No)); + cmNinjaVars& vars = objBuild.Variables; + + std::string const moduleName = + getTargetPropertyOrDefault(target, "Swift_MODULE_NAME", target.GetName()); + std::string const moduleDirectory = getTargetPropertyOrDefault( + target, "Swift_MODULE_DIRECTORY", + target.LocalGenerator->GetCurrentBinaryDirectory()); + std::string const moduleFilename = getTargetPropertyOrDefault( + target, "Swift_MODULE", cmStrCat(moduleName, ".swiftmodule")); + std::string const moduleFilepath = + this->ConvertToNinjaPath(cmStrCat(moduleDirectory, '/', moduleFilename)); + + bool const isSingleOutput = [this, compileMode]() -> bool { + bool isMultiThread = false; + if (cmValue numThreadStr = + this->GetMakefile()->GetDefinition("CMAKE_Swift_NUM_THREADS")) { + unsigned long numThreads; + cmStrToULong(*numThreadStr, &numThreads); + // numThreads == 1 is multi-threaded according to swiftc + isMultiThread = numThreads > 0; + } + return !isMultiThread && compileMode == cmSwiftCompileMode::Wholemodule; + }(); + + // Swift modules only make sense to emit from things that can be imported. + // Executables that don't export symbols can't be imported, so don't try to + // emit a swiftmodule for them. It will break. + if (target.GetType() != cmStateEnums::EXECUTABLE || + target.IsExecutableWithExports()) { + std::string const emitModuleFlag = "-emit-module"; + std::string const modulePathFlag = "-emit-module-path"; + this->LocalGenerator->AppendFlags( + vars["FLAGS"], { emitModuleFlag, modulePathFlag, moduleFilepath }); + objBuild.Outputs.push_back(moduleFilepath); + + std::string const moduleNameFlag = "-module-name"; + this->LocalGenerator->AppendFlags( + vars["FLAGS"], cmStrCat(moduleNameFlag, ' ', moduleName)); + } + + if (target.GetType() != cmStateEnums::EXECUTABLE) { + std::string const libraryLinkNameFlag = "-module-link-name"; + std::string const libraryLinkName = + this->GetGeneratorTarget()->GetLibraryNames(config).Base; + this->LocalGenerator->AppendFlags( + vars["FLAGS"], cmStrCat(libraryLinkNameFlag, ' ', libraryLinkName)); + } + + // Without `-emit-library` or `-emit-executable`, targets with a single + // source file parse as a Swift script instead of like normal source. For + // non-executable targets, append this to ensure that they are parsed like a + // normal source. + if (target.GetType() != cmStateEnums::EXECUTABLE) { + this->LocalGenerator->AppendFlags(vars["FLAGS"], "-parse-as-library"); + } + + this->LocalGenerator->AppendFlags(vars["FLAGS"], + this->GetFlags(language, config)); + vars["DEFINES"] = this->GetDefines(language, config); + vars["INCLUDES"] = this->GetIncludes(language, config); + + // target-level object filename + std::string const targetObjectFilename = this->ConvertToNinjaPath(cmStrCat( + objectDir, '/', moduleName, + this->GetGlobalGenerator()->GetLanguageOutputExtension(language))); + + if (isSingleOutput) { + this->LocalGenerator->AppendFlags(vars["FLAGS"], + cmStrCat("-o ", targetObjectFilename)); + objBuild.Outputs.push_back(targetObjectFilename); + this->Configs[config].Objects.push_back(targetObjectFilename); + } + + for (cmSourceFile const* sf : sources) { + // Add dependency to object build on each source file + std::string const sourceFilePath = this->GetCompiledSourceNinjaPath(sf); + objBuild.ExplicitDeps.push_back(sourceFilePath); + + if (isSingleOutput) { + if (firstForConfig) { + this->ExportObjectCompileCommand( + language, sourceFilePath, objectDir, targetObjectFilename, + cmSystemTools::GetFilenamePath(targetObjectFilename), vars["FLAGS"], + vars["DEFINES"], vars["INCLUDES"], + /*compile pdb*/ "", /*target pdb*/ "", config); + } + } else { + // Object outputs + std::string const objectFilepath = + this->ConvertToNinjaPath(this->GetObjectFilePath(sf, config)); + this->EnsureParentDirectoryExists(objectFilepath); + objBuild.Outputs.push_back(objectFilepath); + this->Configs[config].Objects.push_back(objectFilepath); + + // Add OFM data + this->EmitSwiftDependencyInfo(sf, config); + + // Emit compile commands + if (firstForConfig) { + this->ExportObjectCompileCommand( + language, sourceFilePath, objectDir, objectFilepath, + cmSystemTools::GetFilenamePath(objectFilepath), vars["FLAGS"], + vars["DEFINES"], vars["INCLUDES"], + /*compile pdb*/ "", + /*target pdb*/ "", config); + } + } + } + + if (!isSingleOutput) { + this->GenerateSwiftOutputFileMap(config, vars["FLAGS"]); + } + + for (cmTargetDepend const& dep : + this->GetGlobalGenerator()->GetTargetDirectDepends(&target)) { + if (!dep->IsLanguageUsed("Swift", config)) { + continue; + } + // Add dependencies on the emitted swiftmodule file from swift targets we + // depend on + std::string const depModuleName = + getTargetPropertyOrDefault(*dep, "Swift_MODULE_NAME", dep->GetName()); + std::string const depModuleDir = getTargetPropertyOrDefault( + *dep, "Swift_MODULE_DIRECTORY", + dep->LocalGenerator->GetCurrentBinaryDirectory()); + std::string const depModuleFilename = getTargetPropertyOrDefault( + *dep, "Swift_MODULE", cmStrCat(depModuleName, ".swiftmodule")); + std::string const depModuleFilepath = + this->ConvertToNinjaPath(cmStrCat(depModuleDir, '/', depModuleFilename)); + objBuild.ImplicitDeps.push_back(depModuleFilepath); + } + + objBuild.OrderOnlyDeps.push_back(this->OrderDependsTargetForTarget(config)); + + // Write object build + this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig), + objBuild); +} + void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang, const std::string& config) { diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h index 2131f6d..7a68599 100644 --- a/Source/cmNinjaTargetGenerator.h +++ b/Source/cmNinjaTargetGenerator.h @@ -171,6 +171,9 @@ protected: const std::string& config, const std::string& fileConfig, bool firstForConfig); + void WriteSwiftObjectBuildStatement( + std::vector<cmSourceFile const*> const& sources, const std::string& config, + const std::string& fileConfig, bool firstForConfig); void WriteObjectBuildStatement(cmSourceFile const* source, const std::string& config, const std::string& fileConfig, diff --git a/Tests/RunCMake/Swift/IncrementalSwift-second-stdout.txt b/Tests/RunCMake/Swift/IncrementalSwift-second-stdout.txt index bb08a49..d644d6b 100644 --- a/Tests/RunCMake/Swift/IncrementalSwift-second-stdout.txt +++ b/Tests/RunCMake/Swift/IncrementalSwift-second-stdout.txt @@ -1,3 +1,3 @@ -.*Linking Swift static library libA.a -.*Linking Swift static library libB.a -FAILED: libB.a CMakeFiles/B.dir/b.swift.o B.swiftmodule +.*Building Swift object A.swiftmodule CMakeFiles/A.dir/a.swift.o +.*Building Swift object B.swiftmodule CMakeFiles/B.dir/b.swift.o +FAILED: B.swiftmodule CMakeFiles/B.dir/b.swift.o diff --git a/Tests/SwiftOnly/CMakeLists.txt b/Tests/SwiftOnly/CMakeLists.txt index 7de1e04..2aa5710 100644 --- a/Tests/SwiftOnly/CMakeLists.txt +++ b/Tests/SwiftOnly/CMakeLists.txt @@ -43,6 +43,13 @@ add_library(N N.swift) target_link_libraries(N PUBLIC M) +if(NOT XCODE_VERSION OR XCODE_VERSION VERSION_GREATER_EQUAL 9.0) + # TODO: Add a wholemodule object-library test once that is working + add_library(O OBJECT O.swift L.swift) + target_link_libraries(N PUBLIC O) + set_target_properties(O PROPERTIES Swift_COMPILATION_MODE "incremental") +endif() + # Dummy to make sure generation works with such targets. add_library(SwiftIface INTERFACE) target_link_libraries(SwiftOnly PRIVATE SwiftIface) @@ -59,14 +66,15 @@ if(CMAKE_Swift_COMPILER_VERSION VERSION_GREATER_EQUAL 5.2) endif() function(test_cmp0157_default mode) - - cmake_policy(GET CMP0157 cmp0157_wmo) - if(cmp0157_wmo STREQUAL "NEW") - set(CMAKE_Swift_COMPILATION_MODE "${mode}") - add_executable(hi_${mode} main.swift) - get_target_property(${mode}_swift_comp_mode hi_${mode} "Swift_COMPILATION_MODE") - if(NOT ${mode}_swift_comp_mode STREQUAL ${mode}) - message(SEND_ERROR "expected ${mode} -- found ${${mode}_swift_comp_mode}") + if(POLICY CMP0157) + cmake_policy(GET CMP0157 cmp0157_wmo) + if(cmp0157_wmo STREQUAL "NEW") + set(CMAKE_Swift_COMPILATION_MODE "${mode}") + add_executable(hi_${mode} main.swift) + get_target_property(${mode}_swift_comp_mode hi_${mode} "Swift_COMPILATION_MODE") + if(NOT ${mode}_swift_comp_mode STREQUAL ${mode}) + message(SEND_ERROR "expected ${mode} -- found ${${mode}_swift_comp_mode}") + endif() endif() endif() endfunction() diff --git a/Tests/SwiftOnly/O.swift b/Tests/SwiftOnly/O.swift new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Tests/SwiftOnly/O.swift |