How to set Visual Studio Filters for nested sub directory using cmake
Solution 1:
There are several ready to use or adaptable solutions out there to mimic a Source Tree behavior like in Eclipse with CMake for Visual Studio (e.g. ADD_SRC_SUBFOLDER DESTINATION_SRCS
from Zobra or GroupSources from Luca).
Here is my reduced version for your use case:
cmake_minimum_required(VERSION 2.8.10)
project(Main CXX)
set(
source_list
"File.cpp"
"File.hpp"
"Dir/File1.cpp"
"Dir/File1.hpp"
"Dir/File2.cpp"
"Dir/File2.hpp"
)
add_executable(Main ${source_list})
foreach(source IN LISTS source_list)
get_filename_component(source_path "${source}" PATH)
string(REPLACE "/" "\\" source_path_msvc "${source_path}")
source_group("${source_path_msvc}" FILES "${source}")
endforeach()
See the documentation of source_group()
that you have to give the sub-directories with double backslashes.
For the reason why I replaced your file(GLOB ...)
with a dedicated list of all source files I like to quote from CMake's file()
command documentation:
We do not recommend using
GLOB
to collect a list of source files from your source tree. If no CMakeLists.txt file changes when a source is added or removed then the generated build system cannot know when to ask CMake to regenerate.
And here is my fail-safe version (that checks for absolute paths) to be used as a function:
function(assign_source_group)
foreach(_source IN ITEMS ${ARGN})
if (IS_ABSOLUTE "${_source}")
file(RELATIVE_PATH _source_rel "${CMAKE_CURRENT_SOURCE_DIR}" "${_source}")
else()
set(_source_rel "${_source}")
endif()
get_filename_component(_source_path "${_source_rel}" PATH)
string(REPLACE "/" "\\" _source_path_msvc "${_source_path}")
source_group("${_source_path_msvc}" FILES "${_source}")
endforeach()
endfunction(assign_source_group)
Which you would call in the example with
assign_source_group(${source_list})
Solution 2:
As of CMake 3.8, the source_group
command offers a TREE
argument to recursively search the files paths of your sources, and structures the source groups to match your file system structure. Now, this offers a much cleaner solution:
project(Main)
set(SOURCE_LIST
"File.cpp"
"File.hpp"
"Dir/File1.cpp"
"Dir/File1.hpp"
"Dir/File2.cpp"
"Dir/File2.hpp"
)
add_executable(Main ${SOURCE_LIST})
# Create the source groups for source tree with root at CMAKE_CURRENT_SOURCE_DIR.
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SOURCE_LIST})