diff options
46 files changed, 781 insertions, 289 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 166b664..e6aaf60 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -829,7 +829,7 @@ if(NOT CMake_TEST_EXTERNAL_CMAKE) PATTERN "*.sh*" PERMISSIONS OWNER_READ OWNER_EXECUTE OWNER_WRITE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE - PATTERN "ExportImportList" + REGEX "/(ExportImportList|cpp)$" PERMISSIONS OWNER_READ OWNER_EXECUTE OWNER_WRITE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE diff --git a/CTestCustom.cmake.in b/CTestCustom.cmake.in index 622f054..5b78f2e 100644 --- a/CTestCustom.cmake.in +++ b/CTestCustom.cmake.in @@ -64,6 +64,7 @@ list(APPEND CTEST_CUSTOM_WARNING_EXCEPTION "ld: warning .*/libgcc.a archive's cputype" "ld: warning: ignoring file .*/libgcc.a, file was built for archive which is not the architecture being linked" "ld: warning: in .*/libgcc.a, file is not of required architecture" + "ld: warning: symbol .(deflate|inflate)_copyright. has differing sizes" # system libz and QtCore disagree "warning.*This version of Mac OS X is unsupported" "clang.*: warning: argument unused during compilation: .-g" "note: in expansion of macro" # diagnostic context note diff --git a/Help/command/source_group.rst b/Help/command/source_group.rst index 6623c98..5ae9e51 100644 --- a/Help/command/source_group.rst +++ b/Help/command/source_group.rst @@ -37,11 +37,13 @@ explicitly lists the file with ``FILES`` will be favored, if any. If no group explicitly lists the file, the *last* group whose regular expression matches the file will be favored. -The ``<name>`` of the group and ``<prefix>`` argument may contain backslashes -to specify subgroups: +The ``<name>`` of the group and ``<prefix>`` argument may contain forward +slashes or backslashes to specify subgroups. Backslashes need to be escaped +appropriately: .. code-block:: cmake + source_group(base/subdir ...) source_group(outer\\inner ...) source_group(TREE <root> PREFIX sources\\inc ...) diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index 9031e9c..4103806 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 0000000..ec6b0f6 --- /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 479802e..e140952 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 0000000..1ebab23 --- /dev/null +++ b/Help/prop_tgt/UNITY_BUILD_MODE.rst @@ -0,0 +1,58 @@ +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. + + Example usage: + + .. code-block:: cmake + + add_library(example_library + source1.cxx + source2.cxx + source3.cxx + source4.cxx) + + set_target_properties(example_library PROPERTIES + UNITY_BUILD_MODE BATCH + UNITY_BUILD_BATCH_SIZE 2 + ) + +``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. + + Example usage: + + .. code-block:: cmake + + add_library(example_library + source1.cxx + source2.cxx + source3.cxx + source4.cxx) + + set_target_properties(example_library PROPERTIES + UNITY_BUILD_MODE GROUP + ) + + set_source_files_properties(source1.cxx source2.cxx source3.cxx + PROPERTIES UNITY_GROUP "bucket1" + ) + set_source_files_properties(source4.cxx + PROPERTIES UNITY_GROUP "bucket2" + ) + +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 0000000..802de4a --- /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/Help/release/dev/source_group_forward_slashes.rst b/Help/release/dev/source_group_forward_slashes.rst new file mode 100644 index 0000000..fa0dfa9 --- /dev/null +++ b/Help/release/dev/source_group_forward_slashes.rst @@ -0,0 +1,5 @@ +source_group_forward_slashes +---------------------------- + +* The :command:`source_group` command now also recognizes forward slashes + as subgroup delimiters, not just backslashes. diff --git a/Modules/FindDoxygen.cmake b/Modules/FindDoxygen.cmake index faa03f9..184a9a2 100644 --- a/Modules/FindDoxygen.cmake +++ b/Modules/FindDoxygen.cmake @@ -999,9 +999,11 @@ doxygen_add_docs() for target ${targetName}") foreach(_item IN LISTS DOXYGEN_INPUT) get_filename_component(_abs_item "${_item}" ABSOLUTE BASE_DIR "${_args_WORKING_DIRECTORY}") - if(EXISTS "${_abs_item}" AND - NOT IS_DIRECTORY "${_abs_item}" AND - NOT IS_SYMLINK "${_abs_item}") + get_source_file_property(_isGenerated "${_abs_item}" GENERATED) + if(_isGenerated OR + (EXISTS "${_abs_item}" AND + NOT IS_DIRECTORY "${_abs_item}" AND + NOT IS_SYMLINK "${_abs_item}")) list(APPEND _sources "${_abs_item}") elseif(_args_USE_STAMP_FILE) message(FATAL_ERROR "Source does not exist or is not a file:\n" diff --git a/Modules/FindGTK2.cmake b/Modules/FindGTK2.cmake index 565763d..62f1614 100644 --- a/Modules/FindGTK2.cmake +++ b/Modules/FindGTK2.cmake @@ -695,11 +695,14 @@ foreach(_GTK2_component ${GTK2_FIND_COMPONENTS}) _GTK2_FIND_LIBRARY (CAIRO cairo false false) _GTK2_ADD_TARGET (CAIRO) + _GTK2_FIND_INCLUDE_DIR(HARFBUZZ hb.h) + _GTK2_FIND_LIBRARY (HARFBUZZ harfbuzz false false) + _GTK2_ADD_TARGET (HARFBUZZ) + _GTK2_FIND_INCLUDE_DIR(PANGO pango/pango.h) _GTK2_FIND_LIBRARY (PANGO pango false true) - _GTK2_ADD_TARGET (PANGO GTK2_DEPENDS gobject glib) - - _GTK2_FIND_INCLUDE_DIR(HARFBUZZ hb.h) + _GTK2_ADD_TARGET (PANGO GTK2_DEPENDS gobject glib + GTK2_OPTIONAL_DEPENDS harfbuzz) _GTK2_FIND_LIBRARY (PANGOCAIRO pangocairo false true) _GTK2_ADD_TARGET (PANGOCAIRO GTK2_DEPENDS pango cairo gobject glib) diff --git a/Modules/Platform/Windows-MSVC.cmake b/Modules/Platform/Windows-MSVC.cmake index 7ee501b..2476a33 100644 --- a/Modules/Platform/Windows-MSVC.cmake +++ b/Modules/Platform/Windows-MSVC.cmake @@ -331,13 +331,11 @@ macro(__windows_compiler_msvc lang) set(CMAKE_PCH_EXTENSION .pch) set(CMAKE_LINK_PCH ON) - if(MSVC_VERSION GREATER_EQUAL 1910) - # VS 2017 or greater - if (NOT ${CMAKE_${lang}_COMPILER_ID} STREQUAL "Clang") - set(CMAKE_PCH_PROLOGUE "#pragma system_header") - else() - set(CMAKE_PCH_PROLOGUE "#pragma clang system_header") - endif() + if (CMAKE_${lang}_COMPILER_ID STREQUAL "Clang") + set(CMAKE_PCH_PROLOGUE "#pragma clang system_header") + elseif(MSVC_VERSION GREATER_EQUAL 1913) + # At least MSVC toolet 14.13 from VS 2017 15.6 + set(CMAKE_PCH_PROLOGUE "#pragma system_header") endif() if (NOT ${CMAKE_${lang}_COMPILER_ID} STREQUAL "Clang") set(CMAKE_PCH_COPY_COMPILE_PDB ON) diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 81ceb4b..8dbfe33 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,7 +1,7 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 17) -set(CMake_VERSION_PATCH 20200510) +set(CMake_VERSION_PATCH 20200513) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 9aca775..f29c682 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -2758,6 +2758,120 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target) } } +namespace { + +inline void RegisterUnitySources(cmGeneratorTarget* target, cmSourceFile* sf, + std::string const& filename) +{ + target->AddSourceFileToUnityBatch(sf->ResolveFullPath()); + sf->SetProperty("UNITY_SOURCE_FILE", filename.c_str()); +} + +inline void IncludeFileInUnitySources(cmGeneratedFileStream& unity_file, + std::string const& sf_full_path, + cmProp beforeInclude, + cmProp afterInclude) +{ + if (beforeInclude) { + unity_file << *beforeInclude << "\n"; + } + + unity_file << "#include \"" << sf_full_path << "\"\n"; + + if (afterInclude) { + unity_file << *afterInclude << "\n"; + } +} + +std::vector<std::string> AddUnityFilesModeAuto( + cmGeneratorTarget* target, std::string const& lang, + std::vector<cmSourceFile*> const& filtered_sources, cmProp beforeInclude, + cmProp afterInclude, std::string const& filename_base, size_t batchSize) +{ + if (batchSize == 0) { + batchSize = filtered_sources.size(); + } + + std::vector<std::string> unity_files; + for (size_t itemsLeft = filtered_sources.size(), chunk, batch = 0; + itemsLeft > 0; itemsLeft -= chunk, ++batch) { + + chunk = std::min(itemsLeft, batchSize); + + std::string filename = cmStrCat(filename_base, "unity_", batch, + (lang == "C") ? "_c.c" : "_cxx.cxx"); + + const std::string filename_tmp = cmStrCat(filename, ".tmp"); + { + size_t begin = batch * batchSize; + size_t end = begin + chunk; + + cmGeneratedFileStream file( + filename_tmp, false, + target->GetGlobalGenerator()->GetMakefileEncoding()); + file << "/* generated by CMake */\n\n"; + + for (; begin != end; ++begin) { + cmSourceFile* sf = filtered_sources[begin]; + RegisterUnitySources(target, sf, filename); + IncludeFileInUnitySources(file, sf->ResolveFullPath(), beforeInclude, + afterInclude); + } + } + cmSystemTools::MoveFileIfDifferent(filename_tmp, filename); + unity_files.emplace_back(std::move(filename)); + } + 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) { if (!target->GetPropertyAsBool("UNITY_BUILD")) { @@ -2786,6 +2900,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; @@ -2800,53 +2915,28 @@ void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target) !sf->GetProperty("INCLUDE_DIRECTORIES"); }); - size_t batchSize = unityBatchSize; - if (unityBatchSize == 0) { - batchSize = filtered_sources.size(); + 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 (size_t itemsLeft = filtered_sources.size(), chunk, batch = 0; - itemsLeft > 0; itemsLeft -= chunk, ++batch) { - - chunk = std::min(itemsLeft, batchSize); - - std::string filename = cmStrCat(filename_base, "unity_", batch, - (lang == "C") ? "_c.c" : "_cxx.cxx"); - - const std::string filename_tmp = cmStrCat(filename, ".tmp"); - { - size_t begin = batch * batchSize; - size_t end = begin + chunk; - - cmGeneratedFileStream file( - filename_tmp, false, - this->GetGlobalGenerator()->GetMakefileEncoding()); - file << "/* generated by CMake */\n\n"; - - for (; begin != end; ++begin) { - cmSourceFile* sf = filtered_sources[begin]; - - target->AddSourceFileToUnityBatch(sf->ResolveFullPath()); - sf->SetProperty("UNITY_SOURCE_FILE", filename.c_str()); - - if (beforeInclude) { - file << *beforeInclude << "\n"; - } - - file << "#include \"" << sf->ResolveFullPath() << "\"\n"; - - if (afterInclude) { - file << *afterInclude << "\n"; - } - } - } - cmSystemTools::MoveFileIfDifferent(filename_tmp, filename); - - target->AddSource(filename, true); - - auto unity = this->Makefile->GetOrCreateSource(filename); + for (auto const& file : unity_files) { + auto unity = this->GetMakefile()->GetOrCreateSource(file); + target->AddSource(file, true); unity->SetProperty("SKIP_UNITY_BUILD_INCLUSION", "ON"); - unity->SetProperty("UNITY_SOURCE_FILE", filename.c_str()); + unity->SetProperty("UNITY_SOURCE_FILE", file.c_str()); } } } diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 58883b5..6f05d45 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -2404,11 +2404,11 @@ cmSourceGroup* cmMakefile::GetOrCreateSourceGroup( cmSourceGroup* cmMakefile::GetOrCreateSourceGroup(const std::string& name) { - const char* delimiter = this->GetDefinition("SOURCE_GROUP_DELIMITER"); - if (delimiter == nullptr) { - delimiter = "\\"; + const char* delimiters = this->GetDefinition("SOURCE_GROUP_DELIMITER"); + if (delimiters == nullptr) { + delimiters = "/\\"; } - return this->GetOrCreateSourceGroup(cmTokenize(name, delimiter)); + return this->GetOrCreateSourceGroup(cmTokenize(name, delimiters)); } /** diff --git a/Source/cmSetDirectoryPropertiesCommand.cxx b/Source/cmSetDirectoryPropertiesCommand.cxx index 35daca6..07ad246 100644 --- a/Source/cmSetDirectoryPropertiesCommand.cxx +++ b/Source/cmSetDirectoryPropertiesCommand.cxx @@ -5,12 +5,6 @@ #include "cmExecutionStatus.h" #include "cmMakefile.h" -namespace { -bool RunCommand(cmMakefile& mf, std::vector<std::string>::const_iterator ait, - std::vector<std::string>::const_iterator aitend, - std::string& errors); -} - // cmSetDirectoryPropertiesCommand bool cmSetDirectoryPropertiesCommand(std::vector<std::string> const& args, cmExecutionStatus& status) @@ -20,38 +14,26 @@ bool cmSetDirectoryPropertiesCommand(std::vector<std::string> const& args, return false; } - std::string errors; - bool ret = - RunCommand(status.GetMakefile(), args.begin() + 1, args.end(), errors); - if (!ret) { - status.SetError(errors); + // PROPERTIES followed by prop value pairs + if (args.size() % 2 != 1) { + status.SetError("Wrong number of arguments"); + return false; } - return ret; -} -namespace { -bool RunCommand(cmMakefile& mf, std::vector<std::string>::const_iterator ait, - std::vector<std::string>::const_iterator aitend, - std::string& errors) -{ - for (; ait != aitend; ait += 2) { - if (ait + 1 == aitend) { - errors = "Wrong number of arguments"; - return false; - } - const std::string& prop = *ait; - const std::string& value = *(ait + 1); + for (auto iter = args.begin() + 1; iter != args.end(); iter += 2) { + const std::string& prop = *iter; if (prop == "VARIABLES") { - errors = "Variables and cache variables should be set using SET command"; + status.SetError( + "Variables and cache variables should be set using SET command"); return false; } if (prop == "MACROS") { - errors = "Commands and macros cannot be set using SET_CMAKE_PROPERTIES"; + status.SetError( + "Commands and macros cannot be set using SET_CMAKE_PROPERTIES"); return false; } - mf.SetProperty(prop, value.c_str()); + status.GetMakefile().SetProperty(prop, (iter + 1)->c_str()); } return true; } -} diff --git a/Source/cmSetSourceFilesPropertiesCommand.cxx b/Source/cmSetSourceFilesPropertiesCommand.cxx index 7ff604b..7a53a1d 100644 --- a/Source/cmSetSourceFilesPropertiesCommand.cxx +++ b/Source/cmSetSourceFilesPropertiesCommand.cxx @@ -2,18 +2,17 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmSetSourceFilesPropertiesCommand.h" +#include <algorithm> +#include <iterator> + +#include <cm/string_view> +#include <cmext/algorithm> + #include "cmExecutionStatus.h" #include "cmMakefile.h" #include "cmSourceFile.h" #include "cmStringAlgorithms.h" -static bool RunCommand(cmMakefile* mf, - std::vector<std::string>::const_iterator filebeg, - std::vector<std::string>::const_iterator fileend, - std::vector<std::string>::const_iterator propbeg, - std::vector<std::string>::const_iterator propend, - std::string& errors); - bool cmSetSourceFilesPropertiesCommand(std::vector<std::string> const& args, cmExecutionStatus& status) { @@ -23,108 +22,64 @@ bool cmSetSourceFilesPropertiesCommand(std::vector<std::string> const& args, } // break the arguments into source file names and properties - int numFiles = 0; - std::vector<std::string>::const_iterator j; - j = args.begin(); // old style allows for specifier before PROPERTIES keyword - while (j != args.end() && *j != "ABSTRACT" && *j != "WRAP_EXCLUDE" && - *j != "GENERATED" && *j != "COMPILE_FLAGS" && - *j != "OBJECT_DEPENDS" && *j != "PROPERTIES") { - numFiles++; - ++j; - } + static const cm::string_view propNames[] = { + "ABSTRACT", "GENERATED", "WRAP_EXCLUDE", + "COMPILE_FLAGS", "OBJECT_DEPENDS", "PROPERTIES" + }; + auto propsBegin = std::find_first_of( + args.begin(), args.end(), std::begin(propNames), std::end(propNames)); - cmMakefile& mf = status.GetMakefile(); - - // now call the worker function - std::string errors; - bool ret = RunCommand(&mf, args.begin(), args.begin() + numFiles, - args.begin() + numFiles, args.end(), errors); - if (!ret) { - status.SetError(errors); - } - return ret; -} - -static bool RunCommand(cmMakefile* mf, - std::vector<std::string>::const_iterator filebeg, - std::vector<std::string>::const_iterator fileend, - std::vector<std::string>::const_iterator propbeg, - std::vector<std::string>::const_iterator propend, - std::string& errors) -{ std::vector<std::string> propertyPairs; - bool generated = false; - std::vector<std::string>::const_iterator j; // build the property pairs - for (j = propbeg; j != propend; ++j) { - // old style allows for specifier before PROPERTIES keyword - if (*j == "ABSTRACT") { - propertyPairs.emplace_back("ABSTRACT"); - propertyPairs.emplace_back("1"); - } else if (*j == "WRAP_EXCLUDE") { - propertyPairs.emplace_back("WRAP_EXCLUDE"); - propertyPairs.emplace_back("1"); - } else if (*j == "GENERATED") { - generated = true; - propertyPairs.emplace_back("GENERATED"); + for (auto j = propsBegin; j != args.end(); ++j) { + // consume old style options + if (*j == "ABSTRACT" || *j == "GENERATED" || *j == "WRAP_EXCLUDE") { + propertyPairs.emplace_back(*j); propertyPairs.emplace_back("1"); } else if (*j == "COMPILE_FLAGS") { propertyPairs.emplace_back("COMPILE_FLAGS"); ++j; - if (j == propend) { - errors = "called with incorrect number of arguments " - "COMPILE_FLAGS with no flags"; + if (j == args.end()) { + status.SetError("called with incorrect number of arguments " + "COMPILE_FLAGS with no flags"); return false; } propertyPairs.push_back(*j); } else if (*j == "OBJECT_DEPENDS") { propertyPairs.emplace_back("OBJECT_DEPENDS"); ++j; - if (j == propend) { - errors = "called with incorrect number of arguments " - "OBJECT_DEPENDS with no dependencies"; + if (j == args.end()) { + status.SetError("called with incorrect number of arguments " + "OBJECT_DEPENDS with no dependencies"); return false; } propertyPairs.push_back(*j); } else if (*j == "PROPERTIES") { - // now loop through the rest of the arguments, new style - ++j; - while (j != propend) { - propertyPairs.push_back(*j); - if (*j == "GENERATED") { - ++j; - if (j != propend && cmIsOn(*j)) { - generated = true; - } - } else { - ++j; - } - if (j == propend) { - errors = "called with incorrect number of arguments."; - return false; - } - propertyPairs.push_back(*j); - ++j; + // PROPERTIES is followed by new style prop value pairs + cmStringRange newStyleProps{ j + 1, args.end() }; + if (newStyleProps.size() % 2 != 0) { + status.SetError("called with incorrect number of arguments."); + return false; } - // break out of the loop because j is already == end + // set newStyleProps as is. + cm::append(propertyPairs, newStyleProps); + // break out of the loop. break; } else { - errors = "called with illegal arguments, maybe missing a " - "PROPERTIES specifier?"; + status.SetError("called with illegal arguments, maybe missing a " + "PROPERTIES specifier?"); return false; } } - // now loop over all the files - for (j = filebeg; j != fileend; ++j) { + // loop over all the files + for (const std::string& sfname : cmStringRange{ args.begin(), propsBegin }) { // get the source file - cmSourceFile* sf = mf->GetOrCreateSource(*j, generated); - if (sf) { - // now loop through all the props and set them - unsigned int k; - for (k = 0; k < propertyPairs.size(); k = k + 2) { - sf->SetProperty(propertyPairs[k], propertyPairs[k + 1].c_str()); + if (cmSourceFile* sf = status.GetMakefile().GetOrCreateSource(sfname)) { + // loop through the props and set them + for (auto k = propertyPairs.begin(); k != propertyPairs.end(); k += 2) { + sf->SetProperty(*k, (k + 1)->c_str()); } } } diff --git a/Source/cmSetTargetPropertiesCommand.cxx b/Source/cmSetTargetPropertiesCommand.cxx index cd0fa40..bdc84af 100644 --- a/Source/cmSetTargetPropertiesCommand.cxx +++ b/Source/cmSetTargetPropertiesCommand.cxx @@ -2,19 +2,14 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmSetTargetPropertiesCommand.h" +#include <algorithm> #include <iterator> -#include <cmext/algorithm> - #include "cmExecutionStatus.h" #include "cmMakefile.h" #include "cmStringAlgorithms.h" #include "cmTarget.h" -static bool SetOneTarget(const std::string& tname, - std::vector<std::string>& propertyPairs, - cmMakefile* mf); - bool cmSetTargetPropertiesCommand(std::vector<std::string> const& args, cmExecutionStatus& status) { @@ -23,61 +18,38 @@ bool cmSetTargetPropertiesCommand(std::vector<std::string> const& args, return false; } - // first collect up the list of files - std::vector<std::string> propertyPairs; - int numFiles = 0; - for (auto j = args.begin(); j != args.end(); ++j) { - if (*j == "PROPERTIES") { - // now loop through the rest of the arguments, new style - ++j; - if (std::distance(j, args.end()) % 2 != 0) { - status.SetError("called with incorrect number of arguments."); - return false; - } - cm::append(propertyPairs, j, args.end()); - break; - } - numFiles++; + // first identify the properties arguments + auto propsIter = std::find(args.begin(), args.end(), "PROPERTIES"); + if (propsIter == args.end() || propsIter + 1 == args.end()) { + status.SetError("called with illegal arguments, maybe missing a " + "PROPERTIES specifier?"); + return false; } - if (propertyPairs.empty()) { - status.SetError("called with illegal arguments, maybe missing " - "a PROPERTIES specifier?"); + + if (std::distance(propsIter, args.end()) % 2 != 1) { + status.SetError("called with incorrect number of arguments."); return false; } cmMakefile& mf = status.GetMakefile(); - // now loop over all the targets - for (int i = 0; i < numFiles; ++i) { - if (mf.IsAlias(args[i])) { + // loop over all the targets + for (const std::string& tname : cmStringRange{ args.begin(), propsIter }) { + if (mf.IsAlias(tname)) { status.SetError("can not be used on an ALIAS target."); return false; } - bool ret = SetOneTarget(args[i], propertyPairs, &mf); - if (!ret) { + if (cmTarget* target = mf.FindTargetToUse(tname)) { + // loop through all the props and set them + for (auto k = propsIter + 1; k != args.end(); k += 2) { + target->SetProperty(*k, *(k + 1)); + target->CheckProperty(*k, &mf); + } + } else { status.SetError( - cmStrCat("Can not find target to add properties to: ", args[i])); + cmStrCat("Can not find target to add properties to: ", tname)); return false; } } return true; } - -static bool SetOneTarget(const std::string& tname, - std::vector<std::string>& propertyPairs, - cmMakefile* mf) -{ - if (cmTarget* target = mf->FindTargetToUse(tname)) { - // now loop through all the props and set them - unsigned int k; - for (k = 0; k < propertyPairs.size(); k = k + 2) { - target->SetProperty(propertyPairs[k], propertyPairs[k + 1]); - target->CheckProperty(propertyPairs[k], mf); - } - } - // if file is not already in the makefile, then add it - else { - return false; - } - return true; -} diff --git a/Source/cmSetTestsPropertiesCommand.cxx b/Source/cmSetTestsPropertiesCommand.cxx index 2e7aeca..c4bff76 100644 --- a/Source/cmSetTestsPropertiesCommand.cxx +++ b/Source/cmSetTestsPropertiesCommand.cxx @@ -2,19 +2,14 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmSetTestsPropertiesCommand.h" +#include <algorithm> #include <iterator> -#include <cmext/algorithm> - #include "cmExecutionStatus.h" #include "cmMakefile.h" #include "cmStringAlgorithms.h" #include "cmTest.h" -static bool SetOneTest(const std::string& tname, - std::vector<std::string>& propertyPairs, cmMakefile* mf, - std::string& errors); - bool cmSetTestsPropertiesCommand(std::vector<std::string> const& args, cmExecutionStatus& status) { @@ -23,61 +18,33 @@ bool cmSetTestsPropertiesCommand(std::vector<std::string> const& args, return false; } - cmMakefile& mf = status.GetMakefile(); - - // first collect up the list of files - std::vector<std::string> propertyPairs; - int numFiles = 0; - std::vector<std::string>::const_iterator j; - for (j = args.begin(); j != args.end(); ++j) { - if (*j == "PROPERTIES") { - // now loop through the rest of the arguments, new style - ++j; - if (std::distance(j, args.end()) % 2 != 0) { - status.SetError("called with incorrect number of arguments."); - return false; - } - cm::append(propertyPairs, j, args.end()); - break; - } - numFiles++; - } - if (propertyPairs.empty()) { - status.SetError("called with illegal arguments, maybe " - "missing a PROPERTIES specifier?"); + // first identify the properties arguments + auto propsIter = std::find(args.begin(), args.end(), "PROPERTIES"); + if (propsIter == args.end() || propsIter + 1 == args.end()) { + status.SetError("called with illegal arguments, maybe missing a " + "PROPERTIES specifier?"); return false; } - // now loop over all the targets - int i; - for (i = 0; i < numFiles; ++i) { - std::string errors; - bool ret = SetOneTest(args[i], propertyPairs, &mf, errors); - if (!ret) { - status.SetError(errors); - return ret; - } + if (std::distance(propsIter, args.end()) % 2 != 1) { + status.SetError("called with incorrect number of arguments."); + return false; } - return true; -} - -static bool SetOneTest(const std::string& tname, - std::vector<std::string>& propertyPairs, cmMakefile* mf, - std::string& errors) -{ - if (cmTest* test = mf->GetTest(tname)) { - // now loop through all the props and set them - unsigned int k; - for (k = 0; k < propertyPairs.size(); k = k + 2) { - if (!propertyPairs[k].empty()) { - test->SetProperty(propertyPairs[k], propertyPairs[k + 1].c_str()); + // loop over all the tests + for (const std::string& tname : cmStringRange{ args.begin(), propsIter }) { + if (cmTest* test = status.GetMakefile().GetTest(tname)) { + // loop through all the props and set them + for (auto k = propsIter + 1; k != args.end(); k += 2) { + if (!k->empty()) { + test->SetProperty(*k, (k + 1)->c_str()); + } } + } else { + status.SetError( + cmStrCat("Can not find test to add properties to: ", tname)); + return false; } - } else { - errors = cmStrCat("Can not find test to add properties to: ", tname); - return false; } - return true; } diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index a776398..d43fbe5 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/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 2b20a00..93c09fe 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -2376,7 +2376,7 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( pchOptions = this->GeneratorTarget->GetPchUseCompileOptions(config, lang); } - customAndPchOptions += pchOptions; + customAndPchOptions = cmStrCat(customAndPchOptions, ';', pchOptions); } // if we have flags or defines for this config then diff --git a/Tests/FindDoxygen/StampFile/CMakeLists.txt b/Tests/FindDoxygen/StampFile/CMakeLists.txt index 2d06540..ed2bfbb 100644 --- a/Tests/FindDoxygen/StampFile/CMakeLists.txt +++ b/Tests/FindDoxygen/StampFile/CMakeLists.txt @@ -3,22 +3,41 @@ project(TestFindDoxygen VERSION 1.0 LANGUAGES NONE) find_package(Doxygen REQUIRED) +set(DOXYGEN_OUTPUT_DIRECTORY noFiles) doxygen_add_docs(docsWithoutFilesWithStamp USE_STAMP_FILE) if(NOT EXISTS "${PROJECT_BINARY_DIR}/Doxyfile.docsWithoutFilesWithStamp") - message(FATAL_ERROR "Missing generated file: Doxyfile.docsWithoutFilesWithStamp") + message(FATAL_ERROR "Missing generated file: Doxyfile.docsWithoutFilesWithStamp") endif() if(NOT TARGET docsWithoutFilesWithStamp) - message(FATAL_ERROR "Target docsWithoutFilesWithStamp not created") + message(FATAL_ERROR "Target docsWithoutFilesWithStamp not created") endif() +set(DOXYGEN_OUTPUT_DIRECTORY withFiles) doxygen_add_docs(docsWithFilesWithStamp main.cpp main2.cpp USE_STAMP_FILE) if(NOT EXISTS "${PROJECT_BINARY_DIR}/Doxyfile.docsWithFilesWithStamp") - message(FATAL_ERROR "Missing generated file: Doxyfile.docsWithFilesWithStamp") + message(FATAL_ERROR "Missing generated file: Doxyfile.docsWithFilesWithStamp") endif() if(NOT TARGET docsWithFilesWithStamp) - message(FATAL_ERROR "Target docsWithFilesWithStamp not created") + message(FATAL_ERROR "Target docsWithFilesWithStamp not created") endif() +# Confirm that doxygen_add_docs() doesn't cause a fatal error if given a +# source file that is generated at build time +file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/genDox.cpp) +add_custom_command(OUTPUT genDox.cpp + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/main2.cpp genDox.cpp + DEPENDS main2.cpp +) +set(DOXYGEN_OUTPUT_DIRECTORY withGenFiles) +doxygen_add_docs(docsWithGenFilesWithStamp + main.cpp + ${CMAKE_CURRENT_BINARY_DIR}/genDox.cpp + USE_STAMP_FILE +) add_custom_target(allDocTargets) -add_dependencies(allDocTargets docsWithoutFilesWithStamp docsWithFilesWithStamp) +add_dependencies(allDocTargets + docsWithoutFilesWithStamp + docsWithFilesWithStamp + docsWithGenFilesWithStamp +) diff --git a/Tests/RunCMake/PrecompileHeaders/PchInterface.cmake b/Tests/RunCMake/PrecompileHeaders/PchInterface.cmake index a1e0792..aab20d8 100644 --- a/Tests/RunCMake/PrecompileHeaders/PchInterface.cmake +++ b/Tests/RunCMake/PrecompileHeaders/PchInterface.cmake @@ -9,6 +9,9 @@ target_precompile_headers(foo PUBLIC <stdio.h> \"string.h\" ) +if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") + set_property(SOURCE foo.c APPEND PROPERTY COMPILE_OPTIONS "-WX-") +endif() add_library(bar INTERFACE) target_include_directories(bar INTERFACE include) diff --git a/Tests/RunCMake/UnityBuild/RunCMakeTest.cmake b/Tests/RunCMake/UnityBuild/RunCMakeTest.cmake index 24daa64..9ba3c85 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 0000000..d5813c6 --- /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 0000000..b027682 --- /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 0000000..7bf3f4b --- /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 0000000..024286d --- /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 0000000..33873b6 --- /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 0000000..0b9ea15 --- /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 0000000..1fa17f3 --- /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 0000000..e344627 --- /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 0000000..7b26dc1 --- /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 0000000..ecef3a3 --- /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 0000000..9804289 --- /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 0000000..d00491f --- /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 0000000..b1b17a0 --- /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 0000000..0212200 --- /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 06ccaae..93ef603 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 0000000..d6380da --- /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 0000000..b740e3b --- /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 0000000..d9b8c01 --- /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 0000000..b740e3b --- /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" + ) diff --git a/Tests/SourceGroups/CMakeLists.txt b/Tests/SourceGroups/CMakeLists.txt index a5740bb..d726395 100644 --- a/Tests/SourceGroups/CMakeLists.txt +++ b/Tests/SourceGroups/CMakeLists.txt @@ -30,6 +30,9 @@ source_group(Base\\Sub1\\Base FILES bar.c) # a group without files, is currently not created source_group(EmptyGroup) +# Forward slashes can be delimiters too +source_group(Base/Nested FILES nested.c) + set(root ${CMAKE_CURRENT_SOURCE_DIR}) set(tree_files_without_prefix ${root}/sub1/tree_bar.c @@ -58,4 +61,5 @@ source_group(PREFIX "" FILES ${tree_files_with_empty_prefix} TREE ${root}) add_executable(SourceGroups main.c bar.c foo.c sub1/foo.c sub1/foobar.c baz.c ${tree_files_with_prefix} ${tree_files_without_prefix} - ${tree_files_with_empty_prefix} README.txt) + ${tree_files_with_empty_prefix} README.txt + nested.c) diff --git a/Tests/SourceGroups/main.c b/Tests/SourceGroups/main.c index 87225f5..f646b49 100644 --- a/Tests/SourceGroups/main.c +++ b/Tests/SourceGroups/main.c @@ -12,6 +12,7 @@ extern int tree_empty_prefix_bar(void); extern int tree_bar(void); extern int tree_foobar(void); extern int tree_baz(void); +extern int nested(void); int main() { @@ -23,5 +24,8 @@ int main() "tree_empty_prefix_bar: %d\n", tree_prefix_foo(), tree_prefix_bar(), tree_bar(), tree_foobar(), tree_baz(), tree_empty_prefix_foo(), tree_empty_prefix_bar()); + + printf("nested: %d\n", nested()); + return 0; } diff --git a/Tests/SourceGroups/nested.c b/Tests/SourceGroups/nested.c new file mode 100644 index 0000000..4e31480 --- /dev/null +++ b/Tests/SourceGroups/nested.c @@ -0,0 +1,4 @@ +int nested(void) +{ + return 123; +} |