CMake add_subdirectory и перекомпиляция - PullRequest
2 голосов
/ 12 декабря 2011

Я только что перенес довольно большой проект из решений Visual Studio в CMake и заметил странное поведение. У меня есть что-то вроде следующей структуры:

project/CMakeLists.txt
project/code/CMakeLists.txt

project/code/library-1/CMakeLists.txt
project/code/library-1/*.hpp
project/code/library-1/*.cpp
project/code/library-2/CMakeLists.txt
project/code/library-2/*.hpp
project/code/library-2/*.cpp
...
project/code/library-n/CMakeLists.txt
project/code/library-n/*.hpp
project/code/library-n/*.cpp

project/demo/CMakeLists.txt
project/demo/demo-1/CMakeLists.txt
project/demo/demo-1/*.hpp
project/demo/demo-1/*.cpp
project/demo/demo-2/CMakeLists.txt
project/demo/demo-2/*.hpp
project/demo/demo-2/*.cpp
...
project/demo/demo-n/CMakeLists.txt
project/demo/demo-n/*.hpp
project/demo/demo-n/*.cpp
  1. Корневой файл CMakeLists.txt настраивает флаги компиляции, определения макросов и т. Д. И использует CMake add_subdirectory() для включения целей, определенных библиотеками и демонстрационными проектами.
  2. Подпапка code содержит плоский список подпапок, каждая из которых содержит исходный код статической библиотеки (а также ее цель, определенную в файле CMakeLists.txt).
  3. Подпапка demo содержит плоский список подпапок. Каждый содержит исходный код для исполняемого файла и связанный файл CMakeLists.txt.
  4. Каждая библиотека является автономным компонентом и создается независимо от всех других библиотек и демонстрационных проектов.
  5. Каждая демонстрационная программа зависит от одной или нескольких различных библиотек в подпапке code.

Эта настройка действительно хороша. Если я хочу изменить параметры сборки, мне нужно только изменить root CMakeLists.txt, и все перекомпилируется с новыми настройками. Если я изменю какой-либо исходный код в любом месте дерева, соответствующие библиотеки, если таковые имеются, будут перекомпилированы, и все зависимые демонстрационные программы также будут пересобраны.

Однако, если я изменю любой файл CMakeLists.txt в любом месте дерева, все дерево библиотек и программ будет перекомпилировано без учета зависимостей. Чтобы понять, что я имею в виду, приведу несколько частей сценариев сборки CMake.


project/demo/CMakeLists.txt

# Resolve libraries built in `code` sub-folder.
link_directories(${LIBRARY_OUTPUT_PATH})

set(demo-projects
  demo-1
  demo-2
  ...
  demo-n
)
foreach(demo-project ${demo-projects})
  add_subdirectory(${demo-project})
endforeach()

project/demo/demo-n/CMakeLists.txt

# Find all source code in the same folder.
file(GLOB ${demo-project}_headers
  ${CMAKE_CURRENT_SOURCE_DIR}/*.hpp
)
file(GLOB ${demo-project}_sources
  ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
)

# Select libraries to link with.
set(${demo-project}_libraries
  library-1
  library-2
  library-5
)

# Build the demo program.
add_executable(${demo-project}
  ${${demo-project}_headers}
  ${${demo-project}_sources}
)
if(${demo-project}_libraries)
  target_link_libraries(${demo-project} ${${demo-project}_libraries})
endif()

# Manually register some dependencies on other targets.
if(${demo-project}_dependencies)
  add_dependencies(${demo-project} ${${demo-project}_dependencies})
endif()

Если мне случится изменить project/demo/demo-n/CMakeLists.txt, добавив дополнительную библиотеку, например:

set(${demo-project}_libraries
  library-1
  library-2
  library-5
  library-6
)

Затем весь исходный код для всех библиотек и демонстрационных программ в проекте перекомпилируется. Почему это так? Есть ли лучший способ структурировать мои сценарии, чтобы избежать этого?

Ответы [ 5 ]

4 голосов
/ 21 декабря 2011

Первое, что вы хотите сделать, это выяснить, что изменится.Вы можете использовать git, чтобы помочь вам сделать это, если он у вас установлен.

  1. Запустите cmake для вашего проекта со сборкой из исходного кода
  2. cd для создания каталога
  3. создать git-репо из дерева сборки git add.git commit -m "добавить дерево сборки"
  4. изменить cmakefile, который вызывает перестроение
  5. , повторно запустить cmake на дереве сборки cmake.
  6. запустить git diff и посмотреть, чтоизменено.
2 голосов
/ 21 декабря 2011

Бывает, что моя проблема была вызвана совершенно не связанной проблемой. Я применил предложение Билла Хоффмана , и изменение любого файла "CMakeLists.txt" в проекте привело к изменению переменной CXX_FLAGS (флаги компилятора C ++) во всех сгенерированных файлах Makefile.

Я проследил это до моего корневого файла "CMakeLists.txt", который имел что-то вроде следующего:

if(MSVC)
  # ...
  set(CMAKE_CXX_FLAGS_DEBUG
    "${CMAKE_CXX_FLAGS_DEBUG} /WX /wd4355" // depends on cached value.
    CACHE STRING "Debug compiler flags" FORCE)
  # ...
endif()

Я изменил это на следующее.

if(MSVC)
  # ...
  set(CMAKE_CXX_FLAGS_DEBUG
    "/DWIN32 /D_WINDOWS /WX /wd4355" // no longer depends on cached value.
    CACHE STRING "Debug compiler flags" FORCE)
  # ...
endif()

CMake больше не повторяет флаги /WX /wd4355 при обновлении сценариев сборки, и мой проект больше не перекомпилируется с нуля при каждой модификации!

2 голосов
/ 21 декабря 2011

Это правда, что если какой-либо файл CMakeLists.txt изменится (или какой-либо вход в него, такой как исходный файл вызова configure_file), то CMake будет перезапущен на верхнем уровне дерева сборки и регенерируетсяфайлы решения и файлы проекта, которые изменились.

Тем не менее, он должен восстанавливать только те файлы, которые отличаются от тех, которые использовались в последний раз ... так что, основываясь на том, что вы показали в своем вопросе, я делаюнет хорошего объяснения, почему все перестраивается.

С другой стороны, CMake оставляет за Visual Studio право решать, что перестраивать, когда запускается «решение для сборки».Мы не выражаем никаких зависимостей для VS, за исключением размещения исходных файлов и заголовков в правильных проектах, правильной установки директорий include и доверия к VS для анализа включений и правильной перестройки при изменении заголовков и исходных файлов.

Вы не показываете никаких вызовов include_directories.Делаете ли вы их в файле CMakeLists.txt верхнего уровня таким образом, чтобы все подкаталоги имели одинаковый набор значений включения?Если это так, возможно, именно это вызывает перестройку всего.

Мы, безусловно, делаем все возможное, чтобы CMake производил системы сборки, которые минимизируют время перестройки.

Является ли ваш проект общедоступным?Могу ли я просмотреть полный исходный код и попытаться воспроизвести проблему на своем компьютере?

0 голосов
/ 21 декабря 2011

Привет, вы пытались удалить оператор

link_directories(${LIBRARY_OUTPUT_PATH})

из проекта / demo / CMakeLists.txt

Я не понимаю, почему это необходимо.Вся цель, на которую вы ссылаетесь, должна быть указана в target_link_libraries (...)

0 голосов
/ 20 декабря 2011

Я не знаком с тем, как CMake генерирует файлы решений / проектов Visual Studio, но я предполагаю, что он генерирует один (установлен?) Для всего вашего проекта.Из-за особенностей работы CMake (я не могу найти хорошую документацию по этому вопросу; может быть, книгу «Mastering CMake»?), Если файлы проекта подкаталога не являются отдельными, он будет генерировать их заново каждый раз, когда файл CMakeLists.txtизмененоЗатем Visual Studio будет отвечать за перестройку всего этого или нет (я предполагаю, что он перестраивает его, когда видит, что файл проекта изменился).

Документация для add_subdirectory действительно говорит

Файл CMakeLists.txt в указанном исходном каталоге будет немедленно обработан CMake перед продолжением обработки в текущем входном файле после этой команды.

Кажется,чтобы указать, что все подкаталоги обрабатываются как часть основного проекта.

В той же документации упоминается использование команды project в подкаталоге.Речь идет о том, когда вы используете аргумент EXCLUDE_FROM_ALL, но кажется возможным (стоит попробовать), что это все равно может помочь в вашей ситуации.Например, возможно, если CMake сгенерирует демонстрационный код в качестве своего собственного проекта, основной код не будет перестроен при изменении файла демонстрационного проекта.

Я думаю, что для получения окончательного ответа вам может потребоватьсяпост в списке рассылки CMake (и, если вы получили хороший ответ, опубликуйте его здесь).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...