Как установить фильтры Visual Studio для вложенной подкаталога с помощью cmake

У меня есть следующая структура

Main (dir)
      +-- CMakeLists.txt
      +-- File.cpp
      +-- File.hpp
      +-- Dir (dir)
          +-- CMakeLists.txt
          +-- File1.cpp
          +-- File1.hpp
          +-- File2.cpp
          +-- File2.hpp

Главная /CMakeLists.txt

CMAKE_MINIMUM_REQUIRED (VERSION 2.8.11)
PROJECT(Main)
FILE(GLOB SOURCE
    "*.hpp"
    "*.cpp"
)

ADD_SUBDIRECTORY(Dir)
ADD_EXECUTABLE(Main ${SOURCE})

Главная /Dir/CMakeLists.txt

FILE(GLOB LOCAL_SOURCE
    "*.hpp"
    "*.cpp"
)
SET(SOURCE
    ${SOURCE}
    ${LOCAL_SOURCE}
    PARENT_SCOPE
)

Он сгенерировал следующую структуру в Visual Studio
enter image description here

Что я хочу:

enter image description here enter image description here

Что я пробовал:

Main/CMakeLists.txt

CMAKE_MINIMUM_REQUIRED (VERSION 2.8.11)
PROJECT(Main)
FILE(GLOB LOCAL_SOURCE
    "*.hpp"
    "*.cpp"
)

SET(SOURCE 
    ${LOCAL_SOURCE}
)

ADD_SUBDIRECTORY(Dir)

SOURCE_GROUP(Main FILES ${LOCAL_SOURCE})
ADD_EXECUTABLE(Main ${SOURCE})

Главная /Dir/CMakeLists.txt

FILE(GLOB LOCAL_SOURCE
    "*.hpp"
    "*.cpp"
)
SET(SOURCE
    ${SOURCE}
    ${LOCAL_SOURCE}
    PARENT_SCOPE
)

SOURCE_GROUP(Dir FILES ${LOCAL_SOURCE})

Что я получу:

enter image description here

Пожалуйста, помогите мне в этом.

  • Я не хочу использовать один файл CmakeFile.txt в главном каталоге с фильтрами
  • Фактическая структура многослойной структуры глубокого вложения. Поэтому, пожалуйста, предложите решение, которое будет работать для любого подкаталога уровня.

Ответ 1

Существует несколько готовых к использованию или адаптируемых решений для имитации поведения дерева исходных текстов, как в Eclipse с CMake для Visual Studio (например, ADD_SRC_SUBFOLDER DESTINATION_SRCS от Zobra или GroupSources от Luca).

Вот моя уменьшенная версия для вашего случая использования:

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()

См. документацию source_group(), в которой вы должны указывать подкаталоги с двойной обратной косой чертой.

По той причине, что я заменил ваш file(GLOB ...) выделенным списком всех исходных файлов, которые я хотел бы процитировать из CMake file() документация команды:

Мы не рекомендуем использовать GLOB для сбора списка исходных файлов из ваше исходное дерево. Если файл CMakeLists.txt не изменяется, когда источник добавлена или удалена, тогда созданная система сборки не может знать, когда попросить CMake регенерировать.

И вот моя отказоустойчивая версия (которая проверяет абсолютные пути) для использования в качестве функции:

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)

Который вы бы назвали в примере с

assign_source_group(${source_list})

Ответ 2

Начиная с CMake 3.8, команда source_group предлагает аргумент TREE для рекурсивного поиска путей к файлам ваших источников для структурирования групп источников в соответствии со структурой вашей файловой системы. Теперь, это предлагает намного более чистое решение:

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})

Ответ 3

Я знаю, что использование функции glob CMAKE обычно вызывает недовольство: Почему CMAKE glob зло, но в моем случае я обнаружил, что это лучше, чем явное именование каждого файла. Я подумал, что включу модифицированную версию ответа Флориана, используя GLOB.

# This code sorts the project files as they appear in the root directory

# Generate a list of all .c & .h files in the current directory and sub directores.
file(
     GLOB_RECURSE source_list RELATIVE
     "${CMAKE_CURRENT_SOURCE_DIR}"
     *.c *.h
    )
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()  
message(STATUS "Tree reorganized")