|  | @@ -2821,6 +2821,53 @@ std::vector<std::string> AddUnityFilesModeAuto(
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    return unity_files;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +std::vector<std::string> AddUnityFilesModeGroup(
 | 
	
		
			
				|  |  | +  cmGeneratorTarget* target, std::string const& lang,
 | 
	
		
			
				|  |  | +  std::vector<cmSourceFile*> const& filtered_sources, cmProp beforeInclude,
 | 
	
		
			
				|  |  | +  cmProp afterInclude, std::string const& filename_base)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  std::vector<std::string> unity_files;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // sources organized by group name. Drop any source
 | 
	
		
			
				|  |  | +  // without a group
 | 
	
		
			
				|  |  | +  std::unordered_map<std::string, std::vector<cmSourceFile*>> explicit_mapping;
 | 
	
		
			
				|  |  | +  for (cmSourceFile* sf : filtered_sources) {
 | 
	
		
			
				|  |  | +    if (cmProp value = sf->GetProperty("UNITY_GROUP")) {
 | 
	
		
			
				|  |  | +      auto i = explicit_mapping.find(*value);
 | 
	
		
			
				|  |  | +      if (i == explicit_mapping.end()) {
 | 
	
		
			
				|  |  | +        std::vector<cmSourceFile*> sources{ sf };
 | 
	
		
			
				|  |  | +        explicit_mapping.emplace(*value, sources);
 | 
	
		
			
				|  |  | +      } else {
 | 
	
		
			
				|  |  | +        i->second.emplace_back(sf);
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  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);
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    cmSystemTools::MoveFileIfDifferent(filename_tmp, filename);
 | 
	
		
			
				|  |  | +    unity_files.emplace_back(std::move(filename));
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  return unity_files;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target)
 | 
	
	
		
			
				|  | @@ -2851,6 +2898,7 @@ void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target)
 | 
	
		
			
				|  |  |    cmProp beforeInclude =
 | 
	
		
			
				|  |  |      target->GetProperty("UNITY_BUILD_CODE_BEFORE_INCLUDE");
 | 
	
		
			
				|  |  |    cmProp afterInclude = target->GetProperty("UNITY_BUILD_CODE_AFTER_INCLUDE");
 | 
	
		
			
				|  |  | +  cmProp unityMode = target->GetProperty("UNITY_BUILD_MODE");
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    for (std::string lang : { "C", "CXX" }) {
 | 
	
		
			
				|  |  |      std::vector<cmSourceFile*> filtered_sources;
 | 
	
	
		
			
				|  | @@ -2865,9 +2913,22 @@ void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target)
 | 
	
		
			
				|  |  |                       !sf->GetProperty("INCLUDE_DIRECTORIES");
 | 
	
		
			
				|  |  |                   });
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    std::vector<std::string> unity_files =
 | 
	
		
			
				|  |  | -      AddUnityFilesModeAuto(target, lang, filtered_sources, beforeInclude,
 | 
	
		
			
				|  |  | -                            afterInclude, filename_base, unityBatchSize);
 | 
	
		
			
				|  |  | +    std::vector<std::string> unity_files;
 | 
	
		
			
				|  |  | +    if (!unityMode || *unityMode == "BATCH") {
 | 
	
		
			
				|  |  | +      unity_files =
 | 
	
		
			
				|  |  | +        AddUnityFilesModeAuto(target, lang, filtered_sources, beforeInclude,
 | 
	
		
			
				|  |  | +                              afterInclude, filename_base, unityBatchSize);
 | 
	
		
			
				|  |  | +    } else if (unityMode && *unityMode == "GROUP") {
 | 
	
		
			
				|  |  | +      unity_files =
 | 
	
		
			
				|  |  | +        AddUnityFilesModeGroup(target, lang, 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 +
 | 
	
		
			
				|  |  | +                    " assigned to target " + target->GetName() +
 | 
	
		
			
				|  |  | +                    ". Acceptable values are BATCH and GROUP.");
 | 
	
		
			
				|  |  | +      this->IssueMessage(MessageType::FATAL_ERROR, e);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      for (auto const& file : unity_files) {
 | 
	
		
			
				|  |  |        auto unity = this->GetMakefile()->GetOrCreateSource(file);
 |