Можно ли настроить проекты/библиотеки С++, которые имеют внешние зависимости, для работы сразу?

Я новичок в C++, и недавно я выяснял процесс загрузки внешней библиотеки и связывания ее с проектом, над которым я работаю. Судя по языкам, где добавление новых зависимостей и установка необходимых являются одной командой, кажется, что есть несколько способов загрузить и связать библиотеку на C++, и поэтому я изо всех сил пытаюсь представить, как опытные разработчики с крупномасштабными проектами могут сделать их скрипты и библиотеки переносимыми и простыми в установке.

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

include_directories(/opt/homebrew/Cellar/libxml2/2.10.3_1/include);
link_directories(/opt/homebrew/Cellar/libxml2/2.10.3_1/lib);

Но это потребует отдельной загрузки libxml2 на каждую машину, на которой клонируется этот проект, и путь также будет меняться в зависимости от версии и среды. Итак, мой конкретный вопрос: что считается лучшей практикой для упаковки проектов C++ с внешними зависимостями?

Например, в node.js есть package.json и npm install, в python — requirement.txt и pip install -r requirements.txt. Есть ли эквивалент C++?

Извините, если это глупый вопрос, но я действительно изо всех сил пытаюсь найти правильные условия поиска, чтобы найти правильный ответ. Заранее спасибо!

К сожалению, ничего, что соответствовало бы вашим ожиданиям по сравнению с такими вещами, как npm и maven. См. здесь, а также vcpkg, о котором я не вижу упоминания в связанном посте.

adnan_e 26.12.2022 00:45
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
1
68
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Лично я просто использую git-модули с зависимостями как часть моего репозитория, поэтому, когда кто-то проверяет его, он/она также может получить весь исходный код, необходимый для сборки/связывания необходимых зависимостей.

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

Например. вот как выглядит файловая структура в одном из моих проектов (я избавился от некоторых деталей, которые напрямую не связаны с вопросом):

|-- CMakeLists.txt
|-- CMakeSettings.json
|-- README.md
|-- assets
|   |-- assets-files
|-- lib
|   |-- CMakeLists.txt
|   |-- libTwo
|   |-- libThree
|   `-- libFour
`-- src
    |-- source-files

Каждая подпапка в lib является отдельным подмодулем в моем репозитории. В корень CMakeLists.txt я просто добавляю эту папку со своими зависимостями одной строкой конфигурации:

add_subdirectory(lib)

В то время как CMakeLists.txt в папке lib позаботится обо всем остальном:

add_compile_options(-w)
# Lib One
find_package(libOne REQUIRED)
list(APPEND LIB_TARGETS ${LIB_ONE_LIBRARIES})
list(APPEND LIB_INCLUDE_DIRS ${LIB_ONE_INCLUDE_DIRS})

# Lib Two
add_subdirectory(libTwo)
list(APPEND LIB_TARGETS libTwo)
list(APPEND LIB_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/libTwo/include")

# Lib Three
add_subdirectory(libThree)
list(APPEND LIB_TARGETS libThreeProj)
list(APPEND LIB_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/libThree/include")

# Lib Four
add_subdirectory(libFour)
list(APPEND LIB_TARGETS libFour)

if (LIB_INCLUDE_DIRS)
        list(REMOVE_DUPLICATES LIB_INCLUDE_DIRS)
        target_include_directories(${PROJ_NAME} PRIVATE ${LIB_INCLUDE_DIRS})
        if (MSVC)
                target_compile_options(${PROJ_NAME} PRIVATE
                        "$<$<CXX_COMPILER_ID:Clang>:SHELL:-Xclang -isystem$<JOIN:${LIB_INCLUDE_DIRS}, -Xclang -isystem>>"
                        "$<$<CXX_COMPILER_ID:MSVC>:SHELL:-experimental:external -external:W0 -external:anglebrackets -external:I$<JOIN:${LIB_INCLUDE_DIRS}, -external:I>>")
        else()
                target_compile_options(${PROJ_NAME} PRIVATE "SHELL:-isystem $<JOIN:${LIB_INCLUDE_DIRS}, -isystem>")
        endif ()
endif ()

target_link_libraries(${PROJ_NAME} PRIVATE ${LIB_TARGETS})

Вы можете заметить, что я также сохраняю другие зависимости (например, libOne в данном случае), которые можно найти с помощью find_package, в том же месте, и они точно совместимы со всеми зависимостями, которые я загружал из удаленных репозиториев.

Конечно, это не всегда работает гладко и сильно зависит от того, как авторы библиотек распространяют свой код, но для меня работает большую часть времени, даже когда это требует некоторых настроек в конфигурации (например, libFour — это библиотека только для заголовков, и вообще не требует никакой привязки, а libThree имеет несовместимое целевое имя libThreeProj)

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

Ralph 26.12.2022 02:22

Другие вопросы по теме