mirror of
https://github.com/Kitware/CMake.git
synced 2026-01-09 15:20:56 -06:00
VS: Add support for Visual Studio solution items
Files listed in the `VS_SOLUTION_ITEMS` directory property of a project directory are added as solution items in the 'Solution Items' solution directory. If `source_group` is applied to the files listed in `VS_SOLUTION_ITEMS`, solution groups matching the names of the source groups are created outside of the default 'Solution Items' group. If not items are placed into the default group, it is not created. Solution items added to subprojects are not included in the top-level project. Closes: #26409
This commit is contained in:
@@ -97,6 +97,7 @@ Properties on Directories
|
||||
/prop_dir/VARIABLES
|
||||
/prop_dir/VS_GLOBAL_SECTION_POST_section
|
||||
/prop_dir/VS_GLOBAL_SECTION_PRE_section
|
||||
/prop_dir/VS_SOLUTION_ITEMS
|
||||
/prop_dir/VS_STARTUP_PROJECT
|
||||
|
||||
.. _`Target Properties`:
|
||||
|
||||
19
Help/prop_dir/VS_SOLUTION_ITEMS.rst
Normal file
19
Help/prop_dir/VS_SOLUTION_ITEMS.rst
Normal file
@@ -0,0 +1,19 @@
|
||||
VS_SOLUTION_ITEMS
|
||||
-----------------
|
||||
|
||||
.. versionadded:: 3.32
|
||||
|
||||
Specify solution level items included in the generated Visual Studio solution.
|
||||
|
||||
The :ref:`Visual Studio Generators` create a ``.sln`` file for each directory
|
||||
whose ``CMakeLists.txt`` file calls the :command:`project` command. Append paths
|
||||
to this property in the same directory as the top-level :command:`project`
|
||||
command call (e.g. in the top-level ``CMakeLists.txt`` file) to specify files
|
||||
included in the corresponding solution file.
|
||||
|
||||
If a file specified in ``VS_SOLUTION_ITEMS`` matches a :command:`source_group`
|
||||
command call, the affected solution level items are placed in a hierarchy of
|
||||
solution level folders according to the name specified in that command.
|
||||
Otherwise the items are placed in a default solution level directory named
|
||||
``Solution Items``. This name matches the default directory name used by Visual
|
||||
Studio when attempting to add solution level items at the root of the solution.
|
||||
6
Help/release/dev/vs-solution-items.rst
Normal file
6
Help/release/dev/vs-solution-items.rst
Normal file
@@ -0,0 +1,6 @@
|
||||
vs-solution-items
|
||||
-----------------
|
||||
|
||||
* The :prop_dir:`VS_SOLUTION_ITEMS` directory property was added
|
||||
to tell :ref:`Visual Studio Generators` to attach files directly
|
||||
to the Solution (``.sln``).
|
||||
@@ -541,3 +541,56 @@ std::string cmGlobalVisualStudio14Generator::GetWindows10SDKVersion(
|
||||
// Return an empty string
|
||||
return std::string();
|
||||
}
|
||||
|
||||
void cmGlobalVisualStudio14Generator::AddSolutionItems(cmLocalGenerator* root)
|
||||
{
|
||||
cmValue n = root->GetMakefile()->GetProperty("VS_SOLUTION_ITEMS");
|
||||
if (cmNonempty(n)) {
|
||||
cmMakefile* makefile = root->GetMakefile();
|
||||
|
||||
std::vector<cmSourceGroup> sourceGroups = makefile->GetSourceGroups();
|
||||
|
||||
cmVisualStudioFolder* defaultFolder = nullptr;
|
||||
|
||||
std::vector<std::string> pathComponents = {
|
||||
makefile->GetCurrentSourceDirectory(),
|
||||
"",
|
||||
"",
|
||||
};
|
||||
|
||||
for (const std::string& relativePath : cmList(n)) {
|
||||
pathComponents[2] = relativePath;
|
||||
std::string fullPath = cmSystemTools::JoinPath(pathComponents);
|
||||
|
||||
cmSourceGroup* sg = makefile->FindSourceGroup(fullPath, sourceGroups);
|
||||
|
||||
cmVisualStudioFolder* folder = nullptr;
|
||||
if (!sg->GetFullName().empty()) {
|
||||
std::string folderPath = sg->GetFullName();
|
||||
// Source groups use '\' while solution folders use '/'.
|
||||
cmSystemTools::ReplaceString(folderPath, "\\", "/");
|
||||
folder = this->CreateSolutionFolders(folderPath);
|
||||
} else {
|
||||
// Lazily initialize the default solution items folder.
|
||||
if (defaultFolder == nullptr) {
|
||||
defaultFolder = this->CreateSolutionFolders("Solution Items");
|
||||
}
|
||||
folder = defaultFolder;
|
||||
}
|
||||
|
||||
folder->SolutionItems.insert(fullPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cmGlobalVisualStudio14Generator::WriteFolderSolutionItems(
|
||||
std::ostream& fout, const cmVisualStudioFolder& folder)
|
||||
{
|
||||
fout << "\tProjectSection(SolutionItems) = preProject\n";
|
||||
|
||||
for (const std::string& item : folder.SolutionItems) {
|
||||
fout << "\t\t" << item << " = " << item << "\n";
|
||||
}
|
||||
|
||||
fout << "\tEndProjectSection\n";
|
||||
}
|
||||
|
||||
@@ -67,6 +67,11 @@ protected:
|
||||
|
||||
std::string GetWindows10SDKVersion(cmMakefile* mf);
|
||||
|
||||
void AddSolutionItems(cmLocalGenerator* root) override;
|
||||
|
||||
void WriteFolderSolutionItems(std::ostream& fout,
|
||||
const cmVisualStudioFolder& folder) override;
|
||||
|
||||
private:
|
||||
class Factory;
|
||||
friend class Factory;
|
||||
|
||||
@@ -48,9 +48,10 @@ void cmGlobalVisualStudio71Generator::WriteSLNFile(
|
||||
std::ostringstream targetsSlnString;
|
||||
this->WriteTargetsToSolution(targetsSlnString, root, orderedProjectTargets);
|
||||
|
||||
this->AddSolutionItems(root);
|
||||
|
||||
// Generate folder specification.
|
||||
bool useFolderProperty = this->UseFolderProperty();
|
||||
if (useFolderProperty) {
|
||||
if (!this->VisualStudioFolders.empty()) {
|
||||
this->WriteFolders(fout);
|
||||
}
|
||||
|
||||
@@ -67,7 +68,7 @@ void cmGlobalVisualStudio71Generator::WriteSLNFile(
|
||||
this->WriteTargetConfigurations(fout, configs, orderedProjectTargets);
|
||||
fout << "\tEndGlobalSection\n";
|
||||
|
||||
if (useFolderProperty) {
|
||||
if (!this->VisualStudioFolders.empty()) {
|
||||
// Write out project folders
|
||||
fout << "\tGlobalSection(NestedProjects) = preSolution\n";
|
||||
this->WriteFoldersContent(fout);
|
||||
|
||||
@@ -481,7 +481,13 @@ void cmGlobalVisualStudio7Generator::WriteFolders(std::ostream& fout)
|
||||
std::string nameOnly = cmSystemTools::GetFilenameName(fullName);
|
||||
|
||||
fout << "Project(\"{" << guidProjectTypeFolder << "}\") = \"" << nameOnly
|
||||
<< "\", \"" << fullName << "\", \"{" << guid << "}\"\nEndProject\n";
|
||||
<< "\", \"" << fullName << "\", \"{" << guid << "}\"\n";
|
||||
|
||||
if (!iter.second.SolutionItems.empty()) {
|
||||
this->WriteFolderSolutionItems(fout, iter.second);
|
||||
}
|
||||
|
||||
fout << "EndProject\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ class BT;
|
||||
struct cmVisualStudioFolder
|
||||
{
|
||||
std::set<std::string> Projects;
|
||||
std::set<std::string> SolutionItems;
|
||||
};
|
||||
|
||||
/** \class cmGlobalVisualStudio7Generator
|
||||
@@ -185,6 +186,11 @@ protected:
|
||||
|
||||
virtual void WriteFolders(std::ostream& fout);
|
||||
virtual void WriteFoldersContent(std::ostream& fout);
|
||||
|
||||
virtual void AddSolutionItems(cmLocalGenerator* root) = 0;
|
||||
virtual void WriteFolderSolutionItems(
|
||||
std::ostream& fout, const cmVisualStudioFolder& folder) = 0;
|
||||
|
||||
std::map<std::string, cmVisualStudioFolder> VisualStudioFolders;
|
||||
|
||||
// Set during OutputSLNFile with the name of the current project.
|
||||
|
||||
351
Tests/RunCMake/VS10Project/SolutionItems-check.cmake
Normal file
351
Tests/RunCMake/VS10Project/SolutionItems-check.cmake
Normal file
@@ -0,0 +1,351 @@
|
||||
function(MapAppend map key value)
|
||||
list(APPEND "${map}_k" "${key}")
|
||||
list(APPEND "${map}_v" "${value}")
|
||||
|
||||
set("${map}_k" "${${map}_k}" PARENT_SCOPE)
|
||||
set("${map}_v" "${${map}_v}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(MapLength map out_variable)
|
||||
list(LENGTH "${map}_k" length)
|
||||
set("${out_variable}" "${length}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(MapFind map key out_variable)
|
||||
list(FIND "${map}_k" "${key}" index)
|
||||
if("${index}" LESS 0)
|
||||
unset("${out_variable}" PARENT_SCOPE)
|
||||
else()
|
||||
list(GET "${map}_v" "${index}" value)
|
||||
set("${out_variable}" "${value}" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
macro(MapPropagateToParentScope map)
|
||||
set("${map}_k" "${${map}_k}" PARENT_SCOPE)
|
||||
set("${map}_v" "${${map}_v}" PARENT_SCOPE)
|
||||
endmacro()
|
||||
|
||||
|
||||
function(ParseSln vcSlnFile)
|
||||
if(NOT EXISTS "${vcSlnFile}")
|
||||
set(RunCMake_TEST_FAILED "Solution file ${vcSlnFile} does not exist." PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(SCOPE "")
|
||||
|
||||
set(IN_SOLUTION_ITEMS FALSE)
|
||||
set(IN_NESTED_PROJECTS FALSE)
|
||||
|
||||
set(REGUID "\\{[0-9A-F-]+\\}")
|
||||
|
||||
file(STRINGS "${vcSlnFile}" lines)
|
||||
foreach(line IN LISTS lines)
|
||||
string(STRIP "${line}" line)
|
||||
|
||||
# Project(...)
|
||||
if(line MATCHES "Project\\(\"(${REGUID})\"\\) = \"([^\"]+)\", \"([^\"]+)\", \"(${REGUID})\"")
|
||||
if(NOT "${SCOPE}" STREQUAL "")
|
||||
set(RunCMake_TEST_FAILED "Improper nesting of Project" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
set(SCOPE "Project")
|
||||
|
||||
if("${CMAKE_MATCH_1}" STREQUAL "{2150E333-8FDC-42A3-9474-1A3956D46DE8}")
|
||||
set(GROUP_NAME "${CMAKE_MATCH_2}")
|
||||
|
||||
MapFind(GROUP_PATHS "${GROUP_NAME}" existing_path)
|
||||
if(DEFINED existing_path)
|
||||
set(RunCMake_TEST_FAILED "Duplicate solution items project '${GROUP_NAME}'" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
MapAppend(GROUP_PATHS "${GROUP_NAME}" "${CMAKE_MATCH_3}")
|
||||
MapAppend(GROUP_GUIDS "${GROUP_NAME}" "${CMAKE_MATCH_4}")
|
||||
endif()
|
||||
|
||||
# EndProject
|
||||
elseif(line STREQUAL "EndProject")
|
||||
if(NOT "${SCOPE}" STREQUAL "Project")
|
||||
set(RunCMake_TEST_FAILED "Improper nesting of EndProject" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
set(SCOPE "")
|
||||
|
||||
unset(GROUP_NAME)
|
||||
|
||||
# ProjectSection
|
||||
elseif(line MATCHES "ProjectSection\\(([a-zA-Z]+)\\) = ([a-zA-Z]+)")
|
||||
if(NOT "${SCOPE}" STREQUAL "Project")
|
||||
set(RunCMake_TEST_FAILED "Improper nesting of ProjectSection" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
set(SCOPE "ProjectSection")
|
||||
|
||||
if("${CMAKE_MATCH_1}" STREQUAL "SolutionItems")
|
||||
if(NOT "${CMAKE_MATCH_2}" STREQUAL "preProject")
|
||||
set(RunCMake_TEST_FAILED "SolutionItems must be preProject" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(IN_SOLUTION_ITEMS TRUE)
|
||||
endif()
|
||||
|
||||
# EndProjectSection
|
||||
elseif(line STREQUAL "EndProjectSection")
|
||||
if(NOT "${SCOPE}" STREQUAL "ProjectSection")
|
||||
set(RunCMake_TEST_FAILED "Improper nesting of EndProjectSection" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
set(SCOPE "Project")
|
||||
|
||||
set(IN_SOLUTION_ITEMS FALSE)
|
||||
|
||||
# Global
|
||||
elseif(line STREQUAL "Global")
|
||||
if(NOT "${SCOPE}" STREQUAL "")
|
||||
set(RunCMake_TEST_FAILED "Improper nesting of Global" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
set(SCOPE "Global")
|
||||
|
||||
# EndGlobal
|
||||
elseif(line STREQUAL "EndGlobal")
|
||||
if(NOT "${SCOPE}" STREQUAL "Global")
|
||||
set(RunCMake_TEST_FAILED "Improper nesting of EndGlobal" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
set(SCOPE "")
|
||||
|
||||
# GlobalSection
|
||||
elseif(line MATCHES "GlobalSection\\(([a-zA-Z]+)\\) = ([a-zA-Z]+)")
|
||||
if(NOT "${SCOPE}" STREQUAL "Global")
|
||||
set(RunCMake_TEST_FAILED "Improper nesting of GlobalSection" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
set(SCOPE "GlobalSection")
|
||||
|
||||
if("${CMAKE_MATCH_1}" STREQUAL "NestedProjects")
|
||||
if(NOT "${CMAKE_MATCH_2}" STREQUAL "preSolution")
|
||||
set(RunCMake_TEST_FAILED "NestedProjects must be preSolution" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(IN_NESTED_PROJECTS TRUE)
|
||||
endif()
|
||||
|
||||
# EndGlobalSection
|
||||
elseif(line STREQUAL "EndGlobalSection")
|
||||
if(NOT "${SCOPE}" STREQUAL "GlobalSection")
|
||||
set(RunCMake_TEST_FAILED "Improper nesting of EndGlobalSection" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
set(SCOPE "Global")
|
||||
|
||||
set(IN_NESTED_PROJECTS FALSE)
|
||||
|
||||
# .../solution-item-0-1.txt = .../solution-item-0-1.txt
|
||||
elseif(${IN_SOLUTION_ITEMS})
|
||||
if(NOT line MATCHES "([^=]+)=([^=]+)")
|
||||
set(RunCMake_TEST_FAILED "Invalid solution item paths 1" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
string(STRIP "${CMAKE_MATCH_1}" CMAKE_MATCH_1)
|
||||
string(STRIP "${CMAKE_MATCH_2}" CMAKE_MATCH_2)
|
||||
|
||||
if(NOT "${CMAKE_MATCH_1}" STREQUAL "${CMAKE_MATCH_2}")
|
||||
set(RunCMake_TEST_FAILED "Invalid solution item paths 2" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
cmake_path(GET CMAKE_MATCH_1 FILENAME filename)
|
||||
MapAppend(SOLUTION_ITEMS "${filename}" "${GROUP_NAME}")
|
||||
|
||||
# {1EB55F5E...} = {A11E84C6...}
|
||||
elseif(${IN_NESTED_PROJECTS})
|
||||
if(NOT line MATCHES "(${REGUID}) = (${REGUID})")
|
||||
set(RunCMake_TEST_FAILED "Invalid nested project guids" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
MapFind(PROJECT_PARENTS "${CMAKE_MATCH_1}" existing_parent)
|
||||
if(DEFINED existing_parent)
|
||||
set(RunCMake_TEST_FAILED "Duplicate nested project: '${CMAKE_MATCH_1}'" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
MapAppend(PROJECT_PARENTS "${CMAKE_MATCH_1}" "${CMAKE_MATCH_2}")
|
||||
|
||||
endif()
|
||||
|
||||
MapPropagateToParentScope(GROUP_PATHS)
|
||||
MapPropagateToParentScope(GROUP_GUIDS)
|
||||
MapPropagateToParentScope(PROJECT_PARENTS)
|
||||
MapPropagateToParentScope(SOLUTION_ITEMS)
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
|
||||
# Check the root solution:
|
||||
block()
|
||||
ParseSln("${RunCMake_TEST_BINARY_DIR}/SolutionItems.sln")
|
||||
|
||||
if(DEFINED RunCMake_TEST_FAILED)
|
||||
set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
|
||||
# Check group guids and nesting:
|
||||
|
||||
MapFind(GROUP_GUIDS "Solution Items" root_group_guid)
|
||||
if(NOT DEFINED root_group_guid)
|
||||
set(RunCMake_TEST_FAILED "Solution Items not found" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
MapFind(GROUP_PATHS "Solution Items" root_group_path)
|
||||
if(NOT "${root_group_path}" STREQUAL "Solution Items")
|
||||
set(RunCMake_TEST_FAILED "Invalid Solution Items path: '${root_group_path}'" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
MapFind(PROJECT_PARENTS "${root_group_guid}" root_group_parent_guid)
|
||||
if(DEFINED root_group_parent_guid)
|
||||
set(RunCMake_TEST_FAILED "Solution Items is nested" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
MapFind(GROUP_GUIDS "Outer Group" outer_group_guid)
|
||||
if(NOT DEFINED outer_group_guid)
|
||||
set(RunCMake_TEST_FAILED "Outer Group not found" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
MapFind(GROUP_PATHS "Outer Group" outer_group_path)
|
||||
if(NOT "${outer_group_path}" STREQUAL "Outer Group")
|
||||
set(RunCMake_TEST_FAILED "Invalid Outer Group path: '${outer_group_path}'" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
MapFind(PROJECT_PARENTS "${outer_group_guid}" outer_group_parent_guid)
|
||||
if(DEFINED outer_group_parent_guid)
|
||||
set(RunCMake_TEST_FAILED "Outer Group is nested" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
MapFind(GROUP_GUIDS "Inner Group" inner_group_guid)
|
||||
if(NOT DEFINED inner_group_guid)
|
||||
set(RunCMake_TEST_FAILED "Inner Group not found" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
MapFind(GROUP_PATHS "Inner Group" inner_group_path)
|
||||
if(NOT "${inner_group_path}" STREQUAL "Outer Group\\Inner Group")
|
||||
set(RunCMake_TEST_FAILED "Invalid Inner Group path: '${inner_group_path}'" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
MapFind(PROJECT_PARENTS "${inner_group_guid}" inner_group_parent_guid)
|
||||
if(NOT DEFINED inner_group_parent_guid)
|
||||
set(RunCMake_TEST_FAILED "Inner Group is not nested" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
if(NOT "${inner_group_parent_guid}" STREQUAL "${outer_group_guid}")
|
||||
set(RunCMake_TEST_FAILED "Inner Group is not nested within Outer Group" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
|
||||
# Check solution items and nesting:
|
||||
MapLength(SOLUTION_ITEMS solution_item_count)
|
||||
if(NOT "${solution_item_count}" EQUAL 4)
|
||||
set(RunCMake_TEST_FAILED "Unexpected number of solution items: ${solution_item_count}")
|
||||
return()
|
||||
endif()
|
||||
|
||||
MapFind(SOLUTION_ITEMS "solution-item-0-1.txt" group_name)
|
||||
if(NOT DEFINED group_name)
|
||||
set(RunCMake_TEST_FAILED "Solution item not found: solution-item-0-1.txt")
|
||||
return()
|
||||
endif()
|
||||
if(NOT "${group_name}" STREQUAL "Solution Items")
|
||||
set(RunCMake_TEST_FAILED "Invalid group for solution-item-0-1.txt: '${group_name}'")
|
||||
return()
|
||||
endif()
|
||||
|
||||
MapFind(SOLUTION_ITEMS "solution-item-1-1.txt" group_name)
|
||||
if(NOT DEFINED group_name)
|
||||
set(RunCMake_TEST_FAILED "Solution item not found: solution-item-1-1.txt")
|
||||
return()
|
||||
endif()
|
||||
if(NOT "${group_name}" STREQUAL "Outer Group")
|
||||
set(RunCMake_TEST_FAILED "Invalid group for solution-item-1-1.txt: '${group_name}'")
|
||||
return()
|
||||
endif()
|
||||
|
||||
MapFind(SOLUTION_ITEMS "solution-item-2-1.txt" group_name)
|
||||
if(NOT DEFINED group_name)
|
||||
set(RunCMake_TEST_FAILED "Solution item not found: solution-item-2-1.txt")
|
||||
return()
|
||||
endif()
|
||||
if(NOT "${group_name}" STREQUAL "Inner Group")
|
||||
set(RunCMake_TEST_FAILED "Invalid group for solution-item-2-1.txt: '${group_name}'")
|
||||
return()
|
||||
endif()
|
||||
|
||||
MapFind(SOLUTION_ITEMS "solution-item-2-2.txt" group_name)
|
||||
if(NOT DEFINED group_name)
|
||||
set(RunCMake_TEST_FAILED "Solution item not found: solution-item-2-2.txt")
|
||||
return()
|
||||
endif()
|
||||
if(NOT "${group_name}" STREQUAL "Inner Group")
|
||||
set(RunCMake_TEST_FAILED "Invalid group for solution-item-2-2.txt: '${group_name}'")
|
||||
return()
|
||||
endif()
|
||||
endblock()
|
||||
|
||||
|
||||
# Check the nested solution:
|
||||
block()
|
||||
ParseSln("${RunCMake_TEST_BINARY_DIR}/SolutionItems/SolutionItemsSubproject.sln")
|
||||
|
||||
if(DEFINED RunCMake_TEST_FAILED)
|
||||
set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
|
||||
# Check group guids and nesting:
|
||||
|
||||
MapFind(GROUP_GUIDS "Extraneous" root_group_guid)
|
||||
if(NOT DEFINED root_group_guid)
|
||||
set(RunCMake_TEST_FAILED "Extraneous not found" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
MapFind(GROUP_PATHS "Extraneous" root_group_path)
|
||||
if(NOT "${root_group_path}" STREQUAL "Extraneous")
|
||||
set(RunCMake_TEST_FAILED "Invalid Extraneous path: '${root_group_path}'" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
MapFind(PROJECT_PARENTS "${root_group_guid}" root_group_parent_guid)
|
||||
if(DEFINED root_group_parent_guid)
|
||||
set(RunCMake_TEST_FAILED "Extraneous is nested" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
|
||||
# Check solution items and nesting:
|
||||
|
||||
MapLength(SOLUTION_ITEMS solution_item_count)
|
||||
if(NOT "${solution_item_count}" EQUAL 1)
|
||||
set(RunCMake_TEST_FAILED "Unexpected number of solution items: ${solution_item_count}" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
MapFind(SOLUTION_ITEMS "extraneous.txt" group_name)
|
||||
if(NOT DEFINED group_name)
|
||||
set(RunCMake_TEST_FAILED "Solution item not found: extraneous.txt" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
if(NOT "${group_name}" STREQUAL "Extraneous")
|
||||
set(RunCMake_TEST_FAILED "Invalid group for extraneous.txt: '${group_name}'" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
endblock()
|
||||
4
Tests/RunCMake/VS10Project/SolutionItems.cmake
Normal file
4
Tests/RunCMake/VS10Project/SolutionItems.cmake
Normal file
@@ -0,0 +1,4 @@
|
||||
set_property(DIRECTORY APPEND PROPERTY VS_SOLUTION_ITEMS solution-item-0-1.txt solution-item-1-1.txt solution-item-2-1.txt solution-item-2-2.txt)
|
||||
source_group("Outer Group" FILES solution-item-1-1.txt)
|
||||
source_group("Outer Group/Inner Group" REGULAR_EXPRESSION "solution-item-2-[0-9]+\\.txt")
|
||||
add_subdirectory(SolutionItems)
|
||||
4
Tests/RunCMake/VS10Project/SolutionItems/CMakeLists.txt
Normal file
4
Tests/RunCMake/VS10Project/SolutionItems/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(SolutionItemsSubproject)
|
||||
set_property(DIRECTORY APPEND PROPERTY VS_SOLUTION_ITEMS extraneous.txt)
|
||||
source_group("Extraneous" REGULAR_EXPRESSION "[^.]+\\.txt")
|
||||
0
Tests/RunCMake/VS10Project/solution-item-0-1.txt
Normal file
0
Tests/RunCMake/VS10Project/solution-item-0-1.txt
Normal file
0
Tests/RunCMake/VS10Project/solution-item-1-1.txt
Normal file
0
Tests/RunCMake/VS10Project/solution-item-1-1.txt
Normal file
0
Tests/RunCMake/VS10Project/solution-item-2-1.txt
Normal file
0
Tests/RunCMake/VS10Project/solution-item-2-1.txt
Normal file
0
Tests/RunCMake/VS10Project/solution-item-2-2.txt
Normal file
0
Tests/RunCMake/VS10Project/solution-item-2-2.txt
Normal file
Reference in New Issue
Block a user