From 23fd5703ad1bd2ad2098bc9ef6c8b0434fffa0bb Mon Sep 17 00:00:00 2001 From: Eduard Voronkin Date: Wed, 17 Sep 2025 11:40:56 -0700 Subject: [PATCH] FASTBuild: add support for Unity builds --- Source/cmFastbuildNormalTargetGenerator.cxx | 202 +++++++++++++++++- Source/cmFastbuildNormalTargetGenerator.h | 22 +- Source/cmGlobalFastbuildGenerator.cxx | 33 ++- Source/cmGlobalFastbuildGenerator.h | 16 ++ Source/cmLocalGenerator.cxx | 4 +- Tests/RunCMake/FASTBuild/RunCMakeTest.cmake | 6 + Tests/RunCMake/FASTBuild/Unity1-check.cmake | 10 + Tests/RunCMake/FASTBuild/Unity1.cmake | 4 + Tests/RunCMake/FASTBuild/Unity2-check.cmake | 20 ++ Tests/RunCMake/FASTBuild/Unity2.cmake | 3 + .../FASTBuild/UnityBatchSize-check.cmake | 31 +++ Tests/RunCMake/FASTBuild/UnityBatchSize.cmake | 3 + .../RunCMake/FASTBuild/UnityGroup-check.cmake | 23 ++ Tests/RunCMake/FASTBuild/UnityGroup.cmake | 12 ++ .../FASTBuild/UnityIsolate-check.cmake | 27 +++ Tests/RunCMake/FASTBuild/UnityIsolate.cmake | 18 ++ .../RunCMake/FASTBuild/some_source_file_1.cpp | 0 .../RunCMake/FASTBuild/some_source_file_2.cpp | 0 .../RunCMake/FASTBuild/some_source_file_3.cpp | 0 .../RunCMake/FASTBuild/some_source_file_4.cpp | 0 Tests/RunCMake/UnityBuild/RunCMakeTest.cmake | 6 + 21 files changed, 421 insertions(+), 19 deletions(-) create mode 100644 Tests/RunCMake/FASTBuild/Unity1-check.cmake create mode 100644 Tests/RunCMake/FASTBuild/Unity1.cmake create mode 100644 Tests/RunCMake/FASTBuild/Unity2-check.cmake create mode 100644 Tests/RunCMake/FASTBuild/Unity2.cmake create mode 100644 Tests/RunCMake/FASTBuild/UnityBatchSize-check.cmake create mode 100644 Tests/RunCMake/FASTBuild/UnityBatchSize.cmake create mode 100644 Tests/RunCMake/FASTBuild/UnityGroup-check.cmake create mode 100644 Tests/RunCMake/FASTBuild/UnityGroup.cmake create mode 100644 Tests/RunCMake/FASTBuild/UnityIsolate-check.cmake create mode 100644 Tests/RunCMake/FASTBuild/UnityIsolate.cmake create mode 100644 Tests/RunCMake/FASTBuild/some_source_file_1.cpp create mode 100644 Tests/RunCMake/FASTBuild/some_source_file_2.cpp create mode 100644 Tests/RunCMake/FASTBuild/some_source_file_3.cpp create mode 100644 Tests/RunCMake/FASTBuild/some_source_file_4.cpp diff --git a/Source/cmFastbuildNormalTargetGenerator.cxx b/Source/cmFastbuildNormalTargetGenerator.cxx index f413d3ccce..23c9374b38 100644 --- a/Source/cmFastbuildNormalTargetGenerator.cxx +++ b/Source/cmFastbuildNormalTargetGenerator.cxx @@ -57,6 +57,13 @@ std::string const COMPILE_FLAGS("COMPILE_FLAGS"); std::string const CMAKE_LANGUAGE("CMAKE"); std::string const INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES"); +std::string const CMAKE_UNITY_BUILD("CMAKE_UNITY_BUILD"); +std::string const CMAKE_UNITY_BUILD_BATCH_SIZE("CMAKE_UNITY_BUILD_BATCH_SIZE"); +std::string const UNITY_BUILD("UNITY_BUILD"); +std::string const UNITY_BUILD_BATCH_SIZE("UNITY_BUILD_BATCH_SIZE"); +std::string const SKIP_UNITY_BUILD_INCLUSION("SKIP_UNITY_BUILD_INCLUSION"); +std::string const UNITY_GROUP("UNITY_GROUP"); + } // anonymous namespace cmFastbuildNormalTargetGenerator::cmFastbuildNormalTargetGenerator( @@ -841,7 +848,8 @@ void cmFastbuildNormalTargetGenerator::Generate() fastbuildTarget.PostBuildExecNodes.Nodes.emplace_back(std::move(cc)); } - fastbuildTarget.ObjectListNodes = GenerateObjects(); + GenerateObjects(fastbuildTarget); + std::vector objectDepends; AddObjectDependencies(fastbuildTarget, objectDepends); @@ -1211,8 +1219,7 @@ std::vector cmFastbuildNormalTargetGenerator::GetArches() const return arches; } -std::vector -cmFastbuildNormalTargetGenerator::GenerateObjects() +void cmFastbuildNormalTargetGenerator::GenerateObjects(FastbuildTarget& target) { this->GetGlobalGenerator()->AllFoldersToClean.insert(ObjectOutDir); @@ -1225,22 +1232,50 @@ cmFastbuildNormalTargetGenerator::GenerateObjects() std::set createdPCH; + // Directory level. + bool useUnity = + GeneratorTarget->GetLocalGenerator()->GetMakefile()->IsDefinitionSet( + CMAKE_UNITY_BUILD); + // Check if explicitly disabled for this target. + auto const targetProp = GeneratorTarget->GetProperty(UNITY_BUILD); + if (targetProp.IsSet() && targetProp.IsOff()) { + useUnity = false; + } + + // List of sources isolated from the unity build if enabled. + std::set isolatedFromUnity; + + // Mapping from unity group (if any) to sources belonging to that group. + std::map> sourcesWithGroups; + for (cmSourceFile const* source : objectSources) { cmSourceFile const& srcFile = *source; + std::string const pathToFile = srcFile.GetFullPath(); + if (useUnity) { + // Check if the source should be added to "UnityInputIsolatedFiles". + if (srcFile.GetPropertyAsBool(SKIP_UNITY_BUILD_INCLUSION)) { + isolatedFromUnity.emplace(pathToFile); + } + std::string const perFileUnityGroup = + srcFile.GetSafeProperty(UNITY_GROUP); + if (!perFileUnityGroup.empty()) { + sourcesWithGroups[perFileUnityGroup].emplace_back(pathToFile); + } + } this->GetGlobalGenerator()->AddFileToClean(cmStrCat( ObjectOutDir, '/', this->GeneratorTarget->GetObjectName(source))); // Do not generate separate node for PCH source file. if (this->GeneratorTarget->GetPchSource(Config, srcFile.GetLanguage()) == - srcFile.GetFullPath()) { + pathToFile) { continue; } std::string const language = srcFile.GetLanguage(); - LogMessage(cmStrCat("Source file: ", - this->ConvertToFastbuildPath(srcFile.GetFullPath()))); + LogMessage( + cmStrCat("Source file: ", this->ConvertToFastbuildPath(pathToFile))); LogMessage("Language: " + language); std::string const staticCheckOptions = ComputeCodeCheckOptions(srcFile); @@ -1278,7 +1313,7 @@ cmFastbuildNormalTargetGenerator::GenerateObjects() nodesPermutations[objectListHash]; // Absolute path needed in "RunCMake.SymlinkTrees" test. - objectListNode.CompilerInputFiles.push_back(srcFile.GetFullPath()); + objectListNode.CompilerInputFiles.push_back(pathToFile); std::vector const outputs = GetSourceProperty(srcFile, "OBJECT_OUTPUTS"); @@ -1332,8 +1367,7 @@ cmFastbuildNormalTargetGenerator::GenerateObjects() cmStrCat(objectListNode.Name, "_", std::to_string(++groupNameCount)); LogMessage(cmStrCat("ObjectList name: ", objectListNode.Name)); } - - std::vector objects; + std::vector& objects = target.ObjectListNodes; objects.reserve(nodesPermutations.size()); for (auto& val : nodesPermutations) { auto& node = val.second; @@ -1344,7 +1378,155 @@ cmFastbuildNormalTargetGenerator::GenerateObjects() std::swap(*objects.begin(), objects.back()); } } - return objects; + if (useUnity) { + target.UnityNodes = + GenerateUnity(objects, isolatedFromUnity, sourcesWithGroups); + } +} + +FastbuildUnityNode cmFastbuildNormalTargetGenerator::GetOneUnity( + std::set const& isolatedFiles, std::vector& files, + int unitySize) const +{ + FastbuildUnityNode result; + for (auto iter = files.begin(); iter != files.end();) { + std::string pathToFile = std::move(*iter); + iter = files.erase(iter); + // This source must be isolated + if (isolatedFiles.find(pathToFile) != isolatedFiles.end()) { + result.UnityInputFiles.emplace_back(pathToFile); + result.UnityInputIsolatedFiles.emplace_back(std::move(pathToFile)); + } else { + result.UnityInputFiles.emplace_back(std::move(pathToFile)); + } + if (int(result.UnityInputFiles.size() - + result.UnityInputIsolatedFiles.size()) == unitySize) { + break; + } + } + return result; +} +int cmFastbuildNormalTargetGenerator::GetUnityBatchSize() const +{ + int unitySize = 8; + try { + auto const perTargetSize = + GeneratorTarget->GetSafeProperty(UNITY_BUILD_BATCH_SIZE); + if (!perTargetSize.empty()) { + unitySize = std::stoi(perTargetSize); + } + // Per-directory level. + else { + unitySize = std::stoi( + GeneratorTarget->GetLocalGenerator()->GetMakefile()->GetDefinition( + CMAKE_UNITY_BUILD_BATCH_SIZE)); + } + } catch (...) { + return unitySize; + } + return unitySize; +} + +std::vector +cmFastbuildNormalTargetGenerator::GenerateUnity( + std::vector& objects, + std::set const& isolatedSources, + std::map> const& sourcesWithGroups) +{ + int const unitySize = GetUnityBatchSize(); + // Unity of size less than 2 doesn't make sense. + if (unitySize < 2) { + return {}; + } + + int unityNumber = 0; + int unityGroupNumber = 0; + std::vector result; + + for (FastbuildObjectListNode& obj : objects) { + // Don't use unity for only 1 file. + if (obj.CompilerInputFiles.size() < 2) { + continue; + } + std::string const ext = + cmSystemTools::GetFilenameExtension(obj.CompilerInputFiles[0]); + // Process groups. + auto groupedNode = GenerateGroupedUnityNode( + obj.CompilerInputFiles, sourcesWithGroups, unityGroupNumber); + // We have at least 2 sources in the group. + if (groupedNode.UnityInputFiles.size() > 1) { + groupedNode.UnityOutputPath = obj.CompilerOutputPath; + obj.CompilerInputUnity.emplace_back(groupedNode.Name); + groupedNode.UnityOutputPattern = cmStrCat(groupedNode.Name, ext); + result.emplace_back(std::move(groupedNode)); + } + // General unity batching of the remaining (non-grouped) sources. + while (!obj.CompilerInputFiles.empty()) { + FastbuildUnityNode node = + GetOneUnity(isolatedSources, obj.CompilerInputFiles, unitySize); + node.Name = + cmStrCat(this->GetName(), "_Unity_", std::to_string(++unityNumber)); + node.UnityOutputPath = obj.CompilerOutputPath; + node.UnityOutputPattern = cmStrCat(node.Name, ext); + + // Unity group of size 1 doesn't make sense - just isolate the source. + if (groupedNode.UnityInputFiles.size() == 1) { + node.UnityInputIsolatedFiles.emplace_back( + groupedNode.UnityInputFiles[0]); + node.UnityInputFiles.emplace_back( + std::move(groupedNode.UnityInputFiles[0])); + // Clear so we don't enter here on the next iteration. + groupedNode.UnityInputFiles.clear(); + } + + // We've got only 1 file left. No need to create a Unity node for it, + // just return it back to the ObjectList and exit. + if (node.UnityInputFiles.size() == 1) { + obj.CompilerInputFiles.emplace_back( + std::move(node.UnityInputFiles[0])); + break; + } + + obj.CompilerInputUnity.emplace_back(node.Name); + result.emplace_back(std::move(node)); + } + } + return result; +} + +FastbuildUnityNode cmFastbuildNormalTargetGenerator::GenerateGroupedUnityNode( + std::vector& inputFiles, + std::map> const& sourcesWithGroups, + int& groupId) +{ + std::vector result; + for (auto const& item : sourcesWithGroups) { + auto const& group = item.first; + auto const& sources = item.second; + FastbuildUnityNode node; + // Check if any of the sources belong to this group. + for (auto const& source : sources) { + auto const iter = + std::find(inputFiles.begin(), inputFiles.end(), source); + if (iter == inputFiles.end()) { + continue; + } + node.Name = cmStrCat(this->GetName(), "_Unity_Group_", group, '_', + std::to_string(++groupId)); + node.UnityInputFiles.emplace_back(source); + + // Remove from the general batching. + inputFiles.erase( + std::remove(inputFiles.begin(), inputFiles.end(), source), + inputFiles.end()); + } + if (!node.UnityInputFiles.empty()) { + // The unity group belongs to the ObjectLists that we're processing. + // We've grouped all the sources we could from the current ObjectList. + return node; + } + } + return {}; } std::string cmFastbuildNormalTargetGenerator::ResolveIfAlias( diff --git a/Source/cmFastbuildNormalTargetGenerator.h b/Source/cmFastbuildNormalTargetGenerator.h index d53299b068..cd4c665627 100644 --- a/Source/cmFastbuildNormalTargetGenerator.h +++ b/Source/cmFastbuildNormalTargetGenerator.h @@ -13,13 +13,9 @@ #include "cmComputeLinkInformation.h" #include "cmFastbuildTargetGenerator.h" #include "cmGeneratorTarget.h" +#include "cmGlobalFastbuildGenerator.h" #include "cmRulePlaceholderExpander.h" class cmSourceFile; -struct FastbuildExecNode; -struct FastbuildLinkerNode; -struct FastbuildObjectListNode; -struct FastbuildTarget; -struct FastbuildTargetDep; class cmFastbuildNormalTargetGenerator : public cmFastbuildTargetGenerator { @@ -74,7 +70,21 @@ private: std::vector GetArches() const; - std::vector GenerateObjects(); + void GenerateObjects(FastbuildTarget& target); + FastbuildUnityNode GetOneUnity(std::set const& isolatedFiles, + std::vector& files, + int unitySize) const; + + int GetUnityBatchSize() const; + std::vector GenerateUnity( + std::vector& objects, + std::set const& isolatedSources, + std::map> const& sourcesWithGroups); + FastbuildUnityNode GenerateGroupedUnityNode( + std::vector& inputFiles, + std::map> const& sourcesWithGroups, + int& groupId); + // Computes .CompilerOptions for the ObjectList node. void ComputeCompilerAndOptions(std::string const& compilerOptions, std::string const& staticCheckOptions, diff --git a/Source/cmGlobalFastbuildGenerator.cxx b/Source/cmGlobalFastbuildGenerator.cxx index 2fb71a7926..8dc735be1e 100644 --- a/Source/cmGlobalFastbuildGenerator.cxx +++ b/Source/cmGlobalFastbuildGenerator.cxx @@ -616,7 +616,8 @@ void cmGlobalFastbuildGenerator::WriteVariable(std::string const& key, int indent) { Indent(indent); - *this->BuildFileStream << "." << key << " " + op + " " << value << "\n"; + *this->BuildFileStream << "." << key << " " + op + (value.empty() ? "" : " ") + << value << "\n"; } void cmGlobalFastbuildGenerator::WriteCommand(std::string const& command, @@ -1164,6 +1165,24 @@ void cmGlobalFastbuildGenerator::WriteExec(FastbuildExecNode const& Exec, } } +void cmGlobalFastbuildGenerator::WriteUnity(FastbuildUnityNode const& Unity) +{ + WriteCommand("Unity", Quote(Unity.Name), 1); + Indent(1); + *BuildFileStream << "{\n"; + { + WriteVariable("UnityOutputPath", Quote(Unity.UnityOutputPath), 2); + WriteVariable("UnityOutputPattern", Quote(Unity.UnityOutputPattern), 2); + WriteArray("UnityInputFiles", Wrap(Unity.UnityInputFiles), 2); + if (!Unity.UnityInputIsolatedFiles.empty()) { + WriteArray("UnityInputIsolatedFiles", + Wrap(Unity.UnityInputIsolatedFiles), 2); + } + } + Indent(1); + *BuildFileStream << "}\n"; +} + void cmGlobalFastbuildGenerator::WriteObjectList( FastbuildObjectListNode const& ObjectList, bool allowDistribution) { @@ -1194,7 +1213,12 @@ void cmGlobalFastbuildGenerator::WriteObjectList( WriteVariable("CompilerOutputExtension", Quote(ObjectList.CompilerOutputExtension), 2); WriteVariable("CompilerOutputKeepBaseExtension", "true", 2); - WriteArray("CompilerInputFiles", Wrap(ObjectList.CompilerInputFiles), 2); + if (!ObjectList.CompilerInputUnity.empty()) { + WriteArray("CompilerInputUnity", Wrap(ObjectList.CompilerInputUnity), 2); + } + if (!ObjectList.CompilerInputFiles.empty()) { + WriteArray("CompilerInputFiles", Wrap(ObjectList.CompilerInputFiles), 2); + } if (!ObjectList.AllowCaching) { WriteVariable("AllowCaching", "false", 2); } @@ -1350,6 +1374,11 @@ void cmGlobalFastbuildGenerator::WriteTarget(FastbuildTarget const& target) this->WriteCopy(node); } + // Unity. + for (FastbuildUnityNode const& unity : target.UnityNodes) { + this->WriteUnity(unity); + } + // Objects. for (FastbuildObjectListNode const& objectList : target.ObjectListNodes) { this->WriteObjectList(objectList, target.AllowDistribution); diff --git a/Source/cmGlobalFastbuildGenerator.h b/Source/cmGlobalFastbuildGenerator.h index 6c7d66c39b..280a283331 100644 --- a/Source/cmGlobalFastbuildGenerator.h +++ b/Source/cmGlobalFastbuildGenerator.h @@ -126,6 +126,7 @@ enum class FastbuildTargetType EXEC, // Exec node LINK, // Library, DLL or Executable OBJECTLIST, + UNITY, }; struct FastbuildTargetBase @@ -209,6 +210,7 @@ struct FastbuildObjectListNode : public FastbuildTargetBase std::string CompilerOptions; std::string CompilerOutputPath; std::string CompilerOutputExtension; + std::vector CompilerInputUnity; std::string PCHInputFile; std::string PCHOutputFile; std::string PCHOptions; @@ -228,6 +230,18 @@ struct FastbuildObjectListNode : public FastbuildTargetBase } }; +struct FastbuildUnityNode : public FastbuildTargetBase +{ + std::string UnityOutputPath; + std::vector UnityInputFiles; + std::string UnityOutputPattern; + std::vector UnityInputIsolatedFiles; + FastbuildUnityNode() + : FastbuildTargetBase(FastbuildTargetType::UNITY) + { + } +}; + struct IDEProjectConfig { std::string Config; @@ -305,6 +319,7 @@ struct FastbuildTarget : public FastbuildTargetBase { std::map Variables; std::vector ObjectListNodes; + std::vector UnityNodes; // Potentially multiple libs for different archs (apple only); std::vector LinkerNode; std::string RealOutput; @@ -506,6 +521,7 @@ public: void WriteTarget(FastbuildTarget const& target); void WriteExec(FastbuildExecNode const& Exec, int indent = 1); + void WriteUnity(FastbuildUnityNode const& Unity); void WriteObjectList(FastbuildObjectListNode const& ObjectList, bool allowDistribution); void WriteLinker(FastbuildLinkerNode const&, bool); diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 50a55d849b..0763073b09 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -3259,7 +3259,9 @@ cmLocalGenerator::AddUnityFilesModeGroup( void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target) { - if (!target->GetPropertyAsBool("UNITY_BUILD")) { + // cmFastbuildNormalTargetGenerator handles unity build. + if (this->GetGlobalGenerator()->IsFastbuild() || + !target->GetPropertyAsBool("UNITY_BUILD")) { return; } diff --git a/Tests/RunCMake/FASTBuild/RunCMakeTest.cmake b/Tests/RunCMake/FASTBuild/RunCMakeTest.cmake index 9784930246..a258dbfe4e 100644 --- a/Tests/RunCMake/FASTBuild/RunCMakeTest.cmake +++ b/Tests/RunCMake/FASTBuild/RunCMakeTest.cmake @@ -1,5 +1,11 @@ include(RunCMake) +# Unity of size 1 doesn't make sense and shouldn't be created. +run_cmake(Unity1) +run_cmake(Unity2) +run_cmake(UnityBatchSize) +run_cmake(UnityGroup) +run_cmake(UnityIsolate) run_cmake(DisableCaching) run_cmake(DisableDistribution) run_cmake(SetCompilerProps) diff --git a/Tests/RunCMake/FASTBuild/Unity1-check.cmake b/Tests/RunCMake/FASTBuild/Unity1-check.cmake new file mode 100644 index 0000000000..de9bc809bc --- /dev/null +++ b/Tests/RunCMake/FASTBuild/Unity1-check.cmake @@ -0,0 +1,10 @@ +set(REGEX_TO_MATCH " +.*ObjectList.* +.* + \.CompilerInputFiles = + { + '.*main.cpp', + '.*some_source_file_1.cpp' + } +") +include(${RunCMake_SOURCE_DIR}/check.cmake) diff --git a/Tests/RunCMake/FASTBuild/Unity1.cmake b/Tests/RunCMake/FASTBuild/Unity1.cmake new file mode 100644 index 0000000000..8e6cd3d900 --- /dev/null +++ b/Tests/RunCMake/FASTBuild/Unity1.cmake @@ -0,0 +1,4 @@ +set(CMAKE_UNITY_BUILD ON) +set(CMAKE_UNITY_BUILD_BATCH_SIZE 1) + +add_executable(main main.cpp some_source_file_1.cpp) diff --git a/Tests/RunCMake/FASTBuild/Unity2-check.cmake b/Tests/RunCMake/FASTBuild/Unity2-check.cmake new file mode 100644 index 0000000000..f9ffffa778 --- /dev/null +++ b/Tests/RunCMake/FASTBuild/Unity2-check.cmake @@ -0,0 +1,20 @@ +set(REGEX_TO_MATCH " + Unity\\('main_Unity_1'\\) + { + \.UnityOutputPath = 'CMakeFiles/main.dir' + \.UnityOutputPattern = 'main_Unity_1.cpp' + \.UnityInputFiles = + { + .*main.cpp', + .*some_source_file_1.cpp' + } + } +.*ObjectList.* +.* + .CompilerInputUnity = + { + 'main_Unity_1' + } +") + +include(${RunCMake_SOURCE_DIR}/check.cmake) diff --git a/Tests/RunCMake/FASTBuild/Unity2.cmake b/Tests/RunCMake/FASTBuild/Unity2.cmake new file mode 100644 index 0000000000..da43bea461 --- /dev/null +++ b/Tests/RunCMake/FASTBuild/Unity2.cmake @@ -0,0 +1,3 @@ +set(CMAKE_UNITY_BUILD ON) + +add_executable(main main.cpp some_source_file_1.cpp) diff --git a/Tests/RunCMake/FASTBuild/UnityBatchSize-check.cmake b/Tests/RunCMake/FASTBuild/UnityBatchSize-check.cmake new file mode 100644 index 0000000000..5ab203bd73 --- /dev/null +++ b/Tests/RunCMake/FASTBuild/UnityBatchSize-check.cmake @@ -0,0 +1,31 @@ +set(REGEX_TO_MATCH " + Unity\\('main_Unity_1'\\) + { +.* + .UnityOutputPattern = 'main_Unity_1.cpp' + .UnityInputFiles = + { + '.*main.cpp', + '.*some_source_file_1.cpp' + } + } + Unity\\('main_Unity_2'\\) + { +.* + .UnityOutputPattern = 'main_Unity_2.cpp' + .UnityInputFiles = + { + '.*some_source_file_2.cpp', + '.*some_source_file_3.cpp' + } + } +.*ObjectLis.* +.* + .CompilerInputUnity = + { + 'main_Unity_1', + 'main_Unity_2' + } +") + +include(${RunCMake_SOURCE_DIR}/check.cmake) diff --git a/Tests/RunCMake/FASTBuild/UnityBatchSize.cmake b/Tests/RunCMake/FASTBuild/UnityBatchSize.cmake new file mode 100644 index 0000000000..a8ffa5b5f2 --- /dev/null +++ b/Tests/RunCMake/FASTBuild/UnityBatchSize.cmake @@ -0,0 +1,3 @@ +set(CMAKE_UNITY_BUILD ON) +set(CMAKE_UNITY_BUILD_BATCH_SIZE 2) +add_executable(main main.cpp some_source_file_1.cpp some_source_file_2.cpp some_source_file_3.cpp) diff --git a/Tests/RunCMake/FASTBuild/UnityGroup-check.cmake b/Tests/RunCMake/FASTBuild/UnityGroup-check.cmake new file mode 100644 index 0000000000..86c4f92392 --- /dev/null +++ b/Tests/RunCMake/FASTBuild/UnityGroup-check.cmake @@ -0,0 +1,23 @@ +set(REGEX_TO_MATCH " + Unity\\('main_Unity_Group_TestGroup_2'\\) +.* + .UnityOutputPattern = 'main_Unity_Group_TestGroup_2.cpp' + .UnityInputFiles = + { + '.*some_source_file_1.cpp', + '.*some_source_file_2.cpp' + } +.* + ObjectList.* +.* + \.CompilerInputUnity = + { + 'main_Unity_Group_TestGroup_2' + } + \.CompilerInputFiles = + { + '.*main.cpp' + } +") + +include(${RunCMake_SOURCE_DIR}/check.cmake) diff --git a/Tests/RunCMake/FASTBuild/UnityGroup.cmake b/Tests/RunCMake/FASTBuild/UnityGroup.cmake new file mode 100644 index 0000000000..5e5c43c9f9 --- /dev/null +++ b/Tests/RunCMake/FASTBuild/UnityGroup.cmake @@ -0,0 +1,12 @@ +set(CMAKE_UNITY_BUILD ON) +add_executable(main main.cpp some_source_file_1.cpp some_source_file_2.cpp) + +set_source_files_properties( + some_source_file_1.cpp + some_source_file_2.cpp + + TARGET_DIRECTORY + main + PROPERTIES + UNITY_GROUP "TestGroup" +) diff --git a/Tests/RunCMake/FASTBuild/UnityIsolate-check.cmake b/Tests/RunCMake/FASTBuild/UnityIsolate-check.cmake new file mode 100644 index 0000000000..f42bb1b6cb --- /dev/null +++ b/Tests/RunCMake/FASTBuild/UnityIsolate-check.cmake @@ -0,0 +1,27 @@ +set(REGEX_TO_MATCH " + Unity\\('main_Unity_1'\\) + { +.* + .UnityInputFiles = + { + '.*main.cpp', + '.*some_source_file_1.cpp', + '.*some_source_file_2.cpp', + '.*some_source_file_3.cpp', + '.*some_source_file_4.cpp' + } + .UnityInputIsolatedFiles = + { + '.*some_source_file_1.cpp', + '.*some_source_file_4.cpp' + } + } +.*ObjectList.* +.* + .CompilerInputUnity = + { + 'main_Unity_1' + } +") + +include(${RunCMake_SOURCE_DIR}/check.cmake) diff --git a/Tests/RunCMake/FASTBuild/UnityIsolate.cmake b/Tests/RunCMake/FASTBuild/UnityIsolate.cmake new file mode 100644 index 0000000000..0eb785eb75 --- /dev/null +++ b/Tests/RunCMake/FASTBuild/UnityIsolate.cmake @@ -0,0 +1,18 @@ +set(CMAKE_UNITY_BUILD ON) +add_executable(main + main.cpp + some_source_file_1.cpp + some_source_file_2.cpp + some_source_file_3.cpp + some_source_file_4.cpp +) + +set_source_files_properties( + some_source_file_1.cpp + some_source_file_4.cpp + + TARGET_DIRECTORY + main + PROPERTIES + SKIP_UNITY_BUILD_INCLUSION ON +) diff --git a/Tests/RunCMake/FASTBuild/some_source_file_1.cpp b/Tests/RunCMake/FASTBuild/some_source_file_1.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Tests/RunCMake/FASTBuild/some_source_file_2.cpp b/Tests/RunCMake/FASTBuild/some_source_file_2.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Tests/RunCMake/FASTBuild/some_source_file_3.cpp b/Tests/RunCMake/FASTBuild/some_source_file_3.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Tests/RunCMake/FASTBuild/some_source_file_4.cpp b/Tests/RunCMake/FASTBuild/some_source_file_4.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Tests/RunCMake/UnityBuild/RunCMakeTest.cmake b/Tests/RunCMake/UnityBuild/RunCMakeTest.cmake index f023299437..245a0fee6d 100644 --- a/Tests/RunCMake/UnityBuild/RunCMakeTest.cmake +++ b/Tests/RunCMake/UnityBuild/RunCMakeTest.cmake @@ -1,5 +1,11 @@ include(RunCMake) +# FASTBuild generator does Unity build natively +# and has its own tests for it in "RunCMake/FASTBuild" folder. +if(RunCMake_GENERATOR STREQUAL "FASTBuild") + return() +endif() + function(run_build name) set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${name}-build) run_cmake(${name})