Я работаю над приложением C ++ в Visual Studio, используя шаблон проекта Visual Studio CMake. Для создания моего приложения мне нужен только заголовок и внешняя библиотека, и я могу связать их следующим образом:

# CMakeList.txt : CMake project for myapp, include source and define project specific logic here.

cmake_minimum_required (VERSION 3.8)

# Add source to this project's executable.
add_executable (myapp "myapp.cpp" "myapp.h")

# Add TIFF library
set(TIFF_INCLUDE_DIR "C:\\libs\\tiff\\out\\install\\x64-Debug\\include")
set(TIFF_LIBRARY "C:\\libs\\tiff\\out\\install\\x64-Debug\\lib\\tiffd.lib")
find_package(TIFF REQUIRED)
target_link_libraries(myapp PRIVATE TIFF::TIFF)

Все идет нормально. Я могу использовать библиотеку tiff для открытия, чтения, записи файлов tiff и т. Д., И IntelliSense догоняет объявления в файлах заголовков. Но я бы хотел, чтобы IntelliSense также знала о полном исходном коде библиотеки TIFF. Например, если я нахожусь в myapp.cpp и я ctrl+click на TIFFOpen, он открывает заголовок, соответствующий TIFFOpen, но когда я ctrl+click TIFFOpen в заголовочный файл, он не переходит в соответствующий исходный файл, что является нормальным поведением для исходных файлов в myapp. Это понятно, поскольку я никогда не говорил Visual Studio, где найти исходные файлы внешней библиотеки.

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

Один из вариантов (я еще не пробовал, но уверен, что это сработает) - просто включить всю библиотеку tiff в качестве подпроекта myapp. Однако у меня есть некоторые проблемы с этим решением:

  1. Внешняя библиотека концептуально не является неотъемлемой частью проекта, и я не планирую изменять внешнюю библиотеку. Это скорее принципиальный вопрос.
  2. Простое использование его в качестве подпапки в моем проекте создает риск изменения того, что я не собирался менять.
  3. Я не хочу перестраивать внешнюю библиотеку, когда я перестраиваю все. Я знаю, что Visual Studio / CMake достаточно умен, чтобы понять, что ничего не изменилось и не перестраивается, но я бы предпочел, чтобы Visual Studio / CMake даже не пробовал.

На мой взгляд, я должен указать каталог с исходными файлами где-нибудь в настройках Visual Studio, но все же связанный с проектом. Я предполагаю, что .vs/ProjectSettings.json - это файл, который мне нужно как-то отредактировать, но, честно говоря, я понятия не имею.

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

Вкратце, я хочу, чтобы IntelliSense видел все исходные файлы внешней библиотеки так же, как он видит исходные файлы myapp, без включения всех исходных файлов внешней библиотеки в качестве подпроекта myapp. Как мне это сделать, если возможно?

Если уместно, я использую Visual Studio 2019 Community и CMake, который поставляется с ним (3.15).

3
Andrei 16 Окт 2019 в 00:27
Во-первых, вам не нужно вручную устанавливать TIFF_INCLUDE_DIR и TIFF_LIBRARY, так как find_package и target_link_libraries настраивают все, и эти переменные никогда не нужны. Во-вторых, cmake имеет целевое свойство, называемое «исключить из всех», которое гарантирует, что цель никогда не будет построена. Вы можете включить проект tiff и установить его на это, однако это нарушает ваше намерение вообще не включать его в качестве подпроекта.
 – 
X. Sun
16 Окт 2019 в 10:52
@ X.Sun Я тоже думал, что find_package() хотя бы попытается поискать этот пакет в моих файлах, но этого не произошло. Без установки переменных TIFF_ я получаю эту ошибку Could NOT find TIFF (missing: TIFF_LIBRARY TIFF_INCLUDE_DIR). В конечном итоге я более доволен этим способом, потому что в различных приложениях на моем компьютере есть какая-то версия библиотеки TIFF, и я предпочитаю использовать конкретную, которую я указываю лично. Свойство «исключить из всех» кажется справедливым компромиссом. Я надеюсь на лучшее решение, но если ничего не помогает ...
 – 
Andrei
16 Окт 2019 в 12:28
В этом случае вам может потребоваться проверить, что в установленной вами библиотеке tiff есть полные экспортированные файлы cmake, такие как TIFFConfig.cmake и TIFFConfigVersion.cmake, в папке установки, и их можно найти через системную переменную Path (очевидно, вы используете окна, поэтому следует настраивается вручную после установки). Современный cmake требует только find_package и target_link_libraries. Также файлы cmake чувствительны к регистру, Tiff и TIFF - разные. Но, честно говоря, многие библиотеки еще не перешли на современные cmake и не имеют надлежащего экспорта, даже некоторых фундаментальных.
 – 
