From 7114c141e27532df709fcae1266bb4ce9b6e850c Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Fri, 26 Jul 2019 16:08:32 +0200 Subject: Unity build: Add support for Ninja and Makefile generators --- Help/manual/cmake-properties.7.rst | 5 ++ Help/manual/cmake-variables.7.rst | 2 + Help/prop_sf/SKIP_UNITY_BUILD_INCLUSION.rst | 7 ++ Help/prop_tgt/UNITY_BUILD.rst | 55 +++++++++++++++ Help/prop_tgt/UNITY_BUILD_BATCH_SIZE.rst | 13 ++++ Help/prop_tgt/UNITY_BUILD_CODE_AFTER_INCLUDE.rst | 8 +++ Help/prop_tgt/UNITY_BUILD_CODE_BEFORE_INCLUDE.rst | 8 +++ Help/release/dev/unity-build.rst | 6 ++ Help/variable/CMAKE_UNITY_BUILD.rst | 6 ++ Help/variable/CMAKE_UNITY_BUILD_BATCH_SIZE.rst | 6 ++ Source/cmLocalGenerator.cxx | 85 +++++++++++++++++++++++ Source/cmLocalGenerator.h | 1 + Source/cmMakefileExecutableTargetGenerator.cxx | 1 + Source/cmMakefileLibraryTargetGenerator.cxx | 1 + Source/cmMakefileUtilityTargetGenerator.cxx | 1 + Source/cmNinjaNormalTargetGenerator.cxx | 1 + Source/cmTarget.cxx | 2 + 17 files changed, 208 insertions(+) create mode 100644 Help/prop_sf/SKIP_UNITY_BUILD_INCLUSION.rst create mode 100644 Help/prop_tgt/UNITY_BUILD.rst create mode 100644 Help/prop_tgt/UNITY_BUILD_BATCH_SIZE.rst create mode 100644 Help/prop_tgt/UNITY_BUILD_CODE_AFTER_INCLUDE.rst create mode 100644 Help/prop_tgt/UNITY_BUILD_CODE_BEFORE_INCLUDE.rst create mode 100644 Help/release/dev/unity-build.rst create mode 100644 Help/variable/CMAKE_UNITY_BUILD.rst create mode 100644 Help/variable/CMAKE_UNITY_BUILD_BATCH_SIZE.rst diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index 25d6b24..19afb7d 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -323,6 +323,10 @@ Properties on Targets /prop_tgt/Swift_MODULE_DIRECTORY /prop_tgt/Swift_MODULE_NAME /prop_tgt/TYPE + /prop_tgt/UNITY_BUILD + /prop_tgt/UNITY_BUILD_BATCH_SIZE + /prop_tgt/UNITY_BUILD_CODE_AFTER_INCLUDE + /prop_tgt/UNITY_BUILD_CODE_BEFORE_INCLUDE /prop_tgt/VERSION /prop_tgt/VISIBILITY_INLINES_HIDDEN /prop_tgt/VS_CONFIGURATION_TYPE @@ -450,6 +454,7 @@ Properties on Source Files /prop_sf/SKIP_AUTORCC /prop_sf/SKIP_AUTOUIC /prop_sf/SKIP_PRECOMPILE_HEADERS + /prop_sf/SKIP_UNITY_BUILD_INCLUSION /prop_sf/Swift_DEPENDENCIES_FILE /prop_sf/Swift_DIAGNOSTICS_FILE /prop_sf/SYMBOLIC diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index 0ae1ebe..739e4b5 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -431,6 +431,8 @@ Variables that Control the Build /variable/CMAKE_TRY_COMPILE_CONFIGURATION /variable/CMAKE_TRY_COMPILE_PLATFORM_VARIABLES /variable/CMAKE_TRY_COMPILE_TARGET_TYPE + /variable/CMAKE_UNITY_BUILD + /variable/CMAKE_UNITY_BUILD_BATCH_SIZE /variable/CMAKE_USE_RELATIVE_PATHS /variable/CMAKE_VISIBILITY_INLINES_HIDDEN /variable/CMAKE_VS_GLOBALS diff --git a/Help/prop_sf/SKIP_UNITY_BUILD_INCLUSION.rst b/Help/prop_sf/SKIP_UNITY_BUILD_INCLUSION.rst new file mode 100644 index 0000000..53f3970 --- /dev/null +++ b/Help/prop_sf/SKIP_UNITY_BUILD_INCLUSION.rst @@ -0,0 +1,7 @@ +SKIP_UNITY_BUILD_INCLUSION +-------------------------- + +Is this source file skipped by :prop_tgt:`UNITY_BUILD` feature. + +This property helps with "ODR (One definition rule)" problems +that one would run into when using an :prop_tgt:`UNITY_BUILD`. diff --git a/Help/prop_tgt/UNITY_BUILD.rst b/Help/prop_tgt/UNITY_BUILD.rst new file mode 100644 index 0000000..d326ee2 --- /dev/null +++ b/Help/prop_tgt/UNITY_BUILD.rst @@ -0,0 +1,55 @@ +UNITY_BUILD +----------- + +Should the target source files be processed into batches for +faster compilation. This feature is known as "Unity build", +or "Jumbo build". + +The `C` and `CXX` source files are grouped separately. + +This property is initialized by the value of the +:variable:`CMAKE_UNITY_BUILD` variable if it is set when +a target is created. + +.. note :: + + It's not recommended to directly set :prop_tgt:`UNITY_BUILD` + to `ON`, but to instead set :variable:`CMAKE_UNITY_BUILD` from + the command line. However, it IS recommended to set + :prop_tgt:`UNITY_BUILD` to `OFF` if you need to ensure that a + target doesn't get a unity build. + +The batch size can be specified by setting +:prop_tgt:`UNITY_BUILD_BATCH_SIZE`. + +The batching of source files is done by adding new sources files +wich will `#include` the source files, and exclude them from +building by setting :prop_sf:`HEADER_FILE_ONLY` to `ON`. + + +ODR (One definition rule) errors +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Since multiple source files are included into one source file, +it can lead to ODR errors. This section contains properites +which help fixing these errors. + +The source files marked by :prop_sf:`GENERATED` will be skipped +from unity build. This applies also for the source files marked +with :prop_sf:`SKIP_UNITY_BUILD_INCLUSION`. + +The source files that have :prop_sf:`COMPILE_OPTIONS`, +:prop_sf:`COMPILE_DEFINITIONS`, :prop_sf:`COMPILE_FLAGS`, or +:prop_sf:`INCLUDE_DIRECTORIES` will also be skipped. + +With the :prop_tgt:`UNITY_BUILD_CODE_BEFORE_INCLUDE` and +:prop_tgt:`UNITY_BUILD_CODE_AFTER_INCLUDE` one can specify code +to be injected in the unity source file before and after every +`#include` statement. + +.. note :: + + The order of source files defined in the `CMakeLists.txt` will + be preserved into the generated unity source files. This can + be used to manually enforce a specific grouping based on the + :prop_tgt:`UNITY_BUILD_BATCH_SIZE`. diff --git a/Help/prop_tgt/UNITY_BUILD_BATCH_SIZE.rst b/Help/prop_tgt/UNITY_BUILD_BATCH_SIZE.rst new file mode 100644 index 0000000..2426689 --- /dev/null +++ b/Help/prop_tgt/UNITY_BUILD_BATCH_SIZE.rst @@ -0,0 +1,13 @@ +UNITY_BUILD_BATCH_SIZE +---------------------- + +Specifies how many source code files will be included into a +:prop_tgt:`UNITY_BUILD` source file. + +If the property is not set, CMake will use the value provided +by :variable:`CMAKE_UNITY_BUILD_BATCH_SIZE`. + +By setting it to value `0` the generated unity source file will +contain all the source files that would be otherwise be split +into multiple batches. It is not recommended to do so, since it +would affect performance. diff --git a/Help/prop_tgt/UNITY_BUILD_CODE_AFTER_INCLUDE.rst b/Help/prop_tgt/UNITY_BUILD_CODE_AFTER_INCLUDE.rst new file mode 100644 index 0000000..7795289 --- /dev/null +++ b/Help/prop_tgt/UNITY_BUILD_CODE_AFTER_INCLUDE.rst @@ -0,0 +1,8 @@ +UNITY_BUILD_CODE_AFTER_INCLUDE +------------------------------ + +Code snippet which is included verbatim by the :prop_tgt:`UNITY_BUILD` +feature just after the `#include` statement of the targeted source +files. + +This could be something like `#undef NOMINMAX`. diff --git a/Help/prop_tgt/UNITY_BUILD_CODE_BEFORE_INCLUDE.rst b/Help/prop_tgt/UNITY_BUILD_CODE_BEFORE_INCLUDE.rst new file mode 100644 index 0000000..f335463 --- /dev/null +++ b/Help/prop_tgt/UNITY_BUILD_CODE_BEFORE_INCLUDE.rst @@ -0,0 +1,8 @@ +UNITY_BUILD_CODE_BEFORE_INCLUDE +------------------------------- + +Code snippet which is included verbatim by the :prop_tgt:`UNITY_BUILD` +feature just before the `#include` statement of the targeted source +files. + +This could be something like `#define NOMINMAX`. diff --git a/Help/release/dev/unity-build.rst b/Help/release/dev/unity-build.rst new file mode 100644 index 0000000..293a375 --- /dev/null +++ b/Help/release/dev/unity-build.rst @@ -0,0 +1,6 @@ +Unity build +----------- + +* The :prop_tgt:`UNITY_BUILD` target property was added to tell + generators to batch include source files for faster compilation + times. diff --git a/Help/variable/CMAKE_UNITY_BUILD.rst b/Help/variable/CMAKE_UNITY_BUILD.rst new file mode 100644 index 0000000..3096954 --- /dev/null +++ b/Help/variable/CMAKE_UNITY_BUILD.rst @@ -0,0 +1,6 @@ +CMAKE_UNITY_BUILD +----------------- + +Default value for :prop_tgt:`UNITY_BUILD` of targets. + +By default ``CMAKE_UNITY_BUILD`` is ``OFF``. diff --git a/Help/variable/CMAKE_UNITY_BUILD_BATCH_SIZE.rst b/Help/variable/CMAKE_UNITY_BUILD_BATCH_SIZE.rst new file mode 100644 index 0000000..3ab2344 --- /dev/null +++ b/Help/variable/CMAKE_UNITY_BUILD_BATCH_SIZE.rst @@ -0,0 +1,6 @@ +CMAKE_UNITY_BUILD_BATCH_SIZE +---------------------------- + +Default value for :prop_tgt:`UNITY_BUILD_BATCH_SIZE` of targets. + +By default ``CMAKE_UNITY_BUILD_BATCH_SIZE`` is set to ``8``. diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 7177694..6fade3e 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -2202,6 +2203,90 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target, } } +void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target, + const std::string& config) +{ + if (!target->GetPropertyAsBool("UNITY_BUILD")) { + return; + } + + const std::string buildType = cmSystemTools::UpperCase(config); + + std::string filename_base = + cmStrCat(this->GetCurrentBinaryDirectory(), "/CMakeFiles/", + target->GetName(), ".dir/Unity/"); + + std::vector sources; + target->GetSourceFiles(sources, buildType); + + auto batchSizeString = target->GetProperty("UNITY_BUILD_BATCH_SIZE"); + const size_t unityBatchSize = + static_cast(std::atoi(batchSizeString)); + + auto beforeInclude = target->GetProperty("UNITY_BUILD_CODE_BEFORE_INCLUDE"); + auto afterInclude = target->GetProperty("UNITY_BUILD_CODE_AFTER_INCLUDE"); + + for (std::string lang : { "C", "CXX" }) { + std::vector filtered_sources; + std::copy_if(sources.begin(), sources.end(), + std::back_inserter(filtered_sources), [&](cmSourceFile* sf) { + return sf->GetLanguage() == lang && + !sf->GetPropertyAsBool("SKIP_UNITY_BUILD_INCLUSION") && + !sf->GetPropertyAsBool("GENERATED") && + !sf->GetProperty("COMPILE_OPTIONS") && + !sf->GetProperty("COMPILE_DEFINITIONS") && + !sf->GetProperty("COMPILE_FLAGS") && + !sf->GetProperty("INCLUDE_DIRECTORIES"); + }); + + size_t batchSize = unityBatchSize; + if (unityBatchSize == 0) { + batchSize = filtered_sources.size(); + } + + for (size_t itemsLeft = filtered_sources.size(), chunk = batchSize, + batch = 0; + itemsLeft > 0; itemsLeft -= chunk, ++batch) { + + chunk = std::min(itemsLeft, batchSize); + + std::string filename = cmStrCat(filename_base, "unity_", batch, + (lang == "C") ? ".c" : ".cxx"); + + const std::string filename_tmp = cmStrCat(filename, ".tmp"); + { + size_t begin = batch * batchSize; + size_t end = begin + chunk; + + cmGeneratedFileStream file( + filename_tmp, false, + this->GetGlobalGenerator()->GetMakefileEncoding()); + file << "/* generated by CMake */\n\n"; + + for (; begin != end; ++begin) { + cmSourceFile* sf = filtered_sources[begin]; + + sf->SetProperty("HEADER_FILE_ONLY", "ON"); + + if (beforeInclude) { + file << beforeInclude << "\n"; + } + + file << "#include \"" << sf->GetFullPath() << "\"\n"; + + if (afterInclude) { + file << afterInclude << "\n"; + } + } + } + cmSystemTools::CopyFileIfDifferent(filename_tmp, filename); + cmSystemTools::RemoveFile(filename_tmp); + + target->AddSource(filename, true); + } + } +} + void cmLocalGenerator::AppendIPOLinkerFlags(std::string& flags, cmGeneratorTarget* target, const std::string& config, diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index f63fe0f..515ffae 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -126,6 +126,7 @@ public: const std::string& rawFlag) const; void AddPchDependencies(cmGeneratorTarget* target, const std::string& config); + void AddUnityBuild(cmGeneratorTarget* target, const std::string& config); void AppendIPOLinkerFlags(std::string& flags, cmGeneratorTarget* target, const std::string& config, const std::string& lang); diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index bebd5c4..002addf 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -41,6 +41,7 @@ cmMakefileExecutableTargetGenerator::cmMakefileExecutableTargetGenerator( cm::make_unique(target, this->ConfigName); this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders); + this->LocalGenerator->AddUnityBuild(target, this->ConfigName); this->LocalGenerator->AddPchDependencies(target, this->ConfigName); } diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index 4244402..d603dac 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -43,6 +43,7 @@ cmMakefileLibraryTargetGenerator::cmMakefileLibraryTargetGenerator( cm::make_unique(target, this->ConfigName); this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders); + this->LocalGenerator->AddUnityBuild(target, this->ConfigName); this->LocalGenerator->AddPchDependencies(target, this->ConfigName); } diff --git a/Source/cmMakefileUtilityTargetGenerator.cxx b/Source/cmMakefileUtilityTargetGenerator.cxx index 556191f..d4045b3 100644 --- a/Source/cmMakefileUtilityTargetGenerator.cxx +++ b/Source/cmMakefileUtilityTargetGenerator.cxx @@ -26,6 +26,7 @@ cmMakefileUtilityTargetGenerator::cmMakefileUtilityTargetGenerator( cm::make_unique(target, this->ConfigName); this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders); + this->LocalGenerator->AddUnityBuild(target, this->ConfigName); this->LocalGenerator->AddPchDependencies(target, this->ConfigName); } diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index 0e3aa3a..a4e1d61 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -60,6 +60,7 @@ cmNinjaNormalTargetGenerator::cmNinjaNormalTargetGenerator( cm::make_unique(target, this->GetConfigName()); this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders); + GetLocalGenerator()->AddUnityBuild(target, this->GetConfigName()); GetLocalGenerator()->AddPchDependencies(target, this->GetConfigName()); } diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 2a09b43..10ea7dd 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -352,6 +352,8 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, initProp("Swift_MODULE_DIRECTORY"); initProp("VS_JUST_MY_CODE_DEBUGGING"); initProp("DISABLE_PRECOMPILE_HEADERS"); + initProp("UNITY_BUILD"); + initPropValue("UNITY_BUILD_BATCH_SIZE", "8"); #ifdef __APPLE__ if (this->GetGlobalGenerator()->IsXcode()) { initProp("XCODE_GENERATE_SCHEME"); -- cgit v0.12 From 8dfeb5d278625c55be1cc82399d29c0305ee4438 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Mon, 29 Jul 2019 17:44:55 +0200 Subject: Unity build: Add support for Visual Studio generator It works as expected in Visual Studio. Visual Studio 2017 will (partially) benefit from the build in support for unity builds. The custom unity sources are used, because the build in support doesn't allow batching of certain number of files. It can do only batching by directory. --- Source/cmLocalGenerator.cxx | 9 +++++- Source/cmLocalVisualStudio7Generator.cxx | 8 +++-- Source/cmVisualStudio10TargetGenerator.cxx | 51 ++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 6fade3e..6249c28 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -2266,7 +2266,10 @@ void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target, for (; begin != end; ++begin) { cmSourceFile* sf = filtered_sources[begin]; - sf->SetProperty("HEADER_FILE_ONLY", "ON"); + if (!this->GetGlobalGenerator()->IsMultiConfig()) { + sf->SetProperty("HEADER_FILE_ONLY", "ON"); + } + sf->SetProperty("UNITY_SOURCE_FILE", filename.c_str()); if (beforeInclude) { file << beforeInclude << "\n"; @@ -2283,6 +2286,10 @@ void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target, cmSystemTools::RemoveFile(filename_tmp); target->AddSource(filename, true); + + auto unity = this->Makefile->GetOrCreateSource(filename); + unity->SetProperty("SKIP_UNITY_BUILD_INCLUSION", "ON"); + unity->SetProperty("UNITY_SOURCE_FILE", filename.c_str()); } } } diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 795cee4..e9335c6 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -1320,6 +1320,7 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout, const std::string& libName, cmGeneratorTarget* target) { + this->AddUnityBuild(target, ""); this->AddPchDependencies(target, ""); std::vector configs; @@ -1508,8 +1509,11 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo( const std::string& linkLanguage = gt->GetLinkerLanguage(config.c_str()); // If HEADER_FILE_ONLY is set, we must suppress this generation in // the project file - fc.ExcludedFromBuild = - sf.GetPropertyAsBool("HEADER_FILE_ONLY") || !cmContains(acs.Configs, ci); + fc.ExcludedFromBuild = sf.GetPropertyAsBool("HEADER_FILE_ONLY") || + !cmContains(acs.Configs, ci) || + (gt->GetPropertyAsBool("UNITY_BUILD") && + sf.GetProperty("UNITY_SOURCE_FILE") && + !sf.GetPropertyAsBool("SKIP_UNITY_BUILD_INCLUSION")); if (fc.ExcludedFromBuild) { needfc = true; } diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index b4f05c7..08ad1c0 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -250,6 +250,7 @@ cmVisualStudio10TargetGenerator::cmVisualStudio10TargetGenerator( this->InSourceBuild = (this->Makefile->GetCurrentSourceDirectory() == this->Makefile->GetCurrentBinaryDirectory()); + this->LocalGenerator->AddUnityBuild(target, ""); this->LocalGenerator->AddPchDependencies(target, ""); } @@ -2049,6 +2050,17 @@ void cmVisualStudio10TargetGenerator::WriteAllSources(Elem& e0) if (this->GeneratorTarget->GetType() > cmStateEnums::UTILITY) { return; } + + const bool haveUnityBuild = + this->GeneratorTarget->GetPropertyAsBool("UNITY_BUILD"); + + if (haveUnityBuild && + this->GlobalGenerator->GetVersion() >= + cmGlobalVisualStudioGenerator::VS15) { + Elem e1(e0, "PropertyGroup"); + e1.Element("EnableUnitySupport", "true"); + } + Elem e1(e0, "ItemGroup"); e1.SetHasElements(); @@ -2147,6 +2159,45 @@ void cmVisualStudio10TargetGenerator::WriteAllSources(Elem& e0) Elem e2(e1, tool); this->WriteSource(e2, si.Source); + + bool useNativeUnityBuild = false; + if (haveUnityBuild && + this->GlobalGenerator->GetVersion() >= + cmGlobalVisualStudioGenerator::VS15) { + // Magic value taken from cmGlobalVisualStudioVersionedGenerator.cxx + static const std::string vs15 = "141"; + std::string toolset = + this->GlobalGenerator->GetPlatformToolsetString(); + cmSystemTools::ReplaceString(toolset, "v", ""); + + if (toolset.empty() || + cmSystemTools::VersionCompareGreaterEq(toolset, vs15)) { + useNativeUnityBuild = true; + } + } + + if (haveUnityBuild && strcmp(tool, "ClCompile") == 0 && + si.Source->GetProperty("UNITY_SOURCE_FILE")) { + if (useNativeUnityBuild) { + e2.Attribute( + "IncludeInUnityFile", + si.Source->GetPropertyAsBool("SKIP_UNITY_BUILD_INCLUSION") + ? "false" + : "true"); + e2.Attribute("CustomUnityFile", "true"); + + std::string unityDir = cmSystemTools::GetFilenamePath( + si.Source->GetProperty("UNITY_SOURCE_FILE")); + e2.Attribute("UnityFilesDirectory", unityDir); + } else { + // Visual Studio versions prior to 2017 do not know about unity + // builds, thus we exclude the files alredy part of unity sources. + if (!si.Source->GetPropertyAsBool("SKIP_UNITY_BUILD_INCLUSION")) { + exclude_configs = si.Configs; + } + } + } + if (si.Kind == cmGeneratorTarget::SourceKindObjectSource) { this->OutputSourceSpecificFlags(e2, si.Source); } -- cgit v0.12 From 1353802af366bd64ba8f730e6f93d4c416107d48 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Mon, 29 Jul 2019 19:33:55 +0200 Subject: Unity build: Add unit tests --- Tests/RunCMake/CMakeLists.txt | 1 + Tests/RunCMake/UnityBuild/CMakeLists.txt | 3 ++ Tests/RunCMake/UnityBuild/RunCMakeTest.cmake | 23 +++++++++++ Tests/RunCMake/UnityBuild/func.c | 6 +++ Tests/RunCMake/UnityBuild/func.h | 6 +++ Tests/RunCMake/UnityBuild/main.c | 6 +++ .../UnityBuild/unitybuild_batchsize-check.cmake | 11 +++++ .../RunCMake/UnityBuild/unitybuild_batchsize.cmake | 16 ++++++++ Tests/RunCMake/UnityBuild/unitybuild_c-check.cmake | 5 +++ Tests/RunCMake/UnityBuild/unitybuild_c.cmake | 12 ++++++ .../UnityBuild/unitybuild_c_and_cxx-check.cmake | 11 +++++ .../RunCMake/UnityBuild/unitybuild_c_and_cxx.cmake | 17 ++++++++ .../unitybuild_c_no_unity_build-check.cmake | 5 +++ .../UnityBuild/unitybuild_c_no_unity_build.cmake | 10 +++++ ...build_code_before_and_after_include-check.cmake | 7 ++++ .../unitybuild_code_before_and_after_include.cmake | 13 ++++++ .../RunCMake/UnityBuild/unitybuild_cxx-check.cmake | 5 +++ Tests/RunCMake/UnityBuild/unitybuild_cxx.cmake | 12 ++++++ .../unitybuild_default_batchsize-check.cmake | 7 ++++ .../UnityBuild/unitybuild_default_batchsize.cmake | 15 +++++++ .../UnityBuild/unitybuild_order-check.cmake | 7 ++++ Tests/RunCMake/UnityBuild/unitybuild_order.cmake | 12 ++++++ Tests/RunCMake/UnityBuild/unitybuild_runtest.cmake | 8 ++++ .../UnityBuild/unitybuild_skip-check.cmake | 14 +++++++ Tests/RunCMake/UnityBuild/unitybuild_skip.cmake | 30 ++++++++++++++ Tests/RunCMake/VS10Project/RunCMakeTest.cmake | 9 ++++ .../VS10Project/UnityBuildNative-check.cmake | 45 ++++++++++++++++++++ Tests/RunCMake/VS10Project/UnityBuildNative.cmake | 12 ++++++ .../VS10Project/UnityBuildPre2017-check.cmake | 48 ++++++++++++++++++++++ Tests/RunCMake/VS10Project/UnityBuildPre2017.cmake | 12 ++++++ 30 files changed, 388 insertions(+) create mode 100644 Tests/RunCMake/UnityBuild/CMakeLists.txt create mode 100644 Tests/RunCMake/UnityBuild/RunCMakeTest.cmake create mode 100644 Tests/RunCMake/UnityBuild/func.c create mode 100644 Tests/RunCMake/UnityBuild/func.h create mode 100644 Tests/RunCMake/UnityBuild/main.c create mode 100644 Tests/RunCMake/UnityBuild/unitybuild_batchsize-check.cmake create mode 100644 Tests/RunCMake/UnityBuild/unitybuild_batchsize.cmake create mode 100644 Tests/RunCMake/UnityBuild/unitybuild_c-check.cmake create mode 100644 Tests/RunCMake/UnityBuild/unitybuild_c.cmake create mode 100644 Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx-check.cmake create mode 100644 Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx.cmake create mode 100644 Tests/RunCMake/UnityBuild/unitybuild_c_no_unity_build-check.cmake create mode 100644 Tests/RunCMake/UnityBuild/unitybuild_c_no_unity_build.cmake create mode 100644 Tests/RunCMake/UnityBuild/unitybuild_code_before_and_after_include-check.cmake create mode 100644 Tests/RunCMake/UnityBuild/unitybuild_code_before_and_after_include.cmake create mode 100644 Tests/RunCMake/UnityBuild/unitybuild_cxx-check.cmake create mode 100644 Tests/RunCMake/UnityBuild/unitybuild_cxx.cmake create mode 100644 Tests/RunCMake/UnityBuild/unitybuild_default_batchsize-check.cmake create mode 100644 Tests/RunCMake/UnityBuild/unitybuild_default_batchsize.cmake create mode 100644 Tests/RunCMake/UnityBuild/unitybuild_order-check.cmake create mode 100644 Tests/RunCMake/UnityBuild/unitybuild_order.cmake create mode 100644 Tests/RunCMake/UnityBuild/unitybuild_runtest.cmake create mode 100644 Tests/RunCMake/UnityBuild/unitybuild_skip-check.cmake create mode 100644 Tests/RunCMake/UnityBuild/unitybuild_skip.cmake create mode 100644 Tests/RunCMake/VS10Project/UnityBuildNative-check.cmake create mode 100644 Tests/RunCMake/VS10Project/UnityBuildNative.cmake create mode 100644 Tests/RunCMake/VS10Project/UnityBuildPre2017-check.cmake create mode 100644 Tests/RunCMake/VS10Project/UnityBuildPre2017.cmake diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 48eebcc..8fd5234 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -576,3 +576,4 @@ endif() add_RunCMake_test("CTestCommandExpandLists") add_RunCMake_test(PrecompileHeaders) +add_RunCMake_test("UnityBuild") diff --git a/Tests/RunCMake/UnityBuild/CMakeLists.txt b/Tests/RunCMake/UnityBuild/CMakeLists.txt new file mode 100644 index 0000000..77030d6 --- /dev/null +++ b/Tests/RunCMake/UnityBuild/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.15) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/UnityBuild/RunCMakeTest.cmake b/Tests/RunCMake/UnityBuild/RunCMakeTest.cmake new file mode 100644 index 0000000..8e484d0 --- /dev/null +++ b/Tests/RunCMake/UnityBuild/RunCMakeTest.cmake @@ -0,0 +1,23 @@ +include(RunCMake) + +run_cmake(unitybuild_c) +run_cmake(unitybuild_cxx) +run_cmake(unitybuild_c_and_cxx) +run_cmake(unitybuild_batchsize) +run_cmake(unitybuild_default_batchsize) +run_cmake(unitybuild_skip) +run_cmake(unitybuild_code_before_and_after_include) +run_cmake(unitybuild_c_no_unity_build) +run_cmake(unitybuild_order) + +function(run_test name) + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${name}-build) + set(RunCMake_TEST_NO_CLEAN 1) + run_cmake(${name}) + run_cmake_command(${name}-build ${CMAKE_COMMAND} --build . --config Debug) + run_cmake_command(${name}-test ${CMAKE_CTEST_COMMAND} -C Debug) + unset(RunCMake_TEST_BINARY_DIR) + unset(RunCMake_TEST_NO_CLEAN) +endfunction() + +run_test(unitybuild_runtest) diff --git a/Tests/RunCMake/UnityBuild/func.c b/Tests/RunCMake/UnityBuild/func.c new file mode 100644 index 0000000..b14c907 --- /dev/null +++ b/Tests/RunCMake/UnityBuild/func.c @@ -0,0 +1,6 @@ +#include "func.h" + +int func(void) +{ + return 0; +} diff --git a/Tests/RunCMake/UnityBuild/func.h b/Tests/RunCMake/UnityBuild/func.h new file mode 100644 index 0000000..563a980 --- /dev/null +++ b/Tests/RunCMake/UnityBuild/func.h @@ -0,0 +1,6 @@ +#ifndef func_h +#define func_h + +extern int func(void); + +#endif diff --git a/Tests/RunCMake/UnityBuild/main.c b/Tests/RunCMake/UnityBuild/main.c new file mode 100644 index 0000000..19c18d4 --- /dev/null +++ b/Tests/RunCMake/UnityBuild/main.c @@ -0,0 +1,6 @@ +#include "func.h" + +int main(void) +{ + return func(); +} diff --git a/Tests/RunCMake/UnityBuild/unitybuild_batchsize-check.cmake b/Tests/RunCMake/UnityBuild/unitybuild_batchsize-check.cmake new file mode 100644 index 0000000..32bb8e7 --- /dev/null +++ b/Tests/RunCMake/UnityBuild/unitybuild_batchsize-check.cmake @@ -0,0 +1,11 @@ +set(unitybuild_c0 "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.c") +set(unitybuild_c1 "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_1.c") +if(NOT EXISTS "${unitybuild_c0}") + set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_c0} does not exist.") + return() +endif() + +if(NOT EXISTS "${unitybuild_c1}") + set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_c1} does not exist.") + return() +endif() diff --git a/Tests/RunCMake/UnityBuild/unitybuild_batchsize.cmake b/Tests/RunCMake/UnityBuild/unitybuild_batchsize.cmake new file mode 100644 index 0000000..7caf251 --- /dev/null +++ b/Tests/RunCMake/UnityBuild/unitybuild_batchsize.cmake @@ -0,0 +1,16 @@ +project(unitybuild_batchsize C) + +set(srcs "") +foreach(s RANGE 1 8) + set(src "${CMAKE_CURRENT_BINARY_DIR}/s${s}.c") + file(WRITE "${src}" "int s${s}(void) { return 0; }\n") + list(APPEND srcs "${src}") +endforeach() + +add_library(tgt SHARED ${srcs}) + +set_target_properties(tgt + PROPERTIES + UNITY_BUILD ON + UNITY_BUILD_BATCH_SIZE 4 +) diff --git a/Tests/RunCMake/UnityBuild/unitybuild_c-check.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c-check.cmake new file mode 100644 index 0000000..c980df0 --- /dev/null +++ b/Tests/RunCMake/UnityBuild/unitybuild_c-check.cmake @@ -0,0 +1,5 @@ +set(unitybuild_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.c") +if(NOT EXISTS "${unitybuild_c}") + set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_c} does not exist.") + return() +endif() diff --git a/Tests/RunCMake/UnityBuild/unitybuild_c.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c.cmake new file mode 100644 index 0000000..77a09cb --- /dev/null +++ b/Tests/RunCMake/UnityBuild/unitybuild_c.cmake @@ -0,0 +1,12 @@ +project(unitybuild_c C) + +set(srcs "") +foreach(s RANGE 1 8) + set(src "${CMAKE_CURRENT_BINARY_DIR}/s${s}.c") + file(WRITE "${src}" "int s${s}(void) { return 0; }\n") + list(APPEND srcs "${src}") +endforeach() + +add_library(tgt SHARED ${srcs}) + +set_target_properties(tgt PROPERTIES UNITY_BUILD ON) diff --git a/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx-check.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx-check.cmake new file mode 100644 index 0000000..32c2992 --- /dev/null +++ b/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx-check.cmake @@ -0,0 +1,11 @@ +set(unitybuild_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.c") +if(NOT EXISTS "${unitybuild_c}") + set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_c} does not exist.") + return() +endif() + +set(unitybuild_cxx "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.cxx") +if(NOT EXISTS "${unitybuild_cxx}") + set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_cxx} does not exist.") + return() +endif() diff --git a/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx.cmake new file mode 100644 index 0000000..073aff2 --- /dev/null +++ b/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx.cmake @@ -0,0 +1,17 @@ +project(unitybuild_c_and_cxx C CXX) + +set(srcs "") +foreach(s RANGE 1 8) + set(src_c "${CMAKE_CURRENT_BINARY_DIR}/s${s}.c") + file(WRITE "${src_c}" "int s${s}(void) { return 0; }\n") + + set(src_cxx "${CMAKE_CURRENT_BINARY_DIR}/s${s}.cxx") + file(WRITE "${src_cxx}" "int s${s}(void) { return 0; }\n") + + list(APPEND srcs "${src_c}") + list(APPEND srcs "${src_cxx}") +endforeach() + +add_library(tgt SHARED ${srcs}) + +set_target_properties(tgt PROPERTIES UNITY_BUILD ON) diff --git a/Tests/RunCMake/UnityBuild/unitybuild_c_no_unity_build-check.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c_no_unity_build-check.cmake new file mode 100644 index 0000000..cb71ea3 --- /dev/null +++ b/Tests/RunCMake/UnityBuild/unitybuild_c_no_unity_build-check.cmake @@ -0,0 +1,5 @@ +set(unitybuild_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.c") +if(EXISTS "${unitybuild_c}") + set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_c} should not exist.") + return() +endif() diff --git a/Tests/RunCMake/UnityBuild/unitybuild_c_no_unity_build.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c_no_unity_build.cmake new file mode 100644 index 0000000..1185e9f --- /dev/null +++ b/Tests/RunCMake/UnityBuild/unitybuild_c_no_unity_build.cmake @@ -0,0 +1,10 @@ +project(unitybuild_c_no_unity_build C) + +set(srcs "") +foreach(s RANGE 1 8) + set(src "${CMAKE_CURRENT_BINARY_DIR}/s${s}.c") + file(WRITE "${src}" "int s${s}(void) { return 0; }\n") + list(APPEND srcs "${src}") +endforeach() + +add_library(tgt SHARED ${srcs}) diff --git a/Tests/RunCMake/UnityBuild/unitybuild_code_before_and_after_include-check.cmake b/Tests/RunCMake/UnityBuild/unitybuild_code_before_and_after_include-check.cmake new file mode 100644 index 0000000..8fcb18f --- /dev/null +++ b/Tests/RunCMake/UnityBuild/unitybuild_code_before_and_after_include-check.cmake @@ -0,0 +1,7 @@ +set(unitybuild_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.c") +file(STRINGS ${unitybuild_c} unitybuild_c_strings) +string(REGEX MATCH "#define NOMINMAX.*#include.*s1.c.*#undef NOMINMAX" matched_code ${unitybuild_c_strings}) +if(NOT matched_code) + set(RunCMake_TEST_FAILED "Generated unity file doesn't include expected code before and after include") + return() +endif() diff --git a/Tests/RunCMake/UnityBuild/unitybuild_code_before_and_after_include.cmake b/Tests/RunCMake/UnityBuild/unitybuild_code_before_and_after_include.cmake new file mode 100644 index 0000000..cc9cc28 --- /dev/null +++ b/Tests/RunCMake/UnityBuild/unitybuild_code_before_and_after_include.cmake @@ -0,0 +1,13 @@ +project(unitybuild_code_before_and_after_include C) + +set(src "${CMAKE_CURRENT_BINARY_DIR}/s1.c") +file(WRITE "${src}" "int s1(void) { return 0; }\n") + +add_library(tgt SHARED ${src}) + +set_target_properties(tgt + PROPERTIES + UNITY_BUILD ON + UNITY_BUILD_CODE_BEFORE_INCLUDE "#define NOMINMAX" + UNITY_BUILD_CODE_AFTER_INCLUDE "#undef NOMINMAX" +) diff --git a/Tests/RunCMake/UnityBuild/unitybuild_cxx-check.cmake b/Tests/RunCMake/UnityBuild/unitybuild_cxx-check.cmake new file mode 100644 index 0000000..89a037a --- /dev/null +++ b/Tests/RunCMake/UnityBuild/unitybuild_cxx-check.cmake @@ -0,0 +1,5 @@ +set(unitybuild_cxx "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.cxx") +if(NOT EXISTS "${unitybuild_cxx}") + set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_cxx} does not exist.") + return() +endif() diff --git a/Tests/RunCMake/UnityBuild/unitybuild_cxx.cmake b/Tests/RunCMake/UnityBuild/unitybuild_cxx.cmake new file mode 100644 index 0000000..be800d7 --- /dev/null +++ b/Tests/RunCMake/UnityBuild/unitybuild_cxx.cmake @@ -0,0 +1,12 @@ +project(unitybuild_cxx CXX) + +set(srcs "") +foreach(s RANGE 1 8) + set(src "${CMAKE_CURRENT_BINARY_DIR}/s${s}.cxx") + file(WRITE "${src}" "int s${s}(void) { return 0; }\n") + list(APPEND srcs "${src}") +endforeach() + +add_library(tgt SHARED ${srcs}) + +set_target_properties(tgt PROPERTIES UNITY_BUILD ON) diff --git a/Tests/RunCMake/UnityBuild/unitybuild_default_batchsize-check.cmake b/Tests/RunCMake/UnityBuild/unitybuild_default_batchsize-check.cmake new file mode 100644 index 0000000..7dfc007 --- /dev/null +++ b/Tests/RunCMake/UnityBuild/unitybuild_default_batchsize-check.cmake @@ -0,0 +1,7 @@ +set(unitybuild_c0 "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.c") +file(STRINGS ${unitybuild_c0} unitybuild_c_strings REGEX "/s[0-9]+.c\"$" ) +list(LENGTH unitybuild_c_strings number_of_includes) +if(NOT number_of_includes EQUAL 8) + set(RunCMake_TEST_FAILED "Generated unity doesn't include the expect number of files") + return() +endif() diff --git a/Tests/RunCMake/UnityBuild/unitybuild_default_batchsize.cmake b/Tests/RunCMake/UnityBuild/unitybuild_default_batchsize.cmake new file mode 100644 index 0000000..60b9875 --- /dev/null +++ b/Tests/RunCMake/UnityBuild/unitybuild_default_batchsize.cmake @@ -0,0 +1,15 @@ +project(unitybuild_default_batchsize C) + +set(srcs "") +foreach(s RANGE 1 10) + set(src "${CMAKE_CURRENT_BINARY_DIR}/s${s}.c") + file(WRITE "${src}" "int s${s}(void) { return 0; }\n") + list(APPEND srcs "${src}") +endforeach() + +add_library(tgt SHARED ${srcs}) + +set_target_properties(tgt + PROPERTIES + UNITY_BUILD ON +) diff --git a/Tests/RunCMake/UnityBuild/unitybuild_order-check.cmake b/Tests/RunCMake/UnityBuild/unitybuild_order-check.cmake new file mode 100644 index 0000000..533a89c --- /dev/null +++ b/Tests/RunCMake/UnityBuild/unitybuild_order-check.cmake @@ -0,0 +1,7 @@ +set(unitybuild_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.c") +file(STRINGS ${unitybuild_c} unitybuild_c_strings) +string(REGEX MATCH ".*#include.*s3.c.*#include.*s1.c.*#include.*s2.c.*" matched_code ${unitybuild_c_strings}) +if(NOT matched_code) + set(RunCMake_TEST_FAILED "Generated unity file doesn't include expected oder of source files") + return() +endif() diff --git a/Tests/RunCMake/UnityBuild/unitybuild_order.cmake b/Tests/RunCMake/UnityBuild/unitybuild_order.cmake new file mode 100644 index 0000000..819603d --- /dev/null +++ b/Tests/RunCMake/UnityBuild/unitybuild_order.cmake @@ -0,0 +1,12 @@ +project(unitybuild_order C) + +set(srcs "") +foreach(s 3 1 2) + set(src "${CMAKE_CURRENT_BINARY_DIR}/s${s}.c") + file(WRITE "${src}" "int s${s}(void) { return 0; }\n") + list(APPEND srcs "${src}") +endforeach() + +add_library(tgt SHARED ${srcs}) + +set_target_properties(tgt PROPERTIES UNITY_BUILD ON) diff --git a/Tests/RunCMake/UnityBuild/unitybuild_runtest.cmake b/Tests/RunCMake/UnityBuild/unitybuild_runtest.cmake new file mode 100644 index 0000000..8816299 --- /dev/null +++ b/Tests/RunCMake/UnityBuild/unitybuild_runtest.cmake @@ -0,0 +1,8 @@ +project(unitybuild_runtest C) + +set(CMAKE_UNITY_BUILD ON) # This tests that the variable works in addition to the property + +add_executable(main main.c func.c) + +enable_testing() +add_test(NAME main COMMAND main) diff --git a/Tests/RunCMake/UnityBuild/unitybuild_skip-check.cmake b/Tests/RunCMake/UnityBuild/unitybuild_skip-check.cmake new file mode 100644 index 0000000..fdd45bc --- /dev/null +++ b/Tests/RunCMake/UnityBuild/unitybuild_skip-check.cmake @@ -0,0 +1,14 @@ +set(unitybuild_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.c") +file(STRINGS ${unitybuild_c} unitybuild_c_strings) + +string(REGEX MATCH "\\/s[1-6].c" matched_files_1_6 ${unitybuild_c_strings}) +if(matched_files_1_6) + set(RunCMake_TEST_FAILED "Generated unity contains s1.c -> s6.c which should have been skipped") + return() +endif() + +string(REGEX MATCH "\\/s[7-8].c" matched_files_7_8 ${unitybuild_c_strings}) +if(NOT matched_files_7_8) + set(RunCMake_TEST_FAILED "Generated unity should have contained s7.c, s8.c!") + return() +endif() diff --git a/Tests/RunCMake/UnityBuild/unitybuild_skip.cmake b/Tests/RunCMake/UnityBuild/unitybuild_skip.cmake new file mode 100644 index 0000000..74524ad --- /dev/null +++ b/Tests/RunCMake/UnityBuild/unitybuild_skip.cmake @@ -0,0 +1,30 @@ +project(unitybuild_skip C) + +set(srcs "") +foreach(s RANGE 1 8) + set(src "${CMAKE_CURRENT_BINARY_DIR}/s${s}.c") + file(WRITE "${src}" "int s${s}(void) { return 0; }\n") + list(APPEND srcs "${src}") +endforeach() + +add_library(tgt SHARED ${srcs}) + +set_target_properties(tgt PROPERTIES UNITY_BUILD ON) + +set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/s1.c + PROPERTIES GENERATED ON) + +set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/s2.c + PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON) + +set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/s3.c + PROPERTIES COMPILE_OPTIONS "val") + +set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/s4.c + PROPERTIES COMPILE_DEFINITIONS "val") + +set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/s5.c + PROPERTIES COMPILE_FLAGS "val") + +set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/s6.c + PROPERTIES INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}") diff --git a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake index 72154e7..dcdd177 100644 --- a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake +++ b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake @@ -34,3 +34,12 @@ endif() if(CMAKE_C_COMPILER_ID STREQUAL "MSVC" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 19.20) run_cmake(VsSpectreMitigation) endif() + +# Visual Studio 2017 has toolset version 141 +string(REPLACE "v" "" generator_toolset "${RunCMake_GENERATOR_TOOLSET}") +if (RunCMake_GENERATOR MATCHES "Visual Studio 1[0-4] 201[0-5]" OR + (RunCMake_GENERATOR_TOOLSET AND generator_toolset VERSION_LESS "141")) + run_cmake(UnityBuildPre2017) +else() + run_cmake(UnityBuildNative) +endif() diff --git a/Tests/RunCMake/VS10Project/UnityBuildNative-check.cmake b/Tests/RunCMake/VS10Project/UnityBuildNative-check.cmake new file mode 100644 index 0000000..87f247d --- /dev/null +++ b/Tests/RunCMake/VS10Project/UnityBuildNative-check.cmake @@ -0,0 +1,45 @@ +set(unitybuild_c0 "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.c") +if(NOT EXISTS "${unitybuild_c0}") + set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_c0} does not exist.") + return() +endif() + +set(tgt_project "${RunCMake_TEST_BINARY_DIR}/tgt.vcxproj") +if (NOT EXISTS "${tgt_project}") + set(RunCMake_TEST_FAILED "Generated project file ${tgt_project} doesn't exist.") + return() +endif() + +file(STRINGS ${tgt_project} tgt_projects_strings) + +foreach(line IN LISTS tgt_projects_strings) + if (line MATCHES "true") + set(have_unity_support ON) + endif() + + if (line MATCHES " block.") + return() +endif() + +string(REPLACE "\\" "/" unity_source_line "${unity_source_line}") +string(FIND "${unity_source_line}" "CMakeFiles/tgt.dir/Unity/unity_0.c" unity_source_file_position) +if (unity_source_file_position EQUAL "-1") + set(RunCMake_TEST_FAILED "Generated project should include the generated unity source file.") + return() +endif() + +list(LENGTH sources_list number_of_sources) +if(NOT number_of_sources EQUAL 8) + set(RunCMake_TEST_FAILED "Generated project doesn't include the expect number of files.") + return() +endif() diff --git a/Tests/RunCMake/VS10Project/UnityBuildNative.cmake b/Tests/RunCMake/VS10Project/UnityBuildNative.cmake new file mode 100644 index 0000000..77a09cb --- /dev/null +++ b/Tests/RunCMake/VS10Project/UnityBuildNative.cmake @@ -0,0 +1,12 @@ +project(unitybuild_c C) + +set(srcs "") +foreach(s RANGE 1 8) + set(src "${CMAKE_CURRENT_BINARY_DIR}/s${s}.c") + file(WRITE "${src}" "int s${s}(void) { return 0; }\n") + list(APPEND srcs "${src}") +endforeach() + +add_library(tgt SHARED ${srcs}) + +set_target_properties(tgt PROPERTIES UNITY_BUILD ON) diff --git a/Tests/RunCMake/VS10Project/UnityBuildPre2017-check.cmake b/Tests/RunCMake/VS10Project/UnityBuildPre2017-check.cmake new file mode 100644 index 0000000..1c6bab8 --- /dev/null +++ b/Tests/RunCMake/VS10Project/UnityBuildPre2017-check.cmake @@ -0,0 +1,48 @@ +set(unitybuild_c0 "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.c") +if(NOT EXISTS "${unitybuild_c0}") + set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_c0} does not exist.") + return() +endif() + +set(tgt_project "${RunCMake_TEST_BINARY_DIR}/tgt.vcxproj") +if (NOT EXISTS "${tgt_project}") + set(RunCMake_TEST_FAILED "Generated project file ${tgt_project} doesn't exist.") + return() +endif() + +file(STRINGS ${tgt_project} tgt_projects_strings) + +foreach(line IN LISTS tgt_projects_strings) + if (line MATCHES "") + set(unity_source_line ${line}) + endif() + + if (line MATCHES "") + string(REGEX MATCH "" source_file ${line}) + list(APPEND sources_list ${source_file}) + endif() + + if (line MATCHES "") + list(APPEND excluded_sources_list ${source_file}) + endif() +endforeach() + +string(REPLACE "\\" "/" unity_source_line ${unity_source_line}) +string(FIND "${unity_source_line}" "CMakeFiles/tgt.dir/Unity/unity_0.c" unity_source_file_position) +if (unity_source_file_position EQUAL "-1") + set(RunCMake_TEST_FAILED "Generated project should include the generated unity source file.") + return() +endif() + +list(LENGTH sources_list number_of_sources) +if(NOT number_of_sources EQUAL 8) + set(RunCMake_TEST_FAILED "Generated project doesn't include the expect number of files.") + return() +endif() + +# Exclusions for Debug|Release|MinSizeRel|RelWithDebInfo +list(LENGTH excluded_sources_list number_of_excluded_sources) +if(NOT number_of_excluded_sources EQUAL 32) + set(RunCMake_TEST_FAILED "Generated project doesn't exclude the source files for all configurations.") + return() +endif() diff --git a/Tests/RunCMake/VS10Project/UnityBuildPre2017.cmake b/Tests/RunCMake/VS10Project/UnityBuildPre2017.cmake new file mode 100644 index 0000000..77a09cb --- /dev/null +++ b/Tests/RunCMake/VS10Project/UnityBuildPre2017.cmake @@ -0,0 +1,12 @@ +project(unitybuild_c C) + +set(srcs "") +foreach(s RANGE 1 8) + set(src "${CMAKE_CURRENT_BINARY_DIR}/s${s}.c") + file(WRITE "${src}" "int s${s}(void) { return 0; }\n") + list(APPEND srcs "${src}") +endforeach() + +add_library(tgt SHARED ${srcs}) + +set_target_properties(tgt PROPERTIES UNITY_BUILD ON) -- cgit v0.12 From 7786a05c707dc5ffe9fdf7a6b468f56ed18c9e8a Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Tue, 30 Jul 2019 18:31:16 +0200 Subject: Unity build: Add XCode support --- Source/cmGlobalXCodeGenerator.cxx | 1 + Source/cmLocalGenerator.cxx | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 427ab44..74d97e1 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -2839,6 +2839,7 @@ bool cmGlobalXCodeGenerator::CreateGroups( continue; } + generator->AddUnityBuild(gtgt, ""); generator->AddPchDependencies(gtgt, ""); auto addSourceToGroup = [this, mf, gtgt, diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 6249c28..c85ee2d 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -2266,7 +2266,11 @@ void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target, for (; begin != end; ++begin) { cmSourceFile* sf = filtered_sources[begin]; - if (!this->GetGlobalGenerator()->IsMultiConfig()) { + // Only in Visual Studio generator we keep the source files + // for explicit processing. For the rest the source files will + // not be included in the project. + if (!this->GetGlobalGenerator()->IsMultiConfig() || + this->GetGlobalGenerator()->IsXcode()) { sf->SetProperty("HEADER_FILE_ONLY", "ON"); } sf->SetProperty("UNITY_SOURCE_FILE", filename.c_str()); -- cgit v0.12