diff options
author | Robert Maynard <robert.maynard@kitware.com> | 2020-05-06 15:45:42 -0400 |
---|---|---|
committer | Robert Maynard <robert.maynard@kitware.com> | 2020-05-07 11:13:34 -0400 |
commit | 9f4eb352fe1383f740876e3924205be1d4bf897c (patch) | |
tree | 6911d23d9c5f950860a9ba1d0048b4d7f1417f1c | |
parent | b00585adcc11afcf4d02d9d9927a929f33b19546 (diff) | |
download | cmake-9f4eb352fe1383f740876e3924205be1d4bf897c.tar.gz |
Unity Builds: Support explicit specification of sources to groups
Instead of having CMake determine which files should go into each
unity file, the user can now use explicitly state the mapping.
27 files changed, 511 insertions, 5 deletions
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index 9031e9c69d..4103806cbf 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -346,6 +346,7 @@ Properties on Targets /prop_tgt/UNITY_BUILD_BATCH_SIZE /prop_tgt/UNITY_BUILD_CODE_AFTER_INCLUDE /prop_tgt/UNITY_BUILD_CODE_BEFORE_INCLUDE + /prop_tgt/UNITY_BUILD_MODE /prop_tgt/VERSION /prop_tgt/VISIBILITY_INLINES_HIDDEN /prop_tgt/VS_CONFIGURATION_TYPE @@ -484,6 +485,7 @@ Properties on Source Files /prop_sf/Swift_DEPENDENCIES_FILE /prop_sf/Swift_DIAGNOSTICS_FILE /prop_sf/SYMBOLIC + /prop_sf/UNITY_GROUP /prop_sf/VS_COPY_TO_OUT_DIR /prop_sf/VS_CSHARP_tagname /prop_sf/VS_DEPLOYMENT_CONTENT diff --git a/Help/prop_sf/UNITY_GROUP.rst b/Help/prop_sf/UNITY_GROUP.rst new file mode 100644 index 0000000000..ec6b0f6520 --- /dev/null +++ b/Help/prop_sf/UNITY_GROUP.rst @@ -0,0 +1,5 @@ +UNITY_GROUP +----------- + +This property controls which *bucket* the source will be part of when +the :prop_tgt:`UNITY_BUILD_MODE` is set to ``GROUP``. diff --git a/Help/prop_tgt/UNITY_BUILD.rst b/Help/prop_tgt/UNITY_BUILD.rst index 479802e595..e140952110 100644 --- a/Help/prop_tgt/UNITY_BUILD.rst +++ b/Help/prop_tgt/UNITY_BUILD.rst @@ -5,8 +5,28 @@ When this property is set to true, the target source files will be combined into batches for faster compilation. This is done by creating a (set of) unity sources which ``#include`` the original sources, then compiling these unity sources instead of the originals. This is known as a *Unity* or *Jumbo* -build. The :prop_tgt:`UNITY_BUILD_BATCH_SIZE` property controls the upper -limit on how many sources can be combined per unity source file. +build. + +CMake provides different algorithms for selecting which sources are grouped +together into a *bucket*. Algorithm selection is decided by the +:prop_tgt:`UNITY_BUILD_MODE` target property, which has the following acceptable +values: + +* ``BATCH`` + When in this mode CMake determines which files are grouped together. + The :prop_tgt:`UNITY_BUILD_BATCH_SIZE` property controls the upper limit on + how many sources can be combined per unity source file. + +* ``GROUP`` + When in this mode each target explicitly specifies how to group + source files. Each source file that has the same + :prop_sf:`UNITY_GROUP` value will be grouped together. Any sources + that don't have this property will be compiled individually. The + :prop_tgt:`UNITY_BUILD_BATCH_SIZE` property is ignored when using + this mode. + +If no explicit :prop_tgt:`UNITY_BUILD_MODE` has been specified, CMake will +default to ``BATCH``. Unity builds are not currently supported for all languages. CMake version |release| supports combining ``C`` and ``CXX`` source files. For targets that diff --git a/Help/prop_tgt/UNITY_BUILD_MODE.rst b/Help/prop_tgt/UNITY_BUILD_MODE.rst new file mode 100644 index 0000000000..cbc49891cf --- /dev/null +++ b/Help/prop_tgt/UNITY_BUILD_MODE.rst @@ -0,0 +1,22 @@ +UNITY_BUILD_MODE +---------------- + +CMake provides different algorithms for selecting which sources are grouped +together into a *bucket*. Selection is decided by this property, +which has the following acceptable values: + +* ``BATCH`` + When in this mode CMake determines which files are grouped together. + The :prop_tgt:`UNITY_BUILD_BATCH_SIZE` property controls the upper limit on + how many sources can be combined per unity source file. + +* ``GROUP`` + When in this mode each target explicitly specifies how to group + source files. Each source file that has the same + :prop_sf:`UNITY_GROUP` value will be grouped together. Any sources + that don't have this property will be compiled individually. The + :prop_tgt:`UNITY_BUILD_BATCH_SIZE` property is ignored when using + this mode. + +If no explicit :prop_tgt:`UNITY_BUILD_MODE` has been specified, CMake will +default to ``BATCH``. diff --git a/Help/release/dev/grouped-unity-build-mode.rst b/Help/release/dev/grouped-unity-build-mode.rst new file mode 100644 index 0000000000..802de4af89 --- /dev/null +++ b/Help/release/dev/grouped-unity-build-mode.rst @@ -0,0 +1,6 @@ +grouped-unity-build-mode +------------------------ + +* The :prop_tgt:`UNITY_BUILD_MODE` target property was added to tell + generators which algorithm to use for grouping included source + files. diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index dee5cb4dbd..63b757800a 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -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); diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index a776398857..d43fbe5c03 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -372,6 +372,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, initProp("DISABLE_PRECOMPILE_HEADERS"); initProp("UNITY_BUILD"); initPropValue("UNITY_BUILD_BATCH_SIZE", "8"); + initPropValue("UNITY_BUILD_MODE", "BATCH"); initPropValue("PCH_WARN_INVALID", "ON"); #ifdef __APPLE__ if (this->GetGlobalGenerator()->IsXcode()) { diff --git a/Tests/RunCMake/UnityBuild/RunCMakeTest.cmake b/Tests/RunCMake/UnityBuild/RunCMakeTest.cmake index 24daa64ff0..9ba3c856db 100644 --- a/Tests/RunCMake/UnityBuild/RunCMakeTest.cmake +++ b/Tests/RunCMake/UnityBuild/RunCMakeTest.cmake @@ -1,14 +1,20 @@ include(RunCMake) run_cmake(unitybuild_c) +run_cmake(unitybuild_c_batch) +run_cmake(unitybuild_c_group) run_cmake(unitybuild_cxx) +run_cmake(unitybuild_cxx_group) run_cmake(unitybuild_c_and_cxx) +run_cmake(unitybuild_c_and_cxx_group) 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_c_no_unity_build_group) run_cmake(unitybuild_order) +run_cmake(unitybuild_invalid_mode) function(run_test name) set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${name}-build) diff --git a/Tests/RunCMake/UnityBuild/f.c b/Tests/RunCMake/UnityBuild/f.c new file mode 100644 index 0000000000..d5813c67ca --- /dev/null +++ b/Tests/RunCMake/UnityBuild/f.c @@ -0,0 +1,5 @@ +int f(int x) +{ + (void)x; + return 0; +} diff --git a/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_group-check.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_group-check.cmake new file mode 100644 index 0000000000..b027682b18 --- /dev/null +++ b/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_group-check.cmake @@ -0,0 +1,42 @@ +set(unitybuild_a_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_a_c.c") +if(NOT EXISTS "${unitybuild_a_c}") + set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_a_c} does not exist.") + return() +else() + #verify that the 4 c file is part of this grouping and therefore UNITY_BUILD_BATCH_SIZE + #was ignored + file(STRINGS ${unitybuild_a_c} unitybuild_a_c_strings) + string(REGEX MATCH ".*#include.*s1.c.*#include.*s2.c.*#include.*s3.c.*#include.*s4.c.*" matched_code ${unitybuild_a_c_strings}) + if(NOT matched_code) + set(RunCMake_TEST_FAILED "Generated unity file doesn't include expected source files") + return() + endif() +endif() + +set(unitybuild_b_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_b_c.c") +if(NOT EXISTS "${unitybuild_b_c}") + set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_b_c} does not exist.") + return() +endif() + + +set(unitybuild_a_cxx "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_a_cxx.cxx") +if(NOT EXISTS "${unitybuild_a_cxx}") + set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_a_cxx} does not exist.") + return() +else() + #verify that the 4 cxx file are part of this grouping and therefore UNITY_BUILD_BATCH_SIZE + #was ignored + file(STRINGS ${unitybuild_a_cxx} unitybuild_a_cxx_strings) + string(REGEX MATCH ".*#include.*s1.cxx.*#include.*s2.cxx.*#include.*s3.cxx.*#include.*s4.cxx.*" matched_code ${unitybuild_a_cxx_strings}) + if(NOT matched_code) + set(RunCMake_TEST_FAILED "Generated unity file doesn't include expected source files") + return() + endif() +endif() + +set(unitybuild_b_cxx "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_b_cxx.cxx") +if(NOT EXISTS "${unitybuild_b_cxx}") + set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_b_cxx} does not exist.") + return() +endif() diff --git a/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_group.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_group.cmake new file mode 100644 index 0000000000..7bf3f4b3af --- /dev/null +++ b/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_group.cmake @@ -0,0 +1,39 @@ +project(unitybuild_c_and_cxx C CXX) + +set(srcs f.c) +foreach(s RANGE 1 8) + set(src_c "${CMAKE_CURRENT_BINARY_DIR}/s${s}.c") + file(WRITE "${src_c}" " +int f(int);\n +int s${s}(void) { return f(${s}); }\n" + ) + + set(src_cxx "${CMAKE_CURRENT_BINARY_DIR}/s${s}.cxx") + file(WRITE "${src_cxx}" " +extern \"C\" { \n + int f(int); \n +}\n + int s${s}(void) { return f(${s}); }\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 + UNITY_BUILD_MODE GROUP + #UNITY_BUILD_BATCH_SIZE will be ignored + UNITY_BUILD_BATCH_SIZE 2) + +set_source_files_properties(s1.c s2.c s3.c s4.c + s1.cxx s2.cxx s3.cxx s4.cxx + PROPERTIES UNITY_GROUP "a" + ) +set_source_files_properties(s5.c s6.c s7.c s8.c + s5.cxx s6.cxx s7.cxx s8.cxx + PROPERTIES UNITY_GROUP "b" + ) diff --git a/Tests/RunCMake/UnityBuild/unitybuild_c_batch-check.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c_batch-check.cmake new file mode 100644 index 0000000000..024286d5a0 --- /dev/null +++ b/Tests/RunCMake/UnityBuild/unitybuild_c_batch-check.cmake @@ -0,0 +1,5 @@ +set(unitybuild_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0_c.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_batch.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c_batch.cmake new file mode 100644 index 0000000000..33873b658d --- /dev/null +++ b/Tests/RunCMake/UnityBuild/unitybuild_c_batch.cmake @@ -0,0 +1,15 @@ +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 + UNITY_BUILD_MODE BATCH + ) diff --git a/Tests/RunCMake/UnityBuild/unitybuild_c_group-check.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c_group-check.cmake new file mode 100644 index 0000000000..0b9ea15de7 --- /dev/null +++ b/Tests/RunCMake/UnityBuild/unitybuild_c_group-check.cmake @@ -0,0 +1,11 @@ +set(unitybuild_a_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_a_c.c") +if(NOT EXISTS "${unitybuild_a_c}") + set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_a_c} does not exist.") + return() +endif() + +set(unitybuild_b_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_b_c.c") +if(NOT EXISTS "${unitybuild_b_c}") + set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_b_c} does not exist.") + return() +endif() diff --git a/Tests/RunCMake/UnityBuild/unitybuild_c_group.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c_group.cmake new file mode 100644 index 0000000000..1fa17f3232 --- /dev/null +++ b/Tests/RunCMake/UnityBuild/unitybuild_c_group.cmake @@ -0,0 +1,17 @@ +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 + UNITY_BUILD_MODE GROUP) + +set_source_files_properties(s1.c PROPERTIES UNITY_GROUP "a") +set_source_files_properties(s2.c PROPERTIES UNITY_GROUP "a") +set_source_files_properties(s3.c s4.c PROPERTIES UNITY_GROUP "b") diff --git a/Tests/RunCMake/UnityBuild/unitybuild_c_no_unity_build_group-check.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c_no_unity_build_group-check.cmake new file mode 100644 index 0000000000..e344627455 --- /dev/null +++ b/Tests/RunCMake/UnityBuild/unitybuild_c_no_unity_build_group-check.cmake @@ -0,0 +1,5 @@ +set(unitybuild_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_a_c.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_group.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c_no_unity_build_group.cmake new file mode 100644 index 0000000000..7b26dc166e --- /dev/null +++ b/Tests/RunCMake/UnityBuild/unitybuild_c_no_unity_build_group.cmake @@ -0,0 +1,16 @@ +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}) + +#These should be ignored as UNITY_BUILD is off +set_target_properties(tgt PROPERTIES UNITY_BUILD_MODE GROUP) +set_source_files_properties(s1.c s2.c s3.c s4.c s5.c s6.c s7.c s8.c + PROPERTIES UNITY_GROUP "a" + ) diff --git a/Tests/RunCMake/UnityBuild/unitybuild_cxx_group-check.cmake b/Tests/RunCMake/UnityBuild/unitybuild_cxx_group-check.cmake new file mode 100644 index 0000000000..ecef3a3a7b --- /dev/null +++ b/Tests/RunCMake/UnityBuild/unitybuild_cxx_group-check.cmake @@ -0,0 +1,27 @@ +set(unitybuild_a_cxx "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_a_cxx.cxx") +if(NOT EXISTS "${unitybuild_a_cxx}") + set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_a_cxx} does not exist.") + return() +else() + #verify that odr2 is not part of this source set + file(STRINGS ${unitybuild_a_cxx} unitybuild_a_cxx_strings) + string(REGEX MATCH ".*#include.*odr2.cxx" matched_code ${unitybuild_a_cxx_strings}) + if(matched_code) + set(RunCMake_TEST_FAILED "Generated unity file includes un-expected ord2.cxx source file") + return() + endif() +endif() + +set(unitybuild_b_cxx "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_b_cxx.cxx") +if(NOT EXISTS "${unitybuild_b_cxx}") + set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_b_cxx} does not exist.") + return() +else() + #verify that odr1 is not part of this source set + file(STRINGS ${unitybuild_b_cxx} unitybuild_b_cxx_strings) + string(REGEX MATCH ".*#include.*odr1.cxx" matched_code ${unitybuild_b_cxx_strings}) + if(matched_code) + set(RunCMake_TEST_FAILED "Generated unity file includes un-expected ord1.cxx source file") + return() + endif() +endif() diff --git a/Tests/RunCMake/UnityBuild/unitybuild_cxx_group.cmake b/Tests/RunCMake/UnityBuild/unitybuild_cxx_group.cmake new file mode 100644 index 0000000000..98042896e2 --- /dev/null +++ b/Tests/RunCMake/UnityBuild/unitybuild_cxx_group.cmake @@ -0,0 +1,27 @@ +project(unitybuild_cxx CXX) + +set(srcs "") +foreach(s RANGE 1 4) + set(src "${CMAKE_CURRENT_BINARY_DIR}/s${s}.cxx") + file(WRITE "${src}" "int s${s}(void) { return 0; }\n") + list(APPEND srcs "${src}") +endforeach() + +foreach(s RANGE 1 2) + set(src "${CMAKE_CURRENT_BINARY_DIR}/odr${s}.cxx") + file(WRITE "${src}" "namespace odr { 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_MODE GROUP + ) + +set_source_files_properties(s1.cxx s2.cxx odr1.cxx + PROPERTIES UNITY_GROUP "a" + ) +set_source_files_properties(s3.cxx s4.cxx odr2.cxx + PROPERTIES UNITY_GROUP "b" + ) diff --git a/Tests/RunCMake/UnityBuild/unitybuild_invalid_mode-result.txt b/Tests/RunCMake/UnityBuild/unitybuild_invalid_mode-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/UnityBuild/unitybuild_invalid_mode-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/UnityBuild/unitybuild_invalid_mode-stderr.txt b/Tests/RunCMake/UnityBuild/unitybuild_invalid_mode-stderr.txt new file mode 100644 index 0000000000..b1b17a03c5 --- /dev/null +++ b/Tests/RunCMake/UnityBuild/unitybuild_invalid_mode-stderr.txt @@ -0,0 +1,5 @@ +^CMake Error in CMakeLists.txt: + Invalid UNITY_BUILD_MODE value of INVALID assigned to target tgt\. + Acceptable values are BATCH and GROUP\. +.* +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/UnityBuild/unitybuild_invalid_mode.cmake b/Tests/RunCMake/UnityBuild/unitybuild_invalid_mode.cmake new file mode 100644 index 0000000000..0212200d72 --- /dev/null +++ b/Tests/RunCMake/UnityBuild/unitybuild_invalid_mode.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 UNITY_BUILD_MODE INVALID) diff --git a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake index 06ccaaea31..93ef60343b 100644 --- a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake +++ b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake @@ -56,6 +56,7 @@ if (RunCMake_GENERATOR MATCHES "Visual Studio 1[0-4] 201[0-5]" OR run_cmake(UnityBuildPre2017) else() run_cmake(UnityBuildNative) + run_cmake(UnityBuildNativeGrouped) endif() run_cmake(VsDotnetTargetFramework) diff --git a/Tests/RunCMake/VS10Project/UnityBuildNativeGrouped-check.cmake b/Tests/RunCMake/VS10Project/UnityBuildNativeGrouped-check.cmake new file mode 100644 index 0000000000..d6380da469 --- /dev/null +++ b/Tests/RunCMake/VS10Project/UnityBuildNativeGrouped-check.cmake @@ -0,0 +1,56 @@ +set(unitybuild_c0 "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_poolA_c.c") +if(NOT EXISTS "${unitybuild_c0}") + set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_c0} does not exist.") + return() +endif() + +set(unitybuild_c1 "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_poolB_c.c") +if(NOT EXISTS "${unitybuild_c1}") + set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_c1} 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 "<EnableUnitySupport>true</EnableUnitySupport>") + set(have_unity_support ON) + endif() + + if (line MATCHES "<ClCompile Include=.*IncludeInUnityFile=\"false\" CustomUnityFile=\"true\"") + list(APPEND unity_source_lines ${line}) + endif() + + if (line MATCHES "<ClCompile Include=.*IncludeInUnityFile=\"true\" CustomUnityFile=\"true\"") + list(APPEND sources_list ${line}) + endif() +endforeach() + +if (NOT have_unity_support) + set(RunCMake_TEST_FAILED "Generated project should include the <EnableUnitySupport> block.") + return() +endif() + +string(REPLACE "\\" "/" unity_source_lines "${unity_source_lines}") +string(FIND "${unity_source_lines}" "CMakeFiles/tgt.dir/Unity/unity_poolA_c.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 'poolA'.") + return() +endif() +string(FIND "${unity_source_lines}" "CMakeFiles/tgt.dir/Unity/unity_poolB_c.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 'poolB'.") + return() +endif() + +list(LENGTH sources_list number_of_sources) +if(NOT number_of_sources EQUAL 7) + set(RunCMake_TEST_FAILED "Generated project doesn't include the expect number of files.") + return() +endif() diff --git a/Tests/RunCMake/VS10Project/UnityBuildNativeGrouped.cmake b/Tests/RunCMake/VS10Project/UnityBuildNativeGrouped.cmake new file mode 100644 index 0000000000..b740e3b4e0 --- /dev/null +++ b/Tests/RunCMake/VS10Project/UnityBuildNativeGrouped.cmake @@ -0,0 +1,20 @@ +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 UNITY_BUILD_MODE GROUP) + +set_source_files_properties(s1.c s2.c s3.c s4.c + PROPERTIES UNITY_GROUP "poolA" + ) + +set_source_files_properties(s5.c s6.c s7.c + PROPERTIES UNITY_GROUP "poolB" + ) diff --git a/Tests/RunCMake/VS10Project/UnityBuildPre2017Grouped-check.cmake b/Tests/RunCMake/VS10Project/UnityBuildPre2017Grouped-check.cmake new file mode 100644 index 0000000000..d9b8c01a0a --- /dev/null +++ b/Tests/RunCMake/VS10Project/UnityBuildPre2017Grouped-check.cmake @@ -0,0 +1,59 @@ +set(unitybuild_c0 "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_poolA.c") +if(NOT EXISTS "${unitybuild_c0}") + set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_c0} does not exist.") + return() +endif() + +set(unitybuild_c1 "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_poolB.c") +if(NOT EXISTS "${unitybuild_c1}") + set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_c1} 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 "<ClCompile Include=.*/>") + set(unity_source_line ${line}) + endif() + + if (line MATCHES "<ClCompile Include=\"[^\"]*\">") + string(REGEX MATCH "<ClCompile Include=\"([^\"]*)\">" source_file ${line}) + list(APPEND sources_list ${source_file}) + endif() + + if (line MATCHES "<ExcludedFromBuild.*</ExcludedFromBuild>") + 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_poolA.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() +string(FIND "${unity_source_line}" "CMakeFiles/tgt.dir/Unity/unity_poolB.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 7) + 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 28) + set(RunCMake_TEST_FAILED "Generated project doesn't exclude the source files for all configurations.") + return() +endif() diff --git a/Tests/RunCMake/VS10Project/UnityBuildPre2017Grouped.cmake b/Tests/RunCMake/VS10Project/UnityBuildPre2017Grouped.cmake new file mode 100644 index 0000000000..b740e3b4e0 --- /dev/null +++ b/Tests/RunCMake/VS10Project/UnityBuildPre2017Grouped.cmake @@ -0,0 +1,20 @@ +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 UNITY_BUILD_MODE GROUP) + +set_source_files_properties(s1.c s2.c s3.c s4.c + PROPERTIES UNITY_GROUP "poolA" + ) + +set_source_files_properties(s5.c s6.c s7.c + PROPERTIES UNITY_GROUP "poolB" + ) |