From 0b56f92576232d82a23ab37c597ef9af84daf9e5 Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 10 Nov 2021 11:22:14 -0500 Subject: cmLocalGenerator: De-duplicate unity source file generation --- Source/cmLocalGenerator.cxx | 72 ++++++++++++++++++++------------------------- Source/cmLocalGenerator.h | 8 +++++ 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 68a6a44..66b49e0 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -37,6 +37,7 @@ #include "cmInstallTargetGenerator.h" #include "cmLinkLineComputer.h" #include "cmMakefile.h" +#include "cmRange.h" #include "cmRulePlaceholderExpander.h" #include "cmSourceFile.h" #include "cmSourceFileLocation.h" @@ -2806,6 +2807,29 @@ inline void RegisterUnitySources(cmGeneratorTarget* target, cmSourceFile* sf, } } +std::string cmLocalGenerator::WriteUnitySource( + cmGeneratorTarget* target, + cmRange::const_iterator> sources, + cmValue beforeInclude, cmValue afterInclude, std::string filename) const +{ + cmValue uniqueIdName = target->GetProperty("UNITY_BUILD_UNIQUE_ID"); + const std::string filename_tmp = cmStrCat(filename, ".tmp"); + { + cmGeneratedFileStream file( + filename_tmp, false, + target->GetGlobalGenerator()->GetMakefileEncoding()); + file << "/* generated by CMake */\n\n"; + + for (cmSourceFile* sf : sources) { + RegisterUnitySources(target, sf, filename); + IncludeFileInUnitySources(file, sf->ResolveFullPath(), beforeInclude, + afterInclude, uniqueIdName); + } + } + cmSystemTools::MoveFileIfDifferent(filename_tmp, filename); + return filename; +} + void cmLocalGenerator::IncludeFileInUnitySources( cmGeneratedFileStream& unity_file, std::string const& sf_full_path, cmValue beforeInclude, cmValue afterInclude, cmValue uniqueIdName) const @@ -2856,8 +2880,6 @@ std::vector cmLocalGenerator::AddUnityFilesModeAuto( batchSize = filtered_sources.size(); } - cmValue uniqueIdName = target->GetProperty("UNITY_BUILD_UNIQUE_ID"); - std::vector unity_files; for (size_t itemsLeft = filtered_sources.size(), chunk, batch = 0; itemsLeft > 0; itemsLeft -= chunk, ++batch) { @@ -2866,26 +2888,11 @@ std::vector cmLocalGenerator::AddUnityFilesModeAuto( std::string filename = cmStrCat(filename_base, "unity_", batch, (lang == "C") ? "_c.c" : "_cxx.cxx"); - - const std::string filename_tmp = cmStrCat(filename, ".tmp"); - { - size_t begin = batch * batchSize; - size_t end = begin + chunk; - - cmGeneratedFileStream file( - filename_tmp, false, - target->GetGlobalGenerator()->GetMakefileEncoding()); - file << "/* generated by CMake */\n\n"; - - for (; begin != end; ++begin) { - cmSourceFile* sf = filtered_sources[begin]; - RegisterUnitySources(target, sf, filename); - IncludeFileInUnitySources(file, sf->ResolveFullPath(), beforeInclude, - afterInclude, uniqueIdName); - } - } - cmSystemTools::MoveFileIfDifferent(filename_tmp, filename); - unity_files.emplace_back(std::move(filename)); + auto const begin = filtered_sources.begin() + batch * batchSize; + auto const end = begin + chunk; + unity_files.emplace_back( + this->WriteUnitySource(target, cmMakeRange(begin, end), beforeInclude, + afterInclude, std::move(filename))); } return unity_files; } @@ -2912,28 +2919,13 @@ std::vector cmLocalGenerator::AddUnityFilesModeGroup( } } - cmValue uniqueIdName = target->GetProperty("UNITY_BUILD_UNIQUE_ID"); - for (auto const& item : explicit_mapping) { auto const& name = item.first; std::string filename = cmStrCat(filename_base, "unity_", name, (lang == "C") ? "_c.c" : "_cxx.cxx"); - - const std::string filename_tmp = cmStrCat(filename, ".tmp"); - { - cmGeneratedFileStream file( - filename_tmp, false, - target->GetGlobalGenerator()->GetMakefileEncoding()); - file << "/* generated by CMake */\n\n"; - - for (cmSourceFile* sf : item.second) { - RegisterUnitySources(target, sf, filename); - IncludeFileInUnitySources(file, sf->ResolveFullPath(), beforeInclude, - afterInclude, uniqueIdName); - } - } - cmSystemTools::MoveFileIfDifferent(filename_tmp, filename); - unity_files.emplace_back(std::move(filename)); + unity_files.emplace_back( + this->WriteUnitySource(target, cmMakeRange(item.second), beforeInclude, + afterInclude, std::move(filename))); } return unity_files; diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index b86c8e8..7078482 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -40,6 +40,9 @@ class cmState; class cmTarget; class cmake; +template +class cmRange; + /** Flag if byproducts shall also be considered. */ enum class cmSourceOutputKind { @@ -657,6 +660,11 @@ private: const std::string& ReuseFrom, cmGeneratorTarget* reuseTarget, std::vector const& extensions); + + std::string WriteUnitySource( + cmGeneratorTarget* target, + cmRange::const_iterator> sources, + cmValue beforeInclude, cmValue afterInclude, std::string filename) const; void IncludeFileInUnitySources(cmGeneratedFileStream& unity_file, std::string const& sf_full_path, cmValue beforeInclude, cmValue afterInclude, -- cgit v0.12 From 3017b3e7d4da702c8b1e2dbfb9657b7517e108b8 Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 10 Nov 2021 11:25:12 -0500 Subject: cmLocalGenerator: Simplify unity source copy-if-different logic --- Source/cmLocalGenerator.cxx | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 66b49e0..2b5b711 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -2813,20 +2813,15 @@ std::string cmLocalGenerator::WriteUnitySource( cmValue beforeInclude, cmValue afterInclude, std::string filename) const { cmValue uniqueIdName = target->GetProperty("UNITY_BUILD_UNIQUE_ID"); - const std::string filename_tmp = cmStrCat(filename, ".tmp"); - { - cmGeneratedFileStream file( - filename_tmp, false, - target->GetGlobalGenerator()->GetMakefileEncoding()); - file << "/* generated by CMake */\n\n"; - - for (cmSourceFile* sf : sources) { - RegisterUnitySources(target, sf, filename); - IncludeFileInUnitySources(file, sf->ResolveFullPath(), beforeInclude, - afterInclude, uniqueIdName); - } + cmGeneratedFileStream file( + filename, false, target->GetGlobalGenerator()->GetMakefileEncoding()); + file.SetCopyIfDifferent(true); + file << "/* generated by CMake */\n\n"; + for (cmSourceFile* sf : sources) { + RegisterUnitySources(target, sf, filename); + IncludeFileInUnitySources(file, sf->ResolveFullPath(), beforeInclude, + afterInclude, uniqueIdName); } - cmSystemTools::MoveFileIfDifferent(filename_tmp, filename); return filename; } -- cgit v0.12 From de6e362a88bc67d8376ad261f21b9b9ecefd1282 Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 10 Nov 2021 11:32:37 -0500 Subject: cmLocalGenerator: Clarify name of method to write unity source include lines --- Source/cmLocalGenerator.cxx | 12 +++++++----- Source/cmLocalGenerator.h | 9 ++++----- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 2b5b711..8658281 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -2819,15 +2819,17 @@ std::string cmLocalGenerator::WriteUnitySource( file << "/* generated by CMake */\n\n"; for (cmSourceFile* sf : sources) { RegisterUnitySources(target, sf, filename); - IncludeFileInUnitySources(file, sf->ResolveFullPath(), beforeInclude, - afterInclude, uniqueIdName); + WriteUnitySourceInclude(file, sf->ResolveFullPath(), beforeInclude, + afterInclude, uniqueIdName); } return filename; } -void cmLocalGenerator::IncludeFileInUnitySources( - cmGeneratedFileStream& unity_file, std::string const& sf_full_path, - cmValue beforeInclude, cmValue afterInclude, cmValue uniqueIdName) const +void cmLocalGenerator::WriteUnitySourceInclude(std::ostream& unity_file, + std::string const& sf_full_path, + cmValue beforeInclude, + cmValue afterInclude, + cmValue uniqueIdName) const { if (cmNonempty(uniqueIdName)) { std::string pathToHash; diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index 7078482..5e7de0e 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -28,7 +28,6 @@ class cmComputeLinkInformation; class cmCustomCommand; class cmCustomCommandGenerator; class cmCustomCommandLines; -class cmGeneratedFileStream; class cmGeneratorTarget; class cmGlobalGenerator; class cmImplicitDependsList; @@ -665,10 +664,10 @@ private: cmGeneratorTarget* target, cmRange::const_iterator> sources, cmValue beforeInclude, cmValue afterInclude, std::string filename) const; - void IncludeFileInUnitySources(cmGeneratedFileStream& unity_file, - std::string const& sf_full_path, - cmValue beforeInclude, cmValue afterInclude, - cmValue uniqueIdName) const; + void WriteUnitySourceInclude(std::ostream& unity_file, + std::string const& sf_full_path, + cmValue beforeInclude, cmValue afterInclude, + cmValue uniqueIdName) const; std::vector AddUnityFilesModeAuto( cmGeneratorTarget* target, std::string const& lang, std::vector const& filtered_sources, cmValue beforeInclude, -- cgit v0.12 From 53990059daed056fc5a2c15df70444a2f8da704f Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 10 Nov 2021 11:57:01 -0500 Subject: cmLocalGenerator: Add dedicated types to hold unity source info --- Source/cmLocalGenerator.cxx | 89 +++++++++++++++++++++++++++------------------ Source/cmLocalGenerator.h | 36 ++++++++++++++---- 2 files changed, 81 insertions(+), 44 deletions(-) diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 8658281..3ac77c1 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -2807,9 +2807,9 @@ inline void RegisterUnitySources(cmGeneratorTarget* target, cmSourceFile* sf, } } -std::string cmLocalGenerator::WriteUnitySource( +cmLocalGenerator::UnitySource cmLocalGenerator::WriteUnitySource( cmGeneratorTarget* target, - cmRange::const_iterator> sources, + cmRange::const_iterator> sources, cmValue beforeInclude, cmValue afterInclude, std::string filename) const { cmValue uniqueIdName = target->GetProperty("UNITY_BUILD_UNIQUE_ID"); @@ -2817,12 +2817,14 @@ std::string cmLocalGenerator::WriteUnitySource( filename, false, target->GetGlobalGenerator()->GetMakefileEncoding()); file.SetCopyIfDifferent(true); file << "/* generated by CMake */\n\n"; - for (cmSourceFile* sf : sources) { - RegisterUnitySources(target, sf, filename); - WriteUnitySourceInclude(file, sf->ResolveFullPath(), beforeInclude, + + for (UnityBatchedSource const& ubs : sources) { + RegisterUnitySources(target, ubs.Source, filename); + WriteUnitySourceInclude(file, ubs.Source->ResolveFullPath(), beforeInclude, afterInclude, uniqueIdName); } - return filename; + + return UnitySource(std::move(filename)); } void cmLocalGenerator::WriteUnitySourceInclude(std::ostream& unity_file, @@ -2868,16 +2870,18 @@ void cmLocalGenerator::WriteUnitySourceInclude(std::ostream& unity_file, unity_file << "\n"; } -std::vector cmLocalGenerator::AddUnityFilesModeAuto( +std::vector +cmLocalGenerator::AddUnityFilesModeAuto( cmGeneratorTarget* target, std::string const& lang, - std::vector const& filtered_sources, cmValue beforeInclude, - cmValue afterInclude, std::string const& filename_base, size_t batchSize) + std::vector const& filtered_sources, + cmValue beforeInclude, cmValue afterInclude, + std::string const& filename_base, size_t batchSize) { if (batchSize == 0) { batchSize = filtered_sources.size(); } - std::vector unity_files; + std::vector unity_files; for (size_t itemsLeft = filtered_sources.size(), chunk, batch = 0; itemsLeft > 0; itemsLeft -= chunk, ++batch) { @@ -2894,24 +2898,27 @@ std::vector cmLocalGenerator::AddUnityFilesModeAuto( return unity_files; } -std::vector cmLocalGenerator::AddUnityFilesModeGroup( +std::vector +cmLocalGenerator::AddUnityFilesModeGroup( cmGeneratorTarget* target, std::string const& lang, - std::vector const& filtered_sources, cmValue beforeInclude, - cmValue afterInclude, std::string const& filename_base) + std::vector const& filtered_sources, + cmValue beforeInclude, cmValue afterInclude, + std::string const& filename_base) { - std::vector unity_files; + std::vector unity_files; // sources organized by group name. Drop any source // without a group - std::unordered_map> explicit_mapping; - for (cmSourceFile* sf : filtered_sources) { - if (cmValue value = sf->GetProperty("UNITY_GROUP")) { + std::unordered_map> + explicit_mapping; + for (UnityBatchedSource const& ubs : filtered_sources) { + if (cmValue value = ubs.Source->GetProperty("UNITY_GROUP")) { auto i = explicit_mapping.find(*value); if (i == explicit_mapping.end()) { - std::vector sources{ sf }; - explicit_mapping.emplace(*value, sources); + std::vector sources{ ubs }; + explicit_mapping.emplace(*value, std::move(sources)); } else { - i->second.emplace_back(sf); + i->second.emplace_back(ubs); } } } @@ -2934,20 +2941,28 @@ void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target) return; } - // FIXME: Handle all configurations in multi-config generators. - std::string config; - if (!this->GetGlobalGenerator()->IsMultiConfig()) { - config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"); + std::vector unitySources; + + { + // FIXME: Handle all configurations in multi-config generators. + std::string config; + if (!this->GetGlobalGenerator()->IsMultiConfig()) { + config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"); + } + + // FIXME: Refactor collection of sources to not evaluate object libraries. + std::vector sources; + target->GetSourceFiles(sources, config); + + for (cmSourceFile* sf : sources) { + unitySources.emplace_back(sf); + } } std::string filename_base = cmStrCat(this->GetCurrentBinaryDirectory(), "/CMakeFiles/", target->GetName(), ".dir/Unity/"); - // FIXME: Refactor collection of sources to not evaluate object libraries. - std::vector sources; - target->GetSourceFiles(sources, config); - cmValue batchSizeString = target->GetProperty("UNITY_BUILD_BATCH_SIZE"); const size_t unityBatchSize = batchSizeString ? static_cast(std::atoi(batchSizeString->c_str())) @@ -2959,9 +2974,11 @@ void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target) cmValue unityMode = target->GetProperty("UNITY_BUILD_MODE"); for (std::string lang : { "C", "CXX" }) { - std::vector filtered_sources; - std::copy_if(sources.begin(), sources.end(), - std::back_inserter(filtered_sources), [&](cmSourceFile* sf) { + std::vector filtered_sources; + std::copy_if(unitySources.begin(), unitySources.end(), + std::back_inserter(filtered_sources), + [&](UnityBatchedSource const& ubs) -> bool { + cmSourceFile* sf = ubs.Source; return sf->GetLanguage() == lang && !sf->GetPropertyAsBool("SKIP_UNITY_BUILD_INCLUSION") && !sf->GetPropertyAsBool("HEADER_FILE_ONLY") && @@ -2971,7 +2988,7 @@ void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target) !sf->GetProperty("INCLUDE_DIRECTORIES"); }); - std::vector unity_files; + std::vector unity_files; if (!unityMode || *unityMode == "BATCH") { unity_files = AddUnityFilesModeAuto(target, lang, filtered_sources, beforeInclude, @@ -2988,11 +3005,11 @@ void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target) this->IssueMessage(MessageType::FATAL_ERROR, e); } - for (auto const& file : unity_files) { - auto* unity = this->GetMakefile()->GetOrCreateSource(file); - target->AddSource(file, true); + for (UnitySource const& file : unity_files) { + auto* unity = this->GetMakefile()->GetOrCreateSource(file.Path); + target->AddSource(file.Path, true); unity->SetProperty("SKIP_UNITY_BUILD_INCLUSION", "ON"); - unity->SetProperty("UNITY_SOURCE_FILE", file); + unity->SetProperty("UNITY_SOURCE_FILE", file.Path); } } } diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index 5e7de0e..4c9714b 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -660,22 +661,41 @@ private: cmGeneratorTarget* reuseTarget, std::vector const& extensions); - std::string WriteUnitySource( + struct UnityBatchedSource + { + cmSourceFile* Source = nullptr; + UnityBatchedSource(cmSourceFile* sf) + : Source(sf) + { + } + }; + struct UnitySource + { + std::string Path; + UnitySource(std::string path) + : Path(std::move(path)) + { + } + }; + + UnitySource WriteUnitySource( cmGeneratorTarget* target, - cmRange::const_iterator> sources, + cmRange::const_iterator> sources, cmValue beforeInclude, cmValue afterInclude, std::string filename) const; void WriteUnitySourceInclude(std::ostream& unity_file, std::string const& sf_full_path, cmValue beforeInclude, cmValue afterInclude, cmValue uniqueIdName) const; - std::vector AddUnityFilesModeAuto( + std::vector AddUnityFilesModeAuto( cmGeneratorTarget* target, std::string const& lang, - std::vector const& filtered_sources, cmValue beforeInclude, - cmValue afterInclude, std::string const& filename_base, size_t batchSize); - std::vector AddUnityFilesModeGroup( + std::vector const& filtered_sources, + cmValue beforeInclude, cmValue afterInclude, + std::string const& filename_base, size_t batchSize); + std::vector AddUnityFilesModeGroup( cmGeneratorTarget* target, std::string const& lang, - std::vector const& filtered_sources, cmValue beforeInclude, - cmValue afterInclude, std::string const& filename_base); + std::vector const& filtered_sources, + cmValue beforeInclude, cmValue afterInclude, + std::string const& filename_base); }; #if !defined(CMAKE_BOOTSTRAP) -- cgit v0.12 From ea289314ef473d6bcdc1ca858aac6cdb15ecf56a Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 11 Nov 2021 07:07:02 -0500 Subject: VS: Fix pre-VS15.8 unity build exclusion of per-config sources In a unity build, the original source files need to be excluded from the build. Prior to VS 15.8, this is done via `ExcludeFromBuild`, which is the same mechanism used to implement per-config sources. Fix a conflict in the implementation of the two features so that unity-batched sources are excluded from all configurations rather than just those in which they would otherwise have been included. --- Source/cmVisualStudio10TargetGenerator.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index a7822b2..cd4326f 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -2351,7 +2351,7 @@ void cmVisualStudio10TargetGenerator::WriteAllSources(Elem& e0) // Visual Studio versions prior to 2017 15.8 do not know about unity // builds, thus we exclude the files already part of unity sources. if (!si.Source->GetPropertyAsBool("SKIP_UNITY_BUILD_INCLUSION")) { - exclude_configs = si.Configs; + exclude_configs = all_configs; } } } -- cgit v0.12 From 129e3c65400a96c1f99b0fd6d445f1b9dc38ad51 Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 10 Nov 2021 12:16:22 -0500 Subject: Unity Build: Fix per-config sources in multi-config generators Single-config generators already support unity builds with per-config sources because they compute sources using `CMAKE_BUILD_TYPE` as the configuration. Each original source is either included in the unity build source, or not. Teach multi-config generators to compute the list of sources for inclusion in unity builds using all configurations. Previously they only used the empty string as the configuration. Each original source may be included in some configurations, but not others. Use preprocessor conditions to guard their inclusion when necessary. Fixes: #22892 --- Source/cmLocalGenerator.cxx | 87 +++++++++++++++++--------- Source/cmLocalGenerator.h | 12 +++- Tests/RunCMake/UnityBuild/RunCMakeTest.cmake | 16 +++++ Tests/RunCMake/UnityBuild/per_config_c.c | 16 +++++ Tests/RunCMake/UnityBuild/per_config_c.cmake | 12 ++++ Tests/RunCMake/UnityBuild/per_config_c_debug.c | 9 +++ Tests/RunCMake/UnityBuild/per_config_c_other.c | 9 +++ 7 files changed, 130 insertions(+), 31 deletions(-) create mode 100644 Tests/RunCMake/UnityBuild/per_config_c.c create mode 100644 Tests/RunCMake/UnityBuild/per_config_c.cmake create mode 100644 Tests/RunCMake/UnityBuild/per_config_c_debug.c create mode 100644 Tests/RunCMake/UnityBuild/per_config_c_other.c diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 3ac77c1..c106137 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -2808,7 +2808,7 @@ inline void RegisterUnitySources(cmGeneratorTarget* target, cmSourceFile* sf, } cmLocalGenerator::UnitySource cmLocalGenerator::WriteUnitySource( - cmGeneratorTarget* target, + cmGeneratorTarget* target, std::vector const& configs, cmRange::const_iterator> sources, cmValue beforeInclude, cmValue afterInclude, std::string filename) const { @@ -2818,21 +2818,36 @@ cmLocalGenerator::UnitySource cmLocalGenerator::WriteUnitySource( file.SetCopyIfDifferent(true); file << "/* generated by CMake */\n\n"; + bool perConfig = false; for (UnityBatchedSource const& ubs : sources) { + cm::optional cond; + if (ubs.Configs.size() != configs.size()) { + perConfig = true; + cond = std::string(); + cm::string_view sep; + for (size_t ci : ubs.Configs) { + cond = cmStrCat(*cond, sep, "defined(CMAKE_UNITY_CONFIG_", + cmSystemTools::UpperCase(configs[ci]), ")"); + sep = " || "_s; + } + } RegisterUnitySources(target, ubs.Source, filename); - WriteUnitySourceInclude(file, ubs.Source->ResolveFullPath(), beforeInclude, - afterInclude, uniqueIdName); + WriteUnitySourceInclude(file, cond, ubs.Source->ResolveFullPath(), + beforeInclude, afterInclude, uniqueIdName); } - return UnitySource(std::move(filename)); + return UnitySource(std::move(filename), perConfig); } -void cmLocalGenerator::WriteUnitySourceInclude(std::ostream& unity_file, - std::string const& sf_full_path, - cmValue beforeInclude, - cmValue afterInclude, - cmValue uniqueIdName) const +void cmLocalGenerator::WriteUnitySourceInclude( + std::ostream& unity_file, cm::optional const& cond, + std::string const& sf_full_path, cmValue beforeInclude, cmValue afterInclude, + cmValue uniqueIdName) const { + if (cond) { + unity_file << "#if " << *cond << "\n"; + } + if (cmNonempty(uniqueIdName)) { std::string pathToHash; auto PathEqOrSubDir = [](std::string const& a, std::string const& b) { @@ -2867,12 +2882,16 @@ void cmLocalGenerator::WriteUnitySourceInclude(std::ostream& unity_file, if (afterInclude) { unity_file << *afterInclude << "\n"; } + if (cond) { + unity_file << "#endif\n"; + } unity_file << "\n"; } std::vector cmLocalGenerator::AddUnityFilesModeAuto( cmGeneratorTarget* target, std::string const& lang, + std::vector const& configs, std::vector const& filtered_sources, cmValue beforeInclude, cmValue afterInclude, std::string const& filename_base, size_t batchSize) @@ -2891,9 +2910,9 @@ cmLocalGenerator::AddUnityFilesModeAuto( (lang == "C") ? "_c.c" : "_cxx.cxx"); auto const begin = filtered_sources.begin() + batch * batchSize; auto const end = begin + chunk; - unity_files.emplace_back( - this->WriteUnitySource(target, cmMakeRange(begin, end), beforeInclude, - afterInclude, std::move(filename))); + unity_files.emplace_back(this->WriteUnitySource( + target, configs, cmMakeRange(begin, end), beforeInclude, afterInclude, + std::move(filename))); } return unity_files; } @@ -2901,6 +2920,7 @@ cmLocalGenerator::AddUnityFilesModeAuto( std::vector cmLocalGenerator::AddUnityFilesModeGroup( cmGeneratorTarget* target, std::string const& lang, + std::vector const& configs, std::vector const& filtered_sources, cmValue beforeInclude, cmValue afterInclude, std::string const& filename_base) @@ -2927,9 +2947,9 @@ cmLocalGenerator::AddUnityFilesModeGroup( auto const& name = item.first; std::string filename = cmStrCat(filename_base, "unity_", name, (lang == "C") ? "_c.c" : "_cxx.cxx"); - unity_files.emplace_back( - this->WriteUnitySource(target, cmMakeRange(item.second), beforeInclude, - afterInclude, std::move(filename))); + unity_files.emplace_back(this->WriteUnitySource( + target, configs, cmMakeRange(item.second), beforeInclude, afterInclude, + std::move(filename))); } return unity_files; @@ -2943,19 +2963,24 @@ void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target) std::vector unitySources; - { - // FIXME: Handle all configurations in multi-config generators. - std::string config; - if (!this->GetGlobalGenerator()->IsMultiConfig()) { - config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"); - } + std::vector configs = + this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); + + std::map index; + for (size_t ci = 0; ci < configs.size(); ++ci) { // FIXME: Refactor collection of sources to not evaluate object libraries. std::vector sources; - target->GetSourceFiles(sources, config); - + target->GetSourceFiles(sources, configs[ci]); for (cmSourceFile* sf : sources) { - unitySources.emplace_back(sf); + auto mi = index.find(sf); + if (mi == index.end()) { + unitySources.emplace_back(sf); + std::map::value_type entry( + sf, unitySources.size() - 1); + mi = index.insert(entry).first; + } + unitySources[mi->second].Configs.emplace_back(ci); } } @@ -2990,13 +3015,13 @@ void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target) std::vector unity_files; if (!unityMode || *unityMode == "BATCH") { - unity_files = - AddUnityFilesModeAuto(target, lang, filtered_sources, beforeInclude, - afterInclude, filename_base, unityBatchSize); + unity_files = AddUnityFilesModeAuto( + target, lang, configs, filtered_sources, beforeInclude, afterInclude, + filename_base, unityBatchSize); } else if (unityMode && *unityMode == "GROUP") { unity_files = - AddUnityFilesModeGroup(target, lang, filtered_sources, beforeInclude, - afterInclude, filename_base); + AddUnityFilesModeGroup(target, lang, configs, filtered_sources, + beforeInclude, afterInclude, filename_base); } else { // unity mode is set to an unsupported value std::string e("Invalid UNITY_BUILD_MODE value of " + *unityMode + @@ -3010,6 +3035,10 @@ void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target) target->AddSource(file.Path, true); unity->SetProperty("SKIP_UNITY_BUILD_INCLUSION", "ON"); unity->SetProperty("UNITY_SOURCE_FILE", file.Path); + if (file.PerConfig) { + unity->SetProperty("COMPILE_DEFINITIONS", + "CMAKE_UNITY_CONFIG_$>"); + } } } } diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index 4c9714b..726817a 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -14,6 +14,8 @@ #include #include +#include + #include #include "cmCustomCommandTypes.h" @@ -664,6 +666,7 @@ private: struct UnityBatchedSource { cmSourceFile* Source = nullptr; + std::vector Configs; UnityBatchedSource(cmSourceFile* sf) : Source(sf) { @@ -672,27 +675,32 @@ private: struct UnitySource { std::string Path; - UnitySource(std::string path) + bool PerConfig = false; + UnitySource(std::string path, bool perConfig) : Path(std::move(path)) + , PerConfig(perConfig) { } }; UnitySource WriteUnitySource( - cmGeneratorTarget* target, + cmGeneratorTarget* target, std::vector const& configs, cmRange::const_iterator> sources, cmValue beforeInclude, cmValue afterInclude, std::string filename) const; void WriteUnitySourceInclude(std::ostream& unity_file, + cm::optional const& cond, std::string const& sf_full_path, cmValue beforeInclude, cmValue afterInclude, cmValue uniqueIdName) const; std::vector AddUnityFilesModeAuto( cmGeneratorTarget* target, std::string const& lang, + std::vector const& configs, std::vector const& filtered_sources, cmValue beforeInclude, cmValue afterInclude, std::string const& filename_base, size_t batchSize); std::vector AddUnityFilesModeGroup( cmGeneratorTarget* target, std::string const& lang, + std::vector const& configs, std::vector const& filtered_sources, cmValue beforeInclude, cmValue afterInclude, std::string const& filename_base); diff --git a/Tests/RunCMake/UnityBuild/RunCMakeTest.cmake b/Tests/RunCMake/UnityBuild/RunCMakeTest.cmake index 8019f09..e3643c0 100644 --- a/Tests/RunCMake/UnityBuild/RunCMakeTest.cmake +++ b/Tests/RunCMake/UnityBuild/RunCMakeTest.cmake @@ -26,6 +26,22 @@ run_build(unitybuild_anon_ns) run_build(unitybuild_anon_ns_no_unity_build) run_build(unitybuild_anon_ns_group_mode) +function(run_per_config name) + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${name}-build) + run_cmake(${name}) + set(RunCMake_TEST_NO_CLEAN 1) + if(RunCMake_GENERATOR_IS_MULTI_CONFIG) + run_cmake_command(${name}-build-debug ${CMAKE_COMMAND} --build . --config Debug) + run_cmake_command(${name}-build-release ${CMAKE_COMMAND} --build . --config Release) + else() + run_cmake_command(${name}-build ${CMAKE_COMMAND} --build .) + endif() +endfunction() + +if(NOT RunCMake_GENERATOR STREQUAL "Xcode") + run_per_config(per_config_c) +endif() + function(run_test name) set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${name}-build) run_cmake(${name}) diff --git a/Tests/RunCMake/UnityBuild/per_config_c.c b/Tests/RunCMake/UnityBuild/per_config_c.c new file mode 100644 index 0000000..081c7d3 --- /dev/null +++ b/Tests/RunCMake/UnityBuild/per_config_c.c @@ -0,0 +1,16 @@ +#ifdef CFG_DEBUG +extern void per_config_c_debug(void); +#endif +#ifdef CFG_OTHER +extern void per_config_c_other(void); +#endif +int main(void) +{ +#ifdef CFG_DEBUG + per_config_c_debug(); +#endif +#ifdef CFG_OTHER + per_config_c_other(); +#endif + return 0; +} diff --git a/Tests/RunCMake/UnityBuild/per_config_c.cmake b/Tests/RunCMake/UnityBuild/per_config_c.cmake new file mode 100644 index 0000000..9f2ee48 --- /dev/null +++ b/Tests/RunCMake/UnityBuild/per_config_c.cmake @@ -0,0 +1,12 @@ +enable_language(C) + +add_executable(per_config_c per_config_c.c + "$<$:per_config_c_debug.c>" + "$<$>:per_config_c_other.c>" + ) + +set_target_properties(per_config_c PROPERTIES UNITY_BUILD ON) +target_compile_definitions(per_config_c PRIVATE + "$<$:CFG_DEBUG>" + "$<$>:CFG_OTHER>" + ) diff --git a/Tests/RunCMake/UnityBuild/per_config_c_debug.c b/Tests/RunCMake/UnityBuild/per_config_c_debug.c new file mode 100644 index 0000000..6d32ead --- /dev/null +++ b/Tests/RunCMake/UnityBuild/per_config_c_debug.c @@ -0,0 +1,9 @@ +#ifndef CFG_DEBUG +# error "per_config_c_debug built without CFG_DEBUG" +#endif +#ifdef CFG_OTHER +# error "per_config_c_debug built with CFG_OTHER" +#endif +void per_config_c_debug(void) +{ +} diff --git a/Tests/RunCMake/UnityBuild/per_config_c_other.c b/Tests/RunCMake/UnityBuild/per_config_c_other.c new file mode 100644 index 0000000..89c7a6b --- /dev/null +++ b/Tests/RunCMake/UnityBuild/per_config_c_other.c @@ -0,0 +1,9 @@ +#ifdef CFG_DEBUG +# error "per_config_c_other built with CFG_DEBUG" +#endif +#ifndef CFG_OTHER +# error "per_config_c_other built without CFG_OTHER" +#endif +void per_config_c_other(void) +{ +} -- cgit v0.12