diff --git a/Help/command/target_sources.rst b/Help/command/target_sources.rst index e48211784a..5e35eaed5a 100644 --- a/Help/command/target_sources.rst +++ b/Help/command/target_sources.rst @@ -91,7 +91,8 @@ Each ``target_sources(FILE_SET)`` entry starts with ``INTERFACE``, ``PUBLIC``, o ``FILE_SET `` A string representing the name of the file set to create or add to. This must - not start with a capital letter, unless its name is ``HEADERS``. + contain only numbers, letters, and underscores, and must not start with a + capital letter or underscore, unless its name is ``HEADERS``. ``TYPE `` diff --git a/Source/cmFileSet.cxx b/Source/cmFileSet.cxx index 08d56ba1aa..2c06dc6f67 100644 --- a/Source/cmFileSet.cxx +++ b/Source/cmFileSet.cxx @@ -7,6 +7,8 @@ #include #include +#include "cmsys/RegularExpression.hxx" + #include "cmGeneratorExpression.h" #include "cmListFileCache.h" #include "cmLocalGenerator.h" @@ -149,3 +151,11 @@ void cmFileSet::EvaluateFileEntry( filesPerDir[relDir].push_back(file); } } + +bool cmFileSet::IsValidName(const std::string& name) +{ + static const cmsys::RegularExpression regex("^[a-z0-9][a-zA-Z0-9_]*$"); + + cmsys::RegularExpressionMatch match; + return regex.find(name.c_str(), match); +} diff --git a/Source/cmFileSet.h b/Source/cmFileSet.h index 5ee4a98bae..3aad75f9fd 100644 --- a/Source/cmFileSet.h +++ b/Source/cmFileSet.h @@ -56,6 +56,8 @@ public: const cmGeneratorTarget* target, cmGeneratorExpressionDAGChecker* dagChecker = nullptr) const; + static bool IsValidName(const std::string& name); + private: std::string Name; std::string Type; diff --git a/Source/cmTargetSourcesCommand.cxx b/Source/cmTargetSourcesCommand.cxx index b425acbc7f..954fbb5180 100644 --- a/Source/cmTargetSourcesCommand.cxx +++ b/Source/cmTargetSourcesCommand.cxx @@ -215,9 +215,10 @@ bool TargetSourcesImpl::HandleFileSetMode( auto fileSet = this->Target->GetOrCreateFileSet(args.FileSet, type); if (fileSet.second) { if (!isDefault) { - if (args.FileSet[0] >= 'A' && args.FileSet[0] <= 'Z') { - this->SetError( - "Non-default file set name must not start with a capital letter"); + if (!cmFileSet::IsValidName(args.FileSet)) { + this->SetError("Non-default file set name must contain only letters, " + "numbers, and underscores, and must not start with a " + "capital letter or underscore"); return false; } } diff --git a/Tests/RunCMake/target_sources/FileSetBadName-result.txt b/Tests/RunCMake/target_sources/FileSetBadName-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/target_sources/FileSetBadName-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/target_sources/FileSetBadName-stderr.txt b/Tests/RunCMake/target_sources/FileSetBadName-stderr.txt new file mode 100644 index 0000000000..a0b8054f87 --- /dev/null +++ b/Tests/RunCMake/target_sources/FileSetBadName-stderr.txt @@ -0,0 +1,6 @@ +^CMake Error at FileSetBadName\.cmake:[0-9]+ \(target_sources\): + target_sources Non-default file set name must contain only letters, + numbers, and underscores, and must not start with a capital letter or + underscore +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/target_sources/FileSetBadName.cmake b/Tests/RunCMake/target_sources/FileSetBadName.cmake new file mode 100644 index 0000000000..325843f935 --- /dev/null +++ b/Tests/RunCMake/target_sources/FileSetBadName.cmake @@ -0,0 +1,4 @@ +enable_language(C) + +add_library(lib1 STATIC empty.c) +target_sources(lib1 INTERFACE FILE_SET a+ TYPE HEADERS) diff --git a/Tests/RunCMake/target_sources/RunCMakeTest.cmake b/Tests/RunCMake/target_sources/RunCMakeTest.cmake index da9944d7db..d23bce19f1 100644 --- a/Tests/RunCMake/target_sources/RunCMakeTest.cmake +++ b/Tests/RunCMake/target_sources/RunCMakeTest.cmake @@ -39,6 +39,7 @@ run_cmake(FileSetNoExistInterface) run_cmake(FileSetNoExistInstall) run_cmake(FileSetDirectories) run_cmake(FileSetCustomTarget) +run_cmake(FileSetBadName) set(RunCMake_TEST_OPTIONS -DCMAKE_POLICY_DEFAULT_CMP0115=NEW) run_cmake(FileSetFileNoExist)