X. Sun
16 Окт 2019 в 14:40
Я также заметил, что вы добавили tiffd.lib, что означает всегда использовать отладочную сборку библиотеки tiff. Правильная установка cmake будет переключаться между tiff.lib и tiffd.lib в соответствии с вашей конфигурацией сборки, это просто подсказка на случай, если вы столкнетесь с другими проблемами при сборке двоичных файлов выпуска.
 – 
X. Sun
16 Окт 2019 в 14:46
@ X.Sun Спасибо, что нашли время мне помочь. Я только что загрузил официальную последнюю версию, открыл ее с помощью VS, затем Build, затем Install, и нигде не было создано ни TIFFConfig.cmake, ни TIFFConfigVersion.cmake, но я предполагаю, что libtiff-4.pc может быть файлом TIFFConfigVersion.cmake
 – 
Andrei
16 Окт 2019 в 14:57

2 ответа

Что касается вашего последнего комментария, писать код в разделе комментариев неудобно, поэтому я просто опубликую его здесь, но это не ответ.

libtiff-4.pc предназначен для pkg-config, а не для cmake, и find_package() не может работать с ним непосредственно в Windows и потребует некоторой работы, если вы действительно этого хотите. Может быть проще просто написать все вручную. Не забудьте установить tiff.lib и tiffd.lib в соответствии с вашей конфигурацией. Вы можете использовать переменную CMAKE_BUILD_TYPE и команду if(), например:

# set build type to release if not specified
if(NOT CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "")
    set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build Type" FORCE)
endif()
# switch lib to link according to build type
if(CMAKE_BUILD_TYPE STREQUAL "Release")
    # for release
    set(TIFF_LIBRARY "<your_path_to_installed_lib>/tiff.lib")
else()
    # for debug. If you have other configs like relwithdebinfo you can add more
    set(TIFF_LIBRARY "<your_path_to_installed_lib>/tiffd.lib")
endif()

Также удалите find_package() и используйте target_link_libraries() и target_inlude_directories():

set(TIFF_INCLUDE_DIR "<your_path_to_installed_headers>/include")
target_link_libraries(myapp PRIVATE ${TIFF_LIBRARY})
target_include_directories(myapp PRIVATE ${TIFF_INCLUDE_DIR})

Вы также можете пропустить настройки TIFF_LIBRARY и TIFF_INCLUDE_DIR и передать строку напрямую, если хотите.

Я много использую Visual Studio, и это моя любимая IDE. Но управление пакетами с помощью cmake в Windows не так гладко, как в Linux. Всегда не забывайте устанавливать переменные среды после компиляции и установки внешних библиотек.

Обычно find_package () ищет переменную системной среды с именем <libname>_DIR (например, TIFF_DIR, которая отсутствует в вашем случае), которая используется для хранения пути к установленной библиотеке, а затем ищет <libname>Config.cmake и <libname>ConfigVersion.cmake в этой папке (а для TIFF их нет).

Он также выполняет поиск в других местах, проверьте https: // cmake .org / cmake / help / v3.15 / command / find_package.html? highlight = find_package для получения подробной информации.

Итак, для этих библиотек с экспортированными файлами cmake добавьте переменную с правильным именем и значением. И это только для компиляции.

Если вы хотите, чтобы ваше приложение запускалось после компиляции, вам также необходимо добавить путь к установленным двоичным файлам библиотеки (обычно * .dll) в системную переменную Path. В вашем случае вы должны найти что-то вроде tiff.dll и tiffd.dll после компиляции и установки, добавьте эту папку в Path, и все готово.

3
X. Sun 17 Окт 2019 в 10:37
Спасибо за всю информацию. Чтобы прояснить, с конфигурацией, изложенной в вопросе, она уже работает для использования библиотеки TIFF (с упоминанием, что действительно я строго связываюсь с отладочной версией, и я должен изменить это, как вы предложили). Моя основная проблема заключается в том, что intellisense доходит только до заголовков. Учитывая это, я предвижу неприятности, когда myapp вырастет и мне потребуется более серьезная отладка.
 – 
Andrei
17 Окт 2019 в 16:02

На самом деле, показать исходный код в IDE достаточно просто.

Просто добавьте источник с помощью add_library(tiff_for_ide EXCLUDE_FROM_ALL ${SOURCES}), но не связывайтесь с ним в основной программе. Вы захотите использовать другое целевое имя для библиотеки. Для этого вам понадобится источник в вашем проекте напрямую или в виде подмодуля (если вы используете Git, что-то еще, если это доступно вам VCS).

В других вариантах используется ExternalModule_Add; или FetchContent_MakeAvailable с add_library, как указано выше, чтобы избежать добавления сторонних хранилищ напрямую в репозиторий.

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

1
Spidey 6 Дек 2019 в 14:03